From ddd92c055360ef0d2f1fb87def5478009816d500 Mon Sep 17 00:00:00 2001 From: rtel Date: Mon, 2 Dec 2019 23:39:25 +0000 Subject: [PATCH] Add the Labs projects provided in the V10.2.1_191129 zip file. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@2757 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../Common/FreeRTOS_TCP_server.c | 353 + .../FTP/FreeRTOS_FTP_commands.c | 74 + .../FTP/FreeRTOS_FTP_server.c | 2637 ++++ .../HTTP/FreeRTOS_HTTP_commands.c | 71 + .../HTTP/FreeRTOS_HTTP_server.c | 428 + .../Common/Demo_IP_Protocols/NTP/NTPDemo.c | 440 + .../include/FreeRTOS_FTP_commands.h | 133 + .../include/FreeRTOS_HTTP_commands.h | 67 + .../include/FreeRTOS_TCP_server.h | 125 + .../include/FreeRTOS_server_private.h | 185 + .../Demo_IP_Protocols/include/NTPClient.h | 71 + .../Demo_IP_Protocols/include/NTPDemo.h | 11 + .../File-related-CLI-commands.c | 669 + .../Sample-CLI-commands.c | 518 + .../TCP-related-CLI-commands.c | 374 + .../TCPCommandConsole.c | 365 + .../UARTCommandConsole.c | 272 + .../UDPCommandConsole.c | 279 + .../include/TCPCommandConsole.h | 75 + .../include/UDPCommandConsole.h | 75 + .../CreateAndVerifyExampleFiles.c | 451 + .../test/ff_stdio_tests_with_cwd.c | 1194 ++ .../CreateExampleFiles/File-system-demo.c | 321 + .../SimpleTCPEchoServer.c | 288 + .../TCPEchoClient_SingleTasks.c | 433 + .../FreeRTOS_Plus_TCP_Demos/TFTPServer.c | 582 + .../TraceMacros/Example1/DemoIPTrace.c | 222 + .../TraceMacros/Example1/DemoIPTrace.h | 185 + .../include/DefaultWebPages.h | 2681 ++++ .../HTML_for_default_web_pages/ftp.png | Bin 0 -> 32467 bytes .../HTML_for_default_web_pages/index.html | 100 + .../HTML_for_default_web_pages/logo.jpg | Bin 0 -> 5178 bytes .../include/SimpleTCPEchoServer.h | 76 + .../include/TCPEchoClient_SingleTasks.h | 82 + .../include/TFTPServer.h | 79 + .../CLICommands/CLI-commands.c | 664 + .../CLICommands/UDPCommandInterpreter.h | 33 + .../CLICommands/UDPCommandServer.c | 206 + .../EchoClients/TwoEchoClients.c | 359 + .../EchoClients/TwoEchoClients.h | 38 + .../TraceMacros/Example1/DemoIPTrace.c | 150 + .../TraceMacros/Example1/DemoIPTrace.h | 121 + FreeRTOS-Labs/Demo/Common/ReadMe.txt | 2 + .../Demo/Common/Utilities/UDPLoggingPrintf.c | 502 + .../Demo/Common/Utilities/date_and_time.c | 176 + .../Utilities/include/UDPLoggingPrintf.h | 100 + .../Common/Utilities/include/date_and_time.h | 93 + .../Demo/Common/Utilities/printf-stdarg.c | 675 + .../common/DemoTasks/SimpleHTTPSExamples.c | 520 + .../https/common/WinPCap/Packet32.h | 359 + .../https/common/WinPCap/PacketData.h | 267 + .../https/common/WinPCap/Win32-Extensions.h | 114 + .../https/common/WinPCap/arch.c | 336 + .../https/common/WinPCap/bittypes.h | 137 + .../https/common/WinPCap/ip6_misc.h | 163 + .../https/common/WinPCap/netif.h | 52 + .../https/common/WinPCap/pcap-bpf.h | 47 + .../https/common/WinPCap/pcap-namedb.h | 42 + .../https/common/WinPCap/pcap-stdinc.h | 93 + .../https/common/WinPCap/pcap.h | 45 + .../https/common/WinPCap/pcap/bluetooth.h | 48 + .../https/common/WinPCap/pcap/bpf.h | 934 ++ .../https/common/WinPCap/pcap/namedb.h | 89 + .../https/common/WinPCap/pcap/pcap.h | 407 + .../https/common/WinPCap/pcap/sll.h | 129 + .../https/common/WinPCap/pcap/usb.h | 90 + .../https/common/WinPCap/pcap/vlan.h | 46 + .../https/common/WinPCap/remote-ext.h | 444 + .../https/common/WinPCap/wpcap.lib | Bin 0 -> 19320 bytes .../https/common/atomic.h | 547 + .../https/common/demo_logging.c | 527 + .../https/common/demo_logging.h | 48 + .../https/common/main.c | 356 + .../https/common/mbedtls_config.h | 126 + .../https/common/printf-stdarg.c | 667 + .../https/http_plain_text/FreeRTOSConfig.h | 210 + .../https/http_plain_text/FreeRTOSIPConfig.h | 310 + .../http_plain_text/READ_ME_INSTRUCTIONS.url | 5 + .../https/http_plain_text/WIN32.vcxproj | 220 + .../http_plain_text/WIN32.vcxproj.filters | 293 + .../https/http_plain_text/demo_config.h | 78 + .../http_plain_text/http_plain_text_demo.sln | 23 + .../https/http_plain_text/iot_config.h | 164 + .../FreeRTOSConfig.h | 210 + .../FreeRTOSIPConfig.h | 310 + .../READ_ME_INSTRUCTIONS.url | 5 + .../https_basic_tls_server_auth/WIN32.vcxproj | 618 + .../WIN32.vcxproj.filters | 786 ++ .../https_basic_tls_server_auth/demo_config.h | 78 + .../https_basic_tls_demo.sln | 23 + .../https_basic_tls_server_auth/iot_config.h | 171 + .../https_tls_mutual_auth/FreeRTOSConfig.h | 210 + .../https_tls_mutual_auth/FreeRTOSIPConfig.h | 310 + .../READ_ME_INSTRUCTIONS.url | 5 + .../https/https_tls_mutual_auth/WIN32.vcxproj | 618 + .../WIN32.vcxproj.filters | 786 ++ .../https/https_tls_mutual_auth/demo_config.h | 78 + .../https_tls_mutual_auth_demo.sln | 23 + .../https/https_tls_mutual_auth/iot_config.h | 171 + .../FreeRTOS_IoT_Libraries/https/readme.txt | 24 + .../include/aws_iot_demo_profile.h | 133 + .../include/aws_iot_setup_check.h | 79 + .../include/https_demo_profile.h | 103 + .../include/mqtt_demo_profile.h | 114 + .../DemoTasks/JobsNotifyNextExamples.c | 1079 ++ .../jobs/jobs_notify_next/FreeRTOSConfig.h | 210 + .../jobs/jobs_notify_next/FreeRTOSIPConfig.h | 310 + .../jobs_notify_next/READ_ME_INSTRUCTIONS.url | 5 + .../jobs/jobs_notify_next/WIN32.vcxproj | 644 + .../jobs_notify_next/WIN32.vcxproj.filters | 877 ++ .../jobs/jobs_notify_next/WinPCap/Packet32.h | 359 + .../jobs_notify_next/WinPCap/PacketData.h | 267 + .../WinPCap/Win32-Extensions.h | 114 + .../jobs/jobs_notify_next/WinPCap/arch.c | 336 + .../jobs/jobs_notify_next/WinPCap/bittypes.h | 137 + .../jobs/jobs_notify_next/WinPCap/ip6_misc.h | 163 + .../jobs/jobs_notify_next/WinPCap/netif.h | 52 + .../jobs/jobs_notify_next/WinPCap/pcap-bpf.h | 47 + .../jobs_notify_next/WinPCap/pcap-namedb.h | 42 + .../jobs_notify_next/WinPCap/pcap-stdinc.h | 93 + .../jobs/jobs_notify_next/WinPCap/pcap.h | 45 + .../jobs_notify_next/WinPCap/pcap/bluetooth.h | 48 + .../jobs/jobs_notify_next/WinPCap/pcap/bpf.h | 934 ++ .../jobs_notify_next/WinPCap/pcap/namedb.h | 89 + .../jobs/jobs_notify_next/WinPCap/pcap/pcap.h | 407 + .../jobs/jobs_notify_next/WinPCap/pcap/sll.h | 129 + .../jobs/jobs_notify_next/WinPCap/pcap/usb.h | 90 + .../jobs/jobs_notify_next/WinPCap/pcap/vlan.h | 46 + .../jobs_notify_next/WinPCap/remote-ext.h | 444 + .../jobs/jobs_notify_next/WinPCap/wpcap.lib | Bin 0 -> 19320 bytes .../jobs/jobs_notify_next/atomic.h | 547 + .../jobs/jobs_notify_next/demo_config.h | 39 + .../jobs/jobs_notify_next/demo_logging.c | 527 + .../jobs/jobs_notify_next/demo_logging.h | 48 + .../jobs/jobs_notify_next/iot_config.h | 233 + .../jobs_notify_next_demo.sln | 23 + .../jobs/jobs_notify_next/main.c | 356 + .../jobs/jobs_notify_next/mbedtls_config.h | 126 + .../jobs/jobs_notify_next/printf-stdarg.c | 667 + .../FreeRTOS_IoT_Libraries/jobs/readme.txt | 8 + .../common/DemoTasks/LightWeightMQTTExample.c | 853 ++ .../common/DemoTasks/SimpleMQTTExamples.c | 659 + .../mqtt/common/Run-time-stats-utils.c | 99 + .../mqtt/common/WinPCap/Packet32.h | 359 + .../mqtt/common/WinPCap/PacketData.h | 267 + .../mqtt/common/WinPCap/Win32-Extensions.h | 114 + .../mqtt/common/WinPCap/arch.c | 336 + .../mqtt/common/WinPCap/bittypes.h | 137 + .../mqtt/common/WinPCap/ip6_misc.h | 163 + .../mqtt/common/WinPCap/netif.h | 52 + .../mqtt/common/WinPCap/pcap-bpf.h | 47 + .../mqtt/common/WinPCap/pcap-namedb.h | 42 + .../mqtt/common/WinPCap/pcap-stdinc.h | 93 + .../mqtt/common/WinPCap/pcap.h | 45 + .../mqtt/common/WinPCap/pcap/bluetooth.h | 48 + .../mqtt/common/WinPCap/pcap/bpf.h | 934 ++ .../mqtt/common/WinPCap/pcap/namedb.h | 89 + .../mqtt/common/WinPCap/pcap/pcap.h | 407 + .../mqtt/common/WinPCap/pcap/sll.h | 129 + .../mqtt/common/WinPCap/pcap/usb.h | 90 + .../mqtt/common/WinPCap/pcap/vlan.h | 46 + .../mqtt/common/WinPCap/remote-ext.h | 444 + .../mqtt/common/WinPCap/wpcap.lib | Bin 0 -> 19320 bytes .../mqtt/common/atomic.h | 547 + .../mqtt/common/demo_logging.c | 527 + .../mqtt/common/demo_logging.h | 48 + .../FreeRTOS_IoT_Libraries/mqtt/common/main.c | 369 + .../mqtt/common/mbedtls_config.h | 126 + .../mqtt/common/printf-stdarg.c | 667 + .../FreeRTOSConfig.h | 210 + .../FreeRTOSIPConfig.h | 310 + .../READ_ME_INSTRUCTIONS.url | 5 + .../mqtt_basic_tls_server_auth/WIN32.vcxproj | 620 + .../WIN32.vcxproj.filters | 789 ++ .../mqtt_basic_tls_server_auth/demo_config.h | 78 + .../mqtt_basic_tls_server_auth/iot_config.h | 182 + .../mqtt_basic_tls_demo.sln | 23 + .../mqtt/mqtt_plain_text/FreeRTOSConfig.h | 218 + .../mqtt/mqtt_plain_text/FreeRTOSIPConfig.h | 310 + .../mqtt_plain_text/READ_ME_INSTRUCTIONS.url | 5 + .../mqtt/mqtt_plain_text/WIN32.vcxproj | 226 + .../mqtt_plain_text/WIN32.vcxproj.filters | 312 + .../mqtt/mqtt_plain_text/demo_config.h | 78 + .../mqtt/mqtt_plain_text/iot_config.h | 175 + .../mqtt_plain_text/mqtt_plain_text_demo.sln | 25 + .../mqtt/mqtt_plain_text/trcConfig.h | 300 + .../mqtt/mqtt_plain_text/trcSnapshotConfig.h | 378 + .../mqtt_tls_mutual_auth/FreeRTOSConfig.h | 210 + .../mqtt_tls_mutual_auth/FreeRTOSIPConfig.h | 310 + .../READ_ME_INSTRUCTIONS.url | 5 + .../mqtt/mqtt_tls_mutual_auth/WIN32.vcxproj | 620 + .../WIN32.vcxproj.filters | 789 ++ .../mqtt/mqtt_tls_mutual_auth/demo_config.h | 78 + .../mqtt/mqtt_tls_mutual_auth/iot_config.h | 179 + .../mqtt_tls_mutual_auth_demo.sln | 28 + .../mqtt/mqtt_tls_mutual_auth/readme.txt | 3 + .../FreeRTOS_IoT_Libraries/mqtt/readme.txt | 26 + .../Demo/FreeRTOS_IoT_Libraries/readme.txt | 51 + .../FreeRTOS_IoT_Libraries/shadow/readme.txt | 8 + .../ShadowDeviceOperationsExamples.c | 1065 ++ .../shadow_device_operations/FreeRTOSConfig.h | 210 + .../FreeRTOSIPConfig.h | 310 + .../READ_ME_INSTRUCTIONS.url | 5 + .../shadow_device_operations/WIN32.vcxproj | 644 + .../WIN32.vcxproj.filters | 877 ++ .../WinPCap/Packet32.h | 359 + .../WinPCap/PacketData.h | 267 + .../WinPCap/Win32-Extensions.h | 114 + .../shadow_device_operations/WinPCap/arch.c | 336 + .../WinPCap/bittypes.h | 137 + .../WinPCap/ip6_misc.h | 163 + .../shadow_device_operations/WinPCap/netif.h | 52 + .../WinPCap/pcap-bpf.h | 47 + .../WinPCap/pcap-namedb.h | 42 + .../WinPCap/pcap-stdinc.h | 93 + .../shadow_device_operations/WinPCap/pcap.h | 45 + .../WinPCap/pcap/bluetooth.h | 48 + .../WinPCap/pcap/bpf.h | 934 ++ .../WinPCap/pcap/namedb.h | 89 + .../WinPCap/pcap/pcap.h | 407 + .../WinPCap/pcap/sll.h | 129 + .../WinPCap/pcap/usb.h | 90 + .../WinPCap/pcap/vlan.h | 46 + .../WinPCap/remote-ext.h | 444 + .../WinPCap/wpcap.lib | Bin 0 -> 19320 bytes .../shadow/shadow_device_operations/atomic.h | 547 + .../shadow_device_operations/demo_config.h | 39 + .../shadow_device_operations/demo_logging.c | 527 + .../shadow_device_operations/demo_logging.h | 48 + .../shadow_device_operations/iot_config.h | 214 + .../shadow/shadow_device_operations/main.c | 357 + .../shadow_device_operations/mbedtls_config.h | 126 + .../shadow_device_operations/printf-stdarg.c | 667 + .../shadow_device_operations_demo.sln | 23 + .../CertificateConfigurator.html | 84 + .../js/aws_iot_demo_profile_template.js | 141 + .../tools/aws_config_offline/js/generator.js | 70 + .../tools/aws_config_quick_start/.gitignore | 5 + .../tools/aws_config_quick_start/README.md | 20 + .../tools/aws_config_quick_start/SetupAWS.py | 235 + .../aws_iot_demo_profile.templ | 139 + .../aws_iot_demo_profile_empty.templ | 133 + .../tools/aws_config_quick_start/certs.py | 88 + .../aws_config_quick_start/configure.json | 4 + .../tools/aws_config_quick_start/misc.py | 99 + .../tools/aws_config_quick_start/policy.py | 27 + .../policy_document.templ | 25 + .../tools/aws_config_quick_start/thing.py | 44 + .../FreeRTOS_IoT_Libraries/tools/readme.txt | 1 + .../utilities/readme.txt | 2 + .../DemoTasks/SimpleTaskPoolExamples.c | 306 + .../utilities/task_pool/FreeRTOSConfig.h | 208 + .../utilities/task_pool/FreeRTOSIPConfig.h | 307 + .../task_pool/READ_ME_INSTRUCTIONS.url | 6 + .../utilities/task_pool/WIN32.vcxproj | 209 + .../utilities/task_pool/WIN32.vcxproj.filters | 244 + .../utilities/task_pool/WinPCap/Packet32.h | 359 + .../utilities/task_pool/WinPCap/PacketData.h | 267 + .../task_pool/WinPCap/Win32-Extensions.h | 114 + .../utilities/task_pool/WinPCap/arch.c | 336 + .../utilities/task_pool/WinPCap/bittypes.h | 137 + .../utilities/task_pool/WinPCap/ip6_misc.h | 163 + .../utilities/task_pool/WinPCap/netif.h | 52 + .../utilities/task_pool/WinPCap/pcap-bpf.h | 47 + .../utilities/task_pool/WinPCap/pcap-namedb.h | 42 + .../utilities/task_pool/WinPCap/pcap-stdinc.h | 93 + .../utilities/task_pool/WinPCap/pcap.h | 45 + .../task_pool/WinPCap/pcap/bluetooth.h | 48 + .../utilities/task_pool/WinPCap/pcap/bpf.h | 934 ++ .../utilities/task_pool/WinPCap/pcap/namedb.h | 89 + .../utilities/task_pool/WinPCap/pcap/pcap.h | 407 + .../utilities/task_pool/WinPCap/pcap/sll.h | 129 + .../utilities/task_pool/WinPCap/pcap/usb.h | 90 + .../utilities/task_pool/WinPCap/pcap/vlan.h | 46 + .../utilities/task_pool/WinPCap/remote-ext.h | 444 + .../utilities/task_pool/WinPCap/wpcap.lib | Bin 0 -> 19320 bytes .../utilities/task_pool/demo_config.h | 39 + .../utilities/task_pool/demo_logging.c | 527 + .../utilities/task_pool/demo_logging.h | 48 + .../utilities/task_pool/iot_config.h | 135 + .../utilities/task_pool/main.c | 210 + .../utilities/task_pool/printf-stdarg.c | 667 + .../utilities/task_pool/task_pool_demo.sln | 25 + .../FreeRTOSConfig.h | 119 + .../FreeRTOS_Plus_POSIX_with_actor.sln | 25 + .../WIN32.vcxproj | 185 + .../WIN32.vcxproj.filters | 174 + .../atomic.h | 547 + .../include/FreeRTOS_POSIX.h | 50 + .../include/FreeRTOS_POSIX_internal.h | 129 + .../include/FreeRTOS_POSIX_types.h | 81 + .../FreeRTOS_POSIX_portable_default.h | 145 + .../FreeRTOS_POSIX_portable.h | 60 + .../FreeRTOS_POSIX_portable.h | 50 + .../FreeRTOS_POSIX_portable.h | 37 + .../pc/windows/FreeRTOS_POSIX_portable.h | 37 + .../FreeRTOS_POSIX_portable.h | 37 + .../FreeRTOS_POSIX_portable.h | 37 + .../source/FreeRTOS_POSIX_clock.c | 240 + .../source/FreeRTOS_POSIX_mqueue.c | 893 ++ .../source/FreeRTOS_POSIX_pthread.c | 510 + .../source/FreeRTOS_POSIX_pthread_barrier.c | 165 + .../source/FreeRTOS_POSIX_pthread_cond.c | 294 + .../source/FreeRTOS_POSIX_pthread_mutex.c | 373 + .../source/FreeRTOS_POSIX_sched.c | 64 + .../source/FreeRTOS_POSIX_semaphore.c | 233 + .../source/FreeRTOS_POSIX_timer.c | 330 + .../source/FreeRTOS_POSIX_unistd.c | 54 + .../source/FreeRTOS_POSIX_utils.c | 388 + .../lib/include/FreeRTOS_POSIX/errno.h | 95 + .../lib/include/FreeRTOS_POSIX/fcntl.h | 79 + .../lib/include/FreeRTOS_POSIX/mqueue.h | 250 + .../lib/include/FreeRTOS_POSIX/pthread.h | 501 + .../lib/include/FreeRTOS_POSIX/sched.h | 84 + .../lib/include/FreeRTOS_POSIX/semaphore.h | 143 + .../lib/include/FreeRTOS_POSIX/signal.h | 70 + .../lib/include/FreeRTOS_POSIX/sys/types.h | 191 + .../lib/include/FreeRTOS_POSIX/time.h | 258 + .../lib/include/FreeRTOS_POSIX/unistd.h | 61 + .../lib/include/FreeRTOS_POSIX/utils.h | 155 + .../include/private/iot_doubly_linked_list.h | 242 + .../main.c | 197 + .../posix_demo.c | 374 + .../posix_demo.h | 32 + .../readme.txt | 6 + .../CLI-commands.c | 716 + .../DemoTasks/SimpleTCPEchoServer.c | 527 + .../DemoTasks/SimpleUDPClientAndServer.c | 398 + .../DemoTasks/TCPEchoClient_SeparateTasks.c | 468 + .../DemoTasks/TCPEchoClient_SingleTasks.c | 400 + .../DemoTasks/TCPEchoSelectServer.c | 415 + .../DemoTasks/TwoUDPEchoClients.c | 435 + .../DemoTasks/UDPSelectServer.c | 404 + .../DemoTasks/include/SimpleTCPEchoServer.h | 76 + .../include/SimpleUDPClientAndServer.h | 75 + .../include/TCPEchoClient_SeparateTasks.h | 83 + .../include/TCPEchoClient_SingleTasks.h | 82 + .../DemoTasks/include/TCPEchoSelectServer.h | 75 + .../DemoTasks/include/TwoUDPEchoClients.h | 81 + .../DemoTasks/include/UDPSelectServer.h | 76 + .../FreeRTOSConfig.h | 267 + .../FreeRTOSFATConfig.h | 333 + .../FreeRTOSIPConfig.h | 377 + .../FreeRTOS_Plus_TCP_and_FAT.sln | 23 + .../Read_Me_Build_Instructions.url | 6 + .../Run-time-stats-utils.c | 142 + .../TraceMacros/Example1/DemoIPTrace.c | 222 + .../TraceMacros/Example1/DemoIPTrace.h | 185 + .../WIN32.vcxproj | 248 + .../WIN32.vcxproj.filters | 345 + .../WinPCap/Packet32.h | 359 + .../WinPCap/PacketData.h | 267 + .../WinPCap/Win32-Extensions.h | 114 + .../WinPCap/arch.c | 378 + .../WinPCap/bittypes.h | 137 + .../WinPCap/ip6_misc.h | 163 + .../WinPCap/netif.h | 94 + .../WinPCap/pcap-bpf.h | 47 + .../WinPCap/pcap-namedb.h | 42 + .../WinPCap/pcap-stdinc.h | 87 + .../WinPCap/pcap.h | 45 + .../WinPCap/pcap/bluetooth.h | 48 + .../WinPCap/pcap/bpf.h | 934 ++ .../WinPCap/pcap/namedb.h | 89 + .../WinPCap/pcap/pcap.h | 407 + .../WinPCap/pcap/sll.h | 129 + .../WinPCap/pcap/usb.h | 90 + .../WinPCap/pcap/vlan.h | 46 + .../WinPCap/remote-ext.h | 444 + .../WinPCap/wpcap.lib | Bin 0 -> 19320 bytes .../demo_logging.c | 568 + .../demo_logging.h | 89 + .../main.c | 858 ++ .../printf-stdarg.c | 667 + .../trcConfig.h | 510 + .../trcHardwarePort.h | 474 + .../instructions-for-FreeRTOS+FAT-demo.url | 6 + .../instructions-for-FreeRTOS+POSIX-demo.url | 5 + .../Demo/instructions-for-http-demo.url | 6 + .../Demo/instructions-for-jobs-demo.url | 6 + .../Demo/instructions-for-mqtt-demo.url | 6 + .../Demo/instructions-for-shadow-demo.url | 6 + .../Demo/instructions-for-task-pool-demo.url | 5 + FreeRTOS-Labs/Demo/readme.txt | 49 + .../abstractions/directories.txt | 4 + .../mbedtls/mbedtls_platform_freertos.c | 173 + .../abstractions/mbedtls/threading_alt.h | 44 + .../freertos/include/iot_taskpool_freertos.h | 310 + .../include/platform/iot_network_freertos.h | 150 + .../platform/iot_platform_types_freertos.h | 92 + .../types/iot_taskpool_types_freertos.h | 306 + .../platform/freertos/iot_clock_freertos.c | 225 + .../platform/freertos/iot_network_freertos.c | 968 ++ .../platform/freertos/iot_taskpool_freertos.c | 1006 ++ .../platform/freertos/iot_threads_freertos.c | 365 + .../private/iot_taskpool_internal_freertos.h | 110 + .../c_sdk/aws/common/include/aws_iot.h | 305 + .../aws/common/include/aws_iot_doc_parser.h | 69 + .../c_sdk/aws/common/src/aws_iot_doc_parser.c | 294 + .../c_sdk/aws/common/src/aws_iot_operation.c | 153 + .../c_sdk/aws/common/src/aws_iot_parser.c | 181 + .../aws/common/src/aws_iot_subscription.c | 164 + .../c_sdk/aws/common/src/aws_iot_validate.c | 62 + .../c_sdk/aws/directories.txt | 10 + .../c_sdk/aws/jobs/AWS_IoT_Jobs.url | 5 + .../c_sdk/aws/jobs/include/aws_iot_jobs.h | 927 ++ .../jobs/include/types/aws_iot_jobs_types.h | 1011 ++ .../c_sdk/aws/jobs/src/aws_iot_jobs_api.c | 1624 +++ .../aws/jobs/src/aws_iot_jobs_operation.c | 885 ++ .../aws/jobs/src/aws_iot_jobs_serialize.c | 1214 ++ .../aws/jobs/src/aws_iot_jobs_static_memory.c | 169 + .../aws/jobs/src/aws_iot_jobs_subscription.c | 581 + .../jobs/src/private/aws_iot_jobs_internal.h | 628 + .../c_sdk/aws/shadow/AWS_IoT_Shadow.url | 5 + .../c_sdk/aws/shadow/include/aws_iot_shadow.h | 909 ++ .../include/types/aws_iot_shadow_types.h | 641 + .../c_sdk/aws/shadow/src/aws_iot_shadow_api.c | 1333 ++ .../aws/shadow/src/aws_iot_shadow_operation.c | 925 ++ .../aws/shadow/src/aws_iot_shadow_parser.c | 195 + .../shadow/src/aws_iot_shadow_static_memory.c | 160 + .../shadow/src/aws_iot_shadow_subscription.c | 512 + .../src/private/aws_iot_shadow_internal.h | 565 + .../c_sdk/directories.txt | 7 + .../c_sdk/platform/iot_clock.h | 213 + .../c_sdk/platform/iot_metrics.h | 100 + .../c_sdk/platform/iot_network.h | 318 + .../c_sdk/platform/iot_threads.h | 352 + .../c_sdk/platform/types/iot_platform_types.h | 190 + .../c_sdk/standard/common/include/atomic.h | 547 + .../standard/common/include/iot_atomic.h | 39 + .../c_sdk/standard/common/include/iot_error.h | 114 + .../c_sdk/standard/common/include/iot_init.h | 64 + .../common/include/iot_linear_containers.h | 956 ++ .../standard/common/include/iot_logging.h | 226 + .../common/include/iot_logging_setup.h | 220 + .../common/include/iot_static_memory.h | 197 + .../c_sdk/standard/common/src/iot_logging.c | 451 + .../c_sdk/standard/directories.txt | 10 + .../standard/https/include/iot_https_client.h | 852 ++ .../standard/https/include/iot_https_utils.h | 95 + .../https/include/types/iot_https_types.h | 907 ++ .../standard/https/src/iot_https_client.c | 3365 +++++ .../standard/https/src/iot_https_utils.c | 137 + .../https/src/private/iot_https_internal.h | 497 + .../c_sdk/standard/mqtt/include/iot_mqtt.h | 859 ++ .../mqtt/include/iot_mqtt_serialize.h | 702 + .../mqtt/include/types/iot_mqtt_types.h | 1164 ++ .../c_sdk/standard/mqtt/src/iot_mqtt_api.c | 2145 +++ .../standard/mqtt/src/iot_mqtt_network.c | 884 ++ .../standard/mqtt/src/iot_mqtt_operation.c | 1344 ++ .../standard/mqtt/src/iot_mqtt_serialize.c | 2604 ++++ .../standard/mqtt/src/iot_mqtt_subscription.c | 645 + .../standard/mqtt/src/iot_mqtt_validate.c | 637 + .../mqtt/src/private/iot_mqtt_internal.h | 1038 ++ .../FreeRTOS-IoT-Libraries/directories.txt | 8 + .../Source/FreeRTOS-IoT-Libraries/readme.txt | 46 + .../Source/FreeRTOS-Plus-CLI/FreeRTOS_CLI.c | 347 + .../Source/FreeRTOS-Plus-CLI/FreeRTOS_CLI.h | 120 + .../Source/FreeRTOS-Plus-CLI/History.txt | 27 + .../FreeRTOS-Plus-CLI/LICENSE_INFORMATION.txt | 7 + .../Source/FreeRTOS-Plus-CLI/ReadMe.url | 5 + .../Source/FreeRTOS-Plus-CLI/readme.txt | 4 + .../Source/FreeRTOS-Plus-FAT/History.txt | 58 + .../Source/FreeRTOS-Plus-FAT/History2.txt | 66 + .../Source/FreeRTOS-Plus-FAT/ReadMe.url | 5 + .../Source/FreeRTOS-Plus-FAT/ff_crc.c | 256 + .../Source/FreeRTOS-Plus-FAT/ff_dev_support.c | 235 + .../Source/FreeRTOS-Plus-FAT/ff_dir.c | 3426 +++++ .../Source/FreeRTOS-Plus-FAT/ff_error.c | 311 + .../Source/FreeRTOS-Plus-FAT/ff_fat.c | 1546 +++ .../Source/FreeRTOS-Plus-FAT/ff_file.c | 3080 +++++ .../Source/FreeRTOS-Plus-FAT/ff_format.c | 753 + .../Source/FreeRTOS-Plus-FAT/ff_ioman.c | 1882 +++ .../Source/FreeRTOS-Plus-FAT/ff_locking.c | 325 + .../Source/FreeRTOS-Plus-FAT/ff_locking.org.c | 262 + .../Source/FreeRTOS-Plus-FAT/ff_memory.c | 108 + .../Source/FreeRTOS-Plus-FAT/ff_stdio.c | 2028 +++ .../Source/FreeRTOS-Plus-FAT/ff_string.c | 716 + .../Source/FreeRTOS-Plus-FAT/ff_sys.c | 274 + .../Source/FreeRTOS-Plus-FAT/ff_time.c | 291 + .../include/FreeRTOSFATConfigDefaults.h | 427 + .../include/FreeRTOS_errno_FAT.h | 90 + .../Source/FreeRTOS-Plus-FAT/include/ff_crc.h | 42 + .../FreeRTOS-Plus-FAT/include/ff_devices.h | 64 + .../Source/FreeRTOS-Plus-FAT/include/ff_dir.h | 205 + .../FreeRTOS-Plus-FAT/include/ff_error.h | 260 + .../Source/FreeRTOS-Plus-FAT/include/ff_fat.h | 128 + .../FreeRTOS-Plus-FAT/include/ff_fatdef.h | 109 + .../FreeRTOS-Plus-FAT/include/ff_file.h | 163 + .../FreeRTOS-Plus-FAT/include/ff_format.h | 75 + .../FreeRTOS-Plus-FAT/include/ff_headers.h | 62 + .../FreeRTOS-Plus-FAT/include/ff_ioman.h | 383 + .../FreeRTOS-Plus-FAT/include/ff_locking.h | 91 + .../FreeRTOS-Plus-FAT/include/ff_memory.h | 168 + .../include/ff_old_config_defines.h | 256 + .../FreeRTOS-Plus-FAT/include/ff_stdio.h | 353 + .../FreeRTOS-Plus-FAT/include/ff_string.h | 108 + .../Source/FreeRTOS-Plus-FAT/include/ff_sys.h | 129 + .../FreeRTOS-Plus-FAT/include/ff_time.h | 86 + .../portable/ATSAM4E/ff_sddisk.c | 815 ++ .../portable/ATSAM4E/ff_sddisk_r.c | 552 + .../portable/README_DRIVER_DISCLAIMER.txt | 11 + .../portable/STM32F4xx/ff_sddisk.c | 1121 ++ .../portable/STM32F4xx/stm32f4xx_hal_sd.c | 3561 +++++ .../portable/STM32F4xx/stm32f4xx_hal_sd.h | 802 ++ .../portable/STM32F7xx/ff_sddisk.c | 1204 ++ .../portable/STM32F7xx/stm32f7xx_hal_sd.c | 3600 +++++ .../portable/STM32F7xx/stm32f7xx_hal_sd.h | 788 ++ .../portable/Zynq/ff_sddisk.c | 894 ++ .../FreeRTOS-Plus-FAT/portable/Zynq/xsdps.c | 1577 +++ .../FreeRTOS-Plus-FAT/portable/Zynq/xsdps.h | 221 + .../FreeRTOS-Plus-FAT/portable/Zynq/xsdps_g.c | 69 + .../portable/Zynq/xsdps_hw.h | 1173 ++ .../portable/Zynq/xsdps_info.c | 300 + .../portable/Zynq/xsdps_info.h | 56 + .../portable/Zynq/xsdps_options.c | 978 ++ .../portable/Zynq/xsdps_sinit.c | 95 + .../portable/avr32_uc3/ff_flush.c | 75 + .../portable/avr32_uc3/ff_flush.h | 48 + .../portable/avr32_uc3/ff_locking.c | 343 + .../portable/common/ff_ramdisk.c | 423 + .../portable/common/ff_ramdisk.h | 50 + .../portable/common/ff_sddisk.h | 76 + .../portable/lpc18xx/ff_sddisk.c | 532 + .../Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c | 653 + .../Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c | 1011 ++ .../Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c | 1422 ++ .../Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c | 2324 ++++ .../FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c | 3703 +++++ .../FreeRTOS_Stream_Buffer.c | 199 + .../FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c | 3356 +++++ .../FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c | 1998 +++ .../FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c | 382 + .../Source/FreeRTOS-Plus-TCP/History.txt | 191 + .../FreeRTOS-Plus-TCP/LICENSE_INFORMATION.txt | 19 + .../Source/FreeRTOS-Plus-TCP/ReadMe.url | 5 + .../include/FreeRTOSIPConfigDefaults.h | 568 + .../FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h | 141 + .../FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h | 87 + .../FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h | 137 + .../FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h | 328 + .../include/FreeRTOS_IP_Private.h | 825 ++ .../include/FreeRTOS_Sockets.h | 391 + .../include/FreeRTOS_Stream_Buffer.h | 256 + .../include/FreeRTOS_TCP_IP.h | 80 + .../include/FreeRTOS_TCP_WIN.h | 213 + .../include/FreeRTOS_UDP_IP.h | 56 + .../include/FreeRTOS_errno_TCP.h | 90 + .../include/IPTraceMacroDefaults.h | 193 + .../include/NetworkBufferManagement.h | 70 + .../include/NetworkInterface.h | 44 + .../BufferManagement/BufferAllocation_1.c | 423 + .../BufferManagement/BufferAllocation_2.c | 393 + .../portable/Compiler/GCC/pack_struct_end.h | 46 + .../portable/Compiler/GCC/pack_struct_start.h | 48 + .../portable/Compiler/IAR/pack_struct_end.h | 47 + .../portable/Compiler/IAR/pack_struct_start.h | 49 + .../portable/Compiler/MSVC/pack_struct_end.h | 48 + .../Compiler/MSVC/pack_struct_start.h | 47 + .../Compiler/Renesas/pack_struct_end.h | 60 + .../Compiler/Renesas/pack_struct_start.h | 58 + .../ATSAM4E/NetworkInterface.c | 649 + .../NetworkInterface/ATSAM4E/component/gmac.h | 746 + .../NetworkInterface/ATSAM4E/ethernet_phy.c | 454 + .../NetworkInterface/ATSAM4E/ethernet_phy.h | 281 + .../portable/NetworkInterface/ATSAM4E/gmac.c | 945 ++ .../portable/NetworkInterface/ATSAM4E/gmac.h | 1346 ++ .../NetworkInterface/ATSAM4E/instance/gmac.h | 1349 ++ .../NetworkInterface/Common/phyHandling.c | 712 + .../LPC17xx/NetworkInterface.c | 267 + .../LPC18xx/NetworkInterface.c | 1068 ++ .../NetworkInterface/LPC18xx/ReadMe.txt | 3 + .../README_DRIVER_DISCLAIMER.txt | 10 + .../NetworkInterface/SH2A/NetworkInterface.c | 118 + .../STM32F7xx/NetworkInterface.c | 1193 ++ .../STM32F7xx/stm32f7xx_hal_eth.c | 1835 +++ .../STM32F7xx/stm32f7xx_hal_eth.h | 2214 +++ .../STM32Fxx/NetworkInterface.c | 1181 ++ .../NetworkInterface/STM32Fxx/readme.txt | 20 + .../STM32Fxx/stm32f2xx_hal_eth.h | 6 + .../STM32Fxx/stm32f4xx_hal_eth.c | 1833 +++ .../STM32Fxx/stm32f4xx_hal_eth.h | 6 + .../STM32Fxx/stm32f7xx_hal_eth.h | 6 + .../STM32Fxx/stm32fxx_hal_eth.c | 1800 +++ .../STM32Fxx/stm32fxx_hal_eth.h | 2223 +++ .../NetworkInterface/WinPCap/FaultInjection.c | 173 + .../WinPCap/NetworkInterface.c | 634 + .../NetworkInterface/Zynq/NetworkInterface.c | 424 + .../portable/NetworkInterface/Zynq/README.txt | 25 + .../NetworkInterface/Zynq/uncached_memory.c | 132 + .../NetworkInterface/Zynq/uncached_memory.h | 23 + .../NetworkInterface/Zynq/x_emacpsif.h | 143 + .../NetworkInterface/Zynq/x_emacpsif_dma.c | 647 + .../NetworkInterface/Zynq/x_emacpsif_hw.c | 237 + .../NetworkInterface/Zynq/x_emacpsif_hw.h | 39 + .../Zynq/x_emacpsif_physpeed.c | 581 + .../NetworkInterface/Zynq/x_topology.h | 46 + .../NetworkInterface/include/phyHandling.h | 144 + .../ksz8851snl/NetworkInterface.c | 1272 ++ .../NetworkInterface/ksz8851snl/ksz8851snl.c | 610 + .../NetworkInterface/ksz8851snl/ksz8851snl.h | 67 + .../ksz8851snl/ksz8851snl_reg.h | 473 + .../pic32mzef/BufferAllocation_2.c | 620 + .../pic32mzef/NetworkInterface_eth.c | 889 ++ .../pic32mzef/NetworkInterface_wifi.c | 192 + .../Source/FreeRTOS-Plus-TCP/readme.txt | 18 + .../Include/trcHardwarePort.h | 478 + ...Port - Copy with task notification array.h | 2565 ++++ .../Include/trcKernelPort.h | 2565 ++++ .../Include/trcPortDefines.h | 137 + .../FreeRTOS-Plus-Trace/Include/trcRecorder.h | 1789 +++ .../Source/FreeRTOS-Plus-Trace/ReadMe.url | 5 + .../FreeRTOS-Plus-Trace/config/trcConfig.h | 301 + .../config/trcSnapshotConfig.h | 377 + .../config/trcStreamingConfig.h | 170 + .../Source/FreeRTOS-Plus-Trace/readme.txt | 152 + .../Keil-uVision-Tracealyzer-ITM-Exporter.ini | 52 + .../streamports/ARM_ITM/Readme-ARM_ITM.txt | 28 + .../ARM_ITM/include/trcStreamingPort.h | 91 + .../streamports/ARM_ITM/trcStreamingPort.c | 71 + .../streamports/File/Readme-Streamport.txt | 19 + .../File/include/trcStreamingPort.h | 87 + .../streamports/File/trcStreamingPort.c | 103 + .../Jlink_RTT/Readme-Streamport.txt | 22 + .../streamports/Jlink_RTT/SEGGER_RTT.c | 1447 ++ .../Jlink_RTT/include/SEGGER_RTT.h | 238 + .../Jlink_RTT/include/SEGGER_RTT_Conf.h | 259 + .../Jlink_RTT/include/trcStreamingPort.h | 196 + .../streamports/Jlink_RTT/trcStreamingPort.c | 44 + .../streamports/TCPIP/Readme-Streamport.txt | 22 + .../TCPIP/include/trcStreamingPort.h | 66 + .../streamports/TCPIP/trcStreamingPort.c | 186 + .../streamports/USB_CDC/Readme-Streamport.txt | 27 + .../USB_CDC/include/trcStreamingPort.h | 83 + .../streamports/USB_CDC/trcStreamingPort.c | 246 + .../tracealyzer_readme.txt | 337 + .../FreeRTOS-Plus-Trace/trcKernelPort.c | 833 ++ .../FreeRTOS-Plus-Trace/trcSnapshotRecorder.c | 3105 +++++ .../trcStreamingRecorder.c | 1896 +++ FreeRTOS-Labs/Source/http-parser/LICENSE-MIT | 19 + .../Source/http-parser/http_parser.c | 2498 ++++ .../Source/http-parser/http_parser.h | 439 + .../Source/mbedtls/include/mbedtls/aes.h | 674 + .../Source/mbedtls/include/mbedtls/aesni.h | 138 + .../Source/mbedtls/include/mbedtls/arc4.h | 146 + .../Source/mbedtls/include/mbedtls/aria.h | 370 + .../Source/mbedtls/include/mbedtls/asn1.h | 358 + .../mbedtls/include/mbedtls/asn1write.h | 351 + .../Source/mbedtls/include/mbedtls/base64.h | 98 + .../Source/mbedtls/include/mbedtls/bignum.h | 1000 ++ .../Source/mbedtls/include/mbedtls/blowfish.h | 287 + .../Source/mbedtls/include/mbedtls/bn_mul.h | 915 ++ .../Source/mbedtls/include/mbedtls/camellia.h | 326 + .../Source/mbedtls/include/mbedtls/ccm.h | 310 + .../Source/mbedtls/include/mbedtls/certs.h | 106 + .../Source/mbedtls/include/mbedtls/chacha20.h | 226 + .../mbedtls/include/mbedtls/chachapoly.h | 358 + .../mbedtls/include/mbedtls/check_config.h | 769 ++ .../Source/mbedtls/include/mbedtls/cipher.h | 926 ++ .../mbedtls/include/mbedtls/cipher_internal.h | 153 + .../Source/mbedtls/include/mbedtls/cmac.h | 213 + .../mbedtls/include/mbedtls/compat-1.3.h | 2531 ++++ .../Source/mbedtls/include/mbedtls/config.h | 3521 +++++ .../Source/mbedtls/include/mbedtls/ctr_drbg.h | 380 + .../Source/mbedtls/include/mbedtls/debug.h | 264 + .../Source/mbedtls/include/mbedtls/des.h | 356 + .../Source/mbedtls/include/mbedtls/dhm.h | 1096 ++ .../Source/mbedtls/include/mbedtls/ecdh.h | 428 + .../Source/mbedtls/include/mbedtls/ecdsa.h | 550 + .../Source/mbedtls/include/mbedtls/ecjpake.h | 277 + .../Source/mbedtls/include/mbedtls/ecp.h | 1173 ++ .../mbedtls/include/mbedtls/ecp_internal.h | 299 + .../Source/mbedtls/include/mbedtls/entropy.h | 289 + .../mbedtls/include/mbedtls/entropy_poll.h | 110 + .../Source/mbedtls/include/mbedtls/error.h | 129 + .../Source/mbedtls/include/mbedtls/gcm.h | 326 + .../Source/mbedtls/include/mbedtls/havege.h | 81 + .../Source/mbedtls/include/mbedtls/hkdf.h | 141 + .../mbedtls/include/mbedtls/hmac_drbg.h | 334 + .../Source/mbedtls/include/mbedtls/md.h | 474 + .../Source/mbedtls/include/mbedtls/md2.h | 306 + .../Source/mbedtls/include/mbedtls/md4.h | 311 + .../Source/mbedtls/include/mbedtls/md5.h | 311 + .../mbedtls/include/mbedtls/md_internal.h | 115 + .../include/mbedtls/memory_buffer_alloc.h | 151 + .../Source/mbedtls/include/mbedtls/net.h | 37 + .../mbedtls/include/mbedtls/net_sockets.h | 271 + .../Source/mbedtls/include/mbedtls/nist_kw.h | 184 + .../Source/mbedtls/include/mbedtls/oid.h | 649 + .../Source/mbedtls/include/mbedtls/padlock.h | 126 + .../Source/mbedtls/include/mbedtls/pem.h | 136 + .../Source/mbedtls/include/mbedtls/pk.h | 818 ++ .../mbedtls/include/mbedtls/pk_internal.h | 142 + .../Source/mbedtls/include/mbedtls/pkcs11.h | 175 + .../Source/mbedtls/include/mbedtls/pkcs12.h | 130 + .../Source/mbedtls/include/mbedtls/pkcs5.h | 109 + .../Source/mbedtls/include/mbedtls/platform.h | 419 + .../mbedtls/include/mbedtls/platform_time.h | 82 + .../mbedtls/include/mbedtls/platform_util.h | 185 + .../Source/mbedtls/include/mbedtls/poly1305.h | 192 + .../Source/mbedtls/include/mbedtls/psa_util.h | 482 + .../mbedtls/include/mbedtls/ripemd160.h | 237 + .../Source/mbedtls/include/mbedtls/rsa.h | 1274 ++ .../mbedtls/include/mbedtls/rsa_internal.h | 226 + .../Source/mbedtls/include/mbedtls/sha1.h | 352 + .../Source/mbedtls/include/mbedtls/sha256.h | 297 + .../Source/mbedtls/include/mbedtls/sha512.h | 300 + .../Source/mbedtls/include/mbedtls/ssl.h | 3819 ++++++ .../mbedtls/include/mbedtls/ssl_cache.h | 151 + .../include/mbedtls/ssl_ciphersuites.h | 558 + .../mbedtls/include/mbedtls/ssl_cookie.h | 115 + .../mbedtls/include/mbedtls/ssl_internal.h | 1020 ++ .../mbedtls/include/mbedtls/ssl_ticket.h | 142 + .../mbedtls/include/mbedtls/threading.h | 122 + .../Source/mbedtls/include/mbedtls/timing.h | 153 + .../Source/mbedtls/include/mbedtls/version.h | 112 + .../Source/mbedtls/include/mbedtls/x509.h | 361 + .../Source/mbedtls/include/mbedtls/x509_crl.h | 174 + .../Source/mbedtls/include/mbedtls/x509_crt.h | 999 ++ .../Source/mbedtls/include/mbedtls/x509_csr.h | 307 + .../Source/mbedtls/include/mbedtls/xtea.h | 139 + FreeRTOS-Labs/Source/mbedtls/library/aes.c | 2209 +++ FreeRTOS-Labs/Source/mbedtls/library/aesni.c | 470 + FreeRTOS-Labs/Source/mbedtls/library/arc4.c | 201 + FreeRTOS-Labs/Source/mbedtls/library/aria.c | 1079 ++ .../Source/mbedtls/library/asn1parse.c | 389 + .../Source/mbedtls/library/asn1write.c | 464 + FreeRTOS-Labs/Source/mbedtls/library/base64.c | 293 + FreeRTOS-Labs/Source/mbedtls/library/bignum.c | 2837 ++++ .../Source/mbedtls/library/blowfish.c | 696 + .../Source/mbedtls/library/camellia.c | 1114 ++ FreeRTOS-Labs/Source/mbedtls/library/ccm.c | 552 + FreeRTOS-Labs/Source/mbedtls/library/certs.c | 436 + .../Source/mbedtls/library/chacha20.c | 570 + .../Source/mbedtls/library/chachapoly.c | 540 + FreeRTOS-Labs/Source/mbedtls/library/cipher.c | 1540 +++ .../Source/mbedtls/library/cipher_wrap.c | 2411 ++++ FreeRTOS-Labs/Source/mbedtls/library/cmac.c | 1078 ++ .../Source/mbedtls/library/ctr_drbg.c | 751 + FreeRTOS-Labs/Source/mbedtls/library/debug.c | 438 + FreeRTOS-Labs/Source/mbedtls/library/des.c | 1064 ++ FreeRTOS-Labs/Source/mbedtls/library/dhm.c | 696 + FreeRTOS-Labs/Source/mbedtls/library/ecdh.c | 680 + FreeRTOS-Labs/Source/mbedtls/library/ecdsa.c | 899 ++ .../Source/mbedtls/library/ecjpake.c | 1140 ++ FreeRTOS-Labs/Source/mbedtls/library/ecp.c | 3089 +++++ .../Source/mbedtls/library/ecp_curves.c | 1470 ++ .../Source/mbedtls/library/entropy.c | 721 + .../Source/mbedtls/library/entropy_poll.c | 236 + FreeRTOS-Labs/Source/mbedtls/library/error.c | 918 ++ FreeRTOS-Labs/Source/mbedtls/library/gcm.c | 1020 ++ FreeRTOS-Labs/Source/mbedtls/library/havege.c | 241 + FreeRTOS-Labs/Source/mbedtls/library/hkdf.c | 192 + .../Source/mbedtls/library/hmac_drbg.c | 580 + FreeRTOS-Labs/Source/mbedtls/library/md.c | 475 + FreeRTOS-Labs/Source/mbedtls/library/md2.c | 363 + FreeRTOS-Labs/Source/mbedtls/library/md4.c | 484 + FreeRTOS-Labs/Source/mbedtls/library/md5.c | 498 + .../Source/mbedtls/library/md_wrap.c | 586 + .../mbedtls/library/memory_buffer_alloc.c | 750 + .../Source/mbedtls/library/net_sockets.c | 668 + .../Source/mbedtls/library/nist_kw.c | 755 + FreeRTOS-Labs/Source/mbedtls/library/oid.c | 772 ++ .../Source/mbedtls/library/padlock.c | 170 + FreeRTOS-Labs/Source/mbedtls/library/pem.c | 490 + FreeRTOS-Labs/Source/mbedtls/library/pk.c | 646 + .../Source/mbedtls/library/pk_wrap.c | 1058 ++ FreeRTOS-Labs/Source/mbedtls/library/pkcs11.c | 240 + FreeRTOS-Labs/Source/mbedtls/library/pkcs12.c | 365 + FreeRTOS-Labs/Source/mbedtls/library/pkcs5.c | 417 + .../Source/mbedtls/library/pkparse.c | 1482 ++ .../Source/mbedtls/library/pkwrite.c | 606 + .../Source/mbedtls/library/platform.c | 391 + .../Source/mbedtls/library/platform_util.c | 136 + .../Source/mbedtls/library/poly1305.c | 559 + .../Source/mbedtls/library/ripemd160.c | 559 + FreeRTOS-Labs/Source/mbedtls/library/rsa.c | 2729 ++++ .../Source/mbedtls/library/rsa_internal.c | 492 + FreeRTOS-Labs/Source/mbedtls/library/sha1.c | 573 + FreeRTOS-Labs/Source/mbedtls/library/sha256.c | 586 + FreeRTOS-Labs/Source/mbedtls/library/sha512.c | 636 + .../Source/mbedtls/library/ssl_cache.c | 353 + .../Source/mbedtls/library/ssl_ciphersuites.c | 2373 ++++ .../Source/mbedtls/library/ssl_cli.c | 4065 ++++++ .../Source/mbedtls/library/ssl_cookie.c | 256 + .../Source/mbedtls/library/ssl_srv.c | 4573 +++++++ .../Source/mbedtls/library/ssl_ticket.c | 595 + .../Source/mbedtls/library/ssl_tls.c | 11348 ++++++++++++++++ .../Source/mbedtls/library/threading.c | 187 + FreeRTOS-Labs/Source/mbedtls/library/timing.c | 537 + .../Source/mbedtls/library/version.c | 50 + .../Source/mbedtls/library/version_features.c | 812 ++ FreeRTOS-Labs/Source/mbedtls/library/x509.c | 1069 ++ .../Source/mbedtls/library/x509_create.c | 379 + .../Source/mbedtls/library/x509_crl.c | 773 ++ .../Source/mbedtls/library/x509_crt.c | 3352 +++++ .../Source/mbedtls/library/x509_csr.c | 419 + .../Source/mbedtls/library/x509write_crt.c | 495 + .../Source/mbedtls/library/x509write_csr.c | 287 + FreeRTOS-Labs/Source/mbedtls/library/xtea.c | 277 + FreeRTOS-Labs/readme.txt | 53 + 801 files changed, 356576 insertions(+) create mode 100644 FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/Common/FreeRTOS_TCP_server.c create mode 100644 FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/FTP/FreeRTOS_FTP_commands.c create mode 100644 FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/FTP/FreeRTOS_FTP_server.c create mode 100644 FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/HTTP/FreeRTOS_HTTP_commands.c create mode 100644 FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/HTTP/FreeRTOS_HTTP_server.c create mode 100644 FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/NTP/NTPDemo.c create mode 100644 FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_FTP_commands.h create mode 100644 FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_HTTP_commands.h create mode 100644 FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_TCP_server.h create mode 100644 FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_server_private.h create mode 100644 FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/NTPClient.h create mode 100644 FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/NTPDemo.h create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/File-related-CLI-commands.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/Sample-CLI-commands.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/TCP-related-CLI-commands.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/TCPCommandConsole.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/UARTCommandConsole.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/UDPCommandConsole.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/include/TCPCommandConsole.h create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/include/UDPCommandConsole.h create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_FAT_Demos/CreateAndVerifyExampleFiles.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_FAT_Demos/test/ff_stdio_tests_with_cwd.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_FAT_SL_Demos/CreateExampleFiles/File-system-demo.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/SimpleTCPEchoServer.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TCPEchoClient_SingleTasks.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TFTPServer.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TraceMacros/Example1/DemoIPTrace.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TraceMacros/Example1/DemoIPTrace.h create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/DefaultWebPages.h create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/HTML_for_default_web_pages/ftp.png create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/HTML_for_default_web_pages/index.html create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/HTML_for_default_web_pages/logo.jpg create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/SimpleTCPEchoServer.h create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/TCPEchoClient_SingleTasks.h create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/TFTPServer.h create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/CLICommands/CLI-commands.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/CLICommands/UDPCommandInterpreter.h create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/CLICommands/UDPCommandServer.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/EchoClients/TwoEchoClients.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/EchoClients/TwoEchoClients.h create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/TraceMacros/Example1/DemoIPTrace.c create mode 100644 FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/TraceMacros/Example1/DemoIPTrace.h create mode 100644 FreeRTOS-Labs/Demo/Common/ReadMe.txt create mode 100644 FreeRTOS-Labs/Demo/Common/Utilities/UDPLoggingPrintf.c create mode 100644 FreeRTOS-Labs/Demo/Common/Utilities/date_and_time.c create mode 100644 FreeRTOS-Labs/Demo/Common/Utilities/include/UDPLoggingPrintf.h create mode 100644 FreeRTOS-Labs/Demo/Common/Utilities/include/date_and_time.h create mode 100644 FreeRTOS-Labs/Demo/Common/Utilities/printf-stdarg.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/DemoTasks/SimpleHTTPSExamples.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/Packet32.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/PacketData.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/Win32-Extensions.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/arch.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/bittypes.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/ip6_misc.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/netif.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap-bpf.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap-namedb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap-stdinc.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/bluetooth.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/bpf.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/namedb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/pcap.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/sll.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/usb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/vlan.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/remote-ext.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/wpcap.lib create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/atomic.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/demo_logging.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/demo_logging.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/main.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/mbedtls_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/printf-stdarg.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/FreeRTOSConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/FreeRTOSIPConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/READ_ME_INSTRUCTIONS.url create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/WIN32.vcxproj create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/WIN32.vcxproj.filters create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/demo_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/http_plain_text_demo.sln create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/iot_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/FreeRTOSConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/FreeRTOSIPConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/READ_ME_INSTRUCTIONS.url create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/WIN32.vcxproj create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/WIN32.vcxproj.filters create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/demo_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/https_basic_tls_demo.sln create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/iot_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/FreeRTOSConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/FreeRTOSIPConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/READ_ME_INSTRUCTIONS.url create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/WIN32.vcxproj create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/WIN32.vcxproj.filters create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/demo_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/https_tls_mutual_auth_demo.sln create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/iot_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/readme.txt create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/aws_iot_demo_profile.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/aws_iot_setup_check.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/https_demo_profile.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/mqtt_demo_profile.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/DemoTasks/JobsNotifyNextExamples.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/FreeRTOSConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/FreeRTOSIPConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/READ_ME_INSTRUCTIONS.url create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WIN32.vcxproj create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WIN32.vcxproj.filters create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/Packet32.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/PacketData.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/Win32-Extensions.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/arch.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/bittypes.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/ip6_misc.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/netif.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap-bpf.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap-namedb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap-stdinc.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/bluetooth.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/bpf.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/namedb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/pcap.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/sll.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/usb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/vlan.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/remote-ext.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/wpcap.lib create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/atomic.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/demo_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/demo_logging.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/demo_logging.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/iot_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/jobs_notify_next_demo.sln create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/main.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/mbedtls_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/printf-stdarg.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/readme.txt create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/DemoTasks/LightWeightMQTTExample.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/DemoTasks/SimpleMQTTExamples.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/Run-time-stats-utils.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/Packet32.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/PacketData.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/Win32-Extensions.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/arch.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/bittypes.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/ip6_misc.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/netif.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap-bpf.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap-namedb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap-stdinc.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/bluetooth.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/bpf.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/namedb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/pcap.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/sll.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/usb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/vlan.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/remote-ext.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/wpcap.lib create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/atomic.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/demo_logging.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/demo_logging.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/main.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/mbedtls_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/printf-stdarg.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/FreeRTOSConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/FreeRTOSIPConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/READ_ME_INSTRUCTIONS.url create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/WIN32.vcxproj create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/WIN32.vcxproj.filters create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/demo_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/iot_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/mqtt_basic_tls_demo.sln create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/FreeRTOSConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/FreeRTOSIPConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/READ_ME_INSTRUCTIONS.url create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/WIN32.vcxproj create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/WIN32.vcxproj.filters create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/demo_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/iot_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/mqtt_plain_text_demo.sln create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/trcConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/trcSnapshotConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/FreeRTOSConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/FreeRTOSIPConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/READ_ME_INSTRUCTIONS.url create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/WIN32.vcxproj create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/WIN32.vcxproj.filters create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/demo_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/iot_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/mqtt_tls_mutual_auth_demo.sln create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/readme.txt create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/readme.txt create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/readme.txt create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/readme.txt create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/DemoTasks/ShadowDeviceOperationsExamples.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/FreeRTOSConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/FreeRTOSIPConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/READ_ME_INSTRUCTIONS.url create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WIN32.vcxproj create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WIN32.vcxproj.filters create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/Packet32.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/PacketData.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/Win32-Extensions.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/arch.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/bittypes.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/ip6_misc.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/netif.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap-bpf.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap-namedb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap-stdinc.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/bluetooth.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/bpf.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/namedb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/pcap.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/sll.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/usb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/vlan.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/remote-ext.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/wpcap.lib create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/atomic.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/demo_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/demo_logging.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/demo_logging.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/iot_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/main.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/mbedtls_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/printf-stdarg.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/shadow_device_operations_demo.sln create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_offline/CertificateConfigurator.html create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_offline/js/aws_iot_demo_profile_template.js create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_offline/js/generator.js create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/.gitignore create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/README.md create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/SetupAWS.py create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/aws_iot_demo_profile.templ create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/aws_iot_demo_profile_empty.templ create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/certs.py create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/configure.json create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/misc.py create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/policy.py create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/policy_document.templ create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/thing.py create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/readme.txt create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/readme.txt create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/DemoTasks/SimpleTaskPoolExamples.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/FreeRTOSConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/FreeRTOSIPConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/READ_ME_INSTRUCTIONS.url create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WIN32.vcxproj create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WIN32.vcxproj.filters create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/Packet32.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/PacketData.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/Win32-Extensions.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/arch.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/bittypes.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/ip6_misc.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/netif.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap-bpf.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap-namedb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap-stdinc.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/bluetooth.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/bpf.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/namedb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/pcap.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/sll.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/usb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/vlan.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/remote-ext.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/wpcap.lib create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/demo_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/demo_logging.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/demo_logging.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/iot_config.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/main.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/printf-stdarg.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/task_pool_demo.sln create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/FreeRTOSConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/FreeRTOS_Plus_POSIX_with_actor.sln create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/WIN32.vcxproj create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/WIN32.vcxproj.filters create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/atomic.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/FreeRTOS_POSIX.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/FreeRTOS_POSIX_internal.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/FreeRTOS_POSIX_types.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/FreeRTOS_POSIX_portable_default.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/espressif/esp32_devkitc_esp_wrover_kit/FreeRTOS_POSIX_portable.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/microchip/curiosity_pic32mzef/FreeRTOS_POSIX_portable.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/nxp/lpc54018iotmodule/FreeRTOS_POSIX_portable.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/pc/windows/FreeRTOS_POSIX_portable.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/st/stm32l475_discovery/FreeRTOS_POSIX_portable.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/ti/cc3220_launchpad/FreeRTOS_POSIX_portable.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_clock.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_mqueue.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_barrier.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_cond.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_mutex.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_sched.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_semaphore.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_timer.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_unistd.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_utils.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/errno.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/fcntl.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/mqueue.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/pthread.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/sched.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/semaphore.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/signal.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/sys/types.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/time.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/unistd.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/utils.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/private/iot_doubly_linked_list.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/main.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/posix_demo.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/posix_demo.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/readme.txt create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/CLI-commands.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/SimpleTCPEchoServer.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/SimpleUDPClientAndServer.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TCPEchoClient_SeparateTasks.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TCPEchoClient_SingleTasks.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TCPEchoSelectServer.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TwoUDPEchoClients.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/UDPSelectServer.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/SimpleTCPEchoServer.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/SimpleUDPClientAndServer.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TCPEchoClient_SeparateTasks.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TCPEchoClient_SingleTasks.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TCPEchoSelectServer.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TwoUDPEchoClients.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/UDPSelectServer.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOSConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOSFATConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOSIPConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOS_Plus_TCP_and_FAT.sln create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/Read_Me_Build_Instructions.url create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/Run-time-stats-utils.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/TraceMacros/Example1/DemoIPTrace.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/TraceMacros/Example1/DemoIPTrace.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WIN32.vcxproj create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WIN32.vcxproj.filters create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/Packet32.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/PacketData.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/Win32-Extensions.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/arch.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/bittypes.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/ip6_misc.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/netif.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap-bpf.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap-namedb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap-stdinc.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/bluetooth.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/bpf.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/namedb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/pcap.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/sll.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/usb.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/vlan.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/remote-ext.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/wpcap.lib create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/demo_logging.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/demo_logging.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/main.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/printf-stdarg.c create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/trcConfig.h create mode 100644 FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/trcHardwarePort.h create mode 100644 FreeRTOS-Labs/Demo/instructions-for-FreeRTOS+FAT-demo.url create mode 100644 FreeRTOS-Labs/Demo/instructions-for-FreeRTOS+POSIX-demo.url create mode 100644 FreeRTOS-Labs/Demo/instructions-for-http-demo.url create mode 100644 FreeRTOS-Labs/Demo/instructions-for-jobs-demo.url create mode 100644 FreeRTOS-Labs/Demo/instructions-for-mqtt-demo.url create mode 100644 FreeRTOS-Labs/Demo/instructions-for-shadow-demo.url create mode 100644 FreeRTOS-Labs/Demo/instructions-for-task-pool-demo.url create mode 100644 FreeRTOS-Labs/Demo/readme.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/directories.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/mbedtls/mbedtls_platform_freertos.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/mbedtls/threading_alt.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/iot_taskpool_freertos.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/platform/iot_network_freertos.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/platform/iot_platform_types_freertos.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/types/iot_taskpool_types_freertos.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_clock_freertos.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_network_freertos.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_taskpool_freertos.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_threads_freertos.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/private/iot_taskpool_internal_freertos.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/include/aws_iot.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/include/aws_iot_doc_parser.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_doc_parser.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_operation.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_parser.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_subscription.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_validate.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/directories.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/AWS_IoT_Jobs.url create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/include/aws_iot_jobs.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/include/types/aws_iot_jobs_types.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_api.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_operation.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_serialize.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_static_memory.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_subscription.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/private/aws_iot_jobs_internal.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/AWS_IoT_Shadow.url create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/include/aws_iot_shadow.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/include/types/aws_iot_shadow_types.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_api.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_operation.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_parser.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_static_memory.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_subscription.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/private/aws_iot_shadow_internal.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/directories.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_clock.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_metrics.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_network.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_threads.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/types/iot_platform_types.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/atomic.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_atomic.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_error.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_init.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_linear_containers.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_logging.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_logging_setup.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_static_memory.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/src/iot_logging.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/directories.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/include/iot_https_client.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/include/iot_https_utils.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/include/types/iot_https_types.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/src/iot_https_client.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/src/iot_https_utils.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/src/private/iot_https_internal.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/include/iot_mqtt.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/include/iot_mqtt_serialize.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/include/types/iot_mqtt_types.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_api.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_network.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_operation.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_serialize.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_subscription.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_validate.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/private/iot_mqtt_internal.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/directories.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/readme.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/FreeRTOS_CLI.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/FreeRTOS_CLI.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/History.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/LICENSE_INFORMATION.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/ReadMe.url create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/readme.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/History.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/History2.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ReadMe.url create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_crc.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_dev_support.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_dir.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_error.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_fat.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_file.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_format.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_ioman.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_locking.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_locking.org.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_memory.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_stdio.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_string.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_sys.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_time.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/FreeRTOSFATConfigDefaults.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/FreeRTOS_errno_FAT.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_crc.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_devices.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_dir.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_error.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_fat.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_fatdef.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_file.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_format.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_headers.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_ioman.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_locking.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_memory.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_old_config_defines.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_stdio.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_string.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_sys.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_time.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/ATSAM4E/ff_sddisk.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/ATSAM4E/ff_sddisk_r.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/README_DRIVER_DISCLAIMER.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F4xx/ff_sddisk.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F4xx/stm32f4xx_hal_sd.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F4xx/stm32f4xx_hal_sd.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/ff_sddisk.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/stm32f7xx_hal_sd.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/stm32f7xx_hal_sd.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/ff_sddisk.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_g.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_hw.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_info.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_info.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_options.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_sinit.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/avr32_uc3/ff_flush.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/avr32_uc3/ff_flush.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/avr32_uc3/ff_locking.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_sddisk.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/lpc18xx/ff_sddisk.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/History.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/LICENSE_INFORMATION.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/ReadMe.url create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_2.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_end.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_start.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_end.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_start.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_end.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_start.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_end.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_start.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/component/gmac.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/instance/gmac.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Common/phyHandling.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/ReadMe.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/README_DRIVER_DISCLAIMER.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/NetworkInterface.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/stm32f7xx_hal_eth.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/stm32f7xx_hal_eth.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/readme.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f2xx_hal_eth.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f4xx_hal_eth.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f4xx_hal_eth.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f7xx_hal_eth.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/FaultInjection.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/README.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/uncached_memory.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/uncached_memory.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_topology.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/include/phyHandling.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/ksz8851snl.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/ksz8851snl.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/ksz8851snl_reg.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/BufferAllocation_2.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/NetworkInterface_eth.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/NetworkInterface_wifi.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/readme.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcHardwarePort.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort - Copy with task notification array.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcPortDefines.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcRecorder.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/ReadMe.url create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/config/trcConfig.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/config/trcSnapshotConfig.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/config/trcStreamingConfig.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/readme.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/Keil-uVision-Tracealyzer-ITM-Exporter.ini create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/Readme-ARM_ITM.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/include/trcStreamingPort.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/trcStreamingPort.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/File/Readme-Streamport.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/File/include/trcStreamingPort.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/File/trcStreamingPort.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/Readme-Streamport.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/SEGGER_RTT.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/include/SEGGER_RTT.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/include/SEGGER_RTT_Conf.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/include/trcStreamingPort.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/trcStreamingPort.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/TCPIP/Readme-Streamport.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/TCPIP/include/trcStreamingPort.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/TCPIP/trcStreamingPort.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/USB_CDC/Readme-Streamport.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/USB_CDC/include/trcStreamingPort.h create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/USB_CDC/trcStreamingPort.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/tracealyzer_readme.txt create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/trcKernelPort.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/trcSnapshotRecorder.c create mode 100644 FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/trcStreamingRecorder.c create mode 100644 FreeRTOS-Labs/Source/http-parser/LICENSE-MIT create mode 100644 FreeRTOS-Labs/Source/http-parser/http_parser.c create mode 100644 FreeRTOS-Labs/Source/http-parser/http_parser.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/aes.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/aesni.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/arc4.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/aria.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/asn1.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/asn1write.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/base64.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/bignum.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/blowfish.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/bn_mul.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/camellia.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ccm.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/certs.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/chacha20.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/chachapoly.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/check_config.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/cipher.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/cipher_internal.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/cmac.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/compat-1.3.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/config.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ctr_drbg.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/debug.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/des.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/dhm.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecdh.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecdsa.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecjpake.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecp.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecp_internal.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/entropy.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/entropy_poll.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/error.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/gcm.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/havege.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/hkdf.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/hmac_drbg.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md2.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md4.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md5.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md_internal.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/memory_buffer_alloc.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/net.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/net_sockets.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/nist_kw.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/oid.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/padlock.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pem.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pk.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pk_internal.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pkcs11.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pkcs12.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pkcs5.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/platform.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/platform_time.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/platform_util.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/poly1305.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/psa_util.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ripemd160.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/rsa.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/rsa_internal.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/sha1.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/sha256.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/sha512.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_cache.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_ciphersuites.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_cookie.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_internal.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_ticket.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/threading.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/timing.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/version.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509_crl.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509_crt.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509_csr.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/include/mbedtls/xtea.h create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/aes.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/aesni.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/arc4.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/aria.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/asn1parse.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/asn1write.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/base64.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/bignum.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/blowfish.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/camellia.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ccm.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/certs.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/chacha20.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/chachapoly.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/cipher.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/cipher_wrap.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/cmac.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ctr_drbg.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/debug.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/des.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/dhm.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ecdh.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ecdsa.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ecjpake.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ecp.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ecp_curves.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/entropy.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/entropy_poll.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/error.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/gcm.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/havege.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/hkdf.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/hmac_drbg.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/md.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/md2.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/md4.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/md5.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/md_wrap.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/memory_buffer_alloc.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/net_sockets.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/nist_kw.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/oid.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/padlock.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/pem.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/pk.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/pk_wrap.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/pkcs11.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/pkcs12.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/pkcs5.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/pkparse.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/pkwrite.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/platform.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/platform_util.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/poly1305.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ripemd160.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/rsa.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/rsa_internal.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/sha1.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/sha256.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/sha512.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ssl_cache.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ssl_ciphersuites.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ssl_cli.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ssl_cookie.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ssl_srv.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ssl_ticket.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/ssl_tls.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/threading.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/timing.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/version.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/version_features.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/x509.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/x509_create.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/x509_crl.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/x509_crt.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/x509_csr.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/x509write_crt.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/x509write_csr.c create mode 100644 FreeRTOS-Labs/Source/mbedtls/library/xtea.c create mode 100644 FreeRTOS-Labs/readme.txt diff --git a/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/Common/FreeRTOS_TCP_server.c b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/Common/FreeRTOS_TCP_server.c new file mode 100644 index 000000000..3b9f8fb2f --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/Common/FreeRTOS_TCP_server.c @@ -0,0 +1,353 @@ +/* + * FreeRTOS+TCP V2.0.3 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_TCP_server.h" +#include "FreeRTOS_server_private.h" + +/* Remove the entire file if TCP is not being used. */ +#if( ipconfigUSE_TCP == 1 ) && ( ( ipconfigUSE_HTTP == 1 ) || ( ipconfigUSE_FTP == 1 ) ) + +#if !defined( ARRAY_SIZE ) + #define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] ) +#endif + + +static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket ); +static char *strnew( const char *pcString ); +/* Remove slashes at the end of a path. */ +static void prvRemoveSlash( char *pcDir ); + +TCPServer_t *FreeRTOS_CreateTCPServer( const struct xSERVER_CONFIG *pxConfigs, BaseType_t xCount ) +{ +TCPServer_t *pxServer; +SocketSet_t xSocketSet; + + /* Create a new server. + xPort / xPortAlt : Make the service available on 1 or 2 public port numbers. */ + xSocketSet = FreeRTOS_CreateSocketSet(); + + if( xSocketSet != NULL ) + { + BaseType_t xSize; + + xSize = sizeof( *pxServer ) - sizeof( pxServer->xServers ) + xCount * sizeof( pxServer->xServers[ 0 ] ); + + pxServer = ( TCPServer_t * ) pvPortMallocLarge( xSize ); + if( pxServer != NULL ) + { + struct freertos_sockaddr xAddress; + BaseType_t xNoTimeout = 0; + BaseType_t xIndex; + + memset( pxServer, '\0', xSize ); + pxServer->xServerCount = xCount; + pxServer->xSocketSet = xSocketSet; + + for( xIndex = 0; xIndex < xCount; xIndex++ ) + { + BaseType_t xPortNumber = pxConfigs[ xIndex ].xPortNumber; + + if( xPortNumber > 0 ) + { + Socket_t xSocket; + + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + FreeRTOS_printf( ( "TCP socket on port %d\n", ( int )xPortNumber ) ); + + if( xSocket != FREERTOS_NO_SOCKET ) + { + xAddress.sin_addr = FreeRTOS_GetIPAddress(); // Single NIC, currently not used + xAddress.sin_port = FreeRTOS_htons( xPortNumber ); + + FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) ); + FreeRTOS_listen( xSocket, pxConfigs[ xIndex ].xBackLog ); + + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xNoTimeout, sizeof( BaseType_t ) ); + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xNoTimeout, sizeof( BaseType_t ) ); + + #if( ipconfigHTTP_RX_BUFSIZE > 0 ) + { + if( pxConfigs[ xIndex ].eType == eSERVER_HTTP ) + { + WinProperties_t xWinProps; + + memset( &xWinProps, '\0', sizeof( xWinProps ) ); + /* The parent socket itself won't get connected. The properties below + will be inherited by each new child socket. */ + xWinProps.lTxBufSize = ipconfigHTTP_TX_BUFSIZE; + xWinProps.lTxWinSize = ipconfigHTTP_TX_WINSIZE; + xWinProps.lRxBufSize = ipconfigHTTP_RX_BUFSIZE; + xWinProps.lRxWinSize = ipconfigHTTP_RX_WINSIZE; + + /* Set the window and buffer sizes. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); + } + } + #endif + + FreeRTOS_FD_SET( xSocket, xSocketSet, eSELECT_READ|eSELECT_EXCEPT ); + pxServer->xServers[ xIndex ].xSocket = xSocket; + pxServer->xServers[ xIndex ].eType = pxConfigs[ xIndex ].eType; + pxServer->xServers[ xIndex ].pcRootDir = strnew( pxConfigs[ xIndex ].pcRootDir ); + prvRemoveSlash( ( char * ) pxServer->xServers[ xIndex ].pcRootDir ); + } + } + } + } + else + { + /* Could not allocate the server, delete the socket set */ + FreeRTOS_DeleteSocketSet( xSocketSet ); + } + } + else + { + /* Could not create a socket set, return NULL */ + pxServer = NULL; + } + + return pxServer; +} +/*-----------------------------------------------------------*/ + +static void prvReceiveNewClient( TCPServer_t *pxServer, BaseType_t xIndex, Socket_t xNexSocket ) +{ +TCPClient_t *pxClient = NULL; +BaseType_t xSize = 0; +FTCPWorkFunction fWorkFunc = NULL; +FTCPDeleteFunction fDeleteFunc = NULL; +const char *pcType = "Unknown"; + + /*_RB_ Can the work and delete functions be part of the xSERVER_CONFIG structure + becomes generic, with no pre-processing required? */ + #if( ipconfigUSE_HTTP != 0 ) + { + if( pxServer->xServers[ xIndex ].eType == eSERVER_HTTP ) + { + xSize = sizeof( HTTPClient_t ); + fWorkFunc = xHTTPClientWork; + fDeleteFunc = vHTTPClientDelete; + pcType = "HTTP"; + } + } + #endif /* ipconfigUSE_HTTP != 0 */ + + #if( ipconfigUSE_FTP != 0 ) + { + if( pxServer->xServers[ xIndex ].eType == eSERVER_FTP ) + { + xSize = sizeof( FTPClient_t ); + fWorkFunc = xFTPClientWork; + fDeleteFunc = vFTPClientDelete; + pcType = "FTP"; + } + } + #endif /* ipconfigUSE_FTP != 0 */ + + /* Malloc enough space for a new HTTP-client */ + if( xSize ) + { + pxClient = ( TCPClient_t* ) pvPortMallocLarge( xSize ); + } + + if( pxClient != NULL ) + { + memset( pxClient, '\0', xSize ); + + /* Put the new client in front of the list. */ + pxClient->eType = pxServer->xServers[ xIndex ].eType; + pxClient->pcRootDir = pxServer->xServers[ xIndex ].pcRootDir; + pxClient->pxParent = pxServer; + pxClient->xSocket = xNexSocket; + pxClient->pxNextClient = pxServer->pxClients; + pxClient->fWorkFunction = fWorkFunc; + pxClient->fDeleteFunction = fDeleteFunc; + pxServer->pxClients = pxClient; + + FreeRTOS_FD_SET( xNexSocket, pxServer->xSocketSet, eSELECT_READ|eSELECT_EXCEPT ); + } + else + { + pcType = "closed"; + FreeRTOS_closesocket( xNexSocket ); + } + { + struct freertos_sockaddr xRemoteAddress; + FreeRTOS_GetRemoteAddress( pxClient->xSocket, &xRemoteAddress ); + FreeRTOS_printf( ( "TPC-server: new %s client %xip\n", pcType, (unsigned)FreeRTOS_ntohl( xRemoteAddress.sin_addr ) ) ); + } + + /* Remove compiler warnings in case FreeRTOS_printf() is not used. */ + ( void ) pcType; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_TCPServerWork( TCPServer_t *pxServer, TickType_t xBlockingTime ) +{ +TCPClient_t **ppxClient; +BaseType_t xIndex; +BaseType_t xRc; + + /* Let the server do one working cycle */ + xRc = FreeRTOS_select( pxServer->xSocketSet, xBlockingTime ); + + if( xRc != 0 ) + { + for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ ) + { + struct freertos_sockaddr xAddress; + Socket_t xNexSocket; + socklen_t xSocketLength; + + if( pxServer->xServers[ xIndex ].xSocket == FREERTOS_NO_SOCKET ) + { + continue; + } + + xSocketLength = sizeof( xAddress ); + xNexSocket = FreeRTOS_accept( pxServer->xServers[ xIndex ].xSocket, &xAddress, &xSocketLength); + + if( ( xNexSocket != FREERTOS_NO_SOCKET ) && ( xNexSocket != FREERTOS_INVALID_SOCKET ) ) + { + prvReceiveNewClient( pxServer, xIndex, xNexSocket ); + } + } + } + + ppxClient = &pxServer->pxClients; + + while( ( * ppxClient ) != NULL ) + { + TCPClient_t *pxThis = *ppxClient; + + /* Almost C++ */ + xRc = pxThis->fWorkFunction( pxThis ); + + if (xRc < 0 ) + { + *ppxClient = pxThis->pxNextClient; + /* Close handles, resources */ + pxThis->fDeleteFunction( pxThis ); + /* Free the space */ + vPortFreeLarge( pxThis ); + } + else + { + ppxClient = &( pxThis->pxNextClient ); + } + } +} +/*-----------------------------------------------------------*/ + +static char *strnew( const char *pcString ) +{ +BaseType_t xLength; +char *pxBuffer; + + xLength = strlen( pcString ) + 1; + pxBuffer = ( char * ) pvPortMalloc( xLength ); + if( pxBuffer != NULL ) + { + memcpy( pxBuffer, pcString, xLength ); + } + + return pxBuffer; +} +/*-----------------------------------------------------------*/ + +static void prvRemoveSlash( char *pcDir ) +{ +BaseType_t xLength = strlen( pcDir ); + + while( ( xLength > 0 ) && ( pcDir[ xLength - 1 ] == '/' ) ) + { + pcDir[ --xLength ] = '\0'; + } +} +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SIGNALS != 0 ) + + /* FreeRTOS_TCPServerWork() calls select(). + The two functions below provide a possibility to interrupt + the call to select(). After the interruption, resume + by calling FreeRTOS_TCPServerWork() again. */ + BaseType_t FreeRTOS_TCPServerSignal( TCPServer_t *pxServer ) + { + BaseType_t xIndex; + BaseType_t xResult = pdFALSE; + for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ ) + { + if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET ) + { + FreeRTOS_SignalSocket( pxServer->xServers[ xIndex ].xSocket ); + xResult = pdTRUE; + break; + } + } + + return xResult; + } + +#endif /* ipconfigSUPPORT_SIGNALS */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SIGNALS != 0 ) + + /* Same as above: this function may be called from an ISR, + for instance a GPIO interrupt. */ + BaseType_t FreeRTOS_TCPServerSignalFromISR( TCPServer_t *pxServer, BaseType_t *pxHigherPriorityTaskWoken ) + { + BaseType_t xIndex; + BaseType_t xResult = pdFALSE; + for( xIndex = 0; xIndex < pxServer->xServerCount; xIndex++ ) + { + if( pxServer->xServers[ xIndex ].xSocket != FREERTOS_NO_SOCKET ) + { + FreeRTOS_SignalSocketFromISR( pxServer->xServers[ xIndex ].xSocket, pxHigherPriorityTaskWoken ); + xResult = pdTRUE; + break; + } + } + + return xResult; + } +#endif /* ipconfigSUPPORT_SIGNALS */ +/*-----------------------------------------------------------*/ + +#endif /* ( ipconfigUSE_TCP == 1 ) && ( ( ipconfigUSE_HTTP == 1 ) || ( ipconfigUSE_FTP == 1 ) ) */ diff --git a/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/FTP/FreeRTOS_FTP_commands.c b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/FTP/FreeRTOS_FTP_commands.c new file mode 100644 index 000000000..b399f3648 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/FTP/FreeRTOS_FTP_commands.c @@ -0,0 +1,74 @@ +/* + * FreeRTOS+TCP V2.0.3 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_FTP_commands.h" + +const FTPCommand_t xFTPCommands[ FTP_CMD_COUNT ] = +{ +/* cmdLen cmdName[7] cmdType checkLogin checkNullArg */ + { 4, "USER", ECMD_USER, pdFALSE, pdFALSE }, + { 4, "PASS", ECMD_PASS, pdFALSE, pdFALSE }, + { 4, "ACCT", ECMD_ACCT, pdTRUE, pdFALSE }, + { 3, "CWD", ECMD_CWD, pdTRUE, pdTRUE }, + { 4, "CDUP", ECMD_CDUP, pdTRUE, pdFALSE }, + { 4, "SMNT", ECMD_SMNT, pdTRUE, pdFALSE }, + { 4, "QUIT", ECMD_QUIT, pdTRUE, pdFALSE }, + { 4, "REIN", ECMD_REIN, pdTRUE, pdFALSE }, + { 4, "PORT", ECMD_PORT, pdTRUE, pdFALSE }, + { 4, "PASV", ECMD_PASV, pdTRUE, pdFALSE }, + { 4, "TYPE", ECMD_TYPE, pdTRUE, pdFALSE }, + { 4, "STRU", ECMD_STRU, pdTRUE, pdFALSE }, + { 4, "MODE", ECMD_MODE, pdTRUE, pdFALSE }, + { 4, "RETR", ECMD_RETR, pdTRUE, pdTRUE }, + { 4, "STOR", ECMD_STOR, pdTRUE, pdTRUE }, + { 4, "STOU", ECMD_STOU, pdTRUE, pdFALSE }, + { 4, "APPE", ECMD_APPE, pdTRUE, pdFALSE }, + { 4, "ALLO", ECMD_ALLO, pdTRUE, pdFALSE }, + { 4, "REST", ECMD_REST, pdTRUE, pdFALSE }, + { 4, "RNFR", ECMD_RNFR, pdTRUE, pdTRUE }, + { 4, "RNTO", ECMD_RNTO, pdTRUE, pdTRUE }, + { 4, "ABOR", ECMD_ABOR, pdTRUE, pdFALSE }, + { 4, "SIZE", ECMD_SIZE, pdTRUE, pdTRUE }, + { 4, "MDTM", ECMD_MDTM, pdTRUE, pdTRUE }, + { 4, "DELE", ECMD_DELE, pdTRUE, pdTRUE }, + { 3, "RMD", ECMD_RMD, pdTRUE, pdTRUE }, + { 3, "MKD", ECMD_MKD, pdTRUE, pdTRUE }, + { 3, "PWD", ECMD_PWD, pdTRUE, pdFALSE }, + { 4, "LIST", ECMD_LIST, pdTRUE, pdFALSE }, + { 4, "NLST", ECMD_NLST, pdTRUE, pdFALSE }, + { 4, "SITE", ECMD_SITE, pdTRUE, pdFALSE }, + { 4, "SYST", ECMD_SYST, pdFALSE, pdFALSE }, + { 4, "FEAT", ECMD_FEAT, pdFALSE, pdFALSE }, + { 4, "STAT", ECMD_STAT, pdTRUE, pdFALSE }, + { 4, "HELP", ECMD_HELP, pdFALSE, pdFALSE }, + { 4, "NOOP", ECMD_NOOP, pdFALSE, pdFALSE }, + { 4, "EMPT", ECMD_EMPTY, pdFALSE, pdFALSE }, + { 4, "CLOS", ECMD_CLOSE, pdTRUE, pdFALSE }, + { 4, "UNKN", ECMD_UNKNOWN, pdFALSE, pdFALSE }, +}; diff --git a/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/FTP/FreeRTOS_FTP_server.c b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/FTP/FreeRTOS_FTP_server.c new file mode 100644 index 000000000..a2a6ba155 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/FTP/FreeRTOS_FTP_server.c @@ -0,0 +1,2637 @@ +/* + * FreeRTOS+TCP V2.0.3 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* Standard includes. */ +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "portmacro.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_TCP_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_Stream_Buffer.h" + +/* FreeRTOS Protocol includes. */ +#include "FreeRTOS_FTP_commands.h" +#include "FreeRTOS_TCP_server.h" +#include "FreeRTOS_server_private.h" + +/* Remove the whole file if FTP is not supported. */ +#if( ipconfigUSE_FTP == 1 ) + +#ifndef HTTP_SERVER_BACKLOG + #define HTTP_SERVER_BACKLOG ( 12 ) +#endif + +#if !defined( ARRAY_SIZE ) + #define ARRAY_SIZE( x ) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] ) +#endif + +#if defined(__WIN32__) && !defined(ipconfigFTP_FS_USES_BACKSLAH) + #define ipconfigFTP_FS_USES_BACKSLAH 1 +#endif + +/* Some defines to make the code more readbale */ +#define pcCOMMAND_BUFFER pxClient->pxParent->pcCommandBuffer +#define pcNEW_DIR pxClient->pxParent->pcNewDir +#define pcFILE_BUFFER pxClient->pxParent->pcFileBuffer + +/* This FTP server will only do binary transfers */ +#define TMODE_BINARY 1 +#define TMODE_ASCII 2 +#define TMODE_7BITS 3 +#define TMODE_8BITS 4 + +/* Ascii character definitions. */ +#define ftpASCII_CR 13 +#define ftpASCII_LF 10 + +#if defined( FTP_WRITES_ALIGNED ) || defined( ipconfigFTP_WRITES_ALIGNED ) + #error Name change : please rename the define to the new name 'ipconfigFTP_ZERO_COPY_ALIGNED_WRITES' +#endif + +/* + * ipconfigFTP_ZERO_COPY_ALIGNED_WRITES : experimental optimisation option. + * If non-zero, receiving data will be done with the zero-copy method and also + * writes to disk will be done with sector-alignment as much as possible. + */ +#ifndef ipconfigFTP_ZERO_COPY_ALIGNED_WRITES + #define ipconfigFTP_ZERO_COPY_ALIGNED_WRITES 0 +#endif + +/* + * This module only has 2 public functions: + */ +BaseType_t xFTPClientWork( TCPClient_t *pxClient ); +void vFTPClientDelete( TCPClient_t *pxClient ); + +/* + * Process a single command. + */ +static BaseType_t prvProcessCommand( FTPClient_t *pxClient, BaseType_t xIndex, char *pcRestCommand ); + +/* + * Create a socket for a data connection to the FTP client. + */ +static BaseType_t prvTransferConnect( FTPClient_t *pxClient, BaseType_t xDoListen ); + +/* + * Either call listen() or connect() to start the transfer connection. + */ +static BaseType_t prvTransferStart( FTPClient_t *pxClient ); + +/* + * See if the socket has got connected or disconnected. Close the socket if + * necessary. + */ +static void prvTransferCheck( FTPClient_t *pxClient ); + +/* + * Close the data socket and issue some informative logging. + */ +static void prvTransferCloseSocket( FTPClient_t *pxClient ); + +/* + * Close the file handle (pxReadHandle or pxWriteHandle). + */ +static void prvTransferCloseFile( FTPClient_t *pxClient ); + +/* + * Close a directory (-handle). + */ +static void prvTransferCloseDir( FTPClient_t *pxClient ); + +/* + * Translate a string (indicating a transfer type) to a number. + */ +static BaseType_t prvGetTransferType( const char *pcType ); + +#if( ipconfigHAS_PRINTF != 0 ) + /* + * For nice logging: write an amount (number of bytes), e.g. 3512200 as + * "3.45 MB" + */ + static const char *pcMkSize( uint32_t ulAmount, char *pcBuffer, BaseType_t xBufferSize ); +#endif + +#if( ipconfigHAS_PRINTF != 0 ) + /* + * Calculate the average as bytes-per-second, when amount and milliseconds + * are known. + */ + static uint32_t ulGetAverage( uint32_t ulAmount, TickType_t xDeltaMs ); +#endif + +/* + * A port command looks like: PORT h1,h2,h3,h4,p1,p2. Parse it and translate it + * to an IP-address and a port number. + */ +static UBaseType_t prvParsePortData( const char *pcCommand, uint32_t *pulIPAddress ); + +/* + * CWD: Change current working directory. + */ + +static BaseType_t prvChangeDir( FTPClient_t *pxClient, char *pcDirectory ); + +/* + * RNFR: Rename from ... + */ +static BaseType_t prvRenameFrom( FTPClient_t *pxClient, const char *pcFileName ); + +/* + * RNTO: Rename to ... + */ +static BaseType_t prvRenameTo( FTPClient_t *pxClient, const char *pcFileName ); + +/* + * SITE: Change file permissions. + */ +static BaseType_t prvSiteCmd( FTPClient_t *pxClient, char *pcRestCommand ); + +/* + * DELE: Delete a file. + */ +static BaseType_t prvDeleteFile( FTPClient_t *pxClient, char *pcFileName ); + +/* + * SIZE: get the size of a file (xSendDate = 0). + * MDTM: get data and time properties (xSendDate = 1). + */ +static BaseType_t prvSizeDateFile( FTPClient_t *pxClient, char *pcFileName, BaseType_t xSendDate ); + +/* + * MKD: Make / create a directory (xDoRemove = 0). + * RMD: Remove a directory (xDoRemove = 1). + */ +static BaseType_t prvMakeRemoveDir( FTPClient_t *pxClient, const char *pcDirectory, BaseType_t xDoRemove ); + +/* + * The next three commands: LIST, RETR and STOR all require a data socket. + * The data connection is either started with a 'PORT' or a 'PASV' command. + * Each of the commands has a prepare- (Prep) and a working- (Work) function. + * The Work function should be called as long as the data socket is open, and + * there is data to be transmitted. + */ + +/* + * LIST: Send a directory listing in Unix style. + */ +static BaseType_t prvListSendPrep( FTPClient_t *pxClient ); +static BaseType_t prvListSendWork( FTPClient_t *pxClient ); + +/* + * RETR: Send a file to the FTP client. + */ +static BaseType_t prvRetrieveFilePrep( FTPClient_t *pxClient, char *pcFileName ); +static BaseType_t prvRetrieveFileWork( FTPClient_t *pxClient ); + +/* + * STOR: Receive a file from the FTP client and store it. + */ +static BaseType_t prvStoreFilePrep( FTPClient_t *pxClient, char *pcFileName ); +static BaseType_t prvStoreFileWork( FTPClient_t *pxClient ); + +/* + * Print/format a single directory entry in Unix style. + */ +static BaseType_t prvGetFileInfoStat( FF_DirEnt_t *pxEntry, char *pcLine, BaseType_t xMaxLength ); + +/* + * Send a reply to a socket, either the command- or the data-socket. + */ +static BaseType_t prvSendReply( Socket_t xSocket, const char *pcBuffer, BaseType_t xLength ); + +/* + * Prepend the root directory (if any), plus the current working directory + * (always), to get an absolute path. + */ +BaseType_t xMakeAbsolute( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcPath ); + +/* + +####### ##### ###### # # ## + # ## # # # # # # # # + # # # # # # # + # # # # # # # #### ### ## # # + ##### # ##### # # # # # # # # # # + # # # # # # # # # ## # #### + # # # ## ## # # # # # + # # # ## ## # # # # # +#### #### #### ## ## #### #### ## ## + + * xFTPClientWork() + * will be called by FreeRTOS_TCPServerWork(), after select has expired(). + * FD_ISSET will not be used. This work function will always be called at + * regular intervals, and also after a select() event has occurred. + */ +BaseType_t xFTPClientWork( TCPClient_t *pxTCPClient ) +{ +FTPClient_t *pxClient = ( FTPClient_t * ) pxTCPClient; +BaseType_t xRc; + + if( pxClient->bits.bHelloSent == pdFALSE_UNSIGNED ) + { + BaseType_t xLength; + + pxClient->bits.bHelloSent = pdTRUE_UNSIGNED; + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "220 Welcome to the FreeRTOS+TCP FTP server\r\n" ); + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + } + + /* Call recv() in a non-blocking way, to see if there is an FTP command + sent to this server. */ + xRc = FreeRTOS_recv( pxClient->xSocket, ( void * )pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), 0 ); + + if( xRc > 0 ) + { + BaseType_t xIndex; + const FTPCommand_t *pxCommand; + char *pcRestCommand; + + if( xRc < ( BaseType_t ) sizeof( pcCOMMAND_BUFFER ) ) + { + pcCOMMAND_BUFFER[ xRc ] = '\0'; + } + + while( xRc && ( ( pcCOMMAND_BUFFER[ xRc - 1 ] == ftpASCII_CR ) || ( pcCOMMAND_BUFFER[ xRc - 1 ] == ftpASCII_LF ) ) ) + { + pcCOMMAND_BUFFER[ --xRc ] = '\0'; + } + + /* Now iterate through a list of FTP commands, and look for a match. */ + pxCommand = xFTPCommands; + pcRestCommand = pcCOMMAND_BUFFER; + for( xIndex = 0; xIndex < FTP_CMD_COUNT - 1; xIndex++, pxCommand++ ) + { + BaseType_t xLength; + + /* The length of each command is stored as well, just to be a bit + quicker here. */ + xLength = pxCommand->xCommandLength; + + if( ( xRc >= xLength ) && ( memcmp( ( const void * ) pxCommand->pcCommandName, ( const void * ) pcCOMMAND_BUFFER, xLength ) == 0 ) ) + { + /* A match with an existing command is found. Skip any + whitespace to get the first parameter. */ + pcRestCommand += xLength; + while( ( *pcRestCommand == ' ' ) || ( *pcRestCommand == '\t' ) ) + { + pcRestCommand++; + } + break; + } + } + + /* If the command received was not recognised, xIndex will point to a + fake entry called 'ECMD_UNKNOWN'. */ + prvProcessCommand( pxClient, xIndex, pcRestCommand ); + } + else if( xRc < 0 ) + { + /* The connection will be closed and the client will be deleted. */ + FreeRTOS_printf( ( "xFTPClientWork: xRc = %ld\n", xRc ) ); + } + + /* Does it have an open data connection? */ + if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) + { + /* See if the connection has changed. */ + prvTransferCheck( pxClient ); + + /* "pcConnectionAck" contains a string like: + "Response: 150 Accepted data connection from 192.168.2.3:6789" + The socket can only be used once this acknowledgement has been sent. */ + if( ( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) && ( pxClient->pcConnectionAck[ 0 ] == '\0' ) ) + { + BaseType_t xClientRc = 0; + + if( pxClient->bits1.bDirHasEntry ) + { + /* Still listing a directory. */ + xClientRc = prvListSendWork( pxClient ); + } + else if( pxClient->pxReadHandle != NULL ) + { + /* Sending a file. */ + xClientRc = prvRetrieveFileWork( pxClient ); + } + else if( pxClient->pxWriteHandle != NULL ) + { + /* Receiving a file. */ + xClientRc = prvStoreFileWork( pxClient ); + } + + if( xClientRc < 0 ) + { + prvTransferCloseSocket( pxClient ); + prvTransferCloseFile( pxClient ); + } + } + } + + return xRc; +} +/*-----------------------------------------------------------*/ + +static void prvTransferCloseDir( FTPClient_t *pxClient ) +{ + /* Nothing to close for +FAT. */ + ( void ) pxClient; +} +/*-----------------------------------------------------------*/ + +void vFTPClientDelete( TCPClient_t *pxTCPClient ) +{ +FTPClient_t *pxClient = ( FTPClient_t * ) pxTCPClient; + + /* Close any directory-listing-handles (not used by +FAT ). */ + prvTransferCloseDir( pxClient ); + /* Close the data-socket. */ + prvTransferCloseSocket( pxClient ); + /* Close any open file handle. */ + prvTransferCloseFile( pxClient ); + + /* Close the FTP command socket */ + if( pxClient->xSocket != FREERTOS_NO_SOCKET ) + { + FreeRTOS_FD_CLR( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_ALL ); + FreeRTOS_closesocket( pxClient->xSocket ); + pxClient->xSocket = FREERTOS_NO_SOCKET; + } +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvProcessCommand( FTPClient_t *pxClient, BaseType_t xIndex, char *pcRestCommand ) +{ +const FTPCommand_t *pxFTPCommand = &( xFTPCommands[ xIndex ] ); +const char *pcMyReply = NULL; +BaseType_t xResult = 0; + + if( ( pxFTPCommand->ucCommandType != ECMD_PASS ) && ( pxFTPCommand->ucCommandType != ECMD_PORT ) ) + { + FreeRTOS_printf( ( " %s %s\n", pxFTPCommand->pcCommandName, pcRestCommand ) ); + } + + if( ( pxFTPCommand->checkLogin != pdFALSE ) && ( pxClient->bits.bLoggedIn == pdFALSE_UNSIGNED ) ) + { + pcMyReply = REPL_530; /* Please first log in. */ + } + else if( ( pxFTPCommand->checkNullArg != pdFALSE ) && ( ( pcRestCommand == NULL ) || ( pcRestCommand[ 0 ] == '\0' ) ) ) + { + pcMyReply = REPL_501; /* Command needs a parameter. */ + } + + if( pcMyReply == NULL ) + { + switch( pxFTPCommand->ucCommandType ) + { + case ECMD_USER: /* User. */ + /* User name has been entered, expect password. */ + pxClient->bits.bStatusUser = pdTRUE_UNSIGNED; + + #if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 )/*_RB_ Needs defaulting and adding to the web documentation. */ + { + /* Save the user name in 'pcFileName'. */ + snprintf( pxClient->pcFileName, sizeof( pxClient->pcFileName ), "%s", pcRestCommand ); + + /* The USER name is presented to the application. The function + may return a const string like "331 Please enter your + password\r\n". */ + pcMyReply = pcApplicationFTPUserHook( pxClient->pcFileName ); + if( pcMyReply == NULL ) + { + pcMyReply = REPL_331_ANON; + } + } + #else + { + /* No password checks, any password will be accepted. */ + pcMyReply = REPL_331_ANON; + } + #endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 */ + + #if( ipconfigFTP_HAS_USER_PROPERTIES_HOOK != 0 )/*_RB_ Needs defaulting and adding to the web documentation. */ + { + FTPUserProperties_t xProperties; + + xProperties.pcRootDir = pxClient->pcRootDir; + xProperties.xReadOnly = pdFALSE; + xProperties.usPortNumber = pxClient->usClientPort; + vApplicationFTPUserPropertiesHook( pxClient->pcFileName, &( xProperties ) ); + + if( xProperties.pcRootDir != NULL ) + { + pxClient->pcRootDir = xProperties.pcRootDir; + } + pxClient->bits.bReadOnly = ( xProperties.xReadOnly != pdFALSE_UNSIGNED ); + } + #endif /* ipconfigFTP_HAS_USER_PROPERTIES_HOOK */ + break; + + case ECMD_PASS: /* Password. */ + pxClient->ulRestartOffset = 0; + if( pxClient->bits.bStatusUser == pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_503; /* "503 Bad sequence of commands.\r\n". */ + } + else + { + BaseType_t xAllow; + + pxClient->bits.bStatusUser = pdFALSE_UNSIGNED; + #if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 ) + { + xAllow = xApplicationFTPPasswordHook( pxClient->pcFileName, pcRestCommand ); + } + #else + { + xAllow = 1; + } + #endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */ + + if( xAllow > 0 ) + { + pxClient->bits.bLoggedIn = pdTRUE_UNSIGNED; /* Client has now logged in. */ + pcMyReply = "230 OK. Current directory is /\r\n"; + } + else + { + pcMyReply = "530 Login incorrect\r\n"; /* 530 Login incorrect. */ + } + + strcpy( pxClient->pcCurrentDir, ( const char * ) "/" ); + } + break; + + case ECMD_SYST: /* System. */ + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "215 UNIX Type: L8\r\n" ); + pcMyReply = pcCOMMAND_BUFFER; + break; + + case ECMD_PWD: /* Get working directory. */ + xMakeRelative( pxClient, pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), pxClient->pcCurrentDir ); + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), REPL_257_PWD, pcFILE_BUFFER ); + pcMyReply = pcCOMMAND_BUFFER; + break; + + case ECMD_REST: + if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_553_READ_ONLY; + } + else + { + const char *pcPtr = pcRestCommand; + + while( *pcPtr == ' ' ) + { + pcPtr++; + } + + if( ( *pcPtr >= '0' ) && ( *pcPtr <= '9' ) ) + { + sscanf( pcPtr, "%lu", &pxClient->ulRestartOffset ); + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "350 Restarting at %lu. Send STORE or RETRIEVE\r\n", pxClient->ulRestartOffset ); + pcMyReply = pcCOMMAND_BUFFER; + } + else + { + pcMyReply = REPL_500; /* 500 Syntax error, command unrecognised. */ + } + } + break; + + case ECMD_NOOP: /* NOP operation */ + if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) + { + pcMyReply = REPL_200_PROGRESS; + } + else + { + pcMyReply = REPL_200; + } + break; + + case ECMD_TYPE: /* Ask or set transfer type. */ + { + /* e.g. "TYPE I" for Images (binary). */ + BaseType_t xType = prvGetTransferType( pcRestCommand ); + + if( xType < 0 ) + { + /* TYPE not recognised. */ + pcMyReply = REPL_500; + } + else + { + pxClient->xTransType = xType; + pcMyReply = REPL_200; + } + } + break; + + case ECMD_PASV: /* Enter passive mode. */ + /* Connect passive: Server will listen() and wait for a connection. + Start up a new data connection with 'xDoListen' set to true. */ + if( prvTransferConnect( pxClient, pdTRUE ) == pdFALSE ) + { + pcMyReply = REPL_502; + } + else + { + uint32_t ulIP; + uint16_t ulPort; + struct freertos_sockaddr xLocalAddress; + struct freertos_sockaddr xRemoteAddress; + + FreeRTOS_GetLocalAddress( pxClient->xTransferSocket, &xLocalAddress ); + FreeRTOS_GetRemoteAddress( pxClient->xSocket, &xRemoteAddress ); + + ulIP = FreeRTOS_ntohl( xLocalAddress.sin_addr ); + pxClient->ulClientIP = FreeRTOS_ntohl( xRemoteAddress.sin_addr ); + ulPort = FreeRTOS_ntohs( xLocalAddress.sin_port ); + + pxClient->usClientPort = FreeRTOS_ntohs( xRemoteAddress.sin_port ); + + /* REPL_227_D "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d). */ + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), REPL_227_D, + ( unsigned )ulIP >> 24, + ( unsigned )( ulIP >> 16 ) & 0xFF, + ( unsigned )( ulIP >> 8 ) & 0xFF, + ( unsigned )ulIP & 0xFF, + ( unsigned )ulPort >> 8, + ( unsigned )ulPort & 0xFF ); + + pcMyReply = pcCOMMAND_BUFFER; + } + break; + + case ECMD_PORT: /* Active connection to the client. */ + /* The client uses this command to tell the server to what + client-side port the server should contact; use of this command + indicates an active data transfer. e.g. PORT 192,168,1,2,4,19. */ + { + uint32_t ulIPAddress = 0; + UBaseType_t uxPort; + + uxPort = prvParsePortData( pcRestCommand, &ulIPAddress ); + FreeRTOS_printf( (" PORT %lxip:%ld\n", ulIPAddress, uxPort ) ); + + if( uxPort == 0u ) + { + pcMyReply = REPL_501; + } + else if( prvTransferConnect( pxClient, pdFALSE ) == pdFALSE ) + { + /* Call prvTransferConnect() with 'xDoListen' = false for an + active connect(). */ + pcMyReply = REPL_501; + } + else + { + pxClient->usClientPort = ( uint16_t ) uxPort; + pxClient->ulClientIP = ulIPAddress; + FreeRTOS_printf( ("Client address %lxip:%lu\n", ulIPAddress, uxPort ) ); + pcMyReply = REPL_200; + } + } + break; + + case ECMD_CWD: /* Change current working directory. */ + prvChangeDir( pxClient, pcRestCommand ); + break; + + case ECMD_RNFR: + if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_553_READ_ONLY; + } + else + { + prvRenameFrom( pxClient, pcRestCommand ); + } + break; + + case ECMD_RNTO: + if( pxClient->bits.bInRename == pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_503; /* "503 Bad sequence of commands. */ + } + else + { + prvRenameTo( pxClient, pcRestCommand ); + } + break; + + case ECMD_SITE: /* Set file permissions */ + if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_553_READ_ONLY; + } + else if( prvSiteCmd( pxClient, pcRestCommand ) == pdFALSE ) + { + pcMyReply = REPL_202; + } + break; + + case ECMD_DELE: + if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_553_READ_ONLY; + } + else + { + prvDeleteFile( pxClient, pcRestCommand ); + } + break; + + case ECMD_MDTM: + prvSizeDateFile( pxClient, pcRestCommand, pdTRUE ); + break; + + case ECMD_SIZE: + if( pxClient->pxWriteHandle != NULL ) + { + /* This SIZE query is probably about a file which is now being + received. If so, return the value of pxClient->ulRecvBytes, + pcRestCommand points to 'pcCommandBuffer', make it free by + copying it to pcNewDir. */ + + xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pcRestCommand ); + + if( strcmp( pcNEW_DIR, pcRestCommand ) == 0 ) + { + BaseType_t xCount; + for( xCount = 0; xCount < 3 && pxClient->pxWriteHandle; xCount++ ) + { + prvStoreFileWork( pxClient ); + } + if( pxClient->pxWriteHandle != NULL ) + { + /* File being queried is still open, return number of + bytes received until now. */ + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 %lu\r\n", pxClient->ulRecvBytes ); + pcMyReply = pcCOMMAND_BUFFER; + } /* otherwise, do a normal stat(). */ + } + strcpy( pcRestCommand, pcNEW_DIR ); + } + if( pcMyReply == NULL ) + { + prvSizeDateFile( pxClient, pcRestCommand, pdFALSE ); + } + break; + case ECMD_MKD: + case ECMD_RMD: + if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_553_READ_ONLY; + } + else + { + prvMakeRemoveDir( pxClient, pcRestCommand, pxFTPCommand->ucCommandType == ECMD_RMD ); + } + break; + case ECMD_CDUP: + prvChangeDir( pxClient, ".." ); + break; + + case ECMD_QUIT: + prvSendReply( pxClient->xSocket, REPL_221, 0 ); + pxClient->bits.bLoggedIn = pdFALSE_UNSIGNED; + break; + case ECMD_LIST: + case ECMD_RETR: + case ECMD_STOR: + if( ( pxClient->xTransferSocket == FREERTOS_NO_SOCKET ) && + ( ( pxFTPCommand->ucCommandType != ECMD_STOR ) || + ( pxClient->bits1.bEmptyFile == pdFALSE_UNSIGNED ) ) ) + { + /* Sending "425 Can't open data connection." : + Before receiving any of these commands, there must have been a + PORT or PASV command, which causes the creation of a data socket. */ + /* There is one exception: a STOR command is received while the + data connection has already been closed. This is tested with the + 'bEmptyFile' flag. */ + pcMyReply = REPL_425; + } + else + { + /* In case an empty file was received ( bits1.bEmptyFile ), the + transfer socket never delivered any data. Check if the transfer + socket is still open: */ + if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) + { + prvTransferCheck( pxClient ); + } + switch( pxFTPCommand->ucCommandType ) + { + case ECMD_LIST: + prvListSendPrep( pxClient ); + break; + case ECMD_RETR: + prvRetrieveFilePrep( pxClient, pcRestCommand ); + break; + case ECMD_STOR: + if( pxClient->bits.bReadOnly != pdFALSE_UNSIGNED ) + { + pcMyReply = REPL_553_READ_ONLY; + } + else + { + prvStoreFilePrep( pxClient, pcRestCommand ); + if( pxClient->bits1.bEmptyFile != pdFALSE_UNSIGNED ) + { + /* Although the 'xTransferSocket' is closed already, + call this function just for the logging. */ + prvTransferCloseSocket( pxClient ); + + /* Close an empty file. */ + prvTransferCloseFile( pxClient ); + } + } + break; + } + } + break; + + case ECMD_FEAT: + { + static const char pcFeatAnswer[] = + "211-Features:\x0a" + /* The MDTM command is only allowed when + there is support for date&time. */ + #if( ffconfigTIME_SUPPORT != 0 ) + " MDTM\x0a" + #endif + " REST STREAM\x0a" + " SIZE\x0d\x0a" + "211 End\x0d\x0a"; + pcMyReply = pcFeatAnswer; + } + break; + + case ECMD_UNKNOWN: + FreeRTOS_printf( ("ftp::processCmd: Cmd %s unknown\n", pcRestCommand ) ); + pcMyReply = REPL_500; + break; + } + } + if( pxFTPCommand->ucCommandType != ECMD_RNFR ) + { + pxClient->bits.bInRename = pdFALSE_UNSIGNED; + } + + if( pcMyReply != NULL ) + { + xResult = prvSendReply( pxClient->xSocket, pcMyReply, strlen( pcMyReply ) ); + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvTransferConnect( FTPClient_t *pxClient, BaseType_t xDoListen ) +{ +Socket_t xSocket; +BaseType_t xResult; + + /* Open a socket for a data connection with the FTP client. + Happens after a PORT or a PASV command. */ + + /* Make sure the previous socket is deleted and flags reset */ + prvTransferCloseSocket( pxClient ); + + pxClient->bits1.bEmptyFile = pdFALSE_UNSIGNED; + + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + + if( ( xSocket != FREERTOS_NO_SOCKET ) && ( xSocket != FREERTOS_INVALID_SOCKET ) ) + { + BaseType_t xSmallTimeout = pdMS_TO_TICKS( 100 ); + struct freertos_sockaddr xAddress; + + #if( ipconfigFTP_TX_BUFSIZE > 0 ) + WinProperties_t xWinProps; + #endif + xAddress.sin_addr = FreeRTOS_GetIPAddress( ); /* Single NIC, currently not used */ + xAddress.sin_port = FreeRTOS_htons( 0 ); /* Bind to any available port number */ + + FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) ); + + #if( ipconfigFTP_TX_BUFSIZE > 0 ) + { + /* Fill in the buffer and window sizes that will be used by the + socket. */ + xWinProps.lTxBufSize = ipconfigFTP_TX_BUFSIZE; + xWinProps.lTxWinSize = ipconfigFTP_TX_WINSIZE; + xWinProps.lRxBufSize = ipconfigFTP_RX_BUFSIZE; + xWinProps.lRxWinSize = ipconfigFTP_RX_WINSIZE; + + /* Set the window and buffer sizes. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); + } + #endif + + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xSmallTimeout, sizeof( BaseType_t ) ); + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xSmallTimeout, sizeof( BaseType_t ) ); + + /* The same instance of the socket will be used for the connection and + data transport. */ + if( xDoListen != pdFALSE ) + { + BaseType_t xTrueValue = pdTRUE; + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_REUSE_LISTEN_SOCKET, ( void * ) &xTrueValue, sizeof( xTrueValue ) ); + } + pxClient->bits1.bIsListen = xDoListen; + pxClient->xTransferSocket = xSocket; + + if( xDoListen != pdFALSE ) + { + FreeRTOS_FD_SET( xSocket, pxClient->pxParent->xSocketSet, eSELECT_EXCEPT | eSELECT_READ ); + /* Calling FreeRTOS_listen( ) */ + xResult = prvTransferStart( pxClient ); + if( xResult >= 0 ) + { + xResult = pdTRUE; + } + } + else + { + FreeRTOS_FD_SET( xSocket, pxClient->pxParent->xSocketSet, eSELECT_EXCEPT | eSELECT_READ | eSELECT_WRITE ); + xResult = pdTRUE; + } + } + else + { + FreeRTOS_printf( ( "FreeRTOS_socket() failed\n" ) ); + xResult = -pdFREERTOS_ERRNO_ENOMEM; + } + + /* An active socket (PORT) should connect() later. */ + return xResult; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvTransferStart( FTPClient_t *pxClient ) +{ +BaseType_t xResult; + + /* A transfer socket has been opened, now either call listen() for 'PASV' + or connect() for the 'PORT' command. */ + if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ) + { + xResult = FreeRTOS_listen( pxClient->xTransferSocket, 1 ); + } + else + { + struct freertos_sockaddr xAddress; + + xAddress.sin_addr = FreeRTOS_htonl( pxClient->ulClientIP ); + xAddress.sin_port = FreeRTOS_htons( pxClient->usClientPort ); + /* Start an active connection for this data socket */ + xResult = FreeRTOS_connect( pxClient->xTransferSocket, &xAddress, sizeof( xAddress ) ); + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +static void prvTransferCheck( FTPClient_t *pxClient ) +{ +BaseType_t xRxSize; + + /* A data transfer is busy. Check if there are changes in connectedness. */ + xRxSize = FreeRTOS_rx_size( pxClient->xTransferSocket ); + + if( pxClient->bits1.bClientConnected == pdFALSE_UNSIGNED ) + { + /* The time to receive a small file can be so short, that we don't even + see that the socket gets connected and disconnected. Therefore, check + the sizeof of the RX buffer. */ + { + struct freertos_sockaddr xAddress; + Socket_t xNexSocket; + socklen_t xSocketLength = sizeof( xAddress ); + + if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ) + { + xNexSocket = FreeRTOS_accept( pxClient->xTransferSocket, &xAddress, &xSocketLength); + if( ( ( xNexSocket != FREERTOS_NO_SOCKET ) && ( xNexSocket != FREERTOS_INVALID_SOCKET ) ) || + xRxSize > 0 ) + { + pxClient->bits1.bClientConnected = pdTRUE_UNSIGNED; + } + } + else + { + if( FreeRTOS_issocketconnected( pxClient->xTransferSocket ) > 0 || + xRxSize > 0 ) + { + pxClient->bits1.bClientConnected = pdTRUE_UNSIGNED; + } + } + if( pxClient->bits1.bClientConnected != pdFALSE_UNSIGNED ) + { + pxClient->bits1.bEmptyFile = pdFALSE_UNSIGNED; + #if( ipconfigHAS_PRINTF != 0 ) + { + struct freertos_sockaddr xRemoteAddress, xLocalAddress; + FreeRTOS_GetRemoteAddress( pxClient->xTransferSocket, &xRemoteAddress ); + FreeRTOS_GetLocalAddress( pxClient->xTransferSocket, &xLocalAddress ); + FreeRTOS_printf( ( "%s Connected from %u to %u\n", + pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ? "PASV" : "PORT", + ( unsigned ) FreeRTOS_ntohs( xLocalAddress.sin_port ), + ( unsigned ) FreeRTOS_ntohs( xRemoteAddress.sin_port ) ) ); + } + #endif /* ipconfigHAS_PRINTF */ + FreeRTOS_FD_CLR( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); + FreeRTOS_FD_SET( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_READ|eSELECT_EXCEPT ); + } + } + } + + if ( pxClient->bits1.bClientConnected != pdFALSE_UNSIGNED ) + { + if( pxClient->pcConnectionAck[ 0 ] != '\0' ) + { + BaseType_t xLength; + BaseType_t xRemotePort; + struct freertos_sockaddr xRemoteAddress; + + FreeRTOS_GetRemoteAddress( pxClient->xTransferSocket, &xRemoteAddress ); + xRemotePort = FreeRTOS_ntohs( xRemoteAddress.sin_port ); + + /* Tell on the command port 21 we have a data connection */ + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + pxClient->pcConnectionAck, pxClient->ulClientIP, xRemotePort ); + + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + pxClient->pcConnectionAck[ 0 ] = '\0'; + } + + if( ( FreeRTOS_issocketconnected( pxClient->xTransferSocket ) == pdFALSE ) && FreeRTOS_rx_size( pxClient->xTransferSocket ) == 0 ) + { + prvTransferCloseSocket( pxClient ); + prvTransferCloseFile( pxClient ); + } + } +} +/*-----------------------------------------------------------*/ + +static void prvTransferCloseSocket( FTPClient_t *pxClient ) +{ + if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) + { + /* DEBUGGING ONLY */ + BaseType_t xRxSize = FreeRTOS_rx_size( pxClient->xTransferSocket ); + if( xRxSize > 0 ) + { + BaseType_t xRxSize2; + BaseType_t xStatus; + prvStoreFileWork( pxClient ); + xStatus = FreeRTOS_connstatus( pxClient->xTransferSocket ); + xRxSize2 = FreeRTOS_rx_size( pxClient->xTransferSocket ); + FreeRTOS_printf( ( "FTP: WARNING: %s: RX size = %ld -> %ld (%s)\n", + FreeRTOS_GetTCPStateName( xStatus ), + xRxSize, xRxSize2, pxClient->pcFileName ) ); + if( xRxSize2 > 1 ) + { + return; + } + + /* Remove compiler warnings in case FreeRTOS_printf() is not + defined. */ + ( void ) xStatus; + } + } + + if( ( pxClient->pxWriteHandle != NULL ) || ( pxClient->pxReadHandle != NULL ) ) + { + BaseType_t xLength; + char pcStrBuf[ 32 ]; + + if( pxClient->bits1.bHadError == pdFALSE_UNSIGNED ) + { + xLength = snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ), + "226 Closing connection %d bytes transmitted\r\n", ( int ) pxClient->ulRecvBytes ); + } + else + { + xLength = snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ), + "451 Requested action aborted after %d bytes\r\n", ( int ) pxClient->ulRecvBytes ); + } + + /* Tell on the command socket the data connection is now closed. */ + prvSendReply( pxClient->xSocket, pxClient->pcClientAck, xLength ); + + #if( ipconfigHAS_PRINTF != 0 ) + { + TickType_t xDelta; + uint32_t ulAverage; + xDelta = xTaskGetTickCount( ) - pxClient->xStartTime; + ulAverage = ulGetAverage( pxClient->ulRecvBytes, xDelta ); + + FreeRTOS_printf( ("FTP: %s: '%s' %lu Bytes (%s/sec)\n", + pxClient->pxReadHandle ? "sent" : "recv", + pxClient->pcFileName, + pxClient->ulRecvBytes, + pcMkSize( ulAverage, pcStrBuf, sizeof( pcStrBuf ) ) ) ); + } + #endif + } + + if( pxClient->xTransferSocket != FREERTOS_NO_SOCKET ) + { + FreeRTOS_FD_CLR( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_ALL ); + FreeRTOS_closesocket( pxClient->xTransferSocket ); + pxClient->xTransferSocket = FREERTOS_NO_SOCKET; + if( pxClient->ulRecvBytes == 0ul ) + { + /* Received zero bytes: an empty file */ + pxClient->bits1.bEmptyFile = pdTRUE_UNSIGNED; + } + else + { + pxClient->bits1.bEmptyFile = pdFALSE_UNSIGNED; + } + } + pxClient->bits1.bIsListen = pdFALSE_UNSIGNED; + pxClient->bits1.bDirHasEntry = pdFALSE_UNSIGNED; + pxClient->bits1.bClientConnected = pdFALSE_UNSIGNED; + pxClient->bits1.bHadError = pdFALSE_UNSIGNED; +} +/*-----------------------------------------------------------*/ + +static void prvTransferCloseFile( FTPClient_t *pxClient ) +{ + if( pxClient->pxWriteHandle != NULL ) + { + ff_fclose( pxClient->pxWriteHandle ); + pxClient->pxWriteHandle = NULL; + #if( ipconfigFTP_HAS_RECEIVED_HOOK != 0 ) + { + vApplicationFTPReceivedHook( pxClient->pcFileName, pxClient->ulRecvBytes, pxClient ); + } + #endif + + } + if( pxClient->pxReadHandle != NULL ) + { + ff_fclose( pxClient->pxReadHandle ); + pxClient->pxReadHandle = NULL; + } + /* These two field are only used for logging / file-statistics */ + pxClient->ulRecvBytes = 0ul; + pxClient->xStartTime = 0ul; +} +/*-----------------------------------------------------------*/ + +/** + * Guess the transfer type, given the client requested type. + * Actually in unix there is no difference between binary and + * ascii mode when we work with file descriptors. + * If #type is not recognized as a valid client request, -1 is returned. + */ +static BaseType_t prvGetTransferType( const char *pcType ) +{ +BaseType_t xResult = -1; + + if( pcType != NULL ) + { + BaseType_t xLength = strlen( pcType ); + if( xLength == 0 ) + { + return -1; + } + switch( pcType[ 0 ] ) { + case 'I': + xResult = TMODE_BINARY; + break; + case 'A': + xResult = TMODE_ASCII; + break; + case 'L': + if( xLength >= 3 ) + { + if( pcType[ 2 ] == '7' ) + { + xResult = TMODE_7BITS; + } + else if( pcType[ 2 ] == '8' ) + { + xResult = TMODE_7BITS; + } + } + break; + } + } + return xResult; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigHAS_PRINTF != 0 ) + #define SIZE_1_GB ( 1024ul * 1024ul * 1024ul ) + #define SIZE_1_MB ( 1024ul * 1024ul ) + #define SIZE_1_KB ( 1024ul ) + + static const char *pcMkSize( uint32_t ulAmount, char *pcBuffer, BaseType_t xBufferSize ) + { + uint32_t ulGB, ulMB, ulKB, ulByte; + + ulGB = ( ulAmount / SIZE_1_GB ); + ulAmount -= ( ulGB * SIZE_1_GB ); + ulMB = ( ulAmount / SIZE_1_MB ); + ulAmount -= ( ulMB * SIZE_1_MB ); + ulKB = ( ulAmount / SIZE_1_KB ); + ulAmount -= ( ulKB * SIZE_1_KB ); + ulByte = ( ulAmount ); + + if (ulGB != 0ul ) + { + snprintf( pcBuffer, xBufferSize, "%lu.%02lu GB", ulGB, (100 * ulMB) / SIZE_1_KB ); + } + else if( ulMB != 0ul ) + { + snprintf( pcBuffer, xBufferSize, "%lu.%02lu MB", ulMB, (100 * ulKB) / SIZE_1_KB ); + } + else if( ulKB != 0ul ) + { + snprintf(pcBuffer, xBufferSize, "%lu.%02lu KB", ulKB, (100 * ulByte) / SIZE_1_KB ); + } + else + { + snprintf( pcBuffer, xBufferSize, "%lu bytes", ulByte ); + } + + return pcBuffer; + } + /*-----------------------------------------------------------*/ +#endif /* ipconfigHAS_PRINTF != 0 */ + +#if( ipconfigHAS_PRINTF != 0 ) + static uint32_t ulGetAverage( uint32_t ulAmount, TickType_t xDeltaMs ) + { + uint32_t ulAverage; + + /* Get the average amount of bytes per seconds. Ideally this is + calculated by Multiplying with 1000 and dividing by milliseconds: + ulAverage = ( 1000ul * ulAmount ) / xDeltaMs; + Now get a maximum precision, while avoiding an arithmetic overflow: + */ + if( xDeltaMs == 0ul ) + { + /* Time is zero, there is no average */ + ulAverage = 0ul; + } + else if( ulAmount >= ( ~0ul / 10ul ) ) + { + /* More than 409 MB has been transferred, do not multiply. */ + ulAverage = ( ulAmount / ( xDeltaMs / 1000ul ) ); + } + else if( ulAmount >= ( ~0ul / 100ul ) ) + { + /* Between 409 and 41 MB has been transferred, can multiply by 10. */ + ulAverage = ( ( ulAmount * 10ul ) / ( xDeltaMs / 100ul ) ); + } + else if( ulAmount >= ( ~0ul / 1000ul ) ) + { + /* Between 4.1 MB and 41 has been transferred, can multiply by 100. */ + ulAverage = ( ( ulAmount * 100ul ) / ( xDeltaMs / 10ul ) ); + } + else + { + /* Less than 4.1 MB: can multiply by 1000. */ + ulAverage = ( ( ulAmount * 1000ul ) / xDeltaMs ); + } + + return ulAverage; + } + /*-----------------------------------------------------------*/ +#endif /* ipconfigHAS_PRINTF != 0 */ + +static UBaseType_t prvParsePortData( const char *pcCommand, uint32_t *pulIPAddress ) +{ +/*_HT_ Using 'unsigned' here because when sscanf() sees '%u', it expects a pointer to 'unsigned'. +Not sure about the sscanf() format for UBaseType_t ? */ +unsigned h1, h2, h3, h4, p1, p2; +char sep; +UBaseType_t uxResult; + + /* Expect PORT h1,h2,h3,h4,p1,p2 */ + if (sscanf (pcCommand, "%u%c%u%c%u%c%u%c%u%c%u", &h1, &sep, &h2, &sep, &h3, &sep, &h4, &sep, &p1, &sep, &p2) != 11) + { + uxResult= 0u; + } + else + { + /* Put in network byte order. */ + *pulIPAddress = + ( ( uint32_t ) h1 << 24 ) | + ( ( uint32_t ) h2 << 16 ) | + ( ( uint32_t ) h3 << 8 ) | + ( ( uint32_t ) h4 ); + uxResult = ( p1 << 8 ) | p2; + } + return uxResult; +} +/*-----------------------------------------------------------*/ + +/* + + #### ####### # ### +# # # # ## # # +# # # # # # +# ###### #### ### ## #### # # ### # #### + ## # # # # # # # # ##### # # # # + ## # # # ## # ###### # # # # ###### +# # # # # # # # # # # +# # # ## # # # # ## # # # # ## + #### ## #### #### #### #### ##### ##### #### + +*/ + +static BaseType_t prvStoreFilePrep( FTPClient_t *pxClient, char *pcFileName ) +{ +BaseType_t xResult; +FF_FILE *pxNewHandle; +size_t uxFileSize = 0ul; +int iErrorNo; + + /* Close previous handle (if any) and reset file transfer parameters. */ + prvTransferCloseFile( pxClient ); + + xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); + + pxNewHandle = NULL; + + if( pxClient->ulRestartOffset != 0 ) + { + size_t uxOffset = pxClient->ulRestartOffset; + int32_t lRc; + + pxClient->ulRestartOffset = 0ul; /* Only use 1 time. */ + pxNewHandle = ff_fopen( pxClient->pcFileName, "ab" ); + + if( pxNewHandle != NULL ) + { + uxFileSize = pxNewHandle->ulFileSize; + + if( uxOffset <= uxFileSize ) + { + lRc = ff_fseek( pxNewHandle, uxOffset, FF_SEEK_SET ); + } + else + { + /* Won't even try to seek after EOF */ + lRc = -pdFREERTOS_ERRNO_EINVAL; + } + if( lRc != 0 ) + { + BaseType_t xLength; + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "450 Seek invalid %u length %u\r\n", + ( unsigned ) uxOffset, ( unsigned ) uxFileSize ); + + /* "Requested file action not taken". */ + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + + FreeRTOS_printf( ( "ftp::storeFile: create %s: Seek %u length %u\n", + pxClient->pcFileName, ( unsigned ) uxOffset, ( unsigned ) uxFileSize ) ); + + ff_fclose( pxNewHandle ); + pxNewHandle = NULL; + } + } + } + else + { + pxNewHandle = ff_fopen( pxClient->pcFileName, "wb" ); + } + + if( pxNewHandle == NULL ) + { + iErrorNo = stdioGET_ERRNO(); + if( iErrorNo == pdFREERTOS_ERRNO_ENOSPC ) + { + prvSendReply( pxClient->xSocket, REPL_552, 0 ); + } + else + { + /* "Requested file action not taken". */ + prvSendReply( pxClient->xSocket, REPL_450, 0 ); + } + FreeRTOS_printf( ( "ftp::storeFile: create %s: %s (errno %d)\n", + pxClient->pcFileName, + ( const char* ) strerror( iErrorNo ), iErrorNo ) ); + + xResult = pdFALSE; + } + else + { + if( pxClient->bits1.bIsListen ) + { + /* True if PASV is used. */ + snprintf( pxClient->pcConnectionAck, sizeof( pxClient->pcConnectionAck ), + "150 Accepted data connection from %%xip:%%u\r\n" ); + prvTransferCheck( pxClient ); + } + else + { + BaseType_t xLength; + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "150 Opening BIN connection to store file\r\n" ); + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + pxClient->pcConnectionAck[ 0 ] = '\0'; + prvTransferStart( pxClient ); /* Now active connect. */ + } + + pxClient->pxWriteHandle = pxNewHandle; + + /* To get some statistics about the performance. */ + pxClient->xStartTime = xTaskGetTickCount( ); + + xResult = pdTRUE; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigFTP_ZERO_COPY_ALIGNED_WRITES == 0 ) + + static BaseType_t prvStoreFileWork( FTPClient_t *pxClient ) + { + BaseType_t xRc, xWritten; + + /* Read from the data socket until all has been read or until a negative value + is returned. */ + for( ; ; ) + { + char *pcBuffer; + + /* The "zero-copy" method: */ + xRc = FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) &pcBuffer, + 0x20000u, FREERTOS_ZERO_COPY | FREERTOS_MSG_DONTWAIT ); + if( xRc <= 0 ) + { + break; + } + pxClient->ulRecvBytes += xRc; + xWritten = ff_fwrite( pcBuffer, 1, xRc, pxClient->pxWriteHandle ); + FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) NULL, xRc, 0 ); + if( xWritten != xRc ) + { + xRc = -1; + /* bHadError: a transfer got aborted because of an error. */ + pxClient->bits1.bHadError = pdTRUE_UNSIGNED; + break; + } + } + return xRc; + } + +#else /* ipconfigFTP_ZERO_COPY_ALIGNED_WRITES != 0 */ + + #if !defined( ipconfigFTP_PREFERRED_WRITE_SIZE ) + /* If you store data on flash, it may be profitable to give 'ipconfigFTP_PREFERRED_WRITE_SIZE' + the same size as the size of the flash' erase blocks, e.g. 4KB */ + #define ipconfigFTP_PREFERRED_WRITE_SIZE 512ul + #endif + + static BaseType_t prvStoreFileWork( FTPClient_t *pxClient ) + { + BaseType_t xRc, xWritten; + + /* Read from the data socket until all has been read or until a negative + value is returned. */ + for( ; ; ) + { + char *pcBuffer; + UBaseType_t xStatus; + + /* The "zero-copy" method: */ + xRc = FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) &pcBuffer, + 0x20000u, FREERTOS_ZERO_COPY | FREERTOS_MSG_DONTWAIT ); + + if( xRc <= 0 ) + { + /* There are no data or the connection is closed. */ + break; + } + xStatus = FreeRTOS_connstatus( pxClient->xTransferSocket ); + if( xStatus != eESTABLISHED ) + { + /* The connection is not established (any more), therefore + accept any amount of bytes, probably the last few bytes. */ + } + else + { + if( xRc >= ipconfigFTP_PREFERRED_WRITE_SIZE ) + { + /* More than a sector to write, round down to a multiple of + PREFERRED_WRITE_SIZE bytes. */ + xRc = ( xRc / ipconfigFTP_PREFERRED_WRITE_SIZE ) * ipconfigFTP_PREFERRED_WRITE_SIZE; + } + else + { + const StreamBuffer_t *pxBuffer = FreeRTOS_get_rx_buf( pxClient->xTransferSocket ); + size_t uxSpace = pxBuffer->LENGTH - pxBuffer->uxTail; + + if( uxSpace >= ipconfigFTP_PREFERRED_WRITE_SIZE ) + { + /* At this moment there are les than PREFERRED_WRITE_SIZE bytes in the RX + buffer, but there is space for more. Just return and + wait for more. */ + xRc = 0; + } + else + { + /* Now reading beyond the end of the circular buffer, + use a normal read. */ + pcBuffer = pcFILE_BUFFER; + xRc = FreeRTOS_recvcount( pxClient->xTransferSocket ); + xRc = ( xRc / ipconfigFTP_PREFERRED_WRITE_SIZE ) * ipconfigFTP_PREFERRED_WRITE_SIZE; + if( xRc > 0 ) + { + xRc = FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) pcBuffer, + sizeof( pcFILE_BUFFER ), FREERTOS_MSG_DONTWAIT ); + } + } + } + } + if( xRc == 0 ) + { + break; + } + pxClient->ulRecvBytes += xRc; + + xWritten = ff_fwrite( pcBuffer, 1, xRc, pxClient->pxWriteHandle ); + if( pcBuffer != pcFILE_BUFFER ) + { + FreeRTOS_recv( pxClient->xTransferSocket, ( void * ) NULL, xRc, 0 ); + } + if( xWritten != xRc ) + { + xRc = -1; + /* bHadError: a transfer got aborted because of an error. */ + pxClient->bits1.bHadError = pdTRUE_UNSIGNED; + break; + } + } + return xRc; + } + +#endif /* ipconfigFTP_ZERO_COPY_ALIGNED_WRITES */ +/*-----------------------------------------------------------*/ + +/* +###### # ####### # ### + # # # # # ## # # + # # # # # # + # # #### ###### ### ## ### #### # # #### # # ### # #### + ###### # # # # # # # # # # # # # ##### # # # # + # ## ###### # ## # # ###### # # ###### # # # # ###### + # # # # # # # # # # # # # # + # # # ## # ## # # # ## # # # ## # # # # ## +### ## #### ## #### ##### #### ## #### #### ##### ##### #### +*/ +static BaseType_t prvRetrieveFilePrep( FTPClient_t *pxClient, char *pcFileName ) +{ +BaseType_t xResult = pdTRUE; +size_t uxFileSize; + + /* Close previous handle (if any) and reset file transfer parameters */ + prvTransferCloseFile( pxClient ); + + xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); + + pxClient->pxReadHandle = ff_fopen( pxClient->pcFileName, "rb" ); + if( pxClient->pxReadHandle == NULL ) + { + int iErrno = stdioGET_ERRNO(); + /* "Requested file action not taken". */ + prvSendReply( pxClient->xSocket, REPL_450, 0 ); + FreeRTOS_printf( ("prvRetrieveFilePrep: open '%s': errno %d: %s\n", + pxClient->pcFileName, iErrno, ( const char * ) strerror( iErrno ) ) ); + uxFileSize = 0ul; + xResult = pdFALSE; + } + else + { + uxFileSize = pxClient->pxReadHandle->ulFileSize; + pxClient->uxBytesLeft = uxFileSize; + if( pxClient->ulRestartOffset != 0ul ) + { + size_t uxOffset = pxClient->ulRestartOffset; + int32_t iRc; + + /* Only use 1 time. */ + pxClient->ulRestartOffset = 0; + + if( uxOffset < uxFileSize ) + { + iRc = ff_fseek( pxClient->pxReadHandle, uxOffset, FF_SEEK_SET ); + } + else + { + iRc = -pdFREERTOS_ERRNO_EINVAL; + } + if( iRc != 0 ) + { + BaseType_t xLength; + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "450 Seek invalid %u length %u\r\n", ( unsigned ) uxOffset, ( unsigned ) uxFileSize ); + + /* "Requested file action not taken". */ + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + + FreeRTOS_printf( ( "prvRetrieveFilePrep: create %s: Seek %u length %u\n", + pxClient->pcFileName, ( unsigned ) uxOffset, ( unsigned ) uxFileSize ) ); + + ff_fclose( pxClient->pxReadHandle ); + pxClient->pxReadHandle = NULL; + xResult = pdFALSE; + } + else + { + pxClient->uxBytesLeft = uxFileSize - pxClient->ulRestartOffset; + } + } + } + if( xResult != pdFALSE ) + { + if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ) + { + /* True if PASV is used. */ + snprintf( pxClient->pcConnectionAck, sizeof( pxClient->pcConnectionAck ), + "150%cAccepted data connection from %%xip:%%u\r\n%s", + pxClient->xTransType == TMODE_ASCII ? '-' : ' ', + pxClient->xTransType == TMODE_ASCII ? "150 NOTE: ASCII mode requested, but binary mode used\r\n" : "" ); + } else { + BaseType_t xLength; + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "150%cOpening data connection to %lxip:%u\r\n%s", + pxClient->xTransType == TMODE_ASCII ? '-' : ' ', + pxClient->ulClientIP, + pxClient->usClientPort, + pxClient->xTransType == TMODE_ASCII ? "150 NOTE: ASCII mode requested, but binary mode used\r\n" : "" ); + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + pxClient->pcConnectionAck[ 0 ] = '\0'; + prvTransferStart( pxClient ); + } + + /* Prepare the ACK which will be sent when all data has been sent. */ + snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ), "%s", REPL_226 ); + + /* To get some statistics about the performance. */ + pxClient->xStartTime = xTaskGetTickCount( ); + if( uxFileSize == 0ul ) + { + FreeRTOS_shutdown( pxClient->xTransferSocket, FREERTOS_SHUT_RDWR ); + } + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvRetrieveFileWork( FTPClient_t *pxClient ) +{ +size_t uxSpace; +size_t uxCount, uxItemsRead; +BaseType_t xRc = 0; +BaseType_t xSetEvent = pdFALSE; + + do + { + #if( ipconfigFTP_TX_ZERO_COPY != 0 ) + char *pcBuffer; + BaseType_t xBufferLength; + #endif /* ipconfigFTP_TX_ZERO_COPY */ + + /* Take the lesser of the two: tx_space (number of bytes that can be + queued for transmission) and uxBytesLeft (the number of bytes left to + read from the file) */ + uxSpace = FreeRTOS_tx_space( pxClient->xTransferSocket ); + + if( uxSpace == 0 ) + { + FreeRTOS_FD_SET( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE | eSELECT_EXCEPT ); + xRc = FreeRTOS_select( pxClient->pxParent->xSocketSet, 200 ); + uxSpace = FreeRTOS_tx_space( pxClient->xTransferSocket ); + } + + uxCount = FreeRTOS_min_uint32( pxClient->uxBytesLeft, uxSpace ); + + if( uxCount == 0 ) + { + break; + } + + #if( ipconfigFTP_TX_ZERO_COPY == 0 ) + { + if( uxCount > sizeof( pcFILE_BUFFER ) ) + { + uxCount = sizeof( pcFILE_BUFFER ); + } + uxItemsRead = ff_fread( pcFILE_BUFFER, 1, uxCount, pxClient->pxReadHandle ); + if( uxItemsRead != uxCount ) + { + FreeRTOS_printf( ( "prvRetrieveFileWork: Got %u Expected %u\n", ( unsigned )uxItemsRead, ( unsigned ) uxCount ) ); + xRc = FreeRTOS_shutdown( pxClient->xTransferSocket, FREERTOS_SHUT_RDWR ); + pxClient->uxBytesLeft = 0u; + break; + } + pxClient->uxBytesLeft -= uxCount; + + if( pxClient->uxBytesLeft == 0u ) + { + BaseType_t xTrueValue = 1; + + FreeRTOS_setsockopt( pxClient->xTransferSocket, 0, FREERTOS_SO_CLOSE_AFTER_SEND, ( void * ) &xTrueValue, sizeof( xTrueValue ) ); + } + + xRc = FreeRTOS_send( pxClient->xTransferSocket, pcFILE_BUFFER, uxCount, 0 ); + } + #else /* ipconfigFTP_TX_ZERO_COPY != 0 */ + { + /* Use zero-copy transmission: + FreeRTOS_get_tx_head() returns a direct pointer to the TX stream and + set xBufferLength to know how much space there is left. */ + pcBuffer = ( char * )FreeRTOS_get_tx_head( pxClient->xTransferSocket, &xBufferLength ); + if( ( pcBuffer != NULL ) && ( xBufferLength >= 512 ) ) + { + /* Will read disk data directly to the TX stream of the socket. */ + uxCount = FreeRTOS_min_uint32( uxCount, ( uint32_t )xBufferLength ); + if( uxCount > ( size_t ) 0x40000u ) + { + uxCount = ( size_t ) 0x40000u; + } + } + else + { + /* Use the normal file i/o buffer. */ + pcBuffer = pcFILE_BUFFER; + if( uxCount > sizeof( pcFILE_BUFFER ) ) + { + uxCount = sizeof( pcFILE_BUFFER ); + } + } + + if ( pxClient->uxBytesLeft >= 1024u ) + { + uxCount &= ~( ( size_t ) 512u - 1u ); + } + + if( uxCount <= 0u ) + { + /* Nothing to send after rounding down to a multiple of a sector size. */ + break; + } + + uxItemsRead = ff_fread( pcBuffer, 1, uxCount, pxClient->pxReadHandle ); + + if( uxCount != uxItemsRead ) + { + FreeRTOS_printf( ( "prvRetrieveFileWork: Got %u Expected %u\n", ( unsigned )uxItemsRead, ( unsigned )uxCount ) ); + xRc = FreeRTOS_shutdown( pxClient->xTransferSocket, FREERTOS_SHUT_RDWR ); + pxClient->uxBytesLeft = 0u; + break; + } + pxClient->uxBytesLeft -= uxCount; + + if( pxClient->uxBytesLeft == 0u ) + { + BaseType_t xTrueValue = 1; + + FreeRTOS_setsockopt( pxClient->xTransferSocket, 0, FREERTOS_SO_CLOSE_AFTER_SEND, ( void * ) &xTrueValue, sizeof( xTrueValue ) ); + } + if( pcBuffer != pcFILE_BUFFER ) + { + pcBuffer = NULL; + } + xRc = FreeRTOS_send( pxClient->xTransferSocket, pcBuffer, uxCount, 0 ); + } + #endif /* ipconfigFTP_TX_ZERO_COPY */ + + if( xRc < 0 ) + { + break; + } + + pxClient->ulRecvBytes += xRc; + if( pxClient->uxBytesLeft == 0u ) + { + break; + } + } while( uxCount > 0u ); + + if( xRc < 0 ) + { + FreeRTOS_printf( ( "prvRetrieveFileWork: already disconnected\n" ) ); + } + else if( pxClient->uxBytesLeft <= 0u ) + { + BaseType_t x; + + for( x = 0; x < 5; x++ ) + { + xRc = FreeRTOS_recv( pxClient->xTransferSocket, pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), 0 ); + if( xRc < 0 ) + { + break; + } + } +// FreeRTOS_printf( ( "prvRetrieveFileWork: %s all sent: xRc %ld\n", pxClient->pcFileName, xRc ) ); + } + else + { + FreeRTOS_FD_SET( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); + xSetEvent = pdTRUE; + } + if( xSetEvent == pdFALSE ) + { + FreeRTOS_FD_CLR( pxClient->xTransferSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); + } + return xRc; +} +/*-----------------------------------------------------------*/ + +/* +### ##### #### ##### + # # # # # # # + # # # # # + # # # # + # # ## # + # # # ## # + # # # # # # + # # # # # # +####### ##### #### #### +*/ +/* Prepare sending a directory LIST */ +static BaseType_t prvListSendPrep( FTPClient_t *pxClient ) +{ +BaseType_t xFindResult; +int iErrorNo; + + if( pxClient->bits1.bIsListen != pdFALSE_UNSIGNED ) + { + /* True if PASV is used */ + snprintf( pxClient->pcConnectionAck, sizeof( pxClient->pcConnectionAck ), + "150 Accepted data connection from %%xip:%%u\r\n" ); + } + else + { + BaseType_t xLength; + + /* Here the FTP server is supposed to connect() */ + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "150 Opening ASCII mode data connection to for /bin/ls \r\n" ); + + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + /* Clear the current connection acknowledge message */ + pxClient->pcConnectionAck[ 0 ] = '\0'; + prvTransferStart( pxClient ); + } + + pxClient->xDirCount = 0; + xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pxClient->pcCurrentDir ); + + xFindResult = ff_findfirst( pcNEW_DIR, &pxClient->xFindData ); + + pxClient->bits1.bDirHasEntry = ( xFindResult >= 0 ); + + iErrorNo = stdioGET_ERRNO(); + if( ( xFindResult < 0 ) && ( iErrorNo == pdFREERTOS_ERRNO_ENMFILE ) ) + { + FreeRTOS_printf( ("prvListSendPrep: Empty directory? (%s)\n", pxClient->pcCurrentDir ) ); + prvSendReply( pxClient->xTransferSocket, "total 0\r\n", 0 ); + pxClient->xDirCount++; + } + else if( xFindResult < 0 ) + { + FreeRTOS_printf( ( "prvListSendPrep: rc = %ld iErrorNo = %d\n", xFindResult, iErrorNo ) ); + prvSendReply( pxClient->xSocket, REPL_451, 0 ); + } + pxClient->pcClientAck[ 0 ] = '\0'; + + return pxClient->xDirCount; +} +/*-----------------------------------------------------------*/ + +#define MAX_DIR_LIST_ENTRY_SIZE 256 + +static BaseType_t prvListSendWork( FTPClient_t *pxClient ) +{ +BaseType_t xTxSpace; + + while( pxClient->bits1.bClientConnected != pdFALSE_UNSIGNED ) + { + char *pcWritePtr = pcCOMMAND_BUFFER; + BaseType_t xWriteLength; + + xTxSpace = FreeRTOS_tx_space( pxClient->xTransferSocket ); + + if( xTxSpace > ( BaseType_t ) sizeof( pcCOMMAND_BUFFER ) ) + { + xTxSpace = sizeof( pcCOMMAND_BUFFER ); + } + + while( ( xTxSpace >= MAX_DIR_LIST_ENTRY_SIZE ) && ( pxClient->bits1.bDirHasEntry != pdFALSE_UNSIGNED ) ) + { + BaseType_t xLength, xEndOfDir; + int32_t iRc; + int iErrorNo; + + xLength = prvGetFileInfoStat( &( pxClient->xFindData.xDirectoryEntry ), pcWritePtr, xTxSpace ); + + pxClient->xDirCount++; + pcWritePtr += xLength; + xTxSpace -= xLength; + + iRc = ff_findnext( &pxClient->xFindData ); + iErrorNo = stdioGET_ERRNO(); + + xEndOfDir = ( iRc < 0 ) && ( iErrorNo == pdFREERTOS_ERRNO_ENMFILE ); + + pxClient->bits1.bDirHasEntry = ( xEndOfDir == pdFALSE ) && ( iRc >= 0 ); + + if( ( iRc < 0 ) && ( xEndOfDir == pdFALSE ) ) + { + FreeRTOS_printf( ("prvListSendWork: %s (rc %08x)\n", + ( const char * ) strerror( iErrorNo ), + ( unsigned )iRc ) ); + } + } + xWriteLength = ( BaseType_t ) ( pcWritePtr - pcCOMMAND_BUFFER ); + + if( xWriteLength == 0 ) + { + break; + } + + if( pxClient->bits1.bDirHasEntry == pdFALSE_UNSIGNED ) + { + uint32_t ulTotalCount; + uint32_t ulFreeCount; + uint32_t ulPercentage; + + ulTotalCount = 1; + ulFreeCount = ff_diskfree( pxClient->pcCurrentDir, &ulTotalCount ); + ulPercentage = ( uint32_t ) ( ( 100ULL * ulFreeCount + ulTotalCount / 2 ) / ulTotalCount ); + + /* Prepare the ACK which will be sent when all data has been sent. */ + snprintf( pxClient->pcClientAck, sizeof( pxClient->pcClientAck ), + "226-Options: -l\r\n" + "226-%ld matches total\r\n" + "226 Total %lu KB (%lu %% free)\r\n", + pxClient->xDirCount, ulTotalCount /1024, ulPercentage ); + } + + if( xWriteLength ) + { + if( pxClient->bits1.bDirHasEntry == pdFALSE_UNSIGNED ) + { + BaseType_t xTrueValue = 1; + + FreeRTOS_setsockopt( pxClient->xTransferSocket, 0, FREERTOS_SO_CLOSE_AFTER_SEND, ( void * ) &xTrueValue, sizeof( xTrueValue ) ); + } + + prvSendReply( pxClient->xTransferSocket, pcCOMMAND_BUFFER, xWriteLength ); + } + + if( pxClient->bits1.bDirHasEntry == pdFALSE_UNSIGNED ) + { + prvSendReply( pxClient->xSocket, pxClient->pcClientAck, 0 ); + break; + } + + } /* while( pxClient->bits1.bClientConnected ) */ + + return 0; +} +/*-----------------------------------------------------------*/ + +static const char *pcMonthAbbrev( BaseType_t xMonth ) +{ +static const char pcMonthList[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; + + if( xMonth < 1 || xMonth > 12 ) + xMonth = 12; + + return pcMonthList + 3 * ( xMonth - 1 ); +}; +/*-----------------------------------------------------------*/ + +static BaseType_t prvGetFileInfoStat( FF_DirEnt_t *pxEntry, char *pcLine, BaseType_t xMaxLength ) +{ + char date[ 16 ]; + char mode[ 11 ] = "----------"; + BaseType_t st_nlink = 1; + const char user[ 9 ] = "freertos"; + const char group[ 8 ] = "plusfat"; + +/* + * Creates a unix-style listing, understood by most FTP clients: + * + * -rw-rw-r-- 1 freertos FreeRTOS+FAT 10564588 Sep 01 00:17 03. Metaharmoniks - Star (Instrumental).mp3 + * -rw-rw-r-- 1 freertos FreeRTOS+FAT 19087839 Sep 01 00:17 04. Simon Le Grec - Dimitri (Wherever U Are) (Cosmos Mix).mp3 + * -rw-rw-r-- 1 freertos FreeRTOS+FAT 11100621 Sep 01 00:16 05. D-Chill - Mistake (feat. Katy Blue).mp3 + */ + + #if ( ffconfigTIME_SUPPORT == 1 ) + const FF_SystemTime_t *pxCreateTime = &( pxEntry->xCreateTime ); + #else + #warning Do not use this. + FF_SystemTime_t xCreateTime; + const FF_SystemTime_t *pxCreateTime = &xCreateTime; + #endif + size_t ulSize = ( size_t )pxEntry->ulFileSize; + const char *pcFileName = pxEntry->pcFileName; + + mode[ 0 ] = ( ( pxEntry->ucAttrib & FF_FAT_ATTR_DIR ) != 0 ) ? 'd' : '-'; + #if( ffconfigDEV_SUPPORT != 0 ) + { + if( ( pxEntry->ucAttrib & FF_FAT_ATTR_DIR ) == 0 ) + { + switch( pxEntry->ucIsDeviceDir ) + { + case FF_DEV_CHAR_DEV: + mode[ 0 ] = 'c'; + break; + case FF_DEV_BLOCK_DEV: + mode[ 0 ] = 'b'; + break; + } + } + } + #endif /* ffconfigDEV_SUPPORT != 0 */ + + mode[ 1 ] = 'r'; /* Owner. */ + mode[ 2 ] = ( ( pxEntry->ucAttrib & FF_FAT_ATTR_READONLY ) != 0 ) ? '-' : 'w'; + mode[ 3 ] = '-'; /* x for executable. */ + + mode[ 4 ] = 'r'; /* group. */ + mode[ 5 ] = ( ( pxEntry->ucAttrib & FF_FAT_ATTR_READONLY ) != 0 ) ? '-' : 'w'; + mode[ 6 ] = '-'; /* x for executable. */ + + mode[ 7 ] = 'r'; /* world. */ + mode[ 8 ] = '-'; + mode[ 9 ] = '-'; /* x for executable. */ + + if( pxCreateTime->Month && pxCreateTime->Day ) + { + snprintf( date, sizeof( date ), "%-3.3s %02d %02d:%02d", + pcMonthAbbrev( pxCreateTime->Month ), + pxCreateTime->Day, + pxCreateTime->Hour, + pxCreateTime->Minute ); + } + else + { + snprintf (date, sizeof( date ), "Jan 01 1970"); + } + return snprintf( pcLine, xMaxLength, "%s %3ld %-4s %-4s %8d %12s %s\r\n", + mode, st_nlink, user, group, ( int ) ulSize, date, pcFileName ); +} +/*-----------------------------------------------------------*/ + +/* + #### # # ##### + # # # # # # +# # # # # # +# # # # # # +# # # # # # +# # # # # # +# # ## ## # # + # # ## ## # # + #### ## ## ##### +*/ +static BaseType_t prvChangeDir( FTPClient_t *pxClient, char *pcDirectory ) +{ +BaseType_t xResult; +BaseType_t xIsRootDir, xLength, xValid; +BaseType_t xIsDotDir = 0; + + if( pcDirectory[ 0 ] == '.' ) + { + if( ( pcDirectory[ 1 ] == '.' ) && + ( pcDirectory[ 2 ] == '\0' ) ) + { + xIsDotDir = 2; + } + else if( pcDirectory[ 1 ] == '\0' ) + { + xIsDotDir = 1; + } + } + + if( xIsDotDir != 0 ) + { + strcpy( pcFILE_BUFFER, pxClient->pcCurrentDir ); + + if( pcDirectory[ 1 ] == '.' ) + { + char *p = strrchr( pcFILE_BUFFER, '/' ); + if( p != NULL ) + { + if( p == pcFILE_BUFFER ) + { + p[ 1 ] = '\0'; + } + else + { + p[ 0 ] = '\0'; + } + } + } + } + else + { + if(pcDirectory[ 0 ] != '/' ) + { + BaseType_t xCurLength; + + xCurLength = strlen( pxClient->pcCurrentDir ); + snprintf( pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), "%s%s%s", + pxClient->pcCurrentDir, + pxClient->pcCurrentDir[ xCurLength - 1 ] == '/' ? "" : "/", + pcDirectory ); + } + else + { + snprintf( pcFILE_BUFFER, sizeof( pcFILE_BUFFER ), "%s", pcDirectory ); + } + } + + xIsRootDir = ( pcFILE_BUFFER[ 0 ] == '/' ) && ( pcFILE_BUFFER[ 1 ] == '\0' ); + xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pcFILE_BUFFER ); + + if( ( ( xIsRootDir == pdFALSE ) || ( FF_FS_Count() == 0 ) ) && ( ff_finddir( pcNEW_DIR ) == pdFALSE ) ) + { + xValid = pdFALSE; + } + else + { + xValid = pdTRUE; + } + + if( xValid == pdFALSE ) + { + /* Get the directory cluster, if it exists. */ + FreeRTOS_printf( ("FTP: chdir \"%s\": No such dir\n", pcNEW_DIR ) ); + //#define REPL_550 "550 Requested action not taken.\r\n" + //550 /home/hein/arch/h8300: No such file or directory + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "550 %s: No such file or directory\r\n", + pcNEW_DIR ); + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + xResult = pdFALSE; + } + else + { + memcpy( pxClient->pcCurrentDir, pcNEW_DIR, sizeof( pxClient->pcCurrentDir ) ); + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "250 Changed to %s\r\n", pcNEW_DIR ); + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + xResult = pdTRUE; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +/* +###### ## # ####### ###### + # # ## # # ## # # + # # ## # # # # # + # # ### # # # # # + ###### # ## # ##### ###### + # ## # ## # # # # ## + # # # ### # # # + # # # ## # # # +### ## # ## #### ### ## +*/ +static BaseType_t prvRenameFrom( FTPClient_t *pxClient, const char *pcFileName ) +{ +const char *myReply; +FF_FILE *fh; + + xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); + + myReply = NULL; + + fh = ff_fopen( pxClient->pcFileName, "rb" ); + + if( fh != NULL ) + { + ff_fclose( fh ); + /* REPL_350; "350 Requested file action pending further information." */ + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "350 Rename '%s' ...\r\n", pxClient->pcFileName ); + myReply = pcCOMMAND_BUFFER; + pxClient->bits.bInRename = pdTRUE_UNSIGNED; + } + else if( stdioGET_ERRNO() == pdFREERTOS_ERRNO_EISDIR ) + { + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "350 Rename directory '%s' ...\r\n", pxClient->pcFileName ); + myReply = pcCOMMAND_BUFFER; + pxClient->bits.bInRename = pdTRUE_UNSIGNED; + } + else + { + FreeRTOS_printf( ("ftp::renameFrom[%s]\n%s\n", pxClient->pcFileName, strerror( stdioGET_ERRNO() ) ) ); + myReply = REPL_451; /* "451 Requested action aborted. Local error in processing." */ + } + if( myReply ) + { + prvSendReply( pxClient->xSocket, myReply, 0 ); + } + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +/* +###### ## # ##### ### + # # ## # # # # ## ## + # # ## # # ## ## + # # ### # # # # + ###### # ## # # # # + # ## # ## # # # # + # # # ### # ## ## + # # # ## # ## ## +### ## # ## #### ### +*/ +static BaseType_t prvRenameTo( FTPClient_t *pxClient, const char *pcFileName ) +{ +const char *myReply = NULL; +int iResult; + + xMakeAbsolute( pxClient, pcNEW_DIR, sizeof( pcNEW_DIR ), pcFileName ); + + /* FreeRTOS+FAT rename has an extra parameter: "remove target if already + exists". */ + iResult = ff_rename( pxClient->pcFileName, pcNEW_DIR, pdFALSE ); + + if( iResult < 0 ) + { + iResult = stdioGET_ERRNO(); + } + else + { + iResult = 0; + } + + switch( iResult ) + { + case 0: + FreeRTOS_printf( ( "ftp::renameTo[%s,%s]: Ok\n", pxClient->pcFileName, pcNEW_DIR ) ); + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "250 Rename successful to '%s'\r\n", pcNEW_DIR ); + myReply = pcCOMMAND_BUFFER; + break; + case pdFREERTOS_ERRNO_EEXIST: + /* the destination file already exists. + "450 Requested file action not taken.\r\n"*/ + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "450 Already exists '%s'\r\n", pcNEW_DIR ); + myReply = pcCOMMAND_BUFFER; + break; + case pdFREERTOS_ERRNO_EIO: /* FF_ERR_FILE_COULD_NOT_CREATE_DIRENT */ + /* if dirent creation failed (fatal error!). + "553 Requested action not taken.\r\n" */ + FreeRTOS_printf( ("ftp::renameTo[%s,%s]: Error creating DirEnt\n", + pxClient->pcFileName, pcNEW_DIR ) ); + myReply = REPL_553; + break; + case pdFREERTOS_ERRNO_ENXIO: + case pdFREERTOS_ERRNO_ENOENT: + /* if the source file was not found. + "450 Requested file action not taken.\r\n" */ + snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "450 No such file '%s'\r\n", pxClient->pcFileName ); + myReply = pcCOMMAND_BUFFER; + break; + default: + FreeRTOS_printf( ("ftp::renameTo[%s,%s]: %s\n", pxClient->pcFileName, pcNEW_DIR, + (const char*)strerror( stdioGET_ERRNO() ) ) ); + myReply = REPL_451; /* "451 Requested action aborted. Local error in processing." */ + break; + } + prvSendReply( pxClient->xSocket, myReply, 0 ); + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +/* + #### # +# # # # +# # # +# ### ###### #### + ## # # # # + ## # # ###### +# # # # # +# # # # ## # ## + #### ##### ## #### +*/ +static BaseType_t prvSiteCmd( FTPClient_t *pxClient, char *pcRestCommand ) +{ + ( void ) pxClient; + ( void ) pcRestCommand; + + return 0; +} +/*-----------------------------------------------------------*/ + +/* +##### ### + # # # # + # # # # + # # #### # #### ###### #### + # # # # # # # # # # + # # ###### # ###### # ###### + # # # # # # # + # # # ## # # ## # ## # ## +##### #### ##### #### ## #### +*/ +static BaseType_t prvDeleteFile( FTPClient_t *pxClient, char *pcFileName ) +{ +BaseType_t xResult, xLength; +int32_t iRc; +int iErrorNo; + + /* DELE: Delete a file. */ + xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); + + iRc = ff_remove( pxClient->pcFileName ); + + if (iRc >= 0 ) + { + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "250 File \"%s\" removed\r\n", pxClient->pcFileName ); + xResult = pdTRUE; + } + else + { + const char *errMsg = "other error"; + + iErrorNo = stdioGET_ERRNO(); + switch( iErrorNo ) + { /*_RB_ What do these negative numbers relate to? */ + case pdFREERTOS_ERRNO_ENOENT: errMsg = "No such file"; break; /* -31 File was not found. */ + case pdFREERTOS_ERRNO_EALREADY: errMsg = "File still open"; break; /* -30 File is in use. */ + case pdFREERTOS_ERRNO_EISDIR: errMsg = "Is a dir"; break; /* -32 Tried to FF_Open() a Directory. */ + case pdFREERTOS_ERRNO_EROFS: errMsg = "Read-only"; break; /* -33 Tried to FF_Open() a file marked read only. */ + case pdFREERTOS_ERRNO_ENOTDIR: errMsg = "Invalid path"; break; /* -34 The path of the file was not found. */ + } + FreeRTOS_printf( ( "ftp::delFile: '%s' because %s\n", + pxClient->pcFileName, strerror( iErrorNo ) ) ); + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "521-\"%s\" %s;\r\n" + "521 taking no action\r\n", + pxClient->pcFileName, errMsg ); + + xResult = pdFALSE; + } + + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + + return xResult; +} +/*-----------------------------------------------------------*/ + +/* + #### # ##### +# # # # # # +# # # # # +# ### ###### #### # # #### ###### #### + ## # # # # # # # # # # # + ## # # ###### # # ##### # ###### +# # # # # # # # # # # +# # # # # ## # # # # # ## # ## + #### ##### ###### #### ##### ### ## ## #### +*/ +static BaseType_t prvSizeDateFile( FTPClient_t *pxClient, char *pcFileName, BaseType_t xSendDate ) +{ +BaseType_t xResult = pdFALSE; +char *pcPtr; + + /* SIZE: get the size of a file (xSendDate = 0) + MDTM: get data and time properties (xSendDate = 1) */ + xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcFileName ); + + pcPtr = strrchr( pxClient->pcFileName, '/' ); + + if( ( pcPtr != NULL ) && ( pcPtr[ 1 ] != '\0' ) ) + { + FF_Stat_t xStatBuf; + int32_t iRc = ff_stat( pxClient->pcFileName, &xStatBuf ); + if (iRc < 0 ) + FreeRTOS_printf( ("In %s: %s\n", pxClient->pcFileName, + ( const char* )strerror( stdioGET_ERRNO() ) ) ); + + if( iRc == 0 ) + { + BaseType_t xLength; + /* "YYYYMMDDhhmmss" */ + if( xSendDate != pdFALSE ) + { + #if( ffconfigTIME_SUPPORT != 0 ) + { + FF_TimeStruct_t tmStruct; + time_t secs = xStatBuf.st_mtime; + FreeRTOS_gmtime_r( &secs, &tmStruct ); + + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 %04u%02u%02u%02u%02u%02u\r\n", + tmStruct.tm_year + 1900, + tmStruct.tm_mon+1, + tmStruct.tm_mday, + tmStruct.tm_hour, + tmStruct.tm_min, + tmStruct.tm_sec ); + } + #else + { + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 19700101000000\r\n", + } + #endif + } + else + { + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "213 %lu\r\n", xStatBuf.st_size ); + } + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + xResult = pdTRUE; + } + else + { + FreeRTOS_printf( ("ftp::sizeDateFile: No such file %s\n", pxClient->pcFileName ) ); + } + } else { + FreeRTOS_printf( ("ftp::sizeDateFile: Invalid file name: %s ?\n", pxClient->pcFileName ) ); + } + if( xResult == pdFALSE ) + { + prvSendReply( pxClient->xSocket, REPL_450, 0 ); /* "Requested file action not taken". */ + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +/* +## ## ## ## ##### ###### ## ## ##### +### ### # # # # # # ### ### # # +# ### # # # # # # # # ### # # # +# # # # # # # # # # # # # # +# # # #### # # ###### # # # # # +# # # # # # # ## # # # # +# # # # # # # # # # # # +# # # # # # # # # # # # +# # ### ## ##### ### ## # # ##### +*/ +static BaseType_t prvMakeRemoveDir( FTPClient_t *pxClient, const char *pcDirectory, BaseType_t xDoRemove ) +{ +BaseType_t xResult; +BaseType_t xLength; +int32_t iRc; +int iErrorNo; + + /* MKD: Make / create a directory (xDoRemove = 0) + RMD: Remove a directory (xDoRemove = 1) */ + xMakeAbsolute( pxClient, pxClient->pcFileName, sizeof( pxClient->pcFileName ), pcDirectory ); + + if( xDoRemove ) + { + iRc = ff_rmdir( pxClient->pcFileName ); + } + else + { + #if( ffconfigMKDIR_RECURSIVE != 0 ) + { + iRc = ff_mkdir( pxClient->pcFileName, pdFALSE ); + } + #else + { + iRc = ff_mkdir( pxClient->pcFileName ); + } + #endif /* ffconfigMKDIR_RECURSIVE */ + } + xResult = pdTRUE; + + if( iRc >= 0 ) + { + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), "257 \"%s\" directory %s\r\n", + pxClient->pcFileName, xDoRemove ? "removed" : "created" ); + } + else + { + const char *errMsg = "other error"; + BaseType_t xFTPCode = 521; + + xResult = pdFALSE; + iErrorNo = stdioGET_ERRNO(); + switch( iErrorNo ) + { + case pdFREERTOS_ERRNO_EEXIST: errMsg = "Directory already exists"; break; + case pdFREERTOS_ERRNO_ENOTDIR: errMsg = "Invalid path"; break; /* -34 The path of the file was not found. *//*_RB_ As before, what do these negative numbers relate to? */ + case pdFREERTOS_ERRNO_ENOTEMPTY:errMsg = "Dir not empty"; break; + case pdFREERTOS_ERRNO_EROFS: errMsg = "Read-only"; break; /* -33 Tried to FF_Open() a file marked read only. */ + default: errMsg = strerror( iErrorNo ); break; + } + if( iErrorNo == pdFREERTOS_ERRNO_ENOSPC ) + { + xFTPCode = 552; + } + xLength = snprintf( pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), + "%ld-\"%s\" %s;\r\n" + "%ld taking no action\r\n", + xFTPCode, pxClient->pcFileName, errMsg, xFTPCode ); + FreeRTOS_printf( ( "%sdir '%s': %s\n", xDoRemove ? "rm" : "mk", pxClient->pcFileName, errMsg ) ); + } + prvSendReply( pxClient->xSocket, pcCOMMAND_BUFFER, xLength ); + + return xResult; +} +/*-----------------------------------------------------------*/ + +static portINLINE BaseType_t IsDigit( char cChar ) +{ +BaseType_t xResult; + + if( cChar >= '0' && cChar <= '9' ) + { + xResult = pdTRUE; + } + else + { + xResult = pdFALSE; + } + return xResult; +} + +static BaseType_t prvSendReply( Socket_t xSocket, const char *pcBuffer, BaseType_t xLength ) +{ +BaseType_t xResult; + + if( xLength == 0 ) + { + xLength = strlen( pcBuffer ); + } + xResult = FreeRTOS_send( xSocket, ( const void * )pcBuffer, ( size_t ) xLength, 0 ); + if( IsDigit( ( int ) pcBuffer[ 0 ] ) && + IsDigit( ( int ) pcBuffer[ 1 ] ) && + IsDigit( ( int ) pcBuffer[ 2 ] ) && + IsDigit( ( int ) pcBuffer[ 3 ] ) ) + { + const char *last = pcBuffer + strlen( pcBuffer ); + int iLength; + while( ( last > pcBuffer ) && ( ( last[ -1 ] == ftpASCII_CR ) || ( last[ -1 ] == ftpASCII_LF ) ) ) + { + last--; + } + iLength = ( int )( last - pcBuffer ); + FF_PRINTF( " %-*.*s", iLength, iLength, pcBuffer ); + } + return xResult; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigFTP_HAS_RECEIVED_HOOK != 0 ) + + /* + * The following function is called for every file received: + * void vApplicationFTPReceivedHook( pcFileName, ulSize, pxFTPClient ); + * This callback function may do a callback to vFTPReplyMessage() to send messages + * to the FTP client like: + * 200-Please wait: Received new firmware + * 200-Please wait: Please wait a few seconds for reboot + */ + void vFTPReplyMessage( struct xFTP_CLIENT *pxFTPClient, const char *pcMessage ) + { + if( ( pxFTPClient != NULL ) && ( pxFTPClient->xSocket != NULL ) ) + { + prvSendReply( pxFTPClient->xSocket, pcMessage, 0 ); + } + } + /*-----------------------------------------------------------*/ + +#endif /* ipconfigFTP_HAS_RECEIVED_HOOK != 0 */ + +/* + * Some explanation: + * The FTP client may send: "DELE readme.txt" + * Here the complete path is constructed consisting of 3 parts: + * + * pxClient->pcRootDir + pxClient->pcCurrentDir + pcFileName + * + * 'pcCurrentDir' will not be applied for an absolute path like in "DELE /.htaccess" + */ +BaseType_t xMakeAbsolute( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName ) +{ +BaseType_t xLength = strlen( pxClient->pcRootDir ); + + if( pcFileName[ 0 ] != '/' ) + { + char *pcNewDirBuffer = pcNEW_DIR; + BaseType_t xCurLength; + + xCurLength = strlen( pxClient->pcCurrentDir ); + if( pcBuffer == pcNEW_DIR ) + { + /* In one call, the result already goes into pcNEW_DIR. + Use pcFILE_BUFFER in that case */ + pcNewDirBuffer = pcFILE_BUFFER; + } + snprintf( pcNewDirBuffer, sizeof( pcNEW_DIR ), "%s%s%s", + pxClient->pcCurrentDir, + pxClient->pcCurrentDir[ xCurLength - 1 ] == '/' ? "" : "/", + pcFileName ); + pcFileName = pcNewDirBuffer; + } + if( strncasecmp( pxClient->pcRootDir, pcFileName, xLength ) == 0 ) + { + xLength = snprintf( pcBuffer, xBufferLength, "%s", pcFileName ); + } + else + { + xLength = snprintf( pcBuffer, xBufferLength, "%s/%s", + pxClient->pcRootDir, + pcFileName[ 0 ] == '/' ? ( pcFileName + 1 ) : pcFileName ); + } + + #if( ipconfigFTP_FS_USES_BACKSLAH == 1 ) + for( pcPtr = pcBuffer; *pcPtr; pcPtr++ ) + { + if( pcPtr[ 0 ] == '/' ) + { + pcPtr[ 0 ] = '\\'; + } + } + #endif + + return xLength; +} +/*-----------------------------------------------------------*/ + +BaseType_t xMakeRelative( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName ) +{ +BaseType_t xLength = strlen( pxClient->pcRootDir ); + + if( strncasecmp ( pxClient->pcRootDir, pcFileName, xLength ) == 0 ) + { + xLength = snprintf( pcBuffer, xBufferLength, "%s", pcFileName + xLength ); + } + else + { + xLength = snprintf( pcBuffer, xBufferLength, "%s", pcFileName ); + } + + return xLength; +} +/*-----------------------------------------------------------*/ + +#endif /* ipconfigUSE_FTP */ + + + diff --git a/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/HTTP/FreeRTOS_HTTP_commands.c b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/HTTP/FreeRTOS_HTTP_commands.c new file mode 100644 index 000000000..f8b5ac250 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/HTTP/FreeRTOS_HTTP_commands.c @@ -0,0 +1,71 @@ +/* + * FreeRTOS+TCP V2.0.3 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" + +#include "FreeRTOS_HTTP_commands.h" + +const struct xWEB_COMMAND xWebCommands[ WEB_CMD_COUNT ] = +{ + { 3, "GET", ECMD_GET }, + { 4, "HEAD", ECMD_HEAD }, + { 4, "POST", ECMD_POST }, + { 3, "PUT", ECMD_PUT }, + { 6, "DELETE", ECMD_DELETE }, + { 5, "TRACE", ECMD_TRACE }, + { 7, "OPTIONS", ECMD_OPTIONS }, + { 7, "CONNECT", ECMD_CONNECT }, + { 5, "PATCH", ECMD_PATCH }, + { 4, "UNKN", ECMD_UNK }, +}; + +const char *webCodename (int aCode) +{ + switch (aCode) { + case WEB_REPLY_OK: // = 200, + return "OK"; + case WEB_NO_CONTENT: // 204 + return "No content"; + case WEB_BAD_REQUEST: // = 400, + return "Bad request"; + case WEB_UNAUTHORIZED: // = 401, + return "Authorization Required"; + case WEB_NOT_FOUND: // = 404, + return "Not Found"; + case WEB_GONE: // = 410, + return "Done"; + case WEB_PRECONDITION_FAILED: // = 412, + return "Precondition Failed"; + case WEB_INTERNAL_SERVER_ERROR: // = 500, + return "Internal Server Error"; + } + return "Unknown"; +} diff --git a/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/HTTP/FreeRTOS_HTTP_server.c b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/HTTP/FreeRTOS_HTTP_server.c new file mode 100644 index 000000000..ee69fd11e --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/HTTP/FreeRTOS_HTTP_server.c @@ -0,0 +1,428 @@ +/* + * FreeRTOS+TCP V2.0.3 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* FreeRTOS Protocol includes. */ +#include "FreeRTOS_HTTP_commands.h" +#include "FreeRTOS_TCP_server.h" +#include "FreeRTOS_server_private.h" + +/* Remove the whole file if HTTP is not supported. */ +#if( ipconfigUSE_HTTP == 1 ) + +/* FreeRTOS+FAT includes. */ +#include "ff_stdio.h" + +#ifndef HTTP_SERVER_BACKLOG + #define HTTP_SERVER_BACKLOG ( 12 ) +#endif + +#ifndef USE_HTML_CHUNKS + #define USE_HTML_CHUNKS ( 0 ) +#endif + +#if !defined( ARRAY_SIZE ) + #define ARRAY_SIZE(x) ( BaseType_t ) (sizeof( x ) / sizeof( x )[ 0 ] ) +#endif + +/* Some defines to make the code more readbale */ +#define pcCOMMAND_BUFFER pxClient->pxParent->pcCommandBuffer +#define pcNEW_DIR pxClient->pxParent->pcNewDir +#define pcFILE_BUFFER pxClient->pxParent->pcFileBuffer + +#ifndef ipconfigHTTP_REQUEST_CHARACTER + #define ipconfigHTTP_REQUEST_CHARACTER '?' +#endif + +/*_RB_ Need comment block, although fairly self evident. */ +static void prvFileClose( HTTPClient_t *pxClient ); +static BaseType_t prvProcessCmd( HTTPClient_t *pxClient, BaseType_t xIndex ); +static const char *pcGetContentsType( const char *apFname ); +static BaseType_t prvOpenURL( HTTPClient_t *pxClient ); +static BaseType_t prvSendFile( HTTPClient_t *pxClient ); +static BaseType_t prvSendReply( HTTPClient_t *pxClient, BaseType_t xCode ); + +static const char pcEmptyString[1] = { '\0' }; + +typedef struct xTYPE_COUPLE +{ + const char *pcExtension; + const char *pcType; +} TypeCouple_t; + +static TypeCouple_t pxTypeCouples[ ] = +{ + { "html", "text/html" }, + { "css", "text/css" }, + { "js", "text/javascript" }, + { "png", "image/png" }, + { "jpg", "image/jpeg" }, + { "gif", "image/gif" }, + { "txt", "text/plain" }, + { "mp3", "audio/mpeg3" }, + { "wav", "audio/wav" }, + { "flac", "audio/ogg" }, + { "pdf", "application/pdf" }, + { "ttf", "application/x-font-ttf" }, + { "ttc", "application/x-font-ttf" } +}; + +void vHTTPClientDelete( TCPClient_t *pxTCPClient ) +{ +HTTPClient_t *pxClient = ( HTTPClient_t * ) pxTCPClient; + + /* This HTTP client stops, close / release all resources. */ + if( pxClient->xSocket != FREERTOS_NO_SOCKET ) + { + FreeRTOS_FD_CLR( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_ALL ); + FreeRTOS_closesocket( pxClient->xSocket ); + pxClient->xSocket = FREERTOS_NO_SOCKET; + } + prvFileClose( pxClient ); +} +/*-----------------------------------------------------------*/ + +static void prvFileClose( HTTPClient_t *pxClient ) +{ + if( pxClient->pxFileHandle != NULL ) + { + FreeRTOS_printf( ( "Closing file: %s\n", pxClient->pcCurrentFilename ) ); + ff_fclose( pxClient->pxFileHandle ); + pxClient->pxFileHandle = NULL; + } +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvSendReply( HTTPClient_t *pxClient, BaseType_t xCode ) +{ +struct xTCP_SERVER *pxParent = pxClient->pxParent; +BaseType_t xRc; + + /* A normal command reply on the main socket (port 21). */ + char *pcBuffer = pxParent->pcFileBuffer; + + xRc = snprintf( pcBuffer, sizeof( pxParent->pcFileBuffer ), + "HTTP/1.1 %d %s\r\n" +#if USE_HTML_CHUNKS + "Transfer-Encoding: chunked\r\n" +#endif + "Content-Type: %s\r\n" + "Connection: keep-alive\r\n" + "%s\r\n", + ( int ) xCode, + webCodename (xCode), + pxParent->pcContentsType[0] ? pxParent->pcContentsType : "text/html", + pxParent->pcExtraContents ); + + pxParent->pcContentsType[0] = '\0'; + pxParent->pcExtraContents[0] = '\0'; + + xRc = FreeRTOS_send( pxClient->xSocket, ( const void * ) pcBuffer, xRc, 0 ); + pxClient->bits.bReplySent = pdTRUE_UNSIGNED; + + return xRc; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvSendFile( HTTPClient_t *pxClient ) +{ +size_t uxSpace; +size_t uxCount; +BaseType_t xRc = 0; + + if( pxClient->bits.bReplySent == pdFALSE_UNSIGNED ) + { + pxClient->bits.bReplySent = pdTRUE_UNSIGNED; + + strcpy( pxClient->pxParent->pcContentsType, pcGetContentsType( pxClient->pcCurrentFilename ) ); + snprintf( pxClient->pxParent->pcExtraContents, sizeof( pxClient->pxParent->pcExtraContents ), + "Content-Length: %d\r\n", ( int ) pxClient->uxBytesLeft ); + + /* "Requested file action OK". */ + xRc = prvSendReply( pxClient, WEB_REPLY_OK ); + } + + if( xRc >= 0 ) do + { + uxSpace = FreeRTOS_tx_space( pxClient->xSocket ); + + if( pxClient->uxBytesLeft < uxSpace ) + { + uxCount = pxClient->uxBytesLeft; + } + else + { + uxCount = uxSpace; + } + + if( uxCount > 0u ) + { + if( uxCount > sizeof( pxClient->pxParent->pcFileBuffer ) ) + { + uxCount = sizeof( pxClient->pxParent->pcFileBuffer ); + } + ff_fread( pxClient->pxParent->pcFileBuffer, 1, uxCount, pxClient->pxFileHandle ); + pxClient->uxBytesLeft -= uxCount; + + xRc = FreeRTOS_send( pxClient->xSocket, pxClient->pxParent->pcFileBuffer, uxCount, 0 ); + if( xRc < 0 ) + { + break; + } + } + } while( uxCount > 0u ); + + if( pxClient->uxBytesLeft == 0u ) + { + /* Writing is ready, no need for further 'eSELECT_WRITE' events. */ + FreeRTOS_FD_CLR( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); + prvFileClose( pxClient ); + } + else + { + /* Wake up the TCP task as soon as this socket may be written to. */ + FreeRTOS_FD_SET( pxClient->xSocket, pxClient->pxParent->xSocketSet, eSELECT_WRITE ); + } + + return xRc; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvOpenURL( HTTPClient_t *pxClient ) +{ +BaseType_t xRc; +char pcSlash[ 2 ]; + + pxClient->bits.ulFlags = 0; + + #if( ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK != 0 ) + { + if( strchr( pxClient->pcUrlData, ipconfigHTTP_REQUEST_CHARACTER ) != NULL ) + { + size_t xResult; + + xResult = uxApplicationHTTPHandleRequestHook( pxClient->pcUrlData, pxClient->pcCurrentFilename, sizeof( pxClient->pcCurrentFilename ) ); + if( xResult > 0 ) + { + strcpy( pxClient->pxParent->pcContentsType, "text/html" ); + snprintf( pxClient->pxParent->pcExtraContents, sizeof( pxClient->pxParent->pcExtraContents ), + "Content-Length: %d\r\n", ( int ) xResult ); + xRc = prvSendReply( pxClient, WEB_REPLY_OK ); /* "Requested file action OK" */ + if( xRc > 0 ) + { + xRc = FreeRTOS_send( pxClient->xSocket, pxClient->pcCurrentFilename, xResult, 0 ); + } + /* Although against the coding standard of FreeRTOS, a return is + done here to simplify this conditional code. */ + return xRc; + } + } + } + #endif /* ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK */ + + if( pxClient->pcUrlData[ 0 ] != '/' ) + { + /* Insert a slash before the file name. */ + pcSlash[ 0 ] = '/'; + pcSlash[ 1 ] = '\0'; + } + else + { + /* The browser provided a starting '/' already. */ + pcSlash[ 0 ] = '\0'; + } + snprintf( pxClient->pcCurrentFilename, sizeof( pxClient->pcCurrentFilename ), "%s%s%s", + pxClient->pcRootDir, + pcSlash, + pxClient->pcUrlData); + + pxClient->pxFileHandle = ff_fopen( pxClient->pcCurrentFilename, "rb" ); + + FreeRTOS_printf( ( "Open file '%s': %s\n", pxClient->pcCurrentFilename, + pxClient->pxFileHandle != NULL ? "Ok" : strerror( stdioGET_ERRNO() ) ) ); + + if( pxClient->pxFileHandle == NULL ) + { + /* "404 File not found". */ + xRc = prvSendReply( pxClient, WEB_NOT_FOUND ); + } + else + { + pxClient->uxBytesLeft = ( size_t ) pxClient->pxFileHandle->ulFileSize; + xRc = prvSendFile( pxClient ); + } + + return xRc; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvProcessCmd( HTTPClient_t *pxClient, BaseType_t xIndex ) +{ +BaseType_t xResult = 0; + + /* A new command has been received. Process it. */ + switch( xIndex ) + { + case ECMD_GET: + xResult = prvOpenURL( pxClient ); + break; + + case ECMD_HEAD: + case ECMD_POST: + case ECMD_PUT: + case ECMD_DELETE: + case ECMD_TRACE: + case ECMD_OPTIONS: + case ECMD_CONNECT: + case ECMD_PATCH: + case ECMD_UNK: + { + FreeRTOS_printf( ( "prvProcessCmd: Not implemented: %s\n", + xWebCommands[xIndex].pcCommandName ) ); + } + break; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +BaseType_t xHTTPClientWork( TCPClient_t *pxTCPClient ) +{ +BaseType_t xRc; +HTTPClient_t *pxClient = ( HTTPClient_t * ) pxTCPClient; + + if( pxClient->pxFileHandle != NULL ) + { + prvSendFile( pxClient ); + } + + xRc = FreeRTOS_recv( pxClient->xSocket, ( void * )pcCOMMAND_BUFFER, sizeof( pcCOMMAND_BUFFER ), 0 ); + + if( xRc > 0 ) + { + BaseType_t xIndex; + const char *pcEndOfCmd; + const struct xWEB_COMMAND *curCmd; + char *pcBuffer = pcCOMMAND_BUFFER; + + if( xRc < ( BaseType_t ) sizeof( pcCOMMAND_BUFFER ) ) + { + pcBuffer[ xRc ] = '\0'; + } + while( xRc && ( pcBuffer[ xRc - 1 ] == 13 || pcBuffer[ xRc - 1 ] == 10 ) ) + { + pcBuffer[ --xRc ] = '\0'; + } + pcEndOfCmd = pcBuffer + xRc; + + curCmd = xWebCommands; + + /* Pointing to "/index.html HTTP/1.1". */ + pxClient->pcUrlData = pcBuffer; + + /* Pointing to "HTTP/1.1". */ + pxClient->pcRestData = pcEmptyString; + + /* Last entry is "ECMD_UNK". */ + for( xIndex = 0; xIndex < WEB_CMD_COUNT - 1; xIndex++, curCmd++ ) + { + BaseType_t xLength; + + xLength = curCmd->xCommandLength; + if( ( xRc >= xLength ) && ( memcmp( curCmd->pcCommandName, pcBuffer, xLength ) == 0 ) ) + { + char *pcLastPtr; + + pxClient->pcUrlData += xLength + 1; + for( pcLastPtr = (char *)pxClient->pcUrlData; pcLastPtr < pcEndOfCmd; pcLastPtr++ ) + { + char ch = *pcLastPtr; + if( ( ch == '\0' ) || ( strchr( "\n\r \t", ch ) != NULL ) ) + { + *pcLastPtr = '\0'; + pxClient->pcRestData = pcLastPtr + 1; + break; + } + } + break; + } + } + + if( xIndex < ( WEB_CMD_COUNT - 1 ) ) + { + xRc = prvProcessCmd( pxClient, xIndex ); + } + } + else if( xRc < 0 ) + { + /* The connection will be closed and the client will be deleted. */ + FreeRTOS_printf( ( "xHTTPClientWork: rc = %ld\n", xRc ) ); + } + return xRc; +} +/*-----------------------------------------------------------*/ + +static const char *pcGetContentsType (const char *apFname) +{ + const char *slash = NULL; + const char *dot = NULL; + const char *ptr; + const char *pcResult = "text/html"; + BaseType_t x; + + for( ptr = apFname; *ptr; ptr++ ) + { + if (*ptr == '.') dot = ptr; + if (*ptr == '/') slash = ptr; + } + if( dot > slash ) + { + dot++; + for( x = 0; x < ARRAY_SIZE( pxTypeCouples ); x++ ) + { + if( strcasecmp( dot, pxTypeCouples[ x ].pcExtension ) == 0 ) + { + pcResult = pxTypeCouples[ x ].pcType; + break; + } + } + } + return pcResult; +} + +#endif /* ipconfigUSE_HTTP */ + diff --git a/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/NTP/NTPDemo.c b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/NTP/NTPDemo.c new file mode 100644 index 000000000..7795c41da --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/NTP/NTPDemo.c @@ -0,0 +1,440 @@ +/* + * FreeRTOS+TCP V2.0.3 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* + * NTPDemo.c + * + * An example of how to lookup a domain using DNS + * And also how to send and receive UDP messages to get the NTP time + * + */ + +/* Standard includes. */ +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_DNS.h" +#include "FreeRTOS_Stream_Buffer.h" + +/* Use the date & time functions from +FAT. */ +#include "ff_time.h" + +#include "NTPDemo.h" +#include "ntpClient.h" + +#include "date_and_time.h" + +enum EStatus { + EStatusLookup, + EStatusAsking, + EStatusPause, + EStatusFailed, +}; + +static struct SNtpPacket xNTPPacket; + +#if( ipconfigUSE_CALLBACKS == 0 ) + static char cRecvBuffer[ sizeof( struct SNtpPacket ) + 64 ]; +#endif + +static enum EStatus xStatus = EStatusLookup; + +static const char *pcTimeServers[] = { + "0.asia.pool.ntp.org", + "0.europe.pool.ntp.org", + "0.id.pool.ntp.org", + "0.south-america.pool.ntp.org", + "0.oceania.pool.ntp.org", + "0.north-america.pool.ntp.org" +}; + +static SemaphoreHandle_t xNTPWakeupSem = NULL; +static uint32_t ulIPAddressFound; +static Socket_t xUDPSocket = NULL; +static TaskHandle_t xNTPTaskhandle = NULL; +static TickType_t uxSendTime; + +static void prvNTPTask( void *pvParameters ); + +static void vSignalTask( void ) +{ + #if( ipconfigUSE_CALLBACKS == 0 ) + if( xUDPSocket != NULL ) + { + /* Send a signal to the socket so that the + FreeRTOS_recvfrom will get interrupted. */ + FreeRTOS_SignalSocket( xUDPSocket ); + } + else + #endif + if( xNTPWakeupSem != NULL ) + { + xSemaphoreGive( xNTPWakeupSem ); + } +} + +void vStartNTPTask( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ) +{ + /* The only public function in this module: start a task to contact + some NTP server. */ + + if( xNTPTaskhandle != NULL ) + { + switch( xStatus ) + { + case EStatusPause: + xStatus = EStatusAsking; + vSignalTask(); + break; + case EStatusLookup: + FreeRTOS_printf( ( "NTP looking up server\n" ) ); + break; + case EStatusAsking: + FreeRTOS_printf( ( "NTP still asking\n" ) ); + break; + case EStatusFailed: + FreeRTOS_printf( ( "NTP failed somehow\n" ) ); + ulIPAddressFound = 0ul; + xStatus = EStatusLookup; + vSignalTask(); + break; + } + } + else + { + xUDPSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + if( xUDPSocket != NULL ) + { + struct freertos_sockaddr xAddress; + #if( ipconfigUSE_CALLBACKS != 0 ) + BaseType_t xReceiveTimeOut = pdMS_TO_TICKS( 0 ); + #else + BaseType_t xReceiveTimeOut = pdMS_TO_TICKS( 5000 ); + #endif + + xAddress.sin_addr = 0ul; + xAddress.sin_port = FreeRTOS_htons( NTP_PORT ); + + FreeRTOS_bind( xUDPSocket, &xAddress, sizeof( xAddress ) ); + FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + xTaskCreate( prvNTPTask, /* The function that implements the task. */ + ( const char * ) "NTP client", /* Just a text name for the task to aid debugging. */ + usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */ + NULL, /* The task parameter, not used in this case. */ + uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */ + &xNTPTaskhandle ); /* The task handle. */ + } + else + { + FreeRTOS_printf( ( "Creating socket failed\n" ) ); + } + } +} +/*-----------------------------------------------------------*/ + +static void vDNS_callback( const char *pcName, void *pvSearchID, uint32_t ulIPAddress ) +{ +char pcBuf[16]; + + /* The DNS lookup has a result, or it has reached the time-out. */ + FreeRTOS_inet_ntoa( ulIPAddress, pcBuf ); + FreeRTOS_printf( ( "IP address of %s found: %s\n", pcName, pcBuf ) ); + if( ulIPAddressFound == 0ul ) + { + ulIPAddressFound = ulIPAddress; + } + /* For testing: in case DNS doen't respond, still try some NTP server + with a known IP-address. */ + if( ulIPAddressFound == 0ul ) + { + ulIPAddressFound = FreeRTOS_inet_addr_quick( 184, 105, 182, 7 ); +/* ulIPAddressFound = FreeRTOS_inet_addr_quick( 103, 242, 70, 4 ); */ + } + xStatus = EStatusAsking; + + vSignalTask(); +} +/*-----------------------------------------------------------*/ + +static void prvSwapFields( struct SNtpPacket *pxPacket) +{ + /* NTP messages are big-endian */ + pxPacket->rootDelay = FreeRTOS_htonl( pxPacket->rootDelay ); + pxPacket->rootDispersion = FreeRTOS_htonl( pxPacket->rootDispersion ); + + pxPacket->referenceTimestamp.seconds = FreeRTOS_htonl( pxPacket->referenceTimestamp.seconds ); + pxPacket->referenceTimestamp.fraction = FreeRTOS_htonl( pxPacket->referenceTimestamp.fraction ); + + pxPacket->originateTimestamp.seconds = FreeRTOS_htonl( pxPacket->originateTimestamp.seconds ); + pxPacket->originateTimestamp.fraction = FreeRTOS_htonl( pxPacket->originateTimestamp.fraction ); + + pxPacket->receiveTimestamp.seconds = FreeRTOS_htonl( pxPacket->receiveTimestamp.seconds ); + pxPacket->receiveTimestamp.fraction = FreeRTOS_htonl( pxPacket->receiveTimestamp.fraction ); + + pxPacket->transmitTimestamp.seconds = FreeRTOS_htonl( pxPacket->transmitTimestamp.seconds ); + pxPacket->transmitTimestamp.fraction = FreeRTOS_htonl( pxPacket->transmitTimestamp.fraction ); +} +/*-----------------------------------------------------------*/ + +static void prvNTPPacketInit( ) +{ + memset (&xNTPPacket, '\0', sizeof( xNTPPacket ) ); + + xNTPPacket.flags = 0xDB; /* value 0xDB : mode 3 (client), version 3, leap indicator unknown 3 */ + xNTPPacket.poll = 10; /* 10 means 1 << 10 = 1024 seconds */ + xNTPPacket.precision = 0xFA; /* = 250 = 0.015625 seconds */ + xNTPPacket.rootDelay = 0x5D2E; /* 0x5D2E = 23854 or (23854/65535)= 0.3640 sec */ + xNTPPacket.rootDispersion = 0x0008CAC8; /* 0x0008CAC8 = 8.7912 seconds */ + + /* use the recorded NTP time */ + time_t uxSecs = FreeRTOS_time( NULL );/* apTime may be NULL, returns seconds */ + + xNTPPacket.referenceTimestamp.seconds = uxSecs; /* Current time */ + xNTPPacket.transmitTimestamp.seconds = uxSecs + 3; + + /* Transform the contents of the fields from native to big endian. */ + prvSwapFields( &xNTPPacket ); +} +/*-----------------------------------------------------------*/ + +static void prvReadTime( struct SNtpPacket * pxPacket ) +{ + FF_TimeStruct_t xTimeStruct; + time_t uxPreviousSeconds; + time_t uxPreviousMS; + + time_t uxCurrentSeconds; + time_t uxCurrentMS; + + const char *pcTimeUnit; + int32_t ilDiff; + TickType_t uxTravelTime; + + uxTravelTime = xTaskGetTickCount() - uxSendTime; + + /* Transform the contents of the fields from big to native endian. */ + prvSwapFields( pxPacket ); + + uxCurrentSeconds = pxPacket->receiveTimestamp.seconds - TIME1970; + uxCurrentMS = pxPacket->receiveTimestamp.fraction / 4294967; + uxCurrentSeconds += uxCurrentMS / 1000; + uxCurrentMS = uxCurrentMS % 1000; + + // Get the last time recorded + uxPreviousSeconds = FreeRTOS_get_secs_msec( &uxPreviousMS ); + + // Set the new time with precision in msec. */ + FreeRTOS_set_secs_msec( &uxCurrentSeconds, &uxCurrentMS ); + + if( uxCurrentSeconds >= uxPreviousSeconds ) + { + ilDiff = ( int32_t ) ( uxCurrentSeconds - uxPreviousSeconds ); + } + else + { + ilDiff = 0 - ( int32_t ) ( uxPreviousSeconds - uxCurrentSeconds ); + } + + if( ( ilDiff < -5 ) || ( ilDiff > 5 ) ) + { + /* More than 5 seconds difference. */ + pcTimeUnit = "sec"; + } + else + { + /* Less than or equal to 5 second difference. */ + pcTimeUnit = "ms"; + uint32_t ulLowest = ( uxCurrentSeconds <= uxPreviousSeconds ) ? uxCurrentSeconds : uxPreviousSeconds; + int32_t iCurMS = 1000 * ( uxCurrentSeconds - ulLowest ) + uxCurrentMS; + int32_t iPrevMS = 1000 * ( uxPreviousSeconds - ulLowest ) + uxPreviousMS; + ilDiff = iCurMS - iPrevMS; + } + uxCurrentSeconds -= iTimeZone; + + FreeRTOS_gmtime_r( &uxCurrentSeconds, &xTimeStruct ); + + /* + 378.067 [NTP client] NTP time: 9/11/2015 16:11:19.559 Diff -20 ms (289 ms) + 379.441 [NTP client] NTP time: 9/11/2015 16:11:20.933 Diff 0 ms (263 ms) + */ + + FreeRTOS_printf( ("NTP time: %d/%d/%02d %2d:%02d:%02d.%03u Diff %d %s (%lu ms)\n", + xTimeStruct.tm_mday, + xTimeStruct.tm_mon + 1, + xTimeStruct.tm_year + 1900, + xTimeStruct.tm_hour, + xTimeStruct.tm_min, + xTimeStruct.tm_sec, + ( unsigned )uxCurrentMS, + ( unsigned )ilDiff, + pcTimeUnit, + uxTravelTime ) ); + + /* Remove compiler warnings in case FreeRTOS_printf() is not used. */ + ( void ) pcTimeUnit; + ( void ) uxTravelTime; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_CALLBACKS != 0 ) + + static BaseType_t xOnUDPReceive( Socket_t xSocket, void * pvData, size_t xLength, + const struct freertos_sockaddr *pxFrom, const struct freertos_sockaddr *pxDest ) + { + if( xLength >= sizeof( xNTPPacket ) ) + { + prvReadTime( ( struct SNtpPacket *)pvData ); + if( xStatus != EStatusPause ) + { + xStatus = EStatusPause; + } + } + vSignalTask(); + /* Tell the driver not to store the RX data */ + return 1; + } + /*-----------------------------------------------------------*/ + +#endif /* ipconfigUSE_CALLBACKS != 0 */ + +static void prvNTPTask( void *pvParameters ) +{ +BaseType_t xServerIndex = 3; +struct freertos_sockaddr xAddress; +#if( ipconfigUSE_CALLBACKS != 0 ) + F_TCP_UDP_Handler_t xHandler; +#endif /* ipconfigUSE_CALLBACKS != 0 */ + + xStatus = EStatusLookup; + #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 ) || ( ipconfigUSE_CALLBACKS != 0 ) + { + xNTPWakeupSem = xSemaphoreCreateBinary(); + } + #endif + + #if( ipconfigUSE_CALLBACKS != 0 ) + { + memset( &xHandler, '\0', sizeof( xHandler ) ); + xHandler.pxOnUDPReceive = xOnUDPReceive; + FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_UDP_RECV_HANDLER, ( void * ) &xHandler, sizeof( xHandler ) ); + } + #endif + #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 ) + { + FreeRTOS_setsockopt( xUDPSocket, 0, FREERTOS_SO_SET_SEMAPHORE, ( void * ) &xNTPWakeupSem, sizeof( xNTPWakeupSem ) ); + } + #endif + for( ; ; ) + { + switch( xStatus ) + { + case EStatusLookup: + if( ( ulIPAddressFound == 0ul ) || ( ulIPAddressFound == ~0ul ) ) + { + if( ++xServerIndex == sizeof( pcTimeServers ) / sizeof( pcTimeServers[ 0 ] ) ) + { + xServerIndex = 0; + } + FreeRTOS_printf( ( "Looking up server '%s'\n", pcTimeServers[ xServerIndex ] ) ); + FreeRTOS_gethostbyname_a( pcTimeServers[ xServerIndex ], vDNS_callback, (void *)NULL, 1200 ); + } + else + { + xStatus = EStatusAsking; + } + break; + + case EStatusAsking: + { + char pcBuf[16]; + + prvNTPPacketInit( ); + xAddress.sin_addr = ulIPAddressFound; + xAddress.sin_port = FreeRTOS_htons( NTP_PORT ); + + FreeRTOS_inet_ntoa( xAddress.sin_addr, pcBuf ); + FreeRTOS_printf( ( "Sending UDP message to %s:%u\n", + pcBuf, + FreeRTOS_ntohs( xAddress.sin_port ) ) ); + + uxSendTime = xTaskGetTickCount( ); + FreeRTOS_sendto( xUDPSocket, ( void * )&xNTPPacket, sizeof( xNTPPacket ), 0, &xAddress, sizeof( xAddress ) ); + } + break; + + case EStatusPause: + break; + + case EStatusFailed: + break; + } + + #if( ipconfigUSE_CALLBACKS != 0 ) + { + xSemaphoreTake( xNTPWakeupSem, 5000 ); + } + #else + { + uint32_t xAddressSize; + BaseType_t xReturned; + + xAddressSize = sizeof( xAddress ); + xReturned = FreeRTOS_recvfrom( xUDPSocket, ( void * ) cRecvBuffer, sizeof( cRecvBuffer ), 0, &xAddress, &xAddressSize ); + switch( xReturned ) + { + case 0: + case -pdFREERTOS_ERRNO_EAGAIN: + case -pdFREERTOS_ERRNO_EINTR: + break; + default: + if( xReturned < sizeof( xNTPPacket ) ) + { + FreeRTOS_printf( ( "FreeRTOS_recvfrom: returns %ld\n", xReturned ) ); + } + else + { + prvReadTime( ( struct SNtpPacket *)cRecvBuffer ); + if( xStatus != EStatusPause ) + { + xStatus = EStatusPause; + } + } + break; + } + } + #endif + } +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_FTP_commands.h b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_FTP_commands.h new file mode 100644 index 000000000..6ae2384d9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_FTP_commands.h @@ -0,0 +1,133 @@ +/* + * FreeRTOS+TCP V2.0.1 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef __FTPCMD_H__ + +#define __FTPCMD_H__ + +#define REPL_110 "110 Restart marker reply.\r\n" +#define REPL_120 "120 Try again in 2 minutes.\r\n" +#define REPL_125 "125 Data connection already open; transfer starting.\r\n" +#define REPL_150 "150 File status okay; about to open data connection.\r\n" +#define REPL_200 "200 NOOP command successful.\r\n" +#define REPL_200_PROGRESS "200 NOOP: data transfer in progress.\r\n" +#define REPL_202 "202 Command not implemented, superfluous at this site.\r\n" +#define REPL_211 "221 System status, or system help reply.\r\n" +#define REPL_211_STATUS "221-status of %s.\r\n" +#define REPL_211_END "221 End of status.\r\n" +#define REPL_212 "212 Directory status.\r\n" +#define REPL_213 "213 File status.\r\n" +#define REPL_214 "214 Help message.\r\n" +#define REPL_214_END "214 End Help message.\r\n" +#define REPL_215 "215 %s system type.\r\n" +#define REPL_220 "220 Service ready for new user.\r\n" +#define REPL_221 "221 Service closing control connection.\r\n" +#define REPL_225 "225 Data connection open; no transfer in progress.\r\n" +#define REPL_226 "226 Closing data connection.\r\n" +#define REPL_227 "227 Entering Passive Mode (%s,%s,%s,%s,%s,%s).\r\n" +#define REPL_227_D "227 Entering Passive Mode (%u,%u,%u,%u,%u,%u).\r\n" +#define REPL_230 "230 User logged in, proceed.\r\n" +#define REPL_250 "250 Requested file action okay, completed.\r\n" +#define REPL_257 "257 %s created.\r\n" +// #define REPL_257_PWD "257 \"%s\" is current working dir.\r\n" +#define REPL_257_PWD "257 \"%s\"\r\n" +#define REPL_331 "331 Only anonymous user is accepted.\r\n" +#define REPL_331_ANON "331 Anonymous login okay\r\n" +#define REPL_332 "332 Need account for login.\r\n" +#define REPL_350 "350 Requested file action pending further information.\r\n" +#define REPL_421 "421 Service not available, closing control connection.\r\n" +#define REPL_425 "425 Can't open data connection.\r\n" +#define REPL_426 "426 Connection closed; transfer aborted.\r\n" +#define REPL_450 "450 Requested file action not taken.\r\n" +#define REPL_451 "451 Requested action aborted. Local error in processing.\r\n" +#define REPL_452 "452 Requested action not taken.\r\n" +#define REPL_500 "500 Syntax error, command unrecognized.\r\n" +#define REPL_501 "501 Syntax error in parameters or arguments.\r\n" +#define REPL_502 "502 Command not implemented.\r\n" +#define REPL_503 "503 Bad sequence of commands.\r\n" +#define REPL_504 "504 Command not implemented for that parameter.\r\n" +#define REPL_530 "530 Not logged in.\r\n" +#define REPL_532 "532 Need account for storing files.\r\n" +#define REPL_550 "550 Requested action not taken.\r\n" +#define REPL_551 "551 Requested action aborted. Page type unknown.\r\n" +#define REPL_552 "552 Requested file action aborted.\r\n" +#define REPL_553 "553 Requested action not taken.\r\n" +#define REPL_553_READ_ONLY "553 Read-only file-system.\r\n" + +enum EFTPCommand { + ECMD_USER, + ECMD_PASS, + ECMD_ACCT, + ECMD_CWD, + ECMD_CDUP, + ECMD_SMNT, + ECMD_QUIT, + ECMD_REIN, + ECMD_PORT, + ECMD_PASV, + ECMD_TYPE, + ECMD_STRU, + ECMD_MODE, + ECMD_RETR, + ECMD_STOR, + ECMD_STOU, + ECMD_APPE, + ECMD_ALLO, + ECMD_REST, + ECMD_RNFR, + ECMD_RNTO, + ECMD_ABOR, + ECMD_SIZE, + ECMD_MDTM, + ECMD_DELE, + ECMD_RMD, + ECMD_MKD, + ECMD_PWD, + ECMD_LIST, + ECMD_NLST, + ECMD_SITE, + ECMD_SYST, + ECMD_FEAT, + ECMD_STAT, + ECMD_HELP, + ECMD_NOOP, + ECMD_EMPTY, + ECMD_CLOSE, + ECMD_UNKNOWN, +}; + +typedef struct xFTP_COMMAND { + BaseType_t xCommandLength; + const char pcCommandName[7]; + const unsigned char ucCommandType; + const unsigned char checkLogin; + const unsigned char checkNullArg; +} FTPCommand_t; + +#define FTP_CMD_COUNT (ECMD_UNKNOWN+1) + +extern const FTPCommand_t xFTPCommands[ FTP_CMD_COUNT ]; + +#endif // __FTPCMD_H__ diff --git a/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_HTTP_commands.h b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_HTTP_commands.h new file mode 100644 index 000000000..75eaf5d9f --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_HTTP_commands.h @@ -0,0 +1,67 @@ +/* + * FreeRTOS+TCP V2.0.3 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ +#ifndef FREERTOS_HTTP_COMMANDS_H +#define FREERTOS_HTTP_COMMANDS_H + +enum { + WEB_REPLY_OK = 200, + WEB_NO_CONTENT = 204, + WEB_BAD_REQUEST = 400, + WEB_UNAUTHORIZED = 401, + WEB_NOT_FOUND = 404, + WEB_GONE = 410, + WEB_PRECONDITION_FAILED = 412, + WEB_INTERNAL_SERVER_ERROR = 500, +}; + +enum EWebCommand { + ECMD_GET, + ECMD_HEAD, + ECMD_POST, + ECMD_PUT, + ECMD_DELETE, + ECMD_TRACE, + ECMD_OPTIONS, + ECMD_CONNECT, + ECMD_PATCH, + ECMD_UNK, +}; + +struct xWEB_COMMAND +{ + BaseType_t xCommandLength; + const char *pcCommandName; + const unsigned char ucCommandType; +}; + +#define WEB_CMD_COUNT (ECMD_UNK+1) + +extern const struct xWEB_COMMAND xWebCommands[WEB_CMD_COUNT]; + +extern const char *webCodename (int aCode); + +#endif /* FREERTOS_HTTP_COMMANDS_H */ + + diff --git a/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_TCP_server.h b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_TCP_server.h new file mode 100644 index 000000000..d8140ce82 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_TCP_server.h @@ -0,0 +1,125 @@ +/* + * FreeRTOS+TCP V2.0.3 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* + Some code which is common to TCP servers like HTTP en FTP +*/ + +#ifndef FREERTOS_TCP_SERVER_H +#define FREERTOS_TCP_SERVER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef FTP_SERVER_USES_RELATIVE_DIRECTORY + #define FTP_SERVER_USES_RELATIVE_DIRECTORY 0 +#endif + +enum eSERVER_TYPE +{ + eSERVER_NONE, + eSERVER_HTTP, + eSERVER_FTP, +}; + +struct xFTP_CLIENT; + +#if( ipconfigFTP_HAS_RECEIVED_HOOK != 0 ) + extern void vApplicationFTPReceivedHook( const char *pcFileName, uint32_t ulSize, struct xFTP_CLIENT *pxFTPClient ); + extern void vFTPReplyMessage( struct xFTP_CLIENT *pxFTPClient, const char *pcMessage ); +#endif /* ipconfigFTP_HAS_RECEIVED_HOOK != 0 */ + +#if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 ) + /* + * Function is called when a user name has been submitted. + * The function may return a string such as: "331 Please enter your password" + * or return NULL to use the default reply. + */ + extern const char *pcApplicationFTPUserHook( const char *pcUserName ); +#endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */ + +#if( ipconfigFTP_HAS_USER_PASSWORD_HOOK != 0 ) + /* + * Function is called when a password was received. + * Return positive value to allow the user + */ + extern BaseType_t xApplicationFTPPasswordHook( const char *pcUserName, const char *pcPassword ); +#endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */ + +#if( ipconfigFTP_HAS_USER_PROPERTIES_HOOK != 0 ) + /* + * The FTP server is asking for user-specific properties + */ + typedef struct + { + uint16_t usPortNumber; /* For reference only. Host-endian. */ + const char *pcRootDir; + BaseType_t xReadOnly; + } + FTPUserProperties_t; + extern void vApplicationFTPUserPropertiesHook( const char *pcUserName, FTPUserProperties_t *pxProperties ); +#endif /* ipconfigFTP_HAS_USER_PASSWORD_HOOK */ + +#if( ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK != 0 ) + /* + * A GET request is received containing a special character, + * usually a question mark. + * const char *pcURLData; // A request, e.g. "/request?limit=75" + * char *pcBuffer; // Here the answer can be written + * size_t uxBufferLength; // Size of the buffer + * + */ + extern size_t uxApplicationHTTPHandleRequestHook( const char *pcURLData, char *pcBuffer, size_t uxBufferLength ); +#endif /* ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK */ + +struct xSERVER_CONFIG +{ + enum eSERVER_TYPE eType; /* eSERVER_HTTP | eSERVER_FTP */ + BaseType_t xPortNumber; /* e.g. 80, 8080, 21 */ + BaseType_t xBackLog; /* e.g. 10, maximum number of connected TCP clients */ + const char * const pcRootDir; /* Treat this directory as the root directory */ +}; + +struct xTCP_SERVER; +typedef struct xTCP_SERVER TCPServer_t; + +TCPServer_t *FreeRTOS_CreateTCPServer( const struct xSERVER_CONFIG *pxConfigs, BaseType_t xCount ); +void FreeRTOS_TCPServerWork( TCPServer_t *pxServer, TickType_t xBlockingTime ); + +#if( ipconfigSUPPORT_SIGNALS != 0 ) + /* FreeRTOS_TCPServerWork() calls select(). + The two functions below provide a possibility to interrupt + the call to select(). After the interruption, resume + by calling FreeRTOS_TCPServerWork() again. */ + BaseType_t FreeRTOS_TCPServerSignal( TCPServer_t *pxServer ); + BaseType_t FreeRTOS_TCPServerSignalFromISR( TCPServer_t *pxServer, BaseType_t *pxHigherPriorityTaskWoken ); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* FREERTOS_TCP_SERVER_H */ diff --git a/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_server_private.h b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_server_private.h new file mode 100644 index 000000000..73768040e --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/FreeRTOS_server_private.h @@ -0,0 +1,185 @@ +/* + * FreeRTOS+TCP V2.0.3 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + + /* + Some code which is common to TCP servers like HTTP and FTP +*/ + +#ifndef FREERTOS_SERVER_PRIVATE_H +#define FREERTOS_SERVER_PRIVATE_H + +#define FREERTOS_NO_SOCKET NULL + +/* FreeRTOS+FAT */ +#include "ff_stdio.h" + +/* Each HTTP server has 1, at most 2 sockets */ +#define HTTP_SOCKET_COUNT 2 + +/* + * ipconfigTCP_COMMAND_BUFFER_SIZE sets the size of: + * pcCommandBuffer': a buffer to receive and send TCP commands + * + * ipconfigTCP_FILE_BUFFER_SIZE sets the size of: + * pcFileBuffer' : a buffer to access the file system: read or write data. + * + * The buffers are both used for FTP as well as HTTP. + */ + +#ifndef ipconfigTCP_COMMAND_BUFFER_SIZE + #define ipconfigTCP_COMMAND_BUFFER_SIZE ( 2048 ) +#endif + +#ifndef ipconfigTCP_FILE_BUFFER_SIZE + #define ipconfigTCP_FILE_BUFFER_SIZE ( 2048 ) +#endif + +struct xTCP_CLIENT; + +typedef BaseType_t ( * FTCPWorkFunction ) ( struct xTCP_CLIENT * /* pxClient */ ); +typedef void ( * FTCPDeleteFunction ) ( struct xTCP_CLIENT * /* pxClient */ ); + +#define TCP_CLIENT_FIELDS \ + enum eSERVER_TYPE eType; \ + struct xTCP_SERVER *pxParent; \ + Socket_t xSocket; \ + const char *pcRootDir; \ + FTCPWorkFunction fWorkFunction; \ + FTCPDeleteFunction fDeleteFunction; \ + struct xTCP_CLIENT *pxNextClient + +typedef struct xTCP_CLIENT +{ + /* This define contains fields which must come first within each of the client structs */ + TCP_CLIENT_FIELDS; + /* --- Keep at the top --- */ + +} TCPClient_t; + +struct xHTTP_CLIENT +{ + /* This define contains fields which must come first within each of the client structs */ + TCP_CLIENT_FIELDS; + /* --- Keep at the top --- */ + + const char *pcUrlData; + const char *pcRestData; + char pcCurrentFilename[ ffconfigMAX_FILENAME ]; + size_t uxBytesLeft; + FF_FILE *pxFileHandle; + union { + struct { + uint32_t + bReplySent : 1; + }; + uint32_t ulFlags; + } bits; +}; + +typedef struct xHTTP_CLIENT HTTPClient_t; + +struct xFTP_CLIENT +{ + /* This define contains fields which must come first within each of the client structs */ + TCP_CLIENT_FIELDS; + /* --- Keep at the top --- */ + + uint32_t ulRestartOffset; + uint32_t ulRecvBytes; + size_t uxBytesLeft; /* Bytes left to send */ + uint32_t ulClientIP; + TickType_t xStartTime; + uint16_t usClientPort; + Socket_t xTransferSocket; + BaseType_t xTransType; + BaseType_t xDirCount; + FF_FindData_t xFindData; + FF_FILE *pxReadHandle; + FF_FILE *pxWriteHandle; + char pcCurrentDir[ ffconfigMAX_FILENAME ]; + char pcFileName[ ffconfigMAX_FILENAME ]; + char pcConnectionAck[ 128 ]; + char pcClientAck[ 128 ]; + union { + struct { + uint32_t + bHelloSent : 1, + bLoggedIn : 1, + bStatusUser : 1, + bInRename : 1, + bReadOnly : 1; + }; + uint32_t ulFTPFlags; + } bits; + union { + struct { + uint32_t + bIsListen : 1, /* pdTRUE for passive data connections (using list()). */ + bDirHasEntry : 1, /* pdTRUE if ff_findfirst() was successful. */ + bClientConnected : 1, /* pdTRUE after connect() or accept() has succeeded. */ + bEmptyFile : 1, /* pdTRUE if a connection-without-data was received. */ + bHadError : 1; /* pdTRUE if a transfer got aborted because of an error. */ + }; + uint32_t ulConnFlags; + } bits1; +}; + +typedef struct xFTP_CLIENT FTPClient_t; + +BaseType_t xHTTPClientWork( TCPClient_t *pxClient ); +BaseType_t xFTPClientWork( TCPClient_t *pxClient ); + +void vHTTPClientDelete( TCPClient_t *pxClient ); +void vFTPClientDelete( TCPClient_t *pxClient ); + +BaseType_t xMakeAbsolute( struct xFTP_CLIENT *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName ); +BaseType_t xMakeRelative( FTPClient_t *pxClient, char *pcBuffer, BaseType_t xBufferLength, const char *pcFileName ); + +struct xTCP_SERVER +{ + SocketSet_t xSocketSet; + /* A buffer to receive and send TCP commands, either HTTP of FTP. */ + char pcCommandBuffer[ ipconfigTCP_COMMAND_BUFFER_SIZE ]; + /* A buffer to access the file system: read or write data. */ + char pcFileBuffer[ ipconfigTCP_FILE_BUFFER_SIZE ]; + + #if( ipconfigUSE_FTP != 0 ) + char pcNewDir[ ffconfigMAX_FILENAME ]; + #endif + #if( ipconfigUSE_HTTP != 0 ) + char pcContentsType[40]; /* Space for the msg: "text/javascript" */ + char pcExtraContents[40]; /* Space for the msg: "Content-Length: 346500" */ + #endif + BaseType_t xServerCount; + TCPClient_t *pxClients; + struct xSERVER + { + enum eSERVER_TYPE eType; /* eSERVER_HTTP | eSERVER_FTP */ + const char *pcRootDir; + Socket_t xSocket; + } xServers[ 1 ]; +}; + +#endif /* FREERTOS_SERVER_PRIVATE_H */ diff --git a/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/NTPClient.h b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/NTPClient.h new file mode 100644 index 000000000..813539e6e --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/NTPClient.h @@ -0,0 +1,71 @@ +// +// ntpClient.h +// + +#ifndef __NTPCLIENT_H__ + +#define __NTPCLIENT_H__ + +#define NTP_PORT 123 + +typedef uint32_t quint32; +typedef int32_t qint32; +typedef uint8_t quint8; +typedef int8_t qint8; + +typedef union _SNtpFlags SNtpFlags; + +/** + * 64-bit NTP timestamp. + */ +struct __attribute__ ((__packed__)) _SNtpTimestamp { + /** Number of seconds passed since Jan 1 1900, in big-endian format. */ + quint32 seconds; + + /** Fractional time part, in 1/0xFFFFFFFFs of a second. */ + quint32 fraction; +}; + +typedef struct _SNtpTimestamp SNtpTimestamp; +/** + * Mandatory part of an NTP packet + */ +struct SNtpPacket { + /** Flags. */ + unsigned char flags; // value 0xDB : mode 3 (client), version 3, leap indicator unknown 3 + + /** Stratum of the clock. */ + quint8 stratum; // value 0 : unspecified + + /** Maximum interval between successive messages, in log2 seconds. Note that the value is signed. */ + qint8 poll; // 10 means 1 << 10 = 1024 seconds + + /** Precision of the clock, in log2 seconds. Note that the value is signed. */ + qint8 precision; // 0xFA = 250 = 0.015625 seconds + + /** Round trip time to the primary reference source, in NTP short format. */ + qint32 rootDelay; // 0x5D2E = 23854 or (23854/65535)= 0.3640 sec + + /** Nominal error relative to the primary reference source. */ + qint32 rootDispersion; // 0x0008 CAC8 = 8.7912 seconds + + /** Reference identifier (either a 4 character string or an IP address). */ + qint8 referenceID[4]; // or just 0000 + + /** The time at which the clock was last set or corrected. */ + SNtpTimestamp referenceTimestamp; // Current time + + /** The time at which the request departed the client for the server. */ + SNtpTimestamp originateTimestamp; // Keep 0 + + /** The time at which the request arrived at the server. */ + SNtpTimestamp receiveTimestamp; // Keep 0 + + /** The time at which the reply departed the server for client. */ + SNtpTimestamp transmitTimestamp; +}; + +/* Add this number to get secs since 1-1-1900 */ +#define TIME1970 2208988800UL + +#endif // __NTPCLIENT_H__ diff --git a/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/NTPDemo.h b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/NTPDemo.h new file mode 100644 index 000000000..e75fb76aa --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Demo_IP_Protocols/include/NTPDemo.h @@ -0,0 +1,11 @@ +/* + * A simple demo for NTP using FreeRTOS+TCP + */ + +#ifndef NTPDEMO_H + +#define NTPDEMO_H + +void vStartNTPTask( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ); + +#endif \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/File-related-CLI-commands.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/File-related-CLI-commands.c new file mode 100644 index 000000000..ca89864f6 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/File-related-CLI-commands.c @@ -0,0 +1,669 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS+CLI includes. */ +#include "FreeRTOS_CLI.h" + +/* FreeRTOS+FAT includes. */ +#include "ff_headers.h" +#include "ff_stdio.h" + +#define cliNEW_LINE "\r\n" + +/******************************************************************************* + * See the URL in the comments within main.c for the location of the online + * documentation. + ******************************************************************************/ + +/* + * Print out information on a single file. + */ +static void prvCreateFileInfoString( char *pcBuffer, FF_FindData_t *pxFindStruct ); + +/* + * Copies an existing file into a newly created file. + */ +static BaseType_t prvPerformCopy( const char *pcSourceFile, + int32_t lSourceFileLength, + const char *pcDestinationFile, + char *pxWriteBuffer, + size_t xWriteBufferLen ); + +/* + * Implements the DIR command. + */ +static BaseType_t prvDIRCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the CD command. + */ +static BaseType_t prvCDCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the DEL command. + */ +static BaseType_t prvDELCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the DEL command. + */ +static BaseType_t prvRMDIRCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the TYPE command. + */ +static BaseType_t prvTYPECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the COPY command. + */ +static BaseType_t prvCOPYCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the PWD (print working directory) command. + */ +static BaseType_t prvPWDCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* Structure that defines the DIR command line command, which lists all the +files in the current directory. */ +static const CLI_Command_Definition_t xDIR = +{ + "dir", /* The command string to type. */ + "\r\ndir:\r\n Lists the files in the current directory\r\n", + prvDIRCommand, /* The function to run. */ + 0 /* No parameters are expected. */ +}; + +/* Structure that defines the CD command line command, which changes the +working directory. */ +static const CLI_Command_Definition_t xCD = +{ + "cd", /* The command string to type. */ + "\r\ncd :\r\n Changes the working directory\r\n", + prvCDCommand, /* The function to run. */ + 1 /* One parameter is expected. */ +}; + +/* Structure that defines the TYPE command line command, which prints the +contents of a file to the console. */ +static const CLI_Command_Definition_t xTYPE = +{ + "type", /* The command string to type. */ + "\r\ntype :\r\n Prints file contents to the terminal\r\n", + prvTYPECommand, /* The function to run. */ + 1 /* One parameter is expected. */ +}; + +/* Structure that defines the DEL command line command, which deletes a file. */ +static const CLI_Command_Definition_t xDEL = +{ + "del", /* The command string to type. */ + "\r\ndel :\r\n deletes a file (use rmdir to delete a directory)\r\n", + prvDELCommand, /* The function to run. */ + 1 /* One parameter is expected. */ +}; + +/* Structure that defines the RMDIR command line command, which deletes a directory. */ +static const CLI_Command_Definition_t xRMDIR = +{ + "rmdir", /* The command string to type. */ + "\r\nrmdir :\r\n deletes a directory\r\n", + prvRMDIRCommand, /* The function to run. */ + 1 /* One parameter is expected. */ +}; + +/* Structure that defines the COPY command line command, which deletes a file. */ +static const CLI_Command_Definition_t xCOPY = +{ + "copy", /* The command string to type. */ + "\r\ncopy :\r\n Copies to \r\n", + prvCOPYCommand, /* The function to run. */ + 2 /* Two parameters are expected. */ +}; + +/* Structure that defines the pwd command line command, which prints the current working directory. */ +static const CLI_Command_Definition_t xPWD = +{ + "pwd", /* The command string to type. */ + "\r\npwd:\r\n Print Working Directory\r\n", + prvPWDCommand, /* The function to run. */ + 0 /* No parameters are expected. */ +}; + +/*-----------------------------------------------------------*/ + +void vRegisterFileSystemCLICommands( void ) +{ + /* Register all the command line commands defined immediately above. */ + FreeRTOS_CLIRegisterCommand( &xDIR ); + FreeRTOS_CLIRegisterCommand( &xCD ); + FreeRTOS_CLIRegisterCommand( &xTYPE ); + FreeRTOS_CLIRegisterCommand( &xDEL ); + FreeRTOS_CLIRegisterCommand( &xRMDIR ); + FreeRTOS_CLIRegisterCommand( &xCOPY ); + FreeRTOS_CLIRegisterCommand( &xPWD ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvTYPECommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +const char *pcParameter; +BaseType_t xParameterStringLength, xReturn = pdTRUE; +static FF_FILE *pxFile = NULL; +int iChar; +size_t xByte; +size_t xColumns = 50U; + + /* Ensure there is always a null terminator after each character written. */ + memset( pcWriteBuffer, 0x00, xWriteBufferLen ); + + /* Ensure the buffer leaves space for the \r\n. */ + configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) ); + xWriteBufferLen -= strlen( cliNEW_LINE ); + + if( xWriteBufferLen < xColumns ) + { + /* Ensure the loop that uses xColumns as an end condition does not + write off the end of the buffer. */ + xColumns = xWriteBufferLen; + } + + if( pxFile == NULL ) + { + /* The file has not been opened yet. Find the file name. */ + pcParameter = FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 1, /* Return the first parameter. */ + &xParameterStringLength /* Store the parameter string length. */ + ); + + /* Sanity check something was returned. */ + configASSERT( pcParameter ); + + /* Attempt to open the requested file. */ + pxFile = ff_fopen( pcParameter, "r" ); + } + + if( pxFile != NULL ) + { + /* Read the next chunk of data from the file. */ + for( xByte = 0; xByte < xColumns; xByte++ ) + { + iChar = ff_fgetc( pxFile ); + + if( iChar == -1 ) + { + /* No more characters to return. */ + ff_fclose( pxFile ); + pxFile = NULL; + break; + } + else + { + pcWriteBuffer[ xByte ] = ( char ) iChar; + } + } + } + + if( pxFile == NULL ) + { + /* Either the file was not opened, or all the data from the file has + been returned and the file is now closed. */ + xReturn = pdFALSE; + } + + strcat( pcWriteBuffer, cliNEW_LINE ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvCDCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +const char *pcParameter; +BaseType_t xParameterStringLength; +int iReturned; +size_t xStringLength; + + /* Obtain the parameter string. */ + pcParameter = FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 1, /* Return the first parameter. */ + &xParameterStringLength /* Store the parameter string length. */ + ); + + /* Sanity check something was returned. */ + configASSERT( pcParameter ); + + /* Attempt to move to the requested directory. */ + iReturned = ff_chdir( pcParameter ); + + if( iReturned == FF_ERR_NONE ) + { + sprintf( pcWriteBuffer, "In: " ); + xStringLength = strlen( pcWriteBuffer ); + ff_getcwd( &( pcWriteBuffer[ xStringLength ] ), ( unsigned char ) ( xWriteBufferLen - xStringLength ) ); + } + else + { + sprintf( pcWriteBuffer, "Error" ); + } + + strcat( pcWriteBuffer, cliNEW_LINE ); + + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvDIRCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +static FF_FindData_t *pxFindStruct = NULL; +int iReturned; +BaseType_t xReturn = pdFALSE; + + /* This assumes pcWriteBuffer is long enough. */ + ( void ) pcCommandString; + + /* Ensure the buffer leaves space for the \r\n. */ + configASSERT( xWriteBufferLen > ( strlen( cliNEW_LINE ) * 2 ) ); + xWriteBufferLen -= strlen( cliNEW_LINE ); + + if( pxFindStruct == NULL ) + { + /* This is the first time this function has been executed since the Dir + command was run. Create the find structure. */ + pxFindStruct = ( FF_FindData_t * ) pvPortMalloc( sizeof( FF_FindData_t ) ); + + if( pxFindStruct != NULL ) + { + memset( pxFindStruct, 0x00, sizeof( FF_FindData_t ) ); + iReturned = ff_findfirst( "", pxFindStruct ); + + if( iReturned == FF_ERR_NONE ) + { + prvCreateFileInfoString( pcWriteBuffer, pxFindStruct ); + xReturn = pdPASS; + } + else + { + snprintf( pcWriteBuffer, xWriteBufferLen, "Error: ff_findfirst() failed." ); + pxFindStruct = NULL; + } + } + else + { + snprintf( pcWriteBuffer, xWriteBufferLen, "Failed to allocate RAM (using heap_4.c will prevent fragmentation)." ); + } + } + else + { + /* The find struct has already been created. Find the next file in + the directory. */ + iReturned = ff_findnext( pxFindStruct ); + + if( iReturned == FF_ERR_NONE ) + { + prvCreateFileInfoString( pcWriteBuffer, pxFindStruct ); + xReturn = pdPASS; + } + else + { + vPortFree( pxFindStruct ); + pxFindStruct = NULL; + + /* No string to return. */ + pcWriteBuffer[ 0 ] = 0x00; + } + } + + strcat( pcWriteBuffer, cliNEW_LINE ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvRMDIRCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +const char *pcParameter; +BaseType_t xParameterStringLength; +int iReturned; + + /* This function assumes xWriteBufferLen is large enough! */ + ( void ) xWriteBufferLen; + + /* Obtain the parameter string. */ + pcParameter = FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 1, /* Return the first parameter. */ + &xParameterStringLength /* Store the parameter string length. */ + ); + + /* Sanity check something was returned. */ + configASSERT( pcParameter ); + + /* Attempt to delete the directory. */ + iReturned = ff_rmdir( pcParameter ); + + if( iReturned == FF_ERR_NONE ) + { + sprintf( pcWriteBuffer, "%s was deleted", pcParameter ); + } + else + { + sprintf( pcWriteBuffer, "Error. %s was not deleted", pcParameter ); + } + + strcat( pcWriteBuffer, cliNEW_LINE ); + + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvDELCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +const char *pcParameter; +BaseType_t xParameterStringLength; +int iReturned; + + /* This function assumes xWriteBufferLen is large enough! */ + ( void ) xWriteBufferLen; + + /* Obtain the parameter string. */ + pcParameter = FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 1, /* Return the first parameter. */ + &xParameterStringLength /* Store the parameter string length. */ + ); + + /* Sanity check something was returned. */ + configASSERT( pcParameter ); + + /* Attempt to delete the file. */ + iReturned = ff_remove( pcParameter ); + + if( iReturned == FF_ERR_NONE ) + { + sprintf( pcWriteBuffer, "%s was deleted", pcParameter ); + } + else + { + sprintf( pcWriteBuffer, "Error. %s was not deleted", pcParameter ); + } + + strcat( pcWriteBuffer, cliNEW_LINE ); + + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvCOPYCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +char *pcSourceFile; +const char *pcDestinationFile; +BaseType_t xParameterStringLength; +long lSourceLength, lDestinationLength = 0; +FF_Stat_t xStat; + + /* Obtain the name of the destination file. */ + pcDestinationFile = FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 2, /* Return the second parameter. */ + &xParameterStringLength /* Store the parameter string length. */ + ); + + /* Sanity check something was returned. */ + configASSERT( pcDestinationFile ); + + /* Obtain the name of the source file. */ + pcSourceFile = ( char * ) FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 1, /* Return the first parameter. */ + &xParameterStringLength /* Store the parameter string length. */ + ); + + /* Sanity check something was returned. */ + configASSERT( pcSourceFile ); + + /* Terminate the string. */ + pcSourceFile[ xParameterStringLength ] = 0x00; + + /* See if the source file exists, obtain its length if it does. */ + if( ff_stat( pcSourceFile, &xStat ) == FF_ERR_NONE ) + { + lSourceLength = xStat.st_size; + } + else + { + lSourceLength = 0; + } + + if( lSourceLength == 0 ) + { + sprintf( pcWriteBuffer, "Source file does not exist" ); + } + else + { + /* See if the destination file exists. */ + if( ff_stat( pcDestinationFile, &xStat ) == FF_ERR_NONE ) + { + lDestinationLength = xStat.st_size; + } + else + { + lDestinationLength = 0; + } + + if( xStat.st_mode == FF_IFDIR ) + { + sprintf( pcWriteBuffer, "Error: Destination is a directory not a file" ); + + /* Set lDestinationLength to a non-zero value just to prevent an + attempt to copy the file. */ + lDestinationLength = 1; + } + else if( lDestinationLength != 0 ) + { + sprintf( pcWriteBuffer, "Error: Destination file already exists" ); + } + } + + /* Continue only if the source file exists and the destination file does + not exist. */ + if( ( lSourceLength != 0 ) && ( lDestinationLength == 0 ) ) + { + if( prvPerformCopy( pcSourceFile, lSourceLength, pcDestinationFile, pcWriteBuffer, xWriteBufferLen ) == pdPASS ) + { + sprintf( pcWriteBuffer, "Copy made" ); + } + else + { + sprintf( pcWriteBuffer, "Error during copy" ); + } + } + + strcat( pcWriteBuffer, cliNEW_LINE ); + + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvPWDCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ + ( void ) pcCommandString; + + /* Copy the current working directory into the output buffer. */ + ff_getcwd( pcWriteBuffer, xWriteBufferLen ); + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvPerformCopy( const char *pcSourceFile, + int32_t lSourceFileLength, + const char *pcDestinationFile, + char *pxWriteBuffer, + size_t xWriteBufferLen ) +{ +int32_t lBytesRead = 0, lBytesToRead, lBytesRemaining; +FF_FILE *pxSourceFile, *pxDestinationFile; +BaseType_t xReturn = pdPASS; + + /* NOTE: Error handling has been omitted for clarity. */ + + pxSourceFile = ff_fopen( pcSourceFile, "r" ); + pxDestinationFile = ff_fopen( pcDestinationFile, "a" ); + + if( ( pxSourceFile != NULL ) && ( pxDestinationFile != NULL ) ) + { + while( lBytesRead < lSourceFileLength ) + { + /* How many bytes are left? */ + lBytesRemaining = lSourceFileLength - lBytesRead; + + /* How many bytes should be read this time around the loop. Can't + read more bytes than will fit into the buffer. */ + if( lBytesRemaining > ( long ) xWriteBufferLen ) + { + lBytesToRead = ( long ) xWriteBufferLen; + } + else + { + lBytesToRead = lBytesRemaining; + } + + ff_fread( pxWriteBuffer, lBytesToRead, 1, pxSourceFile ); + ff_fwrite( pxWriteBuffer, lBytesToRead, 1, pxDestinationFile ); + + lBytesRead += lBytesToRead; + } + } + + if( pxSourceFile != NULL ) + { + ff_fclose( pxSourceFile ); + } + + if( pxSourceFile != NULL ) + { + ff_fclose( pxDestinationFile ); + } + + if( lBytesRead == lSourceFileLength ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static void prvCreateFileInfoString( char *pcBuffer, FF_FindData_t *pxFindStruct ) +{ +const char * pcWritableFile = "writable file", *pcReadOnlyFile = "read only file", *pcDirectory = "directory"; +const char * pcAttrib; + + /* Point pcAttrib to a string that describes the file. */ + if( ( pxFindStruct->ucAttributes & FF_FAT_ATTR_DIR ) != 0 ) + { + pcAttrib = pcDirectory; + } + else if( pxFindStruct->ucAttributes & FF_FAT_ATTR_READONLY ) + { + pcAttrib = pcReadOnlyFile; + } + else + { + pcAttrib = pcWritableFile; + } + + /* Create a string that includes the file name, the file size and the + attributes string. */ + sprintf( pcBuffer, "%s [%s] [size=%d]", pxFindStruct->pcFileName, pcAttrib, ( int ) pxFindStruct->ulFileSize ); +} + + + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/Sample-CLI-commands.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/Sample-CLI-commands.c new file mode 100644 index 000000000..3b9728e68 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/Sample-CLI-commands.c @@ -0,0 +1,518 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + + /****************************************************************************** + * + * See the following URL for information on the commands defined in this file: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/Embedded_Ethernet_Examples/Ethernet_Related_CLI_Commands.shtml + * + ******************************************************************************/ + + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Standard includes. */ +#include +#include +#include +#include + +/* FreeRTOS+CLI includes. */ +#include "FreeRTOS_CLI.h" + +#ifndef configINCLUDE_TRACE_RELATED_CLI_COMMANDS + #define configINCLUDE_TRACE_RELATED_CLI_COMMANDS 0 +#endif + +#ifndef configINCLUDE_QUERY_HEAP_COMMAND + #define configINCLUDE_QUERY_HEAP_COMMAND 0 +#endif + +/* + * The function that registers the commands that are defined within this file. + */ +void vRegisterSampleCLICommands( void ); + +/* + * Implements the task-stats command. + */ +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + static BaseType_t prvTaskStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); +#endif + +/* + * Implements the run-time-stats command. + */ +#if( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + static BaseType_t prvRunTimeStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); +#endif + +/* + * Implements the echo-three-parameters command. + */ +static BaseType_t prvThreeParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the echo-parameters command. + */ +static BaseType_t prvParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the "query heap" command. + */ +#if( configINCLUDE_QUERY_HEAP_COMMAND == 1 ) + static BaseType_t prvQueryHeapCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); +#endif + +/* + * Implements the "trace start" and "trace stop" commands; + */ +#if( configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 ) + static BaseType_t prvStartStopTraceCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); +#endif + +/* Structure that defines the "run-time-stats" command line command. This +generates a table that shows how much run time each task has */ +#if( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + static const CLI_Command_Definition_t xRunTimeStats = + { + "run-time-stats", /* The command string to type. */ + "\r\nrun-time-stats:\r\n Displays a table showing how much processing time each FreeRTOS task has used\r\n", + prvRunTimeStatsCommand, /* The function to run. */ + 0 /* No parameters are expected. */ + }; +#endif + +/* Structure that defines the "task-stats" command line command. This generates +a table that gives information on each task in the system. */ +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + static const CLI_Command_Definition_t xTaskStats = + { + "task-stats", /* The command string to type. */ + "\r\ntask-stats:\r\n Displays a table showing the state of each FreeRTOS task\r\n", + prvTaskStatsCommand, /* The function to run. */ + 0 /* No parameters are expected. */ + }; +#endif + +/* Structure that defines the "echo_3_parameters" command line command. This +takes exactly three parameters that the command simply echos back one at a +time. */ +static const CLI_Command_Definition_t xThreeParameterEcho = +{ + "echo-3-parameters", + "\r\necho-3-parameters :\r\n Expects three parameters, echos each in turn\r\n", + prvThreeParameterEchoCommand, /* The function to run. */ + 3 /* Three parameters are expected, which can take any value. */ +}; + +/* Structure that defines the "echo_parameters" command line command. This +takes a variable number of parameters that the command simply echos back one at +a time. */ +static const CLI_Command_Definition_t xParameterEcho = +{ + "echo-parameters", + "\r\necho-parameters <...>:\r\n Take variable number of parameters, echos each in turn\r\n", + prvParameterEchoCommand, /* The function to run. */ + -1 /* The user can enter any number of commands. */ +}; + +#if( configINCLUDE_QUERY_HEAP_COMMAND == 1 ) + /* Structure that defines the "query_heap" command line command. */ + static const CLI_Command_Definition_t xQueryHeap = + { + "query-heap", + "\r\nquery-heap:\r\n Displays the free heap space, and minimum ever free heap space.\r\n", + prvQueryHeapCommand, /* The function to run. */ + 0 /* The user can enter any number of commands. */ + }; +#endif /* configQUERY_HEAP_COMMAND */ + +#if configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 + /* Structure that defines the "trace" command line command. This takes a single + parameter, which can be either "start" or "stop". */ + static const CLI_Command_Definition_t xStartStopTrace = + { + "trace", + "\r\ntrace [start | stop]:\r\n Starts or stops a trace recording for viewing in FreeRTOS+Trace\r\n", + prvStartStopTraceCommand, /* The function to run. */ + 1 /* One parameter is expected. Valid values are "start" and "stop". */ + }; +#endif /* configINCLUDE_TRACE_RELATED_CLI_COMMANDS */ + +/*-----------------------------------------------------------*/ + +void vRegisterSampleCLICommands( void ) +{ + /* Register all the command line commands defined immediately above. */ + FreeRTOS_CLIRegisterCommand( &xThreeParameterEcho ); + FreeRTOS_CLIRegisterCommand( &xParameterEcho ); + + #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + { + FreeRTOS_CLIRegisterCommand( &xTaskStats ); + } + #endif + + #if( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + { + FreeRTOS_CLIRegisterCommand( &xRunTimeStats ); + } + #endif + + #if( configINCLUDE_QUERY_HEAP_COMMAND == 1 ) + { + FreeRTOS_CLIRegisterCommand( &xQueryHeap ); + } + #endif + + #if( configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 ) + { + FreeRTOS_CLIRegisterCommand( &xStartStopTrace ); + } + #endif +} +/*-----------------------------------------------------------*/ + +#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + + static BaseType_t prvTaskStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) + { + const char *const pcHeader = " State\tPriority\tStack\t#\r\n************************************************\r\n"; + BaseType_t xSpacePadding; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + /* Generate a table of task stats. */ + strcpy( pcWriteBuffer, "Task" ); + pcWriteBuffer += strlen( pcWriteBuffer ); + + /* Minus three for the null terminator and half the number of characters in + "Task" so the column lines up with the centre of the heading. */ + configASSERT( configMAX_TASK_NAME_LEN > 3 ); + for( xSpacePadding = strlen( "Task" ); xSpacePadding < ( configMAX_TASK_NAME_LEN - 3 ); xSpacePadding++ ) + { + /* Add a space to align columns after the task's name. */ + *pcWriteBuffer = ' '; + pcWriteBuffer++; + + /* Ensure always terminated. */ + *pcWriteBuffer = 0x00; + } + strcpy( pcWriteBuffer, pcHeader ); + vTaskList( pcWriteBuffer + strlen( pcHeader ) ); + + /* There is no more data to return after this single string, so return + pdFALSE. */ + return pdFALSE; + } + +#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ +/*-----------------------------------------------------------*/ + +#if( configINCLUDE_QUERY_HEAP_COMMAND == 1 ) + + static BaseType_t prvQueryHeapCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) + { + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + sprintf( pcWriteBuffer, "Current free heap %d bytes, minimum ever free heap %d bytes\r\n", ( int ) xPortGetFreeHeapSize(), ( int ) xPortGetMinimumEverFreeHeapSize() ); + + /* There is no more data to return after this single string, so return + pdFALSE. */ + return pdFALSE; + } + +#endif /* configINCLUDE_QUERY_HEAP */ +/*-----------------------------------------------------------*/ + +#if( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) + + static BaseType_t prvRunTimeStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) + { + const char * const pcHeader = "Task Abs Time % Time\r\n****************************************\r\n"; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + /* Generate a table of task stats. */ + strcpy( pcWriteBuffer, pcHeader ); + vTaskGetRunTimeStats( pcWriteBuffer + strlen( pcHeader ) ); + + /* There is no more data to return after this single string, so return + pdFALSE. */ + return pdFALSE; + } + +#endif /* configGENERATE_RUN_TIME_STATS */ +/*-----------------------------------------------------------*/ + +static BaseType_t prvThreeParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +const char *pcParameter; +BaseType_t xParameterStringLength, xReturn; +static BaseType_t lParameterNumber = 0; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + if( lParameterNumber == 0 ) + { + /* The first time the function is called after the command has been + entered just a header string is returned. */ + sprintf( pcWriteBuffer, "The three parameters were:\r\n" ); + + /* Next time the function is called the first parameter will be echoed + back. */ + lParameterNumber = 1L; + + /* There is more data to be returned as no parameters have been echoed + back yet. */ + xReturn = pdPASS; + } + else + { + /* Obtain the parameter string. */ + pcParameter = FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + lParameterNumber, /* Return the next parameter. */ + &xParameterStringLength /* Store the parameter string length. */ + ); + + /* Sanity check something was returned. */ + configASSERT( pcParameter ); + + /* Return the parameter string. */ + memset( pcWriteBuffer, 0x00, xWriteBufferLen ); + sprintf( pcWriteBuffer, "%d: ", ( int ) lParameterNumber ); + strncat( pcWriteBuffer, pcParameter, xParameterStringLength ); + strncat( pcWriteBuffer, "\r\n", strlen( "\r\n" ) ); + + /* If this is the last of the three parameters then there are no more + strings to return after this one. */ + if( lParameterNumber == 3L ) + { + /* If this is the last of the three parameters then there are no more + strings to return after this one. */ + xReturn = pdFALSE; + lParameterNumber = 0L; + } + else + { + /* There are more parameters to return after this one. */ + xReturn = pdTRUE; + lParameterNumber++; + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +const char *pcParameter; +BaseType_t xParameterStringLength, xReturn; +static BaseType_t lParameterNumber = 0; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + if( lParameterNumber == 0 ) + { + /* The first time the function is called after the command has been + entered just a header string is returned. */ + sprintf( pcWriteBuffer, "The parameters were:\r\n" ); + + /* Next time the function is called the first parameter will be echoed + back. */ + lParameterNumber = 1L; + + /* There is more data to be returned as no parameters have been echoed + back yet. */ + xReturn = pdPASS; + } + else + { + /* Obtain the parameter string. */ + pcParameter = FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + lParameterNumber, /* Return the next parameter. */ + &xParameterStringLength /* Store the parameter string length. */ + ); + + if( pcParameter != NULL ) + { + /* Return the parameter string. */ + memset( pcWriteBuffer, 0x00, xWriteBufferLen ); + sprintf( pcWriteBuffer, "%d: ", ( int ) lParameterNumber ); + strncat( pcWriteBuffer, pcParameter, xParameterStringLength ); + strncat( pcWriteBuffer, "\r\n", strlen( "\r\n" ) ); + + /* There might be more parameters to return after this one. */ + xReturn = pdTRUE; + lParameterNumber++; + } + else + { + /* No more parameters were found. Make sure the write buffer does + not contain a valid string. */ + pcWriteBuffer[ 0 ] = 0x00; + + /* No more data to return. */ + xReturn = pdFALSE; + + /* Start over the next time this command is executed. */ + lParameterNumber = 0; + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +#if configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 + + static BaseType_t prvStartStopTraceCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) + { + const char *pcParameter; + BaseType_t lParameterStringLength; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + /* Obtain the parameter string. */ + pcParameter = FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 1, /* Return the first parameter. */ + &lParameterStringLength /* Store the parameter string length. */ + ); + + /* Sanity check something was returned. */ + configASSERT( pcParameter ); + + /* There are only two valid parameter values. */ + if( strncmp( pcParameter, "start", strlen( "start" ) ) == 0 ) + { + /* Start or restart the trace. */ + vTraceStop(); + vTraceClear(); + vTraceStart(); + + sprintf( pcWriteBuffer, "Trace recording (re)started.\r\n" ); + } + else if( strncmp( pcParameter, "stop", strlen( "stop" ) ) == 0 ) + { + /* End the trace, if one is running. */ + vTraceStop(); + sprintf( pcWriteBuffer, "Stopping trace recording.\r\n" ); + } + else + { + sprintf( pcWriteBuffer, "Valid parameters are 'start' and 'stop'.\r\n" ); + } + + /* There is no more data to return after this single string, so return + pdFALSE. */ + return pdFALSE; + } + +#endif /* configINCLUDE_TRACE_RELATED_CLI_COMMANDS */ diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/TCP-related-CLI-commands.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/TCP-related-CLI-commands.c new file mode 100644 index 000000000..a99839669 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/TCP-related-CLI-commands.c @@ -0,0 +1,374 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS+CLI includes. */ +#include "FreeRTOS_CLI.h" + +/* FreeRTOS+TCP includes, just to make the stats available to the CLI +commands. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* + * Defines a command that prints out IP address information. + */ +static BaseType_t prvDisplayIPConfig( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Defines a command that prints out the gathered demo debug stats. + */ +#if( configINCLUDE_DEMO_DEBUG_STATS != 0 ) + static BaseType_t prvDisplayIPDebugStats( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); +#endif + +/* + * Defines a command that sends an ICMP ping request to an IP address. + */ +#if( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + static BaseType_t prvPingCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); +#endif + +/* + * Defines a command that calls FreeRTOS_netstat(). + */ +static BaseType_t prvNetStatCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* Structure that defines the "ip-config" command line command. */ +static const CLI_Command_Definition_t xIPConfig = +{ + "ip-config", + "\r\nip-config:\r\n Displays IP address configuration\r\n", + prvDisplayIPConfig, + 0 +}; + +#if( configINCLUDE_DEMO_DEBUG_STATS != 0 ) + /* Structure that defines the "ip-debug-stats" command line command. */ + static const CLI_Command_Definition_t xIPDebugStats = + { + "ip-debug-stats", /* The command string to type. */ + "\r\nip-debug-stats:\r\n Shows some IP stack stats useful for debug - an example only.\r\n", + prvDisplayIPDebugStats, /* The function to run. */ + 0 /* No parameters are expected. */ + }; +#endif /* configINCLUDE_DEMO_DEBUG_STATS */ + +#if( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + + /* Structure that defines the "ping" command line command. This takes an IP + address or host name and (optionally) the number of bytes to ping as + parameters. */ + static const CLI_Command_Definition_t xPing = + { + "ping", + "\r\nping :\r\n for example, ping 192.168.0.3 8, or ping www.example.com\r\n", + prvPingCommand, /* The function to run. */ + -1 /* Ping can take either one or two parameter, so the number of parameters has to be determined by the ping command implementation. */ + }; + +#endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + +/* Structure that defines the "task-stats" command line command. This generates +a table that gives information on each task in the system. */ +static const CLI_Command_Definition_t xNetStats = +{ + "net-stats", /* The command string to type. */ + "\r\nnet-stats:\r\n Calls FreeRTOS_netstat()\r\n", + prvNetStatCommand, /* The function to run. */ + 0 /* No parameters are expected. */ +}; + +/*-----------------------------------------------------------*/ + +void vRegisterTCPCLICommands( void ) +{ + /* Register all the command line commands defined immediately above. */ + FreeRTOS_CLIRegisterCommand( &xIPConfig ); + + #if( configINCLUDE_DEMO_DEBUG_STATS == 1 ) + { + FreeRTOS_CLIRegisterCommand( &xIPDebugStats ); + } + #endif /* configINCLUDE_DEMO_DEBUG_STATS */ + + #if( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + { + FreeRTOS_CLIRegisterCommand( &xPing ); + } + #endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + + FreeRTOS_CLIRegisterCommand( &xNetStats ); +} +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + + static BaseType_t prvPingCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) + { + char * pcParameter; + BaseType_t lParameterStringLength, xReturn = pdFALSE; + uint32_t ulIPAddress, ulBytesToPing; + const uint32_t ulDefaultBytesToPing = 8UL; + char cBuffer[ 16 ]; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + /* Start with an empty string. */ + pcWriteBuffer[ 0 ] = 0x00; + + /* Obtain the number of bytes to ping. */ + pcParameter = ( char * ) FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 2, /* Return the second parameter. */ + &lParameterStringLength /* Store the parameter string length. */ + ); + + if( pcParameter == NULL ) + { + /* The number of bytes was not specified, so default it. */ + ulBytesToPing = ulDefaultBytesToPing; + } + else + { + ulBytesToPing = atol( pcParameter ); + } + + /* Obtain the IP address string. */ + pcParameter = ( char * ) FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 1, /* Return the first parameter. */ + &lParameterStringLength /* Store the parameter string length. */ + ); + + if( pcParameter != NULL ) + { + /* Terminate the host name or IP address string. */ + pcParameter[ lParameterStringLength ] = 0x00; + + /* Attempt to obtain the IP address. If the first character is not a + digit, assume the host name has been passed in. */ + if( ( *pcParameter >= '0' ) && ( *pcParameter <= '9' ) ) + { + ulIPAddress = FreeRTOS_inet_addr( pcParameter ); + } + else + { + /* Attempt to resolve host. */ + ulIPAddress = FreeRTOS_gethostbyname( pcParameter ); + } + + /* Convert IP address, which may have come from a DNS lookup, to string. */ + FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); + + if( ulIPAddress != 0 ) + { + xReturn = FreeRTOS_SendPingRequest( ulIPAddress, ( uint16_t ) ulBytesToPing, portMAX_DELAY ); + } + } + + if( xReturn == pdFALSE ) + { + sprintf( pcWriteBuffer, "%s", "Could not send ping request\r\n" ); + } + else + { + sprintf( pcWriteBuffer, "Ping sent to %s with identifier %d\r\n", cBuffer, ( int ) xReturn ); + } + + return pdFALSE; + } + /*-----------------------------------------------------------*/ + +#endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + +#if( configINCLUDE_DEMO_DEBUG_STATS != 0 ) + + static BaseType_t prvDisplayIPDebugStats( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) + { + static BaseType_t xIndex = -1; + extern ExampleDebugStatEntry_t xIPTraceValues[]; + BaseType_t xReturn; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + xIndex++; + + if( xIndex < xExampleDebugStatEntries() ) + { + sprintf( pcWriteBuffer, "%s %d\r\n", ( char * ) xIPTraceValues[ xIndex ].pucDescription, ( int ) xIPTraceValues[ xIndex ].ulData ); + xReturn = pdPASS; + } + else + { + /* Reset the index for the next time it is called. */ + xIndex = -1; + + /* Ensure nothing remains in the write buffer. */ + pcWriteBuffer[ 0 ] = 0x00; + xReturn = pdFALSE; + } + + return xReturn; + } + /*-----------------------------------------------------------*/ + +#endif /* configINCLUDE_DEMO_DEBUG_STATS */ + +static BaseType_t prvDisplayIPConfig( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +static BaseType_t xIndex = 0; +BaseType_t xReturn; +uint32_t ulAddress; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + switch( xIndex ) + { + case 0 : + FreeRTOS_GetAddressConfiguration( &ulAddress, NULL, NULL, NULL ); + sprintf( pcWriteBuffer, "\r\nIP address " ); + xReturn = pdTRUE; + xIndex++; + break; + + case 1 : + FreeRTOS_GetAddressConfiguration( NULL, &ulAddress, NULL, NULL ); + sprintf( pcWriteBuffer, "\r\nNet mask " ); + xReturn = pdTRUE; + xIndex++; + break; + + case 2 : + FreeRTOS_GetAddressConfiguration( NULL, NULL, &ulAddress, NULL ); + sprintf( pcWriteBuffer, "\r\nGateway address " ); + xReturn = pdTRUE; + xIndex++; + break; + + case 3 : + FreeRTOS_GetAddressConfiguration( NULL, NULL, NULL, &ulAddress ); + sprintf( pcWriteBuffer, "\r\nDNS server address " ); + xReturn = pdTRUE; + xIndex++; + break; + + default : + ulAddress = 0; + sprintf( pcWriteBuffer, "\r\n\r\n" ); + xReturn = pdFALSE; + xIndex = 0; + break; + } + + if( ulAddress != 0 ) + { + FreeRTOS_inet_ntoa( ulAddress, ( &( pcWriteBuffer[ strlen( pcWriteBuffer ) ] ) ) ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvNetStatCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ + ( void ) pcWriteBuffer; + ( void ) xWriteBufferLen; + ( void ) pcCommandString; + + FreeRTOS_netstat(); + snprintf( pcWriteBuffer, xWriteBufferLen, "FreeRTOS_netstat() called - output uses FreeRTOS_printf\r\n" ); + return pdFALSE; +} + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/TCPCommandConsole.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/TCPCommandConsole.c new file mode 100644 index 000000000..1250ef917 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/TCPCommandConsole.c @@ -0,0 +1,365 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+CLI includes. */ +#include "FreeRTOS_CLI.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Demo app includes. */ +#include "TCPCommandConsole.h" + +/* Dimensions the buffer into which input characters are placed. */ +#define cmdMAX_INPUT_SIZE 60 + +/* Dimensions the buffer into which string outputs can be placed. */ +#define cmdMAX_OUTPUT_SIZE 1024 + +/* Dimensions the buffer passed to the recv() call. */ +#define cmdSOCKET_INPUT_BUFFER_SIZE 60 + +/* DEL acts as a backspace. */ +#define cmdASCII_DEL ( 0x7F ) + +/* The maximum time to wait for a closing socket to close. */ +#define cmdSHUTDOWN_DELAY ( pdMS_TO_TICKS( 5000 ) ) + +/* + * The task that runs FreeRTOS+CLI. + */ +static void prvTCPCommandInterpreterTask( void *pvParameters ); + +/* + * Open and configure the TCP socket. + */ +static Socket_t prvOpenTCPServerSocket( uint16_t usPort ); + +/* + * A connected socket is being closed. Ensure the socket is closed at both ends + * properly. + */ +static void prvGracefulShutdown( Socket_t xSocket ); + +/*-----------------------------------------------------------*/ + +/* + * Various buffers used by the command lin interpreter. + */ +static char cOutputString[ cmdMAX_OUTPUT_SIZE ], cLocalBuffer[ cmdSOCKET_INPUT_BUFFER_SIZE ]; +static char cInputString[ cmdMAX_INPUT_SIZE ], cLastInputString[ cmdMAX_INPUT_SIZE ]; + +/* Const messages output by the command console. */ +static const char * const pcWelcomeMessage = "FreeRTOS command server.\r\nType help to view a list of registered commands.\r\nType quit to end a session.\r\n\r\n>"; +static const char * const pcEndOfOutputMessage = "\r\n[Press ENTER to execute the previous command again]\r\n>"; +static const char * const pcNewLine = "\r\n"; + +/*-----------------------------------------------------------*/ + +void vStartTCPCommandInterpreterTask( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority ) +{ + xTaskCreate( prvTCPCommandInterpreterTask, "TCP CLI", usStackSize, ( void * ) ulPort, uxPriority, NULL ); +} +/*-----------------------------------------------------------*/ + +void prvTCPCommandInterpreterTask( void *pvParameters ) +{ +int32_t lBytes, lByte, lSent; +char cRxedChar, cInputIndex = 0; +BaseType_t xMoreDataToFollow; +struct freertos_sockaddr xClient; +Socket_t xListeningSocket, xConnectedSocket; +socklen_t xSize = sizeof( xClient ); + + memset( cInputString, 0x00, cmdMAX_INPUT_SIZE ); + + for( ;; ) + { + /* Attempt to open the socket. The port number is passed in the task + parameter. The strange casting is to remove compiler warnings on 32-bit + machines. NOTE: The FREERTOS_SO_REUSE_LISTEN_SOCKET option is used, + so the listening and connecting socket are the same - meaning only one + connection will be accepted at a time, and that xListeningSocket must + be created on each iteration. */ + xListeningSocket = prvOpenTCPServerSocket( ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL ); + + /* Nothing for this task to do if the socket cannot be created. */ + if( xListeningSocket == FREERTOS_INVALID_SOCKET ) + { + vTaskDelete( NULL ); + } + + /* Wait for an incoming connection. */ + xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize ); + + /* The FREERTOS_SO_REUSE_LISTEN_SOCKET option is set, so the + connected and listening socket should be the same socket. */ + configASSERT( xConnectedSocket == xListeningSocket ); + + /* Send the welcome message. */ + lSent = FreeRTOS_send( xConnectedSocket, ( void * ) pcWelcomeMessage, strlen( pcWelcomeMessage ), 0 ); + + /* Process the socket as long as it remains connected. */ + while( lSent >= 0 ) + { + /* Receive data on the socket. */ + lBytes = FreeRTOS_recv( xConnectedSocket, cLocalBuffer, sizeof( cLocalBuffer ), 0 ); + + if( lBytes >= 0 ) + { + /* Process each received byte in turn. */ + lByte = 0; + while( lByte < lBytes ) + { + /* The next character in the input buffer. */ + cRxedChar = cLocalBuffer[ lByte ]; + lByte++; + + /* Newline characters are taken as the end of the command + string. */ + if( cRxedChar == '\n' ) + { + /* Just to space the output from the input. */ + FreeRTOS_send( xConnectedSocket, pcNewLine, strlen( pcNewLine ), 0 ); + + /* See if the command is empty, indicating that the last + command is to be executed again. */ + if( cInputIndex == 0 ) + { + /* Copy the last command back into the input string. */ + strcpy( cInputString, cLastInputString ); + } + + /* If the command was "quit" then close the console. */ + if( strcasecmp( cInputString, "quit" ) == 0 ) + { + /* Fake an error code so the outer loop exits on the + assumption there was an error on the socket. The + socket will then be shut down gracefully. */ + lSent = -1; + break; + } + + /* Process the input string received prior to the + newline. */ + do + { + /* Pass the string to FreeRTOS+CLI. */ + cOutputString[ 0 ] = 0x00; + xMoreDataToFollow = FreeRTOS_CLIProcessCommand( cInputString, cOutputString, cmdMAX_OUTPUT_SIZE ); + + /* Send the output generated by the command's + implementation. */ + lSent = FreeRTOS_send( xConnectedSocket, cOutputString, strlen( ( const char * ) cOutputString ), 0 ); + + /* Until the command does not generate any more output. */ + } while( ( xMoreDataToFollow != pdFALSE ) && ( lSent >= 0 ) ); + + if( lSent >= 0 ) + { + /* All the strings generated by the command + processing have been sent. Clear the input string + ready to receive the next command. Remember the + previous command so it can be executed again by + pressing [ENTER]. */ + strcpy( cLastInputString, cInputString ); + cInputIndex = 0; + memset( cInputString, 0x00, cmdMAX_INPUT_SIZE ); + + /* Transmit a spacer to make the console easier to + read. */ + lSent = FreeRTOS_send( xConnectedSocket, ( void * ) pcEndOfOutputMessage, strlen( pcEndOfOutputMessage ), 0 ); + } + + if( lSent < 0 ) + { + /* Socket closed? */ + break; + } + } + else + { + if( cRxedChar == '\r' ) + { + /* Ignore the character. Newlines are used to + detect the end of the input string. */ + } + else if( ( cRxedChar == '\b' ) || ( cRxedChar == cmdASCII_DEL ) ) + { + /* Backspace was pressed. Erase the last character + in the string - if any. */ + if( cInputIndex > 0 ) + { + cInputIndex--; + cInputString[ ( int ) cInputIndex ] = '\0'; + } + } + else + { + /* A character was entered. Add it to the string + entered so far. When a \n is entered the complete + string will be passed to the command interpreter. */ + if( cInputIndex < cmdMAX_INPUT_SIZE ) + { + if( ( cRxedChar >= ' ' ) && ( cRxedChar <= '~' ) ) + { + cInputString[ ( int ) cInputIndex ] = cRxedChar; + cInputIndex++; + } + } + } + } + } + } + else + { + /* Socket closed? */ + break; + } + } + + /* Close the socket correctly. */ + prvGracefulShutdown( xListeningSocket ); + } +} +/*-----------------------------------------------------------*/ + +static void prvGracefulShutdown( Socket_t xSocket ) +{ +TickType_t xTimeOnShutdown; + + /* Initiate a shutdown in case it has not already been initiated. */ + FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR ); + + /* Wait for the shutdown to take effect, indicated by FreeRTOS_recv() + returning an error. */ + xTimeOnShutdown = xTaskGetTickCount(); + do + { + if( FreeRTOS_recv( xSocket, cInputString, ipconfigTCP_MSS, 0 ) < 0 ) + { + break; + } + } while( ( xTaskGetTickCount() - xTimeOnShutdown ) < cmdSHUTDOWN_DELAY ); + + /* Finished with the socket and the task. */ + FreeRTOS_closesocket( xSocket ); +} +/*-----------------------------------------------------------*/ + +static Socket_t prvOpenTCPServerSocket( uint16_t usPort ) +{ +struct freertos_sockaddr xBindAddress; +Socket_t xSocket; +static const TickType_t xReceiveTimeOut = portMAX_DELAY; +const BaseType_t xBacklog = 20; +BaseType_t xReuseSocket = pdTRUE; + + /* Attempt to open the socket. */ + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + configASSERT( xSocket != FREERTOS_INVALID_SOCKET ); + + /* Set a time out so accept() will just wait for a connection. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + + /* Only one connection will be used at a time, so re-use the listening + socket as the connected socket. See SimpleTCPEchoServer.c for an example + that accepts multiple connections. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_REUSE_LISTEN_SOCKET, &xReuseSocket, sizeof( xReuseSocket ) ); + + /* NOTE: The CLI is a low bandwidth interface (typing characters is slow), + so the TCP window properties are left at their default. See + SimpleTCPEchoServer.c for an example of a higher throughput TCP server that + uses are larger RX and TX buffer. */ + + /* Bind the socket to the port that the client task will send to, then + listen for incoming connections. */ + xBindAddress.sin_port = usPort; + xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port ); + FreeRTOS_bind( xSocket, &xBindAddress, sizeof( xBindAddress ) ); + FreeRTOS_listen( xSocket, xBacklog ); + + return xSocket; +} +/*-----------------------------------------------------------*/ + + + + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/UARTCommandConsole.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/UARTCommandConsole.c new file mode 100644 index 000000000..3ab14bb97 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/UARTCommandConsole.c @@ -0,0 +1,272 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * NOTE: This file uses a third party USB CDC driver. + */ + +/* Standard includes. */ +#include "string.h" +#include "stdio.h" + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* Example includes. */ +#include "FreeRTOS_CLI.h" + +/* Demo application includes. */ +#include "serial.h" + +/* Dimensions the buffer into which input characters are placed. */ +#define cmdMAX_INPUT_SIZE 50 + +#define cmdQUEUE_LENGTH 25 + +/* DEL acts as a backspace. */ +#define cmdASCII_DEL ( 0x7F ) + +#define cmdMAX_MUTEX_WAIT ( ( ( TickType_t ) 300 ) / ( portTICK_PERIOD_MS ) ) + +#ifndef configCLI_BAUD_RATE + #define configCLI_BAUD_RATE 115200 +#endif + +/*-----------------------------------------------------------*/ + +/* + * The task that implements the command console processing. + */ +static void prvUARTCommandConsoleTask( void *pvParameters ); +void vUARTCommandConsoleStart( uint16_t usStackSize, UBaseType_t uxPriority ); + +/*-----------------------------------------------------------*/ + +/* Const messages output by the command console. */ +static const char * const pcWelcomeMessage = "FreeRTOS command server.\r\nType Help to view a list of registered commands.\r\n\r\n>"; +static const char * const pcEndOfOutputMessage = "\r\n[Press ENTER to execute the previous command again]\r\n>"; +static const char * const pcNewLine = "\r\n"; + +SemaphoreHandle_t xTxMutex = NULL; +static xComPortHandle xPort = 0; + +/* Serial drivers that use task notifications may need the CLI task's handle. */ +TaskHandle_t xCLITaskHandle = NULL; + +/*-----------------------------------------------------------*/ + +void vUARTCommandConsoleStart( uint16_t usStackSize, UBaseType_t uxPriority ) +{ + /* Create the semaphore used to access the UART Tx. */ + xTxMutex = xSemaphoreCreateMutex(); + configASSERT( xTxMutex ); + + /* Create that task that handles the console itself. */ + xTaskCreate( prvUARTCommandConsoleTask, /* The task that implements the command console. */ + "CLI", /* Text name assigned to the task. This is just to assist debugging. The kernel does not use this name itself. */ + usStackSize, /* The size of the stack allocated to the task. */ + NULL, /* The parameter is not used, so NULL is passed. */ + uxPriority, /* The priority allocated to the task. */ + &xCLITaskHandle ); /* Serial drivers that use task notifications may need the CLI task's handle. */ +} +/*-----------------------------------------------------------*/ + +static void prvUARTCommandConsoleTask( void *pvParameters ) +{ +char cRxedChar; +uint8_t ucInputIndex = 0; +char *pcOutputString; +static char cInputString[ cmdMAX_INPUT_SIZE ], cLastInputString[ cmdMAX_INPUT_SIZE ]; +BaseType_t xReturned; +xComPortHandle xPort; + + ( void ) pvParameters; + + /* Obtain the address of the output buffer. Note there is no mutual + exclusion on this buffer as it is assumed only one command console interface + will be used at any one time. */ + pcOutputString = FreeRTOS_CLIGetOutputBuffer(); + + /* Initialise the UART. */ + xPort = xSerialPortInitMinimal( configCLI_BAUD_RATE, cmdQUEUE_LENGTH ); + + /* Send the welcome message. */ + vSerialPutString( xPort, ( char * ) pcWelcomeMessage, strlen( pcWelcomeMessage ) ); + + for( ;; ) + { + /* Wait for the next character. The while loop is used in case + INCLUDE_vTaskSuspend is not set to 1 - in which case portMAX_DELAY will + be a genuine block time rather than an infinite block time. */ + while( xSerialGetChar( xPort, &cRxedChar, portMAX_DELAY ) != pdPASS ); + + /* Ensure exclusive access to the UART Tx. */ + if( xSemaphoreTake( xTxMutex, cmdMAX_MUTEX_WAIT ) == pdPASS ) + { + /* Echo the character back. */ + xSerialPutChar( xPort, cRxedChar, portMAX_DELAY ); + + /* Was it the end of the line? */ + if( ( cRxedChar == '\n' ) || ( cRxedChar == '\r' ) ) + { + /* Just to space the output from the input. */ + vSerialPutString( xPort, ( char * ) pcNewLine, strlen( pcNewLine ) ); + + /* See if the command is empty, indicating that the last command + is to be executed again. */ + if( ucInputIndex == 0 ) + { + /* Copy the last command back into the input string. */ + strcpy( cInputString, cLastInputString ); + } + + /* Pass the received command to the command interpreter. The + command interpreter is called repeatedly until it returns + pdFALSE (indicating there is no more output) as it might + generate more than one string. */ + do + { + /* Get the next output string from the command interpreter. */ + xReturned = FreeRTOS_CLIProcessCommand( cInputString, pcOutputString, configCOMMAND_INT_MAX_OUTPUT_SIZE ); + + /* Write the generated string to the UART. */ + vSerialPutString( xPort, ( char * ) pcOutputString, strlen( pcOutputString ) ); + + } while( xReturned != pdFALSE ); + + /* All the strings generated by the input command have been + sent. Clear the input string ready to receive the next command. + Remember the command that was just processed first in case it is + to be processed again. */ + strcpy( cLastInputString, cInputString ); + ucInputIndex = 0; + memset( cInputString, 0x00, cmdMAX_INPUT_SIZE ); + + vSerialPutString( xPort, ( char * ) pcEndOfOutputMessage, strlen( pcEndOfOutputMessage ) ); + } + else + { + if( cRxedChar == '\r' ) + { + /* Ignore the character. */ + } + else if( ( cRxedChar == '\b' ) || ( cRxedChar == cmdASCII_DEL ) ) + { + /* Backspace was pressed. Erase the last character in the + string - if any. */ + if( ucInputIndex > 0 ) + { + ucInputIndex--; + cInputString[ ucInputIndex ] = '\0'; + } + } + else + { + /* A character was entered. Add it to the string entered so + far. When a \n is entered the complete string will be + passed to the command interpreter. */ + if( ( cRxedChar >= ' ' ) && ( cRxedChar <= '~' ) ) + { + if( ucInputIndex < cmdMAX_INPUT_SIZE ) + { + cInputString[ ucInputIndex ] = cRxedChar; + ucInputIndex++; + } + } + } + } + + /* Must ensure to give the mutex back. */ + xSemaphoreGive( xTxMutex ); + } + } +} +/*-----------------------------------------------------------*/ + +void vOutputString( const char * const pcMessage ) +{ + if( xSemaphoreTake( xTxMutex, cmdMAX_MUTEX_WAIT ) == pdPASS ) + { + vSerialPutString( xPort, ( char * ) pcMessage, strlen( pcMessage ) ); + xSemaphoreGive( xTxMutex ); + } +} +/*-----------------------------------------------------------*/ + +void vOutputChar( const char cChar, const TickType_t xTicksToWait ) +{ + if( xSemaphoreTake( xTxMutex, xTicksToWait ) == pdPASS ) + { + xSerialPutChar( xPort, cChar, xTicksToWait ); + xSemaphoreGive( xTxMutex ); + } +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/UDPCommandConsole.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/UDPCommandConsole.c new file mode 100644 index 000000000..ffec1a02a --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/UDPCommandConsole.c @@ -0,0 +1,279 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+CLI includes. */ +#include "FreeRTOS_CLI.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Demo app includes. */ +#include "UDPCommandConsole.h" + +/* Dimensions the buffer into which input characters are placed. */ +#define cmdMAX_INPUT_SIZE 60 + +/* Dimensions the buffer into which string outputs can be placed. */ +#define cmdMAX_OUTPUT_SIZE 1024 + +/* Dimensions the buffer passed to the recvfrom() call. */ +#define cmdSOCKET_INPUT_BUFFER_SIZE 60 + +/* DEL acts as a backspace. */ +#define cmdASCII_DEL ( 0x7F ) + +/* The socket used by the CLI and debug print messages. */ +static Socket_t xSocket = FREERTOS_INVALID_SOCKET; + +/* + * The task that runs FreeRTOS+CLI. + */ +static void prvUDPCommandInterpreterTask( void *pvParameters ); + +/* + * Open and configure the UDP socket. + */ +static Socket_t prvOpenUDPServerSocket( uint16_t usPort ); + +/*-----------------------------------------------------------*/ + +/* This is required as a parameter to maintain the sendto() Berkeley sockets +API - but it is not actually used so can take any value. */ +static socklen_t xClientAddressLength = 0; + +/* Const messages output by the command console. */ +static const char * const pcEndOfOutputMessage = "\r\n[Press ENTER to execute the previous command again]\r\n>"; +static const char * const pcNewLine = "\r\n"; + +/*-----------------------------------------------------------*/ + +void vStartUDPCommandInterpreterTask( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority ) +{ + xTaskCreate( prvUDPCommandInterpreterTask, "UDP CLI", usStackSize, ( void * ) ulPort, uxPriority, NULL ); +} +/*-----------------------------------------------------------*/ + +void prvUDPCommandInterpreterTask( void *pvParameters ) +{ +int32_t lBytes, lByte; +char cRxedChar, cInputIndex = 0; +static char cOutputString[ cmdMAX_OUTPUT_SIZE ], cLocalBuffer[ cmdSOCKET_INPUT_BUFFER_SIZE ]; +static char cLastInputString[ cmdMAX_INPUT_SIZE ], cInputString[ cmdMAX_INPUT_SIZE ]; +BaseType_t xMoreDataToFollow; +struct freertos_sockaddr xClient; + + memset( cInputString, 0x00, cmdMAX_INPUT_SIZE ); + + /* Attempt to open the socket. The port number is passed in the task + parameter. The strange casting is to remove compiler warnings on 32-bit + machines. */ + xSocket = prvOpenUDPServerSocket( ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL ); + + if( xSocket != FREERTOS_INVALID_SOCKET ) + { + for( ;; ) + { + /* Wait for incoming data on the opened socket. */ + lBytes = FreeRTOS_recvfrom( xSocket, ( void * ) cLocalBuffer, sizeof( cLocalBuffer ), 0, &xClient, &xClientAddressLength ); + + if( lBytes > 0 ) + { + /* Process each received byte in turn. */ + lByte = 0; + while( lByte < lBytes ) + { + /* The next character in the input buffer. */ + cRxedChar = cLocalBuffer[ lByte ]; + lByte++; + + /* Newline characters are taken as the end of the command + string. */ + if( cRxedChar == '\n' ) + { + /* Just to space the output from the input. */ + FreeRTOS_sendto( xSocket, pcNewLine, strlen( pcNewLine ), 0, &xClient, xClientAddressLength ); + + /* See if the command is empty, indicating that the last command + is to be executed again. */ + if( cInputIndex == 0 ) + { + /* Copy the last command back into the input string. */ + strcpy( cInputString, cLastInputString ); + } + + /* Process the input string received prior to the + newline. */ + do + { + /* Pass the string to FreeRTOS+CLI. */ + cOutputString[ 0 ] = 0x00; + xMoreDataToFollow = FreeRTOS_CLIProcessCommand( cInputString, cOutputString, cmdMAX_OUTPUT_SIZE ); + + /* Send the output generated by the command's + implementation. */ + FreeRTOS_sendto( xSocket, cOutputString, strlen( ( const char * ) cOutputString ), 0, &xClient, xClientAddressLength ); + + /* Until the command does not generate any more output. */ + } while( xMoreDataToFollow != pdFALSE ); + + /* All the strings generated by the command processing + have been sent. Clear the input string ready to receive + the next command. Remember the previous command so it + can be repeated if the user just presses the ENTER key. */ + strcpy( cLastInputString, cInputString ); + cInputIndex = 0; + memset( cInputString, 0x00, cmdMAX_INPUT_SIZE ); + + /* Transmit a spacer to make the console easier to + read. */ + FreeRTOS_sendto( xSocket, ( void * ) pcEndOfOutputMessage, strlen( pcEndOfOutputMessage ), 0, &xClient, xClientAddressLength ); + } + else + { + if( cRxedChar == '\r' ) + { + /* Ignore the character. Newlines are used to + detect the end of the input string. */ + } + else if( ( cRxedChar == '\b' ) || ( cRxedChar == cmdASCII_DEL ) ) + { + /* Backspace was pressed. Erase the last character + in the string - if any. */ + if( cInputIndex > 0 ) + { + cInputIndex--; + cInputString[ ( int ) cInputIndex ] = '\0'; + } + } + else + { + /* A character was entered. Add it to the string + entered so far. When a \n is entered the complete + string will be passed to the command interpreter. */ + if( cInputIndex < cmdMAX_INPUT_SIZE ) + { + cInputString[ ( int ) cInputIndex ] = cRxedChar; + cInputIndex++; + } + } + } + } + } + } + } + else + { + /* The socket could not be opened. */ + vTaskDelete( NULL ); + } +} +/*-----------------------------------------------------------*/ + +static Socket_t prvOpenUDPServerSocket( uint16_t usPort ) +{ +struct freertos_sockaddr xServer; +Socket_t xServerSocket = FREERTOS_INVALID_SOCKET; +TickType_t xSendTimeOut = 0; + + xServerSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + if( xServerSocket != FREERTOS_INVALID_SOCKET) + { + /* Set to non-blocking sends with a timeout of zero as the socket might + also be used for debug prints which should not block. */ + FreeRTOS_setsockopt( xServerSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + + /* Zero out the server structure. */ + memset( ( void * ) &xServer, 0x00, sizeof( xServer ) ); + + /* Set family and port. */ + xServer.sin_port = FreeRTOS_htons( usPort ); + + /* Bind the address to the socket. */ + if( FreeRTOS_bind( xServerSocket, &xServer, sizeof( xServer ) ) == -1 ) + { + FreeRTOS_closesocket( xServerSocket ); + xServerSocket = FREERTOS_INVALID_SOCKET; + } + } + + return xServerSocket; +} +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/include/TCPCommandConsole.h b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/include/TCPCommandConsole.h new file mode 100644 index 000000000..290fbff00 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/include/TCPCommandConsole.h @@ -0,0 +1,75 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef TCP_COMMAND_INTERPRETER_H +#define TCP_COMMAND_INTERPRETER_H + +void vStartTCPCommandInterpreterTask( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority ); + +#endif /* TCP_COMMAND_INTERPRETER_H */ diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/include/UDPCommandConsole.h b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/include/UDPCommandConsole.h new file mode 100644 index 000000000..ccea0df59 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_CLI_Demos/include/UDPCommandConsole.h @@ -0,0 +1,75 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef UDP_COMMAND_INTERPRETER_H +#define UDP_COMMAND_INTERPRETER_H + +void vStartUDPCommandInterpreterTask( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority ); + +#endif /* UDP_COMMAND_INTERPRETER_H */ diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_FAT_Demos/CreateAndVerifyExampleFiles.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_FAT_Demos/CreateAndVerifyExampleFiles.c new file mode 100644 index 000000000..05fe75ec8 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_FAT_Demos/CreateAndVerifyExampleFiles.c @@ -0,0 +1,451 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +/* + * Create and verify a few example files using both line based and character + * based reads and writes. + */ + +/* FreeRTOS+FAT headers. */ +#include "ff_headers.h" +#include "ff_stdio.h" + +/* FTP headers. */ +#include "FreeRTOSIPConfig.h" + +/* Demo headers. */ +#include "DefaultWebPages.h" + +/* The number of bytes read/written to the example files at a time. */ +#define fsRAM_BUFFER_SIZE 200 + +/* The number of bytes written to the file that uses f_putc() and f_getc(). */ +#define fsPUTC_FILE_SIZE 100 + +/* + * Create a set of example files in the root directory of the volume using + * ff_fwrite(). + */ +static void prvCreateDemoFilesUsing_ff_fwrite( const char *pcMountPath ); + +/* + * Use ff_fread() to read back and verify the files that were created by + * prvCreateDemoFilesUsing_ff_fwrite(). + */ +static void prvVerifyDemoFileUsing_ff_fread( void ); + +/* + * Create an example file in a sub-directory using f_putc(). + */ +static void prvCreateDemoFileUsing_ff_fputc( const char *pcMountPath ); + +/* + * Use f_getc() to read back and verify the file that was created by + * prvCreateDemoFileUsing_f_putc(). + */ +static void prvVerifyDemoFileUsing_ff_fgetc( const char *pcMountPath ); + +/* + * Create the configHTTP_ROOT directory, and add a basic default web page. + */ +#if( ipconfigUSE_HTTP == 1 ) + + #ifndef configHTTP_ROOT + #error configHTTP_ROOT must be defined to a string that holds the directory to be used as the root for the HTTP server + #endif + + static void prvCreateDefaultWebPage( void ); + +#endif /* ipconfigUSE_HTTP */ + +/* Names of directories that are created. */ +static const char *pcDirectory1 = "SUB1", *pcDirectory2 = "SUB2", *pcFullPath = "/SUB1/SUB2"; + +/*-----------------------------------------------------------*/ + +void vCreateAndVerifyExampleFiles( const char *pcMountPath ) +{ + /* Create and verify a few example files using both line based and character + based reads and writes. */ + prvCreateDemoFilesUsing_ff_fwrite( pcMountPath ); + prvVerifyDemoFileUsing_ff_fread(); + prvCreateDemoFileUsing_ff_fputc( pcMountPath ); + prvVerifyDemoFileUsing_ff_fgetc( pcMountPath ); + + #if( ipconfigUSE_HTTP == 1 ) + { + prvCreateDefaultWebPage(); + } + #endif /* ipconfigUSE_HTTP */ +} +/*-----------------------------------------------------------*/ + +static void prvCreateDemoFilesUsing_ff_fwrite( const char *pcMountPath ) +{ +BaseType_t xFileNumber, xWriteNumber; +const BaseType_t xMaxFiles = 5; +int32_t lItemsWritten; +int32_t lResult; +FF_FILE *pxFile; +char *pcRAMBuffer, *pcFileName; + + /* Allocate buffers used to hold date written to/from the disk, and the + file names. */ + pcRAMBuffer = ( char * ) pvPortMalloc( fsRAM_BUFFER_SIZE ); + pcFileName = ( char * ) pvPortMalloc( ffconfigMAX_FILENAME ); + configASSERT( pcRAMBuffer ); + configASSERT( pcFileName ); + + /* Ensure in the root of the mount being used. */ + lResult = ff_chdir( pcMountPath ); + configASSERT( lResult >= 0 ); + + /* Create xMaxFiles files. Each created file will be + ( xFileNumber * fsRAM_BUFFER_SIZE ) bytes in length, and filled + with a different repeating character. */ + for( xFileNumber = 1; xFileNumber <= xMaxFiles; xFileNumber++ ) + { + /* Generate a file name. */ + snprintf( pcFileName, ffconfigMAX_FILENAME, "root%03d.txt", ( int ) xFileNumber ); + + /* Obtain the current working directory and print out the file name and + the directory into which the file is being written. */ + ff_getcwd( pcRAMBuffer, fsRAM_BUFFER_SIZE ); + FF_PRINTF( "Creating file %s in %s\n", pcFileName, pcRAMBuffer ); + + /* Open the file, creating the file if it does not already exist. */ + pxFile = ff_fopen( pcFileName, "w" ); + configASSERT( pxFile ); + + /* Fill the RAM buffer with data that will be written to the file. This + is just a repeating ascii character that indicates the file number. */ + memset( pcRAMBuffer, ( int ) ( '0' + xFileNumber ), fsRAM_BUFFER_SIZE ); + + /* Write the RAM buffer to the opened file a number of times. The + number of times the RAM buffer is written to the file depends on the + file number, so the length of each created file will be different. */ + for( xWriteNumber = 0; xWriteNumber < xFileNumber; xWriteNumber++ ) + { + lItemsWritten = ff_fwrite( pcRAMBuffer, fsRAM_BUFFER_SIZE, 1, pxFile ); + configASSERT( lItemsWritten == 1 ); + } + + /* Close the file so another file can be created. */ + ff_fclose( pxFile ); + } + + vPortFree( pcRAMBuffer ); + vPortFree( pcFileName ); +} +/*-----------------------------------------------------------*/ + +static void prvVerifyDemoFileUsing_ff_fread( void ) +{ +BaseType_t xFileNumber, xReadNumber; +const BaseType_t xMaxFiles = 5; +size_t xItemsRead, xChar; +FF_FILE *pxFile; +char *pcRAMBuffer, *pcFileName; + + /* Allocate buffers used to hold date written to/from the disk, and the + file names. */ + pcRAMBuffer = ( char * ) pvPortMalloc( fsRAM_BUFFER_SIZE ); + pcFileName = ( char * ) pvPortMalloc( ffconfigMAX_FILENAME ); + configASSERT( pcRAMBuffer ); + configASSERT( pcFileName ); + + /* Read back the files that were created by + prvCreateDemoFilesUsing_ff_fwrite(). */ + for( xFileNumber = 1; xFileNumber <= xMaxFiles; xFileNumber++ ) + { + /* Generate the file name. */ + snprintf( pcFileName, ffconfigMAX_FILENAME, "root%03d.txt", ( int ) xFileNumber ); + + /* Obtain the current working directory and print out the file name and + the directory from which the file is being read. */ + ff_getcwd( pcRAMBuffer, fsRAM_BUFFER_SIZE ); + FF_PRINTF( "Reading file %s from %s\n", pcFileName, pcRAMBuffer ); + + /* Open the file for reading. */ + pxFile = ff_fopen( pcFileName, "r" ); + configASSERT( pxFile ); + + /* Read the file into the RAM buffer, checking the file contents are as + expected. The size of the file depends on the file number. */ + for( xReadNumber = 0; xReadNumber < xFileNumber; xReadNumber++ ) + { + /* Start with the RAM buffer clear. */ + memset( pcRAMBuffer, 0x00, fsRAM_BUFFER_SIZE ); + + xItemsRead = ff_fread( pcRAMBuffer, fsRAM_BUFFER_SIZE, 1, pxFile ); + configASSERT( xItemsRead == 1 ); + + /* Check the RAM buffer is filled with the expected data. Each + file contains a different repeating ascii character that indicates + the number of the file. */ + for( xChar = 0; xChar < fsRAM_BUFFER_SIZE; xChar++ ) + { + configASSERT( pcRAMBuffer[ xChar ] == ( '0' + ( char ) xFileNumber ) ); + } + } + + /* Close the file. */ + ff_fclose( pxFile ); + } + + vPortFree( pcRAMBuffer ); + vPortFree( pcFileName ); + + /*_RB_ also test what happens when attempting to read using too large item + sizes, etc. */ +} +/*-----------------------------------------------------------*/ + +static void prvCreateDemoFileUsing_ff_fputc( const char *pcMountPath ) +{ +int32_t iReturn, iByte, iReturned; +FF_FILE *pxFile; +char *pcRAMBuffer, *pcFileName; + + /* Allocate buffers used to hold date written to/from the disk, and the + file names. */ + pcRAMBuffer = ( char * ) pvPortMalloc( fsRAM_BUFFER_SIZE ); + pcFileName = ( char * ) pvPortMalloc( ffconfigMAX_FILENAME ); + configASSERT( pcRAMBuffer ); + configASSERT( pcFileName ); + + /* Obtain and print out the working directory. */ + ff_getcwd( pcRAMBuffer, fsRAM_BUFFER_SIZE ); + FF_PRINTF( "In directory %s\n", pcRAMBuffer ); + + /* Create a sub directory. */ + iReturn = ff_mkdir( pcDirectory1 ); + configASSERT( iReturn == pdFREERTOS_ERRNO_NONE ); + + /* Move into the created sub-directory. */ + iReturn = ff_chdir( pcDirectory1 ); + configASSERT( iReturn == pdFREERTOS_ERRNO_NONE ); + + /* Obtain and print out the working directory. */ + ff_getcwd( pcRAMBuffer, fsRAM_BUFFER_SIZE ); + FF_PRINTF( "In directory %s\n", pcRAMBuffer ); + + /* Create a subdirectory in the new directory. */ + iReturn = ff_mkdir( pcDirectory2 ); + configASSERT( iReturn == pdFREERTOS_ERRNO_NONE ); + + /* Move into the directory just created - now two directories down from + the root. */ + iReturn = ff_chdir( pcDirectory2 ); + configASSERT( iReturn == pdFREERTOS_ERRNO_NONE ); + + /* Obtain and print out the working directory. */ + ff_getcwd( pcRAMBuffer, fsRAM_BUFFER_SIZE ); + FF_PRINTF( "In directory %s\n", pcRAMBuffer ); + snprintf( pcFileName, ffconfigMAX_FILENAME, "%s%s", pcMountPath, pcFullPath ); + configASSERT( strcmp( pcRAMBuffer, pcFileName ) == 0 ); + + /* Generate the file name. */ + snprintf( pcFileName, ffconfigMAX_FILENAME, "%s.txt", pcDirectory2 ); + + /* Print out the file name and the directory into which the file is being + written. */ + FF_PRINTF( "Writing file %s in %s\n", pcFileName, pcRAMBuffer ); + + pxFile = ff_fopen( pcFileName, "w" ); + configASSERT( pxFile ); + + /* Create a file 1 byte at a time. The file is filled with incrementing + ascii characters starting from '0'. */ + for( iByte = 0; iByte < fsPUTC_FILE_SIZE; iByte++ ) + { + iReturned = ff_fputc( ( ( int ) '0' + iByte ), pxFile ); + configASSERT( iReturned == ( ( int ) '0' + iByte ) ); + } + + /* Finished so close the file. */ + ff_fclose( pxFile ); + + /* Move back to the root directory. */ + iReturned = ff_chdir( "../.." ); + configASSERT( iReturn == pdFREERTOS_ERRNO_NONE ); + + /* Obtain and print out the working directory. */ + ff_getcwd( pcRAMBuffer, fsRAM_BUFFER_SIZE ); + FF_PRINTF( "Back in root directory %s\n", pcRAMBuffer ); + configASSERT( strcmp( pcRAMBuffer, pcMountPath ) == 0 ); + + vPortFree( pcRAMBuffer ); + vPortFree( pcFileName ); +} +/*-----------------------------------------------------------*/ + +static void prvVerifyDemoFileUsing_ff_fgetc( const char *pcMountPath ) +{ +int iByte, iReturned; +FF_FILE *pxFile; +char *pcRAMBuffer, *pcFileName; + + /* Allocate buffers used to hold date written to/from the disk, and the + file names. */ + pcRAMBuffer = ( char * ) pvPortMalloc( fsRAM_BUFFER_SIZE ); + pcFileName = ( char * ) pvPortMalloc( ffconfigMAX_FILENAME ); + configASSERT( pcRAMBuffer ); + configASSERT( pcFileName ); + + /* Move into the directory in which the file was created. */ + snprintf( pcFileName, ffconfigMAX_FILENAME, "%s%s", pcMountPath, pcFullPath ); + iReturned = ff_chdir( pcFileName ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* Obtain and print out the working directory. */ + ff_getcwd( pcRAMBuffer, fsRAM_BUFFER_SIZE ); + FF_PRINTF( "Back in directory %s\n", pcRAMBuffer ); + configASSERT( strcmp( pcRAMBuffer, pcFileName ) == 0 ); + + /* pcFileName is about to be overwritten - take a copy. */ + strcpy( pcRAMBuffer, pcFileName ); + + /* Generate the file name. */ + sprintf( pcFileName, "%s.txt", pcDirectory2 ); + + /* Print out the file name and the directory from which the file is being + read. */ + FF_PRINTF( "Reading file %s in %s\n", pcFileName, pcRAMBuffer ); + + /* This time the file is opened for reading. */ + pxFile = ff_fopen( pcFileName, "r" ); + + /* Read the file 1 byte at a time. */ + for( iByte = 0; iByte < fsPUTC_FILE_SIZE; iByte++ ) + { + iReturned = ff_fgetc( pxFile ); + configASSERT( iReturned == ( ( int ) '0' + iByte ) ); + } + + /* Should not be able to read another bytes. */ + iReturned = ff_fgetc( pxFile ); + configASSERT( iReturned == FF_EOF ); + + /* Finished so close the file. */ + ff_fclose( pxFile ); + + /* Move back to the root directory. */ + iReturned = ff_chdir( "../.." ); + + /* Obtain and print out the working directory. */ + ff_getcwd( pcRAMBuffer, fsRAM_BUFFER_SIZE ); + FF_PRINTF( "Back in root directory %s\n", pcRAMBuffer ); + + vPortFree( pcRAMBuffer ); + vPortFree( pcFileName ); +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_HTTP == 1 ) + + static void prvCreateDefaultWebPage( void ) + { + int iReturned; + size_t x; + FF_FILE *pxFile; + + /* Create the directory used as the root of the HTTP server. */ + iReturned = ff_mkdir( configHTTP_ROOT ); + + if( iReturned == pdFREERTOS_ERRNO_NONE ) + { + /* Move into the configHTTP_ROOT directory. */ + ff_chdir( configHTTP_ROOT ); + + /* Create each file defined by the xHTTPFilesToCopy array, which is + defined in DefaultWebPages.h. */ + for( x = 0; x < sizeof( xHTTPFilesToCopy ) / sizeof( xFileToCopy_t ); x++ ) + { + /* Create the file. */ + pxFile = ff_fopen( xHTTPFilesToCopy[ x ].pcFileName, "w+" ); + + if( pxFile != NULL ) + { + /* Write out all the data to the file. */ + ff_fwrite( xHTTPFilesToCopy[ x ].pucFileData, + xHTTPFilesToCopy[ x ].xFileSize, + 1, + pxFile ); + + ff_fclose( pxFile ); + } + } + } + } + +#endif /* ipconfigUSE_HTTP */ +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_FAT_Demos/test/ff_stdio_tests_with_cwd.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_FAT_Demos/test/ff_stdio_tests_with_cwd.c new file mode 100644 index 000000000..cc23627f6 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_FAT_Demos/test/ff_stdio_tests_with_cwd.c @@ -0,0 +1,1194 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * Non-systematic sanity checks for the API defined in ff_stdio.c. + */ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" + +/* FreeRTOS+FAT headers. */ +#include "ff_headers.h" +#include "ff_stdio.h" + +/* The number of bytes read/written to the example files at a time. */ +#define fsRAM_BUFFER_SIZE 200 + +/* The number of bytes written to the file that uses f_putc() and f_getc(). */ +#define fsPUTC_FILE_SIZE 100 + +/* The number of tasks to create if the stdio tests will be executed in +multiple tasks simultaneously. */ +#define fsTASKS_TO_CREATE 5 + +/* + * Examples and basic tests of the ff_truncate() function. + */ +static void prvTest_ff_truncate( const char *pcMountPath ); + +/* + * Examples and basic tests of the ff_findNNN() functions. + */ +static void prvTest_ff_findfirst_ff_findnext_ff_findclose( const char *pcMountPath ); + +/* + * Examples and basic tests of the ff_fopen() function. + */ +static void prvTest_ff_fopen( const char *pcMountPath ); + +/* + * Examples and basic tests of the ff_rename() function. + */ +static void prvTest_ff_rename( const char *pcMountPath ); + +/* + * Examples and basic tests of the ff_mkdir, ff_chdir() and ff_rmdir() + * functions. + */ +static void prvTest_ff_fmkdir_ff_chdir_ff_rmdir( const char *pcMountPath ); + +/* + * Non-systematic sanity check that aligned and unaligned data can be written + * within and across sectors. + */ +static void prvTest_ff_fseek_ff_rewind( const char *pcMountPath ); + +/* + * Examples and basic tests of the ff_fgets() function. + */ +#if( ffconfigFPRINTF_SUPPORT == 1 ) + + static void prvTest_ff_fgets_ff_printf( const char *pcMountPath ); + +#endif /* ffconfigFPRINTF_SUPPORT */ + +/* + * Non-systematic sanity check that aligned and unaligned data can be written + * within and across sectors. + */ +static void prvAlignmentReadWriteTests( const char *pcMountPath ); + +/* + * A task that repeatedly creates, tests, then deletes files as an ad hoc test + * of accessing the file system from more than one task simultaneously. + */ +static void prvFileSystemAccessTask( void *pvParameters ); + +/*-----------------------------------------------------------*/ + +void vStdioWithCWDTest( const char *pcMountPath ) +{ + /* Non-systematic sanity checks for the API defined in ff_stdio.c. */ + + /* Must come after the prvCreateDemoFilesUsing_fwrite() and + prvCreateDemoFileUsing_fputc() functions as it expects the files created by + those functions to exist. */ + prvTest_ff_findfirst_ff_findnext_ff_findclose( pcMountPath ); + + prvTest_ff_truncate( pcMountPath ); + prvTest_ff_fmkdir_ff_chdir_ff_rmdir( pcMountPath ); + prvTest_ff_fopen( pcMountPath ); + prvTest_ff_rename( pcMountPath ); + prvAlignmentReadWriteTests( pcMountPath ); + prvTest_ff_fseek_ff_rewind( pcMountPath ); + + #if( ffconfigFPRINTF_SUPPORT == 1 ) + { + prvTest_ff_fgets_ff_printf( pcMountPath ); + } + #endif +} +/*-----------------------------------------------------------*/ + +static void prvTest_ff_fmkdir_ff_chdir_ff_rmdir( const char *pcMountPath ) +{ +int iReturned; +char *pcRAMBuffer, *pcFileName; + + /* Allocate buffers used to hold date written to/from the disk, and the + file names. */ + pcRAMBuffer = ( char * ) pvPortMalloc( fsRAM_BUFFER_SIZE ); + pcFileName = ( char * ) pvPortMalloc( ffconfigMAX_FILENAME ); + configASSERT( pcRAMBuffer ); + configASSERT( pcFileName ); + + /* Try changing to an invalid absolute directory. This should fail. */ + iReturned = ff_chdir( "/not_a_directory" ); + configASSERT( iReturned == -1 ); + + /* Try changing to the root. This should not fail. */ + iReturned = ff_chdir( "/" ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* Try changing to an invalid relative directory. This should also fail. */ + iReturned = ff_chdir( "not_a_directory" ); + configASSERT( iReturned == -1 ); + + /* Ensure in the root of the mount being used. */ + iReturned = ff_chdir( pcMountPath ); + + /* This time the directory should have been entered. */ + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* For test purposes, move back, then try moving to the root of the mount + using a relative path. */ + iReturned = ff_chdir( "/" ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* Ensure in the root of the mount being used but using a relative path, + so move past the '/' at the beginning of pcMountPath. */ + iReturned = ff_chdir( pcMountPath + 1 ); + + /* This time the directory should have been entered. */ + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* Create nested subdirectories from the root of the mount. */ + iReturned = ff_mkdir( "sub1" ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + iReturned = ff_mkdir( "sub1/sub2" ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + iReturned = ff_mkdir( "sub1/sub2/sub3" ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + iReturned = ff_mkdir( "sub1/sub2/sub3/sub4/" ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* This is the non-recursive version, so the following is expected to + fail. */ + iReturned = ff_mkdir( "sub1/sub2/subx/suby" ); + configASSERT( iReturned == -1 ); + + /* Move into sub3. */ + iReturned = ff_chdir( "sub1/sub2/sub3" ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* Make more directories using relative paths. */ + iReturned = ff_mkdir( "../../sub2/sub3/sub4/sub5" ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* Sub6 does not exist, expect this to fail. */ + iReturned = ff_chdir( "../../sub2/sub3/sub4/sub6" ); + configASSERT( iReturned == -1 ); + + /* Sub5 does exist, expect this to pass. */ + iReturned = ff_chdir( "../../sub2/../../sub1/sub2/sub3/../sub3/sub4/sub5" ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* Create a string that contains the expected CWD. */ + snprintf( pcRAMBuffer, fsRAM_BUFFER_SIZE, "%s/%s", pcMountPath, "sub1/sub2/sub3/sub4/sub5" ); + + /* Attempt to get the CWD, but using a buffer too small. There is no room + for the NULL terminator in the line below. */ + configASSERT( ff_getcwd( pcFileName, strlen( pcRAMBuffer ) ) == NULL ); + + /* Ensure the CWD is as expected. */ + configASSERT( ff_getcwd( pcFileName, ffconfigMAX_FILENAME ) == pcFileName ); + configASSERT( strcmp( pcFileName, pcRAMBuffer ) == 0 ); + + /* Should not be possible to delete a directory in the CWD (although it is + possible to delete the CWD if it is empty!). */ + iReturned = ff_rmdir( "../../sub4" ); + configASSERT( iReturned == -1 ); + + /* It should be possible to remove sub5 as it does not contain anything. */ + iReturned = ff_chdir( "../.." ); + configASSERT( iReturned == 0 ); + iReturned = ff_rmdir( "sub4/sub5" ); + configASSERT( iReturned == 0 ); + + /* Should not now be possible to move to sub4/sub5. */ + iReturned = ff_chdir( "sub4/sub5" ); + configASSERT( iReturned == -1 ); + + /* Still possible to move to sub4 though. */ + iReturned = ff_chdir( "sub4" ); + configASSERT( iReturned == 0 ); + + vPortFree( pcRAMBuffer ); + vPortFree( pcFileName ); +} +/*-----------------------------------------------------------*/ + +#if( ffconfigFPRINTF_SUPPORT == 1 ) + + static void prvTest_ff_fgets_ff_printf( const char *pcMountPath ) + { + FF_FILE *pxFile; + int iReturned, iString; + const char *const pcTestFileName = "TestFile.txt"; + const char *const pcStringStart = "Test string"; + const int iMaxStrings = 1000; + char pcReadString[ 17 ], pcExpectedString[ 17 ], *pcReturned; + const char *pcMaximumStringLength = "Test string 999\n"; + + /* For coverage this test wants the buffers to be exactly equal to the + maximum string length. A one is added as the string must also hold the + null terminator. */ + configASSERT( ( strlen( pcMaximumStringLength ) + 1 ) == sizeof( pcReadString ) ); + + /* Move to the root of the mount. */ + iReturned = ff_chdir( pcMountPath ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* Open a test file for writing. */ + pxFile = ff_fopen( pcTestFileName, "w+" ); + configASSERT( pxFile ); + + /* Write the strings to the file. */ + for( iString = 0; iString < iMaxStrings; iString++ ) + { + /* Call ff_fprintf() to write the formatted string to the file. */ + iReturned = ff_fprintf( pxFile, "%s %d\n", pcStringStart, iString ); + + /* Generate the expected string so the return value of ff_fprintf() + can be checked. */ + sprintf( pcExpectedString, "%s %d\n", pcStringStart, iString ); + configASSERT( iReturned == ( int ) strlen( pcExpectedString ) ); + } + + /* Read back and check the strings. */ + ff_rewind( pxFile ); + configASSERT( ff_ftell( pxFile ) == 0 ); + + for( iString = 0; iString < iMaxStrings; iString++ ) + { + /* Generate the expected string. */ + sprintf( pcExpectedString, "%s %d\n", pcStringStart, iString ); + + /* Read back the next string. */ + memset( pcReadString, 0x00, sizeof( pcReadString ) ); + pcReturned = ff_fgets( pcReadString, sizeof( pcReadString ), pxFile ); + + /* The string should have been read back successfully. */ + configASSERT( pcReturned == pcReadString ); + configASSERT( strcmp( pcReadString, pcExpectedString ) == 0 ); + } + + /* Should be at the end of the file now. */ + configASSERT( ff_feof( pxFile ) != 0 ); + + /* Asking for one byte should always pass because the single byte will + just be the NULL terminator, but asking for two bytes should fail as the + EOF has been reached. */ + configASSERT( ff_fgets( pcReadString, 1, pxFile ) == pcReadString ); + configASSERT( strlen( pcReadString ) == 0 ); + configASSERT( ff_fgets( pcReadString, 2, pxFile ) == NULL ); + + /* Back to the start. */ + configASSERT( ff_feof( pxFile ) != 0 ); + iReturned = ff_fseek( pxFile, 0, FF_SEEK_SET ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + configASSERT( ff_ftell( pxFile ) == 0 ); + configASSERT( ff_feof( pxFile ) == 0 ); + + /* This time don't read all the way to a newline. Just read the string + without the number on the end. The +1 is included to accommodate the + NULL terminator. */ + pcReturned = ff_fgets( pcReadString, strlen( pcStringStart ) + 1, pxFile ); + + /* The read should have been successful. */ + configASSERT( pcReturned == pcReadString ); + configASSERT( strcmp( pcReadString, pcStringStart ) == 0 ); + + /* Move to the end of the file. */ + iReturned = ff_fseek( pxFile, 0, FF_SEEK_END ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* Write a string without a \n on the end. */ + ff_fprintf( pxFile, pcStringStart ); + + /* Now seek back and read some characters while attempting to read off + the end of the file. */ + iReturned = ff_fseek( pxFile, 0 - (int ) strlen( pcStringStart ), FF_SEEK_CUR ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + pcReturned = ff_fgets( pcReadString, sizeof( pcReadString ), pxFile ); + /* pcReturned will contain the last string "Test string", without a linefeed. */ + configASSERT( pcReturned == pcReadString ); + configASSERT( strcmp( pcReadString, pcStringStart ) == 0 ); + + pcReturned = ff_fgets( pcReadString, sizeof( pcReadString ), pxFile ); + /* pcReturned will be NULL because EOF has been reached. */ + configASSERT( pcReturned == NULL ); + + ff_fclose( pxFile ); + } + +#endif /* ffconfigFPRINTF_SUPPORT */ +/*-----------------------------------------------------------*/ + +static void prvTest_ff_fseek_ff_rewind( const char *pcMountPath ) +{ +FF_FILE *pxFile; +int iReturned; +const size_t xFileSize = 7776UL; +const size_t xNum32BitValues = xFileSize / sizeof( uint32_t ); +uint32_t x, y; + + /* Move to the root of the mount. */ + iReturned = ff_chdir( pcMountPath ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* Ensure the file does not already exist. */ + ff_remove( "seek_rewind_test_file" ); + + /* Open a test file. */ + pxFile = ff_fopen( "seek_rewind_test_file", "a+" ); + configASSERT( pxFile ); + + /* Fill the file with known data. */ + for( x = 0; x < xNum32BitValues; x++ ) + { + iReturned = ff_fwrite( &x, 1, sizeof( x ), pxFile ); + configASSERT( iReturned == sizeof( uint32_t ) ); + configASSERT( ff_ftell( pxFile ) == ( long ) ( ( x + 1U ) * sizeof( uint32_t ) ) ); + } + + /* Use rewind to get back to the beginning of the file. */ + ff_rewind( pxFile ); + configASSERT( ff_ftell( pxFile ) == 0 ); + + /* Expect 0 to be read from the start. */ + iReturned = ff_fread( &x, 1, sizeof( x ), pxFile ); + configASSERT( iReturned == sizeof( x ) ); + configASSERT( x == 0 ); + + /* Move to the end of the file. */ + iReturned = ff_fseek( pxFile, 0, FF_SEEK_END ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + configASSERT( ff_ftell( pxFile ) == ( long ) xFileSize ); + + /* Try moving past the front of the file. An error should be returned and + the position should not change. */ + iReturned = ff_fseek( pxFile, 0 - ( ( long ) xFileSize * 2 ), FF_SEEK_END ); + configASSERT( iReturned != pdFREERTOS_ERRNO_NONE ); + configASSERT( ff_ftell( pxFile ) == ( long ) xFileSize ); + + /* Reading from here should fail (EOF). */ + iReturned = ( int ) ff_fread( &x, 1, 1, pxFile ); + configASSERT( iReturned == 0 ); + + /* Now go backwards through the file, reading each uint32_t on the way. */ + for( y = ( xNum32BitValues - 1 ); y >= sizeof( uint32_t ); y -= sizeof( x ) ) + { + iReturned = ff_fseek( pxFile, ( long ) y * sizeof( uint32_t ), FF_SEEK_SET ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + configASSERT( ff_ftell( pxFile ) == ( long ) ( y * sizeof( uint32_t ) ) ); + + /* Data read from here should equal the position. */ + iReturned = ( int ) ff_fread( &x, 1, sizeof( x ), pxFile ); + configASSERT( iReturned == sizeof( x ) ); + configASSERT( x == y ); + } + + /* Move forward through the file doing the same thing. Start at the + front. */ + iReturned = ff_fseek( pxFile, 0 - ( ( long ) xFileSize ), FF_SEEK_END ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + configASSERT( ff_ftell( pxFile ) == ( long ) 0 ); + + for( y = 0; y < xNum32BitValues; y++ ) + { + iReturned = ff_fseek( pxFile, ( long ) ( y * sizeof( x ) ), FF_SEEK_CUR ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + configASSERT( ff_ftell( pxFile ) == ( long ) ( y * sizeof( uint32_t ) ) ); + + /* Data read from here should equal the position. */ + iReturned = ( int ) ff_fread( &x, 1, sizeof( x ), pxFile ); + configASSERT( iReturned == sizeof( x ) ); + configASSERT( x == y ); + + /* Move back to the start of the file. */ + iReturned = ff_fseek( pxFile, 0 - ( long ) ( ( y + 1 ) * sizeof( x ) ), FF_SEEK_CUR ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + configASSERT( ff_ftell( pxFile ) == 0 ); + } + + ff_fclose( pxFile ); +} +/*-----------------------------------------------------------*/ + +static void prvTest_ff_findfirst_ff_findnext_ff_findclose( const char* pcMountPath ) +{ +int iReturned; +size_t i; +uint8_t ucFoundFiles[ 8 ]; +FF_FindData_t *pxFindStruct = NULL; +const char *pcExpectedRootFiles[] = +{ + ".", + "..", + "SUB1", + "root001.txt", + "root002.txt", + "root003.txt", + "root004.txt", + "root005.txt" +}; + +const char *pcExpectedSUB1Files[] = +{ + ".", + "..", + "SUB2", +}; + + /* There should be one place in the ucFoundFiles[] array for every place in + the pcExpectedRootFiles[] array. */ + configASSERT( sizeof( ucFoundFiles ) == ( sizeof( pcExpectedRootFiles ) / sizeof( char * ) ) ); + + /* No files found yet. */ + memset( ucFoundFiles, 0x00, sizeof( ucFoundFiles ) ); + + /* Move to the root of the mount. */ + iReturned = ff_chdir( pcMountPath ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* FF_FindData_t is quite large, so best to malloc() it on stack challenged + architectures. */ + pxFindStruct = ( FF_FindData_t * ) pvPortMalloc( sizeof( FF_FindData_t ) ); + configASSERT( pxFindStruct ); + + if( pxFindStruct != NULL ) + { + /* Must be initialised to 0. */ + memset( pxFindStruct, 0x00, sizeof( FF_FindData_t ) ); + + /* The first parameter to ff_findfist() is the directory being searched, + wildcards are not (currently) supported, so as this is searching the + current working directory the string is empty. */ + if( ff_findfirst( "", pxFindStruct ) == pdFREERTOS_ERRNO_NONE ) + { + do + { + /* Which file was found? */ + for( i = 0; i < sizeof( ucFoundFiles ); i++ ) + { + if( strcmp( pcExpectedRootFiles[ i ], pxFindStruct->pcFileName ) == 0 ) + { + /* The file at this index was found. */ + ucFoundFiles[ i ] = pdTRUE; + break; + } + } + + } while( ff_findnext( pxFindStruct ) == pdFREERTOS_ERRNO_NONE ); + } + + /* Were all the files found? */ + for( i = 0; i < sizeof( ucFoundFiles ); i++ ) + { + configASSERT( ucFoundFiles[ i ] == pdTRUE ); + } + + + /* Next check a file can be read from the SUB1 directory. First reset + the FF_FindData_t structure. */ + memset( pxFindStruct, 0x00, sizeof( FF_FindData_t ) ); + memset( ucFoundFiles, 0x00, sizeof( ucFoundFiles ) ); + + if( ff_findfirst( "SUB1", pxFindStruct ) == pdFREERTOS_ERRNO_NONE ) + { + do + { + /* Which file was found? */ + for( i = 0; i < ( sizeof( pcExpectedSUB1Files ) / sizeof( char * ) ); i++ ) + { + if( strcmp( pcExpectedSUB1Files[ i ], pxFindStruct->pcFileName ) == 0 ) + { + /* The file at this index was found. */ + ucFoundFiles[ i ] = pdTRUE; + break; + } + } + + } while( ff_findnext( pxFindStruct ) == pdFREERTOS_ERRNO_NONE ); + } + + /* Were all the files found? */ + for( i = 0; i < ( sizeof( pcExpectedSUB1Files ) / sizeof( char * ) ); i++ ) + { + configASSERT( ucFoundFiles[ i ] == pdTRUE ); + } + + /* Must free the find struct again. */ + vPortFree( pxFindStruct ); + } +} +/*-----------------------------------------------------------*/ + +static void prvTest_ff_truncate( const char *pcMountPath ) +{ +int iReturned, x; +FF_FILE *pxFile; +/*_RB_ Cannot have / on end due to ff_findfirst() being using if ff_stat(). The +original file name has to be used at one point as both the findfirst() and fstat() +functions both use the thread local file name, and having the / on the end prevents +strcmp being used const char * const pcTestFileName = "truncate.bin/"; */ +const char * const pcTestFileName = "truncate.bin"; +FF_Stat_t xStat; +int cChar; + + /* Move to the root of the mount. */ + iReturned = ff_chdir( pcMountPath ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* Ensure the file does not already exist. */ + ff_remove( pcTestFileName ); + + /* This time the file definitely should not exist. */ + configASSERT( ff_remove( pcTestFileName ) == -1 ); + + /* Try closing the file before it is opened. */ + pxFile = NULL; + configASSERT( ff_fclose( pxFile ) == -1 ); + + /* Create a 1000 byte file. */ + pxFile = ff_truncate( pcTestFileName, 1000L ); + + /* Check the file has the expected size. */ + ff_fclose( pxFile ); + ff_stat( pcTestFileName, &xStat ); + configASSERT( xStat.st_size == 1000L ); + + /* The file should have been created full of zeros. */ + pxFile = ff_fopen( pcTestFileName, "r" ); + configASSERT( pxFile != NULL ); + + /* Calling ff_filelength() should pass as the file is not read only. */ + configASSERT( ff_filelength( pxFile ) == 1000 ); + + /* Should not be able to write now. */ + iReturned = ff_fputc( 0xff, pxFile ); + configASSERT( iReturned != 0xff ); + + for( x = 0; x < 1000; x++ ) + { + cChar = ff_fgetc( pxFile ); + configASSERT( cChar == 0 ); + } + + /* Should now be at the end of the file. */ + configASSERT( ff_fgetc( pxFile ) == FF_EOF ); + configASSERT( ff_feof( pxFile ) != 0 ); + + /* ff_seteof() should fail as the file is read only. As should + ff_fprintf(). */ + configASSERT( ff_seteof( pxFile ) == -1 ); + #if( ffconfigFPRINTF_SUPPORT != 0 ) + { + configASSERT( ff_fprintf( pxFile, "this should fail" ) == -1 ); + } + #endif + + /* Fill the file with 0xff. */ + ff_fclose( pxFile ); + pxFile = ff_fopen( pcTestFileName, "r+" ); + configASSERT( pxFile != NULL ); + + for( x = 0; x < 1000; x++ ) + { + configASSERT( ff_fputc( 0xff, pxFile ) == 0xff ); + } + + /* Extend the file to 2000 bytes using ff_truncate(). */ + ff_fclose( pxFile ); + pxFile = ff_truncate( pcTestFileName, 2000L ); + configASSERT( pxFile ); + + /* Ensure the file is indeed 2000 bytes long. */ + ff_fclose( pxFile ); + ff_stat( pcTestFileName, &xStat ); + configASSERT( xStat.st_size == 2000L ); + + /* Now the first 1000 bytes should be 0xff, and the second 1000 bytes should + be 0x00. */ + pxFile = ff_fopen( pcTestFileName, "r+" ); + configASSERT( pxFile ); + configASSERT( ff_ftell( pxFile ) == 0 ); + + for( x = 0; x < 1000; x++ ) + { + cChar = ff_fgetc( pxFile ); + configASSERT( cChar == 0xff ); + } + + for( x = 0; x < 1000; x++ ) + { + cChar = ff_fgetc( pxFile ); + configASSERT( cChar == 0x00 ); + } + + /* Use ff_fseek() then ff_seteof() to make the file 1750 bytes long. */ + configASSERT( ff_fseek( pxFile, 1750L, FF_SEEK_SET ) == pdFREERTOS_ERRNO_NONE ); + configASSERT( ff_ftell( pxFile ) == 1750 ); + configASSERT( ff_seteof( pxFile ) == pdFREERTOS_ERRNO_NONE ); + + /* Attempting another read should result in EOF. */ + configASSERT( ff_feof( pxFile ) != 0 ); + configASSERT( ff_fgetc( pxFile ) == FF_EOF ); + + /* This time use truncate to make the file shorter by another 250 bytes. */ + ff_fclose( pxFile ); + ff_stat( pcTestFileName, &xStat ); + configASSERT( xStat.st_size == 1750L ); + pxFile = ff_truncate( pcTestFileName, 1500L ); + + /* Ensure the file is indeed 1500 bytes long. */ + ff_fclose( pxFile ); + ff_stat( pcTestFileName, &xStat ); + configASSERT( xStat.st_size == 1500L ); + + /* Now the first 1000 bytes should be 0xff, and the second 500 bytes should + be 0x00. */ + pxFile = ff_fopen( pcTestFileName, "r" ); + configASSERT( pxFile ); + configASSERT( ff_ftell( pxFile ) == 0 ); + + for( x = 0; x < 1000; x++ ) + { + cChar = ff_fgetc( pxFile ); + configASSERT( cChar == 0xff ); + } + + for( x = 0; x < 500; x++ ) + { + cChar = ff_fgetc( pxFile ); + configASSERT( cChar == 0x00 ); + } + + /* Attempting another read should result in EOF. */ + configASSERT( ff_feof( pxFile ) != 0 ); + configASSERT( ff_fgetc( pxFile ) == FF_EOF ); + + /* Now truncate the file to 0. */ + ff_fclose( pxFile ); + pxFile = ff_truncate( pcTestFileName, 0L ); + configASSERT( pxFile ); + + /* Don't expect to be able to delete an open file. */ + configASSERT( ff_remove( pcTestFileName ) == -1 ); + + /* Ensure the file is indeed 0 bytes long. */ + ff_fclose( pxFile ); + ff_stat( pcTestFileName, &xStat ); + configASSERT( xStat.st_size == 0L ); + + /* Do expect to be able to delete the file after it is closed. */ + configASSERT( ff_remove( pcTestFileName ) == 0 ); +} +/*-----------------------------------------------------------*/ + +static void prvAlignmentReadWriteTests( const char *pcMountPath ) +{ +const char cOverflowCheckByte = 0xc5; +const size_t xSizeIncrement = 37U; +const size_t xSectorSize = 512U; +const size_t xNumSectors = 3U; +const size_t xOverwriteCheckBytes = 1U; +const size_t xBufferSize = ( xSectorSize * xNumSectors ) + xSizeIncrement; +size_t x, xSkippedBytes, x32BitValues; +char *pcBuffer; +uint32_t *pulVerifyBuffer; +uint32_t *pulVerifyValues; +FF_FILE *pxFile; +FF_Stat_t xStat; +const char* pcTestFileName = "test.bin"; +int iReturned, iExpectedReturn; + + /* Start in the root of the mounted disk. */ + ff_chdir( pcMountPath ); + + /* Create an array that will hold 3 whole sectors plus a few additional + bytes, plus a byte at the end which is used to check it does not get + overwritten. */ + pcBuffer = ( char * ) pvPortMalloc( xBufferSize + xOverwriteCheckBytes ); + configASSERT( pcBuffer ); + pulVerifyBuffer = ( uint32_t * ) pvPortMalloc( xBufferSize ); + + /* Write a byte to the end of the buffer which is used to ensure nothing has + ever written off the end of the buffer. */ + pcBuffer[ xBufferSize ] = cOverflowCheckByte; + + /* In case this test has been executed on the disk already - ensure the file + does not exist. */ + ff_remove( pcTestFileName ); + + /* Create a file that will hold the entire buffer. */ + pxFile = ff_truncate( pcTestFileName, xBufferSize ); + + /* Check the file has the expected size. */ + ff_fclose( pxFile ); + ff_stat( pcTestFileName, &xStat ); + configASSERT( xStat.st_size == xBufferSize ); + + /* Check the file was filled with zeros by reading it back into a buffer + that was previously set to ff. */ + pxFile = ff_fopen( pcTestFileName, "r" ); + configASSERT( pxFile ); + + memset( pcBuffer, 0xff, xBufferSize ); + + /* The +1 is to ensure the xSizeIncrement bytes are also read. */ + iReturned = ff_fread( pcBuffer, xSectorSize, xNumSectors + 1U, pxFile ); + + /* Expected to have read xNumSectors worth of xSectorSize, but xBufferSize + bytes. */ + configASSERT( iReturned == ( int ) xNumSectors ); + + /* Check the buffer is now full of zeros. */ + for( x = 0; x < xBufferSize; x++ ) + { + configASSERT( pcBuffer[ x ] == 0x00 ); + } + + /* Check the byte at the end of the buffer was not overwritten. */ + configASSERT( pcBuffer[ xBufferSize ] == cOverflowCheckByte ); + + /* Re-open in append mode, the move the write position to the start of the + file. */ + ff_fclose( pxFile ); + pxFile = ff_fopen( pcTestFileName, "r+" ); + configASSERT( pxFile ); + iReturned = ( int ) ff_ftell( pxFile ); + configASSERT( iReturned == 0 ); /*_RB_ Unexpected, but how the GCC one works. */ + + /* Fill the file with incrementing 32-bit number starting from various + different offset. */ + for( xSkippedBytes = 0; xSkippedBytes < xSizeIncrement; xSkippedBytes++ ) + { + /* The buffer is going to be written to from xSkippedBytes bytes in. + When that is done, how many 32-bit integers will it hold. */ + x32BitValues = ( xBufferSize - xSkippedBytes ) / sizeof( uint32_t ); + + /* This time start xSkippedBytes bytes into the file. */ + ff_fseek( pxFile, xSkippedBytes, FF_SEEK_SET ); + iReturned = ( int ) ff_ftell( pxFile ); + configASSERT( iReturned == ( int ) xSkippedBytes ); + iExpectedReturn = xSkippedBytes; + + memset( pulVerifyBuffer, 0x00, xBufferSize ); + pulVerifyValues = ( uint32_t * ) pulVerifyBuffer; + + for( x = 0; x < x32BitValues; x++ ) + { + iReturned = ff_fwrite( &x, sizeof( x ), 1, pxFile ); + configASSERT( iReturned == 1 ); + + /* Also write the value into the verify buffer for easy checking + when the file is read back. pulVerifyBuffer should remain on a + 4 byte boundary as it starts from index 0. */ + pulVerifyValues[ x ] = x; + + iExpectedReturn += sizeof( x ); + iReturned = ( int ) ff_ftell( pxFile ); + configASSERT( iExpectedReturn == iReturned ); + } + + /* Calculate the expected file position. */ + iExpectedReturn = ( x32BitValues * sizeof( uint32_t ) ) + xSkippedBytes; + + /* Check the expected file position. */ + iReturned = ff_ftell( pxFile ); + configASSERT( iReturned == iExpectedReturn ); + + /* Read the entire file back into a buffer to check its contents. */ + ff_fseek( pxFile, 0, FF_SEEK_SET ); + memset( pcBuffer, 0x00, xBufferSize ); + iReturned = ff_fread( pcBuffer, iExpectedReturn, 1, pxFile ); + + /* The whole file was read back in one. */ + configASSERT( iReturned == 1 ); + + /* Verify the data. The first xSkippedBytes bytes of the buffer should + still be zero. */ + for( x = 0; x < xSkippedBytes; x++ ) + { + configASSERT( pcBuffer[ x ] == 0 ); + } + + /* As just verified, the first xSkippedBytes bytes were skipped so the + first xSkippedBytes bytes in pcBuffer are zero, pulVerifyBuffer was + written to from its start, and the number of bytes written was the total + number of uint_32 variables that would fit in the buffer. */ + configASSERT( memcmp( ( void * ) ( pcBuffer + xSkippedBytes ), ( void * ) pulVerifyBuffer, ( x32BitValues * sizeof( uint32_t ) ) ) == 0 ); + + + /* Read the file back one byte at a time to check its contents. */ + memset( pcBuffer, 0xff, xBufferSize ); + ff_fseek( pxFile, 0, FF_SEEK_SET ); + for( x = 0; x < ( size_t ) iExpectedReturn; x++ ) + { + iReturned = ff_fread( &( pcBuffer[ x ] ), sizeof( char ), 1, pxFile ); + configASSERT( iReturned == sizeof( char ) ); + iReturned = ff_ftell( pxFile ); + configASSERT( iReturned == ( long ) ( x + 1U ) ); + } + + /* Verify the data using the same offsets as the previous time. */ + configASSERT( memcmp( ( void * ) ( pcBuffer + xSkippedBytes ), ( void * ) pulVerifyBuffer, ( x32BitValues * sizeof( uint32_t ) ) ) == 0 ); + + /* Read the file back three bytes at a time to check its contents. */ + memset( pcBuffer, 0xff, xBufferSize ); + ff_fseek( pxFile, 0, FF_SEEK_SET ); + for( x = 0; x < ( size_t ) iExpectedReturn; x += 3 ) + { + iReturned = ff_fread( &( pcBuffer[ x ] ), 1, 3, pxFile ); + + /* 3 does not go into 4. Don't assert check the last iteration as + it won't be an exact multiple. */ + if( x < ( iExpectedReturn - sizeof( uint32_t ) ) ) + { + configASSERT( iReturned == 3 ); + iReturned = ff_ftell( pxFile ); + configASSERT( iReturned == ( long ) ( x + 3 ) ); + } + } + + /* Verify the data. */ + configASSERT( memcmp( ( void * ) ( pcBuffer + xSkippedBytes ), ( void * ) pulVerifyBuffer, ( x32BitValues * sizeof( uint32_t ) ) ) == 0 ); + } + + ff_fclose( pxFile ); + + /* Check the byte at the end of the buffer was not overwritten. */ + configASSERT( pcBuffer[ xBufferSize ] == cOverflowCheckByte ); + + vPortFree( pcBuffer ); + vPortFree( pulVerifyBuffer ); +} +/*-----------------------------------------------------------*/ + +static void prvTest_ff_rename( const char *pcMountPath ) +{ +FF_FILE *pxFile; +int iReturned; +const char *pcStringToWrite = "This string is written to the file\n"; +const char *pcSecondStringToWrite = "This is another string written to a file\n"; +char cReadBuffer[ 45 ]; + + /* cReadBuffer must be at least big enough to hold pcStringToWrite plus a + null terminator. */ + configASSERT( sizeof( cReadBuffer ) >= ( strlen( pcSecondStringToWrite ) + 1 ) ); + + /* Move to the root of the mount. */ + iReturned = ff_chdir( pcMountPath ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* Attempt to move a file that does not exist. */ + iReturned = ff_rename( "file1.bin", "file2.bin", pdFALSE ); + configASSERT( iReturned == -1 ); + + /* Create subdirectories into/from which files will be moved. */ + iReturned = ff_mkdir( "source_dir" ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + iReturned = ff_mkdir( "destination_dir" ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* Create a file in source_dir then write some data to it. */ + pxFile = ff_fopen( "source_dir/source.txt", "w" ); + configASSERT( pxFile != NULL ); + ff_fwrite( pcStringToWrite, strlen( pcStringToWrite ), 1, pxFile ); + + /* Calling ff_filelength() should fail as the file is not read only. */ + /* configASSERT( ff_filelength( pxFile ) == 0 ); _RB_ The behavior of this function has changed, the documentation and or the test will be updated */ + + /* Ensure the file exists by closing it, reopening it, and reading the + string back. */ + iReturned = ff_fclose( pxFile ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + ff_chdir( "source_dir" ); + pxFile = ff_fopen( "source.txt", "r" ); + configASSERT( pxFile != NULL ); + memset( cReadBuffer, 0x00, sizeof( cReadBuffer ) ); + ff_fgets( cReadBuffer, sizeof( cReadBuffer ), pxFile ); + configASSERT( strcmp( cReadBuffer, pcStringToWrite ) == 0 ); + + /* Calling ff_filelength() should not fail as the file is open for + reading. */ + configASSERT( ff_filelength( pxFile ) == strlen( pcStringToWrite ) ); + + /* Should not be able to move the file because it is open. */ + iReturned = ff_rename( "source.txt", "../destination_dir/destination.txt", pdFALSE ); + configASSERT( iReturned == -1 ); + + /* Close the file so it can be moved. */ + ff_fclose( pxFile ); + + iReturned = ff_rename( "source.txt", "../destination_dir/destination.txt", pdFALSE ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + + /* Attempt to open the file - it should no longer exist. */ + pxFile = ff_fopen( "source.txt", "r" ); + configASSERT( pxFile == NULL ); + + /* Create a new file to try and copy it over an existing file. */ + pxFile = ff_fopen( "source.txt2", "w" ); + configASSERT( pxFile != NULL ); + + /* Write different data to the file. */ + iReturned = ff_fwrite( pcSecondStringToWrite, 1, strlen( pcSecondStringToWrite ), pxFile ); + configASSERT( iReturned == ( int ) strlen( pcSecondStringToWrite ) ); + + /* Now close the file and try moving it to the file that already exists. + That should fail if the last parameter is pdFALSE. */ + ff_fclose( pxFile ); + iReturned = ff_rename( "source.txt2", "../destination_dir/destination.txt", pdFALSE ); + configASSERT( iReturned == -1 ); + + /* This time the last parameter is pdTRUE, so the file should be moved even + through the destination already existed. */ + iReturned = ff_rename( "source.txt2", "../destination_dir/destination.txt", pdTRUE ); + configASSERT( iReturned == 0 ); + + /* Now open the destination file and ensure it was copied as expected. */ + iReturned = ff_chdir( "../destination_dir" ); + configASSERT( iReturned == pdFREERTOS_ERRNO_NONE ); + pxFile = ff_fopen( "destination.txt", "r" ); + configASSERT( pxFile != NULL ); + configASSERT( ff_filelength( pxFile ) == strlen( pcSecondStringToWrite ) ); + memset( cReadBuffer, 0x00, sizeof( cReadBuffer ) ); + /* +1 to get the \n on the end of the string too. */ + ff_fgets( cReadBuffer, strlen( pcSecondStringToWrite ) + 1, pxFile ); + configASSERT( strcmp( cReadBuffer, pcSecondStringToWrite ) == 0 ); + + ff_fclose( pxFile ); +} +/*-----------------------------------------------------------*/ + +static void prvTest_ff_fopen( const char *pcMountPath ) +{ +FF_FILE *pxFile; +FF_Stat_t xStat; +size_t xReturned, xByte; +const size_t xBytesToWrite = 10U; +char *pcRAMBuffer, *pcFileName; + + /* Allocate buffers used to hold date written to/from the disk, and the + file names. */ + pcRAMBuffer = ( char * ) pvPortMalloc( fsRAM_BUFFER_SIZE ); + pcFileName = ( char * ) pvPortMalloc( ffconfigMAX_FILENAME ); + configASSERT( pcRAMBuffer ); + configASSERT( pcFileName ); + + /* Generate file name. */ + snprintf( pcFileName, ffconfigMAX_FILENAME, "%s/Dummy.txt", pcMountPath ); + + /* Attempt to open a file that does not exist in read only mode. */ + pxFile = ff_fopen( pcFileName, "r" ); + + /* Do not expect the file to have been opened as it does not exist. */ + configASSERT( pxFile == NULL ); + + /* Attempt to open the same file, this time using a "+" in addition to the + "r". */ + pxFile = ff_fopen( pcFileName, "r+" ); + + /* The file still does not exist. */ + configASSERT( pxFile == NULL ); + + /* This time attempt to open the file in read/write mode. */ + pxFile = ff_fopen( pcFileName, "w" ); + + /* The file should have been created. */ + configASSERT( pxFile != NULL ); + + /* Write some ascii '0's to the file. */ + memset( pcRAMBuffer, ( int ) '0', fsRAM_BUFFER_SIZE ); + xReturned = ff_fwrite( pcRAMBuffer, xBytesToWrite, 1, pxFile ); + + /* One item was written. */ + configASSERT( xReturned == 1 ); + + /* The write position should be xBytesToWrite into the file. */ + configASSERT( ff_ftell( pxFile ) == ( long ) xBytesToWrite ); + + /* The file length as reported by ff_stat() should be zero though as the + file has not yet been committed. */ + ff_stat( pcFileName, &xStat ); + configASSERT( xStat.st_size == 0 ); + + /* Close the file so it can be re-opened in append mode. */ + ff_fclose( pxFile ); + + /* Now the file has been closed its size should be reported. */ + ff_stat( pcFileName, &xStat ); + configASSERT( xStat.st_size == xBytesToWrite ); + + pxFile = ff_fopen( pcFileName, "a" ); + configASSERT( pxFile ); + + /* Write some ascii '1's to the file. */ + memset( pcRAMBuffer, ( int ) '1', fsRAM_BUFFER_SIZE ); + xReturned = ff_fwrite( pcRAMBuffer, 1, xBytesToWrite, pxFile ); + configASSERT( xReturned == xBytesToWrite ); + + /* The size reported by stat should not yet have changed. */ + ff_stat( pcFileName, &xStat ); + configASSERT( xStat.st_size == xBytesToWrite ); + + /* The file should contain xBytesToWrite lots of '0' and xBytesToWrite lots + of '1'. The file was opened in append mode so the '1's should appear after + the '0's. Open the file in read mode to check the bytes appear in the file + as expected. */ + ff_fclose( pxFile ); + + /* Now the size reported by ff_stat() should have changed. */ + ff_stat( pcFileName, &xStat ); + configASSERT( xStat.st_size == ( xBytesToWrite * 2UL ) ); + + pxFile = ff_fopen( pcFileName, "r" ); + configASSERT( pxFile != NULL ); + + /* Start with the RAM buffer clear. */ + memset( pcRAMBuffer, 0x00, fsRAM_BUFFER_SIZE ); + + /* Read the data into the RAM buffer. */ + ff_fread( pcRAMBuffer, ( 2 * xBytesToWrite ), 1, pxFile ); + + /* Check each byte is as expected. */ + for( xByte = 0; xByte < ( 2 * xBytesToWrite ); xByte++ ) + { + if( xByte < xBytesToWrite ) + { + configASSERT( pcRAMBuffer[ xByte ] == '0' ); + } + else + { + configASSERT( pcRAMBuffer[ xByte ] == '1' ); + } + } + + /* It should not be possible to write to the file as it was opened read + only. */ + xReturned = ff_fwrite( pcRAMBuffer, 1, 1, pxFile ); + configASSERT( xReturned == 0 ); + + /* File size should not have changed. */ + ff_fclose( pxFile ); + ff_stat( pcFileName, &xStat ); + configASSERT( xStat.st_size == ( xBytesToWrite * 2UL ) ); + + /* The file now contains data. Re-open it using "w" mode again. It should + be truncated to zero. */ + pxFile = ff_fopen( pcFileName, "w" ); + ff_fclose( pxFile ); + ff_stat( pcFileName, &xStat ); + configASSERT( xStat.st_size == 0 ); + + vPortFree( pcRAMBuffer ); + vPortFree( pcFileName ); +} +/*-----------------------------------------------------------*/ + +void vMultiTaskStdioWithCWDTest( const char *const pcMountPath, uint16_t usStackSizeWords ) +{ +size_t x; +static char cDirName[ fsTASKS_TO_CREATE ][ 20 ]; /* Static as it must still be available in the task. */ +char cTaskName[ 5 ]; + + /* Create a set of tasks that also create, check and delete files. These + are left running as an ad hoc test of multiple tasks accessing the file + system simultaneously. */ + for( x = 0; x < fsTASKS_TO_CREATE; x++ ) + { + snprintf( &( cDirName[ x ][ 0 ] ), sizeof( cDirName ), "%s/%d", pcMountPath, x ); + snprintf( cTaskName, sizeof( cTaskName ), "FS%d", x ); + xTaskCreate( prvFileSystemAccessTask, + cTaskName, + usStackSizeWords, /* Not used with the Windows port. */ + ( void * ) &( cDirName[ x ][ 0 ] ), + tskIDLE_PRIORITY, + NULL ); + } +} +/*-----------------------------------------------------------*/ + +static void prvFileSystemAccessTask( void *pvParameters ) +{ +extern void vCreateAndVerifyExampleFiles( const char *pcMountPath ); +const char * const pcBasePath = ( char * ) pvParameters; + + for( ;; ) + { + /* Create the directory used as a base by this instance of this task. */ + ff_mkdir( pcBasePath ); + + /* Create a few example files on the disk. */ + vCreateAndVerifyExampleFiles( pcBasePath ); + + /* A few sanity checks only - can only be called after + vCreateAndVerifyExampleFiles(). */ + vStdioWithCWDTest( pcBasePath ); + + /* Remove the base directory again, ready for another loop. */ + ff_deltree( pcBasePath ); + } +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_FAT_SL_Demos/CreateExampleFiles/File-system-demo.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_FAT_SL_Demos/CreateExampleFiles/File-system-demo.c new file mode 100644 index 000000000..0580c0c53 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_FAT_SL_Demos/CreateExampleFiles/File-system-demo.c @@ -0,0 +1,321 @@ +/* + * FreeRTOS Kernel V10.0.1 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/******************************************************************************* + * See the URL in the comments within main.c for the location of the online + * documentation. + ******************************************************************************/ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" + +/* File system includes. */ +#include "fat_sl.h" +#include "api_mdriver_ram.h" + +/* 8.3 format, plus null terminator. */ +#define fsMAX_FILE_NAME_LEN 13 + +/* The number of bytes read/written to the example files at a time. */ +#define fsRAM_BUFFER_SIZE 200 + +/* The number of bytes written to the file that uses f_putc() and f_getc(). */ +#define fsPUTC_FILE_SIZE 100 + +/*-----------------------------------------------------------*/ + +/* + * Creates and verifies different files on the volume, demonstrating the use of + * various different API functions. + */ +void vCreateAndVerifySampleFiles( void ); + +/* + * Create a set of example files in the root directory of the volume using + * f_write(). + */ +static void prvCreateDemoFilesUsing_f_write( void ); + +/* + * Use f_read() to read back and verify the files that were created by + * prvCreateDemoFilesUsing_f_write(). + */ +static void prvVerifyDemoFileUsing_f_read( void ); + +/* + * Create an example file in a sub-directory using f_putc(). + */ +static void prvCreateDemoFileUsing_f_putc( void ); + +/* + * Use f_getc() to read back and verify the file that was created by + * prvCreateDemoFileUsing_f_putc(). + */ +static void prvVerifyDemoFileUsing_f_getc( void ); + +/*-----------------------------------------------------------*/ + +/* A buffer used to both create content to write to disk, and read content back +from a disk. Note there is no mutual exclusion on this buffer. */ +static char cRAMBuffer[ fsRAM_BUFFER_SIZE ]; + +/* Names of directories that are created. */ +static const char *pcRoot = "/", *pcDirectory1 = "SUB1", *pcDirectory2 = "SUB2", *pcFullPath = "/SUB1/SUB2"; + +/*-----------------------------------------------------------*/ + +void vCreateAndVerifySampleFiles( void ) +{ +unsigned char ucStatus; + + /* First create the volume. */ + ucStatus = f_initvolume( ram_initfunc ); + + /* It is expected that the volume is not formatted. */ + if( ucStatus == F_ERR_NOTFORMATTED ) + { + /* Format the created volume. */ + ucStatus = f_format( F_FAT12_MEDIA ); + } + + if( ucStatus == F_NO_ERROR ) + { + /* Create a set of files using f_write(). */ + prvCreateDemoFilesUsing_f_write(); + + /* Read back and verify the files that were created using f_write(). */ + prvVerifyDemoFileUsing_f_read(); + + /* Create sub directories two deep then create a file using putc. */ + prvCreateDemoFileUsing_f_putc(); + + /* Read back and verify the file created by + prvCreateDemoFileUsing_f_putc(). */ + prvVerifyDemoFileUsing_f_getc(); + } +} +/*-----------------------------------------------------------*/ + +static void prvCreateDemoFilesUsing_f_write( void ) +{ +BaseType_t xFileNumber, xWriteNumber; +char cFileName[ fsMAX_FILE_NAME_LEN ]; +const BaseType_t xMaxFiles = 5; +long lItemsWritten; +F_FILE *pxFile; + + /* Create xMaxFiles files. Each created file will be + ( xFileNumber * fsRAM_BUFFER_SIZE ) bytes in length, and filled + with a different repeating character. */ + for( xFileNumber = 1; xFileNumber <= xMaxFiles; xFileNumber++ ) + { + /* Generate a file name. */ + sprintf( cFileName, "root%03d.txt", ( int ) xFileNumber ); + + /* Obtain the current working directory and print out the file name and + the directory into which the file is being written. */ + f_getcwd( cRAMBuffer, fsRAM_BUFFER_SIZE ); + + /* Open the file, creating the file if it does not already exist. */ + pxFile = f_open( cFileName, "w" ); + configASSERT( pxFile ); + + /* Fill the RAM buffer with data that will be written to the file. This + is just a repeating ascii character that indicates the file number. */ + memset( cRAMBuffer, ( int ) ( '0' + xFileNumber ), fsRAM_BUFFER_SIZE ); + + /* Write the RAM buffer to the opened file a number of times. The + number of times the RAM buffer is written to the file depends on the + file number, so the length of each created file will be different. */ + for( xWriteNumber = 0; xWriteNumber < xFileNumber; xWriteNumber++ ) + { + lItemsWritten = f_write( cRAMBuffer, fsRAM_BUFFER_SIZE, 1, pxFile ); + configASSERT( lItemsWritten == 1 ); + } + + /* Close the file so another file can be created. */ + f_close( pxFile ); + } +} +/*-----------------------------------------------------------*/ + +static void prvVerifyDemoFileUsing_f_read( void ) +{ +BaseType_t xFileNumber, xReadNumber; +char cFileName[ fsMAX_FILE_NAME_LEN ]; +const BaseType_t xMaxFiles = 5; +long lItemsRead, lChar; +F_FILE *pxFile; + + /* Read back the files that were created by + prvCreateDemoFilesUsing_f_write(). */ + for( xFileNumber = 1; xFileNumber <= xMaxFiles; xFileNumber++ ) + { + /* Generate the file name. */ + sprintf( cFileName, "root%03d.txt", ( int ) xFileNumber ); + + /* Obtain the current working directory and print out the file name and + the directory from which the file is being read. */ + f_getcwd( cRAMBuffer, fsRAM_BUFFER_SIZE ); + + /* Open the file for reading. */ + pxFile = f_open( cFileName, "r" ); + configASSERT( pxFile ); + + /* Read the file into the RAM buffer, checking the file contents are as + expected. The size of the file depends on the file number. */ + for( xReadNumber = 0; xReadNumber < xFileNumber; xReadNumber++ ) + { + /* Start with the RAM buffer clear. */ + memset( cRAMBuffer, 0x00, fsRAM_BUFFER_SIZE ); + + lItemsRead = f_read( cRAMBuffer, fsRAM_BUFFER_SIZE, 1, pxFile ); + configASSERT( lItemsRead == 1 ); + + /* Check the RAM buffer is filled with the expected data. Each + file contains a different repeating ascii character that indicates + the number of the file. */ + for( lChar = 0; lChar < fsRAM_BUFFER_SIZE; lChar++ ) + { + configASSERT( cRAMBuffer[ lChar ] == ( '0' + ( char ) xFileNumber ) ); + } + } + + /* Close the file. */ + f_close( pxFile ); + } +} +/*-----------------------------------------------------------*/ + +static void prvCreateDemoFileUsing_f_putc( void ) +{ +unsigned char ucReturn; +int iByte, iReturned; +F_FILE *pxFile; +char cFileName[ fsMAX_FILE_NAME_LEN ]; + + /* Obtain and print out the working directory. */ + f_getcwd( cRAMBuffer, fsRAM_BUFFER_SIZE ); + + /* Create a sub directory. */ + ucReturn = f_mkdir( pcDirectory1 ); + configASSERT( ucReturn == F_NO_ERROR ); + + /* Move into the created sub-directory. */ + ucReturn = f_chdir( pcDirectory1 ); + configASSERT( ucReturn == F_NO_ERROR ); + + /* Obtain and print out the working directory. */ + f_getcwd( cRAMBuffer, fsRAM_BUFFER_SIZE ); + + /* Create a subdirectory in the new directory. */ + ucReturn = f_mkdir( pcDirectory2 ); + configASSERT( ucReturn == F_NO_ERROR ); + + /* Move into the directory just created - now two directories down from + the root. */ + ucReturn = f_chdir( pcDirectory2 ); + configASSERT( ucReturn == F_NO_ERROR ); + + /* Obtain and print out the working directory. */ + f_getcwd( cRAMBuffer, fsRAM_BUFFER_SIZE ); + configASSERT( strcmp( cRAMBuffer, pcFullPath ) == 0 ); + + /* Generate the file name. */ + sprintf( cFileName, "%s.txt", pcDirectory2 ); + + /* Print out the file name and the directory into which the file is being + written. */ + pxFile = f_open( cFileName, "w" ); + + /* Create a file 1 byte at a time. The file is filled with incrementing + ascii characters starting from '0'. */ + for( iByte = 0; iByte < fsPUTC_FILE_SIZE; iByte++ ) + { + iReturned = f_putc( ( ( int ) '0' + iByte ), pxFile ); + configASSERT( iReturned == ( ( int ) '0' + iByte ) ); + } + + /* Finished so close the file. */ + f_close( pxFile ); + + /* Move back to the root directory. */ + ucReturn = f_chdir( "../.." ); + configASSERT( ucReturn == F_NO_ERROR ); + + /* Obtain and print out the working directory. */ + f_getcwd( cRAMBuffer, fsRAM_BUFFER_SIZE ); + configASSERT( strcmp( cRAMBuffer, pcRoot ) == 0 ); +} +/*-----------------------------------------------------------*/ + +static void prvVerifyDemoFileUsing_f_getc( void ) +{ +unsigned char ucReturn; +int iByte, iReturned; +F_FILE *pxFile; +char cFileName[ fsMAX_FILE_NAME_LEN ]; + + /* Move into the directory in which the file was created. */ + ucReturn = f_chdir( pcFullPath ); + configASSERT( ucReturn == F_NO_ERROR ); + + /* Obtain and print out the working directory. */ + f_getcwd( cRAMBuffer, fsRAM_BUFFER_SIZE ); + configASSERT( strcmp( cRAMBuffer, pcFullPath ) == 0 ); + + /* Generate the file name. */ + sprintf( cFileName, "%s.txt", pcDirectory2 ); + + /* This time the file is opened for reading. */ + pxFile = f_open( cFileName, "r" ); + + /* Read the file 1 byte at a time. */ + for( iByte = 0; iByte < fsPUTC_FILE_SIZE; iByte++ ) + { + iReturned = f_getc( pxFile ); + configASSERT( iReturned == ( ( int ) '0' + iByte ) ); + } + + /* Finished so close the file. */ + f_close( pxFile ); + + /* Move back to the root directory. */ + ucReturn = f_chdir( "../.." ); + configASSERT( ucReturn == F_NO_ERROR ); + + /* Obtain and print out the working directory. */ + f_getcwd( cRAMBuffer, fsRAM_BUFFER_SIZE ); +} + + + + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/SimpleTCPEchoServer.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/SimpleTCPEchoServer.c new file mode 100644 index 000000000..2a2c704d7 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/SimpleTCPEchoServer.c @@ -0,0 +1,288 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * FreeRTOS tasks are used with FreeRTOS+TCP to create a TCP echo server on the + * standard echo port number (7). + * + * See the following web page for essential demo usage and configuration + * details: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Server.html + */ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Remove the whole file if FreeRTOSIPConfig.h is set to exclude TCP. */ +#if( ipconfigUSE_TCP == 1 ) + +/* The maximum time to wait for a closing socket to close. */ +#define tcpechoSHUTDOWN_DELAY ( pdMS_TO_TICKS( 5000 ) ) + +/* The standard echo port number. */ +#define tcpechoPORT_NUMBER 7 + +/* If ipconfigUSE_TCP_WIN is 1 then the Tx sockets will use a buffer size set by +ipconfigTCP_TX_BUFFER_LENGTH, and the Tx window size will be +configECHO_SERVER_TX_WINDOW_SIZE times the buffer size. Note +ipconfigTCP_TX_BUFFER_LENGTH is set in FreeRTOSIPConfig.h as it is a standard TCP/IP +stack constant, whereas configECHO_SERVER_TX_WINDOW_SIZE is set in +FreeRTOSConfig.h as it is a demo application constant. */ +#ifndef configECHO_SERVER_TX_WINDOW_SIZE + #define configECHO_SERVER_TX_WINDOW_SIZE 2 +#endif + +/* If ipconfigUSE_TCP_WIN is 1 then the Rx sockets will use a buffer size set by +ipconfigTCP_RX_BUFFER_LENGTH, and the Rx window size will be +configECHO_SERVER_RX_WINDOW_SIZE times the buffer size. Note +ipconfigTCP_RX_BUFFER_LENGTH is set in FreeRTOSIPConfig.h as it is a standard TCP/IP +stack constant, whereas configECHO_SERVER_RX_WINDOW_SIZE is set in +FreeRTOSConfig.h as it is a demo application constant. */ +#ifndef configECHO_SERVER_RX_WINDOW_SIZE + #define configECHO_SERVER_RX_WINDOW_SIZE 2 +#endif + +/*-----------------------------------------------------------*/ + +/* + * Uses FreeRTOS+TCP to listen for incoming echo connections, creating a task + * to handle each connection. + */ +static void prvConnectionListeningTask( void *pvParameters ); + +/* + * Created by the connection listening task to handle a single connection. + */ +static void prvServerConnectionInstance( void *pvParameters ); + +/*-----------------------------------------------------------*/ + +/* Stores the stack size passed into vStartSimpleTCPServerTasks() so it can be +reused when the server listening task creates tasks to handle connections. */ +static uint16_t usUsedStackSize = 0; + +/*-----------------------------------------------------------*/ + +void vStartSimpleTCPServerTasks( uint16_t usStackSize, UBaseType_t uxPriority ) +{ + /* Create the TCP echo server. */ + xTaskCreate( prvConnectionListeningTask, "ServerListener", usStackSize, NULL, uxPriority + 1, NULL ); + + /* Remember the requested stack size so it can be re-used by the server + listening task when it creates tasks to handle connections. */ + usUsedStackSize = usStackSize; +} +/*-----------------------------------------------------------*/ + +static void prvConnectionListeningTask( void *pvParameters ) +{ +struct freertos_sockaddr xClient, xBindAddress; +Socket_t xListeningSocket, xConnectedSocket; +socklen_t xSize = sizeof( xClient ); +static const TickType_t xReceiveTimeOut = portMAX_DELAY; +const BaseType_t xBacklog = 20; + +#if( ipconfigUSE_TCP_WIN == 1 ) + WinProperties_t xWinProps; + + /* Fill in the buffer and window sizes that will be used by the socket. */ + xWinProps.lTxBufSize = ipconfigTCP_TX_BUFFER_LENGTH; + xWinProps.lTxWinSize = configECHO_SERVER_TX_WINDOW_SIZE; + xWinProps.lRxBufSize = ipconfigTCP_RX_BUFFER_LENGTH; + xWinProps.lRxWinSize = configECHO_SERVER_RX_WINDOW_SIZE; +#endif /* ipconfigUSE_TCP_WIN */ + + /* Just to prevent compiler warnings. */ + ( void ) pvParameters; + + /* Attempt to open the socket. */ + xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET ); + + /* Set a time out so accept() will just wait for a connection. */ + FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + + /* Set the window and buffer sizes. */ + #if( ipconfigUSE_TCP_WIN == 1 ) + { + FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); + } + #endif /* ipconfigUSE_TCP_WIN */ + + /* Bind the socket to the port that the client task will send to, then + listen for incoming connections. */ + xBindAddress.sin_port = tcpechoPORT_NUMBER; + xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port ); + FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) ); + FreeRTOS_listen( xListeningSocket, xBacklog ); + + for( ;; ) + { + /* Wait for a client to connect. */ + xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize ); + configASSERT( xConnectedSocket != FREERTOS_INVALID_SOCKET ); + + /* Spawn a task to handle the connection. */ + xTaskCreate( prvServerConnectionInstance, "EchoServer", usUsedStackSize, ( void * ) xConnectedSocket, tskIDLE_PRIORITY, NULL ); + } +} +/*-----------------------------------------------------------*/ + +static void prvServerConnectionInstance( void *pvParameters ) +{ +int32_t lBytes, lSent, lTotalSent; +Socket_t xConnectedSocket; +static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 5000 ); +static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 5000 ); +TickType_t xTimeOnShutdown; +uint8_t *pucRxBuffer; + + xConnectedSocket = ( Socket_t ) pvParameters; + + /* Attempt to create the buffer used to receive the string to be echoed + back. This could be avoided using a zero copy interface that just returned + the same buffer. */ + pucRxBuffer = ( uint8_t * ) pvPortMalloc( ipconfigTCP_MSS ); + + if( pucRxBuffer != NULL ) + { + FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xReceiveTimeOut ) ); + + for( ;; ) + { + /* Zero out the receive array so there is NULL at the end of the string + when it is printed out. */ + memset( pucRxBuffer, 0x00, ipconfigTCP_MSS ); + + /* Receive data on the socket. */ + lBytes = FreeRTOS_recv( xConnectedSocket, pucRxBuffer, ipconfigTCP_MSS, 0 ); + + /* If data was received, echo it back. */ + if( lBytes >= 0 ) + { + lSent = 0; + lTotalSent = 0; + + /* Call send() until all the data has been sent. */ + while( ( lSent >= 0 ) && ( lTotalSent < lBytes ) ) + { + lSent = FreeRTOS_send( xConnectedSocket, pucRxBuffer, lBytes - lTotalSent, 0 ); + lTotalSent += lSent; + } + + if( lSent < 0 ) + { + /* Socket closed? */ + break; + } + } + else + { + /* Socket closed? */ + break; + } + } + } + + /* Initiate a shutdown in case it has not already been initiated. */ + FreeRTOS_shutdown( xConnectedSocket, FREERTOS_SHUT_RDWR ); + + /* Wait for the shutdown to take effect, indicated by FreeRTOS_recv() + returning an error. */ + xTimeOnShutdown = xTaskGetTickCount(); + do + { + if( FreeRTOS_recv( xConnectedSocket, pucRxBuffer, ipconfigTCP_MSS, 0 ) < 0 ) + { + break; + } + } while( ( xTaskGetTickCount() - xTimeOnShutdown ) < tcpechoSHUTDOWN_DELAY ); + + /* Finished with the socket, buffer, the task. */ + vPortFree( pucRxBuffer ); + FreeRTOS_closesocket( xConnectedSocket ); + + vTaskDelete( NULL ); +} +/*-----------------------------------------------------------*/ + +/* The whole file is excluded if TCP is not compiled in. */ +#endif /* ipconfigUSE_TCP */ + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TCPEchoClient_SingleTasks.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TCPEchoClient_SingleTasks.c new file mode 100644 index 000000000..d9de1a909 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TCPEchoClient_SingleTasks.c @@ -0,0 +1,433 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * A set of tasks are created that send TCP echo requests to the standard echo + * port (port 7) on the IP address set by the configECHO_SERVER_ADDR0 to + * configECHO_SERVER_ADDR3 constants, then wait for and verify the reply + * (another demo is available that demonstrates the reception being performed in + * a task other than that from with the request was made). + * + * See the following web page for essential demo usage and configuration + * details: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Clients.html + */ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Exclude the whole file if FreeRTOSIPConfig.h is configured to use UDP only. */ +#if( ipconfigUSE_TCP == 1 ) + +/* The echo tasks create a socket, send out a number of echo requests, listen +for the echo reply, then close the socket again before starting over. This +delay is used between each iteration to ensure the network does not get too +congested. */ +#define echoLOOP_DELAY ( ( TickType_t ) 150 / portTICK_PERIOD_MS ) + +/* The echo server is assumed to be on port 7, which is the standard echo +protocol port. */ +#ifndef configTCP_ECHO_CLIENT_PORT + #define echoECHO_PORT ( 7 ) +#else + #define echoECHO_PORT ( configTCP_ECHO_CLIENT_PORT ) +#endif + +/* The size of the buffers is a multiple of the MSS - the length of the data +sent is a pseudo random size between 20 and echoBUFFER_SIZES. */ +#define echoBUFFER_SIZE_MULTIPLIER ( 2 ) +#define echoBUFFER_SIZES ( ipconfigTCP_MSS * echoBUFFER_SIZE_MULTIPLIER ) + +/* The number of instances of the echo client task to create. */ +#define echoNUM_ECHO_CLIENTS ( 1 ) + +/* If ipconfigUSE_TCP_WIN is 1 then the Tx socket will use a buffer size set by +ipconfigTCP_TX_BUFFER_LENGTH, and the Tx window size will be +configECHO_CLIENT_TX_WINDOW_SIZE times the buffer size. Note +ipconfigTCP_TX_BUFFER_LENGTH is set in FreeRTOSIPConfig.h as it is a standard TCP/IP +stack constant, whereas configECHO_CLIENT_TX_WINDOW_SIZE is set in +FreeRTOSConfig.h as it is a demo application constant. */ +#ifndef configECHO_CLIENT_TX_WINDOW_SIZE + #define configECHO_CLIENT_TX_WINDOW_SIZE 2 +#endif + +/* If ipconfigUSE_TCP_WIN is 1 then the Rx socket will use a buffer size set by +ipconfigTCP_RX_BUFFER_LENGTH, and the Rx window size will be +configECHO_CLIENT_RX_WINDOW_SIZE times the buffer size. Note +ipconfigTCP_RX_BUFFER_LENGTH is set in FreeRTOSIPConfig.h as it is a standard TCP/IP +stack constant, whereas configECHO_CLIENT_RX_WINDOW_SIZE is set in +FreeRTOSConfig.h as it is a demo application constant. */ +#ifndef configECHO_CLIENT_RX_WINDOW_SIZE + #define configECHO_CLIENT_RX_WINDOW_SIZE 2 +#endif + +/*-----------------------------------------------------------*/ + +/* + * Uses a socket to send data to, then receive data from, the standard echo + * port number 7. + */ +static void prvEchoClientTask( void *pvParameters ); + +/* + * Creates a pseudo random sized buffer of data to send to the echo server. + */ +static BaseType_t prvCreateTxData( char *ucBuffer, uint32_t ulBufferLength ); + +/*-----------------------------------------------------------*/ + +/* Rx and Tx time outs are used to ensure the sockets do not wait too long for +missing data. */ +static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 4000 ); +static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 2000 ); + +/* Counters for each created task - for inspection only. */ +static uint32_t ulTxRxCycles[ echoNUM_ECHO_CLIENTS ] = { 0 }, + ulTxRxFailures[ echoNUM_ECHO_CLIENTS ] = { 0 }, + ulConnections[ echoNUM_ECHO_CLIENTS ] = { 0 }; + +/* Rx and Tx buffers for each created task. */ +static char cTxBuffers[ echoNUM_ECHO_CLIENTS ][ echoBUFFER_SIZES ], + cRxBuffers[ echoNUM_ECHO_CLIENTS ][ echoBUFFER_SIZES ]; + +/*-----------------------------------------------------------*/ + +void vStartTCPEchoClientTasks_SingleTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ) +{ +BaseType_t x; + + /* Create the echo client tasks. */ + for( x = 0; x < echoNUM_ECHO_CLIENTS; x++ ) + { + xTaskCreate( prvEchoClientTask, /* The function that implements the task. */ + "Echo0", /* Just a text name for the task to aid debugging. */ + usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */ + ( void * ) x, /* The task parameter, not used in this case. */ + uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */ + NULL ); /* The task handle is not used. */ + } +} +/*-----------------------------------------------------------*/ + +static void prvEchoClientTask( void *pvParameters ) +{ +Socket_t xSocket; +struct freertos_sockaddr xEchoServerAddress; +int32_t lLoopCount = 0UL; +const int32_t lMaxLoopCount = 1; +volatile uint32_t ulTxCount = 0UL; +BaseType_t xReceivedBytes, xReturned, xInstance; +BaseType_t lTransmitted, lStringLength; +char *pcTransmittedString, *pcReceivedString; +TickType_t xTimeOnEntering; + + #if( ipconfigUSE_TCP_WIN == 1 ) + + WinProperties_t xWinProps; + + /* Fill in the buffer and window sizes that will be used by the socket. */ + xWinProps.lTxBufSize = ipconfigTCP_TX_BUFFER_LENGTH; + xWinProps.lTxWinSize = configECHO_CLIENT_TX_WINDOW_SIZE; + xWinProps.lRxBufSize = ipconfigTCP_RX_BUFFER_LENGTH; + xWinProps.lRxWinSize = configECHO_CLIENT_RX_WINDOW_SIZE; + + #endif /* ipconfigUSE_TCP_WIN */ + + /* This task can be created a number of times. Each instance is numbered + to enable each instance to use a different Rx and Tx buffer. The number is + passed in as the task's parameter. */ + xInstance = ( BaseType_t ) pvParameters; + + /* Point to the buffers to be used by this instance of this task. */ + pcTransmittedString = &( cTxBuffers[ xInstance ][ 0 ] ); + pcReceivedString = &( cRxBuffers[ xInstance ][ 0 ] ); + + /* Echo requests are sent to the echo server. The address of the echo + server is configured by the constants configECHO_SERVER_ADDR0 to + configECHO_SERVER_ADDR3 in FreeRTOSConfig.h. */ + xEchoServerAddress.sin_port = FreeRTOS_htons( echoECHO_PORT ); + xEchoServerAddress.sin_addr = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0, + configECHO_SERVER_ADDR1, + configECHO_SERVER_ADDR2, + configECHO_SERVER_ADDR3 ); + + for( ;; ) + { + /* Create a TCP socket. */ + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + configASSERT( xSocket != FREERTOS_INVALID_SOCKET ); + + /* Set a time out so a missing reply does not cause the task to block + indefinitely. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + + #if( ipconfigUSE_TCP_WIN == 1 ) + { + /* Set the window and buffer sizes. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); + } + #endif /* ipconfigUSE_TCP_WIN */ + + /* Connect to the echo server. */ + if( FreeRTOS_connect( xSocket, &xEchoServerAddress, sizeof( xEchoServerAddress ) ) == 0 ) + { + ulConnections[ xInstance ]++; + + /* Send a number of echo requests. */ + for( lLoopCount = 0; lLoopCount < lMaxLoopCount; lLoopCount++ ) + { + /* Create the string that is sent to the echo server. */ + lStringLength = prvCreateTxData( pcTransmittedString, echoBUFFER_SIZES ); + + /* Add in some unique text at the front of the string. */ + sprintf( pcTransmittedString, "TxRx message number %u", ( unsigned ) ulTxCount ); + ulTxCount++; + + /* Send the string to the socket. */ + lTransmitted = FreeRTOS_send( xSocket, /* The socket being sent to. */ + ( void * ) pcTransmittedString, /* The data being sent. */ + lStringLength, /* The length of the data being sent. */ + 0 ); /* No flags. */ + + if( lTransmitted < 0 ) + { + /* Error? */ + break; + } + + /* Clear the buffer into which the echoed string will be + placed. */ + memset( ( void * ) pcReceivedString, 0x00, echoBUFFER_SIZES ); + xReceivedBytes = 0; + + /* Receive data echoed back to the socket. */ + while( xReceivedBytes < lTransmitted ) + { + xReturned = FreeRTOS_recv( xSocket, /* The socket being received from. */ + &( pcReceivedString[ xReceivedBytes ] ),/* The buffer into which the received data will be written. */ + lStringLength - xReceivedBytes, /* The size of the buffer provided to receive the data. */ + 0 ); /* No flags. */ + + if( xReturned < 0 ) + { + /* Error occurred. Latch it so it can be detected + below. */ + xReceivedBytes = xReturned; + break; + } + else if( xReturned == 0 ) + { + /* Timed out. */ + break; + } + else + { + /* Keep a count of the bytes received so far. */ + xReceivedBytes += xReturned; + } + } + + /* If an error occurred it will be latched in xReceivedBytes, + otherwise xReceived bytes will be just that - the number of + bytes received from the echo server. */ + if( xReceivedBytes > 0 ) + { + /* Compare the transmitted string to the received string. */ + configASSERT( strncmp( pcReceivedString, pcTransmittedString, lTransmitted ) == 0 ); + if( strncmp( pcReceivedString, pcTransmittedString, lTransmitted ) == 0 ) + { + /* The echo reply was received without error. */ + ulTxRxCycles[ xInstance ]++; + } + else + { + /* The received string did not match the transmitted + string. */ + ulTxRxFailures[ xInstance ]++; + break; + } + } + else if( xReceivedBytes < 0 ) + { + /* FreeRTOS_recv() returned an error. */ + break; + } + else + { + /* Timed out without receiving anything? */ + break; + } + } + + /* Finished using the connected socket, initiate a graceful close: + FIN, FIN+ACK, ACK. */ + FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR ); + + /* Expect FreeRTOS_recv() to return an error once the shutdown is + complete. */ + xTimeOnEntering = xTaskGetTickCount(); + do + { + xReturned = FreeRTOS_recv( xSocket, /* The socket being received from. */ + &( pcReceivedString[ 0 ] ), /* The buffer into which the received data will be written. */ + echoBUFFER_SIZES, /* The size of the buffer provided to receive the data. */ + 0 ); + + if( xReturned < 0 ) + { + break; + } + + } while( ( xTaskGetTickCount() - xTimeOnEntering ) < xReceiveTimeOut ); + } + + /* Close this socket before looping back to create another. */ + FreeRTOS_closesocket( xSocket ); + + /* Pause for a short while to ensure the network is not too + congested. */ + vTaskDelay( echoLOOP_DELAY ); + } +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvCreateTxData( char *cBuffer, uint32_t ulBufferLength ) +{ +BaseType_t lCharactersToAdd, lCharacter; +char cChar = '0'; +const BaseType_t lMinimumLength = 60; + + /* Randomise the number of characters that will be sent in the echo + request. */ + do + { + lCharactersToAdd = ipconfigRAND32() % ( ulBufferLength - 20UL ); + } while ( ( lCharactersToAdd == 0 ) || ( lCharactersToAdd < lMinimumLength ) ); /* Must be at least enough to add the unique text to the start of the string later. */ + + /* Fill the buffer. */ + for( lCharacter = 0; lCharacter < lCharactersToAdd; lCharacter++ ) + { + cBuffer[ lCharacter ] = cChar; + cChar++; + + if( cChar > '~' ) + { + cChar = '0'; + } + } + + return lCharactersToAdd; +} +/*-----------------------------------------------------------*/ + +BaseType_t xAreSingleTaskTCPEchoClientsStillRunning( void ) +{ +static uint32_t ulLastEchoSocketCount[ echoNUM_ECHO_CLIENTS ] = { 0 }, ulLastConnections[ echoNUM_ECHO_CLIENTS ] = { 0 }; +BaseType_t xReturn = pdPASS, x; + + /* Return fail is the number of cycles does not increment between + consecutive calls. */ + for( x = 0; x < echoNUM_ECHO_CLIENTS; x++ ) + { + if( ulTxRxCycles[ x ] == ulLastEchoSocketCount[ x ] ) + { + xReturn = pdFAIL; + } + else + { + ulLastEchoSocketCount[ x ] = ulTxRxCycles[ x ]; + } + + if( ulConnections[ x ] == ulLastConnections[ x ] ) + { + xReturn = pdFAIL; + } + else + { + ulConnections[ x ] = ulLastConnections[ x ]; + } + } + + return xReturn; +} + +#endif /* ipconfigUSE_TCP */ + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TFTPServer.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TFTPServer.c new file mode 100644 index 000000000..0e93f77c0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TFTPServer.c @@ -0,0 +1,582 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * A basic TFTP server that can currently only be used to receive files, and not + * send files. This is a slim implementation intended for use in boot loaders + * and other applications that require over the air reception of files. + */ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* FreeRTOS+FAT includes. */ +#include "ff_stdio.h" + +#if( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND != 1 ) + #error ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND must be set to one to use this TFTP server. +#endif + +#if( configTICK_RATE_HZ > 1000 ) + #error The TFTP server uses the pdMS_TO_TICKS() macro, so configTICK_RATE_HZ must be less than or equal to 1000 +#endif + +#ifndef ipconfigTFTP_TIME_OUT_MS + #define ipconfigTFTP_TIME_OUT_MS ( 10000 ) +#endif + +#ifndef ipconfigTFTP_MAX_RETRIES + #define ipconfigTFTP_MAX_RETRIES ( 6 ) +#endif + +/* Standard/expected TFTP port number. */ +#define tftpPORT_NUMBER ( ( uint16_t ) 69 ) + +/* Offset to the file name within the frame. */ +#define tftpFILE_NAME_OFFSET ( 2 ) + +/* Number of bytes in the Ack message. */ +#define tftpACK_MESSAGE_LENGTH 4 + +/* Files are sent in fixed length blocks of 512 (the original maximum). */ +#define tftpMAX_DATA_LENGTH ( ( size_t ) 512 ) + +/* Standard TFTP opcodes. */ +typedef enum +{ + eReadRequest = 1, + eWriteRequest, + eData, + eAck, + eError +} eTFTPOpcode_t; + +/* Error codes from the RFC. */ +typedef enum +{ + eFileNotFound = 1, + eAccessViolation, + eDiskFull, + eIllegalTFTPOperation, + eUnknownTransferID, + eFileAlreadyExists +} eTFTPErrorCode_t; + +/* Header used in data transfer packets. */ +#include "pack_struct_start.h" +struct DataPacketHeader +{ + uint16_t usOpcode; + uint16_t usBlockNumber; +} +#include "pack_struct_end.h" +typedef struct DataPacketHeader TFTPBlockNumberHeader_t; + +/* + * Manages a single TFTP connection at a time. + */ +static void prvSimpleTFTPServerTask( void *pvParameters ); + +/* + * Manage the reception of a file. If the file is received correctly then + * return pdPASS, otherwise return pdFAIL. + */ +static BaseType_t prvReceiveFile( FF_FILE *pxFile, struct freertos_sockaddr *pxClient ); + +/* + * Send an error frame to the client. + */ +static void prvSendTFTPError( Socket_t xSocket, struct freertos_sockaddr *pxClient, eTFTPErrorCode_t eErrorCode ); + +/* + * Check a received write request contains a potentially valid file name string, + * and is a binary mode transfer. If so return a pointer to the file name with + * the write request packet received from the network, otherwise return NULL. + */ +static const char* prvValidateWriteRequest( Socket_t xSocket, struct freertos_sockaddr *pxClient, uint8_t *pucUDPPayloadBuffer ); + +/* + * Called after a valid write request has been received to first check the file + * does not already exist, and if the file does not exist, create the file ready + * to be written. If the file did already exist, or if the file could not be + * created, then NULL is returned - otherwise a handle to the created file is + * returned. + */ +static FF_FILE* prvValidateFileToWrite( Socket_t xSocket, struct freertos_sockaddr *pxClient, const char *pcFileName ); + +/* + * Send an acknowledgement packet to pxClient with block number usBlockNumber. + */ +static void prvSendAcknowledgement( Socket_t xSocket, struct freertos_sockaddr *pxClient, uint16_t usBlockNumber ); + +/* The index for the error string below MUST match the value of the applicable +eTFTPErrorCode_t error code value. */ +static const char *cErrorStrings[] = +{ + NULL, /* Not valid. */ + "File not found.", + "Access violation.", + "Disk full or allocation exceeded.", + "Illegal TFTP operation.", + "Unknown transfer ID.", + "File already exists.", + "No such user." +}; + +/*-----------------------------------------------------------*/ + +void vStartTFTPServerTask( uint16_t usStackSize, UBaseType_t uxPriority ) +{ + /* A single server task is created. Currently this is only capable of + managing one TFTP transfer at a time. */ + xTaskCreate( prvSimpleTFTPServerTask, "TFTPd", usStackSize, NULL, uxPriority, NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvSimpleTFTPServerTask( void *pvParameters ) +{ +int32_t lBytes; +uint8_t *pucUDPPayloadBuffer; +struct freertos_sockaddr xClient, xBindAddress; +uint32_t xClientLength = sizeof( xClient ), ulIPAddress; +Socket_t xTFTPListeningSocket; +const char *pcFileName; +FF_FILE *pxFile; + + /* Just to prevent compiler warnings. */ + ( void ) pvParameters; + + /* Attempt to open the socket. The receive block time defaults to the max + delay, so there is no need to set that separately. */ + xTFTPListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + configASSERT( xTFTPListeningSocket != FREERTOS_INVALID_SOCKET ); + + /* Bind to the standard TFTP port. */ + FreeRTOS_GetAddressConfiguration( &ulIPAddress, NULL, NULL, NULL ); + xBindAddress.sin_addr = ulIPAddress; + xBindAddress.sin_port = FreeRTOS_htons( tftpPORT_NUMBER ); + FreeRTOS_bind( xTFTPListeningSocket, &xBindAddress, sizeof( xBindAddress ) ); + + for( ;; ) + { + /* Look for the start of a new transfer on the TFTP port. ulFlags has + the zero copy bit set (FREERTOS_ZERO_COPY) indicating to the stack that + a reference to the received data should be passed out to this task using + the second parameter to the FreeRTOS_recvfrom() call. When this is done + the IP stack is no longer responsible for releasing the buffer, and the + task *must* return the buffer to the stack when it is no longer + needed. */ + lBytes = FreeRTOS_recvfrom( xTFTPListeningSocket, ( void * ) &pucUDPPayloadBuffer, 0, FREERTOS_ZERO_COPY, &xClient, &xClientLength ); + + if( lBytes >= 0 ) + { + /* Could this be a new write request? The opcode is contained in + the first two bytes of the received data. */ + if( ( pucUDPPayloadBuffer[ 0 ] == ( uint8_t ) 0 ) && ( pucUDPPayloadBuffer[ 1 ] == ( uint8_t ) eWriteRequest ) ) + { + /* If the write request is valid pcFileName will get set to + point to the file name within pucWriteRequestBuffer - otherwise + an appropriate error will be sent on xTFTPListeningSocket. */ + pcFileName = prvValidateWriteRequest( xTFTPListeningSocket, &xClient, pucUDPPayloadBuffer ); + + if( pcFileName != NULL ) + { + /* If the file does not already exist, and can be created, + then xFile will get set to the file's open handle. + Otherwise an appropriate error will be sent on + xTFTPListeningSocket. */ + pxFile = prvValidateFileToWrite( xTFTPListeningSocket, &xClient, pcFileName ); + + if( pxFile != NULL ) + { + /* Manage reception of the file. */ + prvReceiveFile( pxFile, &xClient ); + } + } + } + else + { + /* Not a transfer ID handled by this server. */ + prvSendTFTPError( xTFTPListeningSocket, &xClient, eUnknownTransferID ); + } + + /* The buffer was received using zero copy, so *must* be freed. */ + FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer ); + } + } +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvReceiveFile( FF_FILE *pxFile, struct freertos_sockaddr *pxClient ) +{ +BaseType_t xReturn = pdPASS, xRetries = 0; +uint16_t usExpectedBlockNumber; +Socket_t xTFTPRxSocket = FREERTOS_INVALID_SOCKET; +TickType_t xRxTimeout = pdMS_TO_TICKS( ipconfigTFTP_TIME_OUT_MS ); +int32_t lBytes; +uint8_t *pucFileBuffer; +struct freertos_sockaddr xClient; +uint32_t xClientLength = sizeof( xClient ); +TFTPBlockNumberHeader_t *pxHeader; +size_t xBlocksWritten, xBytesOfFileDataReceived = tftpMAX_DATA_LENGTH; +const size_t xBlocksToWrite = 1; + + /* The file is open for writing, now create the socket on which the file + will be received from the client. Note the socket is not bound here - so + will be automatically bound to a port number selected by the IP stack when + it is used for the first time. */ + xTFTPRxSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + + if( xTFTPRxSocket != FREERTOS_INVALID_SOCKET ) + { + /* The socket's Rx block time is set to the user configurable timeout + value. */ + FreeRTOS_setsockopt( xTFTPRxSocket, 0, FREERTOS_SO_RCVTIMEO, &xRxTimeout, sizeof( xRxTimeout ) ); + + /* Acknowledge the write request so the client starts to send the file. + The first acknowledgment does not have a corresponding block number so + the special case block number 0 is used. */ + usExpectedBlockNumber = 0; + + do + { + /* The acknowledgment sent here may be a duplicate if the last call + to FreeRTOS_recvfrom() timee out. */ + prvSendAcknowledgement( xTFTPRxSocket, pxClient, usExpectedBlockNumber ); + + /* Wait for next data packet. Zero copy is used so it is the + responsibility of this task to free the received data once it is no + longer required. */ + lBytes = FreeRTOS_recvfrom( xTFTPRxSocket, ( void * ) &pucFileBuffer, 0, FREERTOS_ZERO_COPY, &xClient, &xClientLength ); + + if( lBytes == 0 ) + { + /* Timed out. */ + FreeRTOS_printf( ( "Error: Timeout.\n" ) ); + xRetries++; + + if( xRetries > ipconfigTFTP_MAX_RETRIES ) + { + FreeRTOS_printf( ( "Error: Retry limit exceeded.\n" ) ); + xReturn = pdFAIL; + } + } + else + { + /* Data received. It is expected to be the next sequential + block. */ + usExpectedBlockNumber++; + pxHeader = ( TFTPBlockNumberHeader_t * ) pucFileBuffer; + pxHeader->usOpcode = FreeRTOS_ntohs( pxHeader->usOpcode ); + pxHeader->usBlockNumber = FreeRTOS_ntohs( pxHeader->usBlockNumber ); + + /* Is the data as expected and from the expected IP address and + port? */ + if( ( pxHeader->usOpcode == ( uint16_t ) eData ) && + ( pxHeader->usBlockNumber == usExpectedBlockNumber ) && + ( pxClient->sin_addr == xClient.sin_addr ) && + ( pxClient->sin_port == xClient.sin_port ) ) + { + /* Everything in the packet other than the header is file + data. */ + xBytesOfFileDataReceived = ( size_t ) lBytes - sizeof( TFTPBlockNumberHeader_t ); + FreeRTOS_printf( ( "Received %d bytes of file data.\n", ( int ) xBytesOfFileDataReceived ) ); + + /* Ack the data then write the data to the file. */ + prvSendAcknowledgement( xTFTPRxSocket, pxClient, usExpectedBlockNumber ); + + /* The data is located by jumping over the header. */ + /*_RB_ Is it ok to write 0 bytes? */ + xBlocksWritten = ff_fwrite( pucFileBuffer + sizeof( TFTPBlockNumberHeader_t ), + xBytesOfFileDataReceived, + xBlocksToWrite, + pxFile ); + + if( xBlocksWritten != xBlocksToWrite ) + { + /* File could not be written. */ + prvSendTFTPError( xTFTPRxSocket, pxClient, eDiskFull ); + xReturn = pdFAIL; + } + + /* Start to receive the next block. */ + xRetries = 0; + } + else + { + prvSendTFTPError( xTFTPRxSocket, pxClient, eIllegalTFTPOperation ); + xReturn = pdFAIL; + } + + /* pucFileBuffer was obtained using zero copy mode, so the + buffer must be freed now its contents have been written to the + disk. */ + FreeRTOS_ReleaseUDPPayloadBuffer( pucFileBuffer ); + } + + /* Until a disk write fails, or the maximum number of retries is + exceeded, or fewer bytes than tftpMAX_DATA_LENGTH are received (which + indicates the end of the file). */ + } while( ( xReturn != pdFAIL ) && ( xBytesOfFileDataReceived == tftpMAX_DATA_LENGTH ) ); + + FreeRTOS_printf( ( "Closing connection.\n" ) ); + FreeRTOS_closesocket( xTFTPRxSocket ); + } + else + { + /* An error could be returned here, but it is probably cleaner to just + time out as the error would have to be sent via the listening socket + outside of this function. */ + FreeRTOS_printf( ( "Could not create socket to receive file.\n" ) ); + } + + ff_fclose( pxFile ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void prvSendAcknowledgement( Socket_t xSocket, struct freertos_sockaddr *pxClient, uint16_t usBlockNumber ) +{ +/* Small fixed size buffer, so not much to be gained by using the zero copy +interface, just send the buffer directly. */ +TFTPBlockNumberHeader_t xAckMessage; + + xAckMessage.usOpcode = FreeRTOS_htons( ( ( uint16_t ) eAck ) ); + xAckMessage.usBlockNumber = FreeRTOS_htons( usBlockNumber ); + FreeRTOS_sendto( xSocket, ( void * ) &xAckMessage, tftpACK_MESSAGE_LENGTH, 0, pxClient, sizeof( struct freertos_sockaddr ) ); +} +/*-----------------------------------------------------------*/ + +static FF_FILE* prvValidateFileToWrite( Socket_t xSocket, struct freertos_sockaddr *pxClient, const char *pcFileName ) +{ +FF_FILE *pxFile; + + FreeRTOS_printf( ( "Write request for %s received\n", pcFileName ) ); + + /* The file cannot be received if it already exists. Attempt to open the + file in read mode to see if it exists. */ + pxFile = ff_fopen( pcFileName, "r" ); + + if( pxFile != NULL ) + { + /* Can't receive a new file without deleting the old one first. */ + ff_fclose( pxFile ); + pxFile = NULL; + prvSendTFTPError( xSocket, pxClient, eFileAlreadyExists ); + } + else + { + /* The file does not already exist. Attempt to open the file in write + mode, which will cause it to be created. */ + pxFile = ff_fopen( pcFileName, "w" ); + + if( pxFile == NULL ) + { + /* The file cannot be created. */ + prvSendTFTPError( xSocket, pxClient, eAccessViolation ); + } + } + + return pxFile; +} +/*-----------------------------------------------------------*/ + +static const char* prvValidateWriteRequest( Socket_t xSocket, struct freertos_sockaddr *pxClient, uint8_t *pucUDPPayloadBuffer ) +{ +char *pcFileName; +BaseType_t x; +const char *pcOctedMode = "octet"; + + /* pcFileName is set to point to the file name which is inside the write + request frame, so its important not to free the frame until the operation is + over. The start of the file name string is after the opcode, so two bytes + into the packet. */ + pcFileName = ( char * ) &( pucUDPPayloadBuffer[ tftpFILE_NAME_OFFSET ] ); + + /* Sanity check the file name. */ + for( x = 0; x < ffconfigMAX_FILENAME; x++ ) + { + if( pcFileName[ x ] == 0x00 ) + { + /* The end of the string was located. */ + break; + } + else if( ( pcFileName[ x ] < ' ' ) || ( pcFileName[ x ] > '~' ) ) + { + /* Not a valid file name character. */ + pcFileName = NULL; + break; + } + else + { + /* Just a character in the file name. */ + } + } + + if( pcFileName != NULL ) + { + /* Only binary transfers are supported, indicated by an 'octet' mode + string following the file name. +1 to move past the null terminator to + the start of the next string. */ + x++; + if( strcmpi( pcOctedMode, ( const char * ) &( pucUDPPayloadBuffer[ tftpFILE_NAME_OFFSET + x ] ) ) != 0 ) + { + /* Not the expected mode. */ + prvSendTFTPError( xSocket, pxClient, eIllegalTFTPOperation ); + pcFileName = NULL; + } + } + else + { + prvSendTFTPError( xSocket, pxClient, eFileNotFound ); + } + + return pcFileName; +} +/*-----------------------------------------------------------*/ + +static void prvSendTFTPError( Socket_t xSocket, struct freertos_sockaddr *pxClient, eTFTPErrorCode_t eErrorCode ) +{ +uint8_t *pucUDPPayloadBuffer = NULL; +const size_t xFixedSizePart = ( size_t ) 5; /* 2 byte opcode, plus two byte error code, plus string terminating 0. */ +const size_t xNumberOfErrorStrings = sizeof( cErrorStrings ) / sizeof( char * ); +size_t xErrorCode = ( size_t ) eErrorCode, xTotalLength = 0; /* Only initialised to keep compiler quiet. */ +const char *pcErrorString = NULL; +int32_t lReturned; + + /* The total size of the packet to be sent depends on the length of the + error string. */ + if( xErrorCode < xNumberOfErrorStrings ) + { + pcErrorString = cErrorStrings[ xErrorCode ]; + + /* This task is going to send using the zero copy interface. The data + being sent is therefore written directly into a buffer that is passed + into, rather than copied into, the FreeRTOS_sendto() function. First + obtain a buffer of adequate length from the IP stack into which the + error packet will be written. Although a max delay is used, the actual + delay will be capped to ipconfigMAX_SEND_BLOCK_TIME_TICKS. */ + xTotalLength = strlen( pcErrorString ) + xFixedSizePart; + pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xTotalLength, portMAX_DELAY ); + } + + if( pucUDPPayloadBuffer != NULL ) + { + FreeRTOS_printf( ( "Error: %s\n", pcErrorString ) ); + + /* Create error packet: Opcode. */ + pucUDPPayloadBuffer[ 0 ] = 0; + pucUDPPayloadBuffer[ 1 ] = ( uint8_t ) eError; + + /* Create error packet: Error code. */ + pucUDPPayloadBuffer[ 2 ] = 0; + pucUDPPayloadBuffer[ 3 ] = ( uint8_t ) eErrorCode; + + /* Create error packet: Error string. */ + strcpy( ( ( char * ) &( pucUDPPayloadBuffer[ 4 ] ) ), pcErrorString ); + + /* Pass the buffer into the send function. ulFlags has the + FREERTOS_ZERO_COPY bit set so the IP stack will take control of the + buffer rather than copy data out of the buffer. */ + lReturned = FreeRTOS_sendto( xSocket, /* The socket to which the error frame is sent. */ + ( void * ) pucUDPPayloadBuffer, /* A pointer to the the data being sent. */ + xTotalLength, /* The length of the data being sent. */ + FREERTOS_ZERO_COPY, /* ulFlags with the FREERTOS_ZERO_COPY bit set. */ + pxClient, /* Where the data is being sent. */ + sizeof( *pxClient ) ); + + if( lReturned == 0 ) + { + /* The send operation failed, so this task is still responsible + for the buffer obtained from the IP stack. To ensure the buffer + is not lost it must either be used again, or, as in this case, + returned to the IP stack using FreeRTOS_ReleaseUDPPayloadBuffer(). */ + FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer ); + } + else + { + /* The send was successful so the IP stack is now managing the + buffer pointed to by pucUDPPayloadBuffer, and the IP stack will + return the buffer once it has been sent. */ + } + } +} + + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TraceMacros/Example1/DemoIPTrace.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TraceMacros/Example1/DemoIPTrace.c new file mode 100644 index 000000000..925c09438 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TraceMacros/Example1/DemoIPTrace.c @@ -0,0 +1,222 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * This file, along with DemoIPTrace.h, provides a basic example use of the + * FreeRTOS+TCP trace macros. The statistics gathered here can be viewed in + * the command line interface. + * See http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_CLI.html + * + * A simple generic mechanism is used that allocates a structure (see the + * ExampleDebugStatEntry_t definition in DemoIPTrace.h) to each ID defined in + * the same header file. The structures are stored in an array (see the + * xIPTraceValues[] below. + * + * The structure associates a function with a data value. See the + * vPerformAction and ulData members of ExampleDebugStatEntry_t respectively. + * The function is used to manipulate the data. At the time of writing two + * functions can be used - these are prvIncrementEventCount() which simply + * increments the data each time it is called, and prvStoreLowest() which + * sets the data to the lowest value of an input parameter ever seen. For + * example, to store the lowest ever number of free network buffer descriptors + * the parameter value is the current number of network buffer descriptors. + * + * The trace macros themselves are defined in DemoIPTrace.h and just invoke + * vExampleDebugStatUpdate(), passing in an ID value. vExampleDebugStatUpdate() + * then just executes the function associated with that value (prvStoreLowest(), + * prvIncrementEventCount(), etc.) as defined in the xIPTraceValues[] array. + */ + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_UDP_IP.h" +#include "DemoIPTrace.h" + +/* It is possible to remove the trace macros using the +configINCLUDE_DEMO_DEBUG_STATS setting in FreeRTOSIPConfig.h. */ +#if configINCLUDE_DEMO_DEBUG_STATS == 1 + +/* + * Each row in the xIPTraceValues[] table contains a pointer to a function that + * updates the value for that row. Rows that latch the lowest value point to + * this function (for example, this function can be used to latch the lowest + * number of network buffers that were available during the execution of the + * stack). + */ +static void prvStoreLowest( uint32_t *pulCurrentValue, uint32_t ulCount ); + +/* + * Each row in the xIPTraceValues[] table contains a pointer to a function that + * updates the value for that row. Rows that simply increment an event count + * point to this function. + */ +static void prvIncrementEventCount( uint32_t *pulCurrentValue, uint32_t ulCount ); + +/* The header file defines the IDs within this table. The string is used to +print a friendly message for the stat, and the function pointer is used to +perform the action for the state - for example, note the lowest ever value for +a stat, or just count the number of times the event occurs. */ +ExampleDebugStatEntry_t xIPTraceValues[] = +{ + /* Comment out array entries to remove individual trace items. */ + + { iptraceID_NETWORK_INTERFACE_RECEIVE, "Packets received by the network interface", prvIncrementEventCount, 0 }, + { iptraceID_NETWORK_INTERFACE_TRANSMIT, "Count of transmitted packets", prvIncrementEventCount, 0 }, + { iptraceID_PACKET_DROPPED_TO_GENERATE_ARP, "Count of packets dropped to generate ARP", prvIncrementEventCount, 0 }, + { iptraceID_NETWORK_BUFFER_OBTAINED, "Lowest ever available network buffers", prvStoreLowest, 0xffffUL }, + { iptraceID_NETWORK_EVENT_RECEIVED, "Lowest ever free space in network event queue", prvStoreLowest, 0xffffUL }, + { iptraceID_FAILED_TO_OBTAIN_NETWORK_BUFFER, "Count of failed attempts to obtain a network buffer", prvIncrementEventCount, 0 }, + { iptraceID_ARP_TABLE_ENTRY_EXPIRED, "Count of expired ARP entries", prvIncrementEventCount, 0 }, + { iptraceID_FAILED_TO_CREATE_SOCKET, "Count of failures to create a socket", prvIncrementEventCount, 0 }, + { iptraceID_RECVFROM_DISCARDING_BYTES, "Count of times recvfrom() has discarding bytes", prvIncrementEventCount, 0 }, + { iptraceID_ETHERNET_RX_EVENT_LOST, "Count of lost Etheret Rx events (event queue full?)", prvIncrementEventCount, 0 }, + { iptraceID_STACK_TX_EVENT_LOST, "Count of lost IP stack events (event queue full?)", prvIncrementEventCount, 0 }, + { ipconfigID_BIND_FAILED, "Count of failed calls to bind()", prvIncrementEventCount, 0 }, + { iptraceID_RECVFROM_TIMEOUT, "Count of receive timeouts", prvIncrementEventCount, 0 }, + { iptraceID_SENDTO_DATA_TOO_LONG, "Count of failed sends due to oversized payload", prvIncrementEventCount, 0 }, + { iptraceID_SENDTO_SOCKET_NOT_BOUND, "Count of failed sends due to unbound socket", prvIncrementEventCount, 0 }, + { iptraceID_NO_BUFFER_FOR_SENDTO, "Count of failed transmits due to timeout", prvIncrementEventCount, 0 }, + { iptraceID_WAIT_FOR_TX_DMA_DESCRIPTOR, "Number of times task had to wait to obtain a DMA Tx descriptor", prvIncrementEventCount, 0 }, + { iptraceID_FAILED_TO_NOTIFY_SELECT_GROUP, "Failed to notify select group", prvIncrementEventCount, 0 }, + { iptraceID_TOTAL_NETWORK_BUFFERS_OBTAINED, "Total network buffers obtained", prvIncrementEventCount, 0 }, + { iptraceID_TOTAL_NETWORK_BUFFERS_RELEASED, "Total network buffers released", prvIncrementEventCount, 0 } + +}; + +/*-----------------------------------------------------------*/ + +BaseType_t xExampleDebugStatEntries( void ) +{ + /* Return the number of entries in the xIPTraceValues[] table. */ + return ( BaseType_t ) ( sizeof( xIPTraceValues ) / sizeof( ExampleDebugStatEntry_t ) ); +} +/*-----------------------------------------------------------*/ + +void vExampleDebugStatUpdate( uint8_t ucIdentifier, uint32_t ulValue ) +{ +BaseType_t xIndex; +const BaseType_t xEntries = sizeof( xIPTraceValues ) / sizeof( ExampleDebugStatEntry_t ); + + /* Update an entry in the xIPTraceValues[] table. Each row in the table + includes a pointer to a function that performs the actual update. This + function just executes the update function from that table row. + + Search the array to find the identifier - this could be made more efficient + by using the identifier as an index into the array - but that would come + with the usability cost of needing to change all the identifiers above any + identifiers that are later inserted into the table. */ + for( xIndex = 0; xIndex < xEntries; xIndex++ ) + { + if( xIPTraceValues[ xIndex ].ucIdentifier == ucIdentifier ) + { + xIPTraceValues[ xIndex ].vPerformAction( &( xIPTraceValues[ xIndex ].ulData ), ulValue ); + break; + } + } + + configASSERT( xIndex != xEntries ); +} +/*-----------------------------------------------------------*/ + +static void prvIncrementEventCount( uint32_t *pulCurrentValue, uint32_t ulCount ) +{ + /* Each row in the xIPTraceValues[] table contains a pointer to a function + that updates the value for that row. Rows that simply increment an event + count point to this function. */ + ( void ) ulCount; + ( *pulCurrentValue )++; +} +/*-----------------------------------------------------------*/ + +static void prvStoreLowest( uint32_t *pulCurrentValue, uint32_t ulCount ) +{ + /* Each row in the xIPTraceValues[] table contains a pointer to a function + that updates the value for that row. Rows that latch the lowest value + point to this function (for example, this function can be used to latch + the lowest number of network buffers that were available during the + execution of the stack). */ + if( ulCount < *pulCurrentValue ) + { + *pulCurrentValue = ulCount; + } +} +/*-----------------------------------------------------------*/ + + +#endif /* configINCLUDE_DEMO_DEBUG_STATS == 1 */ + + + + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TraceMacros/Example1/DemoIPTrace.h b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TraceMacros/Example1/DemoIPTrace.h new file mode 100644 index 000000000..70c15b49c --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/TraceMacros/Example1/DemoIPTrace.h @@ -0,0 +1,185 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * This file, along with DemoIPTrace.c, provides a basic example use of the + * FreeRTOS+TCP trace macros. The statistics gathered here can be viewed in + * the command line interface. + * See http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_CLI.html + * + * A simple generic mechanism is used that allocates a structure (see the + * ExampleDebugStatEntry_t definition below) to each ID defined in this file. + * The structures are stored in an array (see the xIPTraceValues[] array in + * DemoIPTrace.c). + * + * The structure associates a function with a data value. See the + * vPerformAction and ulData members of ExampleDebugStatEntry_t respectively. + * The function is used to manipulate the data. At the time of writing two + * functions can be used - these are prvIncrementEventCount() which simply + * increments the data each time it is called, and prvStoreLowest() which + * sets the data to the lowest value of an input parameter ever seen. For + * example, to store the lowest ever number of free network buffer descriptors + * the parameter value is the current number of network buffer descriptors. + * + * The trace macros themselves are defined in this file and just invoke + * vExampleDebugStatUpdate(), passing in an ID value. vExampleDebugStatUpdate() + * then just executes the function associated with that value (prvStoreLowest(), + * prvIncrementEventCount(), etc.) as defined in the xIPTraceValues[] array. + */ + +#ifndef DEMO_IP_TRACE_MACROS_H +#define DEMO_IP_TRACE_MACROS_H + +typedef void ( *vTraceAction_t )( uint32_t *, uint32_t ); + +/* Type that defines each statistic being gathered. */ +typedef struct ExampleDebugStatEntry +{ + uint8_t ucIdentifier; /* Unique identifier for statistic. */ + const char * const pucDescription; /* Text description for the statistic. */ + vTraceAction_t vPerformAction; /* Action to perform when the statistic is updated (increment counter, store minimum value, store maximum value, etc. */ + uint32_t ulData; /* The meaning of this data is dependent on the trace macro ID. */ +} ExampleDebugStatEntry_t; + +/* Unique identifiers used to locate the entry for each trace macro in the +xIPTraceValues[] table defined in DemoIPTrace.c. See the comments at the top of +this file. */ +#define iptraceID_NETWORK_INTERFACE_RECEIVE 0 +#define iptraceID_NETWORK_INTERFACE_TRANSMIT 1 +#define iptraceID_PACKET_DROPPED_TO_GENERATE_ARP 2 +#define iptraceID_NETWORK_BUFFER_OBTAINED 3 +#define iptraceID_NETWORK_BUFFER_OBTAINED_FROM_ISR 4 +#define iptraceID_NETWORK_EVENT_RECEIVED 5 +#define iptraceID_FAILED_TO_OBTAIN_NETWORK_BUFFER 6 +#define iptraceID_ARP_TABLE_ENTRY_EXPIRED 7 +#define iptraceID_FAILED_TO_CREATE_SOCKET 8 +#define iptraceID_RECVFROM_DISCARDING_BYTES 9 +#define iptraceID_ETHERNET_RX_EVENT_LOST 10 +#define iptraceID_STACK_TX_EVENT_LOST 11 +#define ipconfigID_BIND_FAILED 12 +#define iptraceID_RECVFROM_TIMEOUT 13 +#define iptraceID_SENDTO_DATA_TOO_LONG 14 +#define iptraceID_SENDTO_SOCKET_NOT_BOUND 15 +#define iptraceID_NO_BUFFER_FOR_SENDTO 16 +#define iptraceID_WAIT_FOR_TX_DMA_DESCRIPTOR 17 +#define iptraceID_FAILED_TO_NOTIFY_SELECT_GROUP 18 +#define iptraceID_TOTAL_NETWORK_BUFFERS_OBTAINED 19 +#define iptraceID_TOTAL_NETWORK_BUFFERS_RELEASED 20 + +/* It is possible to remove the trace macros using the +configINCLUDE_DEMO_DEBUG_STATS setting in FreeRTOSIPConfig.h. */ +#if configINCLUDE_DEMO_DEBUG_STATS == 1 + + /* The trace macro definitions themselves. Any trace macros left undefined + will default to be empty macros. See the comments at the top of this + file. */ + #define iptraceNETWORK_BUFFER_OBTAINED( pxBufferAddress ) vExampleDebugStatUpdate( iptraceID_NETWORK_BUFFER_OBTAINED, uxQueueMessagesWaiting( ( QueueHandle_t ) xNetworkBufferSemaphore ) ); vExampleDebugStatUpdate( iptraceID_TOTAL_NETWORK_BUFFERS_OBTAINED, 0 ) + #define iptraceNETWORK_BUFFER_RELEASED( pxBufferAddress ) vExampleDebugStatUpdate( iptraceID_TOTAL_NETWORK_BUFFERS_RELEASED, 0 ) + #define iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxBufferAddress ) vExampleDebugStatUpdate( iptraceID_NETWORK_BUFFER_OBTAINED, uxQueueMessagesWaiting( ( QueueHandle_t ) xNetworkBufferSemaphore ) ) + + #define iptraceNETWORK_EVENT_RECEIVED( eEvent ) { \ + uint16_t usSpace; \ + usSpace = ( uint16_t ) uxQueueMessagesWaiting( xNetworkEventQueue ); \ + /* Minus one as an event was removed before the space was queried. */ \ + usSpace = ( ipconfigEVENT_QUEUE_LENGTH - usSpace ) - 1; \ + vExampleDebugStatUpdate( iptraceID_NETWORK_EVENT_RECEIVED, usSpace ); \ + } + + #define iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER() vExampleDebugStatUpdate( iptraceID_FAILED_TO_OBTAIN_NETWORK_BUFFER, 0 ) + #define iptraceARP_TABLE_ENTRY_EXPIRED( ulIPAddress ) vExampleDebugStatUpdate( iptraceID_ARP_TABLE_ENTRY_EXPIRED, 0 ) + #define iptracePACKET_DROPPED_TO_GENERATE_ARP( ulIPAddress ) vExampleDebugStatUpdate( iptraceID_PACKET_DROPPED_TO_GENERATE_ARP, 0 ) + #define iptraceFAILED_TO_CREATE_SOCKET() vExampleDebugStatUpdate( iptraceID_FAILED_TO_CREATE_SOCKET, 0 ) + #define iptraceRECVFROM_DISCARDING_BYTES( xNumberOfBytesDiscarded ) vExampleDebugStatUpdate( iptraceID_RECVFROM_DISCARDING_BYTES, 0 ) + #define iptraceETHERNET_RX_EVENT_LOST() vExampleDebugStatUpdate( iptraceID_ETHERNET_RX_EVENT_LOST, 0 ) + #define iptraceSTACK_TX_EVENT_LOST( xEvent ) vExampleDebugStatUpdate( iptraceID_STACK_TX_EVENT_LOST, 0 ) + #define iptraceBIND_FAILED( xSocket, usPort ) vExampleDebugStatUpdate( ipconfigID_BIND_FAILED, 0 ) + #define iptraceNETWORK_INTERFACE_TRANSMIT() vExampleDebugStatUpdate( iptraceID_NETWORK_INTERFACE_TRANSMIT, 0 ) + #define iptraceRECVFROM_TIMEOUT() vExampleDebugStatUpdate( iptraceID_RECVFROM_TIMEOUT, 0 ) + #define iptraceSENDTO_DATA_TOO_LONG() vExampleDebugStatUpdate( iptraceID_SENDTO_DATA_TOO_LONG, 0 ) + #define iptraceSENDTO_SOCKET_NOT_BOUND() vExampleDebugStatUpdate( iptraceID_SENDTO_SOCKET_NOT_BOUND, 0 ) + #define iptraceNO_BUFFER_FOR_SENDTO() vExampleDebugStatUpdate( iptraceID_NO_BUFFER_FOR_SENDTO, 0 ) + #define iptraceWAITING_FOR_TX_DMA_DESCRIPTOR() vExampleDebugStatUpdate( iptraceID_WAIT_FOR_TX_DMA_DESCRIPTOR, 0 ) + #define iptraceFAILED_TO_NOTIFY_SELECT_GROUP( xSocket ) vExampleDebugStatUpdate( iptraceID_FAILED_TO_NOTIFY_SELECT_GROUP, 0 ) + #define iptraceNETWORK_INTERFACE_RECEIVE() vExampleDebugStatUpdate( iptraceID_NETWORK_INTERFACE_RECEIVE, 0 ) + + /* + * The function that updates a line in the xIPTraceValues table. + */ + void vExampleDebugStatUpdate( uint8_t ucIdentifier, uint32_t ulValue ); + + /* + * Returns the number of entries in the xIPTraceValues table. + */ + BaseType_t xExampleDebugStatEntries( void ); + +#endif /* configINCLUDE_DEMO_DEBUG_STATS == 1 */ + + +#endif /* DEMO_IP_TRACE_MACROS_H */ + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/DefaultWebPages.h b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/DefaultWebPages.h new file mode 100644 index 000000000..43e6a341a --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/DefaultWebPages.h @@ -0,0 +1,2681 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * This file defines some very basic web content that is used as default web + * pages when the HTTP server is created. A FAT file is created in the + * directory set by the configHTTP_ROOT constant (in FreeRTOSConfig.h) from each + * file definition below. The files were converted to C structures using Hex + * Edit (http://www.hexedit.com). + */ + +/* A structure that defines a single file to be copied to the RAM disk. */ +typedef struct FILE_TO_COPY +{ + const char *pcFileName; /* The name of the file. */ + size_t xFileSize; + const uint8_t *pucFileData; /* The C structure that contains the file's data. */ +} xFileToCopy_t; + +static const uint8_t pcFreeRTOS_HTML_Data[] = +{ + 0x3C, 0x21, 0x44, 0x4F, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, 0x48, 0x54, 0x4D, 0x4C, 0x20, 0x50, + 0x55, 0x42, 0x4C, 0x49, 0x43, 0x20, 0x22, 0x2D, 0x2F, 0x2F, 0x57, 0x33, 0x43, 0x2F, 0x2F, 0x44, + 0x54, 0x44, 0x20, 0x48, 0x54, 0x4D, 0x4C, 0x20, 0x34, 0x2E, 0x30, 0x31, 0x20, 0x54, 0x72, 0x61, + 0x6E, 0x73, 0x69, 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x2F, 0x2F, 0x45, 0x4E, 0x22, 0x20, 0x22, + 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x77, 0x33, 0x2E, 0x6F, 0x72, + 0x67, 0x2F, 0x54, 0x52, 0x2F, 0x68, 0x74, 0x6D, 0x6C, 0x34, 0x2F, 0x6C, 0x6F, 0x6F, 0x73, 0x65, + 0x2E, 0x64, 0x74, 0x64, 0x22, 0x3E, 0x0D, 0x0A, 0x3C, 0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x0D, 0x0A, + 0x09, 0x3C, 0x68, 0x65, 0x61, 0x64, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x3C, 0x74, 0x69, 0x74, 0x6C, + 0x65, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x46, 0x72, 0x65, 0x65, 0x52, 0x54, 0x4F, 0x53, 0x2B, + 0x54, 0x43, 0x50, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x46, 0x72, 0x65, 0x65, 0x52, 0x54, 0x4F, 0x53, + 0x2B, 0x46, 0x41, 0x54, 0x20, 0x48, 0x54, 0x54, 0x50, 0x20, 0x57, 0x65, 0x62, 0x20, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x20, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x20, 0x57, 0x65, 0x62, + 0x20, 0x50, 0x61, 0x67, 0x65, 0x0D, 0x0A, 0x09, 0x09, 0x3C, 0x2F, 0x74, 0x69, 0x74, 0x6C, 0x65, + 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x3C, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3E, 0x0D, 0x0A, 0x09, 0x09, + 0x09, 0x48, 0x31, 0x20, 0x7B, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3A, 0x20, 0x23, 0x31, 0x61, 0x33, + 0x30, 0x36, 0x35, 0x3B, 0x20, 0x66, 0x6F, 0x6E, 0x74, 0x2D, 0x73, 0x69, 0x7A, 0x65, 0x3A, 0x32, + 0x37, 0x70, 0x78, 0x3B, 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x2D, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x3A, 0x20, 0x33, 0x30, 0x70, 0x78, 0x3B, 0x7D, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x48, 0x31, 0x20, + 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x20, 0x7B, 0x66, 0x6F, 0x6E, 0x74, 0x2D, 0x73, 0x69, 0x7A, 0x65, + 0x3A, 0x31, 0x36, 0x70, 0x78, 0x3B, 0x7D, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x48, 0x32, 0x20, 0x7B, + 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3A, 0x20, 0x23, 0x31, 0x61, 0x33, 0x30, 0x36, 0x35, 0x3B, 0x20, + 0x66, 0x6F, 0x6E, 0x74, 0x2D, 0x73, 0x69, 0x7A, 0x65, 0x3A, 0x32, 0x32, 0x70, 0x78, 0x3B, 0x7D, + 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x48, 0x33, 0x20, 0x7B, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3A, 0x20, + 0x23, 0x31, 0x61, 0x33, 0x30, 0x36, 0x35, 0x3B, 0x20, 0x66, 0x6F, 0x6E, 0x74, 0x2D, 0x73, 0x69, + 0x7A, 0x65, 0x3A, 0x31, 0x38, 0x70, 0x78, 0x3B, 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x2D, 0x68, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x3A, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x3B, 0x7D, 0x0D, 0x0A, + 0x09, 0x09, 0x09, 0x48, 0x33, 0x20, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x20, 0x7B, 0x63, 0x6F, 0x6C, + 0x6F, 0x72, 0x3A, 0x20, 0x23, 0x31, 0x61, 0x33, 0x30, 0x36, 0x35, 0x3B, 0x20, 0x66, 0x6F, 0x6E, + 0x74, 0x2D, 0x73, 0x69, 0x7A, 0x65, 0x3A, 0x31, 0x35, 0x70, 0x78, 0x3B, 0x7D, 0x0D, 0x0A, 0x09, + 0x09, 0x09, 0x48, 0x34, 0x20, 0x7B, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3A, 0x20, 0x23, 0x31, 0x61, + 0x33, 0x30, 0x36, 0x35, 0x7D, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x54, 0x41, 0x42, 0x4C, 0x45, 0x20, + 0x7B, 0x20, 0x66, 0x6F, 0x6E, 0x74, 0x2D, 0x73, 0x69, 0x7A, 0x65, 0x3A, 0x20, 0x31, 0x34, 0x70, + 0x78, 0x3B, 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x2D, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3A, 0x20, + 0x31, 0x2E, 0x35, 0x65, 0x6D, 0x3B, 0x20, 0x7D, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x54, 0x41, 0x42, + 0x4C, 0x45, 0x2E, 0x74, 0x65, 0x78, 0x74, 0x5F, 0x61, 0x64, 0x20, 0x7B, 0x20, 0x6C, 0x69, 0x6E, + 0x65, 0x2D, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3A, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, + 0x3B, 0x20, 0x7D, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x41, 0x3A, 0x76, 0x69, 0x73, 0x69, 0x74, 0x65, + 0x64, 0x20, 0x7B, 0x74, 0x65, 0x78, 0x74, 0x2D, 0x64, 0x65, 0x63, 0x6F, 0x72, 0x61, 0x74, 0x69, + 0x6F, 0x6E, 0x3A, 0x20, 0x6E, 0x6F, 0x6E, 0x65, 0x3B, 0x20, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3A, + 0x20, 0x23, 0x30, 0x30, 0x30, 0x30, 0x65, 0x65, 0x7D, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x41, 0x3A, + 0x68, 0x6F, 0x76, 0x65, 0x72, 0x20, 0x7B, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2D, 0x64, 0x65, 0x63, + 0x6F, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x6E, 0x6F, 0x6E, 0x65, 0x3B, 0x20, 0x7D, + 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x61, 0x20, 0x7B, 0x74, 0x65, 0x78, 0x74, 0x2D, 0x64, 0x65, 0x63, + 0x6F, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x6E, 0x6F, 0x6E, 0x65, 0x3B, 0x7D, 0x0D, + 0x0A, 0x09, 0x09, 0x09, 0x42, 0x4F, 0x44, 0x59, 0x20, 0x7B, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x20, + 0x20, 0x20, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3A, 0x20, 0x23, 0x32, 0x30, 0x32, 0x30, 0x32, 0x30, + 0x3B, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x20, 0x20, 0x20, 0x66, 0x6F, 0x6E, 0x74, 0x2D, 0x66, 0x61, + 0x6D, 0x69, 0x6C, 0x79, 0x3A, 0x20, 0x61, 0x72, 0x69, 0x61, 0x6C, 0x2C, 0x20, 0x68, 0x65, 0x6C, + 0x76, 0x65, 0x74, 0x69, 0x63, 0x61, 0x2C, 0x20, 0x73, 0x65, 0x72, 0x69, 0x66, 0x3B, 0x0D, 0x0A, + 0x09, 0x09, 0x09, 0x20, 0x20, 0x20, 0x66, 0x6F, 0x6E, 0x74, 0x2D, 0x73, 0x69, 0x7A, 0x65, 0x3A, + 0x20, 0x31, 0x34, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x20, 0x20, 0x20, 0x6C, 0x69, + 0x6E, 0x65, 0x2D, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3A, 0x20, 0x31, 0x2E, 0x35, 0x65, 0x6D, + 0x3B, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x20, 0x20, 0x20, 0x6D, 0x61, 0x72, 0x67, 0x69, 0x6E, 0x2D, + 0x6C, 0x65, 0x66, 0x74, 0x3A, 0x20, 0x30, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x20, + 0x20, 0x20, 0x6D, 0x61, 0x72, 0x67, 0x69, 0x6E, 0x2D, 0x72, 0x69, 0x67, 0x68, 0x74, 0x3A, 0x20, + 0x30, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x20, 0x20, 0x20, 0x6D, 0x61, 0x72, 0x67, + 0x69, 0x6E, 0x2D, 0x74, 0x6F, 0x70, 0x3A, 0x30, 0x70, 0x78, 0x3B, 0x0D, 0x0A, 0x09, 0x09, 0x09, + 0x20, 0x20, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, 0x64, 0x3A, 0x20, 0x77, + 0x68, 0x69, 0x74, 0x65, 0x3B, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x7D, 0x0D, 0x0A, 0x09, 0x09, 0x3C, + 0x2F, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3E, 0x0D, 0x0A, 0x09, 0x3C, 0x2F, 0x68, 0x65, 0x61, 0x64, + 0x3E, 0x0D, 0x0A, 0x09, 0x3C, 0x62, 0x6F, 0x64, 0x79, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x3C, 0x74, + 0x61, 0x62, 0x6C, 0x65, 0x20, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3D, 0x22, 0x68, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x3A, 0x31, 0x30, 0x30, 0x25, 0x3B, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3A, 0x31, + 0x30, 0x30, 0x38, 0x70, 0x78, 0x3B, 0x20, 0x62, 0x61, 0x63, 0x6B, 0x67, 0x72, 0x6F, 0x75, 0x6E, + 0x64, 0x3A, 0x77, 0x68, 0x69, 0x74, 0x65, 0x3B, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x2D, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x3A, 0x73, 0x6F, 0x6C, 0x69, 0x64, 0x20, 0x31, 0x70, 0x78, 0x20, + 0x23, 0x65, 0x36, 0x65, 0x36, 0x65, 0x36, 0x3B, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x2D, + 0x6C, 0x65, 0x66, 0x74, 0x3A, 0x73, 0x6F, 0x6C, 0x69, 0x64, 0x20, 0x31, 0x70, 0x78, 0x20, 0x23, + 0x65, 0x36, 0x65, 0x36, 0x65, 0x36, 0x3B, 0x22, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x70, 0x61, 0x64, + 0x64, 0x69, 0x6E, 0x67, 0x3D, 0x22, 0x35, 0x22, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x70, 0x61, + 0x63, 0x69, 0x6E, 0x67, 0x3D, 0x22, 0x30, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x22, + 0x63, 0x65, 0x6E, 0x74, 0x65, 0x72, 0x22, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x72, + 0x20, 0x76, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x22, 0x74, 0x6F, 0x70, 0x22, 0x3E, 0x0D, 0x0A, + 0x09, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x64, 0x20, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3D, 0x22, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x3A, 0x31, 0x30, 0x30, 0x25, 0x3B, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x3A, 0x31, 0x30, 0x30, 0x70, 0x78, 0x3B, 0x22, 0x3E, 0x20, 0x3C, 0x21, 0x2D, 0x2D, 0x20, + 0x53, 0x70, 0x61, 0x6E, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x6D, + 0x65, 0x6E, 0x75, 0x2C, 0x20, 0x62, 0x6C, 0x61, 0x6E, 0x6B, 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x2C, + 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6D, 0x61, 0x69, 0x6E, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, + 0x74, 0x20, 0x63, 0x6F, 0x6C, 0x75, 0x6D, 0x6E, 0x73, 0x20, 0x6F, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6E, 0x65, 0x78, 0x74, 0x20, 0x72, 0x6F, 0x77, 0x2E, 0x20, 0x2D, 0x2D, 0x3E, 0x0D, 0x0A, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x66, 0x6F, 0x6E, 0x74, 0x20, 0x66, 0x61, 0x63, 0x65, 0x3D, + 0x22, 0x41, 0x72, 0x69, 0x61, 0x6C, 0x2C, 0x20, 0x48, 0x65, 0x6C, 0x76, 0x65, 0x74, 0x69, 0x63, + 0x61, 0x22, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x61, 0x62, 0x6C, + 0x65, 0x20, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3D, 0x22, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3A, 0x31, + 0x30, 0x30, 0x25, 0x3B, 0x22, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x73, 0x70, 0x61, 0x63, 0x69, 0x6E, + 0x67, 0x3D, 0x22, 0x32, 0x22, 0x20, 0x63, 0x65, 0x6C, 0x6C, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, + 0x67, 0x3D, 0x22, 0x30, 0x22, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x3D, 0x22, 0x30, 0x22, + 0x3E, 0x20, 0x3C, 0x21, 0x2D, 0x2D, 0x20, 0x52, 0x6F, 0x77, 0x73, 0x20, 0x66, 0x6F, 0x72, 0x20, + 0x6C, 0x6F, 0x67, 0x6F, 0x73, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x62, 0x61, 0x6E, 0x6E, 0x65, 0x72, + 0x73, 0x2C, 0x20, 0x62, 0x6C, 0x75, 0x65, 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x73, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x20, 0x6D, 0x65, 0x6E, 0x75, 0x2E, 0x20, 0x2D, 0x2D, 0x3E, 0x0D, 0x0A, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x72, 0x20, 0x20, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3D, + 0x22, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x3A, 0x20, 0x30, 0x70, 0x78, 0x20, 0x30, 0x70, + 0x78, 0x20, 0x30, 0x70, 0x78, 0x20, 0x30, 0x70, 0x78, 0x3B, 0x22, 0x3E, 0x20, 0x3C, 0x21, 0x2D, + 0x2D, 0x20, 0x54, 0x6F, 0x70, 0x20, 0x72, 0x6F, 0x77, 0x2C, 0x20, 0x62, 0x61, 0x6E, 0x6E, 0x65, + 0x72, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x6C, 0x6F, 0x67, 0x6F, 0x2E, 0x20, 0x2D, 0x2D, 0x3E, 0x0D, + 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x64, 0x3E, 0x0D, 0x0A, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x77, + 0x69, 0x64, 0x74, 0x68, 0x3D, 0x22, 0x31, 0x30, 0x30, 0x25, 0x22, 0x20, 0x63, 0x65, 0x6C, 0x6C, + 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x3D, 0x22, 0x30, 0x22, 0x20, 0x63, 0x65, 0x6C, 0x6C, + 0x73, 0x70, 0x61, 0x63, 0x69, 0x6E, 0x67, 0x3D, 0x22, 0x35, 0x70, 0x78, 0x22, 0x3E, 0x0D, 0x0A, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x72, 0x3E, 0x0D, 0x0A, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x64, 0x20, 0x73, + 0x74, 0x79, 0x6C, 0x65, 0x3D, 0x22, 0x6C, 0x69, 0x6E, 0x65, 0x2D, 0x68, 0x65, 0x69, 0x67, 0x68, + 0x74, 0x3A, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x3B, 0x22, 0x20, 0x76, 0x61, 0x6C, 0x69, 0x67, + 0x6E, 0x3D, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C, 0x65, 0x22, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3D, 0x22, 0x31, 0x37, 0x34, 0x70, 0x78, 0x22, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x64, 0x69, 0x76, 0x20, 0x73, 0x74, 0x79, 0x6C, + 0x65, 0x3D, 0x22, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x3A, 0x6C, 0x65, 0x66, 0x74, 0x3B, 0x22, 0x3E, + 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, + 0x69, 0x6D, 0x67, 0x20, 0x73, 0x72, 0x63, 0x3D, 0x22, 0x6C, 0x6F, 0x67, 0x6F, 0x2E, 0x6A, 0x70, + 0x67, 0x22, 0x20, 0x61, 0x6C, 0x74, 0x3D, 0x22, 0x46, 0x72, 0x65, 0x65, 0x20, 0x52, 0x54, 0x4F, + 0x53, 0x20, 0x6C, 0x6F, 0x67, 0x6F, 0x22, 0x20, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3D, 0x22, 0x31, + 0x36, 0x34, 0x70, 0x78, 0x22, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x3D, 0x22, 0x30, 0x22, + 0x20, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3D, 0x22, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x3A, + 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x20, 0x35, 0x70, 0x78, 0x3B, 0x22, 0x3E, 0x0D, 0x0A, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x64, 0x69, 0x76, + 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, + 0x74, 0x64, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x3C, 0x74, 0x64, 0x20, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3D, 0x22, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x3A, 0x35, 0x70, 0x78, 0x3B, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x2D, 0x74, 0x6F, 0x70, + 0x3A, 0x73, 0x6F, 0x6C, 0x69, 0x64, 0x20, 0x32, 0x70, 0x78, 0x20, 0x23, 0x65, 0x36, 0x65, 0x36, + 0x65, 0x36, 0x3B, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x2D, 0x6C, 0x65, 0x66, 0x74, 0x3A, + 0x73, 0x6F, 0x6C, 0x69, 0x64, 0x20, 0x32, 0x70, 0x78, 0x20, 0x23, 0x65, 0x36, 0x65, 0x36, 0x65, + 0x36, 0x3B, 0x20, 0x62, 0x6F, 0x72, 0x64, 0x65, 0x72, 0x2D, 0x62, 0x6F, 0x74, 0x74, 0x6F, 0x6D, + 0x3A, 0x73, 0x6F, 0x6C, 0x69, 0x64, 0x20, 0x32, 0x70, 0x78, 0x20, 0x23, 0x65, 0x36, 0x65, 0x36, + 0x65, 0x36, 0x3B, 0x22, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x26, 0x6E, 0x62, 0x73, 0x70, 0x3B, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x64, 0x20, 0x76, 0x61, 0x6C, 0x69, + 0x67, 0x6E, 0x3D, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C, 0x65, 0x22, 0x20, 0x73, 0x74, 0x79, 0x6C, + 0x65, 0x3D, 0x22, 0x6C, 0x69, 0x6E, 0x65, 0x2D, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3A, 0x6E, + 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x3B, 0x22, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x68, 0x33, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, + 0x20, 0x57, 0x65, 0x62, 0x20, 0x50, 0x61, 0x67, 0x65, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x68, 0x33, 0x3E, 0x0D, 0x0A, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x0D, 0x0A, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x64, 0x3E, 0x0D, + 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x74, 0x64, + 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x74, + 0x72, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x74, + 0x61, 0x62, 0x6C, 0x65, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, + 0x2F, 0x74, 0x64, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x74, + 0x72, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x72, 0x20, 0x73, + 0x74, 0x79, 0x6C, 0x65, 0x3D, 0x22, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3A, 0x35, 0x70, 0x78, + 0x3B, 0x22, 0x20, 0x62, 0x67, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3D, 0x22, 0x23, 0x37, 0x30, 0x39, + 0x35, 0x64, 0x33, 0x22, 0x3E, 0x20, 0x3C, 0x21, 0x2D, 0x2D, 0x20, 0x42, 0x6C, 0x61, 0x6E, 0x6B, + 0x20, 0x6C, 0x69, 0x6E, 0x65, 0x2E, 0x20, 0x2D, 0x2D, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x64, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x3C, 0x2F, 0x74, 0x72, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x74, + 0x72, 0x20, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3D, 0x22, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3A, + 0x31, 0x39, 0x70, 0x78, 0x3B, 0x22, 0x20, 0x62, 0x67, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3D, 0x22, + 0x23, 0x62, 0x36, 0x63, 0x66, 0x66, 0x65, 0x22, 0x3E, 0x20, 0x3C, 0x21, 0x2D, 0x2D, 0x20, 0x48, + 0x6F, 0x72, 0x69, 0x7A, 0x6F, 0x6E, 0x74, 0x61, 0x6C, 0x20, 0x6D, 0x65, 0x6E, 0x75, 0x2E, 0x20, + 0x2D, 0x2D, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x64, + 0x20, 0x76, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x22, 0x6D, 0x69, 0x64, 0x64, 0x6C, 0x65, 0x22, + 0x20, 0x62, 0x67, 0x63, 0x6F, 0x6C, 0x6F, 0x72, 0x3D, 0x22, 0x23, 0x62, 0x36, 0x63, 0x66, 0x66, + 0x65, 0x22, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x74, + 0x64, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x74, 0x72, 0x3E, + 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x3E, + 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x66, 0x6F, 0x6E, 0x74, 0x3E, 0x0D, 0x0A, + 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x74, 0x64, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x3C, 0x2F, + 0x74, 0x72, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x72, 0x20, 0x76, 0x61, 0x6C, 0x69, + 0x67, 0x6E, 0x3D, 0x22, 0x74, 0x6F, 0x70, 0x22, 0x3E, 0x20, 0x3C, 0x21, 0x2D, 0x2D, 0x20, 0x4D, + 0x61, 0x69, 0x6E, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x20, 0x72, 0x6F, 0x77, 0x20, + 0x77, 0x69, 0x74, 0x68, 0x20, 0x6D, 0x65, 0x6E, 0x75, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x63, 0x6F, + 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x20, 0x61, 0x72, 0x65, 0x61, 0x20, 0x63, 0x6F, 0x6C, 0x75, 0x6D, + 0x6E, 0x73, 0x2E, 0x20, 0x2D, 0x2D, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x74, 0x64, + 0x20, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3D, 0x22, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6E, 0x67, 0x3A, + 0x20, 0x32, 0x30, 0x70, 0x78, 0x20, 0x32, 0x30, 0x70, 0x78, 0x20, 0x32, 0x30, 0x70, 0x78, 0x20, + 0x32, 0x30, 0x70, 0x78, 0x3B, 0x22, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x64, + 0x69, 0x76, 0x20, 0x73, 0x74, 0x79, 0x6C, 0x65, 0x3D, 0x22, 0x66, 0x6C, 0x6F, 0x61, 0x74, 0x3A, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x3B, 0x22, 0x20, 0x61, 0x6C, 0x69, 0x67, 0x6E, 0x3D, 0x22, 0x63, + 0x65, 0x6E, 0x74, 0x65, 0x72, 0x22, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, + 0x69, 0x6D, 0x67, 0x20, 0x73, 0x72, 0x63, 0x3D, 0x22, 0x66, 0x74, 0x70, 0x2E, 0x70, 0x6E, 0x67, + 0x22, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x73, 0x6D, 0x61, 0x6C, 0x6C, + 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x62, 0x72, 0x3E, 0x0D, 0x0A, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x62, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x46, 0x54, 0x50, 0x27, 0x69, 0x6E, 0x67, 0x20, 0x77, 0x65, 0x62, 0x20, + 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x20, 0x69, 0x6E, 0x74, 0x6F, 0x20, 0x2F, 0x72, 0x61, + 0x6D, 0x2F, 0x77, 0x65, 0x62, 0x73, 0x72, 0x63, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x3C, 0x2F, 0x62, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x73, + 0x6D, 0x61, 0x6C, 0x6C, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x64, 0x69, + 0x76, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x68, 0x31, 0x3E, 0x0D, 0x0A, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x46, 0x72, 0x65, 0x65, 0x52, 0x54, 0x4F, 0x53, 0x2B, 0x54, 0x43, + 0x50, 0x20, 0x57, 0x65, 0x62, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x0D, 0x0A, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x68, 0x31, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x54, + 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6C, 0x74, 0x20, 0x70, 0x61, 0x67, 0x65, 0x20, 0x62, 0x65, 0x69, 0x6E, 0x67, 0x20, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, + 0x52, 0x54, 0x4F, 0x53, 0x2B, 0x54, 0x43, 0x50, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x77, + 0x65, 0x62, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2C, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x66, 0x69, 0x6C, 0x65, 0x73, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6F, + 0x6D, 0x20, 0x61, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 0x69, 0x6D, 0x70, 0x6C, 0x65, 0x6D, 0x65, + 0x6E, 0x74, 0x65, 0x64, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x75, 0x73, 0x69, 0x6E, 0x67, + 0x20, 0x46, 0x72, 0x65, 0x65, 0x52, 0x54, 0x4F, 0x53, 0x2B, 0x46, 0x41, 0x54, 0x2E, 0x0D, 0x0A, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x70, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x54, + 0x68, 0x65, 0x20, 0x48, 0x54, 0x54, 0x50, 0x20, 0x72, 0x6F, 0x6F, 0x74, 0x20, 0x64, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x6F, 0x72, 0x79, 0x20, 0x69, 0x73, 0x20, 0x73, 0x65, 0x74, 0x20, 0x62, 0x79, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6F, 0x6E, 0x66, 0x69, 0x67, 0x48, 0x54, 0x54, 0x50, 0x5F, + 0x52, 0x4F, 0x4F, 0x54, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74, 0x0D, 0x0A, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x69, 0x6E, 0x20, 0x46, 0x72, 0x65, 0x65, 0x52, 0x54, 0x4F, 0x53, 0x43, + 0x6F, 0x6E, 0x66, 0x69, 0x67, 0x2E, 0x68, 0x2E, 0x20, 0x20, 0x54, 0x68, 0x65, 0x73, 0x65, 0x20, + 0x64, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x20, 0x77, 0x65, 0x62, 0x20, 0x70, 0x61, 0x67, 0x65, + 0x73, 0x20, 0x63, 0x61, 0x6E, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6C, 0x61, 0x63, 0x65, + 0x64, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6E, 0x65, 0x77, + 0x20, 0x77, 0x65, 0x62, 0x20, 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x20, 0x62, 0x79, 0x20, + 0x46, 0x54, 0x50, 0x27, 0x69, 0x6E, 0x67, 0x20, 0x66, 0x69, 0x6C, 0x65, 0x73, 0x20, 0x69, 0x6E, + 0x74, 0x6F, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6F, 0x72, + 0x79, 0x2E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x70, 0x3E, 0x0D, 0x0A, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x3C, 0x62, 0x3E, 0x4E, 0x4F, 0x54, 0x45, 0x3A, 0x3C, 0x2F, 0x62, 0x3E, 0x20, + 0x50, 0x65, 0x72, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x6E, 0x63, 0x65, 0x20, 0x77, 0x69, 0x6C, 0x6C, + 0x20, 0x62, 0x65, 0x20, 0x6C, 0x69, 0x6D, 0x69, 0x74, 0x65, 0x64, 0x20, 0x77, 0x68, 0x65, 0x6E, + 0x20, 0x75, 0x73, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x68, 0x65, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x46, 0x72, 0x65, 0x65, 0x52, 0x54, 0x4F, 0x53, 0x20, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, + 0x73, 0x20, 0x70, 0x6F, 0x72, 0x74, 0x2E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x74, + 0x64, 0x3E, 0x0D, 0x0A, 0x09, 0x09, 0x09, 0x3C, 0x2F, 0x74, 0x72, 0x3E, 0x0D, 0x0A, 0x09, 0x09, + 0x3C, 0x2F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x3E, 0x0D, 0x0A, 0x09, 0x3C, 0x2F, 0x62, 0x6F, 0x64, + 0x79, 0x3E, 0x0D, 0x0A, 0x3C, 0x2F, 0x68, 0x74, 0x6D, 0x6C, 0x3E, 0x0D, 0x0A +}; + +static const uint8_t pcLogo_JPG_Data[] = +{ + 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x03, 0x02, 0x02, 0x03, + 0x03, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x05, 0x08, 0x05, 0x05, 0x04, 0x04, 0x05, 0x0A, 0x07, + 0x07, 0x06, 0x08, 0x0C, 0x0A, 0x0C, 0x0C, 0x0B, 0x0A, 0x0B, 0x0B, 0x0D, 0x0E, 0x12, 0x10, 0x0D, + 0x0E, 0x11, 0x0E, 0x0B, 0x0B, 0x10, 0x16, 0x10, 0x11, 0x13, 0x14, 0x15, 0x15, 0x15, 0x0C, 0x0F, + 0x17, 0x18, 0x16, 0x14, 0x18, 0x12, 0x14, 0x15, 0x14, 0xFF, 0xDB, 0x00, 0x43, 0x01, 0x03, 0x04, + 0x04, 0x05, 0x04, 0x05, 0x09, 0x05, 0x05, 0x09, 0x14, 0x0D, 0x0B, 0x0D, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xFF, 0xC0, + 0x00, 0x11, 0x08, 0x00, 0x3E, 0x00, 0xA4, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, + 0x01, 0xFF, 0xC4, 0x00, 0x1F, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, + 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, + 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23, + 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, + 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, + 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, + 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, + 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC4, 0x00, 0x1F, 0x01, 0x00, 0x03, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xFF, 0xC4, 0x00, 0xB5, 0x11, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, + 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, + 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, + 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, + 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, + 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, + 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, + 0xFA, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00, 0xFD, + 0x53, 0xAA, 0x1A, 0xBE, 0xAF, 0x6B, 0xA2, 0x69, 0xB7, 0x37, 0xF7, 0xB2, 0xAD, 0xBD, 0xA5, 0xB2, + 0x19, 0x65, 0x95, 0xF8, 0x0A, 0xA3, 0x92, 0x4D, 0x5E, 0x35, 0xE4, 0xBF, 0x1C, 0xE7, 0x7D, 0x7A, + 0x6F, 0x0E, 0xF8, 0x26, 0xDD, 0x88, 0x97, 0x5D, 0xBC, 0x53, 0x73, 0xB4, 0xF2, 0xB6, 0xB1, 0x10, + 0xF2, 0x13, 0xEC, 0x70, 0x05, 0x73, 0xE2, 0x2A, 0xFB, 0x2A, 0x6E, 0x4B, 0x7E, 0x9E, 0xAF, 0x63, + 0x9F, 0x11, 0x53, 0xD9, 0x53, 0x73, 0x5B, 0xF4, 0xF5, 0x7A, 0x2F, 0xC4, 0xDE, 0x63, 0xAF, 0xF8, + 0xEB, 0x43, 0xB3, 0xD4, 0x34, 0x8D, 0x5C, 0xF8, 0x6A, 0xDA, 0xE9, 0x3C, 0xD8, 0xC3, 0x59, 0xAC, + 0xB3, 0x14, 0x3F, 0x74, 0xB6, 0xE3, 0x85, 0x24, 0x60, 0xE3, 0x1C, 0x67, 0xAD, 0x65, 0x9F, 0x00, + 0xF8, 0xF5, 0x49, 0xDB, 0xF1, 0x22, 0x52, 0x7F, 0xDB, 0xD2, 0xE1, 0x3F, 0xCA, 0xBD, 0x2A, 0xDE, + 0x08, 0xED, 0xED, 0x63, 0x8A, 0x34, 0x08, 0x91, 0xA8, 0x55, 0x51, 0xD0, 0x01, 0xC0, 0xAF, 0xCE, + 0x7F, 0xDB, 0x93, 0xF6, 0xA7, 0xBE, 0xD3, 0x3E, 0x22, 0xF8, 0xDF, 0xE1, 0xFB, 0x7C, 0x44, 0xD5, + 0x7E, 0x17, 0x0D, 0x17, 0x4E, 0xD3, 0xCE, 0x8E, 0x34, 0xC8, 0xC2, 0x4B, 0xAC, 0x5D, 0x5D, 0x3E, + 0x24, 0x96, 0x49, 0x8A, 0x92, 0xB6, 0xF0, 0x29, 0x52, 0x42, 0x15, 0x63, 0x87, 0xE7, 0x8C, 0x56, + 0x6F, 0x0E, 0xA7, 0x67, 0x36, 0xEF, 0xEA, 0xC4, 0xE8, 0x46, 0x7A, 0xC9, 0xBB, 0xFA, 0xB4, 0x7D, + 0x98, 0x3C, 0x15, 0xF1, 0x16, 0x3F, 0xBB, 0xF1, 0x0E, 0x16, 0xC7, 0xFC, 0xF4, 0xD2, 0x10, 0xFF, + 0x00, 0x23, 0x4A, 0x7C, 0x29, 0xF1, 0x34, 0x7D, 0xCF, 0x1C, 0xE9, 0xAD, 0xFE, 0xF6, 0x90, 0x3F, + 0xF8, 0xAA, 0xF1, 0xEF, 0x80, 0x3F, 0x13, 0xFC, 0x43, 0xAF, 0x68, 0xDE, 0x3A, 0xF1, 0x9C, 0x5A, + 0xAE, 0xA5, 0x79, 0xF0, 0xBE, 0xCE, 0xC6, 0xCB, 0x4A, 0xF0, 0x8B, 0x6A, 0xB1, 0x91, 0x2E, 0xA3, + 0x24, 0x51, 0x15, 0x9E, 0xFF, 0x00, 0x73, 0x8F, 0x31, 0x96, 0x59, 0x19, 0x40, 0x2C, 0x4E, 0x76, + 0x16, 0x1D, 0x69, 0xFE, 0x1E, 0xF1, 0xBF, 0x8F, 0xBC, 0x43, 0xA8, 0xA5, 0x8E, 0x9B, 0xAB, 0xDE, + 0x5D, 0x5D, 0xB2, 0x96, 0x11, 0xE5, 0x3A, 0x0E, 0x49, 0xC9, 0x18, 0xAF, 0x0B, 0x1D, 0x8A, 0xC3, + 0xE0, 0x6A, 0xC6, 0x8B, 0x53, 0x94, 0xA5, 0xD1, 0x37, 0xFE, 0x67, 0x0D, 0x65, 0x4A, 0x8C, 0x94, + 0x7D, 0xE6, 0xDF, 0x66, 0xFF, 0x00, 0xCC, 0xF5, 0xDF, 0xF8, 0x47, 0x3E, 0x2A, 0x28, 0xF9, 0x7C, + 0x61, 0xA2, 0xB7, 0xFB, 0xFA, 0x49, 0xFE, 0x8F, 0x49, 0xFD, 0x8B, 0xF1, 0x69, 0x3A, 0x78, 0x97, + 0xC3, 0xB2, 0x7F, 0xBD, 0xA7, 0x48, 0x3F, 0x93, 0xD7, 0x99, 0xEB, 0xBE, 0x30, 0xF8, 0x99, 0xE1, + 0x03, 0x11, 0xD5, 0x6E, 0xEE, 0xAD, 0x55, 0xCE, 0x11, 0xE4, 0x8E, 0x26, 0x46, 0x3E, 0x99, 0x03, + 0x15, 0xE8, 0x5F, 0x06, 0x7E, 0x2A, 0x6A, 0x5E, 0x34, 0xBE, 0xB9, 0xD2, 0xF5, 0x54, 0x8E, 0x4B, + 0x88, 0xA1, 0xF3, 0x92, 0xE2, 0x25, 0xDB, 0xB8, 0x64, 0x02, 0x18, 0x74, 0xCF, 0x23, 0x91, 0xEF, + 0x58, 0xE1, 0xF3, 0x0C, 0x35, 0x7A, 0xEB, 0x0F, 0x2E, 0x78, 0xC9, 0xF7, 0x6F, 0xFC, 0xC9, 0x87, + 0xB3, 0x9C, 0xF9, 0x2F, 0x24, 0xFC, 0xDB, 0xFF, 0x00, 0x32, 0xD7, 0xF6, 0x77, 0xC5, 0xE5, 0xE9, + 0xAC, 0x78, 0x62, 0x4F, 0xAD, 0x9C, 0xA3, 0xFF, 0x00, 0x66, 0xA3, 0xEC, 0xFF, 0x00, 0x17, 0xD0, + 0x71, 0x73, 0xE1, 0x59, 0x3F, 0xED, 0x94, 0xC3, 0xFA, 0xD7, 0x2F, 0xE2, 0xBF, 0x1F, 0xFC, 0x43, + 0xB3, 0xF1, 0x0E, 0xA5, 0xFD, 0x9D, 0x63, 0x73, 0x1E, 0x99, 0x1C, 0xAC, 0xB0, 0xEE, 0xB1, 0x2C, + 0x36, 0x0E, 0x33, 0x9C, 0x77, 0xC1, 0x3F, 0x8D, 0x73, 0x09, 0xF1, 0xFF, 0x00, 0xC6, 0x19, 0x03, + 0xCE, 0xB4, 0x7C, 0xF0, 0x07, 0xD9, 0xB9, 0x3F, 0x91, 0xAC, 0xEA, 0xE6, 0xB8, 0x5A, 0x33, 0x70, + 0x9B, 0xA8, 0xBA, 0x75, 0x26, 0x53, 0xA5, 0x07, 0x67, 0x29, 0xFD, 0xE7, 0xA7, 0x17, 0xF8, 0xC0, + 0x83, 0x02, 0x1F, 0x0A, 0x49, 0xFF, 0x00, 0x02, 0x98, 0x52, 0x0B, 0xDF, 0x8B, 0xF1, 0x9E, 0x74, + 0xBF, 0x0B, 0xC9, 0xF4, 0xB9, 0x98, 0x7F, 0x4A, 0xE1, 0xED, 0xFE, 0x34, 0x78, 0xF9, 0xA7, 0x8A, + 0x13, 0xA6, 0x45, 0xBA, 0x47, 0x08, 0x37, 0x58, 0xC8, 0x06, 0x49, 0xC7, 0xAD, 0x7A, 0xFF, 0x00, + 0x8B, 0xFE, 0x22, 0xE9, 0x7E, 0x04, 0xB1, 0x89, 0xF5, 0x49, 0x8C, 0x97, 0x8E, 0xBF, 0x25, 0xB4, + 0x03, 0x2E, 0xE7, 0xB9, 0x03, 0xB0, 0xCF, 0x73, 0x5D, 0xB8, 0x7C, 0x5D, 0x0A, 0xF0, 0x95, 0x45, + 0x52, 0x71, 0x51, 0xDD, 0xBD, 0x0D, 0xA0, 0xA1, 0x38, 0xB9, 0x2A, 0x92, 0x49, 0x77, 0x7F, 0xF0, + 0x0E, 0x60, 0xEB, 0x5F, 0x17, 0x23, 0x3F, 0xF2, 0x2D, 0xF8, 0x76, 0x41, 0xFE, 0xCD, 0xFC, 0x83, + 0xFF, 0x00, 0x65, 0xA3, 0xFE, 0x12, 0x5F, 0x8B, 0x2B, 0xD7, 0xC1, 0xFA, 0x13, 0xFF, 0x00, 0xBB, + 0xAA, 0x37, 0xFF, 0x00, 0x13, 0x5C, 0x76, 0xA1, 0xFB, 0x49, 0x6A, 0xB3, 0x4E, 0x57, 0x4F, 0xD2, + 0x2D, 0xE2, 0x43, 0xF7, 0x44, 0xCC, 0xD2, 0x39, 0xFC, 0x06, 0x05, 0x57, 0xB7, 0xFD, 0xA3, 0xB5, + 0xF8, 0x25, 0x0B, 0x77, 0xA5, 0xD9, 0x49, 0x8E, 0xAA, 0x03, 0xC6, 0xDF, 0xA9, 0x35, 0xC7, 0x2C, + 0xDB, 0x06, 0x9E, 0x95, 0xE7, 0xEB, 0x6D, 0x3F, 0x23, 0x1F, 0x6B, 0x4F, 0xFE, 0x7E, 0xCB, 0xF0, + 0xFF, 0x00, 0x23, 0xB9, 0xFF, 0x00, 0x84, 0xBB, 0xE2, 0xAA, 0x7D, 0xEF, 0x02, 0xE9, 0x6F, 0xFF, + 0x00, 0x5C, 0xF5, 0x61, 0xFD, 0x56, 0x93, 0xFE, 0x13, 0x9F, 0x89, 0xD1, 0xFD, 0xEF, 0x87, 0x76, + 0xCD, 0xFE, 0xE6, 0xAC, 0x9F, 0xE1, 0x5B, 0x7F, 0x0F, 0xBE, 0x2B, 0xE9, 0x5E, 0x3C, 0x2D, 0x04, + 0x6A, 0xD6, 0x5A, 0x8A, 0x2E, 0xE6, 0xB5, 0x94, 0x83, 0x91, 0xEA, 0xA7, 0xB8, 0xAE, 0x9B, 0xC4, + 0x3E, 0x24, 0xD3, 0x7C, 0x2D, 0xA7, 0x35, 0xEE, 0xA7, 0x72, 0x96, 0xD6, 0xEB, 0xC0, 0x2D, 0xC9, + 0x63, 0xE8, 0x07, 0x52, 0x6B, 0xD9, 0xA6, 0xE3, 0x56, 0x97, 0xB7, 0x86, 0x21, 0xB8, 0xF7, 0xF7, + 0x7F, 0xC8, 0xEA, 0x8D, 0x37, 0x28, 0xF3, 0x2A, 0xCE, 0xDF, 0x2F, 0xF2, 0x3C, 0xF7, 0xFE, 0x16, + 0x1F, 0xC4, 0x75, 0xFB, 0xDF, 0x0D, 0x33, 0xFE, 0xEE, 0xAB, 0x19, 0xFE, 0x94, 0xA3, 0xE2, 0x77, + 0x8E, 0xD4, 0x7C, 0xFF, 0x00, 0x0C, 0x2F, 0x49, 0xFF, 0x00, 0x63, 0x50, 0x88, 0xD6, 0x5E, 0xA7, + 0xFB, 0x4A, 0xE9, 0xF1, 0x4A, 0x56, 0xC7, 0x48, 0xB9, 0xB9, 0x41, 0xD1, 0xE6, 0x91, 0x62, 0x07, + 0xF0, 0xE4, 0xD5, 0x28, 0x7F, 0x69, 0xA5, 0x2F, 0xFB, 0xDD, 0x05, 0xC2, 0xF7, 0xD9, 0x72, 0x09, + 0xFD, 0x54, 0x57, 0x98, 0xF3, 0x4C, 0x24, 0x5D, 0xBE, 0xB4, 0xFE, 0xE5, 0xFF, 0x00, 0xC8, 0x9C, + 0xEE, 0xA4, 0x57, 0xFC, 0xBF, 0x7F, 0x72, 0xFF, 0x00, 0x23, 0x7F, 0xFE, 0x16, 0xC7, 0x8C, 0x57, + 0xFD, 0x67, 0xC2, 0xFD, 0x58, 0x7F, 0xBB, 0x77, 0x11, 0xAD, 0xED, 0x07, 0xE2, 0x79, 0xBC, 0x2A, + 0x35, 0xBF, 0x0F, 0xEA, 0x9E, 0x19, 0x25, 0x82, 0x09, 0x6F, 0xD1, 0x4C, 0x25, 0x89, 0xC0, 0x1E, + 0x62, 0x92, 0x06, 0x4F, 0x1C, 0xE3, 0xAD, 0x6A, 0x78, 0x0F, 0xC6, 0x96, 0xFE, 0x3D, 0xD1, 0x8E, + 0xA3, 0x6F, 0x6B, 0x35, 0xAC, 0x62, 0x46, 0x88, 0xAC, 0xD8, 0xC9, 0x23, 0x19, 0x23, 0x07, 0xA7, + 0x35, 0xC9, 0xFE, 0xD2, 0x97, 0x02, 0xDB, 0xE0, 0xF6, 0xB8, 0x0F, 0xFC, 0xB5, 0x09, 0x17, 0xE6, + 0xE2, 0xBD, 0x55, 0x39, 0x46, 0x8F, 0xD6, 0x23, 0x57, 0x9A, 0x36, 0xBE, 0xCB, 0x5F, 0xC1, 0x1B, + 0x4D, 0xCE, 0x85, 0x29, 0x57, 0xF6, 0x8E, 0x49, 0x2B, 0xEC, 0xBF, 0x44, 0x7A, 0x8A, 0xB0, 0x71, + 0x91, 0xCD, 0x15, 0xE7, 0x3F, 0xB3, 0xBF, 0x88, 0xAF, 0x3C, 0x57, 0xF0, 0x4B, 0xC1, 0xFA, 0xAE, + 0xA0, 0xE6, 0x6B, 0xCB, 0x8B, 0x15, 0x32, 0x48, 0x7A, 0xBE, 0xD2, 0x54, 0x31, 0xF7, 0x21, 0x41, + 0xA2, 0xBD, 0x48, 0xCB, 0x9A, 0x2A, 0x5D, 0xCE, 0xEA, 0x53, 0x55, 0xA9, 0xC6, 0xA2, 0xEA, 0x93, + 0xFB, 0xCF, 0x44, 0x73, 0xC7, 0x35, 0xE4, 0x5E, 0x00, 0xC7, 0x8E, 0x3E, 0x2E, 0x78, 0xA3, 0xC5, + 0x0C, 0x7C, 0xCB, 0x2D, 0x2D, 0x46, 0x8D, 0x60, 0x4F, 0x4C, 0xAF, 0x32, 0xB0, 0xFA, 0xB7, 0x15, + 0xD9, 0x7C, 0x56, 0xF1, 0x6A, 0xF8, 0x27, 0xC0, 0x5A, 0xBE, 0xAB, 0x9C, 0xCD, 0x1C, 0x25, 0x20, + 0x5E, 0xED, 0x2B, 0x7C, 0xA8, 0x07, 0xE2, 0x45, 0x56, 0xF8, 0x3F, 0xE1, 0x26, 0xF0, 0x6F, 0xC3, + 0xED, 0x27, 0x4F, 0x97, 0x9B, 0xB6, 0x8F, 0xCF, 0xB9, 0x6E, 0xED, 0x2B, 0xFC, 0xCD, 0x9F, 0xC4, + 0xE3, 0xF0, 0xAE, 0x3A, 0x9F, 0xBC, 0xAF, 0x0A, 0x7D, 0x17, 0xBC, 0xFF, 0x00, 0x43, 0x96, 0xA3, + 0xF6, 0x95, 0xE3, 0x4F, 0xA4, 0x75, 0x7F, 0x92, 0xFE, 0xBC, 0x8B, 0x1F, 0x16, 0x7E, 0x24, 0x69, + 0xBF, 0x07, 0xFE, 0x19, 0xF8, 0x93, 0xC6, 0x9A, 0xBA, 0xC8, 0xFA, 0x6E, 0x89, 0x63, 0x25, 0xEC, + 0xD1, 0xC5, 0x8D, 0xEE, 0x14, 0x70, 0x8B, 0x9E, 0xEC, 0x70, 0x07, 0xD6, 0xBE, 0x15, 0xF1, 0x17, + 0xED, 0x09, 0xE3, 0x29, 0xB5, 0xBF, 0x16, 0xF8, 0xA7, 0xE2, 0x2E, 0x91, 0xF0, 0xEB, 0x52, 0xD3, + 0xB4, 0x0F, 0x0A, 0x41, 0xAD, 0xE9, 0x5A, 0x25, 0xB5, 0x8F, 0xDB, 0x66, 0xFE, 0xD1, 0xBC, 0x66, + 0x5D, 0x3E, 0xC3, 0xED, 0x4F, 0xCC, 0xB2, 0x1D, 0xA5, 0x98, 0x46, 0xA3, 0xEF, 0x2E, 0x07, 0x3C, + 0xFA, 0xBF, 0xFC, 0x14, 0x2B, 0xF6, 0x91, 0xD1, 0xFE, 0x0F, 0xE8, 0x7E, 0x11, 0xF0, 0xB6, 0xAE, + 0xFA, 0x25, 0xDE, 0x89, 0xE2, 0x7B, 0xF1, 0x6B, 0xE2, 0x3D, 0x37, 0x53, 0x8A, 0x49, 0xE6, 0x3A, + 0x3B, 0x7C, 0x93, 0x4B, 0x0C, 0x68, 0xC0, 0x96, 0x52, 0x41, 0x07, 0x24, 0xF1, 0xC0, 0x35, 0xC7, + 0xFE, 0xCA, 0x5F, 0x04, 0xFF, 0x00, 0x63, 0xAB, 0xEF, 0x88, 0xAB, 0x7F, 0xF0, 0xAA, 0xEA, 0x2F, + 0x15, 0x78, 0x97, 0x4F, 0x43, 0x7F, 0x0C, 0x17, 0x97, 0x77, 0x17, 0x2B, 0x64, 0xA0, 0xA8, 0x12, + 0x08, 0xE4, 0x01, 0x43, 0x02, 0x40, 0x0C, 0xC0, 0xB0, 0xCF, 0x06, 0xBB, 0xB6, 0x47, 0x79, 0xEC, + 0xFF, 0x00, 0x16, 0xBC, 0x55, 0xA8, 0xCD, 0xE0, 0x1F, 0x08, 0x69, 0x9A, 0x95, 0xAC, 0x1A, 0x76, + 0xAD, 0x75, 0x69, 0x15, 0xE6, 0xA1, 0x65, 0x6B, 0x91, 0x14, 0x0F, 0xB0, 0x66, 0x35, 0xCF, 0x38, + 0x0C, 0x5B, 0x1F, 0xEE, 0xD7, 0x11, 0xE0, 0x2F, 0x1C, 0x4D, 0xE0, 0x1D, 0x4A, 0x6B, 0xFB, 0x7B, + 0x08, 0xAF, 0x25, 0x96, 0x3F, 0x28, 0x19, 0x98, 0xA8, 0x41, 0x9C, 0x9C, 0x11, 0xEB, 0xC5, 0x2F, + 0xC4, 0xEF, 0x10, 0xFF, 0x00, 0xC2, 0x4D, 0xE3, 0x7D, 0x4E, 0xED, 0x58, 0xBC, 0x09, 0x27, 0x91, + 0x0F, 0xFB, 0x8B, 0xC7, 0xEA, 0x72, 0x7F, 0x1A, 0xFA, 0x1F, 0xC1, 0xFE, 0x08, 0xB5, 0xB0, 0xF8, + 0x6D, 0x6B, 0xA4, 0xDD, 0xDB, 0x47, 0x2B, 0x4B, 0x6C, 0x5A, 0x70, 0xEA, 0x0E, 0x5D, 0xC1, 0x27, + 0xF2, 0x27, 0xF4, 0xAF, 0xCD, 0x94, 0x2B, 0x66, 0x99, 0x8D, 0x4A, 0xF4, 0x67, 0xCB, 0xC9, 0xB3, + 0xDF, 0x6D, 0x3F, 0xCC, 0xF0, 0xB9, 0x65, 0x88, 0xAF, 0x29, 0x41, 0xDA, 0xC7, 0x85, 0xF8, 0x97, + 0xC7, 0x5A, 0xCF, 0xC5, 0xAD, 0x47, 0x4F, 0xD3, 0x1D, 0x6D, 0x2C, 0xD0, 0xC9, 0x88, 0x60, 0xDE, + 0x55, 0x0B, 0x9E, 0x39, 0x63, 0xD4, 0xF6, 0x1F, 0x5A, 0xF6, 0xDF, 0x85, 0x3F, 0x0C, 0x13, 0xC0, + 0x16, 0xB3, 0xCD, 0x71, 0x32, 0xDC, 0xEA, 0x57, 0x40, 0x09, 0x24, 0x41, 0xF2, 0xA2, 0x8F, 0xE1, + 0x5F, 0xC7, 0xBF, 0x7A, 0xF9, 0x7E, 0xD2, 0x66, 0xD3, 0xB5, 0x18, 0x25, 0x19, 0xDD, 0x6F, 0x3A, + 0xB6, 0x7F, 0xDD, 0x61, 0xFE, 0x15, 0xF6, 0xE5, 0xBB, 0x89, 0x60, 0x8D, 0xFB, 0x32, 0x86, 0xFC, + 0xEB, 0xB3, 0x20, 0x4B, 0x17, 0x5A, 0xA6, 0x23, 0x10, 0xF9, 0xAA, 0x47, 0xAF, 0xFC, 0x03, 0x4C, + 0x15, 0xAA, 0x4A, 0x55, 0x27, 0xAC, 0x91, 0xC9, 0xFC, 0x58, 0xD7, 0x7F, 0xE1, 0x1F, 0xF0, 0x16, + 0xAB, 0x70, 0xAD, 0xB6, 0x59, 0x22, 0xF2, 0x23, 0xFF, 0x00, 0x79, 0xFE, 0x51, 0xFC, 0xF3, 0x5F, + 0x36, 0x7C, 0x33, 0xD1, 0x7F, 0xB7, 0x7C, 0x77, 0xA3, 0x5A, 0x15, 0xDD, 0x18, 0x98, 0x4C, 0xE3, + 0xFD, 0x94, 0xF9, 0xBF, 0xA0, 0x1F, 0x8D, 0x7A, 0x9F, 0xED, 0x29, 0xAE, 0x05, 0xB5, 0xD2, 0x34, + 0x84, 0x3C, 0xBB, 0xB5, 0xCC, 0x80, 0x7A, 0x01, 0xB5, 0x7F, 0x52, 0x7F, 0x2A, 0xC9, 0xFD, 0x9B, + 0x74, 0x5F, 0xB4, 0x6B, 0x9A, 0xA6, 0xA8, 0xC3, 0x22, 0xDE, 0x15, 0x81, 0x09, 0xFE, 0xF3, 0x1C, + 0x9F, 0xD1, 0x47, 0xE7, 0x51, 0x98, 0x3F, 0xAE, 0xE6, 0xF4, 0xB0, 0xEB, 0x68, 0xDB, 0xFC, 0xD8, + 0xAB, 0x7E, 0xFB, 0x15, 0x18, 0x76, 0x3D, 0xF3, 0x51, 0xBC, 0x8B, 0x4B, 0xD3, 0xEE, 0x6E, 0xE6, + 0xF9, 0x62, 0x82, 0x36, 0x91, 0x8F, 0xB0, 0x19, 0x35, 0xF1, 0xA7, 0x88, 0xB5, 0xFB, 0xBF, 0x16, + 0x6B, 0xB7, 0x1A, 0x8D, 0xCB, 0x34, 0x93, 0xDC, 0xBF, 0xC8, 0x9D, 0x76, 0x8C, 0xFC, 0xA8, 0x3D, + 0x87, 0x4A, 0xFA, 0xD3, 0xE2, 0x15, 0x9C, 0xD7, 0xFE, 0x08, 0xD7, 0x2D, 0xED, 0xC1, 0x69, 0xE4, + 0xB4, 0x90, 0x28, 0x1D, 0x49, 0xDB, 0xD2, 0xBE, 0x3E, 0xD3, 0xAE, 0x45, 0x9D, 0xFD, 0xAD, 0xC9, + 0x5D, 0xEB, 0x0C, 0xA9, 0x21, 0x5F, 0x50, 0x08, 0x38, 0xFD, 0x28, 0xE2, 0x6A, 0x92, 0xE7, 0xA5, + 0x45, 0xE9, 0x17, 0xAB, 0xFB, 0xEC, 0x3C, 0xC2, 0x4E, 0xF1, 0x8F, 0x43, 0xEA, 0xEF, 0x86, 0xFF, + 0x00, 0x0E, 0xEC, 0x3C, 0x17, 0xA2, 0x40, 0xA2, 0xDD, 0x1F, 0x51, 0x74, 0x0D, 0x71, 0x72, 0xCA, + 0x0B, 0x16, 0x23, 0x90, 0x0F, 0x60, 0x3A, 0x62, 0xB3, 0x3E, 0x38, 0x78, 0x72, 0xC3, 0x51, 0xF0, + 0x35, 0xFD, 0xEC, 0xB0, 0x20, 0xBB, 0xB3, 0x51, 0x2C, 0x53, 0x00, 0x03, 0x0E, 0x46, 0x46, 0x7D, + 0x08, 0xED, 0x5D, 0xA6, 0x8B, 0xAF, 0xD8, 0x6B, 0x9A, 0x6C, 0x37, 0xB6, 0x57, 0x31, 0xCD, 0x6F, + 0x22, 0x86, 0x0C, 0xAC, 0x38, 0xF6, 0x3E, 0x86, 0xBC, 0x8F, 0xE3, 0xD7, 0xC4, 0x4B, 0x39, 0x74, + 0xB3, 0xE1, 0xDD, 0x3E, 0xE1, 0x6E, 0x27, 0x95, 0xC3, 0x5D, 0x34, 0x44, 0x15, 0x8D, 0x41, 0xC8, + 0x52, 0x7D, 0x49, 0xC7, 0x1E, 0xD5, 0xEF, 0x63, 0x25, 0x85, 0xC2, 0xE5, 0xF2, 0x8E, 0x9C, 0xBC, + 0xB6, 0x5E, 0x6E, 0xDA, 0x1D, 0x95, 0x5D, 0x3A, 0x74, 0x5F, 0x6B, 0x1E, 0x3B, 0xE0, 0xDD, 0x42, + 0x6D, 0x2F, 0xC5, 0x9A, 0x3D, 0xCC, 0x0C, 0x56, 0x54, 0xBA, 0x8C, 0x71, 0xDC, 0x16, 0x00, 0x8F, + 0xC4, 0x13, 0x5E, 0x93, 0xFB, 0x49, 0xC9, 0x74, 0x7C, 0x41, 0xA4, 0xC6, 0xDB, 0x85, 0x88, 0xB7, + 0x66, 0x8F, 0xFB, 0xA6, 0x4D, 0xDF, 0x37, 0xE3, 0x8D, 0xBF, 0x9D, 0x72, 0xBF, 0x07, 0x7C, 0x2D, + 0x2F, 0x89, 0xBC, 0x6F, 0x66, 0xFB, 0x09, 0xB4, 0xB2, 0x61, 0x71, 0x3B, 0xF6, 0x18, 0xFB, 0xA3, + 0xEA, 0x4E, 0x3F, 0x23, 0x5F, 0x4D, 0xEB, 0xBE, 0x1F, 0xD2, 0xFC, 0x53, 0x62, 0xF6, 0x3A, 0x8D, + 0xBC, 0x57, 0x91, 0x03, 0xCA, 0xB7, 0x54, 0x3E, 0xA0, 0xF5, 0x53, 0x5F, 0x35, 0x95, 0x60, 0x6A, + 0xE2, 0xF2, 0xEA, 0xB4, 0xD3, 0xB7, 0x33, 0xD3, 0xE4, 0x79, 0xF8, 0x6A, 0x32, 0xAB, 0x42, 0x51, + 0xDA, 0xE7, 0xCB, 0x9F, 0x0D, 0x75, 0x7F, 0x0E, 0x68, 0xFA, 0xCC, 0xB2, 0x78, 0x92, 0xC3, 0xED, + 0x96, 0xEE, 0x81, 0x62, 0x66, 0x8F, 0xCC, 0x58, 0x9B, 0x3C, 0x92, 0x9D, 0xF3, 0xFA, 0x57, 0xBB, + 0xE9, 0x56, 0x5F, 0x0E, 0x3C, 0x61, 0x1F, 0x97, 0x65, 0x6D, 0xA4, 0x5C, 0xB1, 0x1F, 0xEA, 0xD6, + 0x35, 0x49, 0x07, 0xE1, 0xC1, 0xAE, 0x57, 0xC4, 0x1F, 0xB3, 0x7D, 0x9C, 0xAA, 0xF2, 0x68, 0xFA, + 0x94, 0xB6, 0xCF, 0xFC, 0x30, 0xDD, 0x0D, 0xE9, 0xF4, 0xDC, 0x30, 0x47, 0xEB, 0x5E, 0x1D, 0xA8, + 0xD8, 0xDC, 0xE8, 0x7A, 0xAD, 0xC5, 0xA4, 0xC7, 0xCA, 0xBB, 0xB4, 0x94, 0xC6, 0xC6, 0x36, 0xFB, + 0xAC, 0x0F, 0x50, 0x45, 0x64, 0xAA, 0x62, 0x72, 0x58, 0xAA, 0x78, 0x9A, 0x31, 0x94, 0x5B, 0xDF, + 0x4F, 0xCC, 0x95, 0x2A, 0x98, 0x44, 0xA3, 0x52, 0x09, 0xA3, 0xEC, 0xBF, 0x0E, 0x78, 0x7A, 0xC3, + 0xC3, 0x1A, 0x6A, 0x58, 0x69, 0xD0, 0xF9, 0x16, 0xA8, 0xCC, 0xCA, 0x9B, 0x8B, 0x60, 0xB1, 0xC9, + 0xE4, 0xFB, 0x9A, 0xF2, 0x5F, 0xDA, 0xEE, 0xFC, 0x59, 0xFC, 0x26, 0x95, 0x09, 0xC7, 0x9B, 0x75, + 0x18, 0xFC, 0xB2, 0x7F, 0xA5, 0x75, 0x9F, 0x04, 0x3C, 0x4B, 0x7B, 0xE2, 0x5F, 0x05, 0x47, 0x25, + 0xFC, 0x8D, 0x35, 0xC5, 0xBC, 0xCD, 0x6F, 0xE7, 0x37, 0x57, 0x03, 0x04, 0x13, 0xEF, 0xCE, 0x3F, + 0x0A, 0xF2, 0x8F, 0xDB, 0xB7, 0x53, 0xFB, 0x0F, 0xC3, 0x18, 0x14, 0x1C, 0x36, 0xE9, 0xE5, 0xFF, + 0x00, 0xBE, 0x62, 0x3F, 0xE3, 0x5F, 0x61, 0x5A, 0xB4, 0x2A, 0xE5, 0xDE, 0xD2, 0x9A, 0xB4, 0x64, + 0x95, 0xBE, 0x76, 0x34, 0xCC, 0xEA, 0xA5, 0x97, 0x55, 0x9C, 0x7F, 0x94, 0xF5, 0x0F, 0xD9, 0xCF, + 0x4F, 0x6D, 0x33, 0xE0, 0x37, 0x80, 0x6D, 0xDC, 0x6C, 0x75, 0xD1, 0x6D, 0x49, 0x1E, 0xE6, 0x30, + 0x7F, 0xAD, 0x15, 0xD3, 0x7C, 0x3B, 0xB0, 0x1A, 0x67, 0x80, 0x3C, 0x35, 0x66, 0x3A, 0x5B, 0xE9, + 0x96, 0xD1, 0x7E, 0x51, 0x28, 0xA2, 0xBD, 0x98, 0xA6, 0x92, 0x48, 0xF4, 0xE9, 0x53, 0x50, 0xA7, + 0x18, 0xAE, 0x89, 0x1C, 0x0F, 0xC4, 0xC6, 0x3E, 0x36, 0xF8, 0x9F, 0xE1, 0x1F, 0x07, 0x2F, 0xCF, + 0x69, 0x6A, 0xE7, 0x59, 0xD4, 0x57, 0xB6, 0xC4, 0xE2, 0x25, 0x3F, 0x56, 0xAF, 0x3A, 0xFF, 0x00, + 0x82, 0x86, 0xF8, 0x87, 0xE2, 0x07, 0x87, 0xBE, 0x06, 0x5A, 0x7F, 0xC2, 0xBE, 0xD2, 0x75, 0xFD, + 0x4E, 0xE2, 0xE3, 0x59, 0xB4, 0x5D, 0x52, 0x4F, 0x0C, 0x97, 0x17, 0xF6, 0xF6, 0x2A, 0xC5, 0xE4, + 0x31, 0xF9, 0x7F, 0x3F, 0xCC, 0x55, 0x50, 0x91, 0xD0, 0x39, 0x27, 0x8C, 0xD7, 0x5B, 0xA0, 0xF8, + 0xE3, 0xC3, 0x3E, 0x10, 0xF8, 0xBB, 0xE3, 0xEB, 0x8F, 0x12, 0x6A, 0xF1, 0xD9, 0x6A, 0xF2, 0xDC, + 0x43, 0x04, 0x11, 0xCE, 0x0E, 0x56, 0xD8, 0x44, 0xA5, 0x48, 0xE3, 0xA1, 0x24, 0xFE, 0x55, 0xE8, + 0x51, 0xFC, 0x5E, 0xF0, 0x3E, 0xA0, 0x8D, 0x1A, 0xF8, 0x9B, 0x4D, 0x60, 0xC3, 0x69, 0x0D, 0x38, + 0x19, 0x1E, 0x9C, 0xD7, 0x9B, 0x42, 0xAD, 0x38, 0xCE, 0x72, 0xA9, 0x24, 0xA4, 0xDF, 0x7E, 0x8B, + 0x45, 0xFD, 0x79, 0x9C, 0x38, 0x6A, 0xF4, 0xB9, 0xA7, 0x29, 0x4D, 0x73, 0x37, 0xB5, 0xD6, 0x96, + 0xD1, 0x7F, 0x9F, 0xCC, 0xFC, 0xF1, 0xF0, 0xF7, 0xFC, 0x14, 0x3F, 0x45, 0xF1, 0xB7, 0x89, 0x3C, + 0x4B, 0xA8, 0xF8, 0xE7, 0xE0, 0x77, 0x88, 0x3C, 0x53, 0xE1, 0x0C, 0xC3, 0x69, 0xA0, 0xC1, 0x6D, + 0xE1, 0xB8, 0x6F, 0x67, 0xB6, 0x48, 0x97, 0x6C, 0xC2, 0xE6, 0xE2, 0x46, 0xF9, 0xDF, 0xCC, 0xDD, + 0xF2, 0xAF, 0xDD, 0xE7, 0x3C, 0xD7, 0xD2, 0xBE, 0x05, 0xF8, 0xDD, 0xF0, 0x3F, 0xE1, 0xEF, 0xC0, + 0x8D, 0x4B, 0xE3, 0x95, 0x8F, 0x80, 0x07, 0xC3, 0x8F, 0x0F, 0xDC, 0xC8, 0x34, 0xFB, 0x92, 0xBA, + 0x24, 0x56, 0xB7, 0xF7, 0x38, 0x9B, 0xCB, 0x0A, 0x63, 0x8B, 0x96, 0x1E, 0x63, 0x36, 0x32, 0x7B, + 0x31, 0xE9, 0x5E, 0xEB, 0xE0, 0x4F, 0xF8, 0x57, 0x9E, 0x06, 0xF0, 0xF5, 0xBE, 0x83, 0xE1, 0x26, + 0xD0, 0x34, 0x5D, 0x12, 0x02, 0xED, 0x0E, 0x9F, 0xA6, 0x34, 0x50, 0xC1, 0x19, 0x66, 0x2C, 0xC5, + 0x51, 0x78, 0x19, 0x62, 0x49, 0xF7, 0x26, 0xBA, 0x67, 0x9B, 0x46, 0xD4, 0xE0, 0xF2, 0x5D, 0xEC, + 0x6E, 0xA1, 0x27, 0x3E, 0x5B, 0x14, 0x75, 0xCF, 0xAE, 0x2B, 0xD2, 0x55, 0x20, 0xF6, 0x68, 0xF4, + 0x94, 0xE1, 0x2D, 0x9A, 0x3E, 0x20, 0xB5, 0xFF, 0x00, 0x82, 0x84, 0xFE, 0xC8, 0x53, 0xC9, 0x1C, + 0xAF, 0x79, 0x75, 0x69, 0x20, 0x60, 0xE3, 0x7E, 0x89, 0x77, 0xF2, 0x9C, 0xE7, 0x9D, 0xAA, 0x73, + 0x5E, 0xB3, 0xA6, 0x7F, 0xC1, 0x48, 0x3F, 0x67, 0x2D, 0x4C, 0xAA, 0x27, 0xC4, 0xAB, 0x28, 0x37, + 0x0F, 0xF9, 0x79, 0xB6, 0x9E, 0x20, 0x3E, 0xA5, 0x90, 0x01, 0x5E, 0xE9, 0x7B, 0xF0, 0xE7, 0xC1, + 0xBA, 0xBC, 0x7B, 0x2E, 0xBC, 0x33, 0xA1, 0xDE, 0x27, 0xA4, 0x96, 0x30, 0xB8, 0xFD, 0x56, 0xB9, + 0x7D, 0x6F, 0xF6, 0x60, 0xF8, 0x41, 0xE2, 0x5D, 0xBF, 0xDA, 0xBF, 0x0C, 0xBC, 0x27, 0x7F, 0xB4, + 0xE4, 0x79, 0xFA, 0x3C, 0x0D, 0x83, 0xFF, 0x00, 0x7C, 0xD6, 0x74, 0xE9, 0x52, 0xA7, 0x7F, 0x67, + 0x14, 0xAF, 0xD8, 0x69, 0x45, 0x6C, 0x78, 0x8A, 0xFC, 0x66, 0xFD, 0x94, 0xB5, 0x69, 0x1D, 0xA3, + 0xF8, 0xAB, 0xA1, 0x40, 0xCE, 0x49, 0x25, 0xF5, 0x8F, 0x2F, 0xAF, 0x5F, 0xBF, 0x5E, 0xCF, 0xE1, + 0xDF, 0xDA, 0x6F, 0xE0, 0xE6, 0xB1, 0x6A, 0x91, 0x69, 0x5F, 0x14, 0x3C, 0x27, 0x7C, 0x90, 0x28, + 0x8C, 0x98, 0xF5, 0x98, 0x18, 0x8C, 0x0E, 0xE7, 0x77, 0x5A, 0xE7, 0xEF, 0x3F, 0x61, 0x7F, 0x80, + 0x17, 0xC4, 0x99, 0x7E, 0x12, 0xF8, 0x5D, 0x3F, 0xEB, 0x8D, 0x88, 0x8B, 0xFF, 0x00, 0x41, 0x22, + 0xB9, 0x6D, 0x53, 0xFE, 0x09, 0xA9, 0xFB, 0x39, 0x6A, 0xB1, 0xCA, 0x92, 0x7C, 0x39, 0xB6, 0xB7, + 0x12, 0x02, 0x09, 0xB5, 0xBC, 0xB8, 0x88, 0x8F, 0xA1, 0x59, 0x06, 0x2A, 0x69, 0x61, 0xA8, 0xD0, + 0x6E, 0x54, 0xA0, 0x93, 0x7B, 0xD8, 0x23, 0x08, 0xC3, 0xE1, 0x56, 0x3B, 0x3F, 0x15, 0xE8, 0xDE, + 0x05, 0xF8, 0xA1, 0xAC, 0x7F, 0x6B, 0x47, 0xE3, 0xDD, 0x3D, 0x8F, 0x96, 0xB1, 0x2A, 0xDA, 0xDF, + 0xDB, 0xBA, 0x28, 0x19, 0xE9, 0xCF, 0x72, 0x4D, 0x76, 0x9F, 0x0D, 0xBC, 0x3B, 0xA2, 0xF8, 0x23, + 0x46, 0x92, 0xD2, 0xC7, 0x57, 0x83, 0x50, 0x13, 0x4C, 0x66, 0x69, 0xCC, 0xA9, 0x96, 0x38, 0x00, + 0x0E, 0x0F, 0x6C, 0x57, 0xCD, 0xF7, 0x9F, 0xF0, 0x49, 0x7F, 0xD9, 0xCA, 0xE9, 0x08, 0x8B, 0xC3, + 0x9A, 0xB5, 0x99, 0xFE, 0xF4, 0x3A, 0xD5, 0xC1, 0x23, 0xFE, 0xFA, 0x63, 0x58, 0x37, 0x9F, 0xF0, + 0x48, 0x3F, 0x83, 0x49, 0x1B, 0x2E, 0x8F, 0xAE, 0xF8, 0xC7, 0x41, 0x66, 0xE7, 0x7D, 0x9E, 0xA8, + 0xA4, 0x83, 0xEB, 0xF3, 0x46, 0x45, 0x65, 0x0C, 0x0E, 0x1E, 0x9D, 0x77, 0x88, 0x8C, 0x7D, 0xF7, + 0xD4, 0x85, 0x4A, 0x0A, 0x7C, 0xE9, 0x6A, 0x7D, 0xC6, 0x19, 0x24, 0x4C, 0xA9, 0x0C, 0x31, 0xDB, + 0x9A, 0xF1, 0xEF, 0x1B, 0x7E, 0xCF, 0xB6, 0xDA, 0xD5, 0xE4, 0xD7, 0xDA, 0x25, 0xCA, 0xE9, 0xF3, + 0x4A, 0x4B, 0xBD, 0xBC, 0x8A, 0x4C, 0x45, 0x8F, 0x52, 0x31, 0xCA, 0xFD, 0x39, 0x15, 0xF3, 0x98, + 0xFF, 0x00, 0x82, 0x52, 0x69, 0x76, 0x45, 0x7F, 0xB3, 0x3E, 0x38, 0xFC, 0x4C, 0xB0, 0x0B, 0xF7, + 0x47, 0xF6, 0x92, 0x9C, 0x7F, 0xDF, 0x2A, 0xB5, 0x13, 0x7F, 0xC1, 0x35, 0xFC, 0x7D, 0xA6, 0xDD, + 0x2C, 0xFA, 0x37, 0xED, 0x41, 0xF1, 0x06, 0xDC, 0xA7, 0xDC, 0x5B, 0xAB, 0x89, 0xA5, 0x03, 0xEA, + 0x3C, 0xE0, 0x0F, 0xE5, 0x4F, 0x15, 0x83, 0xA3, 0x8C, 0x87, 0x25, 0x78, 0xDD, 0x05, 0x4A, 0x50, + 0xAA, 0xAD, 0x34, 0x7A, 0xBB, 0x7C, 0x01, 0xF1, 0x95, 0xBB, 0x32, 0xC5, 0xF6, 0x46, 0x56, 0xEA, + 0xC9, 0x74, 0x54, 0x1F, 0xC3, 0x15, 0xA9, 0xA1, 0x7E, 0xCD, 0xDA, 0xB4, 0xF2, 0xA3, 0x6A, 0xBA, + 0x85, 0xBD, 0x9C, 0x39, 0xF9, 0x92, 0xDB, 0x32, 0x39, 0xFC, 0x48, 0x00, 0x7E, 0xB5, 0xE2, 0x71, + 0xFE, 0xC5, 0x3F, 0xB4, 0xF6, 0x92, 0xC5, 0xF4, 0xDF, 0xDA, 0xBA, 0xFE, 0x56, 0x1F, 0x74, 0x5D, + 0x69, 0x8E, 0x41, 0xFA, 0xE6, 0x46, 0xFE, 0x55, 0x0D, 0xD7, 0xEC, 0xDF, 0xFB, 0x6E, 0x69, 0x51, + 0x33, 0x69, 0x9F, 0xB4, 0x66, 0x95, 0x7F, 0x27, 0x64, 0xBB, 0xD3, 0xE3, 0x50, 0x7F, 0x16, 0x81, + 0xFF, 0x00, 0x95, 0x78, 0xD1, 0xE1, 0xEC, 0x14, 0x65, 0x77, 0x77, 0x6E, 0x8D, 0xE8, 0x73, 0x2C, + 0x15, 0x14, 0x7D, 0xBF, 0xE1, 0x6F, 0x08, 0xE9, 0xBE, 0x0D, 0xD2, 0x85, 0x96, 0x99, 0x07, 0x94, + 0x83, 0x97, 0x76, 0x39, 0x79, 0x1B, 0xFB, 0xCC, 0x7B, 0x9A, 0xF0, 0x4F, 0x16, 0xF8, 0x57, 0xC7, + 0xD6, 0xBE, 0x2E, 0xD4, 0xF5, 0x7B, 0x5B, 0x5B, 0xD8, 0xFE, 0xD1, 0x3B, 0x3A, 0xC9, 0x61, 0x36, + 0xE0, 0x54, 0x70, 0xB9, 0x00, 0xE7, 0xA0, 0x1D, 0x45, 0x78, 0xED, 0xB7, 0x83, 0xBF, 0xE0, 0xA0, + 0x7A, 0x0C, 0x22, 0x21, 0xE3, 0x1F, 0x87, 0xDA, 0xFE, 0x06, 0x3C, 0xDB, 0x84, 0x0A, 0xE7, 0xDC, + 0x81, 0x02, 0x0F, 0xCA, 0x99, 0x73, 0xE2, 0x4F, 0xF8, 0x28, 0x2E, 0x8C, 0xBB, 0x47, 0x86, 0x7E, + 0x1E, 0xEB, 0x1B, 0x7F, 0x8E, 0x22, 0x32, 0x7F, 0x39, 0x93, 0xF9, 0x57, 0xA1, 0x8B, 0xCB, 0x69, + 0xE2, 0xA9, 0x46, 0x92, 0x6E, 0x0A, 0x3B, 0x72, 0xE8, 0x6D, 0x56, 0x84, 0x6A, 0x45, 0x46, 0xF6, + 0xB7, 0x63, 0xD5, 0x5F, 0xC4, 0x5F, 0x13, 0x36, 0x98, 0x19, 0xF5, 0xB1, 0x91, 0x8C, 0x7D, 0x94, + 0xE7, 0xF3, 0xDB, 0x55, 0xB4, 0x3F, 0x83, 0xFE, 0x2C, 0xF1, 0x2D, 0xDE, 0xE9, 0x6C, 0x64, 0xB2, + 0x8E, 0x46, 0xDD, 0x25, 0xD5, 0xF1, 0xDA, 0x79, 0xEA, 0x71, 0xF7, 0x89, 0xAF, 0x2D, 0xB5, 0xFD, + 0xA1, 0xBF, 0x6E, 0x7D, 0x2D, 0x76, 0x6A, 0x5F, 0xB3, 0xF6, 0x87, 0xA8, 0x98, 0xF8, 0x79, 0x2D, + 0x2E, 0xE3, 0x40, 0xF8, 0xEE, 0xA0, 0x5C, 0xB7, 0x5A, 0x96, 0x7F, 0xDB, 0x53, 0xF6, 0xA6, 0xD1, + 0xA3, 0x32, 0x6A, 0x3F, 0xB2, 0xAD, 0xDC, 0xCA, 0xBF, 0x7B, 0xEC, 0xB7, 0xD2, 0x12, 0x7E, 0x81, + 0x51, 0xEB, 0xC8, 0xFF, 0x00, 0x57, 0xA1, 0x39, 0x27, 0x5E, 0xB4, 0xA6, 0x97, 0x46, 0x73, 0x7D, + 0x4A, 0x2D, 0xFB, 0xF2, 0x6C, 0xFB, 0x83, 0xC1, 0x9E, 0x15, 0xB6, 0xF0, 0x6F, 0x87, 0xAD, 0x74, + 0xBB, 0x62, 0x59, 0x61, 0x04, 0xB4, 0x8D, 0xD5, 0xDC, 0xF2, 0xCC, 0x7E, 0xA6, 0xBE, 0x68, 0xFD, + 0xBC, 0xE5, 0x37, 0x5A, 0x36, 0x91, 0xA7, 0x02, 0x0B, 0x4D, 0x1C, 0xAA, 0x14, 0xF7, 0x2E, 0xCA, + 0x83, 0xF9, 0xD7, 0xD1, 0xBF, 0x0C, 0x3C, 0x49, 0xAA, 0xF8, 0xCB, 0xE1, 0xD7, 0x86, 0xF5, 0xDD, + 0x73, 0x45, 0x7F, 0x0D, 0xEB, 0x1A, 0x9E, 0x9F, 0x0D, 0xDD, 0xDE, 0x8F, 0x2B, 0x16, 0x7B, 0x29, + 0x1D, 0x03, 0x34, 0x2C, 0x48, 0x04, 0x95, 0x27, 0x07, 0x20, 0x72, 0x3A, 0x57, 0xCC, 0x9F, 0xB6, + 0x43, 0xFF, 0x00, 0x68, 0x7C, 0x46, 0xF0, 0x66, 0x9B, 0xC9, 0x12, 0x5E, 0x69, 0xF1, 0x10, 0x3D, + 0x1E, 0xF2, 0x30, 0x7F, 0x4A, 0xF5, 0x31, 0xD0, 0x8D, 0x2C, 0x34, 0x69, 0x41, 0x69, 0x78, 0xAF, + 0xC4, 0xE4, 0xCE, 0x2D, 0x1C, 0x13, 0x82, 0xEA, 0xD2, 0xFC, 0x51, 0xF5, 0xCD, 0x84, 0x1F, 0x66, + 0xB1, 0xB7, 0x84, 0x0D, 0xA2, 0x38, 0xD5, 0x00, 0xFA, 0x00, 0x28, 0xAB, 0x0A, 0x0E, 0x28, 0xAF, + 0x63, 0x53, 0xDC, 0x4B, 0x43, 0xCE, 0x3E, 0x26, 0xFE, 0xCF, 0xFE, 0x10, 0xF8, 0xB1, 0x73, 0x05, + 0xE6, 0xB7, 0x67, 0x32, 0x6A, 0x50, 0xA7, 0x97, 0x1D, 0xFD, 0x94, 0xED, 0x04, 0xC1, 0x3A, 0xED, + 0x2C, 0xBF, 0x78, 0x67, 0x9C, 0x1C, 0xD7, 0x9A, 0xDD, 0xFE, 0xC3, 0xBE, 0x1A, 0x71, 0x8B, 0x4F, + 0x13, 0xF8, 0x86, 0xD7, 0xEB, 0x3A, 0x49, 0xFF, 0x00, 0xA1, 0x2D, 0x7D, 0x29, 0x49, 0x5C, 0xF5, + 0x30, 0xB4, 0x6A, 0xBB, 0xCE, 0x29, 0xB3, 0xCE, 0xAD, 0x96, 0xE0, 0xEB, 0xC9, 0xCE, 0xA5, 0x24, + 0xDB, 0xEB, 0x63, 0xE5, 0x5B, 0x9F, 0xD8, 0x6B, 0x6E, 0x4D, 0xA7, 0x8F, 0xB5, 0x15, 0x3D, 0x85, + 0xC5, 0x9C, 0x2F, 0xFC, 0x80, 0xAC, 0xB9, 0xFF, 0x00, 0x62, 0xBF, 0x16, 0x5B, 0xE4, 0xD9, 0x78, + 0xF6, 0xD0, 0x9E, 0xDE, 0x76, 0x9E, 0xCB, 0xFF, 0x00, 0xA0, 0xBD, 0x7D, 0x7D, 0x8A, 0x08, 0xAE, + 0x57, 0x96, 0x61, 0x5F, 0xD8, 0x38, 0xDE, 0x47, 0x80, 0x7B, 0x42, 0xDE, 0x8D, 0xFF, 0x00, 0x99, + 0xF1, 0xC1, 0xFD, 0x96, 0x7E, 0x2D, 0xE9, 0xB9, 0x36, 0x7E, 0x2F, 0xD2, 0xA7, 0x23, 0xA6, 0xD9, + 0x2E, 0x21, 0x3F, 0xCC, 0xD4, 0x6D, 0xF0, 0x7F, 0xF6, 0x81, 0xD2, 0x7F, 0xE3, 0xDB, 0x52, 0xB5, + 0xB8, 0x03, 0xFE, 0x79, 0x6B, 0x32, 0xAF, 0xE8, 0xCB, 0x5F, 0x65, 0x81, 0x8A, 0x4D, 0xB5, 0x9F, + 0xF6, 0x5E, 0x1F, 0xA5, 0xD7, 0xCC, 0x8F, 0xEC, 0x3C, 0x32, 0xF8, 0x25, 0x25, 0xE9, 0x26, 0x7C, + 0x66, 0x74, 0xEF, 0xDA, 0x47, 0x4A, 0xFF, 0x00, 0x97, 0x3B, 0xBB, 0x80, 0x3F, 0xE7, 0x86, 0xA7, + 0x14, 0x9F, 0xFA, 0x10, 0x19, 0xA6, 0x37, 0x8F, 0xBF, 0x68, 0x6D, 0x23, 0x99, 0xBC, 0x33, 0xAD, + 0x4A, 0xA3, 0xA9, 0x58, 0x60, 0x97, 0xF9, 0x1A, 0xFB, 0x3F, 0x68, 0xA3, 0x6D, 0x1F, 0xD9, 0x90, + 0x5F, 0x0C, 0xE4, 0xBE, 0x64, 0xBC, 0x9D, 0xAF, 0x83, 0x11, 0x35, 0xF3, 0x3E, 0x31, 0x3F, 0xB4, + 0x57, 0xC6, 0x2D, 0x28, 0xE2, 0xFB, 0xC2, 0x9A, 0xA8, 0xC7, 0x53, 0x26, 0x8A, 0xED, 0xFF, 0x00, + 0xA0, 0x50, 0x9F, 0xB6, 0x77, 0x8C, 0x2C, 0x38, 0xBD, 0xF0, 0xEB, 0x2E, 0x3A, 0xF9, 0xDA, 0x65, + 0xC4, 0x7F, 0xD2, 0xBE, 0xCF, 0xC7, 0xAD, 0x47, 0x25, 0xBC, 0x72, 0x0C, 0x32, 0x2B, 0x7D, 0x54, + 0x1A, 0x9F, 0xA8, 0x55, 0x5F, 0x0D, 0x69, 0x0F, 0xFB, 0x37, 0x17, 0x1F, 0x83, 0x15, 0x2F, 0x9A, + 0x4C, 0xF9, 0x02, 0x0F, 0xDB, 0xC9, 0xA1, 0xFF, 0x00, 0x8F, 0xCD, 0x1E, 0xCD, 0x3D, 0x77, 0x49, + 0x24, 0x5F, 0xFA, 0x12, 0xD6, 0xC5, 0x97, 0xED, 0xE1, 0xA2, 0xCE, 0x07, 0x9B, 0xA5, 0xC2, 0x73, + 0xDE, 0x2B, 0xE5, 0xFE, 0xA2, 0xBE, 0x9A, 0xB8, 0xF0, 0xEE, 0x97, 0x77, 0x9F, 0x3F, 0x4E, 0xB4, + 0x9B, 0xFE, 0xBA, 0x40, 0xA7, 0xF9, 0x8A, 0xC5, 0xBE, 0xF8, 0x57, 0xE0, 0xED, 0x43, 0x3F, 0x69, + 0xF0, 0xB6, 0x91, 0x31, 0x3D, 0x77, 0x59, 0x47, 0xFE, 0x14, 0x7D, 0x57, 0x17, 0x1F, 0x86, 0xBB, + 0xFB, 0x90, 0xBE, 0xA7, 0x99, 0xC7, 0xE1, 0xC4, 0xA7, 0xEB, 0x13, 0xC7, 0x6C, 0xFF, 0x00, 0x6D, + 0x7F, 0x0B, 0xDC, 0x01, 0xE6, 0x69, 0x97, 0x4B, 0xEB, 0xB2, 0x78, 0xDB, 0xFA, 0xD6, 0xDD, 0xA7, + 0xED, 0x75, 0xE0, 0xAB, 0x80, 0x37, 0xC7, 0xA8, 0x45, 0xFF, 0x00, 0x6C, 0x95, 0xBF, 0x91, 0xAE, + 0xA2, 0xFB, 0xF6, 0x6D, 0xF8, 0x63, 0xA8, 0xFF, 0x00, 0xAE, 0xF0, 0x4E, 0x8E, 0x7F, 0xDC, 0xB7, + 0x0B, 0xFC, 0xB1, 0x58, 0x77, 0x5F, 0xB2, 0x07, 0xC2, 0x9B, 0x9C, 0xED, 0xF0, 0xBA, 0x5B, 0x13, + 0xDE, 0xDE, 0xE2, 0x58, 0xF1, 0xF9, 0x35, 0x1E, 0xCB, 0x1F, 0x1D, 0xAA, 0x27, 0xF2, 0x0F, 0x67, + 0x9C, 0x47, 0x6A, 0x90, 0x7F, 0x26, 0x5C, 0xB6, 0xFD, 0xA8, 0x7C, 0x03, 0x70, 0x39, 0xD4, 0x2E, + 0x21, 0xF7, 0x92, 0xD5, 0xFF, 0x00, 0xA0, 0xAD, 0x5B, 0x6F, 0xDA, 0x13, 0xC0, 0x17, 0x58, 0xC7, + 0x88, 0x20, 0x4C, 0xFF, 0x00, 0xCF, 0x45, 0x65, 0xFE, 0x62, 0xB8, 0x5B, 0xAF, 0xD8, 0x93, 0xE1, + 0xBC, 0xA0, 0xF9, 0x2B, 0xAC, 0x59, 0x93, 0xFF, 0x00, 0x3C, 0x75, 0x29, 0x3F, 0xAE, 0x6B, 0x2A, + 0xEB, 0xF6, 0x18, 0xF0, 0xB1, 0xCF, 0xD9, 0x3C, 0x4D, 0xE2, 0x1B, 0x4C, 0xF4, 0x1F, 0x68, 0x49, + 0x31, 0xFF, 0x00, 0x7D, 0x2D, 0x1F, 0xF0, 0xA3, 0x1F, 0xE5, 0x7F, 0x78, 0x73, 0xE7, 0x11, 0xFB, + 0x10, 0x7F, 0x36, 0x7B, 0x25, 0xB7, 0xC6, 0x0F, 0x05, 0xDD, 0xE3, 0xCA, 0xF1, 0x2E, 0x9C, 0x73, + 0xEB, 0x38, 0x1F, 0xCE, 0xB5, 0x6D, 0xFC, 0x6F, 0xE1, 0xFB, 0xBC, 0x79, 0x3A, 0xDE, 0x9F, 0x2E, + 0x7F, 0xBB, 0x72, 0x87, 0xFA, 0xD7, 0xCD, 0xD7, 0x5F, 0xB0, 0xB0, 0x56, 0xCD, 0xA7, 0xC4, 0x0D, + 0x51, 0x71, 0xD1, 0x6E, 0x2D, 0x62, 0x71, 0xFA, 0x01, 0x58, 0xD7, 0x7F, 0xB1, 0x37, 0x89, 0xA1, + 0x24, 0xDA, 0x78, 0xEE, 0xD5, 0xC0, 0x1C, 0x7D, 0xA3, 0x4D, 0xFF, 0x00, 0xE2, 0x5A, 0xA1, 0xD7, + 0xC7, 0xC3, 0x78, 0x47, 0xEF, 0x33, 0xFA, 0xF6, 0x67, 0x0F, 0x8F, 0x0E, 0xBE, 0x52, 0x47, 0xD7, + 0x31, 0xEB, 0x16, 0x53, 0x8F, 0xDD, 0x5E, 0x5B, 0xC9, 0xFE, 0xE4, 0xAA, 0x7F, 0xAD, 0x7C, 0x8B, + 0xF1, 0x82, 0x75, 0xF1, 0x8F, 0xED, 0x81, 0xE0, 0x7F, 0x0F, 0x59, 0x01, 0x79, 0x2C, 0x57, 0x36, + 0xF7, 0xB7, 0x02, 0x33, 0xB8, 0x43, 0x04, 0x00, 0xCA, 0xCE, 0xDE, 0x83, 0x70, 0x45, 0xFA, 0xB0, + 0xAC, 0xA6, 0xFD, 0x8F, 0x7E, 0x23, 0x4D, 0x70, 0xB0, 0x47, 0xE3, 0xCD, 0x22, 0xC6, 0x26, 0xEB, + 0x34, 0x16, 0x52, 0x99, 0x00, 0xF6, 0x1B, 0x80, 0xCF, 0xE3, 0x5F, 0x41, 0x7C, 0x0F, 0xFD, 0x9D, + 0x3C, 0x3D, 0xF0, 0x4E, 0x0B, 0xAB, 0x8B, 0x49, 0xEE, 0x75, 0xAF, 0x11, 0x5F, 0x81, 0xF6, 0xED, + 0x73, 0x51, 0x6D, 0xF7, 0x13, 0x01, 0xD1, 0x07, 0x64, 0x41, 0xD9, 0x47, 0xD4, 0xE4, 0xF3, 0x5A, + 0x45, 0x56, 0xC6, 0x72, 0xFB, 0x58, 0xA8, 0xD9, 0xDF, 0x7B, 0xEC, 0x4C, 0x6A, 0x62, 0x73, 0x37, + 0x1A, 0x75, 0x69, 0x72, 0x46, 0x2D, 0x36, 0xEE, 0x9D, 0xED, 0xAD, 0xB4, 0x3D, 0x58, 0x67, 0x14, + 0x53, 0x82, 0xFB, 0xD1, 0x5E, 0xC1, 0xF5, 0x07, 0xFF, 0xD9 +}; + +static const uint8_t pcFTP_PNG_Data[] = +{ + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x02, 0x07, 0x00, 0x00, 0x02, 0xAB, 0x08, 0x03, 0x00, 0x00, 0x00, 0x52, 0xA1, 0xDE, + 0x9C, 0x00, 0x00, 0x03, 0x00, 0x50, 0x4C, 0x54, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, + 0x3A, 0x3A, 0x36, 0x00, 0x00, 0x36, 0x00, 0x35, 0x33, 0x32, 0x32, 0x00, 0x00, 0x51, 0x00, 0x00, + 0x65, 0x10, 0x2D, 0x71, 0x30, 0x00, 0x51, 0x39, 0x00, 0x66, 0x30, 0x2E, 0x51, 0x2E, 0x30, 0x72, + 0x11, 0x78, 0x10, 0x27, 0x79, 0x2E, 0x30, 0x54, 0x51, 0x36, 0x52, 0x7C, 0x39, 0x66, 0x66, 0x55, + 0x00, 0x00, 0x55, 0x00, 0x2D, 0x55, 0x2E, 0x00, 0x50, 0x2F, 0x2B, 0x66, 0x00, 0x00, 0x66, 0x00, + 0x39, 0x6E, 0x33, 0x00, 0x72, 0x31, 0x2F, 0x55, 0x00, 0x51, 0x4C, 0x31, 0x74, 0x66, 0x00, 0x66, + 0x77, 0x2E, 0x51, 0x70, 0x33, 0x75, 0x56, 0x40, 0x36, 0x5A, 0x75, 0x30, 0x78, 0x55, 0x00, 0x66, + 0x46, 0x38, 0x65, 0x64, 0x25, 0x40, 0x40, 0x40, 0x47, 0x5D, 0x7B, 0x4D, 0x7C, 0x49, 0x55, 0x75, + 0x71, 0x6A, 0x58, 0x50, 0x6C, 0x67, 0x55, 0x6F, 0x6F, 0x72, 0x00, 0x06, 0x8F, 0x01, 0x13, 0xB0, + 0x00, 0x39, 0x8F, 0x14, 0x2E, 0xA4, 0x39, 0x39, 0x8F, 0x26, 0x39, 0xA8, 0x04, 0x1C, 0xD2, 0x00, + 0x54, 0x90, 0x10, 0x54, 0xB6, 0x00, 0x65, 0xB4, 0x32, 0x4E, 0x8C, 0x33, 0x53, 0xAE, 0x37, 0x6A, + 0x8D, 0x30, 0x71, 0xB2, 0x1F, 0x5F, 0xC0, 0x0C, 0x75, 0xD0, 0x0E, 0x70, 0xF3, 0x35, 0x4E, 0xD4, + 0x30, 0x6D, 0xCB, 0x34, 0x7B, 0xE3, 0x50, 0x3F, 0x80, 0x49, 0x36, 0xA8, 0x66, 0x39, 0x8F, 0x66, + 0x3A, 0x90, 0x41, 0x5C, 0x98, 0x45, 0x63, 0x9C, 0x53, 0x72, 0xA9, 0x6C, 0x77, 0x81, 0x62, 0x76, + 0xB4, 0x4A, 0x75, 0xCB, 0x68, 0x7C, 0xDC, 0x0F, 0x96, 0x0E, 0x13, 0xAF, 0x09, 0x0E, 0xB2, 0x21, + 0x34, 0x93, 0x34, 0x25, 0xB6, 0x1B, 0x36, 0xAD, 0x35, 0x3A, 0xAA, 0x46, 0x18, 0xD1, 0x05, 0x14, + 0xCB, 0x2B, 0x1E, 0xEC, 0x08, 0x18, 0xE2, 0x33, 0x25, 0xD3, 0x0E, 0x30, 0xCA, 0x33, 0x28, 0xF4, + 0x06, 0x34, 0xFC, 0x28, 0x2D, 0xC2, 0x44, 0x5A, 0x86, 0x29, 0x4F, 0xAC, 0x39, 0x60, 0xB1, 0x3B, + 0x52, 0x88, 0x4F, 0x5E, 0x97, 0x66, 0x49, 0xB5, 0x46, 0x6D, 0x8D, 0x58, 0x72, 0x92, 0x6E, 0x6A, + 0xAC, 0x4E, 0x6E, 0xB1, 0x68, 0x4F, 0xCC, 0x35, 0x50, 0xEB, 0x06, 0x4B, 0xF4, 0x34, 0x78, 0xD6, + 0x37, 0x4C, 0xC9, 0x49, 0x54, 0xD2, 0x69, 0x52, 0xE6, 0x48, 0x65, 0xC7, 0x54, 0x70, 0xCA, 0x6F, + 0x66, 0xEE, 0x57, 0x74, 0xF0, 0x67, 0x19, 0x87, 0xD3, 0x0C, 0x8F, 0xE5, 0x18, 0xB2, 0xFF, 0x38, + 0x8E, 0xD8, 0x31, 0x8A, 0xF5, 0x3C, 0xAC, 0xEE, 0x48, 0x8C, 0x96, 0x4E, 0x8C, 0xA7, 0x66, 0x8F, + 0x91, 0x67, 0x87, 0xB9, 0x77, 0xB1, 0x89, 0x6A, 0xB1, 0xB4, 0x54, 0x93, 0xCA, 0x50, 0x94, 0xE8, + 0x56, 0xA7, 0xDA, 0x51, 0xA8, 0xED, 0x75, 0x96, 0xC6, 0x6C, 0x97, 0xE3, 0x76, 0xAD, 0xCC, 0x66, + 0xB5, 0xFD, 0x54, 0xC9, 0x82, 0x5D, 0xC2, 0xFF, 0x76, 0xC4, 0xFF, 0x92, 0x00, 0x00, 0x8F, 0x39, + 0x00, 0x8F, 0x39, 0x39, 0xB2, 0x00, 0x00, 0xA3, 0x3A, 0x0F, 0xB2, 0x2D, 0x26, 0x90, 0x3A, 0x66, + 0x96, 0x54, 0x01, 0x98, 0x54, 0x2D, 0x8F, 0x66, 0x00, 0x95, 0x75, 0x2E, 0xAB, 0x55, 0x02, 0xAF, + 0x4D, 0x2C, 0xB5, 0x65, 0x00, 0xB5, 0x71, 0x30, 0x97, 0x54, 0x51, 0x95, 0x58, 0x73, 0x82, 0x65, + 0x55, 0x8A, 0x70, 0x70, 0xA7, 0x58, 0x4F, 0xB6, 0x73, 0x51, 0xB5, 0x68, 0x66, 0xE0, 0x2A, 0x24, + 0xE5, 0x3D, 0x41, 0xDB, 0x58, 0x30, 0xD9, 0x54, 0x47, 0xCC, 0x6F, 0x6E, 0xEA, 0x55, 0x4A, 0xF5, + 0x74, 0x45, 0xE8, 0x71, 0x72, 0x80, 0x52, 0x8F, 0x94, 0x6B, 0x8B, 0xA4, 0x77, 0x94, 0xD5, 0x7D, + 0x83, 0x84, 0xA7, 0x14, 0x8C, 0xB6, 0x3D, 0xB5, 0x8E, 0x38, 0x97, 0x94, 0x51, 0x8A, 0x8E, 0x75, + 0x90, 0xB8, 0x5B, 0x95, 0xB2, 0x71, 0xB3, 0x92, 0x4B, 0xB4, 0x90, 0x71, 0xB6, 0xB3, 0x70, 0x89, + 0xC5, 0x43, 0x83, 0xCB, 0x76, 0x8E, 0xF1, 0x69, 0xB1, 0xD2, 0x5A, 0xAC, 0xC8, 0x78, 0xD5, 0x96, + 0x13, 0xDA, 0x8F, 0x39, 0xD7, 0xAE, 0x11, 0xDD, 0xA9, 0x2D, 0xE9, 0x81, 0x0E, 0xF3, 0x92, 0x31, + 0xE8, 0xB4, 0x06, 0xF2, 0xAA, 0x22, 0xD4, 0x94, 0x51, 0xDA, 0x90, 0x68, 0xCF, 0xB3, 0x4F, 0xD4, + 0xB3, 0x70, 0xF6, 0x8E, 0x58, 0xE7, 0x82, 0x7E, 0xE7, 0xA3, 0x55, 0xFD, 0xB5, 0x66, 0xF8, 0xCD, + 0x05, 0xF1, 0xD0, 0x2F, 0xFB, 0xE3, 0x3D, 0xE0, 0xC8, 0x68, 0x84, 0x84, 0x83, 0x90, 0x99, 0xA6, + 0x8C, 0xB3, 0x8C, 0x98, 0xA7, 0xAF, 0xAB, 0x94, 0x8E, 0xA9, 0x98, 0xA8, 0xA6, 0xA7, 0x95, 0xAF, + 0xB0, 0xB0, 0x83, 0x9C, 0xD2, 0x89, 0xAB, 0xD7, 0x97, 0xBA, 0xE3, 0xAF, 0xB9, 0xC6, 0xA4, 0xBC, + 0xE3, 0x93, 0xD1, 0x8D, 0x90, 0xDA, 0xB5, 0x91, 0xEA, 0x8B, 0xB5, 0xDB, 0x8F, 0xB4, 0xD5, 0x90, + 0xB5, 0xCE, 0xAB, 0xA5, 0xE6, 0x9D, 0xB5, 0xFD, 0xB4, 0x97, 0xD0, 0xC9, 0x8F, 0xDB, 0xFE, 0x92, + 0xD5, 0xFA, 0x99, 0xE1, 0xFF, 0xB6, 0xCF, 0xC8, 0xA6, 0xC9, 0xEE, 0xAA, 0xED, 0xDB, 0xB5, 0xFE, + 0xFE, 0xD3, 0x93, 0x8E, 0xDB, 0xA5, 0x94, 0xCC, 0xB5, 0xAF, 0xE8, 0x8D, 0x8B, 0xE1, 0xAC, 0x9A, + 0xE7, 0xAC, 0xA9, 0xD2, 0xBA, 0xC5, 0xD8, 0xD7, 0x8F, 0xC8, 0xC5, 0xBB, 0xC4, 0xE3, 0x9E, 0xDA, + 0xFE, 0xB6, 0xFE, 0xDA, 0x8F, 0xFB, 0xCE, 0xB4, 0xF0, 0xE4, 0x92, 0xFD, 0xFB, 0xB4, 0xD4, 0xD0, + 0xC8, 0xCF, 0xD8, 0xE9, 0xD3, 0xEB, 0xD5, 0xDA, 0xFE, 0xFE, 0xE4, 0xDD, 0xD8, 0xE3, 0xDF, 0xE0, + 0xEF, 0xED, 0xD9, 0xFE, 0xFE, 0xDB, 0xFE, 0xFE, 0xFE, 0x5A, 0x51, 0xE9, 0x0B, 0x00, 0x00, 0x7B, + 0x8E, 0x49, 0x44, 0x41, 0x54, 0x78, 0xDA, 0xED, 0xBD, 0x09, 0x9C, 0x94, 0xC5, 0x99, 0x3F, 0xFE, + 0xBC, 0x7D, 0xCC, 0x74, 0x0F, 0xC3, 0x7D, 0x0C, 0xE0, 0x70, 0x05, 0x06, 0xC3, 0x31, 0x1C, 0x02, + 0xAE, 0x47, 0xA2, 0x4B, 0x74, 0x25, 0xBA, 0xF1, 0x46, 0xA3, 0xB9, 0x58, 0x25, 0xD9, 0xC4, 0x84, + 0x5C, 0x18, 0x84, 0x8D, 0x8A, 0x82, 0xA8, 0x28, 0x21, 0xD1, 0x48, 0x36, 0xBF, 0xAC, 0x31, 0x59, + 0x4C, 0x5C, 0x5D, 0x45, 0x12, 0x62, 0x76, 0x15, 0x63, 0x42, 0x74, 0xFF, 0x80, 0x61, 0x1C, 0x39, + 0x66, 0x10, 0xC3, 0x30, 0x82, 0x30, 0x30, 0x20, 0x8C, 0x0C, 0xCC, 0xD1, 0x3D, 0xD3, 0xC7, 0xFB, + 0x7F, 0x9E, 0xAA, 0x7A, 0xCF, 0x7E, 0xBB, 0xA7, 0xBB, 0xA7, 0x7B, 0xBA, 0x9B, 0xA9, 0xCF, 0x77, + 0xE6, 0xED, 0x7A, 0xAB, 0xEA, 0x7D, 0xAA, 0xDE, 0xAA, 0xE7, 0x7D, 0xEA, 0x7A, 0xEA, 0x29, 0x25, + 0x00, 0x20, 0xD1, 0xEB, 0x51, 0xE9, 0x01, 0x5F, 0xB7, 0x89, 0x48, 0x14, 0x3A, 0xDE, 0x01, 0x0F, + 0x40, 0xB0, 0xBB, 0x54, 0x24, 0x0A, 0x1F, 0xAE, 0x6E, 0x53, 0x90, 0x38, 0x17, 0x80, 0xF2, 0x00, + 0x60, 0x60, 0xF7, 0x28, 0x84, 0x3D, 0x61, 0xBA, 0x40, 0x18, 0x3C, 0x93, 0xF6, 0x41, 0xB8, 0x72, + 0x1F, 0xE0, 0xCF, 0xA4, 0x7D, 0xE8, 0x98, 0xB4, 0x6F, 0x52, 0x4D, 0x25, 0xEC, 0x9B, 0x44, 0x7F, + 0xA9, 0xD0, 0xEC, 0x77, 0x96, 0xFF, 0xF5, 0x03, 0xFC, 0xB3, 0x85, 0x29, 0x2A, 0x22, 0xFE, 0xA3, + 0x8A, 0xCA, 0x63, 0xC4, 0x89, 0xE3, 0x8A, 0xBA, 0x80, 0xFF, 0xD9, 0x43, 0x66, 0xEE, 0x9C, 0x19, + 0x9F, 0x2A, 0x43, 0x71, 0x07, 0xFE, 0x31, 0x74, 0x11, 0x71, 0xFE, 0x86, 0xF9, 0x80, 0x7F, 0xF1, + 0x82, 0x29, 0x6F, 0xCE, 0xD9, 0x63, 0x99, 0x4F, 0x10, 0xCE, 0x30, 0xA0, 0x99, 0xFF, 0x21, 0x00, + 0xFF, 0xE2, 0xC6, 0x4B, 0x1A, 0x83, 0xF0, 0x9F, 0xF1, 0x01, 0xC0, 0x0A, 0x5B, 0xD0, 0x03, 0xAC, + 0x20, 0x13, 0x95, 0xB7, 0xA8, 0xFB, 0x49, 0x35, 0x61, 0xA0, 0x4B, 0x85, 0xAF, 0x06, 0xA0, 0x12, + 0xF0, 0x02, 0x35, 0x95, 0x35, 0xC1, 0x49, 0x35, 0x35, 0x78, 0x17, 0x46, 0x00, 0xF2, 0x40, 0x4D, + 0x25, 0xFE, 0xA1, 0x07, 0x71, 0x07, 0xBA, 0x12, 0xF2, 0x05, 0x56, 0x3E, 0x03, 0xBA, 0x84, 0x0F, + 0xDD, 0x1A, 0xE1, 0x58, 0x4E, 0x2A, 0xFE, 0xD8, 0xB3, 0x66, 0x2A, 0x3E, 0x0A, 0x11, 0x6E, 0x5B, + 0x2C, 0x64, 0x82, 0x28, 0x44, 0xC1, 0x35, 0x7D, 0x27, 0x5E, 0x01, 0x66, 0xEE, 0x8E, 0xCE, 0xDC, + 0x0D, 0xD3, 0x5D, 0x3B, 0xF1, 0x1F, 0x60, 0xE7, 0xCC, 0x9D, 0x3C, 0x96, 0x03, 0x43, 0x08, 0x0E, + 0xD0, 0xD8, 0x40, 0x77, 0xDA, 0xE3, 0x01, 0xF0, 0xDA, 0x67, 0x6C, 0xB0, 0x61, 0xFE, 0xC6, 0x9B, + 0x80, 0xFD, 0x6D, 0x04, 0xBC, 0xDE, 0x6C, 0xE4, 0x06, 0x73, 0x67, 0xE3, 0x53, 0xCA, 0x3E, 0xCF, + 0xBC, 0x9E, 0x71, 0x87, 0xF2, 0x17, 0xD5, 0xAF, 0xB3, 0x01, 0xE3, 0x82, 0xCC, 0x70, 0x83, 0x12, + 0xF0, 0x05, 0x51, 0x1E, 0xD8, 0xF8, 0xE0, 0x01, 0xF1, 0xEB, 0xC8, 0x08, 0x1E, 0xFC, 0xEE, 0x59, + 0x05, 0x73, 0x60, 0x05, 0x63, 0x0D, 0x87, 0x39, 0x13, 0x54, 0xA2, 0x07, 0x55, 0x78, 0x18, 0xEF, + 0x2A, 0x39, 0xD0, 0x41, 0x7F, 0x14, 0x55, 0xFC, 0x30, 0x38, 0x72, 0x02, 0x55, 0x3F, 0xBB, 0x32, + 0x4E, 0x70, 0x92, 0x06, 0xC0, 0x4A, 0xCA, 0x96, 0x31, 0x2C, 0x45, 0xF6, 0x9F, 0xF0, 0x7B, 0x42, + 0x16, 0xD0, 0x5C, 0x28, 0x0E, 0x66, 0x56, 0xEB, 0x12, 0x61, 0xFA, 0x6E, 0x7E, 0x11, 0xB5, 0x4F, + 0xFC, 0x10, 0x2B, 0x19, 0x4C, 0x9C, 0x00, 0x46, 0xFD, 0x5B, 0x39, 0x01, 0x79, 0x60, 0x03, 0xA6, + 0xC2, 0xB8, 0xCD, 0x75, 0xD3, 0x06, 0xFC, 0x23, 0xAE, 0x40, 0x4E, 0xC0, 0xAB, 0xF2, 0xF2, 0x4D, + 0xE8, 0xC0, 0xAB, 0x43, 0xD6, 0x58, 0xD6, 0x35, 0x67, 0x57, 0xF2, 0x40, 0xE7, 0x01, 0x60, 0xF5, + 0x2F, 0x58, 0x40, 0xE7, 0x84, 0x91, 0xD6, 0xD8, 0x15, 0x75, 0xB6, 0xFB, 0x37, 0x63, 0x62, 0xBC, + 0x89, 0xF2, 0xA0, 0xF6, 0x76, 0x21, 0x0F, 0x08, 0xF7, 0xF0, 0x9F, 0xC7, 0xF1, 0x7F, 0xC5, 0x03, + 0x5C, 0x76, 0xB2, 0xCC, 0xD8, 0xB3, 0x84, 0x2C, 0xC0, 0xB9, 0x80, 0x3E, 0xF1, 0x1A, 0xAA, 0x6F, + 0x0F, 0x7D, 0xED, 0x74, 0x43, 0x3C, 0x81, 0x8D, 0x03, 0xBB, 0xC5, 0x3A, 0xDF, 0xA7, 0xB3, 0x01, + 0x45, 0xA2, 0x26, 0x82, 0x39, 0x0D, 0xCE, 0xB0, 0x33, 0x03, 0x49, 0x01, 0xC6, 0x01, 0xC4, 0x0F, + 0x8C, 0x0D, 0x38, 0x4B, 0x98, 0xD9, 0x81, 0xE4, 0x81, 0xED, 0x73, 0xE2, 0x6C, 0xC0, 0x9B, 0x03, + 0xE1, 0xD2, 0xDA, 0x06, 0x23, 0x1E, 0x55, 0x10, 0xFD, 0xBA, 0xA2, 0xC8, 0x05, 0xBB, 0xAB, 0x49, + 0x18, 0xB8, 0xAA, 0x5D, 0xD3, 0x81, 0x89, 0x83, 0x9D, 0x2E, 0x14, 0x03, 0xC8, 0x0B, 0xE8, 0x9A, + 0x89, 0x5C, 0x60, 0x91, 0x08, 0xAC, 0xF6, 0xE9, 0x1F, 0xAB, 0xBD, 0x03, 0xEF, 0xF1, 0x5F, 0x13, + 0x07, 0x56, 0x36, 0xD8, 0xC0, 0x52, 0xC1, 0xBF, 0x28, 0x71, 0x04, 0xFE, 0xBB, 0x90, 0x17, 0x28, + 0x04, 0xE5, 0xC1, 0xCB, 0x37, 0xA1, 0x4C, 0x50, 0xE0, 0x26, 0x45, 0x45, 0xC1, 0x60, 0xFB, 0xD6, + 0x39, 0x07, 0x0B, 0x09, 0x20, 0x18, 0xC1, 0x49, 0xA0, 0x31, 0x16, 0x40, 0x0E, 0x20, 0x26, 0xC0, + 0x3B, 0x8D, 0x0D, 0x88, 0x2B, 0x0C, 0x81, 0x60, 0xE9, 0xF5, 0xD7, 0xC6, 0xDE, 0x3B, 0xF9, 0x20, + 0x9C, 0xFB, 0x89, 0x0F, 0x91, 0x3F, 0x72, 0x02, 0xD0, 0x9F, 0x95, 0x0D, 0x88, 0x71, 0xF0, 0x1F, + 0xAB, 0xD1, 0x83, 0x95, 0x4E, 0x22, 0xA0, 0x06, 0xBB, 0x04, 0x35, 0x9E, 0x4A, 0xBC, 0xA7, 0x3A, + 0xAE, 0xC4, 0x56, 0x82, 0x33, 0x44, 0x4D, 0x25, 0x0A, 0x89, 0x1A, 0xE4, 0x05, 0x62, 0x10, 0xA0, + 0xA6, 0x81, 0x78, 0x85, 0x9E, 0xE4, 0x7F, 0x18, 0x85, 0xB1, 0xC1, 0x25, 0x3B, 0xB6, 0x70, 0xD2, + 0x58, 0xDB, 0x54, 0xF1, 0x54, 0xEB, 0x9F, 0xDE, 0xB1, 0xE9, 0xD3, 0x6F, 0x6C, 0x22, 0xBF, 0x7E, + 0xE8, 0x47, 0x6C, 0xC1, 0x24, 0x05, 0x83, 0xC2, 0xA5, 0xA8, 0x71, 0x4B, 0x7F, 0xBC, 0x0C, 0xE9, + 0x9F, 0x7E, 0xB4, 0x78, 0xD6, 0xCC, 0xE3, 0xBB, 0xB8, 0x66, 0xD2, 0xB7, 0x4A, 0x12, 0x80, 0xFE, + 0xB0, 0xF6, 0x77, 0xEF, 0xC6, 0xD6, 0x60, 0x77, 0x14, 0x76, 0x4E, 0xDF, 0x39, 0x73, 0xF7, 0x4C, + 0x64, 0x0A, 0xC6, 0x01, 0x16, 0x79, 0x40, 0xF5, 0x8E, 0x15, 0x4E, 0xD5, 0x4E, 0x6C, 0x00, 0xC5, + 0xE8, 0x20, 0x16, 0x20, 0x3F, 0x73, 0xBC, 0x0D, 0xF3, 0xB1, 0xD0, 0xE6, 0xCF, 0x47, 0xC0, 0x86, + 0x8D, 0xD8, 0x28, 0x6C, 0x80, 0x9B, 0xE6, 0x53, 0x93, 0x80, 0x7F, 0x37, 0x63, 0xE5, 0x2B, 0x1B, + 0x01, 0x5E, 0xC6, 0x0C, 0xDD, 0x44, 0x7C, 0x6C, 0xCE, 0x18, 0xBB, 0xC1, 0xAC, 0x63, 0xB6, 0x19, + 0x43, 0xEB, 0xE2, 0xC1, 0x96, 0x7D, 0xC0, 0xDA, 0xE7, 0x55, 0x8F, 0xF5, 0xAE, 0x37, 0x0F, 0x80, + 0x0C, 0x91, 0xB8, 0x59, 0xF0, 0xFB, 0x05, 0x12, 0x45, 0x32, 0xF8, 0x00, 0xE5, 0xC5, 0xE3, 0x8F, + 0x23, 0xC8, 0xDD, 0x97, 0x38, 0x60, 0xCA, 0xD9, 0x8F, 0x3D, 0x30, 0x3B, 0x10, 0x40, 0xBC, 0x36, + 0xF1, 0x20, 0x5E, 0x8F, 0x50, 0xD0, 0x27, 0xD0, 0xD5, 0xF2, 0x21, 0x74, 0x1C, 0x0C, 0xB4, 0x04, + 0x02, 0x2F, 0xE0, 0x04, 0x04, 0xBA, 0x02, 0x3B, 0x1A, 0xC2, 0x58, 0xC5, 0x67, 0xDF, 0xFE, 0x87, + 0x1A, 0xCF, 0xE5, 0x81, 0x1D, 0x81, 0x2D, 0xC4, 0x17, 0xA1, 0x83, 0x3B, 0x02, 0x3B, 0xFE, 0x08, + 0x93, 0x2E, 0x09, 0xEC, 0xD8, 0xF1, 0x02, 0xD4, 0x5C, 0x82, 0x77, 0xFF, 0xC1, 0xD8, 0x83, 0x18, + 0x00, 0xFF, 0xC8, 0x7F, 0xC7, 0xDB, 0xFF, 0xBC, 0xE3, 0x55, 0xB7, 0x96, 0x83, 0xB3, 0x57, 0xEF, + 0x78, 0x03, 0xFD, 0xB6, 0x5C, 0xBA, 0xE3, 0xBF, 0xB9, 0x07, 0xD6, 0x3F, 0x07, 0xE3, 0x10, 0x2D, + 0x1A, 0xAB, 0x6D, 0xF6, 0x11, 0x89, 0x5B, 0x56, 0xB0, 0xC4, 0x08, 0x4C, 0x4E, 0xE8, 0x72, 0x80, + 0x97, 0xAB, 0xF5, 0x4D, 0xA3, 0xBB, 0xA7, 0xBB, 0x88, 0x0D, 0xF0, 0xFD, 0xA6, 0xCF, 0x8A, 0xC2, + 0x74, 0x0E, 0xEC, 0x25, 0x20, 0x13, 0x44, 0x51, 0x12, 0xEC, 0x9C, 0x89, 0x2C, 0x01, 0x3B, 0x45, + 0x4F, 0x41, 0x80, 0x33, 0x01, 0x3A, 0xC4, 0x15, 0x85, 0x03, 0xFD, 0x91, 0x54, 0xB0, 0xC4, 0xDB, + 0x80, 0x54, 0x91, 0x03, 0x36, 0x6C, 0x9C, 0x3F, 0x1F, 0x25, 0x42, 0x94, 0x38, 0x61, 0x23, 0x7A, + 0x61, 0xDF, 0x40, 0xBD, 0x49, 0x05, 0x6C, 0x12, 0x54, 0xFC, 0x7B, 0x99, 0xB1, 0xA7, 0x39, 0x6B, + 0x94, 0x4F, 0xAA, 0x72, 0xDE, 0xAF, 0xE1, 0x37, 0x7A, 0x88, 0x19, 0x58, 0xDD, 0x54, 0xEF, 0x4C, + 0x06, 0xD0, 0xBD, 0xD6, 0x2C, 0xB0, 0x9B, 0x94, 0xC0, 0x79, 0xC2, 0xCC, 0x19, 0x06, 0x1F, 0x7C, + 0x09, 0xFE, 0x53, 0x77, 0x63, 0x93, 0x50, 0xF1, 0xE1, 0x3B, 0x5E, 0xE8, 0x0F, 0xEF, 0x22, 0x1F, + 0x1D, 0x81, 0x3A, 0x38, 0xE9, 0xF7, 0x37, 0x0C, 0xF9, 0x31, 0x85, 0xB5, 0xFB, 0xA7, 0x37, 0x0C, + 0x43, 0x57, 0x60, 0x8C, 0xDF, 0x7F, 0x1B, 0xD4, 0x84, 0x5D, 0xED, 0xFE, 0x69, 0x0D, 0x83, 0x7F, + 0xFC, 0xC9, 0x83, 0xDB, 0xBC, 0x01, 0xF0, 0x2C, 0x5C, 0xD3, 0xD6, 0xF7, 0xE1, 0x3E, 0x7F, 0xAC, + 0x44, 0xBE, 0x68, 0xF7, 0xCF, 0x6C, 0x18, 0xF6, 0x8C, 0x67, 0x4D, 0xDB, 0xDC, 0x86, 0xEB, 0xBF, + 0x37, 0x93, 0x7E, 0x66, 0x7C, 0x8F, 0x49, 0x02, 0x2E, 0x0E, 0x00, 0xDA, 0x2E, 0xBC, 0xF0, 0xA2, + 0xFF, 0xB9, 0xF0, 0x6A, 0x23, 0x33, 0xAF, 0x5E, 0x78, 0xE1, 0x3F, 0x1C, 0x87, 0xD6, 0x57, 0x2F, + 0xFC, 0x3C, 0xBF, 0x47, 0xC9, 0x40, 0xC2, 0x80, 0x84, 0x84, 0x49, 0x1E, 0xF0, 0x56, 0xC1, 0xF2, + 0x3D, 0x09, 0x11, 0x8A, 0xC2, 0x80, 0x9C, 0x5A, 0xEB, 0xC0, 0x83, 0xF4, 0x77, 0x9A, 0xE9, 0x22, + 0x69, 0xB0, 0x13, 0x2B, 0x1A, 0x5B, 0x06, 0xE4, 0x08, 0xEC, 0x21, 0xEC, 0x16, 0x98, 0x4E, 0xBD, + 0x02, 0x94, 0x0C, 0xC8, 0x0A, 0xAC, 0x61, 0xB0, 0xF6, 0x0F, 0xF0, 0xAB, 0x67, 0x6D, 0x83, 0xD6, + 0x4D, 0x34, 0x09, 0x04, 0x13, 0xA8, 0x2F, 0x80, 0xFF, 0x51, 0x98, 0x1F, 0xDD, 0x80, 0x2D, 0x02, + 0x96, 0xEC, 0x4D, 0xD8, 0x52, 0xB8, 0xB0, 0x51, 0xA0, 0x7C, 0x6C, 0x44, 0x39, 0x80, 0x22, 0x41, + 0x55, 0x90, 0x23, 0x18, 0x13, 0xDB, 0xF2, 0x8F, 0x7F, 0xBC, 0xFB, 0x4B, 0x8C, 0x2C, 0x1A, 0x04, + 0x6B, 0xA3, 0x00, 0x42, 0x1E, 0xB0, 0x8F, 0x9F, 0xB1, 0x84, 0xE0, 0x8B, 0x2E, 0xC4, 0x01, 0x00, + 0xFB, 0x94, 0x03, 0xE6, 0x89, 0xE3, 0x00, 0x20, 0x0B, 0xF8, 0xF1, 0x47, 0xF7, 0x61, 0x7C, 0x20, + 0xF8, 0xEE, 0x5F, 0xEE, 0xB9, 0x87, 0x01, 0xE0, 0x0C, 0xA8, 0x75, 0xE3, 0x2E, 0x05, 0xCE, 0x69, + 0x17, 0x8C, 0x6A, 0x7B, 0x70, 0xFF, 0x85, 0x00, 0xCF, 0x42, 0x09, 0xDE, 0xED, 0x9F, 0x02, 0xFB, + 0x9F, 0x25, 0xE1, 0x81, 0x94, 0xB0, 0x7D, 0xF0, 0xC0, 0xFB, 0x53, 0xE0, 0x20, 0x7A, 0xBC, 0x5F, + 0xF1, 0x3D, 0x24, 0x46, 0x1D, 0x87, 0x59, 0x9D, 0xB0, 0x1D, 0xE5, 0x81, 0x77, 0x4A, 0xE5, 0xA1, + 0x67, 0xA1, 0xCF, 0x3F, 0x79, 0x83, 0xBB, 0x9E, 0x86, 0x79, 0xF8, 0xD3, 0xF6, 0x34, 0x5C, 0x09, + 0xFB, 0x84, 0x34, 0xA8, 0x01, 0x2E, 0x06, 0x44, 0xA3, 0xF0, 0x69, 0x92, 0x0D, 0x7D, 0xF1, 0x9B, + 0xBF, 0x7E, 0x78, 0xDB, 0xB5, 0xD8, 0x28, 0xF0, 0x0C, 0xF9, 0x5E, 0x7D, 0xE3, 0x8D, 0x37, 0x9E, + 0xE7, 0xDD, 0x45, 0x53, 0x17, 0x41, 0x48, 0x50, 0xFD, 0x16, 0x84, 0x38, 0xA0, 0xBA, 0x37, 0xF5, + 0x0B, 0x58, 0x71, 0x9B, 0xE2, 0x61, 0xF5, 0xEF, 0x44, 0x06, 0xA0, 0x5E, 0x02, 0x8A, 0x82, 0x59, + 0x51, 0x4D, 0x1E, 0xCC, 0x44, 0x9E, 0xA0, 0xDE, 0xC1, 0xCC, 0x99, 0x3B, 0x5D, 0x28, 0x09, 0x50, + 0x22, 0xA0, 0x48, 0x30, 0x1E, 0xC3, 0xDA, 0xC6, 0xAE, 0xA1, 0x68, 0x13, 0x18, 0x23, 0xE8, 0xE2, + 0xC0, 0xD2, 0x2E, 0x60, 0x87, 0x00, 0xEB, 0x1D, 0x5B, 0x05, 0x6C, 0x1F, 0x36, 0x44, 0xE7, 0x6F, + 0xB8, 0x89, 0x04, 0xC3, 0x4D, 0xD8, 0x2D, 0xC0, 0x76, 0x41, 0x85, 0x9B, 0xB1, 0x49, 0x78, 0x19, + 0x45, 0x03, 0x7D, 0xF6, 0x8C, 0x89, 0x2D, 0xF2, 0x80, 0xBC, 0x88, 0x8D, 0x89, 0x75, 0x91, 0x0B, + 0x38, 0x1F, 0xC7, 0x34, 0x0A, 0xC0, 0xFA, 0x04, 0xCD, 0xF4, 0xCF, 0xFE, 0xD0, 0x8F, 0x5D, 0xD2, + 0x10, 0x08, 0xC8, 0x08, 0x16, 0x36, 0xE0, 0x7C, 0xA0, 0x40, 0x24, 0x62, 0x8E, 0x15, 0x59, 0x21, + 0xF2, 0xC0, 0x38, 0xED, 0xBF, 0xE1, 0x8D, 0x26, 0xFC, 0x99, 0xB2, 0x04, 0xDA, 0x79, 0x30, 0xBA, + 0x8E, 0xE1, 0xCF, 0x87, 0x81, 0xE3, 0x40, 0x2D, 0x7C, 0xA5, 0xA7, 0x12, 0x3D, 0x70, 0x14, 0x41, + 0xD2, 0xF6, 0xCD, 0x86, 0x3E, 0x7F, 0x5D, 0xF1, 0xD1, 0x97, 0x48, 0x1E, 0x40, 0xCD, 0x24, 0x16, + 0x31, 0x52, 0xC1, 0x1F, 0xC3, 0xAE, 0xAB, 0x9B, 0x3A, 0x0F, 0xF8, 0x04, 0xFD, 0x45, 0xA0, 0xCF, + 0x0E, 0xAD, 0x51, 0xF0, 0xAD, 0x6E, 0xBA, 0xF0, 0x6E, 0xD7, 0x8B, 0x67, 0xFB, 0x7D, 0xFA, 0x87, + 0xF0, 0x7B, 0x23, 0x1F, 0x45, 0x97, 0x5E, 0xF9, 0x0F, 0x0D, 0x43, 0x17, 0xF2, 0xF6, 0x41, 0xF8, + 0x09, 0x09, 0x6A, 0xED, 0xB4, 0x70, 0x69, 0xCA, 0xDB, 0x02, 0xAD, 0xCF, 0x1D, 0xD3, 0x3F, 0xE0, + 0x5D, 0x1E, 0xFC, 0xE2, 0x67, 0xE2, 0x37, 0x8F, 0x5D, 0xC4, 0xEA, 0x59, 0x5C, 0x1A, 0x44, 0x61, + 0xF7, 0x4C, 0x1C, 0x49, 0x52, 0x47, 0x01, 0x90, 0x1F, 0x30, 0x92, 0xA5, 0x9B, 0x68, 0xEE, 0x1E, + 0xF0, 0xB1, 0x82, 0x21, 0x0E, 0x2C, 0x12, 0x61, 0x03, 0x0A, 0x01, 0x6C, 0x0B, 0x36, 0x20, 0x0B, + 0x20, 0x27, 0xB8, 0x90, 0x25, 0x6E, 0xDA, 0x80, 0xC2, 0x80, 0x46, 0x8E, 0x1B, 0xB1, 0x49, 0xA0, + 0x9E, 0x01, 0x0A, 0x04, 0x78, 0x59, 0xF4, 0x03, 0xB4, 0xC7, 0x8C, 0xEE, 0x01, 0xEB, 0x19, 0x30, + 0x2E, 0xD0, 0xDF, 0xCA, 0x0C, 0x26, 0x11, 0x48, 0x0A, 0x70, 0x49, 0x80, 0x77, 0x4C, 0x38, 0xF0, + 0xBF, 0x54, 0x81, 0x3C, 0x60, 0x59, 0x59, 0x12, 0xED, 0x82, 0xDB, 0x8D, 0x8C, 0xF0, 0xE8, 0xE3, + 0x8F, 0x3E, 0x7E, 0x1A, 0x7F, 0x00, 0x96, 0x03, 0xCF, 0xC4, 0x19, 0xBC, 0x5E, 0x50, 0xDE, 0xF6, + 0x2D, 0x74, 0x4E, 0xD9, 0xEE, 0x6D, 0x7B, 0x98, 0xC5, 0x9D, 0x49, 0xAE, 0xFD, 0xE3, 0xB0, 0x79, + 0xE8, 0xF3, 0x02, 0xEB, 0x2B, 0x56, 0xBE, 0xE9, 0x6D, 0xFB, 0x6F, 0x31, 0x84, 0xF0, 0x97, 0x45, + 0x1B, 0x60, 0xD8, 0x6F, 0x6B, 0x2A, 0xB1, 0x6F, 0x38, 0x87, 0xFC, 0xD1, 0x73, 0x1F, 0x60, 0xA5, + 0x03, 0xC9, 0x0A, 0xFC, 0xA9, 0xBC, 0x04, 0xBF, 0xFC, 0xEF, 0xA1, 0x9F, 0x9B, 0xDA, 0x05, 0xD1, + 0x28, 0xCC, 0xF5, 0x0E, 0xDE, 0xB1, 0x16, 0x57, 0x3A, 0x5A, 0x96, 0xC0, 0x89, 0x27, 0x4D, 0xB9, + 0xBB, 0xFA, 0x8D, 0xBF, 0x95, 0xD3, 0x2F, 0xB5, 0x0F, 0xC2, 0x8B, 0x49, 0x50, 0x73, 0xFF, 0x00, + 0xCC, 0xD5, 0x4D, 0x3C, 0x10, 0xA7, 0x7F, 0x20, 0x7A, 0xBD, 0xBB, 0xA3, 0x51, 0xF6, 0xE7, 0x9A, + 0xEE, 0xAA, 0xE6, 0xDD, 0x03, 0xEC, 0x31, 0xEE, 0xC4, 0x2E, 0x22, 0xF2, 0x02, 0x76, 0x11, 0x90, + 0x05, 0x76, 0xEA, 0x33, 0x09, 0x02, 0xAC, 0xF6, 0xD9, 0xA8, 0x11, 0xDB, 0x84, 0x0E, 0xF6, 0xEB, + 0x20, 0x0F, 0x18, 0x75, 0xD6, 0x45, 0x98, 0xBF, 0x61, 0x03, 0x8D, 0x0E, 0xB0, 0x7B, 0x80, 0xC3, + 0x05, 0x1A, 0x36, 0xDE, 0x74, 0xB3, 0x8A, 0xBD, 0xC4, 0x97, 0x91, 0x05, 0xB0, 0x83, 0x70, 0x33, + 0x6F, 0xB2, 0xEC, 0xFD, 0x1B, 0xAD, 0x7F, 0xC0, 0x5A, 0x05, 0xF1, 0x32, 0xD6, 0x17, 0x60, 0x4D, + 0x00, 0x93, 0x06, 0xBC, 0x97, 0xC0, 0xFB, 0x09, 0x69, 0x89, 0x03, 0xE0, 0xED, 0x82, 0xE9, 0x5E, + 0xB4, 0x0B, 0x91, 0xC8, 0x9D, 0x10, 0x74, 0x47, 0xDC, 0xDF, 0x19, 0x08, 0x8F, 0xE2, 0x0F, 0xCE, + 0x1F, 0xB0, 0xCC, 0xF4, 0xC7, 0xEB, 0x0B, 0xF0, 0x3C, 0x8A, 0x83, 0x0B, 0xDE, 0xF1, 0x06, 0x26, + 0x93, 0x58, 0x80, 0xAF, 0x63, 0x3F, 0x00, 0x5D, 0x1E, 0xD8, 0xFF, 0x34, 0x5C, 0x4C, 0xD3, 0x06, + 0xE4, 0x71, 0x5D, 0x35, 0x9F, 0x1A, 0xD8, 0xF7, 0x39, 0xEF, 0x8B, 0x93, 0xBE, 0x47, 0xF2, 0xBF, + 0xA6, 0xF2, 0x92, 0xB7, 0xBC, 0x30, 0x19, 0x0B, 0xD9, 0x2D, 0x06, 0x87, 0xEC, 0xA7, 0x06, 0xB6, + 0x61, 0xAF, 0xE0, 0x09, 0xBC, 0xB1, 0x48, 0x20, 0x68, 0xBA, 0xF0, 0xC2, 0x0B, 0xE7, 0xB2, 0x56, + 0xC1, 0xD4, 0x02, 0x5C, 0xBA, 0xA2, 0xE9, 0xCA, 0x47, 0xC0, 0xDA, 0x3B, 0x60, 0xC2, 0xC0, 0xD2, + 0x3F, 0x30, 0x49, 0x03, 0xD6, 0x26, 0xC4, 0xE9, 0x1F, 0x70, 0x79, 0xC0, 0xB9, 0x81, 0x86, 0xF8, + 0xBB, 0xC1, 0xC5, 0xC4, 0xC1, 0xCC, 0xE9, 0xC8, 0x02, 0x80, 0xFC, 0x80, 0x72, 0x00, 0x05, 0x45, + 0x94, 0x7A, 0x07, 0x26, 0x79, 0xC0, 0x47, 0x05, 0xAC, 0xD6, 0x79, 0xFB, 0x80, 0x3F, 0xC8, 0x0E, + 0xB1, 0xF2, 0x00, 0xFB, 0x06, 0x38, 0x52, 0xC0, 0x3F, 0x9E, 0xCE, 0x86, 0x8D, 0x37, 0xE1, 0x3C, + 0x12, 0x75, 0x0E, 0x36, 0x62, 0x3F, 0x11, 0x54, 0x1C, 0x32, 0x28, 0x38, 0x68, 0x20, 0x37, 0xCB, + 0x55, 0xFC, 0xFE, 0x01, 0xBB, 0x32, 0x19, 0x61, 0x79, 0x01, 0xF6, 0xDD, 0x73, 0x69, 0xC0, 0xC7, + 0x0B, 0xFA, 0x58, 0x41, 0x88, 0x03, 0x6B, 0x81, 0x26, 0x06, 0x36, 0x0A, 0xAC, 0x8F, 0xA0, 0x43, + 0xB4, 0x0B, 0x00, 0x65, 0xB0, 0x0E, 0xD9, 0xC0, 0x87, 0xD2, 0x20, 0x02, 0x91, 0x95, 0xC0, 0x26, + 0xDC, 0x88, 0xD3, 0xA8, 0x77, 0x00, 0x30, 0xE5, 0xAF, 0xD0, 0x56, 0xF1, 0x11, 0xFC, 0x20, 0x70, + 0x64, 0xE6, 0x1A, 0xE6, 0xFA, 0x7A, 0x3D, 0x4C, 0xFC, 0x1A, 0xBC, 0x7C, 0x4F, 0xE0, 0x8F, 0xE4, + 0x71, 0xF5, 0x0E, 0x6A, 0x07, 0x88, 0xD8, 0x69, 0xB8, 0x16, 0x7B, 0x97, 0xC1, 0x7B, 0x5A, 0x1A, + 0x3C, 0xE8, 0x5F, 0x7E, 0xB6, 0xE2, 0x4F, 0x21, 0x5F, 0xC9, 0xD7, 0xE0, 0x8D, 0x2D, 0xFC, 0x87, + 0xCF, 0x36, 0xE9, 0xFD, 0x03, 0x94, 0x14, 0x0C, 0xAD, 0x30, 0xF8, 0xBB, 0xF8, 0xC3, 0x5B, 0x05, + 0xA3, 0xCE, 0x8B, 0x41, 0x69, 0xB9, 0x83, 0xB9, 0x4C, 0xA3, 0x05, 0xDE, 0x15, 0x34, 0xBD, 0x02, + 0xAB, 0x70, 0x5E, 0xF3, 0x8C, 0x11, 0xE2, 0xF5, 0x0F, 0x88, 0x03, 0x58, 0x5F, 0x11, 0xE7, 0x0A, + 0x00, 0xFF, 0xA2, 0x5C, 0x1C, 0x60, 0x8F, 0x60, 0xE7, 0x6E, 0x94, 0x08, 0xD4, 0x35, 0x60, 0xEF, + 0x80, 0xC2, 0x40, 0x9F, 0x72, 0x02, 0xD6, 0x49, 0xE4, 0x2D, 0x01, 0xBA, 0xB9, 0x38, 0xA0, 0xE6, + 0xC1, 0xA1, 0x7F, 0x80, 0x7F, 0x1B, 0x61, 0x03, 0x8E, 0x16, 0xF1, 0x6F, 0xA3, 0x0B, 0x87, 0x8C, + 0x24, 0x15, 0x50, 0x1C, 0xDC, 0x4C, 0x22, 0x61, 0xA3, 0x7A, 0xF3, 0xCB, 0xAA, 0x8A, 0x6C, 0x81, + 0x12, 0x81, 0xE5, 0xCA, 0xD2, 0x3F, 0x60, 0x7D, 0x06, 0x21, 0x0F, 0xC4, 0x55, 0xB0, 0x8B, 0x01, + 0xFE, 0xE1, 0x6B, 0xFD, 0x03, 0x60, 0xAD, 0x03, 0xBA, 0x0D, 0x79, 0xA0, 0x8F, 0xBB, 0xBA, 0x1E, + 0x25, 0xB2, 0xBE, 0x81, 0x85, 0x11, 0x4C, 0xF3, 0x07, 0x21, 0x58, 0x4C, 0x6C, 0x30, 0xE2, 0xDF, + 0x80, 0xDA, 0x85, 0xF3, 0x0F, 0x6E, 0x85, 0x3E, 0xAD, 0x4F, 0x4D, 0x7C, 0x99, 0xF7, 0x0E, 0x00, + 0xFA, 0x34, 0x04, 0x4E, 0x79, 0x20, 0xDA, 0xC9, 0x5D, 0x7F, 0x1F, 0x16, 0xD8, 0x5D, 0xBE, 0x69, + 0x31, 0x2F, 0xB0, 0x3E, 0x7F, 0x6D, 0x69, 0xBB, 0xE8, 0xE0, 0x13, 0xE0, 0xFF, 0xEB, 0x6F, 0xD7, + 0x3D, 0xD2, 0xA7, 0x65, 0x45, 0xDB, 0x58, 0x60, 0xDC, 0xD9, 0xA7, 0xE1, 0xF4, 0x96, 0xA2, 0x25, + 0x7D, 0xFE, 0x5A, 0xBE, 0xE9, 0xEB, 0x41, 0xFE, 0x83, 0x9E, 0x46, 0xFF, 0x00, 0xB8, 0x88, 0x40, + 0xFC, 0xDF, 0x65, 0xA1, 0x2F, 0x62, 0x67, 0x61, 0x30, 0x00, 0xFE, 0xBC, 0xAD, 0x57, 0xFA, 0xA6, + 0xD0, 0xA0, 0xBF, 0x0D, 0x61, 0x79, 0x14, 0xBC, 0xD1, 0xCA, 0xFE, 0xF4, 0x9E, 0x80, 0x00, 0x97, + 0xAC, 0xBC, 0x6F, 0x45, 0xA1, 0xE4, 0xC5, 0xE2, 0xD8, 0xFB, 0x07, 0x58, 0xC7, 0xD8, 0x24, 0x4C, + 0x8F, 0x42, 0xF5, 0x2C, 0x1C, 0x3B, 0x72, 0x71, 0x80, 0xED, 0x02, 0x75, 0x11, 0xB9, 0x50, 0xC0, + 0x76, 0x81, 0x35, 0x09, 0xD6, 0x59, 0x15, 0x56, 0xE9, 0xD4, 0x28, 0x68, 0x4C, 0xC1, 0xDA, 0x89, + 0x18, 0x79, 0x40, 0x83, 0x05, 0x14, 0x08, 0xE4, 0xDC, 0x70, 0x13, 0x76, 0x0D, 0x70, 0xB8, 0xC0, + 0x66, 0x0F, 0x54, 0x1C, 0x2C, 0x50, 0xF5, 0xE3, 0xFC, 0x11, 0xCE, 0x1D, 0x28, 0x2F, 0x3B, 0x88, + 0x2A, 0x62, 0x59, 0x31, 0xF1, 0xC1, 0xA5, 0x82, 0x43, 0xBB, 0xC6, 0x3E, 0x7C, 0x2E, 0x11, 0xD0, + 0x25, 0xA6, 0x0F, 0xD0, 0xC1, 0x42, 0x12, 0x22, 0x76, 0xFA, 0x80, 0x0F, 0x1E, 0xCC, 0x43, 0x08, + 0x31, 0xAF, 0xBC, 0x1C, 0x4A, 0xB1, 0x84, 0x91, 0x03, 0x10, 0xBF, 0x3C, 0x09, 0x0F, 0x47, 0x2C, + 0x63, 0x16, 0x07, 0x50, 0xB7, 0x50, 0xFC, 0xE0, 0x4A, 0x03, 0x2E, 0x34, 0xE0, 0x0D, 0xCE, 0x37, + 0xD3, 0x94, 0xF3, 0xA4, 0x1A, 0x9A, 0x52, 0xC4, 0x25, 0x27, 0x06, 0x10, 0xCB, 0x4C, 0xC2, 0xC5, + 0x26, 0x14, 0x93, 0x59, 0x78, 0xE2, 0xD3, 0x88, 0x7C, 0xBD, 0x89, 0x0D, 0x18, 0xCE, 0xF6, 0x6B, + 0x2D, 0x45, 0x7F, 0x56, 0x58, 0xFC, 0xB3, 0x11, 0x10, 0x82, 0x80, 0xF9, 0xF2, 0x26, 0x41, 0x08, + 0x04, 0xE0, 0x17, 0x13, 0xC4, 0xAC, 0x2F, 0x2D, 0x36, 0x4D, 0xA7, 0xC5, 0x85, 0xE9, 0x08, 0xF2, + 0xA7, 0x59, 0x65, 0x92, 0x0B, 0x7C, 0x4A, 0xD9, 0xB6, 0xBE, 0x60, 0x59, 0x57, 0xA0, 0x61, 0x03, + 0x5B, 0x58, 0x60, 0xF3, 0x89, 0xF6, 0x15, 0x06, 0x1A, 0x28, 0xE2, 0x84, 0x32, 0x8E, 0x16, 0xD0, + 0x0D, 0xB4, 0xB2, 0xC0, 0x3B, 0x08, 0x38, 0x9F, 0x8C, 0xFF, 0xC8, 0x0C, 0x2F, 0xF3, 0xC9, 0x44, + 0x73, 0xD6, 0x74, 0x39, 0xC6, 0x1D, 0xA2, 0x71, 0x8B, 0xC9, 0x3A, 0x03, 0x1F, 0x26, 0x6A, 0x33, + 0x48, 0xDA, 0x1A, 0x83, 0x98, 0x47, 0x88, 0x90, 0x40, 0x18, 0x69, 0x9D, 0x2D, 0xBC, 0xBD, 0xCE, + 0x76, 0x8F, 0xF3, 0xCA, 0x31, 0x3E, 0x96, 0x79, 0x65, 0xFC, 0xCE, 0xE0, 0xA3, 0x67, 0x06, 0xCF, + 0x0F, 0x3F, 0x83, 0x8E, 0xA8, 0xC8, 0x91, 0x3D, 0x1F, 0x1A, 0x3C, 0x61, 0xBE, 0xC6, 0x48, 0x6E, + 0x3E, 0x9F, 0x58, 0x51, 0xA7, 0x4D, 0x18, 0x93, 0x0F, 0x4D, 0x29, 0xB2, 0x39, 0xC5, 0x30, 0x5F, + 0x63, 0x60, 0x53, 0xD1, 0x6C, 0xB5, 0x89, 0x4D, 0x1F, 0xD0, 0xD2, 0x94, 0xF3, 0x2A, 0xA4, 0xBE, + 0xCA, 0x78, 0x96, 0x2F, 0x37, 0x89, 0x01, 0x23, 0xFD, 0xBB, 0x90, 0x55, 0xF1, 0x87, 0xB5, 0x9C, + 0x96, 0x9C, 0xB1, 0xEF, 0x86, 0x97, 0xA3, 0x28, 0x41, 0xED, 0x62, 0x13, 0xAD, 0x38, 0x95, 0x0C, + 0x54, 0xFF, 0x38, 0x3D, 0x32, 0x7D, 0x37, 0x9B, 0x52, 0x64, 0x73, 0x07, 0x9C, 0x07, 0xB0, 0x5F, + 0x80, 0x17, 0x6C, 0x2D, 0xB0, 0x8F, 0x60, 0x5E, 0x60, 0xA0, 0x61, 0x22, 0x9B, 0x50, 0x16, 0x93, + 0xCA, 0x82, 0x05, 0xF8, 0xA4, 0xB2, 0x45, 0x1E, 0xE0, 0x9C, 0x11, 0x76, 0x11, 0xA3, 0xF8, 0x3F, + 0x1F, 0xE7, 0x93, 0xB1, 0x89, 0x98, 0xCF, 0xDA, 0x05, 0xFC, 0xDB, 0x78, 0xD3, 0xCD, 0x2F, 0xDF, + 0x4C, 0xF2, 0x00, 0xAF, 0x28, 0xFF, 0x69, 0x91, 0xC1, 0xC8, 0x1A, 0xCF, 0x3E, 0xEF, 0x13, 0xF0, + 0x36, 0x4F, 0x0B, 0xB2, 0x96, 0xBF, 0xD6, 0x39, 0x64, 0x03, 0x46, 0x5E, 0xF3, 0x24, 0x1A, 0x8C, + 0x11, 0x03, 0x6F, 0x17, 0xB4, 0x89, 0x62, 0x0D, 0xF6, 0x7B, 0x27, 0x1F, 0x04, 0x93, 0x07, 0x03, + 0x14, 0x6C, 0x08, 0xCC, 0x78, 0x42, 0x6F, 0xA3, 0x79, 0xB7, 0xC5, 0xF6, 0x90, 0x10, 0x06, 0x08, + 0xAC, 0x6B, 0xBC, 0xA1, 0x1A, 0xF7, 0x20, 0x33, 0x18, 0x5E, 0xA6, 0x55, 0x04, 0x8B, 0x4B, 0x5F, + 0x5A, 0x30, 0x2F, 0x39, 0x59, 0xC0, 0x97, 0x9A, 0xC4, 0xE2, 0x82, 0x58, 0x5F, 0x00, 0x3E, 0xA5, + 0x68, 0x80, 0x8B, 0x56, 0xE3, 0x46, 0xEB, 0x1F, 0x88, 0xD2, 0xE4, 0x2C, 0x1C, 0xF3, 0x59, 0xD1, + 0xCC, 0x01, 0x9B, 0x2C, 0x67, 0x2B, 0x41, 0x6C, 0x7A, 0x99, 0x2F, 0x2F, 0xF0, 0x45, 0x47, 0x2E, + 0x11, 0xEC, 0xD2, 0x80, 0x81, 0x4B, 0x01, 0x31, 0x70, 0xA4, 0xBE, 0xA2, 0x18, 0x49, 0xC6, 0xAC, + 0x38, 0xD2, 0x0C, 0x02, 0x31, 0xC2, 0x46, 0x6C, 0x21, 0x36, 0xD2, 0x9C, 0x12, 0x5F, 0x70, 0x14, + 0x8B, 0x4D, 0x5A, 0x1E, 0xC5, 0x9F, 0xE9, 0x05, 0xCC, 0xFD, 0x1B, 0xB3, 0x3C, 0x88, 0x61, 0x05, + 0x9B, 0x30, 0xE0, 0xBD, 0x04, 0x53, 0xC3, 0x70, 0xB9, 0x2D, 0x43, 0x76, 0xBC, 0x19, 0x13, 0x83, + 0xCB, 0x03, 0xAD, 0x5D, 0x58, 0xB9, 0x7C, 0x65, 0x9F, 0x33, 0x1E, 0xFA, 0x59, 0xBE, 0xD2, 0xDD, + 0xE7, 0x6C, 0x9C, 0x35, 0x7A, 0x84, 0xE0, 0x01, 0xBE, 0xC6, 0xA4, 0xFD, 0xB2, 0xF5, 0x46, 0xB1, + 0x84, 0xC4, 0x2F, 0xFC, 0x16, 0xD7, 0x1D, 0xCD, 0x0B, 0x4B, 0xB1, 0x95, 0x6F, 0xF1, 0xD1, 0x56, + 0x1B, 0x99, 0x3C, 0xB0, 0xAF, 0x2F, 0xB1, 0x46, 0x01, 0xC1, 0xE5, 0xA7, 0x9D, 0x0E, 0x0F, 0x61, + 0xA1, 0x3A, 0x2F, 0x38, 0xC5, 0xA1, 0x11, 0x21, 0x2E, 0x3B, 0xBB, 0xA2, 0xB3, 0xAA, 0xA9, 0x71, + 0x40, 0x1F, 0x6A, 0x18, 0x98, 0x3C, 0xC0, 0x89, 0xE5, 0xDD, 0x4C, 0x12, 0x20, 0x23, 0x98, 0x5E, + 0xDD, 0x3C, 0x93, 0xA8, 0xF1, 0x82, 0x23, 0x0B, 0x00, 0x67, 0x02, 0x6A, 0x18, 0x48, 0x1E, 0xD0, + 0xBC, 0x12, 0xAD, 0x37, 0x0B, 0x16, 0xD8, 0x88, 0x13, 0x49, 0x24, 0x14, 0xB8, 0x30, 0xB0, 0x43, + 0x6B, 0xD5, 0x04, 0x33, 0xC4, 0xB2, 0x0A, 0x82, 0xB5, 0x09, 0xF4, 0xC3, 0x26, 0x93, 0xF8, 0xA8, + 0x51, 0x63, 0x80, 0xEE, 0x2D, 0x3C, 0x9B, 0xF8, 0x20, 0x4E, 0x1B, 0xE0, 0xCC, 0x0D, 0xD4, 0x0B, + 0xD0, 0xB9, 0x41, 0xFB, 0x11, 0x8B, 0x8D, 0xC2, 0xCF, 0xC4, 0x0B, 0x58, 0xD5, 0x28, 0xFF, 0x89, + 0x13, 0x3C, 0xA2, 0x7B, 0x60, 0x5D, 0x73, 0xB4, 0x80, 0x6B, 0x1E, 0x90, 0x83, 0xA9, 0x1D, 0x68, + 0xAB, 0xCF, 0x42, 0x1C, 0x08, 0x5E, 0x88, 0x65, 0x05, 0xAD, 0x79, 0x35, 0xF1, 0x40, 0x6C, 0x23, + 0x4B, 0x9D, 0x03, 0xBE, 0xEA, 0x88, 0x2C, 0xC0, 0x7A, 0x06, 0xA2, 0x7B, 0x60, 0x92, 0x07, 0x36, + 0x26, 0xB0, 0x42, 0xF4, 0x10, 0xF8, 0x6A, 0x23, 0x38, 0x30, 0x03, 0xB2, 0x80, 0x60, 0x06, 0x21, + 0x12, 0xD0, 0x8F, 0x5A, 0x05, 0x02, 0xCB, 0x15, 0x1B, 0x1A, 0x38, 0xC9, 0x03, 0xB3, 0x40, 0x70, + 0xC8, 0xBA, 0x0E, 0xB1, 0xB4, 0x64, 0xED, 0x1A, 0x08, 0x2E, 0x60, 0xFD, 0x83, 0x74, 0xA0, 0xF3, + 0x81, 0xEE, 0x23, 0x38, 0x9E, 0x0B, 0x40, 0xAD, 0xF5, 0xA3, 0xDB, 0x68, 0xEC, 0x30, 0xC4, 0xD4, + 0x53, 0xD4, 0xBD, 0x80, 0x75, 0x19, 0xCC, 0x5E, 0x84, 0x26, 0x1C, 0x07, 0x58, 0x1D, 0x99, 0x84, + 0x3D, 0xB5, 0x73, 0x13, 0xCE, 0x6F, 0x89, 0x05, 0xCA, 0xCA, 0xB4, 0xBB, 0x05, 0x6B, 0xE7, 0x03, + 0x89, 0xDE, 0x89, 0xDA, 0xDB, 0xA5, 0x9E, 0xAA, 0x04, 0x41, 0xF2, 0x81, 0x04, 0x41, 0xF2, 0x81, + 0x04, 0x21, 0x96, 0x0F, 0xAA, 0x86, 0xF2, 0x79, 0x64, 0x67, 0x24, 0x0E, 0x4D, 0x0B, 0x6F, 0xFB, + 0xFD, 0xAB, 0xBA, 0x4D, 0x24, 0x06, 0x71, 0x32, 0x9A, 0x44, 0xFE, 0xB3, 0xF0, 0x8A, 0xF9, 0x0F, + 0x83, 0x0F, 0xAA, 0x4A, 0x71, 0x0E, 0xBA, 0xFF, 0xAB, 0x43, 0x71, 0xE5, 0x39, 0x06, 0x2C, 0xAC, + 0x84, 0xA9, 0xAC, 0x41, 0xF5, 0xD0, 0x26, 0x5B, 0x49, 0xB1, 0xDB, 0x4F, 0x7C, 0x33, 0x41, 0xF1, + 0x8D, 0x63, 0x13, 0xDC, 0x73, 0x1D, 0xC3, 0x82, 0xF3, 0x57, 0x04, 0xEE, 0x73, 0x0C, 0xA1, 0x54, + 0x9D, 0x9F, 0x71, 0x8C, 0xDA, 0x0D, 0x6E, 0x62, 0x6F, 0xD0, 0x2B, 0xEB, 0x5F, 0x83, 0x49, 0x1E, + 0xF8, 0x1B, 0x02, 0x81, 0x33, 0x57, 0x9F, 0x74, 0xDC, 0xD4, 0x42, 0x61, 0xED, 0x5C, 0xA1, 0x79, + 0xD6, 0x49, 0xFB, 0x20, 0x65, 0x4E, 0xDF, 0x67, 0xA0, 0xAA, 0xE5, 0xA1, 0x18, 0x7F, 0x03, 0x07, + 0x03, 0x6F, 0x95, 0x36, 0x04, 0x84, 0x3A, 0xAA, 0x0D, 0x35, 0xED, 0x0B, 0x9C, 0x1F, 0x0A, 0xDE, + 0xB8, 0x3C, 0x70, 0xBA, 0x4F, 0x3C, 0x92, 0x36, 0x60, 0x06, 0xDF, 0x7A, 0xB2, 0x17, 0xD7, 0x63, + 0x77, 0x61, 0x6F, 0x17, 0xAA, 0x48, 0x1E, 0xE0, 0xD7, 0x25, 0x3E, 0x7E, 0x5B, 0x60, 0xA9, 0xFF, + 0xB2, 0x70, 0xF5, 0xD0, 0x63, 0xB7, 0xB6, 0x96, 0x5B, 0xBE, 0xD3, 0x7B, 0x5F, 0x85, 0xC8, 0xD4, + 0x0F, 0x50, 0x4E, 0xD0, 0x73, 0xF8, 0x59, 0x55, 0x0D, 0x3A, 0x01, 0x13, 0x4F, 0xC4, 0x3E, 0x3E, + 0x74, 0x72, 0xFF, 0x13, 0xCF, 0x90, 0x60, 0x41, 0x17, 0x7D, 0xBE, 0xE8, 0x1E, 0x78, 0xF4, 0x86, + 0xC0, 0xD8, 0x81, 0xAF, 0xF3, 0x07, 0x31, 0xD8, 0x1C, 0xBF, 0x78, 0x01, 0xF8, 0xFE, 0xC8, 0x33, + 0x43, 0x61, 0xAF, 0x22, 0xD5, 0xE0, 0xF8, 0x13, 0xFA, 0xBD, 0x3D, 0x81, 0xC8, 0xC4, 0xC1, 0x18, + 0x86, 0xDE, 0xFC, 0x0A, 0xF0, 0x76, 0xC9, 0x37, 0x87, 0x8C, 0xF2, 0x3F, 0x30, 0x8E, 0xA7, 0xC4, + 0x1F, 0x3A, 0x45, 0xDE, 0x8F, 0x53, 0xC2, 0x4E, 0x4C, 0x23, 0x5E, 0xBC, 0x1A, 0x1F, 0xCB, 0x46, + 0x5B, 0x95, 0xC7, 0x30, 0xF1, 0x41, 0xA0, 0x1C, 0xDB, 0x05, 0x2C, 0x27, 0x08, 0xDE, 0x56, 0x1F, + 0x78, 0x73, 0x8D, 0xA5, 0x9C, 0x28, 0x0C, 0xAB, 0x6C, 0x59, 0xE0, 0x2D, 0x9C, 0x2B, 0x2A, 0x7E, + 0xB1, 0xB4, 0xC1, 0xF2, 0x6D, 0x4F, 0xE9, 0x84, 0x77, 0xAF, 0xD0, 0x9E, 0x1B, 0xD9, 0x2F, 0xBC, + 0x67, 0xCC, 0xD3, 0xC1, 0xA8, 0x69, 0x67, 0x84, 0x4E, 0xE5, 0x0B, 0x67, 0xCA, 0x16, 0x06, 0x02, + 0x7F, 0xD9, 0x84, 0xAE, 0xC0, 0x96, 0xB5, 0xAF, 0x2F, 0x39, 0x14, 0x58, 0xEB, 0xF9, 0x7D, 0x69, + 0x43, 0xE3, 0x5D, 0xF4, 0xE0, 0x69, 0x0A, 0x36, 0xC5, 0xF6, 0xDD, 0x3D, 0x16, 0x55, 0x24, 0x39, + 0x51, 0x0A, 0xBB, 0x7A, 0xD5, 0xD3, 0xB0, 0x6B, 0x78, 0x7F, 0xFD, 0xDE, 0x1C, 0x97, 0x32, 0xF8, + 0x99, 0xEB, 0x83, 0x98, 0xC1, 0x1F, 0xDF, 0xC4, 0xAF, 0x00, 0xD5, 0xD7, 0x1C, 0xBC, 0xA3, 0xE3, + 0xDB, 0x5B, 0xD6, 0xDC, 0xB5, 0x65, 0x6D, 0x93, 0x96, 0xEA, 0x99, 0x21, 0xE4, 0x3D, 0x97, 0x12, + 0xB6, 0x4C, 0xCC, 0xD0, 0xFB, 0x5D, 0x16, 0x16, 0x69, 0x01, 0x74, 0x7C, 0x3B, 0xB0, 0x65, 0x4D, + 0x2C, 0x23, 0x9F, 0xC3, 0xB0, 0xB7, 0x0B, 0xB8, 0xDC, 0x0F, 0x7B, 0x4F, 0x8C, 0xF5, 0x5F, 0xD6, + 0x69, 0x29, 0x27, 0x0A, 0x3B, 0x7D, 0xAC, 0xF3, 0x2E, 0x67, 0x22, 0x33, 0x8E, 0x1F, 0x7E, 0xE2, + 0x6B, 0xDA, 0x73, 0x9E, 0x1F, 0xAC, 0x57, 0x1E, 0x79, 0xBD, 0x66, 0xA4, 0x43, 0x2B, 0xE1, 0xC7, + 0xE7, 0xF1, 0x93, 0x9B, 0xFB, 0xDE, 0x69, 0x74, 0xB9, 0x3D, 0x53, 0xFC, 0x13, 0x4F, 0xDC, 0x49, + 0xB5, 0x59, 0xC3, 0x1E, 0x8C, 0x50, 0xB0, 0x19, 0xDF, 0x0C, 0xAC, 0xF5, 0x5F, 0x6A, 0x0A, 0xBB, + 0xE0, 0x55, 0xD8, 0x79, 0x7D, 0x9C, 0xB8, 0x98, 0xC1, 0x37, 0xD7, 0xBC, 0x85, 0x19, 0x9C, 0xB6, + 0x6F, 0x0B, 0xBB, 0x9E, 0x0A, 0xDC, 0xB2, 0xAF, 0x0C, 0x7C, 0x0B, 0xDD, 0x7D, 0x16, 0xBA, 0x3D, + 0x46, 0xAA, 0x40, 0xDE, 0x95, 0x5A, 0xC2, 0xE6, 0xC7, 0x91, 0xC5, 0xF9, 0x0B, 0xA0, 0x62, 0x84, + 0x6F, 0x21, 0xCC, 0xE8, 0xBB, 0x3E, 0xF6, 0x05, 0xCE, 0x5D, 0x38, 0x8E, 0x1B, 0x19, 0x47, 0x58, + 0xCA, 0x29, 0x31, 0x7C, 0x3F, 0x58, 0x3D, 0x9C, 0xA2, 0xF3, 0xE7, 0x8A, 0xDA, 0x1F, 0x99, 0x7E, + 0xFC, 0xC4, 0x55, 0xCE, 0x51, 0xAB, 0x3E, 0xB3, 0x9C, 0xC9, 0x14, 0xF6, 0xD8, 0xD1, 0x13, 0x17, + 0x70, 0xE9, 0xAE, 0xB3, 0xA0, 0x0D, 0x17, 0x9D, 0x3E, 0x7E, 0xCA, 0x08, 0xBB, 0xE8, 0xE4, 0x87, + 0x6B, 0x17, 0xC6, 0x8D, 0x0B, 0x95, 0xFD, 0x2C, 0x9A, 0x59, 0xFE, 0xC7, 0xF9, 0x1A, 0x1F, 0xA1, + 0xDA, 0x48, 0x95, 0xBC, 0x8D, 0x84, 0x6D, 0x88, 0x4B, 0xFB, 0x9C, 0x87, 0x13, 0x1F, 0x4C, 0x29, + 0xFA, 0xB9, 0x63, 0xDC, 0xCA, 0xE2, 0x67, 0x60, 0x0F, 0x13, 0x13, 0x11, 0xDB, 0x6C, 0xF7, 0xCC, + 0x5F, 0x53, 0xB5, 0x8B, 0xE7, 0xA6, 0xFD, 0x6A, 0xD4, 0xC8, 0xFB, 0xEF, 0x2F, 0x72, 0x24, 0x01, + 0xF4, 0xA9, 0x71, 0x1A, 0x00, 0xD5, 0xD7, 0xF9, 0x8E, 0x0E, 0xA6, 0xAF, 0xAE, 0xD2, 0x31, 0xC1, + 0xAA, 0xCB, 0x00, 0x6A, 0xCE, 0x4E, 0x33, 0x85, 0x2D, 0xBD, 0x61, 0xD4, 0x60, 0xE7, 0xB8, 0x84, + 0x5D, 0x1F, 0x53, 0xDC, 0x3D, 0x93, 0xE6, 0xB2, 0xEB, 0x10, 0x98, 0xFF, 0x45, 0xA3, 0x13, 0x63, + 0x4A, 0x15, 0xBD, 0xAB, 0xAE, 0xF3, 0xD5, 0xB3, 0x84, 0x6D, 0x30, 0xBF, 0xF8, 0xAE, 0xB6, 0x85, + 0x71, 0xD2, 0x39, 0x27, 0xE1, 0xC4, 0x07, 0xBE, 0xDF, 0xAF, 0xB6, 0xF7, 0xA3, 0xA8, 0xFD, 0x2C, + 0xF9, 0xE9, 0x86, 0x07, 0xFC, 0xF7, 0xD2, 0x57, 0x35, 0x67, 0xD5, 0x58, 0xEB, 0x78, 0x6E, 0xC6, + 0x48, 0x6C, 0x16, 0xB4, 0xE7, 0x2A, 0xA3, 0x57, 0x43, 0xC5, 0xA1, 0x38, 0xA5, 0x38, 0x67, 0x45, + 0x39, 0xA7, 0x81, 0x98, 0x52, 0xED, 0xF7, 0x8F, 0xA1, 0x41, 0x08, 0x7F, 0xD0, 0x3E, 0x60, 0x9D, + 0x73, 0xC4, 0xEF, 0xBF, 0x7C, 0xC9, 0x79, 0xA6, 0xB0, 0x69, 0x1F, 0xBE, 0x10, 0x27, 0x2E, 0x65, + 0x70, 0xDE, 0xFB, 0x14, 0x77, 0xF1, 0x46, 0x8A, 0xB1, 0x98, 0x14, 0x44, 0xEF, 0xDC, 0x7F, 0xAD, + 0x08, 0x9D, 0x65, 0x4A, 0x15, 0xBD, 0xAF, 0xAF, 0xF6, 0x0F, 0x64, 0x09, 0xDB, 0xA0, 0xD3, 0x66, + 0xD4, 0xB2, 0xB1, 0x28, 0x96, 0xB7, 0x90, 0xEB, 0x4C, 0x0E, 0xA8, 0xBA, 0xA6, 0x77, 0x31, 0x81, + 0x75, 0xBF, 0x33, 0x5F, 0x5A, 0x76, 0xB6, 0x9B, 0x95, 0x28, 0xAC, 0xAB, 0xD0, 0xE4, 0x62, 0x74, + 0xF3, 0xA1, 0xB4, 0x12, 0xB0, 0x3F, 0x9E, 0xFE, 0xF3, 0x05, 0x0F, 0x13, 0x1F, 0x24, 0x2A, 0x84, + 0xC4, 0x05, 0xD4, 0x75, 0xF1, 0xA5, 0x55, 0xC0, 0xA9, 0x3C, 0xD4, 0xCD, 0x1A, 0xB4, 0x3E, 0x3E, + 0xE7, 0x64, 0x5A, 0x44, 0x0A, 0x19, 0x72, 0x9D, 0x49, 0x82, 0x20, 0xF9, 0x40, 0x82, 0x20, 0xF9, + 0x40, 0x82, 0xE0, 0x30, 0xFB, 0x9B, 0x18, 0x8E, 0xDA, 0xEF, 0x30, 0xFB, 0x9D, 0x4C, 0x78, 0x77, + 0x31, 0x72, 0x89, 0x93, 0xB4, 0x1C, 0xEF, 0x64, 0x00, 0x29, 0xF3, 0x01, 0x4C, 0xCD, 0xA2, 0x77, + 0x17, 0x48, 0xEF, 0x29, 0x89, 0x24, 0x90, 0x4A, 0xBB, 0x50, 0x2B, 0x4C, 0xF0, 0xFA, 0x62, 0xE0, + 0xEC, 0x1B, 0xCF, 0x3F, 0x51, 0x6C, 0x2D, 0x8D, 0x38, 0x70, 0x7E, 0x28, 0x33, 0xE8, 0x22, 0xE9, + 0x73, 0x1B, 0x36, 0x79, 0xD0, 0xD1, 0x0A, 0x25, 0xED, 0xA5, 0xB1, 0x5B, 0x34, 0xCC, 0xF0, 0x05, + 0xC9, 0x56, 0xA2, 0x81, 0xCA, 0x20, 0x9B, 0x8A, 0xC2, 0xAB, 0x1D, 0x22, 0x36, 0xE1, 0x4C, 0xE3, + 0x0B, 0xF3, 0x43, 0xD3, 0x0C, 0xFF, 0x38, 0xB1, 0x1D, 0xB0, 0x7F, 0xA2, 0x25, 0x69, 0xC7, 0xC7, + 0xEA, 0x2A, 0xF6, 0x8F, 0x39, 0xA4, 0x28, 0xC2, 0xE0, 0x86, 0x15, 0x76, 0x2B, 0x46, 0x1A, 0x8E, + 0x7D, 0xAC, 0x4C, 0x71, 0x0C, 0x48, 0x0A, 0xD6, 0x5D, 0xE3, 0x0C, 0x1D, 0xDF, 0x7F, 0xDA, 0x4D, + 0xDB, 0x80, 0x0B, 0x12, 0x56, 0x3E, 0x68, 0x52, 0x94, 0xD3, 0xA7, 0x2B, 0x9A, 0x5A, 0x13, 0xCE, + 0xA6, 0x51, 0xD9, 0x9B, 0x76, 0xA0, 0xD4, 0xFC, 0xB4, 0x3F, 0x33, 0x67, 0x84, 0xBE, 0x35, 0x6C, + 0xCB, 0xAB, 0x06, 0x98, 0x64, 0x54, 0xF8, 0xBF, 0x7D, 0xD1, 0xF3, 0x6F, 0x4D, 0xB0, 0xEF, 0xB9, + 0x07, 0x6C, 0xEC, 0xC1, 0xE0, 0xFA, 0x60, 0x6C, 0x02, 0x46, 0x88, 0x98, 0x76, 0x41, 0x62, 0x24, + 0x6F, 0xD4, 0xDD, 0xE1, 0x0B, 0x1E, 0x0B, 0x4D, 0x08, 0xFA, 0x22, 0xBE, 0x88, 0x57, 0x3C, 0xD4, + 0xD1, 0x79, 0xC9, 0xB3, 0x25, 0x43, 0xF6, 0xAA, 0xC5, 0xC8, 0x0A, 0xB6, 0x8A, 0xAF, 0x8B, 0x53, + 0xDD, 0xAD, 0xB7, 0x3F, 0xEF, 0x64, 0x08, 0x13, 0x9F, 0x27, 0x63, 0x2F, 0xF8, 0x02, 0x9D, 0x64, + 0x06, 0x08, 0x60, 0x64, 0x4C, 0x24, 0x2F, 0xC0, 0x19, 0xDA, 0x7B, 0x62, 0x43, 0xD3, 0xA9, 0x3B, + 0x7F, 0x81, 0x41, 0x26, 0x42, 0x2C, 0x23, 0xCE, 0x89, 0xE4, 0x1B, 0x34, 0x3E, 0xE0, 0x5F, 0x5D, + 0x49, 0x7B, 0x0B, 0x6C, 0xF8, 0x57, 0xBE, 0xA1, 0x34, 0x2E, 0xB0, 0xCA, 0x00, 0xCE, 0x44, 0xDB, + 0xA1, 0x94, 0xFE, 0xFB, 0xBF, 0x1F, 0xF9, 0xBC, 0xF8, 0xC2, 0xAB, 0x87, 0x9F, 0xF5, 0x80, 0x27, + 0x48, 0x66, 0x54, 0x7D, 0x30, 0x68, 0xF0, 0x3E, 0xA3, 0xC2, 0x2F, 0x9E, 0x37, 0x08, 0x0E, 0x02, + 0x28, 0xEE, 0x1B, 0x7F, 0xE7, 0x20, 0x0F, 0x3E, 0x78, 0xEF, 0xBD, 0xAB, 0xE2, 0xCB, 0x83, 0x4D, + 0xB7, 0xAC, 0x5E, 0x66, 0x4A, 0xBA, 0xA3, 0x38, 0x84, 0x0F, 0xFF, 0x44, 0xF9, 0x2A, 0x0A, 0x17, + 0x50, 0xC3, 0xFC, 0xB1, 0x8A, 0xBF, 0xA3, 0x4E, 0x13, 0xAE, 0x23, 0x7D, 0x45, 0x75, 0xA9, 0x70, + 0x60, 0xBB, 0xA9, 0xE2, 0xEB, 0x70, 0x07, 0xE9, 0xFE, 0x52, 0x9B, 0xED, 0x48, 0x80, 0x63, 0xA7, + 0xBF, 0xA2, 0xC2, 0x97, 0x5D, 0x2B, 0x27, 0xDE, 0x06, 0xD5, 0xF6, 0xB0, 0x0F, 0x98, 0xF9, 0x83, + 0x4E, 0xF8, 0xE1, 0xC3, 0xB8, 0xA5, 0xC8, 0x13, 0xFD, 0xC0, 0xB4, 0x19, 0xB7, 0xE3, 0xC3, 0x90, + 0xC7, 0x35, 0xDA, 0x8B, 0xE9, 0x7A, 0x42, 0x86, 0xEF, 0xFF, 0xAC, 0x77, 0x0D, 0xF0, 0x7A, 0x70, + 0x2A, 0xEA, 0xF4, 0xBF, 0x3E, 0x68, 0x4E, 0x69, 0x76, 0xE8, 0x65, 0x75, 0xC1, 0xFA, 0xDB, 0x99, + 0x91, 0xD9, 0x7C, 0x87, 0xC6, 0x07, 0x13, 0x8F, 0xD1, 0x1B, 0xB4, 0xD3, 0xAE, 0xFB, 0xF8, 0xDB, + 0x9C, 0x39, 0x58, 0x95, 0xF5, 0x45, 0x6B, 0x17, 0x00, 0x03, 0x23, 0x78, 0x7E, 0x83, 0x4B, 0xFB, + 0xC2, 0x5D, 0x83, 0x4B, 0xA3, 0xC7, 0xC1, 0x17, 0x46, 0x2E, 0xC0, 0x8F, 0x48, 0xF1, 0xE8, 0x15, + 0xFE, 0x20, 0x28, 0x1F, 0xBB, 0x68, 0x53, 0xD7, 0x6D, 0x5F, 0xA8, 0x1F, 0x6F, 0x96, 0x07, 0xAE, + 0x0F, 0xCA, 0x11, 0xA1, 0x4D, 0x67, 0x5E, 0xF8, 0xA5, 0x9D, 0x11, 0xF6, 0xFE, 0x11, 0x2D, 0x24, + 0x28, 0xAA, 0xDA, 0x0E, 0x3F, 0x80, 0x6B, 0x5F, 0x31, 0x92, 0xF6, 0x42, 0x13, 0x6E, 0xDD, 0x9E, + 0xF7, 0x7A, 0x29, 0xB2, 0x41, 0x24, 0x8C, 0x5C, 0xC7, 0x02, 0x68, 0xCF, 0x98, 0x67, 0x68, 0xDF, + 0xE8, 0xEF, 0xCE, 0xAF, 0xAC, 0x33, 0x5B, 0x0D, 0xD8, 0xAF, 0x86, 0x8B, 0x42, 0xEA, 0xD9, 0xD3, + 0x76, 0x91, 0xF0, 0xF1, 0x57, 0x54, 0xD5, 0x03, 0xA1, 0xFB, 0xE1, 0xDD, 0xDA, 0x59, 0x31, 0x8C, + 0x80, 0x86, 0x10, 0x68, 0xEB, 0xDB, 0xEA, 0x69, 0xA0, 0x60, 0xF7, 0xC9, 0x64, 0x23, 0xA7, 0x0E, + 0xC6, 0xE0, 0xC7, 0x5D, 0x3B, 0xD5, 0xDB, 0xA2, 0x9A, 0x2C, 0x65, 0xC0, 0x1F, 0x22, 0x4A, 0xFB, + 0x50, 0xB7, 0x37, 0xE2, 0x3D, 0xB1, 0xE9, 0x46, 0x13, 0x1F, 0xEC, 0x7F, 0x41, 0xC5, 0x54, 0x16, + 0x3C, 0x0F, 0x2D, 0x7D, 0xED, 0x29, 0xE4, 0x1F, 0xF4, 0x76, 0xA1, 0xBC, 0xA1, 0x6D, 0x74, 0xF1, + 0x59, 0x05, 0x36, 0x74, 0xB4, 0x80, 0x9A, 0x50, 0x94, 0x31, 0x79, 0xB0, 0xBF, 0xEC, 0xC4, 0xB8, + 0x83, 0x50, 0x76, 0x62, 0xC4, 0xBB, 0x83, 0x6F, 0xD1, 0xBE, 0x70, 0x9F, 0xCF, 0x47, 0x5B, 0x25, + 0x8F, 0x0E, 0xE6, 0x1D, 0xAE, 0x0A, 0xBD, 0xC2, 0xFF, 0xE8, 0x0D, 0xBD, 0x50, 0x74, 0xEF, 0x89, + 0x8F, 0x5F, 0x0E, 0xDD, 0xF6, 0xAF, 0xFF, 0x9F, 0x59, 0x1E, 0x7C, 0x1E, 0xFA, 0x15, 0x41, 0xE7, + 0xD9, 0x20, 0xBC, 0x36, 0x7D, 0x87, 0x2D, 0x95, 0x0D, 0x9D, 0x0A, 0x28, 0xB8, 0xB7, 0x51, 0x79, + 0x5B, 0xED, 0x50, 0x1F, 0x44, 0x93, 0x2C, 0x82, 0x58, 0x87, 0x1B, 0x9A, 0x07, 0xF9, 0xCE, 0xFF, + 0x53, 0x2B, 0xBA, 0x95, 0x83, 0x23, 0xFB, 0x0B, 0x46, 0x58, 0xBF, 0x60, 0xC1, 0x36, 0xF0, 0xED, + 0x75, 0xC3, 0xFA, 0x4B, 0x60, 0x81, 0x51, 0xB3, 0x21, 0xAF, 0x37, 0xE4, 0x35, 0x7D, 0xBA, 0x1A, + 0x16, 0x28, 0x4A, 0x54, 0x75, 0xA3, 0x15, 0xBD, 0x5A, 0x58, 0x1F, 0xC3, 0x08, 0xAC, 0xEF, 0xEC, + 0x82, 0x49, 0xF6, 0xFD, 0x82, 0x1D, 0xA3, 0x59, 0xB9, 0x8C, 0xDF, 0x3B, 0xA3, 0x6F, 0xD3, 0x1B, + 0x70, 0x83, 0xEE, 0xEF, 0xF1, 0x8C, 0x5E, 0x1B, 0x6D, 0xFA, 0x48, 0xFD, 0xCF, 0xB2, 0xDF, 0xA0, + 0x56, 0x96, 0x86, 0xBA, 0xDB, 0x55, 0xB5, 0x71, 0x28, 0x9C, 0xFC, 0xB2, 0xF2, 0x6C, 0x45, 0xFE, + 0x37, 0x0D, 0x1A, 0x1F, 0x74, 0x14, 0x97, 0x47, 0x5D, 0xEF, 0x8F, 0x39, 0xCA, 0x6E, 0xCE, 0x76, + 0xD9, 0x3F, 0x80, 0x89, 0xAE, 0xFE, 0xF0, 0xC9, 0x28, 0x0C, 0x6C, 0xF3, 0x47, 0xF5, 0x16, 0x1F, + 0xBF, 0x85, 0xF7, 0xFB, 0xC1, 0xC8, 0xD2, 0x43, 0x9F, 0x8C, 0xD2, 0x46, 0x4D, 0xEA, 0x31, 0xB0, + 0xD8, 0x87, 0xC0, 0x5B, 0x7D, 0x91, 0x7A, 0xE2, 0xF4, 0x0B, 0x00, 0xFF, 0xDA, 0xF9, 0x77, 0xD6, + 0x6B, 0x10, 0xF2, 0x20, 0x08, 0x6A, 0x87, 0xAF, 0x23, 0x0A, 0x6F, 0x2A, 0xFF, 0x70, 0xB8, 0xD2, + 0x2A, 0x0F, 0xAA, 0xDB, 0x14, 0xF7, 0x65, 0x61, 0x57, 0x69, 0xF4, 0xA2, 0xB7, 0xC1, 0x2B, 0xD8, + 0x80, 0x88, 0x15, 0x85, 0x9A, 0x37, 0x2C, 0x0F, 0x7A, 0x16, 0xB9, 0x83, 0x1E, 0xFC, 0x26, 0x8B, + 0xC5, 0x43, 0x24, 0xC3, 0x0E, 0x8C, 0x1E, 0xEA, 0x86, 0xEA, 0xDB, 0xC1, 0x6C, 0xD5, 0xC6, 0x1B, + 0xC2, 0x17, 0x74, 0xC7, 0x98, 0x0E, 0xEA, 0x40, 0xBE, 0x19, 0xFD, 0x30, 0x7C, 0xF9, 0x8D, 0xBD, + 0x0B, 0x40, 0xDD, 0x6E, 0x0B, 0xF4, 0xC0, 0xD7, 0x8A, 0xC8, 0xB8, 0xC3, 0xE0, 0xAF, 0x29, 0x83, + 0x8B, 0x8F, 0xA1, 0x69, 0x17, 0x0D, 0x87, 0xCE, 0x67, 0xDB, 0x0C, 0xFD, 0xAE, 0x50, 0x60, 0x4B, + 0xD8, 0x20, 0xE9, 0xBE, 0xA7, 0x6E, 0x52, 0xBB, 0x6F, 0xC8, 0x47, 0xDE, 0xAB, 0xA2, 0x43, 0xDF, + 0x9D, 0xA3, 0x7B, 0x7F, 0x5E, 0x0D, 0x7F, 0x08, 0x45, 0x9D, 0xED, 0xF5, 0x63, 0xBE, 0x3C, 0x5A, + 0xD8, 0x01, 0xCC, 0x63, 0xE8, 0xF2, 0x80, 0x0C, 0x0B, 0x4E, 0x6C, 0xC2, 0x7A, 0xC1, 0x62, 0x24, + 0x91, 0x1F, 0x1F, 0x4C, 0x1E, 0xB4, 0x34, 0x96, 0x1D, 0x1F, 0x0E, 0xED, 0x25, 0x7F, 0x0F, 0x9C, + 0xD5, 0x5B, 0x7C, 0x34, 0x12, 0x10, 0x6D, 0x76, 0x8D, 0x2C, 0x1E, 0x4B, 0xB7, 0x58, 0x31, 0x5A, + 0x85, 0x87, 0x8B, 0x7E, 0x01, 0xC1, 0x68, 0x23, 0x44, 0xE6, 0xC3, 0x8D, 0x10, 0xAC, 0x61, 0x15, + 0xCE, 0xE5, 0xC1, 0xB3, 0xFE, 0x40, 0x69, 0xAB, 0xFF, 0x95, 0x3B, 0xE1, 0xE6, 0x9F, 0x68, 0x1F, + 0xB6, 0x06, 0x37, 0x5C, 0x74, 0x3F, 0xFB, 0x8C, 0x1E, 0xBF, 0x48, 0xE5, 0x76, 0xDA, 0x18, 0x31, + 0x6F, 0xC4, 0xA5, 0x2E, 0xA5, 0x0C, 0x80, 0x6F, 0xDF, 0xF9, 0x51, 0xE8, 0x10, 0x8F, 0xB9, 0x50, + 0xED, 0x45, 0xA5, 0xBE, 0x3A, 0xA9, 0xBF, 0xD4, 0x1B, 0x54, 0x54, 0xEC, 0xB8, 0xFD, 0x7F, 0x0B, + 0x9E, 0x9F, 0x09, 0x2D, 0xEE, 0xC3, 0x9F, 0xD4, 0x7D, 0x3B, 0xEA, 0xD6, 0xC3, 0xB3, 0xEE, 0xC8, + 0x57, 0x76, 0xBD, 0xAF, 0xAE, 0xBF, 0x12, 0x8D, 0xFF, 0x59, 0x11, 0x86, 0x7B, 0x47, 0x1E, 0x83, + 0x91, 0xC7, 0x3A, 0xCE, 0xC3, 0x9B, 0x51, 0xC6, 0xC8, 0xBA, 0x23, 0xAC, 0x78, 0xD8, 0xDE, 0x64, + 0x1F, 0x76, 0x05, 0x4C, 0x8A, 0x38, 0xEE, 0x09, 0x23, 0xB6, 0x9F, 0x98, 0x52, 0x0C, 0xC3, 0x2B, + 0xDE, 0x6D, 0x33, 0xF4, 0x22, 0xEA, 0x42, 0x27, 0x87, 0x86, 0xE0, 0xD9, 0x2F, 0x87, 0x14, 0x08, + 0x7F, 0x90, 0xFF, 0x7D, 0x45, 0x8D, 0x0F, 0x9A, 0xCA, 0xA3, 0xC7, 0xA0, 0x6D, 0x74, 0xB3, 0x82, + 0xBB, 0x9D, 0x55, 0x93, 0x3C, 0x60, 0xA3, 0x23, 0xEB, 0x6A, 0x1C, 0xEF, 0x1F, 0xF4, 0x8F, 0xF6, + 0x8F, 0xB8, 0xFA, 0xED, 0x50, 0xCE, 0x7C, 0x42, 0x97, 0x07, 0xAD, 0xFD, 0x21, 0xBA, 0xF1, 0xAB, + 0xD0, 0x34, 0x84, 0xBF, 0xF5, 0xD1, 0xF3, 0x44, 0x85, 0xBB, 0xD4, 0x67, 0x1F, 0x50, 0xDC, 0x0A, + 0x4C, 0x51, 0x00, 0xAF, 0xFB, 0x4D, 0xF2, 0xA0, 0x3F, 0xC3, 0xCC, 0xE1, 0xCF, 0x8F, 0xEF, 0x6F, + 0xEF, 0x1F, 0x5C, 0x1C, 0xF2, 0xB6, 0xD6, 0x4F, 0x46, 0xC7, 0xCD, 0x1B, 0xBE, 0x8C, 0xB5, 0xA2, + 0x27, 0xED, 0x0B, 0x4E, 0xC1, 0xFF, 0x4E, 0x17, 0x04, 0x27, 0x05, 0x7D, 0xE3, 0xB4, 0x87, 0x46, + 0x1F, 0x86, 0xEF, 0x54, 0xF4, 0x87, 0x33, 0xFD, 0x2B, 0x5F, 0x9E, 0x0D, 0xA6, 0x06, 0x39, 0xA4, + 0xA8, 0xFB, 0xFB, 0xFD, 0xCE, 0xB7, 0x73, 0xF4, 0x66, 0xBC, 0xD1, 0x18, 0xA1, 0xA3, 0x6E, 0x6A, + 0x13, 0xEA, 0x4F, 0xA9, 0xEF, 0xEE, 0x57, 0xE0, 0xCB, 0x31, 0x6C, 0x80, 0xF8, 0x0B, 0xDB, 0x1B, + 0x3F, 0x8F, 0xAB, 0x54, 0xE9, 0x7C, 0x50, 0x8A, 0xAE, 0x30, 0x32, 0x02, 0x53, 0xD0, 0x89, 0x1A, + 0x8C, 0x10, 0x69, 0xFF, 0x95, 0xF7, 0x93, 0xEF, 0x94, 0xC0, 0x01, 0xEC, 0xCB, 0x18, 0x26, 0xEC, + 0x6E, 0xF3, 0xBC, 0x81, 0xA2, 0x69, 0xCA, 0x7F, 0x4F, 0x43, 0x56, 0x3C, 0xF6, 0xA1, 0x69, 0xEC, + 0x9B, 0x9F, 0xD0, 0xF8, 0x60, 0x64, 0x03, 0xB6, 0xA5, 0x7D, 0x8E, 0xBF, 0x74, 0x0B, 0xA0, 0xD5, + 0x99, 0xE1, 0x46, 0x78, 0x00, 0x19, 0xC1, 0xB6, 0xA6, 0xCB, 0xC7, 0x0B, 0xED, 0x2D, 0xD8, 0x39, + 0x00, 0xD7, 0x69, 0x18, 0xA1, 0xCB, 0x83, 0xB3, 0xE7, 0xC1, 0x54, 0x9C, 0xF2, 0x2B, 0x39, 0x45, + 0x1F, 0x12, 0xC0, 0x60, 0xAD, 0xC2, 0xFB, 0x2B, 0xBB, 0xBC, 0x28, 0x9B, 0xA3, 0x78, 0xA1, 0x94, + 0x4C, 0xFD, 0x83, 0x33, 0x0A, 0x7E, 0xD0, 0xBE, 0xB6, 0x0D, 0xA3, 0x63, 0xD8, 0x00, 0x6E, 0x01, + 0xE5, 0xD7, 0x98, 0x19, 0x00, 0xF7, 0xD2, 0x0F, 0xD7, 0xDD, 0x21, 0xF8, 0x80, 0x73, 0xCF, 0xB1, + 0x66, 0xE8, 0xBB, 0xAE, 0x6D, 0x49, 0xED, 0xCD, 0x41, 0xAF, 0xF6, 0x58, 0xF1, 0x70, 0xF8, 0xE9, + 0xAC, 0x99, 0xEF, 0x7D, 0xFE, 0x37, 0x53, 0x71, 0x0C, 0x1B, 0x6E, 0xD4, 0xF9, 0x00, 0x39, 0x72, + 0xE2, 0x1E, 0x15, 0x8A, 0x5E, 0xC5, 0x3E, 0x02, 0xCF, 0x15, 0xE2, 0x92, 0xFF, 0xAA, 0xAB, 0x40, + 0x23, 0x9A, 0xEF, 0x1E, 0x04, 0xF5, 0xCA, 0x0F, 0xAD, 0xA9, 0x72, 0x7C, 0x1E, 0x3A, 0xFB, 0x76, + 0x98, 0x3F, 0x79, 0x0E, 0xD7, 0x29, 0x18, 0x82, 0x72, 0xAE, 0x25, 0xEC, 0xC7, 0xCE, 0xF1, 0xF5, + 0x86, 0x77, 0x53, 0x11, 0x36, 0x3C, 0x2A, 0xDA, 0x1F, 0x28, 0x89, 0x0C, 0xD3, 0x7D, 0xA3, 0x8D, + 0x0B, 0x3E, 0x44, 0xB6, 0xA8, 0xD8, 0x3D, 0xFD, 0x40, 0xC5, 0x88, 0xFC, 0x9F, 0x55, 0x30, 0xE6, + 0x0F, 0x9A, 0x07, 0x60, 0xA7, 0x0A, 0x20, 0x84, 0xD6, 0x1B, 0xDA, 0x4D, 0x73, 0x24, 0x01, 0x7C, + 0x69, 0xEB, 0x23, 0xAC, 0xEC, 0xFB, 0x0F, 0x8C, 0xBA, 0xFA, 0xAB, 0x3B, 0x94, 0xE0, 0x67, 0xF9, + 0x3D, 0xF0, 0xFE, 0x01, 0xC1, 0x2F, 0xBE, 0xA0, 0x26, 0x4D, 0x1E, 0x9C, 0xE7, 0xC1, 0xC6, 0x34, + 0x1A, 0x76, 0xF1, 0x66, 0xBA, 0x95, 0x49, 0x0B, 0x5E, 0xA3, 0xC5, 0x4B, 0xBE, 0x03, 0xFD, 0x83, + 0x34, 0x11, 0x25, 0x98, 0xC9, 0xC0, 0xC8, 0xD6, 0x45, 0x23, 0x9F, 0x24, 0x83, 0xCE, 0x63, 0xE1, + 0x89, 0x86, 0x87, 0x9E, 0xD7, 0x93, 0xF6, 0x82, 0x52, 0x0C, 0xC7, 0x36, 0x2B, 0x25, 0x3F, 0xBB, + 0x0A, 0x8C, 0xF9, 0x03, 0x38, 0xBE, 0x5E, 0x81, 0x9D, 0x5F, 0x81, 0x2F, 0x61, 0xCF, 0x0C, 0x3C, + 0x96, 0x62, 0x2F, 0xC6, 0x2E, 0x02, 0xF5, 0x14, 0x2F, 0xD4, 0x99, 0xA3, 0x7A, 0xD6, 0x7A, 0x64, + 0x04, 0x32, 0x7E, 0x76, 0xFD, 0x79, 0x8E, 0x02, 0xBB, 0x96, 0x8D, 0x98, 0x06, 0x7B, 0x15, 0xB4, + 0xFC, 0xE0, 0x37, 0xD8, 0x61, 0xEA, 0xAE, 0x3E, 0x2D, 0xFD, 0x9A, 0xE9, 0x2D, 0xFC, 0xF3, 0xC2, + 0x26, 0xFD, 0xCB, 0x4F, 0x2C, 0xAC, 0x3A, 0xFF, 0xE8, 0xA0, 0xF6, 0x71, 0x16, 0x1A, 0xAE, 0x11, + 0xDA, 0xB0, 0x65, 0x0C, 0x36, 0x89, 0x4E, 0xA9, 0xE4, 0x15, 0x0C, 0x3E, 0x18, 0xA0, 0x7A, 0x9B, + 0x71, 0x8C, 0x1F, 0xDD, 0xF0, 0x25, 0x6B, 0x3F, 0x31, 0x46, 0xC3, 0x43, 0x8C, 0x17, 0x8E, 0x0F, + 0x77, 0x35, 0x2A, 0x47, 0x2A, 0xA0, 0x4E, 0x9F, 0x4F, 0x3C, 0xD8, 0x1F, 0x3E, 0x06, 0x65, 0x60, + 0x13, 0x4D, 0x3F, 0xA0, 0x51, 0x91, 0x52, 0xBD, 0x01, 0xF8, 0x8F, 0xEF, 0x03, 0x1B, 0xCC, 0x31, + 0x79, 0x70, 0x56, 0xB0, 0x07, 0x0D, 0x19, 0x5F, 0x8F, 0xFE, 0xA0, 0xEF, 0x4A, 0x6A, 0x58, 0x62, + 0xD8, 0x00, 0x5A, 0xFF, 0x2D, 0x7C, 0x7A, 0xC0, 0xE2, 0x91, 0x9F, 0xFF, 0x69, 0x44, 0x3D, 0xA3, + 0x77, 0xFC, 0xD8, 0x78, 0xE1, 0xE4, 0xD0, 0x13, 0xBF, 0x2B, 0x42, 0x93, 0x2C, 0x9F, 0x06, 0x08, + 0xAB, 0xDA, 0x63, 0xEA, 0x20, 0xE4, 0xC2, 0xED, 0x87, 0xEE, 0xA1, 0xAF, 0x78, 0x82, 0x51, 0xB9, + 0xD1, 0xB0, 0x37, 0x34, 0x7B, 0x47, 0xF1, 0x29, 0x18, 0x3C, 0xCB, 0x34, 0xD9, 0x88, 0x8C, 0x70, + 0x70, 0x1C, 0xCA, 0x8A, 0x5B, 0x37, 0x38, 0x6F, 0xA5, 0x9A, 0xC6, 0x08, 0xEC, 0xC5, 0xB9, 0x0A, + 0xEB, 0x94, 0xD4, 0x94, 0x5A, 0x25, 0x10, 0x75, 0x8F, 0xAB, 0x3B, 0x38, 0xCE, 0x3A, 0x99, 0xE8, + 0xBB, 0xF0, 0xEF, 0xAF, 0x78, 0xAE, 0xB3, 0x78, 0xD5, 0x9D, 0xBC, 0x07, 0xD6, 0x36, 0x75, 0x16, + 0x43, 0x74, 0xCC, 0x57, 0xCB, 0x8E, 0xCF, 0x7F, 0xDF, 0x31, 0x9D, 0x3C, 0x82, 0xC6, 0x07, 0xC7, + 0x60, 0xF0, 0xC7, 0x2D, 0xDE, 0x2B, 0xCF, 0x67, 0x37, 0x31, 0xD3, 0x2E, 0x16, 0xE8, 0xE3, 0x05, + 0xF8, 0x7B, 0xCB, 0xD0, 0x4F, 0x7A, 0x2C, 0xF2, 0x60, 0xDF, 0xF9, 0x7E, 0x68, 0x19, 0x12, 0xC4, + 0x19, 0xBF, 0x62, 0x45, 0x1F, 0x2F, 0xF8, 0xC6, 0xAE, 0x01, 0xE4, 0x01, 0x32, 0xDD, 0x4B, 0xC4, + 0x45, 0xEC, 0xB5, 0xC0, 0x46, 0x8C, 0xAF, 0x54, 0xBD, 0x64, 0x9A, 0x6E, 0x36, 0xD0, 0x88, 0xAA, + 0x93, 0x00, 0x27, 0xD1, 0x6E, 0x4D, 0x30, 0xFA, 0x7F, 0xDA, 0x8C, 0x06, 0x93, 0x07, 0x43, 0xEB, + 0x67, 0x84, 0x9A, 0x54, 0xDF, 0x6D, 0xFD, 0x21, 0xA2, 0x1A, 0x87, 0x4A, 0x90, 0xBD, 0xB7, 0xE2, + 0xF3, 0x37, 0xE1, 0xCC, 0xA2, 0x79, 0xB4, 0x1E, 0xC6, 0xCE, 0x63, 0x55, 0xD1, 0xC7, 0x83, 0xE1, + 0x74, 0xF5, 0x18, 0x53, 0xDD, 0x55, 0x0F, 0xFF, 0xAB, 0x02, 0xC1, 0x9B, 0xD4, 0x38, 0x3B, 0xEA, + 0x1E, 0x61, 0x12, 0xED, 0xD6, 0x8F, 0x06, 0x46, 0xDC, 0x21, 0x33, 0x23, 0x78, 0xFB, 0x44, 0x5F, + 0xFA, 0x3E, 0xF2, 0x46, 0x5B, 0x9D, 0x89, 0xA9, 0x9A, 0xCE, 0x0B, 0x79, 0x3D, 0x83, 0xB1, 0x27, + 0x62, 0x21, 0xD1, 0xF1, 0x28, 0xB8, 0x56, 0x7D, 0x7C, 0xBC, 0x2F, 0x84, 0xEF, 0x77, 0xA9, 0x65, + 0xDF, 0xCA, 0xFB, 0x29, 0x04, 0x43, 0x1E, 0x7C, 0x0C, 0xA5, 0x83, 0x0F, 0xDF, 0x0C, 0x27, 0xD1, + 0x0E, 0xF0, 0x26, 0xAB, 0x88, 0xB3, 0x81, 0xC9, 0x83, 0x10, 0x7E, 0xFE, 0x63, 0xDB, 0x9A, 0xFF, + 0xD1, 0x83, 0x07, 0x40, 0x9A, 0xE4, 0xC1, 0x81, 0x03, 0xD7, 0xF6, 0x19, 0xA1, 0xE2, 0x3C, 0x02, + 0x16, 0xDF, 0x29, 0xBD, 0x01, 0x60, 0x23, 0x78, 0x7C, 0x0A, 0x7B, 0x5F, 0x11, 0xF7, 0x31, 0x31, + 0xDD, 0xDC, 0xE0, 0x0B, 0x2A, 0xEA, 0x5F, 0xD1, 0x39, 0xC6, 0x51, 0x1E, 0x4C, 0x45, 0x1B, 0x40, + 0xED, 0x50, 0xC2, 0x35, 0xE4, 0xB5, 0x0E, 0x0B, 0x46, 0x8B, 0x84, 0x9A, 0xA0, 0xF3, 0xC1, 0x19, + 0x9F, 0xEE, 0xB8, 0x1E, 0x09, 0x1A, 0xF3, 0x07, 0xFA, 0xE4, 0x17, 0x33, 0x7C, 0xAA, 0x43, 0x85, + 0x6A, 0xB5, 0x08, 0x27, 0x35, 0x94, 0x81, 0xB0, 0x71, 0xBE, 0x29, 0xE4, 0x8D, 0x5B, 0x5E, 0x9E, + 0x38, 0xC7, 0x8D, 0x1D, 0x58, 0x6B, 0xA2, 0x02, 0xB8, 0xED, 0x16, 0x7B, 0x8A, 0x07, 0x06, 0x02, + 0x19, 0xE8, 0xD7, 0x3C, 0xEB, 0x26, 0x43, 0x78, 0xE4, 0x4F, 0xE8, 0xBE, 0xA2, 0xAE, 0xD3, 0x34, + 0x00, 0x38, 0x7B, 0x9E, 0x2B, 0x04, 0x43, 0x14, 0xE4, 0x49, 0x33, 0x89, 0x0F, 0xDB, 0xD1, 0x68, + 0x11, 0xC9, 0x31, 0x4F, 0x3B, 0xDA, 0x5F, 0xFB, 0x08, 0x19, 0xC2, 0x31, 0xA5, 0xBC, 0x81, 0xC6, + 0x07, 0xCD, 0x9E, 0xBE, 0x2D, 0x7D, 0x3F, 0x9C, 0xB8, 0x07, 0x6A, 0x4D, 0xB3, 0x30, 0xCE, 0x60, + 0x55, 0xE6, 0xE9, 0xEB, 0x9A, 0x58, 0xF5, 0xDE, 0xA8, 0xBE, 0x74, 0xFE, 0xA3, 0x26, 0x0F, 0xF0, + 0x42, 0x1F, 0x98, 0x4F, 0x94, 0xC8, 0x60, 0xA3, 0x43, 0x88, 0xDD, 0xA7, 0x48, 0x07, 0x2E, 0x0E, + 0x46, 0x50, 0x28, 0x68, 0xF2, 0x60, 0x63, 0xAB, 0x3F, 0x50, 0xFF, 0x57, 0xB8, 0xE9, 0x69, 0x9C, + 0x1B, 0x76, 0x62, 0x84, 0xFF, 0x98, 0x31, 0x71, 0x8B, 0x7D, 0xAF, 0x09, 0x93, 0x07, 0x67, 0x37, + 0x2C, 0x1F, 0xF9, 0x8F, 0x7F, 0xDD, 0xD5, 0x09, 0x51, 0x6C, 0xBF, 0xB5, 0x87, 0xE2, 0xAC, 0x9B, + 0x4E, 0xDD, 0x3F, 0x6B, 0x17, 0xFE, 0xDC, 0x08, 0xBF, 0x03, 0xA8, 0x9D, 0x65, 0xF8, 0x17, 0xBF, + 0xFC, 0x79, 0xB2, 0xC4, 0xB8, 0xDE, 0xA9, 0x7B, 0xE0, 0xC1, 0x11, 0x53, 0x13, 0xB4, 0x8C, 0xED, + 0x3C, 0x55, 0x8A, 0x39, 0x8E, 0x68, 0x25, 0x14, 0x0D, 0x29, 0x6E, 0xB1, 0x58, 0x50, 0xB1, 0x1F, + 0xA7, 0x12, 0xB4, 0xE8, 0xFD, 0x42, 0x2E, 0x3A, 0xFD, 0x2B, 0xBA, 0xD1, 0xA2, 0x08, 0xFF, 0xCF, + 0x95, 0xD1, 0x25, 0x6B, 0x8A, 0xD0, 0x58, 0xF0, 0xB8, 0x5B, 0x3C, 0xDF, 0x5D, 0x5D, 0x42, 0x56, + 0x83, 0xF3, 0x1A, 0xDA, 0x5B, 0x0E, 0x08, 0xB5, 0x40, 0x8B, 0x77, 0xFF, 0xED, 0xDF, 0xF9, 0xE9, + 0xD1, 0xF5, 0x3F, 0x7D, 0x81, 0x4F, 0x9C, 0xC5, 0x01, 0x93, 0x07, 0xD8, 0xD4, 0xBB, 0xBE, 0xB8, + 0xF6, 0x62, 0xEA, 0x2D, 0xE9, 0xF2, 0x20, 0x1C, 0xC4, 0xFE, 0x05, 0x5F, 0x5D, 0x00, 0xE8, 0x57, + 0x72, 0x9C, 0x49, 0x15, 0x56, 0xC5, 0xD4, 0x63, 0xE8, 0xE7, 0xE9, 0x28, 0xC6, 0xDA, 0xD2, 0xE5, + 0x01, 0x0D, 0x19, 0x3D, 0xC3, 0x1F, 0xB9, 0xB1, 0xD3, 0x99, 0x0D, 0x00, 0x76, 0x91, 0x15, 0x5E, + 0x7B, 0xD2, 0x45, 0x21, 0x8F, 0x7A, 0x5F, 0xD0, 0xF7, 0xC4, 0x83, 0x23, 0x7D, 0xFB, 0x26, 0x86, + 0xC6, 0x71, 0xEE, 0x43, 0xE0, 0xC0, 0x31, 0x26, 0x36, 0x01, 0x07, 0x6C, 0xBB, 0xBD, 0x9F, 0x2B, + 0xF1, 0xDC, 0xF8, 0xFB, 0x22, 0x13, 0x1B, 0x40, 0x05, 0xEC, 0xAC, 0xBD, 0xF2, 0x0D, 0x67, 0x7D, + 0x06, 0x9A, 0x07, 0x1D, 0x0C, 0xA5, 0x1D, 0x9E, 0x92, 0xE2, 0x76, 0x9C, 0x23, 0xD1, 0x9A, 0x00, + 0xC5, 0x1B, 0x0A, 0x1F, 0x8E, 0xF2, 0x0E, 0xC3, 0xC4, 0xBA, 0x83, 0xFA, 0xF2, 0x53, 0xCB, 0x70, + 0x64, 0x82, 0x0F, 0x6E, 0x86, 0x09, 0x56, 0x2A, 0x35, 0xFB, 0xA3, 0xBF, 0xA3, 0xD1, 0x62, 0x31, + 0x3A, 0x5E, 0x71, 0x5C, 0x08, 0xCD, 0x2B, 0xE8, 0xED, 0x42, 0xC7, 0x44, 0x38, 0xD6, 0xD6, 0x19, + 0x7D, 0xA2, 0x71, 0xC4, 0x13, 0x8D, 0x91, 0xC3, 0x89, 0x18, 0x81, 0xAA, 0xAC, 0x06, 0x3B, 0x82, + 0x9F, 0x5E, 0xF1, 0x89, 0xE3, 0x34, 0xFA, 0xD6, 0xE5, 0x41, 0x25, 0x0D, 0xE9, 0x0D, 0xF8, 0x0D, + 0x79, 0xD0, 0x9F, 0x19, 0xD4, 0xE6, 0xD6, 0x77, 0xF5, 0xE9, 0x25, 0xC4, 0x44, 0xBD, 0x6F, 0xE0, + 0xC4, 0x08, 0xBF, 0x70, 0x4A, 0xDA, 0xC7, 0x12, 0xF9, 0xC4, 0x7F, 0xF0, 0x5F, 0xFD, 0x21, 0x5A, + 0x68, 0x74, 0x46, 0x45, 0x9F, 0xE1, 0x7E, 0x08, 0x97, 0xDC, 0x68, 0x5F, 0x27, 0xF6, 0xBE, 0x11, + 0x6F, 0xCB, 0x15, 0x7B, 0xF7, 0x62, 0x62, 0x00, 0xBF, 0xA9, 0x81, 0xA4, 0xC6, 0xAD, 0xE2, 0x56, + 0xB1, 0x50, 0x51, 0x51, 0xA7, 0x17, 0x90, 0x1A, 0x46, 0xF9, 0x37, 0xCE, 0xDC, 0x63, 0xE0, 0xD0, + 0xA7, 0x0C, 0xF2, 0x7E, 0xEE, 0x80, 0xA0, 0xCF, 0x1F, 0xF0, 0x7F, 0xEB, 0xC1, 0x03, 0xCE, 0xC0, + 0xD2, 0xAF, 0xA0, 0x1A, 0x68, 0xB6, 0x56, 0xA1, 0x99, 0x05, 0x4C, 0x15, 0xCB, 0x5D, 0x16, 0x06, + 0x31, 0xC5, 0x4E, 0xC4, 0x06, 0x10, 0xCB, 0x08, 0xB1, 0x49, 0x38, 0x3D, 0x66, 0x45, 0x31, 0xAF, + 0xCB, 0x18, 0x75, 0x01, 0x43, 0xB2, 0x27, 0x07, 0x46, 0x46, 0x5F, 0xAF, 0x32, 0xAA, 0x7D, 0x1C, + 0x6B, 0x06, 0xF3, 0xFF, 0x8B, 0x4F, 0x8C, 0x54, 0xF4, 0x91, 0xA6, 0xF2, 0x32, 0x0F, 0x3A, 0xC0, + 0xD9, 0x3F, 0xF5, 0xD8, 0x5A, 0x1A, 0x71, 0x10, 0x8F, 0x58, 0x46, 0x90, 0x38, 0xE9, 0x73, 0x1C, + 0x29, 0xEF, 0x6B, 0xCB, 0xA6, 0xF2, 0x56, 0x17, 0x39, 0x89, 0x93, 0x74, 0x6F, 0xAE, 0xBE, 0x0C, + 0xC1, 0xB2, 0xAF, 0x2D, 0x39, 0xE4, 0xB0, 0xD4, 0x65, 0x85, 0x67, 0x0F, 0x8C, 0x0F, 0x9C, 0x15, + 0xC2, 0x25, 0x7A, 0x07, 0x98, 0xE2, 0x3F, 0xE3, 0x03, 0x5C, 0xA2, 0x93, 0xE8, 0xDD, 0x60, 0x7C, + 0x20, 0x05, 0x6E, 0xAF, 0x87, 0xDC, 0xD7, 0x26, 0x41, 0x90, 0x7C, 0x20, 0x41, 0x48, 0x7D, 0x5F, + 0x9B, 0x44, 0x41, 0xC3, 0x61, 0xF0, 0xAD, 0xF7, 0x13, 0x93, 0x42, 0x76, 0x07, 0x15, 0x19, 0xD9, + 0xAD, 0xDA, 0xA3, 0xE3, 0x9E, 0x0C, 0xE4, 0x38, 0x27, 0xF9, 0xA5, 0x1F, 0x6B, 0xC2, 0xB4, 0xCC, + 0x92, 0x82, 0x3C, 0x40, 0x75, 0xBB, 0xAC, 0x21, 0x43, 0x5B, 0x3D, 0xB2, 0x99, 0x45, 0x1B, 0x32, + 0x92, 0xE3, 0x9C, 0xE5, 0xD7, 0x92, 0x30, 0x05, 0xA5, 0xD2, 0x2E, 0xE0, 0x41, 0xDD, 0xD9, 0x42, + 0xA6, 0x46, 0x2C, 0x59, 0xCC, 0xA2, 0x0D, 0x99, 0xC9, 0x71, 0xCE, 0xF2, 0x6B, 0x4E, 0x98, 0x82, + 0x64, 0x3F, 0xB1, 0x97, 0x81, 0xF1, 0xC3, 0xD4, 0x18, 0x69, 0x26, 0xF9, 0x40, 0x82, 0x20, 0xF9, + 0xA0, 0x67, 0x91, 0xAF, 0x87, 0x3C, 0x18, 0x7C, 0x10, 0x7B, 0x14, 0x85, 0x63, 0x9E, 0xD5, 0xD5, + 0x8A, 0xE2, 0x3A, 0x4C, 0x57, 0x45, 0x99, 0x16, 0xA2, 0x5F, 0x1F, 0x2A, 0xA3, 0xAC, 0x53, 0x94, + 0xBB, 0x59, 0x90, 0x62, 0x6C, 0xEC, 0x4A, 0x17, 0x85, 0x77, 0x26, 0x06, 0x1E, 0x02, 0xE2, 0x68, + 0xAE, 0x39, 0xFF, 0x10, 0x37, 0xA7, 0xA9, 0xCB, 0x03, 0xE5, 0x43, 0x75, 0xEB, 0xE7, 0xC2, 0xCB, + 0xD4, 0xD7, 0x16, 0xAB, 0x7B, 0x3C, 0x8F, 0x9D, 0x54, 0xD5, 0x4D, 0x63, 0x8F, 0x6F, 0xFF, 0x8F, + 0x4E, 0x75, 0xD2, 0x71, 0x0A, 0x8A, 0xDE, 0xDC, 0x7D, 0x46, 0x28, 0x38, 0xA0, 0x79, 0xEE, 0xCD, + 0x9F, 0x2C, 0x08, 0xC6, 0x8D, 0x9B, 0xD3, 0x18, 0x3E, 0xE0, 0x87, 0x58, 0xD0, 0x41, 0x15, 0xEC, + 0xB8, 0x8D, 0xAA, 0xBE, 0x0E, 0x07, 0x72, 0xCC, 0x38, 0x2D, 0x48, 0xBD, 0xFD, 0x5F, 0xAB, 0x01, + 0xAE, 0x7A, 0xF0, 0x69, 0x72, 0x7F, 0x95, 0x29, 0x15, 0x2B, 0xDF, 0x3D, 0x72, 0x18, 0x5A, 0x3D, + 0x24, 0x1E, 0x02, 0x9F, 0x79, 0x42, 0xF1, 0x1D, 0xF0, 0xA0, 0x8B, 0x79, 0x3C, 0xE4, 0x90, 0x7A, + 0x22, 0xB0, 0xB3, 0x32, 0x8C, 0x43, 0x38, 0xF4, 0x93, 0x3B, 0xF0, 0x5E, 0x3B, 0x5D, 0x83, 0x1F, + 0x9B, 0x61, 0xCF, 0xE2, 0x66, 0x14, 0x58, 0x0D, 0xAD, 0x33, 0x9E, 0xA0, 0x24, 0x31, 0x61, 0xDF, + 0x71, 0xE1, 0x5E, 0xFD, 0x10, 0x04, 0x86, 0xBF, 0xDB, 0x77, 0x84, 0xB2, 0x7C, 0xB5, 0x11, 0x12, + 0x02, 0xFC, 0xC7, 0x27, 0xA6, 0x39, 0x6C, 0x8A, 0x4E, 0x05, 0x33, 0x06, 0x85, 0x59, 0xDE, 0x78, + 0xB6, 0xE9, 0xF2, 0xBA, 0x76, 0x1E, 0x09, 0x2B, 0x51, 0x76, 0x70, 0x08, 0x3B, 0xC7, 0x24, 0x26, + 0xBF, 0x3D, 0x0C, 0xCC, 0x29, 0xE6, 0xC3, 0xEE, 0x6B, 0xF0, 0x81, 0x38, 0x8A, 0x82, 0x1D, 0x62, + 0x51, 0x45, 0x07, 0x55, 0xB8, 0xED, 0xC7, 0x6D, 0xE8, 0xD8, 0x35, 0x50, 0x6C, 0x74, 0x39, 0x5B, + 0x8C, 0x3B, 0xA0, 0x94, 0x52, 0xB8, 0xF8, 0x5F, 0x8B, 0xB0, 0xB6, 0x19, 0xFC, 0xF7, 0xAD, 0x0F, + 0x4C, 0x6A, 0x50, 0xA3, 0xC3, 0x0E, 0xC3, 0xDE, 0x16, 0xF5, 0x47, 0x53, 0x1B, 0x5A, 0xFE, 0xDF, + 0xF1, 0xC0, 0x84, 0x0F, 0xD4, 0xF6, 0x9F, 0xC5, 0xD1, 0x24, 0x8D, 0x83, 0x6A, 0xCA, 0x42, 0xAB, + 0x7E, 0xE8, 0xC6, 0x10, 0x76, 0x72, 0x87, 0x38, 0x4F, 0x43, 0x9C, 0xAE, 0x71, 0x34, 0xF6, 0xBC, + 0x10, 0xC2, 0x3C, 0x55, 0xDD, 0x7A, 0x23, 0xD4, 0xB6, 0xA8, 0xDB, 0x5E, 0x6A, 0x19, 0xFF, 0x80, + 0xBA, 0xE9, 0x5A, 0xA8, 0x6D, 0x47, 0x77, 0xE8, 0xF2, 0x3F, 0xC0, 0xAE, 0x51, 0x13, 0x83, 0x55, + 0xDB, 0x56, 0x7D, 0x49, 0x0F, 0x61, 0x0F, 0xB4, 0xDD, 0xD4, 0xA8, 0x7E, 0xA7, 0x9B, 0x9F, 0xF3, + 0x73, 0x1F, 0x7B, 0x58, 0xDE, 0x58, 0xC9, 0xED, 0xA0, 0xCB, 0xF9, 0xE2, 0x3C, 0x92, 0x30, 0x3F, + 0x16, 0x04, 0xDF, 0xA1, 0xBF, 0x38, 0xC7, 0x24, 0xB7, 0x78, 0xEE, 0x63, 0xCA, 0x91, 0xDD, 0xD7, + 0xC8, 0x96, 0x1F, 0x6D, 0x4B, 0x57, 0x5D, 0xB3, 0x97, 0x1D, 0x62, 0x31, 0xCC, 0x3F, 0x71, 0xFF, + 0x9D, 0x40, 0x15, 0x37, 0xA7, 0xC5, 0xFE, 0x84, 0x3A, 0x06, 0x66, 0xEF, 0xB1, 0x7B, 0x2E, 0x5A, + 0xB4, 0xCE, 0x75, 0x68, 0x94, 0xB8, 0x89, 0x34, 0x8E, 0xC0, 0x6B, 0xE7, 0x0F, 0xA6, 0x2E, 0x83, + 0x8A, 0x6F, 0x0D, 0x0F, 0x0C, 0xC2, 0xE2, 0x1F, 0x4D, 0xFC, 0x71, 0xBF, 0xFD, 0xA9, 0x44, 0xC0, + 0x43, 0x3A, 0xF6, 0xDF, 0x59, 0x75, 0x02, 0xB7, 0x9D, 0x17, 0xB1, 0x43, 0x37, 0xD8, 0xC9, 0x1D, + 0x50, 0x35, 0x37, 0x02, 0xBE, 0xD3, 0xBE, 0x85, 0x1F, 0xF4, 0x59, 0xF8, 0x01, 0x1D, 0x9B, 0x81, + 0xA1, 0x61, 0x7B, 0x16, 0x5B, 0x07, 0x44, 0xA0, 0x32, 0x8C, 0x89, 0x57, 0xBA, 0x22, 0x23, 0x96, + 0xC1, 0xA5, 0xEF, 0x9D, 0x98, 0xBA, 0x04, 0xDD, 0x78, 0x5A, 0xC8, 0xF1, 0xEA, 0x1B, 0x61, 0x4A, + 0xD9, 0x80, 0x69, 0x65, 0x03, 0xB4, 0x10, 0xF6, 0x80, 0xBB, 0x74, 0xEC, 0xA1, 0xAF, 0xA6, 0x92, + 0x37, 0x3B, 0x02, 0xE5, 0xE0, 0x3B, 0x30, 0x98, 0xE5, 0x6D, 0x24, 0x65, 0x3B, 0xC8, 0x8A, 0xEF, + 0x07, 0xEB, 0x87, 0x3C, 0xF2, 0xE8, 0xBC, 0x91, 0x74, 0x7A, 0x09, 0x1E, 0x0B, 0x82, 0xF9, 0xAF, + 0xE1, 0xE7, 0x98, 0xC4, 0x16, 0x69, 0xCF, 0x81, 0xE5, 0xF4, 0x03, 0x87, 0xF3, 0x54, 0x9C, 0xFB, + 0x07, 0x71, 0x0F, 0xAA, 0x40, 0x28, 0x1F, 0x46, 0x6F, 0xD6, 0x64, 0x7C, 0xBF, 0x0E, 0x14, 0xA7, + 0x6A, 0x1B, 0xED, 0x5A, 0x58, 0xF4, 0xEA, 0x93, 0xCC, 0x2B, 0xB0, 0x6A, 0x01, 0x4C, 0xED, 0x54, + 0x55, 0x35, 0xA5, 0x5A, 0x8F, 0x05, 0xCB, 0x82, 0xE9, 0x10, 0x0E, 0x06, 0xD3, 0x79, 0x1A, 0x04, + 0xC7, 0xF3, 0x42, 0x5A, 0x07, 0x1E, 0x52, 0x5B, 0x9C, 0x5E, 0xCB, 0xBF, 0xF4, 0xA9, 0xC7, 0xEE, + 0x74, 0xF0, 0x07, 0xDF, 0x89, 0xD3, 0xD3, 0xA9, 0xB3, 0x9B, 0x36, 0x30, 0x1F, 0xA7, 0x07, 0xF3, + 0x13, 0x46, 0x58, 0xB6, 0xCF, 0xB0, 0xE2, 0x4B, 0x78, 0x1E, 0x49, 0x8E, 0xC0, 0x72, 0xEA, 0x14, + 0x60, 0x2F, 0x30, 0x3A, 0x8A, 0x62, 0xCF, 0xA4, 0xC3, 0xFC, 0x84, 0x0C, 0xDC, 0x4C, 0xE4, 0xD4, + 0x98, 0x29, 0x97, 0xBF, 0x24, 0x5A, 0xD3, 0x19, 0x27, 0xB0, 0x7F, 0xF0, 0xFA, 0x73, 0x23, 0x36, + 0x23, 0x63, 0xD4, 0xF1, 0x53, 0xC7, 0x9F, 0x19, 0x35, 0xDA, 0x7D, 0xDC, 0xB6, 0xB1, 0x73, 0x06, + 0xF5, 0x19, 0x96, 0xD2, 0x11, 0x0D, 0xC9, 0x00, 0x4F, 0xFB, 0x80, 0x3D, 0x13, 0x3F, 0xA0, 0x2C, + 0x54, 0xD9, 0x0F, 0xDD, 0x30, 0x9D, 0xA7, 0x01, 0xDA, 0xB1, 0x19, 0xF6, 0x2C, 0x4E, 0x29, 0x83, + 0xAD, 0x62, 0x47, 0xA4, 0xBB, 0x71, 0x0D, 0x6C, 0x9D, 0xAC, 0x71, 0xCA, 0xBF, 0x3C, 0x76, 0xAB, + 0xBE, 0x93, 0x5B, 0x84, 0xD4, 0x35, 0x61, 0xDC, 0xB6, 0x15, 0xFE, 0x13, 0x2B, 0xBA, 0x7F, 0x5A, + 0x38, 0xCB, 0x1B, 0x3B, 0x5B, 0x64, 0x05, 0x2B, 0x3E, 0x71, 0x1E, 0x09, 0x1D, 0x1C, 0x42, 0xC7, + 0x82, 0x80, 0x76, 0x8E, 0x49, 0x8E, 0xFB, 0x07, 0xE0, 0x78, 0xEC, 0x89, 0xBD, 0xB9, 0xF2, 0xFD, + 0x7E, 0xEE, 0xC3, 0x45, 0xFB, 0xFB, 0x57, 0xFB, 0xE1, 0xA2, 0x7B, 0x60, 0xD5, 0xD8, 0x8B, 0x1C, + 0xB3, 0x7C, 0xD1, 0x17, 0x1B, 0x47, 0x33, 0x87, 0xFF, 0xD0, 0xD8, 0xE5, 0x50, 0x59, 0xED, 0xBD, + 0xEC, 0x2B, 0xCB, 0x61, 0x76, 0x95, 0x8A, 0x4D, 0x06, 0xFE, 0x80, 0xFF, 0x00, 0x4A, 0xE6, 0xE2, + 0x43, 0x86, 0x35, 0x0D, 0xFF, 0xEF, 0xC6, 0x80, 0x72, 0xC8, 0xB4, 0x9B, 0x3E, 0x21, 0x7E, 0x37, + 0xF7, 0x01, 0x14, 0x5E, 0x7D, 0x28, 0x0B, 0xCB, 0xAF, 0x9E, 0xFB, 0x30, 0xF8, 0xFE, 0x5B, 0x0F, + 0xC2, 0xF3, 0x34, 0xA0, 0xBF, 0x9E, 0x65, 0xCA, 0x2B, 0xC6, 0xB4, 0x3D, 0x5E, 0xFA, 0x55, 0xDC, + 0xC8, 0xC6, 0xB3, 0x07, 0xBE, 0xFA, 0x01, 0xF7, 0x16, 0x1F, 0xD2, 0x43, 0x1E, 0xFE, 0xA2, 0x1E, + 0x8B, 0x87, 0x94, 0x6E, 0x1C, 0x81, 0x71, 0xDD, 0xFF, 0xFE, 0x20, 0x2C, 0x2E, 0xB7, 0x67, 0x23, + 0x55, 0xE0, 0x09, 0x23, 0x98, 0x37, 0x3C, 0x5B, 0x04, 0x2E, 0xFA, 0xF1, 0x78, 0x2A, 0xBE, 0x20, + 0x3F, 0x8F, 0x84, 0x97, 0x28, 0xB5, 0xB1, 0xBE, 0x0D, 0x73, 0x1F, 0x30, 0x72, 0x9F, 0x3B, 0x50, + 0x8E, 0xEC, 0xE6, 0xDE, 0x92, 0xD7, 0x57, 0xAE, 0xBD, 0x3D, 0x9B, 0xEB, 0x0B, 0x29, 0x6A, 0x4D, + 0x3B, 0xA3, 0x8B, 0x2C, 0x6E, 0xFF, 0x7A, 0xB5, 0xC5, 0xAE, 0x5D, 0xB7, 0x90, 0x89, 0x1C, 0x67, + 0xB5, 0x48, 0x6D, 0xB0, 0xE5, 0xD7, 0xBC, 0xFC, 0x1C, 0xB4, 0xE8, 0x2B, 0xE7, 0xCD, 0x51, 0x14, + 0x59, 0xCB, 0x48, 0xF5, 0x2D, 0x99, 0x63, 0x83, 0x24, 0xA0, 0x8D, 0xCD, 0xF2, 0xE9, 0x70, 0x8F, + 0xB8, 0xC7, 0x95, 0x18, 0x7C, 0x90, 0x37, 0xD9, 0xCD, 0x5A, 0x46, 0x16, 0x75, 0x9B, 0x42, 0x4A, + 0xC8, 0xC7, 0xC3, 0x5D, 0xE2, 0xE6, 0x49, 0xAE, 0x2F, 0xF4, 0x32, 0xB0, 0x06, 0xA1, 0xD6, 0x64, + 0x0F, 0x97, 0x43, 0xF2, 0x81, 0x04, 0x21, 0x85, 0xEE, 0x6B, 0x4D, 0xFE, 0xAB, 0xB7, 0x17, 0x40, + 0x16, 0x2D, 0xC8, 0x59, 0x7E, 0x63, 0x12, 0x4E, 0x9E, 0x0F, 0x0A, 0x60, 0xB3, 0x4B, 0xA1, 0xED, + 0xC7, 0xC9, 0x49, 0x7E, 0x49, 0x37, 0xD1, 0x9A, 0x70, 0x6A, 0x7A, 0xAA, 0x05, 0xF0, 0xA9, 0x15, + 0xDA, 0x7E, 0x9C, 0x5C, 0xE4, 0xD7, 0x61, 0x83, 0x7E, 0xAA, 0xFA, 0x89, 0x12, 0xE7, 0x00, 0xE2, + 0xE8, 0xD7, 0xCA, 0x7E, 0xA2, 0x04, 0x41, 0xF2, 0x81, 0x04, 0x41, 0xEE, 0x7B, 0xEF, 0xF5, 0x30, + 0xF6, 0xBD, 0xF7, 0xE4, 0x7E, 0x0A, 0x89, 0x3C, 0x03, 0xEF, 0x30, 0x88, 0x7E, 0x62, 0xCF, 0xAD, + 0x77, 0x48, 0xE4, 0x18, 0xB6, 0x41, 0x8A, 0x98, 0x59, 0x94, 0xE3, 0x85, 0x5E, 0x07, 0xCB, 0x4E, + 0x57, 0xED, 0x44, 0xD5, 0xAC, 0xF5, 0x13, 0x37, 0x6B, 0x0A, 0x8B, 0x16, 0x8F, 0xED, 0x31, 0xFA, + 0xAA, 0xA4, 0x2A, 0xAA, 0x5D, 0xAD, 0x7E, 0x12, 0x59, 0x42, 0x30, 0x68, 0x40, 0xF3, 0xCB, 0x1A, + 0x1F, 0xF4, 0x7B, 0x8B, 0x69, 0x29, 0x93, 0xBE, 0x17, 0x56, 0x3E, 0x6E, 0x6B, 0x40, 0x0F, 0x08, + 0xDC, 0x78, 0x44, 0xFD, 0xBE, 0x5E, 0xC9, 0x5C, 0xAD, 0x39, 0xED, 0x14, 0x24, 0x32, 0x88, 0xAC, + 0xF1, 0x01, 0x6A, 0x85, 0x92, 0x9E, 0xE2, 0x96, 0xAB, 0x42, 0x9B, 0xE7, 0x36, 0xAA, 0xEA, 0xD7, + 0x8F, 0x93, 0x47, 0xA4, 0xC5, 0xDC, 0x0E, 0xD5, 0x3C, 0xA0, 0xB6, 0x3F, 0xB7, 0x3F, 0x4D, 0xFA, + 0x12, 0x19, 0x45, 0xD6, 0xF8, 0xC0, 0xBF, 0xF4, 0x57, 0xF4, 0x33, 0xE3, 0xF4, 0xA9, 0x5D, 0x07, + 0x50, 0x23, 0xED, 0xAB, 0xC3, 0xD1, 0x23, 0x30, 0xBE, 0x7D, 0x84, 0xBF, 0x62, 0x77, 0xD1, 0xA0, + 0x3E, 0xC7, 0x21, 0x30, 0xEA, 0xF8, 0xC5, 0xF7, 0x83, 0xFF, 0xFB, 0x50, 0x3F, 0x1A, 0xB7, 0x1B, + 0x60, 0x4C, 0xF3, 0xB6, 0x03, 0x80, 0xED, 0xCC, 0xAF, 0x15, 0x77, 0x1B, 0x28, 0x0F, 0x19, 0x7B, + 0x11, 0xBA, 0xBD, 0xCD, 0x40, 0x22, 0x0E, 0xB2, 0x37, 0x8F, 0x54, 0xC1, 0x76, 0x04, 0xBC, 0x35, + 0xB0, 0xFF, 0x4A, 0x21, 0x03, 0x2A, 0x9A, 0xFC, 0xF5, 0xD3, 0x3B, 0x03, 0x75, 0xD3, 0x3B, 0x3F, + 0x7E, 0xEC, 0x69, 0xD8, 0x35, 0x9C, 0xF4, 0x15, 0x5B, 0x9F, 0xFF, 0x44, 0xB0, 0x4A, 0x7D, 0xF5, + 0x1A, 0xD4, 0x12, 0x35, 0x6D, 0x3B, 0x08, 0x43, 0xDB, 0x95, 0xC7, 0x98, 0xC2, 0x20, 0x06, 0x6E, + 0x7B, 0xF8, 0x04, 0xDB, 0x7F, 0x40, 0x3B, 0x0E, 0x1C, 0xF5, 0x90, 0x25, 0xD2, 0x81, 0x6D, 0x27, + 0x4B, 0xF6, 0x0A, 0xF6, 0xD2, 0x3F, 0x87, 0x6B, 0x8B, 0x94, 0x25, 0xD5, 0xD1, 0x0A, 0xA1, 0x28, + 0x7D, 0xE9, 0x9F, 0xF5, 0x8F, 0x79, 0xD6, 0x1F, 0xE0, 0x5D, 0xB4, 0x84, 0x0F, 0x81, 0x09, 0x7F, + 0xF4, 0xA0, 0x7A, 0xF1, 0xA5, 0xF5, 0xC8, 0x33, 0xF8, 0xB9, 0x5F, 0xD2, 0xC1, 0xB7, 0x1D, 0x40, + 0xED, 0xF0, 0x7A, 0xAE, 0xD5, 0x8A, 0x81, 0x33, 0x06, 0x9C, 0x61, 0xFB, 0x0F, 0x68, 0xC7, 0x41, + 0x6A, 0x39, 0x90, 0x88, 0x0F, 0xBF, 0x8D, 0x11, 0xB2, 0xC7, 0x07, 0xA5, 0xB7, 0x7F, 0x80, 0xFD, + 0x83, 0x3D, 0x5E, 0xF7, 0x71, 0xB1, 0x11, 0xA2, 0xF4, 0x76, 0x7D, 0x47, 0xC4, 0xC5, 0xB7, 0x1D, + 0xDA, 0x88, 0xDA, 0xE4, 0x81, 0x71, 0xEF, 0xE8, 0x6A, 0xC2, 0x6D, 0xA6, 0x6D, 0x07, 0x45, 0x53, + 0x7F, 0x23, 0xB6, 0x1A, 0x99, 0x50, 0x63, 0x3E, 0x42, 0x55, 0xA2, 0x7B, 0x20, 0x26, 0xB0, 0x30, + 0x42, 0x16, 0x05, 0x6D, 0x9F, 0x17, 0xD9, 0x8F, 0x7F, 0xFD, 0x04, 0x1C, 0x33, 0xFC, 0x12, 0xFF, + 0xFB, 0xFC, 0x9A, 0x79, 0xE0, 0x9E, 0x01, 0x98, 0x7A, 0xCD, 0x0C, 0x2F, 0xB4, 0xF6, 0x13, 0x6C, + 0xC0, 0xB6, 0x18, 0x98, 0xB6, 0x1D, 0x74, 0xC2, 0x0D, 0x0B, 0xEE, 0x86, 0x56, 0xEC, 0x45, 0xE0, + 0xCD, 0xAE, 0x61, 0x9F, 0x60, 0x9E, 0x33, 0x3E, 0x2A, 0x8C, 0x2D, 0xC5, 0x85, 0x00, 0xCE, 0x02, + 0x66, 0x46, 0xC8, 0xE2, 0x3C, 0xD2, 0xAC, 0xEF, 0xF2, 0xB9, 0xAA, 0x79, 0x9B, 0x70, 0x9B, 0xDB, + 0x6C, 0xDC, 0x38, 0x36, 0xEB, 0x3B, 0x78, 0x5E, 0x17, 0x94, 0x3E, 0x36, 0x62, 0xF1, 0xDA, 0x4B, + 0x3F, 0x5C, 0x02, 0xB0, 0x35, 0x8C, 0x3B, 0xE1, 0x06, 0x9E, 0x2D, 0xC2, 0x1D, 0x10, 0x1D, 0xD0, + 0xC7, 0xB4, 0xED, 0x00, 0xB1, 0x70, 0x2C, 0xAC, 0xC0, 0x9F, 0xDA, 0x22, 0xDC, 0x08, 0xC1, 0xF3, + 0xE8, 0xFB, 0x1D, 0xC6, 0x8E, 0xD1, 0xAB, 0x93, 0x48, 0x07, 0xB1, 0xEA, 0xAA, 0x6C, 0xFF, 0x42, + 0x76, 0xF4, 0xE8, 0x03, 0x13, 0xAB, 0xAC, 0x5B, 0x57, 0x62, 0x3C, 0xBA, 0x44, 0xEB, 0xA7, 0xAA, + 0x2C, 0xAA, 0xE6, 0xDB, 0xBF, 0x53, 0x95, 0x1A, 0x01, 0x89, 0x18, 0x58, 0x37, 0x32, 0xD4, 0xDE, + 0x5E, 0xC3, 0x18, 0x20, 0x8B, 0xED, 0x82, 0x7F, 0x99, 0x6D, 0xAF, 0x58, 0x8C, 0x47, 0x6A, 0x40, + 0x5B, 0x1B, 0x73, 0xB5, 0x83, 0xDF, 0x25, 0x32, 0x8C, 0x6C, 0x0E, 0xC4, 0xBE, 0x65, 0xDF, 0x2B, + 0x16, 0xE3, 0xD1, 0x15, 0x4A, 0x77, 0x99, 0xC4, 0xC1, 0x22, 0x55, 0x0D, 0xA6, 0x28, 0x4F, 0x24, + 0x92, 0x85, 0x5C, 0x67, 0xEA, 0x75, 0xD0, 0x96, 0x96, 0x2C, 0xC8, 0x36, 0x1F, 0xD8, 0x5B, 0x78, + 0x67, 0x6C, 0xBF, 0x04, 0x56, 0xA6, 0xBE, 0x4F, 0x5E, 0x7B, 0x2A, 0x99, 0x34, 0xE2, 0xA7, 0x90, + 0xCC, 0xD3, 0xC9, 0xBD, 0x45, 0x2A, 0xC8, 0x3C, 0xC5, 0x64, 0x11, 0xA7, 0xAB, 0x1D, 0x50, 0x03, + 0x81, 0xAA, 0x09, 0x6A, 0x0B, 0x1E, 0xC4, 0xB7, 0x58, 0x6D, 0x99, 0x4E, 0x96, 0x0B, 0x08, 0x86, + 0x2B, 0x3D, 0x10, 0x3D, 0x28, 0x3E, 0x30, 0xFD, 0xB4, 0x89, 0x4E, 0x5C, 0x9A, 0xED, 0x65, 0x47, + 0x92, 0xA1, 0x19, 0xEF, 0xA9, 0x24, 0x72, 0x9D, 0x20, 0x05, 0xED, 0x99, 0xF6, 0xCF, 0x88, 0x67, + 0xB7, 0xB1, 0x92, 0x70, 0x83, 0xC2, 0x1E, 0x79, 0xAA, 0x12, 0xBD, 0x2D, 0x74, 0x63, 0x12, 0xB1, + 0x7A, 0xE8, 0x74, 0x12, 0xA2, 0xBB, 0xE5, 0xDB, 0x0D, 0x60, 0x8D, 0x9B, 0xC1, 0x19, 0x40, 0xF4, + 0x0F, 0x02, 0x13, 0x0E, 0xA9, 0xED, 0x7B, 0x93, 0xE0, 0xA6, 0xA4, 0x41, 0xB6, 0x30, 0x82, 0xE3, + 0x77, 0x25, 0x25, 0x6F, 0xAC, 0xCB, 0x4F, 0xC9, 0x22, 0x95, 0xA7, 0xBA, 0x8E, 0xBB, 0xB9, 0xE4, + 0x24, 0x77, 0x6C, 0xC7, 0x65, 0xB1, 0xB5, 0xF0, 0xB3, 0x43, 0xEA, 0xD6, 0x6B, 0x70, 0xFE, 0x73, + 0xDD, 0xF2, 0xAE, 0x7B, 0x50, 0x96, 0x5E, 0x8C, 0x4E, 0x27, 0x5F, 0x61, 0x3F, 0xF0, 0x8E, 0xFB, + 0x6A, 0x6F, 0xE9, 0xF5, 0x80, 0xFF, 0x35, 0x58, 0xB7, 0xBB, 0xE8, 0x6E, 0xB6, 0xDE, 0x43, 0xAE, + 0x41, 0x26, 0x23, 0x52, 0xAD, 0x5E, 0x5A, 0xF6, 0x49, 0x19, 0xAD, 0x33, 0x70, 0x84, 0x80, 0x13, + 0xC6, 0x6C, 0xD1, 0x88, 0xD3, 0x7C, 0xC2, 0x77, 0xDC, 0xBC, 0xA2, 0x44, 0xD4, 0x5B, 0x70, 0xF9, + 0x69, 0x5A, 0x33, 0xC5, 0x42, 0x4F, 0x66, 0x98, 0x84, 0x7C, 0x9B, 0x79, 0xF2, 0x81, 0x32, 0x8C, + 0xC6, 0x2E, 0x9C, 0x0E, 0xCB, 0x8E, 0xF6, 0x14, 0xAD, 0x3B, 0xB1, 0x34, 0x04, 0x92, 0x4B, 0xA1, + 0x9E, 0xA2, 0x70, 0x6A, 0x78, 0xED, 0xCB, 0x27, 0xAF, 0xE6, 0x69, 0x93, 0x99, 0xEF, 0xD2, 0xB2, + 0x18, 0x0D, 0xB0, 0x71, 0x7E, 0x1B, 0x36, 0x1F, 0xE4, 0x56, 0x9D, 0xF8, 0x62, 0x18, 0xB3, 0xB4, + 0x75, 0x84, 0x0A, 0xC9, 0x94, 0x17, 0x7A, 0xCB, 0x66, 0x6D, 0x79, 0xCC, 0xA0, 0xC3, 0x8B, 0x8D, + 0x45, 0xD3, 0x72, 0xAF, 0x5B, 0xEC, 0x32, 0x52, 0xCD, 0x01, 0xE2, 0x9C, 0x7B, 0x28, 0xDA, 0x85, + 0xA7, 0x60, 0x36, 0x8A, 0x0C, 0x21, 0xAD, 0xB6, 0xCD, 0x26, 0x17, 0xDD, 0xB4, 0x4C, 0x3F, 0x5D, + 0xD2, 0xA8, 0x3E, 0xDD, 0xD8, 0xE2, 0x49, 0x51, 0x72, 0x1B, 0xED, 0xC2, 0xD9, 0xF2, 0x46, 0x41, + 0x97, 0x68, 0xBA, 0x57, 0xB2, 0xE0, 0x6D, 0xB3, 0xC9, 0xB5, 0xAD, 0x52, 0x50, 0x9F, 0xDE, 0xD9, + 0xCE, 0x62, 0x9D, 0xE6, 0xC1, 0x2D, 0xE4, 0x7B, 0x80, 0x25, 0xDF, 0xF9, 0x28, 0xF9, 0xD0, 0x45, + 0xC4, 0x60, 0x41, 0xDA, 0x53, 0x22, 0x8B, 0xE6, 0x76, 0x21, 0x89, 0x14, 0x5A, 0xDC, 0x0F, 0x0B, + 0x6A, 0x67, 0x87, 0xE1, 0x9D, 0x78, 0x5A, 0xFC, 0xB6, 0xE3, 0x19, 0xC4, 0xB0, 0x92, 0x7E, 0xB0, + 0x5D, 0x40, 0xDB, 0x80, 0xCC, 0x9B, 0x5E, 0xFF, 0xB5, 0xCA, 0x4E, 0x2C, 0x17, 0x5E, 0x34, 0xA6, + 0xBC, 0xE0, 0x9A, 0x3A, 0x51, 0x7D, 0x18, 0x93, 0x32, 0xD3, 0x61, 0xAF, 0x70, 0x90, 0xBF, 0x3A, + 0xCB, 0x3D, 0xA6, 0xF4, 0x9A, 0xC8, 0x92, 0x39, 0xD5, 0x9E, 0x87, 0xAD, 0x59, 0x60, 0x4D, 0x43, + 0xD5, 0x04, 0x8D, 0x0F, 0x54, 0x6C, 0x16, 0xD9, 0x2B, 0xB2, 0x1A, 0xAC, 0xA4, 0x12, 0xE6, 0x85, + 0x7C, 0x76, 0x58, 0x31, 0xBE, 0x6A, 0xCA, 0xD0, 0x6A, 0xBE, 0x0D, 0xCB, 0x88, 0x38, 0x82, 0x68, + 0x08, 0x9A, 0x3C, 0x05, 0xAA, 0x3C, 0x8D, 0x3A, 0xAB, 0x3E, 0xCE, 0x37, 0xA2, 0x2E, 0xD0, 0xD7, + 0x54, 0xC7, 0xFA, 0x53, 0x50, 0x7C, 0x90, 0x82, 0x58, 0xB8, 0x89, 0x55, 0x2D, 0x7C, 0xD0, 0x75, + 0x0A, 0xDA, 0x5B, 0x1A, 0x77, 0x46, 0x8E, 0x39, 0x83, 0x94, 0x34, 0x3E, 0xB5, 0x52, 0x7D, 0x74, + 0xB6, 0xFA, 0x28, 0x7D, 0x29, 0x58, 0xBF, 0xEC, 0x89, 0x92, 0x46, 0x0C, 0x43, 0x7F, 0x9D, 0x16, + 0xCB, 0x0B, 0x7B, 0x92, 0x27, 0x65, 0xA6, 0xC3, 0x5F, 0xC1, 0x78, 0x29, 0x4E, 0x81, 0xA7, 0x67, + 0x8E, 0x9D, 0x03, 0x24, 0xEA, 0x1F, 0x20, 0x2E, 0x6E, 0x67, 0xA7, 0xF4, 0xDA, 0xCD, 0x4C, 0x75, + 0xD3, 0x88, 0x54, 0x27, 0xF0, 0x9E, 0x82, 0x69, 0xE0, 0x6F, 0x4E, 0xC1, 0xA0, 0xCE, 0x62, 0x09, + 0x4B, 0x46, 0x7E, 0xF2, 0x8D, 0x59, 0x4D, 0x60, 0x31, 0xC6, 0x52, 0xD0, 0x99, 0x2E, 0xF2, 0xD4, + 0x75, 0x0A, 0xF6, 0x3B, 0x2B, 0x4A, 0x97, 0x1F, 0xFB, 0xE5, 0x32, 0xF8, 0xEE, 0xFC, 0x23, 0xCB, + 0x54, 0xAC, 0x30, 0xC3, 0x88, 0x0A, 0x59, 0xDA, 0xE2, 0x56, 0x9E, 0x8C, 0xBC, 0xC4, 0xC9, 0x06, + 0x7F, 0x85, 0x44, 0x89, 0xE4, 0x0A, 0x09, 0xFB, 0x07, 0xAD, 0x17, 0x03, 0x44, 0x06, 0x0F, 0xA6, + 0x35, 0x20, 0xB1, 0xDE, 0x83, 0x2E, 0x93, 0x11, 0xA9, 0x34, 0xFB, 0x07, 0x04, 0xB2, 0x48, 0x25, + 0x9C, 0xB4, 0xC2, 0x84, 0x30, 0xAD, 0x28, 0xE9, 0x26, 0xAA, 0x4C, 0xB1, 0x00, 0x5A, 0xC9, 0xF7, + 0x0C, 0x4B, 0xBE, 0xCF, 0x6D, 0xE8, 0x5F, 0x4A, 0x17, 0x1E, 0x83, 0x05, 0x1D, 0xD3, 0x0D, 0x5B, + 0xB1, 0x38, 0x74, 0x4E, 0xF3, 0x6A, 0xAE, 0xE0, 0x96, 0x6C, 0x0A, 0xE2, 0x8E, 0xD6, 0x42, 0xB5, + 0x88, 0x0C, 0xAB, 0xEF, 0xF6, 0x2F, 0x5D, 0x03, 0xAD, 0x2B, 0x07, 0x61, 0x70, 0x64, 0xA5, 0x65, + 0x64, 0xB7, 0x75, 0xF2, 0x70, 0x61, 0x69, 0xAB, 0xAE, 0xC9, 0x94, 0x97, 0x38, 0x53, 0xA4, 0x2C, + 0x2C, 0xC2, 0xA2, 0xE9, 0xB9, 0xD7, 0x2C, 0x76, 0xC5, 0xA4, 0xDA, 0xA3, 0x48, 0xDC, 0x3F, 0x40, + 0x09, 0x48, 0xE3, 0xA4, 0xA7, 0x60, 0xF1, 0x53, 0x00, 0x03, 0x51, 0x68, 0xA1, 0xEB, 0x35, 0x72, + 0x9D, 0xC5, 0xF6, 0x12, 0x5B, 0xC9, 0x94, 0xFB, 0x07, 0xA2, 0x5D, 0x40, 0x19, 0xC8, 0x1B, 0x1A, + 0xF2, 0x7C, 0x8A, 0x51, 0xC6, 0x1F, 0xFC, 0xD5, 0xA4, 0x36, 0xA3, 0xAE, 0x35, 0x47, 0x42, 0xC2, + 0x53, 0x1B, 0xBD, 0x58, 0x65, 0xC9, 0xB3, 0xA7, 0x57, 0xEA, 0x17, 0x6C, 0x5B, 0x31, 0x88, 0x87, + 0xD3, 0x53, 0x2C, 0x0E, 0x3E, 0xA5, 0x8D, 0x0B, 0x93, 0x4A, 0xC1, 0x68, 0x3A, 0x3A, 0x71, 0x8C, + 0xC8, 0x1E, 0x50, 0x89, 0x12, 0x3C, 0xCC, 0xC8, 0x3C, 0x4A, 0x25, 0xA1, 0x8F, 0x1B, 0x4D, 0x91, + 0xF1, 0x6E, 0x35, 0xF9, 0x61, 0xD1, 0x18, 0x79, 0xD1, 0xDE, 0x52, 0x93, 0xF4, 0x44, 0x87, 0xF5, + 0x07, 0x58, 0xB2, 0xBC, 0x8D, 0x15, 0xB9, 0x2F, 0xA6, 0x6E, 0x0A, 0xC5, 0x33, 0x52, 0xCD, 0x01, + 0x9C, 0xFB, 0x07, 0x59, 0x5C, 0x67, 0xEA, 0x49, 0x64, 0x68, 0x01, 0xAA, 0x2B, 0x32, 0x19, 0xB5, + 0xB4, 0x95, 0x2B, 0xD8, 0xE5, 0x41, 0xB6, 0xD7, 0x99, 0x7A, 0x12, 0x67, 0xAF, 0xEB, 0x36, 0x09, + 0x42, 0x57, 0x64, 0x7A, 0xD8, 0xD2, 0x56, 0x56, 0xE0, 0xDC, 0x3F, 0x38, 0x47, 0xE4, 0x81, 0x44, + 0xF2, 0x38, 0x97, 0xE5, 0x81, 0x44, 0xD2, 0x48, 0x3C, 0x9F, 0x98, 0x17, 0x88, 0xDD, 0xC7, 0x64, + 0xF1, 0x89, 0xD9, 0x0C, 0x65, 0xEC, 0x99, 0x8A, 0xD9, 0x3D, 0x95, 0xD0, 0x3B, 0x31, 0xE2, 0x3F, + 0x94, 0x16, 0x39, 0x44, 0xDC, 0xFD, 0x59, 0x71, 0x08, 0xA6, 0xB4, 0x9F, 0x2B, 0xD5, 0x4C, 0x39, + 0x8F, 0x17, 0x34, 0x3E, 0xE0, 0x7B, 0x8B, 0x8C, 0x0C, 0x74, 0x7B, 0x6B, 0x99, 0x9D, 0x20, 0xF3, + 0x9B, 0x11, 0xEA, 0x06, 0x5D, 0xDA, 0x0C, 0x45, 0x4B, 0x86, 0x7C, 0x7B, 0x14, 0xF9, 0x88, 0x3D, + 0x53, 0x38, 0x77, 0xAB, 0xB9, 0x6C, 0x9B, 0xE6, 0x34, 0xEF, 0x98, 0x51, 0x3E, 0xF9, 0xD2, 0x44, + 0x31, 0x9D, 0x2A, 0x83, 0xD9, 0xC4, 0x49, 0x60, 0xED, 0x98, 0x88, 0xBB, 0xF5, 0x87, 0x88, 0x96, + 0x08, 0x30, 0x6D, 0xC9, 0x32, 0x25, 0xEF, 0x0C, 0xF1, 0x92, 0x34, 0xD2, 0xC6, 0x3D, 0x1A, 0xF6, + 0x44, 0xEF, 0xB6, 0x94, 0x01, 0x25, 0xE5, 0x1C, 0x97, 0xD1, 0xB1, 0xDC, 0xC7, 0x4B, 0x37, 0x4E, + 0xA6, 0xEC, 0x8F, 0xEB, 0xF7, 0x09, 0xE5, 0x41, 0xC6, 0xD7, 0x99, 0xE2, 0x11, 0xB4, 0xAC, 0xC9, + 0xA4, 0x06, 0xB1, 0x56, 0x24, 0xB6, 0x47, 0x91, 0x53, 0xEC, 0x99, 0x52, 0xA3, 0xE5, 0xC2, 0xD5, + 0xB2, 0xE2, 0x11, 0xCB, 0x23, 0x5A, 0x84, 0x58, 0xFD, 0x15, 0xF4, 0x3D, 0x7B, 0xFE, 0xF1, 0x65, + 0x6C, 0xB4, 0xB7, 0x76, 0xF3, 0x92, 0x4E, 0xB5, 0xFD, 0xB7, 0x77, 0x8B, 0x3C, 0x9B, 0x68, 0x89, + 0x00, 0x2D, 0x4D, 0x0A, 0x31, 0x25, 0x1F, 0x17, 0xEE, 0x26, 0x9C, 0xD6, 0x18, 0xFB, 0x6B, 0x36, + 0x23, 0x63, 0xF8, 0x72, 0xF2, 0x96, 0x02, 0x40, 0x82, 0xCE, 0x71, 0x11, 0xB6, 0x92, 0x8A, 0x9B, + 0x6E, 0xB2, 0x99, 0xD2, 0x90, 0x58, 0x1E, 0x64, 0x7C, 0x9D, 0xC9, 0x46, 0x90, 0xD6, 0x77, 0x1A, + 0x19, 0x51, 0xB1, 0x26, 0xA3, 0xED, 0x4E, 0xE2, 0x47, 0xA2, 0x34, 0xB3, 0x8D, 0x4B, 0xF8, 0x18, + 0x5B, 0x8E, 0xE1, 0x7B, 0x9B, 0x8C, 0xE5, 0x18, 0xE6, 0x49, 0x9B, 0xA1, 0xE8, 0x01, 0xB1, 0x3D, + 0x8A, 0x72, 0x24, 0xF6, 0x4C, 0x21, 0x84, 0xAB, 0xB4, 0xF9, 0x45, 0xBE, 0xB6, 0x43, 0xBA, 0xCE, + 0xF8, 0x85, 0xE9, 0x11, 0xD8, 0x02, 0x96, 0xBE, 0xB4, 0xC4, 0x97, 0xBD, 0xDC, 0x83, 0xC4, 0xC3, + 0x81, 0x05, 0xFF, 0xEB, 0x05, 0x7F, 0xFD, 0x9F, 0xC3, 0x3C, 0xCF, 0x06, 0xAD, 0x16, 0x11, 0x10, + 0xD2, 0xB7, 0x64, 0xE1, 0xFE, 0x1B, 0xE6, 0x2C, 0xE5, 0xB9, 0xB6, 0x2C, 0x5A, 0x89, 0x45, 0x24, + 0x7C, 0xC9, 0xFB, 0x50, 0x01, 0xEF, 0xC8, 0xDA, 0x66, 0xA8, 0xB9, 0xC2, 0xCB, 0x53, 0xE3, 0xCB, + 0x54, 0x8C, 0x3C, 0xBE, 0xAF, 0xB1, 0x50, 0x85, 0x04, 0x49, 0x59, 0xCF, 0x88, 0xCB, 0x96, 0xA2, + 0x68, 0x2A, 0x75, 0xBB, 0xEB, 0x5D, 0x6B, 0x49, 0x69, 0xAF, 0xCD, 0xE2, 0xF0, 0xD2, 0x62, 0xCB, + 0x5E, 0x0D, 0x46, 0xA6, 0x44, 0xA0, 0x9E, 0x0D, 0x9E, 0x88, 0xE9, 0x9E, 0xBD, 0xAD, 0xB3, 0x3C, + 0xC8, 0xD6, 0x3A, 0x93, 0x9D, 0x20, 0xAD, 0xED, 0x70, 0xA2, 0x7C, 0x4D, 0x46, 0x5F, 0x6B, 0x11, + 0xA9, 0x20, 0xFD, 0x6D, 0x38, 0x13, 0x4F, 0xDE, 0xAF, 0xD1, 0x83, 0xF8, 0x48, 0xFB, 0xB0, 0x87, + 0x79, 0x14, 0x72, 0xA0, 0xA7, 0xB1, 0x80, 0x43, 0xE1, 0x2C, 0x47, 0xAF, 0xB1, 0x09, 0x1D, 0x9A, + 0xE2, 0x41, 0x17, 0x8B, 0x5A, 0x2E, 0xD6, 0x76, 0x70, 0x1D, 0x00, 0xDF, 0x42, 0x8B, 0x50, 0x7C, + 0xC0, 0x58, 0x5A, 0xE2, 0x4B, 0x44, 0x18, 0x99, 0x2D, 0x0C, 0x89, 0x99, 0x1D, 0x24, 0x48, 0x8B, + 0x07, 0x2C, 0xCF, 0x06, 0x2D, 0xBE, 0xDC, 0x81, 0xBF, 0x22, 0x4D, 0x0A, 0xE1, 0x4E, 0x91, 0x6B, + 0xA4, 0x6A, 0x2C, 0x5A, 0xD1, 0x12, 0x16, 0xD2, 0x64, 0xD3, 0x5B, 0x8B, 0xD5, 0xE7, 0xCE, 0x7E, + 0xA6, 0xF3, 0xA9, 0x87, 0x45, 0x08, 0x5F, 0xA6, 0x62, 0xE4, 0x79, 0xC1, 0x72, 0x7F, 0x16, 0xD1, + 0x88, 0xCB, 0x5E, 0x93, 0xE8, 0xB1, 0x52, 0xB7, 0x96, 0x14, 0x55, 0x03, 0xE5, 0x85, 0xC7, 0x61, + 0xA5, 0xD5, 0xC8, 0x97, 0xBD, 0x8C, 0x4C, 0x19, 0x04, 0x78, 0x36, 0x62, 0xB2, 0xC5, 0x5F, 0xC2, + 0x71, 0x7D, 0x21, 0x5B, 0xEB, 0x4C, 0x76, 0x82, 0xDA, 0x7A, 0x91, 0x36, 0xF7, 0x66, 0xCC, 0xEB, + 0x31, 0x47, 0x1B, 0x5E, 0xDB, 0xCB, 0xAA, 0xB9, 0x37, 0x96, 0x81, 0x75, 0xEA, 0x4F, 0x78, 0x8A, + 0x29, 0x4A, 0xD3, 0x44, 0x1C, 0xA7, 0x63, 0x72, 0x61, 0x9D, 0xF1, 0x65, 0x2D, 0x2C, 0xA0, 0x75, + 0xC8, 0x28, 0x5A, 0x04, 0x2D, 0x1F, 0xC4, 0x11, 0xDA, 0x95, 0x4D, 0x10, 0x5A, 0xF8, 0x80, 0xE7, + 0xD9, 0x44, 0x4B, 0xE3, 0x03, 0x2D, 0x4D, 0x3D, 0x3D, 0xC1, 0x07, 0xE2, 0x61, 0xCB, 0xA2, 0x15, + 0xF3, 0xB8, 0xA8, 0xE5, 0x4A, 0xF5, 0x47, 0xC7, 0x7E, 0xC4, 0x5E, 0x44, 0x84, 0x50, 0x5D, 0x21, + 0x79, 0x1E, 0x83, 0xFB, 0x33, 0x5E, 0x30, 0xE2, 0xB2, 0x58, 0x2C, 0xAE, 0x9B, 0x05, 0x99, 0x4B, + 0xCA, 0x9C, 0x2E, 0x8B, 0x83, 0x53, 0x9F, 0x7C, 0xD9, 0xCB, 0x29, 0xD0, 0x9C, 0x88, 0x29, 0x5B, + 0xEC, 0x1D, 0x9C, 0xE7, 0x13, 0xB3, 0xB8, 0xCE, 0x14, 0x87, 0x20, 0x87, 0x6D, 0x77, 0x12, 0x2E, + 0x47, 0x31, 0xD0, 0x52, 0x01, 0x58, 0xF6, 0x36, 0xD9, 0xA1, 0x6F, 0x8F, 0x22, 0xE0, 0x9E, 0x29, + 0xAB, 0x0B, 0x5B, 0x59, 0xDE, 0x1F, 0x10, 0x3B, 0xA6, 0x8C, 0x08, 0x08, 0xBE, 0xEA, 0xA3, 0x5D, + 0x5B, 0x68, 0x33, 0x9D, 0x89, 0x24, 0x6B, 0xA0, 0x59, 0x9E, 0x75, 0x5A, 0xC3, 0x44, 0x00, 0xFF, + 0x65, 0xA9, 0x7C, 0x64, 0x4E, 0xDE, 0x46, 0xD9, 0xB8, 0x77, 0x37, 0xFC, 0xE5, 0x32, 0xAC, 0xF2, + 0xFF, 0x1D, 0x6C, 0x0B, 0x41, 0xF2, 0xE2, 0x71, 0xD1, 0x6B, 0xC1, 0x3D, 0x5E, 0x46, 0x5C, 0x13, + 0x3D, 0xD3, 0x7E, 0x2E, 0x5E, 0x52, 0x96, 0xD7, 0x16, 0x10, 0xCB, 0x5E, 0xF1, 0x32, 0x25, 0x12, + 0xB1, 0x2F, 0x73, 0x25, 0xEC, 0x1F, 0x64, 0x7C, 0x9D, 0x29, 0x96, 0x20, 0x41, 0x2C, 0x03, 0x21, + 0x8C, 0xDD, 0x49, 0x2C, 0x15, 0x72, 0xD0, 0xC6, 0xA5, 0x48, 0xE3, 0x6A, 0x5A, 0x8E, 0x61, 0x8F, + 0xE8, 0xCB, 0x31, 0x6E, 0xE6, 0x29, 0xBA, 0x7A, 0xDA, 0xF6, 0x28, 0x9E, 0x23, 0xB1, 0x67, 0x4A, + 0x73, 0x05, 0xC6, 0xDF, 0x5A, 0x2C, 0x96, 0x93, 0xD8, 0x8E, 0x29, 0x73, 0x04, 0x46, 0x46, 0xBB, + 0x22, 0x4A, 0xDF, 0x18, 0x2B, 0xD8, 0xDB, 0xBF, 0x1E, 0x35, 0x8F, 0x02, 0xE3, 0xAF, 0xE8, 0x10, + 0x79, 0xD6, 0x69, 0xF5, 0x15, 0x01, 0x7D, 0x8D, 0x2D, 0x59, 0x1B, 0xB8, 0xF3, 0x84, 0x9E, 0x6B, + 0x83, 0xB2, 0x06, 0x0C, 0xF2, 0x2F, 0x9B, 0x7F, 0x07, 0x14, 0xFD, 0xF3, 0x0C, 0xAF, 0x11, 0xB2, + 0x75, 0x72, 0xA9, 0x46, 0x9E, 0x2D, 0x54, 0x09, 0xFF, 0x3E, 0xBF, 0xB6, 0xC4, 0xD5, 0x96, 0xA2, + 0x68, 0x3F, 0x97, 0x78, 0x90, 0x97, 0x94, 0x8F, 0xA7, 0x7B, 0x4A, 0x5F, 0xAE, 0xDA, 0x35, 0xAC, + 0x4C, 0x3B, 0x60, 0x46, 0xCB, 0x94, 0x11, 0xC8, 0xB3, 0x11, 0x93, 0x2D, 0xF6, 0x9B, 0xB8, 0x7F, + 0x90, 0xE9, 0x75, 0x26, 0x3B, 0x41, 0x2E, 0xBA, 0x68, 0x19, 0x88, 0x9A, 0x00, 0x14, 0x52, 0xB8, + 0xD6, 0xC2, 0x25, 0x33, 0x5F, 0x2A, 0x42, 0x11, 0xC6, 0x96, 0x61, 0xD8, 0x72, 0x0C, 0x5F, 0x27, + 0x32, 0x96, 0x63, 0xB8, 0xA7, 0x26, 0xD9, 0x68, 0x25, 0x07, 0x5B, 0x1C, 0x96, 0xA3, 0x6D, 0x2E, + 0x92, 0x7D, 0x94, 0x10, 0x73, 0x91, 0x43, 0xAC, 0x09, 0x89, 0x36, 0x73, 0x9B, 0xCB, 0x68, 0x4D, + 0x8C, 0x55, 0x1F, 0xDE, 0x4C, 0xBD, 0x46, 0xEB, 0x49, 0x2C, 0x98, 0x2D, 0x32, 0xE9, 0x79, 0x36, + 0x68, 0x69, 0x01, 0x22, 0x4D, 0x0C, 0x99, 0x2D, 0x9C, 0x2C, 0xD7, 0xE2, 0x55, 0x04, 0x65, 0xAD, + 0x95, 0xC0, 0x57, 0xA6, 0xDE, 0x00, 0x7A, 0x52, 0x97, 0x88, 0x85, 0xF0, 0x2C, 0x31, 0xF2, 0x22, + 0x86, 0xB6, 0x72, 0x45, 0x04, 0x4D, 0x71, 0xF5, 0xA5, 0xA8, 0xF6, 0x61, 0xF6, 0x92, 0x12, 0xAF, + 0xCD, 0xE2, 0xB0, 0xD2, 0xC2, 0xEC, 0xB0, 0x65, 0x2F, 0x23, 0x53, 0x66, 0x02, 0x7A, 0x22, 0xE6, + 0x6C, 0xB1, 0xF2, 0xEB, 0xA2, 0x7F, 0xD0, 0xF3, 0xA0, 0x4E, 0x8E, 0x80, 0xA5, 0xD5, 0x4F, 0x01, + 0xAC, 0x51, 0xB7, 0xB9, 0xE2, 0x44, 0x48, 0x01, 0xF1, 0x1F, 0x4A, 0x8B, 0x5C, 0x22, 0x24, 0x47, + 0xD0, 0x54, 0x52, 0x04, 0xAD, 0xB4, 0x84, 0x0A, 0x54, 0x6A, 0x99, 0xEA, 0xAA, 0x7F, 0xD0, 0xC3, + 0xC8, 0xCC, 0xEE, 0x24, 0x63, 0x8B, 0x54, 0x9C, 0xCD, 0x52, 0x69, 0xED, 0xA1, 0x8A, 0xFF, 0x50, + 0x37, 0xB7, 0x64, 0xC5, 0x22, 0x09, 0x82, 0xF1, 0x4B, 0x4A, 0x2C, 0x7B, 0xA5, 0x98, 0xA9, 0xA0, + 0x05, 0xC2, 0xDE, 0xB2, 0x5C, 0x67, 0xEA, 0x6D, 0xD0, 0x7B, 0x04, 0x0C, 0xEF, 0x88, 0xFD, 0x8D, + 0x72, 0x3F, 0x53, 0xEF, 0x83, 0x93, 0x99, 0xF7, 0x9C, 0xDB, 0xCD, 0x23, 0x48, 0x3B, 0x79, 0x39, + 0x87, 0xB4, 0x9B, 0x27, 0x41, 0xC8, 0xA9, 0xDD, 0x3C, 0xDC, 0x26, 0xF0, 0x5C, 0xDA, 0xFA, 0xAF, + 0x12, 0x99, 0x44, 0x4F, 0xDA, 0xCD, 0x7B, 0xDA, 0x6E, 0x37, 0xEF, 0x87, 0x64, 0x37, 0x8F, 0xAF, + 0x26, 0xF1, 0xF5, 0x25, 0xB6, 0xF3, 0x07, 0x9F, 0x92, 0xF6, 0xF2, 0xB2, 0x88, 0x77, 0x6A, 0x6B, + 0x0D, 0x68, 0x9E, 0xD9, 0xEB, 0x27, 0x56, 0xBC, 0x4E, 0x57, 0xB2, 0x9B, 0x47, 0xC7, 0x80, 0x33, + 0x0F, 0x7F, 0x3D, 0xEE, 0xF2, 0xA5, 0x9D, 0xBE, 0xEB, 0x7E, 0xF5, 0x43, 0xCD, 0x6E, 0xDE, 0x37, + 0xC7, 0x3F, 0x70, 0x7F, 0xEB, 0xA7, 0x82, 0x13, 0x1E, 0xB8, 0x7F, 0xF3, 0xB5, 0x55, 0x4F, 0x2E, + 0x12, 0x7B, 0x92, 0x83, 0xFB, 0xCA, 0xB7, 0xCF, 0xFD, 0x02, 0x1A, 0xD1, 0xDB, 0xFE, 0xF5, 0xEF, + 0x61, 0x50, 0xEB, 0xA7, 0x52, 0x4F, 0x5F, 0xC2, 0x19, 0x89, 0xF7, 0x3B, 0xA7, 0x30, 0x11, 0x91, + 0x24, 0x68, 0xA5, 0x0B, 0x53, 0x35, 0x16, 0x38, 0xF4, 0xA5, 0xAB, 0x4E, 0x9A, 0x17, 0xA1, 0x55, + 0x20, 0x5A, 0x2C, 0x31, 0xAD, 0xD8, 0xB0, 0x25, 0x12, 0x2D, 0x2A, 0x5B, 0x76, 0x32, 0x2F, 0xE6, + 0xA4, 0x95, 0x09, 0x89, 0x18, 0x04, 0x02, 0x16, 0x4C, 0xC8, 0xF6, 0x3C, 0x52, 0x8A, 0x76, 0xF3, + 0xE2, 0x42, 0xDA, 0xCB, 0xCB, 0x30, 0x7C, 0x3E, 0x13, 0xB4, 0x86, 0x21, 0xE7, 0x76, 0xF3, 0xF8, + 0x6A, 0x12, 0xDF, 0xEE, 0x33, 0x9E, 0x76, 0xFE, 0x80, 0x6E, 0x2F, 0xEF, 0x93, 0x2C, 0xBA, 0xB4, + 0x97, 0x97, 0x69, 0x38, 0xD9, 0x5B, 0xCF, 0xE2, 0xFA, 0x82, 0x58, 0xE2, 0x51, 0x4D, 0x8B, 0x34, + 0x4C, 0xBE, 0xD3, 0x82, 0x07, 0x5B, 0x05, 0x22, 0x7F, 0x58, 0xCC, 0x57, 0x93, 0xC4, 0x52, 0x12, + 0xDB, 0xF9, 0xC3, 0xF5, 0x0F, 0xCC, 0xBB, 0x7F, 0xC4, 0x7E, 0x28, 0x89, 0x0C, 0x80, 0x2A, 0xDC, + 0x40, 0x95, 0x68, 0x17, 0xF2, 0xD3, 0x6E, 0x9E, 0xB4, 0x97, 0x97, 0x3D, 0xE8, 0x2A, 0x07, 0x0C, + 0x05, 0x64, 0x37, 0x4F, 0xDA, 0xCB, 0xEB, 0x01, 0x64, 0x73, 0x7D, 0xE1, 0x5B, 0x5D, 0x7A, 0xC4, + 0x43, 0xE9, 0x2E, 0xD3, 0xCD, 0xA2, 0x1E, 0x3E, 0xAF, 0xBF, 0x17, 0x40, 0x58, 0xD4, 0x35, 0x99, + 0x55, 0x95, 0xFB, 0x99, 0x7A, 0x23, 0x38, 0x03, 0x98, 0xAD, 0xEB, 0x4A, 0x3E, 0xE8, 0x95, 0x20, + 0x16, 0xB0, 0x18, 0x59, 0x96, 0x7C, 0xD0, 0x3B, 0x11, 0xB0, 0xD9, 0xDA, 0x96, 0x7C, 0xD0, 0x4B, + 0x61, 0x33, 0xB9, 0x2E, 0xF9, 0x40, 0x82, 0x20, 0xF9, 0x40, 0x82, 0x20, 0xF9, 0x40, 0x82, 0x20, + 0xF5, 0x13, 0x7B, 0x1D, 0x72, 0x62, 0x6F, 0x5D, 0x22, 0xDF, 0xE0, 0xAC, 0x7F, 0xC0, 0xF9, 0xA0, + 0xC6, 0x49, 0x85, 0x55, 0xE2, 0x9C, 0x04, 0x3F, 0xE7, 0xDF, 0x0E, 0xC6, 0x07, 0xB3, 0x93, 0xA7, + 0x22, 0x71, 0x6E, 0x82, 0xF1, 0x81, 0x94, 0x06, 0xBD, 0x1E, 0x72, 0xBC, 0x20, 0x41, 0x90, 0x7C, + 0x20, 0x41, 0x60, 0xED, 0x82, 0xAE, 0xBD, 0x9C, 0x3D, 0xCC, 0xC6, 0xB6, 0xA7, 0x07, 0x92, 0x91, + 0x48, 0x1D, 0x54, 0x35, 0x62, 0xBC, 0x70, 0x7B, 0x37, 0xC8, 0x24, 0x05, 0xDE, 0x49, 0xCD, 0x7A, + 0x32, 0x12, 0xA9, 0x83, 0x57, 0x8D, 0x98, 0x3F, 0x70, 0x1E, 0x4C, 0x24, 0x85, 0x54, 0x8E, 0xDA, + 0xED, 0x46, 0x32, 0x16, 0xC8, 0xE3, 0x7D, 0x33, 0x8D, 0x0C, 0xCC, 0x23, 0x39, 0xE9, 0x36, 0x66, + 0x7B, 0x04, 0x22, 0xF7, 0xE9, 0xA7, 0x0D, 0xE7, 0xAA, 0xC9, 0xD6, 0x7C, 0xA2, 0x65, 0x93, 0x3D, + 0x54, 0x64, 0x4A, 0x10, 0x48, 0x74, 0x1F, 0x8E, 0x55, 0x93, 0xB5, 0x79, 0x65, 0x8B, 0x52, 0x6C, + 0x9A, 0x34, 0x24, 0xB2, 0x02, 0xA7, 0xAA, 0x91, 0xE3, 0x46, 0x09, 0x42, 0x97, 0x7C, 0x50, 0x35, + 0x54, 0xB7, 0x75, 0x97, 0x08, 0xE9, 0x9A, 0x22, 0xEF, 0x1E, 0x9C, 0x0D, 0x68, 0xD8, 0x7C, 0xA5, + 0x95, 0x8D, 0x24, 0x60, 0xE6, 0x83, 0x2E, 0x6A, 0x1C, 0x39, 0x22, 0x3E, 0x53, 0x30, 0xAB, 0xDF, + 0xC9, 0xA1, 0xD4, 0xEF, 0x2F, 0x79, 0xDC, 0x39, 0x28, 0x86, 0x7E, 0xC2, 0x34, 0x01, 0xB6, 0x5E, + 0xE1, 0x64, 0xB5, 0xDB, 0xD9, 0x57, 0x22, 0x11, 0x52, 0x68, 0x17, 0xE6, 0x9C, 0xB4, 0x59, 0x04, + 0x37, 0x83, 0xAC, 0x5C, 0x24, 0x49, 0xC7, 0xDF, 0x10, 0x78, 0x73, 0x75, 0x92, 0x7B, 0x16, 0x13, + 0xA6, 0x09, 0x70, 0xE0, 0xFB, 0xC9, 0xFB, 0x4A, 0x24, 0x42, 0x0C, 0x1F, 0x54, 0x95, 0xFA, 0xFB, + 0x9F, 0x80, 0xE0, 0x79, 0x7E, 0xFF, 0xAA, 0x67, 0x8C, 0x0F, 0x17, 0x9D, 0x03, 0x5F, 0x1F, 0x7A, + 0xEC, 0xD6, 0xD6, 0xF2, 0xB9, 0x18, 0x01, 0x7D, 0xAB, 0xFA, 0x5A, 0x3F, 0x69, 0xB2, 0xFA, 0x6D, + 0xA3, 0xE4, 0xF7, 0x33, 0xC4, 0xA6, 0x09, 0x50, 0x39, 0x90, 0x25, 0x54, 0xF2, 0x78, 0xD5, 0x90, + 0x51, 0xFE, 0x07, 0xC6, 0xF9, 0x57, 0x89, 0x64, 0x0D, 0xFA, 0xC9, 0xA4, 0x09, 0x81, 0xD5, 0x1D, + 0xC6, 0x29, 0xBE, 0x68, 0x3A, 0x63, 0xF9, 0x6A, 0xB2, 0xA2, 0x41, 0xBE, 0x21, 0xDA, 0x2C, 0xBB, + 0x56, 0x58, 0x58, 0xE7, 0xD6, 0xCE, 0xF9, 0x59, 0xC1, 0x18, 0x5D, 0x33, 0xB6, 0xD1, 0x8B, 0x11, + 0x5B, 0x35, 0x76, 0x3E, 0x08, 0xDE, 0xB0, 0x2C, 0xF0, 0xE3, 0x9B, 0x60, 0xD2, 0x5D, 0x81, 0xC0, + 0x7D, 0x0B, 0x03, 0x81, 0xBF, 0x6C, 0x62, 0xBE, 0x55, 0x4B, 0x0E, 0x05, 0xD6, 0x46, 0xA0, 0xF8, + 0xC5, 0xD2, 0x86, 0x57, 0x6F, 0xAB, 0x0F, 0xBC, 0xB9, 0x26, 0x56, 0x54, 0x57, 0x34, 0xDB, 0x7D, + 0x62, 0x37, 0x4B, 0xE8, 0xD8, 0xF5, 0xB1, 0x27, 0xC8, 0xE8, 0x9C, 0xEE, 0xF8, 0xF6, 0x96, 0x35, + 0x77, 0x6D, 0x59, 0x7B, 0x94, 0x27, 0x6B, 0xA6, 0x9F, 0x44, 0x9A, 0xBB, 0x86, 0x97, 0xD5, 0xB6, + 0x04, 0x87, 0xCF, 0x53, 0xD5, 0xAD, 0x37, 0x42, 0xB0, 0x6A, 0xDB, 0xAA, 0x2F, 0x6D, 0x7B, 0x29, + 0x84, 0xBE, 0x23, 0x9B, 0x9A, 0xB6, 0x8E, 0x79, 0x3A, 0xF0, 0xBF, 0x7D, 0x26, 0x35, 0xA8, 0x67, + 0x3F, 0x17, 0x0E, 0x56, 0xA9, 0xAF, 0x5E, 0xD3, 0x7C, 0x53, 0xA3, 0xFA, 0x9D, 0xA6, 0xDA, 0xF6, + 0xE0, 0xF0, 0x27, 0x17, 0xA9, 0xEC, 0x3C, 0x8F, 0x5E, 0x8C, 0xD8, 0xAA, 0xB1, 0x8F, 0x1B, 0x6B, + 0x3A, 0xEF, 0x82, 0x69, 0xFB, 0x5E, 0x6D, 0xBD, 0x0B, 0xDD, 0x55, 0x73, 0x23, 0xE0, 0x3B, 0x4D, + 0xBE, 0x95, 0xFE, 0x89, 0xFB, 0xEF, 0xE4, 0x5B, 0x4D, 0x6B, 0x4E, 0x8C, 0x05, 0x28, 0x0A, 0xCF, + 0x69, 0xB1, 0x3D, 0x78, 0xE9, 0xD2, 0x90, 0xBD, 0x55, 0x0E, 0x20, 0xC3, 0x39, 0xB0, 0x41, 0xA0, + 0x1C, 0x7C, 0x07, 0x06, 0x57, 0x31, 0x3A, 0x11, 0xDF, 0xC2, 0x0F, 0xFA, 0x2C, 0xFC, 0xC0, 0xB3, + 0x97, 0x25, 0x4B, 0x8D, 0x85, 0xA0, 0x9F, 0x54, 0x9A, 0xD5, 0x37, 0xC2, 0xD4, 0x65, 0x00, 0xAD, + 0x03, 0x22, 0x50, 0x19, 0x9E, 0x52, 0x36, 0x60, 0x5A, 0xD9, 0x00, 0xE4, 0xEB, 0xEA, 0xEB, 0x70, + 0x23, 0xE5, 0x91, 0x57, 0xBE, 0xF4, 0xFD, 0x76, 0xA5, 0x71, 0x04, 0x40, 0x71, 0x13, 0x5A, 0x6B, + 0xBE, 0xB4, 0xBE, 0xB9, 0x74, 0xEC, 0xA1, 0xAF, 0xB6, 0x4E, 0x5D, 0x02, 0xAD, 0x2F, 0xC8, 0x3D, + 0xB3, 0xB1, 0x55, 0x93, 0xA0, 0x7F, 0x50, 0xF5, 0x99, 0xE5, 0x81, 0xB7, 0x38, 0x9F, 0xF8, 0x8E, + 0x9E, 0xB8, 0xA0, 0xFF, 0x29, 0xEE, 0x8D, 0xCD, 0x7B, 0xE0, 0x4C, 0xEC, 0x59, 0xB5, 0x26, 0x2B, + 0x17, 0x3A, 0xEC, 0x9B, 0x25, 0x34, 0x02, 0x6F, 0x29, 0x58, 0xCF, 0x8C, 0xCE, 0x10, 0xA7, 0x60, + 0x4E, 0x3F, 0x89, 0x34, 0xDB, 0xBE, 0x4C, 0x57, 0xBB, 0x41, 0xF7, 0xB6, 0x3B, 0x60, 0xC2, 0xCF, + 0x9F, 0x1F, 0x3D, 0xFF, 0x2F, 0xD7, 0x98, 0x0D, 0x8E, 0x33, 0xBB, 0xF1, 0xD2, 0x92, 0x82, 0x86, + 0xAE, 0xF6, 0xB1, 0x54, 0x16, 0xFD, 0x1C, 0xF6, 0x4C, 0xBA, 0xBA, 0xF4, 0xE7, 0xE8, 0xF6, 0x2D, + 0x84, 0x3D, 0x7C, 0x87, 0x72, 0xD5, 0x75, 0xBE, 0xA3, 0x83, 0x69, 0xCF, 0x71, 0x24, 0x4C, 0x11, + 0xC8, 0xC7, 0xDE, 0x56, 0x6B, 0x56, 0x2E, 0x2C, 0x70, 0x6C, 0x14, 0x00, 0xE6, 0xFC, 0xEF, 0xC4, + 0x13, 0x82, 0x8E, 0xC0, 0x14, 0x96, 0x6C, 0x99, 0x41, 0x1F, 0x92, 0x48, 0xB3, 0xF5, 0x79, 0xBE, + 0x8D, 0x9E, 0x59, 0x67, 0xE7, 0x16, 0xFB, 0x99, 0x2F, 0x7E, 0xFE, 0x2F, 0xCC, 0xF0, 0xCE, 0x5E, + 0x76, 0x87, 0xC5, 0xDA, 0x39, 0x3B, 0x2B, 0x18, 0x9D, 0xA5, 0xB7, 0x99, 0xAD, 0x90, 0xF7, 0x5A, + 0x24, 0xD8, 0xC7, 0x12, 0x28, 0xF7, 0xF7, 0x3F, 0xF3, 0xFB, 0xD5, 0xFE, 0xC5, 0x1B, 0xE1, 0xC5, + 0xD5, 0x7E, 0xFF, 0xE6, 0x15, 0xE5, 0xFE, 0x7B, 0xB9, 0x3C, 0xA8, 0xAC, 0xF6, 0xFB, 0xC7, 0xDC, + 0x01, 0x30, 0x67, 0xD5, 0xD8, 0xAB, 0x31, 0x82, 0x7F, 0xA0, 0xC3, 0x50, 0x6E, 0xD6, 0x1F, 0x9C, + 0x92, 0x73, 0xC6, 0x45, 0x3F, 0x1E, 0xF7, 0x53, 0x46, 0x87, 0xB5, 0x3A, 0x08, 0x1F, 0x4F, 0xD6, + 0x4C, 0xBF, 0xEB, 0x34, 0xC5, 0xF8, 0xB0, 0xF4, 0xAB, 0x45, 0xCA, 0xED, 0x2E, 0xED, 0x04, 0x07, + 0xE6, 0xEB, 0x6E, 0xFB, 0x3E, 0x14, 0x79, 0xCA, 0xFC, 0xF5, 0x2B, 0xB0, 0x73, 0x18, 0xAE, 0x2D, + 0x52, 0x96, 0x6C, 0x73, 0xFF, 0xBB, 0xA2, 0x7C, 0x34, 0x91, 0x22, 0x2C, 0x42, 0xCF, 0x5E, 0xDE, + 0x4F, 0x8C, 0x85, 0xB0, 0x83, 0xD1, 0x9D, 0xF5, 0x46, 0xB1, 0xE6, 0x63, 0xB1, 0x72, 0xE1, 0x64, + 0x6C, 0xA1, 0x7B, 0xC9, 0x58, 0xC0, 0xD3, 0x5C, 0x77, 0xF6, 0x87, 0x0E, 0x61, 0xCE, 0xBE, 0x12, + 0x1A, 0x9C, 0xED, 0x60, 0x64, 0x6E, 0x7D, 0x21, 0xE3, 0xA6, 0xC8, 0xBB, 0x42, 0xE0, 0x31, 0xA7, + 0x0E, 0x9F, 0xB3, 0xAF, 0x44, 0x17, 0xC8, 0xE0, 0x3A, 0x53, 0xD2, 0x56, 0x2E, 0x32, 0x04, 0xFF, + 0x91, 0xE4, 0x7D, 0x25, 0xBA, 0x80, 0x5C, 0x67, 0x92, 0x20, 0x64, 0x6B, 0xDD, 0xD9, 0x71, 0xF3, + 0x94, 0x44, 0x3E, 0xA0, 0x27, 0xF7, 0xB5, 0x49, 0xC5, 0xB1, 0xBC, 0x45, 0xA2, 0x7D, 0x6D, 0x9A, + 0xE1, 0xA4, 0x74, 0x30, 0x41, 0x9C, 0xEC, 0x92, 0x0C, 0xBA, 0x91, 0x8C, 0x05, 0xA9, 0xA4, 0x29, + 0x91, 0x0C, 0x04, 0x1F, 0xA8, 0xDD, 0xA1, 0xE1, 0x00, 0x9B, 0x12, 0x9C, 0xC6, 0x83, 0x71, 0x92, + 0x09, 0x44, 0x58, 0x37, 0x25, 0x1A, 0xAE, 0x9B, 0xE2, 0x93, 0x1D, 0x96, 0x1E, 0x06, 0xAF, 0xAA, + 0x1E, 0xD1, 0x4F, 0xEC, 0xAA, 0xB3, 0xA0, 0xBA, 0xFD, 0xED, 0xB0, 0x77, 0xAA, 0xDB, 0x3D, 0x15, + 0x82, 0x25, 0x5D, 0xC4, 0x95, 0xC8, 0x0A, 0x12, 0xF2, 0xC1, 0x3E, 0xFE, 0xD3, 0x6F, 0x08, 0xC5, + 0x0A, 0x9F, 0x6A, 0xE1, 0x06, 0x8F, 0x93, 0x43, 0x6A, 0x1A, 0xCB, 0x01, 0xAC, 0xFE, 0x77, 0x68, + 0xBB, 0xED, 0xDE, 0x44, 0x47, 0xEA, 0x4B, 0x64, 0x0D, 0x89, 0xE5, 0xC1, 0xE7, 0xF1, 0xDF, 0xD7, + 0x51, 0x0C, 0xFD, 0x5A, 0x14, 0xE8, 0xE7, 0xFA, 0x89, 0x73, 0x24, 0xBB, 0x11, 0xDC, 0xB4, 0x40, + 0x0B, 0x60, 0x98, 0x90, 0xD9, 0x2B, 0x23, 0x74, 0x25, 0x92, 0x83, 0x95, 0x0F, 0x74, 0x01, 0xAE, + 0xED, 0x84, 0x1F, 0xEE, 0x9A, 0x5D, 0x4D, 0xBF, 0x74, 0x44, 0xFE, 0x34, 0x85, 0x5C, 0xB4, 0xC8, + 0x0B, 0x2B, 0x63, 0xD7, 0xEF, 0x53, 0xA9, 0xB5, 0x98, 0x64, 0x38, 0xEA, 0xA6, 0x46, 0x59, 0x12, + 0x02, 0x52, 0xBD, 0xAC, 0x07, 0x61, 0x93, 0x07, 0xA2, 0x62, 0x8C, 0x06, 0x5D, 0x61, 0x6C, 0xD0, + 0x7C, 0x45, 0xF5, 0x2C, 0x88, 0xF0, 0x5E, 0xDE, 0x54, 0x3C, 0x52, 0x65, 0x00, 0x74, 0x4F, 0x91, + 0x23, 0x26, 0x19, 0x44, 0x40, 0xA9, 0x50, 0xCD, 0x6C, 0x20, 0xD5, 0xCB, 0x7A, 0x12, 0x5D, 0x74, + 0xCF, 0xDD, 0xF8, 0xF1, 0x43, 0x5B, 0xDB, 0x25, 0x81, 0xD9, 0x2E, 0x2F, 0xE8, 0xB5, 0x54, 0xDA, + 0xFC, 0x72, 0x88, 0xAB, 0x7C, 0x91, 0xB2, 0x17, 0x2E, 0x2B, 0x6C, 0x77, 0x1D, 0x59, 0xB7, 0xBB, + 0xE8, 0x6E, 0x76, 0xC8, 0x12, 0x3B, 0x5B, 0x49, 0x44, 0x4C, 0x7E, 0x9C, 0x88, 0x3C, 0xE6, 0x63, + 0x8B, 0x47, 0xFA, 0xA9, 0x1B, 0x81, 0xD5, 0xD2, 0x66, 0x4F, 0xCF, 0x21, 0x21, 0x1F, 0x44, 0xEB, + 0x9A, 0x5B, 0x90, 0x0B, 0x94, 0x39, 0xEF, 0x95, 0x78, 0xD4, 0x88, 0xA9, 0xF5, 0x76, 0x37, 0x1D, + 0x65, 0x2A, 0x5F, 0x5C, 0xD9, 0x0B, 0xDA, 0xAE, 0x3C, 0x36, 0x6A, 0xD1, 0xF4, 0xCE, 0x55, 0xE3, + 0x57, 0xAA, 0x9B, 0xAE, 0x45, 0x05, 0x31, 0x95, 0x8E, 0x4C, 0x40, 0xF8, 0x53, 0x60, 0x84, 0x28, + 0x5B, 0x11, 0xDF, 0x0B, 0x4C, 0xFE, 0x10, 0xF8, 0x01, 0x4E, 0x12, 0x3D, 0x03, 0x3B, 0x1F, 0xE0, + 0x51, 0x8B, 0xEC, 0x6B, 0x7E, 0x87, 0xE0, 0xAA, 0x28, 0xF5, 0xB6, 0xA1, 0x18, 0xC0, 0x9E, 0x7C, + 0xD8, 0xE3, 0xB5, 0x8C, 0xFE, 0x23, 0x8D, 0x23, 0x94, 0xBE, 0xEF, 0xA3, 0xB2, 0xD7, 0xF1, 0xAF, + 0x96, 0xD5, 0x0E, 0xAF, 0x67, 0x55, 0x16, 0x19, 0xB1, 0x04, 0x2E, 0x7D, 0xEF, 0x04, 0xAA, 0x85, + 0xCC, 0x60, 0x71, 0x88, 0x09, 0xE2, 0x30, 0x82, 0x25, 0x19, 0x00, 0x55, 0x65, 0xE3, 0x8B, 0xBD, + 0x7B, 0x61, 0x96, 0x1E, 0xA5, 0xFA, 0x3A, 0xE7, 0x47, 0x25, 0xB2, 0x01, 0x3B, 0x1F, 0xB0, 0x23, + 0x3B, 0xF0, 0x77, 0x36, 0x03, 0x9C, 0x45, 0x95, 0x40, 0x5E, 0xFD, 0x18, 0xD1, 0x68, 0xBD, 0x23, + 0x83, 0x07, 0x33, 0x95, 0xAF, 0xB1, 0x4C, 0xD9, 0x6B, 0xEA, 0x6F, 0xAE, 0x75, 0x22, 0xCD, 0x59, + 0xC0, 0x99, 0x11, 0x6C, 0xC9, 0x18, 0x94, 0x0D, 0x5E, 0x43, 0xF5, 0x32, 0xC7, 0x47, 0x25, 0xB2, + 0x81, 0x2E, 0xFA, 0x07, 0x9F, 0xB9, 0xE5, 0xC2, 0xCF, 0x28, 0x70, 0x19, 0x39, 0xA3, 0x8A, 0x5E, + 0x47, 0x81, 0xF1, 0xB7, 0x16, 0xE3, 0x81, 0x4A, 0x00, 0xAD, 0x5C, 0xD9, 0xEB, 0x86, 0x05, 0xB8, + 0x9B, 0xA9, 0xAE, 0x89, 0x1F, 0xB2, 0x44, 0xEA, 0x80, 0xEC, 0xF8, 0x04, 0x71, 0xF2, 0x4B, 0xE2, + 0x04, 0x18, 0xF6, 0xAA, 0xD0, 0x89, 0xFA, 0x44, 0x01, 0x6C, 0x1C, 0x74, 0x8E, 0x20, 0xF5, 0xB2, + 0x24, 0x1E, 0x95, 0xC8, 0x0C, 0x12, 0xF7, 0xC5, 0x9E, 0x7D, 0xA5, 0xEC, 0x30, 0xAC, 0xD5, 0xEE, + 0x78, 0x1D, 0xD5, 0x16, 0x81, 0x72, 0xB8, 0x1C, 0xEA, 0x07, 0xDC, 0x0B, 0x95, 0x5B, 0xFF, 0xFD, + 0x41, 0x58, 0x8C, 0xCA, 0x5E, 0x0B, 0xC7, 0xC2, 0xDA, 0xC7, 0x46, 0x2C, 0x46, 0xBF, 0xE2, 0x43, + 0x14, 0xA1, 0x38, 0x46, 0x89, 0xBD, 0x4B, 0x70, 0xAD, 0xA6, 0xC0, 0x83, 0x9A, 0x68, 0x91, 0xA3, + 0xC6, 0x1E, 0x85, 0x8D, 0x0F, 0x6C, 0x33, 0xC0, 0x4B, 0x2B, 0x4F, 0xDF, 0xF9, 0x83, 0x9F, 0x6A, + 0x77, 0x7B, 0xE8, 0x52, 0x2A, 0xB4, 0x8E, 0xF8, 0x2F, 0x53, 0x00, 0xDE, 0x05, 0x5E, 0xFC, 0xA5, + 0x63, 0x53, 0xC8, 0xAF, 0x15, 0x07, 0x96, 0x5D, 0xCD, 0x26, 0xC6, 0x4C, 0x34, 0xEF, 0x25, 0x5A, + 0x65, 0x34, 0x93, 0xA4, 0xC9, 0x8F, 0xBA, 0x84, 0x1B, 0x99, 0x24, 0x32, 0x0C, 0x2B, 0x1F, 0xD8, + 0x0D, 0x29, 0x6E, 0x51, 0x83, 0x6F, 0x7D, 0xAA, 0xF1, 0x43, 0x18, 0x03, 0x1F, 0x8E, 0xF9, 0x70, + 0x4C, 0xC6, 0x16, 0xA3, 0x62, 0xEC, 0x35, 0x32, 0x25, 0xD3, 0x32, 0x08, 0x14, 0x77, 0x5C, 0x2B, + 0x56, 0x12, 0xA5, 0x7A, 0x59, 0xCF, 0x22, 0x71, 0xBB, 0xB0, 0xBB, 0x1F, 0x0C, 0xC7, 0x76, 0x21, + 0x0C, 0x1F, 0x28, 0xD8, 0x83, 0xB3, 0xCC, 0xF2, 0xC4, 0x05, 0x3F, 0x5B, 0x29, 0x25, 0x3D, 0x94, + 0x29, 0x7B, 0xB9, 0x18, 0xF0, 0xE3, 0xEC, 0x72, 0x3F, 0xEE, 0x25, 0xD5, 0xCB, 0x7A, 0x16, 0x09, + 0xF9, 0x60, 0x92, 0xF8, 0x75, 0xEB, 0xAE, 0x64, 0x91, 0x9A, 0x1E, 0x4A, 0xC9, 0x1C, 0x68, 0x7F, + 0x47, 0xB9, 0x54, 0x2E, 0x39, 0xE7, 0x0E, 0x49, 0xCD, 0xD9, 0xB1, 0x95, 0x40, 0x01, 0x5C, 0x20, + 0xD6, 0x9C, 0x93, 0xFB, 0xC4, 0x7D, 0xC2, 0xA6, 0xA0, 0xDE, 0x35, 0x5B, 0x94, 0xE0, 0x98, 0xC4, + 0x9C, 0x4C, 0x80, 0x37, 0x42, 0x9D, 0x9E, 0x7D, 0x52, 0x25, 0xA1, 0x27, 0x90, 0x14, 0x1F, 0x98, + 0xDB, 0xF3, 0xBD, 0x93, 0xA7, 0x00, 0xA8, 0xFE, 0x8E, 0xE2, 0x0E, 0xA8, 0x4D, 0xB0, 0x46, 0x9C, + 0x92, 0xFE, 0x81, 0x80, 0x39, 0x19, 0x55, 0x61, 0x2A, 0x09, 0xC5, 0x20, 0x55, 0x12, 0x7A, 0x04, + 0x49, 0x7D, 0x6B, 0xE6, 0x7A, 0x9C, 0xE4, 0xC2, 0x79, 0x84, 0xF7, 0x6A, 0x5B, 0xFF, 0x7E, 0xE8, + 0x50, 0x69, 0x22, 0x33, 0xED, 0x8E, 0x87, 0x08, 0x27, 0x86, 0x95, 0x5D, 0x02, 0x25, 0x25, 0xDC, + 0x47, 0x97, 0x3F, 0x12, 0xD9, 0x43, 0xCA, 0xF2, 0x20, 0xEC, 0x26, 0xDE, 0x19, 0x53, 0x3C, 0x94, + 0x6E, 0x6A, 0x32, 0xAA, 0x8F, 0x6A, 0x1B, 0x46, 0x38, 0xA8, 0x24, 0x48, 0x64, 0x0B, 0x29, 0xF7, + 0x0F, 0xEA, 0xA6, 0xE2, 0xC8, 0x21, 0x78, 0xD0, 0x35, 0x06, 0xDD, 0xFD, 0xB9, 0x57, 0xEB, 0x80, + 0x99, 0x38, 0xC8, 0x5B, 0xF7, 0x1F, 0xD5, 0xDA, 0xCC, 0x4F, 0xEB, 0x80, 0xD6, 0x64, 0xC8, 0x9A, + 0x91, 0x9C, 0x4A, 0x82, 0x44, 0xB6, 0x90, 0xB2, 0x3C, 0xC0, 0xDE, 0x01, 0x8E, 0x21, 0xFB, 0xF5, + 0xF5, 0x7D, 0x34, 0x4C, 0x6F, 0x53, 0xFC, 0x1F, 0x37, 0x94, 0xB7, 0x3E, 0x69, 0xEA, 0x35, 0x4E, + 0x4D, 0x86, 0xAA, 0x15, 0x49, 0xA9, 0x24, 0x48, 0x64, 0x0B, 0x29, 0xF7, 0x0F, 0xF6, 0x46, 0x69, + 0x85, 0xE8, 0x6C, 0xE3, 0xDA, 0xDB, 0x4F, 0x3E, 0xAE, 0x29, 0x0B, 0x8C, 0x5F, 0xFD, 0x13, 0xF8, + 0xCF, 0x9B, 0x01, 0x56, 0x3F, 0x04, 0x81, 0xE1, 0x0D, 0xC9, 0x50, 0x4C, 0x06, 0x76, 0x95, 0x84, + 0x56, 0xBB, 0x0D, 0x9C, 0x47, 0xD2, 0xA5, 0x2C, 0x11, 0x83, 0xA4, 0xF8, 0xC0, 0x22, 0xAB, 0x5D, + 0xF4, 0x85, 0x9E, 0x37, 0x62, 0xC9, 0x8B, 0x65, 0x0B, 0x74, 0xBF, 0xCF, 0xBE, 0x58, 0xFF, 0x4B, + 0x34, 0x4C, 0x72, 0xF9, 0x1F, 0x60, 0xD7, 0xA8, 0xF2, 0x64, 0x28, 0x26, 0x05, 0xBB, 0x4A, 0x82, + 0xDD, 0x06, 0xCE, 0x0B, 0xD2, 0x1E, 0x5E, 0xC6, 0x90, 0xA4, 0x3C, 0x30, 0x40, 0xBA, 0x02, 0x00, + 0x47, 0x1B, 0xDB, 0xCF, 0xB4, 0xF7, 0xD5, 0x67, 0x18, 0x7D, 0x4B, 0x27, 0xDC, 0x8A, 0x2D, 0x0C, + 0x1A, 0x4D, 0x4B, 0x5F, 0x6B, 0xA0, 0x6B, 0x95, 0x04, 0x66, 0x03, 0xC7, 0xA3, 0x5C, 0xD2, 0x81, + 0x36, 0x70, 0x2A, 0xA7, 0x95, 0x55, 0xCA, 0x79, 0x85, 0xCC, 0x21, 0x49, 0x79, 0x60, 0x80, 0xCF, + 0xFF, 0x9F, 0x37, 0xA2, 0x74, 0x62, 0x69, 0x29, 0xE8, 0x1F, 0xE4, 0xBF, 0x94, 0xDC, 0x89, 0x57, + 0xFF, 0xD2, 0xA7, 0x1E, 0xFB, 0x5A, 0x32, 0x04, 0x9D, 0x90, 0x84, 0x4A, 0x02, 0xC4, 0xD8, 0xC0, + 0x91, 0xC8, 0x10, 0x52, 0x1F, 0x2F, 0x4C, 0xA1, 0x55, 0xA1, 0xA3, 0x2E, 0xB2, 0x43, 0x23, 0xC6, + 0x0B, 0x88, 0xD2, 0x36, 0xA0, 0x21, 0xC2, 0xBF, 0x0C, 0xF8, 0x6E, 0x86, 0x94, 0xC9, 0xF6, 0xB2, + 0x64, 0x70, 0xEC, 0x18, 0x65, 0xED, 0x90, 0x0E, 0x66, 0x03, 0x27, 0x1D, 0x82, 0x12, 0x09, 0x91, + 0xF2, 0x78, 0x81, 0x50, 0xD7, 0x71, 0x5E, 0x4B, 0xA9, 0x53, 0xC4, 0xD2, 0x87, 0xBF, 0xC8, 0x7E, + 0x33, 0x63, 0x58, 0xDB, 0xAE, 0x92, 0x80, 0x40, 0x1B, 0x38, 0x30, 0x70, 0xB4, 0x6E, 0x0B, 0x49, + 0x22, 0x53, 0x48, 0x59, 0x1E, 0x40, 0x67, 0x5D, 0x05, 0x14, 0x1F, 0x65, 0x9F, 0xBF, 0x90, 0x07, + 0x7C, 0x85, 0x91, 0xAE, 0xDB, 0x9F, 0x5B, 0xCC, 0x9C, 0xE1, 0xD4, 0xCF, 0x5F, 0xE8, 0x5A, 0x25, + 0x81, 0x25, 0x43, 0x5A, 0x0E, 0x40, 0x1A, 0x0F, 0xEC, 0x2F, 0x39, 0xD2, 0x12, 0x5D, 0x23, 0x75, + 0x79, 0xE0, 0xA9, 0xC0, 0xEF, 0x74, 0x5C, 0x67, 0xDF, 0x88, 0x5B, 0x05, 0xBB, 0xCA, 0x50, 0xF5, + 0x2D, 0xE9, 0x2A, 0x11, 0x25, 0xA1, 0x92, 0x20, 0x91, 0x45, 0xA4, 0x2E, 0x0F, 0xF6, 0x05, 0x7D, + 0x10, 0xF8, 0x93, 0x52, 0x11, 0x75, 0x45, 0x23, 0x38, 0xA9, 0x64, 0x01, 0xFB, 0x58, 0x33, 0x02, + 0x07, 0x95, 0x04, 0x89, 0x2C, 0x22, 0x65, 0x79, 0x30, 0x27, 0x1A, 0x08, 0xD5, 0xF8, 0x2F, 0xB7, + 0x1E, 0xEA, 0x91, 0x79, 0x48, 0x95, 0x84, 0x9E, 0x45, 0xEA, 0xF2, 0xC0, 0xD5, 0x07, 0x3E, 0x6D, + 0x09, 0xCD, 0xD6, 0x59, 0x4C, 0x52, 0x25, 0xA1, 0x07, 0x91, 0xC6, 0x78, 0x21, 0x62, 0x9E, 0xC6, + 0xCB, 0xB2, 0x5C, 0x90, 0x2A, 0x09, 0x3D, 0x84, 0xD4, 0xE5, 0x01, 0x84, 0xF6, 0x81, 0x2B, 0x8A, + 0x0F, 0x7A, 0xC2, 0x9E, 0x71, 0x07, 0x53, 0x55, 0x58, 0x4B, 0x11, 0xD6, 0x94, 0xA5, 0x95, 0x84, + 0xAC, 0x21, 0x9D, 0xF9, 0x03, 0xF7, 0x17, 0x71, 0x54, 0xF0, 0x9B, 0x0D, 0x00, 0x7F, 0xDB, 0x98, + 0x6D, 0xD3, 0x99, 0x31, 0x2A, 0x09, 0x17, 0xE2, 0xB5, 0x3D, 0x75, 0x3A, 0x12, 0x5D, 0xA0, 0xCB, + 0x86, 0xF6, 0x9D, 0x77, 0x04, 0x0C, 0x2F, 0x95, 0xE6, 0x93, 0xDD, 0xF3, 0x6F, 0xBD, 0x95, 0xB6, + 0x34, 0x31, 0xBC, 0x8D, 0x87, 0x3A, 0x5C, 0xDA, 0x15, 0xA5, 0x74, 0x60, 0x9F, 0x55, 0x50, 0xE0, + 0xAD, 0xD3, 0x50, 0x62, 0xCC, 0x34, 0xE3, 0x72, 0x83, 0x72, 0x37, 0x3B, 0x80, 0xA9, 0x75, 0x46, + 0x33, 0xBA, 0x99, 0xE1, 0xE4, 0xC0, 0x15, 0x72, 0x01, 0x2A, 0x55, 0x74, 0xDD, 0xE1, 0x9A, 0x3D, + 0x9B, 0x41, 0xDC, 0x85, 0xF7, 0x61, 0xB7, 0x90, 0x84, 0xC8, 0x62, 0x25, 0x12, 0x41, 0x91, 0xC0, + 0xF0, 0xCC, 0xBC, 0x43, 0x81, 0xC0, 0xC2, 0x6C, 0x18, 0xB5, 0x8F, 0x99, 0x56, 0x00, 0xCB, 0x11, + 0x9E, 0x81, 0x09, 0x87, 0xD4, 0x76, 0x5D, 0x6F, 0x0D, 0xB7, 0x5C, 0xB6, 0xBC, 0x1C, 0x82, 0xCD, + 0x25, 0x27, 0xBB, 0xA0, 0x2A, 0x11, 0x83, 0x54, 0x3B, 0xDE, 0xFB, 0xAE, 0xAB, 0x85, 0x70, 0x91, + 0x2B, 0x14, 0x82, 0x1F, 0xDC, 0x73, 0xCF, 0xDF, 0x84, 0x6A, 0xC0, 0xC3, 0xF7, 0xE2, 0x5E, 0xC4, + 0x3B, 0xCB, 0xD8, 0xD9, 0x3A, 0xFC, 0xA4, 0x9D, 0x14, 0xA9, 0xC6, 0x85, 0x4D, 0x1E, 0xA8, 0xEA, + 0x9B, 0xDC, 0xA1, 0x2D, 0x31, 0x78, 0x3D, 0xE0, 0x7F, 0xCD, 0x14, 0xA1, 0xC6, 0xEB, 0x85, 0x79, + 0x72, 0x21, 0x2A, 0x75, 0xA4, 0x5A, 0x64, 0xEA, 0xDC, 0xE3, 0xE0, 0xA1, 0xDE, 0x7A, 0x0B, 0xA1, + 0x83, 0xD5, 0x47, 0x55, 0x33, 0xD3, 0x44, 0x10, 0x47, 0xFA, 0xB0, 0x93, 0x76, 0x52, 0xA4, 0x1A, + 0x17, 0x76, 0x79, 0x10, 0x00, 0xF5, 0x42, 0x68, 0xD3, 0x55, 0x12, 0xFC, 0x4B, 0x47, 0x98, 0x7A, + 0x8C, 0x68, 0x5F, 0xFF, 0xD2, 0xDF, 0x25, 0x45, 0x56, 0xC2, 0x8E, 0x24, 0xF8, 0xC0, 0xA2, 0x18, + 0xA0, 0xFC, 0x74, 0x0C, 0xB8, 0x3E, 0xC6, 0x2E, 0x42, 0x1B, 0x31, 0x82, 0x78, 0xDC, 0xCD, 0x7A, + 0x9B, 0xFC, 0x48, 0x9F, 0x53, 0xBE, 0x85, 0xEE, 0x3E, 0x0B, 0xBB, 0xA6, 0x9A, 0x1C, 0xEC, 0x9A, + 0x0F, 0x2A, 0x5C, 0x4E, 0x6C, 0xA0, 0xAB, 0x24, 0x2C, 0x52, 0x7F, 0xAA, 0x68, 0x9C, 0x50, 0x84, + 0xED, 0xC2, 0xD9, 0xCF, 0xC9, 0xAE, 0x41, 0x5A, 0x48, 0x82, 0x0F, 0x6C, 0x8A, 0x01, 0x88, 0x48, + 0x04, 0xD4, 0x50, 0x73, 0x73, 0x73, 0x73, 0x31, 0x1B, 0x2F, 0x54, 0x16, 0x3F, 0xD3, 0x35, 0x95, + 0xF4, 0x60, 0xD6, 0x7C, 0xD0, 0x54, 0x12, 0xB0, 0x3F, 0x60, 0x52, 0x49, 0xB8, 0xB8, 0xFD, 0xB8, + 0xE8, 0x98, 0xD0, 0x8A, 0x84, 0xBB, 0x29, 0xA9, 0x53, 0x47, 0x25, 0xEC, 0x48, 0xC7, 0x06, 0x51, + 0x05, 0x7E, 0x9B, 0x1D, 0x50, 0x0C, 0x4D, 0x83, 0x3B, 0xD8, 0xE3, 0xBE, 0x15, 0x8B, 0x17, 0x94, + 0xC1, 0xAF, 0xAE, 0x28, 0xFA, 0xF9, 0x7D, 0x7B, 0x26, 0x39, 0x9C, 0xB8, 0xD4, 0x0D, 0x98, 0xE7, + 0x0F, 0xB8, 0x4A, 0xC2, 0x9B, 0xA8, 0x91, 0xA0, 0x2B, 0xA9, 0xB4, 0xFE, 0xD3, 0x76, 0xB4, 0xC9, + 0x31, 0xEC, 0xF8, 0x89, 0x72, 0xD8, 0x8A, 0x5D, 0x05, 0x80, 0x5D, 0x03, 0xE5, 0x36, 0xE9, 0xB4, + 0x90, 0x06, 0x1F, 0x78, 0xF7, 0x8F, 0x3C, 0x16, 0xF6, 0x84, 0xA3, 0x51, 0x38, 0x05, 0xBC, 0xD6, + 0x17, 0x02, 0x9E, 0xA7, 0x76, 0xC1, 0x9D, 0xBF, 0x9F, 0xFB, 0x70, 0xD1, 0xFE, 0xC3, 0xA9, 0x13, + 0x4C, 0x80, 0x18, 0xCD, 0x07, 0x6C, 0x17, 0xB0, 0xAB, 0xA8, 0xA9, 0x24, 0x94, 0x5E, 0xAF, 0xA0, + 0x31, 0x86, 0xBE, 0x07, 0xE8, 0xC0, 0xB6, 0xEA, 0x0E, 0x32, 0xBC, 0x70, 0xC8, 0x0B, 0x9B, 0x3F, + 0x0B, 0x45, 0x0E, 0x86, 0xFD, 0x24, 0x12, 0xA1, 0x6B, 0x3E, 0xB0, 0x75, 0xD9, 0x0F, 0x46, 0xDD, + 0x93, 0x50, 0xF1, 0xE0, 0xE4, 0x87, 0xDE, 0x69, 0x6E, 0xDD, 0x73, 0x21, 0xEB, 0x10, 0xCC, 0x21, + 0x9D, 0x84, 0xB2, 0x93, 0x30, 0x38, 0x73, 0xE3, 0x36, 0xEB, 0x7C, 0x22, 0x1F, 0x21, 0x16, 0x63, + 0x63, 0xA6, 0x59, 0x49, 0x58, 0x86, 0x2A, 0x8B, 0x20, 0x6C, 0x31, 0x78, 0xC5, 0xA4, 0xD6, 0xBC, + 0x4C, 0x1B, 0x8B, 0xEE, 0x0D, 0xE8, 0x92, 0x0F, 0x6C, 0x5F, 0xE4, 0xE8, 0x03, 0xA4, 0x0C, 0x14, + 0x09, 0x75, 0x56, 0x1C, 0xAE, 0x9D, 0x92, 0x7D, 0xC3, 0x76, 0x96, 0xD4, 0x99, 0x4A, 0xC2, 0x9B, + 0xD0, 0xE1, 0x0F, 0x5C, 0x39, 0x2D, 0x0D, 0x5A, 0x12, 0x09, 0x90, 0xEA, 0xB8, 0xF1, 0xC0, 0x57, + 0xA8, 0x36, 0xF6, 0x1F, 0xFC, 0xF8, 0x80, 0xAA, 0xEC, 0x4E, 0xF1, 0xD9, 0x34, 0x60, 0x16, 0x46, + 0x53, 0xEA, 0xD0, 0xE4, 0x12, 0xFE, 0xE2, 0x76, 0xB7, 0xD9, 0x52, 0x25, 0x21, 0xC3, 0x48, 0xF5, + 0x93, 0x9E, 0xC5, 0x64, 0x73, 0x96, 0x57, 0x97, 0x0C, 0x98, 0xE5, 0x81, 0x54, 0x49, 0xC8, 0x22, + 0xD2, 0x15, 0xED, 0xA6, 0x86, 0x1B, 0x97, 0x9E, 0x77, 0xED, 0x84, 0x99, 0xDC, 0x66, 0xA2, 0x40, + 0xA6, 0x74, 0x12, 0xEC, 0xFA, 0x07, 0xB3, 0x91, 0xF2, 0x5E, 0xD0, 0xF4, 0x0F, 0x92, 0x4B, 0x25, + 0xDB, 0x2A, 0x33, 0xE7, 0x04, 0xD2, 0xFD, 0xBA, 0x2C, 0x0D, 0x77, 0x18, 0xA7, 0xF7, 0xB6, 0xEE, + 0x09, 0x46, 0xCE, 0x64, 0xEA, 0x7C, 0x46, 0x1D, 0x56, 0xFD, 0x03, 0x9C, 0xC7, 0xDC, 0xAB, 0x28, + 0x53, 0xA7, 0x2A, 0xD9, 0x52, 0x7D, 0xE9, 0xBD, 0x48, 0x97, 0x0F, 0x2C, 0xA3, 0x88, 0xDA, 0xA2, + 0xD1, 0x63, 0xCA, 0x0F, 0xFC, 0xE1, 0x5F, 0xBF, 0xFC, 0xA3, 0xF4, 0x88, 0xC5, 0x87, 0x34, 0x89, + 0xD0, 0x43, 0xC8, 0x88, 0x3C, 0xA8, 0x1A, 0x11, 0x2E, 0x81, 0xE9, 0xA5, 0x37, 0xF4, 0xD3, 0x4D, + 0xEC, 0x65, 0x0A, 0x76, 0xFD, 0x03, 0xFC, 0x8F, 0x6F, 0x12, 0xA1, 0x6A, 0xA8, 0x9C, 0x4C, 0x4C, + 0x17, 0xE9, 0xF4, 0x0F, 0x62, 0x6C, 0x15, 0x6C, 0xB8, 0xE0, 0x56, 0x25, 0x3A, 0xF4, 0xEF, 0x50, + 0x64, 0x6C, 0x70, 0xCA, 0x10, 0xAC, 0xF3, 0x07, 0x0C, 0x75, 0x53, 0xE5, 0xFC, 0x40, 0xE6, 0x91, + 0x56, 0x3F, 0xD1, 0x66, 0xAB, 0x60, 0xDF, 0xE4, 0xA2, 0x57, 0x6F, 0x1C, 0xFF, 0x27, 0xD7, 0x1F, + 0x9E, 0x48, 0x87, 0x58, 0x42, 0xC4, 0xB0, 0x01, 0x99, 0x44, 0x48, 0x9D, 0x8C, 0x44, 0x57, 0x48, + 0xB7, 0x5D, 0x30, 0x6D, 0x3A, 0x0C, 0xAE, 0x47, 0x4D, 0xB1, 0xD0, 0x27, 0xE6, 0x0D, 0xFE, 0x42, + 0xE6, 0x8D, 0xD8, 0xD8, 0xF5, 0x0F, 0xC0, 0x6A, 0x12, 0x01, 0x5B, 0x82, 0xAA, 0x41, 0x27, 0x60, + 0xE2, 0x09, 0x54, 0x7D, 0x28, 0x79, 0x1C, 0xD4, 0x19, 0x74, 0x7D, 0x06, 0xCF, 0x86, 0x7F, 0x7D, + 0xE8, 0xE4, 0xFE, 0x27, 0x82, 0xE7, 0xF9, 0xFD, 0xAB, 0x52, 0x48, 0xAC, 0x37, 0x23, 0x03, 0xA3, + 0xF1, 0x87, 0xFE, 0xFC, 0x76, 0xA8, 0xA9, 0xEE, 0xBD, 0xF7, 0x70, 0x7C, 0x96, 0x71, 0x75, 0x45, + 0xBB, 0x3C, 0xB0, 0x99, 0x44, 0xA8, 0xEC, 0x17, 0xDE, 0x33, 0xE6, 0xE9, 0x60, 0x34, 0x7C, 0x5B, + 0x7D, 0xE0, 0xCD, 0x35, 0xA7, 0x3B, 0xBE, 0x1D, 0x78, 0xEA, 0xD1, 0xD7, 0x97, 0x1C, 0x0A, 0xAC, + 0x8D, 0x04, 0xBE, 0x70, 0xA6, 0x6C, 0xD2, 0x5D, 0x81, 0xC0, 0x7D, 0xA9, 0xA4, 0xD6, 0x8B, 0x91, + 0x1E, 0x1F, 0xA0, 0x3E, 0x82, 0xA1, 0x92, 0xF0, 0xA5, 0xFF, 0xD8, 0xB0, 0xF0, 0x0B, 0x6E, 0x3C, + 0xAF, 0xA3, 0xBD, 0x48, 0x39, 0xD3, 0x41, 0x07, 0xB8, 0x64, 0x0E, 0x76, 0xFD, 0x03, 0x9B, 0x49, + 0x04, 0xDF, 0x0F, 0xD6, 0x2B, 0x8F, 0xBC, 0x5E, 0x33, 0xF2, 0xD8, 0x89, 0xB1, 0xFE, 0xCB, 0x3A, + 0x23, 0xBE, 0x85, 0x78, 0x88, 0xD4, 0xF9, 0xFE, 0x89, 0x27, 0xEE, 0x1C, 0xE2, 0xBF, 0x0B, 0xAA, + 0x5A, 0x33, 0xA6, 0x0E, 0x73, 0xEE, 0x23, 0xBD, 0x79, 0x24, 0xB4, 0xB1, 0xCB, 0x5A, 0x69, 0xA6, + 0x18, 0x10, 0x3C, 0xF8, 0x31, 0x14, 0x45, 0xCE, 0x78, 0x3A, 0xCB, 0xFF, 0x8E, 0xCB, 0x90, 0x9E, + 0x71, 0x99, 0x9C, 0xB7, 0xB1, 0xEA, 0x1F, 0xE8, 0x3D, 0x03, 0xDD, 0x51, 0xD4, 0xFE, 0xC8, 0x5B, + 0xC7, 0x4F, 0x5C, 0x05, 0xFE, 0xF7, 0x71, 0xBD, 0x99, 0x5B, 0x64, 0xF6, 0x1D, 0x0D, 0x8E, 0x6F, + 0x7D, 0x21, 0xA5, 0x54, 0x24, 0x32, 0xD1, 0x2E, 0xCC, 0x6A, 0xEF, 0x0C, 0xC3, 0xC4, 0xF2, 0xE1, + 0xC3, 0x8A, 0xC2, 0x10, 0xE8, 0x0C, 0x1B, 0x27, 0xAA, 0x64, 0x18, 0x4E, 0xA7, 0x34, 0x4C, 0xFB, + 0xD5, 0xA8, 0x91, 0xF7, 0xDF, 0x5F, 0x54, 0x59, 0xF4, 0x73, 0xE1, 0xB1, 0x67, 0xD2, 0xE1, 0xEB, + 0x7C, 0x47, 0x07, 0xBF, 0x82, 0xCE, 0x39, 0xA5, 0x9A, 0xA7, 0x44, 0x97, 0x48, 0x77, 0x5E, 0xD9, + 0xD2, 0x69, 0xFF, 0x16, 0x80, 0xF2, 0x69, 0xFA, 0x5A, 0xFF, 0xE7, 0x92, 0xAD, 0xBF, 0x49, 0x87, + 0x5A, 0xD2, 0xB0, 0x9B, 0x44, 0xA8, 0x8C, 0x5E, 0x0D, 0x15, 0x87, 0x16, 0xFA, 0x50, 0xF5, 0x01, + 0x7C, 0xFF, 0x1D, 0x28, 0x07, 0xDF, 0x81, 0x3E, 0xD5, 0x7E, 0xB8, 0xE8, 0x8E, 0x97, 0x30, 0xF0, + 0x45, 0xF4, 0xBC, 0x57, 0x76, 0x10, 0x92, 0x42, 0x5A, 0x7C, 0xE0, 0x60, 0x27, 0x17, 0x99, 0x00, + 0xCD, 0xE9, 0xCD, 0x56, 0x8E, 0xA5, 0x48, 0x2A, 0x25, 0xC4, 0x9E, 0xD2, 0xE0, 0x43, 0xEB, 0x6C, + 0x17, 0x9D, 0x06, 0xAE, 0xFA, 0xC0, 0x6C, 0x32, 0x00, 0x1C, 0xA5, 0x0B, 0xA9, 0x40, 0x70, 0x4F, + 0x89, 0x64, 0x90, 0x0E, 0x1F, 0xD8, 0x3B, 0xF1, 0xF4, 0xED, 0x01, 0x4E, 0xFF, 0xAB, 0xF0, 0xCE, + 0x05, 0x23, 0x52, 0xA4, 0x95, 0x0A, 0xA4, 0x49, 0x84, 0xEC, 0x21, 0x03, 0xEB, 0x8D, 0xCF, 0x7E, + 0x65, 0xBD, 0xF2, 0xD2, 0x2D, 0xCC, 0xF9, 0xF9, 0x97, 0xBF, 0xF7, 0xC5, 0xE7, 0x78, 0x78, 0xCA, + 0x14, 0xBB, 0x84, 0x6E, 0x12, 0x01, 0xFF, 0xA5, 0xFE, 0x41, 0x86, 0x91, 0x2E, 0x1F, 0x98, 0x64, + 0xC2, 0x94, 0x67, 0x7F, 0xD8, 0x00, 0xAF, 0x00, 0xD9, 0x4D, 0x6C, 0x80, 0x4D, 0xCF, 0x31, 0xDB, + 0x18, 0x19, 0xB5, 0xBB, 0x2C, 0x20, 0xF5, 0x0F, 0xB2, 0x88, 0x4C, 0xE8, 0x1F, 0xCC, 0xDA, 0xCC, + 0x7E, 0xC3, 0x6D, 0x87, 0xD1, 0x68, 0x0E, 0x27, 0x58, 0xE3, 0x0B, 0x5A, 0x91, 0x72, 0x02, 0x8E, + 0x20, 0x93, 0x08, 0x26, 0x48, 0xCD, 0x82, 0x8C, 0x21, 0x23, 0xEB, 0x8D, 0x0C, 0xC1, 0xDD, 0xBE, + 0xC9, 0x95, 0x23, 0x77, 0xF1, 0x1A, 0xCF, 0x0E, 0x1B, 0x48, 0x64, 0x0D, 0x19, 0xD1, 0x3F, 0x20, + 0x44, 0x6A, 0x3F, 0xF1, 0x41, 0x38, 0x72, 0x58, 0xA9, 0x65, 0x75, 0x6E, 0x63, 0x03, 0xF9, 0xE1, + 0xE6, 0x3B, 0x32, 0x26, 0x0F, 0x5A, 0x7F, 0xB9, 0x06, 0x3C, 0xA1, 0xE8, 0xE8, 0x62, 0x36, 0xC4, + 0x97, 0xF2, 0xA0, 0xC0, 0x90, 0x11, 0xFD, 0x03, 0xC2, 0xE1, 0x6B, 0x77, 0x82, 0xDB, 0x3D, 0xE4, + 0xD8, 0xDE, 0xF3, 0xE9, 0xCE, 0x2E, 0x0F, 0x24, 0x23, 0xE4, 0x39, 0x32, 0xA1, 0x7F, 0xC0, 0x71, + 0xF6, 0x5A, 0x1C, 0xCC, 0x9D, 0x99, 0x30, 0x92, 0x6D, 0x68, 0x92, 0x6C, 0x50, 0x60, 0xC8, 0x80, + 0xFE, 0x01, 0x87, 0x67, 0x72, 0xD1, 0xA9, 0xA3, 0x91, 0x48, 0x73, 0x09, 0x33, 0x7A, 0x2B, 0xFB, + 0x07, 0x05, 0x86, 0x0C, 0x6D, 0x49, 0x0A, 0x87, 0x21, 0xAC, 0x8E, 0x2B, 0x75, 0x4F, 0x3E, 0x7B, + 0x21, 0x53, 0x0D, 0x90, 0xF2, 0xA0, 0xC0, 0x90, 0x01, 0xFD, 0x03, 0x88, 0x74, 0x9C, 0x51, 0xBC, + 0xE7, 0x4F, 0x88, 0x1C, 0x76, 0x43, 0xA8, 0x7E, 0x03, 0xFB, 0xF6, 0xA5, 0x3C, 0x28, 0x30, 0x64, + 0x44, 0xFF, 0x00, 0xD5, 0x90, 0x90, 0x8E, 0xB7, 0xB3, 0x5A, 0x55, 0xF0, 0x88, 0x6F, 0xCE, 0x08, + 0x16, 0x54, 0x64, 0x7C, 0x63, 0x83, 0x44, 0x66, 0x91, 0x81, 0x76, 0x61, 0xD6, 0x86, 0x49, 0x3A, + 0x95, 0x96, 0xA2, 0x20, 0xDF, 0xF9, 0x96, 0xCE, 0x39, 0x9E, 0x12, 0xB9, 0x43, 0x46, 0xF4, 0x0F, + 0x60, 0x1F, 0xBB, 0x4E, 0x84, 0x69, 0x17, 0x54, 0xBF, 0x2C, 0xBC, 0x64, 0x97, 0xA0, 0xA0, 0x90, + 0x09, 0xFD, 0x83, 0xF0, 0x74, 0xE2, 0x0A, 0x25, 0x3A, 0xFA, 0x0F, 0x17, 0x7A, 0x8F, 0x65, 0xDB, + 0xB2, 0xA6, 0x44, 0x56, 0x90, 0x09, 0xFD, 0x03, 0xD8, 0xB3, 0x1F, 0x2F, 0x93, 0xF6, 0x4D, 0x84, + 0x1D, 0x59, 0xD5, 0x3F, 0x90, 0xC8, 0x1E, 0x32, 0xA1, 0x7F, 0x70, 0xEB, 0x8B, 0xF4, 0x53, 0x03, + 0xEF, 0x79, 0x5E, 0xE8, 0xD3, 0x76, 0xEB, 0x7F, 0xA5, 0x47, 0x50, 0x22, 0xA7, 0xC8, 0x84, 0xFE, + 0xC1, 0x6F, 0x7F, 0x20, 0x5C, 0x0D, 0xE5, 0x0D, 0xF0, 0x5B, 0xDD, 0x36, 0x02, 0xE9, 0x8B, 0x20, + 0x34, 0x15, 0x32, 0x89, 0x7C, 0x46, 0x06, 0xF5, 0x0F, 0xEC, 0xA0, 0x73, 0xBA, 0xF1, 0xDA, 0x35, + 0x2D, 0x89, 0xDC, 0x23, 0x73, 0xFA, 0x07, 0xB1, 0x20, 0x16, 0x90, 0x6C, 0x50, 0x18, 0xC8, 0x98, + 0xFE, 0x81, 0x13, 0x02, 0x92, 0x0D, 0x0A, 0x05, 0xD9, 0x94, 0x07, 0x20, 0xD9, 0xA0, 0x60, 0x90, + 0x31, 0xFD, 0x03, 0x89, 0x82, 0x46, 0xE6, 0xF4, 0x0F, 0x24, 0x0A, 0x19, 0x19, 0xD3, 0x3F, 0x90, + 0x28, 0x68, 0x64, 0x4A, 0xFF, 0x20, 0xC2, 0x16, 0x1C, 0x3C, 0x3A, 0x39, 0x29, 0x2B, 0x0A, 0x0B, + 0xE9, 0xF1, 0x01, 0x4A, 0x03, 0xDC, 0xCD, 0x08, 0x38, 0x8B, 0x40, 0x88, 0x84, 0x83, 0xA5, 0x1E, + 0x26, 0x20, 0x42, 0x61, 0xC5, 0xC3, 0xAC, 0x2E, 0x67, 0x63, 0x1F, 0x8B, 0x44, 0x16, 0x21, 0xF8, + 0xC0, 0xB6, 0x3A, 0x58, 0x99, 0x48, 0x5F, 0x00, 0x03, 0x03, 0x4C, 0xC7, 0x68, 0xAA, 0x40, 0xC8, + 0xA7, 0x86, 0x50, 0x21, 0x81, 0x80, 0xE7, 0x32, 0xD0, 0x41, 0x18, 0x09, 0x9F, 0x97, 0xC8, 0x43, + 0x68, 0xF2, 0xC0, 0xAE, 0x2F, 0x10, 0x5F, 0x83, 0xE8, 0x9D, 0x18, 0xA5, 0xB3, 0x18, 0x8D, 0x23, + 0xD9, 0x28, 0x14, 0x1C, 0xF4, 0x76, 0xC1, 0xAE, 0x2F, 0x90, 0x40, 0x7F, 0xC0, 0x81, 0x0D, 0x12, + 0xC6, 0x97, 0xC8, 0x7F, 0xA4, 0x33, 0x5E, 0xE8, 0x42, 0x1A, 0x48, 0x14, 0x20, 0x6C, 0x7C, 0x20, + 0xD6, 0x08, 0x13, 0xC3, 0x51, 0x1E, 0x24, 0xFD, 0xB4, 0x44, 0x3E, 0xC2, 0xCA, 0x07, 0xC9, 0x55, + 0x64, 0x7C, 0x79, 0x20, 0x19, 0xA1, 0x50, 0x61, 0xE1, 0x83, 0x24, 0xAB, 0x31, 0xAE, 0x3C, 0x48, + 0x9A, 0x82, 0x44, 0xBE, 0xC1, 0xCC, 0x07, 0xC9, 0x56, 0x62, 0xA2, 0xFE, 0x81, 0x64, 0x84, 0xC2, + 0x84, 0x99, 0x0F, 0x92, 0x5D, 0x1D, 0x4C, 0x20, 0x0F, 0xE4, 0x0A, 0x63, 0x81, 0xC2, 0xD2, 0x2E, + 0x24, 0x59, 0x89, 0x09, 0xE4, 0x81, 0x64, 0x83, 0x02, 0x85, 0xB5, 0x9F, 0x98, 0x5C, 0x35, 0xC6, + 0x97, 0x07, 0x92, 0x0D, 0x0A, 0x15, 0xB6, 0x71, 0x63, 0x52, 0x15, 0x19, 0x57, 0x1E, 0x48, 0x36, + 0x28, 0x58, 0xA4, 0x33, 0x8F, 0x94, 0xA8, 0x7F, 0x20, 0x51, 0x98, 0x90, 0xF3, 0x89, 0x12, 0x04, + 0x6D, 0x7D, 0xC1, 0xBE, 0x34, 0x94, 0x68, 0xA9, 0xC8, 0x49, 0x1E, 0xC8, 0xA5, 0xA5, 0xC2, 0x86, + 0xE0, 0x03, 0xBB, 0xBE, 0x40, 0x42, 0xFD, 0x01, 0x07, 0x79, 0x20, 0xED, 0xDC, 0x16, 0x38, 0x84, + 0xD9, 0xCB, 0x94, 0x9E, 0xB1, 0xDA, 0x36, 0x60, 0x48, 0x8E, 0x40, 0x8D, 0xEC, 0x47, 0xE4, 0x2B, + 0x18, 0x1F, 0xF4, 0x90, 0xDE, 0xB1, 0x54, 0x6F, 0xCE, 0x5F, 0x30, 0x3E, 0xE8, 0xA1, 0xCF, 0x54, + 0x4A, 0x83, 0xFC, 0x85, 0xB4, 0x5A, 0x2D, 0x41, 0x90, 0x7C, 0x20, 0x41, 0x60, 0xED, 0x42, 0x6D, + 0xF7, 0x68, 0x24, 0x83, 0xD9, 0xD8, 0x28, 0xF4, 0x40, 0x32, 0x12, 0xA9, 0x83, 0xAA, 0x46, 0x8C, + 0x17, 0x6E, 0xEF, 0x06, 0x99, 0xA4, 0xC0, 0xC7, 0x13, 0x59, 0x4F, 0x46, 0x22, 0x75, 0xF0, 0xAA, + 0x11, 0xF3, 0x07, 0xFC, 0xFC, 0xAB, 0xEC, 0x41, 0x74, 0x11, 0xB3, 0x9D, 0x4C, 0x86, 0x51, 0x91, + 0xF9, 0xFC, 0x66, 0x81, 0x64, 0x0C, 0x12, 0xA7, 0x61, 0xDF, 0xA2, 0xC0, 0x7F, 0xB4, 0xF9, 0x44, + 0x39, 0x64, 0x88, 0x05, 0xB6, 0x63, 0x99, 0xCE, 0x6F, 0x16, 0x48, 0xC6, 0xA0, 0xAB, 0x34, 0x1C, + 0xB7, 0x18, 0x64, 0x68, 0x5F, 0x9B, 0x44, 0x01, 0xC1, 0x89, 0x4B, 0xE4, 0x78, 0x41, 0x82, 0xE0, + 0xC4, 0x07, 0x78, 0x8A, 0x7A, 0x8A, 0x54, 0xD2, 0x42, 0x0F, 0x25, 0xD3, 0xB3, 0x48, 0xED, 0xA5, + 0xF2, 0xA7, 0x08, 0x2C, 0x7C, 0x50, 0xEA, 0xF7, 0xFB, 0xFB, 0xBF, 0x3A, 0x14, 0xCF, 0xC5, 0xCC, + 0x2A, 0x7A, 0x28, 0x99, 0x1E, 0x45, 0x95, 0xD3, 0x4B, 0xC5, 0xAF, 0x66, 0x7B, 0xEC, 0x6C, 0x30, + 0x84, 0x9D, 0x64, 0xC2, 0x34, 0x2C, 0xFD, 0x03, 0x76, 0x5A, 0x36, 0x9C, 0xE4, 0xE7, 0x65, 0x27, + 0x8D, 0xDA, 0xA9, 0xA9, 0xC5, 0xEF, 0xA9, 0x64, 0x7A, 0x16, 0x4E, 0x2F, 0x35, 0x87, 0x4E, 0x95, + 0x4D, 0x3A, 0x76, 0xCF, 0xC2, 0x6F, 0x55, 0x1E, 0x8B, 0x6D, 0x17, 0xAA, 0x88, 0x4B, 0x91, 0xBD, + 0x4B, 0x1E, 0xAF, 0x1A, 0x3A, 0xD9, 0xEF, 0x5F, 0x05, 0xCF, 0xF8, 0xC9, 0x3D, 0x64, 0x94, 0xFF, + 0x81, 0x71, 0x78, 0xC7, 0x42, 0xCC, 0xF1, 0x6B, 0xD3, 0x9B, 0x1F, 0xEA, 0xA1, 0x64, 0x7A, 0x16, + 0xC6, 0x4B, 0xD1, 0xEB, 0x0C, 0x7C, 0x7D, 0xE8, 0xB1, 0x71, 0xF8, 0xE1, 0xAF, 0x8A, 0x79, 0x99, + 0x98, 0xD8, 0xB7, 0xB6, 0x96, 0xFF, 0xE3, 0xB8, 0x55, 0x10, 0x2C, 0xFF, 0x26, 0x16, 0x80, 0xD3, + 0xEB, 0xA7, 0x0B, 0x56, 0xAA, 0x2C, 0x33, 0xC7, 0x30, 0x8D, 0xB9, 0x20, 0x0E, 0xC5, 0xC7, 0xFD, + 0x05, 0xD6, 0x1D, 0x06, 0x56, 0x7D, 0xE5, 0x72, 0x94, 0x56, 0xA7, 0xD0, 0x11, 0xBC, 0xAD, 0x3E, + 0xF0, 0xE6, 0x9A, 0xD3, 0x81, 0x2F, 0x04, 0xB6, 0xAC, 0x6D, 0x5A, 0x18, 0x08, 0xFC, 0x65, 0x13, + 0x74, 0x7C, 0x7B, 0xCB, 0x9A, 0xBB, 0xB6, 0xAC, 0x3D, 0xCA, 0x42, 0x4C, 0x02, 0x86, 0x6A, 0x27, + 0xC5, 0x1A, 0xEA, 0xA1, 0x64, 0x7A, 0x16, 0xB6, 0x97, 0x7A, 0x7D, 0xC9, 0xA1, 0xC0, 0xDA, 0x08, + 0x14, 0x1F, 0x0C, 0x6C, 0xF1, 0xDD, 0x61, 0x7F, 0x99, 0x98, 0xD8, 0x4D, 0x2F, 0x96, 0x36, 0xFC, + 0xF5, 0xF9, 0x57, 0x61, 0xD7, 0x98, 0x3B, 0x3A, 0xBE, 0x1D, 0xD8, 0xB2, 0xE6, 0xC3, 0xD8, 0x27, + 0xD2, 0x04, 0x2B, 0xD5, 0x2A, 0xCA, 0x8C, 0x1B, 0xD3, 0xD8, 0xA2, 0x79, 0x13, 0x13, 0x58, 0x18, + 0x21, 0xB6, 0x5D, 0x20, 0x86, 0xD9, 0x7B, 0x62, 0x2C, 0x40, 0x51, 0xC4, 0x7F, 0x17, 0xB8, 0x3D, + 0x50, 0x35, 0x37, 0x02, 0xBE, 0xD3, 0xBE, 0x85, 0x1F, 0xF4, 0x59, 0xF8, 0x81, 0x87, 0x87, 0x18, + 0xC6, 0xB4, 0x79, 0xDD, 0xA4, 0x26, 0xB3, 0x7B, 0x28, 0x99, 0x9E, 0x85, 0xED, 0xA5, 0xCE, 0xF7, + 0x4F, 0xDC, 0x7F, 0x27, 0xDD, 0x56, 0xFD, 0xD3, 0xFD, 0xC7, 0x6C, 0x2F, 0x13, 0x1B, 0x9B, 0x85, + 0xCD, 0x38, 0x7E, 0xE2, 0xDD, 0xAB, 0xC1, 0xB7, 0x10, 0x66, 0xF4, 0x7D, 0x2C, 0xF6, 0x89, 0x34, + 0xC1, 0x4A, 0x75, 0x24, 0x65, 0x06, 0xD8, 0xC1, 0x59, 0x1C, 0x9C, 0x05, 0xCC, 0x4D, 0x43, 0x9C, + 0xF9, 0x03, 0x3D, 0x9F, 0x00, 0xD5, 0x37, 0x2F, 0xBF, 0xA7, 0xEA, 0x1A, 0x6B, 0x88, 0x81, 0xEE, + 0xD5, 0x4C, 0x0F, 0x25, 0xD3, 0xB3, 0xE0, 0x59, 0x3F, 0x1A, 0x1C, 0xDF, 0xFA, 0x02, 0xFE, 0xDE, + 0xBA, 0xF4, 0x9E, 0x2A, 0xDB, 0xCB, 0x38, 0xC4, 0xA6, 0x3A, 0xF2, 0xDD, 0xFD, 0xF3, 0xDF, 0x6C, + 0x13, 0x95, 0x95, 0xE8, 0x89, 0x54, 0x50, 0xF5, 0x19, 0x2A, 0x55, 0x1F, 0x65, 0x86, 0x6C, 0xA1, + 0x6B, 0x88, 0x55, 0x2C, 0x77, 0x9E, 0x3F, 0x98, 0x52, 0xF4, 0x73, 0xE3, 0x06, 0x39, 0x74, 0x8F, + 0xCE, 0x9A, 0x96, 0x90, 0xEE, 0xA2, 0x87, 0x92, 0xE9, 0x59, 0xF0, 0xAC, 0x57, 0x5D, 0xE7, 0x3B, + 0x3A, 0xF8, 0x15, 0x80, 0x67, 0x46, 0xDE, 0x07, 0x95, 0x09, 0x5E, 0x46, 0x7B, 0xD1, 0x08, 0xBE, + 0xFA, 0x9C, 0x1F, 0x8D, 0x2E, 0x23, 0xF7, 0xAE, 0xB6, 0x7B, 0x33, 0xF6, 0xFA, 0xAC, 0x54, 0xAB, + 0x29, 0x33, 0xEB, 0x59, 0x1A, 0xF1, 0xE0, 0xCC, 0x07, 0xBE, 0xDF, 0xAF, 0xC6, 0x9E, 0x05, 0x1F, + 0xD5, 0xCC, 0x5A, 0x51, 0xEE, 0xBF, 0x57, 0x17, 0x1B, 0x3C, 0x24, 0x43, 0x83, 0x9C, 0x1E, 0x4A, + 0xA6, 0x67, 0xC1, 0xB3, 0x3E, 0xB2, 0xDA, 0xEF, 0x1F, 0x73, 0x07, 0x04, 0x97, 0xBF, 0xEB, 0xEF, + 0x7F, 0x26, 0xC1, 0xCB, 0x88, 0x17, 0x9D, 0xB3, 0x6A, 0xEC, 0x5C, 0x98, 0x33, 0xEC, 0x6A, 0xA0, + 0x9E, 0xC3, 0xBC, 0xF7, 0xCF, 0xCB, 0xC4, 0xEB, 0x23, 0xA5, 0xFE, 0xA3, 0x59, 0xA9, 0x4E, 0xA1, + 0xCC, 0xDC, 0xC3, 0xD2, 0x88, 0x17, 0x59, 0x41, 0x53, 0x47, 0x50, 0x7B, 0x7B, 0x5D, 0xB6, 0x67, + 0xBD, 0x69, 0x8B, 0x43, 0x0F, 0x24, 0x93, 0x51, 0x64, 0x21, 0xBF, 0x09, 0x49, 0xBE, 0x7D, 0xF5, + 0x81, 0xC1, 0x55, 0xD7, 0x74, 0xBB, 0x45, 0xE8, 0x2A, 0xDB, 0x96, 0xDD, 0x26, 0xB5, 0xB7, 0xE3, + 0x91, 0xEC, 0x78, 0x95, 0xEB, 0x0B, 0xF9, 0x83, 0x77, 0xEF, 0xCE, 0x4C, 0xA7, 0xA0, 0x0B, 0x38, + 0x6E, 0x31, 0xD0, 0xF8, 0x20, 0xCB, 0x63, 0x32, 0xAD, 0x9F, 0x57, 0x68, 0xAA, 0x28, 0x59, 0xC8, + 0x6F, 0x7C, 0x92, 0x97, 0x61, 0x98, 0x7F, 0x4B, 0x63, 0x63, 0xD2, 0xA4, 0xE2, 0x22, 0x51, 0xB6, + 0x9D, 0x95, 0x40, 0x04, 0x1F, 0x64, 0x7B, 0xFF, 0x81, 0xD0, 0x6B, 0x2F, 0xB4, 0x6D, 0x0E, 0x59, + 0xC8, 0x6F, 0x4F, 0x14, 0x41, 0xC2, 0x34, 0x6C, 0x5B, 0x0C, 0xAC, 0xFA, 0x07, 0x42, 0x73, 0xE1, + 0xF9, 0x20, 0xCC, 0x9C, 0x91, 0x88, 0x48, 0xBA, 0x30, 0xEB, 0xA1, 0x04, 0xF8, 0x59, 0x6F, 0x51, + 0xD7, 0xDE, 0x8A, 0x7E, 0xD8, 0x4D, 0xE5, 0x86, 0x17, 0x25, 0x7A, 0x0A, 0xD6, 0x4D, 0x88, 0x8E, + 0xFA, 0x07, 0xE1, 0x76, 0xD7, 0xA8, 0x9D, 0xAE, 0x89, 0xDE, 0xD6, 0xC3, 0xD9, 0xB4, 0x87, 0xAA, + 0x2A, 0xC5, 0xED, 0xAE, 0xBD, 0x53, 0xDD, 0xD8, 0x58, 0x9C, 0x1D, 0x80, 0xB7, 0x12, 0x3D, 0x0A, + 0x70, 0xD4, 0x3F, 0xB0, 0xF0, 0x41, 0x6D, 0xD1, 0x48, 0xD7, 0xA0, 0x03, 0xEF, 0x6F, 0x3E, 0x39, + 0x70, 0x7D, 0x97, 0xB5, 0x99, 0x3E, 0xA2, 0xEE, 0x8E, 0x52, 0xE0, 0x07, 0xFB, 0xD4, 0xCD, 0x01, + 0x71, 0x32, 0xAC, 0x44, 0x6E, 0x61, 0x99, 0x3F, 0xA8, 0x1A, 0x11, 0xF6, 0xC3, 0xF4, 0xD2, 0x1B, + 0xFA, 0xFD, 0x34, 0x3D, 0x62, 0xC9, 0x01, 0x93, 0xA4, 0xF9, 0xAC, 0x0E, 0x71, 0x2B, 0xD9, 0x20, + 0x1F, 0x60, 0xE1, 0x83, 0x0D, 0x7F, 0x1E, 0xE6, 0x8B, 0x0E, 0x05, 0x28, 0xEA, 0x9F, 0x16, 0xAD, + 0xD4, 0x50, 0x07, 0x2A, 0x63, 0x01, 0x69, 0xC1, 0x3F, 0x1F, 0x60, 0xE6, 0x83, 0x7D, 0x93, 0x8B, + 0x5E, 0x2D, 0x1E, 0xFF, 0xE7, 0xC0, 0xC6, 0x9F, 0x68, 0x3E, 0xDB, 0x15, 0x45, 0x41, 0xD1, 0x9D, + 0x05, 0x04, 0xA0, 0x42, 0x08, 0x02, 0x29, 0x0F, 0xF2, 0x01, 0x26, 0x3E, 0x08, 0xAE, 0x87, 0x76, + 0x08, 0x75, 0xFC, 0xD3, 0xD0, 0x2F, 0x14, 0x0B, 0x9F, 0xCD, 0x73, 0x1B, 0x55, 0xF5, 0xEB, 0xC7, + 0x53, 0xA7, 0xDA, 0x15, 0xA8, 0xEE, 0xD9, 0xD8, 0xA1, 0x1D, 0xA4, 0x3C, 0xC8, 0x0B, 0x98, 0xF8, + 0x60, 0xF5, 0x9F, 0xDF, 0x0E, 0x7D, 0x54, 0xAF, 0xBE, 0xE7, 0xF3, 0x80, 0x58, 0x90, 0xD8, 0x75, + 0x60, 0x38, 0xC0, 0x57, 0x87, 0xB7, 0x7A, 0x1B, 0x52, 0x27, 0x9C, 0x08, 0xAA, 0x12, 0x25, 0x56, + 0xE8, 0xDC, 0x0B, 0x78, 0x36, 0xBC, 0x94, 0x07, 0xF9, 0x00, 0xD3, 0x78, 0xE1, 0xFB, 0xD7, 0x0F, + 0xFB, 0xB8, 0xF3, 0x08, 0x56, 0xCB, 0xD9, 0x22, 0xF5, 0x8C, 0x8F, 0xCE, 0xD3, 0x58, 0xB9, 0x20, + 0x3D, 0xA2, 0x5D, 0x42, 0xA5, 0xA1, 0x0B, 0xF2, 0xC0, 0xAC, 0x6A, 0x90, 0xE3, 0x85, 0xBC, 0x80, + 0x89, 0x0F, 0x5A, 0x7D, 0x1F, 0x43, 0x51, 0x79, 0x53, 0x51, 0x67, 0xF9, 0x5E, 0xF0, 0x84, 0x3D, + 0xE3, 0x7C, 0x50, 0xC1, 0xE7, 0xBB, 0x4B, 0xE9, 0x68, 0x8D, 0x0C, 0xC2, 0x5A, 0xF1, 0x92, 0x0D, + 0xF2, 0x01, 0xA6, 0x76, 0xE1, 0xAA, 0xF6, 0x4E, 0x0F, 0x14, 0x8F, 0x1C, 0x32, 0xBA, 0x04, 0x20, + 0xD0, 0x19, 0x9E, 0x05, 0x70, 0xFC, 0x44, 0x7A, 0x44, 0xBB, 0x04, 0xB6, 0x08, 0x6C, 0xEC, 0x48, + 0x3C, 0x20, 0xFB, 0x07, 0xF9, 0x00, 0xCB, 0x3C, 0xD2, 0xB7, 0xF0, 0xFF, 0x72, 0xC0, 0xDA, 0xD9, + 0x3D, 0x7A, 0xEB, 0x6F, 0xD0, 0xBD, 0x7E, 0xC2, 0xA1, 0xE1, 0xF0, 0xCB, 0xCF, 0x95, 0x0E, 0x3C, + 0x58, 0x9E, 0x32, 0xE1, 0xF8, 0xD8, 0x3B, 0x45, 0x38, 0xA2, 0x1D, 0x2B, 0xAE, 0x05, 0x4C, 0xAD, + 0xB5, 0xAC, 0x7E, 0x38, 0xFD, 0xA7, 0x4F, 0x52, 0xA2, 0xBB, 0x30, 0x8F, 0x1B, 0x5F, 0xC2, 0x7F, + 0x85, 0x0D, 0xEA, 0x47, 0x2A, 0xC7, 0xC8, 0x63, 0xDE, 0xA6, 0x11, 0x8A, 0xF2, 0x8B, 0xCC, 0xD7, + 0x4F, 0x27, 0x1B, 0x2B, 0x44, 0x79, 0xDA, 0x52, 0x1E, 0xE4, 0x03, 0xCC, 0xF2, 0xE0, 0x96, 0xBF, + 0x02, 0x7E, 0x9D, 0x54, 0x2F, 0x3B, 0x2E, 0x18, 0xC1, 0x7C, 0xE6, 0xB1, 0xC6, 0x3B, 0xD3, 0xFD, + 0x03, 0x6C, 0x14, 0x00, 0x4E, 0x94, 0x75, 0xF8, 0x8B, 0xAF, 0x44, 0x87, 0x0A, 0xA5, 0x6D, 0xC0, + 0xFE, 0x25, 0x72, 0x07, 0x13, 0x1F, 0x3C, 0xFB, 0xC3, 0x75, 0xB0, 0xE1, 0x96, 0x97, 0x6E, 0x41, + 0xE7, 0xE7, 0x5F, 0xFE, 0xDE, 0x17, 0x9F, 0x4B, 0x8F, 0x60, 0xD7, 0xA0, 0x6D, 0xD9, 0x01, 0x28, + 0x43, 0xA5, 0xD9, 0x0E, 0xFF, 0x64, 0x90, 0xE3, 0x85, 0xBC, 0x80, 0x89, 0x0F, 0xA6, 0x3C, 0xF2, + 0x95, 0x72, 0x78, 0x05, 0x76, 0xA2, 0xB3, 0x01, 0x36, 0x3D, 0xA7, 0xB5, 0xE2, 0x19, 0xC7, 0x80, + 0x39, 0x6D, 0xA1, 0x3D, 0x70, 0x61, 0x91, 0x68, 0x92, 0x24, 0x1B, 0xE4, 0x03, 0x4C, 0x7C, 0xE0, + 0x9B, 0xC5, 0x04, 0x76, 0x0F, 0xA0, 0x0F, 0xAA, 0xDE, 0xE8, 0x37, 0xB9, 0x5A, 0x87, 0xEF, 0xAD, + 0x70, 0xAE, 0x12, 0x07, 0xFD, 0xC4, 0x70, 0xDB, 0x61, 0xF0, 0x54, 0xF4, 0x98, 0xE2, 0x62, 0x36, + 0xD6, 0xD8, 0x25, 0xE2, 0xC3, 0xB9, 0x16, 0x62, 0xAB, 0x3B, 0xB8, 0x77, 0xFA, 0x64, 0xF7, 0x99, + 0x5D, 0x53, 0xB3, 0x69, 0x3B, 0x3B, 0xFC, 0x42, 0xD8, 0x15, 0x05, 0xCF, 0x6D, 0x52, 0x4B, 0x36, + 0x5F, 0x10, 0xB3, 0x7F, 0x21, 0x52, 0xFB, 0x89, 0x03, 0x6A, 0xE4, 0xB0, 0x52, 0x9B, 0x45, 0x15, + 0xF3, 0xAD, 0xEB, 0x43, 0x2E, 0x70, 0xB9, 0x3A, 0xD7, 0x6F, 0xED, 0x36, 0x29, 0x89, 0xCC, 0x20, + 0x86, 0x0F, 0x5A, 0x7F, 0xB9, 0x46, 0x55, 0x42, 0xD1, 0xD1, 0xC5, 0xD9, 0x33, 0xE8, 0xF4, 0xDB, + 0xF7, 0x15, 0x35, 0x1C, 0x0E, 0x87, 0x55, 0x78, 0xFF, 0xB7, 0xDD, 0x26, 0x26, 0x91, 0x11, 0xC4, + 0xF0, 0xC1, 0xE1, 0x6B, 0x4B, 0x4A, 0xDC, 0xBE, 0xA2, 0x63, 0x35, 0x9D, 0xA9, 0x13, 0x4B, 0x0E, + 0x9D, 0x0F, 0x82, 0xAA, 0xAA, 0x1E, 0x0F, 0x35, 0x55, 0x1D, 0xD1, 0xE4, 0x9F, 0x6B, 0x9D, 0x61, + 0x9F, 0xC7, 0x88, 0xF5, 0x29, 0x2C, 0xE4, 0x51, 0xFE, 0x63, 0xF7, 0xB5, 0x9D, 0xBD, 0x16, 0x95, + 0x02, 0xD4, 0x09, 0xFF, 0x8C, 0x4E, 0x0F, 0xAA, 0xA1, 0x3C, 0x94, 0x1A, 0xBD, 0x24, 0x70, 0xF7, + 0xD4, 0xD3, 0xA0, 0x2C, 0xBC, 0xFD, 0xF6, 0x85, 0x53, 0xA7, 0x4C, 0x99, 0x62, 0x6C, 0xAA, 0x08, + 0x94, 0x29, 0xBE, 0xE3, 0x96, 0x2B, 0xFA, 0x5D, 0x11, 0x82, 0x56, 0x8F, 0xE2, 0x32, 0xAF, 0x7B, + 0xE7, 0x7B, 0xE5, 0xAF, 0x9B, 0xC6, 0xF2, 0x87, 0xD9, 0x56, 0xEE, 0x16, 0xF7, 0x9B, 0xB1, 0x1C, + 0x6D, 0xFA, 0x3C, 0xC9, 0x69, 0xF8, 0xB0, 0x77, 0x6D, 0xED, 0x8B, 0xB3, 0xBA, 0x88, 0x41, 0x1E, + 0x7A, 0x60, 0xDD, 0xB4, 0x66, 0x51, 0x00, 0x94, 0x42, 0xC6, 0xAA, 0x27, 0x86, 0x0F, 0x3C, 0x93, + 0xC7, 0x76, 0x1E, 0x8D, 0x44, 0x9A, 0x3D, 0x45, 0x00, 0x53, 0x3B, 0xD5, 0x96, 0x15, 0x8F, 0xA4, + 0x4C, 0xB3, 0x0B, 0x1C, 0x19, 0xF0, 0xB3, 0xA6, 0x3B, 0xEF, 0x7B, 0xE8, 0xA1, 0x15, 0xFF, 0x80, + 0x37, 0xAD, 0xBA, 0xF7, 0x33, 0x8B, 0xD4, 0x4D, 0xD7, 0x5A, 0xAE, 0xB0, 0xB9, 0x04, 0x0D, 0x8A, + 0xFC, 0xEC, 0x90, 0xBA, 0xF5, 0x9A, 0xC2, 0xF9, 0xEE, 0xD7, 0x2D, 0xE7, 0x45, 0x5A, 0xF3, 0x80, + 0xDA, 0xFE, 0x1C, 0xF2, 0x2F, 0xDD, 0xCF, 0x43, 0xF9, 0xF7, 0x94, 0x69, 0xA8, 0x0C, 0x42, 0xC3, + 0x27, 0xC9, 0x65, 0xBC, 0xF1, 0x87, 0xD5, 0x96, 0xE9, 0x9D, 0xEA, 0x61, 0xFF, 0xC7, 0x0D, 0xD0, + 0xFA, 0xA4, 0x51, 0x63, 0x99, 0xAC, 0x1E, 0x1B, 0x1F, 0x84, 0x83, 0x23, 0xC3, 0x07, 0xC6, 0x0E, + 0x77, 0x4F, 0x2E, 0xB9, 0x90, 0x6F, 0x86, 0x28, 0x6D, 0x7E, 0x31, 0x94, 0x71, 0x3D, 0x94, 0xCB, + 0x07, 0x74, 0x54, 0x47, 0xA3, 0xA1, 0x23, 0x98, 0x38, 0xAE, 0x6D, 0x02, 0x7E, 0x2E, 0xAE, 0x86, + 0xC0, 0x63, 0x5F, 0x83, 0x4B, 0x43, 0x2D, 0xA6, 0x6B, 0x08, 0xE6, 0xB5, 0xB8, 0xD8, 0xB2, 0x64, + 0xA5, 0xC8, 0xE5, 0xCF, 0x88, 0xFF, 0xD7, 0xED, 0x2E, 0x1A, 0x84, 0x5F, 0xC8, 0xF2, 0xD5, 0x59, + 0x10, 0x55, 0xDD, 0xC7, 0xE6, 0x83, 0x62, 0xE7, 0xFA, 0xC5, 0xF7, 0x83, 0xFF, 0xFB, 0xC6, 0x7D, + 0xEB, 0xD2, 0x25, 0xE6, 0x68, 0x5C, 0xC3, 0xA7, 0x8C, 0xBD, 0x51, 0xEB, 0x8C, 0x27, 0x7C, 0xC7, + 0xF1, 0xE3, 0xC6, 0x8B, 0xF6, 0x5E, 0x76, 0x19, 0xC8, 0x31, 0x7E, 0xF5, 0x4F, 0xE0, 0x3F, 0x6F, + 0xB6, 0x78, 0x51, 0xF5, 0xC4, 0xC4, 0x4B, 0x07, 0x66, 0x3E, 0x88, 0x74, 0x9C, 0x51, 0x8A, 0xFA, + 0x4E, 0x80, 0xC3, 0x6E, 0x08, 0xD5, 0x6F, 0x10, 0xE3, 0x46, 0x77, 0x53, 0xA6, 0x77, 0x1D, 0x47, + 0xC1, 0xBF, 0xE3, 0xA3, 0xB6, 0xEA, 0xEA, 0xBF, 0xA0, 0xA6, 0x0B, 0x03, 0x7E, 0x2E, 0x5B, 0x6F, + 0x24, 0x07, 0x4F, 0xCB, 0x7C, 0x05, 0xF0, 0x7F, 0x67, 0x96, 0xD2, 0xEF, 0x8F, 0x5E, 0x72, 0xD6, + 0xB6, 0xA8, 0xDB, 0x5E, 0x0A, 0x2D, 0x9A, 0xDE, 0x79, 0x38, 0x58, 0xB5, 0x6D, 0xD5, 0x97, 0xB6, + 0xBD, 0x94, 0x09, 0x43, 0x11, 0x99, 0xC5, 0xE6, 0xD7, 0xD7, 0x1A, 0x37, 0xAD, 0xCF, 0x97, 0xE9, + 0xF7, 0xFF, 0xF9, 0x0D, 0xCB, 0x72, 0xDD, 0x4A, 0x3E, 0x62, 0xAE, 0x6D, 0xC7, 0x37, 0x0A, 0xD7, + 0xB6, 0x07, 0xFB, 0x8F, 0x5F, 0x49, 0x12, 0x50, 0xBC, 0x57, 0xCB, 0xA4, 0x06, 0xF5, 0xEC, 0xE7, + 0xA8, 0x82, 0x6B, 0x8B, 0x14, 0xA5, 0xAF, 0xDE, 0x87, 0xFA, 0xEC, 0x8B, 0xF5, 0xBF, 0x5C, 0x66, + 0x4D, 0x30, 0x53, 0xD5, 0x63, 0x1A, 0xC1, 0x07, 0x0F, 0x52, 0xB9, 0x7A, 0xC2, 0xDE, 0xCE, 0x6A, + 0x55, 0xF1, 0xE2, 0x29, 0x4C, 0x5A, 0x40, 0xA6, 0xD7, 0x99, 0xFC, 0x81, 0xE6, 0x51, 0x01, 0xFC, + 0xCE, 0x47, 0xE2, 0xA7, 0x82, 0x7D, 0x11, 0x68, 0x1D, 0x10, 0x81, 0xCA, 0xB8, 0x75, 0xFA, 0xCC, + 0xA2, 0xFB, 0x57, 0xDF, 0xC8, 0x6C, 0x65, 0x4C, 0x5D, 0xA6, 0x49, 0x86, 0x29, 0x65, 0x03, 0xA6, + 0x95, 0x0D, 0xC8, 0x43, 0xDB, 0x8F, 0x3B, 0x7F, 0xFC, 0x63, 0x40, 0x2D, 0x2B, 0xC6, 0xB6, 0x81, + 0x09, 0x55, 0x5E, 0xED, 0xBE, 0x75, 0x69, 0xBD, 0x25, 0x9E, 0xD0, 0xF0, 0x99, 0xBA, 0x84, 0xDE, + 0x08, 0xAF, 0x91, 0x11, 0x4B, 0xE0, 0xD2, 0xF7, 0x4E, 0x88, 0xF7, 0x8A, 0x34, 0xE2, 0x32, 0x5F, + 0x71, 0x13, 0x72, 0xCE, 0xD4, 0x2A, 0x2F, 0xB4, 0x7E, 0x4A, 0x7B, 0xCA, 0xB7, 0x74, 0xC2, 0xC3, + 0x59, 0x9A, 0x72, 0x31, 0x91, 0x9D, 0xB5, 0x61, 0x92, 0x7E, 0xD7, 0x52, 0x14, 0x14, 0xB3, 0xCC, + 0x91, 0xC1, 0x99, 0xDE, 0x84, 0x3B, 0xAC, 0x71, 0xC0, 0x80, 0x6F, 0x57, 0xED, 0x53, 0x3E, 0xF9, + 0x37, 0xBC, 0xE9, 0x8B, 0xFF, 0x03, 0x0F, 0x95, 0xF3, 0x77, 0xE5, 0x69, 0x99, 0xAF, 0x80, 0xE3, + 0xD8, 0x2A, 0xF8, 0xAE, 0xD2, 0x90, 0x49, 0x05, 0x88, 0x2C, 0x62, 0xD9, 0x32, 0xAC, 0x36, 0xAC, + 0x3B, 0x74, 0x06, 0xC6, 0xBD, 0x53, 0xAE, 0xDF, 0xDB, 0xC4, 0x01, 0x6A, 0xF8, 0x24, 0x7C, 0x21, + 0xAA, 0x7E, 0x27, 0xFF, 0x7F, 0x59, 0x7A, 0x27, 0x00, 0x76, 0xDC, 0x0C, 0x64, 0xAA, 0x7A, 0xAC, + 0xDF, 0xD4, 0xBE, 0x7D, 0x84, 0x48, 0x64, 0xCA, 0x37, 0x67, 0x32, 0x05, 0x04, 0x80, 0xC0, 0xF8, + 0x5B, 0xBD, 0x19, 0xEE, 0x1F, 0xFC, 0x02, 0xE5, 0x5C, 0xCB, 0x0D, 0xF5, 0x3F, 0xFB, 0x6F, 0x1C, + 0x38, 0xB6, 0xD3, 0x46, 0xE8, 0x29, 0x65, 0xB0, 0x35, 0xEA, 0x5B, 0xFA, 0x34, 0x6C, 0xF5, 0xF6, + 0x35, 0x5D, 0x79, 0x51, 0xB8, 0x1B, 0x57, 0x43, 0x64, 0xA5, 0xA7, 0xB5, 0x8F, 0xAE, 0x36, 0x5D, + 0x97, 0xFF, 0xE6, 0x31, 0x56, 0xDF, 0x0D, 0xAD, 0xFD, 0x90, 0x0D, 0xB4, 0x7B, 0x5B, 0xEF, 0x00, + 0x50, 0xC3, 0x07, 0x5F, 0xE7, 0x97, 0x46, 0x3F, 0xD1, 0xDD, 0xB8, 0x06, 0xB6, 0x4E, 0x66, 0xD6, + 0x50, 0xC4, 0x9D, 0x23, 0xDD, 0xD2, 0x36, 0x64, 0x27, 0xF3, 0x80, 0x9E, 0x55, 0x0F, 0x16, 0x8D, + 0xF6, 0xEF, 0xFC, 0x58, 0x12, 0x30, 0x8B, 0x99, 0xF0, 0x74, 0x1A, 0xD2, 0xAB, 0x2E, 0x78, 0xF7, + 0x42, 0xEF, 0x31, 0x92, 0xD3, 0xB5, 0x45, 0xA0, 0x1C, 0xCE, 0xF8, 0x97, 0xE8, 0x7E, 0xF0, 0xC1, + 0x41, 0x30, 0x60, 0x43, 0x78, 0x0C, 0xC0, 0xD9, 0x81, 0x64, 0xB1, 0xE9, 0xAB, 0x45, 0x30, 0x70, + 0x34, 0x2C, 0x1C, 0xBB, 0xBC, 0xF8, 0x90, 0xE5, 0x0A, 0x9B, 0x3F, 0x0B, 0x45, 0x0F, 0xD7, 0x0F, + 0x58, 0xAE, 0x1C, 0x1E, 0x6E, 0x8C, 0x2B, 0x4A, 0x1F, 0x1B, 0x81, 0xB1, 0x99, 0xD3, 0xF2, 0x65, + 0xE4, 0x11, 0x02, 0x4F, 0xBC, 0x03, 0x5B, 0xC3, 0xA3, 0x00, 0x16, 0x8B, 0xDE, 0xC1, 0x3A, 0x9B, + 0x38, 0x20, 0x0D, 0x1F, 0x80, 0xD9, 0xB7, 0xE9, 0xF7, 0xFE, 0xFA, 0x01, 0xF7, 0xD2, 0x1B, 0x73, + 0xF8, 0xF0, 0x0E, 0x2A, 0x79, 0xEB, 0xE2, 0x00, 0xAC, 0x96, 0x62, 0x54, 0x14, 0xCB, 0x68, 0xF5, + 0x68, 0xF6, 0x50, 0xD0, 0x39, 0xE5, 0x85, 0xC9, 0x64, 0x4B, 0x69, 0xD2, 0xBE, 0x4F, 0x78, 0xAE, + 0x19, 0xF6, 0xCE, 0x8B, 0xB7, 0x65, 0x72, 0xF5, 0x91, 0x1D, 0xF9, 0xCA, 0x93, 0x41, 0xBC, 0xFB, + 0x20, 0x0C, 0x3A, 0x73, 0x57, 0xBF, 0xF6, 0xF0, 0xC0, 0xEC, 0x6C, 0x92, 0xC9, 0x35, 0xB6, 0x7F, + 0x27, 0x87, 0x06, 0x32, 0xBB, 0x82, 0xF5, 0xF4, 0x5D, 0x07, 0x7B, 0x28, 0xCF, 0xDE, 0xFA, 0x22, + 0x60, 0x37, 0xB1, 0x06, 0xF6, 0xC3, 0x8F, 0xFA, 0xB4, 0xDD, 0xFA, 0x5F, 0x29, 0x51, 0x4F, 0x09, + 0x17, 0x6C, 0xF8, 0xDA, 0xEF, 0x3E, 0x07, 0xCD, 0x7D, 0xFE, 0xF1, 0x1C, 0xB5, 0xF2, 0x7D, 0xF6, + 0xBA, 0x6E, 0x93, 0xE8, 0x69, 0x98, 0xF5, 0x50, 0x7E, 0xFB, 0x03, 0x40, 0x0D, 0x94, 0x72, 0xC0, + 0x4E, 0x59, 0x03, 0xFC, 0x76, 0x52, 0x9A, 0x14, 0x93, 0x41, 0x51, 0x36, 0xF7, 0x53, 0xE7, 0x1E, + 0xF3, 0xE6, 0x75, 0x9B, 0x44, 0x4F, 0xC3, 0xA2, 0x87, 0xB2, 0x39, 0x5D, 0x2A, 0x12, 0x85, 0x0E, + 0x79, 0xFE, 0x82, 0x04, 0x21, 0x37, 0x9A, 0x20, 0x52, 0x0F, 0x25, 0xDF, 0x90, 0x93, 0x9A, 0xD8, + 0xFA, 0xBE, 0xE2, 0x41, 0x49, 0xD4, 0xB9, 0xFE, 0x93, 0x97, 0x76, 0x9B, 0x96, 0x44, 0x46, 0x90, + 0x0B, 0x3E, 0xF8, 0x6D, 0x87, 0x02, 0x61, 0x54, 0x98, 0x44, 0x3D, 0x94, 0x83, 0x5F, 0xEA, 0x36, + 0x35, 0x89, 0x4C, 0x20, 0x07, 0xFD, 0x03, 0xAE, 0x87, 0xE2, 0xE6, 0x7A, 0x28, 0x29, 0x2C, 0x15, + 0x49, 0x3D, 0x94, 0x2C, 0x22, 0x21, 0x1F, 0xA0, 0xA2, 0x83, 0xC3, 0xF2, 0x67, 0x77, 0x61, 0xD1, + 0x43, 0x79, 0x57, 0xF7, 0x8E, 0xA7, 0x87, 0xA2, 0xB9, 0x35, 0x14, 0x88, 0x1E, 0x0A, 0x66, 0x9B, + 0x0A, 0x0F, 0xF5, 0x4D, 0x48, 0x1B, 0x85, 0x5E, 0xC4, 0x12, 0x2B, 0xEF, 0xF5, 0x50, 0xCC, 0x40, + 0x45, 0x87, 0xB3, 0xE7, 0x67, 0xDC, 0x1C, 0xCA, 0x91, 0x11, 0xFF, 0x2F, 0x15, 0x3D, 0x94, 0x27, + 0x17, 0xA9, 0x5B, 0xAE, 0x2A, 0x3C, 0x3D, 0x14, 0x28, 0x6A, 0x54, 0xA3, 0xE5, 0xDB, 0x51, 0xDF, + 0x04, 0xE7, 0x96, 0xD9, 0x8B, 0x98, 0x91, 0x39, 0x3D, 0x94, 0x0C, 0x31, 0x42, 0x8C, 0x1E, 0x4A, + 0x10, 0x61, 0x92, 0xD6, 0xEE, 0x41, 0x00, 0x19, 0x5E, 0x67, 0x8A, 0xC2, 0xA7, 0xB8, 0x1E, 0xCA, + 0xB1, 0xA4, 0xF4, 0x50, 0x7E, 0xF6, 0x35, 0x98, 0x71, 0x9A, 0x2F, 0x2D, 0xD9, 0xF4, 0x50, 0x32, + 0xAE, 0x29, 0x95, 0x01, 0xE8, 0x7A, 0x28, 0x1C, 0xEF, 0x92, 0xBE, 0x09, 0xB0, 0x17, 0xB1, 0x44, + 0x4B, 0xA8, 0x87, 0xF2, 0x48, 0x2A, 0x7A, 0x28, 0x2F, 0x67, 0x47, 0x0F, 0xC5, 0x5D, 0x54, 0x54, + 0x54, 0xE4, 0x81, 0x33, 0x1D, 0x11, 0xEE, 0xB7, 0x6B, 0x60, 0xC6, 0x6D, 0x3F, 0xBB, 0x02, 0xB0, + 0xE3, 0xE4, 0x99, 0xEA, 0xC0, 0x5F, 0xE8, 0x86, 0xF4, 0x0F, 0x12, 0xEA, 0xA1, 0x40, 0x28, 0x0C, + 0xFE, 0x45, 0x8C, 0x31, 0xED, 0x7A, 0x28, 0x2F, 0xE4, 0xB5, 0x1E, 0x4A, 0xE7, 0x08, 0xE5, 0xEE, + 0xC0, 0xCA, 0x51, 0xCE, 0xA2, 0xDB, 0xAA, 0x87, 0xD2, 0x62, 0xD5, 0x43, 0x79, 0x21, 0x0F, 0xF4, + 0x50, 0xD8, 0x7D, 0x58, 0xD8, 0x43, 0xC1, 0x05, 0x2D, 0x5A, 0xF5, 0xCA, 0xB0, 0x1E, 0x0A, 0xBE, + 0x56, 0xB8, 0x3C, 0x74, 0xEA, 0x2D, 0xA6, 0x87, 0x42, 0x48, 0xA8, 0x87, 0xE2, 0x3F, 0x80, 0xA1, + 0xC5, 0xCC, 0x40, 0x4F, 0x41, 0xE9, 0xA1, 0xF8, 0x4F, 0xA0, 0x06, 0xC2, 0xD7, 0x8B, 0x1A, 0xD1, + 0xB2, 0xC3, 0xD7, 0x62, 0x2D, 0x07, 0x58, 0xF5, 0x50, 0x96, 0xA5, 0xA4, 0x87, 0x92, 0x95, 0x55, + 0x56, 0x8B, 0x1E, 0xCA, 0x44, 0xCD, 0x50, 0x9A, 0xD0, 0x43, 0x99, 0x5A, 0xD5, 0x51, 0x46, 0xB9, + 0xC9, 0x2C, 0x86, 0x9D, 0x1A, 0x00, 0x8B, 0xAA, 0xDE, 0x07, 0xA6, 0x87, 0xD2, 0x07, 0xFF, 0x13, + 0xEA, 0xA1, 0x40, 0x69, 0x18, 0x4B, 0xA2, 0x47, 0x0C, 0xD2, 0x67, 0x00, 0x26, 0x3D, 0x14, 0x60, + 0xFA, 0x89, 0x00, 0xA5, 0xCB, 0x1D, 0x58, 0xBC, 0x3B, 0x7A, 0x28, 0x96, 0x0D, 0x05, 0xD9, 0xD0, + 0x43, 0x19, 0xA9, 0x46, 0x3A, 0x22, 0xEC, 0x0F, 0xF5, 0x50, 0xF8, 0xC2, 0x76, 0xE9, 0x1B, 0x63, + 0x51, 0xC1, 0x21, 0xF3, 0x7A, 0x28, 0xAD, 0x37, 0x1C, 0x60, 0x7A, 0x28, 0x67, 0xA9, 0x0B, 0x6C, + 0xD1, 0x43, 0xF9, 0x95, 0x7E, 0x35, 0x8A, 0x62, 0xDD, 0x15, 0x4C, 0xD9, 0x42, 0xDC, 0x15, 0x86, + 0x1E, 0xCA, 0x76, 0xD4, 0x36, 0x5D, 0xD9, 0x6F, 0xE9, 0x1A, 0xBC, 0x3A, 0xCC, 0xD1, 0x98, 0xF5, + 0x50, 0xE8, 0xFB, 0x4E, 0x45, 0x0F, 0xC5, 0x8C, 0x8C, 0xE9, 0xA1, 0x98, 0xF8, 0xA0, 0xFC, 0xB0, + 0x07, 0x39, 0x37, 0x0C, 0xE1, 0x30, 0x5C, 0xE8, 0x3F, 0x86, 0x4B, 0x8E, 0xE4, 0x79, 0xF1, 0xA6, + 0x91, 0x99, 0x1E, 0x39, 0xBA, 0x1F, 0xFC, 0x18, 0x60, 0xC4, 0x86, 0xD3, 0x4C, 0x0F, 0x85, 0xD2, + 0xFF, 0x6A, 0x91, 0x72, 0xBB, 0x0B, 0x16, 0xAE, 0x53, 0xAE, 0x7F, 0x05, 0x16, 0x3E, 0x69, 0x5C, + 0x61, 0x73, 0xDF, 0xDD, 0x45, 0x0F, 0xE1, 0x08, 0xEB, 0xA4, 0x49, 0xF9, 0x93, 0xF4, 0x50, 0x84, + 0x1A, 0x4A, 0xDE, 0x22, 0xF0, 0xC4, 0xF7, 0xA1, 0x72, 0x85, 0xD2, 0xF7, 0xDE, 0xE1, 0x8B, 0x86, + 0x2A, 0xFD, 0xFE, 0x3E, 0x9C, 0xBF, 0x88, 0x39, 0x06, 0xB7, 0x34, 0xC3, 0xEB, 0x9D, 0xBE, 0x6F, + 0x7F, 0xFD, 0x72, 0xF6, 0xC6, 0x1C, 0x3E, 0xBC, 0x53, 0xF8, 0xF0, 0xD3, 0x09, 0xD8, 0x69, 0x60, + 0x23, 0x69, 0xFC, 0xED, 0x53, 0xFD, 0xC3, 0x78, 0xB1, 0x52, 0x83, 0x45, 0x0F, 0x65, 0x22, 0x5A, + 0x4E, 0xC4, 0x9E, 0x01, 0x84, 0x2F, 0xB8, 0x68, 0xDB, 0xC6, 0xF9, 0x52, 0x0F, 0x25, 0x5D, 0x14, + 0xB6, 0x1E, 0xCA, 0x6F, 0x49, 0x0F, 0x85, 0xE3, 0x85, 0xD2, 0xD6, 0x9B, 0xB2, 0xB8, 0xF5, 0x90, + 0xE9, 0xA1, 0x28, 0xCD, 0x25, 0x52, 0x0F, 0x25, 0x6F, 0x60, 0xE2, 0x83, 0x49, 0xBF, 0x21, 0x3D, + 0x14, 0xA1, 0x86, 0x52, 0xFE, 0xDB, 0xAC, 0xD9, 0x43, 0x41, 0x48, 0x3D, 0x94, 0x7C, 0x83, 0x59, + 0x0F, 0x65, 0xB6, 0xD4, 0x43, 0xE9, 0xB5, 0x90, 0x7A, 0x28, 0x12, 0x04, 0xA9, 0x87, 0x22, 0x41, + 0xC8, 0x91, 0x1E, 0x8A, 0xCB, 0x2D, 0xF5, 0x50, 0xF2, 0x0A, 0x39, 0xD2, 0x43, 0x51, 0x69, 0x8E, + 0x4D, 0xEA, 0xA1, 0xE4, 0x0F, 0x72, 0xA6, 0x87, 0x22, 0xED, 0xA1, 0x40, 0xC1, 0xE8, 0xA1, 0x64, + 0x07, 0x49, 0xDB, 0x43, 0xE1, 0x26, 0x45, 0x0A, 0x4A, 0x0F, 0x45, 0xB7, 0x82, 0x42, 0x60, 0x1A, + 0x29, 0xC2, 0xA4, 0x8B, 0xE1, 0xCB, 0x51, 0x50, 0x7A, 0x28, 0xD9, 0x41, 0xD2, 0xF6, 0x50, 0xB8, + 0x49, 0x11, 0xA1, 0x93, 0x52, 0x18, 0xD0, 0xAC, 0xA0, 0x10, 0x98, 0x46, 0x0A, 0xD3, 0x40, 0x31, + 0xFB, 0x72, 0xE4, 0xBB, 0x3D, 0x94, 0x9E, 0x41, 0x92, 0xF6, 0x50, 0x98, 0x49, 0x91, 0x76, 0xA1, + 0x93, 0x42, 0xCF, 0xE5, 0xBF, 0x3D, 0x14, 0x61, 0x05, 0x85, 0xC0, 0x35, 0x52, 0x98, 0x06, 0x8A, + 0xC9, 0x57, 0x20, 0xAF, 0xED, 0xA1, 0xF4, 0x10, 0x52, 0xB1, 0x87, 0xD2, 0xFA, 0x3C, 0x19, 0x7E, + 0x17, 0xCA, 0x16, 0x05, 0x60, 0x0F, 0x05, 0x81, 0x56, 0x50, 0xE8, 0xC7, 0x62, 0x19, 0x45, 0xF7, + 0xD5, 0x90, 0x77, 0xF6, 0x50, 0x72, 0x21, 0x0F, 0xFC, 0x81, 0x53, 0xA3, 0x02, 0xA7, 0x4E, 0x85, + 0x46, 0xE2, 0x0B, 0x32, 0x7B, 0x28, 0x1E, 0xE5, 0x12, 0x67, 0xC5, 0xE5, 0xC0, 0x84, 0x3F, 0x9A, + 0x06, 0x34, 0x66, 0x3D, 0x94, 0xCA, 0x69, 0x65, 0x9A, 0xD5, 0xA4, 0xFC, 0x02, 0x66, 0x99, 0x2D, + 0x98, 0xEF, 0xFC, 0xB1, 0xD2, 0x77, 0xF7, 0x2C, 0xED, 0x63, 0xD5, 0x7C, 0x35, 0xC4, 0xB5, 0x87, + 0xC2, 0xDE, 0x0B, 0xF5, 0x50, 0x94, 0xBE, 0xEF, 0x53, 0x05, 0xA3, 0xE8, 0x57, 0x0D, 0x9D, 0x36, + 0xD4, 0x43, 0xB9, 0x35, 0x4B, 0x03, 0xBC, 0x1C, 0x94, 0xE5, 0xB0, 0x46, 0x40, 0x7B, 0x28, 0xCF, + 0xFE, 0xA6, 0xCA, 0xB0, 0x87, 0x22, 0xDE, 0xD5, 0xAE, 0x87, 0xC2, 0x4C, 0x8A, 0xE8, 0x3E, 0x05, + 0x01, 0x2D, 0xCB, 0xB0, 0x0C, 0x2B, 0x70, 0xBA, 0x66, 0xC2, 0x40, 0xF7, 0xD5, 0xD0, 0xC5, 0x89, + 0x47, 0x54, 0xFD, 0x41, 0x07, 0x05, 0xA0, 0x7F, 0x29, 0xE9, 0x19, 0x7B, 0x28, 0x3D, 0x82, 0xA4, + 0xED, 0xA1, 0x30, 0x93, 0x22, 0x7E, 0xAE, 0x93, 0x52, 0x20, 0x7A, 0x28, 0xC2, 0x0A, 0x0A, 0xEA, + 0xA1, 0x38, 0xF8, 0x9A, 0x90, 0xD7, 0xF6, 0x50, 0x7A, 0x08, 0x49, 0xDB, 0x43, 0xE1, 0x26, 0x45, + 0x56, 0x8D, 0x35, 0x59, 0x0A, 0x41, 0xE4, 0xB5, 0x3D, 0x14, 0x91, 0x65, 0xB4, 0x87, 0x22, 0x3C, + 0xC8, 0xA4, 0xCB, 0xCA, 0x0B, 0xCD, 0xB6, 0x51, 0x18, 0xF2, 0xD9, 0x1E, 0x4A, 0x36, 0x21, 0xF5, + 0x50, 0xF2, 0x06, 0xCE, 0x7A, 0x28, 0x39, 0xE9, 0x6B, 0x5D, 0xB0, 0x61, 0xE0, 0xEF, 0x4A, 0xA0, + 0xD9, 0x7B, 0xE5, 0xB9, 0xC9, 0x06, 0x05, 0xAE, 0x87, 0xD2, 0x83, 0x90, 0x7A, 0x28, 0xF9, 0x06, + 0xA9, 0x7F, 0x20, 0x41, 0x90, 0x7C, 0x20, 0x41, 0x90, 0x7A, 0x28, 0x12, 0x04, 0x69, 0x0F, 0x45, + 0x82, 0x20, 0xED, 0xA1, 0x48, 0x10, 0xA4, 0x3D, 0x94, 0x1C, 0x42, 0xEA, 0xA1, 0x24, 0x65, 0x0F, + 0x45, 0x53, 0xDF, 0xB0, 0x1A, 0x13, 0x29, 0x20, 0x7B, 0x28, 0x34, 0x3D, 0xC2, 0x33, 0x5F, 0xD8, + 0xF6, 0x50, 0xB2, 0x83, 0xA4, 0xED, 0xA1, 0xD4, 0xAC, 0x64, 0xEA, 0x1B, 0x31, 0xC6, 0x44, 0xF2, + 0x1A, 0x9A, 0x3D, 0x94, 0x5D, 0x8B, 0x54, 0x75, 0xBE, 0x96, 0xF9, 0x82, 0xB3, 0x87, 0xD2, 0x13, + 0x48, 0xDA, 0x1E, 0xCA, 0xC5, 0x3F, 0x64, 0xEA, 0x1B, 0x86, 0x31, 0x91, 0x42, 0xB2, 0x87, 0x82, + 0xBA, 0x27, 0x81, 0x75, 0x1E, 0x91, 0xF9, 0xC2, 0xB2, 0x87, 0xD2, 0x43, 0x48, 0xC5, 0x1E, 0x8A, + 0x45, 0x7D, 0xA3, 0xB0, 0xEC, 0xA1, 0xC0, 0xEA, 0x81, 0x55, 0x71, 0x6D, 0x47, 0xE4, 0x9D, 0x3D, + 0x94, 0x9C, 0xC8, 0x03, 0x6E, 0x0F, 0x85, 0xE9, 0xA1, 0x10, 0x12, 0xEA, 0xA1, 0x98, 0x16, 0xDD, + 0x0A, 0x40, 0x0F, 0xC5, 0xAC, 0x7D, 0xB2, 0xEC, 0xF4, 0x8C, 0xB8, 0x26, 0x03, 0xE2, 0xDA, 0x43, + 0x49, 0x42, 0x0F, 0x25, 0x2B, 0xAB, 0xAC, 0xB9, 0xD0, 0x43, 0x69, 0x06, 0xB4, 0x87, 0xF2, 0x1B, + 0xAE, 0x87, 0xC2, 0xED, 0xA1, 0x74, 0xA1, 0x87, 0x52, 0x38, 0xB0, 0x68, 0x9F, 0xF8, 0xEF, 0xFB, + 0x75, 0xBC, 0x78, 0xDD, 0xD1, 0x43, 0xC9, 0xBA, 0x3D, 0x94, 0x1E, 0x42, 0xD2, 0xF6, 0x50, 0xCC, + 0xEA, 0x1B, 0x05, 0x67, 0x0F, 0xE5, 0xCD, 0x06, 0x08, 0xAC, 0xBA, 0x23, 0x5E, 0x84, 0x7C, 0xB6, + 0x87, 0xD2, 0x53, 0x48, 0xDA, 0x1E, 0x0A, 0x2A, 0x75, 0xD0, 0xC0, 0xD1, 0x66, 0x4C, 0xA4, 0x40, + 0xEC, 0xA1, 0x14, 0x8D, 0x52, 0x4A, 0xBE, 0x55, 0x2E, 0x32, 0x5F, 0x50, 0xF6, 0x50, 0xB2, 0x09, + 0xA9, 0x87, 0x92, 0x37, 0xC8, 0x37, 0x3D, 0x14, 0xA5, 0xD9, 0x23, 0xF5, 0x50, 0xF2, 0x06, 0x52, + 0x0F, 0x25, 0x0B, 0x90, 0x7A, 0x28, 0x12, 0x05, 0x0A, 0xC9, 0x07, 0x12, 0x04, 0xA9, 0x87, 0x22, + 0x41, 0x90, 0xF6, 0x50, 0x24, 0x08, 0xD2, 0x1E, 0x8A, 0x04, 0x41, 0xDA, 0x43, 0xC9, 0x21, 0xA4, + 0x1E, 0x4A, 0x0A, 0xF6, 0x50, 0xEC, 0xC6, 0x44, 0xF2, 0xBA, 0xF2, 0xC5, 0x69, 0x3C, 0xDC, 0xC5, + 0xCD, 0xB8, 0xA0, 0x5E, 0x8A, 0xE1, 0xAB, 0x43, 0xEA, 0xA1, 0xA4, 0x6A, 0x0F, 0x25, 0xD6, 0x98, + 0x48, 0x3E, 0x83, 0x9D, 0xC6, 0x43, 0x0E, 0xCD, 0x8C, 0x0B, 0xD3, 0x4B, 0xD1, 0x7D, 0x35, 0x48, + 0x7B, 0x28, 0x84, 0x54, 0xEC, 0xA1, 0x98, 0x8D, 0x89, 0xE4, 0xBF, 0x3D, 0x14, 0x1D, 0xFC, 0x75, + 0x42, 0xF6, 0x73, 0x7A, 0x34, 0x48, 0x7B, 0x28, 0x90, 0xA2, 0x3D, 0x14, 0x5A, 0x8B, 0x11, 0xDA, + 0x28, 0x85, 0x60, 0x0F, 0x85, 0x4E, 0xE3, 0xD1, 0xDC, 0xF8, 0x0A, 0x42, 0x2F, 0xC5, 0xEC, 0xCB, + 0x20, 0xED, 0xA1, 0x20, 0x52, 0xB2, 0x87, 0x82, 0x6B, 0xF9, 0x9A, 0x36, 0x4A, 0x01, 0xE8, 0xA1, + 0xF8, 0x4F, 0x58, 0x1A, 0x31, 0x95, 0xEB, 0xA5, 0x78, 0xAC, 0xBE, 0x08, 0x69, 0x0F, 0x05, 0x52, + 0xB6, 0x87, 0x52, 0x60, 0xDA, 0x28, 0x86, 0x45, 0xAC, 0xC8, 0xE0, 0x21, 0xBA, 0x5E, 0x8A, 0xCD, + 0x4E, 0x96, 0xB4, 0x87, 0x02, 0x29, 0xDA, 0x43, 0x11, 0xC6, 0x44, 0x0A, 0x44, 0x0F, 0x85, 0x9D, + 0xC6, 0xE3, 0x41, 0x3D, 0x14, 0x61, 0xC6, 0xC5, 0xE2, 0x6B, 0x8A, 0x27, 0xED, 0xA1, 0x40, 0xAA, + 0xF6, 0x50, 0xAE, 0x62, 0xD7, 0x15, 0xFA, 0xE3, 0x79, 0x6D, 0x0F, 0xA5, 0xF2, 0xD3, 0xCB, 0x61, + 0xE5, 0xF0, 0x00, 0xDA, 0x43, 0x59, 0x68, 0x32, 0xE3, 0xC2, 0x7D, 0xCD, 0xF1, 0xA4, 0x3D, 0x14, + 0x82, 0xD4, 0x43, 0xC9, 0x21, 0xA4, 0x3D, 0x94, 0x1E, 0x83, 0xD4, 0x43, 0x49, 0x12, 0x52, 0x0F, + 0x25, 0xDF, 0x20, 0xF5, 0x0F, 0x24, 0x08, 0x92, 0x0F, 0x24, 0x08, 0x52, 0x0F, 0x45, 0x82, 0x20, + 0xED, 0xA1, 0x48, 0x10, 0xA4, 0x3D, 0x14, 0x09, 0x82, 0xB4, 0x87, 0x92, 0x43, 0x48, 0x3D, 0x94, + 0x14, 0xEC, 0xA1, 0x68, 0x86, 0x45, 0x34, 0x14, 0xD4, 0xB9, 0x3C, 0x66, 0x6D, 0x14, 0x4B, 0x44, + 0xA9, 0x87, 0x92, 0xAA, 0x3D, 0x14, 0x61, 0x58, 0x24, 0xCD, 0xC4, 0x7A, 0x18, 0xC2, 0x84, 0x0B, + 0x73, 0x93, 0x06, 0x8A, 0x45, 0x1B, 0xC5, 0x04, 0x69, 0x0F, 0x05, 0x52, 0xB5, 0x87, 0x22, 0x0C, + 0x8B, 0xD0, 0x93, 0xF9, 0x6F, 0x0F, 0x45, 0x98, 0x70, 0x21, 0x90, 0x06, 0x4A, 0x30, 0x9E, 0x36, + 0x8A, 0xB4, 0x87, 0x02, 0xA9, 0xDB, 0x43, 0xD1, 0x0C, 0x8B, 0x14, 0x80, 0x3D, 0x14, 0x84, 0xFD, + 0x5C, 0x1E, 0x43, 0x1B, 0xC5, 0x04, 0x69, 0x0F, 0x05, 0x52, 0xB7, 0x87, 0xA2, 0x19, 0x16, 0x29, + 0xBC, 0x73, 0x79, 0x06, 0xE0, 0x0E, 0x7F, 0xD0, 0xB4, 0x51, 0xCC, 0xB1, 0xA4, 0x3D, 0x14, 0x48, + 0xC3, 0x1E, 0x4A, 0x02, 0xC3, 0x22, 0xF9, 0x06, 0xEB, 0xB9, 0x3C, 0xCD, 0x83, 0xC0, 0xD0, 0x46, + 0x31, 0x47, 0x93, 0xF6, 0x50, 0x20, 0x55, 0x7B, 0x28, 0xDC, 0xB0, 0x48, 0x61, 0x9E, 0xCB, 0xE3, + 0x33, 0x6B, 0xA3, 0x98, 0x91, 0x77, 0xF6, 0x50, 0x72, 0xA5, 0x87, 0x32, 0x42, 0xE8, 0xA1, 0x70, + 0x7B, 0x28, 0x66, 0x3D, 0x14, 0xD2, 0xC7, 0xE0, 0x57, 0xAE, 0x87, 0x32, 0x1F, 0x2F, 0x2B, 0xCB, + 0x8D, 0x71, 0x85, 0x49, 0x0F, 0x25, 0xFF, 0x60, 0x3F, 0x97, 0xC7, 0xAC, 0x8D, 0x62, 0x86, 0x59, + 0x0F, 0x85, 0xDB, 0x43, 0x91, 0x7A, 0x28, 0xE7, 0x1E, 0xA4, 0x1E, 0x4A, 0x72, 0x90, 0xF6, 0x50, + 0xF2, 0x0E, 0x52, 0x0F, 0x25, 0x0B, 0xC8, 0x6F, 0x3D, 0x14, 0x63, 0x2B, 0xA1, 0x09, 0x72, 0xE5, + 0xB7, 0xB7, 0xA1, 0xD2, 0xD1, 0x57, 0xF2, 0x41, 0x6F, 0x03, 0xF6, 0x07, 0xAC, 0x60, 0xBE, 0x52, + 0x0F, 0xA5, 0xB7, 0xC1, 0x91, 0x0D, 0xA4, 0x3D, 0x94, 0x5E, 0x07, 0x1B, 0x1B, 0xE4, 0x50, 0x1E, + 0x48, 0x7B, 0x28, 0xB9, 0x84, 0xB3, 0x3C, 0x90, 0xF6, 0x50, 0x72, 0x88, 0x9C, 0xE4, 0xDF, 0x2E, + 0x0F, 0xB8, 0x6F, 0xFE, 0xDB, 0x43, 0xC1, 0x20, 0x8B, 0x12, 0x47, 0x41, 0x9D, 0xCB, 0x83, 0x4B, + 0xEA, 0xF8, 0x63, 0x57, 0xA5, 0x41, 0xE4, 0x4E, 0x0F, 0x25, 0x6F, 0xE4, 0x41, 0x8A, 0xF6, 0x50, + 0x20, 0x46, 0x89, 0x23, 0xAF, 0x61, 0x3D, 0x97, 0x07, 0x97, 0xD4, 0xD5, 0xA7, 0x2E, 0xDB, 0xF5, + 0x5D, 0xBB, 0x2A, 0x4D, 0x0E, 0xED, 0xA1, 0xE4, 0x8D, 0x3C, 0x80, 0xD4, 0xEC, 0xA1, 0x98, 0x94, + 0x38, 0x0A, 0xC0, 0x1E, 0x8A, 0xFD, 0x5C, 0x1E, 0x80, 0xD6, 0xA5, 0x4B, 0x50, 0x3B, 0x45, 0x53, + 0xA5, 0x11, 0xC8, 0xA1, 0x3D, 0x94, 0xBC, 0x91, 0x07, 0x29, 0xDA, 0x43, 0x31, 0x94, 0x38, 0x0A, + 0xC0, 0x1E, 0x8A, 0xC3, 0xB9, 0x3C, 0xFF, 0xF9, 0x0D, 0xBC, 0xDA, 0xCF, 0xE8, 0xC9, 0xA1, 0x3D, + 0x94, 0xFC, 0x91, 0x07, 0xA9, 0xD8, 0x43, 0x79, 0xC5, 0x6B, 0x1C, 0x75, 0x53, 0x90, 0xE7, 0xF2, + 0xA0, 0x38, 0xD0, 0xDD, 0x06, 0x72, 0x68, 0x0F, 0x25, 0x6F, 0xE4, 0x41, 0x4A, 0xF6, 0x50, 0x46, + 0x59, 0x8F, 0xBA, 0xC9, 0x77, 0xC4, 0x9E, 0xCB, 0xC3, 0xC4, 0x81, 0x70, 0x1B, 0xC8, 0xA1, 0x3D, + 0x94, 0xBC, 0x91, 0x07, 0x29, 0xDA, 0x43, 0xE1, 0x28, 0xD4, 0x73, 0x79, 0x98, 0x38, 0x88, 0x3D, + 0xA3, 0x27, 0x87, 0xF6, 0x50, 0x9C, 0xE5, 0x41, 0xFE, 0xDB, 0x43, 0xB1, 0xAB, 0x78, 0xE6, 0xB5, + 0x3D, 0x14, 0x0E, 0xB2, 0x87, 0x52, 0xC4, 0xD4, 0x67, 0x60, 0x1D, 0x89, 0x03, 0xE1, 0x36, 0xC5, + 0xC8, 0xA1, 0x3D, 0x14, 0xBB, 0x3C, 0xE0, 0x8C, 0x20, 0xF5, 0x50, 0xB2, 0x80, 0xBC, 0xD6, 0x43, + 0xB1, 0x33, 0x02, 0x0A, 0x08, 0x69, 0x0F, 0x25, 0x3B, 0xC8, 0x6B, 0x3D, 0x14, 0xE7, 0xFE, 0x81, + 0xD4, 0x43, 0xC9, 0x02, 0xF2, 0x5A, 0x0F, 0x25, 0x6F, 0xC6, 0x0B, 0x12, 0x39, 0x45, 0xFE, 0xCC, + 0x1F, 0x48, 0xE4, 0x12, 0x79, 0x33, 0x5E, 0x40, 0x48, 0x3D, 0x94, 0xDC, 0xC1, 0x79, 0xBC, 0x20, + 0xED, 0xA1, 0xF4, 0x36, 0xE4, 0x8F, 0x3C, 0x90, 0xF6, 0x50, 0x72, 0x09, 0x67, 0x79, 0x20, 0xED, + 0xA1, 0xE4, 0x10, 0x39, 0xC9, 0x7F, 0xDE, 0x8C, 0x17, 0xD2, 0xB0, 0x87, 0x62, 0x5E, 0x84, 0x2D, + 0x9C, 0x73, 0x79, 0x98, 0x2B, 0x70, 0x45, 0x28, 0xE6, 0x68, 0x21, 0x44, 0xEE, 0xF4, 0x50, 0xF2, + 0x66, 0xBC, 0x90, 0xA2, 0x3D, 0x94, 0xD8, 0x43, 0x6D, 0xF2, 0x19, 0x46, 0x66, 0xB9, 0x6B, 0x73, + 0xC9, 0x49, 0xB0, 0x58, 0x49, 0xE1, 0xC8, 0xA1, 0x3D, 0x94, 0xBC, 0x91, 0x07, 0x29, 0xDA, 0x43, + 0x31, 0x3D, 0x99, 0xFF, 0xF6, 0x50, 0x62, 0x30, 0x8F, 0x56, 0x52, 0x63, 0x5E, 0x24, 0x97, 0xF6, + 0x50, 0xF2, 0x46, 0x1E, 0xA4, 0x6A, 0x0F, 0x45, 0x3F, 0xD4, 0xA6, 0x10, 0xEC, 0xA1, 0x18, 0x27, + 0xF0, 0x58, 0xCF, 0xE2, 0x11, 0x56, 0x52, 0x34, 0xE4, 0xD0, 0x1E, 0x4A, 0x1E, 0xC9, 0x83, 0x94, + 0xEC, 0xA1, 0x18, 0x47, 0xDD, 0x14, 0xD4, 0xB9, 0x3C, 0xD6, 0x13, 0x7A, 0x34, 0x2B, 0x29, 0x1A, + 0x72, 0x68, 0x0F, 0x25, 0x6F, 0xE4, 0x41, 0x1A, 0xF6, 0x50, 0xAC, 0x42, 0x35, 0xBF, 0x61, 0x64, + 0xD6, 0x70, 0xC5, 0x1C, 0x2D, 0x94, 0x43, 0x7B, 0x28, 0x79, 0x23, 0x0F, 0x52, 0xB4, 0x87, 0xC2, + 0x0F, 0xB5, 0x29, 0xB4, 0x73, 0x79, 0x2C, 0x67, 0xF1, 0x98, 0x15, 0x6A, 0x38, 0x72, 0x68, 0x0F, + 0xC5, 0x59, 0x1E, 0x40, 0x40, 0x0D, 0x04, 0xAA, 0x26, 0xE0, 0x80, 0x3E, 0xAB, 0xA0, 0x54, 0xF4, + 0x64, 0xAA, 0xAF, 0x5D, 0xB0, 0xE0, 0x1B, 0x0B, 0xBE, 0xB8, 0x7D, 0xFB, 0xF6, 0xCD, 0x3B, 0xE8, + 0xFE, 0x29, 0x80, 0x81, 0xD3, 0x3B, 0xDB, 0x87, 0x41, 0x71, 0xA3, 0x6A, 0xBE, 0xBE, 0x46, 0xF9, + 0x5B, 0xDC, 0x82, 0xEA, 0xAC, 0x2B, 0xD5, 0x96, 0x92, 0x46, 0xEA, 0x33, 0xD3, 0xFF, 0x53, 0x14, + 0x1B, 0x1D, 0x2D, 0xD3, 0x4F, 0xE3, 0x5D, 0xDA, 0x59, 0xCA, 0x0A, 0x78, 0x66, 0xDB, 0xCB, 0x8E, + 0x08, 0x17, 0x7B, 0x87, 0x95, 0xFC, 0x45, 0x2C, 0x11, 0xC9, 0x6B, 0x36, 0x7F, 0x23, 0xF6, 0x16, + 0x18, 0xBD, 0x98, 0xDE, 0x50, 0xFC, 0xE1, 0xC3, 0x95, 0xE4, 0xCB, 0x82, 0xC4, 0x7B, 0xB3, 0x1B, + 0x8A, 0x8F, 0x81, 0x58, 0x3A, 0x2C, 0x05, 0xE5, 0x08, 0xFE, 0x96, 0x34, 0xEA, 0xFF, 0xC9, 0xE4, + 0x11, 0xEB, 0xC2, 0x0C, 0xCE, 0x00, 0x52, 0x0F, 0x25, 0x0B, 0xC8, 0x77, 0x7B, 0x28, 0x31, 0x4D, + 0x83, 0xB4, 0x87, 0x92, 0x15, 0xE4, 0xB5, 0x1E, 0x8A, 0x73, 0xFF, 0x40, 0xEA, 0xA1, 0x64, 0x01, + 0x79, 0xAD, 0x87, 0x12, 0x2B, 0x0D, 0xC8, 0x57, 0xEA, 0x1F, 0xF4, 0x36, 0xE4, 0xCD, 0x78, 0x41, + 0x22, 0xA7, 0x70, 0x1E, 0x2F, 0x48, 0x3D, 0x94, 0xDE, 0x86, 0x3C, 0xEA, 0x1F, 0x48, 0x7B, 0x28, + 0x39, 0x84, 0x73, 0xFF, 0x40, 0xDA, 0x43, 0xE9, 0x6D, 0xC8, 0x9B, 0xFE, 0x81, 0xB4, 0x87, 0xA2, + 0x41, 0xDA, 0x43, 0x49, 0xC5, 0x1E, 0x0A, 0xAA, 0x6C, 0x98, 0x95, 0x38, 0x0A, 0xE4, 0x5C, 0x1E, + 0x6E, 0x03, 0x45, 0x7F, 0x11, 0xFB, 0x32, 0xB2, 0xB4, 0x87, 0x92, 0xAA, 0x3D, 0x94, 0xED, 0xA8, + 0xB2, 0x61, 0xDF, 0xE3, 0x98, 0xB7, 0xD0, 0x4C, 0xB8, 0x00, 0xB7, 0x87, 0x72, 0xE4, 0xC9, 0x45, + 0xEA, 0x96, 0xAB, 0x42, 0x3F, 0x3B, 0xA4, 0x6E, 0xBD, 0xC6, 0xC2, 0xBD, 0xD2, 0x1E, 0x0A, 0x21, + 0x15, 0x7B, 0x28, 0xEA, 0xBB, 0xA4, 0xB2, 0xC1, 0x91, 0xFF, 0xF6, 0x50, 0x84, 0x09, 0x17, 0xEE, + 0x0A, 0xAC, 0x8B, 0xFC, 0xEC, 0x6B, 0x30, 0xE3, 0xF4, 0x51, 0xBC, 0xB5, 0x2D, 0x92, 0x4B, 0x7B, + 0x28, 0x90, 0xA2, 0x3D, 0x94, 0x01, 0x2B, 0x47, 0x69, 0xD2, 0xAF, 0x00, 0xEC, 0xA1, 0x20, 0x74, + 0x8D, 0x13, 0xB4, 0x81, 0x52, 0x16, 0x0A, 0x83, 0x7F, 0x91, 0xE7, 0x3B, 0xB3, 0x94, 0x7E, 0x56, + 0xFD, 0x03, 0x69, 0x0F, 0x05, 0x91, 0x8A, 0x3D, 0x94, 0x3F, 0x7A, 0x50, 0xCF, 0xAF, 0x65, 0x35, + 0x5B, 0x51, 0x2D, 0xA8, 0x73, 0x79, 0x80, 0x6C, 0xA0, 0x34, 0x1D, 0x18, 0xAB, 0x28, 0x0F, 0x78, + 0xB0, 0x99, 0x7B, 0x84, 0x31, 0xBA, 0x0E, 0x69, 0x0F, 0x05, 0x52, 0xB3, 0x87, 0xC2, 0xD6, 0xED, + 0x4B, 0x97, 0xE7, 0xE5, 0x97, 0xEF, 0x04, 0xB3, 0xC6, 0x09, 0xDA, 0x40, 0x29, 0x0D, 0xAB, 0x2D, + 0x9F, 0xF4, 0xE1, 0x47, 0xFC, 0x5D, 0xAB, 0xBD, 0x34, 0x69, 0x0F, 0x05, 0x52, 0xB4, 0x87, 0xE2, + 0x5F, 0xBA, 0xA6, 0x80, 0xF4, 0x50, 0x8C, 0x73, 0x79, 0x74, 0x1B, 0x28, 0xEB, 0xAE, 0x28, 0x46, + 0xB5, 0x92, 0x88, 0xA6, 0x93, 0xC2, 0x91, 0x77, 0xF6, 0x50, 0x72, 0xC0, 0x07, 0xEE, 0x07, 0xF1, + 0x14, 0xB3, 0x01, 0x1B, 0x4E, 0x93, 0x3D, 0x94, 0xBE, 0xDC, 0x1E, 0x8A, 0x82, 0xEB, 0xDF, 0x0B, + 0xD7, 0x29, 0xD7, 0xBF, 0x62, 0xB9, 0xA2, 0x3D, 0x14, 0x1C, 0x85, 0x2D, 0x1A, 0xAA, 0xF4, 0xFB, + 0xBB, 0xE9, 0xDB, 0x40, 0x7B, 0x28, 0xDA, 0xB1, 0x3C, 0xF9, 0x67, 0x0F, 0x85, 0x67, 0x39, 0xF0, + 0xC4, 0xF7, 0xD1, 0x06, 0x8A, 0x52, 0xF2, 0xAD, 0x72, 0x1C, 0x1E, 0x9E, 0x5C, 0xEB, 0xAF, 0x5F, + 0x6E, 0x7D, 0x05, 0x20, 0x7B, 0x28, 0x8A, 0xF2, 0x0B, 0x43, 0x75, 0x95, 0xA2, 0xE0, 0x1B, 0x8B, + 0x3B, 0x1F, 0xDE, 0x29, 0xB6, 0x03, 0x60, 0x4D, 0xC0, 0x4E, 0x03, 0x3B, 0x24, 0x16, 0x7F, 0xFB, + 0x54, 0xFF, 0x30, 0x5E, 0xAC, 0x78, 0x70, 0x96, 0x07, 0x52, 0x0F, 0x25, 0x0B, 0x90, 0xF6, 0x50, + 0x92, 0x83, 0xB4, 0x87, 0x92, 0x43, 0x38, 0xCB, 0x03, 0xA9, 0x87, 0x92, 0x05, 0x48, 0x7B, 0x28, + 0x12, 0x79, 0x8F, 0xFC, 0x99, 0x3F, 0x90, 0xC8, 0x25, 0x9C, 0xE5, 0x81, 0xD4, 0x43, 0xE9, 0x6D, + 0xB0, 0xCB, 0x03, 0x69, 0x0F, 0xA5, 0x77, 0x22, 0x7F, 0xE4, 0x81, 0xB4, 0x87, 0x92, 0x4B, 0x38, + 0xCB, 0x03, 0x69, 0x0F, 0x25, 0x87, 0x90, 0xF6, 0x50, 0x52, 0xB0, 0x87, 0xC2, 0x8F, 0xB6, 0x31, + 0x1E, 0x2F, 0xA8, 0x73, 0x79, 0xF8, 0x2B, 0x48, 0x7B, 0x28, 0x4E, 0x48, 0xD1, 0x1E, 0x0A, 0x3F, + 0xDA, 0x26, 0xCD, 0xB4, 0x7A, 0x1E, 0xD6, 0x73, 0x79, 0xF8, 0x2B, 0x48, 0x7B, 0x28, 0x4E, 0x48, + 0xDD, 0x1E, 0x0A, 0x3F, 0xCB, 0x02, 0x0A, 0xC1, 0x1E, 0x8A, 0xED, 0x5C, 0x1E, 0xF6, 0x0A, 0xAA, + 0xB4, 0x87, 0xE2, 0x84, 0x54, 0xED, 0xA1, 0x80, 0x76, 0x96, 0x45, 0x01, 0xD8, 0x43, 0x71, 0x38, + 0x97, 0xA7, 0xF5, 0x79, 0x7E, 0x95, 0xF6, 0x50, 0x6C, 0x48, 0xD1, 0x1E, 0x0A, 0x86, 0x0B, 0x71, + 0x50, 0x90, 0xE7, 0xF2, 0xF0, 0x57, 0x90, 0xF6, 0x50, 0x62, 0x91, 0xB2, 0x3D, 0x14, 0x21, 0x0E, + 0x0A, 0x01, 0x31, 0xE7, 0xF2, 0xF0, 0x57, 0x90, 0xF6, 0x50, 0x1C, 0x90, 0xA2, 0x3D, 0x14, 0x2E, + 0x0E, 0x0A, 0xF4, 0x5C, 0x1E, 0xFE, 0x0A, 0x05, 0x60, 0x0F, 0x25, 0x57, 0xE7, 0xF2, 0x8C, 0x10, + 0xE7, 0xF2, 0x10, 0x1F, 0x5A, 0xCF, 0xE5, 0xA1, 0xF3, 0x69, 0xF8, 0x55, 0x9C, 0xCB, 0xC3, 0x8E, + 0xB6, 0x31, 0x60, 0x3A, 0x97, 0x27, 0x5F, 0x61, 0x9C, 0xCB, 0xB3, 0x99, 0xBD, 0xC2, 0x55, 0x31, + 0x07, 0x0C, 0x99, 0xCF, 0xE5, 0xA1, 0xEF, 0xBB, 0x07, 0xCF, 0xE5, 0x71, 0x96, 0x07, 0x52, 0x0F, + 0x25, 0x0B, 0x90, 0xF6, 0x50, 0x92, 0x83, 0xB4, 0x87, 0x92, 0x43, 0x38, 0xCB, 0x03, 0xA9, 0x87, + 0x92, 0x05, 0x48, 0x7B, 0x28, 0x12, 0x79, 0x8F, 0xBC, 0x19, 0x2F, 0x48, 0xE4, 0x14, 0x79, 0x33, + 0x5E, 0x40, 0x48, 0x3D, 0x94, 0xDC, 0x21, 0x8F, 0xE4, 0xC1, 0xD6, 0xF5, 0x21, 0x17, 0xB8, 0x5C, + 0x9D, 0xEB, 0xB7, 0x76, 0x9B, 0x94, 0x44, 0xAA, 0x08, 0x5A, 0x51, 0xC9, 0x7D, 0xA5, 0x3D, 0x94, + 0x5E, 0x07, 0xCD, 0x92, 0x2E, 0x83, 0x66, 0x7F, 0x42, 0xDA, 0x43, 0xC9, 0x21, 0x72, 0x94, 0xFF, + 0x60, 0xD0, 0x80, 0xE6, 0x97, 0xFF, 0xF6, 0x50, 0xEC, 0x6B, 0xB0, 0x85, 0xA3, 0x87, 0xC2, 0x36, + 0x9F, 0xD1, 0xB9, 0x3C, 0xDA, 0xD5, 0x84, 0xDC, 0xE9, 0xA1, 0x38, 0x23, 0xEF, 0xED, 0xA1, 0x1C, + 0x89, 0x35, 0x26, 0x92, 0xD7, 0xD0, 0xF4, 0x50, 0xB8, 0x25, 0x14, 0x7E, 0x2E, 0x8F, 0xB8, 0x9A, + 0x90, 0x43, 0x7B, 0x28, 0xCE, 0xC8, 0x7B, 0x7B, 0x28, 0xD4, 0x70, 0x68, 0x2B, 0xCC, 0xF9, 0x6F, + 0x0F, 0x45, 0xD7, 0x43, 0x09, 0x30, 0x4B, 0x28, 0x4D, 0xFC, 0x5C, 0x1E, 0x71, 0x35, 0x21, 0x87, + 0xF6, 0x50, 0x9C, 0x91, 0xF7, 0xF6, 0x50, 0x46, 0x1A, 0xC6, 0x44, 0x0A, 0xC0, 0x1E, 0x8A, 0xA1, + 0x87, 0xC2, 0x2C, 0xA1, 0xC4, 0xCD, 0x60, 0x0E, 0xED, 0xA1, 0x10, 0xFC, 0x7E, 0x06, 0x93, 0x4F, + 0xDE, 0xDB, 0x43, 0xF1, 0x1A, 0xC6, 0x44, 0x0A, 0x49, 0x0F, 0xC5, 0xCF, 0x2D, 0xA1, 0xC4, 0x8B, + 0x97, 0x43, 0x7B, 0x28, 0x84, 0x80, 0xE9, 0xCA, 0x91, 0xF7, 0xF6, 0x50, 0x5A, 0x63, 0x8D, 0x89, + 0xE4, 0x31, 0x0C, 0x3D, 0x14, 0x66, 0x09, 0x25, 0xAE, 0x8E, 0x48, 0x0E, 0xED, 0xA1, 0x30, 0x10, + 0x0B, 0x98, 0xD9, 0x20, 0xFF, 0xED, 0xA1, 0xB8, 0x1B, 0x57, 0x93, 0x31, 0x91, 0x82, 0xD3, 0x43, + 0xC1, 0xEB, 0xBA, 0x2B, 0xE2, 0x69, 0x10, 0xE4, 0xD2, 0x1E, 0x8A, 0x78, 0xD0, 0xCA, 0x06, 0xF9, + 0x6F, 0x0F, 0xE5, 0xBE, 0xFA, 0x15, 0x05, 0x64, 0x0F, 0x85, 0x83, 0xEC, 0xA1, 0x30, 0x4B, 0x28, + 0x00, 0x9B, 0xFB, 0xEE, 0x2E, 0x7A, 0x48, 0x5C, 0x4D, 0x31, 0x72, 0x68, 0x0F, 0x45, 0xC0, 0xCA, + 0x06, 0x52, 0x0F, 0x25, 0x1B, 0xC8, 0x77, 0x3D, 0x14, 0xD3, 0x5D, 0xED, 0xED, 0x35, 0x39, 0xD6, + 0x43, 0x91, 0xF6, 0x50, 0xF2, 0x09, 0x52, 0x0F, 0x25, 0x0B, 0xC8, 0x6B, 0x3D, 0x14, 0x67, 0xC8, + 0x95, 0xDF, 0x5E, 0x07, 0x63, 0x2A, 0xDF, 0x04, 0xC9, 0x07, 0xBD, 0x0D, 0x62, 0xA1, 0xD9, 0x06, + 0xC1, 0x07, 0xE6, 0xAE, 0x03, 0xC5, 0xAD, 0x31, 0x9C, 0x75, 0x0E, 0x0A, 0xAE, 0x5D, 0xC3, 0x99, + 0x5E, 0xFC, 0x64, 0x0A, 0x11, 0x69, 0x16, 0x4D, 0x4F, 0xC3, 0x96, 0x69, 0xE7, 0x32, 0xD7, 0xE4, + 0x81, 0x7D, 0x51, 0x5A, 0xBB, 0x7F, 0xC7, 0x49, 0xCF, 0x39, 0x89, 0xB4, 0x1D, 0x17, 0xB9, 0xE3, + 0x27, 0x53, 0x88, 0x48, 0xB3, 0x68, 0x7A, 0x1A, 0xF1, 0xAA, 0xC2, 0x0A, 0xBD, 0x5D, 0xB0, 0xB1, + 0x8D, 0x71, 0x9F, 0x66, 0xEA, 0x76, 0x7A, 0x5D, 0x25, 0x53, 0x88, 0xC8, 0x5C, 0x65, 0x65, 0x13, + 0x49, 0x95, 0x71, 0xD7, 0xE3, 0xC6, 0xF4, 0xD2, 0xEE, 0x92, 0xEC, 0xB9, 0x80, 0x8C, 0x56, 0x57, + 0xB6, 0x90, 0xDC, 0xAB, 0xD8, 0xF8, 0xC0, 0xBC, 0x04, 0x25, 0x90, 0x56, 0xEA, 0x71, 0xA9, 0x75, + 0x11, 0x50, 0x58, 0xC8, 0x64, 0x75, 0x65, 0x0D, 0x3C, 0xAB, 0x5D, 0x95, 0xB8, 0x95, 0x0F, 0x9C, + 0x62, 0xA7, 0x95, 0x7A, 0x02, 0x7A, 0xF1, 0xBD, 0x0B, 0x0E, 0x99, 0xAC, 0xAE, 0xAC, 0x41, 0xE4, + 0xB5, 0x8B, 0x32, 0xB7, 0xF0, 0x81, 0x63, 0xDC, 0xB4, 0x52, 0x4F, 0x48, 0xF1, 0x5C, 0x61, 0x83, + 0x42, 0x92, 0x07, 0xD0, 0x45, 0xA9, 0x9B, 0xF9, 0xC0, 0x39, 0x66, 0x5A, 0xA9, 0x27, 0xA2, 0x79, + 0xCE, 0xB0, 0x41, 0x81, 0xF5, 0x0F, 0x12, 0x96, 0xBB, 0x99, 0x0F, 0x6C, 0x4B, 0x50, 0x02, 0x69, + 0xA5, 0x9E, 0x88, 0xA6, 0x73, 0x32, 0x85, 0x88, 0x4C, 0x56, 0x57, 0xD6, 0xA0, 0xE7, 0x36, 0x61, + 0xB9, 0x5B, 0xDA, 0x05, 0xC7, 0x98, 0x69, 0xA5, 0x9E, 0x90, 0xE2, 0x39, 0xC3, 0x08, 0x99, 0xAC, + 0xAE, 0xAC, 0x41, 0xCB, 0x6C, 0xE2, 0x52, 0xB7, 0xF6, 0x13, 0x9D, 0xE2, 0xA6, 0x95, 0x7A, 0xE2, + 0xB4, 0xCF, 0x15, 0x46, 0xC8, 0x64, 0x75, 0x65, 0x0D, 0x22, 0xAF, 0x5D, 0x94, 0xB9, 0x6D, 0xDC, + 0xE8, 0x10, 0x3B, 0xAD, 0xD4, 0xBB, 0x48, 0xFB, 0x1C, 0x61, 0x84, 0x4C, 0x56, 0x57, 0xD6, 0xC0, + 0xB3, 0xDA, 0x55, 0x89, 0x77, 0x3D, 0x8F, 0x94, 0x56, 0xEA, 0x5D, 0x52, 0x3D, 0x27, 0x90, 0xC9, + 0xEA, 0xCA, 0x1A, 0x92, 0x7B, 0x15, 0x39, 0x9F, 0xD8, 0x0D, 0x64, 0xB2, 0xBA, 0xB2, 0x86, 0xE4, + 0x5E, 0x45, 0x5B, 0x5F, 0xB0, 0xAF, 0x3F, 0x98, 0x96, 0x86, 0xD2, 0x4A, 0x3D, 0xCE, 0x7A, 0x46, + 0xFC, 0x64, 0x0A, 0x11, 0x99, 0xAB, 0xAC, 0x6C, 0x22, 0xA9, 0x32, 0x16, 0x7C, 0x60, 0x5F, 0x94, + 0x36, 0xDD, 0xA7, 0x95, 0xB6, 0xF3, 0x22, 0x77, 0xA2, 0x64, 0x0A, 0x11, 0x19, 0xAD, 0xAE, 0x6C, + 0x21, 0xB9, 0x32, 0x16, 0x7A, 0xAA, 0x59, 0x57, 0x04, 0xC0, 0x54, 0x7A, 0x22, 0x19, 0x89, 0xD4, + 0xC1, 0x18, 0x40, 0xDA, 0xC5, 0x91, 0x20, 0x88, 0x76, 0xA1, 0xB6, 0x3B, 0x34, 0xBA, 0xC6, 0x6C, + 0xD1, 0x5B, 0xC9, 0x72, 0x32, 0x12, 0xA9, 0x43, 0x54, 0x8D, 0xD6, 0x4F, 0xA4, 0x7D, 0x45, 0x3D, + 0x80, 0x1E, 0x4A, 0x46, 0x22, 0x55, 0xC8, 0x76, 0x41, 0x82, 0x20, 0xF9, 0x40, 0x82, 0x20, 0xF9, + 0x40, 0x82, 0xE0, 0xC8, 0x07, 0x55, 0x43, 0x7B, 0x6C, 0x4B, 0xF1, 0xDB, 0x7E, 0xFF, 0xAA, 0xE4, + 0x93, 0xCB, 0x40, 0xC6, 0x7A, 0xF0, 0xDD, 0x0A, 0x09, 0x3A, 0x1F, 0x04, 0xCF, 0xF3, 0xFB, 0x8D, + 0x53, 0x35, 0xAB, 0x63, 0x4A, 0xCB, 0x52, 0x7E, 0xDD, 0x29, 0xCC, 0xE0, 0x84, 0x26, 0xA8, 0x2A, + 0xF5, 0x97, 0x3C, 0xCE, 0x6E, 0xE6, 0xAF, 0x78, 0xEB, 0xC9, 0xD3, 0x0E, 0xB1, 0xC6, 0x31, 0x83, + 0x1D, 0x73, 0xF9, 0x8D, 0x43, 0x72, 0x8E, 0x39, 0x78, 0x86, 0x9E, 0xB9, 0x14, 0x89, 0x8B, 0x07, + 0xF1, 0x9D, 0xFA, 0x9F, 0x10, 0x57, 0x9E, 0x70, 0x32, 0x54, 0x7A, 0x25, 0x74, 0x3E, 0xD8, 0x75, + 0x57, 0x20, 0xD0, 0xC8, 0xEA, 0x86, 0x30, 0xEB, 0x64, 0x42, 0xF3, 0x0A, 0x73, 0x12, 0x07, 0x27, + 0xC2, 0x33, 0x03, 0xB1, 0xE8, 0x3F, 0xBF, 0x3C, 0xF0, 0x97, 0x47, 0xA9, 0x0A, 0x6A, 0xDA, 0x17, + 0xCC, 0x39, 0x39, 0xD0, 0x21, 0xDA, 0xC1, 0xC0, 0x5B, 0xA5, 0x0D, 0x81, 0x2D, 0x71, 0xC9, 0x38, + 0xE6, 0x60, 0x61, 0x20, 0x10, 0x58, 0x5B, 0x14, 0x59, 0x16, 0x38, 0x5D, 0xC7, 0xDE, 0xE4, 0x57, + 0x77, 0x05, 0x7E, 0x7C, 0x13, 0x4C, 0xBA, 0x2B, 0xB0, 0xF9, 0x93, 0x4D, 0x3C, 0x61, 0x89, 0x38, + 0xD0, 0xF9, 0xE0, 0xA2, 0xFB, 0x20, 0xA8, 0x2C, 0x40, 0x07, 0x7E, 0x4E, 0x97, 0x85, 0xAB, 0x87, + 0xBE, 0x3E, 0x74, 0x72, 0xFF, 0x13, 0xFC, 0xBB, 0x25, 0x51, 0xF1, 0xC0, 0xAD, 0xAD, 0xE5, 0x73, + 0xF1, 0x16, 0xFD, 0x30, 0xE0, 0xD5, 0xA1, 0x4D, 0x3C, 0x08, 0xBF, 0xC0, 0x14, 0x8B, 0x77, 0xE1, + 0x5B, 0x1E, 0xA6, 0x50, 0xEF, 0xA6, 0x11, 0x6B, 0xF0, 0x86, 0xC0, 0x58, 0xFF, 0x40, 0x94, 0x07, + 0xF1, 0xA8, 0xB1, 0x14, 0x81, 0xD2, 0xC6, 0x30, 0x2E, 0x42, 0x80, 0x45, 0x7B, 0x7D, 0xE8, 0x31, + 0x12, 0x19, 0xAB, 0xF8, 0x83, 0x55, 0x7D, 0x35, 0x0E, 0xAE, 0xBA, 0xEF, 0x05, 0x7C, 0x13, 0x1F, + 0xB3, 0x8C, 0x10, 0x5C, 0xFB, 0x35, 0x98, 0xB6, 0xFF, 0xA8, 0x0B, 0x2D, 0x56, 0x0D, 0x0A, 0xB3, + 0x84, 0xC9, 0x57, 0x9D, 0x41, 0x4F, 0x8C, 0x5B, 0x05, 0xC1, 0xF2, 0x87, 0xC4, 0x4B, 0xA5, 0xF5, + 0x22, 0xE7, 0x16, 0x4C, 0xFD, 0x83, 0x71, 0x65, 0xDB, 0xD0, 0x30, 0x43, 0xF0, 0x86, 0x65, 0x01, + 0x56, 0x62, 0x81, 0x2F, 0x9C, 0xE9, 0x7F, 0x5B, 0x7D, 0xE0, 0xCD, 0x35, 0xC7, 0xF0, 0x83, 0x0A, + 0xAC, 0x78, 0xB1, 0xB4, 0xE1, 0x55, 0x0C, 0xC2, 0xEF, 0x0B, 0x03, 0x86, 0x40, 0x90, 0x05, 0xBD, + 0xBE, 0xE4, 0x50, 0x60, 0x6D, 0xEA, 0xD6, 0xAA, 0x7C, 0xEF, 0x3D, 0xE9, 0xBF, 0x7C, 0x09, 0x7E, + 0xD0, 0xBE, 0xDF, 0x97, 0x36, 0x50, 0x62, 0xF1, 0xA8, 0x51, 0x66, 0x30, 0x45, 0x4C, 0x7B, 0x0B, + 0x7E, 0xEB, 0x7F, 0xD9, 0xC4, 0x3C, 0xAB, 0x28, 0x5A, 0x04, 0x8A, 0x0F, 0x06, 0xB6, 0xF8, 0xEE, + 0x60, 0x0F, 0x9A, 0x5B, 0xAC, 0xE9, 0x64, 0x5C, 0xA2, 0xAA, 0x65, 0xA1, 0xB8, 0xAF, 0xEC, 0x17, + 0xEE, 0x58, 0x0F, 0x3E, 0xD5, 0xD8, 0x60, 0xDD, 0xF1, 0xED, 0xC0, 0x53, 0x8F, 0x36, 0x3D, 0xFF, + 0x2A, 0xEC, 0x1A, 0x73, 0x3F, 0xBD, 0x54, 0x77, 0x5E, 0xE4, 0xDC, 0x81, 0x69, 0x9F, 0xEB, 0xC1, + 0xE0, 0x84, 0xEF, 0xDC, 0x03, 0x35, 0x9D, 0x77, 0xF1, 0x5B, 0xFF, 0x5D, 0x50, 0x73, 0x62, 0x2C, + 0x40, 0xD1, 0xEE, 0x56, 0xE1, 0x43, 0x41, 0xD3, 0xF6, 0x9D, 0xC2, 0x00, 0x80, 0xBD, 0x2C, 0xE8, + 0x7C, 0xFF, 0xC4, 0xFD, 0x68, 0xB1, 0x27, 0x65, 0xFC, 0xEA, 0xAE, 0xFB, 0xC6, 0x6D, 0xBA, 0xC7, + 0xB8, 0x8F, 0x47, 0x8D, 0xA7, 0xC8, 0xCC, 0xC7, 0x54, 0xCD, 0x8D, 0x80, 0x8F, 0xF5, 0x24, 0x2A, + 0x29, 0x1A, 0x19, 0x9A, 0xA8, 0xFA, 0xA7, 0xFB, 0x8F, 0xB1, 0x07, 0xC3, 0x73, 0x5A, 0xC4, 0x03, + 0x55, 0xF7, 0xED, 0xC3, 0x6B, 0xF0, 0x46, 0x62, 0x32, 0x01, 0xDF, 0xEF, 0xE6, 0x3E, 0x00, 0x45, + 0x24, 0xE9, 0xC4, 0xFD, 0x42, 0x98, 0xA6, 0x84, 0x67, 0x1C, 0x3F, 0xF1, 0xEE, 0xD5, 0x2C, 0x89, + 0x6E, 0xBD, 0xC8, 0x39, 0x03, 0xF3, 0x78, 0xC1, 0xF7, 0x43, 0xCB, 0x51, 0x60, 0x08, 0x7F, 0x43, + 0x20, 0x80, 0x1F, 0xBF, 0xD3, 0x83, 0x2C, 0x68, 0xCC, 0xD1, 0x13, 0x17, 0xB0, 0x3E, 0x58, 0x6A, + 0xA8, 0x7A, 0xE0, 0x2E, 0xD8, 0x67, 0x74, 0x46, 0x92, 0xA1, 0x56, 0xF5, 0x99, 0xE5, 0x5C, 0x4C, + 0x01, 0xF8, 0x28, 0xDA, 0x29, 0x74, 0xDC, 0xBA, 0xF4, 0x1E, 0xFE, 0xA0, 0x61, 0x5F, 0x86, 0x89, + 0x03, 0xC6, 0xCF, 0xC2, 0xA3, 0xE6, 0xAC, 0x67, 0x4E, 0x6B, 0xE0, 0xAD, 0x22, 0xFB, 0xBE, 0x6E, + 0xDF, 0xDD, 0x3F, 0xC7, 0x56, 0x23, 0xA9, 0xA4, 0x7B, 0x05, 0x74, 0x3E, 0xF8, 0x0D, 0xF6, 0x03, + 0x1E, 0xC1, 0x66, 0xB5, 0xB2, 0xF8, 0x19, 0xD8, 0x23, 0x24, 0x64, 0x65, 0xD1, 0xCF, 0xF1, 0x3A, + 0xA7, 0x94, 0xAE, 0x10, 0x09, 0xD3, 0xED, 0x9E, 0x49, 0x9C, 0x2D, 0xA6, 0xB0, 0xA0, 0xAA, 0xEB, + 0x7C, 0x47, 0x07, 0xA7, 0x6E, 0xD3, 0x82, 0x08, 0xD5, 0x34, 0x1B, 0x9F, 0xA8, 0x85, 0x5A, 0xD5, + 0x20, 0xA3, 0x3E, 0x78, 0x8A, 0x65, 0x98, 0x36, 0x7D, 0xC6, 0x22, 0x5B, 0x2C, 0x1A, 0xDA, 0x12, + 0x7A, 0x66, 0xE4, 0x7D, 0x22, 0x87, 0x7A, 0xFF, 0x00, 0x7B, 0x07, 0x78, 0x19, 0xCA, 0xD8, 0x60, + 0xDC, 0x5C, 0xDF, 0xDD, 0x4F, 0xC3, 0x9E, 0x89, 0x24, 0x19, 0x6E, 0x9D, 0x6A, 0xE9, 0x55, 0x12, + 0xC9, 0x39, 0x3F, 0x1A, 0x8D, 0x2C, 0xC3, 0x5F, 0x4A, 0x4B, 0xDA, 0x96, 0xCD, 0xDE, 0x04, 0x9D, + 0x0F, 0x2A, 0x1E, 0xF0, 0x0F, 0xFC, 0x06, 0x96, 0x9F, 0x6F, 0xC3, 0x03, 0xFE, 0x7B, 0xC5, 0xD7, + 0xE3, 0xFB, 0xFD, 0x6A, 0xEA, 0x3E, 0xBD, 0x88, 0xD7, 0x55, 0x73, 0x56, 0x8D, 0xBD, 0x1A, 0x6F, + 0x17, 0x6F, 0x34, 0x07, 0x8D, 0xAC, 0xF6, 0xFB, 0xC7, 0x98, 0xE4, 0x7B, 0x12, 0x78, 0xE6, 0xB2, + 0xD6, 0xF2, 0x1F, 0xE1, 0xC3, 0x97, 0x2F, 0x33, 0x1D, 0x70, 0x1A, 0x8F, 0x1A, 0xF9, 0x63, 0x8A, + 0x98, 0xF6, 0x3D, 0x2B, 0xCA, 0xB5, 0x6C, 0x55, 0x52, 0xB4, 0x3B, 0x20, 0xB8, 0xFC, 0x5D, 0x7F, + 0xFF, 0x33, 0x3C, 0x87, 0x5A, 0xFC, 0x5B, 0x49, 0x1C, 0xEC, 0x09, 0x3F, 0x80, 0x03, 0xC7, 0x60, + 0xE8, 0x6A, 0xB8, 0xF3, 0xE7, 0xF4, 0x34, 0x4E, 0x51, 0x8C, 0xC5, 0x81, 0x07, 0x25, 0xBC, 0x0A, + 0xE3, 0x04, 0xCA, 0xFD, 0x3F, 0xF8, 0x03, 0xC0, 0x9C, 0x61, 0xD8, 0x2C, 0x88, 0x97, 0x4A, 0xEB, + 0x45, 0xCE, 0x2D, 0x08, 0xFD, 0x83, 0xE7, 0xB3, 0xBB, 0x00, 0x44, 0xFA, 0x10, 0x90, 0xFD, 0x64, + 0xCC, 0x78, 0xFB, 0xEE, 0xC4, 0x87, 0x3B, 0xBC, 0x7D, 0xF5, 0x81, 0xB4, 0xC7, 0xBE, 0xE7, 0x12, + 0x58, 0xD5, 0x9C, 0xC3, 0xFA, 0x07, 0x7B, 0x59, 0x2F, 0x30, 0x3E, 0xDE, 0xBD, 0x5B, 0xB2, 0x81, + 0x09, 0xE7, 0xAC, 0x5D, 0x1C, 0x6D, 0xE0, 0x18, 0x0F, 0xDF, 0x4C, 0x82, 0x46, 0x2F, 0x82, 0x5C, + 0x67, 0x92, 0x20, 0x08, 0x79, 0x30, 0xBB, 0x3B, 0x34, 0x92, 0x47, 0x0F, 0x25, 0x23, 0x91, 0x32, + 0x38, 0x1F, 0xD4, 0xF4, 0xCC, 0x86, 0x83, 0x1E, 0x4A, 0x46, 0x22, 0x75, 0x30, 0x3E, 0x90, 0xD2, + 0xA0, 0xD7, 0x83, 0xF1, 0x41, 0x0F, 0x7D, 0xA6, 0x52, 0x1A, 0xE4, 0x2F, 0x64, 0x3F, 0x51, 0x82, + 0x20, 0xF9, 0x40, 0x82, 0xC0, 0xDA, 0x05, 0xB9, 0xAD, 0xA0, 0x37, 0x83, 0xED, 0x60, 0xE0, 0xE3, + 0x85, 0xDB, 0xBB, 0x41, 0x46, 0xA2, 0xB0, 0xC1, 0xF7, 0x1A, 0x8A, 0xF9, 0x83, 0x6C, 0x9F, 0xC3, + 0x21, 0x91, 0x37, 0xB0, 0xDB, 0x5B, 0xE6, 0x3F, 0xDA, 0xBC, 0xB2, 0xEC, 0xCB, 0xF7, 0x1A, 0x38, + 0xDA, 0x5B, 0x96, 0x76, 0xF7, 0x7B, 0x1F, 0x9C, 0xBE, 0x79, 0x39, 0x5E, 0x90, 0x20, 0xA4, 0xC8, + 0x07, 0x71, 0x14, 0xFE, 0x85, 0x77, 0x6A, 0x9B, 0x52, 0x24, 0xF2, 0x08, 0x16, 0x3E, 0x30, 0x76, + 0x80, 0xC4, 0xC3, 0x1E, 0x37, 0xEE, 0x04, 0x88, 0x17, 0x18, 0x77, 0x53, 0x8A, 0x44, 0xDE, 0xC3, + 0xC2, 0x07, 0x37, 0x2E, 0x0F, 0x9C, 0xEE, 0x93, 0x30, 0x7A, 0xE7, 0x4D, 0x09, 0x02, 0xE3, 0x6E, + 0x4A, 0x91, 0xC8, 0x3F, 0xD8, 0xAC, 0xEC, 0x5A, 0xF8, 0xA0, 0x78, 0x01, 0xF8, 0xFE, 0xC8, 0xF7, + 0x94, 0xB0, 0xDD, 0x2A, 0xA8, 0x31, 0x1A, 0x1C, 0xCF, 0x37, 0xB3, 0xD0, 0x3D, 0xDE, 0xFD, 0xE8, + 0x5A, 0x16, 0x91, 0x6F, 0x2F, 0xA1, 0xFD, 0x2D, 0xAB, 0x8C, 0xFD, 0x25, 0xB6, 0x4D, 0x29, 0x5D, + 0x65, 0x44, 0x22, 0x97, 0xF0, 0xDB, 0x18, 0xC1, 0xC2, 0x07, 0x77, 0x8F, 0xC5, 0x1D, 0x8E, 0x7C, + 0x4F, 0xC9, 0x69, 0xDC, 0xAD, 0x72, 0xF5, 0xAA, 0xA7, 0x61, 0xD7, 0x70, 0xBE, 0x99, 0x85, 0xEE, + 0xCB, 0xF0, 0x8E, 0x69, 0x2B, 0x8B, 0xED, 0x25, 0xB4, 0xBF, 0xE5, 0x3E, 0x63, 0x7F, 0x89, 0x75, + 0x53, 0x8A, 0xEC, 0x25, 0xE4, 0x33, 0x88, 0x09, 0x2C, 0x8C, 0x60, 0xE1, 0x83, 0x6F, 0x06, 0xD6, + 0xFA, 0x2F, 0xC5, 0x8D, 0x1D, 0xFE, 0xCB, 0x3A, 0x23, 0xB4, 0x5B, 0xE5, 0x82, 0x57, 0x61, 0xE7, + 0xF5, 0xA6, 0x7B, 0xE0, 0x5B, 0x3F, 0xC4, 0xF6, 0x92, 0x57, 0xD9, 0xFE, 0x16, 0xFC, 0xF8, 0xE7, + 0xBE, 0x67, 0xE9, 0x14, 0xE0, 0xA6, 0x14, 0x7C, 0xA0, 0x37, 0x6F, 0x0E, 0xCA, 0x7B, 0x70, 0x16, + 0x48, 0x70, 0xEE, 0xFF, 0x45, 0xA7, 0x8F, 0x9F, 0x32, 0x36, 0xAF, 0x5C, 0x74, 0xF2, 0xC3, 0xB5, + 0x0B, 0xCD, 0x9B, 0x59, 0x7E, 0x14, 0x73, 0xA2, 0xB2, 0x69, 0x7F, 0x89, 0x91, 0x8A, 0x75, 0x6F, + 0x89, 0x44, 0xDE, 0x01, 0xF7, 0x03, 0x13, 0x4C, 0x3E, 0x16, 0x3E, 0xB8, 0x0C, 0x70, 0xFF, 0xCF, + 0x34, 0xBE, 0x35, 0x84, 0x61, 0xE9, 0x0D, 0xA3, 0x06, 0x8B, 0xAD, 0x22, 0x04, 0x6D, 0xDB, 0x20, + 0xDF, 0x5E, 0x72, 0x35, 0xDB, 0xDF, 0x62, 0xEC, 0x2F, 0xD1, 0xC0, 0x37, 0xA5, 0x48, 0x14, 0x14, + 0x2C, 0x7C, 0x70, 0xC4, 0x8F, 0xDB, 0x4F, 0xCF, 0x63, 0x1B, 0x3B, 0xB8, 0xA4, 0x9F, 0xF6, 0xE1, + 0x0B, 0x62, 0x8F, 0x09, 0xBB, 0xDF, 0x83, 0xDB, 0x82, 0x70, 0x1B, 0x08, 0xDB, 0x3D, 0x82, 0x1B, + 0x44, 0x68, 0x7F, 0xCB, 0x66, 0x63, 0x7F, 0x89, 0x06, 0xB1, 0xFB, 0x25, 0x89, 0xC4, 0x25, 0xF2, + 0x06, 0xDA, 0x79, 0xEF, 0x49, 0xAD, 0x2F, 0xFC, 0xFB, 0xC7, 0xF7, 0x25, 0x13, 0x4D, 0x22, 0xAF, + 0x41, 0x5B, 0x8A, 0x74, 0x68, 0xE7, 0xBD, 0xA7, 0xB2, 0xBE, 0x10, 0x5C, 0xBB, 0x2D, 0x85, 0xD8, + 0x12, 0x79, 0x8A, 0x84, 0xE7, 0x3B, 0x27, 0xA5, 0x8A, 0xB2, 0xE9, 0xE4, 0xC9, 0x64, 0xA2, 0x49, + 0xE4, 0x33, 0x9C, 0x75, 0x4D, 0x04, 0x1F, 0x54, 0x24, 0x4B, 0x45, 0xA2, 0xD0, 0x61, 0xB3, 0x71, + 0x6D, 0xD5, 0x3F, 0xD0, 0xF4, 0x50, 0x3A, 0x9A, 0x40, 0xC5, 0x21, 0xA2, 0xC7, 0x9D, 0x04, 0x41, + 0x89, 0x82, 0x44, 0x30, 0x29, 0xFD, 0x83, 0xC1, 0x50, 0xDF, 0xDC, 0x7F, 0x68, 0x58, 0xF2, 0xC1, + 0x39, 0x8C, 0x64, 0xF4, 0x0F, 0xA8, 0x03, 0x30, 0xB4, 0x0B, 0x3A, 0x12, 0xE7, 0x1E, 0xEC, 0x7C, + 0x30, 0xF4, 0xA4, 0xAA, 0xCA, 0xCE, 0x60, 0xEF, 0x83, 0x9D, 0x0F, 0x9A, 0x5C, 0xEA, 0x06, 0x97, + 0x9C, 0x03, 0xEA, 0x75, 0xE8, 0x42, 0x1F, 0x29, 0x70, 0x45, 0x08, 0x36, 0x2B, 0x8A, 0xA2, 0xCC, + 0x69, 0xF5, 0x28, 0xCA, 0xDD, 0xCC, 0x8F, 0xBB, 0x02, 0x65, 0x8A, 0xE2, 0x6A, 0x30, 0xEE, 0x79, + 0x5C, 0x74, 0x73, 0x4F, 0x23, 0x96, 0xEF, 0xB8, 0xB8, 0x26, 0x4E, 0x49, 0xA2, 0xA7, 0xF0, 0x4E, + 0x6D, 0xAD, 0x01, 0xCD, 0x33, 0xF1, 0x3C, 0xD2, 0xE6, 0xCF, 0xE2, 0xB0, 0x62, 0x9E, 0x0A, 0xB0, + 0xEE, 0x60, 0xCD, 0xCA, 0x1F, 0x06, 0xC6, 0x7D, 0xBF, 0x1C, 0x3D, 0xB9, 0x6B, 0x70, 0x51, 0xE3, + 0x70, 0x1E, 0x49, 0x84, 0xB0, 0xB8, 0x3F, 0x3B, 0x54, 0xBE, 0xFD, 0x9A, 0x6A, 0xAF, 0xEE, 0xFB, + 0xFB, 0x45, 0xF7, 0x6F, 0xBE, 0xB6, 0xEA, 0x19, 0x76, 0x4D, 0x98, 0x92, 0x44, 0x4F, 0xC1, 0xF9, + 0xBC, 0x26, 0x1B, 0x1F, 0x9C, 0x3A, 0xE3, 0xDA, 0x00, 0x67, 0xA3, 0x9A, 0xC9, 0x98, 0x79, 0x2D, + 0x9F, 0x62, 0xBF, 0xAD, 0x4B, 0xEB, 0x87, 0x5F, 0x0C, 0xFE, 0xEF, 0xB3, 0x9B, 0x8B, 0x75, 0x17, + 0x87, 0xB8, 0xA7, 0xB8, 0xB4, 0x82, 0x55, 0xC9, 0x45, 0x0C, 0xF3, 0x6D, 0x7F, 0xAC, 0x0A, 0x2E, + 0x0D, 0xB5, 0xB0, 0x6B, 0x88, 0xB8, 0x43, 0x22, 0xE7, 0xA8, 0xB3, 0x9D, 0xE3, 0xC5, 0x7D, 0x6D, + 0xED, 0x82, 0x02, 0xFD, 0xE6, 0x03, 0xA8, 0xF6, 0x0E, 0xC2, 0x7F, 0x7E, 0x83, 0xBE, 0xFD, 0xD6, + 0xE7, 0xB5, 0xC5, 0x64, 0x72, 0x75, 0x8E, 0x10, 0xED, 0x84, 0x29, 0xC4, 0xFF, 0x9D, 0x59, 0x4A, + 0xBF, 0x3F, 0x6A, 0x15, 0xDE, 0xFA, 0xFC, 0x08, 0xBC, 0xBA, 0x9B, 0x88, 0x1A, 0xBF, 0x4A, 0xE4, + 0x1E, 0xF6, 0x03, 0xDD, 0xB8, 0xAF, 0x8D, 0x0F, 0x54, 0xB5, 0x79, 0xE3, 0x2D, 0x51, 0x9C, 0x45, + 0xB0, 0xF8, 0xB6, 0x2E, 0x5D, 0x82, 0xD7, 0xC0, 0x04, 0xAD, 0x86, 0xC9, 0xE5, 0x3F, 0xA1, 0xB6, + 0x3F, 0xC7, 0xBB, 0x02, 0xA6, 0x90, 0x67, 0x16, 0xA9, 0x8F, 0xDC, 0x28, 0x9E, 0x42, 0x5F, 0xB9, + 0x3B, 0x22, 0xFF, 0x60, 0x3F, 0xD7, 0x8F, 0xFB, 0xDA, 0xE5, 0x81, 0x02, 0xD1, 0x97, 0x40, 0x21, + 0x6B, 0xA5, 0x26, 0x30, 0x71, 0x10, 0x18, 0xF7, 0x0E, 0xF5, 0x0E, 0x10, 0x9A, 0x4B, 0x6B, 0x1D, + 0x8C, 0x90, 0xD6, 0x5F, 0x2E, 0x83, 0x65, 0xF3, 0x39, 0x77, 0x68, 0xBE, 0x91, 0xC1, 0xC4, 0x55, + 0xFC, 0x2A, 0x91, 0x7B, 0x24, 0x25, 0x0F, 0x06, 0x63, 0x9F, 0x10, 0x40, 0x55, 0x2C, 0x9E, 0x4C, + 0x1C, 0xB4, 0xF6, 0xA3, 0x6A, 0x6D, 0xED, 0x73, 0x5C, 0xB8, 0xB6, 0x3F, 0x04, 0xAD, 0x2B, 0x3D, + 0xC6, 0x3D, 0x83, 0xBB, 0x71, 0x8D, 0xC5, 0xD7, 0xBF, 0xF4, 0x57, 0xB0, 0xD5, 0xDB, 0x97, 0x5D, + 0x65, 0xF7, 0x20, 0x3F, 0xE0, 0x2C, 0x0F, 0x20, 0xA0, 0x06, 0x02, 0x55, 0x13, 0x54, 0x95, 0xE3, + 0xDD, 0x8A, 0x01, 0x15, 0x57, 0x54, 0x54, 0xBC, 0x27, 0x6E, 0x5F, 0xC3, 0x08, 0x2B, 0xD5, 0x47, + 0x17, 0x0B, 0x27, 0x2C, 0x6E, 0x29, 0x69, 0xD4, 0x5C, 0x38, 0xF5, 0xBC, 0x52, 0x35, 0xEE, 0x79, + 0x5C, 0xF4, 0x55, 0x8E, 0x98, 0x7C, 0xDB, 0x87, 0x41, 0x71, 0xA3, 0xCA, 0xAF, 0x5A, 0x1A, 0x12, + 0x39, 0x05, 0x56, 0xB8, 0x1D, 0xC8, 0x00, 0x9A, 0x1E, 0x8A, 0xC1, 0x2F, 0xFF, 0x56, 0xFD, 0x7A, + 0x97, 0x3C, 0x25, 0x51, 0xC0, 0xB0, 0xCB, 0x83, 0x58, 0x7B, 0xAA, 0xA1, 0x8E, 0x7D, 0x57, 0x0D, + 0xAC, 0xAE, 0x9A, 0x77, 0xD5, 0xDE, 0x8E, 0x48, 0x7A, 0x69, 0x48, 0xE4, 0x3D, 0x9C, 0xFB, 0x07, + 0x96, 0x1E, 0x7D, 0xF4, 0xC0, 0x4B, 0x55, 0xE1, 0x2A, 0xD8, 0x01, 0xC1, 0xFA, 0xF1, 0x72, 0xC5, + 0xF1, 0x1C, 0x85, 0x73, 0xFF, 0xC0, 0xC2, 0x07, 0xC5, 0x53, 0xA6, 0x3C, 0x98, 0x32, 0x5D, 0x89, + 0xC2, 0x42, 0xD0, 0x8A, 0x4A, 0x8B, 0x3D, 0x14, 0x06, 0x8B, 0xA6, 0x4A, 0x81, 0x1F, 0xC9, 0x2F, + 0x11, 0x17, 0x5D, 0xEB, 0xA1, 0x98, 0xEA, 0x5E, 0x9E, 0xD0, 0x7F, 0xEE, 0x42, 0xDA, 0xC1, 0x90, + 0x88, 0x07, 0xC9, 0x07, 0x12, 0x84, 0xD4, 0xF8, 0x60, 0xB3, 0xBE, 0xB2, 0x64, 0xB8, 0xE2, 0x44, + 0x48, 0x01, 0xF1, 0x1F, 0x4A, 0x8B, 0x1C, 0xA2, 0x75, 0x46, 0xC8, 0x39, 0x20, 0x0E, 0xC1, 0xB8, + 0xF1, 0x53, 0xA0, 0x91, 0x54, 0x54, 0xE1, 0x91, 0x52, 0x7A, 0x3D, 0x02, 0x2B, 0x1F, 0x44, 0xA3, + 0x10, 0x8D, 0x8D, 0xB3, 0x9D, 0xF4, 0x50, 0x98, 0xAB, 0xDF, 0x5B, 0x4C, 0xBF, 0x04, 0x75, 0x4D, + 0x34, 0xD7, 0x43, 0xD6, 0xA8, 0x9A, 0x77, 0x8C, 0xDA, 0x09, 0xF9, 0xA2, 0x86, 0xCA, 0x6A, 0xD2, + 0x69, 0xC1, 0x75, 0x4A, 0xD2, 0x6D, 0xC1, 0x22, 0xE1, 0xCA, 0x2A, 0x66, 0x5A, 0x22, 0x40, 0xA4, + 0x89, 0x21, 0xE6, 0xE4, 0x9D, 0x81, 0x85, 0x4A, 0xE5, 0xDA, 0xEA, 0x6D, 0x80, 0xC0, 0x28, 0x4B, + 0xBA, 0x8C, 0xBC, 0x08, 0x36, 0xF2, 0xE7, 0x1C, 0x97, 0xD1, 0xB1, 0xDC, 0xC7, 0x4B, 0x37, 0x4E, + 0xA6, 0xEC, 0x8F, 0xD3, 0xBD, 0x78, 0x33, 0x2A, 0x0D, 0xD3, 0x0B, 0xE5, 0x1E, 0xEC, 0xD0, 0x64, + 0xBF, 0x65, 0xE3, 0xBB, 0x69, 0x5E, 0x79, 0x0F, 0xFE, 0x77, 0xAA, 0x11, 0xDD, 0x2D, 0xF0, 0x1A, + 0xCD, 0x09, 0x3F, 0xCD, 0xE6, 0x85, 0xDB, 0xCB, 0x1B, 0x5B, 0xA6, 0x77, 0x9A, 0x5C, 0x2D, 0xEE, + 0x87, 0x2D, 0x93, 0x96, 0x46, 0x04, 0x1B, 0x58, 0x64, 0x9C, 0x6E, 0x66, 0x0E, 0xF5, 0xB5, 0xCA, + 0x4E, 0x9C, 0x6C, 0x5E, 0xDC, 0x5E, 0x76, 0x44, 0x6D, 0x9F, 0x67, 0xA6, 0x25, 0x02, 0xB4, 0x34, + 0x31, 0xC4, 0x9C, 0xBC, 0x33, 0xF0, 0x59, 0x16, 0x6F, 0x02, 0x4E, 0x73, 0x8B, 0xB4, 0xF9, 0xAF, + 0x20, 0xAF, 0xDD, 0x8A, 0xFC, 0xD9, 0xE3, 0x1A, 0xF1, 0xAD, 0x88, 0x9B, 0x6E, 0x9C, 0x4C, 0xD9, + 0x69, 0xD0, 0xBD, 0x78, 0xB3, 0x6D, 0x95, 0x9D, 0xA6, 0x17, 0x8A, 0x93, 0x5E, 0x4F, 0x81, 0x2A, + 0x9C, 0xEF, 0x74, 0xA6, 0x2D, 0xCF, 0x55, 0x13, 0x38, 0x03, 0xD8, 0xE4, 0x01, 0xB8, 0x63, 0x5B, + 0x8A, 0x5D, 0x07, 0x70, 0xB5, 0xF1, 0xAB, 0xC3, 0xE9, 0x1B, 0xA2, 0x75, 0x23, 0xC1, 0x51, 0xDC, + 0x55, 0xDA, 0xFC, 0x62, 0x88, 0xE9, 0xA2, 0xD1, 0xD2, 0x12, 0x7E, 0x61, 0x7A, 0x84, 0xD6, 0x19, + 0x4F, 0xF8, 0x8E, 0x73, 0x2D, 0x35, 0x5D, 0x57, 0xCD, 0x3D, 0x48, 0xE3, 0xBD, 0x05, 0xFF, 0xEB, + 0x05, 0x7F, 0xFD, 0x9F, 0xC3, 0x5E, 0x0F, 0xF8, 0x5F, 0x33, 0xD1, 0x6A, 0x11, 0x01, 0x21, 0x91, + 0xA6, 0x7F, 0x29, 0x5A, 0xE2, 0x60, 0xCE, 0x52, 0xFA, 0x8A, 0x67, 0x34, 0x23, 0xD5, 0x7A, 0x9D, + 0x32, 0xA6, 0x41, 0x42, 0x64, 0xDD, 0xEE, 0xA2, 0xFB, 0x96, 0x85, 0xE1, 0xC8, 0xDA, 0x66, 0xA8, + 0xB9, 0xC2, 0xCB, 0x53, 0xAB, 0x1F, 0x4D, 0x57, 0x46, 0x1E, 0xBF, 0x4B, 0x8C, 0x71, 0x37, 0xF7, + 0x47, 0x82, 0x7E, 0x4B, 0x5C, 0x24, 0x85, 0xF4, 0xF0, 0xA4, 0xC0, 0xED, 0xAE, 0x77, 0x89, 0x3C, + 0x11, 0xA4, 0x4F, 0x78, 0x9A, 0x96, 0x05, 0x1E, 0xA7, 0xEF, 0x08, 0x0A, 0x58, 0xFD, 0x10, 0x04, + 0x86, 0x37, 0x18, 0x99, 0x12, 0x81, 0x7A, 0x36, 0x78, 0x22, 0xA6, 0x7B, 0xF1, 0x66, 0x33, 0x4E, + 0x9F, 0x32, 0xBD, 0x10, 0x46, 0xEA, 0x1B, 0xA5, 0xAB, 0xEF, 0x78, 0xA0, 0xEC, 0x6E, 0x94, 0x4D, + 0x47, 0x38, 0x5D, 0x9E, 0xAC, 0x99, 0x04, 0x95, 0x23, 0x4B, 0x59, 0xDC, 0xF3, 0x18, 0xF6, 0xFA, + 0x49, 0x07, 0xC4, 0x08, 0xE6, 0x6D, 0xEF, 0xB6, 0x5A, 0x77, 0x45, 0x5D, 0x31, 0x2D, 0x03, 0xAE, + 0x1F, 0x1A, 0x37, 0x15, 0x4D, 0x50, 0x5B, 0xC4, 0x32, 0x83, 0x2E, 0xF2, 0x70, 0x37, 0x1D, 0x9D, + 0xD4, 0xA0, 0x9E, 0xFD, 0x5C, 0xF1, 0x63, 0x64, 0x3B, 0x65, 0xB8, 0x16, 0xC1, 0x77, 0xA2, 0xB6, + 0x3D, 0xD8, 0x9F, 0x85, 0xB4, 0xB0, 0x2B, 0x6D, 0x8D, 0xDF, 0x35, 0x50, 0xAC, 0x3D, 0x47, 0x86, + 0x93, 0xDA, 0x8A, 0xBB, 0xA9, 0x6D, 0xE9, 0x08, 0x26, 0x5B, 0x75, 0x5A, 0x1F, 0x89, 0x80, 0xC3, + 0x5A, 0x9A, 0x15, 0xCD, 0x96, 0xE4, 0x01, 0xA9, 0x96, 0xE9, 0x94, 0xC3, 0xB5, 0x2D, 0xEA, 0xB6, + 0x97, 0x42, 0x8B, 0xA6, 0x77, 0xAE, 0x9D, 0xF0, 0x13, 0x28, 0x99, 0xBB, 0x2B, 0x54, 0x3D, 0x38, + 0xC0, 0x43, 0x82, 0x55, 0xEA, 0xAB, 0xD7, 0x78, 0x04, 0x79, 0xC0, 0x18, 0xAB, 0x98, 0x3F, 0x66, + 0xBB, 0x19, 0x8C, 0xB8, 0xE3, 0x57, 0xAA, 0x9B, 0xAE, 0x65, 0x34, 0xA1, 0xED, 0xCA, 0x63, 0x13, + 0x89, 0x3C, 0x12, 0x6C, 0x19, 0xFF, 0x80, 0xDA, 0xE2, 0x6A, 0xE3, 0xE9, 0x8A, 0x38, 0x48, 0x6F, + 0xDB, 0xC3, 0xC7, 0x2F, 0xFF, 0x03, 0xEC, 0x1A, 0x55, 0x6E, 0x64, 0x4A, 0x27, 0x20, 0xB2, 0xC1, + 0x13, 0x31, 0x65, 0x4B, 0xBC, 0xD9, 0x5B, 0x03, 0xFB, 0x1B, 0x2F, 0x44, 0x0F, 0xB5, 0xB8, 0x82, + 0x98, 0xC8, 0xA6, 0x6B, 0xFD, 0xF5, 0xFF, 0xAF, 0xF1, 0x67, 0x07, 0x47, 0x31, 0xBA, 0x83, 0x59, + 0xB2, 0x41, 0x33, 0x09, 0x7A, 0x80, 0xA5, 0x8C, 0xA5, 0xA9, 0x67, 0xCC, 0x54, 0x1A, 0xDD, 0x40, + 0xC0, 0xCA, 0x06, 0xE8, 0x61, 0x6E, 0x17, 0x22, 0x11, 0x04, 0x6B, 0x19, 0x8C, 0x76, 0xC1, 0x22, + 0xC3, 0x5A, 0xA6, 0x9F, 0xD6, 0x45, 0x2F, 0x73, 0xB5, 0x97, 0x1F, 0xA0, 0x19, 0xE8, 0xE2, 0xC6, + 0x6D, 0xB3, 0xD5, 0x75, 0x47, 0x8C, 0x08, 0x5C, 0xD0, 0x53, 0x08, 0x0F, 0xA7, 0x2B, 0xCA, 0x7C, + 0x11, 0xC0, 0xC5, 0x36, 0xC9, 0xC8, 0x6D, 0x30, 0xDB, 0x4C, 0x4B, 0x04, 0xF0, 0x5F, 0x73, 0x7A, + 0xFC, 0x31, 0xBA, 0x31, 0x51, 0xE6, 0x77, 0xCC, 0xE3, 0xA2, 0x96, 0x2B, 0xD5, 0x1F, 0x1D, 0xFB, + 0x51, 0xA3, 0x29, 0x84, 0x5A, 0x21, 0x24, 0xCF, 0x63, 0x70, 0xFF, 0x46, 0x16, 0x5F, 0x8F, 0xCB, + 0x62, 0xB1, 0xB8, 0x6E, 0x16, 0xC4, 0xC9, 0x1B, 0x57, 0x2D, 0x5D, 0x16, 0x07, 0x5B, 0x19, 0xCC, + 0xF1, 0x53, 0x2B, 0xED, 0x99, 0xE2, 0x04, 0x4C, 0x89, 0x98, 0xB2, 0x45, 0x51, 0xD9, 0x8B, 0xEB, + 0x85, 0x68, 0x49, 0x84, 0x2D, 0xCB, 0xE2, 0x62, 0x2E, 0xA3, 0x2B, 0xDE, 0xD0, 0x4C, 0x42, 0x24, + 0xD1, 0x5E, 0x56, 0x6D, 0x79, 0x7B, 0xA3, 0x3A, 0xD2, 0x01, 0x6B, 0x17, 0x74, 0x38, 0xB7, 0x0B, + 0x28, 0x1E, 0x5C, 0x40, 0x32, 0xC1, 0xE4, 0xE5, 0x3E, 0x6E, 0x3A, 0xEF, 0xB6, 0xF4, 0xF6, 0x0F, + 0xAC, 0x2E, 0xD4, 0x2F, 0x99, 0x8A, 0x39, 0x0B, 0x0E, 0xBF, 0xF8, 0xB6, 0x43, 0x1B, 0xF1, 0x63, + 0x36, 0x22, 0x20, 0x58, 0x48, 0x99, 0x76, 0x6D, 0xA9, 0xD7, 0x54, 0xD3, 0x38, 0x49, 0xA6, 0x9A, + 0x72, 0x71, 0xFB, 0xF1, 0xE3, 0x06, 0xAD, 0x61, 0x22, 0x80, 0xFF, 0xB2, 0x54, 0x3E, 0x32, 0x27, + 0x6F, 0xA3, 0x6C, 0xDC, 0xBB, 0x1B, 0xFE, 0x72, 0x19, 0x56, 0xF9, 0xFF, 0x0E, 0xB6, 0x85, 0x20, + 0x79, 0xF1, 0x38, 0xCF, 0x25, 0x12, 0x3C, 0x61, 0xC4, 0x35, 0xD1, 0xFB, 0x0D, 0x37, 0x00, 0x46, + 0xA8, 0x61, 0xAF, 0x6F, 0x79, 0x6D, 0x01, 0xFF, 0xD2, 0xA7, 0x1E, 0xC3, 0xC3, 0x80, 0xE3, 0x65, + 0x4A, 0x24, 0x62, 0xB6, 0x04, 0x83, 0x6F, 0x86, 0x7E, 0x7B, 0xBC, 0x3A, 0x35, 0x4B, 0xF9, 0x20, + 0xFA, 0xE9, 0x74, 0x79, 0xB2, 0xB1, 0x24, 0x0C, 0x88, 0x18, 0x59, 0x81, 0x8D, 0x0F, 0xB0, 0x55, + 0x70, 0x45, 0xA2, 0x16, 0x4F, 0xFF, 0xFA, 0x09, 0xD8, 0xDD, 0xFD, 0xE5, 0x71, 0xEA, 0x1F, 0x00, + 0xF4, 0x79, 0x51, 0xF3, 0x67, 0xAE, 0xC0, 0xF8, 0x5B, 0x8B, 0x51, 0xF7, 0x84, 0xEE, 0xA7, 0x5E, + 0x33, 0x83, 0x54, 0x4D, 0x8C, 0x08, 0xA8, 0x95, 0xB2, 0x5A, 0xBF, 0x22, 0x4A, 0xDF, 0x18, 0x2B, + 0x7A, 0xE8, 0xFE, 0xF5, 0xD7, 0x84, 0xF0, 0xD1, 0x2B, 0x3A, 0x2E, 0x06, 0xCE, 0x0D, 0x1A, 0xAD, + 0xBE, 0x22, 0xA0, 0xAF, 0x48, 0x13, 0x43, 0x36, 0x70, 0xE7, 0x89, 0xBA, 0x26, 0xD8, 0xAA, 0x97, + 0x83, 0x4E, 0x93, 0x01, 0x83, 0xFC, 0xCB, 0xE6, 0xDF, 0x01, 0x45, 0xFF, 0x3C, 0xC3, 0x6B, 0x84, + 0x6C, 0x9D, 0x5C, 0xAA, 0x91, 0xC7, 0x18, 0xBA, 0x7F, 0x9F, 0x5F, 0x5B, 0xE2, 0x6E, 0x9D, 0xCC, + 0xCB, 0xFC, 0x86, 0x05, 0xFA, 0x10, 0x6F, 0xC6, 0x47, 0x54, 0x67, 0x3E, 0x9E, 0xEE, 0x29, 0x7C, + 0x3B, 0x1E, 0x67, 0xD7, 0xB0, 0x32, 0xF8, 0x97, 0xC7, 0x6E, 0x25, 0x45, 0x4D, 0x2D, 0x53, 0x46, + 0x20, 0xCF, 0x46, 0x4C, 0xB6, 0x30, 0x2A, 0x2F, 0x0E, 0xAD, 0x10, 0xD1, 0xE3, 0x65, 0x64, 0x89, + 0xAD, 0x51, 0xD2, 0xD8, 0xD9, 0x3A, 0x79, 0x78, 0xE0, 0xD6, 0x83, 0xA4, 0xDC, 0x47, 0x74, 0x79, + 0xB2, 0xE4, 0xAF, 0x53, 0xA0, 0x4E, 0x17, 0x4B, 0xF9, 0x13, 0xA6, 0x8C, 0x65, 0x09, 0xF6, 0x76, + 0x81, 0x5A, 0x05, 0xFC, 0x33, 0x8D, 0x17, 0x98, 0x4A, 0xC9, 0x6C, 0xB5, 0xC5, 0x83, 0x62, 0x5F, + 0xDD, 0xE6, 0x22, 0xC1, 0x85, 0xBA, 0x26, 0xDC, 0x45, 0x0E, 0x92, 0x86, 0x28, 0xF2, 0x99, 0x1C, + 0x26, 0x6F, 0x5D, 0x9E, 0x89, 0x10, 0x76, 0x65, 0x92, 0xF4, 0x35, 0xD2, 0x51, 0x61, 0xC1, 0x44, + 0x12, 0x47, 0x1A, 0x8F, 0x72, 0x0A, 0x06, 0x2D, 0x2D, 0x40, 0xA4, 0x89, 0x21, 0xB3, 0x85, 0x13, + 0xAF, 0x03, 0xA7, 0xB7, 0x69, 0x92, 0x51, 0xA7, 0x49, 0x77, 0x4F, 0x91, 0x16, 0x0C, 0xE5, 0x80, + 0x06, 0x2F, 0x3C, 0x84, 0x67, 0x89, 0x91, 0x17, 0x31, 0x44, 0x2E, 0x19, 0x41, 0x53, 0xDC, 0x62, + 0xDE, 0x3A, 0x4C, 0xEF, 0x6C, 0x1F, 0xA6, 0x93, 0x27, 0x2B, 0x0F, 0x18, 0x45, 0xBC, 0x36, 0x8B, + 0x83, 0x0F, 0x33, 0x4D, 0x9A, 0xD5, 0x94, 0x47, 0x23, 0x53, 0x66, 0x02, 0x7A, 0x22, 0xE6, 0x6C, + 0x69, 0xC5, 0x61, 0x7E, 0x21, 0x24, 0x3F, 0x90, 0xB5, 0x21, 0xC5, 0x8D, 0xED, 0xC3, 0x1E, 0x56, + 0xB7, 0x11, 0x61, 0xA2, 0xCB, 0x93, 0x35, 0x93, 0xC0, 0x22, 0xE5, 0x29, 0x8B, 0x24, 0x44, 0xC6, + 0x4C, 0x55, 0x93, 0x06, 0x9C, 0xDB, 0x05, 0x87, 0xFE, 0x41, 0x24, 0x6C, 0xE3, 0x03, 0x33, 0xC4, + 0xC0, 0xC7, 0xE2, 0x8A, 0x13, 0x21, 0x05, 0xC4, 0x7F, 0x28, 0x2D, 0x72, 0x89, 0x90, 0x1C, 0x41, + 0xAC, 0x69, 0xF3, 0xAD, 0xD6, 0x2A, 0xE3, 0x00, 0x30, 0x79, 0x1A, 0x0C, 0x31, 0x51, 0x1D, 0x9F, + 0x15, 0x74, 0xED, 0xC9, 0x22, 0xEC, 0xFD, 0x81, 0xD8, 0x18, 0xA9, 0x22, 0x50, 0x55, 0x65, 0x86, + 0xE0, 0x03, 0xAB, 0x46, 0x71, 0xD7, 0x9D, 0x51, 0x1A, 0x75, 0xD9, 0x5D, 0x71, 0x22, 0xA4, 0x80, + 0xF8, 0x0F, 0xA5, 0x45, 0x2E, 0x11, 0x92, 0x20, 0xB8, 0xEE, 0xDB, 0x50, 0x7C, 0xC8, 0x31, 0xA4, + 0xFA, 0x16, 0xA6, 0x65, 0x99, 0x42, 0xA6, 0x62, 0xA2, 0x3A, 0x3E, 0xCB, 0xE8, 0xC6, 0x4F, 0x56, + 0x43, 0xD7, 0x31, 0x92, 0x80, 0xF3, 0x42, 0xB2, 0xD0, 0x4B, 0xB3, 0x1B, 0x47, 0xC8, 0xBF, 0xE5, + 0xC6, 0x4A, 0xB4, 0xE3, 0x23, 0x91, 0x0E, 0xEC, 0xE5, 0x68, 0x2F, 0x59, 0x8C, 0x51, 0x7B, 0xBB, + 0x68, 0x17, 0x02, 0x16, 0xD1, 0x61, 0xBF, 0xCF, 0x03, 0x60, 0xD3, 0xE5, 0xA0, 0x60, 0x29, 0xD1, + 0x35, 0x02, 0xB6, 0x72, 0x34, 0xF7, 0x0E, 0x18, 0x30, 0x8A, 0xA9, 0x5D, 0xB0, 0x2F, 0x4A, 0xE7, + 0xDD, 0x01, 0x2D, 0x39, 0xFF, 0xAE, 0x0A, 0x15, 0x49, 0x55, 0x65, 0xE1, 0xAC, 0x3B, 0xE7, 0xBA, + 0x38, 0x0B, 0x15, 0xC9, 0x95, 0xAE, 0x8D, 0x0F, 0x6C, 0xD6, 0xD8, 0xF3, 0x09, 0x39, 0x2F, 0xD0, + 0x02, 0x05, 0x2F, 0xBD, 0xAE, 0x2A, 0xD6, 0xCA, 0x07, 0x79, 0xCC, 0x06, 0x52, 0x1E, 0xA4, 0x09, + 0x51, 0x7C, 0x5D, 0x54, 0xAD, 0x75, 0xEA, 0x30, 0x71, 0xDC, 0xDC, 0x22, 0xE7, 0x05, 0x5A, 0xA0, + 0xD0, 0xCA, 0x2F, 0x71, 0xE5, 0x9A, 0xF9, 0x20, 0xAF, 0xD9, 0x40, 0xCA, 0x83, 0x34, 0xA1, 0x17, + 0x60, 0xC2, 0xEA, 0x35, 0xF3, 0x81, 0x6D, 0x25, 0x32, 0xCF, 0x90, 0xF3, 0x02, 0x2D, 0x50, 0xE8, + 0x05, 0x98, 0xB0, 0x7A, 0x2D, 0xED, 0x42, 0x5E, 0x33, 0x42, 0xCE, 0x0B, 0xB4, 0x40, 0xA1, 0x95, + 0x5F, 0xE2, 0xCA, 0xB5, 0xF6, 0x13, 0xF3, 0x99, 0x11, 0x72, 0x5E, 0xA0, 0x05, 0x0A, 0x51, 0x7C, + 0x5D, 0x54, 0xAD, 0x6D, 0xDC, 0x98, 0xC7, 0x8C, 0x90, 0xF3, 0x02, 0x2D, 0x50, 0xF0, 0xD2, 0xEB, + 0xAA, 0x62, 0x0B, 0x67, 0x1E, 0x29, 0xE7, 0x05, 0x5A, 0xA0, 0x48, 0xAE, 0x74, 0xE5, 0x7C, 0xE2, + 0xB9, 0x8E, 0xE4, 0x4A, 0x57, 0x5B, 0x5F, 0xB0, 0x1F, 0xCE, 0xE0, 0x78, 0x58, 0x43, 0x4E, 0x91, + 0xF3, 0x02, 0x2D, 0x54, 0x24, 0x55, 0x95, 0x82, 0x0F, 0xEC, 0x8B, 0xD2, 0x79, 0xB8, 0xDB, 0x39, + 0xD7, 0xC5, 0x59, 0xA8, 0x48, 0xAE, 0x2A, 0xB9, 0xFE, 0xC1, 0xD4, 0xA4, 0xE2, 0x4A, 0x9C, 0x93, + 0x20, 0x06, 0xE0, 0xE7, 0x33, 0xCD, 0xEE, 0x1E, 0x21, 0x89, 0xC2, 0x07, 0xE3, 0x03, 0x34, 0x88, + 0x8C, 0x56, 0x6F, 0xE5, 0x5F, 0x2F, 0xFD, 0x9B, 0xA2, 0xF1, 0xC1, 0xCC, 0xB4, 0xD9, 0x48, 0xA2, + 0xF0, 0xE1, 0xA2, 0x21, 0x05, 0xEF, 0x27, 0x4A, 0x2B, 0x08, 0xBD, 0x18, 0x6C, 0x57, 0x08, 0xE3, + 0x83, 0x9D, 0x1E, 0x35, 0x02, 0x6E, 0xEA, 0x58, 0x2A, 0x68, 0x4F, 0xD5, 0x4D, 0x36, 0xF3, 0xB2, + 0xEF, 0xA8, 0x0D, 0xE3, 0xD5, 0x1D, 0x91, 0x97, 0x5C, 0x5E, 0x10, 0x0A, 0x9C, 0xAF, 0xF1, 0xC1, + 0x04, 0xBA, 0x1C, 0x08, 0x69, 0x16, 0x94, 0x74, 0x93, 0x79, 0x59, 0x74, 0x04, 0x41, 0xC5, 0x54, + 0x3B, 0xE9, 0xDC, 0xF0, 0xAC, 0x5D, 0xE8, 0xFF, 0xD8, 0xC8, 0x83, 0xE3, 0xB2, 0x99, 0x46, 0xB7, + 0x2E, 0x70, 0xAC, 0x63, 0x5C, 0xAE, 0x12, 0xE7, 0x85, 0xC3, 0xFF, 0x11, 0x6C, 0xDC, 0xD8, 0x41, + 0xAE, 0x0F, 0x27, 0x26, 0x39, 0x05, 0x99, 0x19, 0x04, 0xF7, 0x4E, 0x80, 0xE2, 0x6E, 0x53, 0xE9, + 0x1A, 0x1D, 0x07, 0x8B, 0x47, 0xF6, 0x44, 0x3A, 0x69, 0xA1, 0xE3, 0x00, 0x7E, 0x0C, 0x58, 0x13, + 0xFC, 0xAF, 0x67, 0x5D, 0x82, 0x01, 0x10, 0xC5, 0xBA, 0x3D, 0xD5, 0x74, 0x0A, 0x6A, 0x1D, 0xDF, + 0xA0, 0x8F, 0x06, 0x4C, 0x70, 0x67, 0xE0, 0x76, 0x27, 0xCB, 0x21, 0xEB, 0x8C, 0x03, 0x1A, 0x38, + 0xB6, 0x9B, 0x77, 0xEF, 0x7B, 0x9D, 0x88, 0x56, 0x0D, 0x35, 0x8E, 0x69, 0x30, 0xBB, 0x9D, 0xF0, + 0xB6, 0xDF, 0xBF, 0x2A, 0x61, 0x04, 0x8E, 0x08, 0xC9, 0x83, 0xE4, 0xA1, 0x51, 0x4D, 0x2F, 0xF5, + 0x8E, 0x71, 0x97, 0x9A, 0xE3, 0x94, 0x3C, 0x9E, 0x90, 0x06, 0xB0, 0x42, 0x40, 0x36, 0xC5, 0x3F, + 0xCA, 0x25, 0xFE, 0x8F, 0xCB, 0xB6, 0x8B, 0x27, 0xC5, 0x6E, 0xCC, 0xB5, 0xCE, 0xF8, 0xA0, 0x18, + 0x8A, 0x8B, 0x8B, 0x99, 0xA5, 0x75, 0x02, 0x9D, 0xBC, 0x94, 0xF4, 0x71, 0x4A, 0x81, 0xAF, 0x54, + 0x76, 0x5E, 0x65, 0xAF, 0x6F, 0x8E, 0xED, 0xDF, 0x5E, 0xBC, 0x96, 0xD9, 0xBB, 0x99, 0xC3, 0x48, + 0x62, 0xA4, 0x8B, 0x5F, 0xAB, 0x59, 0xA6, 0x07, 0x87, 0x8A, 0x8B, 0xB1, 0x55, 0xF2, 0x54, 0x95, + 0xA2, 0x81, 0x96, 0x01, 0x27, 0xD0, 0x05, 0x58, 0xF6, 0x78, 0xAC, 0x3C, 0xB9, 0xD0, 0xCD, 0x1A, + 0x2C, 0x0A, 0x1F, 0xDA, 0xC4, 0x7D, 0xEC, 0x08, 0xCE, 0x5F, 0x11, 0xBA, 0xCF, 0x39, 0xC8, 0x8C, + 0x62, 0x6F, 0x07, 0x4B, 0x07, 0x28, 0xA1, 0xB9, 0x5D, 0xC5, 0xD6, 0xA8, 0xB2, 0xE4, 0xD3, 0x48, + 0xFD, 0xB7, 0x23, 0xFF, 0x86, 0x34, 0x26, 0xE0, 0x43, 0xC8, 0x27, 0x73, 0x3F, 0xF5, 0x97, 0x47, + 0xE3, 0x3C, 0xCE, 0x53, 0xF0, 0x60, 0xA1, 0x63, 0xC9, 0x77, 0xD0, 0x1F, 0x5E, 0xF0, 0x1F, 0x3A, + 0xF0, 0x3F, 0xAB, 0x2E, 0x96, 0x14, 0xDD, 0x88, 0x5B, 0x04, 0x95, 0x34, 0x97, 0x07, 0x1D, 0x18, + 0xA0, 0x6D, 0xB7, 0x0A, 0x8C, 0x3D, 0xD3, 0xD8, 0xDE, 0x5F, 0xDB, 0x9A, 0xDC, 0x15, 0x22, 0x4D, + 0xC5, 0xDE, 0x79, 0xEA, 0x5A, 0xA7, 0xA0, 0x37, 0x8B, 0xD1, 0x5C, 0xFF, 0x1C, 0x55, 0x7D, 0xF4, + 0x9D, 0x87, 0x60, 0x26, 0xFE, 0xFC, 0xA4, 0x01, 0xE6, 0x3D, 0xFA, 0x33, 0x33, 0x5D, 0x56, 0x1E, + 0xFE, 0x86, 0x50, 0xA8, 0xF5, 0x3C, 0x72, 0x7B, 0x2E, 0x6E, 0x1E, 0x31, 0x9E, 0xFB, 0x7A, 0xF0, + 0xCF, 0xC7, 0xDC, 0xA0, 0xF9, 0xD8, 0x51, 0xD3, 0xFE, 0xB5, 0x38, 0x45, 0x6C, 0x85, 0xCA, 0xD9, + 0x20, 0x78, 0xE3, 0x9E, 0xD0, 0xE9, 0x3E, 0x5D, 0xC5, 0xF6, 0x0A, 0xAA, 0x5A, 0xBA, 0x29, 0xA6, + 0x1E, 0x7D, 0xE0, 0x59, 0xF0, 0x3C, 0x33, 0x70, 0xD0, 0x10, 0x78, 0xFB, 0xB3, 0xC7, 0x42, 0xFF, + 0x17, 0xFE, 0xD4, 0x80, 0x5F, 0x44, 0xE2, 0xA4, 0xC4, 0x13, 0x09, 0x17, 0x63, 0x9B, 0x8C, 0x15, + 0x81, 0x75, 0x82, 0xE5, 0xC1, 0x6A, 0x06, 0x7F, 0x3B, 0xB2, 0xE4, 0xC2, 0xB4, 0x98, 0x93, 0xDD, + 0x60, 0x00, 0x56, 0x3B, 0x03, 0x46, 0xD1, 0xDA, 0x05, 0xCE, 0x15, 0x84, 0xB7, 0x3E, 0xFA, 0xD6, + 0x70, 0xFF, 0xB3, 0x1D, 0x6B, 0x48, 0xD4, 0x93, 0xEC, 0x27, 0x03, 0x4F, 0xD3, 0x42, 0xD6, 0x3B, + 0x74, 0x2A, 0xDF, 0xA6, 0xC8, 0x81, 0xF1, 0x91, 0x77, 0x5C, 0x2F, 0xF3, 0x46, 0xC1, 0x08, 0x62, + 0xF2, 0xA1, 0xF5, 0xBE, 0x4A, 0x34, 0x37, 0xB0, 0x1D, 0x57, 0xBE, 0x95, 0x3B, 0xD0, 0xF8, 0x0D, + 0x94, 0xAA, 0xBF, 0x06, 0x98, 0xD9, 0xA9, 0xEF, 0xEE, 0xE3, 0xED, 0x82, 0xE2, 0x1B, 0x3F, 0x44, + 0x81, 0xB0, 0xF2, 0x0B, 0xAF, 0xB7, 0x68, 0xFF, 0xF6, 0x01, 0xA7, 0x60, 0xC8, 0x76, 0x1F, 0xBA, + 0x22, 0x3B, 0x7D, 0xDE, 0x0B, 0xA3, 0x43, 0x70, 0x48, 0x73, 0xEB, 0xEE, 0xF2, 0x21, 0x03, 0x27, + 0x96, 0x1E, 0xE5, 0x11, 0x06, 0x4E, 0xF4, 0x7A, 0x57, 0x02, 0xBA, 0x2F, 0x68, 0xBF, 0x21, 0x30, + 0xF2, 0x82, 0xFF, 0xA5, 0xB8, 0xE8, 0xC9, 0x82, 0x2F, 0xC0, 0x5D, 0xE1, 0x11, 0xEB, 0x1F, 0x60, + 0x6A, 0x94, 0x60, 0x04, 0x14, 0x57, 0xF1, 0x40, 0x28, 0x7D, 0x6D, 0xFB, 0xC0, 0x13, 0x0A, 0xFE, + 0xB7, 0x97, 0x21, 0x99, 0x56, 0xBA, 0xB0, 0xD4, 0xC2, 0xEC, 0x69, 0xBA, 0xB4, 0x21, 0x55, 0x74, + 0x2A, 0x3B, 0x67, 0xB7, 0xD6, 0x0F, 0xC1, 0x43, 0x49, 0x52, 0x4B, 0x1D, 0x76, 0x8C, 0xAC, 0x50, + 0x94, 0xAF, 0xEF, 0x38, 0x08, 0xD1, 0x9D, 0xD5, 0xB8, 0xDF, 0xDE, 0x03, 0xF7, 0xFD, 0xC9, 0x8D, + 0xEF, 0x60, 0xCB, 0x15, 0x65, 0x4C, 0x07, 0xD5, 0x0E, 0xAB, 0x1F, 0x51, 0x21, 0xCC, 0x8D, 0x9F, + 0x25, 0xFD, 0x61, 0x28, 0x39, 0x98, 0x4F, 0x06, 0x5C, 0x8C, 0xE1, 0x58, 0x22, 0x22, 0x1D, 0xC6, + 0x12, 0xBC, 0x79, 0x30, 0x66, 0x0E, 0xB4, 0xF6, 0xBA, 0x8E, 0x4E, 0xE5, 0xE9, 0x07, 0xC2, 0xB0, + 0x97, 0xBB, 0xF5, 0xD3, 0x8B, 0xD5, 0x6D, 0x9A, 0x38, 0xD7, 0xEE, 0xB6, 0x7F, 0x7B, 0x36, 0x6E, + 0xEB, 0x46, 0x0F, 0x7F, 0xBD, 0xBB, 0xB2, 0x83, 0x77, 0x38, 0x44, 0xD0, 0xE6, 0x6F, 0xE3, 0x6E, + 0x6F, 0x92, 0x0F, 0x35, 0x11, 0x76, 0x40, 0xCF, 0xBA, 0x92, 0x07, 0x8F, 0xD1, 0x31, 0x1D, 0xAD, + 0xDF, 0x53, 0xEE, 0x40, 0xBA, 0xC4, 0x0C, 0x1C, 0xD8, 0x53, 0x40, 0x8E, 0x01, 0xA8, 0xF5, 0x79, + 0xBC, 0x03, 0x3E, 0xFA, 0x46, 0x28, 0xFC, 0xFF, 0x7D, 0xD9, 0x37, 0xBE, 0xB4, 0xBE, 0xE3, 0xB6, + 0x23, 0xE1, 0xBF, 0xFD, 0x43, 0xC7, 0x67, 0x7F, 0x18, 0xC6, 0xE2, 0xC4, 0xDC, 0xFD, 0xA1, 0x34, + 0xF8, 0xA7, 0xC0, 0x97, 0xDA, 0xCA, 0xBF, 0x11, 0xA6, 0x08, 0x81, 0x2F, 0x85, 0xB6, 0xFE, 0xFE, + 0x4F, 0x4B, 0x8E, 0x85, 0xBE, 0xD1, 0xF6, 0x5A, 0x69, 0xF0, 0xAD, 0xBB, 0x28, 0x6E, 0x2B, 0x06, + 0x7F, 0x84, 0x5E, 0x8B, 0x5C, 0xA0, 0xE0, 0x80, 0x04, 0x4F, 0x80, 0x60, 0x57, 0x70, 0x23, 0x79, + 0xC1, 0x6C, 0x6E, 0x50, 0x4B, 0x96, 0x8E, 0xFC, 0x07, 0x6C, 0xEF, 0xC6, 0x0F, 0xC1, 0x51, 0xD1, + 0xD0, 0x7F, 0x5F, 0x14, 0x0A, 0x2D, 0x9F, 0xF4, 0xAD, 0x70, 0x78, 0x19, 0x4B, 0x6D, 0x0B, 0x3D, + 0xBD, 0x47, 0xA3, 0xBA, 0xE3, 0x20, 0x9E, 0x70, 0x5D, 0x8F, 0x8F, 0xA9, 0x6A, 0x4A, 0xA9, 0xE3, + 0xBB, 0x9C, 0xEC, 0x83, 0x29, 0xD1, 0x21, 0x26, 0xE1, 0x55, 0x53, 0x8B, 0x91, 0x65, 0x60, 0x66, + 0x98, 0xDE, 0xC1, 0x92, 0x2B, 0x88, 0x52, 0xC6, 0x18, 0x78, 0x41, 0xB0, 0x9A, 0x28, 0xC6, 0x6C, + 0xB1, 0x0A, 0xC1, 0x8B, 0x0F, 0x7D, 0xF0, 0xAE, 0x58, 0xC1, 0xCA, 0x22, 0xB7, 0xC2, 0x42, 0xBA, + 0xEF, 0x02, 0xC6, 0x13, 0xF4, 0x83, 0x5D, 0x1F, 0x96, 0xA6, 0x71, 0xDE, 0x8A, 0xC1, 0x07, 0x46, + 0x0F, 0xCE, 0xCC, 0xAF, 0x91, 0xAD, 0x91, 0x1F, 0x2B, 0x97, 0x68, 0x5C, 0xA1, 0xDD, 0x55, 0xC3, + 0x75, 0xA6, 0x38, 0x1C, 0x7A, 0xC4, 0x1F, 0x6B, 0xDD, 0x05, 0x46, 0x67, 0x91, 0xFA, 0xA3, 0x11, + 0x8F, 0x00, 0xB4, 0x0E, 0x88, 0x4C, 0x65, 0x06, 0x23, 0x9A, 0xB5, 0xF8, 0x1A, 0xDF, 0x4D, 0x0D, + 0x86, 0xC3, 0x6D, 0xC3, 0xDE, 0xF5, 0x79, 0x2E, 0x0D, 0x0D, 0x82, 0xD6, 0xF1, 0xBB, 0x4F, 0x8C, + 0xF4, 0x5C, 0x18, 0xDA, 0x3A, 0xEA, 0x5E, 0x40, 0x99, 0xAC, 0x28, 0xAE, 0x0A, 0x94, 0xCC, 0x53, + 0xF1, 0xA6, 0xA5, 0x98, 0x22, 0xA0, 0xCB, 0xEB, 0xBA, 0xB4, 0xEF, 0xB8, 0x93, 0x5F, 0x1F, 0x86, + 0xB3, 0xA1, 0x75, 0x2C, 0x2E, 0x05, 0x4F, 0xF1, 0x8F, 0x3B, 0xB9, 0x70, 0x98, 0x42, 0x9C, 0xA5, + 0x83, 0xBD, 0x9A, 0xC2, 0xD2, 0xA1, 0xBB, 0x6F, 0x85, 0x9F, 0xF2, 0x5C, 0xC4, 0x52, 0x1C, 0x7F, + 0xE4, 0xE1, 0x1F, 0xBA, 0x5C, 0x3B, 0xCB, 0xEE, 0x55, 0x61, 0x2F, 0xA3, 0xF0, 0x49, 0x7A, 0xFA, + 0x72, 0xBC, 0x30, 0xAA, 0xD4, 0x16, 0xC0, 0xF8, 0xD2, 0xF1, 0xAC, 0xA6, 0x52, 0x48, 0x9D, 0x0E, + 0x35, 0x1A, 0x40, 0x29, 0xD2, 0x43, 0xBE, 0x63, 0xE1, 0x1D, 0x6B, 0x4F, 0x2A, 0xDE, 0x50, 0xC4, + 0x9C, 0x25, 0x96, 0x2D, 0x1C, 0xB1, 0x8B, 0x57, 0x17, 0x99, 0x63, 0x7F, 0xA0, 0x6A, 0x0E, 0xC6, + 0x49, 0xEC, 0x1F, 0x79, 0x83, 0x7A, 0x6D, 0x2C, 0x24, 0x23, 0x2E, 0x62, 0x06, 0xFC, 0x2B, 0xC6, + 0x2F, 0x9D, 0xB9, 0xD0, 0x5F, 0x64, 0x86, 0xF3, 0x01, 0x16, 0xA0, 0x5E, 0x2F, 0x15, 0x54, 0x55, + 0x67, 0xE1, 0x32, 0x71, 0x0B, 0x64, 0xCD, 0x41, 0x35, 0x0E, 0x5F, 0xB4, 0xDE, 0x59, 0xC0, 0x82, + 0xE6, 0xA1, 0xB1, 0x86, 0x1F, 0x5B, 0x06, 0x0F, 0x15, 0xD0, 0x04, 0xDB, 0xFB, 0x46, 0x8A, 0x5F, + 0x67, 0x29, 0xE8, 0xD6, 0x68, 0x90, 0xEF, 0x42, 0xA1, 0x50, 0x28, 0x58, 0x7F, 0x0A, 0xAF, 0xDB, + 0x2E, 0x59, 0x1E, 0x78, 0xEB, 0xE0, 0xDE, 0xFA, 0x50, 0xFD, 0x69, 0x7F, 0x43, 0x20, 0xD0, 0x5C, + 0x8A, 0xBE, 0x2C, 0xA4, 0xB3, 0xA6, 0xFE, 0x14, 0x39, 0xB6, 0x0D, 0xE5, 0x11, 0x4E, 0x85, 0x83, + 0xF5, 0x2D, 0x1F, 0x1E, 0x9F, 0x5A, 0xD2, 0x50, 0x0D, 0xA7, 0x82, 0x7A, 0x5C, 0xD7, 0x51, 0xF2, + 0x22, 0x7A, 0x88, 0x4E, 0xF3, 0x0F, 0x4B, 0x8A, 0xDF, 0x5D, 0x70, 0xFA, 0x58, 0x03, 0xA3, 0xBB, + 0x17, 0x4E, 0x75, 0x76, 0x22, 0xD5, 0x70, 0x88, 0x53, 0x18, 0x81, 0x4F, 0xF7, 0x39, 0xC9, 0x48, + 0x10, 0x55, 0x16, 0xE7, 0x74, 0xFD, 0x49, 0x9E, 0xBB, 0x54, 0x52, 0xFF, 0xA8, 0x59, 0xBC, 0x52, + 0x27, 0x74, 0x86, 0x2A, 0xFB, 0x3F, 0x1D, 0x6A, 0x73, 0xAB, 0x22, 0x53, 0x5A, 0xAE, 0xF4, 0x5F, + 0x96, 0x39, 0x12, 0x8A, 0x58, 0x19, 0x9C, 0x07, 0xCC, 0x0E, 0xAA, 0x22, 0xEC, 0xDB, 0xA0, 0x83, + 0xEA, 0x86, 0xD7, 0x57, 0xB7, 0x5D, 0x74, 0x43, 0xC4, 0x15, 0x0F, 0xFE, 0xB0, 0x10, 0x9E, 0x16, + 0x82, 0xF3, 0x01, 0x4A, 0x33, 0x8F, 0x26, 0x0F, 0x2E, 0x1B, 0xF6, 0xB3, 0xE3, 0x81, 0xAF, 0x28, + 0xDF, 0x03, 0xE8, 0x20, 0xAF, 0x7E, 0x20, 0xBA, 0x76, 0xE6, 0x3B, 0xC6, 0x2B, 0x36, 0x68, 0x11, + 0x2F, 0xE6, 0x56, 0xAC, 0xA0, 0xD2, 0x8D, 0x71, 0xD0, 0x7E, 0x68, 0x60, 0x27, 0x0C, 0x68, 0xFD, + 0x34, 0x54, 0xB6, 0x90, 0x45, 0x99, 0xB3, 0xCA, 0x97, 0xB5, 0xF8, 0x5E, 0xEA, 0x86, 0xE9, 0xF0, + 0x2D, 0x84, 0x3D, 0xAC, 0xEB, 0x30, 0xA5, 0xE8, 0xE7, 0xF4, 0x70, 0xF1, 0x33, 0xE2, 0x1E, 0x22, + 0xFC, 0x47, 0x8F, 0x00, 0x50, 0x7D, 0x9D, 0xEF, 0xE8, 0xE0, 0xF5, 0x14, 0x8B, 0xC5, 0x25, 0x54, + 0x69, 0x5E, 0x31, 0xF0, 0x84, 0xA8, 0x3F, 0x86, 0x31, 0x3E, 0x07, 0x50, 0x73, 0xD6, 0x8D, 0xD4, + 0xF6, 0x84, 0xA7, 0x96, 0xE2, 0x73, 0x73, 0xE8, 0xC2, 0x29, 0xD0, 0xD3, 0x83, 0x56, 0xE8, 0x24, + 0x28, 0x8E, 0x36, 0xD8, 0x4C, 0x2D, 0xF5, 0x29, 0xBB, 0xC4, 0x60, 0xD3, 0x77, 0xF7, 0x6D, 0x50, + 0xD5, 0xBC, 0x00, 0xF6, 0xB2, 0xE9, 0xA2, 0xB8, 0xF0, 0x60, 0x21, 0xA8, 0x1E, 0x0F, 0xD6, 0x13, + 0xB5, 0x18, 0xF8, 0x8B, 0x55, 0x4F, 0x7F, 0x1E, 0x04, 0x7A, 0x92, 0x87, 0x47, 0xC5, 0x00, 0xFA, + 0x21, 0x7F, 0x16, 0x37, 0x5D, 0x17, 0x25, 0xC5, 0x92, 0x23, 0x06, 0x50, 0x29, 0x15, 0x4A, 0x97, + 0x2E, 0x04, 0xDA, 0xF6, 0x4C, 0xAC, 0x19, 0xD8, 0x1D, 0x20, 0x3B, 0x69, 0xF8, 0x8F, 0xA7, 0x29, + 0x81, 0x72, 0x58, 0x8D, 0xA0, 0x55, 0x19, 0xA0, 0x23, 0x98, 0xA8, 0x56, 0x17, 0x3B, 0xDE, 0x61, + 0xE4, 0x16, 0x77, 0x25, 0x9A, 0x6B, 0x41, 0x5B, 0x2F, 0xCC, 0x48, 0x0C, 0x06, 0x91, 0xFD, 0x17, + 0x66, 0xDD, 0x23, 0xF2, 0x68, 0xF1, 0x31, 0x7E, 0x4A, 0x93, 0x78, 0x0A, 0xBD, 0x23, 0x8F, 0x72, + 0xC3, 0x1F, 0xF8, 0x60, 0xE0, 0x1D, 0x4C, 0x13, 0x77, 0x5D, 0xBF, 0x55, 0x8A, 0x5F, 0x55, 0x20, + 0x80, 0x3D, 0x8A, 0xFE, 0xA5, 0x9B, 0x10, 0x0D, 0x6F, 0x61, 0x5C, 0x5F, 0xC3, 0x16, 0xBA, 0x17, + 0x21, 0xCC, 0x21, 0x22, 0x34, 0xE0, 0x03, 0x07, 0xD0, 0x0E, 0xE3, 0x45, 0xEC, 0x41, 0x16, 0x97, + 0x3C, 0x4F, 0x33, 0xAF, 0x98, 0x2D, 0xDD, 0x88, 0xD0, 0xEE, 0x00, 0x4B, 0x27, 0x80, 0x6C, 0xA8, + 0xAC, 0x08, 0xAC, 0x63, 0x74, 0xE9, 0xB9, 0x7B, 0xF5, 0x8B, 0x8F, 0x11, 0xE4, 0x24, 0x88, 0x2A, + 0x8B, 0x43, 0x54, 0x53, 0x4E, 0xFD, 0xF4, 0xE0, 0x15, 0x01, 0x7A, 0x1C, 0xEE, 0xC5, 0xE4, 0x30, + 0xB5, 0xC0, 0xF0, 0x7B, 0x1D, 0x33, 0xA5, 0x67, 0x0E, 0x0B, 0x21, 0x84, 0xF9, 0xE3, 0xD2, 0x41, + 0x77, 0x04, 0x43, 0x01, 0xFC, 0xE3, 0xF7, 0xBC, 0x72, 0x98, 0x8F, 0x39, 0x4A, 0x1A, 0x2E, 0x76, + 0x83, 0x54, 0x38, 0x25, 0x7E, 0xCB, 0x23, 0x68, 0xE7, 0x33, 0x79, 0xC2, 0xF8, 0xC9, 0xEC, 0x9E, + 0xE2, 0x8B, 0x28, 0x68, 0x41, 0x11, 0xC0, 0xD5, 0xDE, 0x6F, 0x72, 0x55, 0x31, 0x5A, 0xCB, 0x8A, + 0x60, 0x67, 0xD7, 0x85, 0x17, 0x66, 0x43, 0x4D, 0xDC, 0x1A, 0x37, 0xF8, 0x17, 0x51, 0x30, 0x3E, + 0x8B, 0xC1, 0x42, 0xB4, 0x1F, 0xAA, 0x74, 0x57, 0xF4, 0x6F, 0x97, 0x2C, 0x5E, 0x63, 0x78, 0x32, + 0x33, 0x6C, 0x7F, 0xFA, 0xEC, 0xA7, 0xFF, 0x8A, 0xFC, 0x4D, 0x84, 0x3A, 0xF7, 0x4F, 0xF4, 0x64, + 0xD8, 0xD4, 0x89, 0x23, 0x3C, 0xBB, 0xA7, 0xB3, 0x21, 0x43, 0xCF, 0xE0, 0x99, 0x5F, 0x6D, 0x35, + 0xDF, 0xBE, 0x79, 0xC3, 0x81, 0x84, 0xC7, 0x15, 0x7A, 0x76, 0x4F, 0xC1, 0x92, 0xC7, 0xA2, 0x0C, + 0x2B, 0x6E, 0xAC, 0x03, 0x2A, 0x53, 0x95, 0x55, 0x06, 0x01, 0xEF, 0x44, 0x90, 0x88, 0xCD, 0x5D, + 0x11, 0x37, 0xFD, 0xF2, 0xC0, 0xE4, 0x5C, 0x61, 0x0F, 0x52, 0xC5, 0x5B, 0x46, 0x97, 0xAE, 0xE8, + 0x81, 0x77, 0x3A, 0xED, 0xB0, 0x3E, 0x9F, 0x48, 0x2D, 0xB7, 0x17, 0xA2, 0xD8, 0xB5, 0xA2, 0x3A, + 0x8C, 0xFA, 0x9E, 0xAF, 0xF1, 0x4D, 0x8B, 0x44, 0xA3, 0x0A, 0xDE, 0xD1, 0x25, 0x1A, 0x21, 0x43, + 0x6A, 0xFC, 0xD6, 0xB8, 0xC1, 0x3F, 0xEC, 0xFC, 0x8A, 0x18, 0x2C, 0x44, 0xFB, 0xA1, 0xD6, 0x26, + 0x0A, 0x17, 0x3E, 0xF9, 0xE3, 0x25, 0xBA, 0x67, 0x04, 0xFF, 0xE0, 0x6F, 0x9F, 0xAD, 0xFC, 0x33, + 0x76, 0xE3, 0x41, 0x89, 0x60, 0x04, 0x5C, 0xF9, 0x76, 0x2E, 0x9C, 0x42, 0xC6, 0x17, 0x8F, 0x59, + 0xE6, 0x13, 0xAF, 0xFE, 0xB7, 0xAE, 0x4E, 0xAD, 0xA4, 0xBA, 0xC1, 0xBA, 0xF0, 0xB8, 0xC9, 0xC5, + 0x1A, 0x07, 0xF0, 0xB0, 0xA1, 0x65, 0x98, 0x2D, 0xC6, 0xF0, 0x20, 0x20, 0x4E, 0x8E, 0x30, 0x17, + 0x2E, 0x0F, 0xB1, 0x5F, 0x1E, 0x98, 0x9C, 0xCB, 0x43, 0x54, 0xF1, 0x96, 0xD1, 0xA5, 0x2B, 0xBB, + 0xD3, 0x68, 0xF3, 0x51, 0x01, 0xE7, 0x3D, 0x15, 0xBB, 0x0B, 0x21, 0xBC, 0x46, 0x78, 0xF7, 0xC1, + 0x7D, 0x73, 0x58, 0xEF, 0x40, 0x50, 0xA0, 0xE8, 0x63, 0x88, 0x3F, 0xCD, 0xC5, 0xE2, 0x6B, 0x9D, + 0x5B, 0xA4, 0xC0, 0x9E, 0xE5, 0xAE, 0x10, 0x0E, 0xE1, 0x40, 0x59, 0xB4, 0x48, 0xD5, 0x3C, 0x79, + 0xF7, 0xE7, 0x42, 0x7C, 0x1D, 0x35, 0xA2, 0x44, 0xD9, 0x83, 0x5E, 0x3D, 0x81, 0x73, 0x08, 0xBE, + 0x83, 0xE6, 0xBB, 0x8B, 0xDA, 0xBB, 0x8A, 0x4F, 0xDF, 0x02, 0xCE, 0x34, 0x51, 0xF7, 0x8D, 0xFD, + 0xB0, 0xEE, 0x3B, 0xF5, 0x0C, 0x30, 0x04, 0x7D, 0x54, 0x16, 0x88, 0xFF, 0x18, 0x8F, 0xB5, 0xE3, + 0xDA, 0x58, 0x13, 0x05, 0xB1, 0xA0, 0xD0, 0x85, 0x0B, 0x57, 0x92, 0x91, 0x02, 0xEB, 0x1C, 0x72, + 0xBA, 0x24, 0x20, 0x78, 0x92, 0x3C, 0x41, 0xEC, 0x31, 0x50, 0x44, 0xC6, 0x07, 0xAC, 0x92, 0xBC, + 0x0A, 0xC6, 0xC6, 0x50, 0xC1, 0x22, 0xE8, 0x22, 0x59, 0x4E, 0x7F, 0x18, 0x31, 0xEA, 0x66, 0x7D, + 0x0B, 0xFA, 0xE1, 0x57, 0x50, 0x59, 0xDB, 0xC0, 0x7C, 0x85, 0x37, 0xBF, 0x63, 0x6E, 0x97, 0x3B, + 0x82, 0xD1, 0x28, 0x33, 0xC2, 0x93, 0x93, 0x12, 0x02, 0x8E, 0x47, 0x0D, 0x89, 0x57, 0xCA, 0x36, + 0xF2, 0x5A, 0xEC, 0x50, 0x21, 0x60, 0xA9, 0x50, 0x05, 0xF0, 0x1F, 0x84, 0x2A, 0x2A, 0x11, 0x7D, + 0x14, 0x16, 0xE8, 0x66, 0x1F, 0x27, 0x7D, 0x5A, 0x14, 0x46, 0x91, 0x54, 0x0A, 0xE2, 0x91, 0x13, + 0xBA, 0x00, 0xCB, 0x99, 0xD1, 0x65, 0x0F, 0x21, 0x5D, 0x41, 0x86, 0xF9, 0x69, 0x09, 0xB2, 0x8B, + 0xDE, 0x67, 0x57, 0x42, 0x38, 0x6D, 0x82, 0xBF, 0x2E, 0xFE, 0x99, 0x22, 0x4F, 0xE0, 0x63, 0xFC, + 0x8F, 0xFB, 0x52, 0xB5, 0xF2, 0x40, 0x71, 0xE5, 0x0E, 0x92, 0xF1, 0x16, 0x6F, 0x76, 0x25, 0x4E, + 0x62, 0x4F, 0x1A, 0x71, 0x75, 0xD2, 0xCC, 0x17, 0xE5, 0x81, 0x76, 0x93, 0x5D, 0xF0, 0x32, 0xC8, + 0x53, 0x28, 0x5E, 0x26, 0x6C, 0xB9, 0x5B, 0xF7, 0x34, 0x3B, 0xCC, 0xFF, 0x31, 0x3F, 0x5D, 0xBA, + 0x2C, 0xEF, 0x6E, 0xF7, 0xB6, 0x94, 0x0B, 0x97, 0x07, 0x54, 0x41, 0x33, 0x6B, 0x27, 0xEB, 0x41, + 0xFC, 0x33, 0x67, 0x83, 0x4C, 0x3D, 0x26, 0xD5, 0x9D, 0xF9, 0x49, 0x2D, 0x6A, 0x5A, 0xBA, 0x4C, + 0xAA, 0xBA, 0x77, 0xC6, 0xDE, 0x29, 0x45, 0x3A, 0xCF, 0xB1, 0x56, 0x45, 0x6F, 0x5E, 0xD8, 0x28, + 0x57, 0xFB, 0xB3, 0x34, 0x38, 0x86, 0x9B, 0x0B, 0x3B, 0x03, 0x46, 0x5C, 0xCB, 0xD3, 0xB0, 0x77, + 0x0A, 0xA5, 0x63, 0x0A, 0x35, 0x25, 0x65, 0x79, 0xDC, 0x94, 0x01, 0x76, 0xC7, 0x4B, 0x45, 0x0B, + 0x4C, 0x9C, 0xBA, 0xE9, 0x91, 0xD8, 0x97, 0x21, 0x1F, 0xCB, 0xBB, 0x1B, 0x51, 0xF7, 0x4E, 0x31, + 0x25, 0xA5, 0x53, 0x34, 0xBD, 0x87, 0x89, 0x82, 0x91, 0x01, 0x3D, 0x39, 0x23, 0x61, 0x67, 0x97, + 0x51, 0x0A, 0x66, 0xB2, 0x3A, 0x71, 0xD3, 0x1B, 0x72, 0x3E, 0x60, 0xC4, 0xD5, 0x89, 0xBB, 0xB1, + 0x4D, 0x0A, 0x9B, 0x14, 0x18, 0x71, 0x7C, 0xE7, 0x8D, 0x46, 0xBC, 0x21, 0x04, 0xFE, 0xF0, 0x3F, + 0xBA, 0x21, 0x50, 0x4C, 0xEC, 0x31, 0x7A, 0xA3, 0x48, 0x0B, 0x7F, 0xE8, 0x56, 0x0B, 0x22, 0x6F, + 0x8C, 0x80, 0x91, 0xB9, 0x2F, 0x8F, 0xCA, 0x63, 0xA3, 0x9C, 0xF0, 0x86, 0x58, 0xF0, 0x14, 0x98, + 0x52, 0xCB, 0x8B, 0x87, 0x25, 0x66, 0x86, 0x59, 0x8B, 0x32, 0x16, 0x6A, 0x98, 0x9E, 0xA7, 0x8C, + 0x9A, 0xCA, 0x96, 0x3A, 0x9D, 0xFC, 0x11, 0xB3, 0x2F, 0xF9, 0x4D, 0x55, 0xA7, 0xEC, 0x15, 0x44, + 0x63, 0x53, 0xD1, 0x7A, 0x37, 0x0E, 0xA9, 0x9B, 0x68, 0x75, 0x95, 0xBA, 0x35, 0xC7, 0xE6, 0xF8, + 0x82, 0x08, 0x3A, 0xF9, 0x6B, 0xD3, 0xB3, 0x66, 0xBA, 0x53, 0x59, 0xC5, 0x52, 0xAB, 0x40, 0xF7, + 0x1A, 0xB7, 0x44, 0xE8, 0x93, 0x23, 0x60, 0xF3, 0x89, 0x3F, 0x28, 0x70, 0xB1, 0x7E, 0xA2, 0xCC, + 0x93, 0xE2, 0xA3, 0x3F, 0xCE, 0x61, 0xA3, 0x37, 0xC6, 0x4F, 0xEC, 0x62, 0x8D, 0x3C, 0x91, 0x31, + 0x91, 0x55, 0x31, 0x88, 0x91, 0xA7, 0xB6, 0xD9, 0x24, 0x43, 0x70, 0xDC, 0xC8, 0x66, 0xE1, 0x29, + 0x32, 0x0B, 0xB0, 0xF1, 0x8A, 0xE0, 0x1E, 0xF3, 0x8D, 0xC6, 0xE2, 0x06, 0xA7, 0x89, 0x8F, 0x84, + 0xFF, 0xB3, 0x17, 0xD2, 0x02, 0x34, 0xA2, 0x3C, 0x96, 0x9E, 0x30, 0x8F, 0xC4, 0x12, 0xB3, 0x7C, + 0xEB, 0x9C, 0x80, 0x9E, 0x03, 0x7E, 0xCF, 0x33, 0x25, 0xDC, 0x5A, 0x1C, 0x2D, 0x43, 0x5A, 0x34, + 0x91, 0x03, 0xFE, 0xA1, 0xEA, 0xFF, 0x9A, 0x1F, 0x23, 0xAA, 0xD3, 0x12, 0x74, 0x58, 0x8E, 0x04, + 0x1D, 0xDD, 0xD7, 0x48, 0xDE, 0x94, 0x39, 0xEE, 0x8C, 0x49, 0x5D, 0xA4, 0x6F, 0x4E, 0x9E, 0x27, + 0x66, 0x4A, 0x81, 0xBD, 0x34, 0xA7, 0x26, 0xA8, 0x18, 0x25, 0xAC, 0x95, 0x06, 0x1B, 0x83, 0x1B, + 0x7F, 0x9C, 0x0C, 0xF5, 0xA6, 0xB0, 0xD2, 0xB4, 0x41, 0x23, 0x1B, 0x8D, 0x8B, 0xA1, 0xA4, 0x9E, + 0x7C, 0x32, 0xE0, 0xF1, 0x6D, 0x4F, 0x69, 0xB7, 0x2C, 0xC1, 0x4E, 0x31, 0x6E, 0xA4, 0xD7, 0x72, + 0xB9, 0x5C, 0xAA, 0x8B, 0x86, 0x02, 0xC8, 0x47, 0x38, 0xB2, 0x63, 0x7F, 0x6E, 0x5A, 0xAA, 0xA1, + 0x7B, 0x50, 0xF0, 0x06, 0xC1, 0x6E, 0x54, 0xBC, 0xAA, 0x6E, 0x2A, 0x65, 0x16, 0x09, 0x07, 0x8F, + 0xF8, 0x3A, 0x0A, 0x35, 0x0F, 0xC8, 0x67, 0xD8, 0x05, 0xA0, 0x68, 0xEC, 0x8A, 0x7F, 0x48, 0x9A, + 0x77, 0x6C, 0xE8, 0x96, 0x3D, 0x80, 0x09, 0xA8, 0xD4, 0xD9, 0x11, 0x93, 0xEC, 0xC4, 0x98, 0xF8, + 0xC7, 0xE8, 0x62, 0x72, 0xAA, 0x1B, 0x83, 0xDD, 0x98, 0x00, 0x25, 0x4D, 0x57, 0x0C, 0xA5, 0xEE, + 0x87, 0x8B, 0x3A, 0xC0, 0x14, 0xC6, 0x73, 0x80, 0xF1, 0x79, 0x7E, 0x30, 0x02, 0x52, 0x10, 0x44, + 0x38, 0x67, 0x29, 0xB4, 0x8E, 0xC3, 0xFE, 0xD9, 0x42, 0x0E, 0xF3, 0xE3, 0x49, 0x33, 0xDA, 0xFA, + 0x3F, 0xA6, 0xC0, 0xF2, 0xC5, 0x21, 0x52, 0xA1, 0x30, 0x96, 0x36, 0xCB, 0xAA, 0x4E, 0x97, 0xC5, + 0xB7, 0xA7, 0xCE, 0x32, 0xC0, 0x13, 0xA7, 0xDE, 0x98, 0xCE, 0xE3, 0xFC, 0x19, 0x5E, 0x6C, 0xE4, + 0x45, 0x17, 0xA2, 0xC6, 0x06, 0x71, 0x22, 0x8B, 0x7A, 0xAE, 0x19, 0x54, 0x2A, 0x7B, 0xD3, 0x1F, + 0x27, 0x43, 0x35, 0xA3, 0xE0, 0xA8, 0x8A, 0xDD, 0xA2, 0xD9, 0x6B, 0x8A, 0x48, 0x63, 0xAC, 0xD4, + 0xDA, 0x61, 0xAA, 0x00, 0xAA, 0x60, 0xEB, 0x53, 0x48, 0x88, 0xA7, 0xC2, 0x3A, 0x6E, 0x94, 0x0F, + 0x9E, 0x1A, 0x20, 0x57, 0x90, 0xEA, 0x22, 0xA8, 0xEE, 0xA8, 0xEA, 0x8A, 0xE0, 0x1F, 0xFA, 0xB0, + 0x89, 0x01, 0x1A, 0xFD, 0xE3, 0x0D, 0xCD, 0x02, 0x44, 0x70, 0xC6, 0x88, 0x22, 0x62, 0x13, 0x82, + 0xB1, 0xF0, 0xB5, 0x78, 0xA8, 0x97, 0x0D, 0x40, 0xF1, 0x71, 0xC1, 0xCD, 0xF4, 0x00, 0xBB, 0x12, + 0x03, 0x6B, 0xFC, 0xAD, 0x13, 0x62, 0x11, 0xF1, 0xCD, 0x2D, 0x6B, 0xAF, 0x3C, 0x05, 0x50, 0x69, + 0x62, 0x0A, 0xFF, 0x31, 0x50, 0x03, 0xCF, 0x19, 0x8A, 0x32, 0x4A, 0x9C, 0xA5, 0xE1, 0x52, 0xA3, + 0x58, 0xCD, 0x3C, 0x47, 0x62, 0xEC, 0x6B, 0x85, 0xEA, 0xC5, 0x38, 0x3C, 0x53, 0x26, 0xF2, 0x2C, + 0xE7, 0x8C, 0xBA, 0xF8, 0x8F, 0x12, 0x1D, 0x31, 0xE9, 0xC1, 0xB2, 0x8C, 0x50, 0xD9, 0x0C, 0x17, + 0x4B, 0xD7, 0xFC, 0xBC, 0x0B, 0x87, 0xBA, 0xF4, 0x04, 0x3A, 0x4C, 0xA9, 0x8B, 0xEC, 0xF1, 0x2C, + 0xC6, 0x7C, 0xA5, 0x51, 0x95, 0xBD, 0xBF, 0x76, 0xA7, 0x67, 0xC2, 0x09, 0x8A, 0x3B, 0xCA, 0x98, + 0x25, 0x4A, 0x0E, 0x56, 0x3E, 0x04, 0x37, 0xD6, 0x0D, 0x96, 0x13, 0xAD, 0x97, 0x21, 0x73, 0xB8, + 0xF1, 0x16, 0x8B, 0x9D, 0xF3, 0x53, 0x0A, 0x40, 0xD6, 0xC3, 0x8A, 0x66, 0x7F, 0x66, 0xDF, 0x88, + 0x98, 0x9C, 0x62, 0x21, 0x4C, 0x58, 0xD3, 0x7C, 0x22, 0x93, 0xA1, 0x74, 0xA3, 0x0B, 0x3C, 0x4D, + 0x48, 0x6B, 0xC2, 0x8C, 0x4B, 0x39, 0x53, 0x04, 0x16, 0x85, 0x0B, 0x61, 0x93, 0x78, 0x15, 0x4F, + 0xEA, 0x81, 0x3C, 0xD8, 0x2C, 0x5D, 0x8D, 0x78, 0xBA, 0x9F, 0x1E, 0xD1, 0xC8, 0x01, 0xCE, 0xAE, + 0x29, 0xAA, 0x37, 0x6C, 0x7B, 0xC4, 0x9C, 0xAE, 0x29, 0x67, 0xB6, 0x3F, 0x8D, 0x92, 0xC9, 0x8F, + 0x28, 0xA9, 0x48, 0x93, 0x1E, 0xD6, 0x27, 0x31, 0x9D, 0x1E, 0xE2, 0xF4, 0x79, 0x74, 0x53, 0x18, + 0xFF, 0xB3, 0x3F, 0x66, 0x44, 0x89, 0xC9, 0x97, 0x53, 0xD6, 0x9C, 0xF2, 0x6A, 0x4A, 0xC0, 0xFC, + 0xF6, 0x1A, 0x4D, 0x73, 0x91, 0xA3, 0xB2, 0x00, 0x0B, 0x31, 0xB7, 0x82, 0x5D, 0xFF, 0x69, 0x24, + 0xAC, 0x8F, 0x71, 0xD2, 0xA6, 0xA4, 0x6B, 0x6F, 0xE7, 0x7C, 0xE0, 0x04, 0xCB, 0xAC, 0x6F, 0x66, + 0xA6, 0x80, 0xE3, 0x52, 0xC1, 0x00, 0x9C, 0xFB, 0x8C, 0xFB, 0x58, 0xFC, 0xA0, 0xB8, 0xE8, 0x91, + 0x39, 0x6B, 0x8E, 0x1E, 0x4C, 0x2A, 0x5B, 0x10, 0xFB, 0x1B, 0x75, 0x98, 0x19, 0xDF, 0xF2, 0x76, + 0xC6, 0x4D, 0xCC, 0xF7, 0x99, 0x02, 0xE2, 0x16, 0x98, 0x50, 0x1B, 0x4A, 0xF5, 0xB1, 0x04, 0x48, + 0xFC, 0x4C, 0x77, 0x5E, 0x22, 0x06, 0x5D, 0x64, 0xAF, 0x36, 0x19, 0x1A, 0x19, 0xC5, 0xEC, 0x34, + 0x6C, 0x22, 0x5B, 0xF9, 0x00, 0x8B, 0xA7, 0xAB, 0x12, 0xCA, 0x64, 0x09, 0xE6, 0x0C, 0x3D, 0xFA, + 0x12, 0x05, 0xB1, 0x99, 0xDC, 0xCA, 0x07, 0x12, 0x29, 0xA0, 0x4E, 0x73, 0xE0, 0x0A, 0x61, 0xD8, + 0x93, 0x9A, 0x76, 0x7C, 0xDE, 0x21, 0xA3, 0x7C, 0x90, 0x51, 0x71, 0x9B, 0xFF, 0x30, 0x5B, 0x98, + 0x28, 0xF4, 0xF3, 0xF1, 0x33, 0xCA, 0x07, 0xBD, 0x8B, 0x0D, 0x4C, 0x78, 0x27, 0x1F, 0x2D, 0x48, + 0x1C, 0x0B, 0xE1, 0x91, 0x5F, 0x4B, 0xBC, 0x62, 0xDB, 0x52, 0x7B, 0xE8, 0x15, 0x80, 0x6B, 0xBD, + 0x25, 0x71, 0x22, 0xCB, 0x76, 0xA1, 0x7B, 0x08, 0xBE, 0x1F, 0x99, 0xB5, 0x7B, 0xBA, 0xAE, 0xF4, + 0x9F, 0x47, 0x68, 0x7C, 0x44, 0x45, 0x4B, 0xBA, 0x8F, 0xDF, 0xA8, 0x8C, 0xA0, 0xBB, 0x33, 0xAF, + 0x44, 0x5D, 0x1E, 0xD8, 0x54, 0x7C, 0x35, 0x3B, 0x28, 0x30, 0x16, 0x69, 0xAD, 0x12, 0x49, 0xE8, + 0xA8, 0xFD, 0xE2, 0x97, 0x71, 0xBF, 0xF0, 0x24, 0x7E, 0x53, 0x59, 0x39, 0xFC, 0x93, 0xF8, 0xC7, + 0x2E, 0x95, 0xC3, 0x2B, 0xF5, 0x22, 0x7F, 0x06, 0xB7, 0x6C, 0xCD, 0xED, 0x92, 0x54, 0xF0, 0x3C, + 0xBF, 0xBF, 0xE4, 0x71, 0xDC, 0x76, 0x25, 0x76, 0xC3, 0x69, 0x2E, 0xDA, 0x61, 0xF7, 0xB6, 0x7F, + 0xC6, 0xD0, 0xD7, 0x69, 0xE7, 0x57, 0x32, 0x3B, 0xF9, 0x18, 0x8E, 0x3D, 0xAC, 0xF6, 0x71, 0xBB, + 0x42, 0x9E, 0xFF, 0xD9, 0x7B, 0x0C, 0xEF, 0x5A, 0x5E, 0x89, 0xFA, 0x7C, 0xAE, 0xA8, 0x47, 0xFD, + 0x4B, 0x8C, 0x4A, 0x04, 0xDF, 0xD5, 0x2A, 0xF9, 0xA0, 0x5B, 0x88, 0x2C, 0xC0, 0xCB, 0x41, 0x4D, + 0xAA, 0x7E, 0xE8, 0x6D, 0x3A, 0x54, 0x34, 0x62, 0x53, 0x73, 0xFD, 0x27, 0x46, 0xBE, 0x5F, 0xF7, + 0x7F, 0xBA, 0xE6, 0xEF, 0x33, 0x3F, 0x40, 0x15, 0xC6, 0xFD, 0x5D, 0x33, 0x82, 0xEF, 0x50, 0xA0, + 0xFD, 0x9E, 0xCF, 0x2F, 0x0F, 0xE0, 0x6E, 0x38, 0xBA, 0x35, 0x5C, 0x50, 0xF5, 0x4F, 0x2B, 0x76, + 0x9D, 0x1C, 0x88, 0xFA, 0xD1, 0x6F, 0x3D, 0x99, 0x78, 0xD7, 0xA5, 0x81, 0x50, 0xB8, 0x0F, 0x04, + 0x3B, 0xCE, 0x9E, 0x3D, 0xFD, 0xBA, 0x82, 0x77, 0xD1, 0xA8, 0x0F, 0x35, 0xA8, 0x55, 0xF5, 0x23, + 0x63, 0x1F, 0x91, 0x96, 0x28, 0x37, 0xA7, 0x26, 0xF9, 0xA0, 0x3B, 0x88, 0xB6, 0x46, 0x5F, 0x78, + 0x16, 0x27, 0x10, 0xF6, 0xF1, 0xDB, 0xD0, 0xB3, 0xB5, 0x45, 0xEF, 0xBD, 0x3F, 0xBD, 0x68, 0xE7, + 0xE3, 0x21, 0x28, 0x9A, 0x48, 0x5B, 0x61, 0x08, 0xC1, 0x07, 0x50, 0x3B, 0xCD, 0xF7, 0xFB, 0xDA, + 0xD7, 0xF1, 0xBB, 0xC6, 0x6F, 0x9B, 0x7D, 0xE6, 0xF4, 0x8D, 0x6B, 0x6E, 0xA8, 0xEA, 0x6B, 0x6C, + 0x87, 0xA5, 0xA1, 0x3F, 0x6A, 0x91, 0x89, 0x3B, 0xE1, 0xAA, 0xFE, 0xCC, 0xFD, 0xF7, 0xB0, 0xBD, + 0x9F, 0x10, 0x99, 0xD8, 0x95, 0xA2, 0x9B, 0x86, 0x3A, 0x3F, 0xDB, 0x10, 0xA5, 0x86, 0xD9, 0x86, + 0xC5, 0xD7, 0x8A, 0xC2, 0x21, 0x9C, 0x40, 0x6C, 0x82, 0xB0, 0xAD, 0xC2, 0x05, 0x1B, 0x48, 0x3E, + 0xE8, 0x0E, 0xA2, 0xAE, 0x03, 0xE1, 0x89, 0x7D, 0xD0, 0xA1, 0x7D, 0x64, 0x97, 0x84, 0x71, 0xF7, + 0x46, 0x75, 0xE8, 0x92, 0xCB, 0x0F, 0x5C, 0x10, 0xAA, 0xD5, 0xC4, 0x41, 0x4D, 0xC7, 0x42, 0xBC, + 0x56, 0xF6, 0xE3, 0xAB, 0x0B, 0xC1, 0xDB, 0xEA, 0x03, 0x6F, 0xAE, 0xA1, 0x3A, 0xD5, 0xDC, 0xFA, + 0x17, 0x1E, 0x1C, 0xEB, 0x9F, 0xEB, 0x7B, 0xEF, 0x49, 0xFF, 0xE5, 0x4B, 0x58, 0x65, 0xEB, 0xAE, + 0x8E, 0x9B, 0xEF, 0xBF, 0x87, 0x3C, 0x02, 0xE5, 0xFE, 0xCF, 0x5C, 0x1F, 0x37, 0x33, 0x36, 0x6C, + 0x76, 0xC1, 0xD9, 0xB3, 0x67, 0x21, 0x1C, 0xF5, 0xB0, 0x75, 0x0E, 0x5C, 0xEF, 0x70, 0xEA, 0xC6, + 0x23, 0x1B, 0xF0, 0xE9, 0x0D, 0xC9, 0x07, 0xDD, 0x80, 0x2B, 0x7A, 0xC5, 0x87, 0x17, 0xDC, 0x8C, + 0xE3, 0x47, 0x6D, 0x04, 0x19, 0x9A, 0x3D, 0x27, 0x84, 0x9A, 0x15, 0x13, 0x46, 0x78, 0x15, 0x88, + 0xD3, 0x33, 0xDF, 0x7B, 0x62, 0xAC, 0xFF, 0xB2, 0x4E, 0xCE, 0x13, 0xDC, 0x1D, 0x9E, 0xD3, 0xC2, + 0xAA, 0xD9, 0x77, 0x34, 0x70, 0xBA, 0xEE, 0xF1, 0x5F, 0xDD, 0x15, 0x28, 0xDB, 0xC4, 0x42, 0x75, + 0x97, 0x5A, 0xC1, 0x9B, 0x07, 0x6C, 0x17, 0x4C, 0x5C, 0xD3, 0x05, 0xE6, 0xC1, 0x19, 0x15, 0xF7, + 0xC9, 0x44, 0xC1, 0x4D, 0x5B, 0x28, 0x8A, 0xA1, 0xA9, 0x89, 0x2D, 0x3D, 0x16, 0x51, 0x2B, 0xA1, + 0x83, 0xD8, 0x40, 0xF6, 0x0F, 0xBA, 0x8F, 0x96, 0x76, 0xA8, 0x3B, 0x60, 0x2C, 0x2C, 0x7A, 0x71, + 0xEF, 0x4A, 0x1D, 0xD4, 0xBD, 0xB7, 0xA7, 0x11, 0xAA, 0x9B, 0xF5, 0x89, 0x25, 0xDA, 0x93, 0x03, + 0xB4, 0x87, 0x86, 0xDF, 0xD2, 0x2E, 0xA8, 0x33, 0xB8, 0x83, 0x52, 0x77, 0x9B, 0x0E, 0xF5, 0xF6, + 0x15, 0x1D, 0x7A, 0xE0, 0x2E, 0xD8, 0xD7, 0xC8, 0xBA, 0x87, 0xE8, 0x3A, 0xC8, 0x5C, 0xBE, 0x3F, + 0xFD, 0x48, 0xDB, 0x46, 0x58, 0xD9, 0x2F, 0xD9, 0x49, 0xF6, 0x0A, 0x37, 0x4A, 0xA9, 0x48, 0xB4, + 0x33, 0xCA, 0xF6, 0x23, 0x5F, 0xE9, 0x19, 0x8C, 0x9C, 0x70, 0x12, 0x06, 0x7F, 0xD6, 0xCC, 0x07, + 0x8C, 0x0D, 0x64, 0xFF, 0xA0, 0xDB, 0x88, 0x1E, 0x00, 0x3C, 0x0E, 0xD1, 0xE4, 0x31, 0xE1, 0xCA, + 0xD9, 0xD7, 0x8D, 0xF9, 0xF4, 0xD5, 0x93, 0x86, 0x8E, 0xA9, 0x9C, 0x3D, 0x7C, 0x8C, 0x50, 0x3C, + 0xF2, 0xAD, 0xC0, 0xCF, 0x39, 0x78, 0xC3, 0x77, 0x07, 0xB2, 0xBD, 0x54, 0x7C, 0xBF, 0x16, 0x98, + 0xDD, 0xA2, 0x7F, 0xF0, 0xF6, 0x2A, 0x64, 0xA3, 0xA5, 0xE8, 0x55, 0xD3, 0xBC, 0xA0, 0x6A, 0xD0, + 0x09, 0xDA, 0x2E, 0x45, 0x5B, 0xA2, 0x28, 0x68, 0xE1, 0x31, 0xD1, 0xCB, 0xDC, 0xF5, 0x71, 0xB2, + 0x03, 0x7D, 0xEF, 0xB7, 0x87, 0xB9, 0x82, 0xED, 0x9D, 0x43, 0xD6, 0x30, 0x7D, 0x64, 0xD7, 0x35, + 0x5E, 0x6A, 0x61, 0x86, 0x5C, 0x6F, 0xAE, 0x6F, 0x13, 0x1B, 0xC8, 0xF9, 0x83, 0xEE, 0xC0, 0x75, + 0x73, 0xF8, 0x39, 0x85, 0x14, 0x78, 0xF7, 0xF1, 0x81, 0xE3, 0x59, 0x2D, 0xC0, 0xBA, 0x04, 0xB9, + 0x10, 0x70, 0xC3, 0xF7, 0xBD, 0xF7, 0xC1, 0x9A, 0xB1, 0xD0, 0xDF, 0xE3, 0xFB, 0xFD, 0xDC, 0x87, + 0x71, 0x07, 0x95, 0xD9, 0x2D, 0xA2, 0xB9, 0x57, 0x3F, 0x0C, 0xF7, 0x8E, 0x41, 0x2F, 0xE5, 0xC1, + 0xB2, 0xC3, 0x80, 0x3D, 0x4B, 0xE6, 0xE2, 0x61, 0xFB, 0xC6, 0x5F, 0x0B, 0xD8, 0x3F, 0x80, 0xA2, + 0xFD, 0xC9, 0xF6, 0x13, 0x47, 0x1E, 0xFB, 0x96, 0x6B, 0x1D, 0x2C, 0x42, 0xB5, 0x74, 0x9A, 0x48, + 0x2A, 0x69, 0xBF, 0xE6, 0xEF, 0x07, 0x61, 0xDC, 0xF9, 0x2E, 0x53, 0x73, 0x25, 0xD8, 0x80, 0xF7, + 0x0F, 0xE2, 0xAF, 0x3B, 0x4B, 0x74, 0x81, 0xBA, 0xCA, 0x48, 0x2B, 0xF4, 0x65, 0x1B, 0xC0, 0xAA, + 0x67, 0xD5, 0x54, 0xC4, 0x8B, 0xC6, 0x8C, 0x16, 0x57, 0x5D, 0xF3, 0x7E, 0xB2, 0x15, 0xD8, 0x7D, + 0x88, 0x1A, 0x3D, 0xC6, 0x9A, 0x00, 0xC6, 0x06, 0x88, 0x76, 0xAE, 0xD1, 0x10, 0xCB, 0x06, 0x14, + 0xDB, 0xBE, 0xEE, 0x2C, 0x91, 0x12, 0xDC, 0x25, 0xA4, 0x78, 0xB5, 0x13, 0x66, 0x75, 0x19, 0x73, + 0xCE, 0x8A, 0x72, 0xE5, 0x41, 0xD6, 0x1B, 0xEC, 0x39, 0xE8, 0x76, 0xB0, 0x18, 0xEC, 0xDD, 0x56, + 0x9D, 0x0D, 0xDE, 0x61, 0x02, 0x41, 0xF2, 0x41, 0x37, 0x10, 0x65, 0x3D, 0x00, 0xE4, 0x82, 0xAE, + 0x19, 0xE1, 0x9B, 0xDF, 0xEC, 0x32, 0x4A, 0x8F, 0xC2, 0x60, 0x03, 0x7E, 0x2F, 0xF9, 0x20, 0x6D, + 0x78, 0x0A, 0x78, 0x8D, 0xD1, 0xC4, 0x06, 0xB2, 0x7F, 0xD0, 0x33, 0xE8, 0x51, 0xAB, 0x94, 0x1C, + 0x29, 0xD7, 0xA8, 0xEC, 0x1F, 0x64, 0x1F, 0x85, 0xF1, 0x99, 0xC9, 0xF9, 0x03, 0x09, 0x82, 0x27, + 0x0F, 0x4F, 0x62, 0x92, 0xE8, 0x79, 0x28, 0xCC, 0xC6, 0xB6, 0x44, 0x6F, 0xC7, 0xFF, 0x0F, 0xFF, + 0x9B, 0xA5, 0xD3, 0x1C, 0xD5, 0x77, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, + 0x42, 0x60, 0x82 +}; + + +const xFileToCopy_t xHTTPFilesToCopy[] = +{ + { "freertos.html", sizeof( pcFreeRTOS_HTML_Data ), pcFreeRTOS_HTML_Data }, + { "logo.jpg", sizeof( pcLogo_JPG_Data ), pcLogo_JPG_Data }, + { "ftp.png", sizeof( pcFTP_PNG_Data ), pcFTP_PNG_Data } +}; + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/HTML_for_default_web_pages/ftp.png b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/HTML_for_default_web_pages/ftp.png new file mode 100644 index 0000000000000000000000000000000000000000..7ff2d183fa1b7cd44aeb8dedef542c7944e6fc35 GIT binary patch literal 32467 zcmV)(K#RYLP)q08u#rW-u;ME--Qtcn~LfE-+M4Hd1^!W@c3Y z0961jRW1NfFDqsM0A>I=ZZiOKF)vjBQA{y(W&mb)E>UnZbyh$&T6HjZRRCs2IAvrd zKtMo8U3*P@NmX@mYFJQgXH{=+asUR80TZwQIgb=Bq&Yc{CON1C9MS+(kPuY10A;i? zPK+~Ct~Y9pFmbXUU%(7?&<=3(HBQtpZOb%!<4`|0 zfns*FN_ER1 zH2f$n!bDnzDNn39V6i(=h)-UZW=XY1ZH-uRl5T3OPHwSiPs}w?>jq2oGv$?mG{+qM4w)02+drIgIIujq}7;jEhHtf|tv#n{)6$i=(F($!+{^Z@*004WANklM11vAkphl=>cE2iAWSW-T@Clu)9vxO-tBL1U_%45WdJrFgYcj60l*4d z&;zU>6P359`$;unpi70X2A~q~0yUL2!AUhWco#+h@<2@`{-FnP2f7mS1y()-x`Yqi z8sS(@D*o8BW-2}k5pG*7WP&I}!8Ls+UIAwAj?UZ-(_K69A7JOqojjHULkJGg*g$vM z;{ov6XKb)x{>Gbt{cQxi-fZLsb7$jI%0AD$o^glr7uBz`0po(qaDx)?1yLT@_}~HY z>&OTm{O(x=b6^Ey4Tm`sRH6q}co^?0InY6W6jl5%IC272Kf5wcaFPbVO3IcoEJgO8 z@OwfQ&|D}EW>)JGVft=<5w%bJ5Gxr>oB&4sTR8!FU<0PYxXpFb2K*zgKu*A`^72jS zz^g;nSk^UXSMosT0bunnSU~55k=EE1b+-FAV`99C@}Ty1ArA=m@Sn%=f5ih_cCyUa zvxF?bxqv?L8mey(eeHBZJb{e^yTv-+r?UY?q9%el4bHGL14#kK0mKiC4LD1f*@5JN z?Q`O6z?%c%(%J?i9#s(ix}wMhyQ@hUxT;;#fr*2iE))aE3+S4OTwsw1toG?2tGxs7 z@m~`MRyNqcQo+9{aRmOmkQXQf<-yB0p-fQVCPhWTVEfiN2MY-x7{N)PF&01$ASS>& zjSYw^41r+j_1DJUJNY1-`-u;cKXL-lpOp=Waqu6j(SwyvBA^Dl1T~&Yyr(*@#8!ec zL`@|Mi5lbuVi2IFfp~?U!04S>C*B$deZbo1Rgd+qHxGaek+@m#`vnq3GWY=H#p917$laGXV9ME#Juo{EK)g2bAYPA9 z&?nH<@*#8_473CSFW>|Ox&k{I!dS&;-~NXh&*gy~fi1)rp@TaDJN^ihE(z?|@dDIb zf_MMH*n=1V|HyyG+yA`dRkxOdvsdqU1O2vKy5qmO2i89a;}9(xt8MlXiCb2%#0X4I z=yHIUtMyHzyQjN|4eI>Z%)1O1Uyu*BPd zRFMNVY@9zIB|?-qVIz8B-$1=d1#A*j{Ckui-a(h#6SjRPRg%(7o0y zu$z>?dBV&Y1|NJ0{!@2jlTh*DJ6`Ay?;;-^fjT(p_csjrF@?4Jr#B2kS740ae;d?< zUG4s94TFFD$%EUx0q`tb)7JOlK7Xu4zG(N)Y#8>8XHDDOhU>pKlYVA=k4XY94glIN zyzrv`x$tTuGp}BF;XfRQ)>kk5JikZDK*E58gh?LoR>AT;2@#6IfSg+Ez=QO6n&~2G zuoEj9TL$C^>>=zHm`=R{lnlrUtYNVB5AdsJZG+ZLGzkO~s4sy3QJ5dyfGq-+>`mBG zxUf;6d~8HHfFeOvkRuoq+wzZpy!%UxEE)uBqX0r4u#caygy4%V!~p>Nlmq68;{YHF z`0+>gVSFI??qBY?hXLRWsCDBm1-9=LuK}b;j7KAvUx;OO;SaF-;VfF7s2B2O7ih@~DO&-id zo}k{r%$Yk~C<#y^phz$t!`jBKp=c8rBk1D5(k@_!0P7uF1#BNSMCWg~i3Gz<*e$?z zL4}*KNq8AW1AX?4i7oPgyoim7b&(4=AICHb!1@Hu^w0j#k6qFb2*?N)HsE}qKqO+0 z6mq;E!%_J5v zQo$d?uB)3m5BLQAMWD|Ptx@o;Zo2Sp*NbQSefo#+dm|r3mtOe~4MP|5_Cfdw32N=M zaB0fh0lrXE(BH}oCJ{&qa7lo7 zOgQkrRDnETSy>Y8g4>OZ@aW@@K7Ja10G0#K#2LI^P~P?}bWYjsZF`u-ok_0!L$)lEDQr+*-Ny}P4P_UD@Js^;AT>@n`d zE+X;*b`g*TcIq<;0<8Ags1e(Q4)*IH4;XdUMVP-~1C0)_dw|0Q8aCc^vx>dMmyrdq zgK#r%vh4jEt$)B;1@SW07hp{QlLow(!21bli38y6g6Uqg3z5j35Ohb}-x&yx;t$Rr zu*~$w>kIHaih~Q@@dhT7Sb(o%KLA}G*#9(KOw$JBaa}c^8rb(a?~9YZNAka>@{+f_ zFc}NkEe40|rv|oRuiy#1u}C0jy70ma=dxD8)B;?(qUp*u=XR(x+ub+gM=S*{9+3mZBwn{#w52>p}j5 zo<{!wxQIaf-({gMVrOA60RFtKSNf*VpuY`ac@(_S%Kr48fB=`Qyl+LJhJ92S=?E-ZXxlq7%fi(%%Sru04)F^07!Pd5zZYbFFS}TVp%cq!KH#jyT(3zE)mcrrVr4;LJ}f&`hX7}%tHtb+4bC^yl=Gw-no`6iCk7D9Ov1$`6q8wa;?szH zy@?GN&h~39MSoUU{Id}df`Iw*CP4@U;1?6btS>D#O{c|$=?L9inlI$vOicCTcTC z+8TqHM~IL>7-^j?yuHqLkMqhgK9+f9{LbK`X9mv?KZA~_$dNrC8a!dX#z<~HpIA|+ zO&F68O)0WD#V}uEU{ld-wTVq1(9)FiDx|*3c$P0Wi2)=1yO34!hqauRoU!kQm!l{_ z?P3$HIF$@k|2RD|eK(s@WOE0c2e4m&7i=xCk6>P4pkX4LP!^NQf(7`bvPB-?oDp^r zqxe4`=aaFCn9te;{M&fb%`e|f@&K#L zf+Gt6X98*%NFLC<60J827TAarNhB1wFt9^w)dVxdvI>H=3G~AzllZ7nV}R~0Je&9+ zP8;CN4b%(Jxk398i;cq1#0yx}DF2BQJfeGGU30X6YaWn;sU2vm&q5psUWjD{t$8)^ zKx`vRoddq=h%CT*2BLdlk_R>>utM|@_-Z3KFaxrHU0lWbGOVE@1tGbfEKr?jty!3qY;)quXfgFvQeT)V+Xp8O&aUCL9M?9hrnZwR02B zZ;1uU%Cx%$Yv%)r-ig}VrJkw;LGpnFLGpnFA(juShVpr2XCw|y3vc`VtGZ1j25~Z) zMEMJaD>CJd!qG2H$$J7uREVVQ&|zNFLzVB|d&zV5$GIaP`n* zx3-pBzSDbOg~-$oP)^Wu_*qpAIsp?;#6CWBa{m+0kYGUU>!VXq?9;P?~zy*+`*#K9Pb-uw#icF8w~jPgG)j;F*QIz`@(Q^HP6BVN23 zAInBtmB%pgL7*Jl1uQ2B-c}!YbB(2(C=9D?S>P?4D=L1mw88RiPw9kruh5w}oVAK%2U0M*wVyrbjWTh`pQWo?s|>X{+rJ(m);Ow7>xT^1H; z0d#yjuw_jwBcH>tw+p!34|`9H^AAaI%+H;;CtXCd+y=J6C zE8)lI@speT-f48XJyZM>PuxkhS;HQTP_P-_46OBEY6`pHRoHoboVb|5H`ly{8JxCn z3%i~Q+_J9>d<)%u7P>t~szBbATEgbXk;VB7pkjn?A8`V&4Hun0e#!{D=;ViM7sibXmHjN5 zS^mfQ8XuwBNR_;egl&jR`<#apA51CwxntbQ;%8tF6B7~JZ1>DxQ?-ldru}Nv$ouav zawGxtsc{+r)z|rs4yLcJ(lNoR%K&Q5PBVoqy4pdV_tIB2XVqBicy7i>Y!c1rHM+Br1f&1=Mx%rB%SGJk-q^v_3xPWLiWD8FHOTf*|=of*|=o zg5WUwn;4GT?=btFOn7%Oa*30)9PeZRDf0nL&7yY~Nbf0$B#=tGP%BLE`eNYh8_z#c zY%PsAaDFH==pyNJ8#Z~+(F!H)rLkKy%Ym_ANjoa z!mEd$^?)ZxW>kGJXz)Ix!Y`gT2o3@$?i+vSAP+ux@4c(y%Y#j~tX^hHx}!LR5C25@ zDhd}+!~C&|zoSkQt|NU#b*XS*yQ$*qa0luBQk(5afMch>qQaM5D<|Ft)%LItnE8WF z_~FC2rN|Tgz_b~+h!-pXijN%=w)@m`rDb2*?fn_ z2NRFc8?@7|`}o_OIarnTMQaxT10#5TgG>9uU4u)b$H5myF2IjS@#q!)ASfTZXj9j1 zU#K5%mItm6$`PSWXI}WFoe}o_5iKMrs@e`efNNhdlJ-IqZrz^udMUC&B#d0g0%*^e zXK3H(@6NBRGg}SVuZD|4>eqSB1-#Ew>RQFvFSz=AMAfY#Z(qN4=sJ|DdZpYcA>nXZFKQj1vYfF zfSOR0F?q1R?8LZ(P?lPrQ*hZ~v)`Og1SE4r0~Bl`Z_^ua zgYNI~j9wdU`bhoHvfrRqmWI09Rkd*_ocyx#Y(@Sz4H_SG6qiR`?~ggkZq9buKY)p@ z{_x2t3~cj9^%ft$h4=fx$kIcfjM7F;>M^j`hrnBXk$U3v3jqJx`FGZ95b_`hYKN~Q z3U4a^aJbSc531V~_hn&MY4oDE!7JE+h!usJH!Kf&7P*5S{3eUVLnOlvj2`NS>f6C= z)y5mb7j(y%4(dR@8T~MP`Hj5`K;3Q&^uX7O$hgDcuPK9zkD+N74TsKW+YJ4#P+&{g zAnCrRZc@8%$Vc9*qC?-EqkDf|4Sxtlo$d8wzC2pk0nB6Q@_-BrPHe(@!D1wlA0JE} zv^16-9}ev$e-E71TYNMU5N&piEFMd@STS0Khl_pz!Du5y=EIE;tYH<-<-xQ5KxwQ0 zl{?|)pJ*Sp1~*)EKl_XxzeweF+88l!#HB8!41jOn`BCT)kGW9oMWwzvslU`4R8;J^ z{eKIdp9wAQ!=KcBJL=ZMv+l@OcD=8zzY>lASrLYNM;?Qb$2!i#n^DHdx+AQ3*xqCx zb_Gm|IPM7}wx5_%48tqlZ8P*D>Ov=nhTz#RhZG2ZkpF!}jSrg2qsO3abhCoHomG=O zV51}JY8>w$^pEzBxcco-&U`|b2d(`fy78;fG=#tP(ep%wyVPeNP}~YkQ2?*|P4b{W z!_48&kMD2qA6y*rw$@KZ$ITnQjJ2XC?F&x9|4tVKCk1`uw1-9?hVNALhco>vU!D!7 z205gt`}_UQw{!GnywMn;qi$*w>QAZf?pNT;F>HYN3)>q%kE>Mad{Bz6FfsyD(1{w1 z5NZFF_ml6Gzya*b7$)p)^SptgY07_3LsmTYp=s=!pV0VVWCOOPeU86$3!v4R;YN4> z8Ns%u%f}1tE!a5#*J&7`%Y(D$!Bm{`D>+3U62M@s!uu<`yeONac%hU`{ev?Ke$c+Q z4Wnb&0B!;0*O(aq_tFp7-68mZbI-A6=)10MN$t%+ul88+aQNx0neTo6H&by88*bG3 z06B8v9um#h} z`wxt|`l~yX;AiaIR5{hH}5{PV&l{mV}*tUCYbp!RVV8mb=c8_Y3za8|Gf4H;jL{-EzlYFJ{}09yYoe0sp*k)Qu*L_MQ-{MdNmF8Aus1Y&NAW2bJj*oMh>UP>9LkDYH#l#ln#Kt1 z#kmUWl+=`3B@lIwt2;Q(I+^IZ@b9m9uCsX6oxBIuHgy(5bj(-Fj?aJJF`Ybu#s|k> z@W(CQE6-;)G1D#<=;H}ZT%sl8iz`dy|?1?H{r~pd9)tJ z&SO>4$AjT?^%zs#RS*BG0>PWqI6LYdVG`}uj|N8EAu}U*`$S**KJrFeor$TM&I@@x zgRv)KA<^+DxK@39yf1|Bcd2FH%KIqvw_Kj5Ptq++nWE; zg9kvG_c1Zu+~5l;>R-`0#!((jMH@ivP{K9j zwGInLi-ek>^T8RP?zkQa8uJJG1muBc4CD8m@#pSeXj|V2WK}dANh}e-PH+EY`?XK;;fra-9Kv= z{@e(^1E`&4_!qzYd9uW~-l==w!4Xpvw2bXMRf;)|XeAU4DQ>Y?P_ZAU613?3LM}S} zE4tC52>;KO(Isn&&{*)eTRh)gT|!oa^BUS)4hXeCi+BI+-}&j$^*?=qPn^X8lLy$; zyS}*gV(KmF@*o_<{smuM0O(h8oJkc{#nfZy=jkZM+S26#4H-SdAGxv9nGFDTkriHh z(nTSUdSB4@#DgP!`zD6QaqdIlz%eE^0S9cmy`L-b-1z$<6B|GU?5w@=4QG7@ng<;W zr5&D<;&z-P(V76o8wwwe@(#nqx`X=iQ_FBH;e2)}Sj+Q$<4#DDN#{UKUtbVfy=;eH60+-P4X_P!Bs%N2X~VqyTlsez=%t>RX( zP*G8*7myl8`8UqoW8l!I4Dx>NfS}JG@PF&U1J1zGub>)ewpO8;1xyvoT^0s0#ZJTq z5X%U$NjN=bMKQ0-7dMqjTos(l=52J`=mPmEObk*4x84?4ivKlRvJ8gUSh zSVoXI>2n+@?`zAZ@>Ul)iIa41uD%Sxvac;Ud9T%wcc z-C%qm1#Yj0+}9>SkbEFPNPSQVyR0EYTRpOwMH@1bMl4y(q79kJanABzXOXXmJQ#csdlZFZp4HWg;yO%MMVS_&Umq%?tW%V`S&(9E>`E7f zcP0iN0^(?{IsXthr>V;W*A}aLJdd4J)lFlMZ~u=@b<%MPir(CPMkqL- zdG5`hEC|Mpo6{IR;D=byK^5${jjFy52Xf3fEl9onU#kJGdhls-f0Zc}E8jhG7+O6f z9s-|vLh&8&po@7td^ z1ctxccZ9NhwGk2m{KqGzIc$nf1v3VPS>AZI>GHaE9tkT^c5nzg$0R1dJq*k#=ELr5 z@PRmrf*oQ}MF&;5?Z<8C*fmgWbU9m$JD`+OxcFa-u(lce_pJ|1YEYxY4#VCS^+!`1 zTK?bhz=RLf_MgSkB#nb=%0jDt=*AFsa)&riL!7R0H1@m@!aP;odLz`fsM}s@8UKK~ z=~}35M|bG*Kftb06N6RTR((kiVGp$3)Tn-^o1gP@AA4BdSjp|6%lYCwk}y9O1mB^* zIL9QncfN5m|v=H`yyL9ZKucneW zI|Ak4J205#Z6swo$cpa=>xVq@=)941dI=s2g88rE=a|G6Y0rV>^aF?URGj+H{Xrw8*BMp(Abu;NR29!ZYCa_SUdFEBcaV$Y<*{DchL zOyty??ou>iXu^IL(PAP+}Vn?LAaSd#ptZ~Y}Ja((TlUsz;HDTPg75)<|x_??Y%Nsje zWCbfeaUKaB974x}fOd{aj{67TcB{2 z(AecrS?#^-E6ZVam5NOU{(%1gO6KB2hBXcU@5X>~$h4b2A$~Xa0Tf<+C=1K4p8GKP z{#y^i^E9Bpo@L4_#S>#hm>v{fpOjc{va$aw`U_& z;0Ys`H#}PeF8c9!D!w2;kA#;fwXwbpb008rpF2>F?B?E**H^B+J)7$bDQZnSql+wV z|9Z8>u3fi~i5zFONNup?*S!23wCF46%~2Ft%SiPtnPY<_ppDJ)>2Qy@$CVg-kT==Q zT1FOin?g#+$HQIX=1HzE^fIspq1I#%mqYS_1R;g)Yfb*Ew--PbEy!7ZV-ilD4+>zj zOQG$@$w_`mH_@7KYI>>#@TnErewnuo(>p(Y>}l9Fob(l2pZ`R#N`3Vj)DksqI|xJDmB*OEAO>!G_ypU3 zKsyc`^^hgffo&&C_6qjWKZk3JlqJ>C3ZW={>7VtFdDb7`U9^M`feC-~pnCD8^~f{$ zxnI)3w;e$3@OrM*ih(l*oMHP9XvaZnIgp4Czl{;H#|Ndie}MgiJzn>5u@R#5c6~?0 z#kU>Wh}z_VaqsAA!fmE)2SrnVBeoiuP-8wqRib+!Ca^F<76ome7uk=0{RA8{{1X5B z{F-^-o&lJ8%?vNJ_7iNtwiuYU9dyDC3+{$i>_y!+$Ls^;6jQD#$#=WD%#U9Z&;-stIZf z9>lj;ZJAD%3kZfQJrF%8J}~{XiB4Ra?PW)jp&9R~Byyb~1?`#k&xmKYv666u!XA05 z61^>SV-m4?=yVdIyXD&rV2zu>89?+80uv6Y?R%5prldi(FoNTEB_(gH%TLK7m8ZIn zySd~fcWlRHv9<8CL+aLRaQ<`M@~(SOmR^ibCtqPd@Q(XxZ|U`b|20^*yXbDV-b1cI zCL>a?aL>x=4q3e@6xgu4X|;38#W*0R-O1_7_+o>gbK-&7kbNP zZF$U~!;6hY({is{>@rf#0pgr{DB6XmU^a>jA+5H}CKuhbOg~-Hs6O4;;z?0*8|}i` z@;F>y7eHfE6(_yc0kiR<1J*M=U z$dWnLo`oszn#r6_g$&~vCqFq24$Qv5+ ze2P)VANKANVF^GrLQ!EZXrHu=dO2KG4I&qB19#DxA zJj}>EN+qF>8%>e%ZZ-K~(HMEr-cpnFM2GbUShBp06}c~_ZVJUSQq2LJ`v+NEXX;60 zXaTA#G8whBl`GigLAKYKdJ<=^>oy5OS7dtF(pFaB+&?%+bQ0kJ)bawPUlA%v^6`9;3AL%PoRh3OI40+znC#FxF?gT%vu1^?>> zfBm1sJkJKL77-BAw`Ae|8|EzKxwb4?iA5xQ$@@?N@5tI_sJX(+Q{&52j6A-tu~3Bs zNmODs{W-U292cug&7{(qhYA4MwI!pq>q$i0Piat+PDH);g1&Ag%3iqI^w8 zUuzMmApLDP6Hnf+(S!I%`>=<36mp=av4BJ2EJv@g2_2f^K^Kc!F4lH%9RS}#i%@*P zSX$ysL>QSZ42hW?BuI+~EYAilzTAPoB25b6PLXS*YAjmO5*E^A(_4$x=gxkn^QnhL z2w$dRcs63P#b3g4eIZ-xOm>3W zdXYBwX3Xm`M;l(-%c{9ImVtHZPk4$cO4CFfr(<$qo$+NYETDDBC|U$9AH)&bl}!*@ z_<-lxL`&lXEloW=!3W}D%c2$YxTxhy^+(5k#9l;%P+cK;9)tTcUNGXaSS+ra1({3A zoGy!lQ=fd<%PG*Dh$&m_9h~PAv$)O_haiV-cM>i~G0;*0SoSvAp>K~O;GQX~3tL&< z9}qjHj0gz6>Z4s-XfvIOBx|5qo^@KoL;(L~seEKk-bUHDcQ^dyGOY6d9c&9h^5SvP zYr#EUMqCp;(|#^qQkK^i5X)ZiG9?nRFLNdAA7p%;DV88XECV5o-AODJa?r-5NaJc+ zj$x1J%Q0@|DY|;v_9&hsv1dwi1;*c6ES8hljwy2lMn=0LO5YeO*xSDzHID-0ujmkY z)@k(>0ey`vSsS?Xgq~}IvIY$DFPnb{6#erIuMx6!a;Zk1EmR5rKEJla)s~`YKbLrr zmz0mEdrDuf+BK|9J77l3lo80Y5tA+Uo49|F>2)SMK`y#z8Hkzy6jHd>!X-0bDnb#) zmSNa(3|}WQmSec5CfR5u2U{GLqirsdeUuP$kwdHri8gba%V3KG2X#pZl44EyQEZ5>y1ZAz2z*nZ;0D4lFh=uShG4djYwsJ)TO>y<5sPivLhIw`9d434-xUN-TS&n5m!z!rro6XXpSF)Q&$AB{re?9K`2FO^Y;4zSDvSTLmJ2Sj<0DhCV&WH(RR%j*GTbA91kU3$br z=`PdFq8>i4zZXDQ)HRt^mHU}`BRB(?t?NoY=#?NAuozjEe9$`)u-V#{e9%i_Gr2DL zK!PCoK!PCoK!PCk6MG$UVsBj{-{7o&!1c?TMhQZfd{8x1w{@2Y>6#+%9-Iwm*nFjxjU-^^gDz?uIU+t&Fst9mq15j$ zdE7ZDhJL~{0k&S@WVPGbS0WKoXcy+3v{?i32@;1$@@wq zLJS{NmHPXifZ%z4|Egz<4;P&SUmtqx*4Fa57y*5&`dU9}vifbK| zc-4?m{s+eSSBYc|`pKjTfz=(xDZXerWBF>bqCvhP+AO^zTNjM%ENj~i<`?}BOjUTwV#-BoiV z;5$vemHvtQ@8nxeYfg*>C<@PMu|0U{(vZDX4j{uhutA_4dg#YL<&jsu^!;|FaRfkd6IyG&w7$7? z?4hr=PF(`6FUUQ!u~n0xe^B+A<$^z-7Wu&o#6nV=0^((M*7_Kc+mTYtXyP|wFks>TY&tBe7jD@g+(Vg{1vF2m3 za^Ylbp?k?#z|&lJ_JUrfL_VM=_q9pIvAjj1eQlcIq;xProa~Yex{-_psiY~93Put|iRHoP@!!``4EnF>WH{=kMp+U9 zQoXDPVUq`ta)_&Zk+K&qD{OZiS+~3BZg$8LJ6lOaOn#h*JmzDINBXH7fz{Gx zPtPGCA4Kb#TaXKsIq#Kt)QG9|b~hbmDqmdL3)-$cHfquI&Q;@As++Dw1u>P5OhEWk zV1y`J5#I|;{t);9P7*x>J0IXti|lKDhv2Fx^|qlHz@B{ATj-fBF$OAnGtNs7?cfOL-jJpMF8T+bx#hyo zC~z4$ql#Wff$_H%Cs z2bNvUCdN!O?@_ka z(=rGYcU&u05~X@s&mwWVu)7}&$95qMA1K&^v&{0u1wUIUB|VfWd$}0!#k&xnjT8Y9B6+>xl}GW=MG8D*|C*C0bC%~oRj;+eZr=o-Zfj4;F!dm zOn^5+ot}MCC7~yf6d#z|^SzU&0I2?s;tr@yutuDc{(*ow8C78_3B@2)5_$wleQV}= zoaDlJg!gJ&|9*hLv3cB_-TPmp>BOL(1|X>?YnBQ#_PzYBH*iY8ys4 zs3b^a3n}*x>ZanzA$ZU=2HpL+SL=Y8ILKS~AJy8-PwRlzWXPJ4oJxX3wve(sz}^9l zA^Y|9eKbsOQ~Vz{l(#-<>NQSHhN=}wsU%2b3n}*x_C{%i=xpQK+fP2ODGQ8W{S)}l zn*mlo1cBiV$xuuNc9n!yyA7O2(xogBgQWPtBCB2Wg`PKJ$%|zRbidEOSpQ2jOmg`j zVArVfWGE&DyGnxH2F?r89$v)o*bwwjMsbm5BSTh0#l>~__B4v3nCmIOV_%F8}>XCU!m4u!}>hi$V z2R>~H&DL2=QYE1Wk;Zr-VxGp!vRsfV2|a|=ayC%d335rb4a-uter zg>aE86oMbzbI;#|YQV$y;$Fl%%h=gE{G^=}sm6s(9;oV@+@UQocs<~M%@m==>xFr8 zAu4sGT4d_n!j2^Pz@iwS{B#VsKE^IW8!>`-+|7EM{79cuzJ=~S3%jP89PFA8DqK!%psOS- zQh%ywoKS@A!r9Nsu0dKzf)8wp0f0a!VAg!lR1&a1U{XoA zxc#{3n9z!ZyD6ztMJQYfEdjOY!|SrsHr5BUaz1rhQ0^rz_#iRGQ4oe3!6U+MGl7jBod)( zKCpG!4@TXSQ1Rg8hu&#!-E$%95X>Q+gtC(`ICJAR>wF>~Ar@m}rddf?hAN97Y%zGn zq}IGl8;kA@=#md?U*zZmqzn`Zbygg%osxaSc9ztcO2V7a;SXFnEe%={36Scz@xWK8 zHufL<_<*YHPVw0^U=~JG>d@p8{^EAG*-|AT!$|d$p2cKymRFYynB{>~NysA7744>m z8<(DU?Sz@!W}-l*bQ0|P2eXm#UeNRpl1nAqDl_K<(*3$D4R;u)_qOf{M$TmFd`2Bs z{R5oG+^Z;4rz+V}ed)bOmk%tXh}xpjW6BTw;a|V}qx6Wyhct=ML&%6cs2UM2f$60; z^wUl3WeRrv1N@I~5}|6SoJ>p?>GTg`Y!z&{;8rC%^zTq)Y;ejDtn&v9byMa1K<1HF zKhb8ZVBh4TS8p8uC)XdINQYQL#IOOGL`a>CL{~_+T`+Ar46a8_vCt>x4gNyrjo8@r z55Q^?0b7EqK__712~>S3c^uRkbbSWThJStNfBLk!HhyMI_sHyI~ z_i%icadkzzJg}KWsO%TsGv?`FG<;iq;LSCsJH8!w>e1Ji915(B1io;lY|>qUz>I^Qha9nBH%)^`Ls z--7i5n^1&cdwXWQy%`tzor%~_h~4XUo*|3ETXQRa_kXj3-_UIFbHV~UU9R=WMsu^+ zlO1f5?V%=vLC^4!)~*xZz9z}Kz2fp=dH^9uympX7i=-<5#N@6b;!CBDk@#;)_$S1u zk2$KXyDCv+9+IU2h!59ALiFqwQZI1RiHV;YYV7uHL2p=Fh`vl9agwn^3eUhuIQpbTGGCWaQ^3zIqBh`?!HdD{v1c^hvN>tS*+) z0vZwLYAD!Ju9d>bb*DuW2O$9L&WEv=>WHV_Mtf5phk-@!q0}XVVb5Jofs_Uq+Zbp1 z%e)Btv6S5SoY8(VC|BU4e7ENF1s;~@B^tMT&`(N&M0+UFVCHi$E{c0=NA`~IK?n|ZtPk#mo*e!m&i@6#;u{K1OmtLokD@ozK^l7oL& zJ9nzhw?R3`U{O(b#2R8tyO_iiJjk2!c!_{7Yq__@nn*Ohgoyi7P)f zoPHa#i|oP1G~`1c!)x_e{>Sqo;c#Q~CUky|{!;9pqoqtHj?nQGC9AM=09RKAumoMJjG1eIJ-&$&vv1%Dd4?QC%YWN7RjXtiyY+|2*-rLU zFdI^Rxq}`N>Z2v@M?c?@?3Vg+;b93ygoqDxeI)-aQ=j4EKLqPsK*ghYZGXOO8VD?; z#Fozccy*_3I-4md&`v&Az0)&CH;KeF%{UxKIyG0|jf<;8L{)D{88Po`#w@1V8%WqF z{Qr$F366{;>aX=)E__?#OP`e&eq8kXMrA3GZdvPT>S@594VUzD_%FVIjpgrM4Omu} z{><0W++FhSZ!A&fx^&5MkVlmybM6p@zranuW9uk6AhC-IKABehM~F3DQ4+G%dxYne z=F2?B#Sy;VVu6e0r@yQAxM^v7(HhVzVn$60%LsdzU6dxXXP#)L+NIkj3jfE1-`VMj zCk2to`?_c4+J?J=0=M`<)-o%gv{yzlz7weJ_c;{ttTZI5NoO zI{J{G*VB44Hqv`YQ}p~*_nR_obg5@DicnWv{XNvz*RbBY%{EpN{3b=!f~w<{T)Y2O zaF^!n#}?^5#>MpIw{;DhNk?93hv;{qo~OSROY+hA9682sDM!pXe|*ulDWlgNbn;8i zFwG29FgKqp+@Myi&rK6UqOkCN2_Cm&t98HxI;h}@cXQk8zb?NANw}@wQI6&$Maed^ zAHtAsb)8gaS7HL@l(r)XX?@UUl%hV}gVsG}OLHrtS7v(VYa`1T`;IHx)R*UUa>#=k zaD>sE|AfCQd)ntHS~Hk_G(IlleIq zd7;oCdgiUk)t6OFe~rra-M>LPiF58Ie4W~n4L+o5bUCPHIJ8=OOXyy_t*M|pxGAso zhgtAL<6l&*k$LK?xP;$RI!%G0N+!IidsPn zdjhF(cVIZi!F$GmLGzVj?3jz#(ODHbQYIIztuJ=Dre6l4t{9lN zRG-an>T=r%(h&ZCz->&(2(tIm8ZjTY)x~NIK;)txj4lE! zlrrD}iI>V2mWERooKDA2C{(OLCnG+qDHc5S-Gkx31ikywe8Uy{M`>2CqN)iABj)ia zvH2>y`|f0xWmj77Z_vUs*#+D3nB?6}s%`0Oi5|Kk%hvPA>Gb{F1JjoQjPd(IRr9QJ z2q{HaC`}KjAJbEXwJFglg5Dv3Bh^JXbp-TL?%wMEh3_E^-*>@h1znDOAnv@VwB^1x20+3x*+Axr)Khm*8BHU>Q&<(v=i2*jHi0BC;9uXj?J(2 z2L~Pb#ps9utolxGKq@1C$Y+7p>651kMy@me;vmsjvRAzMbm|mb(ntZxfet*zB-(XPG6Dyw0dJNuCg@640exoGBAKQi;D|ook{eHCI zL3?%3-cr%9ST2IW60tZ9V^DH2K``*qT#SXOzdrbtrqOY`yKNh7-uPKobJz-MWfHc+ z+T@LL)J+Wc2B)zLuIukVjBK?5^1j0jAG>>Wvt2ooa_dZ!17_9m@M=bry0TWn1j}7I zgPgRF)kW^!weH8hAcE8WdT!fhRR(R&G2T{8Cdwg4F`LbEmh+YienjbSQ?FQE?1leu z`^Jx|EP(DMP}heJ&SUAdMVU|e>K`DoOx9xfoi!&iQc&luejD)##UsMD!3f5c=z|j( zU;UKK9)o2S&w>6uxBb;MkD<3}BdNBeMNvszLItm3#>){I3{@t(%_$2 zQx}$7*a#}Ei26NW;Rs?^x&%J+QDRU8%{T1dJOe?Clca99XPAuMhZ}I^>1G;uBQ{qy z*U)kP?eHNB1>4DX6|V~7>)){rmabPxmojSsAc1&h^zA6sP97l?zn%JQt2s(tmZdl#0kgrehxvRdY4V92Buw2 zOv#?RZ{HA?`_uHClHu_=T}mbqUF6mw62Vj>Q%X2B)cAmxCt8sb^n_Ruxv}Fz&%lf? zC!ESmO+}Gk5ZZHL?P)q8>8*Y9sU)(Xi3cwVf@bv@4Sb~}OB!y}i^Ft!1sxTWj;z_W zULqS#!hT`H7fuBpr}Qfrg@p0wKWKd2UQ}I0+D)I2%}nAKPJPWG5eJdSGEJU25r-o- zvX1F4X@m^_EWCsUT=QhQWV5l%UqU%67}DVPeCWweliOca5&o1?D2=?31&mZS>-XS3 zLk$g$tza&4?2`sNlYR%$7KEzJt*nDiedSJ3pL!pP(_O|4kSu+%ST_PAu0-n6Pr(-3n+E(u(0*$SvQ zauW1{3jkqDq)_nw^`tf2TVXtt`)IhL5ptbYK_B{b4CMK7N#buZ0@O#~E9h;v$3CgK zY8TaCANn8f$V`0bt-qn$Pe|US1@Od}E#oWBODy3>K!!d3@EXoL?US?$j7|WIu=k)W z4epDJ+lOV|=08?}_}{%=XE)drjZpZs<$Ye9lm+2$rg$VW>5Z6D1cy()d`NO_K_{qC zuLwjY5V18dbz5DQ2Ct(Y7RueFTtdT0#-4xPtPJb9Z~!!4ctA4 zx$RDYPp;SfWFoEVw`WtY=4?%9Y#)!+pL)E0s)b5}EvfaCd-LGK*cxpX`|kjjGsLTh z3_Hnz!#BexXFgXqUM23s=zq}yUz|)fLghNBgz;bzYR`-1^OEAS!l{0tx?s!tKa%@( zi9Yl=NZ%r<#RrohF(WKj&&tZNTu0g_vkTz@N#CJ&Zw z2$3)$VdyT5T^~_}`q0kGAkBbL6IPV~Hn zx>A83gVnzxlqiSGY@l=c(nGd!toyb*!$h-DxUGa!hixshrwbnutg=`#Pal6ydfqS} zn@{`k^wvdoub^K+fyW|s#q;Q*iEq^j<0VS=@80em@HPIa4MO^0ql(>SXzCx ziUgN|(wClFxSPv(?iyMh3IO$|+~RRk1pdH-y&`-NXh{hS*GvhP2-ZbD7BFnqyXNIVIN_UYJ62TUv5ty+*`et zCnSfOg;OCC06&Z#kRn@yw|@bJLYire!u;wZC)ELv&=}pvJ149Z3&oCLc=2lT?V7Bd z#!z4{uf9blzZ-lfj8`;I^AA@5=c4~Z1v1(Y=>ITi;x+UQ>LervNqj+ah^i1Gk9G|` z0yf@!(Pt~P)c30~-zaANyW|0^@B^53CR0`)zm(H!BM}%DB(eLY(4@fOx&52s0Jrz| zZP>-o0U}g(4XrSn#lPS5b^sS$OpTaspTR9i>e_H_cKiQ2FBHZL`SWjA0QN%vNXp>= z+g}BoZ*NeOfuGv{lOq`C3_GznQb;3-G}_$vbz)Oqu(*N3P( z4BagSB}SUG59uGQb&=GsW5-kOoWRnV&Qysg^6YuMF#x#V79}TM$KnMEWfDX5e_O>gZ1ZJlP(IJVFok9m-*o(67+WaT$*HDc4X+O<($@Dp}LK zkxeeUubD~zM7AiBQ(_P1>`QMYj5j&3rd<)qNx{Z667Lc&2c~^75zQDVk2j0Z1&1$6 zCi&3sLI6s-0<^ur{73RZCt*BuCfF<2?S=-}-5z<9KRgLcAryU)P@yC7WX0n7EHFVyd1Vdw$Y5Jo{6m2&afFjqk!D6=EI9xeOwQ8uJ2q5OCzsF*t5!e~ zQs*QcE{J8Un(W+$!TP3QrX+JAd&C+8kZJjm4;Por0DI9{twr`1oxg9 zf`X?67bC@8zJ6$Lm$}nl3OOienoduaIpCUlQO6@CXPHvjG+fXfM)R^-9QlMw=o^{# zD9wyLWXBswb4@_hmbn6bT<=NS8VTw3ts#v`2-Xo`M&3q!PUk*&8QQ`=?0)?l?mwRN z^rh!e3I*g2A24oW++M^0&lkM+k4PLQj6v-K3INZ)yu_(XoFQxg@>e2+4k!TT41RtNu8k}Jw3b{S1g*?IGmQ^z%K+ktC>@CXz*!AUTPB=(Tv~0qx|!K9uGk3I z5b3%#Bz*v6mWT=#I=1z9w@pIOsPKL14_XSVyOIDZguNm>K`W1aJhEfoyi{$iV@X!{ zPm!g zvd`xxC;Cng_NvPA4dZCW{HHEzBD-gf6*6|WGft6e`d=-GF<^XW`Et4b{?YJz8~48+ zwUHaf&BZ~N&^R~mkEHa674$N7$x+2A-T!HTPS6SH9IpnRR5?XBwS5T^6LPqUKFcuM zVb%mFTe5H#lCsN(miy9jB;N=kpa_ux{Ns2h zJZ1qNdD@(9Kvwo0szv|=6nRnyZUNLtRscEz!W0P%RI7^YPN?UAumR|}WdcSj%T7Sh zL>J!vs`Y`){J(9>K-&lcS{Eed*Z^{kRtBITOyd|9-Y>_k9xe-HZl(*JR`VH*8+w9HDrVppJ7 zdNhEz@KF6zZb>(Q9wY(ILqM~_BDl z7Z$WX{BMw+IdDvKycWi@dPQ6DNfsExj)k5%Px*2T1Fozo97!Qll3j<*OdGaXTYyF2 zH9m|20I=PDkB@8t4i7zo0dT;5emG(Eku^}_0F;Sz=kPy^f^^VR7;nn(_?U-(MluOd zVXyv^Z$P1152mdefy^0Kk%mBR7-q0}lrGRt1!CV1jvRMPvzR%ruwj$9cY8|+IbH|423|hEbVhDXVOlwR7=a`kG z`5^e5x1nQZl~9JRyH0*9y>D~{-oLBFgRj6i z=`C4cdj%+hZBbrSu^VT2l%kgQO#UvfX_Ni}@<1lgoVdZ?gZkf`Bla6=4cEB28^vip z8?|HjGXDWUU1^xw{ zzszA+R5w>gY#B-G8&_3|W~N6>$_xMYk@<(NtncOa)ZaJ>{7j5fd6!Gl>i<%E769$U zKPv30nm7r3%5=4nIyHQ#iKG8?5s5AIB~eCs!0H9Ln}KX2{UKN2X+}~benzFxUs^Z_ zA}>R&Ip`t&f9o9$f;1(4?G?@!fw~%a5o9EHjL* zg}p6hyvh*z?YL9vbvQJI`LmxRl-%tuUefgwzgI+F6JB&I=sfrS3zl}CGpB|R?MIP0 zcWuh?!Gj3)Lko$&Xl^(lx^6DSpL?PmLT4H8zoC6tAROiAAE#RA>eMg72xf5^;@dGX zrNq+F$I~U?GaOji()L6S@WWMXW~#bNQ4%tZ<{Q6TD|nzRWflVkC})I!k8J<1LfK;r zt?GH_k00A^=LApeYtt|#A=Hjeyjah5eMm9%v>4m&ETU8AMJyF`UiuR+c(R|JRU$~* z*ME-#hxq$#sHQ&;W<~QUvL7x*O&pfN15alCODQ^w76w{P*pPOvxJsNpa@R#(!1-RG??Bc<3>c;U_QV97tzW)xVNg(J z32Ur8B0SLni%id%ET12DsweOYzc3z=xQVuDcp7aj1>1f(>{<&uT|(r^^*q;qF@(AS z&p;C=TI-VHQ`foOa6xU%dwwsyPc}d4EFTXl9{L@c2O1OJ$CnI_4ru&}4@$Ut!^l8F zoLzcf@{sTo)Z?bti>P^X++%kpW5x-;db%S5C;eu>_emnNILw+%^!#L+Ioh#pkRS1{ zSJ#c?h^h%{pd@7wMaNVqv&|?_i>yjS=R>K_8ta_(N10@p77$Zwpa_3UzrgTusreG} zoNsCz5slbC*8O#-+*;Xg?FaQkyW{Gz=ztc@w?bd!k0Q4i*NBiVtGeo2;yIc(7M2rZ z=K>|E6piXm>ekl#to2L9K;uT|=$?M-wturA^q11QZASgat3}x zN&n*1gZS**H@o@p^x;6HEoxTNO)I{Q#EH;}8x;R9vNm(e7sqR-dgg*+y(fc>i`|8zvhmR{@P$h#Qtwe;j_l}_Xb|Fn$=-*?zq^;*%BpdF!64dJ zv`wVpC(&EP&K%P@=BNz$L+Rfvs86B0H7#&b_gINf7NcGdC%ut^t-woE?Lhl3j?Q#W z&ppUjmyKOyrA@y&_|~x*>_V3$_2! zLzVQdYEgejbfLBSXyk^3Z$UrZrR00upkD%Tj z$h#AyC_*An^%$v@o^H@PR&dTq3cJs)(kp~bNBN{d(Yf*?z1#f%>IL4URxLA@a*&XX zy{j1)UU}NnBS>;$gFUf)k9(r6S7I=`28M0ma;d)h8Vmj;G zo)vyFa`wrVDfXDQwqskwJTTf_J?4mZi!16Ca~$xn<%BYG&(;@D{x5E&R)0H0+jRG; z*mq4|wD&q$d;Xc=@piY}dLM7C7|$>NofGD;uQP$H^T~^JNx~OS-b#ay7d>_8zdq{* z;JFo4+XhA_#ke~~ORd1)AmS>D5QsFsc77S-Zs!Rz-N*Qf68nQ1$zhRl)yS1+an&JYw*=;MSZpSicVF{nZ@s0`G6{IVQsovijvM7+- z;>vMXLZZ-kqaa-{Zd&8wFf9sL69U;{eN+Vlxk%#CAyVuNPoZ7V)uliior^C1IEzbg zDI$9iFk^wY-1x5{z_C1=VGKj43HoeNFwjBQkz<)KxbnEV>1K(+ zIj!^FWKqqLuDY#fH4K^UMEVgiv@Hs&7aeFpC{DB{_?EClpC@75BuEY1t!EP+7Pf;C zCNjjR?26v9yI>LBU|wNjWh>Z`$0g1fvxZv!<@dB{PwMK`d}K`WeM1XIG5>-krpcVA zNLG9O^@GE)n?Yl}DAErm;eO%J7MJ+GSs;VGYI-rl(DH^-bd4EInU8{?iK~&exf}zJ zudSicO6O?YgUU4ho)Ddm*^$Baj{)CRs~Qi0|4YqJnSTG>&xR}YNO1U(wHnC>;j$qy zU2HE}Pd*t!w5pv|BcVFJWw1~F+8E^(*`CuYpJaV(Ww(TZWX*Jl|7E9w<~rjXeAoTC zYu`CpxZ6u-H>gj&SSXXzFuGe}JVriN7!M`3SU#9yhz*<2@DP@HV3ao=cp|aTl^6vA z97kb)ZcS?1t1TM;H?xYYz+GmLpAxgH@mxJWNkd~jNzF$Xfr&!uD^`4bP3|Q$^ZTm4 zVh57D68Eg+Olh`f+`_B7f{5V{leS&%@{;A2_}Q}zdzs~o&F;^ zoa@fN_w17vxYKm0E@>`2nnmpwOibbgnEHgx5UbpNa%15!)cz$byV>@?xtm7dTVt+? z57_WjNyUK-dK)Ic)$U`gxoM_-ayg5|B`lUt3LetK*Z((*^E-u-whW|0A~|^q$W!uRIGWjYdIt=`Ydsy&R|)b;sefUe8n7kb?!Wf`a57z7kZwmot?0 z!ucI}?w|a;Cxdfy3qi|9f-cX3df~Y*;k8vv4)Loz&~oAT5h)8XE#DmWQQzvj>rq4p z_2^~e|4QG2|CYX=+Ed4JP@f?YTkKhpdxlG&)xxA9%-1OyqIvLr)(gqIljwV3)RB-H8_AA1 z&ZCREN3ZzHj5M2DT?R!y@!m$iL(R1N`#4mCadlL13DdA2c4r^&(4YhRqM`!QnX#MC zBS$lb>W=5=WQ{y^J*qcj=FTrN1jY#?WEa^=ju$y zSsO@-(V5lKs`Igj;Wlz%EF&9ctY4W{#uX*rOc-f7c>8`8n1r_@{K(gUP7g5<W=gKldl~dqDA4hgp;iX@MdhEjNa}COp28fyizZmOpIOdLyJVqejV>$J|*RU4J zJ7Mq>gjmm3ao%POIMPZhv8c;Xj>#z2voo?`{=k~pw6uu+p*jf!czb)T&4d;%y$4|5 zs#MQcCRDh?EsnE%b?p(Xhy2JDPnan`WM9`8YG%B=L){hL{B}tiGdY6(B8%*;lVM&o zmWO5XCC{X)X_pkvdy)iKG!zz=f2yY@9Jdm&q`@{>wM5QSC5hnmb`T1iP?&Xe5+R2a zE3vrxlG%!Y;;B7FaS9z1m`J*nH#QW^rIbCL`u=~@Pi^~51E}7JCe~5)#UJ-Tv>LEY z3r13SQaY)(8Dif^^($(opyVtfM?Qg^oZh{2^o?hT}8ag9zS6EC;@`(uW2 z6OP@R9LQmOy;ocNv%2TvZbHc|#ZK!k}Alku)oIGG*h* zBGhk?qwt=f*fL9^*sMT6WMr>jMN4v)BRS}=MD@5r4e9&Aj_rQ=+D)1y%%g1^Hr+T? z-xeD}1cC|Ejxj`&sqK6dh6x^odROinOd|G}Z-!ND^1I9MEc`DOX!vrPmh0t$yUl#) z_(N$GKnl&w+}~IHY~u*XY;6^cGs7V7Q4}>u;VV@?LyaHq2kb6OOVqo_dimqSY%bf` zca)X$V#A@_FhY~=1D?OZ4z!$OiGLATpnJ%fRX!}o5=LASztL;OU}?r1!*$oVf3vV% zjq;Jv{+rEVDRUt1zusq)hh=8y))0n&Gs{+d-1ggO`m`ml4P22aey@4yNGc}*lWM%t zObY=Y#ZG!RF7nUz>6Xe?Fg87R{VCj#&q<*~S=;6MbpoM^?gnila!18!Ic*!WJ$)`X z?;5S0mn}G3FQ7s`rITkuZ6mVRM%@g}h43Ia9_TRIs7x#I{;fVO#n_xCPs%Vb!a~cb zJnuqkCPTF)Nd1`Nt@{xPD9|dnzjRh^xc4$Q7`j=VCDXv_TyAbqfwLRl^MY-^G$&pG zrhCheoJEXuqa3v1sJ>4^4vKw$EhS(J+k^{vt%LhmX>Aw+kJZ;KJpB>v1Nmxx0*a!u z^_mCW2-RU6A_-spXU|jL+$b#!o=>*yExBj)s~wD{NS{!LLbqV5N^Do3Tr#pZQ-$&p zQK}@wc>6?$X`d5D>SO8p97pSZ-{up=#KvY7xg+GZre3YE7SS z$?B0cD~vV%u3HR>jEViJd7+V35S$KAH;$}x?Nu(+H2#Z(8I5A0*Z&Chw=s6}82@0L znG;9>L=S5+?3*dA-kOqqYM^+=!`<(O!PZz zI^J@WK2jQY28f&}-=P65PIzi=#dtA$37=Z2Z^ipSuO$Cn?1aG!nWq0`ZluZE=f^_$ z9pQT}E<-KIa|E>XO32lh)e*vx_uz9jHn5a`H>W!FT*oJEA3i)!>9v_RzAs|f2lx{8 zni+~A{%g8tLR`+{SY8h`0}?NU&wql9r8WwCabFRde~!Zsb`RO^`hXHBSiRL4LF9hM`K5;3PWDgA5gnq+l*EkSN5<9S!Qk^GPXo5UGF_-<7qF{# zdG2>r5y$~6y-}FZG>hvn+_`Wi;$P1#=W5swob!!>_ZBZ52+?dc-rS;^!^SH zow#Vv4H;BfTFq5|x{qv|YpFCpG74HZ%z(Qj<trtsg2e4C2;xsHw^Oaaz6EtuSk^n?EUU?}NIlGFq;t zVy7Ll`DRb*1ATcN4`slCZ7tQIo_tc{J5HO9PRU>%Y!9)q=44R91PA$#RrM3G=HAz2 zbLwKB;7hN(TMW#}JY{O8{RskNK+H0vEtk^|O(MEx7ROHVNF+mgg}A4f5B5kW_+9w4G_ZyX+mI3hAF7LH4Kp;4amP z@jzodG{9^A!`X{i!2w;k?fuv0P0BoH!-RxyALPGnw&WazGE7jtUDs5PO|mqx%3SG6 zW{OhlC-M@n%BJtP|B2QW3-&*&(CHecZs?Y1K1Jxqy$m&^NH2C-iRl8#fParxCjCgF zV9KyDfGunGxEJ%0`SeoQEhEcVC*6O=PJpY$j8e2jp~ zFe%w?zD{nZ!ngwM&7n_25fu6;VEl2U#Rr)fV{3-J8JomY2^f@K zClIZ2kyRJsb-1>24}G!)oIB$NG40HSHO0?({Ph^y*vjFdS1c5eFM5+ujFJ!^gIU!J zYM&_OzhH%!RYT`{9mKCKgv#z7)YHyU>O{dRH~d4gSegX8AD`s%S~S#NN_AV+=srd; zK8TWkaQjZJu2*qsoX(FEqeGkn8pSN5K3dEVJ&2gqZZP~P*^3W;uENSA2>A;y&z0~N z%u0G)vl(1Tzlyj=Ss6gt?6D)*&%|qk&9wH{9Izx*5i&LbdkZ(0}5cQ)IbfXz4YX^1N|?PPf8cSML`zo|#aULclY)bwszZ znks=1B%kES_kD2pRDlHV3<+ubl4($&4EXXHtVj#jisi&}>XkY@@QTQIehrt(IvnY|c3X`Z5_6 zd%>Op$5kRP9 z|5SA%c=ehc$zOvY>V+twZgW8g7x`!YcsROtauUKJnQQYKO0Q%g@gokXR6nRZxfQLy zAKFE|N3E+INW^hq<&S>9t_{^)?DPwN*J19MAs8}2&()ohf`jnsJw~+lFzH<);$bXFMVozukD5Rw|_DGtp)$sNxZa&sSOW zz&$N=YNxoMq$ak6Ve_v!XAwGQc$sP=v5~Y^5xTLQ1RpZfUF?RWL256B2KbL7QF`Z}0R^Ke z8(&3#n|^)QuX1D-FOQic=iUMA2x?eTeAW!L zpL(9>B{2VP%5g2+ixziY^iiq7*wcAO%9Jzu8cKe1cH)+-Wd7cKBsQ|&k|r$ZM{%K! z^{F7%VDz1$pp)eJx>g#qTrh7JBWqs%XTh`#uFT|6T{fzuTfi|DoJT^bop?Z9dQy52 zvqo`W6%9}Fw2AQxLCU#5irNe}WV97MavAGl`N=f7C&Dus}t zwq|HA98knD;uuc(oT7ELuR6bk-kTlSg&*|s38}xmVBU>uzD>X(=h*M6j)Ts>CRCVx zY(&;Zb7U{VGOqIFnW$Q%eNt-3&%L?vD&Ax5jgV*xbMB zXks%xF;;ktgQ-0Jbu#aESg_LCNy5ki1)sYCo(M?ml@Kp|ih31$IgU(}q<6aWK z-6x15qdwLHse2~z>V-$Y(&$YV!UjPmlvMueCz9-=qNfoxilId%FEI&m-x0Sxwf-Gk zY{_?=VT)HguZ8b%kbh<^4TEqP@|E4z&`jr2vOWA(sJ{9os=9oBVb{;3zx;d7H4JKt z#ZdI3qhOIGLtjraR%kU_RP)`#53*~cb)g>dfcc`fQ)JcoHdkDJd2izb4ZP;a z*UV!8y;5QF$R&%qpKub+@|rCQhBktc1b^oVKQ)JVPLzUqN;R)&%qf!6>ED&Sy~`Jj zs+TeLBA~;%K3^QKsgpi!6K%8E-K3(=men^!?E*msf89JR%$~ROJAL-wxs11SEIqKZ zk1T?Ten^TITrYbbeY&Y?`+}7$hU$gR;YUSU!OXPV|-DUHh+|JD>=f=zU^ozX` z?iqSrpMiXHMT05ioi1Yhn<1$#C4KrB*tcjFVFFbqSm>PCHMlt;-J?{{gqhjL5vXxfDo#M;P+)k)S;uEtO`&(D}w*ZAcB9vEi_nyK7Gp( z_KSlGUHs@AA+jmtI9GCp-QQxC$LND;gn?6q6E5lCUFb=tyW1^)IG)$ddGMw#OJ_4u6P9z& zP1{XZ_RsNE;AwFw(gl<@&r;B&E&BTAlQ`RUS9MR2u)@xU=|jIU`kZJ`!PC$+?t92X zx*a*QMBT@1Sw`EAol}tM(jBY18|_@s4S1tcP~l^6^RO(_r6p-+nf0_rZ)|@Yfwtk_ zfNK0X|0ojS{%p8@lqipi39Jzmyv6nt<|LdY+Cr~7Tq}2Cx8E_Y+u}2%NBnypRYXV2 zTDcf2rU>E};_t95h2geBDu~xVuO4yACv=-22C&^xI(VUZ#ZUC2R0oc8?WulGC1aQ^ z1(-66gTp#!U!CGUCD1J$>roCaRNFQ1F1$fi9p{{1< + + + + FreeRTOS+TCP and FreeRTOS+FAT HTTP Web Server Default Web Page + + + + + + + + + + + +
+ + + + + + + + + + + +
+ + + + + + + +
+
+ Free RTOS logo +
+
+   + +

+ Default Web Page +

+
+
+
+
+
+
+
+
+ + +
+ + FTP'ing web content into /ram/websrc + +
+
+

+ FreeRTOS+TCP Web Server +

+ This is the default page being served by the FreeRTOS+TCP + web server, with files served from a disk implemented + using FreeRTOS+FAT. +

+ The HTTP root directory is set by the configHTTP_ROOT constant + in FreeRTOSConfig.h. These default web pages can be replaced + with new web content by FTP'ing files into that directory. +

+ NOTE: Performance will be limited when using the + FreeRTOS Windows port. +

+ + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/HTML_for_default_web_pages/logo.jpg b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/HTML_for_default_web_pages/logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2ad5f5c43dbc9dad2dd5fd4d6ee04e23790d883c GIT binary patch literal 5178 zcmbW3cUaR;lfb|94kCo2XjDLuDo7WJh=8GpfD}Q9f`SPG(u+V;Ec6J{L8=t#NEb{* znsfn`UJ?+5P!dWABqW#L``&Z+Jone#&Cc#WJG;+(W_ITp`UHIeIA&r5H3FEJ0Dy@x z0Qxjw0I)DK|Dz0HWhfgb8yhPt8#f0BJ0~wUFE0-_4-X&z@nd}ag8V!@$3%_^3JHTi zAYK7cF%e<0ju66WLK6aGI7{VO2I3FrYISeVWM%z{iTf=u*I z0L<`{jp<(k{HHK6Gkj#{;N;@wVHh+V1DKguSeRK^{_&b&9nRPXSOwXRpHO-s+nEGYa?R9sT}vFuY_ zeM4hYbIa#%9i3g>J>Pr#M#p~s`aM1|Ifcb7F8x_v`MbJC+}_#UBkhw94*%g|0$Bcy z#aRCh_CL4;8C=Y)tSqb?|8Oxe2Qem#AS>Hh753x$mK^tegwClx=M=t{m|xq@C3(q; z0CMpi;TDln!%7qXLHifk{|@ZM|BLLu!2X+S3gBg7VkD165P$$j)@3Kq)gA@#Ce8g% zm0yZJi9bvsa~CF=JF72YBv!&hz4^)KXQR@b+N}NRw;OAZZ40eGVe`YuQRKW#BXX); za|Nv@t^FK#_d=CB=Ul7Fc!Rp1YVmi;h^bZGiHH1s_ZB7GD<9?p>1*{6a{3*q1U;sAjy#X0gkAp?A<8Fub8IL< z?fW;=3MVH$sZ?l8QX}Dl)isdoo0T|QZ~hW@jjgrLzeb_Gt%vpD>AE1I2&9$BFVaKZ z9X&<|Bu&CD5Y@tmB~~kGq_+@q8FA|wM2Koo{b){ynC(zi6hc4`b@!VPViC28N`+FE zpd32jhf+zsBYsukW}wI^IPEkMgK9GSps0sV!sN5~aMIJw517ULhb0rY z?6Et%>Y;c6rQqIuZ))$Gy6gjGDe5#GP#q@)b^Teb2zIfk%r2w@ZiVY~K=g-?ANCGp zBe~;nTp5P}Qw{2f{6$CaUHwjHNL18p)+%W5U&;<@hs67F5$Qm;ILlCd7=dH51(H~? zw%qJ+=}A`U=YaFpMI7!Ij#f%U$zLOx!Q4Hb{-60}l&n$6>MZo4a}!N z5p_51EJhV^2K(0sMzyKzY<5jYg$-nBo}i*hXhIoF_xwlo9))T4oRk&3CqxqLVL^-N zCompF3mtgbiYp7>VqW#819$iCAKAX63FStQ9BsV`9HcE*0%-YFXI({B#BYZf zrR9d?$i%gh=BlhtJ*lxU#S-<+65rI{_^*n+u75eKJSK}5ZPS`wpKadXM}A+6*Oc9n z8=6<%*4?LxfI9;y^L&?Ro8{uPCUi(l1#gyhxcc%l2)5(wFP#wq5#;nUoW{p7w_he9zweU`NFueHj=?nn+Ka-I4pZ zBYR|PkYMEo2QH*dP8}n#mLo3xg3EivOgj4OX_q8+3yH-_M6f`2D(%WhLZP>ZdWDNo zRK-NEq_`wUiFz+>G>v(Bfz&KOZQv4J#(lBTHbVWDw9C{$_ruyxnh(9YU`I-T%CBRt zhsMrr2F26__ol!6Ppc*FV?6^-KWS(sI;)*Lp0Cc|ur2(rvq2XuM%poH`p=MDL= zQVyJTfcJELAn7o?M54Eb92(`*svJ*bgC%bsBlY(L-!Cv6_zI@j?e`DMhFrbs}7~- zqH#}&9=I!-)-lj!oy%eGOnD!DO|{bJkRpCn@1ga;LW2YIE(IhU9Wn6L7Ftr=!-Z8Q#H{85oMo6^ArFef}SrQ$?jWdIzsod3`xQCOhH zO?_C4*AcuqF1Vm9VZLz6#DnsbvsyY8A}gL=s-K-Li0@MF++x(YZ{~~PH#h9txMUIq zD6u_jzQ_}Y;C32kLk-!}94o^#Q5ByvZLS1i*Z zRm;0I_(#*!iSh^vNG$Nmj%8b{>DZ>%@`1|>jYL$9xH_>Us)2$L@n|{`->>#=2J`)W zU>vpd${UlzF&rp+oW?n>xX}(@s(&kc3OYTC)*Gube1BBg>xAe1couexQ|m|;he%o} zGF%lcr>yIKyGcYDtZluf1N`f{q6JqAX2F*Jd_KN?JR*{B1@7s%)ahvj`*v6o)Q{F{ z&a~E9Dp&(7{6Qsu8jz7%f^yP)wYo5wonO6pQZEt^$ z^O+F=P@O`~?;#dyqnUkpc>qH=Vbw;P44{?mP*%Oo*M z;o41zB+ML-29Hv$T}V3dZFY$)eNDIZ^7gD@>M8dSxb3z2v8GF7OCe;0YWX$Gsg?d* zz5pcuqr-tu!ATt(shiJT+)xAdS-MH@cMk1ZS8ZYZy7$3p4?REJtp%_BR)=z6+pFw4 z!FA!;W!sMqlN*Pr7ialacV{jdH0@Yeg|>zu+}o(>CTog7hnTR0#ww%4qFo@1 zu=@`6a)0JVGwUCupaazg){4?>vXRMq0+YiQo|hIhpLxza4jA!-o?gC)tOSjPU9LId z{!CZhO~-LHbtJ-4w%|*8ang<5RqImnX?96_8!Y|j|53J&qxPFyd#v6wGKv-xXDbtdTL#h)N&ncwSx^J$5n&K}RY zR;e}Q`%&t{d_=6_QAoBHVz;H_g1Mh&!|&7)WbOc!NZ6+eLkx*c(YmIkC|zqT zZwEZD-4omF?cR7J?eVu|oYBGj!0dMQ?27LAD4LBtOMqavzQ&s_rl6j2bf5%gzN=A^ zK1Y6={LH0GSqD|*Z1y!w=|(*C*asZ!ge{5hEq zsTZ4%Y+J&;N%zS5I48^$hPO=yS-%u=sLRLbGQxiQuUeHL-G!?s;D(QbW2kON$qn#R zh2--5t3y!fJ(O}a4C6eEouBevSgu7R!ePR?GGT9JvrC|rxTK# z9a!7T5YXQ_HgbLi(!+Rh_6jPsR&Hv3`m?O~>aeeQU@l+VilY#q#e52YvvMeKq8?hl~7gW9(}i!@SM^Q zk@y`W!-u^5r{4!f#f9(xd}YENwu%Vv7MC*n$g47)N!&UaG2A%yYiWE+x^H#I#PmyB zjF}Hqo_%9dQZ{m4u0aUdu1*avo>e&1+|Vbo&y>tK zmPZ${tm!TY{ILK<7RJ4i4xVK*xm8xF7TOxdL`-Q_?IIc3uJ!ug26uoy=0^-p)o&Lf zKEL{st$mO*t*TAE0Yo(5d}v*edQwu??)=nenl0Gh37(*TxNJnT;TvC{r+C3FFTr!` z-BOS;4_e0-Zy`mV(}9%W5$w9~!=NCq_`iM%AmMNf)|+z`%{TfgHG?BLGA&R${`Itdi7+%G zHM#zRb;5)+(#7{`6XU{@S9Ydt>LHOd1)}2I>f;BW5{zc0e-Wob)_nG(s}&oL@-bfF zih&4N9qCPJIypp9Y4Iv~Gw*JbLn?CGnp8YesEUAms+{S=JY8=ZJs$Dg691hJ*yU@> zIM)}a8To~qC{nf`QzF}QK#c_NH(XIOD5hH;~(C zKnEU$84=vFdXGE9iN~&--oA)5*;Dxuub>9khX+@8E)6M42)$SvrCRO{z686~HofF4 z(E0@&0$<9BY3bGTVQ&6gQ^qEAAnkJNGsw#865-s#W8%e{D9j^I$&9v3l_rHB?eC=>oS;A+ z6?%dv-@g~D}WpR{mnWa6}=VLY)Zr;jm42o0G`a-}f=^RWw z>_m>DhkGiGrQ3XYRprBPpU5q>f$_lwD4L?+NRV=-*#Wb_bZ6_N(ZV4HxrOEO+3_E`ykjSj&E7n8-&k}LUVICd*Xrm>3;C3GMQ}w_iSUt zTjcq>jYp+nEKjt5DxKX=`o*BGbo8DQ`YLMQ6LrRn4h$PUq`5RZR!_Xcw&fkjSKN6= z2Xq52K&m|C@FX!p?eL_oIqsy{F8C2tg${%(f(eD-KgeLe6+y}|q{dU}rfvbY*~LDh zQnnvn3p~`|N%h83+Cp^Za+Q#+zHbi42ghMGHMWB#oqU!)BVLLwK8H+>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef SIMPLE_TCP_ECHO_SERVER_H +#define SIMPLE_TCP_ECHO_SERVER_H + +void vStartSimpleTCPServerTasks( uint16_t usStackSize, BaseType_t uxPriority ); +BaseType_t xAreTCPEchoServersStillRunning( void ); + +#endif /* SIMPLE_TCP_ECHO_SERVER_H */ diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/TCPEchoClient_SingleTasks.h b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/TCPEchoClient_SingleTasks.h new file mode 100644 index 000000000..03dae2ff1 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/TCPEchoClient_SingleTasks.h @@ -0,0 +1,82 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef SINGLE_TASK_TCP_ECHO_CLIENTS_H +#define SINGLE_TASK_TCP_ECHO_CLIENTS_H + +/* + * Create the TCP echo client tasks. This is the version where an echo request + * is made from the same task that listens for the echo reply. + */ +void vStartTCPEchoClientTasks_SingleTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ); +BaseType_t xAreSingleTaskTCPEchoClientsStillRunning( void ); + +#endif /* SINGLE_TASK_TCP_ECHO_CLIENTS_H */ + + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/TFTPServer.h b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/TFTPServer.h new file mode 100644 index 000000000..fab6ce9ff --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_TCP_Demos/include/TFTPServer.h @@ -0,0 +1,79 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef TFTP_SERVER_TASK_H +#define TFTP_SERVER_TASK_H + +/* + * Create the task that manages TFTP transfers (one at a time). + */ +void vStartTFTPServerTask( uint16_t usStackSize, UBaseType_t uxPriority ); + +#endif /* TFTP_SERVER_TASK_H */ + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/CLICommands/CLI-commands.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/CLICommands/CLI-commands.c new file mode 100644 index 000000000..7df058825 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/CLICommands/CLI-commands.c @@ -0,0 +1,664 @@ +/* + * FreeRTOS Kernel V10.0.1 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + /****************************************************************************** + * + * See the following URL for information on the commands defined in this file: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/Embedded_Ethernet_Examples/Ethernet_Related_CLI_Commands.shtml + * + ******************************************************************************/ + + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS+CLI includes. */ +#include "FreeRTOS_CLI.h" + +/* FreeRTOS+UDP includes, just to make the stats available to the CLI +commands. */ +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_Sockets.h" + +#ifndef configINCLUDE_TRACE_RELATED_CLI_COMMANDS + #define configINCLUDE_TRACE_RELATED_CLI_COMMANDS 0 +#endif + + +/* + * Implements the run-time-stats command. + */ +static BaseType_t prvTaskStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the task-stats command. + */ +static BaseType_t prvRunTimeStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the echo-three-parameters command. + */ +static BaseType_t prvThreeParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the echo-parameters command. + */ +static BaseType_t prvParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Defines a command that prints out IP address information. + */ +static BaseType_t prvDisplayIPConfig( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Defines a command that prints out the gathered demo debug stats. + */ +static BaseType_t prvDisplayIPDebugStats( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Defines a command that sends an ICMP ping request to an IP address. + */ +static BaseType_t prvPingCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the "trace start" and "trace stop" commands; + */ +#if configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 + static BaseType_t prvStartStopTraceCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); +#endif + +/* Structure that defines the "ip-config" command line command. */ +static const CLI_Command_Definition_t xIPConfig = +{ + "ip-config", + "ip-config:\r\n Displays IP address configuration\r\n\r\n", + prvDisplayIPConfig, + 0 +}; + +#if configINCLUDE_DEMO_DEBUG_STATS != 0 + /* Structure that defines the "ip-debug-stats" command line command. */ + static const CLI_Command_Definition_t xIPDebugStats = + { + "ip-debug-stats", /* The command string to type. */ + "ip-debug-stats:\r\n Shows some IP stack stats useful for debug - an example only.\r\n\r\n", + prvDisplayIPDebugStats, /* The function to run. */ + 0 /* No parameters are expected. */ + }; +#endif /* configINCLUDE_DEMO_DEBUG_STATS */ + +/* Structure that defines the "run-time-stats" command line command. This +generates a table that shows how much run time each task has */ +static const CLI_Command_Definition_t xRunTimeStats = +{ + "run-time-stats", /* The command string to type. */ + "run-time-stats:\r\n Displays a table showing how much processing time each FreeRTOS task has used\r\n\r\n", + prvRunTimeStatsCommand, /* The function to run. */ + 0 /* No parameters are expected. */ +}; + +/* Structure that defines the "task-stats" command line command. This generates +a table that gives information on each task in the system. */ +static const CLI_Command_Definition_t xTaskStats = +{ + "task-stats", /* The command string to type. */ + "task-stats:\r\n Displays a table showing the state of each FreeRTOS task\r\n\r\n", + prvTaskStatsCommand, /* The function to run. */ + 0 /* No parameters are expected. */ +}; + +/* Structure that defines the "echo_3_parameters" command line command. This +takes exactly three parameters that the command simply echos back one at a +time. */ +static const CLI_Command_Definition_t xThreeParameterEcho = +{ + "echo-3-parameters", + "echo-3-parameters :\r\n Expects three parameters, echos each in turn\r\n\r\n", + prvThreeParameterEchoCommand, /* The function to run. */ + 3 /* Three parameters are expected, which can take any value. */ +}; + +/* Structure that defines the "echo_parameters" command line command. This +takes a variable number of parameters that the command simply echos back one at +a time. */ +static const CLI_Command_Definition_t xParameterEcho = +{ + "echo-parameters", + "echo-parameters <...>:\r\n Take variable number of parameters, echos each in turn\r\n\r\n", + prvParameterEchoCommand, /* The function to run. */ + -1 /* The user can enter any number of commands. */ +}; + +#if ipconfigSUPPORT_OUTGOING_PINGS == 1 + + /* Structure that defines the "ping" command line command. This takes an IP + address or host name and (optionally) the number of bytes to ping as + parameters. */ + static const CLI_Command_Definition_t xPing = + { + "ping", + "ping :\r\n for example, ping 192.168.0.3 8, or ping www.example.com\r\n\r\n", + prvPingCommand, /* The function to run. */ + -1 /* Ping can take either one or two parameter, so the number of parameters has to be determined by the ping command implementation. */ + }; + +#endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + +#if configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 + /* Structure that defines the "trace" command line command. This takes a single + parameter, which can be either "start" or "stop". */ + static const CLI_Command_Definition_t xStartStopTrace = + { + "trace", + "trace [start | stop]:\r\n Starts or stops a trace recording for viewing in FreeRTOS+Trace\r\n\r\n", + prvStartStopTraceCommand, /* The function to run. */ + 1 /* One parameter is expected. Valid values are "start" and "stop". */ + }; +#endif /* configINCLUDE_TRACE_RELATED_CLI_COMMANDS */ + +/*-----------------------------------------------------------*/ + +void vRegisterCLICommands( void ) +{ + /* Register all the command line commands defined immediately above. */ + FreeRTOS_CLIRegisterCommand( &xTaskStats ); + FreeRTOS_CLIRegisterCommand( &xRunTimeStats ); + FreeRTOS_CLIRegisterCommand( &xThreeParameterEcho ); + FreeRTOS_CLIRegisterCommand( &xParameterEcho ); + FreeRTOS_CLIRegisterCommand( &xIPDebugStats ); + FreeRTOS_CLIRegisterCommand( &xIPConfig ); + + #if ipconfigSUPPORT_OUTGOING_PINGS == 1 + { + FreeRTOS_CLIRegisterCommand( &xPing ); + } + #endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + + #if configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 + FreeRTOS_CLIRegisterCommand( & xStartStopTrace ); + #endif +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvTaskStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +const char *const pcHeader = " State\tPriority\tStack\t#\r\n************************************************\r\n"; +BaseType_t xSpacePadding; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + /* Generate a table of task stats. */ + strcpy( pcWriteBuffer, "Task" ); + pcWriteBuffer += strlen( pcWriteBuffer ); + + /* Pad the string "task" with however many bytes necessary to make it the + length of a task name. Minus three for the null terminator and half the + number of characters in "Task" so the column lines up with the centre of + the heading. */ + for( xSpacePadding = strlen( "Task" ); xSpacePadding < ( configMAX_TASK_NAME_LEN - 3 ); xSpacePadding++ ) + { + /* Add a space to align columns after the task's name. */ + *pcWriteBuffer = ' '; + pcWriteBuffer++; + + /* Ensure always terminated. */ + *pcWriteBuffer = 0x00; + } + strcpy( pcWriteBuffer, pcHeader ); + vTaskList( pcWriteBuffer + strlen( pcHeader ) ); + + /* There is no more data to return after this single string, so return + pdFALSE. */ + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvRunTimeStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +const char * const pcHeader = " Abs Time % Time\r\n****************************************\r\n"; +BaseType_t xSpacePadding; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + /* Generate a table of task stats. */ + strcpy( pcWriteBuffer, "Task" ); + pcWriteBuffer += strlen( pcWriteBuffer ); + + /* Pad the string "task" with however many bytes necessary to make it the + length of a task name. Minus three for the null terminator and half the + number of characters in "Task" so the column lines up with the centre of + the heading. */ + for( xSpacePadding = strlen( "Task" ); xSpacePadding < ( configMAX_TASK_NAME_LEN - 3 ); xSpacePadding++ ) + { + /* Add a space to align columns after the task's name. */ + *pcWriteBuffer = ' '; + pcWriteBuffer++; + + /* Ensure always terminated. */ + *pcWriteBuffer = 0x00; + } + + strcpy( pcWriteBuffer, pcHeader ); + vTaskGetRunTimeStats( pcWriteBuffer + strlen( pcHeader ) ); + + /* There is no more data to return after this single string, so return + pdFALSE. */ + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvThreeParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +const char *pcParameter; +BaseType_t xParameterStringLength, xReturn; +static BaseType_t lParameterNumber = 0; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + if( lParameterNumber == 0 ) + { + /* The first time the function is called after the command has been + entered just a header string is returned. */ + sprintf( pcWriteBuffer, "The three parameters were:\r\n" ); + + /* Next time the function is called the first parameter will be echoed + back. */ + lParameterNumber = 1L; + + /* There is more data to be returned as no parameters have been echoed + back yet. */ + xReturn = pdPASS; + } + else + { + /* Obtain the parameter string. */ + pcParameter = FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + lParameterNumber, /* Return the next parameter. */ + &xParameterStringLength /* Store the parameter string length. */ + ); + + /* Sanity check something was returned. */ + configASSERT( pcParameter ); + + /* Return the parameter string. */ + memset( pcWriteBuffer, 0x00, xWriteBufferLen ); + sprintf( pcWriteBuffer, "%d: ", ( int ) lParameterNumber ); + strncat( pcWriteBuffer, pcParameter, xParameterStringLength ); + strncat( pcWriteBuffer, "\r\n", strlen( "\r\n" ) ); + + /* If this is the last of the three parameters then there are no more + strings to return after this one. */ + if( lParameterNumber == 3L ) + { + /* If this is the last of the three parameters then there are no more + strings to return after this one. */ + xReturn = pdFALSE; + lParameterNumber = 0L; + } + else + { + /* There are more parameters to return after this one. */ + xReturn = pdTRUE; + lParameterNumber++; + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +const char *pcParameter; +BaseType_t xParameterStringLength, xReturn; +static BaseType_t lParameterNumber = 0; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + if( lParameterNumber == 0 ) + { + /* The first time the function is called after the command has been + entered just a header string is returned. */ + sprintf( pcWriteBuffer, "The parameters were:\r\n" ); + + /* Next time the function is called the first parameter will be echoed + back. */ + lParameterNumber = 1L; + + /* There is more data to be returned as no parameters have been echoed + back yet. */ + xReturn = pdPASS; + } + else + { + /* Obtain the parameter string. */ + pcParameter = FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + lParameterNumber, /* Return the next parameter. */ + &xParameterStringLength /* Store the parameter string length. */ + ); + + if( pcParameter != NULL ) + { + /* Return the parameter string. */ + memset( pcWriteBuffer, 0x00, xWriteBufferLen ); + sprintf( pcWriteBuffer, "%d: ", ( int ) lParameterNumber ); + strncat( pcWriteBuffer, pcParameter, xParameterStringLength ); + strncat( pcWriteBuffer, "\r\n", strlen( "\r\n" ) ); + + /* There might be more parameters to return after this one. */ + xReturn = pdTRUE; + lParameterNumber++; + } + else + { + /* No more parameters were found. Make sure the write buffer does + not contain a valid string. */ + pcWriteBuffer[ 0 ] = 0x00; + + /* No more data to return. */ + xReturn = pdFALSE; + + /* Start over the next time this command is executed. */ + lParameterNumber = 0; + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +#if ipconfigSUPPORT_OUTGOING_PINGS == 1 + + static BaseType_t prvPingCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) + { + char * pcParameter; + BaseType_t lParameterStringLength, xReturn; + uint32_t ulIPAddress, ulBytesToPing; + const uint32_t ulDefaultBytesToPing = 8UL; + char cBuffer[ 16 ]; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + /* Start with an empty string. */ + pcWriteBuffer[ 0 ] = 0x00; + + /* Obtain the number of bytes to ping. */ + pcParameter = ( char * ) FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 2, /* Return the second parameter. */ + &lParameterStringLength /* Store the parameter string length. */ + ); + + if( pcParameter == NULL ) + { + /* The number of bytes was not specified, so default it. */ + ulBytesToPing = ulDefaultBytesToPing; + } + else + { + ulBytesToPing = atol( pcParameter ); + } + + /* Obtain the IP address string. */ + pcParameter = ( char * ) FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 1, /* Return the first parameter. */ + &lParameterStringLength /* Store the parameter string length. */ + ); + + /* Sanity check something was returned. */ + configASSERT( pcParameter ); + + /* Attempt to obtain the IP address. If the first character is not a + digit, assume the host name has been passed in. */ + if( ( *pcParameter >= '0' ) && ( *pcParameter <= '9' ) ) + { + ulIPAddress = FreeRTOS_inet_addr( pcParameter ); + } + else + { + /* Terminate the host name. */ + pcParameter[ lParameterStringLength ] = 0x00; + + /* Attempt to resolve host. */ + ulIPAddress = FreeRTOS_gethostbyname( pcParameter ); + } + + /* Convert IP address, which may have come from a DNS lookup, to string. */ + FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); + + if( ulIPAddress != 0 ) + { + xReturn = FreeRTOS_SendPingRequest( ulIPAddress, ( uint16_t ) ulBytesToPing, portMAX_DELAY ); + } + else + { + xReturn = pdFALSE; + } + + if( xReturn == pdFALSE ) + { + sprintf( pcWriteBuffer, "%s", "Could not send ping request\r\n" ); + } + else + { + sprintf( pcWriteBuffer, "Ping sent to %s with identifier %d\r\n", cBuffer, xReturn ); + } + + return pdFALSE; + } + /*-----------------------------------------------------------*/ + +#endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + +#if configINCLUDE_DEMO_DEBUG_STATS != 0 + + static BaseType_t prvDisplayIPDebugStats( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) + { + static BaseType_t xIndex = -1; + extern xExampleDebugStatEntry_t xIPTraceValues[]; + BaseType_t xReturn; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + xIndex++; + + if( xIndex < xExampleDebugStatEntries() ) + { + sprintf( pcWriteBuffer, "%s %d\r\n", xIPTraceValues[ xIndex ].pucDescription, ( int ) xIPTraceValues[ xIndex ].ulData ); + xReturn = pdPASS; + } + else + { + /* Reset the index for the next time it is called. */ + xIndex = -1; + + /* Ensure nothing remains in the write buffer. */ + pcWriteBuffer[ 0 ] = 0x00; + xReturn = pdFALSE; + } + + return xReturn; + } + /*-----------------------------------------------------------*/ + +#endif /* configINCLUDE_DEMO_DEBUG_STATS */ + +static BaseType_t prvDisplayIPConfig( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +static BaseType_t xIndex = 0; +BaseType_t xReturn; +uint32_t ulAddress; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + switch( xIndex ) + { + case 0 : + FreeRTOS_GetAddressConfiguration( &ulAddress, NULL, NULL, NULL ); + sprintf( pcWriteBuffer, "\r\nIP address " ); + xReturn = pdTRUE; + xIndex++; + break; + + case 1 : + FreeRTOS_GetAddressConfiguration( NULL, &ulAddress, NULL, NULL ); + sprintf( pcWriteBuffer, "\r\nNet mask " ); + xReturn = pdTRUE; + xIndex++; + break; + + case 2 : + FreeRTOS_GetAddressConfiguration( NULL, NULL, &ulAddress, NULL ); + sprintf( pcWriteBuffer, "\r\nGateway address " ); + xReturn = pdTRUE; + xIndex++; + break; + + case 3 : + FreeRTOS_GetAddressConfiguration( NULL, NULL, NULL, &ulAddress ); + sprintf( pcWriteBuffer, "\r\nDNS server address " ); + xReturn = pdTRUE; + xIndex++; + break; + + default : + ulAddress = 0; + sprintf( pcWriteBuffer, "\r\n\r\n" ); + xReturn = pdFALSE; + xIndex = 0; + break; + } + + if( ulAddress != 0 ) + { + FreeRTOS_inet_ntoa( ulAddress, &( pcWriteBuffer[ strlen( pcWriteBuffer ) ] ) ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +#if configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 + + static BaseType_t prvStartStopTraceCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) + { + const char *pcParameter; + BaseType_t lParameterStringLength; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + /* Obtain the parameter string. */ + pcParameter = FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 1, /* Return the first parameter. */ + &lParameterStringLength /* Store the parameter string length. */ + ); + + /* Sanity check something was returned. */ + configASSERT( pcParameter ); + + /* There are only two valid parameter values. */ + if( strncmp( pcParameter, "start", strlen( "start" ) ) == 0 ) + { + /* Start or restart the trace. */ + vTraceStop(); + vTraceClear(); + vTraceStart(); + + sprintf( pcWriteBuffer, "Trace recording (re)started.\r\n" ); + } + else if( strncmp( pcParameter, "stop", strlen( "stop" ) ) == 0 ) + { + /* End the trace, if one is running. */ + vTraceStop(); + sprintf( pcWriteBuffer, "Stopping trace recording.\r\n" ); + } + else + { + sprintf( pcWriteBuffer, "Valid parameters are 'start' and 'stop'.\r\n" ); + } + + /* There is no more data to return after this single string, so return + pdFALSE. */ + return pdFALSE; + } + +#endif /* configINCLUDE_TRACE_RELATED_CLI_COMMANDS */ diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/CLICommands/UDPCommandInterpreter.h b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/CLICommands/UDPCommandInterpreter.h new file mode 100644 index 000000000..2cd88c5a5 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/CLICommands/UDPCommandInterpreter.h @@ -0,0 +1,33 @@ +/* + * FreeRTOS Kernel V10.0.1 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef UDP_COMMAND_INTERPRETER_H +#define UDP_COMMAND_INTERPRETER_H + +void vStartUDPCommandInterpreterTask( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority ); + +#endif /* UDP_COMMAND_INTERPRETER_H */ diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/CLICommands/UDPCommandServer.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/CLICommands/UDPCommandServer.c new file mode 100644 index 000000000..8e84c34b4 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/CLICommands/UDPCommandServer.c @@ -0,0 +1,206 @@ +/* + * FreeRTOS Kernel V10.0.1 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+CLI includes. */ +#include "FreeRTOS_CLI.h" + +/* FreeRTOS+UDP includes. */ +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Demo app includes. */ +#include "UDPCommandInterpreter.h" + +/* Dimensions the buffer into which input characters are placed. */ +#define cmdMAX_INPUT_SIZE 60 + +/* Dimensions the buffer into which string outputs can be placed. */ +#define cmdMAX_OUTPUT_SIZE 1250 + +/* Dimensions the buffer passed to the recvfrom() call. */ +#define cmdSOCKET_INPUT_BUFFER_SIZE 60 + +/* + * The task that runs FreeRTOS+CLI. + */ +void vUDPCommandInterpreterTask( void *pvParameters ); + +/* + * Open and configure the UDP socket. + */ +static xSocket_t prvOpenUDPServerSocket( uint16_t usPort ); + +/*-----------------------------------------------------------*/ + +void vStartUDPCommandInterpreterTask( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority ) +{ + xTaskCreate( vUDPCommandInterpreterTask, "CLI", usStackSize, ( void * ) ulPort, uxPriority, NULL ); +} +/*-----------------------------------------------------------*/ + +/* + * Task that provides the input and output for the FreeRTOS+CLI command + * interpreter. In this case a UDP port is used. See the URL in the comments + * within main.c for the location of the online documentation. + */ +void vUDPCommandInterpreterTask( void *pvParameters ) +{ +long lBytes, lByte; +signed char cInChar, cInputIndex = 0; +static char cInputString[ cmdMAX_INPUT_SIZE ], cOutputString[ cmdMAX_OUTPUT_SIZE ], cLocalBuffer[ cmdSOCKET_INPUT_BUFFER_SIZE ]; +BaseType_t xMoreDataToFollow; +struct freertos_sockaddr xClient; +socklen_t xClientAddressLength = 0; /* This is required as a parameter to maintain the sendto() Berkeley sockets API - but it is not actually used so can take any value. */ +xSocket_t xSocket; + + /* Just to prevent compiler warnings. */ + ( void ) pvParameters; + + /* Attempt to open the socket. The port number is passed in the task + parameter. The strange casting is to remove compiler warnings on 32-bit + machines. */ + xSocket = prvOpenUDPServerSocket( ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL ); + + if( xSocket != FREERTOS_INVALID_SOCKET ) + { + for( ;; ) + { + /* Wait for incoming data on the opened socket. */ + lBytes = FreeRTOS_recvfrom( xSocket, ( void * ) cLocalBuffer, sizeof( cLocalBuffer ), 0, &xClient, &xClientAddressLength ); + + if( lBytes != FREERTOS_SOCKET_ERROR ) + { + /* Process each received byte in turn. */ + lByte = 0; + while( lByte < lBytes ) + { + /* The next character in the input buffer. */ + cInChar = cLocalBuffer[ lByte ]; + lByte++; + + /* Newline characters are taken as the end of the command + string. */ + if( cInChar == '\n' ) + { + /* Process the input string received prior to the + newline. */ + do + { + /* Pass the string to FreeRTOS+CLI. */ + xMoreDataToFollow = FreeRTOS_CLIProcessCommand( cInputString, cOutputString, cmdMAX_OUTPUT_SIZE ); + + /* Send the output generated by the command's + implementation. */ + FreeRTOS_sendto( xSocket, cOutputString, strlen( cOutputString ), 0, &xClient, xClientAddressLength ); + + } while( xMoreDataToFollow != pdFALSE ); /* Until the command does not generate any more output. */ + + /* All the strings generated by the command processing + have been sent. Clear the input string ready to receive + the next command. */ + cInputIndex = 0; + memset( cInputString, 0x00, cmdMAX_INPUT_SIZE ); + + /* Transmit a spacer, just to make the command console + easier to read. */ + FreeRTOS_sendto( xSocket, "\r\n", strlen( "\r\n" ), 0, &xClient, xClientAddressLength ); + } + else + { + if( cInChar == '\r' ) + { + /* Ignore the character. Newlines are used to + detect the end of the input string. */ + } + else if( cInChar == '\b' ) + { + /* Backspace was pressed. Erase the last character + in the string - if any. */ + if( cInputIndex > 0 ) + { + cInputIndex--; + cInputString[ cInputIndex ] = '\0'; + } + } + else + { + /* A character was entered. Add it to the string + entered so far. When a \n is entered the complete + string will be passed to the command interpreter. */ + if( cInputIndex < cmdMAX_INPUT_SIZE ) + { + cInputString[ cInputIndex ] = cInChar; + cInputIndex++; + } + } + } + } + } + } + } + else + { + /* The socket could not be opened. */ + vTaskDelete( NULL ); + } +} +/*-----------------------------------------------------------*/ + +static xSocket_t prvOpenUDPServerSocket( uint16_t usPort ) +{ +struct freertos_sockaddr xServer; +xSocket_t xSocket = FREERTOS_INVALID_SOCKET; + + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + if( xSocket != FREERTOS_INVALID_SOCKET) + { + /* Zero out the server structure. */ + memset( ( void * ) &xServer, 0x00, sizeof( xServer ) ); + + /* Set family and port. */ + xServer.sin_port = FreeRTOS_htons( usPort ); + + /* Bind the address to the socket. */ + if( FreeRTOS_bind( xSocket, &xServer, sizeof( xServer ) ) == -1 ) + { + FreeRTOS_closesocket( xSocket ); + xSocket = FREERTOS_INVALID_SOCKET; + } + } + + return xSocket; +} + + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/EchoClients/TwoEchoClients.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/EchoClients/TwoEchoClients.c new file mode 100644 index 000000000..286c1b127 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/EchoClients/TwoEchoClients.c @@ -0,0 +1,359 @@ +/* + * FreeRTOS Kernel V10.0.1 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +/****************************************************************************** + * + * See the following web page for essential TwoEchoClient.c usage and + * configuration details: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/Embedded_Ethernet_Examples/Common_Echo_Clients.shtml + * + ******************************************************************************/ + + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+UDP includes. */ +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Small delay used between attempts to obtain a zero copy buffer. */ +#define echoTINY_DELAY ( ( TickType_t ) 2 ) + +/* The echo tasks create a socket, send out a number of echo requests +(listening for each echo reply), then close the socket again before +starting over. This delay is used between each iteration to ensure the +network does not get too congested. */ +#define echoLOOP_DELAY ( ( TickType_t ) 250 / portTICK_RATE_MS ) + +#if ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 + /* When the trace recorder code is included user events are generated to + mark the sending and receiving of the echoed data (only in the zero copy + task. */ + #define echoMARK_SEND_IN_TRACE_BUFFER( x ) vTraceUserEvent( x ) + traceLabel xZeroCopySendEvent, xZeroCopyReceiveEvent; + +#else + /* When the trace recorder code is not included just #define away the call + to post the user event. */ + #define echoMARK_SEND_IN_TRACE_BUFFER( x ) + #define xZeroCopySendEvent 0 + #define xZeroCopyReceiveEvent 0 +#endif + +/* The echo server is assumed to be on port 7, which is the standard echo +protocol port. */ +#define echoECHO_PORT ( 7 ) + +/* + * Uses a socket to send data to, then receive data from, the standard echo + * port number 7. prvEchoClientTask() uses the standard interface. + * prvZeroCopyEchoClientTask() uses the zero copy interface. + */ +static void prvEchoClientTask( void *pvParameters ); +static void prvZeroCopyEchoClientTask( void *pvParameters ); + +/* The receive timeout is set shorter when the windows simulator is used +because simulated time is slower than real time. */ +#ifdef _WINDOWS_ + const TickType_t xReceiveTimeOut = 50 / portTICK_RATE_MS; +#else + const TickType_t xReceiveTimeOut = 500 / portTICK_RATE_MS; +#endif + +/*-----------------------------------------------------------*/ + +void vStartEchoClientTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ) +{ + /* Create the echo client task that does not use the zero copy interface. */ + xTaskCreate( prvEchoClientTask, /* The function that implements the task. */ + "Echo0", /* Just a text name for the task to aid debugging. */ + usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */ + NULL, /* The task parameter, not used in this case. */ + uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */ + NULL ); /* The task handle is not used. */ + + /* Create the echo client task that does use the zero copy interface. */ + xTaskCreate( prvZeroCopyEchoClientTask, /* The function that implements the task. */ + "Echo1", /* Just a text name for the task to aid debugging. */ + usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */ + NULL, /* The task parameter, not used in this case. */ + uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */ + NULL ); /* The task handle is not used. */ +} +/*-----------------------------------------------------------*/ + +static void prvEchoClientTask( void *pvParameters ) +{ +xSocket_t xSocket; +struct freertos_sockaddr xEchoServerAddress; +char cTxString[ 25 ], cRxString[ 25 ]; /* Make sure the stack is large enough to hold these. Turn on stack overflow checking during debug to be sure. */ +int32_t lLoopCount = 0UL; +const int32_t lMaxLoopCount = 50; +volatile uint32_t ulRxCount = 0UL, ulTxCount = 0UL; +uint32_t xAddressLength = sizeof( xEchoServerAddress ); + + /* Remove compiler warning about unused parameters. */ + ( void ) pvParameters; + + /* Echo requests are sent to the echo server. The address of the echo + server is configured by the constants configECHO_SERVER_ADDR0 to + configECHO_SERVER_ADDR3 in FreeRTOSConfig.h. */ + xEchoServerAddress.sin_port = FreeRTOS_htons( echoECHO_PORT ); + xEchoServerAddress.sin_addr = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0, + configECHO_SERVER_ADDR1, + configECHO_SERVER_ADDR2, + configECHO_SERVER_ADDR3 ); + + for( ;; ) + { + /* Create a socket. */ + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + configASSERT( xSocket != FREERTOS_INVALID_SOCKET ); + + /* Set a time out so a missing reply does not cause the task to block + indefinitely. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + + /* Send a number of echo requests. */ + for( lLoopCount = 0; lLoopCount < lMaxLoopCount; lLoopCount++ ) + { + /* Create the string that is sent to the echo server. */ + sprintf( cTxString, "Message number %u\r\n", ( unsigned int ) ulTxCount ); + + /* Send the string to the socket. ulFlags is set to 0, so the zero + copy interface is not used. That means the data from cTxString is + copied into a network buffer inside FreeRTOS_sendto(), and cTxString + can be reused as soon as FreeRTOS_sendto() has returned. 1 is added + to ensure the NULL string terminator is sent as part of the message. */ + FreeRTOS_sendto( xSocket, /* The socket being sent to. */ + ( void * ) cTxString, /* The data being sent. */ + strlen( cTxString ) + 1,/* The length of the data being sent. */ + 0, /* ulFlags with the FREERTOS_ZERO_COPY bit clear. */ + &xEchoServerAddress, /* The destination address. */ + sizeof( xEchoServerAddress ) ); + + /* Keep a count of how many echo requests have been transmitted so + it can be compared to the number of echo replies received. It would + be expected to loose at least one to an ARP message the first time + the connection is created. */ + ulTxCount++; + + /* Receive data echoed back to the socket. ulFlags is zero, so the + zero copy option is not being used and the received data will be + copied into the buffer pointed to by cRxString. xAddressLength is + not actually used (at the time of writing this comment, anyway) by + FreeRTOS_recvfrom(), but is set appropriately in case future + versions do use it. */ + memset( ( void * ) cRxString, 0x00, sizeof( cRxString ) ); + FreeRTOS_recvfrom( xSocket, /* The socket being received from. */ + cRxString, /* The buffer into which the received data will be written. */ + sizeof( cRxString ), /* The size of the buffer provided to receive the data. */ + 0, /* ulFlags with the FREERTOS_ZERO_COPY bit clear. */ + &xEchoServerAddress, /* The address from where the data was sent (the source address). */ + &xAddressLength ); + + /* Compare the transmitted string to the received string. */ + if( strcmp( cRxString, cTxString ) == 0 ) + { + /* The echo reply was received without error. */ + ulRxCount++; + } + }; + + /* Pause for a short while to ensure the network is not too + congested. */ + vTaskDelay( echoLOOP_DELAY ); + + /* Close this socket before looping back to create another. */ + FreeRTOS_closesocket( xSocket ); + } +} +/*-----------------------------------------------------------*/ + +static void prvZeroCopyEchoClientTask( void *pvParameters ) +{ +xSocket_t xSocket; +struct freertos_sockaddr xEchoServerAddress; +static char cTxString[ 40 ]; +int32_t lLoopCount = 0UL; +volatile uint32_t ulRxCount = 0UL, ulTxCount = 0UL; +uint32_t xAddressLength = sizeof( xEchoServerAddress ); +int32_t lReturned; +uint8_t *pucUDPPayloadBuffer; + +const int32_t lMaxLoopCount = 50; +const char * const pcStringToSend = "Zero copy message number"; +/* The buffer is large enough to hold the string, a number, and the string terminator. */ +const size_t xBufferLength = strlen( pcStringToSend ) + 15; + + #if ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 + { + /* When the trace recorder code is included user events are generated to + mark the sending and receiving of the echoed data (only in the zero copy + task). */ + xZeroCopySendEvent = xTraceOpenLabel( "ZeroCopyTx" ); + xZeroCopyReceiveEvent = xTraceOpenLabel( "ZeroCopyRx" ); + } + #endif /* ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS */ + + /* Remove compiler warning about unused parameters. */ + ( void ) pvParameters; + + /* Delay for a little while to ensure the task is out of synch with the + other echo task implemented above. */ + vTaskDelay( echoLOOP_DELAY >> 1 ); + + /* Echo requests are sent to the echo server. The address of the echo + server is configured by the constants configECHO_SERVER_ADDR0 to + configECHO_SERVER_ADDR3 in FreeRTOSConfig.h. */ + xEchoServerAddress.sin_port = FreeRTOS_htons( echoECHO_PORT ); + xEchoServerAddress.sin_addr = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0, + configECHO_SERVER_ADDR1, + configECHO_SERVER_ADDR2, + configECHO_SERVER_ADDR3 ); + + for( ;; ) + { + /* Create a socket. */ + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + configASSERT( xSocket != FREERTOS_INVALID_SOCKET ); + + /* Set a time out so a missing reply does not cause the task to block + indefinitely. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + + /* Send a number of echo requests. */ + for( lLoopCount = 0; lLoopCount < lMaxLoopCount; lLoopCount++ ) + { + /* This task is going to send using the zero copy interface. The + data being sent is therefore written directly into a buffer that is + passed by reference into the FreeRTOS_sendto() function. First + obtain a buffer of adequate size from the IP stack. Although a max + delay is used, the actual delay will be capped to + ipconfigMAX_SEND_BLOCK_TIME_TICKS, hence the test to ensure a buffer + was actually obtained. */ + pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xBufferLength, portMAX_DELAY ); + + if( pucUDPPayloadBuffer != NULL ) + { + /* A buffer was successfully obtained. Create the string that is + sent to the echo server. Note the string is written directly + into the buffer obtained from the IP stack. */ + sprintf( ( char * ) pucUDPPayloadBuffer, "%s %u\r\n", "Zero copy message number", ( unsigned int ) ulTxCount ); + + /* Also copy the string into a local buffer so it can be compared + with the string that is later received back from the echo server. */ + strcpy( cTxString, ( char * ) pucUDPPayloadBuffer ); + + /* Pass the buffer into the send function. ulFlags has the + FREERTOS_ZERO_COPY bit set so the IP stack will take control of + the buffer, rather than copy data out of the buffer. */ + echoMARK_SEND_IN_TRACE_BUFFER( xZeroCopySendEvent ); + lReturned = FreeRTOS_sendto( xSocket, /* The socket being sent to. */ + ( void * ) pucUDPPayloadBuffer, /* The buffer being passed into the IP stack. */ + strlen( cTxString ) + 1, /* The length of the data being sent. Plus 1 to ensure the null terminator is part of the data. */ + FREERTOS_ZERO_COPY, /* ulFlags with the zero copy bit is set. */ + &xEchoServerAddress, /* Where the data is being sent. */ + sizeof( xEchoServerAddress ) ); + + if( lReturned == 0 ) + { + /* The send operation failed, so this task is still + responsible for the buffer obtained from the IP stack. To + ensure the buffer is not lost it must either be used again, + or, as in this case, returned to the IP stack using + FreeRTOS_ReleaseUDPPayloadBuffer(). pucUDPPayloadBuffer can + be safely re-used to receive from the socket below once the + buffer has been returned to the stack. */ + FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer ); + } + else + { + /* The send was successful so the IP stack is now managing + the buffer pointed to by pucUDPPayloadBuffer, and the IP + stack will return the buffer once it has been sent. + pucUDPPayloadBuffer can be safely re-used to receive from + the socket below. */ + } + + /* Keep a count of how many echo requests have been transmitted + so it can be compared to the number of echo replies received. + It would be expected to loose at least one to an ARP message the + first time the connection is created. */ + ulTxCount++; + + /* Receive data on the socket. ulFlags has the zero copy bit set + (FREERTOS_ZERO_COPY) indicating to the stack that a reference to + the received data should be passed out to this task using the + second parameter to the FreeRTOS_recvfrom() call. When this is + done the IP stack is no longer responsible for releasing the + buffer, and the task *must* return the buffer to the stack when + it is no longer needed. By default the receive block time is + portMAX_DELAY. */ + echoMARK_SEND_IN_TRACE_BUFFER( xZeroCopyReceiveEvent ); + lReturned = FreeRTOS_recvfrom( xSocket, /* The socket to receive from. */ + ( void * ) &pucUDPPayloadBuffer, /* pucUDPPayloadBuffer will be set to point to the buffer that already contains the received data. */ + 0, /* Ignored because the zero copy interface is being used. */ + FREERTOS_ZERO_COPY, /* ulFlags with the FREERTOS_ZERO_COPY bit set. */ + &xEchoServerAddress, /* The address from which the data was sent. */ + &xAddressLength ); + + if( lReturned > 0 ) + { + /* Compare the string sent to the echo server with the string + received back from the echo server. */ + if( strcmp( ( char * ) pucUDPPayloadBuffer, cTxString ) == 0 ) + { + /* The strings matched. */ + ulRxCount++; + } + + /* The buffer that contains the data passed out of the stack + *must* be returned to the stack. */ + FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer ); + } + } + } + + /* Pause for a short while to ensure the network is not too + congested. */ + vTaskDelay( echoLOOP_DELAY ); + + /* Close this socket before looping back to create another. */ + FreeRTOS_closesocket( xSocket ); + } +} +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/EchoClients/TwoEchoClients.h b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/EchoClients/TwoEchoClients.h new file mode 100644 index 000000000..dca98ac20 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/EchoClients/TwoEchoClients.h @@ -0,0 +1,38 @@ +/* + * FreeRTOS Kernel V10.0.1 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef TWO_ECHO_CLIENTS_H +#define TWO_ECHO_CLIENTS_H + +/* + * Create the two UDP echo client tasks. One task uses the standard interface + * to send to and receive from an echo server. The other task uses the zero + * copy interface to send to and receive from an echo server. + */ +void vStartEchoClientTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ); + +#endif /* TWO_ECHO_CLIENTS_H */ diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/TraceMacros/Example1/DemoIPTrace.c b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/TraceMacros/Example1/DemoIPTrace.c new file mode 100644 index 000000000..4fff3ac65 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/TraceMacros/Example1/DemoIPTrace.c @@ -0,0 +1,150 @@ +/* + * FreeRTOS Kernel V10.0.1 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * This file, along with DemoIPTrace.h, provides a basic example use of the + * FreeRTOS+UDP trace macros. The statistics gathered here can be viewed in + * the command line interface. + * See http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/UDP_IP_Trace.shtml + */ + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+UDP includes. */ +#include "FreeRTOS_UDP_IP.h" +#include "DemoIPTrace.h" + +/* It is possible to remove the trace macros using the +configINCLUDE_DEMO_DEBUG_STATS setting in FreeRTOSIPConfig.h. */ +#if configINCLUDE_DEMO_DEBUG_STATS == 1 + +/* + * Each row in the xIPTraceValues[] table contains a pointer to a function that + * updates the value for that row. Rows that latch the lowest value point to + * this function (for example, this function can be used to latch the lowest + * number of network buffers that were available during the execution of the + * stack). + */ +static void prvStoreLowest( uint32_t *pulCurrentValue, uint32_t ulCount ); + +/* + * Each row in the xIPTraceValues[] table contains a pointer to a function that + * updates the value for that row. Rows that simply increment an event count + * point to this function. + */ +static void prvIncrementEventCount( uint32_t *pulCurrentValue, uint32_t ulCount ); + + +xExampleDebugStatEntry_t xIPTraceValues[] = +{ + /* Comment out array entries to remove individual trace items. */ + + { iptraceID_NETWORK_INTERFACE_RECEIVE, ( const uint8_t * const ) "Packets received by the network interface", prvIncrementEventCount, 0 }, + { iptraceID_NETWORK_INTERFACE_TRANSMIT, ( const uint8_t * const ) "Count of transmitted packets", prvIncrementEventCount, 0 }, + { iptraceID_PACKET_DROPPED_TO_GENERATE_ARP, ( const uint8_t * const ) "Count of packets dropped to generate ARP", prvIncrementEventCount, 0 }, + { iptraceID_NETWORK_BUFFER_OBTAINED, ( const uint8_t * const ) "Lowest ever available network buffers", prvStoreLowest, 0xffffUL }, + { iptraceID_NETWORK_EVENT_RECEIVED, ( const uint8_t * const ) "Lowest ever free space in network event queue", prvStoreLowest, 0xffffUL }, + { iptraceID_FAILED_TO_OBTAIN_NETWORK_BUFFER, ( const uint8_t * const ) "Count of failed attempts to obtain a network buffer",prvIncrementEventCount, 0 }, + { iptraceID_ARP_TABLE_ENTRY_EXPIRED, ( const uint8_t * const ) "Count of expired ARP entries", prvIncrementEventCount, 0 }, + { iptraceID_FAILED_TO_CREATE_SOCKET, ( const uint8_t * const ) "Count of failures to create a socket", prvIncrementEventCount, 0 }, + { iptraceID_RECVFROM_DISCARDING_BYTES, ( const uint8_t * const ) "Count of times recvfrom() has discarding bytes", prvIncrementEventCount, 0 }, + { iptraceID_ETHERNET_RX_EVENT_LOST, ( const uint8_t * const ) "Count of lost Ethenret Rx events (event queue full?)",prvIncrementEventCount, 0 }, + { iptraceID_STACK_TX_EVENT_LOST, ( const uint8_t * const ) "Count of lost IP stack events (event queue full?)", prvIncrementEventCount, 0 }, + { ipconfigID_BIND_FAILED, ( const uint8_t * const ) "Count of failed calls to bind()", prvIncrementEventCount, 0 }, + { iptraceID_RECVFROM_TIMEOUT, ( const uint8_t * const ) "Count of receive timeouts", prvIncrementEventCount, 0 }, + { iptraceID_SENDTO_DATA_TOO_LONG, ( const uint8_t * const ) "Count of failed sends due to oversized payload", prvIncrementEventCount, 0 }, + { iptraceID_SENDTO_SOCKET_NOT_BOUND, ( const uint8_t * const ) "Count of failed sends due to unbound socket", prvIncrementEventCount, 0 }, + { iptraceID_NO_BUFFER_FOR_SENDTO, ( const uint8_t * const ) "Count of failed transmits due to timeout", prvIncrementEventCount, 0 }, + { iptraceID_WAIT_FOR_TX_DMA_DESCRIPTOR, ( const uint8_t * const ) "Number of times task had to wait to obtain a DMA Tx descriptor", prvIncrementEventCount, 0 }, + { iptraceID_FAILED_TO_NOTIFY_SELECT_GROUP, ( const uint8_t * const ) "Failed to notify select group", prvIncrementEventCount, 0 } +}; + +/*-----------------------------------------------------------*/ + +BaseType_t xExampleDebugStatEntries( void ) +{ + /* Return the number of entries in the xIPTraceValues[] table. */ + return ( BaseType_t ) ( sizeof( xIPTraceValues ) / sizeof( xExampleDebugStatEntry_t ) ); +} +/*-----------------------------------------------------------*/ + +void vExampleDebugStatUpdate( uint8_t ucIdentifier, uint32_t ulValue ) +{ +BaseType_t xIndex; +const BaseType_t xEntries = sizeof( xIPTraceValues ) / sizeof( xExampleDebugStatEntry_t ); + + /* Update an entry in the xIPTraceValues[] table. Each row in the table + includes a pointer to a function that performs the actual update. This + function just executes the update function from that table row. */ + for( xIndex = 0; xIndex < xEntries; xIndex++ ) + { + if( xIPTraceValues[ xIndex ].ucIdentifier == ucIdentifier ) + { + xIPTraceValues[ xIndex ].vPerformAction( &( xIPTraceValues[ xIndex ].ulData ), ulValue ); + break; + } + } + + configASSERT( xIndex != xEntries ); +} +/*-----------------------------------------------------------*/ + +static void prvIncrementEventCount( uint32_t *pulCurrentValue, uint32_t ulCount ) +{ + /* Each row in the xIPTraceValues[] table contains a pointer to a function + that updates the value for that row. Rows that simply increment an event + count point to this function. */ + ( void ) ulCount; + ( *pulCurrentValue )++; +} +/*-----------------------------------------------------------*/ + +static void prvStoreLowest( uint32_t *pulCurrentValue, uint32_t ulCount ) +{ + /* Each row in the xIPTraceValues[] table contains a pointer to a function + that updates the value for that row. Rows that latch the lowest value + point to this function (for example, this function can be used to latch + the lowest number of network buffers that were available during the + execution of the stack). */ + if( ulCount < *pulCurrentValue ) + { + *pulCurrentValue = ulCount; + } +} +/*-----------------------------------------------------------*/ + + +#endif /* configINCLUDE_DEMO_DEBUG_STATS == 1 */ + + + + diff --git a/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/TraceMacros/Example1/DemoIPTrace.h b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/TraceMacros/Example1/DemoIPTrace.h new file mode 100644 index 000000000..17a6f394c --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/FreeRTOS_Plus_UDP_Demos/TraceMacros/Example1/DemoIPTrace.h @@ -0,0 +1,121 @@ +/* + * FreeRTOS Kernel V10.0.1 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * This file, along with DemoIPTrace.h, provides a basic example use of the + * FreeRTOS+UDP trace macros. The statistics gathered here can be viewed in + * the command line interface. + * See http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/UDP_IP_Trace.shtml + */ + +#ifndef DEMO_IP_TRACE_MACROS_H +#define DEMO_IP_TRACE_MACROS_H + +typedef void ( *vTraceAction_t )( uint32_t *, uint32_t ); + +/* Type that defines each statistic being gathered. */ +typedef struct ExampleDebugStatEntry +{ + uint8_t ucIdentifier; /* Unique identifier for statistic. */ + const uint8_t * const pucDescription; /* Text description for the statistic. */ + vTraceAction_t vPerformAction; /* Action to perform when the statistic is updated (increment counter, store minimum value, store maximum value, etc. */ + uint32_t ulData; /* The meaning of this data is dependent on the trace macro ID. */ +} xExampleDebugStatEntry_t; + +/* Unique identifiers used to locate the entry for each trace macro in the +xIPTraceValues[] table defined in DemoIPTrace.c. */ +#define iptraceID_NETWORK_INTERFACE_RECEIVE 0 +#define iptraceID_NETWORK_INTERFACE_TRANSMIT 1 +#define iptraceID_PACKET_DROPPED_TO_GENERATE_ARP 2 +/* Do not change IDs above this line as the ID is shared with a FreeRTOS+Nabto +demo. */ +#define iptraceID_NETWORK_BUFFER_OBTAINED 3 +#define iptraceID_NETWORK_BUFFER_OBTAINED_FROM_ISR 4 +#define iptraceID_NETWORK_EVENT_RECEIVED 5 +#define iptraceID_FAILED_TO_OBTAIN_NETWORK_BUFFER 6 +#define iptraceID_ARP_TABLE_ENTRY_EXPIRED 7 +#define iptraceID_FAILED_TO_CREATE_SOCKET 8 +#define iptraceID_RECVFROM_DISCARDING_BYTES 9 +#define iptraceID_ETHERNET_RX_EVENT_LOST 10 +#define iptraceID_STACK_TX_EVENT_LOST 11 +#define ipconfigID_BIND_FAILED 12 +#define iptraceID_RECVFROM_TIMEOUT 13 +#define iptraceID_SENDTO_DATA_TOO_LONG 14 +#define iptraceID_SENDTO_SOCKET_NOT_BOUND 15 +#define iptraceID_NO_BUFFER_FOR_SENDTO 16 +#define iptraceID_WAIT_FOR_TX_DMA_DESCRIPTOR 17 +#define iptraceID_FAILED_TO_NOTIFY_SELECT_GROUP 18 + +/* It is possible to remove the trace macros using the +configINCLUDE_DEMO_DEBUG_STATS setting in FreeRTOSIPConfig.h. */ +#if configINCLUDE_DEMO_DEBUG_STATS == 1 + + /* The trace macro definitions themselves. Any trace macros left undefined + will default to be empty macros. */ + #define iptraceNETWORK_BUFFER_OBTAINED( pxBufferAddress ) vExampleDebugStatUpdate( iptraceID_NETWORK_BUFFER_OBTAINED, uxQueueMessagesWaiting( ( xQueueHandle ) xNetworkBufferSemaphore ) ) + #define iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxBufferAddress ) vExampleDebugStatUpdate( iptraceID_NETWORK_BUFFER_OBTAINED, uxQueueMessagesWaiting( ( xQueueHandle ) xNetworkBufferSemaphore ) ) + + #define iptraceNETWORK_EVENT_RECEIVED( eEvent ) { \ + uint16_t usSpace; \ + usSpace = ( uint16_t ) uxQueueMessagesWaiting( xNetworkEventQueue ); \ + /* Minus one as an event was removed before the space was queried. */ \ + usSpace = ( ipconfigEVENT_QUEUE_LENGTH - usSpace ) - 1; \ + vExampleDebugStatUpdate( iptraceID_NETWORK_EVENT_RECEIVED, usSpace ); \ + } + + #define iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER() vExampleDebugStatUpdate( iptraceID_FAILED_TO_OBTAIN_NETWORK_BUFFER, 0 ) + #define iptraceARP_TABLE_ENTRY_EXPIRED( ulIPAddress ) vExampleDebugStatUpdate( iptraceID_ARP_TABLE_ENTRY_EXPIRED, 0 ) + #define iptracePACKET_DROPPED_TO_GENERATE_ARP( ulIPAddress ) vExampleDebugStatUpdate( iptraceID_PACKET_DROPPED_TO_GENERATE_ARP, 0 ) + #define iptraceFAILED_TO_CREATE_SOCKET() vExampleDebugStatUpdate( iptraceID_FAILED_TO_CREATE_SOCKET, 0 ) + #define iptraceRECVFROM_DISCARDING_BYTES( xNumberOfBytesDiscarded ) vExampleDebugStatUpdate( iptraceID_RECVFROM_DISCARDING_BYTES, 0 ) + #define iptraceETHERNET_RX_EVENT_LOST() vExampleDebugStatUpdate( iptraceID_ETHERNET_RX_EVENT_LOST, 0 ) + #define iptraceSTACK_TX_EVENT_LOST( xEvent ) vExampleDebugStatUpdate( iptraceID_STACK_TX_EVENT_LOST, 0 ) + #define iptraceBIND_FAILED( xSocket, usPort ) vExampleDebugStatUpdate( ipconfigID_BIND_FAILED, 0 ) + #define iptraceNETWORK_INTERFACE_TRANSMIT() vExampleDebugStatUpdate( iptraceID_NETWORK_INTERFACE_TRANSMIT, 0 ) + #define iptraceRECVFROM_TIMEOUT() vExampleDebugStatUpdate( iptraceID_RECVFROM_TIMEOUT, 0 ) + #define iptraceSENDTO_DATA_TOO_LONG() vExampleDebugStatUpdate( iptraceID_SENDTO_DATA_TOO_LONG, 0 ) + #define iptraceSENDTO_SOCKET_NOT_BOUND() vExampleDebugStatUpdate( iptraceID_SENDTO_SOCKET_NOT_BOUND, 0 ) + #define iptraceNO_BUFFER_FOR_SENDTO() vExampleDebugStatUpdate( iptraceID_NO_BUFFER_FOR_SENDTO, 0 ) + #define iptraceWAITING_FOR_TX_DMA_DESCRIPTOR() vExampleDebugStatUpdate( iptraceID_WAIT_FOR_TX_DMA_DESCRIPTOR, 0 ) + #define iptraceFAILED_TO_NOTIFY_SELECT_GROUP( xSocket ) vExampleDebugStatUpdate( iptraceID_FAILED_TO_NOTIFY_SELECT_GROUP, 0 ) + #define iptraceNETWORK_INTERFACE_RECEIVE() vExampleDebugStatUpdate( iptraceID_NETWORK_INTERFACE_RECEIVE, 0 ) + + /* + * The function that updates a line in the xIPTraceValues table. + */ + void vExampleDebugStatUpdate( uint8_t ucIdentifier, uint32_t ulValue ); + + /* + * Returns the number of entries in the xIPTraceValues table. + */ + BaseType_t xExampleDebugStatEntries( void ); + +#endif /* configINCLUDE_DEMO_DEBUG_STATS == 1 */ + + +#endif /* DEMO_IP_TRACE_MACROS_H */ + diff --git a/FreeRTOS-Labs/Demo/Common/ReadMe.txt b/FreeRTOS-Labs/Demo/Common/ReadMe.txt new file mode 100644 index 000000000..126bbfe90 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/ReadMe.txt @@ -0,0 +1,2 @@ +Contains examples and other files that are used by multiple demos, running on +multiple hardware platforms. diff --git a/FreeRTOS-Labs/Demo/Common/Utilities/UDPLoggingPrintf.c b/FreeRTOS-Labs/Demo/Common/Utilities/UDPLoggingPrintf.c new file mode 100644 index 000000000..73ffa3c58 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Utilities/UDPLoggingPrintf.c @@ -0,0 +1,502 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * Logging utility that allows FreeRTOS tasks to log to a UDP port. + * + * Logging print calls generate messages that are buffered in a stream buffer. + * A background task then retrieves messages from the stream buffer and sends + * them to a UDP port. + */ + +/* Standard includes. */ +#include +#include +#include +#include + +/* Scheduler include files. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_tcp_server.h" +#include "FreeRTOS_Stream_Buffer.h" +#include "FreeRTOS_DHCP.h" +#include "NetworkInterface.h" + +/* Demo includes. */ +#include "hr_gettime.h" +#include "UDPLoggingPrintf.h" + +/* Set to 1 to end each line with \r\n, or 0 for just \n. */ +#ifndef configUDP_LOGGING_NEEDS_CR_LF + #define configUDP_LOGGING_NEEDS_CR_LF ( 0 ) +#endif + +/* The maximum string length for each logged message. */ +#ifndef configUDP_LOGGING_STRING_LENGTH + #define configUDP_LOGGING_STRING_LENGTH ( 200 ) +#endif + +/* The maximum number of messages that can be buffered at any one time. */ +#ifndef configUDP_LOGGING_MAX_MESSAGES_IN_BUFFER + #define configUDP_LOGGING_MAX_MESSAGES_IN_BUFFER ( 30 ) +#endif + +#ifndef configUDP_LOGGING_TASK_STACK_SIZE + #define configUDP_LOGGING_TASK_STACK_SIZE ( 512 ) +#endif + +#ifndef configUDP_LOGGING_TASK_PRIORITY + #define configUDP_LOGGING_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 ) +#endif + +/* configUDP_LOGGING_PORT_REMOTE is the port number to which the logging +will be sent. */ +#ifndef configUDP_LOGGING_PORT_REMOTE + #error configUDP_LOGGING_PORT_REMOTE must be defined in FreeRTOSconfig.h to use UDP logging +#endif + +/* configUDP_LOGGING_PORT_LOCAL is the port number to which the +socket will be bound. It is possible to send messages to +this socket. */ +#ifndef configUDP_LOGGING_PORT_LOCAL + /* If not defined, the UDP socket will be bound to a random port number. + If you want to use a specific port number, please define so in FreeRTOSconfig.h */ + #define configUDP_LOGGING_PORT_LOCAL 0 +#endif + +/* The logging task's block time. This is used as the UDP socket's send block +time, and the maximum time the logging task will spend in the Blocked state +waiting to be notified of a new message to send before manually looking for a +message. */ +#ifndef logUDP_LOGGING_BLOCK_TIME_MS + #define logUDP_LOGGING_BLOCK_TIME_MS ( 1000ul ) +#endif + +/* Log messages are cached in a stream buffer. The stream buffer's storage +area is dimensioned to contain the maximum number of strings of the maximum +string length. */ +#define logMESSAGE_BUFFER_SIZE_BYTES ( ( configUDP_LOGGING_STRING_LENGTH ) * ( configUDP_LOGGING_MAX_MESSAGES_IN_BUFFER ) ) + +/* Ascii characters used in this file. */ +#define logASCII_CR ( 13 ) +#define logASCII_NL ( 10 ) + +#ifndef iptraceUDP_LOGGING_TASK_STARTING + /* This macro will be called once when the UDP logging task is starting up. */ + #define iptraceUDP_LOGGING_TASK_STARTING() do { } while( 0 ) +#endif +/*-----------------------------------------------------------*/ + +/* + * Called automatically to create the stream buffer. + */ +static BaseType_t prvInitialiseLogging( void ); + +/* + * The task that reads messages from the stream buffer and sends them to the + * UDP port. + */ +static void prvLoggingTask( void *pvParameters ); + +/* + * Obtain a message from the stream buffer. + */ +static size_t prvGetMessageFromStreamBuffer( char *pcBuffer, size_t xBufferLength ); + +/* + * Generate a formatted string and add it to the stream buffer ready for the + * logging task to transmit. + */ +static size_t prvBufferFormattedString( const char *pcFormatString, va_list xArgs ); + +/*-----------------------------------------------------------*/ + +/* Is this structure used anywhere? */ +typedef struct LogStruct +{ + size_t xLength; + + #if LOGBUF_SHOW_US + uint64_t ullLogTime; + #else + uint32_t ulLogTime; + #endif + uint32_t ulPriority; + +} LogStruct_t; + +typedef struct LogUnit_t +{ + LogStruct_t xHeader; + char cMessage[ configUDP_LOGGING_STRING_LENGTH ]; + +} LogUnit_t; + +static LogUnit_t xLogEntry; +static StreamBuffer_t *pxStreamBuffer = NULL; +static TaskHandle_t xLoggingTask = NULL; +static xSocket_t xUDPLoggingSocket = FREERTOS_INVALID_SOCKET; + +/*-----------------------------------------------------------*/ + +static BaseType_t prvInitialiseLogging( void ) +{ +size_t xSize; +static BaseType_t xLoggingInitialised = pdFALSE; + + if( xLoggingInitialised == pdFALSE ) + { + /* Don't attempt to log unless the scheduler is running. */ + if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING ) + { + /* Create a stream buffer large enough for the maximum number of + bytes + 1. */ /*_RB_ Why is the size of pxStreamBuffer->ucArray + subtracted here? */ + xSize = sizeof( StreamBuffer_t ) - sizeof( pxStreamBuffer->ucArray ) + logMESSAGE_BUFFER_SIZE_BYTES + 1; + pxStreamBuffer = pvPortMalloc( xSize ); + + if( pxStreamBuffer != NULL ) + { + memset( pxStreamBuffer, '\0', xSize ); + pxStreamBuffer->LENGTH = logMESSAGE_BUFFER_SIZE_BYTES + 1; + + xLoggingInitialised = pdTRUE; + } + } + } + + return xLoggingInitialised; +} +/*-----------------------------------------------------------*/ + +static size_t prvGetMessageFromStreamBuffer( char* pcBuffer, size_t xBufferLength ) +{ +size_t uxLength; +size_t xMessageLength = 0; + + if( pxStreamBuffer != NULL ) + { + /* Is there data in the stream buffer? */ + uxLength = uxStreamBufferGetSize( pxStreamBuffer ); + if( uxLength > sizeof( size_t ) ) + { + /* Avoid concurrent access to the buffer. */ + vTaskSuspendAll(); + { + /* Every message is stored as a length followed by the string. + Obtain the length of the data first. */ + uxStreamBufferGet( pxStreamBuffer, 0, ( uint8_t * ) &xMessageLength, sizeof( xMessageLength ), pdFALSE ); + + if( xBufferLength < xMessageLength ) + { + /* The 'pcBuffer' provided by the caller is too small. Load + the message first into 'xLogEntry.message', and then copy + as much as possible to 'pcBuffer'. */ + uxStreamBufferGet( pxStreamBuffer, 0, ( uint8_t * ) xLogEntry.cMessage, xMessageLength, pdFALSE ); + memcpy( pcBuffer, xLogEntry.cMessage, xBufferLength ); + xMessageLength = xBufferLength; + + /* Terminate the string at the very end of the buffer. */ + pcBuffer[ xBufferLength - 1 ] = 0x00; + } + else + { + /* The 'pcBuffer' provided by the caller is big enough. */ + uxStreamBufferGet( pxStreamBuffer, 0, ( uint8_t * ) pcBuffer, xMessageLength, pdFALSE ); + + /* Terminate the string after the string's last character. */ + pcBuffer[ xMessageLength ] = 0x00; + } + } + xTaskResumeAll(); + } + } + + return xMessageLength; +} +/*-----------------------------------------------------------*/ + +static size_t prvBufferFormattedString( const char *pcFormatString, va_list xArgs ) +{ +size_t xLength, xSpace; +uint64_t ullCurrentTime; +uint32_t ulSeconds, ulMilliSeconds, ulMicroSeconds; + + /* Sanity check. */ + configASSERT( pxStreamBuffer ); + + vTaskSuspendAll(); + { + ullCurrentTime = ullGetHighResolutionTime(); + ulSeconds = ( uint32_t ) ( ullCurrentTime / 1000000ull ); + ullCurrentTime = ullCurrentTime % 1000000ull; + ulMilliSeconds = ( uint32_t ) ( ullCurrentTime / 1000ull ); + ulMicroSeconds = ( uint32_t ) ( ullCurrentTime % 1000ull ); + + xLength = ( size_t ) snprintf( xLogEntry.cMessage, sizeof( xLogEntry.cMessage ), "%4u.%03u.%03u [%-10s] ", + ( unsigned int ) ulSeconds, ( unsigned int ) ulMilliSeconds, ( unsigned int ) ulMicroSeconds, pcTaskGetTaskName( NULL ) ); + xLength += ( size_t ) vsnprintf( xLogEntry.cMessage + xLength, sizeof( xLogEntry.cMessage ) - xLength, pcFormatString, xArgs ); + + xSpace = uxStreamBufferGetSpace( pxStreamBuffer ); + + if( xSpace > ( xLength + sizeof( BaseType_t ) ) ) + { + uxStreamBufferAdd( pxStreamBuffer, 0, ( const uint8_t * ) &xLength, sizeof( xLength ) ); + uxStreamBufferAdd( pxStreamBuffer, 0, ( const uint8_t * ) ( xLogEntry.cMessage ), xLength ); + } + } + xTaskResumeAll(); + + if( xLoggingTask != NULL ) + { + /* Unblock the logging task so it can output the message. */ + xTaskNotifyGive( xLoggingTask ); + } + + return xLength; +} +/*-----------------------------------------------------------*/ + +int lUDPLoggingPrintf( const char *pcFormatString, ... ) +{ +size_t xLength; + + if( prvInitialiseLogging() != pdFALSE ) + { + va_list args; + va_start (args, pcFormatString); + xLength = prvBufferFormattedString (pcFormatString, args); + va_end (args); + } + else + { + xLength = 0; + } + + return ( int ) xLength; +} +/*-----------------------------------------------------------*/ + +void vUDPLoggingTaskCreate( void ) +{ + /* Start a task which will send out the logging lines to a UDP address. */ + xTaskCreate( prvLoggingTask, "LogTask", configUDP_LOGGING_TASK_STACK_SIZE, NULL, configUDP_LOGGING_TASK_PRIORITY, &xLoggingTask ); +} +/*-----------------------------------------------------------*/ + +xSocket_t xLoggingGetSocket( void ) +{ +xSocket_t xReturn; + + if( ( xUDPLoggingSocket != NULL ) && ( xUDPLoggingSocket != FREERTOS_INVALID_SOCKET ) ) + { + xReturn = xUDPLoggingSocket; + } + else + { + xReturn = NULL; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void prvLoggingTask( void *pvParameters ) +{ +TickType_t xBlockingTime = pdMS_TO_TICKS( logUDP_LOGGING_BLOCK_TIME_MS ); +struct freertos_sockaddr xLocalAddress, xRemoteAddress; +BaseType_t xSendTimeOut; +int32_t lLines; +size_t xCount; +static char cLoggingLine[ configUDP_LOGGING_STRING_LENGTH ]; +const TickType_t xResolveDelay = pdMS_TO_TICKS( ( TickType_t ) 250 ); + + /* Prevent compiler warnings about unused parameters. */ + ( void ) pvParameters; + + /* A possibility to set some additional task properties. */ + iptraceUDP_LOGGING_TASK_STARTING(); + + xRemoteAddress.sin_port = FreeRTOS_htons( configUDP_LOGGING_PORT_REMOTE ); + #if defined( configUDP_LOGGING_ADDR0 ) + { + /* Use a fixed address to where the logging will be sent. */ + xRemoteAddress.sin_addr = FreeRTOS_inet_addr_quick( configUDP_LOGGING_ADDR0, + configUDP_LOGGING_ADDR1, + configUDP_LOGGING_ADDR2, + configUDP_LOGGING_ADDR3 ); + } + #else + { + /* The logging will be broadcasted on the local broadcasting + address, such as 192.168.0.255 */ + xRemoteAddress.sin_addr = FreeRTOS_GetIPAddress() | ~( FreeRTOS_GetNetmask() ); + } + #endif + + /* Loop until a socket is created. */ + do + { + vTaskDelay( xBlockingTime ); + xUDPLoggingSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + } while( xUDPLoggingSocket == FREERTOS_INVALID_SOCKET ); + + xLocalAddress.sin_port = FreeRTOS_htons( configUDP_LOGGING_PORT_LOCAL ); + xLocalAddress.sin_addr = FreeRTOS_GetIPAddress(); + + FreeRTOS_bind( xUDPLoggingSocket, &xLocalAddress, sizeof( xLocalAddress ) ); + + xSendTimeOut = xBlockingTime; + FreeRTOS_setsockopt( xUDPLoggingSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + + /* Send a dummy message to resolve the IP address before sending the logging + messages. */ + snprintf( cLoggingLine, configUDP_LOGGING_STRING_LENGTH, "Logging Probe\n" ); + FreeRTOS_sendto( xUDPLoggingSocket, ( void * ) cLoggingLine, strlen( cLoggingLine ), 0, &xRemoteAddress, sizeof( xRemoteAddress ) ); + vTaskDelay( xResolveDelay ); + + for( ;; ) + { + /* Wait for another message to be placed into the stream buffer. */ + ulTaskNotifyTake( pdTRUE, xBlockingTime ); + + if( xGetPhyLinkStatus() != pdFALSE ) + { + /* Check for messages in the buffer. */ + for( lLines = 0; lLines < configUDP_LOGGING_MAX_MESSAGES_IN_BUFFER; lLines++ ) + { + xCount = prvGetMessageFromStreamBuffer ( cLoggingLine, sizeof( cLoggingLine ) ); + + if( xCount <= 0 ) + { + break; + } + + #if( configUDP_LOGGING_NEEDS_CR_LF != 0 ) + { + char *pcTarget; + const char *pcSource; + + /* Within the code, a single "\n" is used to denote a + newline. If 'configUDP_LOGGING_NEEDS_CR_LF' is defined as non-zero, + every "\n" will be translated into a "\r\n". */ + pcTarget = cLoggingLine; + pcSource = cLoggingLine; + + while( ( *pcSource != 0x00 ) && ( pcSource < ( cLoggingLine + xCount ) ) ) + { + *pcTarget = *pcSource; + + if( ( ( pcSource == cLoggingLine ) || ( pcSource[ -1 ] != logASCII_CR ) ) && ( pcSource[ 0 ] == logASCII_NL ) ) + { + pcTarget[ 0 ] = logASCII_CR; + pcTarget[ 1 ] = logASCII_NL; + + if( xCount < ( sizeof( cLoggingLine ) - 1 ) ) + { + xCount++; + pcTarget++; + } + } + + pcTarget++; + pcSource++; + } + } + #endif + + FreeRTOS_sendto( xUDPLoggingSocket, ( void * ) cLoggingLine, xCount, 0, &xRemoteAddress, sizeof( xRemoteAddress ) ); + } + } + } +} +/*-----------------------------------------------------------*/ + +void vUDPLoggingFlush( void ) +{ +const TickType_t xDelay = pdMS_TO_TICKS( 20UL ); + + /* In some situations a lot of logging is produced deliberately in which + case vUDPLoggingFlush() can be called to prevent the buffer overflowing. */ + if( xLoggingTask != NULL ) + { + /* Unblock the logging task so it can output the message. */ + xTaskNotifyGive( xLoggingTask ); + } + + /* Allow the low priority logging task a chance to clear the buffer. */ + vTaskDelay( pdMS_TO_TICKS( xDelay ) ); +} + diff --git a/FreeRTOS-Labs/Demo/Common/Utilities/date_and_time.c b/FreeRTOS-Labs/Demo/Common/Utilities/date_and_time.c new file mode 100644 index 000000000..52072e8fe --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Utilities/date_and_time.c @@ -0,0 +1,176 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#include +#include +#include + +#include "FreeRTOS.h" +#include "task.h" + +#include "date_and_time.h" + +int iTimeZone; + +uint32_t ulSeconds, ulMsec; + +/* + * You can add the following code to you FreeRTOSConfig file: + * + extern TickType_t ulSeconds, ulMsec; + + #define traceINCREASE_TICK_COUNT( xTicksToJump ) \ + { \ + ulMsec += xTicksToJump; \ + if( ulMsec >= 1000 ) \ + { \ + ulSeconds += ( ulMsec / 1000ul ); \ + ulMsec = ( ulMsec % 1000ul ); \ + } \ + } + + + #define traceTASK_INCREMENT_TICK( xTickCount ) \ + if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) \ + { \ + if( ++ulMsec >= 1000 ) \ + { \ + ulMsec = 0; \ + ulSeconds++; \ + } \ + } + + */ + + +time_t FreeRTOS_time( time_t *pxTime ) +{ +time_t uxTime; + + /* Critical section required if running on a 16 bit processor. */ + portTICK_TYPE_ENTER_CRITICAL(); + { + uxTime = ( time_t ) ulSeconds; + } + portTICK_TYPE_EXIT_CRITICAL(); + if( pxTime != NULL ) + { + *pxTime = uxTime; + } + return uxTime; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_settime( time_t *pxTime ) +{ + /* Critical section required if running on a 16 bit processor. */ + portTICK_TYPE_ENTER_CRITICAL(); + { + ulSeconds = ( uint32_t ) *pxTime; + ulMsec = ( uint32_t ) 0; + } + portTICK_TYPE_EXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ + +time_t FreeRTOS_get_secs_msec( time_t *pulMsec ) +{ +time_t uxReturn; + + /* Critical section required if running on a 16 bit processor. */ + portTICK_TYPE_ENTER_CRITICAL(); + { + uxReturn = ( time_t ) ulSeconds; + if( pulMsec != NULL ) + { + *pulMsec = ulMsec; + } + } + portTICK_TYPE_EXIT_CRITICAL(); + + return uxReturn; +} +/*-----------------------------------------------------------*/ + + +void FreeRTOS_set_secs_msec( time_t *pulSeconds, time_t *pulMsec ) +{ + + /* Critical section required if running on a 16 bit processor. */ + portTICK_TYPE_ENTER_CRITICAL(); + { + ulSeconds= *pulSeconds; + if( pulMsec != NULL ) + { + ulMsec = *pulMsec; + } + } + portTICK_TYPE_EXIT_CRITICAL(); +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/Common/Utilities/include/UDPLoggingPrintf.h b/FreeRTOS-Labs/Demo/Common/Utilities/include/UDPLoggingPrintf.h new file mode 100644 index 000000000..b7ad13044 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Utilities/include/UDPLoggingPrintf.h @@ -0,0 +1,100 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef DEMO_LOGGING_H +#define DEMO_LOGGING_H + +#include + +/* + * Add a formatted string along with a time-stamp to the buffer of logging messages. + */ +int lUDPLoggingPrintf( const char *pcFormatString, ... ); + +/* + * Start a task which will send out the logging lines to a UDP address. + * Only start this task once the TCP/IP stack is up and running. + */ +void vUDPLoggingTaskCreate( void ); + +/* + * vUDPLoggingFlush() can be called in cases where a lot of logging is being + * generated to try to avoid the logging buffer overflowing. WARNING - this + * function will place the calling task into the Blocked state for 20ms. + */ +void vUDPLoggingFlush( void ); + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +Socket_t xLoggingGetSocket( void ); + +#endif /* DEMO_LOGGING_H */ + diff --git a/FreeRTOS-Labs/Demo/Common/Utilities/include/date_and_time.h b/FreeRTOS-Labs/Demo/Common/Utilities/include/date_and_time.h new file mode 100644 index 000000000..14cf202b6 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Utilities/include/date_and_time.h @@ -0,0 +1,93 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef DATE_AND_TIME_H +#define DATE_AND_TIME_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern uint32_t ulSeconds, ulMsec; +extern int iTimeZone; + +extern time_t FreeRTOS_get_secs_msec( time_t *pulMsec ); +extern void FreeRTOS_set_secs_msec( time_t *pulSeconds, time_t *pulMsec ); + +extern time_t FreeRTOS_time( time_t *pxTime ); +extern void FreeRTOS_settime( time_t *pxTime ); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* DATE_AND_TIME_H */ diff --git a/FreeRTOS-Labs/Demo/Common/Utilities/printf-stdarg.c b/FreeRTOS-Labs/Demo/Common/Utilities/printf-stdarg.c new file mode 100644 index 000000000..4821a2bd7 --- /dev/null +++ b/FreeRTOS-Labs/Demo/Common/Utilities/printf-stdarg.c @@ -0,0 +1,675 @@ +/* + Copyright 2001, 2002 Georges Menie (www.menie.org) + stdarg version contributed by Christian Ettinger + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Changes for the FreeRTOS ports: + + - The dot in "%-8.8s" + - The specifiers 'l' (long) and 'L' (long long) + - The specifier 'u' for unsigned + - Dot notation for IP addresses: + sprintf("IP = %xip\n", 0xC0A80164); + will produce "IP = 192.168.1.100\n" +*/ + +#include +#include +#include +#include + +#include "FreeRTOS.h" + +#define PAD_RIGHT 1 +#define PAD_ZERO 2 + +/* + * Return 1 for readable, 2 for writeable, 3 for both. + * Function must be provided by the application. + */ +extern BaseType_t xApplicationMemoryPermissions( uint32_t aAddress ); + +extern void vOutputChar( const char cChar, const TickType_t xTicksToWait ); +static const TickType_t xTicksToWait = pdMS_TO_TICKS( 20 ); + +struct xPrintFlags +{ + int base; + int width; + int printLimit; + unsigned + pad : 8, + letBase : 8, + isSigned : 1, + isNumber : 1, + long32 : 1, + long64 : 1; +}; + +struct SStringBuf +{ + char *str; + const char *orgStr; + const char *nulPos; + int curLen; + struct xPrintFlags flags; +}; + +static void strbuf_init( struct SStringBuf *apStr, char *apBuf, const char *apMaxStr ) +{ + apStr->str = apBuf; + apStr->orgStr = apBuf; + apStr->nulPos = apMaxStr-1; + apStr->curLen = 0; + + memset( &apStr->flags, '\0', sizeof( apStr->flags ) ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t strbuf_printchar( struct SStringBuf *apStr, int c ) +{ + if( apStr->str == NULL ) + { + vOutputChar( ( char ) c, xTicksToWait ); + apStr->curLen++; + return pdTRUE; + } + if( apStr->str < apStr->nulPos ) + { + *( apStr->str++ ) = c; + apStr->curLen++; + return pdTRUE; + } + if( apStr->str == apStr->nulPos ) + { + *( apStr->str++ ) = '\0'; + } + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static portINLINE BaseType_t strbuf_printchar_inline( struct SStringBuf *apStr, int c ) +{ + if( apStr->str == NULL ) + { + vOutputChar( ( char ) c, xTicksToWait ); + if( c == 0 ) + { + return pdFALSE; + } + apStr->curLen++; + return pdTRUE; + } + if( apStr->str < apStr->nulPos ) + { + *(apStr->str++) = c; + if( c == 0 ) + { + return pdFALSE; + } + apStr->curLen++; + return pdTRUE; + } + if( apStr->str == apStr->nulPos ) + { + *( apStr->str++ ) = '\0'; + } + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static portINLINE int i2hex( int aCh ) +{ +int iResult; + + if( aCh < 10 ) + { + iResult = '0' + aCh; + } + else + { + iResult = 'A' + aCh - 10; + } + + return iResult; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prints(struct SStringBuf *apBuf, const char *apString ) +{ + register int padchar = ' '; + int i,len; + + if( apBuf->flags.width > 0 ) + { + register int len = 0; + register const char *ptr; + for( ptr = apString; *ptr; ++ptr ) + { + ++len; + } + + if( len >= apBuf->flags.width ) + { + apBuf->flags.width = 0; + } + else + { + apBuf->flags.width -= len; + } + + if( apBuf->flags.pad & PAD_ZERO ) + { + padchar = '0'; + } + } + if( ( apBuf->flags.pad & PAD_RIGHT ) == 0 ) + { + for( ; apBuf->flags.width > 0; --apBuf->flags.width ) + { + if( strbuf_printchar( apBuf, padchar ) == 0 ) + { + return pdFALSE; + } + } + } + if( ( apBuf->flags.isNumber == pdTRUE ) && ( apBuf->flags.pad == pdTRUE ) ) + { + /* The string to print represents an integer number. + * In this case, printLimit is the min number of digits to print + * If the length of the number to print is less than the min nb of i + * digits to display, we add 0 before printing the number + */ + len = strlen( apString ); + + if( len < apBuf->flags.printLimit ) + { + i = apBuf->flags.printLimit - len; + for( ; i; i-- ) + { + if( strbuf_printchar( apBuf, '0' ) == 0 ) + { + return pdFALSE; + } + } + } + } + /* The string to print is not the result of a number conversion to ascii. + * For a string, printLimit is the max number of characters to display + */ + for( ; apBuf->flags.printLimit && *apString ; ++apString, --apBuf->flags.printLimit ) + { + if( !strbuf_printchar( apBuf, *apString ) ) + { + return pdFALSE; + } + } + + for( ; apBuf->flags.width > 0; --apBuf->flags.width ) + { + if( !strbuf_printchar( apBuf, padchar ) ) + { + return pdFALSE; + } + } + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +/* the following should be enough for 32 bit int */ +#define PRINT_BUF_LEN 12 /* to print 4294967296 */ + +#if SPRINTF_LONG_LONG +#warning 64-bit libraries will be included as well +static BaseType_t printll( struct SStringBuf *apBuf, long long i ) +{ + char print_buf[ 2 * PRINT_BUF_LEN ]; + register char *s; + register int t, neg = 0; + register unsigned long long u = i; + lldiv_t lldiv_result; + +/* typedef struct + * { + * long long int quot; // quotient + * long long int rem; // remainder + * } lldiv_t; + */ + + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + if( i == 0LL ) + { + print_buf[ 0 ] = '0'; + print_buf[ 1 ] = '\0'; + return prints( apBuf, print_buf ); + } + + if( ( apBuf->flags.isSigned == pdTRUE ) && ( apBuf->flags.base == 10 ) && ( i < 0LL ) ) + { + neg = 1; + u = -i; + } + + s = print_buf + sizeof( print_buf ) - 1; + + *s = '\0'; + /* 18446744073709551616 */ + while( u != 0 ) + { + lldiv_result = lldiv( u, ( unsigned long long ) apBuf->flags.base ); + t = lldiv_result.rem; + if( t >= 10 ) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u = lldiv_result.quot; + } + + if( neg != 0 ) + { + if( ( apBuf->flags.width != 0 ) && ( apBuf->flags.pad & PAD_ZERO ) ) + { + if( !strbuf_printchar( apBuf, '-' ) ) + { + return pdFALSE; + } + --apBuf->flags.width; + } + else + { + *( --s ) = '-'; + } + } + + return prints( apBuf, s ); +} +#endif /* SPRINTF_LONG_LONG */ +/*-----------------------------------------------------------*/ + +static BaseType_t printi( struct SStringBuf *apBuf, int i ) +{ + char print_buf[ PRINT_BUF_LEN ]; + register char *s; + register int t, neg = 0; + register unsigned int u = i; + register unsigned base = apBuf->flags.base; + + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + + if( i == 0 ) + { + print_buf[ 0 ] = '0'; + print_buf[ 1 ] = '\0'; + return prints( apBuf, print_buf ); + } + + if( ( apBuf->flags.isSigned == pdTRUE ) && ( base == 10 ) && ( i < 0 ) ) + { + neg = 1; + u = -i; + } + + s = print_buf + sizeof( print_buf ) - 1; + + *s = '\0'; + switch( base ) + { + case 16: + while( u != 0 ) + { + t = u & 0xF; + if( t >= 10 ) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u >>= 4; + } + break; + + case 8: + case 10: + /* GCC compiles very efficient */ + while( u ) + { + t = u % base; + *( --s ) = t + '0'; + u /= base; + } + break; +/* + // The generic case, not yet in use + default: + while( u ) + { + t = u % base; + if( t >= 10) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u /= base; + } + break; +*/ + } + + if( neg != 0 ) + { + if( apBuf->flags.width && (apBuf->flags.pad & PAD_ZERO ) ) + { + if( strbuf_printchar( apBuf, '-' ) == 0 ) + { + return pdFALSE; + } + --apBuf->flags.width; + } + else + { + *( --s ) = '-'; + } + } + + return prints( apBuf, s ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t printIp(struct SStringBuf *apBuf, unsigned i ) +{ + char print_buf[16]; + + sprintf( print_buf, "%u.%u.%u.%u", + i >> 24, + ( i >> 16 ) & 0xff, + ( i >> 8 ) & 0xff, + i & 0xff ); + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + prints( apBuf, print_buf ); + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +static void tiny_print( struct SStringBuf *apBuf, const char *format, va_list args ) +{ + char scr[2]; + + for( ; ; ) + { + int ch = *( format++ ); + + if( ch != '%' ) + { + do + { + /* Put the most like flow in a small loop */ + if( strbuf_printchar_inline( apBuf, ch ) == 0 ) + { + return; + } + ch = *( format++ ); + } while( ch != '%' ); + } + ch = *( format++ ); + /* Now ch has character after '%', format pointing to next */ + + if( ch == '\0' ) + { + break; + } + if( ch == '%' ) + { + if( strbuf_printchar( apBuf, ch ) == 0 ) + { + return; + } + continue; + } + memset( &apBuf->flags, '\0', sizeof( apBuf->flags ) ); + + if( ch == '-' ) + { + ch = *( format++ ); + apBuf->flags.pad = PAD_RIGHT; + } + while( ch == '0' ) + { + ch = *( format++ ); + apBuf->flags.pad |= PAD_ZERO; + } + if( ch == '*' ) + { + ch = *( format++ ); + apBuf->flags.width = va_arg( args, int ); + } + else + { + while( ch >= '0' && ch <= '9' ) + { + apBuf->flags.width *= 10; + apBuf->flags.width += ch - '0'; + ch = *( format++ ); + } + } + if( ch == '.' ) + { + ch = *( format++ ); + if( ch == '*' ) + { + apBuf->flags.printLimit = va_arg( args, int ); + ch = *( format++ ); + } + else + { + while( ch >= '0' && ch <= '9' ) + { + apBuf->flags.printLimit *= 10; + apBuf->flags.printLimit += ch - '0'; + ch = *( format++ ); + } + } + } + if( apBuf->flags.printLimit == 0 ) + { + apBuf->flags.printLimit--; /* -1: make it unlimited */ + } + if( ch == 's' ) + { + register char *s = ( char * )va_arg( args, int ); + if( prints( apBuf, s ? s : "(null)" ) == 0 ) + { + break; + } + continue; + } + if( ch == 'c' ) + { + /* char are converted to int then pushed on the stack */ + scr[0] = ( char ) va_arg( args, int ); + + if( strbuf_printchar( apBuf, scr[0] ) == 0 ) + { + return; + } + + continue; + } + if( ch == 'l' ) + { + ch = *( format++ ); + apBuf->flags.long32 = 1; + /* Makes not difference as u32 == long */ + } + if( ch == 'L' ) + { + ch = *( format++ ); + apBuf->flags.long64 = 1; + /* Does make a difference */ + } + apBuf->flags.base = 10; + apBuf->flags.letBase = 'a'; + + if( ch == 'd' || ch == 'u' ) + { + apBuf->flags.isSigned = ( ch == 'd' ); +#if SPRINTF_LONG_LONG + if( apBuf->flags.long64 != pdFALSE ) + { + if( printll( apBuf, va_arg( args, long long ) ) == 0 ) + { + break; + } + } else +#endif /* SPRINTF_LONG_LONG */ + if( printi( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + + apBuf->flags.base = 16; /* From here all hexadecimal */ + + if( ch == 'x' && format[0] == 'i' && format[1] == 'p' ) + { + format += 2; /* eat the "xi" of "xip" */ + /* Will use base 10 again */ + if( printIp( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + if( ch == 'x' || ch == 'X' || ch == 'p' || ch == 'o' ) + { + if( ch == 'X' ) + { + apBuf->flags.letBase = 'A'; + } + else if( ch == 'o' ) + { + apBuf->flags.base = 8; + } +#if SPRINTF_LONG_LONG + if( apBuf->flags.long64 != pdFALSE ) + { + if( printll( apBuf, va_arg( args, long long ) ) == 0 ) + { + break; + } + } else +#endif /* SPRINTF_LONG_LONG */ + if( printi( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + } + strbuf_printchar( apBuf, '\0' ); +} +/*-----------------------------------------------------------*/ + +int tiny_printf( const char *format, ... ) +{ +va_list args; + + va_start( args, format ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, NULL, ( const char* )NULL ); + tiny_print( &strBuf, format, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int vsnprintf( char *apBuf, size_t aMaxLen, const char *apFmt, va_list args ) +{ + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen ); + tiny_print( &strBuf, apFmt, args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int snprintf( char *apBuf, size_t aMaxLen, const char *apFmt, ... ) +{ + va_list args; + + va_start( args, apFmt ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen ); + tiny_print( &strBuf, apFmt, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int sprintf( char *apBuf, const char *apFmt, ... ) +{ + va_list args; + + va_start( args, apFmt ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char * )apBuf + 1024 ); + tiny_print( &strBuf, apFmt, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int vsprintf( char *apBuf, const char *apFmt, va_list args ) +{ + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* ) apBuf + 1024 ); + tiny_print( &strBuf, apFmt, args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +const char *mkSize (unsigned long long aSize, char *apBuf, int aLen) +{ +static char retString[33]; +size_t gb, mb, kb, sb; + + if (apBuf == NULL) { + apBuf = retString; + aLen = sizeof( retString ); + } + gb = aSize / (1024*1024*1024); + aSize -= gb * (1024*1024*1024); + mb = aSize / (1024*1024); + aSize -= mb * (1024*1024); + kb = aSize / (1024); + aSize -= kb * (1024); + sb = aSize; + if( gb ) + { + snprintf (apBuf, aLen, "%u.%02u GB", ( unsigned ) gb, ( unsigned ) ( ( 100 * mb ) / 1024ul ) ); + } + else if( mb ) + { + snprintf (apBuf, aLen, "%u.%02u MB", ( unsigned ) mb, ( unsigned ) ( ( 100 * kb) / 1024ul ) ); + } + else if( kb != 0ul ) + { + snprintf (apBuf, aLen, "%u.%02u KB", ( unsigned ) kb, ( unsigned ) ( ( 100 * sb) / 1024ul ) ); + } + else + { + snprintf (apBuf, aLen, "%u bytes", ( unsigned ) sb); + } + return apBuf; +} + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/DemoTasks/SimpleHTTPSExamples.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/DemoTasks/SimpleHTTPSExamples.c new file mode 100644 index 000000000..a543fae83 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/DemoTasks/SimpleHTTPSExamples.c @@ -0,0 +1,520 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * This file contains the common functions for plain text, basic TLS, and mutual + * authentication HTTPS demos. Aside from the difference in security level during + * connect, the three demos perform the same interaction with a HTTPS host. The + * demo creates a singe application task that loops through a set of examples + * demonstrating how to the connect to the server, send a few types of requests to + * the server (GET, HEAD, PUT, POST), and disconnect from the server again. All + * of the responses and their associated HTTPS response status codes are printed + * to the console. + * + * The plain text HTTP demo does not authenticate the server nor the client. The + * basic TLS HTTPS demo builds on top of the plain text demo, adding broker + * authentication and encryption. The mutual authentication HTTPS demo builds on + * top of the basic TLS demo, enabling both server and client authentication. + * + * For more information regarding the HTTPS library and the demo, please refer to: + * https://www.freertos.org/https/index.html + */ + +/* Standard includes. */ +#include +#include + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" + +/* IoT SDK includes. */ +#include "iot_https_client.h" +#include "iot_taskpool_freertos.h" +#include "platform/iot_network_freertos.h" + +/* HTTPS Demo Select */ +#include "demo_config.h" + +/* Select HTTPS profile based on the setting in demo_config.h */ +#if ( democonfigPROFILE_USE_AWS_IOT == 1 ) + #include "aws_iot_demo_profile.h" +#else + #include "https_demo_profile.h" +#endif + +/* Preprocessor check iot configuration */ +#include "aws_iot_setup_check.h" + +/* + * Set the connection profile based on settings in demo_config.h. For more + * information on each variable, please refer to the respective *_profile.h + * file in FreeRTOS-Labs\Demo\FreeRTOS_IoT_Libraries\include. + * + * Note that if you are running the https_tls_mutual_auth demo please make sure + * to visit the following link for setup: + * https://www.freertos.org/https/preconfiguredexamplesMA.html + */ +#if defined( AWS_IOT_DEMO_PROFILE_H ) + #define httpsexampleHTTPS_SERVER_ADDRESS awsiotdemoprofileAWS_ENDPOINT + #define httpsexampleHTTPS_SERVER_PORT awsiotdemoprofileAWS_HTTPS_PORT + #define httpsexampleHTTPS_SERVER_CERTIFICATE awsiotdemoprofileAWS_CERTIFICATE_PEM + #define httpsexampleCLIENT_CERTIFICATE_PEM awsiotdemoprofileCLIENT_CERTIFICATE_PEM + #define httpsexampleCLIENT_PRIVATE_KEY_PEM awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM +#elif defined( HTTPS_DEMO_PROFILE_H ) + #define httpsexampleHTTPS_SERVER_ADDRESS httpsdemoprofileSERVER_ADDRESS + #define httpsexampleHTTPS_SERVER_PORT httpsdemoprofileSERVER_PORT + #define httpsexampleHTTPS_SERVER_CERTIFICATE httpsdemoprofileSERVER_CERTIFICATE_PEM +#endif + +/* + * Each preconfigured host supports different request paths. In this demo, we + * are using httpbin and AWS IoT. + * + * In the demos that uses httpbin.org see http://httpbin.org/#/HTTP_Methods for + * details on supported REST API. + **/ +#if defined( AWS_IOT_DEMO_PROFILE_H ) + #define httpsexampleHTTPS_POST_PATH "/topics/" awsiotdemoprofileCLIENT_IDENTIFIER +#elif defined( HTTPS_DEMO_PROFILE_H ) + #define httpsexampleHTTPS_GET_PATH "/ip" + #define httpsexampleHTTPS_HEAD_PATH "/ip" + #define httpsexampleHTTPS_PUT_PATH "/put" + #define httpsexampleHTTPS_POST_PATH "/post" +#endif + +/** + * @brief The length in bytes of the user buffer to store the HTTPS Client library + * connection context. + * + * The minimum size can be found in @ref connectionUserBufferMinimumSize. + */ +#define httpsexampleCONNECTION_USER_BUFFER_LENGTH ( 512 ) + +/** + * @brief The length in bytes of the user buffer to store the HTTPS Client library + * request context. + * + * The minimum size can be found in @ref requestUserBufferMinimumSize. + */ +#define httpsexampleREQUEST_USER_BUFFER_LENGTH ( 512 ) + +/** + * @brief The length in bytes of the user buffer to store the HTTPS Client library + * response context. + */ +#define httpsexampleRESPONSE_USER_BUFFER_LENGTH ( 512 ) + +/** + * @brief Some text to send as the request body for a PUT and POST request in + * this examples. + */ +#define httpsexampleREQUEST_BODY_TEXT "Hello, world!" + +/** + * @brief The length in bytes of the buffer used to receive the response body. + */ +#define httpsexampleRESPONSE_BODY_BUFFER_LENGTH ( 512 ) + +/** + * @brief Timeout in ms for HTTPS operations in this example. + */ +#define httpsexampleHTTPS_TIMEOUT_MS ( 5000 ) + +/*-----------------------------------------------------------*/ + +/** + * @brief The HTTPS connection handle used in this example. + */ +static IotHttpsConnectionHandle_t xHTTPSConnection = IOT_HTTPS_CONNECTION_HANDLE_INITIALIZER; + +/** + * @brief A buffer used to store the HTTPS Client library's connection context. + */ +static uint8_t ucHTTPSConnectionUserBuffer[ httpsexampleCONNECTION_USER_BUFFER_LENGTH ] = { 0 }; + +/** + * @brief A buffer used to store the HTTPS Client library's request context and + * some headers. + */ +static uint8_t ucHTTPSRequestUserBuffer[ httpsexampleREQUEST_USER_BUFFER_LENGTH ] = { 0 }; + +/** + * @brief A buffer used to store the HTTPS Client library's response context and + * some headers. + */ +static uint8_t ucHTTPSResponseUserBuffer[ httpsexampleRESPONSE_USER_BUFFER_LENGTH ] = { 0 }; + +/** + * @brief The request body. + */ +static char cHTTPSRequestBodyBuffer[] = httpsexampleREQUEST_BODY_TEXT; + +/** + * @brief A buffer used to receive the HTTPS Client library's response body. + */ +static uint8_t ucHTTPSResponseBodyBuffer[ httpsexampleRESPONSE_BODY_BUFFER_LENGTH ] = { 0 }; + +/** + * @brief The task used to demonstrate the HTTPS Client API. + * + * @param[in] pvParameters Parameters as passed at the time of task creation. Not + * used in this example. + */ +static void prvHTTPSDemoTask( void * pvParameters ); + +/** + * @brief Connects to the HTTPS server as specified in httpsexampleHTTPS_SERVER_ADDRESS + * and httpsexampleHTTPS_SERVER_PORT. + */ +static void prvHTTPSConnect( void ); + +/** + * @brief Creates and sends an HTTPS request to the HTTPS server specified in + * httpsexampleHTTPS_SERVER_ADDRESS and httpsexampleHTTPS_SERVER_PORT. + * + * @param[in] xMethod The HTTPS method to use. Please #IotHttpsMethod_t for + * possible parameters. + * @param[in] pcPath The path for the HTTPS request. + * @param[in] ulPathLength The length of the input pcPath. + */ +static void prvHTTPSRequest( IotHttpsMethod_t xMethod, + const char * pcPath, + uint32_t ulPathLength ); + +/** + * @brief Disconnects from the HTTPS server. + */ +static void prvHTTPSDisconnect( void ); + +/** +* @brief Initializes the IoT libraries used by this demo. +*/ +static void prvInitialiseLibraries( void ); + +/*-----------------------------------------------------------*/ + +/** + * @brief Parameters used to create the system task pool. + */ +static const IotTaskPoolInfo_t xTaskPoolParameters = +{ + /* Minimum number of threads in a task pool. + * Note the slimmed down version of the task + * pool used by this library does not auto-scale + * the number of tasks in the pool so in this + * case this sets the number of tasks in the + * pool. */ + 1, + + /* Maximum number of threads in a task pool. + * Note the slimmed down version of the task + * pool used by this library does not auto-scale + * the number of tasks in the pool so in this + * case this parameter is just ignored. */ + 1, + + /* Stack size for every task pool thread - in + * bytes, hence multiplying by the number of bytes + * in a word as configMINIMAL_STACK_SIZE is + * specified in words. */ + configMINIMAL_STACK_SIZE * sizeof( portSTACK_TYPE ), + /* Priority for every task pool thread. */ + tskIDLE_PRIORITY, +}; +/*-----------------------------------------------------------*/ + +static const IotHttpsConnectionInfo_t xConnectionInfo = +{ + /* No connection to the HTTPS server has been established yet and we want to + * establish a new connection. */ + .pAddress = httpsexampleHTTPS_SERVER_ADDRESS, + .addressLen = sizeof( httpsexampleHTTPS_SERVER_ADDRESS ) - 1, + .port = httpsexampleHTTPS_SERVER_PORT, + .userBuffer.pBuffer = ucHTTPSConnectionUserBuffer, + .userBuffer.bufferLen = sizeof( ucHTTPSConnectionUserBuffer ), + + /* Use FreeRTOS+TCP network. */ + .pNetworkInterface = IOT_NETWORK_INTERFACE_FREERTOS, + + /* The HTTPS Client library uses TLS by default as indicated by the "S" + * postfixed to "HTTP" in the name of the library and its types and + * functions. There are no configurations in the flags to enable TLS. */ + .flags = 0, + + /* Optional TLS extensions. For this demo, they are disabled. */ + .pAlpnProtocols = NULL, + .alpnProtocolsLen = 0, + + /* Provide the certificate for authenticating the server. */ + #if ( democonfigENABLE_TLS == 1 ) + .pCaCert = httpsexampleHTTPS_SERVER_CERTIFICATE, + .caCertLen = sizeof( httpsexampleHTTPS_SERVER_CERTIFICATE ), + #else + .pCaCert = NULL, + .caCertLen = 0, + #endif + + /* The HTTPS server at httpbin.org:443 does not require client certificates, + * but AWS IoT does. + * If the server were to require a client certificate, the following members + * need to be set. */ + #if ( democonfigENABLE_MUTUAL_AUTH == 1 ) + .pClientCert = httpsexampleCLIENT_CERTIFICATE_PEM, + .clientCertLen = sizeof( httpsexampleCLIENT_CERTIFICATE_PEM ), + .pPrivateKey = httpsexampleCLIENT_PRIVATE_KEY_PEM, + .privateKeyLen = sizeof( httpsexampleCLIENT_PRIVATE_KEY_PEM ) + #else + .pClientCert = NULL, + .clientCertLen = 0, + .pPrivateKey = NULL, + .privateKeyLen = 0 + #endif +}; +/*-----------------------------------------------------------*/ + +void vStartSimpleHTTPSDemo( void ) +{ + /* This example uses a single application task, which in turn is used to + * connect, send a few requests, and disconnect from the HTTPS server. */ + xTaskCreate( prvHTTPSDemoTask, /* Function that implements the task. */ + "HTTPSDemo", /* Text name for the task - only used for debugging. */ + democonfigDEMO_STACKSIZE, /* Size of stack (in words, not bytes) to allocate for the task. */ + NULL, /* Task parameter - not used in this case. */ + tskIDLE_PRIORITY, /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */ + NULL ); /* Used to pass out a handle to the created task - not used in this case. */ +} +/*-----------------------------------------------------------*/ + +static void prvHTTPSDemoTask( void * pvParameters ) +{ + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + /* One time initialization of the libraries used by this demo. */ + prvInitialiseLibraries(); + + for( ; ; ) + { + /****************************** Connect. ******************************/ + + /* Establish a connection to the HTTPS server. This example connects to + * the HTTPS server as specified in httpsexampleHTTPS_SERVER_ADDRESS and + * httpsexampleHTTPS_SERVER_PORT at the top of this file. Please change + * it to the HTTPS server you want to connect to. */ + configPRINTF( ( "Attempt to connect to %s:%d\r\n", httpsexampleHTTPS_SERVER_ADDRESS, httpsexampleHTTPS_SERVER_PORT ) ); + prvHTTPSConnect(); + configPRINTF( ( "Connected to %s:%d\r\n", httpsexampleHTTPS_SERVER_ADDRESS, httpsexampleHTTPS_SERVER_PORT ) ); + + /*********************** Send HTTPS requests. ************************/ + + /* The client is now connected to the server. This example will send a + * GET, HEAD, PUT, and POST request. For AWS IoT profile, the example will + * only send a POST request. + **/ + #if defined( httpsexampleHTTPS_GET_PATH ) + configPRINTF( ( "Sending HTTPS GET request...\r\n" ) ); + prvHTTPSRequest( IOT_HTTPS_METHOD_GET, + httpsexampleHTTPS_GET_PATH, + sizeof( httpsexampleHTTPS_GET_PATH ) - 1 ); + #endif + #if defined( httpsexampleHTTPS_HEAD_PATH ) + configPRINTF( ( "Sending HTTPS HEAD request...\r\n" ) ); + prvHTTPSRequest( IOT_HTTPS_METHOD_HEAD, + httpsexampleHTTPS_HEAD_PATH, + sizeof( httpsexampleHTTPS_HEAD_PATH ) - 1 ); + #endif + #if defined( httpsexampleHTTPS_PUT_PATH ) + configPRINTF( ( "Sending HTTPS PUT request...\r\n" ) ); + prvHTTPSRequest( IOT_HTTPS_METHOD_PUT, + httpsexampleHTTPS_PUT_PATH, + sizeof( httpsexampleHTTPS_PUT_PATH ) - 1 ); + #endif + #if defined( httpsexampleHTTPS_POST_PATH ) + configPRINTF( ( "Sending HTTPS POST request...\r\n" ) ); + prvHTTPSRequest( IOT_HTTPS_METHOD_POST, + httpsexampleHTTPS_POST_PATH, + sizeof( httpsexampleHTTPS_POST_PATH ) - 1 ); + #endif + + /**************************** Disconnect. *****************************/ + + prvHTTPSDisconnect(); + configPRINTF( ( "Disconnected from %s:%d\r\n\r\n", httpsexampleHTTPS_SERVER_ADDRESS, httpsexampleHTTPS_SERVER_PORT ) ); + + /* Wait between iterations to avoid server throttling. */ + + configPRINTF( ( "prvHTTPSDemoTask() completed an iteration successfully. " + "Total free heap is %u\r\n", + xPortGetFreeHeapSize() ) ); + configPRINTF( ( "Demo completed successfully.\r\n" ) ); + configPRINTF( ( "Short delay before starting the next iteration.... \r\n\r\n" ) ); + vTaskDelay( pdMS_TO_TICKS( httpsexampleHTTPS_TIMEOUT_MS ) ); + } +} + +/*-----------------------------------------------------------*/ + +static void prvHTTPSConnect( void ) +{ +IotHttpsReturnCode_t xHTTPSClientResult; + + /* Establish the connection to the HTTPS server - It is a blocking call and + * will return only when the connection is complete or a timeout occurs. */ + xHTTPSClientResult = IotHttpsClient_Connect( &( xHTTPSConnection ), + &( xConnectionInfo ) ); + configASSERT( xHTTPSClientResult == IOT_HTTPS_OK ); +} + +/*-----------------------------------------------------------*/ + +static void prvHTTPSRequest( IotHttpsMethod_t xMethod, + const char * pcPath, + uint32_t ulPathLength ) +{ +IotHttpsReturnCode_t xHTTPSClientResult; +IotHttpsRequestInfo_t xHTTPSRequestInfo = IOT_HTTPS_REQUEST_INFO_INITIALIZER; +IotHttpsResponseInfo_t xHTTPSResponseInfo = IOT_HTTPS_RESPONSE_INFO_INITIALIZER; +IotHttpsRequestHandle_t xHTTPSRequest = IOT_HTTPS_REQUEST_HANDLE_INITIALIZER; +IotHttpsResponseHandle_t xHTTPSResponse = IOT_HTTPS_RESPONSE_HANDLE_INITIALIZER; +IotHttpsSyncInfo_t xHTTPSSyncRequestInfo = IOT_HTTPS_SYNC_INFO_INITIALIZER; +IotHttpsSyncInfo_t xHTTPSSyncResponseInfo = IOT_HTTPS_SYNC_INFO_INITIALIZER; +uint16_t usResponseStatus = 0; + + configASSERT( pcPath != NULL ); + + /************************** HTTPS request setup. ***************************/ + + if( ( xMethod == IOT_HTTPS_METHOD_PUT ) || ( xMethod == IOT_HTTPS_METHOD_POST ) ) + { + xHTTPSSyncRequestInfo.pBody = ( uint8_t * ) cHTTPSRequestBodyBuffer; + xHTTPSSyncRequestInfo.bodyLen = sizeof( cHTTPSRequestBodyBuffer ); + } + else + { + xHTTPSSyncRequestInfo.pBody = NULL; + xHTTPSSyncRequestInfo.bodyLen = 0; + } + + xHTTPSRequestInfo.pHost = httpsexampleHTTPS_SERVER_ADDRESS; + xHTTPSRequestInfo.hostLen = sizeof( httpsexampleHTTPS_SERVER_ADDRESS ) - 1; + xHTTPSRequestInfo.pPath = pcPath; + xHTTPSRequestInfo.pathLen = ulPathLength; + xHTTPSRequestInfo.method = xMethod; + xHTTPSRequestInfo.isNonPersistent = false; + xHTTPSRequestInfo.userBuffer.pBuffer = ucHTTPSRequestUserBuffer; + xHTTPSRequestInfo.userBuffer.bufferLen = sizeof( ucHTTPSRequestUserBuffer ) - 1; + xHTTPSRequestInfo.isAsync = false; + xHTTPSRequestInfo.u.pSyncInfo = &xHTTPSSyncRequestInfo; + + xHTTPSClientResult = IotHttpsClient_InitializeRequest( &( xHTTPSRequest ), + &( xHTTPSRequestInfo ) ); + configASSERT( xHTTPSClientResult == IOT_HTTPS_OK ); + + /************************** HTTPS response setup. **************************/ + + memset( ucHTTPSResponseBodyBuffer, 0, sizeof( ucHTTPSResponseBodyBuffer ) ); + + if( xMethod == IOT_HTTPS_METHOD_HEAD ) + { + xHTTPSSyncResponseInfo.pBody = NULL; + xHTTPSSyncResponseInfo.bodyLen = 0; + } + else + { + xHTTPSSyncResponseInfo.pBody = ucHTTPSResponseBodyBuffer; + xHTTPSSyncResponseInfo.bodyLen = sizeof( ucHTTPSResponseBodyBuffer ); + } + + xHTTPSResponseInfo.userBuffer.pBuffer = ucHTTPSResponseUserBuffer; + xHTTPSResponseInfo.userBuffer.bufferLen = sizeof( ucHTTPSResponseUserBuffer ); + xHTTPSResponseInfo.pSyncInfo = &xHTTPSSyncResponseInfo; + + /*************************** Send HTTPS request. ***************************/ + + /* This synchronous send function blocks until the full response is received + * from the network. */ + xHTTPSClientResult = IotHttpsClient_SendSync( xHTTPSConnection, + xHTTPSRequest, + &( xHTTPSResponse ), + &( xHTTPSResponseInfo ), + httpsexampleHTTPS_TIMEOUT_MS ); + configASSERT( xHTTPSClientResult == IOT_HTTPS_OK ); + + /* The response status is only available if the httpsexampleRESPONSE_USER_BUFFER + * is large enough to fit not only the HTTPS Client response context, but + * also the Status-Line of the response. The Status-Line and the response + * headers are stored in the provided ucHTTPSResponseUserBuffer right after + * the HTTPS Client response context. */ + xHTTPSClientResult = IotHttpsClient_ReadResponseStatus( xHTTPSResponse, + &usResponseStatus ); + configASSERT( xHTTPSClientResult == IOT_HTTPS_OK ); + + configPRINTF( ( "Response status: %d\r\n", usResponseStatus ) ); + configPRINTF( ( "Response body: \r\n%s\r\n", ucHTTPSResponseBodyBuffer ) ); + + /* The response body may be too large for the print buffer. These extra + * carriage returns and newlines help with clobbering. */ + configPRINTF( ( "\r\n\r\n" ) ); +} + +/*-----------------------------------------------------------*/ + +static void prvHTTPSDisconnect( void ) +{ +IotHttpsReturnCode_t xHTTPSClientResult; + + /* The application must always explicitly disconnect from the server with + * this API if the last request sent on the connection was a persistent + * request. */ + xHTTPSClientResult = IotHttpsClient_Disconnect( xHTTPSConnection ); + configASSERT( xHTTPSClientResult == IOT_HTTPS_OK ); +} + + +static void prvInitialiseLibraries( void ) +{ +IotTaskPoolError_t xTaskPoolResult; +IotHttpsReturnCode_t xHTTPSClientResult; +IotNetworkError_t xNetworkResult; + + /* The HTTPS Client library needs a task pool, so create the system task pool. */ + xTaskPoolResult = IotTaskPool_CreateSystemTaskPool( &( xTaskPoolParameters ) ); + configASSERT( xTaskPoolResult == IOT_TASKPOOL_SUCCESS ); + + /* Initialize the network stack abstraction for FreeRTOS. */ + xNetworkResult = IotNetworkFreeRTOS_Init(); + configASSERT( xNetworkResult == IOT_NETWORK_SUCCESS ); + + /* HTTPS Client library must be initialized before it can be used. This is + * just one time initialization. */ + xHTTPSClientResult = IotHttpsClient_Init(); + configASSERT( xHTTPSClientResult == IOT_HTTPS_OK ); +} diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/Packet32.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/Packet32.h new file mode 100644 index 000000000..1e0eacd77 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/Packet32.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + +/** @ingroup packetapi + * @{ + */ + +/** @defgroup packet32h Packet.dll definitions and data structures + * Packet32.h contains the data structures and the definitions used by packet.dll. + * The file is used both by the Win9x and the WinNTx versions of packet.dll, and can be included + * by the applications that use the functions of this library + * @{ + */ + +#ifndef __PACKET32 +#define __PACKET32 + +#include + +#ifdef HAVE_AIRPCAP_API +#include +#else +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +typedef struct _AirpcapHandle *PAirpcapHandle; +#endif /* AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ */ +#endif /* HAVE_AIRPCAP_API */ + +#ifdef HAVE_DAG_API +#include +#endif /* HAVE_DAG_API */ + +// Working modes +#define PACKET_MODE_CAPT 0x0 ///< Capture mode +#define PACKET_MODE_STAT 0x1 ///< Statistical mode +#define PACKET_MODE_MON 0x2 ///< Monitoring mode +#define PACKET_MODE_DUMP 0x10 ///< Dump mode +#define PACKET_MODE_STAT_DUMP MODE_DUMP | MODE_STAT ///< Statistical dump Mode + + +/// Alignment macro. Defines the alignment size. +#define Packet_ALIGNMENT sizeof(int) +/// Alignment macro. Rounds up to the next even multiple of Packet_ALIGNMENT. +#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1)) + +#define NdisMediumNull -1 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumCHDLC -2 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPPPSerial -3 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumBare80211 -4 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumRadio80211 -5 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPpi -6 ///< Custom linktype: NDIS doesn't provide an equivalent + +// Loopback behaviour definitions +#define NPF_DISABLE_LOOPBACK 1 ///< Drop the packets sent by the NPF driver +#define NPF_ENABLE_LOOPBACK 2 ///< Capture the packets sent by the NPF driver + +/*! + \brief Network type structure. + + This structure is used by the PacketGetNetType() function to return information on the current adapter's type and speed. +*/ +typedef struct NetType +{ + UINT LinkType; ///< The MAC of the current network adapter (see function PacketGetNetType() for more information) + ULONGLONG LinkSpeed; ///< The speed of the network in bits per second +}NetType; + + +//some definitions stolen from libpcap + +#ifndef BPF_MAJOR_VERSION + +/*! + \brief A BPF pseudo-assembly program. + + The program will be injected in the kernel by the PacketSetBPF() function and applied to every incoming packet. +*/ +struct bpf_program +{ + UINT bf_len; ///< Indicates the number of instructions of the program, i.e. the number of struct bpf_insn that will follow. + struct bpf_insn *bf_insns; ///< A pointer to the first instruction of the program. +}; + +/*! + \brief A single BPF pseudo-instruction. + + bpf_insn contains a single instruction for the BPF register-machine. It is used to send a filter program to the driver. +*/ +struct bpf_insn +{ + USHORT code; ///< Instruction type and addressing mode. + UCHAR jt; ///< Jump if true + UCHAR jf; ///< Jump if false + int k; ///< Generic field used for various purposes. +}; + +/*! + \brief Structure that contains a couple of statistics values on the current capture. + + It is used by packet.dll to return statistics about a capture session. +*/ +struct bpf_stat +{ + UINT bs_recv; ///< Number of packets that the driver received from the network adapter + ///< from the beginning of the current capture. This value includes the packets + ///< lost by the driver. + UINT bs_drop; ///< number of packets that the driver lost from the beginning of a capture. + ///< Basically, a packet is lost when the the buffer of the driver is full. + ///< In this situation the packet cannot be stored and the driver rejects it. + UINT ps_ifdrop; ///< drops by interface. XXX not yet supported + UINT bs_capt; ///< number of packets that pass the filter, find place in the kernel buffer and + ///< thus reach the application. +}; + +/*! + \brief Packet header. + + This structure defines the header associated with every packet delivered to the application. +*/ +struct bpf_hdr +{ + struct timeval bh_tstamp; ///< The timestamp associated with the captured packet. + ///< It is stored in a TimeVal structure. + UINT bh_caplen; ///< Length of captured portion. The captured portion can be different + ///< from the original packet, because it is possible (with a proper filter) + ///< to instruct the driver to capture only a portion of the packets. + UINT bh_datalen; ///< Original length of packet + USHORT bh_hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases, + ///< a padding could be added between the end of this structure and the packet + ///< data for performance reasons. This filed can be used to retrieve the actual data + ///< of the packet. +}; + +/*! + \brief Dump packet header. + + This structure defines the header associated with the packets in a buffer to be used with PacketSendPackets(). + It is simpler than the bpf_hdr, because it corresponds to the header associated by WinPcap and libpcap to a + packet in a dump file. This makes straightforward sending WinPcap dump files to the network. +*/ +struct dump_bpf_hdr{ + struct timeval ts; ///< Time stamp of the packet + UINT caplen; ///< Length of captured portion. The captured portion can smaller than the + ///< the original packet, because it is possible (with a proper filter) to + ///< instruct the driver to capture only a portion of the packets. + UINT len; ///< Length of the original packet (off wire). +}; + + +#endif + +struct bpf_stat; + +#define DOSNAMEPREFIX TEXT("Packet_") ///< Prefix added to the adapters device names to create the WinPcap devices +#define MAX_LINK_NAME_LENGTH 64 //< Maximum length of the devices symbolic links +#define NMAX_PACKET 65535 + +/*! + \brief Addresses of a network adapter. + + This structure is used by the PacketGetNetInfoEx() function to return the IP addresses associated with + an adapter. +*/ +typedef struct npf_if_addr { + struct sockaddr_storage IPAddress; ///< IP address. + struct sockaddr_storage SubnetMask; ///< Netmask for that address. + struct sockaddr_storage Broadcast; ///< Broadcast address. +}npf_if_addr; + + +#define ADAPTER_NAME_LENGTH 256 + 12 ///< Maximum length for the name of an adapter. The value is the same used by the IP Helper API. +#define ADAPTER_DESC_LENGTH 128 ///< Maximum length for the description of an adapter. The value is the same used by the IP Helper API. +#define MAX_MAC_ADDR_LENGTH 8 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. +#define MAX_NETWORK_ADDRESSES 16 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. + + +typedef struct WAN_ADAPTER_INT WAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API +typedef WAN_ADAPTER *PWAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API + +#define INFO_FLAG_NDIS_ADAPTER 0 ///< Flag for ADAPTER_INFO: this is a traditional ndis adapter +#define INFO_FLAG_NDISWAN_ADAPTER 1 ///< Flag for ADAPTER_INFO: this is a NdisWan adapter, and it's managed by WANPACKET +#define INFO_FLAG_DAG_CARD 2 ///< Flag for ADAPTER_INFO: this is a DAG card +#define INFO_FLAG_DAG_FILE 6 ///< Flag for ADAPTER_INFO: this is a DAG file +#define INFO_FLAG_DONT_EXPORT 8 ///< Flag for ADAPTER_INFO: when this flag is set, the adapter will not be listed or openend by winpcap. This allows to prevent exporting broken network adapters, like for example FireWire ones. +#define INFO_FLAG_AIRPCAP_CARD 16 ///< Flag for ADAPTER_INFO: this is an airpcap card +#define INFO_FLAG_NPFIM_DEVICE 32 + +/*! + \brief Describes an opened network adapter. + + This structure is the most important for the functioning of packet.dll, but the great part of its fields + should be ignored by the user, since the library offers functions that avoid to cope with low-level parameters +*/ +typedef struct _ADAPTER { + HANDLE hFile; ///< \internal Handle to an open instance of the NPF driver. + CHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; ///< \internal A string containing the name of the network adapter currently opened. + int NumWrites; ///< \internal Number of times a packets written on this adapter will be repeated + ///< on the wire. + HANDLE ReadEvent; ///< A notification event associated with the read calls on the adapter. + ///< It can be passed to standard Win32 functions (like WaitForSingleObject + ///< or WaitForMultipleObjects) to wait until the driver's buffer contains some + ///< data. It is particularly useful in GUI applications that need to wait + ///< concurrently on several events. In Windows NT/2000 the PacketSetMinToCopy() + ///< function can be used to define the minimum amount of data in the kernel buffer + ///< that will cause the event to be signalled. + + UINT ReadTimeOut; ///< \internal The amount of time after which a read on the driver will be released and + ///< ReadEvent will be signaled, also if no packets were captured + CHAR Name[ADAPTER_NAME_LENGTH]; + PWAN_ADAPTER pWanAdapter; + UINT Flags; ///< Adapter's flags. Tell if this adapter must be treated in a different way, using the Netmon API or the dagc API. + +#ifdef HAVE_AIRPCAP_API + PAirpcapHandle AirpcapAd; +#endif // HAVE_AIRPCAP_API + +#ifdef HAVE_NPFIM_API + void* NpfImHandle; +#endif // HAVE_NPFIM_API + +#ifdef HAVE_DAG_API + dagc_t *pDagCard; ///< Pointer to the dagc API adapter descriptor for this adapter + PCHAR DagBuffer; ///< Pointer to the buffer with the packets that is received from the DAG card + struct timeval DagReadTimeout; ///< Read timeout. The dagc API requires a timeval structure + unsigned DagFcsLen; ///< Length of the frame check sequence attached to any packet by the card. Obtained from the registry + DWORD DagFastProcess; ///< True if the user requests fast capture processing on this card. Higher level applications can use this value to provide a faster but possibly unprecise capture (for example, libpcap doesn't convert the timestamps). +#endif // HAVE_DAG_API +} ADAPTER, *LPADAPTER; + +/*! + \brief Structure that contains a group of packets coming from the driver. + + This structure defines the header associated with every packet delivered to the application. +*/ +typedef struct _PACKET { + HANDLE hEvent; ///< \deprecated Still present for compatibility with old applications. + OVERLAPPED OverLapped; ///< \deprecated Still present for compatibility with old applications. + PVOID Buffer; ///< Buffer with containing the packets. See the PacketReceivePacket() for + ///< details about the organization of the data in this buffer + UINT Length; ///< Length of the buffer + DWORD ulBytesReceived; ///< Number of valid bytes present in the buffer, i.e. amount of data + ///< received by the last call to PacketReceivePacket() + BOOLEAN bIoComplete; ///< \deprecated Still present for compatibility with old applications. +} PACKET, *LPPACKET; + +/*! + \brief Structure containing an OID request. + + It is used by the PacketRequest() function to send an OID to the interface card driver. + It can be used, for example, to retrieve the status of the error counters on the adapter, its MAC address, + the list of the multicast groups defined on it, and so on. +*/ +struct _PACKET_OID_DATA { + ULONG Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h + ///< for a complete list of valid codes. + ULONG Length; ///< Length of the data field + UCHAR Data[1]; ///< variable-lenght field that contains the information passed to or received + ///< from the adapter. +}; +typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @} + */ + +/* +BOOLEAN QueryWinPcapRegistryStringA(CHAR *SubKeyName, + CHAR *Value, + UINT *pValueLen, + CHAR *DefaultVal); + +BOOLEAN QueryWinPcapRegistryStringW(WCHAR *SubKeyName, + WCHAR *Value, + UINT *pValueLen, + WCHAR *DefaultVal); +*/ + +//--------------------------------------------------------------------------- +// EXPORTED FUNCTIONS +//--------------------------------------------------------------------------- + +PCHAR PacketGetVersion(); +PCHAR PacketGetDriverVersion(); +BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes); +BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites); +BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode); +BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout); +BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp); +BOOLEAN PacketSetLoopbackBehavior(LPADAPTER AdapterObject, UINT LoopbackBehavior); +INT PacketSetSnapLen(LPADAPTER AdapterObject,int snaplen); +BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim); +BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type); +LPADAPTER PacketOpenAdapter(PCHAR AdapterName); +BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync); +INT PacketSendPackets(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync); +LPPACKET PacketAllocatePacket(void); +VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length); +VOID PacketFreePacket(LPPACKET lpPacket); +BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync); +BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter); +BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize); +BOOLEAN PacketGetNetInfoEx(PCHAR AdapterName, npf_if_addr* buffer, PLONG NEntries); +BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData); +HANDLE PacketGetReadEvent(LPADAPTER AdapterObject); +BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len); +BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks); +BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync); +BOOL PacketStopDriver(); +VOID PacketCloseAdapter(LPADAPTER lpAdapter); +BOOLEAN PacketStartOem(PCHAR errorString, UINT errorStringLength); +BOOLEAN PacketStartOemEx(PCHAR errorString, UINT errorStringLength, ULONG flags); +PAirpcapHandle PacketGetAirPcapHandle(LPADAPTER AdapterObject); + +// +// Used by PacketStartOemEx +// +#define PACKET_START_OEM_NO_NETMON 0x00000001 + +#ifdef __cplusplus +} +#endif + +#endif //__PACKET32 diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/PacketData.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/PacketData.h new file mode 100644 index 000000000..8124db66d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/PacketData.h @@ -0,0 +1,267 @@ +char pkt1[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x30, 0x09, 0x9c, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x07, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x35, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02, +0x40, 0x00, 0xdf, 0xab, 0x00, 0x00, 0x02, 0x04, +0x05, 0xb4, 0x01, 0x01, 0x04, 0x02 }; + +char pkt2[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa6, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt3[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0x9e, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x0d, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt4[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x02, 0x27, 0x09, 0x9f, 0x40, 0x00, 0x80, 0x06, +0x6d, 0x0d, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x18, +0x42, 0xd8, 0x84, 0x3e, 0x00, 0x00, 0x47, 0x45, +0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, +0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, +0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x2c, +0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, +0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, +0x2c, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, +0x6a, 0x70, 0x65, 0x67, 0x2c, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x70, 0x6a, 0x70, 0x65, +0x67, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, +0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, +0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, +0x63, 0x65, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c, +0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, +0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, +0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20, +0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, +0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, +0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70, +0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, +0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78, +0x62, 0x61, 0x70, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, +0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d, +0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, +0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, +0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, +0x20, 0x65, 0x6e, 0x2d, 0x67, 0x62, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, +0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, +0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64, +0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x0d, 0x0a, +0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, +0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69, +0x6c, 0x6c, 0x61, 0x2f, 0x34, 0x2e, 0x30, 0x20, +0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, +0x62, 0x6c, 0x65, 0x3b, 0x20, 0x4d, 0x53, 0x49, +0x45, 0x20, 0x36, 0x2e, 0x30, 0x3b, 0x20, 0x57, +0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e, +0x54, 0x20, 0x35, 0x2e, 0x31, 0x3b, 0x20, 0x53, +0x56, 0x31, 0x3b, 0x20, 0x47, 0x6f, 0x6f, 0x67, +0x6c, 0x65, 0x54, 0x35, 0x3b, 0x20, 0x2e, 0x4e, +0x45, 0x54, 0x20, 0x43, 0x4c, 0x52, 0x20, 0x32, +0x2e, 0x30, 0x2e, 0x35, 0x30, 0x37, 0x32, 0x37, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30, +0x34, 0x35, 0x30, 0x36, 0x2e, 0x36, 0x34, 0x38, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x35, 0x2e, 0x32, +0x31, 0x30, 0x32, 0x32, 0x29, 0x0d, 0x0a, 0x48, +0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, +0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31, +0x32, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, +0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b, +0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, +0x65, 0x0d, 0x0a, 0x0d, 0x0a }; + +char pkt5[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x02, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa5, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt6[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa1, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x0a, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt7[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x02, 0x27, 0x09, 0xa2, 0x40, 0x00, 0x80, 0x06, +0x6d, 0x0a, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x18, +0x42, 0xd8, 0x84, 0x3e, 0x00, 0x00, 0x47, 0x45, +0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, +0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, +0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x2c, +0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, +0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, +0x2c, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, +0x6a, 0x70, 0x65, 0x67, 0x2c, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x70, 0x6a, 0x70, 0x65, +0x67, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, +0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, +0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, +0x63, 0x65, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c, +0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, +0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, +0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20, +0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, +0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, +0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70, +0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, +0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78, +0x62, 0x61, 0x70, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, +0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d, +0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, +0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, +0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, +0x20, 0x65, 0x6e, 0x2d, 0x67, 0x62, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, +0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, +0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64, +0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x0d, 0x0a, +0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, +0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69, +0x6c, 0x6c, 0x61, 0x2f, 0x34, 0x2e, 0x30, 0x20, +0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, +0x62, 0x6c, 0x65, 0x3b, 0x20, 0x4d, 0x53, 0x49, +0x45, 0x20, 0x36, 0x2e, 0x30, 0x3b, 0x20, 0x57, +0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e, +0x54, 0x20, 0x35, 0x2e, 0x31, 0x3b, 0x20, 0x53, +0x56, 0x31, 0x3b, 0x20, 0x47, 0x6f, 0x6f, 0x67, +0x6c, 0x65, 0x54, 0x35, 0x3b, 0x20, 0x2e, 0x4e, +0x45, 0x54, 0x20, 0x43, 0x4c, 0x52, 0x20, 0x32, +0x2e, 0x30, 0x2e, 0x35, 0x30, 0x37, 0x32, 0x37, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30, +0x34, 0x35, 0x30, 0x36, 0x2e, 0x36, 0x34, 0x38, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x35, 0x2e, 0x32, +0x31, 0x30, 0x32, 0x32, 0x29, 0x0d, 0x0a, 0x48, +0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, +0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31, +0x32, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, +0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b, +0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, +0x65, 0x0d, 0x0a, 0x0d, 0x0a }; + +char pkt8[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x03, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa4, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt9[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa3, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x08, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt10[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x04, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa3, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt11[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa6, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x05, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt12[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa7, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x04, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x14, +0x00, 0x00, 0x43, 0xf4, 0x00, 0x00 }; + + +typedef struct +{ + char *pcData; + int iDataLen; +} xPacketData; + +xPacketData xAllPackets[] = +{ + { pkt1, sizeof( pkt1 ) }, +// { pkt2, sizeof( pkt2 ) }, + { pkt3, sizeof( pkt3 ) }, + { pkt4, sizeof( pkt4 ) }, +// { pkt5, sizeof( pkt5 ) }, + { pkt6, sizeof( pkt6 ) }, + { pkt7, sizeof( pkt7 ) }, + { pkt8, sizeof( pkt8 ) }, + { pkt9, sizeof( pkt9 ) }, + { pkt10, sizeof( pkt10 ) }, +// { pkt11, sizeof( pkt11 ) }, +// { pkt12, sizeof( pkt12 ) }, +// { pkt13, sizeof( pkt13 ) }, +// { pkt14, sizeof( pkt14 ) }, +// { pkt15, sizeof( pkt15 ) }, +// { pkt16, sizeof( pkt16 ) }, +}; diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/Win32-Extensions.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/Win32-Extensions.h new file mode 100644 index 000000000..be71c85e9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/Win32-Extensions.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + + +#ifndef __WIN32_EXTENSIONS_H__ +#define __WIN32_EXTENSIONS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Definitions */ + +/*! + \brief A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit(). +*/ +struct pcap_send_queue +{ + u_int maxlen; ///< Maximum size of the the queue, in bytes. This variable contains the size of the buffer field. + u_int len; ///< Current size of the queue, in bytes. + char *buffer; ///< Buffer containing the packets to be sent. +}; + +typedef struct pcap_send_queue pcap_send_queue; + +/*! + \brief This typedef is a support for the pcap_get_airpcap_handle() function +*/ +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +typedef struct _AirpcapHandle *PAirpcapHandle; +#endif + +#define BPF_MEM_EX_IMM 0xc0 +#define BPF_MEM_EX_IND 0xe0 + +/*used for ST*/ +#define BPF_MEM_EX 0xc0 +#define BPF_TME 0x08 + +#define BPF_LOOKUP 0x90 +#define BPF_EXECUTE 0xa0 +#define BPF_INIT 0xb0 +#define BPF_VALIDATE 0xc0 +#define BPF_SET_ACTIVE 0xd0 +#define BPF_RESET 0xe0 +#define BPF_SET_MEMORY 0x80 +#define BPF_GET_REGISTER_VALUE 0x70 +#define BPF_SET_REGISTER_VALUE 0x60 +#define BPF_SET_WORKING 0x50 +#define BPF_SET_ACTIVE_READ 0x40 +#define BPF_SET_AUTODELETION 0x30 +#define BPF_SEPARATION 0xff + +/* Prototypes */ +pcap_send_queue* pcap_sendqueue_alloc(u_int memsize); + +void pcap_sendqueue_destroy(pcap_send_queue* queue); + +int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data); + +u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync); + +HANDLE pcap_getevent(pcap_t *p); + +struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size); + +int pcap_setuserbuffer(pcap_t *p, int size); + +int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks); + +int pcap_live_dump_ended(pcap_t *p, int sync); + +int pcap_offline_filter(struct bpf_program *prog, const struct pcap_pkthdr *header, const u_char *pkt_data); + +int pcap_start_oem(char* err_str, int flags); + +PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p); + +#ifdef __cplusplus +} +#endif + +#endif //__WIN32_EXTENSIONS_H__ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/arch.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/arch.c new file mode 100644 index 000000000..02bf82bf9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/arch.c @@ -0,0 +1,336 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* WinPCap includes. */ +#include "pcap.h" +#include "remote-ext.h" + +/* uIP includes. */ +#include "net/uip.h" +#include "net/uip_arp.h" +#include "net/clock-arch.h" + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* + * Query the computer the simulation is being executed on to find the network + * interfaces it has installed. + */ +static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ); + +/* + * Open the network interface. The number of the interface to be opened is set + * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. + */ +static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ); + +/* + * Configure the capture filter to allow blocking reads, and to filter out + * packets that are not of interest to this demo. + */ +static void prvConfigureCaptureBehaviour( void ); + +pcap_t *pxOpenedInterfaceHandle = NULL; +LARGE_INTEGER freq, sys_start_time; + +#define archNUM_BUFFERS 5 +#define archNUM_BUFFER_POINTERS ( archNUM_BUFFERS - 1 ) + +static void prvInterruptSimulator( void *pvParameters ); + +static unsigned char ucEthernetBuffer[ archNUM_BUFFERS ][ UIP_CONF_BUFFER_SIZE ]; +static unsigned char *pucEthernetBufferPointers[ archNUM_BUFFER_POINTERS ]; + +static long lLengthOfDataInBuffer[ archNUM_BUFFER_POINTERS ] = { 0 }; +static unsigned char ucNextBufferToFill = 0U, ucNextBufferToProcess = 0U; + +unsigned char *uip_buf = NULL; +char cErrorBuffer[PCAP_ERRBUF_SIZE]; + +void vNetifTx( void ) +{ + pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len ); + pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len ); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxNetifRx( void ) +{ +UBaseType_t xDataLen; +unsigned char *pucTemp; + + /* Check there is really data available. */ + xDataLen = lLengthOfDataInBuffer[ ucNextBufferToProcess ]; + if( xDataLen != 0L ) + { + + /* The buffer pointed to by uip_buf is going to change. Remember which + buffer uip_buf is currently pointing to. */ + pucTemp = uip_buf; + + /* Point uip_buf at the next buffer that contains data. */ + uip_buf = pucEthernetBufferPointers[ ucNextBufferToProcess ]; + + /* The buffer pointed to by + pucEthernetBufferPointeres[ ucNextBufferToProcess ] is now in use by + uip_buf, but the buffer uip_buf was pointing to on entry to this + function is free. Set + pucEthernetBufferPointeres[ ucNextBufferToProcess ] to the free + buffer. */ + pucEthernetBufferPointers[ ucNextBufferToProcess ] = pucTemp; + lLengthOfDataInBuffer[ ucNextBufferToProcess ] = 0L; + + ucNextBufferToProcess++; + if( ucNextBufferToProcess >= archNUM_BUFFER_POINTERS ) + { + ucNextBufferToProcess = 0L; + } + } + + return xDataLen; +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetifInit( void ) +{ +BaseType_t x; +pcap_if_t *pxAllNetworkInterfaces; + + /* Allocate a free buffer to each buffer pointer. */ + for( x = 0; x < sizeof( pucEthernetBufferPointers ) / sizeof( unsigned char * ); x++ ) + { + pucEthernetBufferPointers[ x ] = &( ucEthernetBuffer[ x ][ 0 ] ); + } + + /* Start with uip_buf pointing to a buffer that is not referenced from the + pucEthernetBufferPointers[] array. */ + uip_buf = &( ucEthernetBuffer[ archNUM_BUFFERS - 1 ][ 0 ] ); + + /* Query the computer the simulation is being executed on to find the + network interfaces it has installed. */ + pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces(); + + /* Open the network interface. The number of the interface to be opened is + set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. + Calling this function will set the pxOpenedInterfaceHandle variable. If, + after calling this function, pxOpenedInterfaceHandle is equal to NULL, then + the interface could not be opened. */ + if( pxAllNetworkInterfaces != NULL ) + { + prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces ); + } + + + return x; +} +/*-----------------------------------------------------------*/ + +static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ) +{ +pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface; +long lInterfaceNumber = 1; + + if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 ) + { + printf( "\r\nCould not obtain a list of network interfaces\r\n%s\r\n", cErrorBuffer ); + pxAllNetworkInterfaces = NULL; + } + + if( pxAllNetworkInterfaces != NULL ) + { + /* Print out the list of network interfaces. The first in the list + is interface '1', not interface '0'. */ + for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next ) + { + printf( "%d. %s", lInterfaceNumber, xInterface->name ); + + if( xInterface->description != NULL ) + { + printf( " (%s)\r\n", xInterface->description ); + } + else + { + printf( " (No description available)\r\n") ; + } + + lInterfaceNumber++; + } + } + + if( lInterfaceNumber == 1 ) + { + /* The interface number was never incremented, so the above for() loop + did not execute meaning no interfaces were found. */ + printf( " \r\nNo network interfaces were found.\r\n" ); + pxAllNetworkInterfaces = NULL; + } + + printf( "\r\nThe interface that will be opened is set by configNETWORK_INTERFACE_TO_USE which should be defined in FreeRTOSConfig.h\r\n" ); + printf( "Attempting to open interface number %d.\r\n", configNETWORK_INTERFACE_TO_USE ); + + if( ( configNETWORK_INTERFACE_TO_USE < 1L ) || ( configNETWORK_INTERFACE_TO_USE > lInterfaceNumber ) ) + { + printf("\r\nconfigNETWORK_INTERFACE_TO_USE is not in the valid range.\r\n" ); + + if( pxAllNetworkInterfaces != NULL ) + { + /* Free the device list, as no devices are going to be opened. */ + pcap_freealldevs( pxAllNetworkInterfaces ); + pxAllNetworkInterfaces = NULL; + } + } + + return pxAllNetworkInterfaces; +} +/*-----------------------------------------------------------*/ + +static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ) +{ +pcap_if_t *xInterface; +long x; + + /* Walk the list of devices until the selected device is located. */ + xInterface = pxAllNetworkInterfaces; + for( x = 0L; x < ( configNETWORK_INTERFACE_TO_USE - 1L ); x++ ) + { + xInterface = xInterface->next; + } + + /* Open the selected interface. */ + pxOpenedInterfaceHandle = pcap_open( xInterface->name, /* The name of the selected interface. */ + UIP_CONF_BUFFER_SIZE, /* The size of the packet to capture. */ + PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscious mode as the MAC and + IP address is going to be "simulated", and + not be the real MAC and IP address. This allows + trafic to the simulated IP address to be routed + to uIP, and trafic to the real IP address to be + routed to the Windows TCP/IP stack. */ + 0xfffffffL, /* The read time out. This is going to block + until data is available. */ + NULL, /* No authentication is required as this is + not a remote capture session. */ + cErrorBuffer + ); + + if ( pxOpenedInterfaceHandle == NULL ) + { + printf( "\r\n%s is not supported by WinPcap and cannot be opened\r\n", xInterface->name ); + } + else + { + /* Configure the capture filter to allow blocking reads, and to filter + out packets that are not of interest to this demo. */ + prvConfigureCaptureBehaviour(); + } + + /* The device list is no longer required. */ + pcap_freealldevs( pxAllNetworkInterfaces ); +} +/*-----------------------------------------------------------*/ + +static void prvConfigureCaptureBehaviour( void ) +{ +struct bpf_program xFilterCode; +const long lMinBytesToCopy = 10L, lBlocking = 0L; +unsigned long ulNetMask; + + /* Unblock a read as soon as anything is received. */ + pcap_setmintocopy( pxOpenedInterfaceHandle, lMinBytesToCopy ); + + /* Allow blocking. */ + pcap_setnonblock( pxOpenedInterfaceHandle, lBlocking, cErrorBuffer ); + + /* Set up a filter so only the packets of interest are passed to the uIP + stack. cErrorBuffer is used for convenience to create the string. Don't + confuse this with an error message. */ + sprintf( cErrorBuffer, "broadcast or multicast or host %d.%d.%d.%d", configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 ); + + ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0; + + if( pcap_compile(pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 ) + { + printf("\r\nThe packet filter string is invalid\r\n" ); + } + else + { + if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 ) + { + printf( "\r\nAn error occurred setting the packet filter.\r\n" ); + } + } + + /* Create a task that simulates an interrupt in a real system. This will + block waiting for packets, then send a message to the uIP task when data + is available. */ + xTaskCreate( prvInterruptSimulator, ( signed char * ) "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, ( configuIP_TASK_PRIORITY - 1 ), NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvInterruptSimulator( void *pvParameters ) +{ +static struct pcap_pkthdr *pxHeader; +const unsigned char *pucPacketData; +extern QueueHandle_t xEMACEventQueue; +const unsigned long ulRxEvent = uipETHERNET_RX_EVENT; +long lResult; + + /* Just to kill the compiler warning. */ + ( void ) pvParameters; + + for( ;; ) + { + /* Get the next packet. */ + lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData ); + if( lResult ) + { + /* Is the next buffer into which data should be placed free? */ + if( lLengthOfDataInBuffer[ ucNextBufferToFill ] == 0L ) + { + /* Copy the data from the captured packet into the buffer. */ + memcpy( pucEthernetBufferPointers[ ucNextBufferToFill ], pucPacketData, pxHeader->len ); + + /* Note the amount of data that was copied. */ + lLengthOfDataInBuffer[ ucNextBufferToFill ] = pxHeader->len; + + /* Move onto the next buffer, wrapping around if necessary. */ + ucNextBufferToFill++; + if( ucNextBufferToFill >= archNUM_BUFFER_POINTERS ) + { + ucNextBufferToFill = 0U; + } + + /* Data was received and stored. Send a message to the uIP task + to let it know. */ + xQueueSendToBack( xEMACEventQueue, &ulRxEvent, portMAX_DELAY ); + } + } + } +} + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/bittypes.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/bittypes.h new file mode 100644 index 000000000..fcacd45fe --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/bittypes.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 1999 WIDE Project. + * 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. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. + */ +#ifndef _BITTYPES_H +#define _BITTYPES_H + +#ifndef HAVE_U_INT8_T + +#if SIZEOF_CHAR == 1 +typedef unsigned char u_int8_t; +typedef signed char _int8_t; +#elif SIZEOF_INT == 1 +typedef unsigned int u_int8_t; +typedef signed int int8_t; +#else /* XXX */ +#error "there's no appropriate type for u_int8_t" +#endif +#define HAVE_U_INT8_T 1 +#define HAVE_INT8_T 1 + +#endif /* HAVE_U_INT8_T */ + +#ifndef HAVE_U_INT16_T + +#if SIZEOF_SHORT == 2 +typedef unsigned short u_int16_t; +typedef signed short _int16_t; +#elif SIZEOF_INT == 2 +typedef unsigned int u_int16_t; +typedef signed int int16_t; +#elif SIZEOF_CHAR == 2 +typedef unsigned char u_int16_t; +typedef signed char int16_t; +#else /* XXX */ +#error "there's no appropriate type for u_int16_t" +#endif +#define HAVE_U_INT16_T 1 +#define HAVE_INT16_T 1 + +#endif /* HAVE_U_INT16_T */ + +#ifndef HAVE_U_INT32_T + +#if SIZEOF_INT == 4 +typedef unsigned int u_int32_t; +typedef signed int _int32_t; +#elif SIZEOF_LONG == 4 +typedef unsigned long u_int32_t; +typedef signed long int32_t; +#elif SIZEOF_SHORT == 4 +typedef unsigned short u_int32_t; +typedef signed short int32_t; +#else /* XXX */ +#error "there's no appropriate type for u_int32_t" +#endif +#define HAVE_U_INT32_T 1 +#define HAVE_INT32_T 1 + +#endif /* HAVE_U_INT32_T */ + +#ifndef HAVE_U_INT64_T +#if SIZEOF_LONG_LONG == 8 +typedef unsigned long long u_int64_t; +typedef long long int64_t; +#elif defined(_MSC_EXTENSIONS) +typedef unsigned _int64 u_int64_t; +typedef _int64 int64_t; +#elif SIZEOF_INT == 8 +typedef unsigned int u_int64_t; +#elif SIZEOF_LONG == 8 +typedef unsigned long u_int64_t; +#elif SIZEOF_SHORT == 8 +typedef unsigned short u_int64_t; +#else /* XXX */ +#error "there's no appropriate type for u_int64_t" +#endif + +#endif /* HAVE_U_INT64_T */ + +#ifndef PRId64 +#ifdef _MSC_EXTENSIONS +#define PRId64 "I64d" +#else /* _MSC_EXTENSIONS */ +#define PRId64 "lld" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRId64 */ + +#ifndef PRIo64 +#ifdef _MSC_EXTENSIONS +#define PRIo64 "I64o" +#else /* _MSC_EXTENSIONS */ +#define PRIo64 "llo" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIo64 */ + +#ifndef PRIx64 +#ifdef _MSC_EXTENSIONS +#define PRIx64 "I64x" +#else /* _MSC_EXTENSIONS */ +#define PRIx64 "llx" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIx64 */ + +#ifndef PRIu64 +#ifdef _MSC_EXTENSIONS +#define PRIu64 "I64u" +#else /* _MSC_EXTENSIONS */ +#define PRIu64 "llu" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIu64 */ + +#endif /* _BITTYPES_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/ip6_misc.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/ip6_misc.h new file mode 100644 index 000000000..96822d0e8 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/ip6_misc.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1993, 1994, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: /tcpdump/master/libpcap/Win32/Include/ip6_misc.h,v 1.5 2006-01-22 18:02:18 gianluca Exp $ (LBL) + */ + +/* + * This file contains a collage of declarations for IPv6 from FreeBSD not present in Windows + */ + +#include + +#include + +#ifndef __MINGW32__ +#define IN_MULTICAST(a) IN_CLASSD(a) +#endif + +#define IN_EXPERIMENTAL(a) ((((u_int32_t) (a)) & 0xf0000000) == 0xf0000000) + +#define IN_LOOPBACKNET 127 + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +/* IPv6 address */ +struct in6_addr + { + union + { + u_int8_t u6_addr8[16]; + u_int16_t u6_addr16[8]; + u_int32_t u6_addr32[4]; + } in6_u; +#define s6_addr in6_u.u6_addr8 +#define s6_addr16 in6_u.u6_addr16 +#define s6_addr32 in6_u.u6_addr32 +#define s6_addr64 in6_u.u6_addr64 + }; + +#define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } +#endif /* __MINGW32__ */ + + +#if (defined _MSC_VER) || (defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)) +typedef unsigned short sa_family_t; +#endif + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) + +#define __SOCKADDR_COMMON(sa_prefix) \ + sa_family_t sa_prefix##family + +/* Ditto, for IPv6. */ +struct sockaddr_in6 + { + __SOCKADDR_COMMON (sin6_); + u_int16_t sin6_port; /* Transport layer port # */ + u_int32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + }; + +#define IN6_IS_ADDR_V4MAPPED(a) \ + ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \ + (((u_int32_t *) (a))[2] == htonl (0xffff))) + +#define IN6_IS_ADDR_MULTICAST(a) (((u_int8_t *) (a))[0] == 0xff) + +#define IN6_IS_ADDR_LINKLOCAL(a) \ + ((((u_int32_t *) (a))[0] & htonl (0xffc00000)) == htonl (0xfe800000)) + +#define IN6_IS_ADDR_LOOPBACK(a) \ + (((u_int32_t *) (a))[0] == 0 && ((u_int32_t *) (a))[1] == 0 && \ + ((u_int32_t *) (a))[2] == 0 && ((u_int32_t *) (a))[3] == htonl (1)) +#endif /* __MINGW32__ */ + +#define ip6_vfc ip6_ctlun.ip6_un2_vfc +#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt +#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim +#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim + +#define nd_rd_type nd_rd_hdr.icmp6_type +#define nd_rd_code nd_rd_hdr.icmp6_code +#define nd_rd_cksum nd_rd_hdr.icmp6_cksum +#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0] + +/* + * IPV6 extension headers + */ +#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */ +#define IPPROTO_IPV6 41 /* IPv6 header. */ +#define IPPROTO_ROUTING 43 /* IPv6 routing header */ +#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ +#define IPPROTO_ESP 50 /* encapsulating security payload */ +#define IPPROTO_AH 51 /* authentication header */ +#define IPPROTO_ICMPV6 58 /* ICMPv6 */ +#define IPPROTO_NONE 59 /* IPv6 no next header */ +#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ +#define IPPROTO_PIM 103 /* Protocol Independent Multicast. */ + +#define IPV6_RTHDR_TYPE_0 0 + +/* Option types and related macros */ +#define IP6OPT_PAD1 0x00 /* 00 0 00000 */ +#define IP6OPT_PADN 0x01 /* 00 0 00001 */ +#define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ +#define IP6OPT_JUMBO_LEN 6 +#define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 */ + +#define IP6OPT_RTALERT_LEN 4 +#define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ +#define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ +#define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ +#define IP6OPT_MINLEN 2 + +#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */ +#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */ +#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */ +#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */ +#define IP6OPT_EID 0x8a /* 10 0 01010 */ + +#define IP6OPT_TYPE(o) ((o) & 0xC0) +#define IP6OPT_TYPE_SKIP 0x00 +#define IP6OPT_TYPE_DISCARD 0x40 +#define IP6OPT_TYPE_FORCEICMP 0x80 +#define IP6OPT_TYPE_ICMP 0xC0 + +#define IP6OPT_MUTABLE 0x20 + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +#ifndef EAI_ADDRFAMILY +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; +#endif +#endif /* __MINGW32__ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/netif.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/netif.h new file mode 100644 index 000000000..2d51478c0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/netif.h @@ -0,0 +1,52 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef NET_IF_H +#define NET_IF_H + +/* + * Send uip_len bytes from uip_buf to the network interface selected by the + * configNETWORK_INTERFACE_TO_USE constant (defined in FreeRTOSConfig.h). + */ +void vNetifTx( void ); + +/* + * Receive bytes from the network interface selected by the + * configNETWORK_INTERFACE_TO_USE constant (defined in FreeRTOSConfig.h). The + * bytes are placed in uip_buf. The number of bytes copied into uip_buf is + * returned. + */ +UBaseType_t uxNetifRx( void ); + +/* + * Prepare a packet capture session. This will print out all the network + * interfaces available, and the one actually used is set by the + * configNETWORK_INTERFACE_TO_USE constant that is defined in + * FreeRTOSConfig.h. */ +BaseType_t xNetifInit( void ); + +#endif /* NET_IF_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap-bpf.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap-bpf.h new file mode 100644 index 000000000..ff5b6e0da --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap-bpf.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.50 2007/04/01 21:43:55 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap-namedb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap-namedb.h new file mode 100644 index 000000000..ee6715fba --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap-namedb.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-namedb.h,v 1.13 2006/10/04 18:13:32 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap-stdinc.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap-stdinc.h new file mode 100644 index 000000000..cbd62d169 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap-stdinc.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-stdinc.h,v 1.10.2.1 2008-10-06 15:38:39 gianluca Exp $ (LBL) + */ + +#define SIZEOF_CHAR 1 +#define SIZEOF_SHORT 2 +#define SIZEOF_INT 4 +#ifndef _MSC_EXTENSIONS +#define SIZEOF_LONG_LONG 8 +#endif + +/* + * Avoids a compiler warning in case this was already defined + * (someone defined _WINSOCKAPI_ when including 'windows.h', in order + * to prevent it from including 'winsock.h') + */ +#ifdef _WINSOCKAPI_ +#undef _WINSOCKAPI_ +#endif +#include + +#include + +#include "bittypes.h" +#include +#include + +#ifndef __MINGW32__ +#include "IP6_misc.h" +#endif + +#define caddr_t char* + +#if _MSC_VER < 1500 +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#define strdup _strdup +#endif + +#define inline __inline + +#ifdef __MINGW32__ +#include +#else /*__MINGW32__*/ +/* MSVC compiler */ +#ifndef _UINTPTR_T_DEFINED +#ifdef _WIN64 +typedef unsigned __int64 uintptr_t; +#else +typedef _W64 unsigned int uintptr_t; +#endif +#define _UINTPTR_T_DEFINED +#endif + +#ifndef _INTPTR_T_DEFINED +#ifdef _WIN64 +typedef __int64 intptr_t; +#else +typedef _W64 int intptr_t; +#endif +#define _INTPTR_T_DEFINED +#endif + +#endif /*__MINGW32__*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap.h new file mode 100644 index 000000000..2eea0750b --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.59 2006/10/04 18:09:22 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Many applications + * expect to be able to include , and at least some of them + * go through contortions in their configure scripts to try to detect + * OSes that have "helpfully" moved pcap.h to without + * leaving behind a file. + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/bluetooth.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/bluetooth.h new file mode 100644 index 000000000..28b991f43 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/bluetooth.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * bluetooth data struct + * By Paolo Abeni + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/bluetooth.h,v 1.1 2007/09/22 02:10:17 guy Exp $ + */ + +#ifndef _PCAP_BLUETOOTH_STRUCTS_H__ +#define _PCAP_BLUETOOTH_STRUCTS_H__ + +/* + * Header prepended libpcap to each bluetooth h:4 frame. + * fields are in network byte order + */ +typedef struct _pcap_bluetooth_h4_header { + u_int32_t direction; /* if first bit is set direction is incoming */ +} pcap_bluetooth_h4_header; + + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/bpf.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/bpf.h new file mode 100644 index 000000000..b6d259679 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/bpf.h @@ -0,0 +1,934 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)bpf.h 7.1 (Berkeley) 5/7/91 + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/bpf.h,v 1.19.2.8 2008-09-22 20:16:01 guy Exp $ (LBL) + */ + +/* + * This is libpcap's cut-down version of bpf.h; it includes only + * the stuff needed for the code generator and the userland BPF + * interpreter, and the libpcap APIs for setting filters, etc.. + * + * "pcap-bpf.c" will include the native OS version, as it deals with + * the OS's BPF implementation. + * + * XXX - should this all just be moved to "pcap.h"? + */ + +#ifndef BPF_MAJOR_VERSION + +#ifdef __cplusplus +extern "C" { +#endif + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +#ifdef MSDOS /* must be 32-bit */ +typedef long bpf_int32; +typedef unsigned long bpf_u_int32; +#else +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +/* + * Alignment macros. BPF_WORDALIGN rounds up to the next + * even multiple of BPF_ALIGNMENT. + */ +#ifndef __NetBSD__ +#define BPF_ALIGNMENT sizeof(bpf_int32) +#else +#define BPF_ALIGNMENT sizeof(long) +#endif +#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) + +#define BPF_MAXBUFSIZE 0x8000 +#define BPF_MINBUFSIZE 32 + +/* + * Structure for "pcap_compile()", "pcap_setfilter()", etc.. + */ +struct bpf_program { + u_int bf_len; + struct bpf_insn *bf_insns; +}; + +/* + * Struct return by BIOCVERSION. This represents the version number of + * the filter language described by the instruction encodings below. + * bpf understands a program iff kernel_major == filter_major && + * kernel_minor >= filter_minor, that is, if the value returned by the + * running kernel has the same major number and a minor number equal + * equal to or less than the filter being downloaded. Otherwise, the + * results are undefined, meaning an error may be returned or packets + * may be accepted haphazardly. + * It has nothing to do with the source code version. + */ +struct bpf_version { + u_short bv_major; + u_short bv_minor; +}; +/* Current version number of filter architecture. */ +#define BPF_MAJOR_VERSION 1 +#define BPF_MINOR_VERSION 1 + +/* + * Data-link level type codes. + * + * Do *NOT* add new values to this list without asking + * "tcpdump-workers@lists.tcpdump.org" for a value. Otherwise, you run + * the risk of using a value that's already being used for some other + * purpose, and of having tools that read libpcap-format captures not + * being able to handle captures with your new DLT_ value, with no hope + * that they will ever be changed to do so (as that would destroy their + * ability to read captures using that value for that other purpose). + */ + +/* + * These are the types that are the same on all platforms, and that + * have been defined by for ages. + */ +#define DLT_NULL 0 /* BSD loopback encapsulation */ +#define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ +#define DLT_AX25 3 /* Amateur Radio AX.25 */ +#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ +#define DLT_CHAOS 5 /* Chaos */ +#define DLT_IEEE802 6 /* 802.5 Token Ring */ +#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ +#define DLT_SLIP 8 /* Serial Line IP */ +#define DLT_PPP 9 /* Point-to-point Protocol */ +#define DLT_FDDI 10 /* FDDI */ + +/* + * These are types that are different on some platforms, and that + * have been defined by for ages. We use #ifdefs to + * detect the BSDs that define them differently from the traditional + * libpcap + * + * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS, + * but I don't know what the right #define is for BSD/OS. + */ +#define DLT_ATM_RFC1483 11 /* LLC-encapsulated ATM */ + +#ifdef __OpenBSD__ +#define DLT_RAW 14 /* raw IP */ +#else +#define DLT_RAW 12 /* raw IP */ +#endif + +/* + * Given that the only OS that currently generates BSD/OS SLIP or PPP + * is, well, BSD/OS, arguably everybody should have chosen its values + * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they + * didn't. So it goes. + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) +#ifndef DLT_SLIP_BSDOS +#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ +#endif +#else +#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ +#endif + +/* + * 17 is used for DLT_OLD_PFLOG in OpenBSD; + * OBSOLETE: DLT_PFLOG is 117 in OpenBSD now as well. See below. + * 18 is used for DLT_PFSYNC in OpenBSD; don't use it for anything else. + */ + +#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ + +/* + * Apparently Redback uses this for its SmartEdge 400/800. I hope + * nobody else decided to use it, too. + */ +#define DLT_REDBACK_SMARTEDGE 32 + +/* + * These values are defined by NetBSD; other platforms should refrain from + * using them for other purposes, so that NetBSD savefiles with link + * types of 50 or 51 can be read as this type on all platforms. + */ +#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ +#define DLT_PPP_ETHER 51 /* PPP over Ethernet */ + +/* + * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses + * a link-layer type of 99 for the tcpdump it supplies. The link-layer + * header has 6 bytes of unknown data, something that appears to be an + * Ethernet type, and 36 bytes that appear to be 0 in at least one capture + * I've seen. + */ +#define DLT_SYMANTEC_FIREWALL 99 + +/* + * Values between 100 and 103 are used in capture file headers as + * link-layer types corresponding to DLT_ types that differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * This value was defined by libpcap 0.5; platforms that have defined + * it with a different value should define it here with that value - + * a link type of 104 in a save file will be mapped to DLT_C_HDLC, + * whatever value that happens to be, so programs will correctly + * handle files with that link type regardless of the value of + * DLT_C_HDLC. + * + * The name DLT_C_HDLC was used by BSD/OS; we use that name for source + * compatibility with programs written for BSD/OS. + * + * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, + * for source compatibility with programs written for libpcap 0.5. + */ +#define DLT_C_HDLC 104 /* Cisco HDLC */ +#define DLT_CHDLC DLT_C_HDLC + +#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ + +/* + * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW, + * except when it isn't. (I.e., sometimes it's just raw IP, and + * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL, + * so that we don't have to worry about the link-layer header.) + */ + +/* + * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides + * with other values. + * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header + * (DLCI, etc.). + */ +#define DLT_FRELAY 107 + +/* + * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except + * that the AF_ type in the link-layer header is in network byte order. + * + * DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so + * we don't use 12 for it in OSes other than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_LOOP 12 +#else +#define DLT_LOOP 108 +#endif + +/* + * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's + * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other + * than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_ENC 13 +#else +#define DLT_ENC 109 +#endif + +/* + * Values between 110 and 112 are reserved for use in capture file headers + * as link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ types + * other than the corresponding DLT_ types. + */ + +/* + * This is for Linux cooked sockets. + */ +#define DLT_LINUX_SLL 113 + +/* + * Apple LocalTalk hardware. + */ +#define DLT_LTALK 114 + +/* + * Acorn Econet. + */ +#define DLT_ECONET 115 + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define DLT_IPFILTER 116 + +/* + * OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, but that's DLT_LANE8023 + * in SuSE 6.3, so we can't use 17 for it in capture-file headers. + * + * XXX: is there a conflict with DLT_PFSYNC 18 as well? + */ +#ifdef __OpenBSD__ +#define DLT_OLD_PFLOG 17 +#define DLT_PFSYNC 18 +#endif +#define DLT_PFLOG 117 + +/* + * Registered for Cisco-internal use. + */ +#define DLT_CISCO_IOS 118 + +/* + * For 802.11 cards using the Prism II chips, with a link-layer + * header including Prism monitor mode information plus an 802.11 + * header. + */ +#define DLT_PRISM_HEADER 119 + +/* + * Reserved for Aironet 802.11 cards, with an Aironet link-layer header + * (see Doug Ambrisko's FreeBSD patches). + */ +#define DLT_AIRONET_HEADER 120 + +/* + * Reserved for Siemens HiPath HDLC. + */ +#define DLT_HHDLC 121 + +/* + * This is for RFC 2625 IP-over-Fibre Channel. + * + * This is not for use with raw Fibre Channel, where the link-layer + * header starts with a Fibre Channel frame header; it's for IP-over-FC, + * where the link-layer header starts with an RFC 2625 Network_Header + * field. + */ +#define DLT_IP_OVER_FC 122 + +/* + * This is for Full Frontal ATM on Solaris with SunATM, with a + * pseudo-header followed by an AALn PDU. + * + * There may be other forms of Full Frontal ATM on other OSes, + * with different pseudo-headers. + * + * If ATM software returns a pseudo-header with VPI/VCI information + * (and, ideally, packet type information, e.g. signalling, ILMI, + * LANE, LLC-multiplexed traffic, etc.), it should not use + * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump + * and the like don't have to infer the presence or absence of a + * pseudo-header and the form of the pseudo-header. + */ +#define DLT_SUNATM 123 /* Solaris+SunATM */ + +/* + * Reserved as per request from Kent Dahlgren + * for private use. + */ +#define DLT_RIO 124 /* RapidIO */ +#define DLT_PCI_EXP 125 /* PCI Express */ +#define DLT_AURORA 126 /* Xilinx Aurora link layer */ + +/* + * Header for 802.11 plus a number of bits of link-layer information + * including radio information, used by some recent BSD drivers as + * well as the madwifi Atheros driver for Linux. + */ +#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */ + +/* + * Reserved for the TZSP encapsulation, as per request from + * Chris Waters + * TZSP is a generic encapsulation for any other link type, + * which includes a means to include meta-information + * with the packet, e.g. signal strength and channel + * for 802.11 packets. + */ +#define DLT_TZSP 128 /* Tazmen Sniffer Protocol */ + +/* + * BSD's ARCNET headers have the source host, destination host, + * and type at the beginning of the packet; that's what's handed + * up to userland via BPF. + * + * Linux's ARCNET headers, however, have a 2-byte offset field + * between the host IDs and the type; that's what's handed up + * to userland via PF_PACKET sockets. + * + * We therefore have to have separate DLT_ values for them. + */ +#define DLT_ARCNET_LINUX 129 /* ARCNET */ + +/* + * Juniper-private data link types, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MLPPP 130 +#define DLT_JUNIPER_MLFR 131 +#define DLT_JUNIPER_ES 132 +#define DLT_JUNIPER_GGSN 133 +#define DLT_JUNIPER_MFR 134 +#define DLT_JUNIPER_ATM2 135 +#define DLT_JUNIPER_SERVICES 136 +#define DLT_JUNIPER_ATM1 137 + +/* + * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund + * . The header that's presented is an Ethernet-like + * header: + * + * #define FIREWIRE_EUI64_LEN 8 + * struct firewire_header { + * u_char firewire_dhost[FIREWIRE_EUI64_LEN]; + * u_char firewire_shost[FIREWIRE_EUI64_LEN]; + * u_short firewire_type; + * }; + * + * with "firewire_type" being an Ethernet type value, rather than, + * for example, raw GASP frames being handed up. + */ +#define DLT_APPLE_IP_OVER_IEEE1394 138 + +/* + * Various SS7 encapsulations, as per a request from Jeff Morriss + * and subsequent discussions. + */ +#define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */ +#define DLT_MTP2 140 /* MTP2, without pseudo-header */ +#define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */ +#define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */ + +/* + * DOCSIS MAC frames. + */ +#define DLT_DOCSIS 143 + +/* + * Linux-IrDA packets. Protocol defined at http://www.irda.org. + * Those packets include IrLAP headers and above (IrLMP...), but + * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy + * framing can be handled by the hardware and depend on the bitrate. + * This is exactly the format you would get capturing on a Linux-IrDA + * interface (irdaX), but not on a raw serial port. + * Note the capture is done in "Linux-cooked" mode, so each packet include + * a fake packet header (struct sll_header). This is because IrDA packet + * decoding is dependant on the direction of the packet (incomming or + * outgoing). + * When/if other platform implement IrDA capture, we may revisit the + * issue and define a real DLT_IRDA... + * Jean II + */ +#define DLT_LINUX_IRDA 144 + +/* + * Reserved for IBM SP switch and IBM Next Federation switch. + */ +#define DLT_IBM_SP 145 +#define DLT_IBM_SN 146 + +/* + * Reserved for private use. If you have some link-layer header type + * that you want to use within your organization, with the capture files + * using that link-layer header type not ever be sent outside your + * organization, you can use these values. + * + * No libpcap release will use these for any purpose, nor will any + * tcpdump release use them, either. + * + * Do *NOT* use these in capture files that you expect anybody not using + * your private versions of capture-file-reading tools to read; in + * particular, do *NOT* use them in products, otherwise you may find that + * people won't be able to use tcpdump, or snort, or Ethereal, or... to + * read capture files from your firewall/intrusion detection/traffic + * monitoring/etc. appliance, or whatever product uses that DLT_ value, + * and you may also find that the developers of those applications will + * not accept patches to let them read those files. + * + * Also, do not use them if somebody might send you a capture using them + * for *their* private type and tools using them for *your* private type + * would have to read them. + * + * Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value, + * as per the comment above, and use the type you're given. + */ +#define DLT_USER0 147 +#define DLT_USER1 148 +#define DLT_USER2 149 +#define DLT_USER3 150 +#define DLT_USER4 151 +#define DLT_USER5 152 +#define DLT_USER6 153 +#define DLT_USER7 154 +#define DLT_USER8 155 +#define DLT_USER9 156 +#define DLT_USER10 157 +#define DLT_USER11 158 +#define DLT_USER12 159 +#define DLT_USER13 160 +#define DLT_USER14 161 +#define DLT_USER15 162 + +/* + * For future use with 802.11 captures - defined by AbsoluteValue + * Systems to store a number of bits of link-layer information + * including radio information: + * + * http://www.shaftnet.org/~pizza/software/capturefrm.txt + * + * but it might be used by some non-AVS drivers now or in the + * future. + */ +#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MONITOR 164 + +/* + * Reserved for BACnet MS/TP. + */ +#define DLT_BACNET_MS_TP 165 + +/* + * Another PPP variant as per request from Karsten Keil . + * + * This is used in some OSes to allow a kernel socket filter to distinguish + * between incoming and outgoing packets, on a socket intended to + * supply pppd with outgoing packets so it can do dial-on-demand and + * hangup-on-lack-of-demand; incoming packets are filtered out so they + * don't cause pppd to hold the connection up (you don't want random + * input packets such as port scans, packets from old lost connections, + * etc. to force the connection to stay up). + * + * The first byte of the PPP header (0xff03) is modified to accomodate + * the direction - 0x00 = IN, 0x01 = OUT. + */ +#define DLT_PPP_PPPD 166 + +/* + * Names for backwards compatibility with older versions of some PPP + * software; new software should use DLT_PPP_PPPD. + */ +#define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD +#define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, cookies, etc.. + */ +#define DLT_JUNIPER_PPPOE 167 +#define DLT_JUNIPER_PPPOE_ATM 168 + +#define DLT_GPRS_LLC 169 /* GPRS LLC */ +#define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ +#define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ + +/* + * Requested by Oolan Zimmer for use in Gcom's T1/E1 line + * monitoring equipment. + */ +#define DLT_GCOM_T1E1 172 +#define DLT_GCOM_SERIAL 173 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_ is used + * for internal communication to Physical Interface Cards (PIC) + */ +#define DLT_JUNIPER_PIC_PEER 174 + +/* + * Link types requested by Gregor Maier of Endace + * Measurement Systems. They add an ERF header (see + * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of + * the link-layer header. + */ +#define DLT_ERF_ETH 175 /* Ethernet */ +#define DLT_ERF_POS 176 /* Packet-over-SONET */ + +/* + * Requested by Daniele Orlandi for raw LAPD + * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header + * includes additional information before the LAPD header, so it's + * not necessarily a generic LAPD header. + */ +#define DLT_LINUX_LAPD 177 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ are used for prepending meta-information + * like interface index, interface name + * before standard Ethernet, PPP, Frelay & C-HDLC Frames + */ +#define DLT_JUNIPER_ETHER 178 +#define DLT_JUNIPER_PPP 179 +#define DLT_JUNIPER_FRELAY 180 +#define DLT_JUNIPER_CHDLC 181 + +/* + * Multi Link Frame Relay (FRF.16) + */ +#define DLT_MFR 182 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * voice Adapter Card (PIC) + */ +#define DLT_JUNIPER_VP 183 + +/* + * Arinc 429 frames. + * DLT_ requested by Gianluca Varenni . + * Every frame contains a 32bit A429 label. + * More documentation on Arinc 429 can be found at + * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf + */ +#define DLT_A429 184 + +/* + * Arinc 653 Interpartition Communication messages. + * DLT_ requested by Gianluca Varenni . + * Please refer to the A653-1 standard for more information. + */ +#define DLT_A653_ICM 185 + +/* + * USB packets, beginning with a USB setup header; requested by + * Paolo Abeni . + */ +#define DLT_USB 186 + +/* + * Bluetooth HCI UART transport layer (part H:4); requested by + * Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4 187 + +/* + * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz + * . + */ +#define DLT_IEEE802_16_MAC_CPS 188 + +/* + * USB packets, beginning with a Linux USB header; requested by + * Paolo Abeni . + */ +#define DLT_USB_LINUX 189 + +/* + * Controller Area Network (CAN) v. 2.0B packets. + * DLT_ requested by Gianluca Varenni . + * Used to dump CAN packets coming from a CAN Vector board. + * More documentation on the CAN v2.0B frames can be found at + * http://www.can-cia.org/downloads/?269 + */ +#define DLT_CAN20B 190 + +/* + * IEEE 802.15.4, with address fields padded, as is done by Linux + * drivers; requested by Juergen Schimmer. + */ +#define DLT_IEEE802_15_4_LINUX 191 + +/* + * Per Packet Information encapsulated packets. + * DLT_ requested by Gianluca Varenni . + */ +#define DLT_PPI 192 + +/* + * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; + * requested by Charles Clancy. + */ +#define DLT_IEEE802_16_MAC_CPS_RADIO 193 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * integrated service module (ISM). + */ +#define DLT_JUNIPER_ISM 194 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing); requested by Mikko Saarnivala . + */ +#define DLT_IEEE802_15_4 195 + +/* + * Various link-layer types, with a pseudo-header, for SITA + * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). + */ +#define DLT_SITA 196 + +/* + * Various link-layer types, with a pseudo-header, for Endace DAG cards; + * encapsulates Endace ERF records. Requested by Stephen Donnelly + * . + */ +#define DLT_ERF 197 + +/* + * Special header prepended to Ethernet packets when capturing from a + * u10 Networks board. Requested by Phil Mulholland + * . + */ +#define DLT_RAIF1 198 + +/* + * IPMB packet for IPMI, beginning with the I2C slave address, followed + * by the netFn and LUN, etc.. Requested by Chanthy Toeung + * . + */ +#define DLT_IPMB 199 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for capturing data on a secure tunnel interface. + */ +#define DLT_JUNIPER_ST 200 + +/* + * Bluetooth HCI UART transport layer (part H:4), with pseudo-header + * that includes direction information; requested by Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4_WITH_PHDR 201 + +/* + * AX.25 packet with a 1-byte KISS header; see + * + * http://www.ax25.net/kiss.htm + * + * as per Richard Stearn . + */ +#define DLT_AX25_KISS 202 + +/* + * LAPD packets from an ISDN channel, starting with the address field, + * with no pseudo-header. + * Requested by Varuna De Silva . + */ +#define DLT_LAPD 203 + +/* + * Variants of various link-layer headers, with a one-byte direction + * pseudo-header prepended - zero means "received by this host", + * non-zero (any non-zero value) means "sent by this host" - as per + * Will Barker . + */ +#define DLT_PPP_WITH_DIR 204 /* PPP - don't confuse with DLT_PPP_WITH_DIRECTION */ +#define DLT_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ +#define DLT_FRELAY_WITH_DIR 206 /* Frame Relay */ +#define DLT_LAPB_WITH_DIR 207 /* LAPB */ + +/* + * 208 is reserved for an as-yet-unspecified proprietary link-layer + * type, as requested by Will Barker. + */ + +/* + * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman + * . + */ +#define DLT_IPMB_LINUX 209 + +/* + * FlexRay automotive bus - http://www.flexray.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_FLEXRAY 210 + +/* + * Media Oriented Systems Transport (MOST) bus for multimedia + * transport - http://www.mostcooperation.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_MOST 211 + +/* + * Local Interconnect Network (LIN) bus for vehicle networks - + * http://www.lin-subbus.org/ - as requested by Hannes Kaelber + * . + */ +#define DLT_LIN 212 + +/* + * X2E-private data link type used for serial line capture, + * as requested by Hannes Kaelber . + */ +#define DLT_X2E_SERIAL 213 + +/* + * X2E-private data link type used for the Xoraya data logger + * family, as requested by Hannes Kaelber . + */ +#define DLT_X2E_XORAYA 214 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), but with the PHY-level data for non-ASK PHYs (4 octets + * of 0 as preamble, one octet of SFD, one octet of frame length+ + * reserved bit, and then the MAC-layer data, starting with the + * frame control field). + * + * Requested by Max Filippov . + */ +#define DLT_IEEE802_15_4_NONASK_PHY 215 + + +/* + * DLT and savefile link type values are split into a class and + * a member of that class. A class value of 0 indicates a regular + * DLT_/LINKTYPE_ value. + */ +#define DLT_CLASS(x) ((x) & 0x03ff0000) + +/* + * NetBSD-specific generic "raw" link type. The class value indicates + * that this is the generic raw type, and the lower 16 bits are the + * address family we're dealing with. Those values are NetBSD-specific; + * do not assume that they correspond to AF_ values for your operating + * system. + */ +#define DLT_CLASS_NETBSD_RAWAF 0x02240000 +#define DLT_NETBSD_RAWAF(af) (DLT_CLASS_NETBSD_RAWAF | (af)) +#define DLT_NETBSD_RAWAF_AF(x) ((x) & 0x0000ffff) +#define DLT_IS_NETBSD_RAWAF(x) (DLT_CLASS(x) == DLT_CLASS_NETBSD_RAWAF) + + +/* + * The instruction encodings. + */ +/* instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* ret - BPF_K and BPF_X also apply */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 + +/* misc */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +#define BPF_TXA 0x80 + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_u_int32 k; +}; + +/* + * Macros for insn array initializers. + */ +#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } +#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } + +#if __STDC__ || defined(__cplusplus) +extern int bpf_validate(const struct bpf_insn *, int); +extern u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +#else +extern int bpf_validate(); +extern u_int bpf_filter(); +#endif + +/* + * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). + */ +#define BPF_MEMWORDS 16 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/namedb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/namedb.h new file mode 100644 index 000000000..8298e35b9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/namedb.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/namedb.h,v 1.1 2006/10/04 18:09:22 guy Exp $ (LBL) + */ + +#ifndef lib_pcap_namedb_h +#define lib_pcap_namedb_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * As returned by the pcap_next_etherent() + * XXX this stuff doesn't belong in this interface, but this + * library already must do name to address translation, so + * on systems that don't have support for /etc/ethers, we + * export these hooks since they'll + */ +struct pcap_etherent { + u_char addr[6]; + char name[122]; +}; +#ifndef PCAP_ETHERS_FILE +#define PCAP_ETHERS_FILE "/etc/ethers" +#endif +struct pcap_etherent *pcap_next_etherent(FILE *); +u_char *pcap_ether_hostton(const char*); +u_char *pcap_ether_aton(const char *); + +bpf_u_int32 **pcap_nametoaddr(const char *); +#ifdef INET6 +struct addrinfo *pcap_nametoaddrinfo(const char *); +#endif +bpf_u_int32 pcap_nametonetaddr(const char *); + +int pcap_nametoport(const char *, int *, int *); +int pcap_nametoportrange(const char *, int *, int *, int *); +int pcap_nametoproto(const char *); +int pcap_nametoeproto(const char *); +int pcap_nametollc(const char *); +/* + * If a protocol is unknown, PROTO_UNDEF is returned. + * Also, pcap_nametoport() returns the protocol along with the port number. + * If there are ambiguous entried in /etc/services (i.e. domain + * can be either tcp or udp) PROTO_UNDEF is returned. + */ +#define PROTO_UNDEF -1 + +/* XXX move these to pcap-int.h? */ +int __pcap_atodn(const char *, bpf_u_int32 *); +int __pcap_atoin(const char *, bpf_u_int32 *); +u_short __pcap_nametodnaddr(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/pcap.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/pcap.h new file mode 100644 index 000000000..fbf83413a --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/pcap.h @@ -0,0 +1,407 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/pcap.h,v 1.4.2.11 2008-10-06 15:38:39 gianluca Exp $ (LBL) + */ + +#ifndef lib_pcap_pcap_h +#define lib_pcap_pcap_h + +#if defined(WIN32) + #include +#elif defined(MSDOS) + #include + #include /* u_int, u_char etc. */ +#else /* UN*X */ + #include + #include +#endif /* WIN32/MSDOS/UN*X */ + +#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H +#include +#endif + +#include + +#ifdef HAVE_REMOTE + // We have to define the SOCKET here, although it has been defined in sockutils.h + // This is to avoid the distribution of the 'sockutils.h' file around + // (for example in the WinPcap developer's pack) + #ifndef SOCKET + #ifdef WIN32 + #define SOCKET unsigned int + #else + #define SOCKET int + #endif + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 + +#define PCAP_ERRBUF_SIZE 256 + +/* + * Compatibility for systems that have a bpf.h that + * predates the bpf typedefs for 64-bit support. + */ +#if BPF_RELEASE - 0 < 199406 +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +typedef struct pcap pcap_t; +typedef struct pcap_dumper pcap_dumper_t; +typedef struct pcap_if pcap_if_t; +typedef struct pcap_addr pcap_addr_t; + +/* + * The first record in the file contains saved values for some + * of the flags used in the printout phases of tcpdump. + * Many fields here are 32 bit ints so compilers won't insert unwanted + * padding; these files need to be interchangeable across architectures. + * + * Do not change the layout of this structure, in any way (this includes + * changes that only affect the length of fields in this structure). + * + * Also, do not change the interpretation of any of the members of this + * structure, in any way (this includes using values other than + * LINKTYPE_ values, as defined in "savefile.c", in the "linktype" + * field). + * + * Instead: + * + * introduce a new structure for the new format, if the layout + * of the structure changed; + * + * send mail to "tcpdump-workers@lists.tcpdump.org", requesting + * a new magic number for your new capture file format, and, when + * you get the new magic number, put it in "savefile.c"; + * + * use that magic number for save files with the changed file + * header; + * + * make the code in "savefile.c" capable of reading files with + * the old file header as well as files with the new file header + * (using the magic number to determine the header format). + * + * Then supply the changes as a patch at + * + * http://sourceforge.net/projects/libpcap/ + * + * so that future versions of libpcap and programs that use it (such as + * tcpdump) will be able to read your new capture file format. + */ +struct pcap_file_header { + bpf_u_int32 magic; + u_short version_major; + u_short version_minor; + bpf_int32 thiszone; /* gmt to local correction */ + bpf_u_int32 sigfigs; /* accuracy of timestamps */ + bpf_u_int32 snaplen; /* max length saved portion of each pkt */ + bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ +}; + +/* + * Macros for the value returned by pcap_datalink_ext(). + * + * If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro + * gives the FCS length of packets in the capture. + */ +#define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000) +#define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28) +#define LT_FCS_DATALINK_EXT(x) ((((x) & 0xF) << 28) | 0x04000000) + +typedef enum { + PCAP_D_INOUT = 0, + PCAP_D_IN, + PCAP_D_OUT +} pcap_direction_t; + +/* + * Generic per-packet information, as supplied by libpcap. + * + * The time stamp can and should be a "struct timeval", regardless of + * whether your system supports 32-bit tv_sec in "struct timeval", + * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit + * and 64-bit applications. The on-disk format of savefiles uses 32-bit + * tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit + * and 64-bit versions of libpcap, even if they're on the same platform, + * should supply the appropriate version of "struct timeval", even if + * that's not what the underlying packet capture mechanism supplies. + */ +struct pcap_pkthdr { + struct timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ +}; + +/* + * As returned by the pcap_stats() + */ +struct pcap_stat { + u_int ps_recv; /* number of packets received */ + u_int ps_drop; /* number of packets dropped */ + u_int ps_ifdrop; /* drops by interface XXX not yet supported */ +#ifdef HAVE_REMOTE + u_int ps_capt; /* number of packets that are received by the application; please get rid off the Win32 ifdef */ + u_int ps_sent; /* number of packets sent by the server on the network */ + u_int ps_netdrop; /* number of packets lost on the network */ +#endif /* HAVE_REMOTE */ +}; + +#ifdef MSDOS +/* + * As returned by the pcap_stats_ex() + */ +struct pcap_stat_ex { + u_long rx_packets; /* total packets received */ + u_long tx_packets; /* total packets transmitted */ + u_long rx_bytes; /* total bytes received */ + u_long tx_bytes; /* total bytes transmitted */ + u_long rx_errors; /* bad packets received */ + u_long tx_errors; /* packet transmit problems */ + u_long rx_dropped; /* no space in Rx buffers */ + u_long tx_dropped; /* no space available for Tx */ + u_long multicast; /* multicast packets received */ + u_long collisions; + + /* detailed rx_errors: */ + u_long rx_length_errors; + u_long rx_over_errors; /* receiver ring buff overflow */ + u_long rx_crc_errors; /* recv'd pkt with crc error */ + u_long rx_frame_errors; /* recv'd frame alignment error */ + u_long rx_fifo_errors; /* recv'r fifo overrun */ + u_long rx_missed_errors; /* recv'r missed packet */ + + /* detailed tx_errors */ + u_long tx_aborted_errors; + u_long tx_carrier_errors; + u_long tx_fifo_errors; + u_long tx_heartbeat_errors; + u_long tx_window_errors; + }; +#endif + +/* + * Item in a list of interfaces. + */ +struct pcap_if { + struct pcap_if *next; + char *name; /* name to hand to "pcap_open_live()" */ + char *description; /* textual description of interface, or NULL */ + struct pcap_addr *addresses; + bpf_u_int32 flags; /* PCAP_IF_ interface flags */ +}; + +#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ + +/* + * Representation of an interface address. + */ +struct pcap_addr { + struct pcap_addr *next; + struct sockaddr *addr; /* address */ + struct sockaddr *netmask; /* netmask for that address */ + struct sockaddr *broadaddr; /* broadcast address for that address */ + struct sockaddr *dstaddr; /* P2P destination address for that address */ +}; + +typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, + const u_char *); + +/* + * Error codes for the pcap API. + * These will all be negative, so you can check for the success or + * failure of a call that returns these codes by checking for a + * negative value. + */ +#define PCAP_ERROR -1 /* generic error code */ +#define PCAP_ERROR_BREAK -2 /* loop terminated by pcap_breakloop */ +#define PCAP_ERROR_NOT_ACTIVATED -3 /* the capture needs to be activated */ +#define PCAP_ERROR_ACTIVATED -4 /* the operation can't be performed on already activated captures */ +#define PCAP_ERROR_NO_SUCH_DEVICE -5 /* no such device exists */ +#define PCAP_ERROR_RFMON_NOTSUP -6 /* this device doesn't support rfmon (monitor) mode */ +#define PCAP_ERROR_NOT_RFMON -7 /* operation supported only in monitor mode */ +#define PCAP_ERROR_PERM_DENIED -8 /* no permission to open the device */ +#define PCAP_ERROR_IFACE_NOT_UP -9 /* interface isn't up */ + +/* + * Warning codes for the pcap API. + * These will all be positive and non-zero, so they won't look like + * errors. + */ +#define PCAP_WARNING 1 /* generic warning code */ +#define PCAP_WARNING_PROMISC_NOTSUP 2 /* this device doesn't support promiscuous mode */ + +char *pcap_lookupdev(char *); +int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); + +pcap_t *pcap_create(const char *, char *); +int pcap_set_snaplen(pcap_t *, int); +int pcap_set_promisc(pcap_t *, int); +int pcap_can_set_rfmon(pcap_t *); +int pcap_set_rfmon(pcap_t *, int); +int pcap_set_timeout(pcap_t *, int); +int pcap_set_buffer_size(pcap_t *, int); +int pcap_activate(pcap_t *); + +pcap_t *pcap_open_live(const char *, int, int, int, char *); +pcap_t *pcap_open_dead(int, int); +pcap_t *pcap_open_offline(const char *, char *); +#if defined(WIN32) +pcap_t *pcap_hopen_offline(intptr_t, char *); +#if !defined(LIBPCAP_EXPORTS) +#define pcap_fopen_offline(f,b) \ + pcap_hopen_offline(_get_osfhandle(_fileno(f)), b) +#else /*LIBPCAP_EXPORTS*/ +static pcap_t *pcap_fopen_offline(FILE *, char *); +#endif +#else /*WIN32*/ +pcap_t *pcap_fopen_offline(FILE *, char *); +#endif /*WIN32*/ + +void pcap_close(pcap_t *); +int pcap_loop(pcap_t *, int, pcap_handler, u_char *); +int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); +const u_char* + pcap_next(pcap_t *, struct pcap_pkthdr *); +int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); +void pcap_breakloop(pcap_t *); +int pcap_stats(pcap_t *, struct pcap_stat *); +int pcap_setfilter(pcap_t *, struct bpf_program *); +int pcap_setdirection(pcap_t *, pcap_direction_t); +int pcap_getnonblock(pcap_t *, char *); +int pcap_setnonblock(pcap_t *, int, char *); +int pcap_inject(pcap_t *, const void *, size_t); +int pcap_sendpacket(pcap_t *, const u_char *, int); +const char *pcap_statustostr(int); +const char *pcap_strerror(int); +char *pcap_geterr(pcap_t *); +void pcap_perror(pcap_t *, char *); +int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, + bpf_u_int32); +int pcap_compile_nopcap(int, int, struct bpf_program *, + const char *, int, bpf_u_int32); +void pcap_freecode(struct bpf_program *); +int pcap_offline_filter(struct bpf_program *, const struct pcap_pkthdr *, + const u_char *); +int pcap_datalink(pcap_t *); +int pcap_datalink_ext(pcap_t *); +int pcap_list_datalinks(pcap_t *, int **); +int pcap_set_datalink(pcap_t *, int); +void pcap_free_datalinks(int *); +int pcap_datalink_name_to_val(const char *); +const char *pcap_datalink_val_to_name(int); +const char *pcap_datalink_val_to_description(int); +int pcap_snapshot(pcap_t *); +int pcap_is_swapped(pcap_t *); +int pcap_major_version(pcap_t *); +int pcap_minor_version(pcap_t *); + +/* XXX */ +FILE *pcap_file(pcap_t *); +int pcap_fileno(pcap_t *); + +pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); +pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); +FILE *pcap_dump_file(pcap_dumper_t *); +long pcap_dump_ftell(pcap_dumper_t *); +int pcap_dump_flush(pcap_dumper_t *); +void pcap_dump_close(pcap_dumper_t *); +void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); + +int pcap_findalldevs(pcap_if_t **, char *); +void pcap_freealldevs(pcap_if_t *); + +const char *pcap_lib_version(void); + +/* XXX this guy lives in the bpf tree */ +u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +int bpf_validate(const struct bpf_insn *f, int len); +char *bpf_image(const struct bpf_insn *, int); +void bpf_dump(const struct bpf_program *, int); + +#if defined(WIN32) + +/* + * Win32 definitions + */ + +int pcap_setbuff(pcap_t *p, int dim); +int pcap_setmode(pcap_t *p, int mode); +int pcap_setmintocopy(pcap_t *p, int size); + +#ifdef WPCAP +/* Include file with the wpcap-specific extensions */ +#include +#endif /* WPCAP */ + +#define MODE_CAPT 0 +#define MODE_STAT 1 +#define MODE_MON 2 + +#elif defined(MSDOS) + +/* + * MS-DOS definitions + */ + +int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *); +void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait); +u_long pcap_mac_packets (void); + +#else /* UN*X */ + +/* + * UN*X definitions + */ + +int pcap_get_selectable_fd(pcap_t *); + +#endif /* WIN32/MSDOS/UN*X */ + +#ifdef HAVE_REMOTE +/* Includes most of the public stuff that is needed for the remote capture */ +#include +#endif /* HAVE_REMOTE */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/sll.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/sll.h new file mode 100644 index 000000000..5907beded --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/sll.h @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/sll.h,v 1.2.2.1 2008-05-30 01:36:06 guy Exp $ (LBL) + */ + +/* + * For captures on Linux cooked sockets, we construct a fake header + * that includes: + * + * a 2-byte "packet type" which is one of: + * + * LINUX_SLL_HOST packet was sent to us + * LINUX_SLL_BROADCAST packet was broadcast + * LINUX_SLL_MULTICAST packet was multicast + * LINUX_SLL_OTHERHOST packet was sent to somebody else + * LINUX_SLL_OUTGOING packet was sent *by* us; + * + * a 2-byte Ethernet protocol field; + * + * a 2-byte link-layer type; + * + * a 2-byte link-layer address length; + * + * an 8-byte source link-layer address, whose actual length is + * specified by the previous value. + * + * All fields except for the link-layer address are in network byte order. + * + * DO NOT change the layout of this structure, or change any of the + * LINUX_SLL_ values below. If you must change the link-layer header + * for a "cooked" Linux capture, introduce a new DLT_ type (ask + * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it + * a value that collides with a value already being used), and use the + * new header in captures of that type, so that programs that can + * handle DLT_LINUX_SLL captures will continue to handle them correctly + * without any change, and so that capture files with different headers + * can be told apart and programs that read them can dissect the + * packets in them. + */ + +#ifndef lib_pcap_sll_h +#define lib_pcap_sll_h + +/* + * A DLT_LINUX_SLL fake link-layer header. + */ +#define SLL_HDR_LEN 16 /* total header length */ +#define SLL_ADDRLEN 8 /* length of address field */ + +struct sll_header { + u_int16_t sll_pkttype; /* packet type */ + u_int16_t sll_hatype; /* link-layer address type */ + u_int16_t sll_halen; /* link-layer address length */ + u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ + u_int16_t sll_protocol; /* protocol */ +}; + +/* + * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the + * PACKET_ values on Linux, but are defined here so that they're + * available even on systems other than Linux, and so that they + * don't change even if the PACKET_ values change. + */ +#define LINUX_SLL_HOST 0 +#define LINUX_SLL_BROADCAST 1 +#define LINUX_SLL_MULTICAST 2 +#define LINUX_SLL_OTHERHOST 3 +#define LINUX_SLL_OUTGOING 4 + +/* + * The LINUX_SLL_ values for "sll_protocol"; these correspond to the + * ETH_P_ values on Linux, but are defined here so that they're + * available even on systems other than Linux. We assume, for now, + * that the ETH_P_ values won't change in Linux; if they do, then: + * + * if we don't translate them in "pcap-linux.c", capture files + * won't necessarily be readable if captured on a system that + * defines ETH_P_ values that don't match these values; + * + * if we do translate them in "pcap-linux.c", that makes life + * unpleasant for the BPF code generator, as the values you test + * for in the kernel aren't the values that you test for when + * reading a capture file, so the fixup code run on BPF programs + * handed to the kernel ends up having to do more work. + * + * Add other values here as necessary, for handling packet types that + * might show up on non-Ethernet, non-802.x networks. (Not all the ones + * in the Linux "if_ether.h" will, I suspect, actually show up in + * captures.) + */ +#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ +#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/usb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/usb.h new file mode 100644 index 000000000..f150d3be0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/usb.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * Basic USB data struct + * By Paolo Abeni + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/usb.h,v 1.6 2007/09/22 02:06:08 guy Exp $ + */ + +#ifndef _PCAP_USB_STRUCTS_H__ +#define _PCAP_USB_STRUCTS_H__ + +/* + * possible transfer mode + */ +#define URB_TRANSFER_IN 0x80 +#define URB_ISOCHRONOUS 0x0 +#define URB_INTERRUPT 0x1 +#define URB_CONTROL 0x2 +#define URB_BULK 0x3 + +/* + * possible event type + */ +#define URB_SUBMIT 'S' +#define URB_COMPLETE 'C' +#define URB_ERROR 'E' + +/* + * USB setup header as defined in USB specification. + * Appears at the front of each packet in DLT_USB captures. + */ +typedef struct _usb_setup { + u_int8_t bmRequestType; + u_int8_t bRequest; + u_int16_t wValue; + u_int16_t wIndex; + u_int16_t wLength; +} pcap_usb_setup; + + +/* + * Header prepended by linux kernel to each event. + * Appears at the front of each packet in DLT_USB_LINUX captures. + */ +typedef struct _usb_header { + u_int64_t id; + u_int8_t event_type; + u_int8_t transfer_type; + u_int8_t endpoint_number; + u_int8_t device_address; + u_int16_t bus_id; + char setup_flag;/*if !=0 the urb setup header is not present*/ + char data_flag; /*if !=0 no urb data is present*/ + int64_t ts_sec; + int32_t ts_usec; + int32_t status; + u_int32_t urb_len; + u_int32_t data_len; /* amount of urb data really present in this event*/ + pcap_usb_setup setup; +} pcap_usb_header; + + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/vlan.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/vlan.h new file mode 100644 index 000000000..00ed9b616 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/pcap/vlan.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/vlan.h,v 1.1.2.2 2008-08-06 07:45:59 guy Exp $ + */ + +#ifndef lib_pcap_vlan_h +#define lib_pcap_vlan_h + +struct vlan_tag { + u_int16_t vlan_tpid; /* ETH_P_8021Q */ + u_int16_t vlan_tci; /* VLAN TCI */ +}; + +#define VLAN_TAG_LEN 4 + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/remote-ext.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/remote-ext.h new file mode 100644 index 000000000..9f54d6974 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/remote-ext.h @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * 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. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + + +#ifndef __REMOTE_EXT_H__ +#define __REMOTE_EXT_H__ + + +#ifndef HAVE_REMOTE +#error Please do not include this file directly. Just define HAVE_REMOTE and then include pcap.h +#endif + +// Definition for Microsoft Visual Studio +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + \file remote-ext.h + + The goal of this file it to include most of the new definitions that should be + placed into the pcap.h file. + + It includes all new definitions (structures and functions like pcap_open(). + Some of the functions are not really a remote feature, but, right now, + they are placed here. +*/ + + + +// All this stuff is public +/*! \addtogroup remote_struct + \{ +*/ + + + + +/*! + \brief Defines the maximum buffer size in which address, port, interface names are kept. + + In case the adapter name or such is larger than this value, it is truncated. + This is not used by the user; however it must be aware that an hostname / interface + name longer than this value will be truncated. +*/ +#define PCAP_BUF_SIZE 1024 + + +/*! \addtogroup remote_source_ID + \{ +*/ + + +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a file, i.e. the user want to open a capture from a local file. +*/ +#define PCAP_SRC_FILE 2 +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a local interface, i.e. the user want to open a capture from + a local interface. This does not involve the RPCAP protocol. +*/ +#define PCAP_SRC_IFLOCAL 3 +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a remote interface, i.e. the user want to open a capture from + an interface on a remote host. This does involve the RPCAP protocol. +*/ +#define PCAP_SRC_IFREMOTE 4 + +/*! + \} +*/ + + + +/*! \addtogroup remote_source_string + + The formats allowed by the pcap_open() are the following: + - file://path_and_filename [opens a local file] + - rpcap://devicename [opens the selected device devices available on the local host, without using the RPCAP protocol] + - rpcap://host/devicename [opens the selected device available on a remote host] + - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP] + - adaptername [to open a local adapter; kept for compability, but it is strongly discouraged] + - (NULL) [to open the first local adapter; kept for compability, but it is strongly discouraged] + + The formats allowed by the pcap_findalldevs_ex() are the following: + - file://folder/ [lists all the files in the given folder] + - rpcap:// [lists all local adapters] + - rpcap://host:port/ [lists the devices available on a remote host] + + Referring to the 'host' and 'port' paramters, they can be either numeric or literal. Since + IPv6 is fully supported, these are the allowed formats: + + - host (literal): e.g. host.foo.bar + - host (numeric IPv4): e.g. 10.11.12.13 + - host (numeric IPv4, IPv6 style): e.g. [10.11.12.13] + - host (numeric IPv6): e.g. [1:2:3::4] + - port: can be either numeric (e.g. '80') or literal (e.g. 'http') + + Here you find some allowed examples: + - rpcap://host.foo.bar/devicename [everything literal, no port number] + - rpcap://host.foo.bar:1234/devicename [everything literal, with port number] + - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number] + - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number] + - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number] + - rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number] + - rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number] + - rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number] + + \{ +*/ + + +/*! + \brief String that will be used to determine the type of source in use (file, + remote/local interface). + + This string will be prepended to the interface name in order to create a string + that contains all the information required to open the source. + + This string indicates that the user wants to open a capture from a local file. +*/ +#define PCAP_SRC_FILE_STRING "file://" +/*! + \brief String that will be used to determine the type of source in use (file, + remote/local interface). + + This string will be prepended to the interface name in order to create a string + that contains all the information required to open the source. + + This string indicates that the user wants to open a capture from a network interface. + This string does not necessarily involve the use of the RPCAP protocol. If the + interface required resides on the local host, the RPCAP protocol is not involved + and the local functions are used. +*/ +#define PCAP_SRC_IF_STRING "rpcap://" + +/*! + \} +*/ + + + + + +/*! + \addtogroup remote_open_flags + \{ +*/ + +/*! + \brief Defines if the adapter has to go in promiscuous mode. + + It is '1' if you have to open the adapter in promiscuous mode, '0' otherwise. + Note that even if this parameter is false, the interface could well be in promiscuous + mode for some other reason (for example because another capture process with + promiscuous mode enabled is currently using that interface). + On on Linux systems with 2.2 or later kernels (that have the "any" device), this + flag does not work on the "any" device; if an argument of "any" is supplied, + the 'promisc' flag is ignored. +*/ +#define PCAP_OPENFLAG_PROMISCUOUS 1 + +/*! + \brief Defines if the data trasfer (in case of a remote + capture) has to be done with UDP protocol. + + If it is '1' if you want a UDP data connection, '0' if you want + a TCP data connection; control connection is always TCP-based. + A UDP connection is much lighter, but it does not guarantee that all + the captured packets arrive to the client workstation. Moreover, + it could be harmful in case of network congestion. + This flag is meaningless if the source is not a remote interface. + In that case, it is simply ignored. +*/ +#define PCAP_OPENFLAG_DATATX_UDP 2 + + +/*! + \brief Defines if the remote probe will capture its own generated traffic. + + In case the remote probe uses the same interface to capture traffic and to send + data back to the caller, the captured traffic includes the RPCAP traffic as well. + If this flag is turned on, the RPCAP traffic is excluded from the capture, so that + the trace returned back to the collector is does not include this traffic. +*/ +#define PCAP_OPENFLAG_NOCAPTURE_RPCAP 4 + +/*! + \brief Defines if the local adapter will capture its own generated traffic. + + This flag tells the underlying capture driver to drop the packets that were sent by itself. + This is usefult when building applications like bridges, that should ignore the traffic + they just sent. +*/ +#define PCAP_OPENFLAG_NOCAPTURE_LOCAL 8 + +/*! + \brief This flag configures the adapter for maximum responsiveness. + + In presence of a large value for nbytes, WinPcap waits for the arrival of several packets before + copying the data to the user. This guarantees a low number of system calls, i.e. lower processor usage, + i.e. better performance, which is good for applications like sniffers. If the user sets the + PCAP_OPENFLAG_MAX_RESPONSIVENESS flag, the capture driver will copy the packets as soon as the application + is ready to receive them. This is suggested for real time applications (like, for example, a bridge) + that need the best responsiveness.*/ +#define PCAP_OPENFLAG_MAX_RESPONSIVENESS 16 + +/*! + \} +*/ + + +/*! + \addtogroup remote_samp_methods + \{ +*/ + +/*! + \brief No sampling has to be done on the current capture. + + In this case, no sampling algorithms are applied to the current capture. +*/ +#define PCAP_SAMP_NOSAMP 0 + +/*! + \brief It defines that only 1 out of N packets must be returned to the user. + + In this case, the 'value' field of the 'pcap_samp' structure indicates the + number of packets (minus 1) that must be discarded before one packet got accepted. + In other words, if 'value = 10', the first packet is returned to the caller, while + the following 9 are discarded. +*/ +#define PCAP_SAMP_1_EVERY_N 1 + +/*! + \brief It defines that we have to return 1 packet every N milliseconds. + + In this case, the 'value' field of the 'pcap_samp' structure indicates the 'waiting + time' in milliseconds before one packet got accepted. + In other words, if 'value = 10', the first packet is returned to the caller; the next + returned one will be the first packet that arrives when 10ms have elapsed. +*/ +#define PCAP_SAMP_FIRST_AFTER_N_MS 2 + +/*! + \} +*/ + + +/*! + \addtogroup remote_auth_methods + \{ +*/ + +/*! + \brief It defines the NULL authentication. + + This value has to be used within the 'type' member of the pcap_rmtauth structure. + The 'NULL' authentication has to be equal to 'zero', so that old applications + can just put every field of struct pcap_rmtauth to zero, and it does work. +*/ +#define RPCAP_RMTAUTH_NULL 0 +/*! + \brief It defines the username/password authentication. + + With this type of authentication, the RPCAP protocol will use the username/ + password provided to authenticate the user on the remote machine. If the + authentication is successful (and the user has the right to open network devices) + the RPCAP connection will continue; otherwise it will be dropped. + + This value has to be used within the 'type' member of the pcap_rmtauth structure. +*/ +#define RPCAP_RMTAUTH_PWD 1 + +/*! + \} +*/ + + + + +/*! + + \brief This structure keeps the information needed to autheticate + the user on a remote machine. + + The remote machine can either grant or refuse the access according + to the information provided. + In case the NULL authentication is required, both 'username' and + 'password' can be NULL pointers. + + This structure is meaningless if the source is not a remote interface; + in that case, the functions which requires such a structure can accept + a NULL pointer as well. +*/ +struct pcap_rmtauth +{ + /*! + \brief Type of the authentication required. + + In order to provide maximum flexibility, we can support different types + of authentication based on the value of this 'type' variable. The currently + supported authentication methods are defined into the + \link remote_auth_methods Remote Authentication Methods Section\endlink. + + */ + int type; + /*! + \brief Zero-terminated string containing the username that has to be + used on the remote machine for authentication. + + This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + and it can be NULL. + */ + char *username; + /*! + \brief Zero-terminated string containing the password that has to be + used on the remote machine for authentication. + + This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + and it can be NULL. + */ + char *password; +}; + + +/*! + \brief This structure defines the information related to sampling. + + In case the sampling is requested, the capturing device should read + only a subset of the packets coming from the source. The returned packets depend + on the sampling parameters. + + \warning The sampling process is applied after the filtering process. + In other words, packets are filtered first, then the sampling process selects a + subset of the 'filtered' packets and it returns them to the caller. +*/ +struct pcap_samp +{ + /*! + Method used for sampling. Currently, the supported methods are listed in the + \link remote_samp_methods Sampling Methods Section\endlink. + */ + int method; + + /*! + This value depends on the sampling method defined. For its meaning, please check + at the \link remote_samp_methods Sampling Methods Section\endlink. + */ + int value; +}; + + + + +//! Maximum lenght of an host name (needed for the RPCAP active mode) +#define RPCAP_HOSTLIST_SIZE 1024 + + +/*! + \} +*/ // end of public documentation + + +// Exported functions + + + +/** \name New WinPcap functions + + This section lists the new functions that are able to help considerably in writing + WinPcap programs because of their easiness of use. + */ +//\{ +pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf); +int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf); +int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf); +int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf); +struct pcap_samp *pcap_setsampling(pcap_t *p); + +//\} +// End of new winpcap functions + + + +/** \name Remote Capture functions + */ +//\{ +SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf); +int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf); +int pcap_remoteact_close(const char *host, char *errbuf); +void pcap_remoteact_cleanup(); +//\} +// End of remote capture functions + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/wpcap.lib b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/WinPCap/wpcap.lib new file mode 100644 index 0000000000000000000000000000000000000000..f832e0445b5c7dafe5a0f887262064265ba2b293 GIT binary patch literal 19320 zcmdU0O>9(05-uRW4k3h)gbS|j4}Uz#t>t&Y%Y)S%rl;4JTp5pCTuoh zr6{Lp73IKQa^QrbD7U>tdx#=VoK`4`_7Fwch+_^p| zS6BDfKh<5`)$NUA`Fde~ylZ#2`x_V>8Oe?2azi67zdwrRhWbZ!@NyRb{1af)Ai(As zfGr;YjQ*f$?=%3>0gMxkW0+_MhKYuM)O4~3fN1X*n)>bm5FNa!=@dc`jeVwR->(2f zr@qm2dK`f0IF?CtuvgRRPmzx_yk67JDF8*E;}+y2(SaM92H(eeAPs$`X>=9#JJEGb+ptfFdaw>e+iq*x`Yiy_8LSsk zPhHb?lqKrHekD4vPE+rP*gr_)Sa+hqpEMo(8T%RO(3GZ$?*SB*@r$$_@rd?+t!Zo@ zjvvxV99NR-y@~cP&F-(99u}FD=x9fbs_AYW3=3tr%W|L_8r?37d|TiVLY~ zEvy9P(zP&>67jfHb#AU)syKqo60(JIwPA#!ut>cUHY?T2Y`I#v8X-CyA=yYsIvgR1 z{ec~7x`z7J_EoXesO6i5`6%5+g-kun7o&6?6lsXL*a+*hi*s{fJrauXgmly&fhf^s z3E4_`-3*NminK;E-)tB(9ge34;dLpXqEaSo&XvkdS!WX$Qnj#NubO6=h)8cV>r%o- zg$#}#%0zWB5s_Y~F4Rh8)(8_zN(7avo*HT-qioC+@^ketEL4l8NE;P0#e6f5+G>={ zMukkHlCL%9t7a5zRLGPXLF4Uwtri*$kqjZXkpEM)9$X9SjZ(D|bw-RQrAw8hw96CH zIB?un6^x}-su3UwQbeQ|7jfC3NgauZcw9Wn7pTvr=@psX2-v zPKxSZ5_y=PnoE_N$P;l>b2RJuN@JnKx{58)m9q&VA1x?B*qjgRVZ~&L@q{!@+G|$O zMuiOZZ>iF(7OFMdSjiHy%7zr}qAKD-YOYi%Vt=CNK_NilssaMOp#PS~G0a z3#jr@2fHjGTg%rQuBgKil48`YO^Y*yd_7#KHp6_O8RQFvux8Xd$xh8vE;W)lG&5CR zE{YZ+xiZSMFke|T8koY@IHd|2`Ept5435N=dVT?dRHmqxp2NoQb4*B>?S@fVJ*ax; z#(FH|ab7p_3pF&AS9m=V93eT2qkmOwwM1MS~zh^OYj+6w(qzK0R@x9xxG+j`OQ@O)YAwXd4wWGVhD0>`FwwU%QhSy`Bsht3yBaP(% ze(43MpxoU(=zYOFA0d4{0I&g1$&>iKwHu(>kDdVhcHwsomUZU@z?X;clzbTAW2BWw z0NzC^?gw}e%b&*d8(7cxv5c>V09Ik$uOp3b!!mjRZsYgctytC>fI7y0LnY-36{Zf7=>XNfjzJf#$Z1jgA3T1 zPr!??4yIuo*25%B!C6=dn_&}df!E4q}7h2Vp-SXex#;FLwXebxMB`=5C9I^9PV8s(AynihM(q47Hlj}F34Yx5 z5?lA>X`GVyBqM>5uRR)q`2Y)!$;$8I=7z=ffJr=%AQ6tTb`!4lnRETAExQINoiFRt&`kb6)zb#5OTk(WXF`3LzuyeV>Hxo-xE;5&wx*TA8>_O0# zmkw~5!tPVa^mwZsG2>X)OyT6P_FY#r`5rUt)woR?W2mOSw@rK-bJ`>O{@4yI%WYCPuf1kaI9X$ zNp*3w@H`qDr?aNs+&Oo2#&Hz0Why()^2D`)wqGhaX1N5xvM@q!8M4BUSkpzx4EynIBam!|lli=G+Mk}qYj1rahg&EpnNTMnkZ z6X;YS&b;BMmJ!Md!^x2hGOWz7`V;-AEPO=~#ptsfeItO|rMA!b4@pA?b9;q` zELR%xFI6w99i(bVQ6qBcEkNU%@)Gd`Z&9+L3Wy4UP

ii zt(#u7(X5F2?uWKuz$0Zt8OJO)7!6qr;{`-mW-ub#&;iOoI?D5ivfQBP z?YRYMzrS+nDC-bqg+bw+zXjsZL+Gm53p&N2Dhi z$sPL*kF_J!=aoO!_oo5a`Wl^G6SWCz8X~fDnjyWbFWEo#2>_LrfpY(yof(M2GuM&^&tn45RTGq64I1es%5IBD_q*{iK;u2FYa$7I6mN$G=TOG^=4LlDoZVf8Mpw z8`>v5@1R6iH=VS|vlhSLVkx(ih2l^~-N<=b^b_Mk`m)-zIUnA+Dq&#M2jgMyAnZo(4AD0*qp9b5G`pq6hCIM%0W!8nw$ z=X{p)l{75!sW3?UZSYVll0YzKHbPhY;~;29sU1>;c0zRY>-XSai;ZdbYZCG=to zq}NeHHZoF*W4Z&(oJadNNlfy2cY@QRZM55d-N8}r^iGgGy0KXzv2)UbaVVp147WIa zljmv+W4U(#jA6SoBbv{mY-KcYyI`T(Ull#QxQ(&o#f1gqP{wxoR*xQmS-4#qq68LyTjtHxo|KwtJB;6=J(Y@(tt?ceEx_3CTXEKlvOJ{NFy#1JrL^z$>YNrb&<@)H8*An#mck^5f7vwn&$@= zl0z9sY}m8Q7*9o{hYgHkLs{`!j2wCD52oO$CleN~{Wa0!-I!oJ@fxE8EMH$9a z4-3eltbOUxmcuD{<_QVov_E zH5QOV8As7)wU0Y^#`|rDZ3!!<#~Pe)(9AO+ZjXh{+AKB$jT}9S zHBXm1z-lq?X#aRxVyQ<_9pHHO31=jZeQssJ+SYsD$#znrB{r%InpH16?K&%w>>DwL zSc1lTMr+DJqo>Fgh(lRh<ClhvL%JxCqKEC=kR{Bh7JE3l N*?W_a?2Af)@;}RMSJ?mn literal 0 HcmV?d00001 diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/atomic.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/atomic.h new file mode 100644 index 000000000..565c28037 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/atomic.h @@ -0,0 +1,547 @@ +/* + * FreeRTOS Kernel V10.2.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/** + * @file atomic.h + * @brief FreeRTOS atomic operation support. + * + * Two implementations of atomic are given in this header file: + * 1. Disabling interrupt globally. + * 2. ISA native atomic support. + * The former is available to all ports (compiler-architecture combination), + * while the latter is only available to ports compiling with GCC (version at + * least 4.7.0), which also have ISA atomic support. + * + * User can select which implementation to use by: + * setting/clearing configUSE_ATOMIC_INSTRUCTION in FreeRTOSConfig.h. + * Define AND set configUSE_ATOMIC_INSTRUCTION to 1 for ISA native atomic support. + * Undefine OR clear configUSE_ATOMIC_INSTRUCTION for disabling global interrupt + * implementation. + * + * @see GCC Built-in Functions for Memory Model Aware Atomic Operations + * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html + */ + +#ifndef ATOMIC_H +#define ATOMIC_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include atomic.h" +#endif + +/* Standard includes. */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + /* Needed for __atomic_compare_exchange() weak=false. */ + #include + + /* This branch is for GCC compiler and GCC compiler only. */ + #ifndef portFORCE_INLINE + #define portFORCE_INLINE inline __attribute__((always_inline)) + #endif + +#else + + /* Port specific definitions -- entering/exiting critical section. + * Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h + * + * Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with + * ATOMIC_ENTER_CRITICAL(). + */ + #if defined( portSET_INTERRUPT_MASK_FROM_ISR ) + + /* Nested interrupt scheme is supported in this port. */ + #define ATOMIC_ENTER_CRITICAL() \ + UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR() + + #define ATOMIC_EXIT_CRITICAL() \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType ) + + #else + + /* Nested interrupt scheme is NOT supported in this port. */ + #define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL() + #define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL() + + #endif /* portSET_INTERRUPT_MASK_FROM_ISR() */ + + /* Port specific definition -- "always inline". + * Inline is compiler specific, and may not always get inlined depending on your optimization level. + * For atomic operations, inline is considered a performance optimization. + * Thus, if portFORCE_INLINE is not provided by portmacro.h, instead of resulting error, + * simply define it. + */ + #ifndef portFORCE_INLINE + #define portFORCE_INLINE + #endif + +#endif /* configUSE_GCC_BUILTIN_ATOMICS */ + +#define ATOMIC_COMPARE_AND_SWAP_SUCCESS 0x1U /**< Compare and swap succeeded, swapped. */ +#define ATOMIC_COMPARE_AND_SWAP_FAILURE 0x0U /**< Compare and swap failed, did not swap. */ + +/*----------------------------- Swap && CAS ------------------------------*/ + +/** + * Atomic compare-and-swap + * + * @brief Performs an atomic compare-and-swap operation on the specified values. + * + * @param[in, out] pDestination Pointer to memory location from where value is + * to be loaded and checked. + * @param[in] ulExchange If condition meets, write this value to memory. + * @param[in] ulComparand Swap condition. + * + * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. + * + * @note This function only swaps *pDestination with ulExchange, if previous + * *pDestination value equals ulComparand. + */ +static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32( + uint32_t volatile * pDestination, + uint32_t ulExchange, + uint32_t ulComparand ) +{ + + uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + if ( __atomic_compare_exchange( pDestination, + &ulComparand, + &ulExchange, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST ) ) + { + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + +#else + + ATOMIC_ENTER_CRITICAL(); + + if ( *pDestination == ulComparand ) + { + *pDestination = ulExchange; + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return ulReturnValue; + +} + +/** + * Atomic swap (pointers) + * + * @brief Atomically sets the address pointed to by *ppDestination to the value + * of *pExchange. + * + * @param[in, out] ppDestination Pointer to memory location from where a pointer + * value is to be loaded and written back to. + * @param[in] pExchange Pointer value to be written to *ppDestination. + * + * @return The initial value of *ppDestination. + */ +static portFORCE_INLINE void * Atomic_SwapPointers_p32( + void * volatile * ppDestination, + void * pExchange ) +{ + void * pReturnValue; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + __atomic_exchange( ppDestination, &pExchange, &pReturnValue, __ATOMIC_SEQ_CST ); + +#else + + ATOMIC_ENTER_CRITICAL(); + + pReturnValue = *ppDestination; + + *ppDestination = pExchange; + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return pReturnValue; +} + +/** + * Atomic compare-and-swap (pointers) + * + * @brief Performs an atomic compare-and-swap operation on the specified pointer + * values. + * + * @param[in, out] ppDestination Pointer to memory location from where a pointer + * value is to be loaded and checked. + * @param[in] pExchange If condition meets, write this value to memory. + * @param[in] pComparand Swap condition. + * + * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. + * + * @note This function only swaps *ppDestination with pExchange, if previous + * *ppDestination value equals pComparand. + */ +static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32( + void * volatile * ppDestination, + void * pExchange, void * pComparand ) +{ + uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + if ( __atomic_compare_exchange( ppDestination, + &pComparand, + &pExchange, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST ) ) + { + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + +#else + + ATOMIC_ENTER_CRITICAL(); + + if ( *ppDestination == pComparand ) + { + *ppDestination = pExchange; + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return ulReturnValue; +} + + +/*----------------------------- Arithmetic ------------------------------*/ + +/** + * Atomic add + * + * @brief Atomically adds count to the value of the specified pointer points to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * @param[in] ulCount Value to be added to *pAddend. + * + * @return previous *pAddend value. + */ +static portFORCE_INLINE uint32_t Atomic_Add_u32( + uint32_t volatile * pAddend, + uint32_t ulCount ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_add(pAddend, ulCount, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend += ulCount; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic subtract + * + * @brief Atomically subtracts count from the value of the specified pointer + * pointers to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * @param[in] ulCount Value to be subtract from *pAddend. + * + * @return previous *pAddend value. + */ +static portFORCE_INLINE uint32_t Atomic_Subtract_u32( + uint32_t volatile * pAddend, + uint32_t ulCount ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_sub(pAddend, ulCount, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend -= ulCount; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic increment + * + * @brief Atomically increments the value of the specified pointer points to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * + * @return *pAddend value before increment. + */ +static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pAddend ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_add(pAddend, 1, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend += 1; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic decrement + * + * @brief Atomically decrements the value of the specified pointer points to + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * + * @return *pAddend value before decrement. + */ +static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pAddend ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_sub(pAddend, 1, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend -= 1; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/*----------------------------- Bitwise Logical ------------------------------*/ + +/** + * Atomic OR + * + * @brief Performs an atomic OR operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be ORed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_OR_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_or(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination |= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic AND + * + * @brief Performs an atomic AND operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be ANDed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_AND_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_and(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination &= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic NAND + * + * @brief Performs an atomic NAND operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be NANDed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_NAND_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_nand(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination = ~(ulCurrent & ulValue); + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic XOR + * + * @brief Performs an atomic XOR operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be XORed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_XOR_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_xor(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination ^= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif /* ATOMIC_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/demo_logging.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/demo_logging.c new file mode 100644 index 000000000..2dc08cf05 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/demo_logging.c @@ -0,0 +1,527 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * Logging utility that allows FreeRTOS tasks to log to a UDP port, stdout, and + * disk file without making any Win32 system calls themselves. + * + * Messages logged to a UDP port are sent directly (using FreeRTOS+TCP), but as + * FreeRTOS tasks cannot make Win32 system calls messages sent to stdout or a + * disk file are sent via a stream buffer to a Win32 thread which then performs + * the actual output. + */ + +/* Standard includes. */ +#include +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_Stream_Buffer.h" + +/* Demo includes. */ +#include "demo_logging.h" + +/*-----------------------------------------------------------*/ + +/* The maximum size to which the log file may grow, before being renamed +to .ful. */ +#define dlLOGGING_FILE_SIZE ( 40ul * 1024ul * 1024ul ) + +/* Dimensions the arrays into which print messages are created. */ +#define dlMAX_PRINT_STRING_LENGTH 511 + +/* The size of the stream buffer used to pass messages from FreeRTOS tasks to +the Win32 thread that is responsible for making any Win32 system calls that are +necessary for the selected logging method. */ +#define dlLOGGING_STREAM_BUFFER_SIZE 32768 + +/* A block time of zero simply means don't block. */ +#define dlDONT_BLOCK 0 + +/*-----------------------------------------------------------*/ + +/* + * Called from vLoggingInit() to start a new disk log file. + */ +static void prvFileLoggingInit( void ); + +/* + * Attempt to write a message to the file. + */ +static void prvLogToFile( const char *pcMessage, size_t xLength ); + +/* + * Simply close the logging file, if it is open. + */ +static void prvFileClose( void ); + +/* + * Before the scheduler is started this function is called directly. After the + * scheduler has started it is called from the Windows thread dedicated to + * outputting log messages. Only the windows thread actually performs the + * writing so as not to disrupt the simulation by making Windows system calls + * from FreeRTOS tasks. + */ +static void prvLoggingFlushBuffer( void ); + +/* + * The windows thread that performs the actual writing of messages that require + * Win32 system calls. Only the windows thread can make system calls so as not + * to disrupt the simulation by making Windows calls from FreeRTOS tasks. + */ +static DWORD WINAPI prvWin32LoggingThread( void *pvParam ); + +/* + * Creates the socket to which UDP messages are sent. This function is not + * called directly to prevent the print socket being created from within the IP + * task - which could result in a deadlock. Instead the function call is + * deferred to run in the RTOS daemon task - hence it prototype. + */ +static void prvCreatePrintSocket( void *pvParameter1, uint32_t ulParameter2 ); + +/*-----------------------------------------------------------*/ + +/* Windows event used to wake the Win32 thread which performs any logging that +needs Win32 system calls. */ +static void *pvLoggingThreadEvent = NULL; + +/* Stores the selected logging targets passed in as parameters to the +vLoggingInit() function. */ +BaseType_t xStdoutLoggingUsed = pdFALSE, xDiskFileLoggingUsed = pdFALSE, xUDPLoggingUsed = pdFALSE; + +/* Circular buffer used to pass messages from the FreeRTOS tasks to the Win32 +thread that is responsible for making Win32 calls (when stdout or a disk log is +used). */ +static StreamBuffer_t *xLogStreamBuffer = NULL; + +/* Handle to the file used for logging. This is left open while there are +messages waiting to be logged, then closed again in between logs. */ +static FILE *pxLoggingFileHandle = NULL; + +/* When true prints are performed directly. After start up xDirectPrint is set +to pdFALSE - at which time prints that require Win32 system calls are done by +the Win32 thread responsible for logging. */ +BaseType_t xDirectPrint = pdTRUE; + +/* File names for the in use and complete (full) log files. */ +static const char *pcLogFileName = "RTOSDemo.log"; +static const char *pcFullLogFileName = "RTOSDemo.ful"; + +/* As an optimization, the current file size is kept in a variable. */ +static size_t ulSizeOfLoggingFile = 0ul; + +/* The UDP socket and address on/to which print messages are sent. */ +Socket_t xPrintSocket = FREERTOS_INVALID_SOCKET; +struct freertos_sockaddr xPrintUDPAddress; + +/*-----------------------------------------------------------*/ + +void vLoggingInit( BaseType_t xLogToStdout, BaseType_t xLogToFile, BaseType_t xLogToUDP, uint32_t ulRemoteIPAddress, uint16_t usRemotePort ) +{ + /* Can only be called before the scheduler has started. */ + configASSERT( xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED ); + + #if( ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) ) + { + HANDLE Win32Thread; + + /* Record which output methods are to be used. */ + xStdoutLoggingUsed = xLogToStdout; + xDiskFileLoggingUsed = xLogToFile; + xUDPLoggingUsed = xLogToUDP; + + /* If a disk file is used then initialize it now. */ + if( xDiskFileLoggingUsed != pdFALSE ) + { + prvFileLoggingInit(); + } + + /* If UDP logging is used then store the address to which the log data + will be sent - but don't create the socket yet because the network is + not initialized. */ + if( xUDPLoggingUsed != pdFALSE ) + { + /* Set the address to which the print messages are sent. */ + xPrintUDPAddress.sin_port = FreeRTOS_htons( usRemotePort ); + xPrintUDPAddress.sin_addr = ulRemoteIPAddress; + } + + /* If a disk file or stdout are to be used then Win32 system calls will + have to be made. Such system calls cannot be made from FreeRTOS tasks + so create a stream buffer to pass the messages to a Win32 thread, then + create the thread itself, along with a Win32 event that can be used to + unblock the thread. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) ) + { + /* Create the buffer. */ + xLogStreamBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) + dlLOGGING_STREAM_BUFFER_SIZE + 1 ); + configASSERT( xLogStreamBuffer ); + memset( xLogStreamBuffer, '\0', sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) ); + xLogStreamBuffer->LENGTH = dlLOGGING_STREAM_BUFFER_SIZE + 1; + + /* Create the Windows event. */ + pvLoggingThreadEvent = CreateEvent( NULL, FALSE, TRUE, "StdoutLoggingEvent" ); + + /* Create the thread itself. */ + Win32Thread = CreateThread( + NULL, /* Pointer to thread security attributes. */ + 0, /* Initial thread stack size, in bytes. */ + prvWin32LoggingThread, /* Pointer to thread function. */ + NULL, /* Argument for new thread. */ + 0, /* Creation flags. */ + NULL ); + + /* Use the cores that are not used by the FreeRTOS tasks. */ + SetThreadAffinityMask( Win32Thread, ~0x01u ); + SetThreadPriorityBoost( Win32Thread, TRUE ); + SetThreadPriority( Win32Thread, THREAD_PRIORITY_IDLE ); + } + } + #else + { + /* FreeRTOSIPConfig is set such that no print messages will be output. + Avoid compiler warnings about unused parameters. */ + ( void ) xLogToStdout; + ( void ) xLogToFile; + ( void ) xLogToUDP; + ( void ) usRemotePort; + ( void ) ulRemoteIPAddress; + } + #endif /* ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) */ +} +/*-----------------------------------------------------------*/ + +static void prvCreatePrintSocket( void *pvParameter1, uint32_t ulParameter2 ) +{ +static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 0 ); +Socket_t xSocket; + + /* The function prototype is that of a deferred function, but the parameters + are not actually used. */ + ( void ) pvParameter1; + ( void ) ulParameter2; + + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + + if( xSocket != FREERTOS_INVALID_SOCKET ) + { + /* FreeRTOS+TCP decides which port to bind to. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + FreeRTOS_bind( xSocket, NULL, 0 ); + + /* Now the socket is bound it can be assigned to the print socket. */ + xPrintSocket = xSocket; + } +} +/*-----------------------------------------------------------*/ + +void vLoggingPrintf( const char *pcFormat, ... ) +{ +char cPrintString[ dlMAX_PRINT_STRING_LENGTH ]; +char cOutputString[ dlMAX_PRINT_STRING_LENGTH ]; +char *pcSource, *pcTarget, *pcBegin; +size_t xLength, xLength2, rc; +static BaseType_t xMessageNumber = 0; +va_list args; +uint32_t ulIPAddress; +const char *pcTaskName; +const char *pcNoTask = "None"; +int iOriginalPriority; +HANDLE xCurrentTask; + + + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) || ( xUDPLoggingUsed != pdFALSE ) ) + { + /* There are a variable number of parameters. */ + va_start( args, pcFormat ); + + /* Additional info to place at the start of the log. */ + if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED ) + { + pcTaskName = pcTaskGetName( NULL ); + } + else + { + pcTaskName = pcNoTask; + } + + if( strcmp( pcFormat, "\n" ) != 0 ) + { + xLength = snprintf( cPrintString, dlMAX_PRINT_STRING_LENGTH, "%lu %lu [%s] ", + xMessageNumber++, + ( unsigned long ) xTaskGetTickCount(), + pcTaskName ); + } + else + { + xLength = 0; + memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH ); + } + + xLength2 = vsnprintf( cPrintString + xLength, dlMAX_PRINT_STRING_LENGTH - xLength, pcFormat, args ); + + if( xLength2 < 0 ) + { + /* Clean up. */ + xLength2 = dlMAX_PRINT_STRING_LENGTH - 1 - xLength; + cPrintString[ dlMAX_PRINT_STRING_LENGTH - 1 ] = '\0'; + } + + xLength += xLength2; + va_end( args ); + + /* For ease of viewing, copy the string into another buffer, converting + IP addresses to dot notation on the way. */ + pcSource = cPrintString; + pcTarget = cOutputString; + + while( ( *pcSource ) != '\0' ) + { + *pcTarget = *pcSource; + pcTarget++; + pcSource++; + + /* Look forward for an IP address denoted by 'ip'. */ + if( ( isxdigit( pcSource[ 0 ] ) != pdFALSE ) && ( pcSource[ 1 ] == 'i' ) && ( pcSource[ 2 ] == 'p' ) ) + { + *pcTarget = *pcSource; + pcTarget++; + *pcTarget = '\0'; + pcBegin = pcTarget - 8; + + while( ( pcTarget > pcBegin ) && ( isxdigit( pcTarget[ -1 ] ) != pdFALSE ) ) + { + pcTarget--; + } + + sscanf( pcTarget, "%8X", &ulIPAddress ); + rc = sprintf( pcTarget, "%lu.%lu.%lu.%lu", + ( unsigned long ) ( ulIPAddress >> 24UL ), + ( unsigned long ) ( (ulIPAddress >> 16UL) & 0xffUL ), + ( unsigned long ) ( (ulIPAddress >> 8UL) & 0xffUL ), + ( unsigned long ) ( ulIPAddress & 0xffUL ) ); + pcTarget += rc; + pcSource += 3; /* skip "ip" */ + } + } + + /* How far through the buffer was written? */ + xLength = ( BaseType_t ) ( pcTarget - cOutputString ); + + /* If the message is to be logged to a UDP port then it can be sent directly + because it only uses FreeRTOS function (not Win32 functions). */ + if( xUDPLoggingUsed != pdFALSE ) + { + if( ( xPrintSocket == FREERTOS_INVALID_SOCKET ) && ( FreeRTOS_IsNetworkUp() != pdFALSE ) ) + { + /* Create and bind the socket to which print messages are sent. The + xTimerPendFunctionCall() function is used even though this is + not an interrupt because this function is called from the IP task + and the IP task cannot itself wait for a socket to bind. The + parameters to prvCreatePrintSocket() are not required so set to + NULL or 0. */ + xTimerPendFunctionCall( prvCreatePrintSocket, NULL, 0, dlDONT_BLOCK ); + } + + if( xPrintSocket != FREERTOS_INVALID_SOCKET ) + { + FreeRTOS_sendto( xPrintSocket, cOutputString, xLength, 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) ); + + /* Just because the UDP data logger I'm using is dumb. */ + FreeRTOS_sendto( xPrintSocket, "\r", sizeof( char ), 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) ); + } + } + + /* If logging is also to go to either stdout or a disk file then it cannot + be output here - so instead write the message to the stream buffer and wake + the Win32 thread which will read it from the stream buffer and perform the + actual output. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) ) + { + configASSERT( xLogStreamBuffer ); + + /* How much space is in the buffer? */ + xLength2 = uxStreamBufferGetSpace( xLogStreamBuffer ); + + /* There must be enough space to write both the string and the length of + the string. */ + if( xLength2 >= ( xLength + sizeof( xLength ) ) ) + { + /* First write in the length of the data, then write in the data + itself. Raising the thread priority is used as a critical section + as there are potentially multiple writers. The stream buffer is + only thread safe when there is a single writer (likewise for + reading from the buffer). */ + xCurrentTask = GetCurrentThread(); + iOriginalPriority = GetThreadPriority( xCurrentTask ); + SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ); + uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) &( xLength ), sizeof( xLength ) ); + uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) cOutputString, xLength ); + SetThreadPriority( GetCurrentThread(), iOriginalPriority ); + } + + /* xDirectPrint is initialized to pdTRUE, and while it remains true the + logging output function is called directly. When the system is running + the output function cannot be called directly because it would get + called from both FreeRTOS tasks and Win32 threads - so instead wake the + Win32 thread responsible for the actual output. */ + if( xDirectPrint != pdFALSE ) + { + /* While starting up, the thread which calls prvWin32LoggingThread() + is not running yet and xDirectPrint will be pdTRUE. */ + prvLoggingFlushBuffer(); + } + else if( pvLoggingThreadEvent != NULL ) + { + /* While running, wake up prvWin32LoggingThread() to send the + logging data. */ + SetEvent( pvLoggingThreadEvent ); + } + } + } +} +/*-----------------------------------------------------------*/ + +static void prvLoggingFlushBuffer( void ) +{ +size_t xLength; +char cPrintString[ dlMAX_PRINT_STRING_LENGTH ]; + + /* Is there more than the length value stored in the circular buffer + used to pass data from the FreeRTOS simulator into this Win32 thread? */ + while( uxStreamBufferGetSize( xLogStreamBuffer ) > sizeof( xLength ) ) + { + memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH ); + uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE ); + uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) cPrintString, xLength, pdFALSE ); + + /* Write the message to standard out if requested to do so when + vLoggingInit() was called, or if the network is not yet up. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( FreeRTOS_IsNetworkUp() == pdFALSE ) ) + { + /* Write the message to stdout. */ + printf( "%s", cPrintString ); /*_RB_ Replace with _write(). */ + fflush( stdout ); + } + + /* Write the message to a file if requested to do so when + vLoggingInit() was called. */ + if( xDiskFileLoggingUsed != pdFALSE ) + { + prvLogToFile( cPrintString, xLength ); + } + } + + prvFileClose(); +} +/*-----------------------------------------------------------*/ + +static DWORD WINAPI prvWin32LoggingThread( void *pvParameter ) +{ +const DWORD xMaxWait = 1000; + + ( void ) pvParameter; + + /* From now on, prvLoggingFlushBuffer() will only be called from this + Windows thread */ + xDirectPrint = pdFALSE; + + for( ;; ) + { + /* Wait to be told there are message waiting to be logged. */ + WaitForSingleObject( pvLoggingThreadEvent, xMaxWait ); + + /* Write out all waiting messages. */ + prvLoggingFlushBuffer(); + } +} +/*-----------------------------------------------------------*/ + +static void prvFileLoggingInit( void ) +{ +FILE *pxHandle = fopen( pcLogFileName, "a" ); + + if( pxHandle != NULL ) + { + fseek( pxHandle, SEEK_END, 0ul ); + ulSizeOfLoggingFile = ftell( pxHandle ); + fclose( pxHandle ); + } + else + { + ulSizeOfLoggingFile = 0ul; + } +} +/*-----------------------------------------------------------*/ + +static void prvFileClose( void ) +{ + if( pxLoggingFileHandle != NULL ) + { + fclose( pxLoggingFileHandle ); + pxLoggingFileHandle = NULL; + } +} +/*-----------------------------------------------------------*/ + +static void prvLogToFile( const char *pcMessage, size_t xLength ) +{ + if( pxLoggingFileHandle == NULL ) + { + pxLoggingFileHandle = fopen( pcLogFileName, "a" ); + } + + if( pxLoggingFileHandle != NULL ) + { + fwrite( pcMessage, 1, xLength, pxLoggingFileHandle ); + ulSizeOfLoggingFile += xLength; + + /* If the file has grown to its maximum permissible size then close and + rename it - then start with a new file. */ + if( ulSizeOfLoggingFile > ( size_t ) dlLOGGING_FILE_SIZE ) + { + prvFileClose(); + if( _access( pcFullLogFileName, 00 ) == 0 ) + { + remove( pcFullLogFileName ); + } + rename( pcLogFileName, pcFullLogFileName ); + ulSizeOfLoggingFile = 0; + } + } +} +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/demo_logging.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/demo_logging.h new file mode 100644 index 000000000..197b21684 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/demo_logging.h @@ -0,0 +1,48 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef DEMO_LOGGING_H +#define DEMO_LOGGING_H + +/* + * Initialize a logging system that can be used from FreeRTOS tasks and Win32 + * threads. Do not call printf() directly while the scheduler is running. + * + * Set xLogToStdout, xLogToFile and xLogToUDP to either pdTRUE or pdFALSE to + * lot to stdout, a disk file and a UDP port respectively. + * + * If xLogToUDP is pdTRUE then ulRemoteIPAddress and usRemotePort must be set + * to the IP address and port number to which UDP log messages will be sent. + */ +void vLoggingInit( BaseType_t xLogToStdout, + BaseType_t xLogToFile, + BaseType_t xLogToUDP, + uint32_t ulRemoteIPAddress, + uint16_t usRemotePort ); + +#endif /* DEMO_LOGGING_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/main.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/main.c new file mode 100644 index 000000000..dd485a67b --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/main.c @@ -0,0 +1,356 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + /*** + * See https://www.FreeRTOS.org/https/index.html for configuration and usage instructions. + ***/ + +/* Standard includes. */ +#include +#include + +/* Visual studio intrinsics used so the __debugbreak() function is available +should an assert get hit. */ +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" + +/* TCP/IP stack includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Demo app includes. */ +#include "demo_logging.h" + +/* + * Prototypes for the demos that can be started from this project. Note the + * HTTPS demo is not actually started until the network is already, which is + * indicated by vApplicationIPNetworkEventHook() executing - hence + * prvStartSimpleHTTPSDemo() is called from inside vApplicationIPNetworkEventHook(). + */ +extern void vStartSimpleHTTPSDemo( void ); + +/* + * Just seeds the simple pseudo random number generator. + * + * !!! NOTE !!! + * This is not a secure method of generating random numbers and production + * devices should use a true random number generator (TRNG). + */ +static void prvSRand( UBaseType_t ulSeed ); + +/* + * Miscellaneous initialization including preparing the logging and seeding the + * random number generator. + */ +static void prvMiscInitialisation( void ); + +/* The default IP and MAC address used by the demo. The address configuration +defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is +1 but a DHCP server could not be contacted. See the online documentation for +more information. */ +static const uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 }; +static const uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 }; +static const uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 }; +static const uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 }; + +/* Set the following constant to pdTRUE to log using the method indicated by the +name of the constant, or pdFALSE to not log using the method indicated by the +name of the constant. Options include to standard out (xLogToStdout), to a disk +file (xLogToFile), and to a UDP port (xLogToUDP). If xLogToUDP is set to pdTRUE +then UDP messages are sent to the IP address configured as the echo server +address (see the configECHO_SERVER_ADDR0 definitions in FreeRTOSConfig.h) and +the port number set by configPRINT_PORT in FreeRTOSConfig.h. */ +const BaseType_t xLogToStdout = pdTRUE, xLogToFile = pdFALSE, xLogToUDP = pdFALSE; + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition for information on how to configure +the real network connection to use. */ +const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 }; + +/* Use by the pseudo random number generator. */ +static UBaseType_t ulNextRand; +/*-----------------------------------------------------------*/ + +int main( void ) +{ + /*** + * See https://www.FreeRTOS.org/https/index.html for configuration and usage instructions. + ***/ + + /* Miscellaneous initialization including preparing the logging and seeding + the random number generator. */ + prvMiscInitialisation(); + + /* Initialize the network interface. + + ***NOTE*** Tasks that use the network are created in the network event hook + when the network is connected and ready for use (see the implementation of + vApplicationIPNetworkEventHook() below). The address values passed in here + are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1 + but a DHCP server cannot be contacted. */ + FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); + + /* Start the RTOS scheduler. */ + vTaskStartScheduler(); + + /* If all is well, the scheduler will now be running, and the following + line will never be reached. If the following line does execute, then + there was insufficient FreeRTOS heap memory available for the idle and/or + timer tasks to be created. See the memory management section on the + FreeRTOS web site for more details (this is standard text that is not + really applicable to the Win32 simulator port). */ + for( ;; ) + { + __debugbreak(); + } +} +/*-----------------------------------------------------------*/ + +/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect +events are only received if implemented in the MAC driver. */ +void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) +{ +uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress; +char cBuffer[ 16 ]; +static BaseType_t xTasksAlreadyCreated = pdFALSE; + + /* If the network has just come up...*/ + if( eNetworkEvent == eNetworkUp ) + { + /* Create the tasks that use the IP stack if they have not already been + created. */ + if( xTasksAlreadyCreated == pdFALSE ) + { + /* Demos that use the network are created after the network is + up. */ + configPRINTF( ( "---------STARTING DEMO---------\r\n" ) ); + vStartSimpleHTTPSDemo(); + xTasksAlreadyCreated = pdTRUE; + } + + /* Print out the network configuration, which may have come from a DHCP + server. */ + FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress ); + FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); + FreeRTOS_printf( ( "\r\n\r\nIP Address: %s\r\n", cBuffer ) );/*_RB_ Should use IoT libraries logging. */ + + FreeRTOS_inet_ntoa( ulNetMask, cBuffer ); + FreeRTOS_printf( ( "Subnet Mask: %s\r\n", cBuffer ) ); + + FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer ); + FreeRTOS_printf( ( "Gateway Address: %s\r\n", cBuffer ) ); + + FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer ); + FreeRTOS_printf( ( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ) ); + } +} +/*-----------------------------------------------------------*/ + +void vAssertCalled( const char *pcFile, uint32_t ulLine ) +{ + volatile uint32_t ulBlockVariable = 0UL; + volatile char *pcFileName = ( volatile char * ) pcFile; + volatile uint32_t ulLineNumber = ulLine; + + ( void ) pcFileName; + ( void ) ulLineNumber; + + printf( "vAssertCalled( %s, %u\n", pcFile, ulLine ); + + /* Setting ulBlockVariable to a non-zero value in the debugger will allow + this function to be exited. */ + taskDISABLE_INTERRUPTS(); + { + while( ulBlockVariable == 0UL ) + { + __debugbreak(); + } + } + taskENABLE_INTERRUPTS(); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxRand( void ) +{ +const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL; + + /* + * Utility function to generate a pseudo random number. + * + * !!!NOTE!!! + * This is not a secure method of generating a random number. Production + * devices should use a True Random Number Generator (TRNG). + */ + ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement; + return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL ); +} +/*-----------------------------------------------------------*/ + +static void prvSRand( UBaseType_t ulSeed ) +{ + /* Utility function to seed the pseudo random number generator. */ + ulNextRand = ulSeed; +} +/*-----------------------------------------------------------*/ + +static void prvMiscInitialisation( void ) +{ +time_t xTimeNow; +uint32_t ulLoggingIPAddress; + + ulLoggingIPAddress = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0, configECHO_SERVER_ADDR1, configECHO_SERVER_ADDR2, configECHO_SERVER_ADDR3 ); + vLoggingInit( xLogToStdout, xLogToFile, xLogToUDP, ulLoggingIPAddress, configPRINT_PORT ); + + /* + * Seed random number generator. + * + * !!!NOTE!!! + * This is not a secure method of generating a random number. Production + * devices should use a True Random Number Generator (TRNG). + */ + time( &xTimeNow ); + FreeRTOS_debug_printf( ( "Seed for randomizer: %lu\n", xTimeNow ) ); + prvSRand( ( uint32_t ) xTimeNow ); + FreeRTOS_debug_printf( ( "Random numbers: %08X %08X %08X %08X\n", ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32() ) ); +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) + + const char *pcApplicationHostnameHook( void ) + { + /* Assign the name "FreeRTOS" to this network node. This function will + be called during the DHCP: the machine will be registered with an IP + address plus this name. */ + return mainHOST_NAME; + } + +#endif +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) + + BaseType_t xApplicationDNSQueryHook( const char *pcName ) + { + BaseType_t xReturn; + + /* Determine if a name lookup is for this node. Two names are given + to this node: that returned by pcApplicationHostnameHook() and that set + by mainDEVICE_NICK_NAME. */ + if( _stricmp( pcName, pcApplicationHostnameHook() ) == 0 ) + { + xReturn = pdPASS; + } + else if( _stricmp( pcName, mainDEVICE_NICK_NAME ) == 0 ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif +/*-----------------------------------------------------------*/ + +/* + * Callback that provides the inputs necessary to generate a randomized TCP + * Initial Sequence Number per RFC 6528. THIS IS ONLY A DUMMY IMPLEMENTATION + * THAT RETURNS A PSEUDO RANDOM NUMBER SO IS NOT INTENDED FOR USE IN PRODUCTION + * SYSTEMS. + */ +extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress, + uint16_t usSourcePort, + uint32_t ulDestinationAddress, + uint16_t usDestinationPort ) +{ + ( void ) ulSourceAddress; + ( void ) usSourcePort; + ( void ) ulDestinationAddress; + ( void ) usDestinationPort; + + return uxRand(); +} +/*-----------------------------------------------------------*/ + +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an +implementation of vApplicationGetIdleTaskMemory() to provide the memory that is +used by the Idle task. */ +void vApplicationGetIdleTaskMemory( StaticTask_t** ppxIdleTaskTCBBuffer, StackType_t** ppxIdleTaskStackBuffer, uint32_t* pulIdleTaskStackSize ) +{ + /* If the buffers to be provided to the Idle task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xIdleTaskTCB; + static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} +/*-----------------------------------------------------------*/ + +/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the +application must provide an implementation of vApplicationGetTimerTaskMemory() +to provide the memory that is used by the Timer service task. */ +void vApplicationGetTimerTaskMemory( StaticTask_t** ppxTimerTaskTCBBuffer, StackType_t** ppxTimerTaskStackBuffer, uint32_t* pulTimerTaskStackSize ) +{ + /* If the buffers to be provided to the Timer task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xTimerTaskTCB; + static StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/mbedtls_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/mbedtls_config.h new file mode 100644 index 000000000..0f2861a0d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/mbedtls_config.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/* This file configures mbed TLS for FreeRTOS. */ + +#ifndef MBEDTLS_CONFIG_H_ +#define MBEDTLS_CONFIG_H_ + +/* FreeRTOS include. */ +#include "FreeRTOS.h" + +/* Generate errors if deprecated functions are used. */ +#define MBEDTLS_DEPRECATED_REMOVED + +/* Place AES tables in ROM. */ +#define MBEDTLS_AES_ROM_TABLES + +/* Enable the following cipher modes. */ +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_CIPHER_MODE_CFB +#define MBEDTLS_CIPHER_MODE_CTR + +/* Enable the following cipher padding modes. */ +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define MBEDTLS_CIPHER_PADDING_ZEROS + +/* Cipher suite configuration. */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_NIST_OPTIM +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/* Enable all SSL alert messages. */ +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES + +/* Enable the following SSL features. */ +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_SSL_ALPN +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/* Check certificate key usage. */ +#define MBEDTLS_X509_CHECK_KEY_USAGE +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/* Disable platform entropy functions. */ +#define MBEDTLS_NO_PLATFORM_ENTROPY + +/* Enable the following mbed TLS features. */ +#define MBEDTLS_AES_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECP_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_GCM_C +#define MBEDTLS_MD_C +#define MBEDTLS_OID_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA1_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_TLS_C +#define MBEDTLS_THREADING_ALT +#define MBEDTLS_THREADING_C +#define MBEDTLS_X509_USE_C +#define MBEDTLS_X509_CRT_PARSE_C + +/* Set the memory allocation functions on FreeRTOS. */ +void * mbedtls_platform_calloc( size_t nmemb, + size_t size ); +void mbedtls_platform_free( void * ptr ); +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_CALLOC_MACRO mbedtls_platform_calloc +#define MBEDTLS_PLATFORM_FREE_MACRO mbedtls_platform_free + +/* The network send and receive functions on FreeRTOS. */ +int mbedtls_platform_send( void * ctx, + const unsigned char * buf, + size_t len ); +int mbedtls_platform_recv( void * ctx, + unsigned char * buf, + size_t len ); + +/* The entropy poll function. */ +int mbedtls_platform_entropy_poll( void * data, + unsigned char * output, + size_t len, + size_t * olen ); + +#include "mbedtls/check_config.h" + +#endif /* ifndef MBEDTLS_CONFIG_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/printf-stdarg.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/printf-stdarg.c new file mode 100644 index 000000000..5505535c1 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/common/printf-stdarg.c @@ -0,0 +1,667 @@ +/* + Copyright 2001, 2002 Georges Menie (www.menie.org) + stdarg version contributed by Christian Ettinger + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Changes for the FreeRTOS ports: + + - The dot in "%-8.8s" + - The specifiers 'l' (long) and 'L' (long long) + - The specifier 'u' for unsigned + - Dot notation for IP addresses: + sprintf("IP = %xip\n", 0xC0A80164); + will produce "IP = 192.168.1.100\n" +*/ + +#include +#include +#include +#include + +#include "FreeRTOS.h" + +#define PAD_RIGHT 1 +#define PAD_ZERO 2 + +/* + * Return 1 for readable, 2 for writeable, 3 for both. + * Function must be provided by the application. + */ +extern BaseType_t xApplicationMemoryPermissions( uint32_t aAddress ); + +extern void vOutputChar( const char cChar, const TickType_t xTicksToWait ); +static const TickType_t xTicksToWait = pdMS_TO_TICKS( 20 ); + +struct xPrintFlags +{ + int base; + int width; + int printLimit; + unsigned + pad : 8, + letBase : 8, + isSigned : 1, + isNumber : 1, + long32 : 1, + long64 : 1; +}; + +struct SStringBuf +{ + char *str; + const char *orgStr; + const char *nulPos; + int curLen; + struct xPrintFlags flags; +}; + +static void strbuf_init( struct SStringBuf *apStr, char *apBuf, const char *apMaxStr ) +{ + apStr->str = apBuf; + apStr->orgStr = apBuf; + apStr->nulPos = apMaxStr-1; + apStr->curLen = 0; + + memset( &apStr->flags, '\0', sizeof( apStr->flags ) ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t strbuf_printchar( struct SStringBuf *apStr, int c ) +{ + if( apStr->str == NULL ) + { + vOutputChar( ( char ) c, xTicksToWait ); + apStr->curLen++; + return pdTRUE; + } + if( apStr->str < apStr->nulPos ) + { + *( apStr->str++ ) = c; + apStr->curLen++; + return pdTRUE; + } + if( apStr->str == apStr->nulPos ) + { + *( apStr->str++ ) = '\0'; + } + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static portINLINE BaseType_t strbuf_printchar_inline( struct SStringBuf *apStr, int c ) +{ + if( apStr->str == NULL ) + { + vOutputChar( ( char ) c, xTicksToWait ); + if( c == 0 ) + { + return pdFALSE; + } + apStr->curLen++; + return pdTRUE; + } + if( apStr->str < apStr->nulPos ) + { + *(apStr->str++) = c; + if( c == 0 ) + { + return pdFALSE; + } + apStr->curLen++; + return pdTRUE; + } + if( apStr->str == apStr->nulPos ) + { + *( apStr->str++ ) = '\0'; + } + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static portINLINE int i2hex( int aCh ) +{ +int iResult; + + if( aCh < 10 ) + { + iResult = '0' + aCh; + } + else + { + iResult = 'A' + aCh - 10; + } + + return iResult; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prints(struct SStringBuf *apBuf, const char *apString ) +{ + register int padchar = ' '; + int i,len; + + if( xApplicationMemoryPermissions( ( uint32_t )apString ) == 0 ) + { + /* The user has probably made a mistake with the parameter + for '%s', the memory is not readbale. */ + apString = "INV_MEM"; + } + + if( apBuf->flags.width > 0 ) + { + register int len = 0; + register const char *ptr; + for( ptr = apString; *ptr; ++ptr ) + { + ++len; + } + + if( len >= apBuf->flags.width ) + { + apBuf->flags.width = 0; + } + else + { + apBuf->flags.width -= len; + } + + if( apBuf->flags.pad & PAD_ZERO ) + { + padchar = '0'; + } + } + if( ( apBuf->flags.pad & PAD_RIGHT ) == 0 ) + { + for( ; apBuf->flags.width > 0; --apBuf->flags.width ) + { + if( strbuf_printchar( apBuf, padchar ) == 0 ) + { + return pdFALSE; + } + } + } + if( ( apBuf->flags.isNumber == pdTRUE ) && ( apBuf->flags.pad == pdTRUE ) ) + { + /* The string to print represents an integer number. + * In this case, printLimit is the min number of digits to print + * If the length of the number to print is less than the min nb of i + * digits to display, we add 0 before printing the number + */ + len = strlen( apString ); + + if( len < apBuf->flags.printLimit ) + { + i = apBuf->flags.printLimit - len; + for( ; i; i-- ) + { + if( strbuf_printchar( apBuf, '0' ) == 0 ) + { + return pdFALSE; + } + } + } + } + /* The string to print is not the result of a number conversion to ascii. + * For a string, printLimit is the max number of characters to display + */ + for( ; apBuf->flags.printLimit && *apString ; ++apString, --apBuf->flags.printLimit ) + { + if( !strbuf_printchar( apBuf, *apString ) ) + { + return pdFALSE; + } + } + + for( ; apBuf->flags.width > 0; --apBuf->flags.width ) + { + if( !strbuf_printchar( apBuf, padchar ) ) + { + return pdFALSE; + } + } + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +/* the following should be enough for 32 bit int */ +#define PRINT_BUF_LEN 12 /* to print 4294967296 */ + +#if SPRINTF_LONG_LONG +#warning 64-bit libraries will be included as well +static BaseType_t printll( struct SStringBuf *apBuf, long long i ) +{ + char print_buf[ 2 * PRINT_BUF_LEN ]; + register char *s; + register int t, neg = 0; + register unsigned long long u = i; + lldiv_t lldiv_result; + +/* typedef struct + * { + * long long int quot; // quotient + * long long int rem; // remainder + * } lldiv_t; + */ + + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + if( i == 0LL ) + { + print_buf[ 0 ] = '0'; + print_buf[ 1 ] = '\0'; + return prints( apBuf, print_buf ); + } + + if( ( apBuf->flags.isSigned == pdTRUE ) && ( apBuf->flags.base == 10 ) && ( i < 0LL ) ) + { + neg = 1; + u = -i; + } + + s = print_buf + sizeof( print_buf ) - 1; + + *s = '\0'; + /* 18446744073709551616 */ + while( u != 0 ) + { + lldiv_result = lldiv( u, ( unsigned long long ) apBuf->flags.base ); + t = lldiv_result.rem; + if( t >= 10 ) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u = lldiv_result.quot; + } + + if( neg != 0 ) + { + if( ( apBuf->flags.width != 0 ) && ( apBuf->flags.pad & PAD_ZERO ) ) + { + if( !strbuf_printchar( apBuf, '-' ) ) + { + return pdFALSE; + } + --apBuf->flags.width; + } + else + { + *( --s ) = '-'; + } + } + + return prints( apBuf, s ); +} +#endif /* SPRINTF_LONG_LONG */ +/*-----------------------------------------------------------*/ + +static BaseType_t printi( struct SStringBuf *apBuf, int i ) +{ + char print_buf[ PRINT_BUF_LEN ]; + register char *s; + register int t, neg = 0; + register unsigned int u = i; + register unsigned base = apBuf->flags.base; + + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + + if( i == 0 ) + { + print_buf[ 0 ] = '0'; + print_buf[ 1 ] = '\0'; + return prints( apBuf, print_buf ); + } + + if( ( apBuf->flags.isSigned == pdTRUE ) && ( base == 10 ) && ( i < 0 ) ) + { + neg = 1; + u = -i; + } + + s = print_buf + sizeof( print_buf ) - 1; + + *s = '\0'; + switch( base ) + { + case 16: + while( u != 0 ) + { + t = u & 0xF; + if( t >= 10 ) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u >>= 4; + } + break; + + case 8: + case 10: + /* GCC compiles very efficient */ + while( u ) + { + t = u % base; + *( --s ) = t + '0'; + u /= base; + } + break; +/* + // The generic case, not yet in use + default: + while( u ) + { + t = u % base; + if( t >= 10) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u /= base; + } + break; +*/ + } + + if( neg != 0 ) + { + if( apBuf->flags.width && (apBuf->flags.pad & PAD_ZERO ) ) + { + if( strbuf_printchar( apBuf, '-' ) == 0 ) + { + return pdFALSE; + } + --apBuf->flags.width; + } + else + { + *( --s ) = '-'; + } + } + + return prints( apBuf, s ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t printIp(struct SStringBuf *apBuf, unsigned i ) +{ + char print_buf[16]; + + sprintf( print_buf, "%u.%u.%u.%u", + i >> 24, + ( i >> 16 ) & 0xff, + ( i >> 8 ) & 0xff, + i & 0xff ); + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + prints( apBuf, print_buf ); + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +static void tiny_print( struct SStringBuf *apBuf, const char *format, va_list args ) +{ + char scr[2]; + + for( ; ; ) + { + int ch = *( format++ ); + + if( ch != '%' ) + { + do + { + /* Put the most like flow in a small loop */ + if( strbuf_printchar_inline( apBuf, ch ) == 0 ) + { + return; + } + ch = *( format++ ); + } while( ch != '%' ); + } + ch = *( format++ ); + /* Now ch has character after '%', format pointing to next */ + + if( ch == '\0' ) + { + break; + } + if( ch == '%' ) + { + if( strbuf_printchar( apBuf, ch ) == 0 ) + { + return; + } + continue; + } + memset( &apBuf->flags, '\0', sizeof( apBuf->flags ) ); + + if( ch == '-' ) + { + ch = *( format++ ); + apBuf->flags.pad = PAD_RIGHT; + } + while( ch == '0' ) + { + ch = *( format++ ); + apBuf->flags.pad |= PAD_ZERO; + } + if( ch == '*' ) + { + ch = *( format++ ); + apBuf->flags.width = va_arg( args, int ); + } + else + { + while( ch >= '0' && ch <= '9' ) + { + apBuf->flags.width *= 10; + apBuf->flags.width += ch - '0'; + ch = *( format++ ); + } + } + if( ch == '.' ) + { + ch = *( format++ ); + if( ch == '*' ) + { + apBuf->flags.printLimit = va_arg( args, int ); + ch = *( format++ ); + } + else + { + while( ch >= '0' && ch <= '9' ) + { + apBuf->flags.printLimit *= 10; + apBuf->flags.printLimit += ch - '0'; + ch = *( format++ ); + } + } + } + if( apBuf->flags.printLimit == 0 ) + { + apBuf->flags.printLimit--; /* -1: make it unlimited */ + } + if( ch == 's' ) + { + register char *s = ( char * )va_arg( args, int ); + if( prints( apBuf, s ? s : "(null)" ) == 0 ) + { + break; + } + continue; + } + if( ch == 'c' ) + { + /* char are converted to int then pushed on the stack */ + scr[0] = ( char ) va_arg( args, int ); + + if( strbuf_printchar( apBuf, scr[0] ) == 0 ) + { + return; + } + + continue; + } + if( ch == 'l' ) + { + ch = *( format++ ); + apBuf->flags.long32 = 1; + /* Makes not difference as u32 == long */ + } + if( ch == 'L' ) + { + ch = *( format++ ); + apBuf->flags.long64 = 1; + /* Does make a difference */ + } + apBuf->flags.base = 10; + apBuf->flags.letBase = 'a'; + + if( ch == 'd' || ch == 'u' ) + { + apBuf->flags.isSigned = ( ch == 'd' ); +#if SPRINTF_LONG_LONG + if( apBuf->flags.long64 != pdFALSE ) + { + if( printll( apBuf, va_arg( args, long long ) ) == 0 ) + { + break; + } + } else +#endif /* SPRINTF_LONG_LONG */ + if( printi( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + + apBuf->flags.base = 16; /* From here all hexadecimal */ + + if( ch == 'x' && format[0] == 'i' && format[1] == 'p' ) + { + format += 2; /* eat the "xi" of "xip" */ + /* Will use base 10 again */ + if( printIp( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + if( ch == 'x' || ch == 'X' || ch == 'p' || ch == 'o' ) + { + if( ch == 'X' ) + { + apBuf->flags.letBase = 'A'; + } + else if( ch == 'o' ) + { + apBuf->flags.base = 8; + } +#if SPRINTF_LONG_LONG + if( apBuf->flags.long64 != pdFALSE ) + { + if( printll( apBuf, va_arg( args, long long ) ) == 0 ) + { + break; + } + } else +#endif /* SPRINTF_LONG_LONG */ + if( printi( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + } + strbuf_printchar( apBuf, '\0' ); +} +/*-----------------------------------------------------------*/ + +int vsnprintf( char *apBuf, size_t aMaxLen, const char *apFmt, va_list args ) +{ + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen ); + tiny_print( &strBuf, apFmt, args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int snprintf( char *apBuf, size_t aMaxLen, const char *apFmt, ... ) +{ + va_list args; + + va_start( args, apFmt ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen ); + tiny_print( &strBuf, apFmt, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int sprintf( char *apBuf, const char *apFmt, ... ) +{ + va_list args; + + va_start( args, apFmt ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char * )apBuf + 1024 ); + tiny_print( &strBuf, apFmt, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int vsprintf( char *apBuf, const char *apFmt, va_list args ) +{ + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* ) apBuf + 1024 ); + tiny_print( &strBuf, apFmt, args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +const char *mkSize (unsigned long long aSize, char *apBuf, int aLen) +{ +static char retString[33]; +size_t gb, mb, kb, sb; + + if (apBuf == NULL) { + apBuf = retString; + aLen = sizeof( retString ); + } + gb = aSize / (1024*1024*1024); + aSize -= gb * (1024*1024*1024); + mb = aSize / (1024*1024); + aSize -= mb * (1024*1024); + kb = aSize / (1024); + aSize -= kb * (1024); + sb = aSize; + if( gb ) + { + snprintf (apBuf, aLen, "%u.%02u GB", ( unsigned ) gb, ( unsigned ) ( ( 100 * mb ) / 1024ul ) ); + } + else if( mb ) + { + snprintf (apBuf, aLen, "%u.%02u MB", ( unsigned ) mb, ( unsigned ) ( ( 100 * kb) / 1024ul ) ); + } + else if( kb != 0ul ) + { + snprintf (apBuf, aLen, "%u.%02u KB", ( unsigned ) kb, ( unsigned ) ( ( 100 * sb) / 1024ul ) ); + } + else + { + snprintf (apBuf, aLen, "%u bytes", ( unsigned ) sb); + } + return apBuf; +} diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/FreeRTOSConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/FreeRTOSConfig.h new file mode 100644 index 000000000..d58a0b80f --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/FreeRTOSConfig.h @@ -0,0 +1,210 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * http://www.freertos.org/a00110.html + * + * The bottom of this file contains some constants specific to running the UDP + * stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than + * the demo) are contained in FreeRTOSIPConfig.h. + *----------------------------------------------------------*/ +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Run time stats gathering definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_pcTaskGetTaskName 1 + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS +is set to 2 so the formatting functions are included without the stdio.h being +included in tasks.c. That is because this project defines its own sprintf() +functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* Assert call defined for debug builds. */ +#ifdef _DEBUG + extern void vAssertCalled( const char *pcFile, uint32_t ulLine ); + #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) +#endif /* _DEBUG */ + + + +/* Application specific definitions follow. **********************************/ + +/* Only used when running in the FreeRTOS Windows simulator. Defines the +priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet +or WiFi data to and from a real network connection. Many computers have more +than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell +the demo which real port should be used to create the virtual port. The ports +available are displayed on the console when the application is executed. For +example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 +results in the wired network being used, while setting +configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being +used. */ +#define configNETWORK_INTERFACE_TO_USE 1L + +/* The address of an echo server is only left in this project as it doubles as +the address to which logging is sent should UDP logging be enabled. */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 0 +#define configECHO_SERVER_ADDR3 11 + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet/WiFi data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition above for information on how to +configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x11 +#define configMAC_ADDR3 0x11 +#define configMAC_ADDR4 0x11 +#define configMAC_ADDR5 0x41 + +/* Default IP address configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 10 +#define configIP_ADDR1 10 +#define configIP_ADDR2 10 +#define configIP_ADDR3 200 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DNS is set to +0, or ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 10 +#define configGATEWAY_ADDR1 10 +#define configGATEWAY_ADDR2 10 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. OpenDNS addresses are 208.67.222.222 and +208.67.220.220. Used in ipconfigUSE_DNS is set to 0, or ipconfigUSE_DNS is set +to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 208 +#define configDNS_SERVER_ADDR1 67 +#define configDNS_SERVER_ADDR2 222 +#define configDNS_SERVER_ADDR3 222 + +/* Default netmask configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 0 +#define configNET_MASK2 0 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#if( defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) && !defined( snprintf ) ) + /* Map to Windows names. */ + #define snprintf _snprintf + #define vsnprintf _vsnprintf +#endif + +/* Visual studio does not have an implementation of strcasecmp(). */ +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define strcmpi _strcmpi + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); +#define configPRINTF( X ) vLoggingPrintf X + +#endif /* FREERTOS_CONFIG_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/FreeRTOSIPConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/FreeRTOSIPConfig.h new file mode 100644 index 000000000..92b7773b7 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/FreeRTOSIPConfig.h @@ -0,0 +1,310 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +/***************************************************************************** + * + * See the following URL for configuration information. + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html + * + *****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to +1 then FreeRTOS_debug_printf should be defined to the function used to print +out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 0 +#if( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf(X) vLoggingPrintf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the +FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 +then FreeRTOS_printf should be set to the function used to print out the +messages. */ +#define ipconfigHAS_PRINTF 1 +#if( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf(X) vLoggingPrintf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing +on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading (IP/TCP/UDP checksums) +then set ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software +stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 + +/* Several API's will block until the result is known, or the action has been +performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be +set per socket, using setsockopt(). If not set, the times below will be +used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 2000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for LLMNR: Link-local Multicast Name Resolution +(non-Microsoft) */ +#define ipconfigUSE_LLMNR ( 0 ) + +/* Include support for NBNS: NetBIOS Name Service (Microsoft) */ +#define ipconfigUSE_NBNS ( 0 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very +useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low +and also DNS may use small timeouts. If a DNS reply comes in after the DNS +socket has been destroyed, the result will be stored into the cache. The next +call to FreeRTOS_gethostbyname() will return immediately, without even creating +a socket. */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_NAME_LENGTH ( 32 ) +#define ipconfigDNS_CACHE_ENTRIES ( 4 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make +use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY +sets the priority of the task that executes the IP stack. The priority is a +standard FreeRTOS task priority so can take any value from 0 (the lowest +priority) to (configMAX_PRIORITIES - 1) (the highest priority). +configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in +FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to +the priority assigned to the task executing the IP stack relative to the +priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP +task. This setting is less important when the FreeRTOS Win32 simulator is used +as the Win32 simulator only stores a fixed amount of information on the task +stack. FreeRTOS includes optional stack overflow detection, see: +http://www.freertos.org/Stacks-and-stack-overflow-checking.html */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* ipconfigRAND32() is called by the IP stack to generate random numbers for +things such as a DHCP transaction number or initial sequence number. Random +number generation is performed via this macro to allow applications to use their +own random number generation method. For example, it might be possible to +generate a random number by sampling noise on an analogue input. */ +extern UBaseType_t uxRand(); +#define ipconfigRAND32() uxRand() + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the +network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK +is not set to 1 then the network event hook will never be called. See +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml +*/ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but +a network buffer cannot be obtained then the calling task is held in the Blocked +state (so other tasks can continue to executed) until either a network buffer +becomes available or the send block time expires. If the send block time expires +then the send operation is aborted. The maximum allowable send block time is +capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the +maximum allowable send block time prevents prevents a deadlock occurring when +all the network buffers are in use and the tasks that process (and subsequently +free) the network buffers are themselves blocked waiting for a network buffer. +ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in +milliseconds can be converted to a time in ticks by dividing the time in +milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP +address, netmask, DNS server address and gateway address from a DHCP server. If +ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The +stack will revert to using the static IP address even when ipconfigUSE_DHCP is +set to 1 if a valid configuration cannot be obtained from a DHCP server for any +reason. The static configuration used is that passed into the stack by the +FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 1 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at +increasing time intervals until either a reply is received from a DHCP server +and accepted, or the interval between transmissions reaches +ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the +static IP address passed as a parameter to FreeRTOS_IPInit() if the +re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without +a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( 120000 / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP +stack can only send a UDP message to a remove IP address if it knowns the MAC +address associated with the IP address, or the MAC address of the router used to +contact the remote IP address. When a UDP message is received from a remote IP +address the MAC address and IP address are added to the ARP cache. When a UDP +message is sent to a remote IP address that does not already appear in the ARP +cache then the UDP message is replaced by a ARP message that solicits the +required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum +number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a +maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is +aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP +table being created or refreshed and the entry being removed because it is stale. +New ARP requests are sent for ARP cache entries that are nearing their maximum +age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is +equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling +routines, which are relatively large. To save code space the full +FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster +alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() +takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. +FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets +(for example, 192, 168, 0, 1) as its parameters. If +ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and +FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is +not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that +are available to the IP stack. The total number of network buffers is limited +to ensure the total amount of RAM that can be consumed by the IP stack is capped +to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP +stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can +be queued for processing at any one time. The event queue must be a minimum of +5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port +number. FreeRTOS_bind() is used to manually allocate a port number to a socket +(to 'bind' the socket to a port), but manual binding is not normally necessary +for client sockets (those sockets that initiate outgoing connections rather than +wait for incoming connections on a known port number). If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling +FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP +stack automatically binding the socket to a port number from the range +socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() +on a socket that has not yet been bound will result in the send operation being +aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +#define ipconfigTCP_TIME_TO_LIVE 128 /* also defined in FreeRTOSIPConfigDefaults.h */ + +/* USE_TCP: Use TCP and all its features */ +#define ipconfigUSE_TCP ( 1 ) + +/* Use the TCP socket wake context with a callback. */ +#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT ( 1 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can +contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a +lower value can save RAM, depending on the buffer management scheme used. If +ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must +be divisible by 8. */ +#define ipconfigNETWORK_MTU 1200 + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used +through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will +generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the +FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 0 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() +(and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames +that are not in Ethernet II format will be dropped. This option is included for +potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the +responsibility of the Ethernet interface to filter out packets that are of no +interest. If the Ethernet interface does not implement this functionality, then +set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack +perform the filtering instead (it is much less efficient for the stack to do it +because the packet will already have been passed into the stack). If the +Ethernet driver does all the necessary filtering in hardware then software +filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to +block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with +32-bit memory instructions, all packets will be stored 32-bit-aligned, plus 16-bits. +This has to do with the contents of the IP-packets: all 32-bit fields are +32-bit-aligned, plus 16-bit(!) */ +#define ipconfigPACKET_FILLER_SIZE 2 + +/* Define the size of the pool of TCP window descriptors. On the average, each +TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 +outstanding packets (for Rx and Tx). When using up to 10 TP sockets +simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed +maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 1000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 1000 ) + +/* When using call-back handlers, the driver may check if the handler points to +real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS(x) ( (x) != NULL ) + +/* Include support for TCP hang protection. All sockets in a connecting or +disconnecting stage will timeout after a period of non-activity. */ +#define ipconfigTCP_HANG_PROTECTION ( 1 ) +#define ipconfigTCP_HANG_PROTECTION_TIME ( 30 ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* in seconds */ + +#define portINLINE __inline + +#endif /* FREERTOS_IP_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/READ_ME_INSTRUCTIONS.url b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/READ_ME_INSTRUCTIONS.url new file mode 100644 index 000000000..6c689ef14 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/READ_ME_INSTRUCTIONS.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/https/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/WIN32.vcxproj b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/WIN32.vcxproj new file mode 100644 index 000000000..339b9832c --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/WIN32.vcxproj @@ -0,0 +1,220 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {C686325E-3261-42F7-AEB1-DDE5280E1CEB} + RTOSDemo + 10.0 + + + + Application + false + MultiByte + v142 + + + Application + false + MultiByte + v142 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Debug\ + .\Debug\ + true + .\Release\ + .\Release\ + false + AllRules.ruleset + + + + .\Debug/WIN32.tlb + + + + + Disabled + ..\..\include;..\common;..\common\WinPCap;..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\src;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\http-parser;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\platform;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\https\include;.;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDLL + .\Debug/WIN32.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level4 + true + false + EditAndContinue + /wd4210 /wd4127 /wd4214 /wd4201 /wd4244 /wd4310 /wd4200 %(AdditionalOptions) + true + NotUsing + false + CompileAsC + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Debug/RTOSDemo.exe + true + true + .\Debug/WIN32.pdb + Console + MachineX86 + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + ..\common\WinPCap + false + false + + + true + .\Debug/WIN32.bsc + + + + + .\Release/WIN32.tlb + + + + + MaxSpeed + OnlyExplicitInline + _WINSOCKAPI_;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release/WIN32.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + ..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;.\DemoTasks\include;.\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\src;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\platform;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\https\include;.;%(AdditionalIncludeDirectories) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Release/RTOSDemo.exe + true + .\Release/WIN32.pdb + Console + MachineX86 + .\WinPCap + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + + + true + .\Release/WIN32.bsc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/WIN32.vcxproj.filters b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/WIN32.vcxproj.filters new file mode 100644 index 000000000..cf28f677e --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/WIN32.vcxproj.filters @@ -0,0 +1,293 @@ + + + + + {af3445a1-4908-4170-89ed-39345d90d30c} + + + {f32be356-4763-4cae-9020-974a2638cb08} + *.c + + + {88f409e6-d396-4ac5-94bd-7a99c914be46} + + + {e5ad4ec7-23dc-4295-8add-2acaee488f5a} + + + {d2dcd641-8d91-492b-852f-5563ffadaec6} + + + {8672fa26-b119-481f-8b8d-086419c01a3e} + + + {4570be11-ec96-4b55-ac58-24b50ada980a} + + + {5d93ed51-023a-41ad-9243-8d230165d34b} + + + {b71e974a-9f28-4815-972b-d930ba8a34d0} + + + {60717407-397f-4ea5-8492-3314acdd25f0} + + + {8a90222f-d723-4b4e-8e6e-c57afaf7fa92} + + + {7c995f05-2a10-4771-ad77-18a755876e46} + + + {9a636cc3-ebc6-48c5-8c18-c72494686e81} + + + {29376c48-bc8b-4624-ad59-16807874c9f2} + + + {91ef4008-de51-4b41-ba5e-bf24d8cda378} + + + {ade43c6c-04c5-4897-abdb-91af2df04e5d} + + + {08a4e35c-19ca-4b1e-af24-bac368c2bf7b} + + + {1e324500-91b4-4c76-b699-59ba75691760} + + + {bdcbc1ec-99b8-4c72-9075-49035c115488} + + + {2d17d5e6-ed70-4e42-9693-f7a63baf4948} + + + {7158b0be-01e7-42d1-8d3f-c75118a596a2} + + + {6ad56e6d-c330-4830-8f4b-c75b05dfa866} + + + {1d80b387-5a86-4744-a4cc-930033a52e4b} + + + {3dc958a5-cd64-4a6a-af27-beba20339e4b} + + + {d5bf72d9-1e71-4a65-ac2f-5f28a99b0796} + + + {b0616e09-2c08-40a1-aa2d-5cbd592e4451} + + + {f1ad002c-d40b-465f-b648-17cedba667d1} + + + + + FreeRTOS\Source\Portable + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS\Source + + + FreeRTOS\Source\Portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\https\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\https\src + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\http-parser + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + + + DemoTasks + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\https\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\https\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos\include\platform + + + FreeRTOS+\http-parser + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/demo_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/demo_config.h new file mode 100644 index 000000000..e81cc2cd9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/demo_config.h @@ -0,0 +1,78 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef DEMO_CONFIG_H +#define DEMO_CONFIG_H + +/* + * This configuration file determines how the HTTPS demo is run. + * + * http_plain_text demo: Security is turned off. Preconfigured to a public HTTP + * host on unencrypted port so no authentication configuration is required. + * + * https_basic_tls_server_auth demo: TLS security is enabled, allowing host + * side authentication. Preconfigured to a public HTTPS host with certificate + * provided by the host so no authentication configuration is required. + * + * https_tls_mutual_auth demo: Mutual authentication is enabled. Preconfigured to + * AWS IoT broker, will require certificate setup for successful connection. + */ + +/** + * @brief Enable/Disable TLS in demos. + * + * For more information regarding TLS protocol: + * https://www.freertos.org/https/tls.html + */ +#define democonfigENABLE_TLS 0 + +/** + * @brief Enable/Disable mutual authentication in demos. If enabled, require + * democonfigENABLE_TLS to be set to 1. + */ +#define democonfigENABLE_MUTUAL_AUTH 0 + +/** + * @brief Select a connection profile. + * + * If set to 1, the demo will connect to AWS IoT with credential setup in + * aws_iot_demo_profile.h file, otherwise the demo is preconfigured to connect to + * httpbin.org with credential setup in https_demo_profile.h file. If enabled, + * requires democonfigENABLE_MUTUAL_AUTH to be set to 1 since AWS IoT requires + * mutually authenticated connection. + */ +#define democonfigPROFILE_USE_AWS_IOT 0 + +/** + * @brief Set the stack size of the main demo task. + * + * In the Windows port, this stack only holds a structure. The actual + * stack is created by an operating system thread. + */ +#define democonfigDEMO_STACKSIZE configMINIMAL_STACK_SIZE + +#endif /* DEMO_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/http_plain_text_demo.sln b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/http_plain_text_demo.sln new file mode 100644 index 000000000..b362f36c5 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/http_plain_text_demo.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTOSDemo", "WIN32.vcxproj", "{C686325E-3261-42F7-AEB1-DDE5280E1CEB}" +EndProject +Global + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = FreeRTOS_Plus_TCP_Minimal.vsmdi + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.ActiveCfg = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.Build.0 = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.ActiveCfg = Release|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/iot_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/iot_config.h new file mode 100644 index 000000000..0d7075db9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/http_plain_text/iot_config.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/* This file contains configuration settings for the demos. */ + +#ifndef IOT_CONFIG_H_ +#define IOT_CONFIG_H_ + +/* Configure the IoT Libraries for FreeRTOS by including the FreeRTOS header and + * the FreeRTOS platform types. */ +#include "FreeRTOS.h" +#include "platform/iot_platform_types_freertos.h" + +/** + * @brief Set a global default for log levels. + * + * This setting is overridden by log level settings of specific libraries. + * Undefined library-specific log levels will default to this value. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_GLOBAL IOT_LOG_NONE + +/** + * @brief Set the log level of the platform libraries except the network + * component. + * + * Log messages from the platform libraries at or below this setting + * will be printed. As the network component is more verbose, its logging + * is controlled by its own setting, IOT_LOG_LEVEL_NETWORK. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_PLATFORM IOT_LOG_NONE + +/** + * @brief Set the log level of the platform network library. + * + * Log messages from the platform network library at or below this setting + * will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_NETWORK IOT_LOG_WARN + +/* + * @brief Set the log level of the task pool library. + * + * Log messages from the task pool library at or below this setting will be + * printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_TASKPOOL IOT_LOG_WARN + +/** + * @brief Set the log level of the HTTPS Client library. + * + * Log messages from the HTTPS Client library at or below this setting will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_HTTPS IOT_LOG_WARN + +/** + * @brief Enable/Disable asserts for the task pool library. + * + * Set this to 1 to perform sanity checks when using the task pool library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotTaskPool_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_TASKPOOL_ENABLE_ASSERTS 1 + +/** + * @brief The number of worker tasks in the task pool. + * + * The full IoT Task Pool Library has many use cases, including Linux + * development. Typical FreeRTOS use cases do not require the full + * functionality so an optimized implementation is provided specifically for use + * with FreeRTOS. The optimized version has a fixed number of tasks in the + * task pool, each of which uses statically allocated memory to ensure creation + * of the task pool is guaranteed (it does not run out of heap space). + */ +#define IOT_TASKPOOL_NUMBER_OF_WORKERS 1 + +/** + * @brief The stack size (in bytes) for each worker task in the task pool. + * + * The minimal version of the of task pool library only supports one task pool + * and the configuration of each worker task fixed at the compile time. + */ +#define IOT_TASKPOOL_WORKER_STACK_SIZE_BYTES 2048 + +/** + * @brief Enable/Disable asserts for the linear containers library. + * + * Set this to 1 to perform sanity checks when using the linear containers library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotContainers_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_CONTAINERS_ENABLE_ASSERTS 1 + +/* Common settings for FreeRTOS; settings below this line generally do not need + * to be changed. */ + +/* Logging puts function on FreeRTOS. */ +#define IotLogging_Puts( str ) configPRINTF( ( "%s\r\n", str ) ) + +/* Assert functions on FreeRTOS. */ +#define IotContainers_Assert( expression ) configASSERT( expression ) +#define IotTaskPool_Assert( expression ) configASSERT( expression ) + +/* Memory allocation functions on FreeRTOS. */ +#define IotThreads_Malloc pvPortMalloc +#define IotThreads_Free vPortFree + +#define IotLogging_Malloc pvPortMalloc +#define IotLogging_Free vPortFree + +#define IotTaskPool_MallocTaskPool pvPortMalloc +#define IotTaskPool_FreeTaskPool vPortFree +#define IotTaskPool_MallocJob pvPortMalloc +#define IotTaskPool_FreeJob vPortFree +#define IotTaskPool_MallocTimerEvent pvPortMalloc +#define IotTaskPool_FreeTimerEvent vPortFree + +#endif /* ifndef IOT_CONFIG_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/FreeRTOSConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/FreeRTOSConfig.h new file mode 100644 index 000000000..d58a0b80f --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/FreeRTOSConfig.h @@ -0,0 +1,210 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * http://www.freertos.org/a00110.html + * + * The bottom of this file contains some constants specific to running the UDP + * stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than + * the demo) are contained in FreeRTOSIPConfig.h. + *----------------------------------------------------------*/ +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Run time stats gathering definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_pcTaskGetTaskName 1 + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS +is set to 2 so the formatting functions are included without the stdio.h being +included in tasks.c. That is because this project defines its own sprintf() +functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* Assert call defined for debug builds. */ +#ifdef _DEBUG + extern void vAssertCalled( const char *pcFile, uint32_t ulLine ); + #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) +#endif /* _DEBUG */ + + + +/* Application specific definitions follow. **********************************/ + +/* Only used when running in the FreeRTOS Windows simulator. Defines the +priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet +or WiFi data to and from a real network connection. Many computers have more +than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell +the demo which real port should be used to create the virtual port. The ports +available are displayed on the console when the application is executed. For +example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 +results in the wired network being used, while setting +configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being +used. */ +#define configNETWORK_INTERFACE_TO_USE 1L + +/* The address of an echo server is only left in this project as it doubles as +the address to which logging is sent should UDP logging be enabled. */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 0 +#define configECHO_SERVER_ADDR3 11 + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet/WiFi data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition above for information on how to +configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x11 +#define configMAC_ADDR3 0x11 +#define configMAC_ADDR4 0x11 +#define configMAC_ADDR5 0x41 + +/* Default IP address configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 10 +#define configIP_ADDR1 10 +#define configIP_ADDR2 10 +#define configIP_ADDR3 200 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DNS is set to +0, or ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 10 +#define configGATEWAY_ADDR1 10 +#define configGATEWAY_ADDR2 10 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. OpenDNS addresses are 208.67.222.222 and +208.67.220.220. Used in ipconfigUSE_DNS is set to 0, or ipconfigUSE_DNS is set +to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 208 +#define configDNS_SERVER_ADDR1 67 +#define configDNS_SERVER_ADDR2 222 +#define configDNS_SERVER_ADDR3 222 + +/* Default netmask configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 0 +#define configNET_MASK2 0 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#if( defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) && !defined( snprintf ) ) + /* Map to Windows names. */ + #define snprintf _snprintf + #define vsnprintf _vsnprintf +#endif + +/* Visual studio does not have an implementation of strcasecmp(). */ +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define strcmpi _strcmpi + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); +#define configPRINTF( X ) vLoggingPrintf X + +#endif /* FREERTOS_CONFIG_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/FreeRTOSIPConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/FreeRTOSIPConfig.h new file mode 100644 index 000000000..92b7773b7 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/FreeRTOSIPConfig.h @@ -0,0 +1,310 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +/***************************************************************************** + * + * See the following URL for configuration information. + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html + * + *****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to +1 then FreeRTOS_debug_printf should be defined to the function used to print +out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 0 +#if( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf(X) vLoggingPrintf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the +FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 +then FreeRTOS_printf should be set to the function used to print out the +messages. */ +#define ipconfigHAS_PRINTF 1 +#if( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf(X) vLoggingPrintf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing +on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading (IP/TCP/UDP checksums) +then set ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software +stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 + +/* Several API's will block until the result is known, or the action has been +performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be +set per socket, using setsockopt(). If not set, the times below will be +used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 2000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for LLMNR: Link-local Multicast Name Resolution +(non-Microsoft) */ +#define ipconfigUSE_LLMNR ( 0 ) + +/* Include support for NBNS: NetBIOS Name Service (Microsoft) */ +#define ipconfigUSE_NBNS ( 0 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very +useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low +and also DNS may use small timeouts. If a DNS reply comes in after the DNS +socket has been destroyed, the result will be stored into the cache. The next +call to FreeRTOS_gethostbyname() will return immediately, without even creating +a socket. */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_NAME_LENGTH ( 32 ) +#define ipconfigDNS_CACHE_ENTRIES ( 4 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make +use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY +sets the priority of the task that executes the IP stack. The priority is a +standard FreeRTOS task priority so can take any value from 0 (the lowest +priority) to (configMAX_PRIORITIES - 1) (the highest priority). +configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in +FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to +the priority assigned to the task executing the IP stack relative to the +priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP +task. This setting is less important when the FreeRTOS Win32 simulator is used +as the Win32 simulator only stores a fixed amount of information on the task +stack. FreeRTOS includes optional stack overflow detection, see: +http://www.freertos.org/Stacks-and-stack-overflow-checking.html */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* ipconfigRAND32() is called by the IP stack to generate random numbers for +things such as a DHCP transaction number or initial sequence number. Random +number generation is performed via this macro to allow applications to use their +own random number generation method. For example, it might be possible to +generate a random number by sampling noise on an analogue input. */ +extern UBaseType_t uxRand(); +#define ipconfigRAND32() uxRand() + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the +network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK +is not set to 1 then the network event hook will never be called. See +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml +*/ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but +a network buffer cannot be obtained then the calling task is held in the Blocked +state (so other tasks can continue to executed) until either a network buffer +becomes available or the send block time expires. If the send block time expires +then the send operation is aborted. The maximum allowable send block time is +capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the +maximum allowable send block time prevents prevents a deadlock occurring when +all the network buffers are in use and the tasks that process (and subsequently +free) the network buffers are themselves blocked waiting for a network buffer. +ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in +milliseconds can be converted to a time in ticks by dividing the time in +milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP +address, netmask, DNS server address and gateway address from a DHCP server. If +ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The +stack will revert to using the static IP address even when ipconfigUSE_DHCP is +set to 1 if a valid configuration cannot be obtained from a DHCP server for any +reason. The static configuration used is that passed into the stack by the +FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 1 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at +increasing time intervals until either a reply is received from a DHCP server +and accepted, or the interval between transmissions reaches +ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the +static IP address passed as a parameter to FreeRTOS_IPInit() if the +re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without +a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( 120000 / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP +stack can only send a UDP message to a remove IP address if it knowns the MAC +address associated with the IP address, or the MAC address of the router used to +contact the remote IP address. When a UDP message is received from a remote IP +address the MAC address and IP address are added to the ARP cache. When a UDP +message is sent to a remote IP address that does not already appear in the ARP +cache then the UDP message is replaced by a ARP message that solicits the +required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum +number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a +maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is +aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP +table being created or refreshed and the entry being removed because it is stale. +New ARP requests are sent for ARP cache entries that are nearing their maximum +age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is +equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling +routines, which are relatively large. To save code space the full +FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster +alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() +takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. +FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets +(for example, 192, 168, 0, 1) as its parameters. If +ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and +FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is +not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that +are available to the IP stack. The total number of network buffers is limited +to ensure the total amount of RAM that can be consumed by the IP stack is capped +to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP +stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can +be queued for processing at any one time. The event queue must be a minimum of +5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port +number. FreeRTOS_bind() is used to manually allocate a port number to a socket +(to 'bind' the socket to a port), but manual binding is not normally necessary +for client sockets (those sockets that initiate outgoing connections rather than +wait for incoming connections on a known port number). If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling +FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP +stack automatically binding the socket to a port number from the range +socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() +on a socket that has not yet been bound will result in the send operation being +aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +#define ipconfigTCP_TIME_TO_LIVE 128 /* also defined in FreeRTOSIPConfigDefaults.h */ + +/* USE_TCP: Use TCP and all its features */ +#define ipconfigUSE_TCP ( 1 ) + +/* Use the TCP socket wake context with a callback. */ +#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT ( 1 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can +contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a +lower value can save RAM, depending on the buffer management scheme used. If +ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must +be divisible by 8. */ +#define ipconfigNETWORK_MTU 1200 + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used +through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will +generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the +FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 0 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() +(and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames +that are not in Ethernet II format will be dropped. This option is included for +potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the +responsibility of the Ethernet interface to filter out packets that are of no +interest. If the Ethernet interface does not implement this functionality, then +set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack +perform the filtering instead (it is much less efficient for the stack to do it +because the packet will already have been passed into the stack). If the +Ethernet driver does all the necessary filtering in hardware then software +filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to +block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with +32-bit memory instructions, all packets will be stored 32-bit-aligned, plus 16-bits. +This has to do with the contents of the IP-packets: all 32-bit fields are +32-bit-aligned, plus 16-bit(!) */ +#define ipconfigPACKET_FILLER_SIZE 2 + +/* Define the size of the pool of TCP window descriptors. On the average, each +TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 +outstanding packets (for Rx and Tx). When using up to 10 TP sockets +simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed +maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 1000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 1000 ) + +/* When using call-back handlers, the driver may check if the handler points to +real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS(x) ( (x) != NULL ) + +/* Include support for TCP hang protection. All sockets in a connecting or +disconnecting stage will timeout after a period of non-activity. */ +#define ipconfigTCP_HANG_PROTECTION ( 1 ) +#define ipconfigTCP_HANG_PROTECTION_TIME ( 30 ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* in seconds */ + +#define portINLINE __inline + +#endif /* FREERTOS_IP_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/READ_ME_INSTRUCTIONS.url b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/READ_ME_INSTRUCTIONS.url new file mode 100644 index 000000000..6c689ef14 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/READ_ME_INSTRUCTIONS.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/https/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/WIN32.vcxproj b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/WIN32.vcxproj new file mode 100644 index 000000000..371f41edf --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/WIN32.vcxproj @@ -0,0 +1,618 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {C686325E-3261-42F7-AEB1-DDE5280E1CEB} + RTOSDemo + 10.0 + + + + Application + false + MultiByte + v142 + + + Application + false + MultiByte + v142 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Debug\ + .\Debug\ + true + .\Release\ + .\Release\ + false + AllRules.ruleset + + + + .\Debug/WIN32.tlb + + + + + Disabled + ..\..\include;..\common;..\common\WinPCap;..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\src;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\http-parser;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\mbedtls;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\platform;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\https\include;..\..\..\..\Source\mbedtls\include;.;%(AdditionalIncludeDirectories) + MBEDTLS_CONFIG_FILE="mbedtls_config.h";WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDLL + .\Debug/WIN32.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level4 + true + false + EditAndContinue + /wd4210 /wd4127 /wd4214 /wd4201 /wd4244 /wd4310 /wd4200 %(AdditionalOptions) + true + NotUsing + false + CompileAsC + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Debug/RTOSDemo.exe + true + true + .\Debug/WIN32.pdb + Console + MachineX86 + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + ..\common\WinPCap + false + false + + + true + .\Debug/WIN32.bsc + + + + + .\Release/WIN32.tlb + + + + + MaxSpeed + OnlyExplicitInline + MBEDTLS_CONFIG_FILE="mbedtls_config.h";_WINSOCKAPI_;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release/WIN32.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + ..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;.\DemoTasks\include;.\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\src;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\mbedtls;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\platform;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\https\include;..\..\..\..\Source\mbedtls\include;.;%(AdditionalIncludeDirectories) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Release/RTOSDemo.exe + true + .\Release/WIN32.pdb + Console + MachineX86 + .\WinPCap + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + + + true + .\Release/WIN32.bsc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/WIN32.vcxproj.filters b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/WIN32.vcxproj.filters new file mode 100644 index 000000000..e4642308e --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/WIN32.vcxproj.filters @@ -0,0 +1,786 @@ + + + + + {af3445a1-4908-4170-89ed-39345d90d30c} + + + {f32be356-4763-4cae-9020-974a2638cb08} + *.c + + + {88f409e6-d396-4ac5-94bd-7a99c914be46} + + + {e5ad4ec7-23dc-4295-8add-2acaee488f5a} + + + {d2dcd641-8d91-492b-852f-5563ffadaec6} + + + {8672fa26-b119-481f-8b8d-086419c01a3e} + + + {4570be11-ec96-4b55-ac58-24b50ada980a} + + + {5d93ed51-023a-41ad-9243-8d230165d34b} + + + {b71e974a-9f28-4815-972b-d930ba8a34d0} + + + {60717407-397f-4ea5-8492-3314acdd25f0} + + + {8a90222f-d723-4b4e-8e6e-c57afaf7fa92} + + + {7c995f05-2a10-4771-ad77-18a755876e46} + + + {9a636cc3-ebc6-48c5-8c18-c72494686e81} + + + {29376c48-bc8b-4624-ad59-16807874c9f2} + + + {91ef4008-de51-4b41-ba5e-bf24d8cda378} + + + {ade43c6c-04c5-4897-abdb-91af2df04e5d} + + + {08a4e35c-19ca-4b1e-af24-bac368c2bf7b} + + + {1e324500-91b4-4c76-b699-59ba75691760} + + + {bdcbc1ec-99b8-4c72-9075-49035c115488} + + + {2d17d5e6-ed70-4e42-9693-f7a63baf4948} + + + {7158b0be-01e7-42d1-8d3f-c75118a596a2} + + + {6ad56e6d-c330-4830-8f4b-c75b05dfa866} + + + {1d80b387-5a86-4744-a4cc-930033a52e4b} + + + {3dc958a5-cd64-4a6a-af27-beba20339e4b} + + + {1cecca7f-60cd-4d8d-8123-f00aa75af147} + + + {f9a2e0a1-ed56-4ca7-b8b2-d694a94c78c0} + + + {61ac8e2c-8fd1-44a0-a7a9-0326bc190426} + + + {b53bfe50-b4d9-4b78-b7bb-ae90e4d25615} + + + {d5bf72d9-1e71-4a65-ac2f-5f28a99b0796} + + + {b0616e09-2c08-40a1-aa2d-5cbd592e4451} + + + {f1ad002c-d40b-465f-b648-17cedba667d1} + + + + + FreeRTOS\Source\Portable + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS\Source + + + FreeRTOS\Source\Portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\https\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\https\src + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\http-parser + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\mbedtls + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + + + DemoTasks + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\https\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\https\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos\include\platform + + + FreeRTOS+\http-parser + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\mbedtls + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/demo_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/demo_config.h new file mode 100644 index 000000000..73f331883 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/demo_config.h @@ -0,0 +1,78 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef DEMO_CONFIG_H +#define DEMO_CONFIG_H + +/* + * This configuration file determines how the HTTPS demo is run. + * + * http_plain_text demo: Security is turned off. Preconfigured to a public HTTP + * host on unencrypted port so no authentication configuration is required. + * + * https_basic_tls_server_auth demo: TLS security is enabled, allowing host + * side authentication. Preconfigured to a public HTTPS host with certificate + * provided by the host so no authentication configuration is required. + * + * https_tls_mutual_auth demo: Mutual authentication is enabled. Preconfigured to + * AWS IoT broker, will require certificate setup for successful connection. + */ + +/** + * @brief Enable/Disable TLS in demos. + * + * For more information regarding TLS protocol: + * https://www.freertos.org/https/tls.html + */ +#define democonfigENABLE_TLS 1 + +/** + * @brief Enable/Disable mutual authentication in demos. If enabled, require + * democonfigENABLE_TLS to be set to 1. + */ +#define democonfigENABLE_MUTUAL_AUTH 0 + +/** + * @brief Select a connection profile. + * + * If set to 1, the demo will connect to AWS IoT with credential setup in + * aws_iot_demo_profile.h file, otherwise the demo is preconfigured to connect to + * httpbin.org with credential setup in https_demo_profile.h file. If enabled, + * requires democonfigENABLE_MUTUAL_AUTH to be set to 1 since AWS IoT requires + * mutually authenticated connection. + */ +#define democonfigPROFILE_USE_AWS_IOT 0 + +/** + * @brief Set the stack size of the main demo task. + * + * In the Windows port, this stack only holds a structure. The actual + * stack is created by an operating system thread. + */ +#define democonfigDEMO_STACKSIZE configMINIMAL_STACK_SIZE + +#endif /* DEMO_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/https_basic_tls_demo.sln b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/https_basic_tls_demo.sln new file mode 100644 index 000000000..b362f36c5 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/https_basic_tls_demo.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTOSDemo", "WIN32.vcxproj", "{C686325E-3261-42F7-AEB1-DDE5280E1CEB}" +EndProject +Global + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = FreeRTOS_Plus_TCP_Minimal.vsmdi + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.ActiveCfg = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.Build.0 = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.ActiveCfg = Release|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/iot_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/iot_config.h new file mode 100644 index 000000000..0666b8f7e --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_basic_tls_server_auth/iot_config.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/* This file contains configuration settings for the demos. */ + +#ifndef IOT_CONFIG_H_ +#define IOT_CONFIG_H_ + +/* Configure the IoT Libraries for FreeRTOS by including the FreeRTOS header and + * the FreeRTOS platform types. */ +#include "FreeRTOS.h" +#include "platform/iot_platform_types_freertos.h" + +/** + * @brief Set a global default for log levels. + * + * This setting is overridden by log level settings of specific libraries. + * Undefined library-specific log levels will default to this value. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_GLOBAL IOT_LOG_NONE + +/** + * @brief Set the log level of the platform libraries except the network + * component. + * + * Log messages from the platform libraries at or below this setting + * will be printed. As the network component is more verbose, its logging + * is controlled by its own setting, IOT_LOG_LEVEL_NETWORK. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_PLATFORM IOT_LOG_NONE + +/** + * @brief Set the log level of the platform network library. + * + * Log messages from the platform network library at or below this setting + * will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_NETWORK IOT_LOG_WARN + +/* + * @brief Set the log level of the task pool library. + * + * Log messages from the task pool library at or below this setting will be + * printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_TASKPOOL IOT_LOG_WARN + +/** + * @brief Set the log level of the HTTPS Client library. + * + * Log messages from the HTTPS Client library at or below this setting will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_HTTPS IOT_LOG_WARN + +/** + * @brief Enable/Disable asserts for the task pool library. + * + * Set this to 1 to perform sanity checks when using the task pool library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotTaskPool_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_TASKPOOL_ENABLE_ASSERTS 1 + +/** + * @brief The number of worker tasks in the task pool. + * + * The full IoT Task Pool Library has many use cases, including Linux + * development. Typical FreeRTOS use cases do not require the full + * functionality so an optimized implementation is provided specifically for use + * with FreeRTOS. The optimized version has a fixed number of tasks in the + * task pool, each of which uses statically allocated memory to ensure creation + * of the task pool is guaranteed (it does not run out of heap space). + */ +#define IOT_TASKPOOL_NUMBER_OF_WORKERS 1 + +/** + * @brief The stack size (in bytes) for each worker task in the task pool. + * + * The minimal version of the of task pool library only supports one task pool + * and the configuration of each worker task fixed at the compile time. + */ +#define IOT_TASKPOOL_WORKER_STACK_SIZE_BYTES 2048 + +/** + * @brief Enable TLS in the network abstraction. + * + * The TLS implementation requires the mbed TLS library. + */ +#define IOT_NETWORK_ENABLE_TLS 1 + +/** + * @brief Enable/Disable asserts for the linear containers library. + * + * Set this to 1 to perform sanity checks when using the linear containers library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotContainers_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_CONTAINERS_ENABLE_ASSERTS 1 + +/* Common settings for FreeRTOS; settings below this line generally do not need + * to be changed. */ + +/* Logging puts function on FreeRTOS. */ +#define IotLogging_Puts( str ) configPRINTF( ( "%s\r\n", str ) ) + +/* Assert functions on FreeRTOS. */ +#define IotContainers_Assert( expression ) configASSERT( expression ) +#define IotTaskPool_Assert( expression ) configASSERT( expression ) + +/* Memory allocation functions on FreeRTOS. */ +#define IotThreads_Malloc pvPortMalloc +#define IotThreads_Free vPortFree + +#define IotLogging_Malloc pvPortMalloc +#define IotLogging_Free vPortFree + +#define IotTaskPool_MallocTaskPool pvPortMalloc +#define IotTaskPool_FreeTaskPool vPortFree +#define IotTaskPool_MallocJob pvPortMalloc +#define IotTaskPool_FreeJob vPortFree +#define IotTaskPool_MallocTimerEvent pvPortMalloc +#define IotTaskPool_FreeTimerEvent vPortFree + +#endif /* ifndef IOT_CONFIG_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/FreeRTOSConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/FreeRTOSConfig.h new file mode 100644 index 000000000..d58a0b80f --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/FreeRTOSConfig.h @@ -0,0 +1,210 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * http://www.freertos.org/a00110.html + * + * The bottom of this file contains some constants specific to running the UDP + * stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than + * the demo) are contained in FreeRTOSIPConfig.h. + *----------------------------------------------------------*/ +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Run time stats gathering definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_pcTaskGetTaskName 1 + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS +is set to 2 so the formatting functions are included without the stdio.h being +included in tasks.c. That is because this project defines its own sprintf() +functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* Assert call defined for debug builds. */ +#ifdef _DEBUG + extern void vAssertCalled( const char *pcFile, uint32_t ulLine ); + #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) +#endif /* _DEBUG */ + + + +/* Application specific definitions follow. **********************************/ + +/* Only used when running in the FreeRTOS Windows simulator. Defines the +priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet +or WiFi data to and from a real network connection. Many computers have more +than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell +the demo which real port should be used to create the virtual port. The ports +available are displayed on the console when the application is executed. For +example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 +results in the wired network being used, while setting +configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being +used. */ +#define configNETWORK_INTERFACE_TO_USE 1L + +/* The address of an echo server is only left in this project as it doubles as +the address to which logging is sent should UDP logging be enabled. */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 0 +#define configECHO_SERVER_ADDR3 11 + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet/WiFi data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition above for information on how to +configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x11 +#define configMAC_ADDR3 0x11 +#define configMAC_ADDR4 0x11 +#define configMAC_ADDR5 0x41 + +/* Default IP address configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 10 +#define configIP_ADDR1 10 +#define configIP_ADDR2 10 +#define configIP_ADDR3 200 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DNS is set to +0, or ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 10 +#define configGATEWAY_ADDR1 10 +#define configGATEWAY_ADDR2 10 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. OpenDNS addresses are 208.67.222.222 and +208.67.220.220. Used in ipconfigUSE_DNS is set to 0, or ipconfigUSE_DNS is set +to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 208 +#define configDNS_SERVER_ADDR1 67 +#define configDNS_SERVER_ADDR2 222 +#define configDNS_SERVER_ADDR3 222 + +/* Default netmask configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 0 +#define configNET_MASK2 0 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#if( defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) && !defined( snprintf ) ) + /* Map to Windows names. */ + #define snprintf _snprintf + #define vsnprintf _vsnprintf +#endif + +/* Visual studio does not have an implementation of strcasecmp(). */ +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define strcmpi _strcmpi + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); +#define configPRINTF( X ) vLoggingPrintf X + +#endif /* FREERTOS_CONFIG_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/FreeRTOSIPConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/FreeRTOSIPConfig.h new file mode 100644 index 000000000..f6985100f --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/FreeRTOSIPConfig.h @@ -0,0 +1,310 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +/***************************************************************************** + * + * See the following URL for configuration information. + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html + * + *****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to +1 then FreeRTOS_debug_printf should be defined to the function used to print +out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 0 +#if( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf(X) vLoggingPrintf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the +FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 +then FreeRTOS_printf should be set to the function used to print out the +messages. */ +#define ipconfigHAS_PRINTF 1 +#if( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf(X) vLoggingPrintf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing +on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading (IP/TCP/UDP checksums) +then set ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software +stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 + +/* Several API's will block until the result is known, or the action has been +performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be +set per socket, using setsockopt(). If not set, the times below will be +used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 2000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for LLMNR: Link-local Multicast Name Resolution +(non-Microsoft) */ +#define ipconfigUSE_LLMNR ( 0 ) + +/* Include support for NBNS: NetBIOS Name Service (Microsoft) */ +#define ipconfigUSE_NBNS ( 0 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very +useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low +and also DNS may use small timeouts. If a DNS reply comes in after the DNS +socket has been destroyed, the result will be stored into the cache. The next +call to FreeRTOS_gethostbyname() will return immediately, without even creating +a socket. */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_NAME_LENGTH ( 64 ) +#define ipconfigDNS_CACHE_ENTRIES ( 4 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make +use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY +sets the priority of the task that executes the IP stack. The priority is a +standard FreeRTOS task priority so can take any value from 0 (the lowest +priority) to (configMAX_PRIORITIES - 1) (the highest priority). +configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in +FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to +the priority assigned to the task executing the IP stack relative to the +priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP +task. This setting is less important when the FreeRTOS Win32 simulator is used +as the Win32 simulator only stores a fixed amount of information on the task +stack. FreeRTOS includes optional stack overflow detection, see: +http://www.freertos.org/Stacks-and-stack-overflow-checking.html */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* ipconfigRAND32() is called by the IP stack to generate random numbers for +things such as a DHCP transaction number or initial sequence number. Random +number generation is performed via this macro to allow applications to use their +own random number generation method. For example, it might be possible to +generate a random number by sampling noise on an analogue input. */ +extern UBaseType_t uxRand(); +#define ipconfigRAND32() uxRand() + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the +network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK +is not set to 1 then the network event hook will never be called. See +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml +*/ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but +a network buffer cannot be obtained then the calling task is held in the Blocked +state (so other tasks can continue to executed) until either a network buffer +becomes available or the send block time expires. If the send block time expires +then the send operation is aborted. The maximum allowable send block time is +capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the +maximum allowable send block time prevents prevents a deadlock occurring when +all the network buffers are in use and the tasks that process (and subsequently +free) the network buffers are themselves blocked waiting for a network buffer. +ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in +milliseconds can be converted to a time in ticks by dividing the time in +milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP +address, netmask, DNS server address and gateway address from a DHCP server. If +ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The +stack will revert to using the static IP address even when ipconfigUSE_DHCP is +set to 1 if a valid configuration cannot be obtained from a DHCP server for any +reason. The static configuration used is that passed into the stack by the +FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 1 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at +increasing time intervals until either a reply is received from a DHCP server +and accepted, or the interval between transmissions reaches +ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the +static IP address passed as a parameter to FreeRTOS_IPInit() if the +re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without +a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( 120000 / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP +stack can only send a UDP message to a remove IP address if it knowns the MAC +address associated with the IP address, or the MAC address of the router used to +contact the remote IP address. When a UDP message is received from a remote IP +address the MAC address and IP address are added to the ARP cache. When a UDP +message is sent to a remote IP address that does not already appear in the ARP +cache then the UDP message is replaced by a ARP message that solicits the +required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum +number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a +maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is +aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP +table being created or refreshed and the entry being removed because it is stale. +New ARP requests are sent for ARP cache entries that are nearing their maximum +age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is +equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling +routines, which are relatively large. To save code space the full +FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster +alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() +takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. +FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets +(for example, 192, 168, 0, 1) as its parameters. If +ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and +FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is +not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that +are available to the IP stack. The total number of network buffers is limited +to ensure the total amount of RAM that can be consumed by the IP stack is capped +to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP +stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can +be queued for processing at any one time. The event queue must be a minimum of +5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port +number. FreeRTOS_bind() is used to manually allocate a port number to a socket +(to 'bind' the socket to a port), but manual binding is not normally necessary +for client sockets (those sockets that initiate outgoing connections rather than +wait for incoming connections on a known port number). If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling +FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP +stack automatically binding the socket to a port number from the range +socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() +on a socket that has not yet been bound will result in the send operation being +aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +#define ipconfigTCP_TIME_TO_LIVE 128 /* also defined in FreeRTOSIPConfigDefaults.h */ + +/* USE_TCP: Use TCP and all its features */ +#define ipconfigUSE_TCP ( 1 ) + +/* Use the TCP socket wake context with a callback. */ +#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT ( 1 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can +contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a +lower value can save RAM, depending on the buffer management scheme used. If +ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must +be divisible by 8. */ +#define ipconfigNETWORK_MTU 1200 + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used +through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will +generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the +FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 0 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() +(and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames +that are not in Ethernet II format will be dropped. This option is included for +potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the +responsibility of the Ethernet interface to filter out packets that are of no +interest. If the Ethernet interface does not implement this functionality, then +set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack +perform the filtering instead (it is much less efficient for the stack to do it +because the packet will already have been passed into the stack). If the +Ethernet driver does all the necessary filtering in hardware then software +filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to +block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with +32-bit memory instructions, all packets will be stored 32-bit-aligned, plus 16-bits. +This has to do with the contents of the IP-packets: all 32-bit fields are +32-bit-aligned, plus 16-bit(!) */ +#define ipconfigPACKET_FILLER_SIZE 2 + +/* Define the size of the pool of TCP window descriptors. On the average, each +TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 +outstanding packets (for Rx and Tx). When using up to 10 TP sockets +simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed +maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 1000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 1000 ) + +/* When using call-back handlers, the driver may check if the handler points to +real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS(x) ( (x) != NULL ) + +/* Include support for TCP hang protection. All sockets in a connecting or +disconnecting stage will timeout after a period of non-activity. */ +#define ipconfigTCP_HANG_PROTECTION ( 1 ) +#define ipconfigTCP_HANG_PROTECTION_TIME ( 30 ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* in seconds */ + +#define portINLINE __inline + +#endif /* FREERTOS_IP_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/READ_ME_INSTRUCTIONS.url b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/READ_ME_INSTRUCTIONS.url new file mode 100644 index 000000000..6c689ef14 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/READ_ME_INSTRUCTIONS.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/https/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/WIN32.vcxproj b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/WIN32.vcxproj new file mode 100644 index 000000000..52ea745a5 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/WIN32.vcxproj @@ -0,0 +1,618 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {C686325E-3261-42F7-AEB1-DDE5280E1CEB} + RTOSDemo + 10.0 + + + + Application + false + MultiByte + v142 + + + Application + false + MultiByte + v142 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Debug\ + .\Debug\ + true + .\Release\ + .\Release\ + false + AllRules.ruleset + + + + .\Debug/WIN32.tlb + + + + + Disabled + ..\..\include;..\common;..\common\WinPCap;..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\src;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\http-parser;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\mbedtls;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\platform;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\https\include;..\..\..\..\Source\mbedtls\include;.;%(AdditionalIncludeDirectories) + MBEDTLS_CONFIG_FILE="mbedtls_config.h";WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDLL + .\Debug/WIN32.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level4 + true + false + EditAndContinue + /wd4210 /wd4127 /wd4214 /wd4201 /wd4244 /wd4310 /wd4200 %(AdditionalOptions) + true + NotUsing + false + CompileAsC + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Debug/RTOSDemo.exe + true + true + .\Debug/WIN32.pdb + Console + MachineX86 + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + ..\common\WinPCap + false + false + + + true + .\Debug/WIN32.bsc + + + + + .\Release/WIN32.tlb + + + + + MaxSpeed + OnlyExplicitInline + MBEDTLS_CONFIG_FILE="mbedtls_config.h";_WINSOCKAPI_;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release/WIN32.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + ..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;.\DemoTasks\include;.\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\src;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\mbedtls;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\platform;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\https\include;..\..\..\..\Source\mbedtls\include;.;%(AdditionalIncludeDirectories) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Release/RTOSDemo.exe + true + .\Release/WIN32.pdb + Console + MachineX86 + .\WinPCap + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + + + true + .\Release/WIN32.bsc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/WIN32.vcxproj.filters b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/WIN32.vcxproj.filters new file mode 100644 index 000000000..beb540627 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/WIN32.vcxproj.filters @@ -0,0 +1,786 @@ + + + + + {af3445a1-4908-4170-89ed-39345d90d30c} + + + {f32be356-4763-4cae-9020-974a2638cb08} + *.c + + + {88f409e6-d396-4ac5-94bd-7a99c914be46} + + + {e5ad4ec7-23dc-4295-8add-2acaee488f5a} + + + {d2dcd641-8d91-492b-852f-5563ffadaec6} + + + {8672fa26-b119-481f-8b8d-086419c01a3e} + + + {4570be11-ec96-4b55-ac58-24b50ada980a} + + + {5d93ed51-023a-41ad-9243-8d230165d34b} + + + {b71e974a-9f28-4815-972b-d930ba8a34d0} + + + {60717407-397f-4ea5-8492-3314acdd25f0} + + + {8a90222f-d723-4b4e-8e6e-c57afaf7fa92} + + + {7c995f05-2a10-4771-ad77-18a755876e46} + + + {9a636cc3-ebc6-48c5-8c18-c72494686e81} + + + {29376c48-bc8b-4624-ad59-16807874c9f2} + + + {91ef4008-de51-4b41-ba5e-bf24d8cda378} + + + {ade43c6c-04c5-4897-abdb-91af2df04e5d} + + + {08a4e35c-19ca-4b1e-af24-bac368c2bf7b} + + + {1e324500-91b4-4c76-b699-59ba75691760} + + + {bdcbc1ec-99b8-4c72-9075-49035c115488} + + + {2d17d5e6-ed70-4e42-9693-f7a63baf4948} + + + {7158b0be-01e7-42d1-8d3f-c75118a596a2} + + + {6ad56e6d-c330-4830-8f4b-c75b05dfa866} + + + {1d80b387-5a86-4744-a4cc-930033a52e4b} + + + {3dc958a5-cd64-4a6a-af27-beba20339e4b} + + + {1cecca7f-60cd-4d8d-8123-f00aa75af147} + + + {f9a2e0a1-ed56-4ca7-b8b2-d694a94c78c0} + + + {61ac8e2c-8fd1-44a0-a7a9-0326bc190426} + + + {b53bfe50-b4d9-4b78-b7bb-ae90e4d25615} + + + {d5bf72d9-1e71-4a65-ac2f-5f28a99b0796} + + + {b0616e09-2c08-40a1-aa2d-5cbd592e4451} + + + {f1ad002c-d40b-465f-b648-17cedba667d1} + + + + + FreeRTOS\Source\Portable + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS\Source + + + FreeRTOS\Source\Portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\https\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\https\src + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\http-parser + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\mbedtls + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + + + DemoTasks + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\https\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\https\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos\include\platform + + + FreeRTOS+\http-parser + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\mbedtls + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/demo_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/demo_config.h new file mode 100644 index 000000000..1e286386b --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/demo_config.h @@ -0,0 +1,78 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef DEMO_CONFIG_H +#define DEMO_CONFIG_H + +/* + * This configuration file determines how the HTTPS demo is run. + * + * http_plain_text demo: Security is turned off. Preconfigured to a public HTTP + * host on unencrypted port so no authentication configuration is required. + * + * https_basic_tls_server_auth demo: TLS security is enabled, allowing host + * side authentication. Preconfigured to a public HTTPS host with certificate + * provided by the host so no authentication configuration is required. + * + * https_tls_mutual_auth demo: Mutual authentication is enabled. Preconfigured to + * AWS IoT broker, will require certificate setup for successful connection. + */ + +/** + * @brief Enable/Disable TLS in demos. + * + * For more information regarding TLS protocol: + * https://www.freertos.org/https/tls.html + */ +#define democonfigENABLE_TLS 1 + +/** + * @brief Enable/Disable mutual authentication in demos. If enabled, require + * democonfigENABLE_TLS to be set to 1. + */ +#define democonfigENABLE_MUTUAL_AUTH 1 + +/** + * @brief Select a connection profile. + * + * If set to 1, the demo will connect to AWS IoT with credential setup in + * aws_iot_demo_profile.h file, otherwise the demo is preconfigured to connect to + * httpbin.org with credential setup in https_demo_profile.h file. If enabled, + * requires democonfigENABLE_MUTUAL_AUTH to be set to 1 since AWS IoT requires + * mutually authenticated connection. + */ +#define democonfigPROFILE_USE_AWS_IOT 1 + +/** + * @brief Set the stack size of the main demo task. + * + * In the Windows port, this stack only holds a structure. The actual + * stack is created by an operating system thread. + */ +#define democonfigDEMO_STACKSIZE configMINIMAL_STACK_SIZE + +#endif /* DEMO_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/https_tls_mutual_auth_demo.sln b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/https_tls_mutual_auth_demo.sln new file mode 100644 index 000000000..b362f36c5 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/https_tls_mutual_auth_demo.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTOSDemo", "WIN32.vcxproj", "{C686325E-3261-42F7-AEB1-DDE5280E1CEB}" +EndProject +Global + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = FreeRTOS_Plus_TCP_Minimal.vsmdi + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.ActiveCfg = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.Build.0 = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.ActiveCfg = Release|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/iot_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/iot_config.h new file mode 100644 index 000000000..0666b8f7e --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/https_tls_mutual_auth/iot_config.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/* This file contains configuration settings for the demos. */ + +#ifndef IOT_CONFIG_H_ +#define IOT_CONFIG_H_ + +/* Configure the IoT Libraries for FreeRTOS by including the FreeRTOS header and + * the FreeRTOS platform types. */ +#include "FreeRTOS.h" +#include "platform/iot_platform_types_freertos.h" + +/** + * @brief Set a global default for log levels. + * + * This setting is overridden by log level settings of specific libraries. + * Undefined library-specific log levels will default to this value. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_GLOBAL IOT_LOG_NONE + +/** + * @brief Set the log level of the platform libraries except the network + * component. + * + * Log messages from the platform libraries at or below this setting + * will be printed. As the network component is more verbose, its logging + * is controlled by its own setting, IOT_LOG_LEVEL_NETWORK. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_PLATFORM IOT_LOG_NONE + +/** + * @brief Set the log level of the platform network library. + * + * Log messages from the platform network library at or below this setting + * will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_NETWORK IOT_LOG_WARN + +/* + * @brief Set the log level of the task pool library. + * + * Log messages from the task pool library at or below this setting will be + * printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_TASKPOOL IOT_LOG_WARN + +/** + * @brief Set the log level of the HTTPS Client library. + * + * Log messages from the HTTPS Client library at or below this setting will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_HTTPS IOT_LOG_WARN + +/** + * @brief Enable/Disable asserts for the task pool library. + * + * Set this to 1 to perform sanity checks when using the task pool library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotTaskPool_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_TASKPOOL_ENABLE_ASSERTS 1 + +/** + * @brief The number of worker tasks in the task pool. + * + * The full IoT Task Pool Library has many use cases, including Linux + * development. Typical FreeRTOS use cases do not require the full + * functionality so an optimized implementation is provided specifically for use + * with FreeRTOS. The optimized version has a fixed number of tasks in the + * task pool, each of which uses statically allocated memory to ensure creation + * of the task pool is guaranteed (it does not run out of heap space). + */ +#define IOT_TASKPOOL_NUMBER_OF_WORKERS 1 + +/** + * @brief The stack size (in bytes) for each worker task in the task pool. + * + * The minimal version of the of task pool library only supports one task pool + * and the configuration of each worker task fixed at the compile time. + */ +#define IOT_TASKPOOL_WORKER_STACK_SIZE_BYTES 2048 + +/** + * @brief Enable TLS in the network abstraction. + * + * The TLS implementation requires the mbed TLS library. + */ +#define IOT_NETWORK_ENABLE_TLS 1 + +/** + * @brief Enable/Disable asserts for the linear containers library. + * + * Set this to 1 to perform sanity checks when using the linear containers library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotContainers_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_CONTAINERS_ENABLE_ASSERTS 1 + +/* Common settings for FreeRTOS; settings below this line generally do not need + * to be changed. */ + +/* Logging puts function on FreeRTOS. */ +#define IotLogging_Puts( str ) configPRINTF( ( "%s\r\n", str ) ) + +/* Assert functions on FreeRTOS. */ +#define IotContainers_Assert( expression ) configASSERT( expression ) +#define IotTaskPool_Assert( expression ) configASSERT( expression ) + +/* Memory allocation functions on FreeRTOS. */ +#define IotThreads_Malloc pvPortMalloc +#define IotThreads_Free vPortFree + +#define IotLogging_Malloc pvPortMalloc +#define IotLogging_Free vPortFree + +#define IotTaskPool_MallocTaskPool pvPortMalloc +#define IotTaskPool_FreeTaskPool vPortFree +#define IotTaskPool_MallocJob pvPortMalloc +#define IotTaskPool_FreeJob vPortFree +#define IotTaskPool_MallocTimerEvent pvPortMalloc +#define IotTaskPool_FreeTimerEvent vPortFree + +#endif /* ifndef IOT_CONFIG_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/readme.txt b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/readme.txt new file mode 100644 index 000000000..e3e15fa33 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https/readme.txt @@ -0,0 +1,24 @@ +See https://freertos.org/https/ for further information. + +Contains projects that demonstrate the IoT HTTPS library. + +- Securing HTTPS Communication - +The Hypertext Transfer Protocol (HTTP) is a widely used protocol for application +such as home media to interact with web servers. The Hypertext Transfer Protocol +Secure (HTTPS) is an extension to HTTP, adding secure element to the connection. +HTTPS is encrypted with Transport Layer Security (TLS), which also requires server +authentication. In addition to server authentication, mutual authentication +authenticates the identity of both the server and the client. + +- Pre-configured HTTPS Example Projects - +The examples contained in subdirectories from here demonstrate the concepts +described above one at a time. The first example demonstrates plain text +HTTP (insecure) communication, the second example builds on the first to +introduce weak server authentication, and the third example builds on the second to +introduce strong mutual authentication. Note: It is our recommendation to always +use strong mutual authentication in any Internet of Things (IoT) application. The +plain text project is only provided to validate HTTP communication can be +established prior to introducing encryption and authentication, and to allow the +HTTP packets to be observed using a network packet sniffer such as Wireshark for +those who wish to do so. The first two projects are in no way intended to be +examples suitable for production use. diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/aws_iot_demo_profile.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/aws_iot_demo_profile.h new file mode 100644 index 000000000..c4a3e1a58 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/aws_iot_demo_profile.h @@ -0,0 +1,133 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * IMPORTANT, CONFIGURATION REQUIRED: This is a configuration file containing AWS + * IoT profile for the demos, will need additional setup: + * https://www.freertos.org/mqtt/preconfiguredexamplesMA.html + * + * Each profile corresponds to a different service. The demos that use the same + * profile share the same service. It is important to understand the + * correspondence between the preconfigured profiles and demos, since each + * service have different connection configuration and credential validation. + * + * - mqtt_demo_profile.h is preconfigured to test.mosquitto.org MQTT broker. + * The file is used with mqtt_plain_text demo and mqtt_basic_tls_server_auth + * demo. Feel free to try out other broker with the demos. + * + * - https_demo_profile.h is preconfigured to httpbin.org server. The file is + * used with http_plain_text demo and https_basic_tls_server_auth demo. + * + * - aws_iot_demo_profile.h (current) contains information to connect to AWS + * IoT. The file is used with mqtt_tls_mutual_auth demo, https_tls_mutual_auth + * demo, and other AWS IoT related demo. + */ + +#ifndef AWS_IOT_DEMO_PROFILE_H +#define AWS_IOT_DEMO_PROFILE_H + +/** + * @brief Details of the MQTT broker to connect to. + * + * This is the Thing's Rest API Endpoint for AWS IoT. + * + * #define awsiotdemoprofileAWS_ENDPOINT "...insert here..." + */ + +/** + * @brief The port to use for the MQTT demo. + * + * Use 8883 if connecting to AWS IoT services. + */ +#define awsiotdemoprofileAWS_MQTT_PORT 8883 + +/** + * @brief The port to use for the HTTPS demo. + * + * Use 8443 if connecting to AWS IoT services. + */ +#define awsiotdemoprofileAWS_HTTPS_PORT 8443 + +/** + * @brief The AWS IoT server certificate. + * + * This certificate is used to identify the AWS IoT server and is publicly + * available. + */ +#define awsiotdemoprofileAWS_CERTIFICATE_PEM \ + "-----BEGIN CERTIFICATE-----\n" \ + "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n" \ + "ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n" \ + "b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n" \ + "MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n" \ + "b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n" \ + "ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n" \ + "9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n" \ + "IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n" \ + "VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n" \ + "93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n" \ + "jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n" \ + "AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n" \ + "A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n" \ + "U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n" \ + "N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n" \ + "o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n" \ + "5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n" \ + "rqXRfboQnoZsG4q5WTP468SQvvG5\n" \ + "-----END CERTIFICATE-----\n" + +/** + * @brief The MQTT client identifier. + * + * This is the "Thing Name" in AWS IoT. + * + * #define awsiotdemoprofileCLIENT_IDENTIFIER "...insert here..." + */ + +/** + * @brief PEM-encoded client certificate + * + * Must include the PEM header and footer: + * "-----BEGIN CERTIFICATE-----\n"\ + * "...base64 data...\n"\ + * "-----END CERTIFICATE-----\n" + * + * #define awsiotdemoprofileCLIENT_CERTIFICATE_PEM "...insert here..." + */ + +/** + * @brief PEM-encoded client private key. + * + * Must include the PEM header and footer: + * "-----BEGIN RSA PRIVATE KEY-----\n"\ + * "...base64 data...\n"\ + * "-----END RSA PRIVATE KEY-----\n" + * + * #define awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM "...insert here..." + */ + +#endif /* AWS_IOT_DEMO_PROFILE_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/aws_iot_setup_check.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/aws_iot_setup_check.h new file mode 100644 index 000000000..0fefe0305 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/aws_iot_setup_check.h @@ -0,0 +1,79 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * This file performs the configuration check at preprocessor time to make sure + * the credentials are defined. If credentials are not set, users will + * immediately be guided to the getting started documentation for proper setup. + * + * This is meant to be included after the credential define. + * e.g., a .c file that establishes a MQTT connection: + * #include "aws_iot_demo_profile.h" // This file includes the credential for user to define + * #include "aws_iot_setup_check.h" // This file make sure credentials are defined + */ + +#ifndef IOT_CONFIGCHECK_H +#define IOT_CONFIGCHECK_H + +/* + * TLS is enabled by default. This is config to zero for *_plain_text demo. + */ +#ifndef democonfigENABLE_TLS + #define democonfigENABLE_TLS 1 +#endif + +/* + * Mutual authentication is enabled by default. This is config to zero for + * *_plain_text and *_basic_tls_server demo. + */ +#ifndef democonfigENABLE_MUTUAL_AUTH + #define democonfigENABLE_MUTUAL_AUTH 1 +#endif + +/* + * Credential setup check. + */ +#if defined( AWS_IOT_DEMO_PROFILE_H ) + #ifndef awsiotdemoprofileAWS_ENDPOINT + #error ACTION REQUIRED: Please ensure you have awsiotdemoprofileAWS_ENDPOINT (in aws_iot_demo_profile.h) configured. Refer to https://www.freertos.org/mqtt/preconfiguredexamplesMA.html for proper setup. + #endif + #ifndef awsiotdemoprofileCLIENT_IDENTIFIER + #error ACTION REQUIRED: Please ensure you have awsiotdemoprofileCLIENT_IDENTIFIER (in aws_iot_demo_profile.h) configured. Refer to https://www.freertos.org/mqtt/preconfiguredexamplesMA.html for proper setup. + #endif + #if ( democonfigENABLE_TLS ) + #if ( democonfigENABLE_MUTUAL_AUTH ) + #ifndef awsiotdemoprofileCLIENT_CERTIFICATE_PEM + #error ACTION REQUIRED: Please ensure you have awsiotdemoprofileCLIENT_CERTIFICATE_PEM (in aws_iot_demo_profile.h) configured as required for mutual authentication. https://www.freertos.org/mqtt/preconfiguredexamplesMA.html for proper setup. + #endif + #ifndef awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM + #error ACTION REQUIRED: Please ensure you have awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM (in aws_iot_demo_profile.h) configured as required for mutual authentication. https://www.freertos.org/mqtt/preconfiguredexamplesMA.html for proper setup. + #endif + #endif + #endif /* if ( democonfigENABLE_TLS ) */ +#endif /* if defined( AWS_IOT_DEMO_PROFILE_H ) */ + +#endif /* IOT_CONFIGCHECK_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/https_demo_profile.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/https_demo_profile.h new file mode 100644 index 000000000..8ef81df01 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/https_demo_profile.h @@ -0,0 +1,103 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * Each profile corresponds to a different service. The demos that use the same + * profile share the same service. It is important to understand the + * correspondence between the preconfigured profiles and demos, since each + * service have different connection configuration and credential validation. + * + * - mqtt_demo_profile.h is preconfigured to test.mosquitto.org MQTT broker. + * The file is used with mqtt_plain_text demo and mqtt_basic_tls_server_auth + * demo. Feel free to try out other broker with the demos. + * + * - https_demo_profile.h (current) is preconfigured to httpbin.org server. + * The file is used with http_plain_text demo and https_basic_tls_server_auth + * demo. + * + * - aws_iot_demo_profile.h contains information to connect to AWS + * IoT. The file is used with mqtt_tls_mutual_auth demo, https_tls_mutual_auth + * demo, and other AWS IoT related demo. + */ + +#ifndef HTTPS_DEMO_PROFILE_H +#define HTTPS_DEMO_PROFILE_H + +#include "demo_config.h" + +/** + * @brief Details of the HTTPS server to connect to. + * + * Please note that many web servers will close the connection immediately after + * sending the response in order to save resources. This demo is compatible only + * with a server that persists the connection after sending a response. + * + * Port 443 is the standard port designated for encrypted HTTPS traffic. + */ +#define httpsdemoprofileSERVER_ADDRESS "httpbin.org" + + +#if ( democonfigENABLE_TLS ) + #define httpsdemoprofileSERVER_PORT 443 +#else + #define httpsdemoprofileSERVER_PORT 80 +#endif + +/** + * @brief The server certificate for httpbin.org:443. + * + * This certificate is obtained from https://httpbin.org/ and is used to + * authenticate the HTTPS server. This demo only authenticates the server and + * does not authenticate the client. + * + * If you want to connect to any other HTTPS server other than httpbin.org, + * replace it with the certificate of the HTTPS server. + */ +#define httpsdemoprofileSERVER_CERTIFICATE_PEM \ + "-----BEGIN CERTIFICATE-----\n" \ + "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n" \ + "ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n" \ + "b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n" \ + "MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n" \ + "b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n" \ + "ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n" \ + "9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n" \ + "IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n" \ + "VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n" \ + "93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n" \ + "jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n" \ + "AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n" \ + "A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n" \ + "U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n" \ + "N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n" \ + "o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n" \ + "5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n" \ + "rqXRfboQnoZsG4q5WTP468SQvvG5\n" \ + "-----END CERTIFICATE-----\n" + + +#endif /* ifndef HTTPS_DEMO_PROFILE_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/mqtt_demo_profile.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/mqtt_demo_profile.h new file mode 100644 index 000000000..40b5a9773 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include/mqtt_demo_profile.h @@ -0,0 +1,114 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * Each profile corresponds to a different service. The demos that use the same + * profile share the same service. It is important to understand the + * correspondence between the preconfigured profiles and demos, since each + * service have different connection configuration and credential validation. + * + * - mqtt_demo_profile.h (current) is preconfigured to test.mosquitto.org MQTT + * broker. The file is used with mqtt_plain_text demo and + * mqtt_basic_tls_server_auth demo. Feel free to try out other broker with the + * demos. + * + * - https_demo_profile.h is preconfigured to httpbin.org server. The file is + * used with http_plain_text demo and https_basic_tls_server_auth demo. + * + * - aws_iot_demo_profile.h contains information to connect to AWS + * IoT. The file is used with mqtt_tls_mutual_auth demo, https_tls_mutual_auth + * demo, and other AWS IoT related demo. + */ + +#ifndef MQTT_DEMO_PROFILE_H +#define MQTT_DEMO_PROFILE_H + +#include "demo_config.h" + +/** + * @brief Details of the MQTT broker to connect to. + * + * The Mosquitto test server provides a freely available MQTT server that can + * be used to test MQTT clients. + */ +#define mqttdemoprofileBROKER_ENDPOINT "test.mosquitto.org" + +/** + * @brief The port to use for the demo. + * + * If trying to connect to Mosquitto test broker (the default broker), use + * port 1883 for unencrypted MQTT traffic and port 8883 for encrypted MQTT + * traffic. These are also standard MQTT ports, but consult broker + * setting for the actual port. + */ +#if ( democonfigENABLE_TLS == 1 ) + #define mqttdemoprofileBROKER_PORT 8883 +#else + #define mqttdemoprofileBROKER_PORT 1883 +#endif + +/** + * @brief The topic to subscribe and publish to in the example. + * + * The topic starts with the client identifier to ensure that each demo interacts + * with a unique topic. + */ +#define mqttdemoprofileCLIENT_IDENTIFIER "mqttexampleclient" + +/** + * @brief The server certificate for test.mosquitto.org:8883. + * + * This certificate is obtained from https://test.mosquitto.org/ and is used + * to authenticate the Mosquitto MQTT broker. This demo only authenticates + * the server and does not authenticate the client. This is a RSA SHA-1 + * certificate which is not considered secure for production use cases as + * per the industry standards. + * + * If you want to connect to any other MQTT broker other than + * test.mosquitto.org, replace it with the certificate of the MQTT broker. + */ +#define mqttdemoprofileBROKER_CERTIFICATE_PEM \ + "-----BEGIN CERTIFICATE-----\n" \ + "MIIC8DCCAlmgAwIBAgIJAOD63PlXjJi8MA0GCSqGSIb3DQEBBQUAMIGQMQswCQYD\n" \ + "VQQGEwJHQjEXMBUGA1UECAwOVW5pdGVkIEtpbmdkb20xDjAMBgNVBAcMBURlcmJ5\n" \ + "MRIwEAYDVQQKDAlNb3NxdWl0dG8xCzAJBgNVBAsMAkNBMRYwFAYDVQQDDA1tb3Nx\n" \ + "dWl0dG8ub3JnMR8wHQYJKoZIhvcNAQkBFhByb2dlckBhdGNob28ub3JnMB4XDTEy\n" \ + "MDYyOTIyMTE1OVoXDTIyMDYyNzIyMTE1OVowgZAxCzAJBgNVBAYTAkdCMRcwFQYD\n" \ + "VQQIDA5Vbml0ZWQgS2luZ2RvbTEOMAwGA1UEBwwFRGVyYnkxEjAQBgNVBAoMCU1v\n" \ + "c3F1aXR0bzELMAkGA1UECwwCQ0ExFjAUBgNVBAMMDW1vc3F1aXR0by5vcmcxHzAd\n" \ + "BgkqhkiG9w0BCQEWEHJvZ2VyQGF0Y2hvby5vcmcwgZ8wDQYJKoZIhvcNAQEBBQAD\n" \ + "gY0AMIGJAoGBAMYkLmX7SqOT/jJCZoQ1NWdCrr/pq47m3xxyXcI+FLEmwbE3R9vM\n" \ + "rE6sRbP2S89pfrCt7iuITXPKycpUcIU0mtcT1OqxGBV2lb6RaOT2gC5pxyGaFJ+h\n" \ + "A+GIbdYKO3JprPxSBoRponZJvDGEZuM3N7p3S/lRoi7G5wG5mvUmaE5RAgMBAAGj\n" \ + "UDBOMB0GA1UdDgQWBBTad2QneVztIPQzRRGj6ZHKqJTv5jAfBgNVHSMEGDAWgBTa\n" \ + "d2QneVztIPQzRRGj6ZHKqJTv5jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUA\n" \ + "A4GBAAqw1rK4NlRUCUBLhEFUQasjP7xfFqlVbE2cRy0Rs4o3KS0JwzQVBwG85xge\n" \ + "REyPOFdGdhBY2P1FNRy0MDr6xr+D2ZOwxs63dG1nnAnWZg7qwoLgpZ4fESPD3PkA\n" \ + "1ZgKJc2zbSQ9fCPxt2W3mdVav66c6fsb7els2W2Iz7gERJSX\n" \ + "-----END CERTIFICATE-----\n" + +#endif /* ifndef MQTT_DEMO_PROFILE_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/DemoTasks/JobsNotifyNextExamples.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/DemoTasks/JobsNotifyNextExamples.c new file mode 100644 index 000000000..89d36a482 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/DemoTasks/JobsNotifyNextExamples.c @@ -0,0 +1,1079 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* This demo executes Jobs obtained from AWS IoT. An AWS IoT Job is used to define + * a set of remote operations that are sent to and executed on one or more devices + * connected to AWS IoT. Please refer to AWS documentation for more information + * about AWS IoT Jobs. + * https://docs.aws.amazon.com/iot/latest/developerguide/iot-jobs.html + * + * This demo creates a single application task that sets a callback for the + * jobs/notify-next topic and executes Jobs created from the AWS IoT console or AWS + * CLI. Please refer to AWS CLI documentation for more information in creating a + * Job document. + * https://docs.aws.amazon.com/cli/latest/reference/iot/create-job.html + * + * This demo expects Job documents to have an "action" JSON key. Actions can + * be one "print", "publish", or "exit". + * Print Jobs log a message to the local console, and must contain a "message", + * e.g. { "action": "print", "message": "Hello World!" }. + * Publish Jobs publish a message to an MQTT Topic. The Job document must + * contain a "message" and "topic" to publish to, e.g. + * { "action": "publish", "topic": "demo/jobs", "message": "Hello World!" }. + * The exit Job exits the demo. Sending { "action": "exit" } will end the program. + */ + +/* Standard includes. */ +#include +#include + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" + +/* IoT SDK includes. */ +#include "aws_iot_jobs.h" +#include "aws_iot_demo_profile.h" +#include "iot_mqtt.h" +#include "iot_taskpool_freertos.h" +#include "aws_iot_doc_parser.h" +#include "platform/iot_clock.h" +#include "platform/iot_threads.h" +#include "platform/iot_network_freertos.h" + +#include "atomic.h" + +/* Preprocessor check iot configuration. */ +#include "aws_iot_setup_check.h" + +/* Demo specific includes. */ +#include "demo_config.h" + +/*-----------------------------------------------------------*/ + +/** + * @brief The keep-alive interval used for this example. + * + * An MQTT ping request will be sent periodically at this interval. + * + * @note: This value is set to zero to disable MQTT + * keep alive for the Windows simulator project. + * The FreeRTOS kernel does not accurately calculate time for the Windows + * Simulator. Therefore, MQTT PING Request messages may be sent + * at an incorrect time interval to the broker. If the broker does + * not receive a ping request within 1.5x the time sent in a + * connection request, the broker may close the connection. + * To enable the keep alive feature, set this value + * to the desired interval in seconds. + */ +#define jobsexampleKEEP_ALIVE_SECONDS ( 0 ) + +/** + * @brief The timeout for MQTT operations in this example. + */ +#define jobsexampleMQTT_TIMEOUT_MS ( 5000 ) + +/** + * @brief Use default timeout when calling AwsIotJobs_Init. + */ +#define jobsexampleUSE_DEFAULT_MQTT_TIMEOUT ( 0 ) + +/** + * @brief The bit which is set in the demo task's notification value from the + * disconnect callback to inform the demo task about the MQTT disconnect. + */ +#define jobsexampleDISCONNECTED_BIT ( 1UL << 0UL ) + +/** + * @brief The bit which is set in the demo task's notification value from the + * operation complete callback to inform the demo task to exit. + */ +#define jobsexampleEXIT_BIT ( 1UL << 1UL ) + +/** + * @brief Length of the client identifier for this demo. + */ +#define jobsexampleCLIENT_IDENTIFIER_LENGTH ( sizeof( awsiotdemoprofileCLIENT_IDENTIFIER ) - 1 ) + +/** + * @brief The JSON key of the Job ID. + * + * Job documents are in JSON documents received from the AWS IoT Jobs service. + * All such JSON documents will contain this key, whose value represents the unique + * identifier of a Job. + */ +#define jobsexampleID_KEY "jobId" + +/** + * @brief The length of #jobsexampleID_KEY. + */ +#define jobsexampleID_KEY_LENGTH ( sizeof( jobsexampleID_KEY ) - 1 ) + +/** + * @brief The JSON key of the Job document. + * + * Job documents are in JSON documents received from the AWS IoT Jobs service. + * All such JSON documents will contain this key, whose value is an application-specific + * Job document. + */ +#define jobsexampleDOC_KEY "jobDocument" + +/** + * @brief The length of #jobsexampleDOC_KEY. + */ +#define jobsexampleDOC_KEY_LENGTH ( sizeof( jobsexampleDOC_KEY ) - 1 ) + +/** + * @brief The JSON key whose value represents the action this demo should take. + * + * This demo program expects this key to be in the Job document. It is a key + * specific to this demo. + */ +#define jobsexampleACTION_KEY "action" + +/** + * @brief The length of #jobsexampleACTION_KEY. + */ +#define jobsexampleACTION_KEY_LENGTH ( sizeof( jobsexampleACTION_KEY ) - 1 ) + +/** + * @brief A message associated with the Job action. + * + * This demo program expects this key to be in the Job document if the "action" + * is either "publish" or "print". It represents the message that should be + * published or printed, respectively. + */ +#define jobsexampleMESSAGE_KEY "message" + +/** + * @brief The length of #jobsexampleMESSAGE_KEY. + */ +#define jobsexampleMESSAGE_KEY_LENGTH ( sizeof( jobsexampleMESSAGE_KEY ) - 1 ) + +/** + * @brief An MQTT topic associated with the Job "publish" action. + * + * This demo program expects this key to be in the Job document if the "action" + * is "publish". It represents the MQTT topic on which the message should be + * published. + */ +#define jobsexampleTOPIC_KEY "topic" + +/** + * @brief The length of #jobsexampleTOPIC_KEY. + */ +#define jobsexampleTOPIC_KEY_LENGTH ( sizeof( jobsexampleTOPIC_KEY ) - 1 ) + +/** + * @brief The minimum length of a string in a JSON Job document. + * + * At the very least the Job ID must have the quotes that identify it as a JSON + * string and 1 character for the string itself (the string must not be empty). + */ +#define jobsexampleJSON_STRING_MIN_LENGTH ( ( size_t ) 3 ) + +/** + * @brief The maximum length of a Job ID. + * + * This limit is defined by AWS service limits. See the following page for more + * information. + * + * https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html#job-limits + */ +#define jobsexampleID_MAX_LENGTH ( ( size_t ) 64 ) + +/** + * @brief A value passed as context to #prvOperationCompleteCallback to specify that + * it should notify the demo task of an exit request. + */ +#define jobsexampleSHOULD_EXIT ( ( void * ) ( ( intptr_t ) 1 ) ) + +/** + * @brief Time to wait before exiting demo. + * + * The milliseconds to wait before exiting. This is because the MQTT Broker + * will disconnect us if we are idle too long, and we have disabled keep alive. + */ +#define jobsexampleMS_BEFORE_EXIT ( 10 * 60 * 1000 ) + +/*-----------------------------------------------------------*/ + +/** + * @brief Currently supported actions that a Job document can specify. + */ +typedef enum _jobAction +{ + JOB_ACTION_PRINT, /**< Print a message. */ + JOB_ACTION_PUBLISH, /**< Publish a message to an MQTT topic. */ + JOB_ACTION_EXIT, /**< Exit the demo. */ + JOB_ACTION_UNKNOWN /**< Unknown action. */ +} _jobAction_t; + +/** + * @brief The task used to demonstrate Jobs. + * + * @param[in] pvParameters Parameters as passed at the time of task creation. Not + * used in this example. + */ +static void prvJobsDemoTask( void * pvParameters ); + +/** + * @brief The callback invoked by the MQTT library when the MQTT connection gets + * disconnected. + * + * @param[in] pvCallbackContext Callback context as provided at the time of + * connect. + * @param[in] pxCallbackParams Contains the reason why the MQTT connection was + * disconnected. + */ +static void prvExample_OnDisconnect( void * pvCallbackContext, + IotMqttCallbackParam_t * pxCallbackParams ); + +/** + * @brief Connects to the MQTT broker as specified in awsiotdemoprofileAWS_ENDPOINT + * and awsiotdemoprofileAWS_MQTT_PORT. + */ +static void prvMQTTConnect( void ); + +/** + * @brief Disconnects from the MQTT broker gracefully by sending an MQTT + * DISCONNECT message. + */ +static void prvMQTTDisconnect( void ); + +/** + * @brief Set callback for publishes to the jobs/notify-next topic. + */ +static void prvSetNotifyNextCallback( void ); + +/** + * @brief Converts a string in a Job document to a #_jobAction_t. + * + * @param[in] pcAction The Job action as a string. + * @param[in] xActionLength The length of `pcAction`. + * + * @return A #_jobAction_t equivalent to the given string. + */ +static _jobAction_t prvGetAction( const char * pcAction, + size_t xActionLength ); + +/** + * @brief Extracts a JSON string from the Job document. + * + * @param[in] pcJsonDoc The JSON document to search. + * @param[in] xJsonDocLength Length of `pcJsonDoc`. + * @param[in] pcKey The JSON key to search for. + * @param[in] xKeyLength Length of `pcKey`. + * @param[out] ppcValue The extracted JSON value. + * @param[out] pxValueLength Length of ppcValue. + * + * @return `pdTRUE` if the key was found and the value is valid; `pdFALSE` otherwise. + */ +static BaseType_t prvGetJsonString( const char * pcJsonDoc, + size_t xJsonDocLength, + const char * pcKey, + size_t xKeyLength, + const char ** ppcValue, + size_t * pxValueLength ); + +/** + * @brief Job operation completion callback. This function is invoked when an + * asynchronous Job operation finishes. + * + * @param[in] pvCallbackContext Set to a non-NULL value to exit the demo. + * @param[in] pxCallbackParam Information on the Job operation that completed. + */ +static void prvOperationCompleteCallback( void * pvCallbackContext, + AwsIotJobsCallbackParam_t * pxCallbackParam ); + + +/** + * @brief Process an action with a message, such as "print" or "publish". + * + * @param[in] xMqttConnection The MQTT connection to use if the action is "publish". + * @param[in] xAction Either #JOB_ACTION_PRINT or #JOB_ACTION_PUBLISH. + * @param[in] pcJobDoc A pointer to the Job document. + * @param[in] xJobDocLength The length of the Job document. + * + * @return #AWS_IOT_JOB_STATE_SUCCEEDED on success; #AWS_IOT_JOB_STATE_FAILED otherwise. + */ +static AwsIotJobState_t prvProcessMessage( IotMqttConnection_t xMqttConnection, + _jobAction_t xAction, + const char * pcJobDoc, + size_t xJobDocLength ); + +/** + * @brief Process a Job received from the Notify Next callback. + * + * @param[in] pxJobInfo The parameter to the Notify Next callback that contains + * information about the received Job. + * @param[in] pcJobId A pointer to the Job ID. + * @param[in] xJobIdLength The length of the Job ID. + * @param[in] pcJobDoc A pointer to the Job document. + * @param[in] xJobDocLength The length of the Job document. + */ +static void prvProcessJob( const AwsIotJobsCallbackParam_t * pxJobInfo, + const char * pcJobId, + size_t xJobIdLength, + const char * pcJobDoc, + size_t xJobDocLength ); + +/** + * @brief Jobs Notify Next callback. This function is invoked when a new Job is + * received from the Jobs service. + * + * @param[in] pCallbackContext Ignored. + * @param[in] pxCallbackInfo Contains the received Job. + */ +static void prvJobsCallback( void * pCallbackContext, + AwsIotJobsCallbackParam_t * pxCallbackInfo ); + +/*-----------------------------------------------------------*/ + +/** + * @brief The MQTT connection handle used in this example. + */ +static IotMqttConnection_t xMQTTConnection = IOT_MQTT_CONNECTION_INITIALIZER; + +/* + * @brief The main task handle in this demo. + */ +static TaskHandle_t xMainTaskHandle; + +/** + * @brief Parameters used to create the system task pool. + */ +static const IotTaskPoolInfo_t xTaskPoolParameters = +{ + /* Minimum number of threads in a task pool. + * Note the slimmed down version of the task + * pool used by this library does not auto-scale + * the number of tasks in the pool so in this + * case this sets the number of tasks in the + * pool. */ + 1, + + /* Maximum number of threads in a task pool. + * Note the slimmed down version of the task + * pool used by this library does not auto-scale + * the number of tasks in the pool so in this + * case this parameter is just ignored. */ + 1, + + /* Stack size for every task pool thread - in + * bytes, hence multiplying by the number of bytes + * in a word as configMINIMAL_STACK_SIZE is + * specified in words. */ + configMINIMAL_STACK_SIZE * sizeof( portSTACK_TYPE ), + /* Priority for every task pool thread. */ + tskIDLE_PRIORITY, +}; + +/***************** Structures that define the connection. *********************/ + + +static const struct IotNetworkServerInfo xMQTTBrokerInfo = +{ + .pHostName = awsiotdemoprofileAWS_ENDPOINT, + .port = awsiotdemoprofileAWS_MQTT_PORT +}; + +static struct IotNetworkCredentials xNetworkSecurityCredentials = +{ + /* Optional TLS extensions. For this demo, they are disabled. */ + .pAlpnProtos = NULL, + .maxFragmentLength = 0, + + /* SNI is enabled by default. */ + .disableSni = false, + + /* Provide the certificate for validating the server. Only required for + demos using TLS. */ + .pRootCa = awsiotdemoprofileAWS_CERTIFICATE_PEM, + .rootCaSize = sizeof( awsiotdemoprofileAWS_CERTIFICATE_PEM ), + + /* Strong mutual authentication to authenticate both the broker and + * the client. */ + .pClientCert = awsiotdemoprofileCLIENT_CERTIFICATE_PEM, + .clientCertSize = sizeof( awsiotdemoprofileCLIENT_CERTIFICATE_PEM ), + .pPrivateKey = awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM, + .privateKeySize = sizeof( awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM ) +}; + +static IotMqttNetworkInfo_t xNetworkInfo = +{ + /* No connection to the MQTT broker has been established yet and we want to + * establish a new connection. */ + .createNetworkConnection = true, + .u.setup.pNetworkServerInfo = &( xMQTTBrokerInfo ), + + /* Set the TLS credentials for the new MQTT connection. */ + .u.setup.pNetworkCredentialInfo = &xNetworkSecurityCredentials, + + /* Use FreeRTOS+TCP network interface. */ + .pNetworkInterface = IOT_NETWORK_INTERFACE_FREERTOS, + + /* Setup the callback which is called when the MQTT connection is + * disconnected. The task handle is passed as the callback context which + * is used by the callback to send a task notification to this task.*/ + .disconnectCallback.function = prvExample_OnDisconnect +}; + +static const IotMqttConnectInfo_t xConnectInfo = +{ + /* Set this flag to true if connecting to the AWS IoT MQTT broker. */ + .awsIotMqttMode = false, + + /* Start with a clean session i.e. direct the MQTT broker to discard any + * previous session data. Also, establishing a connection with clean session + * will ensure that the broker does not store any data when this client + * gets disconnected. */ + .cleanSession = true, + + /* Since we are starting with a clean session, there are no previous + * subscriptions to be restored. */ + .pPreviousSubscriptions = NULL, + .previousSubscriptionCount = 0, + + /* We do not want to publish Last Will and Testament (LWT) message if the + * client gets disconnected. */ + .pWillInfo = NULL, + + /* Send an MQTT PING request every minute to keep the connection open if + * there is no other MQTT traffic. */ + .keepAliveSeconds = jobsexampleKEEP_ALIVE_SECONDS, + + /* The client identifier is used to uniquely identify this MQTT client to + * the MQTT broker. In a production device the identifier can be something + * unique, such as a device serial number. */ + .pClientIdentifier = awsiotdemoprofileCLIENT_IDENTIFIER, + .clientIdentifierLength = ( uint16_t ) sizeof( awsiotdemoprofileCLIENT_IDENTIFIER ) - 1, + + /* This example does not authenticate the client and therefore username and + * password fields are not used. */ + .pUserName = NULL, + .userNameLength = 0, + .pPassword = NULL, + .passwordLength = 0 +}; +/*-----------------------------------------------------------*/ + +static void prvExample_OnDisconnect( void * pvCallbackContext, + IotMqttCallbackParam_t * pxCallbackParams ) +{ +TaskHandle_t xDemoTaskHandle = ( TaskHandle_t ) pvCallbackContext; + + /* Ensure that we initiated the disconnect. */ + configASSERT( pxCallbackParams->u.disconnectReason == IOT_MQTT_DISCONNECT_CALLED ); + + /* Inform the demo task about the disconnect. */ + xTaskNotify( xDemoTaskHandle, + jobsexampleDISCONNECTED_BIT, + eSetBits /* Set the jobsexampleDISCONNECTED_BIT in the demo task's notification value. */ + ); +} +/*-----------------------------------------------------------*/ + +void vStartJobsDemo( void ) +{ +TickType_t xShortDelay = ( TickType_t ) pdMS_TO_TICKS( ( TickType_t ) 500 ); + + /* Wait a short time to allow receipt of the ARP replies. */ + vTaskDelay( xShortDelay ); + + /* This example uses a single application task, which in turn is used to + * connect, subscribe, publish, unsubscribe and disconnect from the MQTT + * broker. */ + xTaskCreate( prvJobsDemoTask, /* Function that implements the task. */ + "JobsDemo", /* Text name for the task - only used for debugging. */ + democonfigDEMO_STACKSIZE, /* Size of stack (in words, not bytes) to allocate for the task. */ + NULL, /* Task parameter - not used in this case. */ + tskIDLE_PRIORITY, /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */ + NULL ); /* Used to pass out a handle to the created task - not used in this case. */ +} +/*-----------------------------------------------------------*/ + +static void prvJobsDemoTask( void * pvParameters ) +{ +IotMqttError_t xResult; +IotNetworkError_t xNetworkInit; +uint32_t ulNotificationValue = 0; +const TickType_t xNoDelay = ( TickType_t ) 0; +AwsIotJobsError_t xStatus = AWS_IOT_JOBS_SUCCESS; +AwsIotJobsCallbackInfo_t xCallbackInfo = AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER; +AwsIotJobsRequestInfo_t xRequestInfo = AWS_IOT_JOBS_REQUEST_INFO_INITIALIZER; + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + xMainTaskHandle = xTaskGetCurrentTaskHandle(); + + /* The MQTT library needs a task pool, so create the system task pool. */ + xResult = IotTaskPool_CreateSystemTaskPool( &( xTaskPoolParameters ) ); + configASSERT( xResult == IOT_TASKPOOL_SUCCESS ); + + /* Initialize the network stack abstraction for FreeRTOS. */ + xNetworkInit = IotNetworkFreeRTOS_Init(); + configASSERT( xNetworkInit == IOT_NETWORK_SUCCESS ); + + /* MQTT library must be initialized before it can be used. This is just one + * time initialization. */ + xResult = IotMqtt_Init(); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + + /* Initialize Jobs library. */ + xResult = AwsIotJobs_Init( jobsexampleUSE_DEFAULT_MQTT_TIMEOUT ); + configASSERT( xResult == AWS_IOT_JOBS_SUCCESS ); + + /****************************** Connect. ******************************/ + + /* Establish a connection to the AWS IoT MQTT broker. This example connects to + * the MQTT broker as specified in awsiotdemoprofileAWS_ENDPOINT and + * awsiotdemoprofileAWS_MQTT_PORT at the top of this file. + */ + configPRINTF( ( "Attempt to connect to %s\r\n", awsiotdemoprofileAWS_ENDPOINT ) ); + prvMQTTConnect(); + configPRINTF( ( "Connected to %s\r\n", awsiotdemoprofileAWS_ENDPOINT ) ); + + /* Don't expect any notifications to be pending yet. */ + configASSERT( ulTaskNotifyTake( pdTRUE, xNoDelay ) == 0 ); + + configPRINTF( ( "Setting callback for jobs/notify-next\r\n" ) ); + prvSetNotifyNextCallback(); + + /* Call DescribeAsync to see if there are any pending jobs. */ + xRequestInfo.mqttConnection = xMQTTConnection; + xRequestInfo.pThingName = awsiotdemoprofileCLIENT_IDENTIFIER; + xRequestInfo.thingNameLength = jobsexampleCLIENT_IDENTIFIER_LENGTH; + xRequestInfo.pJobId = AWS_IOT_JOBS_NEXT_JOB; + xRequestInfo.jobIdLength = AWS_IOT_JOBS_NEXT_JOB_LENGTH; + + /* Use the same callback as notify-next so any pending jobs will be + * executed the same way. */ + xCallbackInfo.function = prvJobsCallback; + + xStatus = AwsIotJobs_DescribeAsync( &xRequestInfo, AWS_IOT_JOBS_NO_EXECUTION_NUMBER, true, 0, &xCallbackInfo, NULL ); + configPRINTF( ( "Describe queued with result %s.\r\n", AwsIotJobs_strerror( xStatus ) ) ); + + /* Print out a short user guide to the console. The default logging + * limit of 255 characters can be changed in demo_logging.c, but breaking + * up the only instance of a 1000+ character string is more practical. */ + configPRINTF( ( + "\r\n" + "/*-----------------------------------------------------------*/\r\n" + "\r\n" + "The Jobs demo is now ready to accept Jobs.\r\n" + "Jobs may be created using the AWS IoT console or AWS CLI.\r\n" + "See the following link for more information.\r\n" + "\r\n" ) ); + configPRINTF( ( + "\r" + "https://docs.aws.amazon.com/cli/latest/reference/iot/create-job.html\r\n" + "\r\n" + "This demo expects Job documents to have an \"action\" JSON key.\r\n" + "The following actions are currently supported:\r\n" ) ); + configPRINTF( ( + "\r" + " - print \r\n" + " Logs a message to the local console. The Job document must also contain a \"message\".\r\n" + " For example: { \"action\": \"print\", \"message\": \"Hello world!\"} will cause\r\n" + " \"Hello world!\" to be printed on the console.\r\n" ) ); + configPRINTF( ( + "\r" + " - publish \r\n" + " Publishes a message to an MQTT topic. The Job document must also contain a \"message\" and \"topic\".\r\n" ) ); + configPRINTF( ( + "\r" + " For example: { \"action\": \"publish\", \"topic\": \"demo/jobs\", \"message\": \"Hello world!\"} will cause\r\n" + " \"Hello world!\" to be published to the topic \"demo/jobs\".\r\n" ) ); + configPRINTF( ( + "\r" + " - exit \r\n" + " Exits the demo program. This program will run until { \"action\": \"exit\" } is received.\r\n" + "\r\n" + "/*-----------------------------------------------------------*/\r\n" ) ); + + /* Wait for an exit job to be received. If an exit job is not received within + * jobsexampleMS_BEFORE_EXIT, exit anyway. This is because we have disabled + * keep-alive, and the server will disconnect as after some time. */ + xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */ + jobsexampleEXIT_BIT, /* Clear bit on exit. */ + &( ulNotificationValue ), /* Obtain the notification value. */ + pdMS_TO_TICKS( jobsexampleMS_BEFORE_EXIT) ); + /* Check was due to receiving an exit job. */ + if( ( ulNotificationValue & jobsexampleEXIT_BIT ) != jobsexampleEXIT_BIT ) + { + configPRINTF( ( "Disconnecting as %u milliseconds have elapsed.\r\n", jobsexampleMS_BEFORE_EXIT ) ); + } + + /* Disconnect MQTT gracefully. */ + prvMQTTDisconnect(); + configPRINTF( ( "Disconnected from %s\r\n\r\n", awsiotdemoprofileAWS_ENDPOINT ) ); + + /* Wait for the disconnect operation to complete which is informed to us + * by the disconnect callback (prvExample_OnDisconnect)by setting + * the jobsexampleDISCONNECTED_BIT in this task's notification value. */ + xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */ + jobsexampleDISCONNECTED_BIT, /* Clear bit on exit. */ + &( ulNotificationValue ), /* Obtain the notification value. */ + pdMS_TO_TICKS( jobsexampleMQTT_TIMEOUT_MS ) ); + configASSERT( ( ulNotificationValue & jobsexampleDISCONNECTED_BIT ) == jobsexampleDISCONNECTED_BIT ); + + configPRINTF( ( "prvJobsDemoTask() completed successfully. Total free heap is %u\r\n", xPortGetFreeHeapSize() ) ); + configPRINTF( ( "Demo completed successfully.\r\n" ) ); + + /* Clean up initialized libraries. */ + AwsIotJobs_Cleanup(); + IotMqtt_Cleanup(); + IotNetworkFreeRTOS_Cleanup(); + + /* FreeRTOS Tasks must _vTaskDelete( NULL )_ before exiting the function. */ + vTaskDelete( NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvMQTTConnect( void ) +{ +IotMqttError_t xResult; + + /* Set the context to pass into the disconnect callback function. */ + xNetworkInfo.disconnectCallback.pCallbackContext = ( void * ) xTaskGetCurrentTaskHandle(); + + /* Establish the connection to the MQTT broker - It is a blocking call and + * will return only when connection is complete or a timeout occurs. */ + xResult = IotMqtt_Connect( &( xNetworkInfo ), + &( xConnectInfo ), + jobsexampleMQTT_TIMEOUT_MS, + &( xMQTTConnection ) ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); +} +/*-----------------------------------------------------------*/ + +static void prvMQTTDisconnect( void ) +{ + /* Send a MQTT DISCONNECT packet to the MQTT broker to do a graceful + * disconnect. */ + IotMqtt_Disconnect( xMQTTConnection, + 0 /* flags - 0 means a graceful disconnect by sending MQTT DISCONNECT. */ + ); +} +/*-----------------------------------------------------------*/ + +static void prvSetNotifyNextCallback( void ) +{ +AwsIotJobsError_t xCallbackStatus = AWS_IOT_JOBS_SUCCESS; +AwsIotJobsCallbackInfo_t xCallbackInfo = AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER; + + /* Set the jobs callback function. */ + xCallbackInfo.function = prvJobsCallback; + + /************************ Set notify-next callbacks **********************/ + + xCallbackStatus = AwsIotJobs_SetNotifyNextCallback( xMQTTConnection, + awsiotdemoprofileCLIENT_IDENTIFIER, + jobsexampleCLIENT_IDENTIFIER_LENGTH, + 0, + &xCallbackInfo ); + + configASSERT( xCallbackStatus == AWS_IOT_JOBS_SUCCESS ); +} +/*-----------------------------------------------------------*/ + +static _jobAction_t prvGetAction( const char * pcAction, + size_t xActionLength ) +{ +_jobAction_t xAction = JOB_ACTION_UNKNOWN; + + configASSERT( pcAction != NULL ); + + if( strncmp( pcAction, "print", xActionLength ) == 0 ) + { + xAction = JOB_ACTION_PRINT; + } + else if( strncmp( pcAction, "publish", xActionLength ) == 0 ) + { + xAction = JOB_ACTION_PUBLISH; + } + else if( strncmp( pcAction, "exit", xActionLength ) == 0 ) + { + xAction = JOB_ACTION_EXIT; + } + + return xAction; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvGetJsonString( const char * pcJsonDoc, + size_t xJsonDocLength, + const char * pcKey, + size_t xKeyLength, + const char ** ppcValue, + size_t * pxValueLength ) +{ +BaseType_t xKeyFound = pdFALSE; + + configASSERT( pcJsonDoc != NULL ); + configASSERT( pcKey != NULL ); + + /* + * Note: This parser used is specific for parsing AWS IoT document received + * through a mutually authenticated connection. This parser will not check + * for the correctness of the document as it is designed for low memory + * footprint rather than checking for correctness of the document. This + * parser is not meant to be used as a general purpose JSON parser. + */ + xKeyFound = ( BaseType_t ) AwsIotDocParser_FindValue( + pcJsonDoc, + xJsonDocLength, + pcKey, + xKeyLength, + ppcValue, + pxValueLength ); + + if( xKeyFound == pdTRUE ) + { + /* Exclude empty strings. */ + if( *pxValueLength < jobsexampleJSON_STRING_MIN_LENGTH ) + { + xKeyFound = pdFALSE; + } + else + { + /* Adjust the value to remove the quotes. */ + ( *ppcValue )++; + ( *pxValueLength ) -= 2; + } + } + + return xKeyFound; +} +/*-----------------------------------------------------------*/ + +static void prvOperationCompleteCallback( void * pvCallbackContext, + AwsIotJobsCallbackParam_t * pxCallbackParam ) +{ + configASSERT( pxCallbackParam != NULL ); + + /* This function is invoked when either a StartNext or Update completes. */ + if( pxCallbackParam->callbackType == AWS_IOT_JOBS_START_NEXT_COMPLETE ) + { + configPRINTF( ( "Job StartNext complete with result %s.\r\n", + AwsIotJobs_strerror( pxCallbackParam->u.operation.result ) ) ); + } + else + { + configPRINTF( ( "Job Update complete with result %s.\r\n", + AwsIotJobs_strerror( pxCallbackParam->u.operation.result ) ) ); + } + + /* If a non-NULL context is given, set the flag to exit the demo. */ + if( pvCallbackContext != NULL ) + { + xTaskNotify( xMainTaskHandle, + jobsexampleEXIT_BIT, + eSetBits /* Set the jobsexampleEXIT_BIT in the demo task's notification value. */ + ); + } +} +/*-----------------------------------------------------------*/ + +static AwsIotJobState_t prvProcessMessage( IotMqttConnection_t xMqttConnection, + _jobAction_t xAction, + const char * pcJobDoc, + size_t xJobDocLength ) +{ +AwsIotJobState_t xStatus = AWS_IOT_JOB_STATE_SUCCEEDED; +IotMqttError_t xMqttStatus = IOT_MQTT_STATUS_PENDING; +IotMqttPublishInfo_t xPublishInfo = IOT_MQTT_PUBLISH_INFO_INITIALIZER; +const char * pcMessage = NULL, * pcTopic = NULL; +size_t xMessageLength = 0, xTopicLength = 0; + + configASSERT( pcJobDoc != NULL ); + + /* Both "print" and "publish" require a "message" key. Search the Job + * document for this key. */ + if( prvGetJsonString( pcJobDoc, + xJobDocLength, + jobsexampleMESSAGE_KEY, + jobsexampleMESSAGE_KEY_LENGTH, + &pcMessage, + &xMessageLength ) == pdFALSE ) + { + configPRINTF( ( "Job document for \"print\" or \"publish\" does not contain a %s key.\r\n", + jobsexampleMESSAGE_KEY ) ); + + xStatus = AWS_IOT_JOB_STATE_FAILED; + } + + if( xStatus == AWS_IOT_JOB_STATE_SUCCEEDED ) + { + if( xAction == JOB_ACTION_PRINT ) + { + /* Print the given message if the action is "print". */ + configPRINTF( ( + "\r\n" + "/*-----------------------------------------------------------*/\r\n" + "\r\n" + "%.*s\r\n" + "\r\n" + "/*-----------------------------------------------------------*/\r\n" + "\r\n", xMessageLength, pcMessage ) ); + } + else + { + /* Extract the topic if the action is "publish". */ + if( prvGetJsonString( pcJobDoc, + xJobDocLength, + jobsexampleTOPIC_KEY, + jobsexampleTOPIC_KEY_LENGTH, + &pcTopic, + &xTopicLength ) == pdFALSE ) + { + configPRINTF( ( "Job document for action \"publish\" does not contain a %s key.\r\n", + jobsexampleTOPIC_KEY ) ); + + xStatus = AWS_IOT_JOB_STATE_FAILED; + } + + if( xStatus == AWS_IOT_JOB_STATE_SUCCEEDED ) + { + xPublishInfo.qos = IOT_MQTT_QOS_0; + xPublishInfo.pTopicName = pcTopic; + xPublishInfo.topicNameLength = ( uint16_t ) xTopicLength; + xPublishInfo.pPayload = pcMessage; + xPublishInfo.payloadLength = xMessageLength; + + xMqttStatus = IotMqtt_PublishAsync( xMqttConnection, &xPublishInfo, 0, NULL, NULL ); + + if( xMqttStatus != IOT_MQTT_SUCCESS ) + { + xStatus = AWS_IOT_JOB_STATE_FAILED; + } + } + } + } + + return xStatus; +} +/*-----------------------------------------------------------*/ + +static void prvProcessJob( const AwsIotJobsCallbackParam_t * pxJobInfo, + const char * pcJobId, + size_t xJobIdLength, + const char * pcJobDoc, + size_t xJobDocLength ) +{ +AwsIotJobsError_t xStatus = AWS_IOT_JOBS_SUCCESS; +AwsIotJobsUpdateInfo_t xUpdateInfo = AWS_IOT_JOBS_UPDATE_INFO_INITIALIZER; +AwsIotJobsCallbackInfo_t xCallbackInfo = AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER; +const char * pcAction = NULL; +size_t xActionLength = 0; +_jobAction_t xAction = JOB_ACTION_UNKNOWN; +AwsIotJobsRequestInfo_t xRequestInfo = AWS_IOT_JOBS_REQUEST_INFO_INITIALIZER; + + configASSERT( pxJobInfo != NULL ); + configASSERT( pcJobId != NULL ); + configASSERT( pcJobDoc != NULL ); + + configPRINTF( ( "Job document received: %.*s\r\n", xJobDocLength, pcJobDoc ) ); + + xRequestInfo.mqttConnection = pxJobInfo->mqttConnection; + xRequestInfo.pThingName = pxJobInfo->pThingName; + xRequestInfo.thingNameLength = pxJobInfo->thingNameLength; + xRequestInfo.pJobId = pcJobId; + xRequestInfo.jobIdLength = xJobIdLength; + + /* Tell the Jobs service that the device has started working on the Job. + * Use the StartNext API to set the Job's status to IN_PROGRESS. */ + xCallbackInfo.function = prvOperationCompleteCallback; + + xStatus = AwsIotJobs_StartNextAsync( &xRequestInfo, &xUpdateInfo, 0, &xCallbackInfo, NULL ); + + configPRINTF( ( "Jobs StartNext queued with result %s.\r\n", AwsIotJobs_strerror( xStatus ) ) ); + + /* Get the action for this device. */ + if( prvGetJsonString( pcJobDoc, + xJobDocLength, + jobsexampleACTION_KEY, + jobsexampleACTION_KEY_LENGTH, + &pcAction, + &xActionLength ) == pdTRUE ) + { + xAction = prvGetAction( pcAction, xActionLength ); + + switch( xAction ) + { + case JOB_ACTION_EXIT: + xCallbackInfo.pCallbackContext = jobsexampleSHOULD_EXIT; + xUpdateInfo.newStatus = AWS_IOT_JOB_STATE_SUCCEEDED; + break; + + case JOB_ACTION_PRINT: + case JOB_ACTION_PUBLISH: + xUpdateInfo.newStatus = prvProcessMessage( pxJobInfo->mqttConnection, + xAction, + pcJobDoc, + xJobDocLength ); + break; + + default: + configPRINTF( ( "Received Job document with unknown action %.*s.\r\n", + xActionLength, + pcAction ) ); + + xUpdateInfo.newStatus = AWS_IOT_JOB_STATE_FAILED; + break; + } + } + else + { + configPRINTF( ( "Received Job document does not contain an %s key.\r\n", + jobsexampleACTION_KEY ) ); + + /* The given Job document is not valid for this demo. */ + xUpdateInfo.newStatus = AWS_IOT_JOB_STATE_FAILED; + } + + configPRINTF( ( "Setting state of %.*s to %s.\r\n", + xJobIdLength, + pcJobId, + AwsIotJobs_StateName( xUpdateInfo.newStatus ) ) ); + + /* Tell the Jobs service that the device has finished the Job. */ + xStatus = AwsIotJobs_UpdateAsync( &xRequestInfo, &xUpdateInfo, 0, &xCallbackInfo, NULL ); + + configPRINTF( ( "Jobs Update queued with result %s.\r\n", AwsIotJobs_strerror( xStatus ) ) ); +} +/*-----------------------------------------------------------*/ + +static void prvJobsCallback( void * pCallbackContext, + AwsIotJobsCallbackParam_t * pxCallbackInfo ) +{ +BaseType_t xIdKeyFound = pdFALSE, xDocKeyFound = pdFALSE; +const char * pcJobId = NULL; +size_t xJobIdLength = 0; +const char * pcJobDoc = NULL; +size_t xJobDocLength = 0; +const char * pcRawDocument = NULL; +size_t xRawDocumentLength = 0; + + /* Silence warnings about unused parameters. */ + ( void ) pCallbackContext; + + configASSERT( pxCallbackInfo != NULL ); + + /* Check if this callback was called from a describe operation or + * due to notify-next. */ + if( pxCallbackInfo->callbackType == AWS_IOT_JOBS_DESCRIBE_COMPLETE ) + { + pcRawDocument = pxCallbackInfo->u.operation.pResponse; + xRawDocumentLength = pxCallbackInfo->u.operation.responseLength; + } + else + { + pcRawDocument = pxCallbackInfo->u.callback.pDocument; + xRawDocumentLength = pxCallbackInfo->u.callback.documentLength; + } + + /* Get the Job ID. */ + xIdKeyFound = prvGetJsonString( pcRawDocument, + xRawDocumentLength, + jobsexampleID_KEY, + jobsexampleID_KEY_LENGTH, + &pcJobId, + &xJobIdLength ); + + if( xIdKeyFound == pdTRUE ) + { + if( xJobIdLength > jobsexampleID_MAX_LENGTH ) + { + configPRINTF( ( "Received Job ID %.*s longer than %lu, which is the " + "maximum allowed by AWS IoT. Ignoring Job.\r\n", + xJobIdLength, + pcJobId, + ( unsigned long ) jobsexampleID_MAX_LENGTH ) ); + + xIdKeyFound = pdFALSE; + } + else + { + configPRINTF( ( "Job %.*s received.\r\n", xJobIdLength, pcJobId ) ); + } + } + + /* Get the Job document. + * + * Note: This parser used is specific for parsing AWS IoT document received + * through a mutually authenticated connection. This parser will not check + * for the correctness of the document as it is designed for low memory + * footprint rather than checking for correctness of the document. This + * parser is not meant to be used as a general purpose JSON parser. + */ + xDocKeyFound = ( BaseType_t ) AwsIotDocParser_FindValue( + pcRawDocument, + xRawDocumentLength, + jobsexampleDOC_KEY, + jobsexampleDOC_KEY_LENGTH, + &pcJobDoc, + &xJobDocLength ); + + /* When both the Job ID and Job document are available, process the Job. */ + if( ( xIdKeyFound == pdTRUE ) && ( xDocKeyFound == pdTRUE ) ) + { + /* Process the Job document. */ + prvProcessJob( pxCallbackInfo, + pcJobId, + xJobIdLength, + pcJobDoc, + xJobDocLength ); + } + else + { + /* The Jobs service sends an empty Job document when all Jobs are complete. */ + if( ( xIdKeyFound == pdFALSE ) && ( xDocKeyFound == pdFALSE ) ) + { + configPRINTF( ( + "\r\n" + "/*-----------------------------------------------------------*/\r\n" + "\r\n" + "All available Jobs complete.\r\n" + "\r\n" + "/*-----------------------------------------------------------*/\r\n" + "\r\n" ) ); + } + else + { + configPRINTF( ( "Received an invalid Job document: %.*s\r\n", + xRawDocumentLength, + pcRawDocument ) ); + } + } +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/FreeRTOSConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/FreeRTOSConfig.h new file mode 100644 index 000000000..d58a0b80f --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/FreeRTOSConfig.h @@ -0,0 +1,210 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * http://www.freertos.org/a00110.html + * + * The bottom of this file contains some constants specific to running the UDP + * stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than + * the demo) are contained in FreeRTOSIPConfig.h. + *----------------------------------------------------------*/ +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Run time stats gathering definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_pcTaskGetTaskName 1 + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS +is set to 2 so the formatting functions are included without the stdio.h being +included in tasks.c. That is because this project defines its own sprintf() +functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* Assert call defined for debug builds. */ +#ifdef _DEBUG + extern void vAssertCalled( const char *pcFile, uint32_t ulLine ); + #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) +#endif /* _DEBUG */ + + + +/* Application specific definitions follow. **********************************/ + +/* Only used when running in the FreeRTOS Windows simulator. Defines the +priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet +or WiFi data to and from a real network connection. Many computers have more +than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell +the demo which real port should be used to create the virtual port. The ports +available are displayed on the console when the application is executed. For +example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 +results in the wired network being used, while setting +configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being +used. */ +#define configNETWORK_INTERFACE_TO_USE 1L + +/* The address of an echo server is only left in this project as it doubles as +the address to which logging is sent should UDP logging be enabled. */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 0 +#define configECHO_SERVER_ADDR3 11 + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet/WiFi data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition above for information on how to +configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x11 +#define configMAC_ADDR3 0x11 +#define configMAC_ADDR4 0x11 +#define configMAC_ADDR5 0x41 + +/* Default IP address configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 10 +#define configIP_ADDR1 10 +#define configIP_ADDR2 10 +#define configIP_ADDR3 200 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DNS is set to +0, or ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 10 +#define configGATEWAY_ADDR1 10 +#define configGATEWAY_ADDR2 10 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. OpenDNS addresses are 208.67.222.222 and +208.67.220.220. Used in ipconfigUSE_DNS is set to 0, or ipconfigUSE_DNS is set +to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 208 +#define configDNS_SERVER_ADDR1 67 +#define configDNS_SERVER_ADDR2 222 +#define configDNS_SERVER_ADDR3 222 + +/* Default netmask configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 0 +#define configNET_MASK2 0 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#if( defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) && !defined( snprintf ) ) + /* Map to Windows names. */ + #define snprintf _snprintf + #define vsnprintf _vsnprintf +#endif + +/* Visual studio does not have an implementation of strcasecmp(). */ +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define strcmpi _strcmpi + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); +#define configPRINTF( X ) vLoggingPrintf X + +#endif /* FREERTOS_CONFIG_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/FreeRTOSIPConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/FreeRTOSIPConfig.h new file mode 100644 index 000000000..6f86009bf --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/FreeRTOSIPConfig.h @@ -0,0 +1,310 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +/***************************************************************************** + * + * See the following URL for configuration information. + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html + * + *****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to +1 then FreeRTOS_debug_printf should be defined to the function used to print +out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 0 +#if( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf(X) vLoggingPrintf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the +FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 +then FreeRTOS_printf should be set to the function used to print out the +messages. */ +#define ipconfigHAS_PRINTF 1 +#if( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf(X) vLoggingPrintf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing +on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading (IP/TCP/UDP checksums) +then set ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software +stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 + +/* Several API's will block until the result is known, or the action has been +performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be +set per socket, using setsockopt(). If not set, the times below will be +used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 5000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for LLMNR: Link-local Multicast Name Resolution +(non-Microsoft) */ +#define ipconfigUSE_LLMNR ( 0 ) + +/* Include support for NBNS: NetBIOS Name Service (Microsoft) */ +#define ipconfigUSE_NBNS ( 0 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very +useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low +and also DNS may use small timeouts. If a DNS reply comes in after the DNS +socket has been destroyed, the result will be stored into the cache. The next +call to FreeRTOS_gethostbyname() will return immediately, without even creating +a socket. */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_NAME_LENGTH ( 64 ) +#define ipconfigDNS_CACHE_ENTRIES ( 4 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make +use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY +sets the priority of the task that executes the IP stack. The priority is a +standard FreeRTOS task priority so can take any value from 0 (the lowest +priority) to (configMAX_PRIORITIES - 1) (the highest priority). +configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in +FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to +the priority assigned to the task executing the IP stack relative to the +priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP +task. This setting is less important when the FreeRTOS Win32 simulator is used +as the Win32 simulator only stores a fixed amount of information on the task +stack. FreeRTOS includes optional stack overflow detection, see: +http://www.freertos.org/Stacks-and-stack-overflow-checking.html */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* ipconfigRAND32() is called by the IP stack to generate random numbers for +things such as a DHCP transaction number or initial sequence number. Random +number generation is performed via this macro to allow applications to use their +own random number generation method. For example, it might be possible to +generate a random number by sampling noise on an analogue input. */ +extern UBaseType_t uxRand(); +#define ipconfigRAND32() uxRand() + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the +network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK +is not set to 1 then the network event hook will never be called. See +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml +*/ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but +a network buffer cannot be obtained then the calling task is held in the Blocked +state (so other tasks can continue to executed) until either a network buffer +becomes available or the send block time expires. If the send block time expires +then the send operation is aborted. The maximum allowable send block time is +capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the +maximum allowable send block time prevents prevents a deadlock occurring when +all the network buffers are in use and the tasks that process (and subsequently +free) the network buffers are themselves blocked waiting for a network buffer. +ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in +milliseconds can be converted to a time in ticks by dividing the time in +milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP +address, netmask, DNS server address and gateway address from a DHCP server. If +ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The +stack will revert to using the static IP address even when ipconfigUSE_DHCP is +set to 1 if a valid configuration cannot be obtained from a DHCP server for any +reason. The static configuration used is that passed into the stack by the +FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 1 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at +increasing time intervals until either a reply is received from a DHCP server +and accepted, or the interval between transmissions reaches +ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the +static IP address passed as a parameter to FreeRTOS_IPInit() if the +re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without +a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( 120000 / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP +stack can only send a UDP message to a remove IP address if it knowns the MAC +address associated with the IP address, or the MAC address of the router used to +contact the remote IP address. When a UDP message is received from a remote IP +address the MAC address and IP address are added to the ARP cache. When a UDP +message is sent to a remote IP address that does not already appear in the ARP +cache then the UDP message is replaced by a ARP message that solicits the +required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum +number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a +maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is +aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP +table being created or refreshed and the entry being removed because it is stale. +New ARP requests are sent for ARP cache entries that are nearing their maximum +age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is +equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling +routines, which are relatively large. To save code space the full +FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster +alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() +takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. +FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets +(for example, 192, 168, 0, 1) as its parameters. If +ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and +FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is +not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that +are available to the IP stack. The total number of network buffers is limited +to ensure the total amount of RAM that can be consumed by the IP stack is capped +to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP +stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can +be queued for processing at any one time. The event queue must be a minimum of +5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port +number. FreeRTOS_bind() is used to manually allocate a port number to a socket +(to 'bind' the socket to a port), but manual binding is not normally necessary +for client sockets (those sockets that initiate outgoing connections rather than +wait for incoming connections on a known port number). If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling +FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP +stack automatically binding the socket to a port number from the range +socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() +on a socket that has not yet been bound will result in the send operation being +aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +#define ipconfigTCP_TIME_TO_LIVE 128 /* also defined in FreeRTOSIPConfigDefaults.h */ + +/* USE_TCP: Use TCP and all its features */ +#define ipconfigUSE_TCP ( 1 ) + +/* Use the TCP socket wake context with a callback. */ +#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT ( 1 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can +contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a +lower value can save RAM, depending on the buffer management scheme used. If +ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must +be divisible by 8. */ +#define ipconfigNETWORK_MTU 1200 + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used +through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will +generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the +FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 0 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() +(and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames +that are not in Ethernet II format will be dropped. This option is included for +potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the +responsibility of the Ethernet interface to filter out packets that are of no +interest. If the Ethernet interface does not implement this functionality, then +set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack +perform the filtering instead (it is much less efficient for the stack to do it +because the packet will already have been passed into the stack). If the +Ethernet driver does all the necessary filtering in hardware then software +filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to +block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with +32-bit memory instructions, all packets will be stored 32-bit-aligned, plus 16-bits. +This has to do with the contents of the IP-packets: all 32-bit fields are +32-bit-aligned, plus 16-bit(!) */ +#define ipconfigPACKET_FILLER_SIZE 2 + +/* Define the size of the pool of TCP window descriptors. On the average, each +TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 +outstanding packets (for Rx and Tx). When using up to 10 TP sockets +simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed +maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 1000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 1000 ) + +/* When using call-back handlers, the driver may check if the handler points to +real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS(x) ( (x) != NULL ) + +/* Include support for TCP hang protection. All sockets in a connecting or +disconnecting stage will timeout after a period of non-activity. */ +#define ipconfigTCP_HANG_PROTECTION ( 1 ) +#define ipconfigTCP_HANG_PROTECTION_TIME ( 30 ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* in seconds */ + +#define portINLINE __inline + +#endif /* FREERTOS_IP_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/READ_ME_INSTRUCTIONS.url b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/READ_ME_INSTRUCTIONS.url new file mode 100644 index 000000000..94064244e --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/READ_ME_INSTRUCTIONS.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/jobs/index.html diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WIN32.vcxproj b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WIN32.vcxproj new file mode 100644 index 000000000..91e944f1d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WIN32.vcxproj @@ -0,0 +1,644 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {C686325E-3261-42F7-AEB1-DDE5280E1CEB} + RTOSDemo + 10.0 + + + + Application + false + MultiByte + v142 + + + Application + false + MultiByte + v142 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Debug\ + .\Debug\ + true + .\Release\ + .\Release\ + false + AllRules.ruleset + + + + .\Debug/WIN32.tlb + + + + + Disabled + ..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;.\DemoTasks\include;.\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\src;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\mbedtls;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\platform;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\mqtt\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\aws\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\aws\jobs\include;..\..\include;..\..\..\..\Source\mbedtls\include;.;%(AdditionalIncludeDirectories) + MBEDTLS_CONFIG_FILE="mbedtls_config.h";WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDLL + .\Debug/WIN32.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level4 + true + false + EditAndContinue + /wd4210 /wd4127 /wd4214 /wd4201 /wd4244 /wd4310 /wd4200 %(AdditionalOptions) + true + NotUsing + false + CompileAsC + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Debug/RTOSDemo.exe + true + true + .\Debug/WIN32.pdb + Console + MachineX86 + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + .\WinPCap + false + false + + + true + .\Debug/WIN32.bsc + + + + + .\Release/WIN32.tlb + + + + + MaxSpeed + OnlyExplicitInline + MBEDTLS_CONFIG_FILE="mbedtls_config.h";_WINSOCKAPI_;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release/WIN32.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + ..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;.\DemoTasks\include;.\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include\private;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\mbedtls;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\mqtt\include;..\..\..\..\Source\mbedtls\include;.;%(AdditionalIncludeDirectories) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Release/RTOSDemo.exe + true + .\Release/WIN32.pdb + Console + MachineX86 + .\WinPCap + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + + + true + .\Release/WIN32.bsc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WIN32.vcxproj.filters b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WIN32.vcxproj.filters new file mode 100644 index 000000000..53097f987 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WIN32.vcxproj.filters @@ -0,0 +1,877 @@ + + + + + {af3445a1-4908-4170-89ed-39345d90d30c} + + + {f32be356-4763-4cae-9020-974a2638cb08} + *.c + + + {88f409e6-d396-4ac5-94bd-7a99c914be46} + + + {e5ad4ec7-23dc-4295-8add-2acaee488f5a} + + + {d2dcd641-8d91-492b-852f-5563ffadaec6} + + + {8672fa26-b119-481f-8b8d-086419c01a3e} + + + {4570be11-ec96-4b55-ac58-24b50ada980a} + + + {5d93ed51-023a-41ad-9243-8d230165d34b} + + + {b71e974a-9f28-4815-972b-d930ba8a34d0} + + + {60717407-397f-4ea5-8492-3314acdd25f0} + + + {8a90222f-d723-4b4e-8e6e-c57afaf7fa92} + + + {7c995f05-2a10-4771-ad77-18a755876e46} + + + {9a636cc3-ebc6-48c5-8c18-c72494686e81} + + + {29376c48-bc8b-4624-ad59-16807874c9f2} + + + {91ef4008-de51-4b41-ba5e-bf24d8cda378} + + + {ade43c6c-04c5-4897-abdb-91af2df04e5d} + + + {08a4e35c-19ca-4b1e-af24-bac368c2bf7b} + + + {1fc5fc25-c18b-45a2-bad3-0c07795db1e9} + + + {f3a69e5b-1462-4e19-8651-274e86c252b0} + + + {9a849d9e-91e5-4035-ab4c-70a986c6aed1} + + + {1e324500-91b4-4c76-b699-59ba75691760} + + + {bdcbc1ec-99b8-4c72-9075-49035c115488} + + + {2d17d5e6-ed70-4e42-9693-f7a63baf4948} + + + {7158b0be-01e7-42d1-8d3f-c75118a596a2} + + + {6ad56e6d-c330-4830-8f4b-c75b05dfa866} + + + {1d80b387-5a86-4744-a4cc-930033a52e4b} + + + {1cecca7f-60cd-4d8d-8123-f00aa75af147} + + + {f9a2e0a1-ed56-4ca7-b8b2-d694a94c78c0} + + + {61ac8e2c-8fd1-44a0-a7a9-0326bc190426} + + + {b53bfe50-b4d9-4b78-b7bb-ae90e4d25615} + + + {6fc3dbdf-ef1b-4000-96c6-447621d2782e} + + + {ea79ce18-8bb0-4b47-be42-a2c5f2bf1afe} + + + {094110c9-8503-402f-a3b5-61b502fcea5c} + + + {e916c9ca-e771-43b8-95e1-aa833cff5a97} + + + {85805c81-540b-48fd-b34b-42c147be5898} + + + {2eecd6fc-ed08-45e3-a66e-3bc22601d51e} + + + {b09e007d-830b-440f-ae37-81dcf1e1d132} + + + {a3ff1e4c-4e65-42da-9455-a8e634d554d5} + + + {cce1678a-515a-43b2-b5e6-4c3ed1ff93cf} + + + {489acbf8-7c45-447c-80a9-7eac6fdfee26} + + + + + FreeRTOS\Source\Portable + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS\Source + + + FreeRTOS\Source\Portable + + + + FreeRTOS+\FreeRTOS+TCP + + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\mbedtls + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\jobs\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\jobs\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\jobs\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\jobs\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\jobs\src + + + DemoTasks + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\common\src + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include\types + + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos\include\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\include\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\include\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\include\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\include\platform + + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\mbedtls + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\jobs\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\jobs\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src\private + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\common\include + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/Packet32.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/Packet32.h new file mode 100644 index 000000000..1e0eacd77 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/Packet32.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + +/** @ingroup packetapi + * @{ + */ + +/** @defgroup packet32h Packet.dll definitions and data structures + * Packet32.h contains the data structures and the definitions used by packet.dll. + * The file is used both by the Win9x and the WinNTx versions of packet.dll, and can be included + * by the applications that use the functions of this library + * @{ + */ + +#ifndef __PACKET32 +#define __PACKET32 + +#include + +#ifdef HAVE_AIRPCAP_API +#include +#else +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +typedef struct _AirpcapHandle *PAirpcapHandle; +#endif /* AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ */ +#endif /* HAVE_AIRPCAP_API */ + +#ifdef HAVE_DAG_API +#include +#endif /* HAVE_DAG_API */ + +// Working modes +#define PACKET_MODE_CAPT 0x0 ///< Capture mode +#define PACKET_MODE_STAT 0x1 ///< Statistical mode +#define PACKET_MODE_MON 0x2 ///< Monitoring mode +#define PACKET_MODE_DUMP 0x10 ///< Dump mode +#define PACKET_MODE_STAT_DUMP MODE_DUMP | MODE_STAT ///< Statistical dump Mode + + +/// Alignment macro. Defines the alignment size. +#define Packet_ALIGNMENT sizeof(int) +/// Alignment macro. Rounds up to the next even multiple of Packet_ALIGNMENT. +#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1)) + +#define NdisMediumNull -1 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumCHDLC -2 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPPPSerial -3 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumBare80211 -4 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumRadio80211 -5 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPpi -6 ///< Custom linktype: NDIS doesn't provide an equivalent + +// Loopback behaviour definitions +#define NPF_DISABLE_LOOPBACK 1 ///< Drop the packets sent by the NPF driver +#define NPF_ENABLE_LOOPBACK 2 ///< Capture the packets sent by the NPF driver + +/*! + \brief Network type structure. + + This structure is used by the PacketGetNetType() function to return information on the current adapter's type and speed. +*/ +typedef struct NetType +{ + UINT LinkType; ///< The MAC of the current network adapter (see function PacketGetNetType() for more information) + ULONGLONG LinkSpeed; ///< The speed of the network in bits per second +}NetType; + + +//some definitions stolen from libpcap + +#ifndef BPF_MAJOR_VERSION + +/*! + \brief A BPF pseudo-assembly program. + + The program will be injected in the kernel by the PacketSetBPF() function and applied to every incoming packet. +*/ +struct bpf_program +{ + UINT bf_len; ///< Indicates the number of instructions of the program, i.e. the number of struct bpf_insn that will follow. + struct bpf_insn *bf_insns; ///< A pointer to the first instruction of the program. +}; + +/*! + \brief A single BPF pseudo-instruction. + + bpf_insn contains a single instruction for the BPF register-machine. It is used to send a filter program to the driver. +*/ +struct bpf_insn +{ + USHORT code; ///< Instruction type and addressing mode. + UCHAR jt; ///< Jump if true + UCHAR jf; ///< Jump if false + int k; ///< Generic field used for various purposes. +}; + +/*! + \brief Structure that contains a couple of statistics values on the current capture. + + It is used by packet.dll to return statistics about a capture session. +*/ +struct bpf_stat +{ + UINT bs_recv; ///< Number of packets that the driver received from the network adapter + ///< from the beginning of the current capture. This value includes the packets + ///< lost by the driver. + UINT bs_drop; ///< number of packets that the driver lost from the beginning of a capture. + ///< Basically, a packet is lost when the the buffer of the driver is full. + ///< In this situation the packet cannot be stored and the driver rejects it. + UINT ps_ifdrop; ///< drops by interface. XXX not yet supported + UINT bs_capt; ///< number of packets that pass the filter, find place in the kernel buffer and + ///< thus reach the application. +}; + +/*! + \brief Packet header. + + This structure defines the header associated with every packet delivered to the application. +*/ +struct bpf_hdr +{ + struct timeval bh_tstamp; ///< The timestamp associated with the captured packet. + ///< It is stored in a TimeVal structure. + UINT bh_caplen; ///< Length of captured portion. The captured portion can be different + ///< from the original packet, because it is possible (with a proper filter) + ///< to instruct the driver to capture only a portion of the packets. + UINT bh_datalen; ///< Original length of packet + USHORT bh_hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases, + ///< a padding could be added between the end of this structure and the packet + ///< data for performance reasons. This filed can be used to retrieve the actual data + ///< of the packet. +}; + +/*! + \brief Dump packet header. + + This structure defines the header associated with the packets in a buffer to be used with PacketSendPackets(). + It is simpler than the bpf_hdr, because it corresponds to the header associated by WinPcap and libpcap to a + packet in a dump file. This makes straightforward sending WinPcap dump files to the network. +*/ +struct dump_bpf_hdr{ + struct timeval ts; ///< Time stamp of the packet + UINT caplen; ///< Length of captured portion. The captured portion can smaller than the + ///< the original packet, because it is possible (with a proper filter) to + ///< instruct the driver to capture only a portion of the packets. + UINT len; ///< Length of the original packet (off wire). +}; + + +#endif + +struct bpf_stat; + +#define DOSNAMEPREFIX TEXT("Packet_") ///< Prefix added to the adapters device names to create the WinPcap devices +#define MAX_LINK_NAME_LENGTH 64 //< Maximum length of the devices symbolic links +#define NMAX_PACKET 65535 + +/*! + \brief Addresses of a network adapter. + + This structure is used by the PacketGetNetInfoEx() function to return the IP addresses associated with + an adapter. +*/ +typedef struct npf_if_addr { + struct sockaddr_storage IPAddress; ///< IP address. + struct sockaddr_storage SubnetMask; ///< Netmask for that address. + struct sockaddr_storage Broadcast; ///< Broadcast address. +}npf_if_addr; + + +#define ADAPTER_NAME_LENGTH 256 + 12 ///< Maximum length for the name of an adapter. The value is the same used by the IP Helper API. +#define ADAPTER_DESC_LENGTH 128 ///< Maximum length for the description of an adapter. The value is the same used by the IP Helper API. +#define MAX_MAC_ADDR_LENGTH 8 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. +#define MAX_NETWORK_ADDRESSES 16 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. + + +typedef struct WAN_ADAPTER_INT WAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API +typedef WAN_ADAPTER *PWAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API + +#define INFO_FLAG_NDIS_ADAPTER 0 ///< Flag for ADAPTER_INFO: this is a traditional ndis adapter +#define INFO_FLAG_NDISWAN_ADAPTER 1 ///< Flag for ADAPTER_INFO: this is a NdisWan adapter, and it's managed by WANPACKET +#define INFO_FLAG_DAG_CARD 2 ///< Flag for ADAPTER_INFO: this is a DAG card +#define INFO_FLAG_DAG_FILE 6 ///< Flag for ADAPTER_INFO: this is a DAG file +#define INFO_FLAG_DONT_EXPORT 8 ///< Flag for ADAPTER_INFO: when this flag is set, the adapter will not be listed or openend by winpcap. This allows to prevent exporting broken network adapters, like for example FireWire ones. +#define INFO_FLAG_AIRPCAP_CARD 16 ///< Flag for ADAPTER_INFO: this is an airpcap card +#define INFO_FLAG_NPFIM_DEVICE 32 + +/*! + \brief Describes an opened network adapter. + + This structure is the most important for the functioning of packet.dll, but the great part of its fields + should be ignored by the user, since the library offers functions that avoid to cope with low-level parameters +*/ +typedef struct _ADAPTER { + HANDLE hFile; ///< \internal Handle to an open instance of the NPF driver. + CHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; ///< \internal A string containing the name of the network adapter currently opened. + int NumWrites; ///< \internal Number of times a packets written on this adapter will be repeated + ///< on the wire. + HANDLE ReadEvent; ///< A notification event associated with the read calls on the adapter. + ///< It can be passed to standard Win32 functions (like WaitForSingleObject + ///< or WaitForMultipleObjects) to wait until the driver's buffer contains some + ///< data. It is particularly useful in GUI applications that need to wait + ///< concurrently on several events. In Windows NT/2000 the PacketSetMinToCopy() + ///< function can be used to define the minimum amount of data in the kernel buffer + ///< that will cause the event to be signalled. + + UINT ReadTimeOut; ///< \internal The amount of time after which a read on the driver will be released and + ///< ReadEvent will be signaled, also if no packets were captured + CHAR Name[ADAPTER_NAME_LENGTH]; + PWAN_ADAPTER pWanAdapter; + UINT Flags; ///< Adapter's flags. Tell if this adapter must be treated in a different way, using the Netmon API or the dagc API. + +#ifdef HAVE_AIRPCAP_API + PAirpcapHandle AirpcapAd; +#endif // HAVE_AIRPCAP_API + +#ifdef HAVE_NPFIM_API + void* NpfImHandle; +#endif // HAVE_NPFIM_API + +#ifdef HAVE_DAG_API + dagc_t *pDagCard; ///< Pointer to the dagc API adapter descriptor for this adapter + PCHAR DagBuffer; ///< Pointer to the buffer with the packets that is received from the DAG card + struct timeval DagReadTimeout; ///< Read timeout. The dagc API requires a timeval structure + unsigned DagFcsLen; ///< Length of the frame check sequence attached to any packet by the card. Obtained from the registry + DWORD DagFastProcess; ///< True if the user requests fast capture processing on this card. Higher level applications can use this value to provide a faster but possibly unprecise capture (for example, libpcap doesn't convert the timestamps). +#endif // HAVE_DAG_API +} ADAPTER, *LPADAPTER; + +/*! + \brief Structure that contains a group of packets coming from the driver. + + This structure defines the header associated with every packet delivered to the application. +*/ +typedef struct _PACKET { + HANDLE hEvent; ///< \deprecated Still present for compatibility with old applications. + OVERLAPPED OverLapped; ///< \deprecated Still present for compatibility with old applications. + PVOID Buffer; ///< Buffer with containing the packets. See the PacketReceivePacket() for + ///< details about the organization of the data in this buffer + UINT Length; ///< Length of the buffer + DWORD ulBytesReceived; ///< Number of valid bytes present in the buffer, i.e. amount of data + ///< received by the last call to PacketReceivePacket() + BOOLEAN bIoComplete; ///< \deprecated Still present for compatibility with old applications. +} PACKET, *LPPACKET; + +/*! + \brief Structure containing an OID request. + + It is used by the PacketRequest() function to send an OID to the interface card driver. + It can be used, for example, to retrieve the status of the error counters on the adapter, its MAC address, + the list of the multicast groups defined on it, and so on. +*/ +struct _PACKET_OID_DATA { + ULONG Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h + ///< for a complete list of valid codes. + ULONG Length; ///< Length of the data field + UCHAR Data[1]; ///< variable-lenght field that contains the information passed to or received + ///< from the adapter. +}; +typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @} + */ + +/* +BOOLEAN QueryWinPcapRegistryStringA(CHAR *SubKeyName, + CHAR *Value, + UINT *pValueLen, + CHAR *DefaultVal); + +BOOLEAN QueryWinPcapRegistryStringW(WCHAR *SubKeyName, + WCHAR *Value, + UINT *pValueLen, + WCHAR *DefaultVal); +*/ + +//--------------------------------------------------------------------------- +// EXPORTED FUNCTIONS +//--------------------------------------------------------------------------- + +PCHAR PacketGetVersion(); +PCHAR PacketGetDriverVersion(); +BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes); +BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites); +BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode); +BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout); +BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp); +BOOLEAN PacketSetLoopbackBehavior(LPADAPTER AdapterObject, UINT LoopbackBehavior); +INT PacketSetSnapLen(LPADAPTER AdapterObject,int snaplen); +BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim); +BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type); +LPADAPTER PacketOpenAdapter(PCHAR AdapterName); +BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync); +INT PacketSendPackets(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync); +LPPACKET PacketAllocatePacket(void); +VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length); +VOID PacketFreePacket(LPPACKET lpPacket); +BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync); +BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter); +BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize); +BOOLEAN PacketGetNetInfoEx(PCHAR AdapterName, npf_if_addr* buffer, PLONG NEntries); +BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData); +HANDLE PacketGetReadEvent(LPADAPTER AdapterObject); +BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len); +BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks); +BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync); +BOOL PacketStopDriver(); +VOID PacketCloseAdapter(LPADAPTER lpAdapter); +BOOLEAN PacketStartOem(PCHAR errorString, UINT errorStringLength); +BOOLEAN PacketStartOemEx(PCHAR errorString, UINT errorStringLength, ULONG flags); +PAirpcapHandle PacketGetAirPcapHandle(LPADAPTER AdapterObject); + +// +// Used by PacketStartOemEx +// +#define PACKET_START_OEM_NO_NETMON 0x00000001 + +#ifdef __cplusplus +} +#endif + +#endif //__PACKET32 diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/PacketData.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/PacketData.h new file mode 100644 index 000000000..8124db66d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/PacketData.h @@ -0,0 +1,267 @@ +char pkt1[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x30, 0x09, 0x9c, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x07, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x35, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02, +0x40, 0x00, 0xdf, 0xab, 0x00, 0x00, 0x02, 0x04, +0x05, 0xb4, 0x01, 0x01, 0x04, 0x02 }; + +char pkt2[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa6, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt3[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0x9e, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x0d, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt4[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x02, 0x27, 0x09, 0x9f, 0x40, 0x00, 0x80, 0x06, +0x6d, 0x0d, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x18, +0x42, 0xd8, 0x84, 0x3e, 0x00, 0x00, 0x47, 0x45, +0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, +0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, +0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x2c, +0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, +0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, +0x2c, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, +0x6a, 0x70, 0x65, 0x67, 0x2c, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x70, 0x6a, 0x70, 0x65, +0x67, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, +0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, +0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, +0x63, 0x65, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c, +0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, +0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, +0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20, +0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, +0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, +0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70, +0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, +0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78, +0x62, 0x61, 0x70, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, +0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d, +0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, +0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, +0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, +0x20, 0x65, 0x6e, 0x2d, 0x67, 0x62, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, +0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, +0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64, +0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x0d, 0x0a, +0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, +0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69, +0x6c, 0x6c, 0x61, 0x2f, 0x34, 0x2e, 0x30, 0x20, +0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, +0x62, 0x6c, 0x65, 0x3b, 0x20, 0x4d, 0x53, 0x49, +0x45, 0x20, 0x36, 0x2e, 0x30, 0x3b, 0x20, 0x57, +0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e, +0x54, 0x20, 0x35, 0x2e, 0x31, 0x3b, 0x20, 0x53, +0x56, 0x31, 0x3b, 0x20, 0x47, 0x6f, 0x6f, 0x67, +0x6c, 0x65, 0x54, 0x35, 0x3b, 0x20, 0x2e, 0x4e, +0x45, 0x54, 0x20, 0x43, 0x4c, 0x52, 0x20, 0x32, +0x2e, 0x30, 0x2e, 0x35, 0x30, 0x37, 0x32, 0x37, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30, +0x34, 0x35, 0x30, 0x36, 0x2e, 0x36, 0x34, 0x38, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x35, 0x2e, 0x32, +0x31, 0x30, 0x32, 0x32, 0x29, 0x0d, 0x0a, 0x48, +0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, +0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31, +0x32, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, +0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b, +0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, +0x65, 0x0d, 0x0a, 0x0d, 0x0a }; + +char pkt5[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x02, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa5, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt6[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa1, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x0a, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt7[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x02, 0x27, 0x09, 0xa2, 0x40, 0x00, 0x80, 0x06, +0x6d, 0x0a, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x18, +0x42, 0xd8, 0x84, 0x3e, 0x00, 0x00, 0x47, 0x45, +0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, +0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, +0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x2c, +0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, +0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, +0x2c, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, +0x6a, 0x70, 0x65, 0x67, 0x2c, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x70, 0x6a, 0x70, 0x65, +0x67, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, +0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, +0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, +0x63, 0x65, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c, +0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, +0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, +0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20, +0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, +0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, +0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70, +0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, +0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78, +0x62, 0x61, 0x70, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, +0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d, +0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, +0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, +0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, +0x20, 0x65, 0x6e, 0x2d, 0x67, 0x62, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, +0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, +0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64, +0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x0d, 0x0a, +0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, +0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69, +0x6c, 0x6c, 0x61, 0x2f, 0x34, 0x2e, 0x30, 0x20, +0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, +0x62, 0x6c, 0x65, 0x3b, 0x20, 0x4d, 0x53, 0x49, +0x45, 0x20, 0x36, 0x2e, 0x30, 0x3b, 0x20, 0x57, +0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e, +0x54, 0x20, 0x35, 0x2e, 0x31, 0x3b, 0x20, 0x53, +0x56, 0x31, 0x3b, 0x20, 0x47, 0x6f, 0x6f, 0x67, +0x6c, 0x65, 0x54, 0x35, 0x3b, 0x20, 0x2e, 0x4e, +0x45, 0x54, 0x20, 0x43, 0x4c, 0x52, 0x20, 0x32, +0x2e, 0x30, 0x2e, 0x35, 0x30, 0x37, 0x32, 0x37, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30, +0x34, 0x35, 0x30, 0x36, 0x2e, 0x36, 0x34, 0x38, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x35, 0x2e, 0x32, +0x31, 0x30, 0x32, 0x32, 0x29, 0x0d, 0x0a, 0x48, +0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, +0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31, +0x32, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, +0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b, +0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, +0x65, 0x0d, 0x0a, 0x0d, 0x0a }; + +char pkt8[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x03, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa4, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt9[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa3, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x08, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt10[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x04, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa3, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt11[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa6, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x05, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt12[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa7, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x04, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x14, +0x00, 0x00, 0x43, 0xf4, 0x00, 0x00 }; + + +typedef struct +{ + char *pcData; + int iDataLen; +} xPacketData; + +xPacketData xAllPackets[] = +{ + { pkt1, sizeof( pkt1 ) }, +// { pkt2, sizeof( pkt2 ) }, + { pkt3, sizeof( pkt3 ) }, + { pkt4, sizeof( pkt4 ) }, +// { pkt5, sizeof( pkt5 ) }, + { pkt6, sizeof( pkt6 ) }, + { pkt7, sizeof( pkt7 ) }, + { pkt8, sizeof( pkt8 ) }, + { pkt9, sizeof( pkt9 ) }, + { pkt10, sizeof( pkt10 ) }, +// { pkt11, sizeof( pkt11 ) }, +// { pkt12, sizeof( pkt12 ) }, +// { pkt13, sizeof( pkt13 ) }, +// { pkt14, sizeof( pkt14 ) }, +// { pkt15, sizeof( pkt15 ) }, +// { pkt16, sizeof( pkt16 ) }, +}; diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/Win32-Extensions.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/Win32-Extensions.h new file mode 100644 index 000000000..be71c85e9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/Win32-Extensions.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + + +#ifndef __WIN32_EXTENSIONS_H__ +#define __WIN32_EXTENSIONS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Definitions */ + +/*! + \brief A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit(). +*/ +struct pcap_send_queue +{ + u_int maxlen; ///< Maximum size of the the queue, in bytes. This variable contains the size of the buffer field. + u_int len; ///< Current size of the queue, in bytes. + char *buffer; ///< Buffer containing the packets to be sent. +}; + +typedef struct pcap_send_queue pcap_send_queue; + +/*! + \brief This typedef is a support for the pcap_get_airpcap_handle() function +*/ +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +typedef struct _AirpcapHandle *PAirpcapHandle; +#endif + +#define BPF_MEM_EX_IMM 0xc0 +#define BPF_MEM_EX_IND 0xe0 + +/*used for ST*/ +#define BPF_MEM_EX 0xc0 +#define BPF_TME 0x08 + +#define BPF_LOOKUP 0x90 +#define BPF_EXECUTE 0xa0 +#define BPF_INIT 0xb0 +#define BPF_VALIDATE 0xc0 +#define BPF_SET_ACTIVE 0xd0 +#define BPF_RESET 0xe0 +#define BPF_SET_MEMORY 0x80 +#define BPF_GET_REGISTER_VALUE 0x70 +#define BPF_SET_REGISTER_VALUE 0x60 +#define BPF_SET_WORKING 0x50 +#define BPF_SET_ACTIVE_READ 0x40 +#define BPF_SET_AUTODELETION 0x30 +#define BPF_SEPARATION 0xff + +/* Prototypes */ +pcap_send_queue* pcap_sendqueue_alloc(u_int memsize); + +void pcap_sendqueue_destroy(pcap_send_queue* queue); + +int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data); + +u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync); + +HANDLE pcap_getevent(pcap_t *p); + +struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size); + +int pcap_setuserbuffer(pcap_t *p, int size); + +int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks); + +int pcap_live_dump_ended(pcap_t *p, int sync); + +int pcap_offline_filter(struct bpf_program *prog, const struct pcap_pkthdr *header, const u_char *pkt_data); + +int pcap_start_oem(char* err_str, int flags); + +PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p); + +#ifdef __cplusplus +} +#endif + +#endif //__WIN32_EXTENSIONS_H__ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/arch.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/arch.c new file mode 100644 index 000000000..02bf82bf9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/arch.c @@ -0,0 +1,336 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* WinPCap includes. */ +#include "pcap.h" +#include "remote-ext.h" + +/* uIP includes. */ +#include "net/uip.h" +#include "net/uip_arp.h" +#include "net/clock-arch.h" + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* + * Query the computer the simulation is being executed on to find the network + * interfaces it has installed. + */ +static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ); + +/* + * Open the network interface. The number of the interface to be opened is set + * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. + */ +static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ); + +/* + * Configure the capture filter to allow blocking reads, and to filter out + * packets that are not of interest to this demo. + */ +static void prvConfigureCaptureBehaviour( void ); + +pcap_t *pxOpenedInterfaceHandle = NULL; +LARGE_INTEGER freq, sys_start_time; + +#define archNUM_BUFFERS 5 +#define archNUM_BUFFER_POINTERS ( archNUM_BUFFERS - 1 ) + +static void prvInterruptSimulator( void *pvParameters ); + +static unsigned char ucEthernetBuffer[ archNUM_BUFFERS ][ UIP_CONF_BUFFER_SIZE ]; +static unsigned char *pucEthernetBufferPointers[ archNUM_BUFFER_POINTERS ]; + +static long lLengthOfDataInBuffer[ archNUM_BUFFER_POINTERS ] = { 0 }; +static unsigned char ucNextBufferToFill = 0U, ucNextBufferToProcess = 0U; + +unsigned char *uip_buf = NULL; +char cErrorBuffer[PCAP_ERRBUF_SIZE]; + +void vNetifTx( void ) +{ + pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len ); + pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len ); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxNetifRx( void ) +{ +UBaseType_t xDataLen; +unsigned char *pucTemp; + + /* Check there is really data available. */ + xDataLen = lLengthOfDataInBuffer[ ucNextBufferToProcess ]; + if( xDataLen != 0L ) + { + + /* The buffer pointed to by uip_buf is going to change. Remember which + buffer uip_buf is currently pointing to. */ + pucTemp = uip_buf; + + /* Point uip_buf at the next buffer that contains data. */ + uip_buf = pucEthernetBufferPointers[ ucNextBufferToProcess ]; + + /* The buffer pointed to by + pucEthernetBufferPointeres[ ucNextBufferToProcess ] is now in use by + uip_buf, but the buffer uip_buf was pointing to on entry to this + function is free. Set + pucEthernetBufferPointeres[ ucNextBufferToProcess ] to the free + buffer. */ + pucEthernetBufferPointers[ ucNextBufferToProcess ] = pucTemp; + lLengthOfDataInBuffer[ ucNextBufferToProcess ] = 0L; + + ucNextBufferToProcess++; + if( ucNextBufferToProcess >= archNUM_BUFFER_POINTERS ) + { + ucNextBufferToProcess = 0L; + } + } + + return xDataLen; +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetifInit( void ) +{ +BaseType_t x; +pcap_if_t *pxAllNetworkInterfaces; + + /* Allocate a free buffer to each buffer pointer. */ + for( x = 0; x < sizeof( pucEthernetBufferPointers ) / sizeof( unsigned char * ); x++ ) + { + pucEthernetBufferPointers[ x ] = &( ucEthernetBuffer[ x ][ 0 ] ); + } + + /* Start with uip_buf pointing to a buffer that is not referenced from the + pucEthernetBufferPointers[] array. */ + uip_buf = &( ucEthernetBuffer[ archNUM_BUFFERS - 1 ][ 0 ] ); + + /* Query the computer the simulation is being executed on to find the + network interfaces it has installed. */ + pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces(); + + /* Open the network interface. The number of the interface to be opened is + set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. + Calling this function will set the pxOpenedInterfaceHandle variable. If, + after calling this function, pxOpenedInterfaceHandle is equal to NULL, then + the interface could not be opened. */ + if( pxAllNetworkInterfaces != NULL ) + { + prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces ); + } + + + return x; +} +/*-----------------------------------------------------------*/ + +static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ) +{ +pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface; +long lInterfaceNumber = 1; + + if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 ) + { + printf( "\r\nCould not obtain a list of network interfaces\r\n%s\r\n", cErrorBuffer ); + pxAllNetworkInterfaces = NULL; + } + + if( pxAllNetworkInterfaces != NULL ) + { + /* Print out the list of network interfaces. The first in the list + is interface '1', not interface '0'. */ + for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next ) + { + printf( "%d. %s", lInterfaceNumber, xInterface->name ); + + if( xInterface->description != NULL ) + { + printf( " (%s)\r\n", xInterface->description ); + } + else + { + printf( " (No description available)\r\n") ; + } + + lInterfaceNumber++; + } + } + + if( lInterfaceNumber == 1 ) + { + /* The interface number was never incremented, so the above for() loop + did not execute meaning no interfaces were found. */ + printf( " \r\nNo network interfaces were found.\r\n" ); + pxAllNetworkInterfaces = NULL; + } + + printf( "\r\nThe interface that will be opened is set by configNETWORK_INTERFACE_TO_USE which should be defined in FreeRTOSConfig.h\r\n" ); + printf( "Attempting to open interface number %d.\r\n", configNETWORK_INTERFACE_TO_USE ); + + if( ( configNETWORK_INTERFACE_TO_USE < 1L ) || ( configNETWORK_INTERFACE_TO_USE > lInterfaceNumber ) ) + { + printf("\r\nconfigNETWORK_INTERFACE_TO_USE is not in the valid range.\r\n" ); + + if( pxAllNetworkInterfaces != NULL ) + { + /* Free the device list, as no devices are going to be opened. */ + pcap_freealldevs( pxAllNetworkInterfaces ); + pxAllNetworkInterfaces = NULL; + } + } + + return pxAllNetworkInterfaces; +} +/*-----------------------------------------------------------*/ + +static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ) +{ +pcap_if_t *xInterface; +long x; + + /* Walk the list of devices until the selected device is located. */ + xInterface = pxAllNetworkInterfaces; + for( x = 0L; x < ( configNETWORK_INTERFACE_TO_USE - 1L ); x++ ) + { + xInterface = xInterface->next; + } + + /* Open the selected interface. */ + pxOpenedInterfaceHandle = pcap_open( xInterface->name, /* The name of the selected interface. */ + UIP_CONF_BUFFER_SIZE, /* The size of the packet to capture. */ + PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscious mode as the MAC and + IP address is going to be "simulated", and + not be the real MAC and IP address. This allows + trafic to the simulated IP address to be routed + to uIP, and trafic to the real IP address to be + routed to the Windows TCP/IP stack. */ + 0xfffffffL, /* The read time out. This is going to block + until data is available. */ + NULL, /* No authentication is required as this is + not a remote capture session. */ + cErrorBuffer + ); + + if ( pxOpenedInterfaceHandle == NULL ) + { + printf( "\r\n%s is not supported by WinPcap and cannot be opened\r\n", xInterface->name ); + } + else + { + /* Configure the capture filter to allow blocking reads, and to filter + out packets that are not of interest to this demo. */ + prvConfigureCaptureBehaviour(); + } + + /* The device list is no longer required. */ + pcap_freealldevs( pxAllNetworkInterfaces ); +} +/*-----------------------------------------------------------*/ + +static void prvConfigureCaptureBehaviour( void ) +{ +struct bpf_program xFilterCode; +const long lMinBytesToCopy = 10L, lBlocking = 0L; +unsigned long ulNetMask; + + /* Unblock a read as soon as anything is received. */ + pcap_setmintocopy( pxOpenedInterfaceHandle, lMinBytesToCopy ); + + /* Allow blocking. */ + pcap_setnonblock( pxOpenedInterfaceHandle, lBlocking, cErrorBuffer ); + + /* Set up a filter so only the packets of interest are passed to the uIP + stack. cErrorBuffer is used for convenience to create the string. Don't + confuse this with an error message. */ + sprintf( cErrorBuffer, "broadcast or multicast or host %d.%d.%d.%d", configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 ); + + ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0; + + if( pcap_compile(pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 ) + { + printf("\r\nThe packet filter string is invalid\r\n" ); + } + else + { + if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 ) + { + printf( "\r\nAn error occurred setting the packet filter.\r\n" ); + } + } + + /* Create a task that simulates an interrupt in a real system. This will + block waiting for packets, then send a message to the uIP task when data + is available. */ + xTaskCreate( prvInterruptSimulator, ( signed char * ) "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, ( configuIP_TASK_PRIORITY - 1 ), NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvInterruptSimulator( void *pvParameters ) +{ +static struct pcap_pkthdr *pxHeader; +const unsigned char *pucPacketData; +extern QueueHandle_t xEMACEventQueue; +const unsigned long ulRxEvent = uipETHERNET_RX_EVENT; +long lResult; + + /* Just to kill the compiler warning. */ + ( void ) pvParameters; + + for( ;; ) + { + /* Get the next packet. */ + lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData ); + if( lResult ) + { + /* Is the next buffer into which data should be placed free? */ + if( lLengthOfDataInBuffer[ ucNextBufferToFill ] == 0L ) + { + /* Copy the data from the captured packet into the buffer. */ + memcpy( pucEthernetBufferPointers[ ucNextBufferToFill ], pucPacketData, pxHeader->len ); + + /* Note the amount of data that was copied. */ + lLengthOfDataInBuffer[ ucNextBufferToFill ] = pxHeader->len; + + /* Move onto the next buffer, wrapping around if necessary. */ + ucNextBufferToFill++; + if( ucNextBufferToFill >= archNUM_BUFFER_POINTERS ) + { + ucNextBufferToFill = 0U; + } + + /* Data was received and stored. Send a message to the uIP task + to let it know. */ + xQueueSendToBack( xEMACEventQueue, &ulRxEvent, portMAX_DELAY ); + } + } + } +} + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/bittypes.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/bittypes.h new file mode 100644 index 000000000..fcacd45fe --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/bittypes.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 1999 WIDE Project. + * 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. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. + */ +#ifndef _BITTYPES_H +#define _BITTYPES_H + +#ifndef HAVE_U_INT8_T + +#if SIZEOF_CHAR == 1 +typedef unsigned char u_int8_t; +typedef signed char _int8_t; +#elif SIZEOF_INT == 1 +typedef unsigned int u_int8_t; +typedef signed int int8_t; +#else /* XXX */ +#error "there's no appropriate type for u_int8_t" +#endif +#define HAVE_U_INT8_T 1 +#define HAVE_INT8_T 1 + +#endif /* HAVE_U_INT8_T */ + +#ifndef HAVE_U_INT16_T + +#if SIZEOF_SHORT == 2 +typedef unsigned short u_int16_t; +typedef signed short _int16_t; +#elif SIZEOF_INT == 2 +typedef unsigned int u_int16_t; +typedef signed int int16_t; +#elif SIZEOF_CHAR == 2 +typedef unsigned char u_int16_t; +typedef signed char int16_t; +#else /* XXX */ +#error "there's no appropriate type for u_int16_t" +#endif +#define HAVE_U_INT16_T 1 +#define HAVE_INT16_T 1 + +#endif /* HAVE_U_INT16_T */ + +#ifndef HAVE_U_INT32_T + +#if SIZEOF_INT == 4 +typedef unsigned int u_int32_t; +typedef signed int _int32_t; +#elif SIZEOF_LONG == 4 +typedef unsigned long u_int32_t; +typedef signed long int32_t; +#elif SIZEOF_SHORT == 4 +typedef unsigned short u_int32_t; +typedef signed short int32_t; +#else /* XXX */ +#error "there's no appropriate type for u_int32_t" +#endif +#define HAVE_U_INT32_T 1 +#define HAVE_INT32_T 1 + +#endif /* HAVE_U_INT32_T */ + +#ifndef HAVE_U_INT64_T +#if SIZEOF_LONG_LONG == 8 +typedef unsigned long long u_int64_t; +typedef long long int64_t; +#elif defined(_MSC_EXTENSIONS) +typedef unsigned _int64 u_int64_t; +typedef _int64 int64_t; +#elif SIZEOF_INT == 8 +typedef unsigned int u_int64_t; +#elif SIZEOF_LONG == 8 +typedef unsigned long u_int64_t; +#elif SIZEOF_SHORT == 8 +typedef unsigned short u_int64_t; +#else /* XXX */ +#error "there's no appropriate type for u_int64_t" +#endif + +#endif /* HAVE_U_INT64_T */ + +#ifndef PRId64 +#ifdef _MSC_EXTENSIONS +#define PRId64 "I64d" +#else /* _MSC_EXTENSIONS */ +#define PRId64 "lld" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRId64 */ + +#ifndef PRIo64 +#ifdef _MSC_EXTENSIONS +#define PRIo64 "I64o" +#else /* _MSC_EXTENSIONS */ +#define PRIo64 "llo" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIo64 */ + +#ifndef PRIx64 +#ifdef _MSC_EXTENSIONS +#define PRIx64 "I64x" +#else /* _MSC_EXTENSIONS */ +#define PRIx64 "llx" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIx64 */ + +#ifndef PRIu64 +#ifdef _MSC_EXTENSIONS +#define PRIu64 "I64u" +#else /* _MSC_EXTENSIONS */ +#define PRIu64 "llu" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIu64 */ + +#endif /* _BITTYPES_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/ip6_misc.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/ip6_misc.h new file mode 100644 index 000000000..96822d0e8 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/ip6_misc.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1993, 1994, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: /tcpdump/master/libpcap/Win32/Include/ip6_misc.h,v 1.5 2006-01-22 18:02:18 gianluca Exp $ (LBL) + */ + +/* + * This file contains a collage of declarations for IPv6 from FreeBSD not present in Windows + */ + +#include + +#include + +#ifndef __MINGW32__ +#define IN_MULTICAST(a) IN_CLASSD(a) +#endif + +#define IN_EXPERIMENTAL(a) ((((u_int32_t) (a)) & 0xf0000000) == 0xf0000000) + +#define IN_LOOPBACKNET 127 + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +/* IPv6 address */ +struct in6_addr + { + union + { + u_int8_t u6_addr8[16]; + u_int16_t u6_addr16[8]; + u_int32_t u6_addr32[4]; + } in6_u; +#define s6_addr in6_u.u6_addr8 +#define s6_addr16 in6_u.u6_addr16 +#define s6_addr32 in6_u.u6_addr32 +#define s6_addr64 in6_u.u6_addr64 + }; + +#define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } +#endif /* __MINGW32__ */ + + +#if (defined _MSC_VER) || (defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)) +typedef unsigned short sa_family_t; +#endif + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) + +#define __SOCKADDR_COMMON(sa_prefix) \ + sa_family_t sa_prefix##family + +/* Ditto, for IPv6. */ +struct sockaddr_in6 + { + __SOCKADDR_COMMON (sin6_); + u_int16_t sin6_port; /* Transport layer port # */ + u_int32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + }; + +#define IN6_IS_ADDR_V4MAPPED(a) \ + ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \ + (((u_int32_t *) (a))[2] == htonl (0xffff))) + +#define IN6_IS_ADDR_MULTICAST(a) (((u_int8_t *) (a))[0] == 0xff) + +#define IN6_IS_ADDR_LINKLOCAL(a) \ + ((((u_int32_t *) (a))[0] & htonl (0xffc00000)) == htonl (0xfe800000)) + +#define IN6_IS_ADDR_LOOPBACK(a) \ + (((u_int32_t *) (a))[0] == 0 && ((u_int32_t *) (a))[1] == 0 && \ + ((u_int32_t *) (a))[2] == 0 && ((u_int32_t *) (a))[3] == htonl (1)) +#endif /* __MINGW32__ */ + +#define ip6_vfc ip6_ctlun.ip6_un2_vfc +#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt +#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim +#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim + +#define nd_rd_type nd_rd_hdr.icmp6_type +#define nd_rd_code nd_rd_hdr.icmp6_code +#define nd_rd_cksum nd_rd_hdr.icmp6_cksum +#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0] + +/* + * IPV6 extension headers + */ +#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */ +#define IPPROTO_IPV6 41 /* IPv6 header. */ +#define IPPROTO_ROUTING 43 /* IPv6 routing header */ +#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ +#define IPPROTO_ESP 50 /* encapsulating security payload */ +#define IPPROTO_AH 51 /* authentication header */ +#define IPPROTO_ICMPV6 58 /* ICMPv6 */ +#define IPPROTO_NONE 59 /* IPv6 no next header */ +#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ +#define IPPROTO_PIM 103 /* Protocol Independent Multicast. */ + +#define IPV6_RTHDR_TYPE_0 0 + +/* Option types and related macros */ +#define IP6OPT_PAD1 0x00 /* 00 0 00000 */ +#define IP6OPT_PADN 0x01 /* 00 0 00001 */ +#define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ +#define IP6OPT_JUMBO_LEN 6 +#define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 */ + +#define IP6OPT_RTALERT_LEN 4 +#define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ +#define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ +#define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ +#define IP6OPT_MINLEN 2 + +#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */ +#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */ +#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */ +#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */ +#define IP6OPT_EID 0x8a /* 10 0 01010 */ + +#define IP6OPT_TYPE(o) ((o) & 0xC0) +#define IP6OPT_TYPE_SKIP 0x00 +#define IP6OPT_TYPE_DISCARD 0x40 +#define IP6OPT_TYPE_FORCEICMP 0x80 +#define IP6OPT_TYPE_ICMP 0xC0 + +#define IP6OPT_MUTABLE 0x20 + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +#ifndef EAI_ADDRFAMILY +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; +#endif +#endif /* __MINGW32__ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/netif.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/netif.h new file mode 100644 index 000000000..2d51478c0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/netif.h @@ -0,0 +1,52 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef NET_IF_H +#define NET_IF_H + +/* + * Send uip_len bytes from uip_buf to the network interface selected by the + * configNETWORK_INTERFACE_TO_USE constant (defined in FreeRTOSConfig.h). + */ +void vNetifTx( void ); + +/* + * Receive bytes from the network interface selected by the + * configNETWORK_INTERFACE_TO_USE constant (defined in FreeRTOSConfig.h). The + * bytes are placed in uip_buf. The number of bytes copied into uip_buf is + * returned. + */ +UBaseType_t uxNetifRx( void ); + +/* + * Prepare a packet capture session. This will print out all the network + * interfaces available, and the one actually used is set by the + * configNETWORK_INTERFACE_TO_USE constant that is defined in + * FreeRTOSConfig.h. */ +BaseType_t xNetifInit( void ); + +#endif /* NET_IF_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap-bpf.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap-bpf.h new file mode 100644 index 000000000..ff5b6e0da --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap-bpf.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.50 2007/04/01 21:43:55 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap-namedb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap-namedb.h new file mode 100644 index 000000000..ee6715fba --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap-namedb.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-namedb.h,v 1.13 2006/10/04 18:13:32 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap-stdinc.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap-stdinc.h new file mode 100644 index 000000000..cbd62d169 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap-stdinc.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-stdinc.h,v 1.10.2.1 2008-10-06 15:38:39 gianluca Exp $ (LBL) + */ + +#define SIZEOF_CHAR 1 +#define SIZEOF_SHORT 2 +#define SIZEOF_INT 4 +#ifndef _MSC_EXTENSIONS +#define SIZEOF_LONG_LONG 8 +#endif + +/* + * Avoids a compiler warning in case this was already defined + * (someone defined _WINSOCKAPI_ when including 'windows.h', in order + * to prevent it from including 'winsock.h') + */ +#ifdef _WINSOCKAPI_ +#undef _WINSOCKAPI_ +#endif +#include + +#include + +#include "bittypes.h" +#include +#include + +#ifndef __MINGW32__ +#include "IP6_misc.h" +#endif + +#define caddr_t char* + +#if _MSC_VER < 1500 +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#define strdup _strdup +#endif + +#define inline __inline + +#ifdef __MINGW32__ +#include +#else /*__MINGW32__*/ +/* MSVC compiler */ +#ifndef _UINTPTR_T_DEFINED +#ifdef _WIN64 +typedef unsigned __int64 uintptr_t; +#else +typedef _W64 unsigned int uintptr_t; +#endif +#define _UINTPTR_T_DEFINED +#endif + +#ifndef _INTPTR_T_DEFINED +#ifdef _WIN64 +typedef __int64 intptr_t; +#else +typedef _W64 int intptr_t; +#endif +#define _INTPTR_T_DEFINED +#endif + +#endif /*__MINGW32__*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap.h new file mode 100644 index 000000000..2eea0750b --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.59 2006/10/04 18:09:22 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Many applications + * expect to be able to include , and at least some of them + * go through contortions in their configure scripts to try to detect + * OSes that have "helpfully" moved pcap.h to without + * leaving behind a file. + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/bluetooth.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/bluetooth.h new file mode 100644 index 000000000..28b991f43 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/bluetooth.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * bluetooth data struct + * By Paolo Abeni + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/bluetooth.h,v 1.1 2007/09/22 02:10:17 guy Exp $ + */ + +#ifndef _PCAP_BLUETOOTH_STRUCTS_H__ +#define _PCAP_BLUETOOTH_STRUCTS_H__ + +/* + * Header prepended libpcap to each bluetooth h:4 frame. + * fields are in network byte order + */ +typedef struct _pcap_bluetooth_h4_header { + u_int32_t direction; /* if first bit is set direction is incoming */ +} pcap_bluetooth_h4_header; + + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/bpf.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/bpf.h new file mode 100644 index 000000000..b6d259679 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/bpf.h @@ -0,0 +1,934 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)bpf.h 7.1 (Berkeley) 5/7/91 + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/bpf.h,v 1.19.2.8 2008-09-22 20:16:01 guy Exp $ (LBL) + */ + +/* + * This is libpcap's cut-down version of bpf.h; it includes only + * the stuff needed for the code generator and the userland BPF + * interpreter, and the libpcap APIs for setting filters, etc.. + * + * "pcap-bpf.c" will include the native OS version, as it deals with + * the OS's BPF implementation. + * + * XXX - should this all just be moved to "pcap.h"? + */ + +#ifndef BPF_MAJOR_VERSION + +#ifdef __cplusplus +extern "C" { +#endif + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +#ifdef MSDOS /* must be 32-bit */ +typedef long bpf_int32; +typedef unsigned long bpf_u_int32; +#else +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +/* + * Alignment macros. BPF_WORDALIGN rounds up to the next + * even multiple of BPF_ALIGNMENT. + */ +#ifndef __NetBSD__ +#define BPF_ALIGNMENT sizeof(bpf_int32) +#else +#define BPF_ALIGNMENT sizeof(long) +#endif +#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) + +#define BPF_MAXBUFSIZE 0x8000 +#define BPF_MINBUFSIZE 32 + +/* + * Structure for "pcap_compile()", "pcap_setfilter()", etc.. + */ +struct bpf_program { + u_int bf_len; + struct bpf_insn *bf_insns; +}; + +/* + * Struct return by BIOCVERSION. This represents the version number of + * the filter language described by the instruction encodings below. + * bpf understands a program iff kernel_major == filter_major && + * kernel_minor >= filter_minor, that is, if the value returned by the + * running kernel has the same major number and a minor number equal + * equal to or less than the filter being downloaded. Otherwise, the + * results are undefined, meaning an error may be returned or packets + * may be accepted haphazardly. + * It has nothing to do with the source code version. + */ +struct bpf_version { + u_short bv_major; + u_short bv_minor; +}; +/* Current version number of filter architecture. */ +#define BPF_MAJOR_VERSION 1 +#define BPF_MINOR_VERSION 1 + +/* + * Data-link level type codes. + * + * Do *NOT* add new values to this list without asking + * "tcpdump-workers@lists.tcpdump.org" for a value. Otherwise, you run + * the risk of using a value that's already being used for some other + * purpose, and of having tools that read libpcap-format captures not + * being able to handle captures with your new DLT_ value, with no hope + * that they will ever be changed to do so (as that would destroy their + * ability to read captures using that value for that other purpose). + */ + +/* + * These are the types that are the same on all platforms, and that + * have been defined by for ages. + */ +#define DLT_NULL 0 /* BSD loopback encapsulation */ +#define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ +#define DLT_AX25 3 /* Amateur Radio AX.25 */ +#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ +#define DLT_CHAOS 5 /* Chaos */ +#define DLT_IEEE802 6 /* 802.5 Token Ring */ +#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ +#define DLT_SLIP 8 /* Serial Line IP */ +#define DLT_PPP 9 /* Point-to-point Protocol */ +#define DLT_FDDI 10 /* FDDI */ + +/* + * These are types that are different on some platforms, and that + * have been defined by for ages. We use #ifdefs to + * detect the BSDs that define them differently from the traditional + * libpcap + * + * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS, + * but I don't know what the right #define is for BSD/OS. + */ +#define DLT_ATM_RFC1483 11 /* LLC-encapsulated ATM */ + +#ifdef __OpenBSD__ +#define DLT_RAW 14 /* raw IP */ +#else +#define DLT_RAW 12 /* raw IP */ +#endif + +/* + * Given that the only OS that currently generates BSD/OS SLIP or PPP + * is, well, BSD/OS, arguably everybody should have chosen its values + * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they + * didn't. So it goes. + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) +#ifndef DLT_SLIP_BSDOS +#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ +#endif +#else +#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ +#endif + +/* + * 17 is used for DLT_OLD_PFLOG in OpenBSD; + * OBSOLETE: DLT_PFLOG is 117 in OpenBSD now as well. See below. + * 18 is used for DLT_PFSYNC in OpenBSD; don't use it for anything else. + */ + +#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ + +/* + * Apparently Redback uses this for its SmartEdge 400/800. I hope + * nobody else decided to use it, too. + */ +#define DLT_REDBACK_SMARTEDGE 32 + +/* + * These values are defined by NetBSD; other platforms should refrain from + * using them for other purposes, so that NetBSD savefiles with link + * types of 50 or 51 can be read as this type on all platforms. + */ +#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ +#define DLT_PPP_ETHER 51 /* PPP over Ethernet */ + +/* + * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses + * a link-layer type of 99 for the tcpdump it supplies. The link-layer + * header has 6 bytes of unknown data, something that appears to be an + * Ethernet type, and 36 bytes that appear to be 0 in at least one capture + * I've seen. + */ +#define DLT_SYMANTEC_FIREWALL 99 + +/* + * Values between 100 and 103 are used in capture file headers as + * link-layer types corresponding to DLT_ types that differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * This value was defined by libpcap 0.5; platforms that have defined + * it with a different value should define it here with that value - + * a link type of 104 in a save file will be mapped to DLT_C_HDLC, + * whatever value that happens to be, so programs will correctly + * handle files with that link type regardless of the value of + * DLT_C_HDLC. + * + * The name DLT_C_HDLC was used by BSD/OS; we use that name for source + * compatibility with programs written for BSD/OS. + * + * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, + * for source compatibility with programs written for libpcap 0.5. + */ +#define DLT_C_HDLC 104 /* Cisco HDLC */ +#define DLT_CHDLC DLT_C_HDLC + +#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ + +/* + * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW, + * except when it isn't. (I.e., sometimes it's just raw IP, and + * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL, + * so that we don't have to worry about the link-layer header.) + */ + +/* + * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides + * with other values. + * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header + * (DLCI, etc.). + */ +#define DLT_FRELAY 107 + +/* + * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except + * that the AF_ type in the link-layer header is in network byte order. + * + * DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so + * we don't use 12 for it in OSes other than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_LOOP 12 +#else +#define DLT_LOOP 108 +#endif + +/* + * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's + * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other + * than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_ENC 13 +#else +#define DLT_ENC 109 +#endif + +/* + * Values between 110 and 112 are reserved for use in capture file headers + * as link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ types + * other than the corresponding DLT_ types. + */ + +/* + * This is for Linux cooked sockets. + */ +#define DLT_LINUX_SLL 113 + +/* + * Apple LocalTalk hardware. + */ +#define DLT_LTALK 114 + +/* + * Acorn Econet. + */ +#define DLT_ECONET 115 + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define DLT_IPFILTER 116 + +/* + * OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, but that's DLT_LANE8023 + * in SuSE 6.3, so we can't use 17 for it in capture-file headers. + * + * XXX: is there a conflict with DLT_PFSYNC 18 as well? + */ +#ifdef __OpenBSD__ +#define DLT_OLD_PFLOG 17 +#define DLT_PFSYNC 18 +#endif +#define DLT_PFLOG 117 + +/* + * Registered for Cisco-internal use. + */ +#define DLT_CISCO_IOS 118 + +/* + * For 802.11 cards using the Prism II chips, with a link-layer + * header including Prism monitor mode information plus an 802.11 + * header. + */ +#define DLT_PRISM_HEADER 119 + +/* + * Reserved for Aironet 802.11 cards, with an Aironet link-layer header + * (see Doug Ambrisko's FreeBSD patches). + */ +#define DLT_AIRONET_HEADER 120 + +/* + * Reserved for Siemens HiPath HDLC. + */ +#define DLT_HHDLC 121 + +/* + * This is for RFC 2625 IP-over-Fibre Channel. + * + * This is not for use with raw Fibre Channel, where the link-layer + * header starts with a Fibre Channel frame header; it's for IP-over-FC, + * where the link-layer header starts with an RFC 2625 Network_Header + * field. + */ +#define DLT_IP_OVER_FC 122 + +/* + * This is for Full Frontal ATM on Solaris with SunATM, with a + * pseudo-header followed by an AALn PDU. + * + * There may be other forms of Full Frontal ATM on other OSes, + * with different pseudo-headers. + * + * If ATM software returns a pseudo-header with VPI/VCI information + * (and, ideally, packet type information, e.g. signalling, ILMI, + * LANE, LLC-multiplexed traffic, etc.), it should not use + * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump + * and the like don't have to infer the presence or absence of a + * pseudo-header and the form of the pseudo-header. + */ +#define DLT_SUNATM 123 /* Solaris+SunATM */ + +/* + * Reserved as per request from Kent Dahlgren + * for private use. + */ +#define DLT_RIO 124 /* RapidIO */ +#define DLT_PCI_EXP 125 /* PCI Express */ +#define DLT_AURORA 126 /* Xilinx Aurora link layer */ + +/* + * Header for 802.11 plus a number of bits of link-layer information + * including radio information, used by some recent BSD drivers as + * well as the madwifi Atheros driver for Linux. + */ +#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */ + +/* + * Reserved for the TZSP encapsulation, as per request from + * Chris Waters + * TZSP is a generic encapsulation for any other link type, + * which includes a means to include meta-information + * with the packet, e.g. signal strength and channel + * for 802.11 packets. + */ +#define DLT_TZSP 128 /* Tazmen Sniffer Protocol */ + +/* + * BSD's ARCNET headers have the source host, destination host, + * and type at the beginning of the packet; that's what's handed + * up to userland via BPF. + * + * Linux's ARCNET headers, however, have a 2-byte offset field + * between the host IDs and the type; that's what's handed up + * to userland via PF_PACKET sockets. + * + * We therefore have to have separate DLT_ values for them. + */ +#define DLT_ARCNET_LINUX 129 /* ARCNET */ + +/* + * Juniper-private data link types, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MLPPP 130 +#define DLT_JUNIPER_MLFR 131 +#define DLT_JUNIPER_ES 132 +#define DLT_JUNIPER_GGSN 133 +#define DLT_JUNIPER_MFR 134 +#define DLT_JUNIPER_ATM2 135 +#define DLT_JUNIPER_SERVICES 136 +#define DLT_JUNIPER_ATM1 137 + +/* + * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund + * . The header that's presented is an Ethernet-like + * header: + * + * #define FIREWIRE_EUI64_LEN 8 + * struct firewire_header { + * u_char firewire_dhost[FIREWIRE_EUI64_LEN]; + * u_char firewire_shost[FIREWIRE_EUI64_LEN]; + * u_short firewire_type; + * }; + * + * with "firewire_type" being an Ethernet type value, rather than, + * for example, raw GASP frames being handed up. + */ +#define DLT_APPLE_IP_OVER_IEEE1394 138 + +/* + * Various SS7 encapsulations, as per a request from Jeff Morriss + * and subsequent discussions. + */ +#define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */ +#define DLT_MTP2 140 /* MTP2, without pseudo-header */ +#define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */ +#define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */ + +/* + * DOCSIS MAC frames. + */ +#define DLT_DOCSIS 143 + +/* + * Linux-IrDA packets. Protocol defined at http://www.irda.org. + * Those packets include IrLAP headers and above (IrLMP...), but + * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy + * framing can be handled by the hardware and depend on the bitrate. + * This is exactly the format you would get capturing on a Linux-IrDA + * interface (irdaX), but not on a raw serial port. + * Note the capture is done in "Linux-cooked" mode, so each packet include + * a fake packet header (struct sll_header). This is because IrDA packet + * decoding is dependant on the direction of the packet (incomming or + * outgoing). + * When/if other platform implement IrDA capture, we may revisit the + * issue and define a real DLT_IRDA... + * Jean II + */ +#define DLT_LINUX_IRDA 144 + +/* + * Reserved for IBM SP switch and IBM Next Federation switch. + */ +#define DLT_IBM_SP 145 +#define DLT_IBM_SN 146 + +/* + * Reserved for private use. If you have some link-layer header type + * that you want to use within your organization, with the capture files + * using that link-layer header type not ever be sent outside your + * organization, you can use these values. + * + * No libpcap release will use these for any purpose, nor will any + * tcpdump release use them, either. + * + * Do *NOT* use these in capture files that you expect anybody not using + * your private versions of capture-file-reading tools to read; in + * particular, do *NOT* use them in products, otherwise you may find that + * people won't be able to use tcpdump, or snort, or Ethereal, or... to + * read capture files from your firewall/intrusion detection/traffic + * monitoring/etc. appliance, or whatever product uses that DLT_ value, + * and you may also find that the developers of those applications will + * not accept patches to let them read those files. + * + * Also, do not use them if somebody might send you a capture using them + * for *their* private type and tools using them for *your* private type + * would have to read them. + * + * Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value, + * as per the comment above, and use the type you're given. + */ +#define DLT_USER0 147 +#define DLT_USER1 148 +#define DLT_USER2 149 +#define DLT_USER3 150 +#define DLT_USER4 151 +#define DLT_USER5 152 +#define DLT_USER6 153 +#define DLT_USER7 154 +#define DLT_USER8 155 +#define DLT_USER9 156 +#define DLT_USER10 157 +#define DLT_USER11 158 +#define DLT_USER12 159 +#define DLT_USER13 160 +#define DLT_USER14 161 +#define DLT_USER15 162 + +/* + * For future use with 802.11 captures - defined by AbsoluteValue + * Systems to store a number of bits of link-layer information + * including radio information: + * + * http://www.shaftnet.org/~pizza/software/capturefrm.txt + * + * but it might be used by some non-AVS drivers now or in the + * future. + */ +#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MONITOR 164 + +/* + * Reserved for BACnet MS/TP. + */ +#define DLT_BACNET_MS_TP 165 + +/* + * Another PPP variant as per request from Karsten Keil . + * + * This is used in some OSes to allow a kernel socket filter to distinguish + * between incoming and outgoing packets, on a socket intended to + * supply pppd with outgoing packets so it can do dial-on-demand and + * hangup-on-lack-of-demand; incoming packets are filtered out so they + * don't cause pppd to hold the connection up (you don't want random + * input packets such as port scans, packets from old lost connections, + * etc. to force the connection to stay up). + * + * The first byte of the PPP header (0xff03) is modified to accomodate + * the direction - 0x00 = IN, 0x01 = OUT. + */ +#define DLT_PPP_PPPD 166 + +/* + * Names for backwards compatibility with older versions of some PPP + * software; new software should use DLT_PPP_PPPD. + */ +#define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD +#define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, cookies, etc.. + */ +#define DLT_JUNIPER_PPPOE 167 +#define DLT_JUNIPER_PPPOE_ATM 168 + +#define DLT_GPRS_LLC 169 /* GPRS LLC */ +#define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ +#define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ + +/* + * Requested by Oolan Zimmer for use in Gcom's T1/E1 line + * monitoring equipment. + */ +#define DLT_GCOM_T1E1 172 +#define DLT_GCOM_SERIAL 173 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_ is used + * for internal communication to Physical Interface Cards (PIC) + */ +#define DLT_JUNIPER_PIC_PEER 174 + +/* + * Link types requested by Gregor Maier of Endace + * Measurement Systems. They add an ERF header (see + * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of + * the link-layer header. + */ +#define DLT_ERF_ETH 175 /* Ethernet */ +#define DLT_ERF_POS 176 /* Packet-over-SONET */ + +/* + * Requested by Daniele Orlandi for raw LAPD + * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header + * includes additional information before the LAPD header, so it's + * not necessarily a generic LAPD header. + */ +#define DLT_LINUX_LAPD 177 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ are used for prepending meta-information + * like interface index, interface name + * before standard Ethernet, PPP, Frelay & C-HDLC Frames + */ +#define DLT_JUNIPER_ETHER 178 +#define DLT_JUNIPER_PPP 179 +#define DLT_JUNIPER_FRELAY 180 +#define DLT_JUNIPER_CHDLC 181 + +/* + * Multi Link Frame Relay (FRF.16) + */ +#define DLT_MFR 182 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * voice Adapter Card (PIC) + */ +#define DLT_JUNIPER_VP 183 + +/* + * Arinc 429 frames. + * DLT_ requested by Gianluca Varenni . + * Every frame contains a 32bit A429 label. + * More documentation on Arinc 429 can be found at + * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf + */ +#define DLT_A429 184 + +/* + * Arinc 653 Interpartition Communication messages. + * DLT_ requested by Gianluca Varenni . + * Please refer to the A653-1 standard for more information. + */ +#define DLT_A653_ICM 185 + +/* + * USB packets, beginning with a USB setup header; requested by + * Paolo Abeni . + */ +#define DLT_USB 186 + +/* + * Bluetooth HCI UART transport layer (part H:4); requested by + * Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4 187 + +/* + * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz + * . + */ +#define DLT_IEEE802_16_MAC_CPS 188 + +/* + * USB packets, beginning with a Linux USB header; requested by + * Paolo Abeni . + */ +#define DLT_USB_LINUX 189 + +/* + * Controller Area Network (CAN) v. 2.0B packets. + * DLT_ requested by Gianluca Varenni . + * Used to dump CAN packets coming from a CAN Vector board. + * More documentation on the CAN v2.0B frames can be found at + * http://www.can-cia.org/downloads/?269 + */ +#define DLT_CAN20B 190 + +/* + * IEEE 802.15.4, with address fields padded, as is done by Linux + * drivers; requested by Juergen Schimmer. + */ +#define DLT_IEEE802_15_4_LINUX 191 + +/* + * Per Packet Information encapsulated packets. + * DLT_ requested by Gianluca Varenni . + */ +#define DLT_PPI 192 + +/* + * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; + * requested by Charles Clancy. + */ +#define DLT_IEEE802_16_MAC_CPS_RADIO 193 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * integrated service module (ISM). + */ +#define DLT_JUNIPER_ISM 194 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing); requested by Mikko Saarnivala . + */ +#define DLT_IEEE802_15_4 195 + +/* + * Various link-layer types, with a pseudo-header, for SITA + * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). + */ +#define DLT_SITA 196 + +/* + * Various link-layer types, with a pseudo-header, for Endace DAG cards; + * encapsulates Endace ERF records. Requested by Stephen Donnelly + * . + */ +#define DLT_ERF 197 + +/* + * Special header prepended to Ethernet packets when capturing from a + * u10 Networks board. Requested by Phil Mulholland + * . + */ +#define DLT_RAIF1 198 + +/* + * IPMB packet for IPMI, beginning with the I2C slave address, followed + * by the netFn and LUN, etc.. Requested by Chanthy Toeung + * . + */ +#define DLT_IPMB 199 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for capturing data on a secure tunnel interface. + */ +#define DLT_JUNIPER_ST 200 + +/* + * Bluetooth HCI UART transport layer (part H:4), with pseudo-header + * that includes direction information; requested by Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4_WITH_PHDR 201 + +/* + * AX.25 packet with a 1-byte KISS header; see + * + * http://www.ax25.net/kiss.htm + * + * as per Richard Stearn . + */ +#define DLT_AX25_KISS 202 + +/* + * LAPD packets from an ISDN channel, starting with the address field, + * with no pseudo-header. + * Requested by Varuna De Silva . + */ +#define DLT_LAPD 203 + +/* + * Variants of various link-layer headers, with a one-byte direction + * pseudo-header prepended - zero means "received by this host", + * non-zero (any non-zero value) means "sent by this host" - as per + * Will Barker . + */ +#define DLT_PPP_WITH_DIR 204 /* PPP - don't confuse with DLT_PPP_WITH_DIRECTION */ +#define DLT_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ +#define DLT_FRELAY_WITH_DIR 206 /* Frame Relay */ +#define DLT_LAPB_WITH_DIR 207 /* LAPB */ + +/* + * 208 is reserved for an as-yet-unspecified proprietary link-layer + * type, as requested by Will Barker. + */ + +/* + * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman + * . + */ +#define DLT_IPMB_LINUX 209 + +/* + * FlexRay automotive bus - http://www.flexray.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_FLEXRAY 210 + +/* + * Media Oriented Systems Transport (MOST) bus for multimedia + * transport - http://www.mostcooperation.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_MOST 211 + +/* + * Local Interconnect Network (LIN) bus for vehicle networks - + * http://www.lin-subbus.org/ - as requested by Hannes Kaelber + * . + */ +#define DLT_LIN 212 + +/* + * X2E-private data link type used for serial line capture, + * as requested by Hannes Kaelber . + */ +#define DLT_X2E_SERIAL 213 + +/* + * X2E-private data link type used for the Xoraya data logger + * family, as requested by Hannes Kaelber . + */ +#define DLT_X2E_XORAYA 214 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), but with the PHY-level data for non-ASK PHYs (4 octets + * of 0 as preamble, one octet of SFD, one octet of frame length+ + * reserved bit, and then the MAC-layer data, starting with the + * frame control field). + * + * Requested by Max Filippov . + */ +#define DLT_IEEE802_15_4_NONASK_PHY 215 + + +/* + * DLT and savefile link type values are split into a class and + * a member of that class. A class value of 0 indicates a regular + * DLT_/LINKTYPE_ value. + */ +#define DLT_CLASS(x) ((x) & 0x03ff0000) + +/* + * NetBSD-specific generic "raw" link type. The class value indicates + * that this is the generic raw type, and the lower 16 bits are the + * address family we're dealing with. Those values are NetBSD-specific; + * do not assume that they correspond to AF_ values for your operating + * system. + */ +#define DLT_CLASS_NETBSD_RAWAF 0x02240000 +#define DLT_NETBSD_RAWAF(af) (DLT_CLASS_NETBSD_RAWAF | (af)) +#define DLT_NETBSD_RAWAF_AF(x) ((x) & 0x0000ffff) +#define DLT_IS_NETBSD_RAWAF(x) (DLT_CLASS(x) == DLT_CLASS_NETBSD_RAWAF) + + +/* + * The instruction encodings. + */ +/* instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* ret - BPF_K and BPF_X also apply */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 + +/* misc */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +#define BPF_TXA 0x80 + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_u_int32 k; +}; + +/* + * Macros for insn array initializers. + */ +#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } +#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } + +#if __STDC__ || defined(__cplusplus) +extern int bpf_validate(const struct bpf_insn *, int); +extern u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +#else +extern int bpf_validate(); +extern u_int bpf_filter(); +#endif + +/* + * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). + */ +#define BPF_MEMWORDS 16 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/namedb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/namedb.h new file mode 100644 index 000000000..8298e35b9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/namedb.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/namedb.h,v 1.1 2006/10/04 18:09:22 guy Exp $ (LBL) + */ + +#ifndef lib_pcap_namedb_h +#define lib_pcap_namedb_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * As returned by the pcap_next_etherent() + * XXX this stuff doesn't belong in this interface, but this + * library already must do name to address translation, so + * on systems that don't have support for /etc/ethers, we + * export these hooks since they'll + */ +struct pcap_etherent { + u_char addr[6]; + char name[122]; +}; +#ifndef PCAP_ETHERS_FILE +#define PCAP_ETHERS_FILE "/etc/ethers" +#endif +struct pcap_etherent *pcap_next_etherent(FILE *); +u_char *pcap_ether_hostton(const char*); +u_char *pcap_ether_aton(const char *); + +bpf_u_int32 **pcap_nametoaddr(const char *); +#ifdef INET6 +struct addrinfo *pcap_nametoaddrinfo(const char *); +#endif +bpf_u_int32 pcap_nametonetaddr(const char *); + +int pcap_nametoport(const char *, int *, int *); +int pcap_nametoportrange(const char *, int *, int *, int *); +int pcap_nametoproto(const char *); +int pcap_nametoeproto(const char *); +int pcap_nametollc(const char *); +/* + * If a protocol is unknown, PROTO_UNDEF is returned. + * Also, pcap_nametoport() returns the protocol along with the port number. + * If there are ambiguous entried in /etc/services (i.e. domain + * can be either tcp or udp) PROTO_UNDEF is returned. + */ +#define PROTO_UNDEF -1 + +/* XXX move these to pcap-int.h? */ +int __pcap_atodn(const char *, bpf_u_int32 *); +int __pcap_atoin(const char *, bpf_u_int32 *); +u_short __pcap_nametodnaddr(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/pcap.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/pcap.h new file mode 100644 index 000000000..fbf83413a --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/pcap.h @@ -0,0 +1,407 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/pcap.h,v 1.4.2.11 2008-10-06 15:38:39 gianluca Exp $ (LBL) + */ + +#ifndef lib_pcap_pcap_h +#define lib_pcap_pcap_h + +#if defined(WIN32) + #include +#elif defined(MSDOS) + #include + #include /* u_int, u_char etc. */ +#else /* UN*X */ + #include + #include +#endif /* WIN32/MSDOS/UN*X */ + +#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H +#include +#endif + +#include + +#ifdef HAVE_REMOTE + // We have to define the SOCKET here, although it has been defined in sockutils.h + // This is to avoid the distribution of the 'sockutils.h' file around + // (for example in the WinPcap developer's pack) + #ifndef SOCKET + #ifdef WIN32 + #define SOCKET unsigned int + #else + #define SOCKET int + #endif + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 + +#define PCAP_ERRBUF_SIZE 256 + +/* + * Compatibility for systems that have a bpf.h that + * predates the bpf typedefs for 64-bit support. + */ +#if BPF_RELEASE - 0 < 199406 +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +typedef struct pcap pcap_t; +typedef struct pcap_dumper pcap_dumper_t; +typedef struct pcap_if pcap_if_t; +typedef struct pcap_addr pcap_addr_t; + +/* + * The first record in the file contains saved values for some + * of the flags used in the printout phases of tcpdump. + * Many fields here are 32 bit ints so compilers won't insert unwanted + * padding; these files need to be interchangeable across architectures. + * + * Do not change the layout of this structure, in any way (this includes + * changes that only affect the length of fields in this structure). + * + * Also, do not change the interpretation of any of the members of this + * structure, in any way (this includes using values other than + * LINKTYPE_ values, as defined in "savefile.c", in the "linktype" + * field). + * + * Instead: + * + * introduce a new structure for the new format, if the layout + * of the structure changed; + * + * send mail to "tcpdump-workers@lists.tcpdump.org", requesting + * a new magic number for your new capture file format, and, when + * you get the new magic number, put it in "savefile.c"; + * + * use that magic number for save files with the changed file + * header; + * + * make the code in "savefile.c" capable of reading files with + * the old file header as well as files with the new file header + * (using the magic number to determine the header format). + * + * Then supply the changes as a patch at + * + * http://sourceforge.net/projects/libpcap/ + * + * so that future versions of libpcap and programs that use it (such as + * tcpdump) will be able to read your new capture file format. + */ +struct pcap_file_header { + bpf_u_int32 magic; + u_short version_major; + u_short version_minor; + bpf_int32 thiszone; /* gmt to local correction */ + bpf_u_int32 sigfigs; /* accuracy of timestamps */ + bpf_u_int32 snaplen; /* max length saved portion of each pkt */ + bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ +}; + +/* + * Macros for the value returned by pcap_datalink_ext(). + * + * If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro + * gives the FCS length of packets in the capture. + */ +#define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000) +#define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28) +#define LT_FCS_DATALINK_EXT(x) ((((x) & 0xF) << 28) | 0x04000000) + +typedef enum { + PCAP_D_INOUT = 0, + PCAP_D_IN, + PCAP_D_OUT +} pcap_direction_t; + +/* + * Generic per-packet information, as supplied by libpcap. + * + * The time stamp can and should be a "struct timeval", regardless of + * whether your system supports 32-bit tv_sec in "struct timeval", + * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit + * and 64-bit applications. The on-disk format of savefiles uses 32-bit + * tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit + * and 64-bit versions of libpcap, even if they're on the same platform, + * should supply the appropriate version of "struct timeval", even if + * that's not what the underlying packet capture mechanism supplies. + */ +struct pcap_pkthdr { + struct timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ +}; + +/* + * As returned by the pcap_stats() + */ +struct pcap_stat { + u_int ps_recv; /* number of packets received */ + u_int ps_drop; /* number of packets dropped */ + u_int ps_ifdrop; /* drops by interface XXX not yet supported */ +#ifdef HAVE_REMOTE + u_int ps_capt; /* number of packets that are received by the application; please get rid off the Win32 ifdef */ + u_int ps_sent; /* number of packets sent by the server on the network */ + u_int ps_netdrop; /* number of packets lost on the network */ +#endif /* HAVE_REMOTE */ +}; + +#ifdef MSDOS +/* + * As returned by the pcap_stats_ex() + */ +struct pcap_stat_ex { + u_long rx_packets; /* total packets received */ + u_long tx_packets; /* total packets transmitted */ + u_long rx_bytes; /* total bytes received */ + u_long tx_bytes; /* total bytes transmitted */ + u_long rx_errors; /* bad packets received */ + u_long tx_errors; /* packet transmit problems */ + u_long rx_dropped; /* no space in Rx buffers */ + u_long tx_dropped; /* no space available for Tx */ + u_long multicast; /* multicast packets received */ + u_long collisions; + + /* detailed rx_errors: */ + u_long rx_length_errors; + u_long rx_over_errors; /* receiver ring buff overflow */ + u_long rx_crc_errors; /* recv'd pkt with crc error */ + u_long rx_frame_errors; /* recv'd frame alignment error */ + u_long rx_fifo_errors; /* recv'r fifo overrun */ + u_long rx_missed_errors; /* recv'r missed packet */ + + /* detailed tx_errors */ + u_long tx_aborted_errors; + u_long tx_carrier_errors; + u_long tx_fifo_errors; + u_long tx_heartbeat_errors; + u_long tx_window_errors; + }; +#endif + +/* + * Item in a list of interfaces. + */ +struct pcap_if { + struct pcap_if *next; + char *name; /* name to hand to "pcap_open_live()" */ + char *description; /* textual description of interface, or NULL */ + struct pcap_addr *addresses; + bpf_u_int32 flags; /* PCAP_IF_ interface flags */ +}; + +#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ + +/* + * Representation of an interface address. + */ +struct pcap_addr { + struct pcap_addr *next; + struct sockaddr *addr; /* address */ + struct sockaddr *netmask; /* netmask for that address */ + struct sockaddr *broadaddr; /* broadcast address for that address */ + struct sockaddr *dstaddr; /* P2P destination address for that address */ +}; + +typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, + const u_char *); + +/* + * Error codes for the pcap API. + * These will all be negative, so you can check for the success or + * failure of a call that returns these codes by checking for a + * negative value. + */ +#define PCAP_ERROR -1 /* generic error code */ +#define PCAP_ERROR_BREAK -2 /* loop terminated by pcap_breakloop */ +#define PCAP_ERROR_NOT_ACTIVATED -3 /* the capture needs to be activated */ +#define PCAP_ERROR_ACTIVATED -4 /* the operation can't be performed on already activated captures */ +#define PCAP_ERROR_NO_SUCH_DEVICE -5 /* no such device exists */ +#define PCAP_ERROR_RFMON_NOTSUP -6 /* this device doesn't support rfmon (monitor) mode */ +#define PCAP_ERROR_NOT_RFMON -7 /* operation supported only in monitor mode */ +#define PCAP_ERROR_PERM_DENIED -8 /* no permission to open the device */ +#define PCAP_ERROR_IFACE_NOT_UP -9 /* interface isn't up */ + +/* + * Warning codes for the pcap API. + * These will all be positive and non-zero, so they won't look like + * errors. + */ +#define PCAP_WARNING 1 /* generic warning code */ +#define PCAP_WARNING_PROMISC_NOTSUP 2 /* this device doesn't support promiscuous mode */ + +char *pcap_lookupdev(char *); +int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); + +pcap_t *pcap_create(const char *, char *); +int pcap_set_snaplen(pcap_t *, int); +int pcap_set_promisc(pcap_t *, int); +int pcap_can_set_rfmon(pcap_t *); +int pcap_set_rfmon(pcap_t *, int); +int pcap_set_timeout(pcap_t *, int); +int pcap_set_buffer_size(pcap_t *, int); +int pcap_activate(pcap_t *); + +pcap_t *pcap_open_live(const char *, int, int, int, char *); +pcap_t *pcap_open_dead(int, int); +pcap_t *pcap_open_offline(const char *, char *); +#if defined(WIN32) +pcap_t *pcap_hopen_offline(intptr_t, char *); +#if !defined(LIBPCAP_EXPORTS) +#define pcap_fopen_offline(f,b) \ + pcap_hopen_offline(_get_osfhandle(_fileno(f)), b) +#else /*LIBPCAP_EXPORTS*/ +static pcap_t *pcap_fopen_offline(FILE *, char *); +#endif +#else /*WIN32*/ +pcap_t *pcap_fopen_offline(FILE *, char *); +#endif /*WIN32*/ + +void pcap_close(pcap_t *); +int pcap_loop(pcap_t *, int, pcap_handler, u_char *); +int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); +const u_char* + pcap_next(pcap_t *, struct pcap_pkthdr *); +int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); +void pcap_breakloop(pcap_t *); +int pcap_stats(pcap_t *, struct pcap_stat *); +int pcap_setfilter(pcap_t *, struct bpf_program *); +int pcap_setdirection(pcap_t *, pcap_direction_t); +int pcap_getnonblock(pcap_t *, char *); +int pcap_setnonblock(pcap_t *, int, char *); +int pcap_inject(pcap_t *, const void *, size_t); +int pcap_sendpacket(pcap_t *, const u_char *, int); +const char *pcap_statustostr(int); +const char *pcap_strerror(int); +char *pcap_geterr(pcap_t *); +void pcap_perror(pcap_t *, char *); +int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, + bpf_u_int32); +int pcap_compile_nopcap(int, int, struct bpf_program *, + const char *, int, bpf_u_int32); +void pcap_freecode(struct bpf_program *); +int pcap_offline_filter(struct bpf_program *, const struct pcap_pkthdr *, + const u_char *); +int pcap_datalink(pcap_t *); +int pcap_datalink_ext(pcap_t *); +int pcap_list_datalinks(pcap_t *, int **); +int pcap_set_datalink(pcap_t *, int); +void pcap_free_datalinks(int *); +int pcap_datalink_name_to_val(const char *); +const char *pcap_datalink_val_to_name(int); +const char *pcap_datalink_val_to_description(int); +int pcap_snapshot(pcap_t *); +int pcap_is_swapped(pcap_t *); +int pcap_major_version(pcap_t *); +int pcap_minor_version(pcap_t *); + +/* XXX */ +FILE *pcap_file(pcap_t *); +int pcap_fileno(pcap_t *); + +pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); +pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); +FILE *pcap_dump_file(pcap_dumper_t *); +long pcap_dump_ftell(pcap_dumper_t *); +int pcap_dump_flush(pcap_dumper_t *); +void pcap_dump_close(pcap_dumper_t *); +void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); + +int pcap_findalldevs(pcap_if_t **, char *); +void pcap_freealldevs(pcap_if_t *); + +const char *pcap_lib_version(void); + +/* XXX this guy lives in the bpf tree */ +u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +int bpf_validate(const struct bpf_insn *f, int len); +char *bpf_image(const struct bpf_insn *, int); +void bpf_dump(const struct bpf_program *, int); + +#if defined(WIN32) + +/* + * Win32 definitions + */ + +int pcap_setbuff(pcap_t *p, int dim); +int pcap_setmode(pcap_t *p, int mode); +int pcap_setmintocopy(pcap_t *p, int size); + +#ifdef WPCAP +/* Include file with the wpcap-specific extensions */ +#include +#endif /* WPCAP */ + +#define MODE_CAPT 0 +#define MODE_STAT 1 +#define MODE_MON 2 + +#elif defined(MSDOS) + +/* + * MS-DOS definitions + */ + +int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *); +void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait); +u_long pcap_mac_packets (void); + +#else /* UN*X */ + +/* + * UN*X definitions + */ + +int pcap_get_selectable_fd(pcap_t *); + +#endif /* WIN32/MSDOS/UN*X */ + +#ifdef HAVE_REMOTE +/* Includes most of the public stuff that is needed for the remote capture */ +#include +#endif /* HAVE_REMOTE */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/sll.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/sll.h new file mode 100644 index 000000000..5907beded --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/sll.h @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/sll.h,v 1.2.2.1 2008-05-30 01:36:06 guy Exp $ (LBL) + */ + +/* + * For captures on Linux cooked sockets, we construct a fake header + * that includes: + * + * a 2-byte "packet type" which is one of: + * + * LINUX_SLL_HOST packet was sent to us + * LINUX_SLL_BROADCAST packet was broadcast + * LINUX_SLL_MULTICAST packet was multicast + * LINUX_SLL_OTHERHOST packet was sent to somebody else + * LINUX_SLL_OUTGOING packet was sent *by* us; + * + * a 2-byte Ethernet protocol field; + * + * a 2-byte link-layer type; + * + * a 2-byte link-layer address length; + * + * an 8-byte source link-layer address, whose actual length is + * specified by the previous value. + * + * All fields except for the link-layer address are in network byte order. + * + * DO NOT change the layout of this structure, or change any of the + * LINUX_SLL_ values below. If you must change the link-layer header + * for a "cooked" Linux capture, introduce a new DLT_ type (ask + * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it + * a value that collides with a value already being used), and use the + * new header in captures of that type, so that programs that can + * handle DLT_LINUX_SLL captures will continue to handle them correctly + * without any change, and so that capture files with different headers + * can be told apart and programs that read them can dissect the + * packets in them. + */ + +#ifndef lib_pcap_sll_h +#define lib_pcap_sll_h + +/* + * A DLT_LINUX_SLL fake link-layer header. + */ +#define SLL_HDR_LEN 16 /* total header length */ +#define SLL_ADDRLEN 8 /* length of address field */ + +struct sll_header { + u_int16_t sll_pkttype; /* packet type */ + u_int16_t sll_hatype; /* link-layer address type */ + u_int16_t sll_halen; /* link-layer address length */ + u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ + u_int16_t sll_protocol; /* protocol */ +}; + +/* + * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the + * PACKET_ values on Linux, but are defined here so that they're + * available even on systems other than Linux, and so that they + * don't change even if the PACKET_ values change. + */ +#define LINUX_SLL_HOST 0 +#define LINUX_SLL_BROADCAST 1 +#define LINUX_SLL_MULTICAST 2 +#define LINUX_SLL_OTHERHOST 3 +#define LINUX_SLL_OUTGOING 4 + +/* + * The LINUX_SLL_ values for "sll_protocol"; these correspond to the + * ETH_P_ values on Linux, but are defined here so that they're + * available even on systems other than Linux. We assume, for now, + * that the ETH_P_ values won't change in Linux; if they do, then: + * + * if we don't translate them in "pcap-linux.c", capture files + * won't necessarily be readable if captured on a system that + * defines ETH_P_ values that don't match these values; + * + * if we do translate them in "pcap-linux.c", that makes life + * unpleasant for the BPF code generator, as the values you test + * for in the kernel aren't the values that you test for when + * reading a capture file, so the fixup code run on BPF programs + * handed to the kernel ends up having to do more work. + * + * Add other values here as necessary, for handling packet types that + * might show up on non-Ethernet, non-802.x networks. (Not all the ones + * in the Linux "if_ether.h" will, I suspect, actually show up in + * captures.) + */ +#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ +#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/usb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/usb.h new file mode 100644 index 000000000..f150d3be0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/usb.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * Basic USB data struct + * By Paolo Abeni + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/usb.h,v 1.6 2007/09/22 02:06:08 guy Exp $ + */ + +#ifndef _PCAP_USB_STRUCTS_H__ +#define _PCAP_USB_STRUCTS_H__ + +/* + * possible transfer mode + */ +#define URB_TRANSFER_IN 0x80 +#define URB_ISOCHRONOUS 0x0 +#define URB_INTERRUPT 0x1 +#define URB_CONTROL 0x2 +#define URB_BULK 0x3 + +/* + * possible event type + */ +#define URB_SUBMIT 'S' +#define URB_COMPLETE 'C' +#define URB_ERROR 'E' + +/* + * USB setup header as defined in USB specification. + * Appears at the front of each packet in DLT_USB captures. + */ +typedef struct _usb_setup { + u_int8_t bmRequestType; + u_int8_t bRequest; + u_int16_t wValue; + u_int16_t wIndex; + u_int16_t wLength; +} pcap_usb_setup; + + +/* + * Header prepended by linux kernel to each event. + * Appears at the front of each packet in DLT_USB_LINUX captures. + */ +typedef struct _usb_header { + u_int64_t id; + u_int8_t event_type; + u_int8_t transfer_type; + u_int8_t endpoint_number; + u_int8_t device_address; + u_int16_t bus_id; + char setup_flag;/*if !=0 the urb setup header is not present*/ + char data_flag; /*if !=0 no urb data is present*/ + int64_t ts_sec; + int32_t ts_usec; + int32_t status; + u_int32_t urb_len; + u_int32_t data_len; /* amount of urb data really present in this event*/ + pcap_usb_setup setup; +} pcap_usb_header; + + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/vlan.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/vlan.h new file mode 100644 index 000000000..00ed9b616 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/pcap/vlan.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/vlan.h,v 1.1.2.2 2008-08-06 07:45:59 guy Exp $ + */ + +#ifndef lib_pcap_vlan_h +#define lib_pcap_vlan_h + +struct vlan_tag { + u_int16_t vlan_tpid; /* ETH_P_8021Q */ + u_int16_t vlan_tci; /* VLAN TCI */ +}; + +#define VLAN_TAG_LEN 4 + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/remote-ext.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/remote-ext.h new file mode 100644 index 000000000..9f54d6974 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/remote-ext.h @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * 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. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + + +#ifndef __REMOTE_EXT_H__ +#define __REMOTE_EXT_H__ + + +#ifndef HAVE_REMOTE +#error Please do not include this file directly. Just define HAVE_REMOTE and then include pcap.h +#endif + +// Definition for Microsoft Visual Studio +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + \file remote-ext.h + + The goal of this file it to include most of the new definitions that should be + placed into the pcap.h file. + + It includes all new definitions (structures and functions like pcap_open(). + Some of the functions are not really a remote feature, but, right now, + they are placed here. +*/ + + + +// All this stuff is public +/*! \addtogroup remote_struct + \{ +*/ + + + + +/*! + \brief Defines the maximum buffer size in which address, port, interface names are kept. + + In case the adapter name or such is larger than this value, it is truncated. + This is not used by the user; however it must be aware that an hostname / interface + name longer than this value will be truncated. +*/ +#define PCAP_BUF_SIZE 1024 + + +/*! \addtogroup remote_source_ID + \{ +*/ + + +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a file, i.e. the user want to open a capture from a local file. +*/ +#define PCAP_SRC_FILE 2 +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a local interface, i.e. the user want to open a capture from + a local interface. This does not involve the RPCAP protocol. +*/ +#define PCAP_SRC_IFLOCAL 3 +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a remote interface, i.e. the user want to open a capture from + an interface on a remote host. This does involve the RPCAP protocol. +*/ +#define PCAP_SRC_IFREMOTE 4 + +/*! + \} +*/ + + + +/*! \addtogroup remote_source_string + + The formats allowed by the pcap_open() are the following: + - file://path_and_filename [opens a local file] + - rpcap://devicename [opens the selected device devices available on the local host, without using the RPCAP protocol] + - rpcap://host/devicename [opens the selected device available on a remote host] + - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP] + - adaptername [to open a local adapter; kept for compability, but it is strongly discouraged] + - (NULL) [to open the first local adapter; kept for compability, but it is strongly discouraged] + + The formats allowed by the pcap_findalldevs_ex() are the following: + - file://folder/ [lists all the files in the given folder] + - rpcap:// [lists all local adapters] + - rpcap://host:port/ [lists the devices available on a remote host] + + Referring to the 'host' and 'port' paramters, they can be either numeric or literal. Since + IPv6 is fully supported, these are the allowed formats: + + - host (literal): e.g. host.foo.bar + - host (numeric IPv4): e.g. 10.11.12.13 + - host (numeric IPv4, IPv6 style): e.g. [10.11.12.13] + - host (numeric IPv6): e.g. [1:2:3::4] + - port: can be either numeric (e.g. '80') or literal (e.g. 'http') + + Here you find some allowed examples: + - rpcap://host.foo.bar/devicename [everything literal, no port number] + - rpcap://host.foo.bar:1234/devicename [everything literal, with port number] + - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number] + - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number] + - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number] + - rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number] + - rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number] + - rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number] + + \{ +*/ + + +/*! + \brief String that will be used to determine the type of source in use (file, + remote/local interface). + + This string will be prepended to the interface name in order to create a string + that contains all the information required to open the source. + + This string indicates that the user wants to open a capture from a local file. +*/ +#define PCAP_SRC_FILE_STRING "file://" +/*! + \brief String that will be used to determine the type of source in use (file, + remote/local interface). + + This string will be prepended to the interface name in order to create a string + that contains all the information required to open the source. + + This string indicates that the user wants to open a capture from a network interface. + This string does not necessarily involve the use of the RPCAP protocol. If the + interface required resides on the local host, the RPCAP protocol is not involved + and the local functions are used. +*/ +#define PCAP_SRC_IF_STRING "rpcap://" + +/*! + \} +*/ + + + + + +/*! + \addtogroup remote_open_flags + \{ +*/ + +/*! + \brief Defines if the adapter has to go in promiscuous mode. + + It is '1' if you have to open the adapter in promiscuous mode, '0' otherwise. + Note that even if this parameter is false, the interface could well be in promiscuous + mode for some other reason (for example because another capture process with + promiscuous mode enabled is currently using that interface). + On on Linux systems with 2.2 or later kernels (that have the "any" device), this + flag does not work on the "any" device; if an argument of "any" is supplied, + the 'promisc' flag is ignored. +*/ +#define PCAP_OPENFLAG_PROMISCUOUS 1 + +/*! + \brief Defines if the data trasfer (in case of a remote + capture) has to be done with UDP protocol. + + If it is '1' if you want a UDP data connection, '0' if you want + a TCP data connection; control connection is always TCP-based. + A UDP connection is much lighter, but it does not guarantee that all + the captured packets arrive to the client workstation. Moreover, + it could be harmful in case of network congestion. + This flag is meaningless if the source is not a remote interface. + In that case, it is simply ignored. +*/ +#define PCAP_OPENFLAG_DATATX_UDP 2 + + +/*! + \brief Defines if the remote probe will capture its own generated traffic. + + In case the remote probe uses the same interface to capture traffic and to send + data back to the caller, the captured traffic includes the RPCAP traffic as well. + If this flag is turned on, the RPCAP traffic is excluded from the capture, so that + the trace returned back to the collector is does not include this traffic. +*/ +#define PCAP_OPENFLAG_NOCAPTURE_RPCAP 4 + +/*! + \brief Defines if the local adapter will capture its own generated traffic. + + This flag tells the underlying capture driver to drop the packets that were sent by itself. + This is usefult when building applications like bridges, that should ignore the traffic + they just sent. +*/ +#define PCAP_OPENFLAG_NOCAPTURE_LOCAL 8 + +/*! + \brief This flag configures the adapter for maximum responsiveness. + + In presence of a large value for nbytes, WinPcap waits for the arrival of several packets before + copying the data to the user. This guarantees a low number of system calls, i.e. lower processor usage, + i.e. better performance, which is good for applications like sniffers. If the user sets the + PCAP_OPENFLAG_MAX_RESPONSIVENESS flag, the capture driver will copy the packets as soon as the application + is ready to receive them. This is suggested for real time applications (like, for example, a bridge) + that need the best responsiveness.*/ +#define PCAP_OPENFLAG_MAX_RESPONSIVENESS 16 + +/*! + \} +*/ + + +/*! + \addtogroup remote_samp_methods + \{ +*/ + +/*! + \brief No sampling has to be done on the current capture. + + In this case, no sampling algorithms are applied to the current capture. +*/ +#define PCAP_SAMP_NOSAMP 0 + +/*! + \brief It defines that only 1 out of N packets must be returned to the user. + + In this case, the 'value' field of the 'pcap_samp' structure indicates the + number of packets (minus 1) that must be discarded before one packet got accepted. + In other words, if 'value = 10', the first packet is returned to the caller, while + the following 9 are discarded. +*/ +#define PCAP_SAMP_1_EVERY_N 1 + +/*! + \brief It defines that we have to return 1 packet every N milliseconds. + + In this case, the 'value' field of the 'pcap_samp' structure indicates the 'waiting + time' in milliseconds before one packet got accepted. + In other words, if 'value = 10', the first packet is returned to the caller; the next + returned one will be the first packet that arrives when 10ms have elapsed. +*/ +#define PCAP_SAMP_FIRST_AFTER_N_MS 2 + +/*! + \} +*/ + + +/*! + \addtogroup remote_auth_methods + \{ +*/ + +/*! + \brief It defines the NULL authentication. + + This value has to be used within the 'type' member of the pcap_rmtauth structure. + The 'NULL' authentication has to be equal to 'zero', so that old applications + can just put every field of struct pcap_rmtauth to zero, and it does work. +*/ +#define RPCAP_RMTAUTH_NULL 0 +/*! + \brief It defines the username/password authentication. + + With this type of authentication, the RPCAP protocol will use the username/ + password provided to authenticate the user on the remote machine. If the + authentication is successful (and the user has the right to open network devices) + the RPCAP connection will continue; otherwise it will be dropped. + + This value has to be used within the 'type' member of the pcap_rmtauth structure. +*/ +#define RPCAP_RMTAUTH_PWD 1 + +/*! + \} +*/ + + + + +/*! + + \brief This structure keeps the information needed to autheticate + the user on a remote machine. + + The remote machine can either grant or refuse the access according + to the information provided. + In case the NULL authentication is required, both 'username' and + 'password' can be NULL pointers. + + This structure is meaningless if the source is not a remote interface; + in that case, the functions which requires such a structure can accept + a NULL pointer as well. +*/ +struct pcap_rmtauth +{ + /*! + \brief Type of the authentication required. + + In order to provide maximum flexibility, we can support different types + of authentication based on the value of this 'type' variable. The currently + supported authentication methods are defined into the + \link remote_auth_methods Remote Authentication Methods Section\endlink. + + */ + int type; + /*! + \brief Zero-terminated string containing the username that has to be + used on the remote machine for authentication. + + This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + and it can be NULL. + */ + char *username; + /*! + \brief Zero-terminated string containing the password that has to be + used on the remote machine for authentication. + + This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + and it can be NULL. + */ + char *password; +}; + + +/*! + \brief This structure defines the information related to sampling. + + In case the sampling is requested, the capturing device should read + only a subset of the packets coming from the source. The returned packets depend + on the sampling parameters. + + \warning The sampling process is applied after the filtering process. + In other words, packets are filtered first, then the sampling process selects a + subset of the 'filtered' packets and it returns them to the caller. +*/ +struct pcap_samp +{ + /*! + Method used for sampling. Currently, the supported methods are listed in the + \link remote_samp_methods Sampling Methods Section\endlink. + */ + int method; + + /*! + This value depends on the sampling method defined. For its meaning, please check + at the \link remote_samp_methods Sampling Methods Section\endlink. + */ + int value; +}; + + + + +//! Maximum lenght of an host name (needed for the RPCAP active mode) +#define RPCAP_HOSTLIST_SIZE 1024 + + +/*! + \} +*/ // end of public documentation + + +// Exported functions + + + +/** \name New WinPcap functions + + This section lists the new functions that are able to help considerably in writing + WinPcap programs because of their easiness of use. + */ +//\{ +pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf); +int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf); +int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf); +int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf); +struct pcap_samp *pcap_setsampling(pcap_t *p); + +//\} +// End of new winpcap functions + + + +/** \name Remote Capture functions + */ +//\{ +SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf); +int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf); +int pcap_remoteact_close(const char *host, char *errbuf); +void pcap_remoteact_cleanup(); +//\} +// End of remote capture functions + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/wpcap.lib b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/WinPCap/wpcap.lib new file mode 100644 index 0000000000000000000000000000000000000000..f832e0445b5c7dafe5a0f887262064265ba2b293 GIT binary patch literal 19320 zcmdU0O>9(05-uRW4k3h)gbS|j4}Uz#t>t&Y%Y)S%rl;4JTp5pCTuoh zr6{Lp73IKQa^QrbD7U>tdx#=VoK`4`_7Fwch+_^p| zS6BDfKh<5`)$NUA`Fde~ylZ#2`x_V>8Oe?2azi67zdwrRhWbZ!@NyRb{1af)Ai(As zfGr;YjQ*f$?=%3>0gMxkW0+_MhKYuM)O4~3fN1X*n)>bm5FNa!=@dc`jeVwR->(2f zr@qm2dK`f0IF?CtuvgRRPmzx_yk67JDF8*E;}+y2(SaM92H(eeAPs$`X>=9#JJEGb+ptfFdaw>e+iq*x`Yiy_8LSsk zPhHb?lqKrHekD4vPE+rP*gr_)Sa+hqpEMo(8T%RO(3GZ$?*SB*@r$$_@rd?+t!Zo@ zjvvxV99NR-y@~cP&F-(99u}FD=x9fbs_AYW3=3tr%W|L_8r?37d|TiVLY~ zEvy9P(zP&>67jfHb#AU)syKqo60(JIwPA#!ut>cUHY?T2Y`I#v8X-CyA=yYsIvgR1 z{ec~7x`z7J_EoXesO6i5`6%5+g-kun7o&6?6lsXL*a+*hi*s{fJrauXgmly&fhf^s z3E4_`-3*NminK;E-)tB(9ge34;dLpXqEaSo&XvkdS!WX$Qnj#NubO6=h)8cV>r%o- zg$#}#%0zWB5s_Y~F4Rh8)(8_zN(7avo*HT-qioC+@^ketEL4l8NE;P0#e6f5+G>={ zMukkHlCL%9t7a5zRLGPXLF4Uwtri*$kqjZXkpEM)9$X9SjZ(D|bw-RQrAw8hw96CH zIB?un6^x}-su3UwQbeQ|7jfC3NgauZcw9Wn7pTvr=@psX2-v zPKxSZ5_y=PnoE_N$P;l>b2RJuN@JnKx{58)m9q&VA1x?B*qjgRVZ~&L@q{!@+G|$O zMuiOZZ>iF(7OFMdSjiHy%7zr}qAKD-YOYi%Vt=CNK_NilssaMOp#PS~G0a z3#jr@2fHjGTg%rQuBgKil48`YO^Y*yd_7#KHp6_O8RQFvux8Xd$xh8vE;W)lG&5CR zE{YZ+xiZSMFke|T8koY@IHd|2`Ept5435N=dVT?dRHmqxp2NoQb4*B>?S@fVJ*ax; z#(FH|ab7p_3pF&AS9m=V93eT2qkmOwwM1MS~zh^OYj+6w(qzK0R@x9xxG+j`OQ@O)YAwXd4wWGVhD0>`FwwU%QhSy`Bsht3yBaP(% ze(43MpxoU(=zYOFA0d4{0I&g1$&>iKwHu(>kDdVhcHwsomUZU@z?X;clzbTAW2BWw z0NzC^?gw}e%b&*d8(7cxv5c>V09Ik$uOp3b!!mjRZsYgctytC>fI7y0LnY-36{Zf7=>XNfjzJf#$Z1jgA3T1 zPr!??4yIuo*25%B!C6=dn_&}df!E4q}7h2Vp-SXex#;FLwXebxMB`=5C9I^9PV8s(AynihM(q47Hlj}F34Yx5 z5?lA>X`GVyBqM>5uRR)q`2Y)!$;$8I=7z=ffJr=%AQ6tTb`!4lnRETAExQINoiFRt&`kb6)zb#5OTk(WXF`3LzuyeV>Hxo-xE;5&wx*TA8>_O0# zmkw~5!tPVa^mwZsG2>X)OyT6P_FY#r`5rUt)woR?W2mOSw@rK-bJ`>O{@4yI%WYCPuf1kaI9X$ zNp*3w@H`qDr?aNs+&Oo2#&Hz0Why()^2D`)wqGhaX1N5xvM@q!8M4BUSkpzx4EynIBam!|lli=G+Mk}qYj1rahg&EpnNTMnkZ z6X;YS&b;BMmJ!Md!^x2hGOWz7`V;-AEPO=~#ptsfeItO|rMA!b4@pA?b9;q` zELR%xFI6w99i(bVQ6qBcEkNU%@)Gd`Z&9+L3Wy4UP

ii zt(#u7(X5F2?uWKuz$0Zt8OJO)7!6qr;{`-mW-ub#&;iOoI?D5ivfQBP z?YRYMzrS+nDC-bqg+bw+zXjsZL+Gm53p&N2Dhi z$sPL*kF_J!=aoO!_oo5a`Wl^G6SWCz8X~fDnjyWbFWEo#2>_LrfpY(yof(M2GuM&^&tn45RTGq64I1es%5IBD_q*{iK;u2FYa$7I6mN$G=TOG^=4LlDoZVf8Mpw z8`>v5@1R6iH=VS|vlhSLVkx(ih2l^~-N<=b^b_Mk`m)-zIUnA+Dq&#M2jgMyAnZo(4AD0*qp9b5G`pq6hCIM%0W!8nw$ z=X{p)l{75!sW3?UZSYVll0YzKHbPhY;~;29sU1>;c0zRY>-XSai;ZdbYZCG=to zq}NeHHZoF*W4Z&(oJadNNlfy2cY@QRZM55d-N8}r^iGgGy0KXzv2)UbaVVp147WIa zljmv+W4U(#jA6SoBbv{mY-KcYyI`T(Ull#QxQ(&o#f1gqP{wxoR*xQmS-4#qq68LyTjtHxo|KwtJB;6=J(Y@(tt?ceEx_3CTXEKlvOJ{NFy#1JrL^z$>YNrb&<@)H8*An#mck^5f7vwn&$@= zl0z9sY}m8Q7*9o{hYgHkLs{`!j2wCD52oO$CleN~{Wa0!-I!oJ@fxE8EMH$9a z4-3eltbOUxmcuD{<_QVov_E zH5QOV8As7)wU0Y^#`|rDZ3!!<#~Pe)(9AO+ZjXh{+AKB$jT}9S zHBXm1z-lq?X#aRxVyQ<_9pHHO31=jZeQssJ+SYsD$#znrB{r%InpH16?K&%w>>DwL zSc1lTMr+DJqo>Fgh(lRh<ClhvL%JxCqKEC=kR{Bh7JE3l N*?W_a?2Af)@;}RMSJ?mn literal 0 HcmV?d00001 diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/atomic.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/atomic.h new file mode 100644 index 000000000..565c28037 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/atomic.h @@ -0,0 +1,547 @@ +/* + * FreeRTOS Kernel V10.2.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/** + * @file atomic.h + * @brief FreeRTOS atomic operation support. + * + * Two implementations of atomic are given in this header file: + * 1. Disabling interrupt globally. + * 2. ISA native atomic support. + * The former is available to all ports (compiler-architecture combination), + * while the latter is only available to ports compiling with GCC (version at + * least 4.7.0), which also have ISA atomic support. + * + * User can select which implementation to use by: + * setting/clearing configUSE_ATOMIC_INSTRUCTION in FreeRTOSConfig.h. + * Define AND set configUSE_ATOMIC_INSTRUCTION to 1 for ISA native atomic support. + * Undefine OR clear configUSE_ATOMIC_INSTRUCTION for disabling global interrupt + * implementation. + * + * @see GCC Built-in Functions for Memory Model Aware Atomic Operations + * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html + */ + +#ifndef ATOMIC_H +#define ATOMIC_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include atomic.h" +#endif + +/* Standard includes. */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + /* Needed for __atomic_compare_exchange() weak=false. */ + #include + + /* This branch is for GCC compiler and GCC compiler only. */ + #ifndef portFORCE_INLINE + #define portFORCE_INLINE inline __attribute__((always_inline)) + #endif + +#else + + /* Port specific definitions -- entering/exiting critical section. + * Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h + * + * Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with + * ATOMIC_ENTER_CRITICAL(). + */ + #if defined( portSET_INTERRUPT_MASK_FROM_ISR ) + + /* Nested interrupt scheme is supported in this port. */ + #define ATOMIC_ENTER_CRITICAL() \ + UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR() + + #define ATOMIC_EXIT_CRITICAL() \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType ) + + #else + + /* Nested interrupt scheme is NOT supported in this port. */ + #define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL() + #define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL() + + #endif /* portSET_INTERRUPT_MASK_FROM_ISR() */ + + /* Port specific definition -- "always inline". + * Inline is compiler specific, and may not always get inlined depending on your optimization level. + * For atomic operations, inline is considered a performance optimization. + * Thus, if portFORCE_INLINE is not provided by portmacro.h, instead of resulting error, + * simply define it. + */ + #ifndef portFORCE_INLINE + #define portFORCE_INLINE + #endif + +#endif /* configUSE_GCC_BUILTIN_ATOMICS */ + +#define ATOMIC_COMPARE_AND_SWAP_SUCCESS 0x1U /**< Compare and swap succeeded, swapped. */ +#define ATOMIC_COMPARE_AND_SWAP_FAILURE 0x0U /**< Compare and swap failed, did not swap. */ + +/*----------------------------- Swap && CAS ------------------------------*/ + +/** + * Atomic compare-and-swap + * + * @brief Performs an atomic compare-and-swap operation on the specified values. + * + * @param[in, out] pDestination Pointer to memory location from where value is + * to be loaded and checked. + * @param[in] ulExchange If condition meets, write this value to memory. + * @param[in] ulComparand Swap condition. + * + * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. + * + * @note This function only swaps *pDestination with ulExchange, if previous + * *pDestination value equals ulComparand. + */ +static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32( + uint32_t volatile * pDestination, + uint32_t ulExchange, + uint32_t ulComparand ) +{ + + uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + if ( __atomic_compare_exchange( pDestination, + &ulComparand, + &ulExchange, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST ) ) + { + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + +#else + + ATOMIC_ENTER_CRITICAL(); + + if ( *pDestination == ulComparand ) + { + *pDestination = ulExchange; + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return ulReturnValue; + +} + +/** + * Atomic swap (pointers) + * + * @brief Atomically sets the address pointed to by *ppDestination to the value + * of *pExchange. + * + * @param[in, out] ppDestination Pointer to memory location from where a pointer + * value is to be loaded and written back to. + * @param[in] pExchange Pointer value to be written to *ppDestination. + * + * @return The initial value of *ppDestination. + */ +static portFORCE_INLINE void * Atomic_SwapPointers_p32( + void * volatile * ppDestination, + void * pExchange ) +{ + void * pReturnValue; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + __atomic_exchange( ppDestination, &pExchange, &pReturnValue, __ATOMIC_SEQ_CST ); + +#else + + ATOMIC_ENTER_CRITICAL(); + + pReturnValue = *ppDestination; + + *ppDestination = pExchange; + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return pReturnValue; +} + +/** + * Atomic compare-and-swap (pointers) + * + * @brief Performs an atomic compare-and-swap operation on the specified pointer + * values. + * + * @param[in, out] ppDestination Pointer to memory location from where a pointer + * value is to be loaded and checked. + * @param[in] pExchange If condition meets, write this value to memory. + * @param[in] pComparand Swap condition. + * + * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. + * + * @note This function only swaps *ppDestination with pExchange, if previous + * *ppDestination value equals pComparand. + */ +static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32( + void * volatile * ppDestination, + void * pExchange, void * pComparand ) +{ + uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + if ( __atomic_compare_exchange( ppDestination, + &pComparand, + &pExchange, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST ) ) + { + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + +#else + + ATOMIC_ENTER_CRITICAL(); + + if ( *ppDestination == pComparand ) + { + *ppDestination = pExchange; + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return ulReturnValue; +} + + +/*----------------------------- Arithmetic ------------------------------*/ + +/** + * Atomic add + * + * @brief Atomically adds count to the value of the specified pointer points to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * @param[in] ulCount Value to be added to *pAddend. + * + * @return previous *pAddend value. + */ +static portFORCE_INLINE uint32_t Atomic_Add_u32( + uint32_t volatile * pAddend, + uint32_t ulCount ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_add(pAddend, ulCount, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend += ulCount; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic subtract + * + * @brief Atomically subtracts count from the value of the specified pointer + * pointers to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * @param[in] ulCount Value to be subtract from *pAddend. + * + * @return previous *pAddend value. + */ +static portFORCE_INLINE uint32_t Atomic_Subtract_u32( + uint32_t volatile * pAddend, + uint32_t ulCount ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_sub(pAddend, ulCount, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend -= ulCount; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic increment + * + * @brief Atomically increments the value of the specified pointer points to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * + * @return *pAddend value before increment. + */ +static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pAddend ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_add(pAddend, 1, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend += 1; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic decrement + * + * @brief Atomically decrements the value of the specified pointer points to + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * + * @return *pAddend value before decrement. + */ +static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pAddend ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_sub(pAddend, 1, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend -= 1; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/*----------------------------- Bitwise Logical ------------------------------*/ + +/** + * Atomic OR + * + * @brief Performs an atomic OR operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be ORed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_OR_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_or(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination |= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic AND + * + * @brief Performs an atomic AND operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be ANDed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_AND_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_and(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination &= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic NAND + * + * @brief Performs an atomic NAND operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be NANDed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_NAND_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_nand(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination = ~(ulCurrent & ulValue); + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic XOR + * + * @brief Performs an atomic XOR operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be XORed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_XOR_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_xor(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination ^= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif /* ATOMIC_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/demo_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/demo_config.h new file mode 100644 index 000000000..971405caa --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/demo_config.h @@ -0,0 +1,39 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef DEMO_CONFIG_H +#define DEMO_CONFIG_H + +/** + * @brief Set the stack size of the main demo task. + * + * In the Windows port, this stack only holds a structure. The actual + * stack is created by an operating system thread. + */ +#define democonfigDEMO_STACKSIZE configMINIMAL_STACK_SIZE + +#endif /* DEMO_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/demo_logging.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/demo_logging.c new file mode 100644 index 000000000..e22e91093 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/demo_logging.c @@ -0,0 +1,527 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * Logging utility that allows FreeRTOS tasks to log to a UDP port, stdout, and + * disk file without making any Win32 system calls themselves. + * + * Messages logged to a UDP port are sent directly (using FreeRTOS+TCP), but as + * FreeRTOS tasks cannot make Win32 system calls messages sent to stdout or a + * disk file are sent via a stream buffer to a Win32 thread which then performs + * the actual output. + */ + +/* Standard includes. */ +#include +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_Stream_Buffer.h" + +/* Demo includes. */ +#include "demo_logging.h" + +/*-----------------------------------------------------------*/ + +/* The maximum size to which the log file may grow, before being renamed +to .ful. */ +#define dlLOGGING_FILE_SIZE ( 40ul * 1024ul * 1024ul ) + +/* Dimensions the arrays into which print messages are created. */ +#define dlMAX_PRINT_STRING_LENGTH 255 + +/* The size of the stream buffer used to pass messages from FreeRTOS tasks to +the Win32 thread that is responsible for making any Win32 system calls that are +necessary for the selected logging method. */ +#define dlLOGGING_STREAM_BUFFER_SIZE 32768 + +/* A block time of zero simply means don't block. */ +#define dlDONT_BLOCK 0 + +/*-----------------------------------------------------------*/ + +/* + * Called from vLoggingInit() to start a new disk log file. + */ +static void prvFileLoggingInit( void ); + +/* + * Attempt to write a message to the file. + */ +static void prvLogToFile( const char *pcMessage, size_t xLength ); + +/* + * Simply close the logging file, if it is open. + */ +static void prvFileClose( void ); + +/* + * Before the scheduler is started this function is called directly. After the + * scheduler has started it is called from the Windows thread dedicated to + * outputting log messages. Only the windows thread actually performs the + * writing so as not to disrupt the simulation by making Windows system calls + * from FreeRTOS tasks. + */ +static void prvLoggingFlushBuffer( void ); + +/* + * The windows thread that performs the actual writing of messages that require + * Win32 system calls. Only the windows thread can make system calls so as not + * to disrupt the simulation by making Windows calls from FreeRTOS tasks. + */ +static DWORD WINAPI prvWin32LoggingThread( void *pvParam ); + +/* + * Creates the socket to which UDP messages are sent. This function is not + * called directly to prevent the print socket being created from within the IP + * task - which could result in a deadlock. Instead the function call is + * deferred to run in the RTOS daemon task - hence it prototype. + */ +static void prvCreatePrintSocket( void *pvParameter1, uint32_t ulParameter2 ); + +/*-----------------------------------------------------------*/ + +/* Windows event used to wake the Win32 thread which performs any logging that +needs Win32 system calls. */ +static void *pvLoggingThreadEvent = NULL; + +/* Stores the selected logging targets passed in as parameters to the +vLoggingInit() function. */ +BaseType_t xStdoutLoggingUsed = pdFALSE, xDiskFileLoggingUsed = pdFALSE, xUDPLoggingUsed = pdFALSE; + +/* Circular buffer used to pass messages from the FreeRTOS tasks to the Win32 +thread that is responsible for making Win32 calls (when stdout or a disk log is +used). */ +static StreamBuffer_t *xLogStreamBuffer = NULL; + +/* Handle to the file used for logging. This is left open while there are +messages waiting to be logged, then closed again in between logs. */ +static FILE *pxLoggingFileHandle = NULL; + +/* When true prints are performed directly. After start up xDirectPrint is set +to pdFALSE - at which time prints that require Win32 system calls are done by +the Win32 thread responsible for logging. */ +BaseType_t xDirectPrint = pdTRUE; + +/* File names for the in use and complete (full) log files. */ +static const char *pcLogFileName = "RTOSDemo.log"; +static const char *pcFullLogFileName = "RTOSDemo.ful"; + +/* As an optimization, the current file size is kept in a variable. */ +static size_t ulSizeOfLoggingFile = 0ul; + +/* The UDP socket and address on/to which print messages are sent. */ +Socket_t xPrintSocket = FREERTOS_INVALID_SOCKET; +struct freertos_sockaddr xPrintUDPAddress; + +/*-----------------------------------------------------------*/ + +void vLoggingInit( BaseType_t xLogToStdout, BaseType_t xLogToFile, BaseType_t xLogToUDP, uint32_t ulRemoteIPAddress, uint16_t usRemotePort ) +{ + /* Can only be called before the scheduler has started. */ + configASSERT( xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED ); + + #if( ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) ) + { + HANDLE Win32Thread; + + /* Record which output methods are to be used. */ + xStdoutLoggingUsed = xLogToStdout; + xDiskFileLoggingUsed = xLogToFile; + xUDPLoggingUsed = xLogToUDP; + + /* If a disk file is used then initialize it now. */ + if( xDiskFileLoggingUsed != pdFALSE ) + { + prvFileLoggingInit(); + } + + /* If UDP logging is used then store the address to which the log data + will be sent - but don't create the socket yet because the network is + not initialized. */ + if( xUDPLoggingUsed != pdFALSE ) + { + /* Set the address to which the print messages are sent. */ + xPrintUDPAddress.sin_port = FreeRTOS_htons( usRemotePort ); + xPrintUDPAddress.sin_addr = ulRemoteIPAddress; + } + + /* If a disk file or stdout are to be used then Win32 system calls will + have to be made. Such system calls cannot be made from FreeRTOS tasks + so create a stream buffer to pass the messages to a Win32 thread, then + create the thread itself, along with a Win32 event that can be used to + unblock the thread. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) ) + { + /* Create the buffer. */ + xLogStreamBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) + dlLOGGING_STREAM_BUFFER_SIZE + 1 ); + configASSERT( xLogStreamBuffer ); + memset( xLogStreamBuffer, '\0', sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) ); + xLogStreamBuffer->LENGTH = dlLOGGING_STREAM_BUFFER_SIZE + 1; + + /* Create the Windows event. */ + pvLoggingThreadEvent = CreateEvent( NULL, FALSE, TRUE, "StdoutLoggingEvent" ); + + /* Create the thread itself. */ + Win32Thread = CreateThread( + NULL, /* Pointer to thread security attributes. */ + 0, /* Initial thread stack size, in bytes. */ + prvWin32LoggingThread, /* Pointer to thread function. */ + NULL, /* Argument for new thread. */ + 0, /* Creation flags. */ + NULL ); + + /* Use the cores that are not used by the FreeRTOS tasks. */ + SetThreadAffinityMask( Win32Thread, ~0x01u ); + SetThreadPriorityBoost( Win32Thread, TRUE ); + SetThreadPriority( Win32Thread, THREAD_PRIORITY_IDLE ); + } + } + #else + { + /* FreeRTOSIPConfig is set such that no print messages will be output. + Avoid compiler warnings about unused parameters. */ + ( void ) xLogToStdout; + ( void ) xLogToFile; + ( void ) xLogToUDP; + ( void ) usRemotePort; + ( void ) ulRemoteIPAddress; + } + #endif /* ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) */ +} +/*-----------------------------------------------------------*/ + +static void prvCreatePrintSocket( void *pvParameter1, uint32_t ulParameter2 ) +{ +static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 0 ); +Socket_t xSocket; + + /* The function prototype is that of a deferred function, but the parameters + are not actually used. */ + ( void ) pvParameter1; + ( void ) ulParameter2; + + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + + if( xSocket != FREERTOS_INVALID_SOCKET ) + { + /* FreeRTOS+TCP decides which port to bind to. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + FreeRTOS_bind( xSocket, NULL, 0 ); + + /* Now the socket is bound it can be assigned to the print socket. */ + xPrintSocket = xSocket; + } +} +/*-----------------------------------------------------------*/ + +void vLoggingPrintf( const char *pcFormat, ... ) +{ +char cPrintString[ dlMAX_PRINT_STRING_LENGTH ]; +char cOutputString[ dlMAX_PRINT_STRING_LENGTH ]; +char *pcSource, *pcTarget, *pcBegin; +size_t xLength, xLength2, rc; +static BaseType_t xMessageNumber = 0; +va_list args; +uint32_t ulIPAddress; +const char *pcTaskName; +const char *pcNoTask = "None"; +int iOriginalPriority; +HANDLE xCurrentTask; + + + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) || ( xUDPLoggingUsed != pdFALSE ) ) + { + /* There are a variable number of parameters. */ + va_start( args, pcFormat ); + + /* Additional info to place at the start of the log. */ + if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED ) + { + pcTaskName = pcTaskGetName( NULL ); + } + else + { + pcTaskName = pcNoTask; + } + + if( strcmp( pcFormat, "\n" ) != 0 ) + { + xLength = snprintf( cPrintString, dlMAX_PRINT_STRING_LENGTH, "%lu %lu [%s] ", + xMessageNumber++, + ( unsigned long ) xTaskGetTickCount(), + pcTaskName ); + } + else + { + xLength = 0; + memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH ); + } + + xLength2 = vsnprintf( cPrintString + xLength, dlMAX_PRINT_STRING_LENGTH - xLength, pcFormat, args ); + + if( xLength2 < 0 ) + { + /* Clean up. */ + xLength2 = dlMAX_PRINT_STRING_LENGTH - 1 - xLength; + cPrintString[ dlMAX_PRINT_STRING_LENGTH - 1 ] = '\0'; + } + + xLength += xLength2; + va_end( args ); + + /* For ease of viewing, copy the string into another buffer, converting + IP addresses to dot notation on the way. */ + pcSource = cPrintString; + pcTarget = cOutputString; + + while( ( *pcSource ) != '\0' ) + { + *pcTarget = *pcSource; + pcTarget++; + pcSource++; + + /* Look forward for an IP address denoted by 'ip'. */ + if( ( isxdigit( pcSource[ 0 ] ) != pdFALSE ) && ( pcSource[ 1 ] == 'i' ) && ( pcSource[ 2 ] == 'p' ) ) + { + *pcTarget = *pcSource; + pcTarget++; + *pcTarget = '\0'; + pcBegin = pcTarget - 8; + + while( ( pcTarget > pcBegin ) && ( isxdigit( pcTarget[ -1 ] ) != pdFALSE ) ) + { + pcTarget--; + } + + sscanf( pcTarget, "%8X", &ulIPAddress ); + rc = sprintf( pcTarget, "%lu.%lu.%lu.%lu", + ( unsigned long ) ( ulIPAddress >> 24UL ), + ( unsigned long ) ( (ulIPAddress >> 16UL) & 0xffUL ), + ( unsigned long ) ( (ulIPAddress >> 8UL) & 0xffUL ), + ( unsigned long ) ( ulIPAddress & 0xffUL ) ); + pcTarget += rc; + pcSource += 3; /* skip "ip" */ + } + } + + /* How far through the buffer was written? */ + xLength = ( BaseType_t ) ( pcTarget - cOutputString ); + + /* If the message is to be logged to a UDP port then it can be sent directly + because it only uses FreeRTOS function (not Win32 functions). */ + if( xUDPLoggingUsed != pdFALSE ) + { + if( ( xPrintSocket == FREERTOS_INVALID_SOCKET ) && ( FreeRTOS_IsNetworkUp() != pdFALSE ) ) + { + /* Create and bind the socket to which print messages are sent. The + xTimerPendFunctionCall() function is used even though this is + not an interrupt because this function is called from the IP task + and the IP task cannot itself wait for a socket to bind. The + parameters to prvCreatePrintSocket() are not required so set to + NULL or 0. */ + xTimerPendFunctionCall( prvCreatePrintSocket, NULL, 0, dlDONT_BLOCK ); + } + + if( xPrintSocket != FREERTOS_INVALID_SOCKET ) + { + FreeRTOS_sendto( xPrintSocket, cOutputString, xLength, 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) ); + + /* Just because the UDP data logger I'm using is dumb. */ + FreeRTOS_sendto( xPrintSocket, "\r", sizeof( char ), 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) ); + } + } + + /* If logging is also to go to either stdout or a disk file then it cannot + be output here - so instead write the message to the stream buffer and wake + the Win32 thread which will read it from the stream buffer and perform the + actual output. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) ) + { + configASSERT( xLogStreamBuffer ); + + /* How much space is in the buffer? */ + xLength2 = uxStreamBufferGetSpace( xLogStreamBuffer ); + + /* There must be enough space to write both the string and the length of + the string. */ + if( xLength2 >= ( xLength + sizeof( xLength ) ) ) + { + /* First write in the length of the data, then write in the data + itself. Raising the thread priority is used as a critical section + as there are potentially multiple writers. The stream buffer is + only thread safe when there is a single writer (likewise for + reading from the buffer). */ + xCurrentTask = GetCurrentThread(); + iOriginalPriority = GetThreadPriority( xCurrentTask ); + SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ); + uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) &( xLength ), sizeof( xLength ) ); + uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) cOutputString, xLength ); + SetThreadPriority( GetCurrentThread(), iOriginalPriority ); + } + + /* xDirectPrint is initialized to pdTRUE, and while it remains true the + logging output function is called directly. When the system is running + the output function cannot be called directly because it would get + called from both FreeRTOS tasks and Win32 threads - so instead wake the + Win32 thread responsible for the actual output. */ + if( xDirectPrint != pdFALSE ) + { + /* While starting up, the thread which calls prvWin32LoggingThread() + is not running yet and xDirectPrint will be pdTRUE. */ + prvLoggingFlushBuffer(); + } + else if( pvLoggingThreadEvent != NULL ) + { + /* While running, wake up prvWin32LoggingThread() to send the + logging data. */ + SetEvent( pvLoggingThreadEvent ); + } + } + } +} +/*-----------------------------------------------------------*/ + +static void prvLoggingFlushBuffer( void ) +{ +size_t xLength; +char cPrintString[ dlMAX_PRINT_STRING_LENGTH ]; + + /* Is there more than the length value stored in the circular buffer + used to pass data from the FreeRTOS simulator into this Win32 thread? */ + while( uxStreamBufferGetSize( xLogStreamBuffer ) > sizeof( xLength ) ) + { + memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH ); + uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE ); + uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) cPrintString, xLength, pdFALSE ); + + /* Write the message to standard out if requested to do so when + vLoggingInit() was called, or if the network is not yet up. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( FreeRTOS_IsNetworkUp() == pdFALSE ) ) + { + /* Write the message to stdout. */ + printf( "%s", cPrintString ); /*_RB_ Replace with _write(). */ + fflush( stdout ); + } + + /* Write the message to a file if requested to do so when + vLoggingInit() was called. */ + if( xDiskFileLoggingUsed != pdFALSE ) + { + prvLogToFile( cPrintString, xLength ); + } + } + + prvFileClose(); +} +/*-----------------------------------------------------------*/ + +static DWORD WINAPI prvWin32LoggingThread( void *pvParameter ) +{ +const DWORD xMaxWait = 1000; + + ( void ) pvParameter; + + /* From now on, prvLoggingFlushBuffer() will only be called from this + Windows thread */ + xDirectPrint = pdFALSE; + + for( ;; ) + { + /* Wait to be told there are message waiting to be logged. */ + WaitForSingleObject( pvLoggingThreadEvent, xMaxWait ); + + /* Write out all waiting messages. */ + prvLoggingFlushBuffer(); + } +} +/*-----------------------------------------------------------*/ + +static void prvFileLoggingInit( void ) +{ +FILE *pxHandle = fopen( pcLogFileName, "a" ); + + if( pxHandle != NULL ) + { + fseek( pxHandle, SEEK_END, 0ul ); + ulSizeOfLoggingFile = ftell( pxHandle ); + fclose( pxHandle ); + } + else + { + ulSizeOfLoggingFile = 0ul; + } +} +/*-----------------------------------------------------------*/ + +static void prvFileClose( void ) +{ + if( pxLoggingFileHandle != NULL ) + { + fclose( pxLoggingFileHandle ); + pxLoggingFileHandle = NULL; + } +} +/*-----------------------------------------------------------*/ + +static void prvLogToFile( const char *pcMessage, size_t xLength ) +{ + if( pxLoggingFileHandle == NULL ) + { + pxLoggingFileHandle = fopen( pcLogFileName, "a" ); + } + + if( pxLoggingFileHandle != NULL ) + { + fwrite( pcMessage, 1, xLength, pxLoggingFileHandle ); + ulSizeOfLoggingFile += xLength; + + /* If the file has grown to its maximum permissible size then close and + rename it - then start with a new file. */ + if( ulSizeOfLoggingFile > ( size_t ) dlLOGGING_FILE_SIZE ) + { + prvFileClose(); + if( _access( pcFullLogFileName, 00 ) == 0 ) + { + remove( pcFullLogFileName ); + } + rename( pcLogFileName, pcFullLogFileName ); + ulSizeOfLoggingFile = 0; + } + } +} +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/demo_logging.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/demo_logging.h new file mode 100644 index 000000000..197b21684 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/demo_logging.h @@ -0,0 +1,48 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef DEMO_LOGGING_H +#define DEMO_LOGGING_H + +/* + * Initialize a logging system that can be used from FreeRTOS tasks and Win32 + * threads. Do not call printf() directly while the scheduler is running. + * + * Set xLogToStdout, xLogToFile and xLogToUDP to either pdTRUE or pdFALSE to + * lot to stdout, a disk file and a UDP port respectively. + * + * If xLogToUDP is pdTRUE then ulRemoteIPAddress and usRemotePort must be set + * to the IP address and port number to which UDP log messages will be sent. + */ +void vLoggingInit( BaseType_t xLogToStdout, + BaseType_t xLogToFile, + BaseType_t xLogToUDP, + uint32_t ulRemoteIPAddress, + uint16_t usRemotePort ); + +#endif /* DEMO_LOGGING_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/iot_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/iot_config.h new file mode 100644 index 000000000..091abe2de --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/iot_config.h @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/* This file contains configuration settings for the demos. */ + +#ifndef IOT_CONFIG_H_ +#define IOT_CONFIG_H_ + +/* Configure the IoT Libraries for FreeRTOS by including the FreeRTOS header and + * the FreeRTOS platform types. */ +#include "FreeRTOS.h" +#include "platform/iot_platform_types_freertos.h" + +/** + * @brief Set a global default for log levels. + * + * This setting is overridden by log level settings of specific libraries. + * Undefined library-specific log levels will default to this value. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_GLOBAL IOT_LOG_NONE + +/** + * @brief Set the log level of the platform libraries except the network + * component. + * + * Log messages from the platform libraries at or below this setting + * will be printed. As the network component is more verbose, its logging + * is controlled by its own setting, IOT_LOG_LEVEL_NETWORK. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_PLATFORM IOT_LOG_NONE + +/** + * @brief Set the log level of the platform network library. + * + * Log messages from the platform network library at or below this setting + * will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_NETWORK IOT_LOG_WARN + +/* + * @brief Set the log level of the task pool library. + * + * Log messages from the task pool library at or below this setting will be + * printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_TASKPOOL IOT_LOG_WARN + +/** + * @brief Set the log level of the MQTT library. + * + * Log messages from the MQTT library at or below this setting will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_MQTT IOT_LOG_WARN + +/** + * @brief The number of recyclable jobs for the task pool to cache. + * + * Caching dynamically allocated jobs (recyclable jobs) helps the application + * to limit the number of allocations at runtime. Caching recyclable jobs may + * help making the application more responsive and predictable, by removing a + * potential for memory allocation failures, but it may also have negative + * repercussions on the amount of memory available at any given time. It is up + * to the application developer to strike the correct balance among these + * competing needs. The task pool will cache a job when the application calls + * IotTaskPool_RecycleJob on a job which was created using + * IotTaskPool_CreateRecyclableJob API. Any recycled jobs in excess of + * IOT_TASKPOOL_JOBS_RECYCLE_LIMIT will be destroyed and its memory will be + * released. + * + * Default value (if undefined): 8 + */ +#define IOT_TASKPOOL_JOBS_RECYCLE_LIMIT 8 + +/** + * @brief Enable/Disable asserts for the task pool library. + * + * Set this to 1 to perform sanity checks when using the task pool library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotTaskPool_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_TASKPOOL_ENABLE_ASSERTS 1 + +/** + * @brief The number of worker tasks in the task pool. + * + * The full IoT Task Pool Library has many use cases, including Linux + * development. Typical FreeRTOS use cases do not require the full + * functionality so an optimized implementation is provided specifically for use + * with FreeRTOS. The optimized version has a fixed number of tasks in the + * task pool, each of which uses statically allocated memory to ensure creation + * of the task pool is guaranteed (it does not run out of heap space). + */ +#define IOT_TASKPOOL_NUMBER_OF_WORKERS 1 + +/** + * @brief The stack size (in bytes) for each worker task in the task pool. + * + * The minimal version of the of task pool library only supports one task pool + * and the configuration of each worker task fixed at the compile time. + */ +#define IOT_TASKPOOL_WORKER_STACK_SIZE_BYTES 2048 + +/** + * @brief Enable TLS in the network abstraction. + * + * The TLS implementation requires the mbed TLS library. + */ +#define IOT_NETWORK_ENABLE_TLS 1 + +/** + * @brief Enable/Disable asserts for the linear containers library. + * + * Set this to 1 to perform sanity checks when using the linear containers library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotContainers_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_CONTAINERS_ENABLE_ASSERTS 1 + +/** + * @brief Enable/Disable asserts for the MQTT library. + * + * Set this to 1 to perform sanity checks when using the MQTT library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotMqtt_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_MQTT_ENABLE_ASSERTS 1 + +/** + * @brief Enable/Disable anonymous metrics collection when using AWS IoT. + * + * This demo does not use TLS and so does not work with AWS IoT. Therefore, + * the metric collection must be disabled. + */ +#define AWS_IOT_MQTT_ENABLE_METRICS 0 + +/* Common settings for FreeRTOS; settings below this line generally do not need + * to be changed. */ + +/* Logging puts function on FreeRTOS. */ +#define IotLogging_Puts( str ) configPRINTF( ( "%s\r\n", str ) ) + +/* Assert functions on FreeRTOS. */ +#define IotContainers_Assert( expression ) configASSERT( expression ) +#define IotTaskPool_Assert( expression ) configASSERT( expression ) +#define IotMqtt_Assert( expression ) configASSERT( expression ) +#define Iot_DefaultAssert( expression ) configASSERT( expression ) + +/* Memory allocation functions on FreeRTOS. */ +#define IotThreads_Malloc pvPortMalloc +#define IotThreads_Free vPortFree + +#define IotLogging_Malloc pvPortMalloc +#define IotLogging_Free vPortFree + +#define IotTaskPool_MallocTaskPool pvPortMalloc +#define IotTaskPool_FreeTaskPool vPortFree +#define IotTaskPool_MallocJob pvPortMalloc +#define IotTaskPool_FreeJob vPortFree +#define IotTaskPool_MallocTimerEvent pvPortMalloc +#define IotTaskPool_FreeTimerEvent vPortFree + +#define IotMqtt_MallocConnection pvPortMalloc +#define IotMqtt_FreeConnection vPortFree +#define IotMqtt_MallocMessage pvPortMalloc +#define IotMqtt_FreeMessage vPortFree +#define IotMqtt_MallocOperation pvPortMalloc +#define IotMqtt_FreeOperation vPortFree +#define IotMqtt_MallocSubscription pvPortMalloc +#define IotMqtt_FreeSubscription vPortFree + +#define AwsIotShadow_MallocOperation pvPortMalloc +#define AwsIotShadow_FreeOperation vPortFree +#define AwsIotShadow_MallocString pvPortMalloc +#define AwsIotShadow_FreeString vPortFree +#define AwsIotShadow_MallocSubscription pvPortMalloc +#define AwsIotShadow_FreeSubscription vPortFree + +#define Iot_DefaultMalloc pvPortMalloc +#define Iot_DefaultFree vPortFree + +#endif /* ifndef IOT_CONFIG_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/jobs_notify_next_demo.sln b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/jobs_notify_next_demo.sln new file mode 100644 index 000000000..b362f36c5 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/jobs_notify_next_demo.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTOSDemo", "WIN32.vcxproj", "{C686325E-3261-42F7-AEB1-DDE5280E1CEB}" +EndProject +Global + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = FreeRTOS_Plus_TCP_Minimal.vsmdi + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.ActiveCfg = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.Build.0 = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.ActiveCfg = Release|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/main.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/main.c new file mode 100644 index 000000000..e07f2c2eb --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/main.c @@ -0,0 +1,356 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + /*** + * See https://www.FreeRTOS.org/mqtt/index.html for configuration and usage instructions. + ***/ + +/* Standard includes. */ +#include +#include + +/* Visual studio intrinsics used so the __debugbreak() function is available +should an assert get hit. */ +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" + +/* TCP/IP stack includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Demo app includes. */ +#include "demo_logging.h" + +/* + * Prototypes for the demos that can be started from this project. Note the + * Jobs demo is not actually started until the network is already, which is + * indicated by vApplicationIPNetworkEventHook() executing - hence + * vStartJobsDemo() is called from inside vApplicationIPNetworkEventHook(). + */ +extern void vStartJobsDemo( void ); + +/* + * Just seeds the simple pseudo random number generator. + * + * !!! NOTE !!! + * This is not a secure method of generating random numbers and production + * devices should use a true random number generator (TRNG). + */ +static void prvSRand( UBaseType_t ulSeed ); + +/* + * Miscellaneous initialization including preparing the logging and seeding the + * random number generator. + */ +static void prvMiscInitialisation( void ); + +/* The default IP and MAC address used by the demo. The address configuration +defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is +1 but a DHCP server could not be contacted. See the online documentation for +more information. */ +static const uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 }; +static const uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 }; +static const uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 }; +static const uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 }; + +/* Set the following constant to pdTRUE to log using the method indicated by the +name of the constant, or pdFALSE to not log using the method indicated by the +name of the constant. Options include to standard out (xLogToStdout), to a disk +file (xLogToFile), and to a UDP port (xLogToUDP). If xLogToUDP is set to pdTRUE +then UDP messages are sent to the IP address configured as the echo server +address (see the configECHO_SERVER_ADDR0 definitions in FreeRTOSConfig.h) and +the port number set by configPRINT_PORT in FreeRTOSConfig.h. */ +const BaseType_t xLogToStdout = pdTRUE, xLogToFile = pdFALSE, xLogToUDP = pdFALSE; + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition for information on how to configure +the real network connection to use. */ +const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 }; + +/* Use by the pseudo random number generator. */ +static UBaseType_t ulNextRand; +/*-----------------------------------------------------------*/ + +int main( void ) +{ + /*** + * See https://www.FreeRTOS.org/mqtt/index.html for configuration and usage instructions. + ***/ + + /* Miscellaneous initialization including preparing the logging and seeding + the random number generator. */ + prvMiscInitialisation(); + + /* Initialize the network interface. + + ***NOTE*** Tasks that use the network are created in the network event hook + when the network is connected and ready for use (see the implementation of + vApplicationIPNetworkEventHook() below). The address values passed in here + are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1 + but a DHCP server cannot be contacted. */ + FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); + + /* Start the RTOS scheduler. */ + vTaskStartScheduler(); + + /* If all is well, the scheduler will now be running, and the following + line will never be reached. If the following line does execute, then + there was insufficient FreeRTOS heap memory available for the idle and/or + timer tasks to be created. See the memory management section on the + FreeRTOS web site for more details (this is standard text that is not + really applicable to the Win32 simulator port). */ + for( ;; ) + { + __debugbreak(); + } +} +/*-----------------------------------------------------------*/ + +/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect +events are only received if implemented in the MAC driver. */ +void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) +{ +uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress; +char cBuffer[ 16 ]; +static BaseType_t xTasksAlreadyCreated = pdFALSE; + + /* If the network has just come up...*/ + if( eNetworkEvent == eNetworkUp ) + { + /* Create the tasks that use the IP stack if they have not already been + created. */ + if( xTasksAlreadyCreated == pdFALSE ) + { + /* Demos that use the network are created after the network is + up. */ + configPRINTF( ( "---------STARTING DEMO---------\r\n" ) ); + vStartJobsDemo(); + xTasksAlreadyCreated = pdTRUE; + } + + /* Print out the network configuration, which may have come from a DHCP + server. */ + FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress ); + FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); + FreeRTOS_printf( ( "\r\n\r\nIP Address: %s\r\n", cBuffer ) );/*_RB_ Should use IoT libraries logging. */ + + FreeRTOS_inet_ntoa( ulNetMask, cBuffer ); + FreeRTOS_printf( ( "Subnet Mask: %s\r\n", cBuffer ) ); + + FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer ); + FreeRTOS_printf( ( "Gateway Address: %s\r\n", cBuffer ) ); + + FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer ); + FreeRTOS_printf( ( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ) ); + } +} +/*-----------------------------------------------------------*/ + +void vAssertCalled( const char *pcFile, uint32_t ulLine ) +{ + volatile uint32_t ulBlockVariable = 0UL; + volatile char *pcFileName = ( volatile char * ) pcFile; + volatile uint32_t ulLineNumber = ulLine; + + ( void ) pcFileName; + ( void ) ulLineNumber; + + printf( "vAssertCalled( %s, %u\n", pcFile, ulLine ); + + /* Setting ulBlockVariable to a non-zero value in the debugger will allow + this function to be exited. */ + taskDISABLE_INTERRUPTS(); + { + while( ulBlockVariable == 0UL ) + { + __debugbreak(); + } + } + taskENABLE_INTERRUPTS(); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxRand( void ) +{ +const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL; + + /* + * Utility function to generate a pseudo random number. + * + * !!!NOTE!!! + * This is not a secure method of generating a random number. Production + * devices should use a True Random Number Generator (TRNG). + */ + ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement; + return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL ); +} +/*-----------------------------------------------------------*/ + +static void prvSRand( UBaseType_t ulSeed ) +{ + /* Utility function to seed the pseudo random number generator. */ + ulNextRand = ulSeed; +} +/*-----------------------------------------------------------*/ + +static void prvMiscInitialisation( void ) +{ +time_t xTimeNow; +uint32_t ulLoggingIPAddress; + + ulLoggingIPAddress = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0, configECHO_SERVER_ADDR1, configECHO_SERVER_ADDR2, configECHO_SERVER_ADDR3 ); + vLoggingInit( xLogToStdout, xLogToFile, xLogToUDP, ulLoggingIPAddress, configPRINT_PORT ); + + /* + * Seed random number generator. + * + * !!!NOTE!!! + * This is not a secure method of generating a random number. Production + * devices should use a True Random Number Generator (TRNG). + */ + time( &xTimeNow ); + FreeRTOS_debug_printf( ( "Seed for randomizer: %lu\n", xTimeNow ) ); + prvSRand( ( uint32_t ) xTimeNow ); + FreeRTOS_debug_printf( ( "Random numbers: %08X %08X %08X %08X\n", ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32() ) ); +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) + + const char *pcApplicationHostnameHook( void ) + { + /* Assign the name "FreeRTOS" to this network node. This function will + be called during the DHCP: the machine will be registered with an IP + address plus this name. */ + return mainHOST_NAME; + } + +#endif +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) + + BaseType_t xApplicationDNSQueryHook( const char *pcName ) + { + BaseType_t xReturn; + + /* Determine if a name lookup is for this node. Two names are given + to this node: that returned by pcApplicationHostnameHook() and that set + by mainDEVICE_NICK_NAME. */ + if( _stricmp( pcName, pcApplicationHostnameHook() ) == 0 ) + { + xReturn = pdPASS; + } + else if( _stricmp( pcName, mainDEVICE_NICK_NAME ) == 0 ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif +/*-----------------------------------------------------------*/ + +/* + * Callback that provides the inputs necessary to generate a randomized TCP + * Initial Sequence Number per RFC 6528. THIS IS ONLY A DUMMY IMPLEMENTATION + * THAT RETURNS A PSEUDO RANDOM NUMBER SO IS NOT INTENDED FOR USE IN PRODUCTION + * SYSTEMS. + */ +extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress, + uint16_t usSourcePort, + uint32_t ulDestinationAddress, + uint16_t usDestinationPort ) +{ + ( void ) ulSourceAddress; + ( void ) usSourcePort; + ( void ) ulDestinationAddress; + ( void ) usDestinationPort; + + return uxRand(); +} +/*-----------------------------------------------------------*/ + +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an +implementation of vApplicationGetIdleTaskMemory() to provide the memory that is +used by the Idle task. */ +void vApplicationGetIdleTaskMemory( StaticTask_t** ppxIdleTaskTCBBuffer, StackType_t** ppxIdleTaskStackBuffer, uint32_t* pulIdleTaskStackSize ) +{ + /* If the buffers to be provided to the Idle task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xIdleTaskTCB; + static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} +/*-----------------------------------------------------------*/ + +/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the +application must provide an implementation of vApplicationGetTimerTaskMemory() +to provide the memory that is used by the Timer service task. */ +void vApplicationGetTimerTaskMemory( StaticTask_t** ppxTimerTaskTCBBuffer, StackType_t** ppxTimerTaskStackBuffer, uint32_t* pulTimerTaskStackSize ) +{ + /* If the buffers to be provided to the Timer task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xTimerTaskTCB; + static StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/mbedtls_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/mbedtls_config.h new file mode 100644 index 000000000..0f2861a0d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/mbedtls_config.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/* This file configures mbed TLS for FreeRTOS. */ + +#ifndef MBEDTLS_CONFIG_H_ +#define MBEDTLS_CONFIG_H_ + +/* FreeRTOS include. */ +#include "FreeRTOS.h" + +/* Generate errors if deprecated functions are used. */ +#define MBEDTLS_DEPRECATED_REMOVED + +/* Place AES tables in ROM. */ +#define MBEDTLS_AES_ROM_TABLES + +/* Enable the following cipher modes. */ +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_CIPHER_MODE_CFB +#define MBEDTLS_CIPHER_MODE_CTR + +/* Enable the following cipher padding modes. */ +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define MBEDTLS_CIPHER_PADDING_ZEROS + +/* Cipher suite configuration. */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_NIST_OPTIM +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/* Enable all SSL alert messages. */ +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES + +/* Enable the following SSL features. */ +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_SSL_ALPN +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/* Check certificate key usage. */ +#define MBEDTLS_X509_CHECK_KEY_USAGE +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/* Disable platform entropy functions. */ +#define MBEDTLS_NO_PLATFORM_ENTROPY + +/* Enable the following mbed TLS features. */ +#define MBEDTLS_AES_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECP_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_GCM_C +#define MBEDTLS_MD_C +#define MBEDTLS_OID_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA1_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_TLS_C +#define MBEDTLS_THREADING_ALT +#define MBEDTLS_THREADING_C +#define MBEDTLS_X509_USE_C +#define MBEDTLS_X509_CRT_PARSE_C + +/* Set the memory allocation functions on FreeRTOS. */ +void * mbedtls_platform_calloc( size_t nmemb, + size_t size ); +void mbedtls_platform_free( void * ptr ); +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_CALLOC_MACRO mbedtls_platform_calloc +#define MBEDTLS_PLATFORM_FREE_MACRO mbedtls_platform_free + +/* The network send and receive functions on FreeRTOS. */ +int mbedtls_platform_send( void * ctx, + const unsigned char * buf, + size_t len ); +int mbedtls_platform_recv( void * ctx, + unsigned char * buf, + size_t len ); + +/* The entropy poll function. */ +int mbedtls_platform_entropy_poll( void * data, + unsigned char * output, + size_t len, + size_t * olen ); + +#include "mbedtls/check_config.h" + +#endif /* ifndef MBEDTLS_CONFIG_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/printf-stdarg.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/printf-stdarg.c new file mode 100644 index 000000000..5505535c1 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/jobs_notify_next/printf-stdarg.c @@ -0,0 +1,667 @@ +/* + Copyright 2001, 2002 Georges Menie (www.menie.org) + stdarg version contributed by Christian Ettinger + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Changes for the FreeRTOS ports: + + - The dot in "%-8.8s" + - The specifiers 'l' (long) and 'L' (long long) + - The specifier 'u' for unsigned + - Dot notation for IP addresses: + sprintf("IP = %xip\n", 0xC0A80164); + will produce "IP = 192.168.1.100\n" +*/ + +#include +#include +#include +#include + +#include "FreeRTOS.h" + +#define PAD_RIGHT 1 +#define PAD_ZERO 2 + +/* + * Return 1 for readable, 2 for writeable, 3 for both. + * Function must be provided by the application. + */ +extern BaseType_t xApplicationMemoryPermissions( uint32_t aAddress ); + +extern void vOutputChar( const char cChar, const TickType_t xTicksToWait ); +static const TickType_t xTicksToWait = pdMS_TO_TICKS( 20 ); + +struct xPrintFlags +{ + int base; + int width; + int printLimit; + unsigned + pad : 8, + letBase : 8, + isSigned : 1, + isNumber : 1, + long32 : 1, + long64 : 1; +}; + +struct SStringBuf +{ + char *str; + const char *orgStr; + const char *nulPos; + int curLen; + struct xPrintFlags flags; +}; + +static void strbuf_init( struct SStringBuf *apStr, char *apBuf, const char *apMaxStr ) +{ + apStr->str = apBuf; + apStr->orgStr = apBuf; + apStr->nulPos = apMaxStr-1; + apStr->curLen = 0; + + memset( &apStr->flags, '\0', sizeof( apStr->flags ) ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t strbuf_printchar( struct SStringBuf *apStr, int c ) +{ + if( apStr->str == NULL ) + { + vOutputChar( ( char ) c, xTicksToWait ); + apStr->curLen++; + return pdTRUE; + } + if( apStr->str < apStr->nulPos ) + { + *( apStr->str++ ) = c; + apStr->curLen++; + return pdTRUE; + } + if( apStr->str == apStr->nulPos ) + { + *( apStr->str++ ) = '\0'; + } + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static portINLINE BaseType_t strbuf_printchar_inline( struct SStringBuf *apStr, int c ) +{ + if( apStr->str == NULL ) + { + vOutputChar( ( char ) c, xTicksToWait ); + if( c == 0 ) + { + return pdFALSE; + } + apStr->curLen++; + return pdTRUE; + } + if( apStr->str < apStr->nulPos ) + { + *(apStr->str++) = c; + if( c == 0 ) + { + return pdFALSE; + } + apStr->curLen++; + return pdTRUE; + } + if( apStr->str == apStr->nulPos ) + { + *( apStr->str++ ) = '\0'; + } + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static portINLINE int i2hex( int aCh ) +{ +int iResult; + + if( aCh < 10 ) + { + iResult = '0' + aCh; + } + else + { + iResult = 'A' + aCh - 10; + } + + return iResult; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prints(struct SStringBuf *apBuf, const char *apString ) +{ + register int padchar = ' '; + int i,len; + + if( xApplicationMemoryPermissions( ( uint32_t )apString ) == 0 ) + { + /* The user has probably made a mistake with the parameter + for '%s', the memory is not readbale. */ + apString = "INV_MEM"; + } + + if( apBuf->flags.width > 0 ) + { + register int len = 0; + register const char *ptr; + for( ptr = apString; *ptr; ++ptr ) + { + ++len; + } + + if( len >= apBuf->flags.width ) + { + apBuf->flags.width = 0; + } + else + { + apBuf->flags.width -= len; + } + + if( apBuf->flags.pad & PAD_ZERO ) + { + padchar = '0'; + } + } + if( ( apBuf->flags.pad & PAD_RIGHT ) == 0 ) + { + for( ; apBuf->flags.width > 0; --apBuf->flags.width ) + { + if( strbuf_printchar( apBuf, padchar ) == 0 ) + { + return pdFALSE; + } + } + } + if( ( apBuf->flags.isNumber == pdTRUE ) && ( apBuf->flags.pad == pdTRUE ) ) + { + /* The string to print represents an integer number. + * In this case, printLimit is the min number of digits to print + * If the length of the number to print is less than the min nb of i + * digits to display, we add 0 before printing the number + */ + len = strlen( apString ); + + if( len < apBuf->flags.printLimit ) + { + i = apBuf->flags.printLimit - len; + for( ; i; i-- ) + { + if( strbuf_printchar( apBuf, '0' ) == 0 ) + { + return pdFALSE; + } + } + } + } + /* The string to print is not the result of a number conversion to ascii. + * For a string, printLimit is the max number of characters to display + */ + for( ; apBuf->flags.printLimit && *apString ; ++apString, --apBuf->flags.printLimit ) + { + if( !strbuf_printchar( apBuf, *apString ) ) + { + return pdFALSE; + } + } + + for( ; apBuf->flags.width > 0; --apBuf->flags.width ) + { + if( !strbuf_printchar( apBuf, padchar ) ) + { + return pdFALSE; + } + } + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +/* the following should be enough for 32 bit int */ +#define PRINT_BUF_LEN 12 /* to print 4294967296 */ + +#if SPRINTF_LONG_LONG +#warning 64-bit libraries will be included as well +static BaseType_t printll( struct SStringBuf *apBuf, long long i ) +{ + char print_buf[ 2 * PRINT_BUF_LEN ]; + register char *s; + register int t, neg = 0; + register unsigned long long u = i; + lldiv_t lldiv_result; + +/* typedef struct + * { + * long long int quot; // quotient + * long long int rem; // remainder + * } lldiv_t; + */ + + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + if( i == 0LL ) + { + print_buf[ 0 ] = '0'; + print_buf[ 1 ] = '\0'; + return prints( apBuf, print_buf ); + } + + if( ( apBuf->flags.isSigned == pdTRUE ) && ( apBuf->flags.base == 10 ) && ( i < 0LL ) ) + { + neg = 1; + u = -i; + } + + s = print_buf + sizeof( print_buf ) - 1; + + *s = '\0'; + /* 18446744073709551616 */ + while( u != 0 ) + { + lldiv_result = lldiv( u, ( unsigned long long ) apBuf->flags.base ); + t = lldiv_result.rem; + if( t >= 10 ) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u = lldiv_result.quot; + } + + if( neg != 0 ) + { + if( ( apBuf->flags.width != 0 ) && ( apBuf->flags.pad & PAD_ZERO ) ) + { + if( !strbuf_printchar( apBuf, '-' ) ) + { + return pdFALSE; + } + --apBuf->flags.width; + } + else + { + *( --s ) = '-'; + } + } + + return prints( apBuf, s ); +} +#endif /* SPRINTF_LONG_LONG */ +/*-----------------------------------------------------------*/ + +static BaseType_t printi( struct SStringBuf *apBuf, int i ) +{ + char print_buf[ PRINT_BUF_LEN ]; + register char *s; + register int t, neg = 0; + register unsigned int u = i; + register unsigned base = apBuf->flags.base; + + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + + if( i == 0 ) + { + print_buf[ 0 ] = '0'; + print_buf[ 1 ] = '\0'; + return prints( apBuf, print_buf ); + } + + if( ( apBuf->flags.isSigned == pdTRUE ) && ( base == 10 ) && ( i < 0 ) ) + { + neg = 1; + u = -i; + } + + s = print_buf + sizeof( print_buf ) - 1; + + *s = '\0'; + switch( base ) + { + case 16: + while( u != 0 ) + { + t = u & 0xF; + if( t >= 10 ) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u >>= 4; + } + break; + + case 8: + case 10: + /* GCC compiles very efficient */ + while( u ) + { + t = u % base; + *( --s ) = t + '0'; + u /= base; + } + break; +/* + // The generic case, not yet in use + default: + while( u ) + { + t = u % base; + if( t >= 10) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u /= base; + } + break; +*/ + } + + if( neg != 0 ) + { + if( apBuf->flags.width && (apBuf->flags.pad & PAD_ZERO ) ) + { + if( strbuf_printchar( apBuf, '-' ) == 0 ) + { + return pdFALSE; + } + --apBuf->flags.width; + } + else + { + *( --s ) = '-'; + } + } + + return prints( apBuf, s ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t printIp(struct SStringBuf *apBuf, unsigned i ) +{ + char print_buf[16]; + + sprintf( print_buf, "%u.%u.%u.%u", + i >> 24, + ( i >> 16 ) & 0xff, + ( i >> 8 ) & 0xff, + i & 0xff ); + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + prints( apBuf, print_buf ); + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +static void tiny_print( struct SStringBuf *apBuf, const char *format, va_list args ) +{ + char scr[2]; + + for( ; ; ) + { + int ch = *( format++ ); + + if( ch != '%' ) + { + do + { + /* Put the most like flow in a small loop */ + if( strbuf_printchar_inline( apBuf, ch ) == 0 ) + { + return; + } + ch = *( format++ ); + } while( ch != '%' ); + } + ch = *( format++ ); + /* Now ch has character after '%', format pointing to next */ + + if( ch == '\0' ) + { + break; + } + if( ch == '%' ) + { + if( strbuf_printchar( apBuf, ch ) == 0 ) + { + return; + } + continue; + } + memset( &apBuf->flags, '\0', sizeof( apBuf->flags ) ); + + if( ch == '-' ) + { + ch = *( format++ ); + apBuf->flags.pad = PAD_RIGHT; + } + while( ch == '0' ) + { + ch = *( format++ ); + apBuf->flags.pad |= PAD_ZERO; + } + if( ch == '*' ) + { + ch = *( format++ ); + apBuf->flags.width = va_arg( args, int ); + } + else + { + while( ch >= '0' && ch <= '9' ) + { + apBuf->flags.width *= 10; + apBuf->flags.width += ch - '0'; + ch = *( format++ ); + } + } + if( ch == '.' ) + { + ch = *( format++ ); + if( ch == '*' ) + { + apBuf->flags.printLimit = va_arg( args, int ); + ch = *( format++ ); + } + else + { + while( ch >= '0' && ch <= '9' ) + { + apBuf->flags.printLimit *= 10; + apBuf->flags.printLimit += ch - '0'; + ch = *( format++ ); + } + } + } + if( apBuf->flags.printLimit == 0 ) + { + apBuf->flags.printLimit--; /* -1: make it unlimited */ + } + if( ch == 's' ) + { + register char *s = ( char * )va_arg( args, int ); + if( prints( apBuf, s ? s : "(null)" ) == 0 ) + { + break; + } + continue; + } + if( ch == 'c' ) + { + /* char are converted to int then pushed on the stack */ + scr[0] = ( char ) va_arg( args, int ); + + if( strbuf_printchar( apBuf, scr[0] ) == 0 ) + { + return; + } + + continue; + } + if( ch == 'l' ) + { + ch = *( format++ ); + apBuf->flags.long32 = 1; + /* Makes not difference as u32 == long */ + } + if( ch == 'L' ) + { + ch = *( format++ ); + apBuf->flags.long64 = 1; + /* Does make a difference */ + } + apBuf->flags.base = 10; + apBuf->flags.letBase = 'a'; + + if( ch == 'd' || ch == 'u' ) + { + apBuf->flags.isSigned = ( ch == 'd' ); +#if SPRINTF_LONG_LONG + if( apBuf->flags.long64 != pdFALSE ) + { + if( printll( apBuf, va_arg( args, long long ) ) == 0 ) + { + break; + } + } else +#endif /* SPRINTF_LONG_LONG */ + if( printi( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + + apBuf->flags.base = 16; /* From here all hexadecimal */ + + if( ch == 'x' && format[0] == 'i' && format[1] == 'p' ) + { + format += 2; /* eat the "xi" of "xip" */ + /* Will use base 10 again */ + if( printIp( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + if( ch == 'x' || ch == 'X' || ch == 'p' || ch == 'o' ) + { + if( ch == 'X' ) + { + apBuf->flags.letBase = 'A'; + } + else if( ch == 'o' ) + { + apBuf->flags.base = 8; + } +#if SPRINTF_LONG_LONG + if( apBuf->flags.long64 != pdFALSE ) + { + if( printll( apBuf, va_arg( args, long long ) ) == 0 ) + { + break; + } + } else +#endif /* SPRINTF_LONG_LONG */ + if( printi( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + } + strbuf_printchar( apBuf, '\0' ); +} +/*-----------------------------------------------------------*/ + +int vsnprintf( char *apBuf, size_t aMaxLen, const char *apFmt, va_list args ) +{ + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen ); + tiny_print( &strBuf, apFmt, args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int snprintf( char *apBuf, size_t aMaxLen, const char *apFmt, ... ) +{ + va_list args; + + va_start( args, apFmt ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen ); + tiny_print( &strBuf, apFmt, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int sprintf( char *apBuf, const char *apFmt, ... ) +{ + va_list args; + + va_start( args, apFmt ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char * )apBuf + 1024 ); + tiny_print( &strBuf, apFmt, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int vsprintf( char *apBuf, const char *apFmt, va_list args ) +{ + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* ) apBuf + 1024 ); + tiny_print( &strBuf, apFmt, args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +const char *mkSize (unsigned long long aSize, char *apBuf, int aLen) +{ +static char retString[33]; +size_t gb, mb, kb, sb; + + if (apBuf == NULL) { + apBuf = retString; + aLen = sizeof( retString ); + } + gb = aSize / (1024*1024*1024); + aSize -= gb * (1024*1024*1024); + mb = aSize / (1024*1024); + aSize -= mb * (1024*1024); + kb = aSize / (1024); + aSize -= kb * (1024); + sb = aSize; + if( gb ) + { + snprintf (apBuf, aLen, "%u.%02u GB", ( unsigned ) gb, ( unsigned ) ( ( 100 * mb ) / 1024ul ) ); + } + else if( mb ) + { + snprintf (apBuf, aLen, "%u.%02u MB", ( unsigned ) mb, ( unsigned ) ( ( 100 * kb) / 1024ul ) ); + } + else if( kb != 0ul ) + { + snprintf (apBuf, aLen, "%u.%02u KB", ( unsigned ) kb, ( unsigned ) ( ( 100 * sb) / 1024ul ) ); + } + else + { + snprintf (apBuf, aLen, "%u bytes", ( unsigned ) sb); + } + return apBuf; +} diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/readme.txt b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/readme.txt new file mode 100644 index 000000000..2feac962a --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs/readme.txt @@ -0,0 +1,8 @@ +See https://freertos.org/jobs/ for further information. + +Contains projects that demonstrate the Jobs library. + +An AWS (Amazon Web Services) IoT Job is used to define a set of remote operations +that are sent to and executed on one or more devices connected to AWS IoT. Please +refer to AWS documentation for more information about AWS IoT Jobs. +https://docs.aws.amazon.com/iot/latest/developerguide/iot-jobs.html diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/DemoTasks/LightWeightMQTTExample.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/DemoTasks/LightWeightMQTTExample.c new file mode 100644 index 000000000..aabb3a6f3 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/DemoTasks/LightWeightMQTTExample.c @@ -0,0 +1,853 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * Proof of Concept for use of MQTT light weight serializer API. + * Light weight serializer API lets user to serialize and + * deserialize MQTT messages into user provided buffer. + * This API allows use of statically allocated buffer. + * + * Example shown below uses this API to create MQTT messages and + * and send them over connection established using FreeRTOS sockets. + * The example is single threaded and uses statically allocated memory. + * + * !!! NOTE !!! + * This is work in progress to show how light weight serializer + * API can be used. This is not a complete demo, and should not + * be treated as production ready code. + */ + +/* Standard includes. */ +#include +#include + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* IoT SDK includes. */ +#include "iot_mqtt.h" +#include "iot_mqtt_serialize.h" +#include "platform/iot_network_freertos.h" + +/* Demo Specific configs. */ +#include "mqtt_demo_profile.h" + + +/** + * @brief Time to wait between each cycle of the demo implemented by prvMQTTDemoTask(). + */ +#define mqttexampleDELAY_BETWEEN_DEMO_ITERATIONS ( pdMS_TO_TICKS( 5000 ) ) + +/** + * @brief Time to wait before sending ping request to keep MQTT connection alive. + */ +#define mqttexampleKEEP_ALIVE_DELAY ( pdMS_TO_TICKS( 1000 ) ) + + +/** + * @brief The MQTT client identifier used in this example. Each client identifier + * must be unique so edit as required to ensure no two clients connecting to the + * same broker use the same client identifier. + */ +#define mqttexampleCLIENT_IDENTIFIER mqttdemoprofileCLIENT_IDENTIFIER + +/** + * @brief Details of the MQTT broker to connect to. + */ +#define mqttexampleMQTT_BROKER_ENDPOINT mqttdemoprofileBROKER_ENDPOINT + +/** + * @brief The port to use for the demo. + */ +#define mqttexampleMQTT_BROKER_PORT mqttdemoprofileBROKER_PORT + +/** + * @brief The topic to subscribe and publish to in the example. + * + * The topic starts with the client identifier to ensure that each demo interacts + * with a unique topic. + */ +#define mqttexampleTOPIC mqttexampleCLIENT_IDENTIFIER "/example/topic" + +/** + * @brief The MQTT message published in this example. + */ +#define mqttexampleMESSAGE "Hello Light Weight MQTT World!" + +/** + * @brief Dimensions a file scope buffer currently used to send and receive MQTT data from a + * socket + */ +#define mqttexampleSHARED_BUFFER_SIZE 500 + +/*-----------------------------------------------------------*/ + +/** + * @brief MQTT Protocol constants used by this demo. + * These types are defined in internal MQTT include files. + * For light-weight demo application, only a few are needed, therefore + * they are redefined here so that internal files need not be included. + */ + +/* MQTT Control Packet Types.*/ +#define MQTT_PACKET_TYPE_CONNACK ( ( uint8_t ) 0x20U ) /**< @brief CONNACK (server-to-client). */ +#define MQTT_PACKET_TYPE_PUBLISH ( ( uint8_t ) 0x30U ) /**< @brief PUBLISH (bi-directional). */ +#define MQTT_PACKET_TYPE_SUBACK ( ( uint8_t ) 0x90U ) /**< @brief SUBACK (server-to-client). */ +#define MQTT_PACKET_TYPE_UNSUBACK ( ( uint8_t ) 0xb0U ) /**< @brief UNSUBACK (server-to-client). */ +#define MQTT_PACKET_TYPE_PINGRESP ( ( uint8_t ) 0xd0U ) /**< @brief PINGRESP (server-to-client). */ +/* MQTT Fixed Packet Sizes */ +#define MQTT_PACKET_DISCONNECT_SIZE ( ( uint8_t ) 2 ) /**< @brief Size of DISCONNECT packet. */ +#define MQTT_PACKET_PINGREQ_SIZE ( ( uint8_t ) 2 ) /**< @brief Size of PINGREQ packet. */ + +/*-----------------------------------------------------------*/ + +/** + * @brief The task used to demonstrate the MQTT API. + * + * @param[in] pvParameters Parameters as passed at the time of task creation. Not + * used in this example. + */ +static void prvMQTTDemoTask( void * pvParameters ); + +/** + * @brief Creates a TCP connection to the MQTT broker as specified in + * mqttexampleMQTT_BROKER_ENDPOINT and mqttexampleMQTT_BROKER_PORT. + * + * @return On success the socket connected to the MQTT broker is returned. Otherwise + * FREERTOS_INVALID_SOCKET is returned. + * + */ +static Socket_t prvCreateTCPConnectionToBroker( void ); + +/** + * @brief Sends an MQTT Connect packet over the already connected TCP socket. + * + * @param xMQTTSocketis a TCP socket that is connected to an MQTT broker to which + * an MQTT connection has been established. + * + * @return IOT_MQTT_SUCCESS is returned if the reply is a valid connection + * acknowledgeable (CONNACK) packet, otherwise an error code is returned. + */ +static IotMqttError_t prvCreateMQTTConnectionWithBroker( Socket_t xMQTTSocket ); + +/** + * @brief Performs a graceful shutdown and close of the socket passed in as its + * parameter. + * + * @param xMQTTSocket is a TCP socket that is connected to an MQTT broker to which + * an MQTT connection has been established. + */ +static void prvGracefulShutDown( Socket_t xSocket ); + +/** + * @brief Subscribes to the topic as specified in mqttexampleTOPIC. + * + * @param xMQTTSocket is a TCP socket that is connected to an MQTT broker to which + * an MQTT connection has been established. + * + * @return IOT_MQTT_SUCCESS is returned if the + * subscription is successful, otherwise an error code is returned. + */ +static IotMqttError_t prvMQTTSubscribeToTopic( Socket_t xMQTTSocket ); + +/** + * @brief Publishes a messages mqttexampleMESSAGE on mqttexampleTOPIC topic. + * + * @param xMQTTSocket is a TCP socket that is connected to an MQTT broker to which + * an MQTT connection has been established. + * + * @return IOT_MQTT_SUCCESS is returned if Publish is successful, + * otherwise an error code is returned. + */ +static IotMqttError_t prvMQTTPublishToTopic( Socket_t xMQTTSocket ); + +/** + * @brief Process Incoming Publish. + * + * @param xMQTTSocket is a TCP socket that is connected to an MQTT broker to which + * an MQTT connection has been established. + * + * @return #IOT_MQTT_SUCCESS is returned if the processing is successful, + * otherwise an error code is returned. + */ +static IotMqttError_t prvMQTTProcessIncomingPublish( Socket_t xMQTTSocket ); + +/** + * @brief Unsubscribes from the previously subscribed topic as specified + * in mqttexampleTOPIC. + * + * @param xMQTTSocket is a TCP socket that is connected to an MQTT broker to which + * an MQTT connection has been established. + * + * @return IOT_MQTT_SUCCESS is returned if the + * unsubscribe is successful, otherwise an error code is returned. + */ +static IotMqttError_t prvMQTTUnsubscribeFromTopic( Socket_t xMQTTSocket ); + +/** + * @brief Send MQTT Ping Request to broker and receive response. + * Ping request is used to keep connection to broker alive. + * + * @param xMQTTSocket is a TCP socket that is connected to an MQTT broker to which + * an MQTT connection has been established. + * + * @return IOT_MQTT_SUCCESS is returned if the successful Ping Response is received. + * otherwise an error code is returned. + */ +static IotMqttError_t prvMQTTKeepAlive( Socket_t xMQTTSocket ); + +/** + * @brief Disconnect From MQTT Broker. + * + * @param xMQTTSocket is a TCP socket that is connected to an MQTT broker to which + * an MQTT connection has been established. + * + * @return IOT_MQTT_SUCCESS is returned if the disconnect is successful, + * otherwise an error code is returned. + */ +static IotMqttError_t prvMQTTDisconnect( Socket_t xMQTTSocket ); + + +/*-----------------------------------------------------------*/ + +/** + * @brief Function to receive next byte from network, + * The declaration must match IotMqttGetNextByte_t. + * + * @param[in] pvContext Network Connection context. Implementation in this + * file uses FreeRTOS socket. + * @param[in, out] pNextBye Pointer to buffer where the byte will be stored. + * + * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_TIMEOUT + */ + +IotMqttError_t getNextByte( void * pvContext, + uint8_t * pNextByte ); + +/*-----------------------------------------------------------*/ + +/* @brief Static memory buffer used for sending and receiving MQTT messages */ +static uint8_t ucSharedBuffer[ mqttexampleSHARED_BUFFER_SIZE ]; + +/*-----------------------------------------------------------*/ + +/* + * @brief Task for Light Weight MQTT Serializer API Proof of Concept. + * To run the proof of concept example, in main.c, in function vApplicationIPNetworkEventHook(), + * replace vStartSimpleMQTTDemo() with vApplicationIPNetworkEventHook(). + */ +void vStartLightWeightMQTTDemo( void ) +{ +TickType_t xShortDelay = ( TickType_t ) pdMS_TO_TICKS( ( TickType_t ) 500 ); + + /* Wait a short time to allow receipt of the ARP replies. */ + vTaskDelay( xShortDelay ); + + /* This example uses a single application task, which in turn is used to + * connect, subscribe, publish, unsubscribe and disconnect from the MQTT + * broker. */ + xTaskCreate( prvMQTTDemoTask, /* Function that implements the task. */ + "MQTTLWDemo", /* Text name for the task - only used for debugging. */ + democonfigDEMO_STACKSIZE, /* Size of stack (in words, not bytes) to allocate for the task. */ + NULL, /* Task parameter - not used in this case. */ + tskIDLE_PRIORITY, /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */ + NULL ); /* Used to pass out a handle to the created task - not used in this case. */ +} +/*-----------------------------------------------------------*/ + +static void prvGracefulShutDown( Socket_t xSocket ) +{ +uint8_t ucDummy[ 20 ]; +const TickType_t xShortDelay = pdMS_TO_MIN_TICKS( 250 ); + + if( xSocket != ( Socket_t ) 0 ) + { + if( xSocket != FREERTOS_INVALID_SOCKET ) + { + /* Initiate graceful shutdown. */ + FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR ); + + /* Wait for the socket to disconnect gracefully (indicated by FreeRTOS_recv() + * returning a FREERTOS_EINVAL error) before closing the socket. */ + while( FreeRTOS_recv( xSocket, ucDummy, sizeof( ucDummy ), 0 ) >= 0 ) + { + /* Wait for shutdown to complete. If a receive block time is used then + * this delay will not be necessary as FreeRTOS_recv() will place the RTOS task + * into the Blocked state anyway. */ + vTaskDelay( xShortDelay ); + + /* Note ? real applications should implement a timeout here, not just + * loop forever. */ + } + + /* The socket has shut down and is safe to close. */ + FreeRTOS_closesocket( xSocket ); + } + } +} +/*-----------------------------------------------------------*/ + +IotMqttError_t getNextByte( void * pvContext, + uint8_t * pNextByte ) +{ +Socket_t xMQTTSocket = ( Socket_t ) pvContext; +BaseType_t receivedBytes; +IotMqttError_t result; + + /* Receive one byte from network */ + receivedBytes = FreeRTOS_recv( xMQTTSocket, ( void * ) pNextByte, sizeof( uint8_t ), 0 ); + + if( receivedBytes == sizeof( uint8_t ) ) + { + result = IOT_MQTT_SUCCESS; + } + else + { + result = IOT_MQTT_TIMEOUT; + } + + return result; +} + +/*-----------------------------------------------------------*/ + +static void prvMQTTDemoTask( void * pvParameters ) +{ +const TickType_t xNoDelay = ( TickType_t ) 0; +Socket_t xMQTTSocket; +IotMqttError_t xReturned; +uint32_t ulPublishCount = 0; +const uint32_t ulMaxPublishCount = 5UL; + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + for( ; ; ) + { + /* Don't expect any notifications to be pending yet. */ + configASSERT( ulTaskNotifyTake( pdTRUE, xNoDelay ) == 0 ); + + /****************************** Connect. ******************************/ + + /* Establish a TCP connection with the MQTT broker. This example connects to + * the MQTT broker as specified in mqttexampleMQTT_BROKER_ENDPOINT and + * mqttexampleMQTT_BROKER_PORT at the top of this file. */ + configPRINTF( ( "Create a TCP connection to %s\r\n", mqttexampleMQTT_BROKER_ENDPOINT ) ); + xMQTTSocket = prvCreateTCPConnectionToBroker(); + configASSERT( xMQTTSocket != FREERTOS_INVALID_SOCKET ); + configPRINTF( ( "Connected to %s\r\n", mqttexampleMQTT_BROKER_ENDPOINT ) ); + + /* Sends an MQTT Connect packet over the already connected TCP socket + * xMQTTSocket, then waits for and interprets the reply. IOT_MQTT_SUCCESS is + * returned if the reply is a valid connection acknowledgeable (CONNACK) packet, + * otherwise an error code is returned. */ + configPRINTF( ( "Creating an MQTT connection with %s\r\n", mqttexampleMQTT_BROKER_ENDPOINT ) ); + xReturned = prvCreateMQTTConnectionWithBroker( xMQTTSocket ); + configASSERT( xReturned == IOT_MQTT_SUCCESS ); + configPRINTF( ( "Established an MQTT connection.\r\n" ) ); + + /**************************** Subscribe. ******************************/ + + /* The client is now connected to the broker. Subscribe to the topic + * as specified in mqttexampleTOPIC at the top of this file by sending a + * subscribe packet then waiting for a subscribe acknowledgment (SUBACK). + * This client will then publish to the same topic it subscribed to, so will + * expect all the messages it sends to the broker to be sent back to it + * from the broker. */ + configPRINTF( ( "Attempt to subscribed to the MQTT topic %s\r\n", mqttexampleTOPIC ) ); + xReturned = prvMQTTSubscribeToTopic( xMQTTSocket ); + configPRINTF( ( "Subscribed to the topic %s\r\n", mqttexampleTOPIC ) ); + + /**************************** Publish. ******************************/ + /* Send publish for with QOS0, Process Keep alive */ + for( ulPublishCount = 0; ulPublishCount < ulMaxPublishCount; ulPublishCount++ ) + { + configPRINTF( ( "Attempt to publish to the MQTT topic %s\r\n", mqttexampleTOPIC ) ); + xReturned = prvMQTTPublishToTopic( xMQTTSocket ); + configASSERT( xReturned == IOT_MQTT_SUCCESS ); + configPRINTF( ( "Publish successful to the topic %s\r\n", mqttexampleTOPIC ) ); + + /* Process incoming publish echo, since application subscribed to the same topic + * broker will send publish message back to the application */ + configPRINTF( ( "Attempt to receive publish message from broker\r\n" ) ); + xReturned = prvMQTTProcessIncomingPublish( xMQTTSocket ); + configASSERT( xReturned == IOT_MQTT_SUCCESS ); + configPRINTF( ( "Successfully Received Publish message from broker\r\n" ) ); + + /* Leave Connection Idle for some time */ + configPRINTF( ( "Keeping Connection Idle\r\n" ) ); + vTaskDelay( pdMS_TO_TICKS( mqttexampleKEEP_ALIVE_DELAY ) ); + /* Send Ping request to broker and receive ping response */ + configPRINTF( ( "Sending Ping Request to the broker\r\n" ) ); + xReturned = prvMQTTKeepAlive( xMQTTSocket ); + configASSERT( xReturned == IOT_MQTT_SUCCESS ); + configPRINTF( ( "Ping Response successfully received\r\n" ) ); + } + + /************************ Unsubscribe from the topic. **************************/ + configPRINTF( ( "Attempt to unsubscribe from the MQTT topic %s\r\n", mqttexampleTOPIC ) ); + xReturned = prvMQTTUnsubscribeFromTopic( xMQTTSocket ); + configASSERT( xReturned == IOT_MQTT_SUCCESS ); + configPRINTF( ( "Unsubscribe from the topic %s\r\n", mqttexampleTOPIC ) ); + + /**************************** Disconnect. ******************************/ + + /* Sends an MQTT Disconnect packet over the already connected TCP socket + * xMQTTSocket, then waits for and interprets the reply. IOT_MQTT_SUCCESS is + * returned if the reply is a valid connection acknowledgeable (CONNACK) packet, + * otherwise an error code is returned. */ + + configPRINTF( ( "Creating an MQTT connection with %s\r\n", mqttexampleMQTT_BROKER_ENDPOINT ) ); + xReturned = prvMQTTDisconnect( xMQTTSocket ); + configASSERT( xReturned == IOT_MQTT_SUCCESS ); + configPRINTF( ( "Established an MQTT connection.\r\n" ) ); + /* Disconnect from broker. */ + prvGracefulShutDown( xMQTTSocket ); + + /* Wait for some time between two iterations to ensure that we do not + * bombard the public test mosquitto broker. */ + configPRINTF( ( "prvMQTTDemoTask() completed an iteration successfully. Total free heap is %u\r\n", xPortGetFreeHeapSize() ) ); + configPRINTF( ( "Short delay before starting the next iteration.... \r\n\r\n" ) ); + vTaskDelay( pdMS_TO_TICKS( mqttexampleDELAY_BETWEEN_DEMO_ITERATIONS ) ); + } +} +/*-----------------------------------------------------------*/ + +Socket_t prvCreateTCPConnectionToBroker( void ) +{ +Socket_t xMQTTSocket; + struct freertos_sockaddr xBrokerAddress; + uint32_t ulBrokerIPAddress; + + /* This is the socket used to connect to the MQTT broker. */ + xMQTTSocket = FreeRTOS_socket( FREERTOS_AF_INET, + FREERTOS_SOCK_STREAM, + FREERTOS_IPPROTO_TCP ); + + configASSERT( xMQTTSocket != FREERTOS_INVALID_SOCKET ); + + /* Locate then connect to the MQTT broker. */ + ulBrokerIPAddress = FreeRTOS_gethostbyname( mqttexampleMQTT_BROKER_ENDPOINT ); + + if( ulBrokerIPAddress != 0 ) + { + xBrokerAddress.sin_port = FreeRTOS_htons( mqttexampleMQTT_BROKER_PORT ); + xBrokerAddress.sin_addr = ulBrokerIPAddress; + + if( FreeRTOS_connect( xMQTTSocket, &xBrokerAddress, sizeof( xBrokerAddress ) ) != 0 ) + { + /* Could not connect so delete socket and return an error. */ + FreeRTOS_closesocket( xMQTTSocket ); + xMQTTSocket = FREERTOS_INVALID_SOCKET; + } + } + + return xMQTTSocket; +} +/*-----------------------------------------------------------*/ + +static IotMqttError_t prvCreateMQTTConnectionWithBroker( Socket_t xMQTTSocket ) +{ +IotMqttConnectInfo_t xConnectInfo; +size_t xRemainingLength = 0; +size_t xPacketSize = 0; +IotMqttError_t xResult; +IotMqttPacketInfo_t xIncomingPacket; + + /* Many fields not used in this demo so start with everything at 0. */ + memset( ( void * ) &xConnectInfo, 0x00, sizeof( xConnectInfo ) ); + memset( ( void * ) &xIncomingPacket, 0x00, sizeof( xIncomingPacket ) ); + + /* Start with a clean session i.e. direct the MQTT broker to discard any + * previous session data. Also, establishing a connection with clean session + * will ensure that the broker does not store any data when this client + * gets disconnected. */ + xConnectInfo.cleanSession = true; + + /* The client identifier is used to uniquely identify this MQTT client to + * the MQTT broker. In a production device the identifier can be something + * unique, such as a device serial number. */ + xConnectInfo.pClientIdentifier = mqttexampleCLIENT_IDENTIFIER; + xConnectInfo.clientIdentifierLength = ( uint16_t ) strlen( mqttexampleCLIENT_IDENTIFIER ); + + /* Get size requirement for the connect packet */ + xResult = IotMqtt_GetConnectPacketSize( &xConnectInfo, &xRemainingLength, &xPacketSize ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + /* Make sure the packet size is less than static buffer size */ + configASSERT( xPacketSize < mqttexampleSHARED_BUFFER_SIZE ); + /* Serialize MQTT connect packet into provided buffer */ + xResult = IotMqtt_SerializeConnect( &xConnectInfo, xRemainingLength, ucSharedBuffer, xPacketSize ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + + if( FreeRTOS_send( xMQTTSocket, ( void * ) ucSharedBuffer, xPacketSize, 0 ) == ( BaseType_t ) xPacketSize ) + { + /* Wait for the connection ack. TODO check the receive timeout value. */ + + memset( ( void * ) &xIncomingPacket, 0x00, sizeof( IotMqttPacketInfo_t ) ); + + /* Get packet type and remaining length of the received packet + * We cannot assume received data is the connection acknowledgment. + * Therefore this function reads type and remaining length of the + * received packet, before processing entire packet. + */ + xResult = IotMqtt_GetIncomingMQTTPacketTypeAndLength( &xIncomingPacket, getNextByte, ( void * ) xMQTTSocket ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + configASSERT( xIncomingPacket.type == MQTT_PACKET_TYPE_CONNACK ); + configASSERT( xIncomingPacket.remainingLength <= mqttexampleSHARED_BUFFER_SIZE ); + + if( FreeRTOS_recv( xMQTTSocket, ( void * ) ucSharedBuffer, xIncomingPacket.remainingLength, 0 ) + == ( BaseType_t ) xIncomingPacket.remainingLength ) + { + xIncomingPacket.pRemainingData = ucSharedBuffer; + + if( IotMqtt_DeserializeResponse( &xIncomingPacket ) != IOT_MQTT_SUCCESS ) + { + xResult = IOT_MQTT_SERVER_REFUSED; + } + } + else + { + configPRINTF( ( "Receive Failed while receiving MQTT ConnAck\n" ) ); + xResult = IOT_MQTT_NETWORK_ERROR; + } + } + else + { + configPRINTF( ( "Send Failed while connecting to MQTT broker\n" ) ); + xResult = IOT_MQTT_NETWORK_ERROR; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +static IotMqttError_t prvMQTTSubscribeToTopic( Socket_t xMQTTSocket ) +{ +IotMqttError_t xResult; +IotMqttSubscription_t xMQTTSubscription[ 1 ]; +size_t xRemainingLength = 0; +size_t xPacketSize = 0; +uint16_t usPacketIdentifier; +IotMqttPacketInfo_t xIncomingPacket; + + /* Some fields not used by this demo so start with everything at 0. */ + memset( ( void * ) &xMQTTSubscription, 0x00, sizeof( xMQTTSubscription ) ); + + /* Subscribe to the mqttexampleTOPIC topic filter. This example subscribes to only one topic */ + xMQTTSubscription[ 0 ].qos = IOT_MQTT_QOS_0; + xMQTTSubscription[ 0 ].pTopicFilter = mqttexampleTOPIC; + xMQTTSubscription[ 0 ].topicFilterLength = ( uint16_t ) strlen( mqttexampleTOPIC ); + + xResult = IotMqtt_GetSubscriptionPacketSize( IOT_MQTT_SUBSCRIBE, + xMQTTSubscription, + sizeof( xMQTTSubscription ) / sizeof( IotMqttSubscription_t ), + &xRemainingLength, &xPacketSize ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + /* Make sure the packet size is less than static buffer size */ + configASSERT( xPacketSize < mqttexampleSHARED_BUFFER_SIZE ); + + /* Serialize subscribe into statically allocated ucSharedBuffer */ + xResult = IotMqtt_SerializeSubscribe( xMQTTSubscription, + sizeof( xMQTTSubscription ) / sizeof( IotMqttSubscription_t ), + xRemainingLength, + &usPacketIdentifier, + ucSharedBuffer, + xPacketSize ); + + configASSERT( xResult == IOT_MQTT_SUCCESS ); + + if( FreeRTOS_send( xMQTTSocket, ( void * ) ucSharedBuffer, xPacketSize, 0 ) == ( BaseType_t ) xPacketSize ) + { + /* Wait for the subscription ack. The socket is already connected to the MQTT broker, so + * publishes to this client can occur at any time and we cannot assume received + * data is the subscription acknowledgment. Therefore this function is, at this + * time, doing what would otherwise be done wherever incoming packets are + * interpreted (in a callback, or whatever). */ + memset( ( void * ) &xIncomingPacket, 0x00, sizeof( IotMqttPacketInfo_t ) ); + xResult = IotMqtt_GetIncomingMQTTPacketTypeAndLength( &xIncomingPacket, getNextByte, ( void * ) xMQTTSocket ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + configASSERT( xIncomingPacket.type == MQTT_PACKET_TYPE_SUBACK ); + configASSERT( xIncomingPacket.remainingLength <= mqttexampleSHARED_BUFFER_SIZE ); + + /* Receive the remaining bytes. */ + if( FreeRTOS_recv( xMQTTSocket, ( void * ) ucSharedBuffer, xIncomingPacket.remainingLength, 0 ) == ( BaseType_t ) xIncomingPacket.remainingLength ) + { + xIncomingPacket.pRemainingData = ucSharedBuffer; + + if( IotMqtt_DeserializeResponse( &xIncomingPacket ) != IOT_MQTT_SUCCESS ) + { + xResult = IOT_MQTT_BAD_RESPONSE; + } + } + else + { + xResult = IOT_MQTT_NETWORK_ERROR; + } + } + else + { + xResult = IOT_MQTT_NETWORK_ERROR; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +static IotMqttError_t prvMQTTPublishToTopic( Socket_t xMQTTSocket ) +{ +IotMqttError_t xResult; +IotMqttPublishInfo_t xMQTTPublishInfo; +size_t xRemainingLength = 0; +size_t xPacketSize = 0; +uint16_t usPacketIdentifier; +uint8_t * pusPacketIdentifierHigh; + + /* Some fields not used by this demo so start with everything at 0. */ + memset( ( void * ) &xMQTTPublishInfo, 0x00, sizeof( xMQTTPublishInfo ) ); + xMQTTPublishInfo.qos = IOT_MQTT_QOS_0; + xMQTTPublishInfo.retain = false; + xMQTTPublishInfo.pTopicName = mqttexampleTOPIC; + xMQTTPublishInfo.topicNameLength = ( uint16_t ) strlen( mqttexampleTOPIC ); + xMQTTPublishInfo.pPayload = mqttexampleMESSAGE; + xMQTTPublishInfo.payloadLength = strlen( mqttexampleMESSAGE ); + + /* Find out length of Publish packet size. */ + xResult = IotMqtt_GetPublishPacketSize( &xMQTTPublishInfo, &xRemainingLength, &xPacketSize ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + /* Make sure the packet size is less than static buffer size */ + configASSERT( xPacketSize < mqttexampleSHARED_BUFFER_SIZE ); + + xResult = IotMqtt_SerializePublish( &xMQTTPublishInfo, + xRemainingLength, + &usPacketIdentifier, + &pusPacketIdentifierHigh, + ucSharedBuffer, + xPacketSize ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + + if( FreeRTOS_send( xMQTTSocket, ( void * ) ucSharedBuffer, xPacketSize, 0 ) != ( BaseType_t ) xPacketSize ) + { + xResult = IOT_MQTT_NETWORK_ERROR; + } + else + { + /* Send success. Since in this case, we are using IOT_MQTT_QOS_0, + * there will not be any PubAck. Publish will be echoed back, which is processed + * in prvMQTTProcessIncomingPublish() */ + xResult = IOT_MQTT_SUCCESS; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +static IotMqttError_t prvMQTTProcessIncomingPublish( Socket_t xMQTTSocket ) +{ +IotMqttError_t xResult; +IotMqttPacketInfo_t xIncomingPacket; + + memset( ( void * ) &xIncomingPacket, 0x00, sizeof( IotMqttPacketInfo_t ) ); + xResult = IotMqtt_GetIncomingMQTTPacketTypeAndLength( &xIncomingPacket, getNextByte, ( void * ) xMQTTSocket ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + configASSERT( ( xIncomingPacket.type & 0xf0 ) == MQTT_PACKET_TYPE_PUBLISH ); + configASSERT( xIncomingPacket.remainingLength <= mqttexampleSHARED_BUFFER_SIZE ); + + /* Receive the remaining bytes. */ + if( FreeRTOS_recv( xMQTTSocket, ( void * ) ucSharedBuffer, xIncomingPacket.remainingLength, 0 ) == ( BaseType_t ) xIncomingPacket.remainingLength ) + { + xIncomingPacket.pRemainingData = ucSharedBuffer; + + if( IotMqtt_DeserializePublish( &xIncomingPacket ) != IOT_MQTT_SUCCESS ) + { + xResult = IOT_MQTT_BAD_RESPONSE; + } + else + { + /* Process incoming Publish */ + configPRINTF( ( "Incoming QOS : %d\n", xIncomingPacket.pubInfo.qos ) ); + configPRINTF( ( "Incoming Publish Topic Name: %.*s\n", xIncomingPacket.pubInfo.topicNameLength, xIncomingPacket.pubInfo.pTopicName ) ); + configPRINTF( ( "Incoming Publish Message : %.*s\n", xIncomingPacket.pubInfo.payloadLength, xIncomingPacket.pubInfo.pPayload ) ); + } + } + else + { + xResult = IOT_MQTT_NETWORK_ERROR; + } + + return xResult; +} + +/*-----------------------------------------------------------*/ + +static IotMqttError_t prvMQTTUnsubscribeFromTopic( Socket_t xMQTTSocket ) +{ +IotMqttError_t xResult; +IotMqttSubscription_t xMQTTSubscription[ 1 ]; +size_t xRemainingLength; +size_t xPacketSize; +uint16_t usPacketIdentifier; +IotMqttPacketInfo_t xIncomingPacket; + + /* Some fields not used by this demo so start with everything at 0. */ + memset( ( void * ) &xMQTTSubscription, 0x00, sizeof( xMQTTSubscription ) ); + + /* Unsubscribe to the mqttexampleTOPIC topic filter. The task handle is passed + * as the callback context which is used by the callback to send a task + * notification to this task.*/ + xMQTTSubscription[ 0 ].qos = IOT_MQTT_QOS_0; + xMQTTSubscription[ 0 ].pTopicFilter = mqttexampleTOPIC; + xMQTTSubscription[ 0 ].topicFilterLength = ( uint16_t ) strlen( mqttexampleTOPIC ); + + xResult = IotMqtt_GetSubscriptionPacketSize( IOT_MQTT_UNSUBSCRIBE, + xMQTTSubscription, + sizeof( xMQTTSubscription ) / sizeof( IotMqttSubscription_t ), + &xRemainingLength, + &xPacketSize ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + /* Make sure the packet size is less than static buffer size */ + configASSERT( xPacketSize < mqttexampleSHARED_BUFFER_SIZE ); + + xResult = IotMqtt_SerializeUnsubscribe( xMQTTSubscription, + sizeof( xMQTTSubscription ) / sizeof( IotMqttSubscription_t ), + xRemainingLength, + &usPacketIdentifier, + ucSharedBuffer, + xPacketSize ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + + if( FreeRTOS_send( xMQTTSocket, ( void * ) ucSharedBuffer, xPacketSize, 0 ) == ( BaseType_t ) xPacketSize ) + { + /* Wait for the subscription ack. The socket is already connected to the MQTT broker, so + * publishes to this client can occur at any time and we cannot assume received + * data is the subscription acknowledgment. Therefore this function is, at this + * time, doing what would otherwise be done wherever incoming packets are + * interpreted (in a callback, or whatever). */ + memset( ( void * ) &xIncomingPacket, 0x00, sizeof( IotMqttPacketInfo_t ) ); + xResult = IotMqtt_GetIncomingMQTTPacketTypeAndLength( &xIncomingPacket, getNextByte, ( void * ) xMQTTSocket ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + configASSERT( xIncomingPacket.type == MQTT_PACKET_TYPE_UNSUBACK ); + configASSERT( xIncomingPacket.remainingLength <= sizeof( ucSharedBuffer ) ); + + /* Receive the remaining bytes. */ + if( FreeRTOS_recv( xMQTTSocket, ( void * ) ucSharedBuffer, xIncomingPacket.remainingLength, 0 ) == ( BaseType_t ) xIncomingPacket.remainingLength ) + { + xIncomingPacket.pRemainingData = ucSharedBuffer; + + if( IotMqtt_DeserializeResponse( &xIncomingPacket ) != IOT_MQTT_SUCCESS ) + { + xResult = IOT_MQTT_BAD_RESPONSE; + } + } + else + { + xResult = IOT_MQTT_NETWORK_ERROR; + } + } + else + { + xResult = IOT_MQTT_NETWORK_ERROR; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +static IotMqttError_t prvMQTTKeepAlive( Socket_t xMQTTSocket ) +{ +IotMqttError_t xResult; +IotMqttPacketInfo_t xIncomingPacket; + + /* PingReq is fixed length packet, therefore there is no need to calculate the size, + * just makes sure static buffer can accommodate ping request */ + + configASSERT( MQTT_PACKET_PINGREQ_SIZE <= mqttexampleSHARED_BUFFER_SIZE ); + + xResult = IotMqtt_SerializePingreq( ucSharedBuffer, MQTT_PACKET_PINGREQ_SIZE ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + + if( FreeRTOS_send( xMQTTSocket, ( void * ) ucSharedBuffer, MQTT_PACKET_PINGREQ_SIZE, 0 ) == ( BaseType_t ) MQTT_PACKET_PINGREQ_SIZE ) + { + memset( ( void * ) &xIncomingPacket, 0x00, sizeof( IotMqttPacketInfo_t ) ); + xResult = IotMqtt_GetIncomingMQTTPacketTypeAndLength( &xIncomingPacket, getNextByte, ( void * ) xMQTTSocket ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + configASSERT( xIncomingPacket.type == MQTT_PACKET_TYPE_PINGRESP ); + configASSERT( xIncomingPacket.remainingLength <= sizeof( ucSharedBuffer ) ); + + /* Receive the remaining bytes. */ + if( FreeRTOS_recv( xMQTTSocket, ( void * ) ucSharedBuffer, xIncomingPacket.remainingLength, 0 ) + == ( BaseType_t ) xIncomingPacket.remainingLength ) + { + xIncomingPacket.pRemainingData = ucSharedBuffer; + + if( IotMqtt_DeserializeResponse( &xIncomingPacket ) != IOT_MQTT_SUCCESS ) + { + xResult = IOT_MQTT_BAD_RESPONSE; + } + } + else + { + xResult = IOT_MQTT_NETWORK_ERROR; + } + } + else + { + xResult = IOT_MQTT_NETWORK_ERROR; + } + + return xResult; +} + +/*-----------------------------------------------------------*/ + +static IotMqttError_t prvMQTTDisconnect( Socket_t xMQTTSocket ) +{ +IotMqttError_t xResult; + + /* Disconnect is fixed length packet, therefore there is no need to calculate the size, + * just makes sure static buffer can accommodate disconnect request */ + + configASSERT( MQTT_PACKET_DISCONNECT_SIZE <= mqttexampleSHARED_BUFFER_SIZE ); + + xResult = IotMqtt_SerializeDisconnect( ucSharedBuffer, MQTT_PACKET_DISCONNECT_SIZE ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + + if( FreeRTOS_send( xMQTTSocket, ( void * ) ucSharedBuffer, MQTT_PACKET_DISCONNECT_SIZE, 0 ) == ( BaseType_t ) MQTT_PACKET_DISCONNECT_SIZE ) + { + xResult = IOT_MQTT_SUCCESS; + } + else + { + xResult = IOT_MQTT_NETWORK_ERROR; + } + + return xResult; +} diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/DemoTasks/SimpleMQTTExamples.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/DemoTasks/SimpleMQTTExamples.c new file mode 100644 index 000000000..feb872c52 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/DemoTasks/SimpleMQTTExamples.c @@ -0,0 +1,659 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * This file contains the common functions for plain text, basic TLS, and mutual + * authentication MQTT demos. Aside from the difference in security level during + * connect, the three demos perform the same interaction with a MQTT broker. The + * demos create a single application task that connects to a MQTT broker, + * subscribes to a topic, publishes a topic with a message, and disconnect from a + * MQTT broker. The task subscribes to the same topic it publishes to, receiving + * the message it sends to the broker. Note that this demo does not terminate, the + * connect-subscribe-publish-disconnect cycle is repeated for unlimited number of + * times. + * + * The plain text MQTT demo does not authenticate the server nor the client. The + * basic TLS MQTT demo builds on top of the plain text demo, adding broker + * authentication and encryption. The mutual authentication MQTT demo builds on top + * of the basic TLS demo, enabling both server and client authentication. + * + * For more information regarding the MQTT library and the demo, please refer to: + * https://freertos.org/mqtt/index.html + */ + +/* Standard includes. */ +#include +#include + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" + +/* IoT SDK includes. */ +#include "iot_mqtt.h" +#include "iot_taskpool_freertos.h" +#include "platform/iot_network_freertos.h" + +/* MQTT Demo Select */ +#include "demo_config.h" + +/* Select MQTT profile based on the setting in demo_config.h */ +#if ( democonfigPROFILE_USE_AWS_IOT == 1 ) + #include "aws_iot_demo_profile.h" +#else + #include "mqtt_demo_profile.h" +#endif + +/* Preprocessor check for configuration */ +#include "aws_iot_setup_check.h" + +/* + * Set connection profile based on the setting in demo_config.h. For more + * information on each variable, please refer to the respective *_profile.h + * file in FreeRTOS-Labs\Demo\FreeRTOS_IoT_Libraries\include. + * + * Note that if you are running mqtt_tls_mutual_auth demo please make sure to + * visit the following link for setup: + * https://www.freertos.org/mqtt/preconfiguredexamplesMA.html + */ +#if ( democonfigPROFILE_USE_AWS_IOT == 1 ) + #define mqttexampleBROKER_ENDPOINT awsiotdemoprofileAWS_ENDPOINT + #define mqttexampleBROKER_PORT awsiotdemoprofileAWS_MQTT_PORT + #define mqttexampleBROKER_CERTIFICATE_PEM awsiotdemoprofileAWS_CERTIFICATE_PEM + #define mqttexampleCLIENT_IDENTIFIER awsiotdemoprofileCLIENT_IDENTIFIER + #define mqttexampleCLIENT_CERTIFICATE_PEM awsiotdemoprofileCLIENT_CERTIFICATE_PEM + #define mqttexampleCLIENT_PRIVATE_KEY_PEM awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM +#else + #define mqttexampleBROKER_ENDPOINT mqttdemoprofileBROKER_ENDPOINT + #define mqttexampleBROKER_PORT mqttdemoprofileBROKER_PORT + #define mqttexampleBROKER_CERTIFICATE_PEM mqttdemoprofileBROKER_CERTIFICATE_PEM + #define mqttexampleCLIENT_IDENTIFIER mqttdemoprofileCLIENT_IDENTIFIER +#endif /* if ( democonfigPROFILE_USE_AWS_IOT == pdTRUE ) */ + +/** + * @brief The keep-alive interval used for this example. + * + * An MQTT ping request will be sent periodically at this interval. + * + * @note: This value is set to zero to disable MQTT + * keep alive for the Windows simulator project. + * The FreeRTOS kernel does not accurately calculate time for the Windows + * Simulator. Therefore, MQTT PING Request messages may be sent + * at an incorrect time interval to the broker. If the broker does + * not receive a ping request within 1.5x the time sent in a + * connection request, the broker may close the connection. + * To enable the keep alive feature, set this value + * to the desired interval in seconds. + */ +#define mqttexampleKEEP_ALIVE_SECONDS ( 0 ) + +/** + * @brief The timeout for MQTT operations in this example. + */ +#define mqttexampleMQTT_TIMEOUT_MS ( 5000 ) + +/** + * @brief The topic to subscribe and publish to in the example. + * + * The topic starts with the client identifier to ensure that each demo interacts + * with a unique topic. + */ +#define mqttexampleTOPIC mqttexampleCLIENT_IDENTIFIER "/example/topic" + +/** + * @brief The MQTT message published in this example. + */ +#define mqttexampleMESSAGE "Hello World!" + +/** + * @brief Parameters to control the retry behavior in case a QoS1 publish + * message gets lost. + * + * Retry every minutes up to a maximum of 5 retries. + */ +#define mqttexamplePUBLISH_RETRY_MS ( 1000 ) +#define mqttexamplePUBLISH_RETRY_LIMIT ( 5 ) + +/** + * @brief The bit which is set in the demo task's notification value from the + * disconnect callback to inform the demo task about the MQTT disconnect. + */ +#define mqttexampleDISCONNECTED_BIT ( 1UL << 0UL ) + +/** + * @brief The bit which is set in the demo task's notification value from the + * publish callback to inform the demo task about the message received from the + * MQTT broker. + */ +#define mqttexampleMESSAGE_RECEIVED_BIT ( 1UL << 1UL ) + +/*-----------------------------------------------------------*/ + +/** + * @brief The task used to demonstrate the MQTT API. + * + * @param[in] pvParameters Parameters as passed at the time of task creation. Not + * used in this example. + */ +static void prvMQTTDemoTask( void * pvParameters ); + +/** + * @brief The callback invoked by the MQTT library when the MQTT connection gets + * disconnected. + * + * @param[in] pvCallbackContext Callback context as provided at the time of + * connect. + * @param[in] pxCallbackParams Contains the reason why the MQTT connection was + * disconnected. + */ +static void prvExample_OnDisconnect( void * pvCallbackContext, + IotMqttCallbackParam_t * pxCallbackParams ); + +/** + * @brief The callback invoked by the MQTT library when a message is received on + * a subscribed topic from the MQTT broker. + * + * @param[in] pvCallbackContext Callback context as provided at the time of + * subscribe. + * @param[in] pxCallbackParams Contain the details about the received message - + * topic on which the message was received, the received message. + */ +static void prvExample_OnMessageReceived( void * pvCallbackContext, + IotMqttCallbackParam_t * pxCallbackParams ); + +/** + * @brief Connects to the MQTT broker as specified in mqttexampleBROKER_ENDPOINT + * and mqttexampleBROKER_PORT. + */ +static void prvMQTTConnect( void ); + +/** + * @brief Subscribes to the topic as specified in mqttexampleTOPIC. + */ +static void prvMQTTSubscribe( void ); + +/** + * @brief Publishes a messages mqttexampleMESSAGE on mqttexampleTOPIC topic. + */ +static void prvMQTTPublish( void ); + +/** + * @brief Unsubscribes from the mqttexampleTOPIC topic. + */ +static void prvMQTTUnsubscribe( void ); + +/** + * @brief Disconnects from the MQTT broker gracefully by sending an MQTT + * DISCONNECT message. + */ +static void prvMQTTDisconnect( void ); + +/** +* @brief Initializes the IoT libraries used by this demo. +*/ +static void prvInitialiseLibraries( void ); + +/** + * @brief The MQTT connection handle used in this example. + */ +static IotMqttConnection_t xMQTTConnection = IOT_MQTT_CONNECTION_INITIALIZER; + +/*-----------------------------------------------------------*/ + +/** + * @brief Parameters used to create the system task pool. + */ +static const IotTaskPoolInfo_t xTaskPoolParameters = +{ + /* Minimum number of threads in a task pool. + * Note the slimmed down version of the task + * pool used by this library does not auto-scale + * the number of tasks in the pool so in this + * case this sets the number of tasks in the + * pool. */ + 1, + + /* Maximum number of threads in a task pool. + * Note the slimmed down version of the task + * pool used by this library does not auto-scale + * the number of tasks in the pool so in this + * case this parameter is just ignored. */ + 1, + + /* Stack size for every task pool thread - in + * bytes, hence multiplying by the number of bytes + * in a word as configMINIMAL_STACK_SIZE is + * specified in words. */ + configMINIMAL_STACK_SIZE * sizeof( portSTACK_TYPE ), + /* Priority for every task pool thread. */ + tskIDLE_PRIORITY, +}; + +/*-----------------------------------------------------------*/ + +static const struct IotNetworkServerInfo xMQTTBrokerInfo = +{ + .pHostName = mqttexampleBROKER_ENDPOINT, + .port = mqttexampleBROKER_PORT +}; + +#if ( democonfigENABLE_TLS ) + static struct IotNetworkCredentials xNetworkSecurityCredentials = + { + /* Optional TLS extensions. For this demo, they are disabled. */ + .pAlpnProtos = NULL, + .maxFragmentLength = 0, + + /* SNI is enabled by default. */ + .disableSni = false, + + /* Provide the certificate for validating the server. Only required for + * demos using TLS. */ + .pRootCa = mqttexampleBROKER_CERTIFICATE_PEM, + .rootCaSize = sizeof( mqttexampleBROKER_CERTIFICATE_PEM ), + + /* Strong mutual authentication to authenticate both the broker and + * the client. */ + #if ( democonfigENABLE_MUTUAL_AUTH ) + .pClientCert = mqttexampleCLIENT_CERTIFICATE_PEM, + .clientCertSize = sizeof( mqttexampleCLIENT_CERTIFICATE_PEM ), + .pPrivateKey = mqttexampleCLIENT_PRIVATE_KEY_PEM, + .privateKeySize = sizeof( mqttexampleCLIENT_PRIVATE_KEY_PEM ) + #else + .pClientCert = NULL, + .clientCertSize = 0, + .pPrivateKey = NULL, + .privateKeySize = 0 + #endif /* if ( democonfigENABLE_MUTUAL_AUTH ) */ + }; +#endif /* if ( democonfigENABLE_TLS ) */ + +static IotMqttNetworkInfo_t xNetworkInfo = +{ + /* No connection to the MQTT broker has been established yet and we want to + * establish a new connection. */ + .createNetworkConnection = true, + .u.setup.pNetworkServerInfo = &( xMQTTBrokerInfo ), + + /* Set the TLS credentials for the new MQTT connection. This member is NULL + * for the plain text MQTT demo. */ + #if ( democonfigENABLE_TLS ) + .u.setup.pNetworkCredentialInfo = &xNetworkSecurityCredentials, + #else + .u.setup.pNetworkCredentialInfo = NULL, /* Not using TLS so no credentials. */ + #endif + + /* Use FreeRTOS+TCP network interface. */ + .pNetworkInterface = IOT_NETWORK_INTERFACE_FREERTOS, + + /* Setup the callback which is called when the MQTT connection is + * disconnected. The task handle is passed as the callback context which + * is used by the callback to send a task notification to this task.*/ + .disconnectCallback.function = prvExample_OnDisconnect +}; + +static const IotMqttConnectInfo_t xConnectInfo = +{ + /* Set this flag to true if connecting to the AWS IoT MQTT broker. */ + #if ( democonfigPROFILE_USE_AWS_IOT == 1 ) + .awsIotMqttMode = true, + #else + .awsIotMqttMode = false, + #endif + + /* Start with a clean session i.e. direct the MQTT broker to discard any + * previous session data. Also, establishing a connection with clean session + * will ensure that the broker does not store any data when this client + * gets disconnected. */ + .cleanSession = true, + + /* Since we are starting with a clean session, there are no previous + * subscriptions to be restored. */ + .pPreviousSubscriptions = NULL, + .previousSubscriptionCount = 0, + + /* We do not want to publish Last Will and Testament (LWT) message if the + * client gets disconnected. */ + .pWillInfo = NULL, + + /* Send an MQTT PING request every minute to keep the connection open if + there is no other MQTT traffic. */ + .keepAliveSeconds = mqttexampleKEEP_ALIVE_SECONDS, + + /* The client identifier is used to uniquely identify this MQTT client to + * the MQTT broker. In a production device the identifier can be something + * unique, such as a device serial number. */ + .pClientIdentifier = mqttexampleCLIENT_IDENTIFIER, + .clientIdentifierLength = ( uint16_t ) sizeof( mqttexampleCLIENT_IDENTIFIER ) - 1, + + /* This example does not authenticate the client and therefore username and + * password fields are not used. */ + .pUserName = NULL, + .userNameLength = 0, + .pPassword = NULL, + .passwordLength = 0 +}; +/*-----------------------------------------------------------*/ + + +void vStartSimpleMQTTDemo( void ) +{ +TickType_t xShortDelay = ( TickType_t ) pdMS_TO_TICKS( ( TickType_t ) 500 ); + + /* Wait a short time to allow receipt of the ARP replies. */ + vTaskDelay( xShortDelay ); + + /* This example uses a single application task, which in turn is used to + * connect, subscribe, publish, unsubscribe and disconnect from the MQTT + * broker. */ + xTaskCreate( prvMQTTDemoTask, /* Function that implements the task. */ + "MQTTDemo", /* Text name for the task - only used for debugging. */ + democonfigDEMO_STACKSIZE, /* Size of stack (in words, not bytes) to allocate for the task. */ + NULL, /* Task parameter - not used in this case. */ + tskIDLE_PRIORITY, /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */ + NULL ); /* Used to pass out a handle to the created task - not used in this case. */ +} +/*-----------------------------------------------------------*/ + +static void prvMQTTDemoTask( void * pvParameters ) +{ +uint32_t ulNotificationValue = 0, ulPublishCount; +const uint32_t ulMaxPublishCount = 5UL; +const TickType_t xNoDelay = ( TickType_t ) 0; + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + /* One time initialization of the libraries used by this demo. */ + prvInitialiseLibraries(); + + for( ; ; ) + { + /* Notifications are used to send events from the callback functions to this + * task. Don't expect any notifications to be pending at the beginning of the + * loop. */ + configASSERT( ulTaskNotifyTake( pdTRUE, xNoDelay ) == 0 ); + + + /****************************** Connect. ******************************/ + + /* Establish a connection to the MQTT broker. This example connects to + * the MQTT broker as specified by the compile time constants + * mqttexampleBROKER_ENDPOINT and mqttexampleBROKER_PORT. + * Please change it to the MQTT broker you want to connect to. */ + configPRINTF( ( "Attempt to connect to %s:%d\r\n", mqttexampleBROKER_ENDPOINT, mqttexampleBROKER_PORT ) ); + prvMQTTConnect(); + configPRINTF( ( "Connected to %s:%d\r\n", mqttexampleBROKER_ENDPOINT, mqttexampleBROKER_PORT ) ); + + + /**************************** Subscribe. ******************************/ + + /* The client is now connected to the broker. Subscribe to the topic + * as specified by the mqttexampleTOPIC compile time constant. This + * client will then publish to the same topic it subscribed to, so will + * expect all the messages it sends to the broker to be sent back to it + * from the broker. */ + configPRINTF( ( "Attempt to subscribed to the topic %s\r\n", mqttexampleTOPIC ) ); + prvMQTTSubscribe(); + configPRINTF( ( "Subscribed to the topic %s\r\n", mqttexampleTOPIC ) ); + + + /*********************** Publish ulMaxPublishCount messages. **********/ + + /* Publish a few messages while connected. */ + for( ulPublishCount = 0; ulPublishCount < ulMaxPublishCount; ulPublishCount++ ) + { + /* Publish a message on the topic specified by the mqttexampleTOPIC + * compile time constant. */ + configPRINTF( ( "Publish %s on the topic %s\r\n", mqttexampleMESSAGE, mqttexampleTOPIC ) ); + prvMQTTPublish(); + configPRINTF( ( "Published %s on the topic %s\r\n", mqttexampleMESSAGE, mqttexampleTOPIC ) ); + + /* Since we are subscribed to the same topic as we published on, we + * will get the same message back from the MQTT broker. Wait for the + * message to be received which is signaled to us by the publish + * callback (prvExample_OnMessageReceived) setting the + * mqttexampleMESSAGE_RECEIVED_BIT bit in this task's notification + * value. Note the bit is then cleared in the task's notification value + * to ensure the bit being set can be detected on the next iteration. */ + xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */ + mqttexampleMESSAGE_RECEIVED_BIT, /* Clear bit on exit. */ + &( ulNotificationValue ), /* Obtain the notification value. */ + pdMS_TO_TICKS( mqttexampleMQTT_TIMEOUT_MS ) ); + configASSERT( ( ulNotificationValue & mqttexampleMESSAGE_RECEIVED_BIT ) == mqttexampleMESSAGE_RECEIVED_BIT ); + } + + /******************* Unsubscribe and Disconnect. **********************/ + + /* Unsubscribe from the topic mqttexampleTOPIC and disconnect + * gracefully. */ + prvMQTTUnsubscribe(); + prvMQTTDisconnect(); + configPRINTF( ( "Disconnected from %s:%d\r\n\r\n", mqttexampleBROKER_ENDPOINT, mqttexampleBROKER_PORT ) ); + + /* Wait for the disconnect operation to complete which is signaled to us + * by the disconnect callback (prvExample_OnDisconnect)by setting + * the mqttexampleDISCONNECTED_BIT bit in this task's notification value. + * Note the bit is cleared in the task's notification value again to ensure + * it being set can be detected again on the next iteration. */ + xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */ + mqttexampleDISCONNECTED_BIT, /* Clear bit on exit. */ + &( ulNotificationValue ), /* Obtain the notification value. */ + pdMS_TO_TICKS( mqttexampleMQTT_TIMEOUT_MS ) ); + configASSERT( ( ulNotificationValue & mqttexampleDISCONNECTED_BIT ) == mqttexampleDISCONNECTED_BIT ); + + /* Delay between iterations to avoid broker throttling. */ + configPRINTF( ( "prvMQTTDemoTask() completed an iteration successfully. Total free heap is %u\r\n", xPortGetFreeHeapSize() ) ); + configPRINTF( ( "Demo completed successfully.\r\n" ) ); + configPRINTF( ( "Short delay before starting the next iteration.... \r\n\r\n" ) ); + vTaskDelay( pdMS_TO_TICKS( mqttexampleMQTT_TIMEOUT_MS ) ); + } +} +/*-----------------------------------------------------------*/ + +static void prvExample_OnDisconnect( void * pvCallbackContext, + IotMqttCallbackParam_t * pxCallbackParams ) +{ +TaskHandle_t xDemoTaskHandle = ( TaskHandle_t ) pvCallbackContext; + + /* Ensure that we initiated the disconnect. */ + configASSERT( pxCallbackParams->u.disconnectReason == IOT_MQTT_DISCONNECT_CALLED ); + + /* Inform the demo task about the disconnect. */ + xTaskNotify( xDemoTaskHandle, + mqttexampleDISCONNECTED_BIT, + eSetBits /* Set the mqttexampleDISCONNECTED_BIT in the demo task's notification value. */ + ); +} +/*-----------------------------------------------------------*/ + +static void prvExample_OnMessageReceived( void * pvCallbackContext, + IotMqttCallbackParam_t * pxCallbackParams ) +{ +TaskHandle_t xDemoTaskHandle = ( TaskHandle_t ) pvCallbackContext; + + /* Ensure the message is received on the expected topic. */ + configASSERT( pxCallbackParams->u.message.info.topicNameLength == strlen( mqttexampleTOPIC ) ); + configASSERT( strncmp( pxCallbackParams->u.message.info.pTopicName, + mqttexampleTOPIC, + strlen( mqttexampleTOPIC ) ) == 0 ); + + /* Ensure the message itself is as expected. */ + configASSERT( pxCallbackParams->u.message.info.payloadLength == strlen( mqttexampleMESSAGE ) ); + configASSERT( strncmp( pxCallbackParams->u.message.info.pPayload, + mqttexampleMESSAGE, + strlen( mqttexampleMESSAGE ) ) == 0 ); + + /* Ensure the message Quality of Service (QoS) is as expected. */ + configASSERT( pxCallbackParams->u.message.info.qos == IOT_MQTT_QOS_1 ); + + /* So as not to worry about string lengths the print message uses the + * consts rather than the data from the message, but the asserts above have + * already checked the two are equal. */ + configPRINTF( ( "Received %s on the topic %s\r\n", mqttexampleMESSAGE, mqttexampleTOPIC ) ); + + /* Inform the demo task about the message received from the MQTT broker by + * setting the mqttexampleMESSAGE_RECEIVED_BIT bit in the task's notification + * value. */ + xTaskNotify( xDemoTaskHandle, + mqttexampleMESSAGE_RECEIVED_BIT, + eSetBits /* Set the mqttexampleMESSAGE_RECEIVED_BIT in the demo task's notification value. */ + ); +} +/*-----------------------------------------------------------*/ + +static void prvMQTTConnect( void ) +{ +IotMqttError_t xResult; + + /* Set the context to pass into the disconnect callback function. */ + xNetworkInfo.disconnectCallback.pCallbackContext = ( void * ) xTaskGetCurrentTaskHandle(); + + /* Establish the connection to the MQTT broker - It is a blocking call and + * will return only when connection is complete or a timeout occurs. The + * network and connection structures are declared and initialized at the top + * of this file. */ + xResult = IotMqtt_Connect( &( xNetworkInfo ), + &( xConnectInfo ), + mqttexampleMQTT_TIMEOUT_MS, + &( xMQTTConnection ) ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); +} +/*-----------------------------------------------------------*/ + +static void prvMQTTDisconnect( void ) +{ + /* Send a MQTT DISCONNECT packet to the MQTT broker to do a graceful + * disconnect. */ + IotMqtt_Disconnect( xMQTTConnection, + 0 /* flags - 0 means a graceful disconnect by sending MQTT DISCONNECT. */ + ); +} +/*-----------------------------------------------------------*/ + +static void prvMQTTSubscribe( void ) +{ +IotMqttError_t xResult; +IotMqttSubscription_t xMQTTSubscription; + + /* Subscribe to the mqttexampleTOPIC topic filter. The task handle is passed + * as the callback context, which is then used by the callback to send a task + * notification to this task.*/ + xMQTTSubscription.qos = IOT_MQTT_QOS_1; + xMQTTSubscription.pTopicFilter = mqttexampleTOPIC; + xMQTTSubscription.topicFilterLength = ( uint16_t ) strlen( mqttexampleTOPIC ); + xMQTTSubscription.callback.pCallbackContext = ( void * ) xTaskGetCurrentTaskHandle(); + xMQTTSubscription.callback.function = prvExample_OnMessageReceived; + + /* Use the synchronous API to subscribe - It is a blocking call and only + * returns when the subscribe operation is complete or a timeout occurs. */ + xResult = IotMqtt_SubscribeSync( xMQTTConnection, + &( xMQTTSubscription ), + 1, /* We are subscribing to one topic filter. */ + 0, /* flags - currently ignored. */ + mqttexampleMQTT_TIMEOUT_MS ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); +} +/*-----------------------------------------------------------*/ + +static void prvMQTTPublish( void ) +{ +IotMqttError_t xResult; +IotMqttPublishInfo_t xMQTTPublishInfo; + + /* Publish a message with QoS1 on the mqttexampleTOPIC topic. Since we are + * subscribed to the same topic, the MQTT broker will send the same message + * back to us. It is verified in the publish callback. */ + xMQTTPublishInfo.qos = IOT_MQTT_QOS_1; + xMQTTPublishInfo.retain = false; + xMQTTPublishInfo.pTopicName = mqttexampleTOPIC; + xMQTTPublishInfo.topicNameLength = ( uint16_t ) strlen( mqttexampleTOPIC ); + xMQTTPublishInfo.pPayload = mqttexampleMESSAGE; + xMQTTPublishInfo.payloadLength = strlen( mqttexampleMESSAGE ); + xMQTTPublishInfo.retryMs = mqttexamplePUBLISH_RETRY_MS; + xMQTTPublishInfo.retryLimit = mqttexamplePUBLISH_RETRY_LIMIT; + + /* Use the synchronous API to publish - It is a blocking call and only + * returns when the publish operation is complete or a timeout occurs. */ + xResult = IotMqtt_PublishSync( xMQTTConnection, + &( xMQTTPublishInfo ), + 0, /* flags - currently ignored. */ + mqttexampleMQTT_TIMEOUT_MS ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); +} +/*-----------------------------------------------------------*/ + +static void prvMQTTUnsubscribe( void ) +{ +IotMqttError_t xResult; +IotMqttSubscription_t xMQTTSubscription; + + /* Unsubscribe from the mqttexampleTOPIC topic filter. */ + xMQTTSubscription.pTopicFilter = mqttexampleTOPIC; + xMQTTSubscription.topicFilterLength = ( uint16_t ) strlen( mqttexampleTOPIC ); + + /* The following members of the IotMqttSubscription_t are ignored by the + * unsubscribe operation. Just initialize them to avoid "use of uninitialized + * variable" warnings. */ + xMQTTSubscription.qos = IOT_MQTT_QOS_1; + xMQTTSubscription.callback.pCallbackContext = NULL; + xMQTTSubscription.callback.function = NULL; + + /* Use the synchronous API to unsubscribe - It is a blocking call and only + * returns when the unsubscribe operation is complete or a timeout occurs. */ + xResult = IotMqtt_UnsubscribeSync( xMQTTConnection, + &( xMQTTSubscription ), + 1, /* We are unsubscribing from one topic filter. */ + 0, /* flags - currently ignored. */ + mqttexampleMQTT_TIMEOUT_MS ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); +} +/*-----------------------------------------------------------*/ + +static void prvInitialiseLibraries( void ) +{ +IotTaskPoolError_t xTaskPoolResult; +IotMqttError_t xResult; +IotNetworkError_t xNetworkResult; + + /* The MQTT library needs a task pool, so create the system task pool. */ + xTaskPoolResult = IotTaskPool_CreateSystemTaskPool( &( xTaskPoolParameters ) ); + configASSERT( xTaskPoolResult == IOT_TASKPOOL_SUCCESS ); + + /* Initialize the network stack abstraction for FreeRTOS. */ + xNetworkResult = IotNetworkFreeRTOS_Init(); + configASSERT( xNetworkResult == IOT_NETWORK_SUCCESS ); + + /* MQTT library must be initialized before it can be used. This is just one + * time initialization. */ + xResult = IotMqtt_Init(); + configASSERT( xResult == IOT_MQTT_SUCCESS ); +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/Run-time-stats-utils.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/Run-time-stats-utils.c new file mode 100644 index 000000000..d9b7a593d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/Run-time-stats-utils.c @@ -0,0 +1,99 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * Utility functions required to gather run time statistics. See: + * http://www.freertos.org/rtos-run-time-stats.html + * + * Note that this is a simulated port, where simulated time is a lot slower than + * real time, therefore the run time counter values have no real meaningful + * units. + * + * Also note that it is assumed this demo is going to be used for short periods + * of time only, and therefore timer overflows are not handled. +*/ + +/* FreeRTOS includes. */ +#include + +/* Variables used in the creation of the run time stats time base. Run time +stats record how much time each task spends in the Running state. */ +static long long llInitialRunTimeCounterValue = 0LL, llTicksPerHundedthMillisecond = 0LL; + +/*-----------------------------------------------------------*/ + +void vConfigureTimerForRunTimeStats( void ) +{ +LARGE_INTEGER liPerformanceCounterFrequency, liInitialRunTimeValue; + + /* Initialise the variables used to create the run time stats time base. + Run time stats record how much time each task spends in the Running + state. */ + + if( QueryPerformanceFrequency( &liPerformanceCounterFrequency ) == 0 ) + { + llTicksPerHundedthMillisecond = 1; + } + else + { + /* How many times does the performance counter increment in 1/100th + millisecond. */ + llTicksPerHundedthMillisecond = liPerformanceCounterFrequency.QuadPart / 100000LL; + + /* What is the performance counter value now, this will be subtracted + from readings taken at run time. */ + QueryPerformanceCounter( &liInitialRunTimeValue ); + llInitialRunTimeCounterValue = liInitialRunTimeValue.QuadPart; + } +} +/*-----------------------------------------------------------*/ + +unsigned long ulGetRunTimeCounterValue( void ) +{ +LARGE_INTEGER liCurrentCount; +unsigned long ulReturn; + + /* What is the performance counter value now? */ + QueryPerformanceCounter( &liCurrentCount ); + + /* Subtract the performance counter value reading taken when the + application started to get a count from that reference point, then + scale to (simulated) 1/100ths of a millisecond. */ + if( llTicksPerHundedthMillisecond == 0 ) + { + /* The trace macros are probably calling this function before the + scheduler has been started. */ + ulReturn = 0; + } + else + { + ulReturn = ( unsigned long ) ( ( liCurrentCount.QuadPart - llInitialRunTimeCounterValue ) / llTicksPerHundedthMillisecond ); + } + + return ulReturn; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/Packet32.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/Packet32.h new file mode 100644 index 000000000..1e0eacd77 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/Packet32.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + +/** @ingroup packetapi + * @{ + */ + +/** @defgroup packet32h Packet.dll definitions and data structures + * Packet32.h contains the data structures and the definitions used by packet.dll. + * The file is used both by the Win9x and the WinNTx versions of packet.dll, and can be included + * by the applications that use the functions of this library + * @{ + */ + +#ifndef __PACKET32 +#define __PACKET32 + +#include + +#ifdef HAVE_AIRPCAP_API +#include +#else +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +typedef struct _AirpcapHandle *PAirpcapHandle; +#endif /* AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ */ +#endif /* HAVE_AIRPCAP_API */ + +#ifdef HAVE_DAG_API +#include +#endif /* HAVE_DAG_API */ + +// Working modes +#define PACKET_MODE_CAPT 0x0 ///< Capture mode +#define PACKET_MODE_STAT 0x1 ///< Statistical mode +#define PACKET_MODE_MON 0x2 ///< Monitoring mode +#define PACKET_MODE_DUMP 0x10 ///< Dump mode +#define PACKET_MODE_STAT_DUMP MODE_DUMP | MODE_STAT ///< Statistical dump Mode + + +/// Alignment macro. Defines the alignment size. +#define Packet_ALIGNMENT sizeof(int) +/// Alignment macro. Rounds up to the next even multiple of Packet_ALIGNMENT. +#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1)) + +#define NdisMediumNull -1 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumCHDLC -2 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPPPSerial -3 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumBare80211 -4 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumRadio80211 -5 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPpi -6 ///< Custom linktype: NDIS doesn't provide an equivalent + +// Loopback behaviour definitions +#define NPF_DISABLE_LOOPBACK 1 ///< Drop the packets sent by the NPF driver +#define NPF_ENABLE_LOOPBACK 2 ///< Capture the packets sent by the NPF driver + +/*! + \brief Network type structure. + + This structure is used by the PacketGetNetType() function to return information on the current adapter's type and speed. +*/ +typedef struct NetType +{ + UINT LinkType; ///< The MAC of the current network adapter (see function PacketGetNetType() for more information) + ULONGLONG LinkSpeed; ///< The speed of the network in bits per second +}NetType; + + +//some definitions stolen from libpcap + +#ifndef BPF_MAJOR_VERSION + +/*! + \brief A BPF pseudo-assembly program. + + The program will be injected in the kernel by the PacketSetBPF() function and applied to every incoming packet. +*/ +struct bpf_program +{ + UINT bf_len; ///< Indicates the number of instructions of the program, i.e. the number of struct bpf_insn that will follow. + struct bpf_insn *bf_insns; ///< A pointer to the first instruction of the program. +}; + +/*! + \brief A single BPF pseudo-instruction. + + bpf_insn contains a single instruction for the BPF register-machine. It is used to send a filter program to the driver. +*/ +struct bpf_insn +{ + USHORT code; ///< Instruction type and addressing mode. + UCHAR jt; ///< Jump if true + UCHAR jf; ///< Jump if false + int k; ///< Generic field used for various purposes. +}; + +/*! + \brief Structure that contains a couple of statistics values on the current capture. + + It is used by packet.dll to return statistics about a capture session. +*/ +struct bpf_stat +{ + UINT bs_recv; ///< Number of packets that the driver received from the network adapter + ///< from the beginning of the current capture. This value includes the packets + ///< lost by the driver. + UINT bs_drop; ///< number of packets that the driver lost from the beginning of a capture. + ///< Basically, a packet is lost when the the buffer of the driver is full. + ///< In this situation the packet cannot be stored and the driver rejects it. + UINT ps_ifdrop; ///< drops by interface. XXX not yet supported + UINT bs_capt; ///< number of packets that pass the filter, find place in the kernel buffer and + ///< thus reach the application. +}; + +/*! + \brief Packet header. + + This structure defines the header associated with every packet delivered to the application. +*/ +struct bpf_hdr +{ + struct timeval bh_tstamp; ///< The timestamp associated with the captured packet. + ///< It is stored in a TimeVal structure. + UINT bh_caplen; ///< Length of captured portion. The captured portion can be different + ///< from the original packet, because it is possible (with a proper filter) + ///< to instruct the driver to capture only a portion of the packets. + UINT bh_datalen; ///< Original length of packet + USHORT bh_hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases, + ///< a padding could be added between the end of this structure and the packet + ///< data for performance reasons. This filed can be used to retrieve the actual data + ///< of the packet. +}; + +/*! + \brief Dump packet header. + + This structure defines the header associated with the packets in a buffer to be used with PacketSendPackets(). + It is simpler than the bpf_hdr, because it corresponds to the header associated by WinPcap and libpcap to a + packet in a dump file. This makes straightforward sending WinPcap dump files to the network. +*/ +struct dump_bpf_hdr{ + struct timeval ts; ///< Time stamp of the packet + UINT caplen; ///< Length of captured portion. The captured portion can smaller than the + ///< the original packet, because it is possible (with a proper filter) to + ///< instruct the driver to capture only a portion of the packets. + UINT len; ///< Length of the original packet (off wire). +}; + + +#endif + +struct bpf_stat; + +#define DOSNAMEPREFIX TEXT("Packet_") ///< Prefix added to the adapters device names to create the WinPcap devices +#define MAX_LINK_NAME_LENGTH 64 //< Maximum length of the devices symbolic links +#define NMAX_PACKET 65535 + +/*! + \brief Addresses of a network adapter. + + This structure is used by the PacketGetNetInfoEx() function to return the IP addresses associated with + an adapter. +*/ +typedef struct npf_if_addr { + struct sockaddr_storage IPAddress; ///< IP address. + struct sockaddr_storage SubnetMask; ///< Netmask for that address. + struct sockaddr_storage Broadcast; ///< Broadcast address. +}npf_if_addr; + + +#define ADAPTER_NAME_LENGTH 256 + 12 ///< Maximum length for the name of an adapter. The value is the same used by the IP Helper API. +#define ADAPTER_DESC_LENGTH 128 ///< Maximum length for the description of an adapter. The value is the same used by the IP Helper API. +#define MAX_MAC_ADDR_LENGTH 8 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. +#define MAX_NETWORK_ADDRESSES 16 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. + + +typedef struct WAN_ADAPTER_INT WAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API +typedef WAN_ADAPTER *PWAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API + +#define INFO_FLAG_NDIS_ADAPTER 0 ///< Flag for ADAPTER_INFO: this is a traditional ndis adapter +#define INFO_FLAG_NDISWAN_ADAPTER 1 ///< Flag for ADAPTER_INFO: this is a NdisWan adapter, and it's managed by WANPACKET +#define INFO_FLAG_DAG_CARD 2 ///< Flag for ADAPTER_INFO: this is a DAG card +#define INFO_FLAG_DAG_FILE 6 ///< Flag for ADAPTER_INFO: this is a DAG file +#define INFO_FLAG_DONT_EXPORT 8 ///< Flag for ADAPTER_INFO: when this flag is set, the adapter will not be listed or openend by winpcap. This allows to prevent exporting broken network adapters, like for example FireWire ones. +#define INFO_FLAG_AIRPCAP_CARD 16 ///< Flag for ADAPTER_INFO: this is an airpcap card +#define INFO_FLAG_NPFIM_DEVICE 32 + +/*! + \brief Describes an opened network adapter. + + This structure is the most important for the functioning of packet.dll, but the great part of its fields + should be ignored by the user, since the library offers functions that avoid to cope with low-level parameters +*/ +typedef struct _ADAPTER { + HANDLE hFile; ///< \internal Handle to an open instance of the NPF driver. + CHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; ///< \internal A string containing the name of the network adapter currently opened. + int NumWrites; ///< \internal Number of times a packets written on this adapter will be repeated + ///< on the wire. + HANDLE ReadEvent; ///< A notification event associated with the read calls on the adapter. + ///< It can be passed to standard Win32 functions (like WaitForSingleObject + ///< or WaitForMultipleObjects) to wait until the driver's buffer contains some + ///< data. It is particularly useful in GUI applications that need to wait + ///< concurrently on several events. In Windows NT/2000 the PacketSetMinToCopy() + ///< function can be used to define the minimum amount of data in the kernel buffer + ///< that will cause the event to be signalled. + + UINT ReadTimeOut; ///< \internal The amount of time after which a read on the driver will be released and + ///< ReadEvent will be signaled, also if no packets were captured + CHAR Name[ADAPTER_NAME_LENGTH]; + PWAN_ADAPTER pWanAdapter; + UINT Flags; ///< Adapter's flags. Tell if this adapter must be treated in a different way, using the Netmon API or the dagc API. + +#ifdef HAVE_AIRPCAP_API + PAirpcapHandle AirpcapAd; +#endif // HAVE_AIRPCAP_API + +#ifdef HAVE_NPFIM_API + void* NpfImHandle; +#endif // HAVE_NPFIM_API + +#ifdef HAVE_DAG_API + dagc_t *pDagCard; ///< Pointer to the dagc API adapter descriptor for this adapter + PCHAR DagBuffer; ///< Pointer to the buffer with the packets that is received from the DAG card + struct timeval DagReadTimeout; ///< Read timeout. The dagc API requires a timeval structure + unsigned DagFcsLen; ///< Length of the frame check sequence attached to any packet by the card. Obtained from the registry + DWORD DagFastProcess; ///< True if the user requests fast capture processing on this card. Higher level applications can use this value to provide a faster but possibly unprecise capture (for example, libpcap doesn't convert the timestamps). +#endif // HAVE_DAG_API +} ADAPTER, *LPADAPTER; + +/*! + \brief Structure that contains a group of packets coming from the driver. + + This structure defines the header associated with every packet delivered to the application. +*/ +typedef struct _PACKET { + HANDLE hEvent; ///< \deprecated Still present for compatibility with old applications. + OVERLAPPED OverLapped; ///< \deprecated Still present for compatibility with old applications. + PVOID Buffer; ///< Buffer with containing the packets. See the PacketReceivePacket() for + ///< details about the organization of the data in this buffer + UINT Length; ///< Length of the buffer + DWORD ulBytesReceived; ///< Number of valid bytes present in the buffer, i.e. amount of data + ///< received by the last call to PacketReceivePacket() + BOOLEAN bIoComplete; ///< \deprecated Still present for compatibility with old applications. +} PACKET, *LPPACKET; + +/*! + \brief Structure containing an OID request. + + It is used by the PacketRequest() function to send an OID to the interface card driver. + It can be used, for example, to retrieve the status of the error counters on the adapter, its MAC address, + the list of the multicast groups defined on it, and so on. +*/ +struct _PACKET_OID_DATA { + ULONG Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h + ///< for a complete list of valid codes. + ULONG Length; ///< Length of the data field + UCHAR Data[1]; ///< variable-lenght field that contains the information passed to or received + ///< from the adapter. +}; +typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @} + */ + +/* +BOOLEAN QueryWinPcapRegistryStringA(CHAR *SubKeyName, + CHAR *Value, + UINT *pValueLen, + CHAR *DefaultVal); + +BOOLEAN QueryWinPcapRegistryStringW(WCHAR *SubKeyName, + WCHAR *Value, + UINT *pValueLen, + WCHAR *DefaultVal); +*/ + +//--------------------------------------------------------------------------- +// EXPORTED FUNCTIONS +//--------------------------------------------------------------------------- + +PCHAR PacketGetVersion(); +PCHAR PacketGetDriverVersion(); +BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes); +BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites); +BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode); +BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout); +BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp); +BOOLEAN PacketSetLoopbackBehavior(LPADAPTER AdapterObject, UINT LoopbackBehavior); +INT PacketSetSnapLen(LPADAPTER AdapterObject,int snaplen); +BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim); +BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type); +LPADAPTER PacketOpenAdapter(PCHAR AdapterName); +BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync); +INT PacketSendPackets(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync); +LPPACKET PacketAllocatePacket(void); +VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length); +VOID PacketFreePacket(LPPACKET lpPacket); +BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync); +BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter); +BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize); +BOOLEAN PacketGetNetInfoEx(PCHAR AdapterName, npf_if_addr* buffer, PLONG NEntries); +BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData); +HANDLE PacketGetReadEvent(LPADAPTER AdapterObject); +BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len); +BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks); +BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync); +BOOL PacketStopDriver(); +VOID PacketCloseAdapter(LPADAPTER lpAdapter); +BOOLEAN PacketStartOem(PCHAR errorString, UINT errorStringLength); +BOOLEAN PacketStartOemEx(PCHAR errorString, UINT errorStringLength, ULONG flags); +PAirpcapHandle PacketGetAirPcapHandle(LPADAPTER AdapterObject); + +// +// Used by PacketStartOemEx +// +#define PACKET_START_OEM_NO_NETMON 0x00000001 + +#ifdef __cplusplus +} +#endif + +#endif //__PACKET32 diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/PacketData.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/PacketData.h new file mode 100644 index 000000000..8124db66d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/PacketData.h @@ -0,0 +1,267 @@ +char pkt1[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x30, 0x09, 0x9c, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x07, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x35, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02, +0x40, 0x00, 0xdf, 0xab, 0x00, 0x00, 0x02, 0x04, +0x05, 0xb4, 0x01, 0x01, 0x04, 0x02 }; + +char pkt2[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa6, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt3[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0x9e, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x0d, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt4[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x02, 0x27, 0x09, 0x9f, 0x40, 0x00, 0x80, 0x06, +0x6d, 0x0d, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x18, +0x42, 0xd8, 0x84, 0x3e, 0x00, 0x00, 0x47, 0x45, +0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, +0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, +0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x2c, +0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, +0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, +0x2c, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, +0x6a, 0x70, 0x65, 0x67, 0x2c, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x70, 0x6a, 0x70, 0x65, +0x67, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, +0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, +0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, +0x63, 0x65, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c, +0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, +0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, +0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20, +0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, +0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, +0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70, +0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, +0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78, +0x62, 0x61, 0x70, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, +0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d, +0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, +0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, +0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, +0x20, 0x65, 0x6e, 0x2d, 0x67, 0x62, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, +0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, +0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64, +0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x0d, 0x0a, +0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, +0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69, +0x6c, 0x6c, 0x61, 0x2f, 0x34, 0x2e, 0x30, 0x20, +0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, +0x62, 0x6c, 0x65, 0x3b, 0x20, 0x4d, 0x53, 0x49, +0x45, 0x20, 0x36, 0x2e, 0x30, 0x3b, 0x20, 0x57, +0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e, +0x54, 0x20, 0x35, 0x2e, 0x31, 0x3b, 0x20, 0x53, +0x56, 0x31, 0x3b, 0x20, 0x47, 0x6f, 0x6f, 0x67, +0x6c, 0x65, 0x54, 0x35, 0x3b, 0x20, 0x2e, 0x4e, +0x45, 0x54, 0x20, 0x43, 0x4c, 0x52, 0x20, 0x32, +0x2e, 0x30, 0x2e, 0x35, 0x30, 0x37, 0x32, 0x37, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30, +0x34, 0x35, 0x30, 0x36, 0x2e, 0x36, 0x34, 0x38, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x35, 0x2e, 0x32, +0x31, 0x30, 0x32, 0x32, 0x29, 0x0d, 0x0a, 0x48, +0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, +0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31, +0x32, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, +0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b, +0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, +0x65, 0x0d, 0x0a, 0x0d, 0x0a }; + +char pkt5[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x02, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa5, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt6[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa1, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x0a, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt7[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x02, 0x27, 0x09, 0xa2, 0x40, 0x00, 0x80, 0x06, +0x6d, 0x0a, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x18, +0x42, 0xd8, 0x84, 0x3e, 0x00, 0x00, 0x47, 0x45, +0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, +0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, +0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x2c, +0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, +0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, +0x2c, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, +0x6a, 0x70, 0x65, 0x67, 0x2c, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x70, 0x6a, 0x70, 0x65, +0x67, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, +0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, +0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, +0x63, 0x65, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c, +0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, +0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, +0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20, +0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, +0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, +0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70, +0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, +0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78, +0x62, 0x61, 0x70, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, +0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d, +0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, +0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, +0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, +0x20, 0x65, 0x6e, 0x2d, 0x67, 0x62, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, +0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, +0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64, +0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x0d, 0x0a, +0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, +0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69, +0x6c, 0x6c, 0x61, 0x2f, 0x34, 0x2e, 0x30, 0x20, +0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, +0x62, 0x6c, 0x65, 0x3b, 0x20, 0x4d, 0x53, 0x49, +0x45, 0x20, 0x36, 0x2e, 0x30, 0x3b, 0x20, 0x57, +0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e, +0x54, 0x20, 0x35, 0x2e, 0x31, 0x3b, 0x20, 0x53, +0x56, 0x31, 0x3b, 0x20, 0x47, 0x6f, 0x6f, 0x67, +0x6c, 0x65, 0x54, 0x35, 0x3b, 0x20, 0x2e, 0x4e, +0x45, 0x54, 0x20, 0x43, 0x4c, 0x52, 0x20, 0x32, +0x2e, 0x30, 0x2e, 0x35, 0x30, 0x37, 0x32, 0x37, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30, +0x34, 0x35, 0x30, 0x36, 0x2e, 0x36, 0x34, 0x38, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x35, 0x2e, 0x32, +0x31, 0x30, 0x32, 0x32, 0x29, 0x0d, 0x0a, 0x48, +0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, +0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31, +0x32, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, +0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b, +0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, +0x65, 0x0d, 0x0a, 0x0d, 0x0a }; + +char pkt8[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x03, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa4, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt9[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa3, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x08, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt10[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x04, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa3, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt11[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa6, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x05, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt12[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa7, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x04, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x14, +0x00, 0x00, 0x43, 0xf4, 0x00, 0x00 }; + + +typedef struct +{ + char *pcData; + int iDataLen; +} xPacketData; + +xPacketData xAllPackets[] = +{ + { pkt1, sizeof( pkt1 ) }, +// { pkt2, sizeof( pkt2 ) }, + { pkt3, sizeof( pkt3 ) }, + { pkt4, sizeof( pkt4 ) }, +// { pkt5, sizeof( pkt5 ) }, + { pkt6, sizeof( pkt6 ) }, + { pkt7, sizeof( pkt7 ) }, + { pkt8, sizeof( pkt8 ) }, + { pkt9, sizeof( pkt9 ) }, + { pkt10, sizeof( pkt10 ) }, +// { pkt11, sizeof( pkt11 ) }, +// { pkt12, sizeof( pkt12 ) }, +// { pkt13, sizeof( pkt13 ) }, +// { pkt14, sizeof( pkt14 ) }, +// { pkt15, sizeof( pkt15 ) }, +// { pkt16, sizeof( pkt16 ) }, +}; diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/Win32-Extensions.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/Win32-Extensions.h new file mode 100644 index 000000000..be71c85e9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/Win32-Extensions.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + + +#ifndef __WIN32_EXTENSIONS_H__ +#define __WIN32_EXTENSIONS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Definitions */ + +/*! + \brief A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit(). +*/ +struct pcap_send_queue +{ + u_int maxlen; ///< Maximum size of the the queue, in bytes. This variable contains the size of the buffer field. + u_int len; ///< Current size of the queue, in bytes. + char *buffer; ///< Buffer containing the packets to be sent. +}; + +typedef struct pcap_send_queue pcap_send_queue; + +/*! + \brief This typedef is a support for the pcap_get_airpcap_handle() function +*/ +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +typedef struct _AirpcapHandle *PAirpcapHandle; +#endif + +#define BPF_MEM_EX_IMM 0xc0 +#define BPF_MEM_EX_IND 0xe0 + +/*used for ST*/ +#define BPF_MEM_EX 0xc0 +#define BPF_TME 0x08 + +#define BPF_LOOKUP 0x90 +#define BPF_EXECUTE 0xa0 +#define BPF_INIT 0xb0 +#define BPF_VALIDATE 0xc0 +#define BPF_SET_ACTIVE 0xd0 +#define BPF_RESET 0xe0 +#define BPF_SET_MEMORY 0x80 +#define BPF_GET_REGISTER_VALUE 0x70 +#define BPF_SET_REGISTER_VALUE 0x60 +#define BPF_SET_WORKING 0x50 +#define BPF_SET_ACTIVE_READ 0x40 +#define BPF_SET_AUTODELETION 0x30 +#define BPF_SEPARATION 0xff + +/* Prototypes */ +pcap_send_queue* pcap_sendqueue_alloc(u_int memsize); + +void pcap_sendqueue_destroy(pcap_send_queue* queue); + +int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data); + +u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync); + +HANDLE pcap_getevent(pcap_t *p); + +struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size); + +int pcap_setuserbuffer(pcap_t *p, int size); + +int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks); + +int pcap_live_dump_ended(pcap_t *p, int sync); + +int pcap_offline_filter(struct bpf_program *prog, const struct pcap_pkthdr *header, const u_char *pkt_data); + +int pcap_start_oem(char* err_str, int flags); + +PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p); + +#ifdef __cplusplus +} +#endif + +#endif //__WIN32_EXTENSIONS_H__ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/arch.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/arch.c new file mode 100644 index 000000000..02bf82bf9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/arch.c @@ -0,0 +1,336 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* WinPCap includes. */ +#include "pcap.h" +#include "remote-ext.h" + +/* uIP includes. */ +#include "net/uip.h" +#include "net/uip_arp.h" +#include "net/clock-arch.h" + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* + * Query the computer the simulation is being executed on to find the network + * interfaces it has installed. + */ +static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ); + +/* + * Open the network interface. The number of the interface to be opened is set + * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. + */ +static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ); + +/* + * Configure the capture filter to allow blocking reads, and to filter out + * packets that are not of interest to this demo. + */ +static void prvConfigureCaptureBehaviour( void ); + +pcap_t *pxOpenedInterfaceHandle = NULL; +LARGE_INTEGER freq, sys_start_time; + +#define archNUM_BUFFERS 5 +#define archNUM_BUFFER_POINTERS ( archNUM_BUFFERS - 1 ) + +static void prvInterruptSimulator( void *pvParameters ); + +static unsigned char ucEthernetBuffer[ archNUM_BUFFERS ][ UIP_CONF_BUFFER_SIZE ]; +static unsigned char *pucEthernetBufferPointers[ archNUM_BUFFER_POINTERS ]; + +static long lLengthOfDataInBuffer[ archNUM_BUFFER_POINTERS ] = { 0 }; +static unsigned char ucNextBufferToFill = 0U, ucNextBufferToProcess = 0U; + +unsigned char *uip_buf = NULL; +char cErrorBuffer[PCAP_ERRBUF_SIZE]; + +void vNetifTx( void ) +{ + pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len ); + pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len ); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxNetifRx( void ) +{ +UBaseType_t xDataLen; +unsigned char *pucTemp; + + /* Check there is really data available. */ + xDataLen = lLengthOfDataInBuffer[ ucNextBufferToProcess ]; + if( xDataLen != 0L ) + { + + /* The buffer pointed to by uip_buf is going to change. Remember which + buffer uip_buf is currently pointing to. */ + pucTemp = uip_buf; + + /* Point uip_buf at the next buffer that contains data. */ + uip_buf = pucEthernetBufferPointers[ ucNextBufferToProcess ]; + + /* The buffer pointed to by + pucEthernetBufferPointeres[ ucNextBufferToProcess ] is now in use by + uip_buf, but the buffer uip_buf was pointing to on entry to this + function is free. Set + pucEthernetBufferPointeres[ ucNextBufferToProcess ] to the free + buffer. */ + pucEthernetBufferPointers[ ucNextBufferToProcess ] = pucTemp; + lLengthOfDataInBuffer[ ucNextBufferToProcess ] = 0L; + + ucNextBufferToProcess++; + if( ucNextBufferToProcess >= archNUM_BUFFER_POINTERS ) + { + ucNextBufferToProcess = 0L; + } + } + + return xDataLen; +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetifInit( void ) +{ +BaseType_t x; +pcap_if_t *pxAllNetworkInterfaces; + + /* Allocate a free buffer to each buffer pointer. */ + for( x = 0; x < sizeof( pucEthernetBufferPointers ) / sizeof( unsigned char * ); x++ ) + { + pucEthernetBufferPointers[ x ] = &( ucEthernetBuffer[ x ][ 0 ] ); + } + + /* Start with uip_buf pointing to a buffer that is not referenced from the + pucEthernetBufferPointers[] array. */ + uip_buf = &( ucEthernetBuffer[ archNUM_BUFFERS - 1 ][ 0 ] ); + + /* Query the computer the simulation is being executed on to find the + network interfaces it has installed. */ + pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces(); + + /* Open the network interface. The number of the interface to be opened is + set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. + Calling this function will set the pxOpenedInterfaceHandle variable. If, + after calling this function, pxOpenedInterfaceHandle is equal to NULL, then + the interface could not be opened. */ + if( pxAllNetworkInterfaces != NULL ) + { + prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces ); + } + + + return x; +} +/*-----------------------------------------------------------*/ + +static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ) +{ +pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface; +long lInterfaceNumber = 1; + + if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 ) + { + printf( "\r\nCould not obtain a list of network interfaces\r\n%s\r\n", cErrorBuffer ); + pxAllNetworkInterfaces = NULL; + } + + if( pxAllNetworkInterfaces != NULL ) + { + /* Print out the list of network interfaces. The first in the list + is interface '1', not interface '0'. */ + for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next ) + { + printf( "%d. %s", lInterfaceNumber, xInterface->name ); + + if( xInterface->description != NULL ) + { + printf( " (%s)\r\n", xInterface->description ); + } + else + { + printf( " (No description available)\r\n") ; + } + + lInterfaceNumber++; + } + } + + if( lInterfaceNumber == 1 ) + { + /* The interface number was never incremented, so the above for() loop + did not execute meaning no interfaces were found. */ + printf( " \r\nNo network interfaces were found.\r\n" ); + pxAllNetworkInterfaces = NULL; + } + + printf( "\r\nThe interface that will be opened is set by configNETWORK_INTERFACE_TO_USE which should be defined in FreeRTOSConfig.h\r\n" ); + printf( "Attempting to open interface number %d.\r\n", configNETWORK_INTERFACE_TO_USE ); + + if( ( configNETWORK_INTERFACE_TO_USE < 1L ) || ( configNETWORK_INTERFACE_TO_USE > lInterfaceNumber ) ) + { + printf("\r\nconfigNETWORK_INTERFACE_TO_USE is not in the valid range.\r\n" ); + + if( pxAllNetworkInterfaces != NULL ) + { + /* Free the device list, as no devices are going to be opened. */ + pcap_freealldevs( pxAllNetworkInterfaces ); + pxAllNetworkInterfaces = NULL; + } + } + + return pxAllNetworkInterfaces; +} +/*-----------------------------------------------------------*/ + +static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ) +{ +pcap_if_t *xInterface; +long x; + + /* Walk the list of devices until the selected device is located. */ + xInterface = pxAllNetworkInterfaces; + for( x = 0L; x < ( configNETWORK_INTERFACE_TO_USE - 1L ); x++ ) + { + xInterface = xInterface->next; + } + + /* Open the selected interface. */ + pxOpenedInterfaceHandle = pcap_open( xInterface->name, /* The name of the selected interface. */ + UIP_CONF_BUFFER_SIZE, /* The size of the packet to capture. */ + PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscious mode as the MAC and + IP address is going to be "simulated", and + not be the real MAC and IP address. This allows + trafic to the simulated IP address to be routed + to uIP, and trafic to the real IP address to be + routed to the Windows TCP/IP stack. */ + 0xfffffffL, /* The read time out. This is going to block + until data is available. */ + NULL, /* No authentication is required as this is + not a remote capture session. */ + cErrorBuffer + ); + + if ( pxOpenedInterfaceHandle == NULL ) + { + printf( "\r\n%s is not supported by WinPcap and cannot be opened\r\n", xInterface->name ); + } + else + { + /* Configure the capture filter to allow blocking reads, and to filter + out packets that are not of interest to this demo. */ + prvConfigureCaptureBehaviour(); + } + + /* The device list is no longer required. */ + pcap_freealldevs( pxAllNetworkInterfaces ); +} +/*-----------------------------------------------------------*/ + +static void prvConfigureCaptureBehaviour( void ) +{ +struct bpf_program xFilterCode; +const long lMinBytesToCopy = 10L, lBlocking = 0L; +unsigned long ulNetMask; + + /* Unblock a read as soon as anything is received. */ + pcap_setmintocopy( pxOpenedInterfaceHandle, lMinBytesToCopy ); + + /* Allow blocking. */ + pcap_setnonblock( pxOpenedInterfaceHandle, lBlocking, cErrorBuffer ); + + /* Set up a filter so only the packets of interest are passed to the uIP + stack. cErrorBuffer is used for convenience to create the string. Don't + confuse this with an error message. */ + sprintf( cErrorBuffer, "broadcast or multicast or host %d.%d.%d.%d", configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 ); + + ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0; + + if( pcap_compile(pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 ) + { + printf("\r\nThe packet filter string is invalid\r\n" ); + } + else + { + if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 ) + { + printf( "\r\nAn error occurred setting the packet filter.\r\n" ); + } + } + + /* Create a task that simulates an interrupt in a real system. This will + block waiting for packets, then send a message to the uIP task when data + is available. */ + xTaskCreate( prvInterruptSimulator, ( signed char * ) "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, ( configuIP_TASK_PRIORITY - 1 ), NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvInterruptSimulator( void *pvParameters ) +{ +static struct pcap_pkthdr *pxHeader; +const unsigned char *pucPacketData; +extern QueueHandle_t xEMACEventQueue; +const unsigned long ulRxEvent = uipETHERNET_RX_EVENT; +long lResult; + + /* Just to kill the compiler warning. */ + ( void ) pvParameters; + + for( ;; ) + { + /* Get the next packet. */ + lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData ); + if( lResult ) + { + /* Is the next buffer into which data should be placed free? */ + if( lLengthOfDataInBuffer[ ucNextBufferToFill ] == 0L ) + { + /* Copy the data from the captured packet into the buffer. */ + memcpy( pucEthernetBufferPointers[ ucNextBufferToFill ], pucPacketData, pxHeader->len ); + + /* Note the amount of data that was copied. */ + lLengthOfDataInBuffer[ ucNextBufferToFill ] = pxHeader->len; + + /* Move onto the next buffer, wrapping around if necessary. */ + ucNextBufferToFill++; + if( ucNextBufferToFill >= archNUM_BUFFER_POINTERS ) + { + ucNextBufferToFill = 0U; + } + + /* Data was received and stored. Send a message to the uIP task + to let it know. */ + xQueueSendToBack( xEMACEventQueue, &ulRxEvent, portMAX_DELAY ); + } + } + } +} + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/bittypes.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/bittypes.h new file mode 100644 index 000000000..fcacd45fe --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/bittypes.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 1999 WIDE Project. + * 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. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. + */ +#ifndef _BITTYPES_H +#define _BITTYPES_H + +#ifndef HAVE_U_INT8_T + +#if SIZEOF_CHAR == 1 +typedef unsigned char u_int8_t; +typedef signed char _int8_t; +#elif SIZEOF_INT == 1 +typedef unsigned int u_int8_t; +typedef signed int int8_t; +#else /* XXX */ +#error "there's no appropriate type for u_int8_t" +#endif +#define HAVE_U_INT8_T 1 +#define HAVE_INT8_T 1 + +#endif /* HAVE_U_INT8_T */ + +#ifndef HAVE_U_INT16_T + +#if SIZEOF_SHORT == 2 +typedef unsigned short u_int16_t; +typedef signed short _int16_t; +#elif SIZEOF_INT == 2 +typedef unsigned int u_int16_t; +typedef signed int int16_t; +#elif SIZEOF_CHAR == 2 +typedef unsigned char u_int16_t; +typedef signed char int16_t; +#else /* XXX */ +#error "there's no appropriate type for u_int16_t" +#endif +#define HAVE_U_INT16_T 1 +#define HAVE_INT16_T 1 + +#endif /* HAVE_U_INT16_T */ + +#ifndef HAVE_U_INT32_T + +#if SIZEOF_INT == 4 +typedef unsigned int u_int32_t; +typedef signed int _int32_t; +#elif SIZEOF_LONG == 4 +typedef unsigned long u_int32_t; +typedef signed long int32_t; +#elif SIZEOF_SHORT == 4 +typedef unsigned short u_int32_t; +typedef signed short int32_t; +#else /* XXX */ +#error "there's no appropriate type for u_int32_t" +#endif +#define HAVE_U_INT32_T 1 +#define HAVE_INT32_T 1 + +#endif /* HAVE_U_INT32_T */ + +#ifndef HAVE_U_INT64_T +#if SIZEOF_LONG_LONG == 8 +typedef unsigned long long u_int64_t; +typedef long long int64_t; +#elif defined(_MSC_EXTENSIONS) +typedef unsigned _int64 u_int64_t; +typedef _int64 int64_t; +#elif SIZEOF_INT == 8 +typedef unsigned int u_int64_t; +#elif SIZEOF_LONG == 8 +typedef unsigned long u_int64_t; +#elif SIZEOF_SHORT == 8 +typedef unsigned short u_int64_t; +#else /* XXX */ +#error "there's no appropriate type for u_int64_t" +#endif + +#endif /* HAVE_U_INT64_T */ + +#ifndef PRId64 +#ifdef _MSC_EXTENSIONS +#define PRId64 "I64d" +#else /* _MSC_EXTENSIONS */ +#define PRId64 "lld" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRId64 */ + +#ifndef PRIo64 +#ifdef _MSC_EXTENSIONS +#define PRIo64 "I64o" +#else /* _MSC_EXTENSIONS */ +#define PRIo64 "llo" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIo64 */ + +#ifndef PRIx64 +#ifdef _MSC_EXTENSIONS +#define PRIx64 "I64x" +#else /* _MSC_EXTENSIONS */ +#define PRIx64 "llx" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIx64 */ + +#ifndef PRIu64 +#ifdef _MSC_EXTENSIONS +#define PRIu64 "I64u" +#else /* _MSC_EXTENSIONS */ +#define PRIu64 "llu" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIu64 */ + +#endif /* _BITTYPES_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/ip6_misc.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/ip6_misc.h new file mode 100644 index 000000000..96822d0e8 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/ip6_misc.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1993, 1994, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: /tcpdump/master/libpcap/Win32/Include/ip6_misc.h,v 1.5 2006-01-22 18:02:18 gianluca Exp $ (LBL) + */ + +/* + * This file contains a collage of declarations for IPv6 from FreeBSD not present in Windows + */ + +#include + +#include + +#ifndef __MINGW32__ +#define IN_MULTICAST(a) IN_CLASSD(a) +#endif + +#define IN_EXPERIMENTAL(a) ((((u_int32_t) (a)) & 0xf0000000) == 0xf0000000) + +#define IN_LOOPBACKNET 127 + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +/* IPv6 address */ +struct in6_addr + { + union + { + u_int8_t u6_addr8[16]; + u_int16_t u6_addr16[8]; + u_int32_t u6_addr32[4]; + } in6_u; +#define s6_addr in6_u.u6_addr8 +#define s6_addr16 in6_u.u6_addr16 +#define s6_addr32 in6_u.u6_addr32 +#define s6_addr64 in6_u.u6_addr64 + }; + +#define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } +#endif /* __MINGW32__ */ + + +#if (defined _MSC_VER) || (defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)) +typedef unsigned short sa_family_t; +#endif + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) + +#define __SOCKADDR_COMMON(sa_prefix) \ + sa_family_t sa_prefix##family + +/* Ditto, for IPv6. */ +struct sockaddr_in6 + { + __SOCKADDR_COMMON (sin6_); + u_int16_t sin6_port; /* Transport layer port # */ + u_int32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + }; + +#define IN6_IS_ADDR_V4MAPPED(a) \ + ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \ + (((u_int32_t *) (a))[2] == htonl (0xffff))) + +#define IN6_IS_ADDR_MULTICAST(a) (((u_int8_t *) (a))[0] == 0xff) + +#define IN6_IS_ADDR_LINKLOCAL(a) \ + ((((u_int32_t *) (a))[0] & htonl (0xffc00000)) == htonl (0xfe800000)) + +#define IN6_IS_ADDR_LOOPBACK(a) \ + (((u_int32_t *) (a))[0] == 0 && ((u_int32_t *) (a))[1] == 0 && \ + ((u_int32_t *) (a))[2] == 0 && ((u_int32_t *) (a))[3] == htonl (1)) +#endif /* __MINGW32__ */ + +#define ip6_vfc ip6_ctlun.ip6_un2_vfc +#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt +#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim +#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim + +#define nd_rd_type nd_rd_hdr.icmp6_type +#define nd_rd_code nd_rd_hdr.icmp6_code +#define nd_rd_cksum nd_rd_hdr.icmp6_cksum +#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0] + +/* + * IPV6 extension headers + */ +#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */ +#define IPPROTO_IPV6 41 /* IPv6 header. */ +#define IPPROTO_ROUTING 43 /* IPv6 routing header */ +#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ +#define IPPROTO_ESP 50 /* encapsulating security payload */ +#define IPPROTO_AH 51 /* authentication header */ +#define IPPROTO_ICMPV6 58 /* ICMPv6 */ +#define IPPROTO_NONE 59 /* IPv6 no next header */ +#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ +#define IPPROTO_PIM 103 /* Protocol Independent Multicast. */ + +#define IPV6_RTHDR_TYPE_0 0 + +/* Option types and related macros */ +#define IP6OPT_PAD1 0x00 /* 00 0 00000 */ +#define IP6OPT_PADN 0x01 /* 00 0 00001 */ +#define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ +#define IP6OPT_JUMBO_LEN 6 +#define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 */ + +#define IP6OPT_RTALERT_LEN 4 +#define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ +#define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ +#define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ +#define IP6OPT_MINLEN 2 + +#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */ +#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */ +#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */ +#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */ +#define IP6OPT_EID 0x8a /* 10 0 01010 */ + +#define IP6OPT_TYPE(o) ((o) & 0xC0) +#define IP6OPT_TYPE_SKIP 0x00 +#define IP6OPT_TYPE_DISCARD 0x40 +#define IP6OPT_TYPE_FORCEICMP 0x80 +#define IP6OPT_TYPE_ICMP 0xC0 + +#define IP6OPT_MUTABLE 0x20 + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +#ifndef EAI_ADDRFAMILY +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; +#endif +#endif /* __MINGW32__ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/netif.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/netif.h new file mode 100644 index 000000000..2d51478c0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/netif.h @@ -0,0 +1,52 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef NET_IF_H +#define NET_IF_H + +/* + * Send uip_len bytes from uip_buf to the network interface selected by the + * configNETWORK_INTERFACE_TO_USE constant (defined in FreeRTOSConfig.h). + */ +void vNetifTx( void ); + +/* + * Receive bytes from the network interface selected by the + * configNETWORK_INTERFACE_TO_USE constant (defined in FreeRTOSConfig.h). The + * bytes are placed in uip_buf. The number of bytes copied into uip_buf is + * returned. + */ +UBaseType_t uxNetifRx( void ); + +/* + * Prepare a packet capture session. This will print out all the network + * interfaces available, and the one actually used is set by the + * configNETWORK_INTERFACE_TO_USE constant that is defined in + * FreeRTOSConfig.h. */ +BaseType_t xNetifInit( void ); + +#endif /* NET_IF_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap-bpf.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap-bpf.h new file mode 100644 index 000000000..ff5b6e0da --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap-bpf.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.50 2007/04/01 21:43:55 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap-namedb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap-namedb.h new file mode 100644 index 000000000..ee6715fba --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap-namedb.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-namedb.h,v 1.13 2006/10/04 18:13:32 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap-stdinc.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap-stdinc.h new file mode 100644 index 000000000..cbd62d169 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap-stdinc.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-stdinc.h,v 1.10.2.1 2008-10-06 15:38:39 gianluca Exp $ (LBL) + */ + +#define SIZEOF_CHAR 1 +#define SIZEOF_SHORT 2 +#define SIZEOF_INT 4 +#ifndef _MSC_EXTENSIONS +#define SIZEOF_LONG_LONG 8 +#endif + +/* + * Avoids a compiler warning in case this was already defined + * (someone defined _WINSOCKAPI_ when including 'windows.h', in order + * to prevent it from including 'winsock.h') + */ +#ifdef _WINSOCKAPI_ +#undef _WINSOCKAPI_ +#endif +#include + +#include + +#include "bittypes.h" +#include +#include + +#ifndef __MINGW32__ +#include "IP6_misc.h" +#endif + +#define caddr_t char* + +#if _MSC_VER < 1500 +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#define strdup _strdup +#endif + +#define inline __inline + +#ifdef __MINGW32__ +#include +#else /*__MINGW32__*/ +/* MSVC compiler */ +#ifndef _UINTPTR_T_DEFINED +#ifdef _WIN64 +typedef unsigned __int64 uintptr_t; +#else +typedef _W64 unsigned int uintptr_t; +#endif +#define _UINTPTR_T_DEFINED +#endif + +#ifndef _INTPTR_T_DEFINED +#ifdef _WIN64 +typedef __int64 intptr_t; +#else +typedef _W64 int intptr_t; +#endif +#define _INTPTR_T_DEFINED +#endif + +#endif /*__MINGW32__*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap.h new file mode 100644 index 000000000..2eea0750b --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.59 2006/10/04 18:09:22 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Many applications + * expect to be able to include , and at least some of them + * go through contortions in their configure scripts to try to detect + * OSes that have "helpfully" moved pcap.h to without + * leaving behind a file. + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/bluetooth.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/bluetooth.h new file mode 100644 index 000000000..28b991f43 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/bluetooth.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * bluetooth data struct + * By Paolo Abeni + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/bluetooth.h,v 1.1 2007/09/22 02:10:17 guy Exp $ + */ + +#ifndef _PCAP_BLUETOOTH_STRUCTS_H__ +#define _PCAP_BLUETOOTH_STRUCTS_H__ + +/* + * Header prepended libpcap to each bluetooth h:4 frame. + * fields are in network byte order + */ +typedef struct _pcap_bluetooth_h4_header { + u_int32_t direction; /* if first bit is set direction is incoming */ +} pcap_bluetooth_h4_header; + + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/bpf.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/bpf.h new file mode 100644 index 000000000..b6d259679 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/bpf.h @@ -0,0 +1,934 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)bpf.h 7.1 (Berkeley) 5/7/91 + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/bpf.h,v 1.19.2.8 2008-09-22 20:16:01 guy Exp $ (LBL) + */ + +/* + * This is libpcap's cut-down version of bpf.h; it includes only + * the stuff needed for the code generator and the userland BPF + * interpreter, and the libpcap APIs for setting filters, etc.. + * + * "pcap-bpf.c" will include the native OS version, as it deals with + * the OS's BPF implementation. + * + * XXX - should this all just be moved to "pcap.h"? + */ + +#ifndef BPF_MAJOR_VERSION + +#ifdef __cplusplus +extern "C" { +#endif + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +#ifdef MSDOS /* must be 32-bit */ +typedef long bpf_int32; +typedef unsigned long bpf_u_int32; +#else +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +/* + * Alignment macros. BPF_WORDALIGN rounds up to the next + * even multiple of BPF_ALIGNMENT. + */ +#ifndef __NetBSD__ +#define BPF_ALIGNMENT sizeof(bpf_int32) +#else +#define BPF_ALIGNMENT sizeof(long) +#endif +#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) + +#define BPF_MAXBUFSIZE 0x8000 +#define BPF_MINBUFSIZE 32 + +/* + * Structure for "pcap_compile()", "pcap_setfilter()", etc.. + */ +struct bpf_program { + u_int bf_len; + struct bpf_insn *bf_insns; +}; + +/* + * Struct return by BIOCVERSION. This represents the version number of + * the filter language described by the instruction encodings below. + * bpf understands a program iff kernel_major == filter_major && + * kernel_minor >= filter_minor, that is, if the value returned by the + * running kernel has the same major number and a minor number equal + * equal to or less than the filter being downloaded. Otherwise, the + * results are undefined, meaning an error may be returned or packets + * may be accepted haphazardly. + * It has nothing to do with the source code version. + */ +struct bpf_version { + u_short bv_major; + u_short bv_minor; +}; +/* Current version number of filter architecture. */ +#define BPF_MAJOR_VERSION 1 +#define BPF_MINOR_VERSION 1 + +/* + * Data-link level type codes. + * + * Do *NOT* add new values to this list without asking + * "tcpdump-workers@lists.tcpdump.org" for a value. Otherwise, you run + * the risk of using a value that's already being used for some other + * purpose, and of having tools that read libpcap-format captures not + * being able to handle captures with your new DLT_ value, with no hope + * that they will ever be changed to do so (as that would destroy their + * ability to read captures using that value for that other purpose). + */ + +/* + * These are the types that are the same on all platforms, and that + * have been defined by for ages. + */ +#define DLT_NULL 0 /* BSD loopback encapsulation */ +#define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ +#define DLT_AX25 3 /* Amateur Radio AX.25 */ +#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ +#define DLT_CHAOS 5 /* Chaos */ +#define DLT_IEEE802 6 /* 802.5 Token Ring */ +#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ +#define DLT_SLIP 8 /* Serial Line IP */ +#define DLT_PPP 9 /* Point-to-point Protocol */ +#define DLT_FDDI 10 /* FDDI */ + +/* + * These are types that are different on some platforms, and that + * have been defined by for ages. We use #ifdefs to + * detect the BSDs that define them differently from the traditional + * libpcap + * + * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS, + * but I don't know what the right #define is for BSD/OS. + */ +#define DLT_ATM_RFC1483 11 /* LLC-encapsulated ATM */ + +#ifdef __OpenBSD__ +#define DLT_RAW 14 /* raw IP */ +#else +#define DLT_RAW 12 /* raw IP */ +#endif + +/* + * Given that the only OS that currently generates BSD/OS SLIP or PPP + * is, well, BSD/OS, arguably everybody should have chosen its values + * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they + * didn't. So it goes. + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) +#ifndef DLT_SLIP_BSDOS +#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ +#endif +#else +#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ +#endif + +/* + * 17 is used for DLT_OLD_PFLOG in OpenBSD; + * OBSOLETE: DLT_PFLOG is 117 in OpenBSD now as well. See below. + * 18 is used for DLT_PFSYNC in OpenBSD; don't use it for anything else. + */ + +#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ + +/* + * Apparently Redback uses this for its SmartEdge 400/800. I hope + * nobody else decided to use it, too. + */ +#define DLT_REDBACK_SMARTEDGE 32 + +/* + * These values are defined by NetBSD; other platforms should refrain from + * using them for other purposes, so that NetBSD savefiles with link + * types of 50 or 51 can be read as this type on all platforms. + */ +#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ +#define DLT_PPP_ETHER 51 /* PPP over Ethernet */ + +/* + * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses + * a link-layer type of 99 for the tcpdump it supplies. The link-layer + * header has 6 bytes of unknown data, something that appears to be an + * Ethernet type, and 36 bytes that appear to be 0 in at least one capture + * I've seen. + */ +#define DLT_SYMANTEC_FIREWALL 99 + +/* + * Values between 100 and 103 are used in capture file headers as + * link-layer types corresponding to DLT_ types that differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * This value was defined by libpcap 0.5; platforms that have defined + * it with a different value should define it here with that value - + * a link type of 104 in a save file will be mapped to DLT_C_HDLC, + * whatever value that happens to be, so programs will correctly + * handle files with that link type regardless of the value of + * DLT_C_HDLC. + * + * The name DLT_C_HDLC was used by BSD/OS; we use that name for source + * compatibility with programs written for BSD/OS. + * + * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, + * for source compatibility with programs written for libpcap 0.5. + */ +#define DLT_C_HDLC 104 /* Cisco HDLC */ +#define DLT_CHDLC DLT_C_HDLC + +#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ + +/* + * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW, + * except when it isn't. (I.e., sometimes it's just raw IP, and + * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL, + * so that we don't have to worry about the link-layer header.) + */ + +/* + * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides + * with other values. + * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header + * (DLCI, etc.). + */ +#define DLT_FRELAY 107 + +/* + * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except + * that the AF_ type in the link-layer header is in network byte order. + * + * DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so + * we don't use 12 for it in OSes other than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_LOOP 12 +#else +#define DLT_LOOP 108 +#endif + +/* + * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's + * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other + * than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_ENC 13 +#else +#define DLT_ENC 109 +#endif + +/* + * Values between 110 and 112 are reserved for use in capture file headers + * as link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ types + * other than the corresponding DLT_ types. + */ + +/* + * This is for Linux cooked sockets. + */ +#define DLT_LINUX_SLL 113 + +/* + * Apple LocalTalk hardware. + */ +#define DLT_LTALK 114 + +/* + * Acorn Econet. + */ +#define DLT_ECONET 115 + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define DLT_IPFILTER 116 + +/* + * OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, but that's DLT_LANE8023 + * in SuSE 6.3, so we can't use 17 for it in capture-file headers. + * + * XXX: is there a conflict with DLT_PFSYNC 18 as well? + */ +#ifdef __OpenBSD__ +#define DLT_OLD_PFLOG 17 +#define DLT_PFSYNC 18 +#endif +#define DLT_PFLOG 117 + +/* + * Registered for Cisco-internal use. + */ +#define DLT_CISCO_IOS 118 + +/* + * For 802.11 cards using the Prism II chips, with a link-layer + * header including Prism monitor mode information plus an 802.11 + * header. + */ +#define DLT_PRISM_HEADER 119 + +/* + * Reserved for Aironet 802.11 cards, with an Aironet link-layer header + * (see Doug Ambrisko's FreeBSD patches). + */ +#define DLT_AIRONET_HEADER 120 + +/* + * Reserved for Siemens HiPath HDLC. + */ +#define DLT_HHDLC 121 + +/* + * This is for RFC 2625 IP-over-Fibre Channel. + * + * This is not for use with raw Fibre Channel, where the link-layer + * header starts with a Fibre Channel frame header; it's for IP-over-FC, + * where the link-layer header starts with an RFC 2625 Network_Header + * field. + */ +#define DLT_IP_OVER_FC 122 + +/* + * This is for Full Frontal ATM on Solaris with SunATM, with a + * pseudo-header followed by an AALn PDU. + * + * There may be other forms of Full Frontal ATM on other OSes, + * with different pseudo-headers. + * + * If ATM software returns a pseudo-header with VPI/VCI information + * (and, ideally, packet type information, e.g. signalling, ILMI, + * LANE, LLC-multiplexed traffic, etc.), it should not use + * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump + * and the like don't have to infer the presence or absence of a + * pseudo-header and the form of the pseudo-header. + */ +#define DLT_SUNATM 123 /* Solaris+SunATM */ + +/* + * Reserved as per request from Kent Dahlgren + * for private use. + */ +#define DLT_RIO 124 /* RapidIO */ +#define DLT_PCI_EXP 125 /* PCI Express */ +#define DLT_AURORA 126 /* Xilinx Aurora link layer */ + +/* + * Header for 802.11 plus a number of bits of link-layer information + * including radio information, used by some recent BSD drivers as + * well as the madwifi Atheros driver for Linux. + */ +#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */ + +/* + * Reserved for the TZSP encapsulation, as per request from + * Chris Waters + * TZSP is a generic encapsulation for any other link type, + * which includes a means to include meta-information + * with the packet, e.g. signal strength and channel + * for 802.11 packets. + */ +#define DLT_TZSP 128 /* Tazmen Sniffer Protocol */ + +/* + * BSD's ARCNET headers have the source host, destination host, + * and type at the beginning of the packet; that's what's handed + * up to userland via BPF. + * + * Linux's ARCNET headers, however, have a 2-byte offset field + * between the host IDs and the type; that's what's handed up + * to userland via PF_PACKET sockets. + * + * We therefore have to have separate DLT_ values for them. + */ +#define DLT_ARCNET_LINUX 129 /* ARCNET */ + +/* + * Juniper-private data link types, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MLPPP 130 +#define DLT_JUNIPER_MLFR 131 +#define DLT_JUNIPER_ES 132 +#define DLT_JUNIPER_GGSN 133 +#define DLT_JUNIPER_MFR 134 +#define DLT_JUNIPER_ATM2 135 +#define DLT_JUNIPER_SERVICES 136 +#define DLT_JUNIPER_ATM1 137 + +/* + * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund + * . The header that's presented is an Ethernet-like + * header: + * + * #define FIREWIRE_EUI64_LEN 8 + * struct firewire_header { + * u_char firewire_dhost[FIREWIRE_EUI64_LEN]; + * u_char firewire_shost[FIREWIRE_EUI64_LEN]; + * u_short firewire_type; + * }; + * + * with "firewire_type" being an Ethernet type value, rather than, + * for example, raw GASP frames being handed up. + */ +#define DLT_APPLE_IP_OVER_IEEE1394 138 + +/* + * Various SS7 encapsulations, as per a request from Jeff Morriss + * and subsequent discussions. + */ +#define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */ +#define DLT_MTP2 140 /* MTP2, without pseudo-header */ +#define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */ +#define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */ + +/* + * DOCSIS MAC frames. + */ +#define DLT_DOCSIS 143 + +/* + * Linux-IrDA packets. Protocol defined at http://www.irda.org. + * Those packets include IrLAP headers and above (IrLMP...), but + * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy + * framing can be handled by the hardware and depend on the bitrate. + * This is exactly the format you would get capturing on a Linux-IrDA + * interface (irdaX), but not on a raw serial port. + * Note the capture is done in "Linux-cooked" mode, so each packet include + * a fake packet header (struct sll_header). This is because IrDA packet + * decoding is dependant on the direction of the packet (incomming or + * outgoing). + * When/if other platform implement IrDA capture, we may revisit the + * issue and define a real DLT_IRDA... + * Jean II + */ +#define DLT_LINUX_IRDA 144 + +/* + * Reserved for IBM SP switch and IBM Next Federation switch. + */ +#define DLT_IBM_SP 145 +#define DLT_IBM_SN 146 + +/* + * Reserved for private use. If you have some link-layer header type + * that you want to use within your organization, with the capture files + * using that link-layer header type not ever be sent outside your + * organization, you can use these values. + * + * No libpcap release will use these for any purpose, nor will any + * tcpdump release use them, either. + * + * Do *NOT* use these in capture files that you expect anybody not using + * your private versions of capture-file-reading tools to read; in + * particular, do *NOT* use them in products, otherwise you may find that + * people won't be able to use tcpdump, or snort, or Ethereal, or... to + * read capture files from your firewall/intrusion detection/traffic + * monitoring/etc. appliance, or whatever product uses that DLT_ value, + * and you may also find that the developers of those applications will + * not accept patches to let them read those files. + * + * Also, do not use them if somebody might send you a capture using them + * for *their* private type and tools using them for *your* private type + * would have to read them. + * + * Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value, + * as per the comment above, and use the type you're given. + */ +#define DLT_USER0 147 +#define DLT_USER1 148 +#define DLT_USER2 149 +#define DLT_USER3 150 +#define DLT_USER4 151 +#define DLT_USER5 152 +#define DLT_USER6 153 +#define DLT_USER7 154 +#define DLT_USER8 155 +#define DLT_USER9 156 +#define DLT_USER10 157 +#define DLT_USER11 158 +#define DLT_USER12 159 +#define DLT_USER13 160 +#define DLT_USER14 161 +#define DLT_USER15 162 + +/* + * For future use with 802.11 captures - defined by AbsoluteValue + * Systems to store a number of bits of link-layer information + * including radio information: + * + * http://www.shaftnet.org/~pizza/software/capturefrm.txt + * + * but it might be used by some non-AVS drivers now or in the + * future. + */ +#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MONITOR 164 + +/* + * Reserved for BACnet MS/TP. + */ +#define DLT_BACNET_MS_TP 165 + +/* + * Another PPP variant as per request from Karsten Keil . + * + * This is used in some OSes to allow a kernel socket filter to distinguish + * between incoming and outgoing packets, on a socket intended to + * supply pppd with outgoing packets so it can do dial-on-demand and + * hangup-on-lack-of-demand; incoming packets are filtered out so they + * don't cause pppd to hold the connection up (you don't want random + * input packets such as port scans, packets from old lost connections, + * etc. to force the connection to stay up). + * + * The first byte of the PPP header (0xff03) is modified to accomodate + * the direction - 0x00 = IN, 0x01 = OUT. + */ +#define DLT_PPP_PPPD 166 + +/* + * Names for backwards compatibility with older versions of some PPP + * software; new software should use DLT_PPP_PPPD. + */ +#define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD +#define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, cookies, etc.. + */ +#define DLT_JUNIPER_PPPOE 167 +#define DLT_JUNIPER_PPPOE_ATM 168 + +#define DLT_GPRS_LLC 169 /* GPRS LLC */ +#define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ +#define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ + +/* + * Requested by Oolan Zimmer for use in Gcom's T1/E1 line + * monitoring equipment. + */ +#define DLT_GCOM_T1E1 172 +#define DLT_GCOM_SERIAL 173 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_ is used + * for internal communication to Physical Interface Cards (PIC) + */ +#define DLT_JUNIPER_PIC_PEER 174 + +/* + * Link types requested by Gregor Maier of Endace + * Measurement Systems. They add an ERF header (see + * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of + * the link-layer header. + */ +#define DLT_ERF_ETH 175 /* Ethernet */ +#define DLT_ERF_POS 176 /* Packet-over-SONET */ + +/* + * Requested by Daniele Orlandi for raw LAPD + * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header + * includes additional information before the LAPD header, so it's + * not necessarily a generic LAPD header. + */ +#define DLT_LINUX_LAPD 177 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ are used for prepending meta-information + * like interface index, interface name + * before standard Ethernet, PPP, Frelay & C-HDLC Frames + */ +#define DLT_JUNIPER_ETHER 178 +#define DLT_JUNIPER_PPP 179 +#define DLT_JUNIPER_FRELAY 180 +#define DLT_JUNIPER_CHDLC 181 + +/* + * Multi Link Frame Relay (FRF.16) + */ +#define DLT_MFR 182 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * voice Adapter Card (PIC) + */ +#define DLT_JUNIPER_VP 183 + +/* + * Arinc 429 frames. + * DLT_ requested by Gianluca Varenni . + * Every frame contains a 32bit A429 label. + * More documentation on Arinc 429 can be found at + * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf + */ +#define DLT_A429 184 + +/* + * Arinc 653 Interpartition Communication messages. + * DLT_ requested by Gianluca Varenni . + * Please refer to the A653-1 standard for more information. + */ +#define DLT_A653_ICM 185 + +/* + * USB packets, beginning with a USB setup header; requested by + * Paolo Abeni . + */ +#define DLT_USB 186 + +/* + * Bluetooth HCI UART transport layer (part H:4); requested by + * Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4 187 + +/* + * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz + * . + */ +#define DLT_IEEE802_16_MAC_CPS 188 + +/* + * USB packets, beginning with a Linux USB header; requested by + * Paolo Abeni . + */ +#define DLT_USB_LINUX 189 + +/* + * Controller Area Network (CAN) v. 2.0B packets. + * DLT_ requested by Gianluca Varenni . + * Used to dump CAN packets coming from a CAN Vector board. + * More documentation on the CAN v2.0B frames can be found at + * http://www.can-cia.org/downloads/?269 + */ +#define DLT_CAN20B 190 + +/* + * IEEE 802.15.4, with address fields padded, as is done by Linux + * drivers; requested by Juergen Schimmer. + */ +#define DLT_IEEE802_15_4_LINUX 191 + +/* + * Per Packet Information encapsulated packets. + * DLT_ requested by Gianluca Varenni . + */ +#define DLT_PPI 192 + +/* + * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; + * requested by Charles Clancy. + */ +#define DLT_IEEE802_16_MAC_CPS_RADIO 193 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * integrated service module (ISM). + */ +#define DLT_JUNIPER_ISM 194 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing); requested by Mikko Saarnivala . + */ +#define DLT_IEEE802_15_4 195 + +/* + * Various link-layer types, with a pseudo-header, for SITA + * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). + */ +#define DLT_SITA 196 + +/* + * Various link-layer types, with a pseudo-header, for Endace DAG cards; + * encapsulates Endace ERF records. Requested by Stephen Donnelly + * . + */ +#define DLT_ERF 197 + +/* + * Special header prepended to Ethernet packets when capturing from a + * u10 Networks board. Requested by Phil Mulholland + * . + */ +#define DLT_RAIF1 198 + +/* + * IPMB packet for IPMI, beginning with the I2C slave address, followed + * by the netFn and LUN, etc.. Requested by Chanthy Toeung + * . + */ +#define DLT_IPMB 199 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for capturing data on a secure tunnel interface. + */ +#define DLT_JUNIPER_ST 200 + +/* + * Bluetooth HCI UART transport layer (part H:4), with pseudo-header + * that includes direction information; requested by Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4_WITH_PHDR 201 + +/* + * AX.25 packet with a 1-byte KISS header; see + * + * http://www.ax25.net/kiss.htm + * + * as per Richard Stearn . + */ +#define DLT_AX25_KISS 202 + +/* + * LAPD packets from an ISDN channel, starting with the address field, + * with no pseudo-header. + * Requested by Varuna De Silva . + */ +#define DLT_LAPD 203 + +/* + * Variants of various link-layer headers, with a one-byte direction + * pseudo-header prepended - zero means "received by this host", + * non-zero (any non-zero value) means "sent by this host" - as per + * Will Barker . + */ +#define DLT_PPP_WITH_DIR 204 /* PPP - don't confuse with DLT_PPP_WITH_DIRECTION */ +#define DLT_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ +#define DLT_FRELAY_WITH_DIR 206 /* Frame Relay */ +#define DLT_LAPB_WITH_DIR 207 /* LAPB */ + +/* + * 208 is reserved for an as-yet-unspecified proprietary link-layer + * type, as requested by Will Barker. + */ + +/* + * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman + * . + */ +#define DLT_IPMB_LINUX 209 + +/* + * FlexRay automotive bus - http://www.flexray.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_FLEXRAY 210 + +/* + * Media Oriented Systems Transport (MOST) bus for multimedia + * transport - http://www.mostcooperation.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_MOST 211 + +/* + * Local Interconnect Network (LIN) bus for vehicle networks - + * http://www.lin-subbus.org/ - as requested by Hannes Kaelber + * . + */ +#define DLT_LIN 212 + +/* + * X2E-private data link type used for serial line capture, + * as requested by Hannes Kaelber . + */ +#define DLT_X2E_SERIAL 213 + +/* + * X2E-private data link type used for the Xoraya data logger + * family, as requested by Hannes Kaelber . + */ +#define DLT_X2E_XORAYA 214 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), but with the PHY-level data for non-ASK PHYs (4 octets + * of 0 as preamble, one octet of SFD, one octet of frame length+ + * reserved bit, and then the MAC-layer data, starting with the + * frame control field). + * + * Requested by Max Filippov . + */ +#define DLT_IEEE802_15_4_NONASK_PHY 215 + + +/* + * DLT and savefile link type values are split into a class and + * a member of that class. A class value of 0 indicates a regular + * DLT_/LINKTYPE_ value. + */ +#define DLT_CLASS(x) ((x) & 0x03ff0000) + +/* + * NetBSD-specific generic "raw" link type. The class value indicates + * that this is the generic raw type, and the lower 16 bits are the + * address family we're dealing with. Those values are NetBSD-specific; + * do not assume that they correspond to AF_ values for your operating + * system. + */ +#define DLT_CLASS_NETBSD_RAWAF 0x02240000 +#define DLT_NETBSD_RAWAF(af) (DLT_CLASS_NETBSD_RAWAF | (af)) +#define DLT_NETBSD_RAWAF_AF(x) ((x) & 0x0000ffff) +#define DLT_IS_NETBSD_RAWAF(x) (DLT_CLASS(x) == DLT_CLASS_NETBSD_RAWAF) + + +/* + * The instruction encodings. + */ +/* instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* ret - BPF_K and BPF_X also apply */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 + +/* misc */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +#define BPF_TXA 0x80 + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_u_int32 k; +}; + +/* + * Macros for insn array initializers. + */ +#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } +#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } + +#if __STDC__ || defined(__cplusplus) +extern int bpf_validate(const struct bpf_insn *, int); +extern u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +#else +extern int bpf_validate(); +extern u_int bpf_filter(); +#endif + +/* + * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). + */ +#define BPF_MEMWORDS 16 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/namedb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/namedb.h new file mode 100644 index 000000000..8298e35b9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/namedb.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/namedb.h,v 1.1 2006/10/04 18:09:22 guy Exp $ (LBL) + */ + +#ifndef lib_pcap_namedb_h +#define lib_pcap_namedb_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * As returned by the pcap_next_etherent() + * XXX this stuff doesn't belong in this interface, but this + * library already must do name to address translation, so + * on systems that don't have support for /etc/ethers, we + * export these hooks since they'll + */ +struct pcap_etherent { + u_char addr[6]; + char name[122]; +}; +#ifndef PCAP_ETHERS_FILE +#define PCAP_ETHERS_FILE "/etc/ethers" +#endif +struct pcap_etherent *pcap_next_etherent(FILE *); +u_char *pcap_ether_hostton(const char*); +u_char *pcap_ether_aton(const char *); + +bpf_u_int32 **pcap_nametoaddr(const char *); +#ifdef INET6 +struct addrinfo *pcap_nametoaddrinfo(const char *); +#endif +bpf_u_int32 pcap_nametonetaddr(const char *); + +int pcap_nametoport(const char *, int *, int *); +int pcap_nametoportrange(const char *, int *, int *, int *); +int pcap_nametoproto(const char *); +int pcap_nametoeproto(const char *); +int pcap_nametollc(const char *); +/* + * If a protocol is unknown, PROTO_UNDEF is returned. + * Also, pcap_nametoport() returns the protocol along with the port number. + * If there are ambiguous entried in /etc/services (i.e. domain + * can be either tcp or udp) PROTO_UNDEF is returned. + */ +#define PROTO_UNDEF -1 + +/* XXX move these to pcap-int.h? */ +int __pcap_atodn(const char *, bpf_u_int32 *); +int __pcap_atoin(const char *, bpf_u_int32 *); +u_short __pcap_nametodnaddr(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/pcap.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/pcap.h new file mode 100644 index 000000000..fbf83413a --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/pcap.h @@ -0,0 +1,407 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/pcap.h,v 1.4.2.11 2008-10-06 15:38:39 gianluca Exp $ (LBL) + */ + +#ifndef lib_pcap_pcap_h +#define lib_pcap_pcap_h + +#if defined(WIN32) + #include +#elif defined(MSDOS) + #include + #include /* u_int, u_char etc. */ +#else /* UN*X */ + #include + #include +#endif /* WIN32/MSDOS/UN*X */ + +#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H +#include +#endif + +#include + +#ifdef HAVE_REMOTE + // We have to define the SOCKET here, although it has been defined in sockutils.h + // This is to avoid the distribution of the 'sockutils.h' file around + // (for example in the WinPcap developer's pack) + #ifndef SOCKET + #ifdef WIN32 + #define SOCKET unsigned int + #else + #define SOCKET int + #endif + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 + +#define PCAP_ERRBUF_SIZE 256 + +/* + * Compatibility for systems that have a bpf.h that + * predates the bpf typedefs for 64-bit support. + */ +#if BPF_RELEASE - 0 < 199406 +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +typedef struct pcap pcap_t; +typedef struct pcap_dumper pcap_dumper_t; +typedef struct pcap_if pcap_if_t; +typedef struct pcap_addr pcap_addr_t; + +/* + * The first record in the file contains saved values for some + * of the flags used in the printout phases of tcpdump. + * Many fields here are 32 bit ints so compilers won't insert unwanted + * padding; these files need to be interchangeable across architectures. + * + * Do not change the layout of this structure, in any way (this includes + * changes that only affect the length of fields in this structure). + * + * Also, do not change the interpretation of any of the members of this + * structure, in any way (this includes using values other than + * LINKTYPE_ values, as defined in "savefile.c", in the "linktype" + * field). + * + * Instead: + * + * introduce a new structure for the new format, if the layout + * of the structure changed; + * + * send mail to "tcpdump-workers@lists.tcpdump.org", requesting + * a new magic number for your new capture file format, and, when + * you get the new magic number, put it in "savefile.c"; + * + * use that magic number for save files with the changed file + * header; + * + * make the code in "savefile.c" capable of reading files with + * the old file header as well as files with the new file header + * (using the magic number to determine the header format). + * + * Then supply the changes as a patch at + * + * http://sourceforge.net/projects/libpcap/ + * + * so that future versions of libpcap and programs that use it (such as + * tcpdump) will be able to read your new capture file format. + */ +struct pcap_file_header { + bpf_u_int32 magic; + u_short version_major; + u_short version_minor; + bpf_int32 thiszone; /* gmt to local correction */ + bpf_u_int32 sigfigs; /* accuracy of timestamps */ + bpf_u_int32 snaplen; /* max length saved portion of each pkt */ + bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ +}; + +/* + * Macros for the value returned by pcap_datalink_ext(). + * + * If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro + * gives the FCS length of packets in the capture. + */ +#define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000) +#define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28) +#define LT_FCS_DATALINK_EXT(x) ((((x) & 0xF) << 28) | 0x04000000) + +typedef enum { + PCAP_D_INOUT = 0, + PCAP_D_IN, + PCAP_D_OUT +} pcap_direction_t; + +/* + * Generic per-packet information, as supplied by libpcap. + * + * The time stamp can and should be a "struct timeval", regardless of + * whether your system supports 32-bit tv_sec in "struct timeval", + * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit + * and 64-bit applications. The on-disk format of savefiles uses 32-bit + * tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit + * and 64-bit versions of libpcap, even if they're on the same platform, + * should supply the appropriate version of "struct timeval", even if + * that's not what the underlying packet capture mechanism supplies. + */ +struct pcap_pkthdr { + struct timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ +}; + +/* + * As returned by the pcap_stats() + */ +struct pcap_stat { + u_int ps_recv; /* number of packets received */ + u_int ps_drop; /* number of packets dropped */ + u_int ps_ifdrop; /* drops by interface XXX not yet supported */ +#ifdef HAVE_REMOTE + u_int ps_capt; /* number of packets that are received by the application; please get rid off the Win32 ifdef */ + u_int ps_sent; /* number of packets sent by the server on the network */ + u_int ps_netdrop; /* number of packets lost on the network */ +#endif /* HAVE_REMOTE */ +}; + +#ifdef MSDOS +/* + * As returned by the pcap_stats_ex() + */ +struct pcap_stat_ex { + u_long rx_packets; /* total packets received */ + u_long tx_packets; /* total packets transmitted */ + u_long rx_bytes; /* total bytes received */ + u_long tx_bytes; /* total bytes transmitted */ + u_long rx_errors; /* bad packets received */ + u_long tx_errors; /* packet transmit problems */ + u_long rx_dropped; /* no space in Rx buffers */ + u_long tx_dropped; /* no space available for Tx */ + u_long multicast; /* multicast packets received */ + u_long collisions; + + /* detailed rx_errors: */ + u_long rx_length_errors; + u_long rx_over_errors; /* receiver ring buff overflow */ + u_long rx_crc_errors; /* recv'd pkt with crc error */ + u_long rx_frame_errors; /* recv'd frame alignment error */ + u_long rx_fifo_errors; /* recv'r fifo overrun */ + u_long rx_missed_errors; /* recv'r missed packet */ + + /* detailed tx_errors */ + u_long tx_aborted_errors; + u_long tx_carrier_errors; + u_long tx_fifo_errors; + u_long tx_heartbeat_errors; + u_long tx_window_errors; + }; +#endif + +/* + * Item in a list of interfaces. + */ +struct pcap_if { + struct pcap_if *next; + char *name; /* name to hand to "pcap_open_live()" */ + char *description; /* textual description of interface, or NULL */ + struct pcap_addr *addresses; + bpf_u_int32 flags; /* PCAP_IF_ interface flags */ +}; + +#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ + +/* + * Representation of an interface address. + */ +struct pcap_addr { + struct pcap_addr *next; + struct sockaddr *addr; /* address */ + struct sockaddr *netmask; /* netmask for that address */ + struct sockaddr *broadaddr; /* broadcast address for that address */ + struct sockaddr *dstaddr; /* P2P destination address for that address */ +}; + +typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, + const u_char *); + +/* + * Error codes for the pcap API. + * These will all be negative, so you can check for the success or + * failure of a call that returns these codes by checking for a + * negative value. + */ +#define PCAP_ERROR -1 /* generic error code */ +#define PCAP_ERROR_BREAK -2 /* loop terminated by pcap_breakloop */ +#define PCAP_ERROR_NOT_ACTIVATED -3 /* the capture needs to be activated */ +#define PCAP_ERROR_ACTIVATED -4 /* the operation can't be performed on already activated captures */ +#define PCAP_ERROR_NO_SUCH_DEVICE -5 /* no such device exists */ +#define PCAP_ERROR_RFMON_NOTSUP -6 /* this device doesn't support rfmon (monitor) mode */ +#define PCAP_ERROR_NOT_RFMON -7 /* operation supported only in monitor mode */ +#define PCAP_ERROR_PERM_DENIED -8 /* no permission to open the device */ +#define PCAP_ERROR_IFACE_NOT_UP -9 /* interface isn't up */ + +/* + * Warning codes for the pcap API. + * These will all be positive and non-zero, so they won't look like + * errors. + */ +#define PCAP_WARNING 1 /* generic warning code */ +#define PCAP_WARNING_PROMISC_NOTSUP 2 /* this device doesn't support promiscuous mode */ + +char *pcap_lookupdev(char *); +int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); + +pcap_t *pcap_create(const char *, char *); +int pcap_set_snaplen(pcap_t *, int); +int pcap_set_promisc(pcap_t *, int); +int pcap_can_set_rfmon(pcap_t *); +int pcap_set_rfmon(pcap_t *, int); +int pcap_set_timeout(pcap_t *, int); +int pcap_set_buffer_size(pcap_t *, int); +int pcap_activate(pcap_t *); + +pcap_t *pcap_open_live(const char *, int, int, int, char *); +pcap_t *pcap_open_dead(int, int); +pcap_t *pcap_open_offline(const char *, char *); +#if defined(WIN32) +pcap_t *pcap_hopen_offline(intptr_t, char *); +#if !defined(LIBPCAP_EXPORTS) +#define pcap_fopen_offline(f,b) \ + pcap_hopen_offline(_get_osfhandle(_fileno(f)), b) +#else /*LIBPCAP_EXPORTS*/ +static pcap_t *pcap_fopen_offline(FILE *, char *); +#endif +#else /*WIN32*/ +pcap_t *pcap_fopen_offline(FILE *, char *); +#endif /*WIN32*/ + +void pcap_close(pcap_t *); +int pcap_loop(pcap_t *, int, pcap_handler, u_char *); +int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); +const u_char* + pcap_next(pcap_t *, struct pcap_pkthdr *); +int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); +void pcap_breakloop(pcap_t *); +int pcap_stats(pcap_t *, struct pcap_stat *); +int pcap_setfilter(pcap_t *, struct bpf_program *); +int pcap_setdirection(pcap_t *, pcap_direction_t); +int pcap_getnonblock(pcap_t *, char *); +int pcap_setnonblock(pcap_t *, int, char *); +int pcap_inject(pcap_t *, const void *, size_t); +int pcap_sendpacket(pcap_t *, const u_char *, int); +const char *pcap_statustostr(int); +const char *pcap_strerror(int); +char *pcap_geterr(pcap_t *); +void pcap_perror(pcap_t *, char *); +int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, + bpf_u_int32); +int pcap_compile_nopcap(int, int, struct bpf_program *, + const char *, int, bpf_u_int32); +void pcap_freecode(struct bpf_program *); +int pcap_offline_filter(struct bpf_program *, const struct pcap_pkthdr *, + const u_char *); +int pcap_datalink(pcap_t *); +int pcap_datalink_ext(pcap_t *); +int pcap_list_datalinks(pcap_t *, int **); +int pcap_set_datalink(pcap_t *, int); +void pcap_free_datalinks(int *); +int pcap_datalink_name_to_val(const char *); +const char *pcap_datalink_val_to_name(int); +const char *pcap_datalink_val_to_description(int); +int pcap_snapshot(pcap_t *); +int pcap_is_swapped(pcap_t *); +int pcap_major_version(pcap_t *); +int pcap_minor_version(pcap_t *); + +/* XXX */ +FILE *pcap_file(pcap_t *); +int pcap_fileno(pcap_t *); + +pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); +pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); +FILE *pcap_dump_file(pcap_dumper_t *); +long pcap_dump_ftell(pcap_dumper_t *); +int pcap_dump_flush(pcap_dumper_t *); +void pcap_dump_close(pcap_dumper_t *); +void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); + +int pcap_findalldevs(pcap_if_t **, char *); +void pcap_freealldevs(pcap_if_t *); + +const char *pcap_lib_version(void); + +/* XXX this guy lives in the bpf tree */ +u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +int bpf_validate(const struct bpf_insn *f, int len); +char *bpf_image(const struct bpf_insn *, int); +void bpf_dump(const struct bpf_program *, int); + +#if defined(WIN32) + +/* + * Win32 definitions + */ + +int pcap_setbuff(pcap_t *p, int dim); +int pcap_setmode(pcap_t *p, int mode); +int pcap_setmintocopy(pcap_t *p, int size); + +#ifdef WPCAP +/* Include file with the wpcap-specific extensions */ +#include +#endif /* WPCAP */ + +#define MODE_CAPT 0 +#define MODE_STAT 1 +#define MODE_MON 2 + +#elif defined(MSDOS) + +/* + * MS-DOS definitions + */ + +int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *); +void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait); +u_long pcap_mac_packets (void); + +#else /* UN*X */ + +/* + * UN*X definitions + */ + +int pcap_get_selectable_fd(pcap_t *); + +#endif /* WIN32/MSDOS/UN*X */ + +#ifdef HAVE_REMOTE +/* Includes most of the public stuff that is needed for the remote capture */ +#include +#endif /* HAVE_REMOTE */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/sll.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/sll.h new file mode 100644 index 000000000..5907beded --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/sll.h @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/sll.h,v 1.2.2.1 2008-05-30 01:36:06 guy Exp $ (LBL) + */ + +/* + * For captures on Linux cooked sockets, we construct a fake header + * that includes: + * + * a 2-byte "packet type" which is one of: + * + * LINUX_SLL_HOST packet was sent to us + * LINUX_SLL_BROADCAST packet was broadcast + * LINUX_SLL_MULTICAST packet was multicast + * LINUX_SLL_OTHERHOST packet was sent to somebody else + * LINUX_SLL_OUTGOING packet was sent *by* us; + * + * a 2-byte Ethernet protocol field; + * + * a 2-byte link-layer type; + * + * a 2-byte link-layer address length; + * + * an 8-byte source link-layer address, whose actual length is + * specified by the previous value. + * + * All fields except for the link-layer address are in network byte order. + * + * DO NOT change the layout of this structure, or change any of the + * LINUX_SLL_ values below. If you must change the link-layer header + * for a "cooked" Linux capture, introduce a new DLT_ type (ask + * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it + * a value that collides with a value already being used), and use the + * new header in captures of that type, so that programs that can + * handle DLT_LINUX_SLL captures will continue to handle them correctly + * without any change, and so that capture files with different headers + * can be told apart and programs that read them can dissect the + * packets in them. + */ + +#ifndef lib_pcap_sll_h +#define lib_pcap_sll_h + +/* + * A DLT_LINUX_SLL fake link-layer header. + */ +#define SLL_HDR_LEN 16 /* total header length */ +#define SLL_ADDRLEN 8 /* length of address field */ + +struct sll_header { + u_int16_t sll_pkttype; /* packet type */ + u_int16_t sll_hatype; /* link-layer address type */ + u_int16_t sll_halen; /* link-layer address length */ + u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ + u_int16_t sll_protocol; /* protocol */ +}; + +/* + * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the + * PACKET_ values on Linux, but are defined here so that they're + * available even on systems other than Linux, and so that they + * don't change even if the PACKET_ values change. + */ +#define LINUX_SLL_HOST 0 +#define LINUX_SLL_BROADCAST 1 +#define LINUX_SLL_MULTICAST 2 +#define LINUX_SLL_OTHERHOST 3 +#define LINUX_SLL_OUTGOING 4 + +/* + * The LINUX_SLL_ values for "sll_protocol"; these correspond to the + * ETH_P_ values on Linux, but are defined here so that they're + * available even on systems other than Linux. We assume, for now, + * that the ETH_P_ values won't change in Linux; if they do, then: + * + * if we don't translate them in "pcap-linux.c", capture files + * won't necessarily be readable if captured on a system that + * defines ETH_P_ values that don't match these values; + * + * if we do translate them in "pcap-linux.c", that makes life + * unpleasant for the BPF code generator, as the values you test + * for in the kernel aren't the values that you test for when + * reading a capture file, so the fixup code run on BPF programs + * handed to the kernel ends up having to do more work. + * + * Add other values here as necessary, for handling packet types that + * might show up on non-Ethernet, non-802.x networks. (Not all the ones + * in the Linux "if_ether.h" will, I suspect, actually show up in + * captures.) + */ +#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ +#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/usb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/usb.h new file mode 100644 index 000000000..f150d3be0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/usb.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * Basic USB data struct + * By Paolo Abeni + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/usb.h,v 1.6 2007/09/22 02:06:08 guy Exp $ + */ + +#ifndef _PCAP_USB_STRUCTS_H__ +#define _PCAP_USB_STRUCTS_H__ + +/* + * possible transfer mode + */ +#define URB_TRANSFER_IN 0x80 +#define URB_ISOCHRONOUS 0x0 +#define URB_INTERRUPT 0x1 +#define URB_CONTROL 0x2 +#define URB_BULK 0x3 + +/* + * possible event type + */ +#define URB_SUBMIT 'S' +#define URB_COMPLETE 'C' +#define URB_ERROR 'E' + +/* + * USB setup header as defined in USB specification. + * Appears at the front of each packet in DLT_USB captures. + */ +typedef struct _usb_setup { + u_int8_t bmRequestType; + u_int8_t bRequest; + u_int16_t wValue; + u_int16_t wIndex; + u_int16_t wLength; +} pcap_usb_setup; + + +/* + * Header prepended by linux kernel to each event. + * Appears at the front of each packet in DLT_USB_LINUX captures. + */ +typedef struct _usb_header { + u_int64_t id; + u_int8_t event_type; + u_int8_t transfer_type; + u_int8_t endpoint_number; + u_int8_t device_address; + u_int16_t bus_id; + char setup_flag;/*if !=0 the urb setup header is not present*/ + char data_flag; /*if !=0 no urb data is present*/ + int64_t ts_sec; + int32_t ts_usec; + int32_t status; + u_int32_t urb_len; + u_int32_t data_len; /* amount of urb data really present in this event*/ + pcap_usb_setup setup; +} pcap_usb_header; + + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/vlan.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/vlan.h new file mode 100644 index 000000000..00ed9b616 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/pcap/vlan.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/vlan.h,v 1.1.2.2 2008-08-06 07:45:59 guy Exp $ + */ + +#ifndef lib_pcap_vlan_h +#define lib_pcap_vlan_h + +struct vlan_tag { + u_int16_t vlan_tpid; /* ETH_P_8021Q */ + u_int16_t vlan_tci; /* VLAN TCI */ +}; + +#define VLAN_TAG_LEN 4 + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/remote-ext.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/remote-ext.h new file mode 100644 index 000000000..9f54d6974 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/remote-ext.h @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * 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. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + + +#ifndef __REMOTE_EXT_H__ +#define __REMOTE_EXT_H__ + + +#ifndef HAVE_REMOTE +#error Please do not include this file directly. Just define HAVE_REMOTE and then include pcap.h +#endif + +// Definition for Microsoft Visual Studio +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + \file remote-ext.h + + The goal of this file it to include most of the new definitions that should be + placed into the pcap.h file. + + It includes all new definitions (structures and functions like pcap_open(). + Some of the functions are not really a remote feature, but, right now, + they are placed here. +*/ + + + +// All this stuff is public +/*! \addtogroup remote_struct + \{ +*/ + + + + +/*! + \brief Defines the maximum buffer size in which address, port, interface names are kept. + + In case the adapter name or such is larger than this value, it is truncated. + This is not used by the user; however it must be aware that an hostname / interface + name longer than this value will be truncated. +*/ +#define PCAP_BUF_SIZE 1024 + + +/*! \addtogroup remote_source_ID + \{ +*/ + + +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a file, i.e. the user want to open a capture from a local file. +*/ +#define PCAP_SRC_FILE 2 +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a local interface, i.e. the user want to open a capture from + a local interface. This does not involve the RPCAP protocol. +*/ +#define PCAP_SRC_IFLOCAL 3 +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a remote interface, i.e. the user want to open a capture from + an interface on a remote host. This does involve the RPCAP protocol. +*/ +#define PCAP_SRC_IFREMOTE 4 + +/*! + \} +*/ + + + +/*! \addtogroup remote_source_string + + The formats allowed by the pcap_open() are the following: + - file://path_and_filename [opens a local file] + - rpcap://devicename [opens the selected device devices available on the local host, without using the RPCAP protocol] + - rpcap://host/devicename [opens the selected device available on a remote host] + - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP] + - adaptername [to open a local adapter; kept for compability, but it is strongly discouraged] + - (NULL) [to open the first local adapter; kept for compability, but it is strongly discouraged] + + The formats allowed by the pcap_findalldevs_ex() are the following: + - file://folder/ [lists all the files in the given folder] + - rpcap:// [lists all local adapters] + - rpcap://host:port/ [lists the devices available on a remote host] + + Referring to the 'host' and 'port' paramters, they can be either numeric or literal. Since + IPv6 is fully supported, these are the allowed formats: + + - host (literal): e.g. host.foo.bar + - host (numeric IPv4): e.g. 10.11.12.13 + - host (numeric IPv4, IPv6 style): e.g. [10.11.12.13] + - host (numeric IPv6): e.g. [1:2:3::4] + - port: can be either numeric (e.g. '80') or literal (e.g. 'http') + + Here you find some allowed examples: + - rpcap://host.foo.bar/devicename [everything literal, no port number] + - rpcap://host.foo.bar:1234/devicename [everything literal, with port number] + - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number] + - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number] + - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number] + - rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number] + - rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number] + - rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number] + + \{ +*/ + + +/*! + \brief String that will be used to determine the type of source in use (file, + remote/local interface). + + This string will be prepended to the interface name in order to create a string + that contains all the information required to open the source. + + This string indicates that the user wants to open a capture from a local file. +*/ +#define PCAP_SRC_FILE_STRING "file://" +/*! + \brief String that will be used to determine the type of source in use (file, + remote/local interface). + + This string will be prepended to the interface name in order to create a string + that contains all the information required to open the source. + + This string indicates that the user wants to open a capture from a network interface. + This string does not necessarily involve the use of the RPCAP protocol. If the + interface required resides on the local host, the RPCAP protocol is not involved + and the local functions are used. +*/ +#define PCAP_SRC_IF_STRING "rpcap://" + +/*! + \} +*/ + + + + + +/*! + \addtogroup remote_open_flags + \{ +*/ + +/*! + \brief Defines if the adapter has to go in promiscuous mode. + + It is '1' if you have to open the adapter in promiscuous mode, '0' otherwise. + Note that even if this parameter is false, the interface could well be in promiscuous + mode for some other reason (for example because another capture process with + promiscuous mode enabled is currently using that interface). + On on Linux systems with 2.2 or later kernels (that have the "any" device), this + flag does not work on the "any" device; if an argument of "any" is supplied, + the 'promisc' flag is ignored. +*/ +#define PCAP_OPENFLAG_PROMISCUOUS 1 + +/*! + \brief Defines if the data trasfer (in case of a remote + capture) has to be done with UDP protocol. + + If it is '1' if you want a UDP data connection, '0' if you want + a TCP data connection; control connection is always TCP-based. + A UDP connection is much lighter, but it does not guarantee that all + the captured packets arrive to the client workstation. Moreover, + it could be harmful in case of network congestion. + This flag is meaningless if the source is not a remote interface. + In that case, it is simply ignored. +*/ +#define PCAP_OPENFLAG_DATATX_UDP 2 + + +/*! + \brief Defines if the remote probe will capture its own generated traffic. + + In case the remote probe uses the same interface to capture traffic and to send + data back to the caller, the captured traffic includes the RPCAP traffic as well. + If this flag is turned on, the RPCAP traffic is excluded from the capture, so that + the trace returned back to the collector is does not include this traffic. +*/ +#define PCAP_OPENFLAG_NOCAPTURE_RPCAP 4 + +/*! + \brief Defines if the local adapter will capture its own generated traffic. + + This flag tells the underlying capture driver to drop the packets that were sent by itself. + This is usefult when building applications like bridges, that should ignore the traffic + they just sent. +*/ +#define PCAP_OPENFLAG_NOCAPTURE_LOCAL 8 + +/*! + \brief This flag configures the adapter for maximum responsiveness. + + In presence of a large value for nbytes, WinPcap waits for the arrival of several packets before + copying the data to the user. This guarantees a low number of system calls, i.e. lower processor usage, + i.e. better performance, which is good for applications like sniffers. If the user sets the + PCAP_OPENFLAG_MAX_RESPONSIVENESS flag, the capture driver will copy the packets as soon as the application + is ready to receive them. This is suggested for real time applications (like, for example, a bridge) + that need the best responsiveness.*/ +#define PCAP_OPENFLAG_MAX_RESPONSIVENESS 16 + +/*! + \} +*/ + + +/*! + \addtogroup remote_samp_methods + \{ +*/ + +/*! + \brief No sampling has to be done on the current capture. + + In this case, no sampling algorithms are applied to the current capture. +*/ +#define PCAP_SAMP_NOSAMP 0 + +/*! + \brief It defines that only 1 out of N packets must be returned to the user. + + In this case, the 'value' field of the 'pcap_samp' structure indicates the + number of packets (minus 1) that must be discarded before one packet got accepted. + In other words, if 'value = 10', the first packet is returned to the caller, while + the following 9 are discarded. +*/ +#define PCAP_SAMP_1_EVERY_N 1 + +/*! + \brief It defines that we have to return 1 packet every N milliseconds. + + In this case, the 'value' field of the 'pcap_samp' structure indicates the 'waiting + time' in milliseconds before one packet got accepted. + In other words, if 'value = 10', the first packet is returned to the caller; the next + returned one will be the first packet that arrives when 10ms have elapsed. +*/ +#define PCAP_SAMP_FIRST_AFTER_N_MS 2 + +/*! + \} +*/ + + +/*! + \addtogroup remote_auth_methods + \{ +*/ + +/*! + \brief It defines the NULL authentication. + + This value has to be used within the 'type' member of the pcap_rmtauth structure. + The 'NULL' authentication has to be equal to 'zero', so that old applications + can just put every field of struct pcap_rmtauth to zero, and it does work. +*/ +#define RPCAP_RMTAUTH_NULL 0 +/*! + \brief It defines the username/password authentication. + + With this type of authentication, the RPCAP protocol will use the username/ + password provided to authenticate the user on the remote machine. If the + authentication is successful (and the user has the right to open network devices) + the RPCAP connection will continue; otherwise it will be dropped. + + This value has to be used within the 'type' member of the pcap_rmtauth structure. +*/ +#define RPCAP_RMTAUTH_PWD 1 + +/*! + \} +*/ + + + + +/*! + + \brief This structure keeps the information needed to autheticate + the user on a remote machine. + + The remote machine can either grant or refuse the access according + to the information provided. + In case the NULL authentication is required, both 'username' and + 'password' can be NULL pointers. + + This structure is meaningless if the source is not a remote interface; + in that case, the functions which requires such a structure can accept + a NULL pointer as well. +*/ +struct pcap_rmtauth +{ + /*! + \brief Type of the authentication required. + + In order to provide maximum flexibility, we can support different types + of authentication based on the value of this 'type' variable. The currently + supported authentication methods are defined into the + \link remote_auth_methods Remote Authentication Methods Section\endlink. + + */ + int type; + /*! + \brief Zero-terminated string containing the username that has to be + used on the remote machine for authentication. + + This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + and it can be NULL. + */ + char *username; + /*! + \brief Zero-terminated string containing the password that has to be + used on the remote machine for authentication. + + This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + and it can be NULL. + */ + char *password; +}; + + +/*! + \brief This structure defines the information related to sampling. + + In case the sampling is requested, the capturing device should read + only a subset of the packets coming from the source. The returned packets depend + on the sampling parameters. + + \warning The sampling process is applied after the filtering process. + In other words, packets are filtered first, then the sampling process selects a + subset of the 'filtered' packets and it returns them to the caller. +*/ +struct pcap_samp +{ + /*! + Method used for sampling. Currently, the supported methods are listed in the + \link remote_samp_methods Sampling Methods Section\endlink. + */ + int method; + + /*! + This value depends on the sampling method defined. For its meaning, please check + at the \link remote_samp_methods Sampling Methods Section\endlink. + */ + int value; +}; + + + + +//! Maximum lenght of an host name (needed for the RPCAP active mode) +#define RPCAP_HOSTLIST_SIZE 1024 + + +/*! + \} +*/ // end of public documentation + + +// Exported functions + + + +/** \name New WinPcap functions + + This section lists the new functions that are able to help considerably in writing + WinPcap programs because of their easiness of use. + */ +//\{ +pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf); +int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf); +int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf); +int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf); +struct pcap_samp *pcap_setsampling(pcap_t *p); + +//\} +// End of new winpcap functions + + + +/** \name Remote Capture functions + */ +//\{ +SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf); +int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf); +int pcap_remoteact_close(const char *host, char *errbuf); +void pcap_remoteact_cleanup(); +//\} +// End of remote capture functions + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/wpcap.lib b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/WinPCap/wpcap.lib new file mode 100644 index 0000000000000000000000000000000000000000..f832e0445b5c7dafe5a0f887262064265ba2b293 GIT binary patch literal 19320 zcmdU0O>9(05-uRW4k3h)gbS|j4}Uz#t>t&Y%Y)S%rl;4JTp5pCTuoh zr6{Lp73IKQa^QrbD7U>tdx#=VoK`4`_7Fwch+_^p| zS6BDfKh<5`)$NUA`Fde~ylZ#2`x_V>8Oe?2azi67zdwrRhWbZ!@NyRb{1af)Ai(As zfGr;YjQ*f$?=%3>0gMxkW0+_MhKYuM)O4~3fN1X*n)>bm5FNa!=@dc`jeVwR->(2f zr@qm2dK`f0IF?CtuvgRRPmzx_yk67JDF8*E;}+y2(SaM92H(eeAPs$`X>=9#JJEGb+ptfFdaw>e+iq*x`Yiy_8LSsk zPhHb?lqKrHekD4vPE+rP*gr_)Sa+hqpEMo(8T%RO(3GZ$?*SB*@r$$_@rd?+t!Zo@ zjvvxV99NR-y@~cP&F-(99u}FD=x9fbs_AYW3=3tr%W|L_8r?37d|TiVLY~ zEvy9P(zP&>67jfHb#AU)syKqo60(JIwPA#!ut>cUHY?T2Y`I#v8X-CyA=yYsIvgR1 z{ec~7x`z7J_EoXesO6i5`6%5+g-kun7o&6?6lsXL*a+*hi*s{fJrauXgmly&fhf^s z3E4_`-3*NminK;E-)tB(9ge34;dLpXqEaSo&XvkdS!WX$Qnj#NubO6=h)8cV>r%o- zg$#}#%0zWB5s_Y~F4Rh8)(8_zN(7avo*HT-qioC+@^ketEL4l8NE;P0#e6f5+G>={ zMukkHlCL%9t7a5zRLGPXLF4Uwtri*$kqjZXkpEM)9$X9SjZ(D|bw-RQrAw8hw96CH zIB?un6^x}-su3UwQbeQ|7jfC3NgauZcw9Wn7pTvr=@psX2-v zPKxSZ5_y=PnoE_N$P;l>b2RJuN@JnKx{58)m9q&VA1x?B*qjgRVZ~&L@q{!@+G|$O zMuiOZZ>iF(7OFMdSjiHy%7zr}qAKD-YOYi%Vt=CNK_NilssaMOp#PS~G0a z3#jr@2fHjGTg%rQuBgKil48`YO^Y*yd_7#KHp6_O8RQFvux8Xd$xh8vE;W)lG&5CR zE{YZ+xiZSMFke|T8koY@IHd|2`Ept5435N=dVT?dRHmqxp2NoQb4*B>?S@fVJ*ax; z#(FH|ab7p_3pF&AS9m=V93eT2qkmOwwM1MS~zh^OYj+6w(qzK0R@x9xxG+j`OQ@O)YAwXd4wWGVhD0>`FwwU%QhSy`Bsht3yBaP(% ze(43MpxoU(=zYOFA0d4{0I&g1$&>iKwHu(>kDdVhcHwsomUZU@z?X;clzbTAW2BWw z0NzC^?gw}e%b&*d8(7cxv5c>V09Ik$uOp3b!!mjRZsYgctytC>fI7y0LnY-36{Zf7=>XNfjzJf#$Z1jgA3T1 zPr!??4yIuo*25%B!C6=dn_&}df!E4q}7h2Vp-SXex#;FLwXebxMB`=5C9I^9PV8s(AynihM(q47Hlj}F34Yx5 z5?lA>X`GVyBqM>5uRR)q`2Y)!$;$8I=7z=ffJr=%AQ6tTb`!4lnRETAExQINoiFRt&`kb6)zb#5OTk(WXF`3LzuyeV>Hxo-xE;5&wx*TA8>_O0# zmkw~5!tPVa^mwZsG2>X)OyT6P_FY#r`5rUt)woR?W2mOSw@rK-bJ`>O{@4yI%WYCPuf1kaI9X$ zNp*3w@H`qDr?aNs+&Oo2#&Hz0Why()^2D`)wqGhaX1N5xvM@q!8M4BUSkpzx4EynIBam!|lli=G+Mk}qYj1rahg&EpnNTMnkZ z6X;YS&b;BMmJ!Md!^x2hGOWz7`V;-AEPO=~#ptsfeItO|rMA!b4@pA?b9;q` zELR%xFI6w99i(bVQ6qBcEkNU%@)Gd`Z&9+L3Wy4UP

ii zt(#u7(X5F2?uWKuz$0Zt8OJO)7!6qr;{`-mW-ub#&;iOoI?D5ivfQBP z?YRYMzrS+nDC-bqg+bw+zXjsZL+Gm53p&N2Dhi z$sPL*kF_J!=aoO!_oo5a`Wl^G6SWCz8X~fDnjyWbFWEo#2>_LrfpY(yof(M2GuM&^&tn45RTGq64I1es%5IBD_q*{iK;u2FYa$7I6mN$G=TOG^=4LlDoZVf8Mpw z8`>v5@1R6iH=VS|vlhSLVkx(ih2l^~-N<=b^b_Mk`m)-zIUnA+Dq&#M2jgMyAnZo(4AD0*qp9b5G`pq6hCIM%0W!8nw$ z=X{p)l{75!sW3?UZSYVll0YzKHbPhY;~;29sU1>;c0zRY>-XSai;ZdbYZCG=to zq}NeHHZoF*W4Z&(oJadNNlfy2cY@QRZM55d-N8}r^iGgGy0KXzv2)UbaVVp147WIa zljmv+W4U(#jA6SoBbv{mY-KcYyI`T(Ull#QxQ(&o#f1gqP{wxoR*xQmS-4#qq68LyTjtHxo|KwtJB;6=J(Y@(tt?ceEx_3CTXEKlvOJ{NFy#1JrL^z$>YNrb&<@)H8*An#mck^5f7vwn&$@= zl0z9sY}m8Q7*9o{hYgHkLs{`!j2wCD52oO$CleN~{Wa0!-I!oJ@fxE8EMH$9a z4-3eltbOUxmcuD{<_QVov_E zH5QOV8As7)wU0Y^#`|rDZ3!!<#~Pe)(9AO+ZjXh{+AKB$jT}9S zHBXm1z-lq?X#aRxVyQ<_9pHHO31=jZeQssJ+SYsD$#znrB{r%InpH16?K&%w>>DwL zSc1lTMr+DJqo>Fgh(lRh<ClhvL%JxCqKEC=kR{Bh7JE3l N*?W_a?2Af)@;}RMSJ?mn literal 0 HcmV?d00001 diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/atomic.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/atomic.h new file mode 100644 index 000000000..565c28037 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/atomic.h @@ -0,0 +1,547 @@ +/* + * FreeRTOS Kernel V10.2.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/** + * @file atomic.h + * @brief FreeRTOS atomic operation support. + * + * Two implementations of atomic are given in this header file: + * 1. Disabling interrupt globally. + * 2. ISA native atomic support. + * The former is available to all ports (compiler-architecture combination), + * while the latter is only available to ports compiling with GCC (version at + * least 4.7.0), which also have ISA atomic support. + * + * User can select which implementation to use by: + * setting/clearing configUSE_ATOMIC_INSTRUCTION in FreeRTOSConfig.h. + * Define AND set configUSE_ATOMIC_INSTRUCTION to 1 for ISA native atomic support. + * Undefine OR clear configUSE_ATOMIC_INSTRUCTION for disabling global interrupt + * implementation. + * + * @see GCC Built-in Functions for Memory Model Aware Atomic Operations + * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html + */ + +#ifndef ATOMIC_H +#define ATOMIC_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include atomic.h" +#endif + +/* Standard includes. */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + /* Needed for __atomic_compare_exchange() weak=false. */ + #include + + /* This branch is for GCC compiler and GCC compiler only. */ + #ifndef portFORCE_INLINE + #define portFORCE_INLINE inline __attribute__((always_inline)) + #endif + +#else + + /* Port specific definitions -- entering/exiting critical section. + * Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h + * + * Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with + * ATOMIC_ENTER_CRITICAL(). + */ + #if defined( portSET_INTERRUPT_MASK_FROM_ISR ) + + /* Nested interrupt scheme is supported in this port. */ + #define ATOMIC_ENTER_CRITICAL() \ + UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR() + + #define ATOMIC_EXIT_CRITICAL() \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType ) + + #else + + /* Nested interrupt scheme is NOT supported in this port. */ + #define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL() + #define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL() + + #endif /* portSET_INTERRUPT_MASK_FROM_ISR() */ + + /* Port specific definition -- "always inline". + * Inline is compiler specific, and may not always get inlined depending on your optimization level. + * For atomic operations, inline is considered a performance optimization. + * Thus, if portFORCE_INLINE is not provided by portmacro.h, instead of resulting error, + * simply define it. + */ + #ifndef portFORCE_INLINE + #define portFORCE_INLINE + #endif + +#endif /* configUSE_GCC_BUILTIN_ATOMICS */ + +#define ATOMIC_COMPARE_AND_SWAP_SUCCESS 0x1U /**< Compare and swap succeeded, swapped. */ +#define ATOMIC_COMPARE_AND_SWAP_FAILURE 0x0U /**< Compare and swap failed, did not swap. */ + +/*----------------------------- Swap && CAS ------------------------------*/ + +/** + * Atomic compare-and-swap + * + * @brief Performs an atomic compare-and-swap operation on the specified values. + * + * @param[in, out] pDestination Pointer to memory location from where value is + * to be loaded and checked. + * @param[in] ulExchange If condition meets, write this value to memory. + * @param[in] ulComparand Swap condition. + * + * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. + * + * @note This function only swaps *pDestination with ulExchange, if previous + * *pDestination value equals ulComparand. + */ +static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32( + uint32_t volatile * pDestination, + uint32_t ulExchange, + uint32_t ulComparand ) +{ + + uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + if ( __atomic_compare_exchange( pDestination, + &ulComparand, + &ulExchange, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST ) ) + { + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + +#else + + ATOMIC_ENTER_CRITICAL(); + + if ( *pDestination == ulComparand ) + { + *pDestination = ulExchange; + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return ulReturnValue; + +} + +/** + * Atomic swap (pointers) + * + * @brief Atomically sets the address pointed to by *ppDestination to the value + * of *pExchange. + * + * @param[in, out] ppDestination Pointer to memory location from where a pointer + * value is to be loaded and written back to. + * @param[in] pExchange Pointer value to be written to *ppDestination. + * + * @return The initial value of *ppDestination. + */ +static portFORCE_INLINE void * Atomic_SwapPointers_p32( + void * volatile * ppDestination, + void * pExchange ) +{ + void * pReturnValue; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + __atomic_exchange( ppDestination, &pExchange, &pReturnValue, __ATOMIC_SEQ_CST ); + +#else + + ATOMIC_ENTER_CRITICAL(); + + pReturnValue = *ppDestination; + + *ppDestination = pExchange; + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return pReturnValue; +} + +/** + * Atomic compare-and-swap (pointers) + * + * @brief Performs an atomic compare-and-swap operation on the specified pointer + * values. + * + * @param[in, out] ppDestination Pointer to memory location from where a pointer + * value is to be loaded and checked. + * @param[in] pExchange If condition meets, write this value to memory. + * @param[in] pComparand Swap condition. + * + * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. + * + * @note This function only swaps *ppDestination with pExchange, if previous + * *ppDestination value equals pComparand. + */ +static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32( + void * volatile * ppDestination, + void * pExchange, void * pComparand ) +{ + uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + if ( __atomic_compare_exchange( ppDestination, + &pComparand, + &pExchange, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST ) ) + { + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + +#else + + ATOMIC_ENTER_CRITICAL(); + + if ( *ppDestination == pComparand ) + { + *ppDestination = pExchange; + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return ulReturnValue; +} + + +/*----------------------------- Arithmetic ------------------------------*/ + +/** + * Atomic add + * + * @brief Atomically adds count to the value of the specified pointer points to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * @param[in] ulCount Value to be added to *pAddend. + * + * @return previous *pAddend value. + */ +static portFORCE_INLINE uint32_t Atomic_Add_u32( + uint32_t volatile * pAddend, + uint32_t ulCount ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_add(pAddend, ulCount, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend += ulCount; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic subtract + * + * @brief Atomically subtracts count from the value of the specified pointer + * pointers to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * @param[in] ulCount Value to be subtract from *pAddend. + * + * @return previous *pAddend value. + */ +static portFORCE_INLINE uint32_t Atomic_Subtract_u32( + uint32_t volatile * pAddend, + uint32_t ulCount ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_sub(pAddend, ulCount, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend -= ulCount; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic increment + * + * @brief Atomically increments the value of the specified pointer points to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * + * @return *pAddend value before increment. + */ +static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pAddend ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_add(pAddend, 1, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend += 1; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic decrement + * + * @brief Atomically decrements the value of the specified pointer points to + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * + * @return *pAddend value before decrement. + */ +static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pAddend ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_sub(pAddend, 1, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend -= 1; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/*----------------------------- Bitwise Logical ------------------------------*/ + +/** + * Atomic OR + * + * @brief Performs an atomic OR operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be ORed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_OR_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_or(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination |= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic AND + * + * @brief Performs an atomic AND operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be ANDed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_AND_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_and(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination &= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic NAND + * + * @brief Performs an atomic NAND operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be NANDed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_NAND_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_nand(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination = ~(ulCurrent & ulValue); + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic XOR + * + * @brief Performs an atomic XOR operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be XORed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_XOR_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_xor(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination ^= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif /* ATOMIC_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/demo_logging.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/demo_logging.c new file mode 100644 index 000000000..e22e91093 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/demo_logging.c @@ -0,0 +1,527 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * Logging utility that allows FreeRTOS tasks to log to a UDP port, stdout, and + * disk file without making any Win32 system calls themselves. + * + * Messages logged to a UDP port are sent directly (using FreeRTOS+TCP), but as + * FreeRTOS tasks cannot make Win32 system calls messages sent to stdout or a + * disk file are sent via a stream buffer to a Win32 thread which then performs + * the actual output. + */ + +/* Standard includes. */ +#include +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_Stream_Buffer.h" + +/* Demo includes. */ +#include "demo_logging.h" + +/*-----------------------------------------------------------*/ + +/* The maximum size to which the log file may grow, before being renamed +to .ful. */ +#define dlLOGGING_FILE_SIZE ( 40ul * 1024ul * 1024ul ) + +/* Dimensions the arrays into which print messages are created. */ +#define dlMAX_PRINT_STRING_LENGTH 255 + +/* The size of the stream buffer used to pass messages from FreeRTOS tasks to +the Win32 thread that is responsible for making any Win32 system calls that are +necessary for the selected logging method. */ +#define dlLOGGING_STREAM_BUFFER_SIZE 32768 + +/* A block time of zero simply means don't block. */ +#define dlDONT_BLOCK 0 + +/*-----------------------------------------------------------*/ + +/* + * Called from vLoggingInit() to start a new disk log file. + */ +static void prvFileLoggingInit( void ); + +/* + * Attempt to write a message to the file. + */ +static void prvLogToFile( const char *pcMessage, size_t xLength ); + +/* + * Simply close the logging file, if it is open. + */ +static void prvFileClose( void ); + +/* + * Before the scheduler is started this function is called directly. After the + * scheduler has started it is called from the Windows thread dedicated to + * outputting log messages. Only the windows thread actually performs the + * writing so as not to disrupt the simulation by making Windows system calls + * from FreeRTOS tasks. + */ +static void prvLoggingFlushBuffer( void ); + +/* + * The windows thread that performs the actual writing of messages that require + * Win32 system calls. Only the windows thread can make system calls so as not + * to disrupt the simulation by making Windows calls from FreeRTOS tasks. + */ +static DWORD WINAPI prvWin32LoggingThread( void *pvParam ); + +/* + * Creates the socket to which UDP messages are sent. This function is not + * called directly to prevent the print socket being created from within the IP + * task - which could result in a deadlock. Instead the function call is + * deferred to run in the RTOS daemon task - hence it prototype. + */ +static void prvCreatePrintSocket( void *pvParameter1, uint32_t ulParameter2 ); + +/*-----------------------------------------------------------*/ + +/* Windows event used to wake the Win32 thread which performs any logging that +needs Win32 system calls. */ +static void *pvLoggingThreadEvent = NULL; + +/* Stores the selected logging targets passed in as parameters to the +vLoggingInit() function. */ +BaseType_t xStdoutLoggingUsed = pdFALSE, xDiskFileLoggingUsed = pdFALSE, xUDPLoggingUsed = pdFALSE; + +/* Circular buffer used to pass messages from the FreeRTOS tasks to the Win32 +thread that is responsible for making Win32 calls (when stdout or a disk log is +used). */ +static StreamBuffer_t *xLogStreamBuffer = NULL; + +/* Handle to the file used for logging. This is left open while there are +messages waiting to be logged, then closed again in between logs. */ +static FILE *pxLoggingFileHandle = NULL; + +/* When true prints are performed directly. After start up xDirectPrint is set +to pdFALSE - at which time prints that require Win32 system calls are done by +the Win32 thread responsible for logging. */ +BaseType_t xDirectPrint = pdTRUE; + +/* File names for the in use and complete (full) log files. */ +static const char *pcLogFileName = "RTOSDemo.log"; +static const char *pcFullLogFileName = "RTOSDemo.ful"; + +/* As an optimization, the current file size is kept in a variable. */ +static size_t ulSizeOfLoggingFile = 0ul; + +/* The UDP socket and address on/to which print messages are sent. */ +Socket_t xPrintSocket = FREERTOS_INVALID_SOCKET; +struct freertos_sockaddr xPrintUDPAddress; + +/*-----------------------------------------------------------*/ + +void vLoggingInit( BaseType_t xLogToStdout, BaseType_t xLogToFile, BaseType_t xLogToUDP, uint32_t ulRemoteIPAddress, uint16_t usRemotePort ) +{ + /* Can only be called before the scheduler has started. */ + configASSERT( xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED ); + + #if( ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) ) + { + HANDLE Win32Thread; + + /* Record which output methods are to be used. */ + xStdoutLoggingUsed = xLogToStdout; + xDiskFileLoggingUsed = xLogToFile; + xUDPLoggingUsed = xLogToUDP; + + /* If a disk file is used then initialize it now. */ + if( xDiskFileLoggingUsed != pdFALSE ) + { + prvFileLoggingInit(); + } + + /* If UDP logging is used then store the address to which the log data + will be sent - but don't create the socket yet because the network is + not initialized. */ + if( xUDPLoggingUsed != pdFALSE ) + { + /* Set the address to which the print messages are sent. */ + xPrintUDPAddress.sin_port = FreeRTOS_htons( usRemotePort ); + xPrintUDPAddress.sin_addr = ulRemoteIPAddress; + } + + /* If a disk file or stdout are to be used then Win32 system calls will + have to be made. Such system calls cannot be made from FreeRTOS tasks + so create a stream buffer to pass the messages to a Win32 thread, then + create the thread itself, along with a Win32 event that can be used to + unblock the thread. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) ) + { + /* Create the buffer. */ + xLogStreamBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) + dlLOGGING_STREAM_BUFFER_SIZE + 1 ); + configASSERT( xLogStreamBuffer ); + memset( xLogStreamBuffer, '\0', sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) ); + xLogStreamBuffer->LENGTH = dlLOGGING_STREAM_BUFFER_SIZE + 1; + + /* Create the Windows event. */ + pvLoggingThreadEvent = CreateEvent( NULL, FALSE, TRUE, "StdoutLoggingEvent" ); + + /* Create the thread itself. */ + Win32Thread = CreateThread( + NULL, /* Pointer to thread security attributes. */ + 0, /* Initial thread stack size, in bytes. */ + prvWin32LoggingThread, /* Pointer to thread function. */ + NULL, /* Argument for new thread. */ + 0, /* Creation flags. */ + NULL ); + + /* Use the cores that are not used by the FreeRTOS tasks. */ + SetThreadAffinityMask( Win32Thread, ~0x01u ); + SetThreadPriorityBoost( Win32Thread, TRUE ); + SetThreadPriority( Win32Thread, THREAD_PRIORITY_IDLE ); + } + } + #else + { + /* FreeRTOSIPConfig is set such that no print messages will be output. + Avoid compiler warnings about unused parameters. */ + ( void ) xLogToStdout; + ( void ) xLogToFile; + ( void ) xLogToUDP; + ( void ) usRemotePort; + ( void ) ulRemoteIPAddress; + } + #endif /* ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) */ +} +/*-----------------------------------------------------------*/ + +static void prvCreatePrintSocket( void *pvParameter1, uint32_t ulParameter2 ) +{ +static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 0 ); +Socket_t xSocket; + + /* The function prototype is that of a deferred function, but the parameters + are not actually used. */ + ( void ) pvParameter1; + ( void ) ulParameter2; + + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + + if( xSocket != FREERTOS_INVALID_SOCKET ) + { + /* FreeRTOS+TCP decides which port to bind to. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + FreeRTOS_bind( xSocket, NULL, 0 ); + + /* Now the socket is bound it can be assigned to the print socket. */ + xPrintSocket = xSocket; + } +} +/*-----------------------------------------------------------*/ + +void vLoggingPrintf( const char *pcFormat, ... ) +{ +char cPrintString[ dlMAX_PRINT_STRING_LENGTH ]; +char cOutputString[ dlMAX_PRINT_STRING_LENGTH ]; +char *pcSource, *pcTarget, *pcBegin; +size_t xLength, xLength2, rc; +static BaseType_t xMessageNumber = 0; +va_list args; +uint32_t ulIPAddress; +const char *pcTaskName; +const char *pcNoTask = "None"; +int iOriginalPriority; +HANDLE xCurrentTask; + + + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) || ( xUDPLoggingUsed != pdFALSE ) ) + { + /* There are a variable number of parameters. */ + va_start( args, pcFormat ); + + /* Additional info to place at the start of the log. */ + if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED ) + { + pcTaskName = pcTaskGetName( NULL ); + } + else + { + pcTaskName = pcNoTask; + } + + if( strcmp( pcFormat, "\n" ) != 0 ) + { + xLength = snprintf( cPrintString, dlMAX_PRINT_STRING_LENGTH, "%lu %lu [%s] ", + xMessageNumber++, + ( unsigned long ) xTaskGetTickCount(), + pcTaskName ); + } + else + { + xLength = 0; + memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH ); + } + + xLength2 = vsnprintf( cPrintString + xLength, dlMAX_PRINT_STRING_LENGTH - xLength, pcFormat, args ); + + if( xLength2 < 0 ) + { + /* Clean up. */ + xLength2 = dlMAX_PRINT_STRING_LENGTH - 1 - xLength; + cPrintString[ dlMAX_PRINT_STRING_LENGTH - 1 ] = '\0'; + } + + xLength += xLength2; + va_end( args ); + + /* For ease of viewing, copy the string into another buffer, converting + IP addresses to dot notation on the way. */ + pcSource = cPrintString; + pcTarget = cOutputString; + + while( ( *pcSource ) != '\0' ) + { + *pcTarget = *pcSource; + pcTarget++; + pcSource++; + + /* Look forward for an IP address denoted by 'ip'. */ + if( ( isxdigit( pcSource[ 0 ] ) != pdFALSE ) && ( pcSource[ 1 ] == 'i' ) && ( pcSource[ 2 ] == 'p' ) ) + { + *pcTarget = *pcSource; + pcTarget++; + *pcTarget = '\0'; + pcBegin = pcTarget - 8; + + while( ( pcTarget > pcBegin ) && ( isxdigit( pcTarget[ -1 ] ) != pdFALSE ) ) + { + pcTarget--; + } + + sscanf( pcTarget, "%8X", &ulIPAddress ); + rc = sprintf( pcTarget, "%lu.%lu.%lu.%lu", + ( unsigned long ) ( ulIPAddress >> 24UL ), + ( unsigned long ) ( (ulIPAddress >> 16UL) & 0xffUL ), + ( unsigned long ) ( (ulIPAddress >> 8UL) & 0xffUL ), + ( unsigned long ) ( ulIPAddress & 0xffUL ) ); + pcTarget += rc; + pcSource += 3; /* skip "ip" */ + } + } + + /* How far through the buffer was written? */ + xLength = ( BaseType_t ) ( pcTarget - cOutputString ); + + /* If the message is to be logged to a UDP port then it can be sent directly + because it only uses FreeRTOS function (not Win32 functions). */ + if( xUDPLoggingUsed != pdFALSE ) + { + if( ( xPrintSocket == FREERTOS_INVALID_SOCKET ) && ( FreeRTOS_IsNetworkUp() != pdFALSE ) ) + { + /* Create and bind the socket to which print messages are sent. The + xTimerPendFunctionCall() function is used even though this is + not an interrupt because this function is called from the IP task + and the IP task cannot itself wait for a socket to bind. The + parameters to prvCreatePrintSocket() are not required so set to + NULL or 0. */ + xTimerPendFunctionCall( prvCreatePrintSocket, NULL, 0, dlDONT_BLOCK ); + } + + if( xPrintSocket != FREERTOS_INVALID_SOCKET ) + { + FreeRTOS_sendto( xPrintSocket, cOutputString, xLength, 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) ); + + /* Just because the UDP data logger I'm using is dumb. */ + FreeRTOS_sendto( xPrintSocket, "\r", sizeof( char ), 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) ); + } + } + + /* If logging is also to go to either stdout or a disk file then it cannot + be output here - so instead write the message to the stream buffer and wake + the Win32 thread which will read it from the stream buffer and perform the + actual output. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) ) + { + configASSERT( xLogStreamBuffer ); + + /* How much space is in the buffer? */ + xLength2 = uxStreamBufferGetSpace( xLogStreamBuffer ); + + /* There must be enough space to write both the string and the length of + the string. */ + if( xLength2 >= ( xLength + sizeof( xLength ) ) ) + { + /* First write in the length of the data, then write in the data + itself. Raising the thread priority is used as a critical section + as there are potentially multiple writers. The stream buffer is + only thread safe when there is a single writer (likewise for + reading from the buffer). */ + xCurrentTask = GetCurrentThread(); + iOriginalPriority = GetThreadPriority( xCurrentTask ); + SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ); + uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) &( xLength ), sizeof( xLength ) ); + uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) cOutputString, xLength ); + SetThreadPriority( GetCurrentThread(), iOriginalPriority ); + } + + /* xDirectPrint is initialized to pdTRUE, and while it remains true the + logging output function is called directly. When the system is running + the output function cannot be called directly because it would get + called from both FreeRTOS tasks and Win32 threads - so instead wake the + Win32 thread responsible for the actual output. */ + if( xDirectPrint != pdFALSE ) + { + /* While starting up, the thread which calls prvWin32LoggingThread() + is not running yet and xDirectPrint will be pdTRUE. */ + prvLoggingFlushBuffer(); + } + else if( pvLoggingThreadEvent != NULL ) + { + /* While running, wake up prvWin32LoggingThread() to send the + logging data. */ + SetEvent( pvLoggingThreadEvent ); + } + } + } +} +/*-----------------------------------------------------------*/ + +static void prvLoggingFlushBuffer( void ) +{ +size_t xLength; +char cPrintString[ dlMAX_PRINT_STRING_LENGTH ]; + + /* Is there more than the length value stored in the circular buffer + used to pass data from the FreeRTOS simulator into this Win32 thread? */ + while( uxStreamBufferGetSize( xLogStreamBuffer ) > sizeof( xLength ) ) + { + memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH ); + uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE ); + uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) cPrintString, xLength, pdFALSE ); + + /* Write the message to standard out if requested to do so when + vLoggingInit() was called, or if the network is not yet up. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( FreeRTOS_IsNetworkUp() == pdFALSE ) ) + { + /* Write the message to stdout. */ + printf( "%s", cPrintString ); /*_RB_ Replace with _write(). */ + fflush( stdout ); + } + + /* Write the message to a file if requested to do so when + vLoggingInit() was called. */ + if( xDiskFileLoggingUsed != pdFALSE ) + { + prvLogToFile( cPrintString, xLength ); + } + } + + prvFileClose(); +} +/*-----------------------------------------------------------*/ + +static DWORD WINAPI prvWin32LoggingThread( void *pvParameter ) +{ +const DWORD xMaxWait = 1000; + + ( void ) pvParameter; + + /* From now on, prvLoggingFlushBuffer() will only be called from this + Windows thread */ + xDirectPrint = pdFALSE; + + for( ;; ) + { + /* Wait to be told there are message waiting to be logged. */ + WaitForSingleObject( pvLoggingThreadEvent, xMaxWait ); + + /* Write out all waiting messages. */ + prvLoggingFlushBuffer(); + } +} +/*-----------------------------------------------------------*/ + +static void prvFileLoggingInit( void ) +{ +FILE *pxHandle = fopen( pcLogFileName, "a" ); + + if( pxHandle != NULL ) + { + fseek( pxHandle, SEEK_END, 0ul ); + ulSizeOfLoggingFile = ftell( pxHandle ); + fclose( pxHandle ); + } + else + { + ulSizeOfLoggingFile = 0ul; + } +} +/*-----------------------------------------------------------*/ + +static void prvFileClose( void ) +{ + if( pxLoggingFileHandle != NULL ) + { + fclose( pxLoggingFileHandle ); + pxLoggingFileHandle = NULL; + } +} +/*-----------------------------------------------------------*/ + +static void prvLogToFile( const char *pcMessage, size_t xLength ) +{ + if( pxLoggingFileHandle == NULL ) + { + pxLoggingFileHandle = fopen( pcLogFileName, "a" ); + } + + if( pxLoggingFileHandle != NULL ) + { + fwrite( pcMessage, 1, xLength, pxLoggingFileHandle ); + ulSizeOfLoggingFile += xLength; + + /* If the file has grown to its maximum permissible size then close and + rename it - then start with a new file. */ + if( ulSizeOfLoggingFile > ( size_t ) dlLOGGING_FILE_SIZE ) + { + prvFileClose(); + if( _access( pcFullLogFileName, 00 ) == 0 ) + { + remove( pcFullLogFileName ); + } + rename( pcLogFileName, pcFullLogFileName ); + ulSizeOfLoggingFile = 0; + } + } +} +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/demo_logging.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/demo_logging.h new file mode 100644 index 000000000..197b21684 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/demo_logging.h @@ -0,0 +1,48 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef DEMO_LOGGING_H +#define DEMO_LOGGING_H + +/* + * Initialize a logging system that can be used from FreeRTOS tasks and Win32 + * threads. Do not call printf() directly while the scheduler is running. + * + * Set xLogToStdout, xLogToFile and xLogToUDP to either pdTRUE or pdFALSE to + * lot to stdout, a disk file and a UDP port respectively. + * + * If xLogToUDP is pdTRUE then ulRemoteIPAddress and usRemotePort must be set + * to the IP address and port number to which UDP log messages will be sent. + */ +void vLoggingInit( BaseType_t xLogToStdout, + BaseType_t xLogToFile, + BaseType_t xLogToUDP, + uint32_t ulRemoteIPAddress, + uint16_t usRemotePort ); + +#endif /* DEMO_LOGGING_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/main.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/main.c new file mode 100644 index 000000000..3c531b6d9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/main.c @@ -0,0 +1,369 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/*** + * See https://www.FreeRTOS.org/mqtt/index.html for configuration and usage instructions. + ***/ + +/* Standard includes. */ +#include +#include + +/* Visual studio intrinsics used so the __debugbreak() function is available +should an assert get hit. */ +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" + +/* TCP/IP stack includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Demo app includes. */ +#include "demo_logging.h" + +/* + * Prototypes for the demos that can be started from this project. Note the + * MQTT demo is not actually started until the network is already, which is + * indicated by vApplicationIPNetworkEventHook() executing - hence + * prvStartSimpleMQTTDemo() is called from inside vApplicationIPNetworkEventHook(). + */ +extern void vStartSimpleMQTTDemo( void ); + +/* + * Task for Light Weight MQTT Serializer API Proof of Concept. + * To run the proof of concept instead of the demo replace + * vStartSimpleMQTTDemo() with vApplicationIPNetworkEventHook() + * in function vApplicationIPNetworkEventHook(). + */ +extern void vStartLightWeightMQTTDemo( void ); + +/* + * Just seeds the simple pseudo random number generator. + * + * !!! NOTE !!! + * This is not a secure method of generating random numbers and production + * devices should use a true random number generator (TRNG). + */ +static void prvSRand( UBaseType_t ulSeed ); + +/* + * Miscellaneous initialization including preparing the logging and seeding the + * random number generator. + */ +static void prvMiscInitialisation( void ); + +/* The default IP and MAC address used by the demo. The address configuration +defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is +1 but a DHCP server could not be contacted. See the online documentation for +more information. */ +static const uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 }; +static const uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 }; +static const uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 }; +static const uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 }; + +/* Set the following constant to pdTRUE to log using the method indicated by the +name of the constant, or pdFALSE to not log using the method indicated by the +name of the constant. Options include to standard out (xLogToStdout), to a disk +file (xLogToFile), and to a UDP port (xLogToUDP). If xLogToUDP is set to pdTRUE +then UDP messages are sent to the IP address configured as the echo server +address (see the configECHO_SERVER_ADDR0 definitions in FreeRTOSConfig.h) and +the port number set by configPRINT_PORT in FreeRTOSConfig.h. */ +const BaseType_t xLogToStdout = pdTRUE, xLogToFile = pdFALSE, xLogToUDP = pdFALSE; + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition for information on how to configure +the real network connection to use. */ +const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 }; + +/* Use by the pseudo random number generator. */ +static UBaseType_t ulNextRand; +/*-----------------------------------------------------------*/ + +int main( void ) +{ + /*** + * See https://www.FreeRTOS.org/mqtt/index.html for configuration and usage instructions. + ***/ + + /* Miscellaneous initialization including preparing the logging and seeding + the random number generator. */ + prvMiscInitialisation(); + + /* Initialize the network interface. + + ***NOTE*** Tasks that use the network are created in the network event hook + when the network is connected and ready for use (see the implementation of + vApplicationIPNetworkEventHook() below). The address values passed in here + are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1 + but a DHCP server cannot be contacted. */ + FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); + + /* Start the RTOS scheduler. */ + vTaskStartScheduler(); + + /* If all is well, the scheduler will now be running, and the following + line will never be reached. If the following line does execute, then + there was insufficient FreeRTOS heap memory available for the idle and/or + timer tasks to be created. See the memory management section on the + FreeRTOS web site for more details (this is standard text that is not + really applicable to the Win32 simulator port). */ + for( ; ; ) + { + __debugbreak(); + } +} +/*-----------------------------------------------------------*/ + +/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect +events are only received if implemented in the MAC driver. */ +void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) +{ +uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress; +char cBuffer[ 16 ]; +static BaseType_t xTasksAlreadyCreated = pdFALSE; + + /* If the network has just come up...*/ + if( eNetworkEvent == eNetworkUp ) + { + /* Create the tasks that use the IP stack if they have not already been + created. */ + if( xTasksAlreadyCreated == pdFALSE ) + { + /* Demos that use the network are created after the network is + up. */ + configPRINTF( ( "---------STARTING DEMO---------\r\n" ) ); + vStartSimpleMQTTDemo(); + xTasksAlreadyCreated = pdTRUE; + } + + /* Print out the network configuration, which may have come from a DHCP + server. */ + FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress ); + FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); + FreeRTOS_printf( ( "\r\n\r\nIP Address: %s\r\n", cBuffer ) ); /*_RB_ Should use IoT libraries logging. */ + + FreeRTOS_inet_ntoa( ulNetMask, cBuffer ); + FreeRTOS_printf( ( "Subnet Mask: %s\r\n", cBuffer ) ); + + FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer ); + FreeRTOS_printf( ( "Gateway Address: %s\r\n", cBuffer ) ); + + FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer ); + FreeRTOS_printf( ( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ) ); + } +} +/*-----------------------------------------------------------*/ + +void vAssertCalled( const char *pcFile, + uint32_t ulLine ) +{ +volatile uint32_t ulBlockVariable = 0UL; +volatile char *pcFileName = ( volatile char * ) pcFile; +volatile uint32_t ulLineNumber = ulLine; + + ( void ) pcFileName; + ( void ) ulLineNumber; + + printf( "vAssertCalled( %s, %u\n", pcFile, ulLine ); + + /* Setting ulBlockVariable to a non-zero value in the debugger will allow + this function to be exited. */ + taskDISABLE_INTERRUPTS(); + { + while( ulBlockVariable == 0UL ) + { + __debugbreak(); + } + } + taskENABLE_INTERRUPTS(); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxRand( void ) +{ +const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL; + + /* + * Utility function to generate a pseudo random number. + * + * !!!NOTE!!! + * This is not a secure method of generating a random number. Production + * devices should use a True Random Number Generator (TRNG). + */ + ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement; + return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL ); +} +/*-----------------------------------------------------------*/ + +static void prvSRand( UBaseType_t ulSeed ) +{ + /* Utility function to seed the pseudo random number generator. */ + ulNextRand = ulSeed; +} +/*-----------------------------------------------------------*/ + +static void prvMiscInitialisation( void ) +{ +time_t xTimeNow; +uint32_t ulLoggingIPAddress; + + ulLoggingIPAddress = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0, configECHO_SERVER_ADDR1, configECHO_SERVER_ADDR2, configECHO_SERVER_ADDR3 ); + vLoggingInit( xLogToStdout, xLogToFile, xLogToUDP, ulLoggingIPAddress, configPRINT_PORT ); + + /* + * Seed random number generator. + * + * !!!NOTE!!! + * This is not a secure method of generating a random number. Production + * devices should use a True Random Number Generator (TRNG). + */ + time( &xTimeNow ); + FreeRTOS_debug_printf( ( "Seed for randomizer: %lu\n", xTimeNow ) ); + prvSRand( ( uint32_t ) xTimeNow ); + FreeRTOS_debug_printf( ( "Random numbers: %08X %08X %08X %08X\n", ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32() ) ); +} +/*-----------------------------------------------------------*/ + +#if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) + + const char * pcApplicationHostnameHook( void ) + { + /* Assign the name "FreeRTOS" to this network node. This function will + be called during the DHCP: the machine will be registered with an IP + address plus this name. */ + return mainHOST_NAME; + } + +#endif +/*-----------------------------------------------------------*/ + +#if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) + + BaseType_t xApplicationDNSQueryHook( const char *pcName ) + { + BaseType_t xReturn; + + /* Determine if a name lookup is for this node. Two names are given + to this node: that returned by pcApplicationHostnameHook() and that set + by mainDEVICE_NICK_NAME. */ + if( _stricmp( pcName, pcApplicationHostnameHook() ) == 0 ) + { + xReturn = pdPASS; + } + else if( _stricmp( pcName, mainDEVICE_NICK_NAME ) == 0 ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif /* if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) */ +/*-----------------------------------------------------------*/ + +/* + * Callback that provides the inputs necessary to generate a randomized TCP + * Initial Sequence Number per RFC 6528. THIS IS ONLY A DUMMY IMPLEMENTATION + * THAT RETURNS A PSEUDO RANDOM NUMBER SO IS NOT INTENDED FOR USE IN PRODUCTION + * SYSTEMS. + */ +extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress, + uint16_t usSourcePort, + uint32_t ulDestinationAddress, + uint16_t usDestinationPort ) +{ + ( void ) ulSourceAddress; + ( void ) usSourcePort; + ( void ) ulDestinationAddress; + ( void ) usDestinationPort; + + return uxRand(); +} +/*-----------------------------------------------------------*/ + +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an +implementation of vApplicationGetIdleTaskMemory() to provide the memory that is +used by the Idle task. */ +void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, + StackType_t ** ppxIdleTaskStackBuffer, + uint32_t * pulIdleTaskStackSize ) +{ + /* If the buffers to be provided to the Idle task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xIdleTaskTCB; + static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} +/*-----------------------------------------------------------*/ + +/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the +application must provide an implementation of vApplicationGetTimerTaskMemory() +to provide the memory that is used by the Timer service task. */ +void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer, + StackType_t ** ppxTimerTaskStackBuffer, + uint32_t * pulTimerTaskStackSize ) +{ + /* If the buffers to be provided to the Timer task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xTimerTaskTCB; + static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/mbedtls_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/mbedtls_config.h new file mode 100644 index 000000000..0f2861a0d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/mbedtls_config.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/* This file configures mbed TLS for FreeRTOS. */ + +#ifndef MBEDTLS_CONFIG_H_ +#define MBEDTLS_CONFIG_H_ + +/* FreeRTOS include. */ +#include "FreeRTOS.h" + +/* Generate errors if deprecated functions are used. */ +#define MBEDTLS_DEPRECATED_REMOVED + +/* Place AES tables in ROM. */ +#define MBEDTLS_AES_ROM_TABLES + +/* Enable the following cipher modes. */ +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_CIPHER_MODE_CFB +#define MBEDTLS_CIPHER_MODE_CTR + +/* Enable the following cipher padding modes. */ +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define MBEDTLS_CIPHER_PADDING_ZEROS + +/* Cipher suite configuration. */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_NIST_OPTIM +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/* Enable all SSL alert messages. */ +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES + +/* Enable the following SSL features. */ +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_SSL_ALPN +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/* Check certificate key usage. */ +#define MBEDTLS_X509_CHECK_KEY_USAGE +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/* Disable platform entropy functions. */ +#define MBEDTLS_NO_PLATFORM_ENTROPY + +/* Enable the following mbed TLS features. */ +#define MBEDTLS_AES_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECP_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_GCM_C +#define MBEDTLS_MD_C +#define MBEDTLS_OID_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA1_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_TLS_C +#define MBEDTLS_THREADING_ALT +#define MBEDTLS_THREADING_C +#define MBEDTLS_X509_USE_C +#define MBEDTLS_X509_CRT_PARSE_C + +/* Set the memory allocation functions on FreeRTOS. */ +void * mbedtls_platform_calloc( size_t nmemb, + size_t size ); +void mbedtls_platform_free( void * ptr ); +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_CALLOC_MACRO mbedtls_platform_calloc +#define MBEDTLS_PLATFORM_FREE_MACRO mbedtls_platform_free + +/* The network send and receive functions on FreeRTOS. */ +int mbedtls_platform_send( void * ctx, + const unsigned char * buf, + size_t len ); +int mbedtls_platform_recv( void * ctx, + unsigned char * buf, + size_t len ); + +/* The entropy poll function. */ +int mbedtls_platform_entropy_poll( void * data, + unsigned char * output, + size_t len, + size_t * olen ); + +#include "mbedtls/check_config.h" + +#endif /* ifndef MBEDTLS_CONFIG_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/printf-stdarg.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/printf-stdarg.c new file mode 100644 index 000000000..5505535c1 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/common/printf-stdarg.c @@ -0,0 +1,667 @@ +/* + Copyright 2001, 2002 Georges Menie (www.menie.org) + stdarg version contributed by Christian Ettinger + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Changes for the FreeRTOS ports: + + - The dot in "%-8.8s" + - The specifiers 'l' (long) and 'L' (long long) + - The specifier 'u' for unsigned + - Dot notation for IP addresses: + sprintf("IP = %xip\n", 0xC0A80164); + will produce "IP = 192.168.1.100\n" +*/ + +#include +#include +#include +#include + +#include "FreeRTOS.h" + +#define PAD_RIGHT 1 +#define PAD_ZERO 2 + +/* + * Return 1 for readable, 2 for writeable, 3 for both. + * Function must be provided by the application. + */ +extern BaseType_t xApplicationMemoryPermissions( uint32_t aAddress ); + +extern void vOutputChar( const char cChar, const TickType_t xTicksToWait ); +static const TickType_t xTicksToWait = pdMS_TO_TICKS( 20 ); + +struct xPrintFlags +{ + int base; + int width; + int printLimit; + unsigned + pad : 8, + letBase : 8, + isSigned : 1, + isNumber : 1, + long32 : 1, + long64 : 1; +}; + +struct SStringBuf +{ + char *str; + const char *orgStr; + const char *nulPos; + int curLen; + struct xPrintFlags flags; +}; + +static void strbuf_init( struct SStringBuf *apStr, char *apBuf, const char *apMaxStr ) +{ + apStr->str = apBuf; + apStr->orgStr = apBuf; + apStr->nulPos = apMaxStr-1; + apStr->curLen = 0; + + memset( &apStr->flags, '\0', sizeof( apStr->flags ) ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t strbuf_printchar( struct SStringBuf *apStr, int c ) +{ + if( apStr->str == NULL ) + { + vOutputChar( ( char ) c, xTicksToWait ); + apStr->curLen++; + return pdTRUE; + } + if( apStr->str < apStr->nulPos ) + { + *( apStr->str++ ) = c; + apStr->curLen++; + return pdTRUE; + } + if( apStr->str == apStr->nulPos ) + { + *( apStr->str++ ) = '\0'; + } + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static portINLINE BaseType_t strbuf_printchar_inline( struct SStringBuf *apStr, int c ) +{ + if( apStr->str == NULL ) + { + vOutputChar( ( char ) c, xTicksToWait ); + if( c == 0 ) + { + return pdFALSE; + } + apStr->curLen++; + return pdTRUE; + } + if( apStr->str < apStr->nulPos ) + { + *(apStr->str++) = c; + if( c == 0 ) + { + return pdFALSE; + } + apStr->curLen++; + return pdTRUE; + } + if( apStr->str == apStr->nulPos ) + { + *( apStr->str++ ) = '\0'; + } + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static portINLINE int i2hex( int aCh ) +{ +int iResult; + + if( aCh < 10 ) + { + iResult = '0' + aCh; + } + else + { + iResult = 'A' + aCh - 10; + } + + return iResult; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prints(struct SStringBuf *apBuf, const char *apString ) +{ + register int padchar = ' '; + int i,len; + + if( xApplicationMemoryPermissions( ( uint32_t )apString ) == 0 ) + { + /* The user has probably made a mistake with the parameter + for '%s', the memory is not readbale. */ + apString = "INV_MEM"; + } + + if( apBuf->flags.width > 0 ) + { + register int len = 0; + register const char *ptr; + for( ptr = apString; *ptr; ++ptr ) + { + ++len; + } + + if( len >= apBuf->flags.width ) + { + apBuf->flags.width = 0; + } + else + { + apBuf->flags.width -= len; + } + + if( apBuf->flags.pad & PAD_ZERO ) + { + padchar = '0'; + } + } + if( ( apBuf->flags.pad & PAD_RIGHT ) == 0 ) + { + for( ; apBuf->flags.width > 0; --apBuf->flags.width ) + { + if( strbuf_printchar( apBuf, padchar ) == 0 ) + { + return pdFALSE; + } + } + } + if( ( apBuf->flags.isNumber == pdTRUE ) && ( apBuf->flags.pad == pdTRUE ) ) + { + /* The string to print represents an integer number. + * In this case, printLimit is the min number of digits to print + * If the length of the number to print is less than the min nb of i + * digits to display, we add 0 before printing the number + */ + len = strlen( apString ); + + if( len < apBuf->flags.printLimit ) + { + i = apBuf->flags.printLimit - len; + for( ; i; i-- ) + { + if( strbuf_printchar( apBuf, '0' ) == 0 ) + { + return pdFALSE; + } + } + } + } + /* The string to print is not the result of a number conversion to ascii. + * For a string, printLimit is the max number of characters to display + */ + for( ; apBuf->flags.printLimit && *apString ; ++apString, --apBuf->flags.printLimit ) + { + if( !strbuf_printchar( apBuf, *apString ) ) + { + return pdFALSE; + } + } + + for( ; apBuf->flags.width > 0; --apBuf->flags.width ) + { + if( !strbuf_printchar( apBuf, padchar ) ) + { + return pdFALSE; + } + } + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +/* the following should be enough for 32 bit int */ +#define PRINT_BUF_LEN 12 /* to print 4294967296 */ + +#if SPRINTF_LONG_LONG +#warning 64-bit libraries will be included as well +static BaseType_t printll( struct SStringBuf *apBuf, long long i ) +{ + char print_buf[ 2 * PRINT_BUF_LEN ]; + register char *s; + register int t, neg = 0; + register unsigned long long u = i; + lldiv_t lldiv_result; + +/* typedef struct + * { + * long long int quot; // quotient + * long long int rem; // remainder + * } lldiv_t; + */ + + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + if( i == 0LL ) + { + print_buf[ 0 ] = '0'; + print_buf[ 1 ] = '\0'; + return prints( apBuf, print_buf ); + } + + if( ( apBuf->flags.isSigned == pdTRUE ) && ( apBuf->flags.base == 10 ) && ( i < 0LL ) ) + { + neg = 1; + u = -i; + } + + s = print_buf + sizeof( print_buf ) - 1; + + *s = '\0'; + /* 18446744073709551616 */ + while( u != 0 ) + { + lldiv_result = lldiv( u, ( unsigned long long ) apBuf->flags.base ); + t = lldiv_result.rem; + if( t >= 10 ) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u = lldiv_result.quot; + } + + if( neg != 0 ) + { + if( ( apBuf->flags.width != 0 ) && ( apBuf->flags.pad & PAD_ZERO ) ) + { + if( !strbuf_printchar( apBuf, '-' ) ) + { + return pdFALSE; + } + --apBuf->flags.width; + } + else + { + *( --s ) = '-'; + } + } + + return prints( apBuf, s ); +} +#endif /* SPRINTF_LONG_LONG */ +/*-----------------------------------------------------------*/ + +static BaseType_t printi( struct SStringBuf *apBuf, int i ) +{ + char print_buf[ PRINT_BUF_LEN ]; + register char *s; + register int t, neg = 0; + register unsigned int u = i; + register unsigned base = apBuf->flags.base; + + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + + if( i == 0 ) + { + print_buf[ 0 ] = '0'; + print_buf[ 1 ] = '\0'; + return prints( apBuf, print_buf ); + } + + if( ( apBuf->flags.isSigned == pdTRUE ) && ( base == 10 ) && ( i < 0 ) ) + { + neg = 1; + u = -i; + } + + s = print_buf + sizeof( print_buf ) - 1; + + *s = '\0'; + switch( base ) + { + case 16: + while( u != 0 ) + { + t = u & 0xF; + if( t >= 10 ) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u >>= 4; + } + break; + + case 8: + case 10: + /* GCC compiles very efficient */ + while( u ) + { + t = u % base; + *( --s ) = t + '0'; + u /= base; + } + break; +/* + // The generic case, not yet in use + default: + while( u ) + { + t = u % base; + if( t >= 10) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u /= base; + } + break; +*/ + } + + if( neg != 0 ) + { + if( apBuf->flags.width && (apBuf->flags.pad & PAD_ZERO ) ) + { + if( strbuf_printchar( apBuf, '-' ) == 0 ) + { + return pdFALSE; + } + --apBuf->flags.width; + } + else + { + *( --s ) = '-'; + } + } + + return prints( apBuf, s ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t printIp(struct SStringBuf *apBuf, unsigned i ) +{ + char print_buf[16]; + + sprintf( print_buf, "%u.%u.%u.%u", + i >> 24, + ( i >> 16 ) & 0xff, + ( i >> 8 ) & 0xff, + i & 0xff ); + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + prints( apBuf, print_buf ); + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +static void tiny_print( struct SStringBuf *apBuf, const char *format, va_list args ) +{ + char scr[2]; + + for( ; ; ) + { + int ch = *( format++ ); + + if( ch != '%' ) + { + do + { + /* Put the most like flow in a small loop */ + if( strbuf_printchar_inline( apBuf, ch ) == 0 ) + { + return; + } + ch = *( format++ ); + } while( ch != '%' ); + } + ch = *( format++ ); + /* Now ch has character after '%', format pointing to next */ + + if( ch == '\0' ) + { + break; + } + if( ch == '%' ) + { + if( strbuf_printchar( apBuf, ch ) == 0 ) + { + return; + } + continue; + } + memset( &apBuf->flags, '\0', sizeof( apBuf->flags ) ); + + if( ch == '-' ) + { + ch = *( format++ ); + apBuf->flags.pad = PAD_RIGHT; + } + while( ch == '0' ) + { + ch = *( format++ ); + apBuf->flags.pad |= PAD_ZERO; + } + if( ch == '*' ) + { + ch = *( format++ ); + apBuf->flags.width = va_arg( args, int ); + } + else + { + while( ch >= '0' && ch <= '9' ) + { + apBuf->flags.width *= 10; + apBuf->flags.width += ch - '0'; + ch = *( format++ ); + } + } + if( ch == '.' ) + { + ch = *( format++ ); + if( ch == '*' ) + { + apBuf->flags.printLimit = va_arg( args, int ); + ch = *( format++ ); + } + else + { + while( ch >= '0' && ch <= '9' ) + { + apBuf->flags.printLimit *= 10; + apBuf->flags.printLimit += ch - '0'; + ch = *( format++ ); + } + } + } + if( apBuf->flags.printLimit == 0 ) + { + apBuf->flags.printLimit--; /* -1: make it unlimited */ + } + if( ch == 's' ) + { + register char *s = ( char * )va_arg( args, int ); + if( prints( apBuf, s ? s : "(null)" ) == 0 ) + { + break; + } + continue; + } + if( ch == 'c' ) + { + /* char are converted to int then pushed on the stack */ + scr[0] = ( char ) va_arg( args, int ); + + if( strbuf_printchar( apBuf, scr[0] ) == 0 ) + { + return; + } + + continue; + } + if( ch == 'l' ) + { + ch = *( format++ ); + apBuf->flags.long32 = 1; + /* Makes not difference as u32 == long */ + } + if( ch == 'L' ) + { + ch = *( format++ ); + apBuf->flags.long64 = 1; + /* Does make a difference */ + } + apBuf->flags.base = 10; + apBuf->flags.letBase = 'a'; + + if( ch == 'd' || ch == 'u' ) + { + apBuf->flags.isSigned = ( ch == 'd' ); +#if SPRINTF_LONG_LONG + if( apBuf->flags.long64 != pdFALSE ) + { + if( printll( apBuf, va_arg( args, long long ) ) == 0 ) + { + break; + } + } else +#endif /* SPRINTF_LONG_LONG */ + if( printi( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + + apBuf->flags.base = 16; /* From here all hexadecimal */ + + if( ch == 'x' && format[0] == 'i' && format[1] == 'p' ) + { + format += 2; /* eat the "xi" of "xip" */ + /* Will use base 10 again */ + if( printIp( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + if( ch == 'x' || ch == 'X' || ch == 'p' || ch == 'o' ) + { + if( ch == 'X' ) + { + apBuf->flags.letBase = 'A'; + } + else if( ch == 'o' ) + { + apBuf->flags.base = 8; + } +#if SPRINTF_LONG_LONG + if( apBuf->flags.long64 != pdFALSE ) + { + if( printll( apBuf, va_arg( args, long long ) ) == 0 ) + { + break; + } + } else +#endif /* SPRINTF_LONG_LONG */ + if( printi( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + } + strbuf_printchar( apBuf, '\0' ); +} +/*-----------------------------------------------------------*/ + +int vsnprintf( char *apBuf, size_t aMaxLen, const char *apFmt, va_list args ) +{ + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen ); + tiny_print( &strBuf, apFmt, args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int snprintf( char *apBuf, size_t aMaxLen, const char *apFmt, ... ) +{ + va_list args; + + va_start( args, apFmt ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen ); + tiny_print( &strBuf, apFmt, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int sprintf( char *apBuf, const char *apFmt, ... ) +{ + va_list args; + + va_start( args, apFmt ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char * )apBuf + 1024 ); + tiny_print( &strBuf, apFmt, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int vsprintf( char *apBuf, const char *apFmt, va_list args ) +{ + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* ) apBuf + 1024 ); + tiny_print( &strBuf, apFmt, args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +const char *mkSize (unsigned long long aSize, char *apBuf, int aLen) +{ +static char retString[33]; +size_t gb, mb, kb, sb; + + if (apBuf == NULL) { + apBuf = retString; + aLen = sizeof( retString ); + } + gb = aSize / (1024*1024*1024); + aSize -= gb * (1024*1024*1024); + mb = aSize / (1024*1024); + aSize -= mb * (1024*1024); + kb = aSize / (1024); + aSize -= kb * (1024); + sb = aSize; + if( gb ) + { + snprintf (apBuf, aLen, "%u.%02u GB", ( unsigned ) gb, ( unsigned ) ( ( 100 * mb ) / 1024ul ) ); + } + else if( mb ) + { + snprintf (apBuf, aLen, "%u.%02u MB", ( unsigned ) mb, ( unsigned ) ( ( 100 * kb) / 1024ul ) ); + } + else if( kb != 0ul ) + { + snprintf (apBuf, aLen, "%u.%02u KB", ( unsigned ) kb, ( unsigned ) ( ( 100 * sb) / 1024ul ) ); + } + else + { + snprintf (apBuf, aLen, "%u bytes", ( unsigned ) sb); + } + return apBuf; +} diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/FreeRTOSConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/FreeRTOSConfig.h new file mode 100644 index 000000000..d58a0b80f --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/FreeRTOSConfig.h @@ -0,0 +1,210 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * http://www.freertos.org/a00110.html + * + * The bottom of this file contains some constants specific to running the UDP + * stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than + * the demo) are contained in FreeRTOSIPConfig.h. + *----------------------------------------------------------*/ +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Run time stats gathering definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_pcTaskGetTaskName 1 + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS +is set to 2 so the formatting functions are included without the stdio.h being +included in tasks.c. That is because this project defines its own sprintf() +functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* Assert call defined for debug builds. */ +#ifdef _DEBUG + extern void vAssertCalled( const char *pcFile, uint32_t ulLine ); + #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) +#endif /* _DEBUG */ + + + +/* Application specific definitions follow. **********************************/ + +/* Only used when running in the FreeRTOS Windows simulator. Defines the +priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet +or WiFi data to and from a real network connection. Many computers have more +than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell +the demo which real port should be used to create the virtual port. The ports +available are displayed on the console when the application is executed. For +example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 +results in the wired network being used, while setting +configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being +used. */ +#define configNETWORK_INTERFACE_TO_USE 1L + +/* The address of an echo server is only left in this project as it doubles as +the address to which logging is sent should UDP logging be enabled. */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 0 +#define configECHO_SERVER_ADDR3 11 + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet/WiFi data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition above for information on how to +configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x11 +#define configMAC_ADDR3 0x11 +#define configMAC_ADDR4 0x11 +#define configMAC_ADDR5 0x41 + +/* Default IP address configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 10 +#define configIP_ADDR1 10 +#define configIP_ADDR2 10 +#define configIP_ADDR3 200 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DNS is set to +0, or ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 10 +#define configGATEWAY_ADDR1 10 +#define configGATEWAY_ADDR2 10 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. OpenDNS addresses are 208.67.222.222 and +208.67.220.220. Used in ipconfigUSE_DNS is set to 0, or ipconfigUSE_DNS is set +to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 208 +#define configDNS_SERVER_ADDR1 67 +#define configDNS_SERVER_ADDR2 222 +#define configDNS_SERVER_ADDR3 222 + +/* Default netmask configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 0 +#define configNET_MASK2 0 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#if( defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) && !defined( snprintf ) ) + /* Map to Windows names. */ + #define snprintf _snprintf + #define vsnprintf _vsnprintf +#endif + +/* Visual studio does not have an implementation of strcasecmp(). */ +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define strcmpi _strcmpi + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); +#define configPRINTF( X ) vLoggingPrintf X + +#endif /* FREERTOS_CONFIG_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/FreeRTOSIPConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/FreeRTOSIPConfig.h new file mode 100644 index 000000000..b4f55e137 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/FreeRTOSIPConfig.h @@ -0,0 +1,310 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +/***************************************************************************** + * + * See the following URL for configuration information. + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html + * + *****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to +1 then FreeRTOS_debug_printf should be defined to the function used to print +out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 0 +#if( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf(X) vLoggingPrintf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the +FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 +then FreeRTOS_printf should be set to the function used to print out the +messages. */ +#define ipconfigHAS_PRINTF 1 +#if( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf(X) vLoggingPrintf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing +on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading (IP/TCP/UDP checksums) +then set ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software +stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 + +/* Several API's will block until the result is known, or the action has been +performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be +set per socket, using setsockopt(). If not set, the times below will be +used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 5000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for LLMNR: Link-local Multicast Name Resolution +(non-Microsoft) */ +#define ipconfigUSE_LLMNR ( 0 ) + +/* Include support for NBNS: NetBIOS Name Service (Microsoft) */ +#define ipconfigUSE_NBNS ( 0 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very +useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low +and also DNS may use small timeouts. If a DNS reply comes in after the DNS +socket has been destroyed, the result will be stored into the cache. The next +call to FreeRTOS_gethostbyname() will return immediately, without even creating +a socket. */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_NAME_LENGTH ( 32 ) +#define ipconfigDNS_CACHE_ENTRIES ( 4 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make +use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY +sets the priority of the task that executes the IP stack. The priority is a +standard FreeRTOS task priority so can take any value from 0 (the lowest +priority) to (configMAX_PRIORITIES - 1) (the highest priority). +configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in +FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to +the priority assigned to the task executing the IP stack relative to the +priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP +task. This setting is less important when the FreeRTOS Win32 simulator is used +as the Win32 simulator only stores a fixed amount of information on the task +stack. FreeRTOS includes optional stack overflow detection, see: +http://www.freertos.org/Stacks-and-stack-overflow-checking.html */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* ipconfigRAND32() is called by the IP stack to generate random numbers for +things such as a DHCP transaction number or initial sequence number. Random +number generation is performed via this macro to allow applications to use their +own random number generation method. For example, it might be possible to +generate a random number by sampling noise on an analogue input. */ +extern UBaseType_t uxRand(); +#define ipconfigRAND32() uxRand() + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the +network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK +is not set to 1 then the network event hook will never be called. See +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml +*/ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but +a network buffer cannot be obtained then the calling task is held in the Blocked +state (so other tasks can continue to executed) until either a network buffer +becomes available or the send block time expires. If the send block time expires +then the send operation is aborted. The maximum allowable send block time is +capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the +maximum allowable send block time prevents prevents a deadlock occurring when +all the network buffers are in use and the tasks that process (and subsequently +free) the network buffers are themselves blocked waiting for a network buffer. +ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in +milliseconds can be converted to a time in ticks by dividing the time in +milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP +address, netmask, DNS server address and gateway address from a DHCP server. If +ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The +stack will revert to using the static IP address even when ipconfigUSE_DHCP is +set to 1 if a valid configuration cannot be obtained from a DHCP server for any +reason. The static configuration used is that passed into the stack by the +FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 1 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at +increasing time intervals until either a reply is received from a DHCP server +and accepted, or the interval between transmissions reaches +ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the +static IP address passed as a parameter to FreeRTOS_IPInit() if the +re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without +a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( 120000 / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP +stack can only send a UDP message to a remove IP address if it knowns the MAC +address associated with the IP address, or the MAC address of the router used to +contact the remote IP address. When a UDP message is received from a remote IP +address the MAC address and IP address are added to the ARP cache. When a UDP +message is sent to a remote IP address that does not already appear in the ARP +cache then the UDP message is replaced by a ARP message that solicits the +required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum +number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a +maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is +aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP +table being created or refreshed and the entry being removed because it is stale. +New ARP requests are sent for ARP cache entries that are nearing their maximum +age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is +equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling +routines, which are relatively large. To save code space the full +FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster +alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() +takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. +FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets +(for example, 192, 168, 0, 1) as its parameters. If +ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and +FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is +not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that +are available to the IP stack. The total number of network buffers is limited +to ensure the total amount of RAM that can be consumed by the IP stack is capped +to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP +stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can +be queued for processing at any one time. The event queue must be a minimum of +5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port +number. FreeRTOS_bind() is used to manually allocate a port number to a socket +(to 'bind' the socket to a port), but manual binding is not normally necessary +for client sockets (those sockets that initiate outgoing connections rather than +wait for incoming connections on a known port number). If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling +FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP +stack automatically binding the socket to a port number from the range +socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() +on a socket that has not yet been bound will result in the send operation being +aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +#define ipconfigTCP_TIME_TO_LIVE 128 /* also defined in FreeRTOSIPConfigDefaults.h */ + +/* USE_TCP: Use TCP and all its features */ +#define ipconfigUSE_TCP ( 1 ) + +/* Use the TCP socket wake context with a callback. */ +#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT ( 1 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can +contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a +lower value can save RAM, depending on the buffer management scheme used. If +ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must +be divisible by 8. */ +#define ipconfigNETWORK_MTU 1200 + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used +through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will +generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the +FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 0 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() +(and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames +that are not in Ethernet II format will be dropped. This option is included for +potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the +responsibility of the Ethernet interface to filter out packets that are of no +interest. If the Ethernet interface does not implement this functionality, then +set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack +perform the filtering instead (it is much less efficient for the stack to do it +because the packet will already have been passed into the stack). If the +Ethernet driver does all the necessary filtering in hardware then software +filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to +block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with +32-bit memory instructions, all packets will be stored 32-bit-aligned, plus 16-bits. +This has to do with the contents of the IP-packets: all 32-bit fields are +32-bit-aligned, plus 16-bit(!) */ +#define ipconfigPACKET_FILLER_SIZE 2 + +/* Define the size of the pool of TCP window descriptors. On the average, each +TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 +outstanding packets (for Rx and Tx). When using up to 10 TP sockets +simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed +maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 1000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 1000 ) + +/* When using call-back handlers, the driver may check if the handler points to +real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS(x) ( (x) != NULL ) + +/* Include support for TCP hang protection. All sockets in a connecting or +disconnecting stage will timeout after a period of non-activity. */ +#define ipconfigTCP_HANG_PROTECTION ( 1 ) +#define ipconfigTCP_HANG_PROTECTION_TIME ( 30 ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* in seconds */ + +#define portINLINE __inline + +#endif /* FREERTOS_IP_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/READ_ME_INSTRUCTIONS.url b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/READ_ME_INSTRUCTIONS.url new file mode 100644 index 000000000..8a5a8617e --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/READ_ME_INSTRUCTIONS.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/mqtt/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/WIN32.vcxproj b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/WIN32.vcxproj new file mode 100644 index 000000000..7d742d5aa --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/WIN32.vcxproj @@ -0,0 +1,620 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {C686325E-3261-42F7-AEB1-DDE5280E1CEB} + RTOSDemo + 10.0 + + + + Application + false + MultiByte + v142 + + + Application + false + MultiByte + v142 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Debug\ + .\Debug\ + true + .\Release\ + .\Release\ + false + AllRules.ruleset + + + + .\Debug/WIN32.tlb + + + + + Disabled + ..\..\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\common;..\common\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\src;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\mbedtls;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\platform;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\mqtt\include;..\..\..\..\Source\mbedtls\include;.;%(AdditionalIncludeDirectories) + MBEDTLS_CONFIG_FILE="mbedtls_config.h";WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDLL + .\Debug/WIN32.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level4 + true + false + EditAndContinue + /wd4210 /wd4127 /wd4214 /wd4201 /wd4244 /wd4310 /wd4200 %(AdditionalOptions) + true + NotUsing + false + CompileAsC + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Debug/RTOSDemo.exe + true + true + .\Debug/WIN32.pdb + Console + MachineX86 + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + ..\common\WinPCap + false + false + + + true + .\Debug/WIN32.bsc + + + + + .\Release/WIN32.tlb + + + + + MaxSpeed + OnlyExplicitInline + MBEDTLS_CONFIG_FILE="mbedtls_config.h";_WINSOCKAPI_;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release/WIN32.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + ..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;.\DemoTasks\include;.\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\src;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\mbedtls;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\platform;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\mqtt\include;..\..\..\..\Source\mbedtls\include;.;%(AdditionalIncludeDirectories) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Release/RTOSDemo.exe + true + .\Release/WIN32.pdb + Console + MachineX86 + .\WinPCap + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + + + true + .\Release/WIN32.bsc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/WIN32.vcxproj.filters b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/WIN32.vcxproj.filters new file mode 100644 index 000000000..40c20b9c5 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/WIN32.vcxproj.filters @@ -0,0 +1,789 @@ + + + + + {af3445a1-4908-4170-89ed-39345d90d30c} + + + {f32be356-4763-4cae-9020-974a2638cb08} + *.c + + + {88f409e6-d396-4ac5-94bd-7a99c914be46} + + + {e5ad4ec7-23dc-4295-8add-2acaee488f5a} + + + {d2dcd641-8d91-492b-852f-5563ffadaec6} + + + {8672fa26-b119-481f-8b8d-086419c01a3e} + + + {4570be11-ec96-4b55-ac58-24b50ada980a} + + + {5d93ed51-023a-41ad-9243-8d230165d34b} + + + {b71e974a-9f28-4815-972b-d930ba8a34d0} + + + {60717407-397f-4ea5-8492-3314acdd25f0} + + + {8a90222f-d723-4b4e-8e6e-c57afaf7fa92} + + + {7c995f05-2a10-4771-ad77-18a755876e46} + + + {9a636cc3-ebc6-48c5-8c18-c72494686e81} + + + {29376c48-bc8b-4624-ad59-16807874c9f2} + + + {91ef4008-de51-4b41-ba5e-bf24d8cda378} + + + {ade43c6c-04c5-4897-abdb-91af2df04e5d} + + + {08a4e35c-19ca-4b1e-af24-bac368c2bf7b} + + + {1e324500-91b4-4c76-b699-59ba75691760} + + + {bdcbc1ec-99b8-4c72-9075-49035c115488} + + + {2d17d5e6-ed70-4e42-9693-f7a63baf4948} + + + {7158b0be-01e7-42d1-8d3f-c75118a596a2} + + + {6ad56e6d-c330-4830-8f4b-c75b05dfa866} + + + {1d80b387-5a86-4744-a4cc-930033a52e4b} + + + {1cecca7f-60cd-4d8d-8123-f00aa75af147} + + + {f9a2e0a1-ed56-4ca7-b8b2-d694a94c78c0} + + + {61ac8e2c-8fd1-44a0-a7a9-0326bc190426} + + + {b53bfe50-b4d9-4b78-b7bb-ae90e4d25615} + + + {f7bebbc3-22c6-461c-98d6-a4e44cbcca00} + + + {e5377363-356a-4b0c-88ea-bad4f966f9ff} + + + {484626f0-0f84-46bc-89ff-54732d24f271} + + + + + FreeRTOS\Source\Portable + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS\Source + + + FreeRTOS\Source\Portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\mbedtls + + + + + DemoTasks + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos\include\platform + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\mbedtls + + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/demo_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/demo_config.h new file mode 100644 index 000000000..20a783d51 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/demo_config.h @@ -0,0 +1,78 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef DEMO_CONFIG_H +#define DEMO_CONFIG_H + +/* + * This configuration file determines how MQTT demo is run. + * + * mqtt_plain_text demo: Security is turned off. Preconfigured to a public MQTT + * broker on unencrypted port so no authentication configuration required. + * + * mqtt_basic_tls_server_auth demo: TLS security is enabled, allowing broker side + * authentication. Preconfigured to a public MQTT broker with certificate provided + * by the broker so no authentication configuration required. + * + * mqtt_tls_mutual_auth demo: Mutual authentication is enabled. Preconfigured to + * AWS IoT broker, will require certificate setup for successful connection. + */ + +/** + * @brief Enable/Disable TLS in demos. + * + * For more information regarding TLS protocol: + * https://www.freertos.org/mqtt/tls.html + */ +#define democonfigENABLE_TLS 1 + +/** + * @brief Enable/Disable mutual authentication in demos. If enabled, require + * democonfigENABLE_TLS to be set to 1. + */ +#define democonfigENABLE_MUTUAL_AUTH 0 + +/** + * @brief Select a connection profile. + * + * If set to 1, the demo will connect to AWS IoT with credential setup in + * aws_iot_demo_profile.h file, otherwise the demo is preconfigured to connect to + * test.mosquitto.org with credential setup in mqtt_demo_profile.h file. If + * enabled, requires democonfigENABLE_MUTUAL_AUTH to be set to 1 since AWS IoT + * requires mutually authenticated connection. + */ +#define democonfigPROFILE_USE_AWS_IOT 0 + +/** + * @brief Set the stack size of the main demo task. + * + * In the Windows port, this stack only holds a structure. The actual + * stack is created by an operating system thread. + */ +#define democonfigDEMO_STACKSIZE configMINIMAL_STACK_SIZE + +#endif /* DEMO_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/iot_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/iot_config.h new file mode 100644 index 000000000..a0f022e1e --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/iot_config.h @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/* This file contains configuration settings for the demos. */ + +#ifndef IOT_CONFIG_H_ +#define IOT_CONFIG_H_ + +/* Configure the IoT Libraries for FreeRTOS by including the FreeRTOS header and + * the FreeRTOS platform types. */ +#include "FreeRTOS.h" +#include "platform/iot_platform_types_freertos.h" + +/** + * @brief Set a global default for log levels. + * + * This setting is overridden by log level settings of specific libraries. + * Undefined library-specific log levels will default to this value. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_GLOBAL IOT_LOG_NONE + +/** + * @brief Set the log level of the platform libraries except the network + * component. + * + * Log messages from the platform libraries at or below this setting + * will be printed. As the network component is more verbose, its logging + * is controlled by its own setting, IOT_LOG_LEVEL_NETWORK. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_PLATFORM IOT_LOG_NONE + +/** + * @brief Set the log level of the platform network library. + * + * Log messages from the platform network library at or below this setting + * will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_NETWORK IOT_LOG_WARN + +/* + * @brief Set the log level of the task pool library. + * + * Log messages from the task pool library at or below this setting will be + * printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_TASKPOOL IOT_LOG_WARN + +/** + * @brief Set the log level of the MQTT library. + * + * Log messages from the MQTT library at or below this setting will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_MQTT IOT_LOG_WARN + +/** + * @brief Enable/Disable asserts for the task pool library. + * + * Set this to 1 to perform sanity checks when using the task pool library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotTaskPool_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_TASKPOOL_ENABLE_ASSERTS 1 + +/** + * @brief The numer of worker tasks in the task pool. + * + * The full IoT Task Pool Library has many use cases, including Linux + * development. Typical FreeRTOS use cases do not require the full + * functionality so an optimized implementation is provided specifically for use + * with FreeRTOS. The optimized version has a fixed number of tasks in the + * task pool, each of which uses statically allocated memory to ensure creation + * of the task pool is guaranteed (it does not run out of heap space). + */ +#define IOT_TASKPOOL_NUMBER_OF_WORKERS 1 + +/** + * @brief The stack size (in bytes) for each worker task in the task pool. + * + * The minimal version of the of task pool library only supports one task pool + * and the configuration of each worker task fixed at the compile time. + */ +#define IOT_TASKPOOL_WORKER_STACK_SIZE_BYTES 2048 + +/** + * @brief Enable TLS in the network abstraction. + * + * The TLS implementation requires the mbed TLS library. + */ +#define IOT_NETWORK_ENABLE_TLS 1 + +/** + * @brief Enable/Disable asserts for the linear containers library. + * + * Set this to 1 to perform sanity checks when using the linear containers library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotContainers_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_CONTAINERS_ENABLE_ASSERTS 1 + +/** + * @brief Enable/Disable asserts for the MQTT library. + * + * Set this to 1 to perform sanity checks when using the MQTT library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotMqtt_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_MQTT_ENABLE_ASSERTS 1 + +/** + * @brief Enable/Disable anonymous metrics collection when using AWS IoT. + * + * This demo does not work with AWS IoT. Therefore, the metric collection must + * be disabled. + */ +#define AWS_IOT_MQTT_ENABLE_METRICS 0 + +/* Common settings for FreeRTOS; settings below this line generally do not need + * to be changed. */ + +/* Logging puts function on FreeRTOS. */ +#define IotLogging_Puts( str ) configPRINTF( ( "%s\r\n", str ) ) + +/* Assert functions on FreeRTOS. */ +#define Iot_DefaultAssert configASSERT + +/* Memory allocation functions on FreeRTOS. */ +#define Iot_DefaultMalloc pvPortMalloc +#define Iot_DefaultFree vPortFree + +#endif /* ifndef IOT_CONFIG_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/mqtt_basic_tls_demo.sln b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/mqtt_basic_tls_demo.sln new file mode 100644 index 000000000..b362f36c5 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_basic_tls_server_auth/mqtt_basic_tls_demo.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTOSDemo", "WIN32.vcxproj", "{C686325E-3261-42F7-AEB1-DDE5280E1CEB}" +EndProject +Global + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = FreeRTOS_Plus_TCP_Minimal.vsmdi + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.ActiveCfg = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.Build.0 = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.ActiveCfg = Release|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/FreeRTOSConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/FreeRTOSConfig.h new file mode 100644 index 000000000..841ebd1a8 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/FreeRTOSConfig.h @@ -0,0 +1,218 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * http://www.freertos.org/a00110.html + * + * The bottom of this file contains some constants specific to running the UDP + * stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than + * the demo) are contained in FreeRTOSIPConfig.h. + *----------------------------------------------------------*/ +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 0 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Run time stats gathering configuration options. */ +unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */ +void vConfigureTimerForRunTimeStats( void ); /* Prototype of function that initializes the run time counter. */ +#define configGENERATE_RUN_TIME_STATS 0 +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vConfigureTimerForRunTimeStats() +#define portGET_RUN_TIME_COUNTER_VALUE() ulGetRunTimeCounterValue() + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_pcTaskGetTaskName 1 + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS +is set to 2 so the formatting functions are included without the stdio.h being +included in tasks.c. That is because this project defines its own sprintf() +functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* Assert call defined for debug builds. */ +#ifdef _DEBUG + extern void vAssertCalled( const char *pcFile, uint32_t ulLine ); + #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) +#endif /* _DEBUG */ + + + +/* Application specific definitions follow. **********************************/ + +/* Only used when running in the FreeRTOS Windows simulator. Defines the +priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet +or WiFi data to and from a real network connection. Many computers have more +than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell +the demo which real port should be used to create the virtual port. The ports +available are displayed on the console when the application is executed. For +example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 +results in the wired network being used, while setting +configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being +used. */ +#define configNETWORK_INTERFACE_TO_USE 1L + +/* The address of an echo server is only left in this project as it doubles as +the address to which logging is sent should UDP logging be enabled. */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 0 +#define configECHO_SERVER_ADDR3 11 + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet/WiFi data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition above for information on how to +configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x11 +#define configMAC_ADDR3 0x11 +#define configMAC_ADDR4 0x11 +#define configMAC_ADDR5 0x41 + +/* Default IP address configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 10 +#define configIP_ADDR1 10 +#define configIP_ADDR2 10 +#define configIP_ADDR3 200 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DNS is set to +0, or ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 10 +#define configGATEWAY_ADDR1 10 +#define configGATEWAY_ADDR2 10 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. OpenDNS addresses are 208.67.222.222 and +208.67.220.220. Used in ipconfigUSE_DNS is set to 0, or ipconfigUSE_DNS is set +to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 208 +#define configDNS_SERVER_ADDR1 67 +#define configDNS_SERVER_ADDR2 222 +#define configDNS_SERVER_ADDR3 222 + +/* Default netmask configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 0 +#define configNET_MASK2 0 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#if( defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) && !defined( snprintf ) ) + /* Map to Windows names. */ + #define snprintf _snprintf + #define vsnprintf _vsnprintf +#endif + +/* Visual studio does not have an implementation of strcasecmp(). */ +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define strcmpi _strcmpi + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); +#define configPRINTF( X ) vLoggingPrintf X + +/* Include the FreeRTOS+Trace FreeRTOS trace macro definitions. */ +void vSaveTraceFile( void ); +#include "trcRecorder.h" + +#endif /* FREERTOS_CONFIG_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/FreeRTOSIPConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/FreeRTOSIPConfig.h new file mode 100644 index 000000000..92b7773b7 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/FreeRTOSIPConfig.h @@ -0,0 +1,310 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +/***************************************************************************** + * + * See the following URL for configuration information. + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html + * + *****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to +1 then FreeRTOS_debug_printf should be defined to the function used to print +out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 0 +#if( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf(X) vLoggingPrintf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the +FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 +then FreeRTOS_printf should be set to the function used to print out the +messages. */ +#define ipconfigHAS_PRINTF 1 +#if( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf(X) vLoggingPrintf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing +on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading (IP/TCP/UDP checksums) +then set ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software +stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 + +/* Several API's will block until the result is known, or the action has been +performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be +set per socket, using setsockopt(). If not set, the times below will be +used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 2000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for LLMNR: Link-local Multicast Name Resolution +(non-Microsoft) */ +#define ipconfigUSE_LLMNR ( 0 ) + +/* Include support for NBNS: NetBIOS Name Service (Microsoft) */ +#define ipconfigUSE_NBNS ( 0 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very +useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low +and also DNS may use small timeouts. If a DNS reply comes in after the DNS +socket has been destroyed, the result will be stored into the cache. The next +call to FreeRTOS_gethostbyname() will return immediately, without even creating +a socket. */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_NAME_LENGTH ( 32 ) +#define ipconfigDNS_CACHE_ENTRIES ( 4 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make +use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY +sets the priority of the task that executes the IP stack. The priority is a +standard FreeRTOS task priority so can take any value from 0 (the lowest +priority) to (configMAX_PRIORITIES - 1) (the highest priority). +configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in +FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to +the priority assigned to the task executing the IP stack relative to the +priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP +task. This setting is less important when the FreeRTOS Win32 simulator is used +as the Win32 simulator only stores a fixed amount of information on the task +stack. FreeRTOS includes optional stack overflow detection, see: +http://www.freertos.org/Stacks-and-stack-overflow-checking.html */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* ipconfigRAND32() is called by the IP stack to generate random numbers for +things such as a DHCP transaction number or initial sequence number. Random +number generation is performed via this macro to allow applications to use their +own random number generation method. For example, it might be possible to +generate a random number by sampling noise on an analogue input. */ +extern UBaseType_t uxRand(); +#define ipconfigRAND32() uxRand() + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the +network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK +is not set to 1 then the network event hook will never be called. See +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml +*/ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but +a network buffer cannot be obtained then the calling task is held in the Blocked +state (so other tasks can continue to executed) until either a network buffer +becomes available or the send block time expires. If the send block time expires +then the send operation is aborted. The maximum allowable send block time is +capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the +maximum allowable send block time prevents prevents a deadlock occurring when +all the network buffers are in use and the tasks that process (and subsequently +free) the network buffers are themselves blocked waiting for a network buffer. +ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in +milliseconds can be converted to a time in ticks by dividing the time in +milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP +address, netmask, DNS server address and gateway address from a DHCP server. If +ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The +stack will revert to using the static IP address even when ipconfigUSE_DHCP is +set to 1 if a valid configuration cannot be obtained from a DHCP server for any +reason. The static configuration used is that passed into the stack by the +FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 1 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at +increasing time intervals until either a reply is received from a DHCP server +and accepted, or the interval between transmissions reaches +ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the +static IP address passed as a parameter to FreeRTOS_IPInit() if the +re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without +a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( 120000 / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP +stack can only send a UDP message to a remove IP address if it knowns the MAC +address associated with the IP address, or the MAC address of the router used to +contact the remote IP address. When a UDP message is received from a remote IP +address the MAC address and IP address are added to the ARP cache. When a UDP +message is sent to a remote IP address that does not already appear in the ARP +cache then the UDP message is replaced by a ARP message that solicits the +required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum +number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a +maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is +aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP +table being created or refreshed and the entry being removed because it is stale. +New ARP requests are sent for ARP cache entries that are nearing their maximum +age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is +equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling +routines, which are relatively large. To save code space the full +FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster +alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() +takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. +FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets +(for example, 192, 168, 0, 1) as its parameters. If +ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and +FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is +not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that +are available to the IP stack. The total number of network buffers is limited +to ensure the total amount of RAM that can be consumed by the IP stack is capped +to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP +stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can +be queued for processing at any one time. The event queue must be a minimum of +5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port +number. FreeRTOS_bind() is used to manually allocate a port number to a socket +(to 'bind' the socket to a port), but manual binding is not normally necessary +for client sockets (those sockets that initiate outgoing connections rather than +wait for incoming connections on a known port number). If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling +FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP +stack automatically binding the socket to a port number from the range +socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() +on a socket that has not yet been bound will result in the send operation being +aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +#define ipconfigTCP_TIME_TO_LIVE 128 /* also defined in FreeRTOSIPConfigDefaults.h */ + +/* USE_TCP: Use TCP and all its features */ +#define ipconfigUSE_TCP ( 1 ) + +/* Use the TCP socket wake context with a callback. */ +#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT ( 1 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can +contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a +lower value can save RAM, depending on the buffer management scheme used. If +ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must +be divisible by 8. */ +#define ipconfigNETWORK_MTU 1200 + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used +through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will +generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the +FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 0 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() +(and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames +that are not in Ethernet II format will be dropped. This option is included for +potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the +responsibility of the Ethernet interface to filter out packets that are of no +interest. If the Ethernet interface does not implement this functionality, then +set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack +perform the filtering instead (it is much less efficient for the stack to do it +because the packet will already have been passed into the stack). If the +Ethernet driver does all the necessary filtering in hardware then software +filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to +block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with +32-bit memory instructions, all packets will be stored 32-bit-aligned, plus 16-bits. +This has to do with the contents of the IP-packets: all 32-bit fields are +32-bit-aligned, plus 16-bit(!) */ +#define ipconfigPACKET_FILLER_SIZE 2 + +/* Define the size of the pool of TCP window descriptors. On the average, each +TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 +outstanding packets (for Rx and Tx). When using up to 10 TP sockets +simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed +maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 1000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 1000 ) + +/* When using call-back handlers, the driver may check if the handler points to +real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS(x) ( (x) != NULL ) + +/* Include support for TCP hang protection. All sockets in a connecting or +disconnecting stage will timeout after a period of non-activity. */ +#define ipconfigTCP_HANG_PROTECTION ( 1 ) +#define ipconfigTCP_HANG_PROTECTION_TIME ( 30 ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* in seconds */ + +#define portINLINE __inline + +#endif /* FREERTOS_IP_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/READ_ME_INSTRUCTIONS.url b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/READ_ME_INSTRUCTIONS.url new file mode 100644 index 000000000..8a5a8617e --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/READ_ME_INSTRUCTIONS.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/mqtt/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/WIN32.vcxproj b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/WIN32.vcxproj new file mode 100644 index 000000000..78b80e890 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/WIN32.vcxproj @@ -0,0 +1,226 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {C686325E-3261-42F7-AEB1-DDE5280E1CEB} + RTOSDemo + 10.0 + + + + Application + false + MultiByte + v142 + + + Application + false + MultiByte + v142 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Debug\ + .\Debug\ + true + .\Release\ + .\Release\ + false + AllRules.ruleset + + + + .\Debug/WIN32.tlb + + + + + Disabled + ..\..\include;..\..\..\..\Source\FreeRTOS-Plus-Trace\Include;..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\common\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\src;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\platform;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\mqtt\include;.;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDLL + .\Debug/WIN32.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level4 + true + false + EditAndContinue + /wd4210 /wd4127 /wd4214 /wd4201 /wd4244 /wd4310 /wd4200 %(AdditionalOptions) + true + NotUsing + false + CompileAsC + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Debug/RTOSDemo.exe + true + true + .\Debug/WIN32.pdb + Console + MachineX86 + wpcap.lib;%(AdditionalDependencies) + ..\common\WinPCap + false + false + + + true + .\Debug/WIN32.bsc + + + + + .\Release/WIN32.tlb + + + + + MaxSpeed + OnlyExplicitInline + _WINSOCKAPI_;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release/WIN32.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + ..\Common\Utils;..\Common\ethernet\lwip-1.4.0\ports\win32\WinPCap;..\Common\ethernet\lwip-1.4.0\src\include\ipv4;..\Common\ethernet\lwip-1.4.0\src\include;..\..\..\Source\include;..\..\..\Source\portable\MSVC-MingW;..\Common\ethernet\lwip-1.4.0\ports\win32\include;..\Common\Include;.\lwIP_Apps;.;%(AdditionalIncludeDirectories) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Release/RTOSDemo.exe + true + .\Release/WIN32.pdb + Console + MachineX86 + ..\Common\ethernet\lwip-1.4.0\ports\win32\WinPCap + wpcap.lib;%(AdditionalDependencies) + + + true + .\Release/WIN32.bsc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/WIN32.vcxproj.filters b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/WIN32.vcxproj.filters new file mode 100644 index 000000000..fff8a7631 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/WIN32.vcxproj.filters @@ -0,0 +1,312 @@ + + + + + {af3445a1-4908-4170-89ed-39345d90d30c} + + + {f32be356-4763-4cae-9020-974a2638cb08} + *.c + + + {88f409e6-d396-4ac5-94bd-7a99c914be46} + + + {e5ad4ec7-23dc-4295-8add-2acaee488f5a} + + + {d2dcd641-8d91-492b-852f-5563ffadaec6} + + + {8672fa26-b119-481f-8b8d-086419c01a3e} + + + {4570be11-ec96-4b55-ac58-24b50ada980a} + + + {5d93ed51-023a-41ad-9243-8d230165d34b} + + + {b71e974a-9f28-4815-972b-d930ba8a34d0} + + + {60717407-397f-4ea5-8492-3314acdd25f0} + + + {8a90222f-d723-4b4e-8e6e-c57afaf7fa92} + + + {7c995f05-2a10-4771-ad77-18a755876e46} + + + {9a636cc3-ebc6-48c5-8c18-c72494686e81} + + + {29376c48-bc8b-4624-ad59-16807874c9f2} + + + {91ef4008-de51-4b41-ba5e-bf24d8cda378} + + + {ade43c6c-04c5-4897-abdb-91af2df04e5d} + + + {08a4e35c-19ca-4b1e-af24-bac368c2bf7b} + + + {1e324500-91b4-4c76-b699-59ba75691760} + + + {bdcbc1ec-99b8-4c72-9075-49035c115488} + + + {2d17d5e6-ed70-4e42-9693-f7a63baf4948} + + + {7158b0be-01e7-42d1-8d3f-c75118a596a2} + + + {6ad56e6d-c330-4830-8f4b-c75b05dfa866} + + + {1d80b387-5a86-4744-a4cc-930033a52e4b} + + + {7981e96c-e6fc-4ce4-bb37-a1a25a74dc74} + + + {8d49e590-e906-4f21-a3d4-77db6eef6fe7} + + + {da8b4d4b-bdad-4ac4-8ca5-badcb410fbdc} + + + {d9a54ba3-9ae5-4f84-988a-922630f5354a} + + + + + FreeRTOS\Source\Portable + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS\Source + + + FreeRTOS\Source\Portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS+Trace Recorder + + + FreeRTOS+\FreeRTOS+Trace Recorder + + + FreeRTOS\Source + + + + + + DemoTasks + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + DemoTasks + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos\include\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform\types + + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/demo_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/demo_config.h new file mode 100644 index 000000000..6ea370304 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/demo_config.h @@ -0,0 +1,78 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef DEMO_CONFIG_H +#define DEMO_CONFIG_H + +/* + * This configuration file determines how MQTT demo is run. + * + * mqtt_plain_text demo: Security is turned off. Preconfigured to a public MQTT + * broker on unencrypted port so no authentication configuration required. + * + * mqtt_basic_tls_server_auth demo: TLS security is enabled, allowing broker side + * authentication. Preconfigured to a public MQTT broker with certificate provided + * by the broker so no authentication configuration required. + * + * mqtt_tls_mutual_auth demo: Mutual authentication is enabled. Preconfigured to + * AWS IoT broker, will require certificate setup for successful connection. + */ + +/** + * @brief Enable/Disable TLS in demos. + * + * For more information regarding TLS protocol: + * https://www.freertos.org/mqtt/tls.html + */ +#define democonfigENABLE_TLS 0 + +/** + * @brief Enable/Disable mutual authentication in demos. If enabled, require + * democonfigENABLE_TLS to be set to 1. + */ +#define democonfigENABLE_MUTUAL_AUTH 0 + +/** + * @brief Select a connection profile. + * + * If set to 1, the demo will connect to AWS IoT with credential setup in + * aws_iot_demo_profile.h file, otherwise the demo is preconfigured to connect to + * test.mosquitto.org with credential setup in mqtt_demo_profile.h file. If + * enabled, requires democonfigENABLE_MUTUAL_AUTH to be set to 1 since AWS IoT + * requires mutually authenticated connection. + */ +#define democonfigPROFILE_USE_AWS_IOT 0 + +/** + * @brief Set the stack size of the main demo task. + * + * In the Windows port, this stack only holds a structure. The actual + * stack is created by an operating system thread. + */ +#define democonfigDEMO_STACKSIZE configMINIMAL_STACK_SIZE + +#endif /* DEMO_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/iot_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/iot_config.h new file mode 100644 index 000000000..bcb8b8767 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/iot_config.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/* This file contains configuration settings for the demos. */ + +#ifndef IOT_CONFIG_H_ +#define IOT_CONFIG_H_ + +/* Configure the IoT Libraries for FreeRTOS by including the FreeRTOS header and + * the FreeRTOS platform types. */ +#include "FreeRTOS.h" +#include "platform/iot_platform_types_freertos.h" + +/** + * @brief Set a global default for log levels. + * + * This setting is overridden by log level settings of specific libraries. + * Undefined library-specific log levels will default to this value. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_GLOBAL IOT_LOG_NONE + +/** + * @brief Set the log level of the platform libraries except the network + * component. + * + * Log messages from the platform libraries at or below this setting + * will be printed. As the network component is more verbose, its logging + * is controlled by its own setting, IOT_LOG_LEVEL_NETWORK. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_PLATFORM IOT_LOG_NONE + +/** + * @brief Set the log level of the platform network library. + * + * Log messages from the platform network library at or below this setting + * will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_NETWORK IOT_LOG_WARN + +/* + * @brief Set the log level of the task pool library. + * + * Log messages from the task pool library at or below this setting will be + * printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_TASKPOOL IOT_LOG_WARN + +/** + * @brief Set the log level of the MQTT library. + * + * Log messages from the MQTT library at or below this setting will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_MQTT IOT_LOG_WARN + +/** + * @brief Enable/Disable asserts for the task pool library. + * + * Set this to 1 to perform sanity checks when using the task pool library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotTaskPool_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_TASKPOOL_ENABLE_ASSERTS 1 + +/** + * @brief The number of worker tasks in the task pool. + * + * The full IoT Task Pool Library has many use cases, including Linux + * development. Typical FreeRTOS use cases do not require the full + * functionality so an optimized implementation is provided specifically for use + * with FreeRTOS. The optimized version has a fixed number of tasks in the + * task pool, each of which uses statically allocated memory to ensure creation + * of the task pool is guaranteed (it does not run out of heap space). + */ +#define IOT_TASKPOOL_NUMBER_OF_WORKERS 1 + +/** + * @brief The stack size (in bytes) for each worker task in the task pool. + * + * The minimal version of the of task pool library only supports one task pool + * and the configuration of each worker task fixed at the compile time. + */ +#define IOT_TASKPOOL_WORKER_STACK_SIZE_BYTES 2048 + +/** + * @brief Enable/Disable asserts for the linear containers library. + * + * Set this to 1 to perform sanity checks when using the linear containers library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotContainers_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_CONTAINERS_ENABLE_ASSERTS 1 + +/** + * @brief Enable/Disable asserts for the MQTT library. + * + * Set this to 1 to perform sanity checks when using the MQTT library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotMqtt_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_MQTT_ENABLE_ASSERTS 1 + +/** + * @brief Enable/Disable anonymous metrics collection when using AWS IoT. + * + * This demo does not use TLS and so does not work with AWS IoT. Therefore, + * the metric collection must be disabled. + */ +#define AWS_IOT_MQTT_ENABLE_METRICS 0 + +/* Common settings for FreeRTOS; settings below this line generally do not need + * to be changed. */ + +/* Logging puts function on FreeRTOS. */ +#define IotLogging_Puts( str ) configPRINTF( ( "%s\r\n", str ) ) + +/* Assert functions on FreeRTOS. */ +#define Iot_DefaultAssert configASSERT + +/* Memory allocation functions on FreeRTOS. */ +#define Iot_DefaultMalloc pvPortMalloc +#define Iot_DefaultFree vPortFree + +#endif /* ifndef IOT_CONFIG_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/mqtt_plain_text_demo.sln b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/mqtt_plain_text_demo.sln new file mode 100644 index 000000000..b228b4941 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/mqtt_plain_text_demo.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29215.179 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTOSDemo", "WIN32.vcxproj", "{C686325E-3261-42F7-AEB1-DDE5280E1CEB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.ActiveCfg = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.Build.0 = Debug|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {150F08BF-9D61-4CC2-8DBF-1335172A1EA4} + EndGlobalSection + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = FreeRTOS_Plus_TCP_Minimal.vsmdi + EndGlobalSection +EndGlobal diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/trcConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/trcConfig.h new file mode 100644 index 000000000..610b0d97e --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/trcConfig.h @@ -0,0 +1,300 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.4 + * Percepio AB, www.percepio.com + * + * trcConfig.h + * + * Main configuration parameters for the trace recorder library. + * More settings can be found in trcStreamingConfig.h and trcSnapshotConfig.h. + * + * Read more at http://percepio.com/2016/10/05/rtos-tracing/ + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_CONFIG_H +#define TRC_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "trcPortDefines.h" + +/****************************************************************************** + * Include of processor header file + * + * Here you may need to include the header file for your processor. This is + * required at least for the ARM Cortex-M port, that uses the ARM CMSIS API. + * Try that in case of build problems. Otherwise, remove the #error line below. + *****************************************************************************/ +//#error "Trace Recorder: Please include your processor's header file here and remove this line." + +/******************************************************************************* + * Configuration Macro: TRC_CFG_HARDWARE_PORT + * + * Specify what hardware port to use (i.e., the "timestamping driver"). + * + * All ARM Cortex-M MCUs are supported by "TRC_HARDWARE_PORT_ARM_Cortex_M". + * This port uses the DWT cycle counter for Cortex-M3/M4/M7 devices, which is + * available on most such devices. In case your device don't have DWT support, + * you will get an error message opening the trace. In that case, you may + * force the recorder to use SysTick timestamping instead, using this define: + * + * #define TRC_CFG_ARM_CM_USE_SYSTICK + * + * For ARM Cortex-M0/M0+ devices, SysTick mode is used automatically. + * + * See trcHardwarePort.h for available ports and information on how to + * define your own port, if not already present. + ******************************************************************************/ +#define TRC_CFG_HARDWARE_PORT TRC_HARDWARE_PORT_Win32 + +/******************************************************************************* + * Configuration Macro: TRC_CFG_RECORDER_MODE + * + * Specify what recording mode to use. Snapshot means that the data is saved in + * an internal RAM buffer, for later upload. Streaming means that the data is + * transferred continuously to the host PC. + * + * For more information, see http://percepio.com/2016/10/05/rtos-tracing/ + * and the Tracealyzer User Manual. + * + * Values: + * TRC_RECORDER_MODE_SNAPSHOT + * TRC_RECORDER_MODE_STREAMING + ******************************************************************************/ +#define TRC_CFG_RECORDER_MODE TRC_RECORDER_MODE_SNAPSHOT +/****************************************************************************** + * TRC_CFG_FREERTOS_VERSION + * + * Specify what version of FreeRTOS that is used (don't change unless using the + * trace recorder library with an older version of FreeRTOS). + * + * TRC_FREERTOS_VERSION_7_3 If using FreeRTOS v7.3.x + * TRC_FREERTOS_VERSION_7_4 If using FreeRTOS v7.4.x + * TRC_FREERTOS_VERSION_7_5_OR_7_6 If using FreeRTOS v7.5.0 - v7.6.0 + * TRC_FREERTOS_VERSION_8_X If using FreeRTOS v8.X.X + * TRC_FREERTOS_VERSION_9_0_0 If using FreeRTOS v9.0.0 + * TRC_FREERTOS_VERSION_9_0_1 If using FreeRTOS v9.0.1 + * TRC_FREERTOS_VERSION_9_0_2 If using FreeRTOS v9.0.2 + * TRC_FREERTOS_VERSION_10_0_0 If using FreeRTOS v10.0.0 or later + *****************************************************************************/ +#define TRC_CFG_FREERTOS_VERSION TRC_FREERTOS_VERSION_10_0_0 + +/******************************************************************************* + * TRC_CFG_SCHEDULING_ONLY + * + * Macro which should be defined as an integer value. + * + * If this setting is enabled (= 1), only scheduling events are recorded. + * If disabled (= 0), all events are recorded (unless filtered in other ways). + * + * Default value is 0 (= include additional events). + ******************************************************************************/ +#define TRC_CFG_SCHEDULING_ONLY 0 + + /****************************************************************************** + * TRC_CFG_INCLUDE_MEMMANG_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * This controls if malloc and free calls should be traced. Set this to zero (0) + * to exclude malloc/free calls, or one (1) to include such events in the trace. + * + * Default value is 1. + *****************************************************************************/ +#define TRC_CFG_INCLUDE_MEMMANG_EVENTS 1 + + /****************************************************************************** + * TRC_CFG_INCLUDE_USER_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), all code related to User Events is excluded in order + * to reduce code size. Any attempts of storing User Events are then silently + * ignored. + * + * User Events are application-generated events, like "printf" but for the + * trace log, generated using vTracePrint and vTracePrintF. + * The formatting is done on host-side, by Tracealyzer. User Events are + * therefore much faster than a console printf and can often be used + * in timing critical code without problems. + * + * Note: In streaming mode, User Events are used to provide error messages + * and warnings from the recorder (in case of incorrect configuration) for + * display in Tracealyzer. Disabling user events will also disable these + * warnings. You can however still catch them by calling xTraceGetLastError + * or by putting breakpoints in prvTraceError and prvTraceWarning. + * + * Default value is 1. + *****************************************************************************/ +#define TRC_CFG_INCLUDE_USER_EVENTS 1 + + /***************************************************************************** + * TRC_CFG_INCLUDE_ISR_TRACING + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the code for recording Interrupt Service Routines is + * excluded, in order to reduce code size. + * + * Default value is 1. + * + * Note: tracing ISRs requires that you insert calls to vTraceStoreISRBegin + * and vTraceStoreISREnd in your interrupt handlers. + *****************************************************************************/ +#define TRC_CFG_INCLUDE_ISR_TRACING 1 + + /***************************************************************************** + * TRC_CFG_INCLUDE_READY_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * If one (1), events are recorded when tasks enter scheduling state "ready". + * This allows Tracealyzer to show the initial pending time before tasks enter + * the execution state, and present accurate response times. + * If zero (0), "ready events" are not created, which allows for recording + * longer traces in the same amount of RAM. + * + * Default value is 1. + *****************************************************************************/ +#define TRC_CFG_INCLUDE_READY_EVENTS 1 + + /***************************************************************************** + * TRC_CFG_INCLUDE_OSTICK_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is one (1), events will be generated whenever the OS clock is + * increased. If zero (0), OS tick events are not generated, which allows for + * recording longer traces in the same amount of RAM. + * + * Default value is 1. + *****************************************************************************/ +#define TRC_CFG_INCLUDE_OSTICK_EVENTS 1 + + /***************************************************************************** + * TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the trace will exclude any "event group" events. + * + * Default value is 0 (excluded) since dependent on event_groups.c + *****************************************************************************/ +#define TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS 1 + + /***************************************************************************** + * TRC_CFG_INCLUDE_TIMER_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the trace will exclude any Timer events. + * + * Default value is 0 since dependent on timers.c + *****************************************************************************/ +#define TRC_CFG_INCLUDE_TIMER_EVENTS 1 + + /***************************************************************************** + * TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the trace will exclude any "pending function call" + * events, such as xTimerPendFunctionCall(). + * + * Default value is 0 since dependent on timers.c + *****************************************************************************/ +#define TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS 1 + +/******************************************************************************* + * Configuration Macro: TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the trace will exclude any stream buffer or message + * buffer events. + * + * Default value is 0 since dependent on stream_buffer.c (new in FreeRTOS v10) + ******************************************************************************/ +#define TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS 1 + +/******************************************************************************* + * Configuration Macro: TRC_CFG_RECORDER_BUFFER_ALLOCATION + * + * Specifies how the recorder buffer is allocated (also in case of streaming, in + * port using the recorder's internal temporary buffer) + * + * Values: + * TRC_RECORDER_BUFFER_ALLOCATION_STATIC - Static allocation (internal) + * TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC - Malloc in vTraceEnable + * TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM - Use vTraceSetRecorderDataBuffer + * + * Static and dynamic mode does the allocation for you, either in compile time + * (static) or in runtime (malloc). + * The custom mode allows you to control how and where the allocation is made, + * for details see TRC_ALLOC_CUSTOM_BUFFER and vTraceSetRecorderDataBuffer(). + ******************************************************************************/ +#define TRC_CFG_RECORDER_BUFFER_ALLOCATION TRC_RECORDER_BUFFER_ALLOCATION_STATIC + +/****************************************************************************** + * TRC_CFG_MAX_ISR_NESTING + * + * Defines how many levels of interrupt nesting the recorder can handle, in + * case multiple ISRs are traced and ISR nesting is possible. If this + * is exceeded, the particular ISR will not be traced and the recorder then + * logs an error message. This setting is used to allocate an internal stack + * for keeping track of the previous execution context (4 byte per entry). + * + * This value must be a non-zero positive constant, at least 1. + * + * Default value: 8 + *****************************************************************************/ +#define TRC_CFG_MAX_ISR_NESTING 8 + +/* Specific configuration, depending on Streaming/Snapshot mode */ +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) +#include "trcSnapshotConfig.h" +#elif (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) +#include "trcStreamingConfig.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _TRC_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/trcSnapshotConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/trcSnapshotConfig.h new file mode 100644 index 000000000..82175b350 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_plain_text/trcSnapshotConfig.h @@ -0,0 +1,378 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.4 + * Percepio AB, www.percepio.com + * + * trcSnapshotConfig.h + * + * Configuration parameters for trace recorder library in snapshot mode. + * Read more at http://percepio.com/2016/10/05/rtos-tracing/ + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_SNAPSHOT_CONFIG_H +#define TRC_SNAPSHOT_CONFIG_H + +#define TRC_SNAPSHOT_MODE_RING_BUFFER (0x01) +#define TRC_SNAPSHOT_MODE_STOP_WHEN_FULL (0x02) + +/****************************************************************************** + * TRC_CFG_SNAPSHOT_MODE + * + * Macro which should be defined as one of: + * - TRC_SNAPSHOT_MODE_RING_BUFFER + * - TRC_SNAPSHOT_MODE_STOP_WHEN_FULL + * Default is TRC_SNAPSHOT_MODE_RING_BUFFER. + * + * With TRC_CFG_SNAPSHOT_MODE set to TRC_SNAPSHOT_MODE_RING_BUFFER, the + * events are stored in a ring buffer, i.e., where the oldest events are + * overwritten when the buffer becomes full. This allows you to get the last + * events leading up to an interesting state, e.g., an error, without having + * to store the whole run since startup. + * + * When TRC_CFG_SNAPSHOT_MODE is TRC_SNAPSHOT_MODE_STOP_WHEN_FULL, the + * recording is stopped when the buffer becomes full. This is useful for + * recording events following a specific state, e.g., the startup sequence. + *****************************************************************************/ +#define TRC_CFG_SNAPSHOT_MODE TRC_SNAPSHOT_MODE_RING_BUFFER + +/******************************************************************************* + * TRC_CFG_EVENT_BUFFER_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the event buffer, i.e., the number of records + * it may store. Most events use one record (4 byte), although some events + * require multiple 4-byte records. You should adjust this to the amount of RAM + * available in the target system. + * + * Default value is 1000, which means that 4000 bytes is allocated for the + * event buffer. + ******************************************************************************/ +#define TRC_CFG_EVENT_BUFFER_SIZE 50000 + +/******************************************************************************* + * TRC_CFG_NTASK, TRC_CFG_NISR, TRC_CFG_NQUEUE, TRC_CFG_NSEMAPHORE... + * + * A group of macros which should be defined as integer values, zero or larger. + * + * These define the capacity of the Object Property Table, i.e., the maximum + * number of objects active at any given point, within each object class (e.g., + * task, queue, semaphore, ...). + * + * If tasks or other objects are deleted in your system, this + * setting does not limit the total amount of objects created, only the number + * of objects that have been successfully created but not yet deleted. + * + * Using too small values will cause vTraceError to be called, which stores an + * error message in the trace that is shown when opening the trace file. The + * error message can also be retrieved using xTraceGetLastError. + * + * It can be wise to start with large values for these constants, + * unless you are very confident on these numbers. Then do a recording and + * check the actual usage by selecting View menu -> Trace Details -> + * Resource Usage -> Object Table. + ******************************************************************************/ +#define TRC_CFG_NTASK 15 +#define TRC_CFG_NISR 10 +#define TRC_CFG_NQUEUE 10 +#define TRC_CFG_NSEMAPHORE 20 +#define TRC_CFG_NMUTEX 20 +#define TRC_CFG_NTIMER 20 +#define TRC_CFG_NEVENTGROUP 20 +#define TRC_CFG_NSTREAMBUFFER 10 +#define TRC_CFG_NMESSAGEBUFFER 10 + + +/****************************************************************************** + * TRC_CFG_INCLUDE_FLOAT_SUPPORT + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the support for logging floating point values in + * vTracePrintF is stripped out, in case floating point values are not used or + * supported by the platform used. + * + * Floating point values are only used in vTracePrintF and its subroutines, to + * allow for storing float (%f) or double (%lf) arguments. + * + * vTracePrintF can be used with integer and string arguments in either case. + * + * Default value is 0. + *****************************************************************************/ +#define TRC_CFG_INCLUDE_FLOAT_SUPPORT 0 + +/******************************************************************************* + * TRC_CFG_SYMBOL_TABLE_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the symbol table, in bytes. This symbol table + * stores User Events labels and names of deleted tasks, queues, or other kernel + * objects. If you don't use User Events or delete any kernel + * objects you set this to a very low value. The minimum recommended value is 4. + * A size of zero (0) is not allowed since a zero-sized array may result in a + * 32-bit pointer, i.e., using 4 bytes rather than 0. + * + * Default value is 800. + ******************************************************************************/ +#define TRC_CFG_SYMBOL_TABLE_SIZE 8000 + +#if (TRC_CFG_SYMBOL_TABLE_SIZE == 0) +#error "TRC_CFG_SYMBOL_TABLE_SIZE may not be zero!" +#endif + +/****************************************************************************** + * TRC_CFG_NAME_LEN_TASK, TRC_CFG_NAME_LEN_QUEUE, ... + * + * Macros that specify the maximum lengths (number of characters) for names of + * kernel objects, such as tasks and queues. If longer names are used, they will + * be truncated when stored in the recorder. + *****************************************************************************/ +#define TRC_CFG_NAME_LEN_TASK 15 +#define TRC_CFG_NAME_LEN_ISR 15 +#define TRC_CFG_NAME_LEN_QUEUE 15 +#define TRC_CFG_NAME_LEN_SEMAPHORE 15 +#define TRC_CFG_NAME_LEN_MUTEX 15 +#define TRC_CFG_NAME_LEN_TIMER 15 +#define TRC_CFG_NAME_LEN_EVENTGROUP 15 +#define TRC_CFG_NAME_LEN_STREAMBUFFER 15 +#define TRC_CFG_NAME_LEN_MESSAGEBUFFER 15 + +/****************************************************************************** + *** ADVANCED SETTINGS ******************************************************** + ****************************************************************************** + * The remaining settings are not necessary to modify but allows for optimizing + * the recorder setup for your specific needs, e.g., to exclude events that you + * are not interested in, in order to get longer traces. + *****************************************************************************/ + +/****************************************************************************** +* TRC_CFG_HEAP_SIZE_BELOW_16M +* +* An integer constant that can be used to reduce the buffer usage of memory +* allocation events (malloc/free). This value should be 1 if the heap size is +* below 16 MB (2^24 byte), and you can live with reported addresses showing the +* lower 24 bits only. If 0, you get the full 32-bit addresses. +* +* Default value is 0. +******************************************************************************/ +#define TRC_CFG_HEAP_SIZE_BELOW_16M 0 + +/****************************************************************************** + * TRC_CFG_USE_IMPLICIT_IFE_RULES + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * Tracealyzer groups the events into "instances" based on Instance Finish + * Events (IFEs), produced either by default rules or calls to the recorder + * functions vTraceInstanceFinishedNow and vTraceInstanceFinishedNext. + * + * If TRC_CFG_USE_IMPLICIT_IFE_RULES is one (1), the default IFE rules is + * used, resulting in a "typical" grouping of events into instances. + * If these rules don't give appropriate instances in your case, you can + * override the default rules using vTraceInstanceFinishedNow/Next for one + * or several tasks. The default IFE rules are then disabled for those tasks. + * + * If TRC_CFG_USE_IMPLICIT_IFE_RULES is zero (0), the implicit IFE rules are + * disabled globally. You must then call vTraceInstanceFinishedNow or + * vTraceInstanceFinishedNext to manually group the events into instances, + * otherwise the tasks will appear a single long instance. + * + * The default IFE rules count the following events as "instance finished": + * - Task delay, delay until + * - Task suspend + * - Blocking on "input" operations, i.e., when the task is waiting for the + * next a message/signal/event. But only if this event is blocking. + * + * For details, see trcSnapshotKernelPort.h and look for references to the + * macro trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED. + *****************************************************************************/ +#define TRC_CFG_USE_IMPLICIT_IFE_RULES 1 + +/****************************************************************************** + * TRC_CFG_USE_16BIT_OBJECT_HANDLES + * + * Macro which should be defined as either zero (0) or one (1). + * + * If set to 0 (zero), the recorder uses 8-bit handles to identify kernel + * objects such as tasks and queues. This limits the supported number of + * concurrently active objects to 255 of each type (tasks, queues, mutexes, + * etc.) Note: 255, not 256, since handle 0 is reserved. + * + * If set to 1 (one), the recorder uses 16-bit handles to identify kernel + * objects such as tasks and queues. This limits the supported number of + * concurrent objects to 65535 of each type (object class). However, since the + * object property table is limited to 64 KB, the practical limit is about + * 3000 objects in total. + * + * Default is 0 (8-bit handles) + * + * NOTE: An object with handle above 255 will use an extra 4-byte record in + * the event buffer whenever the object is referenced. Moreover, some internal + * tables in the recorder gets slightly larger when using 16-bit handles. + *****************************************************************************/ +#define TRC_CFG_USE_16BIT_OBJECT_HANDLES 0 + +/****************************************************************************** + * TRC_CFG_USE_TRACE_ASSERT + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * If this is one (1), the TRACE_ASSERT macro (used at various locations in the + * trace recorder) will verify that a relevant condition is true. + * If the condition is false, prvTraceError() will be called, which stops the + * recording and stores an error message that is displayed when opening the + * trace in Tracealyzer. + * + * This is used on several places in the recorder code for sanity checks on + * parameters. Can be switched off to reduce the footprint of the tracing, but + * we recommend to have it enabled initially. + *****************************************************************************/ +#define TRC_CFG_USE_TRACE_ASSERT 1 + +/******************************************************************************* + * TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER + * + * Macro which should be defined as an integer value. + * + * Set TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER to 1 to enable the + * separate user event buffer (UB). + * In this mode, user events are stored separately from other events, + * e.g., RTOS events. Thereby you can get a much longer history of + * user events as they don't need to share the buffer space with more + * frequent events. + * + * The UB is typically used with the snapshot ring-buffer mode, so the + * recording can continue when the main buffer gets full. And since the + * main buffer then overwrites the earliest events, Tracealyzer displays + * "Unknown Actor" instead of task scheduling for periods with UB data only. + * + * In UB mode, user events are structured as UB channels, which contains + * a channel name and a default format string. Register a UB channel using + * xTraceRegisterUBChannel. + * + * Events and data arguments are written using vTraceUBEvent and + * vTraceUBData. They are designed to provide efficient logging of + * repeating events, using the same format string within each channel. + * + * Examples: + * + * traceString chn1 = xTraceRegisterString("Channel 1"); + * traceString fmt1 = xTraceRegisterString("Event!"); + * traceUBChannel UBCh1 = xTraceRegisterUBChannel(chn1, fmt1); + * + * traceString chn2 = xTraceRegisterString("Channel 2"); + * traceString fmt2 = xTraceRegisterString("X: %d, Y: %d"); + * traceUBChannel UBCh2 = xTraceRegisterUBChannel(chn2, fmt2); + * + * // Result in "[Channel 1] Event!" + * vTraceUBEvent(UBCh1); + * + * // Result in "[Channel 2] X: 23, Y: 19" + * vTraceUBData(UBCh2, 23, 19); + * + * You can also use the other user event functions, like vTracePrintF. + * as they are then rerouted to the UB instead of the main event buffer. + * vTracePrintF then looks up the correct UB channel based on the + * provided channel name and format string, or creates a new UB channel + * if no match is found. The format string should therefore not contain + * "random" messages but mainly format specifiers. Random strings should + * be stored using %s and with the string as an argument. + * + * // Creates a new UB channel ("Channel 2", "%Z: %d") + * vTracePrintF(chn2, "%Z: %d", value1); + * + * // Finds the existing UB channel + * vTracePrintF(chn2, "%Z: %d", value2); + + ******************************************************************************/ +#define TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER 0 + +/******************************************************************************* + * TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the user event buffer (UB), in number of slots. + * A single user event can use multiple slots, depending on the arguments. + * + * Only applicable if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER is 1. + ******************************************************************************/ +#define TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE 200 + +/******************************************************************************* + * TRC_CFG_UB_CHANNELS + * + * Macro which should be defined as an integer value. + * + * This defines the number of User Event Buffer Channels (UB channels). + * These are used to structure the events when using the separate user + * event buffer, and contains both a User Event Channel (the name) and + * a default format string for the channel. + * + * Only applicable if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER is 1. + ******************************************************************************/ +#define TRC_CFG_UB_CHANNELS 32 + +/******************************************************************************* + * TRC_CFG_ISR_TAILCHAINING_THRESHOLD + * + * Macro which should be defined as an integer value. + * + * If tracing multiple ISRs, this setting allows for accurate display of the + * context-switching also in cases when the ISRs execute in direct sequence. + * + * vTraceStoreISREnd normally assumes that the ISR returns to the previous + * context, i.e., a task or a preempted ISR. But if another traced ISR + * executes in direct sequence, Tracealyzer may incorrectly display a minimal + * fragment of the previous context in between the ISRs. + * + * By using TRC_CFG_ISR_TAILCHAINING_THRESHOLD you can avoid this. This is + * however a threshold value that must be measured for your specific setup. + * See http://percepio.com/2014/03/21/isr_tailchaining_threshold/ + * + * The default setting is 0, meaning "disabled" and that you may get an + * extra fragments of the previous context in between tail-chained ISRs. + * + * Note: This setting has separate definitions in trcSnapshotConfig.h and + * trcStreamingConfig.h, since it is affected by the recorder mode. + ******************************************************************************/ +#define TRC_CFG_ISR_TAILCHAINING_THRESHOLD 0 + +#endif /*TRC_SNAPSHOT_CONFIG_H*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/FreeRTOSConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/FreeRTOSConfig.h new file mode 100644 index 000000000..d58a0b80f --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/FreeRTOSConfig.h @@ -0,0 +1,210 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * http://www.freertos.org/a00110.html + * + * The bottom of this file contains some constants specific to running the UDP + * stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than + * the demo) are contained in FreeRTOSIPConfig.h. + *----------------------------------------------------------*/ +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Run time stats gathering definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_pcTaskGetTaskName 1 + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS +is set to 2 so the formatting functions are included without the stdio.h being +included in tasks.c. That is because this project defines its own sprintf() +functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* Assert call defined for debug builds. */ +#ifdef _DEBUG + extern void vAssertCalled( const char *pcFile, uint32_t ulLine ); + #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) +#endif /* _DEBUG */ + + + +/* Application specific definitions follow. **********************************/ + +/* Only used when running in the FreeRTOS Windows simulator. Defines the +priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet +or WiFi data to and from a real network connection. Many computers have more +than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell +the demo which real port should be used to create the virtual port. The ports +available are displayed on the console when the application is executed. For +example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 +results in the wired network being used, while setting +configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being +used. */ +#define configNETWORK_INTERFACE_TO_USE 1L + +/* The address of an echo server is only left in this project as it doubles as +the address to which logging is sent should UDP logging be enabled. */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 0 +#define configECHO_SERVER_ADDR3 11 + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet/WiFi data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition above for information on how to +configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x11 +#define configMAC_ADDR3 0x11 +#define configMAC_ADDR4 0x11 +#define configMAC_ADDR5 0x41 + +/* Default IP address configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 10 +#define configIP_ADDR1 10 +#define configIP_ADDR2 10 +#define configIP_ADDR3 200 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DNS is set to +0, or ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 10 +#define configGATEWAY_ADDR1 10 +#define configGATEWAY_ADDR2 10 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. OpenDNS addresses are 208.67.222.222 and +208.67.220.220. Used in ipconfigUSE_DNS is set to 0, or ipconfigUSE_DNS is set +to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 208 +#define configDNS_SERVER_ADDR1 67 +#define configDNS_SERVER_ADDR2 222 +#define configDNS_SERVER_ADDR3 222 + +/* Default netmask configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 0 +#define configNET_MASK2 0 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#if( defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) && !defined( snprintf ) ) + /* Map to Windows names. */ + #define snprintf _snprintf + #define vsnprintf _vsnprintf +#endif + +/* Visual studio does not have an implementation of strcasecmp(). */ +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define strcmpi _strcmpi + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); +#define configPRINTF( X ) vLoggingPrintf X + +#endif /* FREERTOS_CONFIG_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/FreeRTOSIPConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/FreeRTOSIPConfig.h new file mode 100644 index 000000000..6f86009bf --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/FreeRTOSIPConfig.h @@ -0,0 +1,310 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +/***************************************************************************** + * + * See the following URL for configuration information. + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html + * + *****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to +1 then FreeRTOS_debug_printf should be defined to the function used to print +out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 0 +#if( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf(X) vLoggingPrintf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the +FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 +then FreeRTOS_printf should be set to the function used to print out the +messages. */ +#define ipconfigHAS_PRINTF 1 +#if( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf(X) vLoggingPrintf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing +on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading (IP/TCP/UDP checksums) +then set ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software +stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 + +/* Several API's will block until the result is known, or the action has been +performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be +set per socket, using setsockopt(). If not set, the times below will be +used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 5000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for LLMNR: Link-local Multicast Name Resolution +(non-Microsoft) */ +#define ipconfigUSE_LLMNR ( 0 ) + +/* Include support for NBNS: NetBIOS Name Service (Microsoft) */ +#define ipconfigUSE_NBNS ( 0 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very +useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low +and also DNS may use small timeouts. If a DNS reply comes in after the DNS +socket has been destroyed, the result will be stored into the cache. The next +call to FreeRTOS_gethostbyname() will return immediately, without even creating +a socket. */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_NAME_LENGTH ( 64 ) +#define ipconfigDNS_CACHE_ENTRIES ( 4 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make +use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY +sets the priority of the task that executes the IP stack. The priority is a +standard FreeRTOS task priority so can take any value from 0 (the lowest +priority) to (configMAX_PRIORITIES - 1) (the highest priority). +configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in +FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to +the priority assigned to the task executing the IP stack relative to the +priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP +task. This setting is less important when the FreeRTOS Win32 simulator is used +as the Win32 simulator only stores a fixed amount of information on the task +stack. FreeRTOS includes optional stack overflow detection, see: +http://www.freertos.org/Stacks-and-stack-overflow-checking.html */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* ipconfigRAND32() is called by the IP stack to generate random numbers for +things such as a DHCP transaction number or initial sequence number. Random +number generation is performed via this macro to allow applications to use their +own random number generation method. For example, it might be possible to +generate a random number by sampling noise on an analogue input. */ +extern UBaseType_t uxRand(); +#define ipconfigRAND32() uxRand() + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the +network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK +is not set to 1 then the network event hook will never be called. See +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml +*/ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but +a network buffer cannot be obtained then the calling task is held in the Blocked +state (so other tasks can continue to executed) until either a network buffer +becomes available or the send block time expires. If the send block time expires +then the send operation is aborted. The maximum allowable send block time is +capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the +maximum allowable send block time prevents prevents a deadlock occurring when +all the network buffers are in use and the tasks that process (and subsequently +free) the network buffers are themselves blocked waiting for a network buffer. +ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in +milliseconds can be converted to a time in ticks by dividing the time in +milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP +address, netmask, DNS server address and gateway address from a DHCP server. If +ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The +stack will revert to using the static IP address even when ipconfigUSE_DHCP is +set to 1 if a valid configuration cannot be obtained from a DHCP server for any +reason. The static configuration used is that passed into the stack by the +FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 1 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at +increasing time intervals until either a reply is received from a DHCP server +and accepted, or the interval between transmissions reaches +ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the +static IP address passed as a parameter to FreeRTOS_IPInit() if the +re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without +a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( 120000 / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP +stack can only send a UDP message to a remove IP address if it knowns the MAC +address associated with the IP address, or the MAC address of the router used to +contact the remote IP address. When a UDP message is received from a remote IP +address the MAC address and IP address are added to the ARP cache. When a UDP +message is sent to a remote IP address that does not already appear in the ARP +cache then the UDP message is replaced by a ARP message that solicits the +required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum +number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a +maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is +aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP +table being created or refreshed and the entry being removed because it is stale. +New ARP requests are sent for ARP cache entries that are nearing their maximum +age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is +equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling +routines, which are relatively large. To save code space the full +FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster +alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() +takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. +FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets +(for example, 192, 168, 0, 1) as its parameters. If +ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and +FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is +not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that +are available to the IP stack. The total number of network buffers is limited +to ensure the total amount of RAM that can be consumed by the IP stack is capped +to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP +stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can +be queued for processing at any one time. The event queue must be a minimum of +5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port +number. FreeRTOS_bind() is used to manually allocate a port number to a socket +(to 'bind' the socket to a port), but manual binding is not normally necessary +for client sockets (those sockets that initiate outgoing connections rather than +wait for incoming connections on a known port number). If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling +FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP +stack automatically binding the socket to a port number from the range +socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() +on a socket that has not yet been bound will result in the send operation being +aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +#define ipconfigTCP_TIME_TO_LIVE 128 /* also defined in FreeRTOSIPConfigDefaults.h */ + +/* USE_TCP: Use TCP and all its features */ +#define ipconfigUSE_TCP ( 1 ) + +/* Use the TCP socket wake context with a callback. */ +#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT ( 1 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can +contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a +lower value can save RAM, depending on the buffer management scheme used. If +ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must +be divisible by 8. */ +#define ipconfigNETWORK_MTU 1200 + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used +through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will +generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the +FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 0 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() +(and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames +that are not in Ethernet II format will be dropped. This option is included for +potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the +responsibility of the Ethernet interface to filter out packets that are of no +interest. If the Ethernet interface does not implement this functionality, then +set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack +perform the filtering instead (it is much less efficient for the stack to do it +because the packet will already have been passed into the stack). If the +Ethernet driver does all the necessary filtering in hardware then software +filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to +block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with +32-bit memory instructions, all packets will be stored 32-bit-aligned, plus 16-bits. +This has to do with the contents of the IP-packets: all 32-bit fields are +32-bit-aligned, plus 16-bit(!) */ +#define ipconfigPACKET_FILLER_SIZE 2 + +/* Define the size of the pool of TCP window descriptors. On the average, each +TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 +outstanding packets (for Rx and Tx). When using up to 10 TP sockets +simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed +maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 1000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 1000 ) + +/* When using call-back handlers, the driver may check if the handler points to +real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS(x) ( (x) != NULL ) + +/* Include support for TCP hang protection. All sockets in a connecting or +disconnecting stage will timeout after a period of non-activity. */ +#define ipconfigTCP_HANG_PROTECTION ( 1 ) +#define ipconfigTCP_HANG_PROTECTION_TIME ( 30 ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* in seconds */ + +#define portINLINE __inline + +#endif /* FREERTOS_IP_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/READ_ME_INSTRUCTIONS.url b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/READ_ME_INSTRUCTIONS.url new file mode 100644 index 000000000..8a5a8617e --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/READ_ME_INSTRUCTIONS.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/mqtt/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/WIN32.vcxproj b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/WIN32.vcxproj new file mode 100644 index 000000000..dc46a77f3 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/WIN32.vcxproj @@ -0,0 +1,620 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {C686325E-3261-42F7-AEB1-DDE5280E1CEB} + RTOSDemo + 10.0 + + + + Application + false + MultiByte + v142 + + + Application + false + MultiByte + v142 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Debug\ + .\Debug\ + true + .\Release\ + .\Release\ + false + AllRules.ruleset + + + + .\Debug/WIN32.tlb + + + + + Disabled + ..\..\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;..\common;..\common\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\src;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\mbedtls;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\platform;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\mqtt\include;..\..\..\..\Source\mbedtls\include;.;%(AdditionalIncludeDirectories) + MBEDTLS_CONFIG_FILE="mbedtls_config.h";WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDLL + .\Debug/WIN32.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level4 + true + false + EditAndContinue + /wd4210 /wd4127 /wd4214 /wd4201 /wd4244 /wd4310 /wd4200 %(AdditionalOptions) + true + NotUsing + false + CompileAsC + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Debug/RTOSDemo.exe + true + true + .\Debug/WIN32.pdb + Console + MachineX86 + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + ..\common\WinPCap + false + false + + + true + .\Debug/WIN32.bsc + + + + + .\Release/WIN32.tlb + + + + + MaxSpeed + OnlyExplicitInline + MBEDTLS_CONFIG_FILE="mbedtls_config.h";_WINSOCKAPI_;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release/WIN32.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + ..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;.\DemoTasks\include;.\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\src;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\mbedtls;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\platform;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\mqtt\include;..\..\..\..\Source\mbedtls\include;.;%(AdditionalIncludeDirectories) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Release/RTOSDemo.exe + true + .\Release/WIN32.pdb + Console + MachineX86 + .\WinPCap + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + + + true + .\Release/WIN32.bsc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/WIN32.vcxproj.filters b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/WIN32.vcxproj.filters new file mode 100644 index 000000000..0738e0a8b --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/WIN32.vcxproj.filters @@ -0,0 +1,789 @@ + + + + + {af3445a1-4908-4170-89ed-39345d90d30c} + + + {f32be356-4763-4cae-9020-974a2638cb08} + *.c + + + {88f409e6-d396-4ac5-94bd-7a99c914be46} + + + {e5ad4ec7-23dc-4295-8add-2acaee488f5a} + + + {d2dcd641-8d91-492b-852f-5563ffadaec6} + + + {8672fa26-b119-481f-8b8d-086419c01a3e} + + + {4570be11-ec96-4b55-ac58-24b50ada980a} + + + {5d93ed51-023a-41ad-9243-8d230165d34b} + + + {b71e974a-9f28-4815-972b-d930ba8a34d0} + + + {60717407-397f-4ea5-8492-3314acdd25f0} + + + {8a90222f-d723-4b4e-8e6e-c57afaf7fa92} + + + {7c995f05-2a10-4771-ad77-18a755876e46} + + + {9a636cc3-ebc6-48c5-8c18-c72494686e81} + + + {29376c48-bc8b-4624-ad59-16807874c9f2} + + + {91ef4008-de51-4b41-ba5e-bf24d8cda378} + + + {ade43c6c-04c5-4897-abdb-91af2df04e5d} + + + {08a4e35c-19ca-4b1e-af24-bac368c2bf7b} + + + {1e324500-91b4-4c76-b699-59ba75691760} + + + {bdcbc1ec-99b8-4c72-9075-49035c115488} + + + {2d17d5e6-ed70-4e42-9693-f7a63baf4948} + + + {7158b0be-01e7-42d1-8d3f-c75118a596a2} + + + {6ad56e6d-c330-4830-8f4b-c75b05dfa866} + + + {1d80b387-5a86-4744-a4cc-930033a52e4b} + + + {1cecca7f-60cd-4d8d-8123-f00aa75af147} + + + {f9a2e0a1-ed56-4ca7-b8b2-d694a94c78c0} + + + {61ac8e2c-8fd1-44a0-a7a9-0326bc190426} + + + {b53bfe50-b4d9-4b78-b7bb-ae90e4d25615} + + + {f7bebbc3-22c6-461c-98d6-a4e44cbcca00} + + + {e5377363-356a-4b0c-88ea-bad4f966f9ff} + + + {484626f0-0f84-46bc-89ff-54732d24f271} + + + + + FreeRTOS\Source\Portable + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS\Source + + + FreeRTOS\Source\Portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\mbedtls + + + + + DemoTasks + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos\include\platform + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\mbedtls + + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform + + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/demo_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/demo_config.h new file mode 100644 index 000000000..6639d2407 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/demo_config.h @@ -0,0 +1,78 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef DEMO_CONFIG_H +#define DEMO_CONFIG_H + +/* + * This configuration file determines how MQTT demo is run. + * + * mqtt_plain_text demo: Security is turned off. Preconfigured to a public MQTT + * broker on unencrypted port so no authentication configuration required. + * + * mqtt_basic_tls_server_auth demo: TLS security is enabled, allowing broker side + * authentication. Preconfigured to a public MQTT broker with certificate provided + * by the broker so no authentication configuration required. + * + * mqtt_tls_mutual_auth demo: Mutual authentication is enabled. Preconfigured to + * AWS IoT broker, will require certificate setup for successful connection. + */ + +/** + * @brief Enable/Disable TLS in demos. + * + * For more information regarding TLS protocol: + * https://www.freertos.org/mqtt/tls.html + */ +#define democonfigENABLE_TLS 1 + +/** + * @brief Enable/Disable mutual authentication in demos. If enabled, require + * democonfigENABLE_TLS to be set to 1. + */ +#define democonfigENABLE_MUTUAL_AUTH 1 + +/** + * @brief Select a connection profile. + * + * If set to 1, the demo will connect to AWS IoT with credential setup in + * aws_iot_demo_profile.h file, otherwise the demo is preconfigured to connect to + * test.mosquitto.org with credential setup in mqtt_demo_profile.h file. If + * enabled, requires democonfigENABLE_MUTUAL_AUTH to be set to 1 since AWS IoT + * requires mutually authenticated connection. + */ +#define democonfigPROFILE_USE_AWS_IOT 1 + +/** + * @brief Set the stack size of the main demo task. + * + * In the Windows port, this stack only holds a structure. The actual + * stack is created by an operating system thread. + */ +#define democonfigDEMO_STACKSIZE configMINIMAL_STACK_SIZE + +#endif /* DEMO_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/iot_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/iot_config.h new file mode 100644 index 000000000..1c08ac44a --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/iot_config.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/* This file contains configuration settings for the demos. */ + +#ifndef IOT_CONFIG_H_ +#define IOT_CONFIG_H_ + +/* Configure the IoT Libraries for FreeRTOS by including the FreeRTOS header and + * the FreeRTOS platform types. */ +#include "FreeRTOS.h" +#include "platform/iot_platform_types_freertos.h" + +/** + * @brief Set a global default for log levels. + * + * This setting is overridden by log level settings of specific libraries. + * Undefined library-specific log levels will default to this value. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_GLOBAL IOT_LOG_NONE + +/** + * @brief Set the log level of the platform libraries except the network + * component. + * + * Log messages from the platform libraries at or below this setting + * will be printed. As the network component is more verbose, its logging + * is controlled by its own setting, IOT_LOG_LEVEL_NETWORK. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_PLATFORM IOT_LOG_NONE + +/** + * @brief Set the log level of the platform network library. + * + * Log messages from the platform network library at or below this setting + * will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_NETWORK IOT_LOG_WARN + +/* + * @brief Set the log level of the task pool library. + * + * Log messages from the task pool library at or below this setting will be + * printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_TASKPOOL IOT_LOG_WARN + +/** + * @brief Set the log level of the MQTT library. + * + * Log messages from the MQTT library at or below this setting will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_MQTT IOT_LOG_WARN + +/** + * @brief Enable/Disable asserts for the task pool library. + * + * Set this to 1 to perform sanity checks when using the task pool library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotTaskPool_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_TASKPOOL_ENABLE_ASSERTS 1 + +/** + * @brief The numer of worker tasks in the task pool. + * + * The full IoT Task Pool Library has many use cases, including Linux + * development. Typical FreeRTOS use cases do not require the full + * functionality so an optimized implementation is provided specifically for use + * with FreeRTOS. The optimized version has a fixed number of tasks in the + * task pool, each of which uses statically allocated memory to ensure creation + * of the task pool is guaranteed (it does not run out of heap space). + */ +#define IOT_TASKPOOL_NUMBER_OF_WORKERS 1 + +/** + * @brief The stack size (in bytes) for each worker task in the task pool. + * + * The minimal version of the of task pool library only supports one task pool + * and the configuration of each worker task fixed at the compile time. + */ +#define IOT_TASKPOOL_WORKER_STACK_SIZE_BYTES 2048 + +/** + * @brief Enable TLS in the network abstraction. + * + * The TLS implementation requires the mbed TLS library. + */ +#define IOT_NETWORK_ENABLE_TLS 1 + +/** + * @brief Enable/Disable asserts for the linear containers library. + * + * Set this to 1 to perform sanity checks when using the linear containers library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotContainers_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_CONTAINERS_ENABLE_ASSERTS 1 + +/** + * @brief Enable/Disable asserts for the MQTT library. + * + * Set this to 1 to perform sanity checks when using the MQTT library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotMqtt_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_MQTT_ENABLE_ASSERTS 1 + +/** + * @brief Enable/Disable anonymous metrics collection when using AWS IoT. + */ +#define AWS_IOT_MQTT_ENABLE_METRICS 0 + +/* Common settings for FreeRTOS; settings below this line generally do not need + * to be changed. */ + +/* Logging puts function on FreeRTOS. */ +#define IotLogging_Puts( str ) configPRINTF( ( "%s\r\n", str ) ) + +/* Assert functions on FreeRTOS. */ +#define Iot_DefaultAssert configASSERT + +/* Memory allocation functions on FreeRTOS. */ +#define Iot_DefaultMalloc pvPortMalloc +#define Iot_DefaultFree vPortFree + +#endif /* ifndef IOT_CONFIG_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/mqtt_tls_mutual_auth_demo.sln b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/mqtt_tls_mutual_auth_demo.sln new file mode 100644 index 000000000..87ec5ca1f --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/mqtt_tls_mutual_auth_demo.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29215.179 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTOSDemo", "WIN32.vcxproj", "{C686325E-3261-42F7-AEB1-DDE5280E1CEB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.ActiveCfg = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.Build.0 = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.ActiveCfg = Release|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {16F43B15-ED4F-44E5-927C-29DF92B9F2E3} + EndGlobalSection + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = FreeRTOS_Plus_TCP_Minimal.vsmdi + EndGlobalSection +EndGlobal diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/readme.txt b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/readme.txt new file mode 100644 index 000000000..1dd11e2b2 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/mqtt_tls_mutual_auth/readme.txt @@ -0,0 +1,3 @@ +The MQTT mutual auth project will be added shortly. In the mean time +https://github.com/aws/amazon-freertos provides demos with complete IoT +integrations that include mutually authenticated MQTT connections. \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/readme.txt b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/readme.txt new file mode 100644 index 000000000..7d32bd344 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt/readme.txt @@ -0,0 +1,26 @@ +See https://freertos.org/mqtt/ for further information. + +Contains projects that demonstrate the IoT MQTT library. + +- Securing MQTT Communication - +Internet of Things use cases require MQTT communications to be secured, but secure +authentication and encryption are not part of the MQTT specification. It is +therefore common to use MQTT in combination with Transport Layer Security (TLS). +TLS encrypts data sent across a network and enables the data's destination to be +authenticated. 'Server authentication' is when the MQTT client authenticates the +identity of the MQTT broker. 'Mutual authentication' is when the MQTT broker also +authenticates the identity of the MQTT client. + + +- Pre-configured MQTT Example Projects - +The examples contained in subdirectories from here demonstrate the concepts +described above one at a time. The first example demonstrates plain text +(unencrypted) MQTT communication, the second example builds on the first to +introduce weak server authentication, and the third example builds on the second to +introduce strong mutual authentication. Note: It is our recommendation to always +use strong mutual authentication in any Internet of Things (IoT) application. The +plain text project is only provided to validate MQTT communication can be +established prior to introducing encryption and authentication, and to allow the +MQTT packets to be observed using a network packet sniffer such as Wireshark for +those who wish to do so. The first two projects are in no way intended to be +examples suitable for production use. diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/readme.txt b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/readme.txt new file mode 100644 index 000000000..d62db29e5 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/readme.txt @@ -0,0 +1,51 @@ +*** IMPORTANT NOTE *** + +FreeRTOS-Labs contains libraries and demos that are fully functional, but +undergoing optimizations or refactoring to improve memory usage, modularity, +documentation, demo usability, or test coverage. At this time the projects ARE +A WORK IN PROGRESS and will be released in the main FreeRTOS directories of the +download following full review and completion of the documentation. + + +*** INTRODUCTION *** + +This distribution currently contains demos from the FreeRTOS task pool library, +MQTT library, HTTPS Client library, Shadow library, and Jobs library. + +The pre-configured projects use the FreeRTOS kernel Windows port (often +called the Windows simulator) to enable their evaluation using the free Visual +Studio tools and without needing specific microcontroller hardware. + + +*** INSTRUCTIONS *** + +Instructions for configuring and using the FreeRTOS IoT libraries are in the +following links: + + + https://www.FreeRTOS.org/task-pool/ + + https://www.FreeRTOS.org/mqtt/ + + https://www.freertos.org/https/ + + https://www.FreeRTOS.org/shadow/ + + https://www.FreeRTOS.org/jobs/ + + +*** LOCATING THE EXAMPLE PROJECTS *** + +The Visual Studio projects for each of the FreeRTOS IoT library examples are +located in sub-directories of the following top-level directories: + + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs + + +*** ADDITIONAL INFORMATION *** + +See http://www.freertos.org/a00017.html for full details of the FreeRTOS +directory structure + +See also - +http://www.freertos.org/FreeRTOS-quick-start-guide.html +http://www.freertos.org/FAQHelp.html diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/readme.txt b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/readme.txt new file mode 100644 index 000000000..7cc62036a --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/readme.txt @@ -0,0 +1,8 @@ +See https://freertos.org/shadow/ for further information. + +Contains projects that demonstrate the Shadow library. + +A device's Shadow is a JSON document that is used to store and retrieve current +state information for a device in AWS (Amazon Web Services) Cloud. Please refer to +the AWS documentation for more details about Device Shadow service. +https://docs.aws.amazon.com/iot/latest/developerguide/iot-device-shadows.html diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/DemoTasks/ShadowDeviceOperationsExamples.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/DemoTasks/ShadowDeviceOperationsExamples.c new file mode 100644 index 000000000..614e2614c --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/DemoTasks/ShadowDeviceOperationsExamples.c @@ -0,0 +1,1065 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* A device's Shadow is a JSON document that is used to store and retrieve + * current state information for a device in AWS (Amazon Web Services) Cloud. + * Please refer to the AWS documentation for more details about Device Shadow + * service. + * https://docs.aws.amazon.com/iot/latest/developerguide/iot-device-shadows.html + * + * This demo creates a single application task that loops through a set of + * examples that demonstrates usage of Shadow library. Please find the list of + * Shadow operations and callbacks used in this demo below. + * Shadow Delete - Deletes the Shadow document of the device. + * Shadow Update - Updates the Shadow document with JSON document + * provided. + * Shadow Delta Callback - Callback to be invoked when Shadow document is + * updated with different desired and reported + * states. + * Shadow Updated Callback - Callback to be invoked when a Shadow document is + * updated. + * + * The demo program uses Shadow Update and Shadow Delta Callbacks to simulate + * toggling a remote device's state. It sends a Shadow Update with a new + * desired state and waits for the device to change its reported state in + * Shadow Delta Callback as a response to the new desired state. In addition, + * a Shadow Updated Callback is used to print the changing Shadow states. + * Shadow Updates are done #shadowexampleUPDATE_COUNT times in each loop.At the + * end of each loop Shadow document is deleted using Shadow Delete. + * + * In this demo both update to the desired state of Shadow document and + * response to it by updating the reported state is done in the same + * application. This is to illustrate the capability of the Shadow service and + * library in a single demo. Ideally the update to the desired state can be + * from an external application to control the state of the device. This demo + * is meant to demonstrate the usage of different Shadow library APIs. + * + * The Shadow demo uses a MQTT connection to connect to Shadow Service in AWS. + * Mutual authentication between AWS IoT MQTT Broker and Device is required to + * run this demo. Please complete configurations in aws_iot_demo_profile.h for + * mutual authentication. + * More details for mutual authentication configuration can be found at + * https://www.freertos.org/mqtt/preconfiguredexamplesMA.html + * + * Note: The parser used in this demo is specific for parsing AWS IoT document + * received through a mutually authenticated connection with AWS IoT MQTT + * broker. This parser will not check for the correctness of the document as it + * is designed for low memory footprint rather than checking for correctness of + * the JSON document. This parser is not meant to be used as a general purpose + * JSON parser. + */ + +/* Standard includes. */ +#include +#include + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" + +/* IoT SDK includes. */ +#include "aws_iot_shadow.h" +#include "aws_iot_demo_profile.h" +#include "iot_mqtt.h" +#include "iot_taskpool_freertos.h" +#include "aws_iot_doc_parser.h" +#include "platform/iot_clock.h" +#include "platform/iot_threads.h" +#include "platform/iot_network_freertos.h" + +/* Preprocessor check iot configuration */ +#include "aws_iot_setup_check.h" + +/* Demo specific includes. */ +#include "demo_config.h" + +/** + * @brief The keep-alive interval used for this example. + * + * An MQTT ping request will be sent periodically at this interval. + * + * @note: This value is set to zero to disable MQTT + * keep alive for the Windows simulator project. + * The FreeRTOS kernel does not accurately calculate time for the Windows + * Simulator. Therefore, MQTT PING Request messages may be sent + * at an incorrect time interval to the broker. If the broker does + * not receive a ping request within 1.5x the time sent in a + * connection request, the broker may close the connection. + * To enable the keep alive feature, set this value + * to the desired interval in seconds. + */ +#define shadowexampleKEEP_ALIVE_SECONDS ( 0 ) + +/** + * @brief The timeout for MQTT operations in this example. + */ +#define shadowexampleMQTT_TIMEOUT_MS ( 5000 ) + +/** + * @brief Update count of shadow in a loop in the demo. + * + */ +#define shadowexampleUPDATE_COUNT ( 20 ) + +/** + * @brief The task wait period between each Shadow update. + * + */ +#define shadowexampleUPDATE_PERIOD_MS ( 3000 ) + +/** + * @brief The task wait period between each demo loop. + */ +#define shadowexampleLOOP_WAIT_PERIOD_MS ( 5000 ) + +/** + * @brief The timeout period for updates from Shadow Delta Callback before + * attempting next Shadow Update. + */ +#define shadowexampleWAIT_PERIOD_FOR_DELTA_MS ( 5000 ) + +/** + * @brief Argument for AwsIotShadow_Init to use the default timeout. + */ +#define shadowexampleUSE_DEFAULT_MQTT_TIMEOUT ( 0 ) + +/** + * @brief The bit which is set in the demo task's notification value from the + * disconnect callback to inform the demo task about the MQTT disconnect. + */ +#define shadowexampleDISCONNECTED_BIT ( 1UL << 0UL ) + +/** + * @brief Compile time calculation of shadowexampleCLIENT_IDENTIFIER_LENGTH. + */ +#define shadowexampleCLIENT_IDENTIFIER_LENGTH sizeof( awsiotdemoprofileCLIENT_IDENTIFIER ) - 1 + +/** + * @brief Format string representing a Shadow document with a "desired" state. + * + * Note the client token, which is required for all Shadow updates. The client + * token must be unique at any given time, but may be reused once the update is + * completed. For this demo, a timestamp is used for a client token. + */ +#define shadowexampleDESIRED_JSON \ + "{" \ + "\"state\":{" \ + "\"desired\":{" \ + "\"powerOn\":%01d" \ + "}" \ + "}," \ + "\"clientToken\":\"%06lu\"" \ + "}" + +/** + * @brief The expected size of #shadowexampleDESIRED_JSON. + * + * Because all the format specifiers in #shadowexampleDESIRED_JSON include a + * length, its full size is known at compile-time. + */ +#define shadowexampleDESIRED_JSON_SIZE ( sizeof( shadowexampleDESIRED_JSON ) - 3 ) + +/** + * @brief Format string representing a Shadow document with a "reported" state. + * + * Note the client token, which is required for all Shadow updates. The client + * token must be unique at any given time, but may be reused once the update is + * completed. For this demo, a timestamp is used for a client token. + */ +#define shadowexampleREPORTED_JSON \ + "{" \ + "\"state\":{" \ + "\"reported\":{" \ + "\"powerOn\":%01d" \ + "}" \ + "}," \ + "\"clientToken\":\"%06lu\"" \ + "}" + +/** + * @brief The expected size of #shadowexampleREPORTED_JSON. + * + * Because all the format specifiers in #shadowexampleREPORTED_JSON include a + * length, its full size is known at compile-time. + */ +#define shadowexampleREPORTED_JSON_SIZE ( sizeof( shadowexampleREPORTED_JSON ) - 3 ) + +/** +* @brief This is the current state of the shadow used in this demo. +*/ +static int32_t lDevicePowerOnState = 0; + +/** + * @brief This is a Semaphore used to synchronize between delta callback and + * Shadow updates. + */ +iot_sem_internal_t xDeltaSemaphore = { 0 }; + +/** + * @brief The task used to demonstrate Shadow. + * + * @param[in] pvParameters Parameters as passed at the time of task creation. Not + * used in this example. + * + */ +static void prvShadowDemoTask( void *pvParameters ); + +/** + * @brief The callback invoked by the MQTT library when the MQTT connection gets + * disconnected. + * + * @param[in] pvCallbackContext Callback context as provided at the time of + * connect. + * @param[in] pxCallbackParams Contains the reason why the MQTT connection was + * disconnected. + */ +static void prvExample_OnDisconnect( void * pvCallbackContext, + IotMqttCallbackParam_t * pxCallbackParams ); + +/** + * @brief The callback invoked by the MQTT library when a message is received on + * a subscribed topic from the MQTT broker. + * + * @param[in] pvCallbackContext Callback context as provided at the time of + * subscribe. + * @param[in] pxCallbackParams Contain the details about the received message - + * topic on which the message was received, the received message. + */ +static void prvExample_OnMessageReceived( void * pvCallbackContext, + IotMqttCallbackParam_t * pxCallbackParams ); + +/** + * @brief Connects to the MQTT broker as specified in awsiotdemoprofileAWS_ENDPOINT + * and awsiotdemoprofileAWS_MQTT_PORT. + * + */ +static void prvMQTTConnect( void ); + +/** + * @brief Disconnects from the MQTT broker gracefully by sending an MQTT + * DISCONNECT message. + * + */ +static void prvMQTTDisconnect( void ); + +/** +* @brief Initializes the IoT libraries used by this demo. +*/ +static void prvInitialiseLibraries( void ); + +/** + * @brief The MQTT connection handle used in this example. + */ +static IotMqttConnection_t xMQTTConnection = IOT_MQTT_CONNECTION_INITIALIZER; + +/** + * @brief Set the Shadow callback functions used in this demo. + * + * There are 2 Shadow callbacks set by this function. updated callback + * and delta Callback. + * + */ +static void prvSetShadowCallbacks( void ); + +/** + * @brief Clear the Shadow callbacks. + * + * There are 2 Shadow callbacks cleared by this function. updated callback + * and delta Callback. + * + */ +static void prvClearShadowCallbacks( void ); + +/** + * @brief Try to delete any Shadow document in the cloud. + * + */ +static void prvClearShadowDocument( void ); + +/** + * @brief Send the Shadow updates that will trigger the Shadow callbacks. + * + */ +static void prvSendShadowUpdates( void ); + +/** + * @brief Shadow delta callback, invoked when the desired and updates Shadow + * states differ. + * + * This function simulates a device updating its state in response to a Shadow. + * + * @param[in] pCallbackContext Delta semaphore used to synchronize between + * delta callback and updated callback. + * @param[in] pxCallbackParam The received Shadow delta document. + */ +static void prvShadowDeltaCallback( void * pCallbackContext, + AwsIotShadowCallbackParam_t * pxCallbackParam ); + +/** + * @brief Shadow updated callback, invoked when the Shadow document changes. + * + * This function reports when a Shadow has been updated. + * + * @param[in] pCallbackContext Not used. + * @param[in] pxCallbackParam The received Shadow updated document. + */ +static void prvShadowUpdatedCallback( void * pCallbackContext, + AwsIotShadowCallbackParam_t * pxCallbackParam ); + +/** + * @brief Parses a key in the "state" section of a Shadow delta document. + * + * @param[in] pcDeltaDocument The Shadow delta document to parse. + * @param[in] xDeltaDocumentLength The length of `pcDeltaDocument`. + * @param[in] pcDeltaKey The key in the delta document to find. Must be NULL-terminated. + * @param[out] ppcDelta Set to the first character in the delta key. + * @param[out] pxDeltaLength The length of the delta key. + * + * @return `true` if the given delta key is found; `false` otherwise. + */ +static BaseType_t prvGetDelta( const char * pcDeltaDocument, + size_t xDeltaDocumentLength, + const char * pcDeltaKey, + const char ** ppcDelta, + size_t * pxDeltaLength ); + +/** + * @brief Parses the "state" key from the "previous" or "current" sections of a + * Shadow updated document. + * + * @param[in] pcUpdatedDocument The Shadow updated document to parse. + * @param[in] xUpdatedDocumentLength The length of `pcUpdatedDocument`. + * @param[in] pcSectionKey Either "previous" or "current". Must be NULL-terminated. + * @param[out] ppcState Set to the first character in "state". + * @param[out] pxStateLength Length of the "state" section. + * + * @return pdTRUE if the "state" was found; pdFALSE otherwise. + */ +static BaseType_t prvGetUpdatedState( const char * pcUpdatedDocument, + size_t xUpdatedDocumentLength, + const char * pcSectionKey, + const char ** ppcState, + size_t * pxStateLength ); + +/*-----------------------------------------------------------*/ + +/** + * @brief Parameters used to create the system task pool. + */ +static const IotTaskPoolInfo_t xTaskPoolParameters = +{ + /* Minimum number of threads in a task pool. + * Note the slimmed down version of the task + * pool used by this library does not auto-scale + * the number of tasks in the pool so in this + * case this sets the number of tasks in the + * pool. */ + 1, + + /* Maximum number of threads in a task pool. + * Note the slimmed down version of the task + * pool used by this library does not auto-scale + * the number of tasks in the pool so in this + * case this parameter is just ignored. */ + 1, + + /* Stack size for every task pool thread - in + * bytes, hence multiplying by the number of bytes + * in a word as configMINIMAL_STACK_SIZE is + * specified in words. */ + configMINIMAL_STACK_SIZE * sizeof( portSTACK_TYPE ), + /* Priority for every task pool thread. */ + tskIDLE_PRIORITY, +}; + +/*-----------------------------------------------------------*/ + +static const struct IotNetworkServerInfo xMQTTBrokerInfo = +{ + .pHostName = awsiotdemoprofileAWS_ENDPOINT, + .port = awsiotdemoprofileAWS_MQTT_PORT +}; + +static struct IotNetworkCredentials xNetworkSecurityCredentials = +{ + /* Optional TLS extensions. For this demo, they are disabled. */ + .pAlpnProtos = NULL, + .maxFragmentLength = 0, + + /* SNI is enabled by default. */ + .disableSni = false, + + /* Provide the certificate for validating the server. Only required for + demos using TLS. */ + .pRootCa = awsiotdemoprofileAWS_CERTIFICATE_PEM, + .rootCaSize = sizeof( awsiotdemoprofileAWS_CERTIFICATE_PEM ), + + /* Strong mutual authentication to authenticate both the broker and + * the client. */ + .pClientCert = awsiotdemoprofileCLIENT_CERTIFICATE_PEM, + .clientCertSize = sizeof( awsiotdemoprofileCLIENT_CERTIFICATE_PEM ), + .pPrivateKey = awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM, + .privateKeySize = sizeof( awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM ) +}; + +static IotMqttNetworkInfo_t xNetworkInfo = +{ + /* No connection to the MQTT broker has been established yet and we want to + * establish a new connection. */ + .createNetworkConnection = true, + .u.setup.pNetworkServerInfo = &( xMQTTBrokerInfo ), + + /* Set the TLS credentials for the new MQTT connection. This member is NULL + * for the plain text MQTT demo. */ + .u.setup.pNetworkCredentialInfo = &xNetworkSecurityCredentials, + + /* Use FreeRTOS+TCP network interface. */ + .pNetworkInterface = IOT_NETWORK_INTERFACE_FREERTOS, + + /* Setup the callback which is called when the MQTT connection is + * disconnected. The task handle is passed as the callback context which + * is used by the callback to send a task notification to this task.*/ + .disconnectCallback.function = prvExample_OnDisconnect +}; + + +static const IotMqttConnectInfo_t xConnectInfo = +{ + /* Set this flag to true if connecting to the AWS IoT MQTT broker. */ + .awsIotMqttMode = true, + + /* Start with a clean session i.e. direct the MQTT broker to discard any + * previous session data. Also, establishing a connection with clean session + * will ensure that the broker does not store any data when this client + * gets disconnected. */ + .cleanSession = true, + + /* Since we are starting with a clean session, there are no previous + * subscriptions to be restored. */ + .pPreviousSubscriptions = NULL, + .previousSubscriptionCount = 0, + + /* We do not want to publish Last Will and Testament (LWT) message if the + * client gets disconnected. */ + .pWillInfo = NULL, + + /* Send an MQTT PING request every minute to keep the connection open if + there is no other MQTT traffic. */ + .keepAliveSeconds = shadowexampleKEEP_ALIVE_SECONDS, + + /* The client identifier is used to uniquely identify this MQTT client to + * the MQTT broker. In a production device the identifier can be something + * unique, such as a device serial number. */ + .pClientIdentifier = awsiotdemoprofileCLIENT_IDENTIFIER, + .clientIdentifierLength = ( uint16_t ) sizeof( awsiotdemoprofileCLIENT_IDENTIFIER ) - 1, + + /* This example does not authenticate the client and therefore username and + * password fields are not used. */ + .pUserName = NULL, + .userNameLength = 0, + .pPassword = NULL, + .passwordLength = 0 +}; +/*-----------------------------------------------------------*/ + +void vStartShadowDeviceOperationsDemo( void ) +{ +TickType_t xShortDelay = ( TickType_t ) pdMS_TO_TICKS( ( TickType_t ) 500 ); + + /* Wait a short time to allow receipt of the ARP replies. */ + vTaskDelay( xShortDelay ); + + /* This example uses a single application task, which in turn is used to + * connect, subscribe, publish, unsubscribe and disconnect from the MQTT + * broker. */ + xTaskCreate( prvShadowDemoTask, /* Function that implements the task. */ + "ShadowDemo", /* Text name for the task - only used for debugging. */ + democonfigDEMO_STACKSIZE,/* Size of stack (in words, not bytes) to allocate for the task. */ + NULL, /* Task parameter - not used in this case. */ + tskIDLE_PRIORITY, /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */ + NULL ); /* Used to pass out a handle to the created task - not used in this case. */ +} +/*-----------------------------------------------------------*/ + +static void prvShadowDemoTask( void *pvParameters ) +{ +uint32_t ulNotificationValue = 0; +const TickType_t xNoDelay = ( TickType_t ) 0; + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + /* One time initialization of the libraries used by this demo. */ + prvInitialiseLibraries(); + + for( ; ; ) + { + /* Don't expect any notifications to be pending yet. */ + configASSERT( ulTaskNotifyTake( pdTRUE, xNoDelay ) == 0 ); + + /****************************** Connect. ******************************/ + + /* Establish a connection to the AWS IoT MQTT broker. This example connects to + * the MQTT broker as specified in awsiotdemoprofileAWS_ENDPOINT and + * awsiotdemoprofileAWS_MQTT_PORT at the top of this file. + */ + configPRINTF( ( "Attempt to connect to %s\r\n", awsiotdemoprofileAWS_ENDPOINT ) ); + prvMQTTConnect(); + configPRINTF( ( "Connected to %s\r\n", awsiotdemoprofileAWS_ENDPOINT ) ); + + /************************ Create a semaphore **************************/ + + /* Creates a semaphore to synchronize between delta callback and + * Shadow updates. + */ + configPRINTF( ( "Creating delta semaphore\r\n" ) ); + configASSERT( xSemaphoreCreateCountingStatic( 1, 0, &xDeltaSemaphore.xSemaphore ) != NULL ); + + /************************ Set shadow callbacks ************************/ + + /* Sets the updated callback and delta callback */ + configPRINTF( ( "Setting the updated callback and delta callback\r\n" ) ); + prvSetShadowCallbacks(); + + /************************ Clear shadow document ***********************/ + + /* Clears the Shadow document if it exists already */ + configPRINTF( ( "Clearing the Shadow document if it already exits\r\n" ) ); + prvClearShadowDocument(); + + /*********************** Send Shadow updates **************************/ + + /* Send Shadow updates for shadowexampleUPDATE_COUNT times. + * For each Shadow update, it waits on xDeltaSemaphore. xDeltaSemaphore + * will be posted by the delta callback. + */ + configPRINTF( ( "Sending Shadow updates\r\n" ) ); + prvSendShadowUpdates(); + + /************************ Clear shadow document ***********************/ + + /* Clears the Shadow document at the end of the demo */ + configPRINTF( ( "Clearing the Shadow document\r\n" ) ); + prvClearShadowDocument(); + + /************** Clear callbacks and Disconnect MQTT. ******************/ + + /* Clear updated callback and delta callback */ + configPRINTF( ( "Clearing the Shadow updated callback and delta callback\r\n" ) ); + prvClearShadowCallbacks(); + + /* Disconnect MQTT gracefully. */ + prvMQTTDisconnect(); + configPRINTF( ( "Disconnected from %s\r\n\r\n", awsiotdemoprofileAWS_ENDPOINT ) ); + + /* Wait for the disconnect operation to complete which is informed to us + * by the disconnect callback (prvExample_OnDisconnect)by setting + * the shadowexampleDISCONNECTED_BIT in this task's notification value. + * Note that the bit is cleared in the task's notification value to + * ensure that it is ready for the next run. */ + xTaskNotifyWait( 0UL, /* Don't clear any bits on entry. */ + shadowexampleDISCONNECTED_BIT, /* Clear bit on exit. */ + &( ulNotificationValue ), /* Obtain the notification value. */ + pdMS_TO_TICKS( shadowexampleMQTT_TIMEOUT_MS ) ); + configASSERT( ( ulNotificationValue & shadowexampleDISCONNECTED_BIT ) == shadowexampleDISCONNECTED_BIT ); + + /* Destroy the delta semaphore*/ + vSemaphoreDelete( ( SemaphoreHandle_t ) &xDeltaSemaphore.xSemaphore ); + + /* Clear the current reported shadow state to toggle the reported state. */ + lDevicePowerOnState = 0; + + /* Wait for some time between two iterations to ensure that we do not + * bombard the broker. */ + configPRINTF( ( "prvShadowDemoTask() completed an iteration successfully. Total free heap is %u\r\n", xPortGetFreeHeapSize() ) ); + configPRINTF( ( "Demo completed successfully.\r\n" ) ); + configPRINTF( ( "Short delay before starting the next iteration... \r\n\r\n" ) ); + vTaskDelay( pdMS_TO_TICKS( shadowexampleLOOP_WAIT_PERIOD_MS ) ); + } +} +/*-----------------------------------------------------------*/ + +static void prvExample_OnDisconnect( void * pvCallbackContext, + IotMqttCallbackParam_t * pxCallbackParams ) +{ +TaskHandle_t xDemoTaskHandle = ( TaskHandle_t ) pvCallbackContext; + + /* Ensure that we initiated the disconnect. */ + configASSERT( pxCallbackParams->u.disconnectReason == IOT_MQTT_DISCONNECT_CALLED ); + + /* Inform the demo task about the disconnect. */ + xTaskNotify( xDemoTaskHandle, + shadowexampleDISCONNECTED_BIT, + eSetBits /* Set the shadowexampleDISCONNECTED_BIT in the demo task's notification value. */ + ); +} +/*-----------------------------------------------------------*/ + +static void prvMQTTConnect( void ) +{ +IotMqttError_t xResult; + + /* Set the context to pass into the disconnect callback function. */ + xNetworkInfo.disconnectCallback.pCallbackContext = ( void * ) xTaskGetCurrentTaskHandle(); + + /* Establish the connection to the MQTT broker - It is a blocking call and + * will return only when connection is complete or a timeout occurs. */ + xResult = IotMqtt_Connect( &( xNetworkInfo ), + &( xConnectInfo ), + shadowexampleMQTT_TIMEOUT_MS, + &( xMQTTConnection ) ); + configASSERT( xResult == IOT_MQTT_SUCCESS ); +} +/*-----------------------------------------------------------*/ + +static void prvMQTTDisconnect( void ) +{ + /* Send a MQTT DISCONNECT packet to the MQTT broker to do a graceful + * disconnect. */ + IotMqtt_Disconnect( xMQTTConnection, + 0 /* flags - 0 means a graceful disconnect by sending MQTT DISCONNECT. */ + ); +} +/*-----------------------------------------------------------*/ + +static void prvSetShadowCallbacks( void ) +{ +AwsIotShadowError_t xCallbackStatus = AWS_IOT_SHADOW_STATUS_PENDING; +AwsIotShadowCallbackInfo_t xDeltaCallback = AWS_IOT_SHADOW_CALLBACK_INFO_INITIALIZER, + xUpdatedCallback = AWS_IOT_SHADOW_CALLBACK_INFO_INITIALIZER; + + /* Set the functions for callbacks. */ + xDeltaCallback.pCallbackContext = &xDeltaSemaphore; + xDeltaCallback.function = prvShadowDeltaCallback; + xUpdatedCallback.function = prvShadowUpdatedCallback; + + /************************ Set delta callbacks ****************************/ + + /* Set the delta callback, which notifies of different desired and reported + * Shadow states. */ + xCallbackStatus = AwsIotShadow_SetDeltaCallback( xMQTTConnection, + awsiotdemoprofileCLIENT_IDENTIFIER, + shadowexampleCLIENT_IDENTIFIER_LENGTH, + 0, &xDeltaCallback ); + configASSERT( xCallbackStatus == AWS_IOT_SHADOW_SUCCESS ); + + /************************ Set updated callbacks **************************/ + + /* Set the updated callback, which notifies when a Shadow document is + * changed. */ + xCallbackStatus = AwsIotShadow_SetUpdatedCallback( xMQTTConnection, + awsiotdemoprofileCLIENT_IDENTIFIER, + shadowexampleCLIENT_IDENTIFIER_LENGTH, + 0, &xUpdatedCallback ); + + configASSERT( xCallbackStatus == AWS_IOT_SHADOW_SUCCESS ); +} +/*-----------------------------------------------------------*/ + +static void prvClearShadowCallbacks( void ) +{ +AwsIotShadowError_t xCallbackStatus = AWS_IOT_SHADOW_STATUS_PENDING; + + /************************ Clear delta callbacks **************************/ + xCallbackStatus = AwsIotShadow_SetDeltaCallback( xMQTTConnection, + awsiotdemoprofileCLIENT_IDENTIFIER, + shadowexampleCLIENT_IDENTIFIER_LENGTH, + 0, NULL ); + configASSERT( xCallbackStatus == AWS_IOT_SHADOW_SUCCESS ); + + /************************ Clear updated callbacks ************************/ + xCallbackStatus = AwsIotShadow_SetUpdatedCallback( xMQTTConnection, + awsiotdemoprofileCLIENT_IDENTIFIER, + shadowexampleCLIENT_IDENTIFIER_LENGTH, + 0, NULL ); + configASSERT( xCallbackStatus == AWS_IOT_SHADOW_SUCCESS ); +} +/*-----------------------------------------------------------*/ + +static void prvShadowDeltaCallback( void * pCallbackContext, + AwsIotShadowCallbackParam_t * pxCallbackParam ) +{ +BaseType_t xDeltaFound = pdFALSE; +const char * pcDelta = NULL; +size_t xDeltaLength = 0; +IotSemaphore_t * pxDeltaSemaphore = pCallbackContext; +uint32_t ulUpdateDocumentLength = 0; +AwsIotShadowError_t xShadowStatus = AWS_IOT_SHADOW_STATUS_PENDING; +AwsIotShadowDocumentInfo_t xUpdateDocument = AWS_IOT_SHADOW_DOCUMENT_INFO_INITIALIZER; +uint8_t ucNewState = 0; + + configASSERT( pxDeltaSemaphore != NULL ); + configASSERT( pxCallbackParam != NULL ); + + /* A buffer containing the update document. It has static duration to prevent + * it from being placed on the call stack.This is only safe because there + * is only one task in the task pool so this function cannot be called from + * two tasks simultaneously. */ + static char cUpdateDocument[ shadowexampleREPORTED_JSON_SIZE + 1 ] = { 0 }; + + /****************** Get delta state from Shadow document *****************/ + /* Check if there is a different "powerOn" state in the Shadow. */ + xDeltaFound = prvGetDelta( pxCallbackParam->u.callback.pDocument, + pxCallbackParam->u.callback.documentLength, + "powerOn", + &pcDelta, + &xDeltaLength ); + + configASSERT( xDeltaFound == pdTRUE ); + + /* Change the current state based on the value in the delta document. */ + if( *pcDelta == '0' ) + { + ucNewState = 0; + } + else if( *pcDelta == '1' ) + { + ucNewState = 1; + } + else + { + configPRINTF( ( "Unknown powerOn state parsed from delta document.\r\n" ) ); + + /* Set new state to current state to ignore the delta document. */ + ucNewState = lDevicePowerOnState; + } + + if( ucNewState != lDevicePowerOnState ) + { + /* Toggle state. */ + configPRINTF( ( "%.*s changing state from %d to %d.\r\n", + pxCallbackParam->thingNameLength, + pxCallbackParam->pThingName, + lDevicePowerOnState, + ucNewState ) ); + + lDevicePowerOnState = ucNewState; + + /* Set the common members to report the new state. */ + xUpdateDocument.pThingName = pxCallbackParam->pThingName; + xUpdateDocument.thingNameLength = pxCallbackParam->thingNameLength; + xUpdateDocument.u.update.pUpdateDocument = cUpdateDocument; + xUpdateDocument.u.update.updateDocumentLength = shadowexampleREPORTED_JSON_SIZE; + + /* Generate a Shadow document for the reported state. To keep the client + * token within 6 characters, it is modded by 1000000. */ + ulUpdateDocumentLength = snprintf( cUpdateDocument, + shadowexampleREPORTED_JSON_SIZE + 1, + shadowexampleREPORTED_JSON, + ( int ) lDevicePowerOnState, + ( long unsigned ) ( IotClock_GetTimeMs() % 1000000 ) ); + + /* Check if the reported state document is generated for Shadow update*/ + configASSERT( ( size_t ) ulUpdateDocumentLength == shadowexampleREPORTED_JSON_SIZE ); + + /* Send the Shadow update. Its result is not checked by waiting for the + * callback, as the Shadow updated callback will report if the Shadow + * was successfully updated. As the Shadow is constantly updated + * in this demo, the "Keep Subscriptions" flag is passed to this + * function. */ + xShadowStatus = AwsIotShadow_UpdateAsync( pxCallbackParam->mqttConnection, + &xUpdateDocument, + AWS_IOT_SHADOW_FLAG_KEEP_SUBSCRIPTIONS, + NULL, + NULL ); + + configASSERT( xShadowStatus == AWS_IOT_SHADOW_STATUS_PENDING ); + configPRINTF( ( "%.*s sent new state report: %.*s\r\n", + pxCallbackParam->thingNameLength, + pxCallbackParam->pThingName, + shadowexampleREPORTED_JSON_SIZE, + cUpdateDocument ) ); + + /* Post to the delta semaphore to unblock the thread sending Shadow updates. */ + xSemaphoreGive( ( SemaphoreHandle_t ) &pxDeltaSemaphore->xSemaphore ); + } +} +/*-----------------------------------------------------------*/ + +static void prvShadowUpdatedCallback( void * pCallbackContext, + AwsIotShadowCallbackParam_t * pxCallbackParam ) +{ +BaseType_t xPreviousFound = pdFALSE, xCurrentFound = pdFALSE; +const char * pcPrevious = NULL, * pcCurrent = NULL; +size_t xPreviousLength = 0, xCurrentLength = 0; + + /* Silence warnings about unused parameters. */ + ( void ) pCallbackContext; + + configASSERT( pxCallbackParam != NULL ); + + /****************** Get previous state from Shadow document **************/ + /* Find the previous Shadow document. */ + xPreviousFound = prvGetUpdatedState( pxCallbackParam->u.callback.pDocument, + pxCallbackParam->u.callback.documentLength, + "previous", + &pcPrevious, + &xPreviousLength ); + + /****************** Get current state from Shadow document **************/ + /* Find the current Shadow document. */ + xCurrentFound = prvGetUpdatedState( pxCallbackParam->u.callback.pDocument, + pxCallbackParam->u.callback.documentLength, + "current", + &pcCurrent, + &xCurrentLength ); + + configASSERT( ( xPreviousFound == pdTRUE ) || ( xCurrentFound == pdTRUE ) ); + + /* Log the previous and current states. */ + configPRINTF( ( "Shadow was updated!\r\n" + "Previous: {\"state\":%.*s}\r\n" + "Current: {\"state\":%.*s}\r\n", + xPreviousLength, + pcPrevious, + xCurrentLength, + pcCurrent ) ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvGetDelta( const char * pcDeltaDocument, + size_t xDeltaDocumentLength, + const char * pcDeltaKey, + const char ** pcDelta, + size_t * pcDeltaLength ) +{ +BaseType_t xStateFound = pdFALSE, xDeltaFound = pdFALSE; +const size_t xDeltaKeyLength = strlen( pcDeltaKey ); +const char * pcState = NULL; +size_t xStateLength = 0; + + configASSERT( pcDeltaDocument != NULL ); + configASSERT( pcDeltaKey != NULL ); + /****************** Get state from Shadow document ***********************/ + + /* Note: This parser used is specific for parsing AWS IoT document received + * through a mutually authenticated connection. This parser will not check + * for the correctness of the document as it is designed for low memory + * footprint rather than checking for correctness of the document. This + * parser is not meant to be used as a general purpose JSON parser. + */ + xStateFound = ( BaseType_t ) AwsIotDocParser_FindValue( + pcDeltaDocument, + xDeltaDocumentLength, + "state", + 5, + &pcState, + &xStateLength ); + + configASSERT( xStateFound == pdTRUE ); + + /********** Get delta key from state section of Shadow document **********/ + + /* Note: This parser used is specific for parsing AWS IoT document received + * through a mutually authenticated connection. This parser will not check + * for the correctness of the document as it is designed for low memory + * footprint rather than checking for correctness of the document. This + * parser is not meant to be used as a general purpose JSON parser. + */ + xDeltaFound = ( BaseType_t ) AwsIotDocParser_FindValue( + pcState, + xStateLength, + pcDeltaKey, + xDeltaKeyLength, + pcDelta, + pcDeltaLength ); + + return xDeltaFound; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvGetUpdatedState( const char * pcUpdatedDocument, + size_t xUpdatedDocumentLength, + const char * pcSectionKey, + const char ** ppcState, + size_t * ppcStateLength ) +{ +BaseType_t xSectionFound = pdFALSE, xStateFound = pdFALSE; +const size_t xSectionKeyLength = strlen( pcSectionKey ); +const char * pcSection = NULL; +size_t xSectionLength = 0; + + configASSERT( pcUpdatedDocument != NULL ); + configASSERT( pcSectionKey != NULL ); + + /*********** Find the given section in the updated document. *************/ + + /* Note: This parser used is specific for parsing AWS IoT document received + * through a mutually authenticated connection. This parser will not check + * for the correctness of the document as it is designed for low memory + * footprint rather than checking for correctness of the document. This + * parser is not meant to be used as a general purpose JSON parser. + */ + xSectionFound = ( BaseType_t ) AwsIotDocParser_FindValue( + pcUpdatedDocument, + xUpdatedDocumentLength, + pcSectionKey, + xSectionKeyLength, + &pcSection, + &xSectionLength ); + + configASSERT( xSectionFound == pdTRUE ); + + /*********** Find the state key within the section found *****************/ + + /* Find the "state" key within the "previous" or "current" section. + * + * Note: This parser used is specific for parsing AWS IoT document received + * through a mutually authenticated connection. This parser will not check + * for the correctness of the document as it is designed for low memory + * footprint rather than checking for correctness of the document. This + * parser is not meant to be used as a general purpose JSON parser. + */ + xStateFound = ( BaseType_t ) AwsIotDocParser_FindValue( + pcSection, + xSectionLength, + "state", + 5, + ppcState, + ppcStateLength ); + + return xStateFound; +} +/*-----------------------------------------------------------*/ + +static void prvClearShadowDocument( void ) +{ +AwsIotShadowError_t xDeleteStatus = AWS_IOT_SHADOW_STATUS_PENDING; + + /************************* Delete Shadow document ************************/ + xDeleteStatus = AwsIotShadow_DeleteSync( xMQTTConnection, + awsiotdemoprofileCLIENT_IDENTIFIER, + shadowexampleCLIENT_IDENTIFIER_LENGTH, + 0, shadowexampleMQTT_TIMEOUT_MS ); + configASSERT( ( xDeleteStatus == AWS_IOT_SHADOW_SUCCESS ) || ( xDeleteStatus == AWS_IOT_SHADOW_NOT_FOUND ) ); + + configPRINTF( ( "Successfully cleared Shadow of %.*s.\r\n", + shadowexampleCLIENT_IDENTIFIER_LENGTH, + awsiotdemoprofileCLIENT_IDENTIFIER ) ); +} +/*-----------------------------------------------------------*/ + +static void prvSendShadowUpdates( void ) +{ +int32_t lIndex = 0, lDesiredState = 0, lStatus = 0; +AwsIotShadowError_t xShadowStatus = AWS_IOT_SHADOW_STATUS_PENDING; +AwsIotShadowDocumentInfo_t xUpdateDocument = AWS_IOT_SHADOW_DOCUMENT_INFO_INITIALIZER; + + /* A buffer containing the update document. It has static duration to prevent + * it from being placed on the call stack. */ + static char cUpdateDocument[ shadowexampleDESIRED_JSON_SIZE + 1 ] = { 0 }; + + /********** Set the common members of Shadow update document *************/ + xUpdateDocument.pThingName = awsiotdemoprofileCLIENT_IDENTIFIER; + xUpdateDocument.thingNameLength = shadowexampleCLIENT_IDENTIFIER_LENGTH; + xUpdateDocument.u.update.pUpdateDocument = cUpdateDocument; + xUpdateDocument.u.update.updateDocumentLength = shadowexampleDESIRED_JSON_SIZE; + + /*************** Publish Shadow updates at a set period. *****************/ + for( lIndex = 1; lIndex <= shadowexampleUPDATE_COUNT; lIndex++ ) + { + /* Toggle the desired state. */ + lDesiredState = !( lDesiredState ); + + /* Generate a Shadow desired state document, using a timestamp for the client + * token. To keep the client token within 6 characters, it is modded by 1000000. */ + lStatus = snprintf( cUpdateDocument, + shadowexampleDESIRED_JSON_SIZE + 1, + shadowexampleDESIRED_JSON, + ( int ) lDesiredState, + ( long unsigned ) ( IotClock_GetTimeMs() % 1000000 ) ); + + /* Check for errors from snprintf. The expected value is the length of + * the desired JSON document less the format specifier for the state. */ + configASSERT( lStatus == shadowexampleDESIRED_JSON_SIZE ); + + configPRINTF( ( "Sending Shadow update %d of %d: %s\r\n", + lIndex, + shadowexampleUPDATE_COUNT, + cUpdateDocument ) ); + + /* Send the Shadow update. Because the Shadow is constantly updated in + * this demo, the "Keep Subscriptions" flag is passed to this function. + * Note that this flag only needs to be passed on the first call, but + * passing it for subsequent calls is fine. + */ + xShadowStatus = AwsIotShadow_UpdateSync( xMQTTConnection, + &xUpdateDocument, + AWS_IOT_SHADOW_FLAG_KEEP_SUBSCRIPTIONS, + shadowexampleMQTT_TIMEOUT_MS ); + + configASSERT( xShadowStatus == AWS_IOT_SHADOW_SUCCESS ); + + configPRINTF( ( "Successfully sent Shadow update %d of %d.\r\n", + lIndex, + shadowexampleUPDATE_COUNT ) ); + + /* Wait for the delta callback to change its state before continuing. */ + configASSERT( xSemaphoreTake( ( SemaphoreHandle_t ) &xDeltaSemaphore.xSemaphore, + pdMS_TO_TICKS( shadowexampleWAIT_PERIOD_FOR_DELTA_MS ) ) == pdTRUE ); + + IotClock_SleepMs( shadowexampleUPDATE_PERIOD_MS ); + } + + /* Remove persistent subscriptions. In the AwsIotShadow_UpdateSync call, we have used the */ + xShadowStatus = AwsIotShadow_RemovePersistentSubscriptions( xMQTTConnection, + awsiotdemoprofileCLIENT_IDENTIFIER, + shadowexampleCLIENT_IDENTIFIER_LENGTH, + AWS_IOT_SHADOW_FLAG_REMOVE_UPDATE_SUBSCRIPTIONS ); + + configASSERT( xShadowStatus == AWS_IOT_SHADOW_SUCCESS ); +} +/*-----------------------------------------------------------*/ + +static void prvInitialiseLibraries( void ) +{ +IotTaskPoolError_t xTaskPoolResult; +IotMqttError_t xResult; +IotNetworkError_t xNetworkResult; + + /* The MQTT library needs a task pool, so create the system task pool. */ + xTaskPoolResult = IotTaskPool_CreateSystemTaskPool( &( xTaskPoolParameters ) ); + configASSERT( xTaskPoolResult == IOT_TASKPOOL_SUCCESS ); + + /* Initialize the network stack abstraction for FreeRTOS. */ + xNetworkResult = IotNetworkFreeRTOS_Init(); + configASSERT( xNetworkResult == IOT_NETWORK_SUCCESS ); + + /* MQTT library must be initialized before it can be used. This is just one + * time initialization. */ + xResult = IotMqtt_Init(); + configASSERT( xResult == IOT_MQTT_SUCCESS ); + + /* Initialize Shadow library*/ + xResult = AwsIotShadow_Init( shadowexampleUSE_DEFAULT_MQTT_TIMEOUT ); + configASSERT( xResult == AWS_IOT_SHADOW_SUCCESS ); +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/FreeRTOSConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/FreeRTOSConfig.h new file mode 100644 index 000000000..e407f438d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/FreeRTOSConfig.h @@ -0,0 +1,210 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * http://www.freertos.org/a00110.html + * + * The bottom of this file contains some constants specific to running the UDP + * stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than + * the demo) are contained in FreeRTOSIPConfig.h. + *----------------------------------------------------------*/ +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Run time stats gathering definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_pcTaskGetTaskName 1 + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS +is set to 2 so the formatting functions are included without the stdio.h being +included in tasks.c. That is because this project defines its own sprintf() +functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* Assert call defined for debug builds. */ +#ifdef _DEBUG + extern void vAssertCalled( const char *pcFile, uint32_t ulLine ); + #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) +#endif /* _DEBUG */ + + + +/* Application specific definitions follow. **********************************/ + +/* Only used when running in the FreeRTOS Windows simulator. Defines the +priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet +or WiFi data to and from a real network connection. Many computers have more +than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell +the demo which real port should be used to create the virtual port. The ports +available are displayed on the console when the application is executed. For +example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 +results in the wired network being used, while setting +configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being +used. */ +#define configNETWORK_INTERFACE_TO_USE 2L + +/* The address of an echo server is only left in this project as it doubles as +the address to which logging is sent should UDP logging be enabled. */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 0 +#define configECHO_SERVER_ADDR3 11 + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet/WiFi data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition above for information on how to +configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x11 +#define configMAC_ADDR3 0x11 +#define configMAC_ADDR4 0x11 +#define configMAC_ADDR5 0x41 + +/* Default IP address configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 10 +#define configIP_ADDR1 10 +#define configIP_ADDR2 10 +#define configIP_ADDR3 200 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DNS is set to +0, or ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 10 +#define configGATEWAY_ADDR1 10 +#define configGATEWAY_ADDR2 10 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. OpenDNS addresses are 208.67.222.222 and +208.67.220.220. Used in ipconfigUSE_DNS is set to 0, or ipconfigUSE_DNS is set +to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 208 +#define configDNS_SERVER_ADDR1 67 +#define configDNS_SERVER_ADDR2 222 +#define configDNS_SERVER_ADDR3 222 + +/* Default netmask configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 0 +#define configNET_MASK2 0 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#if( defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) && !defined( snprintf ) ) + /* Map to Windows names. */ + #define snprintf _snprintf + #define vsnprintf _vsnprintf +#endif + +/* Visual studio does not have an implementation of strcasecmp(). */ +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define strcmpi _strcmpi + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); +#define configPRINTF( X ) vLoggingPrintf X + +#endif /* FREERTOS_CONFIG_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/FreeRTOSIPConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/FreeRTOSIPConfig.h new file mode 100644 index 000000000..6f86009bf --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/FreeRTOSIPConfig.h @@ -0,0 +1,310 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +/***************************************************************************** + * + * See the following URL for configuration information. + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html + * + *****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to +1 then FreeRTOS_debug_printf should be defined to the function used to print +out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 0 +#if( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf(X) vLoggingPrintf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the +FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 +then FreeRTOS_printf should be set to the function used to print out the +messages. */ +#define ipconfigHAS_PRINTF 1 +#if( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf(X) vLoggingPrintf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing +on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading (IP/TCP/UDP checksums) +then set ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software +stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 + +/* Several API's will block until the result is known, or the action has been +performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be +set per socket, using setsockopt(). If not set, the times below will be +used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 5000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for LLMNR: Link-local Multicast Name Resolution +(non-Microsoft) */ +#define ipconfigUSE_LLMNR ( 0 ) + +/* Include support for NBNS: NetBIOS Name Service (Microsoft) */ +#define ipconfigUSE_NBNS ( 0 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very +useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low +and also DNS may use small timeouts. If a DNS reply comes in after the DNS +socket has been destroyed, the result will be stored into the cache. The next +call to FreeRTOS_gethostbyname() will return immediately, without even creating +a socket. */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_NAME_LENGTH ( 64 ) +#define ipconfigDNS_CACHE_ENTRIES ( 4 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make +use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY +sets the priority of the task that executes the IP stack. The priority is a +standard FreeRTOS task priority so can take any value from 0 (the lowest +priority) to (configMAX_PRIORITIES - 1) (the highest priority). +configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in +FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to +the priority assigned to the task executing the IP stack relative to the +priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP +task. This setting is less important when the FreeRTOS Win32 simulator is used +as the Win32 simulator only stores a fixed amount of information on the task +stack. FreeRTOS includes optional stack overflow detection, see: +http://www.freertos.org/Stacks-and-stack-overflow-checking.html */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* ipconfigRAND32() is called by the IP stack to generate random numbers for +things such as a DHCP transaction number or initial sequence number. Random +number generation is performed via this macro to allow applications to use their +own random number generation method. For example, it might be possible to +generate a random number by sampling noise on an analogue input. */ +extern UBaseType_t uxRand(); +#define ipconfigRAND32() uxRand() + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the +network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK +is not set to 1 then the network event hook will never be called. See +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml +*/ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but +a network buffer cannot be obtained then the calling task is held in the Blocked +state (so other tasks can continue to executed) until either a network buffer +becomes available or the send block time expires. If the send block time expires +then the send operation is aborted. The maximum allowable send block time is +capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the +maximum allowable send block time prevents prevents a deadlock occurring when +all the network buffers are in use and the tasks that process (and subsequently +free) the network buffers are themselves blocked waiting for a network buffer. +ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in +milliseconds can be converted to a time in ticks by dividing the time in +milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP +address, netmask, DNS server address and gateway address from a DHCP server. If +ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The +stack will revert to using the static IP address even when ipconfigUSE_DHCP is +set to 1 if a valid configuration cannot be obtained from a DHCP server for any +reason. The static configuration used is that passed into the stack by the +FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 1 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at +increasing time intervals until either a reply is received from a DHCP server +and accepted, or the interval between transmissions reaches +ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the +static IP address passed as a parameter to FreeRTOS_IPInit() if the +re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without +a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( 120000 / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP +stack can only send a UDP message to a remove IP address if it knowns the MAC +address associated with the IP address, or the MAC address of the router used to +contact the remote IP address. When a UDP message is received from a remote IP +address the MAC address and IP address are added to the ARP cache. When a UDP +message is sent to a remote IP address that does not already appear in the ARP +cache then the UDP message is replaced by a ARP message that solicits the +required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum +number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a +maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is +aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP +table being created or refreshed and the entry being removed because it is stale. +New ARP requests are sent for ARP cache entries that are nearing their maximum +age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is +equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling +routines, which are relatively large. To save code space the full +FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster +alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() +takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. +FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets +(for example, 192, 168, 0, 1) as its parameters. If +ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and +FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is +not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that +are available to the IP stack. The total number of network buffers is limited +to ensure the total amount of RAM that can be consumed by the IP stack is capped +to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP +stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can +be queued for processing at any one time. The event queue must be a minimum of +5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port +number. FreeRTOS_bind() is used to manually allocate a port number to a socket +(to 'bind' the socket to a port), but manual binding is not normally necessary +for client sockets (those sockets that initiate outgoing connections rather than +wait for incoming connections on a known port number). If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling +FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP +stack automatically binding the socket to a port number from the range +socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() +on a socket that has not yet been bound will result in the send operation being +aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +#define ipconfigTCP_TIME_TO_LIVE 128 /* also defined in FreeRTOSIPConfigDefaults.h */ + +/* USE_TCP: Use TCP and all its features */ +#define ipconfigUSE_TCP ( 1 ) + +/* Use the TCP socket wake context with a callback. */ +#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT ( 1 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can +contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a +lower value can save RAM, depending on the buffer management scheme used. If +ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must +be divisible by 8. */ +#define ipconfigNETWORK_MTU 1200 + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used +through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will +generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the +FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 0 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() +(and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames +that are not in Ethernet II format will be dropped. This option is included for +potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the +responsibility of the Ethernet interface to filter out packets that are of no +interest. If the Ethernet interface does not implement this functionality, then +set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack +perform the filtering instead (it is much less efficient for the stack to do it +because the packet will already have been passed into the stack). If the +Ethernet driver does all the necessary filtering in hardware then software +filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to +block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with +32-bit memory instructions, all packets will be stored 32-bit-aligned, plus 16-bits. +This has to do with the contents of the IP-packets: all 32-bit fields are +32-bit-aligned, plus 16-bit(!) */ +#define ipconfigPACKET_FILLER_SIZE 2 + +/* Define the size of the pool of TCP window descriptors. On the average, each +TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 +outstanding packets (for Rx and Tx). When using up to 10 TP sockets +simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed +maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 1000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 1000 ) + +/* When using call-back handlers, the driver may check if the handler points to +real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS(x) ( (x) != NULL ) + +/* Include support for TCP hang protection. All sockets in a connecting or +disconnecting stage will timeout after a period of non-activity. */ +#define ipconfigTCP_HANG_PROTECTION ( 1 ) +#define ipconfigTCP_HANG_PROTECTION_TIME ( 30 ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* in seconds */ + +#define portINLINE __inline + +#endif /* FREERTOS_IP_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/READ_ME_INSTRUCTIONS.url b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/READ_ME_INSTRUCTIONS.url new file mode 100644 index 000000000..96d5e654e --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/READ_ME_INSTRUCTIONS.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/shadow/index.html diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WIN32.vcxproj b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WIN32.vcxproj new file mode 100644 index 000000000..1a2348def --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WIN32.vcxproj @@ -0,0 +1,644 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {C686325E-3261-42F7-AEB1-DDE5280E1CEB} + RTOSDemo + 10.0 + + + + Application + false + MultiByte + v142 + + + Application + false + MultiByte + v142 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Debug\ + .\Debug\ + true + .\Release\ + .\Release\ + false + AllRules.ruleset + + + + .\Debug/WIN32.tlb + + + + + Disabled + ..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;.\DemoTasks\include;.\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include\private;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\mbedtls;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\mqtt\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\aws\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\aws\shadow\include;..\..\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\platform;..\..\..\..\Source\mbedtls\include;.;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\src;%(AdditionalIncludeDirectories) + MBEDTLS_CONFIG_FILE="mbedtls_config.h";WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + false + EnableFastChecks + MultiThreadedDLL + .\Debug/WIN32.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level4 + true + false + EditAndContinue + /wd4210 /wd4127 /wd4214 /wd4201 /wd4244 /wd4310 /wd4200 %(AdditionalOptions) + true + NotUsing + false + CompileAsC + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Debug/RTOSDemo.exe + true + true + .\Debug/WIN32.pdb + Console + MachineX86 + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + .\WinPCap + false + false + + + true + .\Debug/WIN32.bsc + + + + + .\Release/WIN32.tlb + + + + + MaxSpeed + OnlyExplicitInline + MBEDTLS_CONFIG_FILE="mbedtls_config.h";_WINSOCKAPI_;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release/WIN32.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + ..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;.\DemoTasks\include;.\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include\private;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\mbedtls;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\mqtt\include;..\..\..\..\Source\mbedtls\include;.;%(AdditionalIncludeDirectories) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Release/RTOSDemo.exe + true + .\Release/WIN32.pdb + Console + MachineX86 + .\WinPCap + wpcap.lib;Bcrypt.lib;%(AdditionalDependencies) + + + true + .\Release/WIN32.bsc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + TurnOffAllWarnings + TurnOffAllWarnings + + + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WIN32.vcxproj.filters b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WIN32.vcxproj.filters new file mode 100644 index 000000000..cafce0780 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WIN32.vcxproj.filters @@ -0,0 +1,877 @@ + + + + + {af3445a1-4908-4170-89ed-39345d90d30c} + + + {f32be356-4763-4cae-9020-974a2638cb08} + *.c + + + {88f409e6-d396-4ac5-94bd-7a99c914be46} + + + {e5ad4ec7-23dc-4295-8add-2acaee488f5a} + + + {d2dcd641-8d91-492b-852f-5563ffadaec6} + + + {8672fa26-b119-481f-8b8d-086419c01a3e} + + + {4570be11-ec96-4b55-ac58-24b50ada980a} + + + {5d93ed51-023a-41ad-9243-8d230165d34b} + + + {b71e974a-9f28-4815-972b-d930ba8a34d0} + + + {60717407-397f-4ea5-8492-3314acdd25f0} + + + {8a90222f-d723-4b4e-8e6e-c57afaf7fa92} + + + {7c995f05-2a10-4771-ad77-18a755876e46} + + + {9a636cc3-ebc6-48c5-8c18-c72494686e81} + + + {29376c48-bc8b-4624-ad59-16807874c9f2} + + + {91ef4008-de51-4b41-ba5e-bf24d8cda378} + + + {ade43c6c-04c5-4897-abdb-91af2df04e5d} + + + {08a4e35c-19ca-4b1e-af24-bac368c2bf7b} + + + {1fc5fc25-c18b-45a2-bad3-0c07795db1e9} + + + {f3a69e5b-1462-4e19-8651-274e86c252b0} + + + {9a849d9e-91e5-4035-ab4c-70a986c6aed1} + + + {1e324500-91b4-4c76-b699-59ba75691760} + + + {bdcbc1ec-99b8-4c72-9075-49035c115488} + + + {2d17d5e6-ed70-4e42-9693-f7a63baf4948} + + + {7158b0be-01e7-42d1-8d3f-c75118a596a2} + + + {6ad56e6d-c330-4830-8f4b-c75b05dfa866} + + + {1d80b387-5a86-4744-a4cc-930033a52e4b} + + + {1cecca7f-60cd-4d8d-8123-f00aa75af147} + + + {f9a2e0a1-ed56-4ca7-b8b2-d694a94c78c0} + + + {61ac8e2c-8fd1-44a0-a7a9-0326bc190426} + + + {b53bfe50-b4d9-4b78-b7bb-ae90e4d25615} + + + {6fc3dbdf-ef1b-4000-96c6-447621d2782e} + + + {765e2757-4ec2-4703-9141-093677be5e13} + + + {bb36e5b2-9eba-47ea-a757-7d55bbb74726} + + + {48eec811-37ca-4b40-b26e-0550a7e3f06c} + + + {16ce18ad-55d5-4b7c-9826-b7ad58b19807} + + + {ea79ce18-8bb0-4b47-be42-a2c5f2bf1afe} + + + {094110c9-8503-402f-a3b5-61b502fcea5c} + + + {e916c9ca-e771-43b8-95e1-aa833cff5a97} + + + {d47bcb87-eb13-4d3d-9020-30183f5885fa} + + + {4c47da91-6627-42da-848a-fcce805dcca1} + + + + + FreeRTOS\Source\Portable + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS\Source + + + FreeRTOS\Source\Portable + + + + FreeRTOS+\FreeRTOS+TCP + + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\src + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\mbedtls\library + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\mbedtls + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\shadow\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\shadow\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\shadow\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\shadow\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\shadow\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\common\src + + + DemoTasks + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\common\src + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\mqtt\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos\include\platform + + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\mbedtls\include + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\mbedtls + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\shadow\include + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\shadow\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src\private + + + FreeRTOS+\FreeRTOS IoT Libraries\aws\common\include + + + + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\include\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\include\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\include\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\include\platform + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\include\types + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/Packet32.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/Packet32.h new file mode 100644 index 000000000..1e0eacd77 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/Packet32.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + +/** @ingroup packetapi + * @{ + */ + +/** @defgroup packet32h Packet.dll definitions and data structures + * Packet32.h contains the data structures and the definitions used by packet.dll. + * The file is used both by the Win9x and the WinNTx versions of packet.dll, and can be included + * by the applications that use the functions of this library + * @{ + */ + +#ifndef __PACKET32 +#define __PACKET32 + +#include + +#ifdef HAVE_AIRPCAP_API +#include +#else +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +typedef struct _AirpcapHandle *PAirpcapHandle; +#endif /* AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ */ +#endif /* HAVE_AIRPCAP_API */ + +#ifdef HAVE_DAG_API +#include +#endif /* HAVE_DAG_API */ + +// Working modes +#define PACKET_MODE_CAPT 0x0 ///< Capture mode +#define PACKET_MODE_STAT 0x1 ///< Statistical mode +#define PACKET_MODE_MON 0x2 ///< Monitoring mode +#define PACKET_MODE_DUMP 0x10 ///< Dump mode +#define PACKET_MODE_STAT_DUMP MODE_DUMP | MODE_STAT ///< Statistical dump Mode + + +/// Alignment macro. Defines the alignment size. +#define Packet_ALIGNMENT sizeof(int) +/// Alignment macro. Rounds up to the next even multiple of Packet_ALIGNMENT. +#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1)) + +#define NdisMediumNull -1 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumCHDLC -2 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPPPSerial -3 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumBare80211 -4 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumRadio80211 -5 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPpi -6 ///< Custom linktype: NDIS doesn't provide an equivalent + +// Loopback behaviour definitions +#define NPF_DISABLE_LOOPBACK 1 ///< Drop the packets sent by the NPF driver +#define NPF_ENABLE_LOOPBACK 2 ///< Capture the packets sent by the NPF driver + +/*! + \brief Network type structure. + + This structure is used by the PacketGetNetType() function to return information on the current adapter's type and speed. +*/ +typedef struct NetType +{ + UINT LinkType; ///< The MAC of the current network adapter (see function PacketGetNetType() for more information) + ULONGLONG LinkSpeed; ///< The speed of the network in bits per second +}NetType; + + +//some definitions stolen from libpcap + +#ifndef BPF_MAJOR_VERSION + +/*! + \brief A BPF pseudo-assembly program. + + The program will be injected in the kernel by the PacketSetBPF() function and applied to every incoming packet. +*/ +struct bpf_program +{ + UINT bf_len; ///< Indicates the number of instructions of the program, i.e. the number of struct bpf_insn that will follow. + struct bpf_insn *bf_insns; ///< A pointer to the first instruction of the program. +}; + +/*! + \brief A single BPF pseudo-instruction. + + bpf_insn contains a single instruction for the BPF register-machine. It is used to send a filter program to the driver. +*/ +struct bpf_insn +{ + USHORT code; ///< Instruction type and addressing mode. + UCHAR jt; ///< Jump if true + UCHAR jf; ///< Jump if false + int k; ///< Generic field used for various purposes. +}; + +/*! + \brief Structure that contains a couple of statistics values on the current capture. + + It is used by packet.dll to return statistics about a capture session. +*/ +struct bpf_stat +{ + UINT bs_recv; ///< Number of packets that the driver received from the network adapter + ///< from the beginning of the current capture. This value includes the packets + ///< lost by the driver. + UINT bs_drop; ///< number of packets that the driver lost from the beginning of a capture. + ///< Basically, a packet is lost when the the buffer of the driver is full. + ///< In this situation the packet cannot be stored and the driver rejects it. + UINT ps_ifdrop; ///< drops by interface. XXX not yet supported + UINT bs_capt; ///< number of packets that pass the filter, find place in the kernel buffer and + ///< thus reach the application. +}; + +/*! + \brief Packet header. + + This structure defines the header associated with every packet delivered to the application. +*/ +struct bpf_hdr +{ + struct timeval bh_tstamp; ///< The timestamp associated with the captured packet. + ///< It is stored in a TimeVal structure. + UINT bh_caplen; ///< Length of captured portion. The captured portion can be different + ///< from the original packet, because it is possible (with a proper filter) + ///< to instruct the driver to capture only a portion of the packets. + UINT bh_datalen; ///< Original length of packet + USHORT bh_hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases, + ///< a padding could be added between the end of this structure and the packet + ///< data for performance reasons. This filed can be used to retrieve the actual data + ///< of the packet. +}; + +/*! + \brief Dump packet header. + + This structure defines the header associated with the packets in a buffer to be used with PacketSendPackets(). + It is simpler than the bpf_hdr, because it corresponds to the header associated by WinPcap and libpcap to a + packet in a dump file. This makes straightforward sending WinPcap dump files to the network. +*/ +struct dump_bpf_hdr{ + struct timeval ts; ///< Time stamp of the packet + UINT caplen; ///< Length of captured portion. The captured portion can smaller than the + ///< the original packet, because it is possible (with a proper filter) to + ///< instruct the driver to capture only a portion of the packets. + UINT len; ///< Length of the original packet (off wire). +}; + + +#endif + +struct bpf_stat; + +#define DOSNAMEPREFIX TEXT("Packet_") ///< Prefix added to the adapters device names to create the WinPcap devices +#define MAX_LINK_NAME_LENGTH 64 //< Maximum length of the devices symbolic links +#define NMAX_PACKET 65535 + +/*! + \brief Addresses of a network adapter. + + This structure is used by the PacketGetNetInfoEx() function to return the IP addresses associated with + an adapter. +*/ +typedef struct npf_if_addr { + struct sockaddr_storage IPAddress; ///< IP address. + struct sockaddr_storage SubnetMask; ///< Netmask for that address. + struct sockaddr_storage Broadcast; ///< Broadcast address. +}npf_if_addr; + + +#define ADAPTER_NAME_LENGTH 256 + 12 ///< Maximum length for the name of an adapter. The value is the same used by the IP Helper API. +#define ADAPTER_DESC_LENGTH 128 ///< Maximum length for the description of an adapter. The value is the same used by the IP Helper API. +#define MAX_MAC_ADDR_LENGTH 8 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. +#define MAX_NETWORK_ADDRESSES 16 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. + + +typedef struct WAN_ADAPTER_INT WAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API +typedef WAN_ADAPTER *PWAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API + +#define INFO_FLAG_NDIS_ADAPTER 0 ///< Flag for ADAPTER_INFO: this is a traditional ndis adapter +#define INFO_FLAG_NDISWAN_ADAPTER 1 ///< Flag for ADAPTER_INFO: this is a NdisWan adapter, and it's managed by WANPACKET +#define INFO_FLAG_DAG_CARD 2 ///< Flag for ADAPTER_INFO: this is a DAG card +#define INFO_FLAG_DAG_FILE 6 ///< Flag for ADAPTER_INFO: this is a DAG file +#define INFO_FLAG_DONT_EXPORT 8 ///< Flag for ADAPTER_INFO: when this flag is set, the adapter will not be listed or openend by winpcap. This allows to prevent exporting broken network adapters, like for example FireWire ones. +#define INFO_FLAG_AIRPCAP_CARD 16 ///< Flag for ADAPTER_INFO: this is an airpcap card +#define INFO_FLAG_NPFIM_DEVICE 32 + +/*! + \brief Describes an opened network adapter. + + This structure is the most important for the functioning of packet.dll, but the great part of its fields + should be ignored by the user, since the library offers functions that avoid to cope with low-level parameters +*/ +typedef struct _ADAPTER { + HANDLE hFile; ///< \internal Handle to an open instance of the NPF driver. + CHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; ///< \internal A string containing the name of the network adapter currently opened. + int NumWrites; ///< \internal Number of times a packets written on this adapter will be repeated + ///< on the wire. + HANDLE ReadEvent; ///< A notification event associated with the read calls on the adapter. + ///< It can be passed to standard Win32 functions (like WaitForSingleObject + ///< or WaitForMultipleObjects) to wait until the driver's buffer contains some + ///< data. It is particularly useful in GUI applications that need to wait + ///< concurrently on several events. In Windows NT/2000 the PacketSetMinToCopy() + ///< function can be used to define the minimum amount of data in the kernel buffer + ///< that will cause the event to be signalled. + + UINT ReadTimeOut; ///< \internal The amount of time after which a read on the driver will be released and + ///< ReadEvent will be signaled, also if no packets were captured + CHAR Name[ADAPTER_NAME_LENGTH]; + PWAN_ADAPTER pWanAdapter; + UINT Flags; ///< Adapter's flags. Tell if this adapter must be treated in a different way, using the Netmon API or the dagc API. + +#ifdef HAVE_AIRPCAP_API + PAirpcapHandle AirpcapAd; +#endif // HAVE_AIRPCAP_API + +#ifdef HAVE_NPFIM_API + void* NpfImHandle; +#endif // HAVE_NPFIM_API + +#ifdef HAVE_DAG_API + dagc_t *pDagCard; ///< Pointer to the dagc API adapter descriptor for this adapter + PCHAR DagBuffer; ///< Pointer to the buffer with the packets that is received from the DAG card + struct timeval DagReadTimeout; ///< Read timeout. The dagc API requires a timeval structure + unsigned DagFcsLen; ///< Length of the frame check sequence attached to any packet by the card. Obtained from the registry + DWORD DagFastProcess; ///< True if the user requests fast capture processing on this card. Higher level applications can use this value to provide a faster but possibly unprecise capture (for example, libpcap doesn't convert the timestamps). +#endif // HAVE_DAG_API +} ADAPTER, *LPADAPTER; + +/*! + \brief Structure that contains a group of packets coming from the driver. + + This structure defines the header associated with every packet delivered to the application. +*/ +typedef struct _PACKET { + HANDLE hEvent; ///< \deprecated Still present for compatibility with old applications. + OVERLAPPED OverLapped; ///< \deprecated Still present for compatibility with old applications. + PVOID Buffer; ///< Buffer with containing the packets. See the PacketReceivePacket() for + ///< details about the organization of the data in this buffer + UINT Length; ///< Length of the buffer + DWORD ulBytesReceived; ///< Number of valid bytes present in the buffer, i.e. amount of data + ///< received by the last call to PacketReceivePacket() + BOOLEAN bIoComplete; ///< \deprecated Still present for compatibility with old applications. +} PACKET, *LPPACKET; + +/*! + \brief Structure containing an OID request. + + It is used by the PacketRequest() function to send an OID to the interface card driver. + It can be used, for example, to retrieve the status of the error counters on the adapter, its MAC address, + the list of the multicast groups defined on it, and so on. +*/ +struct _PACKET_OID_DATA { + ULONG Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h + ///< for a complete list of valid codes. + ULONG Length; ///< Length of the data field + UCHAR Data[1]; ///< variable-lenght field that contains the information passed to or received + ///< from the adapter. +}; +typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @} + */ + +/* +BOOLEAN QueryWinPcapRegistryStringA(CHAR *SubKeyName, + CHAR *Value, + UINT *pValueLen, + CHAR *DefaultVal); + +BOOLEAN QueryWinPcapRegistryStringW(WCHAR *SubKeyName, + WCHAR *Value, + UINT *pValueLen, + WCHAR *DefaultVal); +*/ + +//--------------------------------------------------------------------------- +// EXPORTED FUNCTIONS +//--------------------------------------------------------------------------- + +PCHAR PacketGetVersion(); +PCHAR PacketGetDriverVersion(); +BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes); +BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites); +BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode); +BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout); +BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp); +BOOLEAN PacketSetLoopbackBehavior(LPADAPTER AdapterObject, UINT LoopbackBehavior); +INT PacketSetSnapLen(LPADAPTER AdapterObject,int snaplen); +BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim); +BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type); +LPADAPTER PacketOpenAdapter(PCHAR AdapterName); +BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync); +INT PacketSendPackets(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync); +LPPACKET PacketAllocatePacket(void); +VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length); +VOID PacketFreePacket(LPPACKET lpPacket); +BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync); +BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter); +BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize); +BOOLEAN PacketGetNetInfoEx(PCHAR AdapterName, npf_if_addr* buffer, PLONG NEntries); +BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData); +HANDLE PacketGetReadEvent(LPADAPTER AdapterObject); +BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len); +BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks); +BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync); +BOOL PacketStopDriver(); +VOID PacketCloseAdapter(LPADAPTER lpAdapter); +BOOLEAN PacketStartOem(PCHAR errorString, UINT errorStringLength); +BOOLEAN PacketStartOemEx(PCHAR errorString, UINT errorStringLength, ULONG flags); +PAirpcapHandle PacketGetAirPcapHandle(LPADAPTER AdapterObject); + +// +// Used by PacketStartOemEx +// +#define PACKET_START_OEM_NO_NETMON 0x00000001 + +#ifdef __cplusplus +} +#endif + +#endif //__PACKET32 diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/PacketData.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/PacketData.h new file mode 100644 index 000000000..8124db66d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/PacketData.h @@ -0,0 +1,267 @@ +char pkt1[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x30, 0x09, 0x9c, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x07, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x35, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02, +0x40, 0x00, 0xdf, 0xab, 0x00, 0x00, 0x02, 0x04, +0x05, 0xb4, 0x01, 0x01, 0x04, 0x02 }; + +char pkt2[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa6, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt3[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0x9e, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x0d, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt4[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x02, 0x27, 0x09, 0x9f, 0x40, 0x00, 0x80, 0x06, +0x6d, 0x0d, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x18, +0x42, 0xd8, 0x84, 0x3e, 0x00, 0x00, 0x47, 0x45, +0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, +0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, +0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x2c, +0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, +0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, +0x2c, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, +0x6a, 0x70, 0x65, 0x67, 0x2c, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x70, 0x6a, 0x70, 0x65, +0x67, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, +0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, +0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, +0x63, 0x65, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c, +0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, +0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, +0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20, +0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, +0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, +0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70, +0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, +0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78, +0x62, 0x61, 0x70, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, +0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d, +0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, +0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, +0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, +0x20, 0x65, 0x6e, 0x2d, 0x67, 0x62, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, +0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, +0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64, +0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x0d, 0x0a, +0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, +0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69, +0x6c, 0x6c, 0x61, 0x2f, 0x34, 0x2e, 0x30, 0x20, +0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, +0x62, 0x6c, 0x65, 0x3b, 0x20, 0x4d, 0x53, 0x49, +0x45, 0x20, 0x36, 0x2e, 0x30, 0x3b, 0x20, 0x57, +0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e, +0x54, 0x20, 0x35, 0x2e, 0x31, 0x3b, 0x20, 0x53, +0x56, 0x31, 0x3b, 0x20, 0x47, 0x6f, 0x6f, 0x67, +0x6c, 0x65, 0x54, 0x35, 0x3b, 0x20, 0x2e, 0x4e, +0x45, 0x54, 0x20, 0x43, 0x4c, 0x52, 0x20, 0x32, +0x2e, 0x30, 0x2e, 0x35, 0x30, 0x37, 0x32, 0x37, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30, +0x34, 0x35, 0x30, 0x36, 0x2e, 0x36, 0x34, 0x38, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x35, 0x2e, 0x32, +0x31, 0x30, 0x32, 0x32, 0x29, 0x0d, 0x0a, 0x48, +0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, +0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31, +0x32, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, +0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b, +0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, +0x65, 0x0d, 0x0a, 0x0d, 0x0a }; + +char pkt5[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x02, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa5, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt6[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa1, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x0a, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt7[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x02, 0x27, 0x09, 0xa2, 0x40, 0x00, 0x80, 0x06, +0x6d, 0x0a, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x18, +0x42, 0xd8, 0x84, 0x3e, 0x00, 0x00, 0x47, 0x45, +0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, +0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, +0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x2c, +0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, +0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, +0x2c, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, +0x6a, 0x70, 0x65, 0x67, 0x2c, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x70, 0x6a, 0x70, 0x65, +0x67, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, +0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, +0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, +0x63, 0x65, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c, +0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, +0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, +0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20, +0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, +0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, +0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70, +0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, +0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78, +0x62, 0x61, 0x70, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, +0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d, +0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, +0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, +0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, +0x20, 0x65, 0x6e, 0x2d, 0x67, 0x62, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, +0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, +0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64, +0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x0d, 0x0a, +0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, +0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69, +0x6c, 0x6c, 0x61, 0x2f, 0x34, 0x2e, 0x30, 0x20, +0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, +0x62, 0x6c, 0x65, 0x3b, 0x20, 0x4d, 0x53, 0x49, +0x45, 0x20, 0x36, 0x2e, 0x30, 0x3b, 0x20, 0x57, +0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e, +0x54, 0x20, 0x35, 0x2e, 0x31, 0x3b, 0x20, 0x53, +0x56, 0x31, 0x3b, 0x20, 0x47, 0x6f, 0x6f, 0x67, +0x6c, 0x65, 0x54, 0x35, 0x3b, 0x20, 0x2e, 0x4e, +0x45, 0x54, 0x20, 0x43, 0x4c, 0x52, 0x20, 0x32, +0x2e, 0x30, 0x2e, 0x35, 0x30, 0x37, 0x32, 0x37, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30, +0x34, 0x35, 0x30, 0x36, 0x2e, 0x36, 0x34, 0x38, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x35, 0x2e, 0x32, +0x31, 0x30, 0x32, 0x32, 0x29, 0x0d, 0x0a, 0x48, +0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, +0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31, +0x32, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, +0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b, +0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, +0x65, 0x0d, 0x0a, 0x0d, 0x0a }; + +char pkt8[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x03, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa4, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt9[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa3, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x08, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt10[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x04, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa3, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt11[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa6, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x05, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt12[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa7, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x04, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x14, +0x00, 0x00, 0x43, 0xf4, 0x00, 0x00 }; + + +typedef struct +{ + char *pcData; + int iDataLen; +} xPacketData; + +xPacketData xAllPackets[] = +{ + { pkt1, sizeof( pkt1 ) }, +// { pkt2, sizeof( pkt2 ) }, + { pkt3, sizeof( pkt3 ) }, + { pkt4, sizeof( pkt4 ) }, +// { pkt5, sizeof( pkt5 ) }, + { pkt6, sizeof( pkt6 ) }, + { pkt7, sizeof( pkt7 ) }, + { pkt8, sizeof( pkt8 ) }, + { pkt9, sizeof( pkt9 ) }, + { pkt10, sizeof( pkt10 ) }, +// { pkt11, sizeof( pkt11 ) }, +// { pkt12, sizeof( pkt12 ) }, +// { pkt13, sizeof( pkt13 ) }, +// { pkt14, sizeof( pkt14 ) }, +// { pkt15, sizeof( pkt15 ) }, +// { pkt16, sizeof( pkt16 ) }, +}; diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/Win32-Extensions.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/Win32-Extensions.h new file mode 100644 index 000000000..be71c85e9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/Win32-Extensions.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + + +#ifndef __WIN32_EXTENSIONS_H__ +#define __WIN32_EXTENSIONS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Definitions */ + +/*! + \brief A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit(). +*/ +struct pcap_send_queue +{ + u_int maxlen; ///< Maximum size of the the queue, in bytes. This variable contains the size of the buffer field. + u_int len; ///< Current size of the queue, in bytes. + char *buffer; ///< Buffer containing the packets to be sent. +}; + +typedef struct pcap_send_queue pcap_send_queue; + +/*! + \brief This typedef is a support for the pcap_get_airpcap_handle() function +*/ +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +typedef struct _AirpcapHandle *PAirpcapHandle; +#endif + +#define BPF_MEM_EX_IMM 0xc0 +#define BPF_MEM_EX_IND 0xe0 + +/*used for ST*/ +#define BPF_MEM_EX 0xc0 +#define BPF_TME 0x08 + +#define BPF_LOOKUP 0x90 +#define BPF_EXECUTE 0xa0 +#define BPF_INIT 0xb0 +#define BPF_VALIDATE 0xc0 +#define BPF_SET_ACTIVE 0xd0 +#define BPF_RESET 0xe0 +#define BPF_SET_MEMORY 0x80 +#define BPF_GET_REGISTER_VALUE 0x70 +#define BPF_SET_REGISTER_VALUE 0x60 +#define BPF_SET_WORKING 0x50 +#define BPF_SET_ACTIVE_READ 0x40 +#define BPF_SET_AUTODELETION 0x30 +#define BPF_SEPARATION 0xff + +/* Prototypes */ +pcap_send_queue* pcap_sendqueue_alloc(u_int memsize); + +void pcap_sendqueue_destroy(pcap_send_queue* queue); + +int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data); + +u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync); + +HANDLE pcap_getevent(pcap_t *p); + +struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size); + +int pcap_setuserbuffer(pcap_t *p, int size); + +int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks); + +int pcap_live_dump_ended(pcap_t *p, int sync); + +int pcap_offline_filter(struct bpf_program *prog, const struct pcap_pkthdr *header, const u_char *pkt_data); + +int pcap_start_oem(char* err_str, int flags); + +PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p); + +#ifdef __cplusplus +} +#endif + +#endif //__WIN32_EXTENSIONS_H__ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/arch.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/arch.c new file mode 100644 index 000000000..02bf82bf9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/arch.c @@ -0,0 +1,336 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* WinPCap includes. */ +#include "pcap.h" +#include "remote-ext.h" + +/* uIP includes. */ +#include "net/uip.h" +#include "net/uip_arp.h" +#include "net/clock-arch.h" + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* + * Query the computer the simulation is being executed on to find the network + * interfaces it has installed. + */ +static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ); + +/* + * Open the network interface. The number of the interface to be opened is set + * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. + */ +static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ); + +/* + * Configure the capture filter to allow blocking reads, and to filter out + * packets that are not of interest to this demo. + */ +static void prvConfigureCaptureBehaviour( void ); + +pcap_t *pxOpenedInterfaceHandle = NULL; +LARGE_INTEGER freq, sys_start_time; + +#define archNUM_BUFFERS 5 +#define archNUM_BUFFER_POINTERS ( archNUM_BUFFERS - 1 ) + +static void prvInterruptSimulator( void *pvParameters ); + +static unsigned char ucEthernetBuffer[ archNUM_BUFFERS ][ UIP_CONF_BUFFER_SIZE ]; +static unsigned char *pucEthernetBufferPointers[ archNUM_BUFFER_POINTERS ]; + +static long lLengthOfDataInBuffer[ archNUM_BUFFER_POINTERS ] = { 0 }; +static unsigned char ucNextBufferToFill = 0U, ucNextBufferToProcess = 0U; + +unsigned char *uip_buf = NULL; +char cErrorBuffer[PCAP_ERRBUF_SIZE]; + +void vNetifTx( void ) +{ + pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len ); + pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len ); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxNetifRx( void ) +{ +UBaseType_t xDataLen; +unsigned char *pucTemp; + + /* Check there is really data available. */ + xDataLen = lLengthOfDataInBuffer[ ucNextBufferToProcess ]; + if( xDataLen != 0L ) + { + + /* The buffer pointed to by uip_buf is going to change. Remember which + buffer uip_buf is currently pointing to. */ + pucTemp = uip_buf; + + /* Point uip_buf at the next buffer that contains data. */ + uip_buf = pucEthernetBufferPointers[ ucNextBufferToProcess ]; + + /* The buffer pointed to by + pucEthernetBufferPointeres[ ucNextBufferToProcess ] is now in use by + uip_buf, but the buffer uip_buf was pointing to on entry to this + function is free. Set + pucEthernetBufferPointeres[ ucNextBufferToProcess ] to the free + buffer. */ + pucEthernetBufferPointers[ ucNextBufferToProcess ] = pucTemp; + lLengthOfDataInBuffer[ ucNextBufferToProcess ] = 0L; + + ucNextBufferToProcess++; + if( ucNextBufferToProcess >= archNUM_BUFFER_POINTERS ) + { + ucNextBufferToProcess = 0L; + } + } + + return xDataLen; +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetifInit( void ) +{ +BaseType_t x; +pcap_if_t *pxAllNetworkInterfaces; + + /* Allocate a free buffer to each buffer pointer. */ + for( x = 0; x < sizeof( pucEthernetBufferPointers ) / sizeof( unsigned char * ); x++ ) + { + pucEthernetBufferPointers[ x ] = &( ucEthernetBuffer[ x ][ 0 ] ); + } + + /* Start with uip_buf pointing to a buffer that is not referenced from the + pucEthernetBufferPointers[] array. */ + uip_buf = &( ucEthernetBuffer[ archNUM_BUFFERS - 1 ][ 0 ] ); + + /* Query the computer the simulation is being executed on to find the + network interfaces it has installed. */ + pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces(); + + /* Open the network interface. The number of the interface to be opened is + set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. + Calling this function will set the pxOpenedInterfaceHandle variable. If, + after calling this function, pxOpenedInterfaceHandle is equal to NULL, then + the interface could not be opened. */ + if( pxAllNetworkInterfaces != NULL ) + { + prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces ); + } + + + return x; +} +/*-----------------------------------------------------------*/ + +static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ) +{ +pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface; +long lInterfaceNumber = 1; + + if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 ) + { + printf( "\r\nCould not obtain a list of network interfaces\r\n%s\r\n", cErrorBuffer ); + pxAllNetworkInterfaces = NULL; + } + + if( pxAllNetworkInterfaces != NULL ) + { + /* Print out the list of network interfaces. The first in the list + is interface '1', not interface '0'. */ + for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next ) + { + printf( "%d. %s", lInterfaceNumber, xInterface->name ); + + if( xInterface->description != NULL ) + { + printf( " (%s)\r\n", xInterface->description ); + } + else + { + printf( " (No description available)\r\n") ; + } + + lInterfaceNumber++; + } + } + + if( lInterfaceNumber == 1 ) + { + /* The interface number was never incremented, so the above for() loop + did not execute meaning no interfaces were found. */ + printf( " \r\nNo network interfaces were found.\r\n" ); + pxAllNetworkInterfaces = NULL; + } + + printf( "\r\nThe interface that will be opened is set by configNETWORK_INTERFACE_TO_USE which should be defined in FreeRTOSConfig.h\r\n" ); + printf( "Attempting to open interface number %d.\r\n", configNETWORK_INTERFACE_TO_USE ); + + if( ( configNETWORK_INTERFACE_TO_USE < 1L ) || ( configNETWORK_INTERFACE_TO_USE > lInterfaceNumber ) ) + { + printf("\r\nconfigNETWORK_INTERFACE_TO_USE is not in the valid range.\r\n" ); + + if( pxAllNetworkInterfaces != NULL ) + { + /* Free the device list, as no devices are going to be opened. */ + pcap_freealldevs( pxAllNetworkInterfaces ); + pxAllNetworkInterfaces = NULL; + } + } + + return pxAllNetworkInterfaces; +} +/*-----------------------------------------------------------*/ + +static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ) +{ +pcap_if_t *xInterface; +long x; + + /* Walk the list of devices until the selected device is located. */ + xInterface = pxAllNetworkInterfaces; + for( x = 0L; x < ( configNETWORK_INTERFACE_TO_USE - 1L ); x++ ) + { + xInterface = xInterface->next; + } + + /* Open the selected interface. */ + pxOpenedInterfaceHandle = pcap_open( xInterface->name, /* The name of the selected interface. */ + UIP_CONF_BUFFER_SIZE, /* The size of the packet to capture. */ + PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscious mode as the MAC and + IP address is going to be "simulated", and + not be the real MAC and IP address. This allows + trafic to the simulated IP address to be routed + to uIP, and trafic to the real IP address to be + routed to the Windows TCP/IP stack. */ + 0xfffffffL, /* The read time out. This is going to block + until data is available. */ + NULL, /* No authentication is required as this is + not a remote capture session. */ + cErrorBuffer + ); + + if ( pxOpenedInterfaceHandle == NULL ) + { + printf( "\r\n%s is not supported by WinPcap and cannot be opened\r\n", xInterface->name ); + } + else + { + /* Configure the capture filter to allow blocking reads, and to filter + out packets that are not of interest to this demo. */ + prvConfigureCaptureBehaviour(); + } + + /* The device list is no longer required. */ + pcap_freealldevs( pxAllNetworkInterfaces ); +} +/*-----------------------------------------------------------*/ + +static void prvConfigureCaptureBehaviour( void ) +{ +struct bpf_program xFilterCode; +const long lMinBytesToCopy = 10L, lBlocking = 0L; +unsigned long ulNetMask; + + /* Unblock a read as soon as anything is received. */ + pcap_setmintocopy( pxOpenedInterfaceHandle, lMinBytesToCopy ); + + /* Allow blocking. */ + pcap_setnonblock( pxOpenedInterfaceHandle, lBlocking, cErrorBuffer ); + + /* Set up a filter so only the packets of interest are passed to the uIP + stack. cErrorBuffer is used for convenience to create the string. Don't + confuse this with an error message. */ + sprintf( cErrorBuffer, "broadcast or multicast or host %d.%d.%d.%d", configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 ); + + ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0; + + if( pcap_compile(pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 ) + { + printf("\r\nThe packet filter string is invalid\r\n" ); + } + else + { + if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 ) + { + printf( "\r\nAn error occurred setting the packet filter.\r\n" ); + } + } + + /* Create a task that simulates an interrupt in a real system. This will + block waiting for packets, then send a message to the uIP task when data + is available. */ + xTaskCreate( prvInterruptSimulator, ( signed char * ) "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, ( configuIP_TASK_PRIORITY - 1 ), NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvInterruptSimulator( void *pvParameters ) +{ +static struct pcap_pkthdr *pxHeader; +const unsigned char *pucPacketData; +extern QueueHandle_t xEMACEventQueue; +const unsigned long ulRxEvent = uipETHERNET_RX_EVENT; +long lResult; + + /* Just to kill the compiler warning. */ + ( void ) pvParameters; + + for( ;; ) + { + /* Get the next packet. */ + lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData ); + if( lResult ) + { + /* Is the next buffer into which data should be placed free? */ + if( lLengthOfDataInBuffer[ ucNextBufferToFill ] == 0L ) + { + /* Copy the data from the captured packet into the buffer. */ + memcpy( pucEthernetBufferPointers[ ucNextBufferToFill ], pucPacketData, pxHeader->len ); + + /* Note the amount of data that was copied. */ + lLengthOfDataInBuffer[ ucNextBufferToFill ] = pxHeader->len; + + /* Move onto the next buffer, wrapping around if necessary. */ + ucNextBufferToFill++; + if( ucNextBufferToFill >= archNUM_BUFFER_POINTERS ) + { + ucNextBufferToFill = 0U; + } + + /* Data was received and stored. Send a message to the uIP task + to let it know. */ + xQueueSendToBack( xEMACEventQueue, &ulRxEvent, portMAX_DELAY ); + } + } + } +} + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/bittypes.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/bittypes.h new file mode 100644 index 000000000..fcacd45fe --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/bittypes.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 1999 WIDE Project. + * 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. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. + */ +#ifndef _BITTYPES_H +#define _BITTYPES_H + +#ifndef HAVE_U_INT8_T + +#if SIZEOF_CHAR == 1 +typedef unsigned char u_int8_t; +typedef signed char _int8_t; +#elif SIZEOF_INT == 1 +typedef unsigned int u_int8_t; +typedef signed int int8_t; +#else /* XXX */ +#error "there's no appropriate type for u_int8_t" +#endif +#define HAVE_U_INT8_T 1 +#define HAVE_INT8_T 1 + +#endif /* HAVE_U_INT8_T */ + +#ifndef HAVE_U_INT16_T + +#if SIZEOF_SHORT == 2 +typedef unsigned short u_int16_t; +typedef signed short _int16_t; +#elif SIZEOF_INT == 2 +typedef unsigned int u_int16_t; +typedef signed int int16_t; +#elif SIZEOF_CHAR == 2 +typedef unsigned char u_int16_t; +typedef signed char int16_t; +#else /* XXX */ +#error "there's no appropriate type for u_int16_t" +#endif +#define HAVE_U_INT16_T 1 +#define HAVE_INT16_T 1 + +#endif /* HAVE_U_INT16_T */ + +#ifndef HAVE_U_INT32_T + +#if SIZEOF_INT == 4 +typedef unsigned int u_int32_t; +typedef signed int _int32_t; +#elif SIZEOF_LONG == 4 +typedef unsigned long u_int32_t; +typedef signed long int32_t; +#elif SIZEOF_SHORT == 4 +typedef unsigned short u_int32_t; +typedef signed short int32_t; +#else /* XXX */ +#error "there's no appropriate type for u_int32_t" +#endif +#define HAVE_U_INT32_T 1 +#define HAVE_INT32_T 1 + +#endif /* HAVE_U_INT32_T */ + +#ifndef HAVE_U_INT64_T +#if SIZEOF_LONG_LONG == 8 +typedef unsigned long long u_int64_t; +typedef long long int64_t; +#elif defined(_MSC_EXTENSIONS) +typedef unsigned _int64 u_int64_t; +typedef _int64 int64_t; +#elif SIZEOF_INT == 8 +typedef unsigned int u_int64_t; +#elif SIZEOF_LONG == 8 +typedef unsigned long u_int64_t; +#elif SIZEOF_SHORT == 8 +typedef unsigned short u_int64_t; +#else /* XXX */ +#error "there's no appropriate type for u_int64_t" +#endif + +#endif /* HAVE_U_INT64_T */ + +#ifndef PRId64 +#ifdef _MSC_EXTENSIONS +#define PRId64 "I64d" +#else /* _MSC_EXTENSIONS */ +#define PRId64 "lld" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRId64 */ + +#ifndef PRIo64 +#ifdef _MSC_EXTENSIONS +#define PRIo64 "I64o" +#else /* _MSC_EXTENSIONS */ +#define PRIo64 "llo" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIo64 */ + +#ifndef PRIx64 +#ifdef _MSC_EXTENSIONS +#define PRIx64 "I64x" +#else /* _MSC_EXTENSIONS */ +#define PRIx64 "llx" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIx64 */ + +#ifndef PRIu64 +#ifdef _MSC_EXTENSIONS +#define PRIu64 "I64u" +#else /* _MSC_EXTENSIONS */ +#define PRIu64 "llu" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIu64 */ + +#endif /* _BITTYPES_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/ip6_misc.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/ip6_misc.h new file mode 100644 index 000000000..96822d0e8 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/ip6_misc.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1993, 1994, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: /tcpdump/master/libpcap/Win32/Include/ip6_misc.h,v 1.5 2006-01-22 18:02:18 gianluca Exp $ (LBL) + */ + +/* + * This file contains a collage of declarations for IPv6 from FreeBSD not present in Windows + */ + +#include + +#include + +#ifndef __MINGW32__ +#define IN_MULTICAST(a) IN_CLASSD(a) +#endif + +#define IN_EXPERIMENTAL(a) ((((u_int32_t) (a)) & 0xf0000000) == 0xf0000000) + +#define IN_LOOPBACKNET 127 + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +/* IPv6 address */ +struct in6_addr + { + union + { + u_int8_t u6_addr8[16]; + u_int16_t u6_addr16[8]; + u_int32_t u6_addr32[4]; + } in6_u; +#define s6_addr in6_u.u6_addr8 +#define s6_addr16 in6_u.u6_addr16 +#define s6_addr32 in6_u.u6_addr32 +#define s6_addr64 in6_u.u6_addr64 + }; + +#define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } +#endif /* __MINGW32__ */ + + +#if (defined _MSC_VER) || (defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)) +typedef unsigned short sa_family_t; +#endif + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) + +#define __SOCKADDR_COMMON(sa_prefix) \ + sa_family_t sa_prefix##family + +/* Ditto, for IPv6. */ +struct sockaddr_in6 + { + __SOCKADDR_COMMON (sin6_); + u_int16_t sin6_port; /* Transport layer port # */ + u_int32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + }; + +#define IN6_IS_ADDR_V4MAPPED(a) \ + ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \ + (((u_int32_t *) (a))[2] == htonl (0xffff))) + +#define IN6_IS_ADDR_MULTICAST(a) (((u_int8_t *) (a))[0] == 0xff) + +#define IN6_IS_ADDR_LINKLOCAL(a) \ + ((((u_int32_t *) (a))[0] & htonl (0xffc00000)) == htonl (0xfe800000)) + +#define IN6_IS_ADDR_LOOPBACK(a) \ + (((u_int32_t *) (a))[0] == 0 && ((u_int32_t *) (a))[1] == 0 && \ + ((u_int32_t *) (a))[2] == 0 && ((u_int32_t *) (a))[3] == htonl (1)) +#endif /* __MINGW32__ */ + +#define ip6_vfc ip6_ctlun.ip6_un2_vfc +#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt +#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim +#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim + +#define nd_rd_type nd_rd_hdr.icmp6_type +#define nd_rd_code nd_rd_hdr.icmp6_code +#define nd_rd_cksum nd_rd_hdr.icmp6_cksum +#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0] + +/* + * IPV6 extension headers + */ +#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */ +#define IPPROTO_IPV6 41 /* IPv6 header. */ +#define IPPROTO_ROUTING 43 /* IPv6 routing header */ +#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ +#define IPPROTO_ESP 50 /* encapsulating security payload */ +#define IPPROTO_AH 51 /* authentication header */ +#define IPPROTO_ICMPV6 58 /* ICMPv6 */ +#define IPPROTO_NONE 59 /* IPv6 no next header */ +#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ +#define IPPROTO_PIM 103 /* Protocol Independent Multicast. */ + +#define IPV6_RTHDR_TYPE_0 0 + +/* Option types and related macros */ +#define IP6OPT_PAD1 0x00 /* 00 0 00000 */ +#define IP6OPT_PADN 0x01 /* 00 0 00001 */ +#define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ +#define IP6OPT_JUMBO_LEN 6 +#define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 */ + +#define IP6OPT_RTALERT_LEN 4 +#define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ +#define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ +#define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ +#define IP6OPT_MINLEN 2 + +#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */ +#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */ +#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */ +#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */ +#define IP6OPT_EID 0x8a /* 10 0 01010 */ + +#define IP6OPT_TYPE(o) ((o) & 0xC0) +#define IP6OPT_TYPE_SKIP 0x00 +#define IP6OPT_TYPE_DISCARD 0x40 +#define IP6OPT_TYPE_FORCEICMP 0x80 +#define IP6OPT_TYPE_ICMP 0xC0 + +#define IP6OPT_MUTABLE 0x20 + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +#ifndef EAI_ADDRFAMILY +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; +#endif +#endif /* __MINGW32__ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/netif.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/netif.h new file mode 100644 index 000000000..2d51478c0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/netif.h @@ -0,0 +1,52 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef NET_IF_H +#define NET_IF_H + +/* + * Send uip_len bytes from uip_buf to the network interface selected by the + * configNETWORK_INTERFACE_TO_USE constant (defined in FreeRTOSConfig.h). + */ +void vNetifTx( void ); + +/* + * Receive bytes from the network interface selected by the + * configNETWORK_INTERFACE_TO_USE constant (defined in FreeRTOSConfig.h). The + * bytes are placed in uip_buf. The number of bytes copied into uip_buf is + * returned. + */ +UBaseType_t uxNetifRx( void ); + +/* + * Prepare a packet capture session. This will print out all the network + * interfaces available, and the one actually used is set by the + * configNETWORK_INTERFACE_TO_USE constant that is defined in + * FreeRTOSConfig.h. */ +BaseType_t xNetifInit( void ); + +#endif /* NET_IF_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap-bpf.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap-bpf.h new file mode 100644 index 000000000..ff5b6e0da --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap-bpf.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.50 2007/04/01 21:43:55 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap-namedb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap-namedb.h new file mode 100644 index 000000000..ee6715fba --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap-namedb.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-namedb.h,v 1.13 2006/10/04 18:13:32 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap-stdinc.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap-stdinc.h new file mode 100644 index 000000000..cbd62d169 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap-stdinc.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-stdinc.h,v 1.10.2.1 2008-10-06 15:38:39 gianluca Exp $ (LBL) + */ + +#define SIZEOF_CHAR 1 +#define SIZEOF_SHORT 2 +#define SIZEOF_INT 4 +#ifndef _MSC_EXTENSIONS +#define SIZEOF_LONG_LONG 8 +#endif + +/* + * Avoids a compiler warning in case this was already defined + * (someone defined _WINSOCKAPI_ when including 'windows.h', in order + * to prevent it from including 'winsock.h') + */ +#ifdef _WINSOCKAPI_ +#undef _WINSOCKAPI_ +#endif +#include + +#include + +#include "bittypes.h" +#include +#include + +#ifndef __MINGW32__ +#include "IP6_misc.h" +#endif + +#define caddr_t char* + +#if _MSC_VER < 1500 +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#define strdup _strdup +#endif + +#define inline __inline + +#ifdef __MINGW32__ +#include +#else /*__MINGW32__*/ +/* MSVC compiler */ +#ifndef _UINTPTR_T_DEFINED +#ifdef _WIN64 +typedef unsigned __int64 uintptr_t; +#else +typedef _W64 unsigned int uintptr_t; +#endif +#define _UINTPTR_T_DEFINED +#endif + +#ifndef _INTPTR_T_DEFINED +#ifdef _WIN64 +typedef __int64 intptr_t; +#else +typedef _W64 int intptr_t; +#endif +#define _INTPTR_T_DEFINED +#endif + +#endif /*__MINGW32__*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap.h new file mode 100644 index 000000000..2eea0750b --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.59 2006/10/04 18:09:22 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Many applications + * expect to be able to include , and at least some of them + * go through contortions in their configure scripts to try to detect + * OSes that have "helpfully" moved pcap.h to without + * leaving behind a file. + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/bluetooth.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/bluetooth.h new file mode 100644 index 000000000..28b991f43 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/bluetooth.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * bluetooth data struct + * By Paolo Abeni + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/bluetooth.h,v 1.1 2007/09/22 02:10:17 guy Exp $ + */ + +#ifndef _PCAP_BLUETOOTH_STRUCTS_H__ +#define _PCAP_BLUETOOTH_STRUCTS_H__ + +/* + * Header prepended libpcap to each bluetooth h:4 frame. + * fields are in network byte order + */ +typedef struct _pcap_bluetooth_h4_header { + u_int32_t direction; /* if first bit is set direction is incoming */ +} pcap_bluetooth_h4_header; + + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/bpf.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/bpf.h new file mode 100644 index 000000000..b6d259679 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/bpf.h @@ -0,0 +1,934 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)bpf.h 7.1 (Berkeley) 5/7/91 + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/bpf.h,v 1.19.2.8 2008-09-22 20:16:01 guy Exp $ (LBL) + */ + +/* + * This is libpcap's cut-down version of bpf.h; it includes only + * the stuff needed for the code generator and the userland BPF + * interpreter, and the libpcap APIs for setting filters, etc.. + * + * "pcap-bpf.c" will include the native OS version, as it deals with + * the OS's BPF implementation. + * + * XXX - should this all just be moved to "pcap.h"? + */ + +#ifndef BPF_MAJOR_VERSION + +#ifdef __cplusplus +extern "C" { +#endif + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +#ifdef MSDOS /* must be 32-bit */ +typedef long bpf_int32; +typedef unsigned long bpf_u_int32; +#else +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +/* + * Alignment macros. BPF_WORDALIGN rounds up to the next + * even multiple of BPF_ALIGNMENT. + */ +#ifndef __NetBSD__ +#define BPF_ALIGNMENT sizeof(bpf_int32) +#else +#define BPF_ALIGNMENT sizeof(long) +#endif +#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) + +#define BPF_MAXBUFSIZE 0x8000 +#define BPF_MINBUFSIZE 32 + +/* + * Structure for "pcap_compile()", "pcap_setfilter()", etc.. + */ +struct bpf_program { + u_int bf_len; + struct bpf_insn *bf_insns; +}; + +/* + * Struct return by BIOCVERSION. This represents the version number of + * the filter language described by the instruction encodings below. + * bpf understands a program iff kernel_major == filter_major && + * kernel_minor >= filter_minor, that is, if the value returned by the + * running kernel has the same major number and a minor number equal + * equal to or less than the filter being downloaded. Otherwise, the + * results are undefined, meaning an error may be returned or packets + * may be accepted haphazardly. + * It has nothing to do with the source code version. + */ +struct bpf_version { + u_short bv_major; + u_short bv_minor; +}; +/* Current version number of filter architecture. */ +#define BPF_MAJOR_VERSION 1 +#define BPF_MINOR_VERSION 1 + +/* + * Data-link level type codes. + * + * Do *NOT* add new values to this list without asking + * "tcpdump-workers@lists.tcpdump.org" for a value. Otherwise, you run + * the risk of using a value that's already being used for some other + * purpose, and of having tools that read libpcap-format captures not + * being able to handle captures with your new DLT_ value, with no hope + * that they will ever be changed to do so (as that would destroy their + * ability to read captures using that value for that other purpose). + */ + +/* + * These are the types that are the same on all platforms, and that + * have been defined by for ages. + */ +#define DLT_NULL 0 /* BSD loopback encapsulation */ +#define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ +#define DLT_AX25 3 /* Amateur Radio AX.25 */ +#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ +#define DLT_CHAOS 5 /* Chaos */ +#define DLT_IEEE802 6 /* 802.5 Token Ring */ +#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ +#define DLT_SLIP 8 /* Serial Line IP */ +#define DLT_PPP 9 /* Point-to-point Protocol */ +#define DLT_FDDI 10 /* FDDI */ + +/* + * These are types that are different on some platforms, and that + * have been defined by for ages. We use #ifdefs to + * detect the BSDs that define them differently from the traditional + * libpcap + * + * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS, + * but I don't know what the right #define is for BSD/OS. + */ +#define DLT_ATM_RFC1483 11 /* LLC-encapsulated ATM */ + +#ifdef __OpenBSD__ +#define DLT_RAW 14 /* raw IP */ +#else +#define DLT_RAW 12 /* raw IP */ +#endif + +/* + * Given that the only OS that currently generates BSD/OS SLIP or PPP + * is, well, BSD/OS, arguably everybody should have chosen its values + * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they + * didn't. So it goes. + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) +#ifndef DLT_SLIP_BSDOS +#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ +#endif +#else +#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ +#endif + +/* + * 17 is used for DLT_OLD_PFLOG in OpenBSD; + * OBSOLETE: DLT_PFLOG is 117 in OpenBSD now as well. See below. + * 18 is used for DLT_PFSYNC in OpenBSD; don't use it for anything else. + */ + +#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ + +/* + * Apparently Redback uses this for its SmartEdge 400/800. I hope + * nobody else decided to use it, too. + */ +#define DLT_REDBACK_SMARTEDGE 32 + +/* + * These values are defined by NetBSD; other platforms should refrain from + * using them for other purposes, so that NetBSD savefiles with link + * types of 50 or 51 can be read as this type on all platforms. + */ +#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ +#define DLT_PPP_ETHER 51 /* PPP over Ethernet */ + +/* + * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses + * a link-layer type of 99 for the tcpdump it supplies. The link-layer + * header has 6 bytes of unknown data, something that appears to be an + * Ethernet type, and 36 bytes that appear to be 0 in at least one capture + * I've seen. + */ +#define DLT_SYMANTEC_FIREWALL 99 + +/* + * Values between 100 and 103 are used in capture file headers as + * link-layer types corresponding to DLT_ types that differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * This value was defined by libpcap 0.5; platforms that have defined + * it with a different value should define it here with that value - + * a link type of 104 in a save file will be mapped to DLT_C_HDLC, + * whatever value that happens to be, so programs will correctly + * handle files with that link type regardless of the value of + * DLT_C_HDLC. + * + * The name DLT_C_HDLC was used by BSD/OS; we use that name for source + * compatibility with programs written for BSD/OS. + * + * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, + * for source compatibility with programs written for libpcap 0.5. + */ +#define DLT_C_HDLC 104 /* Cisco HDLC */ +#define DLT_CHDLC DLT_C_HDLC + +#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ + +/* + * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW, + * except when it isn't. (I.e., sometimes it's just raw IP, and + * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL, + * so that we don't have to worry about the link-layer header.) + */ + +/* + * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides + * with other values. + * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header + * (DLCI, etc.). + */ +#define DLT_FRELAY 107 + +/* + * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except + * that the AF_ type in the link-layer header is in network byte order. + * + * DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so + * we don't use 12 for it in OSes other than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_LOOP 12 +#else +#define DLT_LOOP 108 +#endif + +/* + * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's + * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other + * than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_ENC 13 +#else +#define DLT_ENC 109 +#endif + +/* + * Values between 110 and 112 are reserved for use in capture file headers + * as link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ types + * other than the corresponding DLT_ types. + */ + +/* + * This is for Linux cooked sockets. + */ +#define DLT_LINUX_SLL 113 + +/* + * Apple LocalTalk hardware. + */ +#define DLT_LTALK 114 + +/* + * Acorn Econet. + */ +#define DLT_ECONET 115 + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define DLT_IPFILTER 116 + +/* + * OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, but that's DLT_LANE8023 + * in SuSE 6.3, so we can't use 17 for it in capture-file headers. + * + * XXX: is there a conflict with DLT_PFSYNC 18 as well? + */ +#ifdef __OpenBSD__ +#define DLT_OLD_PFLOG 17 +#define DLT_PFSYNC 18 +#endif +#define DLT_PFLOG 117 + +/* + * Registered for Cisco-internal use. + */ +#define DLT_CISCO_IOS 118 + +/* + * For 802.11 cards using the Prism II chips, with a link-layer + * header including Prism monitor mode information plus an 802.11 + * header. + */ +#define DLT_PRISM_HEADER 119 + +/* + * Reserved for Aironet 802.11 cards, with an Aironet link-layer header + * (see Doug Ambrisko's FreeBSD patches). + */ +#define DLT_AIRONET_HEADER 120 + +/* + * Reserved for Siemens HiPath HDLC. + */ +#define DLT_HHDLC 121 + +/* + * This is for RFC 2625 IP-over-Fibre Channel. + * + * This is not for use with raw Fibre Channel, where the link-layer + * header starts with a Fibre Channel frame header; it's for IP-over-FC, + * where the link-layer header starts with an RFC 2625 Network_Header + * field. + */ +#define DLT_IP_OVER_FC 122 + +/* + * This is for Full Frontal ATM on Solaris with SunATM, with a + * pseudo-header followed by an AALn PDU. + * + * There may be other forms of Full Frontal ATM on other OSes, + * with different pseudo-headers. + * + * If ATM software returns a pseudo-header with VPI/VCI information + * (and, ideally, packet type information, e.g. signalling, ILMI, + * LANE, LLC-multiplexed traffic, etc.), it should not use + * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump + * and the like don't have to infer the presence or absence of a + * pseudo-header and the form of the pseudo-header. + */ +#define DLT_SUNATM 123 /* Solaris+SunATM */ + +/* + * Reserved as per request from Kent Dahlgren + * for private use. + */ +#define DLT_RIO 124 /* RapidIO */ +#define DLT_PCI_EXP 125 /* PCI Express */ +#define DLT_AURORA 126 /* Xilinx Aurora link layer */ + +/* + * Header for 802.11 plus a number of bits of link-layer information + * including radio information, used by some recent BSD drivers as + * well as the madwifi Atheros driver for Linux. + */ +#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */ + +/* + * Reserved for the TZSP encapsulation, as per request from + * Chris Waters + * TZSP is a generic encapsulation for any other link type, + * which includes a means to include meta-information + * with the packet, e.g. signal strength and channel + * for 802.11 packets. + */ +#define DLT_TZSP 128 /* Tazmen Sniffer Protocol */ + +/* + * BSD's ARCNET headers have the source host, destination host, + * and type at the beginning of the packet; that's what's handed + * up to userland via BPF. + * + * Linux's ARCNET headers, however, have a 2-byte offset field + * between the host IDs and the type; that's what's handed up + * to userland via PF_PACKET sockets. + * + * We therefore have to have separate DLT_ values for them. + */ +#define DLT_ARCNET_LINUX 129 /* ARCNET */ + +/* + * Juniper-private data link types, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MLPPP 130 +#define DLT_JUNIPER_MLFR 131 +#define DLT_JUNIPER_ES 132 +#define DLT_JUNIPER_GGSN 133 +#define DLT_JUNIPER_MFR 134 +#define DLT_JUNIPER_ATM2 135 +#define DLT_JUNIPER_SERVICES 136 +#define DLT_JUNIPER_ATM1 137 + +/* + * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund + * . The header that's presented is an Ethernet-like + * header: + * + * #define FIREWIRE_EUI64_LEN 8 + * struct firewire_header { + * u_char firewire_dhost[FIREWIRE_EUI64_LEN]; + * u_char firewire_shost[FIREWIRE_EUI64_LEN]; + * u_short firewire_type; + * }; + * + * with "firewire_type" being an Ethernet type value, rather than, + * for example, raw GASP frames being handed up. + */ +#define DLT_APPLE_IP_OVER_IEEE1394 138 + +/* + * Various SS7 encapsulations, as per a request from Jeff Morriss + * and subsequent discussions. + */ +#define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */ +#define DLT_MTP2 140 /* MTP2, without pseudo-header */ +#define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */ +#define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */ + +/* + * DOCSIS MAC frames. + */ +#define DLT_DOCSIS 143 + +/* + * Linux-IrDA packets. Protocol defined at http://www.irda.org. + * Those packets include IrLAP headers and above (IrLMP...), but + * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy + * framing can be handled by the hardware and depend on the bitrate. + * This is exactly the format you would get capturing on a Linux-IrDA + * interface (irdaX), but not on a raw serial port. + * Note the capture is done in "Linux-cooked" mode, so each packet include + * a fake packet header (struct sll_header). This is because IrDA packet + * decoding is dependant on the direction of the packet (incomming or + * outgoing). + * When/if other platform implement IrDA capture, we may revisit the + * issue and define a real DLT_IRDA... + * Jean II + */ +#define DLT_LINUX_IRDA 144 + +/* + * Reserved for IBM SP switch and IBM Next Federation switch. + */ +#define DLT_IBM_SP 145 +#define DLT_IBM_SN 146 + +/* + * Reserved for private use. If you have some link-layer header type + * that you want to use within your organization, with the capture files + * using that link-layer header type not ever be sent outside your + * organization, you can use these values. + * + * No libpcap release will use these for any purpose, nor will any + * tcpdump release use them, either. + * + * Do *NOT* use these in capture files that you expect anybody not using + * your private versions of capture-file-reading tools to read; in + * particular, do *NOT* use them in products, otherwise you may find that + * people won't be able to use tcpdump, or snort, or Ethereal, or... to + * read capture files from your firewall/intrusion detection/traffic + * monitoring/etc. appliance, or whatever product uses that DLT_ value, + * and you may also find that the developers of those applications will + * not accept patches to let them read those files. + * + * Also, do not use them if somebody might send you a capture using them + * for *their* private type and tools using them for *your* private type + * would have to read them. + * + * Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value, + * as per the comment above, and use the type you're given. + */ +#define DLT_USER0 147 +#define DLT_USER1 148 +#define DLT_USER2 149 +#define DLT_USER3 150 +#define DLT_USER4 151 +#define DLT_USER5 152 +#define DLT_USER6 153 +#define DLT_USER7 154 +#define DLT_USER8 155 +#define DLT_USER9 156 +#define DLT_USER10 157 +#define DLT_USER11 158 +#define DLT_USER12 159 +#define DLT_USER13 160 +#define DLT_USER14 161 +#define DLT_USER15 162 + +/* + * For future use with 802.11 captures - defined by AbsoluteValue + * Systems to store a number of bits of link-layer information + * including radio information: + * + * http://www.shaftnet.org/~pizza/software/capturefrm.txt + * + * but it might be used by some non-AVS drivers now or in the + * future. + */ +#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MONITOR 164 + +/* + * Reserved for BACnet MS/TP. + */ +#define DLT_BACNET_MS_TP 165 + +/* + * Another PPP variant as per request from Karsten Keil . + * + * This is used in some OSes to allow a kernel socket filter to distinguish + * between incoming and outgoing packets, on a socket intended to + * supply pppd with outgoing packets so it can do dial-on-demand and + * hangup-on-lack-of-demand; incoming packets are filtered out so they + * don't cause pppd to hold the connection up (you don't want random + * input packets such as port scans, packets from old lost connections, + * etc. to force the connection to stay up). + * + * The first byte of the PPP header (0xff03) is modified to accomodate + * the direction - 0x00 = IN, 0x01 = OUT. + */ +#define DLT_PPP_PPPD 166 + +/* + * Names for backwards compatibility with older versions of some PPP + * software; new software should use DLT_PPP_PPPD. + */ +#define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD +#define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, cookies, etc.. + */ +#define DLT_JUNIPER_PPPOE 167 +#define DLT_JUNIPER_PPPOE_ATM 168 + +#define DLT_GPRS_LLC 169 /* GPRS LLC */ +#define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ +#define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ + +/* + * Requested by Oolan Zimmer for use in Gcom's T1/E1 line + * monitoring equipment. + */ +#define DLT_GCOM_T1E1 172 +#define DLT_GCOM_SERIAL 173 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_ is used + * for internal communication to Physical Interface Cards (PIC) + */ +#define DLT_JUNIPER_PIC_PEER 174 + +/* + * Link types requested by Gregor Maier of Endace + * Measurement Systems. They add an ERF header (see + * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of + * the link-layer header. + */ +#define DLT_ERF_ETH 175 /* Ethernet */ +#define DLT_ERF_POS 176 /* Packet-over-SONET */ + +/* + * Requested by Daniele Orlandi for raw LAPD + * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header + * includes additional information before the LAPD header, so it's + * not necessarily a generic LAPD header. + */ +#define DLT_LINUX_LAPD 177 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ are used for prepending meta-information + * like interface index, interface name + * before standard Ethernet, PPP, Frelay & C-HDLC Frames + */ +#define DLT_JUNIPER_ETHER 178 +#define DLT_JUNIPER_PPP 179 +#define DLT_JUNIPER_FRELAY 180 +#define DLT_JUNIPER_CHDLC 181 + +/* + * Multi Link Frame Relay (FRF.16) + */ +#define DLT_MFR 182 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * voice Adapter Card (PIC) + */ +#define DLT_JUNIPER_VP 183 + +/* + * Arinc 429 frames. + * DLT_ requested by Gianluca Varenni . + * Every frame contains a 32bit A429 label. + * More documentation on Arinc 429 can be found at + * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf + */ +#define DLT_A429 184 + +/* + * Arinc 653 Interpartition Communication messages. + * DLT_ requested by Gianluca Varenni . + * Please refer to the A653-1 standard for more information. + */ +#define DLT_A653_ICM 185 + +/* + * USB packets, beginning with a USB setup header; requested by + * Paolo Abeni . + */ +#define DLT_USB 186 + +/* + * Bluetooth HCI UART transport layer (part H:4); requested by + * Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4 187 + +/* + * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz + * . + */ +#define DLT_IEEE802_16_MAC_CPS 188 + +/* + * USB packets, beginning with a Linux USB header; requested by + * Paolo Abeni . + */ +#define DLT_USB_LINUX 189 + +/* + * Controller Area Network (CAN) v. 2.0B packets. + * DLT_ requested by Gianluca Varenni . + * Used to dump CAN packets coming from a CAN Vector board. + * More documentation on the CAN v2.0B frames can be found at + * http://www.can-cia.org/downloads/?269 + */ +#define DLT_CAN20B 190 + +/* + * IEEE 802.15.4, with address fields padded, as is done by Linux + * drivers; requested by Juergen Schimmer. + */ +#define DLT_IEEE802_15_4_LINUX 191 + +/* + * Per Packet Information encapsulated packets. + * DLT_ requested by Gianluca Varenni . + */ +#define DLT_PPI 192 + +/* + * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; + * requested by Charles Clancy. + */ +#define DLT_IEEE802_16_MAC_CPS_RADIO 193 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * integrated service module (ISM). + */ +#define DLT_JUNIPER_ISM 194 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing); requested by Mikko Saarnivala . + */ +#define DLT_IEEE802_15_4 195 + +/* + * Various link-layer types, with a pseudo-header, for SITA + * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). + */ +#define DLT_SITA 196 + +/* + * Various link-layer types, with a pseudo-header, for Endace DAG cards; + * encapsulates Endace ERF records. Requested by Stephen Donnelly + * . + */ +#define DLT_ERF 197 + +/* + * Special header prepended to Ethernet packets when capturing from a + * u10 Networks board. Requested by Phil Mulholland + * . + */ +#define DLT_RAIF1 198 + +/* + * IPMB packet for IPMI, beginning with the I2C slave address, followed + * by the netFn and LUN, etc.. Requested by Chanthy Toeung + * . + */ +#define DLT_IPMB 199 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for capturing data on a secure tunnel interface. + */ +#define DLT_JUNIPER_ST 200 + +/* + * Bluetooth HCI UART transport layer (part H:4), with pseudo-header + * that includes direction information; requested by Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4_WITH_PHDR 201 + +/* + * AX.25 packet with a 1-byte KISS header; see + * + * http://www.ax25.net/kiss.htm + * + * as per Richard Stearn . + */ +#define DLT_AX25_KISS 202 + +/* + * LAPD packets from an ISDN channel, starting with the address field, + * with no pseudo-header. + * Requested by Varuna De Silva . + */ +#define DLT_LAPD 203 + +/* + * Variants of various link-layer headers, with a one-byte direction + * pseudo-header prepended - zero means "received by this host", + * non-zero (any non-zero value) means "sent by this host" - as per + * Will Barker . + */ +#define DLT_PPP_WITH_DIR 204 /* PPP - don't confuse with DLT_PPP_WITH_DIRECTION */ +#define DLT_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ +#define DLT_FRELAY_WITH_DIR 206 /* Frame Relay */ +#define DLT_LAPB_WITH_DIR 207 /* LAPB */ + +/* + * 208 is reserved for an as-yet-unspecified proprietary link-layer + * type, as requested by Will Barker. + */ + +/* + * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman + * . + */ +#define DLT_IPMB_LINUX 209 + +/* + * FlexRay automotive bus - http://www.flexray.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_FLEXRAY 210 + +/* + * Media Oriented Systems Transport (MOST) bus for multimedia + * transport - http://www.mostcooperation.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_MOST 211 + +/* + * Local Interconnect Network (LIN) bus for vehicle networks - + * http://www.lin-subbus.org/ - as requested by Hannes Kaelber + * . + */ +#define DLT_LIN 212 + +/* + * X2E-private data link type used for serial line capture, + * as requested by Hannes Kaelber . + */ +#define DLT_X2E_SERIAL 213 + +/* + * X2E-private data link type used for the Xoraya data logger + * family, as requested by Hannes Kaelber . + */ +#define DLT_X2E_XORAYA 214 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), but with the PHY-level data for non-ASK PHYs (4 octets + * of 0 as preamble, one octet of SFD, one octet of frame length+ + * reserved bit, and then the MAC-layer data, starting with the + * frame control field). + * + * Requested by Max Filippov . + */ +#define DLT_IEEE802_15_4_NONASK_PHY 215 + + +/* + * DLT and savefile link type values are split into a class and + * a member of that class. A class value of 0 indicates a regular + * DLT_/LINKTYPE_ value. + */ +#define DLT_CLASS(x) ((x) & 0x03ff0000) + +/* + * NetBSD-specific generic "raw" link type. The class value indicates + * that this is the generic raw type, and the lower 16 bits are the + * address family we're dealing with. Those values are NetBSD-specific; + * do not assume that they correspond to AF_ values for your operating + * system. + */ +#define DLT_CLASS_NETBSD_RAWAF 0x02240000 +#define DLT_NETBSD_RAWAF(af) (DLT_CLASS_NETBSD_RAWAF | (af)) +#define DLT_NETBSD_RAWAF_AF(x) ((x) & 0x0000ffff) +#define DLT_IS_NETBSD_RAWAF(x) (DLT_CLASS(x) == DLT_CLASS_NETBSD_RAWAF) + + +/* + * The instruction encodings. + */ +/* instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* ret - BPF_K and BPF_X also apply */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 + +/* misc */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +#define BPF_TXA 0x80 + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_u_int32 k; +}; + +/* + * Macros for insn array initializers. + */ +#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } +#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } + +#if __STDC__ || defined(__cplusplus) +extern int bpf_validate(const struct bpf_insn *, int); +extern u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +#else +extern int bpf_validate(); +extern u_int bpf_filter(); +#endif + +/* + * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). + */ +#define BPF_MEMWORDS 16 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/namedb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/namedb.h new file mode 100644 index 000000000..8298e35b9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/namedb.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/namedb.h,v 1.1 2006/10/04 18:09:22 guy Exp $ (LBL) + */ + +#ifndef lib_pcap_namedb_h +#define lib_pcap_namedb_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * As returned by the pcap_next_etherent() + * XXX this stuff doesn't belong in this interface, but this + * library already must do name to address translation, so + * on systems that don't have support for /etc/ethers, we + * export these hooks since they'll + */ +struct pcap_etherent { + u_char addr[6]; + char name[122]; +}; +#ifndef PCAP_ETHERS_FILE +#define PCAP_ETHERS_FILE "/etc/ethers" +#endif +struct pcap_etherent *pcap_next_etherent(FILE *); +u_char *pcap_ether_hostton(const char*); +u_char *pcap_ether_aton(const char *); + +bpf_u_int32 **pcap_nametoaddr(const char *); +#ifdef INET6 +struct addrinfo *pcap_nametoaddrinfo(const char *); +#endif +bpf_u_int32 pcap_nametonetaddr(const char *); + +int pcap_nametoport(const char *, int *, int *); +int pcap_nametoportrange(const char *, int *, int *, int *); +int pcap_nametoproto(const char *); +int pcap_nametoeproto(const char *); +int pcap_nametollc(const char *); +/* + * If a protocol is unknown, PROTO_UNDEF is returned. + * Also, pcap_nametoport() returns the protocol along with the port number. + * If there are ambiguous entried in /etc/services (i.e. domain + * can be either tcp or udp) PROTO_UNDEF is returned. + */ +#define PROTO_UNDEF -1 + +/* XXX move these to pcap-int.h? */ +int __pcap_atodn(const char *, bpf_u_int32 *); +int __pcap_atoin(const char *, bpf_u_int32 *); +u_short __pcap_nametodnaddr(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/pcap.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/pcap.h new file mode 100644 index 000000000..fbf83413a --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/pcap.h @@ -0,0 +1,407 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/pcap.h,v 1.4.2.11 2008-10-06 15:38:39 gianluca Exp $ (LBL) + */ + +#ifndef lib_pcap_pcap_h +#define lib_pcap_pcap_h + +#if defined(WIN32) + #include +#elif defined(MSDOS) + #include + #include /* u_int, u_char etc. */ +#else /* UN*X */ + #include + #include +#endif /* WIN32/MSDOS/UN*X */ + +#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H +#include +#endif + +#include + +#ifdef HAVE_REMOTE + // We have to define the SOCKET here, although it has been defined in sockutils.h + // This is to avoid the distribution of the 'sockutils.h' file around + // (for example in the WinPcap developer's pack) + #ifndef SOCKET + #ifdef WIN32 + #define SOCKET unsigned int + #else + #define SOCKET int + #endif + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 + +#define PCAP_ERRBUF_SIZE 256 + +/* + * Compatibility for systems that have a bpf.h that + * predates the bpf typedefs for 64-bit support. + */ +#if BPF_RELEASE - 0 < 199406 +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +typedef struct pcap pcap_t; +typedef struct pcap_dumper pcap_dumper_t; +typedef struct pcap_if pcap_if_t; +typedef struct pcap_addr pcap_addr_t; + +/* + * The first record in the file contains saved values for some + * of the flags used in the printout phases of tcpdump. + * Many fields here are 32 bit ints so compilers won't insert unwanted + * padding; these files need to be interchangeable across architectures. + * + * Do not change the layout of this structure, in any way (this includes + * changes that only affect the length of fields in this structure). + * + * Also, do not change the interpretation of any of the members of this + * structure, in any way (this includes using values other than + * LINKTYPE_ values, as defined in "savefile.c", in the "linktype" + * field). + * + * Instead: + * + * introduce a new structure for the new format, if the layout + * of the structure changed; + * + * send mail to "tcpdump-workers@lists.tcpdump.org", requesting + * a new magic number for your new capture file format, and, when + * you get the new magic number, put it in "savefile.c"; + * + * use that magic number for save files with the changed file + * header; + * + * make the code in "savefile.c" capable of reading files with + * the old file header as well as files with the new file header + * (using the magic number to determine the header format). + * + * Then supply the changes as a patch at + * + * http://sourceforge.net/projects/libpcap/ + * + * so that future versions of libpcap and programs that use it (such as + * tcpdump) will be able to read your new capture file format. + */ +struct pcap_file_header { + bpf_u_int32 magic; + u_short version_major; + u_short version_minor; + bpf_int32 thiszone; /* gmt to local correction */ + bpf_u_int32 sigfigs; /* accuracy of timestamps */ + bpf_u_int32 snaplen; /* max length saved portion of each pkt */ + bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ +}; + +/* + * Macros for the value returned by pcap_datalink_ext(). + * + * If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro + * gives the FCS length of packets in the capture. + */ +#define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000) +#define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28) +#define LT_FCS_DATALINK_EXT(x) ((((x) & 0xF) << 28) | 0x04000000) + +typedef enum { + PCAP_D_INOUT = 0, + PCAP_D_IN, + PCAP_D_OUT +} pcap_direction_t; + +/* + * Generic per-packet information, as supplied by libpcap. + * + * The time stamp can and should be a "struct timeval", regardless of + * whether your system supports 32-bit tv_sec in "struct timeval", + * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit + * and 64-bit applications. The on-disk format of savefiles uses 32-bit + * tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit + * and 64-bit versions of libpcap, even if they're on the same platform, + * should supply the appropriate version of "struct timeval", even if + * that's not what the underlying packet capture mechanism supplies. + */ +struct pcap_pkthdr { + struct timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ +}; + +/* + * As returned by the pcap_stats() + */ +struct pcap_stat { + u_int ps_recv; /* number of packets received */ + u_int ps_drop; /* number of packets dropped */ + u_int ps_ifdrop; /* drops by interface XXX not yet supported */ +#ifdef HAVE_REMOTE + u_int ps_capt; /* number of packets that are received by the application; please get rid off the Win32 ifdef */ + u_int ps_sent; /* number of packets sent by the server on the network */ + u_int ps_netdrop; /* number of packets lost on the network */ +#endif /* HAVE_REMOTE */ +}; + +#ifdef MSDOS +/* + * As returned by the pcap_stats_ex() + */ +struct pcap_stat_ex { + u_long rx_packets; /* total packets received */ + u_long tx_packets; /* total packets transmitted */ + u_long rx_bytes; /* total bytes received */ + u_long tx_bytes; /* total bytes transmitted */ + u_long rx_errors; /* bad packets received */ + u_long tx_errors; /* packet transmit problems */ + u_long rx_dropped; /* no space in Rx buffers */ + u_long tx_dropped; /* no space available for Tx */ + u_long multicast; /* multicast packets received */ + u_long collisions; + + /* detailed rx_errors: */ + u_long rx_length_errors; + u_long rx_over_errors; /* receiver ring buff overflow */ + u_long rx_crc_errors; /* recv'd pkt with crc error */ + u_long rx_frame_errors; /* recv'd frame alignment error */ + u_long rx_fifo_errors; /* recv'r fifo overrun */ + u_long rx_missed_errors; /* recv'r missed packet */ + + /* detailed tx_errors */ + u_long tx_aborted_errors; + u_long tx_carrier_errors; + u_long tx_fifo_errors; + u_long tx_heartbeat_errors; + u_long tx_window_errors; + }; +#endif + +/* + * Item in a list of interfaces. + */ +struct pcap_if { + struct pcap_if *next; + char *name; /* name to hand to "pcap_open_live()" */ + char *description; /* textual description of interface, or NULL */ + struct pcap_addr *addresses; + bpf_u_int32 flags; /* PCAP_IF_ interface flags */ +}; + +#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ + +/* + * Representation of an interface address. + */ +struct pcap_addr { + struct pcap_addr *next; + struct sockaddr *addr; /* address */ + struct sockaddr *netmask; /* netmask for that address */ + struct sockaddr *broadaddr; /* broadcast address for that address */ + struct sockaddr *dstaddr; /* P2P destination address for that address */ +}; + +typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, + const u_char *); + +/* + * Error codes for the pcap API. + * These will all be negative, so you can check for the success or + * failure of a call that returns these codes by checking for a + * negative value. + */ +#define PCAP_ERROR -1 /* generic error code */ +#define PCAP_ERROR_BREAK -2 /* loop terminated by pcap_breakloop */ +#define PCAP_ERROR_NOT_ACTIVATED -3 /* the capture needs to be activated */ +#define PCAP_ERROR_ACTIVATED -4 /* the operation can't be performed on already activated captures */ +#define PCAP_ERROR_NO_SUCH_DEVICE -5 /* no such device exists */ +#define PCAP_ERROR_RFMON_NOTSUP -6 /* this device doesn't support rfmon (monitor) mode */ +#define PCAP_ERROR_NOT_RFMON -7 /* operation supported only in monitor mode */ +#define PCAP_ERROR_PERM_DENIED -8 /* no permission to open the device */ +#define PCAP_ERROR_IFACE_NOT_UP -9 /* interface isn't up */ + +/* + * Warning codes for the pcap API. + * These will all be positive and non-zero, so they won't look like + * errors. + */ +#define PCAP_WARNING 1 /* generic warning code */ +#define PCAP_WARNING_PROMISC_NOTSUP 2 /* this device doesn't support promiscuous mode */ + +char *pcap_lookupdev(char *); +int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); + +pcap_t *pcap_create(const char *, char *); +int pcap_set_snaplen(pcap_t *, int); +int pcap_set_promisc(pcap_t *, int); +int pcap_can_set_rfmon(pcap_t *); +int pcap_set_rfmon(pcap_t *, int); +int pcap_set_timeout(pcap_t *, int); +int pcap_set_buffer_size(pcap_t *, int); +int pcap_activate(pcap_t *); + +pcap_t *pcap_open_live(const char *, int, int, int, char *); +pcap_t *pcap_open_dead(int, int); +pcap_t *pcap_open_offline(const char *, char *); +#if defined(WIN32) +pcap_t *pcap_hopen_offline(intptr_t, char *); +#if !defined(LIBPCAP_EXPORTS) +#define pcap_fopen_offline(f,b) \ + pcap_hopen_offline(_get_osfhandle(_fileno(f)), b) +#else /*LIBPCAP_EXPORTS*/ +static pcap_t *pcap_fopen_offline(FILE *, char *); +#endif +#else /*WIN32*/ +pcap_t *pcap_fopen_offline(FILE *, char *); +#endif /*WIN32*/ + +void pcap_close(pcap_t *); +int pcap_loop(pcap_t *, int, pcap_handler, u_char *); +int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); +const u_char* + pcap_next(pcap_t *, struct pcap_pkthdr *); +int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); +void pcap_breakloop(pcap_t *); +int pcap_stats(pcap_t *, struct pcap_stat *); +int pcap_setfilter(pcap_t *, struct bpf_program *); +int pcap_setdirection(pcap_t *, pcap_direction_t); +int pcap_getnonblock(pcap_t *, char *); +int pcap_setnonblock(pcap_t *, int, char *); +int pcap_inject(pcap_t *, const void *, size_t); +int pcap_sendpacket(pcap_t *, const u_char *, int); +const char *pcap_statustostr(int); +const char *pcap_strerror(int); +char *pcap_geterr(pcap_t *); +void pcap_perror(pcap_t *, char *); +int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, + bpf_u_int32); +int pcap_compile_nopcap(int, int, struct bpf_program *, + const char *, int, bpf_u_int32); +void pcap_freecode(struct bpf_program *); +int pcap_offline_filter(struct bpf_program *, const struct pcap_pkthdr *, + const u_char *); +int pcap_datalink(pcap_t *); +int pcap_datalink_ext(pcap_t *); +int pcap_list_datalinks(pcap_t *, int **); +int pcap_set_datalink(pcap_t *, int); +void pcap_free_datalinks(int *); +int pcap_datalink_name_to_val(const char *); +const char *pcap_datalink_val_to_name(int); +const char *pcap_datalink_val_to_description(int); +int pcap_snapshot(pcap_t *); +int pcap_is_swapped(pcap_t *); +int pcap_major_version(pcap_t *); +int pcap_minor_version(pcap_t *); + +/* XXX */ +FILE *pcap_file(pcap_t *); +int pcap_fileno(pcap_t *); + +pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); +pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); +FILE *pcap_dump_file(pcap_dumper_t *); +long pcap_dump_ftell(pcap_dumper_t *); +int pcap_dump_flush(pcap_dumper_t *); +void pcap_dump_close(pcap_dumper_t *); +void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); + +int pcap_findalldevs(pcap_if_t **, char *); +void pcap_freealldevs(pcap_if_t *); + +const char *pcap_lib_version(void); + +/* XXX this guy lives in the bpf tree */ +u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +int bpf_validate(const struct bpf_insn *f, int len); +char *bpf_image(const struct bpf_insn *, int); +void bpf_dump(const struct bpf_program *, int); + +#if defined(WIN32) + +/* + * Win32 definitions + */ + +int pcap_setbuff(pcap_t *p, int dim); +int pcap_setmode(pcap_t *p, int mode); +int pcap_setmintocopy(pcap_t *p, int size); + +#ifdef WPCAP +/* Include file with the wpcap-specific extensions */ +#include +#endif /* WPCAP */ + +#define MODE_CAPT 0 +#define MODE_STAT 1 +#define MODE_MON 2 + +#elif defined(MSDOS) + +/* + * MS-DOS definitions + */ + +int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *); +void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait); +u_long pcap_mac_packets (void); + +#else /* UN*X */ + +/* + * UN*X definitions + */ + +int pcap_get_selectable_fd(pcap_t *); + +#endif /* WIN32/MSDOS/UN*X */ + +#ifdef HAVE_REMOTE +/* Includes most of the public stuff that is needed for the remote capture */ +#include +#endif /* HAVE_REMOTE */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/sll.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/sll.h new file mode 100644 index 000000000..5907beded --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/sll.h @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/sll.h,v 1.2.2.1 2008-05-30 01:36:06 guy Exp $ (LBL) + */ + +/* + * For captures on Linux cooked sockets, we construct a fake header + * that includes: + * + * a 2-byte "packet type" which is one of: + * + * LINUX_SLL_HOST packet was sent to us + * LINUX_SLL_BROADCAST packet was broadcast + * LINUX_SLL_MULTICAST packet was multicast + * LINUX_SLL_OTHERHOST packet was sent to somebody else + * LINUX_SLL_OUTGOING packet was sent *by* us; + * + * a 2-byte Ethernet protocol field; + * + * a 2-byte link-layer type; + * + * a 2-byte link-layer address length; + * + * an 8-byte source link-layer address, whose actual length is + * specified by the previous value. + * + * All fields except for the link-layer address are in network byte order. + * + * DO NOT change the layout of this structure, or change any of the + * LINUX_SLL_ values below. If you must change the link-layer header + * for a "cooked" Linux capture, introduce a new DLT_ type (ask + * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it + * a value that collides with a value already being used), and use the + * new header in captures of that type, so that programs that can + * handle DLT_LINUX_SLL captures will continue to handle them correctly + * without any change, and so that capture files with different headers + * can be told apart and programs that read them can dissect the + * packets in them. + */ + +#ifndef lib_pcap_sll_h +#define lib_pcap_sll_h + +/* + * A DLT_LINUX_SLL fake link-layer header. + */ +#define SLL_HDR_LEN 16 /* total header length */ +#define SLL_ADDRLEN 8 /* length of address field */ + +struct sll_header { + u_int16_t sll_pkttype; /* packet type */ + u_int16_t sll_hatype; /* link-layer address type */ + u_int16_t sll_halen; /* link-layer address length */ + u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ + u_int16_t sll_protocol; /* protocol */ +}; + +/* + * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the + * PACKET_ values on Linux, but are defined here so that they're + * available even on systems other than Linux, and so that they + * don't change even if the PACKET_ values change. + */ +#define LINUX_SLL_HOST 0 +#define LINUX_SLL_BROADCAST 1 +#define LINUX_SLL_MULTICAST 2 +#define LINUX_SLL_OTHERHOST 3 +#define LINUX_SLL_OUTGOING 4 + +/* + * The LINUX_SLL_ values for "sll_protocol"; these correspond to the + * ETH_P_ values on Linux, but are defined here so that they're + * available even on systems other than Linux. We assume, for now, + * that the ETH_P_ values won't change in Linux; if they do, then: + * + * if we don't translate them in "pcap-linux.c", capture files + * won't necessarily be readable if captured on a system that + * defines ETH_P_ values that don't match these values; + * + * if we do translate them in "pcap-linux.c", that makes life + * unpleasant for the BPF code generator, as the values you test + * for in the kernel aren't the values that you test for when + * reading a capture file, so the fixup code run on BPF programs + * handed to the kernel ends up having to do more work. + * + * Add other values here as necessary, for handling packet types that + * might show up on non-Ethernet, non-802.x networks. (Not all the ones + * in the Linux "if_ether.h" will, I suspect, actually show up in + * captures.) + */ +#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ +#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/usb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/usb.h new file mode 100644 index 000000000..f150d3be0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/usb.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * Basic USB data struct + * By Paolo Abeni + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/usb.h,v 1.6 2007/09/22 02:06:08 guy Exp $ + */ + +#ifndef _PCAP_USB_STRUCTS_H__ +#define _PCAP_USB_STRUCTS_H__ + +/* + * possible transfer mode + */ +#define URB_TRANSFER_IN 0x80 +#define URB_ISOCHRONOUS 0x0 +#define URB_INTERRUPT 0x1 +#define URB_CONTROL 0x2 +#define URB_BULK 0x3 + +/* + * possible event type + */ +#define URB_SUBMIT 'S' +#define URB_COMPLETE 'C' +#define URB_ERROR 'E' + +/* + * USB setup header as defined in USB specification. + * Appears at the front of each packet in DLT_USB captures. + */ +typedef struct _usb_setup { + u_int8_t bmRequestType; + u_int8_t bRequest; + u_int16_t wValue; + u_int16_t wIndex; + u_int16_t wLength; +} pcap_usb_setup; + + +/* + * Header prepended by linux kernel to each event. + * Appears at the front of each packet in DLT_USB_LINUX captures. + */ +typedef struct _usb_header { + u_int64_t id; + u_int8_t event_type; + u_int8_t transfer_type; + u_int8_t endpoint_number; + u_int8_t device_address; + u_int16_t bus_id; + char setup_flag;/*if !=0 the urb setup header is not present*/ + char data_flag; /*if !=0 no urb data is present*/ + int64_t ts_sec; + int32_t ts_usec; + int32_t status; + u_int32_t urb_len; + u_int32_t data_len; /* amount of urb data really present in this event*/ + pcap_usb_setup setup; +} pcap_usb_header; + + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/vlan.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/vlan.h new file mode 100644 index 000000000..00ed9b616 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/pcap/vlan.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/vlan.h,v 1.1.2.2 2008-08-06 07:45:59 guy Exp $ + */ + +#ifndef lib_pcap_vlan_h +#define lib_pcap_vlan_h + +struct vlan_tag { + u_int16_t vlan_tpid; /* ETH_P_8021Q */ + u_int16_t vlan_tci; /* VLAN TCI */ +}; + +#define VLAN_TAG_LEN 4 + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/remote-ext.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/remote-ext.h new file mode 100644 index 000000000..9f54d6974 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/remote-ext.h @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * 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. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + + +#ifndef __REMOTE_EXT_H__ +#define __REMOTE_EXT_H__ + + +#ifndef HAVE_REMOTE +#error Please do not include this file directly. Just define HAVE_REMOTE and then include pcap.h +#endif + +// Definition for Microsoft Visual Studio +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + \file remote-ext.h + + The goal of this file it to include most of the new definitions that should be + placed into the pcap.h file. + + It includes all new definitions (structures and functions like pcap_open(). + Some of the functions are not really a remote feature, but, right now, + they are placed here. +*/ + + + +// All this stuff is public +/*! \addtogroup remote_struct + \{ +*/ + + + + +/*! + \brief Defines the maximum buffer size in which address, port, interface names are kept. + + In case the adapter name or such is larger than this value, it is truncated. + This is not used by the user; however it must be aware that an hostname / interface + name longer than this value will be truncated. +*/ +#define PCAP_BUF_SIZE 1024 + + +/*! \addtogroup remote_source_ID + \{ +*/ + + +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a file, i.e. the user want to open a capture from a local file. +*/ +#define PCAP_SRC_FILE 2 +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a local interface, i.e. the user want to open a capture from + a local interface. This does not involve the RPCAP protocol. +*/ +#define PCAP_SRC_IFLOCAL 3 +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a remote interface, i.e. the user want to open a capture from + an interface on a remote host. This does involve the RPCAP protocol. +*/ +#define PCAP_SRC_IFREMOTE 4 + +/*! + \} +*/ + + + +/*! \addtogroup remote_source_string + + The formats allowed by the pcap_open() are the following: + - file://path_and_filename [opens a local file] + - rpcap://devicename [opens the selected device devices available on the local host, without using the RPCAP protocol] + - rpcap://host/devicename [opens the selected device available on a remote host] + - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP] + - adaptername [to open a local adapter; kept for compability, but it is strongly discouraged] + - (NULL) [to open the first local adapter; kept for compability, but it is strongly discouraged] + + The formats allowed by the pcap_findalldevs_ex() are the following: + - file://folder/ [lists all the files in the given folder] + - rpcap:// [lists all local adapters] + - rpcap://host:port/ [lists the devices available on a remote host] + + Referring to the 'host' and 'port' paramters, they can be either numeric or literal. Since + IPv6 is fully supported, these are the allowed formats: + + - host (literal): e.g. host.foo.bar + - host (numeric IPv4): e.g. 10.11.12.13 + - host (numeric IPv4, IPv6 style): e.g. [10.11.12.13] + - host (numeric IPv6): e.g. [1:2:3::4] + - port: can be either numeric (e.g. '80') or literal (e.g. 'http') + + Here you find some allowed examples: + - rpcap://host.foo.bar/devicename [everything literal, no port number] + - rpcap://host.foo.bar:1234/devicename [everything literal, with port number] + - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number] + - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number] + - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number] + - rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number] + - rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number] + - rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number] + + \{ +*/ + + +/*! + \brief String that will be used to determine the type of source in use (file, + remote/local interface). + + This string will be prepended to the interface name in order to create a string + that contains all the information required to open the source. + + This string indicates that the user wants to open a capture from a local file. +*/ +#define PCAP_SRC_FILE_STRING "file://" +/*! + \brief String that will be used to determine the type of source in use (file, + remote/local interface). + + This string will be prepended to the interface name in order to create a string + that contains all the information required to open the source. + + This string indicates that the user wants to open a capture from a network interface. + This string does not necessarily involve the use of the RPCAP protocol. If the + interface required resides on the local host, the RPCAP protocol is not involved + and the local functions are used. +*/ +#define PCAP_SRC_IF_STRING "rpcap://" + +/*! + \} +*/ + + + + + +/*! + \addtogroup remote_open_flags + \{ +*/ + +/*! + \brief Defines if the adapter has to go in promiscuous mode. + + It is '1' if you have to open the adapter in promiscuous mode, '0' otherwise. + Note that even if this parameter is false, the interface could well be in promiscuous + mode for some other reason (for example because another capture process with + promiscuous mode enabled is currently using that interface). + On on Linux systems with 2.2 or later kernels (that have the "any" device), this + flag does not work on the "any" device; if an argument of "any" is supplied, + the 'promisc' flag is ignored. +*/ +#define PCAP_OPENFLAG_PROMISCUOUS 1 + +/*! + \brief Defines if the data trasfer (in case of a remote + capture) has to be done with UDP protocol. + + If it is '1' if you want a UDP data connection, '0' if you want + a TCP data connection; control connection is always TCP-based. + A UDP connection is much lighter, but it does not guarantee that all + the captured packets arrive to the client workstation. Moreover, + it could be harmful in case of network congestion. + This flag is meaningless if the source is not a remote interface. + In that case, it is simply ignored. +*/ +#define PCAP_OPENFLAG_DATATX_UDP 2 + + +/*! + \brief Defines if the remote probe will capture its own generated traffic. + + In case the remote probe uses the same interface to capture traffic and to send + data back to the caller, the captured traffic includes the RPCAP traffic as well. + If this flag is turned on, the RPCAP traffic is excluded from the capture, so that + the trace returned back to the collector is does not include this traffic. +*/ +#define PCAP_OPENFLAG_NOCAPTURE_RPCAP 4 + +/*! + \brief Defines if the local adapter will capture its own generated traffic. + + This flag tells the underlying capture driver to drop the packets that were sent by itself. + This is usefult when building applications like bridges, that should ignore the traffic + they just sent. +*/ +#define PCAP_OPENFLAG_NOCAPTURE_LOCAL 8 + +/*! + \brief This flag configures the adapter for maximum responsiveness. + + In presence of a large value for nbytes, WinPcap waits for the arrival of several packets before + copying the data to the user. This guarantees a low number of system calls, i.e. lower processor usage, + i.e. better performance, which is good for applications like sniffers. If the user sets the + PCAP_OPENFLAG_MAX_RESPONSIVENESS flag, the capture driver will copy the packets as soon as the application + is ready to receive them. This is suggested for real time applications (like, for example, a bridge) + that need the best responsiveness.*/ +#define PCAP_OPENFLAG_MAX_RESPONSIVENESS 16 + +/*! + \} +*/ + + +/*! + \addtogroup remote_samp_methods + \{ +*/ + +/*! + \brief No sampling has to be done on the current capture. + + In this case, no sampling algorithms are applied to the current capture. +*/ +#define PCAP_SAMP_NOSAMP 0 + +/*! + \brief It defines that only 1 out of N packets must be returned to the user. + + In this case, the 'value' field of the 'pcap_samp' structure indicates the + number of packets (minus 1) that must be discarded before one packet got accepted. + In other words, if 'value = 10', the first packet is returned to the caller, while + the following 9 are discarded. +*/ +#define PCAP_SAMP_1_EVERY_N 1 + +/*! + \brief It defines that we have to return 1 packet every N milliseconds. + + In this case, the 'value' field of the 'pcap_samp' structure indicates the 'waiting + time' in milliseconds before one packet got accepted. + In other words, if 'value = 10', the first packet is returned to the caller; the next + returned one will be the first packet that arrives when 10ms have elapsed. +*/ +#define PCAP_SAMP_FIRST_AFTER_N_MS 2 + +/*! + \} +*/ + + +/*! + \addtogroup remote_auth_methods + \{ +*/ + +/*! + \brief It defines the NULL authentication. + + This value has to be used within the 'type' member of the pcap_rmtauth structure. + The 'NULL' authentication has to be equal to 'zero', so that old applications + can just put every field of struct pcap_rmtauth to zero, and it does work. +*/ +#define RPCAP_RMTAUTH_NULL 0 +/*! + \brief It defines the username/password authentication. + + With this type of authentication, the RPCAP protocol will use the username/ + password provided to authenticate the user on the remote machine. If the + authentication is successful (and the user has the right to open network devices) + the RPCAP connection will continue; otherwise it will be dropped. + + This value has to be used within the 'type' member of the pcap_rmtauth structure. +*/ +#define RPCAP_RMTAUTH_PWD 1 + +/*! + \} +*/ + + + + +/*! + + \brief This structure keeps the information needed to autheticate + the user on a remote machine. + + The remote machine can either grant or refuse the access according + to the information provided. + In case the NULL authentication is required, both 'username' and + 'password' can be NULL pointers. + + This structure is meaningless if the source is not a remote interface; + in that case, the functions which requires such a structure can accept + a NULL pointer as well. +*/ +struct pcap_rmtauth +{ + /*! + \brief Type of the authentication required. + + In order to provide maximum flexibility, we can support different types + of authentication based on the value of this 'type' variable. The currently + supported authentication methods are defined into the + \link remote_auth_methods Remote Authentication Methods Section\endlink. + + */ + int type; + /*! + \brief Zero-terminated string containing the username that has to be + used on the remote machine for authentication. + + This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + and it can be NULL. + */ + char *username; + /*! + \brief Zero-terminated string containing the password that has to be + used on the remote machine for authentication. + + This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + and it can be NULL. + */ + char *password; +}; + + +/*! + \brief This structure defines the information related to sampling. + + In case the sampling is requested, the capturing device should read + only a subset of the packets coming from the source. The returned packets depend + on the sampling parameters. + + \warning The sampling process is applied after the filtering process. + In other words, packets are filtered first, then the sampling process selects a + subset of the 'filtered' packets and it returns them to the caller. +*/ +struct pcap_samp +{ + /*! + Method used for sampling. Currently, the supported methods are listed in the + \link remote_samp_methods Sampling Methods Section\endlink. + */ + int method; + + /*! + This value depends on the sampling method defined. For its meaning, please check + at the \link remote_samp_methods Sampling Methods Section\endlink. + */ + int value; +}; + + + + +//! Maximum lenght of an host name (needed for the RPCAP active mode) +#define RPCAP_HOSTLIST_SIZE 1024 + + +/*! + \} +*/ // end of public documentation + + +// Exported functions + + + +/** \name New WinPcap functions + + This section lists the new functions that are able to help considerably in writing + WinPcap programs because of their easiness of use. + */ +//\{ +pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf); +int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf); +int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf); +int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf); +struct pcap_samp *pcap_setsampling(pcap_t *p); + +//\} +// End of new winpcap functions + + + +/** \name Remote Capture functions + */ +//\{ +SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf); +int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf); +int pcap_remoteact_close(const char *host, char *errbuf); +void pcap_remoteact_cleanup(); +//\} +// End of remote capture functions + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/wpcap.lib b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/WinPCap/wpcap.lib new file mode 100644 index 0000000000000000000000000000000000000000..f832e0445b5c7dafe5a0f887262064265ba2b293 GIT binary patch literal 19320 zcmdU0O>9(05-uRW4k3h)gbS|j4}Uz#t>t&Y%Y)S%rl;4JTp5pCTuoh zr6{Lp73IKQa^QrbD7U>tdx#=VoK`4`_7Fwch+_^p| zS6BDfKh<5`)$NUA`Fde~ylZ#2`x_V>8Oe?2azi67zdwrRhWbZ!@NyRb{1af)Ai(As zfGr;YjQ*f$?=%3>0gMxkW0+_MhKYuM)O4~3fN1X*n)>bm5FNa!=@dc`jeVwR->(2f zr@qm2dK`f0IF?CtuvgRRPmzx_yk67JDF8*E;}+y2(SaM92H(eeAPs$`X>=9#JJEGb+ptfFdaw>e+iq*x`Yiy_8LSsk zPhHb?lqKrHekD4vPE+rP*gr_)Sa+hqpEMo(8T%RO(3GZ$?*SB*@r$$_@rd?+t!Zo@ zjvvxV99NR-y@~cP&F-(99u}FD=x9fbs_AYW3=3tr%W|L_8r?37d|TiVLY~ zEvy9P(zP&>67jfHb#AU)syKqo60(JIwPA#!ut>cUHY?T2Y`I#v8X-CyA=yYsIvgR1 z{ec~7x`z7J_EoXesO6i5`6%5+g-kun7o&6?6lsXL*a+*hi*s{fJrauXgmly&fhf^s z3E4_`-3*NminK;E-)tB(9ge34;dLpXqEaSo&XvkdS!WX$Qnj#NubO6=h)8cV>r%o- zg$#}#%0zWB5s_Y~F4Rh8)(8_zN(7avo*HT-qioC+@^ketEL4l8NE;P0#e6f5+G>={ zMukkHlCL%9t7a5zRLGPXLF4Uwtri*$kqjZXkpEM)9$X9SjZ(D|bw-RQrAw8hw96CH zIB?un6^x}-su3UwQbeQ|7jfC3NgauZcw9Wn7pTvr=@psX2-v zPKxSZ5_y=PnoE_N$P;l>b2RJuN@JnKx{58)m9q&VA1x?B*qjgRVZ~&L@q{!@+G|$O zMuiOZZ>iF(7OFMdSjiHy%7zr}qAKD-YOYi%Vt=CNK_NilssaMOp#PS~G0a z3#jr@2fHjGTg%rQuBgKil48`YO^Y*yd_7#KHp6_O8RQFvux8Xd$xh8vE;W)lG&5CR zE{YZ+xiZSMFke|T8koY@IHd|2`Ept5435N=dVT?dRHmqxp2NoQb4*B>?S@fVJ*ax; z#(FH|ab7p_3pF&AS9m=V93eT2qkmOwwM1MS~zh^OYj+6w(qzK0R@x9xxG+j`OQ@O)YAwXd4wWGVhD0>`FwwU%QhSy`Bsht3yBaP(% ze(43MpxoU(=zYOFA0d4{0I&g1$&>iKwHu(>kDdVhcHwsomUZU@z?X;clzbTAW2BWw z0NzC^?gw}e%b&*d8(7cxv5c>V09Ik$uOp3b!!mjRZsYgctytC>fI7y0LnY-36{Zf7=>XNfjzJf#$Z1jgA3T1 zPr!??4yIuo*25%B!C6=dn_&}df!E4q}7h2Vp-SXex#;FLwXebxMB`=5C9I^9PV8s(AynihM(q47Hlj}F34Yx5 z5?lA>X`GVyBqM>5uRR)q`2Y)!$;$8I=7z=ffJr=%AQ6tTb`!4lnRETAExQINoiFRt&`kb6)zb#5OTk(WXF`3LzuyeV>Hxo-xE;5&wx*TA8>_O0# zmkw~5!tPVa^mwZsG2>X)OyT6P_FY#r`5rUt)woR?W2mOSw@rK-bJ`>O{@4yI%WYCPuf1kaI9X$ zNp*3w@H`qDr?aNs+&Oo2#&Hz0Why()^2D`)wqGhaX1N5xvM@q!8M4BUSkpzx4EynIBam!|lli=G+Mk}qYj1rahg&EpnNTMnkZ z6X;YS&b;BMmJ!Md!^x2hGOWz7`V;-AEPO=~#ptsfeItO|rMA!b4@pA?b9;q` zELR%xFI6w99i(bVQ6qBcEkNU%@)Gd`Z&9+L3Wy4UP

ii zt(#u7(X5F2?uWKuz$0Zt8OJO)7!6qr;{`-mW-ub#&;iOoI?D5ivfQBP z?YRYMzrS+nDC-bqg+bw+zXjsZL+Gm53p&N2Dhi z$sPL*kF_J!=aoO!_oo5a`Wl^G6SWCz8X~fDnjyWbFWEo#2>_LrfpY(yof(M2GuM&^&tn45RTGq64I1es%5IBD_q*{iK;u2FYa$7I6mN$G=TOG^=4LlDoZVf8Mpw z8`>v5@1R6iH=VS|vlhSLVkx(ih2l^~-N<=b^b_Mk`m)-zIUnA+Dq&#M2jgMyAnZo(4AD0*qp9b5G`pq6hCIM%0W!8nw$ z=X{p)l{75!sW3?UZSYVll0YzKHbPhY;~;29sU1>;c0zRY>-XSai;ZdbYZCG=to zq}NeHHZoF*W4Z&(oJadNNlfy2cY@QRZM55d-N8}r^iGgGy0KXzv2)UbaVVp147WIa zljmv+W4U(#jA6SoBbv{mY-KcYyI`T(Ull#QxQ(&o#f1gqP{wxoR*xQmS-4#qq68LyTjtHxo|KwtJB;6=J(Y@(tt?ceEx_3CTXEKlvOJ{NFy#1JrL^z$>YNrb&<@)H8*An#mck^5f7vwn&$@= zl0z9sY}m8Q7*9o{hYgHkLs{`!j2wCD52oO$CleN~{Wa0!-I!oJ@fxE8EMH$9a z4-3eltbOUxmcuD{<_QVov_E zH5QOV8As7)wU0Y^#`|rDZ3!!<#~Pe)(9AO+ZjXh{+AKB$jT}9S zHBXm1z-lq?X#aRxVyQ<_9pHHO31=jZeQssJ+SYsD$#znrB{r%InpH16?K&%w>>DwL zSc1lTMr+DJqo>Fgh(lRh<ClhvL%JxCqKEC=kR{Bh7JE3l N*?W_a?2Af)@;}RMSJ?mn literal 0 HcmV?d00001 diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/atomic.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/atomic.h new file mode 100644 index 000000000..565c28037 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/atomic.h @@ -0,0 +1,547 @@ +/* + * FreeRTOS Kernel V10.2.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/** + * @file atomic.h + * @brief FreeRTOS atomic operation support. + * + * Two implementations of atomic are given in this header file: + * 1. Disabling interrupt globally. + * 2. ISA native atomic support. + * The former is available to all ports (compiler-architecture combination), + * while the latter is only available to ports compiling with GCC (version at + * least 4.7.0), which also have ISA atomic support. + * + * User can select which implementation to use by: + * setting/clearing configUSE_ATOMIC_INSTRUCTION in FreeRTOSConfig.h. + * Define AND set configUSE_ATOMIC_INSTRUCTION to 1 for ISA native atomic support. + * Undefine OR clear configUSE_ATOMIC_INSTRUCTION for disabling global interrupt + * implementation. + * + * @see GCC Built-in Functions for Memory Model Aware Atomic Operations + * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html + */ + +#ifndef ATOMIC_H +#define ATOMIC_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include atomic.h" +#endif + +/* Standard includes. */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + /* Needed for __atomic_compare_exchange() weak=false. */ + #include + + /* This branch is for GCC compiler and GCC compiler only. */ + #ifndef portFORCE_INLINE + #define portFORCE_INLINE inline __attribute__((always_inline)) + #endif + +#else + + /* Port specific definitions -- entering/exiting critical section. + * Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h + * + * Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with + * ATOMIC_ENTER_CRITICAL(). + */ + #if defined( portSET_INTERRUPT_MASK_FROM_ISR ) + + /* Nested interrupt scheme is supported in this port. */ + #define ATOMIC_ENTER_CRITICAL() \ + UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR() + + #define ATOMIC_EXIT_CRITICAL() \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType ) + + #else + + /* Nested interrupt scheme is NOT supported in this port. */ + #define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL() + #define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL() + + #endif /* portSET_INTERRUPT_MASK_FROM_ISR() */ + + /* Port specific definition -- "always inline". + * Inline is compiler specific, and may not always get inlined depending on your optimization level. + * For atomic operations, inline is considered a performance optimization. + * Thus, if portFORCE_INLINE is not provided by portmacro.h, instead of resulting error, + * simply define it. + */ + #ifndef portFORCE_INLINE + #define portFORCE_INLINE + #endif + +#endif /* configUSE_GCC_BUILTIN_ATOMICS */ + +#define ATOMIC_COMPARE_AND_SWAP_SUCCESS 0x1U /**< Compare and swap succeeded, swapped. */ +#define ATOMIC_COMPARE_AND_SWAP_FAILURE 0x0U /**< Compare and swap failed, did not swap. */ + +/*----------------------------- Swap && CAS ------------------------------*/ + +/** + * Atomic compare-and-swap + * + * @brief Performs an atomic compare-and-swap operation on the specified values. + * + * @param[in, out] pDestination Pointer to memory location from where value is + * to be loaded and checked. + * @param[in] ulExchange If condition meets, write this value to memory. + * @param[in] ulComparand Swap condition. + * + * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. + * + * @note This function only swaps *pDestination with ulExchange, if previous + * *pDestination value equals ulComparand. + */ +static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32( + uint32_t volatile * pDestination, + uint32_t ulExchange, + uint32_t ulComparand ) +{ + + uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + if ( __atomic_compare_exchange( pDestination, + &ulComparand, + &ulExchange, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST ) ) + { + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + +#else + + ATOMIC_ENTER_CRITICAL(); + + if ( *pDestination == ulComparand ) + { + *pDestination = ulExchange; + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return ulReturnValue; + +} + +/** + * Atomic swap (pointers) + * + * @brief Atomically sets the address pointed to by *ppDestination to the value + * of *pExchange. + * + * @param[in, out] ppDestination Pointer to memory location from where a pointer + * value is to be loaded and written back to. + * @param[in] pExchange Pointer value to be written to *ppDestination. + * + * @return The initial value of *ppDestination. + */ +static portFORCE_INLINE void * Atomic_SwapPointers_p32( + void * volatile * ppDestination, + void * pExchange ) +{ + void * pReturnValue; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + __atomic_exchange( ppDestination, &pExchange, &pReturnValue, __ATOMIC_SEQ_CST ); + +#else + + ATOMIC_ENTER_CRITICAL(); + + pReturnValue = *ppDestination; + + *ppDestination = pExchange; + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return pReturnValue; +} + +/** + * Atomic compare-and-swap (pointers) + * + * @brief Performs an atomic compare-and-swap operation on the specified pointer + * values. + * + * @param[in, out] ppDestination Pointer to memory location from where a pointer + * value is to be loaded and checked. + * @param[in] pExchange If condition meets, write this value to memory. + * @param[in] pComparand Swap condition. + * + * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. + * + * @note This function only swaps *ppDestination with pExchange, if previous + * *ppDestination value equals pComparand. + */ +static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32( + void * volatile * ppDestination, + void * pExchange, void * pComparand ) +{ + uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + if ( __atomic_compare_exchange( ppDestination, + &pComparand, + &pExchange, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST ) ) + { + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + +#else + + ATOMIC_ENTER_CRITICAL(); + + if ( *ppDestination == pComparand ) + { + *ppDestination = pExchange; + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return ulReturnValue; +} + + +/*----------------------------- Arithmetic ------------------------------*/ + +/** + * Atomic add + * + * @brief Atomically adds count to the value of the specified pointer points to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * @param[in] ulCount Value to be added to *pAddend. + * + * @return previous *pAddend value. + */ +static portFORCE_INLINE uint32_t Atomic_Add_u32( + uint32_t volatile * pAddend, + uint32_t ulCount ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_add(pAddend, ulCount, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend += ulCount; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic subtract + * + * @brief Atomically subtracts count from the value of the specified pointer + * pointers to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * @param[in] ulCount Value to be subtract from *pAddend. + * + * @return previous *pAddend value. + */ +static portFORCE_INLINE uint32_t Atomic_Subtract_u32( + uint32_t volatile * pAddend, + uint32_t ulCount ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_sub(pAddend, ulCount, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend -= ulCount; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic increment + * + * @brief Atomically increments the value of the specified pointer points to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * + * @return *pAddend value before increment. + */ +static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pAddend ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_add(pAddend, 1, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend += 1; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic decrement + * + * @brief Atomically decrements the value of the specified pointer points to + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * + * @return *pAddend value before decrement. + */ +static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pAddend ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_sub(pAddend, 1, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend -= 1; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/*----------------------------- Bitwise Logical ------------------------------*/ + +/** + * Atomic OR + * + * @brief Performs an atomic OR operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be ORed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_OR_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_or(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination |= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic AND + * + * @brief Performs an atomic AND operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be ANDed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_AND_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_and(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination &= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic NAND + * + * @brief Performs an atomic NAND operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be NANDed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_NAND_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_nand(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination = ~(ulCurrent & ulValue); + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic XOR + * + * @brief Performs an atomic XOR operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be XORed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_XOR_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_xor(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination ^= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif /* ATOMIC_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/demo_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/demo_config.h new file mode 100644 index 000000000..b96fc0bc9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/demo_config.h @@ -0,0 +1,39 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef DEMO_CONFIG_H +#define DEMO_CONFIG_H + +/** + * @brief Set the stack size of the main demo task. + * + * In the Windows port, this stack only holds a structure. The actual + * stack is created by an operating system thread. + */ +#define democonfigDEMO_STACKSIZE configMINIMAL_STACK_SIZE + +#endif /* DEMO_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/demo_logging.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/demo_logging.c new file mode 100644 index 000000000..e22e91093 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/demo_logging.c @@ -0,0 +1,527 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * Logging utility that allows FreeRTOS tasks to log to a UDP port, stdout, and + * disk file without making any Win32 system calls themselves. + * + * Messages logged to a UDP port are sent directly (using FreeRTOS+TCP), but as + * FreeRTOS tasks cannot make Win32 system calls messages sent to stdout or a + * disk file are sent via a stream buffer to a Win32 thread which then performs + * the actual output. + */ + +/* Standard includes. */ +#include +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_Stream_Buffer.h" + +/* Demo includes. */ +#include "demo_logging.h" + +/*-----------------------------------------------------------*/ + +/* The maximum size to which the log file may grow, before being renamed +to .ful. */ +#define dlLOGGING_FILE_SIZE ( 40ul * 1024ul * 1024ul ) + +/* Dimensions the arrays into which print messages are created. */ +#define dlMAX_PRINT_STRING_LENGTH 255 + +/* The size of the stream buffer used to pass messages from FreeRTOS tasks to +the Win32 thread that is responsible for making any Win32 system calls that are +necessary for the selected logging method. */ +#define dlLOGGING_STREAM_BUFFER_SIZE 32768 + +/* A block time of zero simply means don't block. */ +#define dlDONT_BLOCK 0 + +/*-----------------------------------------------------------*/ + +/* + * Called from vLoggingInit() to start a new disk log file. + */ +static void prvFileLoggingInit( void ); + +/* + * Attempt to write a message to the file. + */ +static void prvLogToFile( const char *pcMessage, size_t xLength ); + +/* + * Simply close the logging file, if it is open. + */ +static void prvFileClose( void ); + +/* + * Before the scheduler is started this function is called directly. After the + * scheduler has started it is called from the Windows thread dedicated to + * outputting log messages. Only the windows thread actually performs the + * writing so as not to disrupt the simulation by making Windows system calls + * from FreeRTOS tasks. + */ +static void prvLoggingFlushBuffer( void ); + +/* + * The windows thread that performs the actual writing of messages that require + * Win32 system calls. Only the windows thread can make system calls so as not + * to disrupt the simulation by making Windows calls from FreeRTOS tasks. + */ +static DWORD WINAPI prvWin32LoggingThread( void *pvParam ); + +/* + * Creates the socket to which UDP messages are sent. This function is not + * called directly to prevent the print socket being created from within the IP + * task - which could result in a deadlock. Instead the function call is + * deferred to run in the RTOS daemon task - hence it prototype. + */ +static void prvCreatePrintSocket( void *pvParameter1, uint32_t ulParameter2 ); + +/*-----------------------------------------------------------*/ + +/* Windows event used to wake the Win32 thread which performs any logging that +needs Win32 system calls. */ +static void *pvLoggingThreadEvent = NULL; + +/* Stores the selected logging targets passed in as parameters to the +vLoggingInit() function. */ +BaseType_t xStdoutLoggingUsed = pdFALSE, xDiskFileLoggingUsed = pdFALSE, xUDPLoggingUsed = pdFALSE; + +/* Circular buffer used to pass messages from the FreeRTOS tasks to the Win32 +thread that is responsible for making Win32 calls (when stdout or a disk log is +used). */ +static StreamBuffer_t *xLogStreamBuffer = NULL; + +/* Handle to the file used for logging. This is left open while there are +messages waiting to be logged, then closed again in between logs. */ +static FILE *pxLoggingFileHandle = NULL; + +/* When true prints are performed directly. After start up xDirectPrint is set +to pdFALSE - at which time prints that require Win32 system calls are done by +the Win32 thread responsible for logging. */ +BaseType_t xDirectPrint = pdTRUE; + +/* File names for the in use and complete (full) log files. */ +static const char *pcLogFileName = "RTOSDemo.log"; +static const char *pcFullLogFileName = "RTOSDemo.ful"; + +/* As an optimization, the current file size is kept in a variable. */ +static size_t ulSizeOfLoggingFile = 0ul; + +/* The UDP socket and address on/to which print messages are sent. */ +Socket_t xPrintSocket = FREERTOS_INVALID_SOCKET; +struct freertos_sockaddr xPrintUDPAddress; + +/*-----------------------------------------------------------*/ + +void vLoggingInit( BaseType_t xLogToStdout, BaseType_t xLogToFile, BaseType_t xLogToUDP, uint32_t ulRemoteIPAddress, uint16_t usRemotePort ) +{ + /* Can only be called before the scheduler has started. */ + configASSERT( xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED ); + + #if( ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) ) + { + HANDLE Win32Thread; + + /* Record which output methods are to be used. */ + xStdoutLoggingUsed = xLogToStdout; + xDiskFileLoggingUsed = xLogToFile; + xUDPLoggingUsed = xLogToUDP; + + /* If a disk file is used then initialize it now. */ + if( xDiskFileLoggingUsed != pdFALSE ) + { + prvFileLoggingInit(); + } + + /* If UDP logging is used then store the address to which the log data + will be sent - but don't create the socket yet because the network is + not initialized. */ + if( xUDPLoggingUsed != pdFALSE ) + { + /* Set the address to which the print messages are sent. */ + xPrintUDPAddress.sin_port = FreeRTOS_htons( usRemotePort ); + xPrintUDPAddress.sin_addr = ulRemoteIPAddress; + } + + /* If a disk file or stdout are to be used then Win32 system calls will + have to be made. Such system calls cannot be made from FreeRTOS tasks + so create a stream buffer to pass the messages to a Win32 thread, then + create the thread itself, along with a Win32 event that can be used to + unblock the thread. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) ) + { + /* Create the buffer. */ + xLogStreamBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) + dlLOGGING_STREAM_BUFFER_SIZE + 1 ); + configASSERT( xLogStreamBuffer ); + memset( xLogStreamBuffer, '\0', sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) ); + xLogStreamBuffer->LENGTH = dlLOGGING_STREAM_BUFFER_SIZE + 1; + + /* Create the Windows event. */ + pvLoggingThreadEvent = CreateEvent( NULL, FALSE, TRUE, "StdoutLoggingEvent" ); + + /* Create the thread itself. */ + Win32Thread = CreateThread( + NULL, /* Pointer to thread security attributes. */ + 0, /* Initial thread stack size, in bytes. */ + prvWin32LoggingThread, /* Pointer to thread function. */ + NULL, /* Argument for new thread. */ + 0, /* Creation flags. */ + NULL ); + + /* Use the cores that are not used by the FreeRTOS tasks. */ + SetThreadAffinityMask( Win32Thread, ~0x01u ); + SetThreadPriorityBoost( Win32Thread, TRUE ); + SetThreadPriority( Win32Thread, THREAD_PRIORITY_IDLE ); + } + } + #else + { + /* FreeRTOSIPConfig is set such that no print messages will be output. + Avoid compiler warnings about unused parameters. */ + ( void ) xLogToStdout; + ( void ) xLogToFile; + ( void ) xLogToUDP; + ( void ) usRemotePort; + ( void ) ulRemoteIPAddress; + } + #endif /* ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) */ +} +/*-----------------------------------------------------------*/ + +static void prvCreatePrintSocket( void *pvParameter1, uint32_t ulParameter2 ) +{ +static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 0 ); +Socket_t xSocket; + + /* The function prototype is that of a deferred function, but the parameters + are not actually used. */ + ( void ) pvParameter1; + ( void ) ulParameter2; + + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + + if( xSocket != FREERTOS_INVALID_SOCKET ) + { + /* FreeRTOS+TCP decides which port to bind to. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + FreeRTOS_bind( xSocket, NULL, 0 ); + + /* Now the socket is bound it can be assigned to the print socket. */ + xPrintSocket = xSocket; + } +} +/*-----------------------------------------------------------*/ + +void vLoggingPrintf( const char *pcFormat, ... ) +{ +char cPrintString[ dlMAX_PRINT_STRING_LENGTH ]; +char cOutputString[ dlMAX_PRINT_STRING_LENGTH ]; +char *pcSource, *pcTarget, *pcBegin; +size_t xLength, xLength2, rc; +static BaseType_t xMessageNumber = 0; +va_list args; +uint32_t ulIPAddress; +const char *pcTaskName; +const char *pcNoTask = "None"; +int iOriginalPriority; +HANDLE xCurrentTask; + + + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) || ( xUDPLoggingUsed != pdFALSE ) ) + { + /* There are a variable number of parameters. */ + va_start( args, pcFormat ); + + /* Additional info to place at the start of the log. */ + if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED ) + { + pcTaskName = pcTaskGetName( NULL ); + } + else + { + pcTaskName = pcNoTask; + } + + if( strcmp( pcFormat, "\n" ) != 0 ) + { + xLength = snprintf( cPrintString, dlMAX_PRINT_STRING_LENGTH, "%lu %lu [%s] ", + xMessageNumber++, + ( unsigned long ) xTaskGetTickCount(), + pcTaskName ); + } + else + { + xLength = 0; + memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH ); + } + + xLength2 = vsnprintf( cPrintString + xLength, dlMAX_PRINT_STRING_LENGTH - xLength, pcFormat, args ); + + if( xLength2 < 0 ) + { + /* Clean up. */ + xLength2 = dlMAX_PRINT_STRING_LENGTH - 1 - xLength; + cPrintString[ dlMAX_PRINT_STRING_LENGTH - 1 ] = '\0'; + } + + xLength += xLength2; + va_end( args ); + + /* For ease of viewing, copy the string into another buffer, converting + IP addresses to dot notation on the way. */ + pcSource = cPrintString; + pcTarget = cOutputString; + + while( ( *pcSource ) != '\0' ) + { + *pcTarget = *pcSource; + pcTarget++; + pcSource++; + + /* Look forward for an IP address denoted by 'ip'. */ + if( ( isxdigit( pcSource[ 0 ] ) != pdFALSE ) && ( pcSource[ 1 ] == 'i' ) && ( pcSource[ 2 ] == 'p' ) ) + { + *pcTarget = *pcSource; + pcTarget++; + *pcTarget = '\0'; + pcBegin = pcTarget - 8; + + while( ( pcTarget > pcBegin ) && ( isxdigit( pcTarget[ -1 ] ) != pdFALSE ) ) + { + pcTarget--; + } + + sscanf( pcTarget, "%8X", &ulIPAddress ); + rc = sprintf( pcTarget, "%lu.%lu.%lu.%lu", + ( unsigned long ) ( ulIPAddress >> 24UL ), + ( unsigned long ) ( (ulIPAddress >> 16UL) & 0xffUL ), + ( unsigned long ) ( (ulIPAddress >> 8UL) & 0xffUL ), + ( unsigned long ) ( ulIPAddress & 0xffUL ) ); + pcTarget += rc; + pcSource += 3; /* skip "ip" */ + } + } + + /* How far through the buffer was written? */ + xLength = ( BaseType_t ) ( pcTarget - cOutputString ); + + /* If the message is to be logged to a UDP port then it can be sent directly + because it only uses FreeRTOS function (not Win32 functions). */ + if( xUDPLoggingUsed != pdFALSE ) + { + if( ( xPrintSocket == FREERTOS_INVALID_SOCKET ) && ( FreeRTOS_IsNetworkUp() != pdFALSE ) ) + { + /* Create and bind the socket to which print messages are sent. The + xTimerPendFunctionCall() function is used even though this is + not an interrupt because this function is called from the IP task + and the IP task cannot itself wait for a socket to bind. The + parameters to prvCreatePrintSocket() are not required so set to + NULL or 0. */ + xTimerPendFunctionCall( prvCreatePrintSocket, NULL, 0, dlDONT_BLOCK ); + } + + if( xPrintSocket != FREERTOS_INVALID_SOCKET ) + { + FreeRTOS_sendto( xPrintSocket, cOutputString, xLength, 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) ); + + /* Just because the UDP data logger I'm using is dumb. */ + FreeRTOS_sendto( xPrintSocket, "\r", sizeof( char ), 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) ); + } + } + + /* If logging is also to go to either stdout or a disk file then it cannot + be output here - so instead write the message to the stream buffer and wake + the Win32 thread which will read it from the stream buffer and perform the + actual output. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) ) + { + configASSERT( xLogStreamBuffer ); + + /* How much space is in the buffer? */ + xLength2 = uxStreamBufferGetSpace( xLogStreamBuffer ); + + /* There must be enough space to write both the string and the length of + the string. */ + if( xLength2 >= ( xLength + sizeof( xLength ) ) ) + { + /* First write in the length of the data, then write in the data + itself. Raising the thread priority is used as a critical section + as there are potentially multiple writers. The stream buffer is + only thread safe when there is a single writer (likewise for + reading from the buffer). */ + xCurrentTask = GetCurrentThread(); + iOriginalPriority = GetThreadPriority( xCurrentTask ); + SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ); + uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) &( xLength ), sizeof( xLength ) ); + uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) cOutputString, xLength ); + SetThreadPriority( GetCurrentThread(), iOriginalPriority ); + } + + /* xDirectPrint is initialized to pdTRUE, and while it remains true the + logging output function is called directly. When the system is running + the output function cannot be called directly because it would get + called from both FreeRTOS tasks and Win32 threads - so instead wake the + Win32 thread responsible for the actual output. */ + if( xDirectPrint != pdFALSE ) + { + /* While starting up, the thread which calls prvWin32LoggingThread() + is not running yet and xDirectPrint will be pdTRUE. */ + prvLoggingFlushBuffer(); + } + else if( pvLoggingThreadEvent != NULL ) + { + /* While running, wake up prvWin32LoggingThread() to send the + logging data. */ + SetEvent( pvLoggingThreadEvent ); + } + } + } +} +/*-----------------------------------------------------------*/ + +static void prvLoggingFlushBuffer( void ) +{ +size_t xLength; +char cPrintString[ dlMAX_PRINT_STRING_LENGTH ]; + + /* Is there more than the length value stored in the circular buffer + used to pass data from the FreeRTOS simulator into this Win32 thread? */ + while( uxStreamBufferGetSize( xLogStreamBuffer ) > sizeof( xLength ) ) + { + memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH ); + uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE ); + uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) cPrintString, xLength, pdFALSE ); + + /* Write the message to standard out if requested to do so when + vLoggingInit() was called, or if the network is not yet up. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( FreeRTOS_IsNetworkUp() == pdFALSE ) ) + { + /* Write the message to stdout. */ + printf( "%s", cPrintString ); /*_RB_ Replace with _write(). */ + fflush( stdout ); + } + + /* Write the message to a file if requested to do so when + vLoggingInit() was called. */ + if( xDiskFileLoggingUsed != pdFALSE ) + { + prvLogToFile( cPrintString, xLength ); + } + } + + prvFileClose(); +} +/*-----------------------------------------------------------*/ + +static DWORD WINAPI prvWin32LoggingThread( void *pvParameter ) +{ +const DWORD xMaxWait = 1000; + + ( void ) pvParameter; + + /* From now on, prvLoggingFlushBuffer() will only be called from this + Windows thread */ + xDirectPrint = pdFALSE; + + for( ;; ) + { + /* Wait to be told there are message waiting to be logged. */ + WaitForSingleObject( pvLoggingThreadEvent, xMaxWait ); + + /* Write out all waiting messages. */ + prvLoggingFlushBuffer(); + } +} +/*-----------------------------------------------------------*/ + +static void prvFileLoggingInit( void ) +{ +FILE *pxHandle = fopen( pcLogFileName, "a" ); + + if( pxHandle != NULL ) + { + fseek( pxHandle, SEEK_END, 0ul ); + ulSizeOfLoggingFile = ftell( pxHandle ); + fclose( pxHandle ); + } + else + { + ulSizeOfLoggingFile = 0ul; + } +} +/*-----------------------------------------------------------*/ + +static void prvFileClose( void ) +{ + if( pxLoggingFileHandle != NULL ) + { + fclose( pxLoggingFileHandle ); + pxLoggingFileHandle = NULL; + } +} +/*-----------------------------------------------------------*/ + +static void prvLogToFile( const char *pcMessage, size_t xLength ) +{ + if( pxLoggingFileHandle == NULL ) + { + pxLoggingFileHandle = fopen( pcLogFileName, "a" ); + } + + if( pxLoggingFileHandle != NULL ) + { + fwrite( pcMessage, 1, xLength, pxLoggingFileHandle ); + ulSizeOfLoggingFile += xLength; + + /* If the file has grown to its maximum permissible size then close and + rename it - then start with a new file. */ + if( ulSizeOfLoggingFile > ( size_t ) dlLOGGING_FILE_SIZE ) + { + prvFileClose(); + if( _access( pcFullLogFileName, 00 ) == 0 ) + { + remove( pcFullLogFileName ); + } + rename( pcLogFileName, pcFullLogFileName ); + ulSizeOfLoggingFile = 0; + } + } +} +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/demo_logging.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/demo_logging.h new file mode 100644 index 000000000..197b21684 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/demo_logging.h @@ -0,0 +1,48 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef DEMO_LOGGING_H +#define DEMO_LOGGING_H + +/* + * Initialize a logging system that can be used from FreeRTOS tasks and Win32 + * threads. Do not call printf() directly while the scheduler is running. + * + * Set xLogToStdout, xLogToFile and xLogToUDP to either pdTRUE or pdFALSE to + * lot to stdout, a disk file and a UDP port respectively. + * + * If xLogToUDP is pdTRUE then ulRemoteIPAddress and usRemotePort must be set + * to the IP address and port number to which UDP log messages will be sent. + */ +void vLoggingInit( BaseType_t xLogToStdout, + BaseType_t xLogToFile, + BaseType_t xLogToUDP, + uint32_t ulRemoteIPAddress, + uint16_t usRemotePort ); + +#endif /* DEMO_LOGGING_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/iot_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/iot_config.h new file mode 100644 index 000000000..bba6b4376 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/iot_config.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/* This file contains configuration settings for the demos. */ + +#ifndef IOT_CONFIG_H_ +#define IOT_CONFIG_H_ + +/* Configure the IoT Libraries for FreeRTOS by including the FreeRTOS header and + * the FreeRTOS platform types. */ +#include "FreeRTOS.h" +#include "platform/iot_platform_types_freertos.h" + +/** + * @brief Set a global default for log levels. + * + * This setting is overridden by log level settings of specific libraries. + * Undefined library-specific log levels will default to this value. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_GLOBAL IOT_LOG_NONE + +/** + * @brief Set the log level of the platform libraries except the network + * component. + * + * Log messages from the platform libraries at or below this setting + * will be printed. As the network component is more verbose, its logging + * is controlled by its own setting, IOT_LOG_LEVEL_NETWORK. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_PLATFORM IOT_LOG_NONE + +/** + * @brief Set the log level of the platform network library. + * + * Log messages from the platform network library at or below this setting + * will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_NETWORK IOT_LOG_WARN + +/* + * @brief Set the log level of the task pool library. + * + * Log messages from the task pool library at or below this setting will be + * printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_TASKPOOL IOT_LOG_WARN + +/** + * @brief Set the log level of the MQTT library. + * + * Log messages from the MQTT library at or below this setting will be printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_MQTT IOT_LOG_WARN + +/** + * @brief Enable/Disable asserts for the task pool library. + * + * Set this to 1 to perform sanity checks when using the task pool library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotTaskPool_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_TASKPOOL_ENABLE_ASSERTS 1 + +/** + * @brief The number of worker tasks in the task pool. + * + * The full IoT Task Pool Library has many use cases, including Linux + * development. Typical FreeRTOS use cases do not require the full + * functionality so an optimized implementation is provided specifically for use + * with FreeRTOS. The optimized version has a fixed number of tasks in the + * task pool, each of which uses statically allocated memory to ensure creation + * of the task pool is guaranteed (it does not run out of heap space). + */ +#define IOT_TASKPOOL_NUMBER_OF_WORKERS 1 + +/** + * @brief The stack size (in bytes) for each worker task in the task pool. + * + * The minimal version of the of task pool library only supports one task pool + * and the configuration of each worker task fixed at the compile time. + */ +#define IOT_TASKPOOL_WORKER_STACK_SIZE_BYTES 2048 + +/** + * @brief Enable TLS in the network abstraction. + * + * The TLS implementation requires the mbed TLS library. + */ +#define IOT_NETWORK_ENABLE_TLS 1 + +/** + * @brief Enable/Disable asserts for the linear containers library. + * + * Set this to 1 to perform sanity checks when using the linear containers library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotContainers_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_CONTAINERS_ENABLE_ASSERTS 1 + +/** + * @brief Enable/Disable asserts for the MQTT library. + * + * Set this to 1 to perform sanity checks when using the MQTT library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotMqtt_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_MQTT_ENABLE_ASSERTS 1 + +/** + * @brief Enable/Disable anonymous metrics collection when using AWS IoT. + * + * This demo does not use TLS and so does not work with AWS IoT. Therefore, + * the metric collection must be disabled. + */ +#define AWS_IOT_MQTT_ENABLE_METRICS 0 + +/* Common settings for FreeRTOS; settings below this line generally do not need + * to be changed. */ + +/* Logging puts function on FreeRTOS. */ +#define IotLogging_Puts( str ) configPRINTF( ( "%s\r\n", str ) ) + +/* Assert functions on FreeRTOS. */ +#define IotContainers_Assert( expression ) configASSERT( expression ) +#define IotTaskPool_Assert( expression ) configASSERT( expression ) +#define IotMqtt_Assert( expression ) configASSERT( expression ) +#define Iot_DefaultAssert( expression ) configASSERT( expression ) + +/* Memory allocation functions on FreeRTOS. */ +#define IotThreads_Malloc pvPortMalloc +#define IotThreads_Free vPortFree + +#define IotLogging_Malloc pvPortMalloc +#define IotLogging_Free vPortFree + +#define IotTaskPool_MallocTaskPool pvPortMalloc +#define IotTaskPool_FreeTaskPool vPortFree +#define IotTaskPool_MallocJob pvPortMalloc +#define IotTaskPool_FreeJob vPortFree +#define IotTaskPool_MallocTimerEvent pvPortMalloc +#define IotTaskPool_FreeTimerEvent vPortFree + +#define IotMqtt_MallocConnection pvPortMalloc +#define IotMqtt_FreeConnection vPortFree +#define IotMqtt_MallocMessage pvPortMalloc +#define IotMqtt_FreeMessage vPortFree +#define IotMqtt_MallocOperation pvPortMalloc +#define IotMqtt_FreeOperation vPortFree +#define IotMqtt_MallocSubscription pvPortMalloc +#define IotMqtt_FreeSubscription vPortFree + +#define AwsIotShadow_MallocOperation pvPortMalloc +#define AwsIotShadow_FreeOperation vPortFree +#define AwsIotShadow_MallocString pvPortMalloc +#define AwsIotShadow_FreeString vPortFree +#define AwsIotShadow_MallocSubscription pvPortMalloc +#define AwsIotShadow_FreeSubscription vPortFree + +#define Iot_DefaultMalloc pvPortMalloc +#define Iot_DefaultFree vPortFree + +#endif /* ifndef IOT_CONFIG_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/main.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/main.c new file mode 100644 index 000000000..6b71b1a83 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/main.c @@ -0,0 +1,357 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + /*** + * See https://www.FreeRTOS.org/shadow/index.html for configuration and usage instructions. + ***/ + +/* Standard includes. */ +#include +#include + +/* Visual studio intrinsics used so the __debugbreak() function is available +should an assert get hit. */ +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" + +/* TCP/IP stack includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Demo app includes. */ +#include "demo_logging.h" + +/* + * Prototypes for the demos that can be started from this project. Note the + * Shadow demo is not actually started until the network is already, which is + * indicated by vApplicationIPNetworkEventHook() executing - hence + * vStartShadowDeviceOperationsDemo() is called from inside + * vApplicationIPNetworkEventHook(). + */ +extern void vStartShadowDeviceOperationsDemo( void ); + +/* + * Just seeds the simple pseudo random number generator. + * + * !!! NOTE !!! + * This is not a secure method of generating random numbers and production + * devices should use a true random number generator (TRNG). + */ +static void prvSRand( UBaseType_t ulSeed ); + +/* + * Miscellaneous initialization including preparing the logging and seeding the + * random number generator. + */ +static void prvMiscInitialisation( void ); + +/* The default IP and MAC address used by the demo. The address configuration +defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is +1 but a DHCP server could not be contacted. See the online documentation for +more information. */ +static const uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 }; +static const uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 }; +static const uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 }; +static const uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 }; + +/* Set the following constant to pdTRUE to log using the method indicated by the +name of the constant, or pdFALSE to not log using the method indicated by the +name of the constant. Options include to standard out (xLogToStdout), to a disk +file (xLogToFile), and to a UDP port (xLogToUDP). If xLogToUDP is set to pdTRUE +then UDP messages are sent to the IP address configured as the echo server +address (see the configECHO_SERVER_ADDR0 definitions in FreeRTOSConfig.h) and +the port number set by configPRINT_PORT in FreeRTOSConfig.h. */ +const BaseType_t xLogToStdout = pdTRUE, xLogToFile = pdFALSE, xLogToUDP = pdFALSE; + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition for information on how to configure +the real network connection to use. */ +const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 }; + +/* Use by the pseudo random number generator. */ +static UBaseType_t ulNextRand; +/*-----------------------------------------------------------*/ + +int main( void ) +{ + /*** + * See https://www.FreeRTOS.org/shadow/index.html for configuration and usage instructions. + ***/ + + /* Miscellaneous initialization including preparing the logging and seeding + the random number generator. */ + prvMiscInitialisation(); + + /* Initialize the network interface. + + ***NOTE*** Tasks that use the network are created in the network event hook + when the network is connected and ready for use (see the implementation of + vApplicationIPNetworkEventHook() below). The address values passed in here + are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1 + but a DHCP server cannot be contacted. */ + FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); + + /* Start the RTOS scheduler. */ + vTaskStartScheduler(); + + /* If all is well, the scheduler will now be running, and the following + line will never be reached. If the following line does execute, then + there was insufficient FreeRTOS heap memory available for the idle and/or + timer tasks to be created. See the memory management section on the + FreeRTOS web site for more details (this is standard text that is not + really applicable to the Win32 simulator port). */ + for( ;; ) + { + __debugbreak(); + } +} +/*-----------------------------------------------------------*/ + +/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect +events are only received if implemented in the MAC driver. */ +void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) +{ +uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress; +char cBuffer[ 16 ]; +static BaseType_t xTasksAlreadyCreated = pdFALSE; + + /* If the network has just come up...*/ + if( eNetworkEvent == eNetworkUp ) + { + /* Create the tasks that use the IP stack if they have not already been + created. */ + if( xTasksAlreadyCreated == pdFALSE ) + { + /* Demos that use the network are created after the network is + up. */ + configPRINTF( ( "---------STARTING DEMO---------\r\n" ) ); + vStartShadowDeviceOperationsDemo(); + xTasksAlreadyCreated = pdTRUE; + } + + /* Print out the network configuration, which may have come from a DHCP + server. */ + FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress ); + FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); + FreeRTOS_printf( ( "\r\n\r\nIP Address: %s\r\n", cBuffer ) );/*_RB_ Should use IoT libraries logging. */ + + FreeRTOS_inet_ntoa( ulNetMask, cBuffer ); + FreeRTOS_printf( ( "Subnet Mask: %s\r\n", cBuffer ) ); + + FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer ); + FreeRTOS_printf( ( "Gateway Address: %s\r\n", cBuffer ) ); + + FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer ); + FreeRTOS_printf( ( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ) ); + } +} +/*-----------------------------------------------------------*/ + +void vAssertCalled( const char *pcFile, uint32_t ulLine ) +{ + volatile uint32_t ulBlockVariable = 0UL; + volatile char *pcFileName = ( volatile char * ) pcFile; + volatile uint32_t ulLineNumber = ulLine; + + ( void ) pcFileName; + ( void ) ulLineNumber; + + printf( "vAssertCalled( %s, %u\n", pcFile, ulLine ); + + /* Setting ulBlockVariable to a non-zero value in the debugger will allow + this function to be exited. */ + taskDISABLE_INTERRUPTS(); + { + while( ulBlockVariable == 0UL ) + { + __debugbreak(); + } + } + taskENABLE_INTERRUPTS(); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxRand( void ) +{ +const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL; + + /* + * Utility function to generate a pseudo random number. + * + * !!!NOTE!!! + * This is not a secure method of generating a random number. Production + * devices should use a True Random Number Generator (TRNG). + */ + ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement; + return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL ); +} +/*-----------------------------------------------------------*/ + +static void prvSRand( UBaseType_t ulSeed ) +{ + /* Utility function to seed the pseudo random number generator. */ + ulNextRand = ulSeed; +} +/*-----------------------------------------------------------*/ + +static void prvMiscInitialisation( void ) +{ +time_t xTimeNow; +uint32_t ulLoggingIPAddress; + + ulLoggingIPAddress = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0, configECHO_SERVER_ADDR1, configECHO_SERVER_ADDR2, configECHO_SERVER_ADDR3 ); + vLoggingInit( xLogToStdout, xLogToFile, xLogToUDP, ulLoggingIPAddress, configPRINT_PORT ); + + /* + * Seed random number generator. + * + * !!!NOTE!!! + * This is not a secure method of generating a random number. Production + * devices should use a True Random Number Generator (TRNG). + */ + time( &xTimeNow ); + FreeRTOS_debug_printf( ( "Seed for randomizer: %lu\n", xTimeNow ) ); + prvSRand( ( uint32_t ) xTimeNow ); + FreeRTOS_debug_printf( ( "Random numbers: %08X %08X %08X %08X\n", ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32() ) ); +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) + + const char *pcApplicationHostnameHook( void ) + { + /* Assign the name "FreeRTOS" to this network node. This function will + be called during the DHCP: the machine will be registered with an IP + address plus this name. */ + return mainHOST_NAME; + } + +#endif +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) + + BaseType_t xApplicationDNSQueryHook( const char *pcName ) + { + BaseType_t xReturn; + + /* Determine if a name lookup is for this node. Two names are given + to this node: that returned by pcApplicationHostnameHook() and that set + by mainDEVICE_NICK_NAME. */ + if( _stricmp( pcName, pcApplicationHostnameHook() ) == 0 ) + { + xReturn = pdPASS; + } + else if( _stricmp( pcName, mainDEVICE_NICK_NAME ) == 0 ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif +/*-----------------------------------------------------------*/ + +/* + * Callback that provides the inputs necessary to generate a randomized TCP + * Initial Sequence Number per RFC 6528. THIS IS ONLY A DUMMY IMPLEMENTATION + * THAT RETURNS A PSEUDO RANDOM NUMBER SO IS NOT INTENDED FOR USE IN PRODUCTION + * SYSTEMS. + */ +extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress, + uint16_t usSourcePort, + uint32_t ulDestinationAddress, + uint16_t usDestinationPort ) +{ + ( void ) ulSourceAddress; + ( void ) usSourcePort; + ( void ) ulDestinationAddress; + ( void ) usDestinationPort; + + return uxRand(); +} +/*-----------------------------------------------------------*/ + +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an +implementation of vApplicationGetIdleTaskMemory() to provide the memory that is +used by the Idle task. */ +void vApplicationGetIdleTaskMemory( StaticTask_t** ppxIdleTaskTCBBuffer, StackType_t** ppxIdleTaskStackBuffer, uint32_t* pulIdleTaskStackSize ) +{ + /* If the buffers to be provided to the Idle task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xIdleTaskTCB; + static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} +/*-----------------------------------------------------------*/ + +/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the +application must provide an implementation of vApplicationGetTimerTaskMemory() +to provide the memory that is used by the Timer service task. */ +void vApplicationGetTimerTaskMemory( StaticTask_t** ppxTimerTaskTCBBuffer, StackType_t** ppxTimerTaskStackBuffer, uint32_t* pulTimerTaskStackSize ) +{ + /* If the buffers to be provided to the Timer task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xTimerTaskTCB; + static StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/mbedtls_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/mbedtls_config.h new file mode 100644 index 000000000..0f2861a0d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/mbedtls_config.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/* This file configures mbed TLS for FreeRTOS. */ + +#ifndef MBEDTLS_CONFIG_H_ +#define MBEDTLS_CONFIG_H_ + +/* FreeRTOS include. */ +#include "FreeRTOS.h" + +/* Generate errors if deprecated functions are used. */ +#define MBEDTLS_DEPRECATED_REMOVED + +/* Place AES tables in ROM. */ +#define MBEDTLS_AES_ROM_TABLES + +/* Enable the following cipher modes. */ +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_CIPHER_MODE_CFB +#define MBEDTLS_CIPHER_MODE_CTR + +/* Enable the following cipher padding modes. */ +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define MBEDTLS_CIPHER_PADDING_ZEROS + +/* Cipher suite configuration. */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_NIST_OPTIM +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/* Enable all SSL alert messages. */ +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES + +/* Enable the following SSL features. */ +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_SSL_ALPN +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/* Check certificate key usage. */ +#define MBEDTLS_X509_CHECK_KEY_USAGE +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/* Disable platform entropy functions. */ +#define MBEDTLS_NO_PLATFORM_ENTROPY + +/* Enable the following mbed TLS features. */ +#define MBEDTLS_AES_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECP_C +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_GCM_C +#define MBEDTLS_MD_C +#define MBEDTLS_OID_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA1_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_TLS_C +#define MBEDTLS_THREADING_ALT +#define MBEDTLS_THREADING_C +#define MBEDTLS_X509_USE_C +#define MBEDTLS_X509_CRT_PARSE_C + +/* Set the memory allocation functions on FreeRTOS. */ +void * mbedtls_platform_calloc( size_t nmemb, + size_t size ); +void mbedtls_platform_free( void * ptr ); +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_CALLOC_MACRO mbedtls_platform_calloc +#define MBEDTLS_PLATFORM_FREE_MACRO mbedtls_platform_free + +/* The network send and receive functions on FreeRTOS. */ +int mbedtls_platform_send( void * ctx, + const unsigned char * buf, + size_t len ); +int mbedtls_platform_recv( void * ctx, + unsigned char * buf, + size_t len ); + +/* The entropy poll function. */ +int mbedtls_platform_entropy_poll( void * data, + unsigned char * output, + size_t len, + size_t * olen ); + +#include "mbedtls/check_config.h" + +#endif /* ifndef MBEDTLS_CONFIG_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/printf-stdarg.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/printf-stdarg.c new file mode 100644 index 000000000..5505535c1 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/printf-stdarg.c @@ -0,0 +1,667 @@ +/* + Copyright 2001, 2002 Georges Menie (www.menie.org) + stdarg version contributed by Christian Ettinger + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Changes for the FreeRTOS ports: + + - The dot in "%-8.8s" + - The specifiers 'l' (long) and 'L' (long long) + - The specifier 'u' for unsigned + - Dot notation for IP addresses: + sprintf("IP = %xip\n", 0xC0A80164); + will produce "IP = 192.168.1.100\n" +*/ + +#include +#include +#include +#include + +#include "FreeRTOS.h" + +#define PAD_RIGHT 1 +#define PAD_ZERO 2 + +/* + * Return 1 for readable, 2 for writeable, 3 for both. + * Function must be provided by the application. + */ +extern BaseType_t xApplicationMemoryPermissions( uint32_t aAddress ); + +extern void vOutputChar( const char cChar, const TickType_t xTicksToWait ); +static const TickType_t xTicksToWait = pdMS_TO_TICKS( 20 ); + +struct xPrintFlags +{ + int base; + int width; + int printLimit; + unsigned + pad : 8, + letBase : 8, + isSigned : 1, + isNumber : 1, + long32 : 1, + long64 : 1; +}; + +struct SStringBuf +{ + char *str; + const char *orgStr; + const char *nulPos; + int curLen; + struct xPrintFlags flags; +}; + +static void strbuf_init( struct SStringBuf *apStr, char *apBuf, const char *apMaxStr ) +{ + apStr->str = apBuf; + apStr->orgStr = apBuf; + apStr->nulPos = apMaxStr-1; + apStr->curLen = 0; + + memset( &apStr->flags, '\0', sizeof( apStr->flags ) ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t strbuf_printchar( struct SStringBuf *apStr, int c ) +{ + if( apStr->str == NULL ) + { + vOutputChar( ( char ) c, xTicksToWait ); + apStr->curLen++; + return pdTRUE; + } + if( apStr->str < apStr->nulPos ) + { + *( apStr->str++ ) = c; + apStr->curLen++; + return pdTRUE; + } + if( apStr->str == apStr->nulPos ) + { + *( apStr->str++ ) = '\0'; + } + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static portINLINE BaseType_t strbuf_printchar_inline( struct SStringBuf *apStr, int c ) +{ + if( apStr->str == NULL ) + { + vOutputChar( ( char ) c, xTicksToWait ); + if( c == 0 ) + { + return pdFALSE; + } + apStr->curLen++; + return pdTRUE; + } + if( apStr->str < apStr->nulPos ) + { + *(apStr->str++) = c; + if( c == 0 ) + { + return pdFALSE; + } + apStr->curLen++; + return pdTRUE; + } + if( apStr->str == apStr->nulPos ) + { + *( apStr->str++ ) = '\0'; + } + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static portINLINE int i2hex( int aCh ) +{ +int iResult; + + if( aCh < 10 ) + { + iResult = '0' + aCh; + } + else + { + iResult = 'A' + aCh - 10; + } + + return iResult; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prints(struct SStringBuf *apBuf, const char *apString ) +{ + register int padchar = ' '; + int i,len; + + if( xApplicationMemoryPermissions( ( uint32_t )apString ) == 0 ) + { + /* The user has probably made a mistake with the parameter + for '%s', the memory is not readbale. */ + apString = "INV_MEM"; + } + + if( apBuf->flags.width > 0 ) + { + register int len = 0; + register const char *ptr; + for( ptr = apString; *ptr; ++ptr ) + { + ++len; + } + + if( len >= apBuf->flags.width ) + { + apBuf->flags.width = 0; + } + else + { + apBuf->flags.width -= len; + } + + if( apBuf->flags.pad & PAD_ZERO ) + { + padchar = '0'; + } + } + if( ( apBuf->flags.pad & PAD_RIGHT ) == 0 ) + { + for( ; apBuf->flags.width > 0; --apBuf->flags.width ) + { + if( strbuf_printchar( apBuf, padchar ) == 0 ) + { + return pdFALSE; + } + } + } + if( ( apBuf->flags.isNumber == pdTRUE ) && ( apBuf->flags.pad == pdTRUE ) ) + { + /* The string to print represents an integer number. + * In this case, printLimit is the min number of digits to print + * If the length of the number to print is less than the min nb of i + * digits to display, we add 0 before printing the number + */ + len = strlen( apString ); + + if( len < apBuf->flags.printLimit ) + { + i = apBuf->flags.printLimit - len; + for( ; i; i-- ) + { + if( strbuf_printchar( apBuf, '0' ) == 0 ) + { + return pdFALSE; + } + } + } + } + /* The string to print is not the result of a number conversion to ascii. + * For a string, printLimit is the max number of characters to display + */ + for( ; apBuf->flags.printLimit && *apString ; ++apString, --apBuf->flags.printLimit ) + { + if( !strbuf_printchar( apBuf, *apString ) ) + { + return pdFALSE; + } + } + + for( ; apBuf->flags.width > 0; --apBuf->flags.width ) + { + if( !strbuf_printchar( apBuf, padchar ) ) + { + return pdFALSE; + } + } + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +/* the following should be enough for 32 bit int */ +#define PRINT_BUF_LEN 12 /* to print 4294967296 */ + +#if SPRINTF_LONG_LONG +#warning 64-bit libraries will be included as well +static BaseType_t printll( struct SStringBuf *apBuf, long long i ) +{ + char print_buf[ 2 * PRINT_BUF_LEN ]; + register char *s; + register int t, neg = 0; + register unsigned long long u = i; + lldiv_t lldiv_result; + +/* typedef struct + * { + * long long int quot; // quotient + * long long int rem; // remainder + * } lldiv_t; + */ + + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + if( i == 0LL ) + { + print_buf[ 0 ] = '0'; + print_buf[ 1 ] = '\0'; + return prints( apBuf, print_buf ); + } + + if( ( apBuf->flags.isSigned == pdTRUE ) && ( apBuf->flags.base == 10 ) && ( i < 0LL ) ) + { + neg = 1; + u = -i; + } + + s = print_buf + sizeof( print_buf ) - 1; + + *s = '\0'; + /* 18446744073709551616 */ + while( u != 0 ) + { + lldiv_result = lldiv( u, ( unsigned long long ) apBuf->flags.base ); + t = lldiv_result.rem; + if( t >= 10 ) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u = lldiv_result.quot; + } + + if( neg != 0 ) + { + if( ( apBuf->flags.width != 0 ) && ( apBuf->flags.pad & PAD_ZERO ) ) + { + if( !strbuf_printchar( apBuf, '-' ) ) + { + return pdFALSE; + } + --apBuf->flags.width; + } + else + { + *( --s ) = '-'; + } + } + + return prints( apBuf, s ); +} +#endif /* SPRINTF_LONG_LONG */ +/*-----------------------------------------------------------*/ + +static BaseType_t printi( struct SStringBuf *apBuf, int i ) +{ + char print_buf[ PRINT_BUF_LEN ]; + register char *s; + register int t, neg = 0; + register unsigned int u = i; + register unsigned base = apBuf->flags.base; + + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + + if( i == 0 ) + { + print_buf[ 0 ] = '0'; + print_buf[ 1 ] = '\0'; + return prints( apBuf, print_buf ); + } + + if( ( apBuf->flags.isSigned == pdTRUE ) && ( base == 10 ) && ( i < 0 ) ) + { + neg = 1; + u = -i; + } + + s = print_buf + sizeof( print_buf ) - 1; + + *s = '\0'; + switch( base ) + { + case 16: + while( u != 0 ) + { + t = u & 0xF; + if( t >= 10 ) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u >>= 4; + } + break; + + case 8: + case 10: + /* GCC compiles very efficient */ + while( u ) + { + t = u % base; + *( --s ) = t + '0'; + u /= base; + } + break; +/* + // The generic case, not yet in use + default: + while( u ) + { + t = u % base; + if( t >= 10) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u /= base; + } + break; +*/ + } + + if( neg != 0 ) + { + if( apBuf->flags.width && (apBuf->flags.pad & PAD_ZERO ) ) + { + if( strbuf_printchar( apBuf, '-' ) == 0 ) + { + return pdFALSE; + } + --apBuf->flags.width; + } + else + { + *( --s ) = '-'; + } + } + + return prints( apBuf, s ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t printIp(struct SStringBuf *apBuf, unsigned i ) +{ + char print_buf[16]; + + sprintf( print_buf, "%u.%u.%u.%u", + i >> 24, + ( i >> 16 ) & 0xff, + ( i >> 8 ) & 0xff, + i & 0xff ); + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + prints( apBuf, print_buf ); + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +static void tiny_print( struct SStringBuf *apBuf, const char *format, va_list args ) +{ + char scr[2]; + + for( ; ; ) + { + int ch = *( format++ ); + + if( ch != '%' ) + { + do + { + /* Put the most like flow in a small loop */ + if( strbuf_printchar_inline( apBuf, ch ) == 0 ) + { + return; + } + ch = *( format++ ); + } while( ch != '%' ); + } + ch = *( format++ ); + /* Now ch has character after '%', format pointing to next */ + + if( ch == '\0' ) + { + break; + } + if( ch == '%' ) + { + if( strbuf_printchar( apBuf, ch ) == 0 ) + { + return; + } + continue; + } + memset( &apBuf->flags, '\0', sizeof( apBuf->flags ) ); + + if( ch == '-' ) + { + ch = *( format++ ); + apBuf->flags.pad = PAD_RIGHT; + } + while( ch == '0' ) + { + ch = *( format++ ); + apBuf->flags.pad |= PAD_ZERO; + } + if( ch == '*' ) + { + ch = *( format++ ); + apBuf->flags.width = va_arg( args, int ); + } + else + { + while( ch >= '0' && ch <= '9' ) + { + apBuf->flags.width *= 10; + apBuf->flags.width += ch - '0'; + ch = *( format++ ); + } + } + if( ch == '.' ) + { + ch = *( format++ ); + if( ch == '*' ) + { + apBuf->flags.printLimit = va_arg( args, int ); + ch = *( format++ ); + } + else + { + while( ch >= '0' && ch <= '9' ) + { + apBuf->flags.printLimit *= 10; + apBuf->flags.printLimit += ch - '0'; + ch = *( format++ ); + } + } + } + if( apBuf->flags.printLimit == 0 ) + { + apBuf->flags.printLimit--; /* -1: make it unlimited */ + } + if( ch == 's' ) + { + register char *s = ( char * )va_arg( args, int ); + if( prints( apBuf, s ? s : "(null)" ) == 0 ) + { + break; + } + continue; + } + if( ch == 'c' ) + { + /* char are converted to int then pushed on the stack */ + scr[0] = ( char ) va_arg( args, int ); + + if( strbuf_printchar( apBuf, scr[0] ) == 0 ) + { + return; + } + + continue; + } + if( ch == 'l' ) + { + ch = *( format++ ); + apBuf->flags.long32 = 1; + /* Makes not difference as u32 == long */ + } + if( ch == 'L' ) + { + ch = *( format++ ); + apBuf->flags.long64 = 1; + /* Does make a difference */ + } + apBuf->flags.base = 10; + apBuf->flags.letBase = 'a'; + + if( ch == 'd' || ch == 'u' ) + { + apBuf->flags.isSigned = ( ch == 'd' ); +#if SPRINTF_LONG_LONG + if( apBuf->flags.long64 != pdFALSE ) + { + if( printll( apBuf, va_arg( args, long long ) ) == 0 ) + { + break; + } + } else +#endif /* SPRINTF_LONG_LONG */ + if( printi( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + + apBuf->flags.base = 16; /* From here all hexadecimal */ + + if( ch == 'x' && format[0] == 'i' && format[1] == 'p' ) + { + format += 2; /* eat the "xi" of "xip" */ + /* Will use base 10 again */ + if( printIp( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + if( ch == 'x' || ch == 'X' || ch == 'p' || ch == 'o' ) + { + if( ch == 'X' ) + { + apBuf->flags.letBase = 'A'; + } + else if( ch == 'o' ) + { + apBuf->flags.base = 8; + } +#if SPRINTF_LONG_LONG + if( apBuf->flags.long64 != pdFALSE ) + { + if( printll( apBuf, va_arg( args, long long ) ) == 0 ) + { + break; + } + } else +#endif /* SPRINTF_LONG_LONG */ + if( printi( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + } + strbuf_printchar( apBuf, '\0' ); +} +/*-----------------------------------------------------------*/ + +int vsnprintf( char *apBuf, size_t aMaxLen, const char *apFmt, va_list args ) +{ + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen ); + tiny_print( &strBuf, apFmt, args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int snprintf( char *apBuf, size_t aMaxLen, const char *apFmt, ... ) +{ + va_list args; + + va_start( args, apFmt ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen ); + tiny_print( &strBuf, apFmt, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int sprintf( char *apBuf, const char *apFmt, ... ) +{ + va_list args; + + va_start( args, apFmt ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char * )apBuf + 1024 ); + tiny_print( &strBuf, apFmt, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int vsprintf( char *apBuf, const char *apFmt, va_list args ) +{ + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* ) apBuf + 1024 ); + tiny_print( &strBuf, apFmt, args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +const char *mkSize (unsigned long long aSize, char *apBuf, int aLen) +{ +static char retString[33]; +size_t gb, mb, kb, sb; + + if (apBuf == NULL) { + apBuf = retString; + aLen = sizeof( retString ); + } + gb = aSize / (1024*1024*1024); + aSize -= gb * (1024*1024*1024); + mb = aSize / (1024*1024); + aSize -= mb * (1024*1024); + kb = aSize / (1024); + aSize -= kb * (1024); + sb = aSize; + if( gb ) + { + snprintf (apBuf, aLen, "%u.%02u GB", ( unsigned ) gb, ( unsigned ) ( ( 100 * mb ) / 1024ul ) ); + } + else if( mb ) + { + snprintf (apBuf, aLen, "%u.%02u MB", ( unsigned ) mb, ( unsigned ) ( ( 100 * kb) / 1024ul ) ); + } + else if( kb != 0ul ) + { + snprintf (apBuf, aLen, "%u.%02u KB", ( unsigned ) kb, ( unsigned ) ( ( 100 * sb) / 1024ul ) ); + } + else + { + snprintf (apBuf, aLen, "%u bytes", ( unsigned ) sb); + } + return apBuf; +} diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/shadow_device_operations_demo.sln b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/shadow_device_operations_demo.sln new file mode 100644 index 000000000..b362f36c5 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow/shadow_device_operations/shadow_device_operations_demo.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTOSDemo", "WIN32.vcxproj", "{C686325E-3261-42F7-AEB1-DDE5280E1CEB}" +EndProject +Global + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = FreeRTOS_Plus_TCP_Minimal.vsmdi + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.ActiveCfg = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.Build.0 = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.ActiveCfg = Release|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_offline/CertificateConfigurator.html b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_offline/CertificateConfigurator.html new file mode 100644 index 000000000..97460ab01 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_offline/CertificateConfigurator.html @@ -0,0 +1,84 @@ + + + + FreeRTOS.org Developer Demos Configuration Tool + + + + + + + + + +

+
+
+
+
+

AWS Profile Configuration Tool

+

FreeRTOS.org Developer Demos

+
+
+
+
+
+

+ Enter Thing name and endpoint. Provide client certificate and private key PEM files downloaded from the AWS IoT Console. +

+
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+ +
+
+
+
+

+ + Save the generated header file to the FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/include folder of the demo project. +

+
+
+
+
+ Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +
+
+
+
+
+
+ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_offline/js/aws_iot_demo_profile_template.js b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_offline/js/aws_iot_demo_profile_template.js new file mode 100644 index 000000000..d30abd5a5 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_offline/js/aws_iot_demo_profile_template.js @@ -0,0 +1,141 @@ +var awsIotProfileTemplate = +`/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * IMPORTANT, CONFIGURATION REQUIRED: This is a configuration file containing AWS + * IoT profile for the demos, will need additional setup: + * https://www.freertos.org/mqtt/preconfiguredexamplesMA.html + * + * Each profile corresponds to a different service. The demos that use the same + * profile share the same service. It is important to understand the + * correspondence between the preconfigured profiles and demos, since each + * service have different connection configuration and credential validation. + * + * - mqtt_demo_profile.h is preconfigured to test.mosquitto.org MQTT broker. + * The file is used with mqtt_plain_text demo and mqtt_basic_tls_server_auth + * demo. Feel free to try out other broker with the demos. + * + * - https_demo_profile.h is preconfigured to httpbin.org server. The file is + * used with http_plain_text demo and https_basic_tls_server_auth demo. + * + * - aws_iot_demo_profile.h (current) contains information to connect to AWS + * IoT. The file is used with mqtt_tls_mutual_auth demo, https_tls_mutual_auth + * demo, and other AWS IoT related demo. + */ + +#ifndef AWS_IOT_DEMO_PROFILE_H +#define AWS_IOT_DEMO_PROFILE_H + +/** + * @brief Details of the MQTT broker to connect to. + * + * This is the Thing's Rest API Endpoint for AWS IoT. + * + * #define awsiotdemoprofileAWS_ENDPOINT "...insert here..." + */ +#define awsiotdemoprofileAWS_ENDPOINT + +/** + * @brief The port to use for the MQTT demo. + * + * Use 8883 if connecting to AWS IoT services. + */ +#define awsiotdemoprofileAWS_MQTT_PORT 8883 + +/** + * @brief The port to use for the HTTPS demo. + * + * Use 8443 if connecting to AWS IoT services. + */ +#define awsiotdemoprofileAWS_HTTPS_PORT 8443 + +/** + * @brief The AWS IoT server certificate. + * + * This certificate is used to identify the AWS IoT server and is publicly + * available. + */ +#define awsiotdemoprofileAWS_CERTIFICATE_PEM \\ + "-----BEGIN CERTIFICATE-----\\n" \\ + "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\\n" \\ + "ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\\n" \\ + "b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\\n" \\ + "MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\\n" \\ + "b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\\n" \\ + "ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\\n" \\ + "9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\\n" \\ + "IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\\n" \\ + "VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\\n" \\ + "93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\\n" \\ + "jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\\n" \\ + "AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\\n" \\ + "A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\\n" \\ + "U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\\n" \\ + "N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\\n" \\ + "o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\\n" \\ + "5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\\n" \\ + "rqXRfboQnoZsG4q5WTP468SQvvG5\\n" \\ + "-----END CERTIFICATE-----\\n" + +/** + * @brief The MQTT client identifier. + * + * This is the "Thing Name" in AWS IoT. + * + * #define awsiotdemoprofileCLIENT_IDENTIFIER "...insert here..." + */ +#define awsiotdemoprofileCLIENT_IDENTIFIER + +/** + * @brief PEM-encoded client certificate + * + * Must include the PEM header and footer: + * "-----BEGIN CERTIFICATE-----\\n"\\ + * "...base64 data...\\n"\\ + * "-----END CERTIFICATE-----\\n" + * + * #define awsiotdemoprofileCLIENT_CERTIFICATE_PEM "...insert here..." + */ +#define awsiotdemoprofileCLIENT_CERTIFICATE_PEM \\ + + +/** + * @brief PEM-encoded client private key. + * + * Must include the PEM header and footer: + * "-----BEGIN RSA PRIVATE KEY-----\\n"\\ + * "...base64 data...\\n"\\ + * "-----END RSA PRIVATE KEY-----\\n" + * + * #define awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM "...insert here..." + */ +#define awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM \\ + + +#endif /* AWS_IOT_DEMO_PROFILE_H */ +` diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_offline/js/generator.js b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_offline/js/generator.js new file mode 100644 index 000000000..49ad050ba --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_offline/js/generator.js @@ -0,0 +1,70 @@ + +// Check for the various File API support. +if (window.File && window.FileReader && window.FileList && window.Blob) { + // Success! All the File APIs are supported. +} else { + alert('Please use a web browser that supports HTML5 file APIs.') +} + +function formatCredentialTextForHeader (credentialText) { + // Replace any CR/LF pairs with a newline character. + credentialText = credentialText.replace(/\r\n/g, '\n') + + // Add line endings for C-language variable declaration. + credentialText = credentialText.replace(/\n/g, '\\n" \\\n "') + + // Remove '\n"' from the last line of the declaration and add a semicolon. + credentialText = credentialText.slice(0, -9) + '"\n' + return credentialText +} + +function generateCertificateConfigurationHeader () { + var pemCertificateText = '' + var pemPrivateKeyText = '' + var filename = 'aws_iot_demo_profile.h' + var outputText = '' + + var readerCertificate = new FileReader() + var readerPrivateKey = new FileReader() + + // Start certificate read + readerCertificate.readAsText(pemInputFileCertificate.files[0]) + + // Define a handler to create appropriate client certificate file text. + readerCertificate.onload = function (e) { + pemCertificateText = e.target.result + + // Add C-language variable declaration plus EOL formatting. + pemCertificateText = ' "' + formatCredentialTextForHeader(pemCertificateText) + + // Because this is async, read next file inline. + readerPrivateKey.readAsText(pemInputFilePrivateKey.files[0]) + } + + // Define a handler to create appropriate private key file text. + readerPrivateKey.onload = function (e) { + pemPrivateKeyText = e.target.result + + // Add C-language variable declaration plus EOL formatting. + pemPrivateKeyText = ' "' + formatCredentialTextForHeader(pemPrivateKeyText) + + outputText = awsIotProfileTemplate + outputText = outputText.replace('', '"' + document.getElementById('AWSEndpoint').value + '"') + outputText = outputText.replace('', '"' + document.getElementById('thingName').value + '"') + outputText = outputText.replace('', pemCertificateText) + outputText = outputText.replace('', pemPrivateKeyText) + + // Because this is async, handle download generation inline. + var downloadBlob = new Blob([outputText], { type: 'text/plain' }) + if (window.navigator.msSaveOrOpenBlob) { + window.navigator.msSaveBlob(downloadBlob, filename) + } else { + var downloadLink = document.createElement('a') + downloadLink.href = window.URL.createObjectURL(downloadBlob) + downloadLink.download = filename + document.body.appendChild(downloadLink) + downloadLink.click() + document.body.removeChild(downloadLink) + } + } +} diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/.gitignore b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/.gitignore new file mode 100644 index 000000000..41af3522a --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/.gitignore @@ -0,0 +1,5 @@ +__pycache__ +test* +*_id_file +*_pem_file +*.pyc diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/README.md b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/README.md new file mode 100644 index 000000000..11926a571 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/README.md @@ -0,0 +1,20 @@ +## Script to setup the AWS resources through command line + +This script automates the process of [Prerequisites](https://docs.aws.amazon.com/freertos/latest/userguide/freertos-prereqs.html) and the configuring the files `aws_iot_demo_profile.h` to connect to AWS IoT. + +Make sure you have `aws cli` configured on your machine with access_key, secret_key and region. + +Open the file `configure.json` and fill in the following details: +* afr_source_dir : The path of the amazon-freertos directory. By default, this is set to the top level of this repo (../..). +* thing_name : Name of the thing you want to create + +**Options to use with the script** +1. To setup your Thing, and update credentials file, type the command: `python SetupAWS.py setup` +2. To cleanup the Thing you created with the script, and revert changes in credentials file, type the command: `python SetupAWS.py cleanup` +3. To only create thing, certificate and policy, type the command: `python SetupAWS.py prereq` +4. To update the files `aws_iot_demo_profile.h` with thing name and the certificate keys, type the command `python SetupAWS.py update_creds` +5. To delete the thing, certificate and policy created by the script, type the command: `python SetupAWS.py delete_prereq` +6. To revert the changes in the file `aws_iot_demo_profile.h`, type the command: `python SetupAWS.py cleanup_creds` +7. To list your certificates, type the command: `python SetupAWS.py list_certificates` +8. To list your policies, type the command: `python SetupAWS.py list_policies` +9. To list your things, type the command: `python SetupAWS.py list_things` \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/SetupAWS.py b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/SetupAWS.py new file mode 100644 index 000000000..dade6b769 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/SetupAWS.py @@ -0,0 +1,235 @@ +#!/usr/bin/env python + +import os +import sys +import json +import pprint +import argparse +import boto3 +import misc +import certs +import thing +import policy + +pp = pprint.PrettyPrinter(indent=4) + + +def check_aws_configuration(): + mysession = boto3.session.Session() + if not mysession._session._config['profiles']: + print("AWS not configured. Please run `aws configure`.") + sys.exit(1) + + +def prereq(): + with open('configure.json') as configure_file: + json_text = json.load(configure_file) + + # Create a Thing + thing_name = json_text['thing_name'] + thing_obj = thing.Thing(thing_name) + if not thing_obj.create(): + + # Create a Certificate + cert_obj = certs.Certificate() + result = cert_obj.create() + + # Store certId + cert_id = result['certificateId'] + cert_id_filename = thing_name + '_cert_id_file.txt' + cert_id_file = open(cert_id_filename, 'w') + cert_id_file.write(cert_id) + cert_id_file_path = os.path.abspath(cert_id_filename) + os.chmod(cert_id_file_path, 0o444) + cert_id_file.close() + + # Store cert_pem as file + cert_pem = result['certificatePem'] + cert_pem_filename = thing_name + '_cert_pem_file.pem' + cert_pem_file = open(cert_pem_filename, 'w') + cert_pem_file.write(cert_pem) + cert_pem_file_path = os.path.abspath(cert_pem_filename) + os.chmod(cert_pem_file_path, 0o444) + cert_pem_file.close() + + # Store private key PEM as file + private_key_pem = result['keyPair']['PrivateKey'] + private_key_pem_filename = thing_name + '_private_key_pem_file.pem' + private_key_pem_file = open(private_key_pem_filename, 'w') + private_key_pem_file.write(private_key_pem) + private_key_pem_file_path = os.path.abspath(private_key_pem_filename) + os.chmod(private_key_pem_file_path, 0o444) + private_key_pem_file.close() + + # Create a Policy + policy_document = misc.create_policy_document() + policy_name = thing_name + '_amazon_freertos_policy' + policy_obj = policy.Policy(policy_name, policy_document) + policy_obj.create() + + # Attach certificate to Thing + cert_obj.attach_thing(thing_name) + + # Attach policy to certificate + cert_obj.attach_policy(policy_name) + + +def update_credential_file(): + with open('configure.json') as configure_file: + json_text = json.load(configure_file) + + source_dir = os.path.expanduser(json_text['FreeRTOS_source_dir']) + thing_name = json_text['thing_name'] + + # Read cert_pem from file + cert_pem_filename = thing_name + '_cert_pem_file.pem' + try: + cert_pem_file = open(cert_pem_filename, 'r') + except IOError: + print("{} file not found. Run prerequisite step" + .format(cert_pem_filename)) + sys.exit(1) + else: + cert_pem = cert_pem_file.read() + + # Read private_key_pem from file + private_key_pem_filename = thing_name + '_private_key_pem_file.pem' + try: + private_key_pem_file = open(private_key_pem_filename, 'r') + except IOError: + print("{} file not found. Run prerequisite step" + .format(private_key_pem_filename)) + sys.exit(1) + else: + private_key_pem = private_key_pem_file.read() + + # Modify 'iot_clientcredential.h' file + misc.write_client_credentials( + source_dir, + thing_name=thing_name, + client_certificate_pem=cert_pem, + client_private_key_pem=private_key_pem, + cleanup=False) + + +def delete_prereq(): + with open('configure.json') as configure_file: + json_text = json.load(configure_file) + + # Delete Thing + thing_name = json_text['thing_name'] + thing_obj = thing.Thing(thing_name) + if thing_obj.exists(): + thing_obj.delete() + + # Delete certificate + cert_id_filename = thing_name + '_cert_id_file.txt' + if os.path.exists(cert_id_filename): + cert_id_file = open(cert_id_filename, 'r') + cert_id = cert_id_file.read() + cert_obj = certs.Certificate(cert_id) + cert_obj.delete() + cert_id_file.close() + cert_id_file_path = os.path.abspath(cert_id_filename) + os.chmod(cert_id_file_path, 0o666) + os.remove(cert_id_filename) + + # Delete cert_pem file and private_key_pem file + cert_pem_filename = thing_name + '_cert_pem_file.pem' + if os.path.exists(cert_pem_filename): + cert_pem_file_path = os.path.abspath(cert_pem_filename) + os.chmod(cert_pem_file_path, 0o666) + os.remove(cert_pem_filename) + + private_key_pem_filename = thing_name + '_private_key_pem_file.pem' + if os.path.exists(private_key_pem_filename): + private_key_pem_file_path = os.path.abspath(private_key_pem_filename) + os.chmod(private_key_pem_file_path, 0o666) + os.remove(private_key_pem_filename) + + # Delete policy + policy_name = thing_name + '_amazon_freertos_policy' + policy_obj = policy.Policy(policy_name) + if policy_obj.exists(): + policy_obj.delete() + + +def cleanup_creds(): + with open('configure.json') as file: + json_text = json.load(file) + + source_dir = os.path.expanduser(json_text['FreeRTOS_source_dir']) + + # Cleanup 'iot_clientcredential.h' file + misc.write_client_credentials(source_dir, cleanup=True) + + +def setup(): + prereq() + update_credential_file() + print("Setup Completed") + + +def cleanup(): + delete_prereq() + cleanup_creds() + print("Cleanup Completed") + + +def list_certificates(): + client = boto3.client('iot') + certs = client.list_certificates()['certificates'] + pp.pprint(certs) + + +def list_things(): + client = boto3.client('iot') + things = client.list_things()['things'] + pp.pprint(things) + + +def list_policies(): + client = boto3.client('iot') + policies = client.list_policies()['policies'] + pp.pprint(policies) + + +if __name__ == "__main__": + + arg_parser = argparse.ArgumentParser() + subparsers = arg_parser.add_subparsers(help='Available commands', + dest='command') + subparsers.add_parser('setup', help='Setup AWS IoT') + subparsers.add_parser('cleanup', help='Cleanup AWS IoT') + subparsers.add_parser('list_certificates', help='List certificates') + subparsers.add_parser('list_things', help='List things') + subparsers.add_parser('list_policies', help='List policies') + subparsers.add_parser('prereq', help='Setup prerequisites for AWS IoT') + subparsers.add_parser('update_creds', help='Update credential files') + subparsers.add_parser('delete_prereq', help='Delete prerequisites created') + subparsers.add_parser('cleanup_creds', help='Cleanup credential files') + args = arg_parser.parse_args() + check_aws_configuration() + + if args.command == 'setup': + setup() + elif args.command == 'cleanup': + cleanup() + elif args.command == 'list_certificates': + list_certificates() + elif args.command == 'list_things': + list_things() + elif args.command == 'list_policies': + list_policies() + elif args.command == 'prereq': + prereq() + elif args.command == 'update_creds': + update_credential_file() + elif args.command == 'delete_prereq': + delete_prereq() + elif args.command == 'cleanup_creds': + cleanup_creds() + else: + print("Command does not exist") + + sys.exit(1) \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/aws_iot_demo_profile.templ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/aws_iot_demo_profile.templ new file mode 100644 index 000000000..817f706a9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/aws_iot_demo_profile.templ @@ -0,0 +1,139 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * IMPORTANT, CONFIGURATION REQUIRED: This is a configuration file containing AWS + * IoT profile for the demos, will need additional setup: + * https://www.freertos.org/mqtt/preconfiguredexamplesMA.html + * + * Each profile corresponds to a different service. The demos that use the same + * profile share the same service. It is important to understand the + * correspondence between the preconfigured profiles and demos, since each + * service have different connection configuration and credential validation. + * + * - mqtt_demo_profile.h is preconfigured to test.mosquitto.org MQTT broker. + * The file is used with mqtt_plain_text demo and mqtt_basic_tls_server_auth + * demo. Feel free to try out other broker with the demos. + * + * - https_demo_profile.h is preconfigured to httpbin.org server. The file is + * used with http_plain_text demo and https_basic_tls_server_auth demo. + * + * - aws_iot_demo_profile.h (current) contains information to connect to AWS + * IoT. The file is used with mqtt_tls_mutual_auth demo, https_tls_mutual_auth + * demo, and other AWS IoT related demo. + */ + +#ifndef AWS_IOT_DEMO_PROFILE_H +#define AWS_IOT_DEMO_PROFILE_H + +/** + * @brief Details of the MQTT broker to connect to. + * + * This is the Thing's Rest API Endpoint for AWS IoT. + * + * #define awsiotdemoprofileAWS_ENDPOINT "...insert here..." + */ +#define awsiotdemoprofileAWS_ENDPOINT + +/** + * @brief The port to use for the MQTT demo. + * + * Use 8883 if connecting to AWS IoT services. + */ +#define awsiotdemoprofileAWS_MQTT_PORT 8883 + +/** + * @brief The port to use for the HTTPS demo. + * + * Use 8443 if connecting to AWS IoT services. + */ +#define awsiotdemoprofileAWS_HTTPS_PORT 8443 + +/** + * @brief The AWS IoT server certificate. + * + * This certificate is used to identify the AWS IoT server and is publicly + * available. + */ +#define awsiotdemoprofileAWS_CERTIFICATE_PEM \ + "-----BEGIN CERTIFICATE-----\n" \ + "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n" \ + "ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n" \ + "b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n" \ + "MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n" \ + "b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n" \ + "ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n" \ + "9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n" \ + "IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n" \ + "VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n" \ + "93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n" \ + "jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n" \ + "AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n" \ + "A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n" \ + "U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n" \ + "N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n" \ + "o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n" \ + "5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n" \ + "rqXRfboQnoZsG4q5WTP468SQvvG5\n" \ + "-----END CERTIFICATE-----\n" + +/** + * @brief The MQTT client identifier. + * + * This is the "Thing Name" in AWS IoT. + * + * #define awsiotdemoprofileCLIENT_IDENTIFIER "...insert here..." + */ +#define awsiotdemoprofileCLIENT_IDENTIFIER + +/** + * @brief PEM-encoded client certificate + * + * Must include the PEM header and footer: + * "-----BEGIN CERTIFICATE-----\n"\ + * "...base64 data...\n"\ + * "-----END CERTIFICATE-----\n" + * + * #define awsiotdemoprofileCLIENT_CERTIFICATE_PEM "...insert here..." + */ +#define awsiotdemoprofileCLIENT_CERTIFICATE_PEM \ + + +/** + * @brief PEM-encoded client private key. + * + * Must include the PEM header and footer: + * "-----BEGIN RSA PRIVATE KEY-----\n"\ + * "...base64 data...\n"\ + * "-----END RSA PRIVATE KEY-----\n" + * + * #define awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM "...insert here..." + */ +#define awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM \ + + +#endif /* AWS_IOT_DEMO_PROFILE_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/aws_iot_demo_profile_empty.templ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/aws_iot_demo_profile_empty.templ new file mode 100644 index 000000000..c4a3e1a58 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/aws_iot_demo_profile_empty.templ @@ -0,0 +1,133 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * IMPORTANT, CONFIGURATION REQUIRED: This is a configuration file containing AWS + * IoT profile for the demos, will need additional setup: + * https://www.freertos.org/mqtt/preconfiguredexamplesMA.html + * + * Each profile corresponds to a different service. The demos that use the same + * profile share the same service. It is important to understand the + * correspondence between the preconfigured profiles and demos, since each + * service have different connection configuration and credential validation. + * + * - mqtt_demo_profile.h is preconfigured to test.mosquitto.org MQTT broker. + * The file is used with mqtt_plain_text demo and mqtt_basic_tls_server_auth + * demo. Feel free to try out other broker with the demos. + * + * - https_demo_profile.h is preconfigured to httpbin.org server. The file is + * used with http_plain_text demo and https_basic_tls_server_auth demo. + * + * - aws_iot_demo_profile.h (current) contains information to connect to AWS + * IoT. The file is used with mqtt_tls_mutual_auth demo, https_tls_mutual_auth + * demo, and other AWS IoT related demo. + */ + +#ifndef AWS_IOT_DEMO_PROFILE_H +#define AWS_IOT_DEMO_PROFILE_H + +/** + * @brief Details of the MQTT broker to connect to. + * + * This is the Thing's Rest API Endpoint for AWS IoT. + * + * #define awsiotdemoprofileAWS_ENDPOINT "...insert here..." + */ + +/** + * @brief The port to use for the MQTT demo. + * + * Use 8883 if connecting to AWS IoT services. + */ +#define awsiotdemoprofileAWS_MQTT_PORT 8883 + +/** + * @brief The port to use for the HTTPS demo. + * + * Use 8443 if connecting to AWS IoT services. + */ +#define awsiotdemoprofileAWS_HTTPS_PORT 8443 + +/** + * @brief The AWS IoT server certificate. + * + * This certificate is used to identify the AWS IoT server and is publicly + * available. + */ +#define awsiotdemoprofileAWS_CERTIFICATE_PEM \ + "-----BEGIN CERTIFICATE-----\n" \ + "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n" \ + "ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n" \ + "b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n" \ + "MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n" \ + "b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n" \ + "ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n" \ + "9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n" \ + "IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n" \ + "VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n" \ + "93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n" \ + "jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n" \ + "AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n" \ + "A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n" \ + "U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n" \ + "N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n" \ + "o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n" \ + "5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n" \ + "rqXRfboQnoZsG4q5WTP468SQvvG5\n" \ + "-----END CERTIFICATE-----\n" + +/** + * @brief The MQTT client identifier. + * + * This is the "Thing Name" in AWS IoT. + * + * #define awsiotdemoprofileCLIENT_IDENTIFIER "...insert here..." + */ + +/** + * @brief PEM-encoded client certificate + * + * Must include the PEM header and footer: + * "-----BEGIN CERTIFICATE-----\n"\ + * "...base64 data...\n"\ + * "-----END CERTIFICATE-----\n" + * + * #define awsiotdemoprofileCLIENT_CERTIFICATE_PEM "...insert here..." + */ + +/** + * @brief PEM-encoded client private key. + * + * Must include the PEM header and footer: + * "-----BEGIN RSA PRIVATE KEY-----\n"\ + * "...base64 data...\n"\ + * "-----END RSA PRIVATE KEY-----\n" + * + * #define awsiotdemoprofileCLIENT_PRIVATE_KEY_PEM "...insert here..." + */ + +#endif /* AWS_IOT_DEMO_PROFILE_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/certs.py b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/certs.py new file mode 100644 index 000000000..3cf6d1b79 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/certs.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python + +import boto3 +import json + + +class Certificate(): + + def __init__(self, certId=''): + self.id = certId + self.arn = '' + self.client = boto3.client('iot') + if (self.id != ''): + result = self.client.describe_certificate(certificateId=self.id) + self.arn = result['certificateDescription']['certificateArn'] + + def create(self): + assert not self.exists(), "Cert already exists" + cert = self.create_keys_and_certificate() + self.id = cert["certificateId"] + self.arn = cert["certificateArn"] + return cert + + def create_keys_and_certificate(self): + result = self.client.create_keys_and_certificate(setAsActive=True) + return result + + def delete(self): + cert_not_found = True + # Detach Policies attached to the cert + policies_attached = self.list_policies() + for policy in policies_attached: + self.detach_policy(policy['policyName']) + + # Detach Things attached to the cert + things_attached = self.list_things() + for thing in things_attached: + self.detach_thing(thing) + + # Update the status of the certificate to INACTIVE + try: + self.client.update_certificate(certificateId=self.id, + newStatus='INACTIVE') + cert_not_found = False + except self.client.exceptions.ResourceNotFoundException: + cert_not_found = True + return cert_not_found + + # Delete the certificate + try: + self.client.delete_certificate(certificateId=self.id) + cert_not_found = False + except self.client.exceptions.ResourceNotFoundException: + cert_not_found = True + return cert_not_found + + def exists(self): + if self.id == '': + return False + else: + return True + + def get_arn(self): + return self.arn + + def list_policies(self): + policies = self.client.list_principal_policies(principal=self.arn) + policies = policies['policies'] + return policies + + def attach_policy(self, policy_name): + self.client.attach_policy(policyName=policy_name, target=self.arn) + + def detach_policy(self, policy_name): + self.client.detach_policy(policyName=policy_name, target=self.arn) + + def list_things(self): + things = self.client.list_principal_things(principal=self.arn) + things = things['things'] + return things + + def attach_thing(self, thing_name): + self.client.attach_thing_principal(thingName=thing_name, + principal=self.arn) + + def detach_thing(self, thing_name): + self.client.detach_thing_principal(thingName=thing_name, + principal=self.arn) diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/configure.json b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/configure.json new file mode 100644 index 000000000..5ba089b48 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/configure.json @@ -0,0 +1,4 @@ +{ + "FreeRTOS_source_dir":"../..", + "thing_name":"$thing_name" +} \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/misc.py b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/misc.py new file mode 100644 index 000000000..9bb25a219 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/misc.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python + +import os +import boto3 + + +def describe_endpoint(): + client = boto3.client('iot') + endpoint = client.describe_endpoint(endpointType='iot:Data-ATS') + return endpoint['endpointAddress'] + + +def get_account_id(): + client = boto3.client('sts') + aws_account_id = client.get_caller_identity()['Account'] + return aws_account_id.strip('\n') + + +def get_aws_region(): + my_session = boto3.session.Session() + aws_region = my_session.region_name + return aws_region.strip('\n') + + +def create_policy_document(): + this_file_directory = os.getcwd() + policy_document = os.path.join(this_file_directory, + 'policy_document.templ') + region_name = str(get_aws_region()) + aws_account_id = str(get_account_id()) + with open(policy_document) as policy_document_file: + policy_document_text = policy_document_file.read() + + # Replace Account ID and AWS Region + policy_document_text = policy_document_text.replace('', + region_name) + policy_document_text = policy_document_text.replace('', + aws_account_id) + + return policy_document_text + + +def format_credential_keys_text(credential_text): + credential_text_lines = credential_text.split('\n') + formatted_credential_text_lines = [] + + for credential_text_line in credential_text_lines: + if credential_text_line.strip(): + formatted_credential_text_line = ' {:68s}'\ + .format('"' + credential_text_line + '\\n"') + formatted_credential_text_lines.append( + formatted_credential_text_line) + + formatted_credential_text = ' \\\n'.join(formatted_credential_text_lines) + return formatted_credential_text + + +def write_client_credentials( + source_dir, + thing_name='', + client_certificate_pem='', + client_private_key_pem='', + cleanup=False): + + file_to_modify = os.path.join(source_dir, + 'FreeRTOS-Labs', + 'Demo', + 'FreeRTOS_IoT_Libraries', + 'include', + 'aws_iot_demo_profile.h') + file_text = '' + + if cleanup: + filename = "aws_iot_demo_profile_empty.templ" + with open(filename, 'r') as template_file: + file_text = template_file.read() + + else: + endpoint = describe_endpoint() + client_certificate_pem =\ + format_credential_keys_text(client_certificate_pem) + client_private_key_pem =\ + format_credential_keys_text(client_private_key_pem) + + filename = "aws_iot_demo_profile.templ" + with open(filename, 'r') as template_file: + file_text = template_file.read() + file_text = file_text.replace("", + "\"" + endpoint + "\"") + file_text = file_text.replace("", + "\"" + thing_name + "\"") + file_text = file_text.replace("", + client_certificate_pem) + file_text = file_text.replace("", + client_private_key_pem) + + header_file = open(str(file_to_modify), 'w') + header_file.write(file_text) + header_file.close() diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/policy.py b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/policy.py new file mode 100644 index 000000000..6cf13c23b --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/policy.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +import boto3 +import json + + +class Policy(): + def __init__(self, name, policy=''): + self.name = name + self.policy = policy + self.client = boto3.client('iot') + + def create(self): + assert not self.exists(), "Policy already exists" + self.client.create_policy(policyName=self.name, + policyDocument=self.policy) + + def delete(self): + assert self.exists(), "Policy does not exist, cannot be deleted" + self.client.delete_policy(policyName=self.name) + + def exists(self): + policies = self.client.list_policies()['policies'] + for policy in policies: + if self.name == policy['policyName']: + return True + return False diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/policy_document.templ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/policy_document.templ new file mode 100644 index 000000000..05ee373d4 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/policy_document.templ @@ -0,0 +1,25 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "iot:Connect", + "Resource": "arn:aws:iot:::*" + }, + { + "Effect": "Allow", + "Action": "iot:Publish", + "Resource": "arn:aws:iot:::*" + }, + { + "Effect": "Allow", + "Action": "iot:Subscribe", + "Resource": "arn:aws:iot:::*" + }, + { + "Effect": "Allow", + "Action": "iot:Receive", + "Resource": "arn:aws:iot:::*" + } + ] +} \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/thing.py b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/thing.py new file mode 100644 index 000000000..5e63805ab --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/aws_config_quick_start/thing.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +import boto3 +import json + + +class Thing(): + def __init__(self, name): + self.client = boto3.client('iot') + self.name = name + self.arn = '' + + def create(self): + assert not self.exists(), "Thing already exists" + result = self.client.create_thing(thingName=self.name) + self.arn = result['thingArn'] + + def delete(self): + assert self.exists(), "Thing does not exist" + principals = self.list_principals() + for principal in principals: + self.detach_principal(principal) + self.client.delete_thing(thingName=self.name) + + def exists(self): + list_of_things = self.client.list_things()['things'] + for thing in list_of_things: + if thing['thingName'] == self.name: + return True + return False + + def attach_principal(self, arn): + assert self.exists(), "Thing does not exist" + self.client.attach_thing_principal(thingName=self.name, principal=arn) + + def detach_principal(self, arn): + assert self.exists(), "Thing does not exist" + self.client.detach_thing_principal(thingName=self.name, principal=arn) + + def list_principals(self): + assert self.exists(), "Thing does not exist" + principals = self.client.list_thing_principals(thingName=self.name) + principals = principals['principals'] + return principals diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/readme.txt b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/readme.txt new file mode 100644 index 000000000..189de1d05 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/tools/readme.txt @@ -0,0 +1 @@ +This folder contains tools referenced from the instruction documentation. \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/readme.txt b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/readme.txt new file mode 100644 index 000000000..54a6059cc --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/readme.txt @@ -0,0 +1,2 @@ +Contains examples of utility functions that are used by other FreeRTOS IoT +libraries. diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/DemoTasks/SimpleTaskPoolExamples.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/DemoTasks/SimpleTaskPoolExamples.c new file mode 100644 index 000000000..3c8fa0699 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/DemoTasks/SimpleTaskPoolExamples.c @@ -0,0 +1,306 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Standard includes. */ +#include + +/* IoT SDK includes. */ +#include "iot_taskpool_freertos.h" + +/* Demo includes. */ +#include "demo_config.h" + +/* The priority at which that tasks in the task pool (the worker tasks) get +created. */ +#define tpTASK_POOL_WORKER_PRIORITY 1 + +/* + * Prototypes for the functions that demonstrate the task pool API. + * See the implementation of the prvTaskPoolDemoTask() function within this file + * for a description of the individual functions. A configASSERT() is hit if + * any of the demos encounter any unexpected behavior. + */ +static void prvExample_BasicSingleJob( void ); +static void prvExample_DeferredJobAndCancellingJobs( void ); + +/* + * Prototypes of the callback functions used in the examples. The callback + * simply sends a signal (in the form of a direct task notification) to the + * prvTaskPoolDemoTask() task to let the task know that the callback execute. + * The handle of the prvTaskPoolDemoTask() task is not accessed directly, but + * instead passed into the task pool job as the job's context. + */ +static void prvSimpleTaskNotifyCallback( IotTaskPool_t pTaskPool, IotTaskPoolJob_t pJob, void *pUserContext ); + +/* + * The task used to demonstrate the task pool API. This task just loops through + * each demo in turn. + */ +static void prvTaskPoolDemoTask( void *pvParameters ); + +/*-----------------------------------------------------------*/ + +/* Parameters used to create the system task pool - see TBD for more information + * as the task pool used in this example is a slimmed down version of the full + * library - the slimmed down version being intended specifically for FreeRTOS + * kernel use cases. */ +static const IotTaskPoolInfo_t xTaskPoolParameters = { + /* minThreads: + * Minimum number of threads in a task pool. + * Note the slimmed down version of the task + * pool used by this library does not auto-scale + * the number of tasks in the pool so in this + * case this sets the number of tasks in the + * pool. */ + IOT_TASKPOOL_NUMBER_OF_WORKERS, + /* maxThreads: + * Maximum number of threads in a task pool. + * Note the slimmed down version of the task + * pool used by this library does not auto-scale + * the number of tasks in the pool so in this + * case this parameter must match minThreads. */ + IOT_TASKPOOL_NUMBER_OF_WORKERS, + /* Stack size for every task pool thread - in + * bytes, hence multiplying by the number of bytes + * in a word as configMINIMAL_STACK_SIZE is + * specified in words. */ + configMINIMAL_STACK_SIZE * sizeof( portSTACK_TYPE ), + /* Priority for every task pool thread. */ + tpTASK_POOL_WORKER_PRIORITY, + }; + +/*-----------------------------------------------------------*/ + +void vStartSimpleTaskPoolDemo( void ) +{ + /* This example uses a single application task, which in turn is used to + * create and send jobs to task pool tasks. */ + xTaskCreate( prvTaskPoolDemoTask, /* Function that implements the task. */ + "PoolDemo", /* Text name for the task - only used for debugging. */ + democonfigDEMO_STACKSIZE, /* Size of stack (in words, not bytes) to allocate for the task. */ + NULL, /* Task parameter - not used in this case. */ + tskIDLE_PRIORITY, /* Task priority, must be between 0 and configMAX_PRIORITIES - 1. */ + NULL ); /* Used to pass out a handle to the created task - not used in this case. */ +} +/*-----------------------------------------------------------*/ + +static void prvTaskPoolDemoTask( void *pvParameters ) +{ +IotTaskPoolError_t xResult; +uint32_t ulLoops = 0; + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + configPRINTF( ( "---------STARTING DEMO---------\r\n" ) ); + + /* The task pool must be created before it can be used. The system task + * pool is the task pool managed by the task pool library itself - the storage + * used by the task pool is provided by the library. */ + xResult = IotTaskPool_CreateSystemTaskPool( &xTaskPoolParameters ); + configASSERT( xResult == IOT_TASKPOOL_SUCCESS ); + + for( ;; ) + { + /* Demonstrate the most basic use case where a non persistent job is + * created and scheduled to run immediately. The task pool worker tasks + * (in which the job callback function executes) have a priority above the + * priority of this task so the job's callback executes as soon as it is + * scheduled. */ + prvExample_BasicSingleJob(); + + /* Demonstrate a job being scheduled to run at some time in the + * future, and how a job scheduled to run in the future can be canceled + * if it has not yet started executing. */ + prvExample_DeferredJobAndCancellingJobs(); + + ulLoops++; + if( ( ulLoops % 10UL ) == 0 ) + { + configPRINTF( ( "prvTaskPoolDemoTask() performed %u iterations successfully.\r\n", ulLoops ) ); + configPRINTF( ( "Demo completed successfully.\r\n" ) ); + fflush( stdout ); + } + } +} +/*-----------------------------------------------------------*/ + +static void prvSimpleTaskNotifyCallback( IotTaskPool_t pTaskPool, IotTaskPoolJob_t pJob, void *pUserContext ) +{ +/* The jobs context is the handle of the task to which a notification should + * be sent. */ +TaskHandle_t xTaskToNotify = ( TaskHandle_t ) pUserContext; + + /* Remove warnings about unused parameters. */ + ( void ) pTaskPool; + ( void ) pJob; + + /* Notify the task that created this job. */ + xTaskNotifyGive( xTaskToNotify ); +} +/*-----------------------------------------------------------*/ + +static void prvExample_BasicSingleJob( void ) +{ +IotTaskPoolJobStorage_t xJobStorage; +IotTaskPoolJob_t xJob; +IotTaskPoolError_t xResult; +uint32_t ulReturn; +const uint32_t ulNoFlags = 0UL; +const TickType_t xNoDelay = ( TickType_t ) 0; +size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize(); +IotTaskPoolJobStatus_t xJobStatus; + + /* Direct to task notifications are used to communicate between worker tasks + and this task. Don't expect any notifications to be pending before commencing. */ + configASSERT( ulTaskNotifyTake( pdTRUE, xNoDelay ) == 0 ); + + /* Create and schedule a job using the handle of this task as the job's + * context and the function that sends a notification to the task handle as + * the job's callback function. This is not a recyclable job so the storage + * required to hold information about the job is provided by this task - in + * this case the storage is on the stack of this task so no memory is allocated + * dynamically but the stack frame must remain in scope for the lifetime of + * the job. */ + xResult = IotTaskPool_CreateJob( prvSimpleTaskNotifyCallback, /* Callback function. */ + ( void * ) xTaskGetCurrentTaskHandle(), /* Job context. */ + &xJobStorage, + &xJob ); + configASSERT( xResult == IOT_TASKPOOL_SUCCESS ); + + /* The job has been created but not scheduled so is now ready. */ + IotTaskPool_GetStatus( NULL, xJob, &xJobStatus ); + configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_READY ); + + /* This is not a persistent (recyclable) job and its storage is on the + * stack of this function, so the amount of heap space available should not + * have changed since entering this function. */ + configASSERT( xFreeHeapBeforeCreatingJob == xPortGetFreeHeapSize() ); + + /* In the full task pool implementation the first parameter is used to + * pass the handle of the task pool to schedule. The lean task pool + * implementation used in this demo only supports a single task pool, which + * is created internally within the library, so the first parameter is NULL. */ + xResult = IotTaskPool_Schedule( NULL, xJob, ulNoFlags ); + configASSERT( xResult == IOT_TASKPOOL_SUCCESS ); + + /* Look for the notification coming from the job's callback function. The + * priority of the task pool worker task that executes the callback is higher + * than the priority of this task so a block time is not needed - the task pool + * worker task preempts this task and sends the notification (from the job's + * callback) as soon as the job is scheduled. */ + ulReturn = ulTaskNotifyTake( pdTRUE, xNoDelay ); + configASSERT( ulReturn ); + + /* The job's callback has executed so the job has now completed. */ + IotTaskPool_GetStatus( NULL, xJob, &xJobStatus ); + configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_COMPLETED ); +} +/*-----------------------------------------------------------*/ + +static void prvExample_DeferredJobAndCancellingJobs( void ) +{ +IotTaskPoolJobStorage_t xJobStorage; +IotTaskPoolJob_t xJob; +IotTaskPoolError_t xResult; +uint32_t ulReturn; +const uint32_t ulShortDelay_ms = 100UL; +const TickType_t xNoDelay = ( TickType_t ) 0, xAllowableMargin = ( TickType_t ) 5; /* Large margin for Windows port, which is not real time. */ +TickType_t xTimeBefore, xElapsedTime, xShortDelay_ticks; +size_t xFreeHeapBeforeCreatingJob = xPortGetFreeHeapSize(); +IotTaskPoolJobStatus_t xJobStatus; + + /* Don't expect any notifications to be pending yet. */ + configASSERT( ulTaskNotifyTake( pdTRUE, xNoDelay ) == 0 ); + + /* Create a job using the handle of this task as the job's context and the + * function that sends a notification to the task handle as the job's callback + * function. The job is created using storage allocated on the stack of this + * function - so no memory is allocated. */ + xResult = IotTaskPool_CreateJob( prvSimpleTaskNotifyCallback, /* Callback function. */ + ( void * ) xTaskGetCurrentTaskHandle(), /* Job context. */ + &xJobStorage, + &xJob ); + configASSERT( xResult == IOT_TASKPOOL_SUCCESS ); + + /* The job has been created but not scheduled so is now ready. */ + IotTaskPool_GetStatus( NULL, xJob, &xJobStatus ); + configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_READY ); + + /* This is not a persistent (recyclable) job and its storage is on the + * stack of this function, so the amount of heap space available should not + * have changed since entering this function. */ + configASSERT( xFreeHeapBeforeCreatingJob == xPortGetFreeHeapSize() ); + + /* Schedule the job to run its callback in ulShortDelay_ms milliseconds time. + * In the full task pool implementation the first parameter is used to pass the + * handle of the task pool to schedule. The lean task pool implementation used + * in this demo only supports a single task pool, which is created internally + * within the library, so the first parameter is NULL. */ + xResult = IotTaskPool_ScheduleDeferred( NULL, xJob, ulShortDelay_ms ); + configASSERT( xResult == IOT_TASKPOOL_SUCCESS ); + + /* The scheduled job should not have executed yet, so don't expect any + * notifications and expect the job's status to be 'deferred'. */ + ulReturn = ulTaskNotifyTake( pdTRUE, xNoDelay ); + configASSERT( ulReturn == 0 ); + IotTaskPool_GetStatus( NULL, xJob, &xJobStatus ); + configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_DEFERRED ); + + /* As the job has not yet been executed it can be canceled. */ + xResult = IotTaskPool_TryCancel( NULL, xJob, &xJobStatus ); + configASSERT( xResult == IOT_TASKPOOL_SUCCESS ); + IotTaskPool_GetStatus( NULL, xJob, &xJobStatus ); + configASSERT( xJobStatus == IOT_TASKPOOL_STATUS_CANCELED ); + + /* Schedule the job again, and this time wait until its callback is + * executed (the callback function sends a notification to this task) to see + * that it executes at the right time. */ + xTimeBefore = xTaskGetTickCount(); + xResult = IotTaskPool_ScheduleDeferred( NULL, xJob, ulShortDelay_ms ); + configASSERT( xResult == IOT_TASKPOOL_SUCCESS ); + + /* Wait twice the deferred execution time to ensure the callback is executed + * before the call below times out. */ + ulReturn = ulTaskNotifyTake( pdTRUE, pdMS_TO_TICKS( ulShortDelay_ms * 2UL ) ); + xElapsedTime = xTaskGetTickCount() - xTimeBefore; + + /* A single notification should have been received... */ + configASSERT( ulReturn == 1 ); + + /* ...and the time since scheduling the job should be greater than or + * equal to the deferred execution time - which is converted to ticks for + * comparison. */ + xShortDelay_ticks = pdMS_TO_TICKS( ulShortDelay_ms ); + configASSERT( ( xElapsedTime >= xShortDelay_ticks ) && ( xElapsedTime < ( xShortDelay_ticks + xAllowableMargin ) ) ); +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/FreeRTOSConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/FreeRTOSConfig.h new file mode 100644 index 000000000..8ec7ee00f --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/FreeRTOSConfig.h @@ -0,0 +1,208 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * http://www.freertos.org/a00110.html + * + * The bottom of this file contains some constants specific to running the UDP + * stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than + * the demo) are contained in FreeRTOSIPConfig.h. + *----------------------------------------------------------*/ +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 0 +#define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Run time stats gathering definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_pcTaskGetTaskName 1 + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS +is set to 2 so the formatting functions are included without the stdio.h being +included in tasks.c. That is because this project defines its own sprintf() +functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* Assert call defined for debug builds. */ +#ifdef _DEBUG + extern void vAssertCalled( const char *pcFile, uint32_t ulLine ); + #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) +#endif /* _DEBUG */ + + + +/* Application specific definitions follow. **********************************/ + +/* Only used when running in the FreeRTOS Windows simulator. Defines the +priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet +or WiFi data to and from a real network connection. Many computers have more +than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell +the demo which real port should be used to create the virtual port. The ports +available are displayed on the console when the application is executed. For +example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 +results in the wired network being used, while setting +configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being +used. */ +#define configNETWORK_INTERFACE_TO_USE 4L + +/* The address of an echo server that will be used by the two demo echo client +tasks. +http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Clients.html +http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_Echo_Clients.html */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 0 +#define configECHO_SERVER_ADDR3 11 + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet/WiFi data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition above for information on how to +configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x22 +#define configMAC_ADDR3 0x33 +#define configMAC_ADDR4 0x44 +#define configMAC_ADDR5 0x41 + +/* Default IP address configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 10 +#define configIP_ADDR1 10 +#define configIP_ADDR2 10 +#define configIP_ADDR3 200 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DNS is set to +0, or ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 10 +#define configGATEWAY_ADDR1 10 +#define configGATEWAY_ADDR2 10 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. OpenDNS addresses are 208.67.222.222 and +208.67.220.220. Used in ipconfigUSE_DNS is set to 0, or ipconfigUSE_DNS is set +to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 208 +#define configDNS_SERVER_ADDR1 67 +#define configDNS_SERVER_ADDR2 222 +#define configDNS_SERVER_ADDR3 222 + +/* Default netmask configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 0 +#define configNET_MASK2 0 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#if( defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) && !defined( snprintf ) ) + /* Map to Windows names. */ + #define snprintf _snprintf + #define vsnprintf _vsnprintf +#endif + +/* Visual studio does not have an implementation of strcasecmp(). */ +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define strcmpi _strcmpi + +#define configPRINTF( X ) printf X + +#endif /* FREERTOS_CONFIG_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/FreeRTOSIPConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/FreeRTOSIPConfig.h new file mode 100644 index 000000000..11f8f00b9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/FreeRTOSIPConfig.h @@ -0,0 +1,307 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +/***************************************************************************** + * + * See the following URL for configuration information. + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html + * + *****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to +1 then FreeRTOS_debug_printf should be defined to the function used to print +out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 0 +#if( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf(X) vLoggingPrintf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the +FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 +then FreeRTOS_printf should be set to the function used to print out the +messages. */ +#define ipconfigHAS_PRINTF 0 +#if( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf(X) vLoggingPrintf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing +on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading (IP/TCP/UDP checksums) +then set ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software +stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 + +/* Several API's will block until the result is known, or the action has been +performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be +set per socket, using setsockopt(). If not set, the times below will be +used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 5000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for LLMNR: Link-local Multicast Name Resolution +(non-Microsoft) */ +#define ipconfigUSE_LLMNR ( 0 ) + +/* Include support for NBNS: NetBIOS Name Service (Microsoft) */ +#define ipconfigUSE_NBNS ( 0 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very +useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low +and also DNS may use small timeouts. If a DNS reply comes in after the DNS +socket has been destroyed, the result will be stored into the cache. The next +call to FreeRTOS_gethostbyname() will return immediately, without even creating +a socket. */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_NAME_LENGTH ( 16 ) +#define ipconfigDNS_CACHE_ENTRIES ( 4 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make +use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY +sets the priority of the task that executes the IP stack. The priority is a +standard FreeRTOS task priority so can take any value from 0 (the lowest +priority) to (configMAX_PRIORITIES - 1) (the highest priority). +configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in +FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to +the priority assigned to the task executing the IP stack relative to the +priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP +task. This setting is less important when the FreeRTOS Win32 simulator is used +as the Win32 simulator only stores a fixed amount of information on the task +stack. FreeRTOS includes optional stack overflow detection, see: +http://www.freertos.org/Stacks-and-stack-overflow-checking.html */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* ipconfigRAND32() is called by the IP stack to generate random numbers for +things such as a DHCP transaction number or initial sequence number. Random +number generation is performed via this macro to allow applications to use their +own random number generation method. For example, it might be possible to +generate a random number by sampling noise on an analogue input. */ +extern UBaseType_t uxRand(); +#define ipconfigRAND32() uxRand() + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the +network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK +is not set to 1 then the network event hook will never be called. See +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml +*/ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but +a network buffer cannot be obtained then the calling task is held in the Blocked +state (so other tasks can continue to executed) until either a network buffer +becomes available or the send block time expires. If the send block time expires +then the send operation is aborted. The maximum allowable send block time is +capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the +maximum allowable send block time prevents prevents a deadlock occurring when +all the network buffers are in use and the tasks that process (and subsequently +free) the network buffers are themselves blocked waiting for a network buffer. +ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in +milliseconds can be converted to a time in ticks by dividing the time in +milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP +address, netmask, DNS server address and gateway address from a DHCP server. If +ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The +stack will revert to using the static IP address even when ipconfigUSE_DHCP is +set to 1 if a valid configuration cannot be obtained from a DHCP server for any +reason. The static configuration used is that passed into the stack by the +FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 0 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at +increasing time intervals until either a reply is received from a DHCP server +and accepted, or the interval between transmissions reaches +ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the +static IP address passed as a parameter to FreeRTOS_IPInit() if the +re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without +a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( 120000 / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP +stack can only send a UDP message to a remove IP address if it knowns the MAC +address associated with the IP address, or the MAC address of the router used to +contact the remote IP address. When a UDP message is received from a remote IP +address the MAC address and IP address are added to the ARP cache. When a UDP +message is sent to a remote IP address that does not already appear in the ARP +cache then the UDP message is replaced by a ARP message that solicits the +required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum +number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a +maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is +aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP +table being created or refreshed and the entry being removed because it is stale. +New ARP requests are sent for ARP cache entries that are nearing their maximum +age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is +equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling +routines, which are relatively large. To save code space the full +FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster +alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() +takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. +FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets +(for example, 192, 168, 0, 1) as its parameters. If +ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and +FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is +not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that +are available to the IP stack. The total number of network buffers is limited +to ensure the total amount of RAM that can be consumed by the IP stack is capped +to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP +stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can +be queued for processing at any one time. The event queue must be a minimum of +5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port +number. FreeRTOS_bind() is used to manually allocate a port number to a socket +(to 'bind' the socket to a port), but manual binding is not normally necessary +for client sockets (those sockets that initiate outgoing connections rather than +wait for incoming connections on a known port number). If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling +FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP +stack automatically binding the socket to a port number from the range +socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() +on a socket that has not yet been bound will result in the send operation being +aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +#define ipconfigTCP_TIME_TO_LIVE 128 /* also defined in FreeRTOSIPConfigDefaults.h */ + +/* USE_TCP: Use TCP and all its features */ +#define ipconfigUSE_TCP ( 1 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can +contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a +lower value can save RAM, depending on the buffer management scheme used. If +ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must +be divisible by 8. */ +#define ipconfigNETWORK_MTU 1200 + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used +through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will +generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the +FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 0 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() +(and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames +that are not in Ethernet II format will be dropped. This option is included for +potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the +responsibility of the Ethernet interface to filter out packets that are of no +interest. If the Ethernet interface does not implement this functionality, then +set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack +perform the filtering instead (it is much less efficient for the stack to do it +because the packet will already have been passed into the stack). If the +Ethernet driver does all the necessary filtering in hardware then software +filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to +block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with +32-bit memory instructions, all packets will be stored 32-bit-aligned, plus 16-bits. +This has to do with the contents of the IP-packets: all 32-bit fields are +32-bit-aligned, plus 16-bit(!) */ +#define ipconfigPACKET_FILLER_SIZE 2 + +/* Define the size of the pool of TCP window descriptors. On the average, each +TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 +outstanding packets (for Rx and Tx). When using up to 10 TP sockets +simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed +maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 1000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 1000 ) + +/* When using call-back handlers, the driver may check if the handler points to +real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS(x) ( (x) != NULL ) + +/* Include support for TCP hang protection. All sockets in a connecting or +disconnecting stage will timeout after a period of non-activity. */ +#define ipconfigTCP_HANG_PROTECTION ( 1 ) +#define ipconfigTCP_HANG_PROTECTION_TIME ( 30 ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* in seconds */ + +#define portINLINE __inline + +#endif /* FREERTOS_IP_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/READ_ME_INSTRUCTIONS.url b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/READ_ME_INSTRUCTIONS.url new file mode 100644 index 000000000..c00147b27 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/READ_ME_INSTRUCTIONS.url @@ -0,0 +1,6 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/task-pool/ +HotKey=0 diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WIN32.vcxproj b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WIN32.vcxproj new file mode 100644 index 000000000..fb0511841 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WIN32.vcxproj @@ -0,0 +1,209 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {C686325E-3261-42F7-AEB1-DDE5280E1CEB} + RTOSDemo + 10.0 + + + + Application + false + MultiByte + v142 + + + Application + false + MultiByte + v142 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Debug\ + .\Debug\ + true + .\Release\ + .\Release\ + false + AllRules.ruleset + + + + .\Debug/WIN32.tlb + + + + + Disabled + ..\..\..\..\Source\FreeRTOS-Plus-TCP\include;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;..\..\..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;.\DemoTasks\include;.\WinPCap;..\..\..\..\..\FreeRTOS\Source\include;..\..\..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\include;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\platform;..\..\..\..\Source\FreeRTOS-IoT-Libraries\c_sdk\standard\common\src;..\..\..\..\Source\FreeRTOS-IoT-Libraries\abstractions\platform\freertos\include;.;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDLL + .\Debug/WIN32.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level4 + true + false + EditAndContinue + /wd4210 /wd4127 /wd4214 /wd4201 /wd4244 /wd4310 %(AdditionalOptions) + true + NotUsing + false + CompileAsC + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Debug/RTOSDemo.exe + true + true + .\Debug/WIN32.pdb + Console + MachineX86 + wpcap.lib;%(AdditionalDependencies) + .\WinPCap + false + false + + + true + .\Debug/WIN32.bsc + + + + + .\Release/WIN32.tlb + + + + + MaxSpeed + OnlyExplicitInline + _WINSOCKAPI_;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release/WIN32.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + ..\Common\Utils;..\Common\ethernet\lwip-1.4.0\ports\win32\WinPCap;..\Common\ethernet\lwip-1.4.0\src\include\ipv4;..\Common\ethernet\lwip-1.4.0\src\include;..\..\..\Source\include;..\..\..\Source\portable\MSVC-MingW;..\Common\ethernet\lwip-1.4.0\ports\win32\include;..\Common\Include;.\lwIP_Apps;.;%(AdditionalIncludeDirectories) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Release/RTOSDemo.exe + true + .\Release/WIN32.pdb + Console + MachineX86 + ..\Common\ethernet\lwip-1.4.0\ports\win32\WinPCap + wpcap.lib;%(AdditionalDependencies) + + + true + .\Release/WIN32.bsc + + + + + + + + + + + + + + + + + + + + + + + + + + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WIN32.vcxproj.filters b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WIN32.vcxproj.filters new file mode 100644 index 000000000..83e7248fd --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WIN32.vcxproj.filters @@ -0,0 +1,244 @@ + + + + + {af3445a1-4908-4170-89ed-39345d90d30c} + + + {f32be356-4763-4cae-9020-974a2638cb08} + *.c + + + {88f409e6-d396-4ac5-94bd-7a99c914be46} + + + {e5ad4ec7-23dc-4295-8add-2acaee488f5a} + + + {d2dcd641-8d91-492b-852f-5563ffadaec6} + + + {8672fa26-b119-481f-8b8d-086419c01a3e} + + + {4570be11-ec96-4b55-ac58-24b50ada980a} + + + {5d93ed51-023a-41ad-9243-8d230165d34b} + + + {b71e974a-9f28-4815-972b-d930ba8a34d0} + + + {60717407-397f-4ea5-8492-3314acdd25f0} + + + {8a90222f-d723-4b4e-8e6e-c57afaf7fa92} + + + {7c995f05-2a10-4771-ad77-18a755876e46} + + + {9a636cc3-ebc6-48c5-8c18-c72494686e81} + + + {29376c48-bc8b-4624-ad59-16807874c9f2} + + + {91ef4008-de51-4b41-ba5e-bf24d8cda378} + + + {ade43c6c-04c5-4897-abdb-91af2df04e5d} + + + {08a4e35c-19ca-4b1e-af24-bac368c2bf7b} + + + {1e324500-91b4-4c76-b699-59ba75691760} + + + {bdcbc1ec-99b8-4c72-9075-49035c115488} + + + {35ce7745-52a2-4220-be31-50dfaa35c0ab} + + + {937ccdd7-efee-403e-8c6d-c75e73586637} + + + {12727ead-3037-4a6d-9679-b326a231a353} + + + {59a372b1-477a-4640-a097-73e2b6c2f1b4} + + + + + FreeRTOS\Source\Portable + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS\Source + + + FreeRTOS\Source\Portable + + + + FreeRTOS+\FreeRTOS+TCP + + + + DemoTasks + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\src + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\common\include + + + + FreeRTOS+\FreeRTOS IoT Libraries\abstractions\platform\freertos\include\platform\types + + + FreeRTOS+\FreeRTOS IoT Libraries\standard\platform\types + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/Packet32.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/Packet32.h new file mode 100644 index 000000000..1e0eacd77 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/Packet32.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + +/** @ingroup packetapi + * @{ + */ + +/** @defgroup packet32h Packet.dll definitions and data structures + * Packet32.h contains the data structures and the definitions used by packet.dll. + * The file is used both by the Win9x and the WinNTx versions of packet.dll, and can be included + * by the applications that use the functions of this library + * @{ + */ + +#ifndef __PACKET32 +#define __PACKET32 + +#include + +#ifdef HAVE_AIRPCAP_API +#include +#else +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +typedef struct _AirpcapHandle *PAirpcapHandle; +#endif /* AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ */ +#endif /* HAVE_AIRPCAP_API */ + +#ifdef HAVE_DAG_API +#include +#endif /* HAVE_DAG_API */ + +// Working modes +#define PACKET_MODE_CAPT 0x0 ///< Capture mode +#define PACKET_MODE_STAT 0x1 ///< Statistical mode +#define PACKET_MODE_MON 0x2 ///< Monitoring mode +#define PACKET_MODE_DUMP 0x10 ///< Dump mode +#define PACKET_MODE_STAT_DUMP MODE_DUMP | MODE_STAT ///< Statistical dump Mode + + +/// Alignment macro. Defines the alignment size. +#define Packet_ALIGNMENT sizeof(int) +/// Alignment macro. Rounds up to the next even multiple of Packet_ALIGNMENT. +#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1)) + +#define NdisMediumNull -1 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumCHDLC -2 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPPPSerial -3 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumBare80211 -4 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumRadio80211 -5 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPpi -6 ///< Custom linktype: NDIS doesn't provide an equivalent + +// Loopback behaviour definitions +#define NPF_DISABLE_LOOPBACK 1 ///< Drop the packets sent by the NPF driver +#define NPF_ENABLE_LOOPBACK 2 ///< Capture the packets sent by the NPF driver + +/*! + \brief Network type structure. + + This structure is used by the PacketGetNetType() function to return information on the current adapter's type and speed. +*/ +typedef struct NetType +{ + UINT LinkType; ///< The MAC of the current network adapter (see function PacketGetNetType() for more information) + ULONGLONG LinkSpeed; ///< The speed of the network in bits per second +}NetType; + + +//some definitions stolen from libpcap + +#ifndef BPF_MAJOR_VERSION + +/*! + \brief A BPF pseudo-assembly program. + + The program will be injected in the kernel by the PacketSetBPF() function and applied to every incoming packet. +*/ +struct bpf_program +{ + UINT bf_len; ///< Indicates the number of instructions of the program, i.e. the number of struct bpf_insn that will follow. + struct bpf_insn *bf_insns; ///< A pointer to the first instruction of the program. +}; + +/*! + \brief A single BPF pseudo-instruction. + + bpf_insn contains a single instruction for the BPF register-machine. It is used to send a filter program to the driver. +*/ +struct bpf_insn +{ + USHORT code; ///< Instruction type and addressing mode. + UCHAR jt; ///< Jump if true + UCHAR jf; ///< Jump if false + int k; ///< Generic field used for various purposes. +}; + +/*! + \brief Structure that contains a couple of statistics values on the current capture. + + It is used by packet.dll to return statistics about a capture session. +*/ +struct bpf_stat +{ + UINT bs_recv; ///< Number of packets that the driver received from the network adapter + ///< from the beginning of the current capture. This value includes the packets + ///< lost by the driver. + UINT bs_drop; ///< number of packets that the driver lost from the beginning of a capture. + ///< Basically, a packet is lost when the the buffer of the driver is full. + ///< In this situation the packet cannot be stored and the driver rejects it. + UINT ps_ifdrop; ///< drops by interface. XXX not yet supported + UINT bs_capt; ///< number of packets that pass the filter, find place in the kernel buffer and + ///< thus reach the application. +}; + +/*! + \brief Packet header. + + This structure defines the header associated with every packet delivered to the application. +*/ +struct bpf_hdr +{ + struct timeval bh_tstamp; ///< The timestamp associated with the captured packet. + ///< It is stored in a TimeVal structure. + UINT bh_caplen; ///< Length of captured portion. The captured portion can be different + ///< from the original packet, because it is possible (with a proper filter) + ///< to instruct the driver to capture only a portion of the packets. + UINT bh_datalen; ///< Original length of packet + USHORT bh_hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases, + ///< a padding could be added between the end of this structure and the packet + ///< data for performance reasons. This filed can be used to retrieve the actual data + ///< of the packet. +}; + +/*! + \brief Dump packet header. + + This structure defines the header associated with the packets in a buffer to be used with PacketSendPackets(). + It is simpler than the bpf_hdr, because it corresponds to the header associated by WinPcap and libpcap to a + packet in a dump file. This makes straightforward sending WinPcap dump files to the network. +*/ +struct dump_bpf_hdr{ + struct timeval ts; ///< Time stamp of the packet + UINT caplen; ///< Length of captured portion. The captured portion can smaller than the + ///< the original packet, because it is possible (with a proper filter) to + ///< instruct the driver to capture only a portion of the packets. + UINT len; ///< Length of the original packet (off wire). +}; + + +#endif + +struct bpf_stat; + +#define DOSNAMEPREFIX TEXT("Packet_") ///< Prefix added to the adapters device names to create the WinPcap devices +#define MAX_LINK_NAME_LENGTH 64 //< Maximum length of the devices symbolic links +#define NMAX_PACKET 65535 + +/*! + \brief Addresses of a network adapter. + + This structure is used by the PacketGetNetInfoEx() function to return the IP addresses associated with + an adapter. +*/ +typedef struct npf_if_addr { + struct sockaddr_storage IPAddress; ///< IP address. + struct sockaddr_storage SubnetMask; ///< Netmask for that address. + struct sockaddr_storage Broadcast; ///< Broadcast address. +}npf_if_addr; + + +#define ADAPTER_NAME_LENGTH 256 + 12 ///< Maximum length for the name of an adapter. The value is the same used by the IP Helper API. +#define ADAPTER_DESC_LENGTH 128 ///< Maximum length for the description of an adapter. The value is the same used by the IP Helper API. +#define MAX_MAC_ADDR_LENGTH 8 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. +#define MAX_NETWORK_ADDRESSES 16 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. + + +typedef struct WAN_ADAPTER_INT WAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API +typedef WAN_ADAPTER *PWAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API + +#define INFO_FLAG_NDIS_ADAPTER 0 ///< Flag for ADAPTER_INFO: this is a traditional ndis adapter +#define INFO_FLAG_NDISWAN_ADAPTER 1 ///< Flag for ADAPTER_INFO: this is a NdisWan adapter, and it's managed by WANPACKET +#define INFO_FLAG_DAG_CARD 2 ///< Flag for ADAPTER_INFO: this is a DAG card +#define INFO_FLAG_DAG_FILE 6 ///< Flag for ADAPTER_INFO: this is a DAG file +#define INFO_FLAG_DONT_EXPORT 8 ///< Flag for ADAPTER_INFO: when this flag is set, the adapter will not be listed or openend by winpcap. This allows to prevent exporting broken network adapters, like for example FireWire ones. +#define INFO_FLAG_AIRPCAP_CARD 16 ///< Flag for ADAPTER_INFO: this is an airpcap card +#define INFO_FLAG_NPFIM_DEVICE 32 + +/*! + \brief Describes an opened network adapter. + + This structure is the most important for the functioning of packet.dll, but the great part of its fields + should be ignored by the user, since the library offers functions that avoid to cope with low-level parameters +*/ +typedef struct _ADAPTER { + HANDLE hFile; ///< \internal Handle to an open instance of the NPF driver. + CHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; ///< \internal A string containing the name of the network adapter currently opened. + int NumWrites; ///< \internal Number of times a packets written on this adapter will be repeated + ///< on the wire. + HANDLE ReadEvent; ///< A notification event associated with the read calls on the adapter. + ///< It can be passed to standard Win32 functions (like WaitForSingleObject + ///< or WaitForMultipleObjects) to wait until the driver's buffer contains some + ///< data. It is particularly useful in GUI applications that need to wait + ///< concurrently on several events. In Windows NT/2000 the PacketSetMinToCopy() + ///< function can be used to define the minimum amount of data in the kernel buffer + ///< that will cause the event to be signalled. + + UINT ReadTimeOut; ///< \internal The amount of time after which a read on the driver will be released and + ///< ReadEvent will be signaled, also if no packets were captured + CHAR Name[ADAPTER_NAME_LENGTH]; + PWAN_ADAPTER pWanAdapter; + UINT Flags; ///< Adapter's flags. Tell if this adapter must be treated in a different way, using the Netmon API or the dagc API. + +#ifdef HAVE_AIRPCAP_API + PAirpcapHandle AirpcapAd; +#endif // HAVE_AIRPCAP_API + +#ifdef HAVE_NPFIM_API + void* NpfImHandle; +#endif // HAVE_NPFIM_API + +#ifdef HAVE_DAG_API + dagc_t *pDagCard; ///< Pointer to the dagc API adapter descriptor for this adapter + PCHAR DagBuffer; ///< Pointer to the buffer with the packets that is received from the DAG card + struct timeval DagReadTimeout; ///< Read timeout. The dagc API requires a timeval structure + unsigned DagFcsLen; ///< Length of the frame check sequence attached to any packet by the card. Obtained from the registry + DWORD DagFastProcess; ///< True if the user requests fast capture processing on this card. Higher level applications can use this value to provide a faster but possibly unprecise capture (for example, libpcap doesn't convert the timestamps). +#endif // HAVE_DAG_API +} ADAPTER, *LPADAPTER; + +/*! + \brief Structure that contains a group of packets coming from the driver. + + This structure defines the header associated with every packet delivered to the application. +*/ +typedef struct _PACKET { + HANDLE hEvent; ///< \deprecated Still present for compatibility with old applications. + OVERLAPPED OverLapped; ///< \deprecated Still present for compatibility with old applications. + PVOID Buffer; ///< Buffer with containing the packets. See the PacketReceivePacket() for + ///< details about the organization of the data in this buffer + UINT Length; ///< Length of the buffer + DWORD ulBytesReceived; ///< Number of valid bytes present in the buffer, i.e. amount of data + ///< received by the last call to PacketReceivePacket() + BOOLEAN bIoComplete; ///< \deprecated Still present for compatibility with old applications. +} PACKET, *LPPACKET; + +/*! + \brief Structure containing an OID request. + + It is used by the PacketRequest() function to send an OID to the interface card driver. + It can be used, for example, to retrieve the status of the error counters on the adapter, its MAC address, + the list of the multicast groups defined on it, and so on. +*/ +struct _PACKET_OID_DATA { + ULONG Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h + ///< for a complete list of valid codes. + ULONG Length; ///< Length of the data field + UCHAR Data[1]; ///< variable-lenght field that contains the information passed to or received + ///< from the adapter. +}; +typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @} + */ + +/* +BOOLEAN QueryWinPcapRegistryStringA(CHAR *SubKeyName, + CHAR *Value, + UINT *pValueLen, + CHAR *DefaultVal); + +BOOLEAN QueryWinPcapRegistryStringW(WCHAR *SubKeyName, + WCHAR *Value, + UINT *pValueLen, + WCHAR *DefaultVal); +*/ + +//--------------------------------------------------------------------------- +// EXPORTED FUNCTIONS +//--------------------------------------------------------------------------- + +PCHAR PacketGetVersion(); +PCHAR PacketGetDriverVersion(); +BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes); +BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites); +BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode); +BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout); +BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp); +BOOLEAN PacketSetLoopbackBehavior(LPADAPTER AdapterObject, UINT LoopbackBehavior); +INT PacketSetSnapLen(LPADAPTER AdapterObject,int snaplen); +BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim); +BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type); +LPADAPTER PacketOpenAdapter(PCHAR AdapterName); +BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync); +INT PacketSendPackets(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync); +LPPACKET PacketAllocatePacket(void); +VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length); +VOID PacketFreePacket(LPPACKET lpPacket); +BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync); +BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter); +BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize); +BOOLEAN PacketGetNetInfoEx(PCHAR AdapterName, npf_if_addr* buffer, PLONG NEntries); +BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData); +HANDLE PacketGetReadEvent(LPADAPTER AdapterObject); +BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len); +BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks); +BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync); +BOOL PacketStopDriver(); +VOID PacketCloseAdapter(LPADAPTER lpAdapter); +BOOLEAN PacketStartOem(PCHAR errorString, UINT errorStringLength); +BOOLEAN PacketStartOemEx(PCHAR errorString, UINT errorStringLength, ULONG flags); +PAirpcapHandle PacketGetAirPcapHandle(LPADAPTER AdapterObject); + +// +// Used by PacketStartOemEx +// +#define PACKET_START_OEM_NO_NETMON 0x00000001 + +#ifdef __cplusplus +} +#endif + +#endif //__PACKET32 diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/PacketData.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/PacketData.h new file mode 100644 index 000000000..8124db66d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/PacketData.h @@ -0,0 +1,267 @@ +char pkt1[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x30, 0x09, 0x9c, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x07, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x35, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02, +0x40, 0x00, 0xdf, 0xab, 0x00, 0x00, 0x02, 0x04, +0x05, 0xb4, 0x01, 0x01, 0x04, 0x02 }; + +char pkt2[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa6, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt3[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0x9e, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x0d, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt4[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x02, 0x27, 0x09, 0x9f, 0x40, 0x00, 0x80, 0x06, +0x6d, 0x0d, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x18, +0x42, 0xd8, 0x84, 0x3e, 0x00, 0x00, 0x47, 0x45, +0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, +0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, +0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x2c, +0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, +0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, +0x2c, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, +0x6a, 0x70, 0x65, 0x67, 0x2c, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x70, 0x6a, 0x70, 0x65, +0x67, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, +0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, +0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, +0x63, 0x65, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c, +0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, +0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, +0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20, +0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, +0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, +0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70, +0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, +0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78, +0x62, 0x61, 0x70, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, +0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d, +0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, +0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, +0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, +0x20, 0x65, 0x6e, 0x2d, 0x67, 0x62, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, +0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, +0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64, +0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x0d, 0x0a, +0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, +0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69, +0x6c, 0x6c, 0x61, 0x2f, 0x34, 0x2e, 0x30, 0x20, +0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, +0x62, 0x6c, 0x65, 0x3b, 0x20, 0x4d, 0x53, 0x49, +0x45, 0x20, 0x36, 0x2e, 0x30, 0x3b, 0x20, 0x57, +0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e, +0x54, 0x20, 0x35, 0x2e, 0x31, 0x3b, 0x20, 0x53, +0x56, 0x31, 0x3b, 0x20, 0x47, 0x6f, 0x6f, 0x67, +0x6c, 0x65, 0x54, 0x35, 0x3b, 0x20, 0x2e, 0x4e, +0x45, 0x54, 0x20, 0x43, 0x4c, 0x52, 0x20, 0x32, +0x2e, 0x30, 0x2e, 0x35, 0x30, 0x37, 0x32, 0x37, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30, +0x34, 0x35, 0x30, 0x36, 0x2e, 0x36, 0x34, 0x38, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x35, 0x2e, 0x32, +0x31, 0x30, 0x32, 0x32, 0x29, 0x0d, 0x0a, 0x48, +0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, +0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31, +0x32, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, +0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b, +0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, +0x65, 0x0d, 0x0a, 0x0d, 0x0a }; + +char pkt5[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x02, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa5, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt6[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa1, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x0a, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt7[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x02, 0x27, 0x09, 0xa2, 0x40, 0x00, 0x80, 0x06, +0x6d, 0x0a, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x18, +0x42, 0xd8, 0x84, 0x3e, 0x00, 0x00, 0x47, 0x45, +0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, +0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, +0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x2c, +0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, +0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, +0x2c, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, +0x6a, 0x70, 0x65, 0x67, 0x2c, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x70, 0x6a, 0x70, 0x65, +0x67, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, +0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, +0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, +0x63, 0x65, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c, +0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, +0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, +0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20, +0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, +0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, +0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70, +0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, +0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78, +0x62, 0x61, 0x70, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, +0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d, +0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, +0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, +0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, +0x20, 0x65, 0x6e, 0x2d, 0x67, 0x62, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, +0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, +0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64, +0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x0d, 0x0a, +0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, +0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69, +0x6c, 0x6c, 0x61, 0x2f, 0x34, 0x2e, 0x30, 0x20, +0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, +0x62, 0x6c, 0x65, 0x3b, 0x20, 0x4d, 0x53, 0x49, +0x45, 0x20, 0x36, 0x2e, 0x30, 0x3b, 0x20, 0x57, +0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e, +0x54, 0x20, 0x35, 0x2e, 0x31, 0x3b, 0x20, 0x53, +0x56, 0x31, 0x3b, 0x20, 0x47, 0x6f, 0x6f, 0x67, +0x6c, 0x65, 0x54, 0x35, 0x3b, 0x20, 0x2e, 0x4e, +0x45, 0x54, 0x20, 0x43, 0x4c, 0x52, 0x20, 0x32, +0x2e, 0x30, 0x2e, 0x35, 0x30, 0x37, 0x32, 0x37, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30, +0x34, 0x35, 0x30, 0x36, 0x2e, 0x36, 0x34, 0x38, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x35, 0x2e, 0x32, +0x31, 0x30, 0x32, 0x32, 0x29, 0x0d, 0x0a, 0x48, +0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, +0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31, +0x32, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, +0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b, +0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, +0x65, 0x0d, 0x0a, 0x0d, 0x0a }; + +char pkt8[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x03, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa4, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt9[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa3, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x08, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt10[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x04, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa3, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt11[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa6, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x05, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt12[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa7, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x04, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x14, +0x00, 0x00, 0x43, 0xf4, 0x00, 0x00 }; + + +typedef struct +{ + char *pcData; + int iDataLen; +} xPacketData; + +xPacketData xAllPackets[] = +{ + { pkt1, sizeof( pkt1 ) }, +// { pkt2, sizeof( pkt2 ) }, + { pkt3, sizeof( pkt3 ) }, + { pkt4, sizeof( pkt4 ) }, +// { pkt5, sizeof( pkt5 ) }, + { pkt6, sizeof( pkt6 ) }, + { pkt7, sizeof( pkt7 ) }, + { pkt8, sizeof( pkt8 ) }, + { pkt9, sizeof( pkt9 ) }, + { pkt10, sizeof( pkt10 ) }, +// { pkt11, sizeof( pkt11 ) }, +// { pkt12, sizeof( pkt12 ) }, +// { pkt13, sizeof( pkt13 ) }, +// { pkt14, sizeof( pkt14 ) }, +// { pkt15, sizeof( pkt15 ) }, +// { pkt16, sizeof( pkt16 ) }, +}; diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/Win32-Extensions.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/Win32-Extensions.h new file mode 100644 index 000000000..be71c85e9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/Win32-Extensions.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + + +#ifndef __WIN32_EXTENSIONS_H__ +#define __WIN32_EXTENSIONS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Definitions */ + +/*! + \brief A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit(). +*/ +struct pcap_send_queue +{ + u_int maxlen; ///< Maximum size of the the queue, in bytes. This variable contains the size of the buffer field. + u_int len; ///< Current size of the queue, in bytes. + char *buffer; ///< Buffer containing the packets to be sent. +}; + +typedef struct pcap_send_queue pcap_send_queue; + +/*! + \brief This typedef is a support for the pcap_get_airpcap_handle() function +*/ +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +typedef struct _AirpcapHandle *PAirpcapHandle; +#endif + +#define BPF_MEM_EX_IMM 0xc0 +#define BPF_MEM_EX_IND 0xe0 + +/*used for ST*/ +#define BPF_MEM_EX 0xc0 +#define BPF_TME 0x08 + +#define BPF_LOOKUP 0x90 +#define BPF_EXECUTE 0xa0 +#define BPF_INIT 0xb0 +#define BPF_VALIDATE 0xc0 +#define BPF_SET_ACTIVE 0xd0 +#define BPF_RESET 0xe0 +#define BPF_SET_MEMORY 0x80 +#define BPF_GET_REGISTER_VALUE 0x70 +#define BPF_SET_REGISTER_VALUE 0x60 +#define BPF_SET_WORKING 0x50 +#define BPF_SET_ACTIVE_READ 0x40 +#define BPF_SET_AUTODELETION 0x30 +#define BPF_SEPARATION 0xff + +/* Prototypes */ +pcap_send_queue* pcap_sendqueue_alloc(u_int memsize); + +void pcap_sendqueue_destroy(pcap_send_queue* queue); + +int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data); + +u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync); + +HANDLE pcap_getevent(pcap_t *p); + +struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size); + +int pcap_setuserbuffer(pcap_t *p, int size); + +int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks); + +int pcap_live_dump_ended(pcap_t *p, int sync); + +int pcap_offline_filter(struct bpf_program *prog, const struct pcap_pkthdr *header, const u_char *pkt_data); + +int pcap_start_oem(char* err_str, int flags); + +PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p); + +#ifdef __cplusplus +} +#endif + +#endif //__WIN32_EXTENSIONS_H__ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/arch.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/arch.c new file mode 100644 index 000000000..02bf82bf9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/arch.c @@ -0,0 +1,336 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* WinPCap includes. */ +#include "pcap.h" +#include "remote-ext.h" + +/* uIP includes. */ +#include "net/uip.h" +#include "net/uip_arp.h" +#include "net/clock-arch.h" + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* + * Query the computer the simulation is being executed on to find the network + * interfaces it has installed. + */ +static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ); + +/* + * Open the network interface. The number of the interface to be opened is set + * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. + */ +static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ); + +/* + * Configure the capture filter to allow blocking reads, and to filter out + * packets that are not of interest to this demo. + */ +static void prvConfigureCaptureBehaviour( void ); + +pcap_t *pxOpenedInterfaceHandle = NULL; +LARGE_INTEGER freq, sys_start_time; + +#define archNUM_BUFFERS 5 +#define archNUM_BUFFER_POINTERS ( archNUM_BUFFERS - 1 ) + +static void prvInterruptSimulator( void *pvParameters ); + +static unsigned char ucEthernetBuffer[ archNUM_BUFFERS ][ UIP_CONF_BUFFER_SIZE ]; +static unsigned char *pucEthernetBufferPointers[ archNUM_BUFFER_POINTERS ]; + +static long lLengthOfDataInBuffer[ archNUM_BUFFER_POINTERS ] = { 0 }; +static unsigned char ucNextBufferToFill = 0U, ucNextBufferToProcess = 0U; + +unsigned char *uip_buf = NULL; +char cErrorBuffer[PCAP_ERRBUF_SIZE]; + +void vNetifTx( void ) +{ + pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len ); + pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len ); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxNetifRx( void ) +{ +UBaseType_t xDataLen; +unsigned char *pucTemp; + + /* Check there is really data available. */ + xDataLen = lLengthOfDataInBuffer[ ucNextBufferToProcess ]; + if( xDataLen != 0L ) + { + + /* The buffer pointed to by uip_buf is going to change. Remember which + buffer uip_buf is currently pointing to. */ + pucTemp = uip_buf; + + /* Point uip_buf at the next buffer that contains data. */ + uip_buf = pucEthernetBufferPointers[ ucNextBufferToProcess ]; + + /* The buffer pointed to by + pucEthernetBufferPointeres[ ucNextBufferToProcess ] is now in use by + uip_buf, but the buffer uip_buf was pointing to on entry to this + function is free. Set + pucEthernetBufferPointeres[ ucNextBufferToProcess ] to the free + buffer. */ + pucEthernetBufferPointers[ ucNextBufferToProcess ] = pucTemp; + lLengthOfDataInBuffer[ ucNextBufferToProcess ] = 0L; + + ucNextBufferToProcess++; + if( ucNextBufferToProcess >= archNUM_BUFFER_POINTERS ) + { + ucNextBufferToProcess = 0L; + } + } + + return xDataLen; +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetifInit( void ) +{ +BaseType_t x; +pcap_if_t *pxAllNetworkInterfaces; + + /* Allocate a free buffer to each buffer pointer. */ + for( x = 0; x < sizeof( pucEthernetBufferPointers ) / sizeof( unsigned char * ); x++ ) + { + pucEthernetBufferPointers[ x ] = &( ucEthernetBuffer[ x ][ 0 ] ); + } + + /* Start with uip_buf pointing to a buffer that is not referenced from the + pucEthernetBufferPointers[] array. */ + uip_buf = &( ucEthernetBuffer[ archNUM_BUFFERS - 1 ][ 0 ] ); + + /* Query the computer the simulation is being executed on to find the + network interfaces it has installed. */ + pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces(); + + /* Open the network interface. The number of the interface to be opened is + set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. + Calling this function will set the pxOpenedInterfaceHandle variable. If, + after calling this function, pxOpenedInterfaceHandle is equal to NULL, then + the interface could not be opened. */ + if( pxAllNetworkInterfaces != NULL ) + { + prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces ); + } + + + return x; +} +/*-----------------------------------------------------------*/ + +static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ) +{ +pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface; +long lInterfaceNumber = 1; + + if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 ) + { + printf( "\r\nCould not obtain a list of network interfaces\r\n%s\r\n", cErrorBuffer ); + pxAllNetworkInterfaces = NULL; + } + + if( pxAllNetworkInterfaces != NULL ) + { + /* Print out the list of network interfaces. The first in the list + is interface '1', not interface '0'. */ + for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next ) + { + printf( "%d. %s", lInterfaceNumber, xInterface->name ); + + if( xInterface->description != NULL ) + { + printf( " (%s)\r\n", xInterface->description ); + } + else + { + printf( " (No description available)\r\n") ; + } + + lInterfaceNumber++; + } + } + + if( lInterfaceNumber == 1 ) + { + /* The interface number was never incremented, so the above for() loop + did not execute meaning no interfaces were found. */ + printf( " \r\nNo network interfaces were found.\r\n" ); + pxAllNetworkInterfaces = NULL; + } + + printf( "\r\nThe interface that will be opened is set by configNETWORK_INTERFACE_TO_USE which should be defined in FreeRTOSConfig.h\r\n" ); + printf( "Attempting to open interface number %d.\r\n", configNETWORK_INTERFACE_TO_USE ); + + if( ( configNETWORK_INTERFACE_TO_USE < 1L ) || ( configNETWORK_INTERFACE_TO_USE > lInterfaceNumber ) ) + { + printf("\r\nconfigNETWORK_INTERFACE_TO_USE is not in the valid range.\r\n" ); + + if( pxAllNetworkInterfaces != NULL ) + { + /* Free the device list, as no devices are going to be opened. */ + pcap_freealldevs( pxAllNetworkInterfaces ); + pxAllNetworkInterfaces = NULL; + } + } + + return pxAllNetworkInterfaces; +} +/*-----------------------------------------------------------*/ + +static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ) +{ +pcap_if_t *xInterface; +long x; + + /* Walk the list of devices until the selected device is located. */ + xInterface = pxAllNetworkInterfaces; + for( x = 0L; x < ( configNETWORK_INTERFACE_TO_USE - 1L ); x++ ) + { + xInterface = xInterface->next; + } + + /* Open the selected interface. */ + pxOpenedInterfaceHandle = pcap_open( xInterface->name, /* The name of the selected interface. */ + UIP_CONF_BUFFER_SIZE, /* The size of the packet to capture. */ + PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscious mode as the MAC and + IP address is going to be "simulated", and + not be the real MAC and IP address. This allows + trafic to the simulated IP address to be routed + to uIP, and trafic to the real IP address to be + routed to the Windows TCP/IP stack. */ + 0xfffffffL, /* The read time out. This is going to block + until data is available. */ + NULL, /* No authentication is required as this is + not a remote capture session. */ + cErrorBuffer + ); + + if ( pxOpenedInterfaceHandle == NULL ) + { + printf( "\r\n%s is not supported by WinPcap and cannot be opened\r\n", xInterface->name ); + } + else + { + /* Configure the capture filter to allow blocking reads, and to filter + out packets that are not of interest to this demo. */ + prvConfigureCaptureBehaviour(); + } + + /* The device list is no longer required. */ + pcap_freealldevs( pxAllNetworkInterfaces ); +} +/*-----------------------------------------------------------*/ + +static void prvConfigureCaptureBehaviour( void ) +{ +struct bpf_program xFilterCode; +const long lMinBytesToCopy = 10L, lBlocking = 0L; +unsigned long ulNetMask; + + /* Unblock a read as soon as anything is received. */ + pcap_setmintocopy( pxOpenedInterfaceHandle, lMinBytesToCopy ); + + /* Allow blocking. */ + pcap_setnonblock( pxOpenedInterfaceHandle, lBlocking, cErrorBuffer ); + + /* Set up a filter so only the packets of interest are passed to the uIP + stack. cErrorBuffer is used for convenience to create the string. Don't + confuse this with an error message. */ + sprintf( cErrorBuffer, "broadcast or multicast or host %d.%d.%d.%d", configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 ); + + ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0; + + if( pcap_compile(pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 ) + { + printf("\r\nThe packet filter string is invalid\r\n" ); + } + else + { + if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 ) + { + printf( "\r\nAn error occurred setting the packet filter.\r\n" ); + } + } + + /* Create a task that simulates an interrupt in a real system. This will + block waiting for packets, then send a message to the uIP task when data + is available. */ + xTaskCreate( prvInterruptSimulator, ( signed char * ) "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, ( configuIP_TASK_PRIORITY - 1 ), NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvInterruptSimulator( void *pvParameters ) +{ +static struct pcap_pkthdr *pxHeader; +const unsigned char *pucPacketData; +extern QueueHandle_t xEMACEventQueue; +const unsigned long ulRxEvent = uipETHERNET_RX_EVENT; +long lResult; + + /* Just to kill the compiler warning. */ + ( void ) pvParameters; + + for( ;; ) + { + /* Get the next packet. */ + lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData ); + if( lResult ) + { + /* Is the next buffer into which data should be placed free? */ + if( lLengthOfDataInBuffer[ ucNextBufferToFill ] == 0L ) + { + /* Copy the data from the captured packet into the buffer. */ + memcpy( pucEthernetBufferPointers[ ucNextBufferToFill ], pucPacketData, pxHeader->len ); + + /* Note the amount of data that was copied. */ + lLengthOfDataInBuffer[ ucNextBufferToFill ] = pxHeader->len; + + /* Move onto the next buffer, wrapping around if necessary. */ + ucNextBufferToFill++; + if( ucNextBufferToFill >= archNUM_BUFFER_POINTERS ) + { + ucNextBufferToFill = 0U; + } + + /* Data was received and stored. Send a message to the uIP task + to let it know. */ + xQueueSendToBack( xEMACEventQueue, &ulRxEvent, portMAX_DELAY ); + } + } + } +} + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/bittypes.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/bittypes.h new file mode 100644 index 000000000..fcacd45fe --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/bittypes.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 1999 WIDE Project. + * 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. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. + */ +#ifndef _BITTYPES_H +#define _BITTYPES_H + +#ifndef HAVE_U_INT8_T + +#if SIZEOF_CHAR == 1 +typedef unsigned char u_int8_t; +typedef signed char _int8_t; +#elif SIZEOF_INT == 1 +typedef unsigned int u_int8_t; +typedef signed int int8_t; +#else /* XXX */ +#error "there's no appropriate type for u_int8_t" +#endif +#define HAVE_U_INT8_T 1 +#define HAVE_INT8_T 1 + +#endif /* HAVE_U_INT8_T */ + +#ifndef HAVE_U_INT16_T + +#if SIZEOF_SHORT == 2 +typedef unsigned short u_int16_t; +typedef signed short _int16_t; +#elif SIZEOF_INT == 2 +typedef unsigned int u_int16_t; +typedef signed int int16_t; +#elif SIZEOF_CHAR == 2 +typedef unsigned char u_int16_t; +typedef signed char int16_t; +#else /* XXX */ +#error "there's no appropriate type for u_int16_t" +#endif +#define HAVE_U_INT16_T 1 +#define HAVE_INT16_T 1 + +#endif /* HAVE_U_INT16_T */ + +#ifndef HAVE_U_INT32_T + +#if SIZEOF_INT == 4 +typedef unsigned int u_int32_t; +typedef signed int _int32_t; +#elif SIZEOF_LONG == 4 +typedef unsigned long u_int32_t; +typedef signed long int32_t; +#elif SIZEOF_SHORT == 4 +typedef unsigned short u_int32_t; +typedef signed short int32_t; +#else /* XXX */ +#error "there's no appropriate type for u_int32_t" +#endif +#define HAVE_U_INT32_T 1 +#define HAVE_INT32_T 1 + +#endif /* HAVE_U_INT32_T */ + +#ifndef HAVE_U_INT64_T +#if SIZEOF_LONG_LONG == 8 +typedef unsigned long long u_int64_t; +typedef long long int64_t; +#elif defined(_MSC_EXTENSIONS) +typedef unsigned _int64 u_int64_t; +typedef _int64 int64_t; +#elif SIZEOF_INT == 8 +typedef unsigned int u_int64_t; +#elif SIZEOF_LONG == 8 +typedef unsigned long u_int64_t; +#elif SIZEOF_SHORT == 8 +typedef unsigned short u_int64_t; +#else /* XXX */ +#error "there's no appropriate type for u_int64_t" +#endif + +#endif /* HAVE_U_INT64_T */ + +#ifndef PRId64 +#ifdef _MSC_EXTENSIONS +#define PRId64 "I64d" +#else /* _MSC_EXTENSIONS */ +#define PRId64 "lld" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRId64 */ + +#ifndef PRIo64 +#ifdef _MSC_EXTENSIONS +#define PRIo64 "I64o" +#else /* _MSC_EXTENSIONS */ +#define PRIo64 "llo" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIo64 */ + +#ifndef PRIx64 +#ifdef _MSC_EXTENSIONS +#define PRIx64 "I64x" +#else /* _MSC_EXTENSIONS */ +#define PRIx64 "llx" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIx64 */ + +#ifndef PRIu64 +#ifdef _MSC_EXTENSIONS +#define PRIu64 "I64u" +#else /* _MSC_EXTENSIONS */ +#define PRIu64 "llu" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIu64 */ + +#endif /* _BITTYPES_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/ip6_misc.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/ip6_misc.h new file mode 100644 index 000000000..96822d0e8 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/ip6_misc.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1993, 1994, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: /tcpdump/master/libpcap/Win32/Include/ip6_misc.h,v 1.5 2006-01-22 18:02:18 gianluca Exp $ (LBL) + */ + +/* + * This file contains a collage of declarations for IPv6 from FreeBSD not present in Windows + */ + +#include + +#include + +#ifndef __MINGW32__ +#define IN_MULTICAST(a) IN_CLASSD(a) +#endif + +#define IN_EXPERIMENTAL(a) ((((u_int32_t) (a)) & 0xf0000000) == 0xf0000000) + +#define IN_LOOPBACKNET 127 + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +/* IPv6 address */ +struct in6_addr + { + union + { + u_int8_t u6_addr8[16]; + u_int16_t u6_addr16[8]; + u_int32_t u6_addr32[4]; + } in6_u; +#define s6_addr in6_u.u6_addr8 +#define s6_addr16 in6_u.u6_addr16 +#define s6_addr32 in6_u.u6_addr32 +#define s6_addr64 in6_u.u6_addr64 + }; + +#define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } +#endif /* __MINGW32__ */ + + +#if (defined _MSC_VER) || (defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)) +typedef unsigned short sa_family_t; +#endif + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) + +#define __SOCKADDR_COMMON(sa_prefix) \ + sa_family_t sa_prefix##family + +/* Ditto, for IPv6. */ +struct sockaddr_in6 + { + __SOCKADDR_COMMON (sin6_); + u_int16_t sin6_port; /* Transport layer port # */ + u_int32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + }; + +#define IN6_IS_ADDR_V4MAPPED(a) \ + ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \ + (((u_int32_t *) (a))[2] == htonl (0xffff))) + +#define IN6_IS_ADDR_MULTICAST(a) (((u_int8_t *) (a))[0] == 0xff) + +#define IN6_IS_ADDR_LINKLOCAL(a) \ + ((((u_int32_t *) (a))[0] & htonl (0xffc00000)) == htonl (0xfe800000)) + +#define IN6_IS_ADDR_LOOPBACK(a) \ + (((u_int32_t *) (a))[0] == 0 && ((u_int32_t *) (a))[1] == 0 && \ + ((u_int32_t *) (a))[2] == 0 && ((u_int32_t *) (a))[3] == htonl (1)) +#endif /* __MINGW32__ */ + +#define ip6_vfc ip6_ctlun.ip6_un2_vfc +#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt +#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim +#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim + +#define nd_rd_type nd_rd_hdr.icmp6_type +#define nd_rd_code nd_rd_hdr.icmp6_code +#define nd_rd_cksum nd_rd_hdr.icmp6_cksum +#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0] + +/* + * IPV6 extension headers + */ +#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */ +#define IPPROTO_IPV6 41 /* IPv6 header. */ +#define IPPROTO_ROUTING 43 /* IPv6 routing header */ +#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ +#define IPPROTO_ESP 50 /* encapsulating security payload */ +#define IPPROTO_AH 51 /* authentication header */ +#define IPPROTO_ICMPV6 58 /* ICMPv6 */ +#define IPPROTO_NONE 59 /* IPv6 no next header */ +#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ +#define IPPROTO_PIM 103 /* Protocol Independent Multicast. */ + +#define IPV6_RTHDR_TYPE_0 0 + +/* Option types and related macros */ +#define IP6OPT_PAD1 0x00 /* 00 0 00000 */ +#define IP6OPT_PADN 0x01 /* 00 0 00001 */ +#define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ +#define IP6OPT_JUMBO_LEN 6 +#define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 */ + +#define IP6OPT_RTALERT_LEN 4 +#define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ +#define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ +#define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ +#define IP6OPT_MINLEN 2 + +#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */ +#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */ +#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */ +#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */ +#define IP6OPT_EID 0x8a /* 10 0 01010 */ + +#define IP6OPT_TYPE(o) ((o) & 0xC0) +#define IP6OPT_TYPE_SKIP 0x00 +#define IP6OPT_TYPE_DISCARD 0x40 +#define IP6OPT_TYPE_FORCEICMP 0x80 +#define IP6OPT_TYPE_ICMP 0xC0 + +#define IP6OPT_MUTABLE 0x20 + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +#ifndef EAI_ADDRFAMILY +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; +#endif +#endif /* __MINGW32__ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/netif.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/netif.h new file mode 100644 index 000000000..2d51478c0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/netif.h @@ -0,0 +1,52 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef NET_IF_H +#define NET_IF_H + +/* + * Send uip_len bytes from uip_buf to the network interface selected by the + * configNETWORK_INTERFACE_TO_USE constant (defined in FreeRTOSConfig.h). + */ +void vNetifTx( void ); + +/* + * Receive bytes from the network interface selected by the + * configNETWORK_INTERFACE_TO_USE constant (defined in FreeRTOSConfig.h). The + * bytes are placed in uip_buf. The number of bytes copied into uip_buf is + * returned. + */ +UBaseType_t uxNetifRx( void ); + +/* + * Prepare a packet capture session. This will print out all the network + * interfaces available, and the one actually used is set by the + * configNETWORK_INTERFACE_TO_USE constant that is defined in + * FreeRTOSConfig.h. */ +BaseType_t xNetifInit( void ); + +#endif /* NET_IF_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap-bpf.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap-bpf.h new file mode 100644 index 000000000..ff5b6e0da --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap-bpf.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.50 2007/04/01 21:43:55 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap-namedb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap-namedb.h new file mode 100644 index 000000000..ee6715fba --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap-namedb.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-namedb.h,v 1.13 2006/10/04 18:13:32 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap-stdinc.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap-stdinc.h new file mode 100644 index 000000000..cbd62d169 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap-stdinc.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-stdinc.h,v 1.10.2.1 2008-10-06 15:38:39 gianluca Exp $ (LBL) + */ + +#define SIZEOF_CHAR 1 +#define SIZEOF_SHORT 2 +#define SIZEOF_INT 4 +#ifndef _MSC_EXTENSIONS +#define SIZEOF_LONG_LONG 8 +#endif + +/* + * Avoids a compiler warning in case this was already defined + * (someone defined _WINSOCKAPI_ when including 'windows.h', in order + * to prevent it from including 'winsock.h') + */ +#ifdef _WINSOCKAPI_ +#undef _WINSOCKAPI_ +#endif +#include + +#include + +#include "bittypes.h" +#include +#include + +#ifndef __MINGW32__ +#include "IP6_misc.h" +#endif + +#define caddr_t char* + +#if _MSC_VER < 1500 +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#define strdup _strdup +#endif + +#define inline __inline + +#ifdef __MINGW32__ +#include +#else /*__MINGW32__*/ +/* MSVC compiler */ +#ifndef _UINTPTR_T_DEFINED +#ifdef _WIN64 +typedef unsigned __int64 uintptr_t; +#else +typedef _W64 unsigned int uintptr_t; +#endif +#define _UINTPTR_T_DEFINED +#endif + +#ifndef _INTPTR_T_DEFINED +#ifdef _WIN64 +typedef __int64 intptr_t; +#else +typedef _W64 int intptr_t; +#endif +#define _INTPTR_T_DEFINED +#endif + +#endif /*__MINGW32__*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap.h new file mode 100644 index 000000000..2eea0750b --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.59 2006/10/04 18:09:22 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Many applications + * expect to be able to include , and at least some of them + * go through contortions in their configure scripts to try to detect + * OSes that have "helpfully" moved pcap.h to without + * leaving behind a file. + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/bluetooth.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/bluetooth.h new file mode 100644 index 000000000..28b991f43 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/bluetooth.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * bluetooth data struct + * By Paolo Abeni + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/bluetooth.h,v 1.1 2007/09/22 02:10:17 guy Exp $ + */ + +#ifndef _PCAP_BLUETOOTH_STRUCTS_H__ +#define _PCAP_BLUETOOTH_STRUCTS_H__ + +/* + * Header prepended libpcap to each bluetooth h:4 frame. + * fields are in network byte order + */ +typedef struct _pcap_bluetooth_h4_header { + u_int32_t direction; /* if first bit is set direction is incoming */ +} pcap_bluetooth_h4_header; + + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/bpf.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/bpf.h new file mode 100644 index 000000000..b6d259679 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/bpf.h @@ -0,0 +1,934 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)bpf.h 7.1 (Berkeley) 5/7/91 + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/bpf.h,v 1.19.2.8 2008-09-22 20:16:01 guy Exp $ (LBL) + */ + +/* + * This is libpcap's cut-down version of bpf.h; it includes only + * the stuff needed for the code generator and the userland BPF + * interpreter, and the libpcap APIs for setting filters, etc.. + * + * "pcap-bpf.c" will include the native OS version, as it deals with + * the OS's BPF implementation. + * + * XXX - should this all just be moved to "pcap.h"? + */ + +#ifndef BPF_MAJOR_VERSION + +#ifdef __cplusplus +extern "C" { +#endif + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +#ifdef MSDOS /* must be 32-bit */ +typedef long bpf_int32; +typedef unsigned long bpf_u_int32; +#else +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +/* + * Alignment macros. BPF_WORDALIGN rounds up to the next + * even multiple of BPF_ALIGNMENT. + */ +#ifndef __NetBSD__ +#define BPF_ALIGNMENT sizeof(bpf_int32) +#else +#define BPF_ALIGNMENT sizeof(long) +#endif +#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) + +#define BPF_MAXBUFSIZE 0x8000 +#define BPF_MINBUFSIZE 32 + +/* + * Structure for "pcap_compile()", "pcap_setfilter()", etc.. + */ +struct bpf_program { + u_int bf_len; + struct bpf_insn *bf_insns; +}; + +/* + * Struct return by BIOCVERSION. This represents the version number of + * the filter language described by the instruction encodings below. + * bpf understands a program iff kernel_major == filter_major && + * kernel_minor >= filter_minor, that is, if the value returned by the + * running kernel has the same major number and a minor number equal + * equal to or less than the filter being downloaded. Otherwise, the + * results are undefined, meaning an error may be returned or packets + * may be accepted haphazardly. + * It has nothing to do with the source code version. + */ +struct bpf_version { + u_short bv_major; + u_short bv_minor; +}; +/* Current version number of filter architecture. */ +#define BPF_MAJOR_VERSION 1 +#define BPF_MINOR_VERSION 1 + +/* + * Data-link level type codes. + * + * Do *NOT* add new values to this list without asking + * "tcpdump-workers@lists.tcpdump.org" for a value. Otherwise, you run + * the risk of using a value that's already being used for some other + * purpose, and of having tools that read libpcap-format captures not + * being able to handle captures with your new DLT_ value, with no hope + * that they will ever be changed to do so (as that would destroy their + * ability to read captures using that value for that other purpose). + */ + +/* + * These are the types that are the same on all platforms, and that + * have been defined by for ages. + */ +#define DLT_NULL 0 /* BSD loopback encapsulation */ +#define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ +#define DLT_AX25 3 /* Amateur Radio AX.25 */ +#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ +#define DLT_CHAOS 5 /* Chaos */ +#define DLT_IEEE802 6 /* 802.5 Token Ring */ +#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ +#define DLT_SLIP 8 /* Serial Line IP */ +#define DLT_PPP 9 /* Point-to-point Protocol */ +#define DLT_FDDI 10 /* FDDI */ + +/* + * These are types that are different on some platforms, and that + * have been defined by for ages. We use #ifdefs to + * detect the BSDs that define them differently from the traditional + * libpcap + * + * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS, + * but I don't know what the right #define is for BSD/OS. + */ +#define DLT_ATM_RFC1483 11 /* LLC-encapsulated ATM */ + +#ifdef __OpenBSD__ +#define DLT_RAW 14 /* raw IP */ +#else +#define DLT_RAW 12 /* raw IP */ +#endif + +/* + * Given that the only OS that currently generates BSD/OS SLIP or PPP + * is, well, BSD/OS, arguably everybody should have chosen its values + * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they + * didn't. So it goes. + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) +#ifndef DLT_SLIP_BSDOS +#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ +#endif +#else +#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ +#endif + +/* + * 17 is used for DLT_OLD_PFLOG in OpenBSD; + * OBSOLETE: DLT_PFLOG is 117 in OpenBSD now as well. See below. + * 18 is used for DLT_PFSYNC in OpenBSD; don't use it for anything else. + */ + +#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ + +/* + * Apparently Redback uses this for its SmartEdge 400/800. I hope + * nobody else decided to use it, too. + */ +#define DLT_REDBACK_SMARTEDGE 32 + +/* + * These values are defined by NetBSD; other platforms should refrain from + * using them for other purposes, so that NetBSD savefiles with link + * types of 50 or 51 can be read as this type on all platforms. + */ +#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ +#define DLT_PPP_ETHER 51 /* PPP over Ethernet */ + +/* + * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses + * a link-layer type of 99 for the tcpdump it supplies. The link-layer + * header has 6 bytes of unknown data, something that appears to be an + * Ethernet type, and 36 bytes that appear to be 0 in at least one capture + * I've seen. + */ +#define DLT_SYMANTEC_FIREWALL 99 + +/* + * Values between 100 and 103 are used in capture file headers as + * link-layer types corresponding to DLT_ types that differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * This value was defined by libpcap 0.5; platforms that have defined + * it with a different value should define it here with that value - + * a link type of 104 in a save file will be mapped to DLT_C_HDLC, + * whatever value that happens to be, so programs will correctly + * handle files with that link type regardless of the value of + * DLT_C_HDLC. + * + * The name DLT_C_HDLC was used by BSD/OS; we use that name for source + * compatibility with programs written for BSD/OS. + * + * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, + * for source compatibility with programs written for libpcap 0.5. + */ +#define DLT_C_HDLC 104 /* Cisco HDLC */ +#define DLT_CHDLC DLT_C_HDLC + +#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ + +/* + * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW, + * except when it isn't. (I.e., sometimes it's just raw IP, and + * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL, + * so that we don't have to worry about the link-layer header.) + */ + +/* + * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides + * with other values. + * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header + * (DLCI, etc.). + */ +#define DLT_FRELAY 107 + +/* + * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except + * that the AF_ type in the link-layer header is in network byte order. + * + * DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so + * we don't use 12 for it in OSes other than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_LOOP 12 +#else +#define DLT_LOOP 108 +#endif + +/* + * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's + * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other + * than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_ENC 13 +#else +#define DLT_ENC 109 +#endif + +/* + * Values between 110 and 112 are reserved for use in capture file headers + * as link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ types + * other than the corresponding DLT_ types. + */ + +/* + * This is for Linux cooked sockets. + */ +#define DLT_LINUX_SLL 113 + +/* + * Apple LocalTalk hardware. + */ +#define DLT_LTALK 114 + +/* + * Acorn Econet. + */ +#define DLT_ECONET 115 + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define DLT_IPFILTER 116 + +/* + * OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, but that's DLT_LANE8023 + * in SuSE 6.3, so we can't use 17 for it in capture-file headers. + * + * XXX: is there a conflict with DLT_PFSYNC 18 as well? + */ +#ifdef __OpenBSD__ +#define DLT_OLD_PFLOG 17 +#define DLT_PFSYNC 18 +#endif +#define DLT_PFLOG 117 + +/* + * Registered for Cisco-internal use. + */ +#define DLT_CISCO_IOS 118 + +/* + * For 802.11 cards using the Prism II chips, with a link-layer + * header including Prism monitor mode information plus an 802.11 + * header. + */ +#define DLT_PRISM_HEADER 119 + +/* + * Reserved for Aironet 802.11 cards, with an Aironet link-layer header + * (see Doug Ambrisko's FreeBSD patches). + */ +#define DLT_AIRONET_HEADER 120 + +/* + * Reserved for Siemens HiPath HDLC. + */ +#define DLT_HHDLC 121 + +/* + * This is for RFC 2625 IP-over-Fibre Channel. + * + * This is not for use with raw Fibre Channel, where the link-layer + * header starts with a Fibre Channel frame header; it's for IP-over-FC, + * where the link-layer header starts with an RFC 2625 Network_Header + * field. + */ +#define DLT_IP_OVER_FC 122 + +/* + * This is for Full Frontal ATM on Solaris with SunATM, with a + * pseudo-header followed by an AALn PDU. + * + * There may be other forms of Full Frontal ATM on other OSes, + * with different pseudo-headers. + * + * If ATM software returns a pseudo-header with VPI/VCI information + * (and, ideally, packet type information, e.g. signalling, ILMI, + * LANE, LLC-multiplexed traffic, etc.), it should not use + * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump + * and the like don't have to infer the presence or absence of a + * pseudo-header and the form of the pseudo-header. + */ +#define DLT_SUNATM 123 /* Solaris+SunATM */ + +/* + * Reserved as per request from Kent Dahlgren + * for private use. + */ +#define DLT_RIO 124 /* RapidIO */ +#define DLT_PCI_EXP 125 /* PCI Express */ +#define DLT_AURORA 126 /* Xilinx Aurora link layer */ + +/* + * Header for 802.11 plus a number of bits of link-layer information + * including radio information, used by some recent BSD drivers as + * well as the madwifi Atheros driver for Linux. + */ +#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */ + +/* + * Reserved for the TZSP encapsulation, as per request from + * Chris Waters + * TZSP is a generic encapsulation for any other link type, + * which includes a means to include meta-information + * with the packet, e.g. signal strength and channel + * for 802.11 packets. + */ +#define DLT_TZSP 128 /* Tazmen Sniffer Protocol */ + +/* + * BSD's ARCNET headers have the source host, destination host, + * and type at the beginning of the packet; that's what's handed + * up to userland via BPF. + * + * Linux's ARCNET headers, however, have a 2-byte offset field + * between the host IDs and the type; that's what's handed up + * to userland via PF_PACKET sockets. + * + * We therefore have to have separate DLT_ values for them. + */ +#define DLT_ARCNET_LINUX 129 /* ARCNET */ + +/* + * Juniper-private data link types, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MLPPP 130 +#define DLT_JUNIPER_MLFR 131 +#define DLT_JUNIPER_ES 132 +#define DLT_JUNIPER_GGSN 133 +#define DLT_JUNIPER_MFR 134 +#define DLT_JUNIPER_ATM2 135 +#define DLT_JUNIPER_SERVICES 136 +#define DLT_JUNIPER_ATM1 137 + +/* + * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund + * . The header that's presented is an Ethernet-like + * header: + * + * #define FIREWIRE_EUI64_LEN 8 + * struct firewire_header { + * u_char firewire_dhost[FIREWIRE_EUI64_LEN]; + * u_char firewire_shost[FIREWIRE_EUI64_LEN]; + * u_short firewire_type; + * }; + * + * with "firewire_type" being an Ethernet type value, rather than, + * for example, raw GASP frames being handed up. + */ +#define DLT_APPLE_IP_OVER_IEEE1394 138 + +/* + * Various SS7 encapsulations, as per a request from Jeff Morriss + * and subsequent discussions. + */ +#define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */ +#define DLT_MTP2 140 /* MTP2, without pseudo-header */ +#define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */ +#define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */ + +/* + * DOCSIS MAC frames. + */ +#define DLT_DOCSIS 143 + +/* + * Linux-IrDA packets. Protocol defined at http://www.irda.org. + * Those packets include IrLAP headers and above (IrLMP...), but + * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy + * framing can be handled by the hardware and depend on the bitrate. + * This is exactly the format you would get capturing on a Linux-IrDA + * interface (irdaX), but not on a raw serial port. + * Note the capture is done in "Linux-cooked" mode, so each packet include + * a fake packet header (struct sll_header). This is because IrDA packet + * decoding is dependant on the direction of the packet (incomming or + * outgoing). + * When/if other platform implement IrDA capture, we may revisit the + * issue and define a real DLT_IRDA... + * Jean II + */ +#define DLT_LINUX_IRDA 144 + +/* + * Reserved for IBM SP switch and IBM Next Federation switch. + */ +#define DLT_IBM_SP 145 +#define DLT_IBM_SN 146 + +/* + * Reserved for private use. If you have some link-layer header type + * that you want to use within your organization, with the capture files + * using that link-layer header type not ever be sent outside your + * organization, you can use these values. + * + * No libpcap release will use these for any purpose, nor will any + * tcpdump release use them, either. + * + * Do *NOT* use these in capture files that you expect anybody not using + * your private versions of capture-file-reading tools to read; in + * particular, do *NOT* use them in products, otherwise you may find that + * people won't be able to use tcpdump, or snort, or Ethereal, or... to + * read capture files from your firewall/intrusion detection/traffic + * monitoring/etc. appliance, or whatever product uses that DLT_ value, + * and you may also find that the developers of those applications will + * not accept patches to let them read those files. + * + * Also, do not use them if somebody might send you a capture using them + * for *their* private type and tools using them for *your* private type + * would have to read them. + * + * Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value, + * as per the comment above, and use the type you're given. + */ +#define DLT_USER0 147 +#define DLT_USER1 148 +#define DLT_USER2 149 +#define DLT_USER3 150 +#define DLT_USER4 151 +#define DLT_USER5 152 +#define DLT_USER6 153 +#define DLT_USER7 154 +#define DLT_USER8 155 +#define DLT_USER9 156 +#define DLT_USER10 157 +#define DLT_USER11 158 +#define DLT_USER12 159 +#define DLT_USER13 160 +#define DLT_USER14 161 +#define DLT_USER15 162 + +/* + * For future use with 802.11 captures - defined by AbsoluteValue + * Systems to store a number of bits of link-layer information + * including radio information: + * + * http://www.shaftnet.org/~pizza/software/capturefrm.txt + * + * but it might be used by some non-AVS drivers now or in the + * future. + */ +#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MONITOR 164 + +/* + * Reserved for BACnet MS/TP. + */ +#define DLT_BACNET_MS_TP 165 + +/* + * Another PPP variant as per request from Karsten Keil . + * + * This is used in some OSes to allow a kernel socket filter to distinguish + * between incoming and outgoing packets, on a socket intended to + * supply pppd with outgoing packets so it can do dial-on-demand and + * hangup-on-lack-of-demand; incoming packets are filtered out so they + * don't cause pppd to hold the connection up (you don't want random + * input packets such as port scans, packets from old lost connections, + * etc. to force the connection to stay up). + * + * The first byte of the PPP header (0xff03) is modified to accomodate + * the direction - 0x00 = IN, 0x01 = OUT. + */ +#define DLT_PPP_PPPD 166 + +/* + * Names for backwards compatibility with older versions of some PPP + * software; new software should use DLT_PPP_PPPD. + */ +#define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD +#define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, cookies, etc.. + */ +#define DLT_JUNIPER_PPPOE 167 +#define DLT_JUNIPER_PPPOE_ATM 168 + +#define DLT_GPRS_LLC 169 /* GPRS LLC */ +#define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ +#define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ + +/* + * Requested by Oolan Zimmer for use in Gcom's T1/E1 line + * monitoring equipment. + */ +#define DLT_GCOM_T1E1 172 +#define DLT_GCOM_SERIAL 173 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_ is used + * for internal communication to Physical Interface Cards (PIC) + */ +#define DLT_JUNIPER_PIC_PEER 174 + +/* + * Link types requested by Gregor Maier of Endace + * Measurement Systems. They add an ERF header (see + * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of + * the link-layer header. + */ +#define DLT_ERF_ETH 175 /* Ethernet */ +#define DLT_ERF_POS 176 /* Packet-over-SONET */ + +/* + * Requested by Daniele Orlandi for raw LAPD + * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header + * includes additional information before the LAPD header, so it's + * not necessarily a generic LAPD header. + */ +#define DLT_LINUX_LAPD 177 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ are used for prepending meta-information + * like interface index, interface name + * before standard Ethernet, PPP, Frelay & C-HDLC Frames + */ +#define DLT_JUNIPER_ETHER 178 +#define DLT_JUNIPER_PPP 179 +#define DLT_JUNIPER_FRELAY 180 +#define DLT_JUNIPER_CHDLC 181 + +/* + * Multi Link Frame Relay (FRF.16) + */ +#define DLT_MFR 182 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * voice Adapter Card (PIC) + */ +#define DLT_JUNIPER_VP 183 + +/* + * Arinc 429 frames. + * DLT_ requested by Gianluca Varenni . + * Every frame contains a 32bit A429 label. + * More documentation on Arinc 429 can be found at + * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf + */ +#define DLT_A429 184 + +/* + * Arinc 653 Interpartition Communication messages. + * DLT_ requested by Gianluca Varenni . + * Please refer to the A653-1 standard for more information. + */ +#define DLT_A653_ICM 185 + +/* + * USB packets, beginning with a USB setup header; requested by + * Paolo Abeni . + */ +#define DLT_USB 186 + +/* + * Bluetooth HCI UART transport layer (part H:4); requested by + * Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4 187 + +/* + * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz + * . + */ +#define DLT_IEEE802_16_MAC_CPS 188 + +/* + * USB packets, beginning with a Linux USB header; requested by + * Paolo Abeni . + */ +#define DLT_USB_LINUX 189 + +/* + * Controller Area Network (CAN) v. 2.0B packets. + * DLT_ requested by Gianluca Varenni . + * Used to dump CAN packets coming from a CAN Vector board. + * More documentation on the CAN v2.0B frames can be found at + * http://www.can-cia.org/downloads/?269 + */ +#define DLT_CAN20B 190 + +/* + * IEEE 802.15.4, with address fields padded, as is done by Linux + * drivers; requested by Juergen Schimmer. + */ +#define DLT_IEEE802_15_4_LINUX 191 + +/* + * Per Packet Information encapsulated packets. + * DLT_ requested by Gianluca Varenni . + */ +#define DLT_PPI 192 + +/* + * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; + * requested by Charles Clancy. + */ +#define DLT_IEEE802_16_MAC_CPS_RADIO 193 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * integrated service module (ISM). + */ +#define DLT_JUNIPER_ISM 194 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing); requested by Mikko Saarnivala . + */ +#define DLT_IEEE802_15_4 195 + +/* + * Various link-layer types, with a pseudo-header, for SITA + * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). + */ +#define DLT_SITA 196 + +/* + * Various link-layer types, with a pseudo-header, for Endace DAG cards; + * encapsulates Endace ERF records. Requested by Stephen Donnelly + * . + */ +#define DLT_ERF 197 + +/* + * Special header prepended to Ethernet packets when capturing from a + * u10 Networks board. Requested by Phil Mulholland + * . + */ +#define DLT_RAIF1 198 + +/* + * IPMB packet for IPMI, beginning with the I2C slave address, followed + * by the netFn and LUN, etc.. Requested by Chanthy Toeung + * . + */ +#define DLT_IPMB 199 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for capturing data on a secure tunnel interface. + */ +#define DLT_JUNIPER_ST 200 + +/* + * Bluetooth HCI UART transport layer (part H:4), with pseudo-header + * that includes direction information; requested by Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4_WITH_PHDR 201 + +/* + * AX.25 packet with a 1-byte KISS header; see + * + * http://www.ax25.net/kiss.htm + * + * as per Richard Stearn . + */ +#define DLT_AX25_KISS 202 + +/* + * LAPD packets from an ISDN channel, starting with the address field, + * with no pseudo-header. + * Requested by Varuna De Silva . + */ +#define DLT_LAPD 203 + +/* + * Variants of various link-layer headers, with a one-byte direction + * pseudo-header prepended - zero means "received by this host", + * non-zero (any non-zero value) means "sent by this host" - as per + * Will Barker . + */ +#define DLT_PPP_WITH_DIR 204 /* PPP - don't confuse with DLT_PPP_WITH_DIRECTION */ +#define DLT_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ +#define DLT_FRELAY_WITH_DIR 206 /* Frame Relay */ +#define DLT_LAPB_WITH_DIR 207 /* LAPB */ + +/* + * 208 is reserved for an as-yet-unspecified proprietary link-layer + * type, as requested by Will Barker. + */ + +/* + * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman + * . + */ +#define DLT_IPMB_LINUX 209 + +/* + * FlexRay automotive bus - http://www.flexray.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_FLEXRAY 210 + +/* + * Media Oriented Systems Transport (MOST) bus for multimedia + * transport - http://www.mostcooperation.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_MOST 211 + +/* + * Local Interconnect Network (LIN) bus for vehicle networks - + * http://www.lin-subbus.org/ - as requested by Hannes Kaelber + * . + */ +#define DLT_LIN 212 + +/* + * X2E-private data link type used for serial line capture, + * as requested by Hannes Kaelber . + */ +#define DLT_X2E_SERIAL 213 + +/* + * X2E-private data link type used for the Xoraya data logger + * family, as requested by Hannes Kaelber . + */ +#define DLT_X2E_XORAYA 214 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), but with the PHY-level data for non-ASK PHYs (4 octets + * of 0 as preamble, one octet of SFD, one octet of frame length+ + * reserved bit, and then the MAC-layer data, starting with the + * frame control field). + * + * Requested by Max Filippov . + */ +#define DLT_IEEE802_15_4_NONASK_PHY 215 + + +/* + * DLT and savefile link type values are split into a class and + * a member of that class. A class value of 0 indicates a regular + * DLT_/LINKTYPE_ value. + */ +#define DLT_CLASS(x) ((x) & 0x03ff0000) + +/* + * NetBSD-specific generic "raw" link type. The class value indicates + * that this is the generic raw type, and the lower 16 bits are the + * address family we're dealing with. Those values are NetBSD-specific; + * do not assume that they correspond to AF_ values for your operating + * system. + */ +#define DLT_CLASS_NETBSD_RAWAF 0x02240000 +#define DLT_NETBSD_RAWAF(af) (DLT_CLASS_NETBSD_RAWAF | (af)) +#define DLT_NETBSD_RAWAF_AF(x) ((x) & 0x0000ffff) +#define DLT_IS_NETBSD_RAWAF(x) (DLT_CLASS(x) == DLT_CLASS_NETBSD_RAWAF) + + +/* + * The instruction encodings. + */ +/* instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* ret - BPF_K and BPF_X also apply */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 + +/* misc */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +#define BPF_TXA 0x80 + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_u_int32 k; +}; + +/* + * Macros for insn array initializers. + */ +#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } +#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } + +#if __STDC__ || defined(__cplusplus) +extern int bpf_validate(const struct bpf_insn *, int); +extern u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +#else +extern int bpf_validate(); +extern u_int bpf_filter(); +#endif + +/* + * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). + */ +#define BPF_MEMWORDS 16 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/namedb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/namedb.h new file mode 100644 index 000000000..8298e35b9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/namedb.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/namedb.h,v 1.1 2006/10/04 18:09:22 guy Exp $ (LBL) + */ + +#ifndef lib_pcap_namedb_h +#define lib_pcap_namedb_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * As returned by the pcap_next_etherent() + * XXX this stuff doesn't belong in this interface, but this + * library already must do name to address translation, so + * on systems that don't have support for /etc/ethers, we + * export these hooks since they'll + */ +struct pcap_etherent { + u_char addr[6]; + char name[122]; +}; +#ifndef PCAP_ETHERS_FILE +#define PCAP_ETHERS_FILE "/etc/ethers" +#endif +struct pcap_etherent *pcap_next_etherent(FILE *); +u_char *pcap_ether_hostton(const char*); +u_char *pcap_ether_aton(const char *); + +bpf_u_int32 **pcap_nametoaddr(const char *); +#ifdef INET6 +struct addrinfo *pcap_nametoaddrinfo(const char *); +#endif +bpf_u_int32 pcap_nametonetaddr(const char *); + +int pcap_nametoport(const char *, int *, int *); +int pcap_nametoportrange(const char *, int *, int *, int *); +int pcap_nametoproto(const char *); +int pcap_nametoeproto(const char *); +int pcap_nametollc(const char *); +/* + * If a protocol is unknown, PROTO_UNDEF is returned. + * Also, pcap_nametoport() returns the protocol along with the port number. + * If there are ambiguous entried in /etc/services (i.e. domain + * can be either tcp or udp) PROTO_UNDEF is returned. + */ +#define PROTO_UNDEF -1 + +/* XXX move these to pcap-int.h? */ +int __pcap_atodn(const char *, bpf_u_int32 *); +int __pcap_atoin(const char *, bpf_u_int32 *); +u_short __pcap_nametodnaddr(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/pcap.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/pcap.h new file mode 100644 index 000000000..fbf83413a --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/pcap.h @@ -0,0 +1,407 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/pcap.h,v 1.4.2.11 2008-10-06 15:38:39 gianluca Exp $ (LBL) + */ + +#ifndef lib_pcap_pcap_h +#define lib_pcap_pcap_h + +#if defined(WIN32) + #include +#elif defined(MSDOS) + #include + #include /* u_int, u_char etc. */ +#else /* UN*X */ + #include + #include +#endif /* WIN32/MSDOS/UN*X */ + +#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H +#include +#endif + +#include + +#ifdef HAVE_REMOTE + // We have to define the SOCKET here, although it has been defined in sockutils.h + // This is to avoid the distribution of the 'sockutils.h' file around + // (for example in the WinPcap developer's pack) + #ifndef SOCKET + #ifdef WIN32 + #define SOCKET unsigned int + #else + #define SOCKET int + #endif + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 + +#define PCAP_ERRBUF_SIZE 256 + +/* + * Compatibility for systems that have a bpf.h that + * predates the bpf typedefs for 64-bit support. + */ +#if BPF_RELEASE - 0 < 199406 +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +typedef struct pcap pcap_t; +typedef struct pcap_dumper pcap_dumper_t; +typedef struct pcap_if pcap_if_t; +typedef struct pcap_addr pcap_addr_t; + +/* + * The first record in the file contains saved values for some + * of the flags used in the printout phases of tcpdump. + * Many fields here are 32 bit ints so compilers won't insert unwanted + * padding; these files need to be interchangeable across architectures. + * + * Do not change the layout of this structure, in any way (this includes + * changes that only affect the length of fields in this structure). + * + * Also, do not change the interpretation of any of the members of this + * structure, in any way (this includes using values other than + * LINKTYPE_ values, as defined in "savefile.c", in the "linktype" + * field). + * + * Instead: + * + * introduce a new structure for the new format, if the layout + * of the structure changed; + * + * send mail to "tcpdump-workers@lists.tcpdump.org", requesting + * a new magic number for your new capture file format, and, when + * you get the new magic number, put it in "savefile.c"; + * + * use that magic number for save files with the changed file + * header; + * + * make the code in "savefile.c" capable of reading files with + * the old file header as well as files with the new file header + * (using the magic number to determine the header format). + * + * Then supply the changes as a patch at + * + * http://sourceforge.net/projects/libpcap/ + * + * so that future versions of libpcap and programs that use it (such as + * tcpdump) will be able to read your new capture file format. + */ +struct pcap_file_header { + bpf_u_int32 magic; + u_short version_major; + u_short version_minor; + bpf_int32 thiszone; /* gmt to local correction */ + bpf_u_int32 sigfigs; /* accuracy of timestamps */ + bpf_u_int32 snaplen; /* max length saved portion of each pkt */ + bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ +}; + +/* + * Macros for the value returned by pcap_datalink_ext(). + * + * If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro + * gives the FCS length of packets in the capture. + */ +#define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000) +#define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28) +#define LT_FCS_DATALINK_EXT(x) ((((x) & 0xF) << 28) | 0x04000000) + +typedef enum { + PCAP_D_INOUT = 0, + PCAP_D_IN, + PCAP_D_OUT +} pcap_direction_t; + +/* + * Generic per-packet information, as supplied by libpcap. + * + * The time stamp can and should be a "struct timeval", regardless of + * whether your system supports 32-bit tv_sec in "struct timeval", + * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit + * and 64-bit applications. The on-disk format of savefiles uses 32-bit + * tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit + * and 64-bit versions of libpcap, even if they're on the same platform, + * should supply the appropriate version of "struct timeval", even if + * that's not what the underlying packet capture mechanism supplies. + */ +struct pcap_pkthdr { + struct timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ +}; + +/* + * As returned by the pcap_stats() + */ +struct pcap_stat { + u_int ps_recv; /* number of packets received */ + u_int ps_drop; /* number of packets dropped */ + u_int ps_ifdrop; /* drops by interface XXX not yet supported */ +#ifdef HAVE_REMOTE + u_int ps_capt; /* number of packets that are received by the application; please get rid off the Win32 ifdef */ + u_int ps_sent; /* number of packets sent by the server on the network */ + u_int ps_netdrop; /* number of packets lost on the network */ +#endif /* HAVE_REMOTE */ +}; + +#ifdef MSDOS +/* + * As returned by the pcap_stats_ex() + */ +struct pcap_stat_ex { + u_long rx_packets; /* total packets received */ + u_long tx_packets; /* total packets transmitted */ + u_long rx_bytes; /* total bytes received */ + u_long tx_bytes; /* total bytes transmitted */ + u_long rx_errors; /* bad packets received */ + u_long tx_errors; /* packet transmit problems */ + u_long rx_dropped; /* no space in Rx buffers */ + u_long tx_dropped; /* no space available for Tx */ + u_long multicast; /* multicast packets received */ + u_long collisions; + + /* detailed rx_errors: */ + u_long rx_length_errors; + u_long rx_over_errors; /* receiver ring buff overflow */ + u_long rx_crc_errors; /* recv'd pkt with crc error */ + u_long rx_frame_errors; /* recv'd frame alignment error */ + u_long rx_fifo_errors; /* recv'r fifo overrun */ + u_long rx_missed_errors; /* recv'r missed packet */ + + /* detailed tx_errors */ + u_long tx_aborted_errors; + u_long tx_carrier_errors; + u_long tx_fifo_errors; + u_long tx_heartbeat_errors; + u_long tx_window_errors; + }; +#endif + +/* + * Item in a list of interfaces. + */ +struct pcap_if { + struct pcap_if *next; + char *name; /* name to hand to "pcap_open_live()" */ + char *description; /* textual description of interface, or NULL */ + struct pcap_addr *addresses; + bpf_u_int32 flags; /* PCAP_IF_ interface flags */ +}; + +#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ + +/* + * Representation of an interface address. + */ +struct pcap_addr { + struct pcap_addr *next; + struct sockaddr *addr; /* address */ + struct sockaddr *netmask; /* netmask for that address */ + struct sockaddr *broadaddr; /* broadcast address for that address */ + struct sockaddr *dstaddr; /* P2P destination address for that address */ +}; + +typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, + const u_char *); + +/* + * Error codes for the pcap API. + * These will all be negative, so you can check for the success or + * failure of a call that returns these codes by checking for a + * negative value. + */ +#define PCAP_ERROR -1 /* generic error code */ +#define PCAP_ERROR_BREAK -2 /* loop terminated by pcap_breakloop */ +#define PCAP_ERROR_NOT_ACTIVATED -3 /* the capture needs to be activated */ +#define PCAP_ERROR_ACTIVATED -4 /* the operation can't be performed on already activated captures */ +#define PCAP_ERROR_NO_SUCH_DEVICE -5 /* no such device exists */ +#define PCAP_ERROR_RFMON_NOTSUP -6 /* this device doesn't support rfmon (monitor) mode */ +#define PCAP_ERROR_NOT_RFMON -7 /* operation supported only in monitor mode */ +#define PCAP_ERROR_PERM_DENIED -8 /* no permission to open the device */ +#define PCAP_ERROR_IFACE_NOT_UP -9 /* interface isn't up */ + +/* + * Warning codes for the pcap API. + * These will all be positive and non-zero, so they won't look like + * errors. + */ +#define PCAP_WARNING 1 /* generic warning code */ +#define PCAP_WARNING_PROMISC_NOTSUP 2 /* this device doesn't support promiscuous mode */ + +char *pcap_lookupdev(char *); +int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); + +pcap_t *pcap_create(const char *, char *); +int pcap_set_snaplen(pcap_t *, int); +int pcap_set_promisc(pcap_t *, int); +int pcap_can_set_rfmon(pcap_t *); +int pcap_set_rfmon(pcap_t *, int); +int pcap_set_timeout(pcap_t *, int); +int pcap_set_buffer_size(pcap_t *, int); +int pcap_activate(pcap_t *); + +pcap_t *pcap_open_live(const char *, int, int, int, char *); +pcap_t *pcap_open_dead(int, int); +pcap_t *pcap_open_offline(const char *, char *); +#if defined(WIN32) +pcap_t *pcap_hopen_offline(intptr_t, char *); +#if !defined(LIBPCAP_EXPORTS) +#define pcap_fopen_offline(f,b) \ + pcap_hopen_offline(_get_osfhandle(_fileno(f)), b) +#else /*LIBPCAP_EXPORTS*/ +static pcap_t *pcap_fopen_offline(FILE *, char *); +#endif +#else /*WIN32*/ +pcap_t *pcap_fopen_offline(FILE *, char *); +#endif /*WIN32*/ + +void pcap_close(pcap_t *); +int pcap_loop(pcap_t *, int, pcap_handler, u_char *); +int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); +const u_char* + pcap_next(pcap_t *, struct pcap_pkthdr *); +int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); +void pcap_breakloop(pcap_t *); +int pcap_stats(pcap_t *, struct pcap_stat *); +int pcap_setfilter(pcap_t *, struct bpf_program *); +int pcap_setdirection(pcap_t *, pcap_direction_t); +int pcap_getnonblock(pcap_t *, char *); +int pcap_setnonblock(pcap_t *, int, char *); +int pcap_inject(pcap_t *, const void *, size_t); +int pcap_sendpacket(pcap_t *, const u_char *, int); +const char *pcap_statustostr(int); +const char *pcap_strerror(int); +char *pcap_geterr(pcap_t *); +void pcap_perror(pcap_t *, char *); +int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, + bpf_u_int32); +int pcap_compile_nopcap(int, int, struct bpf_program *, + const char *, int, bpf_u_int32); +void pcap_freecode(struct bpf_program *); +int pcap_offline_filter(struct bpf_program *, const struct pcap_pkthdr *, + const u_char *); +int pcap_datalink(pcap_t *); +int pcap_datalink_ext(pcap_t *); +int pcap_list_datalinks(pcap_t *, int **); +int pcap_set_datalink(pcap_t *, int); +void pcap_free_datalinks(int *); +int pcap_datalink_name_to_val(const char *); +const char *pcap_datalink_val_to_name(int); +const char *pcap_datalink_val_to_description(int); +int pcap_snapshot(pcap_t *); +int pcap_is_swapped(pcap_t *); +int pcap_major_version(pcap_t *); +int pcap_minor_version(pcap_t *); + +/* XXX */ +FILE *pcap_file(pcap_t *); +int pcap_fileno(pcap_t *); + +pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); +pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); +FILE *pcap_dump_file(pcap_dumper_t *); +long pcap_dump_ftell(pcap_dumper_t *); +int pcap_dump_flush(pcap_dumper_t *); +void pcap_dump_close(pcap_dumper_t *); +void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); + +int pcap_findalldevs(pcap_if_t **, char *); +void pcap_freealldevs(pcap_if_t *); + +const char *pcap_lib_version(void); + +/* XXX this guy lives in the bpf tree */ +u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +int bpf_validate(const struct bpf_insn *f, int len); +char *bpf_image(const struct bpf_insn *, int); +void bpf_dump(const struct bpf_program *, int); + +#if defined(WIN32) + +/* + * Win32 definitions + */ + +int pcap_setbuff(pcap_t *p, int dim); +int pcap_setmode(pcap_t *p, int mode); +int pcap_setmintocopy(pcap_t *p, int size); + +#ifdef WPCAP +/* Include file with the wpcap-specific extensions */ +#include +#endif /* WPCAP */ + +#define MODE_CAPT 0 +#define MODE_STAT 1 +#define MODE_MON 2 + +#elif defined(MSDOS) + +/* + * MS-DOS definitions + */ + +int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *); +void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait); +u_long pcap_mac_packets (void); + +#else /* UN*X */ + +/* + * UN*X definitions + */ + +int pcap_get_selectable_fd(pcap_t *); + +#endif /* WIN32/MSDOS/UN*X */ + +#ifdef HAVE_REMOTE +/* Includes most of the public stuff that is needed for the remote capture */ +#include +#endif /* HAVE_REMOTE */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/sll.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/sll.h new file mode 100644 index 000000000..5907beded --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/sll.h @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/sll.h,v 1.2.2.1 2008-05-30 01:36:06 guy Exp $ (LBL) + */ + +/* + * For captures on Linux cooked sockets, we construct a fake header + * that includes: + * + * a 2-byte "packet type" which is one of: + * + * LINUX_SLL_HOST packet was sent to us + * LINUX_SLL_BROADCAST packet was broadcast + * LINUX_SLL_MULTICAST packet was multicast + * LINUX_SLL_OTHERHOST packet was sent to somebody else + * LINUX_SLL_OUTGOING packet was sent *by* us; + * + * a 2-byte Ethernet protocol field; + * + * a 2-byte link-layer type; + * + * a 2-byte link-layer address length; + * + * an 8-byte source link-layer address, whose actual length is + * specified by the previous value. + * + * All fields except for the link-layer address are in network byte order. + * + * DO NOT change the layout of this structure, or change any of the + * LINUX_SLL_ values below. If you must change the link-layer header + * for a "cooked" Linux capture, introduce a new DLT_ type (ask + * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it + * a value that collides with a value already being used), and use the + * new header in captures of that type, so that programs that can + * handle DLT_LINUX_SLL captures will continue to handle them correctly + * without any change, and so that capture files with different headers + * can be told apart and programs that read them can dissect the + * packets in them. + */ + +#ifndef lib_pcap_sll_h +#define lib_pcap_sll_h + +/* + * A DLT_LINUX_SLL fake link-layer header. + */ +#define SLL_HDR_LEN 16 /* total header length */ +#define SLL_ADDRLEN 8 /* length of address field */ + +struct sll_header { + u_int16_t sll_pkttype; /* packet type */ + u_int16_t sll_hatype; /* link-layer address type */ + u_int16_t sll_halen; /* link-layer address length */ + u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ + u_int16_t sll_protocol; /* protocol */ +}; + +/* + * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the + * PACKET_ values on Linux, but are defined here so that they're + * available even on systems other than Linux, and so that they + * don't change even if the PACKET_ values change. + */ +#define LINUX_SLL_HOST 0 +#define LINUX_SLL_BROADCAST 1 +#define LINUX_SLL_MULTICAST 2 +#define LINUX_SLL_OTHERHOST 3 +#define LINUX_SLL_OUTGOING 4 + +/* + * The LINUX_SLL_ values for "sll_protocol"; these correspond to the + * ETH_P_ values on Linux, but are defined here so that they're + * available even on systems other than Linux. We assume, for now, + * that the ETH_P_ values won't change in Linux; if they do, then: + * + * if we don't translate them in "pcap-linux.c", capture files + * won't necessarily be readable if captured on a system that + * defines ETH_P_ values that don't match these values; + * + * if we do translate them in "pcap-linux.c", that makes life + * unpleasant for the BPF code generator, as the values you test + * for in the kernel aren't the values that you test for when + * reading a capture file, so the fixup code run on BPF programs + * handed to the kernel ends up having to do more work. + * + * Add other values here as necessary, for handling packet types that + * might show up on non-Ethernet, non-802.x networks. (Not all the ones + * in the Linux "if_ether.h" will, I suspect, actually show up in + * captures.) + */ +#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ +#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/usb.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/usb.h new file mode 100644 index 000000000..f150d3be0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/usb.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * Basic USB data struct + * By Paolo Abeni + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/usb.h,v 1.6 2007/09/22 02:06:08 guy Exp $ + */ + +#ifndef _PCAP_USB_STRUCTS_H__ +#define _PCAP_USB_STRUCTS_H__ + +/* + * possible transfer mode + */ +#define URB_TRANSFER_IN 0x80 +#define URB_ISOCHRONOUS 0x0 +#define URB_INTERRUPT 0x1 +#define URB_CONTROL 0x2 +#define URB_BULK 0x3 + +/* + * possible event type + */ +#define URB_SUBMIT 'S' +#define URB_COMPLETE 'C' +#define URB_ERROR 'E' + +/* + * USB setup header as defined in USB specification. + * Appears at the front of each packet in DLT_USB captures. + */ +typedef struct _usb_setup { + u_int8_t bmRequestType; + u_int8_t bRequest; + u_int16_t wValue; + u_int16_t wIndex; + u_int16_t wLength; +} pcap_usb_setup; + + +/* + * Header prepended by linux kernel to each event. + * Appears at the front of each packet in DLT_USB_LINUX captures. + */ +typedef struct _usb_header { + u_int64_t id; + u_int8_t event_type; + u_int8_t transfer_type; + u_int8_t endpoint_number; + u_int8_t device_address; + u_int16_t bus_id; + char setup_flag;/*if !=0 the urb setup header is not present*/ + char data_flag; /*if !=0 no urb data is present*/ + int64_t ts_sec; + int32_t ts_usec; + int32_t status; + u_int32_t urb_len; + u_int32_t data_len; /* amount of urb data really present in this event*/ + pcap_usb_setup setup; +} pcap_usb_header; + + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/vlan.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/vlan.h new file mode 100644 index 000000000..00ed9b616 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/pcap/vlan.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/vlan.h,v 1.1.2.2 2008-08-06 07:45:59 guy Exp $ + */ + +#ifndef lib_pcap_vlan_h +#define lib_pcap_vlan_h + +struct vlan_tag { + u_int16_t vlan_tpid; /* ETH_P_8021Q */ + u_int16_t vlan_tci; /* VLAN TCI */ +}; + +#define VLAN_TAG_LEN 4 + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/remote-ext.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/remote-ext.h new file mode 100644 index 000000000..9f54d6974 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/remote-ext.h @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * 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. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + + +#ifndef __REMOTE_EXT_H__ +#define __REMOTE_EXT_H__ + + +#ifndef HAVE_REMOTE +#error Please do not include this file directly. Just define HAVE_REMOTE and then include pcap.h +#endif + +// Definition for Microsoft Visual Studio +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + \file remote-ext.h + + The goal of this file it to include most of the new definitions that should be + placed into the pcap.h file. + + It includes all new definitions (structures and functions like pcap_open(). + Some of the functions are not really a remote feature, but, right now, + they are placed here. +*/ + + + +// All this stuff is public +/*! \addtogroup remote_struct + \{ +*/ + + + + +/*! + \brief Defines the maximum buffer size in which address, port, interface names are kept. + + In case the adapter name or such is larger than this value, it is truncated. + This is not used by the user; however it must be aware that an hostname / interface + name longer than this value will be truncated. +*/ +#define PCAP_BUF_SIZE 1024 + + +/*! \addtogroup remote_source_ID + \{ +*/ + + +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a file, i.e. the user want to open a capture from a local file. +*/ +#define PCAP_SRC_FILE 2 +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a local interface, i.e. the user want to open a capture from + a local interface. This does not involve the RPCAP protocol. +*/ +#define PCAP_SRC_IFLOCAL 3 +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a remote interface, i.e. the user want to open a capture from + an interface on a remote host. This does involve the RPCAP protocol. +*/ +#define PCAP_SRC_IFREMOTE 4 + +/*! + \} +*/ + + + +/*! \addtogroup remote_source_string + + The formats allowed by the pcap_open() are the following: + - file://path_and_filename [opens a local file] + - rpcap://devicename [opens the selected device devices available on the local host, without using the RPCAP protocol] + - rpcap://host/devicename [opens the selected device available on a remote host] + - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP] + - adaptername [to open a local adapter; kept for compability, but it is strongly discouraged] + - (NULL) [to open the first local adapter; kept for compability, but it is strongly discouraged] + + The formats allowed by the pcap_findalldevs_ex() are the following: + - file://folder/ [lists all the files in the given folder] + - rpcap:// [lists all local adapters] + - rpcap://host:port/ [lists the devices available on a remote host] + + Referring to the 'host' and 'port' paramters, they can be either numeric or literal. Since + IPv6 is fully supported, these are the allowed formats: + + - host (literal): e.g. host.foo.bar + - host (numeric IPv4): e.g. 10.11.12.13 + - host (numeric IPv4, IPv6 style): e.g. [10.11.12.13] + - host (numeric IPv6): e.g. [1:2:3::4] + - port: can be either numeric (e.g. '80') or literal (e.g. 'http') + + Here you find some allowed examples: + - rpcap://host.foo.bar/devicename [everything literal, no port number] + - rpcap://host.foo.bar:1234/devicename [everything literal, with port number] + - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number] + - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number] + - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number] + - rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number] + - rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number] + - rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number] + + \{ +*/ + + +/*! + \brief String that will be used to determine the type of source in use (file, + remote/local interface). + + This string will be prepended to the interface name in order to create a string + that contains all the information required to open the source. + + This string indicates that the user wants to open a capture from a local file. +*/ +#define PCAP_SRC_FILE_STRING "file://" +/*! + \brief String that will be used to determine the type of source in use (file, + remote/local interface). + + This string will be prepended to the interface name in order to create a string + that contains all the information required to open the source. + + This string indicates that the user wants to open a capture from a network interface. + This string does not necessarily involve the use of the RPCAP protocol. If the + interface required resides on the local host, the RPCAP protocol is not involved + and the local functions are used. +*/ +#define PCAP_SRC_IF_STRING "rpcap://" + +/*! + \} +*/ + + + + + +/*! + \addtogroup remote_open_flags + \{ +*/ + +/*! + \brief Defines if the adapter has to go in promiscuous mode. + + It is '1' if you have to open the adapter in promiscuous mode, '0' otherwise. + Note that even if this parameter is false, the interface could well be in promiscuous + mode for some other reason (for example because another capture process with + promiscuous mode enabled is currently using that interface). + On on Linux systems with 2.2 or later kernels (that have the "any" device), this + flag does not work on the "any" device; if an argument of "any" is supplied, + the 'promisc' flag is ignored. +*/ +#define PCAP_OPENFLAG_PROMISCUOUS 1 + +/*! + \brief Defines if the data trasfer (in case of a remote + capture) has to be done with UDP protocol. + + If it is '1' if you want a UDP data connection, '0' if you want + a TCP data connection; control connection is always TCP-based. + A UDP connection is much lighter, but it does not guarantee that all + the captured packets arrive to the client workstation. Moreover, + it could be harmful in case of network congestion. + This flag is meaningless if the source is not a remote interface. + In that case, it is simply ignored. +*/ +#define PCAP_OPENFLAG_DATATX_UDP 2 + + +/*! + \brief Defines if the remote probe will capture its own generated traffic. + + In case the remote probe uses the same interface to capture traffic and to send + data back to the caller, the captured traffic includes the RPCAP traffic as well. + If this flag is turned on, the RPCAP traffic is excluded from the capture, so that + the trace returned back to the collector is does not include this traffic. +*/ +#define PCAP_OPENFLAG_NOCAPTURE_RPCAP 4 + +/*! + \brief Defines if the local adapter will capture its own generated traffic. + + This flag tells the underlying capture driver to drop the packets that were sent by itself. + This is usefult when building applications like bridges, that should ignore the traffic + they just sent. +*/ +#define PCAP_OPENFLAG_NOCAPTURE_LOCAL 8 + +/*! + \brief This flag configures the adapter for maximum responsiveness. + + In presence of a large value for nbytes, WinPcap waits for the arrival of several packets before + copying the data to the user. This guarantees a low number of system calls, i.e. lower processor usage, + i.e. better performance, which is good for applications like sniffers. If the user sets the + PCAP_OPENFLAG_MAX_RESPONSIVENESS flag, the capture driver will copy the packets as soon as the application + is ready to receive them. This is suggested for real time applications (like, for example, a bridge) + that need the best responsiveness.*/ +#define PCAP_OPENFLAG_MAX_RESPONSIVENESS 16 + +/*! + \} +*/ + + +/*! + \addtogroup remote_samp_methods + \{ +*/ + +/*! + \brief No sampling has to be done on the current capture. + + In this case, no sampling algorithms are applied to the current capture. +*/ +#define PCAP_SAMP_NOSAMP 0 + +/*! + \brief It defines that only 1 out of N packets must be returned to the user. + + In this case, the 'value' field of the 'pcap_samp' structure indicates the + number of packets (minus 1) that must be discarded before one packet got accepted. + In other words, if 'value = 10', the first packet is returned to the caller, while + the following 9 are discarded. +*/ +#define PCAP_SAMP_1_EVERY_N 1 + +/*! + \brief It defines that we have to return 1 packet every N milliseconds. + + In this case, the 'value' field of the 'pcap_samp' structure indicates the 'waiting + time' in milliseconds before one packet got accepted. + In other words, if 'value = 10', the first packet is returned to the caller; the next + returned one will be the first packet that arrives when 10ms have elapsed. +*/ +#define PCAP_SAMP_FIRST_AFTER_N_MS 2 + +/*! + \} +*/ + + +/*! + \addtogroup remote_auth_methods + \{ +*/ + +/*! + \brief It defines the NULL authentication. + + This value has to be used within the 'type' member of the pcap_rmtauth structure. + The 'NULL' authentication has to be equal to 'zero', so that old applications + can just put every field of struct pcap_rmtauth to zero, and it does work. +*/ +#define RPCAP_RMTAUTH_NULL 0 +/*! + \brief It defines the username/password authentication. + + With this type of authentication, the RPCAP protocol will use the username/ + password provided to authenticate the user on the remote machine. If the + authentication is successful (and the user has the right to open network devices) + the RPCAP connection will continue; otherwise it will be dropped. + + This value has to be used within the 'type' member of the pcap_rmtauth structure. +*/ +#define RPCAP_RMTAUTH_PWD 1 + +/*! + \} +*/ + + + + +/*! + + \brief This structure keeps the information needed to autheticate + the user on a remote machine. + + The remote machine can either grant or refuse the access according + to the information provided. + In case the NULL authentication is required, both 'username' and + 'password' can be NULL pointers. + + This structure is meaningless if the source is not a remote interface; + in that case, the functions which requires such a structure can accept + a NULL pointer as well. +*/ +struct pcap_rmtauth +{ + /*! + \brief Type of the authentication required. + + In order to provide maximum flexibility, we can support different types + of authentication based on the value of this 'type' variable. The currently + supported authentication methods are defined into the + \link remote_auth_methods Remote Authentication Methods Section\endlink. + + */ + int type; + /*! + \brief Zero-terminated string containing the username that has to be + used on the remote machine for authentication. + + This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + and it can be NULL. + */ + char *username; + /*! + \brief Zero-terminated string containing the password that has to be + used on the remote machine for authentication. + + This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + and it can be NULL. + */ + char *password; +}; + + +/*! + \brief This structure defines the information related to sampling. + + In case the sampling is requested, the capturing device should read + only a subset of the packets coming from the source. The returned packets depend + on the sampling parameters. + + \warning The sampling process is applied after the filtering process. + In other words, packets are filtered first, then the sampling process selects a + subset of the 'filtered' packets and it returns them to the caller. +*/ +struct pcap_samp +{ + /*! + Method used for sampling. Currently, the supported methods are listed in the + \link remote_samp_methods Sampling Methods Section\endlink. + */ + int method; + + /*! + This value depends on the sampling method defined. For its meaning, please check + at the \link remote_samp_methods Sampling Methods Section\endlink. + */ + int value; +}; + + + + +//! Maximum lenght of an host name (needed for the RPCAP active mode) +#define RPCAP_HOSTLIST_SIZE 1024 + + +/*! + \} +*/ // end of public documentation + + +// Exported functions + + + +/** \name New WinPcap functions + + This section lists the new functions that are able to help considerably in writing + WinPcap programs because of their easiness of use. + */ +//\{ +pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf); +int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf); +int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf); +int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf); +struct pcap_samp *pcap_setsampling(pcap_t *p); + +//\} +// End of new winpcap functions + + + +/** \name Remote Capture functions + */ +//\{ +SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf); +int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf); +int pcap_remoteact_close(const char *host, char *errbuf); +void pcap_remoteact_cleanup(); +//\} +// End of remote capture functions + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/wpcap.lib b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/WinPCap/wpcap.lib new file mode 100644 index 0000000000000000000000000000000000000000..f832e0445b5c7dafe5a0f887262064265ba2b293 GIT binary patch literal 19320 zcmdU0O>9(05-uRW4k3h)gbS|j4}Uz#t>t&Y%Y)S%rl;4JTp5pCTuoh zr6{Lp73IKQa^QrbD7U>tdx#=VoK`4`_7Fwch+_^p| zS6BDfKh<5`)$NUA`Fde~ylZ#2`x_V>8Oe?2azi67zdwrRhWbZ!@NyRb{1af)Ai(As zfGr;YjQ*f$?=%3>0gMxkW0+_MhKYuM)O4~3fN1X*n)>bm5FNa!=@dc`jeVwR->(2f zr@qm2dK`f0IF?CtuvgRRPmzx_yk67JDF8*E;}+y2(SaM92H(eeAPs$`X>=9#JJEGb+ptfFdaw>e+iq*x`Yiy_8LSsk zPhHb?lqKrHekD4vPE+rP*gr_)Sa+hqpEMo(8T%RO(3GZ$?*SB*@r$$_@rd?+t!Zo@ zjvvxV99NR-y@~cP&F-(99u}FD=x9fbs_AYW3=3tr%W|L_8r?37d|TiVLY~ zEvy9P(zP&>67jfHb#AU)syKqo60(JIwPA#!ut>cUHY?T2Y`I#v8X-CyA=yYsIvgR1 z{ec~7x`z7J_EoXesO6i5`6%5+g-kun7o&6?6lsXL*a+*hi*s{fJrauXgmly&fhf^s z3E4_`-3*NminK;E-)tB(9ge34;dLpXqEaSo&XvkdS!WX$Qnj#NubO6=h)8cV>r%o- zg$#}#%0zWB5s_Y~F4Rh8)(8_zN(7avo*HT-qioC+@^ketEL4l8NE;P0#e6f5+G>={ zMukkHlCL%9t7a5zRLGPXLF4Uwtri*$kqjZXkpEM)9$X9SjZ(D|bw-RQrAw8hw96CH zIB?un6^x}-su3UwQbeQ|7jfC3NgauZcw9Wn7pTvr=@psX2-v zPKxSZ5_y=PnoE_N$P;l>b2RJuN@JnKx{58)m9q&VA1x?B*qjgRVZ~&L@q{!@+G|$O zMuiOZZ>iF(7OFMdSjiHy%7zr}qAKD-YOYi%Vt=CNK_NilssaMOp#PS~G0a z3#jr@2fHjGTg%rQuBgKil48`YO^Y*yd_7#KHp6_O8RQFvux8Xd$xh8vE;W)lG&5CR zE{YZ+xiZSMFke|T8koY@IHd|2`Ept5435N=dVT?dRHmqxp2NoQb4*B>?S@fVJ*ax; z#(FH|ab7p_3pF&AS9m=V93eT2qkmOwwM1MS~zh^OYj+6w(qzK0R@x9xxG+j`OQ@O)YAwXd4wWGVhD0>`FwwU%QhSy`Bsht3yBaP(% ze(43MpxoU(=zYOFA0d4{0I&g1$&>iKwHu(>kDdVhcHwsomUZU@z?X;clzbTAW2BWw z0NzC^?gw}e%b&*d8(7cxv5c>V09Ik$uOp3b!!mjRZsYgctytC>fI7y0LnY-36{Zf7=>XNfjzJf#$Z1jgA3T1 zPr!??4yIuo*25%B!C6=dn_&}df!E4q}7h2Vp-SXex#;FLwXebxMB`=5C9I^9PV8s(AynihM(q47Hlj}F34Yx5 z5?lA>X`GVyBqM>5uRR)q`2Y)!$;$8I=7z=ffJr=%AQ6tTb`!4lnRETAExQINoiFRt&`kb6)zb#5OTk(WXF`3LzuyeV>Hxo-xE;5&wx*TA8>_O0# zmkw~5!tPVa^mwZsG2>X)OyT6P_FY#r`5rUt)woR?W2mOSw@rK-bJ`>O{@4yI%WYCPuf1kaI9X$ zNp*3w@H`qDr?aNs+&Oo2#&Hz0Why()^2D`)wqGhaX1N5xvM@q!8M4BUSkpzx4EynIBam!|lli=G+Mk}qYj1rahg&EpnNTMnkZ z6X;YS&b;BMmJ!Md!^x2hGOWz7`V;-AEPO=~#ptsfeItO|rMA!b4@pA?b9;q` zELR%xFI6w99i(bVQ6qBcEkNU%@)Gd`Z&9+L3Wy4UP

ii zt(#u7(X5F2?uWKuz$0Zt8OJO)7!6qr;{`-mW-ub#&;iOoI?D5ivfQBP z?YRYMzrS+nDC-bqg+bw+zXjsZL+Gm53p&N2Dhi z$sPL*kF_J!=aoO!_oo5a`Wl^G6SWCz8X~fDnjyWbFWEo#2>_LrfpY(yof(M2GuM&^&tn45RTGq64I1es%5IBD_q*{iK;u2FYa$7I6mN$G=TOG^=4LlDoZVf8Mpw z8`>v5@1R6iH=VS|vlhSLVkx(ih2l^~-N<=b^b_Mk`m)-zIUnA+Dq&#M2jgMyAnZo(4AD0*qp9b5G`pq6hCIM%0W!8nw$ z=X{p)l{75!sW3?UZSYVll0YzKHbPhY;~;29sU1>;c0zRY>-XSai;ZdbYZCG=to zq}NeHHZoF*W4Z&(oJadNNlfy2cY@QRZM55d-N8}r^iGgGy0KXzv2)UbaVVp147WIa zljmv+W4U(#jA6SoBbv{mY-KcYyI`T(Ull#QxQ(&o#f1gqP{wxoR*xQmS-4#qq68LyTjtHxo|KwtJB;6=J(Y@(tt?ceEx_3CTXEKlvOJ{NFy#1JrL^z$>YNrb&<@)H8*An#mck^5f7vwn&$@= zl0z9sY}m8Q7*9o{hYgHkLs{`!j2wCD52oO$CleN~{Wa0!-I!oJ@fxE8EMH$9a z4-3eltbOUxmcuD{<_QVov_E zH5QOV8As7)wU0Y^#`|rDZ3!!<#~Pe)(9AO+ZjXh{+AKB$jT}9S zHBXm1z-lq?X#aRxVyQ<_9pHHO31=jZeQssJ+SYsD$#znrB{r%InpH16?K&%w>>DwL zSc1lTMr+DJqo>Fgh(lRh<ClhvL%JxCqKEC=kR{Bh7JE3l N*?W_a?2Af)@;}RMSJ?mn literal 0 HcmV?d00001 diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/demo_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/demo_config.h new file mode 100644 index 000000000..971405caa --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/demo_config.h @@ -0,0 +1,39 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef DEMO_CONFIG_H +#define DEMO_CONFIG_H + +/** + * @brief Set the stack size of the main demo task. + * + * In the Windows port, this stack only holds a structure. The actual + * stack is created by an operating system thread. + */ +#define democonfigDEMO_STACKSIZE configMINIMAL_STACK_SIZE + +#endif /* DEMO_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/demo_logging.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/demo_logging.c new file mode 100644 index 000000000..e22e91093 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/demo_logging.c @@ -0,0 +1,527 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + * Logging utility that allows FreeRTOS tasks to log to a UDP port, stdout, and + * disk file without making any Win32 system calls themselves. + * + * Messages logged to a UDP port are sent directly (using FreeRTOS+TCP), but as + * FreeRTOS tasks cannot make Win32 system calls messages sent to stdout or a + * disk file are sent via a stream buffer to a Win32 thread which then performs + * the actual output. + */ + +/* Standard includes. */ +#include +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_Stream_Buffer.h" + +/* Demo includes. */ +#include "demo_logging.h" + +/*-----------------------------------------------------------*/ + +/* The maximum size to which the log file may grow, before being renamed +to .ful. */ +#define dlLOGGING_FILE_SIZE ( 40ul * 1024ul * 1024ul ) + +/* Dimensions the arrays into which print messages are created. */ +#define dlMAX_PRINT_STRING_LENGTH 255 + +/* The size of the stream buffer used to pass messages from FreeRTOS tasks to +the Win32 thread that is responsible for making any Win32 system calls that are +necessary for the selected logging method. */ +#define dlLOGGING_STREAM_BUFFER_SIZE 32768 + +/* A block time of zero simply means don't block. */ +#define dlDONT_BLOCK 0 + +/*-----------------------------------------------------------*/ + +/* + * Called from vLoggingInit() to start a new disk log file. + */ +static void prvFileLoggingInit( void ); + +/* + * Attempt to write a message to the file. + */ +static void prvLogToFile( const char *pcMessage, size_t xLength ); + +/* + * Simply close the logging file, if it is open. + */ +static void prvFileClose( void ); + +/* + * Before the scheduler is started this function is called directly. After the + * scheduler has started it is called from the Windows thread dedicated to + * outputting log messages. Only the windows thread actually performs the + * writing so as not to disrupt the simulation by making Windows system calls + * from FreeRTOS tasks. + */ +static void prvLoggingFlushBuffer( void ); + +/* + * The windows thread that performs the actual writing of messages that require + * Win32 system calls. Only the windows thread can make system calls so as not + * to disrupt the simulation by making Windows calls from FreeRTOS tasks. + */ +static DWORD WINAPI prvWin32LoggingThread( void *pvParam ); + +/* + * Creates the socket to which UDP messages are sent. This function is not + * called directly to prevent the print socket being created from within the IP + * task - which could result in a deadlock. Instead the function call is + * deferred to run in the RTOS daemon task - hence it prototype. + */ +static void prvCreatePrintSocket( void *pvParameter1, uint32_t ulParameter2 ); + +/*-----------------------------------------------------------*/ + +/* Windows event used to wake the Win32 thread which performs any logging that +needs Win32 system calls. */ +static void *pvLoggingThreadEvent = NULL; + +/* Stores the selected logging targets passed in as parameters to the +vLoggingInit() function. */ +BaseType_t xStdoutLoggingUsed = pdFALSE, xDiskFileLoggingUsed = pdFALSE, xUDPLoggingUsed = pdFALSE; + +/* Circular buffer used to pass messages from the FreeRTOS tasks to the Win32 +thread that is responsible for making Win32 calls (when stdout or a disk log is +used). */ +static StreamBuffer_t *xLogStreamBuffer = NULL; + +/* Handle to the file used for logging. This is left open while there are +messages waiting to be logged, then closed again in between logs. */ +static FILE *pxLoggingFileHandle = NULL; + +/* When true prints are performed directly. After start up xDirectPrint is set +to pdFALSE - at which time prints that require Win32 system calls are done by +the Win32 thread responsible for logging. */ +BaseType_t xDirectPrint = pdTRUE; + +/* File names for the in use and complete (full) log files. */ +static const char *pcLogFileName = "RTOSDemo.log"; +static const char *pcFullLogFileName = "RTOSDemo.ful"; + +/* As an optimization, the current file size is kept in a variable. */ +static size_t ulSizeOfLoggingFile = 0ul; + +/* The UDP socket and address on/to which print messages are sent. */ +Socket_t xPrintSocket = FREERTOS_INVALID_SOCKET; +struct freertos_sockaddr xPrintUDPAddress; + +/*-----------------------------------------------------------*/ + +void vLoggingInit( BaseType_t xLogToStdout, BaseType_t xLogToFile, BaseType_t xLogToUDP, uint32_t ulRemoteIPAddress, uint16_t usRemotePort ) +{ + /* Can only be called before the scheduler has started. */ + configASSERT( xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED ); + + #if( ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) ) + { + HANDLE Win32Thread; + + /* Record which output methods are to be used. */ + xStdoutLoggingUsed = xLogToStdout; + xDiskFileLoggingUsed = xLogToFile; + xUDPLoggingUsed = xLogToUDP; + + /* If a disk file is used then initialize it now. */ + if( xDiskFileLoggingUsed != pdFALSE ) + { + prvFileLoggingInit(); + } + + /* If UDP logging is used then store the address to which the log data + will be sent - but don't create the socket yet because the network is + not initialized. */ + if( xUDPLoggingUsed != pdFALSE ) + { + /* Set the address to which the print messages are sent. */ + xPrintUDPAddress.sin_port = FreeRTOS_htons( usRemotePort ); + xPrintUDPAddress.sin_addr = ulRemoteIPAddress; + } + + /* If a disk file or stdout are to be used then Win32 system calls will + have to be made. Such system calls cannot be made from FreeRTOS tasks + so create a stream buffer to pass the messages to a Win32 thread, then + create the thread itself, along with a Win32 event that can be used to + unblock the thread. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) ) + { + /* Create the buffer. */ + xLogStreamBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) + dlLOGGING_STREAM_BUFFER_SIZE + 1 ); + configASSERT( xLogStreamBuffer ); + memset( xLogStreamBuffer, '\0', sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) ); + xLogStreamBuffer->LENGTH = dlLOGGING_STREAM_BUFFER_SIZE + 1; + + /* Create the Windows event. */ + pvLoggingThreadEvent = CreateEvent( NULL, FALSE, TRUE, "StdoutLoggingEvent" ); + + /* Create the thread itself. */ + Win32Thread = CreateThread( + NULL, /* Pointer to thread security attributes. */ + 0, /* Initial thread stack size, in bytes. */ + prvWin32LoggingThread, /* Pointer to thread function. */ + NULL, /* Argument for new thread. */ + 0, /* Creation flags. */ + NULL ); + + /* Use the cores that are not used by the FreeRTOS tasks. */ + SetThreadAffinityMask( Win32Thread, ~0x01u ); + SetThreadPriorityBoost( Win32Thread, TRUE ); + SetThreadPriority( Win32Thread, THREAD_PRIORITY_IDLE ); + } + } + #else + { + /* FreeRTOSIPConfig is set such that no print messages will be output. + Avoid compiler warnings about unused parameters. */ + ( void ) xLogToStdout; + ( void ) xLogToFile; + ( void ) xLogToUDP; + ( void ) usRemotePort; + ( void ) ulRemoteIPAddress; + } + #endif /* ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) */ +} +/*-----------------------------------------------------------*/ + +static void prvCreatePrintSocket( void *pvParameter1, uint32_t ulParameter2 ) +{ +static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 0 ); +Socket_t xSocket; + + /* The function prototype is that of a deferred function, but the parameters + are not actually used. */ + ( void ) pvParameter1; + ( void ) ulParameter2; + + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + + if( xSocket != FREERTOS_INVALID_SOCKET ) + { + /* FreeRTOS+TCP decides which port to bind to. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + FreeRTOS_bind( xSocket, NULL, 0 ); + + /* Now the socket is bound it can be assigned to the print socket. */ + xPrintSocket = xSocket; + } +} +/*-----------------------------------------------------------*/ + +void vLoggingPrintf( const char *pcFormat, ... ) +{ +char cPrintString[ dlMAX_PRINT_STRING_LENGTH ]; +char cOutputString[ dlMAX_PRINT_STRING_LENGTH ]; +char *pcSource, *pcTarget, *pcBegin; +size_t xLength, xLength2, rc; +static BaseType_t xMessageNumber = 0; +va_list args; +uint32_t ulIPAddress; +const char *pcTaskName; +const char *pcNoTask = "None"; +int iOriginalPriority; +HANDLE xCurrentTask; + + + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) || ( xUDPLoggingUsed != pdFALSE ) ) + { + /* There are a variable number of parameters. */ + va_start( args, pcFormat ); + + /* Additional info to place at the start of the log. */ + if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED ) + { + pcTaskName = pcTaskGetName( NULL ); + } + else + { + pcTaskName = pcNoTask; + } + + if( strcmp( pcFormat, "\n" ) != 0 ) + { + xLength = snprintf( cPrintString, dlMAX_PRINT_STRING_LENGTH, "%lu %lu [%s] ", + xMessageNumber++, + ( unsigned long ) xTaskGetTickCount(), + pcTaskName ); + } + else + { + xLength = 0; + memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH ); + } + + xLength2 = vsnprintf( cPrintString + xLength, dlMAX_PRINT_STRING_LENGTH - xLength, pcFormat, args ); + + if( xLength2 < 0 ) + { + /* Clean up. */ + xLength2 = dlMAX_PRINT_STRING_LENGTH - 1 - xLength; + cPrintString[ dlMAX_PRINT_STRING_LENGTH - 1 ] = '\0'; + } + + xLength += xLength2; + va_end( args ); + + /* For ease of viewing, copy the string into another buffer, converting + IP addresses to dot notation on the way. */ + pcSource = cPrintString; + pcTarget = cOutputString; + + while( ( *pcSource ) != '\0' ) + { + *pcTarget = *pcSource; + pcTarget++; + pcSource++; + + /* Look forward for an IP address denoted by 'ip'. */ + if( ( isxdigit( pcSource[ 0 ] ) != pdFALSE ) && ( pcSource[ 1 ] == 'i' ) && ( pcSource[ 2 ] == 'p' ) ) + { + *pcTarget = *pcSource; + pcTarget++; + *pcTarget = '\0'; + pcBegin = pcTarget - 8; + + while( ( pcTarget > pcBegin ) && ( isxdigit( pcTarget[ -1 ] ) != pdFALSE ) ) + { + pcTarget--; + } + + sscanf( pcTarget, "%8X", &ulIPAddress ); + rc = sprintf( pcTarget, "%lu.%lu.%lu.%lu", + ( unsigned long ) ( ulIPAddress >> 24UL ), + ( unsigned long ) ( (ulIPAddress >> 16UL) & 0xffUL ), + ( unsigned long ) ( (ulIPAddress >> 8UL) & 0xffUL ), + ( unsigned long ) ( ulIPAddress & 0xffUL ) ); + pcTarget += rc; + pcSource += 3; /* skip "ip" */ + } + } + + /* How far through the buffer was written? */ + xLength = ( BaseType_t ) ( pcTarget - cOutputString ); + + /* If the message is to be logged to a UDP port then it can be sent directly + because it only uses FreeRTOS function (not Win32 functions). */ + if( xUDPLoggingUsed != pdFALSE ) + { + if( ( xPrintSocket == FREERTOS_INVALID_SOCKET ) && ( FreeRTOS_IsNetworkUp() != pdFALSE ) ) + { + /* Create and bind the socket to which print messages are sent. The + xTimerPendFunctionCall() function is used even though this is + not an interrupt because this function is called from the IP task + and the IP task cannot itself wait for a socket to bind. The + parameters to prvCreatePrintSocket() are not required so set to + NULL or 0. */ + xTimerPendFunctionCall( prvCreatePrintSocket, NULL, 0, dlDONT_BLOCK ); + } + + if( xPrintSocket != FREERTOS_INVALID_SOCKET ) + { + FreeRTOS_sendto( xPrintSocket, cOutputString, xLength, 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) ); + + /* Just because the UDP data logger I'm using is dumb. */ + FreeRTOS_sendto( xPrintSocket, "\r", sizeof( char ), 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) ); + } + } + + /* If logging is also to go to either stdout or a disk file then it cannot + be output here - so instead write the message to the stream buffer and wake + the Win32 thread which will read it from the stream buffer and perform the + actual output. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) ) + { + configASSERT( xLogStreamBuffer ); + + /* How much space is in the buffer? */ + xLength2 = uxStreamBufferGetSpace( xLogStreamBuffer ); + + /* There must be enough space to write both the string and the length of + the string. */ + if( xLength2 >= ( xLength + sizeof( xLength ) ) ) + { + /* First write in the length of the data, then write in the data + itself. Raising the thread priority is used as a critical section + as there are potentially multiple writers. The stream buffer is + only thread safe when there is a single writer (likewise for + reading from the buffer). */ + xCurrentTask = GetCurrentThread(); + iOriginalPriority = GetThreadPriority( xCurrentTask ); + SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ); + uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) &( xLength ), sizeof( xLength ) ); + uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) cOutputString, xLength ); + SetThreadPriority( GetCurrentThread(), iOriginalPriority ); + } + + /* xDirectPrint is initialized to pdTRUE, and while it remains true the + logging output function is called directly. When the system is running + the output function cannot be called directly because it would get + called from both FreeRTOS tasks and Win32 threads - so instead wake the + Win32 thread responsible for the actual output. */ + if( xDirectPrint != pdFALSE ) + { + /* While starting up, the thread which calls prvWin32LoggingThread() + is not running yet and xDirectPrint will be pdTRUE. */ + prvLoggingFlushBuffer(); + } + else if( pvLoggingThreadEvent != NULL ) + { + /* While running, wake up prvWin32LoggingThread() to send the + logging data. */ + SetEvent( pvLoggingThreadEvent ); + } + } + } +} +/*-----------------------------------------------------------*/ + +static void prvLoggingFlushBuffer( void ) +{ +size_t xLength; +char cPrintString[ dlMAX_PRINT_STRING_LENGTH ]; + + /* Is there more than the length value stored in the circular buffer + used to pass data from the FreeRTOS simulator into this Win32 thread? */ + while( uxStreamBufferGetSize( xLogStreamBuffer ) > sizeof( xLength ) ) + { + memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH ); + uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE ); + uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) cPrintString, xLength, pdFALSE ); + + /* Write the message to standard out if requested to do so when + vLoggingInit() was called, or if the network is not yet up. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( FreeRTOS_IsNetworkUp() == pdFALSE ) ) + { + /* Write the message to stdout. */ + printf( "%s", cPrintString ); /*_RB_ Replace with _write(). */ + fflush( stdout ); + } + + /* Write the message to a file if requested to do so when + vLoggingInit() was called. */ + if( xDiskFileLoggingUsed != pdFALSE ) + { + prvLogToFile( cPrintString, xLength ); + } + } + + prvFileClose(); +} +/*-----------------------------------------------------------*/ + +static DWORD WINAPI prvWin32LoggingThread( void *pvParameter ) +{ +const DWORD xMaxWait = 1000; + + ( void ) pvParameter; + + /* From now on, prvLoggingFlushBuffer() will only be called from this + Windows thread */ + xDirectPrint = pdFALSE; + + for( ;; ) + { + /* Wait to be told there are message waiting to be logged. */ + WaitForSingleObject( pvLoggingThreadEvent, xMaxWait ); + + /* Write out all waiting messages. */ + prvLoggingFlushBuffer(); + } +} +/*-----------------------------------------------------------*/ + +static void prvFileLoggingInit( void ) +{ +FILE *pxHandle = fopen( pcLogFileName, "a" ); + + if( pxHandle != NULL ) + { + fseek( pxHandle, SEEK_END, 0ul ); + ulSizeOfLoggingFile = ftell( pxHandle ); + fclose( pxHandle ); + } + else + { + ulSizeOfLoggingFile = 0ul; + } +} +/*-----------------------------------------------------------*/ + +static void prvFileClose( void ) +{ + if( pxLoggingFileHandle != NULL ) + { + fclose( pxLoggingFileHandle ); + pxLoggingFileHandle = NULL; + } +} +/*-----------------------------------------------------------*/ + +static void prvLogToFile( const char *pcMessage, size_t xLength ) +{ + if( pxLoggingFileHandle == NULL ) + { + pxLoggingFileHandle = fopen( pcLogFileName, "a" ); + } + + if( pxLoggingFileHandle != NULL ) + { + fwrite( pcMessage, 1, xLength, pxLoggingFileHandle ); + ulSizeOfLoggingFile += xLength; + + /* If the file has grown to its maximum permissible size then close and + rename it - then start with a new file. */ + if( ulSizeOfLoggingFile > ( size_t ) dlLOGGING_FILE_SIZE ) + { + prvFileClose(); + if( _access( pcFullLogFileName, 00 ) == 0 ) + { + remove( pcFullLogFileName ); + } + rename( pcLogFileName, pcFullLogFileName ); + ulSizeOfLoggingFile = 0; + } + } +} +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/demo_logging.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/demo_logging.h new file mode 100644 index 000000000..197b21684 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/demo_logging.h @@ -0,0 +1,48 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef DEMO_LOGGING_H +#define DEMO_LOGGING_H + +/* + * Initialize a logging system that can be used from FreeRTOS tasks and Win32 + * threads. Do not call printf() directly while the scheduler is running. + * + * Set xLogToStdout, xLogToFile and xLogToUDP to either pdTRUE or pdFALSE to + * lot to stdout, a disk file and a UDP port respectively. + * + * If xLogToUDP is pdTRUE then ulRemoteIPAddress and usRemotePort must be set + * to the IP address and port number to which UDP log messages will be sent. + */ +void vLoggingInit( BaseType_t xLogToStdout, + BaseType_t xLogToFile, + BaseType_t xLogToUDP, + uint32_t ulRemoteIPAddress, + uint16_t usRemotePort ); + +#endif /* DEMO_LOGGING_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/iot_config.h b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/iot_config.h new file mode 100644 index 000000000..2188aa44d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/iot_config.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/* This file contains configuration settings for the demos. */ + +#ifndef IOT_CONFIG_H_ +#define IOT_CONFIG_H_ + +/* Configure the IoT Libraries for FreeRTOS by including the FreeRTOS header and + * the FreeRTOS platform types. */ +#include "FreeRTOS.h" +#include "platform/iot_platform_types_freertos.h" + +/** + * @brief Set a global default for log levels. + * + * This setting is overridden by log level settings of specific libraries. + * Undefined library-specific log levels will default to this value. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_GLOBAL IOT_LOG_NONE + +/** + * @brief Set the log level of the platform libraries except the network + * component. + * + * Log messages from the platform libraries at or below this setting + * will be printed. As the network component is more verbose, its logging + * is controlled by its own setting, IOT_LOG_LEVEL_NETWORK. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_PLATFORM IOT_LOG_NONE + +/* + * @brief Set the log level of the task pool library. + * + * Log messages from the task pool library at or below this setting will be + * printed. + * + * Possible values: One of the Log levels. + * Default value (if undefined): IOT_LOG_LEVEL_GLOBAL; if that is undefined, + * then IOT_LOG_NONE. + */ +#define IOT_LOG_LEVEL_TASKPOOL IOT_LOG_WARN + +/** + * @brief The number of recyclable jobs for the task pool to cache. + * + * Caching dynamically allocated jobs (recyclable jobs) helps the application + * to limit the number of allocations at runtime. Caching recyclable jobs may + * help making the application more responsive and predictable, by removing a + * potential for memory allocation failures, but it may also have negative + * repercussions on the amount of memory available at any given time. It is up + * to the application developer to strike the correct balance among these + * competing needs. The task pool will cache a job when the application calls + * IotTaskPool_RecycleJob on a job which was created using + * IotTaskPool_CreateRecyclableJob API. Any recycled jobs in excess of + * IOT_TASKPOOL_JOBS_RECYCLE_LIMIT will be destroyed and its memory will be + * released. + * + * Default value (if undefined): 8 + */ +#define IOT_TASKPOOL_JOBS_RECYCLE_LIMIT 8 + +/** + * @brief The number of worker tasks in the task pool. + * + * The full IoT Task Pool Library has many use cases, including Linux + * development. Typical FreeRTOS use cases do not require the full + * functionality so an optimized implementation is provided specifically for use + * with FreeRTOS. The optimized version has a fixed number of tasks in the + * task pool, each of which uses statically allocated memory to ensure creation + * of the task pool is guaranteed (it does not run out of heap space). + */ +#define IOT_TASKPOOL_NUMBER_OF_WORKERS 1 + +/** + * @brief The stack size (in bytes) for each worker task in the task pool. + * + * The minimal version of the of task pool library only supports one task pool + * and the configuration of each worker task fixed at the compile time. + */ +#define IOT_TASKPOOL_WORKER_STACK_SIZE_BYTES 2048 + +/** + * @brief Enable/Disable asserts for the linear containers library. + * + * Set this to 1 to perform sanity checks when using the linear containers library. + * Asserts are useful for debugging, but should be disabled in production code. + * If this is set to 1, IotContainers_Assert can be defined to set the assertion + * function; otherwise, the standard library's assert function will be used. + * + * Possible values: 0 (asserts disabled) or 1 (asserts enabled) + * Recommended values: 1 when debugging; 0 in production code. + * Default value (if undefined): 0 + */ +#define IOT_CONTAINERS_ENABLE_ASSERTS 1 + +/* Common settings for FreeRTOS; settings below this line generally do not need + * to be changed. */ + +/* Logging puts function on FreeRTOS. */ +#define IotLogging_Puts( str ) configPRINTF( ( "%s\r\n", str ) ) + +/* Assert functions on FreeRTOS. */ +#define Iot_DefaultAssert configASSERT + +/* Memory allocation functions on FreeRTOS. */ +#define Iot_DefaultMalloc pvPortMalloc +#define Iot_DefaultFree vPortFree + +#endif /* ifndef IOT_CONFIG_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/main.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/main.c new file mode 100644 index 000000000..f7bc12dcb --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/main.c @@ -0,0 +1,210 @@ +/* + * FreeRTOS Kernel V10.2.1 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + /*** + * See https://www.FreeRTOS.org/task-pool/ for configuration and usage instructions. + ***/ + + +/* Standard includes. */ +#include +#include + +/* Visual studio intrinsics used so the __debugbreak() function is available +should an assert get hit. */ +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" + +/* TCP/IP stack includes. */ +#include "FreeRTOS_IP.h" + +/* + * Prototypes for the demos that can be started from this project. + */ +extern void vStartSimpleTaskPoolDemo( void ); + +/* This example is the first in a sequence that adds IoT functionality into +an existing TCP/IP project. In this first project the TCP/IP stack is not +actually used, but it is still built, which requires this array to be +present. */ +const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 }; + +/*-----------------------------------------------------------*/ + +int main( void ) +{ + /*** + * See https://www.FreeRTOS.org/task-pool/ for configuration and usage instructions. + ***/ + + /* Create the example that demonstrates task pool functionality. Examples + that demonstrate networking connectivity will be added in future projects + and get started after the network has connected (from within the + vApplicationIPNetworkEventHook() function).*/ + vStartSimpleTaskPoolDemo(); + + /* Start the scheduler - if all is well from this point on only FreeRTOS + tasks will execute. */ + vTaskStartScheduler(); + + /* If all is well, the scheduler will now be running, and the following + line will never be reached. If the following line does execute, then + there was insufficient FreeRTOS heap memory available for the idle and/or + timer tasks to be created. See the memory management section on the + FreeRTOS web site for more details (this is standard text that is not + really applicable to the Win32 simulator port). */ + for( ;; ) + { + __debugbreak(); + } +} +/*-----------------------------------------------------------*/ + +void vAssertCalled( const char *pcFile, uint32_t ulLine ) +{ +volatile uint32_t ulBlockVariable = 0UL; +volatile char *pcFileName = ( volatile char * ) pcFile; +volatile uint32_t ulLineNumber = ulLine; + + ( void ) pcFileName; + ( void ) ulLineNumber; + + printf( "vAssertCalled( %s, %u\n", pcFile, ulLine ); + + /* Setting ulBlockVariable to a non-zero value in the debugger will allow + this function to be exited. */ + taskDISABLE_INTERRUPTS(); + { + while( ulBlockVariable == 0UL ) + { + __debugbreak(); + } + } + taskENABLE_INTERRUPTS(); +} +/*-----------------------------------------------------------*/ + +/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect +events are only received if implemented in the MAC driver. */ +void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) +{ + /* This example is the first in a sequence that adds IoT functionality into + an existing TCP/IP project. In this first project the TCP/IP stack is not + actually used, but it is still built, which requires this function to be + present. For now this function does not need to do anything, so just ensure + the unused parameters don't cause compiler warnings and that calls to this + function are trapped by the debugger. */ + __debugbreak(); + ( void ) eNetworkEvent; +} +/*-----------------------------------------------------------*/ + +extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress, + uint16_t usSourcePort, + uint32_t ulDestinationAddress, + uint16_t usDestinationPort ) +{ + /* This example is the first in a sequence that adds IoT functionality into + an existing TCP/IP project. In this first project the TCP/IP stack is not + actually used, but it is still built, which requires this function to be + present. For now this function does not need to do anything, so just ensure + the unused parameters don't cause compiler warnings and that calls to this + function are trapped by the debugger. */ + ( void ) ulSourceAddress; + ( void ) usSourcePort; + ( void ) ulDestinationAddress; + ( void ) usDestinationPort; + __debugbreak(); + return 0; +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxRand( void ) +{ + /* This example is the first in a sequence that adds IoT functionality into + an existing TCP/IP project. In this first project the TCP/IP stack is not + actually used, but it is still built, which requires this function to be + present. For now this function does not need to do anything, so just ensure + the calls to the function are trapped by the debugger. */ + __debugbreak(); + return 0; +} +/*-----------------------------------------------------------*/ + +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an +implementation of vApplicationGetIdleTaskMemory() to provide the memory that is +used by the Idle task. */ +void vApplicationGetIdleTaskMemory( StaticTask_t** ppxIdleTaskTCBBuffer, StackType_t** ppxIdleTaskStackBuffer, uint32_t* pulIdleTaskStackSize ) +{ + /* If the buffers to be provided to the Idle task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xIdleTaskTCB; + static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle task's + state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} +/*-----------------------------------------------------------*/ + +/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the +application must provide an implementation of vApplicationGetTimerTaskMemory() +to provide the memory that is used by the Timer service task. */ +void vApplicationGetTimerTaskMemory( StaticTask_t** ppxTimerTaskTCBBuffer, StackType_t** ppxTimerTaskStackBuffer, uint32_t* pulTimerTaskStackSize ) +{ + /* If the buffers to be provided to the Timer task are declared inside this + function then they must be declared static - otherwise they will be allocated on + the stack and so not exists after this function exits. */ + static StaticTask_t xTimerTaskTCB; + static StackType_t uxTimerTaskStack[configTIMER_TASK_STACK_DEPTH]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + Note that, as the array is necessarily of type StackType_t, + configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/printf-stdarg.c b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/printf-stdarg.c new file mode 100644 index 000000000..5505535c1 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/printf-stdarg.c @@ -0,0 +1,667 @@ +/* + Copyright 2001, 2002 Georges Menie (www.menie.org) + stdarg version contributed by Christian Ettinger + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Changes for the FreeRTOS ports: + + - The dot in "%-8.8s" + - The specifiers 'l' (long) and 'L' (long long) + - The specifier 'u' for unsigned + - Dot notation for IP addresses: + sprintf("IP = %xip\n", 0xC0A80164); + will produce "IP = 192.168.1.100\n" +*/ + +#include +#include +#include +#include + +#include "FreeRTOS.h" + +#define PAD_RIGHT 1 +#define PAD_ZERO 2 + +/* + * Return 1 for readable, 2 for writeable, 3 for both. + * Function must be provided by the application. + */ +extern BaseType_t xApplicationMemoryPermissions( uint32_t aAddress ); + +extern void vOutputChar( const char cChar, const TickType_t xTicksToWait ); +static const TickType_t xTicksToWait = pdMS_TO_TICKS( 20 ); + +struct xPrintFlags +{ + int base; + int width; + int printLimit; + unsigned + pad : 8, + letBase : 8, + isSigned : 1, + isNumber : 1, + long32 : 1, + long64 : 1; +}; + +struct SStringBuf +{ + char *str; + const char *orgStr; + const char *nulPos; + int curLen; + struct xPrintFlags flags; +}; + +static void strbuf_init( struct SStringBuf *apStr, char *apBuf, const char *apMaxStr ) +{ + apStr->str = apBuf; + apStr->orgStr = apBuf; + apStr->nulPos = apMaxStr-1; + apStr->curLen = 0; + + memset( &apStr->flags, '\0', sizeof( apStr->flags ) ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t strbuf_printchar( struct SStringBuf *apStr, int c ) +{ + if( apStr->str == NULL ) + { + vOutputChar( ( char ) c, xTicksToWait ); + apStr->curLen++; + return pdTRUE; + } + if( apStr->str < apStr->nulPos ) + { + *( apStr->str++ ) = c; + apStr->curLen++; + return pdTRUE; + } + if( apStr->str == apStr->nulPos ) + { + *( apStr->str++ ) = '\0'; + } + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static portINLINE BaseType_t strbuf_printchar_inline( struct SStringBuf *apStr, int c ) +{ + if( apStr->str == NULL ) + { + vOutputChar( ( char ) c, xTicksToWait ); + if( c == 0 ) + { + return pdFALSE; + } + apStr->curLen++; + return pdTRUE; + } + if( apStr->str < apStr->nulPos ) + { + *(apStr->str++) = c; + if( c == 0 ) + { + return pdFALSE; + } + apStr->curLen++; + return pdTRUE; + } + if( apStr->str == apStr->nulPos ) + { + *( apStr->str++ ) = '\0'; + } + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static portINLINE int i2hex( int aCh ) +{ +int iResult; + + if( aCh < 10 ) + { + iResult = '0' + aCh; + } + else + { + iResult = 'A' + aCh - 10; + } + + return iResult; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prints(struct SStringBuf *apBuf, const char *apString ) +{ + register int padchar = ' '; + int i,len; + + if( xApplicationMemoryPermissions( ( uint32_t )apString ) == 0 ) + { + /* The user has probably made a mistake with the parameter + for '%s', the memory is not readbale. */ + apString = "INV_MEM"; + } + + if( apBuf->flags.width > 0 ) + { + register int len = 0; + register const char *ptr; + for( ptr = apString; *ptr; ++ptr ) + { + ++len; + } + + if( len >= apBuf->flags.width ) + { + apBuf->flags.width = 0; + } + else + { + apBuf->flags.width -= len; + } + + if( apBuf->flags.pad & PAD_ZERO ) + { + padchar = '0'; + } + } + if( ( apBuf->flags.pad & PAD_RIGHT ) == 0 ) + { + for( ; apBuf->flags.width > 0; --apBuf->flags.width ) + { + if( strbuf_printchar( apBuf, padchar ) == 0 ) + { + return pdFALSE; + } + } + } + if( ( apBuf->flags.isNumber == pdTRUE ) && ( apBuf->flags.pad == pdTRUE ) ) + { + /* The string to print represents an integer number. + * In this case, printLimit is the min number of digits to print + * If the length of the number to print is less than the min nb of i + * digits to display, we add 0 before printing the number + */ + len = strlen( apString ); + + if( len < apBuf->flags.printLimit ) + { + i = apBuf->flags.printLimit - len; + for( ; i; i-- ) + { + if( strbuf_printchar( apBuf, '0' ) == 0 ) + { + return pdFALSE; + } + } + } + } + /* The string to print is not the result of a number conversion to ascii. + * For a string, printLimit is the max number of characters to display + */ + for( ; apBuf->flags.printLimit && *apString ; ++apString, --apBuf->flags.printLimit ) + { + if( !strbuf_printchar( apBuf, *apString ) ) + { + return pdFALSE; + } + } + + for( ; apBuf->flags.width > 0; --apBuf->flags.width ) + { + if( !strbuf_printchar( apBuf, padchar ) ) + { + return pdFALSE; + } + } + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +/* the following should be enough for 32 bit int */ +#define PRINT_BUF_LEN 12 /* to print 4294967296 */ + +#if SPRINTF_LONG_LONG +#warning 64-bit libraries will be included as well +static BaseType_t printll( struct SStringBuf *apBuf, long long i ) +{ + char print_buf[ 2 * PRINT_BUF_LEN ]; + register char *s; + register int t, neg = 0; + register unsigned long long u = i; + lldiv_t lldiv_result; + +/* typedef struct + * { + * long long int quot; // quotient + * long long int rem; // remainder + * } lldiv_t; + */ + + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + if( i == 0LL ) + { + print_buf[ 0 ] = '0'; + print_buf[ 1 ] = '\0'; + return prints( apBuf, print_buf ); + } + + if( ( apBuf->flags.isSigned == pdTRUE ) && ( apBuf->flags.base == 10 ) && ( i < 0LL ) ) + { + neg = 1; + u = -i; + } + + s = print_buf + sizeof( print_buf ) - 1; + + *s = '\0'; + /* 18446744073709551616 */ + while( u != 0 ) + { + lldiv_result = lldiv( u, ( unsigned long long ) apBuf->flags.base ); + t = lldiv_result.rem; + if( t >= 10 ) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u = lldiv_result.quot; + } + + if( neg != 0 ) + { + if( ( apBuf->flags.width != 0 ) && ( apBuf->flags.pad & PAD_ZERO ) ) + { + if( !strbuf_printchar( apBuf, '-' ) ) + { + return pdFALSE; + } + --apBuf->flags.width; + } + else + { + *( --s ) = '-'; + } + } + + return prints( apBuf, s ); +} +#endif /* SPRINTF_LONG_LONG */ +/*-----------------------------------------------------------*/ + +static BaseType_t printi( struct SStringBuf *apBuf, int i ) +{ + char print_buf[ PRINT_BUF_LEN ]; + register char *s; + register int t, neg = 0; + register unsigned int u = i; + register unsigned base = apBuf->flags.base; + + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + + if( i == 0 ) + { + print_buf[ 0 ] = '0'; + print_buf[ 1 ] = '\0'; + return prints( apBuf, print_buf ); + } + + if( ( apBuf->flags.isSigned == pdTRUE ) && ( base == 10 ) && ( i < 0 ) ) + { + neg = 1; + u = -i; + } + + s = print_buf + sizeof( print_buf ) - 1; + + *s = '\0'; + switch( base ) + { + case 16: + while( u != 0 ) + { + t = u & 0xF; + if( t >= 10 ) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u >>= 4; + } + break; + + case 8: + case 10: + /* GCC compiles very efficient */ + while( u ) + { + t = u % base; + *( --s ) = t + '0'; + u /= base; + } + break; +/* + // The generic case, not yet in use + default: + while( u ) + { + t = u % base; + if( t >= 10) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u /= base; + } + break; +*/ + } + + if( neg != 0 ) + { + if( apBuf->flags.width && (apBuf->flags.pad & PAD_ZERO ) ) + { + if( strbuf_printchar( apBuf, '-' ) == 0 ) + { + return pdFALSE; + } + --apBuf->flags.width; + } + else + { + *( --s ) = '-'; + } + } + + return prints( apBuf, s ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t printIp(struct SStringBuf *apBuf, unsigned i ) +{ + char print_buf[16]; + + sprintf( print_buf, "%u.%u.%u.%u", + i >> 24, + ( i >> 16 ) & 0xff, + ( i >> 8 ) & 0xff, + i & 0xff ); + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + prints( apBuf, print_buf ); + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +static void tiny_print( struct SStringBuf *apBuf, const char *format, va_list args ) +{ + char scr[2]; + + for( ; ; ) + { + int ch = *( format++ ); + + if( ch != '%' ) + { + do + { + /* Put the most like flow in a small loop */ + if( strbuf_printchar_inline( apBuf, ch ) == 0 ) + { + return; + } + ch = *( format++ ); + } while( ch != '%' ); + } + ch = *( format++ ); + /* Now ch has character after '%', format pointing to next */ + + if( ch == '\0' ) + { + break; + } + if( ch == '%' ) + { + if( strbuf_printchar( apBuf, ch ) == 0 ) + { + return; + } + continue; + } + memset( &apBuf->flags, '\0', sizeof( apBuf->flags ) ); + + if( ch == '-' ) + { + ch = *( format++ ); + apBuf->flags.pad = PAD_RIGHT; + } + while( ch == '0' ) + { + ch = *( format++ ); + apBuf->flags.pad |= PAD_ZERO; + } + if( ch == '*' ) + { + ch = *( format++ ); + apBuf->flags.width = va_arg( args, int ); + } + else + { + while( ch >= '0' && ch <= '9' ) + { + apBuf->flags.width *= 10; + apBuf->flags.width += ch - '0'; + ch = *( format++ ); + } + } + if( ch == '.' ) + { + ch = *( format++ ); + if( ch == '*' ) + { + apBuf->flags.printLimit = va_arg( args, int ); + ch = *( format++ ); + } + else + { + while( ch >= '0' && ch <= '9' ) + { + apBuf->flags.printLimit *= 10; + apBuf->flags.printLimit += ch - '0'; + ch = *( format++ ); + } + } + } + if( apBuf->flags.printLimit == 0 ) + { + apBuf->flags.printLimit--; /* -1: make it unlimited */ + } + if( ch == 's' ) + { + register char *s = ( char * )va_arg( args, int ); + if( prints( apBuf, s ? s : "(null)" ) == 0 ) + { + break; + } + continue; + } + if( ch == 'c' ) + { + /* char are converted to int then pushed on the stack */ + scr[0] = ( char ) va_arg( args, int ); + + if( strbuf_printchar( apBuf, scr[0] ) == 0 ) + { + return; + } + + continue; + } + if( ch == 'l' ) + { + ch = *( format++ ); + apBuf->flags.long32 = 1; + /* Makes not difference as u32 == long */ + } + if( ch == 'L' ) + { + ch = *( format++ ); + apBuf->flags.long64 = 1; + /* Does make a difference */ + } + apBuf->flags.base = 10; + apBuf->flags.letBase = 'a'; + + if( ch == 'd' || ch == 'u' ) + { + apBuf->flags.isSigned = ( ch == 'd' ); +#if SPRINTF_LONG_LONG + if( apBuf->flags.long64 != pdFALSE ) + { + if( printll( apBuf, va_arg( args, long long ) ) == 0 ) + { + break; + } + } else +#endif /* SPRINTF_LONG_LONG */ + if( printi( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + + apBuf->flags.base = 16; /* From here all hexadecimal */ + + if( ch == 'x' && format[0] == 'i' && format[1] == 'p' ) + { + format += 2; /* eat the "xi" of "xip" */ + /* Will use base 10 again */ + if( printIp( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + if( ch == 'x' || ch == 'X' || ch == 'p' || ch == 'o' ) + { + if( ch == 'X' ) + { + apBuf->flags.letBase = 'A'; + } + else if( ch == 'o' ) + { + apBuf->flags.base = 8; + } +#if SPRINTF_LONG_LONG + if( apBuf->flags.long64 != pdFALSE ) + { + if( printll( apBuf, va_arg( args, long long ) ) == 0 ) + { + break; + } + } else +#endif /* SPRINTF_LONG_LONG */ + if( printi( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + } + strbuf_printchar( apBuf, '\0' ); +} +/*-----------------------------------------------------------*/ + +int vsnprintf( char *apBuf, size_t aMaxLen, const char *apFmt, va_list args ) +{ + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen ); + tiny_print( &strBuf, apFmt, args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int snprintf( char *apBuf, size_t aMaxLen, const char *apFmt, ... ) +{ + va_list args; + + va_start( args, apFmt ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen ); + tiny_print( &strBuf, apFmt, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int sprintf( char *apBuf, const char *apFmt, ... ) +{ + va_list args; + + va_start( args, apFmt ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char * )apBuf + 1024 ); + tiny_print( &strBuf, apFmt, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int vsprintf( char *apBuf, const char *apFmt, va_list args ) +{ + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* ) apBuf + 1024 ); + tiny_print( &strBuf, apFmt, args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +const char *mkSize (unsigned long long aSize, char *apBuf, int aLen) +{ +static char retString[33]; +size_t gb, mb, kb, sb; + + if (apBuf == NULL) { + apBuf = retString; + aLen = sizeof( retString ); + } + gb = aSize / (1024*1024*1024); + aSize -= gb * (1024*1024*1024); + mb = aSize / (1024*1024); + aSize -= mb * (1024*1024); + kb = aSize / (1024); + aSize -= kb * (1024); + sb = aSize; + if( gb ) + { + snprintf (apBuf, aLen, "%u.%02u GB", ( unsigned ) gb, ( unsigned ) ( ( 100 * mb ) / 1024ul ) ); + } + else if( mb ) + { + snprintf (apBuf, aLen, "%u.%02u MB", ( unsigned ) mb, ( unsigned ) ( ( 100 * kb) / 1024ul ) ); + } + else if( kb != 0ul ) + { + snprintf (apBuf, aLen, "%u.%02u KB", ( unsigned ) kb, ( unsigned ) ( ( 100 * sb) / 1024ul ) ); + } + else + { + snprintf (apBuf, aLen, "%u bytes", ( unsigned ) sb); + } + return apBuf; +} diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/task_pool_demo.sln b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/task_pool_demo.sln new file mode 100644 index 000000000..9fe7adbfd --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities/task_pool/task_pool_demo.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29215.179 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTOSDemo", "WIN32.vcxproj", "{C686325E-3261-42F7-AEB1-DDE5280E1CEB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.ActiveCfg = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.Build.0 = Debug|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A6079C9D-CF20-456A-8108-48DB9F98282E} + EndGlobalSection + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = FreeRTOS_Plus_TCP_Minimal.vsmdi + EndGlobalSection +EndGlobal diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/FreeRTOSConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/FreeRTOSConfig.h new file mode 100644 index 000000000..1bfa65e42 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/FreeRTOSConfig.h @@ -0,0 +1,119 @@ +/* + * FreeRTOS Kernel V10.0.1 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +#include + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * http://www.freertos.org/a00110.html + *----------------------------------------------------------*/ + +#define configUSE_PREEMPTION 1 +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configMAX_TASK_NAME_LEN ( 7 ) +#define configUSE_TRACE_FACILITY 0 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 0 +#define configUSE_MUTEXES 1 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 + +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY 2 +#define configTIMER_QUEUE_LENGTH 20 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +#define configMAX_PRIORITIES ( 7 ) +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Hook functions */ +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configUSE_MALLOC_FAILED_HOOK 1 + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_xTaskAbortDelay 1 + +/* heap_4.c, */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) ) + +/* Allow RTOS objects to be created using RAM provided by the application writer. */ +#define configSUPPORT_STATIC_ALLOCATION 1 + +/* Create RTOS objects using dynamically allocated RAM */ +#define configSUPPORT_DYNAMIC_ALLOCATION 1 + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* Run time stats gathering definitions. */ +#define configGENERATE_RUN_TIME_STATS 0 + +/* Assert call defined for debug builds. */ +extern void vAssertCalled(const char * pcFile, uint32_t ulLine); +#define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) + +#endif /* FREERTOS_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/FreeRTOS_Plus_POSIX_with_actor.sln b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/FreeRTOS_Plus_POSIX_with_actor.sln new file mode 100644 index 000000000..cf251a22b --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/FreeRTOS_Plus_POSIX_with_actor.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28010.2050 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTOS_POSIX_Demo", "WIN32.vcxproj", "{C686325E-3261-42F7-AEB1-DDE5280E1CEB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.ActiveCfg = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.Build.0 = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.ActiveCfg = Release|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {18112148-F9F0-43E0-B713-B146289BDEF3} + EndGlobalSection +EndGlobal diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/WIN32.vcxproj b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/WIN32.vcxproj new file mode 100644 index 000000000..33ff7444b --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/WIN32.vcxproj @@ -0,0 +1,185 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {C686325E-3261-42F7-AEB1-DDE5280E1CEB} + RTOS_POSIX_Demo + 10.0 + + + + Application + false + MultiByte + v142 + + + Application + false + MultiByte + v142 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Debug\ + .\Debug\ + true + .\Release\ + .\Release\ + false + + + + .\Debug/WIN32.tlb + + + + + Disabled + ..\..\..\FreeRTOS\Source\include;..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\..\FreeRTOS-Labs\Demo\FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator\lib\FreeRTOS-Plus-POSIX\include\portable\pc\windows;..\..\..\FreeRTOS-Labs\Demo\FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator\lib\FreeRTOS-Plus-POSIX\include\portable;..\..\..\FreeRTOS-Labs\Demo\FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator\lib\FreeRTOS-Plus-POSIX\include;..\..\..\FreeRTOS-Labs\Demo\FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator\lib\FreeRTOS-Plus-POSIX\source;..\..\..\FreeRTOS-Labs\Demo\FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator\lib\include\private;..\..\..\FreeRTOS-Labs\Demo\FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator\lib\third_party\win_pcap;..\..\..\FreeRTOS-Labs\Demo\FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator\lib\include;..\..\..\FreeRTOS-Labs\Demo\FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator;..\..\..\FreeRTOS\Demo\Common\ethernet\lwip-1.4.0\ports\win32\WinPCap;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + .\Debug/WIN32.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level3 + true + false + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Debug/RTOS_POSIX_demo.exe + true + true + .\Debug/WIN32.pdb + Console + MachineX86 + %(AdditionalDependencies) + + + false + + + true + .\Debug/WIN32.bsc + + + + + .\Release/WIN32.tlb + + + + + MaxSpeed + OnlyExplicitInline + _WINSOCKAPI_;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release/WIN32.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + ..\Common\Utils;..\Common\ethernet\lwip-1.4.0\ports\win32\WinPCap;..\Common\ethernet\lwip-1.4.0\src\include\ipv4;..\Common\ethernet\lwip-1.4.0\src\include;..\..\Source\include;..\..\Source\portable\MSVC-MingW;..\Common\ethernet\lwip-1.4.0\ports\win32\include;..\Common\Include;.\lwIP_Apps;.;%(AdditionalIncludeDirectories) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Release/RTOSDemo.exe + true + .\Release/WIN32.pdb + Console + MachineX86 + ..\Common\ethernet\lwip-1.4.0\ports\win32\WinPCap + wpcap.lib;%(AdditionalDependencies) + + + true + .\Release/WIN32.bsc + + + + + + + + + + + + + + + + + + + + + + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/WIN32.vcxproj.filters b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/WIN32.vcxproj.filters new file mode 100644 index 000000000..54dbe0e52 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/WIN32.vcxproj.filters @@ -0,0 +1,174 @@ + + + + + {34567deb-d5ab-4a56-8640-0aaec609521a} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {e3396fdf-de1f-4cb9-975c-673cb9315287} + + + {02f5b936-2f92-411d-89d3-985520c10e9d} + + + {1f6970f5-2901-4d3b-a119-86195fed3601} + + + {63611657-d97d-479c-af87-69d6817b564d} + + + {7c2a7031-ca15-4d3e-838e-efe7b508f899} + + + {dddb94ad-d701-41db-ab34-8fd5b9b4d2db} + + + {db0fccd4-1177-4630-8a6d-b1ea48d0b0fa} + + + {af3445a1-4908-4170-89ed-39345d90d30c} + + + {26ccdf01-559e-4934-9311-bd1a25bdd658} + + + {19ff1a34-36de-4c48-9d10-3fb1fa0d1fa4} + + + + + {88f409e6-d396-4ac5-94bd-7a99c914be46} + + + {a4b373f5-dc97-40ff-9b67-118253049621} + + + {0447c18c-e805-43d8-8b36-744f7c7fb88f} + + + + + application_code + + + lib\FreeRTOS-Plus-POSIX\source + + + lib\FreeRTOS-Plus-POSIX\source + + + lib\FreeRTOS-Plus-POSIX\source + + + lib\FreeRTOS-Plus-POSIX\source + + + lib\FreeRTOS-Plus-POSIX\source + + + lib\FreeRTOS-Plus-POSIX\source + + + lib\FreeRTOS-Plus-POSIX\source + + + lib\FreeRTOS-Plus-POSIX\source + + + lib\FreeRTOS-Plus-POSIX\source + + + lib\FreeRTOS-Plus-POSIX\source + + + lib\FreeRTOS-Plus-POSIX\source + + + lib\FreeRTOS\Portable\MemMang + + + lib\FreeRTOS\Portable\MSVC-W + + + lib\FreeRTOS + + + lib\FreeRTOS + + + lib\FreeRTOS + + + lib\FreeRTOS + + + lib\FreeRTOS + + + lib\FreeRTOS + + + application_code + + + + + configuration_files + + + lib\FreeRTOS-Plus-POSIX\include + + + lib\FreeRTOS-Plus-POSIX\include + + + lib\FreeRTOS-Plus-POSIX\include + + + lib\FreeRTOS-Plus-POSIX\include + + + lib\include\private + + + lib\include\FreeRTOS_POSIX + + + lib\include\FreeRTOS_POSIX + + + lib\include\FreeRTOS_POSIX + + + lib\include\FreeRTOS_POSIX + + + lib\include\FreeRTOS_POSIX + + + lib\include\FreeRTOS_POSIX + + + lib\include\FreeRTOS_POSIX + + + lib\include\FreeRTOS_POSIX + + + lib\include\FreeRTOS_POSIX + + + lib\include\FreeRTOS_POSIX + + + lib\include\FreeRTOS_POSIX\sys + + + lib\FreeRTOS\Portable\MSVC-W + + + application_code + + + \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/atomic.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/atomic.h new file mode 100644 index 000000000..565c28037 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/atomic.h @@ -0,0 +1,547 @@ +/* + * FreeRTOS Kernel V10.2.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/** + * @file atomic.h + * @brief FreeRTOS atomic operation support. + * + * Two implementations of atomic are given in this header file: + * 1. Disabling interrupt globally. + * 2. ISA native atomic support. + * The former is available to all ports (compiler-architecture combination), + * while the latter is only available to ports compiling with GCC (version at + * least 4.7.0), which also have ISA atomic support. + * + * User can select which implementation to use by: + * setting/clearing configUSE_ATOMIC_INSTRUCTION in FreeRTOSConfig.h. + * Define AND set configUSE_ATOMIC_INSTRUCTION to 1 for ISA native atomic support. + * Undefine OR clear configUSE_ATOMIC_INSTRUCTION for disabling global interrupt + * implementation. + * + * @see GCC Built-in Functions for Memory Model Aware Atomic Operations + * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html + */ + +#ifndef ATOMIC_H +#define ATOMIC_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include atomic.h" +#endif + +/* Standard includes. */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + /* Needed for __atomic_compare_exchange() weak=false. */ + #include + + /* This branch is for GCC compiler and GCC compiler only. */ + #ifndef portFORCE_INLINE + #define portFORCE_INLINE inline __attribute__((always_inline)) + #endif + +#else + + /* Port specific definitions -- entering/exiting critical section. + * Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h + * + * Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with + * ATOMIC_ENTER_CRITICAL(). + */ + #if defined( portSET_INTERRUPT_MASK_FROM_ISR ) + + /* Nested interrupt scheme is supported in this port. */ + #define ATOMIC_ENTER_CRITICAL() \ + UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR() + + #define ATOMIC_EXIT_CRITICAL() \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType ) + + #else + + /* Nested interrupt scheme is NOT supported in this port. */ + #define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL() + #define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL() + + #endif /* portSET_INTERRUPT_MASK_FROM_ISR() */ + + /* Port specific definition -- "always inline". + * Inline is compiler specific, and may not always get inlined depending on your optimization level. + * For atomic operations, inline is considered a performance optimization. + * Thus, if portFORCE_INLINE is not provided by portmacro.h, instead of resulting error, + * simply define it. + */ + #ifndef portFORCE_INLINE + #define portFORCE_INLINE + #endif + +#endif /* configUSE_GCC_BUILTIN_ATOMICS */ + +#define ATOMIC_COMPARE_AND_SWAP_SUCCESS 0x1U /**< Compare and swap succeeded, swapped. */ +#define ATOMIC_COMPARE_AND_SWAP_FAILURE 0x0U /**< Compare and swap failed, did not swap. */ + +/*----------------------------- Swap && CAS ------------------------------*/ + +/** + * Atomic compare-and-swap + * + * @brief Performs an atomic compare-and-swap operation on the specified values. + * + * @param[in, out] pDestination Pointer to memory location from where value is + * to be loaded and checked. + * @param[in] ulExchange If condition meets, write this value to memory. + * @param[in] ulComparand Swap condition. + * + * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. + * + * @note This function only swaps *pDestination with ulExchange, if previous + * *pDestination value equals ulComparand. + */ +static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32( + uint32_t volatile * pDestination, + uint32_t ulExchange, + uint32_t ulComparand ) +{ + + uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + if ( __atomic_compare_exchange( pDestination, + &ulComparand, + &ulExchange, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST ) ) + { + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + +#else + + ATOMIC_ENTER_CRITICAL(); + + if ( *pDestination == ulComparand ) + { + *pDestination = ulExchange; + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return ulReturnValue; + +} + +/** + * Atomic swap (pointers) + * + * @brief Atomically sets the address pointed to by *ppDestination to the value + * of *pExchange. + * + * @param[in, out] ppDestination Pointer to memory location from where a pointer + * value is to be loaded and written back to. + * @param[in] pExchange Pointer value to be written to *ppDestination. + * + * @return The initial value of *ppDestination. + */ +static portFORCE_INLINE void * Atomic_SwapPointers_p32( + void * volatile * ppDestination, + void * pExchange ) +{ + void * pReturnValue; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + __atomic_exchange( ppDestination, &pExchange, &pReturnValue, __ATOMIC_SEQ_CST ); + +#else + + ATOMIC_ENTER_CRITICAL(); + + pReturnValue = *ppDestination; + + *ppDestination = pExchange; + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return pReturnValue; +} + +/** + * Atomic compare-and-swap (pointers) + * + * @brief Performs an atomic compare-and-swap operation on the specified pointer + * values. + * + * @param[in, out] ppDestination Pointer to memory location from where a pointer + * value is to be loaded and checked. + * @param[in] pExchange If condition meets, write this value to memory. + * @param[in] pComparand Swap condition. + * + * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. + * + * @note This function only swaps *ppDestination with pExchange, if previous + * *ppDestination value equals pComparand. + */ +static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32( + void * volatile * ppDestination, + void * pExchange, void * pComparand ) +{ + uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + if ( __atomic_compare_exchange( ppDestination, + &pComparand, + &pExchange, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST ) ) + { + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + +#else + + ATOMIC_ENTER_CRITICAL(); + + if ( *ppDestination == pComparand ) + { + *ppDestination = pExchange; + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return ulReturnValue; +} + + +/*----------------------------- Arithmetic ------------------------------*/ + +/** + * Atomic add + * + * @brief Atomically adds count to the value of the specified pointer points to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * @param[in] ulCount Value to be added to *pAddend. + * + * @return previous *pAddend value. + */ +static portFORCE_INLINE uint32_t Atomic_Add_u32( + uint32_t volatile * pAddend, + uint32_t ulCount ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_add(pAddend, ulCount, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend += ulCount; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic subtract + * + * @brief Atomically subtracts count from the value of the specified pointer + * pointers to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * @param[in] ulCount Value to be subtract from *pAddend. + * + * @return previous *pAddend value. + */ +static portFORCE_INLINE uint32_t Atomic_Subtract_u32( + uint32_t volatile * pAddend, + uint32_t ulCount ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_sub(pAddend, ulCount, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend -= ulCount; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic increment + * + * @brief Atomically increments the value of the specified pointer points to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * + * @return *pAddend value before increment. + */ +static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pAddend ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_add(pAddend, 1, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend += 1; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic decrement + * + * @brief Atomically decrements the value of the specified pointer points to + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * + * @return *pAddend value before decrement. + */ +static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pAddend ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_sub(pAddend, 1, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend -= 1; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/*----------------------------- Bitwise Logical ------------------------------*/ + +/** + * Atomic OR + * + * @brief Performs an atomic OR operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be ORed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_OR_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_or(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination |= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic AND + * + * @brief Performs an atomic AND operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be ANDed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_AND_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_and(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination &= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic NAND + * + * @brief Performs an atomic NAND operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be NANDed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_NAND_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_nand(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination = ~(ulCurrent & ulValue); + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic XOR + * + * @brief Performs an atomic XOR operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be XORed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_XOR_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_xor(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination ^= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif /* ATOMIC_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/FreeRTOS_POSIX.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/FreeRTOS_POSIX.h new file mode 100644 index 000000000..de88b80aa --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/FreeRTOS_POSIX.h @@ -0,0 +1,50 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX.h + * @brief FreeRTOS+POSIX header. + * + * This file must be included before all other FreeRTOS+POSIX includes. + */ + +#ifndef _FREERTOS_POSIX_H_ +#define _FREERTOS_POSIX_H_ + +/* FreeRTOS+POSIX platform-specific configuration headers. */ +#include "FreeRTOS_POSIX_portable.h" +#include "FreeRTOS_POSIX_portable_default.h" + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "event_groups.h" +#include "semphr.h" +#include "task.h" + +/* FreeRTOS+POSIX data types and internal structs. */ +#include "FreeRTOS_POSIX/sys/types.h" +#include "FreeRTOS_POSIX_internal.h" + +#endif /* _FREERTOS_POSIX_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/FreeRTOS_POSIX_internal.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/FreeRTOS_POSIX_internal.h new file mode 100644 index 000000000..3f88bb13c --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/FreeRTOS_POSIX_internal.h @@ -0,0 +1,129 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef _FREERTOS_POSIX_INTERNAL_H_ +#define _FREERTOS_POSIX_INTERNAL_H_ + +/** + * @file FreeRTOS_POSIX_internal.h + * @brief Internal structs and initializers for FreeRTOS+POSIX. + */ + +/* Amazon FreeRTOS includes. */ +#include "iot_doubly_linked_list.h" + +/** + * @brief Mutex attribute object. + */ +#if posixconfigENABLE_PTHREAD_MUTEXATTR_T == 1 + typedef struct pthread_mutexattr_internal + { + int iType; /**< Mutex type. */ + } pthread_mutexattr_internal_t; +#endif + +#if posixconfigENABLE_PTHREAD_MUTEX_T == 1 + +/** + * @brief Mutex. + */ + typedef struct pthread_mutex_internal + { + BaseType_t xIsInitialized; /**< Set to pdTRUE if this mutex is initialized, pdFALSE otherwise. */ + StaticSemaphore_t xMutex; /**< FreeRTOS mutex. */ + TaskHandle_t xTaskOwner; /**< Owner; used for deadlock detection and permission checks. */ + pthread_mutexattr_internal_t xAttr; /**< Mutex attributes. */ + } pthread_mutex_internal_t; + +/** + * @brief Compile-time initializer of pthread_mutex_internal_t. + */ + #define FREERTOS_POSIX_MUTEX_INITIALIZER \ + ( ( ( pthread_mutex_internal_t ) \ + { \ + .xIsInitialized = pdFALSE, \ + .xMutex = { { 0 } }, \ + .xTaskOwner = NULL, \ + .xAttr = { .iType = 0 } \ + } \ + ) \ + ) +#endif /* if posixconfigENABLE_PTHREAD_MUTEX_T == 1 */ + +#if posixconfigENABLE_PTHREAD_COND_T == 1 + +/** + * @brief Condition variable. + */ + typedef struct pthread_cond_internal + { + BaseType_t xIsInitialized; /**< Set to pdTRUE if this condition variable is initialized, pdFALSE otherwise. */ + StaticSemaphore_t xCondWaitSemaphore; /**< Threads block on this semaphore in pthread_cond_wait. */ + unsigned iWaitingThreads; /**< The number of threads currently waiting on this condition variable. */ + } pthread_cond_internal_t; + +/** + * @brief Compile-time initializer of pthread_cond_internal_t. + */ + + #define FREERTOS_POSIX_COND_INITIALIZER \ + ( ( ( pthread_cond_internal_t ) \ + { \ + .xIsInitialized = pdFALSE, \ + .xCondWaitSemaphore = { { 0 } }, \ + .iWaitingThreads = 0 \ + } \ + ) \ + ) + +#endif /* if posixconfigENABLE_PTHREAD_COND_T == 1 */ + +#if posixconfigENABLE_SEM_T == 1 + +/** + * @brief Semaphore type. + */ + typedef struct + { + StaticSemaphore_t xSemaphore; /**< FreeRTOS semaphore. */ + int value; /**< POSIX semaphore count. */ + } sem_internal_t; +#endif /* if posixconfigENABLE_SEM_T == 1 */ + +#if posixconfigENABLE_PTHREAD_BARRIER_T == 1 + +/** + * @brief Barrier object. + */ + typedef struct pthread_barrier_internal + { + unsigned uThreadCount; /**< Current number of threads that have entered barrier. */ + unsigned uThreshold; /**< The count argument of pthread_barrier_init. */ + StaticSemaphore_t xThreadCountSemaphore; /**< Prevents more than uThreshold threads from exiting pthread_barrier_wait at once. */ + StaticEventGroup_t xBarrierEventGroup; /**< FreeRTOS event group that blocks to wait on threads entering barrier. */ + } pthread_barrier_internal_t; +#endif /* if posixconfigENABLE_PTHREAD_BARRIER_T == 1 */ + +#endif /* _FREERTOS_POSIX_INTERNAL_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/FreeRTOS_POSIX_types.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/FreeRTOS_POSIX_types.h new file mode 100644 index 000000000..90233ecc6 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/FreeRTOS_POSIX_types.h @@ -0,0 +1,81 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef _FREERTOS_POSIX_INTERNAL_TYPES_H_ +#define _FREERTOS_POSIX_INTERNAL_TYPES_H_ + +#include "FreeRTOS_POSIX_internal.h" + +/* + * sys/types.h defines a POSIX type when posixconfigENABLE_PTHREAD__T + * is not defined AND when posixconfigENABLE_PTHREAD__T is set to 1. + * FreeRTOS_POSIX_internal.h defines internal type ONLY when + * posixconfigENABLE_PTHREAD__T is set to 1. + * #else part below is to have a type defined, so the code compiles, when + * posixconfigENABLE_PTHREAD__T is not defined. + */ +#if posixconfigENABLE_PTHREAD_MUTEX_T == 1 + typedef pthread_mutex_internal_t PthreadMutexType_t; +#else + typedef void * PthreadMutexType_t; +#endif + +#if posixconfigENABLE_PTHREAD_COND_T == 1 + typedef pthread_cond_internal_t PthreadCondType_t; +#else + typedef void * PthreadCondType_t; +#endif + +#if posixconfigENABLE_SEM_T == 1 + typedef sem_internal_t PosixSemType_t; +#else + typedef void * PosixSemType_t; +#endif + +#if posixconfigENABLE_PTHREAD_MUTEXATTR_T == 1 + typedef struct pthread_mutexattr + { + uint32_t ulpthreadMutexAttrStorage; + } PthreadMutexAttrType_t; +#else + typedef void * PthreadMutexAttrType_t; +#endif + +#if posixconfigENABLE_PTHREAD_ATTR_T == 1 + typedef struct pthread_attr + { + uint32_t ulpthreadAttrStorage; + } PthreadAttrType_t; +#else + typedef void * PthreadAttrType_t; +#endif + +#if posixconfigENABLE_PTHREAD_BARRIER_T == 1 + typedef pthread_barrier_internal_t PthreadBarrierType_t; +#else + typedef void * PthreadBarrierType_t; +#endif + +#endif /* _FREERTOS_POSIX_INTERNAL_TYPES_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/FreeRTOS_POSIX_portable_default.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/FreeRTOS_POSIX_portable_default.h new file mode 100644 index 000000000..38c7a0070 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/FreeRTOS_POSIX_portable_default.h @@ -0,0 +1,145 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_portable_default.h + * @brief Defaults for port-specific configuration of FreeRTOS+POSIX. + */ + +#ifndef _FREERTOS_POSIX_PORTABLE_DEFAULT_H_ +#define _FREERTOS_POSIX_PORTABLE_DEFAULT_H_ + +/** + * @name The FreeRTOS task name given to pthreads. + */ +/**@{ */ +#ifndef posixconfigPTHREAD_TASK_NAME + #define posixconfigPTHREAD_TASK_NAME "pthread" /**< Task name. */ +#endif +/**@} */ + +/** + * @name the FreeRTOS timer name given to POSIX timers. + */ +/**@{ */ +#ifndef posixconfigTIMER_NAME + #define posixconfigTIMER_NAME "timer" /**< Timer name. */ +#endif +/**@} */ + +/** + * @name Defaults for POSIX message queue implementation. + */ +/**@{ */ +#ifndef posixconfigMQ_MAX_MESSAGES + #define posixconfigMQ_MAX_MESSAGES 10 /**< Maximum number of messages in an mq at one time. */ +#endif + +#ifndef posixconfigMQ_MAX_SIZE + #define posixconfigMQ_MAX_SIZE 128 /**< Maximum size (in bytes) of each message. */ +#endif +/**@} */ + +/** + * @name POSIX implementation-dependent constants usually defined in limits.h. + * + * They are defined here to provide portability between platforms. + */ +/**@{ */ +#ifndef PTHREAD_STACK_MIN + #define PTHREAD_STACK_MIN configMINIMAL_STACK_SIZE * sizeof( StackType_t ) /**< Minimum size in bytes of thread stack storage. */ +#endif +#ifndef NAME_MAX + #define NAME_MAX 64 /**< Maximum number of bytes in a filename (not including terminating null). */ +#endif +#ifndef SEM_VALUE_MAX + #define SEM_VALUE_MAX 0x7FFFU /**< Maximum value of a sem_t. */ +#endif +/**@} */ + +/** + * @name Enable typedefs of POSIX types. + * + * Set these values to 1 or 0 to enable or disable the typedefs, respectively. + * These typedefs should only be disabled if they conflict with system typedefs. + */ +/**@{ */ +#ifndef posixconfigENABLE_CLOCK_T + #define posixconfigENABLE_CLOCK_T 1 /**< clock_t in sys/types.h */ +#endif +#ifndef posixconfigENABLE_CLOCKID_T + #define posixconfigENABLE_CLOCKID_T 1 /**< clockid_t in sys/types.h */ +#endif +#ifndef posixconfigENABLE_MODE_T + #define posixconfigENABLE_MODE_T 1 /**< mode_t in sys/types.h */ +#endif +#ifndef posixconfigENABLE_PID_T + #define posixconfigENABLE_PID_T 1 /**< pid_t in sys/types.h */ +#endif +#ifndef posixconfigENABLE_PTHREAD_ATTR_T + #define posixconfigENABLE_PTHREAD_ATTR_T 1 /**< pthread_attr_t in sys/types.h */ +#endif +#ifndef posixconfigENABLE_PTHREAD_COND_T + #define posixconfigENABLE_PTHREAD_COND_T 1 /**< pthread_cond_t in sys/types.h */ +#endif +#ifndef posixconfigENABLE_PTHREAD_CONDATTR_T + #define posixconfigENABLE_PTHREAD_CONDATTR_T 1 /**< pthread_condattr_t in sys/types.h */ +#endif +#ifndef posixconfigENABLE_PTHREAD_MUTEX_T + #define posixconfigENABLE_PTHREAD_MUTEX_T 1 /**< pthread_mutex_t in sys/types.h */ +#endif +#ifndef posixconfigENABLE_PTHREAD_MUTEXATTR_T + #define posixconfigENABLE_PTHREAD_MUTEXATTR_T 1 /**< pthread_mutexattr_t in sys/types.h */ +#endif +#ifndef posixconfigENABLE_PTHREAD_T + #define posixconfigENABLE_PTHREAD_T 1 /**< pthread_t in sys/types.h */ +#endif +#ifndef posixconfigENABLE_SSIZE_T + #define posixconfigENABLE_SSIZE_T 1 /**< ssize_t in sys/types.h */ +#endif +#ifndef posixconfigENABLE_TIME_T + #define posixconfigENABLE_TIME_T 1 /**< time_t in sys/types.h */ +#endif +#ifndef posixconfigENABLE_TIMER_T + #define posixconfigENABLE_TIMER_T 1 /**< timer_t in sys/types.h */ +#endif +#ifndef posixconfigENABLE_USECONDS_T + #define posixconfigENABLE_USECONDS_T 1 /**< useconds_t in sys/types.h */ +#endif +#ifndef posixconfigENABLE_TIMESPEC + #define posixconfigENABLE_TIMESPEC 1 /**< struct timespec in time.h */ +#endif +#ifndef posixconfigENABLE_ITIMERSPEC + #define posixconfigENABLE_ITIMERSPEC 1 /**< struct itimerspec in time.h */ +#endif +#ifndef posixconfigENABLE_SEM_T + #define posixconfigENABLE_SEM_T 1 /**< struct sem_t in semaphore.h */ +#endif +#ifndef posixconfigENABLE_PTHREAD_BARRIER_T + #define posixconfigENABLE_PTHREAD_BARRIER_T 1 /**< pthread_barrier_t in sys/types.h */ +#endif +/**@} */ + +#endif /* ifndef _FREERTOS_POSIX_PORTABLE_DEFAULT_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/espressif/esp32_devkitc_esp_wrover_kit/FreeRTOS_POSIX_portable.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/espressif/esp32_devkitc_esp_wrover_kit/FreeRTOS_POSIX_portable.h new file mode 100644 index 000000000..5ede08cb6 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/espressif/esp32_devkitc_esp_wrover_kit/FreeRTOS_POSIX_portable.h @@ -0,0 +1,60 @@ +/* + * Amazon FreeRTOS+POSIX V1.0.4 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_portable.h + * @brief Port-specific configuration of FreeRTOS+POSIX. + */ + +#ifndef _FREERTOS_POSIX_PORTABLE_H_ +#define _FREERTOS_POSIX_PORTABLE_H_ + +/* ESP-IDF already defines the following types. */ +#define posixconfigENABLE_CLOCK_T 0 +#define posixconfigENABLE_CLOCKID_T 0 +#define posixconfigENABLE_MODE_T 0 +#define posixconfigENABLE_PTHREAD_ATTR_T 0 +#define posixconfigENABLE_PTHREAD_COND_T 0 +#define posixconfigENABLE_PTHREAD_CONDATTR_T 0 +#define posixconfigENABLE_PTHREAD_MUTEX_T 0 +#define posixconfigENABLE_PTHREAD_MUTEXATTR_T 0 +#define posixconfigENABLE_PTHREAD_T 0 +#define posixconfigENABLE_TIME_T 0 +#define posixconfigENABLE_TIMESPEC 0 +#define posixconfigENABLE_ITIMERSPEC 0 + +/* ESP-IDF already provides the header sched.h. Exclude FreeRTOS+POSIX sched.h by + * defining its double inclusion guard. */ +#define _FREERTOS_POSIX_SCHED_H_ + +/* Use the FreeRTOS+POSIX time.h header instead of the ESP-IDF time.h. Disable + * ESP-IDF time.h by defining its double inclusion guard. */ +#define _TIME_H_ + +/* Disable the timer_t type defined by ESP-IDF. */ +#define __timer_t_defined +#include + +#endif /* _FREERTOS_POSIX_PORTABLE_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/microchip/curiosity_pic32mzef/FreeRTOS_POSIX_portable.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/microchip/curiosity_pic32mzef/FreeRTOS_POSIX_portable.h new file mode 100644 index 000000000..7ebbc346f --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/microchip/curiosity_pic32mzef/FreeRTOS_POSIX_portable.h @@ -0,0 +1,50 @@ +/* + * Amazon FreeRTOS+POSIX V1.0.4 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_portable.h + * @brief Port-specific configuration of FreeRTOS+POSIX. + */ + +#ifndef _FREERTOS_POSIX_PORTABLE_H_ +#define _FREERTOS_POSIX_PORTABLE_H_ + +/* Microchip includes. */ +#include + +/* Microchip already typedefs the following types. */ +#define posixconfigENABLE_MODE_T 0 +#define posixconfigENABLE_PID_T 0 +#define posixconfigENABLE_SSIZE_T 0 +#define posixconfigENABLE_USECONDS_T 0 +/* Microchip -mnewlib compiler option supports these types. */ +#define posixconfigENABLE_TIMESPEC 0 +#define posixconfigENABLE_ITIMERSPEC 0 +#define posixconfigENABLE_CLOCKID_T 0 +#define posixconfigENABLE_TIME_T 0 +#define posixconfigENABLE_TIMER_T 0 + + +#endif /* _FREERTOS_POSIX_PORTABLE_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/nxp/lpc54018iotmodule/FreeRTOS_POSIX_portable.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/nxp/lpc54018iotmodule/FreeRTOS_POSIX_portable.h new file mode 100644 index 000000000..f6d95cad6 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/nxp/lpc54018iotmodule/FreeRTOS_POSIX_portable.h @@ -0,0 +1,37 @@ +/* + * Amazon FreeRTOS+POSIX V1.0.4 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_portable.h + * @brief Port-specific configuration of FreeRTOS+POSIX. + */ + +#ifndef _FREERTOS_POSIX_PORTABLE_H_ +#define _FREERTOS_POSIX_PORTABLE_H_ + +/* This port uses the defaults in FreeRTOS_POSIX_portable_default.h, so this + * file is empty. */ + +#endif /* _FREERTOS_POSIX_PORTABLE_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/pc/windows/FreeRTOS_POSIX_portable.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/pc/windows/FreeRTOS_POSIX_portable.h new file mode 100644 index 000000000..f6d95cad6 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/pc/windows/FreeRTOS_POSIX_portable.h @@ -0,0 +1,37 @@ +/* + * Amazon FreeRTOS+POSIX V1.0.4 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_portable.h + * @brief Port-specific configuration of FreeRTOS+POSIX. + */ + +#ifndef _FREERTOS_POSIX_PORTABLE_H_ +#define _FREERTOS_POSIX_PORTABLE_H_ + +/* This port uses the defaults in FreeRTOS_POSIX_portable_default.h, so this + * file is empty. */ + +#endif /* _FREERTOS_POSIX_PORTABLE_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/st/stm32l475_discovery/FreeRTOS_POSIX_portable.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/st/stm32l475_discovery/FreeRTOS_POSIX_portable.h new file mode 100644 index 000000000..f6d95cad6 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/st/stm32l475_discovery/FreeRTOS_POSIX_portable.h @@ -0,0 +1,37 @@ +/* + * Amazon FreeRTOS+POSIX V1.0.4 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_portable.h + * @brief Port-specific configuration of FreeRTOS+POSIX. + */ + +#ifndef _FREERTOS_POSIX_PORTABLE_H_ +#define _FREERTOS_POSIX_PORTABLE_H_ + +/* This port uses the defaults in FreeRTOS_POSIX_portable_default.h, so this + * file is empty. */ + +#endif /* _FREERTOS_POSIX_PORTABLE_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/ti/cc3220_launchpad/FreeRTOS_POSIX_portable.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/ti/cc3220_launchpad/FreeRTOS_POSIX_portable.h new file mode 100644 index 000000000..f6d95cad6 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/include/portable/ti/cc3220_launchpad/FreeRTOS_POSIX_portable.h @@ -0,0 +1,37 @@ +/* + * Amazon FreeRTOS+POSIX V1.0.4 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_portable.h + * @brief Port-specific configuration of FreeRTOS+POSIX. + */ + +#ifndef _FREERTOS_POSIX_PORTABLE_H_ +#define _FREERTOS_POSIX_PORTABLE_H_ + +/* This port uses the defaults in FreeRTOS_POSIX_portable_default.h, so this + * file is empty. */ + +#endif /* _FREERTOS_POSIX_PORTABLE_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_clock.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_clock.c new file mode 100644 index 000000000..1c2b803e0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_clock.c @@ -0,0 +1,240 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_clock.c + * @brief Implementation of clock functions in time.h + */ + +/* C standard library includes. */ +#include +#include + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX.h" +#include "FreeRTOS_POSIX/errno.h" +#include "FreeRTOS_POSIX/time.h" +#include "FreeRTOS_POSIX/utils.h" + +/* Declaration of snprintf. The header stdio.h is not included because it + * includes conflicting symbols on some platforms. */ +extern int snprintf( char * s, + size_t n, + const char * format, + ... ); + +/*-----------------------------------------------------------*/ + +clock_t clock( void ) +{ + /* This function is currently unsupported. It will always return -1. */ + + return ( clock_t ) -1; +} + +/*-----------------------------------------------------------*/ + +int clock_getcpuclockid( pid_t pid, + clockid_t * clock_id ) +{ + /* Silence warnings about unused parameters. */ + ( void ) pid; + ( void ) clock_id; + + /* This function is currently unsupported. It will always return EPERM. */ + return EPERM; +} + +/*-----------------------------------------------------------*/ + +int clock_getres( clockid_t clock_id, + struct timespec * res ) +{ + /* Silence warnings about unused parameters. */ + ( void ) clock_id; + + /* Convert FreeRTOS tick resolution as timespec. */ + if( res != NULL ) + { + res->tv_sec = 0; + res->tv_nsec = NANOSECONDS_PER_TICK; + } + + return 0; +} + +/*-----------------------------------------------------------*/ + +int clock_gettime( clockid_t clock_id, + struct timespec * tp ) +{ + TimeOut_t xCurrentTime = { 0 }; + + /* Intermediate variable used to convert TimeOut_t to struct timespec. + * Also used to detect overflow issues. It must be unsigned because the + * behavior of signed integer overflow is undefined. */ + uint64_t ullTickCount = 0ULL; + + /* Silence warnings about unused parameters. */ + ( void ) clock_id; + + /* Get the current tick count and overflow count. vTaskSetTimeOutState() + * is used to get these values because they are both static in tasks.c. */ + vTaskSetTimeOutState( &xCurrentTime ); + + /* Adjust the tick count for the number of times a TickType_t has overflowed. + * portMAX_DELAY should be the maximum value of a TickType_t. */ + ullTickCount = ( uint64_t ) ( xCurrentTime.xOverflowCount ) << ( sizeof( TickType_t ) * 8 ); + + /* Add the current tick count. */ + ullTickCount += xCurrentTime.xTimeOnEntering; + + /* Convert ullTickCount to timespec. */ + UTILS_NanosecondsToTimespec( ( int64_t ) ullTickCount * NANOSECONDS_PER_TICK, tp ); + + return 0; +} + +/*-----------------------------------------------------------*/ + +int clock_nanosleep( clockid_t clock_id, + int flags, + const struct timespec * rqtp, + struct timespec * rmtp ) +{ + int iStatus = 0; + TickType_t xSleepTime = 0; + struct timespec xCurrentTime = { 0 }; + + /* Silence warnings about unused parameters. */ + ( void ) clock_id; + ( void ) rmtp; + ( void ) flags; /* This is only ignored if INCLUDE_vTaskDelayUntil is 0. */ + + /* Check rqtp. */ + if( UTILS_ValidateTimespec( rqtp ) == false ) + { + iStatus = EINVAL; + } + + /* Get current time */ + if( ( iStatus == 0 ) && ( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 ) ) + { + iStatus = EINVAL; + } + + if( iStatus == 0 ) + { + /* Check for absolute time sleep. */ + if( ( flags & TIMER_ABSTIME ) == TIMER_ABSTIME ) + { + /* Get current time */ + if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 ) + { + iStatus = EINVAL; + } + + /* Get number of ticks until absolute time. */ + if( ( iStatus == 0 ) && ( UTILS_AbsoluteTimespecToDeltaTicks( rqtp, &xCurrentTime, &xSleepTime ) == 0 ) ) + { + /* Delay until absolute time if vTaskDelayUntil is available. */ + #if ( INCLUDE_vTaskDelayUntil == 1 ) + + /* Get the current tick count. This variable isn't declared + * at the top of the function because it's only used and needed + * if vTaskDelayUntil is available. */ + TickType_t xCurrentTicks = xTaskGetTickCount(); + + /* Delay until absolute time. */ + vTaskDelayUntil( &xCurrentTicks, xSleepTime ); + #else + + /* If vTaskDelayUntil isn't available, ignore the TIMER_ABSTIME flag + * and sleep for a relative time. */ + vTaskDelay( xSleepTime ); + #endif + } + } + else + { + /* If TIMER_ABSTIME isn't specified, convert rqtp to ticks and + * sleep for a relative time. */ + if( UTILS_TimespecToTicks( rqtp, &xSleepTime ) == 0 ) + { + vTaskDelay( xSleepTime ); + } + } + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int clock_settime( clockid_t clock_id, + const struct timespec * tp ) +{ + /* Silence warnings about unused parameters. */ + ( void ) clock_id; + ( void ) tp; + + /* This function is currently unsupported. It will always return -1 and + * set errno to EPERM. */ + errno = EPERM; + + return -1; +} + +/*-----------------------------------------------------------*/ + +int nanosleep( const struct timespec * rqtp, + struct timespec * rmtp ) +{ + int iStatus = 0; + TickType_t xSleepTime = 0; + + /* Silence warnings about unused parameters. */ + ( void ) rmtp; + + /* Check rqtp. */ + if( UTILS_ValidateTimespec( rqtp ) == false ) + { + errno = EINVAL; + iStatus = -1; + } + + if( iStatus == 0 ) + { + /* Convert rqtp to ticks and delay. */ + if( UTILS_TimespecToTicks( rqtp, &xSleepTime ) == 0 ) + { + vTaskDelay( xSleepTime ); + } + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_mqueue.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_mqueue.c new file mode 100644 index 000000000..c14567486 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_mqueue.c @@ -0,0 +1,893 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_mqueue.c + * @brief Implementation of message queue functions in mqueue.h + */ + +/* C standard library includes. */ +#include + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX.h" +#include "FreeRTOS_POSIX/errno.h" +#include "FreeRTOS_POSIX/fcntl.h" +#include "FreeRTOS_POSIX/mqueue.h" +#include "FreeRTOS_POSIX/utils.h" + +/** + * @brief Element of the FreeRTOS queues that store mq data. + */ +typedef struct QueueElement +{ + char * pcData; /**< Data in queue. Type char* to match msg_ptr. */ + size_t xDataSize; /**< Size of data pointed by pcData. */ +} QueueElement_t; + +/** + * @brief Data structure of an mq. + * + * FreeRTOS isn't guaranteed to have a file-like abstraction, so message + * queues in this implementation are stored as a linked list (in RAM). + */ +typedef struct QueueListElement +{ + Link_t xLink; /**< Pointer to the next element in the list. */ + QueueHandle_t xQueue; /**< FreeRTOS queue handle. */ + size_t xOpenDescriptors; /**< Number of threads that have opened this queue. */ + char * pcName; /**< Null-terminated queue name. */ + struct mq_attr xAttr; /**< Queue attibutes. */ + BaseType_t xPendingUnlink; /**< If pdTRUE, this queue will be unlinked once all descriptors close. */ +} QueueListElement_t; + +/*-----------------------------------------------------------*/ + +/** + * @brief Convert an absolute timespec into a tick timeout, taking into account + * queue flags. + * + * @param[in] lMessageQueueFlags Message queue flags to consider. + * @param[in] pxAbsoluteTimeout The absolute timespec to convert. + * @param[out] pxTimeoutTicks Output parameter of the timeout in ticks. + * + * @return 0 if successful; EINVAL if pxAbsoluteTimeout is invalid, or ETIMEDOUT + * if pxAbsoluteTimeout is in the past. + */ +static int prvCalculateTickTimeout( long lMessageQueueFlags, + const struct timespec * const pxAbsoluteTimeout, + TickType_t * pxTimeoutTicks ); + +/** + * @brief Add a new queue to the queue list. + * + * @param[out] ppxMessageQueue Pointer to new queue. + * @param[in] pxAttr mq_attr of the new queue. + * @param[in] pcName Name of new queue. + * @param[in] xNameLength Length of pcName. + * + * @return pdTRUE if the queue is found; pdFALSE otherwise. + */ +static BaseType_t prvCreateNewMessageQueue( QueueListElement_t ** ppxMessageQueue, + const struct mq_attr * const pxAttr, + const char * const pcName, + size_t xNameLength ); + +/** + * @brief Free all the resources used by a message queue. + * + * @param[out] pxMessageQueue Pointer to queue to free. + * + * @return nothing + */ +static void prvDeleteMessageQueue( const QueueListElement_t * const pxMessageQueue ); + +/** + * @brief Attempt to find the queue identified by pcName or xMqId in the queue list. + * + * Matches queues by pcName first; if pcName is NULL, matches by xMqId. + * @param[out] ppxQueueListElement Output parameter set when queue is found. + * @param[in] pcName A queue name to match. + * @param[in] xMessageQueueDescriptor A queue descriptor to match. + * + * @return pdTRUE if the queue is found; pdFALSE otherwise. + */ +static BaseType_t prvFindQueueInList( QueueListElement_t ** const ppxQueueListElement, + const char * const pcName, + mqd_t xMessageQueueDescriptor ); + +/** + * @brief Initialize the queue list. + * + * Performs initialization of the queue list mutex and queue list head. + * + * @return nothing + */ +static void prvInitializeQueueList( void ); + +/** + * @brief Checks that pcName is a valid name for a message queue. + * + * Also outputs the length of pcName. + * @param[in] pcName The name to check. + * @param[out] pxNameLength Output parameter for name length. + * + * @return pdTRUE if the name is valid; pdFALSE otherwise. + */ +static BaseType_t prvValidateQueueName( const char * const pcName, + size_t * pxNameLength ); + +/** + * @brief Guards access to the list of message queues. + */ +static StaticSemaphore_t xQueueListMutex = { { 0 }, .u = { 0 } }; + +/** + * @brief Head of the linked list of queues. + */ +static Link_t xQueueListHead = { 0 }; + +/*-----------------------------------------------------------*/ + +static int prvCalculateTickTimeout( long lMessageQueueFlags, + const struct timespec * const pxAbsoluteTimeout, + TickType_t * pxTimeoutTicks ) +{ + int iStatus = 0; + + /* Check for nonblocking queue. */ + if( lMessageQueueFlags & O_NONBLOCK ) + { + /* No additional checks are done for nonblocking queues. Timeout is 0. */ + *pxTimeoutTicks = 0; + } + else + { + /* No absolute timeout given. Block forever. */ + if( pxAbsoluteTimeout == NULL ) + { + *pxTimeoutTicks = portMAX_DELAY; + } + else + { + struct timespec xCurrentTime = { 0 }; + + /* Check that the given timespec is valid. */ + if( UTILS_ValidateTimespec( pxAbsoluteTimeout ) == false ) + { + iStatus = EINVAL; + } + + /* Get current time */ + if( ( iStatus == 0 ) && ( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 ) ) + { + iStatus = EINVAL; + } + + /* Convert absolute timespec to ticks. */ + if( ( iStatus == 0 ) && + ( UTILS_AbsoluteTimespecToDeltaTicks( pxAbsoluteTimeout, &xCurrentTime, pxTimeoutTicks ) != 0 ) ) + { + iStatus = ETIMEDOUT; + } + } + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +static BaseType_t prvCreateNewMessageQueue( QueueListElement_t ** ppxMessageQueue, + const struct mq_attr * const pxAttr, + const char * const pcName, + size_t xNameLength ) +{ + BaseType_t xStatus = pdTRUE; + + /* Allocate space for a new queue element. */ + *ppxMessageQueue = pvPortMalloc( sizeof( QueueListElement_t ) ); + + /* Check that memory allocation succeeded. */ + if( *ppxMessageQueue == NULL ) + { + xStatus = pdFALSE; + } + + /* Create the FreeRTOS queue. */ + if( xStatus == pdTRUE ) + { + ( *ppxMessageQueue )->xQueue = + xQueueCreate( pxAttr->mq_maxmsg, sizeof( QueueElement_t ) ); + + /* Check that queue creation succeeded. */ + if( ( *ppxMessageQueue )->xQueue == NULL ) + { + vPortFree( *ppxMessageQueue ); + xStatus = pdFALSE; + } + } + + if( xStatus == pdTRUE ) + { + /* Allocate space for the queue name plus null-terminator. */ + ( *ppxMessageQueue )->pcName = pvPortMalloc( xNameLength + 1 ); + + /* Check that memory was successfully allocated for queue name. */ + if( ( *ppxMessageQueue )->pcName == NULL ) + { + vQueueDelete( ( *ppxMessageQueue )->xQueue ); + vPortFree( *ppxMessageQueue ); + xStatus = pdFALSE; + } + else + { + /* Copy queue name. Copying xNameLength+1 will cause strncpy to add + * the null-terminator. */ + ( void ) strncpy( ( *ppxMessageQueue )->pcName, pcName, xNameLength + 1 ); + } + } + + if( xStatus == pdTRUE ) + { + /* Copy attributes. */ + ( *ppxMessageQueue )->xAttr = *pxAttr; + + /* A newly-created queue will have 1 open descriptor for it. */ + ( *ppxMessageQueue )->xOpenDescriptors = 1; + + /* A newly-created queue will not be pending unlink. */ + ( *ppxMessageQueue )->xPendingUnlink = pdFALSE; + + /* Add the new queue to the list. */ + listADD( &xQueueListHead, &( *ppxMessageQueue )->xLink ); + } + + return xStatus; +} + +/*-----------------------------------------------------------*/ + +static void prvDeleteMessageQueue( const QueueListElement_t * const pxMessageQueue ) +{ + QueueElement_t xQueueElement = { 0 }; + + /* Free all data in the queue. It's assumed that no more data will be added + * to the queue, so xQueueReceive does not block. */ + while( xQueueReceive( pxMessageQueue->xQueue, + ( void * ) &xQueueElement, + 0 ) == pdTRUE ) + { + vPortFree( xQueueElement.pcData ); + } + + /* Free memory used by this message queue. */ + vQueueDelete( pxMessageQueue->xQueue ); + vPortFree( ( void * ) pxMessageQueue->pcName ); + vPortFree( ( void * ) pxMessageQueue ); +} + +/*-----------------------------------------------------------*/ + +static BaseType_t prvFindQueueInList( QueueListElement_t ** const ppxQueueListElement, + const char * const pcName, + mqd_t xMessageQueueDescriptor ) +{ + Link_t * pxQueueListLink = NULL; + QueueListElement_t * pxMessageQueue = NULL; + BaseType_t xQueueFound = pdFALSE; + + /* Iterate through the list of queues. */ + listFOR_EACH( pxQueueListLink, &xQueueListHead ) + { + pxMessageQueue = listCONTAINER( pxQueueListLink, QueueListElement_t, xLink ); + + /* Match by name first if provided. */ + if( ( pcName != NULL ) && ( strcmp( pxMessageQueue->pcName, pcName ) == 0 ) ) + { + xQueueFound = pdTRUE; + break; + } + /* If name doesn't match, match by descriptor. */ + else + { + if( ( mqd_t ) pxMessageQueue == xMessageQueueDescriptor ) + { + xQueueFound = pdTRUE; + break; + } + } + } + + /* If the queue was found, set the output parameter. */ + if( ( xQueueFound == pdTRUE ) && ( ppxQueueListElement != NULL ) ) + { + *ppxQueueListElement = pxMessageQueue; + } + + return xQueueFound; +} + +/*-----------------------------------------------------------*/ + +static void prvInitializeQueueList( void ) +{ + /* Keep track of whether the queue list has been initialized. */ + static BaseType_t xQueueListInitialized = pdFALSE; + + /* Check if queue list needs to be initialized. */ + if( xQueueListInitialized == pdFALSE ) + { + /* Initialization must be in a critical section to prevent two threads + * from initializing at the same time. */ + taskENTER_CRITICAL(); + + /* Check again that queue list is still uninitialized, i.e. it wasn't + * initialized while this function was waiting to enter the critical + * section. */ + if( xQueueListInitialized == pdFALSE ) + { + /* Initialize the queue list mutex and list head. */ + ( void ) xSemaphoreCreateMutexStatic( &xQueueListMutex ); + listINIT_HEAD( &xQueueListHead ); + xQueueListInitialized = pdTRUE; + } + + /* Exit the critical section. */ + taskEXIT_CRITICAL(); + } +} + +/*-----------------------------------------------------------*/ + +static BaseType_t prvValidateQueueName( const char * const pcName, + size_t * pxNameLength ) +{ + BaseType_t xStatus = pdTRUE; + size_t xNameLength = 0; + + /* All message queue names must start with '/'. */ + if( pcName[ 0 ] != '/' ) + { + xStatus = pdFALSE; + } + else + { + /* Get the length of pcName, excluding the first '/' and null-terminator. */ + xNameLength = UTILS_strnlen( pcName, NAME_MAX + 2 ); + + if( xNameLength == NAME_MAX + 2 ) + { + /* Name too long. */ + xStatus = pdFALSE; + } + else + { + /* Name length passes, set output parameter. */ + *pxNameLength = xNameLength; + } + } + + return xStatus; +} + +/*-----------------------------------------------------------*/ + +int mq_close( mqd_t mqdes ) +{ + int iStatus = 0; + QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes; + BaseType_t xQueueRemoved = pdFALSE; + + /* Initialize the queue list, if needed. */ + prvInitializeQueueList(); + + /* Lock the mutex that guards access to the queue list. This call will + * never fail because it blocks forever. */ + ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY ); + + /* Attempt to find the message queue based on the given descriptor. */ + if( prvFindQueueInList( NULL, NULL, mqdes ) == pdTRUE ) + { + /* Decrement the number of open descriptors. */ + if( pxMessageQueue->xOpenDescriptors > 0 ) + { + pxMessageQueue->xOpenDescriptors--; + } + + /* Check if the queue has any more open descriptors. */ + if( pxMessageQueue->xOpenDescriptors == 0 ) + { + /* If no open descriptors remain and mq_unlink has already been called, + * remove the queue. */ + if( pxMessageQueue->xPendingUnlink == pdTRUE ) + { + listREMOVE( &pxMessageQueue->xLink ); + + /* Set the flag to delete the queue. Deleting the queue is deferred + * until xQueueListMutex is released. */ + xQueueRemoved = pdTRUE; + } + /* Otherwise, wait for the call to mq_unlink. */ + else + { + pxMessageQueue->xPendingUnlink = pdTRUE; + } + } + } + else + { + /* Queue not found; bad descriptor. */ + errno = EBADF; + iStatus = -1; + } + + /* Release the mutex protecting the queue list. */ + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex ); + + /* Delete all resources used by the queue if needed. */ + if( xQueueRemoved == pdTRUE ) + { + prvDeleteMessageQueue( pxMessageQueue ); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int mq_getattr( mqd_t mqdes, + struct mq_attr * mqstat ) +{ + int iStatus = 0; + QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes; + + /* Lock the mutex that guards access to the queue list. This call will + * never fail because it blocks forever. */ + ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY ); + + /* Find the mq referenced by mqdes. */ + if( prvFindQueueInList( NULL, NULL, mqdes ) == pdTRUE ) + { + /* Update the number of messages in the queue and copy the attributes + * into mqstat. */ + pxMessageQueue->xAttr.mq_curmsgs = ( long ) uxQueueMessagesWaiting( pxMessageQueue->xQueue ); + *mqstat = pxMessageQueue->xAttr; + } + else + { + /* Queue not found; bad descriptor. */ + errno = EBADF; + iStatus = -1; + } + + /* Release the mutex protecting the queue list. */ + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex ); + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +mqd_t mq_open( const char * name, + int oflag, + mode_t mode, + struct mq_attr * attr ) +{ + mqd_t xMessageQueue = NULL; + size_t xNameLength = 0; + + /* Default mq_attr. */ + struct mq_attr xQueueCreationAttr = + { + .mq_flags = 0, + .mq_maxmsg = posixconfigMQ_MAX_MESSAGES, + .mq_msgsize = posixconfigMQ_MAX_SIZE, + .mq_curmsgs = 0 + }; + + /* Silence warnings about unused parameters. */ + ( void ) mode; + + /* Initialize the queue list, if needed. */ + prvInitializeQueueList(); + + /* Check queue name. */ + if( prvValidateQueueName( name, &xNameLength ) == pdFALSE ) + { + /* Invalid name. */ + errno = EINVAL; + xMessageQueue = ( mqd_t ) -1; + } + + /* Check attributes, if given. */ + if( xMessageQueue == NULL ) + { + if( ( oflag & O_CREAT ) && ( attr != NULL ) && ( ( attr->mq_maxmsg <= 0 ) || ( attr->mq_msgsize <= 0 ) ) ) + { + /* Invalid mq_attr.mq_maxmsg or mq_attr.mq_msgsize. */ + errno = EINVAL; + xMessageQueue = ( mqd_t ) -1; + } + } + + if( xMessageQueue == NULL ) + { + /* Lock the mutex that guards access to the queue list. This call will + * never fail because it blocks forever. */ + ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY ); + + /* Search the queue list to check if the queue exists. */ + if( prvFindQueueInList( ( QueueListElement_t ** ) &xMessageQueue, + name, + ( mqd_t ) NULL ) == pdTRUE ) + { + /* If the mq exists, check that this function wasn't called with + * O_CREAT and O_EXCL. */ + if( ( oflag & O_EXCL ) && ( oflag & O_CREAT ) ) + { + errno = EEXIST; + xMessageQueue = ( mqd_t ) -1; + } + else + { + /* Check if the mq has been unlinked and is pending removal. */ + if( ( ( QueueListElement_t * ) xMessageQueue )->xPendingUnlink == pdTRUE ) + { + /* Queue pending deletion. Don't allow it to be re-opened. */ + errno = EINVAL; + xMessageQueue = ( mqd_t ) -1; + } + else + { + /* Increase count of open file descriptors for queue. */ + ( ( QueueListElement_t * ) xMessageQueue )->xOpenDescriptors++; + } + } + } + /* Queue does not exist. */ + else + { + /* Only create the new queue if O_CREAT was specified. */ + if( oflag & O_CREAT ) + { + /* Copy attributes if provided. */ + if( attr != NULL ) + { + xQueueCreationAttr = *attr; + } + + /* Copy oflags. */ + xQueueCreationAttr.mq_flags = ( long ) oflag; + + /* Create the new message queue. */ + if( prvCreateNewMessageQueue( ( QueueListElement_t ** ) &xMessageQueue, + &xQueueCreationAttr, + name, + xNameLength ) == pdFALSE ) + { + errno = ENOSPC; + xMessageQueue = ( mqd_t ) -1; + } + } + else + { + errno = ENOENT; + xMessageQueue = ( mqd_t ) -1; + } + } + + /* Release the mutex protecting the queue list. */ + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex ); + } + + return xMessageQueue; +} + +/*-----------------------------------------------------------*/ + +ssize_t mq_receive( mqd_t mqdes, + char * msg_ptr, + size_t msg_len, + unsigned int * msg_prio ) +{ + return mq_timedreceive( mqdes, msg_ptr, msg_len, msg_prio, NULL ); +} + +/*-----------------------------------------------------------*/ + +int mq_send( mqd_t mqdes, + const char * msg_ptr, + size_t msg_len, + unsigned msg_prio ) +{ + return mq_timedsend( mqdes, msg_ptr, msg_len, msg_prio, NULL ); +} + +/*-----------------------------------------------------------*/ + +ssize_t mq_timedreceive( mqd_t mqdes, + char * msg_ptr, + size_t msg_len, + unsigned * msg_prio, + const struct timespec * abstime ) +{ + ssize_t xStatus = 0; + int iCalculateTimeoutReturn = 0; + TickType_t xTimeoutTicks = 0; + QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes; + QueueElement_t xReceiveData = { 0 }; + + /* Silence warnings about unused parameters. */ + ( void ) msg_prio; + + /* Lock the mutex that guards access to the queue list. This call will + * never fail because it blocks forever. */ + ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY ); + + /* Find the mq referenced by mqdes. */ + if( prvFindQueueInList( NULL, NULL, mqdes ) == pdFALSE ) + { + /* Queue not found; bad descriptor. */ + errno = EBADF; + xStatus = -1; + } + + /* Verify that msg_len is large enough. */ + if( xStatus == 0 ) + { + if( msg_len < ( size_t ) pxMessageQueue->xAttr.mq_msgsize ) + { + /* msg_len too small. */ + errno = EMSGSIZE; + xStatus = -1; + } + } + + if( xStatus == 0 ) + { + /* Convert abstime to a tick timeout. */ + iCalculateTimeoutReturn = prvCalculateTickTimeout( pxMessageQueue->xAttr.mq_flags, + abstime, + &xTimeoutTicks ); + + if( iCalculateTimeoutReturn != 0 ) + { + errno = iCalculateTimeoutReturn; + xStatus = -1; + } + } + + /* Release the mutex protecting the queue list. */ + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex ); + + if( xStatus == 0 ) + { + /* Receive data from the FreeRTOS queue. */ + if( xQueueReceive( pxMessageQueue->xQueue, + &xReceiveData, + xTimeoutTicks ) == pdFALSE ) + { + /* If queue receive fails, set the appropriate errno. */ + if( pxMessageQueue->xAttr.mq_flags & O_NONBLOCK ) + { + /* Set errno to EAGAIN for nonblocking mq. */ + errno = EAGAIN; + } + else + { + /* Otherwise, set errno to ETIMEDOUT. */ + errno = ETIMEDOUT; + } + + xStatus = -1; + } + } + + if( xStatus == 0 ) + { + /* Get the length of data for return value. */ + xStatus = ( ssize_t ) xReceiveData.xDataSize; + + /* Copy received data into given buffer, then free it. */ + ( void ) memcpy( msg_ptr, xReceiveData.pcData, xReceiveData.xDataSize ); + vPortFree( xReceiveData.pcData ); + } + + return xStatus; +} + +/*-----------------------------------------------------------*/ + +int mq_timedsend( mqd_t mqdes, + const char * msg_ptr, + size_t msg_len, + unsigned int msg_prio, + const struct timespec * abstime ) +{ + int iStatus = 0, iCalculateTimeoutReturn = 0; + TickType_t xTimeoutTicks = 0; + QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes; + QueueElement_t xSendData = { 0 }; + + /* Silence warnings about unused parameters. */ + ( void ) msg_prio; + + /* Lock the mutex that guards access to the queue list. This call will + * never fail because it blocks forever. */ + ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY ); + + /* Find the mq referenced by mqdes. */ + if( prvFindQueueInList( NULL, NULL, mqdes ) == pdFALSE ) + { + /* Queue not found; bad descriptor. */ + errno = EBADF; + iStatus = -1; + } + + /* Verify that mq_msgsize is large enough. */ + if( iStatus == 0 ) + { + if( msg_len > ( size_t ) pxMessageQueue->xAttr.mq_msgsize ) + { + /* msg_len too large. */ + errno = EMSGSIZE; + iStatus = -1; + } + } + + if( iStatus == 0 ) + { + /* Convert abstime to a tick timeout. */ + iCalculateTimeoutReturn = prvCalculateTickTimeout( pxMessageQueue->xAttr.mq_flags, + abstime, + &xTimeoutTicks ); + + if( iCalculateTimeoutReturn != 0 ) + { + errno = iCalculateTimeoutReturn; + iStatus = -1; + } + } + + /* Release the mutex protecting the queue list. */ + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex ); + + /* Allocate memory for the message. */ + if( iStatus == 0 ) + { + xSendData.xDataSize = msg_len; + xSendData.pcData = pvPortMalloc( msg_len ); + + /* Check that memory allocation succeeded. */ + if( xSendData.pcData == NULL ) + { + /* msg_len too large. */ + errno = EMSGSIZE; + iStatus = -1; + } + else + { + /* Copy the data to send. */ + ( void ) memcpy( xSendData.pcData, msg_ptr, msg_len ); + } + } + + if( iStatus == 0 ) + { + /* Send data to the FreeRTOS queue. */ + if( xQueueSend( pxMessageQueue->xQueue, + &xSendData, + xTimeoutTicks ) == pdFALSE ) + { + /* If queue send fails, set the appropriate errno. */ + if( pxMessageQueue->xAttr.mq_flags & O_NONBLOCK ) + { + /* Set errno to EAGAIN for nonblocking mq. */ + errno = EAGAIN; + } + else + { + /* Otherwise, set errno to ETIMEDOUT. */ + errno = ETIMEDOUT; + } + + /* Free the allocated queue data. */ + vPortFree( xSendData.pcData ); + + iStatus = -1; + } + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int mq_unlink( const char * name ) +{ + int iStatus = 0; + size_t xNameSize = 0; + BaseType_t xQueueRemoved = pdFALSE; + QueueListElement_t * pxMessageQueue = NULL; + + /* Initialize the queue list, if needed. */ + prvInitializeQueueList(); + + /* Check queue name. */ + if( prvValidateQueueName( name, &xNameSize ) == pdFALSE ) + { + /* Error with mq name. */ + errno = EINVAL; + iStatus = -1; + } + + if( iStatus == 0 ) + { + /* Lock the mutex that guards access to the queue list. This call will + * never fail because it blocks forever. */ + ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY ); + + /* Check if the named queue exists. */ + if( prvFindQueueInList( &pxMessageQueue, name, ( mqd_t ) NULL ) == pdTRUE ) + { + /* If the queue exists and there are no open descriptors to it, + * remove it from the list. */ + if( pxMessageQueue->xOpenDescriptors == 0 ) + { + listREMOVE( &pxMessageQueue->xLink ); + + /* Set the flag to delete the queue. Deleting the queue is deferred + * until xQueueListMutex is released. */ + xQueueRemoved = pdTRUE; + } + else + { + /* If the queue has open descriptors, set the pending unlink flag + * so that mq_close will free its resources. */ + pxMessageQueue->xPendingUnlink = pdTRUE; + } + } + else + { + /* The named message queue doesn't exist. */ + errno = ENOENT; + iStatus = -1; + } + + /* Release the mutex protecting the queue list. */ + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex ); + } + + /* Delete all resources used by the queue if needed. */ + if( xQueueRemoved == pdTRUE ) + { + prvDeleteMessageQueue( pxMessageQueue ); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread.c new file mode 100644 index 000000000..63aec0653 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread.c @@ -0,0 +1,510 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_pthread.c + * @brief Implementation of thread functions in pthread.h + */ + +/* C standard library includes. */ +#include +#include + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX.h" +#include "FreeRTOS_POSIX/errno.h" +#include "FreeRTOS_POSIX/pthread.h" + +/** + * @brief Thread attribute object. + */ +typedef struct pthread_attr_internal +{ + uint16_t usStackSize; /**< Stack size. */ + uint16_t usSchedPriorityDetachState; /**< Schedule priority 15 bits (LSB) Detach state: 1 bits (MSB) */ +} pthread_attr_internal_t; + +#define pthreadDETACH_STATE_MASK 0x8000 +#define pthreadSCHED_PRIORITY_MASK 0x7FFF +#define pthreadDETACH_STATE_SHIFT 15 +#define pthreadGET_SCHED_PRIORITY( var ) ( ( var ) & ( pthreadSCHED_PRIORITY_MASK ) ) +#define pthreadIS_JOINABLE( var ) ( ( ( var ) & ( pthreadDETACH_STATE_MASK ) ) == pthreadDETACH_STATE_MASK ) + +/** + * @brief Thread object. + */ +typedef struct pthread_internal +{ + pthread_attr_internal_t xAttr; /**< Thread attributes. */ + void * ( *pvStartRoutine )( void * ); /**< Application thread function. */ + void * xTaskArg; /**< Arguments for application thread function. */ + TaskHandle_t xTaskHandle; /**< FreeRTOS task handle. */ + StaticSemaphore_t xJoinBarrier; /**< Synchronizes the two callers of pthread_join. */ + StaticSemaphore_t xJoinMutex; /**< Ensures that only one other thread may join this thread. */ + void * xReturn; /**< Return value of pvStartRoutine. */ +} pthread_internal_t; + +/** + * @brief Terminates the calling thread. + * + * For joinable threads, this function waits for pthread_join. Otherwise, + * it deletes the thread and frees up resources used by the thread. + * + * @return This function does not return. + */ +static void prvExitThread( void ); + +/** + * @brief Wrapper function for the user's thread routine. + * + * This function is executed as a FreeRTOS task function. + * @param[in] pxArg A pointer to a pthread_internal_t. + * + * @return nothing + */ +static void prvRunThread( void * pxArg ); + +/** + * @brief Default pthread_attr_t. + */ +static const pthread_attr_internal_t xDefaultThreadAttributes = +{ + .usStackSize = PTHREAD_STACK_MIN, + .usSchedPriorityDetachState = ( ( uint16_t ) tskIDLE_PRIORITY & pthreadSCHED_PRIORITY_MASK ) | ( PTHREAD_CREATE_JOINABLE << pthreadDETACH_STATE_SHIFT ), +}; + +/*-----------------------------------------------------------*/ + +static void prvExitThread( void ) +{ + pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread_self(); + + /* If this thread is joinable, wait for a call to pthread_join. */ + if( pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) ) + { + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier ); + + /* Suspend until the call to pthread_join. The caller of pthread_join + * will perform cleanup. */ + vTaskSuspend( NULL ); + } + else + { + /* For a detached thread, perform cleanup of thread object. */ + vPortFree( pxThread ); + vTaskDelete( NULL ); + } +} + +/*-----------------------------------------------------------*/ + +static void prvRunThread( void * pxArg ) +{ + pthread_internal_t * pxThread = ( pthread_internal_t * ) pxArg; + + /* Run the thread routine. */ + pxThread->xReturn = pxThread->pvStartRoutine( ( void * ) pxThread->xTaskArg ); + + /* Exit once finished. This function does not return. */ + prvExitThread(); +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_destroy( pthread_attr_t * attr ) +{ + ( void ) attr; + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_getdetachstate( const pthread_attr_t * attr, + int * detachstate ) +{ + pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr ); + + if( pthreadIS_JOINABLE( pxAttr->usSchedPriorityDetachState ) ) + { + *detachstate = PTHREAD_CREATE_JOINABLE; + } + else + { + *detachstate = PTHREAD_CREATE_DETACHED; + } + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_getschedparam( const pthread_attr_t * attr, + struct sched_param * param ) +{ + pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr ); + + param->sched_priority = ( int ) ( pthreadGET_SCHED_PRIORITY( pxAttr->usSchedPriorityDetachState ) ); + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_getstacksize( const pthread_attr_t * attr, + size_t * stacksize ) +{ + pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr ); + + *stacksize = ( size_t ) pxAttr->usStackSize; + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_init( pthread_attr_t * attr ) +{ + /* Copy the default values into the new thread attributes object. */ + *( ( pthread_attr_internal_t * ) ( attr ) ) = xDefaultThreadAttributes; + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_setdetachstate( pthread_attr_t * attr, + int detachstate ) +{ + int iStatus = 0; + pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr ); + + if( ( detachstate != PTHREAD_CREATE_DETACHED ) && ( detachstate != PTHREAD_CREATE_JOINABLE ) ) + { + iStatus = EINVAL; + } + else + { + /* clear and then set msb bit to detachstate) */ + pxAttr->usSchedPriorityDetachState &= ~pthreadDETACH_STATE_MASK; + pxAttr->usSchedPriorityDetachState |= ( ( uint16_t ) detachstate << pthreadDETACH_STATE_SHIFT ); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_setschedparam( pthread_attr_t * attr, + const struct sched_param * param ) +{ + int iStatus = 0; + pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr ); + + /* Check for NULL param. */ + if( param == NULL ) + { + iStatus = EINVAL; + } + + /* Ensure that param.sched_priority is valid. */ + if( ( iStatus == 0 ) && + ( ( param->sched_priority > sched_get_priority_max( SCHED_OTHER ) ) || + ( param->sched_priority < 0 ) ) ) + { + iStatus = ENOTSUP; + } + + /* Set the sched_param. */ + if( iStatus == 0 ) + { + /* clear and then set 15 LSB to schedule priority) */ + pxAttr->usSchedPriorityDetachState &= ~pthreadSCHED_PRIORITY_MASK; + pxAttr->usSchedPriorityDetachState |= ( ( uint16_t ) param->sched_priority ); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_setschedpolicy( pthread_attr_t * attr, + int policy ) +{ + /* Silence warnings about unused parameters. */ + ( void ) attr; + ( void ) policy; + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_attr_setstacksize( pthread_attr_t * attr, + size_t stacksize ) +{ + int iStatus = 0; + pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr ); + + if( stacksize < PTHREAD_STACK_MIN ) + { + iStatus = EINVAL; + } + else + { + pxAttr->usStackSize = ( uint16_t ) stacksize; + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_create( pthread_t * thread, + const pthread_attr_t * attr, + void *( *startroutine )( void * ), + void * arg ) +{ + int iStatus = 0; + pthread_internal_t * pxThread = NULL; + struct sched_param xSchedParam = { .sched_priority = tskIDLE_PRIORITY }; + + /* Allocate memory for new thread object. */ + pxThread = ( pthread_internal_t * ) pvPortMalloc( sizeof( pthread_internal_t ) ); + + if( pxThread == NULL ) + { + /* No memory. */ + iStatus = EAGAIN; + } + + if( iStatus == 0 ) + { + /* No attributes given, use default attributes. */ + if( attr == NULL ) + { + pxThread->xAttr = xDefaultThreadAttributes; + } + /* Otherwise, use provided attributes. */ + else + { + pxThread->xAttr = *( ( pthread_attr_internal_t * ) ( attr ) ); + } + + /* Get priority from attributes */ + xSchedParam.sched_priority = ( int ) pthreadGET_SCHED_PRIORITY( pxThread->xAttr.usSchedPriorityDetachState ); + + /* Set argument and start routine. */ + pxThread->xTaskArg = arg; + pxThread->pvStartRoutine = startroutine; + + /* If this thread is joinable, create the synchronization mechanisms for + * pthread_join. */ + + if( pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) ) + { + /* These calls will not fail when their arguments aren't NULL. */ + ( void ) xSemaphoreCreateMutexStatic( &pxThread->xJoinMutex ); + ( void ) xSemaphoreCreateBinaryStatic( &pxThread->xJoinBarrier ); + } + } + + if( iStatus == 0 ) + { + /* Suspend all tasks to create a critical section. This ensures that + * the new thread doesn't exit before a tag is assigned. */ + vTaskSuspendAll(); + + /* Create the FreeRTOS task that will run the pthread. */ + if( xTaskCreate( prvRunThread, + posixconfigPTHREAD_TASK_NAME, + ( uint16_t ) ( pxThread->xAttr.usStackSize / sizeof( StackType_t ) ), + ( void * ) pxThread, + xSchedParam.sched_priority, + &pxThread->xTaskHandle ) != pdPASS ) + { + /* Task creation failed, no memory. */ + vPortFree( pxThread ); + iStatus = EAGAIN; + } + else + { + /* Store the pointer to the thread object in the task tag. */ + vTaskSetApplicationTaskTag( pxThread->xTaskHandle, ( TaskHookFunction_t ) pxThread ); + + /* Set the thread object for the user. */ + *thread = ( pthread_t ) pxThread; + } + + /* End the critical section. */ + xTaskResumeAll(); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_getschedparam( pthread_t thread, + int * policy, + struct sched_param * param ) +{ + int iStatus = 0; + pthread_internal_t * pxThread = ( pthread_internal_t * ) thread; + + *policy = SCHED_OTHER; + param->sched_priority = ( int ) pthreadGET_SCHED_PRIORITY( pxThread->xAttr.usSchedPriorityDetachState ); + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_equal( pthread_t t1, + pthread_t t2 ) +{ + return t1 == t2; +} + +/*-----------------------------------------------------------*/ + +void pthread_exit( void * value_ptr ) +{ + pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread_self(); + + /* Set the return value. */ + pxThread->xReturn = value_ptr; + + /* Exit this thread. */ + prvExitThread(); +} + +/*-----------------------------------------------------------*/ + +int pthread_join( pthread_t pthread, + void ** retval ) +{ + int iStatus = 0; + pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread; + + /* Make sure pthread is joinable. Otherwise, this function would block + * forever waiting for an unjoinable thread. */ + if( !pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) ) + { + iStatus = EDEADLK; + } + + /* Only one thread may attempt to join another. Lock the join mutex + * to prevent other threads from calling pthread_join on the same thread. */ + if( iStatus == 0 ) + { + if( xSemaphoreTake( ( SemaphoreHandle_t ) &pxThread->xJoinMutex, 0 ) != pdPASS ) + { + /* Another thread has already joined the requested thread, which would + * cause this thread to wait forever. */ + iStatus = EDEADLK; + } + } + + /* Attempting to join the calling thread would cause a deadlock. */ + if( iStatus == 0 ) + { + if( pthread_equal( pthread_self(), pthread ) != 0 ) + { + iStatus = EDEADLK; + } + } + + if( iStatus == 0 ) + { + /* Wait for the joining thread to finish. Because this call waits forever, + * it should never fail. */ + ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier, portMAX_DELAY ); + + /* Create a critical section to clean up the joined thread. */ + vTaskSuspendAll(); + + /* Release xJoinBarrier and delete it. */ + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier ); + vSemaphoreDelete( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier ); + + /* Release xJoinMutex and delete it. */ + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinMutex ); + vSemaphoreDelete( ( SemaphoreHandle_t ) &pxThread->xJoinMutex ); + + /* Delete the FreeRTOS task that ran the thread. */ + vTaskDelete( pxThread->xTaskHandle ); + + /* Set the return value. */ + if( retval != NULL ) + { + *retval = pxThread->xReturn; + } + + /* Free the thread object. */ + vPortFree( pxThread ); + + /* End the critical section. */ + xTaskResumeAll(); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +pthread_t pthread_self( void ) +{ + /* Return a reference to this pthread object, which is stored in the + * FreeRTOS task tag. */ + return ( pthread_t ) xTaskGetApplicationTaskTag( NULL ); +} + +/*-----------------------------------------------------------*/ + +int pthread_setschedparam( pthread_t thread, + int policy, + const struct sched_param * param ) +{ + int iStatus = 0; + + pthread_internal_t * pxThread = ( pthread_internal_t * ) thread; + + /* Silence compiler warnings about unused parameters. */ + ( void ) policy; + + /* Copy the given sched_param. */ + iStatus = pthread_attr_setschedparam( ( pthread_attr_t * ) &pxThread->xAttr, param ); + + if( iStatus == 0 ) + { + /* Change the priority of the FreeRTOS task. */ + vTaskPrioritySet( pxThread->xTaskHandle, param->sched_priority ); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_barrier.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_barrier.c new file mode 100644 index 000000000..51d9b2f86 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_barrier.c @@ -0,0 +1,165 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_pthread_barrier.c + * @brief Implementation of barrier functions in pthread.h + */ + +/* C standard library includes. */ +#include + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX.h" +#include "FreeRTOS_POSIX/errno.h" +#include "FreeRTOS_POSIX/pthread.h" + +#include "atomic.h" + +/* + * @brief barrier max count + * + * Barriers are implemented on FreeRTOS event groups, of which 8 bits are usable + * when configUSE_16_BIT_TICKS is 1. Otherwise, 24 bits are usable. + */ +/**@{ */ +#if ( configUSE_16_BIT_TICKS == 1 ) + #define posixPTHREAD_BARRIER_MAX_COUNT ( 8 ) +#else + #define posixPTHREAD_BARRIER_MAX_COUNT ( 24 ) +#endif +/**@} */ + +/*-----------------------------------------------------------*/ + +int pthread_barrier_destroy( pthread_barrier_t * barrier ) +{ + pthread_barrier_internal_t * pxBarrier = ( pthread_barrier_internal_t * ) ( barrier ); + + /* Free all resources used by the barrier. */ + ( void ) vEventGroupDelete( ( EventGroupHandle_t ) &pxBarrier->xBarrierEventGroup ); + ( void ) vSemaphoreDelete( ( SemaphoreHandle_t ) &pxBarrier->xThreadCountSemaphore ); + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_barrier_init( pthread_barrier_t * barrier, + const pthread_barrierattr_t * attr, + unsigned count ) +{ + int iStatus = 0; + pthread_barrier_internal_t * pxNewBarrier = ( pthread_barrier_internal_t * ) ( barrier ); + + /* Silence warnings about unused parameters. */ + ( void ) attr; + + /* Ensure count is greater than 0. */ + if( count == 0 ) + { + iStatus = EINVAL; + } + + /* Ensure that count will fit in a FreeRTOS event group. */ + if( iStatus == 0 ) + { + if( count > posixPTHREAD_BARRIER_MAX_COUNT ) + { + /* No memory exists in the event group for more than + * posixPTHREAD_BARRIER_MAX_COUNT threads. */ + iStatus = ENOMEM; + } + } + + if( iStatus == 0 ) + { + /* Set the current thread count and threshold. */ + pxNewBarrier->uThreadCount = 0; + pxNewBarrier->uThreshold = count; + + /* Create the FreeRTOS event group. This call will not fail when its + * argument isn't NULL. */ + ( void ) xEventGroupCreateStatic( &pxNewBarrier->xBarrierEventGroup ); + + /* Create the semaphore that prevents more than count threads from being + * unblocked by a single successful pthread_barrier_wait. This semaphore + * counts down from count and cannot decrement below 0. */ + ( void ) xSemaphoreCreateCountingStatic( ( UBaseType_t ) count, /* Max count. */ + ( UBaseType_t ) count, /* Initial count. */ + &pxNewBarrier->xThreadCountSemaphore ); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_barrier_wait( pthread_barrier_t * barrier ) +{ + int iStatus = 0; + unsigned i = 0; /* Loop iterator. */ + pthread_barrier_internal_t * pxBarrier = ( pthread_barrier_internal_t * ) ( barrier ); + unsigned uThreadNumber = 0; + + /* Decrement the number of threads waiting on this barrier. This will prevent more + * than pxBarrier->uThreshold threads from being unblocked by a single successful + * pthread_barrier_wait call. + * + * This call will never fail because it blocks forever. + */ + ( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &pxBarrier->xThreadCountSemaphore, portMAX_DELAY ); + + uThreadNumber = Atomic_Increment_u32( ( uint32_t * ) &pxBarrier->uThreadCount ); + + /* Set the bit in the event group representing this thread, then wait for the other + * threads to set their bit. This call should wait forever until all threads have set + * their bit, so the return value is ignored. */ + ( void ) xEventGroupSync( ( EventGroupHandle_t ) &pxBarrier->xBarrierEventGroup, + 1 << uThreadNumber, /* Which bit in the event group to set. */ + ( 1 << pxBarrier->uThreshold ) - 1, /* Wait for all threads to set their bits. */ + portMAX_DELAY ); + + /* The first thread to enter the barrier gets PTHREAD_BARRIER_SERIAL_THREAD as its + * return value and resets xThreadCountSemaphore. */ + + if( uThreadNumber == 0 ) + { + iStatus = PTHREAD_BARRIER_SERIAL_THREAD; + + /* uThreadCount can be safely changed without locking xThreadCountMutex + * because xThreadCountSemaphore is currently 0. */ + pxBarrier->uThreadCount = 0; + + /* Reset xThreadCountSemaphore. This allows more threads to enter the + * barrier, starting a new cycle. */ + for( i = 0; i < pxBarrier->uThreshold; i++ ) + { + xSemaphoreGive( ( SemaphoreHandle_t ) &pxBarrier->xThreadCountSemaphore ); + } + } + + return iStatus; +} diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_cond.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_cond.c new file mode 100644 index 000000000..9c6a73469 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_cond.c @@ -0,0 +1,294 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_pthread_cond.c + * @brief Implementation of condition variable functions in pthread.h + */ + +/* C standard library includes. */ +#include + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX.h" +#include "FreeRTOS_POSIX/errno.h" +#include "FreeRTOS_POSIX/pthread.h" +#include "FreeRTOS_POSIX/utils.h" + +#include "atomic.h" + +/** + * @brief Initialize a PTHREAD_COND_INITIALIZER cond. + * + * PTHREAD_COND_INITIALIZER sets a flag for a cond to be initialized later. + * This function performs the initialization. + * @param[in] pxCond The cond to initialize. + * + * @return nothing + */ +static void prvInitializeStaticCond( pthread_cond_internal_t * pxCond ); + +/*-----------------------------------------------------------*/ + +static void prvInitializeStaticCond( pthread_cond_internal_t * pxCond ) +{ + /* Check if the condition variable needs to be initialized. */ + if( pxCond->xIsInitialized == pdFALSE ) + { + /* Cond initialization must be in a critical section to prevent two threads + * from initializing it at the same time. */ + taskENTER_CRITICAL(); + + /* Check again that the cond is still uninitialized, i.e. it wasn't + * initialized while this function was waiting to enter the critical + * section. */ + if( pxCond->xIsInitialized == pdFALSE ) + { + /* Set the members of the cond. The semaphore create calls will never fail + * when their arguments aren't NULL. */ + pxCond->xIsInitialized = pdTRUE; + ( void ) xSemaphoreCreateCountingStatic( INT_MAX, 0U, &pxCond->xCondWaitSemaphore ); + pxCond->iWaitingThreads = 0; + } + + /* Exit the critical section. */ + taskEXIT_CRITICAL(); + } +} + +/** + * @brief Check "atomically" if iLocalWaitingThreads == pxCond->iWaitingThreads and decrement. + */ +static void prvTestAndDecrement( pthread_cond_t * pxCond, + unsigned iLocalWaitingThreads ) +{ + /* Test local copy of threads waiting is larger than zero. */ + while( iLocalWaitingThreads > 0 ) + { + /* Test-and-set. Atomically check whether the copy in memory has changed. + * And, if not decrease the copy of threads waiting in memory. */ + if( ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32( ( uint32_t * ) &pxCond->iWaitingThreads, ( uint32_t ) iLocalWaitingThreads - 1, ( uint32_t ) iLocalWaitingThreads ) ) + { + /* Signal one succeeded. Break. */ + break; + } + + /* Local copy may be out dated. Reload, and retry. */ + iLocalWaitingThreads = pxCond->iWaitingThreads; + } +} + +/*-----------------------------------------------------------*/ + +int pthread_cond_broadcast( pthread_cond_t * cond ) +{ + unsigned i = 0; + pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond ); + + /* If the cond is uninitialized, perform initialization. */ + prvInitializeStaticCond( pxCond ); + + /* Local copy of number of threads waiting. */ + unsigned iLocalWaitingThreads = pxCond->iWaitingThreads; + + /* Test local copy of threads waiting is larger than zero. */ + while( iLocalWaitingThreads > 0 ) + { + /* Test-and-set. Atomically check whether the copy in memory has changed. + * And, if not set the copy of threads waiting in memory to zero. */ + if( ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32( ( uint32_t * ) &pxCond->iWaitingThreads, 0, ( uint32_t ) iLocalWaitingThreads ) ) + { + /* Unblock all. */ + for( i = 0; i < iLocalWaitingThreads; i++ ) + { + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore ); + } + + break; + } + + /* Local copy is out dated. Reload, and retry. */ + iLocalWaitingThreads = pxCond->iWaitingThreads; + } + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_cond_destroy( pthread_cond_t * cond ) +{ + pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond ); + + /* Free all resources in use by the cond. */ + vSemaphoreDelete( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore ); + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_cond_init( pthread_cond_t * cond, + const pthread_condattr_t * attr ) +{ + int iStatus = 0; + pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) cond; + + /* Silence warnings about unused parameters. */ + ( void ) attr; + + if( pxCond == NULL ) + { + iStatus = ENOMEM; + } + + if( iStatus == 0 ) + { + /* Set the members of the cond. The semaphore create calls will never fail + * when their arguments aren't NULL. */ + pxCond->xIsInitialized = pdTRUE; + + ( void ) xSemaphoreCreateCountingStatic( INT_MAX, 0U, &pxCond->xCondWaitSemaphore ); + pxCond->iWaitingThreads = 0; + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_cond_signal( pthread_cond_t * cond ) +{ + pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond ); + + /* If the cond is uninitialized, perform initialization. */ + prvInitializeStaticCond( pxCond ); + + /* Local copy of number of threads waiting. */ + unsigned iLocalWaitingThreads = pxCond->iWaitingThreads; + + /* Test local copy of threads waiting is larger than zero. */ + while( iLocalWaitingThreads > 0 ) + { + /* Test-and-set. Atomically check whether the copy in memory has changed. + * And, if not decrease the copy of threads waiting in memory. */ + if( ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32( ( uint32_t * ) &pxCond->iWaitingThreads, ( uint32_t ) iLocalWaitingThreads - 1, ( uint32_t ) iLocalWaitingThreads ) ) + { + /* Unblock one. */ + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore ); + + /* Signal one succeeded. Break. */ + break; + } + + /* Local copy may be out dated. Reload, and retry. */ + iLocalWaitingThreads = pxCond->iWaitingThreads; + } + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_cond_timedwait( pthread_cond_t * cond, + pthread_mutex_t * mutex, + const struct timespec * abstime ) +{ + unsigned iLocalWaitingThreads; + int iStatus = 0; + pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond ); + TickType_t xDelay = portMAX_DELAY; + + /* If the cond is uninitialized, perform initialization. */ + prvInitializeStaticCond( pxCond ); + + /* Convert abstime to a delay in TickType_t if provided. */ + if( abstime != NULL ) + { + struct timespec xCurrentTime = { 0 }; + + /* Get current time */ + if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 ) + { + iStatus = EINVAL; + } + else + { + iStatus = UTILS_AbsoluteTimespecToDeltaTicks( abstime, &xCurrentTime, &xDelay ); + } + } + + /* Increase the counter of threads blocking on condition variable, then + * unlock mutex. */ + if( iStatus == 0 ) + { + /* Atomically increments thread waiting by 1, and + * stores number of threads waiting before increment. */ + iLocalWaitingThreads = Atomic_Increment_u32( ( uint32_t * ) &pxCond->iWaitingThreads ); + + iStatus = pthread_mutex_unlock( mutex ); + } + + /* Wait on the condition variable. */ + if( iStatus == 0 ) + { + if( xSemaphoreTake( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore, + xDelay ) == pdPASS ) + { + /* When successful, relock mutex. */ + iStatus = pthread_mutex_lock( mutex ); + } + else + { + /* Timeout. Relock mutex and decrement number of waiting threads. */ + iStatus = ETIMEDOUT; + ( void ) pthread_mutex_lock( mutex ); + + /* Atomically decrements thread waiting by 1. + * If iLocalWaitingThreads is updated by other thread(s) in between, + * this implementation guarantees to decrement by 1 based on the + * value currently in pxCond->iWaitingThreads. */ + prvTestAndDecrement( pxCond, iLocalWaitingThreads + 1 ); + } + } + else + { + /* Atomically decrements thread waiting by 1. + * If iLocalWaitingThreads is updated by other thread(s) in between, + * this implementation guarantees to decrement by 1 based on the + * value currently in pxCond->iWaitingThreads. */ + prvTestAndDecrement( pxCond, iLocalWaitingThreads + 1 ); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_cond_wait( pthread_cond_t * cond, + pthread_mutex_t * mutex ) +{ + return pthread_cond_timedwait( cond, mutex, NULL ); +} \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_mutex.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_mutex.c new file mode 100644 index 000000000..c5dc3c5c1 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_pthread_mutex.c @@ -0,0 +1,373 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_pthread_mutex.c + * @brief Implementation of mutex functions in pthread.h + */ + +/* C standard library includes. */ +#include +#include + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX.h" +#include "FreeRTOS_POSIX/errno.h" +#include "FreeRTOS_POSIX/pthread.h" +#include "FreeRTOS_POSIX/utils.h" + +/** + * @brief Initialize a PTHREAD_MUTEX_INITIALIZER mutex. + * + * PTHREAD_MUTEX_INITIALIZER sets a flag for a mutex to be initialized later. + * This function performs the initialization. + * @param[in] pxMutex The mutex to initialize. + * + * @return nothing + */ +static void prvInitializeStaticMutex( pthread_mutex_internal_t * pxMutex ); + +/** + * @brief Default pthread_mutexattr_t. + */ +static const pthread_mutexattr_internal_t xDefaultMutexAttributes = +{ + .iType = PTHREAD_MUTEX_DEFAULT, +}; + +/*-----------------------------------------------------------*/ + +static void prvInitializeStaticMutex( pthread_mutex_internal_t * pxMutex ) +{ + /* Check if the mutex needs to be initialized. */ + if( pxMutex->xIsInitialized == pdFALSE ) + { + /* Mutex initialization must be in a critical section to prevent two threads + * from initializing it at the same time. */ + taskENTER_CRITICAL(); + + /* Check again that the mutex is still uninitialized, i.e. it wasn't + * initialized while this function was waiting to enter the critical + * section. */ + if( pxMutex->xIsInitialized == pdFALSE ) + { + /* Set the mutex as the default type. */ + pxMutex->xAttr.iType = PTHREAD_MUTEX_DEFAULT; + + /* Call the correct FreeRTOS mutex initialization function based on + * the mutex type. */ + #if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_RECURSIVE + ( void ) xSemaphoreCreateRecursiveMutexStatic( &pxMutex->xMutex ); + #else + ( void ) xSemaphoreCreateMutexStatic( &pxMutex->xMutex ); + #endif + + pxMutex->xIsInitialized = pdTRUE; + } + + /* Exit the critical section. */ + taskEXIT_CRITICAL(); + } +} + +/*-----------------------------------------------------------*/ + +int pthread_mutex_destroy( pthread_mutex_t * mutex ) +{ + pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) ( mutex ); + + /* Free resources in use by the mutex. */ + if( pxMutex->xTaskOwner == NULL ) + { + vSemaphoreDelete( ( SemaphoreHandle_t ) &pxMutex->xMutex ); + } + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_mutex_init( pthread_mutex_t * mutex, + const pthread_mutexattr_t * attr ) +{ + int iStatus = 0; + pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) mutex; + + if( pxMutex == NULL ) + { + /* No memory. */ + iStatus = ENOMEM; + } + + if( iStatus == 0 ) + { + *pxMutex = FREERTOS_POSIX_MUTEX_INITIALIZER; + + /* No attributes given, use default attributes. */ + if( attr == NULL ) + { + pxMutex->xAttr = xDefaultMutexAttributes; + } + /* Otherwise, use provided attributes. */ + else + { + pxMutex->xAttr = *( ( pthread_mutexattr_internal_t * ) ( attr ) ); + } + + /* Call the correct FreeRTOS mutex creation function based on mutex type. */ + if( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE ) + { + /* Recursive mutex. */ + ( void ) xSemaphoreCreateRecursiveMutexStatic( &pxMutex->xMutex ); + } + else + { + /* All other mutex types. */ + ( void ) xSemaphoreCreateMutexStatic( &pxMutex->xMutex ); + } + + /* Ensure that the FreeRTOS mutex was successfully created. */ + if( ( SemaphoreHandle_t ) &pxMutex->xMutex == NULL ) + { + /* Failed to create mutex. Set error EAGAIN and free mutex object. */ + iStatus = EAGAIN; + vPortFree( pxMutex ); + } + else + { + /* Mutex successfully created. */ + pxMutex->xIsInitialized = pdTRUE; + } + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_mutex_lock( pthread_mutex_t * mutex ) +{ + return pthread_mutex_timedlock( mutex, NULL ); +} + +/*-----------------------------------------------------------*/ + +int pthread_mutex_timedlock( pthread_mutex_t * mutex, + const struct timespec * abstime ) +{ + int iStatus = 0; + pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) ( mutex ); + TickType_t xDelay = portMAX_DELAY; + BaseType_t xFreeRTOSMutexTakeStatus = pdFALSE; + + /* If mutex in uninitialized, perform initialization. */ + prvInitializeStaticMutex( pxMutex ); + + /* At this point, the mutex should be initialized. */ + configASSERT( pxMutex->xIsInitialized == pdTRUE ); + + /* Convert abstime to a delay in TickType_t if provided. */ + if( abstime != NULL ) + { + struct timespec xCurrentTime = { 0 }; + + /* Get current time */ + if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 ) + { + iStatus = EINVAL; + } + else + { + iStatus = UTILS_AbsoluteTimespecToDeltaTicks( abstime, &xCurrentTime, &xDelay ); + } + + /* If abstime was in the past, still attempt to lock the mutex without + * blocking, per POSIX spec. */ + if( iStatus == ETIMEDOUT ) + { + xDelay = 0; + iStatus = 0; + } + } + + /* Check if trying to lock a currently owned mutex. */ + if( ( iStatus == 0 ) && + ( pxMutex->xAttr.iType == PTHREAD_MUTEX_ERRORCHECK ) && /* Only PTHREAD_MUTEX_ERRORCHECK type detects deadlock. */ + ( pxMutex->xTaskOwner == xTaskGetCurrentTaskHandle() ) ) /* Check if locking a currently owned mutex. */ + { + iStatus = EDEADLK; + } + + if( iStatus == 0 ) + { + /* Call the correct FreeRTOS mutex take function based on mutex type. */ + if( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE ) + { + xFreeRTOSMutexTakeStatus = xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) &pxMutex->xMutex, xDelay ); + } + else + { + xFreeRTOSMutexTakeStatus = xSemaphoreTake( ( SemaphoreHandle_t ) &pxMutex->xMutex, xDelay ); + } + + /* If the mutex was successfully taken, set its owner. */ + if( xFreeRTOSMutexTakeStatus == pdPASS ) + { + pxMutex->xTaskOwner = xTaskGetCurrentTaskHandle(); + } + /* Otherwise, the mutex take timed out. */ + else + { + iStatus = ETIMEDOUT; + } + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_mutex_trylock( pthread_mutex_t * mutex ) +{ + int iStatus = 0; + struct timespec xTimeout = + { + .tv_sec = 0, + .tv_nsec = 0 + }; + + /* Attempt to lock with no timeout. */ + iStatus = pthread_mutex_timedlock( mutex, &xTimeout ); + + /* POSIX specifies that this function should return EBUSY instead of + * ETIMEDOUT for attempting to lock a locked mutex. */ + if( iStatus == ETIMEDOUT ) + { + iStatus = EBUSY; + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_mutex_unlock( pthread_mutex_t * mutex ) +{ + int iStatus = 0; + pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) ( mutex ); + + /* If mutex in uninitialized, perform initialization. */ + prvInitializeStaticMutex( pxMutex ); + + /* Check if trying to unlock an unowned mutex. */ + if( ( ( pxMutex->xAttr.iType == PTHREAD_MUTEX_ERRORCHECK ) || + ( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE ) ) && + ( pxMutex->xTaskOwner != xTaskGetCurrentTaskHandle() ) ) + { + iStatus = EPERM; + } + + if( iStatus == 0 ) + { + /* Suspend the scheduler so that + * mutex is unlocked AND owner is updated atomically */ + vTaskSuspendAll(); + + /* Call the correct FreeRTOS mutex unlock function based on mutex type. */ + if( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE ) + { + ( void ) xSemaphoreGiveRecursive( ( SemaphoreHandle_t ) &pxMutex->xMutex ); + } + else + { + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxMutex->xMutex ); + } + + /* Update the owner of the mutex. A recursive mutex may still have an + * owner, so it should be updated with xSemaphoreGetMutexHolder. */ + pxMutex->xTaskOwner = xSemaphoreGetMutexHolder( ( SemaphoreHandle_t ) &pxMutex->xMutex ); + + /* Resume the scheduler */ + ( void ) xTaskResumeAll(); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int pthread_mutexattr_destroy( pthread_mutexattr_t * attr ) +{ + ( void ) attr; + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_mutexattr_gettype( const pthread_mutexattr_t * attr, + int * type ) +{ + pthread_mutexattr_internal_t * pxAttr = ( pthread_mutexattr_internal_t * ) ( attr ); + + *type = pxAttr->iType; + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_mutexattr_init( pthread_mutexattr_t * attr ) +{ + *( ( pthread_mutexattr_internal_t * ) ( attr ) ) = xDefaultMutexAttributes; + + return 0; +} + +/*-----------------------------------------------------------*/ + +int pthread_mutexattr_settype( pthread_mutexattr_t * attr, + int type ) +{ + int iStatus = 0; + pthread_mutexattr_internal_t * pxAttr = ( pthread_mutexattr_internal_t * ) ( attr ); + + switch( type ) + { + case PTHREAD_MUTEX_NORMAL: + case PTHREAD_MUTEX_RECURSIVE: + case PTHREAD_MUTEX_ERRORCHECK: + pxAttr->iType = type; + break; + + default: + iStatus = EINVAL; + break; + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_sched.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_sched.c new file mode 100644 index 000000000..2edf91871 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_sched.c @@ -0,0 +1,64 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_sched.c + * @brief Implementation of scheduler functions in sched.h + */ + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX.h" +#include "FreeRTOS_POSIX/sched.h" + +/*-----------------------------------------------------------*/ + +int sched_get_priority_max( int policy ) +{ + /* Silence warnings about unused parameters. */ + ( void ) policy; + + return configMAX_PRIORITIES - 1; +} + +/*-----------------------------------------------------------*/ + +int sched_get_priority_min( int policy ) +{ + /* Silence warnings about unused parameters. */ + ( void ) policy; + + return tskIDLE_PRIORITY; +} + +/*-----------------------------------------------------------*/ + +int sched_yield( void ) +{ + taskYIELD(); + + return 0; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_semaphore.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_semaphore.c new file mode 100644 index 000000000..f49ceadac --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_semaphore.c @@ -0,0 +1,233 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_semaphore.c + * @brief Implementation of functions in semaphore.h + */ + +/* C standard library includes. */ +#include + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX.h" +#include "FreeRTOS_POSIX/errno.h" +#include "FreeRTOS_POSIX/semaphore.h" +#include "FreeRTOS_POSIX/utils.h" + +#include "atomic.h" + + +/*-----------------------------------------------------------*/ + +int sem_destroy( sem_t * sem ) +{ + sem_internal_t * pxSem = ( sem_internal_t * ) ( sem ); + + /* Free the resources in use by the semaphore. */ + vSemaphoreDelete( ( SemaphoreHandle_t ) &pxSem->xSemaphore ); + + return 0; +} + +/*-----------------------------------------------------------*/ + +int sem_getvalue( sem_t * sem, + int * sval ) +{ + sem_internal_t * pxSem = ( sem_internal_t * ) ( sem ); + + /* Get value does not need atomic operation, since -- Open Group + * states "the updated value represents an actual semaphore value that + * occurred at some unspecified time during the call, but it need not be the + * actual value of the semaphore when it is returned to the calling process." + */ + *sval = pxSem->value; + + return 0; +} + +/*-----------------------------------------------------------*/ + +int sem_init( sem_t * sem, + int pshared, + unsigned value ) +{ + int iStatus = 0; + sem_internal_t * pxSem = ( sem_internal_t * ) ( sem ); + + /* Silence warnings about unused parameters. */ + ( void ) pshared; + + /* Check value parameter. */ + if( value > SEM_VALUE_MAX ) + { + errno = EINVAL; + iStatus = -1; + } + + /* value is guaranteed to not exceed INT32_MAX, which is the default value of SEM_VALUE_MAX (0x7FFFU). */ + pxSem->value = ( int ) value; + + /* Create the FreeRTOS semaphore. + * This is only used to queue threads when no semaphore is available. + * Initializing with semaphore initial count zero. + * This call will not fail because the memory for the semaphore has already been allocated. + */ + if( iStatus == 0 ) + { + ( void ) xSemaphoreCreateCountingStatic( SEM_VALUE_MAX, 0, &pxSem->xSemaphore ); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int sem_post( sem_t * sem ) +{ + sem_internal_t * pxSem = ( sem_internal_t * ) ( sem ); + + int iPreviouValue = Atomic_Increment_u32( ( uint32_t * ) &pxSem->value ); + + /* If previous semaphore value is equal or larger than zero, there is no + * thread waiting for this semaphore. Otherwise (<0), call FreeRTOS interface + * to wake up a thread. */ + if( iPreviouValue < 0 ) + { + /* Give the semaphore using the FreeRTOS API. */ + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxSem->xSemaphore ); + } + + return 0; +} + +/*-----------------------------------------------------------*/ + +int sem_timedwait( sem_t * sem, + const struct timespec * abstime ) +{ + int iStatus = 0; + sem_internal_t * pxSem = ( sem_internal_t * ) ( sem ); + TickType_t xDelay = portMAX_DELAY; + + if( abstime != NULL ) + { + /* If the provided timespec is invalid, still attempt to take the + * semaphore without blocking, per POSIX spec. */ + if( UTILS_ValidateTimespec( abstime ) == false ) + { + xDelay = 0; + iStatus = EINVAL; + } + else + { + struct timespec xCurrentTime = { 0 }; + + /* Get current time */ + if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 ) + { + iStatus = EINVAL; + } + else + { + iStatus = UTILS_AbsoluteTimespecToDeltaTicks( abstime, &xCurrentTime, &xDelay ); + } + + /* If abstime was in the past, still attempt to take the semaphore without + * blocking, per POSIX spec. */ + if( iStatus == ETIMEDOUT ) + { + xDelay = 0; + } + } + } + + int iPreviousValue = Atomic_Decrement_u32( ( uint32_t * ) &pxSem->value ); + + /* If previous semaphore value is larger than zero, the thread entering this function call + * can take the semaphore without yielding. Else (<=0), calling into FreeRTOS API to yield. + */ + if( iPreviousValue > 0 ) + { + /* Under no circumstance shall the function fail with a timeout if the semaphore can be locked immediately. */ + iStatus = 0; + } + else + { + /* Take the semaphore using the FreeRTOS API. */ + if( xSemaphoreTake( ( SemaphoreHandle_t ) &pxSem->xSemaphore, + xDelay ) != pdTRUE ) + { + if( iStatus == 0 ) + { + errno = ETIMEDOUT; + } + else + { + errno = iStatus; + } + + iStatus = -1; + } + else + { + iStatus = 0; + } + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int sem_trywait( sem_t * sem ) +{ + int iStatus = 0; + + /* Setting an absolute timeout of 0 (i.e. in the past) will cause sem_timedwait + * to not block. */ + struct timespec xTimeout = { 0 }; + + iStatus = sem_timedwait( sem, &xTimeout ); + + /* POSIX specifies that this function should set errno to EAGAIN and not + * ETIMEDOUT. */ + if( ( iStatus == -1 ) && ( errno == ETIMEDOUT ) ) + { + errno = EAGAIN; + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int sem_wait( sem_t * sem ) +{ + return sem_timedwait( sem, NULL ); +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_timer.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_timer.c new file mode 100644 index 000000000..05fbca873 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_timer.c @@ -0,0 +1,330 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_timer.c + * @brief Implementation of timer functions in time.h + */ + +/* C standard library includes. */ +#include + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX.h" +#include "FreeRTOS_POSIX/errno.h" +#include "FreeRTOS_POSIX/pthread.h" +#include "FreeRTOS_POSIX/signal.h" +#include "FreeRTOS_POSIX/time.h" +#include "FreeRTOS_POSIX/utils.h" + +/* FreeRTOS timer include. */ +#include "timers.h" + +/* Timespec zero check macros. */ +#define TIMESPEC_IS_ZERO( xTimespec ) ( xTimespec.tv_sec == 0 && xTimespec.tv_nsec == 0 ) /**< Check for 0. */ +#define TIMESPEC_IS_NOT_ZERO( xTimespec ) ( !( TIMESPEC_IS_ZERO( xTimespec ) ) ) /**< Check for not 0. */ + +/** + * @brief Internal timer structure. + */ +typedef struct timer_internal +{ + StaticTimer_t xTimerBuffer; /**< Memory that holds the FreeRTOS timer. */ + struct sigevent xTimerEvent; /**< What to do when this timer expires. */ + TickType_t xTimerPeriod; /**< Period of this timer. */ +} timer_internal_t; + +/*-----------------------------------------------------------*/ + +void prvTimerCallback( TimerHandle_t xTimerHandle ) +{ + timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle ); + pthread_t xTimerNotificationThread; + + /* The value of the timer ID, set in timer_create, should not be NULL. */ + configASSERT( pxTimer != NULL ); + + /* A value of SIGEV_SIGNAL isn't supported and should not have been successfully + * set. */ + configASSERT( pxTimer->xTimerEvent.sigev_notify != SIGEV_SIGNAL ); + + /* Update the timer period, which may need to be set to an it_interval + * argument. This call should not block. */ + if( pxTimer->xTimerPeriod > 0 ) + { + xTimerChangePeriod( xTimerHandle, pxTimer->xTimerPeriod, 0 ); + } + + /* Create the timer notification thread if requested. */ + if( pxTimer->xTimerEvent.sigev_notify == SIGEV_THREAD ) + { + /* if the user has provided thread attributes, create a thread + * with the provided attributes. Otherwise dispatch callback directly */ + if( pxTimer->xTimerEvent.sigev_notify_attributes == NULL ) + { + ( *pxTimer->xTimerEvent.sigev_notify_function )( pxTimer->xTimerEvent.sigev_value ); + } + else + { + ( void ) pthread_create( &xTimerNotificationThread, + pxTimer->xTimerEvent.sigev_notify_attributes, + ( void * ( * )( void * ) )pxTimer->xTimerEvent.sigev_notify_function, + pxTimer->xTimerEvent.sigev_value.sival_ptr ); + } + } +} + +/*-----------------------------------------------------------*/ + +int timer_create( clockid_t clockid, + struct sigevent * evp, + timer_t * timerid ) +{ + int iStatus = 0; + timer_internal_t * pxTimer = NULL; + + /* Silence warnings about unused parameters. */ + ( void ) clockid; + + /* POSIX specifies that when evp is NULL, the behavior shall be as is + * sigev_notify is SIGEV_SIGNAL. SIGEV_SIGNAL is currently not supported. */ + if( ( evp == NULL ) || ( evp->sigev_notify == SIGEV_SIGNAL ) ) + { + errno = ENOTSUP; + iStatus = -1; + } + + /* Allocate memory for a new timer object. */ + if( iStatus == 0 ) + { + pxTimer = pvPortMalloc( sizeof( timer_internal_t ) ); + + if( pxTimer == NULL ) + { + errno = EAGAIN; + iStatus = -1; + } + } + + if( iStatus == 0 ) + { + /* Copy the event notification structure and set the current timer period. */ + pxTimer->xTimerEvent = *evp; + pxTimer->xTimerPeriod = 0; + + /* Create a new FreeRTOS timer. This call will not fail because the + * memory for it has already been allocated, so the output parameter is + * also set. */ + *timerid = ( timer_t ) xTimerCreateStatic( posixconfigTIMER_NAME, /* Timer name. */ + portMAX_DELAY, /* Initial timer period. Timers are created disarmed. */ + pdFALSE, /* Don't auto-reload timer. */ + ( void * ) pxTimer, /* Timer id. */ + prvTimerCallback, /* Timer expiration callback. */ + &pxTimer->xTimerBuffer ); /* Pre-allocated memory for timer. */ + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int timer_delete( timer_t timerid ) +{ + TimerHandle_t xTimerHandle = timerid; + timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle ); + + /* The value of the timer ID, set in timer_create, should not be NULL. */ + configASSERT( pxTimer != NULL ); + + /* Stop the FreeRTOS timer. Because the timer is statically allocated, no call + * to xTimerDelete is necessary. The timer is stopped so that it's not referenced + * anywhere. xTimerStop will not fail when it has unlimited block time. */ + ( void ) xTimerStop( xTimerHandle, portMAX_DELAY ); + + /* Wait until the timer stop command is processed. */ + while( xTimerIsTimerActive( xTimerHandle ) == pdTRUE ) + { + vTaskDelay( 1 ); + } + + /* Free the memory in use by the timer. */ + vPortFree( pxTimer ); + + return 0; +} + +/*-----------------------------------------------------------*/ + +int timer_getoverrun( timer_t timerid ) +{ + /* Silence warnings about unused parameters. */ + ( void ) timerid; + + return 0; +} + +/*-----------------------------------------------------------*/ + +int timer_settime( timer_t timerid, + int flags, + const struct itimerspec * value, + struct itimerspec * ovalue ) +{ + int iStatus = 0; + TimerHandle_t xTimerHandle = timerid; + timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle ); + TickType_t xNextTimerExpiration = 0, xTimerExpirationPeriod = 0; + + /* Validate the value argument, but only if the timer isn't being disarmed. */ + if( TIMESPEC_IS_NOT_ZERO( value->it_value ) ) + { + if( ( UTILS_ValidateTimespec( &value->it_interval ) == false ) || + ( UTILS_ValidateTimespec( &value->it_value ) == false ) ) + { + errno = EINVAL; + iStatus = -1; + } + } + + /* Set ovalue, if given. */ + if( ovalue != NULL ) + { + ( void ) timer_gettime( timerid, ovalue ); + } + + /* Stop the timer if it's currently active. */ + if( ( iStatus == 0 ) && xTimerIsTimerActive( xTimerHandle ) ) + { + ( void ) xTimerStop( xTimerHandle, portMAX_DELAY ); + } + + /* Only restart the timer if it_value is not zero. */ + if( ( iStatus == 0 ) && TIMESPEC_IS_NOT_ZERO( value->it_value ) ) + { + /* Convert it_interval to ticks, but only if it_interval is not 0. If + * it_interval is 0, then the timer is not periodic. */ + if( TIMESPEC_IS_NOT_ZERO( value->it_interval ) ) + { + ( void ) UTILS_TimespecToTicks( &value->it_interval, &xTimerExpirationPeriod ); + } + + /* Set the new timer period. A non-periodic timer will have its period set + * to portMAX_DELAY. */ + pxTimer->xTimerPeriod = xTimerExpirationPeriod; + + /* Convert it_value to ticks, but only if it_value is not 0. If it_value + * is 0, then the timer will remain disarmed. */ + if( TIMESPEC_IS_NOT_ZERO( value->it_value ) ) + { + /* Absolute timeout. */ + if( ( flags & TIMER_ABSTIME ) == TIMER_ABSTIME ) + { + struct timespec xCurrentTime = { 0 }; + + /* Get current time */ + if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 ) + { + iStatus = EINVAL; + } + else + { + iStatus = UTILS_AbsoluteTimespecToDeltaTicks( &value->it_value, &xCurrentTime, &xNextTimerExpiration ); + } + + /* Make sure xNextTimerExpiration is zero in case we got negative time difference */ + if( iStatus != 0 ) + { + xNextTimerExpiration = 0; + + if( iStatus == ETIMEDOUT ) + { + /* Set Status to 0 as absolute time is past is treated as expiry but not an error */ + iStatus = 0; + } + } + } + /* Relative timeout. */ + else + { + ( void ) UTILS_TimespecToTicks( &value->it_value, &xNextTimerExpiration ); + } + } + + /* If xNextTimerExpiration is still 0, that means that it_value specified + * an absolute timeout in the past. Per POSIX spec, a notification should be + * triggered immediately. */ + if( xNextTimerExpiration == 0 ) + { + prvTimerCallback( xTimerHandle ); + } + else + { + /* Set the timer to expire at the it_value, then start it. */ + ( void ) xTimerChangePeriod( xTimerHandle, xNextTimerExpiration, portMAX_DELAY ); + ( void ) xTimerStart( xTimerHandle, xNextTimerExpiration ); + } + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int timer_gettime( timer_t timerid, + struct itimerspec * value ) +{ + TimerHandle_t xTimerHandle = timerid; + timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle ); + TickType_t xNextExpirationTime = xTimerGetExpiryTime( xTimerHandle ) - xTaskGetTickCount(), + xTimerExpirationPeriod = pxTimer->xTimerPeriod; + + /* Set it_value only if the timer is armed. Otherwise, set it to 0. */ + if( xTimerIsTimerActive( xTimerHandle ) != pdFALSE ) + { + value->it_value.tv_sec = ( time_t ) ( xNextExpirationTime / configTICK_RATE_HZ ); + value->it_value.tv_nsec = ( long ) ( ( xNextExpirationTime % configTICK_RATE_HZ ) * NANOSECONDS_PER_TICK ); + } + else + { + value->it_value.tv_sec = 0; + value->it_value.tv_nsec = 0; + } + + /* Set it_interval only if the timer is periodic. Otherwise, set it to 0. */ + if( xTimerExpirationPeriod != portMAX_DELAY ) + { + value->it_interval.tv_sec = ( time_t ) ( xTimerExpirationPeriod / configTICK_RATE_HZ ); + value->it_interval.tv_nsec = ( long ) ( ( xTimerExpirationPeriod % configTICK_RATE_HZ ) * NANOSECONDS_PER_TICK ); + } + else + { + value->it_interval.tv_sec = 0; + value->it_interval.tv_nsec = 0; + } + + return 0; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_unistd.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_unistd.c new file mode 100644 index 000000000..abe20028f --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_unistd.c @@ -0,0 +1,54 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_unistd.c + * @brief Implementation of functions in unistd.h + */ + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX.h" +#include "FreeRTOS_POSIX/unistd.h" + +/*-----------------------------------------------------------*/ + +unsigned sleep( unsigned seconds ) +{ + vTaskDelay( pdMS_TO_TICKS( seconds * 1000 ) ); + + return 0; +} + +/*-----------------------------------------------------------*/ + +int usleep( useconds_t usec ) +{ + /* To avoid delaying for less than usec, always round up. */ + vTaskDelay( pdMS_TO_TICKS( usec / 1000 + ( usec % 1000 != 0 ) ) ); + + return 0; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_utils.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_utils.c new file mode 100644 index 000000000..a7cca7d46 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/FreeRTOS-Plus-POSIX/source/FreeRTOS_POSIX_utils.c @@ -0,0 +1,388 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file FreeRTOS_POSIX_utils.c + * @brief Implementation of utility functions in utils.h + */ + +/* C standard library includes. */ +#include +#include + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX.h" +#include "FreeRTOS_POSIX/errno.h" +#include "FreeRTOS_POSIX/utils.h" + +/*-----------------------------------------------------------*/ + +size_t UTILS_strnlen( const char * const pcString, + size_t xMaxLength ) +{ + const char * pcCharPointer = pcString; + size_t xLength = 0; + + if( pcString != NULL ) + { + while( ( *pcCharPointer != '\0' ) && ( xLength < xMaxLength ) ) + { + xLength++; + pcCharPointer++; + } + } + + return xLength; +} + +/*-----------------------------------------------------------*/ + +int UTILS_AbsoluteTimespecToDeltaTicks( const struct timespec * const pxAbsoluteTime, + const struct timespec * const pxCurrentTime, + TickType_t * const pxResult ) +{ + int iStatus = 0; + struct timespec xDifference = { 0 }; + + /* Check parameters. */ + if( ( pxAbsoluteTime == NULL ) || ( pxCurrentTime == NULL ) || ( pxResult == NULL ) ) + { + iStatus = EINVAL; + } + + /* Calculate the difference between the current time and absolute time. */ + if( iStatus == 0 ) + { + iStatus = UTILS_TimespecSubtract( pxAbsoluteTime, pxCurrentTime, &xDifference ); + + if( iStatus == 1 ) + { + /* pxAbsoluteTime was in the past. */ + iStatus = ETIMEDOUT; + } + else if( iStatus == -1 ) + { + /* error */ + iStatus = EINVAL; + } + } + + /* Convert the time difference to ticks. */ + if( iStatus == 0 ) + { + iStatus = UTILS_TimespecToTicks( &xDifference, pxResult ); + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int UTILS_TimespecToTicks( const struct timespec * const pxTimespec, + TickType_t * const pxResult ) +{ + int iStatus = 0; + int64_t llTotalTicks = 0; + long lNanoseconds = 0; + + /* Check parameters. */ + if( ( pxTimespec == NULL ) || ( pxResult == NULL ) ) + { + iStatus = EINVAL; + } + else if( ( iStatus == 0 ) && ( UTILS_ValidateTimespec( pxTimespec ) == false ) ) + { + iStatus = EINVAL; + } + + if( iStatus == 0 ) + { + /* Convert timespec.tv_sec to ticks. */ + llTotalTicks = ( int64_t ) configTICK_RATE_HZ * ( pxTimespec->tv_sec ); + + /* Convert timespec.tv_nsec to ticks. This value does not have to be checked + * for overflow because a valid timespec has 0 <= tv_nsec < 1000000000 and + * NANOSECONDS_PER_TICK > 1. */ + lNanoseconds = pxTimespec->tv_nsec / ( long ) NANOSECONDS_PER_TICK + /* Whole nanoseconds. */ + ( long ) ( pxTimespec->tv_nsec % ( long ) NANOSECONDS_PER_TICK != 0 ); /* Add 1 to round up if needed. */ + + /* Add the nanoseconds to the total ticks. */ + llTotalTicks += ( int64_t ) lNanoseconds; + + /* Check for overflow */ + if( llTotalTicks < 0 ) + { + iStatus = EINVAL; + } + else + { + /* check if TickType_t is 32 bit or 64 bit */ + uint32_t ulTickTypeSize = sizeof( TickType_t ); + + /* check for downcast overflow */ + if( ulTickTypeSize == sizeof( uint32_t ) ) + { + if( llTotalTicks > UINT_MAX ) + { + iStatus = EINVAL; + } + } + } + + /* Write result. */ + *pxResult = ( TickType_t ) llTotalTicks; + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +void UTILS_NanosecondsToTimespec( int64_t llSource, + struct timespec * const pxDestination ) +{ + long lCarrySec = 0; + + /* Convert to timespec. */ + pxDestination->tv_sec = ( time_t ) ( llSource / NANOSECONDS_PER_SECOND ); + pxDestination->tv_nsec = ( long ) ( llSource % NANOSECONDS_PER_SECOND ); + + /* Subtract from tv_sec if tv_nsec < 0. */ + if( pxDestination->tv_nsec < 0L ) + { + /* Compute the number of seconds to carry. */ + lCarrySec = ( pxDestination->tv_nsec / ( long ) NANOSECONDS_PER_SECOND ) + 1L; + + pxDestination->tv_sec -= ( time_t ) ( lCarrySec ); + pxDestination->tv_nsec += lCarrySec * ( long ) NANOSECONDS_PER_SECOND; + } +} + +/*-----------------------------------------------------------*/ + +int UTILS_TimespecAdd( const struct timespec * const x, + const struct timespec * const y, + struct timespec * const pxResult ) +{ + int64_t llPartialSec = 0; + int iStatus = 0; + + /* Check parameters. */ + if( ( pxResult == NULL ) || ( x == NULL ) || ( y == NULL ) ) + { + iStatus = -1; + } + + if( iStatus == 0 ) + { + /* Perform addition. */ + pxResult->tv_nsec = x->tv_nsec + y->tv_nsec; + + /* check for overflow in case nsec value was invalid */ + if( pxResult->tv_nsec < 0 ) + { + iStatus = 1; + } + else + { + llPartialSec = ( pxResult->tv_nsec ) / NANOSECONDS_PER_SECOND; + pxResult->tv_nsec = ( pxResult->tv_nsec ) % NANOSECONDS_PER_SECOND; + pxResult->tv_sec = x->tv_sec + y->tv_sec + llPartialSec; + + /* check for overflow */ + if( pxResult->tv_sec < 0 ) + { + iStatus = 1; + } + } + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int UTILS_TimespecAddNanoseconds( const struct timespec * const x, + int64_t llNanoseconds, + struct timespec * const pxResult ) +{ + int64_t llTotalNSec = 0; + int iStatus = 0; + + /* Check parameters. */ + if( ( pxResult == NULL ) || ( x == NULL ) ) + { + iStatus = -1; + } + + if( iStatus == 0 ) + { + /* add nano seconds */ + llTotalNSec = x->tv_nsec + llNanoseconds; + + /* check for nano seconds overflow */ + if( llTotalNSec < 0 ) + { + iStatus = 1; + } + else + { + pxResult->tv_nsec = llTotalNSec % NANOSECONDS_PER_SECOND; + pxResult->tv_sec = x->tv_sec + ( llTotalNSec / NANOSECONDS_PER_SECOND ); + + /* check for seconds overflow */ + if( pxResult->tv_sec < 0 ) + { + iStatus = 1; + } + } + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int UTILS_TimespecSubtract( const struct timespec * const x, + const struct timespec * const y, + struct timespec * const pxResult ) +{ + int iCompareResult = 0; + int iStatus = 0; + + /* Check parameters. */ + if( ( pxResult == NULL ) || ( x == NULL ) || ( y == NULL ) ) + { + iStatus = -1; + } + + if( iStatus == 0 ) + { + iCompareResult = UTILS_TimespecCompare( x, y ); + + /* if x < y then result would be negative, return 1 */ + if( iCompareResult == -1 ) + { + iStatus = 1; + } + else if( iCompareResult == 0 ) + { + /* if times are the same return zero */ + pxResult->tv_sec = 0; + pxResult->tv_nsec = 0; + } + else + { + /* If x > y Perform subtraction. */ + pxResult->tv_sec = x->tv_sec - y->tv_sec; + pxResult->tv_nsec = x->tv_nsec - y->tv_nsec; + + /* check if nano seconds value needs to borrow */ + if( pxResult->tv_nsec < 0 ) + { + /* Based on comparison, tv_sec > 0 */ + pxResult->tv_sec--; + pxResult->tv_nsec += ( long ) NANOSECONDS_PER_SECOND; + } + + /* if nano second is negative after borrow, it is an overflow error */ + if( pxResult->tv_nsec < 0 ) + { + iStatus = -1; + } + } + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +int UTILS_TimespecCompare( const struct timespec * const x, + const struct timespec * const y ) +{ + int iStatus = 0; + + /* Check parameters */ + if( ( x == NULL ) && ( y == NULL ) ) + { + iStatus = 0; + } + else if( y == NULL ) + { + iStatus = 1; + } + else if( x == NULL ) + { + iStatus = -1; + } + else if( x->tv_sec > y->tv_sec ) + { + iStatus = 1; + } + else if( x->tv_sec < y->tv_sec ) + { + iStatus = -1; + } + else + { + /* seconds are equal compare nano seconds */ + if( x->tv_nsec > y->tv_nsec ) + { + iStatus = 1; + } + else if( x->tv_nsec < y->tv_nsec ) + { + iStatus = -1; + } + else + { + iStatus = 0; + } + } + + return iStatus; +} + +/*-----------------------------------------------------------*/ + +bool UTILS_ValidateTimespec( const struct timespec * const pxTimespec ) +{ + bool xReturn = false; + + if( pxTimespec != NULL ) + { + /* Verify 0 <= tv_nsec < 1000000000. */ + if( ( pxTimespec->tv_nsec >= 0 ) && + ( pxTimespec->tv_nsec < NANOSECONDS_PER_SECOND ) ) + { + xReturn = true; + } + } + + return xReturn; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/errno.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/errno.h new file mode 100644 index 000000000..7d8d9d5d0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/errno.h @@ -0,0 +1,95 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file errno.h + * @brief System error numbers. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html + * + * The values defined in this file may not be compatible with the strerror + * function provided by this system. + */ + +#ifndef _FREERTOS_POSIX_ERRNO_H_ +#define _FREERTOS_POSIX_ERRNO_H_ + +/* Undefine all errnos to avoid redefinition errors with system errnos. */ +#undef EPERM +#undef ENOENT +#undef EBADF +#undef EAGAIN +#undef ENOMEM +#undef EEXIST +#undef EBUSY +#undef EINVAL +#undef ENOSPC +#undef ERANGE +#undef ENAMETOOLONG +#undef EDEADLK +#undef EOVERFLOW +#undef ENOSYS +#undef EMSGSIZE +#undef ENOTSUP +#undef ETIMEDOUT + +/** + * @name Definition of POSIX errnos. + */ +/**@{ */ +#define EPERM 1 /**< Operation not permitted. */ +#define ENOENT 2 /**< No such file or directory. */ +#define EBADF 9 /**< Bad file descriptor. */ +#define EAGAIN 11 /**< Resource unavailable, try again. */ +#define ENOMEM 12 /**< Not enough space. */ +#define EEXIST 17 /**< File exists. */ +#define EBUSY 16 /**< Device or resource busy. */ +#define EINVAL 22 /**< Invalid argument. */ +#define ENOSPC 28 /**< No space left on device. */ +#define ERANGE 34 /**< Result too large. */ +#define ENAMETOOLONG 36 /**< File name too long. */ +#define EDEADLK 45 /**< Resource deadlock would occur. */ +#define EOVERFLOW 75 /**< Value too large to be stored in data type. */ +#define ENOSYS 88 /**< Function not supported. */ +#define EMSGSIZE 90 /**< Message too long. */ +#define ENOTSUP 95 /**< Operation not supported. */ +#define ETIMEDOUT 116 /**< Connection timed out. */ +/**@} */ + +/** + * @name System Variable + * + * @brief Define FreeRTOS+POSIX errno, if enabled. + * Set configUSE_POSIX_ERRNO to enable, and clear to disable. See FreeRTOS.h. + * + * @{ + */ +#if ( configUSE_POSIX_ERRNO == 1 ) + extern int FreeRTOS_errno; + #define errno FreeRTOS_errno +#endif +/**@} */ + +#endif /* ifndef _FREERTOS_POSIX_ERRNO_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/fcntl.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/fcntl.h new file mode 100644 index 000000000..fe9e1a976 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/fcntl.h @@ -0,0 +1,79 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file fcntl.h + * @brief File control options. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/fcntl.h.html + */ + +#ifndef _FREERTOS_POSIX_FCNTL_H_ +#define _FREERTOS_POSIX_FCNTL_H_ + +/** + * @name File creation flags for use in the oflag value to open() and openat(). + */ +/**@{ */ +#define O_CLOEXEC 0x0001 /**< Close the file descriptor upon exec(). */ +#define O_CREAT 0x0002 /**< Create file if it does not exist. */ +#define O_DIRECTORY 0x0004 /**< Fail if file is a non-directory file. */ +#define O_EXCL 0x0008 /**< Exclusive use flag. */ +#define O_NOCTTY 0x0010 /**< Do not assign controlling terminal. */ +#define O_NOFOLLOW 0x0020 /**< Do not follow symbolic links. */ +#define O_TRUNC 0x0040 /**< Truncate flag. */ +#define O_TTY_INIT 0x0080 /**< termios structure provides conforming behavior. */ +/**@} */ + +/** + * @name File status flags for open(), openat(), and fcntl(). + */ +/**@{ */ +#define O_APPEND 0x0100 /**< Set append mode. */ +#define O_DSYNC 0x0200 /**< Write according to synchronized I/O data integrity completion. */ +#define O_NONBLOCK 0x0400 /**< Non-blocking mode. */ +#define O_RSYNC 0x0800 /**< Synchronized read I/O operations. */ +#define O_SYNC 0x0200 /**< Write according to synchronized I/O file integrity completion. */ +/**@} */ + +/** + * @name Mask for file access modes. + */ +/**@{ */ +#define O_ACCMODE 0xF000 +/**@} */ + +/** + * @name File access modes for open(), openat(), and fcntl(). + */ +/**@{ */ +#define O_EXEC 0x1000 /**< Open for execute only (non-directory files). */ +#define O_RDONLY 0x2000 /**< Open for reading only. */ +#define O_RDWR 0xA000 /**< Open for reading and writing. */ +#define O_SEARCH 0x4000 /**< Open directory for search only. */ +#define O_WRONLY 0x8000 /**< Open for writing only. */ +/**@} */ + +#endif /* ifndef _FREERTOS_POSIX_FCNTL_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/mqueue.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/mqueue.h new file mode 100644 index 000000000..5acfd01e8 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/mqueue.h @@ -0,0 +1,250 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file mqueue.h + * @brief Message queues. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/mqueue.h.html + */ + +#ifndef _FREERTOS_POSIX_MQUEUE_H_ +#define _FREERTOS_POSIX_MQUEUE_H_ + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX/time.h" + +/** + * @brief Message queue descriptor. + */ +typedef void * mqd_t; + +/** + * @brief Message queue attributes. + */ +struct mq_attr +{ + long mq_flags; /**< Message queue flags. */ + long mq_maxmsg; /**< Maximum number of messages. */ + long mq_msgsize; /**< Maximum message size. */ + long mq_curmsgs; /**< Number of messages currently queued. */ +}; + +/** + * @brief Close a message queue. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_close.html + * + * @retval 0 - Upon successful completion + * @retval -1 - A error occurred. errno is also set. + * + * @sideeffect Possible errno values + *
+ * EBADF - The mqdes argument is not a valid message queue descriptor. + */ +int mq_close( mqd_t mqdes ); + +/** + * @brief Get message queue attributes. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_getattr.html + * + * @retval 0 - Upon successful completion + * @retval -1 - A error occurred. errno is also set. + * + * @sideeffect Possible errno values + *
+ * DBADF - The mqdes argument is not a valid message queue descriptor. + */ +int mq_getattr( mqd_t mqdes, + struct mq_attr * mqstat ); + +/** + * @brief Open a message queue. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html + * + * @note Supported name pattern: leading <slash> character in name is always required; + * the maximum length (excluding null-terminator) of the name argument can be NAME_MAX. + * The default value of NAME_MAX in FreeRTOS_POSIX_portable_default.h is 64, which can be + * overwritten by user. + * @note mode argument is not supported. + * @note Supported oflags: O_RDWR, O_CREAT, O_EXCL, and O_NONBLOCK. + * + * @retval Message queue descriptor -- Upon successful completion + * @retval (mqd_t) - 1 -- An error occurred. errno is also set. + * + * @sideeffect Possible errno values + *
+ * EINVAL - name argument is invalid (not following name pattern), + * OR if O_CREAT is specified in oflag with attr argument not NULL and either mq_maxmsg or mq_msgsize is equal to or less than zero, + * OR either O_CREAT or O_EXCL is not set and a queue with the same name is unlinked but pending to be removed. + *
+ * EEXIST - O_CREAT and O_EXCL are set and the named message queue already exists. + *
+ * ENOSPC - There is insufficient space for the creation of the new message queue. + *
+ * ENOENT - O_CREAT is not set and the named message queue does not exist. + */ +mqd_t mq_open( const char * name, + int oflag, + mode_t mode, + struct mq_attr * attr ); + +/** + * @brief Receive a message from a message queue. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html + * + * @note msg_prio argument is not supported. Messages are not checked for corruption. + * + * @retval The length of the selected message in bytes - Upon successful completion. + * The message is removed from the queue + * @retval -1 - An error occurred. errno is also set. + * + * @sideeffect Possible errno values + *
+ * EBADF - The mqdes argument is not a valid message queue descriptor open for reading. + *
+ * EMSGSIZE - The specified message buffer size, msg_len, is less than the message size attribute of the message queue. + *
+ * ETIMEDOUT - The O_NONBLOCK flag was not set when the message queue was opened, + * but no message arrived on the queue before the specified timeout expired. + *
+ * EAGAIN - O_NONBLOCK was set in the message description associated with mqdes, and the specified message queue is empty. + */ +ssize_t mq_receive( mqd_t mqdes, + char * msg_ptr, + size_t msg_len, + unsigned int * msg_prio ); + +/** + * @brief Send a message to a message queue. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html + * + * @note msg_prio argument is not supported. + * + * @retval 0 - Upon successful completion. + * @retval -1 - An error occurred. errno is also set. + * + * @sideeffect Possible errno values + *
+ * EBADF - The mqdes argument is not a valid message queue descriptor open for writing. + *
+ * EMSGSIZE - The specified message length, msg_len, exceeds the message size attribute of the message queue, + * OR insufficient memory for the message to be sent. + *
+ * ETIMEDOUT - The O_NONBLOCK flag was not set when the message queue was opened, + * but the timeout expired before the message could be added to the queue. + *
+ * EAGAIN - The O_NONBLOCK flag is set in the message queue description associated with mqdes, + * and the specified message queue is full. + */ +int mq_send( mqd_t mqdes, + const char * msg_ptr, + size_t msg_len, + unsigned msg_prio ); + +/** + * @brief Receive a message from a message queue with timeout. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_timedreceive.html + * + * @note msg_prio argument is not supported. Messages are not checked for corruption. + * + * @retval The length of the selected message in bytes - Upon successful completion. + * The message is removed from the queue + * @retval -1 - An error occurred. errno is also set. + * + * @sideeffect Possible errno values + *
+ * EBADF - The mqdes argument is not a valid message queue descriptor open for reading. + *
+ * EMSGSIZE - The specified message buffer size, msg_len, is less than the message size attribute of the message queue. + *
+ * EINVAL - The process or thread would have blocked, and the abstime parameter specified a nanoseconds field value + * less than zero or greater than or equal to 1000 million. + *
+ * ETIMEDOUT - The O_NONBLOCK flag was not set when the message queue was opened, + * but no message arrived on the queue before the specified timeout expired. + *
+ * EAGAIN - O_NONBLOCK was set in the message description associated with mqdes, and the specified message queue is empty. + */ +ssize_t mq_timedreceive( mqd_t mqdes, + char * msg_ptr, + size_t msg_len, + unsigned * msg_prio, + const struct timespec * abstime ); + +/** + * @brief Send a message to a message queue with timeout. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_timedsend.html + * + * @note msg_prio argument is not supported. + * + * @retval 0 - Upon successful completion. + * @retval -1 - An error occurred. errno is also set. + * + * @sideeffect Possible errno values + *
+ * EBADF - The mqdes argument is not a valid message queue descriptor open for writing. + *
+ * EMSGSIZE - The specified message length, msg_len, exceeds the message size attribute of the message queue, + * OR insufficient memory for the message to be sent. + *
+ * EINVAL - The process or thread would have blocked, and the abstime parameter specified a nanoseconds field + * value less than zero or greater than or equal to 1000 million. + *
+ * ETIMEDOUT - The O_NONBLOCK flag was not set when the message queue was opened, + * but the timeout expired before the message could be added to the queue. + *
+ * EAGAIN - The O_NONBLOCK flag is set in the message queue description associated with mqdes, + * and the specified message queue is full. + */ +int mq_timedsend( mqd_t mqdes, + const char * msg_ptr, + size_t msg_len, + unsigned msg_prio, + const struct timespec * abstime ); + +/** + * @brief Remove a message queue. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_unlink.html + * + * @retval 0 - Upon successful completion. + * @retval -1 - An error occurred. errno is also set. + * + * @sideeffect Possible errno values + *
+ * EINVAL - name argument is invalid. Refer to requirements on name argument in mq_open(). + *
+ * ENOENT - The named message queue does not exist. + */ +int mq_unlink( const char * name ); + +#endif /* ifndef _FREERTOS_POSIX_MQUEUE_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/pthread.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/pthread.h new file mode 100644 index 000000000..aab1be1fc --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/pthread.h @@ -0,0 +1,501 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file pthread.h + * @brief Threads. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/pthread.h.html + */ + +#ifndef _FREERTOS_POSIX_PTHREAD_H_ +#define _FREERTOS_POSIX_PTHREAD_H_ + +/* FreeRTOS+POSIX includes. POSIX states that this header shall make symbols + * defined in sched.h and time.h visible. */ +#include "FreeRTOS_POSIX/sched.h" +#include "FreeRTOS_POSIX/time.h" + +/** + * @name pthread detach state. + */ +/**@{ */ +#define PTHREAD_CREATE_DETACHED 0 /**< Detached. */ +#define PTHREAD_CREATE_JOINABLE 1 /**< Joinable (default). */ +/**@} */ + +/** + * @name Returned to a single thread after a successful pthread_barrier_wait. + * + * @brief POSIX specifies that "The constant PTHREAD_BARRIER_SERIAL_THREAD is defined in + * and its value shall be distinct from any other value returned by pthread_barrier_wait()." + * So it's defined as negative to distinguish it from the errnos, which are positive. + */ +#define PTHREAD_BARRIER_SERIAL_THREAD ( -2 ) + +/** + * @name Mutex types. + */ +/**@{ */ +#ifndef PTHREAD_MUTEX_NORMAL + #define PTHREAD_MUTEX_NORMAL 0 /**< Non-robust, deadlock on relock, does not remember owner. */ +#endif +#ifndef PTHREAD_MUTEX_ERRORCHECK + #define PTHREAD_MUTEX_ERRORCHECK 1 /**< Non-robust, error on relock, remembers owner. */ +#endif +#ifndef PTHREAD_MUTEX_RECURSIVE + #define PTHREAD_MUTEX_RECURSIVE 2 /**< Non-robust, recursive relock, remembers owner. */ +#endif +#ifndef PTHREAD_MUTEX_DEFAULT + #define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL /**< PTHREAD_MUTEX_NORMAL (default). */ +#endif +/**@} */ + +/** + * @name Compile-time initializers. + * + * @brief To use PTHREAD_COND_INITIALIZER, posixconfigENABLE_PTHREAD_COND_T needs to be set to 1 + * in port specific POSIX config file. + * + * To use PTHREAD_MUTEX_INITIALIZER, posixconfigENABLE_PTHREAD_MUTEX_T needs to be set to 1 in + * port specific POSIX config file. + */ +/**@{ */ +#if posixconfigENABLE_PTHREAD_COND_T == 1 + #define PTHREAD_COND_INITIALIZER FREERTOS_POSIX_COND_INITIALIZER /**< pthread_cond_t. */ +#endif + +#if posixconfigENABLE_PTHREAD_MUTEX_T == 1 + #define PTHREAD_MUTEX_INITIALIZER FREERTOS_POSIX_MUTEX_INITIALIZER /**< pthread_mutex_t. */ +#endif + +/**@} */ + +/** + * @brief Destroy the thread attributes object. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_destroy.html + * + * @retval 0 - Upon successful completion. + */ +int pthread_attr_destroy( pthread_attr_t * attr ); + +/** + * @brief Get detachstate attribute. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getdetachstate.html + * + * @retval 0 - Upon successful completion. + */ +int pthread_attr_getdetachstate( const pthread_attr_t * attr, + int * detachstate ); + +/** + * @brief Get schedparam attribute. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getschedparam.html + * + * @retval 0 - Upon successful completion. + */ +int pthread_attr_getschedparam( const pthread_attr_t * attr, + struct sched_param * param ); + +/** + * @brief Get stacksize attribute. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getstacksize.html + * + * @retval 0 - Upon successful completion. + */ +int pthread_attr_getstacksize( const pthread_attr_t * attr, + size_t * stacksize ); + +/** + * @brief Initialize the thread attributes object. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_init.html + * + * @retval 0 - Upon successful completion. + * + * @note Currently, only stack size, sched_param, and detach state attributes + * are supported. Also see pthread_attr_get*() and pthread_attr_set*(). + */ +int pthread_attr_init( pthread_attr_t * attr ); + +/** + * @brief Set detachstate attribute. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setdetachstate.html + * + * @retval 0 - Upon successful completion + * @retval EINVAL - The value of detachstate is not valid. Currently, supported detach states are -- + * PTHREAD_CREATE_DETACHED and PTHREAD_CREATE_JOINABLE. + */ +int pthread_attr_setdetachstate( pthread_attr_t * attr, + int detachstate ); + +/** + * @brief Set schedparam attribute. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setschedparam.html + * + * @retval 0 - Upon successful completion. + * @retval EINVAL - The value of param is not valid. + * @retval ENOTSUP - An attempt was made to set the attribute to an unsupported value. + */ +int pthread_attr_setschedparam( pthread_attr_t * attr, + const struct sched_param * param ); + +/** + * @brief Set the schedpolicy attribute. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setschedpolicy.html + * + * @retval 0 - Upon successful completion. + * + * @warning This function is a stub and always returns 0. + */ +int pthread_attr_setschedpolicy( pthread_attr_t * attr, + int policy ); + +/** + * @brief Set stacksize attribute. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setstacksize.html + * + * @retval 0 - Upon successful completion. + * @retval EINVAL - The value of stacksize is less than {PTHREAD_STACK_MIN}. + */ +int pthread_attr_setstacksize( pthread_attr_t * attr, + size_t stacksize ); + +/** + * @brief Destroy a barrier object. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_barrier_destroy.html + * + * @retval 0 - Upon successful completion. + * + * @note This function does not validate whether there is any thread blocking on the barrier before destroying. + */ +int pthread_barrier_destroy( pthread_barrier_t * barrier ); + +/** + * @brief Initialize a barrier object. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_barrier_init.html + * + * @retval 0 - Upon successful completion. + * @retval EINVAL - The value specified by count is equal to zero. + * @retval ENOMEM - count cannot fit into FreeRTOS event group type OR insufficient memory exists to initialize the barrier. + * + * @note attr is ignored. + * + * @note pthread_barrier_init() is implemented with FreeRTOS event group. + * To ensure count fits in event group, count may be at most 8 when configUSE_16_BIT_TICKS is 1; + * it may be at most 24 otherwise. configUSE_16_BIT_TICKS is configured in application FreeRTOSConfig.h + * file, which defines how many bits tick count type has. See further details and limitation about event + * group and configUSE_16_BIT_TICKS in FreeRTOS site. + */ +int pthread_barrier_init( pthread_barrier_t * barrier, + const pthread_barrierattr_t * attr, + unsigned count ); + +/** + * @brief Synchronize at a barrier. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_barrier_wait.html + * + * @retval PTHREAD_BARRIER_SERIAL_THREAD - Upon successful completion, the first thread. + * @retval 0 - Upon successful completion, other thread(s). + */ +int pthread_barrier_wait( pthread_barrier_t * barrier ); + +/** + * @brief Thread creation. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_create.html + * + * @retval 0 - Upon successful completion. + * @retval EAGAIN - Insufficient memory for either thread structure or task creation. + */ +int pthread_create( pthread_t * thread, + const pthread_attr_t * attr, + void *( *startroutine )( void * ), + void * arg ); + +/** + * @brief Broadcast a condition. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_broadcast.html + * + * @retval 0 - Upon successful completion. + */ +int pthread_cond_broadcast( pthread_cond_t * cond ); + +/** + * @brief Destroy condition variables. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_destroy.html + * + * @retval 0 - Upon successful completion. + */ +int pthread_cond_destroy( pthread_cond_t * cond ); + +/** + * @brief Initialize condition variables. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_init.html + * + * @retval 0 - Upon successful completion. + * @retval ENOMEM - Insufficient memory exists to initialize the condition variable. + * + * @note attr is ignored and treated as NULL. Default setting is always used. + */ +int pthread_cond_init( pthread_cond_t * cond, + const pthread_condattr_t * attr ); + +/** + * @brief Signal a condition. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_signal.html + * + * @retval 0 - Upon successful completion. + */ +int pthread_cond_signal( pthread_cond_t * cond ); + +/** + * @brief Wait on a condition with a timeout. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html + * + * @retval 0 - Upon successful completion. + * @retval EINVAL - The abstime argument passed in does not refer to an initialized structure OR + * the abstime parameter specified a nanoseconds field value less than zero or + * greater than or equal to 1000 million. + * @retval ETIMEDOUT - The time specified by abstime to pthread_cond_timedwait() has passed. + */ +int pthread_cond_timedwait( pthread_cond_t * cond, + pthread_mutex_t * mutex, + const struct timespec * abstime ); + +/** + * @brief Wait on a condition. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_wait.html + * + * @retval 0 - Upon successful completion. + */ +int pthread_cond_wait( pthread_cond_t * cond, + pthread_mutex_t * mutex ); + +/** + * @brief Compare thread IDs. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_equal.html + * + * @retval 0 - t1 and t2 are both not NULL && equal. + * @retval non-zero - otherwise. + */ +int pthread_equal( pthread_t t1, + pthread_t t2 ); + +/** + * @brief Thread termination. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_exit.html + * + * @retval void - this function cannot return to its caller. + */ +void pthread_exit( void * value_ptr ); + +/** + * @brief Dynamic thread scheduling parameters access. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getschedparam.html + * + * @retval 0 - Upon successful completion. + * + * @note policy is always set to SCHED_OTHER by this function. + */ +int pthread_getschedparam( pthread_t thread, + int * policy, + struct sched_param * param ); + +/** + * @brief Wait for thread termination. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_join.html + * + * @retval 0 - Upon successful completion. + * @retval EDEADLK - The value specified by the thread argument to pthread_join() does not refer + * to a joinable thread OR multiple simultaneous calls to pthread_join() + * specifying the same target thread OR the value specified by the thread argument + * to pthread_join() refers to the calling thread. + */ +int pthread_join( pthread_t thread, + void ** retval ); + +/** + * @brief Destroy a mutex. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_destroy.html + * + * @retval 0 - Upon successful completion. + * + * @note If there exists a thread holding this mutex, this function returns 0 with mutex not being destroyed. + */ +int pthread_mutex_destroy( pthread_mutex_t * mutex ); + +/** + * @brief Initialize a mutex. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html + * + * @retval 0 - Upon successful completion. + * @retval ENOMEM - Insufficient memory exists to initialize the mutex structure. + * @retval EAGAIN - Unable to initialize the mutex structure member(s). + */ +int pthread_mutex_init( pthread_mutex_t * mutex, + const pthread_mutexattr_t * attr ); + +/** + * @brief Lock a mutex. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_lock.html + * + * @retval 0 - Upon successful completion. + * @retval EINVAL - the abstime parameter specified a nanoseconds field value less than zero + * or greater than or equal to 1000 million. + * @retval EDEADLK - The mutex type is PTHREAD_MUTEX_ERRORCHECK and the current thread already + * owns the mutex. + */ +int pthread_mutex_lock( pthread_mutex_t * mutex ); + +/** + * @brief Lock a mutex with timeout. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_timedlock.html + * + * @retval 0 - Upon successful completion. + * @retval EINVAL - The abstime argument passed in does not refer to an initialized structure OR + * the abstime parameter specified a nanoseconds field value less than zero or + * greater than or equal to 1000 million. + * @retval EDEADLK - The mutex type is PTHREAD_MUTEX_ERRORCHECK and the current thread already owns the mutex. + * @retval ETIMEDOUT - The mutex could not be locked before the specified timeout expired. + */ +int pthread_mutex_timedlock( pthread_mutex_t * mutex, + const struct timespec * abstime ); + +/** + * @brief Attempt to lock a mutex. Fail immediately if mutex is already locked. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_trylock.html + * + * @retval 0 - Upon successful completion. + * @retval EINVAL - the abstime parameter specified a nanoseconds field value less than zero + * or greater than or equal to 1000 million. + * @retval EDEADLK - The mutex type is PTHREAD_MUTEX_ERRORCHECK and the current thread already + * owns the mutex. + * @retval EBUSY - The mutex could not be acquired because it was already locked. + */ +int pthread_mutex_trylock( pthread_mutex_t * mutex ); + +/** + * @brief Unlock a mutex. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_unlock.html + * + * @retval 0 - Upon successful completion. + * @retval EPERM - The mutex type is PTHREAD_MUTEX_ERRORCHECK or PTHREAD_MUTEX_RECURSIVE, and + * the current thread does not own the mutex. + */ +int pthread_mutex_unlock( pthread_mutex_t * mutex ); + +/** + * @brief Destroy the mutex attributes object. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_destroy.html + * + * @retval 0 - Upon successful completion. + */ +int pthread_mutexattr_destroy( pthread_mutexattr_t * attr ); + +/** + * @brief Get the mutex type attribute. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_gettype.html + * + * @retval 0 - Upon successful completion. + */ +int pthread_mutexattr_gettype( const pthread_mutexattr_t * attr, + int * type ); + +/** + * @brief Initialize the mutex attributes object. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_init.html + * + * @retval 0 - Upon successful completion. + * + * @note Currently, only the type attribute is supported. Also see pthread_mutexattr_settype() + * and pthread_mutexattr_gettype(). + */ +int pthread_mutexattr_init( pthread_mutexattr_t * attr ); + +/** + * @brief Set the mutex type attribute. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_settype.html + * + * @retval 0 - Upon successful completion. + * @retval EINVAL - The value type is invalid. + */ +int pthread_mutexattr_settype( pthread_mutexattr_t * attr, + int type ); + +/** + * @brief Get the calling thread ID. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_self.html + * + * @retval the thread ID of the calling thread. + */ +pthread_t pthread_self( void ); + +/** + * @brief Dynamic thread scheduling parameters access. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_setschedparam.html + * + * @note policy is ignored; only priority (param.sched_priority) may be changed. + * + * @retval 0 - Upon successful completion. + */ +int pthread_setschedparam( pthread_t thread, + int policy, + const struct sched_param * param ); + +#endif /* _FREERTOS_POSIX_PTHREAD_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/sched.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/sched.h new file mode 100644 index 000000000..101dd7774 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/sched.h @@ -0,0 +1,84 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file sched.h + * @brief Execution scheduling. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sched.h.html + */ + +#ifndef _FREERTOS_POSIX_SCHED_H_ +#define _FREERTOS_POSIX_SCHED_H_ + +/** + * @name Scheduling Policies + */ +/**@{ */ +#define SCHED_OTHER 0 /**< Another scheduling policy. */ +/**@} */ + +/** + * @brief Scheduling parameters required for implementation of each supported + * scheduling policy. + */ +struct sched_param +{ + int sched_priority; /**< Process or thread execution scheduling priority. */ +}; + +/** + * @brief Get priority limit (max). + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_get_priority_max.html + * + * @note policy is ignored. + * + * @return the maximum priority value (0-based) system configuration allows. + *
+ * e.g. if configMAX_PRIORITIES == 7, this function returns (configMAX_PRIORITIES - 1). + * configMAX_PRIORITIES is configured in application FreeRTOSConfig.h file. + */ +int sched_get_priority_max( int policy ); + +/** + * @brief Get priority limit (min). + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_get_priority_min.html + * + * @note policy is ignored. + */ +int sched_get_priority_min( int policy ); + +/** + * @brief Yield the processor. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html + * + * @retval 0 - Upon successful completion + */ +int sched_yield( void ); + +#endif /* ifndef _FREERTOS_POSIX_SCHED_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/semaphore.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/semaphore.h new file mode 100644 index 000000000..4b1172676 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/semaphore.h @@ -0,0 +1,143 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file semaphore.h + * @brief Semaphores. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/semaphore.h.html + */ + +#ifndef _FREERTOS_POSIX_SEMAPHORE_H_ +#define _FREERTOS_POSIX_SEMAPHORE_H_ + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX/time.h" +#include "FreeRTOS_POSIX_types.h" + +/** + * @brief Semaphore type. + */ +typedef PosixSemType_t sem_t; + +/** + * @brief Destroy an unnamed semaphore. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_destroy.html + * + * @retval 0 - upon successful completion + * + * @note Semaphore is destroyed regardless of whether there is any thread currently blocked on this semaphore. + */ +int sem_destroy( sem_t * sem ); + +/** + * @brief Get the value of a semaphore. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_getvalue.html + * + * @retval 0 - Upon successful completion + * + * @note If sem is locked, then the object to which sval points is set to zero. + */ +int sem_getvalue( sem_t * sem, + int * sval ); + +/** + * @brief Initialize an unnamed semaphore. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_init.html + * + * @note pshared is ignored. Semaphores will always be considered "shared". + * + * @retval 0 - upon successful completion + * @retval -1 - otherwise. System error variable errno is also set in this case. + * + * @sideeffect Possible errno values + *
+ * EINVAL - The value argument exceeds {SEM_VALUE_MAX}. + *
+ * ENOSPC - A resource required to initialize the semaphore has been exhausted. + */ +int sem_init( sem_t * sem, + int pshared, + unsigned value ); + +/** + * @brief Unlock a semaphore. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_post.html + * + * @retval 0 - upon successful completion + */ +int sem_post( sem_t * sem ); + +/** + * @brief Lock a semaphore with timeout. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_timedwait.html + * + * @retval 0 - upon successful completion + * @retval -1 - otherwise. System error variable errno is also set in this case. + * + * @sideeffect Possible errno values + *
+ * EINVAL - parameter specified a nanoseconds field value less than zero or greater + * than or equal to 1000 million + *
+ * ETIMEDOUT - The semaphore could not be locked before the specified timeout expired. + * + * @note Deadlock detection is not implemented. + */ +int sem_timedwait( sem_t * sem, + const struct timespec * abstime ); + +/** + * @brief Lock a semaphore if available. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_trywait.html + * + * @retval 0 - upon successful completion + * @retval -1 - otherwise. System error variable errno is also set in this case. + * + * @sideeffect Possible errno values + *
+ * EAGAIN - The semaphore was already locked, so it cannot be immediately locked by the sem_trywait() operation. + */ +int sem_trywait( sem_t * sem ); + +/** + * @brief Lock a semaphore. + * + * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_wait.html + * + * @retval 0 - upon successful completion + * @retval -1 - otherwise. System error variable errno is also set in this case. + * + * @note Deadlock detection is not implemented. + */ +int sem_wait( sem_t * sem ); + +#endif /* ifndef _FREERTOS_POSIX_SEMAPHORE_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/signal.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/signal.h new file mode 100644 index 000000000..981843007 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/signal.h @@ -0,0 +1,70 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file signal.h + * @brief Signals. + * + * Signals are currently not implemented in FreeRTOS+POSIX. This header only + * defines the signal data structures used elsewhere. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html + */ + + +#ifndef _FREERTOS_POSIX_SIGNAL_H_ +#define _FREERTOS_POSIX_SIGNAL_H_ + +/** + * @name Values of sigev_notify. + */ +/**@{ */ +#define SIGEV_NONE 0 /**< No asynchronous notification is delivered when the event of interest occurs. */ +#define SIGEV_SIGNAL 1 /**< A queued signal, with an application-defined value, is generated when the event of interest occurs. Not supported. */ +#define SIGEV_THREAD 2 /**< A notification function is called to perform notification. */ +/**@} */ + +/** + * @brief Signal value. + */ +union sigval +{ + int sival_int; /**< Integer signal value. */ + void * sival_ptr; /**< Pointer signal value. */ +}; + +/** + * @brief Signal event structure. + */ +struct sigevent +{ + int sigev_notify; /**< Notification type. A value of SIGEV_SIGNAL is not supported. */ + int sigev_signo; /**< Signal number. This member is ignored. */ + union sigval sigev_value; /**< Signal value. Only the sival_ptr member is used. */ + void ( * sigev_notify_function )( union sigval ); /**< Notification function. */ + pthread_attr_t * sigev_notify_attributes; /**< Notification attributes. */ +}; + +#endif /* ifndef _FREERTOS_POSIX_SIGNAL_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/sys/types.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/sys/types.h new file mode 100644 index 000000000..fc0d51674 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/sys/types.h @@ -0,0 +1,191 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file sys/types.h + * @brief Data types. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_types.h.html + */ + +#ifndef _FREERTOS_POSIX_TYPES_H_ +#define _FREERTOS_POSIX_TYPES_H_ + +/* C standard library includes. */ +#include + +/* FreeRTOS types include */ +#include "FreeRTOS_POSIX_types.h" + +/** + * @brief Used for system times in clock ticks or CLOCKS_PER_SEC. + * + * Enabled/disabled by posixconfigENABLE_CLOCK_T. + */ +#if !defined( posixconfigENABLE_CLOCK_T ) || ( posixconfigENABLE_CLOCK_T == 1 ) + typedef uint32_t clock_t; +#endif + +/** + * @brief Used for clock ID type in the clock and timer functions. + * + * Enabled/disabled by posixconfigENABLE_CLOCKID_T. + */ +#if !defined( posixconfigENABLE_CLOCKID_T ) || ( posixconfigENABLE_CLOCKID_T == 1 ) + typedef int clockid_t; +#endif + +/** + * @brief Used for some file attributes. + * + * Enabled/disabled by posixconfigENABLE_MODE_T. + */ +#if !defined( posixconfigENABLE_MODE_T ) || ( posixconfigENABLE_MODE_T == 1 ) + typedef int mode_t; +#endif + +/** + * @brief Used for process IDs and process group IDs. + * + * Enabled/disabled by posixconfigENABLE_PID_T. + */ +#if !defined( posixconfigENABLE_PID_T ) || ( posixconfigENABLE_PID_T == 1 ) + typedef int pid_t; +#endif + +/** + * @brief Used to identify a thread attribute object. + * + * Enabled/disabled by posixconfigENABLE_PTHREAD_ATTR_T. + */ +#if !defined( posixconfigENABLE_PTHREAD_ATTR_T ) || ( posixconfigENABLE_PTHREAD_ATTR_T == 1 ) + typedef PthreadAttrType_t pthread_attr_t; +#endif + +/** + * @brief Used to identify a barrier. + * + * Enabled/disabled by posixconfigENABLE_PTHREAD_BARRIER_T. + */ +#if !defined( posixconfigENABLE_PTHREAD_BARRIER_T ) || ( posixconfigENABLE_PTHREAD_BARRIER_T == 1 ) + typedef PthreadBarrierType_t pthread_barrier_t; +#endif + +/** + * @brief Used to define a barrier attributes object. + */ +typedef void * pthread_barrierattr_t; + +/** + * @brief Used for condition variables. + * + * Enabled/disabled by posixconfigENABLE_PTHREAD_COND_T. + */ +#if !defined( posixconfigENABLE_PTHREAD_COND_T ) || ( posixconfigENABLE_PTHREAD_COND_T == 1 ) + typedef PthreadCondType_t pthread_cond_t; +#endif + +/** + * @brief Used to identify a condition attribute object. + * + * Enabled/disabled by posixconfigENABLE_PTHREAD_CONDATTR_T. + */ +#if !defined( posixconfigENABLE_PTHREAD_CONDATTR_T ) || ( posixconfigENABLE_PTHREAD_CONDATTR_T == 1 ) + typedef void * pthread_condattr_t; +#endif + +/** + * @brief Used for mutexes. + * + * Enabled/disabled by posixconfigENABLE_PTHREAD_MUTEX_T. + */ +#if !defined( posixconfigENABLE_PTHREAD_MUTEX_T ) || ( posixconfigENABLE_PTHREAD_MUTEX_T == 1 ) + typedef PthreadMutexType_t pthread_mutex_t; +#endif + +/** + * @brief Used to identify a mutex attribute object. + * + * Enabled/disabled by posixconfigENABLE_PTHREAD_MUTEXATTR_T. + */ +#if !defined( posixconfigENABLE_PTHREAD_MUTEXATTR_T ) || ( posixconfigENABLE_PTHREAD_MUTEXATTR_T == 1 ) + typedef PthreadMutexAttrType_t pthread_mutexattr_t; +#endif + +/** + * @brief Used to identify a thread. + * + * Enabled/disabled by posixconfigENABLE_PTHREAD_T. + */ +#if !defined( posixconfigENABLE_PTHREAD_T ) || ( posixconfigENABLE_PTHREAD_T == 1 ) + typedef void * pthread_t; +#endif + +/** + * @brief Used for a count of bytes or an error indication. + * + * Enabled/disabled by posixconfigENABLE_SSIZE_T. + */ +#if !defined( posixconfigENABLE_SSIZE_T ) || ( posixconfigENABLE_SSIZE_T == 1 ) + typedef int ssize_t; +#endif + +/** + * @brief Used for time in seconds. + * + * Enabled/disabled by posixconfigENABLE_TIME_T. + */ +#if !defined( posixconfigENABLE_TIME_T ) || ( posixconfigENABLE_TIME_T == 1 ) + typedef int64_t time_t; +#endif + +/** + * @brief Used for timer ID returned by timer_create(). + * + * Enabled/disabled by posixconfigENABLE_TIMER_T. + */ +#if !defined( posixconfigENABLE_TIMER_T ) || ( posixconfigENABLE_TIMER_T == 1 ) + typedef void * timer_t; +#endif + +/** + * @brief Used for time in microseconds. + * + * Enabled/disabled by posixconfigENABLE_USECONDS_T. + */ +#if !defined( posixconfigENABLE_USECONDS_T ) || ( posixconfigENABLE_USECONDS_T == 1 ) + typedef unsigned long useconds_t; +#endif + +/** + * @brief Used for file sizes. + * + * Enabled/disabled by posixconfigENABLE_OFF_T. + */ +#if !defined( posixconfigENABLE_OFF_T ) || ( posixconfigENABLE_OFF_T == 1 ) + typedef long int off_t; +#endif + +#endif /* ifndef _FREERTOS_POSIX_TYPES_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/time.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/time.h new file mode 100644 index 000000000..bbb34af6f --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/time.h @@ -0,0 +1,258 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file time.h + * @brief Time types. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/time.h.html + */ + +#ifndef _FREERTOS_POSIX_TIME_H_ +#define _FREERTOS_POSIX_TIME_H_ + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX/sys/types.h" +#include "FreeRTOS_POSIX/signal.h" + +/** + * @name Unit conversion constants. + */ +/**@{ */ +#define MICROSECONDS_PER_SECOND ( 1000000LL ) /**< Microseconds per second. */ +#define NANOSECONDS_PER_SECOND ( 1000000000LL ) /**< Nanoseconds per second. */ +#define NANOSECONDS_PER_TICK ( NANOSECONDS_PER_SECOND / configTICK_RATE_HZ ) /**< Nanoseconds per FreeRTOS tick. */ +/**@} */ + +/** + * @name Clock identifiers. + */ +/**@{ */ +#define CLOCK_REALTIME 0 /**< The identifier of the system-wide clock measuring real time. */ +#define CLOCK_MONOTONIC 1 /**< The identifier for the system-wide monotonic clock.*/ +/**@} */ + +/** + * @name A number used to convert the value returned by the clock() function into seconds. + */ +/**@{ */ +#define CLOCKS_PER_SEC ( ( clock_t ) configTICK_RATE_HZ ) +/**@} */ + +/** + * @name Flag indicating time is absolute. + * + * For functions taking timer objects, this refers to the clock associated with the timer. + */ +/**@{ */ +#define TIMER_ABSTIME 0x01 +/**@} */ + +#if !defined( posixconfigENABLE_TIMESPEC ) || ( posixconfigENABLE_TIMESPEC == 1 ) + +/** + * @brief represents an elapsed time + */ + struct timespec + { + time_t tv_sec; /**< Seconds. */ + long tv_nsec; /**< Nanoseconds. */ + }; +#endif + +#if !defined( posixconfigENABLE_ITIMERSPEC ) || ( posixconfigENABLE_ITIMERSPEC == 1 ) + +/** + * @brief timer + */ + struct itimerspec + { + struct timespec it_interval; /**< Timer period. */ + struct timespec it_value; /**< Timer expiration. */ + }; +#endif + +/** + * @brief Report CPU time used. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock.html + * + * @return The number of FreeRTOS ticks since the scheduler + * was started minus the ticks spent in the idle task. + * + * @note This function does NOT report the number of ticks spent by the calling thread. + */ +clock_t clock( void ); + +/** + * @brief Access a process CPU-time clock. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getcpuclockid.html + * + * @retval EPERM + * + * @note This function is currently unsupported. + * + */ +int clock_getcpuclockid( pid_t pid, + clockid_t * clock_id ); + +/** + * @brief Returns the resolution of a clock. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html + * + * @note clock_id is ignored + * @note This function stores the resolution of the FreeRTOS tick count in the object res points to. + * + * @retval 0 - Upon successful execution + */ +int clock_getres( clockid_t clock_id, + struct timespec * res ); + +/** + * @brief Returns the current value for the specified clock, clock_id. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_gettime.html + * + * @note clock_id is ignored + * @note this function does not check for overflows of time_t. + * + * @retval 0 - Upon successful completion. + */ +int clock_gettime( clockid_t clock_id, + struct timespec * tp ); + +/** + * @brief High resolution sleep with specifiable clock. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_nanosleep.html + * + * @note clock_id is ignored, as this function uses the FreeRTOS tick count as its clock. + * @note flags is ignored, if INCLUDE_vTaskDelayUntil is 0. i.e. the FreeRTOS function vTaskDelayUntil isn't available. + * @note rmtp is also ignored, as signals are not implemented. + * + * @retval 0 - Upon successful completion. + * @retval EINVAL - The rqtp argument specified a nanosecond value less than zero or greater than or equal to 1000 million. + */ +int clock_nanosleep( clockid_t clock_id, + int flags, + const struct timespec * rqtp, + struct timespec * rmtp ); + +/** + * @brief Sets the time for the specified clock. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_settime.html + * + * @retval -1 with errno set to EPERM. + * + * @note This function is currently unsupported, as FreeRTOS does not provide a function to modify the tick count. + */ +int clock_settime( clockid_t clock_id, + const struct timespec * tp ); + +/** + * @brief High resolution sleep. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/nanosleep.html + * + * @note rmtp is ignored, as signals are not implemented. + * + * @retval 0 - Upon successful completion. + * @retval -1 - The rqtp argument is invalid OR the rqtp argument specified a nanosecond value less than zero or greater than or equal to 1000 million. + * + */ +int nanosleep( const struct timespec * rqtp, + struct timespec * rmtp ); + +/** + * @brief Create a per-process timer. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_create.html + * + * @note clock_id is ignored, as this function used the FreeRTOS tick count as its clock. + * @note evp.sigev_notify must be set to SIGEV_THREAD, since signals are currently not supported. + * + * @retval 0 - Upon successful completion, with location referenced by timerid updated. + * @retval -1 - If an error occurs. errno is also set. + * + * @sideeffect Possible errno values + *
+ * ENOTSUP - If evp is NULL OR evp->sigen_notify == SIGEV_SIGNAL. + *
+ * EAGAIN - The system lacks sufficient signal queuing resources to honor the request. + */ +int timer_create( clockid_t clockid, + struct sigevent * evp, + timer_t * timerid ); + +/** + * @brief Delete a per-process timer. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_delete.html + * + * @retval 0 - Upon successful completion. + */ +int timer_delete( timer_t timerid ); + +/** + * @brief Get the timer overrun count. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_getoverrun.html + * + * @retval 0 - Always return 0, since signals are not supported. + */ +int timer_getoverrun( timer_t timerid ); + +/** + * @brief Get the amount of time until the timer expires. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_gettime.html + * + * @retval 0 - Upon successful completion. + */ +int timer_gettime( timer_t timerid, + struct itimerspec * value ); + +/** + * @brief Set the time until the next expiration of the timer. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_settime.html + * + * @retval 0 - Upon successful completion. + * @retval -1 - An error occurred, errno is also set. + * + * @sideeffect Possible errno values + *
+ * EINVAL - A value structure specified a nanosecond value less than zero or greater than or equal to 1000 million, + * AND the it_value member of that structure did not specify zero seconds and nanoseconds. + */ +int timer_settime( timer_t timerid, + int flags, + const struct itimerspec * value, + struct itimerspec * ovalue ); + +#endif /* ifndef _FREERTOS_POSIX_TIME_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/unistd.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/unistd.h new file mode 100644 index 000000000..f5bdb358c --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/unistd.h @@ -0,0 +1,61 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file unistd.h + * @brief Standard symbolic constants and types + * + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html + */ + +#ifndef _FREERTOS_POSIX_UNISTD_H_ +#define _FREERTOS_POSIX_UNISTD_H_ + +#include "FreeRTOS_POSIX/sys/types.h" + +/** + * @brief Suspend execution for an interval of time. + * + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/sleep.html + * + * @param[in] seconds The number of seconds to suspend execution. + * + * @retval 0 - Upon successful completion. + * + * @note Return value of a positive number is not yet supported. + */ +unsigned sleep( unsigned seconds ); + +/** + * @brief Suspend execution for microsecond intervals. + * + * This is a useful, non-POSIX function. + * @param[in] usec The number of microseconds to suspend execution. + * + * @retval 0 - Upon successful completion. + */ +int usleep( useconds_t usec ); + +#endif /* ifndef _FREERTOS_POSIX_UNISTD_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/utils.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/utils.h new file mode 100644 index 000000000..82e0cafdf --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/FreeRTOS_POSIX/utils.h @@ -0,0 +1,155 @@ +/* + * Amazon FreeRTOS POSIX V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file utils.h + * @brief Utility functions used by FreeRTOS+POSIX. + */ + +#ifndef _FREERTOS_POSIX_UTILS_ +#define _FREERTOS_POSIX_UTILS_ + +/* C standard library includes. */ +#include +#include + +/* FreeRTOS+POSIX includes. */ +#include "FreeRTOS_POSIX/time.h" + +/** + * @brief Calculates the length of pcString, up to xMaxLength. + * + * @param[in] pcString The string to find the length of. + * @param[in] xMaxLength The limit when searching for the end of pcString. + * + * @return 0 if pcString is NULL; otherwise, the length of pcString or xMaxLength, + * whichever is smaller. + */ +size_t UTILS_strnlen( const char * const pcString, + size_t xMaxLength ); + +/** + * @brief Calculates the number of ticks between now and a given timespec. + * + * @param[in] pxAbsoluteTime A time in the future, specified as seconds and + * nanoseconds since CLOCK_REALTIME's 0. + * @param[in] pxCurrentTime current time, specified as seconds and + * nanoseconds. + * @param[out] pxResult Where the result of the conversion is stored. The result + * is rounded up for fractional ticks. + * + * @return 0 on success. Otherwise, ETIMEDOUT if pxAbsoluteTime is in the past, + * or EINVAL for invalid parameters. + */ +int UTILS_AbsoluteTimespecToDeltaTicks( const struct timespec * const pxAbsoluteTime, + const struct timespec * const pxCurrentTime, + TickType_t * const pxResult ); + +/** + * @brief Converts a struct timespec to FreeRTOS ticks. + * + * @param[in] pxTimespec The timespec to convert. + * @param[out] Where the result of the conversion is stored. The result is rounded + * up for fractional ticks. + * + * @return 0 on success. Otherwise, EINVAL for invalid parameters. + */ +int UTILS_TimespecToTicks( const struct timespec * const pxTimespec, + TickType_t * const pxResult ); + +/** + * @brief Converts an integer value to a timespec. + * + * @param[in] llSource The value to convert. + * @param[out] pxDestination Where to store the converted value. + * + * @return No return value. + */ +void UTILS_NanosecondsToTimespec( int64_t llSource, + struct timespec * const pxDestination ); + +/** + * @brief Calculates pxResult = x + y. + * + * @param[in] x The first argument for addition. + * @param[in] y The second argument for addition. + * @param[out] pxResult Where the result of the calculation is stored. + * + * @return -1 if any argument was NULL; 1 if result is negative (overflow); otherwise, 0. + */ +int UTILS_TimespecAdd( const struct timespec * const x, + const struct timespec * const y, + struct timespec * const pxResult ); + +/** + * @brief Calculates pxResult = x + ( struct timespec ) nanosec. + * + * @param[in] x The first argument for addition. + * @param[in] llNanoseconds The second argument for addition. + * @param[out] pxResult Where the result of the calculation is stored. + * + * @return -1 if pxResult or x was NULL; 1 if result is negative; otherwise, 0. + */ +int UTILS_TimespecAddNanoseconds( const struct timespec * const x, + int64_t llNanoseconds, + struct timespec * const pxResult ); + +/** + * @brief Calculates pxResult = x - y. If the result is negative contents of + * pResult are undefined + * + * @param[in] x The first argument for subtraction. + * @param[in] y The second argument for subtraction. + * @param[out] pxResult Where the result of the calculation is stored. + * + * @return -1 if any argument was NULL; 1 if result is negative; otherwise, 0. + */ +int UTILS_TimespecSubtract( const struct timespec * const x, + const struct timespec * const y, + struct timespec * const pxResult ); + +/** + * @brief Compare x == y. + * + * @param[in] x The first argument for comparison. + * @param[in] y The second argument for comparison. + * + * @return 0 if x == y; 1 if x > y; -1 if x < y or any argument was NULL + */ +int UTILS_TimespecCompare( const struct timespec * const x, + const struct timespec * const y ); + +/** + * @brief Checks that a timespec conforms to POSIX. + * + * A valid timespec must have 0 <= tv_nsec < 1000000000. + * + * @param[in] pxTimespec The timespec to validate. + * + * @return true if the pxTimespec is valid, false otherwise. + */ +bool UTILS_ValidateTimespec( const struct timespec * const pxTimespec ); + +#endif /* ifndef _FREERTOS_POSIX_UTILS_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/private/iot_doubly_linked_list.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/private/iot_doubly_linked_list.h new file mode 100644 index 000000000..734dd8f78 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/lib/include/private/iot_doubly_linked_list.h @@ -0,0 +1,242 @@ +/* + * Amazon FreeRTOS Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_doubly_linked_list.h + * @brief Doubly Linked List implementation. + * + * A generic implementation of circular Doubly Linked List which consists of a + * list head and some list entries (zero in case of an empty list). + * + * To start with, a structure of type Link_t should be embedded in the structure + * which is to be organized as doubly linked list. + * @code + * typedef struct UserStruct + * { + * uint32_t ulField1; + * uint32_t ulField2; + * Link_t xLink; + * } UserStruct_t; + * @endcode + * + * A List head should then be defined and initialized. + * @code + * Link_t xListHead; + * listINIT_HEAD( &xListHead ); + * @endcode + * + * listADD can then be used to add nodes to the list. + * @code + * listADD( &( xListHead ), &( pxUserStruct->xLink ) ); + * @endcode + * + * listFOR_EACH can be used for traversing the list. + * @code + * Link_t *pxLink; + * UserStruct_t *pxUserStruct; + * listFOR_EACH( pxLink, &( xListHead ) ) + * { + * pxUserStruct = listCONTAINER( pxLink, UserStruct_t, xLink ); + * } + * @endcode + * + * listFOR_EACH_SAFE should be used if you want to perform destructive operations + * (like free) on nodes while traversing the list. + * @code + * Link_t *pxLink, *pxTempLink; + * UserStruct_t *pxUserStruct; + * listFOR_EACH( pxLink, pxTempLink, &( xListHead ) ) + * { + * pxUserStruct = listCONTAINER( pxLink, UserStruct_t, xLink ); + * free( pxUserStruct ); + * } + * @endcode + */ + +#ifndef _AWS_DOUBLY_LINKED_LIST_H_ +#define _AWS_DOUBLY_LINKED_LIST_H_ + +#include +#include + +/** + * @brief Struct embedded in any struct to make it a doubly linked + * list. + * + * pxNext in the head points to the first node in the list and pxPrev + * in the head points to the last node in the list. In case of empty + * list, both pxPrev and pxNext in the head point to the head node itself. + */ +typedef struct Link +{ + struct Link * pxPrev; /**< Pointer to the previous node. */ + struct Link * pxNext; /**< Pointer to the next node. */ +} Link_t; + +/** + * @brief Initializes the given list head to an empty list. + * + * @param[in] pxHead The given list head to initialize. + */ +#define listINIT_HEAD( pxHead ) \ + { \ + ( pxHead )->pxPrev = ( pxHead ); \ + ( pxHead )->pxNext = ( pxHead ); \ + } + +/** + * @brief Adds the given new node to the given list. + * + * @param[in] pxHead The head of the given list. + * @param[in] pxLink The given new node to be added to the given + * list. + */ +#define listADD( pxHead, pxLink ) \ + { \ + Link_t * pxPrevLink = ( pxHead ); \ + Link_t * pxNextLink = ( ( pxHead )->pxNext ); \ + \ + ( pxLink )->pxNext = pxNextLink; \ + pxNextLink->pxPrev = ( pxLink ); \ + pxPrevLink->pxNext = ( pxLink ); \ + ( pxLink )->pxPrev = ( pxPrevLink ); \ + } + +/** + * @brief Removes the given node from the list it is part of. + * + * If the given node is not a part of any list (i.e. next and previous + * nodes are NULL), nothing happens. + * + * @param[in] pxLink The given node to remove from the list. + */ +#define listREMOVE( pxLink ) \ + { \ + /* If the link is part of a list, remove it from the list. */ \ + if( ( pxLink )->pxNext != NULL && ( pxLink )->pxPrev != NULL ) \ + { \ + ( pxLink )->pxPrev->pxNext = ( pxLink )->pxNext; \ + ( pxLink )->pxNext->pxPrev = ( pxLink )->pxPrev; \ + } \ + \ + /* Make sure that this link is not part of any list anymore. */ \ + ( pxLink )->pxPrev = NULL; \ + ( pxLink )->pxNext = NULL; \ + } + +/** + * @brief Given the head of a list, checks if the list is empty. + * + * @param[in] pxHead The head of the given list. + */ +#define listIS_EMPTY( pxHead ) ( ( ( pxHead ) == NULL ) || ( ( pxHead )->pxNext == ( pxHead ) ) ) + +/** + * @brief Removes the first node from the given list and returns it. + * + * Removes the first node from the given list and assigns it to the + * pxLink parameter. If the list is empty, it assigns NULL to the + * pxLink. + * + * @param[in] pxHead The head of the list from which to remove the + * first node. + * @param[out] pxLink The output parameter to receive the removed + * node. + */ +#define listPOP( pxHead, pxLink ) \ + { \ + if( listIS_EMPTY( ( pxHead ) ) ) \ + { \ + ( pxLink ) = NULL; \ + } \ + else \ + { \ + ( pxLink ) = ( pxHead )->pxNext; \ + /* If the link is part of a list, remove it from the list. */ \ + if( ( pxLink )->pxNext != NULL && ( pxLink )->pxPrev != NULL ) \ + { \ + ( pxLink )->pxPrev->pxNext = ( pxLink )->pxNext; \ + ( pxLink )->pxNext->pxPrev = ( pxLink )->pxPrev; \ + } \ + \ + /* Make sure that this link is not part of any list anymore. */ \ + ( pxLink )->pxPrev = NULL; \ + ( pxLink )->pxNext = NULL; \ + } \ + } + +/** + * @brief Merges a list into a given list. + * + * @param[in] pxHeadResultList The head of the given list into which the + * other list should be merged. + * @param[in] pxHeadListToMerge The head of the list to be merged into the + * given list. + */ +#define listMERGE( pxHeadResultList, pxHeadListToMerge ) \ + { \ + if( !listIS_EMPTY( ( pxHeadListToMerge ) ) ) \ + { \ + /* Setup links between last node of listToMerge and first node of resultList. */ \ + ( pxHeadListToMerge )->pxPrev->pxNext = ( pxHeadResultList )->pxNext; \ + ( pxHeadResultList )->pxNext->pxPrev = ( pxHeadListToMerge )->pxPrev; \ + \ + /* Setup links between first node of listToMerge and the head of resultList. */ \ + ( pxHeadListToMerge )->pxNext->pxPrev = ( pxHeadResultList ); \ + ( pxHeadResultList )->pxNext = ( pxHeadListToMerge )->pxNext; \ + /* Empty the merged list. */ \ + listINIT_HEAD( ( pxHeadListToMerge ) ); \ + } \ + } + +/** + * @brief Helper macro to iterate over a list. pxLink contains the link node + * in each iteration. + */ +#define listFOR_EACH( pxLink, pxHead ) \ + for( ( pxLink ) = ( pxHead )->pxNext; \ + ( pxLink ) != ( pxHead ); \ + ( pxLink ) = ( pxLink )->pxNext ) + +/** + * @brief Helper macro to iterate over a list. It is safe to destroy/free the + * nodes while iterating. pxLink contains the link node in each iteration. + */ +#define listFOR_EACH_SAFE( pxLink, pxTempLink, pxHead ) \ + for( ( pxLink ) = ( pxHead )->pxNext, ( pxTempLink ) = ( pxLink )->pxNext; \ + ( pxLink ) != ( pxHead ); \ + ( pxLink ) = ( pxTempLink ), ( pxTempLink ) = ( pxLink )->pxNext ) + +/** + * @brief Given the pointer to the link member (of type Link_t) in a struct, + * extracts the pointer to the containing struct. + * + * @param[in] pxLink The pointer to the link member. + * @param[in] type The type of the containing struct. + * @param[in] member Name of the link member in the containing struct. + */ +#define listCONTAINER( pxLink, type, member ) ( ( type * ) ( ( uint8_t * ) ( pxLink ) - ( uint8_t * ) ( &( ( type * ) 0 )->member ) ) ) + +#endif /* _AWS_DOUBLY_LINKED_LIST_H_ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/main.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/main.c new file mode 100644 index 000000000..3b7a16240 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/main.c @@ -0,0 +1,197 @@ +/* + * FreeRTOS POSIX Demo V1.0.0 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* + ****************************************************************************** + * -NOTE- The Win32 port is a simulation (or is that emulation?) only! Do not + * expect to get real time behaviour from the Win32 port or this demo + * application. It is provided as a convenient development and demonstration + * test bed only. This was tested using Windows 10 with Intel Core i7-6700 CPU. + * + * Windows will not be running the FreeRTOS simulator threads continuously, so + * the timing information has no meaningful units. See the documentation page for + * the Windows simulator for an explanation of the slow timing: + * http://www.freertos.org/FreeRTOS-Windows-Simulator-Emulator-for-Visual-Studio-and-Eclipse-MingW.html + * - READ THE WEB DOCUMENTATION FOR THIS PORT FOR MORE INFORMATION ON USING IT - + * + * Documentation for this demo can be found on: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_POSIX/demo/posix_demo.html + ****************************************************************************** + * + * + * /* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* System headers */ +#include + +/* demo include */ +#include "posix_demo.h" + +/* Demo task priority */ +#define mainPOSIX_DEMO_PRIORITY ( tskIDLE_PRIORITY + 4 ) + +/*-----------------------------------------------------------*/ + +int main( void ) +{ + configASSERT( ( mainPOSIX_DEMO_PRIORITY < configMAX_PRIORITIES ) ); + + const uint32_t ulLongTime_ms = pdMS_TO_TICKS( 1000UL ); + + printf( "FreeRTOS POSIX demo\n" ); + + /* Start the task to run POSIX demo */ + xTaskCreate( vStartPOSIXDemo, + "posix", + configMINIMAL_STACK_SIZE, + NULL, + mainPOSIX_DEMO_PRIORITY, + NULL ); + + vTaskStartScheduler(); + + /* If all is well, the scheduler will now be running, and the following + * line will never be reached. If the following line does execute, then + * there was insufficient FreeRTOS heap memory available for the idle and/or + * timer tasks to be created. See the memory management section on the + * FreeRTOS web site for more details (this is standard text that is not + * really applicable to the Win32 simulator port). */ + for( ; ; ) + { + Sleep( ulLongTime_ms ); + } + + return 0; +} + + +/*-----------------------------------------------------------*/ + +void vAssertCalled( const char * pcFile, + uint32_t ulLine ) +{ + const uint32_t ulLongSleep = 1000UL; + volatile uint32_t ulBlockVariable = 0UL; + volatile char * pcFileName = ( volatile char * ) pcFile; + volatile uint32_t ulLineNumber = ulLine; + + ( void ) pcFileName; + ( void ) ulLineNumber; + + printf( "vAssertCalled %s, %ld\n", pcFile, ( long ) ulLine ); + fflush( stdout ); + + /* Setting ulBlockVariable to a non-zero value in the debugger will allow + * this function to be exited. */ + taskDISABLE_INTERRUPTS(); + { + while( ulBlockVariable == 0UL ) + { + Sleep( ulLongSleep ); + } + } + taskENABLE_INTERRUPTS(); +} + +/*-----------------------------------------------------------*/ + +/* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an + * implementation of vApplicationGetIdleTaskMemory() to provide the memory that is + * used by the Idle task. */ +void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, + StackType_t ** ppxIdleTaskStackBuffer, + uint32_t * pulIdleTaskStackSize ) +{ + /* If the buffers to be provided to the Idle task are declared inside this + * function then they must be declared static - otherwise they will be allocated on + * the stack and so not exists after this function exits. */ + static StaticTask_t xIdleTaskTCB; + static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Idle + * task's state will be stored. */ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + + /* Pass out the array that will be used as the Idle task's stack. */ + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + + /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. + * Note that, as the array is necessarily of type StackType_t, + * configMINIMAL_STACK_SIZE is specified in words, not bytes. */ + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} + +/*-----------------------------------------------------------*/ + +/* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the + * application must provide an implementation of vApplicationGetTimerTaskMemory() + * to provide the memory that is used by the Timer service task. */ +void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer, + StackType_t ** ppxTimerTaskStackBuffer, + uint32_t * pulTimerTaskStackSize ) +{ + /* If the buffers to be provided to the Timer task are declared inside this + * function then they must be declared static - otherwise they will be allocated on + * the stack and so not exists after this function exits. */ + static StaticTask_t xTimerTaskTCB; + static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; + + /* Pass out a pointer to the StaticTask_t structure in which the Timer + * task's state will be stored. */ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + + /* Pass out the array that will be used as the Timer task's stack. */ + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + + /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. + * Note that, as the array is necessarily of type StackType_t, + * configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */ + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} + +/*-----------------------------------------------------------*/ + +/** + * @brief Warn user if pvPortMalloc fails. + * + * Called if a call to pvPortMalloc() fails because there is insufficient + * free memory available in the FreeRTOS heap. pvPortMalloc() is called + * internally by FreeRTOS API functions that create tasks, queues, software + * timers, and semaphores. The size of the FreeRTOS heap is set by the + * configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. + * + */ +void vApplicationMallocFailedHook() +{ + taskDISABLE_INTERRUPTS(); + + for( ; ; ) + { + } +} diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/posix_demo.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/posix_demo.c new file mode 100644 index 000000000..8aba18231 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/posix_demo.c @@ -0,0 +1,374 @@ +/* + * FreeRTOS POSIX Demo V1.0.0 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @brief Demo intro: job distribution with actor model. + * + * This demo simulates job distribution with actor model. + * https://en.wikipedia.org/wiki/Actor_model + * + * In this demo, vStartPOSIXDemo() first creates all mailboxes + * which will be used by actors to send and receive messages. + * Then it spins up two types of actors -- Dispatcher and Workers. + * + * Dispatcher -- Distributing sub-tasks to workers. + * Distribution is done by putting messages into each worker's inbox, + * which is essentially an mqueue. Dispatcher keeps distributing tasks + * until all intended tasks are distributed. + * + * Workers -- Take sub-tasks and perform predefined routine for each type of tasks. + * + * Upon finishing distributing all tasks, Dispatcher will send a "terminate" message to + * each worker. vStartPOSIXDemo() will then join all actor threads and clean up mailboxes. + * + * @note A few assumptions are made in this demo, which a user might have to alter + * if to adopt this model in a new application: + * + * - The upper limit for MQUEUE_NUMBER_OF_WORKERS is set to 10. + * This is not due to physical constraint (e.g. memory), rather to make queue + * names end with a single digit number. + * + * - Message enum is cast to char/uint8_t directly, with the assumption that + * the system is not going to have more than 254 messages, which is often true + * in practice. Could extend bits used in a message to either have more messages + * or include additional arguments for a message. Proper typecasting is needed + * in that case. + * + * - The philosophy is "failure is expected". It is shown in both the way dispatcher + * delivers messages (i.e. messages can be dropped by worker(s)), and also the + * way workers process messages (i.e. workers do not inform dispatcher success or + * failure). + * + * - Following the philosophy, dispatcher shall never use blocking calls to distribute + * tasks. The only exception made here is that dispatcher needs to make sure the + * successful delivery of "terminate" messages. So that, main thread could join + * all actor threads and finish the demo. + */ + +/* FreeRTOS includes. */ +#include "FreeRTOS_POSIX.h" + +/* System headers. */ +#include +#include +#include + +/* Demo includes. */ +#include "posix_demo.h" + +/* FreeRTOS+POSIX. */ +#include "FreeRTOS_POSIX/pthread.h" +#include "FreeRTOS_POSIX/mqueue.h" +#include "FreeRTOS_POSIX/time.h" +#include "FreeRTOS_POSIX/fcntl.h" +#include "FreeRTOS_POSIX/errno.h" + +/* Constants. */ +#define LINE_BREAK "\r\n" + +/** + * @brief Control messages. + * + * uint8_t is sufficient for this enum, that we are going to cast to char directly. + * If ever needed, implement a function to properly typecast. + */ +/**@{ */ +typedef enum ControlMessage +{ + eMSG_LOWER_INAVLID = 0x00, /**< Guard, let's not use 0x00 for messages. */ + eWORKER_CTRL_MSG_CONTINUE = 0x01, /**< Dispatcher to worker, distributing another job. */ + eWORKER_CTRL_MSG_EXIT = 0x02, /**< Dispatcher to worker, all jobs are finished and the worker receiving such can exit. */ + + /* define additional messages here */ + + eMSG_UPPER_INVALID = 0xFF /**< Guard, additional tasks shall be defined above. */ +} eControlMessage; +/**@} */ + +/** + * @defgroup Configuration constants for the dispatcher-worker demo. + */ +/**@{ */ +#define MQUEUE_NUMBER_OF_WORKERS ( 4 ) /**< The number of worker threads, each thread has one queue which is used as income box. */ + +#if ( MQUEUE_NUMBER_OF_WORKERS > 10 ) + #error "Please keep MQUEUE_NUMBER_OF_WORKERS < 10." +#endif + +#define MQUEUE_WORKER_QNAME_BASE "/qNode0" /**< Queue name base. */ +#define MQUEUE_WORKER_QNAME_BASE_LEN ( 6 ) /** Queue name base length. */ + +#define MQUEUE_TIMEOUT_SECONDS ( 1 ) /**< Relative timeout for mqueue functions. */ +#define MQUEUE_MAX_NUMBER_OF_MESSAGES_WORKER ( 1 ) /**< Maximum number of messages in a queue. */ + +#define MQUEUE_MSG_WORKER_CTRL_MSG_SIZE sizeof( uint8_t ) /**< Control message size. */ +#define DEMO_ERROR ( -1 ) /**< Any non-zero value would work. */ +/**@} */ + +/** + * @brief Structure used by Worker thread. + */ +/**@{ */ +typedef struct WorkerThreadResources +{ + pthread_t pxID; /**< thread ID. */ + mqd_t xInboxID; /**< mqueue inbox ID. */ +} WorkerThreadResources_t; +/**@} */ + +/** + * @brief Structure used by Dispatcher thread. + */ +/**@{ */ +typedef struct DispatcherThreadResources +{ + pthread_t pxID; /**< thread ID. */ + mqd_t * pOutboxID; /**< a list of mqueue outbox ID. */ +} DispatcherThreadResources_t; +/**@} */ + +/*-----------------------------------------------------------*/ + +static void * prvWorkerThread( void * pvArgs ) +{ + WorkerThreadResources_t pArgList = *( WorkerThreadResources_t * ) pvArgs; + + printf( "Worker thread #[%d] - start %s", ( int ) pArgList.pxID, LINE_BREAK ); + + struct timespec xReceiveTimeout = { 0 }; + + ssize_t xMessageSize = 0; + char pcReceiveBuffer[ MQUEUE_MSG_WORKER_CTRL_MSG_SIZE ] = { 0 }; + + /* This is a worker thread that reacts based on what is sent to its inbox (mqueue). */ + while( true ) + { + clock_gettime( CLOCK_REALTIME, &xReceiveTimeout ); + xReceiveTimeout.tv_sec += MQUEUE_TIMEOUT_SECONDS; + + xMessageSize = mq_receive( pArgList.xInboxID, + pcReceiveBuffer, + MQUEUE_MSG_WORKER_CTRL_MSG_SIZE, + 0 ); + + /* Parse messages */ + if( xMessageSize == MQUEUE_MSG_WORKER_CTRL_MSG_SIZE ) + { + switch( ( int ) pcReceiveBuffer[ 0 ] ) + { + case eWORKER_CTRL_MSG_CONTINUE: + /* Task branch, currently only prints message to screen. */ + /* Could perform tasks here. Could also notify dispatcher upon completion, if desired. */ + printf( "Worker thread #[%d] -- Received eWORKER_CTRL_MSG_CONTINUE %s", ( int ) pArgList.pxID, LINE_BREAK ); + break; + + case eWORKER_CTRL_MSG_EXIT: + printf( "Worker thread #[%d] -- Finished. Exit now. %s", ( int ) pArgList.pxID, LINE_BREAK ); + + return NULL; + + default: + /* Received a message that we don't care or not defined. */ + break; + } + } + else + { + /* Invalid message. Error handling can be done here, if desired. */ + } + } + + /* You should never hit here. */ + /* return NULL; */ +} + +/*-----------------------------------------------------------*/ + +static void * prvDispatcherThread( void * pvArgs ) +{ + DispatcherThreadResources_t pArgList = *( DispatcherThreadResources_t * ) pvArgs; + + printf( "Dispatcher thread - start %s", LINE_BREAK ); + + struct timespec xSendTimeout = { 0 }; + + ssize_t xMessageSize = 0; + char pcSendBuffer[ MQUEUE_MSG_WORKER_CTRL_MSG_SIZE ] = { 0 }; + + /* Just for fun, let threads do a total of 100 independent tasks. */ + int i = 0; + const int totalNumOfJobsPerThread = 100; + + /* Distribute 1000 independent tasks to workers, in round-robin fashion. */ + pcSendBuffer[ 0 ] = ( char ) eWORKER_CTRL_MSG_CONTINUE; + + for( i = 0; i < totalNumOfJobsPerThread; i++ ) + { + clock_gettime( CLOCK_REALTIME, &xSendTimeout ); + xSendTimeout.tv_sec += MQUEUE_TIMEOUT_SECONDS; + + printf( "Dispatcher iteration #[%d] -- Sending msg to worker thread #[%d]. %s", i, ( int ) pArgList.pOutboxID[ i % MQUEUE_NUMBER_OF_WORKERS ], LINE_BREAK ); + + xMessageSize = mq_timedsend( pArgList.pOutboxID[ i % MQUEUE_NUMBER_OF_WORKERS ], + pcSendBuffer, + MQUEUE_MSG_WORKER_CTRL_MSG_SIZE, + 0, + &xSendTimeout ); + + if( xMessageSize != 0 ) + { + /* This error is acceptable in our setup. + * Since inbox for each thread fits only one message. + * In reality, balance inbox size, message arrival rate, and message drop rate. */ + printf( "An acceptable failure -- dispatcher failed to send eWORKER_CTRL_MSG_CONTINUE to outbox ID: %x. errno %d %s", + ( int ) pArgList.pOutboxID[ i % MQUEUE_NUMBER_OF_WORKERS ], errno, LINE_BREAK ); + } + } + + /* Control thread is now done with distributing jobs. Tell workers they are done. */ + pcSendBuffer[ 0 ] = ( char ) eWORKER_CTRL_MSG_EXIT; + + for( i = 0; i < MQUEUE_NUMBER_OF_WORKERS; i++ ) + { + printf( "Dispatcher [%d] -- Sending eWORKER_CTRL_MSG_EXIT to worker thread #[%d]. %s", i, ( int ) pArgList.pOutboxID[ i % MQUEUE_NUMBER_OF_WORKERS ], LINE_BREAK ); + + /* This is a blocking call, to guarantee worker thread exits. */ + xMessageSize = mq_send( pArgList.pOutboxID[ i % MQUEUE_NUMBER_OF_WORKERS ], + pcSendBuffer, + MQUEUE_MSG_WORKER_CTRL_MSG_SIZE, + 0 ); + } + + return NULL; +} + +/*-----------------------------------------------------------*/ + +/** + * @brief Job distribution with actor model. + * + * See the top of this file for detailed description. + */ +void vStartPOSIXDemo( void *pvParameters ) +{ + int i = 0; + int iStatus = 0; + + /* Remove warnings about unused parameters. */ + ( void ) pvParameters; + + /* Handles of the threads and related resources. */ + DispatcherThreadResources_t pxDispatcher = { 0 }; + WorkerThreadResources_t pxWorkers[ MQUEUE_NUMBER_OF_WORKERS ] = { { 0 } }; + mqd_t workerMqueues[ MQUEUE_NUMBER_OF_WORKERS ] = { 0 }; + + struct mq_attr xQueueAttributesWorker = + { + .mq_flags = 0, + .mq_maxmsg = MQUEUE_MAX_NUMBER_OF_MESSAGES_WORKER, + .mq_msgsize = MQUEUE_MSG_WORKER_CTRL_MSG_SIZE, + .mq_curmsgs = 0 + }; + + pxDispatcher.pOutboxID = workerMqueues; + + /* Create message queues for each worker thread. */ + for( i = 0; i < MQUEUE_NUMBER_OF_WORKERS; i++ ) + { + /* Prepare a unique queue name for each worker. */ + char qName[] = MQUEUE_WORKER_QNAME_BASE; + qName[ MQUEUE_WORKER_QNAME_BASE_LEN - 1 ] = qName[ MQUEUE_WORKER_QNAME_BASE_LEN - 1 ] + i; + + /* Open a queue with -- + * O_CREAT -- create a message queue. + * O_RDWR -- both receiving and sending messages. + */ + pxWorkers[ i ].xInboxID = mq_open( qName, + O_CREAT | O_RDWR, + ( mode_t ) 0, + &xQueueAttributesWorker ); + + if( pxWorkers[ i ].xInboxID == ( mqd_t ) -1 ) + { + printf( "Invalid inbox (mqueue) for worker. %s", LINE_BREAK ); + iStatus = DEMO_ERROR; + break; + } + + /* Outboxes of dispatcher thread is the inboxes of all worker threads. */ + pxDispatcher.pOutboxID[ i ] = pxWorkers[ i ].xInboxID; + } + + /* Create and start Worker threads. */ + if( iStatus == 0 ) + { + for( i = 0; i < MQUEUE_NUMBER_OF_WORKERS; i++ ) + { + ( void ) pthread_create( &( pxWorkers[ i ].pxID ), NULL, prvWorkerThread, &pxWorkers[ i ] ); + } + + /* Create and start dispatcher thread. */ + ( void ) pthread_create( &( pxDispatcher.pxID ), NULL, prvDispatcherThread, &pxDispatcher ); + + /* Actors will do predefined tasks in threads. Current implementation is that + * dispatcher actor notifies worker actors to terminate upon finishing distributing tasks. */ + + /* Wait for worker threads to join. */ + for( i = 0; i < MQUEUE_NUMBER_OF_WORKERS; i++ ) + { + ( void ) pthread_join( pxWorkers[ i ].pxID, NULL ); + } + + /* Wait for dispatcher thread to join. */ + ( void ) pthread_join( pxDispatcher.pxID, NULL ); + } + + /* Close and unlink worker message queues. */ + for( i = 0; i < MQUEUE_NUMBER_OF_WORKERS; i++ ) + { + char qName[] = MQUEUE_WORKER_QNAME_BASE; + qName[ MQUEUE_WORKER_QNAME_BASE_LEN - 1 ] = qName[ MQUEUE_WORKER_QNAME_BASE_LEN - 1 ] + i; + + if( pxWorkers[ i ].xInboxID != NULL ) + { + ( void ) mq_close( pxWorkers[ i ].xInboxID ); + ( void ) mq_unlink( qName ); + } + } + + /* Have something on console. */ + if( iStatus == 0 ) + { + printf( "All threads finished. %s", LINE_BREAK ); + } + else + { + printf( "Queues did not get initialized properly. Did not run demo. %s", LINE_BREAK ); + } + + /* This task was created with the native xTaskCreate() API function, so + must not run off the end of its implementing thread. */ + vTaskDelete( NULL ); +} diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/posix_demo.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/posix_demo.h new file mode 100644 index 000000000..06cb2b5dc --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/posix_demo.h @@ -0,0 +1,32 @@ +/* + * FreeRTOS Kernel V10.0.1 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef _POSIX_DEMO_H_ +#define _POSIX_DEMO_H_ +void vStartPOSIXDemo( void * pvParameters ); + +#endif /* _POSIX_DEMO_H_ */ \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/readme.txt b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/readme.txt new file mode 100644 index 000000000..3809279e6 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator/readme.txt @@ -0,0 +1,6 @@ +Directories: + ++ FreeRTOS-Plus\Demo\FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator + contains a FreeRTOS windows simulator demo project for FreeRTOS+POSIX. + See http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_POSIX/ for information about this project. + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/CLI-commands.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/CLI-commands.c new file mode 100644 index 000000000..033e66761 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/CLI-commands.c @@ -0,0 +1,716 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+CLI includes. */ +#include "FreeRTOS_CLI.h" + +/* FreeRTOS+TCP includes, just to make the stats available to the CLI +commands. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +#ifndef configINCLUDE_TRACE_RELATED_CLI_COMMANDS + #define configINCLUDE_TRACE_RELATED_CLI_COMMANDS 0 +#endif + + +/* + * Implements the run-time-stats command. + */ +static BaseType_t prvTaskStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the task-stats command. + */ +static BaseType_t prvRunTimeStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the echo-three-parameters command. + */ +static BaseType_t prvThreeParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the echo-parameters command. + */ +static BaseType_t prvParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Defines a command that prints out IP address information. + */ +static BaseType_t prvDisplayIPConfig( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Defines a command that prints out the gathered demo debug stats. + */ +static BaseType_t prvDisplayIPDebugStats( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Defines a command that sends an ICMP ping request to an IP address. + */ +static BaseType_t prvPingCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Defines a command that calls FreeRTOS_netstat(). + */ +static BaseType_t prvNetStatCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Implements the "trace start" and "trace stop" commands; + */ +#if configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 + static BaseType_t prvStartStopTraceCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); +#endif + +/* Structure that defines the "ip-config" command line command. */ +static const CLI_Command_Definition_t xIPConfig = +{ + "ip-config", + "ip-config:\r\n Displays IP address configuration\r\n\r\n", + prvDisplayIPConfig, + 0 +}; + +#if configINCLUDE_DEMO_DEBUG_STATS != 0 + /* Structure that defines the "ip-debug-stats" command line command. */ + static const CLI_Command_Definition_t xIPDebugStats = + { + "ip-debug-stats", /* The command string to type. */ + "ip-debug-stats:\r\n Shows some IP stack stats useful for debug - an example only.\r\n\r\n", + prvDisplayIPDebugStats, /* The function to run. */ + 0 /* No parameters are expected. */ + }; +#endif /* configINCLUDE_DEMO_DEBUG_STATS */ + +/* Structure that defines the "run-time-stats" command line command. This +generates a table that shows how much run time each task has */ +static const CLI_Command_Definition_t xRunTimeStats = +{ + "run-time-stats", /* The command string to type. */ + "run-time-stats:\r\n Displays a table showing how much processing time each FreeRTOS task has used\r\n\r\n", + prvRunTimeStatsCommand, /* The function to run. */ + 0 /* No parameters are expected. */ +}; + +/* Structure that defines the "task-stats" command line command. This generates +a table that gives information on each task in the system. */ +static const CLI_Command_Definition_t xTaskStats = +{ + "task-stats", /* The command string to type. */ + "task-stats:\r\n Displays a table showing the state of each FreeRTOS task\r\n\r\n", + prvTaskStatsCommand, /* The function to run. */ + 0 /* No parameters are expected. */ +}; + +/* Structure that defines the "echo_3_parameters" command line command. This +takes exactly three parameters that the command simply echos back one at a +time. */ +static const CLI_Command_Definition_t xThreeParameterEcho = +{ + "echo-3-parameters", + "echo-3-parameters :\r\n Expects three parameters, echos each in turn\r\n\r\n", + prvThreeParameterEchoCommand, /* The function to run. */ + 3 /* Three parameters are expected, which can take any value. */ +}; + +/* Structure that defines the "echo_parameters" command line command. This +takes a variable number of parameters that the command simply echos back one at +a time. */ +static const CLI_Command_Definition_t xParameterEcho = +{ + "echo-parameters", + "echo-parameters <...>:\r\n Take variable number of parameters, echos each in turn\r\n\r\n", + prvParameterEchoCommand, /* The function to run. */ + -1 /* The user can enter any number of commands. */ +}; + +#ifdef ipconfigUSE_TCP + #if( ipconfigUSE_TCP == 1 ) + /* Structure that defines the "task-stats" command line command. This generates + a table that gives information on each task in the system. */ + static const CLI_Command_Definition_t xNetStats = + { + "net-stats", /* The command string to type. */ + "net-stats:\r\n Calls FreeRTOS_netstat()\r\n\r\n", + prvNetStatCommand, /* The function to run. */ + 0 /* No parameters are expected. */ + }; + #endif /* ipconfigUSE_TCP == 1 */ +#endif /* ifdef ipconfigUSE_TCP */ + +#if ipconfigSUPPORT_OUTGOING_PINGS == 1 + + /* Structure that defines the "ping" command line command. This takes an IP + address or host name and (optionally) the number of bytes to ping as + parameters. */ + static const CLI_Command_Definition_t xPing = + { + "ping", + "ping :\r\n for example, ping 192.168.0.3 8, or ping www.example.com\r\n\r\n", + prvPingCommand, /* The function to run. */ + -1 /* Ping can take either one or two parameter, so the number of parameters has to be determined by the ping command implementation. */ + }; + +#endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + +#if configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 + /* Structure that defines the "trace" command line command. This takes a single + parameter, which can be either "start" or "stop". */ + static const CLI_Command_Definition_t xStartStopTrace = + { + "trace", + "trace [start | stop]:\r\n Starts or stops a trace recording for viewing in FreeRTOS+Trace\r\n\r\n", + prvStartStopTraceCommand, /* The function to run. */ + 1 /* One parameter is expected. Valid values are "start" and "stop". */ + }; +#endif /* configINCLUDE_TRACE_RELATED_CLI_COMMANDS */ + +/*-----------------------------------------------------------*/ + +void vRegisterCLICommands( void ) +{ +static BaseType_t xCommandRegistered = pdFALSE; + + /* Prevent commands being registered more than once. */ + if( xCommandRegistered == pdFALSE ) + { + /* Register all the command line commands defined immediately above. */ + FreeRTOS_CLIRegisterCommand( &xTaskStats ); + FreeRTOS_CLIRegisterCommand( &xRunTimeStats ); + FreeRTOS_CLIRegisterCommand( &xThreeParameterEcho ); + FreeRTOS_CLIRegisterCommand( &xParameterEcho ); + FreeRTOS_CLIRegisterCommand( &xIPDebugStats ); + FreeRTOS_CLIRegisterCommand( &xIPConfig ); + + #if ipconfigSUPPORT_OUTGOING_PINGS == 1 + { + FreeRTOS_CLIRegisterCommand( &xPing ); + } + #endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + + #ifdef ipconfigUSE_TCP + { + #if ipconfigUSE_TCP == 1 + { + FreeRTOS_CLIRegisterCommand( &xNetStats ); + } + #endif /* ipconfigUSE_TCP == 1 */ + } + #endif /* ifdef ipconfigUSE_TCP */ + + #if configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 + { + FreeRTOS_CLIRegisterCommand( & xStartStopTrace ); + } + #endif + + xCommandRegistered = pdTRUE; + } +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvTaskStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +const char *const pcHeader = "Task State Priority Stack #\r\n************************************************\r\n"; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + /* Generate a table of task stats. */ + strcpy( pcWriteBuffer, pcHeader ); + vTaskList( pcWriteBuffer + strlen( pcHeader ) ); + + /* There is no more data to return after this single string, so return + pdFALSE. */ + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvRunTimeStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +const char * const pcHeader = "Task Abs Time % Time\r\n****************************************\r\n"; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + ( void ) xWriteBufferLen; + configASSERT( pcWriteBuffer ); + + /* Generate a table of task stats. */ + strcpy( pcWriteBuffer, pcHeader ); + vTaskGetRunTimeStats( pcWriteBuffer + strlen( pcHeader ) ); + + /* There is no more data to return after this single string, so return + pdFALSE. */ + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvThreeParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +const char *pcParameter; +BaseType_t xParameterStringLength, xReturn; +static BaseType_t lParameterNumber = 0; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + configASSERT( pcWriteBuffer ); + + if( lParameterNumber == 0 ) + { + /* The first time the function is called after the command has been + entered just a header string is returned. */ + snprintf( pcWriteBuffer, xWriteBufferLen, "The three parameters were:\r\n" ); + + /* Next time the function is called the first parameter will be echoed + back. */ + lParameterNumber = 1L; + + /* There is more data to be returned as no parameters have been echoed + back yet. */ + xReturn = pdPASS; + } + else + { + /* Obtain the parameter string. */ + pcParameter = FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + lParameterNumber, /* Return the next parameter. */ + &xParameterStringLength /* Store the parameter string length. */ + ); + + /* Sanity check something was returned. */ + configASSERT( pcParameter ); + + /* Return the parameter string. */ + memset( pcWriteBuffer, 0x00, xWriteBufferLen ); + snprintf( pcWriteBuffer, xWriteBufferLen, "%d: ", ( int ) lParameterNumber ); + strncat( pcWriteBuffer, pcParameter, xParameterStringLength ); + strncat( pcWriteBuffer, "\r\n", strlen( "\r\n" ) ); + + /* If this is the last of the three parameters then there are no more + strings to return after this one. */ + if( lParameterNumber == 3L ) + { + /* If this is the last of the three parameters then there are no more + strings to return after this one. */ + xReturn = pdFALSE; + lParameterNumber = 0L; + } + else + { + /* There are more parameters to return after this one. */ + xReturn = pdTRUE; + lParameterNumber++; + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +const char *pcParameter; +BaseType_t xParameterStringLength, xReturn; +static BaseType_t lParameterNumber = 0; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + configASSERT( pcWriteBuffer ); + + if( lParameterNumber == 0 ) + { + /* The first time the function is called after the command has been + entered just a header string is returned. */ + snprintf( pcWriteBuffer, xWriteBufferLen, "The parameters were:\r\n" ); + + /* Next time the function is called the first parameter will be echoed + back. */ + lParameterNumber = 1L; + + /* There is more data to be returned as no parameters have been echoed + back yet. */ + xReturn = pdPASS; + } + else + { + /* Obtain the parameter string. */ + pcParameter = FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + lParameterNumber, /* Return the next parameter. */ + &xParameterStringLength /* Store the parameter string length. */ + ); + + if( pcParameter != NULL ) + { + /* Return the parameter string. */ + memset( pcWriteBuffer, 0x00, xWriteBufferLen ); + snprintf( pcWriteBuffer, xWriteBufferLen, "%d: ", ( int ) lParameterNumber ); + strncat( pcWriteBuffer, pcParameter, xParameterStringLength ); + strncat( pcWriteBuffer, "\r\n", strlen( "\r\n" ) ); + + /* There might be more parameters to return after this one. */ + xReturn = pdTRUE; + lParameterNumber++; + } + else + { + /* No more parameters were found. Make sure the write buffer does + not contain a valid string. */ + pcWriteBuffer[ 0 ] = 0x00; + + /* No more data to return. */ + xReturn = pdFALSE; + + /* Start over the next time this command is executed. */ + lParameterNumber = 0; + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +#ifdef ipconfigUSE_TCP + + #if ipconfigUSE_TCP == 1 + + static BaseType_t prvNetStatCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) + { + ( void ) pcWriteBuffer; + ( void ) xWriteBufferLen; + ( void ) pcCommandString; + + FreeRTOS_netstat(); + snprintf( pcWriteBuffer, xWriteBufferLen, "FreeRTOS_netstat() called - output uses FreeRTOS_printf\r\n" ); + return pdFALSE; + } + + #endif /* ipconfigUSE_TCP == 1 */ + +#endif /* ifdef ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if ipconfigSUPPORT_OUTGOING_PINGS == 1 + + static BaseType_t prvPingCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) + { + char * pcParameter; + BaseType_t lParameterStringLength, xReturn; + uint32_t ulIPAddress, ulBytesToPing; + const uint32_t ulDefaultBytesToPing = 8UL; + char cBuffer[ 16 ]; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + configASSERT( pcWriteBuffer ); + + /* Start with an empty string. */ + pcWriteBuffer[ 0 ] = 0x00; + + /* Obtain the number of bytes to ping. */ + pcParameter = ( char * ) FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 2, /* Return the second parameter. */ + &lParameterStringLength /* Store the parameter string length. */ + ); + + if( pcParameter == NULL ) + { + /* The number of bytes was not specified, so default it. */ + ulBytesToPing = ulDefaultBytesToPing; + } + else + { + ulBytesToPing = atol( pcParameter ); + } + + /* Obtain the IP address string. */ + pcParameter = ( char * ) FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 1, /* Return the first parameter. */ + &lParameterStringLength /* Store the parameter string length. */ + ); + + /* Sanity check something was returned. */ + configASSERT( pcParameter ); + + /* Attempt to obtain the IP address. If the first character is not a + digit, assume the host name has been passed in. */ + if( ( *pcParameter >= '0' ) && ( *pcParameter <= '9' ) ) + { + ulIPAddress = FreeRTOS_inet_addr( pcParameter ); + } + else + { + /* Terminate the host name. */ + pcParameter[ lParameterStringLength ] = 0x00; + + /* Attempt to resolve host. */ + ulIPAddress = FreeRTOS_gethostbyname( pcParameter ); + } + + /* Convert IP address, which may have come from a DNS lookup, to string. */ + FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); + + if( ulIPAddress != 0 ) + { + xReturn = FreeRTOS_SendPingRequest( ulIPAddress, ( uint16_t ) ulBytesToPing, portMAX_DELAY ); + } + else + { + xReturn = pdFALSE; + } + + if( xReturn == pdFALSE ) + { + snprintf( pcWriteBuffer, xWriteBufferLen, "%s", "Could not send ping request\r\n" ); + } + else + { + snprintf( pcWriteBuffer, xWriteBufferLen, "Ping sent to %s with identifier %d\r\n", cBuffer, xReturn ); + } + + return pdFALSE; + } + /*-----------------------------------------------------------*/ + +#endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + +#if configINCLUDE_DEMO_DEBUG_STATS != 0 + + static BaseType_t prvDisplayIPDebugStats( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) + { + static BaseType_t xIndex = -1; + extern ExampleDebugStatEntry_t xIPTraceValues[]; + BaseType_t xReturn; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + configASSERT( pcWriteBuffer ); + + xIndex++; + + if( xIndex < xExampleDebugStatEntries() ) + { + snprintf( pcWriteBuffer, xWriteBufferLen, "%s %d\r\n", xIPTraceValues[ xIndex ].pucDescription, ( int ) xIPTraceValues[ xIndex ].ulData ); + xReturn = pdPASS; + } + else + { + /* Reset the index for the next time it is called. */ + xIndex = -1; + + /* Ensure nothing remains in the write buffer. */ + pcWriteBuffer[ 0 ] = 0x00; + xReturn = pdFALSE; + } + + return xReturn; + } + /*-----------------------------------------------------------*/ + +#endif /* configINCLUDE_DEMO_DEBUG_STATS */ + +static BaseType_t prvDisplayIPConfig( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +static BaseType_t xIndex = 0; +BaseType_t xReturn; +uint32_t ulAddress; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + configASSERT( pcWriteBuffer ); + + switch( xIndex ) + { + case 0 : + FreeRTOS_GetAddressConfiguration( &ulAddress, NULL, NULL, NULL ); + snprintf( pcWriteBuffer, xWriteBufferLen, "\r\nIP address " ); + xReturn = pdTRUE; + xIndex++; + break; + + case 1 : + FreeRTOS_GetAddressConfiguration( NULL, &ulAddress, NULL, NULL ); + snprintf( pcWriteBuffer, xWriteBufferLen, "\r\nNet mask " ); + xReturn = pdTRUE; + xIndex++; + break; + + case 2 : + FreeRTOS_GetAddressConfiguration( NULL, NULL, &ulAddress, NULL ); + snprintf( pcWriteBuffer, xWriteBufferLen, "\r\nGateway address " ); + xReturn = pdTRUE; + xIndex++; + break; + + case 3 : + FreeRTOS_GetAddressConfiguration( NULL, NULL, NULL, &ulAddress ); + snprintf( pcWriteBuffer, xWriteBufferLen, "\r\nDNS server address " ); + xReturn = pdTRUE; + xIndex++; + break; + + default : + ulAddress = 0; + snprintf( pcWriteBuffer, xWriteBufferLen, "\r\n\r\n" ); + xReturn = pdFALSE; + xIndex = 0; + break; + } + + if( ulAddress != 0 ) + { + FreeRTOS_inet_ntoa( ulAddress, &( pcWriteBuffer[ strlen( pcWriteBuffer ) ] ) ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +#if configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 + + static BaseType_t prvStartStopTraceCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) + { + const char *pcParameter; + BaseType_t lParameterStringLength; + + /* Remove compile time warnings about unused parameters, and check the + write buffer is not NULL. NOTE - for simplicity, this example assumes the + write buffer length is adequate, so does not check for buffer overflows. */ + ( void ) pcCommandString; + configASSERT( pcWriteBuffer ); + + /* Obtain the parameter string. */ + pcParameter = FreeRTOS_CLIGetParameter + ( + pcCommandString, /* The command string itself. */ + 1, /* Return the first parameter. */ + &lParameterStringLength /* Store the parameter string length. */ + ); + + /* Sanity check something was returned. */ + configASSERT( pcParameter ); + + /* There are only two valid parameter values. */ + if( strncmp( pcParameter, "start", strlen( "start" ) ) == 0 ) + { + /* Start or restart the trace. */ + vTraceStop(); + vTraceClear(); + vTraceStart(); + + snprintf( pcWriteBuffer, xWriteBufferLen, "Trace recording (re)started.\r\n" ); + } + else if( strncmp( pcParameter, "stop", strlen( "stop" ) ) == 0 ) + { + /* End the trace, if one is running. */ + vTraceStop(); + snprintf( pcWriteBuffer, xWriteBufferLen, "Stopping trace recording.\r\n" ); + } + else + { + snprintf( pcWriteBuffer, xWriteBufferLen, "Valid parameters are 'start' and 'stop'.\r\n" ); + } + + /* There is no more data to return after this single string, so return + pdFALSE. */ + return pdFALSE; + } + +#endif /* configINCLUDE_TRACE_RELATED_CLI_COMMANDS */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/SimpleTCPEchoServer.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/SimpleTCPEchoServer.c new file mode 100644 index 000000000..bd2033668 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/SimpleTCPEchoServer.c @@ -0,0 +1,527 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * FreeRTOS tasks are used with FreeRTOS+TCP to create a TCP echo server. Echo + * clients are also created, but the echo clients use Windows threads (as + * opposed to FreeRTOS tasks) and use the Windows TCP library (Winsocks). This + * creates a communication between the FreeRTOS+TCP TCP/IP stack and the Windows + * TCP/IP stack. + * + * See the following web page for essential demo usage and configuration + * details: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html + */ + +/* Standard includes. */ +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Remove the whole file if FreeRTOSIPConfig.h is set to exclude TCP. */ +#if( ipconfigUSE_TCP == 1 ) + +/* This example uses Winsocks clients to talk to a FreeRTOS+TCP server. */ +#pragma comment( lib, "ws2_32.lib" ) + +/* The number of Winsock clients that communicate with the FreeRTOS+TCP +server. */ +#define tcpechoNUMBER_OF_CLIENTS 1 + +/* Specifies the size of the data sent to the server in MSS units. */ +#define tcpechoBUFFER_SIZE_MULTIPLIER 3 + +/* Delay between cycles so as not to flood the network. */ +#define tcpechoLOOP_DELAY ( ( TickType_t ) 750 / portTICK_PERIOD_MS ) + +/* The maximum time to wait for a closing socket to close. */ +#define tcpechoSHUTDOWN_DELAY ( pdMS_TO_TICKS( 5000 ) ) + +/* The time to wait between reads of a Winsock socket when shutting the socket +down. */ +#define tcpechoWINSOCK_SHUTDOWN_DELAY ( 5 ) + +/* The standard echo port number. */ +#define tcpechoPORT_NUMBER 7 + +/* The size of the Rx and Tx buffers. */ +#define tcpechoBUFFER_SIZE ( ipconfigTCP_MSS * tcpechoBUFFER_SIZE_MULTIPLIER ) + +/*-----------------------------------------------------------*/ + +/* + * Uses Winsocks from Windows threads to send data from the real IP and MAC + * addresses to the IP and MAC addresses spoofed by FreeRTOS+TCP. Multiple + * instances of this task are created. + */ +DWORD WINAPI prvSimpleWinsockTCPClientTask( void *pvParameters ); + +/* + * Uses FreeRTOS+TCP to listen for incoming echo connections, creating a task + * to handle each connection. + */ +static void prvConnectionListeningTask( void *pvParameters ); + +/* + * Created by the connection listening task to handle a single connection. + */ +static void prvServerConnectionInstance( void *pvParameters ); + +/* + * Create a string to transmit of pseudo random length. + */ +static BaseType_t prvCreateTxData( char *cBuffer, uint32_t ulBufferLength ); + +/* + * Create the Windows threads that use the Windows TCP/IP stack to talk to the + * FreeRTOS task that is using the FreeRTOS+TCP TCP/IP stack. + */ +static void prvCreateWindowsThreadClients( void ); + +/*-----------------------------------------------------------*/ + +/* Stores the stack size passed into vStartSimpleTCPServerTasks() so it can be +reused when the server listening task creates tasks to handle connections. */ +static uint16_t usUsedStackSize = 0; + +/* Used for error reporting. */ +static uint32_t ulConnectionCount = 0, ulClientCycles = 0, ulClientTransmitErrors = 0, ulIncorrectDataReceived; +static uint32_t ulClientSocketsClosedDuringReceive = 0, ulClientReceiveErrors = 0; + +/* The buffers used to hold the string to Tx and the received string. */ +static char cTxBuffers[ tcpechoNUMBER_OF_CLIENTS ][ tcpechoBUFFER_SIZE ], cRxBuffers[ tcpechoNUMBER_OF_CLIENTS ][ tcpechoBUFFER_SIZE ]; + +/*-----------------------------------------------------------*/ + +void vStartSimpleTCPServerTasks( uint16_t usStackSize, UBaseType_t uxPriority ) +{ +WORD wVersionRequested; +WSADATA xWSAData; + + /* The clients use Winsock sockets and must therefore run at the idle + priority. */ + configASSERT( uxPriority == tskIDLE_PRIORITY ); + + /* Create the TCP echo server. The echo server uses FreeRTOS+TCP through + the spoofed IP and MAC address. The WinSock client tasks are created from + inside the listening task. */ + xTaskCreate( prvConnectionListeningTask, "ServerListener", usStackSize, NULL, uxPriority + 1, NULL ); + + /* Prepare to use WinSock library. */ + wVersionRequested = MAKEWORD( 2, 2 ); + configASSERT( WSAStartup( wVersionRequested, &xWSAData ) == ( WORD ) 0 ); + + /* Remember the requested stack size so it can be re-used by the server + listening task when it creates tasks to handle connections. */ + usUsedStackSize = usStackSize; +} +/*-----------------------------------------------------------*/ + +static void prvCreateWindowsThreadClients( void ) +{ +BaseType_t xClientTask; +HANDLE xWinHandle; + + /* Create a set of (Windows thread) clients, all of which talk to the same + (FreeRTOS task) server. The clients use Winsocks through the real IP and + MAC address. */ + for( xClientTask = 0; xClientTask < tcpechoNUMBER_OF_CLIENTS; xClientTask++ ) + { + xWinHandle = CreateThread( + NULL, /* Pointer to thread security attributes. */ + 0, /* Initial thread stack size, in bytes. */ + prvSimpleWinsockTCPClientTask, /* Pointer to thread function. */ + ( void * ) xClientTask, /* Argument for new thread. */ + 0, /* Creation flags. */ + NULL ); + + /* Set the priority and the cores used of the Windows threads such that + they do no interfere with the FreeRTOS simulator. */ + SetThreadPriority( xWinHandle, THREAD_PRIORITY_IDLE ); + SetThreadPriorityBoost( xWinHandle, TRUE ); + SetThreadAffinityMask( xWinHandle, ~0x01u ); + } +} +/*-----------------------------------------------------------*/ + +static void prvConnectionListeningTask( void *pvParameters ) +{ +struct freertos_sockaddr xClient, xBindAddress; +Socket_t xListeningSocket, xConnectedSocket; +socklen_t xSize = sizeof( xClient ); +static const TickType_t xReceiveTimeOut = portMAX_DELAY; +const BaseType_t xBacklog = 20; +WinProperties_t xWinProps; + + /* Just to prevent compiler warnings. */ + ( void ) pvParameters; + + /* Attempt to open the socket. */ + xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET ); + + /* Set a time out so accept() will just wait for a connection. */ + FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + + /* Fill in the buffer and window sizes that will be used by the socket. */ + xWinProps.lTxBufSize = 6 * ipconfigTCP_MSS; + xWinProps.lTxWinSize = 3; + xWinProps.lRxBufSize = 6 * ipconfigTCP_MSS; + xWinProps.lRxWinSize = 3; + + /* Set the window and buffer sizes. */ + FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); + + /* Bind the socket to the port that the client task will send to, then + listen for incoming connections. */ + xBindAddress.sin_port = tcpechoPORT_NUMBER; + xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port ); + FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) ); + FreeRTOS_listen( xListeningSocket, xBacklog ); + + /* Create the clients that will connect to the listening socket. */ + prvCreateWindowsThreadClients(); + + for( ;; ) + { + /* Wait for a client to connect. */ + xConnectedSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize ); + configASSERT( xConnectedSocket != FREERTOS_INVALID_SOCKET ); + + /* Spawn a task to handle the connection. */ + xTaskCreate( prvServerConnectionInstance, "EchoServer", usUsedStackSize, ( void * ) xConnectedSocket, tskIDLE_PRIORITY, NULL ); + } +} +/*-----------------------------------------------------------*/ + +static void prvServerConnectionInstance( void *pvParameters ) +{ +int32_t lBytes, lSent, lTotalSent; +uint8_t cReceivedString[ ipconfigTCP_MSS ]; +Socket_t xConnectedSocket; +static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 5000 ); +static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 5000 ); +TickType_t xTimeOnShutdown; + + ulConnectionCount++; + xConnectedSocket = ( Socket_t ) pvParameters; + FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + FreeRTOS_setsockopt( xConnectedSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xReceiveTimeOut ) ); + + for( ;; ) + { + /* Zero out the receive array so there is NULL at the end of the string + when it is printed out. */ + memset( cReceivedString, 0x00, sizeof( cReceivedString ) ); + + /* Receive data on the socket. */ + lBytes = FreeRTOS_recv( xConnectedSocket, cReceivedString, sizeof( cReceivedString ), 0 ); + + /* If data was received, echo it back. */ + if( lBytes >= 0 ) + { + lSent = 0; + lTotalSent = 0; + + /* Call send() until all the data has been sent. */ + while( ( lSent >= 0 ) && ( lTotalSent < lBytes ) ) + { + lSent = FreeRTOS_send( xConnectedSocket, cReceivedString, lBytes - lTotalSent, 0 ); + lTotalSent += lSent; + } + + if( lSent < 0 ) + { + /* Socket closed? */ + break; + } + } + else + { + /* Socket closed? */ + break; + } + } + + /* Initiate a shutdown in case it has not already been initiated. */ + FreeRTOS_shutdown( xConnectedSocket, FREERTOS_SHUT_RDWR ); + + /* Wait for the shutdown to take effect, indicated by FreeRTOS_recv() + returning an error. */ + xTimeOnShutdown = xTaskGetTickCount(); + do + { + if( FreeRTOS_recv( xConnectedSocket, cReceivedString, ipconfigTCP_MSS, 0 ) < 0 ) + { + break; + } + } while( ( xTaskGetTickCount() - xTimeOnShutdown ) < tcpechoSHUTDOWN_DELAY ); + + /* Finished with the socket and the task. */ + FreeRTOS_closesocket( xConnectedSocket ); + vTaskDelete( NULL ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvCreateTxData( char *cBuffer, uint32_t ulBufferLength ) +{ +BaseType_t lCharactersToAdd, lCharacter; +char cChar = '0'; + + /* Randomise the number of characters that will be sent. */ + do + { + lCharactersToAdd = ipconfigRAND32() % ( ulBufferLength - 20UL ); + } while ( lCharactersToAdd == 0 ); + + /* Fill the buffer. */ + for( lCharacter = 0; lCharacter < lCharactersToAdd; lCharacter++ ) + { + cBuffer[ lCharacter ] = cChar; + cChar++; + + if( cChar > '~' ) + { + cChar = '0'; + } + } + + return lCharactersToAdd; +} +/*-----------------------------------------------------------*/ + +BaseType_t xAreTCPEchoServersStillRunning( void ) +{ +static uint32_t ulLastConnectionCount = 0, ulLastClientCycles = 0; +BaseType_t xReturn = pdPASS; + + if( ulConnectionCount == ulLastConnectionCount ) + { + xReturn = pdFAIL; + } + else + { + ulLastConnectionCount = ulConnectionCount; + } + + if( ulClientCycles == ulLastClientCycles ) + { + xReturn = pdFAIL; + } + else + { + ulLastClientCycles = ulClientCycles; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +DWORD WINAPI prvSimpleWinsockTCPClientTask( void *pvParameters ) +{ +char *pcTransmittedString, *pcReceivedString; +BaseType_t lReceived, lTransmitted = 0, lStringLength, lReturned = 0, lInstance; +uint32_t ulCount = 0UL, ulMaxCount, ulIPAddress; +const uint32_t ulMaxLoopsPerSocket = 100UL; +struct sockaddr_in xConnection; +SOCKET xClientSocket; +int iReturned; +TickType_t xTimeOnShutdown; + + /* Multiple instances of this task are created. The instance is passed in + as the parameter. */ + lInstance = ( BaseType_t ) pvParameters; + + /* Locate the buffers for this instance of this task. */ + pcTransmittedString = &( cTxBuffers[ lInstance ][ 0 ] ); + pcReceivedString = &( cRxBuffers[ lInstance ][ 0 ] ); + + /* It is assumed that this task is not created until the network is up, + so the IP address of the server (which is the FreeRTOS+TCP side of the + connection) can be obtained immediately. Store the IP address being + used in ulIPAddress. */ + FreeRTOS_GetAddressConfiguration( &ulIPAddress, NULL, NULL, NULL ); + + /* Set family and port for client socket. */ + memset( ( void * ) &xConnection, 0x00, sizeof( struct sockaddr_in ) ); + xConnection.sin_family = AF_INET; + xConnection.sin_addr.s_addr = ulIPAddress; + xConnection.sin_port = htons( tcpechoPORT_NUMBER ); + + for( ;; ) + { + /* Create the socket then connect it to the FreeRTOS+TCP server. */ + xClientSocket = socket( AF_INET, SOCK_STREAM, 0 ); + configASSERT( xClientSocket != INVALID_SOCKET ); + + do + { + iReturned = connect( xClientSocket, (const struct sockaddr*) &xConnection, sizeof( xConnection ) ); + } while( iReturned != 0 ); + + ulMaxCount = ipconfigRAND32() % ulMaxLoopsPerSocket; + + for( ulCount = 0; ulCount < ulMaxCount; ulCount++ ) + { + /* Create a string then send it to the server. */ + lStringLength = prvCreateTxData( pcTransmittedString, tcpechoBUFFER_SIZE ); + lTransmitted = send( xClientSocket, pcTransmittedString, lStringLength, 0 ); + + configASSERT( lTransmitted != SOCKET_ERROR ); + configASSERT( lTransmitted == lStringLength ); + + if( lTransmitted == lStringLength ) + { + memset( ( void * ) pcReceivedString, 0x00, tcpechoBUFFER_SIZE ); + lReceived = 0; + + /* Wait for the echoed string. */ + while( lReceived < lTransmitted ) + { + lReturned = recv( xClientSocket, ( char * ) &( pcReceivedString[ lReceived ] ), lTransmitted - lReceived, 0 ); + + if( lReturned >= 0 ) + { + /* Data was received. */ + lReceived += lReturned; + } + else + { + /* Error was returned. */ + ulClientReceiveErrors++; + break; + } + } + + /* If the socket was not closed, check the number of bytes + received. */ + if( lReceived == lTransmitted ) + { + /* Were the expected characters received? */ + configASSERT( memcmp( pcTransmittedString, pcReceivedString, lTransmitted ) == 0x00 ); + if( memcmp( pcTransmittedString, pcReceivedString, lReceived ) != 0x00 ) + { + ulIncorrectDataReceived++; + break; + } + else + { + /* Received expected string, increment the count of + successful cycles. */ + ulClientCycles++; + } + } + else + { + /* Socket is being closed or an error occurred. Don't try + using the same socket again. */ + break; + } + } + else + { + ulClientTransmitErrors++; + break; + } + } + + shutdown( xClientSocket, SD_BOTH ); + xTimeOnShutdown = xTaskGetTickCount(); + + do + { + Sleep( tcpechoWINSOCK_SHUTDOWN_DELAY ); + lReturned = recv( xClientSocket, pcReceivedString, lTransmitted, 0 ); + + if( lReturned < 0 ) + { + break; + } + } while( ( xTaskGetTickCount() - xTimeOnShutdown ) < tcpechoSHUTDOWN_DELAY ); + + configASSERT( closesocket( xClientSocket ) == 0 ); + + Sleep( tcpechoLOOP_DELAY ); + } +} +/*-----------------------------------------------------------*/ + +/* The whole file is excluded if TCP is not compiled in. */ +#endif /* ipconfigUSE_TCP */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/SimpleUDPClientAndServer.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/SimpleUDPClientAndServer.c new file mode 100644 index 000000000..af6e57f70 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/SimpleUDPClientAndServer.c @@ -0,0 +1,398 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * Creates two transmitting tasks and two receiving tasks. The transmitting + * tasks send values that are received by the receiving tasks. One set of tasks + * uses the standard API. The other set of tasks uses the zero copy API. + * + * See the following web page for essential demo usage and configuration + * details: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html + */ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +#define simpTINY_DELAY ( ( TickType_t ) 2 ) + +/* + * Uses a socket to send data without using the zero copy option. + * prvSimpleServerTask() will receive the data. + */ +static void prvSimpleClientTask( void *pvParameters ); + +/* + * Uses a socket to receive the data sent by the prvSimpleClientTask() task. + * Does not use the zero copy option. + */ +static void prvSimpleServerTask( void *pvParameters ); + +/* + * Uses a socket to send data using the zero copy option. + * prvSimpleZeroCopyServerTask() will receive the data. + */ +static void prvSimpleZeroCopyUDPClientTask( void *pvParameters ); + +/* + * Uses a socket to receive the data sent by the prvSimpleZeroCopyUDPClientTask() + * task. Uses the zero copy option. + */ +static void prvSimpleZeroCopyServerTask( void *pvParameters ); + +/*-----------------------------------------------------------*/ + +void vStartSimpleUDPClientServerTasks( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority ) +{ + /* Create the client and server tasks that do not use the zero copy + interface. */ + xTaskCreate( prvSimpleClientTask, "SimpCpyClnt", usStackSize, ( void * ) ulPort, uxPriority, NULL ); + xTaskCreate( prvSimpleServerTask, "SimpCpySrv", usStackSize, ( void * ) ulPort, uxPriority + 1, NULL ); + + /* Create the client and server tasks that do use the zero copy interface. */ + xTaskCreate( prvSimpleZeroCopyUDPClientTask, "SimpZCpyClnt", usStackSize, ( void * ) ( ulPort + 1 ), uxPriority, NULL ); + xTaskCreate( prvSimpleZeroCopyServerTask, "SimpZCpySrv", usStackSize, ( void * ) ( ulPort + 1 ), uxPriority + 1, NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvSimpleClientTask( void *pvParameters ) +{ +Socket_t xClientSocket; +struct freertos_sockaddr xDestinationAddress; +uint8_t cString[ 50 ]; +BaseType_t lReturned; +uint32_t ulCount = 0UL, ulIPAddress; +const uint32_t ulLoopsPerSocket = 10UL; +const TickType_t x150ms = 150UL / portTICK_PERIOD_MS; + + /* Remove compiler warning about unused parameters. */ + ( void ) pvParameters; + + /* It is assumed that this task is not created until the network is up, + so the IP address can be obtained immediately. store the IP address being + used in ulIPAddress. This is done so the socket can send to a different + port on the same IP address. */ + FreeRTOS_GetAddressConfiguration( &ulIPAddress, NULL, NULL, NULL ); + + /* This test sends to itself, so data sent from here is received by a server + socket on the same IP address. Setup the freertos_sockaddr structure with + this nodes IP address, and the port number being sent to. The strange + casting is to try and remove compiler warnings on 32 bit machines. */ + xDestinationAddress.sin_addr = ulIPAddress; + xDestinationAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL; + xDestinationAddress.sin_port = FreeRTOS_htons( xDestinationAddress.sin_port ); + + for( ;; ) + { + /* Create the socket. */ + xClientSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + configASSERT( xClientSocket != FREERTOS_INVALID_SOCKET ); + + /* The count is used to differentiate between different messages sent to + the server, and to break out of the do while loop below. */ + ulCount = 0UL; + + do + { + /* Create the string that is sent to the server. */ + sprintf( ( char * ) cString, "Server received (not zero copy): Message number %lu\r\n", ulCount ); + + /* Send the string to the socket. ulFlags is set to 0, so the zero + copy option is not selected. That means the data from cString[] is + copied into a network buffer inside FreeRTOS_sendto(), and cString[] + can be reused as soon as FreeRTOS_sendto() has returned. */ + lReturned = FreeRTOS_sendto( xClientSocket, ( void * ) cString, strlen( ( const char * ) cString ), 0, &xDestinationAddress, sizeof( xDestinationAddress ) ); + + ulCount++; + + } while( ( lReturned != FREERTOS_SOCKET_ERROR ) && ( ulCount < ulLoopsPerSocket ) ); + + FreeRTOS_closesocket( xClientSocket ); + + /* A short delay to prevent the messages printed by the server task + scrolling off the screen too quickly, and to prevent reduce the network + loading. */ + vTaskDelay( x150ms ); + } +} +/*-----------------------------------------------------------*/ + +static void prvSimpleServerTask( void *pvParameters ) +{ +int32_t lBytes; +uint8_t cReceivedString[ 60 ]; +struct freertos_sockaddr xClient, xBindAddress; +uint32_t xClientLength = sizeof( xClient ); +Socket_t xListeningSocket; + + /* Just to prevent compiler warnings. */ + ( void ) pvParameters; + + /* Attempt to open the socket. */ + xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET ); + + /* This test receives data sent from a different port on the same IP + address. Configure the freertos_sockaddr structure with the address being + bound to. The strange casting is to try and remove compiler warnings on 32 + bit machines. Note that this task is only created after the network is up, + so the IP address is valid here. */ + xBindAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL; + xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port ); + + /* Bind the socket to the port that the client task will send to. */ + FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) ); + + for( ;; ) + { + /* Zero out the receive array so there is NULL at the end of the string + when it is printed out. */ + memset( cReceivedString, 0x00, sizeof( cReceivedString ) ); + + /* Receive data on the socket. ulFlags is zero, so the zero copy option + is not set and the received data is copied into the buffer pointed to by + cReceivedString. By default the block time is + ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME. xClientLength is not actually + used by FreeRTOS_recvfrom(), but is set appropriately in case future + versions do use it. */ + lBytes = FreeRTOS_recvfrom( xListeningSocket, cReceivedString, sizeof( cReceivedString ), 0, &xClient, &xClientLength ); + + /* Error check. */ + configASSERT( lBytes == ( BaseType_t ) strlen( ( const char * ) cReceivedString ) ); + } +} +/*-----------------------------------------------------------*/ + +static void prvSimpleZeroCopyUDPClientTask( void *pvParameters ) +{ +Socket_t xClientSocket; +uint8_t *pucUDPPayloadBuffer; +struct freertos_sockaddr xDestinationAddress; +BaseType_t lReturned; +uint32_t ulCount = 0UL, ulIPAddress; +const uint32_t ulLoopsPerSocket = 10UL; +const char *pcStringToSend = "Server received (using zero copy): Message number "; +const TickType_t x150ms = 150UL / portTICK_PERIOD_MS; +/* 15 is added to ensure the number, \r\n and terminating zero fit. */ +const size_t xStringLength = strlen( pcStringToSend ) + 15; + + /* Remove compiler warning about unused parameters. */ + ( void ) pvParameters; + + /* It is assumed that this task is not created until the network is up, + so the IP address can be obtained immediately. store the IP address being + used in ulIPAddress. This is done so the socket can send to a different + port on the same IP address. */ + FreeRTOS_GetAddressConfiguration( &ulIPAddress, NULL, NULL, NULL ); + + /* This test sends to itself, so data sent from here is received by a server + socket on the same IP address. Setup the freertos_sockaddr structure with + this nodes IP address, and the port number being sent to. The strange + casting is to try and remove compiler warnings on 32 bit machines. */ + xDestinationAddress.sin_addr = ulIPAddress; + xDestinationAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL; + xDestinationAddress.sin_port = FreeRTOS_htons( xDestinationAddress.sin_port ); + + for( ;; ) + { + /* Create the socket. */ + xClientSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + configASSERT( xClientSocket != FREERTOS_INVALID_SOCKET ); + + /* The count is used to differentiate between different messages sent to + the server, and to break out of the do while loop below. */ + ulCount = 0UL; + + do + { + /* This task is going to send using the zero copy interface. The + data being sent is therefore written directly into a buffer that is + passed into, rather than copied into, the FreeRTOS_sendto() + function. + + First obtain a buffer of adequate length from the IP stack into which + the string will be written. Although a max delay is used, the actual + delay will be capped to ipconfigMAX_SEND_BLOCK_TIME_TICKS, hence + the do while loop is used to ensure a buffer is obtained. */ + do + { + } while( ( pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xStringLength, portMAX_DELAY ) ) == NULL ); + + /* A buffer was successfully obtained. Create the string that is + sent to the server. First the string is filled with zeros as this will + effectively be the null terminator when the string is received at the other + end. Note that the string is being written directly into the buffer + obtained from the IP stack above. */ + memset( ( void * ) pucUDPPayloadBuffer, 0x00, xStringLength ); + sprintf( ( char * ) pucUDPPayloadBuffer, "%s%lu\r\n", pcStringToSend, ulCount ); + + /* Pass the buffer into the send function. ulFlags has the + FREERTOS_ZERO_COPY bit set so the IP stack will take control of the + buffer rather than copy data out of the buffer. */ + lReturned = FreeRTOS_sendto( xClientSocket, /* The socket being sent to. */ + ( void * ) pucUDPPayloadBuffer, /* A pointer to the the data being sent. */ + strlen( ( const char * ) pucUDPPayloadBuffer ) + 1, /* The length of the data being sent - including the string's null terminator. */ + FREERTOS_ZERO_COPY, /* ulFlags with the FREERTOS_ZERO_COPY bit set. */ + &xDestinationAddress, /* Where the data is being sent. */ + sizeof( xDestinationAddress ) ); + + if( lReturned == 0 ) + { + /* The send operation failed, so this task is still responsible + for the buffer obtained from the IP stack. To ensure the buffer + is not lost it must either be used again, or, as in this case, + returned to the IP stack using FreeRTOS_ReleaseUDPPayloadBuffer(). + pucUDPPayloadBuffer can be safely re-used after this call. */ + FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer ); + } + else + { + /* The send was successful so the IP stack is now managing the + buffer pointed to by pucUDPPayloadBuffer, and the IP stack will + return the buffer once it has been sent. pucUDPPayloadBuffer can + be safely re-used. */ + } + + ulCount++; + + } while( ( lReturned != FREERTOS_SOCKET_ERROR ) && ( ulCount < ulLoopsPerSocket ) ); + + FreeRTOS_closesocket( xClientSocket ); + + /* A short delay to prevent the messages scrolling off the screen too + quickly. */ + vTaskDelay( x150ms ); + } +} +/*-----------------------------------------------------------*/ + +static void prvSimpleZeroCopyServerTask( void *pvParameters ) +{ +int32_t lBytes; +uint8_t *pucUDPPayloadBuffer; +struct freertos_sockaddr xClient, xBindAddress; +uint32_t xClientLength = sizeof( xClient ), ulIPAddress; +Socket_t xListeningSocket; + + /* Just to prevent compiler warnings. */ + ( void ) pvParameters; + + /* Attempt to open the socket. */ + xListeningSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET ); + + /* This test receives data sent from a different port on the same IP address. + Obtain the nodes IP address. Configure the freertos_sockaddr structure with + the address being bound to. The strange casting is to try and remove + compiler warnings on 32 bit machines. Note that this task is only created + after the network is up, so the IP address is valid here. */ + FreeRTOS_GetAddressConfiguration( &ulIPAddress, NULL, NULL, NULL ); + xBindAddress.sin_addr = ulIPAddress; + xBindAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL; + xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port ); + + /* Bind the socket to the port that the client task will send to. */ + FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) ); + + for( ;; ) + { + /* Receive data on the socket. ulFlags has the zero copy bit set + (FREERTOS_ZERO_COPY) indicating to the stack that a reference to the + received data should be passed out to this task using the second + parameter to the FreeRTOS_recvfrom() call. When this is done the + IP stack is no longer responsible for releasing the buffer, and + the task *must* return the buffer to the stack when it is no longer + needed. By default the block time is portMAX_DELAY. */ + lBytes = FreeRTOS_recvfrom( xListeningSocket, ( void * ) &pucUDPPayloadBuffer, 0, FREERTOS_ZERO_COPY, &xClient, &xClientLength ); + + /* Print the received characters. */ + if( lBytes > 0 ) + { + /* It is expected to receive one more byte than the string length as + the NULL terminator is also transmitted. */ + configASSERT( lBytes == ( ( BaseType_t ) strlen( ( const char * ) pucUDPPayloadBuffer ) + 1 ) ); + } + + if( lBytes >= 0 ) + { + /* The buffer *must* be freed once it is no longer needed. */ + FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer ); + } + } +} + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TCPEchoClient_SeparateTasks.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TCPEchoClient_SeparateTasks.c new file mode 100644 index 000000000..22993d2e3 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TCPEchoClient_SeparateTasks.c @@ -0,0 +1,468 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * A set of Tx and a set of Rx tasks are created. The Tx tasks send TCP echo + * requests to the standard echo port (port 7) on the IP address set by the + * configECHO_SERVER_ADDR0 to configECHO_SERVER_ADDR3 constants. The Rx tasks + * then use the same socket to receive and validate the echoed reply. + * + * See the following web page for essential demo usage and configuration + * details: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html + */ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "event_groups.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Exclude the whole file if FreeRTOSIPConfig.h is configured to use UDP only. */ +#if( ipconfigUSE_TCP == 1 ) + +/* Short delay used between demo cycles to ensure the network does not get too +congested. */ +#define echoLOOP_DELAY pdMS_TO_TICKS( 500UL ) + +/* The echo server is assumed to be on port 7, which is the standard echo +protocol port. */ +#define echoECHO_PORT ( 7 ) + +/* Dimensions the buffer used by prvEchoClientTxTask() to send a multiple of +MSS bytes at once. */ +#define echoLARGE_BUFFER_SIZE_MULTIPLIER ( 10 ) + +/* Bit definitions used with the xSyncEventGroup event group to allow the +prvEchoClientTxTask() and prvEchoClientRxTask() tasks to synchronise before +commencing a new cycle with a different socket. */ +#define echoTX_TASK_BIT ( 0x01 << 1 ) +#define echoRX_TASK_BIT ( 0x01 << 2 ) + +/*-----------------------------------------------------------*/ + +/* + * Uses a socket to send more than MSS bytes in one go to the standard echo + * port number 7. The echoed data is received on the same socket but in a + * different task (see prvEchoClientRxTask() below). + */ +static void prvEchoClientTxTask( void *pvParameters ); + +/* + * Uses the socket created in prvEchoClientTxTask() to receive the data sent + * to the echo server by the prvEchoClientTxTask(). + */ +static void prvEchoClientRxTask( void *pvParameters ); + +/* Rx and Tx time outs are used to ensure the sockets do not wait too long for +missing data. */ +static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 500 ); +static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 2000 ); + +/* Counters for each task created - for inspection only. */ +static uint32_t ulTxTaskCycles = 0, ulRxTaskCycles = 0; + +/* The queue used by prvEchoClientTxTask() to send the next socket to use to +prvEchoClientRxTask(). */ +static QueueHandle_t xSocketPassingQueue = NULL; + +/* The event group used by the prvEchoClientTxTask() and prvEchoClientRxTask() +to synchronise prior to commencing a cycle using a new socket. */ +static EventGroupHandle_t xSyncEventGroup = NULL; + +/* Flag used to inform the Rx task that the socket is about to be shut down. */ +int32_t lShuttingDown = pdFALSE; + +/*-----------------------------------------------------------*/ + +void vStartTCPEchoClientTasks_SeparateTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ) +{ + /* Create the queue used to pass the socket to use from the Tx task to the + Rx task. */ + xSocketPassingQueue = xQueueCreate( 1, sizeof( Socket_t ) ); + configASSERT( xSocketPassingQueue ); + + /* Create the event group used by the Tx and Rx tasks to synchronise prior + to commencing a cycle using a new socket. */ + xSyncEventGroup = xEventGroupCreate(); + configASSERT( xSyncEventGroup ); + + /* Create the task that sends to an echo server, but lets a different task + receive the reply on the same socket. */ + xTaskCreate( prvEchoClientTxTask, /* The function that implements the task. */ + "Echo0", /* Just a text name for the task to aid debugging. */ + usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */ + NULL, /* The task parameter, not used in this case. */ + uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */ + NULL ); /* The task handle is not used. */ + + /* Create the task that receives the reply to echos initiated by the + prvEchoClientTxTask() task. */ + xTaskCreate( prvEchoClientRxTask, "EchoRx", configMINIMAL_STACK_SIZE, NULL, uxTaskPriority + 1, NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvEchoClientTxTask( void *pvParameters ) +{ +Socket_t xSocket; +struct freertos_sockaddr xEchoServerAddress; +static char cTransmittedString[ ipconfigTCP_MSS * echoLARGE_BUFFER_SIZE_MULTIPLIER ]; +uint32_t ulTxCount = 0UL, ulJunk; +BaseType_t lTransmitted, lReturned = 0, lCharacter; +const BaseType_t lStringLength = ipconfigTCP_MSS * echoLARGE_BUFFER_SIZE_MULTIPLIER; +size_t xLenToSend; +const uint32_t ulNumTxPerSocket = 5UL; +WinProperties_t xWinProps; +const TickType_t xTxEmptyDelay = 20 / portTICK_PERIOD_MS; +TickType_t xTimeEnteringLoop; + + /* Avoid warning about unused parameter. */ + ( void ) pvParameters; + + /* Fill in the required buffer and window sizes. */ + xWinProps.lTxBufSize = 6 * ipconfigTCP_MSS; + xWinProps.lTxWinSize = 3; + xWinProps.lRxBufSize = 6 * ipconfigTCP_MSS; + xWinProps.lRxWinSize = 3; + + /* Echo requests are sent to the echo server. The address of the echo + server is configured by the constants configECHO_SERVER_ADDR0 to + configECHO_SERVER_ADDR3 in FreeRTOSConfig.h. */ + xEchoServerAddress.sin_port = FreeRTOS_htons( echoECHO_PORT ); + xEchoServerAddress.sin_addr = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0, + configECHO_SERVER_ADDR1, + configECHO_SERVER_ADDR2, + configECHO_SERVER_ADDR3 ); + + /* Create the string that is sent to the echo server. */ + for( ulTxCount = 0; ulTxCount < echoLARGE_BUFFER_SIZE_MULTIPLIER; ulTxCount++ ) + { + /* Generate character. */ + lCharacter = ( int32_t ) '0' + ulTxCount; + + /* Write a whole ipconfigTCP_MSS block of the character into the Tx + buffer. */ + memset( ( void * ) &( cTransmittedString[ ipconfigTCP_MSS * ulTxCount ] ), lCharacter, ipconfigTCP_MSS ); + } + + for( ;; ) + { + ulTxCount = 0; + + /* Create a socket. */ + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + configASSERT( xSocket != FREERTOS_INVALID_SOCKET ); + + /* Set a time out so a missing reply does not cause the task to block + indefinitely. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + + /* Set the buffer and window sizes. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); + + /* Attempt to connect to the echo server. */ + if( FreeRTOS_connect( xSocket, &xEchoServerAddress, sizeof( xEchoServerAddress ) ) == 0 ) + { + /* Send the connected socket to the Rx task so it can receive the + echoed replies from a different task. */ + lReturned = xQueueSend( xSocketPassingQueue, &xSocket, portMAX_DELAY ); + configASSERT( lReturned == pdPASS ); + + while( ulTxCount < ulNumTxPerSocket ) + { + lTransmitted = 0; + + /* Keep sending until the entire buffer has been sent. */ + while( lTransmitted < lStringLength ) + { + /* How many bytes are left to send? Attempt to send them + all at once (so the length is potentially greater than the + MSS). */ + xLenToSend = lStringLength - lTransmitted; + + lReturned = FreeRTOS_send( xSocket, /* The socket being sent to. */ + ( void * ) &( cTransmittedString[ lTransmitted ] ), /* The data being sent. */ + xLenToSend, /* The length of the data being sent. */ + 0 ); /* ulFlags. */ + + if( lReturned >= 0 ) + { + /* Data was sent successfully. */ + lTransmitted += lReturned; + } + else + { + /* Error - close the socket. */ + break; + } + } + + if( lReturned < 0 ) + { + /* The data was not sent for some reason - close the + socket. */ + break; + } + else + { + /* Keep a count of how many echo requests have been transmitted + so it can be compared to the number of echo replies received. + It would be expected to loose at least one to an ARP message + the first time the connection is created. */ + ulTxTaskCycles++; + + /* Increment the number of times the message has been sent + to this socket - after so many cycles the socket will be + closed and a new one opened. */ + ulTxCount++; + } + } + + /* Wait until all Tx data has left the buffer. */ + xTimeEnteringLoop = xTaskGetTickCount(); + while( ( FreeRTOS_tx_size( xSocket ) > 0 ) && ( FreeRTOS_issocketconnected( xSocket ) == pdTRUE ) ) + { + vTaskDelay( xTxEmptyDelay ); + + if( ( xTaskGetTickCount() - xTimeEnteringLoop ) > xSendTimeOut ) + { + /* Give up waiting. */ + break; + } + } + + /* Inform the other task that is using the same socket that this + task is waiting to shut the socket. */ + lShuttingDown = pdTRUE; + + /* Wait for the Rx task to recognise the socket is closing and stop + using it. NOTE: This should really have a time out but for simplicity + of demonstration the time out is omitted. */ + xEventGroupSync( xSyncEventGroup, /* The event group used for the rendezvous. */ + echoTX_TASK_BIT, /* The bit representing the Tx task reaching the rendezvous. */ + ( echoTX_TASK_BIT | echoRX_TASK_BIT ), /* Also wait for the Rx task. */ + portMAX_DELAY ); /* See comment above about lack of time out. */ + lShuttingDown = pdFALSE; + + xTimeEnteringLoop = xTaskGetTickCount(); + + /* Initiate graceful shut down. */ + FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR ); + + /* Wait for the receive calls to return an error - indicating that + the socket is no longer connected. */ + xTimeEnteringLoop = xTaskGetTickCount(); + do + { + lReturned = FreeRTOS_recv( xSocket, /* The socket being received from. */ + &ulJunk, /* The buffer into which the received data will be written. */ + sizeof( ulJunk ), /* The size of the buffer provided to receive the data. */ + 0 ); + + if( lReturned < 0 ) + { + break; + } + + } while( ( xTaskGetTickCount() - xTimeEnteringLoop ) < ( xReceiveTimeOut * 2 ) ); + } + + /* The Rx task is no longer using the socket so the socket can be + closed. */ + FreeRTOS_closesocket( xSocket ); + + /* Pause for a short while to ensure the network is not too + congested. */ + vTaskDelay( echoLOOP_DELAY ); + } +} +/*-----------------------------------------------------------*/ + +static void prvEchoClientRxTask( void *pvParameters ) +{ +Socket_t xSocket; +static char cReceivedString[ ipconfigTCP_MSS ], cExpectedString[ ipconfigTCP_MSS ]; +BaseType_t lReceived, lReturned = 0, lExpectedCharacter; + + ( void ) pvParameters; + + for( ;; ) + { + lExpectedCharacter = 0; + + /* Wait to receive the socket that will be used from the Tx task. */ + xQueueReceive( xSocketPassingQueue, &xSocket, portMAX_DELAY ); + + for( ;; ) + { + /* Clear down the Rx buffer. */ + memset( ( void * ) cReceivedString, 0x00, ipconfigTCP_MSS ); + + /* Fill the buffer that contains the expected string with the next + expected value. */ + memset( ( void * ) cExpectedString, ( int32_t ) '0' + lExpectedCharacter, ipconfigTCP_MSS ); + lExpectedCharacter++; + + if( lExpectedCharacter >= echoLARGE_BUFFER_SIZE_MULTIPLIER ) + { + lExpectedCharacter = 0; + } + + /* Nothing received yet. */ + lReceived = 0; + + /* Receive MSS bytes at a time as the data changes each MSS size. */ + while( lReceived < ipconfigTCP_MSS ) + { + lReturned = FreeRTOS_recv( xSocket, &( cReceivedString[ lReceived ] ), ipconfigTCP_MSS - lReceived, 0 ); + + if( ( lReturned == 0 ) && ( lShuttingDown == pdTRUE ) ) + { + /* No bytes received but the Tx task is waiting to shut the + socket. Set lReturned to a negative number so the logic + below breaks out of the loop. */ + lReturned = -1; + break; + } + else if( lReturned >= 0 ) + { + /* Data was received. */ + lReceived += lReturned; + } + else + { + /* Error. The socket has probably been shut down already by + the Tx task, but try again just in case not. */ + break; + } + } + + if( lReturned < 0 ) + { + /* Socket is probably being shut down. */ + break; + } + else + { + /* Check the string actually received matches the string + expected. */ + configASSERT( memcmp( ( void * ) cReceivedString, ( void * ) cExpectedString, ipconfigTCP_MSS ) == 0 ); + ulRxTaskCycles++; + } + } + + /* Rendezvous with the Tx task ready to start a new cycle with a + different socket. NOTE: This should really have a time out but for + simplicity of demonstration the time out is omitted. */ + xEventGroupSync( xSyncEventGroup, /* The event group used for the rendezvous. */ + echoRX_TASK_BIT, /* The bit representing the Rx task reaching the rendezvous. */ + ( echoTX_TASK_BIT | echoRX_TASK_BIT ), /* Also wait for the Tx task. */ + portMAX_DELAY ); /* See comment above about lack of time out. */ + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xAreSeparateTaskTCPEchoClientsStillRunning( void ) +{ +static uint32_t ulLastTxTaskCycles = 0, ulLastRxTaskCycles = 0; +BaseType_t xReturn = pdPASS; + + if( ulTxTaskCycles == ulLastTxTaskCycles ) + { + xReturn = pdFAIL; + } + else + { + ulLastTxTaskCycles = ulTxTaskCycles; + } + + if( ulRxTaskCycles == ulLastRxTaskCycles ) + { + xReturn = pdFAIL; + } + else + { + ulLastRxTaskCycles = ulRxTaskCycles; + } + + return xReturn; +} + +#endif /* ipconfigUSE_TCP */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TCPEchoClient_SingleTasks.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TCPEchoClient_SingleTasks.c new file mode 100644 index 000000000..4ebd6e3d5 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TCPEchoClient_SingleTasks.c @@ -0,0 +1,400 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * A set of tasks are created that send TCP echo requests to the standard echo + * port (port 7) on the IP address set by the configECHO_SERVER_ADDR0 to + * configECHO_SERVER_ADDR3 constants, then wait for and verify the reply + * (another demo is avilable that demonstrates the reception being performed in + * a task other than that from with the request was made). + * + * See the following web page for essential demo usage and configuration + * details: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html + */ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Exclude the whole file if FreeRTOSIPConfig.h is configured to use UDP only. */ +#if( ipconfigUSE_TCP == 1 ) + +/* The echo tasks create a socket, send out a number of echo requests, listen +for the echo reply, then close the socket again before starting over. This +delay is used between each iteration to ensure the network does not get too +congested. */ +#define echoLOOP_DELAY ( ( TickType_t ) 150 / portTICK_PERIOD_MS ) + +/* The echo server is assumed to be on port 7, which is the standard echo +protocol port. */ +#define echoECHO_PORT ( 7 ) + +/* The size of the buffers is a multiple of the MSS - the length of the data +sent is a pseudo random size between 20 and echoBUFFER_SIZES. */ +#define echoBUFFER_SIZE_MULTIPLIER ( 3 ) +#define echoBUFFER_SIZES ( ipconfigTCP_MSS * echoBUFFER_SIZE_MULTIPLIER ) + +/* The number of instances of the echo client task to create. */ +#define echoNUM_ECHO_CLIENTS ( 5 ) + +/*-----------------------------------------------------------*/ + +/* + * Uses a socket to send data to, then receive data from, the standard echo + * port number 7. + */ +static void prvEchoClientTask( void *pvParameters ); + +/* + * Creates a pseudo random sized buffer of data to send to the echo server. + */ +static BaseType_t prvCreateTxData( char *ucBuffer, uint32_t ulBufferLength ); + +/*-----------------------------------------------------------*/ + +/* Rx and Tx time outs are used to ensure the sockets do not wait too long for +missing data. */ +static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 4000 ); +static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 2000 ); + +/* Counters for each created task - for inspection only. */ +static uint32_t ulTxRxCycles[ echoNUM_ECHO_CLIENTS ] = { 0 }, + ulTxRxFailures[ echoNUM_ECHO_CLIENTS ] = { 0 }, + ulConnections[ echoNUM_ECHO_CLIENTS ] = { 0 }; + +/* Rx and Tx buffers for each created task. */ +static char cTxBuffers[ echoNUM_ECHO_CLIENTS ][ echoBUFFER_SIZES ], + cRxBuffers[ echoNUM_ECHO_CLIENTS ][ echoBUFFER_SIZES ]; + +/*-----------------------------------------------------------*/ + +void vStartTCPEchoClientTasks_SingleTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ) +{ +BaseType_t x; + + /* Create the echo client tasks. */ + for( x = 0; x < echoNUM_ECHO_CLIENTS; x++ ) + { + xTaskCreate( prvEchoClientTask, /* The function that implements the task. */ + "Echo0", /* Just a text name for the task to aid debugging. */ + usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */ + ( void * ) x, /* The task parameter, not used in this case. */ + uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */ + NULL ); /* The task handle is not used. */ + } +} +/*-----------------------------------------------------------*/ + +static void prvEchoClientTask( void *pvParameters ) +{ +Socket_t xSocket; +struct freertos_sockaddr xEchoServerAddress; +int32_t lLoopCount = 0UL; +const int32_t lMaxLoopCount = 1; +volatile uint32_t ulTxCount = 0UL; +BaseType_t xReceivedBytes, xReturned, xInstance; +BaseType_t lTransmitted, lStringLength; +char *pcTransmittedString, *pcReceivedString; +WinProperties_t xWinProps; +TickType_t xTimeOnEntering; + + /* Fill in the buffer and window sizes that will be used by the socket. */ + xWinProps.lTxBufSize = 6 * ipconfigTCP_MSS; + xWinProps.lTxWinSize = 3; + xWinProps.lRxBufSize = 6 * ipconfigTCP_MSS; + xWinProps.lRxWinSize = 3; + + /* This task can be created a number of times. Each instance is numbered + to enable each instance to use a different Rx and Tx buffer. The number is + passed in as the task's parameter. */ + xInstance = ( BaseType_t ) pvParameters; + + /* Point to the buffers to be used by this instance of this task. */ + pcTransmittedString = &( cTxBuffers[ xInstance ][ 0 ] ); + pcReceivedString = &( cRxBuffers[ xInstance ][ 0 ] ); + + /* Echo requests are sent to the echo server. The address of the echo + server is configured by the constants configECHO_SERVER_ADDR0 to + configECHO_SERVER_ADDR3 in FreeRTOSConfig.h. */ + xEchoServerAddress.sin_port = FreeRTOS_htons( echoECHO_PORT ); + xEchoServerAddress.sin_addr = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0, + configECHO_SERVER_ADDR1, + configECHO_SERVER_ADDR2, + configECHO_SERVER_ADDR3 ); + + for( ;; ) + { + /* Create a TCP socket. */ + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + configASSERT( xSocket != FREERTOS_INVALID_SOCKET ); + + /* Set a time out so a missing reply does not cause the task to block + indefinitely. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + + /* Set the window and buffer sizes. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) ); + + /* Connect to the echo server. */ + if( FreeRTOS_connect( xSocket, &xEchoServerAddress, sizeof( xEchoServerAddress ) ) == 0 ) + { + ulConnections[ xInstance ]++; + + /* Send a number of echo requests. */ + for( lLoopCount = 0; lLoopCount < lMaxLoopCount; lLoopCount++ ) + { + /* Create the string that is sent to the echo server. */ + lStringLength = prvCreateTxData( pcTransmittedString, echoBUFFER_SIZES ); + + /* Add in some unique text at the front of the string. */ + sprintf( pcTransmittedString, "TxRx message number %u", ulTxCount ); + ulTxCount++; + + /* Send the string to the socket. */ + lTransmitted = FreeRTOS_send( xSocket, /* The socket being sent to. */ + ( void * ) pcTransmittedString, /* The data being sent. */ + lStringLength, /* The length of the data being sent. */ + 0 ); /* No flags. */ + + if( lTransmitted < 0 ) + { + /* Error? */ + break; + } + + /* Clear the buffer into which the echoed string will be + placed. */ + memset( ( void * ) pcReceivedString, 0x00, echoBUFFER_SIZES ); + xReceivedBytes = 0; + + /* Receive data echoed back to the socket. */ + while( xReceivedBytes < lTransmitted ) + { + xReturned = FreeRTOS_recv( xSocket, /* The socket being received from. */ + &( pcReceivedString[ xReceivedBytes ] ),/* The buffer into which the received data will be written. */ + lStringLength - xReceivedBytes, /* The size of the buffer provided to receive the data. */ + 0 ); /* No flags. */ + + if( xReturned < 0 ) + { + /* Error occurred. Latch it so it can be detected + below. */ + xReceivedBytes = xReturned; + break; + } + else if( xReturned == 0 ) + { + /* Timed out. */ + break; + } + else + { + /* Keep a count of the bytes received so far. */ + xReceivedBytes += xReturned; + } + } + + /* If an error occurred it will be latched in xReceivedBytes, + otherwise xReceived bytes will be just that - the number of + bytes received from the echo server. */ + if( xReceivedBytes > 0 ) + { + /* Compare the transmitted string to the received string. */ + configASSERT( strncmp( pcReceivedString, pcTransmittedString, lTransmitted ) == 0 ); + if( strncmp( pcReceivedString, pcTransmittedString, lTransmitted ) == 0 ) + { + /* The echo reply was received without error. */ + ulTxRxCycles[ xInstance ]++; + } + else + { + /* The received string did not match the transmitted + string. */ + ulTxRxFailures[ xInstance ]++; + break; + } + } + else if( xReceivedBytes < 0 ) + { + /* FreeRTOS_recv() returned an error. */ + break; + } + else + { + /* Timed out without receiving anything? */ + break; + } + } + + /* Finished using the connected socket, initiate a graceful close: + FIN, FIN+ACK, ACK. */ + FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR ); + + /* Expect FreeRTOS_recv() to return an error once the shutdown is + complete. */ + xTimeOnEntering = xTaskGetTickCount(); + do + { + xReturned = FreeRTOS_recv( xSocket, /* The socket being received from. */ + &( pcReceivedString[ 0 ] ), /* The buffer into which the received data will be written. */ + echoBUFFER_SIZES, /* The size of the buffer provided to receive the data. */ + 0 ); + + if( xReturned < 0 ) + { + break; + } + + } while( ( xTaskGetTickCount() - xTimeOnEntering ) < xReceiveTimeOut ); + } + + /* Close this socket before looping back to create another. */ + FreeRTOS_closesocket( xSocket ); + + /* Pause for a short while to ensure the network is not too + congested. */ + vTaskDelay( echoLOOP_DELAY ); + } +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvCreateTxData( char *cBuffer, uint32_t ulBufferLength ) +{ +BaseType_t lCharactersToAdd, lCharacter; +char cChar = '0'; +const BaseType_t lMinimumLength = 60; + + /* Randomise the number of characters that will be sent in the echo + request. */ + do + { + lCharactersToAdd = ipconfigRAND32() % ( ulBufferLength - 20UL ); + } while ( ( lCharactersToAdd == 0 ) || ( lCharactersToAdd < lMinimumLength ) ); /* Must be at least enough to add the unique text to the start of the string later. */ + + /* Fill the buffer. */ + for( lCharacter = 0; lCharacter < lCharactersToAdd; lCharacter++ ) + { + cBuffer[ lCharacter ] = cChar; + cChar++; + + if( cChar > '~' ) + { + cChar = '0'; + } + } + + return lCharactersToAdd; +} +/*-----------------------------------------------------------*/ + +BaseType_t xAreSingleTaskTCPEchoClientsStillRunning( void ) +{ +static uint32_t ulLastEchoSocketCount[ echoNUM_ECHO_CLIENTS ] = { 0 }, ulLastConnections[ echoNUM_ECHO_CLIENTS ] = { 0 }; +BaseType_t xReturn = pdPASS, x; + + /* Return fail is the number of cycles does not increment between + consecutive calls. */ + for( x = 0; x < echoNUM_ECHO_CLIENTS; x++ ) + { + if( ulTxRxCycles[ x ] == ulLastEchoSocketCount[ x ] ) + { + xReturn = pdFAIL; + } + else + { + ulLastEchoSocketCount[ x ] = ulTxRxCycles[ x ]; + } + + if( ulConnections[ x ] == ulLastConnections[ x ] ) + { + xReturn = pdFAIL; + } + else + { + ulConnections[ x ] = ulLastConnections[ x ]; + } + } + + return xReturn; +} + +#endif /* ipconfigUSE_TCP */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TCPEchoSelectServer.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TCPEchoSelectServer.c new file mode 100644 index 000000000..5d612e272 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TCPEchoSelectServer.c @@ -0,0 +1,415 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* Standard includes. */ +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_char_buf.h" + +#include "SimpleTCPEchoServer.h" /* For prvSimpleTcpServerClientTask */ + + +#define tcpechoNUMBER_OF_CLIENTS 0 + +void tcpWinShowEvent( BaseType_t aDoLog ); + +/* + * Listens for incoming echo connections. Creates a task to handle each + * connection. + */ +static void prvConnectionListeningTask( void *pvParameters ); + +/* Stores the stack size passed into vStartSimpleTCPServerTasks() so it can be +reused when the server listening task creates tasks to handle connections. */ +static unsigned short usUsedStackSize = 0; + +/*-----------------------------------------------------------*/ + +void vStartSelectTCPServerTasks( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority ) +{ +WORD wVersionRequested; +WSADATA xWSAData; +BaseType_t xClient; +//extern void prvSimpleTCPClientTask( void *pvParameters ); + + /* The clients use non-blocking Winsock sockets and must therefore run at + the idle priority. */ + configASSERT( uxPriority == tskIDLE_PRIORITY ); + + /* Create the TCP echo server. The echo server uses FreeRTOS+TCP through + the spoofed IP and MAC address. */ + xTaskCreate( prvConnectionListeningTask, "ServerListener", usStackSize, ( void * ) ulPort, uxPriority + 1, NULL ); + + /* Prepare to use WinSock library. */ + wVersionRequested = MAKEWORD( 2, 2 ); + configASSERT( WSAStartup( wVersionRequested, &xWSAData ) == ( WORD ) 0 ); + + /* Remember the requested stack size so it can be re-used by the server + listening task when it creates tasks to handle connections. */ + usUsedStackSize = usStackSize; +} + +#define SEND_BUFFER_SIZE ( 8 * ipconfigTCP_MSS ) + +typedef struct xTCP_SERVER { + Socket_t xSocket; + struct xTCP_SERVER *pxNext; + SSimpleBuf *pxSendData; + BaseType_t bHasSendRequest; +} TCPServer_t; + +static uint8_t cReceivedString[ ipconfigTCP_MSS ]; + +static void prvTcpInit( TCPServer_t *pxTcpServer ) +{ +struct freertos_sockaddr addr; +BaseType_t xReceiveTimeOut = 0; +BaseType_t xSendTimeOut = 0; + + pxTcpServer->pxSendData = ( SSimpleBuf * )pvPortMalloc( sizeof( *pxTcpServer->pxSendData ) - sizeof( pxTcpServer->pxSendData->array ) + SEND_BUFFER_SIZE + 1 ); + + configASSERT( pxTcpServer->pxSendData != NULL ); + memset( pxTcpServer->pxSendData, '\0', sizeof( *pxTcpServer->pxSendData ) ); + pxTcpServer->pxSendData->LENGTH = SEND_BUFFER_SIZE + 1; + + FreeRTOS_GetRemoteAddress( pxTcpServer->xSocket, &addr ); + FreeRTOS_debug_printf( ( "prvTcpInit: serving %xip:%u\n", + FreeRTOS_ntohl( addr.sin_addr ), addr.sin_port) ); + + FreeRTOS_setsockopt( pxTcpServer->xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + FreeRTOS_setsockopt( pxTcpServer->xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xReceiveTimeOut ) ); +} + +static void prvTcpClose( TCPServer_t *pxThisServer ) +{ + FreeRTOS_closesocket( pxThisServer->xSocket ); + vPortFree( pxThisServer->pxSendData ); + vPortFree( pxThisServer ); +} + +static BaseType_t prvTcpSend( TCPServer_t *pxTcpServer ) +{ +BaseType_t lBytes, lReturned, xReturn = 0; + + lBytes = sbGet( pxTcpServer->pxSendData, 0, cReceivedString, sizeof( cReceivedString ), pdTRUE ); + if( lBytes ) + { + /* Send as much as possible, non-blocking */ + lReturned = FreeRTOS_send( pxTcpServer->xSocket, cReceivedString, lBytes, 0 ); + if( lReturned > 0 ) + { + xReturn = sbGet( pxTcpServer->pxSendData, 0, NULL, lReturned, pdFALSE ); + } + } + return xReturn; +} + +static BaseType_t prvTcpHasSendData( TCPServer_t *pxTcpServer ) +{ + return ( sbGetSize( pxTcpServer->pxSendData ) > 0 ) ? 1 : 0; +} + +static BaseType_t prvTcpWork( TCPServer_t *pxTcpServer ) +{ +BaseType_t lBytes, lReturned, lMayWrite; + + lMayWrite = FreeRTOS_maywrite( pxTcpServer->xSocket ); + if( lMayWrite < 0 ) + return lMayWrite; + while( lMayWrite > 0 ) + { + lReturned = prvTcpSend( pxTcpServer ); + if( lReturned < 0 ) + return lReturned; + if( lReturned == 0 ) + break; + lMayWrite = FreeRTOS_maywrite( pxTcpServer->xSocket ); + if( lMayWrite < 0 ) + return lMayWrite; + } + for( ; ; ) + { + /* Zero out the receive array so there is NULL at the end of the string + when it is printed out. */ + memset( cReceivedString, 0x00, sizeof( cReceivedString ) ); + + /* Receive data on the socket. */ + lBytes = FreeRTOS_recv( pxTcpServer->xSocket, cReceivedString, sizeof( cReceivedString ), 0 ); + if( lBytes <= 0 ) + return lBytes; + /* Return the received characters. */ + if( lMayWrite > 0 && sbGetSize( pxTcpServer->pxSendData ) == 0 ) + { + /* The cirular buffer is empty, send the received data directly */ + lReturned = FreeRTOS_send( pxTcpServer->xSocket, cReceivedString, lBytes, 0 ); + if( lReturned < 0 ) + { + return -1; + } + if( lBytes > lReturned ) + { + /* Not all dta could be delivered, save them for later + * FD_SET( eSELECT_WRITE ) will be called */ + sbAdd( pxTcpServer->pxSendData, 0, cReceivedString + lReturned, lBytes - lReturned ); + } + lMayWrite = FreeRTOS_maywrite( pxTcpServer->xSocket ); + if( lMayWrite < 0 ) + return lMayWrite; + } else + { + sbAdd( pxTcpServer->pxSendData, 0, cReceivedString, lBytes ); + } + } +} + +static TickType_t lastTickTime; +static BaseType_t xTaskCount = 0, xConfirmedCount = 0; +static void prvConnectionListeningTask( void *pvParameters ) +{ +struct freertos_sockaddr xClient, xBindAddress; +Socket_t xListeningSocket; + +socklen_t xSize = sizeof( xClient ); +static const TickType_t xReceiveTimeOut = 0; //portMAX_DELAY; +const BaseType_t xBacklog = 10; +SocketSet_t xSocketSet; +struct xTCP_SERVER *pxServerList = NULL; +struct xTCP_SERVER *pxIterator; + +WinProperties_t winProps; + + /* Just to prevent compiler warnings. */ + ( void ) pvParameters; + + /* Attempt to open the socket. */ + xListeningSocket = FreeRTOS_socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); + configASSERT( xListeningSocket != FREERTOS_INVALID_SOCKET ); + + /* Set a time out so accept() will just wait for a connection. */ + FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + + memset(&winProps, '\0', sizeof( winProps ) ); + // Size in units of MSS + winProps.lTxBufSize = 1 * 1460;//1000; + winProps.lTxWinSize = 2; + + winProps.lRxBufSize = 2 * 1460; + winProps.lRxWinSize = 2; + + FreeRTOS_setsockopt( xListeningSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &winProps, sizeof( winProps ) ); + + /* The strange casting is to remove compiler errors. */ + xBindAddress.sin_port = ( uint16_t ) ( ( uint32_t ) pvParameters ) & 0xffffUL; + xBindAddress.sin_port = FreeRTOS_htons( xBindAddress.sin_port ); + + /* Bind the socket to the port that the client task will send to, then + listen for incoming connections. */ + while( FreeRTOS_bind( xListeningSocket, &xBindAddress, sizeof( xBindAddress ) ) != 0 ); + FreeRTOS_listen( xListeningSocket, xBacklog ); + lastTickTime = xTaskGetTickCount (); + + pxServerList = NULL; + + xSocketSet = FreeRTOS_createsocketset( ); + configASSERT( xSocketSet != NULL ); + FreeRTOS_FD_SET( xListeningSocket, xSocketSet, eSELECT_READ ); + + for( ;; ) + { + TickType_t xMask = FreeRTOS_select( xSocketSet, 3000 ); + + if( FreeRTOS_FD_ISSET( xListeningSocket, xSocketSet ) ) + { + Socket_t xNewSocket; + + xNewSocket = FreeRTOS_accept( xListeningSocket, &xClient, &xSize ); + if ( xNewSocket && xNewSocket != FREERTOS_INVALID_SOCKET ) + { + TCPServer_t *pxServer; + + FreeRTOS_debug_printf( ( "prvConnectionListeningTask: new connection %xip:%u\n", + FreeRTOS_ntohl( xClient.sin_addr ), FreeRTOS_ntohs( xClient.sin_port ) ) ); + + pxServer = (TCPServer_t *)pvPortMalloc( sizeof( *pxServer ) ); + memset( pxServer, '\0', sizeof( *pxServer )); + + pxServer->xSocket = xNewSocket; + FreeRTOS_FD_SET( xNewSocket, xSocketSet, eSELECT_READ | eSELECT_EXCEPT ); + if( pxServerList == NULL ) + { + /* This is the first server */ + pxServerList = pxServer; + } + else + { + /* Attach it to the end of the list */ + for( pxIterator = pxServerList; pxIterator->pxNext != NULL; pxIterator = pxIterator->pxNext ) + { + } + pxIterator->pxNext = pxServer; + } + prvTcpInit( pxServer ); + } + } + { + TCPServer_t *pxThisServer = NULL; + + for( pxIterator = pxServerList; pxIterator != NULL; ) + { + BaseType_t rc; + pxThisServer = pxIterator; + /* Move to the next one before the current gets deleted */ + pxIterator = pxIterator->pxNext; + + if( FreeRTOS_FD_ISSET( pxThisServer->xSocket, xSocketSet ) == 0 ) + { + continue; + } + + rc = prvTcpWork( pxThisServer ); + + if( rc < 0) + { + FreeRTOS_FD_CLR( pxThisServer->xSocket, xSocketSet, eSELECT_ALL ); + + if( pxServerList = pxThisServer ) + { + pxServerList = pxThisServer->pxNext; + } + else + { + struct xTCP_SERVER *pxOther; + for( pxOther = pxServerList; pxOther->pxNext != NULL; pxOther = pxOther->pxNext ) + { + if( pxOther->pxNext == pxThisServer ) + { + pxOther->pxNext == pxThisServer->pxNext; + break; + } + } + } + /* Close the socket and free the space */ + prvTcpClose( pxThisServer ); + } else + { + pxThisServer->bHasSendRequest = prvTcpHasSendData( pxThisServer ); + if( pxThisServer->bHasSendRequest ) + FreeRTOS_FD_SET( pxThisServer->xSocket, xSocketSet, eSELECT_WRITE ); + else + FreeRTOS_FD_CLR( pxThisServer->xSocket, xSocketSet, eSELECT_WRITE ); + //FreeRTOS_debug_printf( ( "SET_FD WRITE %d\n", pxServerFound->bHasSendRequest != 0 ) ); + } + } + } + if( ( xTaskGetTickCount () - lastTickTime ) > 30000 ) + { + lastTickTime = xTaskGetTickCount (); + //plusPrintf( "ListeningTask %ld,%ld tasks\n", xTaskCount, xConfirmedCount ); + } + } +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvCreateTxData( uint8_t *ucBuffer, uint32_t ulBufferLength ) +{ +BaseType_t lCharactersToAdd, lCharacter; +uint8_t ucChar = '0'; + + /* Randomise the number of characters that will be sent. */ + do + { + lCharactersToAdd = ipconfigRAND32() % ( ulBufferLength - 20UL ); + } while ( lCharactersToAdd == 0 ); + + /* Fill the buffer. */ + for( lCharacter = 0; lCharacter < lCharactersToAdd; lCharacter++ ) + { + ucBuffer[ lCharacter ] = ucChar; + ucChar++; + + if( ucChar > '~' ) + { + ucChar = '0'; + } + } + + return lCharactersToAdd; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TwoUDPEchoClients.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TwoUDPEchoClients.c new file mode 100644 index 000000000..3f60910ab --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/TwoUDPEchoClients.c @@ -0,0 +1,435 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * Two tasks are created that send UDP echo requests to the standard echo port + * (port 7). One task uses the standard socket interface, the other the zero + * copy socket interface. The IP address of the echo server must be configured + * using the configECHO_SERVER_ADDR0 to configECHO_SERVER_ADDR3 constants in + * FreeRTOSConfig.h. These tasks are self checking and will trigger a + * configASSERT() if the received echo reply does not match the transmitted echo + * request. As these tasks use UDP, and can therefore loose packets, they will + * cause configASSERT() to be called when they are run in a less than perfect + * networking environment, or when connected to an echo server that + * legitimately as UDP is used) opts not to reply to every echo request. + * + * See the following web page for essential demo usage and configuration + * details: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html + */ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Small delay used between attempts to obtain a zero copy buffer. */ +#define echoTINY_DELAY ( ( TickType_t ) 2 ) + +/* The echo tasks create a socket, send out a number of echo requests +(listening for each echo reply), then close the socket again before +starting over. This delay is used between each iteration to ensure the +network does not get too congested. */ +#define echoLOOP_DELAY ( ( TickType_t ) 250 / portTICK_PERIOD_MS ) + +/* When the trace recorder code is not included just #define away the call +to post the user event. */ +#define echoMARK_SEND_IN_TRACE_BUFFER( x ) +#define xZeroCopySendEvent 0 +#define xZeroCopyReceiveEvent 0 + +/* The echo server is assumed to be on port 7, which is the standard echo +protocol port. */ +#define echoECHO_PORT ( 7 ) + +/*-----------------------------------------------------------*/ + +/* + * Uses a socket to send data to, then receive data from, the standard echo + * port number 7. prvEchoClientTask() uses the standard interface. + * prvZeroCopyEchoClientTask() uses the zero copy interface. + */ +static void prvEchoClientTask( void *pvParameters ); +static void prvZeroCopyEchoClientTask( void *pvParameters ); + +/*-----------------------------------------------------------*/ + +/* Timeouts used to ensure the sockets don't wait forever. */ +static const TickType_t xReceiveTimeOut = 1500 / portTICK_PERIOD_MS; +static const TickType_t xSendTimeOut = 1500 / portTICK_PERIOD_MS; + +/* Simple delay to ensure ARPs don't get in the way. */ +const TickType_t ulInitialARPReplyDelay = ( 500UL / portTICK_PERIOD_MS ); + +/* Used for detecting errors. */ +static uint32_t ulStandardCycles = 0, ulZeroCopyCycles = 0; + +/*-----------------------------------------------------------*/ + +void vStartUDPEchoClientTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ) +{ + /* Create the echo client task that does not use the zero copy interface. */ + xTaskCreate( prvEchoClientTask, /* The function that implements the task. */ + "UDPEcho0", /* Just a text name for the task to aid debugging. */ + usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */ + NULL, /* The task parameter, not used in this case. */ + uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */ + NULL ); /* The task handle is not used. */ + + /* Create the echo client task that does use the zero copy interface. */ + xTaskCreate( prvZeroCopyEchoClientTask, /* The function that implements the task. */ + "UDPEcho1", /* Just a text name for the task to aid debugging. */ + usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */ + NULL, /* The task parameter, not used in this case. */ + uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */ + NULL ); /* The task handle is not used. */ +} +/*-----------------------------------------------------------*/ + +static void prvEchoClientTask( void *pvParameters ) +{ +Socket_t xSocket; +struct freertos_sockaddr xEchoServerAddress; +int8_t cTxString[ 50 ], cRxString[ 50 ]; /* Make sure the stack is large enough to hold these. Turn on stack overflow checking during debug to be sure. */ +int32_t lLoopCount = 0UL, lReturned; +const int32_t lMaxLoopCount = 50; +uint32_t xAddressLength = sizeof( xEchoServerAddress ), ulTxCount = 0; + + /* Remove compiler warning about unused parameters. */ + ( void ) pvParameters; + + /* Echo requests are sent to the echo server. The address of the echo + server is configured by the constants configECHO_SERVER_ADDR0 to + configECHO_SERVER_ADDR3 in FreeRTOSConfig.h. */ + xEchoServerAddress.sin_port = FreeRTOS_htons( echoECHO_PORT ); + xEchoServerAddress.sin_addr = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0, + configECHO_SERVER_ADDR1, + configECHO_SERVER_ADDR2, + configECHO_SERVER_ADDR3 ); + + /* Send a ping to elicit an ARP to ensure the MAC address is known before + the first UDP packet is sent - otherwise the UDP packet lost to the ARP will + trigger an assert. Wait enough time for the ARP reply before continuing. */ + #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + { + FreeRTOS_SendPingRequest( xEchoServerAddress.sin_addr, 1, portMAX_DELAY ); + } + #endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + + /* Just ensure ARPS don't get in the way. */ + vTaskDelay( ulInitialARPReplyDelay ); + + for( ;; ) + { + /* Create a socket. */ + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + configASSERT( xSocket != FREERTOS_INVALID_SOCKET ); + + /* Set time outs so failed sends and missing replies do not cause the + task to block indefinitely. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + + /* Send a number of echo requests. */ + for( lLoopCount = 0; lLoopCount < lMaxLoopCount; lLoopCount++ ) + { + /* Create the string that is sent to the echo server. */ + sprintf( ( char * ) cTxString, "Message number %u\r\n", ulTxCount ); + ulTxCount++; + + /* Send the string to the socket. ulFlags is set to 0, so the zero + copy interface is not used. That means the data from cTxString is + copied into a network buffer inside FreeRTOS_sendto(), and cTxString + can be reused as soon as FreeRTOS_sendto() has returned. 1 is added + to ensure the NULL string terminator is sent as part of the message. */ + lReturned = FreeRTOS_sendto( xSocket, /* The socket being sent to. */ + ( void * ) cTxString, /* The data being sent. */ + strlen( ( const char * ) cTxString ) + 1, /* The length of the data being sent. */ + 0, /* ulFlags with the FREERTOS_ZERO_COPY bit clear. */ + &xEchoServerAddress, /* The destination address. */ + sizeof( xEchoServerAddress ) ); + configASSERT( lReturned > 0 ); + + /* Receive data echoed back to the socket. ulFlags is zero, so the + zero copy option is not being used and the received data will be + copied into the buffer pointed to by cRxString. xAddressLength is + not actually used (at the time of writing this comment, anyway) by + FreeRTOS_recvfrom(), but is set appropriately in case future + versions do use it. */ + memset( ( void * ) cRxString, 0x00, sizeof( cRxString ) ); + lReturned = FreeRTOS_recvfrom( xSocket, /* The socket being received from. */ + cRxString, /* The buffer into which the received data will be written. */ + sizeof( cRxString ), /* The size of the buffer provided to receive the data. */ + 0, /* ulFlags with the FREERTOS_ZERO_COPY bit clear. */ + &xEchoServerAddress, /* The address from which the data was sent (the source address). */ + &xAddressLength ); + + /* Compare the transmitted string to the received string. */ + if( lReturned > 1 ) + { + if( strcmp( ( char * ) cRxString, ( char * ) cTxString ) == 0 ) + { + /* The echo reply was received without error. */ + ulStandardCycles++; + } + } + } + + /* Pause for a short while to ensure the network is not too + congested. */ + vTaskDelay( echoLOOP_DELAY ); + + /* Close this socket before looping back to create another. */ + FreeRTOS_closesocket( xSocket ); + } +} +/*-----------------------------------------------------------*/ + +static void prvZeroCopyEchoClientTask( void *pvParameters ) +{ +Socket_t xSocket; +struct freertos_sockaddr xEchoServerAddress; +static int8_t cTxString[ 40 ]; +int32_t lLoopCount = 0UL; +uint32_t xAddressLength = sizeof( xEchoServerAddress ), ulTxCount = 0; +int32_t lReturned; +uint8_t *pucUDPPayloadBuffer; +const int32_t lMaxLoopCount = 50; +const char * const pcStringToSend = "Zero copy message number"; +/* The buffer is large enough to hold the string, a number, and the string terminator. */ +const size_t xBufferLength = strlen( pcStringToSend ) + 35; + + #if ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 + { + /* When the trace recorder code is included user events are generated to + mark the sending and receiving of the echoed data (only in the zero copy + task). */ + xZeroCopySendEvent = xTraceOpenLabel( "ZeroCopyTx" ); + xZeroCopyReceiveEvent = xTraceOpenLabel( "ZeroCopyRx" ); + } + #endif /* ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS */ + + /* Remove compiler warning about unused parameters. */ + ( void ) pvParameters; + + /* Delay for a little while to ensure the other task has sent out a ping + in order for the ARP cache to contain the address of the echo server. */ + vTaskDelay( echoLOOP_DELAY >> 1 ); + + /* Echo requests are sent to the echo server. The address of the echo + server is configured by the constants configECHO_SERVER_ADDR0 to + configECHO_SERVER_ADDR3 in FreeRTOSConfig.h. */ + xEchoServerAddress.sin_port = FreeRTOS_htons( echoECHO_PORT ); + xEchoServerAddress.sin_addr = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0, + configECHO_SERVER_ADDR1, + configECHO_SERVER_ADDR2, + configECHO_SERVER_ADDR3 ); + + for( ;; ) + { + /* Create a socket. */ + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + configASSERT( xSocket != FREERTOS_INVALID_SOCKET ); + + /* Set a time outs so failed sends and missing replies do not cause the + task to block indefinitely. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) ); + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + + /* Send a number of echo requests. */ + for( lLoopCount = 0; lLoopCount < lMaxLoopCount; lLoopCount++ ) + { + /* This task is going to send using the zero copy interface. The + data being sent is therefore written directly into a buffer that is + passed by reference into the FreeRTOS_sendto() function. First + obtain a buffer of adequate size from the IP stack. Although a max + delay is used, the actual delay will be capped to + ipconfigMAX_SEND_BLOCK_TIME_TICKS, hence the test to ensure a buffer + was actually obtained. */ + pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xBufferLength, portMAX_DELAY ); + + if( pucUDPPayloadBuffer != NULL ) + { + /* A buffer was successfully obtained. Create the string that is + sent to the echo server. Note the string is written directly + into the buffer obtained from the IP stack. */ + sprintf( ( char * ) pucUDPPayloadBuffer, "%s %u\r\n", ( const char * ) "Zero copy message number", ulTxCount ); + ulTxCount++; + + /* Also copy the string into a local buffer so it can be compared + with the string that is later received back from the echo server. */ + strcpy( ( char * ) cTxString, ( char * ) pucUDPPayloadBuffer ); + + /* Pass the buffer into the send function. ulFlags has the + FREERTOS_ZERO_COPY bit set so the IP stack will take control of + the buffer, rather than copy data out of the buffer. */ + echoMARK_SEND_IN_TRACE_BUFFER( xZeroCopySendEvent ); + lReturned = FreeRTOS_sendto( xSocket, /* The socket being sent to. */ + ( void * ) pucUDPPayloadBuffer, /* The buffer being passed into the IP stack. */ + strlen( ( const char * ) cTxString ) + 1, /* The length of the data being sent. Plus 1 to ensure the null terminator is part of the data. */ + FREERTOS_ZERO_COPY, /* ulFlags with the zero copy bit is set. */ + &xEchoServerAddress, /* Where the data is being sent. */ + sizeof( xEchoServerAddress ) ); + + if( lReturned == 0 ) + { + /* The send operation failed, so this task is still + responsible for the buffer obtained from the IP stack. To + ensure the buffer is not lost it must either be used again, + or, as in this case, returned to the IP stack using + FreeRTOS_ReleaseUDPPayloadBuffer(). pucUDPPayloadBuffer can + be safely re-used to receive from the socket below once the + buffer has been returned to the stack. */ + FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer ); + } + else + { + /* The send was successful so the IP stack is now managing + the buffer pointed to by pucUDPPayloadBuffer, and the IP + stack will return the buffer once it has been sent. + pucUDPPayloadBuffer can be safely re-used to receive from + the socket below. */ + } + + /* Receive data on the socket. ulFlags has the zero copy bit set + (FREERTOS_ZERO_COPY) indicating to the stack that a reference to + the received data should be passed out to this task using the + second parameter to the FreeRTOS_recvfrom() call. When this is + done the IP stack is no longer responsible for releasing the + buffer, and the task *must* return the buffer to the stack when + it is no longer needed. By default the receive block time is + portMAX_DELAY. */ + echoMARK_SEND_IN_TRACE_BUFFER( xZeroCopyReceiveEvent ); + lReturned = FreeRTOS_recvfrom( xSocket, /* The socket to receive from. */ + ( void * ) &pucUDPPayloadBuffer, /* pucUDPPayloadBuffer will be set to point to the buffer that already contains the received data. */ + 0, /* Ignored because the zero copy interface is being used. */ + FREERTOS_ZERO_COPY, /* ulFlags with the FREERTOS_ZERO_COPY bit set. */ + &xEchoServerAddress, /* The address from which the data was sent. */ + &xAddressLength ); + + if( lReturned > 0 ) + { + /* Compare the string sent to the echo server with the string + received back from the echo server. */ + if( strcmp( ( char * ) pucUDPPayloadBuffer, ( char * ) cTxString ) == 0 ) + { + /* The strings matched. */ + ulZeroCopyCycles++; + } + + /* The buffer that contains the data passed out of the stack + *must* be returned to the stack. */ + FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer ); + } + } + } + + /* Pause for a short while to ensure the network is not too + congested. */ + vTaskDelay( echoLOOP_DELAY ); + + /* Close this socket before looping back to create another. */ + FreeRTOS_closesocket( xSocket ); + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xAreUDPEchoClientsStillRunning( void ) +{ +static uint32_t ulLastStandardCycles = 0, ulLastZeroCopyCycles = 0; +BaseType_t xReturn = pdPASS; + + if( ulStandardCycles == ulLastStandardCycles ) + { + xReturn = pdFAIL; + } + else + { + ulLastStandardCycles = ulStandardCycles; + } + + if( ulZeroCopyCycles == ulLastZeroCopyCycles ) + { + xReturn = pdFAIL; + } + else + { + ulLastZeroCopyCycles = ulZeroCopyCycles; + } + + return xReturn; +} diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/UDPSelectServer.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/UDPSelectServer.c new file mode 100644 index 000000000..a7fff8f94 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/UDPSelectServer.c @@ -0,0 +1,404 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * A number of sockets are created and added to a set. One task then blocks on + * the set while the other task sends data to a (pseudo) random member of the + * set. The value sent increments from 0 to selMAX_TX_VALUE, and when all the + * values have been sent a check is made that each expected value has indeed + * been received before the cycle re-starts. + * + * See the following web page for essential demo usage and configuration + * details: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html + */ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* Demo project includes. */ +#include "UDPSelectServer.h" + +/* Exclude the whole file if select() is not being supported. */ +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + +/* The numbers of sockets added to the set. */ +#define selNUMBER_OF_SOCKETS ( 3 ) + +/* Each cycle of the demo sends the value 0 to selMAX_TX_VALUE to a socket in +the set. */ +#define selMAX_TX_VALUE ( 100 ) + +/*-----------------------------------------------------------*/ + +/* + * The Tx task that sends the data to the sockets created by the Rx task and + * added to the select set. + */ +static void prvMultipleSocketTxTask( void *pvParameters ); + +/* + * Uses the FreeRTOS_select() API function to receive from multiple sockets. + * This task expects to receive every value from 0 to selMAX_TX_VALUE during + * each cycle of the demo. An array with an index for each value it expects to + * receive is used to record which values were and were not received. + */ +static void prvMultipleSocketRxTask( void *pvParameters ); + +/*-----------------------------------------------------------*/ + +/* The sockets used in FreeRTOS_select(). */ +static Socket_t xRxSockets[ selNUMBER_OF_SOCKETS ] = { 0 }; + +/* Used to monitor the status of the task. */ +static volatile uint32_t ulTxCycles = 0, ulRxCycles = 0, ulFailedRxCycles = 0, ulErrorOccurred = pdFALSE; + +/* The block time used by the Tx task when sending - other delays are derived +from this value. */ +const TickType_t xSendBlockTime = pdMS_TO_TICKS( 400 ); +const TickType_t xReceiveBlockTime = pdMS_TO_TICKS( 600 ); + +/* The Tx task needs to know the handle of the Rx task. */ +static TaskHandle_t xRxTaskHandle; + +/*-----------------------------------------------------------*/ + +void vStartUDPSelectServerTasks( uint16_t usStackSize, uint32_t ulFirstPortNumber, UBaseType_t uxPriority ) +{ + /* Create a task that sends to multiple sockets, and the task that uses the + FreeRTOS_select() function to receive from multiple sockets. The first port + number to use is passed into both tasks using the task's parameter. Other + port numbers are consecutive from the first. */ + xTaskCreate( prvMultipleSocketTxTask, "MultiTx", usStackSize, ( void * ) ulFirstPortNumber, uxPriority, NULL ); + xTaskCreate( prvMultipleSocketRxTask, "MultiRx", usStackSize, ( void * ) ulFirstPortNumber, uxPriority, &xRxTaskHandle ); +} +/*-----------------------------------------------------------*/ + +static void prvMultipleSocketRxTask( void *pvParameters ) +{ +SocketSet_t xFD_Set; +Socket_t xSocket; +struct freertos_sockaddr xAddress; +uint32_t xClientLength = sizeof( struct freertos_sockaddr ), ulFirstRxPortNumber, x; +uint32_t ulReceivedValue = 0, ulCount; +uint8_t ucReceivedValues[ selMAX_TX_VALUE ]; /* If the array position is pdTRUE then the corresponding value has been received. */ +int32_t lBytes; +const TickType_t xRxBlockTime = 0; +BaseType_t xResult; + + /* The number of the port the first Rx socket will be bound to is passed in + as the task parameter. Other port numbers used are consecutive from this. */ + ulFirstRxPortNumber = ( uint32_t ) pvParameters; + + /* Create the set for sockets that will be passed into FreeRTOS_select(). */ + xFD_Set = FreeRTOS_CreateSocketSet(); + + /* Create the sockets and add them to the set. */ + for( x = 0; x < selNUMBER_OF_SOCKETS; x++ ) + { + /* Create the next Rx socket. */ + xRxSockets[ x ] = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + configASSERT( xRxSockets[ x ] != FREERTOS_INVALID_SOCKET ); + + /* Bind to the next port number. */ + xAddress.sin_port = FreeRTOS_htons( ( uint16_t ) ( ulFirstRxPortNumber + x ) ); + FreeRTOS_bind( xRxSockets[ x ], &xAddress, sizeof( struct freertos_sockaddr ) ); + + /* There should always be data available after FreeRTOS_select() so + blocking on a read should not be necessary. */ + FreeRTOS_setsockopt( xRxSockets[ x ], 0, FREERTOS_SO_RCVTIMEO, &xRxBlockTime, sizeof( xRxBlockTime ) ); + + /* Add the created socket to the set. */ + FreeRTOS_FD_SET( xRxSockets[ x ], xFD_Set, eSELECT_ALL ); + } + + for( ;; ) + { + /* No values have yet been received so set each array position to + pdFALSE. Each expected Rx value has a corresponding array position. */ + memset( ( void * ) ucReceivedValues, pdFALSE, sizeof( ucReceivedValues ) ); + + /* Wait for the other task to resume this task - indicating that it is + about to start sending. */ + vTaskSuspend( NULL ); + + /* Expect to receive selMAX_TX_VALUE values. */ + ulCount = 0; + + while( ulCount < selMAX_TX_VALUE ) + { + /* Wait for a socket from the set to become available for + reading. */ + xResult = FreeRTOS_select( xFD_Set, xReceiveBlockTime ); + + if( xResult != 0 ) + { + /* See which sockets have data waiting to be read. */ + for( x = 0; x < selNUMBER_OF_SOCKETS; x++ ) + { + xSocket = xRxSockets[ x ]; + + /* Find the expected value for this socket */ + if( FreeRTOS_FD_ISSET( xSocket, xFD_Set ) != 0 ) + { + while( ( lBytes = FreeRTOS_recvfrom( xSocket, &( ulReceivedValue ), sizeof( uint32_t ), 0, &xAddress, &xClientLength ) ) > 0 ) + { + /* Received another message. */ + ulCount++; + + /* It is always expected that the read will pass. */ + configASSERT( ( size_t ) lBytes == ( sizeof( uint32_t ) ) ); + + /* Don't expect to receive anything greater than + selMAX_TX_VALUE - 1. */ + configASSERT( ulReceivedValue < selMAX_TX_VALUE ); + + /* Don't expect to receive any value twice. */ + configASSERT( ucReceivedValues[ ulReceivedValue ] != pdTRUE ); + if( ucReceivedValues[ ulReceivedValue ] != pdTRUE ) + { + /* Mark the value as received by setting its + index in the received array to pdTRUE. */ + ucReceivedValues[ ulReceivedValue ] = pdTRUE; + } + else + { + ulErrorOccurred = pdTRUE; + } + } + } + } + } + else + { + /* No value was received in time. */ + break; + } + } + + /* Were all values received? */ + if( ulCount == selMAX_TX_VALUE ) + { + /* Check all selMAX_TX_VALUE values are present and correct + before starting a new cycle. It is valid for a few values at + the beginning of the array to be missing as they may have been + dropped for ARP messages, so start a few indexes in. */ + for( ulCount = 4; ulCount < selMAX_TX_VALUE; ulCount++ ) + { + configASSERT( ucReceivedValues[ ulCount ] == pdTRUE ); + + if( ucReceivedValues[ ulCount ] != pdTRUE ) + { + /* The value corresponding to this array position was + never received. In a real application UDP is not + reliable, but in this tightly controlled test it is + unusual for a packet to be dropped. */ + ulErrorOccurred = pdTRUE; + } + } + + ulRxCycles++; + } + else + { + /* Just for viewing in the debugger. */ + ulFailedRxCycles++; + } + } +} +/*-----------------------------------------------------------*/ + +static void prvMultipleSocketTxTask( void *pvParameters ) +{ +uint32_t ulTxValue = 0; +struct freertos_sockaddr xDestinationAddress; +uint32_t ulIPAddress, ulFirstDestinationPortNumber, xPortNumber; +Socket_t xTxSocket; +uint32_t ulSendCount[ selNUMBER_OF_SOCKETS ]; + + memset( ulSendCount, '\0', sizeof( ulSendCount ) ); + + /* The first destination port number is passed in as the task parameter. + Other destination port numbers used are consecutive from this. */ + ulFirstDestinationPortNumber = ( uint32_t ) pvParameters; + + /* Create the socket used to send to the sockets created by the Rx task. + Let the IP stack select a port to bind to. */ + xTxSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + FreeRTOS_bind( xTxSocket, NULL, sizeof( struct freertos_sockaddr ) ); + + /* The Rx and Tx tasks execute at the same priority so it is possible that + the Tx task will fill up the send queue - set a Tx block time to ensure + flow control is managed if this happens. */ + FreeRTOS_setsockopt( xTxSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendBlockTime, sizeof( xSendBlockTime ) ); + + /* It is assumed that this task is not created until the network is up, + so the IP address can be obtained immediately. Store the IP address being + used in ulIPAddress. This is done so the socket can send to a different + port on the same IP address. */ + FreeRTOS_GetAddressConfiguration( &ulIPAddress, NULL, NULL, NULL ); + + /* This test sends to itself, so data sent from here is received by a server + socket on the same IP address. Setup the freertos_sockaddr structure with + this nodes IP address. */ + xDestinationAddress.sin_addr = ulIPAddress; + + /* Block for a short time to ensure the task implemented by the + prvMultipleSocketRxTask() function has finished creating the Rx sockets. */ + while( eTaskGetState( xRxTaskHandle ) != eSuspended ) + { + vTaskDelay( xSendBlockTime ); + } + vTaskResume( xRxTaskHandle ); + + for( ;; ) + { + /* Pseudo randomly select the destination port number from the range of + valid destination port numbers. */ + xPortNumber = ipconfigRAND32() % selNUMBER_OF_SOCKETS; + ulSendCount[ xPortNumber ]++; + xDestinationAddress.sin_port = ( uint16_t ) ( ulFirstDestinationPortNumber + xPortNumber ); + xDestinationAddress.sin_port = FreeRTOS_htons( xDestinationAddress.sin_port ); + + /* Send an incrementing value to the pseudo randomly selected port. */ + FreeRTOS_sendto( xTxSocket, &ulTxValue, sizeof( ulTxValue ), 0, &xDestinationAddress, sizeof( xDestinationAddress ) ); + ulTxValue++; + + if( ulTxValue >= selMAX_TX_VALUE ) + { + /* Start over. */ + ulTxValue = 0; + + /* As a sanity check that this demo is valid, ensure each socket has + been used at least once. */ + for( xPortNumber = 0; xPortNumber < selNUMBER_OF_SOCKETS; xPortNumber++ ) + { + if( ulSendCount[ xPortNumber ] == 0 ) + { + ulErrorOccurred = pdTRUE; + } + + ulSendCount[ xPortNumber ] = 0; + } + + /* Allow the Rx task to check it has received all the values. */ + while( eTaskGetState( xRxTaskHandle ) != eSuspended ) + { + vTaskDelay( xSendBlockTime ); + } + vTaskResume( xRxTaskHandle ); + + /* Increment to show this task is still executing. */ + ulTxCycles++; + } + + /* Delay here because in the Windows simulator the MAC interrupt + simulator delays, so network traffic cannot be received any faster than + this. */ + vTaskDelay( configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY << 2 ); + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xAreUDPSelectTasksStillRunning( void ) +{ +static uint32_t ulLastRxCycles = 0, ulLastTxCycles = 0; +BaseType_t ulError; + + ulError = ulErrorOccurred; + + if( ulRxCycles == ulLastRxCycles ) + { + ulError |= pdTRUE; + } + + if( ulTxCycles == ulLastTxCycles ) + { + ulError |= pdTRUE; + } + + ulLastRxCycles = ulRxCycles; + ulLastTxCycles = ulTxCycles; + + return !ulError; +} + +/* The whole file is excluded if select() is not being supported. */ +#endif /* ipconfigSUPPORT_SELECT_FUNCTION */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/SimpleTCPEchoServer.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/SimpleTCPEchoServer.h new file mode 100644 index 000000000..7409e6777 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/SimpleTCPEchoServer.h @@ -0,0 +1,76 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef SIMPLE_TCP_ECHO_SERVER_H +#define SIMPLE_TCP_ECHO_SERVER_H + +void vStartSimpleTCPServerTasks( uint16_t usStackSize, BaseType_t uxPriority ); +BaseType_t xAreTCPEchoServersStillRunning( void ); + +#endif /* SIMPLE_TCP_ECHO_SERVER_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/SimpleUDPClientAndServer.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/SimpleUDPClientAndServer.h new file mode 100644 index 000000000..daeec4993 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/SimpleUDPClientAndServer.h @@ -0,0 +1,75 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef SIMPLE_UDP_CLIENT_AND_SERVER_H +#define SIMPLE_UDPCLIENT_AND_SERVER_H + +void vStartSimpleUDPClientServerTasks( uint16_t usStackSize, uint32_t ulsPort, UBaseType_t uxPriority ); + +#endif /* SIMPLE_UDPCLIENT_AND_SERVER_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TCPEchoClient_SeparateTasks.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TCPEchoClient_SeparateTasks.h new file mode 100644 index 000000000..2ebca0d0b --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TCPEchoClient_SeparateTasks.h @@ -0,0 +1,83 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef SEPARATE_TASK_TCP_ECHO_CLIENTS_H +#define SEPARATE_TASK_TCP_ECHO_CLIENTS_H + +/* + * Create the TCP echo client tasks. One task uses the standard interface + * to send to and receive from an echo server. The other task uses the zero + * copy interface to send to and receive from an echo server. + */ +void vStartTCPEchoClientTasks_SeparateTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ); +BaseType_t xAreSeparateTaskTCPEchoClientsStillRunning( void ); + +#endif /* SEPARATE_TASK_TCP_ECHO_CLIENTS_H */ + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TCPEchoClient_SingleTasks.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TCPEchoClient_SingleTasks.h new file mode 100644 index 000000000..03dae2ff1 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TCPEchoClient_SingleTasks.h @@ -0,0 +1,82 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef SINGLE_TASK_TCP_ECHO_CLIENTS_H +#define SINGLE_TASK_TCP_ECHO_CLIENTS_H + +/* + * Create the TCP echo client tasks. This is the version where an echo request + * is made from the same task that listens for the echo reply. + */ +void vStartTCPEchoClientTasks_SingleTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ); +BaseType_t xAreSingleTaskTCPEchoClientsStillRunning( void ); + +#endif /* SINGLE_TASK_TCP_ECHO_CLIENTS_H */ + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TCPEchoSelectServer.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TCPEchoSelectServer.h new file mode 100644 index 000000000..c324a0771 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TCPEchoSelectServer.h @@ -0,0 +1,75 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef TCP_ECHO_SELECT_SERVER_H +#define TCP_ECHO_SELECT_SERVER_H + +void vStartSelectTCPServerTasks( uint16_t usStackSize, uint32_t ulPort, UBaseType_t uxPriority ); + +#endif /* TCP_ECHO_SELECT_SERVER_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TwoUDPEchoClients.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TwoUDPEchoClients.h new file mode 100644 index 000000000..9d7b54610 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/TwoUDPEchoClients.h @@ -0,0 +1,81 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef TWO_UDP_ECHO_CLIENTS_H +#define TWO_UDP_ECHO_CLIENTS_H + +/* + * Create the two UDP echo client tasks. One task uses the standard interface + * to send to and receive from an echo server. The other task uses the zero + * copy interface to send to and receive from an echo server. + */ +void vStartUDPEchoClientTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority ); +extern BaseType_t xAreUDPEchoClientsStillRunning( void ); + +#endif /* TWO_UDP_ECHO_CLIENTS_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/UDPSelectServer.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/UDPSelectServer.h new file mode 100644 index 000000000..accd2fdc0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/DemoTasks/include/UDPSelectServer.h @@ -0,0 +1,76 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef UDP_SELECT_SERVER_H +#define UDP_SELECT_SERVER_H + +void vStartUDPSelectServerTasks( uint16_t usStackSize, uint32_t ulFirstPortNumber, UBaseType_t uxPriority ); +BaseType_t xAreUDPSelectTasksStillRunning( void ); + +#endif /* UDP_SELECT_SERVER_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOSConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOSConfig.h new file mode 100644 index 000000000..7c3f0f247 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOSConfig.h @@ -0,0 +1,267 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef FREERTOS_CONFIG_H +#define FREERTOS_CONFIG_H + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * http://www.freertos.org/a00110.html + * + * The bottom of this file contains some constants specific to running the UDP + * stack in this demo. Constants specific to FreeRTOS+TCP itself (rather than + * the demo) are contained in FreeRTOSIPConfig.h. + *----------------------------------------------------------*/ +#define configENABLE_BACKWARD_COMPATIBILITY 0 +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 +#define configMAX_PRIORITIES ( 7 ) +#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */ +#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */ +#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 2048U * 1024U ) ) +#define configMAX_TASK_NAME_LEN ( 15 ) +#define configUSE_TRACE_FACILITY 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_CO_ROUTINES 0 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configQUEUE_REGISTRY_SIZE 0 +#define configUSE_APPLICATION_TASK_TAG 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_ALTERNATIVE_API 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 3 /* FreeRTOS+FAT requires 2 pointers if a CWD is supported. */ + +/* Hook function related definitions. */ +#define configUSE_TICK_HOOK 0 +#define configUSE_IDLE_HOOK 1 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configCHECK_FOR_STACK_OVERFLOW 0 /* Not applicable to the Win32 port. */ + +/* Software timer related definitions. */ +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) +#define configTIMER_QUEUE_LENGTH 5 +#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 ) + +/* Event group related definitions. */ +#define configUSE_EVENT_GROUPS 1 + +/* Run time stats gathering definitions. */ +uint32_t ulGetRunTimeCounterValue( void ); +void vConfigureTimerForRunTimeStats( void ); +#define configGENERATE_RUN_TIME_STATS 1 +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vConfigureTimerForRunTimeStats() +#define portGET_RUN_TIME_COUNTER_VALUE() ulGetRunTimeCounterValue() + +/* Co-routine definitions. */ +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) + +/* Set the following definitions to 1 to include the API function, or zero +to exclude the API function. */ +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskCleanUpResources 0 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTimerGetTimerTaskHandle 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_xQueueGetMutexHolder 1 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xEventGroupSetBitsFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_pcTaskGetTaskName 1 + +/* This demo makes use of one or more example stats formatting functions. These +format the raw data provided by the uxTaskGetSystemState() function in to human +readable ASCII form. See the notes in the implementation of vTaskList() within +FreeRTOS/Source/tasks.c for limitations. configUSE_STATS_FORMATTING_FUNCTIONS +is set to 2 so the formatting functions are included without the stdio.h being +included in tasks.c. That is because this project defines its own sprintf() +functions. */ +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 + +/* Assert call defined for debug builds. */ +#ifdef _DEBUG + extern void vAssertCalled( const char *pcFile, uint32_t ulLine ); + #define configASSERT( x ) if( ( x ) == 0 ) vAssertCalled( __FILE__, __LINE__ ) +#endif /* _DEBUG */ + + + +/* Application specific definitions follow. **********************************/ + +/* If configINCLUDE_DEMO_DEBUG_STATS is set to one, then a few basic IP trace +macros are defined to gather some UDP stack statistics that can then be viewed +through the CLI interface. */ +#define configINCLUDE_DEMO_DEBUG_STATS 1 + +/* The size of the global output buffer that is available for use when there +are multiple command interpreters running at once (for example, one on a UART +and one on TCP/IP). This is done to prevent an output buffer being defined by +each implementation - which would waste RAM. In this case, there is only one +command interpreter running, and it has its own local output buffer, so the +global buffer is just set to be one byte long as it is not used and should not +take up unnecessary RAM. */ +#define configCOMMAND_INT_MAX_OUTPUT_SIZE 1 + +/* Only used when running in the FreeRTOS Windows simulator. Defines the +priority of the task used to simulate Ethernet interrupts. */ +#define configMAC_ISR_SIMULATOR_PRIORITY ( configMAX_PRIORITIES - 1 ) + +/* This demo creates a virtual network connection by accessing the raw Ethernet +or WiFi data to and from a real network connection. Many computers have more +than one real network port, and configNETWORK_INTERFACE_TO_USE is used to tell +the demo which real port should be used to create the virtual port. The ports +available are displayed on the console when the application is executed. For +example, on my development laptop setting configNETWORK_INTERFACE_TO_USE to 4 +results in the wired network being used, while setting +configNETWORK_INTERFACE_TO_USE to 2 results in the wireless network being +used. */ +#define configNETWORK_INTERFACE_TO_USE 2L + +/* The address of an echo server that will be used by the two demo echo client +tasks. +http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Clients.html +http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_Echo_Clients.html */ +#define configECHO_SERVER_ADDR0 192 +#define configECHO_SERVER_ADDR1 168 +#define configECHO_SERVER_ADDR2 0 +#define configECHO_SERVER_ADDR3 6 + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet/WiFi data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition above for information on how to +configure the real network connection to use. */ +#define configMAC_ADDR0 0x00 +#define configMAC_ADDR1 0x11 +#define configMAC_ADDR2 0x22 +#define configMAC_ADDR3 0x33 +#define configMAC_ADDR4 0x44 +#define configMAC_ADDR5 0x48 + +/* Default IP address configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configIP_ADDR0 172 +#define configIP_ADDR1 25 +#define configIP_ADDR2 218 +#define configIP_ADDR3 200 + +/* Default gateway IP address configuration. Used in ipconfigUSE_DNS is set to +0, or ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configGATEWAY_ADDR0 172 +#define configGATEWAY_ADDR1 25 +#define configGATEWAY_ADDR2 218 +#define configGATEWAY_ADDR3 1 + +/* Default DNS server configuration. OpenDNS addresses are 208.67.222.222 and +208.67.220.220. Used in ipconfigUSE_DNS is set to 0, or ipconfigUSE_DNS is set +to 1 but a DNS server cannot be contacted.*/ +#define configDNS_SERVER_ADDR0 208 +#define configDNS_SERVER_ADDR1 67 +#define configDNS_SERVER_ADDR2 222 +#define configDNS_SERVER_ADDR3 222 + +/* Default netmask configuration. Used in ipconfigUSE_DNS is set to 0, or +ipconfigUSE_DNS is set to 1 but a DNS server cannot be contacted. */ +#define configNET_MASK0 255 +#define configNET_MASK1 255 +#define configNET_MASK2 255 +#define configNET_MASK3 0 + +/* The UDP port to which print messages are sent. */ +#define configPRINT_PORT ( 15000 ) + +#define configHTTP_ROOT "/ram/websrc" + +#if( defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) && !defined( snprintf ) ) + /* Map to Windows names. */ + #define snprintf _snprintf + #define vsnprintf _vsnprintf +#endif + +/* Visual studio does not have an implementation of strcasecmp(). */ +#define strcasecmp _stricmp +#define strncasecmp _strnicmp +#define strcmpi _strcmpi + +#endif /* FREERTOS_CONFIG_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOSFATConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOSFATConfig.h new file mode 100644 index 000000000..8fd8821ef --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOSFATConfig.h @@ -0,0 +1,333 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef _FF_CONFIG_H_ +#define _FF_CONFIG_H_ + +/* Must be set to either pdFREERTOS_LITTLE_ENDIAN or pdFREERTOS_BIG_ENDIAN, +depending on the endian of the architecture on which FreeRTOS is running. */ +#define ffconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* Set to 1 to maintain a current working directory (CWD) for each task that +accesses the file system, allowing relative paths to be used. + +Set to 0 not to use a CWD, in which case full paths must be used for each +file access. */ +#define ffconfigHAS_CWD 1 + +/* Set to an index within FreeRTOS's thread local storage array that is free for +use by FreeRTOS+FAT. FreeRTOS+FAT will use two consecutive indexes from this +that set by ffconfigCWD_THREAD_LOCAL_INDEX. The number of thread local storage +pointers provided by FreeRTOS is set by configNUM_THREAD_LOCAL_STORAGE_POINTERS +in FreeRTOSConfig.h */ +#define ffconfigCWD_THREAD_LOCAL_INDEX 0 + +/* Set to 1 to include long file name support. Set to 0 to exclude long +file name support. + +If long file name support is excluded then only 8.3 file names can be used. +Long file names will be recognised but ignored. + +Users should familiarise themselves with any patent issues that may +potentially exist around the use of long file names in FAT file systems +before enabling long file name support. */ +#define ffconfigLFN_SUPPORT 1 + +/* Only used when ffconfigLFN_SUPPORT is set to 1. + +Set to 1 to include a file's short name when listing a directory, i.e. when +calling findfirst()/findnext(). The short name will be stored in the +'pcShortName' field of FF_DirEnt_t. + +Set to 0 to only include a file's long name. */ +#define ffconfigINCLUDE_SHORT_NAME 0 + +/* Set to 1 to recognise and apply the case bits used by Windows XP+ when +using short file names - storing file names such as "readme.TXT" or +"SETUP.exe" in a short-name entry. This is the recommended setting for +maximum compatibility. + +Set to 0 to ignore the case bits. */ +#define ffconfigSHORTNAME_CASE 1 + +/* Only used when ffconfigLFN_SUPPORT is set to 1. + +Set to 1 to use UTF-16 (wide-characters) for file and directory names. + +Set to 0 to use either 8-bit ASCII or UTF-8 for file and directory names +(see the ffconfigUNICODE_UTF8_SUPPORT). */ +#define ffconfigUNICODE_UTF16_SUPPORT 0 + +/* Only used when ffconfigLFN_SUPPORT is set to 1. + +Set to 1 to use UTF-8 encoding for file and directory names. + +Set to 0 to use either 8-bit ASCII or UTF-16 for file and directory +names (see the ffconfig_UTF_16_SUPPORT setting). */ +#define ffconfigUNICODE_UTF8_SUPPORT 0 + +/* Set to 1 to include FAT12 support. + +Set to 0 to exclude FAT12 support. + +FAT16 and FAT32 are always enabled. */ +#define ffconfigFAT12_SUPPORT 0 + +/* When writing and reading data, i/o becomes less efficient if sizes other +than 512 bytes are being used. When set to 1 each file handle will +allocate a 512-byte character buffer to facilitate "unaligned access". */ +#define ffconfigOPTIMISE_UNALIGNED_ACCESS 1 + +/* Input and output to a disk uses buffers that are only flushed at the +following times: + +- When a new buffer is needed and no other buffers are available. +- When opening a buffer in READ mode for a sector that has just been changed. +- After creating, removing or closing a file or a directory. + +Normally this is quick enough and it is efficient. If +ffconfigCACHE_WRITE_THROUGH is set to 1 then buffers will also be flushed each +time a buffer is released - which is less efficient but more secure. */ +#define ffconfigCACHE_WRITE_THROUGH 1 + +/* In most cases, the FAT table has two identical copies on the disk, +allowing the second copy to be used in the case of a read error. If + +Set to 1 to use both FATs - this is less efficient but more secure. + +Set to 0 to use only one FAT - the second FAT will never be written to. */ +#define ffconfigWRITE_BOTH_FATS 1 + +/* Set to 1 to have the number of free clusters and the first free cluster +to be written to the FS info sector each time one of those values changes. + +Set to 0 not to store these values in the FS info sector, making booting +slower, but making changes faster. */ +#define ffconfigWRITE_FREE_COUNT 1 + +/* Set to 1 to maintain file and directory time stamps for creation, modify +and last access. + +Set to 0 to exclude time stamps. + +If time support is used, the following function must be supplied: + + time_t FreeRTOS_time( time_t *pxTime ); + +FreeRTOS_time has the same semantics as the standard time() function. */ +#define ffconfigTIME_SUPPORT 1 + +/* Set to 1 if the media is removable (such as a memory card). + +Set to 0 if the media is not removable. + +When set to 1 all file handles will be "invalidated" if the media is +extracted. If set to 0 then file handles will not be invalidated. +In that case the user will have to confirm that the media is still present +before every access. */ +#define ffconfigREMOVABLE_MEDIA 0 + +/* Set to 1 to determine the disk's free space and the disk's first free +cluster when a disk is mounted. + +Set to 0 to find these two values when they are first needed. Determining +the values can take some time. */ +#define ffconfigMOUNT_FIND_FREE 1 + +/* Set to 1 to 'trust' the contents of the 'ulLastFreeCluster' and +ulFreeClusterCount fields. + +Set to 0 not to 'trust' these fields.*/ +#define ffconfigFSINFO_TRUSTED 1 + +/* Set to 1 to store recent paths in a cache, enabling much faster access +when the path is deep within a directory structure at the expense of +additional RAM usage. + +Set to 0 to not use a path cache. */ +#define ffconfigPATH_CACHE 1 + +/* Only used if ffconfigPATH_CACHE is 1. + +Sets the maximum number of paths that can exist in the patch cache at any +one time. */ +#define ffconfigPATH_CACHE_DEPTH 8 + +/* Set to 1 to calculate a HASH value for each existing short file name. +Use of HASH values can improve performance when working with large +directories, or with files that have a similar name. + +Set to 0 not to calculate a HASH value. */ +#define ffconfigHASH_CACHE 1 + +/* Only used if ffconfigHASH_CACHE is set to 1 + +Set to CRC8 or CRC16 to use 8-bit or 16-bit HASH values respectively. */ +#define ffconfigHASH_FUNCTION CRC16 + +/*_RB_ Not in FreeRTOSFFConfigDefaults.h. */ +#define ffconfigHASH_CACHE_DEPTH 64 + +/* Set to 1 to add a parameter to ff_mkdir() that allows an entire directory +tree to be created in one go, rather than having to create one directory in +the tree at a time. For example mkdir( "/etc/settings/network", pdTRUE );. + +Set to 0 to use the normal mkdir() semantics (without the additional +parameter). */ +#define ffconfigMKDIR_RECURSIVE 0 + +/* Set to a function that will be used for all dynamic memory allocations. +Setting to pvPortMalloc() will use the same memory allocator as FreeRTOS. */ +#define ffconfigMALLOC( size ) pvPortMalloc( size ) + +/* Set to a function that matches the above allocator defined with +ffconfigMALLOC. Setting to vPortFree() will use the same memory free +function as FreeRTOS. */ +#define ffconfigFREE( ptr ) vPortFree( ptr ) + +/* Set to 1 to calculate the free size and volume size as a 64-bit number. + +Set to 0 to calculate these values as a 32-bit number. */ +#define ffconfig64_NUM_SUPPORT 0 + +/* Defines the maximum number of partitions (and also logical partitions) +that can be recognised. */ +#define ffconfigMAX_PARTITIONS 1 + +/* Defines how many drives can be combined in total. Should be set to at +least 2. */ +#define ffconfigMAX_FILE_SYS 2 + +/* In case the low-level driver returns an error 'FF_ERR_DRIVER_BUSY', +the library will pause for a number of ms, defined in +ffconfigDRIVER_BUSY_SLEEP_MS before re-trying. */ +#define ffconfigDRIVER_BUSY_SLEEP_MS 20 + +/* Set to 1 to include the ff_fprintf() function. + +Set to 0 to exclude the ff_fprintf() function. + +ff_fprintf() is quite a heavy function because it allocates RAM and +brings in a lot of string and variable argument handling code. If +ff_fprintf() is not being used then the code size can be reduced by setting +ffconfigFPRINTF_SUPPORT to 0. */ +#define ffconfigFPRINTF_SUPPORT 1 + +/* ff_fprintf() will allocate a buffer of this size in which it will create +its formatted string. The buffer will be freed before the function +exits. */ +#define ffconfigFPRINTF_BUFFER_LENGTH 128 + +/* Set to 1 to inline some internal memory access functions. + +Set to 0 to not inline the memory access functions. */ +#define ffconfigINLINE_MEMORY_ACCESS 1 + +/* Officially the only criteria to determine the FAT type (12, 16, or 32 +bits) is the total number of clusters: +if( ulNumberOfClusters < 4085 ) : Volume is FAT12 +if( ulNumberOfClusters < 65525 ) : Volume is FAT16 +if( ulNumberOfClusters >= 65525 ) : Volume is FAT32 +Not every formatted device follows the above rule. + +Set to 1 to perform additional checks over and above inspecting the +number of clusters on a disk to determine the FAT type. + +Set to 0 to only look at the number of clusters on a disk to determine the +FAT type. */ +#define ffconfigFAT_CHECK 1 + +/* Sets the maximum length for file names, including the path. +Note that the value of this define is directly related to the maximum stack +use of the +FAT library. In some API's, a character buffer of size +'ffconfigMAX_FILENAME' will be declared on stack. */ +#define ffconfigMAX_FILENAME 250 + +/* Defined in main.c as Visual Studio does not provide its own implementation. */ +struct tm *gmtime_r( const time_t *pxTime, struct tm *tmStruct ); + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); +#define FF_PRINTF vLoggingPrintf + +/* Visual studio does not have an implementation of strcasecmp(). +_RB_ Cannot use FF_NOSTRCASECMP setting as the internal implementation of +strcasecmp() is in ff_dir, whereas it is used in the http server. Also not +sure of why FF_NOSTRCASECMP is being tested against 0 to define the internal +implementation, so I have to set it to 1 here, so it is not defined. */ +#define FF_NOSTRCASECMP 1 + +/* Include the recursive function ff_deltree(). The use of recursion does not +conform with the coding standard, so use this function with care! */ +#define ffconfigUSE_DELTREE 1 + +#endif /* _FF_CONFIG_H_ */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOSIPConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOSIPConfig.h new file mode 100644 index 000000000..3d506e440 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOSIPConfig.h @@ -0,0 +1,377 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + + +/***************************************************************************** + * + * See the following URL for configuration information. + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html + * + *****************************************************************************/ + +#ifndef FREERTOS_IP_CONFIG_H +#define FREERTOS_IP_CONFIG_H + +/* Prototype for the function used to print out. In this case it prints to the +console before the network is connected then a UDP port after the network has +connected. */ +extern void vLoggingPrintf( const char *pcFormatString, ... ); + +/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to +1 then FreeRTOS_debug_printf should be defined to the function used to print +out the debugging messages. */ +#define ipconfigHAS_DEBUG_PRINTF 0 +#if( ipconfigHAS_DEBUG_PRINTF == 1 ) + #define FreeRTOS_debug_printf(X) vLoggingPrintf X +#endif + +/* Set to 1 to print out non debugging messages, for example the output of the +FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1 +then FreeRTOS_printf should be set to the function used to print out the +messages. */ +#define ipconfigHAS_PRINTF 1 +#if( ipconfigHAS_PRINTF == 1 ) + #define FreeRTOS_printf(X) vLoggingPrintf X +#endif + +/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing +on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */ +#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN + +/* If the network card/driver includes checksum offloading (IP/TCP/UDP checksums) +then set ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software +stack repeating the checksum calculations. */ +#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 + +/* Several API's will block until the result is known, or the action has been +performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be +set per socket, using setsockopt(). If not set, the times below will be +used as defaults. */ +#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 5000 ) +#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 ) + +/* Include support for LLMNR: Link-local Multicast Name Resolution +(non-Microsoft) */ +#define ipconfigUSE_LLMNR ( 1 ) + +/* Include support for NBNS: NetBIOS Name Service (Microsoft) */ +#define ipconfigUSE_NBNS ( 1 ) + +/* Include support for DNS caching. For TCP, having a small DNS cache is very +useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low +and also DNS may use small timeouts. If a DNS reply comes in after the DNS +socket has been destroyed, the result will be stored into the cache. The next +call to FreeRTOS_gethostbyname() will return immediately, without even creating +a socket. */ +#define ipconfigUSE_DNS_CACHE ( 1 ) +#define ipconfigDNS_CACHE_NAME_LENGTH ( 16 ) +#define ipconfigDNS_CACHE_ENTRIES ( 4 ) +#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 ) + +/* The IP stack executes it its own task (although any application task can make +use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY +sets the priority of the task that executes the IP stack. The priority is a +standard FreeRTOS task priority so can take any value from 0 (the lowest +priority) to (configMAX_PRIORITIES - 1) (the highest priority). +configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in +FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to +the priority assigned to the task executing the IP stack relative to the +priority assigned to tasks that use the IP stack. */ +#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 ) + +/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP +task. This setting is less important when the FreeRTOS Win32 simulator is used +as the Win32 simulator only stores a fixed amount of information on the task +stack. FreeRTOS includes optional stack overflow detection, see: +http://www.freertos.org/Stacks-and-stack-overflow-checking.html */ +#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 ) + +/* ipconfigRAND32() is called by the IP stack to generate random numbers for +things such as a DHCP transaction number or initial sequence number. Random +number generation is performed via this macro to allow applications to use their +own random number generation method. For example, it might be possible to +generate a random number by sampling noise on an analogue input. */ +extern UBaseType_t uxRand(); +#define ipconfigRAND32() uxRand() + +/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the +network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK +is not set to 1 then the network event hook will never be called. See +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml +*/ +#define ipconfigUSE_NETWORK_EVENT_HOOK 1 + +/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but +a network buffer cannot be obtained then the calling task is held in the Blocked +state (so other tasks can continue to executed) until either a network buffer +becomes available or the send block time expires. If the send block time expires +then the send operation is aborted. The maximum allowable send block time is +capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the +maximum allowable send block time prevents prevents a deadlock occurring when +all the network buffers are in use and the tasks that process (and subsequently +free) the network buffers are themselves blocked waiting for a network buffer. +ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in +milliseconds can be converted to a time in ticks by dividing the time in +milliseconds by portTICK_PERIOD_MS. */ +#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000 / portTICK_PERIOD_MS ) + +/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP +address, netmask, DNS server address and gateway address from a DHCP server. If +ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The +stack will revert to using the static IP address even when ipconfigUSE_DHCP is +set to 1 if a valid configuration cannot be obtained from a DHCP server for any +reason. The static configuration used is that passed into the stack by the +FreeRTOS_IPInit() function call. */ +#define ipconfigUSE_DHCP 1 + +/* If ipconfigUSE_DHCP_HOOK is set to 1 then the application must provide a +hook (or 'callback') function called xApplicationDHCPHook(), the use of which is +explained on the following URL: +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html#ipconfigUSE_DHCP_HOOK */ +#define ipconfigUSE_DHCP_HOOK 0 + +/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at +increasing time intervals until either a reply is received from a DHCP server +and accepted, or the interval between transmissions reaches +ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the +static IP address passed as a parameter to FreeRTOS_IPInit() if the +re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without +a DHCP reply being received. */ +#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( 120000 / portTICK_PERIOD_MS ) + +/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP +stack can only send a UDP message to a remove IP address if it knowns the MAC +address associated with the IP address, or the MAC address of the router used to +contact the remote IP address. When a UDP message is received from a remote IP +address the MAC address and IP address are added to the ARP cache. When a UDP +message is sent to a remote IP address that does not already appear in the ARP +cache then the UDP message is replaced by a ARP message that solicits the +required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum +number of entries that can exist in the ARP table at any one time. */ +#define ipconfigARP_CACHE_ENTRIES 6 + +/* ARP requests that do not result in an ARP response will be re-transmitted a +maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is +aborted. */ +#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 ) + +/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP +table being created or refreshed and the entry being removed because it is stale. +New ARP requests are sent for ARP cache entries that are nearing their maximum +age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is +equal to 1500 seconds (or 25 minutes). */ +#define ipconfigMAX_ARP_AGE 150 + +/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling +routines, which are relatively large. To save code space the full +FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster +alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr() +takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter. +FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets +(for example, 192, 168, 0, 1) as its parameters. If +ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and +FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is +not set to 1 then only FreeRTOS_indet_addr_quick() is available. */ +#define ipconfigINCLUDE_FULL_INET_ADDR 1 + +/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that +are available to the IP stack. The total number of network buffers is limited +to ensure the total amount of RAM that can be consumed by the IP stack is capped +to a pre-determinable value. */ +#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60 + +/* A FreeRTOS queue is used to send events from application tasks to the IP +stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can +be queued for processing at any one time. The event queue must be a minimum of +5 greater than the total number of network buffers. */ +#define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) + +/* The address of a socket is the combination of its IP address and its port +number. FreeRTOS_bind() is used to manually allocate a port number to a socket +(to 'bind' the socket to a port), but manual binding is not normally necessary +for client sockets (those sockets that initiate outgoing connections rather than +wait for incoming connections on a known port number). If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling +FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP +stack automatically binding the socket to a port number from the range +socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If +ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto() +on a socket that has not yet been bound will result in the send operation being +aborted. */ +#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 + +/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */ +#define ipconfigUDP_TIME_TO_LIVE 128 +#define ipconfigTCP_TIME_TO_LIVE 128 /* also defined in FreeRTOSIPConfigDefaults.h */ + +/* USE_TCP: Use TCP and all its features */ +#define ipconfigUSE_TCP ( 1 ) + +/* USE_WIN: Let TCP use windowing mechanism. */ +#define ipconfigUSE_TCP_WIN ( 1 ) + +/* The MTU is the maximum number of bytes the payload of a network frame can +contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a +lower value can save RAM, depending on the buffer management scheme used. If +ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must +be divisible by 8. */ +#define ipconfigNETWORK_MTU 1200 + +/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used +through the FreeRTOS_gethostbyname() API function. */ +#define ipconfigUSE_DNS 1 + +/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will +generate replies to incoming ICMP echo (ping) requests. */ +#define ipconfigREPLY_TO_INCOMING_PINGS 1 + +/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the +FreeRTOS_SendPingRequest() API function is available. */ +#define ipconfigSUPPORT_OUTGOING_PINGS 1 + +/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select() +(and associated) API function is available. */ +#define ipconfigSUPPORT_SELECT_FUNCTION 1 + +/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames +that are not in Ethernet II format will be dropped. This option is included for +potential future IP stack developments. */ +#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the +responsibility of the Ethernet interface to filter out packets that are of no +interest. If the Ethernet interface does not implement this functionality, then +set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack +perform the filtering instead (it is much less efficient for the stack to do it +because the packet will already have been passed into the stack). If the +Ethernet driver does all the necessary filtering in hardware then software +filtering can be removed by using a value other than 1 or 0. */ +#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 + +/* The windows simulator cannot really simulate MAC interrupts, and needs to +block occasionally to allow other tasks to run. */ +#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 10 / portTICK_PERIOD_MS ) + +/* Advanced only: in order to access 32-bit fields in the IP packets with +32-bit memory instructions, all packets will be stored 32-bit-aligned, plus 16-bits. +This has to do with the contents of the IP-packets: all 32-bit fields are +32-bit-aligned, plus 16-bit(!) */ +#define ipconfigPACKET_FILLER_SIZE 2 + + +/* Define the size of the pool of TCP window descriptors. On the average, each +TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6 +outstanding packets (for Rx and Tx). When using up to 10 TP sockets +simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */ +#define ipconfigTCP_WIN_SEG_COUNT 240 + +/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed +maximum size. Define the size of Rx buffer for TCP sockets. */ +#define ipconfigTCP_RX_BUFFER_LENGTH ( 1000 ) + +/* Define the size of Tx buffer for TCP sockets. */ +#define ipconfigTCP_TX_BUFFER_LENGTH ( 1000 ) + +/* When using call-back handlers, the driver may check if the handler points to +real program memory (RAM or flash) or just has a random non-zero value. */ +#define ipconfigIS_VALID_PROG_ADDRESS(x) ( (x) != NULL ) + +/* Include support for TCP hang protection. All sockets in a connecting or +disconnecting stage will timeout after a period of non-activity. */ +#define ipconfigTCP_HANG_PROTECTION ( 1 ) +#define ipconfigTCP_HANG_PROTECTION_TIME ( 30 ) + +/* Include support for TCP keep-alive messages. */ +#define ipconfigTCP_KEEP_ALIVE ( 1 ) +#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* in seconds */ + +/* Include both TCP and HTTP. */ +#define ipconfigUSE_FTP 1 +#define ipconfigUSE_HTTP 1 + +/* Dimension the buffers and windows used by the FTP and HTTP servers. */ +#define ipconfigFTP_TX_BUFSIZE ( 8 * 1024 ) +#define ipconfigFTP_TX_WINSIZE ( 4 ) +#define ipconfigFTP_RX_BUFSIZE ( 8 * ipconfigNETWORK_MTU ) +#define ipconfigFTP_RX_WINSIZE ( 4 ) +#define ipconfigHTTP_TX_BUFSIZE ( 8 * ipconfigNETWORK_MTU ) +#define ipconfigHTTP_TX_WINSIZE ( 4 ) +#define ipconfigHTTP_RX_BUFSIZE ( 8 * ipconfigNETWORK_MTU ) +#define ipconfigHTTP_RX_WINSIZE ( 4 ) +#define portINLINE __inline + + +#define ipconfigTFTP_TIME_OUT_MS ( 10000 ) /*_RB_ Parameters need commenting and documenting. */ +#define ipconfigTFTP_MAX_RETRIES ( 6 ) + +/* The example IP trace macros are included here so the definitions are +available in all the FreeRTOS+TCP source files. */ +#include "DemoIPTrace.h" + +#endif /* FREERTOS_IP_CONFIG_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOS_Plus_TCP_and_FAT.sln b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOS_Plus_TCP_and_FAT.sln new file mode 100644 index 000000000..83e9992a9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/FreeRTOS_Plus_TCP_and_FAT.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RTOSDemo", "WIN32.vcxproj", "{C686325E-3261-42F7-AEB1-DDE5280E1CEB}" +EndProject +Global + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = FreeRTOS_Plus_TCP_with_CLI.vsmdi + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.ActiveCfg = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Debug|Win32.Build.0 = Debug|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.ActiveCfg = Release|Win32 + {C686325E-3261-42F7-AEB1-DDE5280E1CEB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/Read_Me_Build_Instructions.url b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/Read_Me_Build_Instructions.url new file mode 100644 index 000000000..3ceab7642 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/Read_Me_Build_Instructions.url @@ -0,0 +1,6 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,2 +[InternetShortcut] +URL=http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html +IDList= +HotKey=0 diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/Run-time-stats-utils.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/Run-time-stats-utils.c new file mode 100644 index 000000000..0b6473c7d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/Run-time-stats-utils.c @@ -0,0 +1,142 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * Utility functions required to gather run time statistics. See: + * http://www.freertos.org/rtos-run-time-stats.html + * + * Note that this is a simulated port, where simulated time is a lot slower than + * real time, therefore the run time counter values have no real meaningful + * units. + * + * Also note that it is assumed this demo is going to be used for short periods + * of time only, and therefore timer overflows are not handled. +*/ + +/* FreeRTOS includes. */ +#include + +/* Variables used in the creation of the run time stats time base. Run time +stats record how much time each task spends in the Running state. */ +static long long llInitialRunTimeCounterValue = 0LL, llTicksPerHundedthMillisecond = 0LL; + +/*-----------------------------------------------------------*/ + +void vConfigureTimerForRunTimeStats( void ) +{ +LARGE_INTEGER liPerformanceCounterFrequency, liInitialRunTimeValue; + + /* Initialise the variables used to create the run time stats time base. + Run time stats record how much time each task spends in the Running + state. */ + + if( QueryPerformanceFrequency( &liPerformanceCounterFrequency ) == 0 ) + { + llTicksPerHundedthMillisecond = 1; + } + else + { + /* How many times does the performance counter increment in 1/100th + millisecond. */ + llTicksPerHundedthMillisecond = liPerformanceCounterFrequency.QuadPart / 100000LL; + + /* What is the performance counter value now, this will be subtracted + from readings taken at run time. */ + QueryPerformanceCounter( &liInitialRunTimeValue ); + llInitialRunTimeCounterValue = liInitialRunTimeValue.QuadPart; + } +} +/*-----------------------------------------------------------*/ + +uint32_t ulGetRunTimeCounterValue( void ) +{ +LARGE_INTEGER liCurrentCount; +uint32_t ulReturn; + + /* What is the performance counter value now? */ + QueryPerformanceCounter( &liCurrentCount ); + + /* Subtract the performance counter value reading taken when the + application started to get a count from that reference point, then + scale to (simulated) 1/100ths of a millisecond. */ + if( llTicksPerHundedthMillisecond == 0 ) + { + /* The trace macros can call this function before the kernel has been + started, in which case llTicksPerHundedthMillisecond will not have been + initialised. */ + ulReturn = 0; + } + else + { + ulReturn = ( uint32_t ) ( ( liCurrentCount.QuadPart - llInitialRunTimeCounterValue ) / llTicksPerHundedthMillisecond ); + } + + return ulReturn; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/TraceMacros/Example1/DemoIPTrace.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/TraceMacros/Example1/DemoIPTrace.c new file mode 100644 index 000000000..925c09438 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/TraceMacros/Example1/DemoIPTrace.c @@ -0,0 +1,222 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * This file, along with DemoIPTrace.h, provides a basic example use of the + * FreeRTOS+TCP trace macros. The statistics gathered here can be viewed in + * the command line interface. + * See http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_CLI.html + * + * A simple generic mechanism is used that allocates a structure (see the + * ExampleDebugStatEntry_t definition in DemoIPTrace.h) to each ID defined in + * the same header file. The structures are stored in an array (see the + * xIPTraceValues[] below. + * + * The structure associates a function with a data value. See the + * vPerformAction and ulData members of ExampleDebugStatEntry_t respectively. + * The function is used to manipulate the data. At the time of writing two + * functions can be used - these are prvIncrementEventCount() which simply + * increments the data each time it is called, and prvStoreLowest() which + * sets the data to the lowest value of an input parameter ever seen. For + * example, to store the lowest ever number of free network buffer descriptors + * the parameter value is the current number of network buffer descriptors. + * + * The trace macros themselves are defined in DemoIPTrace.h and just invoke + * vExampleDebugStatUpdate(), passing in an ID value. vExampleDebugStatUpdate() + * then just executes the function associated with that value (prvStoreLowest(), + * prvIncrementEventCount(), etc.) as defined in the xIPTraceValues[] array. + */ + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_UDP_IP.h" +#include "DemoIPTrace.h" + +/* It is possible to remove the trace macros using the +configINCLUDE_DEMO_DEBUG_STATS setting in FreeRTOSIPConfig.h. */ +#if configINCLUDE_DEMO_DEBUG_STATS == 1 + +/* + * Each row in the xIPTraceValues[] table contains a pointer to a function that + * updates the value for that row. Rows that latch the lowest value point to + * this function (for example, this function can be used to latch the lowest + * number of network buffers that were available during the execution of the + * stack). + */ +static void prvStoreLowest( uint32_t *pulCurrentValue, uint32_t ulCount ); + +/* + * Each row in the xIPTraceValues[] table contains a pointer to a function that + * updates the value for that row. Rows that simply increment an event count + * point to this function. + */ +static void prvIncrementEventCount( uint32_t *pulCurrentValue, uint32_t ulCount ); + +/* The header file defines the IDs within this table. The string is used to +print a friendly message for the stat, and the function pointer is used to +perform the action for the state - for example, note the lowest ever value for +a stat, or just count the number of times the event occurs. */ +ExampleDebugStatEntry_t xIPTraceValues[] = +{ + /* Comment out array entries to remove individual trace items. */ + + { iptraceID_NETWORK_INTERFACE_RECEIVE, "Packets received by the network interface", prvIncrementEventCount, 0 }, + { iptraceID_NETWORK_INTERFACE_TRANSMIT, "Count of transmitted packets", prvIncrementEventCount, 0 }, + { iptraceID_PACKET_DROPPED_TO_GENERATE_ARP, "Count of packets dropped to generate ARP", prvIncrementEventCount, 0 }, + { iptraceID_NETWORK_BUFFER_OBTAINED, "Lowest ever available network buffers", prvStoreLowest, 0xffffUL }, + { iptraceID_NETWORK_EVENT_RECEIVED, "Lowest ever free space in network event queue", prvStoreLowest, 0xffffUL }, + { iptraceID_FAILED_TO_OBTAIN_NETWORK_BUFFER, "Count of failed attempts to obtain a network buffer", prvIncrementEventCount, 0 }, + { iptraceID_ARP_TABLE_ENTRY_EXPIRED, "Count of expired ARP entries", prvIncrementEventCount, 0 }, + { iptraceID_FAILED_TO_CREATE_SOCKET, "Count of failures to create a socket", prvIncrementEventCount, 0 }, + { iptraceID_RECVFROM_DISCARDING_BYTES, "Count of times recvfrom() has discarding bytes", prvIncrementEventCount, 0 }, + { iptraceID_ETHERNET_RX_EVENT_LOST, "Count of lost Etheret Rx events (event queue full?)", prvIncrementEventCount, 0 }, + { iptraceID_STACK_TX_EVENT_LOST, "Count of lost IP stack events (event queue full?)", prvIncrementEventCount, 0 }, + { ipconfigID_BIND_FAILED, "Count of failed calls to bind()", prvIncrementEventCount, 0 }, + { iptraceID_RECVFROM_TIMEOUT, "Count of receive timeouts", prvIncrementEventCount, 0 }, + { iptraceID_SENDTO_DATA_TOO_LONG, "Count of failed sends due to oversized payload", prvIncrementEventCount, 0 }, + { iptraceID_SENDTO_SOCKET_NOT_BOUND, "Count of failed sends due to unbound socket", prvIncrementEventCount, 0 }, + { iptraceID_NO_BUFFER_FOR_SENDTO, "Count of failed transmits due to timeout", prvIncrementEventCount, 0 }, + { iptraceID_WAIT_FOR_TX_DMA_DESCRIPTOR, "Number of times task had to wait to obtain a DMA Tx descriptor", prvIncrementEventCount, 0 }, + { iptraceID_FAILED_TO_NOTIFY_SELECT_GROUP, "Failed to notify select group", prvIncrementEventCount, 0 }, + { iptraceID_TOTAL_NETWORK_BUFFERS_OBTAINED, "Total network buffers obtained", prvIncrementEventCount, 0 }, + { iptraceID_TOTAL_NETWORK_BUFFERS_RELEASED, "Total network buffers released", prvIncrementEventCount, 0 } + +}; + +/*-----------------------------------------------------------*/ + +BaseType_t xExampleDebugStatEntries( void ) +{ + /* Return the number of entries in the xIPTraceValues[] table. */ + return ( BaseType_t ) ( sizeof( xIPTraceValues ) / sizeof( ExampleDebugStatEntry_t ) ); +} +/*-----------------------------------------------------------*/ + +void vExampleDebugStatUpdate( uint8_t ucIdentifier, uint32_t ulValue ) +{ +BaseType_t xIndex; +const BaseType_t xEntries = sizeof( xIPTraceValues ) / sizeof( ExampleDebugStatEntry_t ); + + /* Update an entry in the xIPTraceValues[] table. Each row in the table + includes a pointer to a function that performs the actual update. This + function just executes the update function from that table row. + + Search the array to find the identifier - this could be made more efficient + by using the identifier as an index into the array - but that would come + with the usability cost of needing to change all the identifiers above any + identifiers that are later inserted into the table. */ + for( xIndex = 0; xIndex < xEntries; xIndex++ ) + { + if( xIPTraceValues[ xIndex ].ucIdentifier == ucIdentifier ) + { + xIPTraceValues[ xIndex ].vPerformAction( &( xIPTraceValues[ xIndex ].ulData ), ulValue ); + break; + } + } + + configASSERT( xIndex != xEntries ); +} +/*-----------------------------------------------------------*/ + +static void prvIncrementEventCount( uint32_t *pulCurrentValue, uint32_t ulCount ) +{ + /* Each row in the xIPTraceValues[] table contains a pointer to a function + that updates the value for that row. Rows that simply increment an event + count point to this function. */ + ( void ) ulCount; + ( *pulCurrentValue )++; +} +/*-----------------------------------------------------------*/ + +static void prvStoreLowest( uint32_t *pulCurrentValue, uint32_t ulCount ) +{ + /* Each row in the xIPTraceValues[] table contains a pointer to a function + that updates the value for that row. Rows that latch the lowest value + point to this function (for example, this function can be used to latch + the lowest number of network buffers that were available during the + execution of the stack). */ + if( ulCount < *pulCurrentValue ) + { + *pulCurrentValue = ulCount; + } +} +/*-----------------------------------------------------------*/ + + +#endif /* configINCLUDE_DEMO_DEBUG_STATS == 1 */ + + + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/TraceMacros/Example1/DemoIPTrace.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/TraceMacros/Example1/DemoIPTrace.h new file mode 100644 index 000000000..70c15b49c --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/TraceMacros/Example1/DemoIPTrace.h @@ -0,0 +1,185 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * This file, along with DemoIPTrace.c, provides a basic example use of the + * FreeRTOS+TCP trace macros. The statistics gathered here can be viewed in + * the command line interface. + * See http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_CLI.html + * + * A simple generic mechanism is used that allocates a structure (see the + * ExampleDebugStatEntry_t definition below) to each ID defined in this file. + * The structures are stored in an array (see the xIPTraceValues[] array in + * DemoIPTrace.c). + * + * The structure associates a function with a data value. See the + * vPerformAction and ulData members of ExampleDebugStatEntry_t respectively. + * The function is used to manipulate the data. At the time of writing two + * functions can be used - these are prvIncrementEventCount() which simply + * increments the data each time it is called, and prvStoreLowest() which + * sets the data to the lowest value of an input parameter ever seen. For + * example, to store the lowest ever number of free network buffer descriptors + * the parameter value is the current number of network buffer descriptors. + * + * The trace macros themselves are defined in this file and just invoke + * vExampleDebugStatUpdate(), passing in an ID value. vExampleDebugStatUpdate() + * then just executes the function associated with that value (prvStoreLowest(), + * prvIncrementEventCount(), etc.) as defined in the xIPTraceValues[] array. + */ + +#ifndef DEMO_IP_TRACE_MACROS_H +#define DEMO_IP_TRACE_MACROS_H + +typedef void ( *vTraceAction_t )( uint32_t *, uint32_t ); + +/* Type that defines each statistic being gathered. */ +typedef struct ExampleDebugStatEntry +{ + uint8_t ucIdentifier; /* Unique identifier for statistic. */ + const char * const pucDescription; /* Text description for the statistic. */ + vTraceAction_t vPerformAction; /* Action to perform when the statistic is updated (increment counter, store minimum value, store maximum value, etc. */ + uint32_t ulData; /* The meaning of this data is dependent on the trace macro ID. */ +} ExampleDebugStatEntry_t; + +/* Unique identifiers used to locate the entry for each trace macro in the +xIPTraceValues[] table defined in DemoIPTrace.c. See the comments at the top of +this file. */ +#define iptraceID_NETWORK_INTERFACE_RECEIVE 0 +#define iptraceID_NETWORK_INTERFACE_TRANSMIT 1 +#define iptraceID_PACKET_DROPPED_TO_GENERATE_ARP 2 +#define iptraceID_NETWORK_BUFFER_OBTAINED 3 +#define iptraceID_NETWORK_BUFFER_OBTAINED_FROM_ISR 4 +#define iptraceID_NETWORK_EVENT_RECEIVED 5 +#define iptraceID_FAILED_TO_OBTAIN_NETWORK_BUFFER 6 +#define iptraceID_ARP_TABLE_ENTRY_EXPIRED 7 +#define iptraceID_FAILED_TO_CREATE_SOCKET 8 +#define iptraceID_RECVFROM_DISCARDING_BYTES 9 +#define iptraceID_ETHERNET_RX_EVENT_LOST 10 +#define iptraceID_STACK_TX_EVENT_LOST 11 +#define ipconfigID_BIND_FAILED 12 +#define iptraceID_RECVFROM_TIMEOUT 13 +#define iptraceID_SENDTO_DATA_TOO_LONG 14 +#define iptraceID_SENDTO_SOCKET_NOT_BOUND 15 +#define iptraceID_NO_BUFFER_FOR_SENDTO 16 +#define iptraceID_WAIT_FOR_TX_DMA_DESCRIPTOR 17 +#define iptraceID_FAILED_TO_NOTIFY_SELECT_GROUP 18 +#define iptraceID_TOTAL_NETWORK_BUFFERS_OBTAINED 19 +#define iptraceID_TOTAL_NETWORK_BUFFERS_RELEASED 20 + +/* It is possible to remove the trace macros using the +configINCLUDE_DEMO_DEBUG_STATS setting in FreeRTOSIPConfig.h. */ +#if configINCLUDE_DEMO_DEBUG_STATS == 1 + + /* The trace macro definitions themselves. Any trace macros left undefined + will default to be empty macros. See the comments at the top of this + file. */ + #define iptraceNETWORK_BUFFER_OBTAINED( pxBufferAddress ) vExampleDebugStatUpdate( iptraceID_NETWORK_BUFFER_OBTAINED, uxQueueMessagesWaiting( ( QueueHandle_t ) xNetworkBufferSemaphore ) ); vExampleDebugStatUpdate( iptraceID_TOTAL_NETWORK_BUFFERS_OBTAINED, 0 ) + #define iptraceNETWORK_BUFFER_RELEASED( pxBufferAddress ) vExampleDebugStatUpdate( iptraceID_TOTAL_NETWORK_BUFFERS_RELEASED, 0 ) + #define iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxBufferAddress ) vExampleDebugStatUpdate( iptraceID_NETWORK_BUFFER_OBTAINED, uxQueueMessagesWaiting( ( QueueHandle_t ) xNetworkBufferSemaphore ) ) + + #define iptraceNETWORK_EVENT_RECEIVED( eEvent ) { \ + uint16_t usSpace; \ + usSpace = ( uint16_t ) uxQueueMessagesWaiting( xNetworkEventQueue ); \ + /* Minus one as an event was removed before the space was queried. */ \ + usSpace = ( ipconfigEVENT_QUEUE_LENGTH - usSpace ) - 1; \ + vExampleDebugStatUpdate( iptraceID_NETWORK_EVENT_RECEIVED, usSpace ); \ + } + + #define iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER() vExampleDebugStatUpdate( iptraceID_FAILED_TO_OBTAIN_NETWORK_BUFFER, 0 ) + #define iptraceARP_TABLE_ENTRY_EXPIRED( ulIPAddress ) vExampleDebugStatUpdate( iptraceID_ARP_TABLE_ENTRY_EXPIRED, 0 ) + #define iptracePACKET_DROPPED_TO_GENERATE_ARP( ulIPAddress ) vExampleDebugStatUpdate( iptraceID_PACKET_DROPPED_TO_GENERATE_ARP, 0 ) + #define iptraceFAILED_TO_CREATE_SOCKET() vExampleDebugStatUpdate( iptraceID_FAILED_TO_CREATE_SOCKET, 0 ) + #define iptraceRECVFROM_DISCARDING_BYTES( xNumberOfBytesDiscarded ) vExampleDebugStatUpdate( iptraceID_RECVFROM_DISCARDING_BYTES, 0 ) + #define iptraceETHERNET_RX_EVENT_LOST() vExampleDebugStatUpdate( iptraceID_ETHERNET_RX_EVENT_LOST, 0 ) + #define iptraceSTACK_TX_EVENT_LOST( xEvent ) vExampleDebugStatUpdate( iptraceID_STACK_TX_EVENT_LOST, 0 ) + #define iptraceBIND_FAILED( xSocket, usPort ) vExampleDebugStatUpdate( ipconfigID_BIND_FAILED, 0 ) + #define iptraceNETWORK_INTERFACE_TRANSMIT() vExampleDebugStatUpdate( iptraceID_NETWORK_INTERFACE_TRANSMIT, 0 ) + #define iptraceRECVFROM_TIMEOUT() vExampleDebugStatUpdate( iptraceID_RECVFROM_TIMEOUT, 0 ) + #define iptraceSENDTO_DATA_TOO_LONG() vExampleDebugStatUpdate( iptraceID_SENDTO_DATA_TOO_LONG, 0 ) + #define iptraceSENDTO_SOCKET_NOT_BOUND() vExampleDebugStatUpdate( iptraceID_SENDTO_SOCKET_NOT_BOUND, 0 ) + #define iptraceNO_BUFFER_FOR_SENDTO() vExampleDebugStatUpdate( iptraceID_NO_BUFFER_FOR_SENDTO, 0 ) + #define iptraceWAITING_FOR_TX_DMA_DESCRIPTOR() vExampleDebugStatUpdate( iptraceID_WAIT_FOR_TX_DMA_DESCRIPTOR, 0 ) + #define iptraceFAILED_TO_NOTIFY_SELECT_GROUP( xSocket ) vExampleDebugStatUpdate( iptraceID_FAILED_TO_NOTIFY_SELECT_GROUP, 0 ) + #define iptraceNETWORK_INTERFACE_RECEIVE() vExampleDebugStatUpdate( iptraceID_NETWORK_INTERFACE_RECEIVE, 0 ) + + /* + * The function that updates a line in the xIPTraceValues table. + */ + void vExampleDebugStatUpdate( uint8_t ucIdentifier, uint32_t ulValue ); + + /* + * Returns the number of entries in the xIPTraceValues table. + */ + BaseType_t xExampleDebugStatEntries( void ); + +#endif /* configINCLUDE_DEMO_DEBUG_STATS == 1 */ + + +#endif /* DEMO_IP_TRACE_MACROS_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WIN32.vcxproj b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WIN32.vcxproj new file mode 100644 index 000000000..d4dbeb9da --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WIN32.vcxproj @@ -0,0 +1,248 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {C686325E-3261-42F7-AEB1-DDE5280E1CEB} + RTOSDemo + + + + Application + false + MultiByte + v142 + + + Application + false + MultiByte + v142 + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + .\Debug\ + .\Debug\ + true + .\Release\ + .\Release\ + false + AllRules.ruleset + + + + .\Debug/WIN32.tlb + + + + + Disabled + ..\Common\FreeRTOS_Plus_CLI_Demos\include;..\Common\FreeRTOS_Plus_TCP_Demos\include;..\Common\Demo_IP_Protocols\include;..\..\Source\FreeRTOS-Plus-FAT\include;..\..\Source\FreeRTOS-Plus-FAT\portable\common;..\..\Source\FreeRTOS-Plus-TCP\protocols\include;..\..\Source\FreeRTOS-Plus-TCP\portable\BufferManagement;.\DemoTasks\include;..\..\Source\FreeRTOS-Plus-TCP\portable\Compiler\MSVC;.\WinPCap;..\..\..\FreeRTOS\Source\include;..\..\..\FreeRTOS\Source\portable\MSVC-MingW;..\..\Source\FreeRTOS-Plus-CLI;.\TraceMacros\Example1;..\..\Source\FreeRTOS-Plus-TCP\include;.;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0500;WINVER=0x400;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDLL + .\Debug/WIN32.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level4 + true + false + EditAndContinue + /wd4210 /wd4127 /wd4214 /wd4201 /wd4244 /wd4310 %(AdditionalOptions) + true + NotUsing + false + CompileAsC + + + _DEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Debug/RTOSDemo.exe + true + true + .\Debug/WIN32.pdb + Console + MachineX86 + wpcap.lib;%(AdditionalDependencies) + .\WinPCap + false + + + true + .\Debug/WIN32.bsc + + + + + .\Release/WIN32.tlb + + + + + MaxSpeed + OnlyExplicitInline + _WINSOCKAPI_;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + MultiThreaded + true + .\Release/WIN32.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + ..\Common\Utils;..\Common\ethernet\lwip-1.4.0\ports\win32\WinPCap;..\Common\ethernet\lwip-1.4.0\src\include\ipv4;..\Common\ethernet\lwip-1.4.0\src\include;..\..\Source\include;..\..\Source\portable\MSVC-MingW;..\Common\ethernet\lwip-1.4.0\ports\win32\include;..\Common\Include;.\lwIP_Apps;.;%(AdditionalIncludeDirectories) + + + NDEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + .\Release/RTOSDemo.exe + true + .\Release/WIN32.pdb + Console + MachineX86 + ..\Common\ethernet\lwip-1.4.0\ports\win32\WinPCap + wpcap.lib;%(AdditionalDependencies) + + + true + .\Release/WIN32.bsc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %(AdditionalIncludeDirectories) + %(PreprocessorDefinitions) + %(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WIN32.vcxproj.filters b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WIN32.vcxproj.filters new file mode 100644 index 000000000..43fc77402 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WIN32.vcxproj.filters @@ -0,0 +1,345 @@ + + + + + {38712199-cebf-4124-bf15-398f7c3419ea} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + {af3445a1-4908-4170-89ed-39345d90d30c} + + + {f32be356-4763-4cae-9020-974a2638cb08} + *.c + + + {88f409e6-d396-4ac5-94bd-7a99c914be46} + + + {e5ad4ec7-23dc-4295-8add-2acaee488f5a} + + + {fd43c0ed-fdbc-437f-a5a3-c50399690bd7} + + + {c5889fe2-af0f-4cea-927f-6a6935ec5e14} + + + {d2dcd641-8d91-492b-852f-5563ffadaec6} + + + {8672fa26-b119-481f-8b8d-086419c01a3e} + + + {4570be11-ec96-4b55-ac58-24b50ada980a} + + + {5d93ed51-023a-41ad-9243-8d230165d34b} + + + {b71e974a-9f28-4815-972b-d930ba8a34d0} + + + {7ffdff79-2c12-4bd4-af38-521cc93b7d95} + + + {712b79e7-ea36-46c5-92b9-1b36987c7dd7} + + + {7ab2c463-5171-40fc-8d1f-4bd0abdd61d3} + + + {3f4295c8-0a11-411e-bfdb-b4c393325686} + + + {f7d79c65-cc92-4557-8767-47291edd1ff3} + + + {d232bbe4-6782-4451-8758-726ca14ddaeb} + + + {edeb20f4-c0e9-464e-807b-310470f612e2} + + + + + FreeRTOS\Source\Portable + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + FreeRTOS\Source + + + DemoTasks + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+TCP\portable + + + FreeRTOS+\FreeRTOS+CLI + + + DemoTasks + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + FreeRTOS+\FreeRTOS+TCP + + + DemoTasks + + + FreeRTOS\Source + + + + + DemoTasks + + + DemoTasks + + + + DemoTasks + + + DemoTasks + + + FreeRTOS+\FreeRTOS+TCP + + + + FreeRTOS+\FreeRTOS+FAT + + + FreeRTOS+\FreeRTOS+FAT + + + FreeRTOS+\FreeRTOS+FAT + + + FreeRTOS+\FreeRTOS+FAT + + + FreeRTOS+\FreeRTOS+FAT + + + FreeRTOS+\FreeRTOS+FAT + + + FreeRTOS+\FreeRTOS+FAT + + + FreeRTOS+\FreeRTOS+FAT + + + FreeRTOS+\FreeRTOS+FAT + + + FreeRTOS+\FreeRTOS+FAT + + + FreeRTOS+\FreeRTOS+FAT + + + FreeRTOS+\FreeRTOS+FAT + + + FreeRTOS+\FreeRTOS+FAT\portable + + + FreeRTOS+\FreeRTOS+FAT + + + + + DemoTasks + + + FreeRTOS\Source\Portable + + + + DemoTasks + + + DemoTasks + + + FreeRTOS+\FreeRTOS+TCP\protocols\Common + + + FreeRTOS+\FreeRTOS+TCP\protocols\FTP + + + FreeRTOS+\FreeRTOS+TCP\protocols\FTP + + + FreeRTOS+\FreeRTOS+TCP\protocols\HTTP + + + FreeRTOS+\FreeRTOS+TCP\protocols\HTTP + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+CLI\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS+\FreeRTOS+TCP\include + + + + + FreeRTOS+\FreeRTOS+TCP\include + + + FreeRTOS\Source\include + + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + FreeRTOS\Source\include + + + FreeRTOS+\FreeRTOS+FAT\include + + + \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/Packet32.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/Packet32.h new file mode 100644 index 000000000..1e0eacd77 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/Packet32.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2007 CACE Technologies, Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + +/** @ingroup packetapi + * @{ + */ + +/** @defgroup packet32h Packet.dll definitions and data structures + * Packet32.h contains the data structures and the definitions used by packet.dll. + * The file is used both by the Win9x and the WinNTx versions of packet.dll, and can be included + * by the applications that use the functions of this library + * @{ + */ + +#ifndef __PACKET32 +#define __PACKET32 + +#include + +#ifdef HAVE_AIRPCAP_API +#include +#else +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +typedef struct _AirpcapHandle *PAirpcapHandle; +#endif /* AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ */ +#endif /* HAVE_AIRPCAP_API */ + +#ifdef HAVE_DAG_API +#include +#endif /* HAVE_DAG_API */ + +// Working modes +#define PACKET_MODE_CAPT 0x0 ///< Capture mode +#define PACKET_MODE_STAT 0x1 ///< Statistical mode +#define PACKET_MODE_MON 0x2 ///< Monitoring mode +#define PACKET_MODE_DUMP 0x10 ///< Dump mode +#define PACKET_MODE_STAT_DUMP MODE_DUMP | MODE_STAT ///< Statistical dump Mode + + +/// Alignment macro. Defines the alignment size. +#define Packet_ALIGNMENT sizeof(int) +/// Alignment macro. Rounds up to the next even multiple of Packet_ALIGNMENT. +#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1)) + +#define NdisMediumNull -1 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumCHDLC -2 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPPPSerial -3 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumBare80211 -4 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumRadio80211 -5 ///< Custom linktype: NDIS doesn't provide an equivalent +#define NdisMediumPpi -6 ///< Custom linktype: NDIS doesn't provide an equivalent + +// Loopback behaviour definitions +#define NPF_DISABLE_LOOPBACK 1 ///< Drop the packets sent by the NPF driver +#define NPF_ENABLE_LOOPBACK 2 ///< Capture the packets sent by the NPF driver + +/*! + \brief Network type structure. + + This structure is used by the PacketGetNetType() function to return information on the current adapter's type and speed. +*/ +typedef struct NetType +{ + UINT LinkType; ///< The MAC of the current network adapter (see function PacketGetNetType() for more information) + ULONGLONG LinkSpeed; ///< The speed of the network in bits per second +}NetType; + + +//some definitions stolen from libpcap + +#ifndef BPF_MAJOR_VERSION + +/*! + \brief A BPF pseudo-assembly program. + + The program will be injected in the kernel by the PacketSetBPF() function and applied to every incoming packet. +*/ +struct bpf_program +{ + UINT bf_len; ///< Indicates the number of instructions of the program, i.e. the number of struct bpf_insn that will follow. + struct bpf_insn *bf_insns; ///< A pointer to the first instruction of the program. +}; + +/*! + \brief A single BPF pseudo-instruction. + + bpf_insn contains a single instruction for the BPF register-machine. It is used to send a filter program to the driver. +*/ +struct bpf_insn +{ + USHORT code; ///< Instruction type and addressing mode. + UCHAR jt; ///< Jump if true + UCHAR jf; ///< Jump if false + int k; ///< Generic field used for various purposes. +}; + +/*! + \brief Structure that contains a couple of statistics values on the current capture. + + It is used by packet.dll to return statistics about a capture session. +*/ +struct bpf_stat +{ + UINT bs_recv; ///< Number of packets that the driver received from the network adapter + ///< from the beginning of the current capture. This value includes the packets + ///< lost by the driver. + UINT bs_drop; ///< number of packets that the driver lost from the beginning of a capture. + ///< Basically, a packet is lost when the the buffer of the driver is full. + ///< In this situation the packet cannot be stored and the driver rejects it. + UINT ps_ifdrop; ///< drops by interface. XXX not yet supported + UINT bs_capt; ///< number of packets that pass the filter, find place in the kernel buffer and + ///< thus reach the application. +}; + +/*! + \brief Packet header. + + This structure defines the header associated with every packet delivered to the application. +*/ +struct bpf_hdr +{ + struct timeval bh_tstamp; ///< The timestamp associated with the captured packet. + ///< It is stored in a TimeVal structure. + UINT bh_caplen; ///< Length of captured portion. The captured portion can be different + ///< from the original packet, because it is possible (with a proper filter) + ///< to instruct the driver to capture only a portion of the packets. + UINT bh_datalen; ///< Original length of packet + USHORT bh_hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases, + ///< a padding could be added between the end of this structure and the packet + ///< data for performance reasons. This filed can be used to retrieve the actual data + ///< of the packet. +}; + +/*! + \brief Dump packet header. + + This structure defines the header associated with the packets in a buffer to be used with PacketSendPackets(). + It is simpler than the bpf_hdr, because it corresponds to the header associated by WinPcap and libpcap to a + packet in a dump file. This makes straightforward sending WinPcap dump files to the network. +*/ +struct dump_bpf_hdr{ + struct timeval ts; ///< Time stamp of the packet + UINT caplen; ///< Length of captured portion. The captured portion can smaller than the + ///< the original packet, because it is possible (with a proper filter) to + ///< instruct the driver to capture only a portion of the packets. + UINT len; ///< Length of the original packet (off wire). +}; + + +#endif + +struct bpf_stat; + +#define DOSNAMEPREFIX TEXT("Packet_") ///< Prefix added to the adapters device names to create the WinPcap devices +#define MAX_LINK_NAME_LENGTH 64 //< Maximum length of the devices symbolic links +#define NMAX_PACKET 65535 + +/*! + \brief Addresses of a network adapter. + + This structure is used by the PacketGetNetInfoEx() function to return the IP addresses associated with + an adapter. +*/ +typedef struct npf_if_addr { + struct sockaddr_storage IPAddress; ///< IP address. + struct sockaddr_storage SubnetMask; ///< Netmask for that address. + struct sockaddr_storage Broadcast; ///< Broadcast address. +}npf_if_addr; + + +#define ADAPTER_NAME_LENGTH 256 + 12 ///< Maximum length for the name of an adapter. The value is the same used by the IP Helper API. +#define ADAPTER_DESC_LENGTH 128 ///< Maximum length for the description of an adapter. The value is the same used by the IP Helper API. +#define MAX_MAC_ADDR_LENGTH 8 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. +#define MAX_NETWORK_ADDRESSES 16 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API. + + +typedef struct WAN_ADAPTER_INT WAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API +typedef WAN_ADAPTER *PWAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API + +#define INFO_FLAG_NDIS_ADAPTER 0 ///< Flag for ADAPTER_INFO: this is a traditional ndis adapter +#define INFO_FLAG_NDISWAN_ADAPTER 1 ///< Flag for ADAPTER_INFO: this is a NdisWan adapter, and it's managed by WANPACKET +#define INFO_FLAG_DAG_CARD 2 ///< Flag for ADAPTER_INFO: this is a DAG card +#define INFO_FLAG_DAG_FILE 6 ///< Flag for ADAPTER_INFO: this is a DAG file +#define INFO_FLAG_DONT_EXPORT 8 ///< Flag for ADAPTER_INFO: when this flag is set, the adapter will not be listed or openend by winpcap. This allows to prevent exporting broken network adapters, like for example FireWire ones. +#define INFO_FLAG_AIRPCAP_CARD 16 ///< Flag for ADAPTER_INFO: this is an airpcap card +#define INFO_FLAG_NPFIM_DEVICE 32 + +/*! + \brief Describes an opened network adapter. + + This structure is the most important for the functioning of packet.dll, but the great part of its fields + should be ignored by the user, since the library offers functions that avoid to cope with low-level parameters +*/ +typedef struct _ADAPTER { + HANDLE hFile; ///< \internal Handle to an open instance of the NPF driver. + CHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; ///< \internal A string containing the name of the network adapter currently opened. + int NumWrites; ///< \internal Number of times a packets written on this adapter will be repeated + ///< on the wire. + HANDLE ReadEvent; ///< A notification event associated with the read calls on the adapter. + ///< It can be passed to standard Win32 functions (like WaitForSingleObject + ///< or WaitForMultipleObjects) to wait until the driver's buffer contains some + ///< data. It is particularly useful in GUI applications that need to wait + ///< concurrently on several events. In Windows NT/2000 the PacketSetMinToCopy() + ///< function can be used to define the minimum amount of data in the kernel buffer + ///< that will cause the event to be signalled. + + UINT ReadTimeOut; ///< \internal The amount of time after which a read on the driver will be released and + ///< ReadEvent will be signaled, also if no packets were captured + CHAR Name[ADAPTER_NAME_LENGTH]; + PWAN_ADAPTER pWanAdapter; + UINT Flags; ///< Adapter's flags. Tell if this adapter must be treated in a different way, using the Netmon API or the dagc API. + +#ifdef HAVE_AIRPCAP_API + PAirpcapHandle AirpcapAd; +#endif // HAVE_AIRPCAP_API + +#ifdef HAVE_NPFIM_API + void* NpfImHandle; +#endif // HAVE_NPFIM_API + +#ifdef HAVE_DAG_API + dagc_t *pDagCard; ///< Pointer to the dagc API adapter descriptor for this adapter + PCHAR DagBuffer; ///< Pointer to the buffer with the packets that is received from the DAG card + struct timeval DagReadTimeout; ///< Read timeout. The dagc API requires a timeval structure + unsigned DagFcsLen; ///< Length of the frame check sequence attached to any packet by the card. Obtained from the registry + DWORD DagFastProcess; ///< True if the user requests fast capture processing on this card. Higher level applications can use this value to provide a faster but possibly unprecise capture (for example, libpcap doesn't convert the timestamps). +#endif // HAVE_DAG_API +} ADAPTER, *LPADAPTER; + +/*! + \brief Structure that contains a group of packets coming from the driver. + + This structure defines the header associated with every packet delivered to the application. +*/ +typedef struct _PACKET { + HANDLE hEvent; ///< \deprecated Still present for compatibility with old applications. + OVERLAPPED OverLapped; ///< \deprecated Still present for compatibility with old applications. + PVOID Buffer; ///< Buffer with containing the packets. See the PacketReceivePacket() for + ///< details about the organization of the data in this buffer + UINT Length; ///< Length of the buffer + DWORD ulBytesReceived; ///< Number of valid bytes present in the buffer, i.e. amount of data + ///< received by the last call to PacketReceivePacket() + BOOLEAN bIoComplete; ///< \deprecated Still present for compatibility with old applications. +} PACKET, *LPPACKET; + +/*! + \brief Structure containing an OID request. + + It is used by the PacketRequest() function to send an OID to the interface card driver. + It can be used, for example, to retrieve the status of the error counters on the adapter, its MAC address, + the list of the multicast groups defined on it, and so on. +*/ +struct _PACKET_OID_DATA { + ULONG Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h + ///< for a complete list of valid codes. + ULONG Length; ///< Length of the data field + UCHAR Data[1]; ///< variable-lenght field that contains the information passed to or received + ///< from the adapter. +}; +typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @} + */ + +/* +BOOLEAN QueryWinPcapRegistryStringA(CHAR *SubKeyName, + CHAR *Value, + UINT *pValueLen, + CHAR *DefaultVal); + +BOOLEAN QueryWinPcapRegistryStringW(WCHAR *SubKeyName, + WCHAR *Value, + UINT *pValueLen, + WCHAR *DefaultVal); +*/ + +//--------------------------------------------------------------------------- +// EXPORTED FUNCTIONS +//--------------------------------------------------------------------------- + +PCHAR PacketGetVersion(); +PCHAR PacketGetDriverVersion(); +BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes); +BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites); +BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode); +BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout); +BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp); +BOOLEAN PacketSetLoopbackBehavior(LPADAPTER AdapterObject, UINT LoopbackBehavior); +INT PacketSetSnapLen(LPADAPTER AdapterObject,int snaplen); +BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s); +BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim); +BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type); +LPADAPTER PacketOpenAdapter(PCHAR AdapterName); +BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync); +INT PacketSendPackets(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync); +LPPACKET PacketAllocatePacket(void); +VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length); +VOID PacketFreePacket(LPPACKET lpPacket); +BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync); +BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter); +BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize); +BOOLEAN PacketGetNetInfoEx(PCHAR AdapterName, npf_if_addr* buffer, PLONG NEntries); +BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData); +HANDLE PacketGetReadEvent(LPADAPTER AdapterObject); +BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len); +BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks); +BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync); +BOOL PacketStopDriver(); +VOID PacketCloseAdapter(LPADAPTER lpAdapter); +BOOLEAN PacketStartOem(PCHAR errorString, UINT errorStringLength); +BOOLEAN PacketStartOemEx(PCHAR errorString, UINT errorStringLength, ULONG flags); +PAirpcapHandle PacketGetAirPcapHandle(LPADAPTER AdapterObject); + +// +// Used by PacketStartOemEx +// +#define PACKET_START_OEM_NO_NETMON 0x00000001 + +#ifdef __cplusplus +} +#endif + +#endif //__PACKET32 diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/PacketData.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/PacketData.h new file mode 100644 index 000000000..8124db66d --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/PacketData.h @@ -0,0 +1,267 @@ +char pkt1[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x30, 0x09, 0x9c, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x07, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x35, 0x00, 0x00, 0x00, 0x00, 0x70, 0x02, +0x40, 0x00, 0xdf, 0xab, 0x00, 0x00, 0x02, 0x04, +0x05, 0xb4, 0x01, 0x01, 0x04, 0x02 }; + +char pkt2[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa6, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt3[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0x9e, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x0d, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt4[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x02, 0x27, 0x09, 0x9f, 0x40, 0x00, 0x80, 0x06, +0x6d, 0x0d, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x18, +0x42, 0xd8, 0x84, 0x3e, 0x00, 0x00, 0x47, 0x45, +0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, +0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, +0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x2c, +0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, +0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, +0x2c, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, +0x6a, 0x70, 0x65, 0x67, 0x2c, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x70, 0x6a, 0x70, 0x65, +0x67, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, +0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, +0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, +0x63, 0x65, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c, +0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, +0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, +0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20, +0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, +0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, +0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70, +0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, +0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78, +0x62, 0x61, 0x70, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, +0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d, +0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, +0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, +0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, +0x20, 0x65, 0x6e, 0x2d, 0x67, 0x62, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, +0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, +0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64, +0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x0d, 0x0a, +0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, +0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69, +0x6c, 0x6c, 0x61, 0x2f, 0x34, 0x2e, 0x30, 0x20, +0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, +0x62, 0x6c, 0x65, 0x3b, 0x20, 0x4d, 0x53, 0x49, +0x45, 0x20, 0x36, 0x2e, 0x30, 0x3b, 0x20, 0x57, +0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e, +0x54, 0x20, 0x35, 0x2e, 0x31, 0x3b, 0x20, 0x53, +0x56, 0x31, 0x3b, 0x20, 0x47, 0x6f, 0x6f, 0x67, +0x6c, 0x65, 0x54, 0x35, 0x3b, 0x20, 0x2e, 0x4e, +0x45, 0x54, 0x20, 0x43, 0x4c, 0x52, 0x20, 0x32, +0x2e, 0x30, 0x2e, 0x35, 0x30, 0x37, 0x32, 0x37, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30, +0x34, 0x35, 0x30, 0x36, 0x2e, 0x36, 0x34, 0x38, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x35, 0x2e, 0x32, +0x31, 0x30, 0x32, 0x32, 0x29, 0x0d, 0x0a, 0x48, +0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, +0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31, +0x32, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, +0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b, +0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, +0x65, 0x0d, 0x0a, 0x0d, 0x0a }; + +char pkt5[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x02, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa5, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt6[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa1, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x0a, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt7[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x02, 0x27, 0x09, 0xa2, 0x40, 0x00, 0x80, 0x06, +0x6d, 0x0a, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc7, 0x36, 0x00, 0x00, 0x06, 0x69, 0x50, 0x18, +0x42, 0xd8, 0x84, 0x3e, 0x00, 0x00, 0x47, 0x45, +0x54, 0x20, 0x2f, 0x20, 0x48, 0x54, 0x54, 0x50, +0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x41, 0x63, +0x63, 0x65, 0x70, 0x74, 0x3a, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x67, 0x69, 0x66, 0x2c, +0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x78, +0x2d, 0x78, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70, +0x2c, 0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, +0x6a, 0x70, 0x65, 0x67, 0x2c, 0x20, 0x69, 0x6d, +0x61, 0x67, 0x65, 0x2f, 0x70, 0x6a, 0x70, 0x65, +0x67, 0x2c, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, +0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, +0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, 0x65, 0x78, +0x63, 0x65, 0x6c, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x6d, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2c, +0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x6e, 0x64, +0x2e, 0x6d, 0x73, 0x2d, 0x70, 0x6f, 0x77, 0x65, +0x72, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2c, 0x20, +0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, +0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, +0x2d, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, +0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x70, +0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, +0x6e, 0x2f, 0x78, 0x2d, 0x6d, 0x73, 0x2d, 0x78, +0x62, 0x61, 0x70, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x76, 0x6e, 0x64, 0x2e, 0x6d, 0x73, 0x2d, +0x78, 0x70, 0x73, 0x64, 0x6f, 0x63, 0x75, 0x6d, +0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x70, 0x70, +0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, +0x2f, 0x78, 0x61, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, +0x6c, 0x2c, 0x20, 0x2a, 0x2f, 0x2a, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x4c, +0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3a, +0x20, 0x65, 0x6e, 0x2d, 0x67, 0x62, 0x0d, 0x0a, +0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x45, +0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3a, +0x20, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x20, 0x64, +0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x0d, 0x0a, +0x55, 0x73, 0x65, 0x72, 0x2d, 0x41, 0x67, 0x65, +0x6e, 0x74, 0x3a, 0x20, 0x4d, 0x6f, 0x7a, 0x69, +0x6c, 0x6c, 0x61, 0x2f, 0x34, 0x2e, 0x30, 0x20, +0x28, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, +0x62, 0x6c, 0x65, 0x3b, 0x20, 0x4d, 0x53, 0x49, +0x45, 0x20, 0x36, 0x2e, 0x30, 0x3b, 0x20, 0x57, +0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e, +0x54, 0x20, 0x35, 0x2e, 0x31, 0x3b, 0x20, 0x53, +0x56, 0x31, 0x3b, 0x20, 0x47, 0x6f, 0x6f, 0x67, +0x6c, 0x65, 0x54, 0x35, 0x3b, 0x20, 0x2e, 0x4e, +0x45, 0x54, 0x20, 0x43, 0x4c, 0x52, 0x20, 0x32, +0x2e, 0x30, 0x2e, 0x35, 0x30, 0x37, 0x32, 0x37, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x30, 0x2e, 0x30, +0x34, 0x35, 0x30, 0x36, 0x2e, 0x36, 0x34, 0x38, +0x3b, 0x20, 0x2e, 0x4e, 0x45, 0x54, 0x20, 0x43, +0x4c, 0x52, 0x20, 0x33, 0x2e, 0x35, 0x2e, 0x32, +0x31, 0x30, 0x32, 0x32, 0x29, 0x0d, 0x0a, 0x48, +0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x39, 0x32, +0x2e, 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x31, +0x32, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, +0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x4b, +0x65, 0x65, 0x70, 0x2d, 0x41, 0x6c, 0x69, 0x76, +0x65, 0x0d, 0x0a, 0x0d, 0x0a }; + +char pkt8[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x03, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa4, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt9[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa3, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x08, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt10[] = { +0x00, 0x14, 0x22, 0xcb, 0x18, 0x2d, 0x00, 0x01, +0x02, 0x45, 0x09, 0x11, 0x08, 0x00, 0x45, 0x00, +0x00, 0x2c, 0x00, 0x04, 0x00, 0x00, 0x40, 0x06, +0xf8, 0xa3, 0xc0, 0xa8, 0x00, 0x0c, 0xc0, 0xa8, +0x00, 0xc8, 0x00, 0x50, 0x0f, 0xe2, 0x00, 0x00, +0x06, 0x68, 0x09, 0xe7, 0xc7, 0x36, 0x60, 0x12, +0x05, 0x92, 0x28, 0xca, 0x00, 0x00, 0x02, 0x04, +0x05, 0x92 }; + +char pkt11[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa6, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x05, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x10, +0x42, 0xd8, 0x82, 0x3f, 0x00, 0x00 }; + +char pkt12[] = { +0x00, 0x01, 0x02, 0x45, 0x09, 0x11, 0x00, 0x14, +0x22, 0xcb, 0x18, 0x2d, 0x08, 0x00, 0x45, 0x00, +0x00, 0x28, 0x09, 0xa7, 0x40, 0x00, 0x80, 0x06, +0x6f, 0x04, 0xc0, 0xa8, 0x00, 0xc8, 0xc0, 0xa8, +0x00, 0x0c, 0x0f, 0xe2, 0x00, 0x50, 0x09, 0xe7, +0xc9, 0x35, 0x00, 0x00, 0x06, 0x69, 0x50, 0x14, +0x00, 0x00, 0x43, 0xf4, 0x00, 0x00 }; + + +typedef struct +{ + char *pcData; + int iDataLen; +} xPacketData; + +xPacketData xAllPackets[] = +{ + { pkt1, sizeof( pkt1 ) }, +// { pkt2, sizeof( pkt2 ) }, + { pkt3, sizeof( pkt3 ) }, + { pkt4, sizeof( pkt4 ) }, +// { pkt5, sizeof( pkt5 ) }, + { pkt6, sizeof( pkt6 ) }, + { pkt7, sizeof( pkt7 ) }, + { pkt8, sizeof( pkt8 ) }, + { pkt9, sizeof( pkt9 ) }, + { pkt10, sizeof( pkt10 ) }, +// { pkt11, sizeof( pkt11 ) }, +// { pkt12, sizeof( pkt12 ) }, +// { pkt13, sizeof( pkt13 ) }, +// { pkt14, sizeof( pkt14 ) }, +// { pkt15, sizeof( pkt15 ) }, +// { pkt16, sizeof( pkt16 ) }, +}; diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/Win32-Extensions.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/Win32-Extensions.h new file mode 100644 index 000000000..be71c85e9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/Win32-Extensions.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino, CACE Technologies + * nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + + +#ifndef __WIN32_EXTENSIONS_H__ +#define __WIN32_EXTENSIONS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Definitions */ + +/*! + \brief A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit(). +*/ +struct pcap_send_queue +{ + u_int maxlen; ///< Maximum size of the the queue, in bytes. This variable contains the size of the buffer field. + u_int len; ///< Current size of the queue, in bytes. + char *buffer; ///< Buffer containing the packets to be sent. +}; + +typedef struct pcap_send_queue pcap_send_queue; + +/*! + \brief This typedef is a support for the pcap_get_airpcap_handle() function +*/ +#if !defined(AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_) +#define AIRPCAP_HANDLE__EAE405F5_0171_9592_B3C2_C19EC426AD34__DEFINED_ +typedef struct _AirpcapHandle *PAirpcapHandle; +#endif + +#define BPF_MEM_EX_IMM 0xc0 +#define BPF_MEM_EX_IND 0xe0 + +/*used for ST*/ +#define BPF_MEM_EX 0xc0 +#define BPF_TME 0x08 + +#define BPF_LOOKUP 0x90 +#define BPF_EXECUTE 0xa0 +#define BPF_INIT 0xb0 +#define BPF_VALIDATE 0xc0 +#define BPF_SET_ACTIVE 0xd0 +#define BPF_RESET 0xe0 +#define BPF_SET_MEMORY 0x80 +#define BPF_GET_REGISTER_VALUE 0x70 +#define BPF_SET_REGISTER_VALUE 0x60 +#define BPF_SET_WORKING 0x50 +#define BPF_SET_ACTIVE_READ 0x40 +#define BPF_SET_AUTODELETION 0x30 +#define BPF_SEPARATION 0xff + +/* Prototypes */ +pcap_send_queue* pcap_sendqueue_alloc(u_int memsize); + +void pcap_sendqueue_destroy(pcap_send_queue* queue); + +int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data); + +u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync); + +HANDLE pcap_getevent(pcap_t *p); + +struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size); + +int pcap_setuserbuffer(pcap_t *p, int size); + +int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks); + +int pcap_live_dump_ended(pcap_t *p, int sync); + +int pcap_offline_filter(struct bpf_program *prog, const struct pcap_pkthdr *header, const u_char *pkt_data); + +int pcap_start_oem(char* err_str, int flags); + +PAirpcapHandle pcap_get_airpcap_handle(pcap_t *p); + +#ifdef __cplusplus +} +#endif + +#endif //__WIN32_EXTENSIONS_H__ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/arch.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/arch.c new file mode 100644 index 000000000..c90f03006 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/arch.c @@ -0,0 +1,378 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* WinPCap includes. */ +#include "pcap.h" +#include "remote-ext.h" + +/* uIP includes. */ +#include "net/uip.h" +#include "net/uip_arp.h" +#include "net/clock-arch.h" + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* + * Query the computer the simulation is being executed on to find the network + * interfaces it has installed. + */ +static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ); + +/* + * Open the network interface. The number of the interface to be opened is set + * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. + */ +static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ); + +/* + * Configure the capture filter to allow blocking reads, and to filter out + * packets that are not of interest to this demo. + */ +static void prvConfigureCaptureBehaviour( void ); + +pcap_t *pxOpenedInterfaceHandle = NULL; +LARGE_INTEGER freq, sys_start_time; + +#define archNUM_BUFFERS 5 +#define archNUM_BUFFER_POINTERS ( archNUM_BUFFERS - 1 ) + +static void prvInterruptSimulator( void *pvParameters ); + +static unsigned char ucEthernetBuffer[ archNUM_BUFFERS ][ UIP_CONF_BUFFER_SIZE ]; +static unsigned char *pucEthernetBufferPointers[ archNUM_BUFFER_POINTERS ]; + +static long lLengthOfDataInBuffer[ archNUM_BUFFER_POINTERS ] = { 0 }; +static unsigned char ucNextBufferToFill = 0U, ucNextBufferToProcess = 0U; + +unsigned char *uip_buf = NULL; +char cErrorBuffer[PCAP_ERRBUF_SIZE]; + +void vNetifTx( void ) +{ + pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len ); + pcap_sendpacket( pxOpenedInterfaceHandle, uip_buf, uip_len ); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxNetifRx( void ) +{ +UBaseType_t xDataLen; +unsigned char *pucTemp; + + /* Check there is really data available. */ + xDataLen = lLengthOfDataInBuffer[ ucNextBufferToProcess ]; + if( xDataLen != 0L ) + { + + /* The buffer pointed to by uip_buf is going to change. Remember which + buffer uip_buf is currently pointing to. */ + pucTemp = uip_buf; + + /* Point uip_buf at the next buffer that contains data. */ + uip_buf = pucEthernetBufferPointers[ ucNextBufferToProcess ]; + + /* The buffer pointed to by + pucEthernetBufferPointeres[ ucNextBufferToProcess ] is now in use by + uip_buf, but the buffer uip_buf was pointing to on entry to this + function is free. Set + pucEthernetBufferPointeres[ ucNextBufferToProcess ] to the free + buffer. */ + pucEthernetBufferPointers[ ucNextBufferToProcess ] = pucTemp; + lLengthOfDataInBuffer[ ucNextBufferToProcess ] = 0L; + + ucNextBufferToProcess++; + if( ucNextBufferToProcess >= archNUM_BUFFER_POINTERS ) + { + ucNextBufferToProcess = 0L; + } + } + + return xDataLen; +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetifInit( void ) +{ +BaseType_t x; +pcap_if_t *pxAllNetworkInterfaces; + + /* Allocate a free buffer to each buffer pointer. */ + for( x = 0; x < sizeof( pucEthernetBufferPointers ) / sizeof( unsigned char * ); x++ ) + { + pucEthernetBufferPointers[ x ] = &( ucEthernetBuffer[ x ][ 0 ] ); + } + + /* Start with uip_buf pointing to a buffer that is not referenced from the + pucEthernetBufferPointers[] array. */ + uip_buf = &( ucEthernetBuffer[ archNUM_BUFFERS - 1 ][ 0 ] ); + + /* Query the computer the simulation is being executed on to find the + network interfaces it has installed. */ + pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces(); + + /* Open the network interface. The number of the interface to be opened is + set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. + Calling this function will set the pxOpenedInterfaceHandle variable. If, + after calling this function, pxOpenedInterfaceHandle is equal to NULL, then + the interface could not be opened. */ + if( pxAllNetworkInterfaces != NULL ) + { + prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces ); + } + + + return x; +} +/*-----------------------------------------------------------*/ + +static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ) +{ +pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface; +long lInterfaceNumber = 1; + + if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 ) + { + printf( "\r\nCould not obtain a list of network interfaces\r\n%s\r\n", cErrorBuffer ); + pxAllNetworkInterfaces = NULL; + } + + if( pxAllNetworkInterfaces != NULL ) + { + /* Print out the list of network interfaces. The first in the list + is interface '1', not interface '0'. */ + for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next ) + { + printf( "%d. %s", lInterfaceNumber, xInterface->name ); + + if( xInterface->description != NULL ) + { + printf( " (%s)\r\n", xInterface->description ); + } + else + { + printf( " (No description available)\r\n") ; + } + + lInterfaceNumber++; + } + } + + if( lInterfaceNumber == 1 ) + { + /* The interface number was never incremented, so the above for() loop + did not execute meaning no interfaces were found. */ + printf( " \r\nNo network interfaces were found.\r\n" ); + pxAllNetworkInterfaces = NULL; + } + + printf( "\r\nThe interface that will be opened is set by configNETWORK_INTERFACE_TO_USE which should be defined in FreeRTOSConfig.h\r\n" ); + printf( "Attempting to open interface number %d.\r\n", configNETWORK_INTERFACE_TO_USE ); + + if( ( configNETWORK_INTERFACE_TO_USE < 1L ) || ( configNETWORK_INTERFACE_TO_USE > lInterfaceNumber ) ) + { + printf("\r\nconfigNETWORK_INTERFACE_TO_USE is not in the valid range.\r\n" ); + + if( pxAllNetworkInterfaces != NULL ) + { + /* Free the device list, as no devices are going to be opened. */ + pcap_freealldevs( pxAllNetworkInterfaces ); + pxAllNetworkInterfaces = NULL; + } + } + + return pxAllNetworkInterfaces; +} +/*-----------------------------------------------------------*/ + +static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ) +{ +pcap_if_t *xInterface; +long x; + + /* Walk the list of devices until the selected device is located. */ + xInterface = pxAllNetworkInterfaces; + for( x = 0L; x < ( configNETWORK_INTERFACE_TO_USE - 1L ); x++ ) + { + xInterface = xInterface->next; + } + + /* Open the selected interface. */ + pxOpenedInterfaceHandle = pcap_open( xInterface->name, /* The name of the selected interface. */ + UIP_CONF_BUFFER_SIZE, /* The size of the packet to capture. */ + PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscious mode as the MAC and + IP address is going to be "simulated", and + not be the real MAC and IP address. This allows + trafic to the simulated IP address to be routed + to uIP, and trafic to the real IP address to be + routed to the Windows TCP/IP stack. */ + 0xfffffffL, /* The read time out. This is going to block + until data is available. */ + NULL, /* No authentication is required as this is + not a remote capture session. */ + cErrorBuffer + ); + + if ( pxOpenedInterfaceHandle == NULL ) + { + printf( "\r\n%s is not supported by WinPcap and cannot be opened\r\n", xInterface->name ); + } + else + { + /* Configure the capture filter to allow blocking reads, and to filter + out packets that are not of interest to this demo. */ + prvConfigureCaptureBehaviour(); + } + + /* The device list is no longer required. */ + pcap_freealldevs( pxAllNetworkInterfaces ); +} +/*-----------------------------------------------------------*/ + +static void prvConfigureCaptureBehaviour( void ) +{ +struct bpf_program xFilterCode; +const long lMinBytesToCopy = 10L, lBlocking = 0L; +unsigned long ulNetMask; + + /* Unblock a read as soon as anything is received. */ + pcap_setmintocopy( pxOpenedInterfaceHandle, lMinBytesToCopy ); + + /* Allow blocking. */ + pcap_setnonblock( pxOpenedInterfaceHandle, lBlocking, cErrorBuffer ); + + /* Set up a filter so only the packets of interest are passed to the uIP + stack. cErrorBuffer is used for convenience to create the string. Don't + confuse this with an error message. */ + sprintf( cErrorBuffer, "broadcast or multicast or host %d.%d.%d.%d", configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 ); + + ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0; + + if( pcap_compile(pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 ) + { + printf("\r\nThe packet filter string is invalid\r\n" ); + } + else + { + if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 ) + { + printf( "\r\nAn error occurred setting the packet filter.\r\n" ); + } + } + + /* Create a task that simulates an interrupt in a real system. This will + block waiting for packets, then send a message to the uIP task when data + is available. */ + xTaskCreate( prvInterruptSimulator, ( signed char * ) "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, ( configuIP_TASK_PRIORITY - 1 ), NULL ); +} +/*-----------------------------------------------------------*/ + +static void prvInterruptSimulator( void *pvParameters ) +{ +static struct pcap_pkthdr *pxHeader; +const unsigned char *pucPacketData; +extern QueueHandle_t xEMACEventQueue; +const unsigned long ulRxEvent = uipETHERNET_RX_EVENT; +long lResult; + + /* Just to kill the compiler warning. */ + ( void ) pvParameters; + + for( ;; ) + { + /* Get the next packet. */ + lResult = pcap_next_ex( pxOpenedInterfaceHandle, &pxHeader, &pucPacketData ); + if( lResult ) + { + /* Is the next buffer into which data should be placed free? */ + if( lLengthOfDataInBuffer[ ucNextBufferToFill ] == 0L ) + { + /* Copy the data from the captured packet into the buffer. */ + memcpy( pucEthernetBufferPointers[ ucNextBufferToFill ], pucPacketData, pxHeader->len ); + + /* Note the amount of data that was copied. */ + lLengthOfDataInBuffer[ ucNextBufferToFill ] = pxHeader->len; + + /* Move onto the next buffer, wrapping around if necessary. */ + ucNextBufferToFill++; + if( ucNextBufferToFill >= archNUM_BUFFER_POINTERS ) + { + ucNextBufferToFill = 0U; + } + + /* Data was received and stored. Send a message to the uIP task + to let it know. */ + xQueueSendToBack( xEMACEventQueue, &ulRxEvent, portMAX_DELAY ); + } + } + } +} + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/bittypes.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/bittypes.h new file mode 100644 index 000000000..fcacd45fe --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/bittypes.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 1999 WIDE Project. + * 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. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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. + */ +#ifndef _BITTYPES_H +#define _BITTYPES_H + +#ifndef HAVE_U_INT8_T + +#if SIZEOF_CHAR == 1 +typedef unsigned char u_int8_t; +typedef signed char _int8_t; +#elif SIZEOF_INT == 1 +typedef unsigned int u_int8_t; +typedef signed int int8_t; +#else /* XXX */ +#error "there's no appropriate type for u_int8_t" +#endif +#define HAVE_U_INT8_T 1 +#define HAVE_INT8_T 1 + +#endif /* HAVE_U_INT8_T */ + +#ifndef HAVE_U_INT16_T + +#if SIZEOF_SHORT == 2 +typedef unsigned short u_int16_t; +typedef signed short _int16_t; +#elif SIZEOF_INT == 2 +typedef unsigned int u_int16_t; +typedef signed int int16_t; +#elif SIZEOF_CHAR == 2 +typedef unsigned char u_int16_t; +typedef signed char int16_t; +#else /* XXX */ +#error "there's no appropriate type for u_int16_t" +#endif +#define HAVE_U_INT16_T 1 +#define HAVE_INT16_T 1 + +#endif /* HAVE_U_INT16_T */ + +#ifndef HAVE_U_INT32_T + +#if SIZEOF_INT == 4 +typedef unsigned int u_int32_t; +typedef signed int _int32_t; +#elif SIZEOF_LONG == 4 +typedef unsigned long u_int32_t; +typedef signed long int32_t; +#elif SIZEOF_SHORT == 4 +typedef unsigned short u_int32_t; +typedef signed short int32_t; +#else /* XXX */ +#error "there's no appropriate type for u_int32_t" +#endif +#define HAVE_U_INT32_T 1 +#define HAVE_INT32_T 1 + +#endif /* HAVE_U_INT32_T */ + +#ifndef HAVE_U_INT64_T +#if SIZEOF_LONG_LONG == 8 +typedef unsigned long long u_int64_t; +typedef long long int64_t; +#elif defined(_MSC_EXTENSIONS) +typedef unsigned _int64 u_int64_t; +typedef _int64 int64_t; +#elif SIZEOF_INT == 8 +typedef unsigned int u_int64_t; +#elif SIZEOF_LONG == 8 +typedef unsigned long u_int64_t; +#elif SIZEOF_SHORT == 8 +typedef unsigned short u_int64_t; +#else /* XXX */ +#error "there's no appropriate type for u_int64_t" +#endif + +#endif /* HAVE_U_INT64_T */ + +#ifndef PRId64 +#ifdef _MSC_EXTENSIONS +#define PRId64 "I64d" +#else /* _MSC_EXTENSIONS */ +#define PRId64 "lld" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRId64 */ + +#ifndef PRIo64 +#ifdef _MSC_EXTENSIONS +#define PRIo64 "I64o" +#else /* _MSC_EXTENSIONS */ +#define PRIo64 "llo" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIo64 */ + +#ifndef PRIx64 +#ifdef _MSC_EXTENSIONS +#define PRIx64 "I64x" +#else /* _MSC_EXTENSIONS */ +#define PRIx64 "llx" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIx64 */ + +#ifndef PRIu64 +#ifdef _MSC_EXTENSIONS +#define PRIu64 "I64u" +#else /* _MSC_EXTENSIONS */ +#define PRIu64 "llu" +#endif /* _MSC_EXTENSIONS */ +#endif /* PRIu64 */ + +#endif /* _BITTYPES_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/ip6_misc.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/ip6_misc.h new file mode 100644 index 000000000..96822d0e8 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/ip6_misc.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1993, 1994, 1997 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code distributions + * retain the above copyright notice and this paragraph in its entirety, (2) + * distributions including binary code include the above copyright notice and + * this paragraph in its entirety in the documentation or other materials + * provided with the distribution, and (3) all advertising materials mentioning + * features or use of this software display the following acknowledgement: + * ``This product includes software developed by the University of California, + * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of + * the University nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#) $Header: /tcpdump/master/libpcap/Win32/Include/ip6_misc.h,v 1.5 2006-01-22 18:02:18 gianluca Exp $ (LBL) + */ + +/* + * This file contains a collage of declarations for IPv6 from FreeBSD not present in Windows + */ + +#include + +#include + +#ifndef __MINGW32__ +#define IN_MULTICAST(a) IN_CLASSD(a) +#endif + +#define IN_EXPERIMENTAL(a) ((((u_int32_t) (a)) & 0xf0000000) == 0xf0000000) + +#define IN_LOOPBACKNET 127 + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +/* IPv6 address */ +struct in6_addr + { + union + { + u_int8_t u6_addr8[16]; + u_int16_t u6_addr16[8]; + u_int32_t u6_addr32[4]; + } in6_u; +#define s6_addr in6_u.u6_addr8 +#define s6_addr16 in6_u.u6_addr16 +#define s6_addr32 in6_u.u6_addr32 +#define s6_addr64 in6_u.u6_addr64 + }; + +#define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } +#endif /* __MINGW32__ */ + + +#if (defined _MSC_VER) || (defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF)) +typedef unsigned short sa_family_t; +#endif + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) + +#define __SOCKADDR_COMMON(sa_prefix) \ + sa_family_t sa_prefix##family + +/* Ditto, for IPv6. */ +struct sockaddr_in6 + { + __SOCKADDR_COMMON (sin6_); + u_int16_t sin6_port; /* Transport layer port # */ + u_int32_t sin6_flowinfo; /* IPv6 flow information */ + struct in6_addr sin6_addr; /* IPv6 address */ + }; + +#define IN6_IS_ADDR_V4MAPPED(a) \ + ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \ + (((u_int32_t *) (a))[2] == htonl (0xffff))) + +#define IN6_IS_ADDR_MULTICAST(a) (((u_int8_t *) (a))[0] == 0xff) + +#define IN6_IS_ADDR_LINKLOCAL(a) \ + ((((u_int32_t *) (a))[0] & htonl (0xffc00000)) == htonl (0xfe800000)) + +#define IN6_IS_ADDR_LOOPBACK(a) \ + (((u_int32_t *) (a))[0] == 0 && ((u_int32_t *) (a))[1] == 0 && \ + ((u_int32_t *) (a))[2] == 0 && ((u_int32_t *) (a))[3] == htonl (1)) +#endif /* __MINGW32__ */ + +#define ip6_vfc ip6_ctlun.ip6_un2_vfc +#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow +#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt +#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim +#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim + +#define nd_rd_type nd_rd_hdr.icmp6_type +#define nd_rd_code nd_rd_hdr.icmp6_code +#define nd_rd_cksum nd_rd_hdr.icmp6_cksum +#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0] + +/* + * IPV6 extension headers + */ +#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */ +#define IPPROTO_IPV6 41 /* IPv6 header. */ +#define IPPROTO_ROUTING 43 /* IPv6 routing header */ +#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ +#define IPPROTO_ESP 50 /* encapsulating security payload */ +#define IPPROTO_AH 51 /* authentication header */ +#define IPPROTO_ICMPV6 58 /* ICMPv6 */ +#define IPPROTO_NONE 59 /* IPv6 no next header */ +#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ +#define IPPROTO_PIM 103 /* Protocol Independent Multicast. */ + +#define IPV6_RTHDR_TYPE_0 0 + +/* Option types and related macros */ +#define IP6OPT_PAD1 0x00 /* 00 0 00000 */ +#define IP6OPT_PADN 0x01 /* 00 0 00001 */ +#define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ +#define IP6OPT_JUMBO_LEN 6 +#define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 */ + +#define IP6OPT_RTALERT_LEN 4 +#define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ +#define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ +#define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ +#define IP6OPT_MINLEN 2 + +#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */ +#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */ +#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */ +#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */ +#define IP6OPT_EID 0x8a /* 10 0 01010 */ + +#define IP6OPT_TYPE(o) ((o) & 0xC0) +#define IP6OPT_TYPE_SKIP 0x00 +#define IP6OPT_TYPE_DISCARD 0x40 +#define IP6OPT_TYPE_FORCEICMP 0x80 +#define IP6OPT_TYPE_ICMP 0xC0 + +#define IP6OPT_MUTABLE 0x20 + + +#if defined(__MINGW32__) && defined(DEFINE_ADDITIONAL_IPV6_STUFF) +#ifndef EAI_ADDRFAMILY +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; +#endif +#endif /* __MINGW32__ */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/netif.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/netif.h new file mode 100644 index 000000000..6982ca09c --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/netif.h @@ -0,0 +1,94 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +#ifndef NET_IF_H +#define NET_IF_H + +/* + * Send uip_len bytes from uip_buf to the network interface selected by the + * configNETWORK_INTERFACE_TO_USE constant (defined in FreeRTOSConfig.h). + */ +void vNetifTx( void ); + +/* + * Receive bytes from the network interface selected by the + * configNETWORK_INTERFACE_TO_USE constant (defined in FreeRTOSConfig.h). The + * bytes are placed in uip_buf. The number of bytes copied into uip_buf is + * returned. + */ +UBaseType_t uxNetifRx( void ); + +/* + * Prepare a packet capture session. This will print out all the network + * interfaces available, and the one actually used is set by the + * configNETWORK_INTERFACE_TO_USE constant that is defined in + * FreeRTOSConfig.h. */ +BaseType_t xNetifInit( void ); + +#endif /* NET_IF_H */ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap-bpf.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap-bpf.h new file mode 100644 index 000000000..ff5b6e0da --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap-bpf.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.50 2007/04/01 21:43:55 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap-namedb.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap-namedb.h new file mode 100644 index 000000000..ee6715fba --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap-namedb.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-namedb.h,v 1.13 2006/10/04 18:13:32 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Some applications + * might expect to be able to include . + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap-stdinc.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap-stdinc.h new file mode 100644 index 000000000..c6ca8401a --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap-stdinc.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy) + * Copyright (c) 2005 - 2009 CACE Technologies, Inc. Davis (California) + * 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. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-stdinc.h,v 1.10.2.1 2008-10-06 15:38:39 gianluca Exp $ (LBL) + */ + +#define SIZEOF_CHAR 1 +#define SIZEOF_SHORT 2 +#define SIZEOF_INT 4 +#ifndef _MSC_EXTENSIONS +#define SIZEOF_LONG_LONG 8 +#endif + +/* + * Avoids a compiler warning in case this was already defined + * (someone defined _WINSOCKAPI_ when including 'windows.h', in order + * to prevent it from including 'winsock.h') + */ +#ifdef _WINSOCKAPI_ +#undef _WINSOCKAPI_ +#endif +#include + +#include + +#include "bittypes.h" +#include +#include + +#ifndef __MINGW32__ +#include "IP6_misc.h" +#endif + +#define caddr_t char* + +#define inline __inline + +#ifdef __MINGW32__ +#include +#else /*__MINGW32__*/ +/* MSVC compiler */ +#ifndef _UINTPTR_T_DEFINED +#ifdef _WIN64 +typedef unsigned __int64 uintptr_t; +#else +typedef _W64 unsigned int uintptr_t; +#endif +#define _UINTPTR_T_DEFINED +#endif + +#ifndef _INTPTR_T_DEFINED +#ifdef _WIN64 +typedef __int64 intptr_t; +#else +typedef _W64 int intptr_t; +#endif +#define _INTPTR_T_DEFINED +#endif + +#endif /*__MINGW32__*/ diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap.h new file mode 100644 index 000000000..2eea0750b --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.59 2006/10/04 18:09:22 guy Exp $ (LBL) + */ + +/* + * For backwards compatibility. + * + * Note to OS vendors: do NOT get rid of this file! Many applications + * expect to be able to include , and at least some of them + * go through contortions in their configure scripts to try to detect + * OSes that have "helpfully" moved pcap.h to without + * leaving behind a file. + */ +#include diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/bluetooth.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/bluetooth.h new file mode 100644 index 000000000..28b991f43 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/bluetooth.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * bluetooth data struct + * By Paolo Abeni + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/bluetooth.h,v 1.1 2007/09/22 02:10:17 guy Exp $ + */ + +#ifndef _PCAP_BLUETOOTH_STRUCTS_H__ +#define _PCAP_BLUETOOTH_STRUCTS_H__ + +/* + * Header prepended libpcap to each bluetooth h:4 frame. + * fields are in network byte order + */ +typedef struct _pcap_bluetooth_h4_header { + u_int32_t direction; /* if first bit is set direction is incoming */ +} pcap_bluetooth_h4_header; + + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/bpf.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/bpf.h new file mode 100644 index 000000000..b6d259679 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/bpf.h @@ -0,0 +1,934 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)bpf.h 7.1 (Berkeley) 5/7/91 + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/bpf.h,v 1.19.2.8 2008-09-22 20:16:01 guy Exp $ (LBL) + */ + +/* + * This is libpcap's cut-down version of bpf.h; it includes only + * the stuff needed for the code generator and the userland BPF + * interpreter, and the libpcap APIs for setting filters, etc.. + * + * "pcap-bpf.c" will include the native OS version, as it deals with + * the OS's BPF implementation. + * + * XXX - should this all just be moved to "pcap.h"? + */ + +#ifndef BPF_MAJOR_VERSION + +#ifdef __cplusplus +extern "C" { +#endif + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +#ifdef MSDOS /* must be 32-bit */ +typedef long bpf_int32; +typedef unsigned long bpf_u_int32; +#else +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +/* + * Alignment macros. BPF_WORDALIGN rounds up to the next + * even multiple of BPF_ALIGNMENT. + */ +#ifndef __NetBSD__ +#define BPF_ALIGNMENT sizeof(bpf_int32) +#else +#define BPF_ALIGNMENT sizeof(long) +#endif +#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) + +#define BPF_MAXBUFSIZE 0x8000 +#define BPF_MINBUFSIZE 32 + +/* + * Structure for "pcap_compile()", "pcap_setfilter()", etc.. + */ +struct bpf_program { + u_int bf_len; + struct bpf_insn *bf_insns; +}; + +/* + * Struct return by BIOCVERSION. This represents the version number of + * the filter language described by the instruction encodings below. + * bpf understands a program iff kernel_major == filter_major && + * kernel_minor >= filter_minor, that is, if the value returned by the + * running kernel has the same major number and a minor number equal + * equal to or less than the filter being downloaded. Otherwise, the + * results are undefined, meaning an error may be returned or packets + * may be accepted haphazardly. + * It has nothing to do with the source code version. + */ +struct bpf_version { + u_short bv_major; + u_short bv_minor; +}; +/* Current version number of filter architecture. */ +#define BPF_MAJOR_VERSION 1 +#define BPF_MINOR_VERSION 1 + +/* + * Data-link level type codes. + * + * Do *NOT* add new values to this list without asking + * "tcpdump-workers@lists.tcpdump.org" for a value. Otherwise, you run + * the risk of using a value that's already being used for some other + * purpose, and of having tools that read libpcap-format captures not + * being able to handle captures with your new DLT_ value, with no hope + * that they will ever be changed to do so (as that would destroy their + * ability to read captures using that value for that other purpose). + */ + +/* + * These are the types that are the same on all platforms, and that + * have been defined by for ages. + */ +#define DLT_NULL 0 /* BSD loopback encapsulation */ +#define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ +#define DLT_AX25 3 /* Amateur Radio AX.25 */ +#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ +#define DLT_CHAOS 5 /* Chaos */ +#define DLT_IEEE802 6 /* 802.5 Token Ring */ +#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ +#define DLT_SLIP 8 /* Serial Line IP */ +#define DLT_PPP 9 /* Point-to-point Protocol */ +#define DLT_FDDI 10 /* FDDI */ + +/* + * These are types that are different on some platforms, and that + * have been defined by for ages. We use #ifdefs to + * detect the BSDs that define them differently from the traditional + * libpcap + * + * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS, + * but I don't know what the right #define is for BSD/OS. + */ +#define DLT_ATM_RFC1483 11 /* LLC-encapsulated ATM */ + +#ifdef __OpenBSD__ +#define DLT_RAW 14 /* raw IP */ +#else +#define DLT_RAW 12 /* raw IP */ +#endif + +/* + * Given that the only OS that currently generates BSD/OS SLIP or PPP + * is, well, BSD/OS, arguably everybody should have chosen its values + * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they + * didn't. So it goes. + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) +#ifndef DLT_SLIP_BSDOS +#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ +#endif +#else +#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ +#endif + +/* + * 17 is used for DLT_OLD_PFLOG in OpenBSD; + * OBSOLETE: DLT_PFLOG is 117 in OpenBSD now as well. See below. + * 18 is used for DLT_PFSYNC in OpenBSD; don't use it for anything else. + */ + +#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ + +/* + * Apparently Redback uses this for its SmartEdge 400/800. I hope + * nobody else decided to use it, too. + */ +#define DLT_REDBACK_SMARTEDGE 32 + +/* + * These values are defined by NetBSD; other platforms should refrain from + * using them for other purposes, so that NetBSD savefiles with link + * types of 50 or 51 can be read as this type on all platforms. + */ +#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ +#define DLT_PPP_ETHER 51 /* PPP over Ethernet */ + +/* + * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses + * a link-layer type of 99 for the tcpdump it supplies. The link-layer + * header has 6 bytes of unknown data, something that appears to be an + * Ethernet type, and 36 bytes that appear to be 0 in at least one capture + * I've seen. + */ +#define DLT_SYMANTEC_FIREWALL 99 + +/* + * Values between 100 and 103 are used in capture file headers as + * link-layer types corresponding to DLT_ types that differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * This value was defined by libpcap 0.5; platforms that have defined + * it with a different value should define it here with that value - + * a link type of 104 in a save file will be mapped to DLT_C_HDLC, + * whatever value that happens to be, so programs will correctly + * handle files with that link type regardless of the value of + * DLT_C_HDLC. + * + * The name DLT_C_HDLC was used by BSD/OS; we use that name for source + * compatibility with programs written for BSD/OS. + * + * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, + * for source compatibility with programs written for libpcap 0.5. + */ +#define DLT_C_HDLC 104 /* Cisco HDLC */ +#define DLT_CHDLC DLT_C_HDLC + +#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ + +/* + * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW, + * except when it isn't. (I.e., sometimes it's just raw IP, and + * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL, + * so that we don't have to worry about the link-layer header.) + */ + +/* + * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides + * with other values. + * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header + * (DLCI, etc.). + */ +#define DLT_FRELAY 107 + +/* + * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except + * that the AF_ type in the link-layer header is in network byte order. + * + * DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so + * we don't use 12 for it in OSes other than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_LOOP 12 +#else +#define DLT_LOOP 108 +#endif + +/* + * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's + * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other + * than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_ENC 13 +#else +#define DLT_ENC 109 +#endif + +/* + * Values between 110 and 112 are reserved for use in capture file headers + * as link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ types + * other than the corresponding DLT_ types. + */ + +/* + * This is for Linux cooked sockets. + */ +#define DLT_LINUX_SLL 113 + +/* + * Apple LocalTalk hardware. + */ +#define DLT_LTALK 114 + +/* + * Acorn Econet. + */ +#define DLT_ECONET 115 + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define DLT_IPFILTER 116 + +/* + * OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, but that's DLT_LANE8023 + * in SuSE 6.3, so we can't use 17 for it in capture-file headers. + * + * XXX: is there a conflict with DLT_PFSYNC 18 as well? + */ +#ifdef __OpenBSD__ +#define DLT_OLD_PFLOG 17 +#define DLT_PFSYNC 18 +#endif +#define DLT_PFLOG 117 + +/* + * Registered for Cisco-internal use. + */ +#define DLT_CISCO_IOS 118 + +/* + * For 802.11 cards using the Prism II chips, with a link-layer + * header including Prism monitor mode information plus an 802.11 + * header. + */ +#define DLT_PRISM_HEADER 119 + +/* + * Reserved for Aironet 802.11 cards, with an Aironet link-layer header + * (see Doug Ambrisko's FreeBSD patches). + */ +#define DLT_AIRONET_HEADER 120 + +/* + * Reserved for Siemens HiPath HDLC. + */ +#define DLT_HHDLC 121 + +/* + * This is for RFC 2625 IP-over-Fibre Channel. + * + * This is not for use with raw Fibre Channel, where the link-layer + * header starts with a Fibre Channel frame header; it's for IP-over-FC, + * where the link-layer header starts with an RFC 2625 Network_Header + * field. + */ +#define DLT_IP_OVER_FC 122 + +/* + * This is for Full Frontal ATM on Solaris with SunATM, with a + * pseudo-header followed by an AALn PDU. + * + * There may be other forms of Full Frontal ATM on other OSes, + * with different pseudo-headers. + * + * If ATM software returns a pseudo-header with VPI/VCI information + * (and, ideally, packet type information, e.g. signalling, ILMI, + * LANE, LLC-multiplexed traffic, etc.), it should not use + * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump + * and the like don't have to infer the presence or absence of a + * pseudo-header and the form of the pseudo-header. + */ +#define DLT_SUNATM 123 /* Solaris+SunATM */ + +/* + * Reserved as per request from Kent Dahlgren + * for private use. + */ +#define DLT_RIO 124 /* RapidIO */ +#define DLT_PCI_EXP 125 /* PCI Express */ +#define DLT_AURORA 126 /* Xilinx Aurora link layer */ + +/* + * Header for 802.11 plus a number of bits of link-layer information + * including radio information, used by some recent BSD drivers as + * well as the madwifi Atheros driver for Linux. + */ +#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */ + +/* + * Reserved for the TZSP encapsulation, as per request from + * Chris Waters + * TZSP is a generic encapsulation for any other link type, + * which includes a means to include meta-information + * with the packet, e.g. signal strength and channel + * for 802.11 packets. + */ +#define DLT_TZSP 128 /* Tazmen Sniffer Protocol */ + +/* + * BSD's ARCNET headers have the source host, destination host, + * and type at the beginning of the packet; that's what's handed + * up to userland via BPF. + * + * Linux's ARCNET headers, however, have a 2-byte offset field + * between the host IDs and the type; that's what's handed up + * to userland via PF_PACKET sockets. + * + * We therefore have to have separate DLT_ values for them. + */ +#define DLT_ARCNET_LINUX 129 /* ARCNET */ + +/* + * Juniper-private data link types, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MLPPP 130 +#define DLT_JUNIPER_MLFR 131 +#define DLT_JUNIPER_ES 132 +#define DLT_JUNIPER_GGSN 133 +#define DLT_JUNIPER_MFR 134 +#define DLT_JUNIPER_ATM2 135 +#define DLT_JUNIPER_SERVICES 136 +#define DLT_JUNIPER_ATM1 137 + +/* + * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund + * . The header that's presented is an Ethernet-like + * header: + * + * #define FIREWIRE_EUI64_LEN 8 + * struct firewire_header { + * u_char firewire_dhost[FIREWIRE_EUI64_LEN]; + * u_char firewire_shost[FIREWIRE_EUI64_LEN]; + * u_short firewire_type; + * }; + * + * with "firewire_type" being an Ethernet type value, rather than, + * for example, raw GASP frames being handed up. + */ +#define DLT_APPLE_IP_OVER_IEEE1394 138 + +/* + * Various SS7 encapsulations, as per a request from Jeff Morriss + * and subsequent discussions. + */ +#define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */ +#define DLT_MTP2 140 /* MTP2, without pseudo-header */ +#define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */ +#define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */ + +/* + * DOCSIS MAC frames. + */ +#define DLT_DOCSIS 143 + +/* + * Linux-IrDA packets. Protocol defined at http://www.irda.org. + * Those packets include IrLAP headers and above (IrLMP...), but + * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy + * framing can be handled by the hardware and depend on the bitrate. + * This is exactly the format you would get capturing on a Linux-IrDA + * interface (irdaX), but not on a raw serial port. + * Note the capture is done in "Linux-cooked" mode, so each packet include + * a fake packet header (struct sll_header). This is because IrDA packet + * decoding is dependant on the direction of the packet (incomming or + * outgoing). + * When/if other platform implement IrDA capture, we may revisit the + * issue and define a real DLT_IRDA... + * Jean II + */ +#define DLT_LINUX_IRDA 144 + +/* + * Reserved for IBM SP switch and IBM Next Federation switch. + */ +#define DLT_IBM_SP 145 +#define DLT_IBM_SN 146 + +/* + * Reserved for private use. If you have some link-layer header type + * that you want to use within your organization, with the capture files + * using that link-layer header type not ever be sent outside your + * organization, you can use these values. + * + * No libpcap release will use these for any purpose, nor will any + * tcpdump release use them, either. + * + * Do *NOT* use these in capture files that you expect anybody not using + * your private versions of capture-file-reading tools to read; in + * particular, do *NOT* use them in products, otherwise you may find that + * people won't be able to use tcpdump, or snort, or Ethereal, or... to + * read capture files from your firewall/intrusion detection/traffic + * monitoring/etc. appliance, or whatever product uses that DLT_ value, + * and you may also find that the developers of those applications will + * not accept patches to let them read those files. + * + * Also, do not use them if somebody might send you a capture using them + * for *their* private type and tools using them for *your* private type + * would have to read them. + * + * Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value, + * as per the comment above, and use the type you're given. + */ +#define DLT_USER0 147 +#define DLT_USER1 148 +#define DLT_USER2 149 +#define DLT_USER3 150 +#define DLT_USER4 151 +#define DLT_USER5 152 +#define DLT_USER6 153 +#define DLT_USER7 154 +#define DLT_USER8 155 +#define DLT_USER9 156 +#define DLT_USER10 157 +#define DLT_USER11 158 +#define DLT_USER12 159 +#define DLT_USER13 160 +#define DLT_USER14 161 +#define DLT_USER15 162 + +/* + * For future use with 802.11 captures - defined by AbsoluteValue + * Systems to store a number of bits of link-layer information + * including radio information: + * + * http://www.shaftnet.org/~pizza/software/capturefrm.txt + * + * but it might be used by some non-AVS drivers now or in the + * future. + */ +#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MONITOR 164 + +/* + * Reserved for BACnet MS/TP. + */ +#define DLT_BACNET_MS_TP 165 + +/* + * Another PPP variant as per request from Karsten Keil . + * + * This is used in some OSes to allow a kernel socket filter to distinguish + * between incoming and outgoing packets, on a socket intended to + * supply pppd with outgoing packets so it can do dial-on-demand and + * hangup-on-lack-of-demand; incoming packets are filtered out so they + * don't cause pppd to hold the connection up (you don't want random + * input packets such as port scans, packets from old lost connections, + * etc. to force the connection to stay up). + * + * The first byte of the PPP header (0xff03) is modified to accomodate + * the direction - 0x00 = IN, 0x01 = OUT. + */ +#define DLT_PPP_PPPD 166 + +/* + * Names for backwards compatibility with older versions of some PPP + * software; new software should use DLT_PPP_PPPD. + */ +#define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD +#define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, cookies, etc.. + */ +#define DLT_JUNIPER_PPPOE 167 +#define DLT_JUNIPER_PPPOE_ATM 168 + +#define DLT_GPRS_LLC 169 /* GPRS LLC */ +#define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ +#define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ + +/* + * Requested by Oolan Zimmer for use in Gcom's T1/E1 line + * monitoring equipment. + */ +#define DLT_GCOM_T1E1 172 +#define DLT_GCOM_SERIAL 173 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . The DLT_ is used + * for internal communication to Physical Interface Cards (PIC) + */ +#define DLT_JUNIPER_PIC_PEER 174 + +/* + * Link types requested by Gregor Maier of Endace + * Measurement Systems. They add an ERF header (see + * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of + * the link-layer header. + */ +#define DLT_ERF_ETH 175 /* Ethernet */ +#define DLT_ERF_POS 176 /* Packet-over-SONET */ + +/* + * Requested by Daniele Orlandi for raw LAPD + * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header + * includes additional information before the LAPD header, so it's + * not necessarily a generic LAPD header. + */ +#define DLT_LINUX_LAPD 177 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ are used for prepending meta-information + * like interface index, interface name + * before standard Ethernet, PPP, Frelay & C-HDLC Frames + */ +#define DLT_JUNIPER_ETHER 178 +#define DLT_JUNIPER_PPP 179 +#define DLT_JUNIPER_FRELAY 180 +#define DLT_JUNIPER_CHDLC 181 + +/* + * Multi Link Frame Relay (FRF.16) + */ +#define DLT_MFR 182 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * voice Adapter Card (PIC) + */ +#define DLT_JUNIPER_VP 183 + +/* + * Arinc 429 frames. + * DLT_ requested by Gianluca Varenni . + * Every frame contains a 32bit A429 label. + * More documentation on Arinc 429 can be found at + * http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf + */ +#define DLT_A429 184 + +/* + * Arinc 653 Interpartition Communication messages. + * DLT_ requested by Gianluca Varenni . + * Please refer to the A653-1 standard for more information. + */ +#define DLT_A653_ICM 185 + +/* + * USB packets, beginning with a USB setup header; requested by + * Paolo Abeni . + */ +#define DLT_USB 186 + +/* + * Bluetooth HCI UART transport layer (part H:4); requested by + * Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4 187 + +/* + * IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz + * . + */ +#define DLT_IEEE802_16_MAC_CPS 188 + +/* + * USB packets, beginning with a Linux USB header; requested by + * Paolo Abeni . + */ +#define DLT_USB_LINUX 189 + +/* + * Controller Area Network (CAN) v. 2.0B packets. + * DLT_ requested by Gianluca Varenni . + * Used to dump CAN packets coming from a CAN Vector board. + * More documentation on the CAN v2.0B frames can be found at + * http://www.can-cia.org/downloads/?269 + */ +#define DLT_CAN20B 190 + +/* + * IEEE 802.15.4, with address fields padded, as is done by Linux + * drivers; requested by Juergen Schimmer. + */ +#define DLT_IEEE802_15_4_LINUX 191 + +/* + * Per Packet Information encapsulated packets. + * DLT_ requested by Gianluca Varenni . + */ +#define DLT_PPI 192 + +/* + * Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header; + * requested by Charles Clancy. + */ +#define DLT_IEEE802_16_MAC_CPS_RADIO 193 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for internal communication with a + * integrated service module (ISM). + */ +#define DLT_JUNIPER_ISM 194 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing); requested by Mikko Saarnivala . + */ +#define DLT_IEEE802_15_4 195 + +/* + * Various link-layer types, with a pseudo-header, for SITA + * (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com). + */ +#define DLT_SITA 196 + +/* + * Various link-layer types, with a pseudo-header, for Endace DAG cards; + * encapsulates Endace ERF records. Requested by Stephen Donnelly + * . + */ +#define DLT_ERF 197 + +/* + * Special header prepended to Ethernet packets when capturing from a + * u10 Networks board. Requested by Phil Mulholland + * . + */ +#define DLT_RAIF1 198 + +/* + * IPMB packet for IPMI, beginning with the I2C slave address, followed + * by the netFn and LUN, etc.. Requested by Chanthy Toeung + * . + */ +#define DLT_IPMB 199 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler . + * The DLT_ is used for capturing data on a secure tunnel interface. + */ +#define DLT_JUNIPER_ST 200 + +/* + * Bluetooth HCI UART transport layer (part H:4), with pseudo-header + * that includes direction information; requested by Paolo Abeni. + */ +#define DLT_BLUETOOTH_HCI_H4_WITH_PHDR 201 + +/* + * AX.25 packet with a 1-byte KISS header; see + * + * http://www.ax25.net/kiss.htm + * + * as per Richard Stearn . + */ +#define DLT_AX25_KISS 202 + +/* + * LAPD packets from an ISDN channel, starting with the address field, + * with no pseudo-header. + * Requested by Varuna De Silva . + */ +#define DLT_LAPD 203 + +/* + * Variants of various link-layer headers, with a one-byte direction + * pseudo-header prepended - zero means "received by this host", + * non-zero (any non-zero value) means "sent by this host" - as per + * Will Barker . + */ +#define DLT_PPP_WITH_DIR 204 /* PPP - don't confuse with DLT_PPP_WITH_DIRECTION */ +#define DLT_C_HDLC_WITH_DIR 205 /* Cisco HDLC */ +#define DLT_FRELAY_WITH_DIR 206 /* Frame Relay */ +#define DLT_LAPB_WITH_DIR 207 /* LAPB */ + +/* + * 208 is reserved for an as-yet-unspecified proprietary link-layer + * type, as requested by Will Barker. + */ + +/* + * IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman + * . + */ +#define DLT_IPMB_LINUX 209 + +/* + * FlexRay automotive bus - http://www.flexray.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_FLEXRAY 210 + +/* + * Media Oriented Systems Transport (MOST) bus for multimedia + * transport - http://www.mostcooperation.com/ - as requested + * by Hannes Kaelber . + */ +#define DLT_MOST 211 + +/* + * Local Interconnect Network (LIN) bus for vehicle networks - + * http://www.lin-subbus.org/ - as requested by Hannes Kaelber + * . + */ +#define DLT_LIN 212 + +/* + * X2E-private data link type used for serial line capture, + * as requested by Hannes Kaelber . + */ +#define DLT_X2E_SERIAL 213 + +/* + * X2E-private data link type used for the Xoraya data logger + * family, as requested by Hannes Kaelber . + */ +#define DLT_X2E_XORAYA 214 + +/* + * IEEE 802.15.4, exactly as it appears in the spec (no padding, no + * nothing), but with the PHY-level data for non-ASK PHYs (4 octets + * of 0 as preamble, one octet of SFD, one octet of frame length+ + * reserved bit, and then the MAC-layer data, starting with the + * frame control field). + * + * Requested by Max Filippov . + */ +#define DLT_IEEE802_15_4_NONASK_PHY 215 + + +/* + * DLT and savefile link type values are split into a class and + * a member of that class. A class value of 0 indicates a regular + * DLT_/LINKTYPE_ value. + */ +#define DLT_CLASS(x) ((x) & 0x03ff0000) + +/* + * NetBSD-specific generic "raw" link type. The class value indicates + * that this is the generic raw type, and the lower 16 bits are the + * address family we're dealing with. Those values are NetBSD-specific; + * do not assume that they correspond to AF_ values for your operating + * system. + */ +#define DLT_CLASS_NETBSD_RAWAF 0x02240000 +#define DLT_NETBSD_RAWAF(af) (DLT_CLASS_NETBSD_RAWAF | (af)) +#define DLT_NETBSD_RAWAF_AF(x) ((x) & 0x0000ffff) +#define DLT_IS_NETBSD_RAWAF(x) (DLT_CLASS(x) == DLT_CLASS_NETBSD_RAWAF) + + +/* + * The instruction encodings. + */ +/* instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* ret - BPF_K and BPF_X also apply */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 + +/* misc */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +#define BPF_TXA 0x80 + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_u_int32 k; +}; + +/* + * Macros for insn array initializers. + */ +#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } +#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } + +#if __STDC__ || defined(__cplusplus) +extern int bpf_validate(const struct bpf_insn *, int); +extern u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +#else +extern int bpf_validate(); +extern u_int bpf_filter(); +#endif + +/* + * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). + */ +#define BPF_MEMWORDS 16 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/namedb.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/namedb.h new file mode 100644 index 000000000..8298e35b9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/namedb.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1994, 1996 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/namedb.h,v 1.1 2006/10/04 18:09:22 guy Exp $ (LBL) + */ + +#ifndef lib_pcap_namedb_h +#define lib_pcap_namedb_h + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * As returned by the pcap_next_etherent() + * XXX this stuff doesn't belong in this interface, but this + * library already must do name to address translation, so + * on systems that don't have support for /etc/ethers, we + * export these hooks since they'll + */ +struct pcap_etherent { + u_char addr[6]; + char name[122]; +}; +#ifndef PCAP_ETHERS_FILE +#define PCAP_ETHERS_FILE "/etc/ethers" +#endif +struct pcap_etherent *pcap_next_etherent(FILE *); +u_char *pcap_ether_hostton(const char*); +u_char *pcap_ether_aton(const char *); + +bpf_u_int32 **pcap_nametoaddr(const char *); +#ifdef INET6 +struct addrinfo *pcap_nametoaddrinfo(const char *); +#endif +bpf_u_int32 pcap_nametonetaddr(const char *); + +int pcap_nametoport(const char *, int *, int *); +int pcap_nametoportrange(const char *, int *, int *, int *); +int pcap_nametoproto(const char *); +int pcap_nametoeproto(const char *); +int pcap_nametollc(const char *); +/* + * If a protocol is unknown, PROTO_UNDEF is returned. + * Also, pcap_nametoport() returns the protocol along with the port number. + * If there are ambiguous entried in /etc/services (i.e. domain + * can be either tcp or udp) PROTO_UNDEF is returned. + */ +#define PROTO_UNDEF -1 + +/* XXX move these to pcap-int.h? */ +int __pcap_atodn(const char *, bpf_u_int32 *); +int __pcap_atoin(const char *, bpf_u_int32 *); +u_short __pcap_nametodnaddr(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/pcap.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/pcap.h new file mode 100644 index 000000000..fbf83413a --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/pcap.h @@ -0,0 +1,407 @@ +/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */ +/* + * Copyright (c) 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/pcap.h,v 1.4.2.11 2008-10-06 15:38:39 gianluca Exp $ (LBL) + */ + +#ifndef lib_pcap_pcap_h +#define lib_pcap_pcap_h + +#if defined(WIN32) + #include +#elif defined(MSDOS) + #include + #include /* u_int, u_char etc. */ +#else /* UN*X */ + #include + #include +#endif /* WIN32/MSDOS/UN*X */ + +#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H +#include +#endif + +#include + +#ifdef HAVE_REMOTE + // We have to define the SOCKET here, although it has been defined in sockutils.h + // This is to avoid the distribution of the 'sockutils.h' file around + // (for example in the WinPcap developer's pack) + #ifndef SOCKET + #ifdef WIN32 + #define SOCKET unsigned int + #else + #define SOCKET int + #endif + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define PCAP_VERSION_MAJOR 2 +#define PCAP_VERSION_MINOR 4 + +#define PCAP_ERRBUF_SIZE 256 + +/* + * Compatibility for systems that have a bpf.h that + * predates the bpf typedefs for 64-bit support. + */ +#if BPF_RELEASE - 0 < 199406 +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +typedef struct pcap pcap_t; +typedef struct pcap_dumper pcap_dumper_t; +typedef struct pcap_if pcap_if_t; +typedef struct pcap_addr pcap_addr_t; + +/* + * The first record in the file contains saved values for some + * of the flags used in the printout phases of tcpdump. + * Many fields here are 32 bit ints so compilers won't insert unwanted + * padding; these files need to be interchangeable across architectures. + * + * Do not change the layout of this structure, in any way (this includes + * changes that only affect the length of fields in this structure). + * + * Also, do not change the interpretation of any of the members of this + * structure, in any way (this includes using values other than + * LINKTYPE_ values, as defined in "savefile.c", in the "linktype" + * field). + * + * Instead: + * + * introduce a new structure for the new format, if the layout + * of the structure changed; + * + * send mail to "tcpdump-workers@lists.tcpdump.org", requesting + * a new magic number for your new capture file format, and, when + * you get the new magic number, put it in "savefile.c"; + * + * use that magic number for save files with the changed file + * header; + * + * make the code in "savefile.c" capable of reading files with + * the old file header as well as files with the new file header + * (using the magic number to determine the header format). + * + * Then supply the changes as a patch at + * + * http://sourceforge.net/projects/libpcap/ + * + * so that future versions of libpcap and programs that use it (such as + * tcpdump) will be able to read your new capture file format. + */ +struct pcap_file_header { + bpf_u_int32 magic; + u_short version_major; + u_short version_minor; + bpf_int32 thiszone; /* gmt to local correction */ + bpf_u_int32 sigfigs; /* accuracy of timestamps */ + bpf_u_int32 snaplen; /* max length saved portion of each pkt */ + bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ +}; + +/* + * Macros for the value returned by pcap_datalink_ext(). + * + * If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro + * gives the FCS length of packets in the capture. + */ +#define LT_FCS_LENGTH_PRESENT(x) ((x) & 0x04000000) +#define LT_FCS_LENGTH(x) (((x) & 0xF0000000) >> 28) +#define LT_FCS_DATALINK_EXT(x) ((((x) & 0xF) << 28) | 0x04000000) + +typedef enum { + PCAP_D_INOUT = 0, + PCAP_D_IN, + PCAP_D_OUT +} pcap_direction_t; + +/* + * Generic per-packet information, as supplied by libpcap. + * + * The time stamp can and should be a "struct timeval", regardless of + * whether your system supports 32-bit tv_sec in "struct timeval", + * 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit + * and 64-bit applications. The on-disk format of savefiles uses 32-bit + * tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit + * and 64-bit versions of libpcap, even if they're on the same platform, + * should supply the appropriate version of "struct timeval", even if + * that's not what the underlying packet capture mechanism supplies. + */ +struct pcap_pkthdr { + struct timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ +}; + +/* + * As returned by the pcap_stats() + */ +struct pcap_stat { + u_int ps_recv; /* number of packets received */ + u_int ps_drop; /* number of packets dropped */ + u_int ps_ifdrop; /* drops by interface XXX not yet supported */ +#ifdef HAVE_REMOTE + u_int ps_capt; /* number of packets that are received by the application; please get rid off the Win32 ifdef */ + u_int ps_sent; /* number of packets sent by the server on the network */ + u_int ps_netdrop; /* number of packets lost on the network */ +#endif /* HAVE_REMOTE */ +}; + +#ifdef MSDOS +/* + * As returned by the pcap_stats_ex() + */ +struct pcap_stat_ex { + u_long rx_packets; /* total packets received */ + u_long tx_packets; /* total packets transmitted */ + u_long rx_bytes; /* total bytes received */ + u_long tx_bytes; /* total bytes transmitted */ + u_long rx_errors; /* bad packets received */ + u_long tx_errors; /* packet transmit problems */ + u_long rx_dropped; /* no space in Rx buffers */ + u_long tx_dropped; /* no space available for Tx */ + u_long multicast; /* multicast packets received */ + u_long collisions; + + /* detailed rx_errors: */ + u_long rx_length_errors; + u_long rx_over_errors; /* receiver ring buff overflow */ + u_long rx_crc_errors; /* recv'd pkt with crc error */ + u_long rx_frame_errors; /* recv'd frame alignment error */ + u_long rx_fifo_errors; /* recv'r fifo overrun */ + u_long rx_missed_errors; /* recv'r missed packet */ + + /* detailed tx_errors */ + u_long tx_aborted_errors; + u_long tx_carrier_errors; + u_long tx_fifo_errors; + u_long tx_heartbeat_errors; + u_long tx_window_errors; + }; +#endif + +/* + * Item in a list of interfaces. + */ +struct pcap_if { + struct pcap_if *next; + char *name; /* name to hand to "pcap_open_live()" */ + char *description; /* textual description of interface, or NULL */ + struct pcap_addr *addresses; + bpf_u_int32 flags; /* PCAP_IF_ interface flags */ +}; + +#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */ + +/* + * Representation of an interface address. + */ +struct pcap_addr { + struct pcap_addr *next; + struct sockaddr *addr; /* address */ + struct sockaddr *netmask; /* netmask for that address */ + struct sockaddr *broadaddr; /* broadcast address for that address */ + struct sockaddr *dstaddr; /* P2P destination address for that address */ +}; + +typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *, + const u_char *); + +/* + * Error codes for the pcap API. + * These will all be negative, so you can check for the success or + * failure of a call that returns these codes by checking for a + * negative value. + */ +#define PCAP_ERROR -1 /* generic error code */ +#define PCAP_ERROR_BREAK -2 /* loop terminated by pcap_breakloop */ +#define PCAP_ERROR_NOT_ACTIVATED -3 /* the capture needs to be activated */ +#define PCAP_ERROR_ACTIVATED -4 /* the operation can't be performed on already activated captures */ +#define PCAP_ERROR_NO_SUCH_DEVICE -5 /* no such device exists */ +#define PCAP_ERROR_RFMON_NOTSUP -6 /* this device doesn't support rfmon (monitor) mode */ +#define PCAP_ERROR_NOT_RFMON -7 /* operation supported only in monitor mode */ +#define PCAP_ERROR_PERM_DENIED -8 /* no permission to open the device */ +#define PCAP_ERROR_IFACE_NOT_UP -9 /* interface isn't up */ + +/* + * Warning codes for the pcap API. + * These will all be positive and non-zero, so they won't look like + * errors. + */ +#define PCAP_WARNING 1 /* generic warning code */ +#define PCAP_WARNING_PROMISC_NOTSUP 2 /* this device doesn't support promiscuous mode */ + +char *pcap_lookupdev(char *); +int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *); + +pcap_t *pcap_create(const char *, char *); +int pcap_set_snaplen(pcap_t *, int); +int pcap_set_promisc(pcap_t *, int); +int pcap_can_set_rfmon(pcap_t *); +int pcap_set_rfmon(pcap_t *, int); +int pcap_set_timeout(pcap_t *, int); +int pcap_set_buffer_size(pcap_t *, int); +int pcap_activate(pcap_t *); + +pcap_t *pcap_open_live(const char *, int, int, int, char *); +pcap_t *pcap_open_dead(int, int); +pcap_t *pcap_open_offline(const char *, char *); +#if defined(WIN32) +pcap_t *pcap_hopen_offline(intptr_t, char *); +#if !defined(LIBPCAP_EXPORTS) +#define pcap_fopen_offline(f,b) \ + pcap_hopen_offline(_get_osfhandle(_fileno(f)), b) +#else /*LIBPCAP_EXPORTS*/ +static pcap_t *pcap_fopen_offline(FILE *, char *); +#endif +#else /*WIN32*/ +pcap_t *pcap_fopen_offline(FILE *, char *); +#endif /*WIN32*/ + +void pcap_close(pcap_t *); +int pcap_loop(pcap_t *, int, pcap_handler, u_char *); +int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *); +const u_char* + pcap_next(pcap_t *, struct pcap_pkthdr *); +int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **); +void pcap_breakloop(pcap_t *); +int pcap_stats(pcap_t *, struct pcap_stat *); +int pcap_setfilter(pcap_t *, struct bpf_program *); +int pcap_setdirection(pcap_t *, pcap_direction_t); +int pcap_getnonblock(pcap_t *, char *); +int pcap_setnonblock(pcap_t *, int, char *); +int pcap_inject(pcap_t *, const void *, size_t); +int pcap_sendpacket(pcap_t *, const u_char *, int); +const char *pcap_statustostr(int); +const char *pcap_strerror(int); +char *pcap_geterr(pcap_t *); +void pcap_perror(pcap_t *, char *); +int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, + bpf_u_int32); +int pcap_compile_nopcap(int, int, struct bpf_program *, + const char *, int, bpf_u_int32); +void pcap_freecode(struct bpf_program *); +int pcap_offline_filter(struct bpf_program *, const struct pcap_pkthdr *, + const u_char *); +int pcap_datalink(pcap_t *); +int pcap_datalink_ext(pcap_t *); +int pcap_list_datalinks(pcap_t *, int **); +int pcap_set_datalink(pcap_t *, int); +void pcap_free_datalinks(int *); +int pcap_datalink_name_to_val(const char *); +const char *pcap_datalink_val_to_name(int); +const char *pcap_datalink_val_to_description(int); +int pcap_snapshot(pcap_t *); +int pcap_is_swapped(pcap_t *); +int pcap_major_version(pcap_t *); +int pcap_minor_version(pcap_t *); + +/* XXX */ +FILE *pcap_file(pcap_t *); +int pcap_fileno(pcap_t *); + +pcap_dumper_t *pcap_dump_open(pcap_t *, const char *); +pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp); +FILE *pcap_dump_file(pcap_dumper_t *); +long pcap_dump_ftell(pcap_dumper_t *); +int pcap_dump_flush(pcap_dumper_t *); +void pcap_dump_close(pcap_dumper_t *); +void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *); + +int pcap_findalldevs(pcap_if_t **, char *); +void pcap_freealldevs(pcap_if_t *); + +const char *pcap_lib_version(void); + +/* XXX this guy lives in the bpf tree */ +u_int bpf_filter(const struct bpf_insn *, const u_char *, u_int, u_int); +int bpf_validate(const struct bpf_insn *f, int len); +char *bpf_image(const struct bpf_insn *, int); +void bpf_dump(const struct bpf_program *, int); + +#if defined(WIN32) + +/* + * Win32 definitions + */ + +int pcap_setbuff(pcap_t *p, int dim); +int pcap_setmode(pcap_t *p, int mode); +int pcap_setmintocopy(pcap_t *p, int size); + +#ifdef WPCAP +/* Include file with the wpcap-specific extensions */ +#include +#endif /* WPCAP */ + +#define MODE_CAPT 0 +#define MODE_STAT 1 +#define MODE_MON 2 + +#elif defined(MSDOS) + +/* + * MS-DOS definitions + */ + +int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *); +void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait); +u_long pcap_mac_packets (void); + +#else /* UN*X */ + +/* + * UN*X definitions + */ + +int pcap_get_selectable_fd(pcap_t *); + +#endif /* WIN32/MSDOS/UN*X */ + +#ifdef HAVE_REMOTE +/* Includes most of the public stuff that is needed for the remote capture */ +#include +#endif /* HAVE_REMOTE */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/sll.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/sll.h new file mode 100644 index 000000000..5907beded --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/sll.h @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/sll.h,v 1.2.2.1 2008-05-30 01:36:06 guy Exp $ (LBL) + */ + +/* + * For captures on Linux cooked sockets, we construct a fake header + * that includes: + * + * a 2-byte "packet type" which is one of: + * + * LINUX_SLL_HOST packet was sent to us + * LINUX_SLL_BROADCAST packet was broadcast + * LINUX_SLL_MULTICAST packet was multicast + * LINUX_SLL_OTHERHOST packet was sent to somebody else + * LINUX_SLL_OUTGOING packet was sent *by* us; + * + * a 2-byte Ethernet protocol field; + * + * a 2-byte link-layer type; + * + * a 2-byte link-layer address length; + * + * an 8-byte source link-layer address, whose actual length is + * specified by the previous value. + * + * All fields except for the link-layer address are in network byte order. + * + * DO NOT change the layout of this structure, or change any of the + * LINUX_SLL_ values below. If you must change the link-layer header + * for a "cooked" Linux capture, introduce a new DLT_ type (ask + * "tcpdump-workers@lists.tcpdump.org" for one, so that you don't give it + * a value that collides with a value already being used), and use the + * new header in captures of that type, so that programs that can + * handle DLT_LINUX_SLL captures will continue to handle them correctly + * without any change, and so that capture files with different headers + * can be told apart and programs that read them can dissect the + * packets in them. + */ + +#ifndef lib_pcap_sll_h +#define lib_pcap_sll_h + +/* + * A DLT_LINUX_SLL fake link-layer header. + */ +#define SLL_HDR_LEN 16 /* total header length */ +#define SLL_ADDRLEN 8 /* length of address field */ + +struct sll_header { + u_int16_t sll_pkttype; /* packet type */ + u_int16_t sll_hatype; /* link-layer address type */ + u_int16_t sll_halen; /* link-layer address length */ + u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ + u_int16_t sll_protocol; /* protocol */ +}; + +/* + * The LINUX_SLL_ values for "sll_pkttype"; these correspond to the + * PACKET_ values on Linux, but are defined here so that they're + * available even on systems other than Linux, and so that they + * don't change even if the PACKET_ values change. + */ +#define LINUX_SLL_HOST 0 +#define LINUX_SLL_BROADCAST 1 +#define LINUX_SLL_MULTICAST 2 +#define LINUX_SLL_OTHERHOST 3 +#define LINUX_SLL_OUTGOING 4 + +/* + * The LINUX_SLL_ values for "sll_protocol"; these correspond to the + * ETH_P_ values on Linux, but are defined here so that they're + * available even on systems other than Linux. We assume, for now, + * that the ETH_P_ values won't change in Linux; if they do, then: + * + * if we don't translate them in "pcap-linux.c", capture files + * won't necessarily be readable if captured on a system that + * defines ETH_P_ values that don't match these values; + * + * if we do translate them in "pcap-linux.c", that makes life + * unpleasant for the BPF code generator, as the values you test + * for in the kernel aren't the values that you test for when + * reading a capture file, so the fixup code run on BPF programs + * handed to the kernel ends up having to do more work. + * + * Add other values here as necessary, for handling packet types that + * might show up on non-Ethernet, non-802.x networks. (Not all the ones + * in the Linux "if_ether.h" will, I suspect, actually show up in + * captures.) + */ +#define LINUX_SLL_P_802_3 0x0001 /* Novell 802.3 frames without 802.2 LLC header */ +#define LINUX_SLL_P_802_2 0x0004 /* 802.2 frames (not D/I/X Ethernet) */ + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/usb.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/usb.h new file mode 100644 index 000000000..f150d3be0 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/usb.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2006 Paolo Abeni (Italy) + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + * Basic USB data struct + * By Paolo Abeni + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/usb.h,v 1.6 2007/09/22 02:06:08 guy Exp $ + */ + +#ifndef _PCAP_USB_STRUCTS_H__ +#define _PCAP_USB_STRUCTS_H__ + +/* + * possible transfer mode + */ +#define URB_TRANSFER_IN 0x80 +#define URB_ISOCHRONOUS 0x0 +#define URB_INTERRUPT 0x1 +#define URB_CONTROL 0x2 +#define URB_BULK 0x3 + +/* + * possible event type + */ +#define URB_SUBMIT 'S' +#define URB_COMPLETE 'C' +#define URB_ERROR 'E' + +/* + * USB setup header as defined in USB specification. + * Appears at the front of each packet in DLT_USB captures. + */ +typedef struct _usb_setup { + u_int8_t bmRequestType; + u_int8_t bRequest; + u_int16_t wValue; + u_int16_t wIndex; + u_int16_t wLength; +} pcap_usb_setup; + + +/* + * Header prepended by linux kernel to each event. + * Appears at the front of each packet in DLT_USB_LINUX captures. + */ +typedef struct _usb_header { + u_int64_t id; + u_int8_t event_type; + u_int8_t transfer_type; + u_int8_t endpoint_number; + u_int8_t device_address; + u_int16_t bus_id; + char setup_flag;/*if !=0 the urb setup header is not present*/ + char data_flag; /*if !=0 no urb data is present*/ + int64_t ts_sec; + int32_t ts_usec; + int32_t status; + u_int32_t urb_len; + u_int32_t data_len; /* amount of urb data really present in this event*/ + pcap_usb_setup setup; +} pcap_usb_header; + + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/vlan.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/vlan.h new file mode 100644 index 000000000..00ed9b616 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/pcap/vlan.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#) $Header: /tcpdump/master/libpcap/pcap/vlan.h,v 1.1.2.2 2008-08-06 07:45:59 guy Exp $ + */ + +#ifndef lib_pcap_vlan_h +#define lib_pcap_vlan_h + +struct vlan_tag { + u_int16_t vlan_tpid; /* ETH_P_8021Q */ + u_int16_t vlan_tci; /* VLAN TCI */ +}; + +#define VLAN_TAG_LEN 4 + +#endif diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/remote-ext.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/remote-ext.h new file mode 100644 index 000000000..9f54d6974 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/remote-ext.h @@ -0,0 +1,444 @@ +/* + * Copyright (c) 2002 - 2003 + * NetGroup, Politecnico di Torino (Italy) + * 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. + * 3. Neither the name of the Politecnico di Torino nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + * + */ + + +#ifndef __REMOTE_EXT_H__ +#define __REMOTE_EXT_H__ + + +#ifndef HAVE_REMOTE +#error Please do not include this file directly. Just define HAVE_REMOTE and then include pcap.h +#endif + +// Definition for Microsoft Visual Studio +#if _MSC_VER > 1000 +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + \file remote-ext.h + + The goal of this file it to include most of the new definitions that should be + placed into the pcap.h file. + + It includes all new definitions (structures and functions like pcap_open(). + Some of the functions are not really a remote feature, but, right now, + they are placed here. +*/ + + + +// All this stuff is public +/*! \addtogroup remote_struct + \{ +*/ + + + + +/*! + \brief Defines the maximum buffer size in which address, port, interface names are kept. + + In case the adapter name or such is larger than this value, it is truncated. + This is not used by the user; however it must be aware that an hostname / interface + name longer than this value will be truncated. +*/ +#define PCAP_BUF_SIZE 1024 + + +/*! \addtogroup remote_source_ID + \{ +*/ + + +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a file, i.e. the user want to open a capture from a local file. +*/ +#define PCAP_SRC_FILE 2 +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a local interface, i.e. the user want to open a capture from + a local interface. This does not involve the RPCAP protocol. +*/ +#define PCAP_SRC_IFLOCAL 3 +/*! + \brief Internal representation of the type of source in use (file, + remote/local interface). + + This indicates a remote interface, i.e. the user want to open a capture from + an interface on a remote host. This does involve the RPCAP protocol. +*/ +#define PCAP_SRC_IFREMOTE 4 + +/*! + \} +*/ + + + +/*! \addtogroup remote_source_string + + The formats allowed by the pcap_open() are the following: + - file://path_and_filename [opens a local file] + - rpcap://devicename [opens the selected device devices available on the local host, without using the RPCAP protocol] + - rpcap://host/devicename [opens the selected device available on a remote host] + - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP] + - adaptername [to open a local adapter; kept for compability, but it is strongly discouraged] + - (NULL) [to open the first local adapter; kept for compability, but it is strongly discouraged] + + The formats allowed by the pcap_findalldevs_ex() are the following: + - file://folder/ [lists all the files in the given folder] + - rpcap:// [lists all local adapters] + - rpcap://host:port/ [lists the devices available on a remote host] + + Referring to the 'host' and 'port' paramters, they can be either numeric or literal. Since + IPv6 is fully supported, these are the allowed formats: + + - host (literal): e.g. host.foo.bar + - host (numeric IPv4): e.g. 10.11.12.13 + - host (numeric IPv4, IPv6 style): e.g. [10.11.12.13] + - host (numeric IPv6): e.g. [1:2:3::4] + - port: can be either numeric (e.g. '80') or literal (e.g. 'http') + + Here you find some allowed examples: + - rpcap://host.foo.bar/devicename [everything literal, no port number] + - rpcap://host.foo.bar:1234/devicename [everything literal, with port number] + - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number] + - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number] + - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number] + - rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number] + - rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number] + - rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number] + + \{ +*/ + + +/*! + \brief String that will be used to determine the type of source in use (file, + remote/local interface). + + This string will be prepended to the interface name in order to create a string + that contains all the information required to open the source. + + This string indicates that the user wants to open a capture from a local file. +*/ +#define PCAP_SRC_FILE_STRING "file://" +/*! + \brief String that will be used to determine the type of source in use (file, + remote/local interface). + + This string will be prepended to the interface name in order to create a string + that contains all the information required to open the source. + + This string indicates that the user wants to open a capture from a network interface. + This string does not necessarily involve the use of the RPCAP protocol. If the + interface required resides on the local host, the RPCAP protocol is not involved + and the local functions are used. +*/ +#define PCAP_SRC_IF_STRING "rpcap://" + +/*! + \} +*/ + + + + + +/*! + \addtogroup remote_open_flags + \{ +*/ + +/*! + \brief Defines if the adapter has to go in promiscuous mode. + + It is '1' if you have to open the adapter in promiscuous mode, '0' otherwise. + Note that even if this parameter is false, the interface could well be in promiscuous + mode for some other reason (for example because another capture process with + promiscuous mode enabled is currently using that interface). + On on Linux systems with 2.2 or later kernels (that have the "any" device), this + flag does not work on the "any" device; if an argument of "any" is supplied, + the 'promisc' flag is ignored. +*/ +#define PCAP_OPENFLAG_PROMISCUOUS 1 + +/*! + \brief Defines if the data trasfer (in case of a remote + capture) has to be done with UDP protocol. + + If it is '1' if you want a UDP data connection, '0' if you want + a TCP data connection; control connection is always TCP-based. + A UDP connection is much lighter, but it does not guarantee that all + the captured packets arrive to the client workstation. Moreover, + it could be harmful in case of network congestion. + This flag is meaningless if the source is not a remote interface. + In that case, it is simply ignored. +*/ +#define PCAP_OPENFLAG_DATATX_UDP 2 + + +/*! + \brief Defines if the remote probe will capture its own generated traffic. + + In case the remote probe uses the same interface to capture traffic and to send + data back to the caller, the captured traffic includes the RPCAP traffic as well. + If this flag is turned on, the RPCAP traffic is excluded from the capture, so that + the trace returned back to the collector is does not include this traffic. +*/ +#define PCAP_OPENFLAG_NOCAPTURE_RPCAP 4 + +/*! + \brief Defines if the local adapter will capture its own generated traffic. + + This flag tells the underlying capture driver to drop the packets that were sent by itself. + This is usefult when building applications like bridges, that should ignore the traffic + they just sent. +*/ +#define PCAP_OPENFLAG_NOCAPTURE_LOCAL 8 + +/*! + \brief This flag configures the adapter for maximum responsiveness. + + In presence of a large value for nbytes, WinPcap waits for the arrival of several packets before + copying the data to the user. This guarantees a low number of system calls, i.e. lower processor usage, + i.e. better performance, which is good for applications like sniffers. If the user sets the + PCAP_OPENFLAG_MAX_RESPONSIVENESS flag, the capture driver will copy the packets as soon as the application + is ready to receive them. This is suggested for real time applications (like, for example, a bridge) + that need the best responsiveness.*/ +#define PCAP_OPENFLAG_MAX_RESPONSIVENESS 16 + +/*! + \} +*/ + + +/*! + \addtogroup remote_samp_methods + \{ +*/ + +/*! + \brief No sampling has to be done on the current capture. + + In this case, no sampling algorithms are applied to the current capture. +*/ +#define PCAP_SAMP_NOSAMP 0 + +/*! + \brief It defines that only 1 out of N packets must be returned to the user. + + In this case, the 'value' field of the 'pcap_samp' structure indicates the + number of packets (minus 1) that must be discarded before one packet got accepted. + In other words, if 'value = 10', the first packet is returned to the caller, while + the following 9 are discarded. +*/ +#define PCAP_SAMP_1_EVERY_N 1 + +/*! + \brief It defines that we have to return 1 packet every N milliseconds. + + In this case, the 'value' field of the 'pcap_samp' structure indicates the 'waiting + time' in milliseconds before one packet got accepted. + In other words, if 'value = 10', the first packet is returned to the caller; the next + returned one will be the first packet that arrives when 10ms have elapsed. +*/ +#define PCAP_SAMP_FIRST_AFTER_N_MS 2 + +/*! + \} +*/ + + +/*! + \addtogroup remote_auth_methods + \{ +*/ + +/*! + \brief It defines the NULL authentication. + + This value has to be used within the 'type' member of the pcap_rmtauth structure. + The 'NULL' authentication has to be equal to 'zero', so that old applications + can just put every field of struct pcap_rmtauth to zero, and it does work. +*/ +#define RPCAP_RMTAUTH_NULL 0 +/*! + \brief It defines the username/password authentication. + + With this type of authentication, the RPCAP protocol will use the username/ + password provided to authenticate the user on the remote machine. If the + authentication is successful (and the user has the right to open network devices) + the RPCAP connection will continue; otherwise it will be dropped. + + This value has to be used within the 'type' member of the pcap_rmtauth structure. +*/ +#define RPCAP_RMTAUTH_PWD 1 + +/*! + \} +*/ + + + + +/*! + + \brief This structure keeps the information needed to autheticate + the user on a remote machine. + + The remote machine can either grant or refuse the access according + to the information provided. + In case the NULL authentication is required, both 'username' and + 'password' can be NULL pointers. + + This structure is meaningless if the source is not a remote interface; + in that case, the functions which requires such a structure can accept + a NULL pointer as well. +*/ +struct pcap_rmtauth +{ + /*! + \brief Type of the authentication required. + + In order to provide maximum flexibility, we can support different types + of authentication based on the value of this 'type' variable. The currently + supported authentication methods are defined into the + \link remote_auth_methods Remote Authentication Methods Section\endlink. + + */ + int type; + /*! + \brief Zero-terminated string containing the username that has to be + used on the remote machine for authentication. + + This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + and it can be NULL. + */ + char *username; + /*! + \brief Zero-terminated string containing the password that has to be + used on the remote machine for authentication. + + This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication + and it can be NULL. + */ + char *password; +}; + + +/*! + \brief This structure defines the information related to sampling. + + In case the sampling is requested, the capturing device should read + only a subset of the packets coming from the source. The returned packets depend + on the sampling parameters. + + \warning The sampling process is applied after the filtering process. + In other words, packets are filtered first, then the sampling process selects a + subset of the 'filtered' packets and it returns them to the caller. +*/ +struct pcap_samp +{ + /*! + Method used for sampling. Currently, the supported methods are listed in the + \link remote_samp_methods Sampling Methods Section\endlink. + */ + int method; + + /*! + This value depends on the sampling method defined. For its meaning, please check + at the \link remote_samp_methods Sampling Methods Section\endlink. + */ + int value; +}; + + + + +//! Maximum lenght of an host name (needed for the RPCAP active mode) +#define RPCAP_HOSTLIST_SIZE 1024 + + +/*! + \} +*/ // end of public documentation + + +// Exported functions + + + +/** \name New WinPcap functions + + This section lists the new functions that are able to help considerably in writing + WinPcap programs because of their easiness of use. + */ +//\{ +pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf); +int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf); +int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf); +int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf); +struct pcap_samp *pcap_setsampling(pcap_t *p); + +//\} +// End of new winpcap functions + + + +/** \name Remote Capture functions + */ +//\{ +SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf); +int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf); +int pcap_remoteact_close(const char *host, char *errbuf); +void pcap_remoteact_cleanup(); +//\} +// End of remote capture functions + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/wpcap.lib b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/WinPCap/wpcap.lib new file mode 100644 index 0000000000000000000000000000000000000000..f832e0445b5c7dafe5a0f887262064265ba2b293 GIT binary patch literal 19320 zcmdU0O>9(05-uRW4k3h)gbS|j4}Uz#t>t&Y%Y)S%rl;4JTp5pCTuoh zr6{Lp73IKQa^QrbD7U>tdx#=VoK`4`_7Fwch+_^p| zS6BDfKh<5`)$NUA`Fde~ylZ#2`x_V>8Oe?2azi67zdwrRhWbZ!@NyRb{1af)Ai(As zfGr;YjQ*f$?=%3>0gMxkW0+_MhKYuM)O4~3fN1X*n)>bm5FNa!=@dc`jeVwR->(2f zr@qm2dK`f0IF?CtuvgRRPmzx_yk67JDF8*E;}+y2(SaM92H(eeAPs$`X>=9#JJEGb+ptfFdaw>e+iq*x`Yiy_8LSsk zPhHb?lqKrHekD4vPE+rP*gr_)Sa+hqpEMo(8T%RO(3GZ$?*SB*@r$$_@rd?+t!Zo@ zjvvxV99NR-y@~cP&F-(99u}FD=x9fbs_AYW3=3tr%W|L_8r?37d|TiVLY~ zEvy9P(zP&>67jfHb#AU)syKqo60(JIwPA#!ut>cUHY?T2Y`I#v8X-CyA=yYsIvgR1 z{ec~7x`z7J_EoXesO6i5`6%5+g-kun7o&6?6lsXL*a+*hi*s{fJrauXgmly&fhf^s z3E4_`-3*NminK;E-)tB(9ge34;dLpXqEaSo&XvkdS!WX$Qnj#NubO6=h)8cV>r%o- zg$#}#%0zWB5s_Y~F4Rh8)(8_zN(7avo*HT-qioC+@^ketEL4l8NE;P0#e6f5+G>={ zMukkHlCL%9t7a5zRLGPXLF4Uwtri*$kqjZXkpEM)9$X9SjZ(D|bw-RQrAw8hw96CH zIB?un6^x}-su3UwQbeQ|7jfC3NgauZcw9Wn7pTvr=@psX2-v zPKxSZ5_y=PnoE_N$P;l>b2RJuN@JnKx{58)m9q&VA1x?B*qjgRVZ~&L@q{!@+G|$O zMuiOZZ>iF(7OFMdSjiHy%7zr}qAKD-YOYi%Vt=CNK_NilssaMOp#PS~G0a z3#jr@2fHjGTg%rQuBgKil48`YO^Y*yd_7#KHp6_O8RQFvux8Xd$xh8vE;W)lG&5CR zE{YZ+xiZSMFke|T8koY@IHd|2`Ept5435N=dVT?dRHmqxp2NoQb4*B>?S@fVJ*ax; z#(FH|ab7p_3pF&AS9m=V93eT2qkmOwwM1MS~zh^OYj+6w(qzK0R@x9xxG+j`OQ@O)YAwXd4wWGVhD0>`FwwU%QhSy`Bsht3yBaP(% ze(43MpxoU(=zYOFA0d4{0I&g1$&>iKwHu(>kDdVhcHwsomUZU@z?X;clzbTAW2BWw z0NzC^?gw}e%b&*d8(7cxv5c>V09Ik$uOp3b!!mjRZsYgctytC>fI7y0LnY-36{Zf7=>XNfjzJf#$Z1jgA3T1 zPr!??4yIuo*25%B!C6=dn_&}df!E4q}7h2Vp-SXex#;FLwXebxMB`=5C9I^9PV8s(AynihM(q47Hlj}F34Yx5 z5?lA>X`GVyBqM>5uRR)q`2Y)!$;$8I=7z=ffJr=%AQ6tTb`!4lnRETAExQINoiFRt&`kb6)zb#5OTk(WXF`3LzuyeV>Hxo-xE;5&wx*TA8>_O0# zmkw~5!tPVa^mwZsG2>X)OyT6P_FY#r`5rUt)woR?W2mOSw@rK-bJ`>O{@4yI%WYCPuf1kaI9X$ zNp*3w@H`qDr?aNs+&Oo2#&Hz0Why()^2D`)wqGhaX1N5xvM@q!8M4BUSkpzx4EynIBam!|lli=G+Mk}qYj1rahg&EpnNTMnkZ z6X;YS&b;BMmJ!Md!^x2hGOWz7`V;-AEPO=~#ptsfeItO|rMA!b4@pA?b9;q` zELR%xFI6w99i(bVQ6qBcEkNU%@)Gd`Z&9+L3Wy4UP

ii zt(#u7(X5F2?uWKuz$0Zt8OJO)7!6qr;{`-mW-ub#&;iOoI?D5ivfQBP z?YRYMzrS+nDC-bqg+bw+zXjsZL+Gm53p&N2Dhi z$sPL*kF_J!=aoO!_oo5a`Wl^G6SWCz8X~fDnjyWbFWEo#2>_LrfpY(yof(M2GuM&^&tn45RTGq64I1es%5IBD_q*{iK;u2FYa$7I6mN$G=TOG^=4LlDoZVf8Mpw z8`>v5@1R6iH=VS|vlhSLVkx(ih2l^~-N<=b^b_Mk`m)-zIUnA+Dq&#M2jgMyAnZo(4AD0*qp9b5G`pq6hCIM%0W!8nw$ z=X{p)l{75!sW3?UZSYVll0YzKHbPhY;~;29sU1>;c0zRY>-XSai;ZdbYZCG=to zq}NeHHZoF*W4Z&(oJadNNlfy2cY@QRZM55d-N8}r^iGgGy0KXzv2)UbaVVp147WIa zljmv+W4U(#jA6SoBbv{mY-KcYyI`T(Ull#QxQ(&o#f1gqP{wxoR*xQmS-4#qq68LyTjtHxo|KwtJB;6=J(Y@(tt?ceEx_3CTXEKlvOJ{NFy#1JrL^z$>YNrb&<@)H8*An#mck^5f7vwn&$@= zl0z9sY}m8Q7*9o{hYgHkLs{`!j2wCD52oO$CleN~{Wa0!-I!oJ@fxE8EMH$9a z4-3eltbOUxmcuD{<_QVov_E zH5QOV8As7)wU0Y^#`|rDZ3!!<#~Pe)(9AO+ZjXh{+AKB$jT}9S zHBXm1z-lq?X#aRxVyQ<_9pHHO31=jZeQssJ+SYsD$#znrB{r%InpH16?K&%w>>DwL zSc1lTMr+DJqo>Fgh(lRh<ClhvL%JxCqKEC=kR{Bh7JE3l N*?W_a?2Af)@;}RMSJ?mn literal 0 HcmV?d00001 diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/demo_logging.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/demo_logging.c new file mode 100644 index 000000000..6646fc79f --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/demo_logging.c @@ -0,0 +1,568 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * Logging utility that allows FreeRTOS tasks to log to a UDP port, stdout, and + * disk file without making any Win32 system calls themselves. + * + * Messages logged to a UDP port are sent directly (using FreeRTOS+TCP), but as + * FreeRTOS tasks cannot make Win32 system calls messages sent to stdout or a + * disk file are sent via a stream buffer to a Win32 thread which then performs + * the actual output. + */ + +/* Standard includes. */ +#include +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_Stream_Buffer.h" + +/* Demo includes. */ +#include "demo_logging.h" + +/*-----------------------------------------------------------*/ + +/* The maximum size to which the log file may grow, before being renamed +to .ful. */ +#define dlLOGGING_FILE_SIZE ( 40ul * 1024ul * 1024ul ) + +/* Dimensions the arrays into which print messages are created. */ +#define dlMAX_PRINT_STRING_LENGTH 255 + +/* The size of the stream buffer used to pass messages from FreeRTOS tasks to +the Win32 thread that is responsible for making any Win32 system calls that are +necessary for the selected logging method. */ +#define dlLOGGING_STREAM_BUFFER_SIZE 32768 + +/* A block time of zero simply means don't block. */ +#define dlDONT_BLOCK 0 + +/*-----------------------------------------------------------*/ + +/* + * Called from vLoggingInit() to start a new disk log file. + */ +static void prvFileLoggingInit( void ); + +/* + * Attempt to write a message to the file. + */ +static void prvLogToFile( const char *pcMessage, size_t xLength ); + +/* + * Simply close the logging file, if it is open. + */ +static void prvFileClose( void ); + +/* + * Before the scheduler is started this function is called directly. After the + * scheduler has started it is called from the Windows thread dedicated to + * outputting log messages. Only the windows thread actually performs the + * writing so as not to disrupt the simulation by making Windows system calls + * from FreeRTOS tasks. + */ +static void prvLoggingFlushBuffer( void ); + +/* + * The windows thread that performs the actual writing of messages that require + * Win32 system calls. Only the windows thread can make system calls so as not + * to disrupt the simulation by making Windows calls from FreeRTOS tasks. + */ +static DWORD WINAPI prvWin32LoggingThread( void *pvParam ); + +/* + * Creates the socket to which UDP messages are sent. This function is not + * called directly to prevent the print socket being created from within the IP + * task - which could result in a deadlock. Instead the function call is + * deferred to run in the RTOS daemon task - hence it prototype. + */ +static void prvCreatePrintSocket( void *pvParameter1, uint32_t ulParameter2 ); + +/*-----------------------------------------------------------*/ + +/* Windows event used to wake the Win32 thread which performs any logging that +needs Win32 system calls. */ +static void *pvLoggingThreadEvent = NULL; + +/* Stores the selected logging targets passed in as parameters to the +vLoggingInit() function. */ +BaseType_t xStdoutLoggingUsed = pdFALSE, xDiskFileLoggingUsed = pdFALSE, xUDPLoggingUsed = pdFALSE; + +/* Circular buffer used to pass messages from the FreeRTOS tasks to the Win32 +thread that is responsible for making Win32 calls (when stdout or a disk log is +used). */ +static StreamBuffer_t *xLogStreamBuffer = NULL; + +/* Handle to the file used for logging. This is left open while there are +messages waiting to be logged, then closed again in between logs. */ +static FILE *pxLoggingFileHandle = NULL; + +/* When true prints are performed directly. After start up xDirectPrint is set +to pdFALSE - at which time prints that require Win32 system calls are done by +the Win32 thread responsible for logging. */ +BaseType_t xDirectPrint = pdTRUE; + +/* File names for the in use and complete (full) log files. */ +static const char *pcLogFileName = "RTOSDemo.log"; +static const char *pcFullLogFileName = "RTOSDemo.ful"; + +/* Keep the current file size in a variable, as an optimisation. */ +static size_t ulSizeOfLoggingFile = 0ul; + +/* The UDP socket and address on/to which print messages are sent. */ +Socket_t xPrintSocket = FREERTOS_INVALID_SOCKET; +struct freertos_sockaddr xPrintUDPAddress; + +/*-----------------------------------------------------------*/ + +void vLoggingInit( BaseType_t xLogToStdout, BaseType_t xLogToFile, BaseType_t xLogToUDP, uint32_t ulRemoteIPAddress, uint16_t usRemotePort ) +{ + /* Can only be called before the scheduler has started. */ + configASSERT( xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED ); + + #if( ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) ) + { + HANDLE Win32Thread; + + /* Record which output methods are to be used. */ + xStdoutLoggingUsed = xLogToStdout; + xDiskFileLoggingUsed = xLogToFile; + xUDPLoggingUsed = xLogToUDP; + + /* If a disk file is used then initialise it now. */ + if( xDiskFileLoggingUsed != pdFALSE ) + { + prvFileLoggingInit(); + } + + /* If UDP logging is used then store the address to which the log data + will be sent - but don't create the socket yet because the network is + not initialised. */ + if( xUDPLoggingUsed != pdFALSE ) + { + /* Set the address to which the print messages are sent. */ + xPrintUDPAddress.sin_port = FreeRTOS_htons( usRemotePort ); + xPrintUDPAddress.sin_addr = ulRemoteIPAddress; + } + + /* If a disk file or stdout are to be used then Win32 system calls will + have to be made. Such system calls cannot be made from FreeRTOS tasks + so create a stream buffer to pass the messages to a Win32 thread, then + create the thread itself, along with a Win32 event that can be used to + unblock the thread. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) ) + { + /* Create the buffer. */ + xLogStreamBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) + dlLOGGING_STREAM_BUFFER_SIZE + 1 ); + configASSERT( xLogStreamBuffer ); + memset( xLogStreamBuffer, '\0', sizeof( *xLogStreamBuffer ) - sizeof( xLogStreamBuffer->ucArray ) ); + xLogStreamBuffer->LENGTH = dlLOGGING_STREAM_BUFFER_SIZE + 1; + + /* Create the Windows event. */ + pvLoggingThreadEvent = CreateEvent( NULL, FALSE, TRUE, "StdoutLoggingEvent" ); + + /* Create the thread itself. */ + Win32Thread = CreateThread( + NULL, /* Pointer to thread security attributes. */ + 0, /* Initial thread stack size, in bytes. */ + prvWin32LoggingThread, /* Pointer to thread function. */ + NULL, /* Argument for new thread. */ + 0, /* Creation flags. */ + NULL ); + + /* Use the cores that are not used by the FreeRTOS tasks. */ + SetThreadAffinityMask( Win32Thread, ~0x01u ); + SetThreadPriorityBoost( Win32Thread, TRUE ); + SetThreadPriority( Win32Thread, THREAD_PRIORITY_IDLE ); + } + } + #else + { + /* FreeRTOSIPConfig is set such that no print messages will be output. + Avoid compiler warnings about unused parameters. */ + ( void ) xLogToStdout; + ( void ) xLogToFile; + ( void ) xLogToUDP; + ( void ) usRemotePort; + ( void ) ulRemoteIPAddress; + } + #endif /* ( ipconfigHAS_DEBUG_PRINTF == 1 ) || ( ipconfigHAS_PRINTF == 1 ) */ +} +/*-----------------------------------------------------------*/ + +static void prvCreatePrintSocket( void *pvParameter1, uint32_t ulParameter2 ) +{ +static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 0 ); +Socket_t xSocket; + + /* The function prototype is that of a deferred function, but the parameters + are not actually used. */ + ( void ) pvParameter1; + ( void ) ulParameter2; + + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + + if( xSocket != FREERTOS_INVALID_SOCKET ) + { + /* FreeRTOS+TCP decides which port to bind to. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) ); + FreeRTOS_bind( xSocket, NULL, 0 ); + + /* Now the socket is bound it can be assigned to the print socket. */ + xPrintSocket = xSocket; + } +} +/*-----------------------------------------------------------*/ + +void vLoggingPrintf( const char *pcFormat, ... ) +{ +char cPrintString[ dlMAX_PRINT_STRING_LENGTH ]; +char cOutputString[ dlMAX_PRINT_STRING_LENGTH ]; +char *pcSource, *pcTarget, *pcBegin; +size_t xLength, xLength2, rc; +static BaseType_t xMessageNumber = 0; +va_list args; +uint32_t ulIPAddress; +const char *pcTaskName; +const char *pcNoTask = "None"; +int iOriginalPriority; +HANDLE xCurrentTask; + + + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) || ( xUDPLoggingUsed != pdFALSE ) ) + { + /* There are a variable number of parameters. */ + va_start( args, pcFormat ); + + /* Additional info to place at the start of the log. */ + if( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED ) + { + pcTaskName = pcTaskGetName( NULL ); + } + else + { + pcTaskName = pcNoTask; + } + + if( strcmp( pcFormat, "\n" ) != 0 ) + { + xLength = snprintf( cPrintString, dlMAX_PRINT_STRING_LENGTH, "%lu %lu [%s] ", + xMessageNumber++, + ( unsigned long ) xTaskGetTickCount(), + pcTaskName ); + } + else + { + xLength = 0; + memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH ); + } + + xLength2 = vsnprintf( cPrintString + xLength, dlMAX_PRINT_STRING_LENGTH - xLength, pcFormat, args ); + + if( xLength2 < 0 ) + { + /* Clean up. */ + xLength2 = sizeof( cPrintString ) - 1 - xLength; + cPrintString[ sizeof( cPrintString ) - 1 ] = '\0'; + } + + xLength += xLength2; + va_end( args ); + + /* For ease of viewing, copy the string into another buffer, converting + IP addresses to dot notation on the way. */ + pcSource = cPrintString; + pcTarget = cOutputString; + + while( ( *pcSource ) != '\0' ) + { + *pcTarget = *pcSource; + pcTarget++; + pcSource++; + + /* Look forward for an IP address denoted by 'ip'. */ + if( ( isxdigit( pcSource[ 0 ] ) != pdFALSE ) && ( pcSource[ 1 ] == 'i' ) && ( pcSource[ 2 ] == 'p' ) ) + { + *pcTarget = *pcSource; + pcTarget++; + *pcTarget = '\0'; + pcBegin = pcTarget - 8; + + while( ( pcTarget > pcBegin ) && ( isxdigit( pcTarget[ -1 ] ) != pdFALSE ) ) + { + pcTarget--; + } + + sscanf( pcTarget, "%8X", &ulIPAddress ); + rc = sprintf( pcTarget, "%lu.%lu.%lu.%lu", + ( unsigned long ) ( ulIPAddress >> 24UL ), + ( unsigned long ) ( (ulIPAddress >> 16UL) & 0xffUL ), + ( unsigned long ) ( (ulIPAddress >> 8UL) & 0xffUL ), + ( unsigned long ) ( ulIPAddress & 0xffUL ) ); + pcTarget += rc; + pcSource += 3; /* skip "ip" */ + } + } + + /* How far through the buffer was written? */ + xLength = ( BaseType_t ) ( pcTarget - cOutputString ); + + /* If the message is to be logged to a UDP port then it can be sent directly + because it only uses FreeRTOS function (not Win32 functions). */ + if( xUDPLoggingUsed != pdFALSE ) + { + if( ( xPrintSocket == FREERTOS_INVALID_SOCKET ) && ( FreeRTOS_IsNetworkUp() != pdFALSE ) ) + { + /* Create and bind the socket to which print messages are sent. The + xTimerPendFunctionCall() function is used even though this is + not an interrupt because this function is called from the IP task + and the IP task cannot itself wait for a socket to bind. The + parameters to prvCreatePrintSocket() are not required so set to + NULL or 0. */ + xTimerPendFunctionCall( prvCreatePrintSocket, NULL, 0, dlDONT_BLOCK ); + } + + if( xPrintSocket != FREERTOS_INVALID_SOCKET ) + { + FreeRTOS_sendto( xPrintSocket, cOutputString, xLength, 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) ); + + /* Just because the UDP data logger I'm using is dumb. */ + FreeRTOS_sendto( xPrintSocket, "\r", sizeof( char ), 0, &xPrintUDPAddress, sizeof( xPrintUDPAddress ) ); + } + } + + /* If logging is also to go to either stdout or a disk file then it cannot + be output here - so instead write the message to the stream buffer and wake + the Win32 thread which will read it from the stream buffer and perform the + actual output. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( xDiskFileLoggingUsed != pdFALSE ) ) + { + configASSERT( xLogStreamBuffer ); + + /* How much space is in the buffer? */ + xLength2 = uxStreamBufferGetSpace( xLogStreamBuffer ); + + /* There must be enough space to write both the string and the length of + the string. */ + if( xLength2 >= ( xLength + sizeof( xLength ) ) ) + { + /* First write in the length of the data, then write in the data + itself. Raising the thread priority is used as a critical section + as there are potentially multiple writers. The stream buffer is + only thread safe when there is a single writer (likewise for + reading from the buffer). */ + xCurrentTask = GetCurrentThread(); + iOriginalPriority = GetThreadPriority( xCurrentTask ); + SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL ); + uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) &( xLength ), sizeof( xLength ) ); + uxStreamBufferAdd( xLogStreamBuffer, 0, ( const uint8_t * ) cOutputString, xLength ); + SetThreadPriority( GetCurrentThread(), iOriginalPriority ); + } + + /* xDirectPrint is initialised to pdTRUE, and while it remains true the + logging output function is called directly. When the system is running + the output function cannot be called directly because it would get + called from both FreeRTOS tasks and Win32 threads - so instead wake the + Win32 thread responsible for the actual output. */ + if( xDirectPrint != pdFALSE ) + { + /* While starting up, the thread which calls prvWin32LoggingThread() + is not running yet and xDirectPrint will be pdTRUE. */ + prvLoggingFlushBuffer(); + } + else if( pvLoggingThreadEvent != NULL ) + { + /* While running, wake up prvWin32LoggingThread() to send the + logging data. */ + SetEvent( pvLoggingThreadEvent ); + } + } + } +} +/*-----------------------------------------------------------*/ + +static void prvLoggingFlushBuffer( void ) +{ +size_t xLength; +char cPrintString[ dlMAX_PRINT_STRING_LENGTH ]; + + /* Is there more than the length value stored in the circular buffer + used to pass data from the FreeRTOS simulator into this Win32 thread? */ + while( uxStreamBufferGetSize( xLogStreamBuffer ) > sizeof( xLength ) ) + { + memset( cPrintString, 0x00, dlMAX_PRINT_STRING_LENGTH ); + uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE ); + uxStreamBufferGet( xLogStreamBuffer, 0, ( uint8_t * ) cPrintString, xLength, pdFALSE ); + + /* Write the message to standard out if requested to do so when + vLoggingInit() was called, or if the network is not yet up. */ + if( ( xStdoutLoggingUsed != pdFALSE ) || ( FreeRTOS_IsNetworkUp() == pdFALSE ) ) + { + /* Write the message to stdout. */ + printf( "%s", cPrintString ); /*_RB_ Replace with _write(). */ + } + + /* Write the message to a file if requested to do so when + vLoggingInit() was called. */ + if( xDiskFileLoggingUsed != pdFALSE ) + { + prvLogToFile( cPrintString, xLength ); + } + } + + prvFileClose(); +} +/*-----------------------------------------------------------*/ + +static DWORD WINAPI prvWin32LoggingThread( void *pvParameter ) +{ +const DWORD xMaxWait = 1000; + + ( void ) pvParameter; + + /* From now on, prvLoggingFlushBuffer() will only be called from this + Windows thread */ + xDirectPrint = pdFALSE; + + for( ;; ) + { + /* Wait to be told there are message waiting to be logged. */ + WaitForSingleObject( pvLoggingThreadEvent, xMaxWait ); + + /* Write out all waiting messages. */ + prvLoggingFlushBuffer(); + } +} +/*-----------------------------------------------------------*/ + +static void prvFileLoggingInit( void ) +{ +FILE *pxHandle = fopen( pcLogFileName, "a" ); + + if( pxHandle != NULL ) + { + fseek( pxHandle, SEEK_END, 0ul ); + ulSizeOfLoggingFile = ftell( pxHandle ); + fclose( pxHandle ); + } + else + { + ulSizeOfLoggingFile = 0ul; + } +} +/*-----------------------------------------------------------*/ + +static void prvFileClose( void ) +{ + if( pxLoggingFileHandle != NULL ) + { + fclose( pxLoggingFileHandle ); + pxLoggingFileHandle = NULL; + } +} +/*-----------------------------------------------------------*/ + +static void prvLogToFile( const char *pcMessage, size_t xLength ) +{ + if( pxLoggingFileHandle == NULL ) + { + pxLoggingFileHandle = fopen( pcLogFileName, "a" ); + } + + if( pxLoggingFileHandle != NULL ) + { + fwrite( pcMessage, 1, xLength, pxLoggingFileHandle ); + ulSizeOfLoggingFile += xLength; + + /* If the file has grown to its maximum permissible size then close and + rename it - then start with a new file. */ + if( ulSizeOfLoggingFile > ( size_t ) dlLOGGING_FILE_SIZE ) + { + prvFileClose(); + if( _access( pcFullLogFileName, 00 ) == 0 ) + { + remove( pcFullLogFileName ); + } + rename( pcLogFileName, pcFullLogFileName ); + ulSizeOfLoggingFile = 0; + } + } +} +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/demo_logging.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/demo_logging.h new file mode 100644 index 000000000..e64ab70e8 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/demo_logging.h @@ -0,0 +1,89 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ +#ifndef DEMO_LOGGING_H +#define DEMO_LOGGING_H + +/* + * Initialise a logging system that can be used from FreeRTOS tasks and Win32 + * threads. Do not call printf() directly while the scheduler is running. + * + * Set xLogToStdout, xLogToFile and xLogToUDP to either pdTRUE or pdFALSE to + * lot to stdout, a disk file and a UDP port respectively. + * + * If xLogToUDP is pdTRUE then ulRemoteIPAddress and usRemotePort must be set + * to the IP address and port number to which UDP log messages will be sent. + */ +void vLoggingInit( BaseType_t xLogToStdout, + BaseType_t xLogToFile, + BaseType_t xLogToUDP, + uint32_t ulRemoteIPAddress, + uint16_t usRemotePort ); + +#endif /* DEMO_LOGGING_H */ + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/main.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/main.c new file mode 100644 index 000000000..a94a1cd54 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/main.c @@ -0,0 +1,858 @@ +/* + FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + All rights reserved + + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. + + This file is part of the FreeRTOS distribution. + + FreeRTOS 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 >>!AND MODIFIED BY!<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + *************************************************************************** + * * + * FreeRTOS provides completely free yet professionally developed, * + * robust, strictly quality controlled, supported, and cross * + * platform software that is more than just the market leader, it * + * is the industry's de facto standard. * + * * + * Help yourself get started quickly while simultaneously helping * + * to support the FreeRTOS project by purchasing a FreeRTOS * + * tutorial book, reference manual, or both: * + * http://www.FreeRTOS.org/Documentation * + * * + *************************************************************************** + + http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? + + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. + + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. + + http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, + including FreeRTOS+Trace - an indispensable productivity tool, a DOS + compatible FAT file system, and our tiny thread aware UDP/IP stack. + + http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate. + Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS. + + http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High + Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS + licenses offer ticketed support, indemnification and commercial middleware. + + http://www.SafeRTOS.com - High Integrity Systems also provide a safety + engineered and independently SIL3 certified version for use in safety and + mission critical applications that require provable dependability. + + 1 tab == 4 spaces! +*/ + +/* + * Instructions for using this project are provided on: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html + * + * NOTE: Some versions of Visual Studio will generate erroneous compiler + * warnings about variables being used before they are set. + */ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include +#include "task.h" +#include "timers.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_TCP_server.h" +#include "FreeRTOS_DHCP.h" + +/* FreeRTOS+FAT includes. */ +#include "ff_headers.h" +#include "ff_stdio.h" +#include "ff_ramdisk.h" + +/* Demo application includes. */ +#include "SimpleUDPClientAndServer.h" +#include "TwoUDPEchoClients.h" +#include "TCPEchoClient_SingleTasks.h" +#include "TCPEchoClient_SeparateTasks.h" +#include "UDPCommandConsole.h" +#include "TCPCommandConsole.h" +#include "UDPSelectServer.h" +#include "SimpleTCPEchoServer.h" +#include "TFTPServer.h" +#include "demo_logging.h" + +/* UDP command server task parameters. */ +#define mainUDP_CLI_TASK_PRIORITY ( tskIDLE_PRIORITY ) +#define mainUDP_CLI_PORT_NUMBER ( 5001UL ) + +/* TCP command server task parameters. The standard telnet port is used even +though this is not implementing a real telnet server. */ +#define mainTCP_CLI_TASK_PRIORITY ( tskIDLE_PRIORITY ) +#define mainTCP_CLI_PORT_NUMBER ( 23UL ) + +/* Simple UDP client and server task parameters. */ +#define mainSIMPLE_UDP_CLIENT_SERVER_TASK_PRIORITY ( tskIDLE_PRIORITY ) +#define mainSIMPLE_UDP_CLIENT_SERVER_PORT ( 5005UL ) + +/* Select UDP server task parameters. */ +#define mainUDP_SELECT_SERVER_TASK_PRIORITY ( tskIDLE_PRIORITY ) +#define mainUDP_SELECT_SERVER_PORT ( 30001UL ) + +/* Echo client task parameters - used for both TCP and UDP echo clients. */ +#define mainECHO_CLIENT_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE * 2 ) +#define mainECHO_CLIENT_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 ) + +/* FTP and HTTP servers execute in the TCP server work task. */ +#define mainTCP_SERVER_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 ) +#define mainTCP_SERVER_STACK_SIZE 1400 /* Not used in the Win32 simulator. */ + +/* TFTP server parameters. */ +#define mainTFTP_SERVER_PRIORITY ( tskIDLE_PRIORITY + 1 ) +#define mainTFTP_SERVER_STACK_SIZE 1400 /* Not used in the Win32 simulator. */ + +/* Dimensions the buffer used to send UDP print and debug messages. */ +#define cmdPRINTF_BUFFER_SIZE 512 + +/* The number and size of sectors that will make up the RAM disk. The RAM disk +is huge to allow some verbose FTP tests. */ +#define mainRAM_DISK_SECTOR_SIZE 512UL /* Currently fixed! */ +#define mainRAM_DISK_SECTORS ( ( 5UL * 1024UL * 1024UL ) / mainRAM_DISK_SECTOR_SIZE ) /* 5M bytes. */ +#define mainIO_MANAGER_CACHE_SIZE ( 15UL * mainRAM_DISK_SECTOR_SIZE ) + +/* Where the RAM disk is mounted. */ +#define mainRAM_DISK_NAME "/ram" + +/* Define a name that will be used for LLMNR and NBNS searches. */ +#define mainHOST_NAME "RTOSDemo" +#define mainDEVICE_NICK_NAME "windows_demo" + +/* Set to 0 to run the STDIO examples once only, or 1 to create multiple tasks +that run the tests continuously. */ +#define mainRUN_STDIO_TESTS_IN_MULTIPLE_TASK 0 + +/* Set the following constants to 1 or 0 to define which tasks to include and +exclude: + +mainCREATE_FTP_SERVER: When set to 1 the TCP server task will include an FTP +server. +See http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/FTP_Server.html + +mainCREATE_HTTP_SERVER: When set to 1 the TCP server task will include a basic +HTTP server. +See http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/HTTP_web_Server.html + +mainCREATE_UDP_CLI_TASKS: When set to 1 a command console that uses a UDP port +for input and output is created using FreeRTOS+CLI. The port number used is set +by the mainUDP_CLI_PORT_NUMBER constant above. A dumb UDP terminal such as YAT +can be used to connect. +See http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_CLI.html + +mainCREATE_TCP_CLI_TASKS: When set to 1 a command console that uses a TCP port +for input and output is created using FreeRTOS+CLI. The port number used is set +by the mainTCP_CLI_PORT_NUMBER constant above. A dumb UDP terminal such as YAT +can be used to connect. + +mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS: When set to 1 two UDP client tasks +and two UDP server tasks are created. The clients talk to the servers. One set +of tasks use the standard sockets interface, and the other the zero copy sockets +interface. These tasks are self checking and will trigger a configASSERT() if +they detect a difference in the data that is received from that which was sent. +As these tasks use UDP, and can therefore loose packets, they will cause +configASSERT() to be called when they are run in a less than perfect networking +environment. +See http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_client_server.html + +mainCREATE_SELECT_UDP_SERVER_TASKS: Uses two tasks to demonstrate the use of the +FreeRTOS_select() function. + +mainCREATE_UDP_ECHO_TASKS: When set to 1 a two tasks are created that send +UDP echo requests to the standard echo port (port 7). One task uses the +standard socket interface, the other the zero copy socket interface. The IP +address of the echo server must be configured using the configECHO_SERVER_ADDR0 +to configECHO_SERVER_ADDR3 constants in FreeRTOSConfig.h. These tasks are self +checking and will trigger a configASSERT() if the received echo reply does not +match the transmitted echo request. As these tasks use UDP, and can therefore +loose packets, they will cause configASSERT() to be called when they are run in +a less than perfect networking environment, or when connected to an echo server +that (legitimately as UDP is used) opts not to reply to every echo request. +See http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/UDP_Echo_Clients.html + +mainCREATE_TCP_ECHO_TASKS_SINGLE: When set to 1 a set of tasks are created that +send TCP echo requests to the standard echo port (port 7), then wait for and +verify the echo reply, from within the same task (Tx and Rx are performed in the +same RTOS task). The IP address of the echo server must be configured using the +configECHO_SERVER_ADDR0 to configECHO_SERVER_ADDR3 constants in +FreeRTOSConfig.h. +See http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Clients.html + +mainCREATE_TCP_ECHO_TASKS_SEPARATE: As per the description for the +mainCREATE_TCP_ECHO_TASKS_SINGLE constant above, except this time separate tasks +are used to send data to and receive data from the echo server (one task is used +for Tx and another task for Rx, using the same socket). +See http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Clients_Separate.html + +mainCREATE_SIMPLE_TCP_ECHO_SERVER: When set to 1 FreeRTOS tasks are used with +FreeRTOS+TCP to create a TCP echo server. Echo clients are also created, but +the echo clients use Windows threads (as opposed to FreeRTOS tasks) and use the +Windows TCP library (Winsocks). This creates a communication between the +FreeRTOS+TCP TCP/IP stack and the Windows TCP/IP stack. +See http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Echo_Server.html +*/ +#define mainCREATE_UDP_CLI_TASKS 1 +#define mainCREATE_TCP_CLI_TASKS 1 +#define mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS 1 +#define mainCREATE_SELECT_UDP_SERVER_TASKS 0 /* _RB_ Requires retest. */ +#define mainCREATE_UDP_ECHO_TASKS 1 +#define mainCREATE_TCP_ECHO_TASKS_SINGLE 1 +#define mainCREATE_TCP_ECHO_TASKS_SEPARATE 1 +#define mainCREATE_SIMPLE_TCP_ECHO_SERVER 1 +#define mainCREATE_FTP_SERVER 1 +#define mainCREATE_HTTP_SERVER 1 +#define mainCREATE_TFTP_SERVER 1 + +/* Set the following constant to pdTRUE to log using the method indicated by the +name of the constant, or pdFALSE to not log using the method indicated by the +name of the constant. Options include to standard out (mainLOG_TO_STDOUT), to a +disk file (mainLOG_TO_DISK_FILE), and to a UDP port (mainLOG_TO_UDP). If +mainLOG_TO_UDP is set to pdTRUE then UDP messages are sent to the IP address +configured as the echo server address (see the configECHO_SERVER_ADDR0 +definitions in FreeRTOSConfig.h) and the port number set by configPRINT_PORT in +FreeRTOSConfig.h. */ +#define mainLOG_TO_STDOUT pdTRUE +#define mainLOG_TO_DISK_FILE pdFALSE +#define mainLOG_TO_UDP pdFALSE + +/*-----------------------------------------------------------*/ + +/* + * Register commands that can be used with FreeRTOS+CLI through the UDP socket. + * The commands are defined in CLI-commands.c and File-related-CLI-commands.c + * respectively. + */ +extern void vRegisterCLICommands( void ); +extern void vRegisterFileSystemCLICommands( void ); + +/* + * A software timer is created that periodically checks that some of the TCP/IP + * demo tasks are still functioning as expected. This is the timer's callback + * function. + */ +static void prvCheckTimerCallback( TimerHandle_t xTimer ); + +/* + * Just seeds the simple pseudo random number generator. + */ +static void prvSRand( UBaseType_t ulSeed ); + +/* + * Miscellaneous initialisation including preparing the logging and seeding the + * random number generator. + */ +static void prvMiscInitialisation( void ); + +/* + * Creates a RAM disk, then creates files on the RAM disk. The files can then + * be viewed via the FTP server and the command line interface. + */ +static void prvCreateDiskAndExampleFiles( void ); + +/* + * Functions used to create and then test files on a disk. + */ +extern void vCreateAndVerifyExampleFiles( const char *pcMountPath ); +extern void vStdioWithCWDTest( const char *pcMountPath ); +extern void vMultiTaskStdioWithCWDTest( const char *const pcMountPath, uint16_t usStackSizeWords ); + +/* + * The task that runs the FTP and HTTP servers. + */ +#if( ( mainCREATE_FTP_SERVER == 1 ) || ( mainCREATE_HTTP_SERVER == 1 ) ) + static void prvServerWorkTask( void *pvParameters ); +#endif + + +/* The default IP and MAC address used by the demo. The address configuration +defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is +1 but a DHCP server could not be contacted. See the online documentation for +more information. */ +static const uint8_t ucIPAddress[ 4 ] = { configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3 }; +static const uint8_t ucNetMask[ 4 ] = { configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3 }; +static const uint8_t ucGatewayAddress[ 4 ] = { configGATEWAY_ADDR0, configGATEWAY_ADDR1, configGATEWAY_ADDR2, configGATEWAY_ADDR3 }; +static const uint8_t ucDNSServerAddress[ 4 ] = { configDNS_SERVER_ADDR0, configDNS_SERVER_ADDR1, configDNS_SERVER_ADDR2, configDNS_SERVER_ADDR3 }; + +/* Default MAC address configuration. The demo creates a virtual network +connection that uses this MAC address by accessing the raw Ethernet data +to and from a real network connection on the host PC. See the +configNETWORK_INTERFACE_TO_USE definition for information on how to configure +the real network connection to use. */ +const uint8_t ucMACAddress[ 6 ] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 }; + +/* The UDP address to which print messages are sent. */ +static struct freertos_sockaddr xPrintUDPAddress; + +/* Use by the pseudo random number generator. */ +static UBaseType_t ulNextRand; + +/* Handle of the task that runs the FTP and HTTP servers. */ +static TaskHandle_t xServerWorkTaskHandle = NULL; + +/*-----------------------------------------------------------*/ + +/* + * NOTE: Some versions of Visual Studio will generate erroneous compiler + * warnings about variables being used before they are set. + */ +int main( void ) +{ +const uint32_t ulLongTime_ms = 250UL, ulCheckTimerPeriod_ms = 15000UL; +TimerHandle_t xCheckTimer; + + /* + * Instructions for using this project are provided on: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html + * + * NOTE: Some versions of Visual Studio will generate erroneous compiler + * warnings about variables being used before they are set. + */ + + /* Miscellaneous initialisation including preparing the logging and seeding + the random number generator. */ + prvMiscInitialisation(); + + /* Initialise the network interface. + + ***NOTE*** Tasks that use the network are created in the network event hook + when the network is connected and ready for use (see the definition of + vApplicationIPNetworkEventHook() below). The address values passed in here + are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1 + but a DHCP server cannot be contacted. */ + FreeRTOS_debug_printf( ( "FreeRTOS_IPInit\n" ) ); + FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); + + /* A timer is used to periodically check the example tasks are functioning + as expected. First create the software timer ... */ + xCheckTimer = xTimerCreate( "Check", /* Text name used for debugging only. */ + pdMS_TO_TICKS( ulCheckTimerPeriod_ms ), + pdTRUE, /* This is an auto-reload timer. */ + NULL, /* Parameter not used. */ + prvCheckTimerCallback ); /* The timer callback function. */ + + /* ... assert if the timer was not created, ... */ + configASSERT( xCheckTimer ); + + /* ... then start the timer. */ + xTimerStart( xCheckTimer, 0 ); + + #if( ( mainCREATE_FTP_SERVER == 1 ) || ( mainCREATE_HTTP_SERVER == 1 ) ) + { + /* Create the task that handles the FTP and HTTP servers. This will + initialise the file system then wait for a notification from the network + event hook before creating the servers. The task is created at the idle + priority, and sets itself to mainTCP_SERVER_TASK_PRIORITY after the file + system has initialised. */ + xTaskCreate( prvServerWorkTask, "SvrWork", mainTCP_SERVER_STACK_SIZE, NULL, tskIDLE_PRIORITY, &xServerWorkTaskHandle ); + } + #endif + + /* Start the RTOS scheduler. */ + FreeRTOS_debug_printf( ("vTaskStartScheduler\n") ); + vTaskStartScheduler(); + + /* If all is well, the scheduler will now be running, and the following + line will never be reached. If the following line does execute, then + there was insufficient FreeRTOS heap memory available for the idle and/or + timer tasks to be created. See the memory management section on the + FreeRTOS web site for more details (this is standard text that is not not + really applicable to the Win32 simulator port). */ + for( ;; ) + { + Sleep( ulLongTime_ms ); + } +} +/*-----------------------------------------------------------*/ + +static void prvCreateDiskAndExampleFiles( void ) +{ +static uint8_t ucRAMDisk[ mainRAM_DISK_SECTORS * mainRAM_DISK_SECTOR_SIZE ]; +FF_Disk_t *pxDisk; + + /* Create the RAM disk. */ + pxDisk = FF_RAMDiskInit( mainRAM_DISK_NAME, ucRAMDisk, mainRAM_DISK_SECTORS, mainIO_MANAGER_CACHE_SIZE ); + configASSERT( pxDisk ); + + /* Print out information on the disk. */ + FF_RAMDiskShowPartition( pxDisk ); + + /* Create a few example files on the disk. These are not deleted again. */ + vCreateAndVerifyExampleFiles( mainRAM_DISK_NAME ); + + /* A few sanity checks only - can only be called after + vCreateAndVerifyExampleFiles(). */ + #if( mainRUN_STDIO_TESTS_IN_MULTIPLE_TASK == 1 ) + { + /* Note the stack size is not actually used in the Windows port. */ + vMultiTaskStdioWithCWDTest( mainRAM_DISK_NAME, configMINIMAL_STACK_SIZE * 2U ); + } + #else + { + vStdioWithCWDTest( mainRAM_DISK_NAME ); + } + #endif +} +/*-----------------------------------------------------------*/ + +#if( ( mainCREATE_FTP_SERVER == 1 ) || ( mainCREATE_HTTP_SERVER == 1 ) ) + + static void prvServerWorkTask( void *pvParameters ) + { + TCPServer_t *pxTCPServer = NULL; + const TickType_t xInitialBlockTime = pdMS_TO_TICKS( 200UL ); + + /* A structure that defines the servers to be created. Which servers are + included in the structure depends on the mainCREATE_HTTP_SERVER and + mainCREATE_FTP_SERVER settings at the top of this file. */ + static const struct xSERVER_CONFIG xServerConfiguration[] = + { + #if( mainCREATE_HTTP_SERVER == 1 ) + /* Server type, port number, backlog, root dir. */ + { eSERVER_HTTP, 80, 12, configHTTP_ROOT }, + #endif + + #if( mainCREATE_FTP_SERVER == 1 ) + /* Server type, port number, backlog, root dir. */ + { eSERVER_FTP, 21, 12, "" } + #endif + }; + + /* Remove compiler warning about unused parameter. */ + ( void ) pvParameters; + + /* Create the RAM disk used by the FTP and HTTP servers. */ + prvCreateDiskAndExampleFiles(); + + /* The priority of this task can be raised now the disk has been + initialised. */ + vTaskPrioritySet( NULL, mainTCP_SERVER_TASK_PRIORITY ); + + /* If the CLI is included in the build then register commands that allow + the file system to be accessed. */ + #if( ( mainCREATE_UDP_CLI_TASKS == 1 ) || ( mainCREATE_TCP_CLI_TASKS == 1 ) ) + { + vRegisterFileSystemCLICommands(); + } + #endif /* mainCREATE_UDP_CLI_TASKS */ + + + /* Wait until the network is up before creating the servers. The + notification is given from the network event hook. */ + ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); + + /* Create the servers defined by the xServerConfiguration array above. */ + pxTCPServer = FreeRTOS_CreateTCPServer( xServerConfiguration, sizeof( xServerConfiguration ) / sizeof( xServerConfiguration[ 0 ] ) ); + configASSERT( pxTCPServer ); + + for( ;; ) + { + FreeRTOS_TCPServerWork( pxTCPServer, xInitialBlockTime ); + } + } + +#endif /* ( ( mainCREATE_FTP_SERVER == 1 ) || ( mainCREATE_HTTP_SERVER == 1 ) ) */ +/*-----------------------------------------------------------*/ + +void vApplicationIdleHook( void ) +{ +const uint32_t ulMSToSleep = 1; + + /* This is just a trivial example of an idle hook. It is called on each + cycle of the idle task if configUSE_IDLE_HOOK is set to 1 in + FreeRTOSConfig.h. It must *NOT* attempt to block. In this case the + idle task just sleeps to lower the CPU usage. */ + Sleep( ulMSToSleep ); +} +/*-----------------------------------------------------------*/ + +void vAssertCalled( const char *pcFile, uint32_t ulLine ) +{ +const uint32_t ulLongSleep = 1000UL; +volatile uint32_t ulBlockVariable = 0UL; +volatile char *pcFileName = ( volatile char * ) pcFile; +volatile uint32_t ulLineNumber = ulLine; + + ( void ) pcFileName; + ( void ) ulLineNumber; + + FreeRTOS_printf( ( "vAssertCalled( %s, %ld\n", pcFile, ulLine ) ); + + /* Setting ulBlockVariable to a non-zero value in the debugger will allow + this function to be exited. */ + taskDISABLE_INTERRUPTS(); + { + while( ulBlockVariable == 0UL ) + { + Sleep( ulLongSleep ); + } + } + taskENABLE_INTERRUPTS(); +} +/*-----------------------------------------------------------*/ + +/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect +events are only received if implemented in the MAC driver. */ +void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) +{ +uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress; +char cBuffer[ 16 ]; +static BaseType_t xTasksAlreadyCreated = pdFALSE; + + /* If the network has just come up...*/ + if( eNetworkEvent == eNetworkUp ) + { + /* Create the tasks that use the IP stack if they have not already been + created. */ + if( xTasksAlreadyCreated == pdFALSE ) + { + /* See the comments above the definitions of these pre-processor + macros at the top of this file for a description of the individual + demo tasks. */ + #if( mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS == 1 ) + { + vStartSimpleUDPClientServerTasks( configMINIMAL_STACK_SIZE, mainSIMPLE_UDP_CLIENT_SERVER_PORT, mainSIMPLE_UDP_CLIENT_SERVER_TASK_PRIORITY ); + } + #endif /* mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS */ + + #if( mainCREATE_SELECT_UDP_SERVER_TASKS == 1 ) + { + vStartUDPSelectServerTasks( configMINIMAL_STACK_SIZE, mainUDP_SELECT_SERVER_PORT, mainUDP_SELECT_SERVER_TASK_PRIORITY ); + } + #endif /* mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS */ + + #if( mainCREATE_UDP_ECHO_TASKS == 1 ) + { + vStartUDPEchoClientTasks( mainECHO_CLIENT_TASK_STACK_SIZE, mainECHO_CLIENT_TASK_PRIORITY ); + } + #endif /* mainCREATE_UDP_ECHO_TASKS */ + + #if( mainCREATE_TCP_ECHO_TASKS_SINGLE == 1 ) + { + vStartTCPEchoClientTasks_SingleTasks( mainECHO_CLIENT_TASK_STACK_SIZE, mainECHO_CLIENT_TASK_PRIORITY ); + } + #endif /* mainCREATE_TCP_ECHO_TASKS_SINGLE */ + + #if( mainCREATE_TCP_ECHO_TASKS_SEPARATE == 1 ) + { + vStartTCPEchoClientTasks_SeparateTasks( mainECHO_CLIENT_TASK_STACK_SIZE, mainECHO_CLIENT_TASK_PRIORITY ); + } + #endif /* mainCREATE_TCP_ECHO_TASKS_SEPARATE */ + + #if( mainCREATE_TFTP_SERVER == 1 ) + { + vStartTFTPServerTask( mainTFTP_SERVER_STACK_SIZE, mainTFTP_SERVER_PRIORITY ); + } + #endif /* mainCREATE_TFTP_SERVER */ + + #if( mainCREATE_UDP_CLI_TASKS == 1 ) + { + /* Register example commands with the FreeRTOS+CLI command + interpreter via the UDP port specified by the + mainUDP_CLI_PORT_NUMBER constant. */ + vRegisterCLICommands(); + vStartUDPCommandInterpreterTask( configMINIMAL_STACK_SIZE, mainUDP_CLI_PORT_NUMBER, mainUDP_CLI_TASK_PRIORITY ); + } + #endif /* mainCREATE_UDP_CLI_TASKS */ + + #if( mainCREATE_TCP_CLI_TASKS == 1 ) + { + /* Register example commands with the FreeRTOS+CLI command + interpreter via the TCP port specified by the + mainTCP_CLI_PORT_NUMBER constant. */ + vRegisterCLICommands(); + vStartTCPCommandInterpreterTask( configMINIMAL_STACK_SIZE, mainTCP_CLI_PORT_NUMBER, mainTCP_CLI_TASK_PRIORITY ); + } + #endif /* mainCREATE_TCPP_CLI_TASKS */ + + #if( mainCREATE_SIMPLE_TCP_ECHO_SERVER == 1 ) + { + /* TCP server on port 5001, using multiple threads */ + vStartSimpleTCPServerTasks( configMINIMAL_STACK_SIZE, mainSIMPLE_UDP_CLIENT_SERVER_TASK_PRIORITY ); + } + #endif /* mainCREATE_SIMPLE_TCP_ECHO_SERVER */ + + #if( ( mainCREATE_FTP_SERVER == 1 ) || ( mainCREATE_HTTP_SERVER == 1 ) ) + { + /* See TBD. + Let the server work task now it can now create the servers. */ + xTaskNotifyGive( xServerWorkTaskHandle ); + } + #endif + + xTasksAlreadyCreated = pdTRUE; + } + + /* Print out the network configuration, which may have come from a DHCP + server. */ + FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress ); + FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); + FreeRTOS_printf( ( "\r\n\r\nIP Address: %s\r\n", cBuffer ) ); + + FreeRTOS_inet_ntoa( ulNetMask, cBuffer ); + FreeRTOS_printf( ( "Subnet Mask: %s\r\n", cBuffer ) ); + + FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer ); + FreeRTOS_printf( ( "Gateway Address: %s\r\n", cBuffer ) ); + + FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer ); + FreeRTOS_printf( ( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ) ); + } +} +/*-----------------------------------------------------------*/ + +/* Called automatically when a reply to an outgoing ping is received. */ +void vApplicationPingReplyHook( ePingReplyStatus_t eStatus, uint16_t usIdentifier ) +{ +static const char *pcSuccess = "Ping reply received - "; +static const char *pcInvalidChecksum = "Ping reply received with invalid checksum - "; +static const char *pcInvalidData = "Ping reply received with invalid data - "; + + switch( eStatus ) + { + case eSuccess : + FreeRTOS_printf( ( pcSuccess ) ); + break; + + case eInvalidChecksum : + FreeRTOS_printf( ( pcInvalidChecksum ) ); + break; + + case eInvalidData : + FreeRTOS_printf( ( pcInvalidData ) ); + break; + + default : + /* It is not possible to get here as all enums have their own + case. */ + break; + } + + FreeRTOS_printf( ( "identifier %d\r\n", ( int ) usIdentifier ) ); + + /* Prevent compiler warnings in case FreeRTOS_debug_printf() is not defined. */ + ( void ) usIdentifier; +} +/*-----------------------------------------------------------*/ + +void vApplicationMallocFailedHook( void ) +{ + /* Called if a call to pvPortMalloc() fails because there is insufficient + free memory available in the FreeRTOS heap. pvPortMalloc() is called + internally by FreeRTOS API functions that create tasks, queues, software + timers, and semaphores. The size of the FreeRTOS heap is set by the + configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */ + vAssertCalled( __FILE__, __LINE__ ); +} +/*-----------------------------------------------------------*/ + +static void prvCheckTimerCallback( TimerHandle_t xTimer ) +{ +static volatile uint32_t ulEchoClientErrors_Single = 0, ulEchoClientErrors_Separate = 0, ulEchoServerErrors = 0, ulUDPEchoClientErrors = 0, ulUDPSelectServerErrors = 0; + + ( void ) xTimer; + + /* Not all the demo tasks contain a check function yet - although an + assert() will be triggered if a task fails. */ + + #if( mainCREATE_TCP_ECHO_TASKS_SINGLE == 1 ) + { + if( xAreSingleTaskTCPEchoClientsStillRunning() != pdPASS ) + { + ulEchoClientErrors_Single++; + } + } + #endif + + #if( mainCREATE_TCP_ECHO_TASKS_SEPARATE == 1 ) + { + if( xAreSeparateTaskTCPEchoClientsStillRunning() != pdPASS ) + { + ulEchoClientErrors_Separate++; + } + } + #endif + + #if( mainCREATE_SIMPLE_TCP_ECHO_SERVER == 1 ) + { + if( xAreTCPEchoServersStillRunning() != pdPASS ) + { + ulEchoServerErrors++; + } + } + #endif + + #if( mainCREATE_UDP_ECHO_TASKS == 1 ) + { + if( xAreUDPEchoClientsStillRunning() != pdPASS ) + { + ulUDPEchoClientErrors++; + } + } + #endif + + #if( mainCREATE_SELECT_UDP_SERVER_TASKS == 1 ) + { + if( xAreUDPSelectTasksStillRunning() != pdPASS ) + { + ulUDPSelectServerErrors++; + } + } + #endif +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxRand( void ) +{ +const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL; + + /* Utility function to generate a pseudo random number. */ + + ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement; + return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL ); +} +/*-----------------------------------------------------------*/ + +static void prvSRand( UBaseType_t ulSeed ) +{ + /* Utility function to seed the pseudo random number generator. */ + ulNextRand = ulSeed; +} +/*-----------------------------------------------------------*/ + +static void prvMiscInitialisation( void ) +{ +time_t xTimeNow; +uint32_t ulLoggingIPAddress; + + ulLoggingIPAddress = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0, configECHO_SERVER_ADDR1, configECHO_SERVER_ADDR2, configECHO_SERVER_ADDR3 ); + vLoggingInit( mainLOG_TO_STDOUT, mainLOG_TO_DISK_FILE, mainLOG_TO_UDP, ulLoggingIPAddress, configPRINT_PORT ); + + /* Seed the random number generator. */ + time( &xTimeNow ); + FreeRTOS_debug_printf( ( "Seed for randomiser: %lu\n", xTimeNow ) ); + prvSRand( ( uint32_t ) xTimeNow ); + FreeRTOS_debug_printf( ( "Random numbers: %08X %08X %08X %08X\n", ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32(), ipconfigRAND32() ) ); +} +/*-----------------------------------------------------------*/ + +struct tm *gmtime_r( const time_t *pxTime, struct tm *tmStruct ) +{ + /* Dummy time functions to keep the file system happy in the absence of + target support. */ + memcpy( tmStruct, gmtime( pxTime ), sizeof( * tmStruct ) ); + return tmStruct; +} +/*-----------------------------------------------------------*/ + +time_t FreeRTOS_time( time_t *pxTime ) +{ +time_t xReturn; + + xReturn = time( &xReturn ); + + if( pxTime != NULL ) + { + *pxTime = xReturn; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +/* + * Callback that provides the inputs necessary to generate a randomized TCP + * Initial Sequence Number per RFC 6528. THIS IS ONLY A DUMMY IMPLEMENTATION + * THAT RETURNS A PSEUDO RANDOM NUMBER SO IS NOT INTENDED FOR USE IN PRODUCTION + * SYSTEMS. + */ +extern uint32_t ulApplicationGetNextSequenceNumber(uint32_t ulSourceAddress, + uint16_t usSourcePort, + uint32_t ulDestinationAddress, + uint16_t usDestinationPort) +{ + (void)ulSourceAddress; + (void)usSourcePort; + (void)ulDestinationAddress; + (void)usDestinationPort; + + return uxRand(); +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME != 0 ) + + const char *pcApplicationHostnameHook( void ) + { + /* Assign the name "FreeRTOS" to this network node. This function will + be called during the DHCP: the machine will be registered with an IP + address plus this name. */ + return mainHOST_NAME; + } + +#endif +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) + + BaseType_t xApplicationDNSQueryHook( const char *pcName ) + { + BaseType_t xReturn; + + /* Determine if a name lookup is for this node. Two names are given + to this node: that returned by pcApplicationHostnameHook() and that set + by mainDEVICE_NICK_NAME. */ + if( FF_stricmp( pcName, pcApplicationHostnameHook() ) == 0 ) + { + xReturn = pdPASS; + } + else if( FF_stricmp( pcName, mainDEVICE_NICK_NAME ) == 0 ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; + } + +#endif +/*-----------------------------------------------------------*/ + + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/printf-stdarg.c b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/printf-stdarg.c new file mode 100644 index 000000000..5505535c1 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/printf-stdarg.c @@ -0,0 +1,667 @@ +/* + Copyright 2001, 2002 Georges Menie (www.menie.org) + stdarg version contributed by Christian Ettinger + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Changes for the FreeRTOS ports: + + - The dot in "%-8.8s" + - The specifiers 'l' (long) and 'L' (long long) + - The specifier 'u' for unsigned + - Dot notation for IP addresses: + sprintf("IP = %xip\n", 0xC0A80164); + will produce "IP = 192.168.1.100\n" +*/ + +#include +#include +#include +#include + +#include "FreeRTOS.h" + +#define PAD_RIGHT 1 +#define PAD_ZERO 2 + +/* + * Return 1 for readable, 2 for writeable, 3 for both. + * Function must be provided by the application. + */ +extern BaseType_t xApplicationMemoryPermissions( uint32_t aAddress ); + +extern void vOutputChar( const char cChar, const TickType_t xTicksToWait ); +static const TickType_t xTicksToWait = pdMS_TO_TICKS( 20 ); + +struct xPrintFlags +{ + int base; + int width; + int printLimit; + unsigned + pad : 8, + letBase : 8, + isSigned : 1, + isNumber : 1, + long32 : 1, + long64 : 1; +}; + +struct SStringBuf +{ + char *str; + const char *orgStr; + const char *nulPos; + int curLen; + struct xPrintFlags flags; +}; + +static void strbuf_init( struct SStringBuf *apStr, char *apBuf, const char *apMaxStr ) +{ + apStr->str = apBuf; + apStr->orgStr = apBuf; + apStr->nulPos = apMaxStr-1; + apStr->curLen = 0; + + memset( &apStr->flags, '\0', sizeof( apStr->flags ) ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t strbuf_printchar( struct SStringBuf *apStr, int c ) +{ + if( apStr->str == NULL ) + { + vOutputChar( ( char ) c, xTicksToWait ); + apStr->curLen++; + return pdTRUE; + } + if( apStr->str < apStr->nulPos ) + { + *( apStr->str++ ) = c; + apStr->curLen++; + return pdTRUE; + } + if( apStr->str == apStr->nulPos ) + { + *( apStr->str++ ) = '\0'; + } + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static portINLINE BaseType_t strbuf_printchar_inline( struct SStringBuf *apStr, int c ) +{ + if( apStr->str == NULL ) + { + vOutputChar( ( char ) c, xTicksToWait ); + if( c == 0 ) + { + return pdFALSE; + } + apStr->curLen++; + return pdTRUE; + } + if( apStr->str < apStr->nulPos ) + { + *(apStr->str++) = c; + if( c == 0 ) + { + return pdFALSE; + } + apStr->curLen++; + return pdTRUE; + } + if( apStr->str == apStr->nulPos ) + { + *( apStr->str++ ) = '\0'; + } + return pdFALSE; +} +/*-----------------------------------------------------------*/ + +static portINLINE int i2hex( int aCh ) +{ +int iResult; + + if( aCh < 10 ) + { + iResult = '0' + aCh; + } + else + { + iResult = 'A' + aCh - 10; + } + + return iResult; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prints(struct SStringBuf *apBuf, const char *apString ) +{ + register int padchar = ' '; + int i,len; + + if( xApplicationMemoryPermissions( ( uint32_t )apString ) == 0 ) + { + /* The user has probably made a mistake with the parameter + for '%s', the memory is not readbale. */ + apString = "INV_MEM"; + } + + if( apBuf->flags.width > 0 ) + { + register int len = 0; + register const char *ptr; + for( ptr = apString; *ptr; ++ptr ) + { + ++len; + } + + if( len >= apBuf->flags.width ) + { + apBuf->flags.width = 0; + } + else + { + apBuf->flags.width -= len; + } + + if( apBuf->flags.pad & PAD_ZERO ) + { + padchar = '0'; + } + } + if( ( apBuf->flags.pad & PAD_RIGHT ) == 0 ) + { + for( ; apBuf->flags.width > 0; --apBuf->flags.width ) + { + if( strbuf_printchar( apBuf, padchar ) == 0 ) + { + return pdFALSE; + } + } + } + if( ( apBuf->flags.isNumber == pdTRUE ) && ( apBuf->flags.pad == pdTRUE ) ) + { + /* The string to print represents an integer number. + * In this case, printLimit is the min number of digits to print + * If the length of the number to print is less than the min nb of i + * digits to display, we add 0 before printing the number + */ + len = strlen( apString ); + + if( len < apBuf->flags.printLimit ) + { + i = apBuf->flags.printLimit - len; + for( ; i; i-- ) + { + if( strbuf_printchar( apBuf, '0' ) == 0 ) + { + return pdFALSE; + } + } + } + } + /* The string to print is not the result of a number conversion to ascii. + * For a string, printLimit is the max number of characters to display + */ + for( ; apBuf->flags.printLimit && *apString ; ++apString, --apBuf->flags.printLimit ) + { + if( !strbuf_printchar( apBuf, *apString ) ) + { + return pdFALSE; + } + } + + for( ; apBuf->flags.width > 0; --apBuf->flags.width ) + { + if( !strbuf_printchar( apBuf, padchar ) ) + { + return pdFALSE; + } + } + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +/* the following should be enough for 32 bit int */ +#define PRINT_BUF_LEN 12 /* to print 4294967296 */ + +#if SPRINTF_LONG_LONG +#warning 64-bit libraries will be included as well +static BaseType_t printll( struct SStringBuf *apBuf, long long i ) +{ + char print_buf[ 2 * PRINT_BUF_LEN ]; + register char *s; + register int t, neg = 0; + register unsigned long long u = i; + lldiv_t lldiv_result; + +/* typedef struct + * { + * long long int quot; // quotient + * long long int rem; // remainder + * } lldiv_t; + */ + + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + if( i == 0LL ) + { + print_buf[ 0 ] = '0'; + print_buf[ 1 ] = '\0'; + return prints( apBuf, print_buf ); + } + + if( ( apBuf->flags.isSigned == pdTRUE ) && ( apBuf->flags.base == 10 ) && ( i < 0LL ) ) + { + neg = 1; + u = -i; + } + + s = print_buf + sizeof( print_buf ) - 1; + + *s = '\0'; + /* 18446744073709551616 */ + while( u != 0 ) + { + lldiv_result = lldiv( u, ( unsigned long long ) apBuf->flags.base ); + t = lldiv_result.rem; + if( t >= 10 ) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u = lldiv_result.quot; + } + + if( neg != 0 ) + { + if( ( apBuf->flags.width != 0 ) && ( apBuf->flags.pad & PAD_ZERO ) ) + { + if( !strbuf_printchar( apBuf, '-' ) ) + { + return pdFALSE; + } + --apBuf->flags.width; + } + else + { + *( --s ) = '-'; + } + } + + return prints( apBuf, s ); +} +#endif /* SPRINTF_LONG_LONG */ +/*-----------------------------------------------------------*/ + +static BaseType_t printi( struct SStringBuf *apBuf, int i ) +{ + char print_buf[ PRINT_BUF_LEN ]; + register char *s; + register int t, neg = 0; + register unsigned int u = i; + register unsigned base = apBuf->flags.base; + + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + + if( i == 0 ) + { + print_buf[ 0 ] = '0'; + print_buf[ 1 ] = '\0'; + return prints( apBuf, print_buf ); + } + + if( ( apBuf->flags.isSigned == pdTRUE ) && ( base == 10 ) && ( i < 0 ) ) + { + neg = 1; + u = -i; + } + + s = print_buf + sizeof( print_buf ) - 1; + + *s = '\0'; + switch( base ) + { + case 16: + while( u != 0 ) + { + t = u & 0xF; + if( t >= 10 ) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u >>= 4; + } + break; + + case 8: + case 10: + /* GCC compiles very efficient */ + while( u ) + { + t = u % base; + *( --s ) = t + '0'; + u /= base; + } + break; +/* + // The generic case, not yet in use + default: + while( u ) + { + t = u % base; + if( t >= 10) + { + t += apBuf->flags.letBase - '0' - 10; + } + *( --s ) = t + '0'; + u /= base; + } + break; +*/ + } + + if( neg != 0 ) + { + if( apBuf->flags.width && (apBuf->flags.pad & PAD_ZERO ) ) + { + if( strbuf_printchar( apBuf, '-' ) == 0 ) + { + return pdFALSE; + } + --apBuf->flags.width; + } + else + { + *( --s ) = '-'; + } + } + + return prints( apBuf, s ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t printIp(struct SStringBuf *apBuf, unsigned i ) +{ + char print_buf[16]; + + sprintf( print_buf, "%u.%u.%u.%u", + i >> 24, + ( i >> 16 ) & 0xff, + ( i >> 8 ) & 0xff, + i & 0xff ); + apBuf->flags.isNumber = pdTRUE; /* Parameter for prints */ + prints( apBuf, print_buf ); + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +static void tiny_print( struct SStringBuf *apBuf, const char *format, va_list args ) +{ + char scr[2]; + + for( ; ; ) + { + int ch = *( format++ ); + + if( ch != '%' ) + { + do + { + /* Put the most like flow in a small loop */ + if( strbuf_printchar_inline( apBuf, ch ) == 0 ) + { + return; + } + ch = *( format++ ); + } while( ch != '%' ); + } + ch = *( format++ ); + /* Now ch has character after '%', format pointing to next */ + + if( ch == '\0' ) + { + break; + } + if( ch == '%' ) + { + if( strbuf_printchar( apBuf, ch ) == 0 ) + { + return; + } + continue; + } + memset( &apBuf->flags, '\0', sizeof( apBuf->flags ) ); + + if( ch == '-' ) + { + ch = *( format++ ); + apBuf->flags.pad = PAD_RIGHT; + } + while( ch == '0' ) + { + ch = *( format++ ); + apBuf->flags.pad |= PAD_ZERO; + } + if( ch == '*' ) + { + ch = *( format++ ); + apBuf->flags.width = va_arg( args, int ); + } + else + { + while( ch >= '0' && ch <= '9' ) + { + apBuf->flags.width *= 10; + apBuf->flags.width += ch - '0'; + ch = *( format++ ); + } + } + if( ch == '.' ) + { + ch = *( format++ ); + if( ch == '*' ) + { + apBuf->flags.printLimit = va_arg( args, int ); + ch = *( format++ ); + } + else + { + while( ch >= '0' && ch <= '9' ) + { + apBuf->flags.printLimit *= 10; + apBuf->flags.printLimit += ch - '0'; + ch = *( format++ ); + } + } + } + if( apBuf->flags.printLimit == 0 ) + { + apBuf->flags.printLimit--; /* -1: make it unlimited */ + } + if( ch == 's' ) + { + register char *s = ( char * )va_arg( args, int ); + if( prints( apBuf, s ? s : "(null)" ) == 0 ) + { + break; + } + continue; + } + if( ch == 'c' ) + { + /* char are converted to int then pushed on the stack */ + scr[0] = ( char ) va_arg( args, int ); + + if( strbuf_printchar( apBuf, scr[0] ) == 0 ) + { + return; + } + + continue; + } + if( ch == 'l' ) + { + ch = *( format++ ); + apBuf->flags.long32 = 1; + /* Makes not difference as u32 == long */ + } + if( ch == 'L' ) + { + ch = *( format++ ); + apBuf->flags.long64 = 1; + /* Does make a difference */ + } + apBuf->flags.base = 10; + apBuf->flags.letBase = 'a'; + + if( ch == 'd' || ch == 'u' ) + { + apBuf->flags.isSigned = ( ch == 'd' ); +#if SPRINTF_LONG_LONG + if( apBuf->flags.long64 != pdFALSE ) + { + if( printll( apBuf, va_arg( args, long long ) ) == 0 ) + { + break; + } + } else +#endif /* SPRINTF_LONG_LONG */ + if( printi( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + + apBuf->flags.base = 16; /* From here all hexadecimal */ + + if( ch == 'x' && format[0] == 'i' && format[1] == 'p' ) + { + format += 2; /* eat the "xi" of "xip" */ + /* Will use base 10 again */ + if( printIp( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + if( ch == 'x' || ch == 'X' || ch == 'p' || ch == 'o' ) + { + if( ch == 'X' ) + { + apBuf->flags.letBase = 'A'; + } + else if( ch == 'o' ) + { + apBuf->flags.base = 8; + } +#if SPRINTF_LONG_LONG + if( apBuf->flags.long64 != pdFALSE ) + { + if( printll( apBuf, va_arg( args, long long ) ) == 0 ) + { + break; + } + } else +#endif /* SPRINTF_LONG_LONG */ + if( printi( apBuf, va_arg( args, int ) ) == 0 ) + { + break; + } + continue; + } + } + strbuf_printchar( apBuf, '\0' ); +} +/*-----------------------------------------------------------*/ + +int vsnprintf( char *apBuf, size_t aMaxLen, const char *apFmt, va_list args ) +{ + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen ); + tiny_print( &strBuf, apFmt, args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int snprintf( char *apBuf, size_t aMaxLen, const char *apFmt, ... ) +{ + va_list args; + + va_start( args, apFmt ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* )apBuf + aMaxLen ); + tiny_print( &strBuf, apFmt, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int sprintf( char *apBuf, const char *apFmt, ... ) +{ + va_list args; + + va_start( args, apFmt ); + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char * )apBuf + 1024 ); + tiny_print( &strBuf, apFmt, args ); + va_end( args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +int vsprintf( char *apBuf, const char *apFmt, va_list args ) +{ + struct SStringBuf strBuf; + strbuf_init( &strBuf, apBuf, ( const char* ) apBuf + 1024 ); + tiny_print( &strBuf, apFmt, args ); + + return strBuf.curLen; +} +/*-----------------------------------------------------------*/ + +const char *mkSize (unsigned long long aSize, char *apBuf, int aLen) +{ +static char retString[33]; +size_t gb, mb, kb, sb; + + if (apBuf == NULL) { + apBuf = retString; + aLen = sizeof( retString ); + } + gb = aSize / (1024*1024*1024); + aSize -= gb * (1024*1024*1024); + mb = aSize / (1024*1024); + aSize -= mb * (1024*1024); + kb = aSize / (1024); + aSize -= kb * (1024); + sb = aSize; + if( gb ) + { + snprintf (apBuf, aLen, "%u.%02u GB", ( unsigned ) gb, ( unsigned ) ( ( 100 * mb ) / 1024ul ) ); + } + else if( mb ) + { + snprintf (apBuf, aLen, "%u.%02u MB", ( unsigned ) mb, ( unsigned ) ( ( 100 * kb) / 1024ul ) ); + } + else if( kb != 0ul ) + { + snprintf (apBuf, aLen, "%u.%02u KB", ( unsigned ) kb, ( unsigned ) ( ( 100 * sb) / 1024ul ) ); + } + else + { + snprintf (apBuf, aLen, "%u bytes", ( unsigned ) sb); + } + return apBuf; +} diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/trcConfig.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/trcConfig.h new file mode 100644 index 000000000..a5e508b58 --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/trcConfig.h @@ -0,0 +1,510 @@ +/******************************************************************************* + * Tracealyzer v2.4.1 Recorder Library + * Percepio AB, www.percepio.com + * + * trcConfig.h + * + * Configuration parameters for the trace recorder library. Before using the + * trace recorder library, please check that the default settings are + * appropriate for your system, and if necessary adjust these. Most likely, you + * will need to adjust the NTask, NISR, NQueue, NMutex and NSemaphore values to + * reflect the number of such objects in your system. These may be + * over-approximated, although larger values values implies more RAM usage. + * + * Terms of Use + * This software is copyright Percepio AB. The recorder library is free for + * use together with Percepio products. You may distribute the recorder library + * in its original form, including modifications in trcHardwarePort.c/.h + * given that these modification are clearly marked as your own modifications + * and documented in the initial comment section of these source files. + * This software is the intellectual property of Percepio AB and may not be + * sold or in other ways commercially redistributed without explicit written + * permission by Percepio AB. + * + * Disclaimer + * The trace tool and recorder library is being delivered to you AS IS and + * Percepio AB makes no warranty as to its use or performance. Percepio AB does + * not and cannot warrant the performance or results you may obtain by using the + * software or documentation. Percepio AB make no warranties, express or + * implied, as to noninfringement of third party rights, merchantability, or + * fitness for any particular purpose. In no event will Percepio AB, its + * technology partners, or distributors be liable to you for any consequential, + * incidental or special damages, including any lost profits or lost savings, + * even if a representative of Percepio AB has been advised of the possibility + * of such damages, or for any claim by any third party. Some jurisdictions do + * not allow the exclusion or limitation of incidental, consequential or special + * damages, or the exclusion of implied warranties or limitations on how long an + * implied warranty may last, so the above limitations may not apply to you. + * + * Copyright Percepio AB, 2013. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRCCONFIG_H +#define TRCCONFIG_H + +#include + +/******************************************************************************* + * CONFIGURATION RELATED TO CAPACITY AND ALLOCATION + ******************************************************************************/ + +/******************************************************************************* + * EVENT_BUFFER_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the event buffer, i.e., the number of records + * it may store. Each registered event typically use one record (4 byte), but + * vTracePrintF may use multiple records depending on the number of data args. + ******************************************************************************/ + +#define EVENT_BUFFER_SIZE 100000 /* Adjust wrt. to available RAM */ + + +/******************************************************************************* + * USE_LINKER_PRAGMA + * + * Macro which should be defined as an integer value, default is 0. + * + * If this is 1, the header file "recorderdata_linker_pragma.h" is included just + * before the declaration of RecorderData (in trcBase.c), i.e., the trace data + * structure. This allows the user to specify a pragma with linker options. + * + * Example (for IAR Embedded Workbench and NXP LPC17xx): + * #pragma location="AHB_RAM_MEMORY" + * + * This example instructs the IAR linker to place RecorderData in another RAM + * bank, the AHB RAM. This can also be used for other compilers with a similar + * pragmas for linker options. + * + * Note that this only applies if using static allocation, see below. + ******************************************************************************/ + +#define USE_LINKER_PRAGMA 0 + + +/******************************************************************************* + * SYMBOL_TABLE_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the symbol table, in bytes. This symbol table + * stores User Events labels and names of deleted tasks, queues, or other kernel + * objects. Note that the names of active objects not stored here but in the + * Object Table. Thus, if you don't use User Events or delete any kernel + * objects you set this to zero (0) to minimize RAM usage. + ******************************************************************************/ +#define SYMBOL_TABLE_SIZE 5000 + +/******************************************************************************* + * USE_SEPARATE_USER_EVENT_BUFFER + * + * Macro which should be defined as an integer value. + * Default is zero (0). + * + * This enables and disables the use of the separate user event buffer. + * + * Note: When using the separate user event buffer, you may get an artificial + * task instance named "Unknown actor". This is added as a placeholder when the + * user event history is longer than the task scheduling history. + ******************************************************************************/ +#define USE_SEPARATE_USER_EVENT_BUFFER 0 + +/******************************************************************************* + * USER_EVENT_BUFFER_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the user event buffer, in number of slots. + * A single user event can use between 1 and X slots, depending on the data. + * + * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. + ******************************************************************************/ +#define USER_EVENT_BUFFER_SIZE 500 + +/******************************************************************************* + * USER_EVENT_CHANNELS + * + * Macro which should be defined as an integer value. + * + * This defines the number of allowed user event channels. + * + * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. + ******************************************************************************/ +#define CHANNEL_FORMAT_PAIRS 32 + +/******************************************************************************* + * NTask, NISR, NQueue, NSemaphore, NMutex + * + * A group of Macros which should be defined as an integer value of zero (0) + * or larger. + * + * This defines the capacity of the Object Property Table - the maximum number + * of objects active at any given point within each object class. + * + * NOTE: In case objects are deleted and created during runtime, this setting + * does not limit the total amount of objects, only the number of concurrently + * active objects. + * + * Using too small values will give an error message through the vTraceError + * routine, which makes the error message appear when opening the trace data + * in Tracealyzer. If you are using the recorder status monitor task, + * any error messages are displayed in console prints, assuming that the + * print macro has been defined properly (vConsolePrintMessage). + * + * It can be wise to start with very large values for these constants, + * unless you are very confident on these numbers. Then do a recording and + * check the actual usage in Tracealyzer. This is shown by selecting + * View -> Trace Details -> Resource Usage -> Object Table + * + * NOTE 2: Remember to account for all tasks created by the kernel, such as the + * IDLE task, timer task, and any tasks created by other 3rd party + * software components, such as communication stacks. The recorder also has an + * optional monitor task to account for, if this is used. + * Moreover, one task slot is used to indicate "(startup)", i.e., a fictive + * task that represent the time before the scheduler starts. + * NTask should thus be at least 2-3 slots larger than your application task count. + * + ******************************************************************************/ +#define NTask 100 +#define NISR 60 +#define NQueue 60 +#define NSemaphore 60 +#define NMutex 60 + +/* Maximum object name length for each class (includes zero termination) */ +#define NameLenTask 15 +#define NameLenISR 15 +#define NameLenQueue 15 +#define NameLenSemaphore 15 +#define NameLenMutex 15 + +/****************************************************************************** + * TRACE_DESCRIPTION + * + * Macro which should be defined as a string. + * + * This string is stored in the trace and displayed in Tracealyzer. Can be + * used to store, e.g., system version or build date. This is also used to store + * internal error messages from the recorder, which if occurs overwrites the + * value defined here. This may be maximum 256 chars. + *****************************************************************************/ +#define TRACE_DESCRIPTION "Tracealyzer Recorder Test Program" + +/****************************************************************************** + * TRACE_DESCRIPTION_MAX_LENGTH + * + * The maximum length (including zero termination) for the TRACE_DESCRIPTION + * string. Since this string also is used for internal error messages from the + * recorder do not make it too short, as this may truncate the error messages. + * Default is 80. + * Maximum allowed length is 256 - the trace will fail to load if longer. + *****************************************************************************/ +#define TRACE_DESCRIPTION_MAX_LENGTH 80 + + +/****************************************************************************** + * TRACE_DATA_ALLOCATION + * + * This defines how to allocate the recorder data structure, i.e., using a + * static declaration or using a dynamic allocation in runtime (malloc). + * + * Should be one of these two options: + * - TRACE_DATA_ALLOCATION_STATIC (default) + * - TRACE_DATA_ALLOCATION_DYNAMIC + * + * Using static allocation has the benefits of compile-time errors if the buffer + * is too large (too large constants in trcConfig.h) and no need to call the + * initialization routine (xTraceInitTraceData). + * + * Using dynamic allocation may give more flexibility in some cases. + *****************************************************************************/ + +#define TRACE_DATA_ALLOCATION TRACE_DATA_ALLOCATION_STATIC + + +/****************************************************************************** + * CONFIGURATION REGARDING WHAT CODE/FEATURES TO INCLUDE + *****************************************************************************/ + +/****************************************************************************** + * USE_TRACE_ASSERT + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 0. + * + * If this is one (1), the TRACE_ASSERT macro will verify that a condition is + * true. If the condition is false, vTraceError() will be called. + *****************************************************************************/ +#define USE_TRACE_ASSERT 1 + +/****************************************************************************** + * INCLUDE_FLOAT_SUPPORT + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * If this is zero (0), all references to floating point values are removed, + * in case floating point values are not supported by the platform used. + * Floating point values are only used in vTracePrintF and its subroutines, to + * store float (%f) or double (%lf) argments. + * + * Note: vTracePrintF can still be used with integer and string arguments in + * either case. + *****************************************************************************/ +#define INCLUDE_FLOAT_SUPPORT 0 + +/****************************************************************************** + * INCLUDE_USER_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * If this is zero (0) the code for creating User Events is excluded to + * reduce code size. User Events are application-generated events, like + * "printf" but for the trace log instead of console output. User Events are + * much faster than a printf and can therefore be used in timing critical code. + * See vTraceUserEvent() and vTracePrintF() in trcUser.h + * + * Note that Tracealyzer Standard Edition or Professional Edition is required + * for User Events, they are not displayed in Tracealyzer Free Edition. + *****************************************************************************/ +#define INCLUDE_USER_EVENTS 1 + +/***************************************************************************** + * INCLUDE_READY_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * If this is zero (0), the code for recording Ready events is + * excluded. Note, this will make it impossible to calculate the correct + * response times. + *****************************************************************************/ +#define INCLUDE_READY_EVENTS 1 + +/***************************************************************************** + * INCLUDE_NEW_TIME_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 0. + * + * If this is zero (1), events will be generated whenever the os clock is + * increased. + *****************************************************************************/ +#define INCLUDE_NEW_TIME_EVENTS 0 + +/***************************************************************************** + * INCLUDE_ISR_TRACING + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * If this is zero (0), the code for recording Interrupt Service Routines is + * excluded to reduce code size. + * + * Note, if the kernel has no central interrupt dispatcher, recording ISRs + * require that you insert calls to vTraceStoreISRBegin and vTraceStoreISREnd + * in your interrupt handlers. + *****************************************************************************/ +#define INCLUDE_ISR_TRACING 1 + +/****************************************************************************** + * INCLUDE_OBJECT_DELETE + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * This must be enabled (1) if tasks, queues or other + * traced kernel objects are deleted at runtime. If no deletes are made, this + * can be set to 0 in order to exclude the delete-handling code. + *****************************************************************************/ +#define INCLUDE_OBJECT_DELETE 0 + +/****************************************************************************** + * CONFIGURATION RELATED TO BEHAVIOR + *****************************************************************************/ + +/****************************************************************************** + * TRACE_RECORDER_STORE_MODE + * + * Macro which should be defined as one of: + * - TRACE_STORE_MODE_RING_BUFFER + * - TRACE_STORE_MODE_STOP_WHEN_FULL + * Default is TRACE_STORE_MODE_RING_BUFFER. + * + * With TRACE_RECORDER_STORE_MODE set to TRACE_STORE_MODE_RING_BUFFER, the events are + * stored in a ring buffer, i.e., where the oldest events are overwritten when + * the buffer becomes full. This allows you to get the last events leading up + * to an interesting state, e.g., an error, without having a large trace buffer + * for string the whole run since startup. In this mode, the recorder can run + * "forever" as the buffer never gets full, i.e., in the sense that it always + * has room for more events. + * + * To fetch the trace in mode TRACE_STORE_MODE_RING_BUFFER, you need to first halt the + * system using your debugger and then do a RAM dump, or to explicitly stop the + * recorder using vTraceStop() and then store/upload the trace data using a + * task that you need to provide yourself. The trace data is found in the struct + * RecorderData, initialized in trcBase.c. + * + * Note that, if you upload the trace using a RAM dump, i.e., when the system is + * halted on a breakpoint or by a debugger command, there is no need to stop the + * recorder first. + * + * When TRACE_RECORDER_STORE_MODE is TRACE_STORE_MODE_STOP_WHEN_FULL, the recording is + * stopped when the buffer becomes full. When the recorder stops itself this way + * vTracePortEnd() is called which allows for custom actions, such as triggering + * a task that stores the trace buffer, i.e., in case taking a RAM dump + * using an on-chip debugger is not possible. In the Windows port, vTracePortEnd + * saves the trace to file directly, but this is not recommended in a real-time + * system since the scheduler is blocked during the processing of vTracePortEnd. + *****************************************************************************/ + +#define TRACE_RECORDER_STORE_MODE TRACE_STORE_MODE_RING_BUFFER + +/****************************************************************************** + * STOP_AFTER_N_EVENTS + * + * Macro which should be defined as an integer value, or not defined. + * Default is -1 + * + * STOP_AFTER_N_EVENTS is intended for tests of the ring buffer mode (when + * RECORDER_STORE_MODE is STORE_MODE_RING_BUFFER). It stops the recording when + * the specified number of events has been observed. This value can be larger + * than the buffer size, to allow for test of the "wrapping around" that occurs + * in ring buffer mode . A negative value (or no definition of this macro) + * disables this feature. + *****************************************************************************/ +#define STOP_AFTER_N_EVENTS -1 + +/****************************************************************************** + * USE_IMPLICIT_IFE_RULES + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * ### Instance Finish Events (IFE) ### + * + * For tasks with "infinite" main loops (non-terminating tasks), the concept + * of a task instance has no clear definition, it is an application-specific + * thing. Tracealyzer allows you to define Instance Finish Events (IFEs), + * which marks the point in a cyclic task when the "task instance" ends. + * The IFE is a blocking kernel call, typically in the main loop of a task + * which typically reads a message queue, waits for a semaphore or performs + * an explicit delay. + * + * If USE_IMPLICIT_IFE_RULES is one (1), the kernel macros (trcKernelPort.h) + * will define what kernel calls are considered by default to be IFEs. + * + * However, Implicit IFEs only applies to blocking kernel calls. If a + * service reads a message without blocking, it does not create a new + * instance since no blocking occurred. + * + * Moreover, the actual IFE might sometimes be another blocking call. We + * therefore allow for user-defined Explicit IFEs by calling + * + * vTraceTaskInstanceIsFinished() + * + * right before the kernel call considered as IFE. This does not create an + * additional event but instead stores the service code and object handle + * of the IFE call as properties of the task. + * + * If using Explicit IFEs and the task also calls an Implicit IFE, this may + * result in additional incorrect task instances. + * This is solved by disabling the Implicit IFEs for the task, by adding + * a call to + * + * vTraceTaskSkipDefaultInstanceFinishedEvents() + * + * in the very beginning of that task. This allows you to combine Explicit IFEs + * for some tasks with Implicit IFEs for the rest of the tasks, if + * USE_IMPLICIT_IFE_RULES is 1. + * + * By setting USE_IMPLICIT_IFE_RULES to zero (0), the implicit IFEs are disabled + * for all tasks. Tasks will then be considered to have a single instance only, + * covering all execution fragments, unless you define an explicit IFE in each + * task by calling vTraceTaskInstanceIsFinished before the blocking call. + *****************************************************************************/ +#define USE_IMPLICIT_IFE_RULES 1 + +/****************************************************************************** + * INCLUDE_SAVE_TO_FILE + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 0. + * + * If enabled (1), the recorder will include code for saving the trace + * to a local file system. + ******************************************************************************/ +#ifdef WIN32 + #define INCLUDE_SAVE_TO_FILE 1 +#else + #define INCLUDE_SAVE_TO_FILE 0 +#endif + +/****************************************************************************** + * TRACE_PROGRESS_MONITOR_TASK_PRIORITY + * + * Macro which sets the priority of the "recorder status monitor" task. + * + * This task, vTraceMonitorTask in trcUser.c, periodically writes + * the recorder status using the vTraceConsoleMessage macro, which is to + * be mapped to your console "printf" routine. The task is named TraceMon but + * is intentionally excluded from the demo trace. + * + * Default is tskIDLE_PRIORITY + 1 + * Note that if your system constantly has a high CPU load from high-priority + * tasks, this might not be get a chance to execute. + * + * See vTraceMonitorTask in trcUser.c + *****************************************************************************/ +#define TRACE_PROGRESS_MONITOR_TASK_PRIORITY (tskIDLE_PRIORITY + 1) + +/****************************************************************************** + * TRACE_PROGRESS_MONITOR_TASK_STACKSIZE + * + * Macro which sets the stack size of the "recorder status monitor" task. + * + * This task, vTraceMonitorTask in trcUser.c, periodically writes + * the recorder status using the vTraceConsoleMessage macro, which is to + * be mapped to your console "printf" routine. The task is intentionally + * excluded from the demo trace. + * + * See vTraceMonitorTask in trcUser.c + *****************************************************************************/ +#define TRACE_PROGRESS_MONITOR_TASK_STACKSIZE 500 + +/****************************************************************************** + * TRACE_PROGRESS_MONITOR_TASK_PERIOD + * + * Macro which sets the period of the "recorder status monitor" task. + * + * This task, vTraceMonitorTask in trcUser.c, periodically writes + * the recorder status using the vTraceConsoleMessage macro, which is to + * be mapped to your console "printf" routine. The task is named TraceMon but + * is intentionally excluded from the demo trace. + * + * Default is 1000 ticks (typically 1 second). On the Windows port, a lower + * value is suggested since the Windows port runs very slowly, often 20-40 + * times slower than the simulated time. + * + * See vTraceMonitorTask in trcUser.c + *****************************************************************************/ +#ifdef WIN32 + #define TRACE_PROGRESS_MONITOR_TASK_PERIOD 100 +#else + #define TRACE_PROGRESS_MONITOR_TASK_PERIOD 1000 +#endif + +/****************************************************************************** + * TEAM_LICENSE_CODE + * + * Macro which defines a string - the team license code. + * If no team license is available, this should be an empty string "". + * This should be maximum 32 chars, including zero-termination. + *****************************************************************************/ +#define TEAM_LICENSE_CODE "" + +#endif + diff --git a/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/trcHardwarePort.h b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/trcHardwarePort.h new file mode 100644 index 000000000..c324445ff --- /dev/null +++ b/FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator/trcHardwarePort.h @@ -0,0 +1,474 @@ +/******************************************************************************* + * Tracealyzer v2.4.1 Recorder Library + * Percepio AB, www.percepio.com + * + * trcHardwarePort.h + * + * Contains together with trcHardwarePort.c all hardware portability issues of + * the trace recorder library. + * + * Terms of Use + * This software is copyright Percepio AB. The recorder library is free for + * use together with Percepio products. You may distribute the recorder library + * in its original form, including modifications in trcPort.c and trcPort.h + * given that these modification are clearly marked as your own modifications + * and documented in the initial comment section of these source files. + * This software is the intellectual property of Percepio AB and may not be + * sold or in other ways commercially redistributed without explicit written + * permission by Percepio AB. + * + * Disclaimer + * The trace tool and recorder library is being delivered to you AS IS and + * Percepio AB makes no warranty as to its use or performance. Percepio AB does + * not and cannot warrant the performance or results you may obtain by using the + * software or documentation. Percepio AB make no warranties, express or + * implied, as to noninfringement of third party rights, merchantability, or + * fitness for any particular purpose. In no event will Percepio AB, its + * technology partners, or distributors be liable to you for any consequential, + * incidental or special damages, including any lost profits or lost savings, + * even if a representative of Percepio AB has been advised of the possibility + * of such damages, or for any claim by any third party. Some jurisdictions do + * not allow the exclusion or limitation of incidental, consequential or special + * damages, or the exclusion of implied warranties or limitations on how long an + * implied warranty may last, so the above limitations may not apply to you. + * + * Copyright Percepio AB, 2013. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRCPORT_H +#define TRCPORT_H + +#include "trcKernelPort.h" + +/* If Win32 port */ +#ifdef WIN32 + + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0600 + + /* Standard includes. */ + #include + #include + #include + +/******************************************************************************* + * The Win32 port by default saves the trace to file and then kills the + * program when the recorder is stopped, to facilitate quick, simple tests + * of the recorder. + ******************************************************************************/ + #define WIN32_PORT_SAVE_WHEN_STOPPED 1 + #define WIN32_PORT_EXIT_WHEN_STOPPED 1 + +#endif + +#define DIRECTION_INCREMENTING 1 +#define DIRECTION_DECREMENTING 2 + +/****************************************************************************** + * Supported ports + * + * PORT_HWIndependent + * A hardware independent fallback option for event timestamping. Provides low + * resolution timestamps based on the OS tick. + * This may be used on the Win32 port, but may also be used on embedded hardware + * platforms. All time durations will be truncated to the OS tick frequency, + * typically 1 KHz. This means that a task or ISR that executes in less than + * 1 ms get an execution time of zero. + * + * PORT_Win32 + * "Accurate" timestamping based on the Windows performance counter. Note that + * this gives the host machine time. + * + * Officially supported hardware timer ports: + * - PORT_Atmel_AT91SAM7 + * - PORT_Atmel_UC3A0 + * - PORT_ARM_CortexM + * - PORT_Renesas_RX600 + * - PORT_Microchip_dsPIC_AND_PIC24 + * + * We also provide several "unofficial" hardware-specific ports. There have + * been developed by external contributors, and have not yet been verified + * by Percepio AB. Let us know if you have problems getting these to work. + * + * Unofficial hardware specific ports provided are: + * - PORT_TEXAS_INSTRUMENTS_TMS570 + * - PORT_TEXAS_INSTRUMENTS_MSP430 + * - PORT_MICROCHIP_PIC32 + * - PORT_XILINX_PPC405 + * - PORT_XILINX_PPC440 + * - PORT_XILINX_MICROBLAZE + * - PORT_NXP_LPC210X + * + *****************************************************************************/ + +#define PORT_NOT_SET -1 + +/*** Officially supported hardware timer ports *******************************/ +#define PORT_HWIndependent 0 +#define PORT_Win32 1 +#define PORT_Atmel_AT91SAM7 2 +#define PORT_Atmel_UC3A0 3 +#define PORT_ARM_CortexM 4 +#define PORT_Renesas_RX600 5 +#define PORT_Microchip_dsPIC_AND_PIC24 6 + +/*** Unofficial ports, provided by external developers, not yet verified *****/ +#define PORT_TEXAS_INSTRUMENTS_TMS570 7 +#define PORT_TEXAS_INSTRUMENTS_MSP430 8 +#define PORT_MICROCHIP_PIC32 9 +#define PORT_XILINX_PPC405 10 +#define PORT_XILINX_PPC440 11 +#define PORT_XILINX_MICROBLAZE 12 +#define PORT_NXP_LPC210X 13 + +/*** Select your port here! **************************************************/ +#define SELECTED_PORT PORT_Win32 +/*****************************************************************************/ + +#if (SELECTED_PORT == PORT_NOT_SET) +#error "You need to define SELECTED_PORT here!" +#endif + +/******************************************************************************* + * IRQ_PRIORITY_ORDER + * + * Macro which should be defined as an integer of 0 or 1. + * + * This should be 0 if lower IRQ priority values implies higher priority + * levels, such as on ARM Cortex M. If the opposite scheme is used, i.e., + * if higher IRQ priority values means higher priority, this should be 1. + * + * This setting is not critical. It is used only to sort and colorize the + * interrupts in priority order, in case you record interrupts using + * the vTraceStoreISRBegin and vTraceStoreISREnd routines. + * + * We provide this setting for some hardware architectures below: + * - ARM Cortex M: 0 (lower IRQ priority values are more significant) + * - Atmel AT91SAM7x: 1 (higher IRQ priority values are more significant) + * - Atmel AVR32: 1 (higher IRQ priority values are more significant) + * - Renesas RX600: 1 (higher IRQ priority values are more significant) + * - Microchip PIC24: 0 (lower IRQ priority values are more significant) + * - Microchip dsPIC: 0 (lower IRQ priority values are more significant) + * - TI TMS570: 0 (lower IRQ priority values are more significant) + * - Freescale HCS08: 0 (lower IRQ priority values are more significant) + * - Freescale HCS12: 0 (lower IRQ priority values are more significant) + * - PowerPC 405: 0 (lower IRQ priority values are more significant) + * - PowerPC 440: 0 (lower IRQ priority values are more significant) + * - Freescale ColdFire: 1 (higher IRQ priority values are more significant) + * - NXP LPC210x: 0 (lower IRQ priority values are more significant) + * - MicroBlaze: 0 (lower IRQ priority values are more significant) + * + * If your chip is not on the above list, and you perhaps know this detail by + * heart, please inform us by e-mail to support@percepio.com. + * + ****************************************************************************** + * + * HWTC Macros + * + * These four HWTC macros provides a hardware isolation layer representing a + * generic hardware timer/counter used for driving the operating system tick, + * such as the SysTick feature of ARM Cortex M3/M4, or the PIT of the Atmel + * AT91SAM7X. + * + * HWTC_COUNT: The current value of the counter. This is expected to be reset + * a each tick interrupt. Thus, when the tick handler starts, the counter has + * already wrapped. + * + * HWTC_COUNT_DIRECTION: Should be one of: + * - DIRECTION_INCREMENTING - for hardware timer/counters of incrementing type + * such as the PIT on Atmel AT91SAM7X. + * When the counter value reach HWTC_PERIOD, it is reset to zero and the + * interrupt is signaled. + * - DIRECTION_DECREMENTING - for hardware timer/counters of decrementing type + * such as the SysTick on ARM Cortex M3/M4 chips. + * When the counter value reach 0, it is reset to HWTC_PERIOD and the + * interrupt is signaled. + * + * HWTC_PERIOD: The number of increments or decrements of HWTC_COUNT between + * two tick interrupts. This should preferably be mapped to the reload + * register of the hardware timer, to make it more portable between chips in the + * same family. The macro should in most cases be (reload register + 1). + * + * HWTC_DIVISOR: If the timer frequency is very high, like on the Cortex M chips + * (where the SysTick runs at the core clock frequency), the "differential + * timestamping" used in the recorder will more frequently insert extra XTS + * events to store the timestamps, which increases the event buffer usage. + * In such cases, to reduce the number of XTS events and thereby get longer + * traces, you use HWTC_DIVISOR to scale down the timestamps and frequency. + * Assuming a OS tick rate of 1 KHz, it is suggested to keep the effective timer + * frequency below 65 MHz to avoid an excessive amount of XTS events. Thus, a + * Cortex M chip running at 72 MHZ should use a HWTC_DIVISOR of 2, while a + * faster chip require a higher HWTC_DIVISOR value. + * + * The HWTC macros and vTracePortGetTimeStamp is the main porting issue + * or the trace recorder library. Typically you should not need to change + * the code of vTracePortGetTimeStamp if using the HWTC macros. + * + ******************************************************************************/ + +#if (SELECTED_PORT == PORT_Win32) + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (ulGetRunTimeCounterValue()) + #define HWTC_PERIOD 0 + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 1 // Please update according to your hardware... + +#elif (SELECTED_PORT == PORT_HWIndependent) + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT 0 + #define HWTC_PERIOD 1 + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 1 // Please update according to your hardware... + +#elif (SELECTED_PORT == PORT_Atmel_AT91SAM7) + + /* HWTC_PERIOD is hardcoded for AT91SAM7X256-EK Board (48 MHz) + A more generic solution is to get the period from pxPIT->PITC_PIMR */ + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (AT91C_BASE_PITC->PITC_PIIR & 0xFFFFF) + #define HWTC_PERIOD 2995 + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant + +#elif (SELECTED_PORT == PORT_Atmel_UC3A0) + + /* For Atmel AVR32 (AT32UC3A) */ + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT sysreg_read(AVR32_COUNT) + #define HWTC_PERIOD ( TRACE_CPU_CLOCK_HZ / TRACE_TICK_RATE_HZ ) + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant + +#elif (SELECTED_PORT == PORT_ARM_CortexM) + + /* For all chips using ARM Cortex M cores */ + + #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING + #define HWTC_COUNT (*((uint32_t*)0xE000E018)) + #define HWTC_PERIOD ((*(uint32_t*)0xE000E014) + 1) + #define HWTC_DIVISOR 2 + + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + +#elif (SELECTED_PORT == PORT_Renesas_RX600) + + #include "iodefine.h" + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (CMT0.CMCNT) + #define HWTC_PERIOD ((((TRACE_PERIPHERAL_CLOCK_HZ/TRACE_TICK_RATE_HZ)-1)/8)) + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant + +#elif (SELECTED_PORT == PORT_Microchip_dsPIC_AND_PIC24) + + /* For Microchip PIC24 and dsPIC (16 bit) */ + + /* Note: The trace library was originally designed for 32-bit MCUs, and is slower + than intended on 16-bit MCUs. Storing an event on a PIC24 takes about 70 µs. + In comparison, 32-bit MCUs are often 10-20 times faster. If recording overhead + becomes a problem on PIC24, use the filters to exclude less interesting tasks + or system calls. */ + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (TMR1) + #define HWTC_PERIOD (PR1+1) + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + +#elif (SELECTED_PORT == PORT_NXP_LPC210X) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + /* Tested with LPC2106, but should work with most LPC21XX chips. */ + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT *((uint32_t *)0xE0004008 ) + #define HWTC_PERIOD ( TRACE_CPU_CLOCK_HZ / TRACE_TICK_RATE_HZ ) + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + +#elif (SELECTED_PORT == PORT_TEXAS_INSTRUMENTS_TMS570) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + #define RTIFRC0 *((uint32_t *)0xFFFFFC10) + #define RTICOMP0 *((uint32_t *)0xFFFFFC50) + #define RTIUDCP0 *((uint32_t *)0xFFFFFC54) + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (RTIFRC0 - (RTICOMP0 - RTIUDCP0)) + #define HWTC_PERIOD (RTIUDCP0) + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + +#elif (SELECTED_PORT == PORT_TEXAS_INSTRUMENTS_MSP430) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (TA0R) + #define HWTC_PERIOD TRACE_CPU_CLOCKS_PER_TICK + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant + +#elif (SELECTED_PORT == PORT_MICROCHIP_PIC32) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING + #define HWTC_COUNT (ReadTimer1()) /* Should be available in BSP */ + #define HWTC_PERIOD (ReadPeriod1()+1) /* Should be available in BSP */ + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + +#elif (SELECTED_PORT == PORT_XILINX_PPC405) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING + #define HWTC_COUNT mfspr( 0x3db) + #define HWTC_PERIOD ( TRACE_CPU_CLOCK_HZ / TRACE_TICK_RATE_HZ ) + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + +#elif (SELECTED_PORT == PORT_XILINX_PPC440) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + /* This should work with most PowerPC chips */ + + #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING + #define HWTC_COUNT mfspr( 0x016 ) + #define HWTC_PERIOD ( TRACE_CPU_CLOCK_HZ / TRACE_TICK_RATE_HZ ) + #define HWTC_DIVISOR 1 + + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + +#elif (SELECTED_PORT == PORT_XILINX_MICROBLAZE) + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + /* This should work with most Microblaze configurations. + * It uses the AXI Timer 0 - the tick interrupt source. + * If an AXI Timer 0 peripheral is available on your hardware platform, no modifications are required. + */ + #include "xtmrctr_l.h" + + #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING + #define HWTC_COUNT XTmrCtr_GetTimerCounterReg( XPAR_TMRCTR_0_BASEADDR, 0 ) + #define HWTC_PERIOD ( TRACE_CPU_CLOCK_HZ / TRACE_TICK_RATE_HZ ) + #define HWTC_DIVISOR 16 + + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant + +#elif (SELECTED_PORT != PORT_NOT_SET) + + #error "SELECTED_PORT had unsupported value!" + #define SELECTED_PORT PORT_NOT_SET + +#endif + +#if (SELECTED_PORT != PORT_NOT_SET) + + #ifndef HWTC_COUNT_DIRECTION + #error "HWTC_COUNT_DIRECTION is not set!" + #endif + + #ifndef HWTC_COUNT + #error "HWTC_COUNT is not set!" + #endif + + #ifndef HWTC_PERIOD + #error "HWTC_PERIOD is not set!" + #endif + + #ifndef HWTC_DIVISOR + #error "HWTC_DIVISOR is not set!" + #endif + + #ifndef IRQ_PRIORITY_ORDER + #error "IRQ_PRIORITY_ORDER is not set!" + #elif (IRQ_PRIORITY_ORDER != 0) && (IRQ_PRIORITY_ORDER != 1) + #error "IRQ_PRIORITY_ORDER has bad value!" + #endif + + #if (HWTC_DIVISOR < 1) + #error "HWTC_DIVISOR must be a non-zero positive value!" + #endif + +#endif +/******************************************************************************* + * vTraceConsoleMessage + * + * A wrapper for your system-specific console "printf" console output function. + * This needs to be correctly defined to see status reports from the trace + * status monitor task (this is defined in trcUser.c). + ******************************************************************************/ +#if (SELECTED_PORT == PORT_Atmel_AT91SAM7) +/* Port specific includes */ +#include "console.h" +#endif + +#define vTraceConsoleMessage(x) + +/******************************************************************************* + * vTracePortGetTimeStamp + * + * Returns the current time based on the HWTC macros which provide a hardware + * isolation layer towards the hardware timer/counter. + * + * The HWTC macros and vTracePortGetTimeStamp is the main porting issue + * or the trace recorder library. Typically you should not need to change + * the code of vTracePortGetTimeStamp if using the HWTC macros. + * + ******************************************************************************/ +void vTracePortGetTimeStamp(uint32_t *puiTimestamp); + +/******************************************************************************* + * vTracePortEnd + * + * This function is called when the recorder is stopped due to full buffer. + * Mainly intended to show a message in the console. + * This is used by the Win32 port to store the trace to a file. The file path is + * set using vTracePortSetFileName. + ******************************************************************************/ +void vTracePortEnd(void); + +#if (INCLUDE_SAVE_TO_FILE == 1) + +/******************************************************************************* + * vTracePortSetOutFile + * + * Sets the filename/path used in vTracePortSave. + * This is set in a separate function, since the Win32 port calls vTracePortSave + * in vTracePortEnd if WIN32_PORT_SAVE_WHEN_STOPPED is set. + ******************************************************************************/ +void vTracePortSetOutFile(char* path); + +/****************************************************************************** + * vTracePortSave + * + * Saves the trace to a file on a target-side file system. The path is set in a + * separate function, vTracePortSetOutFile, since the Win32 port may call + * vTracePortSave in vTracePortEnd, if using WIN32_PORT_SAVE_WHEN_STOPPED. + ******************************************************************************/ +void vTracePortSave(void); + +#else + +#define vTraceConsoleMessage(x) +#define vTracePortSetOutFile(path) +#define vTracePortSave(void) + +#endif + +#endif diff --git a/FreeRTOS-Labs/Demo/instructions-for-FreeRTOS+FAT-demo.url b/FreeRTOS-Labs/Demo/instructions-for-FreeRTOS+FAT-demo.url new file mode 100644 index 000000000..3ceab7642 --- /dev/null +++ b/FreeRTOS-Labs/Demo/instructions-for-FreeRTOS+FAT-demo.url @@ -0,0 +1,6 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,2 +[InternetShortcut] +URL=http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html +IDList= +HotKey=0 diff --git a/FreeRTOS-Labs/Demo/instructions-for-FreeRTOS+POSIX-demo.url b/FreeRTOS-Labs/Demo/instructions-for-FreeRTOS+POSIX-demo.url new file mode 100644 index 000000000..5eb87d736 --- /dev/null +++ b/FreeRTOS-Labs/Demo/instructions-for-FreeRTOS+POSIX-demo.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/posix diff --git a/FreeRTOS-Labs/Demo/instructions-for-http-demo.url b/FreeRTOS-Labs/Demo/instructions-for-http-demo.url new file mode 100644 index 000000000..05d27179c --- /dev/null +++ b/FreeRTOS-Labs/Demo/instructions-for-http-demo.url @@ -0,0 +1,6 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/https/index.html +HotKey=0 \ No newline at end of file diff --git a/FreeRTOS-Labs/Demo/instructions-for-jobs-demo.url b/FreeRTOS-Labs/Demo/instructions-for-jobs-demo.url new file mode 100644 index 000000000..3742c73c9 --- /dev/null +++ b/FreeRTOS-Labs/Demo/instructions-for-jobs-demo.url @@ -0,0 +1,6 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/jobs/index.html +HotKey=0 diff --git a/FreeRTOS-Labs/Demo/instructions-for-mqtt-demo.url b/FreeRTOS-Labs/Demo/instructions-for-mqtt-demo.url new file mode 100644 index 000000000..218cdfd74 --- /dev/null +++ b/FreeRTOS-Labs/Demo/instructions-for-mqtt-demo.url @@ -0,0 +1,6 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/mqtt/index.html +HotKey=0 diff --git a/FreeRTOS-Labs/Demo/instructions-for-shadow-demo.url b/FreeRTOS-Labs/Demo/instructions-for-shadow-demo.url new file mode 100644 index 000000000..02391564b --- /dev/null +++ b/FreeRTOS-Labs/Demo/instructions-for-shadow-demo.url @@ -0,0 +1,6 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/shadow/index.html +HotKey=0 diff --git a/FreeRTOS-Labs/Demo/instructions-for-task-pool-demo.url b/FreeRTOS-Labs/Demo/instructions-for-task-pool-demo.url new file mode 100644 index 000000000..65becfc51 --- /dev/null +++ b/FreeRTOS-Labs/Demo/instructions-for-task-pool-demo.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/task-pool/ diff --git a/FreeRTOS-Labs/Demo/readme.txt b/FreeRTOS-Labs/Demo/readme.txt new file mode 100644 index 000000000..e5e2e5c14 --- /dev/null +++ b/FreeRTOS-Labs/Demo/readme.txt @@ -0,0 +1,49 @@ +*** INTRODUCTION *** + +This distribution currently contains demos from the FreeRTOS task pool library, +MQTT library, HTTPS Client library, Shadow library, Jobs library, +FreeRTOS+POSIX, and FreeRTOS+FAT. + +The pre-configured projects use the FreeRTOS kernel Windows port (often +called the Windows simulator) to enable their evaluation using the free Visual +Studio tools and without needing specific microcontroller hardware. + +NOTE: At this time the projects ARE A WORK IN PROGRESS and will be released in +the main FreeRTOS kernel download following full review and completion of the +documentation. + + +*** INSTRUCTIONS *** + +Instructions for configuring and using the FreeRTOS IoT libraries are in the +following links: + + + https://www.FreeRTOS.org/task-pool/ + + https://www.FreeRTOS.org/mqtt/ + + https://www.freertos.org/https/ + + https://www.FreeRTOS.org/shadow/ + + https://www.FreeRTOS.org/jobs/ + + https://freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_POSIX/ + + https://freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/ + +*** LOCATING THE EXAMPLE PROJECTS *** + +The Visual Studio projects for each of the FreeRTOS IoT library examples are +located in sub-directories of the following top-level directories: + + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs + + /FreeRTOS-Labs/Demo/FreeRTOS_Plus_POSIX_with_actor_Windows_Simulator + + /FreeRTOS-Labs/Demo/FreeRTOS_Plus_TCP_and_FAT_Windows_Simulator + +*** ADDITIONAL INFORMATION *** + +See http://www.freertos.org/a00017.html for full details of the FreeRTOS +directory structure + +See also - +http://www.freertos.org/FreeRTOS-quick-start-guide.html +http://www.freertos.org/FAQHelp.html diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/directories.txt b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/directories.txt new file mode 100644 index 000000000..6eb48c195 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/directories.txt @@ -0,0 +1,4 @@ ++ platform +Contains FreeRTOS specific implementations of abstractions used within the IoT +libraries. + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/mbedtls/mbedtls_platform_freertos.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/mbedtls/mbedtls_platform_freertos.c new file mode 100644 index 000000000..2fadb89bc --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/mbedtls/mbedtls_platform_freertos.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file mbedtls_platform.c + * @brief Implements mbed TLS platform functions for FreeRTOS. + */ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "FreeRTOS_Sockets.h" + +/* mbed TLS includes. */ +#include "mbedtls_config.h" +#include "threading_alt.h" +#include "mbedtls/entropy.h" + +/*-----------------------------------------------------------*/ + +void * mbedtls_platform_calloc( size_t nmemb, + size_t size ) +{ + size_t totalSize = nmemb * size; + void * pBuffer = NULL; + + /* Check that neither nmemb nor size were 0. */ + if( totalSize > 0 ) + { + /* Overflow check. */ + if( totalSize / size == nmemb ) + { + pBuffer = pvPortMalloc( totalSize ); + + if( pBuffer != NULL ) + { + ( void ) memset( pBuffer, 0x00, totalSize ); + } + } + } + + return pBuffer; +} + +/*-----------------------------------------------------------*/ + +void mbedtls_platform_free( void * ptr ) +{ + vPortFree( ptr ); +} + +/*-----------------------------------------------------------*/ + +int mbedtls_platform_send( void * ctx, + const unsigned char * buf, + size_t len ) +{ + Socket_t socket = ctx; + + return ( int ) FreeRTOS_send( socket, buf, len, 0 ); +} + +/*-----------------------------------------------------------*/ + +int mbedtls_platform_recv( void * ctx, + unsigned char * buf, + size_t len ) +{ + Socket_t socket = ctx; + + return ( int ) FreeRTOS_recv( socket, buf, len, 0 ); +} + +/*-----------------------------------------------------------*/ + +void mbedtls_platform_mutex_init( mbedtls_threading_mutex_t * pMutex ) +{ + /* Create a statically-allocated FreeRTOS mutex. This should never fail as + * storage is provided. */ + pMutex->mutexHandle = xSemaphoreCreateMutexStatic( &( pMutex->mutexStorage ) ); + configASSERT( pMutex->mutexHandle != NULL ); +} + +/*-----------------------------------------------------------*/ + +void mbedtls_platform_mutex_free( mbedtls_threading_mutex_t * pMutex ) +{ + /* Nothing needs to be done to free a statically-allocated FreeRTOS mutex. */ + ( void ) pMutex; +} + +/*-----------------------------------------------------------*/ + +int mbedtls_platform_mutex_lock( mbedtls_threading_mutex_t * pMutex ) +{ + BaseType_t mutexStatus = 0; + + /* mutexStatus is not used if asserts are disabled. */ + ( void ) mutexStatus; + + /* This function should never fail if the mutex is initialized. */ + mutexStatus = xSemaphoreTake( pMutex->mutexHandle, portMAX_DELAY ); + configASSERT( mutexStatus == pdTRUE ); + + return 0; +} + +/*-----------------------------------------------------------*/ + +int mbedtls_platform_mutex_unlock( mbedtls_threading_mutex_t * pMutex ) +{ + BaseType_t mutexStatus = 0; + + /* mutexStatus is not used if asserts are disabled. */ + ( void ) mutexStatus; + + /* This function should never fail if the mutex is initialized. */ + mutexStatus = xSemaphoreGive( pMutex->mutexHandle ); + configASSERT( mutexStatus == pdTRUE ); + + return 0; +} + +/*-----------------------------------------------------------*/ + +int mbedtls_platform_entropy_poll( void * data, + unsigned char * output, + size_t len, + size_t * olen ) +{ + int status = 0; + NTSTATUS rngStatus = 0; + + /* Context is not used by this function. */ + ( void ) data; + + /* TLS requires a secure random number generator; use the RNG provided + * by Windows. This function MUST be re-implemented for other platforms. */ + rngStatus = BCryptGenRandom( NULL, output, len, BCRYPT_USE_SYSTEM_PREFERRED_RNG ); + + if( rngStatus == 0 ) + { + /* All random bytes generated. */ + *olen = len; + } + else + { + /* RNG failure. */ + *olen = 0; + status = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; + } + + return status; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/mbedtls/threading_alt.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/mbedtls/threading_alt.h new file mode 100644 index 000000000..e8b6648d1 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/mbedtls/threading_alt.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/* mbed TLS threading functions implemented for FreeRTOS. */ + +#ifndef MBEDTLS_THREADING_ALT_H_ +#define MBEDTLS_THREADING_ALT_H_ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "semphr.h" + +/* mbed TLS mutex type. */ +typedef struct mbedtls_threading_mutex +{ + SemaphoreHandle_t mutexHandle; + StaticSemaphore_t mutexStorage; +} mbedtls_threading_mutex_t; + +/* mbed TLS mutex functions. */ +void mbedtls_platform_mutex_init( mbedtls_threading_mutex_t * pMutex ); +void mbedtls_platform_mutex_free( mbedtls_threading_mutex_t * pMutex ); +int mbedtls_platform_mutex_lock( mbedtls_threading_mutex_t * pMutex ); +int mbedtls_platform_mutex_unlock( mbedtls_threading_mutex_t * pMutex ); + +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/iot_taskpool_freertos.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/iot_taskpool_freertos.h new file mode 100644 index 000000000..b8b87f34d --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/iot_taskpool_freertos.h @@ -0,0 +1,310 @@ +/* + * IoT Common V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_taskpool.h + * @brief User-facing functions of the task pool library. + */ + +#ifndef IOT_TASKPOOL_H_ +#define IOT_TASKPOOL_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include +#include + +/* Task pool types. */ +#include "types/iot_taskpool_types_freertos.h" + +/*------------------------- Task Pool library functions --------------------------*/ + +/** + * @functionspage{taskpool,task pool library} + * - @functionname{taskpool_function_createsystemtaskpool} + * - @functionname{taskpool_function_createjob} + * - @functionname{taskpool_function_schedule} + * - @functionname{taskpool_function_scheduledeferred} + * - @functionname{taskpool_function_getstatus} + * - @functionname{taskpool_function_trycancel} + * - @functionname{taskpool_function_getjobstoragefromhandle} + * - @functionname{taskpool_function_strerror} + */ + +/** + * @functionpage{IotTaskPool_CreateSystemTaskPool,taskpool,createsystemtaskpool} + * @functionpage{IotTaskPool_CreateJob,taskpool,createjob} + * @functionpage{IotTaskPool_Schedule,taskpool,schedule} + * @functionpage{IotTaskPool_ScheduleDeferred,taskpool,scheduledeferred} + * @functionpage{IotTaskPool_GetStatus,taskpool,getstatus} + * @functionpage{IotTaskPool_TryCancel,taskpool,trycancel} + * @functionpage{IotTaskPool_GetJobStorageFromHandle,taskpool,getjobstoragefromhandle} + * @functionpage{IotTaskPool_strerror,taskpool,strerror} + */ + +/** + * @brief Creates the one single instance of the system task pool. + * + * This function should be called once by the application to initialize the one single instance of the system task pool. + * An application should initialize the system task pool early in the boot sequence, before initializing any other library + * (e.g. MQTT) that uses the system task pool. An application should also initialize the system + * task pool before posting any jobs. Early initialization is typically easy to accomplish by creating the system task pool + * before the scheduler is started. + * + * The shortcut @ref IOT_SYSTEM_TASKPOOL contains the system task pool handle. + * + * @param[in] pInfo A pointer to the task pool initialization data. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_NO_MEMORY + * + * @warning This function should be called only once. Calling this function more that once will result in + * undefined behavior. + * + */ +/* @[declare_taskpool_createsystemtaskpool] */ +IotTaskPoolError_t IotTaskPool_CreateSystemTaskPool( const IotTaskPoolInfo_t * const pInfo ); +/* @[declare_taskpool_createsystemtaskpool] */ + +/** + * @brief Creates a job for the task pool around a user-provided storage. + * + * @param[in] userCallback A user-specified callback for the job. + * @param[in] pUserContext A user-specified context for the callback. + * @param[in,out] pJobStorage The storage for the job data structure. + * @param[out] pJob A pointer to an instance of @ref IotTaskPoolJob_t that will be initialized when this + * function returns successfully. This handle can be used to inspect the job status with + * @ref IotTaskPool_GetStatus or cancel the job with @ref IotTaskPool_TryCancel, etc.... + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * + * + */ +/* @[declare_taskpool_createjob] */ +IotTaskPoolError_t IotTaskPool_CreateJob( IotTaskPoolRoutine_t userCallback, + void * pUserContext, + IotTaskPoolJobStorage_t * const pJobStorage, + IotTaskPoolJob_t * const pJob ); +/* @[declare_taskpool_createjob] */ + +/** + * @brief This function schedules a job created with @ref IotTaskPool_CreateJob against the task pool pointed to by `taskPool`. + * + * @param[in] taskPool A handle to an initialized taskpool. + * @param[in] job A job to schedule for execution. This must be first initialized with a call to @ref IotTaskPool_CreateJob. + * @param[in] flags Flags to be passed by the user, e.g. to identify the job as high priority by specifying #IOT_TASKPOOL_JOB_HIGH_PRIORITY. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_ILLEGAL_OPERATION + * - #IOT_TASKPOOL_NO_MEMORY + * - #IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS + * + * @note This function will not allocate memory, so it is guaranteed to succeed if the parameters are correct and the task pool + * was correctly initialized, and not yet destroyed. + * + * Example + * @code{c} + * // An example of a user context to pass to a callback through a task pool thread. + * typedef struct JobUserContext + * { + * uint32_t counter; + * } JobUserContext_t; + * + * // An example of a user callback to invoke through a task pool thread. + * static void ExecutionCb( IotTaskPool_t taskPool, IotTaskPoolJob_t job, void * context ) + * { + * ( void )taskPool; + * ( void )job; + * + * JobUserContext_t * pUserContext = ( JobUserContext_t * )context; + * + * pUserContext->counter++; + * } + * + * void TaskPoolExample( ) + * { + * JobUserContext_t userContext = { 0 }; + * IotTaskPoolJob_t job; + * IotTaskPool_t taskPool; + * + * // Configure the task pool to hold one thread. + * // Provide proper stack size and priority per the application needs. + * + * const IotTaskPoolInfo_t tpInfo = { .minThreads = 1, .maxThreads = 1, .stackSize = 512, .priority = 0 }; + * + * // Create a task pool. + * IotTaskPool_Create( &tpInfo, &taskPool ); + * + * // Statically allocate one job, schedule it. + * IotTaskPool_CreateJob( &ExecutionCb, &userContext, &job ); + * + * IotTaskPoolError_t errorSchedule = IotTaskPool_Schedule( taskPool, &job, 0 ); + * + * switch ( errorSchedule ) + * { + * case IOT_TASKPOOL_SUCCESS: + * break; + * case IOT_TASKPOOL_BAD_PARAMETER: // Invalid parameters, such as a NULL handle, can trigger this error. + * case IOT_TASKPOOL_ILLEGAL_OPERATION: // Scheduling a job that was previously scheduled or destroyed could trigger this error. + * case IOT_TASKPOOL_NO_MEMORY: // Scheduling a with flag #IOT_TASKPOOL_JOB_HIGH_PRIORITY could trigger this error. + * case IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS: // Scheduling a job after trying to destroy the task pool could trigger this error. + * // ASSERT + * break; + * default: + * // ASSERT + * } + * + * // + * // ... Perform other operations ... + * // + * + * IotTaskPool_Destroy( taskPool ); + * } + * @endcode + */ +/* @[declare_taskpool_schedule] */ +IotTaskPoolError_t IotTaskPool_Schedule( IotTaskPool_t taskPool, + IotTaskPoolJob_t job, + uint32_t flags ); +/* @[declare_taskpool_schedule] */ + +/** + * @brief This function schedules a job created with @ref IotTaskPool_CreateJob to be executed after a user-defined time interval. + * + * @param[in] taskPool A handle to an initialized taskpool. + * @param[in] job A job to schedule for execution. This must be first initialized with a call to @ref IotTaskPool_CreateJob. + * @param[in] timeMs The time in milliseconds to wait before scheduling the job. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_ILLEGAL_OPERATION + * - #IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS + * + * + * @note This function will not allocate memory. + * + * @warning The `taskPool` used in this function should be the same + * used to create the job pointed to by `job`, or the results will be undefined. + * + */ +/* @[declare_taskpool_scheduledeferred] */ +IotTaskPoolError_t IotTaskPool_ScheduleDeferred( IotTaskPool_t taskPool, + IotTaskPoolJob_t job, + uint32_t timeMs ); +/* @[declare_taskpool_scheduledeferred] */ + +/** + * @brief This function retrieves the current status of a job. + * + * @param[in] taskPool A handle to an initialized taskpool. + * @param[in] job The job to cancel. + * @param[out] pStatus The status of the job at the time of cancellation. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS + * + * @warning This function is not thread safe and the job status returned in `pStatus` may be invalid by the time + * the calling thread has a chance to inspect it. + */ +/* @[declare_taskpool_getstatus] */ +IotTaskPoolError_t IotTaskPool_GetStatus( IotTaskPool_t taskPool, + IotTaskPoolJob_t job, + IotTaskPoolJobStatus_t * const pStatus ); +/* @[declare_taskpool_getstatus] */ + +/** + * @brief This function tries to cancel a job that was previously scheduled with @ref IotTaskPool_Schedule. + * + * A job can be canceled only if it is not yet executing, i.e. if its status is + * @ref IOT_TASKPOOL_STATUS_READY or @ref IOT_TASKPOOL_STATUS_SCHEDULED. Calling + * @ref IotTaskPool_TryCancel on a job whose status is @ref IOT_TASKPOOL_STATUS_COMPLETED, + * or #IOT_TASKPOOL_STATUS_CANCELED will yield a #IOT_TASKPOOL_CANCEL_FAILED return result. + * + * @param[in] taskPool A handle to an initialized taskpool. + * @param[in] job The job to cancel. + * @param[out] pStatus The status of the job at the time of cancellation. + * + * @return One of the following: + * - #IOT_TASKPOOL_SUCCESS + * - #IOT_TASKPOOL_BAD_PARAMETER + * - #IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS + * - #IOT_TASKPOOL_CANCEL_FAILED + * + * @warning The `taskPool` used in this function should be the same + * used to create the job pointed to by `job`, or the results will be undefined. + * + */ +/* @[declare_taskpool_trycancel] */ +IotTaskPoolError_t IotTaskPool_TryCancel( IotTaskPool_t taskPool, + IotTaskPoolJob_t job, + IotTaskPoolJobStatus_t * const pStatus ); +/* @[declare_taskpool_trycancel] */ + +/** + * @brief Returns a pointer to the job storage from an instance of a job handle + * of type @ref IotTaskPoolJob_t. This function is guaranteed to succeed for a + * valid job handle. + * + * @param[in] job The job handle. + * + * @return A pointer to the storage associated with the job handle `job`. + * + * @warning If the `job` handle used is invalid, the results will be undefined. + */ +/* @[declare_taskpool_getjobstoragefromhandle] */ +IotTaskPoolJobStorage_t * IotTaskPool_GetJobStorageFromHandle( IotTaskPoolJob_t job ); +/* @[declare_taskpool_getjobstoragefromhandle] */ + +/** + * @brief Returns a string that describes an @ref IotTaskPoolError_t. + * + * Like the POSIX's `strerror`, this function returns a string describing a + * return code. In this case, the return code is a task pool library error code, + * `status`. + * + * The string returned by this function MUST be treated as read-only: any + * attempt to modify its contents may result in a crash. Therefore, this function + * is limited to usage in logging. + * + * @param[in] status The status to describe. + * + * @return A read-only string that describes `status`. + * + * @warning The string returned by this function must never be modified. + */ +/* @[declare_taskpool_strerror] */ +const char * IotTaskPool_strerror( IotTaskPoolError_t status ); +/* @[declare_taskpool_strerror] */ + +#endif /* ifndef IOT_TASKPOOL_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/platform/iot_network_freertos.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/platform/iot_network_freertos.h new file mode 100644 index 000000000..b7d093710 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/platform/iot_network_freertos.h @@ -0,0 +1,150 @@ +/* + * Amazon FreeRTOS Platform V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_network_freertos.h + * @brief Declares the network stack functions specified in iot_network.h for + * FreeRTOS+TCP. + */ + +#ifndef _IOT_NETWORK_FREERTOS_H_ +#define _IOT_NETWORK_FREERTOS_H_ + +/* Standard includes. */ +#include + +/* Platform types include. */ +#include "types/iot_platform_types.h" + +/* Platform network include. */ +#include "platform/iot_network.h" + +/** + * @brief Provides a default value for an #IotNetworkConnectionFreeRTOS_t. + * + * All instances of #IotNetworkConnectionFreeRTOS_t should be initialized with + * this constant. + * + * @warning Failing to initialize an #IotNetworkConnectionFreeRTOS_t with this + * initializer may result in undefined behavior! + * @note This initializer may change at any time in future versions, but its + * name will remain the same. + */ +#define IOT_NETWORK_CONNECTION_FREERTOS_INITIALIZER { 0 } + +/** + * @brief Generic initializer for an #IotNetworkServerInfo_t. + * + * @note This initializer may change at any time in future versions, but its + * name will remain the same. + */ +#define IOT_NETWORK_SERVER_INFO_FREERTOS_INITIALIZER { 0 } + +/** + * @brief Generic initializer for an #IotNetworkCredentials_t. + * + * @note This initializer may change at any time in future versions, but its + * name will remain the same. + */ +#define IOT_NETWORK_CREDENTIALS_FREERTOS_INITIALIZER { 0 } + +/** + * @brief Provides a pointer to an #IotNetworkInterface_t that uses the functions + * declared in this file. + */ +#define IOT_NETWORK_INTERFACE_FREERTOS ( &( IotNetworkFreeRTOS ) ) + +/** + * @brief One-time initialization function for this network stack. + */ +IotNetworkError_t IotNetworkFreeRTOS_Init( void ); + +/** + * @brief One-time cleanup function for this network stack. + */ +void IotNetworkFreeRTOS_Cleanup( void ); + +/** + * @brief An implementation of #IotNetworkInterface_t::create for FreeRTOS+TCP + * sockets. + */ +IotNetworkError_t IotNetworkFreeRTOS_Create( IotNetworkServerInfo_t pServerInfo, + IotNetworkCredentials_t pCredentialInfo, + IotNetworkConnection_t * pConnection ); + +/** + * @brief An implementation of #IotNetworkInterface_t::setReceiveCallback for + * FreeRTOS+TCP sockets. + */ +IotNetworkError_t IotNetworkFreeRTOS_SetReceiveCallback( IotNetworkConnection_t pConnection, + IotNetworkReceiveCallback_t receiveCallback, + void * pContext ); + +/** + * @brief An implementation of #IotNetworkInterface_t::send for FreeRTOS+TCP + * sockets. + */ +size_t IotNetworkFreeRTOS_Send( IotNetworkConnection_t pConnection, + const uint8_t * pMessage, + size_t messageLength ); + +/** + * @brief An implementation of #IotNetworkInterface_t::receive for FreeRTOS+TCP + * sockets. + */ +size_t IotNetworkFreeRTOS_Receive( IotNetworkConnection_t pConnection, + uint8_t * pBuffer, + size_t bytesRequested ); + +/** + * @brief An implementation of #IotNetworkInterface::receiveUpto for FreeRTOS+TCP + * sockets. + */ +size_t IotNetworkFreeRTOS_ReceiveUpto( IotNetworkConnection_t pConnection, + uint8_t * pBuffer, + size_t bufferSize ); + +/** + * @brief An implementation of #IotNetworkInterface_t::close for FreeRTOS+TCP + * sockets. + */ +IotNetworkError_t IotNetworkFreeRTOS_Close( IotNetworkConnection_t pConnection ); + +/** + * @brief An implementation of #IotNetworkInterface_t::destroy for FreeRTOS+TCP + * sockets. + */ +IotNetworkError_t IotNetworkFreeRTOS_Destroy( IotNetworkConnection_t pConnection ); + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * Declaration of a network interface struct using the functions in this file. + */ +extern const IotNetworkInterface_t IotNetworkFreeRTOS; +/** @endcond */ + +#endif /* ifndef _IOT_NETWORK_FREERTOS_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/platform/iot_platform_types_freertos.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/platform/iot_platform_types_freertos.h new file mode 100644 index 000000000..a331f6cf8 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/platform/iot_platform_types_freertos.h @@ -0,0 +1,92 @@ +/* + * Amazon FreeRTOS Platform V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_platform_types_posix.h + * @brief Definitions of platform layer types on POSIX systems. + */ + +#ifndef _IOT_PLATFORM_TYPES_AFR_H_ +#define _IOT_PLATFORM_TYPES_AFR_H_ + +#include "timers.h" + +typedef struct iot_mutex_internal +{ + StaticSemaphore_t xMutex; /**< FreeRTOS mutex. */ + BaseType_t recursive; /**< Type; used for indicating if this is reentrant or normal. */ +} iot_mutex_internal_t; + +/** + * @brief The native mutex type on AFR systems. + */ +typedef iot_mutex_internal_t _IotSystemMutex_t; + +typedef struct iot_sem_internal +{ + StaticSemaphore_t xSemaphore; /**< FreeRTOS semaphore. */ +} iot_sem_internal_t; + +/** + * @brief The native semaphore type on AFR systems. + */ +typedef iot_sem_internal_t _IotSystemSemaphore_t; + +/** + * @brief Holds information about an active detached thread so that we can + * delete the FreeRTOS task when it completes + */ +typedef struct threadInfo +{ + void * pArgument; /**< @brief Argument to `threadRoutine`. */ + void ( * threadRoutine )( void * ); /**< @brief Thread function to run. */ +} threadInfo_t; + +/** + * @brief Holds information about an active timer. + */ +typedef struct timerInfo +{ + TimerHandle_t timer; /**< @brief Underlying timer. */ + void ( * threadRoutine )( void * ); /**< @brief Thread function to run on timer expiration. */ + void * pArgument; /**< @brief First argument to threadRoutine. */ + StaticTimer_t xTimerBuffer; /**< Memory that holds the FreeRTOS timer. */ + TickType_t xTimerPeriod; /**< Period of this timer. */ +} timerInfo_t; + +/** + * @brief Represents an #IotTimer_t on AFR systems. + */ +typedef timerInfo_t _IotSystemTimer_t; + +struct IotNetworkServerInfo; +struct IotNetworkCredentials; +struct _networkConnection; + +typedef struct IotNetworkServerInfo const * _IotNetworkServerInfo_t; +typedef struct IotNetworkCredentials * _IotNetworkCredentials_t; +typedef struct _networkConnection * _IotNetworkConnection_t; + +#endif /* ifndef _IOT_PLATFORM_TYPES_POSIX_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/types/iot_taskpool_types_freertos.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/types/iot_taskpool_types_freertos.h new file mode 100644 index 000000000..7e567e710 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/include/types/iot_taskpool_types_freertos.h @@ -0,0 +1,306 @@ +/* + * IoT Common V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_taskpool_types.h + * @brief Types of the task pool. + */ + +#ifndef IOT_TASKPOOL_TYPES_H_ +#define IOT_TASKPOOL_TYPES_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include + +/* Platform types includes. */ +#include "types/iot_platform_types.h" + +/* Linear containers (lists and queues) include. */ +#include "iot_linear_containers.h" + +/*-------------------------- Task pool enumerated types --------------------------*/ + +/** + * @ingroup taskpool_datatypes_enums + * @brief Return codes of [task pool functions](@ref taskpool_functions). + */ +typedef enum IotTaskPoolError +{ + /** + * @brief Task pool operation completed successfully. + */ + IOT_TASKPOOL_SUCCESS = 0, + + /** + * @brief Task pool operation failed because at least one parameter is invalid. + */ + IOT_TASKPOOL_BAD_PARAMETER, + + /** + * @brief Task pool operation failed because it is illegal. + */ + IOT_TASKPOOL_ILLEGAL_OPERATION, + + /** + * @brief Task pool operation failed because allocating memory failed. + */ + IOT_TASKPOOL_NO_MEMORY, + + /** + * @brief Task pool operation failed because of an invalid parameter. + */ + IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS, + + /** + * @brief Task pool cancellation failed. + */ + IOT_TASKPOOL_CANCEL_FAILED, + + /** + * @brief Task pool operation general failure. + */ + IOT_TASKPOOL_GENERAL_FAILURE, +} IotTaskPoolError_t; + +/** + * @enums{taskpool,Task pool library} + */ + +/** + * @ingroup taskpool_datatypes_enums + * @brief Status codes of [task pool Job](@ref IotTaskPoolJob_t). + * + */ +typedef enum IotTaskPoolJobStatus +{ + /** + * @brief Job is ready to be scheduled. + * + */ + IOT_TASKPOOL_STATUS_READY = 0, + + /** + * @brief Job has been queued for execution. + * + */ + IOT_TASKPOOL_STATUS_SCHEDULED, + + /** + * @brief Job has been scheduled for deferred execution. + * + */ + IOT_TASKPOOL_STATUS_DEFERRED, + + /** + * @brief Job is executing. + * + */ + IOT_TASKPOOL_STATUS_COMPLETED, + + /** + * @brief Job has been canceled before executing. + * + */ + IOT_TASKPOOL_STATUS_CANCELED, + + /** + * @brief Job status is undefined. + * + */ + IOT_TASKPOOL_STATUS_UNDEFINED, +} IotTaskPoolJobStatus_t; + +/*------------------------- Task pool types and handles --------------------------*/ + +/** + * @ingroup taskpool_datatypes_handles + * @brief Opaque handle of a Task Pool instance. + * + * This type identifies a Task Pool instance, which is valid after a successful call + * to @ref taskpool_function_createsystemtaskpool. + * + * @initializer{IotTaskPool_t,IOT_TASKPOOL_INITIALIZER} + */ +typedef struct _taskPool * IotTaskPool_t; + +/** + * @ingroup taskpool_datatypes_handles + * @brief A storage placeholder for TaskPool Jobs. + * + * This type provides a means to statically allocate an IoT TaskPool Job while + * hiding internal details. + */ +typedef struct IotTaskPoolJobStorage IotTaskPoolJobStorage_t; + +/** + * @ingroup taskpool_datatypes_structs + * @brief A storage placeholder for private data in the IotTaskPoolJobStorage struct. + * + * @warning This is a system-level data type that should not be modified or used directly in any application. + * @warning This is a system-level data type that can and will change across different versions of the platform, with no regards for backward compatibility. + */ +struct PrivateMember +{ + IotLink_t dummy1; /**< @brief Placeholder. */ + TickType_t dummy2; /**< @brief Placeholder. */ +}; + +/** + * @ingroup taskpool_datatypes_structs + * @brief The job storage data structure provides the storage for a statically allocated Task Pool Job instance. + * + * @warning This is a system-level data type that should not be modified or used directly in any application. + * @warning This is a system-level data type that can and will change across different versions of the platform, with no regards for backward compatibility. + * + */ +struct IotTaskPoolJobStorage +{ + IotLink_t link; /**< @brief Placeholder. */ + void * dummy2; /**< @brief Placeholder. */ + void * dummy3; /**< @brief Placeholder. */ + IotTaskPoolJobStatus_t status; /**< @brief Placeholder. */ + struct PrivateMember dummy6; /**< @brief Placeholder. */ +}; + +/** + * @ingroup taskpool_datatypes_handles + * @brief Opaque handle of a Task Pool Job. + * + * This type identifies a Task Pool Job instance, which is valid after a successful call + * to @ref taskpool_function_createjob. + * + * @initializer{IotTaskPoolJob_t,IOT_TASKPOOL_JOB_INITIALIZER} + * + */ +typedef struct _taskPoolJob * IotTaskPoolJob_t; + +/*------------------------- Task pool parameter structs --------------------------*/ + +/** + * @ingroup taskpool_datatypes_functionpointers + * @brief Callback type for a user callback. + * + * This type identifies the user callback signature to execute a task pool job. This callback will be invoked + * by the task pool threads with the `pUserContext` parameter, as specified by the user when + * calling @ref IotTaskPool_Schedule. + * + */ +typedef void ( * IotTaskPoolRoutine_t )( IotTaskPool_t pTaskPool, + IotTaskPoolJob_t pJob, + void * pUserContext ); + +/** + * @ingroup taskpool_datatypes_paramstructs + * @brief Initialization information to create one task pool instance. + * + * @paramfor @ref taskpool_function_createsystemtaskpool + * + * @initializer{IotTaskPoolInfo_t,IOT_TASKPOOL_INFO_INITIALIZER} + */ +typedef struct IotTaskPoolInfo +{ + /** + * @brief Specifies the operating parameters for a task pool. + * + * @attention #IotTaskPoolInfo_t.minThreads MUST be at least 1. + */ + + uint32_t minThreads; /**< @brief Minimum number of threads in a task pool. These tasks will be statically allocated. */ + uint32_t maxThreads; /**< @brief Maximum number of threads in a task pool. This is fixed for the lifetime of the taskpool. */ + uint32_t stackSize; /**< @brief Stack size for every task pool thread. The stack size for each thread is fixed after the task pool is created and cannot be changed. */ + int32_t priority; /**< @brief priority for every task pool thread. The priority for each thread is fixed after the task pool is created and cannot be changed. */ +} IotTaskPoolInfo_t; + +/*------------------------- TASKPOOL defined constants --------------------------*/ + +/** + * @constantspage{taskpool,task pool library} + * + * @section taskpool_constants_initializers Task pool Initializers + * @brief Provides default values for initializing the data types of the task pool library. + * + * @snippet this define_taskpool_initializers + * + * All user-facing data types of the task pool library can be initialized using + * one of the following. + * + * @warning Failure to initialize a task pool data type with the appropriate initializer + * may result in a runtime error! + * @note The initializers may change at any time in future versions, but their + * names will remain the same. + * + * Example + * @code{c} + * + * IotTaskPool_t * pTaskPool; + * + * const IotTaskPoolInfo_t tpInfo = IOT_TASKPOOL_INFO_INITIALIZER_LARGE; + * + * IotTaskPoolError_t error = IotTaskPool_Create( &tpInfo, &pTaskPool ); + * + * // Use the task pool + * // ... + * + * @endcode + * + */ +/* @[define_taskpool_initializers] */ +/** @brief Initializer for a small #IotTaskPoolInfo_t. */ +#define IOT_TASKPOOL_INFO_INITIALIZER_SMALL { .minThreads = 1, .maxThreads = 1, .stackSize = IOT_THREAD_DEFAULT_STACK_SIZE, .priority = IOT_THREAD_DEFAULT_PRIORITY } +/** @brief Initializer for a medium #IotTaskPoolInfo_t. */ +#define IOT_TASKPOOL_INFO_INITIALIZER_MEDIUM { .minThreads = 1, .maxThreads = 2, .stackSize = IOT_THREAD_DEFAULT_STACK_SIZE, .priority = IOT_THREAD_DEFAULT_PRIORITY } +/** @brief Initializer for a large #IotTaskPoolInfo_t. */ +#define IOT_TASKPOOL_INFO_INITIALIZER_LARGE { .minThreads = 2, .maxThreads = 3, .stackSize = IOT_THREAD_DEFAULT_STACK_SIZE, .priority = IOT_THREAD_DEFAULT_PRIORITY } +/** @brief Initializer for a very large #IotTaskPoolInfo_t. */ +#define IOT_TASKPOOL_INFO_INITIALIZER_XLARGE { .minThreads = 2, .maxThreads = 4, .stackSize = IOT_THREAD_DEFAULT_STACK_SIZE, .priority = IOT_THREAD_DEFAULT_PRIORITY } +/** @brief Initializer for a typical #IotTaskPoolInfo_t. */ +#define IOT_TASKPOOL_INFO_INITIALIZER IOT_TASKPOOL_INFO_INITIALIZER_MEDIUM +/** @brief Initializer for a #IotTaskPool_t. */ +#define IOT_TASKPOOL_INITIALIZER NULL +/** @brief Initializer for a #IotTaskPoolJobStorage_t. */ +#define IOT_TASKPOOL_JOB_STORAGE_INITIALIZER { { NULL, NULL }, NULL, NULL, 0, IOT_TASKPOOL_STATUS_UNDEFINED } +/** @brief Initializer for a #IotTaskPoolJob_t. */ +#define IOT_TASKPOOL_JOB_INITIALIZER NULL +/* @[define_taskpool_initializers] */ + +/** + * @brief Flag for scheduling a job to execute immediately, even if the maximum number of threads in the + * task pool was reached already. + * + * @warning This flag may cause the task pool to create a worker to serve the job immediately, and + * therefore using this flag may incur in additional memory usage and potentially fail scheduling the job. + */ +#define IOT_TASKPOOL_JOB_HIGH_PRIORITY ( ( uint32_t ) 0x00000001 ) + +/** + * @brief Allows the use of the handle to the system task pool. + * + * @warning The system task pool handle is not valid unless @ref IotTaskPool_CreateSystemTaskPool is + * called before the handle is used. + */ +#define IOT_SYSTEM_TASKPOOL ( NULL ) + +#endif /* ifndef IOT_TASKPOOL_TYPES_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_clock_freertos.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_clock_freertos.c new file mode 100644 index 000000000..c95bb9a4e --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_clock_freertos.c @@ -0,0 +1,225 @@ +/* + * Amazon FreeRTOS Platform V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_clock_freertos.c + * @brief Implementation of the platform specific functions in iot_clock.h for + * FreeRTOS. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* Platform clock include. */ +#include "platform/iot_platform_types_freertos.h" +#include "platform/iot_clock.h" +#include "task.h" + +/* Configure logs for the functions in this file. */ +#ifdef IOT_LOG_LEVEL_PLATFORM + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_PLATFORM +#else + #ifdef IOT_LOG_LEVEL_GLOBAL + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_GLOBAL + #else + #define LIBRARY_LOG_LEVEL IOT_LOG_NONE + #endif +#endif + +#define LIBRARY_LOG_NAME ( "CLOCK" ) +#include "iot_logging_setup.h" + +/*-----------------------------------------------------------*/ + +/* + * Time conversion constants. + */ +#define _MILLISECONDS_PER_SECOND ( 1000 ) /**< @brief Milliseconds per second. */ +#define _MILLISECONDS_PER_TICK ( _MILLISECONDS_PER_SECOND / configTICK_RATE_HZ ) /**< Milliseconds per FreeRTOS tick. */ + +/*-----------------------------------------------------------*/ + +/* Private Callback function for timer expiry, delegate work to a Task to free + * up the timer task for managing other timers */ +static void prvTimerCallback( TimerHandle_t xTimerHandle ) +{ + _IotSystemTimer_t * pxTimer = ( _IotSystemTimer_t * ) pvTimerGetTimerID( xTimerHandle ); + + /* The value of the timer ID, set in timer_create, should not be NULL. */ + configASSERT( pxTimer != NULL ); + + /* Restart the timer if it is periodic. */ + if( pxTimer->xTimerPeriod > 0 ) + { + xTimerChangePeriod( xTimerHandle, pxTimer->xTimerPeriod, 0 ); + } + + /* Call timer Callback from this task */ + pxTimer->threadRoutine( ( void * ) pxTimer->pArgument ); +} + +/*-----------------------------------------------------------*/ + +bool IotClock_GetTimestring( char * pBuffer, + size_t bufferSize, + size_t * pTimestringLength ) +{ + uint64_t milliSeconds = IotClock_GetTimeMs(); + int timestringLength = 0; + + configASSERT( pBuffer != NULL ); + configASSERT( pTimestringLength != NULL ); + + /* Convert the localTime struct to a string. */ + timestringLength = snprintf( pBuffer, bufferSize, "%llu", milliSeconds ); + + /* Check for error from no string */ + if( timestringLength == 0 ) + { + return false; + } + + /* Set the output parameter. */ + *pTimestringLength = timestringLength; + + return true; +} + +/*-----------------------------------------------------------*/ + +uint64_t IotClock_GetTimeMs( void ) +{ + TimeOut_t xCurrentTime = { 0 }; + + /* This must be unsigned because the behavior of signed integer overflow is undefined. */ + uint64_t ullTickCount = 0ULL; + + /* Get the current tick count and overflow count. vTaskSetTimeOutState() + * is used to get these values because they are both static in tasks.c. */ + vTaskSetTimeOutState( &xCurrentTime ); + + /* Adjust the tick count for the number of times a TickType_t has overflowed. */ + ullTickCount = ( uint64_t ) ( xCurrentTime.xOverflowCount ) << ( sizeof( TickType_t ) * 8 ); + + /* Add the current tick count. */ + ullTickCount += xCurrentTime.xTimeOnEntering; + + /* Return the ticks converted to Milliseconds */ + return ullTickCount * _MILLISECONDS_PER_TICK; +} +/*-----------------------------------------------------------*/ + +void IotClock_SleepMs( uint32_t sleepTimeMs ) +{ + vTaskDelay( pdMS_TO_TICKS( sleepTimeMs ) ); +} + +/*-----------------------------------------------------------*/ + +bool IotClock_TimerCreate( IotTimer_t * pNewTimer, + IotThreadRoutine_t expirationRoutine, + void * pArgument ) +{ + _IotSystemTimer_t * pxTimer = ( _IotSystemTimer_t * ) pNewTimer; + + configASSERT( pNewTimer != NULL ); + configASSERT( expirationRoutine != NULL ); + + IotLogDebug( "Creating new timer %p.", pNewTimer ); + + /* Set the timer expiration routine, argument and period */ + pxTimer->threadRoutine = expirationRoutine; + pxTimer->pArgument = pArgument; + pxTimer->xTimerPeriod = 0; + + /* Create a new FreeRTOS timer. This call will not fail because the + * memory for it has already been allocated, so the output parameter is + * also set. */ + pxTimer->timer = ( TimerHandle_t ) xTimerCreateStatic( "timer", /* Timer name. */ + portMAX_DELAY, /* Initial timer period. Timers are created disarmed. */ + pdFALSE, /* Don't auto-reload timer. */ + ( void * ) pxTimer, /* Timer id. */ + prvTimerCallback, /* Timer expiration callback. */ + &pxTimer->xTimerBuffer ); /* Pre-allocated memory for timer. */ + + return true; +} + +/*-----------------------------------------------------------*/ + +void IotClock_TimerDestroy( IotTimer_t * pTimer ) +{ + _IotSystemTimer_t * pTimerInfo = ( _IotSystemTimer_t * ) pTimer; + + configASSERT( pTimerInfo != NULL ); + configASSERT( pTimerInfo->timer != NULL ); + + IotLogDebug( "Destroying timer %p.", pTimer ); + + if( xTimerIsTimerActive( pTimerInfo->timer ) == pdTRUE ) + { + /* Stop the FreeRTOS timer. Because the timer is statically allocated, no call + * to xTimerDelete is necessary. The timer is stopped so that it's not referenced + * anywhere. xTimerStop will not fail when it has unlimited block time. */ + ( void ) xTimerStop( pTimerInfo->timer, portMAX_DELAY ); + + /* Wait until the timer stop command is processed. */ + while( xTimerIsTimerActive( pTimerInfo->timer ) == pdTRUE ) + { + vTaskDelay( 1 ); + } + } +} + +/*-----------------------------------------------------------*/ + +bool IotClock_TimerArm( IotTimer_t * pTimer, + uint32_t relativeTimeoutMs, + uint32_t periodMs ) +{ + _IotSystemTimer_t * pTimerInfo = ( _IotSystemTimer_t * ) pTimer; + + configASSERT( pTimerInfo != NULL ); + + TimerHandle_t xTimerHandle = pTimerInfo->timer; + + IotLogDebug( "Arming timer %p with timeout %llu and period %llu.", + pTimer, + relativeTimeoutMs, + periodMs ); + + /* Set the timer period in ticks */ + pTimerInfo->xTimerPeriod = pdMS_TO_TICKS( periodMs ); + + /* Set the timer to expire after relativeTimeoutMs, and restart it. */ + ( void ) xTimerChangePeriod( xTimerHandle, pdMS_TO_TICKS( relativeTimeoutMs ), portMAX_DELAY ); + + return true; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_network_freertos.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_network_freertos.c new file mode 100644 index 000000000..50ea1df02 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_network_freertos.c @@ -0,0 +1,968 @@ +/* + * Amazon FreeRTOS Platform V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_network_freertos.c + * @brief Implementation of the network-related functions from iot_network_freertos.h + * for FreeRTOS+TCP sockets. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "atomic.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +/* FreeRTOS-IoT-Libraries includes. */ +#include "iot_error.h" +#include "platform/iot_network_freertos.h" + +#if ( IOT_NETWORK_ENABLE_TLS == 1 ) + /* mbed TLS includes. */ + #include "mbedtls/ctr_drbg.h" + #include "mbedtls/entropy.h" + #include "mbedtls/ssl.h" + #include "mbedtls/threading.h" + #include "mbedtls/x509.h" +#endif + +/* Configure logs for the functions in this file. */ +#ifdef IOT_LOG_LEVEL_NETWORK + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_NETWORK +#else + #ifdef IOT_LOG_LEVEL_GLOBAL + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_GLOBAL + #else + #define LIBRARY_LOG_LEVEL IOT_LOG_NONE + #endif +#endif + +#define LIBRARY_LOG_NAME ( "NET" ) +#include "iot_logging_setup.h" + +/* Provide a default value for socket timeout and network task parameters. */ +#ifndef IOT_NETWORK_SOCKET_TIMEOUT_MS + #define IOT_NETWORK_SOCKET_TIMEOUT_MS ( 5000 ) +#endif +#ifndef IOT_NETWORK_TASK_STACK_SIZE + #define IOT_NETWORK_TASK_STACK_SIZE ( 2048 ) +#endif +#ifndef IOT_NETWORK_TASK_PRIORITY + #define IOT_NETWORK_TASK_PRIORITY ( tskIDLE_PRIORITY ) +#endif + +/* Maximum number of simultaneous socket receive callbacks. */ +#ifndef IOT_NETWORK_MAX_RECEIVE_CALLBACKS + #define IOT_NETWORK_MAX_RECEIVE_CALLBACKS ( 2 ) +#endif + +/** + * @brief Maximum length of a DNS name. + * + * Per https://tools.ietf.org/html/rfc1035, 253 is the maximum string length + * of a DNS name. + */ +#define MAX_DNS_NAME_LENGTH ( 253 ) +/*-----------------------------------------------------------*/ + +/** + * @brief Internal network context. + */ +typedef struct _networkConnection +{ + Socket_t socket; /**< @brief FreeRTOS+TCP sockets handle. */ + SemaphoreHandle_t socketMutex; /**< @brief Prevents concurrent threads from using a socket. */ + StaticSemaphore_t socketMutexStorage; /**< @brief Storage space for socketMutex. */ + IotNetworkReceiveCallback_t receiveCallback; /**< @brief Network receive callback, if any. */ + void * pReceiveContext; /**< @brief The context for the receive callback. */ + + #if ( IOT_NETWORK_ENABLE_TLS == 1 ) + BaseType_t secured; /**< @brief Flag that marks a connection as secured. */ + + /** + * @brief Secured connection context. Valid if `secured` is `pdTRUE`. + */ + struct + { + mbedtls_ssl_config config; /**< @brief SSL connection configuration. */ + mbedtls_ssl_context context; /**< @brief SSL connection context */ + mbedtls_x509_crt_profile certProfile; /**< @brief Certificate security profile for this connection. */ + mbedtls_x509_crt rootCa; /**< @brief Root CA certificate context. */ + mbedtls_x509_crt clientCert; /**< @brief Client certificate context. */ + mbedtls_pk_context privKey; /**< @brief Client private key context. */ + } ssl; + #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */ +} _networkConnection_t; +/*-----------------------------------------------------------*/ + +#if ( IOT_NETWORK_ENABLE_TLS == 1 ) + +/** + * @brief mbed TLS entropy context for generation of random numbers. + */ + static mbedtls_entropy_context _entropyContext; + +/** + * @brief mbed TLS CTR DRBG context for generation of random numbers. + */ + static mbedtls_ctr_drbg_context _ctrDrgbContext; +#endif + +/** + * @brief Handle of the network task. + */ +static TaskHandle_t _networkTaskHandle; + +/** + * @brief Socket set for the network task. + */ +static SocketSet_t _socketSet; + +/** + * @brief Connections in _socketSet. + */ +static _networkConnection_t * _connections[ IOT_NETWORK_MAX_RECEIVE_CALLBACKS ]; + +/** + * @brief An #IotNetworkInterface_t that uses the functions in this file. + */ +const IotNetworkInterface_t IotNetworkFreeRTOS = +{ + .create = IotNetworkFreeRTOS_Create, + .setReceiveCallback = IotNetworkFreeRTOS_SetReceiveCallback, + .send = IotNetworkFreeRTOS_Send, + .receive = IotNetworkFreeRTOS_Receive, + .receiveUpto = IotNetworkFreeRTOS_ReceiveUpto, + .close = IotNetworkFreeRTOS_Close, + .destroy = IotNetworkFreeRTOS_Destroy +}; +/*-----------------------------------------------------------*/ + +#if ( IOT_NETWORK_ENABLE_TLS == 1 ) + +/** + * @brief Initialize the mbed TLS structures in a network connection. + * + * @param[in] pNetworkConnection The network connection to initialize. + */ + static void _sslContextInit( _networkConnection_t * pNetworkConnection ) + { + mbedtls_ssl_config_init( &( pNetworkConnection->ssl.config ) ); + mbedtls_x509_crt_init( &( pNetworkConnection->ssl.rootCa ) ); + mbedtls_pk_init( &( pNetworkConnection->ssl.privKey ) ); + mbedtls_x509_crt_init( &( pNetworkConnection->ssl.clientCert ) ); + mbedtls_ssl_init( &( pNetworkConnection->ssl.context ) ); + } +/*-----------------------------------------------------------*/ + +/** + * @brief Free the mbed TLS structures in a network connection. + * + * @param[in] pNetworkConnection The network connection with the contexts to free. + */ + static void _sslContextFree( _networkConnection_t * pNetworkConnection ) + { + mbedtls_ssl_free( &( pNetworkConnection->ssl.context ) ); + mbedtls_x509_crt_free( &( pNetworkConnection->ssl.rootCa ) ); + mbedtls_x509_crt_free( &( pNetworkConnection->ssl.clientCert ) ); + mbedtls_pk_free( &( pNetworkConnection->ssl.privKey ) ); + mbedtls_ssl_config_free( &( pNetworkConnection->ssl.config ) ); + } +/*-----------------------------------------------------------*/ + +/** + * @brief Set up TLS on a TCP connection. + * + * @param[in] pNetworkConnection An established TCP connection. + * @param[in] pServerName Remote host name, used for server name indication. + * @param[in] pCredentials TLS setup parameters. + * + * @return #IOT_NETWORK_SUCCESS, #IOT_NETWORK_FAILURE, #IOT_NETWORK_NO_MEMORY, + * or #IOT_NETWORK_SYSTEM_ERROR. + */ + static IotNetworkError_t _tlsSetup( _networkConnection_t * pNetworkConnection, + const char * pServerName, + IotNetworkCredentials_t pCredentials ) + { + IOT_FUNCTION_ENTRY( IotNetworkError_t, IOT_NETWORK_SUCCESS ); + int mbedtlsError = 0; + + /* Initialize the mbed TLS context structures. */ + _sslContextInit( pNetworkConnection ); + + mbedtlsError = mbedtls_ssl_config_defaults( &( pNetworkConnection->ssl.config ), + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT ); + + if( mbedtlsError != 0 ) + { + IotLogError( "Failed to set default SSL configuration, error %d.", mbedtlsError ); + + /* Per mbed TLS docs, mbedtls_ssl_config_defaults only fails on memory allocation. */ + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_NO_MEMORY ); + } + + /* Set up the certificate security profile, starting from the default value. */ + pNetworkConnection->ssl.certProfile = mbedtls_x509_crt_profile_default; + + /* test.mosquitto.org only provides a 1024-bit RSA certificate, which is + * not acceptable by the default mbed TLS certificate security profile. + * For the purposes of this demo, allow the use of 1024-bit RSA certificates. + * This block should be removed otherwise. */ + if( strncmp( pServerName, "test.mosquitto.org", strlen( pServerName ) ) == 0 ) + { + pNetworkConnection->ssl.certProfile.rsa_min_bitlen = 1024; + } + + /* Set SSL authmode and the RNG context. */ + mbedtls_ssl_conf_authmode( &( pNetworkConnection->ssl.config ), + MBEDTLS_SSL_VERIFY_REQUIRED ); + mbedtls_ssl_conf_rng( &( pNetworkConnection->ssl.config ), + mbedtls_ctr_drbg_random, + &_ctrDrgbContext ); + mbedtls_ssl_conf_cert_profile( &( pNetworkConnection->ssl.config ), + &( pNetworkConnection->ssl.certProfile ) ); + + /* Parse the server root CA certificate into the SSL context. */ + mbedtlsError = mbedtls_x509_crt_parse( &( pNetworkConnection->ssl.rootCa ), + ( const unsigned char * ) pCredentials->pRootCa, + pCredentials->rootCaSize ); + + if( mbedtlsError != 0 ) + { + IotLogError( "Failed to parse server root CA certificate, error %d.", + mbedtlsError ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR ); + } + + mbedtls_ssl_conf_ca_chain( &( pNetworkConnection->ssl.config ), + &( pNetworkConnection->ssl.rootCa ), + NULL ); + + if( ( pCredentials->pPrivateKey != NULL ) && ( pCredentials->pClientCert != NULL ) ) + { + /* Setup the client private key. */ + mbedtlsError = mbedtls_pk_parse_key( &( pNetworkConnection->ssl.privKey ), + ( const unsigned char * ) pCredentials->pPrivateKey, + pCredentials->privateKeySize, + 0, + 0 ); + + if( mbedtlsError != 0 ) + { + IotLogError( "Failed to parse client certificate, error %d.", + mbedtlsError ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR ); + } + + /* Setup the client certificate. */ + mbedtlsError = mbedtls_x509_crt_parse( &( pNetworkConnection->ssl.clientCert ), + ( const unsigned char * ) pCredentials->pClientCert, + pCredentials->clientCertSize ); + + if( mbedtlsError != 0 ) + { + IotLogError( "Failed to parse the client private key, error %d.", + mbedtlsError ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR ); + } + + mbedtls_ssl_conf_own_cert( &( pNetworkConnection->ssl.config ), + &( pNetworkConnection->ssl.clientCert ), + &( pNetworkConnection->ssl.privKey ) ); + } + + /* Initialize the mbed TLS secured connection context. */ + mbedtlsError = mbedtls_ssl_setup( &( pNetworkConnection->ssl.context ), + &( pNetworkConnection->ssl.config ) ); + + if( mbedtlsError != 0 ) + { + IotLogError( "Failed to set up mbed TLS SSL context, error %d.", + mbedtlsError ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR ); + } + + /* Set the underlying IO for the TLS connection. */ + mbedtls_ssl_set_bio( &( pNetworkConnection->ssl.context ), + pNetworkConnection->socket, + mbedtls_platform_send, + mbedtls_platform_recv, + NULL ); + + /* Enable SNI if requested. */ + if( pCredentials->disableSni == false ) + { + mbedtlsError = mbedtls_ssl_set_hostname( &( pNetworkConnection->ssl.context ), + pServerName ); + + if( mbedtlsError != 0 ) + { + IotLogError( "Failed to set server name, error %d.", mbedtlsError ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR ); + } + } + + /* Perform the TLS handshake. */ + do + { + mbedtlsError = mbedtls_ssl_handshake( &( pNetworkConnection->ssl.context ) ); + } while( ( mbedtlsError == MBEDTLS_ERR_SSL_WANT_READ ) || + ( mbedtlsError == MBEDTLS_ERR_SSL_WANT_WRITE ) ); + + if( mbedtlsError != 0 ) + { + IotLogError( "Failed to perform TLS handshake, error %d.", mbedtlsError ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_FAILURE ); + } + + /* Clean up on error. */ + IOT_FUNCTION_CLEANUP_BEGIN(); + + if( status != IOT_NETWORK_SUCCESS ) + { + _sslContextFree( pNetworkConnection ); + } + else + { + pNetworkConnection->secured = pdTRUE; + + IotLogInfo( "(Network connection %p) TLS handshake successful.", + pNetworkConnection ); + } + + IOT_FUNCTION_CLEANUP_END(); + } +#endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */ +/*-----------------------------------------------------------*/ + +static void _networkTask( void * pvParameters ) +{ + _networkConnection_t * pConnection = NULL; + BaseType_t socketEvents = 0, i = 0, socketStatus = 0; + SocketSet_t socketSet = pvParameters; + + while( true ) + { + socketEvents = FreeRTOS_select( socketSet, IOT_NETWORK_SOCKET_TIMEOUT_MS ); + + if( socketEvents > 0 ) + { + for( i = 0; i < IOT_NETWORK_MAX_RECEIVE_CALLBACKS; i++ ) + { + pConnection = _connections[ i ]; + + if( pConnection != NULL ) + { + socketStatus = FreeRTOS_FD_ISSET( pConnection->socket, socketSet ); + + if( socketStatus & eSELECT_READ ) + { + /* A receive callback must be set; otherwise, select should not + * have returned this socket. */ + configASSERT( pConnection->receiveCallback != NULL ); + + pConnection->receiveCallback( pConnection, + pConnection->pReceiveContext ); + } + } + } + } + + /* This task will receive a notification when cleanup is called. Exit when + * cleanup is called. */ + if( ulTaskNotifyTake( pdTRUE, 0 ) != 0 ) + { + break; + } + } + + FreeRTOS_DeleteSocketSet( socketSet ); + vTaskDelete( NULL ); +} +/*-----------------------------------------------------------*/ + +IotNetworkError_t IotNetworkFreeRTOS_Init( void ) +{ + IOT_FUNCTION_ENTRY( IotNetworkError_t, IOT_NETWORK_SUCCESS ); + + #if ( IOT_NETWORK_ENABLE_TLS == 1 ) + int mbedtlsError = 0; + + /* Set the mutex functions for mbed TLS thread safety. */ + mbedtls_threading_set_alt( mbedtls_platform_mutex_init, + mbedtls_platform_mutex_free, + mbedtls_platform_mutex_lock, + mbedtls_platform_mutex_unlock ); + + /* Initialize contexts for random number generation. */ + mbedtls_entropy_init( &_entropyContext ); + mbedtls_ctr_drbg_init( &_ctrDrgbContext ); + + /* Add a strong entropy source. At least one is required. */ + mbedtlsError = mbedtls_entropy_add_source( &_entropyContext, + mbedtls_platform_entropy_poll, + NULL, + 32, + MBEDTLS_ENTROPY_SOURCE_STRONG ); + + if( mbedtlsError != 0 ) + { + IotLogError( "Failed to add entropy source, error %d.", mbedtlsError ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_FAILURE ); + } + + /* Seed the random number generator. */ + mbedtlsError = mbedtls_ctr_drbg_seed( &_ctrDrgbContext, + mbedtls_entropy_func, + &_entropyContext, + NULL, + 0 ); + + if( mbedtlsError != 0 ) + { + IotLogError( "Failed to seed PRNG, error %d.", mbedtlsError ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_FAILURE ); + } + #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */ + + /* Create socket set for network task. */ + _socketSet = FreeRTOS_CreateSocketSet(); + + if( _socketSet == NULL ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_FAILURE ); + } + + static StaticTask_t networkTask; + static StackType_t networkTaskStack[ IOT_NETWORK_TASK_STACK_SIZE ]; + + /* Create the network task. Since valid parameters are provided, this should + * never fail. */ + _networkTaskHandle = xTaskCreateStatic( _networkTask, + "Network", + IOT_NETWORK_TASK_STACK_SIZE, + _socketSet, + IOT_NETWORK_TASK_PRIORITY, + ( StackType_t * const ) &networkTaskStack, + &networkTask ); + configASSERT( _networkTaskHandle != NULL ); + + IotLogInfo( "Network successfully initialized." ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} +/*-----------------------------------------------------------*/ + +void IotNetworkFreeRTOS_Cleanup( void ) +{ + #if ( IOT_NETWORK_ENABLE_TLS == 1 ) + /* Free the contexts for random number generation. */ + mbedtls_ctr_drbg_free( &_ctrDrgbContext ); + mbedtls_entropy_free( &_entropyContext ); + + /* Clear the mutex functions for mbed TLS thread safety. */ + mbedtls_threading_free_alt(); + #endif + + xTaskNotifyGive( _networkTaskHandle ); + + IotLogInfo( "Network cleanup done." ); +} +/*-----------------------------------------------------------*/ + +IotNetworkError_t IotNetworkFreeRTOS_Create( IotNetworkServerInfo_t pServerInfo, + IotNetworkCredentials_t pCredentialInfo, + IotNetworkConnection_t * pConnection ) +{ + IOT_FUNCTION_ENTRY( IotNetworkError_t, IOT_NETWORK_SUCCESS ); + Socket_t tcpSocket = FREERTOS_INVALID_SOCKET; + BaseType_t socketStatus = 0; + struct freertos_sockaddr serverAddress = { 0 }; + const TickType_t receiveTimeout = pdMS_TO_TICKS( IOT_NETWORK_SOCKET_TIMEOUT_MS ); + _networkConnection_t * pNewNetworkConnection = NULL; + + /* Credentials are not used if TLS is disabled. */ + ( void ) pCredentialInfo; + + /* Check host name length against the maximum length allowed. */ + const size_t hostnameLength = strlen( pServerInfo->pHostName ); + + if( hostnameLength > ( size_t ) MAX_DNS_NAME_LENGTH ) + { + IotLogError( "Host name length exceeds %d, which is the maximum allowed.", + MAX_DNS_NAME_LENGTH ); + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_BAD_PARAMETER ); + } + + pNewNetworkConnection = pvPortMalloc( sizeof( _networkConnection_t ) ); + + if( pNewNetworkConnection == NULL ) + { + IotLogError( "Failed to allocate memory for new network connection." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_NO_MEMORY ); + } + + /* Clear the connection information. */ + ( void ) memset( pNewNetworkConnection, 0x00, sizeof( _networkConnection_t ) ); + + /* Create a new TCP socket. */ + tcpSocket = FreeRTOS_socket( FREERTOS_AF_INET, + FREERTOS_SOCK_STREAM, + FREERTOS_IPPROTO_TCP ); + + if( tcpSocket == FREERTOS_INVALID_SOCKET ) + { + IotLogError( "Failed to create new socket." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR ); + } + + /* Set the timeout for receive. */ + socketStatus = FreeRTOS_setsockopt( tcpSocket, + 0, + FREERTOS_SO_RCVTIMEO, + &receiveTimeout, + sizeof( TickType_t ) ); + + if( socketStatus != 0 ) + { + IotLogError( "Failed to set socket receive timeout." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR ); + } + + /* Establish connection. */ + serverAddress.sin_family = FREERTOS_AF_INET; + serverAddress.sin_port = FreeRTOS_htons( pServerInfo->port ); + serverAddress.sin_addr = FreeRTOS_gethostbyname( pServerInfo->pHostName ); + serverAddress.sin_len = ( uint8_t ) sizeof( serverAddress ); + + /* Check for errors from DNS lookup. */ + if( serverAddress.sin_addr == 0 ) + { + IotLogError( "Failed to resolve %s.", pServerInfo->pHostName ); + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR ); + } + + socketStatus = FreeRTOS_connect( tcpSocket, + &serverAddress, + sizeof( serverAddress ) ); + + if( socketStatus != 0 ) + { + IotLogError( "Failed to establish new connection. Socket status %d.", socketStatus ); + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_SYSTEM_ERROR ); + } + + /* Set the socket. */ + pNewNetworkConnection->socket = tcpSocket; + + #if ( IOT_NETWORK_ENABLE_TLS == 1 ) + /* Set up TLS if credentials are provided. */ + if( pCredentialInfo != NULL ) + { + status = _tlsSetup( pNewNetworkConnection, + pServerInfo->pHostName, + pCredentialInfo ); + } + #endif + + IOT_FUNCTION_CLEANUP_BEGIN(); + + /* Clean up on failure. */ + if( status != IOT_NETWORK_SUCCESS ) + { + if( tcpSocket != FREERTOS_INVALID_SOCKET ) + { + FreeRTOS_closesocket( tcpSocket ); + } + + /* Clear the connection information. */ + if( pNewNetworkConnection != NULL ) + { + vPortFree( pNewNetworkConnection ); + } + } + else + { + /* Create the socket mutex. */ + pNewNetworkConnection->socketMutex = xSemaphoreCreateMutexStatic( &( pNewNetworkConnection->socketMutexStorage ) ); + + /* Set the output parameter. */ + *pConnection = pNewNetworkConnection; + + IotLogInfo( "(Network connection %p) Connection to %s established.", + pNewNetworkConnection, + pServerInfo->pHostName ); + } + + IOT_FUNCTION_CLEANUP_END(); +} +/*-----------------------------------------------------------*/ + +IotNetworkError_t IotNetworkFreeRTOS_SetReceiveCallback( IotNetworkConnection_t pConnection, + IotNetworkReceiveCallback_t receiveCallback, + void * pContext ) +{ + IotNetworkError_t status = IOT_NETWORK_SUCCESS; + BaseType_t i = 0; + + /* Set the receive callback and context. */ + pConnection->receiveCallback = receiveCallback; + pConnection->pReceiveContext = pContext; + + /* Add this connection to the list of connections that select should check. */ + for( i = 0; i < IOT_NETWORK_MAX_RECEIVE_CALLBACKS; i++ ) + { + if( Atomic_CompareAndSwapPointers_p32( &_connections[ i ], + pConnection, + NULL ) == 1 ) + { + break; + } + } + + if( i == IOT_NETWORK_MAX_RECEIVE_CALLBACKS ) + { + status = IOT_NETWORK_NO_MEMORY; + } + else + { + /* Add this socket to the socket set for the network task. */ + FreeRTOS_FD_SET( pConnection->socket, + _socketSet, + eSELECT_READ ); + } + + return status; +} +/*-----------------------------------------------------------*/ + +size_t IotNetworkFreeRTOS_Send( IotNetworkConnection_t pConnection, + const uint8_t * pMessage, + size_t messageLength ) +{ + size_t bytesSent = 0; + BaseType_t socketStatus = 0; + + /* Only one thread at a time may send on the connection. Lock the send + * mutex to prevent other threads from sending. */ + if( xSemaphoreTake( pConnection->socketMutex, + IOT_NETWORK_SOCKET_TIMEOUT_MS ) == pdTRUE ) + { + #if ( IOT_NETWORK_ENABLE_TLS == 1 ) + if( pConnection->secured == pdTRUE ) + { + while( bytesSent < messageLength ) + { + socketStatus = ( BaseType_t ) mbedtls_ssl_write( &( pConnection->ssl.context ), + pMessage + bytesSent, + messageLength - bytesSent ); + + if( ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_WRITE ) || + ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_READ ) ) + { + /* Try again for WANT_WRITE and WANT_READ errors. */ + continue; + } + else if( socketStatus < 0 ) + { + /* Exit on other errors. */ + break; + } + else + { + bytesSent += ( size_t ) socketStatus; + configASSERT( bytesSent <= messageLength ); + } + } + } + else + #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */ + { + socketStatus = FreeRTOS_send( pConnection->socket, + pMessage, + messageLength, + 0 ); + } + + if( socketStatus > 0 ) + { + bytesSent = ( size_t ) socketStatus; + } + + xSemaphoreGive( pConnection->socketMutex ); + } + + IotLogDebug( "(Network connection %p) Sent %lu bytes.", + pConnection, + ( unsigned long ) bytesSent ); + + return bytesSent; +} +/*-----------------------------------------------------------*/ + +size_t IotNetworkFreeRTOS_Receive( IotNetworkConnection_t pConnection, + uint8_t * pBuffer, + size_t bytesRequested ) +{ + BaseType_t socketStatus = 0; + size_t bytesReceived = 0, bytesRemaining = bytesRequested; + + /* Block and wait for incoming data. */ + while( bytesRemaining > 0 ) + { + #if ( IOT_NETWORK_ENABLE_TLS == 1 ) + if( pConnection->secured == pdTRUE ) + { + if( xSemaphoreTake( pConnection->socketMutex, + IOT_NETWORK_SOCKET_TIMEOUT_MS ) == pdTRUE ) + { + socketStatus = ( BaseType_t ) mbedtls_ssl_read( &( pConnection->ssl.context ), + pBuffer + bytesReceived, + bytesRequested - bytesReceived ); + + xSemaphoreGive( pConnection->socketMutex ); + + if( ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_READ ) || + ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_WRITE ) ) + { + /* Try again for WANT_WRITE and WANT_READ errors. */ + continue; + } + } + else + { + /* Could not obtain socket mutex, exit. */ + break; + } + } + else + #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */ + { + socketStatus = FreeRTOS_recv( pConnection->socket, + pBuffer + bytesReceived, + bytesRemaining, + 0 ); + + if( socketStatus == FREERTOS_EWOULDBLOCK ) + { + /* The return value EWOULDBLOCK means no data was received within + * the socket timeout. Ignore it and try again. */ + continue; + } + } + + if( socketStatus < 0 ) + { + IotLogError( "Error %ld while receiving data.", ( long int ) socketStatus ); + break; + } + else + { + bytesReceived += ( size_t ) socketStatus; + bytesRemaining -= ( size_t ) socketStatus; + + configASSERT( bytesReceived + bytesRemaining == bytesRequested ); + } + } + + if( bytesReceived < bytesRequested ) + { + IotLogWarn( "(Network connection %p) Receive requested %lu bytes, but %lu bytes received instead.", + pConnection, + ( unsigned long ) bytesRequested, + ( unsigned long ) bytesReceived ); + } + else + { + IotLogDebug( "(Network connection %p) Successfully received %lu bytes.", + pConnection, + ( unsigned long ) bytesRequested ); + } + + return bytesReceived; +} + +/*-----------------------------------------------------------*/ + +size_t IotNetworkFreeRTOS_ReceiveUpto( IotNetworkConnection_t pConnection, + uint8_t * pBuffer, + size_t bufferSize ) +{ + int32_t socketStatus = 0; + size_t bytesReceived = 0; + + /* Caller should never pass a zero-length buffer. */ + configASSERT( bufferSize > 0 ); + + #if ( IOT_NETWORK_ENABLE_TLS == 1 ) + if( pConnection->secured == pdTRUE ) + { + if( xSemaphoreTake( pConnection->socketMutex, + IOT_NETWORK_SOCKET_TIMEOUT_MS ) == pdTRUE ) + { + do + { + socketStatus = ( BaseType_t ) mbedtls_ssl_read( &( pConnection->ssl.context ), + pBuffer + bytesReceived, + bufferSize - bytesReceived ); + } while( ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_READ ) || + ( socketStatus == ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_WRITE ) ); + + xSemaphoreGive( pConnection->socketMutex ); + } + else + { + IotLogError( "Could not obtain the socket mutex." ); + } + } + else + #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */ + { + socketStatus = FreeRTOS_recv( pConnection->socket, + pBuffer + bytesReceived, + bufferSize - bytesReceived, + 0 ); + } + + if( socketStatus <= 0 ) + { + IotLogError( "Error %ld while receiving data.", ( long int ) socketStatus ); + } + else + { + bytesReceived += ( size_t ) socketStatus; + } + + IotLogDebug( "Received %lu bytes.", + ( unsigned long ) bytesReceived ); + + return bytesReceived; +} + +/*-----------------------------------------------------------*/ + +IotNetworkError_t IotNetworkFreeRTOS_Close( IotNetworkConnection_t pConnection ) +{ + BaseType_t socketStatus = 0, i = 0; + + #if ( IOT_NETWORK_ENABLE_TLS == 1 ) + /* Notify the peer that the TLS connection is being closed. */ + if( pConnection->secured == pdTRUE ) + { + if( xSemaphoreTake( pConnection->socketMutex, + IOT_NETWORK_SOCKET_TIMEOUT_MS ) == pdTRUE ) + { + socketStatus = ( BaseType_t ) mbedtls_ssl_close_notify( &( pConnection->ssl.context ) ); + + /* Ignore the WANT_READ and WANT_WRITE return values. */ + if( ( socketStatus != ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_READ ) && + ( socketStatus != ( BaseType_t ) MBEDTLS_ERR_SSL_WANT_WRITE ) ) + { + if( socketStatus == 0 ) + { + IotLogInfo( "(Network connection %p) TLS close-notify sent.", + pConnection ); + } + else + { + IotLogWarn( "(Network connection %p) Failed to send TLS close-notify, error %d.", + pConnection, + socketStatus ); + } + } + + xSemaphoreGive( pConnection->socketMutex ); + } + } + #endif /* if ( IOT_NETWORK_ENABLE_TLS == 1 ) */ + + /* Call socket shutdown function to close connection. */ + socketStatus = FreeRTOS_shutdown( pConnection->socket, + FREERTOS_SHUT_RDWR ); + + if( socketStatus != 0 ) + { + IotLogWarn( "(Network connection %p) Failed to close connection.", + pConnection ); + } + else + { + IotLogInfo( "(Network connection %p) Connection closed.", + pConnection ); + } + + /* Remove this connection from Select's socket set (if present). */ + for( i = 0; i < IOT_NETWORK_MAX_RECEIVE_CALLBACKS; i++ ) + { + if( Atomic_CompareAndSwapPointers_p32( &_connections[ i ], NULL, pConnection ) == 1 ) + { + FreeRTOS_FD_CLR( pConnection->socket, _socketSet, eSELECT_ALL ); + } + } + + return IOT_NETWORK_SUCCESS; +} +/*-----------------------------------------------------------*/ + +IotNetworkError_t IotNetworkFreeRTOS_Destroy( IotNetworkConnection_t pConnection ) +{ + FreeRTOS_closesocket( pConnection->socket ); + + #if ( IOT_NETWORK_ENABLE_TLS == 1 ) + /* Free mbed TLS contexts. */ + if( pConnection->secured == pdTRUE ) + { + _sslContextFree( pConnection ); + } + #endif + + /* Free memory used by network connection. */ + vPortFree( pConnection ); + + IotLogInfo( "(Network connection %p) Connection destroyed.", + pConnection ); + + return IOT_NETWORK_SUCCESS; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_taskpool_freertos.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_taskpool_freertos.c new file mode 100644 index 000000000..135afc7a7 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_taskpool_freertos.c @@ -0,0 +1,1006 @@ +/* + * FreeRTOS Task Pool v1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_taskpool_freertos.c + * @brief Implements the task pool functions in iot_taskpool.h for FreeRTOS. + */ + + +/* + * The full IoT Task Pool Library has many use cases, including Linux development. + * Typical FreeRTOS use cases do not require the full functionality so an optimized + * implementation is provided specifically for use with FreeRTOS. The optimized + * version has a fixed number of tasks in the pool, each of which uses statically + * allocated memory to ensure creation of the pool is guaranteed (it does not run out + * of heap space). The constant IOT_TASKPOOL_NUMBER_OF_WORKERS sets the number of + * tasks in the pool. + * + * Unlike the full version, this optimized version: + * + Only supports a single task pool (system task pool) at a time. + * + Does not auto-scale by dynamically adding more tasks if the number of + * tasks in the pool becomes exhausted. The number of tasks in the pool + * are fixed at compile time. See the task pool configuration options for + * more information. + * + Cannot be shut down - it exists for the lifetime of the application. + * + * Users who are interested in the functionality of the full IoT Task Pool + * library can us it in place of this optimized version. + */ + + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "semphr.h" + +/* IoT libraries includes. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include +#include +#include +#include + +#if !defined( configSUPPORT_STATIC_ALLOCATION ) || ( configSUPPORT_STATIC_ALLOCATION != 1 ) + #error configSUPPORT_STATIC_ALLOCATION must be set to 1 in FreeRTOSConfig.h to build this file. +#endif + +/* Task pool internal include. */ +#include "private/iot_taskpool_internal_freertos.h" + +/** + * @brief Maximum semaphore value for wait operations. + */ +#define TASKPOOL_MAX_SEM_VALUE ( ( UBaseType_t ) 0xFFFF ) + +/** + * @brief Reschedule delay in milliseconds for deferred jobs. + */ +#define TASKPOOL_JOB_RESCHEDULE_DELAY_MS ( 10ULL ) + +/* ---------------------------------------------------------------------------------- */ + +/** + * @brief Get the job associated with a timer. + * + * @warning This only works on a _taskPoolTimerEvent_t within a _taskPoolJob_t. + */ +#define GET_JOB_FROM_TIMER(t) ((_taskPoolJob_t *)((uint8_t*)(t) - offsetof(_taskPoolJob_t, timer))) + +/** + * brief The maximum time to wait when attempting to obtain an internal semaphore. + * Don't wait indefinitely to give the application a chance to recover in the case + * of an error. + */ +#define MAX_SEMAPHORE_TAKE_WAIT_TIME_MS ( pdMS_TO_TICKS( 10000UL ) ) +/* ---------------------------------------------------------------------------------- */ + +/** + * Doxygen should ignore this section. + * + * @brief The system task pool handle for all libraries to use. + * User application can use the system task pool as well knowing that the usage will be shared with + * the system libraries as well. The system task pool needs to be initialized before any library is used or + * before any code that posts jobs to the task pool runs. + */ +static _taskPool_t _IotSystemTaskPool = { 0 }; + +/* -------------- Convenience functions to create/recycle/destroy jobs -------------- */ + +/** + * @brief Initialize a job. + * + * @param[in] pJob The job to initialize. + * @param[in] userCallback The user callback for the job. + * @param[in] pUserContext The context to be passed to the callback. + */ +static void _initializeJob( _taskPoolJob_t * const pJob, + IotTaskPoolRoutine_t userCallback, + void * pUserContext ); + +/* -------------- The worker thread procedure for a task pool thread -------------- */ + +/** + * The procedure for a task pool worker thread. + * + * @param[in] pUserContext The user context. + * + */ +static void _taskPoolWorker( void * pUserContext ); + +/* -------------- Convenience functions to handle timer events -------------- */ + +/** + * Comparer for the time list. + * + * param[in] pTimerEventLink1 The link to the first timer event. + * param[in] pTimerEventLink1 The link to the first timer event. + */ +static int32_t _timerEventCompare( const IotLink_t * const pTimerEventLink1, + const IotLink_t * const pTimerEventLink2 ); + +/** + * Reschedules the timer for handling deferred jobs to the next timeout. + * + * param[in] timer The timer to reschedule. + * param[in] pFirstTimerEvent The timer event that carries the timeout and job information. + */ +static void _rescheduleDeferredJobsTimer( TimerHandle_t const timer, + _taskPoolTimerEvent_t * const pFirstTimerEvent ); + +/** + * The task pool timer procedure for scheduling deferred jobs. + * + * param[in] timer The timer to handle. + */ +static void _timerCallback( TimerHandle_t xTimer ); + +/* -------------- Convenience functions to create/initialize/destroy the task pool -------------- */ + +/** + * Initializes a pre-allocated instance of a task pool. + */ +static void _initTaskPoolControlStructures( void ); + +/** + * Initializes a pre-allocated instance of a task pool. + * + * @param[in] pInfo The initialization information for the task pool. + * + */ +static IotTaskPoolError_t _createTaskPool( const IotTaskPoolInfo_t * const pInfo ); + +/** + * Places a job in the dispatch queue. + * + * @param[in] pJob The job to schedule. + * + */ +static void _scheduleInternal( _taskPoolJob_t * const pJob ); +/** + * Matches a deferred job in the timer queue with its timer event wrapper. + * + * @param[in] pLink A pointer to the timer event link in the timer queue. + * @param[in] pMatch A pointer to the job to match. + * + */ +static bool _matchJobByPointer( const IotLink_t * const pLink, + void * pMatch ); + +/** + * Tries to cancel a job. + * + * @param[in] pJob The job to cancel. + * @param[out] pStatus The status of the job at the time of cancellation. + * + */ +static IotTaskPoolError_t _tryCancelInternal( _taskPoolJob_t * const pJob, + IotTaskPoolJobStatus_t * const pStatus ); + +/* ---------------------------------------------------------------------------------------------- */ + +IotTaskPoolError_t IotTaskPool_CreateSystemTaskPool( const IotTaskPoolInfo_t * const pInfo ) +{ + IotTaskPoolError_t status; + static BaseType_t isInitialized = pdFALSE; + + configASSERT( pInfo ); + configASSERT( pInfo->minThreads >= 1UL ); + + /* This version of the task pool does not auto-scale so the specified minimum + number of threads in the pool must match the specified maximum number of threads + in the pool. */ + configASSERT( pInfo->maxThreads == pInfo->minThreads ); + + /* Guard against multiple attempts to create the system task pool in case + this function is called by more than one library initialization routine. */ + taskENTER_CRITICAL(); + { + /* If the task pool has already been initialized then + IOT_TASKPOOL_ILLEGAL_OPERATION will be returned - but that does not guarantee + the initialization operation is complete as the task to which + IOT_TASKPOOL_ILLEGAL_OPERATION is returned may have preempted the task that + was performing the initialization before the initialization was complete - + hence the assert to catch this occurrence during development and debug. */ + configASSERT( isInitialized == pdFALSE ); + + if( isInitialized == pdFALSE ) + { + /* The task pool has not been initialized already so will be initialized + now. */ + status = IOT_TASKPOOL_SUCCESS; + isInitialized = pdTRUE; + } + else + { + /* This function has already been called but executing this path does + not guarantee the task pool has already been initialized as the task + to which this error is returned may have preempted the task that was + performing the initialization before the initialization was complete. */ + status = IOT_TASKPOOL_ILLEGAL_OPERATION; + } + } + taskEXIT_CRITICAL(); + + if( status == IOT_TASKPOOL_SUCCESS ) + { + /* Create the system task pool. Note in this version _createTaskPool() + cannot fail because it is using statically allocated memory. Therefore the + return value can be safely ignored and there is no need to consider resetting + isInitialized in a failure case. */ + ( void ) _createTaskPool( pInfo ); + } + + return status; +} +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_CreateJob( IotTaskPoolRoutine_t userCallback, + void * pUserContext, + IotTaskPoolJobStorage_t * const pJobStorage, + IotTaskPoolJob_t * const ppJob ) +{ + /* Parameter checking. */ + configASSERT( userCallback != NULL ); + configASSERT( pJobStorage != NULL ); + configASSERT( ppJob != NULL ); + + /* Build a job around the user-provided storage. */ + _initializeJob( ( _taskPoolJob_t * ) pJobStorage, userCallback, pUserContext ); + + *ppJob = ( IotTaskPoolJob_t ) pJobStorage; + + return IOT_TASKPOOL_SUCCESS; +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_Schedule( IotTaskPool_t taskPoolHandle, + IotTaskPoolJob_t pJob, + uint32_t flags ) +{ + IotTaskPoolError_t status = IOT_TASKPOOL_SUCCESS; + + /* Task pool must have been created. */ + configASSERT( _IotSystemTaskPool.running != false ); + + /* This lean version of the task pool only supports the task pool created + by this library (the system task pool). NULL means use the system task + pool - no other values are allowed. Use the full implementation of this + library if you want multiple task pools (there is more than one task in + each pool. */ + configASSERT( ( taskPoolHandle == NULL ) || ( taskPoolHandle == &_IotSystemTaskPool ) ); + + /* Avoid compiler warnings about unused parameters if configASSERT() is not + defined. */ + ( void ) taskPoolHandle; + + configASSERT( pJob != NULL ); + configASSERT( ( flags == 0UL ) || ( flags == IOT_TASKPOOL_JOB_HIGH_PRIORITY ) ); + + /* Acquire the mutex for manipulating the job timer queue. */ + if ( xSemaphoreTake( _IotSystemTaskPool.xTimerEventMutex, MAX_SEMAPHORE_TAKE_WAIT_TIME_MS ) == pdTRUE ) + { + _scheduleInternal( pJob ); + if ( xSemaphoreGive( _IotSystemTaskPool.xTimerEventMutex ) == pdFALSE ) + { + /* This can only be reached if semaphores are configured incorrectly. */ + status = IOT_TASKPOOL_GENERAL_FAILURE; + } + /* Signal a worker task that a job was queued. */ + if ( xSemaphoreGive( _IotSystemTaskPool.dispatchSignal ) == pdFALSE ) + { + /* This can only be reached if semaphores are configured incorrectly. */ + status = IOT_TASKPOOL_GENERAL_FAILURE; + } + } + else + { + status = IOT_TASKPOOL_GENERAL_FAILURE; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_ScheduleDeferred( IotTaskPool_t taskPoolHandle, + IotTaskPoolJob_t job, + uint32_t timeMs ) +{ + TickType_t now; + IotTaskPoolError_t status = IOT_TASKPOOL_SUCCESS; + + /* This lean version of the task pool only supports the task pool created + by this library (the system task pool). NULL means use the system task + pool - no other values are allowed. Use the full implementation of this + library if you want multiple task pools (there is more than one task in + each pool. */ + configASSERT( ( taskPoolHandle == NULL ) || ( taskPoolHandle == &_IotSystemTaskPool ) ); + + configASSERT( job != NULL ); + + /* If the timer period is zero, just immediately queue the job for execution. */ + if( timeMs == 0UL ) + { + status = IotTaskPool_Schedule( &_IotSystemTaskPool, job, 0 ); + } + else + { + _taskPoolTimerEvent_t* pTimerEvent = &(job->timer); + + configASSERT( job->timer.link.pNext == NULL ); + + IotLink_t* pTimerEventLink; + + pTimerEvent->link.pNext = NULL; + pTimerEvent->link.pPrevious = NULL; + + now = xTaskGetTickCount(); + pTimerEvent->expirationTime = now + pdMS_TO_TICKS( timeMs ); + + if ( xSemaphoreTake( _IotSystemTaskPool.xTimerEventMutex, MAX_SEMAPHORE_TAKE_WAIT_TIME_MS ) == pdTRUE ) + { + + /* Append the timer event to the timer list. */ + IotListDouble_InsertSorted( &( _IotSystemTaskPool.timerEventsList ), &( pTimerEvent->link ), _timerEventCompare ); + + /* Update the job status to 'scheduled'. */ + job->status = IOT_TASKPOOL_STATUS_DEFERRED; + + /* Peek the first event in the timer event list. There must be at least one, + * since we just inserted it. */ + pTimerEventLink = IotListDouble_PeekHead( &( _IotSystemTaskPool.timerEventsList ) ); + configASSERT( pTimerEventLink != NULL ); + + /* If the event we inserted is at the front of the queue, then + * we need to reschedule the underlying timer. */ + if ( pTimerEventLink == &( pTimerEvent->link ) ) + { + pTimerEvent = IotLink_Container( _taskPoolTimerEvent_t, pTimerEventLink, link ); + + _rescheduleDeferredJobsTimer( _IotSystemTaskPool.timer, pTimerEvent ); + } + + if ( xSemaphoreGive( _IotSystemTaskPool.xTimerEventMutex ) == pdFALSE ) + { + /* This can only be reached if semaphores are configured incorrectly. */ + status = IOT_TASKPOOL_GENERAL_FAILURE; + } + + } + else + { + status = IOT_TASKPOOL_GENERAL_FAILURE; + } + } + + return status; +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_GetStatus( IotTaskPool_t taskPoolHandle, + IotTaskPoolJob_t job, + IotTaskPoolJobStatus_t * const pStatus ) +{ + + /* This lean version of the task pool only supports the task pool created by + this library (the system task pool). NULL means use the system task pool - + no other values are allowed. Use the full implementation of this library if you + want multiple task pools (there is more than one task in each pool. */ + configASSERT( ( taskPoolHandle == NULL ) || ( taskPoolHandle == &_IotSystemTaskPool ) ); + + /* Remove warning about unused parameter. */ + ( void ) taskPoolHandle; + + /* Parameter checking. */ + configASSERT( job != NULL ); + configASSERT( pStatus != NULL ); + + taskENTER_CRITICAL(); + { + *pStatus = job->status; + } + taskEXIT_CRITICAL(); + + return IOT_TASKPOOL_SUCCESS; +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolError_t IotTaskPool_TryCancel( IotTaskPool_t taskPoolHandle, + IotTaskPoolJob_t job, + IotTaskPoolJobStatus_t * const pStatus ) +{ + IotTaskPoolError_t status = IOT_TASKPOOL_SUCCESS; + const TickType_t dontBlock = ( TickType_t ) 0; + + /* This lean version of the task pool only supports the task pool created + by this library (the system task pool). NULL means use the system task + pool - no other values are allowed. Use the full implementation of this + library if you want multiple task pools (there is more than one task in + each pool. */ + configASSERT( ( taskPoolHandle == NULL ) || ( taskPoolHandle == &_IotSystemTaskPool ) ); + + if( job != NULL ) + { + if( pStatus != NULL ) + { + *pStatus = IOT_TASKPOOL_STATUS_UNDEFINED; + } + + if ( xSemaphoreTake( _IotSystemTaskPool.xTimerEventMutex, dontBlock ) != pdFALSE ) + { + status = _tryCancelInternal( job, pStatus ); + if ( xSemaphoreGive( _IotSystemTaskPool.xTimerEventMutex ) == pdFALSE ) + { + /* This can only be reached if semaphores are configured incorrectly. */ + status = IOT_TASKPOOL_GENERAL_FAILURE; + } + } + else + { + /* If we fail to take the semaphore, just abort the cancel. */ + status = IOT_TASKPOOL_CANCEL_FAILED; + } + } + else + { + status = IOT_TASKPOOL_BAD_PARAMETER; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +IotTaskPoolJobStorage_t * IotTaskPool_GetJobStorageFromHandle( IotTaskPoolJob_t pJob ) +{ + return ( IotTaskPoolJobStorage_t * ) pJob; +} + +/*-----------------------------------------------------------*/ + +const char * IotTaskPool_strerror( IotTaskPoolError_t status ) +{ + const char * pMessage = NULL; + + switch( status ) + { + case IOT_TASKPOOL_SUCCESS: + pMessage = "SUCCESS"; + break; + + case IOT_TASKPOOL_BAD_PARAMETER: + pMessage = "BAD PARAMETER"; + break; + + case IOT_TASKPOOL_ILLEGAL_OPERATION: + pMessage = "ILLEGAL OPERATION"; + break; + + case IOT_TASKPOOL_NO_MEMORY: + pMessage = "NO MEMORY"; + break; + + case IOT_TASKPOOL_SHUTDOWN_IN_PROGRESS: + pMessage = "SHUTDOWN IN PROGRESS"; + break; + + case IOT_TASKPOOL_CANCEL_FAILED: + pMessage = "CANCEL FAILED"; + break; + + case IOT_TASKPOOL_GENERAL_FAILURE: + pMessage = "GENERAL FAILURE"; + break; + + default: + pMessage = "INVALID STATUS"; + break; + } + + return pMessage; +} + +/* ---------------------------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------------------------------- */ + +static void _initTaskPoolControlStructures( void ) +{ + /* Initialize a job data structures that require no de-initialization. + * All other data structures carry a value of 'NULL' before initialization. + */ + IotDeQueue_Create( &( _IotSystemTaskPool.dispatchQueue ) ); + IotListDouble_Create( &( _IotSystemTaskPool.timerEventsList ) ); + + /* Initialize the semaphore for waiting for incoming work. Cannot fail as + statically allocated. */ + _IotSystemTaskPool.dispatchSignal = xSemaphoreCreateCountingStatic( TASKPOOL_MAX_SEM_VALUE, 0, &( _IotSystemTaskPool.dispatchSignalBuffer ) ); + _IotSystemTaskPool.xTimerEventMutex = xSemaphoreCreateMutexStatic( &( _IotSystemTaskPool.xTimerEventMutexBuffer ) ); +} + +static IotTaskPoolError_t _createTaskPool( const IotTaskPoolInfo_t * const pInfo ) +{ + /* The taskpool will create a number of threads equal to the minThreads + setting. The number of workers should be equal to avoid over/under + allocation. */ + configASSERT( IOT_TASKPOOL_NUMBER_OF_WORKERS == pInfo->minThreads ); + + /* Static TCB structures and arrays to be used by statically allocated worker + tasks. */ + static StaticTask_t workerTaskTCBs[ IOT_TASKPOOL_NUMBER_OF_WORKERS ]; + static StackType_t workerTaskStacks[ IOT_TASKPOOL_NUMBER_OF_WORKERS ][ IOT_TASKPOOL_WORKER_STACK_SIZE_BYTES / sizeof( portSTACK_TYPE ) ]; + + /* Static structure to hold the software timer. */ + static StaticTimer_t staticTimer; + + uint32_t threadsCreated = 0; /* Although initialized before use removing the initializer here results in compiler warnings. */ + char taskName[ 10 ]; + + + /* This assert is primarily to catch the function being called more than once, + but will also ensure the C start up code has zeroed out the structure + correctly. */ + #if( configASSERT_DEFINED == 1 ) + { + size_t x; + uint8_t *pucNextByte = ( uint8_t * ) &_IotSystemTaskPool; + + for( x = 0; x < sizeof( _taskPool_t ); x++ ) + { + configASSERT( pucNextByte[ x ] == ( uint8_t ) 0x00 ); + } + } + #endif /* configASSERT_DEFINED */ + + + + /* Initialize all internal data structure prior to creating all threads. */ + _initTaskPoolControlStructures(); + + /* Create the FreeRTOS timer for managing Task Pool timers. */ + _IotSystemTaskPool.timer = xTimerCreateStatic( NULL, /* Text name for the timer, only used for debugging. */ + portMAX_DELAY, /* Timer period in ticks. */ + pdFALSE, /* pdFALSE means its a one-shot timer. */ + ( void * ) &_IotSystemTaskPool, /* Parameter passed into callback. */ + _timerCallback, /* Callback that executes when the timer expires. */ + &staticTimer ); /* Static storage for the timer's data structure. */ + + /* The task pool will initialize the minimum number of threads requested by the user upon start. + Note this tailored version of the task pool does not auto-scale, but fixes the number of tasks + in the pool to the originally specified minimum, and the specified maximum value is ignored. */ + /* Create the minimum number of threads specified by the user, and if one fails shutdown and return error. */ + for( threadsCreated = 0; threadsCreated < pInfo->minThreads; ) + { + /* Generate a unique name for the task. */ + snprintf( taskName, sizeof( taskName ), "pool%d", ( int ) threadsCreated ); + + xTaskCreateStatic( _taskPoolWorker, /* Function that implements the task. */ + taskName, /* Text name for the task, used for debugging only. */ + IOT_TASKPOOL_WORKER_STACK_SIZE_BYTES / sizeof( portSTACK_TYPE ), /* xTaskCreate() expects the stack size to be specified in words. */ + &_IotSystemTaskPool, /* Parameter passed into the task. */ + pInfo->priority, /* Priority at which the task starts running. */ + &( workerTaskStacks[ threadsCreated ][ 0 ] ), /* Pointer to static storage for the task's stack. */ + &( workerTaskTCBs[ threadsCreated ] ) ); /* Pointer to static storage for the task's TCB. */ + + ++threadsCreated; + } + _IotSystemTaskPool.running = true; + + /* This version of this function cannot fail as all the memory is allocated + statically at compile time. */ + return IOT_TASKPOOL_SUCCESS; +} + +/* ---------------------------------------------------------------------------------------------- */ + +static void _taskPoolWorker( void * pUserContext ) +{ + configASSERT( pUserContext != NULL ); + + IotTaskPoolRoutine_t userCallback = NULL; + + /* Extract pTaskPool pointer from context. */ + _taskPool_t * pTaskPool = ( _taskPool_t * ) pUserContext; + + /* OUTER LOOP: it controls the lifetime of the worker thread. */ + for( ; ; ) + { + IotLink_t * pFirst = NULL; + _taskPoolJob_t * pJob = NULL; + + /* Wait on incoming notifications... */ + configASSERT( pTaskPool->dispatchSignal ); + + /* If the semaphore for job dispatch expires without a job, a critical + precondition of this task has not been met. See the xBlockTime + parameter of xSemaphoreTake for details. */ + configASSERT( xSemaphoreTake( pTaskPool->dispatchSignal, portMAX_DELAY ) ); + + /* Acquire the lock to check for incoming notifications. This call + should not expire. See the xBlockTime parameter of xSemaphoreTake + for details. */ + configASSERT( xSemaphoreTake( pTaskPool->xTimerEventMutex, portMAX_DELAY ) ); + + /* Dequeue the first job in FIFO order. */ + pFirst = IotDeQueue_DequeueHead( &pTaskPool->dispatchQueue ); + + /* If there is indeed a job, then update status under lock, and release the lock before processing the job. */ + if( pFirst != NULL ) + { + /* Extract the job from its link. */ + pJob = IotLink_Container( _taskPoolJob_t, pFirst, link ); + + /* Update status to 'completed' to indicate it is queued for execution. */ + pJob->status = IOT_TASKPOOL_STATUS_COMPLETED; + userCallback = pJob->userCallback; + } + + /* Release the lock now that the job dispatch queue has been checked. + This call should not expire. See the xBlockTime parameter of + xSemaphoreTake for details. */ + configASSERT( xSemaphoreGive( pTaskPool->xTimerEventMutex ) ); + + /* INNER LOOP: it controls the execution of jobs: the exit condition is the lack of a job to execute. */ + while( pJob != NULL ) + { + /* Process the job by invoking the associated callback with the user context. + * This task pool thread will not be available until the user callback returns. + */ + { + configASSERT( IotLink_IsLinked( &pJob->link ) == false ); + configASSERT( userCallback != NULL ); + + userCallback( pTaskPool, pJob, pJob->pUserContext ); + + /* This job is finished, clear its pointer. */ + pJob = NULL; + userCallback = NULL; + } + + /* Acquire the lock to check for incoming notifications. This call + should not expire. See the xBlockTime parameter of xSemaphoreTake + for details. */ + configASSERT( xSemaphoreTake( pTaskPool->xTimerEventMutex, portMAX_DELAY ) ); + { + /* Try and dequeue the next job in the dispatch queue. */ + IotLink_t * pItem = NULL; + + /* Dequeue the next job from the dispatch queue. */ + pItem = IotDeQueue_DequeueHead( &( pTaskPool->dispatchQueue ) ); + + /* If there is no job left in the dispatch queue, update the worker status and leave. */ + if( pItem == NULL ) + { + /* Release the lock before exiting the loop. */ + configASSERT( xSemaphoreGive( pTaskPool->xTimerEventMutex ) ); + + /* Abandon the INNER LOOP. Execution will transfer back to the OUTER LOOP condition. */ + break; + } + else + { + pJob = IotLink_Container( _taskPoolJob_t, pItem, link ); + + userCallback = pJob->userCallback; + } + + pJob->status = IOT_TASKPOOL_STATUS_COMPLETED; + } + /* Release the lock now that the job dispatch queue has been checked. */ + configASSERT( xSemaphoreGive( pTaskPool->xTimerEventMutex ) ); + } + } +} + +/* ---------------------------------------------------------------------------------------------- */ + +static void _initializeJob( _taskPoolJob_t * const pJob, + IotTaskPoolRoutine_t userCallback, + void * pUserContext ) +{ + memset( ( void * ) pJob, 0x00, sizeof( _taskPoolJob_t ) ); + + pJob->userCallback = userCallback; + pJob->pUserContext = pUserContext; + pJob->status = IOT_TASKPOOL_STATUS_READY; +} + +/* ---------------------------------------------------------------------------------------------- */ + +static void _scheduleInternal( _taskPoolJob_t * const pJob ) +{ + /* Update the job status to 'scheduled'. */ + pJob->status = IOT_TASKPOOL_STATUS_SCHEDULED; + + /* Append the job to the dispatch queue. */ + IotDeQueue_EnqueueTail( &( _IotSystemTaskPool.dispatchQueue ), &( pJob->link ) ); + + /* NOTE: Every call to this function must be followed by giving the + dispatchSignal semaphore - but do not give the semaphore directly in + this function as giving the semaphore will result in the execution of + a task pool worker task (depending on relative priorities) and we don't + want the worker task to execute until all semaphores obtained before calling + this function have been released. */ +} + +/*-----------------------------------------------------------*/ + +static bool _matchJobByPointer( const IotLink_t * const pLink, + void * pMatch ) +{ + const _taskPoolJob_t * const pJob = ( _taskPoolJob_t * ) pMatch; + + const _taskPoolTimerEvent_t * const pTimerEvent = IotLink_Container( _taskPoolTimerEvent_t, pLink, link ); + + if( pJob == GET_JOB_FROM_TIMER( pTimerEvent ) ) + { + return true; + } + + return false; +} + +/*-----------------------------------------------------------*/ + +static IotTaskPoolError_t _tryCancelInternal( _taskPoolJob_t * const pJob, + IotTaskPoolJobStatus_t * const pStatus ) +{ + IotTaskPoolError_t result = IOT_TASKPOOL_SUCCESS; + + bool cancelable = false; + + /* We can only cancel jobs that are either 'ready' (waiting to be scheduled). 'deferred', or 'scheduled'. */ + + IotTaskPoolJobStatus_t currentStatus = pJob->status; + + switch( currentStatus ) + { + case IOT_TASKPOOL_STATUS_READY: + case IOT_TASKPOOL_STATUS_DEFERRED: + case IOT_TASKPOOL_STATUS_SCHEDULED: + case IOT_TASKPOOL_STATUS_CANCELED: + cancelable = true; + break; + + case IOT_TASKPOOL_STATUS_COMPLETED: + /* Log message for debug purposes. */ + IotLogWarn( "Attempt to cancel a job that is already executing, or canceled." ); + break; + + default: + /* Log message for debug purposes. */ + IotLogError( "Attempt to cancel a job with an undefined state." ); + break; + } + + /* Update the returned status to the current status of the job. */ + if( pStatus != NULL ) + { + *pStatus = currentStatus; + } + + if( cancelable == false ) + { + result = IOT_TASKPOOL_CANCEL_FAILED; + } + else + { + /* Update the status of the job. */ + pJob->status = IOT_TASKPOOL_STATUS_CANCELED; + + /* If the job is cancelable and its current status is 'scheduled' then unlink it from the dispatch + * queue and signal any waiting threads. */ + if( currentStatus == IOT_TASKPOOL_STATUS_SCHEDULED ) + { + /* A scheduled work items must be in the dispatch queue. */ + configASSERT( IotLink_IsLinked( &pJob->link ) ); + + IotDeQueue_Remove( &pJob->link ); + } + + /* If the job current status is 'deferred' then the job has to be pending + * in the timeouts queue. */ + else if( currentStatus == IOT_TASKPOOL_STATUS_DEFERRED ) + { + /* Find the timer event associated with the current job. There MUST be one, hence assert if not. */ + IotLink_t * pTimerEventLink = IotListDouble_FindFirstMatch( &( _IotSystemTaskPool.timerEventsList ), NULL, _matchJobByPointer, pJob ); + configASSERT( pTimerEventLink != NULL ); + + if( pTimerEventLink != NULL ) + { + bool shouldReschedule = false; + + /* If the job being canceled was at the head of the timeouts queue, then we need to reschedule the timer + * with the next job timeout */ + IotLink_t * pHeadLink = IotListDouble_PeekHead( &( _IotSystemTaskPool.timerEventsList ) ); + + if( pHeadLink == pTimerEventLink ) + { + shouldReschedule = true; + } + + /* Remove the timer event associated with the canceled job and free the associated memory. */ + IotListDouble_Remove( pTimerEventLink ); + memset( IotLink_Container( _taskPoolTimerEvent_t, pTimerEventLink, link ), 0, sizeof( IotLink_t ) ); + + if( shouldReschedule ) + { + IotLink_t * pNextTimerEventLink = IotListDouble_PeekHead( &( _IotSystemTaskPool.timerEventsList ) ); + + if( pNextTimerEventLink != NULL ) + { + _rescheduleDeferredJobsTimer( _IotSystemTaskPool.timer, IotLink_Container( _taskPoolTimerEvent_t, pNextTimerEventLink, link ) ); + } + } + } + } + else + { + /* A cancelable job status should be either 'scheduled' or 'deferred'. */ + configASSERT( ( currentStatus == IOT_TASKPOOL_STATUS_READY ) || ( currentStatus == IOT_TASKPOOL_STATUS_CANCELED ) ); + } + } + + return result; +} + +/*-----------------------------------------------------------*/ + +static int32_t _timerEventCompare( const IotLink_t * const pTimerEventLink1, + const IotLink_t * const pTimerEventLink2 ) +{ + const _taskPoolTimerEvent_t * const pTimerEvent1 = IotLink_Container( _taskPoolTimerEvent_t, + pTimerEventLink1, + link ); + const _taskPoolTimerEvent_t * const pTimerEvent2 = IotLink_Container( _taskPoolTimerEvent_t, + pTimerEventLink2, + link ); + + if( pTimerEvent1->expirationTime < pTimerEvent2->expirationTime ) + { + return -1; + } + + if( pTimerEvent1->expirationTime > pTimerEvent2->expirationTime ) + { + return 1; + } + + return 0; +} + +/*-----------------------------------------------------------*/ + +static void _rescheduleDeferredJobsTimer( TimerHandle_t const timer, + _taskPoolTimerEvent_t * const pFirstTimerEvent ) +{ + uint64_t delta = 0; + TickType_t now = xTaskGetTickCount(); + + configASSERT( pFirstTimerEvent != NULL ); + configASSERT( timer != NULL ); + + /* Determine how much time is left for the deferred job. */ + if( pFirstTimerEvent->expirationTime > now ) + { + delta = pFirstTimerEvent->expirationTime - now; + } + + /* If the job timer has exceeded it's period, schedule it to be executed shortly. */ + if( delta < TASKPOOL_JOB_RESCHEDULE_DELAY_MS ) + { + delta = TASKPOOL_JOB_RESCHEDULE_DELAY_MS; /* The job will be late... */ + } + + /* Change the period of the task pools timer to be the period of this + timer. A precondition of this function is that this TimerEvent is the + timer event with the shortest deadline. + */ + if( xTimerChangePeriod( timer, ( uint32_t ) delta, portMAX_DELAY ) == pdFAIL ) + { + IotLogWarn( "Failed to re-arm timer for task pool" ); + } +} + +/*-----------------------------------------------------------*/ + +static void _timerCallback( TimerHandle_t xTimer ) +{ + _taskPool_t * pTaskPool = pvTimerGetTimerID( xTimer ); + + configASSERT( pTaskPool ); + + _taskPoolTimerEvent_t * pTimerEvent = NULL; + BaseType_t numberOfSchedules = 0; + + IotLogDebug( "Timer thread started for task pool %p.", pTaskPool ); + + /* Attempt to lock the timer mutex. Return immediately if the mutex cannot be locked. + * If this mutex cannot be locked it means that another thread is manipulating the + * timeouts list, and will reset the timer to fire again, although it will be late. + */ + if ( xSemaphoreTake( pTaskPool->xTimerEventMutex, 0 ) == pdPASS ) + { + + /* Dispatch all deferred job whose timer expired, then reset the timer for the next + * job down the line. */ + for( ; ; ) + { + /* Peek the first event in the timer event list. */ + IotLink_t * pLink = IotListDouble_PeekHead( &pTaskPool->timerEventsList ); + + /* Check if the timer misfired for any reason. */ + if( pLink != NULL ) + { + /* Record the current time. */ + TickType_t now = xTaskGetTickCount(); + + /* Extract the job from its envelope. */ + pTimerEvent = IotLink_Container( _taskPoolTimerEvent_t, pLink, link ); + + /* Check if the first event should be processed now. */ + if( pTimerEvent->expirationTime <= now ) + { + /* Remove the timer event for immediate processing. */ + IotListDouble_Remove( &( pTimerEvent->link ) ); + } + else + { + /* The first element in the timer queue shouldn't be processed yet. + * Arm the timer for when it should be processed and leave altogether. */ + _rescheduleDeferredJobsTimer( pTaskPool->timer, pTimerEvent ); + break; + } + } + /* If there are no timer events to process, terminate this thread. */ + else + { + IotLogDebug( "Finished scheduling deferred jobs." ); + break; + } + + /* Queue the job associated with the received timer event. */ + _scheduleInternal( GET_JOB_FROM_TIMER( pTimerEvent ) ); + numberOfSchedules++; + IotLogDebug( "Scheduled a job." ); + + /* Free the timer event. */ + memset( &( pTimerEvent->link ), 0, sizeof( pTimerEvent->link ) ); + } + + /* Release mutex guarding the timer list. */ + configASSERT( xSemaphoreGive( pTaskPool->xTimerEventMutex ) == pdPASS ); + + for (; numberOfSchedules > 0; numberOfSchedules--) + { + /* Signal a worker task that a job was queued. */ + configASSERT( xSemaphoreGive( pTaskPool->dispatchSignal ) ); + } + } + +} diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_threads_freertos.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_threads_freertos.c new file mode 100644 index 000000000..e1d8119f6 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/iot_threads_freertos.c @@ -0,0 +1,365 @@ +/* + * Amazon FreeRTOS Platform V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_threads_freertos.c + * @brief Implementation of the platform specific functions in iot_threads.h for + * FreeRTOS. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +#include "semphr.h" + +/* Platform threads include. */ +#include "platform/iot_platform_types_freertos.h" +#include "platform/iot_threads.h" +#include "types/iot_platform_types.h" + +/* Configure logs for the functions in this file. */ +#ifdef IOT_LOG_LEVEL_PLATFORM + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_PLATFORM +#else + #ifdef IOT_LOG_LEVEL_GLOBAL + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_GLOBAL + #else + #define LIBRARY_LOG_LEVEL IOT_LOG_NONE + #endif +#endif + +#define LIBRARY_LOG_NAME ( "THREAD" ) +#include "iot_logging_setup.h" + +/* + * Provide default values for undefined memory allocation functions based on + * the usage of dynamic memory allocation. + */ +#ifndef IotThreads_Malloc + #include + +/** + * @brief Memory allocation. This function should have the same signature + * as [malloc](http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html). + */ + #define IotThreads_Malloc malloc +#endif +#ifndef IotThreads_Free + #include + +/** + * @brief Free memory. This function should have the same signature as + * [free](http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ + #define IotThreads_Free free +#endif + +/*-----------------------------------------------------------*/ + +static void _threadRoutineWrapper( void * pArgument ) +{ + threadInfo_t * pThreadInfo = ( threadInfo_t * ) pArgument; + + /* Run the thread routine. */ + pThreadInfo->threadRoutine( pThreadInfo->pArgument ); + IotThreads_Free( pThreadInfo ); + + vTaskDelete( NULL ); +} + +/*-----------------------------------------------------------*/ + +bool Iot_CreateDetachedThread( IotThreadRoutine_t threadRoutine, + void * pArgument, + int32_t priority, + size_t stackSize ) +{ + bool status = true; + + configASSERT( threadRoutine != NULL ); + + IotLogDebug( "Creating new thread." ); + threadInfo_t * pThreadInfo = IotThreads_Malloc( sizeof( threadInfo_t ) ); + + if( pThreadInfo == NULL ) + { + IotLogDebug( "Unable to allocate memory for threadRoutine %p.", threadRoutine ); + status = false; + } + + /* Create the FreeRTOS task that will run the thread. */ + if( status ) + { + pThreadInfo->threadRoutine = threadRoutine; + pThreadInfo->pArgument = pArgument; + + if( xTaskCreate( _threadRoutineWrapper, + "iot_thread", + ( configSTACK_DEPTH_TYPE ) stackSize, + pThreadInfo, + priority, + NULL ) != pdPASS ) + { + /* Task creation failed. */ + IotLogWarn( "Failed to create thread." ); + IotThreads_Free( pThreadInfo ); + status = false; + } + } + + return status; +} + +/*-----------------------------------------------------------*/ + +bool IotMutex_Create( IotMutex_t * pNewMutex, + bool recursive ) +{ + _IotSystemMutex_t * internalMutex = ( _IotSystemMutex_t * ) pNewMutex; + + configASSERT( internalMutex != NULL ); + + IotLogDebug( "Creating new mutex %p.", pNewMutex ); + + if( recursive ) + { + ( void ) xSemaphoreCreateRecursiveMutexStatic( &internalMutex->xMutex ); + } + else + { + ( void ) xSemaphoreCreateMutexStatic( &internalMutex->xMutex ); + } + + /* remember the type of mutex */ + if( recursive ) + { + internalMutex->recursive = pdTRUE; + } + else + { + internalMutex->recursive = pdFALSE; + } + + return true; +} + +/*-----------------------------------------------------------*/ + +void IotMutex_Destroy( IotMutex_t * pMutex ) +{ + _IotSystemMutex_t * internalMutex = ( _IotSystemMutex_t * ) pMutex; + + configASSERT( internalMutex != NULL ); + + vSemaphoreDelete( ( SemaphoreHandle_t ) &internalMutex->xMutex ); +} + +/*-----------------------------------------------------------*/ + +bool prIotMutexTimedLock( IotMutex_t * pMutex, + TickType_t timeout ) +{ + _IotSystemMutex_t * internalMutex = ( _IotSystemMutex_t * ) pMutex; + BaseType_t lockResult; + + configASSERT( internalMutex != NULL ); + + IotLogDebug( "Locking mutex %p.", internalMutex ); + + /* Call the correct FreeRTOS mutex take function based on mutex type. */ + if( internalMutex->recursive == pdTRUE ) + { + lockResult = xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) &internalMutex->xMutex, timeout ); + } + else + { + lockResult = xSemaphoreTake( ( SemaphoreHandle_t ) &internalMutex->xMutex, timeout ); + } + + return( lockResult == pdTRUE ); +} + +/*-----------------------------------------------------------*/ + +void IotMutex_Lock( IotMutex_t * pMutex ) +{ + prIotMutexTimedLock( pMutex, portMAX_DELAY ); +} + +/*-----------------------------------------------------------*/ + +bool IotMutex_TryLock( IotMutex_t * pMutex ) +{ + return prIotMutexTimedLock( pMutex, 0 ); +} + +/*-----------------------------------------------------------*/ + +void IotMutex_Unlock( IotMutex_t * pMutex ) +{ + _IotSystemMutex_t * internalMutex = ( _IotSystemMutex_t * ) pMutex; + + configASSERT( internalMutex != NULL ); + + IotLogDebug( "Unlocking mutex %p.", internalMutex ); + + /* Call the correct FreeRTOS mutex unlock function based on mutex type. */ + if( internalMutex->recursive == pdTRUE ) + { + ( void ) xSemaphoreGiveRecursive( ( SemaphoreHandle_t ) &internalMutex->xMutex ); + } + else + { + ( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &internalMutex->xMutex ); + } +} + +/*-----------------------------------------------------------*/ + +bool IotSemaphore_Create( IotSemaphore_t * pNewSemaphore, + uint32_t initialValue, + uint32_t maxValue ) +{ + _IotSystemSemaphore_t * internalSemaphore = ( _IotSystemSemaphore_t * ) pNewSemaphore; + + configASSERT( internalSemaphore != NULL ); + + IotLogDebug( "Creating new semaphore %p.", pNewSemaphore ); + + ( void ) xSemaphoreCreateCountingStatic( maxValue, initialValue, &internalSemaphore->xSemaphore ); + + return true; +} + +/*-----------------------------------------------------------*/ + +uint32_t IotSemaphore_GetCount( IotSemaphore_t * pSemaphore ) +{ + _IotSystemSemaphore_t * internalSemaphore = ( _IotSystemSemaphore_t * ) pSemaphore; + UBaseType_t count = 0; + + configASSERT( internalSemaphore != NULL ); + + count = uxSemaphoreGetCount( ( SemaphoreHandle_t ) &internalSemaphore->xSemaphore ); + + IotLogDebug( "Semaphore %p has count %d.", pSemaphore, count ); + + return ( uint32_t ) count; +} + +/*-----------------------------------------------------------*/ + +void IotSemaphore_Destroy( IotSemaphore_t * pSemaphore ) +{ + _IotSystemSemaphore_t * internalSemaphore = ( _IotSystemSemaphore_t * ) pSemaphore; + + configASSERT( internalSemaphore != NULL ); + + IotLogDebug( "Destroying semaphore %p.", internalSemaphore ); + + vSemaphoreDelete( ( SemaphoreHandle_t ) &internalSemaphore->xSemaphore ); +} + +/*-----------------------------------------------------------*/ + +void IotSemaphore_Wait( IotSemaphore_t * pSemaphore ) +{ + _IotSystemSemaphore_t * internalSemaphore = ( _IotSystemSemaphore_t * ) pSemaphore; + + configASSERT( internalSemaphore != NULL ); + + IotLogDebug( "Waiting on semaphore %p.", internalSemaphore ); + + /* Take the semaphore using the FreeRTOS API. */ + if( xSemaphoreTake( ( SemaphoreHandle_t ) &internalSemaphore->xSemaphore, + portMAX_DELAY ) != pdTRUE ) + { + IotLogWarn( "Failed to wait on semaphore %p.", + pSemaphore ); + + /* There is an assert here because during debugging we could falsely + * believe that we are waiting successfully on a semaphore. */ + configASSERT( false ); + } +} + +/*-----------------------------------------------------------*/ + +bool IotSemaphore_TryWait( IotSemaphore_t * pSemaphore ) +{ + _IotSystemSemaphore_t * internalSemaphore = ( _IotSystemSemaphore_t * ) pSemaphore; + + configASSERT( internalSemaphore != NULL ); + + IotLogDebug( "Attempting to wait on semaphore %p.", internalSemaphore ); + + return IotSemaphore_TimedWait( pSemaphore, 0 ); +} + +/*-----------------------------------------------------------*/ + +bool IotSemaphore_TimedWait( IotSemaphore_t * pSemaphore, + uint32_t timeoutMs ) +{ + _IotSystemSemaphore_t * internalSemaphore = ( _IotSystemSemaphore_t * ) pSemaphore; + + configASSERT( internalSemaphore != NULL ); + + /* Take the semaphore using the FreeRTOS API. Cast the calculation to 64 bit to avoid overflows. */ + if( xSemaphoreTake( ( SemaphoreHandle_t ) &internalSemaphore->xSemaphore, + pdMS_TO_TICKS( timeoutMs ) ) != pdTRUE ) + { + /* Only warn if timeout > 0. */ + if( timeoutMs > 0 ) + { + IotLogWarn( "Timeout waiting on semaphore %p.", + internalSemaphore ); + } + + return false; + } + + return true; +} + +/*-----------------------------------------------------------*/ + +void IotSemaphore_Post( IotSemaphore_t * pSemaphore ) +{ + _IotSystemSemaphore_t * internalSemaphore = ( _IotSystemSemaphore_t * ) pSemaphore; + + configASSERT( internalSemaphore != NULL ); + + IotLogDebug( "Posting to semaphore %p.", internalSemaphore ); + /* Give the semaphore using the FreeRTOS API. */ + BaseType_t result = xSemaphoreGive( ( SemaphoreHandle_t ) &internalSemaphore->xSemaphore ); + + if( result == pdFALSE ) + { + IotLogDebug( "Unable to give semaphore over maximum", internalSemaphore ); + } +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/private/iot_taskpool_internal_freertos.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/private/iot_taskpool_internal_freertos.h new file mode 100644 index 000000000..646996425 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/abstractions/platform/freertos/private/iot_taskpool_internal_freertos.h @@ -0,0 +1,110 @@ +/* + * IoT Common V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_taskpool_internal.h + * @brief Internal header of task pool library. This header should not be included in + * typical application code. + */ + +#ifndef IOT_TASKPOOL_INTERNAL_H_ +#define IOT_TASKPOOL_INTERNAL_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Task pool include. */ +#include "iot_error.h" +#include "iot_taskpool_freertos.h" + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "semphr.h" +#include "timers.h" + +/* Configure logs for TASKPOOL functions. */ +#ifdef IOT_LOG_LEVEL_TASKPOOL + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_TASKPOOL +#else + #ifdef IOT_LOG_LEVEL_GLOBAL + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_GLOBAL + #else + #define LIBRARY_LOG_LEVEL IOT_LOG_NONE + #endif +#endif + +#define LIBRARY_LOG_NAME ( "TASKPOOL" ) +#include "iot_logging_setup.h" + +/* ---------------------------------------------------------------------------------------------- */ + +/** + * @brief The task pool data structure keeps track of the internal state and the signals for the dispatcher threads. + * The task pool is a thread safe data structure. + * + * @warning This is a system-level data type that should not be modified or used directly in any application. + * @warning This is a system-level data type that can and will change across different versions of the platform, with no regards for backward compatibility. + * + */ +typedef struct _taskPool +{ + IotDeQueue_t dispatchQueue; /**< @brief The queue for the jobs waiting to be executed. */ + IotListDouble_t timerEventsList; /**< @brief The timeouts queue for all deferred jobs waiting to be executed. */ + SemaphoreHandle_t dispatchSignal; /**< @brief The synchronization object on which threads are waiting for incoming jobs. */ + StaticSemaphore_t dispatchSignalBuffer; /**< @brief The semaphore buffer. */ + SemaphoreHandle_t xTimerEventMutex; /**< @brief The mutex for guarding the Timer Event Queue. */ + StaticSemaphore_t xTimerEventMutexBuffer; /**< @brief The buffer for statically allocating the mutex. */ + TimerHandle_t timer; /**< @brief The timer for deferred jobs. */ + StaticTimer_t timerBuffer; /**< @brief The timer buffer. */ + bool running; /**< @brief A flag to track whether the task pool is operational or should shut down. */ +} _taskPool_t; + +/** + * @brief Represents an operation that is subject to a timer. + * + * These events are queued per MQTT connection. They are sorted by their + * expiration time. + */ +typedef struct _taskPoolTimerEvent +{ + IotLink_t link; /**< @brief List link member. */ + TickType_t expirationTime; /**< @brief When this event should be processed. */ +} _taskPoolTimerEvent_t; + +/** + * @brief The job data structure keeps track of the user callback and context, as well as the status of the job. + * + * @warning This is a system-level data type that should not be modified or used directly in any application. + * @warning This is a system-level data type that can and will change across different versions of the platform, with no regards for backward compatibility. + * + */ +typedef struct _taskPoolJob +{ + IotLink_t link; /**< @brief The link to insert the job in the dispatch queue. */ + IotTaskPoolRoutine_t userCallback; /**< @brief The user provided callback. */ + void * pUserContext; /**< @brief The user provided context. */ + IotTaskPoolJobStatus_t status; /**< @brief The status for the job. */ + _taskPoolTimerEvent_t timer; /**< @brief The timer for scheduling this job deferred. */ +} _taskPoolJob_t; + + +#endif /* ifndef IOT_TASKPOOL_INTERNAL_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/include/aws_iot.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/include/aws_iot.h new file mode 100644 index 000000000..3c1aacd3f --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/include/aws_iot.h @@ -0,0 +1,305 @@ +/* + * AWS IoT Common V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot.h + * @brief Provides routines and constants that are common to AWS IoT libraries. + * This header should not be included in typical application code. + */ + +#ifndef AWS_IOT_H_ +#define AWS_IOT_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include + +/* Platform types include. */ +#include "types/iot_platform_types.h" + +/* MQTT types include. */ +#include "types/iot_mqtt_types.h" + +/** + * @brief The longest Thing Name accepted by AWS IoT, per the [AWS IoT + * Service Limits](https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html#limits_iot). + */ +#define AWS_IOT_MAX_THING_NAME_LENGTH ( 128 ) + +/** + * @brief The common prefix of all AWS IoT MQTT topics. + */ +#define AWS_IOT_TOPIC_PREFIX "$aws/things/" + +/** + * @brief The length of #AWS_IOT_TOPIC_PREFIX. + */ +#define AWS_IOT_TOPIC_PREFIX_LENGTH ( ( uint16_t ) ( sizeof( AWS_IOT_TOPIC_PREFIX ) - 1 ) ) + +/** + * @brief The suffix for an AWS IoT operation "accepted" topic. + */ +#define AWS_IOT_ACCEPTED_SUFFIX "/accepted" + +/** + * @brief The length of #AWS_IOT_ACCEPTED_SUFFIX. + */ +#define AWS_IOT_ACCEPTED_SUFFIX_LENGTH ( ( uint16_t ) ( sizeof( AWS_IOT_ACCEPTED_SUFFIX ) - 1 ) ) + +/** + * @brief The suffix for an AWS IoT operation "rejected" topic. + */ +#define AWS_IOT_REJECTED_SUFFIX "/rejected" + +/** + * @brief The length of #AWS_IOT_REJECTED_SUFFIX. + */ +#define AWS_IOT_REJECTED_SUFFIX_LENGTH ( ( uint16_t ) ( sizeof( AWS_IOT_REJECTED_SUFFIX ) - 1 ) ) + +/** + * @brief The JSON key used to represent client tokens for AWS IoT. + */ +#define AWS_IOT_CLIENT_TOKEN_KEY "clientToken" + +/** + * @brief The length of #AWS_IOT_CLIENT_TOKEN_KEY. + */ +#define AWS_IOT_CLIENT_TOKEN_KEY_LENGTH ( sizeof( AWS_IOT_CLIENT_TOKEN_KEY ) - 1 ) + +/** + * @brief The length of the longest client token allowed by AWS IoT. + */ +#define AWS_IOT_CLIENT_TOKEN_MAX_LENGTH ( 64 ) + +/** + * @brief A flag to represent persistent subscriptions in a subscriptions + * object. + * + * Its value is negative to distinguish it from valid subscription counts, which + * are 0 or positive. + */ +#define AWS_IOT_PERSISTENT_SUBSCRIPTION ( -1 ) + +/** + * @brief Function pointer representing an MQTT blocking operation. + * + * Currently, this is used to represent @ref mqtt_function_subscribesync or + * @ref mqtt_function_unsubscribesync. + * + * @param[in] mqttConnection The MQTT connection to use for the subscription. + * @param[in] pSubscriptionList Pointer to the first element in the array of + * subscriptions. + * @param[in] subscriptionCount The number of elements in pSubscriptionList. + * @param[in] flags Flags which modify the behavior of this function. See @ref mqtt_constants_flags. + * Currently, flags are ignored by this function; this parameter is for + * future-compatibility. + * @param[in] timeoutMs If the MQTT server does not acknowledge the subscriptions within + * this timeout in milliseconds, this function returns #IOT_MQTT_TIMEOUT. + * + * @return One of the following: + * - #IOT_MQTT_SUCCESS + * - #IOT_MQTT_NOT_INITIALIZED + * - #IOT_MQTT_BAD_PARAMETER + * - #IOT_MQTT_NO_MEMORY + * - #IOT_MQTT_NETWORK_ERROR + * - #IOT_MQTT_SCHEDULING_ERROR + * - #IOT_MQTT_BAD_RESPONSE + * - #IOT_MQTT_TIMEOUT + * - #IOT_MQTT_SERVER_REFUSED + */ +typedef IotMqttError_t ( * AwsIotMqttFunction_t )( IotMqttConnection_t mqttConnection, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + uint32_t timeoutMs ); + +/** + * @brief Function pointer representing an MQTT library callback function. + * + * @param[in] pArgument Ignored. + * @param[in] pMessage The received DELTA document (as an MQTT PUBLISH message). + */ +typedef void ( * AwsIotMqttCallbackFunction_t )( void * pArgument, + IotMqttCallbackParam_t * pMessage ); + +/** + * @brief Enumerations representing each of the statuses that may be parsed + * from a topic. + */ +typedef enum AwsIotStatus +{ + AWS_IOT_ACCEPTED = 0, /**< Operation accepted. */ + AWS_IOT_REJECTED = 1, /**< Operation rejected. */ + AWS_IOT_UNKNOWN = 2 /**< Unknown status (neither accepted nor rejected). */ +} AwsIotStatus_t; + +/** + * @brief Information required to generate a topic for AWS IoT. + */ +typedef struct AwsIotTopicInfo +{ + const char * pThingName; /**< @brief The Thing Name associated with the operation. */ + size_t thingNameLength; /**< @brief The length of `pThingName`. */ + const char * pOperationName; /**< @brief The operation name to place in the topic. */ + uint16_t operationNameLength; /**< @brief The length of `pOperationName`. */ + uint16_t longestSuffixLength; /**< @brief The length of longest suffix that will be placed at the end of the topic. */ + void * ( *mallocString )( size_t size ); /**< @brief Function used to allocate a string, if needed. */ +} AwsIotTopicInfo_t; + +/** + * @brief Information needed to modify AWS IoT subscription topics. + * + * @warning The buffer passed as `pTopicFilterBase` must be large enough to + * accommodate the "/accepted" and "/rejected" suffixes. + */ +typedef struct AwsIotSubscriptionInfo_t +{ + IotMqttConnection_t mqttConnection; /**< @brief The MQTT connection to use. */ + AwsIotMqttCallbackFunction_t callbackFunction; /**< @brief Callback function for MQTT subscribe. */ + uint32_t timeout; /**< @brief Timeout for MQTT function. */ + + /* Topic filter. */ + char * pTopicFilterBase; /**< @brief Contains the base topic filter, without "/accepted" or "/rejected". */ + uint16_t topicFilterBaseLength; /**< @brief Length of the base topic filter. */ +} AwsIotSubscriptionInfo_t; + +/** + * @brief Thing Name and length, used to match subscriptions. + */ +typedef struct AwsIotThingName +{ + const char * pThingName; /**< @brief Thing Name to compare. */ + size_t thingNameLength; /**< @brief Length of `pThingName`. */ +} AwsIotThingName_t; + +/** + * @brief Initializes the lists used by AWS IoT operations. + * + * @param[in] pPendingOperationsList The list that holds pending operations for + * a library. + * @param[in] pSubscriptionsList The list that holds subscriptions for a library. + * @param[in] pPendingOperationsMutex The mutex that guards the pending operations + * list. + * @param[in] pSubscriptionsMutex The mutex that guards the subscriptions list. + * + * @return `true` if all initialization succeeded; `false` otherwise. + */ +bool AwsIot_InitLists( IotListDouble_t * pPendingOperationsList, + IotListDouble_t * pSubscriptionsList, + IotMutex_t * pPendingOperationsMutex, + IotMutex_t * pSubscriptionsMutex ); + +/** + * @brief Checks that a Thing Name is valid for AWS IoT. + * + * @param[in] pThingName Thing Name to validate. + * @param[in] thingNameLength Length of `pThingName`. + * + * @return `true` if `pThingName` is valid; `false` otherwise. + */ +bool AwsIot_ValidateThingName( const char * pThingName, + size_t thingNameLength ); + +/** + * @brief Extracts the client token from a JSON document. + * + * The client token is used to differentiate AWS IoT operations. It is unique per + * operation. + * + * @param[in] pJsonDocument The JSON document to parse. + * @param[in] jsonDocumentLength The length of `pJsonDocument`. + * @param[out] pClientToken Set to point to the client token in `pJsonDocument`. + * @param[out] pClientTokenLength Set to the length of the client token. + * + * @return `true` if the client token was found; `false` otherwise. The output + * parameters are only valid if this function returns `true`. + */ +bool AwsIot_GetClientToken( const char * pJsonDocument, + size_t jsonDocumentLength, + const char ** pClientToken, + size_t * pClientTokenLength ); + +/** + * @brief Parse the Thing Name from an MQTT topic. + * + * @param[in] pTopicName The topic to parse. + * @param[in] topicNameLength The length of `pTopicName`. + * @param[out] pThingName Set to point to the Thing Name. + * @param[out] pThingNameLength Set to the length of the Thing Name. + * + * @return `true` if a Thing Name was successfully parsed; `false` otherwise. The output + * parameters are only valid if this function returns `true`. + */ +bool AwsIot_ParseThingName( const char * pTopicName, + uint16_t topicNameLength, + const char ** pThingName, + size_t * pThingNameLength ); + +/** + * @brief Parse the operation status (accepted or rejected) from an MQTT topic. + * + * @param[in] pTopicName The topic to parse. + * @param[in] topicNameLength The length of `pTopicName`. + * + * @return Any #AwsIotStatus_t. + */ +AwsIotStatus_t AwsIot_ParseStatus( const char * pTopicName, + uint16_t topicNameLength ); + +/** + * @brief Generate a topic to use for an AWS IoT operation. + * + * @param[in] pTopicInfo Information needed to generate an AWS IoT topic. + * @param[in,out] pTopicBuffer Where to place the generated topic. An existing + * buffer may be passed in. If `NULL`, this function will attempt to allocate a + * new buffer. + * @param[out] pOperationTopicLength Set to the length of the generated topic. + * + * @warning This function does not check the length of `pTopicBuffer`! Any provided + * buffer must be long enough to accommodate the Thing Name, operation name, and + * any other suffixes. + * + * @return `true` if the topic was successfully generated; `false` otherwise. + * This function will always succeed when an input buffer is provided. + */ +bool AwsIot_GenerateOperationTopic( const AwsIotTopicInfo_t * pTopicInfo, + char ** pTopicBuffer, + uint16_t * pOperationTopicLength ); + +/** + * @brief Add or remove subscriptions for AWS IoT operations. + * + * @param[in] mqttOperation Either @ref mqtt_function_subscribesync or + * @ref mqtt_function_unsubscribesync. + * @param[in] pSubscriptionInfo Information needed to process an MQTT + * operation. + * + * @return See the return values of @ref mqtt_function_subscribesync or + * @ref mqtt_function_unsubscribesync. + */ +IotMqttError_t AwsIot_ModifySubscriptions( AwsIotMqttFunction_t mqttOperation, + const AwsIotSubscriptionInfo_t * pSubscriptionInfo ); + +#endif /* ifndef AWS_IOT_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/include/aws_iot_doc_parser.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/include/aws_iot_doc_parser.h new file mode 100644 index 000000000..e3b1f594b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/include/aws_iot_doc_parser.h @@ -0,0 +1,69 @@ +/* + * AWS IoT Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_doc_parser.h + * @brief Parser for AWS IoT Services Documents. This is a JSON parser + * specifically designed to process and retrieve a value from a AWS IoT JSON + * document, used in AWS IoT libraries such as Shadow and Jobs. Given a key and + * a JSON document, AwsIotDocParser_FindValue() will find the first occurrence + * of the key and return its respective value. The design goal of this parser + * is to be light weight and to be of low memory footprint. However, it does + * not check the correctness of the JSON documents. Hence, this parser is not + * meant to be used for general purpose JSON parsing. + */ + +#ifndef AWS_IOT_DOC_PARSER_H_ +#define AWS_IOT_DOC_PARSER_H_ + +/* Standard includes. */ +#include +#include + +/** + * @brief Find a value for a key from a AWS IoT service JSON document. + * + * @warning The parsing will not check for the correctness of the JSON document. + * It is designed to be light weight and to be of low memory footprint rather + * than checking for the correctness of the JSON document. Hence this is not + * meant to be used for a general purpose JSON parsing. This is recommended to + * be used only with mutually authenticated AWS IoT services such as Shadow and + * Jobs where the document will always be a well formatted JSON. + * + * @param[in] pAwsIotJsonDocument Pointer to AWS IoT Service JSON document. + * @param[in] awsIotJsonDocumentLength Length of AWS IoT Service JSON document. + * @param[in] pAwsIotJsonKey JSON key for finding the associated value. + * @param[in] awsIotJsonKeyLength Length of the JSON key. + * @param[out] pAwsIotJsonValue Pointer to the pointer of value found. + * @param[out] pAwsIotJsonValueLength Pointer to the length of the value found. + * + * @returns `true` if a value is found, `false` if a value cannot be found. If + * returns `false`, the values in out pointers will not be valid. + */ +bool AwsIotDocParser_FindValue( const char * pAwsIotJsonDocument, + size_t awsIotJsonDocumentLength, + const char * pAwsIotJsonKey, + size_t awsIotJsonKeyLength, + const char ** pAwsIotJsonValue, + size_t * pAwsIotJsonValueLength ); + +#endif /* ifndef AWS_IOT_DOC_PARSER_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_doc_parser.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_doc_parser.c new file mode 100644 index 000000000..a4322840b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_doc_parser.c @@ -0,0 +1,294 @@ +/* + * AWS IoT Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_doc_parser.c + * @brief Implements the functions in aws_iot_doc_parser.h + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* JSON utilities include. */ +#include "aws_iot_doc_parser.h" + +#define IS_QUOTE( str, idx ) \ + ( ( str )[ ( idx ) ] == '"' && ( ( idx ) == 0 || ( str )[ ( idx ) - 1 ] != '\\' ) ) +#define IS_WHITESPACE( str, idx ) \ + ( ( str )[ ( idx ) ] == ' ' || ( str )[ ( idx ) ] == '\n' || ( str )[ ( idx ) ] == '\r' || ( str )[ ( idx ) ] == '\t' ) + +/*-----------------------------------------------------------*/ + +bool AwsIotDocParser_FindValue( const char * pAwsIotJsonDocument, + size_t awsIotJsonDocumentLength, + const char * pAwsIotJsonKey, + size_t awsIotJsonKeyLength, + const char ** pAwsIotJsonValue, + size_t * pAwsIotJsonValueLength ) +{ + size_t i = 0; + size_t jsonValueLength = 0; + char openCharacter = '\0', closeCharacter = '\0'; + int nestingLevel = 0; + bool isWithinQuotes = false; + + /* Validate all the arguments.*/ + if( ( pAwsIotJsonDocument == NULL ) || ( pAwsIotJsonKey == NULL ) || + ( awsIotJsonDocumentLength == 0 ) || ( awsIotJsonKeyLength == 0 ) ) + { + return false; + } + + /* Ensure the JSON document is long enough to contain the key/value pair. At + * the very least, a JSON key/value pair must contain the key and the 6 + * characters {":""} */ + if( awsIotJsonDocumentLength < awsIotJsonKeyLength + 6 ) + { + return false; + } + + /* Search the characters in the JSON document for the key. The end of the JSON + * document does not have to be searched once too few characters remain to hold a + * value. */ + while( i < awsIotJsonDocumentLength - awsIotJsonKeyLength - 3 ) + { + /* If the first character in the key is found and there's an unescaped double + * quote after the key length, do a string compare for the key. */ + if( ( IS_QUOTE( pAwsIotJsonDocument, i ) ) && + ( IS_QUOTE( pAwsIotJsonDocument, i + 1 + awsIotJsonKeyLength ) ) && + ( pAwsIotJsonDocument[ i + 1 ] == pAwsIotJsonKey[ 0 ] ) && + ( strncmp( pAwsIotJsonDocument + i + 1, + pAwsIotJsonKey, + awsIotJsonKeyLength ) == 0 ) ) + { + /* Key found; this is a potential match. */ + + /* Skip the characters in the JSON key and closing double quote. */ + /* While loop guarantees that i < awsIotJsonDocumentLength - 1 */ + i += awsIotJsonKeyLength + 2; + + /* Skip all whitespace characters between the closing " and the : */ + while( IS_WHITESPACE( pAwsIotJsonDocument, i ) ) + { + i++; + + /* If the end of the document is reached, this isn't a match. */ + if( i >= awsIotJsonDocumentLength ) + { + return false; + } + } + + /* The character immediately following a key (and any whitespace) must be a : + * If it's another character, then this string is a JSON value; skip it. */ + if( pAwsIotJsonDocument[ i ] != ':' ) + { + continue; + } + else + { + /* Skip the : */ + i++; + } + + /* If the end of the document is reached, this isn't a match. */ + if( i >= awsIotJsonDocumentLength ) + { + return false; + } + + /* Skip all whitespace characters between : and the first character in the value. */ + while( IS_WHITESPACE( pAwsIotJsonDocument, i ) ) + { + i++; + + /* If the end of the document is reached, this isn't a match. */ + if( i >= awsIotJsonDocumentLength ) + { + return false; + } + } + + /* Value found. Set the output parameter. */ + if( pAwsIotJsonValue != NULL ) + { + *pAwsIotJsonValue = pAwsIotJsonDocument + i; + } + + /* Calculate the value's length. */ + switch( pAwsIotJsonDocument[ i ] ) + { + /* Calculate length of a JSON string. */ + case '\"': + /* Include the length of the opening and closing double quotes. */ + jsonValueLength = 2; + + /* Skip the opening double quote. */ + i++; + + /* If the end of the document is reached, this isn't a match. */ + if( i >= awsIotJsonDocumentLength ) + { + return false; + } + + /* Add the length of all characters in the JSON string. */ + while( pAwsIotJsonDocument[ i ] != '\"' ) + { + /* Ignore escaped double quotes. */ + if( ( pAwsIotJsonDocument[ i ] == '\\' ) && + ( i + 1 < awsIotJsonDocumentLength ) && + ( pAwsIotJsonDocument[ i + 1 ] == '\"' ) ) + { + /* Skip the characters \" */ + i += 2; + jsonValueLength += 2; + } + else + { + /* Add the length of a single character. */ + i++; + jsonValueLength++; + } + + /* If the end of the document is reached, this isn't a match. */ + if( i >= awsIotJsonDocumentLength ) + { + return false; + } + } + + break; + + /* Set the matching opening and closing characters of a JSON object or array. + * The length calculation is performed below. */ + case '{': + openCharacter = '{'; + closeCharacter = '}'; + break; + + case '[': + openCharacter = '['; + closeCharacter = ']'; + break; + + /* Calculate the length of a JSON primitive. */ + default: + + /* Skip the characters in the JSON value. The JSON value ends with a , or } */ + while( pAwsIotJsonDocument[ i ] != ',' && + pAwsIotJsonDocument[ i ] != '}' ) + { + /* Any whitespace before a , or } means the JSON document is invalid. */ + if( IS_WHITESPACE( pAwsIotJsonDocument, i ) ) + { + return false; + } + + i++; + jsonValueLength++; + + /* If the end of the document is reached, this isn't a match. */ + if( i >= awsIotJsonDocumentLength ) + { + return false; + } + } + + break; + } + + /* Calculate the length of a JSON object or array. */ + if( ( openCharacter != '\0' ) && ( closeCharacter != '\0' ) ) + { + /* Include the length of the opening and closing characters. */ + jsonValueLength = 2; + + /* Skip the opening character. */ + i++; + + /* If the end of the document is reached, this isn't a match. */ + if( i >= awsIotJsonDocumentLength ) + { + return false; + } + + /* Add the length of all characters in the JSON object or array. This + * includes the length of nested objects. */ + while( pAwsIotJsonDocument[ i ] != closeCharacter || + ( pAwsIotJsonDocument[ i ] == closeCharacter && ( nestingLevel != 0 || isWithinQuotes ) ) ) + { + /* Check if its a quote so as to avoid considering the + * nested levels for opening and closing characters within + * quotes. + */ + if( IS_QUOTE( pAwsIotJsonDocument, i ) ) + { + /*Toggle the flag*/ + isWithinQuotes = !isWithinQuotes; + } + + /* Calculate the nesting levels only if not in quotes. */ + if( !isWithinQuotes ) + { + /* An opening character starts a nested object. */ + if( pAwsIotJsonDocument[ i ] == openCharacter ) + { + nestingLevel++; + } + /* A closing character ends a nested object. */ + else if( pAwsIotJsonDocument[ i ] == closeCharacter ) + { + nestingLevel--; + } + } + + i++; + jsonValueLength++; + + /* If the end of the document is reached, this isn't a match. */ + if( i >= awsIotJsonDocumentLength ) + { + return false; + } + } + } + + /* JSON value length calculated; set the output parameter. */ + if( pAwsIotJsonValueLength != NULL ) + { + *pAwsIotJsonValueLength = jsonValueLength; + } + + return true; + } + + i++; + } + + return false; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_operation.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_operation.c new file mode 100644 index 000000000..00181ef94 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_operation.c @@ -0,0 +1,153 @@ +/* + * AWS IoT Common V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_operation.c + * @brief Functions for common AWS IoT operations. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* Platform threads include. */ +#include "platform/iot_threads.h" + +/* AWS IoT include. */ +#include "aws_iot.h" + +/* Error handling include. */ +#include "iot_error.h" + +/*-----------------------------------------------------------*/ + +bool AwsIot_InitLists( IotListDouble_t * pPendingOperationsList, + IotListDouble_t * pSubscriptionsList, + IotMutex_t * pPendingOperationsMutex, + IotMutex_t * pSubscriptionsMutex ) +{ + IOT_FUNCTION_ENTRY( bool, true ); + + /* Flags to track cleanup. */ + bool operationsMutexCreated = false; + bool subscriptionsMutexCreated = false; + + /* Create the mutex guarding the pending operations list. */ + operationsMutexCreated = IotMutex_Create( pPendingOperationsMutex, false ); + + if( operationsMutexCreated == false ) + { + IOT_SET_AND_GOTO_CLEANUP( false ); + } + + /* Create the mutex guarding the subscriptions list. */ + subscriptionsMutexCreated = IotMutex_Create( pSubscriptionsMutex, false ); + + if( subscriptionsMutexCreated == false ) + { + IOT_SET_AND_GOTO_CLEANUP( false ); + } + + /* Initialize lists. */ + IotListDouble_Create( pPendingOperationsList ); + IotListDouble_Create( pSubscriptionsList ); + + IOT_FUNCTION_CLEANUP_BEGIN(); + + /* Clean up on error. */ + if( status == false ) + { + if( operationsMutexCreated == true ) + { + IotMutex_Destroy( pPendingOperationsMutex ); + } + } + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +bool AwsIot_GenerateOperationTopic( const AwsIotTopicInfo_t * pTopicInfo, + char ** pTopicBuffer, + uint16_t * pOperationTopicLength ) +{ + bool status = true; + uint16_t bufferLength = 0; + uint16_t operationTopicLength = 0; + char * pBuffer = NULL; + + /* Calculate the required topic buffer length. */ + bufferLength = ( uint16_t ) ( AWS_IOT_TOPIC_PREFIX_LENGTH + + pTopicInfo->thingNameLength + + pTopicInfo->operationNameLength + + pTopicInfo->longestSuffixLength ); + + /* Allocate memory for the topic buffer if no topic buffer is given. */ + if( *pTopicBuffer == NULL ) + { + pBuffer = pTopicInfo->mallocString( ( size_t ) bufferLength ); + + if( pBuffer == NULL ) + { + status = false; + } + } + /* Otherwise, use the given topic buffer. */ + else + { + pBuffer = *pTopicBuffer; + } + + if( status == true ) + { + /* Copy the AWS IoT topic prefix into the topic buffer. */ + ( void ) memcpy( pBuffer, AWS_IOT_TOPIC_PREFIX, AWS_IOT_TOPIC_PREFIX_LENGTH ); + operationTopicLength = ( uint16_t ) ( operationTopicLength + AWS_IOT_TOPIC_PREFIX_LENGTH ); + + /* Copy the Thing Name into the topic buffer. */ + ( void ) memcpy( pBuffer + operationTopicLength, + pTopicInfo->pThingName, + pTopicInfo->thingNameLength ); + operationTopicLength = ( uint16_t ) ( operationTopicLength + pTopicInfo->thingNameLength ); + + /* Copy the Shadow operation string into the topic buffer. */ + ( void ) memcpy( pBuffer + operationTopicLength, + pTopicInfo->pOperationName, + pTopicInfo->operationNameLength ); + operationTopicLength = ( uint16_t ) ( operationTopicLength + pTopicInfo->operationNameLength ); + + /* Set the output parameters. */ + if( *pTopicBuffer == NULL ) + { + *pTopicBuffer = pBuffer; + } + + *pOperationTopicLength = operationTopicLength; + } + + return status; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_parser.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_parser.c new file mode 100644 index 000000000..0ebed63e4 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_parser.c @@ -0,0 +1,181 @@ +/* + * AWS IoT Common V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_parser.c + * @brief Parses topics for Thing Name and status. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* AWS IoT include. */ +#include "aws_iot.h" + +/* Error handling include. */ +#include "iot_error.h" + +/* AWS Parser include. */ +#include "aws_iot_doc_parser.h" + +/** + * @brief Minimum allowed topic length for an AWS IoT status topic. + * + * Topics must contain at least: + * - The common prefix + * - The suffix "/accepted" or "/rejected" + * - 1 character for the Thing Name + * - 2 characters for the operation name and the enclosing slashes + */ +#define MINIMUM_TOPIC_NAME_LENGTH \ + ( uint16_t ) ( AWS_IOT_TOPIC_PREFIX_LENGTH + \ + AWS_IOT_ACCEPTED_SUFFIX_LENGTH + \ + 1 + 2 ) + +/** + * @brief The longest client token accepted by AWS IoT service, per AWS IoT + * service limits. + */ +#define MAX_CLIENT_TOKEN_LENGTH ( 64 ) + +/*-----------------------------------------------------------*/ + +bool AwsIot_GetClientToken( const char * pJsonDocument, + size_t jsonDocumentLength, + const char ** pClientToken, + size_t * pClientTokenLength ) +{ + /* Extract the client token from the JSON document. */ + bool status = AwsIotDocParser_FindValue( pJsonDocument, + jsonDocumentLength, + AWS_IOT_CLIENT_TOKEN_KEY, + AWS_IOT_CLIENT_TOKEN_KEY_LENGTH, + pClientToken, + pClientTokenLength ); + + if( status == true ) + { + /* Check that the length of the client token is valid. */ + if( ( *pClientTokenLength < 2 ) || + ( *pClientTokenLength > MAX_CLIENT_TOKEN_LENGTH ) ) + { + status = false; + } + } + + return status; +} + +/*-----------------------------------------------------------*/ + +bool AwsIot_ParseThingName( const char * pTopicName, + uint16_t topicNameLength, + const char ** pThingName, + size_t * pThingNameLength ) +{ + IOT_FUNCTION_ENTRY( bool, true ); + const char * pThingNameStart = NULL; + size_t thingNameLength = 0; + + /* Check that the topic name is at least as long as the minimum allowed. */ + if( topicNameLength < MINIMUM_TOPIC_NAME_LENGTH ) + { + IOT_SET_AND_GOTO_CLEANUP( false ); + } + + /* Check that the given topic starts with the common prefix. */ + if( strncmp( AWS_IOT_TOPIC_PREFIX, + pTopicName, + AWS_IOT_TOPIC_PREFIX_LENGTH ) != 0 ) + { + IOT_SET_AND_GOTO_CLEANUP( false ); + } + + /* The Thing Name starts immediately after the topic prefix. */ + pThingNameStart = pTopicName + AWS_IOT_TOPIC_PREFIX_LENGTH; + + /* Calculate the length of the Thing Name, which is terminated with a '/'. */ + while( ( thingNameLength + AWS_IOT_TOPIC_PREFIX_LENGTH < ( size_t ) topicNameLength ) && + ( pThingNameStart[ thingNameLength ] != '/' ) ) + { + thingNameLength++; + } + + /* The end of the topic name was reached without finding a '/'. The topic + * name is invalid. */ + if( thingNameLength + AWS_IOT_TOPIC_PREFIX_LENGTH >= ( size_t ) topicNameLength ) + { + IOT_SET_AND_GOTO_CLEANUP( false ); + } + + /* Set the output parameters. */ + *pThingName = pThingNameStart; + *pThingNameLength = thingNameLength; + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +AwsIotStatus_t AwsIot_ParseStatus( const char * pTopicName, + uint16_t topicNameLength ) +{ + IOT_FUNCTION_ENTRY( AwsIotStatus_t, AWS_IOT_UNKNOWN ); + const char * pSuffixStart = NULL; + + /* Both 'accepted' and 'rejected' topics are of the same length + * The below is a defensive check at run time to ensure that. + */ + Iot_DefaultAssert( AWS_IOT_ACCEPTED_SUFFIX_LENGTH == AWS_IOT_REJECTED_SUFFIX_LENGTH ); + + /* Check that the status topic name is at least as long as the + * "accepted" suffix. This length check will be good for rejected also + * as both are of 8 characters in length. */ + if( topicNameLength > AWS_IOT_ACCEPTED_SUFFIX_LENGTH ) + { + /* Calculate where the "accepted" suffix should start. */ + pSuffixStart = pTopicName + topicNameLength - AWS_IOT_ACCEPTED_SUFFIX_LENGTH; + + /* Check if the end of the status topic name is "/accepted". */ + if( strncmp( pSuffixStart, + AWS_IOT_ACCEPTED_SUFFIX, + AWS_IOT_ACCEPTED_SUFFIX_LENGTH ) == 0 ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_ACCEPTED ); + } + + /* Check if the end of the status topic name is "/rejected". */ + if( strncmp( pSuffixStart, + AWS_IOT_REJECTED_SUFFIX, + AWS_IOT_REJECTED_SUFFIX_LENGTH ) == 0 ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_REJECTED ); + } + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_subscription.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_subscription.c new file mode 100644 index 000000000..1755601fe --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_subscription.c @@ -0,0 +1,164 @@ +/* + * AWS IoT Common V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_subscription.c + * @brief Functions for common AWS IoT subscriptions. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* AWS IoT include. */ +#include "aws_iot.h" + +/* Error handling include. */ +#include "iot_error.h" + +/* MQTT include. */ +#include "iot_mqtt.h" + +/** + * @brief Modify subscriptions, either by unsubscribing or subscribing. + * + * @param[in] mqttOperation Either @ref mqtt_function_subscribesync or @ref + * mqtt_function_unsubscribesync. + * @param[in] pSubscriptionInfo Information needed to process an MQTT + * operation. + * @param[in] pTopicFilter The topic filter to modify. + * @param[in] topicFilterLength The length of `pTopicFilter`. + * + * @return See the return values of @ref mqtt_function_subscribesync or + * @ref mqtt_function_unsubscribesync. + */ +static IotMqttError_t _modifySubscriptions( AwsIotMqttFunction_t mqttOperation, + const AwsIotSubscriptionInfo_t * pSubscriptionInfo, + const char * pTopicFilter, + uint16_t topicFilterLength ); + +/*-----------------------------------------------------------*/ + +static IotMqttError_t _modifySubscriptions( AwsIotMqttFunction_t mqttOperation, + const AwsIotSubscriptionInfo_t * pSubscriptionInfo, + const char * pTopicFilter, + uint16_t topicFilterLength ) +{ + IotMqttError_t status = IOT_MQTT_STATUS_PENDING; + IotMqttSubscription_t subscription = IOT_MQTT_SUBSCRIPTION_INITIALIZER; + + /* Per the AWS IoT documentation, topic subscriptions are QoS 1. */ + subscription.qos = IOT_MQTT_QOS_1; + + /* Set the members of the subscription parameter. */ + subscription.pTopicFilter = pTopicFilter; + subscription.topicFilterLength = topicFilterLength; + subscription.callback.pCallbackContext = NULL; + subscription.callback.function = pSubscriptionInfo->callbackFunction; + + /* Call the MQTT operation function. + * Subscription count is 1 in this case. + * None of the flags are set in this call. Hence 0 is passed for flags. + * Please refer to documentation for AwsIotMqttFunction_t for more details. + */ + status = mqttOperation( pSubscriptionInfo->mqttConnection, + &subscription, + 1, + 0, + pSubscriptionInfo->timeout ); + + return status; +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t AwsIot_ModifySubscriptions( AwsIotMqttFunction_t mqttOperation, + const AwsIotSubscriptionInfo_t * pSubscriptionInfo ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_STATUS_PENDING ); + IotMqttError_t acceptedStatus = IOT_MQTT_STATUS_PENDING; + uint16_t topicFilterLength = 0; + + /* Place the topic "accepted" suffix at the end of the topic buffer. */ + ( void ) memcpy( pSubscriptionInfo->pTopicFilterBase + + pSubscriptionInfo->topicFilterBaseLength, + AWS_IOT_ACCEPTED_SUFFIX, + AWS_IOT_ACCEPTED_SUFFIX_LENGTH ); + topicFilterLength = ( uint16_t ) ( pSubscriptionInfo->topicFilterBaseLength + + AWS_IOT_ACCEPTED_SUFFIX_LENGTH ); + + /* Modify the subscription to the "accepted" topic. */ + acceptedStatus = _modifySubscriptions( mqttOperation, + pSubscriptionInfo, + pSubscriptionInfo->pTopicFilterBase, + topicFilterLength ); + + if( acceptedStatus != IOT_MQTT_SUCCESS ) + { + IOT_SET_AND_GOTO_CLEANUP( acceptedStatus ); + } + + /* Place the topic "rejected" suffix at the end of the topic buffer. */ + ( void ) memcpy( pSubscriptionInfo->pTopicFilterBase + + pSubscriptionInfo->topicFilterBaseLength, + AWS_IOT_REJECTED_SUFFIX, + AWS_IOT_REJECTED_SUFFIX_LENGTH ); + topicFilterLength = ( uint16_t ) ( pSubscriptionInfo->topicFilterBaseLength + + AWS_IOT_REJECTED_SUFFIX_LENGTH ); + + /* Modify the subscription to the "rejected" topic. */ + status = _modifySubscriptions( mqttOperation, + pSubscriptionInfo, + pSubscriptionInfo->pTopicFilterBase, + topicFilterLength ); + + IOT_FUNCTION_CLEANUP_BEGIN(); + + /* Clean up on error. */ + if( status != IOT_MQTT_SUCCESS ) + { + /* Remove the subscription to the "accepted" topic if the subscription + * to the "rejected" topic failed. */ + if( ( mqttOperation == IotMqtt_SubscribeSync ) && + ( acceptedStatus == IOT_MQTT_SUCCESS ) ) + { + /* Place the topic "accepted" suffix at the end of the topic buffer. */ + ( void ) memcpy( pSubscriptionInfo->pTopicFilterBase + + pSubscriptionInfo->topicFilterBaseLength, + AWS_IOT_ACCEPTED_SUFFIX, + AWS_IOT_ACCEPTED_SUFFIX_LENGTH ); + topicFilterLength = ( uint16_t ) ( pSubscriptionInfo->topicFilterBaseLength + + AWS_IOT_ACCEPTED_SUFFIX_LENGTH ); + + ( void ) _modifySubscriptions( IotMqtt_UnsubscribeSync, + pSubscriptionInfo, + pSubscriptionInfo->pTopicFilterBase, + topicFilterLength ); + } + } + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_validate.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_validate.c new file mode 100644 index 000000000..307314620 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/common/src/aws_iot_validate.c @@ -0,0 +1,62 @@ +/* + * AWS IoT Common V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_validate.c + * @brief Validates Thing Names and other parameters to AWS IoT. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* AWS IoT include. */ +#include "aws_iot.h" + +/* Error handling include. */ +#include "iot_error.h" + +/*-----------------------------------------------------------*/ + +bool AwsIot_ValidateThingName( const char * pThingName, + size_t thingNameLength ) +{ + IOT_FUNCTION_ENTRY( bool, true ); + + if( pThingName == NULL ) + { + IOT_SET_AND_GOTO_CLEANUP( false ); + } + + if( thingNameLength == 0 ) + { + IOT_SET_AND_GOTO_CLEANUP( false ); + } + + if( thingNameLength > AWS_IOT_MAX_THING_NAME_LENGTH ) + { + IOT_SET_AND_GOTO_CLEANUP( false ); + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/directories.txt b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/directories.txt new file mode 100644 index 000000000..e236f222e --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/directories.txt @@ -0,0 +1,10 @@ ++ common +Contains the implementation of utility functions used by other AWS IoT libraries. + ++ shadow +Contains the implementation of the AWS IoT Shadow client library. + ++ jobs +Contain the implementation of the AWS IoT Jobs client library. + +Further libraries will be rolled out soon. \ No newline at end of file diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/AWS_IoT_Jobs.url b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/AWS_IoT_Jobs.url new file mode 100644 index 000000000..65f28df29 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/AWS_IoT_Jobs.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/jobs diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/include/aws_iot_jobs.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/include/aws_iot_jobs.h new file mode 100644 index 000000000..40dac3272 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/include/aws_iot_jobs.h @@ -0,0 +1,927 @@ +/* + * AWS IoT Jobs V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_jobs.h + * @brief User-facing functions of the Jobs library. + */ + +#ifndef AWS_IOT_JOBS_H_ +#define AWS_IOT_JOBS_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Jobs types include. */ +#include "types/aws_iot_jobs_types.h" + +/*------------------------- Jobs library functions --------------------------*/ + +/** + * @functionspage{jobs,Jobs library} + * - @functionname{jobs_function_init} + * - @functionname{jobs_function_cleanup} + * - @functionname{jobs_function_getpendingasync} + * - @functionname{jobs_function_getpendingsync} + * - @functionname{jobs_function_startnextasync} + * - @functionname{jobs_function_startnextsync} + * - @functionname{jobs_function_describeasync} + * - @functionname{jobs_function_describesync} + * - @functionname{jobs_function_updateasync} + * - @functionname{jobs_function_updatesync} + * - @functionname{jobs_function_wait} + * - @functionname{jobs_function_setnotifypendingcallback} + * - @functionname{jobs_function_setnotifynextcallback} + * - @functionname{jobs_function_removepersistentsubscriptions} + * - @functionname{jobs_function_strerror} + * - @functionname{jobs_function_statename} + */ + +/** + * @functionpage{AwsIotJobs_Init,jobs,init} + * @functionpage{AwsIotJobs_Cleanup,jobs,cleanup} + * @functionpage{AwsIotJobs_GetPendingAsync,jobs,getpendingasync} + * @functionpage{AwsIotJobs_GetPendingSync,jobs,getpendingsync} + * @functionpage{AwsIotJobs_StartNextAsync,jobs,startnextasync} + * @functionpage{AwsIotJobs_StartNextSync,jobs,startnextsync} + * @functionpage{AwsIotJobs_DescribeAsync,jobs,describeasync} + * @functionpage{AwsIotJobs_DescribeSync,jobs,describesync} + * @functionpage{AwsIotJobs_UpdateAsync,jobs,updateasync} + * @functionpage{AwsIotJobs_UpdateSync,jobs,updatesync} + * @functionpage{AwsIotJobs_Wait,jobs,wait} + * @functionpage{AwsIotJobs_SetNotifyPendingCallback,jobs,setnotifypendingcallback} + * @functionpage{AwsIotJobs_SetNotifyNextCallback,jobs,setnotifynextcallback} + * @functionpage{AwsIotJobs_RemovePersistentSubscriptions,jobs,removepersistentsubscriptions} + * @functionpage{AwsIotJobs_strerror,jobs,strerror} + * @functionpage{AwsIotJobs_StateName,jobs,statename} + */ + +/** + * @brief One-time initialization function for the Jobs library. + * + * This function performs internal setup of the Jobs library. It must be + * called once (and only once) before calling any other Jobs function. + * Calling this function more than once without first calling @ref + * jobs_function_cleanup may result in a crash. + * + * @param[in] mqttTimeoutMs The amount of time (in milliseconds) that the Jobs + * library will wait for MQTT operations. Optional; set this to `0` to use + * @ref AWS_IOT_JOBS_DEFAULT_MQTT_TIMEOUT_MS. + * + * @return One of the following: + * - #AWS_IOT_JOBS_SUCCESS + * - #AWS_IOT_JOBS_INIT_FAILED + * + * @warning No thread-safety guarantees are provided for this function. + * + * @see @ref jobs_function_cleanup + */ +/* @[declare_jobs_init] */ +AwsIotJobsError_t AwsIotJobs_Init( uint32_t mqttTimeoutMs ); +/* @[declare_jobs_init] */ + +/** + * @brief One-time deinitialization function for the Jobs library. + * + * This function frees resources taken in @ref jobs_function_init and deletes + * any [persistent subscriptions.](@ref AWS_IOT_JOBS_FLAG_KEEP_SUBSCRIPTIONS) + * It should be called to clean up the Jobs library. After this function returns, + * @ref jobs_function_init must be called again before calling any other Jobs + * function. + * + * @warning No thread-safety guarantees are provided for this function. + * + * @see @ref jobs_function_init + */ +/* @[declare_jobs_cleanup] */ +void AwsIotJobs_Cleanup( void ); +/* @[declare_jobs_cleanup] */ + +/** + * @brief Get the list of all pending jobs for a Thing and receive an asynchronous + * notification when the response arrives. + * + * This function implements the [GetPendingJobExecutions] + * (https://docs.aws.amazon.com/iot/latest/developerguide/jobs-api.html#mqtt-getpendingjobexecutions) + * command of the Jobs API, which gets the list of all Jobs for a Thing that are + * not in a terminal state. The list of retrieved Jobs is returned as the `pResponse` + * member in #AwsIotJobsCallbackParam_t, or through the #AwsIotJobsResponse_t + * parameter of @ref jobs_function_wait. + * + * @param[in] pRequestInfo Jobs request parameters. + * @param[in] flags Flags which modify the behavior of the Jobs request. See + * @ref jobs_constants_flags. + * @param[in] pCallbackInfo Asynchronous notification of this function's completion. + * @param[out] pGetPendingOperation Set to a handle by which this operation may be referenced + * after this function returns. This reference is invalidated once the Jobs operation + * completes. + * + * @return This function will return #AWS_IOT_JOBS_STATUS_PENDING upon successfully + * queuing the Jobs operation. + * @return If this function fails before queuing the Jobs operation, it will return one of: + * - #AWS_IOT_JOBS_NOT_INITIALIZED + * - #AWS_IOT_JOBS_BAD_PARAMETER + * - #AWS_IOT_JOBS_NO_MEMORY + * @return Upon successful completion of the Jobs operation (either through an #AwsIotJobsCallbackInfo_t + * or @ref jobs_function_wait), the status will be #AWS_IOT_JOBS_SUCCESS. + * @return Should the Jobs operation fail, the status will be one of: + * - #AWS_IOT_JOBS_NO_MEMORY (Memory could not be allocated for incoming document) + * - #AWS_IOT_JOBS_MQTT_ERROR + * - #AWS_IOT_JOBS_BAD_RESPONSE + * - A Jobs failure reason between #AWS_IOT_JOBS_INVALID_TOPIC and #AWS_IOT_JOBS_TERMINAL_STATE. + * + * @see @ref jobs_function_getpendingsync for a blocking variant of this function. + * + * Example + * @code{c} + * #define THING_NAME "Test_device" + * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1 ) + * + * // Signature of Jobs callback function. + * void _jobsCallback( void * pCallbackContext, AwsIotJobsCallbackParam_t * pCallbackParam ); + * + * AwsIotJobsOperation_t getPendingOperation = AWS_IOT_JOBS_OPERATION_INITIALIZER; + * AwsIotJobsRequestInfo_t requestInfo = AWS_IOT_JOBS_REQUEST_INFO_INITIALIZER; + * AwsIotJobsCallbackInfo_t callbackInfo = AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER; + * + * // Set the request info. + * requestInfo.mqttConnection = _mqttConnection; + * requestInfo.pThingName = THING_NAME; + * requestInfo.thingNameLength = THING_NAME_LENGTH; + * + * // Set the callback function to invoke. + * callbackInfo.function = _jobsCallback; + * + * // Queue Jobs GET PENDING. + * AwsIotJobsError_t getPendingResult = AwsIotJobs_GetPendingAsync( &requestInfo, + * 0, + * &callbackInfo, + * &getPendingOperation ); + * + * // GET PENDING should have returned AWS_IOT_JOBS_STATUS_PENDING. The function + * // _jobsCallback will be invoked once the Jobs response is received. + * @endcode + */ +/* @[declare_jobs_getpendingasync] */ +AwsIotJobsError_t AwsIotJobs_GetPendingAsync( const AwsIotJobsRequestInfo_t * pRequestInfo, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pCallbackInfo, + AwsIotJobsOperation_t * const pGetPendingOperation ); +/* @[declare_jobs_getpendingasync] */ + +/** + * @brief Get the list of all pending jobs for a Thing with a timeout for receiving + * the response. + * + * This function queues a Jobs GET PENDING, then waits for the result. Internally, + * this function is a call to @ref jobs_function_getpendingasync followed by + * @ref jobs_function_wait. See @ref jobs_function_getpendingasync for more information + * on the Jobs GET PENDING command. + * + * @param[in] pRequestInfo Jobs request parameters. + * @param[in] flags Flags which modify the behavior of the Jobs request. See + * @ref jobs_constants_flags. + * @param[in] timeoutMs If a response is not received within this timeout, this + * function returns #AWS_IOT_JOBS_TIMEOUT. + * @param[out] pJobsResponse The response received from the Jobs service. + * + * @return One of the following: + * - #AWS_IOT_JOBS_SUCCESS + * - #AWS_IOT_JOBS_NOT_INITIALIZED + * - #AWS_IOT_JOBS_BAD_PARAMETER + * - #AWS_IOT_JOBS_NO_MEMORY + * - #AWS_IOT_JOBS_MQTT_ERROR + * - #AWS_IOT_JOBS_BAD_RESPONSE + * - #AWS_IOT_JOBS_TIMEOUT + * - A Jobs failure reason between #AWS_IOT_JOBS_INVALID_TOPIC and #AWS_IOT_JOBS_TERMINAL_STATE. + */ +/* @[declare_jobs_getpendingsync] */ +AwsIotJobsError_t AwsIotJobs_GetPendingSync( const AwsIotJobsRequestInfo_t * pRequestInfo, + uint32_t flags, + uint32_t timeoutMs, + AwsIotJobsResponse_t * const pJobsResponse ); +/* @[declare_jobs_getpendingsync] */ + +/** + * @brief Start the next pending job execution for a Thing and receive an asynchronous + * notification when the response arrives. + * + * This function implements the [StartNextPendingJobExecution] + * (https://docs.aws.amazon.com/iot/latest/developerguide/jobs-api.html#mqtt-startnextpendingjobexecution) + * command of the Jobs API, which gets and starts the next pending job execution + * for a Thing. + * + * @param[in] pRequestInfo Jobs request parameters. + * @param[in] pUpdateInfo Jobs update parameters. + * @param[in] flags Flags which modify the behavior of the Jobs request. See + * @ref jobs_constants_flags. + * @param[in] pCallbackInfo Asynchronous notification of this function's completion. + * @param[out] pStartNextOperation Set to a handle by which this operation may be referenced + * after this function returns. This reference is invalidated once the Jobs operation + * completes. + * + * @return This function will return #AWS_IOT_JOBS_STATUS_PENDING upon successfully + * queuing the Jobs operation. + * @return If this function fails before queuing the Jobs operation, it will return one of: + * - #AWS_IOT_JOBS_NOT_INITIALIZED + * - #AWS_IOT_JOBS_BAD_PARAMETER + * - #AWS_IOT_JOBS_NO_MEMORY + * @return Upon successful completion of the Jobs operation (either through an #AwsIotJobsCallbackInfo_t + * or @ref jobs_function_wait), the status will be #AWS_IOT_JOBS_SUCCESS. + * @return Should the Jobs operation fail, the status will be one of: + * - #AWS_IOT_JOBS_NO_MEMORY (Memory could not be allocated for incoming document) + * - #AWS_IOT_JOBS_MQTT_ERROR + * - #AWS_IOT_JOBS_BAD_RESPONSE + * - A Jobs failure reason between #AWS_IOT_JOBS_INVALID_TOPIC and #AWS_IOT_JOBS_TERMINAL_STATE. + * + * @see @ref jobs_function_startnextsync for a blocking variant of this function. + * + * Example + * @code{c} + * #define THING_NAME "Test_device" + * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1 ) + * + * // Signature of Jobs callback function. + * void _jobsCallback( void * pCallbackContext, AwsIotJobsCallbackParam_t * pCallbackParam ); + * + * AwsIotJobsOperation_t startNextOperation = AWS_IOT_JOBS_OPERATION_INITIALIZER; + * AwsIotJobsRequestInfo_t requestInfo = AWS_IOT_JOBS_REQUEST_INFO_INITIALIZER; + * AwsIotJobsUpdateInfo_t updateInfo = AWS_IOT_JOBS_UPDATE_INFO_INITIALIZER; + * AwsIotJobsCallbackInfo_t callbackInfo = AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER; + * + * // Set the request info. The update info generally does not need to be + * // changed, as its defaults are suitable. + * requestInfo.mqttConnection = _mqttConnection; + * requestInfo.pThingName = THING_NAME; + * requestInfo.thingNameLength = THING_NAME_LENGTH; + * + * // Set the callback function to invoke. + * callbackInfo.function = _jobsCallback; + * + * // Queue Jobs START NEXT. + * AwsIotJobsError_t startNextResult = AwsIotJobs_StartNextAsync( &requestInfo, + * &updateInfo, + * 0, + * &callbackInfo, + * &startNextOperation ); + * + * // START NEXT should have returned AWS_IOT_JOBS_STATUS_PENDING. The function + * // _jobsCallback will be invoked once the Jobs response is received. + * @endcode + */ +/* @[declare_jobs_startnextasync] */ +AwsIotJobsError_t AwsIotJobs_StartNextAsync( const AwsIotJobsRequestInfo_t * pRequestInfo, + const AwsIotJobsUpdateInfo_t * pUpdateInfo, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pCallbackInfo, + AwsIotJobsOperation_t * const pStartNextOperation ); +/* @[declare_jobs_startnextasync] */ + +/** + * @brief Start the next pending job execution for a Thing with a timeout for + * receiving the response. + * + * This function queues a Jobs START NEXT, then waits for the result. Internally, + * this function is a call to @ref jobs_function_startnextasync followed by + * @ref jobs_function_wait. See @ref jobs_function_startnextasync for more information + * on the Jobs START NEXT command. + * + * @param[in] pRequestInfo Jobs request parameters. + * @param[in] pUpdateInfo Jobs update parameters. + * @param[in] flags Flags which modify the behavior of the Jobs request. See + * @ref jobs_constants_flags. + * @param[in] timeoutMs If a response is not received within this timeout, this + * function returns #AWS_IOT_JOBS_TIMEOUT. + * @param[out] pJobsResponse The response received from the Jobs service. + * + * @return One of the following: + * - #AWS_IOT_JOBS_SUCCESS + * - #AWS_IOT_JOBS_NOT_INITIALIZED + * - #AWS_IOT_JOBS_BAD_PARAMETER + * - #AWS_IOT_JOBS_NO_MEMORY + * - #AWS_IOT_JOBS_MQTT_ERROR + * - #AWS_IOT_JOBS_BAD_RESPONSE + * - #AWS_IOT_JOBS_TIMEOUT + * - A Jobs failure reason between #AWS_IOT_JOBS_INVALID_TOPIC and #AWS_IOT_JOBS_TERMINAL_STATE. + */ +/* @[declare_jobs_startnextsync] */ +AwsIotJobsError_t AwsIotJobs_StartNextSync( const AwsIotJobsRequestInfo_t * pRequestInfo, + const AwsIotJobsUpdateInfo_t * pUpdateInfo, + uint32_t flags, + uint32_t timeoutMs, + AwsIotJobsResponse_t * const pJobsResponse ); +/* @[declare_jobs_startnextsync] */ + +/** + * @brief Get detailed information about a job execution and receive an asynchronous + * notification when the response arrives. + * + * This function implements the [DescribeJobExecution] + * (https://docs.aws.amazon.com/iot/latest/developerguide/jobs-api.html#mqtt-describejobexecution) + * command of the Jobs API, which gets detailed information about a job execution. + * The description is returned as the `pResponse` member in #AwsIotJobsCallbackParam_t, + * or through the #AwsIotJobsResponse_t parameter of @ref jobs_function_wait. + * + * @param[in] pRequestInfo Jobs request parameters. + * @param[in] executionNumber The execution number to describe. Optional; pass + * #AWS_IOT_JOBS_NO_EXECUTION_NUMBER to ignore. + * @param[in] includeJobDocument Whether the response should include the full + * Job document. + * @param[in] flags Flags which modify the behavior of the Jobs request. See + * @ref jobs_constants_flags. + * @param[in] pCallbackInfo Asynchronous notification of this function's completion. + * @param[out] pDescribeOperation Set to a handle by which this operation may be referenced + * after this function returns. This reference is invalidated once the Jobs operation + * completes. + * + * @return This function will return #AWS_IOT_JOBS_STATUS_PENDING upon successfully + * queuing the Jobs operation. + * @return If this function fails before queuing the Jobs operation, it will return one of: + * - #AWS_IOT_JOBS_NOT_INITIALIZED + * - #AWS_IOT_JOBS_BAD_PARAMETER + * - #AWS_IOT_JOBS_NO_MEMORY + * @return Upon successful completion of the Jobs operation (either through an #AwsIotJobsCallbackInfo_t + * or @ref jobs_function_wait), the status will be #AWS_IOT_JOBS_SUCCESS. + * @return Should the Jobs operation fail, the status will be one of: + * - #AWS_IOT_JOBS_NO_MEMORY (Memory could not be allocated for incoming document) + * - #AWS_IOT_JOBS_MQTT_ERROR + * - #AWS_IOT_JOBS_BAD_RESPONSE + * - A Jobs failure reason between #AWS_IOT_JOBS_INVALID_TOPIC and #AWS_IOT_JOBS_TERMINAL_STATE. + * + * @see @ref jobs_function_describesync for a blocking variant of this function. + * + * Example + * @code{c} + * #define THING_NAME "Test_device" + * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1 ) + * + * // Signature of Jobs callback function. + * void _jobsCallback( void * pCallbackContext, AwsIotJobsCallbackParam_t * pCallbackParam ); + * + * AwsIotJobsOperation_t describeOperation = AWS_IOT_JOBS_OPERATION_INITIALIZER; + * AwsIotJobsRequestInfo_t requestInfo = AWS_IOT_JOBS_REQUEST_INFO_INITIALIZER; + * AwsIotJobsCallbackInfo_t callbackInfo = AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER; + * + * // Set the request info. + * requestInfo.mqttConnection = _mqttConnection; + * requestInfo.pThingName = THING_NAME; + * requestInfo.thingNameLength = THING_NAME_LENGTH; + * + * // Describe the next Job. Or, this may be set to a specific Job ID. + * requestInfo.pJobId = AWS_IOT_JOBS_NEXT_JOB; + * requestInfo.jobIdLength = AWS_IOT_JOBS_NEXT_JOB_LENGTH; + * + * // Set the callback function to invoke. + * callbackInfo.function = _jobsCallback; + * + * // Queue Jobs DESCRIBE. + * AwsIotJobsError_t describeResult = AwsIotJobs_DescribeAsync( &requestInfo, + * AWS_IOT_JOBS_NO_EXECUTION_NUMBER, + * false, + * 0, + * &callbackInfo, + * &describeOperation ); + * + * // DESCRIBE should have returned AWS_IOT_JOBS_STATUS_PENDING. The function + * // _jobsCallback will be invoked once the Jobs response is received. + * @endcode + */ +/* @[declare_jobs_describeasync] */ +AwsIotJobsError_t AwsIotJobs_DescribeAsync( const AwsIotJobsRequestInfo_t * pRequestInfo, + int32_t executionNumber, + bool includeJobDocument, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pCallbackInfo, + AwsIotJobsOperation_t * const pDescribeOperation ); +/* @[declare_jobs_describeasync] */ + +/** + * @brief Get detailed information about a job execution with a timeout for receiving + * the response. + * + * This function queues a Jobs DESCRIBE, then waits for the result. Internally, + * this function is a call to @ref jobs_function_describeasync followed by + * @ref jobs_function_wait. See @ref jobs_function_describeasync for more information + * on the Jobs DESCRIBE command. + * + * @param[in] pRequestInfo Jobs request parameters. + * @param[in] executionNumber The execution number to describe. Optional; pass + * #AWS_IOT_JOBS_NO_EXECUTION_NUMBER to ignore. + * @param[in] includeJobDocument Whether the response should include the full + * Job document. + * @param[in] flags Flags which modify the behavior of the Jobs request. See + * @ref jobs_constants_flags. + * @param[in] timeoutMs If a response is not received within this timeout, this + * function returns #AWS_IOT_JOBS_TIMEOUT. + * @param[out] pJobsResponse The response received from the Jobs service. + * + * @return One of the following: + * - #AWS_IOT_JOBS_SUCCESS + * - #AWS_IOT_JOBS_NOT_INITIALIZED + * - #AWS_IOT_JOBS_BAD_PARAMETER + * - #AWS_IOT_JOBS_NO_MEMORY + * - #AWS_IOT_JOBS_MQTT_ERROR + * - #AWS_IOT_JOBS_BAD_RESPONSE + * - #AWS_IOT_JOBS_TIMEOUT + * - A Jobs failure reason between #AWS_IOT_JOBS_INVALID_TOPIC and #AWS_IOT_JOBS_TERMINAL_STATE. + */ +/* @[declare_jobs_describesync] */ +AwsIotJobsError_t AwsIotJobs_DescribeSync( const AwsIotJobsRequestInfo_t * pRequestInfo, + int32_t executionNumber, + bool includeJobDocument, + uint32_t flags, + uint32_t timeoutMs, + AwsIotJobsResponse_t * const pJobsResponse ); +/* @[declare_jobs_describesync] */ + +/** + * @brief Update the status of a job execution and receive an asynchronous + * notification when the Job update completes. + * + * This function implements the [UpdateJobExecution] + * (https://docs.aws.amazon.com/iot/latest/developerguide/jobs-api.html#mqtt-updatejobexecution) + * command of the Jobs API, which updates the status of a Job execution. + * + * @param[in] pRequestInfo Jobs request parameters. + * @param[in] pUpdateInfo Jobs update parameters. + * @param[in] flags Flags which modify the behavior of the Jobs request. See + * @ref jobs_constants_flags. + * @param[in] pCallbackInfo Asynchronous notification of this function's completion. + * @param[out] pUpdateOperation Set to a handle by which this operation may be referenced + * after this function returns. This reference is invalidated once the Jobs operation + * completes. + * + * @return This function will return #AWS_IOT_JOBS_STATUS_PENDING upon successfully + * queuing the Jobs operation. + * @return If this function fails before queuing the Jobs operation, it will return one of: + * - #AWS_IOT_JOBS_NOT_INITIALIZED + * - #AWS_IOT_JOBS_BAD_PARAMETER + * - #AWS_IOT_JOBS_NO_MEMORY + * @return Upon successful completion of the Jobs operation (either through an #AwsIotJobsCallbackInfo_t + * or @ref jobs_function_wait), the status will be #AWS_IOT_JOBS_SUCCESS. + * @return Should the Jobs operation fail, the status will be one of: + * - #AWS_IOT_JOBS_NO_MEMORY (Memory could not be allocated for incoming document) + * - #AWS_IOT_JOBS_MQTT_ERROR + * - #AWS_IOT_JOBS_BAD_RESPONSE + * - A Jobs failure reason between #AWS_IOT_JOBS_INVALID_TOPIC and #AWS_IOT_JOBS_TERMINAL_STATE. + * + * @see @ref jobs_function_updatesync for a blocking variant of this function. + * + * Example + * @code{c} + * #define THING_NAME "Test_device" + * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1 ) + * + * // Signature of Jobs callback function. + * void _jobsCallback( void * pCallbackContext, AwsIotJobsCallbackParam_t * pCallbackParam ); + * + * AwsIotJobsOperation_t updateOperation = AWS_IOT_JOBS_OPERATION_INITIALIZER; + * AwsIotJobsRequestInfo_t requestInfo = AWS_IOT_JOBS_REQUEST_INFO_INITIALIZER; + * AwsIotJobsUpdateInfo_t updateInfo = AWS_IOT_JOBS_UPDATE_INFO_INITIALIZER; + * AwsIotJobsCallbackInfo_t callbackInfo = AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER; + * + * // Set the request info. + * requestInfo.mqttConnection = _mqttConnection; + * requestInfo.pThingName = THING_NAME; + * requestInfo.thingNameLength = THING_NAME_LENGTH; + * + * // A Job ID must be set. AWS_IOT_JOBS_NEXT_JOB is not valid for UPDATE. + * requestInfo.pJobId = "job-id"; + * requestInfo.jobIdLength = 6; + * + * // Set the update info. + * updateInfo.newStatus = AWS_IOT_JOB_STATE_SUCCEEDED; + * + * // Set the callback function to invoke. + * callbackInfo.function = _jobsCallback; + * + * // Queue Jobs UPDATE. + * AwsIotJobsError_t updateResult = AwsIotJobs_UpdateAsync( &requestInfo, + * &updateInfo, + * 0, + * &callbackInfo, + * &updateOperation ); + * + * // UPDATE should have returned AWS_IOT_JOBS_STATUS_PENDING. The function + * // _jobsCallback will be invoked once the Jobs response is received. + * @endcode + */ +/* @[declare_jobs_updateasync] */ +AwsIotJobsError_t AwsIotJobs_UpdateAsync( const AwsIotJobsRequestInfo_t * pRequestInfo, + const AwsIotJobsUpdateInfo_t * pUpdateInfo, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pCallbackInfo, + AwsIotJobsOperation_t * const pUpdateOperation ); +/* @[declare_jobs_updateasync] */ + +/** + * @brief Update the status of a job execution with a timeout for receiving the + * response. + * + * This function queues a Jobs UPDATE, then waits for the result. Internally, + * this function is a call to @ref jobs_function_updateasync followed by + * @ref jobs_function_wait. See @ref jobs_function_updateasync for more information + * on the Jobs UPDATE command. + * + * @param[in] pRequestInfo Jobs request parameters. + * @param[in] pUpdateInfo Jobs update parameters. + * @param[in] flags Flags which modify the behavior of the Jobs request. See + * @ref jobs_constants_flags. + * @param[in] timeoutMs If a response is not received within this timeout, this + * function returns #AWS_IOT_JOBS_TIMEOUT. + * @param[out] pJobsResponse The response received from the Jobs service. + * + * @return One of the following: + * - #AWS_IOT_JOBS_SUCCESS + * - #AWS_IOT_JOBS_NOT_INITIALIZED + * - #AWS_IOT_JOBS_BAD_PARAMETER + * - #AWS_IOT_JOBS_NO_MEMORY + * - #AWS_IOT_JOBS_MQTT_ERROR + * - #AWS_IOT_JOBS_BAD_RESPONSE + * - #AWS_IOT_JOBS_TIMEOUT + * - A Jobs failure reason between #AWS_IOT_JOBS_INVALID_TOPIC and #AWS_IOT_JOBS_TERMINAL_STATE. + */ +/* @[declare_jobs_updatesync] */ +AwsIotJobsError_t AwsIotJobs_UpdateSync( const AwsIotJobsRequestInfo_t * pRequestInfo, + const AwsIotJobsUpdateInfo_t * pUpdateInfo, + uint32_t flags, + uint32_t timeoutMs, + AwsIotJobsResponse_t * const pJobsResponse ); +/* @[declare_jobs_updatesync] */ + +/** + * @brief Wait for a Jobs operation to complete. + * + * This function blocks to wait for a [GET PENDING](@ref jobs_function_getpendingasync), + * [START NEXT](@ref jobs_function_startnextasync), [DESCRIBE](@ref jobs_function_describeasync), + * or [UPDATE](@ref jobs_function_updateasync) operation to complete. These operations are + * by default asynchronous; the function calls queue an operation for processing, + * and a callback is invoked once the operation is complete. + * + * To use this function, the flag #AWS_IOT_JOBS_FLAG_WAITABLE must have been + * set in the operation's function call. Additionally, this function must always + * be called with any waitable operation to clean up resources. + * + * Regardless of its return value, this function always clean up resources used + * by the waitable operation. This means `operation` is invalidated as soon as + * this function returns, even if it returns #AWS_IOT_JOBS_TIMEOUT or another + * error. + * + * @param[in] operation Reference to the Jobs operation to wait for. The flag + * #AWS_IOT_JOBS_FLAG_WAITABLE must have been set for this operation. + * @param[in] timeoutMs How long to wait before returning #AWS_IOT_JOBS_TIMEOUT. + * @param[out] pJobsResponse The response received from the Jobs service. + * + * @return One of the following: + * - #AWS_IOT_JOBS_SUCCESS + * - #AWS_IOT_JOBS_NOT_INITIALIZED + * - #AWS_IOT_JOBS_BAD_PARAMETER + * - #AWS_IOT_JOBS_BAD_RESPONSE + * - #AWS_IOT_JOBS_TIMEOUT + * - A Jobs failure reason between #AWS_IOT_JOBS_INVALID_TOPIC and #AWS_IOT_JOBS_TERMINAL_STATE. + * + * Example: + * @code{c} + * #define THING_NAME "Test_device" + * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1 ) + * + * AwsIotJobsOperation_t updateOperation = AWS_IOT_JOBS_OPERATION_INITIALIZER; + * AwsIotJobsRequestInfo_t requestInfo = AWS_IOT_JOBS_REQUEST_INFO_INITIALIZER; + * AwsIotJobsUpdateInfo_t updateInfo = AWS_IOT_JOBS_UPDATE_INFO_INITIALIZER; + * AwsIotJobsResponse_t jobsResponse = AWS_IOT_JOBS_RESPONSE_INITIALIZER; + * + * // Set the request info. + * requestInfo.mqttConnection = _mqttConnection; + * requestInfo.pThingName = THING_NAME; + * requestInfo.thingNameLength = THING_NAME_LENGTH; + * + * // Set the function used to allocate memory for an incoming response. + * requestInfo.mallocResponse = malloc; + * + * // A Job ID must be set. AWS_IOT_JOBS_NEXT_JOB is not valid for UPDATE. + * requestInfo.pJobId = "job-id"; + * requestInfo.jobIdLength = 6; + * + * // Set the update info. + * updateInfo.newStatus = AWS_IOT_JOB_STATE_SUCCEEDED; + * + * // Queue Jobs UPDATE. + * AwsIotJobsError_t updateResult = AwsIotJobs_UpdateAsync( &requestInfo, + * &updateInfo, + * AWS_IOT_JOBS_FLAG_WAITABLE, + * NULL, + * &updateOperation ); + * + * // UPDATE should have returned AWS_IOT_JOBS_STATUS_PENDING. The call to wait + * // returns once the result of the UPDATE is available or the timeout expires. + * if( updateResult == AWS_IOT_JOBS_STATUS_PENDING ) + * { + * updateResult = AwsIotJobs_Wait( updateOperation, 5000, &jobsResponse ); + * + * if( updateResult == AWS_IOT_JOBS_SUCCESS ) + * { + * // Jobs operation succeeded. Do something with the Jobs response. + * + * // Once the Jobs response is no longer needed, free it. + * free( jobsResponse.pJobsResponse ); + * } + * else + * { + * // Jobs operation failed. + * } + * } + * @endcode + */ +/* @[declare_jobs_wait] */ +AwsIotJobsError_t AwsIotJobs_Wait( AwsIotJobsOperation_t operation, + uint32_t timeoutMs, + AwsIotJobsResponse_t * const pJobsResponse ); +/* @[declare_jobs_wait] */ + +/** + * @brief Set a callback to be invoked when the list of pending Jobs changes. + * + * The Jobs service publishes a [JobExecutionsChanged] + * (https://docs.aws.amazon.com/iot/latest/developerguide/jobs-api.html#mqtt-jobexecutionschanged) + * message to the `jobs/notify` topic whenever a Job execution is added to or + * removed from the list of pending Job executions for a Thing. The message sent is + * useful for monitoring the list of pending Job executions. + * + * A NOTIFY PENDING callback may be invoked whenever a message is published + * to `jobs/notify`. Each Thing may have up to @ref AWS_IOT_JOBS_NOTIFY_CALLBACKS + * NOTIFY PENDING callbacks set. This function modifies the NOTIFY PENDING callback + * for a specific Thing depending on the `pNotifyPendingCallback` parameter and the + * presence of any existing NOTIFY PENDING callback. + * - When no existing NOTIFY PENDING callback exists for a specific Thing, a new + * callback is added. + * - If there is an existing NOTIFY PENDING callback and `pNotifyPendingCallback` is not `NULL`, + * then the existing callback function and parameter are replaced with `pNotifyPendingCallback`. + * - If there is an existing NOTIFY PENDING callback and `pNotifyPendingCallback` is `NULL`, + * then the callback is removed. + * + * The member @ref AwsIotJobsCallbackInfo_t.oldFunction must be used to select an + * already-registered callback function for replacement or removal when @ref + * AWS_IOT_JOBS_NOTIFY_CALLBACKS is greater than `1`. When multiple callbacks are + * set, all of them will be invoked when a message is received. + * + * @param[in] mqttConnection The MQTT connection to use for the subscription to `jobs/notify`. + * @param[in] pThingName The subscription to `jobs/notify` will be added for + * this Thing Name. + * @param[in] thingNameLength The length of `pThingName`. + * @param[in] flags This parameter is for future-compatibility. Currently, flags are + * not supported for this function and this parameter is ignored. + * @param[in] pNotifyPendingCallback Callback function to invoke for incoming messages. + * + * @return One of the following: + * - #AWS_IOT_JOBS_SUCCESS + * - #AWS_IOT_JOBS_NOT_INITIALIZED + * - #AWS_IOT_JOBS_BAD_PARAMETER + * - #AWS_IOT_JOBS_NO_MEMORY + * - #AWS_IOT_JOBS_MQTT_ERROR + * - #AWS_IOT_JOBS_TIMEOUT + * + * @see @ref jobs_function_setnotifynextcallback for the function to register callbacks + * for next Job changes. + * + * Example: + * @code{c} + * #define THING_NAME "Test_device" + * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1 ) + * + * AwsIotJobsError_t result = AWS_IOT_JOBS_STATUS_PENDING; + * AwsIotJobsCallbackInfo_t notifyPendingCallback = AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER; + * + * // _jobsCallback will be invoked when any messages are received. + * notifyPendingCallback.function = _jobsCallback; + * + * // Set the NOTIFY PENDING callback for the Thing "Test_device". + * result = AwsIotJobs_SetNotifyPendingCallback( mqttConnection, + * THING_NAME, + * THING_NAME_LENGTH, + * 0, + * ¬ifyPendingCallback ); + * + * // Check if the callback was successfully set. + * if( status == AWS_IOT_JOBS_SUCCESS ) + * { + * // The callback will now be invoked whenever the list of pending Job + * // executions changes. + * + * // Once the callback is no longer needed, it may be removed by passing + * // NULL as the callback function and specifying the function to remove. + * notifyPendingCallback.function = NULL; + * notifyPendingCallback.oldFunction = _jobsCallback; + * + * status = AwsIotJobs_SetNotifyPendingCallback( mqttConnection, + * THING_NAME, + * THING_NAME_LENGTH, + * 0, + * ¬ifyPendingCallback ); + * + * // The return value from removing a callback should always be success. + * assert( status == AWS_IOT_JOBS_SUCCESS ); + * } + * @endcode + */ +/* @[declare_jobs_setnotifypendingcallback] */ +AwsIotJobsError_t AwsIotJobs_SetNotifyPendingCallback( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pNotifyPendingCallback ); +/* @[declare_jobs_setnotifypendingcallback] */ + +/** + * @brief Set a callback to be invoked when the next pending Job changes. + * + * The Jobs service publishes a [NextJobExecutionChanged] + * (https://docs.aws.amazon.com/iot/latest/developerguide/jobs-api.html#mqtt-nextjobexecutionchanged) + * message to the `jobs/notify-next` topic whenever the next Job execution in + * the list of pending Job executions changes for a Thing. The message sent is + * useful for being notified of changes to the next Job. + * + * A NOTIFY NEXT callback may be invoked whenever a message is published + * to `jobs/notify-next`. Each Thing may have up to @ref AWS_IOT_JOBS_NOTIFY_CALLBACKS + * NOTIFY NEXT callbacks set. This function modifies the NOTIFY NEXT callback for + * a specific Thing depending on the `pNotifyNextCallback` parameter and the presence + * of any existing NOTIFY NEXT callback. + * - When no existing NOTIFY NEXT callback exists for a specific Thing, a new + * callback is added. + * - If there is an existing NOTIFY NEXT callback and `pNotifyNextCallback` is not `NULL`, + * then the existing callback function and parameter are replaced with `pNotifyNextCallback`. + * - If there is an existing NOTIFY NEXT callback and `pNotifyNextCallback` is `NULL`, + * then the callback is removed. + * + * The member @ref AwsIotJobsCallbackInfo_t.oldFunction must be used to select an + * already-registered callback function for replacement or removal when @ref + * AWS_IOT_JOBS_NOTIFY_CALLBACKS is greater than `1`. When multiple callbacks are + * set, all of them will be invoked when a message is received. + * + * @param[in] mqttConnection The MQTT connection to use for the subscription to `jobs/notify-next`. + * @param[in] pThingName The subscription to `jobs/notify-next` will be added for + * this Thing Name. + * @param[in] thingNameLength The length of `pThingName`. + * @param[in] flags This parameter is for future-compatibility. Currently, flags are + * not supported for this function and this parameter is ignored. + * @param[in] pNotifyNextCallback Callback function to invoke for incoming messages. + * + * @return One of the following: + * - #AWS_IOT_JOBS_SUCCESS + * - #AWS_IOT_JOBS_NOT_INITIALIZED + * - #AWS_IOT_JOBS_BAD_PARAMETER + * - #AWS_IOT_JOBS_NO_MEMORY + * - #AWS_IOT_JOBS_MQTT_ERROR + * - #AWS_IOT_JOBS_TIMEOUT + * + * @see @ref jobs_function_setnotifypendingcallback for the function to register callbacks + * for all pending Job changes. + * + * Example: + * @code{c} + * #define THING_NAME "Test_device" + * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1 ) + * + * AwsIotJobsError_t result = AWS_IOT_JOBS_STATUS_PENDING; + * AwsIotJobsCallbackInfo_t notifyNextCallback = AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER; + * + * // _jobsCallback will be invoked when any messages are received. + * notifyNextCallback.function = _jobsCallback; + * + * // Set the NOTIFY NEXT callback for the Thing "Test_device". + * result = AwsIotJobs_SetNotifyNextCallback( mqttConnection, + * THING_NAME, + * THING_NAME_LENGTH, + * 0, + * ¬ifyNextCallback ); + * + * // Check if the callback was successfully set. + * if( status == AWS_IOT_JOBS_SUCCESS ) + * { + * // The callback will now be invoked whenever the next pending Job + * // execution changes. + * + * // Once the callback is no longer needed, it may be removed by passing + * // NULL as the callback function and specifying the function to remove. + * notifyNextCallback.function = NULL; + * notifyNextCallback.oldFunction = _jobsCallback; + * + * status = AwsIotJobs_SetNotifyNextCallback( mqttConnection, + * THING_NAME, + * THING_NAME_LENGTH, + * 0, + * ¬ifyNextCallback ); + * + * // The return value from removing a callback should always be success. + * assert( status == AWS_IOT_JOBS_SUCCESS ); + * } + * @endcode + */ +/* @[declare_jobs_setnotifynextcallback] */ +AwsIotJobsError_t AwsIotJobs_SetNotifyNextCallback( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pNotifyNextCallback ); +/* @[declare_jobs_setnotifynextcallback] */ + +/** + * @brief Remove persistent Jobs operation topic subscriptions. + * + * Passing the flag @ref AWS_IOT_JOBS_FLAG_KEEP_SUBSCRIPTIONS to @ref jobs_function_getpendingasync, + * @ref jobs_function_startnextasync, @ref jobs_function_describeasync, @ref jobs_function_updateasync, + * or their blocking versions causes the Jobs operation topic subscriptions to be + * maintained for future calls to the same function. If a persistent subscription for a + * Jobs topic are no longer needed, this function may be used to remove it. + * + * @param[in] pRequestInfo Jobs request info. Only the [pThingName] + * (@ref #AwsIotJobsRequestInfo_t.pThingName), [thingNameLength] + * (@ref #AwsIotJobsRequestInfo_t.thingNameLength), and [mqttConnection] + * (@ref #AwsIotJobsRequestInfo_t.mqttConnection) members need to be set for this + * function. + * @param[in] flags Flags that determine which subscriptions to remove. Valid values are + * the bitwise OR of the following individual flags: + * - @ref AWS_IOT_JOBS_FLAG_REMOVE_GET_PENDING_SUBSCRIPTIONS + * - @ref AWS_IOT_JOBS_FLAG_REMOVE_START_NEXT_SUBSCRIPTIONS + * - @ref AWS_IOT_JOBS_FLAG_REMOVE_DESCRIBE_SUBSCRIPTIONS + * - @ref AWS_IOT_JOBS_FLAG_REMOVE_UPDATE_SUBSCRIPTIONS + * + * @return On success: + * - #AWS_IOT_JOBS_SUCCESS + * @return If an MQTT UNSUBSCRIBE packet cannot be sent, one of the following: + * - #AWS_IOT_JOBS_NO_MEMORY + * - #AWS_IOT_JOBS_MQTT_ERROR + * + * @note @ref jobs_function_cleanup removes persistent sessions as well. + * + * @warning This function is not safe to call with any in-progress operations! + * It also does not affect NOTIFY PENDING and NOTIFY NEXT callbacks registered + * with @ref jobs_function_setnotifypendingcallback and + * @ref jobs_function_setnotifynextcallback, respectively. (See documentation for + * those functions on how to remove their callbacks). + */ +/* @[declare_jobs_removepersistentsubscriptions] */ +AwsIotJobsError_t AwsIotJobs_RemovePersistentSubscriptions( const AwsIotJobsRequestInfo_t * pRequestInfo, + uint32_t flags ); +/* @[declare_jobs_removepersistentsubscriptions] */ + +/*-------------------------- Jobs helper functions --------------------------*/ + +/** + * @brief Returns a string that describes an #AwsIotJobsError_t. + * + * Like POSIX's `strerror`, this function returns a string describing a return + * code. In this case, the return code is a Jobs library error code, `status`. + * + * The string returned by this function MUST be treated as read-only: any + * attempt to modify its contents may result in a crash. Therefore, this function + * is limited to usage in logging. + * + * @param[in] status The status to describe. + * + * @return A read-only string that describes `status`. + * + * @warning The string returned by this function must never be modified. + */ +/* @[declare_jobs_strerror] */ +const char * AwsIotJobs_strerror( AwsIotJobsError_t status ); +/* @[declare_jobs_strerror] */ + +/** + * @brief Returns a string that describes an #AwsIotJobState_t. + * + * This function returns a string describing a Job state, `state`. + * + * The string returned by this function MUST be treated as read-only: any + * attempt to modify its contents may result in a crash. Therefore, this function + * is limited to usage in logging. + * + * @param[in] state The job state to describe. + * + * @return A read-only string that describes `state`. + * + * @warning The string returned by this function must never be modified. + */ +/* @[declare_jobs_statename] */ +const char * AwsIotJobs_StateName( AwsIotJobState_t state ); +/* @[declare_jobs_statename] */ + +#endif /* ifndef AWS_IOT_JOBS_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/include/types/aws_iot_jobs_types.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/include/types/aws_iot_jobs_types.h new file mode 100644 index 000000000..dbeebb70e --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/include/types/aws_iot_jobs_types.h @@ -0,0 +1,1011 @@ +/* + * AWS IoT Jobs V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_jobs_types.h + * @brief Types of the Jobs library. + */ + +#ifndef AWS_IOT_JOBS_TYPES_H_ +#define AWS_IOT_JOBS_TYPES_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* MQTT types include. */ +#include "types/iot_mqtt_types.h" + +/*---------------------------- Jobs handle types ----------------------------*/ + +/** + * @handles{jobs,Jobs library} + */ + +/** + * @ingroup jobs_datatypes_handles + * @brief Opaque handle that references an in-progress Jobs operation. + * + * Set as an output parameter of @ref jobs_function_getpendingasync, @ref jobs_function_startnextasync, + * @ref jobs_function_describeasync, and @ref jobs_function_updateasync. These functions send a + * message to the Jobs service requesting a Jobs operation; the result of this operation + * is unknown until the Jobs service sends a response. Therefore, this handle serves as a + * reference to Jobs operations awaiting a response from the Jobs service. + * + * This reference will be valid from the successful return of @ref jobs_function_getpendingasync, + * @ref jobs_function_startnextasync, @ref jobs_function_describeasync, and @ref jobs_function_updateasync. + * The reference becomes invalid once the [completion callback](@ref AwsIotJobsCallbackInfo_t) + * is invoked, or @ref jobs_function_wait returns. + * + * @initializer{AwsIotJobsOperation_t,AWS_IOT_JOBS_OPERATION_INITIALIZER} + * + * @see @ref jobs_function_wait and #AWS_IOT_JOBS_FLAG_WAITABLE for waiting on + * a reference; or #AwsIotJobsCallbackInfo_t and #AwsIotJobsCallbackParam_t for an + * asynchronous notification of completion. + */ +typedef struct _jobsOperation * AwsIotJobsOperation_t; + +/*-------------------------- Jobs enumerated types --------------------------*/ + +/** + * @enums{jobs,Jobs library} + */ + +/** + * @ingroup jobs_datatypes_enums + * @brief Return codes of [Jobs functions](@ref jobs_functions). + * + * The function @ref jobs_function_strerror can be used to get a return code's + * description. + * + * The values between #AWS_IOT_JOBS_INVALID_TOPIC and #AWS_IOT_JOBS_TERMINAL_STATE + * may be returned by the Jobs service upon failure of a Jobs operation. See [this page] + * (https://docs.aws.amazon.com/iot/latest/developerguide/jobs-api.html#jobs-mqtt-error-response) + * for more information. + */ +typedef enum AwsIotJobsError +{ + /** + * @brief Jobs operation completed successfully. + * + * Functions that may return this value: + * - @ref jobs_function_init + * - @ref jobs_function_wait + * - @ref jobs_function_getpendingsync + * - @ref jobs_function_startnextsync + * - @ref jobs_function_describesync + * - @ref jobs_function_updatesync + * - @ref jobs_function_setnotifypendingcallback + * - @ref jobs_function_setnotifynextcallback + * - @ref jobs_function_removepersistentsubscriptions + * + * Will also be the value of a Jobs operation completion callback's
+ * [AwsIotJobsCallbackParam_t.operation.result](@ref AwsIotJobsCallbackParam_t.result) + * when successful. + */ + AWS_IOT_JOBS_SUCCESS = 0, + + /** + * @brief Jobs operation queued, awaiting result. + * + * Functions that may return this value: + * - @ref jobs_function_getpendingasync + * - @ref jobs_function_startnextasync + * - @ref jobs_function_describeasync + * - @ref jobs_function_updateasync + */ + AWS_IOT_JOBS_STATUS_PENDING = 1, + + /** + * @brief Initialization failed. + * + * Functions that may return this value: + * - @ref jobs_function_init + */ + AWS_IOT_JOBS_INIT_FAILED = 2, + + /** + * @brief At least one parameter is invalid. + * + * Functions that may return this value: + * - @ref jobs_function_getpendingasync and @ref jobs_function_getpendingsync + * - @ref jobs_function_startnextasync and @ref jobs_function_startnextsync + * - @ref jobs_function_describeasync and @ref jobs_function_describesync + * - @ref jobs_function_updateasync and @ref jobs_function_updatesync + * - @ref jobs_function_wait + * - @ref jobs_function_setnotifypendingcallback + * - @ref jobs_function_setnotifynextcallback + * - @ref jobs_function_removepersistentsubscriptions + */ + AWS_IOT_JOBS_BAD_PARAMETER = 3, + + /** + * @brief Jobs operation failed because of memory allocation failure. + * + * Functions that may return this value: + * - @ref jobs_function_getpendingasync and @ref jobs_function_getpendingsync + * - @ref jobs_function_startnextasync and @ref jobs_function_startnextsync + * - @ref jobs_function_describeasync and @ref jobs_function_describesync + * - @ref jobs_function_updateasync and @ref jobs_function_updatesync + * - @ref jobs_function_setnotifypendingcallback + * - @ref jobs_function_setnotifynextcallback + */ + AWS_IOT_JOBS_NO_MEMORY = 4, + + /** + * @brief Jobs operation failed because of failure in MQTT library. + * + * Functions that may return this value: + * - @ref jobs_function_getpendingasync and @ref jobs_function_getpendingsync + * - @ref jobs_function_startnextasync and @ref jobs_function_startnextsync + * - @ref jobs_function_describeasync and @ref jobs_function_describesync + * - @ref jobs_function_updateasync and @ref jobs_function_updatesync + * - @ref jobs_function_setnotifypendingcallback + * - @ref jobs_function_setnotifynextcallback + * - @ref jobs_function_removepersistentsubscriptions + */ + AWS_IOT_JOBS_MQTT_ERROR = 5, + + /** + * @brief Response received from Jobs service not understood. + * + * Functions that may return this value: + * - @ref jobs_function_getpendingsync + * - @ref jobs_function_startnextsync + * - @ref jobs_function_describesync + * - @ref jobs_function_updatesync + * - @ref jobs_function_wait + * + * May also be the value of a Jobs operation completion callback's
+ * [AwsIotJobsCallbackParam_t.operation.result](@ref AwsIotJobsCallbackParam_t.result). + */ + AWS_IOT_JOBS_BAD_RESPONSE = 7, + + /** + * @brief A blocking Jobs operation timed out. + * + * Functions that may return this value: + * - @ref jobs_function_getpendingsync + * - @ref jobs_function_startnextsync + * - @ref jobs_function_describesync + * - @ref jobs_function_updatesync + * - @ref jobs_function_wait + * - @ref jobs_function_setnotifypendingcallback + * - @ref jobs_function_setnotifynextcallback + */ + AWS_IOT_JOBS_TIMEOUT = 8, + + /** + * @brief An API function was called before @ref jobs_function_init. + * + * Functions that may return this value: + * - @ref jobs_function_getpendingasync and @ref jobs_function_getpendingsync + * - @ref jobs_function_startnextasync and @ref jobs_function_startnextsync + * - @ref jobs_function_describeasync and @ref jobs_function_describesync + * - @ref jobs_function_updateasync and @ref jobs_function_updatesync + * - @ref jobs_function_wait + * - @ref jobs_function_setnotifypendingcallback + * - @ref jobs_function_setnotifynextcallback + */ + AWS_IOT_JOBS_NOT_INITIALIZED = 11, + + /** + * @brief Jobs operation failed: A request was sent to an unknown topic. + * + * Functions that may return this value: + * - @ref jobs_function_getpendingsync + * - @ref jobs_function_startnextsync + * - @ref jobs_function_describesync + * - @ref jobs_function_updatesync + * - @ref jobs_function_wait + * + * May also be the value of a Jobs operation completion callback's
+ * [AwsIotJobsCallbackParam_t.operation.result](@ref AwsIotJobsCallbackParam_t.result). + */ + AWS_IOT_JOBS_INVALID_TOPIC = 12, + + /** + * @brief Jobs operation failed: The contents of the request were not understood. + * + * Jobs requests must be UTF-8 encoded JSON documents. + * + * Functions that may return this value: + * - @ref jobs_function_getpendingsync + * - @ref jobs_function_startnextsync + * - @ref jobs_function_describesync + * - @ref jobs_function_updatesync + * - @ref jobs_function_wait + * + * May also be the value of a Jobs operation completion callback's
+ * [AwsIotJobsCallbackParam_t.operation.result](@ref AwsIotJobsCallbackParam_t.result). + */ + AWS_IOT_JOBS_INVALID_JSON = 13, + + /** + * @brief Jobs operation failed: The contents of the request were invalid. + * + * Functions that may return this value: + * - @ref jobs_function_getpendingsync + * - @ref jobs_function_startnextsync + * - @ref jobs_function_describesync + * - @ref jobs_function_updatesync + * - @ref jobs_function_wait + * + * May also be the value of a Jobs operation completion callback's
+ * [AwsIotJobsCallbackParam_t.operation.result](@ref AwsIotJobsCallbackParam_t.result). + */ + AWS_IOT_JOBS_INVALID_REQUEST = 14, + + /** + * @brief Jobs operation failed: An update attempted to change the job execution + * to an invalid state. + * + * Functions that may return this value: + * - @ref jobs_function_startnextsync + * - @ref jobs_function_updatesync + * - @ref jobs_function_wait + * + * May also be the value of a Jobs operation completion callback's
+ * [AwsIotJobsCallbackParam_t.operation.result](@ref AwsIotJobsCallbackParam_t.result) + * following a call to @ref jobs_function_startnextasync or @ref jobs_function_updateasync. + */ + AWS_IOT_JOBS_INVALID_STATE = 15, + + /** + * @brief Jobs operation failed: The specified job execution does not exist. + * + * * Functions that may return this value: + * - @ref jobs_function_describesync + * - @ref jobs_function_updatesync + * - @ref jobs_function_wait + * + * May also be the value of a Jobs operation completion callback's
+ * [AwsIotJobsCallbackParam_t.operation.result](@ref AwsIotJobsCallbackParam_t.result) + * following a call to @ref jobs_function_describeasync or @ref jobs_function_updateasync. + */ + AWS_IOT_JOBS_NOT_FOUND = 16, + + /** + * @brief Jobs operation failed: The Jobs service expected a version that did + * not match what was in the request. + * + * * Functions that may return this value: + * - @ref jobs_function_updatesync + * - @ref jobs_function_wait + * + * May also be the value of a Jobs operation completion callback's
+ * [AwsIotJobsCallbackParam_t.operation.result](@ref AwsIotJobsCallbackParam_t.result) + * following a call to @ref jobs_function_updateasync. + */ + AWS_IOT_JOBS_VERSION_MISMATCH = 17, + + /** + * @brief Jobs operation failed: The Jobs service encountered an internal error. + * + * Functions that may return this value: + * - @ref jobs_function_getpendingsync + * - @ref jobs_function_startnextsync + * - @ref jobs_function_describesync + * - @ref jobs_function_updatesync + * - @ref jobs_function_wait + * + * May also be the value of a Jobs operation completion callback's
+ * [AwsIotJobsCallbackParam_t.operation.result](@ref AwsIotJobsCallbackParam_t.result). + */ + AWS_IOT_JOBS_INTERNAL_ERROR = 18, + + /** + * @brief Jobs operation failed: The request was throttled. + * + * Functions that may return this value: + * - @ref jobs_function_getpendingsync + * - @ref jobs_function_startnextsync + * - @ref jobs_function_describesync + * - @ref jobs_function_updatesync + * - @ref jobs_function_wait + * + * May also be the value of a Jobs operation completion callback's
+ * [AwsIotJobsCallbackParam_t.operation.result](@ref AwsIotJobsCallbackParam_t.result). + */ + AWS_IOT_JOBS_THROTTLED = 19, + + /** + * @brief Jobs operation failed: Attempt to describe a Job in a terminal state. + * + * Functions that may return this value: + * - @ref jobs_function_describesync + * - @ref jobs_function_wait + * + * May also be the value of a Jobs operation completion callback's
+ * [AwsIotJobsCallbackParam_t.operation.result](@ref AwsIotJobsCallbackParam_t.result) + * following a call to @ref jobs_function_describeasync. + */ + AWS_IOT_JOBS_TERMINAL_STATE = 20 +} AwsIotJobsError_t; + +/** + * @ingroup jobs_datatypes_enums + * @brief Possible states of jobs. + * + * The function @ref jobs_function_statename can be used to get a state's + * description. + * + * See [this page] + * (https://docs.aws.amazon.com/iot/latest/apireference/API_iot-jobs-data_JobExecutionState.html) + * for more information on Job states. + */ +typedef enum AwsIotJobState +{ + /** + * @brief A Job is queued and awaiting execution. + */ + AWS_IOT_JOB_STATE_QUEUED, + + /** + * @brief A Job is currently executing. + */ + AWS_IOT_JOB_STATE_IN_PROGRESS, + + /** + * @brief A Job has failed. This is a terminal state. + */ + AWS_IOT_JOB_STATE_FAILED, + + /** + * @brief A Job has succeeded. This is a terminal state. + */ + AWS_IOT_JOB_STATE_SUCCEEDED, + + /** + * @brief A Job was canceled. This is a terminal state. + */ + AWS_IOT_JOB_STATE_CANCELED, + + /** + * @brief A Job's timer has expired. This is a terminal state. + * + * Jobs are considered timed out if they remain [IN_PROGRESS] + * (@ref AWS_IOT_JOB_STATE_IN_PROGRESS) for more than their + * `inProgressTimeoutInMinutes` property or a [Job update](@ref jobs_function_updateasync) + * was not sent within [stepTimeoutInMinutes](@ref AwsIotJobsUpdateInfo_t.stepTimeoutInMinutes). + */ + AWS_IOT_JOB_STATE_TIMED_OUT, + + /** + * @brief A Job was rejected by the device. This is a terminal state. + */ + AWS_IOT_JOB_STATE_REJECTED, + + /** + * @brief A Job was removed. This is a terminal state. + */ + AWS_IOT_JOB_STATE_REMOVED +} AwsIotJobState_t; + +/** + * @ingroup jobs_datatypes_enums + * @brief Types of Jobs library callbacks. + * + * One of these values will be placed in #AwsIotJobsCallbackParam_t.callbackType + * to identify the reason for invoking a callback function. + */ +typedef enum AwsIotJobsCallbackType +{ + AWS_IOT_JOBS_GET_PENDING_COMPLETE = 0, /**< Callback invoked because a [Jobs get pending](@ref jobs_function_getpendingasync) completed. */ + AWS_IOT_JOBS_START_NEXT_COMPLETE = 1, /**< Callback invoked because a [Jobs start next](@ref jobs_function_startnextasync) completed. */ + AWS_IOT_JOBS_DESCRIBE_COMPLETE = 2, /**< Callback invoked because a [Jobs describe](@ref jobs_function_describeasync) completed. */ + AWS_IOT_JOBS_UPDATE_COMPLETE = 3, /**< Callback invoked because a [Jobs update](@ref jobs_function_updateasync) completed. */ + AWS_IOT_JOBS_NOTIFY_PENDING_CALLBACK = 4, /**< Callback invoked for an incoming message on a [Jobs notify-pending](@ref jobs_function_setnotifypendingcallback) topic. */ + AWS_IOT_JOBS_NOTIFY_NEXT_CALLBACK = 5 /**< Callback invoked for an incoming message on a [Jobs notify-next](@ref jobs_function_setnotifynextcallback) topic. */ +} AwsIotJobsCallbackType_t; + +/*-------------------------- Jobs parameter structs -------------------------*/ + +/** + * @paramstructs{jobs,Jobs library} + */ + +/** + * @ingroup jobs_datatypes_paramstructs + * @brief Parameter to a Jobs callback function. + * + * @paramfor Jobs callback functions + * + * The Jobs library passes this struct to a callback function whenever a + * Jobs operation completes or a message is received on a Jobs notify-pending + * or notify-next topic. + * + * The valid members of this struct are different based on + * #AwsIotJobsCallbackParam_t.callbackType. If the callback type is + * #AWS_IOT_JOBS_GET_PENDING_COMPLETE, #AWS_IOT_JOBS_START_NEXT_COMPLETE, + * #AWS_IOT_JOBS_DESCRIBE_COMPLETE, or #AWS_IOT_JOBS_UPDATE_COMPLETE, then + * #AwsIotJobsCallbackParam_t.operation is valid. Otherwise, if the callback type + * is #AWS_IOT_JOBS_NOTIFY_PENDING_CALLBACK or #AWS_IOT_JOBS_NOTIFY_NEXT_CALLBACK, + * then #AwsIotJobsCallbackParam_t.callback is valid. + * + * @attention Any pointers in this callback parameter may be freed as soon as the + * [callback function](@ref AwsIotJobsCallbackInfo_t.function) returns. Therefore, + * data must be copied if it is needed after the callback function returns. + * @attention The Jobs library may set strings that are not NULL-terminated. + * + * @see #AwsIotJobsCallbackInfo_t for the signature of a callback function. + */ +typedef struct AwsIotJobsCallbackParam +{ + AwsIotJobsCallbackType_t callbackType; /**< @brief Reason for invoking the Jobs callback function to provide context. */ + + const char * pThingName; /**< @brief The Thing Name associated with this Jobs callback. */ + size_t thingNameLength; /**< @brief Length of #AwsIotJobsCallbackParam_t.pThingName. */ + + IotMqttConnection_t mqttConnection; /**< @brief The MQTT connection associated with the Jobs callback. */ + + union + { + /* Valid for completed Jobs operations. */ + struct + { + AwsIotJobsError_t result; /**< @brief Result of Jobs operation, e.g. succeeded or failed. */ + AwsIotJobsOperation_t reference; /**< @brief Reference to the Jobs operation that completed. */ + + const char * pResponse; /**< @brief Response retrieved from the Jobs service. */ + size_t responseLength; /**< @brief Length of retrieved response. */ + } operation; /**< @brief Information on a completed Jobs operation. */ + + /* Valid for a message on a Jobs notify-pending or notify-next topic. */ + struct + { + const char * pDocument; /**< @brief Job execution document received on callback. */ + size_t documentLength; /**< @brief Length of job execution document. */ + } callback; /**< @brief Jobs document from an incoming delta or updated topic. */ + } u; /**< @brief Valid member depends on callback type. */ +} AwsIotJobsCallbackParam_t; + +/** + * @ingroup jobs_datatypes_paramstructs + * @brief Information on a user-provided Jobs callback function. + * + * @paramfor @ref jobs_function_getpendingasync, @ref jobs_function_startnextasync, + * @ref jobs_function_describeasync, @ref jobs_function_updateasync, + * @ref jobs_function_setnotifypendingcallback, @ref jobs_function_setnotifynextcallback + * + * Provides a function to be invoked when a Jobs operation completes or when a + * Jobs document is received on a callback topic (notify-pending or notify-next). + * + * @initializer{AwsIotJobsCallbackInfo_t,AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER} + */ +typedef struct AwsIotJobsCallbackInfo +{ + void * pCallbackContext; /**< @brief The first parameter to pass to the callback function. */ + + /** + * @brief User-provided callback function signature. + * + * @param[in] void* #AwsIotJobsCallbackInfo_t.pCallbackContext + * @param[in] AwsIotJobsCallbackParam_t* Details on the outcome of the Jobs + * operation or an incoming Job document. + * + * @see #AwsIotJobsCallbackParam_t for more information on the second parameter. + */ + void ( * function )( void *, + AwsIotJobsCallbackParam_t * ); + + /** + * @brief Callback function to replace when passed to @ref jobs_function_setnotifynextcallback + * or @ref jobs_function_setnotifypendingcallback. + * + * This member is ignored by Jobs operation functions. + * + * The number of callbacks of each type that may be registered for each Thing + * is limited by @ref AWS_IOT_JOBS_NOTIFY_CALLBACKS. If @ref AWS_IOT_JOBS_NOTIFY_CALLBACKS + * is `2`, that means that a maximum of `2` NOTIFY PENDING and `2` NOTIFY NEXT callbacks + * (`4` total callbacks) may be set. This member is used to replace an existing callback + * with a new one. + * + * To add a new callback: + * @code{c} + * AwsIotJobsCallbackInfo_t callbackInfo = AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER; + * + * callbackInfo.function = _newCallback; + * callbackInfo.oldFunction = NULL; + * @endcode + * + * For example, if the function `_oldCallback()` is currently registered: + * - To replace `_oldCallback()` with a new callback function `_newCallback()`: + * @code{c} + * AwsIotJobsCallbackInfo_t callbackInfo = AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER; + * + * callbackInfo.function = _newCallback; + * callbackInfo.oldFunction = _oldCallback; + * @endcode + * - To remove `_oldCallback()`: + * @code{c} + * AwsIotJobsCallbackInfo_t callbackInfo = AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER; + * + * callbackInfo.function = NULL; + * callbackInfo.oldFunction = _oldCallback; + * @endcode + */ + void ( * oldFunction )( void *, + AwsIotJobsCallbackParam_t * ); +} AwsIotJobsCallbackInfo_t; + +/** + * @ingroup jobs_datatypes_paramstructs + * @brief Common information provided to Jobs requests. + * + * @paramfor @ref jobs_function_getpendingasync, @ref jobs_function_getpendingsync, + * @ref jobs_function_startnextasync, @ref jobs_function_startnextsync + * @ref jobs_function_describeasync, @ref jobs_function_describesync, + * @ref jobs_function_updateasync, @ref jobs_function_updatesync + * + * @initializer{AwsIotJobsRequestInfo_t,AWS_IOT_JOBS_REQUEST_INFO_INITIALIZER} + */ +typedef struct AwsIotJobsRequestInfo +{ + /** + * @brief The MQTT connection to use for the Jobs request. + */ + IotMqttConnection_t mqttConnection; + + /* These members allow Jobs commands to be retried. Be careful that duplicate + * commands do no cause unexpected application behavior. Use of QoS 0 is recommended. */ + IotMqttQos_t qos; /**< @brief QoS when sending the Jobs command. See #IotMqttPublishInfo_t.qos. */ + uint32_t retryLimit; /**< @brief Maximum number of retries for the Jobs command. See #IotMqttPublishInfo_t.retryLimit. */ + uint32_t retryMs; /**< @brief First retry time for the Jobs command. See IotMqttPublishInfo_t.retryMs. */ + + /** + * @brief Function to allocate memory for an incoming response. + * + * This only needs to be set if #AWS_IOT_JOBS_FLAG_WAITABLE is passed. + */ + void * ( *mallocResponse )( size_t ); + + /** + * @brief The Thing Name associated with the Job. + */ + const char * pThingName; + + /** + * @brief Length of #AwsIotJobsRequestInfo_t.pThingName. + */ + size_t thingNameLength; + + /** + * @brief The Job ID to update. + * + * This may be set to #AWS_IOT_JOBS_NEXT_JOB to update the next pending Job. + * When using #AWS_IOT_JOBS_NEXT_JOB, #AwsIotJobsRequestInfo_t.jobIdLength + * should be set to #AWS_IOT_JOBS_NEXT_JOB_LENGTH. + * + * This parameter is ignored for calls to @ref jobs_function_getpendingasync, + * @ref jobs_function_getpendingsync, @ref jobs_function_startnextasync, + * and @ref jobs_function_startnextsync. + */ + const char * pJobId; + + /** + * @brief Length of #AwsIotJobsRequestInfo_t.pJobId. + * + * This parameter is ignored for calls to @ref jobs_function_getpendingasync, + * @ref jobs_function_getpendingsync, @ref jobs_function_startnextasync, + * and @ref jobs_function_startnextsync. + */ + size_t jobIdLength; + + /** + * @brief An arbitrary string that identifies this Job update to the Jobs + * service. + * + * The recommended value is #AWS_IOT_JOBS_CLIENT_TOKEN_AUTOGENERATE. + */ + const char * pClientToken; + + /** + * @brief Length of #AwsIotJobsRequestInfo_t.pClientToken. + */ + size_t clientTokenLength; +} AwsIotJobsRequestInfo_t; + +/** + * @ingroup jobs_datatypes_paramstructs + * @brief Output parameter of blocking Jobs API functions. + * + * @paramfor @ref jobs_function_getpendingsync, @ref jobs_function_startnextsync, + * @ref jobs_function_describesync, @ref jobs_function_updatesync, + * @ref jobs_function_wait + * + * Provides the response received from the Jobs service. The buffer for the + * response is allocated with #AwsIotJobsRequestInfo_t.mallocResponse. + * + * @initializer{AwsIotJobsResponse_t,AWS_IOT_JOBS_RESPONSE_INITIALIZER} + */ +typedef struct AwsIotJobsResponse +{ + const char * pJobsResponse; /**< @brief JSON response received from the Jobs service. */ + size_t jobsResponseLength; /**< @brief Length of #AwsIotJobsResponse_t.pJobsResponse. */ +} AwsIotJobsResponse_t; + +/** + * @ingroup jobs_datatypes_paramstructs + * @brief Information on a Job update for @ref jobs_function_startnextasync and + * @ref jobs_function_updateasync. These functions modify a Job's state. + * + * @paramfor @ref jobs_function_startnextasync, @ref jobs_function_startnextsync, + * @ref jobs_function_updateasync, and @ref jobs_function_updatesync. + * + * @initializer{AwsIotJobsUpdateInfo_t,AWS_IOT_JOBS_UPDATE_INFO_INITIALIZER} + */ +typedef struct AwsIotJobsUpdateInfo +{ + /** + * @brief The new status to report as a Job execution update. + * + * Valid values are: + * - #AWS_IOT_JOB_STATE_IN_PROGRESS + * - #AWS_IOT_JOB_STATE_FAILED + * - #AWS_IOT_JOB_STATE_SUCCEEDED + * - #AWS_IOT_JOB_STATE_REJECTED + * + * This parameter is ignored for calls to @ref jobs_function_startnextasync and + * @ref jobs_function_startnextsync. These functions always set the state + * to #AWS_IOT_JOB_STATE_IN_PROGRESS. + */ + AwsIotJobState_t newStatus; + + /** + * @brief The expected current version of job execution. + * + * Each time a Job update is sent (for the same `JobId`), the version stored + * on the AWS IoT Jobs service is updated. If this value does not match the + * value stored by the Jobs service, the Job update is rejected with the code + * #AWS_IOT_JOBS_VERSION_MISMATCH. + * + * This value is useful for ensuring the order of Job updates, i.e. that the + * Jobs service does not overwrite a later update with a previous one. If not + * needed, it can be set to #AWS_IOT_JOBS_NO_VERSION. + * + * This parameter is ignored for calls to @ref jobs_function_startnextasync and + * @ref jobs_function_startnextsync. + */ + uint32_t expectedVersion; + + /** + * @brief An application-defined value that identifies a Job execution on a + * specific device. + * + * The Jobs service provides commands for tracking the status of Job execution + * on a specific target. Therefore, this value is used to provide a unique + * identifier of a specific Job execution on a specific target. + * + * This value is optional. It may be set to #AWS_IOT_JOBS_NO_EXECUTION_NUMBER + * if not needed. + * + * This parameter is ignored for calls to @ref jobs_function_startnextasync and + * @ref jobs_function_startnextsync. + */ + int32_t executionNumber; + + /** + * @brief The amount of time (in minutes) before a new Job update must be reported. + * + * If this timeout expires without a new Job update being reported (for the same + * `jobId`), the Job's status is set to #AWS_IOT_JOB_STATE_TIMED_OUT. Sending a + * new Job update will reset this step timeout; a value of #AWS_IOT_JOBS_NO_TIMEOUT + * will clear any previous step timeout. + * + * Valid values are between 1 and 10,080 (7 days). This value is optional. It may + * be set to #AWS_IOT_JOBS_NO_TIMEOUT if not needed. + */ + int32_t stepTimeoutInMinutes; + + /** + * @brief Whether the Job response document should contain the `JobExecutionState`. + * + * The default value is `false`. + * + * This parameter is ignored for calls to @ref jobs_function_startnextasync and + * @ref jobs_function_startnextsync. + */ + bool includeJobExecutionState; + + /** + * @brief Whether the Job response document should contain the `JobDocument`. + * + * The default value is `false`. + * + * This parameter is ignored for calls to @ref jobs_function_startnextasync and + * @ref jobs_function_startnextsync. + */ + bool includeJobDocument; + + /** + * @brief An application-defined set of JSON name-value pairs that describe + * the status of Job execution. + * + * This value is optional. It may be set to #AWS_IOT_JOBS_NO_STATUS_DETAILS + * if not needed. + */ + const char * pStatusDetails; + + /** + * @brief Length of #AwsIotJobsUpdateInfo_t.pStatusDetails. + */ + size_t statusDetailsLength; +} AwsIotJobsUpdateInfo_t; + +/*------------------------- Jobs defined constants --------------------------*/ + +/** + * @brief Set #AwsIotJobsRequestInfo_t.pJobId to this value to use the next pending + * Job as the Job ID. + * + * @note The value of this constant may change at any time in future versions, but + * its name will remain the same. + */ +#define AWS_IOT_JOBS_NEXT_JOB ( "$next" ) + +/** + * @brief Length of #AWS_IOT_JOBS_NEXT_JOB. + * + * Set #AwsIotJobsRequestInfo_t.jobIdLength to this value when using + * #AWS_IOT_JOBS_NEXT_JOB. + * + * @note The value of this constant may change at any time in future versions, but + * its name will remain the same. + */ +#define AWS_IOT_JOBS_NEXT_JOB_LENGTH ( sizeof( AWS_IOT_JOBS_NEXT_JOB ) - 1 ) + +/** + * @brief Set #AwsIotJobsRequestInfo_t.pClientToken to this value to automatically + * generate a client token for the Jobs request. + * + * @note The value of this constant may change at any time in future versions, but + * its name will remain the same. + */ +#define AWS_IOT_JOBS_CLIENT_TOKEN_AUTOGENERATE ( NULL ) + +/** + * @brief Set #AwsIotJobsUpdateInfo_t.expectedVersion to this value to omit the + * version in the Jobs request. + * + * @note The value of this constant may change at any time in future versions, but + * its name will remain the same. + */ +#define AWS_IOT_JOBS_NO_VERSION ( 0 ) + +/** + * @brief Set #AwsIotJobsUpdateInfo_t.executionNumber to this value or pass it to + * @ref jobs_function_describeasync to omit the execution number in the Jobs request. + * + * @note The value of this constant may change at any time in future versions, but + * its name will remain the same. + */ +#define AWS_IOT_JOBS_NO_EXECUTION_NUMBER ( -1 ) + +/** + * @brief Set #AwsIotJobsUpdateInfo_t.stepTimeoutInMinutes to this value to omit the + * step timeout in the Jobs request. + * + * @note The value of this constant may change at any time in future versions, but + * its name will remain the same. + */ +#define AWS_IOT_JOBS_NO_TIMEOUT ( 0 ) + +/** + * @brief Set #AwsIotJobsUpdateInfo_t.stepTimeoutInMinutes to this value to cancel + * any previously set step timeout. + * + * The Jobs service will return an (InvalidRequest)[@ref AWS_IOT_JOBS_INVALID_REQUEST] + * error if this value is used without an existing step timeout. + * + * @note The value of this constant may change at any time in future versions, but + * its name will remain the same. + */ +#define AWS_IOT_JOBS_CANCEL_TIMEOUT ( -1 ) + +/** + * @brief Set #AwsIotJobsUpdateInfo_t.pStatusDetails to this value to omit the + * status details in the Jobs request. + * + * @note The value of this constant may change at any time in future versions, but + * its name will remain the same. + */ +#define AWS_IOT_JOBS_NO_STATUS_DETAILS ( NULL ) + +/** + * @constantspage{jobs,Jobs library} + * + * @section jobs_constants_initializers Jobs Initializers + * @brief Provides default values for the data types of the Jobs library. + * + * @snippet this define_jobs_initializers + * + * All user-facing data types of the Jobs library should be initialized + * using one of the following. + * + * @warning Failing to initialize a Jobs data type with the appropriate + * initializer may result in undefined behavior! + * @note The initializers may change at any time in future versions, but their + * names will remain the same. + * + * Example + * @code{c} + * AwsIotJobsCallbackInfo_t callbackInfo = AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER; + * AwsIotJobsRequestInfo_t requestInfo = AWS_IOT_JOBS_REQUEST_INFO_INITIALIZER; + * AwsIotJobsUpdateInfo_t updateInfo = AWS_IOT_JOBS_UPDATE_INFO_INITIALIZER; + * AwsIotJobsOperation_t operation = AWS_IOT_JOBS_OPERATION_INITIALIZER; + * AwsIotJobsResponse_t response = AWS_IOT_JOBS_RESPONSE_INITIALIZER; + * @endcode + * + * @section jobs_constants_flags Jobs Function Flags + * @brief Flags that modify the behavior of Jobs library functions. + * + * Flags should be bitwise-ORed with each other to change the behavior of + * Jobs library functions. + * + * The following flags are valid for the Jobs operation functions: + * @ref jobs_function_getpendingasync, @ref jobs_function_startnextasync, + * @ref jobs_function_describeasync, @ref jobs_function_updateasync, + * and their blocking versions. + * - #AWS_IOT_JOBS_FLAG_WAITABLE
+ * @copybrief AWS_IOT_JOBS_FLAG_WAITABLE + * - #AWS_IOT_JOBS_FLAG_KEEP_SUBSCRIPTIONS
+ * @copybrief AWS_IOT_JOBS_FLAG_KEEP_SUBSCRIPTIONS + * + * The following flags are valid for @ref jobs_function_removepersistentsubscriptions. + * These flags are not valid for the Jobs operation functions. + * - #AWS_IOT_JOBS_FLAG_REMOVE_GET_PENDING_SUBSCRIPTIONS
+ * @copybrief AWS_IOT_JOBS_FLAG_REMOVE_GET_PENDING_SUBSCRIPTIONS + * - #AWS_IOT_JOBS_FLAG_REMOVE_START_NEXT_SUBSCRIPTIONS
+ * @copybrief AWS_IOT_JOBS_FLAG_REMOVE_START_NEXT_SUBSCRIPTIONS + * - #AWS_IOT_JOBS_FLAG_REMOVE_DESCRIBE_SUBSCRIPTIONS
+ * @copybrief AWS_IOT_JOBS_FLAG_REMOVE_DESCRIBE_SUBSCRIPTIONS + * - #AWS_IOT_JOBS_FLAG_REMOVE_UPDATE_SUBSCRIPTIONS
+ * @copybrief AWS_IOT_JOBS_FLAG_REMOVE_UPDATE_SUBSCRIPTIONS + * + * @note The values of the flags may change at any time in future versions, but + * their names will remain the same. Additionally, flags which may be used at + * the same time will be bitwise-exclusive of each other. + */ + +/* @[define_jobs_initializers] */ +#define AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER { 0 } /**< @brief Initializer for #AwsIotJobsCallbackInfo_t. */ +/** @brief Initializer for #AwsIotJobsRequestInfo_t. */ +#define AWS_IOT_JOBS_REQUEST_INFO_INITIALIZER \ + { .pClientToken = AWS_IOT_JOBS_CLIENT_TOKEN_AUTOGENERATE } +/** @brief Initializer for #AwsIotJobsUpdateInfo_t. */ +#define AWS_IOT_JOBS_UPDATE_INFO_INITIALIZER \ + { .newStatus = AWS_IOT_JOB_STATE_IN_PROGRESS, \ + .expectedVersion = AWS_IOT_JOBS_NO_VERSION, \ + .executionNumber = AWS_IOT_JOBS_NO_EXECUTION_NUMBER, \ + .stepTimeoutInMinutes = AWS_IOT_JOBS_NO_TIMEOUT, \ + .includeJobExecutionState = false, \ + .includeJobDocument = false, \ + .pStatusDetails = AWS_IOT_JOBS_NO_STATUS_DETAILS } +#define AWS_IOT_JOBS_OPERATION_INITIALIZER NULL /**< @brief Initializer for #AwsIotJobsOperation_t. */ +#define AWS_IOT_JOBS_RESPONSE_INITIALIZER { 0 } /**< @brief Initializer for #AwsIotJobsResponse_t. */ +/* @[define_jobs_initializers] */ + +/** + * @brief Allows the use of @ref jobs_function_wait for blocking until completion. + * + * This flag is only valid if passed to the functions @ref jobs_function_getpendingasync, + * @ref jobs_function_startnextasync, @ref jobs_function_describeasync, or @ref jobs_function_updateasync. + * + * An #AwsIotJobsOperation_t MUST be provided if this flag is set. + * Additionally, an #AwsIotJobsCallbackInfo_t MUST NOT be provided. + * + * When this flag is set, #AwsIotJobsRequestInfo_t.mallocResponse must be set + * to a function that can be used to allocate memory to hold an incoming response. + * + * @note If this flag is set, @ref jobs_function_wait MUST be called to + * clean up resources. + */ +#define AWS_IOT_JOBS_FLAG_WAITABLE ( 0x00000001 ) + +/** + * @brief Maintain the subscriptions for the Jobs operation topics, even after + * this function returns. + * + * This flag is only valid if passed to the functions @ref jobs_function_getpendingasync, + * @ref jobs_function_startnextasync, @ref jobs_function_describeasync, or @ref jobs_function_updateasync, + * and their blocking versions. + * + * The Jobs service reports results of Jobs operations by publishing + * messages to MQTT topics. By default, the Job operation functions subscribe to the + * necessary topics, wait for the Jobs service to publish the result of the + * Jobs operation, then unsubscribe from those topics. This workflow is suitable + * for infrequent Jobs operations, but is inefficient for frequent, periodic + * Jobs operations (where subscriptions for the Jobs operation topics would be + * constantly added and removed). + * + * This flag causes the Jobs operation functions to maintain Jobs operation + * topic subscriptions, even after the function returns. These subscriptions + * may then be used by a future call to the same function. + * + * This flags only needs to be set once, after which subscriptions are maintained + * and reused for a specific Thing Name and Jobs function. The function @ref + * jobs_function_removepersistentsubscriptions may be used to remove + * subscriptions maintained by this flag. + */ +#define AWS_IOT_JOBS_FLAG_KEEP_SUBSCRIPTIONS ( 0x00000002 ) + +/** + * @brief Remove the persistent subscriptions from a Jobs get pending operation. + * + * This flag is only valid if passed to the function @ref + * jobs_function_removepersistentsubscriptions. + * + * This flag may be passed to @ref jobs_function_removepersistentsubscriptions + * to remove any subscriptions for a specific Thing Name maintained by a previous + * call to @ref jobs_function_getpendingasync or @ref jobs_function_getpendingsync. + * + * @warning Do not call @ref jobs_function_removepersistentsubscriptions with + * this flag for Thing Names with any in-progress Jobs get pending operations. + */ +#define AWS_IOT_JOBS_FLAG_REMOVE_GET_PENDING_SUBSCRIPTIONS ( 0x00000001 ) + +/** + * @brief Remove the persistent subscriptions from a Jobs start next operation. + * + * This flag is only valid if passed to the function @ref + * jobs_function_removepersistentsubscriptions. + * + * This flag may be passed to @ref jobs_function_removepersistentsubscriptions + * to remove any subscriptions for a specific Thing Name maintained by a previous + * call to @ref jobs_function_startnextasync or @ref jobs_function_startnextsync. + * + * @warning Do not call @ref jobs_function_removepersistentsubscriptions with + * this flag for Thing Names with any in-progress Jobs start next operations. + */ +#define AWS_IOT_JOBS_FLAG_REMOVE_START_NEXT_SUBSCRIPTIONS ( 0x00000002 ) + +/** + * @brief Remove the persistent subscriptions from a Jobs describe operation. + * + * This flag is only valid if passed to the function @ref + * jobs_function_removepersistentsubscriptions. + * + * This flag may be passed to @ref jobs_function_removepersistentsubscriptions + * to remove any subscriptions for a specific Thing Name maintained by a previous + * call to @ref jobs_function_describeasync or @ref jobs_function_describesync. + * + * @warning Do not call @ref jobs_function_removepersistentsubscriptions with + * this flag for Thing Names with any in-progress Jobs describe operations. + */ +#define AWS_IOT_JOBS_FLAG_REMOVE_DESCRIBE_SUBSCRIPTIONS ( 0x00000004 ) + +/** + * @brief Remove the persistent subscriptions from a Jobs update operation. + * + * This flag is only valid if passed to the function @ref + * jobs_function_removepersistentsubscriptions. + * + * This flag may be passed to @ref jobs_function_removepersistentsubscriptions + * to remove any subscriptions for a specific Thing Name maintained by a previous + * call to @ref jobs_function_updateasync or @ref jobs_function_updatesync. + * + * @warning Do not call @ref jobs_function_removepersistentsubscriptions with + * this flag for Thing Names with any in-progress Jobs update operations. + */ +#define AWS_IOT_JOBS_FLAG_REMOVE_UPDATE_SUBSCRIPTIONS ( 0x00000008 ) + +#endif /* ifndef AWS_IOT_JOBS_TYPES_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_api.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_api.c new file mode 100644 index 000000000..49fb09f39 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_api.c @@ -0,0 +1,1624 @@ +/* + * AWS IoT Jobs V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_jobs_api.c + * @brief Implements the user-facing functions of the Jobs library. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* Platform threads include. */ +#include "platform/iot_threads.h" + +/* Jobs internal include. */ +#include "private/aws_iot_jobs_internal.h" + +/* Error handling include. */ +#include "iot_error.h" + +/* MQTT include. */ +#include "iot_mqtt.h" + +/* Validate Jobs configuration settings. */ +#if AWS_IOT_JOBS_ENABLE_ASSERTS != 0 && AWS_IOT_JOBS_ENABLE_ASSERTS != 1 + #error "AWS_IOT_JOBS_ENABLE_ASSERTS must be 0 or 1." +#endif +#if AWS_IOT_JOBS_DEFAULT_MQTT_TIMEOUT_MS <= 0 + #error "AWS_IOT_JOBS_DEFAULT_MQTT_TIMEOUT_MS cannot be 0 or negative." +#endif +#if AWS_IOT_JOBS_NOTIFY_CALLBACKS <= 0 + #error "AWS_IOT_JOBS_NOTIFY_CALLBACKS cannot be 0 or negative." +#endif + +/** + * @brief Returned by @ref _getCallbackIndex when there's no space in the callback array. + */ +#define NO_SPACE_FOR_CALLBACK ( -1 ) + +/** + * @brief Returned by @ref _getCallbackIndex when a searching for an oldCallback that + * does not exist. + */ +#define OLD_CALLBACK_NOT_FOUND ( -2 ) + +/*-----------------------------------------------------------*/ + +/** + * @brief Check if the library is initialized. + * + * @return `true` if AwsIotJobs_Init was called; `false` otherwise. + */ +static bool _checkInit( void ); + +/** + * @brief Validate the #AwsIotJobsRequestInfo_t passed to a Jobs API function. + * + * @param[in] type The Jobs API function type. + * @param[in] pRequestInfo The request info passed to a Jobs API function. + * @param[in] flags Flags used by the Jobs API function. + * @param[in] pCallbackInfo The callback info passed with the request info. + * @param[in] pOperation Operation reference pointer passed to a Jobs API function. + * + * @return #AWS_IOT_JOBS_SUCCESS or #AWS_IOT_JOBS_BAD_PARAMETER. + */ +static AwsIotJobsError_t _validateRequestInfo( _jobsOperationType_t type, + const AwsIotJobsRequestInfo_t * pRequestInfo, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pCallbackInfo, + const AwsIotJobsOperation_t * pOperation ); + +/** + * @brief Validate the #AwsIotJobsUpdateInfo_t passed to a Jobs API function. + * + * @param[in] type The Jobs API function type. + * @param[in] pUpdateInfo The update info passed to a Jobs API function. + * + * @return #AWS_IOT_JOBS_SUCCESS or #AWS_IOT_JOBS_BAD_PARAMETER. + */ +static AwsIotJobsError_t _validateUpdateInfo( _jobsOperationType_t type, + const AwsIotJobsUpdateInfo_t * pUpdateInfo ); + +/** + * @brief Gets an element of the callback array to modify. + * + * @param[in] type The type of callback to modify. + * @param[in] pSubscription Subscription object that holds the callback array. + * @param[in] pCallbackInfo User provided callback info. + * + * @return The index of the callback array to modify; on error: + * - #NO_SPACE_FOR_CALLBACK if no free spaces are available + * - #OLD_CALLBACK_NOT_FOUND if an old callback to remove was specified, but that function does not exist. + * + * @note This function should be called with the subscription list mutex locked. + */ +static int32_t _getCallbackIndex( _jobsCallbackType_t type, + _jobsSubscription_t * pSubscription, + const AwsIotJobsCallbackInfo_t * pCallbackInfo ); + +/** + * @brief Common function for setting Jobs callbacks. + * + * @param[in] mqttConnection The MQTT connection to use. + * @param[in] type Type of Jobs callback. + * @param[in] pThingName Thing Name for Jobs callback. + * @param[in] thingNameLength Length of `pThingName`. + * @param[in] pCallbackInfo Callback information to set. + * + * @return #AWS_IOT_JOBS_SUCCESS, #AWS_IOT_JOBS_BAD_PARAMETER, + * #AWS_IOT_JOBS_NO_MEMORY, or #AWS_IOT_JOBS_MQTT_ERROR. + */ +static AwsIotJobsError_t _setCallbackCommon( IotMqttConnection_t mqttConnection, + _jobsCallbackType_t type, + const char * pThingName, + size_t thingNameLength, + const AwsIotJobsCallbackInfo_t * pCallbackInfo ); + +/** + * @brief Change the subscriptions for Jobs callbacks, either by subscribing + * or unsubscribing. + * + * @param[in] mqttConnection The MQTT connection to use. + * @param[in] type Type of Jobs callback. + * @param[in] pSubscription Jobs subscriptions object for callback. + * @param[in] mqttOperation Either @ref mqtt_function_subscribesync or + * @ref mqtt_function_unsubscribesync. + * + * @return #AWS_IOT_JOBS_SUCCESS, #AWS_IOT_JOBS_NO_MEMORY, or + * #AWS_IOT_JOBS_MQTT_ERROR. + */ +static AwsIotJobsError_t _modifyCallbackSubscriptions( IotMqttConnection_t mqttConnection, + _jobsCallbackType_t type, + _jobsSubscription_t * pSubscription, + AwsIotMqttFunction_t mqttOperation ); + +/** + * @brief Invoked when a document is received on the Jobs NOTIFY PENDING callback. + * + * @param[in] pArgument Ignored. + * @param[in] pMessage The received Jobs document (as an MQTT PUBLISH message). + */ +static void _notifyPendingCallbackWrapper( void * pArgument, + IotMqttCallbackParam_t * pMessage ); + +/** + * @brief Invoked when a document is received on the Jobs NOTIFY NEXT callback. + * + * @param[in] pArgument Ignored. + * @param[in] pMessage The received Jobs document (as an MQTT PUBLISH message). + */ +static void _notifyNextCallbackWrapper( void * pArgument, + IotMqttCallbackParam_t * pMessage ); + +/** + * @brief Common function for incoming Jobs callbacks. + * + * @param[in] type Jobs callback type. + * @param[in] pMessage The received Jobs callback document (as an MQTT PUBLISH + * message). + */ +static void _callbackWrapperCommon( _jobsCallbackType_t type, + IotMqttCallbackParam_t * pMessage ); + +/*-----------------------------------------------------------*/ + +/** + * @brief Tracks whether @ref jobs_function_init has been called. + * + * API functions will fail if @ref jobs_function_init was not called. + */ +static uint32_t _initCalled = 0; + +/** + * @brief Timeout used for MQTT operations. + */ +uint32_t _AwsIotJobsMqttTimeoutMs = AWS_IOT_JOBS_DEFAULT_MQTT_TIMEOUT_MS; + +#if LIBRARY_LOG_LEVEL > IOT_LOG_NONE + +/** + * @brief Printable names for the Jobs callbacks. + */ + const char * const _pAwsIotJobsCallbackNames[] = + { + "NOTIFY PENDING", + "NOTIFY NEXT" + }; +#endif + +/*-----------------------------------------------------------*/ + +static bool _checkInit( void ) +{ + bool status = true; + + if( _initCalled == 0 ) + { + IotLogError( "AwsIotJobs_Init was not called." ); + + status = false; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +static AwsIotJobsError_t _validateRequestInfo( _jobsOperationType_t type, + const AwsIotJobsRequestInfo_t * pRequestInfo, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pCallbackInfo, + const AwsIotJobsOperation_t * pOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_SUCCESS ); + + /* Check that the given MQTT connection is valid. */ + if( pRequestInfo->mqttConnection == IOT_MQTT_CONNECTION_INITIALIZER ) + { + IotLogError( "MQTT connection is not initialized for Jobs %s.", + _pAwsIotJobsOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + /* Check Thing Name. */ + if( AwsIot_ValidateThingName( pRequestInfo->pThingName, + pRequestInfo->thingNameLength ) == false ) + { + IotLogError( "Thing Name is not valid for Jobs %s.", + _pAwsIotJobsOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + /* Checks for waitable operations. */ + if( ( flags & AWS_IOT_JOBS_FLAG_WAITABLE ) == AWS_IOT_JOBS_FLAG_WAITABLE ) + { + if( pOperation == NULL ) + { + IotLogError( "Reference must be provided for a waitable Jobs %s.", + _pAwsIotJobsOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + if( pRequestInfo->mallocResponse == NULL ) + { + IotLogError( "Memory allocation function must be set for waitable Jobs %s.", + _pAwsIotJobsOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + if( pCallbackInfo != NULL ) + { + IotLogError( "Callback should not be set for a waitable Jobs %s.", + _pAwsIotJobsOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + } + + /* Check that a callback function is set. */ + if( pCallbackInfo != NULL ) + { + if( pCallbackInfo->function == NULL ) + { + IotLogError( "Callback function must be set for Jobs %s callback.", + _pAwsIotJobsOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + } + + /* Check client token length. */ + if( pRequestInfo->pClientToken != AWS_IOT_JOBS_CLIENT_TOKEN_AUTOGENERATE ) + { + if( pRequestInfo->clientTokenLength == 0 ) + { + IotLogError( "Client token length must be set for Jobs %s.", + _pAwsIotJobsOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + if( pRequestInfo->clientTokenLength > AWS_IOT_CLIENT_TOKEN_MAX_LENGTH ) + { + IotLogError( "Client token for Jobs %s cannot be longer than %d.", + _pAwsIotJobsOperationNames[ type ], + AWS_IOT_CLIENT_TOKEN_MAX_LENGTH ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + } + + /* Check Job ID for DESCRIBE and UPDATE. */ + if( ( type == JOBS_DESCRIBE ) || ( type == JOBS_UPDATE ) ) + { + if( ( pRequestInfo->pJobId == NULL ) || ( pRequestInfo->jobIdLength == 0 ) ) + { + IotLogError( "Job ID must be set for Jobs %s.", + _pAwsIotJobsOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + if( pRequestInfo->jobIdLength > JOBS_MAX_ID_LENGTH ) + { + IotLogError( "Job ID for Jobs %s cannot be longer than %d.", + _pAwsIotJobsOperationNames[ type ], + JOBS_MAX_ID_LENGTH ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + } + + /* A Job ID (not $next job) must be specified for UPDATE. */ + if( type == JOBS_UPDATE ) + { + if( ( pRequestInfo->jobIdLength == AWS_IOT_JOBS_NEXT_JOB_LENGTH ) && + ( strncmp( AWS_IOT_JOBS_NEXT_JOB, + pRequestInfo->pJobId, + AWS_IOT_JOBS_NEXT_JOB_LENGTH ) == 0 ) ) + { + IotLogError( "Job ID $next is not valid for Jobs UPDATE." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static AwsIotJobsError_t _validateUpdateInfo( _jobsOperationType_t type, + const AwsIotJobsUpdateInfo_t * pUpdateInfo ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_SUCCESS ); + + /* Only START NEXT and UPDATE operations need an update info. */ + AwsIotJobs_Assert( ( type == JOBS_START_NEXT ) || ( type == JOBS_UPDATE ) ); + + /* Check that Job status to report is valid for Jobs UPDATE. */ + if( type == JOBS_UPDATE ) + { + switch( pUpdateInfo->newStatus ) + { + case AWS_IOT_JOB_STATE_IN_PROGRESS: + case AWS_IOT_JOB_STATE_FAILED: + case AWS_IOT_JOB_STATE_SUCCEEDED: + case AWS_IOT_JOB_STATE_REJECTED: + break; + + default: + IotLogError( "Job state %s is not valid for Jobs UPDATE.", + AwsIotJobs_StateName( pUpdateInfo->newStatus ) ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + } + + /* Check that step timeout is valid. */ + if( ( pUpdateInfo->stepTimeoutInMinutes != AWS_IOT_JOBS_NO_TIMEOUT ) && + ( pUpdateInfo->stepTimeoutInMinutes != AWS_IOT_JOBS_CANCEL_TIMEOUT ) ) + { + if( pUpdateInfo->stepTimeoutInMinutes < 1 ) + { + IotLogError( "Step timeout for Jobs %s must be at least 1.", + _pAwsIotJobsOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + else if( pUpdateInfo->stepTimeoutInMinutes > JOBS_MAX_TIMEOUT ) + { + IotLogError( "Step timeout for Jobs %s cannot exceed %d.", + _pAwsIotJobsOperationNames[ type ], + JOBS_MAX_TIMEOUT ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + } + + /* Check status details. */ + if( pUpdateInfo->pStatusDetails != AWS_IOT_JOBS_NO_STATUS_DETAILS ) + { + if( pUpdateInfo->statusDetailsLength == 0 ) + { + IotLogError( "Status details length not set for Jobs %s.", + _pAwsIotJobsOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + if( pUpdateInfo->statusDetailsLength > JOBS_MAX_STATUS_DETAILS_LENGTH ) + { + IotLogError( "Status details length for Jobs %s cannot exceed %d.", + _pAwsIotJobsOperationNames[ type ], + JOBS_MAX_STATUS_DETAILS_LENGTH ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static int32_t _getCallbackIndex( _jobsCallbackType_t type, + _jobsSubscription_t * pSubscription, + const AwsIotJobsCallbackInfo_t * pCallbackInfo ) +{ + int32_t callbackIndex = 0; + + /* Find the matching oldFunction. */ + if( pCallbackInfo->oldFunction != NULL ) + { + for( callbackIndex = 0; callbackIndex < AWS_IOT_JOBS_NOTIFY_CALLBACKS; callbackIndex++ ) + { + if( pSubscription->callbacks[ type ][ callbackIndex ].function == pCallbackInfo->oldFunction ) + { + /* oldFunction found. */ + break; + } + } + + if( callbackIndex == AWS_IOT_JOBS_NOTIFY_CALLBACKS ) + { + /* oldFunction not found. */ + callbackIndex = OLD_CALLBACK_NOT_FOUND; + } + } + /* Find space for a new callback. */ + else + { + for( callbackIndex = 0; callbackIndex < AWS_IOT_JOBS_NOTIFY_CALLBACKS; callbackIndex++ ) + { + if( pSubscription->callbacks[ type ][ callbackIndex ].function == NULL ) + { + break; + } + } + + if( callbackIndex == AWS_IOT_JOBS_NOTIFY_CALLBACKS ) + { + /* No memory for new callback. */ + callbackIndex = NO_SPACE_FOR_CALLBACK; + } + } + + return callbackIndex; +} + +/*-----------------------------------------------------------*/ + +static AwsIotJobsError_t _setCallbackCommon( IotMqttConnection_t mqttConnection, + _jobsCallbackType_t type, + const char * pThingName, + size_t thingNameLength, + const AwsIotJobsCallbackInfo_t * pCallbackInfo ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_SUCCESS ); + bool subscriptionMutexLocked = false; + _jobsSubscription_t * pSubscription = NULL; + int32_t callbackIndex = 0; + + /* Check that AwsIotJobs_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NOT_INITIALIZED ); + } + + /* Validate Thing Name. */ + if( AwsIot_ValidateThingName( pThingName, thingNameLength ) == false ) + { + IotLogError( "Thing Name for Jobs %s callback is not valid.", + _pAwsIotJobsCallbackNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + /* Check that a callback parameter is provided. */ + if( pCallbackInfo == NULL ) + { + IotLogError( "Callback parameter must be provided for Jobs %s callback.", + _pAwsIotJobsCallbackNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + /* The oldFunction member must be set when removing or replacing a callback. */ + if( pCallbackInfo->function == NULL ) + { + if( pCallbackInfo->oldFunction == NULL ) + { + IotLogError( "Both oldFunction and function pointers cannot be NULL for Jobs %s callback.", + _pAwsIotJobsCallbackNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + } + + IotLogInfo( "(%.*s) Modifying Jobs %s callback.", + thingNameLength, + pThingName, + _pAwsIotJobsCallbackNames[ type ] ); + + /* Lock the subscription list mutex to check for an existing subscription + * object. */ + IotMutex_Lock( &_AwsIotJobsSubscriptionsMutex ); + subscriptionMutexLocked = true; + + /* Check for an existing subscription. This function will attempt to allocate + * a new subscription if not found. */ + pSubscription = _AwsIotJobs_FindSubscription( pThingName, thingNameLength, true ); + + if( pSubscription == NULL ) + { + /* No existing subscription was found, and no new subscription could be + * allocated. */ + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NO_MEMORY ); + } + + /* Get the index of the callback element to modify. */ + callbackIndex = _getCallbackIndex( type, pSubscription, pCallbackInfo ); + + switch( callbackIndex ) + { + case NO_SPACE_FOR_CALLBACK: + IotLogError( "No memory for a new Jobs %s callback.", + _pAwsIotJobsCallbackNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NO_MEMORY ); + + case OLD_CALLBACK_NOT_FOUND: + IotLogWarn( "Requested replacement function for Jobs %s callback not found.", + _pAwsIotJobsCallbackNames[ type ] ); + + /* A subscription may have been allocated, but the callback operation can't + * proceed. Check if the subscription should be removed. */ + _AwsIotJobs_RemoveSubscription( pSubscription, NULL ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + + default: + break; + } + + /* Check for an existing callback. */ + if( pSubscription->callbacks[ type ][ callbackIndex ].function != NULL ) + { + /* Replace existing callback. */ + if( pCallbackInfo->function != NULL ) + { + IotLogInfo( "(%.*s) Found existing %s callback. Replacing callback.", + thingNameLength, + pThingName, + _pAwsIotJobsCallbackNames[ type ] ); + + pSubscription->callbacks[ type ][ callbackIndex ] = *pCallbackInfo; + } + /* Remove existing callback. */ + else + { + IotLogInfo( "(%.*s) Removing existing %s callback.", + thingNameLength, + pThingName, + _pAwsIotJobsCallbackNames[ type ] ); + + /* Clear the callback information and unsubscribe. */ + ( void ) memset( &( pSubscription->callbacks[ type ][ callbackIndex ] ), + 0x00, + sizeof( AwsIotJobsCallbackInfo_t ) ); + ( void ) _modifyCallbackSubscriptions( mqttConnection, + type, + pSubscription, + IotMqtt_UnsubscribeSync ); + + /* Check if this subscription object can be removed. */ + _AwsIotJobs_RemoveSubscription( pSubscription, NULL ); + } + } + /* No existing callback. */ + else + { + /* Add new callback. */ + IotLogInfo( "(%.*s) Adding new %s callback.", + thingNameLength, + pThingName, + _pAwsIotJobsCallbackNames[ type ] ); + + status = _modifyCallbackSubscriptions( mqttConnection, + type, + pSubscription, + IotMqtt_SubscribeSync ); + + if( status == AWS_IOT_JOBS_SUCCESS ) + { + pSubscription->callbacks[ type ][ callbackIndex ] = *pCallbackInfo; + } + else + { + /* On failure, check if this subscription can be removed. */ + _AwsIotJobs_RemoveSubscription( pSubscription, NULL ); + } + } + + IOT_FUNCTION_CLEANUP_BEGIN(); + + if( subscriptionMutexLocked == true ) + { + IotMutex_Unlock( &_AwsIotJobsSubscriptionsMutex ); + } + + IotLogInfo( "(%.*s) Jobs %s callback operation complete with result %s.", + thingNameLength, + pThingName, + _pAwsIotJobsCallbackNames[ type ], + AwsIotJobs_strerror( status ) ); + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +static AwsIotJobsError_t _modifyCallbackSubscriptions( IotMqttConnection_t mqttConnection, + _jobsCallbackType_t type, + _jobsSubscription_t * pSubscription, + AwsIotMqttFunction_t mqttOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_SUCCESS ); + int32_t i = 0; + IotMqttError_t mqttStatus = IOT_MQTT_STATUS_PENDING; + IotMqttSubscription_t subscription = IOT_MQTT_SUBSCRIPTION_INITIALIZER; + AwsIotTopicInfo_t topicInfo = { 0 }; + char * pTopicFilter = NULL; + uint16_t topicFilterLength = 0; + + /* Lookup table for Jobs callback suffixes. */ + const char * const pCallbackSuffix[ JOBS_CALLBACK_COUNT ] = + { + JOBS_NOTIFY_PENDING_CALLBACK_STRING, /* Notify pending callback. */ + JOBS_NOTIFY_NEXT_CALLBACK_STRING /* Notify next callback. */ + }; + + /* Lookup table for Jobs callback suffix lengths. */ + const uint16_t pCallbackSuffixLength[ JOBS_CALLBACK_COUNT ] = + { + JOBS_NOTIFY_PENDING_CALLBACK_STRING_LENGTH, /* Notify pending callback. */ + JOBS_NOTIFY_NEXT_CALLBACK_STRING_LENGTH /* Notify next callback. */ + }; + + /* Lookup table for Jobs callback function wrappers. */ + const AwsIotMqttCallbackFunction_t pCallbackWrapper[ JOBS_CALLBACK_COUNT ] = + { + _notifyPendingCallbackWrapper, /* Notify pending callback. */ + _notifyNextCallbackWrapper, /* Notify next callback. */ + }; + + /* MQTT operation may only be subscribe or unsubscribe. */ + AwsIotJobs_Assert( ( mqttOperation == IotMqtt_SubscribeSync ) || + ( mqttOperation == IotMqtt_UnsubscribeSync ) ); + + /* Check if any subscriptions are currently registered for this type. */ + for( i = 0; i < AWS_IOT_JOBS_NOTIFY_CALLBACKS; i++ ) + { + if( pSubscription->callbacks[ type ][ i ].function != NULL ) + { + /* No action is needed when another callback exists. */ + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_SUCCESS ); + } + } + + /* Use the subscription's topic buffer if available. */ + if( pSubscription->pTopicBuffer != NULL ) + { + pTopicFilter = pSubscription->pTopicBuffer; + } + + /* Generate the topic for the MQTT subscription. */ + topicInfo.pThingName = pSubscription->pThingName; + topicInfo.thingNameLength = pSubscription->thingNameLength; + topicInfo.longestSuffixLength = JOBS_LONGEST_SUFFIX_LENGTH; + topicInfo.mallocString = AwsIotJobs_MallocString; + topicInfo.pOperationName = pCallbackSuffix[ type ]; + topicInfo.operationNameLength = pCallbackSuffixLength[ type ]; + + if( AwsIot_GenerateOperationTopic( &topicInfo, + &pTopicFilter, + &topicFilterLength ) == false ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NO_MEMORY ); + } + + IotLogDebug( "%s subscription for %.*s", + mqttOperation == IotMqtt_SubscribeSync ? "Adding" : "Removing", + topicFilterLength, + pTopicFilter ); + + /* Set the members of the MQTT subscription. */ + subscription.qos = IOT_MQTT_QOS_1; + subscription.pTopicFilter = pTopicFilter; + subscription.topicFilterLength = topicFilterLength; + subscription.callback.pCallbackContext = NULL; + subscription.callback.function = pCallbackWrapper[ type ]; + + /* Call the MQTT operation function. */ + mqttStatus = mqttOperation( mqttConnection, + &subscription, + 1, + 0, + _AwsIotJobsMqttTimeoutMs ); + + /* Check the result of the MQTT operation. */ + if( mqttStatus != IOT_MQTT_SUCCESS ) + { + IotLogError( "Failed to %s callback for %.*s %s callback, error %s.", + mqttOperation == IotMqtt_SubscribeSync ? "subscribe to" : "unsubscribe from", + pSubscription->thingNameLength, + pSubscription->pThingName, + _pAwsIotJobsCallbackNames[ type ], + IotMqtt_strerror( mqttStatus ) ); + + /* Convert the MQTT "NO MEMORY" error to a Jobs "NO MEMORY" error. */ + if( mqttStatus == IOT_MQTT_NO_MEMORY ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NO_MEMORY ); + } + else + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_MQTT_ERROR ); + } + } + + IotLogDebug( "Successfully %s %.*s Jobs %s callback.", + mqttOperation == IotMqtt_SubscribeSync ? "subscribed to" : "unsubscribed from", + pSubscription->thingNameLength, + pSubscription->pThingName, + _pAwsIotJobsCallbackNames[ type ] ); + + IOT_FUNCTION_CLEANUP_BEGIN(); + + /* MQTT subscribe should check the subscription topic buffer. */ + if( mqttOperation == IotMqtt_SubscribeSync ) + { + /* If the current subscription has no topic buffer, assign it the current + * topic buffer. */ + if( pSubscription->pTopicBuffer == NULL ) + { + pSubscription->pTopicBuffer = pTopicFilter; + } + } + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +static void _notifyPendingCallbackWrapper( void * pArgument, + IotMqttCallbackParam_t * pMessage ) +{ + /* Silence warnings about unused parameters. */ + ( void ) pArgument; + + _callbackWrapperCommon( NOTIFY_PENDING_CALLBACK, + pMessage ); +} + +/*-----------------------------------------------------------*/ + +static void _notifyNextCallbackWrapper( void * pArgument, + IotMqttCallbackParam_t * pMessage ) +{ + /* Silence warnings about unused parameters. */ + ( void ) pArgument; + + _callbackWrapperCommon( NOTIFY_NEXT_CALLBACK, + pMessage ); +} + +/*-----------------------------------------------------------*/ + +static void _callbackWrapperCommon( _jobsCallbackType_t type, + IotMqttCallbackParam_t * pMessage ) +{ + int32_t callbackIndex = 0; + AwsIotJobsCallbackInfo_t callbackInfo = AWS_IOT_JOBS_CALLBACK_INFO_INITIALIZER; + AwsIotJobsCallbackParam_t callbackParam = { .callbackType = ( AwsIotJobsCallbackType_t ) 0 }; + _jobsSubscription_t * pSubscription = NULL; + const char * pThingName = NULL; + size_t thingNameLength = 0; + + /* Parse the Thing Name from the topic. */ + if( AwsIot_ParseThingName( pMessage->u.message.info.pTopicName, + pMessage->u.message.info.topicNameLength, + &pThingName, + &thingNameLength ) == false ) + { + IOT_GOTO_CLEANUP(); + } + + /* Search for a matching subscription. */ + IotMutex_Lock( &_AwsIotJobsSubscriptionsMutex ); + + pSubscription = _AwsIotJobs_FindSubscription( pThingName, + thingNameLength, + false ); + + if( pSubscription != NULL ) + { + /* Increment callback reference count to prevent the subscription object from being + * freed while callbacks are running. */ + pSubscription->callbackReferences++; + } + + IotMutex_Unlock( &_AwsIotJobsSubscriptionsMutex ); + + if( pSubscription != NULL ) + { + /* Invoke all callbacks for this Thing. */ + for( callbackIndex = 0; callbackIndex < AWS_IOT_JOBS_NOTIFY_CALLBACKS; callbackIndex++ ) + { + /* Copy the callback function and parameter, as it may be modified at any time. */ + IotMutex_Lock( &_AwsIotJobsSubscriptionsMutex ); + callbackInfo = pSubscription->callbacks[ type ][ callbackIndex ]; + IotMutex_Unlock( &_AwsIotJobsSubscriptionsMutex ); + + if( callbackInfo.function != NULL ) + { + /* Set the callback type. Jobs callbacks are enumerated after the operations. */ + callbackParam.callbackType = ( AwsIotJobsCallbackType_t ) ( type + JOBS_OPERATION_COUNT ); + + /* Set the remaining members of the callback param. */ + callbackParam.mqttConnection = pMessage->mqttConnection; + callbackParam.pThingName = pThingName; + callbackParam.thingNameLength = thingNameLength; + callbackParam.u.callback.pDocument = pMessage->u.message.info.pPayload; + callbackParam.u.callback.documentLength = pMessage->u.message.info.payloadLength; + + /* Invoke the callback function. */ + callbackInfo.function( callbackInfo.pCallbackContext, + &callbackParam ); + } + } + + /* Callbacks are finished. Decrement reference count and check if subscription + * object should be destroyed. */ + IotMutex_Lock( &_AwsIotJobsSubscriptionsMutex ); + + pSubscription->callbackReferences--; + AwsIotJobs_Assert( pSubscription->callbackReferences >= 0 ); + + _AwsIotJobs_RemoveSubscription( pSubscription, NULL ); + + IotMutex_Unlock( &_AwsIotJobsSubscriptionsMutex ); + } + + /* This function uses cleanup sections to exit on error. */ + IOT_FUNCTION_CLEANUP_BEGIN(); +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t AwsIotJobs_Init( uint32_t mqttTimeoutMs ) +{ + AwsIotJobsError_t status = AWS_IOT_JOBS_SUCCESS; + bool listInitStatus = false; + + if( _initCalled == 0 ) + { + listInitStatus = AwsIot_InitLists( &_AwsIotJobsPendingOperations, + &_AwsIotJobsSubscriptions, + &_AwsIotJobsPendingOperationsMutex, + &_AwsIotJobsSubscriptionsMutex ); + + if( listInitStatus == false ) + { + IotLogInfo( "Failed to create Jobs lists." ); + + status = AWS_IOT_JOBS_INIT_FAILED; + } + else + { + /* Save the MQTT timeout option. */ + if( mqttTimeoutMs != 0 ) + { + _AwsIotJobsMqttTimeoutMs = mqttTimeoutMs; + } + + /* Set the flag that specifies initialization is complete. */ + _initCalled = 1; + + IotLogInfo( "Jobs library successfully initialized." ); + } + } + else + { + IotLogWarn( "AwsIotJobs_Init called with library already initialized." ); + } + + return status; +} + +/*-----------------------------------------------------------*/ + +void AwsIotJobs_Cleanup( void ) +{ + if( _initCalled == 1 ) + { + _initCalled = 0; + + /* Remove and free all items in the Jobs pending operation list. */ + IotMutex_Lock( &_AwsIotJobsPendingOperationsMutex ); + IotListDouble_RemoveAll( &_AwsIotJobsPendingOperations, + _AwsIotJobs_DestroyOperation, + offsetof( _jobsOperation_t, link ) ); + IotMutex_Unlock( &_AwsIotJobsPendingOperationsMutex ); + + /* Remove and free all items in the Jobs subscription list. */ + IotMutex_Lock( &_AwsIotJobsSubscriptionsMutex ); + IotListDouble_RemoveAll( &_AwsIotJobsSubscriptions, + _AwsIotJobs_DestroySubscription, + offsetof( _jobsSubscription_t, link ) ); + IotMutex_Unlock( &_AwsIotJobsSubscriptionsMutex ); + + /* Restore the default MQTT timeout. */ + _AwsIotJobsMqttTimeoutMs = AWS_IOT_JOBS_DEFAULT_MQTT_TIMEOUT_MS; + + /* Destroy Jobs library mutexes. */ + IotMutex_Destroy( &_AwsIotJobsPendingOperationsMutex ); + IotMutex_Destroy( &_AwsIotJobsSubscriptionsMutex ); + + IotLogInfo( "Jobs library cleanup done." ); + } + else + { + IotLogWarn( "AwsIotJobs_Init was not called before AwsIotShadow_Cleanup." ); + } +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t AwsIotJobs_GetPendingAsync( const AwsIotJobsRequestInfo_t * pRequestInfo, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pCallbackInfo, + AwsIotJobsOperation_t * const pGetPendingOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_STATUS_PENDING ); + _jobsOperation_t * pOperation = NULL; + + /* Check that AwsIotJobs_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NOT_INITIALIZED ); + } + + /* Check request info. */ + status = _validateRequestInfo( JOBS_GET_PENDING, + pRequestInfo, + flags, + pCallbackInfo, + pGetPendingOperation ); + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + + /* Allocate a new Jobs operation. */ + status = _AwsIotJobs_CreateOperation( JOBS_GET_PENDING, + pRequestInfo, + NULL, + flags, + pCallbackInfo, + &pOperation ); + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + /* No memory for Jobs operation. */ + IOT_GOTO_CLEANUP(); + } + + /* Set the reference if provided. This must be done before the Jobs operation + * is processed. */ + if( pGetPendingOperation != NULL ) + { + *pGetPendingOperation = pOperation; + } + + /* Process the Jobs operation. This subscribes to any required topics and + * sends the MQTT message for the Jobs operation. */ + status = _AwsIotJobs_ProcessOperation( pRequestInfo, pOperation ); + + /* If the Jobs operation failed, clear the now invalid reference. */ + if( ( status != AWS_IOT_JOBS_STATUS_PENDING ) && ( pGetPendingOperation != NULL ) ) + { + *pGetPendingOperation = AWS_IOT_JOBS_OPERATION_INITIALIZER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t AwsIotJobs_GetPendingSync( const AwsIotJobsRequestInfo_t * pRequestInfo, + uint32_t flags, + uint32_t timeoutMs, + AwsIotJobsResponse_t * const pJobsResponse ) +{ + AwsIotJobsError_t status = AWS_IOT_JOBS_STATUS_PENDING; + AwsIotJobsOperation_t getPendingOperation = AWS_IOT_JOBS_OPERATION_INITIALIZER; + + /* Set the waitable flag. */ + flags |= AWS_IOT_JOBS_FLAG_WAITABLE; + + /* Call the asynchronous Jobs Get Pending function. */ + status = AwsIotJobs_GetPendingAsync( pRequestInfo, + flags, + NULL, + &getPendingOperation ); + + /* Wait for the Jobs Get Pending operation to complete. */ + if( status == AWS_IOT_JOBS_STATUS_PENDING ) + { + status = AwsIotJobs_Wait( getPendingOperation, + timeoutMs, + pJobsResponse ); + } + + return status; +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t AwsIotJobs_StartNextAsync( const AwsIotJobsRequestInfo_t * pRequestInfo, + const AwsIotJobsUpdateInfo_t * pUpdateInfo, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pCallbackInfo, + AwsIotJobsOperation_t * const pStartNextOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_STATUS_PENDING ); + _jobsOperation_t * pOperation = NULL; + _jsonRequestContents_t requestContents = { 0 }; + + /* Check that AwsIotJobs_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NOT_INITIALIZED ); + } + + /* Check request info. */ + status = _validateRequestInfo( JOBS_START_NEXT, + pRequestInfo, + flags, + pCallbackInfo, + pStartNextOperation ); + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + + /* Check update info. */ + status = _validateUpdateInfo( JOBS_START_NEXT, + pUpdateInfo ); + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + + /* Allocate a new Jobs operation. */ + requestContents.pUpdateInfo = pUpdateInfo; + + status = _AwsIotJobs_CreateOperation( JOBS_START_NEXT, + pRequestInfo, + &requestContents, + flags, + pCallbackInfo, + &pOperation ); + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + /* No memory for Jobs operation. */ + IOT_GOTO_CLEANUP(); + } + + /* Set the reference if provided. This must be done before the Jobs operation + * is processed. */ + if( pStartNextOperation != NULL ) + { + *pStartNextOperation = pOperation; + } + + /* Process the Jobs operation. This subscribes to any required topics and + * sends the MQTT message for the Jobs operation. */ + status = _AwsIotJobs_ProcessOperation( pRequestInfo, pOperation ); + + /* If the Jobs operation failed, clear the now invalid reference. */ + if( ( status != AWS_IOT_JOBS_STATUS_PENDING ) && ( pStartNextOperation != NULL ) ) + { + *pStartNextOperation = AWS_IOT_JOBS_OPERATION_INITIALIZER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t AwsIotJobs_StartNextSync( const AwsIotJobsRequestInfo_t * pRequestInfo, + const AwsIotJobsUpdateInfo_t * pUpdateInfo, + uint32_t flags, + uint32_t timeoutMs, + AwsIotJobsResponse_t * const pJobsResponse ) +{ + AwsIotJobsError_t status = AWS_IOT_JOBS_STATUS_PENDING; + AwsIotJobsOperation_t startNextOperation = AWS_IOT_JOBS_OPERATION_INITIALIZER; + + /* Set the waitable flag. */ + flags |= AWS_IOT_JOBS_FLAG_WAITABLE; + + /* Call the asynchronous Jobs Start Next function. */ + status = AwsIotJobs_StartNextAsync( pRequestInfo, + pUpdateInfo, + flags, + NULL, + &startNextOperation ); + + /* Wait for the Jobs Start Next operation to complete. */ + if( status == AWS_IOT_JOBS_STATUS_PENDING ) + { + status = AwsIotJobs_Wait( startNextOperation, + timeoutMs, + pJobsResponse ); + } + + return status; +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t AwsIotJobs_DescribeAsync( const AwsIotJobsRequestInfo_t * pRequestInfo, + int32_t executionNumber, + bool includeJobDocument, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pCallbackInfo, + AwsIotJobsOperation_t * const pDescribeOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_STATUS_PENDING ); + _jobsOperation_t * pOperation = NULL; + _jsonRequestContents_t requestContents = { 0 }; + + /* Check that AwsIotJobs_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NOT_INITIALIZED ); + } + + /* Check request info. */ + status = _validateRequestInfo( JOBS_DESCRIBE, + pRequestInfo, + flags, + pCallbackInfo, + pDescribeOperation ); + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + + /* Allocate a new Jobs operation. */ + requestContents.describe.executionNumber = executionNumber; + requestContents.describe.includeJobDocument = includeJobDocument; + + status = _AwsIotJobs_CreateOperation( JOBS_DESCRIBE, + pRequestInfo, + &requestContents, + flags, + pCallbackInfo, + &pOperation ); + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + /* No memory for Jobs operation. */ + IOT_GOTO_CLEANUP(); + } + + /* Set the reference if provided. This must be done before the Jobs operation + * is processed. */ + if( pDescribeOperation != NULL ) + { + *pDescribeOperation = pOperation; + } + + /* Process the Jobs operation. This subscribes to any required topics and + * sends the MQTT message for the Jobs operation. */ + status = _AwsIotJobs_ProcessOperation( pRequestInfo, pOperation ); + + /* If the Jobs operation failed, clear the now invalid reference. */ + if( ( status != AWS_IOT_JOBS_STATUS_PENDING ) && ( pDescribeOperation != NULL ) ) + { + *pDescribeOperation = AWS_IOT_JOBS_OPERATION_INITIALIZER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t AwsIotJobs_DescribeSync( const AwsIotJobsRequestInfo_t * pRequestInfo, + int32_t executionNumber, + bool includeJobDocument, + uint32_t flags, + uint32_t timeoutMs, + AwsIotJobsResponse_t * const pJobsResponse ) +{ + AwsIotJobsError_t status = AWS_IOT_JOBS_STATUS_PENDING; + AwsIotJobsOperation_t describeOperation = AWS_IOT_JOBS_OPERATION_INITIALIZER; + + /* Set the waitable flag. */ + flags |= AWS_IOT_JOBS_FLAG_WAITABLE; + + /* Call the asynchronous Jobs Describe function. */ + status = AwsIotJobs_DescribeAsync( pRequestInfo, + executionNumber, + includeJobDocument, + flags, + NULL, + &describeOperation ); + + /* Wait for the Jobs Describe operation to complete. */ + if( status == AWS_IOT_JOBS_STATUS_PENDING ) + { + status = AwsIotJobs_Wait( describeOperation, + timeoutMs, + pJobsResponse ); + } + + return status; +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t AwsIotJobs_UpdateAsync( const AwsIotJobsRequestInfo_t * pRequestInfo, + const AwsIotJobsUpdateInfo_t * pUpdateInfo, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pCallbackInfo, + AwsIotJobsOperation_t * const pUpdateOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_STATUS_PENDING ); + _jobsOperation_t * pOperation = NULL; + _jsonRequestContents_t requestContents = { 0 }; + + /* Check that AwsIotJobs_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NOT_INITIALIZED ); + } + + /* Check request info. */ + status = _validateRequestInfo( JOBS_UPDATE, + pRequestInfo, + flags, + pCallbackInfo, + pUpdateOperation ); + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + + /* Check update info. */ + status = _validateUpdateInfo( JOBS_UPDATE, + pUpdateInfo ); + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + + /* Allocate a new Jobs operation. */ + requestContents.pUpdateInfo = pUpdateInfo; + + status = _AwsIotJobs_CreateOperation( JOBS_UPDATE, + pRequestInfo, + &requestContents, + flags, + pCallbackInfo, + &pOperation ); + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + /* No memory for Jobs operation. */ + IOT_GOTO_CLEANUP(); + } + + /* Set the reference if provided. This must be done before the Jobs operation + * is processed. */ + if( pUpdateOperation != NULL ) + { + *pUpdateOperation = pOperation; + } + + /* Process the Jobs operation. This subscribes to any required topics and + * sends the MQTT message for the Jobs operation. */ + status = _AwsIotJobs_ProcessOperation( pRequestInfo, pOperation ); + + /* If the Jobs operation failed, clear the now invalid reference. */ + if( ( status != AWS_IOT_JOBS_STATUS_PENDING ) && ( pUpdateOperation != NULL ) ) + { + *pUpdateOperation = AWS_IOT_JOBS_OPERATION_INITIALIZER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t AwsIotJobs_UpdateSync( const AwsIotJobsRequestInfo_t * pRequestInfo, + const AwsIotJobsUpdateInfo_t * pUpdateInfo, + uint32_t flags, + uint32_t timeoutMs, + AwsIotJobsResponse_t * const pJobsResponse ) +{ + AwsIotJobsError_t status = AWS_IOT_JOBS_STATUS_PENDING; + AwsIotJobsOperation_t updateOperation = AWS_IOT_JOBS_OPERATION_INITIALIZER; + + /* Set the waitable flag. */ + flags |= AWS_IOT_JOBS_FLAG_WAITABLE; + + /* Call the asynchronous Jobs Update function. */ + status = AwsIotJobs_UpdateAsync( pRequestInfo, + pUpdateInfo, + flags, + NULL, + &updateOperation ); + + /* Wait for the Jobs Update operation to complete. */ + if( status == AWS_IOT_JOBS_STATUS_PENDING ) + { + status = AwsIotJobs_Wait( updateOperation, + timeoutMs, + pJobsResponse ); + } + + return status; +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t AwsIotJobs_Wait( AwsIotJobsOperation_t operation, + uint32_t timeoutMs, + AwsIotJobsResponse_t * const pJobsResponse ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_STATUS_PENDING ); + + /* Check that AwsIotJobs_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NOT_INITIALIZED ); + } + + /* Check that reference is set. */ + if( operation == NULL ) + { + IotLogError( "Operation reference cannot be NULL." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + /* Check that reference is waitable. */ + if( ( operation->flags & AWS_IOT_JOBS_FLAG_WAITABLE ) == 0 ) + { + IotLogError( "Operation is not waitable." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + /* Check that output parameter is set. */ + if( pJobsResponse == NULL ) + { + IotLogError( "Output Jobs response parameter must be set for Jobs %s.", + _pAwsIotJobsOperationNames[ operation->type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + /* Wait for a response to the Jobs operation. */ + if( IotSemaphore_TimedWait( &( operation->notify.waitSemaphore ), + timeoutMs ) == true ) + { + status = operation->status; + } + else + { + status = AWS_IOT_JOBS_TIMEOUT; + } + + /* Remove the completed operation from the pending operation list. */ + IotMutex_Lock( &( _AwsIotJobsPendingOperationsMutex ) ); + IotListDouble_Remove( &( operation->link ) ); + IotMutex_Unlock( &( _AwsIotJobsPendingOperationsMutex ) ); + + /* Decrement the reference count. This also removes subscriptions if the + * count reaches 0. */ + IotMutex_Lock( &_AwsIotJobsSubscriptionsMutex ); + _AwsIotJobs_DecrementReferences( operation, + operation->pSubscription->pTopicBuffer, + NULL ); + IotMutex_Unlock( &_AwsIotJobsSubscriptionsMutex ); + + /* Set the output parameters. Jobs responses are available on success or + * when the Jobs service returns an error document. */ + if( ( status == AWS_IOT_JOBS_SUCCESS ) || ( status > AWS_IOT_JOBS_INVALID_TOPIC ) ) + { + AwsIotJobs_Assert( operation->pJobsResponse != NULL ); + AwsIotJobs_Assert( operation->jobsResponseLength > 0 ); + + pJobsResponse->pJobsResponse = operation->pJobsResponse; + pJobsResponse->jobsResponseLength = operation->jobsResponseLength; + } + + /* Destroy the Jobs operation. */ + _AwsIotJobs_DestroyOperation( operation ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t AwsIotJobs_SetNotifyPendingCallback( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pNotifyPendingCallback ) +{ + /* Flags are not currently used by this function. */ + ( void ) flags; + + return _setCallbackCommon( mqttConnection, + NOTIFY_PENDING_CALLBACK, + pThingName, + thingNameLength, + pNotifyPendingCallback ); +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t AwsIotJobs_SetNotifyNextCallback( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pNotifyNextCallback ) +{ + /* Flags are not currently used by this function. */ + ( void ) flags; + + return _setCallbackCommon( mqttConnection, + NOTIFY_NEXT_CALLBACK, + pThingName, + thingNameLength, + pNotifyNextCallback ); +} + +/*-----------------------------------------------------------*/ + +const char * AwsIotJobs_strerror( AwsIotJobsError_t status ) +{ + const char * pMessage = NULL; + + switch( status ) + { + case AWS_IOT_JOBS_SUCCESS: + pMessage = "SUCCESS"; + break; + + case AWS_IOT_JOBS_STATUS_PENDING: + pMessage = "STATUS PENDING"; + break; + + case AWS_IOT_JOBS_INIT_FAILED: + pMessage = "INIT FAILED"; + break; + + case AWS_IOT_JOBS_BAD_PARAMETER: + pMessage = "BAD PARAMETER"; + break; + + case AWS_IOT_JOBS_NO_MEMORY: + pMessage = "NO MEMORY"; + break; + + case AWS_IOT_JOBS_MQTT_ERROR: + pMessage = "MQTT ERROR"; + break; + + case AWS_IOT_JOBS_BAD_RESPONSE: + pMessage = "BAD RESPONSE"; + break; + + case AWS_IOT_JOBS_TIMEOUT: + pMessage = "TIMEOUT"; + break; + + case AWS_IOT_JOBS_NOT_INITIALIZED: + pMessage = "NOT INITIALIZED"; + break; + + case AWS_IOT_JOBS_INVALID_TOPIC: + pMessage = "FAILED: INVALID TOPIC"; + break; + + case AWS_IOT_JOBS_INVALID_JSON: + pMessage = "FAILED: INVALID JSON"; + break; + + case AWS_IOT_JOBS_INVALID_REQUEST: + pMessage = "FAILED: INVALID REQUEST"; + break; + + case AWS_IOT_JOBS_INVALID_STATE: + pMessage = "FAILED: INVALID STATE TRANSITION"; + break; + + case AWS_IOT_JOBS_NOT_FOUND: + pMessage = "FAILED: NOT FOUND"; + break; + + case AWS_IOT_JOBS_VERSION_MISMATCH: + pMessage = "FAILED: VERSION MISMATCH"; + break; + + case AWS_IOT_JOBS_INTERNAL_ERROR: + pMessage = "FAILED: INTERNAL ERROR"; + break; + + case AWS_IOT_JOBS_THROTTLED: + pMessage = "FAILED: THROTTLED"; + break; + + case AWS_IOT_JOBS_TERMINAL_STATE: + pMessage = "FAILED: TERMINAL STATE"; + break; + + default: + pMessage = "INVALID STATUS"; + break; + } + + return pMessage; +} + +/*-----------------------------------------------------------*/ + +const char * AwsIotJobs_StateName( AwsIotJobState_t state ) +{ + const char * pMessage = NULL; + + switch( state ) + { + case AWS_IOT_JOB_STATE_QUEUED: + pMessage = "QUEUED"; + break; + + case AWS_IOT_JOB_STATE_IN_PROGRESS: + pMessage = "IN PROGRESS"; + break; + + case AWS_IOT_JOB_STATE_FAILED: + pMessage = "FAILED"; + break; + + case AWS_IOT_JOB_STATE_SUCCEEDED: + pMessage = "SUCCEEDED"; + break; + + case AWS_IOT_JOB_STATE_CANCELED: + pMessage = "CANCELED"; + break; + + case AWS_IOT_JOB_STATE_TIMED_OUT: + pMessage = "TIMED OUT"; + break; + + case AWS_IOT_JOB_STATE_REJECTED: + pMessage = "REJECTED"; + break; + + case AWS_IOT_JOB_STATE_REMOVED: + pMessage = "REMOVED"; + break; + + default: + pMessage = "INVALID STATE"; + break; + } + + return pMessage; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_operation.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_operation.c new file mode 100644 index 000000000..8180a015b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_operation.c @@ -0,0 +1,885 @@ +/* + * AWS IoT Jobs V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_jobs_operation.c + * @brief Implements functions that process Jobs operations. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* Jobs internal include. */ +#include "private/aws_iot_jobs_internal.h" + +/* Platform threads include. */ +#include "platform/iot_threads.h" + +/* Error handling include. */ +#include "iot_error.h" + +/* MQTT include. */ +#include "iot_mqtt.h" + +/*-----------------------------------------------------------*/ + +#if LIBRARY_LOG_LEVEL > IOT_LOG_NONE + +/** + * @brief Printable names for each of the Jobs operations. + */ + const char * const _pAwsIotJobsOperationNames[] = + { + "GET PENDING", + "START NEXT", + "DESCRIBE", + "UPDATE", + "SET NOTIFY-PENDING", + "SET NOTIFY-NEXT" + }; +#endif /* if LIBRARY_LOG_LEVEL > IOT_LOG_NONE */ + +/*-----------------------------------------------------------*/ + +/** + * @brief First parameter to #_jobsOperation_match. + */ +typedef struct _operationMatchParams +{ + _jobsOperationType_t type; /**< @brief GET PENDING, START NEXT, DESCRIBE, or UPDATE. */ + const char * pThingName; /**< @brief Thing Name of Jobs operation. */ + size_t thingNameLength; /**< @brief Length of #_operationMatchParams_t.pThingName. */ + const char * pResponse; /**< @brief Jobs response document. */ + size_t responseLength; /**< @brief Length of #_operationMatchParams_t.pResponse. */ +} _operationMatchParams_t; + +/*-----------------------------------------------------------*/ + +/** + * @brief Match a received Jobs response with a Jobs operation awaiting a + * response. + * + * @param[in] pOperationLink Pointer to the link member of the #_jobsOperation_t + * to check. + * @param[in] pMatch Pointer to an #_operationMatchParams_t. + * + * @return `true` if `pMatch` matches the received response; `false` otherwise. + */ +static bool _jobsOperation_match( const IotLink_t * pOperationLink, + void * pMatch ); + +/** + * @brief Invoked when a Jobs response is received for Jobs GET PENDING. + * + * @param[in] pArgument Ignored. + * @param[in] pMessage Received Jobs response (as an MQTT PUBLISH message). + */ +static void _getPendingCallback( void * pArgument, + IotMqttCallbackParam_t * pMessage ); + +/** + * @brief Invoked when a Jobs response is received for a Jobs START NEXT. + * + * @param[in] pArgument Ignored. + * @param[in] pMessage Received Jobs response (as an MQTT PUBLISH message). + */ +static void _startNextCallback( void * pArgument, + IotMqttCallbackParam_t * pMessage ); + +/** + * @brief Invoked when a Jobs response is received for Jobs DESCRIBE. + * + * @param[in] pArgument Ignored. + * @param[in] pMessage Received Jobs response (as an MQTT PUBLISH message). + */ +static void _describeCallback( void * pArgument, + IotMqttCallbackParam_t * pMessage ); + +/** + * @brief Invoked when a Jobs response is received for a Jobs UPDATE. + * + * @param[in] pArgument Ignored. + * @param[in] pMessage Received Jobs response (as an MQTT PUBLISH message). + */ +static void _updateCallback( void * pArgument, + IotMqttCallbackParam_t * pMessage ); + +/** + * @brief Common function for processing received Jobs responses. + * + * @param[in] type GET PENDING, START NEXT, DESCRIBE, or UPDATE. + * @param[in] pMessage Received Jobs response (as an MQTT PUBLISH message). + */ +static void _commonOperationCallback( _jobsOperationType_t type, + IotMqttCallbackParam_t * pMessage ); + +/** + * @brief Notify of a completed Jobs operation. + * + * @param[in] pOperation The operation which completed. + * + * Depending on the parameters passed to a user-facing Jobs function, the + * notification will cause @ref jobs_function_wait to return or invoke a + * user-provided callback. + */ +static void _notifyCompletion( _jobsOperation_t * pOperation ); + +/** + * @brief Get a Jobs subscription to use with a Jobs operation. + * + * This function may use an existing Jobs subscription, or it may allocate a + * new one. + * + * @param[in] pRequestInfo Common Jobs request parameters. + * @param[in] pTopicBuffer Contains the topic to use for subscribing. + * @param[in] operationTopicLength The length of the base topic in `pTopicBuffer`. + * @param[in] pOperation Jobs operation that needs a subscription. + * @param[out] pFreeTopicBuffer Whether the caller may free `pTopicBuffer` + * (which may be assigned to a subscription). + * + * @return #AWS_IOT_JOBS_SUCCESS or #AWS_IOT_JOBS_NO_MEMORY + */ +static AwsIotJobsError_t _findSubscription( const AwsIotJobsRequestInfo_t * pRequestInfo, + char * pTopicBuffer, + uint16_t operationTopicLength, + _jobsOperation_t * pOperation, + bool * pFreeTopicBuffer ); + +/*-----------------------------------------------------------*/ + +/** + * @brief List of active Jobs operations awaiting a response from the Jobs + * service. + */ +IotListDouble_t _AwsIotJobsPendingOperations = { 0 }; + +/** + * @brief Protects #_AwsIotJobsPendingOperations from concurrent access. + */ +IotMutex_t _AwsIotJobsPendingOperationsMutex; + +/*-----------------------------------------------------------*/ + +static bool _jobsOperation_match( const IotLink_t * pOperationLink, + void * pMatch ) +{ + /* Because this function is called from a container function, the given link + * must never be NULL. */ + AwsIotJobs_Assert( pOperationLink != NULL ); + + _jobsOperation_t * pOperation = IotLink_Container( _jobsOperation_t, + pOperationLink, + link ); + _operationMatchParams_t * pParam = ( _operationMatchParams_t * ) pMatch; + _jobsSubscription_t * pSubscription = pOperation->pSubscription; + const char * pClientToken = NULL; + size_t clientTokenLength = 0; + + /* Check for matching Thing Name and operation type. */ + bool match = ( pOperation->type == pParam->type ) && + ( pParam->thingNameLength == pSubscription->thingNameLength ) && + ( strncmp( pParam->pThingName, + pSubscription->pThingName, + pParam->thingNameLength ) == 0 ); + + if( match == true ) + { + IotLogDebug( "Verifying client tokens for Jobs %s.", + _pAwsIotJobsOperationNames[ pParam->type ] ); + + /* Check the response for a client token. */ + match = AwsIot_GetClientToken( pParam->pResponse, + pParam->responseLength, + &pClientToken, + &clientTokenLength ); + + /* If the response contains a client token, check for a match. */ + if( match == true ) + { + match = ( pOperation->clientTokenLength == clientTokenLength ) && + ( strncmp( pOperation->pClientToken, pClientToken, clientTokenLength ) == 0 ); + } + else + { + IotLogWarn( "Received a Jobs %s response with no client token. " + "This is possibly a response to a bad JSON document:\r\n%.*s", + _pAwsIotJobsOperationNames[ pParam->type ], + pParam->responseLength, + pParam->pResponse ); + } + } + + return match; +} + +/*-----------------------------------------------------------*/ + +static void _getPendingCallback( void * pArgument, + IotMqttCallbackParam_t * pMessage ) +{ + /* Silence warnings about unused parameter. */ + ( void ) pArgument; + + _commonOperationCallback( JOBS_GET_PENDING, pMessage ); +} + +/*-----------------------------------------------------------*/ + +static void _startNextCallback( void * pArgument, + IotMqttCallbackParam_t * pMessage ) +{ + /* Silence warnings about unused parameter. */ + ( void ) pArgument; + + _commonOperationCallback( JOBS_START_NEXT, pMessage ); +} + +/*-----------------------------------------------------------*/ + +static void _describeCallback( void * pArgument, + IotMqttCallbackParam_t * pMessage ) +{ + /* Silence warnings about unused parameter. */ + ( void ) pArgument; + + _commonOperationCallback( JOBS_DESCRIBE, pMessage ); +} + +/*-----------------------------------------------------------*/ + +static void _updateCallback( void * pArgument, + IotMqttCallbackParam_t * pMessage ) +{ + /* Silence warnings about unused parameter. */ + ( void ) pArgument; + + _commonOperationCallback( JOBS_UPDATE, pMessage ); +} + +/*-----------------------------------------------------------*/ + +static void _commonOperationCallback( _jobsOperationType_t type, + IotMqttCallbackParam_t * pMessage ) +{ + _jobsOperation_t * pOperation = NULL; + IotLink_t * pOperationLink = NULL; + _operationMatchParams_t param = { 0 }; + AwsIotStatus_t status = AWS_IOT_UNKNOWN; + uint32_t flags = 0; + + /* Set operation type and response. */ + param.type = type; + param.pResponse = pMessage->u.message.info.pPayload; + param.responseLength = pMessage->u.message.info.payloadLength; + + /* Parse the Thing Name from the MQTT topic name. */ + if( AwsIot_ParseThingName( pMessage->u.message.info.pTopicName, + pMessage->u.message.info.topicNameLength, + &( param.pThingName ), + &( param.thingNameLength ) ) == false ) + { + IOT_GOTO_CLEANUP(); + } + + /* Lock the pending operations list for exclusive access. */ + IotMutex_Lock( &( _AwsIotJobsPendingOperationsMutex ) ); + + /* Search for a matching pending operation. */ + pOperationLink = IotListDouble_FindFirstMatch( &_AwsIotJobsPendingOperations, + NULL, + _jobsOperation_match, + ¶m ); + + /* Find and remove the first Jobs operation of the given type. */ + if( pOperationLink == NULL ) + { + /* Operation is not pending. It may have already been processed. Return + * without doing anything */ + IotMutex_Unlock( &( _AwsIotJobsPendingOperationsMutex ) ); + + IotLogWarn( "Jobs %s callback received an unknown operation.", + _pAwsIotJobsOperationNames[ type ] ); + + IOT_GOTO_CLEANUP(); + } + else + { + pOperation = IotLink_Container( _jobsOperation_t, pOperationLink, link ); + + /* Copy the flags from the Jobs operation. */ + flags = pOperation->flags; + + /* Remove a non-waitable operation from the pending operation list. + * Waitable operations are removed by the Wait function. */ + if( ( flags & AWS_IOT_JOBS_FLAG_WAITABLE ) == 0 ) + { + IotListDouble_Remove( &( pOperation->link ) ); + IotMutex_Unlock( &( _AwsIotJobsPendingOperationsMutex ) ); + } + } + + /* Parse the status from the topic name. */ + status = AwsIot_ParseStatus( pMessage->u.message.info.pTopicName, + pMessage->u.message.info.topicNameLength ); + + switch( status ) + { + case AWS_IOT_ACCEPTED: + case AWS_IOT_REJECTED: + _AwsIotJobs_ParseResponse( status, + pMessage->u.message.info.pPayload, + pMessage->u.message.info.payloadLength, + pOperation ); + break; + + default: + IotLogWarn( "Unknown status for %s of %.*s Jobs. Ignoring message.", + _pAwsIotJobsOperationNames[ type ], + pOperation->pSubscription->thingNameLength, + pOperation->pSubscription->pThingName ); + + pOperation->status = AWS_IOT_JOBS_BAD_RESPONSE; + + break; + } + + _notifyCompletion( pOperation ); + + /* For waitable operations, unlock the pending operation list mutex to allow + * the Wait function to run. */ + if( ( flags & AWS_IOT_JOBS_FLAG_WAITABLE ) == AWS_IOT_JOBS_FLAG_WAITABLE ) + { + IotMutex_Unlock( &( _AwsIotJobsPendingOperationsMutex ) ); + } + + /* This function has no return value and no cleanup, but uses the cleanup + * label to exit on error. */ + IOT_FUNCTION_CLEANUP_BEGIN(); +} + +/*-----------------------------------------------------------*/ + +static void _notifyCompletion( _jobsOperation_t * pOperation ) +{ + AwsIotJobsCallbackParam_t callbackParam = { .callbackType = ( AwsIotJobsCallbackType_t ) 0 }; + _jobsSubscription_t * pSubscription = pOperation->pSubscription, + * pRemovedSubscription = NULL; + + /* If the operation is waiting, post to its wait semaphore and return. */ + if( ( pOperation->flags & AWS_IOT_JOBS_FLAG_WAITABLE ) == AWS_IOT_JOBS_FLAG_WAITABLE ) + { + IotSemaphore_Post( &( pOperation->notify.waitSemaphore ) ); + } + else + { + /* Decrement the reference count. This also removes subscriptions if the + * count reaches 0. */ + IotMutex_Lock( &_AwsIotJobsSubscriptionsMutex ); + _AwsIotJobs_DecrementReferences( pOperation, + pSubscription->pTopicBuffer, + &pRemovedSubscription ); + IotMutex_Unlock( &_AwsIotJobsSubscriptionsMutex ); + + /* Set the subscription pointer used for the user callback based on whether + * a subscription was removed from the list. */ + if( pRemovedSubscription != NULL ) + { + pSubscription = pRemovedSubscription; + } + + AwsIotJobs_Assert( pSubscription != NULL ); + + /* Invoke the user callback if provided. */ + if( pOperation->notify.callback.function != NULL ) + { + /* Set the common members of the callback parameter. */ + callbackParam.callbackType = ( AwsIotJobsCallbackType_t ) pOperation->type; + callbackParam.mqttConnection = pOperation->mqttConnection; + callbackParam.pThingName = pSubscription->pThingName; + callbackParam.thingNameLength = pSubscription->thingNameLength; + callbackParam.u.operation.result = pOperation->status; + callbackParam.u.operation.reference = pOperation; + callbackParam.u.operation.pResponse = pOperation->pJobsResponse; + callbackParam.u.operation.responseLength = pOperation->jobsResponseLength; + + pOperation->notify.callback.function( pOperation->notify.callback.pCallbackContext, + &callbackParam ); + } + + /* Destroy a removed subscription. */ + if( pRemovedSubscription != NULL ) + { + _AwsIotJobs_DestroySubscription( pRemovedSubscription ); + } + + _AwsIotJobs_DestroyOperation( pOperation ); + } +} + +/*-----------------------------------------------------------*/ + +static AwsIotJobsError_t _findSubscription( const AwsIotJobsRequestInfo_t * pRequestInfo, + char * pTopicBuffer, + uint16_t operationTopicLength, + _jobsOperation_t * pOperation, + bool * pFreeTopicBuffer ) +{ + AwsIotJobsError_t status = AWS_IOT_JOBS_SUCCESS; + _jobsSubscription_t * pSubscription = NULL; + + /* Lookup table for Jobs operation callbacks. */ + const AwsIotMqttCallbackFunction_t jobsCallbacks[ JOBS_OPERATION_COUNT ] = + { + _getPendingCallback, + _startNextCallback, + _describeCallback, + _updateCallback + }; + + /* Lock the subscriptions mutex for exclusive access. */ + IotMutex_Lock( &_AwsIotJobsSubscriptionsMutex ); + + /* Check for an existing subscription. This function will attempt to allocate + * a new subscription if not found. */ + pSubscription = _AwsIotJobs_FindSubscription( pRequestInfo->pThingName, + pRequestInfo->thingNameLength, + true ); + + if( pSubscription == NULL ) + { + status = AWS_IOT_JOBS_NO_MEMORY; + } + else + { + /* Ensure that the subscription Thing Name matches. */ + AwsIotJobs_Assert( pSubscription != NULL ); + AwsIotJobs_Assert( pSubscription->thingNameLength == pRequestInfo->thingNameLength ); + AwsIotJobs_Assert( strncmp( pSubscription->pThingName, + pRequestInfo->pThingName, + pRequestInfo->thingNameLength ) == 0 ); + + /* Set the subscription object for the Jobs operation. */ + pOperation->pSubscription = pSubscription; + + /* Assign the topic buffer to the subscription to use for unsubscribing if + * the subscription has no topic buffer. */ + if( pSubscription->pTopicBuffer == NULL ) + { + pSubscription->pTopicBuffer = pTopicBuffer; + + /* Don't free the topic buffer if it was allocated to the subscription. */ + *pFreeTopicBuffer = false; + } + else + { + *pFreeTopicBuffer = true; + } + + /* Increment the reference count for this Jobs operation's + * subscriptions. */ + status = _AwsIotJobs_IncrementReferences( pOperation, + pTopicBuffer, + operationTopicLength, + jobsCallbacks[ pOperation->type ] ); + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + /* Failed to add subscriptions for a Jobs operation. The reference + * count was not incremented. Check if this subscription should be + * deleted. */ + _AwsIotJobs_RemoveSubscription( pSubscription, NULL ); + } + } + + /* Unlock the Jobs subscription list mutex. */ + IotMutex_Unlock( &_AwsIotJobsSubscriptionsMutex ); + + return status; +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t _AwsIotJobs_CreateOperation( _jobsOperationType_t type, + const AwsIotJobsRequestInfo_t * pRequestInfo, + const _jsonRequestContents_t * pRequestContents, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pCallbackInfo, + _jobsOperation_t ** pNewOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_SUCCESS ); + size_t operationSize = sizeof( _jobsOperation_t ); + _jobsOperation_t * pOperation = NULL; + + IotLogDebug( "Creating operation record for Jobs %s.", + _pAwsIotJobsOperationNames[ type ] ); + + /* The Job ID must be saved for DESCRIBE and UPDATE operations. */ + if( ( type == JOBS_DESCRIBE ) || ( type == JOBS_UPDATE ) ) + { + /* Ensure a valid Job ID is provided. */ + AwsIotJobs_Assert( pRequestInfo->pJobId != NULL ); + AwsIotJobs_Assert( pRequestInfo->jobIdLength > 1 ); + AwsIotJobs_Assert( pRequestInfo->jobIdLength <= JOBS_MAX_ID_LENGTH ); + + operationSize += pRequestInfo->jobIdLength; + } + + /* Allocate memory for a new Jobs operation. */ + pOperation = AwsIotJobs_MallocOperation( operationSize ); + + if( pOperation == NULL ) + { + IotLogError( "Failed to allocate memory for Jobs %s.", + _pAwsIotJobsOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NO_MEMORY ); + } + + /* Clear the operation data. */ + ( void ) memset( pOperation, 0x00, sizeof( _jobsOperation_t ) ); + + /* Set the remaining common members of the Jobs operation. */ + pOperation->type = type; + pOperation->flags = flags; + pOperation->status = AWS_IOT_JOBS_STATUS_PENDING; + pOperation->mallocResponse = pRequestInfo->mallocResponse; + + /* Save the Job ID for DESCRIBE and UPDATE operations. */ + if( ( type == JOBS_DESCRIBE ) || ( type == JOBS_UPDATE ) ) + { + pOperation->jobIdLength = pRequestInfo->jobIdLength; + + ( void ) memcpy( pOperation->pJobId, pRequestInfo->pJobId, pRequestInfo->jobIdLength ); + } + + /* Generate a Jobs request document. */ + status = _AwsIotJobs_GenerateJsonRequest( type, + pRequestInfo, + pRequestContents, + pOperation ); + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + + /* Check if the waitable flag is set. If it is, create a semaphore to + * wait on. */ + if( ( flags & AWS_IOT_JOBS_FLAG_WAITABLE ) == AWS_IOT_JOBS_FLAG_WAITABLE ) + { + if( IotSemaphore_Create( &( pOperation->notify.waitSemaphore ), 0, 1 ) == false ) + { + IotLogError( "Failed to create semaphore for waitable Jobs %s.", + _pAwsIotJobsOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NO_MEMORY ); + } + } + else + { + /* If the waitable flag isn't set but a callback is, copy the callback + * information. */ + if( pCallbackInfo != NULL ) + { + pOperation->notify.callback = *pCallbackInfo; + } + } + + IOT_FUNCTION_CLEANUP_BEGIN(); + + /* Clean up on error. */ + if( status != AWS_IOT_JOBS_SUCCESS ) + { + if( pOperation != NULL ) + { + if( pOperation->pJobsRequest != NULL ) + { + AwsIotJobs_FreeString( ( void * ) ( pOperation->pJobsRequest ) ); + } + + AwsIotJobs_FreeOperation( pOperation ); + } + } + else + { + /* Set the output parameter. */ + *pNewOperation = pOperation; + } + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +void _AwsIotJobs_DestroyOperation( void * pData ) +{ + _jobsOperation_t * pOperation = ( _jobsOperation_t * ) pData; + + AwsIotJobs_Assert( pOperation != NULL ); + + IotLogDebug( "Destroying Jobs operation %s.", + _pAwsIotJobsOperationNames[ pOperation->type ] ); + + /* Check if a wait semaphore was created for this operation. */ + if( ( pOperation->flags & AWS_IOT_JOBS_FLAG_WAITABLE ) == AWS_IOT_JOBS_FLAG_WAITABLE ) + { + /* Destroy the wait semaphore */ + IotSemaphore_Destroy( &( pOperation->notify.waitSemaphore ) ); + } + + /* Free any Jobs request documents. */ + if( pOperation->pJobsRequest != NULL ) + { + AwsIotJobs_Assert( pOperation->jobsRequestLength > 0 ); + + AwsIotJobs_FreeString( ( void * ) ( pOperation->pJobsRequest ) ); + } + + /* Free the memory used to hold operation data. */ + AwsIotJobs_FreeOperation( pOperation ); +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t _AwsIotJobs_GenerateJobsTopic( _jobsOperationType_t type, + const AwsIotJobsRequestInfo_t * pRequestInfo, + char ** pTopicBuffer, + uint16_t * pOperationTopicLength ) +{ + AwsIotJobsError_t status = AWS_IOT_JOBS_SUCCESS; + AwsIotTopicInfo_t topicInfo = { 0 }; + char pJobOperationName[ JOBS_LONGEST_SUFFIX_LENGTH ] = { 0 }; + uint16_t operationNameLength = 0; + + /* Lookup table for Jobs operation strings. */ + const char * const pOperationString[ JOBS_OPERATION_COUNT ] = + { + JOBS_GET_PENDING_OPERATION_STRING, /* Jobs get pending operation. */ + JOBS_START_NEXT_OPERATION_STRING, /* Jobs start next operation. */ + JOBS_DESCRIBE_OPERATION_STRING, /* Jobs describe operation */ + JOBS_UPDATE_OPERATION_STRING /* Jobs update operation. */ + }; + + /* Lookup table for Jobs operation string lengths. */ + const uint16_t pOperationStringLength[ JOBS_OPERATION_COUNT ] = + { + JOBS_GET_PENDING_OPERATION_STRING_LENGTH, /* Jobs get pending operation */ + JOBS_START_NEXT_OPERATION_STRING_LENGTH, /* Jobs start next operation. */ + JOBS_DESCRIBE_OPERATION_STRING_LENGTH, /* Jobs describe operation */ + JOBS_UPDATE_OPERATION_STRING_LENGTH /* Jobs update operation. */ + }; + + /* Ensure type is valid. */ + AwsIotJobs_Assert( ( type == JOBS_GET_PENDING ) || ( type == JOBS_START_NEXT ) || + ( type == JOBS_DESCRIBE ) || ( type == JOBS_UPDATE ) ); + + /* Set the members needed to generate an operation topic. */ + topicInfo.pThingName = pRequestInfo->pThingName; + topicInfo.thingNameLength = pRequestInfo->thingNameLength; + topicInfo.longestSuffixLength = JOBS_LONGEST_SUFFIX_LENGTH; + topicInfo.mallocString = AwsIotJobs_MallocString; + + /* Job operations that require a Job ID require additional processing to + * create an operation name with the Job ID. */ + if( ( type == JOBS_DESCRIBE ) || ( type == JOBS_UPDATE ) ) + { + /* Ensure Job ID length is valid. */ + AwsIotJobs_Assert( pRequestInfo->jobIdLength > 0 ); + AwsIotJobs_Assert( pRequestInfo->jobIdLength <= JOBS_MAX_ID_LENGTH ); + + /* Construct the Jobs operation name with the Job ID. */ + ( void ) memcpy( pJobOperationName, "/jobs/", 6 ); + operationNameLength = 6; + + ( void ) memcpy( pJobOperationName + operationNameLength, + pRequestInfo->pJobId, + pRequestInfo->jobIdLength ); + operationNameLength = ( uint16_t ) ( pRequestInfo->jobIdLength + operationNameLength ); + + ( void ) memcpy( pJobOperationName + operationNameLength, + pOperationString[ type ], + pOperationStringLength[ type ] ); + operationNameLength = ( uint16_t ) ( operationNameLength + pOperationStringLength[ type ] ); + + topicInfo.pOperationName = pJobOperationName; + topicInfo.operationNameLength = operationNameLength; + } + else + { + topicInfo.pOperationName = pOperationString[ type ]; + topicInfo.operationNameLength = pOperationStringLength[ type ]; + } + + if( AwsIot_GenerateOperationTopic( &topicInfo, + pTopicBuffer, + pOperationTopicLength ) == false ) + { + status = AWS_IOT_JOBS_NO_MEMORY; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t _AwsIotJobs_ProcessOperation( const AwsIotJobsRequestInfo_t * pRequestInfo, + _jobsOperation_t * pOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_STATUS_PENDING ); + char * pTopicBuffer = NULL; + uint16_t operationTopicLength = 0; + bool freeTopicBuffer = true; + IotMqttPublishInfo_t publishInfo = IOT_MQTT_PUBLISH_INFO_INITIALIZER; + IotMqttError_t publishStatus = IOT_MQTT_STATUS_PENDING; + + IotLogDebug( "Processing Jobs operation %s for Thing %.*s.", + _pAwsIotJobsOperationNames[ pOperation->type ], + pRequestInfo->thingNameLength, + pRequestInfo->pThingName ); + + /* Set the operation's MQTT connection. */ + pOperation->mqttConnection = pRequestInfo->mqttConnection; + + /* Generate the operation topic buffer. */ + status = _AwsIotJobs_GenerateJobsTopic( pOperation->type, + pRequestInfo, + &pTopicBuffer, + &operationTopicLength ); + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + IotLogError( "No memory for Jobs operation topic buffer." ); + + IOT_GOTO_CLEANUP(); + } + + /* Get a subscription object for this Jobs operation. */ + status = _findSubscription( pRequestInfo, + pTopicBuffer, + operationTopicLength, + pOperation, + &freeTopicBuffer ); + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + /* No subscription was found and no subscription could be allocated. */ + IOT_GOTO_CLEANUP(); + } + + /* Set the members for PUBLISH retry. */ + publishInfo.qos = pRequestInfo->qos; + publishInfo.retryLimit = pRequestInfo->retryLimit; + publishInfo.retryMs = pRequestInfo->retryMs; + + /* Set the payload as the Jobs request. */ + publishInfo.pPayload = pOperation->pJobsRequest; + publishInfo.payloadLength = pOperation->jobsRequestLength; + + /* Set the operation topic name. */ + publishInfo.pTopicName = pTopicBuffer; + publishInfo.topicNameLength = operationTopicLength; + + IotLogDebug( "Jobs %s message will be published to topic %.*s", + _pAwsIotJobsOperationNames[ pOperation->type ], + publishInfo.topicNameLength, + publishInfo.pTopicName ); + + /* Add Jobs operation to the pending operations list. */ + IotMutex_Lock( &( _AwsIotJobsPendingOperationsMutex ) ); + IotListDouble_InsertHead( &( _AwsIotJobsPendingOperations ), + &( pOperation->link ) ); + IotMutex_Unlock( &( _AwsIotJobsPendingOperationsMutex ) ); + + /* Publish to the Jobs topic name. */ + publishStatus = IotMqtt_PublishSync( pOperation->mqttConnection, + &publishInfo, + 0, + _AwsIotJobsMqttTimeoutMs ); + + if( publishStatus != IOT_MQTT_SUCCESS ) + { + IotLogError( "Failed to publish MQTT message to %s %.*s Jobs, error %s.", + _pAwsIotJobsOperationNames[ pOperation->type ], + pRequestInfo->thingNameLength, + pRequestInfo->pThingName, + IotMqtt_strerror( publishStatus ) ); + + /* Convert the MQTT "NO MEMORY" error to a Jobs "NO MEMORY" error. */ + if( publishStatus == IOT_MQTT_NO_MEMORY ) + { + status = AWS_IOT_JOBS_NO_MEMORY; + } + else + { + status = AWS_IOT_JOBS_MQTT_ERROR; + } + + /* If the "keep subscriptions" flag is not set, decrement the reference + * count. */ + if( ( pOperation->flags & AWS_IOT_JOBS_FLAG_KEEP_SUBSCRIPTIONS ) == 0 ) + { + IotMutex_Lock( &_AwsIotJobsSubscriptionsMutex ); + _AwsIotJobs_DecrementReferences( pOperation, + pTopicBuffer, + NULL ); + IotMutex_Unlock( &_AwsIotJobsSubscriptionsMutex ); + } + + /* Remove Jobs operation from the pending operations list. */ + IotMutex_Lock( &( _AwsIotJobsPendingOperationsMutex ) ); + IotListDouble_Remove( &( pOperation->link ) ); + IotMutex_Unlock( &( _AwsIotJobsPendingOperationsMutex ) ); + } + else + { + IotLogDebug( "Jobs %s PUBLISH message successfully sent.", + _pAwsIotJobsOperationNames[ pOperation->type ] ); + } + + IOT_FUNCTION_CLEANUP_BEGIN(); + + /* Free the topic buffer used by this function if it was not assigned to a + * subscription. */ + if( ( freeTopicBuffer == true ) && ( pTopicBuffer != NULL ) ) + { + AwsIotJobs_FreeString( pTopicBuffer ); + } + + /* Destroy the Jobs operation on failure. */ + if( status != AWS_IOT_JOBS_SUCCESS ) + { + _AwsIotJobs_DestroyOperation( pOperation ); + } + else + { + /* Convert successful return code to "status pending", as the Jobs + * library is now waiting for a response from the service. */ + status = AWS_IOT_JOBS_STATUS_PENDING; + } + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_serialize.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_serialize.c new file mode 100644 index 000000000..c00fc23f1 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_serialize.c @@ -0,0 +1,1214 @@ +/* + * AWS IoT Jobs V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_jobs_serialize.c + * @brief Implements functions that generate and parse Jobs JSON documents. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include + +/* Jobs internal include. */ +#include "private/aws_iot_jobs_internal.h" + +/* Error handling include. */ +#include "iot_error.h" + +/* JSON utilities include. */ +#include "aws_iot_doc_parser.h" + +/** + * @brief Minimum length of a Jobs request. + * + * At the very least, the request will contain: {"clientToken":""} + */ +#define MINIMUM_REQUEST_LENGTH ( AWS_IOT_CLIENT_TOKEN_KEY_LENGTH + 7 ) + +/** + * @brief The length of client tokens generated by this library. + */ +#define CLIENT_TOKEN_AUTOGENERATE_LENGTH ( 8 ) + +/** + * @brief JSON key representing Jobs status. + */ +#define STATUS_KEY "status" + +/** + * @brief Length of #STATUS_KEY. + */ +#define STATUS_KEY_LENGTH ( sizeof( STATUS_KEY ) - 1 ) + +/** + * @brief JSON key representing Jobs status details. + */ +#define STATUS_DETAILS_KEY "statusDetails" + +/** + * @brief Length of #STATUS_DETAILS_KEY. + */ +#define STATUS_DETAILS_KEY_LENGTH ( sizeof( STATUS_DETAILS_KEY ) - 1 ) + +/** + * @brief JSON key representing Jobs expected version. + */ +#define EXPECTED_VERSION_KEY "expectedVersion" + +/** + * @brief Length of #EXPECTED_VERSION_KEY. + */ +#define EXPECTED_VERSION_KEY_LENGTH ( sizeof( EXPECTED_VERSION_KEY ) - 1 ) + +/** + * @brief Maximum length of the expected version when represented as a string. + * + * The expected version is a 32-bit unsigned integer. This can be represented in + * 10 digits plus a NULL-terminator. + */ +#define EXPECTED_VERSION_STRING_LENGTH ( 11 ) + +/** + * @brief JSON key representing Jobs step timeout. + */ +#define STEP_TIMEOUT_KEY "stepTimeoutInMinutes" + +/** + * @brief Length of #STEP_TIMEOUT_KEY. + */ +#define STEP_TIMEOUT_KEY_LENGTH ( sizeof( STEP_TIMEOUT_KEY ) - 1 ) + +/** + * @brief Maximum length of the step timeout when represented as a string. + * + * The step timeout is in the range of [-1,10080]. This can be represented as + * 5 digits plus a NULL-terminator. + */ +#define STEP_TIMEOUT_STRING_LENGTH ( 6 ) + +/** + * @brief JSON key representing the "include Job document" flag. + */ +#define INCLUDE_JOB_DOCUMENT_KEY "includeJobDocument" + +/** + * @brief JSON key representing the "include Job Execution state" flag. + */ +#define INCLUDE_JOB_EXECUTION_STATE_KEY "includeJobExecutionState" + +/** + * @brief Length of #INCLUDE_JOB_EXECUTION_STATE_KEY. + */ +#define INCLUDE_JOB_EXECUTION_STATE_KEY_LENGTH ( sizeof( INCLUDE_JOB_EXECUTION_STATE_KEY ) - 1 ) + +/** + * @brief Length of #INCLUDE_JOB_DOCUMENT_KEY. + */ +#define INCLUDE_JOB_DOCUMENT_KEY_LENGTH ( sizeof( INCLUDE_JOB_DOCUMENT_KEY ) - 1 ) + +/** + * @brief JSON key representing the Jobs execution number. + */ +#define EXECUTION_NUMBER_KEY "executionNumber" + +/** + * @brief Length of #EXECUTION_NUMBER_KEY. + */ +#define EXECUTION_NUMBER_KEY_LENGTH ( sizeof( EXECUTION_NUMBER_KEY ) - 1 ) + +/** + * @brief Maximum length of the execution number when represented as a string. + * + * The execution number is a 32-bit integer. This can be represented in 10 digits, + * plus 1 for a possible negative sign, plus a NULL-terminator. + */ +#define EXECUTION_NUMBER_STRING_LENGTH ( 12 ) + +/** + * @brief JSON key representing Jobs error code in error responses. + */ +#define CODE_KEY "code" + +/** + * @brief Length of #CODE_KEY. + */ +#define CODE_KEY_LENGTH ( sizeof( CODE_KEY ) - 1 ) + +/** + * @brief Append a string to a buffer. + * + * Also updates `copyOffset` with `stringLength`. + * + * @param[in] pBuffer Start of a buffer. + * @param[in] copyOffset Offset in `pBuffer` where `pString` will be placed. + * @param[in] pString The string to append. + * @param[in] stringLength Length of `pString`. + */ +#define APPEND_STRING( pBuffer, copyOffset, pString, stringLength ) \ + ( void ) memcpy( pBuffer + copyOffset, pString, stringLength ); \ + copyOffset += ( size_t ) stringLength; + +/*-----------------------------------------------------------*/ + +/** + * @brief Place a JSON boolean flag in the given buffer. + * + * @param[in] pBuffer The buffer where the flag is placed. + * @param[in] copyOffset Offset in `pBuffer` where the flag is placed. + * @param[in] pFlagName Either #INCLUDE_JOB_DOCUMENT_KEY or #INCLUDE_JOB_EXECUTION_STATE_KEY. + * @param[in] flagNameLength Either #INCLUDE_JOB_EXECUTION_STATE_KEY_LENGTH or + * #INCLUDE_JOB_EXECUTION_STATE_KEY_LENGTH + * @param[in] value Either `true` or `false`. + * + * @warning This function does not check the length of `pBuffer`! Any provided + * buffer must be large enough to accommodate the flag and value. + * + * @return A value of `copyOffset` after the flag. + */ +static size_t _appendFlag( char * pBuffer, + size_t copyOffset, + const char * pFlagName, + size_t flagNameLength, + bool value ); + +/** + * @brief Place Job status details in the given buffer. + * + * @param[in] pBuffer The buffer where the status details are placed. + * @param[in] copyOffset Offset in `pBuffer` where the status details are placed. + * @param[in] pStatusDetails The status details to place in the buffer. + * @param[in] statusDetailsLength Length of `pStatusDetails`. + * + * @warning This function does not check the length of `pBuffer`! Any provided + * buffer must be large enough to accommodate the status details. + * + * @return A value of `copyOffset` after the status details. + */ +static size_t _appendStatusDetails( char * pBuffer, + size_t copyOffset, + const char * pStatusDetails, + size_t statusDetailsLength ); + +/** + * @brief Place Job execution number in the given buffer. + * + * @param[in] pBuffer The buffer where the execution number is placed. + * @param[in] copyOffset Offset in `pBuffer` where the execution number is placed. + * @param[in] pExecutionNumber The execution number to place in the buffer. + * @param[in] executionNumberLength Length of `pExecutionNumber`. + * + * @warning This function does not check the length of `pBuffer`! Any provided + * buffer must be large enough to accommodate the execution number. + * + * @return A value of `copyOffset` after the execution number. + */ +static size_t _appendExecutionNumber( char * pBuffer, + size_t copyOffset, + const char * pExecutionNumber, + size_t executionNumberLength ); + +/** + * @brief Place Job step timeout in the given buffer. + * + * @param[in] pBuffer The buffer where the step timeout is placed. + * @param[in] copyOffset Offset in `pBuffer` where the step timeout is placed. + * @param[in] pStepTimeout The step timeout to place in the buffer. + * @param[in] stepTimeoutLength Length of `pStepTimeout`. + * + * @warning This function does not check the length of `pBuffer`! Any provided + * buffer must be large enough to accommodate the step timeout. + * + * @return A value of `copyOffset` after the step timeout. + */ +static size_t _appendStepTimeout( char * pBuffer, + size_t copyOffset, + const char * pStepTimeout, + size_t stepTimeoutLength ); + +/** + * @brief Place a client token in the given buffer. + * + * @param[in] pBuffer The buffer where the client token is placed. + * @param[in] copyOffset Offset in `pBuffer` where client token is placed. + * @param[in] pRequestInfo Contains information on a client token to place. + * @param[out] pOperation Location and length of client token are written here. + * + * @warning This function does not check the length of `pBuffer`! Any provided + * buffer must be large enough to accommodate #CLIENT_TOKEN_AUTOGENERATE_LENGTH + * characters. + * + * @return A value of `copyOffset` after the client token. + */ +static size_t _appendClientToken( char * pBuffer, + size_t copyOffset, + const AwsIotJobsRequestInfo_t * pRequestInfo, + _jobsOperation_t * pOperation ); + +/** + * @brief Generates a request JSON for a GET PENDING operation. + * + * @param[in] pRequestInfo Common Jobs request parameters. + * @param[in] pOperation Operation associated with the Jobs request. + * + * @return #AWS_IOT_JOBS_SUCCESS or #AWS_IOT_JOBS_NO_MEMORY + */ +static AwsIotJobsError_t _generateGetPendingRequest( const AwsIotJobsRequestInfo_t * pRequestInfo, + _jobsOperation_t * pOperation ); + +/** + * @brief Generates a request JSON for a START NEXT operation. + * + * @param[in] pRequestInfo Common Jobs request parameters. + * @param[in] pUpdateInfo Jobs update parameters. + * @param[in] pOperation Operation associated with the Jobs request. + * + * @return #AWS_IOT_JOBS_SUCCESS or #AWS_IOT_JOBS_NO_MEMORY + */ +static AwsIotJobsError_t _generateStartNextRequest( const AwsIotJobsRequestInfo_t * pRequestInfo, + const AwsIotJobsUpdateInfo_t * pUpdateInfo, + _jobsOperation_t * pOperation ); + +/** + * @brief Generates a request JSON for a DESCRIBE operation. + * + * @param[in] pRequestInfo Common jobs request parameters. + * @param[in] executionNumber Job execution number to include in request. + * @param[in] includeJobDocument Whether the response should include the Job document. + * @param[in] pOperation Operation associated with the Jobs request. + * + * @return #AWS_IOT_JOBS_SUCCESS or #AWS_IOT_JOBS_NO_MEMORY. + */ +static AwsIotJobsError_t _generateDescribeRequest( const AwsIotJobsRequestInfo_t * pRequestInfo, + int32_t executionNumber, + bool includeJobDocument, + _jobsOperation_t * pOperation ); + +/** + * @brief Generates a request JSON for an UPDATE operation. + * + * @param[in] pRequestInfo Common Jobs request parameters. + * @param[in] pUpdateInfo Jobs update parameters. + * @param[in] pOperation Operation associated with the Jobs request. + */ +static AwsIotJobsError_t _generateUpdateRequest( const AwsIotJobsRequestInfo_t * pRequestInfo, + const AwsIotJobsUpdateInfo_t * pUpdateInfo, + _jobsOperation_t * pOperation ); + +/** + * @brief Parse an error from a Jobs error document. + * + * @param[in] pErrorDocument Jobs error document. + * @param[in] errorDocumentLength Length of `pErrorDocument`. + * + * @return A Jobs error code between #AWS_IOT_JOBS_INVALID_TOPIC and + * #AWS_IOT_JOBS_TERMINAL_STATE. + */ +static AwsIotJobsError_t _parseErrorDocument( const char * pErrorDocument, + size_t errorDocumentLength ); + +/*-----------------------------------------------------------*/ + +static size_t _appendFlag( char * pBuffer, + size_t copyOffset, + const char * pFlagName, + size_t flagNameLength, + bool value ) +{ + if( value == true ) + { + APPEND_STRING( pBuffer, + copyOffset, + pFlagName, + flagNameLength ); + APPEND_STRING( pBuffer, copyOffset, "\":true,\"", 8 ); + } + else + { + APPEND_STRING( pBuffer, + copyOffset, + pFlagName, + flagNameLength ); + APPEND_STRING( pBuffer, copyOffset, "\":false,\"", 9 ); + } + + return copyOffset; +} + +/*-----------------------------------------------------------*/ + +static size_t _appendStatusDetails( char * pBuffer, + size_t copyOffset, + const char * pStatusDetails, + size_t statusDetailsLength ) +{ + APPEND_STRING( pBuffer, copyOffset, STATUS_DETAILS_KEY, STATUS_DETAILS_KEY_LENGTH ); + APPEND_STRING( pBuffer, copyOffset, "\":", 2 ); + APPEND_STRING( pBuffer, + copyOffset, + pStatusDetails, + statusDetailsLength ); + APPEND_STRING( pBuffer, copyOffset, ",\"", 2 ); + + return copyOffset; +} + +/*-----------------------------------------------------------*/ + +static size_t _appendExecutionNumber( char * pBuffer, + size_t copyOffset, + const char * pExecutionNumber, + size_t executionNumberLength ) +{ + APPEND_STRING( pBuffer, + copyOffset, + EXECUTION_NUMBER_KEY, + EXECUTION_NUMBER_KEY_LENGTH ); + APPEND_STRING( pBuffer, + copyOffset, + "\":", + 2 ); + APPEND_STRING( pBuffer, + copyOffset, + pExecutionNumber, + executionNumberLength ); + APPEND_STRING( pBuffer, copyOffset, ",\"", 2 ); + + return copyOffset; +} + +/*-----------------------------------------------------------*/ + +static size_t _appendStepTimeout( char * pBuffer, + size_t copyOffset, + const char * pStepTimeout, + size_t stepTimeoutLength ) +{ + APPEND_STRING( pBuffer, + copyOffset, + STEP_TIMEOUT_KEY, + STEP_TIMEOUT_KEY_LENGTH ); + APPEND_STRING( pBuffer, copyOffset, "\":", 2 ); + APPEND_STRING( pBuffer, copyOffset, pStepTimeout, stepTimeoutLength ); + APPEND_STRING( pBuffer, copyOffset, ",\"", 2 ); + + return copyOffset; +} + +/*-----------------------------------------------------------*/ + +static size_t _appendClientToken( char * pBuffer, + size_t copyOffset, + const AwsIotJobsRequestInfo_t * pRequestInfo, + _jobsOperation_t * pOperation ) +{ + int clientTokenLength = 0; + uint32_t clientToken = 0; + + /* Place the client token key in the buffer. */ + APPEND_STRING( pBuffer, + copyOffset, + AWS_IOT_CLIENT_TOKEN_KEY, + AWS_IOT_CLIENT_TOKEN_KEY_LENGTH ); + APPEND_STRING( pBuffer, copyOffset, "\":\"", 3 ); + + /* Set the pointer to the client token. */ + pOperation->pClientToken = pBuffer + copyOffset - 1; + + if( pRequestInfo->pClientToken == AWS_IOT_JOBS_CLIENT_TOKEN_AUTOGENERATE ) + { + /* Take the address of the given buffer, truncated to 8 characters. This + * provides a client token that is very likely to be unique while in use. */ + clientToken = ( uint32_t ) ( ( uint64_t ) pBuffer % 100000000ULL ); + + clientTokenLength = snprintf( pBuffer + copyOffset, + CLIENT_TOKEN_AUTOGENERATE_LENGTH + 1, + "%08u", clientToken ); + AwsIotJobs_Assert( clientTokenLength == CLIENT_TOKEN_AUTOGENERATE_LENGTH ); + + copyOffset += ( size_t ) clientTokenLength; + pOperation->clientTokenLength = CLIENT_TOKEN_AUTOGENERATE_LENGTH + 2; + } + else + { + APPEND_STRING( pBuffer, + copyOffset, + pRequestInfo->pClientToken, + pRequestInfo->clientTokenLength ); + + pOperation->clientTokenLength = pRequestInfo->clientTokenLength + 2; + } + + return copyOffset; +} + +/*-----------------------------------------------------------*/ + +static AwsIotJobsError_t _generateGetPendingRequest( const AwsIotJobsRequestInfo_t * pRequestInfo, + _jobsOperation_t * pOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_SUCCESS ); + char * pJobsRequest = NULL; + size_t copyOffset = 0; + size_t requestLength = MINIMUM_REQUEST_LENGTH; + + /* Add the length of the client token. */ + if( pRequestInfo->pClientToken != AWS_IOT_JOBS_CLIENT_TOKEN_AUTOGENERATE ) + { + AwsIotJobs_Assert( pRequestInfo->clientTokenLength > 0 ); + + requestLength += pRequestInfo->clientTokenLength; + } + else + { + requestLength += CLIENT_TOKEN_AUTOGENERATE_LENGTH; + } + + /* Allocate memory for the request JSON. */ + pJobsRequest = AwsIotJobs_MallocString( requestLength ); + + if( pJobsRequest == NULL ) + { + IotLogError( "No memory for Jobs GET PENDING request." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NO_MEMORY ); + } + + /* Clear the request JSON. */ + ( void ) memset( pJobsRequest, 0x00, requestLength ); + + /* Construct the request JSON, which consists of just a clientToken key. */ + APPEND_STRING( pJobsRequest, copyOffset, "{\"", 2 ); + copyOffset = _appendClientToken( pJobsRequest, copyOffset, pRequestInfo, pOperation ); + APPEND_STRING( pJobsRequest, copyOffset, "\"}", 2 ); + + /* Set the output parameters. */ + pOperation->pJobsRequest = pJobsRequest; + pOperation->jobsRequestLength = requestLength; + + /* Ensure offsets are valid. */ + AwsIotJobs_Assert( copyOffset == requestLength ); + AwsIotJobs_Assert( pOperation->pClientToken > pOperation->pJobsRequest ); + AwsIotJobs_Assert( pOperation->pClientToken < + pOperation->pJobsRequest + pOperation->jobsRequestLength ); + + IotLogDebug( "Jobs GET PENDING request: %.*s", + pOperation->jobsRequestLength, + pOperation->pJobsRequest ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static AwsIotJobsError_t _generateStartNextRequest( const AwsIotJobsRequestInfo_t * pRequestInfo, + const AwsIotJobsUpdateInfo_t * pUpdateInfo, + _jobsOperation_t * pOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_SUCCESS ); + char * pJobsRequest = NULL; + size_t copyOffset = 0; + size_t requestLength = MINIMUM_REQUEST_LENGTH; + char pStepTimeout[ STEP_TIMEOUT_STRING_LENGTH ] = { 0 }; + int stepTimeoutLength = 0; + + /* Add the length of status details if provided. */ + if( pUpdateInfo->pStatusDetails != AWS_IOT_JOBS_NO_STATUS_DETAILS ) + { + /* Add 4 for the 2 quotes, colon, and comma. */ + requestLength += STATUS_DETAILS_KEY_LENGTH + 4; + requestLength += pUpdateInfo->statusDetailsLength; + } + + if( pUpdateInfo->stepTimeoutInMinutes != AWS_IOT_JOBS_NO_TIMEOUT ) + { + /* Calculate the length of the step timeout. Add 4 for the 2 quotes, colon, and comma. */ + requestLength += STEP_TIMEOUT_KEY_LENGTH + 4; + + if( pUpdateInfo->stepTimeoutInMinutes == AWS_IOT_JOBS_CANCEL_TIMEOUT ) + { + /* Step timeout will be set to -1. */ + pStepTimeout[ 0 ] = '-'; + pStepTimeout[ 1 ] = '1'; + stepTimeoutLength = 2; + } + else + { + /* Convert the step timeout to a string. */ + stepTimeoutLength = snprintf( pStepTimeout, + STEP_TIMEOUT_STRING_LENGTH, + "%d", + pUpdateInfo->stepTimeoutInMinutes ); + AwsIotJobs_Assert( stepTimeoutLength > 0 ); + AwsIotJobs_Assert( stepTimeoutLength < STEP_TIMEOUT_STRING_LENGTH ); + } + + requestLength += ( size_t ) stepTimeoutLength; + } + + /* Add the length of the client token. */ + if( pRequestInfo->pClientToken != AWS_IOT_JOBS_CLIENT_TOKEN_AUTOGENERATE ) + { + AwsIotJobs_Assert( pRequestInfo->clientTokenLength > 0 ); + + requestLength += pRequestInfo->clientTokenLength; + } + else + { + requestLength += CLIENT_TOKEN_AUTOGENERATE_LENGTH; + } + + /* Allocate memory for the request JSON. */ + pJobsRequest = AwsIotJobs_MallocString( requestLength ); + + if( pJobsRequest == NULL ) + { + IotLogError( "No memory for Jobs START NEXT request." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NO_MEMORY ); + } + + /* Clear the request JSON. */ + ( void ) memset( pJobsRequest, 0x00, requestLength ); + + /* Construct the request JSON. */ + APPEND_STRING( pJobsRequest, copyOffset, "{\"", 2 ); + + /* Add status details if present. */ + if( pUpdateInfo->pStatusDetails != AWS_IOT_JOBS_NO_STATUS_DETAILS ) + { + copyOffset = _appendStatusDetails( pJobsRequest, + copyOffset, + pUpdateInfo->pStatusDetails, + pUpdateInfo->statusDetailsLength ); + } + + /* Add step timeout if present. */ + if( pUpdateInfo->stepTimeoutInMinutes != AWS_IOT_JOBS_NO_TIMEOUT ) + { + copyOffset = _appendStepTimeout( pJobsRequest, + copyOffset, + pStepTimeout, + stepTimeoutLength ); + } + + /* Add client token. */ + copyOffset = _appendClientToken( pJobsRequest, copyOffset, pRequestInfo, pOperation ); + + APPEND_STRING( pJobsRequest, copyOffset, "\"}", 2 ); + + /* Set the output parameters. */ + pOperation->pJobsRequest = pJobsRequest; + pOperation->jobsRequestLength = requestLength; + + /* Ensure offsets are valid. */ + AwsIotJobs_Assert( copyOffset == requestLength ); + AwsIotJobs_Assert( pOperation->pClientToken > pOperation->pJobsRequest ); + AwsIotJobs_Assert( pOperation->pClientToken < + pOperation->pJobsRequest + pOperation->jobsRequestLength ); + + IotLogDebug( "Jobs START NEXT request: %.*s", + pOperation->jobsRequestLength, + pOperation->pJobsRequest ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static AwsIotJobsError_t _generateDescribeRequest( const AwsIotJobsRequestInfo_t * pRequestInfo, + int32_t executionNumber, + bool includeJobDocument, + _jobsOperation_t * pOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_SUCCESS ); + char * pJobsRequest = NULL; + size_t copyOffset = 0; + size_t requestLength = MINIMUM_REQUEST_LENGTH; + char pExecutionNumber[ EXECUTION_NUMBER_STRING_LENGTH ] = { 0 }; + int executionNumberLength = 0; + + /* Add the "include job document" flag if false. The default value is true, + * so the flag is not needed if true. */ + if( includeJobDocument == false ) + { + /* Add the length of "includeJobDocument" plus 4 for 2 quotes, a colon, + * and a comma. */ + requestLength += INCLUDE_JOB_DOCUMENT_KEY_LENGTH + 4; + + /* Add the length of "false". */ + requestLength += 5; + } + + /* Add the length of the execution number if present. */ + if( executionNumber != AWS_IOT_JOBS_NO_EXECUTION_NUMBER ) + { + /* Convert the execution number to a string. */ + executionNumberLength = snprintf( pExecutionNumber, + EXECUTION_NUMBER_STRING_LENGTH, + "%d", + executionNumber ); + AwsIotJobs_Assert( executionNumberLength > 0 ); + AwsIotJobs_Assert( executionNumberLength < EXECUTION_NUMBER_STRING_LENGTH ); + + requestLength += EXECUTION_NUMBER_KEY_LENGTH + 4; + requestLength += ( size_t ) executionNumberLength; + } + + /* Add the length of the client token. */ + if( pRequestInfo->pClientToken != AWS_IOT_JOBS_CLIENT_TOKEN_AUTOGENERATE ) + { + AwsIotJobs_Assert( pRequestInfo->clientTokenLength > 0 ); + + requestLength += pRequestInfo->clientTokenLength; + } + else + { + requestLength += CLIENT_TOKEN_AUTOGENERATE_LENGTH; + } + + /* Allocate memory for the request JSON. */ + pJobsRequest = AwsIotJobs_MallocString( requestLength ); + + if( pJobsRequest == NULL ) + { + IotLogError( "No memory for Jobs DESCRIBE request." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NO_MEMORY ); + } + + /* Clear the request JSON. */ + ( void ) memset( pJobsRequest, 0x00, requestLength ); + + /* Construct the request JSON. */ + APPEND_STRING( pJobsRequest, copyOffset, "{\"", 2 ); + + /* Add the "include job document" flag if false. */ + if( includeJobDocument == false ) + { + copyOffset = _appendFlag( pJobsRequest, + copyOffset, + INCLUDE_JOB_DOCUMENT_KEY, + INCLUDE_JOB_DOCUMENT_KEY_LENGTH, + false ); + } + + /* Add the length of the execution number if present. */ + if( executionNumber != AWS_IOT_JOBS_NO_EXECUTION_NUMBER ) + { + copyOffset = _appendExecutionNumber( pJobsRequest, + copyOffset, + pExecutionNumber, + ( size_t ) executionNumberLength ); + } + + /* Add client token. */ + copyOffset = _appendClientToken( pJobsRequest, copyOffset, pRequestInfo, pOperation ); + + APPEND_STRING( pJobsRequest, copyOffset, "\"}", 2 ); + + /* Set the output parameters. */ + pOperation->pJobsRequest = pJobsRequest; + pOperation->jobsRequestLength = requestLength; + + /* Ensure offsets are valid. */ + AwsIotJobs_Assert( copyOffset == requestLength ); + AwsIotJobs_Assert( pOperation->pClientToken > pOperation->pJobsRequest ); + AwsIotJobs_Assert( pOperation->pClientToken < + pOperation->pJobsRequest + pOperation->jobsRequestLength ); + + IotLogDebug( "Jobs DESCRIBE request: %.*s", + pOperation->jobsRequestLength, + pOperation->pJobsRequest ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static AwsIotJobsError_t _generateUpdateRequest( const AwsIotJobsRequestInfo_t * pRequestInfo, + const AwsIotJobsUpdateInfo_t * pUpdateInfo, + _jobsOperation_t * pOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_SUCCESS ); + char * pJobsRequest = NULL; + size_t copyOffset = 0; + size_t requestLength = MINIMUM_REQUEST_LENGTH; + const char * pStatus = NULL; + size_t statusLength = 0; + char pExpectedVersion[ EXPECTED_VERSION_STRING_LENGTH ] = { 0 }; + char pExecutionNumber[ EXECUTION_NUMBER_STRING_LENGTH ] = { 0 }; + char pStepTimeout[ STEP_TIMEOUT_STRING_LENGTH ] = { 0 }; + int expectedVersionLength = 0, executionNumberLength = 0, stepTimeoutLength = 0; + + /* Determine the status string and length to report to the Jobs service. + * Add 6 for the 4 quotes, colon, and comma. */ + requestLength += STATUS_KEY_LENGTH + 6; + + switch( pUpdateInfo->newStatus ) + { + case AWS_IOT_JOB_STATE_IN_PROGRESS: + pStatus = "IN_PROGRESS"; + break; + + case AWS_IOT_JOB_STATE_FAILED: + pStatus = "FAILED"; + break; + + case AWS_IOT_JOB_STATE_SUCCEEDED: + pStatus = "SUCCEEDED"; + break; + + default: + /* The only remaining valid state is REJECTED. */ + AwsIotJobs_Assert( pUpdateInfo->newStatus == AWS_IOT_JOB_STATE_REJECTED ); + pStatus = "REJECTED"; + break; + } + + statusLength = strlen( pStatus ); + requestLength += statusLength; + + /* Add the length of status details if provided. */ + if( pUpdateInfo->pStatusDetails != AWS_IOT_JOBS_NO_STATUS_DETAILS ) + { + /* Add 4 for the 2 quotes, colon, and comma. */ + requestLength += STATUS_DETAILS_KEY_LENGTH + 4; + requestLength += pUpdateInfo->statusDetailsLength; + } + + /* Add the expected version if provided. */ + if( pUpdateInfo->expectedVersion != AWS_IOT_JOBS_NO_VERSION ) + { + /* Convert the expected version to a string. */ + expectedVersionLength = snprintf( pExpectedVersion, + EXPECTED_VERSION_STRING_LENGTH, + "%u", + pUpdateInfo->expectedVersion ); + AwsIotJobs_Assert( expectedVersionLength > 0 ); + AwsIotJobs_Assert( expectedVersionLength < EXPECTED_VERSION_STRING_LENGTH ); + + /* Add 6 for the 4 quotes, colon, and comma. */ + requestLength += EXPECTED_VERSION_KEY_LENGTH + 6; + requestLength += ( size_t ) expectedVersionLength; + } + + /* Add the length of the execution number if present. */ + if( pUpdateInfo->executionNumber != AWS_IOT_JOBS_NO_EXECUTION_NUMBER ) + { + /* Convert the execution number to a string. */ + executionNumberLength = snprintf( pExecutionNumber, + EXECUTION_NUMBER_STRING_LENGTH, + "%d", + pUpdateInfo->executionNumber ); + AwsIotJobs_Assert( executionNumberLength > 0 ); + AwsIotJobs_Assert( executionNumberLength < EXECUTION_NUMBER_STRING_LENGTH ); + + requestLength += EXECUTION_NUMBER_KEY_LENGTH + 4; + requestLength += ( size_t ) executionNumberLength; + } + + /* Add the flags if true. The default values are false, so the flags are not + * needed if false. */ + if( pUpdateInfo->includeJobExecutionState == true ) + { + /* Add the length of "includeJobExecutionState" plus 4 for 2 quotes, a colon, + * and a comma. */ + requestLength += INCLUDE_JOB_EXECUTION_STATE_KEY_LENGTH + 4; + + /* Add the length of "true". */ + requestLength += 4; + } + + if( pUpdateInfo->includeJobDocument == true ) + { + /* Add the length of "includeJobDocument" plus 4 for 2 quotes, a colon, + * and a comma. */ + requestLength += INCLUDE_JOB_DOCUMENT_KEY_LENGTH + 4; + + /* Add the length of "true". */ + requestLength += 4; + } + + /* Add the step timeout if provided. */ + if( pUpdateInfo->stepTimeoutInMinutes != AWS_IOT_JOBS_NO_TIMEOUT ) + { + /* Calculate the length of the step timeout. Add 4 for the 2 quotes, colon, and comma. */ + requestLength += STEP_TIMEOUT_KEY_LENGTH + 4; + + if( pUpdateInfo->stepTimeoutInMinutes == AWS_IOT_JOBS_CANCEL_TIMEOUT ) + { + /* Step timeout will be set to -1. */ + pStepTimeout[ 0 ] = '-'; + pStepTimeout[ 1 ] = '1'; + stepTimeoutLength = 2; + } + else + { + /* Convert the step timeout to a string. */ + stepTimeoutLength = snprintf( pStepTimeout, + STEP_TIMEOUT_STRING_LENGTH, + "%d", + pUpdateInfo->stepTimeoutInMinutes ); + AwsIotJobs_Assert( stepTimeoutLength > 0 ); + AwsIotJobs_Assert( stepTimeoutLength < STEP_TIMEOUT_STRING_LENGTH ); + } + + requestLength += ( size_t ) stepTimeoutLength; + } + + /* Add the length of the client token. */ + if( pRequestInfo->pClientToken != AWS_IOT_JOBS_CLIENT_TOKEN_AUTOGENERATE ) + { + AwsIotJobs_Assert( pRequestInfo->clientTokenLength > 0 ); + + requestLength += pRequestInfo->clientTokenLength; + } + else + { + requestLength += CLIENT_TOKEN_AUTOGENERATE_LENGTH; + } + + /* Allocate memory for the request JSON. */ + pJobsRequest = AwsIotJobs_MallocString( requestLength ); + + if( pJobsRequest == NULL ) + { + IotLogError( "No memory for Jobs UPDATE request." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_NO_MEMORY ); + } + + /* Clear the request JSON. */ + ( void ) memset( pJobsRequest, 0x00, requestLength ); + + /* Construct the request JSON. */ + APPEND_STRING( pJobsRequest, copyOffset, "{\"", 2 ); + + /* Add the status. */ + APPEND_STRING( pJobsRequest, copyOffset, STATUS_KEY, STATUS_KEY_LENGTH ); + APPEND_STRING( pJobsRequest, copyOffset, "\":\"", 3 ); + APPEND_STRING( pJobsRequest, copyOffset, pStatus, statusLength ); + APPEND_STRING( pJobsRequest, copyOffset, "\",\"", 3 ); + + /* Add status details if present. */ + if( pUpdateInfo->pStatusDetails != AWS_IOT_JOBS_NO_STATUS_DETAILS ) + { + copyOffset = _appendStatusDetails( pJobsRequest, + copyOffset, + pUpdateInfo->pStatusDetails, + pUpdateInfo->statusDetailsLength ); + } + + /* Add expected version. */ + if( pUpdateInfo->expectedVersion != AWS_IOT_JOBS_NO_VERSION ) + { + APPEND_STRING( pJobsRequest, + copyOffset, + EXPECTED_VERSION_KEY, + EXPECTED_VERSION_KEY_LENGTH ); + APPEND_STRING( pJobsRequest, copyOffset, "\":\"", 3 ); + APPEND_STRING( pJobsRequest, copyOffset, pExpectedVersion, expectedVersionLength ); + APPEND_STRING( pJobsRequest, copyOffset, "\",\"", 3 ); + } + + /* Add execution number. */ + if( pUpdateInfo->executionNumber != AWS_IOT_JOBS_NO_EXECUTION_NUMBER ) + { + copyOffset = _appendExecutionNumber( pJobsRequest, + copyOffset, + pExecutionNumber, + executionNumberLength ); + } + + /* Add flags if not default values. */ + if( pUpdateInfo->includeJobExecutionState == true ) + { + copyOffset = _appendFlag( pJobsRequest, + copyOffset, + INCLUDE_JOB_EXECUTION_STATE_KEY, + INCLUDE_JOB_EXECUTION_STATE_KEY_LENGTH, + true ); + } + + if( pUpdateInfo->includeJobDocument == true ) + { + copyOffset = _appendFlag( pJobsRequest, + copyOffset, + INCLUDE_JOB_DOCUMENT_KEY, + INCLUDE_JOB_DOCUMENT_KEY_LENGTH, + true ); + } + + /* Add step timeout if provided. */ + if( pUpdateInfo->stepTimeoutInMinutes != AWS_IOT_JOBS_NO_TIMEOUT ) + { + copyOffset = _appendStepTimeout( pJobsRequest, + copyOffset, + pStepTimeout, + stepTimeoutLength ); + } + + /* Add the client token. */ + copyOffset = _appendClientToken( pJobsRequest, copyOffset, pRequestInfo, pOperation ); + + APPEND_STRING( pJobsRequest, copyOffset, "\"}", 2 ); + + /* Set the output parameters. */ + pOperation->pJobsRequest = pJobsRequest; + pOperation->jobsRequestLength = requestLength; + + /* Ensure offsets are valid. */ + AwsIotJobs_Assert( copyOffset == requestLength ); + AwsIotJobs_Assert( pOperation->pClientToken > pOperation->pJobsRequest ); + AwsIotJobs_Assert( pOperation->pClientToken < + pOperation->pJobsRequest + pOperation->jobsRequestLength ); + + IotLogDebug( "Jobs UPDATE request: %.*s", + pOperation->jobsRequestLength, + pOperation->pJobsRequest ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static AwsIotJobsError_t _parseErrorDocument( const char * pErrorDocument, + size_t errorDocumentLength ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_STATUS_PENDING ); + const char * pCode = NULL; + size_t codeLength = 0; + + /* Find the error code. */ + if( AwsIotDocParser_FindValue( pErrorDocument, + errorDocumentLength, + CODE_KEY, + CODE_KEY_LENGTH, + &pCode, + &codeLength ) == false ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_RESPONSE ); + } + + /* Match the JSON error code to a Jobs return value. Assume invalid status + * unless matched.*/ + status = AWS_IOT_JOBS_BAD_RESPONSE; + + switch( codeLength ) + { + /* InvalidJson */ + case 13: + + if( strncmp( "\"InvalidJson\"", pCode, codeLength ) == 0 ) + { + status = AWS_IOT_JOBS_INVALID_JSON; + } + + break; + + /* InvalidTopic */ + case 14: + + if( strncmp( "\"InvalidTopic\"", pCode, codeLength ) == 0 ) + { + status = AWS_IOT_JOBS_INVALID_TOPIC; + } + + break; + + /* InternalError */ + case 15: + + if( strncmp( "\"InternalError\"", pCode, codeLength ) == 0 ) + { + status = AWS_IOT_JOBS_INTERNAL_ERROR; + } + + break; + + /* InvalidRequest */ + case 16: + + if( strncmp( "\"InvalidRequest\"", pCode, codeLength ) == 0 ) + { + status = AWS_IOT_JOBS_INVALID_REQUEST; + } + + break; + + /* VersionMismatch */ + case 17: + + if( strncmp( "\"VersionMismatch\"", pCode, codeLength ) == 0 ) + { + status = AWS_IOT_JOBS_VERSION_MISMATCH; + } + + break; + + /* ResourceNotFound, RequestThrottled */ + case 18: + + if( strncmp( "\"ResourceNotFound\"", pCode, codeLength ) == 0 ) + { + status = AWS_IOT_JOBS_NOT_FOUND; + } + else if( strncmp( "\"RequestThrottled\"", pCode, codeLength ) == 0 ) + { + status = AWS_IOT_JOBS_THROTTLED; + } + + break; + + /* TerminalStateReached */ + case 22: + + if( strncmp( "\"TerminalStateReached\"", pCode, codeLength ) == 0 ) + { + status = AWS_IOT_JOBS_TERMINAL_STATE; + } + + break; + + /* InvalidStateTransition */ + case 24: + + if( strncmp( "\"InvalidStateTransition\"", pCode, codeLength ) == 0 ) + { + status = AWS_IOT_JOBS_INVALID_STATE; + } + + break; + + default: + break; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t _AwsIotJobs_GenerateJsonRequest( _jobsOperationType_t type, + const AwsIotJobsRequestInfo_t * pRequestInfo, + const _jsonRequestContents_t * pRequestContents, + _jobsOperation_t * pOperation ) +{ + AwsIotJobsError_t status = AWS_IOT_JOBS_STATUS_PENDING; + + /* Generate request based on the Job operation type. */ + switch( type ) + { + case JOBS_GET_PENDING: + status = _generateGetPendingRequest( pRequestInfo, pOperation ); + break; + + case JOBS_START_NEXT: + status = _generateStartNextRequest( pRequestInfo, + pRequestContents->pUpdateInfo, + pOperation ); + break; + + case JOBS_DESCRIBE: + status = _generateDescribeRequest( pRequestInfo, + pRequestContents->describe.executionNumber, + pRequestContents->describe.includeJobDocument, + pOperation ); + break; + + default: + /* The only remaining valid type is UPDATE. */ + AwsIotJobs_Assert( type == JOBS_UPDATE ); + + status = _generateUpdateRequest( pRequestInfo, + pRequestContents->pUpdateInfo, + pOperation ); + break; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +void _AwsIotJobs_ParseResponse( AwsIotStatus_t status, + const char * pResponse, + size_t responseLength, + _jobsOperation_t * pOperation ) +{ + AwsIotJobs_Assert( pOperation->status == AWS_IOT_JOBS_STATUS_PENDING ); + + /* A non-waitable operation can re-use the pointers from the publish info, + * since those are guaranteed to be in-scope throughout the user callback. + * But a waitable operation must copy the data from the publish info because + * AwsIotJobs_Wait may be called after the MQTT library frees the publish + * info. */ + if( ( pOperation->flags & AWS_IOT_JOBS_FLAG_WAITABLE ) == 0 ) + { + pOperation->pJobsResponse = pResponse; + pOperation->jobsResponseLength = responseLength; + } + else + { + IotLogDebug( "Allocating new buffer for waitable Jobs %s.", + _pAwsIotJobsOperationNames[ pOperation->type ] ); + + /* Parameter validation should not have allowed a NULL malloc function. */ + AwsIotJobs_Assert( pOperation->mallocResponse != NULL ); + + /* Allocate a buffer for the retrieved document. */ + pOperation->pJobsResponse = pOperation->mallocResponse( responseLength ); + + if( pOperation->pJobsResponse == NULL ) + { + IotLogError( "Failed to allocate buffer for retrieved Jobs %s response.", + _pAwsIotJobsOperationNames[ pOperation->type ] ); + + pOperation->status = AWS_IOT_JOBS_NO_MEMORY; + } + else + { + /* Copy the response. */ + ( void ) memcpy( ( void * ) pOperation->pJobsResponse, pResponse, responseLength ); + pOperation->jobsResponseLength = responseLength; + } + } + + /* Set the status of the Jobs operation. */ + if( pOperation->status == AWS_IOT_JOBS_STATUS_PENDING ) + { + if( status == AWS_IOT_ACCEPTED ) + { + pOperation->status = AWS_IOT_JOBS_SUCCESS; + } + else + { + pOperation->status = _parseErrorDocument( pResponse, responseLength ); + } + } +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_static_memory.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_static_memory.c new file mode 100644 index 000000000..bfdbed64f --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_static_memory.c @@ -0,0 +1,169 @@ +/* + * AWS IoT Jobs V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_jobs_static_memory.c + * @brief Implementation of Jobs static memory functions. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* This file should only be compiled if dynamic memory allocation is forbidden. */ +#if IOT_STATIC_MEMORY_ONLY == 1 + +/* Standard includes. */ +#include +#include +#include + +/* Static memory include. */ +#include "iot_static_memory.h" + +/* Jobs internal include. */ +#include "private/aws_iot_jobs_internal.h" + +/*-----------------------------------------------------------*/ + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * Provide default values for undefined configuration constants. + */ +#ifndef AWS_IOT_JOBS_MAX_IN_PROGRESS_OPERATIONS + #define AWS_IOT_JOBS_MAX_IN_PROGRESS_OPERATIONS ( 10 ) +#endif +#ifndef AWS_IOT_JOBS_SUBSCRIPTIONS + #define AWS_IOT_JOBS_SUBSCRIPTIONS ( 2 ) +#endif +/** @endcond */ + +/* Validate static memory configuration settings. */ +#if AWS_IOT_JOBS_MAX_IN_PROGRESS_OPERATIONS <= 0 + #error "AWS_IOT_JOBS_MAX_IN_PROGRESS_OPERATIONS cannot be 0 or negative." +#endif +#if AWS_IOT_JOBS_SUBSCRIPTIONS <= 0 + #error "AWS_IOT_JOBS_SUBSCRIPTIONS cannot be 0 or negative." +#endif + +/** + * @brief The size of a static memory Jobs operation. + * + * Since the pJobId member of #_jobsOperation_t is variable-length, + * the constant `JOBS_MAX_ID_LENGTH` is used for the length of + * #_jobsOperation_t.pJobId. + */ +#define JOBS_OPERATION_SIZE ( sizeof( _jobsOperation_t ) + JOBS_MAX_ID_LENGTH ) + +/** + * @brief The size of a static memory Jobs subscription. + * + * Since the pThingName member of #_jobsSubscription_t is variable-length, + * the constant `AWS_IOT_MAX_THING_NAME_LENGTH` is used for the length of + * #_jobsSubscription_t.pThingName. + */ +#define JOBS_SUBSCRIPTION_SIZE ( sizeof( _jobsSubscription_t ) + AWS_IOT_MAX_THING_NAME_LENGTH ) + +/*-----------------------------------------------------------*/ + +/* + * Static memory buffers and flags, allocated and zeroed at compile-time. + */ +static uint32_t _pInUseJobsOperations[ AWS_IOT_JOBS_MAX_IN_PROGRESS_OPERATIONS ] = { 0U }; /**< @brief Jobs operation in-use flags. */ +static char _pJobsOperations[ AWS_IOT_JOBS_MAX_IN_PROGRESS_OPERATIONS ][ JOBS_OPERATION_SIZE ] = { { 0 } }; /**< @brief Jobs operations. */ + +static uint32_t _pInUseJobsSubscriptions[ AWS_IOT_JOBS_SUBSCRIPTIONS ] = { 0U }; /**< @brief Jobs subscription in-use flags. */ +static char _pJobsSubscriptions[ AWS_IOT_JOBS_SUBSCRIPTIONS ][ JOBS_SUBSCRIPTION_SIZE ] = { { 0 } }; /**< @brief Jobs subscriptions. */ + +/*-----------------------------------------------------------*/ + +void * AwsIotJobs_MallocOperation( size_t size ) +{ + int32_t freeIndex = -1; + void * pNewOperation = NULL; + + /* Check size argument. */ + if( size <= JOBS_OPERATION_SIZE ) + { + /* Find a free Jobs operation. */ + freeIndex = IotStaticMemory_FindFree( _pInUseJobsOperations, + AWS_IOT_JOBS_MAX_IN_PROGRESS_OPERATIONS ); + + if( freeIndex != -1 ) + { + pNewOperation = &( _pJobsOperations[ freeIndex ] ); + } + } + + return pNewOperation; +} + +/*-----------------------------------------------------------*/ + +void AwsIotJobs_FreeOperation( void * ptr ) +{ + /* Return the in-use Jobs operation. */ + IotStaticMemory_ReturnInUse( ptr, + _pJobsOperations, + _pInUseJobsOperations, + AWS_IOT_JOBS_MAX_IN_PROGRESS_OPERATIONS, + JOBS_OPERATION_SIZE ); +} + +/*-----------------------------------------------------------*/ + +void * AwsIotJobs_MallocSubscription( size_t size ) +{ + int32_t freeIndex = -1; + void * pNewSubscription = NULL; + + if( size <= JOBS_SUBSCRIPTION_SIZE ) + { + /* Get the index of a free Jobs subscription. */ + freeIndex = IotStaticMemory_FindFree( _pInUseJobsSubscriptions, + AWS_IOT_JOBS_SUBSCRIPTIONS ); + + if( freeIndex != -1 ) + { + pNewSubscription = &( _pJobsSubscriptions[ freeIndex ][ 0 ] ); + } + } + + return pNewSubscription; +} + +/*-----------------------------------------------------------*/ + +void AwsIotJobs_FreeSubscription( void * ptr ) +{ + /* Return the in-use Jobs subscription. */ + IotStaticMemory_ReturnInUse( ptr, + _pJobsSubscriptions, + _pInUseJobsSubscriptions, + AWS_IOT_JOBS_SUBSCRIPTIONS, + JOBS_SUBSCRIPTION_SIZE ); +} + +/*-----------------------------------------------------------*/ + +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_subscription.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_subscription.c new file mode 100644 index 000000000..aa944cf7e --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/aws_iot_jobs_subscription.c @@ -0,0 +1,581 @@ +/* + * AWS IoT Jobs V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_jobs_subscription.c + * @brief Implements functions for interacting with the Jobs library's + * subscription list. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* Jobs internal include. */ +#include "private/aws_iot_jobs_internal.h" + +/* Error handling include. */ +#include "iot_error.h" + +/* Platform layer includes. */ +#include "platform/iot_threads.h" + +/* MQTT include. */ +#include "iot_mqtt.h" + +/*-----------------------------------------------------------*/ + +/** + * @brief Match two #_jobsSubscription_t by Thing Name. + * + * @param[in] pSubscriptionLink Pointer to the link member of a #_jobsSubscription_t + * containing the Thing Name to check. + * @param[in] pMatch Pointer to a `AwsIotThingName_t`. + * + * @return `true` if the Thing Names match; `false` otherwise. + */ +static bool _jobsSubscription_match( const IotLink_t * pSubscriptionLink, + void * pMatch ); + +/*-----------------------------------------------------------*/ + +/** + * @brief List of active Jobs subscriptions objects. + */ +IotListDouble_t _AwsIotJobsSubscriptions = { 0 }; + +/** + * @brief Protects #_AwsIotJobsSubscriptions from concurrent access. + */ +IotMutex_t _AwsIotJobsSubscriptionsMutex; + +/*-----------------------------------------------------------*/ + +static bool _jobsSubscription_match( const IotLink_t * pSubscriptionLink, + void * pMatch ) +{ + bool match = false; + + /* Because this function is called from a container function, the given link + * must never be NULL. */ + AwsIotJobs_Assert( pSubscriptionLink != NULL ); + + const _jobsSubscription_t * pSubscription = IotLink_Container( _jobsSubscription_t, + pSubscriptionLink, + link ); + const AwsIotThingName_t * pThingName = ( AwsIotThingName_t * ) pMatch; + + if( pThingName->thingNameLength == pSubscription->thingNameLength ) + { + /* Check for matching Thing Names. */ + match = ( strncmp( pThingName->pThingName, + pSubscription->pThingName, + pThingName->thingNameLength ) == 0 ); + } + + return match; +} + +/*-----------------------------------------------------------*/ + +_jobsSubscription_t * _AwsIotJobs_FindSubscription( const char * pThingName, + size_t thingNameLength, + bool createIfNotFound ) +{ + _jobsSubscription_t * pSubscription = NULL; + IotLink_t * pSubscriptionLink = NULL; + AwsIotThingName_t thingName = { 0 }; + + thingName.pThingName = pThingName; + thingName.thingNameLength = thingNameLength; + + /* Search the list for an existing subscription for Thing Name. */ + pSubscriptionLink = IotListDouble_FindFirstMatch( &( _AwsIotJobsSubscriptions ), + NULL, + _jobsSubscription_match, + &thingName ); + + /* Check if a subscription was found. */ + if( pSubscriptionLink == NULL ) + { + if( createIfNotFound == true ) + { + /* No subscription found. Allocate a new subscription. */ + pSubscription = AwsIotJobs_MallocSubscription( sizeof( _jobsSubscription_t ) + thingNameLength ); + + if( pSubscription != NULL ) + { + /* Clear the new subscription. */ + ( void ) memset( pSubscription, 0x00, sizeof( _jobsSubscription_t ) + thingNameLength ); + + /* Set the Thing Name length and copy the Thing Name into the new subscription. */ + pSubscription->thingNameLength = thingNameLength; + ( void ) memcpy( pSubscription->pThingName, pThingName, thingNameLength ); + + /* Add the new subscription to the subscription list. */ + IotListDouble_InsertHead( &( _AwsIotJobsSubscriptions ), + &( pSubscription->link ) ); + + IotLogDebug( "Created new Jobs subscriptions object for %.*s.", + thingNameLength, + pThingName ); + } + else + { + IotLogError( "Failed to allocate memory for %.*s Jobs subscriptions.", + thingNameLength, + pThingName ); + } + } + } + else + { + IotLogDebug( "Found existing Jobs subscriptions object for %.*s.", + thingNameLength, + pThingName ); + + pSubscription = IotLink_Container( _jobsSubscription_t, pSubscriptionLink, link ); + } + + return pSubscription; +} + +/*-----------------------------------------------------------*/ + +void _AwsIotJobs_RemoveSubscription( _jobsSubscription_t * pSubscription, + _jobsSubscription_t ** pRemovedSubscription ) +{ + IOT_FUNCTION_ENTRY( bool, true ); + int32_t i = 0, callbackIndex = 0; + + IotLogDebug( "Checking if subscription object for %.*s can be removed.", + pSubscription->thingNameLength, + pSubscription->pThingName ); + + /* Check for active operations. If any Jobs operation's subscription + * reference count is not 0, then the subscription cannot be removed. */ + for( i = 0; i < JOBS_OPERATION_COUNT; i++ ) + { + if( pSubscription->operationReferences[ i ] > 0 ) + { + IotLogDebug( "Reference count %ld for %.*s subscription object. " + "Subscription cannot be removed yet.", + ( long int ) pSubscription->operationReferences[ i ], + pSubscription->thingNameLength, + pSubscription->pThingName ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else if( pSubscription->operationReferences[ i ] == AWS_IOT_PERSISTENT_SUBSCRIPTION ) + { + IotLogDebug( "Subscription object for %.*s has persistent subscriptions. " + "Subscription will not be removed.", + pSubscription->thingNameLength, + pSubscription->pThingName ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + } + + /* Check for active subscriptions. If any Jobs callbacks are active, then the + * subscription cannot be removed. */ + if( pSubscription->callbackReferences > 0 ) + { + IotLogDebug( "Notify callbacks are using %.*s subscription object. " + "Subscription cannot be removed yet.", + pSubscription->thingNameLength, + pSubscription->pThingName ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + + for( i = 0; i < JOBS_CALLBACK_COUNT; i++ ) + { + for( callbackIndex = 0; callbackIndex < AWS_IOT_JOBS_NOTIFY_CALLBACKS; callbackIndex++ ) + { + if( pSubscription->callbacks[ i ][ callbackIndex ].function != NULL ) + { + IotLogDebug( "Found active Jobs %s callback for %.*s subscription object. " + "Subscription cannot be removed yet.", + _pAwsIotJobsCallbackNames[ i ], + pSubscription->thingNameLength, + pSubscription->pThingName ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + } + } + + /* Remove the subscription if unused. */ + IOT_FUNCTION_CLEANUP_BEGIN(); + + if( status == true ) + { + /* No Jobs operation subscription references or active Jobs callbacks. + * Remove the subscription object. */ + IotListDouble_Remove( &( pSubscription->link ) ); + + IotLogDebug( "Removed subscription object for %.*s.", + pSubscription->thingNameLength, + pSubscription->pThingName ); + + /* If the caller requested the removed subscription, set the output parameter. + * Otherwise, free the memory used by the subscription. */ + if( pRemovedSubscription != NULL ) + { + *pRemovedSubscription = pSubscription; + } + else + { + _AwsIotJobs_DestroySubscription( pSubscription ); + } + } +} + +/*-----------------------------------------------------------*/ + +void _AwsIotJobs_DestroySubscription( void * pData ) +{ + _jobsSubscription_t * pSubscription = ( _jobsSubscription_t * ) pData; + + /* Free the topic buffer if allocated. */ + if( pSubscription->pTopicBuffer != NULL ) + { + AwsIotJobs_FreeString( pSubscription->pTopicBuffer ); + } + + /* Free memory used by subscription. */ + AwsIotJobs_FreeSubscription( pSubscription ); +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t _AwsIotJobs_IncrementReferences( _jobsOperation_t * pOperation, + char * pTopicBuffer, + uint16_t operationTopicLength, + AwsIotMqttCallbackFunction_t callback ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_SUCCESS ); + const _jobsOperationType_t type = pOperation->type; + _jobsSubscription_t * pSubscription = pOperation->pSubscription; + IotMqttError_t subscriptionStatus = IOT_MQTT_STATUS_PENDING; + AwsIotSubscriptionInfo_t subscriptionInfo = { 0 }; + + /* Do nothing if this operation has persistent subscriptions. */ + if( pSubscription->operationReferences[ type ] == AWS_IOT_PERSISTENT_SUBSCRIPTION ) + { + IotLogDebug( "Jobs %s for %.*s has persistent subscriptions. Reference " + "count will not be incremented.", + _pAwsIotJobsOperationNames[ type ], + pSubscription->thingNameLength, + pSubscription->pThingName ); + + IOT_GOTO_CLEANUP(); + } + + /* When persistent subscriptions are not present, the reference count must + * not be negative. */ + AwsIotJobs_Assert( pSubscription->operationReferences[ type ] >= 0 ); + + /* Check if there are any existing references for this operation. */ + if( pSubscription->operationReferences[ type ] == 0 ) + { + /* Set the parameters needed to add subscriptions. */ + subscriptionInfo.mqttConnection = pOperation->mqttConnection; + subscriptionInfo.callbackFunction = callback; + subscriptionInfo.timeout = _AwsIotJobsMqttTimeoutMs; + subscriptionInfo.pTopicFilterBase = pTopicBuffer; + subscriptionInfo.topicFilterBaseLength = operationTopicLength; + + subscriptionStatus = AwsIot_ModifySubscriptions( IotMqtt_SubscribeSync, + &subscriptionInfo ); + + /* Convert MQTT return code to Jobs return code. */ + switch( subscriptionStatus ) + { + case IOT_MQTT_SUCCESS: + status = AWS_IOT_JOBS_SUCCESS; + break; + + case IOT_MQTT_NO_MEMORY: + status = AWS_IOT_JOBS_NO_MEMORY; + break; + + default: + status = AWS_IOT_JOBS_MQTT_ERROR; + break; + } + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + } + + /* Increment the number of subscription references for this operation when + * the keep subscriptions flag is not set. */ + if( ( pOperation->flags & AWS_IOT_JOBS_FLAG_KEEP_SUBSCRIPTIONS ) == 0 ) + { + ( pSubscription->operationReferences[ type ] )++; + + IotLogDebug( "Jobs %s subscriptions for %.*s now has count %d.", + _pAwsIotJobsOperationNames[ type ], + pSubscription->thingNameLength, + pSubscription->pThingName, + pSubscription->operationReferences[ type ] ); + } + /* Otherwise, set the persistent subscriptions flag. */ + else + { + pSubscription->operationReferences[ type ] = AWS_IOT_PERSISTENT_SUBSCRIPTION; + + IotLogDebug( "Set persistent subscriptions flag for Jobs %s of %.*s.", + _pAwsIotJobsOperationNames[ type ], + pSubscription->thingNameLength, + pSubscription->pThingName ); + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +void _AwsIotJobs_DecrementReferences( _jobsOperation_t * pOperation, + char * pTopicBuffer, + _jobsSubscription_t ** pRemovedSubscription ) +{ + const _jobsOperationType_t type = pOperation->type; + _jobsSubscription_t * pSubscription = pOperation->pSubscription; + uint16_t operationTopicLength = 0; + AwsIotSubscriptionInfo_t subscriptionInfo = { 0 }; + AwsIotJobsRequestInfo_t requestInfo = AWS_IOT_JOBS_REQUEST_INFO_INITIALIZER; + + /* Do nothing if this Jobs operation has persistent subscriptions. */ + if( pSubscription->operationReferences[ type ] != AWS_IOT_PERSISTENT_SUBSCRIPTION ) + { + /* Decrement the number of subscription references for this operation. + * Ensure that it's positive. */ + ( pSubscription->operationReferences[ type ] )--; + AwsIotJobs_Assert( pSubscription->operationReferences[ type ] >= 0 ); + + /* Check if the number of references has reached 0. */ + if( pSubscription->operationReferences[ type ] == 0 ) + { + IotLogDebug( "Reference count for %.*s %s is 0. Unsubscribing.", + pSubscription->thingNameLength, + pSubscription->pThingName, + _pAwsIotJobsOperationNames[ type ] ); + + /* Subscription must have a topic buffer. */ + AwsIotJobs_Assert( pSubscription->pTopicBuffer != NULL ); + + /* Set the parameters needed to generate a Jobs topic. */ + requestInfo.pThingName = pSubscription->pThingName; + requestInfo.thingNameLength = pSubscription->thingNameLength; + requestInfo.pJobId = pOperation->pJobId; + requestInfo.jobIdLength = pOperation->jobIdLength; + + /* Generate the prefix of the Jobs topic. This function will not + * fail when given a buffer. */ + ( void ) _AwsIotJobs_GenerateJobsTopic( ( _jobsOperationType_t ) type, + &requestInfo, + &( pSubscription->pTopicBuffer ), + &operationTopicLength ); + + /* Set the parameters needed to remove subscriptions. */ + subscriptionInfo.mqttConnection = pOperation->mqttConnection; + subscriptionInfo.timeout = _AwsIotJobsMqttTimeoutMs; + subscriptionInfo.pTopicFilterBase = pTopicBuffer; + subscriptionInfo.topicFilterBaseLength = operationTopicLength; + + ( void ) AwsIot_ModifySubscriptions( IotMqtt_UnsubscribeSync, + &subscriptionInfo ); + } + + /* Check if this subscription should be deleted. */ + _AwsIotJobs_RemoveSubscription( pSubscription, + pRemovedSubscription ); + } + else + { + IotLogDebug( "Jobs %s for %.*s has persistent subscriptions. Reference " + "count will not be decremented.", + _pAwsIotJobsOperationNames[ type ], + pSubscription->thingNameLength, + pSubscription->pThingName ); + } +} + +/*-----------------------------------------------------------*/ + +AwsIotJobsError_t AwsIotJobs_RemovePersistentSubscriptions( const AwsIotJobsRequestInfo_t * pRequestInfo, + uint32_t flags ) +{ + IOT_FUNCTION_ENTRY( AwsIotJobsError_t, AWS_IOT_JOBS_SUCCESS ); + int32_t i = 0; + uint16_t operationTopicLength = 0; + IotMqttError_t unsubscribeStatus = IOT_MQTT_STATUS_PENDING; + AwsIotSubscriptionInfo_t subscriptionInfo = { 0 }; + _jobsSubscription_t * pSubscription = NULL; + IotLink_t * pSubscriptionLink = NULL; + AwsIotThingName_t thingName = { 0 }; + + thingName.pThingName = pRequestInfo->pThingName; + thingName.thingNameLength = pRequestInfo->thingNameLength; + + IotLogInfo( "Removing persistent subscriptions for %.*s.", + pRequestInfo->thingNameLength, + pRequestInfo->pThingName ); + + /* Check parameters. */ + if( pRequestInfo->mqttConnection == IOT_MQTT_CONNECTION_INITIALIZER ) + { + IotLogError( "MQTT connection is not initialized." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + if( AwsIot_ValidateThingName( pRequestInfo->pThingName, + pRequestInfo->thingNameLength ) == false ) + { + IotLogError( "Thing Name is not valid." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + if( ( ( flags & AWS_IOT_JOBS_FLAG_REMOVE_DESCRIBE_SUBSCRIPTIONS ) != 0 ) || + ( ( flags & AWS_IOT_JOBS_FLAG_REMOVE_UPDATE_SUBSCRIPTIONS ) != 0 ) ) + { + if( ( pRequestInfo->pJobId == NULL ) || ( pRequestInfo->jobIdLength == 0 ) ) + { + IotLogError( "Job ID must be set." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + + if( pRequestInfo->jobIdLength > JOBS_MAX_ID_LENGTH ) + { + IotLogError( "Job ID cannot be longer than %d.", + JOBS_MAX_ID_LENGTH ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_JOBS_BAD_PARAMETER ); + } + } + + IotMutex_Lock( &( _AwsIotJobsSubscriptionsMutex ) ); + + /* Search the list for an existing subscription for Thing Name. */ + pSubscriptionLink = IotListDouble_FindFirstMatch( &( _AwsIotJobsSubscriptions ), + NULL, + _jobsSubscription_match, + &thingName ); + + if( pSubscriptionLink != NULL ) + { + IotLogDebug( "Found subscription object for %.*s. Checking for persistent " + "subscriptions to remove.", + pRequestInfo->thingNameLength, + pRequestInfo->pThingName ); + + pSubscription = IotLink_Container( _jobsSubscription_t, pSubscriptionLink, link ); + + for( i = 0; i < JOBS_OPERATION_COUNT; i++ ) + { + if( ( flags & ( 0x1UL << i ) ) != 0 ) + { + IotLogDebug( "Removing %.*s %s persistent subscriptions.", + pRequestInfo->thingNameLength, + pRequestInfo->pThingName, + _pAwsIotJobsOperationNames[ i ] ); + + /* Subscription must have a topic buffer. */ + AwsIotJobs_Assert( pSubscription->pTopicBuffer != NULL ); + + if( pSubscription->operationReferences[ i ] == AWS_IOT_PERSISTENT_SUBSCRIPTION ) + { + /* Generate the prefix of the Jobs topic. This function will not + * fail when given a buffer. */ + ( void ) _AwsIotJobs_GenerateJobsTopic( ( _jobsOperationType_t ) i, + pRequestInfo, + &( pSubscription->pTopicBuffer ), + &operationTopicLength ); + + /* Set the parameters needed to remove subscriptions. */ + subscriptionInfo.mqttConnection = pRequestInfo->mqttConnection; + subscriptionInfo.timeout = _AwsIotJobsMqttTimeoutMs; + subscriptionInfo.pTopicFilterBase = pSubscription->pTopicBuffer; + subscriptionInfo.topicFilterBaseLength = operationTopicLength; + + unsubscribeStatus = AwsIot_ModifySubscriptions( IotMqtt_UnsubscribeSync, + &subscriptionInfo ); + + /* Convert MQTT return code to Shadow return code. */ + switch( unsubscribeStatus ) + { + case IOT_MQTT_SUCCESS: + status = AWS_IOT_JOBS_SUCCESS; + break; + + case IOT_MQTT_NO_MEMORY: + status = AWS_IOT_JOBS_NO_MEMORY; + break; + + default: + status = AWS_IOT_JOBS_MQTT_ERROR; + break; + } + + if( status != AWS_IOT_JOBS_SUCCESS ) + { + break; + } + + /* Clear the persistent subscriptions flag and check if the + * subscription can be removed. */ + pSubscription->operationReferences[ i ] = 0; + _AwsIotJobs_RemoveSubscription( pSubscription, NULL ); + } + else + { + IotLogDebug( "%.*s %s does not have persistent subscriptions.", + pRequestInfo->thingNameLength, + pRequestInfo->pThingName, + _pAwsIotJobsOperationNames[ i ] ); + } + } + } + } + else + { + IotLogWarn( "No subscription object found for %.*s", + pRequestInfo->thingNameLength, + pRequestInfo->pThingName ); + } + + IotMutex_Unlock( &( _AwsIotJobsSubscriptionsMutex ) ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/private/aws_iot_jobs_internal.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/private/aws_iot_jobs_internal.h new file mode 100644 index 000000000..458bc0058 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/jobs/src/private/aws_iot_jobs_internal.h @@ -0,0 +1,628 @@ +/* + * AWS IoT Jobs V1.0.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_jobs_internal.h + * @brief Internal header of Jobs library. This header should not be included in + * typical application code. + */ + +#ifndef AWS_IOT_JOBS_INTERNAL_H_ +#define AWS_IOT_JOBS_INTERNAL_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Linear containers (lists and queues) include. */ +#include "iot_linear_containers.h" + +/* Jobs include. */ +#include "aws_iot_jobs.h" + +/* AWS IoT include. */ +#include "aws_iot.h" + +/** + * @def AwsIotJobs_Assert( expression ) + * @brief Assertion macro for the Jobs library. + * + * Set @ref AWS_IOT_JOBS_ENABLE_ASSERTS to `1` to enable assertions in the Jobs + * library. + * + * @param[in] expression Expression to be evaluated. + */ +#if AWS_IOT_JOBS_ENABLE_ASSERTS == 1 + #ifndef AwsIotJobs_Assert + #ifdef Iot_DefaultAssert + #define AwsIotJobs_Assert( expression ) Iot_DefaultAssert( expression ) + #else + #error "Asserts are enabled for Jobs, but AwsIotJobs_Assert is not defined" + #endif + #endif +#else + #define AwsIotJobs_Assert( expression ) +#endif + +/* Configure logs for Jobs functions. */ +#ifdef AWS_IOT_LOG_LEVEL_JOBS + #define LIBRARY_LOG_LEVEL AWS_IOT_LOG_LEVEL_JOBS +#else + #ifdef IOT_LOG_LEVEL_GLOBAL + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_GLOBAL + #else + #define LIBRARY_LOG_LEVEL IOT_LOG_NONE + #endif +#endif + +#define LIBRARY_LOG_NAME ( "Jobs" ) +#include "iot_logging_setup.h" + +/* + * Provide default values for undefined memory allocation functions based on + * the usage of dynamic memory allocation. + */ +#if IOT_STATIC_MEMORY_ONLY == 1 + #include "iot_static_memory.h" + +/** + * @brief Allocate a #_jobsOperation_t. This function should have the same + * signature as [malloc] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html). + */ + void * AwsIotJobs_MallocOperation( size_t size ); + +/** + * @brief Free a #_jobsOperation_t. This function should have the same + * signature as [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ + void AwsIotJobs_FreeOperation( void * ptr ); + +/** + * @brief Allocate a buffer for a short string, used for topic names or client + * tokens. This function should have the same signature as [malloc] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html). + */ + #define AwsIotJobs_MallocString Iot_MallocMessageBuffer + +/** + * @brief Free a string. This function should have the same signature as + * [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ + #define AwsIotJobs_FreeString Iot_FreeMessageBuffer + +/** + * @brief Allocate a #_jobsSubscription_t. This function should have the + * same signature as [malloc] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html). + */ + void * AwsIotJobs_MallocSubscription( size_t size ); + +/** + * @brief Free a #_jobsSubscription_t. This function should have the same + * signature as [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ + void AwsIotJobs_FreeSubscription( void * ptr ); +#else /* if IOT_STATIC_MEMORY_ONLY == 1 */ + #ifndef AwsIotJobs_MallocOperation + #ifdef Iot_DefaultMalloc + #define AwsIotJobs_MallocOperation Iot_DefaultMalloc + #else + #error "No malloc function defined for AwsIotJobs_MallocOperation" + #endif + #endif + + #ifndef AwsIotJobs_FreeOperation + #ifdef Iot_DefaultFree + #define AwsIotJobs_FreeOperation Iot_DefaultFree + #else + #error "No free function defined for AwsIotJobs_FreeOperation" + #endif + #endif + + #ifndef AwsIotJobs_MallocString + #ifdef Iot_DefaultMalloc + #define AwsIotJobs_MallocString Iot_DefaultMalloc + #else + #error "No malloc function defined for AwsIotJobs_MallocString" + #endif + #endif + + #ifndef AwsIotJobs_FreeString + #ifdef Iot_DefaultFree + #define AwsIotJobs_FreeString Iot_DefaultFree + #else + #error "No free function defined for AwsIotJobs_FreeString" + #endif + #endif + + #ifndef AwsIotJobs_MallocSubscription + #ifdef Iot_DefaultMalloc + #define AwsIotJobs_MallocSubscription Iot_DefaultMalloc + #else + #error "No malloc function defined for AwsIotJobs_MallocSubscription" + #endif + #endif + + #ifndef AwsIotJobs_FreeSubscription + #ifdef Iot_DefaultFree + #define AwsIotJobs_FreeSubscription Iot_DefaultFree + #else + #error "No free function defined for AwsIotJobs_FreeSubscription" + #endif + #endif +#endif /* if IOT_STATIC_MEMORY_ONLY == 1 */ + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * Provide default values for undefined configuration constants. + */ +#ifndef AWS_IOT_JOBS_DEFAULT_MQTT_TIMEOUT_MS + #define AWS_IOT_JOBS_DEFAULT_MQTT_TIMEOUT_MS ( 5000 ) +#endif +#ifndef AWS_IOT_JOBS_NOTIFY_CALLBACKS + #define AWS_IOT_JOBS_NOTIFY_CALLBACKS ( 1 ) +#endif +/** @endcond */ + +/** + * @brief The number of currently available Jobs operations. + * + * The 4 Jobs operations are GET PENDING, START NEXT, DESCRIBE, and UPDATE. + */ +#define JOBS_OPERATION_COUNT ( 4 ) + +/** + * @brief The number of currently available Jobs callbacks. + * + * The 2 Jobs callbacks are `jobs/notify` (AKA "Notify Pending") and + * `/jobs/notify-next` (AKA "Notify Next"). + */ +#define JOBS_CALLBACK_COUNT ( 2 ) + +/** + * @brief The string representing a Jobs GET PENDING operation in a Jobs MQTT topic. + */ +#define JOBS_GET_PENDING_OPERATION_STRING "/jobs/get" + +/** + * @brief The length of #JOBS_GET_PENDING_OPERATION_STRING. + */ +#define JOBS_GET_PENDING_OPERATION_STRING_LENGTH ( ( uint16_t ) ( sizeof( JOBS_GET_PENDING_OPERATION_STRING ) - 1 ) ) + +/** + * @brief The string representing a Jobs START NEXT operation in a Jobs MQTT topic. + */ +#define JOBS_START_NEXT_OPERATION_STRING "/jobs/start-next" + +/** + * @brief The length of #JOBS_START_NEXT_OPERATION_STRING. + */ +#define JOBS_START_NEXT_OPERATION_STRING_LENGTH ( ( uint16_t ) ( sizeof( JOBS_START_NEXT_OPERATION_STRING ) - 1 ) ) + +/** + * @brief The string representing a Jobs DESCRIBE operation in a Jobs MQTT topic. + * + * This string should be placed after a Job ID. + */ +#define JOBS_DESCRIBE_OPERATION_STRING "/get" + +/** + * @brief The length of #JOBS_DESCRIBE_OPERATION_STRING. + */ +#define JOBS_DESCRIBE_OPERATION_STRING_LENGTH ( ( uint16_t ) ( sizeof( JOBS_DESCRIBE_OPERATION_STRING ) - 1 ) ) + +/** + * @brief The string representing a Jobs UPDATE operation in a Jobs MQTT topic. + * + * This string should be placed after a Job ID. + */ +#define JOBS_UPDATE_OPERATION_STRING "/update" + +/** + * @brief The length of #JOBS_UPDATE_OPERATION_STRING. + * + * This length excludes the length of the placeholder %s. + */ +#define JOBS_UPDATE_OPERATION_STRING_LENGTH ( ( uint16_t ) ( sizeof( JOBS_UPDATE_OPERATION_STRING ) - 1 ) ) + +/** + * @brief The string representing the Jobs MQTT topic for receiving notifications + * of pending Jobs. + */ +#define JOBS_NOTIFY_PENDING_CALLBACK_STRING "/jobs/notify" + +/** + * @brief The length of #JOBS_NOTIFY_PENDING_CALLBACK_STRING. + */ +#define JOBS_NOTIFY_PENDING_CALLBACK_STRING_LENGTH ( ( uint16_t ) ( sizeof( JOBS_NOTIFY_PENDING_CALLBACK_STRING ) - 1 ) ) + +/** + * @brief The string representing the Jobs MQTT topic for receiving notifications + * of the next pending Job. + */ +#define JOBS_NOTIFY_NEXT_CALLBACK_STRING "/jobs/notify-next" + +/** + * @brief The length of #JOBS_NOTIFY_NEXT_CALLBACK_STRING. + */ +#define JOBS_NOTIFY_NEXT_CALLBACK_STRING_LENGTH ( ( uint16_t ) ( sizeof( JOBS_NOTIFY_NEXT_CALLBACK_STRING ) - 1 ) ) + +/** + * @brief The maximum length of a Job ID, per AWS IoT Service Limits. + * + * See https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html#job-limits + */ +#define JOBS_MAX_ID_LENGTH ( 64 ) + +/** + * @brief The maximum value of the Jobs step timeout, per AWS IoT Service Limits. + * + * See https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html#job-limits + */ +#define JOBS_MAX_TIMEOUT ( 10080 ) + +/** + * @brief A limit on the maximum length of a Jobs status details, per AWS IoT + * Service Limits. + * + * See https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html#job-limits + * + * This is actually the limit on the length of an entire Jobs document; but the + * status details must also not exceed this length, + */ +#define JOBS_MAX_STATUS_DETAILS_LENGTH ( 32768 ) + +/** + * @brief The length of the longest Jobs topic suffix. + * + * This is the length of the longest Job ID, plus the length of the "UPDATE" + * operation suffix, plus the length of "/jobs/". + */ +#define JOBS_LONGEST_SUFFIX_LENGTH ( JOBS_MAX_ID_LENGTH + JOBS_UPDATE_OPERATION_STRING_LENGTH + 6 ) + +/*------------------------ Jobs internal data types -------------------------*/ + +/** + * @brief Enumerations representing each of the Jobs library's API functions. + */ +typedef enum _jobsOperationType +{ + /* Jobs operations. */ + JOBS_GET_PENDING = 0, /**< @ref jobs_function_getpendingasync */ + JOBS_START_NEXT = 1, /**< @ref jobs_function_startnextasync */ + JOBS_DESCRIBE = 2, /**< @ref jobs_function_describeasync */ + JOBS_UPDATE = 3, /**< @ref jobs_function_updateasync */ + + /* Jobs callbacks. */ + SET_NOTIFY_PENDING_CALLBACK = 4, /**< @ref jobs_function_setnotifypendingcallback */ + SET_NOTIFY_NEXT_CALLBACK = 5 /**< @ref jobs_function_setnotifynextcallback */ +} _jobsOperationType_t; + +/** + * @brief Enumerations representing each of the Jobs callback functions. + */ +typedef enum _jobsCallbackType +{ + NOTIFY_PENDING_CALLBACK = 0, /**< Pending Job notification callback. */ + NOTIFY_NEXT_CALLBACK = 1 /**< Next Job notification callback. */ +} _jobsCallbackType_t; + +/** + * @brief Parameter to #_AwsIotJobs_GenerateJsonRequest. + */ +typedef union _jsonRequestContents +{ + const AwsIotJobsUpdateInfo_t * pUpdateInfo; /**< @brief Valid for #JOBS_START_NEXT and #JOBS_UPDATE. */ + + struct + { + int32_t executionNumber; /**< @brief Execution number. */ + bool includeJobDocument; /**< @brief Whether the response should include the Job document. */ + } describe; /**< @brief Valid for #JOBS_DESCRIBE. */ +} _jsonRequestContents_t; + +/** + * @brief Represents a Jobs subscriptions object. + * + * These structures are stored in a list. + */ +typedef struct _jobsSubscription +{ + IotLink_t link; /**< @brief List link member. */ + + int32_t operationReferences[ JOBS_OPERATION_COUNT ]; /**< @brief Reference counters for Jobs operation topics. */ + int32_t callbackReferences; /**< @brief Reference counter for Jobs callbacks. */ + + /** @brief Jobs callbacks for this Thing. */ + AwsIotJobsCallbackInfo_t callbacks[ JOBS_CALLBACK_COUNT ][ AWS_IOT_JOBS_NOTIFY_CALLBACKS ]; + + /** + * @brief Buffer allocated for removing Jobs topics. + * + * This buffer is pre-allocated to ensure that memory is available when + * unsubscribing. + */ + char * pTopicBuffer; + + size_t thingNameLength; /**< @brief Length of Thing Name. */ + char pThingName[]; /**< @brief Thing Name associated with this subscriptions object. */ +} _jobsSubscription_t; + +/** + * @brief Internal structure representing a single Jobs operation. + * + * A list of these structures keeps track of all in-progress Jobs operations. + */ +typedef struct _jobsOperation +{ + IotLink_t link; /**< @brief List link member. */ + + /* Basic operation information. */ + _jobsOperationType_t type; /**< @brief Operation type. */ + uint32_t flags; /**< @brief Flags passed to operation API function. */ + AwsIotJobsError_t status; /**< @brief Status of operation. */ + + IotMqttConnection_t mqttConnection; /**< @brief MQTT connection associated with this operation. */ + _jobsSubscription_t * pSubscription; /**< @brief Jobs subscriptions object associated with this operation. */ + + /* Jobs request information. */ + const char * pJobsRequest; /**< @brief JSON document to send to the Jobs service. */ + size_t jobsRequestLength; /**< @brief Length of #_jobsOperation_t.pJobsRequest. */ + + const char * pClientToken; /**< @brief Client token sent with request. */ + size_t clientTokenLength; /**< @brief Length of #_jobsOperation_t.pClientToken. */ + + /* Jobs response information. */ + const char * pJobsResponse; /**< @brief Response received from the Jobs service. */ + size_t jobsResponseLength; /**< @brief Length of #_jobsOperation_t.pJobsResponse. */ + + /** + * @brief Function to allocate memory for an incoming Jobs response. + * + * Only used when the flag #AWS_IOT_JOBS_FLAG_WAITABLE is set. + */ + void * ( *mallocResponse )( size_t ); + + /* How to notify of an operation's completion. */ + union + { + IotSemaphore_t waitSemaphore; /**< @brief Semaphore to be used with @ref jobs_function_wait. */ + AwsIotJobsCallbackInfo_t callback; /**< @brief User-provided callback function and parameter. */ + } notify; /**< @brief How to notify of an operation's completion. */ + + size_t jobIdLength; /**< @brief Length of #_jobsOperation_t.pJobId. */ + char pJobId[]; /**< @brief Job ID, saved for DESCRIBE and UPDATE operations. */ +} _jobsOperation_t; + +/* Declarations of names printed in logs. */ +#if LIBRARY_LOG_LEVEL > IOT_LOG_NONE + extern const char * const _pAwsIotJobsOperationNames[]; + extern const char * const _pAwsIotJobsCallbackNames[]; +#endif + +/* Declarations of variables for internal Jobs files. */ +extern uint32_t _AwsIotJobsMqttTimeoutMs; +extern IotListDouble_t _AwsIotJobsPendingOperations; +extern IotListDouble_t _AwsIotJobsSubscriptions; +extern IotMutex_t _AwsIotJobsPendingOperationsMutex; +extern IotMutex_t _AwsIotJobsSubscriptionsMutex; + +/*------------------------ Jobs operation functions -------------------------*/ + +/** + * @brief Create a record for a new in-progress Jobs operation. + * + * @param[in] type The type of Jobs operation for the request. + * @param[in] pRequestInfo Common Jobs request parameters. + * @param[in] pRequestContents Additional values to place in the JSON document, + * depending on `type`. + * @param[in] flags Flags variables passed to a user-facing Jobs function. + * @param[in] pCallbackInfo User-provided callback function and parameter. + * @param[out] pNewOperation Set to point to the new operation on success. + * + * @return #AWS_IOT_JOBS_SUCCESS or #AWS_IOT_JOBS_NO_MEMORY + */ +AwsIotJobsError_t _AwsIotJobs_CreateOperation( _jobsOperationType_t type, + const AwsIotJobsRequestInfo_t * pRequestInfo, + const _jsonRequestContents_t * pRequestContents, + uint32_t flags, + const AwsIotJobsCallbackInfo_t * pCallbackInfo, + _jobsOperation_t ** pNewOperation ); + +/** + * @brief Free resources used to record a Jobs operation. This is called when + * the operation completes. + * + * @param[in] pData The operation which completed. This parameter is of type + * `void*` to match the signature of [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ +void _AwsIotJobs_DestroyOperation( void * pData ); + +/** + * @brief Fill a buffer with a Jobs topic. + * + * @param[in] type One of: GET PENDING, START NEXT, DESCRIBE, or UPDATE. + * @param[in] pRequestInfo Common Jobs request parameters. + * @param[out] pTopicBuffer Address of the buffer for the Jobs topic. If the + * pointer at this address is `NULL`, this function will allocate a new buffer; + * otherwise, it will use the provided buffer. + * @param[out] pOperationTopicLength Length of the Jobs operation topic (excluding + * any suffix) placed in `pTopicBuffer`. + * + * @warning This function does not check the length of `pTopicBuffer`! Any provided + * buffer must be large enough to accommodate the full Jobs topic, plus + * #JOBS_LONGEST_SUFFIX_LENGTH. + * + * @return #AWS_IOT_JOBS_SUCCESS or #AWS_IOT_JOBS_NO_MEMORY. This function + * will not return #AWS_IOT_JOBS_NO_MEMORY when a buffer is provided. + */ +AwsIotJobsError_t _AwsIotJobs_GenerateJobsTopic( _jobsOperationType_t type, + const AwsIotJobsRequestInfo_t * pRequestInfo, + char ** pTopicBuffer, + uint16_t * pOperationTopicLength ); + +/** + * @brief Process a Jobs operation by sending the necessary MQTT packets. + * + * @param[in] pRequestInfo Common Jobs request parameters. + * @param[in] pOperation Operation data to process. + * + * @return #AWS_IOT_JOBS_STATUS_PENDING on success. On error, one of + * #AWS_IOT_JOBS_NO_MEMORY or #AWS_IOT_JOBS_MQTT_ERROR. + */ +AwsIotJobsError_t _AwsIotJobs_ProcessOperation( const AwsIotJobsRequestInfo_t * pRequestInfo, + _jobsOperation_t * pOperation ); + +/*----------------------- Jobs subscription functions -----------------------*/ + +/** + * @brief Find a Jobs subscription object. May create a new subscription object + * and adds it to the subscription list if not found. + * + * @param[in] pThingName Thing Name in the subscription object. + * @param[in] thingNameLength Length of `pThingName`. + * @param[in] createIfNotFound If `true`, attempt to create a new subscription + * object if no match is found. + * + * @return Pointer to a Jobs subscription object, either found or newly + * allocated. Returns `NULL` if no subscription object is found and a new + * subscription object could not be allocated. + * + * @note This function should be called with the subscription list mutex locked. + */ +_jobsSubscription_t * _AwsIotJobs_FindSubscription( const char * pThingName, + size_t thingNameLength, + bool createIfNotFound ); + +/** + * @brief Remove a Jobs subscription object from the subscription list if + * unreferenced. + * + * @param[in] pSubscription Subscription object to check. If this object has no + * active references, it is removed from the subscription list. + * @param[out] pRemovedSubscription Removed subscription object, if any. Optional; + * pass `NULL` to ignore. If not `NULL`, this parameter will be set to the removed + * subscription and that subscription will not be destroyed. + * + * @note This function should be called with the subscription list mutex locked. + */ +void _AwsIotJobs_RemoveSubscription( _jobsSubscription_t * pSubscription, + _jobsSubscription_t ** pRemovedSubscription ); + +/** + * @brief Free resources used for a Jobs subscription object. + * + * @param[in] pData The subscription object to destroy. This parameter is of type + * `void*` to match the signature of [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ +void _AwsIotJobs_DestroySubscription( void * pData ); + +/** + * @brief Increment the reference count of a Jobs subscriptions object. + * + * Also adds MQTT subscriptions if necessary. + * + * @param[in] pOperation The operation for which the reference count should be + * incremented. + * @param[in] pTopicBuffer Topic buffer containing the operation topic, used if + * subscriptions need to be added. + * @param[in] operationTopicLength The length of the operation topic in `pTopicBuffer`. + * @param[in] callback MQTT callback function for when this operation completes. + * + * @warning This function does not check the length of `pTopicBuffer`! Any provided + * buffer must already contain the Jobs operation topic, plus enough space for the + * status suffix. + * + * @return #AWS_IOT_JOBS_SUCCESS on success. On error, one of + * #AWS_IOT_JOBS_NO_MEMORY or #AWS_IOT_JOBS_MQTT_ERROR. + * + * @note This function should be called with the subscription list mutex locked. + */ +AwsIotJobsError_t _AwsIotJobs_IncrementReferences( _jobsOperation_t * pOperation, + char * pTopicBuffer, + uint16_t operationTopicLength, + AwsIotMqttCallbackFunction_t callback ); + +/** + * @brief Decrement the reference count of a Jobs subscriptions object. + * + * Also removed MQTT subscriptions and deletes the subscription object if necessary. + * + * @param[in] pOperation The operation for which the reference count should be + * decremented. + * @param[in] pTopicBuffer Topic buffer containing the operation topic, used if + * subscriptions need to be removed. + * @param[out] pRemovedSubscription Set to point to a removed subscription. + * Optional; pass `NULL` to ignore. If not `NULL`, this function will not destroy + * a removed subscription. + * + * @warning This function does not check the length of `pTopicBuffer`! Any provided + * buffer must be large enough to accommodate the full Jobs topic, plus + * #JOBS_LONGEST_SUFFIX_LENGTH. + * + * @note This function should be called with the subscription list mutex locked. + */ +void _AwsIotJobs_DecrementReferences( _jobsOperation_t * pOperation, + char * pTopicBuffer, + _jobsSubscription_t ** pRemovedSubscription ); + +/*------------------------ Jobs serializer functions ------------------------*/ + +/** + * @brief Generates a Jobs JSON request document from an #AwsIotJobsRequestInfo_t + * and an #AwsIotJobsUpdateInfo_t. + * + * @param[in] type The type of Jobs operation for the request. + * @param[in] pRequestInfo Common Jobs request parameters. + * @param[in] pRequestContents Additional values to place in the JSON document, + * depending on `type`. + * @param[in] pOperation Operation associated with the Jobs request. + * + * @return #AWS_IOT_JOBS_SUCCESS on success; otherwise, #AWS_IOT_JOBS_NO_MEMORY. + */ +AwsIotJobsError_t _AwsIotJobs_GenerateJsonRequest( _jobsOperationType_t type, + const AwsIotJobsRequestInfo_t * pRequestInfo, + const _jsonRequestContents_t * pRequestContents, + _jobsOperation_t * pOperation ); + +/** + * @brief Parse a response received from the Jobs service. + * + * @param[in] status Either ACCEPTED or REJECTED. + * @param[in] pResponse The response received from the Jobs service. + * @param[in] responseLength Length of `pResponse`. + * @param[out] pOperation Associated Jobs operation, where parse results are + * written. + */ +void _AwsIotJobs_ParseResponse( AwsIotStatus_t status, + const char * pResponse, + size_t responseLength, + _jobsOperation_t * pOperation ); + +#endif /* ifndef AWS_IOT_JOBS_INTERNAL_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/AWS_IoT_Shadow.url b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/AWS_IoT_Shadow.url new file mode 100644 index 000000000..5fde7f5de --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/AWS_IoT_Shadow.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.freertos.org/shadow diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/include/aws_iot_shadow.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/include/aws_iot_shadow.h new file mode 100644 index 000000000..3c12ee7a1 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/include/aws_iot_shadow.h @@ -0,0 +1,909 @@ +/* + * AWS IoT Shadow V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_shadow.h + * @brief User-facing functions of the Shadow library. + */ + +#ifndef AWS_IOT_SHADOW_H_ +#define AWS_IOT_SHADOW_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Shadow types include. */ +#include "types/aws_iot_shadow_types.h" + +/*------------------------ Shadow library functions -------------------------*/ + +/** + * @functionspage{shadow,Shadow library} + * - @functionname{shadow_function_init} + * - @functionname{shadow_function_cleanup} + * - @functionname{shadow_function_deleteasync} + * - @functionname{shadow_function_deletesync} + * - @functionname{shadow_function_getasync} + * - @functionname{shadow_function_getsync} + * - @functionname{shadow_function_updateasync} + * - @functionname{shadow_function_updatesync} + * - @functionname{shadow_function_wait} + * - @functionname{shadow_function_setdeltacallback} + * - @functionname{shadow_function_setupdatedcallback} + * - @functionname{shadow_function_removepersistentsubscriptions} + * - @functionname{shadow_function_strerror} + */ + +/** + * @functionpage{AwsIotShadow_Init,shadow,init} + * @functionpage{AwsIotShadow_Cleanup,shadow,cleanup} + * @functionpage{AwsIotShadow_DeleteAsync,shadow,deleteasync} + * @functionpage{AwsIotShadow_DeleteSync,shadow,deletesync} + * @functionpage{AwsIotShadow_GetAsync,shadow,getasync} + * @functionpage{AwsIotShadow_GetSync,shadow,getsync} + * @functionpage{AwsIotShadow_UpdateAsync,shadow,updateasync} + * @functionpage{AwsIotShadow_UpdateSync,shadow,updatesync} + * @functionpage{AwsIotShadow_Wait,shadow,wait} + * @functionpage{AwsIotShadow_SetDeltaCallback,shadow,setdeltacallback} + * @functionpage{AwsIotShadow_SetUpdatedCallback,shadow,setupdatedcallback} + * @functionpage{AwsIotShadow_RemovePersistentSubscriptions,shadow,removepersistentsubscriptions} + * @functionpage{AwsIotShadow_strerror,shadow,strerror} + */ + +/** + * @brief One-time initialization function for the Shadow library. + * + * This function performs internal setup of the Shadow library. It must be + * called once (and only once) before calling any other Shadow function. + * Calling this function more than once without first calling @ref + * shadow_function_cleanup may result in a crash. + * + * @param[in] mqttTimeout The amount of time (in milliseconds) that the Shadow + * library will wait for MQTT operations. Optional; set this to `0` to use + * @ref AWS_IOT_SHADOW_DEFAULT_MQTT_TIMEOUT_MS. + * + * @return One of the following: + * - #AWS_IOT_SHADOW_SUCCESS + * - #AWS_IOT_SHADOW_INIT_FAILED + * + * @warning No thread-safety guarantees are provided for this function. + * + * @see @ref shadow_function_cleanup + */ +/* @[declare_shadow_init] */ +AwsIotShadowError_t AwsIotShadow_Init( uint32_t mqttTimeout ); +/* @[declare_shadow_init] */ + +/** + * @brief One-time deinitialization function for the Shadow library. + * + * This function frees resources taken in @ref shadow_function_init and deletes + * any [persistent subscriptions.](@ref AWS_IOT_SHADOW_FLAG_KEEP_SUBSCRIPTIONS) + * It should be called to clean up the Shadow library. After this function returns, + * @ref shadow_function_init must be called again before calling any other Shadow + * function. + * + * @warning No thread-safety guarantees are provided for this function. + * + * @see @ref shadow_function_init + */ +/* @[declare_shadow_cleanup] */ +void AwsIotShadow_Cleanup( void ); +/* @[declare_shadow_cleanup] */ + +/** + * @brief Delete a Thing Shadow and receive an asynchronous notification when + * the Delete completes. + * + * This function deletes any existing Shadow document for the given Thing Name. + * If the given Thing has no Shadow and this function is called, the result will + * be #AWS_IOT_SHADOW_NOT_FOUND. + * + * Deleting a Shadow involves sending an MQTT message to AWS IoT and waiting on + * a response. This message will always be sent at [MQTT QoS 0](@ref #IOT_MQTT_QOS_0). + * + * @param[in] mqttConnection The MQTT connection to use for Shadow delete. + * @param[in] pThingName The Thing Name associated with the Shadow to delete. + * @param[in] thingNameLength The length of `pThingName`. + * @param[in] flags Flags which modify the behavior of this function. See @ref shadow_constants_flags. + * @param[in] pCallbackInfo Asynchronous notification of this function's completion. + * @param[out] pDeleteOperation Set to a handle by which this operation may be referenced + * after this function returns. This reference is invalidated once the Shadow delete + * completes. + * + * @return This function will return #AWS_IOT_SHADOW_STATUS_PENDING upon successfully + * queuing a Shadow delete. + * @return If this function fails before queuing a Shadow delete, it will return one of: + * - #AWS_IOT_SHADOW_NOT_INITIALIZED + * - #AWS_IOT_SHADOW_BAD_PARAMETER + * - #AWS_IOT_SHADOW_NO_MEMORY + * @return Upon successful completion of the Shadow delete (either through an #AwsIotShadowCallbackInfo_t + * or #AwsIotShadow_Wait), the status will be #AWS_IOT_SHADOW_SUCCESS. + * @return Should the Shadow delete fail, the status will be one of: + * - #AWS_IOT_SHADOW_MQTT_ERROR + * - #AWS_IOT_SHADOW_BAD_RESPONSE + * - A Shadow service rejection reason between 400 (#AWS_IOT_SHADOW_BAD_REQUEST) + * and 500 (#AWS_IOT_SHADOW_SERVER_ERROR) + * + * @see @ref shadow_function_deletesync for a blocking variant of this function. + * + * Example + * @code{c} + * #define THING_NAME "Test_device" + * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1 ) + * + * // Shadow operation handle. + * AwsIotShadowOperation_t deleteOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; + * + * // Queue a Shadow delete. + * AwsIotShadowError_t deleteResult = AwsIotShadow_DeleteAsync( mqttConnection, + * THING_NAME, + * THING_NAME_LENGTH, + * AWS_IOT_SHADOW_FLAG_WAITABLE, + * NULL, + * &deleteOperation ); + * + * // Shadow delete should return AWS_IOT_SHADOW_STATUS_PENDING upon success. + * if( deleteResult == AWS_IOT_SHADOW_STATUS_PENDING ) + * { + * // Wait for the Shadow delete to complete. + * deleteResult = AwsIotShadow_Wait( deleteOperation, 5000 ); + * + * // Delete result should be AWS_IOT_SHADOW_SUCCESS upon successfully + * // deleting an existing Shadow. + * } + * @endcode + */ +/* @[declare_shadow_deleteasync] */ +AwsIotShadowError_t AwsIotShadow_DeleteAsync( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + uint32_t flags, + const AwsIotShadowCallbackInfo_t * pCallbackInfo, + AwsIotShadowOperation_t * const pDeleteOperation ); +/* @[declare_shadow_deleteasync] */ + +/** + * @brief Delete a Thing Shadow with a timeout. + * + * This function queues a Shadow delete, then waits for the result. Internally, this + * function is a call to @ref shadow_function_deleteasync followed by @ref shadow_function_wait. + * See @ref shadow_function_deleteasync for more information on the Shadow delete operation. + * + * @param[in] mqttConnection The MQTT connection to use for Shadow delete. + * @param[in] pThingName The Thing Name associated with the Shadow to delete. + * @param[in] thingNameLength The length of `pThingName`. + * @param[in] flags Flags which modify the behavior of this function. See @ref shadow_constants_flags. + * @param[in] timeoutMs If the Shadow service does not respond to the Shadow delete + * within this timeout, this function returns #AWS_IOT_SHADOW_TIMEOUT. + * + * @return One of the following: + * - #AWS_IOT_SHADOW_SUCCESS + * - #AWS_IOT_SHADOW_NOT_INITIALIZED + * - #AWS_IOT_SHADOW_BAD_PARAMETER + * - #AWS_IOT_SHADOW_NO_MEMORY + * - #AWS_IOT_SHADOW_MQTT_ERROR + * - #AWS_IOT_SHADOW_BAD_RESPONSE + * - #AWS_IOT_SHADOW_TIMEOUT + * - A Shadow service rejection reason between 400 (#AWS_IOT_SHADOW_BAD_REQUEST) + * and 500 (#AWS_IOT_SHADOW_SERVER_ERROR) + */ +/* @[declare_shadow_deletesync] */ +AwsIotShadowError_t AwsIotShadow_DeleteSync( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + uint32_t flags, + uint32_t timeoutMs ); +/* @[declare_shadow_deletesync] */ + +/** + * @brief Retrieve a Thing Shadow and receive an asynchronous notification when + * the Shadow document is received. + * + * This function retrieves the Thing Shadow document currently stored by the + * Shadow service. If a given Thing has no Shadow and this function is called, + * the result will be #AWS_IOT_SHADOW_NOT_FOUND. + * + * Shadow documents may be large, and their size is not known beforehand. + * Therefore, this function works best when memory is dynamically allocated. + * Because the Shadow document is retrieved in an MQTT PUBLISH packet, the MQTT + * library will allocate a buffer for the Shadow document using #IotMqtt_MallocMessage. + * + * The MQTT library may free the buffer for a retrieved Shadow document as soon + * as the [Shadow completion callback](@ref AwsIotShadowCallbackInfo_t) returns. + * Therefore, any data needed later must be copied from the Shadow document. + * Similarly, if the flag #AWS_IOT_SHADOW_FLAG_WAITABLE is given to this function + * (which indicates that the Shadow document will be needed after the Shadow + * operation completes), #AwsIotShadowDocumentInfo_t.mallocDocument must be + * provided to allocate a longer-lasting buffer. + * + * @note Because of the potentially large size of complete Shadow documents, it is more + * memory-efficient for most applications to use [delta callbacks] + * (@ref shadow_function_setdeltacallback) to retrieve Shadows from + * the Shadow service. + * + * @param[in] mqttConnection The MQTT connection to use for Shadow get. + * @param[in] pGetInfo Shadow document parameters. + * @param[in] flags Flags which modify the behavior of this function. See @ref shadow_constants_flags. + * @param[in] pCallbackInfo Asynchronous notification of this function's completion. + * @param[out] pGetOperation Set to a handle by which this operation may be referenced + * after this function returns. This reference is invalidated once the Shadow get + * completes. + * + * @return This function will return #AWS_IOT_SHADOW_STATUS_PENDING upon successfully + * queuing a Shadow get. + * @return If this function fails before queuing a Shadow get, it will return one of: + * - #AWS_IOT_SHADOW_NOT_INITIALIZED + * - #AWS_IOT_SHADOW_BAD_PARAMETER + * - #AWS_IOT_SHADOW_NO_MEMORY + * @return Upon successful completion of the Shadow get (either through an #AwsIotShadowCallbackInfo_t + * or #AwsIotShadow_Wait), the status will be #AWS_IOT_SHADOW_SUCCESS. + * @return Should the Shadow get fail, the status will be one of: + * - #AWS_IOT_SHADOW_NO_MEMORY (Memory could not be allocated for incoming document) + * - #AWS_IOT_SHADOW_MQTT_ERROR + * - #AWS_IOT_SHADOW_BAD_RESPONSE + * - A Shadow service rejection reason between 400 (#AWS_IOT_SHADOW_BAD_REQUEST) + * and 500 (#AWS_IOT_SHADOW_SERVER_ERROR) + * + * @see @ref shadow_function_getsync for a blocking variant of this function. + * + * Example + * @code{c} + * // Shadow get completion callback. The retrieved document will be in + * // pCallbackParam. Any data in the retrieved document needed after this + * // function returns must be copied. + * void _processRetrievedDocument( void * pCallbackContext, + * AwsIotShadowCallbackParam_t * pCallbackParam ); + * + * // Parameters and return value of Shadow get. + * AwsIotShadowError_t result = AWS_IOT_SHADOW_STATUS_PENDING; + * AwsIotShadowDocumentInfo_t getInfo = { ... }; + * uint32_t timeout = 5000; // 5 seconds + * + * // Callback for get completion. + * AwsIotShadowCallbackInfo_t getCallback = AWS_IOT_SHADOW_CALLBACK_INFO_INITIALIZER; + * getCallback.function = _processRetrievedDocument; + * + * // Shadow get operation. + * result = AwsIotShadow_GetAsync( mqttConnection, + * &getInfo, + * 0, + * &getCallback, + * NULL ); + * + * // Get should have returned AWS_IOT_SHADOW_STATUS_PENDING. The function + * // _processRetrievedDocument will be invoked once the Shadow get completes. + * @endcode + * + * See @ref shadow_function_wait Example 2 for an example of using this + * function with #AWS_IOT_SHADOW_FLAG_WAITABLE and @ref shadow_function_wait. + */ +/* @[declare_shadow_getasync] */ +AwsIotShadowError_t AwsIotShadow_GetAsync( IotMqttConnection_t mqttConnection, + const AwsIotShadowDocumentInfo_t * pGetInfo, + uint32_t flags, + const AwsIotShadowCallbackInfo_t * pCallbackInfo, + AwsIotShadowOperation_t * const pGetOperation ); +/* @[declare_shadow_getasync] */ + +/** + * @brief Retrieve a Thing Shadow with a timeout. + * + * This function queues a Shadow get, then waits for the result. Internally, this + * function is a call to @ref shadow_function_getasync followed by @ref shadow_function_wait. + * See @ref shadow_function_getasync for more information on the Shadow get operation. + * + * @param[in] mqttConnection The MQTT connection to use for Shadow get. + * @param[in] pGetInfo Shadow document parameters. + * @param[in] flags Flags which modify the behavior of this function. See @ref shadow_constants_flags. + * @param[in] timeoutMs If the Shadow service does not respond to the Shadow get + * within this timeout, this function returns #AWS_IOT_SHADOW_TIMEOUT. + * @param[out] pShadowDocument A pointer to a buffer containing the Shadow document + * retrieved by a Shadow get is placed here. The buffer was allocated with the function + * `pGetInfo->get.mallocDocument`. This output parameter is only valid if this function + * returns #AWS_IOT_SHADOW_SUCCESS. + * @param[out] pShadowDocumentLength The length of the Shadow document in + * `pShadowDocument` is placed here. This output parameter is only valid if this function + * returns #AWS_IOT_SHADOW_SUCCESS. + * + * @return One of the following: + * - #AWS_IOT_SHADOW_SUCCESS + * - #AWS_IOT_SHADOW_NOT_INITIALIZED + * - #AWS_IOT_SHADOW_BAD_PARAMETER + * - #AWS_IOT_SHADOW_NO_MEMORY + * - #AWS_IOT_SHADOW_MQTT_ERROR + * - #AWS_IOT_SHADOW_BAD_RESPONSE + * - #AWS_IOT_SHADOW_TIMEOUT + * - A Shadow service rejection reason between 400 (#AWS_IOT_SHADOW_BAD_REQUEST) + * and 500 (#AWS_IOT_SHADOW_SERVER_ERROR) + */ +/* @[declare_shadow_getsync] */ +AwsIotShadowError_t AwsIotShadow_GetSync( IotMqttConnection_t mqttConnection, + const AwsIotShadowDocumentInfo_t * pGetInfo, + uint32_t flags, + uint32_t timeoutMs, + const char ** const pShadowDocument, + size_t * const pShadowDocumentLength ); +/* @[declare_shadow_getsync] */ + +/** + * @brief Send a Thing Shadow update and receive an asynchronous notification when + * the Shadow Update completes. + * + * This function modifies the Thing Shadow document stored by the Shadow service. + * If a given Thing has no Shadow and this function is called, then a new Shadow + * is created. + * + * New JSON keys in the Shadow document will be appended. For example, if the Shadow service + * currently has a document containing key `example1` and this function sends a document + * only containing key `example2`, then the resulting document in the Shadow service + * will contain both `example1` and `example2`. + * + * Existing JSON keys in the Shadow document will be replaced. For example, if the Shadow + * service currently has a document containing `"example1": [0,1,2]` and this function sends + * a document containing key `"example1": [1,2,3]`, then the resulting document in the Shadow + * service will contain `"example1": [1,2,3]`. + * + * Successful Shadow updates will trigger the [Shadow updated callback] + * (@ref shadow_function_setupdatedcallback). If the resulting Shadow document contains + * different `desired` and `reported` keys, then the [Shadow delta callback] + * (@ref shadow_function_setdeltacallback) will be triggered as well. + * + * @attention All documents passed to this function must contain a `clientToken`. + * The [client token] + * (https://docs.aws.amazon.com/iot/latest/developerguide/device-shadow-document.html#client-token) + * is a string used to distinguish between Shadow updates. They are limited to 64 + * characters; attempting to use a client token longer than 64 characters will + * cause the Shadow update to fail. They must be unique at any given time, i.e. + * they may be reused as long as no two Shadow updates are using the same + * client token at the same time. + * + * @param[in] mqttConnection The MQTT connection to use for Shadow update. + * @param[in] pUpdateInfo Shadow document parameters. + * @param[in] flags Flags which modify the behavior of this function. See @ref shadow_constants_flags. + * @param[in] pCallbackInfo Asynchronous notification of this function's completion. + * @param[out] pUpdateOperation Set to a handle by which this operation may be referenced + * after this function returns. This reference is invalidated once the Shadow update + * completes. + * + * @return This function will return #AWS_IOT_SHADOW_STATUS_PENDING upon successfully + * queuing a Shadow update. + * @return If this function fails before queuing a Shadow update, it will return one of: + * - #AWS_IOT_SHADOW_NOT_INITIALIZED + * - #AWS_IOT_SHADOW_BAD_PARAMETER + * - #AWS_IOT_SHADOW_NO_MEMORY + * @return Upon successful completion of the Shadow update (either through an #AwsIotShadowCallbackInfo_t + * or #AwsIotShadow_Wait), the status will be #AWS_IOT_SHADOW_SUCCESS. + * @return Should the Shadow update fail, the status will be one of: + * - #AWS_IOT_SHADOW_MQTT_ERROR + * - #AWS_IOT_SHADOW_BAD_RESPONSE + * - A Shadow service rejection reason between 400 (#AWS_IOT_SHADOW_BAD_REQUEST) + * and 500 (#AWS_IOT_SHADOW_SERVER_ERROR) + * + * @see @ref shadow_function_updatesync for a blocking variant of this function. + * + * Example + * @code{c} + * // Shadow update completion callback. + * void _updateComplete( void * pCallbackContext, + * AwsIotShadowCallbackParam_t * pCallbackParam ); + * + * // Parameters and return value of Shadow update. + * AwsIotShadowError_t result = AWS_IOT_SHADOW_STATUS_PENDING; + * AwsIotShadowDocumentInfo_t updateInfo = { ... }; + * uint32_t timeout = 5000; // 5 seconds + * + * // Set Shadow document to send. + * updateInfo.update.pUpdateDocument = "{...}"; // Must contain clientToken + * updateInfo.update.updateDocumentLength = strlen( updateInfo.update.pUpdateDocument ); + * + * // Callback for update completion. + * AwsIotShadowCallbackInfo_t updateCallback = AWS_IOT_SHADOW_CALLBACK_INFO_INITIALIZER; + * updateCallback.function = _updateComplete; + * + * // Shadow update operation. + * result = AwsIotShadow_UpdateAsync( mqttConnection, + * &updateInfo, + * 0, + * &updateCallback, + * NULL ); + * + * // Update should have returned AWS_IOT_SHADOW_STATUS_PENDING. The function + * // _updateComplete will be invoked once the Shadow update completes. + * @endcode + * + * See @ref shadow_function_wait Example 1 for an example of using this + * function with #AWS_IOT_SHADOW_FLAG_WAITABLE and @ref shadow_function_wait. + */ +/* @[declare_shadow_updateasync] */ +AwsIotShadowError_t AwsIotShadow_UpdateAsync( IotMqttConnection_t mqttConnection, + const AwsIotShadowDocumentInfo_t * pUpdateInfo, + uint32_t flags, + const AwsIotShadowCallbackInfo_t * pCallbackInfo, + AwsIotShadowOperation_t * const pUpdateOperation ); +/* @[declare_shadow_updateasync] */ + +/** + * @brief Send a Thing Shadow update with a timeout. + * + * This function queues a Shadow update, then waits for the result. Internally, this + * function is a call to @ref shadow_function_updateasync followed by @ref shadow_function_wait. + * See @ref shadow_function_updateasync for more information on the Shadow update operation. + * + * @param[in] mqttConnection The MQTT connection to use for Shadow update. + * @param[in] pUpdateInfo Shadow document parameters. + * @param[in] flags Flags which modify the behavior of this function. See @ref shadow_constants_flags. + * @param[in] timeoutMs If the Shadow service does not respond to the Shadow update + * within this timeout, this function returns #AWS_IOT_SHADOW_TIMEOUT. + * + * @return One of the following: + * - #AWS_IOT_SHADOW_SUCCESS + * - #AWS_IOT_SHADOW_NOT_INITIALIZED + * - #AWS_IOT_SHADOW_BAD_PARAMETER + * - #AWS_IOT_SHADOW_NO_MEMORY + * - #AWS_IOT_SHADOW_MQTT_ERROR + * - #AWS_IOT_SHADOW_BAD_RESPONSE + * - #AWS_IOT_SHADOW_TIMEOUT + * - A Shadow service rejection reason between 400 (#AWS_IOT_SHADOW_BAD_REQUEST) + * and 500 (#AWS_IOT_SHADOW_SERVER_ERROR) + */ +/* @[declare_shadow_updatesync] */ +AwsIotShadowError_t AwsIotShadow_UpdateSync( IotMqttConnection_t mqttConnection, + const AwsIotShadowDocumentInfo_t * pUpdateInfo, + uint32_t flags, + uint32_t timeoutMs ); +/* @[declare_shadow_updatesync] */ + +/** + * @brief Wait for a Shadow operation to complete. + * + * This function blocks to wait for a [delete](@ref shadow_function_deleteasync), + * [get](@ref shadow_function_getasync), or [update](@ref shadow_function_updateasync) to + * complete. These operations are by default asynchronous; the function calls + * queue an operation for processing, and a callback is invoked once the operation + * is complete. + * + * To use this function, the flag #AWS_IOT_SHADOW_FLAG_WAITABLE must have been + * set in the operation's function call. Additionally, this function must always + * be called with any waitable operation to clean up resources. + * + * Regardless of its return value, this function always clean up resources used + * by the waitable operation. This means `operation` is invalidated as soon as + * this function returns, even if it returns #AWS_IOT_SHADOW_TIMEOUT or another + * error. + * + * @param[in] operation Reference to the Shadow operation to wait for. The flag + * #AWS_IOT_SHADOW_FLAG_WAITABLE must have been set for this operation. + * @param[in] timeoutMs How long to wait before returning #AWS_IOT_SHADOW_TIMEOUT. + * @param[out] pShadowDocument A pointer to a buffer containing the Shadow document + * retrieved by a [Shadow get](@ref shadow_function_getasync) is placed here. The buffer + * was allocated with the function #AwsIotShadowDocumentInfo_t.mallocDocument passed + * to @ref shadow_function_getasync. This parameter is only valid for a [Shadow get] + * (@ref shadow_function_getasync) and ignored for other Shadow operations. This output + * parameter is only valid if this function returns #AWS_IOT_SHADOW_SUCCESS. + * @param[out] pShadowDocumentLength The length of the Shadow document in + * `pShadowDocument` is placed here. This parameter is only valid for a [Shadow get] + * (@ref shadow_function_getasync) and ignored for other Shadow operations. This output + * parameter is only valid if this function returns #AWS_IOT_SHADOW_SUCCESS. + * + * @return One of the following: + * - #AWS_IOT_SHADOW_SUCCESS + * - #AWS_IOT_SHADOW_NOT_INITIALIZED + * - #AWS_IOT_SHADOW_BAD_PARAMETER + * - #AWS_IOT_SHADOW_BAD_RESPONSE + * - #AWS_IOT_SHADOW_TIMEOUT + * - A Shadow service rejection reason between 400 (#AWS_IOT_SHADOW_BAD_REQUEST) + * and 500 (#AWS_IOT_SHADOW_SERVER_ERROR) + * + * Example 1 (Shadow Update) + * @code{c} + * AwsIotShadowError_t result = AWS_IOT_SHADOW_STATUS_PENDING; + * AwsIotShadowDocumentInfo_t updateInfo = { ... }; + * + * // Reference and timeout. + * AwsIotShadowOperation_t updateOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; + * uint32_t timeout = 5000; // 5 seconds + * + * // Shadow update operation. + * result = AwsIotShadow_UpdateAsync( mqttConnection, + * &updateInfo, + * AWS_IOT_SHADOW_FLAG_WAITABLE, + * NULL, + * &updateOperation ); + * + * // Update should have returned AWS_IOT_SHADOW_STATUS_PENDING. The call to wait + * // returns once the result of the update is available or the timeout expires. + * if( result == AWS_IOT_SHADOW_STATUS_PENDING ) + * { + * // The last two parameters are ignored for a Shadow update. + * result = AwsIotShadow_Wait( updateOperation, timeout, NULL, NULL ); + * + * // After the call to wait, the result of the update is known + * // (not AWS_IOT_SHADOW_STATUS_PENDING). + * assert( result != AWS_IOT_SHADOW_STATUS_PENDING ); + * } + * @endcode + * + * Example 2 (Shadow Get) + * @code{c} + * AwsIotShadowError_t result = AWS_IOT_SHADOW_STATUS_PENDING; + * AwsIotShadowDocumentInfo_t getInfo = { ... }; + * + * // Reference and timeout. + * AwsIotShadowOperation_t getOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; + * uint32_t timeout = 5000; // 5 seconds + * + * // Buffer pointer and size for retrieved Shadow document. + * const char * pShadowDocument = NULL; + * size_t documentLength = 0; + * + * // Buffer allocation function must be set for a waitable Shadow get. + * getInfo.get.mallocDocument = malloc; + * + * // Shadow get operation. + * result = AwsIotShadow_GetAsync( mqttConnection, + * &getInfo, + * AWS_IOT_SHADOW_FLAG_WAITABLE, + * NULL, + * &getOperation ); + * + * // Get should have returned AWS_IOT_SHADOW_STATUS_PENDING. The call to wait + * // returns once the result of the get is available or the timeout expires. + * if( result == AWS_IOT_SHADOW_STATUS_PENDING ) + * { + * // The last two parameters must be set for a Shadow get. + * result = AwsIotShadow_Wait( getOperation, timeout, &pShadowDocument, &documentLength ); + * + * // After the call to wait, the result of the get is known + * // (not AWS_IOT_SHADOW_STATUS_PENDING). + * assert( result != AWS_IOT_SHADOW_STATUS_PENDING ); + * + * // The retrieved Shadow document is only valid for a successful Shadow get. + * if( result == AWS_IOT_SHADOW_SUCCESS ) + * { + * // Do something with the Shadow document... + * + * // Free the Shadow document when finished. + * free( pShadowDocument ); + * } + * } + * @endcode + */ +/* @[declare_shadow_wait] */ +AwsIotShadowError_t AwsIotShadow_Wait( AwsIotShadowOperation_t operation, + uint32_t timeoutMs, + const char ** const pShadowDocument, + size_t * const pShadowDocumentLength ); +/* @[declare_shadow_wait] */ + +/** + * @brief Set a callback to be invoked when the Thing Shadow `desired` and `reported` + * states differ. + * + * A Thing Shadow contains `reported` and `desired` states, meant to represent + * the current device status and some desired status, respectively. When the + * `reported` and `desired` states differ, the Thing Shadow service generates a + * delta document and publishes it to the topic `update/delta`. Devices + * with a subscription for this topic will receive the delta document and may act + * based on the different `reported` and `desired` states. See [this page] + * (https://docs.aws.amazon.com/iot/latest/developerguide/using-device-shadows.html#delta-state) + * for more information about using delta documents. + * + * A delta callback may be invoked whenever a delta document is generated. + * Each Thing may have a single delta callback set. This function modifies the delta + * callback for a specific Thing depending on the `pDeltaCallback` parameter and + * the presence of any existing delta callback: + * - When no existing delta callback exists for a specific Thing, a new delta + * callback is added. + * - If there is an existing delta callback and `pDeltaCallback` is not `NULL`, then + * the existing callback function and parameter are replaced with `pDeltaCallback`. + * - If there is an existing subscription and `pDeltaCallback` is `NULL`, then the + * delta callback is removed. + * + * This function is always blocking; it may block for up to the default MQTT + * timeout. This timeout is set as a parameter to @ref shadow_function_init, + * and defaults to @ref AWS_IOT_SHADOW_DEFAULT_MQTT_TIMEOUT_MS if not set. If + * this function's underlying MQTT operations fail to complete within this + * timeout, then this function returns #AWS_IOT_SHADOW_TIMEOUT. + * + * @param[in] mqttConnection The MQTT connection to use for the subscription to + * `update/delta`. + * @param[in] pThingName The subscription to `update/delta` will be added for + * this Thing Name. + * @param[in] thingNameLength The length of `pThingName`. + * @param[in] flags This parameter is for future-compatibility. Currently, flags + * are not supported for this function and this parameter is ignored. + * @param[in] pDeltaCallback Callback function to invoke for incoming delta + * documents. + * + * @return One of the following: + * - #AWS_IOT_SHADOW_SUCCESS + * - #AWS_IOT_SHADOW_NOT_INITIALIZED + * - #AWS_IOT_SHADOW_BAD_PARAMETER + * - #AWS_IOT_SHADOW_NO_MEMORY + * - #AWS_IOT_SHADOW_MQTT_ERROR + * - #AWS_IOT_SHADOW_TIMEOUT + * + * @return This function always returns #AWS_IOT_SHADOW_SUCCESS when replacing or + * removing existing delta callbacks. + * + * @see @ref shadow_function_setupdatedcallback for the function to register + * callbacks for all Shadow updates. + * + * Example + * @code{c} + * #define THING_NAME "Test_device" + * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1 ) + * + * AwsIotShadowError_t result = AWS_IOT_SHADOW_STATUS_PENDING; + * AwsIotShadowCallbackInfo_t deltaCallback = AWS_IOT_SHADOW_CALLBACK_INFO_INITIALIZER; + * + * // _deltaCallbackFunction will be invoked when a delta document is received. + * deltaCallback.function = _deltaCallbackFunction; + * + * // Set the delta callback for the Thing "Test_device". + * result = AwsIotShadow_SetDeltaCallback( mqttConnection, + * THING_NAME, + * THING_NAME_LENGTH, + * 0, + * &deltaCallback ); + * + * // Check if callback was successfully set. + * if( result == AWS_IOT_SHADOW_SUCCESS ) + * { + * AwsIotShadowDocumentInfo_t updateInfo = AWS_IOT_SHADOW_DOCUMENT_INFO_INITIALIZER; + * + * // Set the Thing Name for Shadow update. + * updateInfo.pThingName = THING_NAME; + * updateInfo.thingNameLength = THING_NAME_LENGTH; + * + * // Set the Shadow document to send. This document has different "reported" + * // and "desired" states. It represents a scenario where a device is currently + * // off, but is being ordered to turn on. + * updateInfo.update.pUpdateDocument = + * "{" + * "\"state\": {" + * "\"reported\": { \"deviceOn\": false }," + * "\"desired\": { \"deviceOn\": true }" + * "}" + * "}"; + * updateInfo.update.updateDocumentLength = strlen( updateInfo.update.pUpdateDocument ); + * + * // Send the Shadow document with different "reported" and desired states. + * result = AwsIotShadow_UpdateSync( mqttConnection, + * &updateInfo, + * 0, + * 0, + * 5000 ); + * + * // After the update is successfully sent, the function _deltaCallbackFunction + * // will be invoked once the Shadow service generates and sends a delta document. + * // The delta document will contain the different "deviceOn" states, as well as + * // metadata. + * + * // Once the delta callback is no longer needed, it may be removed by passing + * // NULL as pDeltaCallback. + * result = AwsIotShadow_SetDeltaCallback( mqttConnection, + * THING_NAME, + * THING_NAME_LENGTH, + * 0, + * NULL ); + * + * // The return value from removing a delta callback should always be success. + * assert( result == AWS_IOT_SHADOW_SUCCESS ); + * } + * @endcode + */ +/* @[declare_shadow_setdeltacallback] */ +AwsIotShadowError_t AwsIotShadow_SetDeltaCallback( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + uint32_t flags, + const AwsIotShadowCallbackInfo_t * pDeltaCallback ); +/* @[declare_shadow_setdeltacallback] */ + +/** + * @brief Set a callback to be invoked when a Thing Shadow changes. + * + * The Shadow service publishes a state document to the `update/documents` topic + * whenever a Thing Shadow is successfully updated. This document reports the + * complete previous and current Shadow documents in `previous` and `current` + * sections, respectively. Therefore, the `update/documents` topic is useful + * for monitoring Shadow updates. + * + * An updated callback may be invoked whenever a document is published to + * `update/documents`. Each Thing may have a single updated callback set. This function + * modifies the updated callback for a specific Thing depending on the `pUpdatedCallback` + * parameter and the presence of any existing updated callback. + * - When no existing updated callback exists for a specific Thing, a new updated + * callback is added. + * - If there is an existing updated callback and `pUpdatedCallback` is not `NULL`, + * then the existing callback function and parameter are replaced with `pUpdatedCallback`. + * - If there is an existing updated callback and `pUpdatedCallback` is `NULL`, + * then the updated callback is removed. + * + * @param[in] mqttConnection The MQTT connection to use for the subscription to `update/documents`. + * @param[in] pThingName The subscription to `update/documents` will be added for + * this Thing Name. + * @param[in] thingNameLength The length of `pThingName`. + * @param[in] flags This parameter is for future-compatibility. Currently, flags are + * not supported for this function and this parameter is ignored. + * @param[in] pUpdatedCallback Callback function to invoke for incoming updated documents. + * + * @return One of the following: + * - #AWS_IOT_SHADOW_SUCCESS + * - #AWS_IOT_SHADOW_NOT_INITIALIZED + * - #AWS_IOT_SHADOW_BAD_PARAMETER + * - #AWS_IOT_SHADOW_NO_MEMORY + * - #AWS_IOT_SHADOW_MQTT_ERROR + * - #AWS_IOT_SHADOW_TIMEOUT + * + * @note Documents published to `update/documents` will be large, as they contain 2 + * complete Shadow state documents. If an updated callback is used, ensure that the + * device has sufficient memory for incoming documents. + * + * @see @ref shadow_function_setdeltacallback for the function to register callbacks + * for delta documents. + * + * Example + * @code{c} + * #define THING_NAME "Test_device" + * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1 ) + * + * AwsIotShadowError_t result = AWS_IOT_SHADOW_STATUS_PENDING; + * AwsIotShadowCallbackInfo_t updatedCallback = AWS_IOT_SHADOW_CALLBACK_INFO_INITIALIZER; + * + * // _updatedCallbackFunction will be invoked when an updated document is received. + * updatedCallback.function = _updatedCallbackFunction; + * + * // Set the updated callback for the Thing "Test_device". + * result = AwsIotShadow_SetUpdatedCallback( mqttConnection, + * THING_NAME, + * THING_NAME_LENGTH, + * 0, + * &updatedCallback ); + * + * // Check if the callback was successfully set. + * if( result == AWS_IOT_SHADOW_SUCCESS ) + * { + * AwsIotShadowDocumentInfo_t updateInfo = AWS_IOT_SHADOW_DOCUMENT_INFO_INITIALIZER; + * + * // Set the Thing Name for Shadow update. + * updateInfo.pThingName = THING_NAME; + * updateInfo.thingNameLength = THING_NAME_LENGTH; + * + * // Set the Shadow document to send. Any Shadow update will trigger the + * // updated callback. + * updateInfo.update.pUpdateDocument = + * "{" + * "\"state\": {" + * "\"reported\": { \"deviceOn\": false }" + * "}" + * "}"; + * updateInfo.update.updateDocumentLength = strlen( updateInfo.update.pUpdateDocument ); + * + * // Send the Shadow document. A successful update will trigger the updated callback. + * result = AwsIotShadow_UpdateSync( mqttConnection, + * &updateInfo, + * 0, + * 0, + * 5000 ); + * + * // After a successful Shadow update, the updated callback will be invoked. + * + * // Once the updated callback is no longer needed, it may be removed by + * // passing NULL as pUpdatedCallback. + * result = AwsIotShadow_SetUpdatedCallback( mqttConnection, + * THING_NAME, + * THING_NAME_LENGTH, + * NULL ); + * + * // The return value from removing an updated callback should always be + * // success. + * assert( result == AWS_IOT_SHADOW_SUCCESS ); + * } + * @endcode + */ +/* @[declare_shadow_setupdatedcallback] */ +AwsIotShadowError_t AwsIotShadow_SetUpdatedCallback( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + uint32_t flags, + const AwsIotShadowCallbackInfo_t * pUpdatedCallback ); +/* @[declare_shadow_setupdatedcallback] */ + +/** + * @brief Remove persistent Thing Shadow operation topic subscriptions. + * + * Passing the flag @ref AWS_IOT_SHADOW_FLAG_KEEP_SUBSCRIPTIONS to @ref shadow_function_deleteasync, + * @ref shadow_function_getasync, @ref shadow_function_updateasync, or their blocking versions. + * causes the Shadow operation topic subscriptions to be maintained for future calls to the + * same function. If a persistent subscription for a Shadow topic are no longer needed, + * this function may be used to remove it. + * + * @param[in] mqttConnection The MQTT connection associated with the persistent subscription. + * @param[in] pThingName The Thing Name associated with the persistent subscription. + * @param[in] thingNameLength The length of `pThingName`. + * @param[in] flags Flags that determine which subscriptions to remove. Valid values are + * the bitwise OR of the following individual flags: + * - @ref AWS_IOT_SHADOW_FLAG_REMOVE_DELETE_SUBSCRIPTIONS + * - @ref AWS_IOT_SHADOW_FLAG_REMOVE_GET_SUBSCRIPTIONS + * - @ref AWS_IOT_SHADOW_FLAG_REMOVE_UPDATE_SUBSCRIPTIONS + * + * @return On success: + * - #AWS_IOT_SHADOW_SUCCESS + * @return If an MQTT UNSUBSCRIBE packet cannot be sent, one of the following: + * - #AWS_IOT_SHADOW_NO_MEMORY + * - #AWS_IOT_SHADOW_MQTT_ERROR + * + * @note @ref shadow_function_cleanup removes all persistent subscriptions as well. + * + * @warning This function is not safe to call with any in-progress operations! + * It also does not affect delta and updated callbacks registered with @ref + * shadow_function_setdeltacallback and @ref shadow_function_setupdatedcallback, + * respectively. (See documentation for those functions on how to remove their + * callbacks). + */ +/* @[declare_shadow_removepersistentsubscriptions] */ +AwsIotShadowError_t AwsIotShadow_RemovePersistentSubscriptions( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + uint32_t flags ); +/* @[declare_shadow_removepersistentsubscriptions] */ + +/*------------------------- Shadow helper functions -------------------------*/ + +/** + * @brief Returns a string that describes an #AwsIotShadowError_t. + * + * Like POSIX's `strerror`, this function returns a string describing a return + * code. In this case, the return code is a Shadow library error code, `status`. + * + * The string returned by this function MUST be treated as read-only: any + * attempt to modify its contents may result in a crash. Therefore, this function + * is limited to usage in logging. + * + * @param[in] status The status to describe. + * + * @return A read-only string that describes `status`. + * + * @warning The string returned by this function must never be modified. + */ +/* @[declare_shadow_strerror] */ +const char * AwsIotShadow_strerror( AwsIotShadowError_t status ); +/* @[declare_shadow_strerror] */ + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * Backwards compatibility macros for previous function names. + */ +#define AwsIotShadow_Delete AwsIotShadow_DeleteAsync +#define AwsIotShadow_TimedDelete AwsIotShadow_DeleteSync +#define AwsIotShadow_Get AwsIotShadow_GetAsync +#define AwsIotShadow_TimedGet AwsIotShadow_GetSync +#define AwsIotShadow_Update AwsIotShadow_UpdateAsync +#define AwsIotShadow_TimedUpdate AwsIotShadow_UpdateSync +/** @endcond */ + +#endif /* ifndef AWS_IOT_SHADOW_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/include/types/aws_iot_shadow_types.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/include/types/aws_iot_shadow_types.h new file mode 100644 index 000000000..8faca8bf6 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/include/types/aws_iot_shadow_types.h @@ -0,0 +1,641 @@ +/* + * AWS IoT Shadow V2.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_shadow_types.h + * @brief Types of the Thing Shadow library. + */ + +#ifndef AWS_IOT_SHADOW_TYPES_H_ +#define AWS_IOT_SHADOW_TYPES_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* MQTT types include. */ +#include "types/iot_mqtt_types.h" + +/*--------------------------- Shadow handle types ---------------------------*/ + +/** + * @handles{shadow,Shadow library} + */ + +/** + * @ingroup shadow_datatypes_handles + * @brief Opaque handle that references an in-progress Shadow operation. + * + * Set as an output parameter of @ref shadow_function_deleteasync, @ref shadow_function_getasync, + * and @ref shadow_function_updateasync. These functions send a message to the Shadow + * service requesting a Shadow operation; the result of this operation is unknown + * until the Shadow service sends a response. Therefore, this handle serves as a + * reference to Shadow operations awaiting a response from the Shadow service. + * + * This reference will be valid from the successful return of @ref shadow_function_deleteasync, + * @ref shadow_function_getasync, or @ref shadow_function_updateasync. The reference becomes + * invalid once the [completion callback](@ref AwsIotShadowCallbackInfo_t) is invoked, + * or @ref shadow_function_wait returns. + * + * @initializer{AwsIotShadowOperation_t,AWS_IOT_SHADOW_OPERATION_INITIALIZER} + * + * @see @ref shadow_function_wait and #AWS_IOT_SHADOW_FLAG_WAITABLE for waiting on + * a reference; or #AwsIotShadowCallbackInfo_t and #AwsIotShadowCallbackParam_t for an + * asynchronous notification of completion. + */ +typedef struct _shadowOperation * AwsIotShadowOperation_t; + +/*------------------------- Shadow enumerated types -------------------------*/ + +/** + * @enums{shadow,Shadow library} + */ + +/** + * @ingroup shadow_datatypes_enums + * @brief Return codes of [Shadow functions](@ref shadow_functions). + * + * The function @ref shadow_function_strerror can be used to get a return code's + * description. + * + * The values between 400 (#AWS_IOT_SHADOW_BAD_REQUEST) and 500 + * (#AWS_IOT_SHADOW_SERVER_ERROR) may be returned by the Shadow service when it + * rejects a Shadow operation. See [this page] + * (https://docs.aws.amazon.com/iot/latest/developerguide/device-shadow-error-messages.html) + * for more information. + */ +typedef enum AwsIotShadowError +{ + /** + * @brief Shadow operation completed successfully. + * + * Functions that may return this value: + * - @ref shadow_function_init + * - @ref shadow_function_wait + * - @ref shadow_function_deletesync + * - @ref shadow_function_getsync + * - @ref shadow_function_updatesync + * - @ref shadow_function_setdeltacallback + * - @ref shadow_function_setupdatedcallback + * - @ref shadow_function_removepersistentsubscriptions + * + * Will also be the value of a Shadow operation completion callback's
+ * [AwsIotShadowCallbackParam_t.operation.result](@ref AwsIotShadowCallbackParam_t.result) + * when successful. + */ + AWS_IOT_SHADOW_SUCCESS = 0, + + /** + * @brief Shadow operation queued, awaiting result. + * + * Functions that may return this value: + * - @ref shadow_function_deleteasync + * - @ref shadow_function_getasync + * - @ref shadow_function_updateasync + */ + AWS_IOT_SHADOW_STATUS_PENDING = 1, + + /** + * @brief Initialization failed. + * + * Functions that may return this value: + * - @ref shadow_function_init + */ + AWS_IOT_SHADOW_INIT_FAILED = 2, + + /** + * @brief At least one parameter is invalid. + * + * Functions that may return this value: + * - @ref shadow_function_deleteasync and @ref shadow_function_deletesync + * - @ref shadow_function_getasync and @ref shadow_function_getsync + * - @ref shadow_function_updateasync and @ref shadow_function_updatesync + * - @ref shadow_function_wait + * - @ref shadow_function_setdeltacallback + * - @ref shadow_function_setupdatedcallback + */ + AWS_IOT_SHADOW_BAD_PARAMETER = 3, + + /** + * @brief Shadow operation failed because of memory allocation failure. + * + * Functions that may return this value: + * - @ref shadow_function_deleteasync and @ref shadow_function_deletesync + * - @ref shadow_function_getasync and @ref shadow_function_getsync + * - @ref shadow_function_updateasync and @ref shadow_function_updatesync + * - @ref shadow_function_setdeltacallback + * - @ref shadow_function_setupdatedcallback + */ + AWS_IOT_SHADOW_NO_MEMORY = 4, + + /** + * @brief Shadow operation failed because of failure in MQTT library. + * + * Check the Shadow library logs for the error code returned by the MQTT + * library. + * + * Functions that may return this value: + * - @ref shadow_function_deleteasync and @ref shadow_function_deletesync + * - @ref shadow_function_getasync and @ref shadow_function_getsync + * - @ref shadow_function_updateasync and @ref shadow_function_updatesync + * - @ref shadow_function_setdeltacallback + * - @ref shadow_function_setupdatedcallback + * - @ref shadow_function_removepersistentsubscriptions + */ + AWS_IOT_SHADOW_MQTT_ERROR = 5, + + /** + * @brief Response received from Shadow service not understood. + * + * Functions that may return this value: + * - @ref shadow_function_deletesync + * - @ref shadow_function_getsync + * - @ref shadow_function_updatesync + * - @ref shadow_function_wait + * + * May also be the value of a Shadow operation completion callback's
+ * [AwsIotShadowCallbackParam_t.operation.result](@ref AwsIotShadowCallbackParam_t.result) + */ + AWS_IOT_SHADOW_BAD_RESPONSE = 7, + + /** + * @brief A blocking Shadow operation timed out. + * + * Functions that may return this value: + * - @ref shadow_function_deletesync + * - @ref shadow_function_getsync + * - @ref shadow_function_updatesync + * - @ref shadow_function_wait + * - @ref shadow_function_setdeltacallback + * - @ref shadow_function_setupdatedcallback + */ + AWS_IOT_SHADOW_TIMEOUT = 8, + + /** + * @brief An API function was called before @ref shadow_function_init. + * + * Functions that may return this value: + * - @ref shadow_function_deleteasync and @ref shadow_function_deletesync + * - @ref shadow_function_getasync and @ref shadow_function_getsync + * - @ref shadow_function_updateasync and @ref shadow_function_updatesync + * - @ref shadow_function_wait + * - @ref shadow_function_setdeltacallback + * - @ref shadow_function_setupdatedcallback + */ + AWS_IOT_SHADOW_NOT_INITIALIZED = 11, + + /** + * @brief Shadow operation rejected: Bad request. + * + * Functions that may return this value: + * - @ref shadow_function_deletesync + * - @ref shadow_function_getsync + * - @ref shadow_function_updatesync + * - @ref shadow_function_wait + * + * May also be the value of a Shadow operation completion callback's
+ * [AwsIotShadowCallbackParam_t.operation.result](@ref AwsIotShadowCallbackParam_t.result) + */ + AWS_IOT_SHADOW_BAD_REQUEST = 400, + + /** + * @brief Shadow operation rejected: Unauthorized. + * + * Functions that may return this value: + * - @ref shadow_function_deletesync + * - @ref shadow_function_getsync + * - @ref shadow_function_updatesync + * - @ref shadow_function_wait + * + * May also be the value of a Shadow operation completion callback's
+ * [AwsIotShadowCallbackParam_t.operation.result](@ref AwsIotShadowCallbackParam_t.result) + */ + AWS_IOT_SHADOW_UNAUTHORIZED = 401, + + /** + * @brief Shadow operation rejected: Forbidden. + * + * Functions that may return this value: + * - @ref shadow_function_deletesync + * - @ref shadow_function_getsync + * - @ref shadow_function_updatesync + * - @ref shadow_function_wait + * + * May also be the value of a Shadow operation completion callback's
+ * [AwsIotShadowCallbackParam_t.operation.result](@ref AwsIotShadowCallbackParam_t.result) + */ + AWS_IOT_SHADOW_FORBIDDEN = 403, + + /** + * @brief Shadow operation rejected: Thing not found. + * + * Functions that may return this value: + * - @ref shadow_function_deletesync + * - @ref shadow_function_getsync + * - @ref shadow_function_updatesync + * - @ref shadow_function_wait + * + * May also be the value of a Shadow operation completion callback's
+ * [AwsIotShadowCallbackParam_t.operation.result](@ref AwsIotShadowCallbackParam_t.result) + */ + AWS_IOT_SHADOW_NOT_FOUND = 404, + + /** + * @brief Shadow operation rejected: Version conflict. + * + * Functions that may return this value: + * - @ref shadow_function_deletesync + * - @ref shadow_function_getsync + * - @ref shadow_function_updatesync + * - @ref shadow_function_wait + * + * May also be the value of a Shadow operation completion callback's
+ * [AwsIotShadowCallbackParam_t.operation.result](@ref AwsIotShadowCallbackParam_t.result) + */ + AWS_IOT_SHADOW_CONFLICT = 409, + + /** + * @brief Shadow operation rejected: The payload exceeds the maximum size + * allowed. + * + * Functions that may return this value: + * - @ref shadow_function_deletesync + * - @ref shadow_function_getsync + * - @ref shadow_function_updatesync + * - @ref shadow_function_wait + * + * May also be the value of a Shadow operation completion callback's
+ * [AwsIotShadowCallbackParam_t.operation.result](@ref AwsIotShadowCallbackParam_t.result) + */ + AWS_IOT_SHADOW_TOO_LARGE = 413, + + /** + * @brief Shadow operation rejected: Unsupported document encoding; supported + * encoding is UTF-8. + * + * Functions that may return this value: + * - @ref shadow_function_deletesync + * - @ref shadow_function_getsync + * - @ref shadow_function_updatesync + * - @ref shadow_function_wait + * + * May also be the value of a Shadow operation completion callback's
+ * [AwsIotShadowCallbackParam_t.operation.result](@ref AwsIotShadowCallbackParam_t.result) + */ + AWS_IOT_SHADOW_UNSUPPORTED = 415, + + /** + * @brief Shadow operation rejected: The Device Shadow service will generate + * this error message when there are more than 10 in-flight requests. + * + * Functions that may return this value: + * - @ref shadow_function_deletesync + * - @ref shadow_function_getsync + * - @ref shadow_function_updatesync + * - @ref shadow_function_wait + * + * May also be the value of a Shadow operation completion callback's
+ * [AwsIotShadowCallbackParam_t.operation.result](@ref AwsIotShadowCallbackParam_t.result) + */ + AWS_IOT_SHADOW_TOO_MANY_REQUESTS = 429, + + /** + * @brief Shadow operation rejected: Internal service failure. + * + * Functions that may return this value: + * - @ref shadow_function_deletesync + * - @ref shadow_function_getsync + * - @ref shadow_function_updatesync + * - @ref shadow_function_wait + * + * May also be the value of a Shadow operation completion callback's
+ * [AwsIotShadowCallbackParam_t.operation.result](@ref AwsIotShadowCallbackParam_t.result) + */ + AWS_IOT_SHADOW_SERVER_ERROR = 500, +} AwsIotShadowError_t; + +/** + * @ingroup shadow_datatypes_enums + * @brief Types of Shadow library callbacks. + * + * One of these values will be placed in #AwsIotShadowCallbackParam_t.callbackType + * to identify the reason for invoking a callback function. + */ +typedef enum AwsIotShadowCallbackType +{ + AWS_IOT_SHADOW_DELETE_COMPLETE, /**< Callback invoked because a [Shadow delete](@ref shadow_function_deleteasync) completed. */ + AWS_IOT_SHADOW_GET_COMPLETE, /**< Callback invoked because a [Shadow get](@ref shadow_function_getasync) completed. */ + AWS_IOT_SHADOW_UPDATE_COMPLETE, /**< Callback invoked because a [Shadow update](@ref shadow_function_updateasync) completed. */ + AWS_IOT_SHADOW_DELTA_CALLBACK, /**< Callback invoked for an incoming message on a [Shadow delta](@ref shadow_function_setdeltacallback) topic. */ + AWS_IOT_SHADOW_UPDATED_CALLBACK /**< Callback invoked for an incoming message on a [Shadow updated](@ref shadow_function_setupdatedcallback) topic. */ +} AwsIotShadowCallbackType_t; + +/*------------------------- Shadow parameter structs ------------------------*/ + +/** + * @paramstructs{shadow,Shadow} + */ + +/** + * @ingroup shadow_datatypes_paramstructs + * @brief Parameter to a Shadow callback function. + * + * @paramfor Shadow callback functions + * + * The Shadow library passes this struct to a callback function whenever a + * Shadow operation completes or a message is received on a Shadow delta or + * updated topic. + * + * The valid members of this struct are different based on + * #AwsIotShadowCallbackParam_t.callbackType. If the callback type is + * #AWS_IOT_SHADOW_DELETE_COMPLETE, #AWS_IOT_SHADOW_GET_COMPLETE, or + * #AWS_IOT_SHADOW_UPDATE_COMPLETE, then #AwsIotShadowCallbackParam_t.operation + * is valid. Otherwise, if the callback type is #AWS_IOT_SHADOW_DELTA_CALLBACK + * or #AWS_IOT_SHADOW_UPDATED_CALLBACK, then #AwsIotShadowCallbackParam_t.callback + * is valid. + * + * @attention Any pointers in this callback parameter may be freed as soon as the + * [callback function](@ref AwsIotShadowCallbackInfo_t.function) returns. Therefore, + * data must be copied if it is needed after the callback function returns. + * @attention The Shadow library may set strings that are not NULL-terminated. + * + * @see #AwsIotShadowCallbackInfo_t for the signature of a callback function. + */ +typedef struct AwsIotShadowCallbackParam +{ + AwsIotShadowCallbackType_t callbackType; /**< @brief Reason for invoking the Shadow callback function to provide context. */ + + const char * pThingName; /**< @brief The Thing Name associated with this Shadow callback. */ + size_t thingNameLength; /**< @brief Length of #AwsIotShadowCallbackParam_t.pThingName. */ + + IotMqttConnection_t mqttConnection; /**< @brief The MQTT connection associated with the Shadow callback. */ + + union + { + /* Valid for completed Shadow operations. */ + struct + { + /* Valid for a completed Shadow GET operation. */ + struct + { + const char * pDocument; /**< @brief Retrieved Shadow document. */ + size_t documentLength; /**< @brief Length of retrieved Shadow document. */ + } get; /**< @brief Retrieved Shadow document, valid only for a completed [Shadow Get](@ref shadow_function_getasync). */ + + AwsIotShadowError_t result; /**< @brief Result of Shadow operation, e.g. succeeded or failed. */ + AwsIotShadowOperation_t reference; /**< @brief Reference to the Shadow operation that completed. */ + } operation; /**< @brief Information on a completed Shadow operation. */ + + /* Valid for a message on a Shadow delta or updated topic. */ + struct + { + const char * pDocument; /**< @brief Shadow delta or updated document. */ + size_t documentLength; /**< @brief Length of Shadow delta or updated document. */ + } callback; /**< @brief Shadow document from an incoming delta or updated topic. */ + } u; /**< @brief Valid member depends on callback type. */ +} AwsIotShadowCallbackParam_t; + +/** + * @ingroup shadow_datatypes_paramstructs + * @brief Information on a user-provided Shadow callback function. + * + * @paramfor @ref shadow_function_deleteasync, @ref shadow_function_getasync, @ref + * shadow_function_updateasync, @ref shadow_function_setdeltacallback, @ref + * shadow_function_setupdatedcallback + * + * Provides a function to be invoked when a Shadow operation completes or when a + * Shadow document is received on a callback topic (delta or updated). + * + * @initializer{AwsIotShadowCallbackInfo_t,AWS_IOT_SHADOW_CALLBACK_INFO_INITIALIZER} + */ +typedef struct AwsIotShadowCallbackInfo +{ + void * pCallbackContext; /**< @brief The first parameter to pass to the callback function. */ + + /** + * @brief User-provided callback function signature. + * + * @param[in] pCallbackContext #AwsIotShadowCallbackInfo_t.pCallbackContext + * @param[in] pCallbackParam Details on the outcome of the Shadow + * operation or an incoming Shadow document. + * + * @see #AwsIotShadowCallbackParam_t for more information on the second parameter. + */ + void ( * function )( void * pCallbackContext, + AwsIotShadowCallbackParam_t * pCallbackParam ); +} AwsIotShadowCallbackInfo_t; + +/** + * @ingroup shadow_datatypes_paramstructs + * @brief Information on a Shadow document for @ref shadow_function_getasync or @ref + * shadow_function_updateasync. + * + * @paramfor @ref shadow_function_getasync, @ref shadow_function_updateasync + * + * The valid members of this struct are different based on whether this struct + * is passed to @ref shadow_function_getasync or @ref shadow_function_updateasync. When + * passed to @ref shadow_function_getasync, the `get` member is valid. When passed to + * @ref shadow_function_updateasync, the `update` member is valid. All other members + * must always be set. + * + * @initializer{AwsIotShadowDocumentInfo_t,AWS_IOT_SHADOW_DOCUMENT_INFO_INITIALIZER} + */ +typedef struct AwsIotShadowDocumentInfo +{ + const char * pThingName; /**< @brief The Thing Name associated with this Shadow document. */ + size_t thingNameLength; /**< @brief Length of #AwsIotShadowDocumentInfo_t.pThingName. */ + + IotMqttQos_t qos; /**< @brief QoS when sending a Shadow get or update message. See #IotMqttPublishInfo_t.qos. */ + uint32_t retryLimit; /**< @brief Maximum number of retries for a Shadow get or update message. See #IotMqttPublishInfo_t.retryLimit. */ + uint32_t retryMs; /**< @brief First retry time for a Shadow get or update message. See IotMqttPublishInfo_t.retryMs. */ + + union + { + /* Valid for Shadow get. */ + struct + { + /** + * @brief Function to allocate memory for an incoming Shadow document. + * + * @param[in] documentLength Length of the document that needs to + * be allocated. + * This only needs to be set if #AWS_IOT_SHADOW_FLAG_WAITABLE is passed to + * @ref shadow_function_getasync. + */ + void *( *mallocDocument )( size_t documentLength ); + } get; /**< @brief Valid members for @ref shadow_function_getasync. */ + + /* Valid for Shadow update. */ + struct + { + const char * pUpdateDocument; /**< @brief The Shadow document to send in the update. */ + size_t updateDocumentLength; /**< @brief Length of Shadow update document. */ + } update; /**< @brief Valid members for @ref shadow_function_updateasync. */ + } u; /**< @brief Valid member depends on operation type. */ +} AwsIotShadowDocumentInfo_t; + +/*------------------------ Shadow defined constants -------------------------*/ + +/** + * @constantspage{shadow,Shadow library} + * + * @section shadow_constants_initializers Shadow Initializers + * @brief Provides default values for the data types of the Shadow library. + * + * @snippet this define_shadow_initializers + * + * All user-facing data types of the Shadow library should be initialized + * using one of the following. + * + * @warning Failing to initialize a Shadow data type with the appropriate + * initializer may result in undefined behavior! + * @note The initializers may change at any time in future versions, but their + * names will remain the same. + * + * Example + * @code{c} + * AwsIotShadowCallbackInfo_t callbackInfo = AWS_IOT_SHADOW_CALLBACK_INFO_INITIALIZER; + * AwsIotShadowDocumentInfo_t documentInfo = AWS_IOT_SHADOW_DOCUMENT_INFO_INITIALIZER; + * AwsIotShadowOperation_t operation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; + * @endcode + * + * @section shadow_constants_flags Shadow Function Flags + * @brief Flags that modify the behavior of Shadow library functions. + * + * Flags should be bitwise-ORed with each other to change the behavior of + * Shadow library functions. + * + * The following flags are valid for the Shadow operation functions: + * @ref shadow_function_deleteasync, @ref shadow_function_getasync, @ref shadow_function_updateasync, + * and their blocking versions. + * - #AWS_IOT_SHADOW_FLAG_WAITABLE
+ * @copybrief AWS_IOT_SHADOW_FLAG_WAITABLE + * - #AWS_IOT_SHADOW_FLAG_KEEP_SUBSCRIPTIONS
+ * @copybrief AWS_IOT_SHADOW_FLAG_KEEP_SUBSCRIPTIONS + * + * The following flags are valid for @ref shadow_function_removepersistentsubscriptions. + * These flags are not valid for the Shadow operation functions. + * - #AWS_IOT_SHADOW_FLAG_REMOVE_DELETE_SUBSCRIPTIONS
+ * @copybrief AWS_IOT_SHADOW_FLAG_REMOVE_DELETE_SUBSCRIPTIONS + * - #AWS_IOT_SHADOW_FLAG_REMOVE_GET_SUBSCRIPTIONS
+ * @copybrief AWS_IOT_SHADOW_FLAG_REMOVE_GET_SUBSCRIPTIONS + * - #AWS_IOT_SHADOW_FLAG_REMOVE_UPDATE_SUBSCRIPTIONS
+ * @copybrief AWS_IOT_SHADOW_FLAG_REMOVE_UPDATE_SUBSCRIPTIONS + * + * @note The values of the flags may change at any time in future versions, but + * their names will remain the same. Additionally, flags which may be used at + * the same time will be bitwise-exclusive of each other. + */ + +/* @[define_shadow_initializers] */ +#define AWS_IOT_SHADOW_CALLBACK_INFO_INITIALIZER { 0 } /**< @brief Initializer for #AwsIotShadowCallbackInfo_t. */ +#define AWS_IOT_SHADOW_DOCUMENT_INFO_INITIALIZER { 0 } /**< @brief Initializer for #AwsIotShadowDocumentInfo_t. */ +#define AWS_IOT_SHADOW_OPERATION_INITIALIZER NULL /**< @brief Initializer for #AwsIotShadowOperation_t. */ +/* @[define_shadow_initializers] */ + +/** + * @brief Allows the use of @ref shadow_function_wait for blocking until completion. + * + * This flag is only valid if passed to the functions @ref shadow_function_deleteasync, + * @ref shadow_function_getasync, or @ref shadow_function_updateasync. + * + * An #AwsIotShadowOperation_t MUST be provided if this flag is set. + * Additionally, an #AwsIotShadowCallbackInfo_t MUST NOT be provided. + * + * @note If this flag is set, @ref shadow_function_wait MUST be called to + * clean up resources. + */ +#define AWS_IOT_SHADOW_FLAG_WAITABLE ( 0x00000001 ) + +/** + * @brief Maintain the subscriptions for the Shadow operation topics, even after + * this function returns. + * + * This flag is only valid if passed to the functions @ref shadow_function_deleteasync, + * @ref shadow_function_getasync, @ref shadow_function_updateasync, or their blocking versions. + * + * The Shadow service reports results of Shadow operations by publishing + * messages to MQTT topics. By default, the functions @ref shadow_function_deleteasync, + * @ref shadow_function_getasync, and @ref shadow_function_updateasync subscribe to the + * necessary topics, wait for the Shadow service to publish the result of the + * Shadow operation, then unsubscribe from those topics. This workflow is suitable + * for infrequent Shadow operations, but is inefficient for frequent, periodic + * Shadow operations (where subscriptions for the Shadow operation topics would be + * constantly added and removed). + * + * This flag causes @ref shadow_function_deleteasync, @ref shadow_function_getasync, or + * @ref shadow_function_updateasync to maintain Shadow operation topic subscriptions, + * even after the function returns. These subscriptions may then be used by a + * future call to the same function. + * + * This flags only needs to be set once, after which subscriptions are maintained + * and reused for a specific Thing Name and Shadow function. The function @ref + * shadow_function_removepersistentsubscriptions may be used to remove + * subscriptions maintained by this flag. + */ +#define AWS_IOT_SHADOW_FLAG_KEEP_SUBSCRIPTIONS ( 0x00000002 ) + +/** + * @brief Remove the persistent subscriptions from a Shadow delete operation. + * + * This flag is only valid if passed to the function @ref + * shadow_function_removepersistentsubscriptions. + * + * This flag may be passed to @ref shadow_function_removepersistentsubscriptions + * to remove any subscriptions for a specific Thing Name maintained by a previous + * call to @ref shadow_function_deleteasync or @ref shadow_function_deletesync. + * + * @warning Do not call @ref shadow_function_removepersistentsubscriptions with + * this flag for Thing Names with any in-progress Shadow delete operations. + */ +#define AWS_IOT_SHADOW_FLAG_REMOVE_DELETE_SUBSCRIPTIONS ( 0x00000001 ) + +/** + * @brief Remove the persistent subscriptions from a Shadow get operation. + * + * This flag is only valid if passed to the function @ref + * shadow_function_removepersistentsubscriptions. + * + * This flag may be passed to @ref shadow_function_removepersistentsubscriptions + * to remove any subscriptions for a specific Thing Name maintained by a previous + * call to @ref shadow_function_getasync or @ref shadow_function_getsync. + * + * @warning Do not call @ref shadow_function_removepersistentsubscriptions with + * this flag for Thing Names with any in-progress Shadow get operations. + */ +#define AWS_IOT_SHADOW_FLAG_REMOVE_GET_SUBSCRIPTIONS ( 0x00000002 ) + +/** + * @brief Remove the persistent subscriptions from a Shadow update operation. + * + * This flag is only valid if passed to the function @ref + * shadow_function_removepersistentsubscriptions. + * + * This flag may be passed to @ref shadow_function_removepersistentsubscriptions + * to remove any subscriptions for a specific Thing Name maintained by a previous + * call to @ref shadow_function_updateasync or @ref shadow_function_updatesync. + * + * @warning Do not call @ref shadow_function_removepersistentsubscriptions with + * this flag for Thing Names with any in-progress Shadow update operations. + */ +#define AWS_IOT_SHADOW_FLAG_REMOVE_UPDATE_SUBSCRIPTIONS ( 0x00000004 ) + +#endif /* ifndef AWS_IOT_SHADOW_TYPES_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_api.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_api.c new file mode 100644 index 000000000..b9936bb6d --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_api.c @@ -0,0 +1,1333 @@ +/* + * AWS IoT Shadow V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_shadow_api.c + * @brief Implements the user-facing functions of the Shadow library. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* Shadow internal include. */ +#include "private/aws_iot_shadow_internal.h" + +/* Error handling include. */ +#include "iot_error.h" + +/* Platform layer includes. */ +#include "platform/iot_threads.h" + +/* MQTT include. */ +#include "iot_mqtt.h" + +/* Validate Shadow configuration settings. */ +#if AWS_IOT_SHADOW_ENABLE_ASSERTS != 0 && AWS_IOT_SHADOW_ENABLE_ASSERTS != 1 + #error "AWS_IOT_SHADOW_ENABLE_ASSERTS must be 0 or 1." +#endif +#if AWS_IOT_SHADOW_DEFAULT_MQTT_TIMEOUT_MS <= 0 + #error "AWS_IOT_SHADOW_DEFAULT_MQTT_TIMEOUT_MS cannot be 0 or negative." +#endif + +/*-----------------------------------------------------------*/ + +/** + * @brief Check if the library is initialized. + * + * @return `true` if AwsIotShadow_Init was called; `false` otherwise. + */ +static bool _checkInit( void ); + +/** + * @brief Checks Thing Name and flags parameters passed to Shadow API functions. + * + * @param[in] type The Shadow API function type. + * @param[in] pThingName Thing Name passed to Shadow API function. + * @param[in] thingNameLength Length of `pThingName`. + * @param[in] flags Flags passed to Shadow API function. + * @param[in] pCallbackInfo Callback info passed to Shadow API function. + * @param[in] pOperation Operation reference pointer passed to Shadow API function. + * + * @return #AWS_IOT_SHADOW_SUCCESS or #AWS_IOT_SHADOW_BAD_PARAMETER. + */ +static AwsIotShadowError_t _validateThingNameFlags( _shadowOperationType_t type, + const char * pThingName, + size_t thingNameLength, + uint32_t flags, + const AwsIotShadowCallbackInfo_t * pCallbackInfo, + const AwsIotShadowOperation_t * pOperation ); + +/** + * @brief Checks document info parameter passed to Shadow API functions. + * + * @param[in] type The Shadow API function type. + * @param[in] flags Flags passed to Shadow API function. + * @param[in] pDocumentInfo Document info passed to Shadow API function. + * + * @return #AWS_IOT_SHADOW_SUCCESS or #AWS_IOT_SHADOW_BAD_PARAMETER. + */ +static AwsIotShadowError_t _validateDocumentInfo( _shadowOperationType_t type, + uint32_t flags, + const AwsIotShadowDocumentInfo_t * pDocumentInfo ); + +/** + * @brief Common function for setting Shadow callbacks. + * + * @param[in] mqttConnection The MQTT connection to use. + * @param[in] type Type of Shadow callback. + * @param[in] pThingName Thing Name for Shadow callback. + * @param[in] thingNameLength Length of `pThingName`. + * @param[in] pCallbackInfo Callback information to set. + * + * @return #AWS_IOT_SHADOW_SUCCESS, #AWS_IOT_SHADOW_BAD_PARAMETER, + * #AWS_IOT_SHADOW_NO_MEMORY, or #AWS_IOT_SHADOW_MQTT_ERROR. + */ +static AwsIotShadowError_t _setCallbackCommon( IotMqttConnection_t mqttConnection, + _shadowCallbackType_t type, + const char * pThingName, + size_t thingNameLength, + const AwsIotShadowCallbackInfo_t * pCallbackInfo ); + +/** + * @brief Change the subscriptions for Shadow callbacks, either by subscribing + * or unsubscribing. + * + * @param[in] mqttConnection The MQTT connection to use. + * @param[in] type Type of Shadow callback. + * @param[in] pSubscription Shadow subscriptions object for callback. + * @param[in] mqttOperation Either @ref mqtt_function_subscribesync or + * @ref mqtt_function_unsubscribesync. + * + * @return #AWS_IOT_SHADOW_SUCCESS, #AWS_IOT_SHADOW_NO_MEMORY, or + * #AWS_IOT_SHADOW_MQTT_ERROR. + */ +static AwsIotShadowError_t _modifyCallbackSubscriptions( IotMqttConnection_t mqttConnection, + _shadowCallbackType_t type, + _shadowSubscription_t * pSubscription, + AwsIotMqttFunction_t mqttOperation ); + +/** + * @brief Common function for incoming Shadow callbacks. + * + * @param[in] type Shadow callback type. + * @param[in] pMessage The received Shadow callback document (as an MQTT PUBLISH + * message). + */ +static void _callbackWrapperCommon( _shadowCallbackType_t type, + IotMqttCallbackParam_t * pMessage ); + +/** + * @brief Invoked when a document is received on the Shadow DELTA callback. + * + * @param[in] pArgument Ignored. + * @param[in] pMessage The received DELTA document (as an MQTT PUBLISH message). + */ +static void _deltaCallbackWrapper( void * pArgument, + IotMqttCallbackParam_t * pMessage ); + +/** + * @brief Invoked when a document is received on the Shadow UPDATED callback. + * + * @param[in] pArgument Ignored. + * @param[in] pMessage The received UPDATED document (as an MQTT PUBLISH message). + */ +static void _updatedCallbackWrapper( void * pArgument, + IotMqttCallbackParam_t * pMessage ); + +/*-----------------------------------------------------------*/ + +/** + * @brief Tracks whether @ref shadow_function_init has been called. + * + * API functions will fail if @ref shadow_function_init was not called. + */ +static uint32_t _initCalled = 0; + +/** + * @brief Timeout used for MQTT operations. + */ +uint32_t _AwsIotShadowMqttTimeoutMs = AWS_IOT_SHADOW_DEFAULT_MQTT_TIMEOUT_MS; + +#if LIBRARY_LOG_LEVEL > IOT_LOG_NONE + +/** + * @brief Printable names for the Shadow callbacks. + */ + const char * const _pAwsIotShadowCallbackNames[] = + { + "DELTA", + "UPDATED" + }; +#endif + +/*-----------------------------------------------------------*/ + +static bool _checkInit( void ) +{ + bool status = true; + + if( _initCalled == 0 ) + { + IotLogError( "AwsIotShadow_Init was not called." ); + + status = false; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +static AwsIotShadowError_t _validateThingNameFlags( _shadowOperationType_t type, + const char * pThingName, + size_t thingNameLength, + uint32_t flags, + const AwsIotShadowCallbackInfo_t * pCallbackInfo, + const AwsIotShadowOperation_t * pOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_SUCCESS ); + + /* Type is not used when logging is disabled. */ + ( void ) type; + + /* Check Thing Name. */ + if( AwsIot_ValidateThingName( pThingName, thingNameLength ) == false ) + { + IotLogError( "Thing Name for Shadow %s is not valid.", + _pAwsIotShadowOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); + } + + /* Check the waitable operation flag. */ + if( ( flags & AWS_IOT_SHADOW_FLAG_WAITABLE ) == AWS_IOT_SHADOW_FLAG_WAITABLE ) + { + /* Check that a reference pointer is provided for a waitable operation. */ + if( pOperation == NULL ) + { + IotLogError( "Reference must be set for a waitable Shadow %s.", + _pAwsIotShadowOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); + } + + /* A callback should not be set for a waitable operation. */ + if( pCallbackInfo != NULL ) + { + IotLogError( "Callback should not be set for a waitable Shadow %s.", + _pAwsIotShadowOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); + } + } + + /* A callback info must be passed to a non-waitable GET. */ + if( ( type == SHADOW_GET ) && + ( ( flags & AWS_IOT_SHADOW_FLAG_WAITABLE ) == 0 ) && + ( pCallbackInfo == NULL ) ) + { + IotLogError( "Callback info must be provided for non-waitable Shadow GET." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); + } + + /* Check that a callback function is set. */ + if( ( pCallbackInfo != NULL ) && + ( pCallbackInfo->function == NULL ) ) + { + IotLogError( "Callback function must be set for Shadow %s callback.", + _pAwsIotShadowOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static AwsIotShadowError_t _validateDocumentInfo( _shadowOperationType_t type, + uint32_t flags, + const AwsIotShadowDocumentInfo_t * pDocumentInfo ) +{ + IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_SUCCESS ); + + /* This function should only be called for Shadow GET or UPDATE. */ + AwsIotShadow_Assert( ( type == SHADOW_GET ) || ( type == SHADOW_UPDATE ) ); + + /* Check QoS. */ + if( pDocumentInfo->qos != IOT_MQTT_QOS_0 ) + { + if( pDocumentInfo->qos != IOT_MQTT_QOS_1 ) + { + IotLogError( "QoS for Shadow %d must be 0 or 1.", + _pAwsIotShadowOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); + } + } + + /* Check the retry parameters. */ + if( pDocumentInfo->retryLimit > 0 ) + { + if( pDocumentInfo->retryMs == 0 ) + { + IotLogError( "Retry time of Shadow %s must be positive.", + _pAwsIotShadowOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); + } + } + + /* Check members relevant to a Shadow GET. */ + if( type == SHADOW_GET ) + { + /* Check memory allocation function for waitable GET. */ + if( ( ( flags & AWS_IOT_SHADOW_FLAG_WAITABLE ) == AWS_IOT_SHADOW_FLAG_WAITABLE ) && + ( pDocumentInfo->u.get.mallocDocument == NULL ) ) + { + IotLogError( "Memory allocation function must be set for waitable Shadow GET." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); + } + } + /* Check members relevant to a Shadow UPDATE. */ + else + { + /* Check UPDATE document pointer and length. */ + if( ( pDocumentInfo->u.update.pUpdateDocument == NULL ) || + ( pDocumentInfo->u.update.updateDocumentLength == 0 ) ) + { + IotLogError( "Shadow document for Shadow UPDATE cannot be NULL or" + " have length 0." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); + } + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static AwsIotShadowError_t _setCallbackCommon( IotMqttConnection_t mqttConnection, + _shadowCallbackType_t type, + const char * pThingName, + size_t thingNameLength, + const AwsIotShadowCallbackInfo_t * pCallbackInfo ) +{ + IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_SUCCESS ); + bool subscriptionMutexLocked = false; + _shadowSubscription_t * pSubscription = NULL; + + /* Check that AwsIotShadow_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NOT_INITIALIZED ); + } + + /* Check parameters. */ + status = _validateThingNameFlags( ( _shadowOperationType_t ) ( type + SHADOW_OPERATION_COUNT ), + pThingName, + thingNameLength, + 0, + pCallbackInfo, + NULL ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + + IotLogInfo( "(%.*s) Modifying Shadow %s callback.", + thingNameLength, + pThingName, + _pAwsIotShadowCallbackNames[ type ] ); + + /* Lock the subscription list mutex to check for an existing subscription + * object. */ + IotMutex_Lock( &( _AwsIotShadowSubscriptionsMutex ) ); + subscriptionMutexLocked = true; + + /* Check for an existing subscription. This function will attempt to allocate + * a new subscription if not found. */ + pSubscription = _AwsIotShadow_FindSubscription( pThingName, + thingNameLength, + true ); + + if( pSubscription == NULL ) + { + /* No existing subscription was found, and no new subscription could be + * allocated. */ + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NO_MEMORY ); + } + + /* Check for an existing callback. */ + if( pSubscription->callbacks[ type ].function != NULL ) + { + /* Replace existing callback. */ + if( pCallbackInfo != NULL ) + { + IotLogInfo( "(%.*s) Found existing %s callback. Replacing callback.", + thingNameLength, + pThingName, + _pAwsIotShadowCallbackNames[ type ] ); + + pSubscription->callbacks[ type ] = *pCallbackInfo; + } + /* Remove existing callback. */ + else + { + IotLogInfo( "(%.*s) Removing existing %s callback.", + thingNameLength, + pThingName, + _pAwsIotShadowCallbackNames[ type ] ); + + /* Unsubscribe, then clear the callback information. */ + ( void ) _modifyCallbackSubscriptions( mqttConnection, + type, + pSubscription, + IotMqtt_UnsubscribeSync ); + ( void ) memset( &( pSubscription->callbacks[ type ] ), + 0x00, + sizeof( AwsIotShadowCallbackInfo_t ) ); + + /* Check if this subscription object can be removed. */ + _AwsIotShadow_RemoveSubscription( pSubscription, NULL ); + } + } + /* No existing callback. */ + else + { + /* Add new callback. */ + if( pCallbackInfo != NULL ) + { + IotLogInfo( "(%.*s) Adding new %s callback.", + thingNameLength, + pThingName, + _pAwsIotShadowCallbackNames[ type ] ); + + status = _modifyCallbackSubscriptions( mqttConnection, + type, + pSubscription, + IotMqtt_SubscribeSync ); + + if( status == AWS_IOT_SHADOW_SUCCESS ) + { + pSubscription->callbacks[ type ] = *pCallbackInfo; + } + else + { + /* On failure, check if this subscription can be removed. */ + _AwsIotShadow_RemoveSubscription( pSubscription, NULL ); + } + } + /* Do nothing; set return value to success. */ + else + { + status = AWS_IOT_SHADOW_SUCCESS; + } + } + + IOT_FUNCTION_CLEANUP_BEGIN(); + + if( subscriptionMutexLocked == true ) + { + IotMutex_Unlock( &( _AwsIotShadowSubscriptionsMutex ) ); + } + + IotLogInfo( "(%.*s) Shadow %s callback operation complete with result %s.", + thingNameLength, + pThingName, + _pAwsIotShadowCallbackNames[ type ], + AwsIotShadow_strerror( status ) ); + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +static AwsIotShadowError_t _modifyCallbackSubscriptions( IotMqttConnection_t mqttConnection, + _shadowCallbackType_t type, + _shadowSubscription_t * pSubscription, + AwsIotMqttFunction_t mqttOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_SUCCESS ); + IotMqttError_t mqttStatus = IOT_MQTT_STATUS_PENDING; + IotMqttSubscription_t subscription = IOT_MQTT_SUBSCRIPTION_INITIALIZER; + char * pTopicFilter = NULL; + uint16_t operationTopicLength = 0; + + /* Lookup table for Shadow callback suffixes. */ + const char * const pCallbackSuffix[ SHADOW_CALLBACK_COUNT ] = + { + SHADOW_DELTA_SUFFIX, /* Delta callback. */ + SHADOW_UPDATED_SUFFIX /* Updated callback. */ + }; + + /* Lookup table for Shadow callback suffix lengths. */ + const uint16_t pCallbackSuffixLength[ SHADOW_CALLBACK_COUNT ] = + { + SHADOW_DELTA_SUFFIX_LENGTH, /* Delta callback. */ + SHADOW_UPDATED_SUFFIX_LENGTH /* Updated callback. */ + }; + + /* Lookup table for Shadow callback function wrappers. */ + const AwsIotMqttCallbackFunction_t pCallbackWrapper[ SHADOW_CALLBACK_COUNT ] = + { + _deltaCallbackWrapper, /* Delta callback. */ + _updatedCallbackWrapper, /* Updated callback. */ + }; + + /* MQTT operation may only be subscribe or unsubscribe. */ + AwsIotShadow_Assert( ( mqttOperation == IotMqtt_SubscribeSync ) || + ( mqttOperation == IotMqtt_UnsubscribeSync ) ); + + /* Use the subscription's topic buffer if available. */ + if( pSubscription->pTopicBuffer != NULL ) + { + pTopicFilter = pSubscription->pTopicBuffer; + } + + /* Generate the prefix portion of the Shadow callback topic filter. Both + * callbacks share the same callback as the Shadow Update operation. */ + status = _AwsIotShadow_GenerateShadowTopic( SHADOW_UPDATE, + pSubscription->pThingName, + pSubscription->thingNameLength, + &pTopicFilter, + &operationTopicLength ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + + /* Place the callback suffix in the topic filter. */ + ( void ) memcpy( pTopicFilter + operationTopicLength, + pCallbackSuffix[ type ], + pCallbackSuffixLength[ type ] ); + + IotLogDebug( "%s subscription for %.*s", + mqttOperation == IotMqtt_SubscribeSync ? "Adding" : "Removing", + operationTopicLength + pCallbackSuffixLength[ type ], + pTopicFilter ); + + /* Set the members of the MQTT subscription. */ + subscription.qos = IOT_MQTT_QOS_1; + subscription.pTopicFilter = pTopicFilter; + subscription.topicFilterLength = ( uint16_t ) ( operationTopicLength + pCallbackSuffixLength[ type ] ); + subscription.callback.pCallbackContext = NULL; + subscription.callback.function = pCallbackWrapper[ type ]; + + /* Call the MQTT operation function. */ + mqttStatus = mqttOperation( mqttConnection, + &subscription, + 1, + 0, + _AwsIotShadowMqttTimeoutMs ); + + /* Check the result of the MQTT operation. */ + if( mqttStatus != IOT_MQTT_SUCCESS ) + { + IotLogError( "Failed to %s callback for %.*s %s callback, error %s.", + mqttOperation == IotMqtt_SubscribeSync ? "subscribe to" : "unsubscribe from", + pSubscription->thingNameLength, + pSubscription->pThingName, + _pAwsIotShadowCallbackNames[ type ], + IotMqtt_strerror( mqttStatus ) ); + + /* Convert the MQTT "NO MEMORY" error to a Shadow "NO MEMORY" error. */ + IOT_SET_AND_GOTO_CLEANUP( SHADOW_CONVERT_STATUS_CODE_MQTT_TO_SHADOW( mqttStatus ) ); + } + + IotLogDebug( "Successfully %s %.*s Shadow %s callback.", + mqttOperation == IotMqtt_SubscribeSync ? "subscribed to" : "unsubscribed from", + pSubscription->thingNameLength, + pSubscription->pThingName, + _pAwsIotShadowCallbackNames[ type ] ); + + IOT_FUNCTION_CLEANUP_BEGIN(); + + /* MQTT subscribe should check the subscription topic buffer. */ + if( mqttOperation == IotMqtt_SubscribeSync ) + { + /* If the current subscription has no topic buffer, assign it the current + * topic buffer. */ + if( pSubscription->pTopicBuffer == NULL ) + { + pSubscription->pTopicBuffer = pTopicFilter; + } + } + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +static void _callbackWrapperCommon( _shadowCallbackType_t type, + IotMqttCallbackParam_t * pMessage ) +{ + AwsIotShadowCallbackInfo_t callbackInfo = AWS_IOT_SHADOW_CALLBACK_INFO_INITIALIZER; + AwsIotShadowCallbackParam_t callbackParam = { .callbackType = ( AwsIotShadowCallbackType_t ) 0 }; + _shadowSubscription_t * pSubscription = NULL; + const char * pThingName = NULL; + size_t thingNameLength = 0; + + /* Parse the Thing Name from the topic. */ + if( AwsIot_ParseThingName( pMessage->u.message.info.pTopicName, + pMessage->u.message.info.topicNameLength, + &pThingName, + &thingNameLength ) == false ) + { + IOT_GOTO_CLEANUP(); + } + + /* Search for a matching subscription. */ + IotMutex_Lock( &_AwsIotShadowSubscriptionsMutex ); + + pSubscription = _AwsIotShadow_FindSubscription( pThingName, + thingNameLength, + false ); + + if( pSubscription == NULL ) + { + /* No subscription found. */ + IotMutex_Unlock( &_AwsIotShadowSubscriptionsMutex ); + IOT_GOTO_CLEANUP(); + } + + /* Ensure that a callback function is set. */ + AwsIotShadow_Assert( pSubscription->callbacks[ type ].function != NULL ); + + /* Copy the subscription callback info, as the subscription may be modified + * when the subscriptions mutex is released. */ + callbackInfo = pSubscription->callbacks[ type ]; + + IotMutex_Unlock( &_AwsIotShadowSubscriptionsMutex ); + + /* Set the callback type. Shadow callbacks are enumerated after the operations. */ + callbackParam.callbackType = ( AwsIotShadowCallbackType_t ) ( type + SHADOW_OPERATION_COUNT ); + + /* Set the remaining members of the callback param. */ + callbackParam.mqttConnection = pMessage->mqttConnection; + callbackParam.pThingName = pThingName; + callbackParam.thingNameLength = thingNameLength; + callbackParam.u.callback.pDocument = pMessage->u.message.info.pPayload; + callbackParam.u.callback.documentLength = pMessage->u.message.info.payloadLength; + + /* Invoke the callback function. */ + callbackInfo.function( callbackInfo.pCallbackContext, + &callbackParam ); + + /* This function uses cleanup sections to exit on error. */ + IOT_FUNCTION_CLEANUP_BEGIN(); +} + +/*-----------------------------------------------------------*/ + +static void _deltaCallbackWrapper( void * pArgument, + IotMqttCallbackParam_t * pMessage ) +{ + /* Silence warnings about unused parameters. */ + ( void ) pArgument; + + _callbackWrapperCommon( DELTA_CALLBACK, pMessage ); +} + +/*-----------------------------------------------------------*/ + +static void _updatedCallbackWrapper( void * pArgument, + IotMqttCallbackParam_t * pMessage ) +{ + /* Silence warnings about unused parameters. */ + ( void ) pArgument; + + _callbackWrapperCommon( UPDATED_CALLBACK, pMessage ); +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t AwsIotShadow_Init( uint32_t mqttTimeoutMs ) +{ + AwsIotShadowError_t status = AWS_IOT_SHADOW_SUCCESS; + bool listInitStatus = false; + + if( _initCalled == 0 ) + { + /* Initialize Shadow lists and mutexes. */ + listInitStatus = AwsIot_InitLists( &_AwsIotShadowPendingOperations, + &_AwsIotShadowSubscriptions, + &_AwsIotShadowPendingOperationsMutex, + &_AwsIotShadowSubscriptionsMutex ); + + if( listInitStatus == false ) + { + IotLogInfo( "Failed to create Shadow lists." ); + + status = AWS_IOT_SHADOW_INIT_FAILED; + } + else + { + /* Save the MQTT timeout option. */ + if( mqttTimeoutMs != 0 ) + { + _AwsIotShadowMqttTimeoutMs = mqttTimeoutMs; + } + + /* Set the flag that specifies initialization is complete. */ + _initCalled = 1; + + IotLogInfo( "Shadow library successfully initialized." ); + } + } + else + { + IotLogWarn( "AwsIotShadow_Init called with library already initialized." ); + } + + return status; +} + +/*-----------------------------------------------------------*/ + +void AwsIotShadow_Cleanup( void ) +{ + if( _initCalled == 1 ) + { + _initCalled = 0; + + /* Remove and free all items in the Shadow pending operation list. */ + IotMutex_Lock( &( _AwsIotShadowPendingOperationsMutex ) ); + IotListDouble_RemoveAll( &( _AwsIotShadowPendingOperations ), + _AwsIotShadow_DestroyOperation, + offsetof( _shadowOperation_t, link ) ); + IotMutex_Unlock( &( _AwsIotShadowPendingOperationsMutex ) ); + + /* Remove and free all items in the Shadow subscription list. */ + IotMutex_Lock( &( _AwsIotShadowSubscriptionsMutex ) ); + IotListDouble_RemoveAll( &( _AwsIotShadowSubscriptions ), + _AwsIotShadow_DestroySubscription, + offsetof( _shadowSubscription_t, link ) ); + IotMutex_Unlock( &( _AwsIotShadowSubscriptionsMutex ) ); + + /* Destroy Shadow library mutexes. */ + IotMutex_Destroy( &( _AwsIotShadowPendingOperationsMutex ) ); + IotMutex_Destroy( &( _AwsIotShadowSubscriptionsMutex ) ); + + /* Restore the default MQTT timeout. */ + _AwsIotShadowMqttTimeoutMs = AWS_IOT_SHADOW_DEFAULT_MQTT_TIMEOUT_MS; + + IotLogInfo( "Shadow library cleanup done." ); + } + else + { + IotLogWarn( "AwsIotShadow_Init was not called before AwsIotShadow_Cleanup." ); + } +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t AwsIotShadow_DeleteAsync( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + uint32_t flags, + const AwsIotShadowCallbackInfo_t * pCallbackInfo, + AwsIotShadowOperation_t * const pDeleteOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_STATUS_PENDING ); + _shadowOperation_t * pOperation = NULL; + + /* Check that AwsIotShadow_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NOT_INITIALIZED ); + } + + /* Validate the Thing Name and flags for Shadow DELETE. */ + status = _validateThingNameFlags( SHADOW_DELETE, + pThingName, + thingNameLength, + flags, + pCallbackInfo, + pDeleteOperation ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + /* The Thing Name or some flag was invalid. */ + IOT_GOTO_CLEANUP(); + } + + /* Allocate a new Shadow operation for DELETE. */ + status = _AwsIotShadow_CreateOperation( &pOperation, + SHADOW_DELETE, + flags, + pCallbackInfo ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + /* No memory for a new Shadow operation. */ + IOT_GOTO_CLEANUP(); + } + + /* Check the members set by Shadow operation creation. */ + AwsIotShadow_Assert( pOperation != NULL ); + AwsIotShadow_Assert( pOperation->type == SHADOW_DELETE ); + AwsIotShadow_Assert( pOperation->flags == flags ); + AwsIotShadow_Assert( pOperation->status == AWS_IOT_SHADOW_STATUS_PENDING ); + + /* Set the reference if provided. This must be done before the Shadow operation + * is processed. */ + if( pDeleteOperation != NULL ) + { + *pDeleteOperation = pOperation; + } + + /* Process the Shadow operation. This subscribes to any required topics and + * sends the MQTT message for the Shadow operation. */ + status = _AwsIotShadow_ProcessOperation( mqttConnection, + pThingName, + thingNameLength, + pOperation, + NULL ); + + /* If the Shadow operation failed, clear the now invalid reference. */ + if( ( status != AWS_IOT_SHADOW_STATUS_PENDING ) && ( pDeleteOperation != NULL ) ) + { + *pDeleteOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t AwsIotShadow_DeleteSync( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + uint32_t flags, + uint32_t timeoutMs ) +{ + AwsIotShadowError_t status = AWS_IOT_SHADOW_STATUS_PENDING; + AwsIotShadowOperation_t deleteOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; + + /* Set the waitable flag. */ + flags |= AWS_IOT_SHADOW_FLAG_WAITABLE; + + /* Call the asynchronous Shadow delete function. */ + status = AwsIotShadow_DeleteAsync( mqttConnection, + pThingName, + thingNameLength, + flags, + NULL, + &deleteOperation ); + + /* Wait for the Shadow delete operation to complete. */ + if( status == AWS_IOT_SHADOW_STATUS_PENDING ) + { + status = AwsIotShadow_Wait( deleteOperation, timeoutMs, NULL, NULL ); + } + + /* Ensure that a status was set. */ + AwsIotShadow_Assert( status != AWS_IOT_SHADOW_STATUS_PENDING ); + + return status; +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t AwsIotShadow_GetAsync( IotMqttConnection_t mqttConnection, + const AwsIotShadowDocumentInfo_t * pGetInfo, + uint32_t flags, + const AwsIotShadowCallbackInfo_t * pCallbackInfo, + AwsIotShadowOperation_t * const pGetOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_STATUS_PENDING ); + _shadowOperation_t * pOperation = NULL; + + /* Check that AwsIotShadow_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NOT_INITIALIZED ); + } + + /* Validate the Thing Name and flags for Shadow GET. */ + status = _validateThingNameFlags( SHADOW_GET, + pGetInfo->pThingName, + pGetInfo->thingNameLength, + flags, + pCallbackInfo, + pGetOperation ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + /* The Thing Name or some flag was invalid. */ + IOT_GOTO_CLEANUP(); + } + + /* Validate the document info for Shadow GET. */ + status = _validateDocumentInfo( SHADOW_GET, + flags, + pGetInfo ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + /* Document info was invalid. */ + IOT_GOTO_CLEANUP(); + } + + /* Allocate a new Shadow operation for GET. */ + status = _AwsIotShadow_CreateOperation( &pOperation, + SHADOW_GET, + flags, + pCallbackInfo ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + /* No memory for a new Shadow operation. */ + IOT_GOTO_CLEANUP(); + } + + /* Check the members set by Shadow operation creation. */ + AwsIotShadow_Assert( pOperation != NULL ); + AwsIotShadow_Assert( pOperation->type == SHADOW_GET ); + AwsIotShadow_Assert( pOperation->flags == flags ); + AwsIotShadow_Assert( pOperation->status == AWS_IOT_SHADOW_STATUS_PENDING ); + + /* Copy the memory allocation function. */ + pOperation->u.get.mallocDocument = pGetInfo->u.get.mallocDocument; + + /* Set the reference if provided. This must be done before the Shadow operation + * is processed. */ + if( pGetOperation != NULL ) + { + *pGetOperation = pOperation; + } + + /* Process the Shadow operation. This subscribes to any required topics and + * sends the MQTT message for the Shadow operation. */ + status = _AwsIotShadow_ProcessOperation( mqttConnection, + pGetInfo->pThingName, + pGetInfo->thingNameLength, + pOperation, + pGetInfo ); + + /* If the Shadow operation failed, clear the now invalid reference. */ + if( ( status != AWS_IOT_SHADOW_STATUS_PENDING ) && ( pGetOperation != NULL ) ) + { + *pGetOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t AwsIotShadow_GetSync( IotMqttConnection_t mqttConnection, + const AwsIotShadowDocumentInfo_t * pGetInfo, + uint32_t flags, + uint32_t timeoutMs, + const char ** const pShadowDocument, + size_t * const pShadowDocumentLength ) +{ + AwsIotShadowError_t status = AWS_IOT_SHADOW_STATUS_PENDING; + AwsIotShadowOperation_t getOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; + + /* Set the waitable flag. */ + flags |= AWS_IOT_SHADOW_FLAG_WAITABLE; + + /* Call the asynchronous Shadow get function. */ + status = AwsIotShadow_GetAsync( mqttConnection, + pGetInfo, + flags, + NULL, + &getOperation ); + + /* Wait for the Shadow get operation to complete. */ + if( status == AWS_IOT_SHADOW_STATUS_PENDING ) + { + status = AwsIotShadow_Wait( getOperation, + timeoutMs, + pShadowDocument, + pShadowDocumentLength ); + } + + /* Ensure that a status was set. */ + AwsIotShadow_Assert( status != AWS_IOT_SHADOW_STATUS_PENDING ); + + return status; +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t AwsIotShadow_UpdateAsync( IotMqttConnection_t mqttConnection, + const AwsIotShadowDocumentInfo_t * pUpdateInfo, + uint32_t flags, + const AwsIotShadowCallbackInfo_t * pCallbackInfo, + AwsIotShadowOperation_t * const pUpdateOperation ) +{ + IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_STATUS_PENDING ); + _shadowOperation_t * pOperation = NULL; + const char * pClientToken = NULL; + size_t clientTokenLength = 0; + + /* Check that AwsIotShadow_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NOT_INITIALIZED ); + } + + /* Validate the Thing Name and flags for Shadow UPDATE. */ + status = _validateThingNameFlags( SHADOW_UPDATE, + pUpdateInfo->pThingName, + pUpdateInfo->thingNameLength, + flags, + pCallbackInfo, + pUpdateOperation ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + /* The Thing Name or some flag was invalid. */ + IOT_GOTO_CLEANUP(); + } + + /* Validate the document info for Shadow UPDATE. */ + status = _validateDocumentInfo( SHADOW_UPDATE, + flags, + pUpdateInfo ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + /* Document info was invalid. */ + IOT_GOTO_CLEANUP(); + } + + /* Check UPDATE document for a client token. */ + if( AwsIot_GetClientToken( pUpdateInfo->u.update.pUpdateDocument, + pUpdateInfo->u.update.updateDocumentLength, + &pClientToken, + &clientTokenLength ) == false ) + { + IotLogError( "Shadow document for Shadow UPDATE does not contain a valid client token." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); + } + + /* Allocate a new Shadow operation for UPDATE. */ + status = _AwsIotShadow_CreateOperation( &pOperation, + SHADOW_UPDATE, + flags, + pCallbackInfo ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + /* No memory for a new Shadow operation. */ + IOT_GOTO_CLEANUP(); + } + + /* Check the members set by Shadow operation creation. */ + AwsIotShadow_Assert( pOperation != NULL ); + AwsIotShadow_Assert( pOperation->type == SHADOW_UPDATE ); + AwsIotShadow_Assert( pOperation->flags == flags ); + AwsIotShadow_Assert( pOperation->status == AWS_IOT_SHADOW_STATUS_PENDING ); + + /* Allocate memory for the client token. */ + pOperation->u.update.pClientToken = AwsIotShadow_MallocString( clientTokenLength ); + + if( pOperation->u.update.pClientToken == NULL ) + { + IotLogError( "Failed to allocate memory for Shadow update client token." ); + _AwsIotShadow_DestroyOperation( pOperation ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NO_MEMORY ); + } + + /* Copy the client token. The client token must be copied in case the application + * frees the buffer containing it. */ + ( void ) memcpy( ( void * ) pOperation->u.update.pClientToken, + pClientToken, + clientTokenLength ); + pOperation->u.update.clientTokenLength = clientTokenLength; + + /* Set the reference if provided. This must be done before the Shadow operation + * is processed. */ + if( pUpdateOperation != NULL ) + { + *pUpdateOperation = pOperation; + } + + /* Process the Shadow operation. This subscribes to any required topics and + * sends the MQTT message for the Shadow operation. */ + status = _AwsIotShadow_ProcessOperation( mqttConnection, + pUpdateInfo->pThingName, + pUpdateInfo->thingNameLength, + pOperation, + pUpdateInfo ); + + /* If the Shadow operation failed, clear the now invalid reference. */ + if( ( status != AWS_IOT_SHADOW_STATUS_PENDING ) && ( pUpdateOperation != NULL ) ) + { + *pUpdateOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t AwsIotShadow_UpdateSync( IotMqttConnection_t mqttConnection, + const AwsIotShadowDocumentInfo_t * pUpdateInfo, + uint32_t flags, + uint32_t timeoutMs ) +{ + AwsIotShadowError_t status = AWS_IOT_SHADOW_STATUS_PENDING; + AwsIotShadowOperation_t updateOperation = AWS_IOT_SHADOW_OPERATION_INITIALIZER; + + /* Set the waitable flag. */ + flags |= AWS_IOT_SHADOW_FLAG_WAITABLE; + + /* Call the asynchronous Shadow update function. */ + status = AwsIotShadow_UpdateAsync( mqttConnection, + pUpdateInfo, + flags, + NULL, + &updateOperation ); + + /* Wait for the Shadow update operation to complete. */ + if( status == AWS_IOT_SHADOW_STATUS_PENDING ) + { + status = AwsIotShadow_Wait( updateOperation, timeoutMs, NULL, NULL ); + } + + /* Ensure that a status was set. */ + AwsIotShadow_Assert( status != AWS_IOT_SHADOW_STATUS_PENDING ); + + return status; +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t AwsIotShadow_Wait( AwsIotShadowOperation_t operation, + uint32_t timeoutMs, + const char ** const pShadowDocument, + size_t * const pShadowDocumentLength ) +{ + IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_STATUS_PENDING ); + + /* Check that AwsIotShadow_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NOT_INITIALIZED ); + } + + /* Check that reference is set. */ + if( operation == NULL ) + { + IotLogError( "Operation reference cannot be NULL." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); + } + + /* Check that reference is waitable. */ + if( ( operation->flags & AWS_IOT_SHADOW_FLAG_WAITABLE ) == 0 ) + { + IotLogError( "Operation is not waitable." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); + } + + /* Check that output parameters are set for a Shadow GET. */ + if( operation->type == SHADOW_GET ) + { + if( ( pShadowDocument == NULL ) || ( pShadowDocumentLength == NULL ) ) + { + IotLogError( "Output buffer and size pointer must be set for Shadow GET." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_PARAMETER ); + } + } + + /* Wait for a response to the Shadow operation. */ + if( IotSemaphore_TimedWait( &( operation->notify.waitSemaphore ), + timeoutMs ) == true ) + { + status = operation->status; + } + else + { + status = AWS_IOT_SHADOW_TIMEOUT; + } + + /* Remove the completed operation from the pending operation list. */ + IotMutex_Lock( &( _AwsIotShadowPendingOperationsMutex ) ); + IotListDouble_Remove( &( operation->link ) ); + IotMutex_Unlock( &( _AwsIotShadowPendingOperationsMutex ) ); + + /* Decrement the reference count. This also removes subscriptions if the + * count reaches 0. */ + IotMutex_Lock( &_AwsIotShadowSubscriptionsMutex ); + _AwsIotShadow_DecrementReferences( operation, + operation->pSubscription->pTopicBuffer, + NULL ); + IotMutex_Unlock( &_AwsIotShadowSubscriptionsMutex ); + + /* Set the output parameters for Shadow GET. */ + if( ( operation->type == SHADOW_GET ) && + ( status == AWS_IOT_SHADOW_SUCCESS ) ) + { + *pShadowDocument = operation->u.get.pDocument; + *pShadowDocumentLength = operation->u.get.documentLength; + } + + /* Destroy the Shadow operation. */ + _AwsIotShadow_DestroyOperation( operation ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t AwsIotShadow_SetDeltaCallback( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + uint32_t flags, + const AwsIotShadowCallbackInfo_t * pDeltaCallback ) +{ + /* Flags are currently not used by this function. */ + ( void ) flags; + + return _setCallbackCommon( mqttConnection, + DELTA_CALLBACK, + pThingName, + thingNameLength, + pDeltaCallback ); +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t AwsIotShadow_SetUpdatedCallback( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + uint32_t flags, + const AwsIotShadowCallbackInfo_t * pUpdatedCallback ) +{ + /* Flags are currently not used by this function. */ + ( void ) flags; + + return _setCallbackCommon( mqttConnection, + UPDATED_CALLBACK, + pThingName, + thingNameLength, + pUpdatedCallback ); +} + +/*-----------------------------------------------------------*/ + +const char * AwsIotShadow_strerror( AwsIotShadowError_t status ) +{ + const char * pMessage = NULL; + + switch( status ) + { + case AWS_IOT_SHADOW_SUCCESS: + pMessage = "SUCCESS"; + break; + + case AWS_IOT_SHADOW_STATUS_PENDING: + pMessage = "STATUS PENDING"; + break; + + case AWS_IOT_SHADOW_INIT_FAILED: + pMessage = "INITIALIZATION FAILED"; + break; + + case AWS_IOT_SHADOW_BAD_PARAMETER: + pMessage = "BAD PARAMETER"; + break; + + case AWS_IOT_SHADOW_NO_MEMORY: + pMessage = "NO MEMORY"; + break; + + case AWS_IOT_SHADOW_MQTT_ERROR: + pMessage = "MQTT LIBRARY ERROR"; + break; + + case AWS_IOT_SHADOW_BAD_RESPONSE: + pMessage = "BAD RESPONSE RECEIVED"; + break; + + case AWS_IOT_SHADOW_TIMEOUT: + pMessage = "TIMEOUT"; + break; + + case AWS_IOT_SHADOW_NOT_INITIALIZED: + pMessage = "NOT INITIALIZED"; + break; + + case AWS_IOT_SHADOW_BAD_REQUEST: + pMessage = "REJECTED: 400 BAD REQUEST"; + break; + + case AWS_IOT_SHADOW_UNAUTHORIZED: + pMessage = "REJECTED: 401 UNAUTHORIZED"; + break; + + case AWS_IOT_SHADOW_FORBIDDEN: + pMessage = "REJECTED: 403 FORBIDDEN"; + break; + + case AWS_IOT_SHADOW_NOT_FOUND: + pMessage = "REJECTED: 404 NOT FOUND"; + break; + + case AWS_IOT_SHADOW_CONFLICT: + pMessage = "REJECTED: 409 VERSION CONFLICT"; + break; + + case AWS_IOT_SHADOW_TOO_LARGE: + pMessage = "REJECTED: 413 PAYLOAD TOO LARGE"; + break; + + case AWS_IOT_SHADOW_UNSUPPORTED: + pMessage = "REJECTED: 415 UNSUPPORTED ENCODING"; + break; + + case AWS_IOT_SHADOW_TOO_MANY_REQUESTS: + pMessage = "REJECTED: 429 TOO MANY REQUESTS"; + break; + + case AWS_IOT_SHADOW_SERVER_ERROR: + pMessage = "500 SERVER ERROR"; + break; + + default: + pMessage = "INVALID STATUS"; + break; + } + + return pMessage; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_operation.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_operation.c new file mode 100644 index 000000000..27f7f91ef --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_operation.c @@ -0,0 +1,925 @@ +/* + * AWS IoT Shadow V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_shadow_operation.c + * @brief Implements functions that process Shadow operations. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* Shadow internal include. */ +#include "private/aws_iot_shadow_internal.h" + +/* Platform layer includes. */ +#include "platform/iot_threads.h" + +/* MQTT include. */ +#include "iot_mqtt.h" + +/* Error handling include. */ +#include "iot_error.h" + +/*-----------------------------------------------------------*/ + +/** + * @brief First parameter to #_shadowOperation_match. + */ +typedef struct _operationMatchParams +{ + _shadowOperationType_t type; /**< @brief DELETE, GET, or UPDATE. */ + const char * pThingName; /**< @brief Thing Name of Shadow operation. */ + size_t thingNameLength; /**< @brief Length of #_operationMatchParams_t.pThingName. */ + const char * pDocument; /**< @brief Shadow UPDATE response document. */ + size_t documentLength; /**< @brief Length of #_operationMatchParams_t.pDocument. */ +} _operationMatchParams_t; + +/*-----------------------------------------------------------*/ + +/** + * @brief Match a received Shadow response with a Shadow operation awaiting a + * response. + * + * @param[in] pOperationLink Pointer to the link member of the #_shadowOperation_t + * to check. + * @param[in] pMatch Pointer to an #_operationMatchParams_t. + * + * @return `true` if `pMatch` matches the received response; `false` otherwise. + */ +static bool _shadowOperation_match( const IotLink_t * pOperationLink, + void * pMatch ); + +/** + * @brief Common function for processing received Shadow responses. + * + * @param[in] type DELETE, GET, or UPDATE. + * @param[in] pMessage Received Shadow response (as an MQTT PUBLISH message). + */ +static void _commonOperationCallback( _shadowOperationType_t type, + IotMqttCallbackParam_t * pMessage ); + +/** + * @brief Invoked when a Shadow response is received for Shadow DELETE. + * + * @param[in] pArgument Ignored. + * @param[in] pMessage Received Shadow response (as an MQTT PUBLISH message). + */ +static void _deleteCallback( void * pArgument, + IotMqttCallbackParam_t * pMessage ); + +/** + * @brief Invoked when a Shadow response is received for a Shadow GET. + * + * @param[in] pArgument Ignored. + * @param[in] pMessage Received Shadow response (as an MQTT PUBLISH message). + */ +static void _getCallback( void * pArgument, + IotMqttCallbackParam_t * pMessage ); + +/** + * @brief Process an incoming Shadow document received when a Shadow GET is + * accepted. + * + * @param[in] pOperation The GET operation associated with the incoming Shadow + * document. + * @param[in] pPublishInfo The received Shadow document (as an MQTT PUBLISH + * message). + * + * @return #AWS_IOT_SHADOW_SUCCESS or #AWS_IOT_SHADOW_NO_MEMORY. Memory allocation + * only happens for a waitable `pOperation`. + */ +static AwsIotShadowError_t _processAcceptedGet( _shadowOperation_t * pOperation, + const IotMqttPublishInfo_t * pPublishInfo ); + +/** + * @brief Invoked when a Shadow response is received for a Shadow UPDATE. + * + * @param[in] pArgument Ignored. + * @param[in] pMessage Received Shadow response (as an MQTT PUBLISH message). + */ +static void _updateCallback( void * pArgument, + IotMqttCallbackParam_t * pMessage ); + +/** + * @brief Notify of a completed Shadow operation. + * + * @param[in] pOperation The operation which completed. + * + * Depending on the parameters passed to a user-facing Shadow function, the + * notification will cause @ref shadow_function_wait to return or invoke a + * user-provided callback. + */ +static void _notifyCompletion( _shadowOperation_t * pOperation ); + +/** + * @brief Get a Shadow subscription to use with a Shadow operation. + * + * This function may use an existing Shadow subscription, or it may allocate a + * new one. + * + * @param[in] pThingName Thing Name associated with operation. + * @param[in] thingNameLength Length of `pThingName`. + * @param[in] pTopicBuffer Contains the topic to use for subscribing. + * @param[in] operationTopicLength The length of the base topic in `pTopicBuffer`. + * @param[in] pOperation Shadow operation that needs a subscription. + * @param[out] pFreeTopicBuffer Whether the caller may free `pTopicBuffer` + * (which may be assigned to a subscription). + * + * @return #AWS_IOT_SHADOW_SUCCESS or #AWS_IOT_SHADOW_NO_MEMORY + */ +static AwsIotShadowError_t _findSubscription( const char * pThingName, + size_t thingNameLength, + char * pTopicBuffer, + uint16_t operationTopicLength, + _shadowOperation_t * pOperation, + bool * pFreeTopicBuffer ); + +/*-----------------------------------------------------------*/ + +#if LIBRARY_LOG_LEVEL > IOT_LOG_NONE + +/** + * @brief Printable names for each of the Shadow operations. + */ + const char * const _pAwsIotShadowOperationNames[] = + { + "DELETE", + "GET", + "UPDATE", + "SET DELTA", + "SET UPDATED" + }; +#endif /* if LIBRARY_LOG_LEVEL > IOT_LOG_NONE */ + +/** + * @brief List of active Shadow operations awaiting a response from the Shadow + * service. + */ +IotListDouble_t _AwsIotShadowPendingOperations = { 0 }; + +/** + * @brief Protects #_AwsIotShadowPendingOperations from concurrent access. + */ +IotMutex_t _AwsIotShadowPendingOperationsMutex; + +/*-----------------------------------------------------------*/ + +static bool _shadowOperation_match( const IotLink_t * pOperationLink, + void * pMatch ) +{ + /* Because this function is called from a container function, the given link + * must never be NULL. */ + AwsIotShadow_Assert( pOperationLink != NULL ); + + _shadowOperation_t * pOperation = IotLink_Container( _shadowOperation_t, + pOperationLink, + link ); + _operationMatchParams_t * pParam = ( _operationMatchParams_t * ) pMatch; + _shadowSubscription_t * pSubscription = pOperation->pSubscription; + const char * pClientToken = NULL; + size_t clientTokenLength = 0; + + /* Check for matching Thing Name and operation type. */ + bool match = ( pOperation->type == pParam->type ) && + ( pParam->thingNameLength == pSubscription->thingNameLength ) && + ( strncmp( pParam->pThingName, + pSubscription->pThingName, + pParam->thingNameLength ) == 0 ); + + /* For a Shadow UPDATE operation, compare the client tokens. */ + if( ( match == true ) && ( pOperation->type == SHADOW_UPDATE ) ) + { + /* Check document pointers. */ + AwsIotShadow_Assert( pParam->pDocument != NULL ); + AwsIotShadow_Assert( pParam->documentLength > 0 ); + AwsIotShadow_Assert( pOperation->u.update.pClientToken != NULL ); + AwsIotShadow_Assert( pOperation->u.update.clientTokenLength > 0 ); + + IotLogDebug( "Verifying client tokens for Shadow UPDATE." ); + + /* Check for the client token in the UPDATE response document. */ + match = AwsIot_GetClientToken( pParam->pDocument, + pParam->documentLength, + &pClientToken, + &clientTokenLength ); + + /* If the UPDATE response document has a client token, check that it + * matches. */ + if( match == true ) + { + match = ( clientTokenLength == pOperation->u.update.clientTokenLength ) && + ( strncmp( pClientToken, + pOperation->u.update.pClientToken, + clientTokenLength ) == 0 ); + } + else + { + IotLogWarn( "Received a Shadow UPDATE response with no client token. " + "This is possibly a response to a bad JSON document:\r\n%.*s", + pParam->documentLength, + pParam->pDocument ); + } + } + + return match; +} + +/*-----------------------------------------------------------*/ + +static void _commonOperationCallback( _shadowOperationType_t type, + IotMqttCallbackParam_t * pMessage ) +{ + _shadowOperation_t * pOperation = NULL; + IotLink_t * pOperationLink = NULL; + AwsIotStatus_t status = AWS_IOT_UNKNOWN; + _operationMatchParams_t param = { .type = ( _shadowOperationType_t ) 0 }; + uint32_t flags = 0; + + /* Set operation type to search. */ + param.type = type; + + /* Set the response document for a Shadow UPDATE. */ + if( type == SHADOW_UPDATE ) + { + param.pDocument = pMessage->u.message.info.pPayload; + param.documentLength = pMessage->u.message.info.payloadLength; + } + + /* Parse the Thing Name from the MQTT topic name. */ + if( AwsIot_ParseThingName( pMessage->u.message.info.pTopicName, + pMessage->u.message.info.topicNameLength, + &( param.pThingName ), + &( param.thingNameLength ) ) == false ) + { + IOT_GOTO_CLEANUP(); + } + + /* Lock the pending operations list for exclusive access. */ + IotMutex_Lock( &( _AwsIotShadowPendingOperationsMutex ) ); + + /* Search for a matching pending operation. */ + pOperationLink = IotListDouble_FindFirstMatch( &( _AwsIotShadowPendingOperations ), + NULL, + _shadowOperation_match, + ¶m ); + + /* Find and remove the first Shadow operation of the given type. */ + if( pOperationLink == NULL ) + { + /* Operation is not pending. It may have already been processed. Return + * without doing anything */ + IotMutex_Unlock( &( _AwsIotShadowPendingOperationsMutex ) ); + + IotLogWarn( "Shadow %s callback received an unknown operation.", + _pAwsIotShadowOperationNames[ type ] ); + + IOT_GOTO_CLEANUP(); + } + else + { + pOperation = IotLink_Container( _shadowOperation_t, pOperationLink, link ); + + /* Remove a non-waitable operation from the pending operation list. + * Waitable operations are removed by the Wait function. */ + if( ( pOperation->flags & AWS_IOT_SHADOW_FLAG_WAITABLE ) == 0 ) + { + IotListDouble_Remove( &( pOperation->link ) ); + IotMutex_Unlock( &( _AwsIotShadowPendingOperationsMutex ) ); + } + } + + /* Check that the Shadow operation type and status. */ + AwsIotShadow_Assert( pOperation->type == type ); + AwsIotShadow_Assert( pOperation->status == AWS_IOT_SHADOW_STATUS_PENDING ); + + IotLogDebug( "Received Shadow response on topic %.*s", + pMessage->u.message.info.topicNameLength, + pMessage->u.message.info.pTopicName ); + + /* Parse the status from the topic name. */ + status = AwsIot_ParseStatus( pMessage->u.message.info.pTopicName, + pMessage->u.message.info.topicNameLength ); + + switch( status ) + { + case AWS_IOT_ACCEPTED: + IotLogInfo( "Shadow %s of %.*s was ACCEPTED.", + _pAwsIotShadowOperationNames[ type ], + pOperation->pSubscription->thingNameLength, + pOperation->pSubscription->pThingName ); + + /* Process the retrieved document for a Shadow GET. Otherwise, set + * status to success. */ + if( type == SHADOW_GET ) + { + pOperation->status = _processAcceptedGet( pOperation, + &( pMessage->u.message.info ) ); + } + else + { + pOperation->status = AWS_IOT_SHADOW_SUCCESS; + } + + break; + + case AWS_IOT_REJECTED: + IotLogWarn( "Shadow %s of %.*s was REJECTED.", + _pAwsIotShadowOperationNames[ type ], + pOperation->pSubscription->thingNameLength, + pOperation->pSubscription->pThingName ); + + pOperation->status = _AwsIotShadow_ParseErrorDocument( pMessage->u.message.info.pPayload, + pMessage->u.message.info.payloadLength ); + break; + + default: + IotLogWarn( "Unknown status for %s of %.*s Shadow. Ignoring message.", + _pAwsIotShadowOperationNames[ type ], + pOperation->pSubscription->thingNameLength, + pOperation->pSubscription->pThingName ); + + pOperation->status = AWS_IOT_SHADOW_BAD_RESPONSE; + break; + } + + /* Copy the flags from the Shadow operation. The notify function may delete the operation. */ + flags = pOperation->flags; + + /* Notify of operation completion. */ + _notifyCompletion( pOperation ); + + /* For waitable operations, unlock the pending operation list mutex to allow + * the Wait function to run. */ + if( ( flags & AWS_IOT_SHADOW_FLAG_WAITABLE ) == AWS_IOT_SHADOW_FLAG_WAITABLE ) + { + IotMutex_Unlock( &( _AwsIotShadowPendingOperationsMutex ) ); + } + + /* This function has no return value and no cleanup, but uses the cleanup + * label to exit on error. */ + IOT_FUNCTION_CLEANUP_BEGIN(); +} + +/*-----------------------------------------------------------*/ + +static void _deleteCallback( void * pArgument, + IotMqttCallbackParam_t * pMessage ) +{ + /* Silence warnings about unused parameter. */ + ( void ) pArgument; + + _commonOperationCallback( SHADOW_DELETE, pMessage ); +} + +/*-----------------------------------------------------------*/ + +static void _getCallback( void * pArgument, + IotMqttCallbackParam_t * pMessage ) +{ + /* Silence warnings about unused parameter. */ + ( void ) pArgument; + + _commonOperationCallback( SHADOW_GET, pMessage ); +} + +/*-----------------------------------------------------------*/ + +static AwsIotShadowError_t _processAcceptedGet( _shadowOperation_t * pOperation, + const IotMqttPublishInfo_t * pPublishInfo ) +{ + AwsIotShadowError_t status = AWS_IOT_SHADOW_SUCCESS; + + /* A non-waitable operation can re-use the pointers from the publish info, + * since those are guaranteed to be in-scope throughout the user callback. + * But a waitable operation must copy the data from the publish info because + * AwsIotShadow_Wait may be called after the MQTT library frees the publish + * info. */ + if( ( pOperation->flags & AWS_IOT_SHADOW_FLAG_WAITABLE ) == 0 ) + { + pOperation->u.get.pDocument = pPublishInfo->pPayload; + pOperation->u.get.documentLength = pPublishInfo->payloadLength; + } + else + { + IotLogDebug( "Allocating new buffer for waitable Shadow GET." ); + + /* Parameter validation should not have allowed a NULL malloc function. */ + AwsIotShadow_Assert( pOperation->u.get.mallocDocument != NULL ); + + /* Allocate a buffer for the retrieved document. */ + pOperation->u.get.pDocument = pOperation->u.get.mallocDocument( pPublishInfo->payloadLength ); + + if( pOperation->u.get.pDocument == NULL ) + { + IotLogError( "Failed to allocate buffer for retrieved Shadow document." ); + + status = AWS_IOT_SHADOW_NO_MEMORY; + } + else + { + /* Copy the retrieved document. */ + ( void ) memcpy( ( void * ) pOperation->u.get.pDocument, + pPublishInfo->pPayload, + pPublishInfo->payloadLength ); + pOperation->u.get.documentLength = pPublishInfo->payloadLength; + } + } + + return status; +} + +/*-----------------------------------------------------------*/ + +static void _updateCallback( void * pArgument, + IotMqttCallbackParam_t * pMessage ) +{ + /* Silence warnings about unused parameter. */ + ( void ) pArgument; + + _commonOperationCallback( SHADOW_UPDATE, pMessage ); +} + +/*-----------------------------------------------------------*/ + +static void _notifyCompletion( _shadowOperation_t * pOperation ) +{ + AwsIotShadowCallbackParam_t callbackParam = { .callbackType = ( AwsIotShadowCallbackType_t ) 0 }; + _shadowSubscription_t * pSubscription = pOperation->pSubscription, + * pRemovedSubscription = NULL; + + /* If the operation is waiting, post to its wait semaphore and return. */ + if( ( pOperation->flags & AWS_IOT_SHADOW_FLAG_WAITABLE ) == AWS_IOT_SHADOW_FLAG_WAITABLE ) + { + IotSemaphore_Post( &( pOperation->notify.waitSemaphore ) ); + } + else + { + /* Decrement the reference count. This also removes subscriptions if the + * count reaches 0. */ + IotMutex_Lock( &_AwsIotShadowSubscriptionsMutex ); + _AwsIotShadow_DecrementReferences( pOperation, + pSubscription->pTopicBuffer, + &pRemovedSubscription ); + IotMutex_Unlock( &_AwsIotShadowSubscriptionsMutex ); + + /* Set the subscription pointer used for the user callback based on whether + * a subscription was removed from the list. */ + if( pRemovedSubscription != NULL ) + { + pSubscription = pRemovedSubscription; + } + + AwsIotShadow_Assert( pSubscription != NULL ); + + /* Invoke the user callback if provided. */ + if( pOperation->notify.callback.function != NULL ) + { + /* Set the common members of the callback parameter. */ + callbackParam.callbackType = ( AwsIotShadowCallbackType_t ) pOperation->type; + callbackParam.mqttConnection = pOperation->mqttConnection; + callbackParam.u.operation.result = pOperation->status; + callbackParam.u.operation.reference = pOperation; + callbackParam.pThingName = pSubscription->pThingName; + callbackParam.thingNameLength = pSubscription->thingNameLength; + + /* Set the members of the callback parameter for a received document. */ + if( pOperation->type == SHADOW_GET ) + { + callbackParam.u.operation.get.pDocument = pOperation->u.get.pDocument; + callbackParam.u.operation.get.documentLength = pOperation->u.get.documentLength; + } + + pOperation->notify.callback.function( pOperation->notify.callback.pCallbackContext, + &callbackParam ); + } + + /* Destroy a removed subscription. */ + if( pRemovedSubscription != NULL ) + { + _AwsIotShadow_DestroySubscription( pRemovedSubscription ); + } + + _AwsIotShadow_DestroyOperation( pOperation ); + } +} + +/*-----------------------------------------------------------*/ + +static AwsIotShadowError_t _findSubscription( const char * pThingName, + size_t thingNameLength, + char * pTopicBuffer, + uint16_t operationTopicLength, + _shadowOperation_t * pOperation, + bool * pFreeTopicBuffer ) +{ + AwsIotShadowError_t status = AWS_IOT_SHADOW_SUCCESS; + _shadowSubscription_t * pSubscription = NULL; + + /* Lookup table for Shadow operation callbacks. */ + const AwsIotMqttCallbackFunction_t shadowCallbacks[ SHADOW_OPERATION_COUNT ] = + { + _deleteCallback, + _getCallback, + _updateCallback + }; + + /* Lock the subscriptions mutex for exclusive access. */ + IotMutex_Lock( &_AwsIotShadowSubscriptionsMutex ); + + /* Check for an existing subscription. This function will attempt to allocate + * a new subscription if not found. */ + pSubscription = _AwsIotShadow_FindSubscription( pThingName, + thingNameLength, + true ); + + if( pSubscription == NULL ) + { + status = AWS_IOT_SHADOW_NO_MEMORY; + } + else + { + /* Ensure that the subscription Thing Name matches. */ + AwsIotShadow_Assert( pSubscription != NULL ); + AwsIotShadow_Assert( pSubscription->thingNameLength == thingNameLength ); + AwsIotShadow_Assert( strncmp( pSubscription->pThingName, + pThingName, + thingNameLength ) == 0 ); + + /* Set the subscription object for the Shadow operation. */ + pOperation->pSubscription = pSubscription; + + /* Assign the topic buffer to the subscription to use for unsubscribing if + * the subscription has no topic buffer. */ + if( pSubscription->pTopicBuffer == NULL ) + { + pSubscription->pTopicBuffer = pTopicBuffer; + + /* Don't free the topic buffer if it was allocated to the subscription. */ + *pFreeTopicBuffer = false; + } + else + { + *pFreeTopicBuffer = true; + } + + /* Increment the reference count for this Shadow operation's + * subscriptions. */ + status = _AwsIotShadow_IncrementReferences( pOperation, + pTopicBuffer, + operationTopicLength, + shadowCallbacks[ pOperation->type ] ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + /* Failed to add subscriptions for a Shadow operation. The reference + * count was not incremented. Check if this subscription should be + * deleted. */ + _AwsIotShadow_RemoveSubscription( pSubscription, NULL ); + } + } + + /* Unlock the Shadow subscription list mutex. */ + IotMutex_Unlock( &_AwsIotShadowSubscriptionsMutex ); + + return status; +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t _AwsIotShadow_CreateOperation( _shadowOperation_t ** pNewOperation, + _shadowOperationType_t type, + uint32_t flags, + const AwsIotShadowCallbackInfo_t * pCallbackInfo ) +{ + IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_SUCCESS ); + _shadowOperation_t * pOperation = NULL; + + IotLogDebug( "Creating operation record for Shadow %s.", + _pAwsIotShadowOperationNames[ type ] ); + + /* Allocate memory for a new Shadow operation. */ + pOperation = AwsIotShadow_MallocOperation( sizeof( _shadowOperation_t ) ); + + if( pOperation == NULL ) + { + IotLogError( "Failed to allocate memory for Shadow %s.", + _pAwsIotShadowOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NO_MEMORY ); + } + + /* Clear the operation data. */ + ( void ) memset( pOperation, 0x00, sizeof( _shadowOperation_t ) ); + + /* Check if the waitable flag is set. If it is, create a semaphore to + * wait on. */ + if( ( flags & AWS_IOT_SHADOW_FLAG_WAITABLE ) == AWS_IOT_SHADOW_FLAG_WAITABLE ) + { + if( IotSemaphore_Create( &( pOperation->notify.waitSemaphore ), 0, 1 ) == false ) + { + IotLogError( "Failed to create semaphore for waitable Shadow %s.", + _pAwsIotShadowOperationNames[ type ] ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NO_MEMORY ); + } + } + else + { + /* If the waitable flag isn't set but a callback is, copy the callback + * information. */ + if( pCallbackInfo != NULL ) + { + pOperation->notify.callback = *pCallbackInfo; + } + } + + /* Set the remaining common members of the Shadow operation. */ + pOperation->type = type; + pOperation->flags = flags; + pOperation->status = AWS_IOT_SHADOW_STATUS_PENDING; + + IOT_FUNCTION_CLEANUP_BEGIN(); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + if( pOperation != NULL ) + { + AwsIotShadow_FreeOperation( pOperation ); + } + } + else + { + /* Set the output parameter. */ + *pNewOperation = pOperation; + } + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +void _AwsIotShadow_DestroyOperation( void * pData ) +{ + _shadowOperation_t * pOperation = ( _shadowOperation_t * ) pData; + + /* The Shadow operation pointer must not be NULL. */ + AwsIotShadow_Assert( pOperation != NULL ); + + IotLogDebug( "Destroying Shadow operation %s.", + _pAwsIotShadowOperationNames[ pOperation->type ] ); + + /* Check if a wait semaphore was created for this operation. */ + if( ( pOperation->flags & AWS_IOT_SHADOW_FLAG_WAITABLE ) == AWS_IOT_SHADOW_FLAG_WAITABLE ) + { + /* Destroy the wait semaphore */ + IotSemaphore_Destroy( &( pOperation->notify.waitSemaphore ) ); + } + + /* If this is a Shadow update, free any allocated client token. */ + if( ( pOperation->type == SHADOW_UPDATE ) && + ( pOperation->u.update.pClientToken != NULL ) ) + { + AwsIotShadow_Assert( pOperation->u.update.clientTokenLength > 0 ); + + AwsIotShadow_FreeString( ( void * ) ( pOperation->u.update.pClientToken ) ); + } + + /* Free the memory used to hold operation data. */ + AwsIotShadow_FreeOperation( pOperation ); +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t _AwsIotShadow_GenerateShadowTopic( _shadowOperationType_t type, + const char * pThingName, + size_t thingNameLength, + char ** pTopicBuffer, + uint16_t * pOperationTopicLength ) +{ + AwsIotShadowError_t status = AWS_IOT_SHADOW_SUCCESS; + AwsIotTopicInfo_t topicInfo = { 0 }; + + /* Lookup table for Shadow operation strings. */ + const char * const pOperationString[ SHADOW_OPERATION_COUNT ] = + { + SHADOW_DELETE_OPERATION_STRING, /* Shadow delete operation. */ + SHADOW_GET_OPERATION_STRING, /* Shadow get operation. */ + SHADOW_UPDATE_OPERATION_STRING /* Shadow update operation. */ + }; + + /* Lookup table for Shadow operation string lengths. */ + const uint16_t pOperationStringLength[ SHADOW_OPERATION_COUNT ] = + { + SHADOW_DELETE_OPERATION_STRING_LENGTH, /* Shadow delete operation. */ + SHADOW_GET_OPERATION_STRING_LENGTH, /* Shadow get operation. */ + SHADOW_UPDATE_OPERATION_STRING_LENGTH /* Shadow update operation. */ + }; + + /* Only Shadow delete, get, and update operation types should be passed to this + * function. */ + AwsIotShadow_Assert( ( type == SHADOW_DELETE ) || + ( type == SHADOW_GET ) || + ( type == SHADOW_UPDATE ) ); + + /* Set the members needed to generate an operation topic. */ + topicInfo.pThingName = pThingName; + topicInfo.thingNameLength = thingNameLength; + topicInfo.pOperationName = pOperationString[ type ]; + topicInfo.operationNameLength = pOperationStringLength[ type ]; + topicInfo.longestSuffixLength = SHADOW_LONGEST_SUFFIX_LENGTH; + topicInfo.mallocString = AwsIotShadow_MallocString; + + if( AwsIot_GenerateOperationTopic( &topicInfo, + pTopicBuffer, + pOperationTopicLength ) == false ) + { + status = AWS_IOT_SHADOW_NO_MEMORY; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t _AwsIotShadow_ProcessOperation( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + _shadowOperation_t * pOperation, + const AwsIotShadowDocumentInfo_t * pDocumentInfo ) +{ + IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_STATUS_PENDING ); + IotMqttError_t publishStatus = IOT_MQTT_STATUS_PENDING; + char * pTopicBuffer = NULL; + uint16_t operationTopicLength = 0; + bool freeTopicBuffer = true; + IotMqttPublishInfo_t publishInfo = IOT_MQTT_PUBLISH_INFO_INITIALIZER; + + IotLogDebug( "Processing Shadow operation %s for Thing %.*s.", + _pAwsIotShadowOperationNames[ pOperation->type ], + thingNameLength, + pThingName ); + + /* Set the operation's MQTT connection. */ + pOperation->mqttConnection = mqttConnection; + + /* Generate the operation topic buffer. */ + status = _AwsIotShadow_GenerateShadowTopic( pOperation->type, + pThingName, + thingNameLength, + &pTopicBuffer, + &operationTopicLength ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + IotLogError( "No memory for Shadow operation topic buffer." ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_NO_MEMORY ); + } + + /* Get a subscription object for this Shadow operation. */ + status = _findSubscription( pThingName, + thingNameLength, + pTopicBuffer, + operationTopicLength, + pOperation, + &freeTopicBuffer ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + /* No subscription was found and no subscription could be allocated. */ + IOT_GOTO_CLEANUP(); + } + + /* Set the operation topic name. */ + publishInfo.pTopicName = pTopicBuffer; + publishInfo.topicNameLength = operationTopicLength; + + IotLogDebug( "Shadow %s message will be published to topic %.*s", + _pAwsIotShadowOperationNames[ pOperation->type ], + publishInfo.topicNameLength, + publishInfo.pTopicName ); + + /* Set the document info if this operation is not a Shadow DELETE. */ + if( pOperation->type != SHADOW_DELETE ) + { + publishInfo.qos = pDocumentInfo->qos; + publishInfo.retryLimit = pDocumentInfo->retryLimit; + publishInfo.retryMs = pDocumentInfo->retryMs; + + IotLogDebug( "Shadow %s message will be published at QoS %d with " + "retryLimit %d and retryMs %llu.", + _pAwsIotShadowOperationNames[ pOperation->type ], + publishInfo.qos, + publishInfo.retryLimit, + publishInfo.retryMs ); + } + + /* Set the PUBLISH payload to the update document for Shadow UPDATE. */ + if( pOperation->type == SHADOW_UPDATE ) + { + publishInfo.pPayload = pDocumentInfo->u.update.pUpdateDocument; + publishInfo.payloadLength = pDocumentInfo->u.update.updateDocumentLength; + } + + /* Set the PUBLISH payload to an empty string for Shadow DELETE and GET, + * per the Shadow spec. */ + else + { + publishInfo.pPayload = ""; + publishInfo.payloadLength = 0; + } + + /* Add Shadow operation to the pending operations list. */ + IotMutex_Lock( &( _AwsIotShadowPendingOperationsMutex ) ); + IotListDouble_InsertHead( &( _AwsIotShadowPendingOperations ), + &( pOperation->link ) ); + IotMutex_Unlock( &( _AwsIotShadowPendingOperationsMutex ) ); + + /* Publish to the Shadow topic name. */ + publishStatus = IotMqtt_PublishSync( pOperation->mqttConnection, + &publishInfo, + 0, + _AwsIotShadowMqttTimeoutMs ); + + /* Check for errors from the MQTT publish. */ + if( publishStatus != IOT_MQTT_SUCCESS ) + { + IotLogError( "Failed to publish MQTT message to %s %.*s Shadow, error %s.", + _pAwsIotShadowOperationNames[ pOperation->type ], + thingNameLength, + pThingName, + IotMqtt_strerror( publishStatus ) ); + + /* Convert the MQTT "NO MEMORY" error to a Shadow "NO MEMORY" error. */ + status = SHADOW_CONVERT_STATUS_CODE_MQTT_TO_SHADOW( publishStatus ); + + /* If the "keep subscriptions" flag is not set, decrement the reference + * count. */ + if( ( pOperation->flags & AWS_IOT_SHADOW_FLAG_KEEP_SUBSCRIPTIONS ) == 0 ) + { + IotMutex_Lock( &_AwsIotShadowSubscriptionsMutex ); + _AwsIotShadow_DecrementReferences( pOperation, + pTopicBuffer, + NULL ); + IotMutex_Unlock( &_AwsIotShadowSubscriptionsMutex ); + } + + /* Remove Shadow operation from the pending operations list. */ + IotMutex_Lock( &( _AwsIotShadowPendingOperationsMutex ) ); + IotListDouble_Remove( &( pOperation->link ) ); + IotMutex_Unlock( &( _AwsIotShadowPendingOperationsMutex ) ); + } + else + { + IotLogDebug( "Shadow %s PUBLISH message successfully sent.", + _pAwsIotShadowOperationNames[ pOperation->type ] ); + } + + IOT_FUNCTION_CLEANUP_BEGIN(); + + /* Free the topic buffer used by this function if it was not assigned to a + * subscription. */ + if( ( freeTopicBuffer == true ) && ( pTopicBuffer != NULL ) ) + { + AwsIotShadow_FreeString( pTopicBuffer ); + } + + /* Destroy the Shadow operation on failure. */ + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + _AwsIotShadow_DestroyOperation( pOperation ); + } + else + { + /* Convert successful return code to "status pending", as the Shadow + * library is now waiting for a response from the service. */ + status = AWS_IOT_SHADOW_STATUS_PENDING; + } + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_parser.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_parser.c new file mode 100644 index 000000000..3506e131d --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_parser.c @@ -0,0 +1,195 @@ +/* + * AWS IoT Shadow V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_shadow_parser.c + * @brief Implements JSON parsing functions of the Shadow library. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include + +/* Shadow internal include. */ +#include "private/aws_iot_shadow_internal.h" + +/* Error handling include. */ +#include "iot_error.h" + +/* AWS Parser include. */ +#include "aws_iot_doc_parser.h" + +/*-----------------------------------------------------------*/ + +/** + * @brief The JSON key for the error code in a Shadow error document. + */ +#define ERROR_DOCUMENT_CODE_KEY "code" + +/** + * @brief The length of #ERROR_DOCUMENT_CODE_KEY. + */ +#define ERROR_DOCUMENT_CODE_KEY_LENGTH ( sizeof( ERROR_DOCUMENT_CODE_KEY ) - 1 ) + +/** + * @brief The JSON key for the error message in a Shadow error document. + */ +#define ERROR_DOCUMENT_MESSAGE_KEY "message" + +/** + * @brief The length of #ERROR_DOCUMENT_MESSAGE_KEY. + */ +#define ERROR_DOCUMENT_MESSAGE_KEY_LENGTH ( sizeof( ERROR_DOCUMENT_MESSAGE_KEY ) - 1 ) + +/*-----------------------------------------------------------*/ + +/** + * @brief Converts a `unsigned long` to an `AwsIotShadowError_t`. + * + * @param[in] code A value between 400 and 500 to convert. + * + * @return A corresponding #AwsIotShadowError_t; #AWS_IOT_SHADOW_BAD_RESPONSE + * if `code` is unknown. + */ +static AwsIotShadowError_t _codeToShadowStatus( uint32_t code ); + +/*-----------------------------------------------------------*/ + +static AwsIotShadowError_t _codeToShadowStatus( uint32_t code ) +{ + AwsIotShadowError_t errorCode = AWS_IOT_SHADOW_STATUS_PENDING; + + /* Convert the Shadow response code to an AwsIotShadowError_t. */ + switch( code ) + { + case 400UL: + errorCode = AWS_IOT_SHADOW_BAD_REQUEST; + break; + + case 401UL: + errorCode = AWS_IOT_SHADOW_UNAUTHORIZED; + break; + + case 403UL: + errorCode = AWS_IOT_SHADOW_FORBIDDEN; + break; + + case 404UL: + errorCode = AWS_IOT_SHADOW_NOT_FOUND; + break; + + case 409UL: + errorCode = AWS_IOT_SHADOW_CONFLICT; + break; + + case 413UL: + errorCode = AWS_IOT_SHADOW_TOO_LARGE; + break; + + case 415UL: + errorCode = AWS_IOT_SHADOW_UNSUPPORTED; + break; + + case 429UL: + errorCode = AWS_IOT_SHADOW_TOO_MANY_REQUESTS; + break; + + case 500UL: + errorCode = AWS_IOT_SHADOW_SERVER_ERROR; + break; + + default: + errorCode = AWS_IOT_SHADOW_BAD_RESPONSE; + break; + } + + return errorCode; +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t _AwsIotShadow_ParseErrorDocument( const char * pErrorDocument, + size_t errorDocumentLength ) +{ + IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_STATUS_PENDING ); + const char * pCode = NULL, * pMessage = NULL; + size_t codeLength = 0, messageLength = 0; + uint32_t code = 0; + + /* Parse the code from the error document. */ + if( AwsIotDocParser_FindValue( pErrorDocument, + errorDocumentLength, + ERROR_DOCUMENT_CODE_KEY, + ERROR_DOCUMENT_CODE_KEY_LENGTH, + &pCode, + &codeLength ) == false ) + { + /* Error parsing JSON document, or no "code" key was found. */ + IotLogWarn( "Failed to parse code from error document.\n%.*s", + errorDocumentLength, + pErrorDocument ); + + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_RESPONSE ); + } + + /* Code must be in error document. */ + AwsIotShadow_Assert( ( pCode > pErrorDocument ) && + ( pCode + codeLength < pErrorDocument + errorDocumentLength ) ); + + /* Convert the code to an unsigned integer value. */ + code = ( uint32_t ) strtoul( pCode, NULL, 10 ); + + /* Parse the error message and print it. An error document must always contain + * a message. */ + if( AwsIotDocParser_FindValue( pErrorDocument, + errorDocumentLength, + ERROR_DOCUMENT_MESSAGE_KEY, + ERROR_DOCUMENT_MESSAGE_KEY_LENGTH, + &pMessage, + &messageLength ) == true ) + { + IotLogWarn( "Code %lu: %.*s.", + code, + messageLength, + pMessage ); + } + else + { + IotLogWarn( "Code %lu; failed to parse message from error document.\n%.*s", + code, + errorDocumentLength, + pErrorDocument ); + + /* An error document must contain a message; if it does not, then it is invalid. */ + IOT_SET_AND_GOTO_CLEANUP( AWS_IOT_SHADOW_BAD_RESPONSE ); + } + + /* Convert a successfully parsed JSON code to a Shadow status. */ + status = _codeToShadowStatus( code ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_static_memory.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_static_memory.c new file mode 100644 index 000000000..9e8c7e7a9 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_static_memory.c @@ -0,0 +1,160 @@ +/* + * AWS IoT Shadow V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_shadow_static_memory.c + * @brief Implementation of Shadow static memory functions. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* This file should only be compiled if dynamic memory allocation is forbidden. */ +#if IOT_STATIC_MEMORY_ONLY == 1 + +/* Standard includes. */ +#include +#include +#include + +/* Static memory include. */ +#include "iot_static_memory.h" + +/* Shadow internal include. */ +#include "private/aws_iot_shadow_internal.h" + +/*-----------------------------------------------------------*/ + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * Provide default values for undefined configuration constants. + */ +#ifndef AWS_IOT_SHADOW_MAX_IN_PROGRESS_OPERATIONS + #define AWS_IOT_SHADOW_MAX_IN_PROGRESS_OPERATIONS ( 10 ) +#endif +#ifndef AWS_IOT_SHADOW_SUBSCRIPTIONS + #define AWS_IOT_SHADOW_SUBSCRIPTIONS ( 2 ) +#endif +/** @endcond */ + +/* Validate static memory configuration settings. */ +#if AWS_IOT_SHADOW_MAX_IN_PROGRESS_OPERATIONS <= 0 + #error "AWS_IOT_SHADOW_MAX_IN_PROGRESS_OPERATIONS cannot be 0 or negative." +#endif +#if AWS_IOT_SHADOW_SUBSCRIPTIONS <= 0 + #error "AWS_IOT_SHADOW_SUBSCRIPTIONS cannot be 0 or negative." +#endif + +/** + * @brief The size of a static memory Shadow subscription. + * + * Since the pThingName member of #_shadowSubscription_t is variable-length, + * the constant `AWS_IOT_MAX_THING_NAME_LENGTH` is used for the length of + * #_shadowSubscription_t.pThingName. + */ +#define SHADOW_SUBSCRIPTION_SIZE ( sizeof( _shadowSubscription_t ) + AWS_IOT_MAX_THING_NAME_LENGTH ) + +/*-----------------------------------------------------------*/ + +/* + * Static memory buffers and flags, allocated and zeroed at compile-time. + */ +static uint32_t _pInUseShadowOperations[ AWS_IOT_SHADOW_MAX_IN_PROGRESS_OPERATIONS ] = { 0U }; /**< @brief Shadow operation in-use flags. */ +static _shadowOperation_t _pShadowOperations[ AWS_IOT_SHADOW_MAX_IN_PROGRESS_OPERATIONS ] = { { .link = { 0 } } }; /**< @brief Shadow operations. */ + +static uint32_t _pInUseShadowSubscriptions[ AWS_IOT_SHADOW_SUBSCRIPTIONS ] = { 0U }; /**< @brief Shadow subscription in-use flags. */ +static char _pShadowSubscriptions[ AWS_IOT_SHADOW_SUBSCRIPTIONS ][ SHADOW_SUBSCRIPTION_SIZE ] = { { 0 } }; /**< @brief Shadow subscriptions. */ + +/*-----------------------------------------------------------*/ + +void * AwsIotShadow_MallocOperation( size_t size ) +{ + int32_t freeIndex = -1; + void * pNewOperation = NULL; + + /* Check size argument. */ + if( size == sizeof( _shadowOperation_t ) ) + { + /* Find a free Shadow operation. */ + freeIndex = IotStaticMemory_FindFree( _pInUseShadowOperations, + AWS_IOT_SHADOW_MAX_IN_PROGRESS_OPERATIONS ); + + if( freeIndex != -1 ) + { + pNewOperation = &( _pShadowOperations[ freeIndex ] ); + } + } + + return pNewOperation; +} + +/*-----------------------------------------------------------*/ + +void AwsIotShadow_FreeOperation( void * ptr ) +{ + /* Return the in-use Shadow operation. */ + IotStaticMemory_ReturnInUse( ptr, + _pShadowOperations, + _pInUseShadowOperations, + AWS_IOT_SHADOW_MAX_IN_PROGRESS_OPERATIONS, + sizeof( _shadowOperation_t ) ); +} + +/*-----------------------------------------------------------*/ + +void * AwsIotShadow_MallocSubscription( size_t size ) +{ + int32_t freeIndex = -1; + void * pNewSubscription = NULL; + + if( size <= SHADOW_SUBSCRIPTION_SIZE ) + { + /* Get the index of a free Shadow subscription. */ + freeIndex = IotStaticMemory_FindFree( _pInUseShadowSubscriptions, + AWS_IOT_SHADOW_SUBSCRIPTIONS ); + + if( freeIndex != -1 ) + { + pNewSubscription = &( _pShadowSubscriptions[ freeIndex ][ 0 ] ); + } + } + + return pNewSubscription; +} + +/*-----------------------------------------------------------*/ + +void AwsIotShadow_FreeSubscription( void * ptr ) +{ + /* Return the in-use Shadow subscription. */ + IotStaticMemory_ReturnInUse( ptr, + _pShadowSubscriptions, + _pInUseShadowSubscriptions, + AWS_IOT_SHADOW_SUBSCRIPTIONS, + SHADOW_SUBSCRIPTION_SIZE ); +} + +/*-----------------------------------------------------------*/ + +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_subscription.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_subscription.c new file mode 100644 index 000000000..882939942 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/aws_iot_shadow_subscription.c @@ -0,0 +1,512 @@ +/* + * AWS IoT Shadow V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_shadow_subscription.c + * @brief Implements functions for interacting with the Shadow library's + * subscription list. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* Shadow internal include. */ +#include "private/aws_iot_shadow_internal.h" + +/* Error handling include. */ +#include "iot_error.h" + +/* Platform layer includes. */ +#include "platform/iot_threads.h" + +/* MQTT include. */ +#include "iot_mqtt.h" + +/*-----------------------------------------------------------*/ + +/** + * @brief Match two #_shadowSubscription_t by Thing Name. + * + * @param[in] pSubscriptionLink Pointer to the link member of a #_shadowSubscription_t + * containing the Thing Name to check. + * @param[in] pMatch Pointer to an `AwsIotThingName_t`. + * + * @return `true` if the Thing Names match; `false` otherwise. + */ +static bool _shadowSubscription_match( const IotLink_t * pSubscriptionLink, + void * pMatch ); + +/*-----------------------------------------------------------*/ + +/** + * @brief List of active Shadow subscriptions objects. + */ +IotListDouble_t _AwsIotShadowSubscriptions = { 0 }; + +/** + * @brief Protects #_AwsIotShadowSubscriptions from concurrent access. + */ +IotMutex_t _AwsIotShadowSubscriptionsMutex; + +/*-----------------------------------------------------------*/ + +static bool _shadowSubscription_match( const IotLink_t * pSubscriptionLink, + void * pMatch ) +{ + bool match = false; + + /* Because this function is called from a container function, the given link + * must never be NULL. */ + AwsIotShadow_Assert( pSubscriptionLink != NULL ); + + const _shadowSubscription_t * pSubscription = IotLink_Container( _shadowSubscription_t, + pSubscriptionLink, + link ); + const AwsIotThingName_t * pThingName = ( AwsIotThingName_t * ) pMatch; + + if( pThingName->thingNameLength == pSubscription->thingNameLength ) + { + /* Check for matching Thing Names. */ + match = ( strncmp( pThingName->pThingName, + pSubscription->pThingName, + pThingName->thingNameLength ) == 0 ); + } + + return match; +} + +/*-----------------------------------------------------------*/ + +_shadowSubscription_t * _AwsIotShadow_FindSubscription( const char * pThingName, + size_t thingNameLength, + bool createIfNotFound ) +{ + _shadowSubscription_t * pSubscription = NULL; + IotLink_t * pSubscriptionLink = NULL; + AwsIotThingName_t thingName = { 0 }; + + thingName.pThingName = pThingName; + thingName.thingNameLength = thingNameLength; + + /* Search the list for an existing subscription for Thing Name. */ + pSubscriptionLink = IotListDouble_FindFirstMatch( &( _AwsIotShadowSubscriptions ), + NULL, + _shadowSubscription_match, + &thingName ); + + /* Check if a subscription was found. */ + if( pSubscriptionLink == NULL ) + { + if( createIfNotFound == true ) + { + /* No subscription found. Allocate a new subscription. */ + pSubscription = AwsIotShadow_MallocSubscription( sizeof( _shadowSubscription_t ) + thingNameLength ); + + if( pSubscription != NULL ) + { + /* Clear the new subscription. */ + ( void ) memset( pSubscription, 0x00, sizeof( _shadowSubscription_t ) + thingNameLength ); + + /* Set the Thing Name length and copy the Thing Name into the new subscription. */ + pSubscription->thingNameLength = thingNameLength; + ( void ) memcpy( pSubscription->pThingName, pThingName, thingNameLength ); + + /* Add the new subscription to the subscription list. */ + IotListDouble_InsertHead( &( _AwsIotShadowSubscriptions ), + &( pSubscription->link ) ); + + IotLogDebug( "Created new Shadow subscriptions object for %.*s.", + thingNameLength, + pThingName ); + } + else + { + IotLogError( "Failed to allocate memory for %.*s Shadow subscriptions.", + thingNameLength, + pThingName ); + } + } + } + else + { + IotLogDebug( "Found existing Shadow subscriptions object for %.*s.", + thingNameLength, + pThingName ); + + pSubscription = IotLink_Container( _shadowSubscription_t, pSubscriptionLink, link ); + } + + return pSubscription; +} + +/*-----------------------------------------------------------*/ + +void _AwsIotShadow_RemoveSubscription( _shadowSubscription_t * pSubscription, + _shadowSubscription_t ** pRemovedSubscription ) +{ + int32_t i = 0; + bool removeSubscription = true; + + IotLogDebug( "Checking if subscription object for %.*s can be removed.", + pSubscription->thingNameLength, + pSubscription->pThingName ); + + /* Check for active operations. If any Shadow operation's subscription + * reference count is not 0, then the subscription cannot be removed. */ + for( i = 0; i < SHADOW_OPERATION_COUNT; i++ ) + { + if( pSubscription->references[ i ] > 0 ) + { + IotLogDebug( "Reference count %ld for %.*s subscription object. " + "Subscription cannot be removed yet.", + ( long int ) pSubscription->references[ i ], + pSubscription->thingNameLength, + pSubscription->pThingName ); + + removeSubscription = false; + } + else if( pSubscription->references[ i ] == AWS_IOT_PERSISTENT_SUBSCRIPTION ) + { + IotLogDebug( "Subscription object for %.*s has persistent subscriptions. " + "Subscription will not be removed.", + pSubscription->thingNameLength, + pSubscription->pThingName ); + + removeSubscription = false; + } + + if( removeSubscription == false ) + { + break; + } + } + + /* Check for active subscriptions. If any Shadow callbacks are active, then the + * subscription cannot be removed. */ + if( removeSubscription == true ) + { + for( i = 0; i < SHADOW_CALLBACK_COUNT; i++ ) + { + if( pSubscription->callbacks[ i ].function != NULL ) + { + IotLogDebug( "Found active Shadow %s callback for %.*s subscription object. " + "Subscription cannot be removed yet.", + _pAwsIotShadowCallbackNames[ i ], + pSubscription->thingNameLength, + pSubscription->pThingName ); + + removeSubscription = false; + break; + } + } + } + + /* Remove the subscription if unused. */ + if( removeSubscription == true ) + { + /* No Shadow operation subscription references or active Shadow callbacks. + * Remove the subscription object. */ + IotListDouble_Remove( &( pSubscription->link ) ); + + IotLogDebug( "Removed subscription object for %.*s.", + pSubscription->thingNameLength, + pSubscription->pThingName ); + + /* If the caller requested the removed subscription, set the output parameter. + * Otherwise, free the memory used by the subscription. */ + if( pRemovedSubscription != NULL ) + { + *pRemovedSubscription = pSubscription; + } + else + { + _AwsIotShadow_DestroySubscription( pSubscription ); + } + } +} + +/*-----------------------------------------------------------*/ + +void _AwsIotShadow_DestroySubscription( void * pData ) +{ + _shadowSubscription_t * pSubscription = ( _shadowSubscription_t * ) pData; + + /* Free the topic buffer if allocated. */ + if( pSubscription->pTopicBuffer != NULL ) + { + AwsIotShadow_FreeString( pSubscription->pTopicBuffer ); + } + + /* Free memory used by subscription. */ + AwsIotShadow_FreeSubscription( pSubscription ); +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t _AwsIotShadow_IncrementReferences( _shadowOperation_t * pOperation, + char * pTopicBuffer, + uint16_t operationTopicLength, + AwsIotMqttCallbackFunction_t callback ) +{ + IOT_FUNCTION_ENTRY( AwsIotShadowError_t, AWS_IOT_SHADOW_SUCCESS ); + const _shadowOperationType_t type = pOperation->type; + _shadowSubscription_t * pSubscription = pOperation->pSubscription; + IotMqttError_t subscriptionStatus = IOT_MQTT_STATUS_PENDING; + AwsIotSubscriptionInfo_t subscriptionInfo = { 0 }; + + /* Do nothing if this operation has persistent subscriptions. */ + if( pSubscription->references[ type ] == AWS_IOT_PERSISTENT_SUBSCRIPTION ) + { + IotLogDebug( "Shadow %s for %.*s has persistent subscriptions. Reference " + "count will not be incremented.", + _pAwsIotShadowOperationNames[ type ], + pSubscription->thingNameLength, + pSubscription->pThingName ); + + IOT_GOTO_CLEANUP(); + } + + /* When persistent subscriptions are not present, the reference count must + * not be negative. */ + AwsIotShadow_Assert( pSubscription->references[ type ] >= 0 ); + + /* Check if there are any existing references for this operation. */ + if( pSubscription->references[ type ] == 0 ) + { + /* Set the parameters needed to add subscriptions. */ + subscriptionInfo.mqttConnection = pOperation->mqttConnection; + subscriptionInfo.callbackFunction = callback; + subscriptionInfo.timeout = _AwsIotShadowMqttTimeoutMs; + subscriptionInfo.pTopicFilterBase = pTopicBuffer; + subscriptionInfo.topicFilterBaseLength = operationTopicLength; + + subscriptionStatus = AwsIot_ModifySubscriptions( IotMqtt_SubscribeSync, + &subscriptionInfo ); + + /* Convert MQTT return code to Shadow return code. */ + status = SHADOW_CONVERT_STATUS_CODE_MQTT_TO_SHADOW( subscriptionStatus ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + } + + /* Increment the number of subscription references for this operation when + * the keep subscriptions flag is not set. */ + if( ( pOperation->flags & AWS_IOT_SHADOW_FLAG_KEEP_SUBSCRIPTIONS ) == 0 ) + { + ( pSubscription->references[ type ] )++; + + IotLogDebug( "Shadow %s subscriptions for %.*s now has count %d.", + _pAwsIotShadowOperationNames[ type ], + pSubscription->thingNameLength, + pSubscription->pThingName, + pSubscription->references[ type ] ); + } + /* Otherwise, set the persistent subscriptions flag. */ + else + { + pSubscription->references[ type ] = AWS_IOT_PERSISTENT_SUBSCRIPTION; + + IotLogDebug( "Set persistent subscriptions flag for Shadow %s of %.*s.", + _pAwsIotShadowOperationNames[ type ], + pSubscription->thingNameLength, + pSubscription->pThingName ); + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +void _AwsIotShadow_DecrementReferences( _shadowOperation_t * pOperation, + char * pTopicBuffer, + _shadowSubscription_t ** pRemovedSubscription ) +{ + const _shadowOperationType_t type = pOperation->type; + _shadowSubscription_t * pSubscription = pOperation->pSubscription; + uint16_t operationTopicLength = 0; + AwsIotSubscriptionInfo_t subscriptionInfo = { 0 }; + + /* Do nothing if this Shadow operation has persistent subscriptions. */ + if( pSubscription->references[ type ] != AWS_IOT_PERSISTENT_SUBSCRIPTION ) + { + /* Decrement the number of subscription references for this operation. + * Ensure that it's positive. */ + ( pSubscription->references[ type ] )--; + AwsIotShadow_Assert( pSubscription->references[ type ] >= 0 ); + + /* Check if the number of references has reached 0. */ + if( pSubscription->references[ type ] == 0 ) + { + IotLogDebug( "Reference count for %.*s %s is 0. Unsubscribing.", + pSubscription->thingNameLength, + pSubscription->pThingName, + _pAwsIotShadowOperationNames[ type ] ); + + /* Subscription must have a topic buffer. */ + AwsIotShadow_Assert( pSubscription->pTopicBuffer != NULL ); + + /* Generate the prefix of the Shadow topic. This function will not + * fail when given a buffer. */ + ( void ) _AwsIotShadow_GenerateShadowTopic( ( _shadowOperationType_t ) type, + pSubscription->pThingName, + pSubscription->thingNameLength, + &( pSubscription->pTopicBuffer ), + &operationTopicLength ); + + /* Set the parameters needed to remove subscriptions. */ + subscriptionInfo.mqttConnection = pOperation->mqttConnection; + subscriptionInfo.timeout = _AwsIotShadowMqttTimeoutMs; + subscriptionInfo.pTopicFilterBase = pTopicBuffer; + subscriptionInfo.topicFilterBaseLength = operationTopicLength; + + ( void ) AwsIot_ModifySubscriptions( IotMqtt_UnsubscribeSync, + &subscriptionInfo ); + } + + /* Check if this subscription should be deleted. */ + _AwsIotShadow_RemoveSubscription( pSubscription, + pRemovedSubscription ); + } + else + { + IotLogDebug( "Shadow %s for %.*s has persistent subscriptions. Reference " + "count will not be decremented.", + _pAwsIotShadowOperationNames[ type ], + pSubscription->thingNameLength, + pSubscription->pThingName ); + } +} + +/*-----------------------------------------------------------*/ + +AwsIotShadowError_t AwsIotShadow_RemovePersistentSubscriptions( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + uint32_t flags ) +{ + int32_t i = 0; + uint16_t operationTopicLength = 0; + AwsIotShadowError_t status = AWS_IOT_SHADOW_STATUS_PENDING; + IotMqttError_t unsubscribeStatus = IOT_MQTT_STATUS_PENDING; + AwsIotSubscriptionInfo_t subscriptionInfo = { 0 }; + _shadowSubscription_t * pSubscription = NULL; + IotLink_t * pSubscriptionLink = NULL; + AwsIotThingName_t thingName = { 0 }; + + thingName.pThingName = pThingName; + thingName.thingNameLength = thingNameLength; + + IotLogInfo( "Removing persistent subscriptions for %.*s.", + thingNameLength, + pThingName ); + + IotMutex_Lock( &( _AwsIotShadowSubscriptionsMutex ) ); + + /* Search the list for an existing subscription for Thing Name. */ + pSubscriptionLink = IotListDouble_FindFirstMatch( &( _AwsIotShadowSubscriptions ), + NULL, + _shadowSubscription_match, + &thingName ); + + /* Unsubscribe from operation subscriptions if found. */ + if( pSubscriptionLink != NULL ) + { + IotLogDebug( "Found subscription object for %.*s. Checking for persistent " + "subscriptions to remove.", + thingNameLength, + pThingName ); + + pSubscription = IotLink_Container( _shadowSubscription_t, pSubscriptionLink, link ); + + for( i = 0; i < SHADOW_OPERATION_COUNT; i++ ) + { + if( ( flags & ( 0x1UL << i ) ) != 0 ) + { + IotLogDebug( "Removing %.*s %s persistent subscriptions.", + thingNameLength, + pThingName, + _pAwsIotShadowOperationNames[ i ] ); + + /* Subscription must have a topic buffer. */ + AwsIotShadow_Assert( pSubscription->pTopicBuffer != NULL ); + + if( pSubscription->references[ i ] == AWS_IOT_PERSISTENT_SUBSCRIPTION ) + { + /* Generate the prefix of the Shadow topic. This function will not + * fail when given a buffer. */ + ( void ) _AwsIotShadow_GenerateShadowTopic( ( _shadowOperationType_t ) i, + pThingName, + thingNameLength, + &( pSubscription->pTopicBuffer ), + &operationTopicLength ); + + /* Set the parameters needed to remove subscriptions. */ + subscriptionInfo.mqttConnection = mqttConnection; + subscriptionInfo.timeout = _AwsIotShadowMqttTimeoutMs; + subscriptionInfo.pTopicFilterBase = pSubscription->pTopicBuffer; + subscriptionInfo.topicFilterBaseLength = operationTopicLength; + + unsubscribeStatus = AwsIot_ModifySubscriptions( IotMqtt_UnsubscribeSync, + &subscriptionInfo ); + + /* Convert MQTT return code to Shadow return code. */ + status = SHADOW_CONVERT_STATUS_CODE_MQTT_TO_SHADOW( unsubscribeStatus ); + + if( status != AWS_IOT_SHADOW_SUCCESS ) + { + break; + } + + /* Clear the persistent subscriptions flag and check if the + * subscription can be removed. */ + pSubscription->references[ i ] = 0; + _AwsIotShadow_RemoveSubscription( pSubscription, NULL ); + } + else + { + IotLogDebug( "%.*s %s does not have persistent subscriptions.", + thingNameLength, + pThingName, + _pAwsIotShadowOperationNames[ i ] ); + } + } + } + } + else + { + IotLogWarn( "No subscription object found for %.*s", + thingNameLength, + pThingName ); + } + + IotMutex_Unlock( &( _AwsIotShadowSubscriptionsMutex ) ); + + return status; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/private/aws_iot_shadow_internal.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/private/aws_iot_shadow_internal.h new file mode 100644 index 000000000..f3795f371 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/aws/shadow/src/private/aws_iot_shadow_internal.h @@ -0,0 +1,565 @@ +/* + * AWS IoT Shadow V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file aws_iot_shadow_internal.h + * @brief Internal header of Shadow library. This header should not be included in + * typical application code. + */ + +#ifndef AWS_IOT_SHADOW_INTERNAL_H_ +#define AWS_IOT_SHADOW_INTERNAL_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Linear containers (lists and queues) include. */ +#include "iot_linear_containers.h" + +/* Platform layer types include. */ +#include "types/iot_platform_types.h" + +/* Shadow include. */ +#include "aws_iot_shadow.h" + +/* AWS IoT include. */ +#include "aws_iot.h" + +/** + * @def AwsIotShadow_Assert( expression ) + * @brief Assertion macro for the Shadow library. + * + * Set @ref AWS_IOT_SHADOW_ENABLE_ASSERTS to `1` to enable assertions in the Shadow + * library. + * + * @param[in] expression Expression to be evaluated. + */ +#if AWS_IOT_SHADOW_ENABLE_ASSERTS == 1 + #ifndef AwsIotShadow_Assert + #ifdef Iot_DefaultAssert + #define AwsIotShadow_Assert( expression ) Iot_DefaultAssert( expression ) + #else + #error "Asserts are enabled for Shadow, but AwsIotShadow_Assert is not defined" + #endif + #endif +#else /* if AWS_IOT_SHADOW_ENABLE_ASSERTS == 1 */ + #define AwsIotShadow_Assert( expression ) +#endif /* if AWS_IOT_SHADOW_ENABLE_ASSERTS == 1 */ + +/* Configure logs for Shadow functions. */ +#ifdef AWS_IOT_LOG_LEVEL_SHADOW + #define LIBRARY_LOG_LEVEL AWS_IOT_LOG_LEVEL_SHADOW +#else + #ifdef IOT_LOG_LEVEL_GLOBAL + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_GLOBAL + #else + #define LIBRARY_LOG_LEVEL IOT_LOG_NONE + #endif +#endif + +#define LIBRARY_LOG_NAME ( "Shadow" ) +#include "iot_logging_setup.h" + +/* + * Provide default values for undefined memory allocation functions based on + * the usage of dynamic memory allocation. + */ +#if IOT_STATIC_MEMORY_ONLY == 1 + #include "iot_static_memory.h" + +/** + * @brief Allocate a #_shadowOperation_t. This function should have the same + * signature as [malloc] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html). + */ + void * AwsIotShadow_MallocOperation( size_t size ); + +/** + * @brief Free a #_shadowOperation_t. This function should have the same + * signature as [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ + void AwsIotShadow_FreeOperation( void * ptr ); + +/** + * @brief Allocate a buffer for a short string, used for topic names or client + * tokens. This function should have the same signature as [malloc] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html). + */ + #define AwsIotShadow_MallocString Iot_MallocMessageBuffer + +/** + * @brief Free a string. This function should have the same signature as + * [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ + #define AwsIotShadow_FreeString Iot_FreeMessageBuffer + +/** + * @brief Allocate a #_shadowSubscription_t. This function should have the + * same signature as [malloc] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html). + */ + void * AwsIotShadow_MallocSubscription( size_t size ); + +/** + * @brief Free a #_shadowSubscription_t. This function should have the same + * signature as [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ + void AwsIotShadow_FreeSubscription( void * ptr ); +#else /* if IOT_STATIC_MEMORY_ONLY == 1 */ + #ifndef AwsIotShadow_MallocOperation + #ifdef Iot_DefaultMalloc + #define AwsIotShadow_MallocOperation Iot_DefaultMalloc + #else + #error "No malloc function defined for AwsIotShadow_MallocOperation" + #endif + #endif + + #ifndef AwsIotShadow_FreeOperation + #ifdef Iot_DefaultFree + #define AwsIotShadow_FreeOperation Iot_DefaultFree + #else + #error "No free function defined for AwsIotShadow_FreeOperation" + #endif + #endif + + #ifndef AwsIotShadow_MallocString + #ifdef Iot_DefaultMalloc + #define AwsIotShadow_MallocString Iot_DefaultMalloc + #else + #error "No malloc function defined for AwsIotShadow_MallocString" + #endif + #endif + + #ifndef AwsIotShadow_FreeString + #ifdef Iot_DefaultFree + #define AwsIotShadow_FreeString Iot_DefaultFree + #else + #error "No free function defined for AwsIotShadow_FreeString" + #endif + #endif + + #ifndef AwsIotShadow_MallocSubscription + #ifdef Iot_DefaultMalloc + #define AwsIotShadow_MallocSubscription Iot_DefaultMalloc + #else + #error "No malloc function defined for AwsIotShadow_MallocSubscription" + #endif + #endif + + #ifndef AwsIotShadow_FreeSubscription + #ifdef Iot_DefaultFree + #define AwsIotShadow_FreeSubscription Iot_DefaultFree + #else + #error "No free function defined for AwsIotShadow_FreeSubscription" + #endif + #endif +#endif /* if IOT_STATIC_MEMORY_ONLY == 1 */ + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * Provide default values for undefined configuration constants. + */ +#ifndef AWS_IOT_SHADOW_DEFAULT_MQTT_TIMEOUT_MS + #define AWS_IOT_SHADOW_DEFAULT_MQTT_TIMEOUT_MS ( 5000 ) +#endif +/** @endcond */ + +/** + * @brief The number of currently available Shadow operations. + * + * The 3 Shadow operations are DELETE, GET, and UPDATE. + */ +#define SHADOW_OPERATION_COUNT ( 3 ) + +/** + * @brief The number of currently available Shadow callbacks. + * + * The 2 Shadow callbacks are `update/delta` (AKA "Delta") and `/update/documents` + * (AKA "Updated"). + */ +#define SHADOW_CALLBACK_COUNT ( 2 ) + +/** + * @brief The string representing a Shadow DELETE operation in a Shadow MQTT topic. + */ +#define SHADOW_DELETE_OPERATION_STRING "/shadow/delete" + +/** + * @brief The length of #SHADOW_DELETE_OPERATION_STRING. + */ +#define SHADOW_DELETE_OPERATION_STRING_LENGTH ( ( uint16_t ) ( sizeof( SHADOW_DELETE_OPERATION_STRING ) - 1 ) ) + +/** + * @brief The string representing a Shadow GET operation in a Shadow MQTT topic. + */ +#define SHADOW_GET_OPERATION_STRING "/shadow/get" + +/** + * @brief The length of #SHADOW_GET_OPERATION_STRING. + */ +#define SHADOW_GET_OPERATION_STRING_LENGTH ( ( uint16_t ) ( sizeof( SHADOW_GET_OPERATION_STRING ) - 1 ) ) + +/** + * @brief The string representing a Shadow UPDATE operation in a Shadow MQTT topic. + */ +#define SHADOW_UPDATE_OPERATION_STRING "/shadow/update" + +/** + * @brief The length of #SHADOW_UPDATE_OPERATION_STRING. + */ +#define SHADOW_UPDATE_OPERATION_STRING_LENGTH ( ( uint16_t ) ( sizeof( SHADOW_UPDATE_OPERATION_STRING ) - 1 ) ) + +/** + * @brief The suffix for a Shadow delta topic. + */ +#define SHADOW_DELTA_SUFFIX "/delta" + +/** + * @brief The length of #SHADOW_DELTA_SUFFIX. + */ +#define SHADOW_DELTA_SUFFIX_LENGTH ( ( uint16_t ) ( sizeof( SHADOW_DELTA_SUFFIX ) - 1 ) ) + +/** + * @brief The suffix for a Shadow updated topic. + */ +#define SHADOW_UPDATED_SUFFIX "/documents" + +/** + * @brief The length of #SHADOW_UPDATED_SUFFIX. + */ +#define SHADOW_UPDATED_SUFFIX_LENGTH ( ( uint16_t ) ( sizeof( SHADOW_UPDATED_SUFFIX ) - 1 ) ) + +/** + * @brief The length of the longest Shadow suffix. + */ +#define SHADOW_LONGEST_SUFFIX_LENGTH SHADOW_UPDATED_SUFFIX_LENGTH + +/** + * @brief The macro to convert MQTT error codes to Shadow error codes. + * Below are the conversions happening. + * IOT_MQTT_SUCCESS to AWS_IOT_SHADOW_SUCCESS + * IOT_MQTT_NO_MEMORY to AWS_IOT_SHADOW_NO_MEMORY + * all other error codes to AWS_IOT_SHADOW_MQTT_ERROR + */ +#define SHADOW_CONVERT_STATUS_CODE_MQTT_TO_SHADOW( X ) \ + ( ( X ) == IOT_MQTT_SUCCESS ) ? AWS_IOT_SHADOW_SUCCESS : \ + ( ( X ) == IOT_MQTT_NO_MEMORY ) ? AWS_IOT_SHADOW_NO_MEMORY : \ + AWS_IOT_SHADOW_MQTT_ERROR + +/*----------------------- Shadow internal data types ------------------------*/ + +/** + * @brief Enumerations representing each of the Shadow library's API functions. + */ +typedef enum _shadowOperationType +{ + /* Shadow operations. */ + SHADOW_DELETE = 0, /**< @ref shadow_function_deleteasync */ + SHADOW_GET = 1, /**< @ref shadow_function_getasync */ + SHADOW_UPDATE = 2, /**< @ref shadow_function_updateasync */ + + /* Shadow callbacks. */ + SET_DELTA_CALLBACK = 3, /**< @ref shadow_function_setdeltacallback */ + SET_UPDATED_CALLBACK = 4 /**< @ref shadow_function_setupdatedcallback */ +} _shadowOperationType_t; + +/** + * @brief Enumerations representing each of the Shadow callback functions. + */ +typedef enum _shadowCallbackType +{ + DELTA_CALLBACK = 0, /**< Delta callback. */ + UPDATED_CALLBACK = 1 /**< Updated callback. */ +} _shadowCallbackType_t; + +/** + * @brief Represents a Shadow subscriptions object. + * + * These structures are stored in a list. + */ +typedef struct _shadowSubscription +{ + IotLink_t link; /**< @brief List link member. */ + + int32_t references[ SHADOW_OPERATION_COUNT ]; /**< @brief Reference counter for Shadow operation topics. */ + AwsIotShadowCallbackInfo_t callbacks[ SHADOW_CALLBACK_COUNT ]; /**< @brief Shadow callbacks for this Thing. */ + + /** + * @brief Buffer allocated for removing Shadow topics. + * + * This buffer is pre-allocated to ensure that memory is available when + * unsubscribing. + */ + char * pTopicBuffer; + + size_t thingNameLength; /**< @brief Length of Thing Name. */ + char pThingName[]; /**< @brief Thing Name associated with this subscriptions object. */ +} _shadowSubscription_t; + +/** + * @brief Internal structure representing a single Shadow operation (DELETE, + * GET, or UPDATE). + * + * A list of these structures keeps track of all in-progress Shadow operations. + */ +typedef struct _shadowOperation +{ + IotLink_t link; /**< @brief List link member. */ + + /* Basic operation information. */ + _shadowOperationType_t type; /**< @brief Operation type. */ + uint32_t flags; /**< @brief Flags passed to operation API function. */ + AwsIotShadowError_t status; /**< @brief Status of operation. */ + + IotMqttConnection_t mqttConnection; /**< @brief MQTT connection associated with this operation. */ + _shadowSubscription_t * pSubscription; /**< @brief Shadow subscriptions object associated with this operation. */ + + union + { + /* Members valid only for a GET operation. */ + struct + { + /** + * @brief Function to allocate memory for an incoming Shadow document. + * + * Only used when the flag #AWS_IOT_SHADOW_FLAG_WAITABLE is set. + */ + void *( *mallocDocument )( size_t ); + + const char * pDocument; /**< @brief Retrieved Shadow document. */ + size_t documentLength; /**< @brief Length of retrieved Shadow document. */ + } get; + + /* Members valid only for an UPDATE operation. */ + struct + { + const char * pClientToken; /**< @brief Client token in update document. */ + size_t clientTokenLength; /**< @brief Length of client token. */ + } update; + } u; /**< @brief Valid member depends on _shadowOperation_t.type. */ + + /* How to notify of an operation's completion. */ + union + { + IotSemaphore_t waitSemaphore; /**< @brief Semaphore to be used with @ref shadow_function_wait. */ + AwsIotShadowCallbackInfo_t callback; /**< @brief User-provided callback function and parameter. */ + } notify; /**< @brief How to notify of an operation's completion. */ +} _shadowOperation_t; + +/* Declarations of names printed in logs. */ +#if LIBRARY_LOG_LEVEL > IOT_LOG_NONE + extern const char * const _pAwsIotShadowOperationNames[]; + extern const char * const _pAwsIotShadowCallbackNames[]; +#endif + +/* Declarations of variables for internal Shadow files. */ +extern uint32_t _AwsIotShadowMqttTimeoutMs; +extern IotListDouble_t _AwsIotShadowPendingOperations; +extern IotListDouble_t _AwsIotShadowSubscriptions; +extern IotMutex_t _AwsIotShadowPendingOperationsMutex; +extern IotMutex_t _AwsIotShadowSubscriptionsMutex; + +/*----------------------- Shadow operation functions ------------------------*/ + +/** + * @brief Create a record for a new in-progress Shadow operation. + * + * @param[out] pNewOperation Set to point to the new operation on success. + * @param[in] operation The type of Shadow operation. + * @param[in] flags Flags variables passed to a user-facing Shadow function. + * @param[in] pCallbackInfo User-provided callback function and parameter. + * + * @return #AWS_IOT_SHADOW_SUCCESS or #AWS_IOT_SHADOW_NO_MEMORY + */ +AwsIotShadowError_t _AwsIotShadow_CreateOperation( _shadowOperation_t ** pNewOperation, + _shadowOperationType_t operation, + uint32_t flags, + const AwsIotShadowCallbackInfo_t * pCallbackInfo ); + +/** + * @brief Free resources used to record a Shadow operation. This is called when + * the operation completes. + * + * @param[in] pData The operation which completed. This parameter is of type + * `void*` to match the signature of [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ +void _AwsIotShadow_DestroyOperation( void * pData ); + +/** + * @brief Fill a buffer with a Shadow topic. + * + * @param[in] type One of: DELETE, GET, UPDATE. + * @param[in] pThingName Thing Name to place in the topic. + * @param[in] thingNameLength Length of `pThingName`. + * @param[out] pTopicBuffer Address of the buffer for the Shadow topic. If the + * pointer at this address is `NULL`, this function will allocate a new buffer; + * otherwise, it will use the provided buffer. + * @param[out] pOperationTopicLength Length of the Shadow operation topic (excluding + * any suffix) placed in `pTopicBuffer`. + * + * @warning This function does not check the length of `pTopicBuffer`! Any provided + * buffer must be large enough to accommodate the full Shadow topic, plus + * #SHADOW_LONGEST_SUFFIX_LENGTH. + * + * @return #AWS_IOT_SHADOW_SUCCESS or #AWS_IOT_SHADOW_NO_MEMORY. This function + * will not return #AWS_IOT_SHADOW_NO_MEMORY when a buffer is provided. + */ +AwsIotShadowError_t _AwsIotShadow_GenerateShadowTopic( _shadowOperationType_t type, + const char * pThingName, + size_t thingNameLength, + char ** pTopicBuffer, + uint16_t * pOperationTopicLength ); + +/** + * @brief Process a Shadow operation by sending the necessary MQTT packets. + * + * @param[in] mqttConnection The MQTT connection to use. + * @param[in] pThingName Thing Name for the Shadow operation. + * @param[in] thingNameLength Length of `pThingName`. + * @param[in] pOperation Operation data to process. + * @param[in] pDocumentInfo Information on the Shadow document for GET or UPDATE + * operations. + * + * @return #AWS_IOT_SHADOW_STATUS_PENDING on success. On error, one of + * #AWS_IOT_SHADOW_NO_MEMORY or #AWS_IOT_SHADOW_MQTT_ERROR. + */ +AwsIotShadowError_t _AwsIotShadow_ProcessOperation( IotMqttConnection_t mqttConnection, + const char * pThingName, + size_t thingNameLength, + _shadowOperation_t * pOperation, + const AwsIotShadowDocumentInfo_t * pDocumentInfo ); + +/*---------------------- Shadow subscription functions ----------------------*/ + +/** + * @brief Find a Shadow subscription object. May create a new subscription object + * and adds it to the subscription list if not found. + * + * @param[in] pThingName Thing Name in the subscription object. + * @param[in] thingNameLength Length of `pThingName`. + * @param[in] createIfNotFound If `true`, attempt to create a new subscription + * object if no match is found. + * + * @return Pointer to a Shadow subscription object, either found or newly + * allocated. Returns `NULL` if no subscription object is found and a new + * subscription object could not be allocated. + * + * @note This function should be called with the subscription list mutex locked. + */ +_shadowSubscription_t * _AwsIotShadow_FindSubscription( const char * pThingName, + size_t thingNameLength, + bool createIfNotFound ); + +/** + * @brief Remove a Shadow subscription object from the subscription list if + * unreferenced. + * + * @param[in] pSubscription Subscription object to check. If this object has no + * active references, it is removed from the subscription list. + * @param[out] pRemovedSubscription Removed subscription object, if any. Optional; + * pass `NULL` to ignore. If not `NULL`, this parameter will be set to the removed + * subscription and that subscription will not be destroyed. + * + * @note This function should be called with the subscription list mutex locked. + */ +void _AwsIotShadow_RemoveSubscription( _shadowSubscription_t * pSubscription, + _shadowSubscription_t ** pRemovedSubscription ); + +/** + * @brief Free resources used for a Shadow subscription object. + * + * @param[in] pData The subscription object to destroy. This parameter is of type + * `void*` to match the signature of [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ +void _AwsIotShadow_DestroySubscription( void * pData ); + +/** + * @brief Increment the reference count of a Shadow subscriptions object. + * + * Also adds MQTT subscriptions if necessary. + * + * @param[in] pOperation The operation for which the reference count should be + * incremented. + * @param[in] pTopicBuffer Topic buffer containing the operation topic, used if + * subscriptions need to be added. + * @param[in] operationTopicLength The length of the operation topic in `pTopicBuffer`. + * @param[in] callback MQTT callback function for when this operation completes. + * + * @warning This function does not check the length of `pTopicBuffer`! Any provided + * buffer must already contain the Shadow operation topic, plus enough space for the + * status suffix. + * + * @return #AWS_IOT_SHADOW_SUCCESS on success. On error, one of + * #AWS_IOT_SHADOW_NO_MEMORY or #AWS_IOT_SHADOW_MQTT_ERROR. + * + * @note This function should be called with the subscription list mutex locked. + */ +AwsIotShadowError_t _AwsIotShadow_IncrementReferences( _shadowOperation_t * pOperation, + char * pTopicBuffer, + uint16_t operationTopicLength, + AwsIotMqttCallbackFunction_t callback ); + +/** + * @brief Decrement the reference count of a Shadow subscriptions object. + * + * Also removed MQTT subscriptions and deletes the subscription object if necessary. + * + * @param[in] pOperation The operation for which the reference count should be + * decremented. + * @param[in] pTopicBuffer Topic buffer containing the operation topic, used if + * subscriptions need to be removed. + * @param[out] pRemovedSubscription Set to point to a removed subscription. + * Optional; pass `NULL` to ignore. If not `NULL`, this function will not destroy + * a removed subscription. + * + * @warning This function does not check the length of `pTopicBuffer`! Any provided + * buffer must be large enough to accommodate the full Shadow topic, plus + * #SHADOW_LONGEST_SUFFIX_LENGTH. + * + * @note This function should be called with the subscription list mutex locked. + */ +void _AwsIotShadow_DecrementReferences( _shadowOperation_t * pOperation, + char * pTopicBuffer, + _shadowSubscription_t ** pRemovedSubscription ); + +/*------------------------- Shadow parser functions -------------------------*/ + +/** + * @brief Parse a Shadow error document. + * + * @param[in] pErrorDocument The error document to parse. + * @param[in] errorDocumentLength The length of `pErrorDocument`. + * + * @return One of the #AwsIotShadowError_t ranging from 400 to 500 on success. + * #AWS_IOT_SHADOW_BAD_RESPONSE on error. + */ +AwsIotShadowError_t _AwsIotShadow_ParseErrorDocument( const char * pErrorDocument, + size_t errorDocumentLength ); + +#endif /* ifndef AWS_IOT_SHADOW_INTERNAL_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/directories.txt b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/directories.txt new file mode 100644 index 000000000..773e72bfe --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/directories.txt @@ -0,0 +1,7 @@ ++ standard +Contains the implementation of IoT libraries that implement standard protocols +and interfaces, such as MQTT. + ++ aws +Contains the implementation of AWS IoT libraries that implement device side +interfaces for using AWS IoT services such as Shadow, Jobs. \ No newline at end of file diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_clock.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_clock.h new file mode 100644 index 000000000..a9633dc8d --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_clock.h @@ -0,0 +1,213 @@ +/* + * IoT Platform V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_clock.h + * @brief Time-related functions used by libraries in this SDK. + */ + +#ifndef IOT_CLOCK_H_ +#define IOT_CLOCK_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include +#include + +/* Platform layer types include. */ +#include "types/iot_platform_types.h" + +/** + * @functionspage{platform_clock,platform clock component,Clock} + * - @functionname{platform_clock_function_gettimestring} + * - @functionname{platform_clock_function_gettimems} + * - @functionname{platform_clock_function_sleepms} + * - @functionname{platform_clock_function_timercreate} + * - @functionname{platform_clock_function_timerdestroy} + * - @functionname{platform_clock_function_timerarm} + */ + +/** + * @functionpage{IotClock_GetTimestring,platform_clock,gettimestring} + * @functionpage{IotClock_GetTimeMs,platform_clock,gettimems} + * @functionpage{IotClock_SleepMs,platform_clock,sleepms} + * @functionpage{IotClock_TimerCreate,platform_clock,timercreate} + * @functionpage{IotClock_TimerDestroy,platform_clock,timerdestroy} + * @functionpage{IotClock_TimerArm,platform_clock,timerarm} + */ + +/** + * @brief Generates a human-readable timestring, such as "01 Jan 2018 12:00". + * + * This function uses the system clock to generate a human-readable timestring. + * This timestring is printed by the [logging functions](@ref logging_functions). + * + * @param[out] pBuffer A buffer to store the timestring in. + * @param[in] bufferSize The size of `pBuffer`. + * @param[out] pTimestringLength The actual length of the timestring stored in + * `pBuffer`. + * + * @return `true` if a timestring was successfully generated; `false` otherwise. + * + * @warning The implementation of this function must not call any [logging functions] + * (@ref logging_functions). + * + * Example + * @code{c} + * char timestring[ 32 ]; + * size_t timestringLength = 0; + * + * if( IotClock_GetTimestring( timestring, 32, ×tringLength ) == true ) + * { + * printf( "Timestring: %.*s", timestringLength, timestring ); + * } + * @endcode + */ +/* @[declare_platform_clock_gettimestring] */ +bool IotClock_GetTimestring( char * pBuffer, + size_t bufferSize, + size_t * pTimestringLength ); +/* @[declare_platform_clock_gettimestring] */ + +/** + * @brief Returns a nonzero, monotonically-increasing system time in milliseconds. + * + * This function reads a millisecond-resolution system clock. The clock should + * always be monotonically-increasing; therefore, real-time clocks that may be + * set by another process are not suitable for this function's implementation. + * + * @return The value of the system clock. This function is not expected to fail. + * + * Example + * @code{c} + * // Get current time. + * uint64_t currentTime = IotClock_GetTimeMs(); + * @endcode + */ +/* @[declare_platform_clock_gettimems] */ +uint64_t IotClock_GetTimeMs( void ); +/* @[declare_platform_clock_gettimems] */ + +/** + * @brief Delay for the given number of milliseconds. + * + * This function suspends its calling thread for at least `sleepTimeMs` milliseconds. + * + * @param[in] sleepTimeMs Sleep time (in milliseconds). + */ +/* @[declare_platform_clock_sleepms] */ +void IotClock_SleepMs( uint32_t sleepTimeMs ); +/* @[declare_platform_clock_sleepms] */ + +/** + * @brief Create a new timer. + * + * This function creates a new, unarmed timer. It must be called on an uninitialized + * #IotTimer_t. This function must not be called on an already-initialized #IotTimer_t. + * + * @param[out] pNewTimer Set to a new timer handle on success. + * @param[in] expirationRoutine The function to run when this timer expires. This + * function should be called in its own detached thread. + * @param[in] pArgument The argument to pass to `expirationRoutine`. + * + * @return `true` if the timer is successfully created; `false` otherwise. + * + * @see @ref platform_clock_function_timerdestroy, @ref platform_clock_function_timerarm + */ +/* @[declare_platform_clock_timercreate] */ +bool IotClock_TimerCreate( IotTimer_t * pNewTimer, + IotThreadRoutine_t expirationRoutine, + void * pArgument ); +/* @[declare_platform_clock_timercreate] */ + +/** + * @brief Free resources used by a timer. + * + * This function frees resources used by a timer. It must be called on an initialized + * #IotTimer_t. No other timer functions should be called on `pTimer` after calling + * this function (unless the timer is re-created). + * + * This function will stop the `pTimer` if it is armed. + * + * @param[in] pTimer The timer to destroy. + * + * @see @ref platform_clock_function_timercreate, @ref platform_clock_function_timerarm + */ +/* @[declare_platform_clock_timerdestroy] */ +void IotClock_TimerDestroy( IotTimer_t * pTimer ); +/* @[declare_platform_clock_timerdestroy] */ + +/** + * @brief Arm a timer to expire at the given relative timeout. + * + * This function arms a timer to run its expiration routine at the given time. + * + * If `periodMs` is nonzero, the timer should expire periodically at intervals + * such as: + * - `relativeTimeoutMs` + * - `relativeTimeoutMs + periodMs` + * - `relativeTimeoutMs + 2 * periodMs` + * - Etc. (subject to some jitter). + * + * Setting `periodMs` to `0` arms a one-shot, non-periodic timer. + * + * @param[in] pTimer The timer to arm. + * @param[in] relativeTimeoutMs When the timer should expire, relative to the time + * this function is called. + * @param[in] periodMs How often the timer should expire again after `relativeTimerMs`. + * + * @return `true` if the timer was successfully armed; `false` otherwise. + * + * @see @ref platform_clock_function_timercreate, @ref platform_clock_function_timerdestroy + * + * Example + * @code{c} + * + * void timerExpirationRoutine( void * pArgument ); + * + * void timerExample( void ) + * { + * IotTimer_t timer; + * + * if( IotClock_TimerCreate( &timer, timerExpirationRoutine, NULL ) == true ) + * { + * // Set the timer to periodically expire every 10 seconds. + * if( IotClock_TimerArm( &timer, 10000, 10000 ) == true ) + * { + * // Wait for timer to expire. + * } + * + * IotClock_TimerDestroy( &timer ); + * } + * } + * @endcode + */ +/* @[declare_platform_clock_timerarm] */ +bool IotClock_TimerArm( IotTimer_t * pTimer, + uint32_t relativeTimeoutMs, + uint32_t periodMs ); +/* @[declare_platform_clock_timerarm] */ + +#endif /* ifndef IOT_CLOCK_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_metrics.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_metrics.h new file mode 100644 index 000000000..a5ece4267 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_metrics.h @@ -0,0 +1,100 @@ +/* + * IoT Platform V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_metrics.h + * @brief Functions for retrieving [Device Defender](@ref defender) metrics. + * + * The functions in this header are only required by Device Defender. They do not + * need to be implemented if Device Defender is not used. + */ + +#ifndef IOT_METRICS_H_ +#define IOT_METRICS_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* Linear containers (lists and queues) include. */ +#include "iot_linear_containers.h" + +/** + * @functionspage{platform_metrics,platform metrics component,Metrics} + * - @functionname{platform_metrics_function_init} + * - @functionname{platform_metrics_function_cleanup} + * - @functionname{platform_metrics_function_gettcpconnections} + */ + +/** + * @functionpage{IotMetrics_Init,platform_metrics,init} + * @functionpage{IotMetrics_Cleanup,platform_metrics,cleanup} + * @functionpage{IotMetrics_GetTcpConnections,platform_metrics,gettcpconnections} + */ + +/** + * @brief One-time initialization function for the platform metrics component. + * + * This function initializes the platform metrics component. It must be called + * once (and only once) before calling any other metrics or [Device Defender function] + * (@ref defender_functions). Calling this function more than once without first + * calling @ref platform_metrics_function_cleanup may result in a crash. + * + * @return `true` is initialization succeeded; `false` otherwise. + * + * @warning No thread-safety guarantees are provided for this function. + */ +/* @[declare_platform_metrics_init] */ +bool IotMetrics_Init( void ); +/* @[declare_platform_metrics_init] */ + +/** + * @brief One-time deinitialization function for the platform metrics component. + * + * This function frees resources taken in @ref platform_metrics_function_init. + * No other metrics or [Device Defender functions](@ref defender_functions) may + * be called unless @ref platform_metrics_function_init is called again. + * + * @warning No thread-safety guarantees are provided for this function. + */ +/* @[declare_platform_metrics_cleanup] */ +void IotMetrics_Cleanup( void ); +/* @[declare_platform_metrics_cleanup] */ + +/** + * @brief Retrieve a list of active TCP connections from the system. + * + * The provided connections are reported by Device Defender. + * + * @param[in] pContext Context passed as the first parameter of `metricsCallback`. + * @param[in] metricsCallback Called by this function to provide the list of TCP + * connections. The list given by this function is should not be used after the + * callback returns. + */ +/* @[declare_platform_metrics_gettcpconnections] */ +void IotMetrics_GetTcpConnections( void * pContext, + void ( * metricsCallback )( void *, const IotListDouble_t * ) ); +/* @[declare_platform_metrics_gettcpconnections] */ + +#endif /* ifndef IOT_METRICS_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_network.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_network.h new file mode 100644 index 000000000..015fa49aa --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_network.h @@ -0,0 +1,318 @@ +/* + * IoT Platform V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_network.h + * @brief Abstraction of network functions used by libraries in this SDK. + */ + +#ifndef IOT_NETWORK_H_ +#define IOT_NETWORK_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include + +/** + * @ingroup platform_datatypes_enums + * @brief Return codes for [network functions](@ref platform_network_functions). + */ +typedef enum IotNetworkError +{ + IOT_NETWORK_SUCCESS = 0, /**< Function successfully completed. */ + IOT_NETWORK_FAILURE, /**< Generic failure not covered by other values. */ + IOT_NETWORK_BAD_PARAMETER, /**< At least one parameter was invalid. */ + IOT_NETWORK_NO_MEMORY, /**< Memory allocation failed. */ + IOT_NETWORK_SYSTEM_ERROR /**< An error occurred when calling a system API. */ +} IotNetworkError_t; + +/** + * @page platform_network_functions Networking + * @brief Functions of the network abstraction component. + * + * The network abstraction component does not declare functions, but uses function + * pointers instead. This allows multiple network stacks to be used at the same time. + * Libraries that require the network will request an #IotNetworkInterface_t + * parameter. The members of the #IotNetworkInterface_t will be called whenever + * the library interacts with the network. + * + * The following function pointers are associated with an #IotNetworkInterface_t. + * Together, they represent a network stack. + * - @functionname{platform_network_function_create} + * - @functionname{platform_network_function_setreceivecallback} + * - @functionname{platform_network_function_send} + * - @functionname{platform_network_function_receive} + * - @functionname{platform_network_function_close} + * - @functionname{platform_network_function_destroy} + * - @functionname{platform_network_function_receivecallback} + */ + +/** + * @functionpage{IotNetworkInterface_t::create,platform_network,create} + * @functionpage{IotNetworkInterface_t::setReceiveCallback,platform_network,setreceivecallback} + * @functionpage{IotNetworkInterface_t::send,platform_network,send} + * @functionpage{IotNetworkInterface_t::receive,platform_network,receive} + * @functionpage{IotNetworkInterface_t::close,platform_network,close} + * @functionpage{IotNetworkInterface_t::destroy,platform_network,destroy} + * @functionpage{IotNetworkReceiveCallback_t,platform_network,receivecallback} + */ + +/** + * @brief Provide an asynchronous notification of incoming network data. + * + * A function with this signature may be set with @ref platform_network_function_setreceivecallback + * to be invoked when data is available on the network. + * + * @param[in] pConnection The connection on which data is available, defined by + * the network stack. + * @param[in] pContext The third argument passed to @ref platform_network_function_setreceivecallback. + */ +/* @[declare_platform_network_receivecallback] */ +typedef void ( * IotNetworkReceiveCallback_t )( IotNetworkConnection_t pConnection, + void * pContext ); +/* @[declare_platform_network_receivecallback] */ + +/** + * @ingroup platform_datatypes_paramstructs + * @brief Represents the functions of a network stack. + * + * Functions that match these signatures should be implemented against a system's + * network stack. See the `platform` directory for existing implementations. + */ +typedef struct IotNetworkInterface +{ + /** + * @brief Create a new network connection. + * + * This function allocates resources and establishes a new network connection. + * @param[in] pServerInfo Represents information needed to set up the + * new connection, defined by the network stack. + * @param[in] pCredentialInfo Represents information needed to secure the + * new connection, defined by the network stack. + * @param[out] pConnection Set to represent a new connection, defined by the + * network stack. + * + * @return Any #IotNetworkError_t, as defined by the network stack. + */ + /* @[declare_platform_network_create] */ + IotNetworkError_t ( * create )( IotNetworkServerInfo_t pServerInfo, + IotNetworkCredentials_t pCredentialInfo, + IotNetworkConnection_t * pConnection ); + /* @[declare_platform_network_create] */ + + /** + * @brief Register an @ref platform_network_function_receivecallback. + * + * Sets an @ref platform_network_function_receivecallback to be called + * asynchronously when data arrives on the network. The network stack + * should invoke this function "as if" it were the thread routine of a + * detached thread. + * + * Each network connection may only have one receive callback at any time. + * @ref platform_network_function_close is expected to remove any active + * receive callbacks. + * + * @param[in] pConnection The connection to associate with the receive callback. + * @param[in] receiveCallback The function to invoke for incoming network data. + * @param[in] pContext A value to pass as the first parameter to the receive callback. + * + * @return Any #IotNetworkError_t, as defined by the network stack. + * + * @see platform_network_function_receivecallback + */ + /* @[declare_platform_network_setreceivecallback] */ + IotNetworkError_t ( * setReceiveCallback )( IotNetworkConnection_t pConnection, + IotNetworkReceiveCallback_t receiveCallback, + void * pContext ); + /* @[declare_platform_network_setreceivecallback] */ + + /** + * @brief Send data over a return connection. + * + * Attempts to transmit `messageLength` bytes of `pMessage` across the + * connection represented by `pConnection`. Returns the number of bytes + * actually sent, `0` on failure. + * + * @param[in] pConnection The connection used to send data, defined by the + * network stack. + * @param[in] pMessage The message to send. + * @param[in] messageLength The length of `pMessage`. + * + * @return The number of bytes successfully sent, `0` on failure. + */ + /* @[declare_platform_network_send] */ + size_t ( * send )( IotNetworkConnection_t pConnection, + const uint8_t * pMessage, + size_t messageLength ); + /* @[declare_platform_network_send] */ + + /** + * @brief Block and wait for incoming network data. + * + * Wait for a message of size `bytesRequested` to arrive on the network and + * place it in `pBuffer`. + * + * @param[in] pConnection The connection to wait on, defined by the network + * stack. + * @param[out] pBuffer Where to place the incoming network data. This buffer + * must be at least `bytesRequested` in size. + * @param[in] bytesRequested How many bytes to wait for. `pBuffer` must be at + * least this size. + * + * @return The number of bytes successfully received. This should be + * `bytesRequested` when successful. Any other value may indicate an error. + */ + /* @[declare_platform_network_receive] */ + size_t ( * receive )( IotNetworkConnection_t pConnection, + uint8_t * pBuffer, + size_t bytesRequested ); + + /* @[declare_platform_network_receive] */ + + /** + * @brief Read incoming data available in the network buffers. + * + * Reads bytes available in the network buffers into `pBuffer`. + * - If there is less data available than requested, it will return + * the available number of bytes. + * - If there is more data available than requested, it will fill the + * whole `pBuffer`. + * - If there is no data available, it will return 0. + * + * @param[in] pConnection The connection to receive data on, defined by + * the network stack. + * @param[out] pBuffer The buffer to place the incoming network data. + * @param[in] bufferSize The size of `pBuffer`. + * + * @return The number of bytes successfully received. + */ + /* @[declare_platform_network_receiveupto] */ + size_t ( * receiveUpto )( IotNetworkConnection_t pConnection, + uint8_t * pBuffer, + size_t bufferSize ); + /* @[declare_platform_network_receiveupto] */ + + + /** + * @brief Close a network connection. + * + * This function closes the connection, but does not release the resources + * used by the connection. This allows calls to other networking functions + * to return an error and handle a closed connection without the risk of + * crashing. Once it can be guaranteed that `pConnection` will no longer be + * used, the connection can be destroyed with @ref platform_network_function_destroy. + * + * In addition to closing the connection, this function should also remove + * any active [receive callback](@ref platform_network_function_receivecallback). + * + * @param[in] pConnection The network connection to close, defined by the + * network stack. + * + * @return Any #IotNetworkError_t, as defined by the network stack. + * + * @note It must be safe to call this function on an already-closed connection. + */ + /* @[declare_platform_network_close] */ + IotNetworkError_t ( * close )( IotNetworkConnection_t pConnection ); + /* @[declare_platform_network_close] */ + + /** + * @brief Free resources used by a network connection. + * + * This function releases the resources of a closed connection. It should be + * called after @ref platform_network_function_close. + * + * @param[in] pConnection The network connection to destroy, defined by + * the network stack. + * + * @return Any #IotNetworkError_t, as defined by the network stack. + * + * @attention No function should be called on the network connection after + * calling this function. This function must be safe to call from a + * [receive callback](@ref platform_network_function_receivecallback). + */ + /* @[declare_platform_network_destroy] */ + IotNetworkError_t ( * destroy )( IotNetworkConnection_t pConnection ); + /* @[declare_platform_network_destroy] */ +} IotNetworkInterface_t; + +/** + * @ingroup platform_datatypes_paramstructs + * @brief Information on the remote server for connection setup. + * + * May be passed to #IotNetworkInterface_t.create as `pConnectionInfo`. This + * structure contains commonly-used parameters, but may be replaced with an + * alternative. + */ +struct IotNetworkServerInfo +{ + const char * pHostName; /**< @brief Server host name. Must be NULL-terminated. */ + uint16_t port; /**< @brief Server port in host-order. */ +}; + +/** + * @ingroup platform_datatypes_paramstructs + * @brief Contains the credentials necessary for connection setup. + * + * May be passed to #IotNetworkInterface_t.create as `pCredentialInfo`. This + * structure contains commonly-used parameters, but may be replaced with an + * alternative. + */ +struct IotNetworkCredentials +{ + /** + * @brief Set this to a non-NULL value to use ALPN. + * + * This string must be NULL-terminated. + * + * See [this link] + * (https://aws.amazon.com/blogs/iot/mqtt-with-tls-client-authentication-on-port-443-why-it-is-useful-and-how-it-works/) + * for more information. + */ + const char * pAlpnProtos; + + /** + * @brief Set this to a non-zero value to use TLS max fragment length + * negotiation (TLS MFLN). + * + * @note The network stack may have a minimum value for this parameter and + * may return an error if this parameter is too small. + */ + size_t maxFragmentLength; + + /** + * @brief Disable server name indication (SNI) for a TLS session. + */ + bool disableSni; + + const char * pRootCa; /**< @brief String representing a trusted server root certificate. */ + size_t rootCaSize; /**< @brief Size associated with #IotNetworkCredentials.pRootCa. */ + const char * pClientCert; /**< @brief String representing the client certificate. */ + size_t clientCertSize; /**< @brief Size associated with #IotNetworkCredentials.pClientCert. */ + const char * pPrivateKey; /**< @brief String representing the client certificate's private key. */ + size_t privateKeySize; /**< @brief Size associated with #IotNetworkCredentials.pPrivateKey. */ +}; + +#endif /* ifndef IOT_NETWORK_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_threads.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_threads.h new file mode 100644 index 000000000..54b4df41f --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/iot_threads.h @@ -0,0 +1,352 @@ +/* + * IoT Platform V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_threads.h + * @brief Threading and synchronization functions used by libraries in this SDK. + */ + +#ifndef IOT_THREADS_H_ +#define IOT_THREADS_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include + +/* Platform layer types include. */ +#include "types/iot_platform_types.h" + +/** + * @functionspage{platform_threads,platform thread management,Thread Management} + * - @functionname{platform_threads_function_createdetachedthread} + * - @functionname{platform_threads_function_mutexcreate} + * - @functionname{platform_threads_function_mutexdestroy} + * - @functionname{platform_threads_function_mutexlock} + * - @functionname{platform_threads_function_mutextrylock} + * - @functionname{platform_threads_function_mutexunlock} + * - @functionname{platform_threads_function_semaphorecreate} + * - @functionname{platform_threads_function_semaphoredestroy} + * - @functionname{platform_threads_function_semaphoregetcount} + * - @functionname{platform_threads_function_semaphorewait} + * - @functionname{platform_threads_function_semaphoretrywait} + * - @functionname{platform_threads_function_semaphoretimedwait} + * - @functionname{platform_threads_function_semaphorepost} + */ + +/** + * @functionpage{Iot_CreateDetachedThread,platform_threads,createdetachedthread} + * @functionpage{IotMutex_Create,platform_threads,mutexcreate} + * @functionpage{IotMutex_Destroy,platform_threads,mutexdestroy} + * @functionpage{IotMutex_Lock,platform_threads,mutexlock} + * @functionpage{IotMutex_TryLock,platform_threads,mutextrylock} + * @functionpage{IotMutex_Unlock,platform_threads,mutexunlock} + * @functionpage{IotSemaphore_Create,platform_threads,semaphorecreate} + * @functionpage{IotSemaphore_Destroy,platform_threads,semaphoredestroy} + * @functionpage{IotSemaphore_GetCount,platform_threads,semaphoregetcount} + * @functionpage{IotSemaphore_Wait,platform_threads,semaphorewait} + * @functionpage{IotSemaphore_TryWait,platform_threads,semaphoretrywait} + * @functionpage{IotSemaphore_TimedWait,platform_threads,semaphoretimedwait} + * @functionpage{IotSemaphore_Post,platform_threads,semaphorepost} + */ + +/** + * @brief Create a new detached thread, i.e. a thread that cleans up after itself. + * + * This function creates a new thread. Threads created by this function exit + * upon returning from the thread routine. Any resources taken must be freed + * by the exiting thread. + * + * @param[in] threadRoutine The function this thread should run. + * @param[in] pArgument The argument passed to `threadRoutine`. + * @param[in] priority Represents the priority of the new thread, as defined by + * the system. The value #IOT_THREAD_DEFAULT_PRIORITY (i.e. `0`) must be used to + * represent the system default for thread priority. + * @param[in] stackSize Represents the stack size of the new thread, as defined + * by the system. The value #IOT_THREAD_DEFAULT_STACK_SIZE (i.e. `0`) must be used + * to represent the system default for stack size. + * + * @return `true` if the new thread was successfully created; `false` otherwise. + * + * @code{c} + * // Thread routine. + * void threadRoutine( void * pArgument ); + * + * // Run threadRoutine in a detached thread, using default priority and stack size. + * if( Iot_CreateDetachedThread( threadRoutine, + * NULL, + * IOT_THREAD_DEFAULT_PRIORITY, + * IOT_THREAD_DEFAULT_STACK_SIZE ) == true ) + * { + * // Success + * } + * else + * { + * // Failure, no thread was created. + * } + * @endcode + */ +/* @[declare_platform_threads_createdetachedthread] */ +bool Iot_CreateDetachedThread( IotThreadRoutine_t threadRoutine, + void * pArgument, + int32_t priority, + size_t stackSize ); +/* @[declare_platform_threads_createdetachedthread] */ + +/** + * @brief Create a new mutex. + * + * This function creates a new, unlocked mutex. It must be called on an uninitialized + * #IotMutex_t. This function must not be called on an already-initialized #IotMutex_t. + * + * @param[in] pNewMutex Pointer to the memory that will hold the new mutex. + * @param[in] recursive Set to `true` to create a recursive mutex, i.e. a mutex that + * may be locked multiple times by the same thread. If the system does not support + * recursive mutexes, this function should do nothing and return `false`. + * + * @return `true` if mutex creation succeeds; `false` otherwise. + * + * @see @ref platform_threads_function_mutexdestroy + * + * Example + * @code{c} + * IotMutex_t mutex; + * + * // Create non-recursive mutex. + * if( IotMutex_Create( &mutex, false ) == true ) + * { + * // Lock and unlock the mutex... + * + * // Destroy the mutex when it's no longer needed. + * IotMutex_Destroy( &mutex ); + * } + * @endcode + */ +/* @[declare_platform_threads_mutexcreate] */ +bool IotMutex_Create( IotMutex_t * pNewMutex, bool recursive ); +/* @[declare_platform_threads_mutexcreate] */ + +/** + * @brief Free resources used by a mutex. + * + * This function frees resources used by a mutex. It must be called on an initialized + * #IotMutex_t. No other mutex functions should be called on `pMutex` after calling + * this function (unless the mutex is re-created). + * + * @param[in] pMutex The mutex to destroy. + * + * @warning This function must not be called on a locked mutex. + * @see @ref platform_threads_function_mutexcreate + */ +/* @[declare_platform_threads_mutexdestroy] */ +void IotMutex_Destroy( IotMutex_t * pMutex ); +/* @[declare_platform_threads_mutexdestroy] */ + +/** + * @brief Lock a mutex. This function should only return when the mutex is locked; + * it is not expected to fail. + * + * This function blocks and waits until a mutex is available. It waits forever + * (deadlocks) if `pMutex` is already locked and never unlocked. + * + * @param[in] pMutex The mutex to lock. + * + * @see @ref platform_threads_function_mutextrylock for a nonblocking lock. + */ +/* @[declare_platform_threads_mutexlock] */ +void IotMutex_Lock( IotMutex_t * pMutex ); +/* @[declare_platform_threads_mutexlock] */ + +/** + * @brief Attempt to lock a mutex. Return immediately if the mutex is not available. + * + * If `pMutex` is available, this function immediately locks it and returns. + * Otherwise, this function returns without locking `pMutex`. + * + * @param[in] pMutex The mutex to lock. + * + * @return `true` if the mutex was successfully locked; `false` if the mutex was + * not available. + * + * @see @ref platform_threads_function_mutexlock for a blocking lock. + */ +/* @[declare_platform_threads_mutextrylock] */ +bool IotMutex_TryLock( IotMutex_t * pMutex ); +/* @[declare_platform_threads_mutextrylock] */ + +/** + * @brief Unlock a mutex. This function should only return when the mutex is unlocked; + * it is not expected to fail. + * + * Unlocks a locked mutex. `pMutex` must have been locked by the thread calling + * this function. + * + * @param[in] pMutex The mutex to unlock. + * + * @note This function should not be called on a mutex that is already unlocked. + */ +/* @[declare_platform_threads_mutexunlock] */ +void IotMutex_Unlock( IotMutex_t * pMutex ); +/* @[declare_platform_threads_mutexunlock] */ + +/** + * @brief Create a new counting semaphore. + * + * This function creates a new counting semaphore with a given initial and + * maximum value. It must be called on an uninitialized #IotSemaphore_t. + * This function must not be called on an already-initialized #IotSemaphore_t. + * + * @param[in] pNewSemaphore Pointer to the memory that will hold the new semaphore. + * @param[in] initialValue The semaphore should be initialized with this value. + * @param[in] maxValue The maximum value the semaphore will reach. + * + * @return `true` if semaphore creation succeeds; `false` otherwise. + * + * @see @ref platform_threads_function_semaphoredestroy + * + * Example + * @code{c} + * IotSemaphore_t sem; + * + * // Create a locked binary semaphore. + * if( IotSemaphore_Create( &sem, 0, 1 ) == true ) + * { + * // Unlock the semaphore. + * IotSemaphore_Post( &sem ); + * + * // Destroy the semaphore when it's no longer needed. + * IotSemaphore_Destroy( &sem ); + * } + * @endcode + */ +/* @[declare_platform_threads_semaphorecreate] */ +bool IotSemaphore_Create( IotSemaphore_t * pNewSemaphore, + uint32_t initialValue, + uint32_t maxValue ); +/* @[declare_platform_threads_semaphorecreate] */ + +/** + * @brief Free resources used by a semaphore. + * + * This function frees resources used by a semaphore. It must be called on an initialized + * #IotSemaphore_t. No other semaphore functions should be called on `pSemaphore` after + * calling this function (unless the semaphore is re-created). + * + * @param[in] pSemaphore The semaphore to destroy. + * + * @warning This function must not be called on a semaphore with waiting threads. + * @see @ref platform_threads_function_semaphorecreate + */ +/* @[declare_platform_threads_semaphoredestroy] */ +void IotSemaphore_Destroy( IotSemaphore_t * pSemaphore ); +/* @[declare_platform_threads_semaphoredestroy] */ + +/** + * @brief Query the current count of the semaphore. + * + * This function queries a counting semaphore for its current value. A counting + * semaphore's value is always 0 or positive. + * + * @param[in] pSemaphore The semaphore to query. + * + * @return The current count of the semaphore. This function should not fail. + */ +/* @[declare_platform_threads_semaphoregetcount] */ +uint32_t IotSemaphore_GetCount( IotSemaphore_t * pSemaphore ); +/* @[declare_platform_threads_semaphoregetcount] */ + +/** + * @brief Wait on (lock) a semaphore. This function should only return when the + * semaphore wait succeeds; it is not expected to fail. + * + * This function blocks and waits until a counting semaphore is positive. It + * waits forever (deadlocks) if `pSemaphore` has a count `0` that is never + * [incremented](@ref platform_threads_function_semaphorepost). + * + * @param[in] pSemaphore The semaphore to lock. + * + * @see @ref platform_threads_function_semaphoretrywait for a nonblocking wait; + * @ref platform_threads_function_semaphoretimedwait for a wait with timeout. + */ +/* @[declare_platform_threads_semaphorewait] */ +void IotSemaphore_Wait( IotSemaphore_t * pSemaphore ); +/* @[declare_platform_threads_semaphorewait] */ + +/** + * @brief Attempt to wait on (lock) a semaphore. Return immediately if the semaphore + * is not available. + * + * If the count of `pSemaphore` is positive, this function immediately decrements + * the semaphore and returns. Otherwise, this function returns without decrementing + * `pSemaphore`. + * + * @param[in] pSemaphore The semaphore to lock. + * + * @return `true` if the semaphore wait succeeded; `false` if the semaphore has + * a count of `0`. + * + * @see @ref platform_threads_function_semaphorewait for a blocking wait; + * @ref platform_threads_function_semaphoretimedwait for a wait with timeout. + */ +/* @[declare_platform_threads_semaphoretrywait] */ +bool IotSemaphore_TryWait( IotSemaphore_t * pSemaphore ); +/* @[declare_platform_threads_semaphoretrywait] */ + +/** + * @brief Attempt to wait on (lock) a semaphore with a timeout. + * + * This function blocks and waits until a counting semaphore is positive + * or its timeout expires (whichever is sooner). It decrements + * `pSemaphore` and returns `true` if the semaphore is positive at some + * time during the wait. If `pSemaphore` is always `0` during the wait, + * this function returns `false`. + * + * @param[in] pSemaphore The semaphore to lock. + * @param[in] timeoutMs Relative timeout of semaphore lock. This function returns + * false if the semaphore couldn't be locked within this timeout. + * + * @return `true` if the semaphore wait succeeded; `false` if it timed out. + * + * @see @ref platform_threads_function_semaphoretrywait for a nonblocking wait; + * @ref platform_threads_function_semaphorewait for a blocking wait. + */ +/* @[declare_platform_threads_semaphoretimedwait] */ +bool IotSemaphore_TimedWait( IotSemaphore_t * pSemaphore, + uint32_t timeoutMs ); +/* @[declare_platform_threads_semaphoretimedwait] */ + +/** + * @brief Post to (unlock) a semaphore. This function should only return when the + * semaphore post succeeds; it is not expected to fail. + * + * This function increments the count of a semaphore. Any thread may call this + * function to increment a semaphore's count. + * + * @param[in] pSemaphore The semaphore to unlock. + */ +/* @[declare_platform_threads_semaphorepost] */ +void IotSemaphore_Post( IotSemaphore_t * pSemaphore ); +/* @[declare_platform_threads_semaphorepost] */ + +#endif /* ifndef IOT_THREADS_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/types/iot_platform_types.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/types/iot_platform_types.h new file mode 100644 index 000000000..986a1e555 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/platform/types/iot_platform_types.h @@ -0,0 +1,190 @@ +/* + * IoT Platform V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_platform_types.h + * @brief Types of the platform layer. + */ + +#ifndef IOT_PLATFORM_TYPES_H_ +#define IOT_PLATFORM_TYPES_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Linear containers (lists and queues) include for metrics types. */ +#include "iot_linear_containers.h" + +/*------------------------- Thread management types -------------------------*/ + +/** + * @brief A value representing the system default for new thread priority. + */ +#ifndef IOT_THREAD_DEFAULT_PRIORITY +#define IOT_THREAD_DEFAULT_PRIORITY 0 +#endif + +/** + * @brief A value representing the system default for new thread stack size. + */ +#ifndef IOT_THREAD_DEFAULT_STACK_SIZE +#define IOT_THREAD_DEFAULT_STACK_SIZE 0 +#endif + +/** + * @ingroup platform_datatypes_handles + * @brief The type used to represent mutexes, configured with the type + * `_IotSystemMutex_t`. + * + * For the provided ports, `_IotSystemMutex_t` will be automatically configured. + * For other ports, `_IotSystemMutex_t` should be set in `iot_config.h`. + * + * Mutexes should only be released by the threads that take them. + * + * Example
+ * To change the type of #IotMutex_t to `long`: + * @code{c} + * typedef long _IotSystemMutex_t; + * #include "iot_threads.h" + * @endcode + */ +typedef _IotSystemMutex_t IotMutex_t; + +/** + * @ingroup platform_datatypes_handles + * @brief The type used to represent semaphores, configured with the type + * `_IotSystemSemaphore_t`. + * + * For the provided ports, `_IotSystemSemaphore_t` will be automatically configured. + * For other ports, `_IotSystemSemaphore_t` should be set in `iot_config.h`. + * + * Semaphores must be counting, and any thread may take (wait on) or release + * (post to) a semaphore. + * + * Example
+ * To change the type of #IotSemaphore_t to `long`: + * @code{c} + * typedef long _IotSystemSemaphore_t; + * #include "iot_threads.h" + * @endcode + */ +typedef _IotSystemSemaphore_t IotSemaphore_t; + +/** + * @brief Thread routine function. + * + * @param[in] void * The argument passed to the @ref + * platform_threads_function_createdetachedthread. For application use. + */ +typedef void ( * IotThreadRoutine_t )( void * ); + +/*-------------------------- Clock and timer types --------------------------*/ + +/** + * @ingroup platform_datatypes_handles + * @brief The type used to represent timers, configured with the type + * `_IotSystemTimer_t`. + * + * For the provided ports, `_IotSystemTimer_t` will be automatically configured. + * For other ports, `_IotSystemTimer_t` should be set in `iot_config.h`. + * + * Example
+ * To change the type of #IotTimer_t to `long`: + * @code{c} + * typedef long _IotSystemTimer_t; + * #include "iot_clock.h" + * @endcode + */ +typedef _IotSystemTimer_t IotTimer_t; + +/*--------------------------- Network stack types ---------------------------*/ + +/** + * @ingroup platform_datatypes_handles + * @brief The type used to represent network server info, configured with the + * type `_IotNetworkServerInfo_t`. + * + * For the provided ports, `_IotNetworkServerInfo_t` will be automatically configured. + * For other ports, `_IotNetworkServerInfo_t` should be set in `iot_config.h`. + * + * All of the provided ports configure this to #IotNetworkServerInfo, which provides + * the necessary information to connect to a TCP peer. For other network protocols, + * this type should be set to an alternate structure as needed by the other protocol. + */ +typedef _IotNetworkServerInfo_t IotNetworkServerInfo_t; + +/** + * @ingroup platform_datatypes_handles + * @brief The type used to represent network credentials, configured with the + * type `_IotNetworkCredentials_t`. + * + * For the provided ports, `_IotNetworkCredentials_t` will be automatically configured. + * For other ports, `_IotNetworkCredentials_t` should be set in `iot_config.h`. + * + * All of the provided ports configure this to #IotNetworkCredentials, which provides + * the necessary information to connect to a TLS server over TCP. For other network + * protocols, this type should be set to an alternate structure as needed by the other + * protocol. + */ +typedef _IotNetworkCredentials_t IotNetworkCredentials_t; + +/** + * @ingroup platform_datatypes_handles + * @brief The type used to represent network connections, configured with the + * type `_IotNetworkConnection_t`. + * + * For the provided ports, `_IotNetworkConnection_t` will be automatically configured. + * For other ports, `_IotNetworkConnection_t` should be set in `iot_config.h`. + */ +typedef _IotNetworkConnection_t IotNetworkConnection_t; + +/*------------------------------ Metrics types ------------------------------*/ + +/** + * @brief The length of the buffer used to store IP addresses for metrics. + * + * This is the length of the longest IPv6 address plus space for the port number + * and NULL terminator. + */ +#define IOT_METRICS_IP_ADDRESS_LENGTH 54 + +/** + * @brief Represents a TCP connection to a remote IPv4 server. + * + * A list of these is provided by @ref platform_metrics_function_gettcpconnections. + */ +typedef struct IotMetricsTcpConnection +{ + IotLink_t link; /**< @brief List link member. */ + void * pNetworkContext; /**< @brief Context that may be used by metrics or Defender. */ + size_t addressLength; /**< @brief The length of the address stored in #IotMetricsTcpConnection_t.pRemoteAddress. */ + + /** + * @brief NULL-terminated IP address and port in text format. + * + * IPv4 addresses will be in the format `xxx.xxx.xxx.xxx:port`. + * IPv6 addresses will be in the format `[xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx]:port`. + */ + char pRemoteAddress[ IOT_METRICS_IP_ADDRESS_LENGTH ]; +} IotMetricsTcpConnection_t; + +#endif /* ifndef IOT_PLATFORM_TYPES_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/atomic.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/atomic.h new file mode 100644 index 000000000..760b1d9d5 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/atomic.h @@ -0,0 +1,547 @@ +/* + * FreeRTOS Kernel V10.2.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/** + * @file atomic.h + * @brief FreeRTOS atomic operation support. + * + * Two implementations of atomic are given in this header file: + * 1. Disabling interrupt globally. + * 2. ISA native atomic support. + * The former is available to all ports (compiler-architecture combination), + * while the latter is only available to ports compiling with GCC (version at + * least 4.7.0), which also have ISA atomic support. + * + * User can select which implementation to use by: + * setting/clearing configUSE_ATOMIC_INSTRUCTION in FreeRTOSConfig.h. + * Define AND set configUSE_ATOMIC_INSTRUCTION to 1 for ISA native atomic support. + * Undefine OR clear configUSE_ATOMIC_INSTRUCTION for disabling global interrupt + * implementation. + * + * @see GCC Built-in Functions for Memory Model Aware Atomic Operations + * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html + */ + +#ifndef ATOMIC_H +#define ATOMIC_H + +#ifndef INC_FREERTOS_H + #error "include FreeRTOS.h must appear in source files before include atomic.h" +#endif + +/* Standard includes. */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + /* Needed for __atomic_compare_exchange() weak=false. */ + #include + + /* This branch is for GCC compiler and GCC compiler only. */ + #ifndef portFORCE_INLINE + #define portFORCE_INLINE inline __attribute__((always_inline)) + #endif + +#else + + /* Port specific definitions -- entering/exiting critical section. + * Refer template -- ./lib/FreeRTOS/portable/Compiler/Arch/portmacro.h + * + * Every call to ATOMIC_EXIT_CRITICAL() must be closely paired with + * ATOMIC_ENTER_CRITICAL(). + */ + #if defined( portSET_INTERRUPT_MASK_FROM_ISR ) + + /* Nested interrupt scheme is supported in this port. */ + #define ATOMIC_ENTER_CRITICAL() \ + UBaseType_t uxCriticalSectionType = portSET_INTERRUPT_MASK_FROM_ISR() + + #define ATOMIC_EXIT_CRITICAL() \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxCriticalSectionType ) + + #else + + /* Nested interrupt scheme is NOT supported in this port. */ + #define ATOMIC_ENTER_CRITICAL() portENTER_CRITICAL() + #define ATOMIC_EXIT_CRITICAL() portEXIT_CRITICAL() + + #endif /* portSET_INTERRUPT_MASK_FROM_ISR() */ + + /* Port specific definition -- "always inline". + * Inline is compiler specific, and may not always get inlined depending on your optimization level. + * Also, inline is considered as performance optimization for atomic. + * Thus, if portFORCE_INLINE is not provided by portmacro.h, instead of resulting error, + * simply define it. + */ + #ifndef portFORCE_INLINE + #define portFORCE_INLINE + #endif + +#endif /* configUSE_GCC_BUILTIN_ATOMICS */ + +#define ATOMIC_COMPARE_AND_SWAP_SUCCESS 0x1U /**< Compare and swap succeeded, swapped. */ +#define ATOMIC_COMPARE_AND_SWAP_FAILURE 0x0U /**< Compare and swap failed, did not swap. */ + +/*----------------------------- Swap && CAS ------------------------------*/ + +/** + * Atomic compare-and-swap + * + * @brief Performs an atomic compare-and-swap operation on the specified values. + * + * @param[in, out] pDestination Pointer to memory location from where value is + * to be loaded and checked. + * @param[in] ulExchange If condition meets, write this value to memory. + * @param[in] ulComparand Swap condition. + * + * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. + * + * @note This function only swaps *pDestination with ulExchange, if previous + * *pDestination value equals ulComparand. + */ +static portFORCE_INLINE uint32_t Atomic_CompareAndSwap_u32( + uint32_t volatile * pDestination, + uint32_t ulExchange, + uint32_t ulComparand ) +{ + + uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + if ( __atomic_compare_exchange( pDestination, + &ulComparand, + &ulExchange, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST ) ) + { + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + +#else + + ATOMIC_ENTER_CRITICAL(); + + if ( *pDestination == ulComparand ) + { + *pDestination = ulExchange; + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return ulReturnValue; + +} + +/** + * Atomic swap (pointers) + * + * @brief Atomically sets the address pointed to by *ppDestination to the value + * of *pExchange. + * + * @param[in, out] ppDestination Pointer to memory location from where a pointer + * value is to be loaded and written back to. + * @param[in] pExchange Pointer value to be written to *ppDestination. + * + * @return The initial value of *ppDestination. + */ +static portFORCE_INLINE void * Atomic_SwapPointers_p32( + void * volatile * ppDestination, + void * pExchange ) +{ + void * pReturnValue; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + __atomic_exchange( ppDestination, &pExchange, &pReturnValue, __ATOMIC_SEQ_CST ); + +#else + + ATOMIC_ENTER_CRITICAL(); + + pReturnValue = *ppDestination; + + *ppDestination = pExchange; + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return pReturnValue; +} + +/** + * Atomic compare-and-swap (pointers) + * + * @brief Performs an atomic compare-and-swap operation on the specified pointer + * values. + * + * @param[in, out] ppDestination Pointer to memory location from where a pointer + * value is to be loaded and checked. + * @param[in] pExchange If condition meets, write this value to memory. + * @param[in] pComparand Swap condition. + * + * @return Unsigned integer of value 1 or 0. 1 for swapped, 0 for not swapped. + * + * @note This function only swaps *ppDestination with pExchange, if previous + * *ppDestination value equals pComparand. + */ +static portFORCE_INLINE uint32_t Atomic_CompareAndSwapPointers_p32( + void * volatile * ppDestination, + void * pExchange, void * pComparand ) +{ + uint32_t ulReturnValue = ATOMIC_COMPARE_AND_SWAP_FAILURE; + +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + if ( __atomic_compare_exchange( ppDestination, + &pComparand, + &pExchange, + false, + __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST ) ) + { + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + +#else + + ATOMIC_ENTER_CRITICAL(); + + if ( *ppDestination == pComparand ) + { + *ppDestination = pExchange; + ulReturnValue = ATOMIC_COMPARE_AND_SWAP_SUCCESS; + } + + ATOMIC_EXIT_CRITICAL(); + +#endif + + return ulReturnValue; +} + + +/*----------------------------- Arithmetic ------------------------------*/ + +/** + * Atomic add + * + * @brief Atomically adds count to the value of the specified pointer points to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * @param[in] ulCount Value to be added to *pAddend. + * + * @return previous *pAddend value. + */ +static portFORCE_INLINE uint32_t Atomic_Add_u32( + uint32_t volatile * pAddend, + uint32_t ulCount ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_add(pAddend, ulCount, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend += ulCount; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic subtract + * + * @brief Atomically subtracts count from the value of the specified pointer + * pointers to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * @param[in] ulCount Value to be subtract from *pAddend. + * + * @return previous *pAddend value. + */ +static portFORCE_INLINE uint32_t Atomic_Subtract_u32( + uint32_t volatile * pAddend, + uint32_t ulCount ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_sub(pAddend, ulCount, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend -= ulCount; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic increment + * + * @brief Atomically increments the value of the specified pointer points to. + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * + * @return *pAddend value before increment. + */ +static portFORCE_INLINE uint32_t Atomic_Increment_u32( uint32_t volatile * pAddend ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_add(pAddend, 1, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend += 1; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic decrement + * + * @brief Atomically decrements the value of the specified pointer points to + * + * @param[in,out] pAddend Pointer to memory location from where value is to be + * loaded and written back to. + * + * @return *pAddend value before decrement. + */ +static portFORCE_INLINE uint32_t Atomic_Decrement_u32( uint32_t volatile * pAddend ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_sub(pAddend, 1, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pAddend; + + *pAddend -= 1; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/*----------------------------- Bitwise Logical ------------------------------*/ + +/** + * Atomic OR + * + * @brief Performs an atomic OR operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be ORed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_OR_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_or(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination |= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic AND + * + * @brief Performs an atomic AND operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be ANDed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_AND_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_and(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination &= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic NAND + * + * @brief Performs an atomic NAND operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be NANDed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_NAND_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_nand(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination = ~(ulCurrent & ulValue); + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +/** + * Atomic XOR + * + * @brief Performs an atomic XOR operation on the specified values. + * + * @param [in, out] pDestination Pointer to memory location from where value is + * to be loaded and written back to. + * @param [in] ulValue Value to be XORed with *pDestination. + * + * @return The original value of *pDestination. + */ +static portFORCE_INLINE uint32_t Atomic_XOR_u32( + uint32_t volatile * pDestination, + uint32_t ulValue ) +{ +#if defined ( configUSE_GCC_BUILTIN_ATOMICS ) && ( configUSE_GCC_BUILTIN_ATOMICS == 1 ) + + return __atomic_fetch_xor(pDestination, ulValue, __ATOMIC_SEQ_CST); + +#else + + uint32_t ulCurrent; + + ATOMIC_ENTER_CRITICAL(); + + ulCurrent = *pDestination; + + *pDestination ^= ulValue; + + ATOMIC_EXIT_CRITICAL(); + + return ulCurrent; + +#endif +} + +#ifdef __cplusplus +} +#endif + +#endif /* ATOMIC_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_atomic.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_atomic.h new file mode 100644 index 000000000..ff2a21972 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_atomic.h @@ -0,0 +1,39 @@ +/* + * Amazon FreeRTOS Common V1.0.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_atomic.h + * @brief Chooses the appropriate atomic operations header. + * + * On FreeRTOS, this file chooses the atomic header provided with the FreeRTOS + * kernel. + */ + +#ifndef IOT_ATOMIC_H_ +#define IOT_ATOMIC_H_ + +#include "atomic.h" + +#endif /* ifndef IOT_ATOMIC_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_error.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_error.h new file mode 100644 index 000000000..7afe1c2be --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_error.h @@ -0,0 +1,114 @@ +/* + * IoT Common V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_error.h + * @brief Provides macros for error checking and function cleanup. + * + * The macros in this file are generic. They may be customized by each library + * by setting the library prefix. + */ + +#ifndef IOT_ERROR_H_ +#define IOT_ERROR_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/** + * @brief Declare the status variable and an initial value. + * + * This macro should be at the beginning of any functions that use cleanup sections. + * + * @param[in] statusType The type of the status variable for this function. + * @param[in] initialValue The initial value to assign to the status variable. + */ +#define IOT_FUNCTION_ENTRY( statusType, initialValue ) statusType status = initialValue + +/** + * @brief Declares the label that begins a cleanup section. + * + * This macro should be placed at the end of a function and followed by + * #IOT_FUNCTION_CLEANUP_END. + */ +#define IOT_FUNCTION_CLEANUP_BEGIN() iotCleanup: + +/** + * @brief Declares the end of a cleanup section. + * + * This macro should be placed at the end of a function and preceded by + * #IOT_FUNCTION_CLEANUP_BEGIN. + */ +#define IOT_FUNCTION_CLEANUP_END() return status + +/** + * @brief Declares an empty cleanup section. + * + * This macro should be placed at the end of a function to exit on error if no + * cleanup is required. + */ +#define IOT_FUNCTION_EXIT_NO_CLEANUP() IOT_FUNCTION_CLEANUP_BEGIN(); IOT_FUNCTION_CLEANUP_END() + +/** + * @brief Jump to the cleanup section. + */ +#define IOT_GOTO_CLEANUP() goto iotCleanup + +/** + * @brief Assign a value to the status variable and jump to the cleanup section. + * + * @param[in] statusValue The value to assign to the status variable. + */ +#define IOT_SET_AND_GOTO_CLEANUP( statusValue ) { status = ( statusValue ); IOT_GOTO_CLEANUP(); } + +/** + * @brief Jump to the cleanup section if a condition is `false`. + * + * This macro may be used in place of `assert` to exit a function is a condition + * is `false`. + * + * @param[in] condition The condition to check. + */ +#define IOT_GOTO_CLEANUP_IF_FALSE( condition ) { if( ( condition ) == false ) { IOT_GOTO_CLEANUP(); } } + +/** + * @brief Assign a value to the status variable and jump to the cleanup section + * if a condition is `false`. + * + * @param[in] statusValue The value to assign to the status variable. + * @param[in] condition The condition to check. + */ +#define IOT_SET_AND_GOTO_CLEANUP_IF_FALSE( statusValue, condition ) \ + if( ( condition ) == false ) \ + IOT_SET_AND_GOTO_CLEANUP( statusValue ) + +/** + * @brief Check a condition; if `false`, assign the "Bad parameter" status value + * and jump to the cleanup section. + * + * @param[in] libraryPrefix The library prefix of the status variable. + * @param[in] condition The condition to check. + */ +#define IOT_VALIDATE_PARAMETER( libraryPrefix, condition ) \ + IOT_SET_AND_GOTO_CLEANUP_IF_FALSE( libraryPrefix ## _BAD_PARAMETER, condition ) + +#endif /* ifndef IOT_ERROR_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_init.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_init.h new file mode 100644 index 000000000..5253000c7 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_init.h @@ -0,0 +1,64 @@ +/* + * IoT Common V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_init.h + * @brief Provides function signatures for common initialization and cleanup of + * this SDK. + */ + +#ifndef IOT_INIT_H_ +#define IOT_INIT_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/** + * @brief One-time initialization function for this SDK. + * + * This function initializes common libraries, such as static memory and task + * pool. It must be called once (and only once) before calling any other + * function in this SDK. Calling this function more than once without first + * calling `IotSdk_Cleanup` may result in a crash. + * + * @return `true` if initialization succeeded; `false` otherwise. Logs may be + * printed in case of failure. + * + * @warning No thread-safety guarantees are provided for this function. + */ +bool IotSdk_Init( void ); + +/** + * @brief One-time deinitialization function for all common libraries. + * + * This function frees resources taken in `IotSdk_Init`. No other function + * in this SDK may be called after calling this function unless `IotSdk_Init` + * is called again. + * + * @warning No thread-safety guarantees are provided for this function. + */ +void IotSdk_Cleanup( void ); + +#endif /* IOT_INIT_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_linear_containers.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_linear_containers.h new file mode 100644 index 000000000..70fcb361b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_linear_containers.h @@ -0,0 +1,956 @@ +/* + * IoT Common V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_linear_containers.h + * @brief Declares and implements doubly-linked lists and queues. + */ + +#ifndef IOT_LINEAR_CONTAINERS_H_ +#define IOT_LINEAR_CONTAINERS_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include +#include + +/** + * @defgroup linear_containers_datatypes_listqueue List and queue + * @brief Structures that represent a list or queue. + */ + +/** + * @ingroup linear_containers_datatypes_listqueue + * @brief Link member placed in structs of a list or queue. + * + * All elements in a list or queue must contain one of these members. The macro + * #IotLink_Container can be used to calculate the starting address of the + * link's container. + */ +typedef struct IotLink +{ + struct IotLink * pPrevious; /**< @brief Pointer to the previous element. */ + struct IotLink * pNext; /**< @brief Pointer to the next element. */ +} IotLink_t; + +/** + * @ingroup linear_containers_datatypes_listqueue + * @brief Represents a doubly-linked list. + */ +typedef IotLink_t IotListDouble_t; + +/** + * @ingroup linear_containers_datatypes_listqueue + * @brief Represents a queue. + */ +typedef IotLink_t IotDeQueue_t; + +/** + * @constantspage{linear_containers,linear containers library} + * + * @section linear_containers_constants_initializers Linear Containers Initializers + * @brief Provides default values for initializing the linear containers data types. + * + * @snippet this define_linear_containers_initializers + * + * All user-facing data types of the linear containers library should be initialized + * using one of the following. + * + * @warning Failure to initialize a linear containers data type with the appropriate + * initializer may result in a runtime error! + * @note The initializers may change at any time in future versions, but their + * names will remain the same. + */ +/* @[define_linear_containers_initializers] */ +#define IOT_LINK_INITIALIZER { 0 } /**< @brief Initializer for an #IotLink_t. */ +#define IOT_LIST_DOUBLE_INITIALIZER IOT_LINK_INITIALIZER /**< @brief Initializer for an #IotListDouble_t. */ +#define IOT_DEQUEUE_INITIALIZER IOT_LINK_INITIALIZER /**< @brief Initializer for an #IotDeQueue_t. */ +/* @[define_linear_containers_initializers] */ + +/** + * @def IotContainers_Assert( expression ) + * @brief Assertion macro for the linear containers library. + * + * Set @ref IOT_CONTAINERS_ENABLE_ASSERTS to `1` to enable assertions in the linear + * containers library. + * + * @param[in] expression Expression to be evaluated. + */ +#if IOT_CONTAINERS_ENABLE_ASSERTS == 1 + #ifndef IotContainers_Assert + #ifdef Iot_DefaultAssert + #define IotContainers_Assert( expression ) Iot_DefaultAssert( expression ) + #else + #error "Asserts are enabled for containers, but IotContainers_Assert is not defined" + #endif + #endif +#else /* if IOT_CONTAINERS_ENABLE_ASSERTS == 1 */ + #define IotContainers_Assert( expression ) +#endif /* if IOT_CONTAINERS_ENABLE_ASSERTS == 1 */ + +/** + * @brief Calculates the starting address of a containing struct. + * + * @param[in] type Type of the containing struct. + * @param[in] pLink Pointer to a link member. + * @param[in] linkName Name of the #IotLink_t in the containing struct. + */ +#define IotLink_Container( type, pLink, linkName ) \ + ( ( type * ) ( void * ) ( ( ( uint8_t * ) ( pLink ) ) - offsetof( type, linkName ) ) ) + +/** + * @brief Iterates through all elements of a linear container. + * + * Container elements must not be freed or removed while iterating. + * + * @param[in] pStart The first element to iterate from. + * @param[out] pLink Pointer to a container element. + */ +#define IotContainers_ForEach( pStart, pLink ) \ + for( ( pLink ) = ( pStart )->pNext; \ + ( pLink ) != ( pStart ); \ + ( pLink ) = ( pLink )->pNext ) + +/** + * @functionspage{linear_containers,linear containers library} + * - @functionname{linear_containers_function_link_islinked} + * - @functionname{linear_containers_function_list_double_create} + * - @functionname{linear_containers_function_list_double_count} + * - @functionname{linear_containers_function_list_double_isempty} + * - @functionname{linear_containers_function_list_double_peekhead} + * - @functionname{linear_containers_function_list_double_peektail} + * - @functionname{linear_containers_function_list_double_inserthead} + * - @functionname{linear_containers_function_list_double_inserttail} + * - @functionname{linear_containers_function_list_double_insertbefore} + * - @functionname{linear_containers_function_list_double_insertafter} + * - @functionname{linear_containers_function_list_double_insertsorted} + * - @functionname{linear_containers_function_list_double_remove} + * - @functionname{linear_containers_function_list_double_removehead} + * - @functionname{linear_containers_function_list_double_removetail} + * - @functionname{linear_containers_function_list_double_removeall} + * - @functionname{linear_containers_function_list_double_findfirstmatch} + * - @functionname{linear_containers_function_list_double_removefirstmatch} + * - @functionname{linear_containers_function_list_double_removeallmatches} + * - @functionname{linear_containers_function_queue_create} + * - @functionname{linear_containers_function_queue_count} + * - @functionname{linear_containers_function_queue_isempty} + * - @functionname{linear_containers_function_queue_peekhead} + * - @functionname{linear_containers_function_queue_peektail} + * - @functionname{linear_containers_function_queue_enqueuehead} + * - @functionname{linear_containers_function_queue_dequeuehead} + * - @functionname{linear_containers_function_queue_enqueuetail} + * - @functionname{linear_containers_function_queue_dequeuetail} + * - @functionname{linear_containers_function_queue_remove} + * - @functionname{linear_containers_function_queue_removeall} + * - @functionname{linear_containers_function_queue_removeallmatches} + */ + +/** + * @functionpage{IotLink_IsLinked,linear_containers,link_islinked} + * @functionpage{IotListDouble_Create,linear_containers,list_double_create} + * @functionpage{IotListDouble_Count,linear_containers,list_double_count} + * @functionpage{IotListDouble_IsEmpty,linear_containers,list_double_isempty} + * @functionpage{IotListDouble_PeekHead,linear_containers,list_double_peekhead} + * @functionpage{IotListDouble_PeekTail,linear_containers,list_double_peektail} + * @functionpage{IotListDouble_InsertHead,linear_containers,list_double_inserthead} + * @functionpage{IotListDouble_InsertTail,linear_containers,list_double_inserttail} + * @functionpage{IotListDouble_InsertBefore,linear_containers,list_double_insertbefore} + * @functionpage{IotListDouble_InsertAfter,linear_containers,list_double_insertafter} + * @functionpage{IotListDouble_InsertSorted,linear_containers,list_double_insertsorted} + * @functionpage{IotListDouble_Remove,linear_containers,list_double_remove} + * @functionpage{IotListDouble_RemoveHead,linear_containers,list_double_removehead} + * @functionpage{IotListDouble_RemoveTail,linear_containers,list_double_removetail} + * @functionpage{IotListDouble_RemoveAll,linear_containers,list_double_removeall} + * @functionpage{IotListDouble_FindFirstMatch,linear_containers,list_double_findfirstmatch} + * @functionpage{IotListDouble_RemoveFirstMatch,linear_containers,list_double_removefirstmatch} + * @functionpage{IotListDouble_RemoveAllMatches,linear_containers,list_double_removeallmatches} + * @functionpage{IotDeQueue_Create,linear_containers,queue_create} + * @functionpage{IotDeQueue_Count,linear_containers,queue_count} + * @functionpage{IotDeQueue_IsEmpty,linear_containers,queue_isempty} + * @functionpage{IotDeQueue_PeekHead,linear_containers,queue_peekhead} + * @functionpage{IotDeQueue_PeekTail,linear_containers,queue_peektail} + * @functionpage{IotDeQueue_EnqueueHead,linear_containers,queue_enqueuehead} + * @functionpage{IotDeQueue_DequeueHead,linear_containers,queue_dequeuehead} + * @functionpage{IotDeQueue_EnqueueTail,linear_containers,queue_enqueuetail} + * @functionpage{IotDeQueue_DequeueTail,linear_containers,queue_dequeuetail} + * @functionpage{IotDeQueue_Remove,linear_containers,queue_remove} + * @functionpage{IotDeQueue_RemoveAll,linear_containers,queue_removeall} + * @functionpage{IotDeQueue_RemoveAllMatches,linear_containers,queue_removeallmatches} + */ + +/** + * @brief Check if an #IotLink_t is linked in a list or queue. + * + * @param[in] pLink The link to check. + * + * @return `true` if `pCurrent` is linked in a list or queue; `false` otherwise. + */ +/* @[declare_linear_containers_link_islinked] */ +static inline bool IotLink_IsLinked( const IotLink_t * const pLink ) +/* @[declare_linear_containers_link_islinked] */ +{ + bool isLinked = false; + + if( pLink != NULL ) + { + isLinked = ( pLink->pNext != NULL ) && ( pLink->pPrevious != NULL ); + } + + return isLinked; +} + +/** + * @brief Create a new doubly-linked list. + * + * This function initializes a new doubly-linked list. It must be called on an + * uninitialized #IotListDouble_t before calling any other doubly-linked list + * function. This function must not be called on an already-initialized + * #IotListDouble_t. + * + * This function will not fail. The function @ref linear_containers_function_list_double_removeall + * may be called to destroy a list. + * + * @param[in] pList Pointer to the memory that will hold the new doubly-linked list. + */ +/* @[declare_linear_containers_list_double_create] */ +static inline void IotListDouble_Create( IotListDouble_t * const pList ) +/* @[declare_linear_containers_list_double_create] */ +{ + /* This function must not be called with a NULL parameter. */ + IotContainers_Assert( pList != NULL ); + + /* An empty list is a link pointing to itself. */ + pList->pPrevious = pList; + pList->pNext = pList; +} + +/** + * @brief Return the number of elements contained in an #IotListDouble_t. + * + * @param[in] pList The doubly-linked list with the elements to count. + * + * @return The number of elements in the doubly-linked list. + */ +/* @[declare_linear_containers_list_double_count] */ +static inline size_t IotListDouble_Count( const IotListDouble_t * const pList ) +/* @[declare_linear_containers_list_double_count] */ +{ + size_t count = 0; + + if( pList != NULL ) + { + /* Get the list head. */ + const IotLink_t * pCurrent = pList->pNext; + + /* Iterate through the list to count the elements. */ + while( pCurrent != pList ) + { + count++; + pCurrent = pCurrent->pNext; + } + } + + return count; +} + +/** + * @brief Check if a doubly-linked list is empty. + * + * @param[in] pList The doubly-linked list to check. + * + * @return `true` if the list is empty; `false` otherwise. + */ +/* @[declare_linear_containers_list_double_isempty] */ +static inline bool IotListDouble_IsEmpty( const IotListDouble_t * const pList ) +/* @[declare_linear_containers_list_double_isempty] */ +{ + /* An empty list is NULL link, or a link pointing to itself. */ + return( ( pList == NULL ) || ( pList->pNext == pList ) ); +} + +/** + * @brief Return an #IotLink_t representing the first element in a doubly-linked list + * without removing it. + * + * @param[in] pList The list to peek. + * + * @return Pointer to an #IotLink_t representing the element at the head of the + * list; `NULL` if the list is empty. The macro #IotLink_Container may be used to + * determine the address of the link's container. + */ +/* @[declare_linear_containers_list_double_peekhead] */ +static inline IotLink_t * IotListDouble_PeekHead( const IotListDouble_t * const pList ) +/* @[declare_linear_containers_list_double_peekhead] */ +{ + IotLink_t * pHead = NULL; + + if( pList != NULL ) + { + if( IotListDouble_IsEmpty( pList ) == false ) + { + pHead = pList->pNext; + } + } + + return pHead; +} + +/** + * @brief Return an #IotLink_t representing the last element in a doubly-linked + * list without removing it. + * + * @param[in] pList The list to peek. + * + * @return Pointer to an #IotLink_t representing the element at the tail of the + * list; `NULL` if the list is empty. The macro #IotLink_Container may be used to + * determine the address of the link's container. + */ +/* @[declare_linear_containers_list_double_peektail] */ +static inline IotLink_t * IotListDouble_PeekTail( const IotListDouble_t * const pList ) +/* @[declare_linear_containers_list_double_peektail] */ +{ + IotLink_t * pTail = NULL; + + if( pList != NULL ) + { + if( IotListDouble_IsEmpty( pList ) == false ) + { + pTail = pList->pPrevious; + } + } + + return pTail; +} + +/** + * @brief Insert an element at the head of a doubly-linked list. + * + * @param[in] pList The doubly-linked list that will hold the new element. + * @param[in] pLink Pointer to the new element's link member. + */ +/* @[declare_linear_containers_list_double_inserthead] */ +static inline void IotListDouble_InsertHead( IotListDouble_t * const pList, + IotLink_t * const pLink ) +/* @[declare_linear_containers_list_double_inserthead] */ +{ + /* This function must not be called with NULL parameters. */ + IotContainers_Assert( pList != NULL ); + IotContainers_Assert( pLink != NULL ); + + /* Save current list head. */ + IotLink_t * pHead = pList->pNext; + + /* Place new element before list head. */ + pLink->pNext = pHead; + pLink->pPrevious = pList; + + /* Assign new list head. */ + pHead->pPrevious = pLink; + pList->pNext = pLink; +} + +/** + * @brief Insert an element at the tail of a doubly-linked list. + * + * @param[in] pList The double-linked list that will hold the new element. + * @param[in] pLink Pointer to the new element's link member. + */ +/* @[declare_linear_containers_list_double_inserttail] */ +static inline void IotListDouble_InsertTail( IotListDouble_t * const pList, + IotLink_t * const pLink ) +/* @[declare_linear_containers_list_double_inserttail] */ +{ + /* This function must not be called with NULL parameters. */ + IotContainers_Assert( pList != NULL ); + IotContainers_Assert( pLink != NULL ); + + /* Save current list tail. */ + IotLink_t * pTail = pList->pPrevious; + + pLink->pNext = pList; + pLink->pPrevious = pTail; + + pList->pPrevious = pLink; + pTail->pNext = pLink; +} + +/** + * @brief Insert an element before another element in a doubly-linked list. + * + * @param[in] pElement The new element will be placed before this element. + * @param[in] pLink Pointer to the new element's link member. + */ +/* @[declare_linear_containers_list_double_insertbefore] */ +static inline void IotListDouble_InsertBefore( IotLink_t * const pElement, + IotLink_t * const pLink ) +/* @[declare_linear_containers_list_double_insertbefore] */ +{ + IotListDouble_InsertTail( pElement, pLink ); +} + +/** + * @brief Insert an element after another element in a doubly-linked list. + * + * @param[in] pElement The new element will be placed after this element. + * @param[in] pLink Pointer to the new element's link member. + */ +/* @[declare_linear_containers_list_double_insertafter] */ +static inline void IotListDouble_InsertAfter( IotLink_t * const pElement, + IotLink_t * const pLink ) +/* @[declare_linear_containers_list_double_insertafter] */ +{ + IotListDouble_InsertHead( pElement, pLink ); +} + +/** + * @brief Insert an element in a sorted doubly-linked list. + * + * Places an element into a list by sorting it into order. The function + * `compare` is used to determine where to place the new element. + * + * @param[in] pList The list that will hold the new element. + * @param[in] pLink Pointer to the new element's link member. + * @param[in] compare Determines the order of the list. Returns a negative + * value if its first argument is less than its second argument; returns + * zero if its first argument is equal to its second argument; returns a + * positive value if its first argument is greater than its second argument. + * The parameters to this function are #IotLink_t, so the macro #IotLink_Container + * may be used to determine the address of the link's container. + */ +/* @[declare_linear_containers_list_double_insertsorted] */ +static inline void IotListDouble_InsertSorted( IotListDouble_t * const pList, + IotLink_t * const pLink, + int32_t ( *compare )( const IotLink_t * const, const IotLink_t * const ) ) +/* @[declare_linear_containers_list_double_insertsorted] */ +{ + /* This function must not be called with NULL parameters. */ + IotContainers_Assert( pList != NULL ); + IotContainers_Assert( pLink != NULL ); + IotContainers_Assert( compare != NULL ); + + /* Insert at head for empty list. */ + if( IotListDouble_IsEmpty( pList ) == true ) + { + IotListDouble_InsertHead( pList, pLink ); + } + else + { + bool inserted = false; + IotLink_t * pCurrent = pList->pNext; + + /* Iterate through the list to find the correct position. */ + while( pCurrent != pList ) + { + /* Comparing for '<' preserves the order of insertion. */ + if( compare( pLink, pCurrent ) < 0 ) + { + IotListDouble_InsertBefore( pCurrent, pLink ); + inserted = true; + + break; + } + + pCurrent = pCurrent->pNext; + } + + /* New element is greater than all elements in list. Insert at tail. */ + if( inserted == false ) + { + IotListDouble_InsertTail( pList, pLink ); + } + } +} + +/** + * @brief Remove a single element from a doubly-linked list. + * + * @param[in] pLink The element to remove. + */ +/* @[declare_linear_containers_list_double_remove] */ +static inline void IotListDouble_Remove( IotLink_t * const pLink ) +/* @[declare_linear_containers_list_double_remove] */ +{ + /* This function must not be called with a NULL parameter. */ + IotContainers_Assert( pLink != NULL ); + + /* This function must be called on a linked element. */ + IotContainers_Assert( IotLink_IsLinked( pLink ) == true ); + + pLink->pPrevious->pNext = pLink->pNext; + pLink->pNext->pPrevious = pLink->pPrevious; + pLink->pPrevious = NULL; + pLink->pNext = NULL; +} + +/** + * @brief Remove the element at the head of a doubly-linked list. + * + * @param[in] pList The doubly-linked list that holds the element to remove. + * + * @return Pointer to an #IotLink_t representing the removed list head; `NULL` + * if the list is empty. The macro #IotLink_Container may be used to determine + * the address of the link's container. + */ +/* @[declare_linear_containers_list_double_removehead] */ +static inline IotLink_t * IotListDouble_RemoveHead( IotListDouble_t * const pList ) +/* @[declare_linear_containers_list_double_removehead] */ +{ + IotLink_t * pHead = NULL; + + if( IotListDouble_IsEmpty( pList ) == false ) + { + pHead = pList->pNext; + IotListDouble_Remove( pHead ); + } + + return pHead; +} + +/** + * @brief Remove the element at the tail of a doubly-linked list. + * + * @param[in] pList The doubly-linked list that holds the element to remove. + * + * @return Pointer to an #IotLink_t representing the removed list tail; `NULL` + * if the list is empty. The macro #IotLink_Container may be used to determine + * the address of the link's container. + */ +/* @[declare_linear_containers_list_double_removetail] */ +static inline IotLink_t * IotListDouble_RemoveTail( IotListDouble_t * const pList ) +/* @[declare_linear_containers_list_double_removetail] */ +{ + IotLink_t * pTail = NULL; + + if( IotListDouble_IsEmpty( pList ) == false ) + { + pTail = pList->pPrevious; + IotListDouble_Remove( pTail ); + } + + return pTail; +} + +/** + * @brief Remove all elements in a doubly-linked list. + * + * @param[in] pList The list to empty. + * @param[in] freeElement A function to free memory used by each removed list + * element. Optional; pass `NULL` to ignore. + * @param[in] linkOffset Offset in bytes of a link member in its container, used + * to calculate the pointer to pass to `freeElement`. This value should be calculated + * with the C `offsetof` macro. This parameter is ignored if `freeElement` is `NULL` + * or its value is `0`. + */ +/* @[declare_linear_containers_list_double_removeall] */ +static inline void IotListDouble_RemoveAll( IotListDouble_t * const pList, + void ( *freeElement )( void * ), + size_t linkOffset ) +/* @[declare_linear_containers_list_double_removeall] */ +{ + /* This function must not be called with a NULL pList parameter. */ + IotContainers_Assert( pList != NULL ); + + /* Get the list head. */ + IotLink_t * pCurrent = pList->pNext; + + /* Iterate through the list and remove all elements. */ + while( pCurrent != pList ) + { + /* Save a pointer to the next list element. */ + IotLink_t * pNext = pCurrent->pNext; + + /* Remove and free the current list element. */ + IotListDouble_Remove( pCurrent ); + + if( freeElement != NULL ) + { + freeElement( ( ( uint8_t * ) pCurrent ) - linkOffset ); + } + + /* Move the iterating pointer to the next list element. */ + pCurrent = pNext; + } +} + +/** + * @brief Search a doubly-linked list for the first matching element. + * + * If a match is found, the matching element is not removed from the list. + * See @ref linear_containers_function_list_double_removefirstmatch for the function + * that searches and removes. + * + * @param[in] pList The doubly-linked list to search. + * @param[in] pStartPoint An element in `pList`. Only elements between this one and + * the list tail are checked. Pass `NULL` to search from the beginning of the list. + * @param[in] isMatch Function to determine if an element matches. Pass `NULL` to + * search using the address `pMatch`, i.e. `element == pMatch`. + * @param[in] pMatch If `isMatch` is `NULL`, each element in the list is compared + * to this address to find a match. Otherwise, it is passed as the second argument + * to `isMatch`. + * + * @return Pointer to an #IotLink_t representing the first matched element; `NULL` + * if no match is found. The macro #IotLink_Container may be used to determine the + * address of the link's container. + */ +/* @[declare_linear_containers_list_double_findfirstmatch] */ +static inline IotLink_t * IotListDouble_FindFirstMatch( const IotListDouble_t * const pList, + const IotLink_t * const pStartPoint, + bool ( *isMatch )( const IotLink_t * const, void * ), + void * pMatch ) +/* @[declare_linear_containers_list_double_findfirstmatch] */ +{ + /* The const must be cast away to match this function's return value. Nevertheless, + * this function will respect the const-ness of pStartPoint. */ + IotLink_t * pCurrent = ( IotLink_t * ) pStartPoint; + + /* This function must not be called with a NULL pList parameter. */ + IotContainers_Assert( pList != NULL ); + + /* Search starting from list head if no start point is given. */ + if( pStartPoint == NULL ) + { + pCurrent = pList->pNext; + } + + /* Iterate through the list to search for matches. */ + while( pCurrent != pList ) + { + /* Call isMatch if provided. Otherwise, compare pointers. */ + if( isMatch != NULL ) + { + if( isMatch( pCurrent, pMatch ) == true ) + { + return pCurrent; + } + } + else + { + if( pCurrent == pMatch ) + { + return pCurrent; + } + } + + pCurrent = pCurrent->pNext; + } + + /* No match found, return NULL. */ + return NULL; +} + +/** + * @brief Search a doubly-linked list for the first matching element and remove + * it. + * + * An #IotLink_t may be passed as `pList` to start searching after the head of a + * doubly-linked list. + * + * @param[in] pList The doubly-linked list to search. + * @param[in] pStartPoint An element in `pList`. Only elements between this one and + * the list tail are checked. Pass `NULL` to search from the beginning of the list. + * @param[in] isMatch Function to determine if an element matches. Pass `NULL` to + * search using the address `pMatch`, i.e. `element == pMatch`. + * @param[in] pMatch If `isMatch` is `NULL`, each element in the list is compared + * to this address to find a match. Otherwise, it is passed as the second argument + * to `isMatch`. + * + * @return Pointer to an #IotLink_t representing the matched and removed element; + * `NULL` if no match is found. The macro #IotLink_Container may be used to determine + * the address of the link's container. + */ +/* @[declare_linear_containers_list_double_removefirstmatch] */ +static inline IotLink_t * IotListDouble_RemoveFirstMatch( IotListDouble_t * const pList, + const IotLink_t * const pStartPoint, + bool ( *isMatch )( const IotLink_t *, void * ), + void * pMatch ) +/* @[declare_linear_containers_list_double_removefirstmatch] */ +{ + IotLink_t * pMatchedElement = IotListDouble_FindFirstMatch( pList, + pStartPoint, + isMatch, + pMatch ); + + if( pMatchedElement != NULL ) + { + IotListDouble_Remove( pMatchedElement ); + } + + return pMatchedElement; +} + +/** + * @brief Remove all matching elements from a doubly-linked list. + * + * @param[in] pList The doubly-linked list to search. + * @param[in] isMatch Function to determine if an element matches. Pass `NULL` to + * search using the address `pMatch`, i.e. `element == pMatch`. + * @param[in] pMatch If `isMatch` is `NULL`, each element in the list is compared + * to this address to find a match. Otherwise, it is passed as the second argument + * to `isMatch`. + * @param[in] freeElement A function to free memory used by each removed list + * element. Optional; pass `NULL` to ignore. + * @param[in] linkOffset Offset in bytes of a link member in its container, used + * to calculate the pointer to pass to `freeElement`. This value should be calculated + * with the C `offsetof` macro. This parameter is ignored if `freeElement` is `NULL` + * or its value is `0`. + */ +/* @[declare_linear_containers_list_double_removeallmatches] */ +static inline void IotListDouble_RemoveAllMatches( IotListDouble_t * const pList, + bool ( *isMatch )( const IotLink_t *, void * ), + void * pMatch, + void ( *freeElement )( void * ), + size_t linkOffset ) +/* @[declare_linear_containers_list_double_removeallmatches] */ +{ + IotLink_t * pMatchedElement = NULL, * pNextElement = NULL; + + /* Search the list for all matching elements. */ + do + { + pMatchedElement = IotListDouble_FindFirstMatch( pList, + pMatchedElement, + isMatch, + pMatch ); + + if( pMatchedElement != NULL ) + { + /* Save pointer to next element. */ + pNextElement = pMatchedElement->pNext; + + /* Match found; remove and free. */ + IotListDouble_Remove( pMatchedElement ); + + if( freeElement != NULL ) + { + freeElement( ( ( uint8_t * ) pMatchedElement ) - linkOffset ); + } + + /* Continue search from next element. */ + pMatchedElement = pNextElement; + } + } while( pMatchedElement != NULL ); +} + +/** + * @brief Create a new queue. + * + * This function initializes a new double-ended queue. It must be called on an uninitialized + * #IotDeQueue_t before calling any other queue function. This function must not be + * called on an already-initialized #IotDeQueue_t. + * + * This function will not fail. + * + * @param[in] pQueue Pointer to the memory that will hold the new queue. + */ +/* @[declare_linear_containers_queue_create] */ +static inline void IotDeQueue_Create( IotDeQueue_t * const pQueue ) +/* @[declare_linear_containers_queue_create] */ +{ + IotListDouble_Create( pQueue ); +} + +/** + * @brief Return the number of elements contained in an #IotDeQueue_t. + * + * @param[in] pQueue The queue with the elements to count. + * + * @return The number of items elements in the queue. + */ +/* @[declare_linear_containers_queue_count] */ +static inline size_t IotDeQueue_Count( const IotDeQueue_t * const pQueue ) +/* @[declare_linear_containers_queue_count] */ +{ + return IotListDouble_Count( pQueue ); +} + +/** + * @brief Check if a queue is empty. + * + * @param[in] pQueue The queue to check. + * + * @return `true` if the queue is empty; `false` otherwise. + * + */ +/* @[declare_linear_containers_queue_isempty] */ +static inline bool IotDeQueue_IsEmpty( const IotDeQueue_t * const pQueue ) +/* @[declare_linear_containers_queue_isempty] */ +{ + return IotListDouble_IsEmpty( pQueue ); +} + +/** + * @brief Return an #IotLink_t representing the element at the front of the queue + * without removing it. + * + * @param[in] pQueue The queue to peek. + * + * @return Pointer to an #IotLink_t representing the element at the head of the + * queue; `NULL` if the queue is empty. The macro #IotLink_Container may be used + * to determine the address of the link's container. + */ +/* @[declare_linear_containers_queue_peekhead] */ +static inline IotLink_t * IotDeQueue_PeekHead( const IotDeQueue_t * const pQueue ) +/* @[declare_linear_containers_queue_peekhead] */ +{ + return IotListDouble_PeekHead( pQueue ); +} + +/** + * @brief Return an #IotLink_t representing the element at the back of the queue + * without removing it. + * + * @param[in] pQueue The queue to peek. + * + * @return Pointer to an #IotLink_t representing the element at the head of the + * queue; `NULL` if the queue is empty. The macro #IotLink_Container may be used + * to determine the address of the link's container. + */ +/* @[declare_linear_containers_queue_peektail] */ +static inline IotLink_t * IotDeQueue_PeekTail( const IotDeQueue_t * const pQueue ) +/* @[declare_linear_containers_queue_peektail] */ +{ + return IotListDouble_PeekTail( pQueue ); +} + +/** + * @brief Add an element at the head of the queue. + * + * @param[in] pQueue The queue that will hold the new element. + * @param[in] pLink Pointer to the new element's link member. + */ +/* @[declare_linear_containers_queue_enqueuehead] */ +static inline void IotDeQueue_EnqueueHead( IotDeQueue_t * const pQueue, + IotLink_t * const pLink ) +/* @[declare_linear_containers_queue_enqueuehead] */ +{ + IotListDouble_InsertHead( pQueue, pLink ); +} + +/** + * @brief Remove an element at the head of the queue. + * + * @param[in] pQueue The queue that holds the element to remove. + * + * @return Pointer to an #IotLink_t representing the removed queue element; `NULL` + * if the queue is empty. The macro #IotLink_Container may be used to determine + * the address of the link's container. + */ +/* @[declare_linear_containers_queue_dequeuehead] */ +static inline IotLink_t * IotDeQueue_DequeueHead( IotDeQueue_t * const pQueue ) +/* @[declare_linear_containers_queue_dequeuehead] */ +{ + return IotListDouble_RemoveHead( pQueue ); +} + +/** + * @brief Add an element at the tail of the queue. + * + * @param[in] pQueue The queue that will hold the new element. + * @param[in] pLink Pointer to the new element's link member. + */ +/* @[declare_linear_containers_queue_enqueuetail] */ +static inline void IotDeQueue_EnqueueTail( IotDeQueue_t * const pQueue, + IotLink_t * const pLink ) +/* @[declare_linear_containers_queue_enqueuetail] */ +{ + IotListDouble_InsertTail( pQueue, pLink ); +} + +/** + * @brief Remove an element at the tail of the queue. + * + * @param[in] pQueue The queue that holds the element to remove. + * + * @return Pointer to an #IotLink_t representing the removed queue element; `NULL` + * if the queue is empty. The macro #IotLink_Container may be used to determine + * the address of the link's container. + */ +/* @[declare_linear_containers_queue_dequeuetail] */ +static inline IotLink_t * IotDeQueue_DequeueTail( IotDeQueue_t * const pQueue ) +/* @[declare_linear_containers_queue_dequeuetail] */ +{ + return IotListDouble_RemoveTail( pQueue ); +} + +/** + * @brief Remove a single element from a queue. + * + * @param[in] pLink The element to remove. + */ +/* @[declare_linear_containers_queue_remove] */ +static inline void IotDeQueue_Remove( IotLink_t * const pLink ) +/* @[declare_linear_containers_queue_remove] */ +{ + IotListDouble_Remove( pLink ); +} + +/** + * @brief Remove all elements in a queue. + * + * @param[in] pQueue The queue to empty. + * @param[in] freeElement A function to free memory used by each removed queue + * element. Optional; pass `NULL` to ignore. + * @param[in] linkOffset Offset in bytes of a link member in its container, used + * to calculate the pointer to pass to `freeElement`. This value should be calculated + * with the C `offsetof` macro. This parameter is ignored if `freeElement` is `NULL` + * or its value is `0`. + */ +/* @[declare_linear_containers_queue_removeall] */ +static inline void IotDeQueue_RemoveAll( IotDeQueue_t * const pQueue, + void ( * freeElement )( void * ), + size_t linkOffset ) +/* @[declare_linear_containers_queue_removeall] */ +{ + IotListDouble_RemoveAll( pQueue, freeElement, linkOffset ); +} + +/** + * @brief Remove all matching elements from a queue. + * + * @param[in] pQueue The queue to search. + * @param[in] isMatch Function to determine if an element matches. Pass `NULL` to + * search using the address `pMatch`, i.e. `element == pMatch`. + * @param[in] pMatch If `isMatch` is `NULL`, each element in the queue is compared + * to this address to find a match. Otherwise, it is passed as the second argument + * to `isMatch`. + * @param[in] freeElement A function to free memory used by each removed queue + * element. Optional; pass `NULL` to ignore. + * @param[in] linkOffset Offset in bytes of a link member in its container, used + * to calculate the pointer to pass to `freeElement`. This value should be calculated + * with the C `offsetof` macro. This parameter is ignored if `freeElement` is `NULL` + * or its value is `0`. + */ +/* @[declare_linear_containers_queue_removeallmatches] */ +static inline void IotDeQueue_RemoveAllMatches( IotDeQueue_t * const pQueue, + bool ( * isMatch )( const IotLink_t *, void * ), + void * pMatch, + void ( * freeElement )( void * ), + size_t linkOffset ) +/* @[declare_linear_containers_queue_removeallmatches] */ +{ + IotListDouble_RemoveAllMatches( pQueue, isMatch, pMatch, freeElement, linkOffset ); +} + +#endif /* IOT_LINEAR_CONTAINERS_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_logging.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_logging.h new file mode 100644 index 000000000..dc5a68b00 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_logging.h @@ -0,0 +1,226 @@ +/* + * IoT Common V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_logging.h + * @brief Generic logging function header file. + * + * Declares the generic logging function and the log levels. This file never + * needs to be included in source code. The header iot_logging_setup.h should + * be included instead. + * + * @see iot_logging_setup.h + */ + +#ifndef IOT_LOGGING_H_ +#define IOT_LOGGING_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include +#include + +/** + * @constantspage{logging,logging library} + * + * @section logging_constants_levels Log levels + * @brief Log levels for the libraries in this SDK. + * + * Each library should specify a log level by setting @ref LIBRARY_LOG_LEVEL. + * All log messages with a level at or below the specified level will be printed + * for that library. + * + * Currently, there are 4 log levels. In the order of lowest to highest, they are: + * - #IOT_LOG_NONE
+ * @copybrief IOT_LOG_NONE + * - #IOT_LOG_ERROR
+ * @copybrief IOT_LOG_ERROR + * - #IOT_LOG_WARN
+ * @copybrief IOT_LOG_WARN + * - #IOT_LOG_INFO
+ * @copybrief IOT_LOG_INFO + * - #IOT_LOG_DEBUG
+ * @copybrief IOT_LOG_DEBUG + */ + +/** + * @brief No log messages. + * + * Log messages with this level will be silently discarded. When @ref + * LIBRARY_LOG_LEVEL is #IOT_LOG_NONE, logging is disabled and no [logging functions] + * (@ref logging_functions) can be called. + */ +#define IOT_LOG_NONE 0 + +/** + * @brief Only critical, unrecoverable errors. + * + * Log messages with this level will be printed when a library encounters an + * error from which it cannot easily recover. + */ +#define IOT_LOG_ERROR 1 + +/** + * @brief Message about an abnormal but recoverable event. + * + * Log messages with this level will be printed when a library encounters an + * abnormal event that may be indicative of an error. Libraries should continue + * execution after logging a warning. + */ +#define IOT_LOG_WARN 2 + +/** + * @brief A helpful, informational message. + * + * Log messages with this level may indicate the normal status of a library + * function. They should be used to track how far a program has executed. + */ +#define IOT_LOG_INFO 3 + +/** + * @brief Detailed and excessive debug information. + * + * Log messages with this level are intended for developers. They may contain + * excessive information such as internal variables, buffers, or other specific + * information. + */ +#define IOT_LOG_DEBUG 4 + +/** + * @paramstructs{logging,logging} + */ + +/** + * @ingroup logging_datatypes_paramstructs + * @brief Log message configuration struct. + * + * @paramfor @ref logging_function_log, @ref logging_function_generic + * + * By default, log messages print the library name, log level, and a timestring. + * This struct can be passed to @ref logging_function_generic to disable one of + * the above components in the log message. + * + * Example: + * + * @code{c} + * IotLog_Generic( IOT_LOG_DEBUG, "SAMPLE", IOT_LOG_DEBUG, NULL, "Hello world!" ); + * @endcode + * The code above prints the following message: + * @code + * [DEBUG][SAMPLE][2018-01-01 12:00:00] Hello world! + * @endcode + * + * The timestring can be disabled as follows: + * @code + * IotLogConfig_t logConfig = { .hideLogLevel = false, .hideLibraryName = false, .hideTimestring = true}; + * IotLog_Generic( IOT_LOG_DEBUG, "SAMPLE", IOT_LOG_DEBUG, &logConfig, "Hello world!" ); + * @endcode + * The resulting log message will be: + * @code + * [DEBUG][SAMPLE] Hello world! + * @endcode + */ +typedef struct IotLogConfig +{ + bool hideLogLevel; /**< @brief Don't print the log level string for this message. */ + bool hideLibraryName; /**< @brief Don't print the library name for this message. */ + bool hideTimestring; /**< @brief Don't print the timestring for this message. */ +} IotLogConfig_t; + +/** + * @functionspage{logging,logging library} + * + * - @functionname{logging_function_log} + * - @functionname{logging_function_printbuffer} + * - @functionname{logging_function_generic} + * - @functionname{logging_function_genericprintbuffer} + */ + +/** + * @functionpage{IotLog_Generic,logging,generic} + * @functionpage{IotLog_PrintBuffer,logging,genericprintbuffer} + */ + +/** + * @brief Generic logging function that prints a single message. + * + * This function is the generic logging function shared across all libraries. + * The library-specific logging function @ref logging_function_log is implemented + * using this function. Like @ref logging_function_log, this function is only + * available when @ref LIBRARY_LOG_LEVEL is #IOT_LOG_NONE. + * + * In most cases, the library-specific logging function @ref logging_function_log + * should be called instead of this function. + * + * @param[in] libraryLogSetting The log level setting of the library, used to + * determine if the log message should be printed. Must be one of the @ref + * logging_constants_levels. + * @param[in] pLibraryName The library name to print. See @ref LIBRARY_LOG_NAME. + * @param[in] messageLevel The log level of the this message. See @ref LIBRARY_LOG_LEVEL. + * @param[in] pLogConfig Pointer to a #IotLogConfig_t. Optional; pass `NULL` to ignore. + * @param[in] pFormat Format string for the log message. + * @param[in] ... Arguments for format specification. + * + * @return No return value. On errors, it prints nothing. + */ +/* @[declare_logging_generic] */ +void IotLog_Generic( int libraryLogSetting, + const char * const pLibraryName, + int messageLevel, + const IotLogConfig_t * const pLogConfig, + const char * const pFormat, + ... ); +/* @[declare_logging_generic] */ + +/** + * @brief Generic function to log the contents of a buffer as bytes. + * + * This function is the generic buffer logging function shared across all libraries. + * The library-specific buffer logging function @ref logging_function_printbuffer is + * implemented using this function. Like @ref logging_function_printbuffer, this + * function is only available when @ref LIBRARY_LOG_LEVEL is #IOT_LOG_DEBUG. + * + * In most cases, the library-specific buffer logging function @ref + * logging_function_printbuffer should be called instead of this function. + * + * @param[in] pLibraryName The library name to print with the log. See @ref LIBRARY_LOG_NAME. + * @param[in] pHeader A message to print before printing the buffer. + * @param[in] pBuffer The buffer to print. + * @param[in] bufferSize The number of bytes in `pBuffer` to print. + * + * @return No return value. On errors, it prints nothing. + * + * @note To conserve memory, this function only allocates enough memory for a + * single line of output. Therefore, in multithreaded systems, its output may + * appear "fragmented" if other threads are logging simultaneously. + */ +/* @[declare_logging_genericprintbuffer] */ +void IotLog_GenericPrintBuffer( const char * const pLibraryName, + const char * const pHeader, + const uint8_t * const pBuffer, + size_t bufferSize ); +/* @[declare_logging_genericprintbuffer] */ + +#endif /* ifndef IOT_LOGGING_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_logging_setup.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_logging_setup.h new file mode 100644 index 000000000..39ceb94b1 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_logging_setup.h @@ -0,0 +1,220 @@ +/* + * IoT Common V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_logging_setup.h + * @brief Defines the logging macro #IotLog. + */ + +#ifndef IOT_LOGGING_SETUP_H_ +#define IOT_LOGGING_SETUP_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Logging include. Because it's included here, iot_logging.h never needs + * to be included in source. */ +#include "iot_logging.h" + +/** + * @functionpage{IotLog,logging,log} + * @functionpage{IotLog_PrintBuffer,logging,printbuffer} + */ + +/** + * @def IotLog( messageLevel, pLogConfig, ... ) + * @brief Logging function for a specific library. In most cases, this is the + * logging function to call. + * + * This function prints a single log message. It is available when @ref + * LIBRARY_LOG_LEVEL is not #IOT_LOG_NONE. Log messages automatically + * include the [log level](@ref logging_constants_levels), [library name] + * (@ref LIBRARY_LOG_NAME), and time. An optional @ref IotLogConfig_t may + * be passed to this function to hide information for a single log message. + * + * The logging library must be set up before this function may be called. See + * @ref logging_setup_use for more information. + * + * This logging function also has the following abbreviated forms that can be used + * when an #IotLogConfig_t isn't needed. + * + * Name | Equivalent to + * ---- | ------------- + * #IotLogError | @code{c} IotLog( IOT_LOG_ERROR, NULL, ... ) @endcode + * #IotLogWarn | @code{c} IotLog( IOT_LOG_WARN, NULL, ... ) @endcode + * #IotLogInfo | @code{c} IotLog( IOT_LOG_INFO, NULL, ... ) @endcode + * #IotLogDebug | @code{c} IotLog( IOT_LOG_DEBUG, NULL, ... ) @endcode + * + * @param[in] messageLevel Log level of this message. Must be one of the + * @ref logging_constants_levels. + * @param[in] pLogConfig Pointer to an #IotLogConfig_t. Optional; pass `NULL` + * to ignore. + * @param[in] ... Message and format specification. + * + * @return No return value. On errors, it prints nothing. + * + * @note This function may be implemented as a macro. + * @see @ref logging_function_generic for the generic (not library-specific) + * logging function. + */ + +/** + * @def IotLog_PrintBuffer( pHeader, pBuffer, bufferSize ) + * @brief Log the contents of buffer as bytes. Only available when @ref + * LIBRARY_LOG_LEVEL is #IOT_LOG_DEBUG. + * + * This function prints the bytes located at a given memory address. It is + * intended for debugging only, and is therefore only available when @ref + * LIBRARY_LOG_LEVEL is #IOT_LOG_DEBUG. + * + * Log messages printed by this function always include the [log level] + * (@ref logging_constants_levels), [library name](@ref LIBRARY_LOG_NAME), + * and time. In addition, this function may print an optional header `pHeader` + * before it prints the contents of the buffer. This function does not have an + * #IotLogConfig_t parameter. + * + * The logging library must be set up before this function may be called. See + * @ref logging_setup_use for more information. + * + * @param[in] pHeader A message to log before the buffer. Optional; pass `NULL` + * to ignore. + * @param[in] pBuffer Pointer to start of buffer. + * @param[in] bufferSize Size of `pBuffer`. + * + * @return No return value. On errors, it prints nothing. + * + * @note This function may be implemented as a macro. + * @note To conserve memory, @ref logging_function_genericprintbuffer (the underlying + * implementation) only allocates enough memory for a single line of output. Therefore, + * in multithreaded systems, its output may appear "fragmented" if other threads are + * logging simultaneously. + * @see @ref logging_function_genericprintbuffer for the generic (not library-specific) + * buffer logging function. + * + * Example + * @code{c} + * const uint8_t pBuffer[] = { 0x00, 0x01, 0x02, 0x03 }; + * + * IotLog_PrintBuffer( "This buffer contains:", + * pBuffer, + * 4 ); + * @endcode + * The code above prints something like the following: + * @code{c} + * [DEBUG][LIB_NAME][2018-01-01 12:00:00] This buffer contains: + * 00 01 02 03 + * @endcode + */ + +/** + * @def IotLogError( ... ) + * @brief Abbreviated logging macro for level #IOT_LOG_ERROR. + * + * Equivalent to: + * @code{c} + * IotLog( IOT_LOG_ERROR, NULL, ... ) + * @endcode + */ + +/** + * @def IotLogWarn( ... ) + * @brief Abbreviated logging macro for level #IOT_LOG_WARN. + * + * Equivalent to: + * @code{c} + * IotLog( IOT_LOG_WARN, NULL, ... ) + * @endcode + */ + +/** + * @def IotLogInfo( ... ) + * @brief Abbreviated logging macro for level #IOT_LOG_INFO. + * + * Equivalent to: + * @code{c} + * IotLog( IOT_LOG_INFO, NULL, ... ) + * @endcode + */ + +/** + * @def IotLogDebug( ... ) + * @brief Abbreviated logging macro for level #IOT_LOG_DEBUG. + * + * Equivalent to: + * @code{c} + * IotLog( IOT_LOG_DEBUG, NULL, ... ) + * @endcode + */ + +/* Check that LIBRARY_LOG_LEVEL is defined and has a valid value. */ +#if !defined( LIBRARY_LOG_LEVEL ) || \ + ( LIBRARY_LOG_LEVEL != IOT_LOG_NONE && \ + LIBRARY_LOG_LEVEL != IOT_LOG_ERROR && \ + LIBRARY_LOG_LEVEL != IOT_LOG_WARN && \ + LIBRARY_LOG_LEVEL != IOT_LOG_INFO && \ + LIBRARY_LOG_LEVEL != IOT_LOG_DEBUG ) + #error "Please define LIBRARY_LOG_LEVEL as either IOT_LOG_NONE, IOT_LOG_ERROR, IOT_LOG_WARN, IOT_LOG_INFO, or IOT_LOG_DEBUG." +/* Check that LIBRARY_LOG_NAME is defined and has a valid value. */ +#elif !defined( LIBRARY_LOG_NAME ) + #error "Please define LIBRARY_LOG_NAME." +#else + /* Define IotLog if the log level is greater than "none". */ + #if LIBRARY_LOG_LEVEL > IOT_LOG_NONE + #define IotLog( messageLevel, pLogConfig, ... ) \ + IotLog_Generic( LIBRARY_LOG_LEVEL, \ + LIBRARY_LOG_NAME, \ + messageLevel, \ + pLogConfig, \ + __VA_ARGS__ ) + + /* Define the abbreviated logging macros. */ + #define IotLogError( ... ) IotLog( IOT_LOG_ERROR, NULL, __VA_ARGS__ ) + #define IotLogWarn( ... ) IotLog( IOT_LOG_WARN, NULL, __VA_ARGS__ ) + #define IotLogInfo( ... ) IotLog( IOT_LOG_INFO, NULL, __VA_ARGS__ ) + #define IotLogDebug( ... ) IotLog( IOT_LOG_DEBUG, NULL, __VA_ARGS__ ) + + /* If log level is DEBUG, enable the function to print buffers. */ + #if LIBRARY_LOG_LEVEL >= IOT_LOG_DEBUG + #define IotLog_PrintBuffer( pHeader, pBuffer, bufferSize ) \ + IotLog_GenericPrintBuffer( LIBRARY_LOG_NAME, \ + pHeader, \ + pBuffer, \ + bufferSize ) + #else + #define IotLog_PrintBuffer( pHeader, pBuffer, bufferSize ) + #endif + /* Remove references to IotLog from the source code if logging is disabled. */ + #else + /* @[declare_logging_log] */ + #define IotLog( messageLevel, pLogConfig, ... ) + /* @[declare_logging_log] */ + /* @[declare_logging_printbuffer] */ + #define IotLog_PrintBuffer( pHeader, pBuffer, bufferSize ) + /* @[declare_logging_printbuffer] */ + #define IotLogError( ... ) + #define IotLogWarn( ... ) + #define IotLogInfo( ... ) + #define IotLogDebug( ... ) + #endif +#endif + +#endif /* ifndef IOT_LOGGING_SETUP_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_static_memory.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_static_memory.h new file mode 100644 index 000000000..7ddf2df2f --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/include/iot_static_memory.h @@ -0,0 +1,197 @@ +/* + * IoT Common V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_static_memory.h + * @brief Common functions for managing static buffers. Only used when + * @ref IOT_STATIC_MEMORY_ONLY is `1`. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* The functions in this file should only exist in static memory only mode, hence + * the check for IOT_STATIC_MEMORY_ONLY in the double inclusion guard. */ +#if !defined( IOT_STATIC_MEMORY_H_ ) && ( IOT_STATIC_MEMORY_ONLY == 1 ) +#define IOT_STATIC_MEMORY_H_ + +/* Standard includes. */ +#include +#include + +/** + * @functionspage{static_memory,static memory component} + * - @functionname{static_memory_function_findfree} + * - @functionname{static_memory_function_returninuse} + * - @functionname{static_memory_function_messagebuffersize} + * - @functionname{static_memory_function_mallocmessagebuffer} + * - @functionname{static_memory_function_freemessagebuffer} + */ + +/*------------------------- Buffer allocation and free ----------------------*/ + +/** + * @functionpage{IotStaticMemory_FindFree,static_memory,findfree} + * @functionpage{IotStaticMemory_ReturnInUse,static_memory,returninuse} + */ + +/** + * @brief Find a free buffer using the "in-use" flags. + * + * If a free buffer is found, this function marks the buffer in-use. This function + * is common to the static memory implementation. + * + * @param[in] pInUse The "in-use" flags to search. + * @param[in] limit How many flags to check, i.e. the size of `pInUse`. + * + * @return The index of a free buffer; `-1` if no free buffers are available. + * + * Example: + * @code{c} + * // To use this function, first declare two arrays. One provides the statically-allocated + * // objects, the other provides flags to determine which objects are in-use. + * #define NUMBER_OF_OBJECTS ... + * #define OBJECT_SIZE ... + * static uint32_t _pInUseObjects[ NUMBER_OF_OBJECTS ] = { 0 }; + * static uint8_t _pObjects[ NUMBER_OF_OBJECTS ][ OBJECT_SIZE ] = { { 0 } }; // Placeholder for objects. + * + * // The function to statically allocate objects. Must have the same signature + * // as malloc(). + * void * Iot_MallocObject( size_t size ) + * { + * int32_t freeIndex = -1; + * void * pNewObject = NULL; + * + * // Check that sizes match. + * if( size != OBJECT_SIZE ) + * { + * // Get the index of a free object. + * freeIndex = IotStaticMemory_FindFree( _pInUseMessageBuffers, + * IOT_MESSAGE_BUFFERS ); + * + * if( freeIndex != -1 ) + * { + * pNewBuffer = &( _pMessageBuffers[ freeIndex ][ 0 ] ); + * } + * } + * + * return pNewBuffer; + * } + * @endcode + */ +/* @[declare_static_memory_findfree] */ +int32_t IotStaticMemory_FindFree( uint32_t * pInUse, + size_t limit ); +/* @[declare_static_memory_findfree] */ + +/** + * @brief Return an "in-use" buffer. + * + * This function is common to the static memory implementation. + * + * @param[in] ptr Pointer to the buffer to return. + * @param[in] pPool The pool of buffers that the in-use buffer was allocated from. + * @param[in] pInUse The "in-use" flags for pPool. + * @param[in] limit How many buffers (and flags) to check while searching for ptr. + * @param[in] elementSize The size of a single element in pPool. + * + * Example: + * @code{c} + * // To use this function, first declare two arrays. One provides the statically-allocated + * // objects, the other provides flags to determine which objects are in-use. + * #define NUMBER_OF_OBJECTS ... + * #define OBJECT_SIZE ... + * static uint32_t _pInUseObjects[ NUMBER_OF_OBJECTS ] = { 0 }; + * static uint8_t _pObjects[ NUMBER_OF_OBJECTS ][ OBJECT_SIZE ] = { { 0 } }; // Placeholder for objects. + * + * // The function to free statically-allocated objects. Must have the same signature + * // as free(). + * void Iot_FreeObject( void * ptr ) + * { + * IotStaticMemory_ReturnInUse( ptr, + * _pObjects, + * _pInUseObjects, + * NUMBER_OF_OBJECTS, + * OBJECT_SIZE ); + * } + * @endcode + */ +/* @[declare_static_memory_returninuse] */ +void IotStaticMemory_ReturnInUse( void * ptr, + void * pPool, + uint32_t * pInUse, + size_t limit, + size_t elementSize ); +/* @[declare_static_memory_returninuse] */ + +/*------------------------ Message buffer management ------------------------*/ + +/** + * @functionpage{Iot_MessageBufferSize,static_memory,messagebuffersize} + * @functionpage{Iot_MallocMessageBuffer,static_memory,mallocmessagebuffer} + * @functionpage{Iot_FreeMessageBuffer,static_memory,freemessagebuffer} + */ + +/** + * @brief Get the fixed size of a message buffer. + * + * The size of the message buffers are known at compile time, but it is a [constant] + * (@ref IOT_MESSAGE_BUFFER_SIZE) that may not be visible to all source files. + * This function allows other source files to know the size of a message buffer. + * + * @return The size, in bytes, of a single message buffer. + */ +/* @[declare_static_memory_messagebuffersize] */ +size_t Iot_MessageBufferSize( void ); +/* @[declare_static_memory_messagebuffersize] */ + +/** + * @brief Get an empty message buffer. + * + * This function is the analog of [malloc] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html) + * for message buffers. + * + * @param[in] size Requested size for a message buffer. + * + * @return Pointer to the start of a message buffer. If the `size` argument is larger + * than the [fixed size of a message buffer](@ref IOT_MESSAGE_BUFFER_SIZE) + * or no message buffers are available, `NULL` is returned. + */ +/* @[declare_static_memory_mallocmessagebuffer] */ +void * Iot_MallocMessageBuffer( size_t size ); +/* @[declare_static_memory_mallocmessagebuffer] */ + +/** + * @brief Free an in-use message buffer. + * + * This function is the analog of [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html) + * for message buffers. + * + * @param[in] ptr Pointer to the message buffer to free. + */ +/* @[declare_static_memory_freemessagebuffer] */ +void Iot_FreeMessageBuffer( void * ptr ); +/* @[declare_static_memory_freemessagebuffer] */ + +#endif /* if !defined( IOT_STATIC_MEMORY_H_ ) && ( IOT_STATIC_MEMORY_ONLY == 1 ) */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/src/iot_logging.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/src/iot_logging.c new file mode 100644 index 000000000..451c9d13b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/common/src/iot_logging.c @@ -0,0 +1,451 @@ +/* + * IoT Common V1.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_logging.c + * @brief Implementation of logging functions from iot_logging.h + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include +#include + +/* Platform clock include. */ +#include "platform/iot_clock.h" + +/* Logging includes. */ +#include "iot_logging.h" + +/*-----------------------------------------------------------*/ + +/* This implementation assumes the following values for the log level constants. + * Ensure that the values have not been modified. */ +#if IOT_LOG_NONE != 0 + #error "IOT_LOG_NONE must be 0." +#endif +#if IOT_LOG_ERROR != 1 + #error "IOT_LOG_ERROR must be 1." +#endif +#if IOT_LOG_WARN != 2 + #error "IOT_LOG_WARN must be 2." +#endif +#if IOT_LOG_INFO != 3 + #error "IOT_LOG_INFO must be 3." +#endif +#if IOT_LOG_DEBUG != 4 + #error "IOT_LOG_DEBUG must be 4." +#endif + +/** + * @def IotLogging_Puts( message ) + * @brief Function the logging library uses to print a line. + * + * This function can be set by using a define. By default, the standard library + * [puts](http://pubs.opengroup.org/onlinepubs/9699919799/functions/puts.html) + * function is used. + */ +#ifndef IotLogging_Puts + #define IotLogging_Puts puts +#endif + +/* + * Provide default values for undefined memory allocation functions based on + * the usage of dynamic memory allocation. + */ +#if IOT_STATIC_MEMORY_ONLY == 1 + /* Static memory allocation header. */ + #include "iot_static_memory.h" + +/** + * @brief Allocate a new logging buffer. This function must have the same + * signature as [malloc](http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html). + */ + #ifndef IotLogging_Malloc + #define IotLogging_Malloc Iot_MallocMessageBuffer + #endif + +/** + * @brief Free a logging buffer. This function must have the same signature + * as [free](http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ + #ifndef IotLogging_Free + #define IotLogging_Free Iot_FreeMessageBuffer + #endif + +/** + * @brief Get the size of a logging buffer. Statically-allocated buffers + * should all have the same size. + */ + #ifndef IotLogging_StaticBufferSize + #define IotLogging_StaticBufferSize Iot_MessageBufferSize + #endif +#else /* if IOT_STATIC_MEMORY_ONLY == 1 */ + #ifndef IotLogging_Malloc + #include + #define IotLogging_Malloc malloc + #endif + + #ifndef IotLogging_Free + #include + #define IotLogging_Free free + #endif +#endif /* if IOT_STATIC_MEMORY_ONLY == 1 */ + +/** + * @brief A guess of the maximum length of a timestring. + * + * There's no way for this logging library to know the length of a timestring + * before it's generated. Therefore, the logging library will assume a maximum + * length of any timestring it may get. This value should be generous enough + * to accommodate the vast majority of timestrings. + * + * @see @ref platform_clock_function_gettimestring + */ +#define MAX_TIMESTRING_LENGTH ( 64 ) + +/** + * @brief The longest string in #_pLogLevelStrings (below), plus 3 to accommodate + * `[]` and a null-terminator. + */ +#define MAX_LOG_LEVEL_LENGTH ( 8 ) + +/** + * @brief How many bytes @ref logging_function_genericprintbuffer should output on + * each line. + */ +#define BYTES_PER_LINE ( 16 ) + +/*-----------------------------------------------------------*/ + +/** + * @brief Lookup table for log levels. + * + * Converts one of the @ref logging_constants_levels to a string. + */ +static const char * const _pLogLevelStrings[ 5 ] = +{ + "", /* IOT_LOG_NONE */ + "ERROR", /* IOT_LOG_ERROR */ + "WARN ", /* IOT_LOG_WARN */ + "INFO ", /* IOT_LOG_INFO */ + "DEBUG" /* IOT_LOG_DEBUG */ +}; + +/*-----------------------------------------------------------*/ + +#if !defined( IOT_STATIC_MEMORY_ONLY ) || ( IOT_STATIC_MEMORY_ONLY == 0 ) + static bool _reallocLoggingBuffer( void ** pOldBuffer, + size_t newSize, + size_t oldSize ) + { + bool status = false; + + /* Allocate a new, larger buffer. */ + void * pNewBuffer = IotLogging_Malloc( newSize ); + + /* Ensure that memory allocation succeeded. */ + if( pNewBuffer != NULL ) + { + /* Copy the data from the old buffer to the new buffer. */ + ( void ) memcpy( pNewBuffer, *pOldBuffer, oldSize ); + + /* Free the old buffer and update the pointer. */ + IotLogging_Free( *pOldBuffer ); + *pOldBuffer = pNewBuffer; + + status = true; + } + + return status; + } +#endif /* if !defined( IOT_STATIC_MEMORY_ONLY ) || ( IOT_STATIC_MEMORY_ONLY == 0 ) */ + +/*-----------------------------------------------------------*/ + +void IotLog_Generic( int libraryLogSetting, + const char * const pLibraryName, + int messageLevel, + const IotLogConfig_t * const pLogConfig, + const char * const pFormat, + ... ) +{ + int requiredMessageSize = 0; + size_t bufferSize = 0, + bufferPosition = 0, timestringLength = 0; + char * pLoggingBuffer = NULL; + va_list args; + + /* If the library's log level setting is lower than the message level, + * return without doing anything. */ + if( ( messageLevel == 0 ) || ( messageLevel > libraryLogSetting ) ) + { + return; + } + + if( ( pLogConfig == NULL ) || ( pLogConfig->hideLogLevel == false ) ) + { + /* Add length of log level if requested. */ + bufferSize += MAX_LOG_LEVEL_LENGTH; + } + + /* Estimate the amount of buffer needed for this log message. */ + if( ( pLogConfig == NULL ) || ( pLogConfig->hideLibraryName == false ) ) + { + /* Add size of library name if requested. Add 2 to accommodate "[]". */ + bufferSize += strlen( pLibraryName ) + 2; + } + + if( ( pLogConfig == NULL ) || ( pLogConfig->hideTimestring == false ) ) + { + /* Add length of timestring if requested. */ + bufferSize += MAX_TIMESTRING_LENGTH; + } + + /* Add 64 as an initial (arbitrary) guess for the length of the message. */ + bufferSize += 64; + + /* In static memory mode, check that the log message will fit in the a + * static buffer. */ + #if IOT_STATIC_MEMORY_ONLY == 1 + if( bufferSize >= IotLogging_StaticBufferSize() ) + { + /* If the static buffers are likely too small to fit the log message, + * return. */ + return; + } + + /* Otherwise, update the buffer size to the size of a static buffer. */ + bufferSize = IotLogging_StaticBufferSize(); + #endif + + /* Allocate memory for the logging buffer. */ + pLoggingBuffer = ( char * ) IotLogging_Malloc( bufferSize ); + + if( pLoggingBuffer == NULL ) + { + return; + } + + /* Print the message log level if requested. */ + if( ( pLogConfig == NULL ) || ( pLogConfig->hideLogLevel == false ) ) + { + /* Ensure that message level is valid. */ + if( ( messageLevel >= IOT_LOG_NONE ) && ( messageLevel <= IOT_LOG_DEBUG ) ) + { + /* Add the log level string to the logging buffer. */ + requiredMessageSize = snprintf( pLoggingBuffer + bufferPosition, + bufferSize - bufferPosition, + "[%s]", + _pLogLevelStrings[ messageLevel ] ); + + /* Check for encoding errors. */ + if( requiredMessageSize <= 0 ) + { + IotLogging_Free( pLoggingBuffer ); + + return; + } + + /* Update the buffer position. */ + bufferPosition += ( size_t ) requiredMessageSize; + } + } + + /* Print the library name if requested. */ + if( ( pLogConfig == NULL ) || ( pLogConfig->hideLibraryName == false ) ) + { + /* Add the library name to the logging buffer. */ + requiredMessageSize = snprintf( pLoggingBuffer + bufferPosition, + bufferSize - bufferPosition, + "[%s]", + pLibraryName ); + + /* Check for encoding errors. */ + if( requiredMessageSize <= 0 ) + { + IotLogging_Free( pLoggingBuffer ); + + return; + } + + /* Update the buffer position. */ + bufferPosition += ( size_t ) requiredMessageSize; + } + + /* Print the timestring if requested. */ + if( ( pLogConfig == NULL ) || ( pLogConfig->hideTimestring == false ) ) + { + /* Add the opening '[' enclosing the timestring. */ + pLoggingBuffer[ bufferPosition ] = '['; + bufferPosition++; + + /* Generate the timestring and add it to the buffer. */ + if( IotClock_GetTimestring( pLoggingBuffer + bufferPosition, + bufferSize - bufferPosition, + ×tringLength ) == true ) + { + /* If the timestring was successfully generated, add the closing "]". */ + bufferPosition += timestringLength; + pLoggingBuffer[ bufferPosition ] = ']'; + bufferPosition++; + } + else + { + /* Sufficient memory for a timestring should have been allocated. A timestring + * probably failed to generate due to a clock read error; remove the opening '[' + * from the logging buffer. */ + bufferPosition--; + pLoggingBuffer[ bufferPosition ] = '\0'; + } + } + + /* Add a padding space between the last closing ']' and the message, unless + * the logging buffer is empty. */ + if( bufferPosition > 0 ) + { + pLoggingBuffer[ bufferPosition ] = ' '; + bufferPosition++; + } + + va_start( args, pFormat ); + + /* Add the log message to the logging buffer. */ + requiredMessageSize = vsnprintf( pLoggingBuffer + bufferPosition, + bufferSize - bufferPosition, + pFormat, + args ); + + va_end( args ); + + /* If the logging buffer was too small to fit the log message, reallocate + * a larger logging buffer. */ + if( ( size_t ) requiredMessageSize >= bufferSize - bufferPosition ) + { + #if IOT_STATIC_MEMORY_ONLY == 1 + + /* There's no point trying to allocate a larger static buffer. Return + * immediately. */ + IotLogging_Free( pLoggingBuffer ); + + return; + #else + if( _reallocLoggingBuffer( ( void ** ) &pLoggingBuffer, + ( size_t ) requiredMessageSize + bufferPosition + 1, + bufferSize ) == false ) + { + /* If buffer reallocation failed, return. */ + IotLogging_Free( pLoggingBuffer ); + + return; + } + + /* Reallocation successful, update buffer size. */ + bufferSize = ( size_t ) requiredMessageSize + bufferPosition + 1; + + /* Add the log message to the buffer. Now that the buffer has been + * reallocated, this should succeed. */ + va_start( args, pFormat ); + requiredMessageSize = vsnprintf( pLoggingBuffer + bufferPosition, + bufferSize - bufferPosition, + pFormat, + args ); + va_end( args ); + #endif /* if IOT_STATIC_MEMORY_ONLY == 1 */ + } + + /* Check for encoding errors. */ + if( requiredMessageSize <= 0 ) + { + IotLogging_Free( pLoggingBuffer ); + + return; + } + + /* Print the logging buffer to stdout. */ + IotLogging_Puts( pLoggingBuffer ); + + /* Free the logging buffer. */ + IotLogging_Free( pLoggingBuffer ); +} + +/*-----------------------------------------------------------*/ + +void IotLog_GenericPrintBuffer( const char * const pLibraryName, + const char * const pHeader, + const uint8_t * const pBuffer, + size_t bufferSize ) +{ + size_t i = 0, offset = 0; + + /* Allocate memory to hold each line of the log message. Since each byte + * of pBuffer is printed in 4 characters (2 digits, a space, and a null- + * terminator), the size of each line is 4 * BYTES_PER_LINE. */ + char * pMessageBuffer = IotLogging_Malloc( 4 * BYTES_PER_LINE ); + + /* Exit if no memory is available. */ + if( pMessageBuffer == NULL ) + { + return; + } + + /* Print pHeader before printing pBuffer. */ + if( pHeader != NULL ) + { + IotLog_Generic( IOT_LOG_DEBUG, + pLibraryName, + IOT_LOG_DEBUG, + NULL, + pHeader ); + } + + /* Print each byte in pBuffer. */ + for( i = 0; i < bufferSize; i++ ) + { + /* Print a line if BYTES_PER_LINE is reached. But don't print a line + * at the beginning (when i=0). */ + if( ( i % BYTES_PER_LINE == 0 ) && ( i != 0 ) ) + { + IotLogging_Puts( pMessageBuffer ); + + /* Reset offset so that pMessageBuffer is filled from the beginning. */ + offset = 0; + } + + /* Print a single byte into pMessageBuffer. */ + ( void ) snprintf( pMessageBuffer + offset, 4, "%02x ", pBuffer[ i ] ); + + /* Move the offset where the next character is printed. */ + offset += 3; + } + + /* Print the final line of bytes. This line isn't printed by the for-loop above. */ + IotLogging_Puts( pMessageBuffer ); + + /* Free memory used by this function. */ + IotLogging_Free( pMessageBuffer ); +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/directories.txt b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/directories.txt new file mode 100644 index 000000000..70157b438 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/directories.txt @@ -0,0 +1,10 @@ ++ mqtt +Contains the implementation of the MQTT library. + ++ https +Contains the implementation of the HTTPS Client library. + ++ common +Contains the implementation of utility functions used by other IoT libraries. + +Further libraries will be rolled out soon. diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/include/iot_https_client.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/include/iot_https_client.h new file mode 100644 index 000000000..88ab12fc0 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/include/iot_https_client.h @@ -0,0 +1,852 @@ +/* + * Amazon FreeRTOS HTTPS Client V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_https_client.h + * @brief User-facing functions of the Amazon FreeRTOS HTTPS Client library. + */ + +#ifndef IOT_HTTPS_CLIENT_H_ +#define IOT_HTTPS_CLIENT_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* HTTP types include. */ +#include "types/iot_https_types.h" + +/** + * @functionspage{https_client,HTTPS Client Library} + * - @functionname{https_client_function_init} + * - @functionname{https_client_function_deinit} + * - @functionname{https_client_function_disconnect} + * - @functionname{https_client_function_connect} + * - @functionname{https_client_function_initializerequest} + * - @functionname{https_client_function_addheader} + * - @functionname{https_client_function_writerequestbody} + * - @functionname{https_client_function_sendsync} + * - @functionname{https_client_function_sendasync} + * - @functionname{https_client_function_cancelrequestasync} + * - @functionname{https_client_function_cancelresponseasync} + * - @functionname{https_client_function_readresponsestatus} + * - @functionname{https_client_function_readcontentlength} + * - @functionname{https_client_function_readheader} + * - @functionname{https_client_function_readresponsebody} + */ + +/** + * @functionpage{IotHttpsClient_Init,https_client,init} + * @functionpage{IotHttpsClient_Deinit,https_client,deinit} + * @functionpage{IotHttpsClient_Disconnect,https_client,disconnect} + * @functionpage{IotHttpsClient_Connect,https_client,connect} + * @functionpage{IotHttpsClient_InitializeRequest,https_client,initializerequest} + * @functionpage{IotHttpsClient_AddHeader,https_client,addheader} + * @functionpage{IotHttpsClient_WriteRequestBody,https_client,writerequestbody} + * @functionpage{IotHttpsClient_SendSync,https_client,sendsync} + * @functionpage{IotHttpsClient_SendAsync,https_client,sendasync} + * @functionpage{IotHttpsClient_CancelRequestAsync,https_client,cancelrequestasync} + * @functionpage{IotHttpsClient_CancelResponseAsync,https_client,cancelresponseasync} + * @functionpage{IotHttpsClient_ReadResponseStatus,https_client,readresponsestatus} + * @functionpage{IotHttpsClient_ReadContentLength,https_client,readcontentlength} + * @functionpage{IotHttpsClient_ReadHeader,https_client,readheader} + * @functionpage{IotHttpsClient_ReadResponseBody,https_client,readresponsebody} + */ + + +/** + * @brief One-time initialization of the IoT HTTPS Client library. + * + * This must be called once before calling any API. + * + * @warning No thread safety guarantees are provided for this function. + * + * @return One of the following: + * - #IOT_HTTPS_OK if the HTTPS library is successfully initialized. + * + * @see @ref https_client_function_cleanup + */ +/* @[declare_https_client_init] */ +IotHttpsReturnCode_t IotHttpsClient_Init( void ); +/* @[declare_https_client_init] */ + +/** + * @brief One time clean up of the IoT HTTPS Client library. + * + * This function frees resources taken in in @ref https_client_function_init. It should be called after + * all HTTPS Connections have been close. HTTPS Connections are represented by #IotHttpsConnectionHandle_t and returned + * by @ref https_client_function_connect. After this function returns @ref https_client_function_init + * must be called again to use this library. + * + * @warning No thread safety guarantees are provided for this function. + */ +/* @[declare_https_client_cleanup] */ +void IotHttpsClient_Cleanup( void ); +/* @[declare_https_client_cleanup] */ + +/** + * @cond DOXYGEN_IGNORE + * + * Backward compatibility function for one time clean up of the IoT HTTPS Client library. + */ +#define IotHttpsClient_Deinit IotHttpsClient_Cleanup +/** @endcond */ + +/** + * @brief Explicitly connect to the HTTPS server given the connection configuration pConnConfig. + * + * This routine blocks until the connection is complete. + * + * This function opens a new HTTPS connection with the server specified in #IotHttpsConnectionInfo_t.pAddress. The + * connection is established by default on top of TLS over TCP. If the application wants to connect over TCP only, then + * it must add the @ref IOT_HTTPS_IS_NON_TLS_FLAG to #IotHttpsConnectionInfo_t.flags. This is done at the application's + * own risk. + * + * When the the last HTTP request sent on the connection is specified as persistent and we want to close the connection, + * @ref https_client_function_disconnect must always be called on the valid #IotHttpsConnectionHandle_t. For more + * information about persistent HTTP connections please see #IotHttpsRequestInfo_t.isNonPersistent. + * + * If the application receives a #IOT_HTTPS_NETWORK_ERROR from @ref https_client_function_sendsync or + * @ref https_client_function_sendasync, on a persistent request, then the connection will be closed. The application + * can call this this function again to reestablish the connection. + * + * If pConnHandle passed in is valid and represents a previously opened connection, this function will disconnect, + * then reconnect. Before calling this function make sure that all outstanding requests on the connection have + * completed. Outstanding requests are completed when @ref https_client_function_sendsync has returned or when + * #IotHttpsClientCallbacks_t.responseCompleteCallback has been invoked for requests scheduled with + * @ref https_client_function_sendasync. + * + * Keep in mind that many HTTP servers will close a connection, if it does not receive any requests, after a certain + * amount of time. Many web servers may close the connection after 30-60 seconds. The state of pConnHandle will still be + * in a connected state if this happens. If the server closed the connection, then the next request on the connection + * will fail to send with a network error and the connection will move to a closed state. + * + * Also keep in mind that some HTTP servers do not accept persistent requests. Some HTTP servers will ignore that the + * request contains the "Connection: keep-alive" header and close the connection immediately after sending the response. + * If this happens, then the next request on the connection will fail to send with a network error and the connection + * will close. + * + * To know if the connection was closed by the server, debug logging can be turned on to view the network error code + * received. Debug logging is configured when @ref IOT_LOG_LEVEL_HTTPS is set to @ref IOT_LOG_DEBUG in iot_config.h. + * + * #IotHttpsConnectionInfo_t.userBuffer is used to store the internal context and therefore, multiple threads + * calling this function simultaneously must ensure to use different #IotHttpsConnectionInfo_t objects. + * + * See @ref connectionUserBufferMinimumSize for information about the user buffer configured in + * #IotHttpsConnectionInfo_t.userBuffer needed to create a valid connection handle. + * + * @param[out] pConnHandle - Handle returned representing the open connection. NULL if the function failed. + * @param[in] pConnInfo - Configurations for the HTTPS connection. + * + * @return One of the following: + * - #IOT_HTTPS_OK if the connection was successful. + * - #IOT_HTTPS_CONNECTION_ERROR if the connection failed. + * - #IOT_HTTPS_INVALID_PARAMETER if NULL parameters were passed in. + * - #IOT_HTTPS_INTERNAL_ERROR if there was an error creating resources for the connection context. + * + * Example + * @code{c} + * // An initialized network interface. + * IotNetworkInterface_t* pNetworkInterface; + * + * // Parameters to HTTPS Client connect. + * IotHttpsConnectionInfo_t connInfo = IOT_HTTPS_CONNECTION_INFO_INITIALIZER; + * IotHttpsConnectionHandle_t connHandle = IOT_HTTPS_CONNECTION_HANDLE_INITIALIZER; + * uint8_t* pConnUserBuffer = (uint8_t*)malloc(connectionUserBufferMinimumSize); + * + * // Set the connection configuration information. + * connInfo.pAddress = "www.amazon.com"; + * connInfo.addressLen = strlen("www.amazon.com"); + * connInfo.port = 443; + * connInfo.flags = 0; + * connInfo.pAlpnProtocols = "alpnproto0,alpnproto1" + * connInfo.pCaCert = HTTPS_TRUSTED_ROOT_CA; // defined elsewhere + * connInfo.caCertLen = sizeof( HTTPS_TRUSTED_ROOT_CA ); + * connInfo.userBuffer.pBuffer = pConnUserBuffer; + * connInfo.userBuffer.bufferLen = connectionUserBufferMinimumSize; + * connInfo.pClientCert = TLS_CLIENT_CERT; + * connInfo.clientCertLen = sizeof( TLS_CLIENT_CERT ); + * connInfo.pPrivateKey = TLS_CLIENT_PRIV_KEY; + * connInfo.privateKeyLen = sizeof( TLS_CLIENT_PRIV_KEY ); + * connInfo.pNetworkInterface = pNetworkInterface; + * + * IotHttpsReturnCode_t returnCode = IotHttpsClient_Connect(&connHandle, &connInfo); + * if( returnCode == IOT_HTTPS_OK ) + * { + * // Do something with the HTTPS connection... + * + * // Clean up and close the HTTPS connection once it's no longer needed. + * IotHttpsClient_Disconnect(connHandle); + * } + * @endcode + */ +/* @[declare_https_client_connect] */ +IotHttpsReturnCode_t IotHttpsClient_Connect( IotHttpsConnectionHandle_t * pConnHandle, + IotHttpsConnectionInfo_t * pConnInfo ); +/* @[declare_https_client_connect] */ + +/** + * @brief Disconnect from the HTTPS server given the connection handle connHandle. + * + * This routine blocks until the disconnect is complete. + * If the connection handle is not valid, the behavior is undefined. + * If the connection handle is already disconnected then this routine will return IOT_HTTPS_OK. + * + * When the HTTP request is specified as persistent and we want to close the connection, this API must always + * be called on the valid #IotHttpsConnectionHandle_t. For more information about persistent HTTP connections please see + * #IotHttpsRequestInfo_t.isNonPersistent. + * + * When the HTTP request is specified as non-persistent, by setting #IotHttpsRequestInfo_t.isNonPersistent to true, then + * this function will be called automatically on the valid IotHttpsConnectionHandle_t after receiving the response. There + * is no need to call this function in case of a non-persistent request. + * + * This will put the internal connection state in #IotHttpsConnectionHandle_t to disconnected. + * + * If the application receives a #IOT_HTTPS_NETWORK_ERROR from @ref https_client_function_sendsync or + * @ref https_client_function_sendasync, on a persistent request, that does not always mean the connection has been + * disconnected. This function MUST be called to close the connection and clean up connection resources taken by + * #IotHttpsConnectionHandle_t. + * + * This function will cancel all pending requests on the connection. If a request currently being sent on the connection, + * then this function will disconnect the connection, but it will not free network connection resource and will return + * with #IOT_HTTPS_BUSY. The application may call this function again later to try again. + * + * Multiple threads must not call this function for the same #IotHttpsConnectionHandle_t. Multiple threads + * can call this function for different #IotHttpsConnectionHandle_t. Make sure that all request/responses + * have finished on the connection before calling this API. Outstanding requests are completed when + * @ref https_client_function_sendsync has returned or when #IotHttpsClientCallbacks_t.responseCompleteCallback + * has been invoked for requests scheduled with @ref https_client_function_sendasync. + * + * @param[in] connHandle - Valid handle representing an open connection. + * + * @return One of the following: + * - #IOT_HTTPS_OK if the disconnect was successful + * - #IOT_HTTPS_INVALID_PARAMETER if NULL parameters were passed in. + * - #IOT_HTTPS_BUSY if the connection is in use and cannot be destroyed. + */ +/* @[declare_https_client_disconnect] */ +IotHttpsReturnCode_t IotHttpsClient_Disconnect( IotHttpsConnectionHandle_t connHandle ); +/* @[declare_https_client_disconnect] */ + +/** + * @brief Initializes the request by adding a formatted Request-Line to the start of HTTPS request header buffer. + * + * This function will initialize the HTTP request context by setting where to write the next headers to the start + * of the configured header buffer in #IotHttpsRequestInfo_t.userBuffer. + * + * The Request-Line will be added to the start of the headers space in #IotHttpsRequestInfo_t.userBuffer. + * The header space follows the request context in the user buffer. See @ref requestUserBufferMinimumSize for more + * information on sizing the #IotHttpsRequestInfo_t.userBuffer so that this function does not fail. + * + * The Request-Line generated is of the following format: + * + * @code + * method path version\r\n + * @endcode + * + * Example: + * + * @code + * GET /path/to/item.file?possible_query HTTP/1.1\r\n + * @endcode + * + * The initial required headers are also added to the #IotHttpsRequestInfo_t.userBuffer. These headers are User-Agent + * and Host. The User-Agent value is configured in iot_config.h using IOT_HTTPS_USER_AGENT. The Host value is the DNS + * resolvable server address. + * + * @param[out] pReqHandle - request handle representing the internal request context is returned. NULL if the function failed. + * @param[in] pReqInfo - HTTPS request information. + * + * @return One of the following: + * - #IOT_HTTPS_OK if the Request-Line was successfully added to the header space in #IotHttpsRequestInfo_t.userBuffer. + * - #IOT_HTTPS_INSUFFICIENT_MEMORY if the Request-Line generated exceeds #IotHttpsUserBuffer_t.bufferLen in #IotHttpsRequestInfo_t.userBuffer. + * - #IOT_HTTPS_INVALID_PARAMETER for NULL parameters. + * - #IOT_HTTPS_INTERNAL_ERROR for library internal errors. + * + * Example + * @code{c} + * // An initialized network interface. + * IotNetworkInterface_t* pNetworkInterface; + * + * // Parameters to HTTPS Client request initialization. + * IotHttpsRequestInfo_t reqInfo = IOT_HTTPS_REQUEST_INFO_INITIALIZER; + * IotHttpsRequestHandle_t reqHandle = IOT_HTTPS_REQUEST_HANDLE_INITIALIZER; + * IotHttpsSyncInfo_t syncInfo = IOT_HTTPS_SYNC_INFO_INITIALIZER; + * // Leave some room for extra headers. + * uint32_t userBufferSize = requestUserBufferMinimumSize + 256; + * uint8_t* pRequestUserBuffer = (uint8_t*)malloc(userBufferSize); + * + * // Set the synchronous information. + * syncInfo.pBody = PREDEFINED_BODY_BUFFER; + * syncInfo.bodyLen = PREDEFINED_BODY_BUFFER_LEN; + * + * // Set the request configuration information. + * reqInfo.pPath = "/path_to_item?query_maybe"; + * reqInfo.pPathLen = strlen("/path_to_item?query_maybe"); + * reqInfo.method = IOT_HTTPS_METHOD_GET; + * reqInfo.pHost = "www.amazon.com"; + * reqInfo.hostLen = strlen("www.amazon.com"); + * reqInfo.isNonPersistent = false; + * reqInfo.userBuffer.pBuffer = pRequestUserBuffer; + * reqInfo.userBuffer.bufferLen = userBufferSize; + * reqInfo.isAsync = false; + * reqInfo.pSyncInfo = &syncInfo; + * + * IotHttpsReturnCode_t returnCode = IotHttpsClient_InitializeRequest(&reqHandle, &reqInfo); + * if( returnCode == IOT_HTTPS_OK ) + * { + * // Handle the error. + * } + * @endcode + */ +/* @[declare_https_client_initializerequest] */ +IotHttpsReturnCode_t IotHttpsClient_InitializeRequest( IotHttpsRequestHandle_t * pReqHandle, + IotHttpsRequestInfo_t * pReqInfo ); +/* @[declare_https_client_initializerequest] */ + +/** + * @brief Add a header to the current HTTPS request represented by reqHandle. + * + * The header line is appended to the request header buffer space in #IotHttpsRequestInfo_t.userBuffer. + * Please see #requestUserBufferMinimumSize for information about sizing the #IotHttpsRequestInfo_t.userBuffer so + * that this function does not fail. + * + * Header lines are appended in the following format: + * @code + * header_field_name: header_value\r\n" + * @endcode + * Example: + * @code + * Range: bytes=1024-2047\r\n + * @endcode + * The last header line must be followed by a "\r\n" to separate the last header line from + * the entity body. These 2 characters are accounted for in #requestUserBufferMinimumSize. + * + * The remaining length, after the header is added, is printed to the system configured standard debug output when + * @ref IOT_LOG_LEVEL_HTTPS is set to @ref IOT_LOG_DEBUG in iot_config.h. + * + * For an asynchronous request, this function can be invoked before the request is sent with + * @ref https_client_function_sendasync, or during #IotHttpsClientCallbacks_t.appendHeaderCallback. It is + * recommended to invoke this function in #IotHttpsClientCallbacks_t.appendHeaderCallback. + * + * Asynchronous Example + * @code{c} + * void _applicationDefined_appendHeaderCallback(void * pPrivData, IotHttpsRequestHandle_t reqHandle) + * { + * ... + * char date_in_iso8601[17] = { 0 }; + * GET_DATE_IN_ISO8601(date_in_iso8601); + * const char amz_date_header[] = "x-amz-date"; + * uint32_t amz_date_header_length = strlen(amz_date_header); + * IotHttpsClient_AddHeader(reqHandle, amz_date_header, amz_date_header_length, date_in_iso8601, strlen(date_in_iso8601)); + * ... + * } + * @endcode + * + * For a synchronous request, if extra headers are desired to be added, this function must be invoked before + * @ref https_client_function_sendsync. + * Synchronous Example + * @code{c} + * ... + * char date_in_iso8601[17] = { 0 }; + * GET_DATE_IN_ISO8601(date_in_iso8601); + * const char amz_date_header[] = "x-amz-date"; + * uint32_t amz_date_header_length = strlen(amz_date_header); + * IotHttpsClient_AddHeader(reqHandle, amz_date_header, amz_date_header_length, date_in_iso8601, strlen(date_in_iso8601)); + * ... + * IotHttpsClient_SendSync(connHandle, reqHandle, &respHandle, &respInfo, timeout); + * ... + * @endcode + * + * The following header fields are automatically added to the request header buffer and must NOT be added again with + * this routine: + * - Connection: - This header is added to the request when the headers are being sent on the network. + * - User-agent: - This header is added during @ref https_client_function_initializerequest + * - Host: - This header is added during @ref https_client_function_initializerequest + * - Content-Length: - This header is added to the request when the headers are being sent on the network. + * + * The reqHandle is not thread safe. If two threads have the same reqHandle and attempt to add headers at the same + * time, garbage strings may be written to the reqHandle. + * + * @param[in] reqHandle - HTTPS request to write the header line to. + * @param[in] pName - String header field name to write. + * @param[in] nameLen - The length of the header name to write. + * @param[in] pValue - https header value buffer pointer. Do not include token name. + * @param[in] valueLen - length of header value to write. + * + * @return One of the following: + * - #IOT_HTTPS_OK if the header line was successfully added to the header space in #IotHttpsRequestInfo_t.userBuffer. + * - #IOT_HTTPS_INSUFFICIENT_MEMORY if the header line cannot fit into the header buffer. + * - #IOT_HTTPS_INVALID_PARAMETER for NULL parameters or if an attempt to add automatically added headers is made. + */ +/* @[declare_https_client_addheader] */ +IotHttpsReturnCode_t IotHttpsClient_AddHeader( IotHttpsRequestHandle_t reqHandle, + char * pName, + uint32_t nameLen, + char * pValue, + uint32_t valueLen ); +/* @[declare_https_client_addheader] */ + +/** + * @brief Writes the request body to the network for the request represented by reqHandle. + * + * This function is intended to be used by an asynchronous request. It must be called within the + * #IotHttpsClientCallbacks_t.writeCallback. + * + * In HTTP/1.1 the headers are sent on the network first before any body can be sent. The auto-generated header + * Content-Length is taken from the len parameter and sent first before the data in parameter pBuf is sent. + * This library does not support Transfer-Encoding: chunked or other requests where the Content-Length is unknown, so + * this function cannot be called more than once in #IotHttpsClientCallbacks_t.writeCallback for an HTTP/1.1 request. + * + * isComplete must always be set to 1 in this current version of the HTTPS client library. + * + * If there are network errors in sending the HTTP headers, then the #IotHttpsClientCallbacks_t.errorCallback will be + * invoked following a return from the #IotHttpsClientCallbacks_t.writeCallback. + * + * Example Asynchronous Code + * @code{c} + * void applicationDefined_writeCallback(void * pPrivData, IotHttpsRequestHandle_t reqHandle) + * { + * ... + * char * writeData[1024]; + * IotHttpsClient_WriteRequestBody(reqHandle, writeData, 1024, 1); + * ... + * } + * @endcode + * + * @param[in] reqHandle - identifier of the connection. + * @param[in] pBuf - client write data buffer pointer. + * @param[in] len - length of data to write. + * @param[in] isComplete - This parameter parameter must be set to 1. + * + * @return one of the following: + * - #IOT_HTTPS_OK if write successfully, failure code otherwise. + * - #IOT_HTTPS_MESSAGE_FINISHED if this function is called a second time with the same reqHandle. + * - #IOT_HTTPS_NOT_SUPPORTED if isComplete is set to 0. + * - #IOT_HTTPS_INVALID_PARAMETER if this API is used for a synchronous request. + * - #IOT_HTTPS_NETWORK_ERROR if there was an error sending the headers or body on the network. + * - Please see #IotHttpsReturnCode_t for other failure codes. + */ +/* @[declare_https_client_writerequestbody] */ +IotHttpsReturnCode_t IotHttpsClient_WriteRequestBody( IotHttpsRequestHandle_t reqHandle, + uint8_t * pBuf, + uint32_t len, + int isComplete ); +/* @[declare_https_client_writerequestbody] */ + +/** + * @brief Synchronous send of the HTTPS request. + * + * This function blocks waiting for the entirety of sending the request and receiving the response. + * + * If #IotHttpsRequestInfo_t.isNonPersistent is set to true, then the connection will disconnect, close, and clean all + * taken resources automatically after receiving the first response. + * + * See @ref connectionUserBufferMinimumSize for information about the user buffer configured in + * #IotHttpsConnectionInfo_t.userBuffer needed to create a valid connection handle. + * + * To retrieve the response body applications must directly refer #IotHttpsSyncInfo_t.pBody configured in #IotHttpsRequestInfo_t.u. + * + * If the response body does not fit in the configured #IotHttpsSyncInfo_t.pBody, then this function will return with error + * #IOT_HTTPS_MESSAGE_TOO_LARGE. To avoid this issue, the application needs to determine beforehand how large the file + * to download is. This can be done with a HEAD request first, then extracting the "Content-Length" with + * @ref https_client_function_readcontentlength. This could also be done with a GET request with the header + * "Range: bytes=0-0", then extracting the "Content-Range" with @ref https_client_function_readheader. Keep in mind that + * not all HTTP servers support Partial Content responses. + * + * Once a the file size is known, the application can initialize the request with a large + * enough buffer or the application can make a partial content request with the header + * "Range: bytes=N-M", where N is the starting byte requested and M is the ending byte requested. + * + * The response headers as received from the network will be stored in the header buffer space in + * #IotHttpsResponseInfo_t.userBuffer. If the configured #IotHttpsResponseInfo_t.userBuffer is too small + * to fit the headers received, then headers that don't fit will be thrown away. Please see + * #responseUserBufferMinimumSize for information about sizing the #IotHttpsResponseInfo_t.userBuffer. + * To receive feedback on headers discarded, debug logging must be turned on in iot_config.h by setting + * @ref IOT_LOG_LEVEL_HTTPS to @ref IOT_LOG_DEBUG. + * + * Multiple threads must not call this function for the same #IotHttpsRequestHandle_t. Multiple threads can call this + * function for a different #IotHttpsRequestHandle_t, even on the same #IotHttpsConnectionHandle_t. An application must + * wait util a request is fully sent, before scheduling it again. A request is fully sent when this function has returned. + * + * @param[in] connHandle - Handle from an HTTPS connection created with @ref https_client_function_connect. + * @param[in] reqHandle - Handle from a request created with @ref https_client_function_initializerequest. + * @param[out] pRespHandle - HTTPS response handle resulting from a successful send and receive. + * @param[in] pRespInfo - HTTP response configuration information. + * @param[in] timeoutMs - Timeout waiting for the sync request to finish. Set this to 0 to wait forever. + * + * @return One of the following: + * - #IOT_HTTPS_OK if the request was sent and the response was received successfully. + * - #IOT_HTTPS_MESSAGE_TOO_LARGE if the response cannot fit in the configured struct IotHttpsRequestHandle.userBuffer.pBuffer and struct IotHttpsRequestHandle.u.pSyncInfo.pRespData. + * - #IOT_HTTPS_CONNECTION_ERROR if the connection failed. + * - #IOT_HTTPS_INVALID_PARAMETER if there are NULL parameters or the request is asynchronous. + * - #IOT_HTTPS_NETWORK_ERROR if there was an error sending the data on the network. + * - #IOT_HTTPS_PARSING_ERROR if there was an error parsing the HTTP response. + * - #IOT_HTTPS_TIMEOUT_ERROR if the timeoutMs is reached when waiting for a response to the request. + */ +/* @[declare_https_client_sendsync] */ +IotHttpsReturnCode_t IotHttpsClient_SendSync( IotHttpsConnectionHandle_t connHandle, + IotHttpsRequestHandle_t reqHandle, + IotHttpsResponseHandle_t * pRespHandle, + IotHttpsResponseInfo_t * pRespInfo, + uint32_t timeoutMs ); +/* @[declare_https_client_sendsync] */ + +/** + * @brief Asynchronous send of the the HTTPS request. + * + * This function will invoke, as needed, each of the non-NULL callbacks configured in #IotHttpsAsyncInfo_t.callbacks + * when the scheduled asynchronous request is progress. Please see #IotHttpsClientCallbacks_t for information on each of + * the callbacks. + * + * After this API is executed, the scheduled async response will store the response headers as received from + * the network, in the header buffer space configured in #IotHttpsResponseInfo_t.userBuffer. If the + * configured #IotHttpsResponseInfo_t.userBuffer is too small to fit the headers received, then headers that don't + * fit will be thrown away. Please see #responseUserBufferMinimumSize for information about sizing the + * #IotHttpsResponseInfo_t.userBuffer. + * + * If #IotHttpsRequestInfo_t.isNonPersistent is set to true, then the connection will disconnect, close, and clean all + * taken resources automatically after receiving the first response. + * + * See @ref connectionUserBufferMinimumSize for information about the user buffer configured in + * #IotHttpsConnectionInfo_t.userBuffer needed to create a valid connection handle. + * + * A #IotHttpsRequestHandle_t cannot be schedule again or reused until the request has finished sending. The request + * has safely finished sending once #IotHttpsClientCallbacks_t.readReadyCallback is invoked. After the + * #IotHttpsClientCallbacks_t.readReadyCallback is invoked the #IotHttpsRequestInfo_t.userBuffer can freed, + * modified, or reused. + * + * @param[in] connHandle - Handle from an HTTPS connection. + * @param[in] reqHandle - Handle from a request created with IotHttpsClient_initialize_request. + * @param[out] pRespHandle - HTTPS response handle. + * @param[in] pRespInfo - HTTP response configuration information. + * + * @return One of the following: + * - #IOT_HTTPS_OK if the request was sent and the response was received successfully. + * - #IOT_HTTPS_MESSAGE_TOO_LARGE if the response cannot fit in the configured + * IotHttpsRequestHandle_t.response_message.headers and IotHttpsRequestHandle_t.response_message.body. + * - #IOT_HTTPS_CONNECTION_ERROR if the connection failed. + * - #IOT_HTTPS_FATAL if there was a grave error with the last async job finishing. + * - #IOT_HTTPS_ASYNC_SCHEDULING_ERROR if there was an error scheduling the asynchronous request. + * - #IOT_HTTPS_INTERNAL_ERROR if there was an internal error with starting an asynchronous request servicing task. + * - #IOT_HTTPS_INVALID_PARAMETER if there were NULL parameters or the request passed in was a synchronous type. + * + */ +/* @[declare_https_client_sendasync] */ +IotHttpsReturnCode_t IotHttpsClient_SendAsync( IotHttpsConnectionHandle_t connHandle, + IotHttpsRequestHandle_t reqHandle, + IotHttpsResponseHandle_t * pRespHandle, + IotHttpsResponseInfo_t * pRespInfo ); +/* @[declare_https_client_sendasync] */ + +/** + * @brief Cancel an Asynchronous request. + * + * This will stop an asynchronous request. When an asynchronous request is stopped it will not proceed to do any of + * the following: send headers, send body, receive headers, or receive body. This depends on where in the process + * the request is. For example, if the request is cancelled after sending the headers, then it will not attempt tp + * send the body. A cancelled return code will be returned to the application. + * + * If this is called before the scheduled asynchronous request actually runs, then request will not be sent. + * If this is called during any of the asynchronous callbacks, then the library will stop processing the request when + * the callback returns. This is useful for any error conditions, found during the asynchronous callbacks, where the + * application wants to stop the rest of the request processing. + * + * If the asynchronous request stops processing, the buffers in #IotHttpsRequestInfo_t.userBuffer can be safely freed, + * modified, or reused, only once #IotHttpsClientCallbacks_t.readReadyCallback is invoked. + * + * Example Asynchronous Code + * @code{c} + * void _applicationDefined_appendHeaderCallback(void * pPrivData, IotHttpsRequestHandle_t reqHandle) + * { + * char token[MAX_TOKEN_LENGTH] = { 0 } + * int len = MAX_TOKEN_LENGTH; + * int status = gen_auth_token(token, &len); + * if( status == GEN_TOKEN_FAIL) + * { + * IotHttpsClient_CancelRequestAsync(reqHandle); + * } + * ... + * } + * + * void _applicationDefined_writeCallback(void * pPrivData, IotHttpsRequestHandle_t reqHandle) + * { + * if( application_data_get(writeBuffer, writeBufferLen) == GEN_TOKEN_FAIL) + * { + * IotHttpsClient_CancelRequestAsync(reqHandle); + * } + * ... + * } + * @endcode + * + * @param[in] reqHandle - Request handle associated with the request. + * + * @return One of the following: + * - IOT_HTTPS_OK if the request was successfully cancelled. + */ +/* @[declare_https_client_cancelrequestasync] */ +IotHttpsReturnCode_t IotHttpsClient_CancelRequestAsync( IotHttpsRequestHandle_t reqHandle ); +/* @[declare_https_client_cancelrequestasync] */ + +/** + * @brief Cancel an Asynchronous response. + * + * This will stop an asynchronous response. When an asynchronous response is stopped it will not proceed to do any of + * the following: send headers, send body, receive headers, or receive body. This depends on where in the process + * the response is. For example, if the response is cancelled after receiving the headers, then it will not attempt tp + * receive the body. A cancelled return code will be returned to the application. + * + * If this is called during ANY of the asynchronous callbacks, then the library will stop processing the response when + * the callback returns. This is useful for any error conditions, found during the asynchronous callbacks, where the + * application wants to stop the rest of the response processing. + * + * If the asynchronous response stops processing, the buffers configured in #IotHttpsResponseInfo_t.userBuffer can + * be freed, modified, or reused only after the #IotHttpsClientCallbacks_t.responseCompleteCallback in invoked. + * + * Example Asynchronous Code + * @code{c} + * + * void applicationDefined_readReadyCallback(void * pPrivData, IotHttpsResponseHandle_t respHandle, IotHttpsReturnCode_t rc, uint16_t status) + * { + * ... + * if (status != IOT_HTTPS_STATUS_OK) + * { + * IotHttpsClient_CancelResponseAsync(NULL, respHandle); + * } + * ... + * } + * @endcode + * + * @param[in] respHandle - Response handle associated with the response. + * + * @return One of the following: + * - #IOT_HTTPS_OK if the response was successfully cancelled. + */ +/* @[declare_https_client_cancelresponseasync] */ +IotHttpsReturnCode_t IotHttpsClient_CancelResponseAsync( IotHttpsResponseHandle_t respHandle ); +/* @[declare_https_client_cancelresponseasync] */ + +/** + * @brief Retrieve the HTTPS response status. + * + * The HTTP response status code is contained in the Status-Line of the response header buffer configured in + * #IotHttpsResponseInfo_t.userBuffer. It is the first line of a standard HTTP response message. If the response + * Status-Line could not fit into #IotHttpsResponseInfo_t.userBuffer, then this function will return an error code. + * Please see #responseUserBufferMinimumSize for information about sizing the #IotHttpsResponseInfo_t.userBuffer. + * + * This routine can be used for both a synchronous and asynchronous response. + * + * Example Synchronous Code + * @code{c} + * ... + * IotHttpsClient_SendSync(connHandle, reqHandle, &respHandle, &respInfo, timeout); + * uint16_t status = 0; + * IotHttpsClient_ReadResponseStatus(respHandle, &status); + * if (status != IOT_HTTPS_STATUS_OK) + * { + * // Handle server response status. + * } + * ... + * @endcode + * + * For an asynchronous response the response status is the status parameter in + * #IotHttpsClientCallbacks_t.readReadyCallback and #IotHttpsClientCallbacks_t.responseCompleteCallback. The application + * should refer to that instead of using this function. + * Example Asynchronous Code + * @code + * void applicationDefined_readReadyCallback(void * pPrivData, IotHttpsResponseHandle_t respHandle, IotHttpsReturnCode_t rc, uint16_t status) + * { + * ... + * if (status != IOT_HTTPS_STATUS_OK) + * { + * // Handle error server response status. + * } + * ... + * } + * @endcode + * + * @param[in] respHandle - Unique handle representing the HTTPS response. + * @param[out] pStatus - Integer status returned by the server. + * + * @return One of the following: + * - #IOT_HTTPS_OK if the response status was successfully read into *status. + * - #IOT_HTTPS_INVALID_PARAMETER for NULL parameters. + * - #IOT_HTTPS_NOT_FOUND if the HTTP response status was not found in the header buffer. + */ +/* @[declare_https_client_readresponsestatus] */ +IotHttpsReturnCode_t IotHttpsClient_ReadResponseStatus( IotHttpsResponseHandle_t respHandle, + uint16_t * pStatus ); +/* @[declare_https_client_readresponsestatus] */ + +/** + * @brief Retrieve the HTTPS response content length. + * + * If the "Content-Length" header is available in #IotHttpsResponseInfo_t.userBuffer, this routine extracts that + * value. In some cases the "Content-Length" header is not available. This could be because the server sent a multi-part + * encoded response (For example, "Transfer-Encoding: chunked") or the "Content-Length" header was far down in the list + * of response headers and could not fit into the header buffer configured in #IotHttpsResponseInfo_t.userBuffer. + * Please see #responseUserBufferMinimumSize for information about sizing the #IotHttpsResponseInfo_t.userBuffer. + * + * In the asynchronous request process, the Content-Length is not available until the + * #IotHttpsClientCallbacks_t.readReadyCallback. Before the #IotHttpsClientCallbacks_t.readReadyCallback is invoked, the + * headers are read into as much as can fit in in the header buffer space of #IotHttpsResponseInfo_t.userBuffer. + * Example Asynchronous Code + * @code{c} + * void applicationDefined_readReadyCallback(void * pPrivData, IotHttpsResponseHandle_t respHandle, IotHttpsReturnCode_t rc, uint16_t status) + * { + * uint8_t * readBuffer = NULL; + * uint32_t contentLength = 0; + * IotHttpsClient_ReadContentLength(respHandle, &contentLength); + * readBuffer = (uint8_t*)malloc(contentLength); + * ... + * } + * @endcode + * + * In a synchronous request process, the Content-Length is available after @ref https_client_function_sendsync has + * returned successfully. + * Example Synchronous Code + * @code{c} + * ... + * IotHttpsClient_SendSync(connHandle, reqHandle, &respHandle, &respInfo, timeout); + * uint32_t contentLength = 0; + * IotHttpsClient_ReadContentLength(respHandle, &contentLength); + * printf("Content-Length: %u", (unsigned int)contentLength); + * ... + * @endcode + * + * @param[in] respHandle - Unique handle representing the HTTPS response. + * @param[out] pContentLength - Integer content length from the Content-Length header from the server. If the content + * length is not found this will be 0. + * + * @return One of the following: + * - #IOT_HTTPS_OK if the response body Content-Length was successfully read into contentLength. + * - #IOT_HTTPS_NOT_FOUND if the Content-Length header was not found in the header buffer. + * - #IOT_HTTPS_INVALID_PARAMETER if NULL parameters are passed in. + */ +/* @[declare_https_client_readcontentlength] */ +IotHttpsReturnCode_t IotHttpsClient_ReadContentLength( IotHttpsResponseHandle_t respHandle, + uint32_t * pContentLength ); +/* @[declare_https_client_readcontentlength] */ + +/** + * @brief Retrieve the header of interest from the response represented by respHandle. + * + * The response headers as received from the network will be stored in the header buffer space in + * #IotHttpsResponseInfo_t.userBuffer. If the configured #IotHttpsResponseInfo_t.userBuffer is too small to fit + * the headers received, then headers that don't fit will be thrown away. Please see #responseUserBufferMinimumSize for + * information about sizing the #IotHttpsResponseInfo_t.userBuffer. + * + * This routine parses the formatted HTTPS header lines in the header buffer for the header field name specified. If the + * header is not available, then #IOT_HTTPS_NOT_FOUND is returned. + * + * For an asynchronous response, this routine is to be called during the #IotHttpsClientCallbacks_t.readReadyCallback. + * Before the #IotHttpsClientCallbacks_t.readReadyCallback is invoked, the + * headers are read into as much as can fit in in the header buffer space of #IotHttpsResponseInfo_t.userBuffer. + * Example Asynchronous Code + * @code{c} + * void applicationDefined_readReadyCallback(void * pPrivData, IotHttpsResponseHandle_t respHandle, IotHttpsReturnCode_t rc, uint16_t status) + * { + * ... + * char valueBuf[64]; + * const char contentTypeName[] = "Content-Type"; + * uint32_t contentTypeNmeLength = strlen(contentTypeName); + * IotHttpsClient_ReadHeader(respHandle, contentTypeName, contentTypeNameLength, valueBuf, sizeof(valueBuf)); + * ... + * } + * @endcode + * + * For a syncrhonous response, this routine is to be called after @ref https_client_function_sendsync has + * returned successfully. + * Example Synchronous Code + * @code{c} + * ... + * IotHttpsClient_SendSync(&connHandle, reqHandle, &respHandle, &respInfo, timeout); + * char valueBuf[10]; + * const char contentTypeName[] = "Content-Type"; + * uint32_t contentTypeNmeLength = strlen(contentTypeName); + * IotHttpsClient_ReadHeader(respHandle, contentTypeName, contentTypeNmeLength, valueBuf, sizeof(valueBuf)); + * uint32_t length = strtoul(valueBuf, NULL, 10); + * ... + * @endcode + * + * @param[in] respHandle - Unique handle representing the HTTPS response. + * @param[in] pName - HTTPS Header field name we want the value of. This must be NULL terminated. + * @param[in] nameLen - The length of the name string. + * @param[out] pValue - Buffer to hold the HTTPS field's value. The returned value will be NULL terminated + * and therfore the buffer must be large enough to hold the terminating NULL character. + * @param[in] valueLen - The length of the value buffer. + * + * @return One of the following: + * - #IOT_HTTPS_OK if the header's corresponding value was read into *pValue. + * - #IOT_HTTPS_NOT_FOUND if the header value was not found. + * - #IOT_HTTPS_INVALID_PARAMETER if the respHandle is not valid, there is no response saved or the handle does not exist. + * - #IOT_HTTPS_INSUFFICIENT_MEMORY if the value is too large to fit into *pValue. + */ +/* @[declare_https_client_readheader] */ +IotHttpsReturnCode_t IotHttpsClient_ReadHeader( IotHttpsResponseHandle_t respHandle, + char * pName, + uint32_t nameLen, + char * pValue, + uint32_t valueLen ); +/* @[declare_https_client_readheader] */ + +/** + * @brief Read the HTTPS response body from the network. + * + * This is intended to be used with an asynchronous response, this is to be invoked during the + * #IotHttpsClientCallbacks_t.readReadyCallback to read data directly from the network into pBuf. + * Example Asynchronous Code + * @code{c} + * void applicationDefined_readReadyCallback(void * pPrivData, IotHttpsRequestHandle_t handle, IotHttpsReturnCode_t rc, uint16_t status) + * { + * ... + * char * myBuf = STORE_ADDRESS; + * uint32_t len = STORE_READ_SIZE; + * IotHttpsClient_ReadResponseBody(handle, myBuf, &len); + * ... + * } + * @endcode + * + * For a syncrhonous response, to retrieve the response body applications must directly refer to the memory configured + * to receive the response body: #IotHttpsSyncInfo_t.pBody in #IotHttpsResponseInfo_t.pSyncInfo. Otherwise this function + * will return an #IOT_HTTPS_INVALID_PARAMETER error code. This function is intended to read the response entity body + * from the network and the synchronous response process handles all of that in @ref https_client_function_sendsync. + * + * @param[in] respHandle - Unique handle representing the HTTPS response. + * @param[out] pBuf - Pointer to the response body memory location. This is not a char* because the body may have binary data. + * @param[in,out] pLen - The length of the response to read. This should not exceed the size of the buffer that we are reading into. This will be replace with the amount of data read upon return. + * + * @return One of the following: + * - #IOT_HTTPS_OK if the response body was successfully retrieved. + * - #IOT_HTTPS_INVALID_PARAMETER if there are NULL parameters or if the response is a synchronous type. + * - #IOT_HTTPS_NETWORK_ERROR if there was an error sending the data on the network. + * - #IOT_HTTPS_PARSING_ERROR if there was an error parsing the HTTP response. + */ +/* @[declare_https_client_readresponsebody] */ +IotHttpsReturnCode_t IotHttpsClient_ReadResponseBody( IotHttpsResponseHandle_t respHandle, + uint8_t * pBuf, + uint32_t * pLen ); +/* @[declare_https_client_readresponsebody] */ + +#endif /* IOT_HTTPS_CLIENT_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/include/iot_https_utils.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/include/iot_https_utils.h new file mode 100644 index 000000000..849d3fa3a --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/include/iot_https_utils.h @@ -0,0 +1,95 @@ +/* + * Amazon FreeRTOS HTTPS Client V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_https_utils.h + * @brief User facing HTTPS Client library utilities. + */ + +#ifndef IOT_HTTPS_UTILS_H_ +#define IOT_HTTPS_UTILS_H_ + +#include "types/iot_https_types.h" + +/*-----------------------------------------------------------*/ + +/** + * @brief Retrieve the path from the input URL. + * + * This function retrieves the location and length of the path from within the + * input the URL. The query is not included in the length returned. + * + * The URL MUST start with "http://" or "https://" to find the path. + * + * For example, if the URL is: + * pUrl = "https://www.somewebsite.com/path/to/item.txt?optionalquery=stuff" + * + * *pPath = "/path/to/item.txt?optionalquery=stuff" + * *pPathLen = 17 + * + * @param[in] pUrl - URL string to parse. + * @param[in] urlLen - The length of the URL string input. + * @param[out] pPath - pointer within input url that the path starts at. + * @param[out] pPathLen - Length of the path. + * + * - #IOT_HTTPS_OK if the path was successfully parsed. + * - #IOT_HTTPS_PARSING_ERROR if there was an error parsing the URL. + * - #IOT_HTTPS_NOT_FOUND if the path was not found. + */ +IotHttpsReturnCode_t IotHttpsClient_GetUrlPath( const char * pUrl, + size_t urlLen, + const char ** pPath, + size_t * pPathLen ); + +/** + * @brief Retrieve the Address from the input URL. + * + * This function retrieves the location and length of the address from within + * the input URL. The path and query are not included in the length returned. + * + * The URL MUST start with "http://" or "https://" to find the address. + * + * For example, if the URL is: + * pUrl = "https://www.somewebsite.com/path/to/item.txt?optionalquery=stuff" + * + * *pAddress = "www.somewebsite.com/path/to/item.txt?optionalquery=stuff" + * *pAddressLen = 19 + * + * @param[in] pUrl - URL string to parse. + * @param[in] urlLen - The length of the URL string input. + * @param[out] pAddress - pointer within input url that the address starts at. + * @param[out] pAddressLen - Length of the address. + * + * @return One of the following: + * - #IOT_HTTPS_OK if the path was successfully parsed. + * - #IOT_HTTPS_PARSING_ERROR if there was an error parsing the URL. + * - #IOT_HTTPS_NOT_FOUND if the address was not found. + */ +IotHttpsReturnCode_t IotHttpsClient_GetUrlAddress( const char * pUrl, + size_t urlLen, + const char ** pAddress, + size_t * pAddressLen ); + +#endif /* IOT_HTTPS_UTILS_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/include/types/iot_https_types.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/include/types/iot_https_types.h new file mode 100644 index 000000000..e78bf0a18 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/include/types/iot_https_types.h @@ -0,0 +1,907 @@ +/* + * Amazon FreeRTOS HTTPS Client V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_https_types.h + * @brief Types of the HTTPS Client library. + */ + +#ifndef IOT_HTTPS_TYPES_H_ +#define IOT_HTTPS_TYPES_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* C standard includes. */ +#include +#include +#include + +/* Type includes. */ +#include "types/iot_platform_types.h" + +/* Platform network include. */ +#include "platform/iot_network.h" + +/*------------------------- HTTPS defined constants --------------------------*/ + +/** + * @constantspage{https_client,HTTPS Client library} + * + * @section https_minimum_user_buffer_sizes HTTPS Client Minimum User Buffer Sizes + * @brief Variables calculating the size of #IotHttpsUserBuffer_t.bufferLen needed for the request, response, and + * connection. + * + * @note These user buffer minimum values may change at any time in future versions, but their names will remain the + * same. + * - @ref requestUserBufferMinimumSize
+ * @copybrief requestUserBufferMinimumSize + * - @ref responseUserBufferMinimumSize
+ * @copybrief responseUserBufferMinimumSize + * - @ref connectionUserBufferMinimumSize
+ * @copybrief connectionUserBufferMinimumSize + * + * @section https_connection_flags HTTPS Client Connection Flags + * @brief Flags that modify the behavior of the HTTPS Connection. + * + * Flags should be bitwise-ORed with each other to change the behavior of @ref https_client_function_sendasync and + * @ref https_client_function_sendsync. These flags are set in #IotHttpsConnectionInfo_t.flags. + * + * @note The values of flags may change at any time in future versions, but their names will remain the same. + * + * @section https_initializers HTTP Initializers + * @brief Provide default values for the data types of the HTTP Client Library. + * + * @snippet this define_https_initializers + * + * All user-facing data types of the HTTPS Client library should be initialized using one of the following. + * + * @warning Failing to initialize an HTTPS Client data type with the appropriate initializer may result in undefined + * behavior. + * @note The initializers may change at any time in future versions, but their names will remain the same. + * + * Example + * @code{c} + * IotHttpsConnectionHandle_t connHandle = IOT_HTTPS_CONNECTION_HANDLE_INITIALIZER; + * IotHttpsRequestHandle_t reqHandle = IOT_HTTPS_REQUEST_HANDLE_INITIALIZER; + * IotHttpsResponseHandle_t respHandle = IOT_HTTPS_RESPONSE_HANDLE_INITIALIZER; + * IotHttpsUserBuffer_t userBuffer = IOT_HTTPS_USER_BUFFER_INITIALIZER; + * IotHttpsSyncInfo_t syncInfoReq = IOT_HTTPS_SYNC_INFO_INITIALIZER; + * IotHttpsSyncInfo_t syncInfoResp = IOT_HTTPS_SYNC_INFO_INITIALIZER; + * IotHttpsConnectionInfo_t connInfo = IOT_HTTPS_CONNECTION_INFO_INITIALIZER; + * IotHttpsRequestInfo_t reqInfo = IOT_HTTPS_REQUEST_INFO_INITIALIZER + * IotHttpsResponseInfo_t respInfo = IOT_HTTPS_RESPONSE_INFO_INITIALIZER + * @endcode + * + * @section http_constants_connection_flags HTTPS Client Connection Flags + * @brief Flags that modify the behavior the HTTPS connection. + * - #IOT_HTTPS_IS_NON_TLS_FLAG
+ * @copybrief IOT_HTTPS_IS_NON_TLS_FLAG + * - #IOT_HTTPS_DISABLE_SNI
+ * @copybrief IOT_HTTPS_DISABLE_SNI + */ + +/** + * @brief The minimum user buffer size for the HTTP request context and headers. + * + * This helps to calculate the size of the buffer needed for #IotHttpsRequestInfo_t.userBuffer. + * + * This buffer size is calculated to fit the HTTP Request-Line and the default headers. It does not account for the + * length of the path in the Request-Line nor does it account for the length of the host name. It also does not account + * for extra headers that the application may add. These sizes need to be accounted for by the application when + * assigning a buffer. + * + * A typical value for sizing the request user buffer for the request context is 512 bytes. See the example below. + * @code{c} + * uint8_t requestUserBuffer[512] = { 0 }; + * IotHttpsRequestInfo_t requestInfo = IOT_HTTPS_REQUEST_INFO_INITIALIZER; + * requestInfo.userBuffer.pBuffer = requestUserBuffer; + * @endcode + * + * By the application providing the memory for the internal context, no memory is needed to be allocated internally to + * the library for the internal context. The application has control over the memory allocation related to the request, + * response, and connection. + */ +extern const uint32_t requestUserBufferMinimumSize; + +/** + * @brief The minimum user buffer size for the HTTP response context and headers. + * + * This helps to calculate the size of the buffer needed for #IotHttpsResponseInfo_t.userBuffer. + * + * The buffer size is calculated to fit the HTTP response context only. It does not account for the HTTP response status + * line. It does not account for any HTTP response headers. If the buffer assigned to + * #IotHttpsResponseInfo_t.userBuffer is of this minimum size, then the response Status-Line and the response headers + * will not be stored. These sizes need to be accounted for by the application when assigning a buffer. + * + * If the response Status-Line and response headers cannot fit into #IotHttpsResponseInfo_t.userBuffer, then after a + * call to @ref https_client_function_sendsync, calls to @ref https_client_function_readresponsestatus, + * @ref https_client_function_readcontentlength, and @ref https_client_function_readheader will return a failure code. + * + * A typical value for sizing the response user buffer for the response context is 512 bytes. See the example below. + * @code{c} + * uint8_t responseUserBuffer[512] = { 0 }; + * IotHttpsResponseInfo_t responseInfo = IOT_HTTPS_RESPONSE_INFO_INITIALIZER; + * responseInfo.userBuffer.pBuffer = responseUserBuffer; + * @endcode + * + * By the application providing the memory for the internal context, no memory is needed to be allocated internally to + * the library for the internal context. The application has control over the memory allocation related to the request, + * response, and connection. + */ +extern const uint32_t responseUserBufferMinimumSize; + +/** + * @brief The minimum user buffer size for the HTTP connection context and headers. + * + * This helps to calculate the size of the buffer needed for #IotHttpsConnectionInfo_t.userBuffer. + * + * The buffer size is calculated to fit the HTTP connection context only. The buffer assigned by the application must be + * at least this size. + * + * A typical value for sizing the request user buffer for the connection context is 512 bytes. See the example below. + * @code{c} + * uint8_t connectionUserBuffer[512] = { 0 }; + * IotHttpsConnectionInfo_t connectionInfo = IOT_HTTPS_CONNECTION_INFO_INITIALIZER; + * connectionInfo.userBuffer.pBuffer = connectionUserBuffer; + * @endcode + * + * By the application providing the memory for the internal context, no memory is needed to be allocated internally to + * the library for the internal context. The application has control over the memory allocation related to the request, + * response, and connection. + */ +extern const uint32_t connectionUserBufferMinimumSize; + +/** + * @brief Flag for #IotHttpsConnectionInfo_t that disables TLS. + * + * Set this bit in #IotHttpsConnectionInfo_t.flags to disable use of TLS when the connection is created. This library + * creates secure connections by default. + */ +#define IOT_HTTPS_IS_NON_TLS_FLAG ( 0x00000001 ) + +/** + * @brief Flag for #IotHttpsConnectionInfo_t that disables Server Name Indication (SNI). + * + * Set this bit #IotHttpsConnectionInfo_t.flags to disable SNI. SNI is enabled by default in this library. When SNI is + * enabled #IotHttpsConnectionInfo_t.pAddress will be used for the server name verification. + */ +#define IOT_HTTPS_DISABLE_SNI ( 0x00000008 ) + +/* @[define_https_initializers] */ +/** @brief Initializer for #IotHttpsConnectionHandle_t. */ +#define IOT_HTTPS_CONNECTION_HANDLE_INITIALIZER NULL +/** @brief Initializer for #IotHttpsRequestHandle_t. */ +#define IOT_HTTPS_REQUEST_HANDLE_INITIALIZER NULL +/** @brief Initializer for #IotHttpsResponseHandle_t. */ +#define IOT_HTTPS_RESPONSE_HANDLE_INITIALIZER NULL +/** @brief Initializer for #IotHttpsUserBuffer_t. */ +#define IOT_HTTPS_USER_BUFFER_INITIALIZER { 0 } +/** @brief Initializer for #IotHttpsSyncInfo_t. */ +#define IOT_HTTPS_SYNC_INFO_INITIALIZER { 0 } +/** @brief Initializer for #IotHttpsAsyncInfo_t. */ +#define IOT_HTTPS_ASYNC_INFO_INITIALIZER { 0 } +/** @brief Initializer for #IotHttpsConnectionInfo_t. */ +#define IOT_HTTPS_CONNECTION_INFO_INITIALIZER { 0 } +/** @brief Initializer for #IotHttpsRequestInfo_t. */ +#define IOT_HTTPS_REQUEST_INFO_INITIALIZER { 0 } +/** @brief Initializer for #IotHttpsResponseInfo_t. */ +#define IOT_HTTPS_RESPONSE_INFO_INITIALIZER { 0 } +/* @[define_https_initializers] */ + +/* Network include for the network types below. */ +#include "platform/iot_network.h" + +/** + * @brief Type for the network interface containing the operations to send, receive, connect, and disconnect from + * the network. + */ +#define IOT_HTTPS_NETWORK_INTERFACE_TYPE const IotNetworkInterface_t * + +/*---------------------------- HTTPS handle types ----------------------------*/ + +/** + * @handles{https_client,HTTPS Client library} + */ + +/** + * @ingroup https_client_datatypes_handles + * @brief Opaque handle of an HTTP connection. + * + * A connection handle is needed to send many requests over a single persistent connection. This handle is valid after + * a successful call to @ref https_client_function_connect or @ref https_client_function_sendsync or + * @ref https_client_function_sendasync. A variable of this type is passed to @ref https_client_function_sendsync, + * @ref https_client_function_sendasync, and @ref https_client_function_disconnect to identify which connection that + * function acts on. + * + * A call to @ref https_client_function_disconnect makes a connection handle invalid. Once @ref https_client_function_disconnect + * returns, the connection handle should no longer be used. The application must call @ref https_client_function_connect + * again to retrieve a new handle and a new connection. + * + * Typical web servers disconnect the client in around 30-60 seconds. The application needs to be aware of this, when + * taking time between requests in a persistent connection. + * + * A connection handle is not thread safe. Multiple threads cannot connect and disconnect with the same handle at the + * same time. + * + * Multiple threads can call @ref https_client_function_sendasync or @ref https_client_function_sendsync with the same + * connection handle. + */ +typedef struct _httpsConnection * IotHttpsConnectionHandle_t; + +/** + * @ingroup https_client_datatypes_handles + * @brief Opaque handle of an HTTP request. + * + * Having a separate handle for the HTTP request allows the application to re-use a request. + * + * This handle is valid after a successful call to @ref https_client_function_initializerequest. A variable of this type + * is passed to @ref https_client_function_sendasync or @ref https_client_function_sendsync. + * + * A request handle cannot be sent on multiple connections at the same time. + * + * A request handle is not thread safe. Multiple threads cannot write headers to the same request handle. + */ +typedef struct _httpsRequest * IotHttpsRequestHandle_t; + +/** + * @ingroup https_client_datatypes_handles + * @brief Opaque handle of an HTTP response. + * + * This handle is valid after a successful call to @ref https_client_function_sendsync or + * @ref https_client_function_sendasync. A variable of this type is passed to + * @ref https_client_function_readresponsestatus, @ref https_client_function_readcontentlength, + * @ref https_client_function_readheader, and @ref https_client_function_readresponsebody. + * + * When returned from @ref https_client_function_sendsync or @ref https_client_function_sendasync, there is an + * associated #IotHttpsRequestHandle_t. If the #IotHttpsRequestHandle_t associated with this response is re-initialized + * with @ref https_client_function_initializerequest, then this response handle is no longer valid. + * + * A response handle is not thread safe. Multiple threads cannot read the headers in a response at the same time. + */ +typedef struct _httpsResponse * IotHttpsResponseHandle_t; + +/*-------------------------- HTTPS enumerated types --------------------------*/ + +/** + * @enums{https_client,HTTPS Client library} + */ + +/** + * @ingroup https_client_datatypes_enums + * @brief Return codes of [HTTPS Client functions](@ref https_client_functions). + */ +typedef enum IotHttpsReturnCode +{ + /** + * @brief Returned for a successful operation. + */ + IOT_HTTPS_OK = 0, + + /** + * @brief An invalid parameter was passed into an API function. + */ + IOT_HTTPS_INVALID_PARAMETER = 101, + + /** + * @brief Invalid payload. + */ + IOT_HTTPS_INVALID_PAYLOAD = 102, + + /** + * @brief HTTPS message was too large to fit into a configured synchronous body buffer. + */ + IOT_HTTPS_MESSAGE_TOO_LARGE = 103, + + /** + * @brief Overflow occurred somewhere. + */ + IOT_HTTPS_OVERFLOW = 104, + + /** + * @brief A buffer provided could not hold data required by the library. + */ + IOT_HTTPS_INSUFFICIENT_MEMORY = 105, + + /** + * @brief Queue full. + */ + IOT_HTTPS_QUEUE_FULL = 106, + + /** + * @brief Operation retry. + */ + IOT_HTTPS_RETRY = 107, + + /** + * @brief Could not find an item specified by an API. + * + * Returned for not being able to find the address in a URL, the path in a URL, or a header field from the response + * headers. + */ + IOT_HTTPS_NOT_FOUND = 108, + + /** + * @brief The HTTP request message was finished being written and we cannot write more with @ref https_client_function_writerequestbody. + */ + IOT_HTTPS_MESSAGE_FINISHED = 109, + + /** + * @brief An error occurred internally to the library. + */ + IOT_HTTPS_INTERNAL_ERROR = 201, + + /** + * @brief A network error occurred. + */ + IOT_HTTPS_NETWORK_ERROR = 202, + + /** + * @brief A network connection error occurred. + */ + IOT_HTTPS_CONNECTION_ERROR = 203, + + /** + * @brief A stream error occurred. + */ + IOT_HTTPS_STREAM_ERROR = 204, + + /** + * @brief An authentication error occurred. + */ + IOT_HTTPS_AUTHENTICATION_ERROR = 205, + + /** + * @brief A TLS error occurred. + */ + IOT_HTTPS_TLS_ERROR = 206, + + /** + * @brief An error occurred during the user callback. + */ + IOT_HTTPS_USER_CALLBACK_ERROR = 207, + + /** + * @brief The synchronous response could not be received in the specified timeout in @ref https_client_function_sendsync. + */ + IOT_HTTPS_TIMEOUT_ERROR = 208, + + /** + * @brief An error in the HTTP protocol. + */ + IOT_HTTPS_PROTOCOL_ERROR = 209, + + /** + * @brief The HTTPS request send was cancelled. + */ + IOT_HTTPS_SEND_ABORT = 210, + + /** + * @brief The HTTPS response receiving was cancelled. + */ + IOT_HTTPS_RECEIVE_ABORT = 211, + + /** + * @brief The asynchronous request had an error being scheduled. + */ + IOT_HTTPS_ASYNC_SCHEDULING_ERROR = 212, + + /** + * @brief There was an error parsing the HTTP response. + */ + IOT_HTTPS_PARSING_ERROR = 213, + + /** + * @brief Fatal HTTP library error. + */ + IOT_HTTPS_FATAL = 901, + + /** + * @brief The connection is busy and cannot be cleaned up. + * + * The connection was closed, but @ref https_client_function_disconnect must be called again to cleanup connection + * resources. + */ + IOT_HTTPS_BUSY = 902, + + /** + * @brief Try again. + */ + IOT_HTTPS_TRY_AGAIN = 903, + + /** + * @brief Data exists. + */ + IOT_HTTPS_DATA_EXIST = 904, + + /** + * @brief The operation on the public API is not supported. + */ + IOT_HTTPS_NOT_SUPPORTED = 905 +} IotHttpsReturnCode_t; + +/** + * @ingroup https_client_datatypes_enums + * @brief Types of HTTP methods. + * + * The HTTP method is configured in #IotHttpsRequestInfo_t.method. + */ +typedef enum IotHttpsMethod +{ + IOT_HTTPS_METHOD_GET = 0, /* Client-to-server method GET */ + IOT_HTTPS_METHOD_HEAD, /* Client-to-server method HEAD */ + IOT_HTTPS_METHOD_PUT, /* Client-to-server method PUT */ + IOT_HTTPS_METHOD_POST /* Client-to-server method POST. */ +} IotHttpsMethod_t; + +/** + * @ingroup https_client_datatypes_enums + * @brief Types of standard HTTP Response status codes. + * + * These status codes are taken from RFC 2616. Please see RFC 2616 for a description of each response status. + */ +enum IotHttpsResponseStatus +{ + IOT_HTTPS_STATUS_CONTINUE = 100, + IOT_HTTPS_STATUS_SWITCHING_PROTOCOLS, + IOT_HTTPS_STATUS_OK = 200, + IOT_HTTPS_STATUS_CREATED, + IOT_HTTPS_STATUS_ACCEPTED, + IOT_HTTPS_STATUS_NON_AUTHORITIVE_INFORMATION, + IOT_HTTPS_STATUS_NO_CONTENT, + IOT_HTTPS_STATUS_RESET_CONTENT, + IOT_HTTPS_STATUS_PARTIAL_CONTENT, + IOT_HTTPS_STATUS_MULTIPLE_CHOICES = 300, + IOT_HTTPS_STATUS_MOVED_PERMANENTLY, + IOT_HTTPS_STATUS_FOUND, + IOT_HTTPS_STATUS_SEE_OTHER, + IOT_HTTPS_STATUS_NOT_MODIFIED, + IOT_HTTPS_STATUS_USE_PROXY, + IOT_HTTPS_STATUS_UNUSED, + IOT_HTTPS_STATUS_TEMPORARY_REDIRECT, + IOT_HTTPS_STATUS_BAD_REQUEST = 400, + IOT_HTTPS_STATUS_UNAUTHORIZED, + IOT_HTTPS_STATUS_PAYMENT_REQUIRED, + IOT_HTTPS_STATUS_FORBIDDEN, + IOT_HTTPS_STATUS_NOT_FOUND, + IOT_HTTPS_STATUS_METHOD_NOT_ALLOWED, + IOT_HTTPS_STATUS_NOT_ACCEPTABLE, + IOT_HTTPS_STATUS_PROXY_AUTHENTICATION_REQUIRED, + IOT_HTTPS_STATUS_REQUEST_TIMEOUT, + IOT_HTTPS_STATUS_CONFLICT, + IOT_HTTPS_STATUS_GONE, + IOT_HTTPS_STATUS_LENGTH_REQUIRED, + IOT_HTTPS_STATUS_PRECONDITION_FAILED, + IOT_HTTPS_STATUS_REQUEST_ENTITY_TOO_LARGE, + IOT_HTTPS_STATUS_REQUEST_URI_TOO_LONG, + IOT_HTTPS_STATUS_UNSUPPORTED_MEDIA_TYPE, + IOT_HTTPS_STATUS_REQUEST_RANGE_NOT_SATISFIABLE, + IOT_HTTPS_STATUS_EXPECTATION_FAILED, + IOT_HTTPS_STATUS_INTERNAL_SERVER_ERROR = 500, + IOT_HTTPS_STATUS_NOT_IMPLEMENTED, + IOT_HTTPS_STATUS_BAD_GATEWAY, + IOT_HTTPS_STATUS_SERVICE_UNAVAILABLE, + IOT_HTTPS_STATUS_GATEWAY_TIMEOUT, + IOT_HTTPS_STATUS_HTTP_VERSION_NOT_SUPPORTED +}; + +/*------------------------- HTTPS parameter structs --------------------------*/ + +/** + * @paramstructs{https_client,HTTPS Client library} + */ + +/** + * @ingroup https_client_datatypes_paramstructs + * + * @brief HTTPS Client library callbacks for asynchronous requests. + * + * @paramfor @ref https_client_function_initializerequest + * + * This type is a parameter in #IotHttpsResponseInfo_t. + * + * If any of the members in this type are set to NULL, then they will not be invoked during the asynchronous + * request/response process. + * + * See @ref Asynchronous_Callback_Order for the order of the order of the callbacks and when they will be invoked. + */ +typedef struct IotHttpsClientCallbacks +{ + /** + * @brief User-provided callback function signature for appending a header to current asynchronous request. + * + * If this is set to NULL, then it will not be invoked. + * See @ref https_client_function_addheader for more information on adding a header in this callback. + * + * Appending the header when request is in progress is good for things like time limited authentication tokens. + * + * @param[in] pPrivData - User context configured in #IotHttpsAsyncInfo_t.pPrivData + * @param[in] reqHandle - The handle for the current HTTP request in progress. + */ + void ( * appendHeaderCallback )( void * pPrivData, + IotHttpsRequestHandle_t reqHandle ); + + /** + * @brief User-provided callback function signature for writing data to the network for a current asynchronous + * request. + * + * If this is set to NULL, then it will not be invoked. + * See @ref https_client_function_writerequestbody for more information on writing request body. + * + * @param[in] pPrivData - User context configured in #IotHttpsAsyncInfo_t.pPrivData + * @param[in] reqHandle - The handle for the current HTTP request in progress. + */ + void ( * writeCallback )( void * pPrivData, + IotHttpsRequestHandle_t reqHandle ); + + /** + * @brief User-provided callback function signature for reading data from the network for a current asynchronous + * response. + * + * The network indicated that after sending the associated request, the response is available for reading. + * If this is set to NULL, then it will not be invoked and any response body received will be ignored. + * See @ref https_client_function_readresponsebody for more information about reading the response body in this + * callback. + * + * @param[in] pPrivData - User context configured in #IotHttpsAsyncInfo_t.pPrivData + * @param[in] respHandle - The handle for the current HTTP response in progress. + * @param[in] rc - A return code indicating any errors before this callback was invoked. + * @param[in] status - The HTTP response status code of the current response in progress. + */ + void ( * readReadyCallback )( void * pPrivData, + IotHttpsResponseHandle_t respHandle, + IotHttpsReturnCode_t rc, + uint16_t status ); + + /** + * @brief User-provided callback function signature to indicate that the asynchronous response is completed. + * + * If this is set to NULL, then it will not be invoked. + * + * This callback is invoked when the response is fully received from the network and the request/response pair is + * complete. + * If there was an error in sending the request or an error in receiving the associated response, this callback will + * be invoked, if the error caused the request or associated response to finish. + * #IotHttpsClientCallbacks_t.errorCallback will be invoked first before this callback. + * This callback is invoked to let the application know that memory used by #IotHttpsRequestInfo_t.userBuffer and + * #IotHttpsResponseInfo_t.userBuffer can be freed, modified, or reused. + * + * For a non-persistent connection, the connection will be closed first before invoking this callback. + * + * @param[in] pPrivData - User context configured in #IotHttpsAsyncInfo_t.pPrivData + * @param[in] respHandle - The handle for the current HTTP response in progress. + * @param[in] rc - A return code indicating any errors before this callback was invoked. + * @param[in] status - The HTTP response status code of the current response in progress. + */ + void ( * responseCompleteCallback )( void * pPrivData, + IotHttpsResponseHandle_t respHandle, + IotHttpsReturnCode_t rc, + uint16_t status ); + + /** + * @brief User-provided callback function signature to indicate that the connection has been close in an asynchronous + * request process. + * + * If this is set to NULL, then it will not be invoked. + * If there are errors during sending/receiving in the asynchronous process, the connection is not automatically + * closed. If the server closes the connection during the asynchronous process, this callback is not invoked. + * This callback is invoked only if the connection was flagged as non-persistent in + * #IotHttpsConnectionInfo_t.flags. + * + * @param[in] pPrivData - User context configured in #IotHttpsAsyncInfo_t.pPrivData + * @param[in] connHandle - The handle for the current HTTP connection. + * @param[in] rc - A return code indicating any errors before this callback was invoked. + */ + void ( * connectionClosedCallback )( void * pPrivData, + IotHttpsConnectionHandle_t connHandle, + IotHttpsReturnCode_t rc ); + + /** + * @brief User-provided callback function signature to indicate that an error occurred during the asynchronous + * request process. + * + * If respHandle is NULL, then reqHandle will not be NULL and vise-versa. This signals which handle the error + * occurred and if it is during the sending or receiving. + * + * @param[in] pPrivData - User context configured in #IotHttpsAsyncInfo_t.pPrivData + * @param[in] respHandle - The handle for the current HTTP response. + * @param[in] reqHandle - The handle for the current HTTP request. + * @param[in] rc - A return code indicating any errors before this callback was invoked. + */ + void ( * errorCallback )( void * pPrivData, + IotHttpsRequestHandle_t reqHandle, + IotHttpsResponseHandle_t respHandle, + IotHttpsReturnCode_t rc ); +} IotHttpsClientCallbacks_t; + +/** + * @ingroup https_client_datatypes_paramstructs + * @brief User-provided buffer for storing the HTTPS headers and library internal context. + * + * @paramfor @ref https_client_function_initializerequest. + * + * The user buffer is configured in #IotHttpsConnectionInfo_t.userBuffer, #IotHttpsRequestInfo_t.userBuffer and + * #IotHttpsResponseInfo_t.userBuffer. + * + * The minimum size that the buffer must be configured to is indicated by requestUserBufferMinimumSize, + * responseUserBufferMinimumSize, connectionUserBufferMinimumSize. + */ +typedef struct IotHttpsUserBuffer +{ + uint8_t * pBuffer; /**< @brief Application provided buffer pointer. */ + uint32_t bufferLen; /**< @brief The length of the application provided buffer. */ +} IotHttpsUserBuffer_t; + +/** + * @ingroup https_client_datatypes_paramstructs + * @brief HTTPS Client synchronous request information. + * + * @paramfor @ref https_client_function_initializerequest, @ref https_client_function_sendsync, + * @ref https_client_function_sendasync + * + * This structure is configured in #IotHttpsRequestInfo_t.u and #IotHttpsResponseInfo_t. + * + * A synchronous request will block until the response is fully received from the network. + * This structure defines memory locations to store the response body. + */ +typedef struct IotHttpsSyncRequestInfo +{ + /** + * Pointer to the HTTP message body. + * + * For a request this is the file or data we want to send. The data is separated from the headers for the + * flexibility to point to an already established file elsewhere in memory. + * + * For a response this is where to receive the response entity body. + * If the length of the buffer provided to store the response body is smaller than the amount of body received, + * then @ref https_client_function_sendsync will return a IOT_HTTPS_INSUFFICIENT_MEMORY error code. Although an error + * was returned, the first #IotHttpsSyncInfo_t.bodyLen of the response received on the network will + * still be available in the buffer. + */ + uint8_t * pBody; + uint32_t bodyLen; /**< @brief The length of the HTTP message body. */ +} IotHttpsSyncInfo_t; + +/** + * @ingroup https_client_datatypes_paramstructs + * @brief HTTPS Client asynchronous request information. + * + * @paramfor @ref https_client_function_initializerequest. + * + * This is parameter in #IotHttpsRequestInfo_t.u. + * + * An asynchronous request will ask the application for headers and body right before the request is ready + * to be sent onto the network. + * An asynchronous request will have the application read headers and body as soon as the response is received + * on the network. + */ +typedef struct IotHttpsAsyncInfo +{ + /** + * @brief Callbacks are used for an asynchronous request. + * See #IotHttpsClientCallbacks_t for more information. + */ + IotHttpsClientCallbacks_t callbacks; + void * pPrivData; /**< @brief User private data to provide context to the asynchronous callbacks. */ +} IotHttpsAsyncInfo_t; + +/** + * @ingroup https_client_datatypes_paramstructs + * @brief HTTP connection configuration. + * + * @paramfor @ref https_client_function_connect or @ref https_client_function_sendsync or + * @ref https_client_function_sendasync. + * + * This parameter is used to connection in @ref https_client_function_connect. + * + * @note The lengths of the strings in this struct should not include the NULL + * terminator. Strings in this struct do not need to be NULL-terminated. + */ +typedef struct IotHttpsConnectionInfo +{ + /** + * @brief Remote server address that is DNS discoverable. + * + * For example: avs-alexa-na.amazon.com. + */ + const char * pAddress; + uint32_t addressLen; /**< @brief remote address length. */ + + uint16_t port; /**< @brief Remote port number */ + + /** + * @brief Flags to configure the HTTPS connection. + * + * See @ref https_connection_flags for the available flags. + * + * Unknown flags are ignored. + */ + uint32_t flags; /**< @brief Flags to configure the HTTPS connection. */ + + /** + * @brief Timeout waiting for a response from the network in milliseconds. + * + * If this is set to zero, it will default to @ref IOT_HTTPS_RESPONSE_WAIT_MS. + */ + uint32_t timeout; + + const char * pCaCert; /**< @brief Server trusted certificate store for this connection. */ + uint32_t caCertLen; /**< @brief Server trusted certificate store size. */ + + const char * pClientCert; /**< @brief Client certificate store for this connection. */ + uint32_t clientCertLen; /**< @brief Client certificate store size. */ + + const char * pPrivateKey; /**< @brief Client private key store for this connection. */ + uint32_t privateKeyLen; /**< @brief Client private key store size. */ + + /** + * @brief String of all the ALPN protocols separated by commas needed for this connection. + * + * For the protocols needed for the AWS Iot Message broker endpoint please see: + * https://docs.aws.amazon.com/iot/latest/developerguide/protocols.html + */ + char * pAlpnProtocols; + uint32_t alpnProtocolsLen; /**< @brief ALPN protocol string length. */ + + /** + * @brief User buffer to store the internal connection context. + * + * See @ref connectionUserBufferMinimumSize for information about the user buffer configured in + * #IotHttpsConnectionInfo_t.userBuffer needed to create a valid connection handle. + */ + IotHttpsUserBuffer_t userBuffer; + + /** + * @brief The IOT network abstraction interface. + * + * This contains the interface to connect, disconnect, send data, and receive data from the network. + * + * In Amazon FreeRTOS this should be of the type IotNetworkInterface_t. + */ + IOT_HTTPS_NETWORK_INTERFACE_TYPE pNetworkInterface; +} IotHttpsConnectionInfo_t; + +/** + * @ingroup https_client_datatypes_paramstructs + * @brief HTTP request configuration. + * + * @paramfor @ref https_client_function_initializerequest. + * + * This parameter is used to configure the request in https_client_function_initializerequest. + * + * @note The lengths of the strings in this struct should not include the NULL + * terminator. Strings in this struct do not need to be NULL-terminated. + */ +typedef struct IotHttpsRequestInfo +{ + /** + * @brief The absolute path to the HTTP request object. + * + * The absolute path includes the path to the file AND the optional query. + * An example URI path: "/v20160207/directives?query". + * + * If this is NULL, a "/" will be added to the Request-Line automatically. + * + * This is used to generate the Request-Line in the HTTP request message, see + * @ref https_client_function_initializerequest for more information. + */ + const char * pPath; + uint32_t pathLen; /**< @brief URI path length */ + + /** + * @brief On of the HTTP method tokens defined in #IotHttpsMethod_t. + * + * This is used to generate the Request-Line in the HTTP request message, see + * @ref https_client_function_initializerequest for more information. + */ + IotHttpsMethod_t method; + + /** + * @brief Host address this request is intended for, e.g., "awsamazon.com". + * + * This is the same as the address in #IotHttpsConnectionInfo_t.pAddress. This is here in the request structure to + * automatically generate the "Host" header field in the header buffer space configured in + * #IotHttpsRequestInfo_t.userBuffer. See @ref https_client_function_initializerequest for more information. + */ + const char * pHost; + uint32_t hostLen; /**< @brief Host address length. */ + + /** + * @brief Flag denoting if the connection should be non-persistent. + * + * If this flag is set to false, then the connection is persistent. When the connection is persistent, the HTTP + * header "Connection: keep-alive" is automatically added to the headers to send to the server. This header + * asks the server to not close the connection after sending the response. + * + * If this flag is set to true, then the connection is non-persistent. When the connection is non-persistent, then + * HTTP header "Connection: close" is automatically added to the headers to send to the server. This header asks + * the server to close the connection after sending the response. + * + * Please see https://tools.ietf.org/html/rfc2616#section-8.1.1 for more details. + */ + bool isNonPersistent; + + /** + * @brief Application owned buffer for storing the request headers and internal request context. + * + * For an asynchronous request, if the application owns the memory for this buffer, then it must not be modified, + * freed, or reused until the the #IotHttpsClientCallbacks_t.responseCompleteCallback is invoked. + * + * Please see #IotHttpsUserBuffer_t for more information. + */ + IotHttpsUserBuffer_t userBuffer; + + /** + * @brief Indicator if this request is sync or async. + * + * Set this to false to use a synchronous request. Set this to true to use an asynchronous request. + */ + bool isAsync; + + /** + * @brief Specific information for either a synchronous request or an asynchronous request. + * + * See #IotHttpsAsyncInfo_t for information on pAsyncInfo. + * See #IotHttpsSyncInfo_t for information on u.pSyncInfo. + */ + union + { + IotHttpsAsyncInfo_t * pAsyncInfo; /**< @brief Information specifically for Asynchronous requests. */ + IotHttpsSyncInfo_t * pSyncInfo; /**< @brief Information specifically for synchronous requests. */ + } u; +} IotHttpsRequestInfo_t; + +/** + * @ingroup https_client_datatypes_paramstructs + * @brief HTTP request configuration. + * + * @paramfor @ref https_client_function_sendsync and @ref https_client_function_sendasync + * + * A separate response info is defined so that the application can re-initialize a request for re-use while still + * processing a response that was already completed. + */ +typedef struct IotHttpsResponseInfo +{ + /** + * The application owned buffer for storing the response headers and internal response context. + * + * For an asynchronous request, if the application owns the memory for this buffer, then it must not be modified, + * freed, or reused until the the #IotHttpsClientCallbacks_t.responseCompleteCallback is invoked. + * + * Please see #IotHttpsUserBuffer_t for more information. + */ + IotHttpsUserBuffer_t userBuffer; + + /** + * @brief Specific information for a synchronously received response. + * + * Set this to NULL if the response is to be received asynchronously. + * + * See #IotHttpsSyncInfo_t for more information. + */ + IotHttpsSyncInfo_t * pSyncInfo; +} IotHttpsResponseInfo_t; + +#endif /* ifndef IOT_HTTPS_TYPES_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/src/iot_https_client.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/src/iot_https_client.c new file mode 100644 index 000000000..eb468674c --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/src/iot_https_client.c @@ -0,0 +1,3365 @@ +/* + * Amazon FreeRTOS HTTPS Client V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_https_client.c + * @brief Implementation of the user-facing functions of the Amazon FreeRTOS HTTPS Client library. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* HTTPS Client library private includes. */ +#include "private/iot_https_internal.h" + +/*-----------------------------------------------------------*/ + +/** + * @brief Partial HTTPS request first line. + * + * This is used for the calculation of the requestUserBufferMinimumSize. + * The minimum path is "/" because we cannot know how long the application requested path is is going to be. + * CONNECT is the longest string length HTTP method according to RFC 2616. + */ +#define HTTPS_PARTIAL_REQUEST_LINE HTTPS_CONNECT_METHOD " " HTTPS_EMPTY_PATH " " HTTPS_PROTOCOL_VERSION + +/** + * @brief The User-Agent header line string. + * + * This is of the form: + * "User-Agent: \r\n" + * This is used for the calculation of the requestUserBufferMinimumSize. + */ +#define HTTPS_USER_AGENT_HEADER_LINE HTTPS_USER_AGENT_HEADER HTTPS_HEADER_FIELD_SEPARATOR IOT_HTTPS_USER_AGENT HTTPS_END_OF_HEADER_LINES_INDICATOR + +/** + * @brief The Host header line with the field only and not the value. + * + * This is of the form: + * "Host: \r\n" + * This is used for the calculation of the requestUserBufferMinimumSize. The Host value is not specified because we + * cannot anticipate what server the client is making requests to. + */ +#define HTTPS_PARTIAL_HOST_HEADER_LINE HTTPS_HOST_HEADER HTTPS_HEADER_FIELD_SEPARATOR HTTPS_END_OF_HEADER_LINES_INDICATOR + +/** + * String constants for the Connection header and possible values. + * + * This is used for writing headers automatically during the sending of the HTTP request. + * "Connection: keep-alive\r\n" is written automatically for a persistent connection. + * "Connection: close\r\n" is written automatically for a non-persistent connection. + */ +#define HTTPS_CONNECTION_KEEP_ALIVE_HEADER_LINE HTTPS_CONNECTION_HEADER HTTPS_HEADER_FIELD_SEPARATOR HTTPS_CONNECTION_KEEP_ALIVE_HEADER_VALUE HTTPS_END_OF_HEADER_LINES_INDICATOR /**< @brief String literal for "Connection: keep-alive\r\n". */ +#define HTTPS_CONNECTION_CLOSE_HEADER_LINE HTTPS_CONNECTION_HEADER HTTPS_HEADER_FIELD_SEPARATOR HTTPS_CONNECTION_CLOSE_HEADER_VALUE HTTPS_END_OF_HEADER_LINES_INDICATOR /**< @brief String literal for "Connection: close\r\n". */ + +/** + * @brief The length of the "Connection: keep-alive\r\n" header. + * + * This is used for sizing a local buffer for the final headers to send that include the "Connection: keep-alive\r\n" + * header line. + * + * This is used to initialize a local array for the final headers to send. + */ +#define HTTPS_CONNECTION_KEEP_ALIVE_HEADER_LINE_LENGTH ( 24 ) + +/** + * Indicates for the http-parser parsing execution function to tell it to keep parsing or to stop parsing. + * + * A value of 0 means the parser should keep parsing if there is more unparsed length. + * A value greater than 0 tells the parser to stop parsing. + */ +#define KEEP_PARSING ( ( int ) 0 ) /**< @brief Indicator in the http-parser callback to keep parsing when the function returns. */ +#define STOP_PARSING ( ( int ) 1 ) /**< @brief Indicator in the http-parser callback to stop parsing when the function returns. */ + +/*-----------------------------------------------------------*/ + +/** + * @brief Minimum size of the request user buffer. + * + * The request user buffer is configured in IotHttpsClientRequestInfo_t.userBuffer. This buffer stores the internal context + * of the request and then the request headers right after. The minimum size for the buffer is the total size of the + * internal request context, the HTTP formatted request line, the User-Agent header line, and the part of the Host + * header line. + */ +const uint32_t requestUserBufferMinimumSize = sizeof( _httpsRequest_t ) + + sizeof( HTTPS_PARTIAL_REQUEST_LINE ) + + sizeof( HTTPS_USER_AGENT_HEADER_LINE ) + + sizeof( HTTPS_PARTIAL_HOST_HEADER_LINE ); + +/** + * @brief Minimum size of the response user buffer. + * + * The response user buffer is configured in IotHttpsClientRequestInfo_t.userBuffer. This buffer stores the internal context + * of the response and then the response headers right after. This minimum size is calculated for the case if no bytes + * from the HTTP response headers are to be stored. + */ +const uint32_t responseUserBufferMinimumSize = sizeof( _httpsResponse_t ); + +/** + * @brief Minimum size of the connection user buffer. + * + * The connection user buffer is configured in IotHttpsConnectionInfo_t.userBuffer. This buffer stores the internal context of the + * connection. + */ +const uint32_t connectionUserBufferMinimumSize = sizeof( _httpsConnection_t ); + +/*-----------------------------------------------------------*/ + +/** + * @brief Callback from http-parser to indicate the start of the HTTP response message is reached. + * + * See https://github.com/nodejs/http-parser for more information. + * + * @param[in] pHttpParser - http-parser state structure. + * + * @return 0 to tell http-parser to keep parsing. + * 1 to tell http-parser that parsing should stop return from http_parser_execute with error HPE_CB_message_begin. + */ +static int _httpParserOnMessageBeginCallback( http_parser * pHttpParser ); + +/** + * @brief Callback from http-parser to indicate it found the HTTP response status code. + * + * See https://github.com/nodejs/http-parser for more information. + * + * @param[in] pHttpParser - http-parser state structure. + * @param[in] pLoc - Pointer to the HTTP response status code string in the response message buffer. + * @param[in] length - The length of the HTTP response status code string. + * + * @return 0 to tell http-parser to keep parsing. + * 1 to tell http-parser that parsing should stop return from http_parser_execute with error HPE_CB_status. + */ +static int _httpParserOnStatusCallback( http_parser * pHttpParser, + const char * pLoc, + size_t length ); + +/** + * @brief Callback from http-parser to indicate it found an HTTP response header field. + * + * If only part of the header field was returned here in this callback, then this callback will be invoked again the + * next time the parser executes on the next part of the header field. + * + * See https://github.com/nodejs/http-parser for more information. + * + * @param[in] pHttpParser - http-parser state structure. + * @param[in] pLoc - Pointer to the header field string in the response message buffer. + * @param[in] length - The length of the header field. + * + * @return 0 to tell http-parser to keep parsing. + * 1 to tell http-parser that parsing should stop return from http_parser_execute with error HPE_CB_header_field. + */ +static int _httpParserOnHeaderFieldCallback( http_parser * pHttpParser, + const char * pLoc, + size_t length ); + +/** + * @brief Callback from http-parser to indicate it found an HTTP response header value. + * + * This value corresponds to the field that was found in the _httpParserOnHeaderFieldCallback() called immediately + * before this callback was called. + * + * If only part of the header value was returned here in this callback, then this callback will be invoked again the + * next time the parser executes on the next part of the header value. + * + * See https://github.com/nodejs/http-parser for more information. + * + * @param[in] pHttpParser - http-parser state structure. + * @param[in] pLoc - Pointer to the header value string in the response message buffer. + * @param[in] length - The length of the header value. + * + * @return 0 to tell http-parser to keep parsing. + * 1 to tell http-parser that parsing should stop return from http_parser_execute with error HPE_CB_header_value. + */ +static int _httpParserOnHeaderValueCallback( http_parser * pHttpParser, + const char * pLoc, + size_t length ); + +/** + * @brief Callback from http-parser to indicate it reached the end of the headers in the HTTP response message. + * + * The end of the headers is signalled in a HTTP response message by another "\r\n" after the final header line. + * + * See https://github.com/nodejs/http-parser for more information. + * + * @param[in] pHttpParser - http-parser state structure. + * + * @return 0 to tell http-parser to keep parsing. + * 1 to tell http-parser that parsing should stop return from http_parser_execute with error HPE_CB_headers_complete. + */ +static int _httpParserOnHeadersCompleteCallback( http_parser * pHttpParser ); + +/** + * @brief Callback from http-parser to indicate it found HTTP response body. + * + * This callback will be invoked multiple times if the response body is of "Transfer-Encoding: chunked". + * _httpParserOnChunkHeaderCallback() will be invoked first, then _httpParserOnBodyCallback(), then + * _httpParserOnChunkCompleteCallback(), then repeated back to _httpParserOnChunkHeaderCallback() if there are more + * "chunks". + * + * See https://github.com/nodejs/http-parser for more information. + * + * @param[in] pHttpParser - http-parser state structure. + * @param[in] pLoc - Pointer to the body string in the response message buffer. + * @param[in] length - The length of the body found. + * + * @return 0 to tell http-parser to keep parsing. + * 1 to tell http-parser that parsing should stop return from http_parser_execute with error HPE_CB_body. + */ +static int _httpParserOnBodyCallback( http_parser * pHttpParser, + const char * pLoc, + size_t length ); + +/** + * @brief Callback from http-parser to indicate it reached the end of the HTTP response message. + * + * The end of the message is signalled in a HTTP response message by another "\r\n" after the final header line, with no + * entity body; or it is signaled by "\r\n" at the end of the entity body. + * + * For a Transfer-Encoding: chunked type of response message, the end of the message is signalled by a terminating + * chunk header with length zero. + * + * See https://github.com/nodejs/http-parser for more information. + * + * @param[in] pHttpParser - http-parser state structure. + * + * @return 0 to tell http-parser to keep parsing. + * 1 to tell http-parser that parsing should stop return from http_parser_execute with error HPE_CB_message_complete. + */ +static int _httpParserOnMessageCompleteCallback( http_parser * pHttpParser ); + +/* This code prints debugging information and is, therefore, compiled only when + * log level is set to IOT_LOG_DEBUG. */ +#if ( LIBRARY_LOG_LEVEL == IOT_LOG_DEBUG ) + +/** + * @brief Callback from http-parser to indicate it found an HTTP Transfer-Encoding: chunked header. + * + * Transfer-Encoding: chunked headers are embedded in the HTTP response entity body by a "\r\n" followed by the size of + * the chunk followed by another "\r\n". + * + * If only part of the header field was returned here in this callback, then this callback will be invoked again the + * next time the parser executes on the next part of the header field. + * + * See https://github.com/nodejs/http-parser for more information. + * + * @param[in] pHttpParser - http-parser state structure. + * + * @return 0 to tell http-parser to keep parsing. + * 1 to tell http-parser that parsing should stop return from http_parser_execute with error HPE_CB_chunk_header. + */ + static int _httpParserOnChunkHeaderCallback( http_parser * pHttpParser ); + +/** + * @brief Callback from http-parser to indicate it reached the end of an HTTP response message "chunk". + * + * A chunk is complete when the chunk header size is read fully in the body. + * + * See https://github.com/nodejs/http-parser for more information. + * + * @param[in] pHttpParser - http-parser state structure. + * + * @return 0 to tell http-parser to keep parsing. + * 1 to tell http-parser that parsing should stop return from http_parser_execute with error HPE_CB_chunk_complete. + */ + static int _httpParserOnChunkCompleteCallback( http_parser * pHttpParser ); +#endif + +/** + * @brief Network receive callback for the HTTPS Client library. + * + * This function is called by the network layer whenever data is available for the HTTP library. + * + * @param[in] pNetworkConnection - The network connection with the HTTPS connection, passed by the network stack. + * @param[in] pReceiveContext - A pointer to the HTTPS Client connection handle for which the packet was received. + */ +static void _networkReceiveCallback( void * pNetworkConnection, + void * pReceiveContext ); + +/** + * @brief Connects to HTTPS server and initializes the connection context. + * + * @param[out] pConnHandle - The out parameter to return handle representing the open connection. + * @param[in] pConnInfo - The connection configuration. + * + * @return #IOT_HTTPS_OK if the connection context initialization was successful. + * #IOT_HTTPS_CONNECTION_ERROR if the connection failed. + * #IOT_HTTPS_INTERNAL_ERROR if the context initialization failed. + */ +static IotHttpsReturnCode_t _createHttpsConnection( IotHttpsConnectionHandle_t * pConnHandle, + IotHttpsConnectionInfo_t * pConnInfo ); + +/** + * @brief Disconnects from the network. + * + * @param[in] pHttpsConnection - HTTPS connection handle. + */ +static void _networkDisconnect( _httpsConnection_t * pHttpsConnection ); + +/** + * @brief Destroys the network connection. + * + * @param[in] pHttpsConnection - HTTPS connection handle. + */ +static void _networkDestroy( _httpsConnection_t * pHttpsConnection ); + +/** + * @brief Add a header to the current HTTP request. + * + * The headers are stored in reqHandle->pHeaders. + * + * @param[in] pHttpsRequest - HTTP request context. + * @param[in] pName - The name of the header to add. + * @param[in] nameLen - The length of the header name string. + * @param[in] pValue - The buffer containing the value string. + * @param[in] valueLen - The length of the header value string. + * + * @return #IOT_HTTPS_OK if the header was added to the request successfully. + * #IOT_HTTPS_INSUFFICIENT_MEMORY if there was not enough room in the IotHttpsRequestHandle_t->pHeaders. + */ +static IotHttpsReturnCode_t _addHeader( _httpsRequest_t * pHttpsRequest, + const char * pName, + uint32_t nameLen, + const char * pValue, + uint32_t valueLen ); + +/** + * @brief Send data on the network. + * + * @param[in] pHttpsConnection - HTTP connection context. + * @param[in] pBuf - The buffer containing the data to send. + * @param[in] len - The length of the data to send. + * + * @return #IOT_HTTPS_OK if the data sent successfully. + * #IOT_HTTPS_NETWORK_ERROR if there was an error sending the data on the network. + */ +static IotHttpsReturnCode_t _networkSend( _httpsConnection_t * pHttpsConnection, + uint8_t * pBuf, + size_t len ); + +/** + * @brief Receive data on the network. + * + * @param[in] pHttpsConnection - HTTP connection context. + * @param[in] pBuf - The buffer to receive the data into. + * @param[in] bufLen - The length of the data to receive. + * @param[in] numBytesRecv - The number of bytes read from the network. + * + * @return #IOT_HTTPS_OK if the data was received successfully. + * #IOT_HTTPS_NETWORK_ERROR if we timedout trying to receive data from the network. + */ +static IotHttpsReturnCode_t _networkRecv( _httpsConnection_t * pHttpsConnection, + uint8_t * pBuf, + size_t bufLen, + size_t * numBytesRecv ); + +/** + * @brief Send all of the HTTP request headers in the pHeadersBuf and the final Content-Length and Connection headers. + * + * All of the headers in headerbuf are sent first followed by the computed content length and persistent connection + * indication. + * + * @param[in] pHttpsConnection - HTTP connection context. + * @param[in] pHeadersBuf - The buffer containing the request headers to send. This buffer must contain HTTP headers + * lines without the indicator for the the end of the HTTP headers. + * @param[in] headersLength - The length of the request headers to send. + * @param[in] isNonPersistent - Indicator of whether the connection is persistent or not. + * @param[in] contentLength - The length of the request body used for automatically creating a "Content-Length" header. + * + * @return #IOT_HTTPS_OK if the headers were fully sent successfully. + * #IOT_HTTPS_NETWORK_ERROR if there was an error receiving the data on the network. + */ +static IotHttpsReturnCode_t _sendHttpsHeaders( _httpsConnection_t * pHttpsConnection, + uint8_t * pHeadersBuf, + uint32_t headersLength, + bool isNonPersistent, + uint32_t contentLength ); + +/** + * @brief Send all of the HTTP request body in pBodyBuf. + * + * @param[in] pHttpsConnection - HTTP connection context. + * @param[in] pBodyBuf - Buffer of the request body to send. + * @param[in] bodyLength - The length of the body to send. + * + * @return #IOT_HTTPS_OK if the body was fully sent successfully. + * #IOT_HTTPS_NETWORK_ERROR if there was an error receiving the data on the network. + */ +static IotHttpsReturnCode_t _sendHttpsBody( _httpsConnection_t * pHttpsConnection, + uint8_t * pBodyBuf, + uint32_t bodyLength ); + +/** + * @brief Parse the HTTP response message in pBuf. + * + * @param[in] pHttpParserInfo - Pointer to the information containing the instance of the http-parser and the execution function. + * @param[in] pBuf - The buffer containing the data to parse. + * @param[in] len - The length of data to parse. + * + * @return #IOT_HTTPS_OK if the data was parsed successfully. + * #IOT_HTTPS_PARSING_ERROR if there was an error with parsing the data. + */ +static IotHttpsReturnCode_t _parseHttpsMessage( _httpParserInfo_t * pHttpParserInfo, + char * pBuf, + size_t len ); + +/** + * @brief Receive any part of an HTTP response. + * + * This function is used for both receiving the body into the body buffer and receiving the header into the header + * buffer. + * + * @param[in] pHttpsConnection - HTTP Connection context. + * @param[in] pParser - Pointer to the instance of the http-parser. + * @param[in] pCurrentParserState - The current state of what has been parsed in the HTTP response. + * @param[in] finalParserState - The final state of the parser expected after this function finishes. + * @param[in] currentBufferProcessingState - The current buffer that is the HTTPS message is being received into. + * @param[in] pBufCur - Pointer to the next location to write data into the buffer pBuf. This is a double pointer to update the response context buffer pointers. + * @param[in] pBufEnd - Pointer to the end of the buffer to receive the HTTP response into. + * + * @return #IOT_HTTPS_OK if we received the HTTP response message part successfully. + * #IOT_HTTPS_PARSING_ERROR if there was an error with parsing the data. + * #IOT_HTTPS_NETWORK_ERROR if there was an error receiving the data on the network. + */ +static IotHttpsReturnCode_t _receiveHttpsMessage( _httpsConnection_t * pHttpsConnection, + _httpParserInfo_t * pParser, + IotHttpsResponseParserState_t * pCurrentParserState, + IotHttpsResponseParserState_t finalParserState, + IotHttpsResponseBufferState_t currentBufferProcessingState, + uint8_t ** pBufCur, + uint8_t ** pBufEnd ); + +/** + * @brief Receive the HTTP response headers. + * + * Receiving the response headers is always the first step in receiving the response, therefore the + * pHttpsResponse->httpParserInfo will be initialized to a starting state when this function is called. + * + * This function also sets internal states to indicate that the header buffer is being processed now for a new response. + * + * @param[in] pHttpsConnection - HTTP connection context. + * @param[in] pHttpsResponse - HTTP response context. + * + * @return #IOT_HTTPS_OK if we received the HTTP headers successfully. + * #IOT_HTTPS_PARSING_ERROR if there was an error with parsing the header buffer. + * #IOT_HTTPS_NETWORK_ERROR if there was an error receiving the data on the network. + */ +static IotHttpsReturnCode_t _receiveHttpsHeaders( _httpsConnection_t * pHttpsConnection, + _httpsResponse_t * pHttpsResponse ); + +/** + * @brief Receive the HTTP response body. + * + * Sets internal states to indicate that the the body buffer is being processed now for a new response. + * + * @param[in] pHttpsConnection - HTTP connection context. + * @param[in] pHttpsResponse - HTTP response context. + * + * @return #IOT_HTTPS_OK if we received the HTTP body successfully. + * #IOT_HTTPS_PARSING_ERROR if there was an error with parsing the body buffer. + * #IOT_HTTPS_NETWORK_ERROR if there was an error receiving the data on the network. + */ +static IotHttpsReturnCode_t _receiveHttpsBody( _httpsConnection_t * pHttpsConnection, + _httpsResponse_t * pHttpsResponse ); + +/** + * @brief Read the rest of any HTTP response that may be on the network. + * + * This reads the rest of any left over response data that might still be on the network buffers. We do not want this + * data left over because it will spill into the header and body buffers of next response that we try to receive. + * + * If we performed a request without a body and the headers received exceeds the size of the + * pHttpsResponse->pHeaders buffer, then we need to flush the network buffer. + * + * If the application configured the body buffer as null in IotHttpsResponseInfo_t.syncInfo.respData and the server + * sends body in the response, but it exceeds the size of pHttpsResponse->pHeaders buffer, then we need to flush the + * network buffer. + * + * If the amount of body received on the network does not fit into a non-null IotHttpsResponseInfo_t.syncInfo.respData, + * then we need to flush the network buffer. + * + * If an asynchronous request cancels in the middle of a response process, after already sending the request message, + * then we need to flush the network buffer. + * + * @param[in] pHttpsConnection - HTTP connection context. + * @param[in] pHttpsResponse - HTTP response context. + * + * @return #IOT_HTTPS_OK if we successfully flushed the network data. + * #IOT_HTTPS_PARSING_ERROR if there was an error with parsing the data. + * #IOT_HTTPS_NETWORK_ERROR if there was an error receiving the data on the network. + */ +static IotHttpsReturnCode_t _flushHttpsNetworkData( _httpsConnection_t * pHttpsConnection, + _httpsResponse_t * pHttpsResponse ); + +/** + * @brief Task pool job routine to send the HTTP request within the pUserContext. + * + * @param[in] pTaskPool Pointer to the system task pool. + * @param[in] pJob Pointer the to the HTTP request sending job. + * @param[in] pUserContext Pointer to an HTTP request, passed as an opaque context. + */ +static void _sendHttpsRequest( IotTaskPool_t pTaskPool, + IotTaskPoolJob_t pJob, + void * pUserContext ); + + +/** + * @brief Receive the HTTPS body specific to an asynchronous type of response. + * + * @param[in] pHttpsResponse - HTTP response context. + * + * @return #IOT_HTTPS_OK - If the the response body was received with no issues. + * #IOT_HTTPS_RECEIVE_ABORT - If the request was cancelled by the Application + * #IOT_HTTPS_PARSING_ERROR - If there was an issue parsing the HTTP response body. + * #IOT_HTTPS_NETWORK_ERROR if there was an error receiving the data on the network. + */ +static IotHttpsReturnCode_t _receiveHttpsBodyAsync( _httpsResponse_t * pHttpsResponse ); + +/** + * @brief Receive the HTTPS body specific to a synchronous type of response. + * + * @param[in] pHttpsResponse - HTTP response context. + * + * @return #IOT_HTTPS_OK - If the the response body was received with no issues. + * #IOT_HTTPS_MESSAGE_TOO_LARGE - If the body from the network is too large to fit into the configured body buffer. + * #IOT_HTTPS_PARSING_ERROR - If there was an issue parsing the HTTP response body. + * #IOT_HTTPS_NETWORK_ERROR if there was an error receiving the data on the network. + */ +static IotHttpsReturnCode_t _receiveHttpsBodySync( _httpsResponse_t * pHttpsResponse ); + +/** + * @brief Schedule the task to send the the HTTP request. + * + * @param[in] pHttpsRequest - HTTP request context. + * + * @return #IOT_HTTPS_OK - If the task to send the HTTP request was successfully scheduled. + * #IOT_HTTPS_INTERNAL_ERROR - If a taskpool job could not be created. + * #IOT_HTTPS_ASYNC_SCHEDULING_ERROR - If there was an error scheduling the job. + */ +IotHttpsReturnCode_t _scheduleHttpsRequestSend( _httpsRequest_t * pHttpsRequest ); + +/** + * @brief Add the request to the connection's request queue. + * + * This will schedule a task if the request is first and only request in the queue. + * + * @param[in] pHttpsRequest - HTTP request context. + * + * @return #IOT_HTTPS_OK - If the request was successfully added to the connection's request queue. + * #IOT_HTTPS_INTERNAL_ERROR - If a taskpool job could not be created. + * #IOT_HTTPS_ASYNC_SCHEDULING_ERROR - If there was an error scheduling the job. + */ +IotHttpsReturnCode_t _addRequestToConnectionReqQ( _httpsRequest_t * pHttpsRequest ); + +/** + * @brief Cancel the HTTP request's processing. + * + * pHttpsRequest->cancelled will be checked and the request cancelled if specified so at the following intervals: + * - Before sending the HTTPS headers at the start of the scheduled sending of the HTTPS request. + * - After Sending the HTTPS headers. + * - After Sending the HTTPS body. + * + * @param[in] pHttpsRequest - HTTP request context. + */ +static void _cancelRequest( _httpsRequest_t * pHttpsRequest ); + +/** + * @brief Cancel the HTTP response's processing. + * + * pHttpsResponse->cancelled will be checked and the response cancelled if specified so at the following intervals: + * - At the start of the network receive callback. + * - After receiving the HTTPS headers. + * - After Receiving the HTTPS body. + * + * @param[in] pHttpsResponse - HTTP response context. + */ +static void _cancelResponse( _httpsResponse_t * pHttpsResponse ); + +/** + * @brief Initialize the input pHttpsResponse with pRespInfo. + * + * @param[in] pRespHandle - Non-null HTTP response context. + * @param[in] pRespInfo - Response configuration information. + * @param[in] pHttpsRequest - HTTP request to grab async information, persistence, and method from. + */ +static IotHttpsReturnCode_t _initializeResponse( IotHttpsResponseHandle_t * pRespHandle, + IotHttpsResponseInfo_t * pRespInfo, + _httpsRequest_t * pHttpsRequest ); + +/** + * @brief Increment the pointer stored in pBufCur depending on the character found in there. + * + * This function increments the pHeadersCur pointer further if the message ended with a header line delimiter. + * + * @param[in] pBufCur - Pointer to the next location to write data into the buffer pBuf. This is a double pointer to update the response context buffer pointers. + * @param[in] pBufEnd - Pointer to the end of the buffer to receive the HTTP response into. + */ +static void _incrementNextLocationToWriteBeyondParsed( uint8_t ** pBufCur, + uint8_t ** pBufEnd ); + +/** + * @brief Send the HTTPS headers and body referenced in pHttpsRequest. + * + * Sends both the headers and body over the network. + * + * @param[in] pHttpsConnection - HTTPS connection context. + * @param[in] pHttpsRequest - HTTPS request context. + */ +static IotHttpsReturnCode_t _sendHttpsHeadersAndBody( _httpsConnection_t * pHttpsConnection, + _httpsRequest_t * pHttpsRequest ); + +/*-----------------------------------------------------------*/ + +/** + * @brief Definition of the http-parser settings. + * + * The http_parser_settings holds all of the callbacks invoked by the http-parser. + */ +static http_parser_settings _httpParserSettings = { 0 }; + +/*-----------------------------------------------------------*/ + +static int _httpParserOnMessageBeginCallback( http_parser * pHttpParser ) +{ + int retVal = KEEP_PARSING; + + IotLogDebug( "Parser: Start of HTTPS Response message." ); + + _httpsResponse_t * pHttpsResponse = ( _httpsResponse_t * ) ( pHttpParser->data ); + /* Set the state of the parser. The headers are at the start of the message always. */ + pHttpsResponse->parserState = PARSER_STATE_IN_HEADERS; + return retVal; +} + +/*-----------------------------------------------------------*/ + +static int _httpParserOnStatusCallback( http_parser * pHttpParser, + const char * pLoc, + size_t length ) +{ + _httpsResponse_t * pHttpsResponse = ( _httpsResponse_t * ) ( pHttpParser->data ); + + IotLogDebug( "Parser: Status %.*s retrieved from HTTPS response.", length, pLoc ); + + /* Save the status code so it can be retrieved with IotHttpsClient_ReadResponseStatus(). */ + pHttpsResponse->status = ( uint16_t ) ( pHttpParser->status_code ); + + /* If we are parsing the network data received in the header buffer then we + * increment pHttpsResponse->pHeadersCur. The status line in the response is + * part of the data stored in header buffer _httpResponse->pHeaders. */ + if( pHttpsResponse->bufferProcessingState == PROCESSING_STATE_FILLING_HEADER_BUFFER ) + { + /* pHeadersCur will never exceed the pHeadersEnd here because PROCESSING_STATE_FILLING_HEADER_BUFFER + * indicates we are currently in the header buffer and the total size of the header buffer is passed + * into http_parser_execute() as the maximum length to parse. */ + pHttpsResponse->pHeadersCur = ( uint8_t * ) ( pLoc += length ); + } + + return KEEP_PARSING; +} + +/*-----------------------------------------------------------*/ + +static int _httpParserOnHeaderFieldCallback( http_parser * pHttpParser, + const char * pLoc, + size_t length ) +{ + IotLogDebug( "Parser: HTTPS header field parsed %.*s", length, pLoc ); + + _httpsResponse_t * pHttpsResponse = ( _httpsResponse_t * ) ( pHttpParser->data ); + + /* If we are parsing the network data received in the header buffer then we can increment + * pHttpsResponse->pHeadersCur. */ + if( pHttpsResponse->bufferProcessingState == PROCESSING_STATE_FILLING_HEADER_BUFFER ) + { + pHttpsResponse->pHeadersCur = ( uint8_t * ) ( pLoc += length ); + } + + /* If the IotHttpsClient_ReadHeader() was called, then we check for the header field of interest. */ + if( pHttpsResponse->bufferProcessingState == PROCESSING_STATE_SEARCHING_HEADER_BUFFER ) + { + if( pHttpsResponse->readHeaderFieldLength != length ) + { + pHttpsResponse->foundHeaderField = false; + } + else if( strncmp( pHttpsResponse->pReadHeaderField, pLoc, length ) == 0 ) + { + pHttpsResponse->foundHeaderField = true; + } + } + + return KEEP_PARSING; +} + +/*-----------------------------------------------------------*/ + +static int _httpParserOnHeaderValueCallback( http_parser * pHttpParser, + const char * pLoc, + size_t length ) +{ + int retVal = KEEP_PARSING; + + IotLogDebug( "Parser: HTTPS header value parsed %.*s", length, pLoc ); + _httpsResponse_t * pHttpsResponse = ( _httpsResponse_t * ) ( pHttpParser->data ); + + /* If we are parsing the network data received in the header buffer then we can increment + * pHttpsResponse->pHeadersCur. */ + if( pHttpsResponse->bufferProcessingState == PROCESSING_STATE_FILLING_HEADER_BUFFER ) + { + pHttpsResponse->pHeadersCur = ( uint8_t * ) ( pLoc += length ); + } + + /* If the IotHttpsClient_ReadHeader() was called, then we check if we found the header field of interest. */ + if( pHttpsResponse->bufferProcessingState == PROCESSING_STATE_SEARCHING_HEADER_BUFFER ) + { + if( pHttpsResponse->foundHeaderField ) + { + pHttpsResponse->pReadHeaderValue = ( char * ) ( pLoc ); + pHttpsResponse->readHeaderValueLength = length; + /* We found a header field so we don't want to keep parsing.*/ + retVal = STOP_PARSING; + } + } + + return retVal; +} + +/*-----------------------------------------------------------*/ + +static int _httpParserOnHeadersCompleteCallback( http_parser * pHttpParser ) +{ + IotLogDebug( "Parser: End of the headers reached." ); + + int retVal = KEEP_PARSING; + _httpsResponse_t * pHttpsResponse = ( _httpsResponse_t * ) ( pHttpParser->data ); + pHttpsResponse->parserState = PARSER_STATE_HEADERS_COMPLETE; + + /* If the IotHttpsClient_ReadHeader() was called, we return after finishing looking through all of the headers. + * Returning a non-zero value exits the http parsing. */ + if( pHttpsResponse->bufferProcessingState == PROCESSING_STATE_SEARCHING_HEADER_BUFFER ) + { + retVal = STOP_PARSING; + } + + /* When in this callback the pHeaderCur pointer is at the first "\r" in the last header line. HTTP/1.1 + * headers end with another "\r\n" at the end of the last line. This means we must increment + * the headerCur pointer to the length of "\r\n\r\n". */ + if( pHttpsResponse->bufferProcessingState == PROCESSING_STATE_FILLING_HEADER_BUFFER ) + { + pHttpsResponse->pHeadersCur += ( 2 * HTTPS_END_OF_HEADER_LINES_INDICATOR_LENGTH ); + } + + /* This if-case is not incrementing any pHeaderCur pointers, so this case is safe to call when flushing the + * network buffer. Flushing the network buffer needs the logic below to reach PARSER_STATE_BODY_COMPLETE if the + * response is for a HEAD request. Before flushing the network buffer the bufferProcessingState is set to + * PROCESSING_STATE_FINISHED so that other callback functions don't update header or body current pointers in the + * response context. We don't want those pointers incremented because flushing the network uses a different buffer + * to receive the rest of the response. */ + if( pHttpsResponse->bufferProcessingState <= PROCESSING_STATE_FINISHED ) + { + /* For a HEAD method, there is no body expected in the response, so we return 1 to skip body parsing. */ + if( ( pHttpsResponse->method == IOT_HTTPS_METHOD_HEAD ) ) + { + retVal = STOP_PARSING; + + /* Since the message is considered complete now for a HEAD response, then we set the parser state + * to the completed state. */ + pHttpsResponse->parserState = PARSER_STATE_BODY_COMPLETE; + } + + /* If this is NOT a HEAD method and there is body configured, but the server does not send a body in the + * response, then the body buffer will be filled with the zeros from rest of the header buffer. http-parser + * will invoke the on_body callback and consider the zeros following the headers as body. */ + + /* If there is not body configured for a synchronous reponse, we do not stop the parser from continueing. */ + + /* Skipping the body will cause the parser to invoke the _httpParserOnMessageComplete() callback. This is + * not desired when there is actually HTTP response body sent by the server because this will set the parser + * state to PARSER_STATE_BODY_COMPLETE. If this state is set then the rest of possible body will not be + * flushed out. The network flush looks for the state being PARSER_STATE_BODY_COMPLETE to finish flushing. */ + } + + return retVal; +} + +/*-----------------------------------------------------------*/ + +static int _httpParserOnBodyCallback( http_parser * pHttpParser, + const char * pLoc, + size_t length ) +{ + IotLogDebug( "Parser: Reached the HTTPS message body. It is of length: %d", length ); + + _httpsResponse_t * pHttpsResponse = ( _httpsResponse_t * ) ( pHttpParser->data ); + pHttpsResponse->parserState = PARSER_STATE_IN_BODY; + + /* If the header buffer is currently being processed, but HTTP response body was found, then for an asynchronous + * request this if-case saves where the body is located. In the asynchronous case, the body buffer is not available + * until the readReadyCallback is invoked, which happens after the headers are processed. */ + if( ( pHttpsResponse->bufferProcessingState == PROCESSING_STATE_FILLING_HEADER_BUFFER ) && ( pHttpsResponse->isAsync ) ) + { + /* For an asynchronous response, the buffer to store the body will be available after the headers + * are read first. We may receive part of the body in the header buffer. We will want to leave this here + * and copy it over when the body buffer is available in the _readReadyCallback(). + */ + if( pHttpsResponse->pBodyInHeaderBuf == NULL ) + { + pHttpsResponse->pBodyInHeaderBuf = ( uint8_t * ) ( pLoc ); + pHttpsResponse->pBodyCurInHeaderBuf = pHttpsResponse->pBodyInHeaderBuf; + } + + /* If there is a chunk encoded body in the header buffer, we will want to overwrite the chunk headers with the + * actual body. This is so that when the application calls IotHttpsClient_ReadResponseBody(), in the + * readReadyCallback(), we can pass the body into the body buffer provided right away. */ + if( pHttpsResponse->pBodyCurInHeaderBuf != ( uint8_t * ) pLoc ) + { + memcpy( pHttpsResponse->pBodyCurInHeaderBuf, pLoc, length ); + } + + pHttpsResponse->pBodyCurInHeaderBuf += length; + } + else if( pHttpsResponse->bufferProcessingState < PROCESSING_STATE_FINISHED ) + { + /* Has the user provided a buffer and is it large enough to fit the body? The + * case of body buffer not being large enough can happen if the body was received + * in the header buffer and the body buffer can not fit in all the body. */ + if( ( pHttpsResponse->pBodyCur != NULL ) && ( pHttpsResponse->pBodyEnd - pHttpsResponse->pBodyCur > 0 ) ) + { + /* There are two scenarios when we need to copy data around: + * 1. Some or all of the response body may have been received in the header + * buffer. If that is the case, we copy the response body received in the + * header buffer to the user provided body buffer. + * 2. When we receive chunked header, the actual body is separated in + * multiple chunks which are preceeded by length. For example, a chunked + * body may look like: + * + * 7\r\n + * Mozilla\r\n + * 9\r\n + * Developer\r\n + * 7\r\n + * Network\r\n + * 0\r\n + * \r\n + * + * In this case, we want the parsed body buffer to contain actual body only + * (MozillaDeveloperNetwork in the above example). + */ + + /* If the response body found by the parser (pLoc) is not equal to the + * current writable location in the body buffer (_httpsResponse->pBodyCur), + * it indicates that: + * - Either the data is in the header buffer and needs to be copied into the + * body buffer. + * - Or it is a chunked response and the data needs to be moved up in the + * body buffer. */ + if( ( pHttpsResponse->pBodyCur + length ) <= pHttpsResponse->pBodyEnd ) + { + if( pHttpsResponse->pBodyCur != ( uint8_t * ) pLoc ) + { + memcpy( pHttpsResponse->pBodyCur, pLoc, length ); + } + + pHttpsResponse->pBodyCur += length; + } + } + } + + return KEEP_PARSING; +} + +/*-----------------------------------------------------------*/ + +static int _httpParserOnMessageCompleteCallback( http_parser * pHttpParser ) +{ + IotLogDebug( "Parser: End of the HTTPS message reached." ); + + _httpsResponse_t * pHttpsResponse = ( _httpsResponse_t * ) ( pHttpParser->data ); + pHttpsResponse->parserState = PARSER_STATE_BODY_COMPLETE; + + /* This callback is invoked when the complete HTTP response has been received. + * We tell the parser to parse the whole body buffer as opposed to the size of + * the response body. For example, if the size of the body buffer is 1000 but + * the size of the actual body is 500, we tell the parser to parse the whole + * buffer of length 1000. We do zero out the buffer in the beginning so that all + * the buffer after the actual body contains zeros. We return greater than zero to stop parsing + * since the end of the HTTP message has been reached. Any data beyond the end of the message is + * ignored. */ + return STOP_PARSING; +} + +/*-----------------------------------------------------------*/ + +/* This code prints debugging information and is, therefore, compiled only when + * log level is set to IOT_LOG_DEBUG. */ +#if ( LIBRARY_LOG_LEVEL == IOT_LOG_DEBUG ) + static int _httpParserOnChunkHeaderCallback( http_parser * pHttpParser ) + { + ( void ) pHttpParser; + IotLogDebug( "Parser: HTTPS message Chunked encoding header callback." ); + IotLogDebug( "Parser: HTTPS message Chunk size: %d", pHttpParser->content_length ); + return 0; + } + +/*-----------------------------------------------------------*/ + + static int _httpParserOnChunkCompleteCallback( http_parser * pHttpParser ) + { + ( void ) pHttpParser; + IotLogDebug( "End of a HTTPS message Chunk complete callback." ); + return 0; + } +#endif /* if ( LIBRARY_LOG_LEVEL == IOT_LOG_DEBUG ) */ + +/*-----------------------------------------------------------*/ + +static IotHttpsReturnCode_t _receiveHttpsBodyAsync( _httpsResponse_t * pHttpsResponse ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + if( pHttpsResponse->pCallbacks->readReadyCallback ) + { + /* If there is still more body that has not been passed back to the user, then this callback is invoked again. */ + do + { + IotLogDebug( "Invoking the readReadyCallback." ); + pHttpsResponse->pCallbacks->readReadyCallback( pHttpsResponse->pUserPrivData, + pHttpsResponse, + pHttpsResponse->bodyRxStatus, + pHttpsResponse->status ); + + if( pHttpsResponse->cancelled == true ) + { + IotLogDebug( "Cancelled HTTP response %d.", pHttpsResponse ); + status = IOT_HTTPS_RECEIVE_ABORT; + + /* We break out of the loop and do not goto clean up because we want to print debugging logs for + * the parser state and the networks status. */ + break; + } + } while( ( pHttpsResponse->parserState < PARSER_STATE_BODY_COMPLETE ) && ( pHttpsResponse->bodyRxStatus == IOT_HTTPS_OK ) ); + + if( HTTPS_FAILED( pHttpsResponse->bodyRxStatus ) ) + { + IotLogError( "Error receiving the HTTP response body for response %d. Error code: %d", + pHttpsResponse, + pHttpsResponse->bodyRxStatus ); + /* An error in the network or the parser takes precedence */ + status = pHttpsResponse->bodyRxStatus; + } + + if( pHttpsResponse->parserState < PARSER_STATE_BODY_COMPLETE ) + { + IotLogDebug( "Did not receive all of the HTTP response body for response %d.", + pHttpsResponse ); + } + } + + /* This GOTO cleanup is here for compiler warnings about using HTTPS_FUNCTION_EXIT_NO_CLEANUP() without a + * corresponding goto. */ + HTTPS_GOTO_CLEANUP(); + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static IotHttpsReturnCode_t _receiveHttpsBodySync( _httpsResponse_t * pHttpsResponse ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + _httpsConnection_t * pHttpsConnection = pHttpsResponse->pHttpsConnection; + + /* The header buffer is now filled or the end of the headers has been reached already. If part of the response + * body was read from the network into the header buffer, then it was already copied to the body buffer in the + * _httpParserOnBodyCallback(). */ + if( pHttpsResponse->pBody != NULL ) + { + /* If there is room left in the body buffer and we have not received the whole response body, + * then try to receive more. */ + if( ( ( pHttpsResponse->pBodyEnd - pHttpsResponse->pBodyCur ) > 0 ) && + ( pHttpsResponse->parserState < PARSER_STATE_BODY_COMPLETE ) ) + { + status = _receiveHttpsBody( pHttpsConnection, + pHttpsResponse ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Error receiving the HTTPS response body for response %d. Error code: %d.", + pHttpsResponse, + status ); + HTTPS_GOTO_CLEANUP(); + } + } + else + { + IotLogDebug( "Received the maximum amount of HTTP body when filling the header buffer for response %d.", + pHttpsResponse ); + } + + /* If we don't reach the end of the HTTPS body in the parser, then we only received part of the body. + * The rest of body will be on the network socket. */ + if( HTTPS_SUCCEEDED( status ) && ( pHttpsResponse->parserState < PARSER_STATE_BODY_COMPLETE ) ) + { + IotLogError( "HTTPS response body does not fit into application provided response buffer at location 0x%x " + "with length: %d", + pHttpsResponse->pBody, + pHttpsResponse->pBodyEnd - pHttpsResponse->pBody ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_MESSAGE_TOO_LARGE ); + } + } + else + { + IotLogDebug( "No response body was configure for response %d.", pHttpsResponse ); + } + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static void _networkReceiveCallback( void * pNetworkConnection, + void * pReceiveContext ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + IotHttpsReturnCode_t flushStatus = IOT_HTTPS_OK; + IotHttpsReturnCode_t disconnectStatus = IOT_HTTPS_OK; + IotHttpsReturnCode_t scheduleStatus = IOT_HTTPS_OK; + _httpsConnection_t * pHttpsConnection = ( _httpsConnection_t * ) pReceiveContext; + _httpsResponse_t * pCurrentHttpsResponse = NULL; + _httpsRequest_t * pNextHttpsRequest = NULL; + IotLink_t * pQItem = NULL; + bool fatalDisconnect = false; + + /* The network connection is already in the connection context. */ + ( void ) pNetworkConnection; + + /* Get the response from the response queue. */ + IotMutex_Lock( &( pHttpsConnection->connectionMutex ) ); + pQItem = IotDeQueue_PeekHead( &( pHttpsConnection->respQ ) ); + IotMutex_Unlock( &( pHttpsConnection->connectionMutex ) ); + + /* If the receive callback is invoked and there is no response expected, then this a violation of the HTTP/1.1 + * protocol. */ + if( pQItem == NULL ) + { + IotLogError( "Received data on the network, when no response was expected..." ); + fatalDisconnect = true; + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_NETWORK_ERROR ); + } + + /* Set the current HTTP response context to use. */ + pCurrentHttpsResponse = IotLink_Container( _httpsResponse_t, pQItem, link ); + + /* If the receive callback has invoked, but the request associated with this response has not finished sending + * to the server, then this is a violation of the HTTP/1.1 protocol. */ + if( pCurrentHttpsResponse->reqFinishedSending == false ) + { + IotLogError( "Received response data on the network when the request was not finished sending. This is unexpected." ); + fatalDisconnect = true; + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_NETWORK_ERROR ); + } + + /* If the current response was cancelled, then don't bother receiving the headers and body. */ + if( pCurrentHttpsResponse->cancelled ) + { + IotLogDebug( "Response ID: %d was cancelled.", pCurrentHttpsResponse ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_RECEIVE_ABORT ); + } + + /* Reset the http-parser state to an initial state. This is done so that a new response can be parsed from the + * beginning. */ + pCurrentHttpsResponse->parserState = PARSER_STATE_NONE; + + /* Receive the response from the network. */ + /* Receive the headers first. */ + status = _receiveHttpsHeaders( pHttpsConnection, pCurrentHttpsResponse ); + + if( HTTPS_FAILED( status ) ) + { + if( status == IOT_HTTPS_PARSING_ERROR ) + { + /* There was an error parsing the HTTPS response body. This may be an indication of a server that does + * not adhere to protocol correctly. We should disconnect. */ + IotLogError( "Failed to parse the HTTPS headers for response %d, Error code: %d.", + pCurrentHttpsResponse, + status ); + fatalDisconnect = true; + } + else if( status == IOT_HTTPS_NETWORK_ERROR ) + { + /* Given the function signature of IotNetworkInterface_t.receive, we can only receive 0 to the number of bytes + * requested. Receiving less than the number of bytes requests is OK since we do not how much data is expected, so + * we ask for the full size of the receive buffer. Therefore, the only error that can be returned from receiving + * the headers or body is a timeout. We always disconnect from the network when there is a timeout because the + * server may be slow to respond. If the server happens to send the response later at the same time another response + * is waiting in the queue, then the workflow is corrupted. Pipelining is not current supported in this library. */ + IotLogError( "Network error receiving the HTTPS headers for response %d. Error code: %d", + pCurrentHttpsResponse, + status ); + fatalDisconnect = true; + } + else /* Any other error. */ + { + IotLogError( "Failed to retrive the HTTPS body for response %d. Error code: %d", pCurrentHttpsResponse, status ); + } + + HTTPS_GOTO_CLEANUP(); + } + + /* Check if we received all of the headers into the header buffer. */ + if( pCurrentHttpsResponse->parserState < PARSER_STATE_HEADERS_COMPLETE ) + { + IotLogDebug( "Headers received on the network did not all fit into the configured header buffer for response %d." + " The length of the headers buffer is: %d", + pCurrentHttpsResponse, + pCurrentHttpsResponse->pHeadersEnd - pCurrentHttpsResponse->pHeaders ); + /* It is not error if the headers did not all fit into the buffer. */ + } + + /* Receive the body. */ + if( pCurrentHttpsResponse->isAsync ) + { + status = _receiveHttpsBodyAsync( pCurrentHttpsResponse ); + } + else + { + /* Otherwise receive synchronously. */ + status = _receiveHttpsBodySync( pCurrentHttpsResponse ); + } + + if( HTTPS_FAILED( status ) ) + { + if( status == IOT_HTTPS_RECEIVE_ABORT ) + { + /* If the request was cancelled, this is logged, but does not close the connection. */ + IotLogDebug( "User cancelled during the async readReadyCallback() for response %d.", + pCurrentHttpsResponse ); + } + else if( status == IOT_HTTPS_PARSING_ERROR ) + { + /* There was an error parsing the HTTPS response body. This may be an indication of a server that does + * not adhere to protocol correctly. We should disconnect. */ + IotLogError( "Failed to parse the HTTPS body for response %d, Error code: %d.", + pCurrentHttpsResponse, + status ); + fatalDisconnect = true; + } + else if( status == IOT_HTTPS_NETWORK_ERROR ) + { + /* We always disconnect for a network error because failure to receive the HTTPS body will result in a + * corruption of the workflow. */ + IotLogError( "Network error receiving the HTTPS body for response %d. Error code: %d", + pCurrentHttpsResponse, + status ); + fatalDisconnect = true; + } + else /* Any other error. */ + { + IotLogError( "Failed to retrive the HTTPS body for response %d. Error code: %d", pCurrentHttpsResponse, status ); + } + + HTTPS_GOTO_CLEANUP(); + } + + IOT_FUNCTION_CLEANUP_BEGIN(); + + /* Disconnect and return in the event of an out-of-order response. If a response is received out of order + * pCurrentHttpsResponse will be NULL because there will be no response in the connection's response queue. + * If a response is received out of order that is an indication of a rogue server. */ + if( fatalDisconnect && !pCurrentHttpsResponse ) + { + IotLogError( "An out-of-order response was received. The connection will be disconnected." ); + disconnectStatus = IotHttpsClient_Disconnect( pHttpsConnection ); + + if( HTTPS_FAILED( disconnectStatus ) ) + { + IotLogWarn( "Failed to disconnect after an out of order response. Error code: %d.", disconnectStatus ); + } + + /* In this case this routine returns immediately after to avoid further uses of pCurrentHttpsResponse. */ + return; + } + + /* Report errors back to the application. */ + if( HTTPS_FAILED( status ) ) + { + if( pCurrentHttpsResponse->isAsync && pCurrentHttpsResponse->pCallbacks->errorCallback ) + { + pCurrentHttpsResponse->pCallbacks->errorCallback( pCurrentHttpsResponse->pUserPrivData, NULL, pCurrentHttpsResponse, status ); + } + + pCurrentHttpsResponse->syncStatus = status; + } + + /* If this is not a persistent request, the server would have closed it after sending a response, but we + * disconnect anyways. If we are disconnecting there is is no point in wasting time + * flushing the network. If the network is being disconnected we also do not schedule any pending requests. */ + if( fatalDisconnect || pCurrentHttpsResponse->isNonPersistent ) + { + IotLogDebug( "Disconnecting response %d.", pCurrentHttpsResponse ); + disconnectStatus = IotHttpsClient_Disconnect( pHttpsConnection ); + + if( ( pCurrentHttpsResponse != NULL ) && pCurrentHttpsResponse->isAsync && pCurrentHttpsResponse->pCallbacks->connectionClosedCallback ) + { + pCurrentHttpsResponse->pCallbacks->connectionClosedCallback( pCurrentHttpsResponse->pUserPrivData, pHttpsConnection, disconnectStatus ); + } + + if( HTTPS_FAILED( disconnectStatus ) ) + { + IotLogWarn( "Failed to disconnect response %d. Error code: %d.", pCurrentHttpsResponse, disconnectStatus ); + } + + /* If we disconnect, we do not process anymore requests. */ + } + else + { + /* Set the processing state of the buffer to finished for completeness. This is also to prevent the parsing of the flush + * data from incrementing any pointer in the HTTP response context. */ + pCurrentHttpsResponse->bufferProcessingState = PROCESSING_STATE_FINISHED; + + /* Flush the socket of the rest of the data if there is data left from this response. We need to do this + * so that for the next request on this connection, there is not left over response from this request in + * the next response buffer. + * + * If a continuous stream of data is coming in from the connection, with an unknown end, we may not be able to + * flush the network data. It may sit here forever. A continuous stream should be ingested with the async workflow. + * + * All network errors are ignore here because network read will have read the data from network buffer despite + * errors. */ + flushStatus = _flushHttpsNetworkData( pHttpsConnection, pCurrentHttpsResponse ); + + if( flushStatus == IOT_HTTPS_PARSING_ERROR ) + { + IotLogWarn( "There an error parsing the network flush data. The network buffer might not be fully flushed." ); + } + else if( flushStatus != IOT_HTTPS_OK ) + { + IotLogDebug( "Network error when flushing the https network data: %d", flushStatus ); + } + + IotMutex_Lock( &( pHttpsConnection->connectionMutex ) ); + /* Get the next request to process. */ + pQItem = IotDeQueue_PeekHead( &( pHttpsConnection->reqQ ) ); + IotMutex_Unlock( &( pHttpsConnection->connectionMutex ) ); + + /* If there is a next request to process, then create a taskpool job to send the request. */ + if( pQItem != NULL ) + { + /* Set this next request to send. */ + pNextHttpsRequest = IotLink_Container( _httpsRequest_t, pQItem, link ); + + if( pNextHttpsRequest->scheduled == false ) + { + IotLogDebug( "Request %d is next in the queue. Now scheduling a task to send the request.", pNextHttpsRequest ); + scheduleStatus = _scheduleHttpsRequestSend( pNextHttpsRequest ); + + /* If there was an error with scheduling the new task, then report it. */ + if( HTTPS_FAILED( scheduleStatus ) ) + { + IotLogError( "Error scheduling HTTPS request %d. Error code: %d", pNextHttpsRequest, scheduleStatus ); + + if( pNextHttpsRequest->isAsync && pNextHttpsRequest->pCallbacks->errorCallback ) + { + pNextHttpsRequest->pCallbacks->errorCallback( pNextHttpsRequest->pUserPrivData, pNextHttpsRequest, NULL, scheduleStatus ); + } + else + { + pNextHttpsRequest->pHttpsResponse->syncStatus = scheduleStatus; + } + } + } + } + else + { + IotLogDebug( "Network receive callback found the request queue empty. A network send task was not scheduled." ); + } + } + + /* Dequeue response from the response queue now that it is finished. */ + IotMutex_Lock( &( pHttpsConnection->connectionMutex ) ); + + /* There could be a scenario where the request fails to send and the network server still responds, + * In this case, the failed response will have been cancelled and removed from the queue. If the network + * server still got a response, then the safest way to remove the current response is to remove it explicitly + * from the queue instead of dequeuing the header of the queue which might not be the current response. */ + if( IotLink_IsLinked( &( pCurrentHttpsResponse->link ) ) ) + { + IotDeQueue_Remove( &( pCurrentHttpsResponse->link ) ); + } + + IotMutex_Unlock( &( pHttpsConnection->connectionMutex ) ); + + /* The first if-case below notifies IotHttpsClient_SendSync() that the response is finished receiving. When + * IotHttpsClient_SendSync() returns the user is allowed to modify the user buffer used for the response context. + * In the asynchronous case, the responseCompleteCallback notifies the application that the user buffer used for the + * response context can be modified. Posting to the respFinishedSem or calling the responseCompleteCallback MUST be + * mutually exclusive by wrapping in an if/else. If these were separate if-cases, then there could be a context + * switch in between where the application modifies the buffer causing the next if-case to be executed. */ + if( pCurrentHttpsResponse->isAsync == false ) + { + IotSemaphore_Post( &( pCurrentHttpsResponse->respFinishedSem ) ); + } + else if( pCurrentHttpsResponse->pCallbacks->responseCompleteCallback ) + { + /* Signal to a synchronous reponse that the response is complete. */ + pCurrentHttpsResponse->pCallbacks->responseCompleteCallback( pCurrentHttpsResponse->pUserPrivData, pCurrentHttpsResponse, status, pCurrentHttpsResponse->status ); + } +} + +/*-----------------------------------------------------------*/ + +static IotHttpsReturnCode_t _createHttpsConnection( IotHttpsConnectionHandle_t * pConnHandle, + IotHttpsConnectionInfo_t * pConnInfo ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + IotNetworkError_t networkStatus = IOT_NETWORK_SUCCESS; + + /* The maximum string length of the ALPN protocols is configured in IOT_HTTPS_MAX_ALPN_PROTOCOLS_LENGTH. + * The +1 is for the NULL terminator needed by IotNetworkCredentials_t.pAlpnProtos. */ + char pAlpnProtos[ IOT_HTTPS_MAX_ALPN_PROTOCOLS_LENGTH + 1 ] = { 0 }; + + /* The maximum string length of the Server host name is configured in IOT_HTTPS_MAX_HOST_NAME_LENGTH. + * This +1 is for the NULL terminator needed by IotNetworkServerInfo_t.pHostName. */ + char pHostName[ IOT_HTTPS_MAX_HOST_NAME_LENGTH + 1 ] = { 0 }; + bool connectionMutexCreated = false; + struct IotNetworkServerInfo networkServerInfo = { 0 }; + struct IotNetworkCredentials networkCredentials = { 0 }; + _httpsConnection_t * pHttpsConnection = NULL; + IotNetworkCredentials_t pNetworkCredentials = NULL; + + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pConnInfo->userBuffer.pBuffer ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pConnInfo->pNetworkInterface ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pConnInfo->pAddress ); + HTTPS_ON_ARG_ERROR_GOTO_CLEANUP( pConnInfo->addressLen > 0 ); + + /* Make sure the connection context can fit in the user buffer. */ + HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( pConnInfo->userBuffer.bufferLen >= connectionUserBufferMinimumSize, + IOT_HTTPS_INSUFFICIENT_MEMORY, + "Buffer size is too small to initialize the connection context. User buffer size: %d, required minimum size; %d.", + ( *pConnInfo ).userBuffer.bufferLen, + connectionUserBufferMinimumSize ); + + /* Make sure that the server address does not exceed the maximum permitted length. */ + HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( pConnInfo->addressLen <= IOT_HTTPS_MAX_HOST_NAME_LENGTH, + IOT_HTTPS_INVALID_PARAMETER, + "IotHttpsConnectionInfo_t.addressLen has a host name length %d that exceeds maximum length %d.", + pConnInfo->addressLen, + IOT_HTTPS_MAX_HOST_NAME_LENGTH ); + + /* Make sure that the ALPN protocols does not exceed the maximum permitted length. */ + HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( pConnInfo->alpnProtocolsLen <= IOT_HTTPS_MAX_ALPN_PROTOCOLS_LENGTH, + IOT_HTTPS_INVALID_PARAMETER, + "IotHttpsConnectionInfo_t.alpnProtocolsLen of %d exceeds the configured maximum protocol length %d. See IOT_HTTPS_MAX_ALPN_PROTOCOLS_LENGTH for more information.", + pConnInfo->alpnProtocolsLen, + IOT_HTTPS_MAX_ALPN_PROTOCOLS_LENGTH ); + + pHttpsConnection = ( _httpsConnection_t * ) ( pConnInfo->userBuffer.pBuffer ); + + /* Start with the disconnected state. */ + pHttpsConnection->isConnected = false; + + /* Initialize disconnection state keeper. */ + pHttpsConnection->isDestroyed = false; + + /* Initialize the queue of responses and requests. */ + IotDeQueue_Create( &( pHttpsConnection->reqQ ) ); + IotDeQueue_Create( &( pHttpsConnection->respQ ) ); + + /* This timeout is used to wait for a response on the connection as well as + * for the timeout for the connect operation. */ + if( pConnInfo->timeout == 0 ) + { + pHttpsConnection->timeout = IOT_HTTPS_RESPONSE_WAIT_MS; + } + else + { + pHttpsConnection->timeout = pConnInfo->timeout; + } + + /* pNetworkInterface contains all the routines to be able to send/receive data on the network. */ + pHttpsConnection->pNetworkInterface = pConnInfo->pNetworkInterface; + + /* The address from the connection configuration information is copied to a local buffer because a NULL pointer + * is required in IotNetworkServerInfo_t.pHostName. IotNetworkServerInfo_t contains the server information needed + * by the network interface to create the connection. */ + memcpy( pHostName, pConnInfo->pAddress, pConnInfo->addressLen ); + pHostName[ pConnInfo->addressLen ] = '\0'; + /* Set it in the IOT network abstractions server information parameter. */ + networkServerInfo.pHostName = pHostName; + networkServerInfo.port = pConnInfo->port; + + /* If this is TLS connection, then set the network credentials. */ + if( ( pConnInfo->flags & IOT_HTTPS_IS_NON_TLS_FLAG ) == 0 ) + { + if( pConnInfo->flags & IOT_HTTPS_DISABLE_SNI ) + { + networkCredentials.disableSni = true; + } + else + { + networkCredentials.disableSni = false; + } + + if( pConnInfo->pAlpnProtocols != NULL ) + { + /* The alpn protocol strings in IotNetworkCredentials_t require a NULL terminator, so the alpn protocol + * string in the connection configuration information is copied to a local buffer to append the NULL + * terminator. */ + memcpy( pAlpnProtos, pConnInfo->pAlpnProtocols, pConnInfo->alpnProtocolsLen ); + pAlpnProtos[ pConnInfo->alpnProtocolsLen ] = '\0'; + networkCredentials.pAlpnProtos = pAlpnProtos; + } + else + { + networkCredentials.pAlpnProtos = NULL; + } + + /* If any of these are NULL a network error will result when trying to make the connection. Because there is + * no invalid memory access resulting from these configurations being NULL, it is not check at the start + * of the function. */ + networkCredentials.pRootCa = pConnInfo->pCaCert; + networkCredentials.rootCaSize = pConnInfo->caCertLen; + networkCredentials.pClientCert = pConnInfo->pClientCert; + networkCredentials.clientCertSize = pConnInfo->clientCertLen; + networkCredentials.pPrivateKey = pConnInfo->pPrivateKey; + networkCredentials.privateKeySize = pConnInfo->privateKeyLen; + + pNetworkCredentials = &networkCredentials; + } + else + { + /* create() takes a NULL if there is no TLS configuration. */ + pNetworkCredentials = NULL; + } + + /* create() will connect to the server specified in addition to creating other network layer + * specific resources. */ + networkStatus = pHttpsConnection->pNetworkInterface->create( &networkServerInfo, + pNetworkCredentials, + &( pHttpsConnection->pNetworkConnection ) ); + + /* Check to see if the network connection succeeded. If it did not succeed, + * then the output parameter pConnHandle will be used to return NULL and the + * function returns an error. */ + if( networkStatus != IOT_NETWORK_SUCCESS ) + { + IotLogError( "Failed to connect to the server at %.*s on port %d with error: %d", + pConnInfo->addressLen, + pConnInfo->pAddress, + pConnInfo->port, + networkStatus ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_CONNECTION_ERROR ); + } + + /* The connection succeeded so set the state to connected. */ + pHttpsConnection->isConnected = true; + + /* The receive callback is invoked by the network layer when data is ready + * to be read from the network. */ + networkStatus = pHttpsConnection->pNetworkInterface->setReceiveCallback( pHttpsConnection->pNetworkConnection, + _networkReceiveCallback, + pHttpsConnection ); + + if( networkStatus != IOT_NETWORK_SUCCESS ) + { + IotLogError( "Failed to connect to set the HTTPS receive callback. " ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_INTERNAL_ERROR ); + } + + /* Connection was successful, so create synchronization primitives. */ + + connectionMutexCreated = IotMutex_Create( &( pHttpsConnection->connectionMutex ), false ); + + if( !connectionMutexCreated ) + { + IotLogError( "Failed to create an internal mutex." ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_INTERNAL_ERROR ); + } + + /* Return the new connection information. */ + *pConnHandle = pHttpsConnection; + + HTTPS_FUNCTION_CLEANUP_BEGIN(); + + /* If we failed anywhere in the connection process, then destroy the semaphores created. */ + if( HTTPS_FAILED( status ) ) + { + /* If there was a connect was successful, disconnect from the network. */ + if( ( pHttpsConnection != NULL ) && ( pHttpsConnection->isConnected ) ) + { + _networkDisconnect( pHttpsConnection ); + _networkDestroy( pHttpsConnection ); + } + + if( connectionMutexCreated ) + { + IotMutex_Destroy( &( pHttpsConnection->connectionMutex ) ); + } + + /* Set the connection handle as NULL if everything failed. */ + *pConnHandle = NULL; + } + + HTTPS_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +static void _networkDisconnect( _httpsConnection_t * pHttpsConnection ) +{ + IotNetworkError_t networkStatus = IOT_NETWORK_SUCCESS; + + networkStatus = pHttpsConnection->pNetworkInterface->close( pHttpsConnection->pNetworkConnection ); + + if( networkStatus != IOT_NETWORK_SUCCESS ) + { + IotLogWarn( "Failed to shutdown the socket with error code: %d", networkStatus ); + } +} + +/*-----------------------------------------------------------*/ + +static void _networkDestroy( _httpsConnection_t * pHttpsConnection ) +{ + IotNetworkError_t networkStatus = IOT_NETWORK_SUCCESS; + + networkStatus = pHttpsConnection->pNetworkInterface->destroy( pHttpsConnection->pNetworkConnection ); + + if( networkStatus != IOT_NETWORK_SUCCESS ) + { + IotLogWarn( "Failed to shutdown the socket with error code: %d", networkStatus ); + } +} + +/*-----------------------------------------------------------*/ + +static IotHttpsReturnCode_t _addHeader( _httpsRequest_t * pHttpsRequest, + const char * pName, + uint32_t nameLen, + const char * pValue, + uint32_t valueLen ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + int headerFieldSeparatorLen = HTTPS_HEADER_FIELD_SEPARATOR_LENGTH; + uint32_t additionalLength = nameLen + headerFieldSeparatorLen + valueLen + HTTPS_END_OF_HEADER_LINES_INDICATOR_LENGTH; + uint32_t possibleLastHeaderAdditionalLength = HTTPS_END_OF_HEADER_LINES_INDICATOR_LENGTH; + + /* Check if there is enough space to add the header field and value + * (name:value\r\n). We need to add a "\r\n" at the end of headers. The use of + * possibleLastHeaderAdditionalLength is to make sure that there is always + * space for the last "\r\n". */ + if( ( additionalLength + possibleLastHeaderAdditionalLength ) > ( ( uint32_t ) ( pHttpsRequest->pHeadersEnd - pHttpsRequest->pHeadersCur ) ) ) + { + IotLogError( "There is %d space left in the header buffer, but we want to add %d more of header.", + pHttpsRequest->pHeadersEnd - pHttpsRequest->pHeadersCur, + additionalLength + possibleLastHeaderAdditionalLength ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_INSUFFICIENT_MEMORY ); + } + + memcpy( pHttpsRequest->pHeadersCur, pName, nameLen ); + pHttpsRequest->pHeadersCur += nameLen; + memcpy( pHttpsRequest->pHeadersCur, HTTPS_HEADER_FIELD_SEPARATOR, headerFieldSeparatorLen ); + pHttpsRequest->pHeadersCur += headerFieldSeparatorLen; + memcpy( pHttpsRequest->pHeadersCur, pValue, valueLen ); + pHttpsRequest->pHeadersCur += valueLen; + memcpy( pHttpsRequest->pHeadersCur, HTTPS_END_OF_HEADER_LINES_INDICATOR, HTTPS_END_OF_HEADER_LINES_INDICATOR_LENGTH ); + pHttpsRequest->pHeadersCur += HTTPS_END_OF_HEADER_LINES_INDICATOR_LENGTH; + IotLogDebug( "Wrote header: \"%s: %.*s\r\n\". Space left in request user buffer: %d", + pName, + valueLen, + pValue, + pHttpsRequest->pHeadersEnd - pHttpsRequest->pHeadersCur ); + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static IotHttpsReturnCode_t _networkSend( _httpsConnection_t * pHttpsConnection, + uint8_t * pBuf, + size_t len ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + size_t numBytesSent = 0; + size_t numBytesSentTotal = 0; + size_t sendLength = len; + + while( numBytesSentTotal < sendLength ) + { + numBytesSent = pHttpsConnection->pNetworkInterface->send( pHttpsConnection->pNetworkConnection, + &( pBuf[ numBytesSentTotal ] ), + sendLength - numBytesSentTotal ); + + /* pNetworkInterface->send returns 0 on error. */ + if( numBytesSent == 0 ) + { + IotLogError( "Error in sending the HTTPS headers. Error code: %d", numBytesSent ); + break; + } + + numBytesSentTotal += numBytesSent; + } + + if( numBytesSentTotal != sendLength ) + { + IotLogError( "Error sending data on the network. We sent %d but there were total %d.", numBytesSentTotal, sendLength ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_NETWORK_ERROR ); + } + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static IotHttpsReturnCode_t _networkRecv( _httpsConnection_t * pHttpsConnection, + uint8_t * pBuf, + size_t bufLen, + size_t * numBytesRecv ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + /* The HTTP server could send the header and the body in two separate TCP packets. If that is the case, then + * receiveUpTo will return return the full headers first. Then on a second call, the body will be returned. + * If the http parser receives just the headers despite the content length being greater than */ + *numBytesRecv = pHttpsConnection->pNetworkInterface->receiveUpto( pHttpsConnection->pNetworkConnection, + pBuf, + bufLen ); + + IotLogDebug( "The network interface receive returned %d.", numBytesRecv ); + + /* We return IOT_HTTPS_NETWORK_ERROR only if we receive nothing. Receiving less + * data than requested is okay because it is not known in advance how much data + * we are going to receive and therefore we request for the available buffer + * size. */ + if( *numBytesRecv == 0 ) + { + IotLogError( "Error in receiving the HTTPS response message. Socket Error code %d", *numBytesRecv ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_NETWORK_ERROR ); + + /* A network error is returned when zero is received because that would indicate that either there + * was a network error or there was a timeout reading data. If there was timeout reading data, then + * the server was too slow to respond. If the server is too slow to respond, then a network error must + * be returned to trigger a connection close. The connection must close after the network error so + * that the response from this request does not piggyback on the response from the next request. */ + } + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static IotHttpsReturnCode_t _sendHttpsHeaders( _httpsConnection_t * pHttpsConnection, + uint8_t * pHeadersBuf, + uint32_t headersLength, + bool isNonPersistent, + uint32_t contentLength ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + const char * connectionHeader = NULL; + int numWritten = 0; + int connectionHeaderLen = 0; + /* The Content-Length header of the form "Content-Length: N\r\n" with a NULL terminator for snprintf. */ + char contentLengthHeaderStr[ HTTPS_MAX_CONTENT_LENGTH_LINE_LENGTH + 1 ]; + + /* The HTTP headers to send after the headers in pHeadersBuf are the Content-Length and the Connection type and + * the final "\r\n" to indicate the end of the the header lines. Note that we are using + * HTTPS_CONNECTION_KEEP_ALIVE_HEADER_LINE_LENGTH because length of "Connection: keep-alive\r\n" is + * more than "Connection: close\r\n". Creating a buffer of bigger size ensures that + * both the connection type strings will fit in the buffer. */ + char finalHeaders[ HTTPS_MAX_CONTENT_LENGTH_LINE_LENGTH + HTTPS_CONNECTION_KEEP_ALIVE_HEADER_LINE_LENGTH + HTTPS_END_OF_HEADER_LINES_INDICATOR_LENGTH ] = { 0 }; + + /* Send the headers passed into this function first. These headers are not terminated with a second set of "\r\n". */ + status = _networkSend( pHttpsConnection, pHeadersBuf, headersLength ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Error sending the HTTPS headers in the request user buffer. Error code: %d", status ); + HTTPS_GOTO_CLEANUP(); + } + + /* If there is a Content-Length, then write that to the finalHeaders to send. */ + if( contentLength > 0 ) + { + numWritten = snprintf( contentLengthHeaderStr, + sizeof( contentLengthHeaderStr ), + "%s: %u\r\n", + HTTPS_CONTENT_LENGTH_HEADER, + ( unsigned int ) contentLength ); + } + + if( ( numWritten < 0 ) || ( numWritten >= sizeof( contentLengthHeaderStr ) ) ) + { + IotLogError( "Internal error in snprintf() in _sendHttpsHeaders(). Error code %d.", numWritten ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_INTERNAL_ERROR ); + } + + /* snprintf() succeeded so copy that to the finalHeaders. */ + memcpy( finalHeaders, contentLengthHeaderStr, numWritten ); + + /* Write the connection persistence type to the final headers. */ + if( isNonPersistent ) + { + connectionHeader = HTTPS_CONNECTION_CLOSE_HEADER_LINE; + connectionHeaderLen = FAST_MACRO_STRLEN( HTTPS_CONNECTION_CLOSE_HEADER_LINE ); + } + else + { + connectionHeader = HTTPS_CONNECTION_KEEP_ALIVE_HEADER_LINE; + connectionHeaderLen = FAST_MACRO_STRLEN( HTTPS_CONNECTION_KEEP_ALIVE_HEADER_LINE ); + } + + memcpy( &finalHeaders[ numWritten ], connectionHeader, connectionHeaderLen ); + numWritten += connectionHeaderLen; + memcpy( &finalHeaders[ numWritten ], HTTPS_END_OF_HEADER_LINES_INDICATOR, HTTPS_END_OF_HEADER_LINES_INDICATOR_LENGTH ); + numWritten += HTTPS_END_OF_HEADER_LINES_INDICATOR_LENGTH; + + status = _networkSend( pHttpsConnection, ( uint8_t * ) finalHeaders, numWritten ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Error sending final HTTPS Headers \r\n%s. Error code: %d", finalHeaders, status ); + HTTPS_GOTO_CLEANUP(); + } + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static IotHttpsReturnCode_t _sendHttpsBody( _httpsConnection_t * pHttpsConnection, + uint8_t * pBodyBuf, + uint32_t bodyLength ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + status = _networkSend( pHttpsConnection, pBodyBuf, bodyLength ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Error sending final HTTPS body at location 0x%x. Error code: %d", pBodyBuf, status ); + HTTPS_GOTO_CLEANUP(); + } + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static IotHttpsReturnCode_t _parseHttpsMessage( _httpParserInfo_t * pHttpParserInfo, + char * pBuf, + size_t len ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + size_t parsedBytes = 0; + const char * pHttpParserErrorDescription = NULL; + http_parser * pHttpParser = &( pHttpParserInfo->responseParser ); + + IotLogDebug( "Now parsing HTTP message buffer to process a response." ); + parsedBytes = pHttpParserInfo->parseFunc( pHttpParser, &_httpParserSettings, pBuf, len ); + IotLogDebug( "http-parser parsed %d bytes out of %d specified.", parsedBytes, len ); + + /* If the parser fails with HPE_CLOSED_CONNECTION or HPE_INVALID_CONSTANT that simply means there + * was data beyond the end of the message. We do not fail in this case because we give the whole + * header buffer or body buffer to the parser even if it is only partly filled with data. + * Errors <= HPE_CB_chunk_complete means that a non-zero number was returned from some callback. + * A nonzero number is returned from some callbacks when we want to stop the parser early + * for example - a HEAD request or the user explicitly asked to ignore the body by not + * providing the body buffer. */ + if( ( pHttpParser->http_errno != 0 ) && + ( HTTP_PARSER_ERRNO( pHttpParser ) != HPE_CLOSED_CONNECTION ) && + ( HTTP_PARSER_ERRNO( pHttpParser ) != HPE_INVALID_CONSTANT ) && + ( HTTP_PARSER_ERRNO( pHttpParser ) > HPE_CB_chunk_complete ) ) + { + pHttpParserErrorDescription = http_errno_description( HTTP_PARSER_ERRNO( pHttpParser ) ); + IotLogError( "http_parser failed on the http response with error: %s", pHttpParserErrorDescription ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_PARSING_ERROR ); + } + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static void _incrementNextLocationToWriteBeyondParsed( uint8_t ** pBufCur, + uint8_t ** pBufEnd ) +{ + /* There is an edge case where the final one or two character received in the header buffer is part of + * the header field separator ": " or part of the header line end "\r\n" delimiters. When this + * happens, pHeadersCur in the response will point not the end of the buffer, but to a character in + * the delimiter. For example: + * Let's say this is our current header buffer after receiving and parsing: + * ["HTTP/1.1 200 OK\r\n\header0: value0\r\nheader1: value1\r\n"] + * pHeadersCur will point to \r because the http-parser does not invoke a callback on the + * delimiters. Since no callback is invoked, pHeadersCur is not incremented. pHeadersEnd points to + * the end of the header buffer which is the unwritable memory location right after the final '\n'. + * Because pHeadersCur is less than pHeaderEnd we loop again and receive on the network causing the + * buffer to look like this: + * ["HTTP/1.1 200 OK\r\n\header0: value0\r\nheader1: value1he"] + * Which will cause an incorrect header1 value to be read if the application decides to read it with + * IotHttpsClient_ReadHeader(). + * + * If our header buffer looks like: + * ["HTTP/1.1 200 OK\r\n\header0: value0\r\nheader1: "] + * then pHeaderCur will point to the colon. + * + * If our header buffer looks like: + * ["HTTP/1.1 200 OK\r\n\header0: value0\r\nheader1:"] + * then pHeaderCur will point to the colon. + * + * If our header buffer looks like + * ["HTTP/1.1 200 OK\r\n\header0: value0\r\nheader1: value1 "] + * then http-parser will consider that space as part of value1. + * + * If our header buffer looks like + * ["HTTP/1.1 200 OK\r\n\header0: value0\r\nheader1: value1\r"] + * then pHeaderCur will point to the carriage return. + * + * If our header buffer looks like + * ["HTTP/1.1 200 OK\r\n\header0: value0\r\nheader1: value1\r\n"] + * As explained in the example above, pHeaderCur will point to the carriage return. + * + * If we somehow receive a partial HTTP response message in our zeroed-out header buffer: + * case 1: ["HTTP/1.1 200 OK\r\nheader0: value0\r\nheader1: value1\r\0\0\0\0\0\0\0"] + * case 2: ["HTTP/1.1 200 OK\r\nheader0: value0\r\nheader1: value1\r\n\0\0\0\0\0\0"] + * case 3: ["HTTP/1.1 200 OK\r\nheader0: value0\r\nheader1:\0\0\0\0\0\0\0\0\0\0\0"] + * case 4: ["HTTP/1.1 200 OK\r\nheader0: value0\r\nheader1: \0\0\0\0\0\0\0\0\0\0\0"] + * then parser may fail or append all of the NULL characters to a header field name or value. */ + while( *pBufCur < *pBufEnd ) + { + if( **pBufCur == CARRIAGE_RETURN_CHARACTER ) + { + ( *pBufCur )++; + } + else if( **pBufCur == NEWLINE_CHARACTER ) + { + ( *pBufCur )++; + break; + } + else if( **pBufCur == COLON_CHARACTER ) + { + ( *pBufCur )++; + } + else if( ( **pBufCur == SPACE_CHARACTER ) && ( *( *pBufCur - 1 ) == COLON_CHARACTER ) ) + { + ( *pBufCur )++; + break; + } + else + { + break; + } + } +} + +/*-----------------------------------------------------------*/ + +static IotHttpsReturnCode_t _receiveHttpsMessage( _httpsConnection_t * pHttpsConnection, + _httpParserInfo_t * pHttpParserInfo, + IotHttpsResponseParserState_t * pCurrentParserState, + IotHttpsResponseParserState_t finalParserState, + IotHttpsResponseBufferState_t currentBufferProcessingState, + uint8_t ** pBufCur, + uint8_t ** pBufEnd ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + size_t numBytesRecv = 0; + + /* The final parser state is either the end of the header lines or the end of the entity body. This state is set in + * the http-parser callbacks. */ + while( ( *pCurrentParserState < finalParserState ) && ( *pBufEnd - *pBufCur > 0 ) ) + { + status = _networkRecv( pHttpsConnection, + *pBufCur, + *pBufEnd - *pBufCur, + &numBytesRecv ); + + /* A network error in _networkRecv is returned only when we received zero bytes. In that case, there is + * no point in parsing we return immediately with the network error. */ + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Network error receiving the HTTPS response headers. Error code: %d", status ); + break; + } + + status = _parseHttpsMessage( pHttpParserInfo, ( char * ) ( *pBufCur ), numBytesRecv ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Failed to parse the message buffer with error: %d", pHttpParserInfo->responseParser.http_errno ); + break; + } + + /* If the current buffer being filled is the header buffer, then \r\n header line separators should not get + * overwritten on the next network read. See _incrementNextLocationToWriteBeyondParsed() for more + * information. */ + if( currentBufferProcessingState == PROCESSING_STATE_FILLING_HEADER_BUFFER ) + { + _incrementNextLocationToWriteBeyondParsed( pBufCur, pBufEnd ); + } + + /* The _httpsResponse->pHeadersCur pointer is updated in the http_parser callbacks. */ + IotLogDebug( "There is %d of space left in the buffer.", *pBufEnd - *pBufCur ); + } + + /* If we did not reach the end of the headers or body in the parser callbacks, then the buffer configured does not + * fit all of that part of the HTTP message. */ + if( *pCurrentParserState < finalParserState ) + { + IotLogDebug( "There are still more data on the network. It could not fit into the specified length %d.", + *pBufEnd - *pBufCur ); + } + + HTTPS_GOTO_CLEANUP(); + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static IotHttpsReturnCode_t _receiveHttpsHeaders( _httpsConnection_t * pHttpsConnection, + _httpsResponse_t * pHttpsResponse ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + pHttpsResponse->bufferProcessingState = PROCESSING_STATE_FILLING_HEADER_BUFFER; + + IotLogDebug( "Now attempting to receive the HTTP response headers into a buffer with length %d.", + pHttpsResponse->pHeadersEnd - pHttpsResponse->pHeadersCur ); + + status = _receiveHttpsMessage( pHttpsConnection, + &( pHttpsResponse->httpParserInfo ), + &( pHttpsResponse->parserState ), + PARSER_STATE_HEADERS_COMPLETE, + PROCESSING_STATE_FILLING_HEADER_BUFFER, + &( pHttpsResponse->pHeadersCur ), + &( pHttpsResponse->pHeadersEnd ) ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Error receiving the HTTP headers. Error code %d", status ); + HTTPS_GOTO_CLEANUP(); + } + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +/* _receiveHttpsHeaders() must be called first before this function is called. */ +static IotHttpsReturnCode_t _receiveHttpsBody( _httpsConnection_t * pHttpsConnection, + _httpsResponse_t * pHttpsResponse ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + IotLogDebug( "Now attempting to receive the HTTP response body into a buffer with length %d.", + pHttpsResponse->pBodyEnd - pHttpsResponse->pBodyCur ); + + pHttpsResponse->bufferProcessingState = PROCESSING_STATE_FILLING_BODY_BUFFER; + + status = _receiveHttpsMessage( pHttpsConnection, + &( pHttpsResponse->httpParserInfo ), + &( pHttpsResponse->parserState ), + PARSER_STATE_BODY_COMPLETE, + PROCESSING_STATE_FILLING_BODY_BUFFER, + &( pHttpsResponse->pBodyCur ), + &( pHttpsResponse->pBodyEnd ) ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Error receiving the HTTP body. Error code %d", status ); + HTTPS_GOTO_CLEANUP(); + } + + HTTPS_FUNCTION_CLEANUP_BEGIN(); + + IotLogDebug( "The remaining content length on the network is %d.", + pHttpsResponse->httpParserInfo.responseParser.content_length ); + + HTTPS_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +static IotHttpsReturnCode_t _flushHttpsNetworkData( _httpsConnection_t * pHttpsConnection, + _httpsResponse_t * pHttpsResponse ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + static uint8_t flushBuffer[ IOT_HTTPS_MAX_FLUSH_BUFFER_SIZE ] = { 0 }; + const char * pHttpParserErrorDescription = NULL; + IotHttpsReturnCode_t parserStatus = IOT_HTTPS_OK; + IotHttpsReturnCode_t networkStatus = IOT_HTTPS_OK; + size_t numBytesRecv = 0; + + /* Even if there is not body, the parser state will become body complete after the headers finish. */ + while( pHttpsResponse->parserState < PARSER_STATE_BODY_COMPLETE ) + { + IotLogDebug( "Now clearing the rest of the response data on the socket. " ); + networkStatus = _networkRecv( pHttpsConnection, flushBuffer, IOT_HTTPS_MAX_FLUSH_BUFFER_SIZE, &numBytesRecv ); + + /* Run this through the parser so that we can get the end of the HTTP message, instead of simply timing out the socket to stop. + * If we relied on the socket timeout to stop reading the network socket, then the server may close the connection. */ + parserStatus = _parseHttpsMessage( &( pHttpsResponse->httpParserInfo ), ( char * ) flushBuffer, numBytesRecv ); + + if( HTTPS_FAILED( parserStatus ) ) + { + pHttpParserErrorDescription = http_errno_description( HTTP_PARSER_ERRNO( &pHttpsResponse->httpParserInfo.responseParser ) ); + IotLogError( "Network Flush: Failed to parse the response body buffer with error: %d, %s", + pHttpsResponse->httpParserInfo.responseParser.http_errno, + pHttpParserErrorDescription ); + break; + } + + /* If there is a network error then we want to stop clearing out the buffer. */ + if( HTTPS_FAILED( networkStatus ) ) + { + IotLogWarn( "Network Flush: Error receiving the rest of the HTTP response. Error code: %d", + networkStatus ); + break; + } + } + + /* All network errors except timeouts are returned. */ + if( HTTPS_FAILED( networkStatus ) ) + { + status = networkStatus; + } + else + { + status = parserStatus; + } + + HTTPS_GOTO_CLEANUP(); + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static IotHttpsReturnCode_t _sendHttpsHeadersAndBody( _httpsConnection_t * pHttpsConnection, + _httpsRequest_t * pHttpsRequest ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + /* Send the HTTP headers. */ + status = _sendHttpsHeaders( pHttpsConnection, + pHttpsRequest->pHeaders, + pHttpsRequest->pHeadersCur - pHttpsRequest->pHeaders, + pHttpsRequest->isNonPersistent, + pHttpsRequest->bodyLength ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Error sending the HTTPS headers with error code: %d", status ); + HTTPS_GOTO_CLEANUP(); + } + + if( ( pHttpsRequest->pBody != NULL ) && ( pHttpsRequest->bodyLength > 0 ) ) + { + status = _sendHttpsBody( pHttpsConnection, pHttpsRequest->pBody, pHttpsRequest->bodyLength ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Error sending final HTTPS body. Return code: %d", status ); + HTTPS_GOTO_CLEANUP(); + } + } + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static void _sendHttpsRequest( IotTaskPool_t pTaskPool, + IotTaskPoolJob_t pJob, + void * pUserContext ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + _httpsRequest_t * pHttpsRequest = ( _httpsRequest_t * ) ( pUserContext ); + _httpsConnection_t * pHttpsConnection = pHttpsRequest->pHttpsConnection; + _httpsResponse_t * pHttpsResponse = pHttpsRequest->pHttpsResponse; + IotHttpsReturnCode_t disconnectStatus = IOT_HTTPS_OK; + IotHttpsReturnCode_t scheduleStatus = IOT_HTTPS_OK; + IotLink_t * pQItem = NULL; + _httpsRequest_t * pNextHttpsRequest = NULL; + + ( void ) pTaskPool; + ( void ) pJob; + + IotLogDebug( "Task with request ID: %d started.", pHttpsRequest ); + + if( pHttpsRequest->cancelled == true ) + { + IotLogDebug( "Request ID: %d was cancelled.", pHttpsRequest ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_SEND_ABORT ); + } + + /* To protect against out of order network data from a rouge server, signal that the request is + * not finished sending. */ + pHttpsResponse->reqFinishedSending = false; + + /* Queue the response to expect from the network. */ + IotMutex_Lock( &( pHttpsConnection->connectionMutex ) ); + IotDeQueue_EnqueueTail( &( pHttpsConnection->respQ ), &( pHttpsResponse->link ) ); + IotMutex_Unlock( &( pHttpsConnection->connectionMutex ) ); + + /* Get the headers from the application. For a synchronous request the application should have appended extra + * headers before this point. */ + if( pHttpsRequest->isAsync && pHttpsRequest->pCallbacks->appendHeaderCallback ) + { + pHttpsRequest->pCallbacks->appendHeaderCallback( pHttpsRequest->pUserPrivData, pHttpsRequest ); + } + + if( pHttpsRequest->cancelled == true ) + { + IotLogDebug( "Request ID: %d was cancelled.", pHttpsRequest ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_SEND_ABORT ); + } + + /* Ask the user for data to write body to the network. We only ask the user once. This is so that + * we can calculate the Content-Length to send.*/ + if( pHttpsRequest->isAsync && pHttpsRequest->pCallbacks->writeCallback ) + { + /* If there is data, then a Content-Length header value will be provided and we send the headers + * before that user data. */ + pHttpsRequest->pCallbacks->writeCallback( pHttpsRequest->pUserPrivData, pHttpsRequest ); + } + + if( HTTPS_FAILED( pHttpsRequest->bodyTxStatus ) ) + { + IotLogError( "Failed to send the headers and body over the network during the writeCallback. Error code: %d.", + status ); + HTTPS_SET_AND_GOTO_CLEANUP( pHttpsRequest->bodyTxStatus ); + } + + if( pHttpsRequest->cancelled == true ) + { + IotLogDebug( "Request ID: %d was cancelled.", pHttpsRequest ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_SEND_ABORT ); + } + + /* If this is a synchronous request then the header and body were configured beforehand. The header and body + * are sent now. For an asynchronous request, the header and body are sent in IotHttpsClient_WriteRequestBody() + * which is to be invoked in #IotHttpsClientCallbacks_t.writeCallback(). If the application never invokes + * IotHttpsClient_WriteRequestBody(), then pHttpsRequest->pBody will be NULL. In this case we still want to + * send whatever headers we have. */ + if( ( pHttpsRequest->isAsync == false ) || + ( ( pHttpsRequest->isAsync ) && ( pHttpsRequest->pBody == NULL ) ) ) + { + status = _sendHttpsHeadersAndBody( pHttpsConnection, pHttpsRequest ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Failed to send the headers and body on the network. Error code: %d", status ); + HTTPS_GOTO_CLEANUP(); + } + } + + HTTPS_FUNCTION_CLEANUP_BEGIN(); + + /* The request has finished sending. This indicates to the network receive callback that the request was + * finished, so a response received on the network is valid. This also lets a possible application called + * IotHttpsClient_Disconnect() know that the connection is not busy, so the connection can be destroyed. */ + pHttpsResponse->reqFinishedSending = true; + + if( HTTPS_FAILED( status ) ) + { + /* If the headers or body failed to send, then there should be no response expected from the server. */ + /* Cancel the response incase there is a response from the server. */ + _cancelResponse( pHttpsResponse ); + IotMutex_Lock( &( pHttpsConnection->connectionMutex ) ); + + if( IotLink_IsLinked( &( pHttpsResponse->link ) ) ) + { + IotDeQueue_Remove( &( pHttpsResponse->link ) ); + } + + IotMutex_Unlock( &( pHttpsConnection->connectionMutex ) ); + + /* Set the error status in the sync workflow. */ + pHttpsResponse->syncStatus = status; + + /* Return the error status or cancel status to the application for an asynchronous workflow. */ + if( pHttpsRequest->isAsync && pHttpsRequest->pCallbacks->errorCallback ) + { + pHttpsRequest->pCallbacks->errorCallback( pHttpsRequest->pUserPrivData, pHttpsRequest, NULL, status ); + } + + /* We close the connection on all network errors. All network errors in receiving the response, close the + * connection. For consistency in behavior, if there is a network error in send, the connection should also be + * closed. */ + if( status == IOT_HTTPS_NETWORK_ERROR ) + { + IotLogDebug( "Disconnecting request %d.", pHttpsRequest ); + disconnectStatus = IotHttpsClient_Disconnect( pHttpsConnection ); + + if( pHttpsRequest->isAsync && pHttpsRequest->pCallbacks->connectionClosedCallback ) + { + pHttpsRequest->pCallbacks->connectionClosedCallback( pHttpsRequest->pUserPrivData, + pHttpsConnection, + disconnectStatus ); + } + + if( HTTPS_FAILED( disconnectStatus ) ) + { + IotLogWarn( "Failed to disconnect request %d. Error code: %d.", pHttpsRequest, disconnectStatus ); + } + } + else + { + /* Because this request failed, the network receive callback may never be invoked to schedule other possible + * requests in the queue. In order to avoid requests never getting scheduled on a connected connection, + * the first item in the queue is scheduled if it can be. */ + IotMutex_Lock( &( pHttpsConnection->connectionMutex ) ); + + /* Get the next item in the queue by removing this current (which is the first) and peeking at the head + * again. */ + IotDeQueue_Remove( &( pHttpsRequest->link ) ); + pQItem = IotDeQueue_PeekHead( &( pHttpsConnection->reqQ ) ); + /* This current request is put back because it is removed again for all cases at the end of this routine. */ + IotDeQueue_EnqueueHead( &( pHttpsConnection->reqQ ), &( pHttpsRequest->link ) ); + IotMutex_Unlock( &( pHttpsConnection->connectionMutex ) ); + + if( pQItem != NULL ) + { + /* Set this next request to send. */ + pNextHttpsRequest = IotLink_Container( _httpsRequest_t, pQItem, link ); + + if( pNextHttpsRequest->scheduled == false ) + { + IotLogDebug( "Request %d is next in the queue. Now scheduling a task to send the request.", pNextHttpsRequest ); + scheduleStatus = _scheduleHttpsRequestSend( pNextHttpsRequest ); + + /* If there was an error with scheduling the new task, then report it. */ + if( HTTPS_FAILED( scheduleStatus ) ) + { + IotLogError( "Error scheduling HTTPS request %d. Error code: %d", pNextHttpsRequest, scheduleStatus ); + + if( pNextHttpsRequest->isAsync && pNextHttpsRequest->pCallbacks->errorCallback ) + { + pNextHttpsRequest->pCallbacks->errorCallback( pNextHttpsRequest->pUserPrivData, pNextHttpsRequest, NULL, scheduleStatus ); + } + else + { + pNextHttpsRequest->pHttpsResponse->syncStatus = scheduleStatus; + } + } + } + } + } + + /* Post to the response finished semaphore to unlock the application waiting on a synchronous request. */ + if( pHttpsRequest->isAsync == false ) + { + IotSemaphore_Post( &( pHttpsResponse->respFinishedSem ) ); + } + else if( pHttpsRequest->pCallbacks->responseCompleteCallback ) + { + /* Call the response complete callback. We always call this even if we did not receive the response to + * let the application know that the request has completed. */ + pHttpsRequest->pCallbacks->responseCompleteCallback( pHttpsRequest->pUserPrivData, NULL, status, 0 ); + } + } + + IotMutex_Lock( &( pHttpsConnection->connectionMutex ) ); + /* Now that the current request is finished, we dequeue the current request from the queue. */ + IotDeQueue_DequeueHead( &( pHttpsConnection->reqQ ) ); + IotMutex_Unlock( &( pHttpsConnection->connectionMutex ) ); + + /* This routine returns a void so there is no HTTPS_FUNCTION_CLEANUP_END();. */ +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t _scheduleHttpsRequestSend( _httpsRequest_t * pHttpsRequest ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + IotTaskPoolError_t taskPoolStatus = IOT_TASKPOOL_SUCCESS; + _httpsConnection_t * pHttpsConnection = pHttpsRequest->pHttpsConnection; + + /* Set the request to scheduled even if scheduling fails. */ + pHttpsRequest->scheduled = true; + + taskPoolStatus = IotTaskPool_CreateJob( _sendHttpsRequest, + ( void * ) ( pHttpsRequest ), + &( pHttpsConnection->taskPoolJobStorage ), + &( pHttpsConnection->taskPoolJob ) ); + + /* Creating a task pool job should never fail when parameters are valid. */ + if( taskPoolStatus != IOT_TASKPOOL_SUCCESS ) + { + IotLogError( "Error creating a taskpool job for request servicing. Error code: %d", taskPoolStatus ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_INTERNAL_ERROR ); + } + + taskPoolStatus = IotTaskPool_Schedule( IOT_SYSTEM_TASKPOOL, pHttpsConnection->taskPoolJob, 0 ); + + if( taskPoolStatus != IOT_TASKPOOL_SUCCESS ) + { + IotLogError( "Failed to schedule taskpool job. Error code: %d", taskPoolStatus ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_ASYNC_SCHEDULING_ERROR ); + } + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t _addRequestToConnectionReqQ( _httpsRequest_t * pHttpsRequest ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + _httpsConnection_t * pHttpsConnection = pHttpsRequest->pHttpsConnection; + bool scheduleRequest = false; + + /* Log information about the request*/ + IotLogDebug( "Now queueing request %d.", pHttpsRequest ); + + if( pHttpsRequest->isNonPersistent ) + { + IotLogDebug( "Request %d is non-persistent.", pHttpsRequest ); + } + else + { + IotLogDebug( "Request %d is persistent. ", pHttpsRequest ); + } + + if( pHttpsRequest->isAsync ) + { + IotLogDebug( " Request %d is asynchronous.", pHttpsRequest ); + } + else + { + IotLogDebug( " Request %d is synchronous.", pHttpsRequest ); + } + + /* This is a new request and has not been scheduled if this routine is called. */ + pHttpsRequest->scheduled = false; + + /* Place the request into the queue. */ + IotMutex_Lock( &( pHttpsConnection->connectionMutex ) ); + + /* If there is an active response, scheduling the next request at the same time may corrupt the workflow. Part of + * the next response for the next request may be present in the currently receiving response's buffers. To avoid + * this, check if there are pending responses to determine if this request should be scheduled right away or not. + * + * If there are other requests in the queue, and there are responses in the queue, then the network receive callback + * will handle scheduling the next requests (or is already scheduled and currently sending). */ + if( ( IotDeQueue_IsEmpty( &( pHttpsConnection->reqQ ) ) ) && + ( IotDeQueue_IsEmpty( &( pHttpsConnection->respQ ) ) ) ) + { + scheduleRequest = true; + } + + /* Place into the connection's request to have a taskpool worker schedule to serve it later. */ + IotDeQueue_EnqueueTail( &( pHttpsConnection->reqQ ), &( pHttpsRequest->link ) ); + IotMutex_Unlock( &( pHttpsConnection->connectionMutex ) ); + + if( scheduleRequest ) + { + /* This routine schedules a task pool worker to send the request. If a worker is available immediately, then + * the request is sent right away. */ + status = _scheduleHttpsRequestSend( pHttpsRequest ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Failed to schedule the request in the queue for request %d. Error code: %d", pHttpsRequest, status ); + + /* If we fail to schedule the only request in the queue we should remove it. */ + IotMutex_Lock( &( pHttpsConnection->connectionMutex ) ); + IotDeQueue_Remove( &( pHttpsRequest->link ) ); + IotMutex_Unlock( &( pHttpsConnection->connectionMutex ) ); + + HTTPS_GOTO_CLEANUP(); + } + } + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static void _cancelRequest( _httpsRequest_t * pHttpsRequest ) +{ + pHttpsRequest->cancelled = true; +} + +/*-----------------------------------------------------------*/ + +static void _cancelResponse( _httpsResponse_t * pHttpsResponse ) +{ + pHttpsResponse->cancelled = true; +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_Init( void ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + /* This sets all member in the _httpParserSettings to zero. It does not return any errors. */ + http_parser_settings_init( &_httpParserSettings ); + + /* Set the http-parser callbacks. */ + _httpParserSettings.on_message_begin = _httpParserOnMessageBeginCallback; + _httpParserSettings.on_status = _httpParserOnStatusCallback; + _httpParserSettings.on_header_field = _httpParserOnHeaderFieldCallback; + _httpParserSettings.on_header_value = _httpParserOnHeaderValueCallback; + _httpParserSettings.on_headers_complete = _httpParserOnHeadersCompleteCallback; + _httpParserSettings.on_body = _httpParserOnBodyCallback; + _httpParserSettings.on_message_complete = _httpParserOnMessageCompleteCallback; + +/* This code prints debugging information and is, therefore, compiled only when + * log level is set to IOT_LOG_DEBUG. */ + #if ( LIBRARY_LOG_LEVEL == IOT_LOG_DEBUG ) + _httpParserSettings.on_chunk_header = _httpParserOnChunkHeaderCallback; + _httpParserSettings.on_chunk_complete = _httpParserOnChunkCompleteCallback; + #endif + HTTPS_GOTO_CLEANUP(); + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static IotHttpsReturnCode_t _initializeResponse( IotHttpsResponseHandle_t * pRespHandle, + IotHttpsResponseInfo_t * pRespInfo, + _httpsRequest_t * pHttpsRequest ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + _httpsResponse_t * pHttpsResponse = NULL; + + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pRespInfo->userBuffer.pBuffer ); + + /* Check of the user buffer is large enough for the response context + default headers. */ + HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( pRespInfo->userBuffer.bufferLen >= responseUserBufferMinimumSize, + IOT_HTTPS_INSUFFICIENT_MEMORY, + "Buffer size is too small to initialize the response context. User buffer size: %d, required minimum size; %d.", + pRespInfo->userBuffer.bufferLen, + responseUserBufferMinimumSize ); + + /* Initialize the corresponding response to this request. */ + pHttpsResponse = ( _httpsResponse_t * ) ( pRespInfo->userBuffer.pBuffer ); + + /* Clear out the response user buffer. This is important because we + * give the whole buffer to the parser as opposed to the actual content + * length and rely on the parser to stop when a complete HTTP response + * is found. To make sure that any data in the buffer which is not part + * of the received HTTP response, does not get interpreted as part of + * the HTTP repose, we zero out the buffer here. */ + memset( pRespInfo->userBuffer.pBuffer, 0, pRespInfo->userBuffer.bufferLen ); + + pHttpsResponse->pHeaders = ( uint8_t * ) ( pHttpsResponse ) + sizeof( _httpsResponse_t ); + pHttpsResponse->pHeadersEnd = ( uint8_t * ) ( pHttpsResponse ) + pRespInfo->userBuffer.bufferLen; + pHttpsResponse->pHeadersCur = pHttpsResponse->pHeaders; + + if( pHttpsRequest->isAsync ) + { + pHttpsResponse->isAsync = true; + + /* For an asynchronous request the response body is provided by the application in the + * IotHttpsCallbacks_t.readReadyCallback(). These pointers will be updated when IotHttpsClient_ReadResponseBody() + * is invoked. */ + pHttpsResponse->pBody = NULL; + pHttpsResponse->pBodyCur = NULL; + pHttpsResponse->pBodyEnd = NULL; + + pHttpsResponse->pCallbacks = pHttpsRequest->pCallbacks; + pHttpsResponse->pUserPrivData = pHttpsRequest->pUserPrivData; + } + else + { + pHttpsResponse->isAsync = false; + /* The request body pointer is allowed to be NULL. u.pSyncInfo was checked for NULL earlier in this function. */ + pHttpsResponse->pBody = pRespInfo->pSyncInfo->pBody; + pHttpsResponse->pBodyCur = pHttpsResponse->pBody; + pHttpsResponse->pBodyEnd = pHttpsResponse->pBody + pRespInfo->pSyncInfo->bodyLen; + + /* Clear out the body bufffer. This is important because we give the + * whole buffer to the parser as opposed to the actual content length and + * rely on the parser to stop when a complete HTTP response is found. To + * make sure that any data in the buffer which is not part of the received + * HTTP response, does not get interpreted as part of the HTTP repose, we + * zero out the buffer here. */ + memset( pRespInfo->pSyncInfo->pBody, 0, pRespInfo->pSyncInfo->bodyLen ); + } + + /* Reinitialize the parser and set the fill buffer state to empty. This does not return any errors. */ + http_parser_init( &( pHttpsResponse->httpParserInfo.responseParser ), HTTP_RESPONSE ); + http_parser_init( &( pHttpsResponse->httpParserInfo.readHeaderParser ), HTTP_RESPONSE ); + /* Set the third party http parser function. */ + pHttpsResponse->httpParserInfo.parseFunc = http_parser_execute; + pHttpsResponse->httpParserInfo.readHeaderParser.data = ( void * ) ( pHttpsResponse ); + pHttpsResponse->httpParserInfo.responseParser.data = ( void * ) ( pHttpsResponse ); + + pHttpsResponse->status = 0; + pHttpsResponse->method = pHttpsRequest->method; + pHttpsResponse->parserState = PARSER_STATE_NONE; + pHttpsResponse->bufferProcessingState = PROCESSING_STATE_NONE; + pHttpsResponse->pReadHeaderField = NULL; + pHttpsResponse->readHeaderFieldLength = 0; + pHttpsResponse->pReadHeaderValue = NULL; + pHttpsResponse->readHeaderValueLength = 0; + pHttpsResponse->foundHeaderField = 0; + pHttpsResponse->pHttpsConnection = NULL; + + pHttpsResponse->pBodyInHeaderBuf = NULL; + pHttpsResponse->pBodyCurInHeaderBuf = NULL; + pHttpsResponse->bodyRxStatus = IOT_HTTPS_OK; + pHttpsResponse->cancelled = false; + pHttpsResponse->syncStatus = IOT_HTTPS_OK; + /* There is no request associated with this response right now, so it is finished sending. */ + pHttpsResponse->reqFinishedSending = true; + pHttpsResponse->isNonPersistent = pHttpsRequest->isNonPersistent; + + /* Set the response handle to return. */ + *pRespHandle = pHttpsResponse; + + HTTPS_FUNCTION_CLEANUP_BEGIN(); + + if( HTTPS_FAILED( status ) ) + { + pRespHandle = NULL; + } + + HTTPS_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +void IotHttpsClient_Cleanup( void ) +{ + /* There is nothing to clean up here as of now. */ +} + +/* --------------------------------------------------------- */ + +IotHttpsReturnCode_t IotHttpsClient_Connect( IotHttpsConnectionHandle_t * pConnHandle, + IotHttpsConnectionInfo_t * pConnInfo ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + /* Check for NULL parameters in a public API. */ + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pConnHandle ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pConnInfo ); + + /* If a valid connection handle is passed in. */ + if( *pConnHandle != NULL ) + { + /* If the handle in a connected state, then we want to disconnect before reconnecting. The ONLY way to put the + * handle is a disconnect state is to call IotHttpsClient_Disconnect(). */ + if( ( *pConnHandle )->isConnected ) + { + status = IotHttpsClient_Disconnect( *pConnHandle ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Error disconnecting a connected *pConnHandle passed to IotHttpsClient_Connect().Error code %d", status ); + *pConnHandle = NULL; + HTTPS_GOTO_CLEANUP(); + } + } + } + + /* Connect to the server now. Initialize all resources needed for the connection context as well here. */ + status = _createHttpsConnection( pConnHandle, pConnInfo ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Error in IotHttpsClient_Connect(). Error code %d.", status ); + } + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_Disconnect( IotHttpsConnectionHandle_t connHandle ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + _httpsRequest_t * pHttpsRequest = NULL; + _httpsResponse_t * pHttpsResponse = NULL; + IotLink_t * pRespItem = NULL; + IotLink_t * pReqItem = NULL; + + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( connHandle ); + + /* If this routine is currently is progress by another thread, for instance the taskpool worker that received a + * network error after sending, then return right away because connection resources are being used. */ + if( IotMutex_TryLock( &( connHandle->connectionMutex ) ) == false ) + { + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_BUSY ); + } + + /* Do not attempt to disconnect an already disconnected connection. + * It can happen when a user calls this functions and we return IOT_HTTPS_BUSY. */ + if( connHandle->isConnected ) + { + /* Mark the network as disconnected whether the disconnect passes or not. */ + connHandle->isConnected = false; + _networkDisconnect( connHandle ); + } + + /* If there is a response in the connection's response queue and the associated request has not finished sending, + * then we cannot destroy the connection until it finishes. */ + pRespItem = IotDeQueue_DequeueHead( &( connHandle->respQ ) ); + + if( pRespItem != NULL ) + { + pHttpsResponse = IotLink_Container( _httpsResponse_t, pRespItem, link ); + + if( pHttpsResponse->reqFinishedSending == false ) + { + IotLogError( "Connection is in use. Disconnected, but cannot destroy the connection." ); + status = IOT_HTTPS_BUSY; + + /* The request is busy, to as quickly as possible allow a successful retry call of this function we must + * cancel the busy request which is the first in the queue. */ + pReqItem = IotDeQueue_PeekHead( &( connHandle->reqQ ) ); + + if( pReqItem != NULL ) + { + pHttpsRequest = IotLink_Container( _httpsRequest_t, pReqItem, link ); + _cancelRequest( pHttpsRequest ); + } + + /* We set the status as busy, but we do not goto the cleanup right away because we still want to remove + * all pending requests. */ + } + + /* Delete all possible pending responses. (This is defensive.) */ + IotDeQueue_RemoveAll( &( connHandle->respQ ), NULL, 0 ); + + /* Put the response that was dequeued back so that the application can call this function again to check later + * that is exited and marked itself as finished sending. + * If during the last check and this check reqFinishedSending gets set to true, that is OK because on the next + * call to this routine, the disconnect will succeed. */ + if( pHttpsResponse->reqFinishedSending == false ) + { + IotDeQueue_EnqueueHead( &( connHandle->respQ ), pRespItem ); + } + } + + /* Remove all pending requests. If this routine is called from the application context and there is a + * network receive callback in process, this routine will wait in _networkDestroy until that routine returns. + * If this is routine is called from the network receive callback context, then the destroy happens after the + * network receive callback context returns. */ + IotDeQueue_RemoveAll( &( connHandle->reqQ ), NULL, 0 ); + + /* Do not attempt to destroy an already destroyed connection. This can happen when the user calls this function and + * IOT_HTTPS_BUSY is returned. */ + if( HTTPS_SUCCEEDED( status ) ) + { + if( connHandle->isDestroyed == false ) + { + connHandle->isDestroyed = true; + _networkDestroy( connHandle ); + } + } + + HTTPS_FUNCTION_CLEANUP_BEGIN(); + + /* This function is no longer in process, so disconnecting is no longer in process. This signals to the retry + * on this function that it can proceed with the disconnecting activities. */ + if( connHandle != NULL ) + { + IotMutex_Unlock( &( connHandle->connectionMutex ) ); + } + + HTTPS_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_InitializeRequest( IotHttpsRequestHandle_t * pReqHandle, + IotHttpsRequestInfo_t * pReqInfo ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + _httpsRequest_t * pHttpsRequest = NULL; + size_t additionalLength = 0; + size_t spaceLen = 1; + char * pSpace = " "; + size_t httpsMethodLen = 0; + size_t httpsProtocolVersionLen = FAST_MACRO_STRLEN( HTTPS_PROTOCOL_VERSION ); + + /* Check for NULL parameters in the public API. */ + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pReqHandle ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pReqInfo ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pReqInfo->userBuffer.pBuffer ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pReqInfo->pHost ); + + if( pReqInfo->isAsync ) + { + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pReqInfo->u.pAsyncInfo ); + } + else + { + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pReqInfo->u.pSyncInfo ); + } + + /* Check of the user buffer is large enough for the request context + default headers. */ + HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( pReqInfo->userBuffer.bufferLen >= requestUserBufferMinimumSize, + IOT_HTTPS_INSUFFICIENT_MEMORY, + "Buffer size is too small to initialize the request context. User buffer size: %d, required minimum size; %d.", + pReqInfo->userBuffer.bufferLen, + requestUserBufferMinimumSize ); + + /* Set the request contet to the start of the userbuffer. */ + pHttpsRequest = ( _httpsRequest_t * ) ( pReqInfo->userBuffer.pBuffer ); + /* Clear out the user buffer. */ + memset( pReqInfo->userBuffer.pBuffer, 0, pReqInfo->userBuffer.bufferLen ); + + /* Set the start of the headers to the end of the request context in the user buffer. */ + pHttpsRequest->pHeaders = ( uint8_t * ) pHttpsRequest + sizeof( _httpsRequest_t ); + pHttpsRequest->pHeadersEnd = ( uint8_t * ) pHttpsRequest + pReqInfo->userBuffer.bufferLen; + pHttpsRequest->pHeadersCur = pHttpsRequest->pHeaders; + + /* Get the length of the HTTP method. */ + httpsMethodLen = strlen( _pHttpsMethodStrings[ pReqInfo->method ] ); + + /* Add the request line to the header buffer. */ + additionalLength = httpsMethodLen + \ + spaceLen + \ + pReqInfo->pathLen + \ + spaceLen + \ + httpsProtocolVersionLen + \ + HTTPS_END_OF_HEADER_LINES_INDICATOR_LENGTH; + + if( ( additionalLength + pHttpsRequest->pHeadersCur ) > ( pHttpsRequest->pHeadersEnd ) ) + { + IotLogError( "Request line does not fit into the request user buffer: \"%s %.*s HTTP/1.1\\r\\n\" . ", + _pHttpsMethodStrings[ pReqInfo->method ], + pReqInfo->pathLen, + pReqInfo->pPath ); + IotLogError( "The length needed is %d and the space available is %d.", additionalLength, pHttpsRequest->pHeadersEnd - pHttpsRequest->pHeadersCur ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_INSUFFICIENT_MEMORY ); + } + + /* Write " HTTP/1.1\r\n" to the start of the header space. */ + memcpy( pHttpsRequest->pHeadersCur, _pHttpsMethodStrings[ pReqInfo->method ], httpsMethodLen ); + pHttpsRequest->pHeadersCur += httpsMethodLen; + memcpy( pHttpsRequest->pHeadersCur, pSpace, spaceLen ); + pHttpsRequest->pHeadersCur += spaceLen; + + if( pReqInfo->pPath == NULL ) + { + pReqInfo->pPath = HTTPS_EMPTY_PATH; + pReqInfo->pathLen = FAST_MACRO_STRLEN( HTTPS_EMPTY_PATH ); + } + + memcpy( pHttpsRequest->pHeadersCur, pReqInfo->pPath, pReqInfo->pathLen ); + pHttpsRequest->pHeadersCur += pReqInfo->pathLen; + memcpy( pHttpsRequest->pHeadersCur, pSpace, spaceLen ); + pHttpsRequest->pHeadersCur += spaceLen; + memcpy( pHttpsRequest->pHeadersCur, HTTPS_PROTOCOL_VERSION, httpsProtocolVersionLen ); + pHttpsRequest->pHeadersCur += httpsProtocolVersionLen; + memcpy( pHttpsRequest->pHeadersCur, HTTPS_END_OF_HEADER_LINES_INDICATOR, HTTPS_END_OF_HEADER_LINES_INDICATOR_LENGTH ); + pHttpsRequest->pHeadersCur += HTTPS_END_OF_HEADER_LINES_INDICATOR_LENGTH; + + /* Add the User-Agent header. */ + status = _addHeader( pHttpsRequest, HTTPS_USER_AGENT_HEADER, FAST_MACRO_STRLEN( HTTPS_USER_AGENT_HEADER ), IOT_HTTPS_USER_AGENT, FAST_MACRO_STRLEN( IOT_HTTPS_USER_AGENT ) ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Failed to write header to the request user buffer: \"User-Agent: %s\\r\\n\" . Error code: %d", + IOT_HTTPS_USER_AGENT, + status ); + HTTPS_GOTO_CLEANUP(); + } + + status = _addHeader( pHttpsRequest, HTTPS_HOST_HEADER, FAST_MACRO_STRLEN( HTTPS_HOST_HEADER ), pReqInfo->pHost, pReqInfo->hostLen ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Failed to write \"Host: %.*s\\r\\n\" to the request user buffer. Error code: %d", + pReqInfo->hostLen, + pReqInfo->pHost, + status ); + HTTPS_GOTO_CLEANUP(); + } + + if( pReqInfo->isAsync ) + { + pHttpsRequest->isAsync = true; + /* If this is an asynchronous request then save the callbacks to use. */ + pHttpsRequest->pCallbacks = &( pReqInfo->u.pAsyncInfo->callbacks ); + pHttpsRequest->pUserPrivData = pReqInfo->u.pAsyncInfo->pPrivData; + /* The body pointer and body length will be filled in when the application sends data in the writeCallback. */ + pHttpsRequest->pBody = NULL; + pHttpsRequest->bodyLength = 0; + } + else + { + pHttpsRequest->isAsync = false; + /* Set the HTTP request entity body. This is allowed to be NULL for no body like for a GET request. */ + pHttpsRequest->pBody = pReqInfo->u.pSyncInfo->pBody; + pHttpsRequest->bodyLength = pReqInfo->u.pSyncInfo->bodyLen; + } + + /* Save the method of this request. */ + pHttpsRequest->method = pReqInfo->method; + /* Set the connection persistence flag for keeping the connection open after receiving a response. */ + pHttpsRequest->isNonPersistent = pReqInfo->isNonPersistent; + /* Initialize the request cancellation. */ + pHttpsRequest->cancelled = false; + /* Initialize the status of sending the body over the network in a possible asynchronous request. */ + pHttpsRequest->bodyTxStatus = IOT_HTTPS_OK; + /* This is a new request and therefore not scheduled yet. */ + pHttpsRequest->scheduled = false; + + /* Set the request handle to return. */ + *pReqHandle = pHttpsRequest; + + HTTPS_FUNCTION_CLEANUP_BEGIN(); + + if( HTTPS_FAILED( status ) && ( pReqHandle != NULL ) ) + { + /* Set the request handle to return to NULL, if we failed anywhere. */ + *pReqHandle = NULL; + } + + HTTPS_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_AddHeader( IotHttpsRequestHandle_t reqHandle, + char * pName, + uint32_t nameLen, + char * pValue, + uint32_t valueLen ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + /* Check for NULL pointer paramters. */ + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pName ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pValue ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( reqHandle ); + + /* Check for name long enough for header length calculation to overflow */ + HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( nameLen <= ( UINT32_MAX >> 2 ), + IOT_HTTPS_INVALID_PARAMETER, + "Attempting to generate headers with name length %d > %d. This is not allowed.", + nameLen, UINT32_MAX >> 2 ); + + /* Check for value long enough for header length calculation to overflow */ + HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( valueLen <= ( UINT32_MAX >> 2 ), + IOT_HTTPS_INVALID_PARAMETER, + "Attempting to generate headers with value length %d > %d. This is not allowed.", + valueLen, UINT32_MAX >> 2 ); + + /* Check for auto-generated header "Content-Length". This header is created and send automatically when right before + * request body is sent on the network. */ + HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( strncmp( pName, HTTPS_CONTENT_LENGTH_HEADER, FAST_MACRO_STRLEN( HTTPS_CONTENT_LENGTH_HEADER ) ) != 0, + IOT_HTTPS_INVALID_PARAMETER, + "Attempting to add auto-generated header %s. This is not allowed.", + HTTPS_CONTENT_LENGTH_HEADER ); + + /* Check for auto-generated header "Connection". This header is created and send automatically when right before + * request body is sent on the network. */ + HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( strncmp( pName, HTTPS_CONNECTION_HEADER, FAST_MACRO_STRLEN( HTTPS_CONNECTION_HEADER ) ) != 0, + IOT_HTTPS_INVALID_PARAMETER, + "Attempting to add auto-generated header %s. This is not allowed.", + HTTPS_CONNECTION_HEADER ); + + /* Check for auto-generated header "Host". This header is created and placed into the header buffer space + * in IotHttpsClient_InitializeRequest(). */ + HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( strncmp( pName, HTTPS_HOST_HEADER, FAST_MACRO_STRLEN( HTTPS_HOST_HEADER ) ) != 0, + IOT_HTTPS_INVALID_PARAMETER, + "Attempting to add auto-generated header %s. This is not allowed.", + HTTPS_HOST_HEADER ); + + /* Check for auto-generated header "User-Agent". This header is created and placed into the header buffer space + * in IotHttpsClient_InitializeRequest(). */ + HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( strncmp( pName, HTTPS_USER_AGENT_HEADER, FAST_MACRO_STRLEN( HTTPS_USER_AGENT_HEADER ) ) != 0, + IOT_HTTPS_INVALID_PARAMETER, + "Attempting to add auto-generated header %s. This is not allowed.", + HTTPS_USER_AGENT_HEADER ); + + + status = _addHeader( reqHandle, pName, nameLen, pValue, valueLen ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Error in IotHttpsClient_AddHeader(), error code %d.", status ); + HTTPS_GOTO_CLEANUP(); + } + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_SendSync( IotHttpsConnectionHandle_t connHandle, + IotHttpsRequestHandle_t reqHandle, + IotHttpsResponseHandle_t * pRespHandle, + IotHttpsResponseInfo_t * pRespInfo, + uint32_t timeoutMs ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + bool respFinishedSemCreated = false; + _httpsResponse_t * pHttpsResponse = NULL; + + /* Parameter checks. */ + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( connHandle ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( reqHandle ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pRespHandle ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pRespInfo ); + /* Stop the application from scheduling requests on a closed connection. */ + HTTPS_ON_ARG_ERROR_GOTO_CLEANUP( connHandle->isConnected ); + + /* If an asynchronous request/response is configured, that is invalid for this API. */ + if( reqHandle->isAsync ) + { + IotLogError( "Called IotHttpsClient_SendSync on an asynchronous configured request." ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_INVALID_PARAMETER ); + } + + /* Initialize the response handle to return. */ + status = _initializeResponse( pRespHandle, pRespInfo, reqHandle ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Failed to initialize the response on the synchronous request %d.", reqHandle ); + HTTPS_GOTO_CLEANUP(); + } + + /* Set the internal response to use. */ + pHttpsResponse = *pRespHandle; + + /* The implicit connection passed and we need to the set the connection handle in the request and response. */ + reqHandle->pHttpsConnection = connHandle; + pHttpsResponse->pHttpsConnection = connHandle; + + /* Create the semaphore used to wait on the response to finish being received. */ + respFinishedSemCreated = IotSemaphore_Create( &( pHttpsResponse->respFinishedSem ), 0 /* initialValue */, 1 /* maxValue */ ); + + if( respFinishedSemCreated == false ) + { + IotLogError( "Failed to create an internal semaphore." ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_INTERNAL_ERROR ); + } + + /* Associate the response to the request so that we can schedule it to be received when the request gets scheduled to send. */ + reqHandle->pHttpsResponse = pHttpsResponse; + + /* Schedule this request to be sent by adding it to the connection's request queue. */ + status = _addRequestToConnectionReqQ( reqHandle ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Failed to schedule the synchronous request. Error code: %d", status ); + HTTPS_GOTO_CLEANUP(); + } + + /* Wait for the request to finish. */ + if( timeoutMs == 0 ) + { + IotSemaphore_Wait( &( pHttpsResponse->respFinishedSem ) ); + } + else + { + if( IotSemaphore_TimedWait( &( pHttpsResponse->respFinishedSem ), timeoutMs ) == false ) + { + IotLogError( "Timed out waiting for the synchronous request to finish. Timeout ms: %d", timeoutMs ); + _cancelRequest( reqHandle ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_TIMEOUT_ERROR ); + } + } + + HTTPS_FUNCTION_CLEANUP_BEGIN(); + + if( respFinishedSemCreated ) + { + IotSemaphore_Destroy( &( pHttpsResponse->respFinishedSem ) ); + } + + /* If the syncStatus is anything other than IOT_HTTPS_OK, then the request was scheduled. */ + if( ( pHttpsResponse != NULL ) && HTTPS_FAILED( pHttpsResponse->syncStatus ) ) + { + status = pHttpsResponse->syncStatus; + } + + if( HTTPS_FAILED( status ) ) + { + if( pRespHandle != NULL ) + { + *pRespHandle = NULL; + } + + IotLogError( "IotHttpsClient_SendSync() failed." ); + } + + HTTPS_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_WriteRequestBody( IotHttpsRequestHandle_t reqHandle, + uint8_t * pBuf, + uint32_t len, + int isComplete ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( reqHandle ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pBuf ); + + /* This function is not valid for a synchronous response. Applications need to configure the request body in + * IotHttpsRequestInfo_t.pSyncInfo_t.reqData before calling IotHttpsClient_SendSync(). */ + HTTPS_ON_ARG_ERROR_GOTO_CLEANUP( reqHandle->isAsync ); + HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( isComplete == 1, + IOT_HTTPS_NOT_SUPPORTED, + "isComplete must be 1 in IotHttpsClient_WriteRequestBody() for the current version of the HTTPS Client library." ); + + /* If the bodyLength is greater than 0, then we already called this function and we need to enforce that this + * function must only be called once. We only call this function once so that we can calculate the Content-Length. */ + if( reqHandle->bodyLength > 0 ) + { + IotLogError( "Error this function must be called once with the data needed to send. Variable length HTTP " + "request body is not supported in this library." ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_MESSAGE_FINISHED ); + } + + /* Set the pointer to the body and the length for the content-length calculation. */ + reqHandle->pBody = ( uint8_t * ) pBuf; + reqHandle->bodyLength = len; + + /* We send the HTTPS headers and body in this function so that the application has the freedom to specify a body + * that may be buffer on stack. */ + status = _sendHttpsHeadersAndBody( reqHandle->pHttpsConnection, reqHandle ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Failed to send the headers and body. Error code %d.", status ); + HTTPS_GOTO_CLEANUP(); + } + + HTTPS_FUNCTION_CLEANUP_BEGIN(); + + if( reqHandle != NULL ) + { + reqHandle->bodyTxStatus = status; + } + + HTTPS_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_ReadResponseBody( IotHttpsResponseHandle_t respHandle, + uint8_t * pBuf, + uint32_t * pLen ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + uint32_t bodyLengthInHeaderBuf = 0; + + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( respHandle ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pBuf ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pLen ); + HTTPS_ON_ARG_ERROR_GOTO_CLEANUP( respHandle->isAsync ); + + /* Set the current body in the respHandle to use in _receiveHttpsBody(). _receiveHttpsBody is generic + * to both async and sync request/response handling. In the sync version the body is configured during + * initializing the request. In the async version the body is given in this function on the fly. */ + respHandle->pBody = pBuf; + respHandle->pBodyCur = respHandle->pBody; + respHandle->pBodyEnd = respHandle->pBodyCur + *pLen; + + /* When there is part of the body in the header pBuffer. We need to move that data to this body pBuffer + * provided in this function. */ + bodyLengthInHeaderBuf = respHandle->pBodyCurInHeaderBuf - respHandle->pBodyInHeaderBuf; + + if( bodyLengthInHeaderBuf > 0 ) + { + uint32_t copyLength = bodyLengthInHeaderBuf > *pLen ? *pLen : bodyLengthInHeaderBuf; + memcpy( respHandle->pBodyCur, respHandle->pBodyInHeaderBuf, copyLength ); + respHandle->pBodyCur += copyLength; + + /* This function may be called multiple times until all of the body that may be present in the header buffer is + * moved out. */ + respHandle->pBodyInHeaderBuf += copyLength; + } + + /* If there is room in the body buffer just provided by the application and we have not completed the current + * HTTP response message, then try to receive more body. */ + if( ( ( respHandle->pBodyEnd - respHandle->pBodyCur ) > 0 ) && ( respHandle->parserState < PARSER_STATE_BODY_COMPLETE ) ) + { + status = _receiveHttpsBody( respHandle->pHttpsConnection, respHandle ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Failed to receive the HTTP response body on the network. Error code: %d.", status ); + HTTPS_GOTO_CLEANUP(); + } + } + + *pLen = respHandle->pBodyCur - respHandle->pBody; + + HTTPS_FUNCTION_CLEANUP_BEGIN(); + + if( respHandle != NULL ) + { + respHandle->bodyRxStatus = status; + } + + HTTPS_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_CancelRequestAsync( IotHttpsRequestHandle_t reqHandle ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( reqHandle ); + + _cancelRequest( reqHandle ); + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_CancelResponseAsync( IotHttpsResponseHandle_t respHandle ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( respHandle ); + + _cancelResponse( respHandle ); + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_SendAsync( IotHttpsConnectionHandle_t connHandle, + IotHttpsRequestHandle_t reqHandle, + IotHttpsResponseHandle_t * pRespHandle, + IotHttpsResponseInfo_t * pRespInfo ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( connHandle ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( reqHandle ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pRespHandle ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pRespInfo ); + HTTPS_ON_ARG_ERROR_GOTO_CLEANUP( reqHandle->isAsync ); + /* Stop the application from scheduling requests on a closed connection. */ + HTTPS_ON_ARG_ERROR_GOTO_CLEANUP( connHandle->isConnected ); + + /* Initialize the response handle to return. */ + status = _initializeResponse( pRespHandle, pRespInfo, reqHandle ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Failed to initialize the response on the synchronous request %d.", reqHandle ); + HTTPS_GOTO_CLEANUP(); + } + + /* Set the connection handle in the request handle so that we can use it in the _writeRequestBody() callback. */ + reqHandle->pHttpsConnection = connHandle; + + /* Set the connection handle in the response handle sp that we can use it in the _readReadyCallback() callback. */ + ( *pRespHandle )->pHttpsConnection = connHandle; + + /* Associate the response to the request so that we can schedule it to be received when the request gets scheduled to send. */ + reqHandle->pHttpsResponse = *pRespHandle; + + /* Add the request to the connection's request queue. */ + status = _addRequestToConnectionReqQ( reqHandle ); + + if( HTTPS_FAILED( status ) ) + { + IotLogError( "Failed to add request %d to the connection's request queue. Error code: %d.", reqHandle, status ); + HTTPS_GOTO_CLEANUP(); + } + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_ReadResponseStatus( IotHttpsResponseHandle_t respHandle, + uint16_t * pStatus ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( respHandle ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pStatus ); + + HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( respHandle->status != 0, + IOT_HTTPS_NOT_FOUND, + "The HTTP response status was not found in the HTTP response header buffer." ); + + *pStatus = respHandle->status; + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_ReadHeader( IotHttpsResponseHandle_t respHandle, + char * pName, + uint32_t nameLen, + char * pValue, + uint32_t valueLen ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + const char * pHttpParserErrorDescription = NULL; + IotHttpsResponseBufferState_t savedBufferState = PROCESSING_STATE_NONE; + IotHttpsResponseParserState_t savedParserState = PARSER_STATE_NONE; + size_t numParsed = 0; + + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( respHandle ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pName ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pValue ); + HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( valueLen > 0, + IOT_HTTPS_INVALID_PARAMETER, + "pValue has insufficient space to store a value string (length is 0)" ); + + /* The buffer processing state is changed to searching the header buffer in this function. The parser state is + * changed in the response to wherever the parser is currently located in the response. If this function is called + * in the middle of processing a response (for example in readReadyCallback() routine of an asynchronous response), + * then parsing the response need to be able to start at the same place it was before calling this function. */ + savedBufferState = respHandle->bufferProcessingState; + savedParserState = respHandle->parserState; + + /* The header search parameters in the response handle are used as context in the http-parser callbacks. During + * the callback, pReadHeaderField is checked against the currently parsed header name. foundHeaderField is set to + * true when the pReadHeaderField is found in a header field callback. The bufferProcessingState tells the callback + * to skip the logic pertaining to when the response is being parsed for the first time. pReadHeaderValue will store + * the header value found. readHeaderValueLength will store the length of the header value found from within the + * response headers. */ + respHandle->pReadHeaderField = pName; + respHandle->readHeaderFieldLength = nameLen; + respHandle->foundHeaderField = false; + respHandle->bufferProcessingState = PROCESSING_STATE_SEARCHING_HEADER_BUFFER; + respHandle->pReadHeaderValue = NULL; + respHandle->readHeaderValueLength = 0; + + /* Start over the HTTP parser so that it will parser from the beginning of the message. */ + http_parser_init( &( respHandle->httpParserInfo.readHeaderParser ), HTTP_RESPONSE ); + + IotLogDebug( "Now parsing HTTP Message buffer to read a header." ); + numParsed = respHandle->httpParserInfo.parseFunc( &( respHandle->httpParserInfo.readHeaderParser ), &_httpParserSettings, ( char * ) ( respHandle->pHeaders ), respHandle->pHeadersCur - respHandle->pHeaders ); + IotLogDebug( "Parsed %d characters in IotHttpsClient_ReadHeader().", numParsed ); + + /* There shouldn't be any errors parsing the response body given that the handle is from a validly + * received response, so this check is defensive. If there were errors parsing the original response headers, then + * the response handle would have been invalidated and the connection closed. */ + if( ( respHandle->httpParserInfo.readHeaderParser.http_errno != 0 ) && + ( HTTP_PARSER_ERRNO( &( respHandle->httpParserInfo.readHeaderParser ) ) > HPE_CB_chunk_complete ) ) + { + pHttpParserErrorDescription = http_errno_description( HTTP_PARSER_ERRNO( &( respHandle->httpParserInfo.readHeaderParser ) ) ); + IotLogError( "http_parser failed on the http response with error: %s", pHttpParserErrorDescription ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_PARSING_ERROR ); + } + + /* Not only do we need an indication that the header field was found, but also that the value was found as well. + * The value is found when it is non-NULL. The case where the header field is found, but the value is not found + * occurs when there are incomplete headers stored in the header buffer. The header buffer could end with a header + * field name. */ + if( respHandle->foundHeaderField && ( respHandle->pReadHeaderValue != NULL ) ) + { + /* The len of the pValue buffer must account for the NULL terminator. */ + if( respHandle->readHeaderValueLength > ( valueLen - 1 ) ) + { + IotLogError( "IotHttpsClient_ReadHeader(): The length of the pValue buffer specified is less than the actual length of the pValue. " ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_INSUFFICIENT_MEMORY ); + } + else + { + memcpy( pValue, respHandle->pReadHeaderValue, respHandle->readHeaderValueLength ); + pValue[ respHandle->readHeaderValueLength ] = '\0'; + } + } + else + { + IotLogWarn( "IotHttpsClient_ReadHeader(): The header field %s was not found.", pName ); + HTTPS_SET_AND_GOTO_CLEANUP( IOT_HTTPS_NOT_FOUND ); + } + + HTTPS_FUNCTION_CLEANUP_BEGIN(); + + /* Always restore the state back to what it was before entering this function. */ + if( respHandle != NULL ) + { + respHandle->bufferProcessingState = savedBufferState; + respHandle->parserState = savedParserState; + } + + HTTPS_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_ReadContentLength( IotHttpsResponseHandle_t respHandle, + uint32_t * pContentLength ) +{ + HTTPS_FUNCTION_ENTRY( IOT_HTTPS_OK ); + + const int CONTENT_LENGTH_NUMBERIC_BASE = 10; + char pContentLengthStr[ HTTPS_MAX_CONTENT_LENGTH_LINE_LENGTH ] = { 0 }; + + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( respHandle ); + HTTPS_ON_NULL_ARG_GOTO_CLEANUP( pContentLength ); + + /* If there is no content-length header or if we were not able to store it in the header buffer this will be + * invalid. We do not use the content-length member of the http-parser state structure to get the content + * length as this is a PRIVATE member. Because it is a PRIVATE member it can be any value. */ + status = IotHttpsClient_ReadHeader( respHandle, HTTPS_CONTENT_LENGTH_HEADER, FAST_MACRO_STRLEN( HTTPS_CONTENT_LENGTH_HEADER ), pContentLengthStr, HTTPS_MAX_CONTENT_LENGTH_LINE_LENGTH ); + + if( HTTPS_FAILED( status ) ) + { + *pContentLength = 0; + IotLogError( "Could not read the Content-Length for the response." ); + HTTPS_GOTO_CLEANUP(); + } + + *pContentLength = strtoul( pContentLengthStr, NULL, CONTENT_LENGTH_NUMBERIC_BASE ); + + HTTPS_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +/* Provide access to internal functions and variables if testing. */ +#if IOT_BUILD_TESTS == 1 + #include "iot_test_access_https_client.c" +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/src/iot_https_utils.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/src/iot_https_utils.c new file mode 100644 index 000000000..b4b5a2119 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/src/iot_https_utils.c @@ -0,0 +1,137 @@ +/* + * Amazon FreeRTOS HTTPS Client V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/** + * @file iot_https_utils.c + * @brief Implements functions for HTTPS Client library utilities. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* iot_https_includes */ +#include "iot_https_utils.h" +#include "http_parser.h" +#include "private/iot_https_internal.h" + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_GetUrlPath( const char * pUrl, + size_t urlLen, + const char ** pPath, + size_t * pPathLen ) +{ + /* http-parser status. Initialized to 0 to signify success. */ + int parserStatus = 0; + struct http_parser_url urlParser; + IotHttpsReturnCode_t returnStatus = IOT_HTTPS_OK; + + /* Sets all members in urlParser to 0. */ + http_parser_url_init( &urlParser ); + + if( ( pUrl == NULL ) || ( pPath == NULL ) || ( pPathLen == NULL ) ) + { + IotLogError( "NULL parameter passed to IotHttpsClient_GetUrlPath()." ); + returnStatus = IOT_HTTPS_INVALID_PARAMETER; + } + + if( returnStatus == IOT_HTTPS_OK ) + { + parserStatus = http_parser_parse_url( pUrl, urlLen, 0, &urlParser ); + + if( parserStatus != 0 ) + { + IotLogError( "Error parsing the input URL %.*s. Error code: %d.", urlLen, pUrl, parserStatus ); + returnStatus = IOT_HTTPS_PARSING_ERROR; + } + } + + if( returnStatus == IOT_HTTPS_OK ) + { + *pPathLen = ( size_t ) ( urlParser.field_data[ UF_PATH ].len ); + + if( *pPathLen == 0 ) + { + returnStatus = IOT_HTTPS_NOT_FOUND; + *pPath = NULL; + } + else + { + *pPath = &pUrl[ urlParser.field_data[ UF_PATH ].off ]; + } + } + + return returnStatus; +} + +/*-----------------------------------------------------------*/ + +IotHttpsReturnCode_t IotHttpsClient_GetUrlAddress( const char * pUrl, + size_t urlLen, + const char ** pAddress, + size_t * pAddressLen ) +{ + /* http-parser status. Initialized to 0 to signify success. */ + int parserStatus = 0; + struct http_parser_url urlParser; + IotHttpsReturnCode_t returnStatus = IOT_HTTPS_OK; + + /* Sets all members in urlParser to 0. */ + http_parser_url_init( &urlParser ); + + if( ( pUrl == NULL ) || ( pAddress == NULL ) || ( pAddressLen == NULL ) ) + { + IotLogError( "NULL parameter passed to IotHttpsClient_GetUrlAddress()." ); + returnStatus = IOT_HTTPS_INVALID_PARAMETER; + } + + if( returnStatus == IOT_HTTPS_OK ) + { + parserStatus = http_parser_parse_url( pUrl, urlLen, 0, &urlParser ); + + if( parserStatus != 0 ) + { + IotLogError( "Error parsing the input URL %.*s. Error code: %d.", urlLen, pUrl, parserStatus ); + returnStatus = IOT_HTTPS_PARSING_ERROR; + } + } + + if( returnStatus == IOT_HTTPS_OK ) + { + *pAddressLen = ( size_t ) ( urlParser.field_data[ UF_HOST ].len ); + + if( *pAddressLen == 0 ) + { + returnStatus = IOT_HTTPS_NOT_FOUND; + *pAddress = NULL; + } + else + { + *pAddress = &pUrl[ urlParser.field_data[ UF_HOST ].off ]; + } + } + + return returnStatus; +} diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/src/private/iot_https_internal.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/src/private/iot_https_internal.h new file mode 100644 index 000000000..ff51d0bc3 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/https/src/private/iot_https_internal.h @@ -0,0 +1,497 @@ +/* + * Amazon FreeRTOS HTTPS Client V1.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef IOT_HTTPS_INTERNAL_H_ +#define IOT_HTTPS_INTERNAL_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard Includes. */ +#include +#include +#include +#include + +/* Third party http-parser include. */ +#include "http_parser.h" + +/* HTTPS Client library includes. */ +#include "iot_https_client.h" + +/* Task pool include. */ +#include "iot_taskpool_freertos.h" + +/* Linear containers (lists and queues) include. */ +#include "iot_linear_containers.h" + +/* Types include. */ +#include "types/iot_taskpool_types_freertos.h" + +/* Platform layer includes. */ +#include "platform/iot_threads.h" +#include "platform/iot_network.h" + +/* Error handling include. */ +#include "iot_error.h" + +/*-----------------------------------------------------------*/ + +/* Convenience macros for handling errors in a standard way. */ + +/** + * @brief Every public API return an enumeration value with an underlying value of 0 in case of success. + */ +#define HTTPS_SUCCEEDED( x ) ( ( x ) == IOT_HTTPS_OK ) + +/** + * @brief Every public API returns an enumeration value with an underlying value different than 0 in case of success. + */ +#define HTTPS_FAILED( x ) ( ( x ) != IOT_HTTPS_OK ) + +/** + * @brief Declare the storage for the error status variable. + */ +#define HTTPS_FUNCTION_ENTRY( result ) IOT_FUNCTION_ENTRY( IotHttpsReturnCode_t, result ) + +/** + * @brief Jump to the cleanup area. + */ +#define HTTPS_GOTO_CLEANUP() IOT_GOTO_CLEANUP() + +/** + * @brief Set error and leave. + */ +#define HTTPS_SET_AND_GOTO_CLEANUP( statusValue ) IOT_SET_AND_GOTO_CLEANUP( statusValue ) + +/** + * @brief Initialize error and declare start of cleanup area. + */ +#define HTTPS_FUNCTION_CLEANUP_BEGIN() IOT_FUNCTION_CLEANUP_BEGIN() + +/** + * @brief Initialize error and declare end of cleanup area. + */ +#define HTTPS_FUNCTION_CLEANUP_END() IOT_FUNCTION_CLEANUP_END() + +/** + * @brief Create an empty cleanup area. + */ +#define HTTPS_FUNCTION_EXIT_NO_CLEANUP() IOT_FUNCTION_EXIT_NO_CLEANUP() + +/** + * @brief Exit if an argument is NULL. + */ +#define HTTPS_ON_NULL_ARG_GOTO_CLEANUP( ptr ) \ + if( ( ptr == NULL ) ) \ + { \ + IotLogError( # ptr " was NULL." ); \ + IOT_SET_AND_GOTO_CLEANUP( IOT_HTTPS_INVALID_PARAMETER ); \ + } + +/** + * @brief Exit if an condition is false. + */ +#define HTTPS_ON_ARG_ERROR_GOTO_CLEANUP( expr ) \ + if( ( expr ) == false ) \ + { \ + IotLogError( # expr " must be true." ); \ + IOT_SET_AND_GOTO_CLEANUP( IOT_HTTPS_INVALID_PARAMETER ); \ + } + +/** + * @brief Exit if an argument is false with a message. + */ +#define HTTPS_ON_ARG_ERROR_MSG_GOTO_CLEANUP( expr, statusValue, ... ) \ + if( ( expr ) == false ) \ + { \ + IotLogError( __VA_ARGS__ ); \ + IOT_SET_AND_GOTO_CLEANUP( statusValue ); \ + } + +/* Configure logs for HTTPS Client functions. */ +#ifdef IOT_LOG_LEVEL_HTTPS + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_HTTPS +#else + #ifdef IOT_LOG_LEVEL_GLOBAL + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_GLOBAL + #else + #define LIBRARY_LOG_LEVEL IOT_LOG_NONE + #endif +#endif + +#define LIBRARY_LOG_NAME ( "HTTPS Client" ) +#include "iot_logging_setup.h" + +/* + * Provide default values for undefined memory allocation functions based on + * the usage of dynamic memory allocation. + */ +#if IOT_STATIC_MEMORY_ONLY == 1 + #include "iot_static_memory.h" +#endif + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * Provide default values for undefined configuration constants. + */ +#ifndef AWS_IOT_HTTPS_ENABLE_METRICS + #define AWS_IOT_HTTPS_ENABLE_METRICS ( 1 ) +#endif +#ifndef IOT_HTTPS_USER_AGENT + #define IOT_HTTPS_USER_AGENT "FreeRTOS" +#endif +#ifndef IOT_HTTPS_MAX_FLUSH_BUFFER_SIZE + #define IOT_HTTPS_MAX_FLUSH_BUFFER_SIZE ( 1024 ) +#endif +#ifndef IOT_HTTPS_RESPONSE_WAIT_MS + #define IOT_HTTPS_RESPONSE_WAIT_MS ( 1000 ) +#endif +#ifndef IOT_HTTPS_MAX_HOST_NAME_LENGTH + #define IOT_HTTPS_MAX_HOST_NAME_LENGTH ( 255 ) /* Per FQDN, the maximum host name length is 255 bytes. */ +#endif +#ifndef IOT_HTTPS_MAX_ALPN_PROTOCOLS_LENGTH + #define IOT_HTTPS_MAX_ALPN_PROTOCOLS_LENGTH ( 255 ) /* The maximum alpn protocols length is chosen arbitrarily. */ +#endif + +/** @endcond */ + +/** + * @brief The HTTP protocol version of this library is HTTP/1.1. + */ +#define HTTPS_PROTOCOL_VERSION "HTTP/1.1" + +/** + * @brief An empty path for a NULL specified path in the request initialization configuration. + */ +#define HTTPS_EMPTY_PATH "/" + +/** + * @brief HTTPS "CONNECT" method, defined as the longest string length method. + */ +#define HTTPS_CONNECT_METHOD "CONNECT" + +/* + * Constants for the values of the HTTP "Connection" header field. + * + * This is used for writing headers automatically during the sending of the HTTP request. + * "Connection: keep-alive\r\n" is written automatically for a persistent connection. + * "Connection: close\r\n" is written automatically for a non-persistent connection. + */ +#define HTTPS_CONNECTION_KEEP_ALIVE_HEADER_VALUE "keep-alive" +#define HTTPS_CONNECTION_CLOSE_HEADER_VALUE "close" + +/** + * Constants for HTTP header formatting. + * + * ": " separates and header field from the header value. + */ +#define HTTPS_HEADER_FIELD_SEPARATOR ": " +#define HTTPS_HEADER_FIELD_SEPARATOR_LENGTH ( 2 ) +#define COLON_CHARACTER ':' +#define SPACE_CHARACTER ' ' + +/** + * Constants for HTTP header formatting. + * + * "\r\n" Ends the header line. + */ +#define HTTPS_END_OF_HEADER_LINES_INDICATOR "\r\n" +#define HTTPS_END_OF_HEADER_LINES_INDICATOR_LENGTH ( 2 ) +#define CARRIAGE_RETURN_CHARACTER '\r' +#define NEWLINE_CHARACTER '\n' + +/* + * Constants for header fields added automatically during the request initialization. + */ +#define HTTPS_USER_AGENT_HEADER "User-Agent" +#define HTTPS_HOST_HEADER "Host" + +/* + * Constants for the header fields added automatically during the sending of the HTTP request. + */ +#define HTTPS_CONTENT_LENGTH_HEADER "Content-Length" +#define HTTPS_CONNECTION_HEADER "Connection" + +/** + * @brief The maximum Content-Length header line size. + * + * This is the length of header line string: "Content-Length: 4294967296\r\n". 4294967296 is 2^32. This number is chosen + * because it is the maximum file size that can be represented in a 32 bit system. + * + * This is used to initialize a local array for the final headers to send. + */ +#define HTTPS_MAX_CONTENT_LENGTH_LINE_LENGTH ( 26 ) + +/** + * @brief Macro for fast string length calculation of string macros. + * + * We subtract 1 to subtract the NULL terminating character. + * We do not assume that the size of a character is a single byte or 8 bits with this calculation. + */ +#define FAST_MACRO_STRLEN( x ) ( ( sizeof( x ) / sizeof( char ) ) - 1 ) + +/*-----------------------------------------------------------*/ + +/** + * @brief The state of the HTTP response parsing. + * + * This state notes what has been parsed in the HTTP response. As soon as any part of the HTTP response is received from + * the network, it is sent to be parsed. + * + * The states move as follows: + * PARSER_STATE_NONE --> PARSER_STATE_IN_HEADERS --> PARSER_STATE_HEADERS_COMPLETE --> PARSER_STATE_BODY_COMPLETE + * + * The parser callbacks are called in the following order: + * 1. _httpParserOnMessageBeginCallback() + * 2. _httpParserOnStatusCallback() + * 3. _httpParserOnHeaderFieldCallback() + * 4. _httpParserOnHeaderValueCallback() + * 5. _httpParserOnHeadersCompleteCallback() + * 6. _httpParserOnChunkHeaderCallback() (optional only if the response is chunked) + * 7. _httpParserOnBodyCallback() + * 8. _httpParserOnChunkCompleteCallback() (optional only if the response is chunked) + * 9. _httpParserOnMessageCompleteCallback() + * + * Theses states are set in the parser callbacks and used outside the callbacks to determine action. + * + * PARSER_STATE_NONE is assigned to #_httpsResponse_t.parserState when the _httpsResponse_t.parserState is initialized + * in @ref IotHttpsClient_InitializeRequest and before parsing a new respone message from the server. + * + * PARSER_STATE_IN_HEADERS is assigned at the start of the HTTP Response message. This occurs in the + * _httpParserOnMessageBeginCallback(). HTTP headers are always first and there is always the response status line + * and some headers in a response message according to RFC 2616. + * + * PARSER_STATE_HEADERS_COMPLETE is assigned when all of the headers are finished being parsed in the HTTP response + * message. This occurs in the _httpParserOnHeadersCompleteCallback(). The state can end here if the response has no + * body, like for a response to a HEAD request. + * If this state is not reached after receiving headers from the network into the user configured header buffer and + * running it through the parser, then we know that not all of the headers from the response could fit into the buffer. + * + * PARSER_STATE_IN_BODY is assigned each time the parser reaches HTTP response body. This occurs in the + * _httpParserOnBodyCallback(). + * + * PARSER_STATE_BODY_COMPLETE is assigned when the parser has finished with the whole HTTP response message. This + * happens when _httpParserOnMessageCompleteCallback() is invoked. + * If this state is not reached after receiving body from the network into the user configured body buffer and + * running it through the parser, then we know that not all of the body from the response could fit into the buffer. + */ +typedef enum IotHttpsResponseParserState +{ + PARSER_STATE_NONE = 0, /**< @brief The parser has not started so we are neither in the headers or the body. */ + PARSER_STATE_IN_HEADERS, /**< @brief The parser is currently parsing the HTTP respone headers. */ + PARSER_STATE_HEADERS_COMPLETE, /**< @brief The parser has finished parsing the headers. */ + PARSER_STATE_IN_BODY, /**< @brief The parser is currently parsing the HTTP response body. */ + PARSER_STATE_BODY_COMPLETE /**< @brief The parser has completed parsing the HTTP response body. */ +} IotHttpsResponseParserState_t; + +/** + * @brief The state denoting which buffer (the header buffer or the body buffer) is currently being processed + * and for what. + * + * This state is set outside of the parser callbacks and used inside the of parser callbacks to determine actions. + * + * The state moves as follows: + * Receiving and parsing a response: PROCESSING_STATE_NONE --> PROCESSING_STATE_FILLING_HEADER_BUFFER --> PROCESSING_STATE_FILLING_BODY_BUFFER --> PROCESSING_STATE_FINISHED + * Searching a response for headers: ((enter state)) --> PROCESSING_STATE_SEARCHING_HEADER_BUFFER --> ((enter state)) + * + * PROCESSING_STATE_NONE is assigned when #_httpsResponse_t.bufferProcessingState is initialized in + * @ref IotHttpsClient_InitializeRequest. + * + * PROCESSING_STATE_FILLING_HEADER_BUFFER is assigned at the start of receiving HTTP response headers from the network + * into the header buffer, before processing the received headers with the parser. + * This state is then used in the parser callbacks _httpParserOnStatusCallback(), _httpParserOnHeaderFieldCallback(), + * _httpParserOnHeaderValueCallback(), and _httpParserOnHeadersCompleteCallback() to move the + * #_httpsResponse_t.headersCur pointer along in the header buffer. + * Since the server sends the HTTP response as a single continuous message, sometimes during receiving of the HTTP + * headers we may receive part or all of the HTTP response body: + * ((example header buffer))[headers headers headers headers body body body] + * When parsing this header buffer the parser will execute _httpParserOnBodyCallback() in the + * PROCESSING_STATE_FILLING_HEADER_BUFFER state. The state is used here, for an asynchronous response, to save where + * and how much body is inside the of the header buffer. When a body buffer becomes available, the body in the header + * buffer will be copied to the body buffer. + * + * PROCESSING_STATE_FILLING_BODY_BUFFER is assigned at the start of receiving the HTTP response body form the network + * into the body buffer, before processing the received body with the parser. + * + * PROCESSING_STATE_FINISHED is assigned at the end of IotHttpsClient_SendSync() or at the end of + * IotHttpsClient_SendAsync() when both the header and body buffer are finished being filled with network data and + * parsed. + * + * PROCESSING_STATE_SEARCHING_HEADER_BUFFER is assigned in IotHttpsClient_ReadHeader() when searching for a header + * in the header buffer. + * This state is used in the parser callback _httpParserOnHeaderFieldCallback() to check if the current header field + * parsed equals the header we are searching for. It is used in parser callback _httpParserOnHeaderValueCallback() to + * return the header value if the corresponding field we are searching for was found. It is used in parser callback + * _httpParserOnHeadersCompleteCallback() to stop parsing the header buffer if the header we are searching for was not + * found. + * + * The header buffer is separate from the body buffer. + * The header buffer is configured in #IotHttpRequestInfo_t.respUserBuff. The body buffer is configured in + * #IotHttpRequestInfo_t.syncInfo->respData or as buffer provided asynchronously during the + * #IotHttpsClientCallbacks_t.readReadyCallback() to call to @ref IotHttpsClient_ReadResponseBody(). + */ +typedef enum IotHttpsResponseBufferState +{ + PROCESSING_STATE_NONE, /**< @brief There is no buffer processing currently. */ + PROCESSING_STATE_FILLING_HEADER_BUFFER, /**< @brief The header buffer is being filled and parsed. */ + PROCESSING_STATE_FILLING_BODY_BUFFER, /**< @brief The body buffer is being filled and parsed. */ + PROCESSING_STATE_FINISHED, /**< @brief Filling and parsing of both buffers is finished. */ + PROCESSING_STATE_SEARCHING_HEADER_BUFFER /**< @brief The header buffer is being searched. */ +} IotHttpsResponseBufferState_t; + +/*-----------------------------------------------------------*/ + +/** + * @brief Represents an HTTP connection. + */ +typedef struct _httpsConnection +{ + const IotNetworkInterface_t * pNetworkInterface; /**< @brief Network interface with calls for connect, disconnect, send, and receive. */ + IotNetworkConnection_t pNetworkConnection; /**< @brief Pointer to the network connection to use pNetworkInterface calls on. */ + uint32_t timeout; /**< @brief Timeout for a connection and waiting for a response from the network. */ + + /** + * @brief true if a connection was successful most recently on this context + * + * We have no way of knowing if the server closed the connection because that error is unique to the underlying TLS + * layer. This is set to false initially, then set to true for a successful intentional call to connect. + * Post connection, this is set to false only after an implicit disconnect with a non-persistent request, an implicit + * disconnect with a network error, or an explicit disconnect with a call to @ref https_client_function_disconnect. + */ + bool isConnected; + bool isDestroyed; /**< @brief true if the connection is already destroyed and we should call anymore */ + IotMutex_t connectionMutex; /**< @brief Mutex protecting operations on this entire connection context. */ + IotDeQueue_t reqQ; /**< @brief The queue for the requests that are not finished yet. */ + IotDeQueue_t respQ; /**< @brief The queue for the responses that are waiting to be processed. */ + IotTaskPoolJobStorage_t taskPoolJobStorage; /**< @brief An asynchronous operation requires storage for the task pool job. */ + IotTaskPoolJob_t taskPoolJob; /**< @brief The task pool job identifier for an asynchronous request. */ +} _httpsConnection_t; + +/** + * @brief Third party library http-parser information. + * + * There are two separate structures for http_parser state information. This is so that the application can read + * a header during it's readReadyCallback. The readReadyCallback could be invoked many times and the parser will + * therefore be invoked many times for each response read from the network. In order to ensure that the state of + * the parser remains intact whilst headers may be read, two structures holding the state are kept. + */ +typedef struct _httpParserInfo +{ + http_parser responseParser; /**< @brief http_parser state information for parsing the response. */ + size_t ( * parseFunc )( http_parser * parser, + const http_parser_settings * settings, + const char * data, + size_t len ); /**< @brief http_parser_execute function is to be plugged in here during initialization of the response. */ + http_parser readHeaderParser; /**< @brief http_parser state information for parsing the header buffer for reading a header. */ +} _httpParserInfo_t; + +/** + * @brief Represents an HTTP response. + */ +typedef struct _httpsResponse +{ + IotLink_t link; /**< @brief The link to insert the job in the connection's respQ. */ + uint8_t * pHeaders; /**< @brief Pointer to the start of the headers buffer. */ + uint8_t * pHeadersEnd; /**< @brief Pointer to the end of the headers buffer. */ + uint8_t * pHeadersCur; /**< @brief Pointer to the next location to write in the headers buffer. */ + uint8_t * pBody; /**< @brief Pointer to the start of the body buffer. */ + uint8_t * pBodyEnd; /**< @brief Pointer to the end of the body buffer. */ + uint8_t * pBodyCur; /**< @brief Pointer to the next location to write in the body buffer. */ + _httpParserInfo_t httpParserInfo; /**< @brief Third party http-parser information. */ + uint16_t status; /**< @brief The HTTP response status code of this response. */ + IotHttpsMethod_t method; /**< @brief The method of the originating request. */ + IotHttpsResponseParserState_t parserState; /**< @brief The current state of the parser. See IotHttpsResponseParserState_t documentation for more details. */ + IotHttpsResponseBufferState_t bufferProcessingState; /**< @brief Which buffer is currently being processed and for what. See IotHttpsResponseBufferState_t documentation. */ + char * pReadHeaderField; /**< @brief Header field that we want to read from the headers buffer when IotHttpsClient_ReadHeader() is called. */ + size_t readHeaderFieldLength; /**< @brief Length of pReadHeaderField */ + char * pReadHeaderValue; /**< @brief Header value that we read from the headers buffer when IotHttpsClient_ReadHeader() is called. */ + size_t readHeaderValueLength; /**< @brief Length of pReadHeaderValue. */ + bool foundHeaderField; /**< @brief State to use during parsing to let us know when we found the header field in the https-parser callbacks. + * This is set to true when the header field is found in parser callback _httpParserOnHeaderFieldCallback(). + * On the following parser callback _httpParserOnHeaderValueCallback() we will store the value in pReadHeaderValue and then exit the parsing. */ + struct _httpsConnection * pHttpsConnection; /**< @brief Connection associated with response. This is set during IotHttpsClient_SendAsync(). This is needed during the asynchronous workflow to receive data given the respHandle only in the callback. */ + bool isAsync; /**< @brief This is set to true if this response is to be retrieved asynchronously. Set to false otherwise. */ + uint8_t * pBodyInHeaderBuf; /**< @brief Pointer to the start of body inside the header buffer for copying to a body buffer provided later by the asynchronous response process. */ + uint8_t * pBodyCurInHeaderBuf; /**< @brief Pointer to the next location to write body data during processing of the header buffer. This is necessary in case there is a chunk encoded HTTP response. */ + IotHttpsReturnCode_t bodyRxStatus; /**< @brief The status of network receiving the HTTPS body to be returned during the #IotHttpsClientCallbacks_t.readReadyCallback. */ + bool cancelled; /**< @brief This is set to true to stop the request/response processing in the asynchronous request workflow. */ + IotSemaphore_t respFinishedSem; /**< @brief This is for synchronous response to post that is finished being received. It is better to use a task event signal, but that is not implemented yet in the iot_threads.h API. */ + IotHttpsReturnCode_t syncStatus; /**< @brief The status of the synchronous response. */ + + /** + * @brief This is set to true to when the request is finished being sent on the network + * + * A request is not shared with multiple tasks, so only one task will update this. This is to let the let the + * network receive callback know that the request is fully pushed out to the server. This is also to let the + * disconnect know that the request is not using the network interface resources anymore. + */ + bool reqFinishedSending; + IotHttpsClientCallbacks_t * pCallbacks; /**< @brief Pointer to the asynchronous request callbacks. */ + void * pUserPrivData; /**< @brief User private data to hand back in the asynchronous callbacks for context. */ + bool isNonPersistent; /**< @brief Non-persistent flag to indicate closing the connection immediately after receiving the response. */ +} _httpsResponse_t; + +/** + * @brief Represents and HTTP request. + */ +typedef struct _httpsRequest +{ + IotLink_t link; /**< @brief The link to insert the job in the connection's reqQ. */ + uint8_t * pHeaders; /**< @brief Pointer to the start of the headers buffer. */ + uint8_t * pHeadersEnd; /**< @brief Pointer to the end of the headers buffer. */ + uint8_t * pHeadersCur; /**< @brief Pointer to the next location to write in the headers buffer. */ + uint8_t * pBody; /**< @brief Pointer to the start of the body buffer. */ + uint32_t bodyLength; /**< @brief Length of request body buffer. */ + IotHttpsMethod_t method; /**< @brief The method of the originating request. */ + IotHttpsConnectionInfo_t * pConnInfo; /**< @brief Connection info associated with this request. For an implicit connection. */ + struct _httpsResponse * pHttpsResponse; /**< @brief Response associated with request. This is initialized during IotHttpsClient_InitializeRequest(), then returned to the application in IotHttpsClient_SendAsync() and IotHttpsClient_SendSync(). */ + struct _httpsConnection * pHttpsConnection; /**< @brief Connection associated with request. This is set during IotHttpsClient_SendAsync(). It is needed for the asynchronous workflow to use to send data given the reqHandle only in the callback. */ + bool isNonPersistent; /**< @brief Non-persistent flag to indicate closing the connection immediately after receiving the response. */ + bool isAsync; /**< @brief This is set to true if this request is to be sent asynchronously. Set to false otherwise. */ + void * pUserPrivData; /**< @brief User private data to hand back in the asynchronous callbacks for context. */ + IotHttpsClientCallbacks_t * pCallbacks; /**< @brief Pointer to the asynchronous request callbacks. */ + bool cancelled; /**< @brief Set this to true to stop the response processing in the asynchronous workflow. */ + IotHttpsReturnCode_t bodyTxStatus; /**< @brief The status of network sending the HTTPS body to be returned during the #IotHttpsClientCallbacks_t.writeCallback. */ + bool scheduled; /**< @brief Set to true when this request has already been scheduled to the task pool. */ +} _httpsRequest_t; + +/*-----------------------------------------------------------*/ + +/** + * @brief A map of the method enum to strings + * + * These are in order to the HTTP request method enums defined in IotHttpsMethod_t. + */ +static const char * _pHttpsMethodStrings[] = { + "GET", + "HEAD", + "PUT", + "POST" +}; + +#endif /* IOT_HTTPS_INTERNAL_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/include/iot_mqtt.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/include/iot_mqtt.h new file mode 100644 index 000000000..f266f546b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/include/iot_mqtt.h @@ -0,0 +1,859 @@ +/* + * IoT MQTT V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_mqtt.h + * @brief User-facing functions of the MQTT 3.1.1 library. + */ + +#ifndef IOT_MQTT_H_ +#define IOT_MQTT_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* MQTT types include. */ +#include "types/iot_mqtt_types.h" + +/*------------------------- MQTT library functions --------------------------*/ + +/** + * @functionspage{mqtt,MQTT library} + * - @functionname{mqtt_function_init} + * - @functionname{mqtt_function_cleanup} + * - @functionname{mqtt_function_receivecallback} + * - @functionname{mqtt_function_connect} + * - @functionname{mqtt_function_disconnect} + * - @functionname{mqtt_function_subscribeasync} + * - @functionname{mqtt_function_subscribesync} + * - @functionname{mqtt_function_unsubscribeasync} + * - @functionname{mqtt_function_unsubscribesync} + * - @functionname{mqtt_function_publishasync} + * - @functionname{mqtt_function_publishsync} + * - @functionname{mqtt_function_wait} + * - @functionname{mqtt_function_strerror} + * - @functionname{mqtt_function_operationtype} + * - @functionname{mqtt_function_issubscribed} + */ + +/** + * @functionpage{IotMqtt_Init,mqtt,init} + * @functionpage{IotMqtt_Cleanup,mqtt,cleanup} + * @functionpage{IotMqtt_ReceiveCallback,mqtt,receivecallback} + * @functionpage{IotMqtt_Connect,mqtt,connect} + * @functionpage{IotMqtt_Disconnect,mqtt,disconnect} + * @functionpage{IotMqtt_SubscribeAsync,mqtt,subscribeasync} + * @functionpage{IotMqtt_SubscribeSync,mqtt,subscribesync} + * @functionpage{IotMqtt_UnsubscribeAsync,mqtt,unsubscribeasync} + * @functionpage{IotMqtt_UnsubscribeSync,mqtt,unsubscribesync} + * @functionpage{IotMqtt_PublishAsync,mqtt,publishasync} + * @functionpage{IotMqtt_PublishSync,mqtt,publishsync} + * @functionpage{IotMqtt_Wait,mqtt,wait} + * @functionpage{IotMqtt_strerror,mqtt,strerror} + * @functionpage{IotMqtt_OperationType,mqtt,operationtype} + * @functionpage{IotMqtt_IsSubscribed,mqtt,issubscribed} + */ + +/** + * @brief One-time initialization function for the MQTT library. + * + * This function performs setup of the MQTT library. It must be called + * once (and only once) before calling any other MQTT function. Calling this + * function more than once without first calling @ref mqtt_function_cleanup + * may result in a crash. + * + * @return One of the following: + * - #IOT_MQTT_SUCCESS + * - #IOT_MQTT_NOT_INITIALIZED + * + * @warning No thread-safety guarantees are provided for this function. + * + * @see @ref mqtt_function_cleanup + */ +/* @[declare_mqtt_init] */ +IotMqttError_t IotMqtt_Init( void ); +/* @[declare_mqtt_init] */ + +/** + * @brief One-time deinitialization function for the MQTT library. + * + * This function frees resources taken in @ref mqtt_function_init. It should be + * called after [closing all MQTT connections](@ref mqtt_function_disconnect) to + * clean up the MQTT library. After this function returns, @ref mqtt_function_init + * must be called again before calling any other MQTT function. + * + * @warning No thread-safety guarantees are provided for this function. Do not + * call this function if any MQTT connections are open! + * + * @see @ref mqtt_function_init + */ +/* @[declare_mqtt_cleanup] */ +void IotMqtt_Cleanup( void ); +/* @[declare_mqtt_cleanup] */ + +/** + * @brief Network receive callback for the MQTT library. + * + * This function should be called by the system whenever data is available for + * the MQTT library. + * + * @param[in] pNetworkConnection The network connection associated with the MQTT + * connection, passed by the network stack. + * @param[in] pReceiveContext A pointer to the MQTT connection handle for which + * the packet was received. + */ +/* @[declare_mqtt_receivecallback] */ +void IotMqtt_ReceiveCallback( IotNetworkConnection_t pNetworkConnection, + void * pReceiveContext ); +/* @[declare_mqtt_receivecallback] */ + +/** + * @brief Establish a new MQTT connection. + * + * This function opens a connection between a new MQTT client and an MQTT server + * (also called a broker). MQTT connections are established on top of transport + * layer protocols (such as TCP/IP), and optionally, application layer security + * protocols (such as TLS). The MQTT packet that establishes a connection is called + * the MQTT CONNECT packet. After @ref mqtt_function_init, this function must be + * called before any other MQTT library function. + * + * If [pConnectInfo->cleanSession](@ref IotMqttConnectInfo_t.cleanSession) is `true`, + * this function establishes a clean MQTT session. Subscriptions and unacknowledged + * PUBLISH messages will be discarded when the connection is closed. + * + * If [pConnectInfo->cleanSession](@ref IotMqttConnectInfo_t.cleanSession) is `false`, + * this function establishes (or re-establishes) a persistent MQTT session. The parameters + * [pConnectInfo->pPreviousSubscriptions](@ref IotMqttConnectInfo_t.pPreviousSubscriptions) + * and [pConnectInfo->previousSubscriptionCount](@ref IotMqttConnectInfo_t.previousSubscriptionCount) + * may be used to restore subscriptions present in a re-established persistent session. + * Any restored subscriptions MUST have been present in the persistent session; + * this function does not send an MQTT SUBSCRIBE packet! + * + * [pConnectInfo->pPreviousSubscriptions](@ref IotMqttConnectInfo_t.pPreviousSubscriptions) + * and [pConnectInfo->previousSubscriptionCount](@ref IotMqttConnectInfo_t.previousSubscriptionCount) can + * also be used to pass a list of subscriptions to be stored locally without a SUBSCRIBE packet being + * sent to the broker. These subscriptions are useful to invoke application level callbacks for messages received + * on unsolicited topics from the broker. + * + * This MQTT library is network agnostic, meaning it has no knowledge of the + * underlying network protocol carrying the MQTT packets. It interacts with the + * network through a network abstraction layer, allowing it to be used with many + * different network stacks. The network abstraction layer is established + * per-connection, allowing every #IotMqttConnection_t to use a different network + * stack. The parameter `pNetworkInterface` sets up the network abstraction layer + * for an MQTT connection; see the documentation on #IotMqttNetworkInfo_t for details + * on its members. + * + * The `pConnectInfo` parameter provides the contents of the MQTT CONNECT packet. + * Most members [are defined by the MQTT spec.](@ref IotMqttConnectInfo_t). The + * [pConnectInfo->pWillInfo](@ref IotMqttConnectInfo_t.pWillInfo) member provides + * information on a Last Will and Testament (LWT) message to be published if the + * MQTT connection is closed without [sending a DISCONNECT packet] + * (@ref mqtt_function_disconnect). Unlike other PUBLISH + * messages, a LWT message payload is limited to 65535 bytes in length. Additionally, + * the retry [interval](@ref IotMqttPublishInfo_t.retryMs) and [limit] + * (@ref IotMqttPublishInfo_t.retryLimit) members of #IotMqttPublishInfo_t + * are ignored for LWT messages. The LWT message is optional; `pWillInfo` may be NULL. + * + * Unlike @ref mqtt_function_publishasync, @ref mqtt_function_subscribeasync, and + * @ref mqtt_function_unsubscribeasync, this function is always blocking. Additionally, + * because the MQTT connection acknowledgement packet (CONNACK packet) does not + * contain any information on which CONNECT packet it acknowledges, only one + * CONNECT operation may be in progress at any time. This means that parallel + * threads making calls to @ref mqtt_function_connect will be serialized to send + * their CONNECT packets one-by-one. + * + * @param[in] pNetworkInfo Information on the transport-layer network connection + * to use with the MQTT connection. + * @param[in] pConnectInfo MQTT connection setup parameters. + * @param[in] timeoutMs If the MQTT server does not accept the connection within + * this timeout in milliseconds, this function returns #IOT_MQTT_TIMEOUT. + * @param[out] pMqttConnection Set to a newly-initialized MQTT connection handle + * if this function succeeds. + * + * @return One of the following: + * - #IOT_MQTT_SUCCESS + * - #IOT_MQTT_NOT_INITIALIZED + * - #IOT_MQTT_BAD_PARAMETER + * - #IOT_MQTT_NO_MEMORY + * - #IOT_MQTT_NETWORK_ERROR + * - #IOT_MQTT_SCHEDULING_ERROR + * - #IOT_MQTT_BAD_RESPONSE + * - #IOT_MQTT_TIMEOUT + * - #IOT_MQTT_SERVER_REFUSED + * + * Example + * @code{c} + * + * // Callback function to receive messages from the broker on an unsolicited topic. + * void unsolicitedMessageCallback( void * pArgument, IotMqttCallbackParam_t * pPublish ); + * + * // Parameters to MQTT connect. + * IotMqttConnection_t mqttConnection = IOT_MQTT_CONNECTION_INITIALIZER; + * IotMqttNetworkInfo_t networkInfo = IOT_MQTT_NETWORK_INFO_INITIALIZER; + * IotMqttConnectInfo_t connectInfo = IOT_MQTT_CONNECT_INFO_INITIALIZER; + * IotMqttPublishInfo_t willInfo = IOT_MQTT_PUBLISH_INFO_INITIALIZER; + * + * // A local subscription to receive messages from the broker on an unsolicited topic. + * IotMqttSubscription_t subscription = IOT_MQTT_SUBSCRIPTION_INITIALIZER; + * + * // Example network abstraction types. + * IotNetworkServerInfo_t serverInfo = { ... }; + * IotNetworkCredentials_t credentialInfo = { ... }; + * IotNetworkInterface_t networkInterface = { ... }; + * + * // Example using a generic network implementation. + * networkInfo.createNetworkConnection = true; + * networkInfo.u.setup.pNetworkServerInfo = &serverInfo; + * networkInfo.u.setup.pNetworkCredentialInfo = &credentialInfo; + * networkInfo.pNetworkInterface = &networkInterface; + * + * // Set the members of the connection info (password and username not used). + * connectInfo.cleanSession = true; + * connectInfo.keepAliveSeconds = 30; + * connectInfo.pClientIdentifier = "uniqueclientidentifier"; + * connectInfo.clientIdentifierLength = 22; + * + * // Set the members of the will info (retain and retry not used). + * willInfo.qos = IOT_MQTT_QOS_1; + * willInfo.pTopicName = "will/topic/name"; + * willInfo.topicNameLength = ( uint16_t ) strlen( willInfo.pTopicName ); + * willInfo.pPayload = "MQTT client unexpectedly disconnected."; + * willInfo.payloadLength = strlen( willInfo.pPayload ); + * + * // Set the pointer to the will info. + * connectInfo.pWillInfo = &willInfo; + * + * // [Optional] Set a local subscription to receive the broker messages on an unsolicited topic. + * subscription.qos = IOT_MQTT_QOS_0; + * subscription.pTopicFilter = "some/unsolicited/topic"; + * subscription.topicLength = ( uint16_t ) strlen( subscription.pTopicFilter ); + * subscription.callback.function = unsolicitedMessageCallback; + * connectInfo.pPreviousSubscriptions = &subscription; + * connectInfo.previousSubscriptionCount = 1; + * + * + * // Call CONNECT with a 5 second block time. Should return + * // IOT_MQTT_SUCCESS when successful. + * IotMqttError_t result = IotMqtt_Connect( &networkInfo, + * &connectInfo, + * 5000, + * &mqttConnection ); + * + * if( result == IOT_MQTT_SUCCESS ) + * { + * // Do something with the MQTT connection... + * + * // Clean up and close the MQTT connection once it's no longer needed. + * IotMqtt_Disconnect( mqttConnection, 0 ); + * } + * @endcode + */ +/* @[declare_mqtt_connect] */ +IotMqttError_t IotMqtt_Connect( const IotMqttNetworkInfo_t * pNetworkInfo, + const IotMqttConnectInfo_t * pConnectInfo, + uint32_t timeoutMs, + IotMqttConnection_t * const pMqttConnection ); +/* @[declare_mqtt_connect] */ + +/** + * @brief Closes an MQTT connection and frees resources. + * + * This function closes an MQTT connection and should only be called once + * the MQTT connection is no longer needed. Its exact behavior depends on the + * `flags` parameter. + * + * Normally, `flags` should be `0`. This gracefully shuts down an MQTT + * connection by sending an MQTT DISCONNECT packet. Any [network close function] + * (@ref IotNetworkInterface_t::close) provided [when the connection was established] + * (@ref mqtt_function_connect) will also be called. Note that because the MQTT server + * will not acknowledge a DISCONNECT packet, the client has no way of knowing if + * the server received the DISCONNECT packet. In the case where the DISCONNECT + * packet is lost in transport, any Last Will and Testament (LWT) message established + * with the connection may be published. However, if the DISCONNECT reaches the + * MQTT server, the LWT message will be discarded and not published. + * + * Should the underlying network connection become unusable, this function should + * be called with `flags` set to #IOT_MQTT_FLAG_CLEANUP_ONLY. In this case, no + * DISCONNECT packet will be sent, though the [network close function](@ref IotNetworkInterface_t::close) + * will still be called. This function will only free the resources used by the MQTT + * connection; it still must be called even if the network is offline to avoid leaking + * resources. + * + * @ref mqtt_function_disconnect modifies `mqttConnection`, so it shouldn't + * be used after calling this function. + * + * @param[in] mqttConnection The MQTT connection to close and clean up. + * @param[in] flags Flags which modify the behavior of this function. See @ref mqtt_constants_flags. + */ +/* @[declare_mqtt_disconnect] */ +void IotMqtt_Disconnect( IotMqttConnection_t mqttConnection, + uint32_t flags ); +/* @[declare_mqtt_disconnect] */ + +/** + * @brief Subscribes to the given array of topic filters and optionally + * receive an asynchronous notification when the subscribe completes. + * + * This function sends an MQTT SUBSCRIBE packet to the server. A SUBSCRIBE + * packet notifies the server to send any matching PUBLISH messages to this client. + * A single SUBSCRIBE packet may carry more than one topic filter, hence the + * parameters to this function include an array of [subscriptions] + * (@ref IotMqttSubscription_t). + * + * An MQTT subscription has two pieces: + * 1. The subscription topic filter registered with the MQTT server. The MQTT + * SUBSCRIBE packet sent from this client to server notifies the server to send + * messages matching the given topic filters to this client. + * 2. The [callback function](@ref IotMqttCallbackInfo_t.function) that this + * client will invoke when an incoming message is received. The callback function + * notifies applications of an incoming PUBLISH message. + * + * The helper function @ref mqtt_function_issubscribed can be used to check if a + * [callback function](@ref IotMqttCallbackInfo_t.function) is registered for + * a particular topic filter. + * + * To modify an already-registered subscription callback, call this function with + * a new `pSubscriptionList`. Any topic filters in `pSubscriptionList` that already + * have a registered callback will be replaced with the new values in `pSubscriptionList`. + * + * @attention QoS 2 subscriptions are currently unsupported. Only 0 or 1 are valid + * for subscription QoS. + * + * @param[in] mqttConnection The MQTT connection to use for the subscription. + * @param[in] pSubscriptionList Pointer to the first element in the array of + * subscriptions. + * @param[in] subscriptionCount The number of elements in pSubscriptionList. + * @param[in] flags Flags which modify the behavior of this function. See @ref mqtt_constants_flags. + * @param[in] pCallbackInfo Asynchronous notification of this function's completion (`NULL` to disable). + * @param[out] pSubscribeOperation Set to a handle by which this operation may be + * referenced after this function returns. This reference is invalidated once + * the subscription operation completes. + * + * @return This function will return #IOT_MQTT_STATUS_PENDING upon success. + * @return Upon completion of the subscription (either through an + * #IotMqttCallbackInfo_t or @ref mqtt_function_wait), the status will be one of: + * - #IOT_MQTT_SUCCESS + * - #IOT_MQTT_NETWORK_ERROR + * - #IOT_MQTT_SCHEDULING_ERROR + * - #IOT_MQTT_BAD_RESPONSE + * - #IOT_MQTT_SERVER_REFUSED + * @return If this function fails before queuing a subscribe operation, it will return + * one of: + * - #IOT_MQTT_NOT_INITIALIZED + * - #IOT_MQTT_BAD_PARAMETER + * - #IOT_MQTT_NO_MEMORY + * + * @see @ref mqtt_function_subscribesync for a blocking variant of this function. + * @see @ref mqtt_function_unsubscribeasync for the function that removes subscriptions. + * + * Example + * @code{c} + * #define NUMBER_OF_SUBSCRIPTIONS ... + * + * // Subscription callback function. + * void subscriptionCallback( void * pArgument, IotMqttCallbackParam_t * pPublish ); + * + * // An initialized and connected MQTT connection. + * IotMqttConnection_t mqttConnection; + * + * // Subscription information. + * pSubscriptions[ NUMBER_OF_SUBSCRIPTIONS ] = { IOT_MQTT_SUBSCRIPTION_INITIALIZER }; + * IotMqttOperation_t lastOperation = IOT_MQTT_OPERATION_INITIALIZER; + * + * // Set the subscription information. + * for( int i = 0; i < NUMBER_OF_SUBSCRIPTIONS; i++ ) + * { + * pSubscriptions[ i ].qos = IOT_MQTT_QOS_1; + * pSubscriptions[ i ].pTopicFilter = "some/topic/filter"; + * pSubscriptions[ i ].topicLength = ( uint16_t ) strlen( pSubscriptions[ i ].pTopicFilter ); + * pSubscriptions[ i ].callback.function = subscriptionCallback; + * } + * + * IotMqttError_t result = IotMqtt_SubscribeAsync( mqttConnection, + * pSubscriptions, + * NUMBER_OF_SUBSCRIPTIONS, + * IOT_MQTT_FLAG_WAITABLE, + * NULL, + * &lastOperation ); + * + * // Subscribe returns IOT_MQTT_STATUS_PENDING when successful. Wait up to + * // 5 seconds for the operation to complete. + * if( result == IOT_MQTT_STATUS_PENDING ) + * { + * result = IotMqtt_Wait( subscriptionRef, 5000 ); + * } + * + * // Check that the subscriptions were successful. + * if( result == IOT_MQTT_SUCCESS ) + * { + * // Wait for messages on the subscription topic filters... + * + * // Unsubscribe once the subscriptions are no longer needed. + * result = IotMqtt_UnsubscribeAsync( mqttConnection, + * pSubscriptions, + * NUMBER_OF_SUBSCRIPTIONS, + * IOT_MQTT_FLAG_WAITABLE, + * NULL, + * &lastOperation ); + * + * // UNSUBSCRIBE returns IOT_MQTT_STATUS_PENDING when successful. + * // Wait up to 5 seconds for the operation to complete. + * if( result == IOT_MQTT_STATUS_PENDING ) + * { + * result = IotMqtt_Wait( lastOperation, 5000 ); + * } + * } + * // Check which subscriptions were rejected by the server. + * else if( result == IOT_MQTT_SERVER_REFUSED ) + * { + * for( int i = 0; i < NUMBER_OF_SUBSCRIPTIONS; i++ ) + * { + * if( IotMqtt_IsSubscribed( mqttConnection, + * pSubscriptions[ i ].pTopicFilter, + * pSubscriptions[ i ].topicFilterLength, + * NULL ) == false ) + * { + * // This subscription was rejected. + * } + * } + * } + * @endcode + */ +/* @[declare_mqtt_subscribeasync] */ +IotMqttError_t IotMqtt_SubscribeAsync( IotMqttConnection_t mqttConnection, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + const IotMqttCallbackInfo_t * pCallbackInfo, + IotMqttOperation_t * const pSubscribeOperation ); +/* @[declare_mqtt_subscribeasync] */ + +/** + * @brief Subscribes to the given array of topic filters with a timeout. + * + * This function sends an MQTT SUBSCRIBE packet to the server, then waits for + * a server response to the packet. Internally, this function is a call to @ref + * mqtt_function_subscribeasync followed by @ref mqtt_function_wait. See @ref + * mqtt_function_subscribeasync for more information about the MQTT SUBSCRIBE operation. + * + * @attention QoS 2 subscriptions are currently unsupported. Only 0 or 1 are valid + * for subscription QoS. + * + * @param[in] mqttConnection The MQTT connection to use for the subscription. + * @param[in] pSubscriptionList Pointer to the first element in the array of + * subscriptions. + * @param[in] subscriptionCount The number of elements in pSubscriptionList. + * @param[in] flags Flags which modify the behavior of this function. See @ref mqtt_constants_flags. + * Currently, flags are ignored by this function; this parameter is for + * future-compatibility. + * @param[in] timeoutMs If the MQTT server does not acknowledge the subscriptions within + * this timeout in milliseconds, this function returns #IOT_MQTT_TIMEOUT. + * + * @return One of the following: + * - #IOT_MQTT_SUCCESS + * - #IOT_MQTT_NOT_INITIALIZED + * - #IOT_MQTT_BAD_PARAMETER + * - #IOT_MQTT_NO_MEMORY + * - #IOT_MQTT_NETWORK_ERROR + * - #IOT_MQTT_SCHEDULING_ERROR + * - #IOT_MQTT_BAD_RESPONSE + * - #IOT_MQTT_TIMEOUT + * - #IOT_MQTT_SERVER_REFUSED + */ +/* @[declare_mqtt_subscribesync] */ +IotMqttError_t IotMqtt_SubscribeSync( IotMqttConnection_t mqttConnection, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + uint32_t timeoutMs ); +/* @[declare_mqtt_subscribesync] */ + +/** + * @brief Unsubscribes from the given array of topic filters and optionally + * receive an asynchronous notification when the unsubscribe completes. + * + * This function sends an MQTT UNSUBSCRIBE packet to the server. An UNSUBSCRIBE + * packet removes registered topic filters from the server. After unsubscribing, + * the server will no longer send messages on these topic filters to the client. + * + * Corresponding [subscription callback functions](@ref IotMqttCallbackInfo_t.function) + * are also removed from the MQTT connection. These subscription callback functions + * will be removed even if the MQTT UNSUBSCRIBE packet fails to send. + * + * @param[in] mqttConnection The MQTT connection used for the subscription. + * @param[in] pSubscriptionList Pointer to the first element in the array of + * subscriptions. + * @param[in] subscriptionCount The number of elements in pSubscriptionList. + * @param[in] flags Flags which modify the behavior of this function. See @ref mqtt_constants_flags. + * @param[in] pCallbackInfo Asynchronous notification of this function's completion (`NULL` to disable). + * @param[out] pUnsubscribeOperation Set to a handle by which this operation may be + * referenced after this function returns. This reference is invalidated once + * the unsubscribe operation completes. + * + * @return This function will return #IOT_MQTT_STATUS_PENDING upon success. + * @return Upon completion of the unsubscribe (either through an + * #IotMqttCallbackInfo_t or @ref mqtt_function_wait), the status will be one of: + * - #IOT_MQTT_SUCCESS + * - #IOT_MQTT_NETWORK_ERROR + * - #IOT_MQTT_SCHEDULING_ERROR + * - #IOT_MQTT_BAD_RESPONSE + * @return If this function fails before queuing an unsubscribe operation, it will return + * one of: + * - #IOT_MQTT_NOT_INITIALIZED + * - #IOT_MQTT_BAD_PARAMETER + * - #IOT_MQTT_NO_MEMORY + * + * @see @ref mqtt_function_unsubscribesync for a blocking variant of this function. + * @see @ref mqtt_function_subscribeasync for the function that adds subscriptions. + */ +/* @[declare_mqtt_unsubscribeasync] */ +IotMqttError_t IotMqtt_UnsubscribeAsync( IotMqttConnection_t mqttConnection, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + const IotMqttCallbackInfo_t * pCallbackInfo, + IotMqttOperation_t * const pUnsubscribeOperation ); +/* @[declare_mqtt_unsubscribeasync] */ + +/** + * @brief Unsubscribes from a given array of topic filters with a timeout. + * + * This function sends an MQTT UNSUBSCRIBE packet to the server, then waits + * for a server response to the packet. Internally, this function is a call to + * @ref mqtt_function_unsubscribeasync followed by @ref mqtt_function_wait. See @ref + * mqtt_function_unsubscribeasync for more information about the MQTT UNSUBSCRIBE + * operation. + * + * @param[in] mqttConnection The MQTT connection used for the subscription. + * @param[in] pSubscriptionList Pointer to the first element in the array of + * subscriptions. + * @param[in] subscriptionCount The number of elements in pSubscriptionList. + * @param[in] flags Flags which modify the behavior of this function. See @ref mqtt_constants_flags. + * Flags are currently ignored but reserved for future use. + * @param[in] timeoutMs If the MQTT server does not acknowledge the UNSUBSCRIBE within + * this timeout in milliseconds, this function returns #IOT_MQTT_TIMEOUT. + * + * @return One of the following: + * - #IOT_MQTT_SUCCESS + * - #IOT_MQTT_NOT_INITIALIZED + * - #IOT_MQTT_BAD_PARAMETER + * - #IOT_MQTT_NO_MEMORY + * - #IOT_MQTT_NETWORK_ERROR + * - #IOT_MQTT_SCHEDULING_ERROR + * - #IOT_MQTT_BAD_RESPONSE + */ +/* @[declare_mqtt_unsubscribesync] */ +IotMqttError_t IotMqtt_UnsubscribeSync( IotMqttConnection_t mqttConnection, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + uint32_t timeoutMs ); +/* @[declare_mqtt_unsubscribesync] */ + +/** + * @brief Publishes a message to the given topic name and optionally + * receive an asynchronous notification when the publish completes. + * + * This function sends an MQTT PUBLISH packet to the server. A PUBLISH packet + * contains a payload and a topic name. Any clients with a subscription on a + * topic filter matching the PUBLISH topic name will receive a copy of the + * PUBLISH packet from the server. + * + * If a PUBLISH packet fails to reach the server and it is not a QoS 0 message, + * it will be retransmitted. See #IotMqttPublishInfo_t for a description + * of the retransmission strategy. + * + * @attention QoS 2 messages are currently unsupported. Only 0 or 1 are valid + * for message QoS. + * + * @param[in] mqttConnection The MQTT connection to use for the publish. + * @param[in] pPublishInfo MQTT publish parameters. + * @param[in] flags Flags which modify the behavior of this function. See @ref mqtt_constants_flags. + * @param[in] pCallbackInfo Asynchronous notification of this function's completion (`NULL` to disable). + * @param[out] pPublishOperation Set to a handle by which this operation may be + * referenced after this function returns. This reference is invalidated once + * the publish operation completes. + * + * @return This function will return #IOT_MQTT_STATUS_PENDING upon success for + * QoS 1 publishes. For a QoS 0 publish it returns #IOT_MQTT_SUCCESS upon + * success. + * @return Upon completion of a QoS 1 publish (either through an + * #IotMqttCallbackInfo_t or @ref mqtt_function_wait), the status will be one of: + * - #IOT_MQTT_SUCCESS + * - #IOT_MQTT_NETWORK_ERROR + * - #IOT_MQTT_SCHEDULING_ERROR + * - #IOT_MQTT_BAD_RESPONSE + * - #IOT_MQTT_RETRY_NO_RESPONSE (if [pPublishInfo->retryMs](@ref IotMqttPublishInfo_t.retryMs) + * and [pPublishInfo->retryLimit](@ref IotMqttPublishInfo_t.retryLimit) were set). + * @return If this function fails before queuing an publish operation (regardless + * of QoS), it will return one of: + * - #IOT_MQTT_NOT_INITIALIZED + * - #IOT_MQTT_BAD_PARAMETER + * - #IOT_MQTT_NO_MEMORY + * + * @note The parameters `pCallbackInfo` and `pPublishOperation` should only be used for QoS + * 1 publishes. For QoS 0, they should both be `NULL`. + * + * @see @ref mqtt_function_publishsync for a blocking variant of this function. + * + * Example + * @code{c} + * // An initialized and connected MQTT connection. + * IotMqttConnection_t mqttConnection; + * + * // Publish information. + * IotMqttPublishInfo_t publishInfo = IOT_MQTT_PUBLISH_INFO_INITIALIZER; + * + * // Set the publish information. QoS 0 example (retain not used): + * publishInfo.qos = IOT_MQTT_QOS_0; + * publishInfo.pTopicName = "some/topic/name"; + * publishInfo.topicNameLength = ( uint16_t ) strlen( publishInfo.pTopicName ); + * publishInfo.pPayload = "payload"; + * publishInfo.payloadLength = strlen( publishInfo.pPayload ); + * + * // QoS 0 publish should return IOT_MQTT_SUCCESS upon success. + * IotMqttError_t qos0Result = IotMqtt_PublishAsync( mqttConnection, + * &publishInfo, + * 0, + * NULL, + * NULL ); + * + * // QoS 1 with retry example (using same topic name and payload as QoS 0 example): + * IotMqttOperation_t qos1Operation = IOT_MQTT_OPERATION_INITIALIZER; + * publishInfo.qos = IOT_MQTT_QOS_1; + * publishInfo.retryMs = 1000; // Retry if no response is received in 1 second. + * publishInfo.retryLimit = 5; // Retry up to 5 times. + * + * // QoS 1 publish should return IOT_MQTT_STATUS_PENDING upon success. + * IotMqttError_t qos1Result = IotMqtt_PublishAsync( mqttConnection, + * &publishInfo, + * IOT_MQTT_FLAG_WAITABLE, + * NULL, + * &qos1Operation ); + * + * // Wait up to 5 seconds for the publish to complete. + * if( qos1Result == IOT_MQTT_STATUS_PENDING ) + * { + * qos1Result = IotMqtt_Wait( qos1Operation, 5000 ); + * } + * @endcode + */ +/* @[declare_mqtt_publishasync] */ +IotMqttError_t IotMqtt_PublishAsync( IotMqttConnection_t mqttConnection, + const IotMqttPublishInfo_t * pPublishInfo, + uint32_t flags, + const IotMqttCallbackInfo_t * pCallbackInfo, + IotMqttOperation_t * const pPublishOperation ); +/* @[declare_mqtt_publishasync] */ + +/** + * @brief Publish a message to the given topic name with a timeout. + * + * This function sends an MQTT PUBLISH packet to the server, then waits for + * a server response to the packet. Internally, this function is a call to @ref + * mqtt_function_publishasync followed by @ref mqtt_function_wait. See @ref + * mqtt_function_publishasync for more information about the MQTT PUBLISH operation. + * + * @attention QoS 2 messages are currently unsupported. Only 0 or 1 are valid + * for message QoS. + * + * @param[in] mqttConnection The MQTT connection to use for the publish. + * @param[in] pPublishInfo MQTT publish parameters. + * @param[in] flags Flags which modify the behavior of this function. See @ref mqtt_constants_flags. + * Currently, flags are ignored by this function; this parameter is for + * future-compatibility. + * @param[in] timeoutMs If the MQTT server does not acknowledge a QoS 1 PUBLISH + * within this timeout in milliseconds, this function returns #IOT_MQTT_TIMEOUT. + * This parameter is ignored for QoS 0 PUBLISH messages. + * + * @return One of the following: + * - #IOT_MQTT_SUCCESS + * - #IOT_MQTT_NOT_INITIALIZED + * - #IOT_MQTT_BAD_PARAMETER + * - #IOT_MQTT_NO_MEMORY + * - #IOT_MQTT_NETWORK_ERROR + * - #IOT_MQTT_SCHEDULING_ERROR + * - #IOT_MQTT_BAD_RESPONSE + * - #IOT_MQTT_RETRY_NO_RESPONSE (if [pPublishInfo->retryMs](@ref IotMqttPublishInfo_t.retryMs) + * and [pPublishInfo->retryLimit](@ref IotMqttPublishInfo_t.retryLimit) were set). + */ +/* @[declare_mqtt_publishsync] */ +IotMqttError_t IotMqtt_PublishSync( IotMqttConnection_t mqttConnection, + const IotMqttPublishInfo_t * pPublishInfo, + uint32_t flags, + uint32_t timeoutMs ); +/* @[declare_mqtt_publishsync] */ + +/** + * @brief Waits for an operation to complete. + * + * This function blocks to wait for a [subscribe](@ref mqtt_function_subscribeasync), + * [unsubscribe](@ref mqtt_function_unsubscribeasync), or [publish] + * (@ref mqtt_function_publishasync) to complete. These operations are by default + * asynchronous; the function calls queue an operation for processing, and a + * callback is invoked once the operation is complete. + * + * To use this function, the flag #IOT_MQTT_FLAG_WAITABLE must have been + * set in the operation's function call. Additionally, this function must always + * be called with any waitable operation to clean up resources. + * + * Regardless of its return value, this function always clean up resources used + * by the waitable operation. This means `reference` is invalidated as soon as + * this function returns, even if it returns #IOT_MQTT_TIMEOUT or another error. + * + * @param[in] operation Reference to the operation to wait for. The flag + * #IOT_MQTT_FLAG_WAITABLE must have been set for this operation. + * @param[in] timeoutMs How many milliseconds to wait before returning + * #IOT_MQTT_TIMEOUT. + * + * @return The return value of this function depends on the MQTT operation associated + * with `reference`. See #IotMqttError_t for possible return values. + * + * Example + * @code{c} + * // Operation reference and timeout. + * IotMqttOperation_t publishOperation = IOT_MQTT_OPERATION_INITIALIZER; + * uint32_t timeoutMs = 5000; // 5 seconds + * + * // MQTT operation to wait for. + * IotMqttError_t result = IotMqtt_PublishAsync( mqttConnection, + * &publishInfo, + * IOT_MQTT_FLAG_WAITABLE, + * NULL, + * &publishOperation ); + * + * // Publish should have returned IOT_MQTT_STATUS_PENDING. The call to wait + * // returns once the result of the publish is available or the timeout expires. + * if( result == IOT_MQTT_STATUS_PENDING ) + * { + * result = IotMqtt_Wait( publishOperation, timeoutMs ); + * + * // After the call to wait, the result of the publish is known + * // (not IOT_MQTT_STATUS_PENDING). + * assert( result != IOT_MQTT_STATUS_PENDING ); + * } + * @endcode + */ +/* @[declare_mqtt_wait] */ +IotMqttError_t IotMqtt_Wait( IotMqttOperation_t operation, + uint32_t timeoutMs ); +/* @[declare_mqtt_wait] */ + +/*-------------------------- MQTT helper functions --------------------------*/ + +/** + * @brief Returns a string that describes an #IotMqttError_t. + * + * Like the POSIX `strerror`, this function returns a string describing a + * return code. In this case, the return code is an MQTT library error code, + * `status`. + * + * The string returned by this function MUST be treated as read-only: any + * attempt to modify its contents may result in a crash. Therefore, this function + * is limited to usage in logging. + * + * @param[in] status The status to describe. + * + * @return A read-only string that describes `status`. + * + * @warning The string returned by this function must never be modified. + */ +/* @[declare_mqtt_strerror] */ +const char * IotMqtt_strerror( IotMqttError_t status ); +/* @[declare_mqtt_strerror] */ + +/** + * @brief Returns a string that describes an #IotMqttOperationType_t. + * + * This function returns a string describing an MQTT operation type, `operation`. + * + * The string returned by this function MUST be treated as read-only: any + * attempt to modify its contents may result in a crash. Therefore, this function + * is limited to usage in logging. + * + * @param[in] operation The operation to describe. + * + * @return A read-only string that describes `operation`. + * + * @warning The string returned by this function must never be modified. + */ +/* @[declare_mqtt_operationtype] */ +const char * IotMqtt_OperationType( IotMqttOperationType_t operation ); +/* @[declare_mqtt_operationtype] */ + +/** + * @brief Check if an MQTT connection has a subscription for a topic filter. + * + * This function checks whether an MQTT connection `mqttConnection` has a + * subscription callback registered for a topic filter `pTopicFilter`. If a + * subscription callback is found, its details are copied into the output parameter + * `pCurrentSubscription`. This subscription callback will be invoked for incoming + * PUBLISH messages on `pTopicFilter`. + * + * The check for a matching subscription is only performed client-side; + * therefore, this function should not be relied upon for perfect accuracy. For + * example, this function may return an incorrect result if the MQTT server + * crashes and drops subscriptions without informing the client. + * + * Note that an MQTT connection's subscriptions might change between the time this + * function checks the subscription list and its caller tests the return value. + * This function certainly should not be used concurrently with any pending SUBSCRIBE + * or UNSUBSCRIBE operations. + * + * One suitable use of this function is to check which subscriptions were rejected + * if @ref mqtt_function_subscribeasync returns #IOT_MQTT_SERVER_REFUSED; that return + * code only means that at least one subscription was rejected. + * + * @param[in] mqttConnection The MQTT connection to check. + * @param[in] pTopicFilter The topic filter to check. + * @param[in] topicFilterLength Length of `pTopicFilter`. + * @param[out] pCurrentSubscription If a subscription is found, its details are + * copied here. This output parameter is only valid if this function returns `true` (`NULL` to disable). + * + * @return `true` if a subscription was found; `false` otherwise. + * + * @note The subscription QoS is not stored by the MQTT library; therefore, + * `pCurrentSubscription->qos` will always be set to #IOT_MQTT_QOS_0. + */ +/* @[declare_mqtt_issubscribed] */ +bool IotMqtt_IsSubscribed( IotMqttConnection_t mqttConnection, + const char * pTopicFilter, + uint16_t topicFilterLength, + IotMqttSubscription_t * const pCurrentSubscription ); +/* @[declare_mqtt_issubscribed] */ + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * Backwards compatibility macros for previous function names. + */ +#define IotMqtt_Subscribe IotMqtt_SubscribeAsync +#define IotMqtt_TimedSubscribe IotMqtt_SubscribeSync +#define IotMqtt_Unsubscribe IotMqtt_UnsubscribeAsync +#define IotMqtt_TimedUnsubscribe IotMqtt_UnsubscribeSync +#define IotMqtt_Publish IotMqtt_PublishAsync +#define IotMqtt_TimedPublish IotMqtt_PublishSync +/** @endcond */ + +#endif /* ifndef IOT_MQTT_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/include/iot_mqtt_serialize.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/include/iot_mqtt_serialize.h new file mode 100644 index 000000000..34691ffba --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/include/iot_mqtt_serialize.h @@ -0,0 +1,702 @@ +/* + * IoT MQTT V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_mqtt_serialize.h + * @brief User-facing functions for serializing MQTT 3.1.1 packets. This header should + * be included for building a single threaded light-weight MQTT client bypassing + * stateful CSDK MQTT library. + */ + +#ifndef _IOT_MQTT_SERIALIZE_H_ +#define _IOT_MQTT_SERIALIZE_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* MQTT types include. */ +#include "types/iot_mqtt_types.h" + +/*------------------------- MQTT library functions --------------------------*/ + +/** + * @functionspage{mqtt,MQTT library} + * - @functionname{mqtt_function_getconnectpacketsize} + * - @functionname{mqtt_function_serializeconnect} + * - @functionname{mqtt_function_getsubscriptionpacketsize} + * - @functionname{mqtt_function_serializesubscribe} + * - @functionname{mqtt_function_serializeunsubscribe} + * - @functionname{mqtt_function_getpublishpacketsize} + * - @functionname{mqtt_function_serializepublish} + * - @functionname{mqtt_function_serializedisconnect} + * - @functionname{mqtt_function_serializepingreq} + * - @functionname{mqtt_function_getincomingmqttpackettypeandlength} + * - @functionname{mqtt_function_deserializeresponse} + * - @functionname{mqtt_function_deserializepublish} + */ + +/** + * @functionpage{IotMqtt_GetConnectPacketSize,mqtt,getconnectpacketsize} + * @functionpage{IotMqtt_SerializeConnect,mqtt,serializeconnect} + * @functionpage{IotMqtt_GetSubscriptionPacketSize,mqtt,getsubscriptionpacketsize} + * @functionpage{IotMqtt_SerializeSubscribe,mqtt,serializesubscribe} + * @functionpage{IotMqtt_SerializeUnsubscribe,mqtt,serializeunsubscribe} + * @functionpage{IotMqtt_GetPublishPacketSize,mqtt,getpublishpacketsize} + * @functionpage{IotMqtt_SerializePublish,mqtt,serializepublish} + * @functionpage{IotMqtt_SerializeDisconnect,mqtt,serializedisconnect} + * @functionpage{IotMqtt_SerializePingreq,mqtt,serializepingreq} + * @functionpage{IotMqtt_GetIncomingMQTTPacketTypeAndLength,mqtt,getincomingmqttpackettypeandlength} + * @functionpage{IotMqtt_DeserializeResponse,mqtt,deserializeresponse} + * @functionpage{IotMqtt_DeserializePublish,mqtt,deserializepublish} + */ + +/** + * @brief Calculate the size and "Remaining length" of a CONNECT packet generated + * from the given parameters. + * + * @param[in] pConnectInfo User-provided CONNECT information struct. + * @param[out] pRemainingLength Output for calculated "Remaining length" field. + * @param[out] pPacketSize Output for calculated total packet size. + * + * @return IOT_MQTT_SUCCESS if the packet is within the length allowed by MQTT 3.1.1 spec; + * IOT_MQTT_BAD_PARAMETER otherwise. If this function returns `IOT_MQTT_BAD_PARAMETER`, + * the output parameters should be ignored. + * + * @note This call is part of serializer API used for implementing light-weight MQTT client. + * + * Example + * @code{c} + * // Example code below shows how IotMqtt_GetConnectPacketSize() should be used to calculate + * // the size of connect request. + * + * IotMqttConnectInfo_t xConnectInfo; + * size_t xRemainingLength = 0; + * size_t xPacketSize = 0; + * IotMqttError_t xResult; + * + * // start with everything set to zero + * memset( ( void * ) &xConnectInfo, 0x00, sizeof( xConnectInfo ) ); + * + * // Initialize connection info, details are out of scope for this example. + * _initializeConnectInfo( &xConnectInfo ); + * // Get size requirement for the connect packet + * xResult = IotMqtt_GetConnectPacketSize( &xConnectInfo, &xRemainingLength, &xPacketSize ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * + * // Application should allocate buffer with size == xPacketSize or use static buffer + * // with size >= xPacketSize to serialize connect request. + * @endcode + */ +/* @[declare_mqtt_getconnectpacketsize] */ +IotMqttError_t IotMqtt_GetConnectPacketSize( const IotMqttConnectInfo_t * pConnectInfo, + size_t * pRemainingLength, + size_t * pPacketSize ); +/* @[declare_mqtt_getconnectpacketsize] */ + +/** + * @brief Generate a CONNECT packet from the given parameters. + * + * @param[in] pConnectInfo User-provided CONNECT information. + * @param[in] remainingLength remaining length of the packet to be serialized. + * @param[in, out] pBuffer User provided buffer where the CONNECT packet is written. + * @param[in] bufferSize Size of the buffer pointed to by pBuffer. + * + * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY. + * + * @note pBuffer must be allocated by caller. Use @ref mqtt_function_getconnectpacketsize + * to determine the required size. + * @note This call is part of serializer API used for implementing light-weight MQTT client. + * + * Example + * @code{c} + * // Example code below shows how IotMqtt_SerializeConnect() should be used to serialize + * // MQTT connect packet and send it to MQTT broker. + * // Example uses static memory but dynamically allocated memory can be used as well. + * // Get size requirement for the connect packet. + * + * #define mqttexampleSHARED_BUFFER_SIZE 100 + * static ucSharedBuffer[mqttexampleSHARED_BUFFER_SIZE]; + * void sendConnectPacket( int xMQTTSocket ) + * { + * IotMqttConnectInfo_t xConnectInfo; + * size_t xRemainingLength = 0; + * size_t xPacketSize = 0; + * IotMqttError_t xResult; + * size_t xSentBytes = 0; + * // Get size requirement for MQTT connect packet. + * xResult = IotMqtt_GetConnectPacketSize( &xConnectInfo, &xRemainingLength, &xPacketSize ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * // Make sure the packet size is less than static buffer size + * IotMqtt_Assert( xPacketSize < mqttexampleSHARED_BUFFER_SIZE ); + * // Serialize MQTT connect packet into provided buffer + * xResult = IotMqtt_SerializeConnect( &xConnectInfo, xRemainingLength, ucSharedBuffer, xPacketSize ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * // xMQTTSocket here is posix socket created and connected to MQTT broker outside of this function. + * xSentBytes = send( xMQTTSocket, ( void * ) ucSharedBuffer, xPacketSize, 0 ); + * IotMqtt_Assert( xSentBytes == xPacketSize ); + * } + * @endcode + */ +/* @[declare_mqtt_serializeconnect] */ +IotMqttError_t IotMqtt_SerializeConnect( const IotMqttConnectInfo_t * pConnectInfo, + size_t remainingLength, + uint8_t * pBuffer, + size_t bufferSize ); +/* @[declare_mqtt_serializeconnect] */ + +/** + * @brief Calculate the size and "Remaining length" of a SUBSCRIBE or UNSUBSCRIBE + * packet generated from the given parameters. + * + * @param[in] type Either IOT_MQTT_SUBSCRIBE or IOT_MQTT_UNSUBSCRIBE. + * @param[in] pSubscriptionList User-provided array of subscriptions. + * @param[in] subscriptionCount Size of `pSubscriptionList`. + * @param[out] pRemainingLength Output for calculated "Remaining length" field. + * @param[out] pPacketSize Output for calculated total packet size. + * + * @return IOT_MQTT_SUCCESS if the packet is within the length allowed by MQTT 3.1.1 spec; + * IOT_MQTT_BAD_PARAMETER otherwise. If this function returns IOT_MQTT_BAD_PARAMETER, + * the output parameters should be ignored. + * + * @note This call is part of serializer API used for implementing light-weight MQTT client. + * + * Example + * @code{c} + * // Example code below shows how IotMqtt_GetSubscriptionPacketSize() should be used to calculate + * // the size of subscribe or unsubscribe request. + * + * IotMqttError_t xResult; + * IotMqttSubscription_t xMQTTSubscription[ 1 ]; + * size_t xRemainingLength = 0; + * size_t xPacketSize = 0; + * + * // Initialize Subscribe parameters. Details are out of scope for this example. + * // It will involve setting QOS, topic filter and topic filter length. + * _initializeSubscribe( xMQTTSubscription ); + * + * xResult = IotMqtt_GetSubscriptionPacketSize( IOT_MQTT_SUBSCRIBE, + * xMQTTSubscription, + * sizeof( xMQTTSubscription ) / sizeof( IotMqttSubscription_t ), + * &xRemainingLength, &xPacketSize ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * + * // Application should allocate buffer with size == xPacketSize or use static buffer + * // with size >= xPacketSize to serialize connect request. + * @endcode + */ +/* @[declare_mqtt_getsubscriptionpacketsize] */ +IotMqttError_t IotMqtt_GetSubscriptionPacketSize( IotMqttOperationType_t type, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + size_t * pRemainingLength, + size_t * pPacketSize ); +/* @[declare_mqtt_getsubscriptionpacketsize] */ + +/** + * @brief Generate a SUBSCRIBE packet from the given parameters. + * + * @param[in] pSubscriptionList User-provided array of subscriptions. + * @param[in] subscriptionCount Size of `pSubscriptionList`. + * @param[in] remainingLength remaining length of the packet to be serialized. + * @param[out] pPacketIdentifier The packet identifier generated for this SUBSCRIBE. + * @param[in, out] pBuffer User provide buffer where the SUBSCRIBE packet is written. + * @param[in] bufferSize Size of the buffer pointed to by pBuffer. + * + * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY. + * + * @note pBuffer must be allocated by caller. + * @note This call is part of serializer API used for implementing light-weight MQTT client. + * Example + * @code{c} + * // Example code below shows how IotMqtt_SerializeSubscribe() should be used to serialize + * // MQTT Subscribe packet and send it to MQTT broker. + * // Example uses static memory, but dynamically allocated memory can be used as well. + * // Get size requirement for the MQTT subscribe packet. + * + * #define mqttexampleSHARED_BUFFER_SIZE 100 + * static ucSharedBuffer[mqttexampleSHARED_BUFFER_SIZE]; + * void sendSubscribePacket( int xMQTTSocket ) + * { + * IotMqttSubscription_t xMQTTSubscription[ 1 ]; + * size_t xRemainingLength = 0; + * size_t xPacketSize = 0; + * IotMqttError_t xResult; + * size_t xSentBytes = 0; + * + * // Initialize Subscribe parameters. Details are out of scope for this example. + * // It will involve setting QOS, topic filter and topic filter length. + * _initializeSubscribe( xMQTTSubscription ); + * // Get size requirement for MQTT Subscribe packet. + * xResult = IotMqtt_GetSubscriptionPacketSize( IOT_MQTT_SUBSCRIBE, + * xMQTTSubscription, + * sizeof( xMQTTSubscription ) / sizeof( IotMqttSubscription_t ), + * &xRemainingLength, &xPacketSize ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * // Make sure the packet size is less than static buffer size. + * IotMqtt_Assert( xPacketSize < mqttexampleSHARED_BUFFER_SIZE ); + * + * // Serialize subscribe into statically allocated ucSharedBuffer. + * xResult = IotMqtt_SerializeSubscribe( xMQTTSubscription, + * sizeof( xMQTTSubscription ) / sizeof( IotMqttSubscription_t ), + * xRemainingLength, + * &usPacketIdentifier, + * ucSharedBuffer, + * xPacketSize ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * // xMQTTSocket here is posix socket created and connected to MQTT broker outside of this function. + * xSentBytes = send( xMQTTSocket, ( void * ) ucSharedBuffer, xPacketSize, 0 ); + * IotMqtt_Assert( xSentBytes == xPacketSize ); + * } + * @endcode + */ +/* @[declare_mqtt_serializesubscribe] */ +IotMqttError_t IotMqtt_SerializeSubscribe( const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + size_t remainingLength, + uint16_t * pPacketIdentifier, + uint8_t * pBuffer, + size_t bufferSize ); +/* @[declare_mqtt_serializesubscribe] */ + +/** + * @brief Generate a UNSUBSCRIBE packet from the given parameters. + * + * @param[in] pSubscriptionList User-provided array of subscriptions to remove. + * @param[in] subscriptionCount Size of `pSubscriptionList`. + * @param[in] remainingLength remaining length of the packet to be serialized. + * @param[out] pPacketIdentifier The packet identifier generated for this UNSUBSCRIBE. + * @param[in, out] pBuffer User provide buffer where the UNSUBSCRIBE packet is written. + * @param[in] bufferSize Size of the buffer pointed to by pBuffer. + * + * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY. + * + * @note pBuffer must be allocated by caller. + * @note This call is part of serializer API used for implementing light-weight MQTT client. + * + * Example + * @code{c} + * // Example code below shows how IotMqtt_SerializeUnsubscribe() should be used to serialize + * // MQTT unsubscribe packet and send it to MQTT broker. + * // Example uses static memory, but dynamically allocated memory can be used as well. + * // Get size requirement for the Unsubscribe packet. + * + * #define mqttexampleSHARED_BUFFER_SIZE 100 + * static ucSharedBuffer[mqttexampleSHARED_BUFFER_SIZE]; + * void sendUnsubscribePacket( int xMQTTSocket ) + * { + * // Following example shows one topic example. + * IotMqttSubscription_t xMQTTSubscription[ 1 ]; + * size_t xRemainingLength = 0; + * size_t xPacketSize = 0; + * IotMqttError_t xResult; + * size_t xSentBytes = 0; + * // Get size requirement for MQTT unsubscribe packet. + * xResult = IotMqtt_GetSubscriptionPacketSize( IOT_MQTT_UNSUBSCRIBE, + * xMQTTSubscription, + * sizeof( xMQTTSubscription ) / sizeof( IotMqttSubscription_t ), + * &xRemainingLength, &xPacketSize ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * // Make sure the packet size is less than static buffer size. + * IotMqtt_Assert( xPacketSize < mqttexampleSHARED_BUFFER_SIZE ); + * // Serialize subscribe into statically allocated ucSharedBuffer. + * xResult = IotMqtt_SerializeUnsubscribe( xMQTTSubscription, + * sizeof( xMQTTSubscription ) / sizeof( IotMqttSubscription_t ), + * xRemainingLength, + * &usPacketIdentifier, + * ucSharedBuffer, + * xPacketSize ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * // xMQTTSocket here is posix socket created and connected to MQTT broker outside of this function. + * xSentBytes = send( xMQTTSocket, ( void * ) ucSharedBuffer, xPacketSize, 0 ); + * IotMqtt_Assert( xSentBytes == xPacketSize ); + * } + * @endcode + */ +/* @[declare_mqtt_serializeunsubscribe] */ +IotMqttError_t IotMqtt_SerializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + size_t remainingLength, + uint16_t * pPacketIdentifier, + uint8_t * pBuffer, + size_t bufferSize ); +/* @[declare_mqtt_serializeunsubscribe] */ + +/** + * @brief Calculate the size and "Remaining length" of a PUBLISH packet generated + * from the given parameters. + * + * @param[in] pPublishInfo User-provided PUBLISH information struct. + * @param[out] pRemainingLength Output for calculated "Remaining length" field. + * @param[out] pPacketSize Output for calculated total packet size. + * + * @return IOT_MQTT_SUCCESS if the packet is within the length allowed by MQTT 3.1.1 spec; + * IOT_MQTT_BAD_PARAMETER otherwise. If this function returns IOT_MQTT_BAD_PARAMETER, + * the output parameters should be ignored. + * + * @note This call is part of serializer API used for implementing light-weight MQTT client. + * + * Example + * @code{c} + * // Example code below shows how IotMqtt_GetPublishPacketSize() should be used to calculate + * // the size of MQTT publish request. + * + * IotMqttError_t xResult; + * IotMqttPublishInfo_t xMQTTPublishInfo; + * size_t xRemainingLength = 0; + * size_t xPacketSize = 0; + * + * // Initialize Publish parameters. Details are out of scope for this example. + * // It will involve setting QOS, topic filter, topic filter length, payload + * // payload length + * _initializePublish( &xMQTTPublishInfo ); + * + * // Find out length of Publish packet size. + * xResult = IotMqtt_GetPublishPacketSize( &xMQTTPublishInfo, &xRemainingLength, &xPacketSize ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * + * // Application should allocate buffer with size == xPacketSize or use static buffer + * // with size >= xPacketSize to serialize connect request. + * @endcode + */ +/* @[declare_mqtt_getpublishpacketsize] */ +IotMqttError_t IotMqtt_GetPublishPacketSize( IotMqttPublishInfo_t * pPublishInfo, + size_t * pRemainingLength, + size_t * pPacketSize ); +/* @[declare_mqtt_getpublishpacketsize] */ + +/** + * @brief Generate a PUBLISH packet from the given parameters. + * + * @param[in] pPublishInfo User-provided PUBLISH information. + * @param[in] remainingLength remaining length of the packet to be serialized. + * @param[out] pPacketIdentifier The packet identifier generated for this PUBLISH. + * @param[out] pPacketIdentifierHigh Where the high byte of the packet identifier + * is written. + * @param[in, out] pBuffer User provide buffer where the PUBLISH packet is written. + * @param[in] bufferSize Size of the buffer pointed to by pBuffer. + * + * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_BAD_PARAMETER. + * + * @note pBuffer must be allocated by caller. + * @note This call is part of serializer API used for implementing light-weight MQTT client. + * + * Example + * @code{c} + * // Example code below shows how IotMqtt_SerializePublish() should be used to serialize + * // MQTT Publish packet and send it to broker. + * // Example uses static memory, but dynamically allocated memory can be used as well. + * + * #define mqttexampleSHARED_BUFFER_SIZE 100 + * static ucSharedBuffer[mqttexampleSHARED_BUFFER_SIZE]; + * void sendUnsubscribePacket( int xMQTTSocket ) + * { + * IotMqttError_t xResult; + * IotMqttPublishInfo_t xMQTTPublishInfo; + * size_t xRemainingLength = 0; + * size_t xPacketSize = 0; + * size_t xSentBytes = 0; + * uint16_t usPacketIdentifier; + * uint8_t * pusPacketIdentifierHigh; + * + * // Initialize Publish parameters. Details are out of scope for this example. + * // It will involve setting QOS, topic filter, topic filter length, payload + * // payload length. + * _initializePublish( &xMQTTPublishInfo ); + * + * // Find out length of Publish packet size. + * xResult = IotMqtt_GetPublishPacketSize( &xMQTTPublishInfo, &xRemainingLength, &xPacketSize ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * // Make sure the packet size is less than static buffer size + * IotMqtt_Assert( xPacketSize < mqttexampleSHARED_BUFFER_SIZE ); + * + * xResult = IotMqtt_SerializePublish( &xMQTTPublishInfo, + * xRemainingLength, + * &usPacketIdentifier, + * &pusPacketIdentifierHigh, + * ucSharedBuffer, + * xPacketSize ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * + * // xMQTTSocket here is posix socket created and connected to MQTT broker outside of this function. + * xSentBytes = send( xMQTTSocket, ( void * ) ucSharedBuffer, xPacketSize, 0 ); + * IotMqtt_Assert( xSentBytes == xPacketSize ); + * } + * @endcode + */ +/* @[declare_mqtt_serializepublish] */ +IotMqttError_t IotMqtt_SerializePublish( IotMqttPublishInfo_t * pPublishInfo, + size_t remainingLength, + uint16_t * pPacketIdentifier, + uint8_t ** pPacketIdentifierHigh, + uint8_t * pBuffer, + size_t bufferSize ); +/* @[declare_mqtt_serializepublish] */ + +/** + * @brief Generate a DISCONNECT packet + * + * @param[in, out] pBuffer User provide buffer where the DISCONNECT packet is written. + * @param[in] bufferSize Size of the buffer pointed to by pBuffer. + * + * @return returns #IOT_MQTT_SUCCESS or #IOT_MQTT_BAD_PARAMETER + * + * @note This call is part of serializer API used for implementing light-weight MQTT client. + * + * Example + * @code{c} + * // Example below shows how IotMqtt_SerializeDisconnect() should be used. + * + * #define mqttexampleSHARED_BUFFER_SIZE 100 + * static ucSharedBuffer[mqttexampleSHARED_BUFFER_SIZE]; + * void sendDisconnectRequest( int xMQTTSocket ) + * { + * size_t xSentBytes = 0; + * + * // Disconnect is fixed length packet, therefore there is no need to calculate the size, + * // just makes sure static buffer can accommodate disconnect request. + * IotMqtt_Assert( MQTT_PACKET_DISCONNECT_SIZE <= mqttexampleSHARED_BUFFER_SIZE ); + * + * // Serialize Disconnect packet into static buffer (dynamically allocated buffer can be used as well) + * xResult = IotMqtt_SerializeDisconnect( ucSharedBuffer, MQTT_PACKET_DISCONNECT_SIZE ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * + * // xMQTTSocket here is posix socket created and connected to MQTT broker outside of this function. + * xSentByte = send( xMQTTSocket, ( void * ) ucSharedBuffer, MQTT_PACKET_DISCONNECT_SIZE, 0 ); + * IotMqtt_Assert( xSentByte == MQTT_PACKET_DISCONNECT_SIZE ); + * } + * + * @endcode + */ +/* @[declare_mqtt_serializedisconnect] */ +IotMqttError_t IotMqtt_SerializeDisconnect( uint8_t * pBuffer, + size_t bufferSize ); +/* @[declare_mqtt_serializedisconnect] */ + +/** + * @brief Generate a PINGREQ packet. + * + * @param[in, out] pBuffer User provide buffer where the PINGREQ packet is written. + * @param[in] bufferSize Size of the buffer pointed to by pBuffer. + * + * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_BAD_PARAMETER. + * + * @note This call is part of serializer API used for implementing light-weight MQTT client. + * + * Example + * @code{c} + * // Example below shows how IotMqtt_SerializePingReq() should be used. + * + * #define mqttexampleSHARED_BUFFER_SIZE 100 + * static ucSharedBuffer[mqttexampleSHARED_BUFFER_SIZE]; + * void sendPingRequest( int xMQTTSocket ) + * { + * size_t xSentBytes = 0; + * + * // PingReq is fixed length packet, therefore there is no need to calculate the size, + * // just makes sure static buffer can accommodate Ping request. + * IotMqtt_Assert( MQTT_PACKET_PINGREQ_SIZE <= mqttexampleSHARED_BUFFER_SIZE ); + * + * xResult = IotMqtt_SerializePingreq( ucSharedBuffer, MQTT_PACKET_PINGREQ_SIZE ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * + * // xMQTTSocket here is posix socket created and connected to MQTT broker outside of this function. + * xSentByte = send( xMQTTSocket, ( void * ) ucSharedBuffer, MQTT_PACKET_DISCONNECT_SIZE, 0 ); + * IotMqtt_Assert( xSentByte == MQTT_PACKET_PINGREQ_SIZE); + * } + * @endcode + */ +/* @[declare_mqtt_serializepingreq] */ +IotMqttError_t IotMqtt_SerializePingreq( uint8_t * pBuffer, + size_t bufferSize ); +/* @[declare_mqtt_serializepingreq] */ + +/** + * @brief Extract MQTT packet type and length from incoming packet + * + * @param[in, out] pIncomingPacket Pointer to IotMqttPacketInfo_t structure + * where type, remaining length and packet identifier are stored. + * @param[in] getNextByte Pointer to platform specific function which is used + * to extract type and length from incoming received stream (see example ). + * @param[in] pNetworkConnection Pointer to platform specific network connection + * which is used by getNextByte to receive network data + * + * @return #IOT_MQTT_SUCCESS on successful extraction of type and length, + * #IOT_MQTT_BAD_RESPONSE on failure. + * + * @note This call is part of serializer API used for implementing light-weight MQTT client. + * + * Example + * @code{c} + * // Example code below shows how to implement getNetxByte function with posix sockets. + * // Note: IotMqttGetNextByte_t typedef IotMqttError_t (* IotMqttGetNextByte_t)( void * pNetworkContext, + * // uint8_t * pNextByte ); + * // Note: It is assumed that socket is already created and connected, + * + * IotMqttError_t getNextByte( void * pContext, + * uint8_t * pNextByte ) + * { + * int socket = ( int ) ( *pvContext ); + * int receivedBytes; + * IotMqttError_t result; + * + * receivedBytes = recv( socket, ( void * ) pNextByte, sizeof( uint8_t ), 0 ); + * + * if( receivedBytes == sizeof( uint8_t ) ) + * { + * result = IOT_MQTT_SUCCESS; + * } + * else + * { + * result = IOT_MQTT_TIMEOUT; + * } + * + * return result; + * } + * + * // Example below shows how IotMqtt_GetIncomingMQTTPacketTypeAndLength() is used to extract type + * // and length from incoming ping response. + * // xMQTTSocket here is posix socket created and connected to MQTT broker outside of this function. + * void getTypeAndLengthFromIncomingMQTTPingResponse( int xMQTTSocket ) + * { + * IotMqttPacketInfo_t xIncomingPacket; + * IotMqttError_t xResult = IotMqtt_GetIncomingMQTTPacketTypeAndLength( &xIncomingPacket, getNextByte, ( void * ) xMQTTSocket ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * IotMqtt_Assert( xIncomingPacket.type == MQTT_PACKET_TYPE_PINGRESP ); + * } + * @endcode + * + */ +/* @[declare_mqtt_getincomingmqttpackettypeandlength] */ +IotMqttError_t IotMqtt_GetIncomingMQTTPacketTypeAndLength( IotMqttPacketInfo_t * pIncomingPacket, + IotMqttGetNextByte_t getNextByte, + void * pNetworkConnection ); +/* @[declare_mqtt_getincomingmqttpackettypeandlength] */ + +/** + * @brief Deserialize incoming publish packet. + * + * @param[in, out] pMqttPacket The caller of this API sets type, remainingLength and pRemainingData. + * On success, packetIdentifier and pubInfo will be set by the function. + * + * @return One of the following: + * - #IOT_MQTT_SUCCESS + * - #IOT_MQTT_BAD_RESPONSE + * - #IOT_MQTT_SERVER_REFUSED + * + * @note This call is part of serializer API used for implementing light-weight MQTT client. + * + * Example + * @code{c} + * // Example below shows how IotMqtt_DeserializePublish() used to extract contents of incoming + * // Publish. xMQTTSocket here is posix socket created and connected to MQTT broker outside of this function. + * void processIncomingPublish( int xMQTTSocket ) + * { + * IotMqttError_t xResult; + * IotMqttPacketInfo_t xIncomingPacket; + * + * xResult = IotMqtt_GetIncomingMQTTPacketTypeAndLength( &xIncomingPacket, getNextByte, ( void * ) xMQTTSocket ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * IotMqtt_Assert( ( xIncomingPacket.type & 0xf0 ) == MQTT_PACKET_TYPE_PUBLISH ); + * IotMqtt_Assert( xIncomingPacket.remainingLength <= mqttexampleSHARED_BUFFER_SIZE ); + * + * // Receive the remaining bytes. + * if( recv( xMQTTSocket, ( void * ) ucSharedBuffer, xIncomingPacket.remainingLength, 0 ) == xIncomingPacket.remainingLength ) + * { + * xIncomingPacket.pRemainingData = ucSharedBuffer; + * + * if( IotMqtt_DeserializePublish( &xIncomingPacket ) != IOT_MQTT_SUCCESS ) + * { + * xResult = IOT_MQTT_BAD_RESPONSE; + * } + * else + * { + * // Process incoming Publish. + * IotLogInfo( "Incoming QOS : %d\n", xIncomingPacket.pubInfo.qos ); + * IotLogInfo( "Incoming Publish Topic Name: %.*s\n", xIncomingPacket.pubInfo.topicNameLength, xIncomingPacket.pubInfo.pTopicName ); + * IotLogInfo( "Incoming Publish Message : %.*s\n", xIncomingPacket.pubInfo.payloadLength, xIncomingPacket.pubInfo.pPayload ); + * } + * } + * else + * { + * xResult = IOT_MQTT_NETWORK_ERROR; + * } + * + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * } + * @endcode + */ +/* @[declare_mqtt_deserializepublish] */ +IotMqttError_t IotMqtt_DeserializePublish( IotMqttPacketInfo_t * pMqttPacket ); +/* @[declare_mqtt_deserializepublish] */ + +/** + * @brief Deserialize incoming ack packets. + * + * @param[in, out] pMqttPacket The caller of this API sets type, remainingLength and pRemainingData. + * On success, packetIdentifier will be set. + * + * @return One of the following: + * - #IOT_MQTT_SUCCESS + * - #IOT_MQTT_BAD_RESPONSE + * - #IOT_MQTT_SERVER_REFUSED + * + * @note This call is part of serializer API used for implementing light-weight MQTT client. + * + * Example + * @code{c} + * // Example below shows how IotMqtt_DeserializeResponse() is used to process unsubscribe ack. + * // xMQTTSocket here is posix socket created and connected to MQTT broker outside of this function. + * void processUnsubscribeAck( int xMQTTSocket ) + * { + * IotMqttError_t xResult; + * IotMqttPacketInfo_t xIncomingPacket; + * + * xResult = IotMqtt_GetIncomingMQTTPacketTypeAndLength( &xIncomingPacket, getNextByte, ( void * ) xMQTTSocket ); + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * IotMqtt_Assert( xIncomingPacket.type == MQTT_PACKET_TYPE_UNSUBACK ); + * IotMqtt_Assert( xIncomingPacket.remainingLength <= sizeof( ucSharedBuffer ) ); + * + * // Receive the remaining bytes. + * if( recv( xMQTTSocket, ( void * ) ucSharedBuffer, xIncomingPacket.remainingLength, 0 ) == xIncomingPacket.remainingLength ) + * { + * xIncomingPacket.pRemainingData = ucSharedBuffer; + * + * if( IotMqtt_DeserializeResponse( &xIncomingPacket ) != IOT_MQTT_SUCCESS ) + * { + * xResult = IOT_MQTT_BAD_RESPONSE; + * } + * } + * else + * { + * xResult = IOT_MQTT_NETWORK_ERROR; + * } + * IotMqtt_Assert( xResult == IOT_MQTT_SUCCESS ); + * } + * @endcode + */ +/* @[declare_mqtt_deserializeresponse] */ +IotMqttError_t IotMqtt_DeserializeResponse( IotMqttPacketInfo_t * pMqttPacket ); +/* @[declare_mqtt_deserializeresponse] */ + + + +#endif /* ifndef IOT_MQTT_SERIALIZE_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/include/types/iot_mqtt_types.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/include/types/iot_mqtt_types.h new file mode 100644 index 000000000..2cf854be5 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/include/types/iot_mqtt_types.h @@ -0,0 +1,1164 @@ +/* + * IoT MQTT V2.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_mqtt_types.h + * @brief MQTT library types. + */ + +#ifndef IOT_MQTT_TYPES_H_ +#define IOT_MQTT_TYPES_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include +#include + +/* Type includes. */ +#include "types/iot_platform_types.h" +#include "types/iot_taskpool_types_freertos.h" + +/* Platform network include. */ +#include "platform/iot_network.h" + +/*---------------------------- MQTT handle types ----------------------------*/ + +/** + * @handles{mqtt,MQTT library} + */ + +/** + * @ingroup mqtt_datatypes_handles + * @brief Opaque handle of an MQTT connection. + * + * MQTT connection handle type. MQTT connection handles are created by + * successful calls to @ref mqtt_function_connect and are used to refer to + * the connection when calling MQTT library functions. + * + * A call to @ref mqtt_function_disconnect makes a connection handle invalid. Once + * @ref mqtt_function_disconnect returns, the connection handle should no longer + * be used. + * + * @initializer{IotMqttConnection_t,IOT_MQTT_CONNECTION_INITIALIZER} + */ +typedef struct _mqttConnection * IotMqttConnection_t; + +/** + * @ingroup mqtt_datatypes_handles + * @brief Opaque handle that references an in-progress MQTT operation. + * + * Set as an output parameter of @ref mqtt_function_publishasync, @ref mqtt_function_subscribeasync, + * and @ref mqtt_function_unsubscribeasync. These functions queue an MQTT operation; the result + * of the operation is unknown until a response from the MQTT server is received. Therefore, + * this handle serves as a reference to MQTT operations awaiting MQTT server response. + * + * This reference will be valid from the successful return of @ref mqtt_function_publishasync, + * @ref mqtt_function_subscribeasync, or @ref mqtt_function_unsubscribeasync. The reference becomes + * invalid once the [completion callback](@ref IotMqttCallbackInfo_t) is invoked, or + * @ref mqtt_function_wait returns. + * + * @initializer{IotMqttOperation_t,IOT_MQTT_OPERATION_INITIALIZER} + * + * @see @ref mqtt_function_wait and #IOT_MQTT_FLAG_WAITABLE for waiting on a reference. + * #IotMqttCallbackInfo_t and #IotMqttCallbackParam_t for an asynchronous notification + * of completion. + */ +typedef struct _mqttOperation * IotMqttOperation_t; + +/*-------------------------- MQTT enumerated types --------------------------*/ + +/** + * @enums{mqtt,MQTT library} + */ + +/** + * @ingroup mqtt_datatypes_enums + * @brief Return codes of [MQTT functions](@ref mqtt_functions). + * + * The function @ref mqtt_function_strerror can be used to get a return code's + * description. + */ +typedef enum IotMqttError +{ + /** + * @brief MQTT operation completed successfully. + * + * Functions that may return this value: + * - @ref mqtt_function_connect + * - @ref mqtt_function_publishasync with QoS 0 parameter + * - @ref mqtt_function_wait + * - @ref mqtt_function_subscribesync + * - @ref mqtt_function_unsubscribesync + * - @ref mqtt_function_publishsync + * + * Will also be the value of an operation completion callback's + * #IotMqttCallbackParam_t.result when successful. + */ + IOT_MQTT_SUCCESS = 0, + + /** + * @brief MQTT operation queued, awaiting result. + * + * Functions that may return this value: + * - @ref mqtt_function_subscribeasync + * - @ref mqtt_function_unsubscribeasync + * - @ref mqtt_function_publishasync with QoS 1 parameter + */ + IOT_MQTT_STATUS_PENDING = 1, + + /** + * @brief Initialization failed. + * + * Functions that may return this value: + * - @ref mqtt_function_init + */ + IOT_MQTT_INIT_FAILED = 2, + + /** + * @brief At least one parameter is invalid. + * + * Functions that may return this value: + * - @ref mqtt_function_connect + * - @ref mqtt_function_subscribeasync and @ref mqtt_function_subscribesync + * - @ref mqtt_function_unsubscribeasync and @ref mqtt_function_unsubscribesync + * - @ref mqtt_function_publishasync and @ref mqtt_function_publishsync + * - @ref mqtt_function_wait + */ + IOT_MQTT_BAD_PARAMETER = 3, + + /** + * @brief MQTT operation failed because of memory allocation failure. + * + * Functions that may return this value: + * - @ref mqtt_function_connect + * - @ref mqtt_function_subscribeasync and @ref mqtt_function_subscribesync + * - @ref mqtt_function_unsubscribeasync and @ref mqtt_function_unsubscribesync + * - @ref mqtt_function_publishasync and @ref mqtt_function_publishsync + */ + IOT_MQTT_NO_MEMORY = 4, + + /** + * @brief MQTT operation failed because the network was unusable. + * + * This return value may indicate that the network is disconnected. + * + * Functions that may return this value: + * - @ref mqtt_function_connect + * - @ref mqtt_function_wait + * - @ref mqtt_function_subscribesync + * - @ref mqtt_function_unsubscribesync + * - @ref mqtt_function_publishsync + * + * May also be the value of an operation completion callback's + * #IotMqttCallbackParam_t.result. + */ + IOT_MQTT_NETWORK_ERROR = 5, + + /** + * @brief MQTT operation could not be scheduled, i.e. enqueued for sending. + * + * Functions that may return this value: + * - @ref mqtt_function_connect + * - @ref mqtt_function_subscribeasync and @ref mqtt_function_subscribesync + * - @ref mqtt_function_unsubscribeasync and @ref mqtt_function_unsubscribesync + * - @ref mqtt_function_publishasync and @ref mqtt_function_publishsync + */ + IOT_MQTT_SCHEDULING_ERROR = 6, + + /** + * @brief MQTT response packet received from the network is malformed. + * + * Functions that may return this value: + * - @ref mqtt_function_connect + * - @ref mqtt_function_wait + * - @ref mqtt_function_subscribesync + * - @ref mqtt_function_unsubscribesync + * - @ref mqtt_function_publishsync + * + * May also be the value of an operation completion callback's + * #IotMqttCallbackParam_t.result. + * + * @note If this value is received, the network connection has been closed. + */ + IOT_MQTT_BAD_RESPONSE = 7, + + /** + * @brief A blocking MQTT operation timed out. + * + * Functions that may return this value: + * - @ref mqtt_function_connect + * - @ref mqtt_function_wait + * - @ref mqtt_function_subscribesync + * - @ref mqtt_function_unsubscribesync + * - @ref mqtt_function_publishsync + */ + IOT_MQTT_TIMEOUT = 8, + + /** + * @brief A CONNECT or at least one subscription was refused by the server. + * + * Functions that may return this value: + * - @ref mqtt_function_connect + * - @ref mqtt_function_wait, but only when its #IotMqttOperation_t parameter + * is associated with a SUBSCRIBE operation. + * - @ref mqtt_function_subscribesync + * + * May also be the value of an operation completion callback's + * #IotMqttCallbackParam_t.result for a SUBSCRIBE. + * + * @note If this value is returned and multiple subscriptions were passed to + * @ref mqtt_function_subscribeasync (or @ref mqtt_function_subscribesync), it's + * still possible that some of the subscriptions succeeded. This value only + * signifies that AT LEAST ONE subscription was rejected. The function @ref + * mqtt_function_issubscribed can be used to determine which subscriptions + * were accepted or rejected. + */ + IOT_MQTT_SERVER_REFUSED = 9, + + /** + * @brief A QoS 1 PUBLISH received no response and [the retry limit] + * (#IotMqttPublishInfo_t.retryLimit) was reached. + * + * Functions that may return this value: + * - @ref mqtt_function_wait, but only when its #IotMqttOperation_t parameter + * is associated with a QoS 1 PUBLISH operation + * - @ref mqtt_function_publishsync + * + * May also be the value of an operation completion callback's + * #IotMqttCallbackParam_t.result for a QoS 1 PUBLISH. + */ + IOT_MQTT_RETRY_NO_RESPONSE = 10, + + /** + * @brief An API function was called before @ref mqtt_function_init. + * + * Functions that may return this value: + * - @ref mqtt_function_connect + * - @ref mqtt_function_subscribeasync + * - @ref mqtt_function_subscribesync + * - @ref mqtt_function_unsubscribeasync + * - @ref mqtt_function_unsubscribesync + * - @ref mqtt_function_publishasync + * - @ref mqtt_function_publishsync + * - @ref mqtt_function_wait + */ + IOT_MQTT_NOT_INITIALIZED = 11 +} IotMqttError_t; + +/** + * @ingroup mqtt_datatypes_enums + * @brief Types of MQTT operations. + * + * The function @ref mqtt_function_operationtype can be used to get an operation + * type's description. + */ +typedef enum IotMqttOperationType +{ + IOT_MQTT_CONNECT, /**< Client-to-server CONNECT. */ + IOT_MQTT_PUBLISH_TO_SERVER, /**< Client-to-server PUBLISH. */ + IOT_MQTT_PUBACK, /**< Client-to-server PUBACK. */ + IOT_MQTT_SUBSCRIBE, /**< Client-to-server SUBSCRIBE. */ + IOT_MQTT_UNSUBSCRIBE, /**< Client-to-server UNSUBSCRIBE. */ + IOT_MQTT_PINGREQ, /**< Client-to-server PINGREQ. */ + IOT_MQTT_DISCONNECT /**< Client-to-server DISCONNECT. */ +} IotMqttOperationType_t; + +/** + * @ingroup mqtt_datatypes_enums + * @brief Quality of service levels for MQTT PUBLISH messages. + * + * All MQTT PUBLISH messages, including Last Will and Testament and messages + * received on subscription filters, have an associated Quality of Service, + * which defines any delivery guarantees for that message. + * - QoS 0 messages will be delivered at most once. This is a "best effort" + * transmission with no retransmissions. + * - QoS 1 messages will be delivered at least once. See #IotMqttPublishInfo_t + * for the retransmission strategy this library uses to redeliver messages + * assumed to be lost. + * + * @attention QoS 2 is not supported by this library and should not be used. + */ +typedef enum IotMqttQos +{ + IOT_MQTT_QOS_0 = 0, /**< Delivery at most once. */ + IOT_MQTT_QOS_1 = 1, /**< Delivery at least once. See #IotMqttPublishInfo_t for client-side retry strategy. */ + IOT_MQTT_QOS_2 = 2 /**< Delivery exactly once. Unsupported, but enumerated for completeness. */ +} IotMqttQos_t; + +/** + * @ingroup mqtt_datatypes_enums + * @brief The reason that an MQTT connection (and its associated network connection) + * was disconnected. + * + * When an MQTT connection is closed, its associated [disconnect callback] + * (@ref IotMqttNetworkInfo_t::disconnectCallback) will be invoked. This type + * is passed inside of an #IotMqttCallbackParam_t to provide a reason for the + * disconnect. + */ +typedef enum IotMqttDisconnectReason +{ + IOT_MQTT_DISCONNECT_CALLED, /**< @ref mqtt_function_disconnect was invoked. */ + IOT_MQTT_BAD_PACKET_RECEIVED, /**< An invalid packet was received from the network. */ + IOT_MQTT_KEEP_ALIVE_TIMEOUT /**< Keep-alive response was not received within @ref IOT_MQTT_RESPONSE_WAIT_MS. */ +} IotMqttDisconnectReason_t; + +/*------------------------- MQTT parameter structs --------------------------*/ + +/** + * @paramstructs{mqtt,MQTT} + */ + +/** + * @ingroup mqtt_datatypes_paramstructs + * @brief Information on a PUBLISH message. + * + * @paramfor @ref mqtt_function_connect, @ref mqtt_function_publishasync + * + * Passed to @ref mqtt_function_publishasync as the message to publish and @ref + * mqtt_function_connect as the Last Will and Testament (LWT) message. + * + * @initializer{IotMqttPublishInfo_t,IOT_MQTT_PUBLISH_INFO_INITIALIZER} + * + * #IotMqttPublishInfo_t.retryMs and #IotMqttPublishInfo_t.retryLimit are only + * relevant to QoS 1 PUBLISH messages. They are ignored for QoS 0 PUBLISH + * messages and LWT messages. These members control retransmissions of QoS 1 + * messages under the following rules: + * - Retransmission is disabled when #IotMqttPublishInfo_t.retryLimit is 0. + * After sending the PUBLISH, the library will wait indefinitely for a PUBACK. + * - If #IotMqttPublishInfo_t.retryLimit is greater than 0, then QoS 1 publishes + * that do not receive a PUBACK within #IotMqttPublishInfo_t.retryMs will be + * retransmitted, up to #IotMqttPublishInfo_t.retryLimit times. + * + * Retransmission follows a truncated exponential backoff strategy. The constant + * @ref IOT_MQTT_RETRY_MS_CEILING controls the maximum time between retransmissions. + * + * After #IotMqttPublishInfo_t.retryLimit retransmissions are sent, the MQTT + * library will wait @ref IOT_MQTT_RESPONSE_WAIT_MS before a final check + * for a PUBACK. If no PUBACK was received within this time, the QoS 1 PUBLISH + * fails with the code #IOT_MQTT_RETRY_NO_RESPONSE. + * + * @note The lengths of the strings in this struct should not include the NULL + * terminator. Strings in this struct do not need to be NULL-terminated. + * + * @note The AWS IoT MQTT broker does not support the DUP bit. More + * information about connecting to AWS IoT via MQTT is available + * [here](https://docs.aws.amazon.com/iot/latest/developerguide/mqtt.html). + * + * Example + * + * Consider a situation where + * - @ref IOT_MQTT_RETRY_MS_CEILING is 60000 + * - #IotMqttPublishInfo_t.retryMs is 2000 + * - #IotMqttPublishInfo_t.retryLimit is 20 + * + * A PUBLISH message will be retransmitted at the following times after the initial + * transmission if no PUBACK is received: + * - 2000 ms (2000 ms after previous transmission) + * - 6000 ms (4000 ms after previous transmission) + * - 14000 ms (8000 ms after previous transmission) + * - 30000 ms (16000 ms after previous transmission) + * - 62000 ms (32000 ms after previous transmission) + * - 122000 ms, 182000 ms, 242000 ms... (every 60000 ms until 20 transmissions have been sent) + * + * After the 20th retransmission, the MQTT library will wait + * @ref IOT_MQTT_RESPONSE_WAIT_MS before checking a final time for a PUBACK. + */ +typedef struct IotMqttPublishInfo +{ + IotMqttQos_t qos; /**< @brief QoS of message. Must be 0 or 1. */ + bool retain; /**< @brief MQTT message retain flag. */ + + const char * pTopicName; /**< @brief Topic name of PUBLISH. */ + uint16_t topicNameLength; /**< @brief Length of #IotMqttPublishInfo_t.pTopicName. */ + + const void * pPayload; /**< @brief Payload of PUBLISH. */ + size_t payloadLength; /**< @brief Length of #IotMqttPublishInfo_t.pPayload. For LWT messages, this is limited to 65535. */ + + uint32_t retryMs; /**< @brief If no response is received within this time, the message is retransmitted. */ + uint32_t retryLimit; /**< @brief How many times to attempt retransmission. */ +} IotMqttPublishInfo_t; + +/** + * @ingroup mqtt_datatypes_paramstructs + * @brief Parameter to an MQTT callback function. + * + * @paramfor MQTT callback functions + * + * The MQTT library passes this struct to a registered callback whenever an + * operation completes, a message is received on a topic filter, or an MQTT + * connection is disconnected. + * + * The members of this struct are different based on the callback trigger. If the + * callback function was triggered for completed operation, the `operation` + * member is valid. Otherwise, if the callback was triggered because of a + * server-to-client PUBLISH, the `message` member is valid. Finally, if the callback + * was triggered because of a disconnect, the `disconnectReason` member is valid. + * + * For an incoming PUBLISH, the `message.pTopicFilter` parameter provides the + * subscription topic filter that matched the topic name in the PUBLISH. Because + * topic filters may use MQTT wildcards, the topic filter may be different from the + * topic name. This pointer must be treated as read-only; the topic filter must not + * be modified. Additionally, the topic filter may go out of scope as soon as the + * callback function returns, so it must be copied if it is needed at a later time. + * + * @attention Any pointers in this callback parameter may be freed as soon as + * the [callback function](@ref IotMqttCallbackInfo_t.function) returns. + * Therefore, data must be copied if it is needed after the callback function + * returns. + * @attention The MQTT library may set strings that are not NULL-terminated. + * + * @see #IotMqttCallbackInfo_t for the signature of a callback function. + */ +typedef struct IotMqttCallbackParam +{ + /** + * @brief The MQTT connection associated with this completed operation, + * incoming PUBLISH, or disconnect. + * + * [MQTT API functions](@ref mqtt_functions) are safe to call from a callback + * for completed operations or incoming PUBLISH messages. However, blocking + * function calls (including @ref mqtt_function_wait) are not recommended + * (though still safe). Do not call any API functions from a disconnect + * callback. + */ + IotMqttConnection_t mqttConnection; + + union + { + /* Valid for completed operations. */ + struct + { + IotMqttOperationType_t type; /**< @brief Type of operation that completed. */ + IotMqttOperation_t reference; /**< @brief Reference to the operation that completed. */ + IotMqttError_t result; /**< @brief Result of operation, e.g. succeeded or failed. */ + } operation; + + /* Valid for incoming PUBLISH messages. */ + struct + { + const char * pTopicFilter; /**< @brief Topic filter that matched the message. */ + uint16_t topicFilterLength; /**< @brief Length of `pTopicFilter`. */ + IotMqttPublishInfo_t info; /**< @brief PUBLISH message received from the server. */ + } message; + + /* Valid when a connection is disconnected. */ + IotMqttDisconnectReason_t disconnectReason; /**< @brief Why the MQTT connection was disconnected. */ + } u; /**< @brief Valid member depends on callback type. */ +} IotMqttCallbackParam_t; + +/** + * @ingroup mqtt_datatypes_paramstructs + * @brief MQTT callback function and context. + * + * @paramfor @ref mqtt_function_subscribeasync, @ref mqtt_function_unsubscribeasync, + * and @ref mqtt_function_publishasync. Cannot be used with #IOT_MQTT_FLAG_WAITABLE. + * + * Specifies a function to be invoked with optional context when an operation + * completes or when a server-to-client PUBLISH is received. + * + * @initializer{IotMqttCallbackInfo_t,IOT_MQTT_CALLBACK_INFO_INITIALIZER} + * + * Below is an example for receiving an asynchronous notification on operation + * completion. See @ref mqtt_function_subscribeasync for an example of using this struct + * with for incoming PUBLISH messages. + * + * @code{c} + * // Operation completion callback. + * void operationComplete( void * pArgument, IotMqttCallbackParam_t * pOperation ); + * + * // Callback information. + * IotMqttCallbackInfo_t callbackInfo = IOT_MQTT_CALLBACK_INFO_INITIALIZER; + * callbackInfo.function = operationComplete; + * + * // Operation to wait for. + * IotMqttError_t result = IotMqtt_PublishAsync( &mqttConnection, + * &publishInfo, + * 0, + * &callbackInfo, + * &reference ); + * + * // Publish should have returned IOT_MQTT_STATUS_PENDING. Once a response + * // is received, operationComplete is executed with the actual status passed + * // in pOperation. + * @endcode + */ +typedef struct IotMqttCallbackInfo +{ + void * pCallbackContext; /**< @brief The first parameter to pass to the callback function to provide context. */ + + /** + * @brief User-provided callback function signature. + * + * @param[in] void * #IotMqttCallbackInfo_t.pCallbackContext + * @param[in] IotMqttCallbackParam_t * Details on the outcome of the MQTT operation + * or an incoming MQTT PUBLISH. + * + * @see #IotMqttCallbackParam_t for more information on the second parameter. + */ + void ( * function )( void *, + IotMqttCallbackParam_t * ); +} IotMqttCallbackInfo_t; + +/** + * @ingroup mqtt_datatypes_paramstructs + * @brief MQTT subscription. + * + * @paramfor @ref mqtt_function_subscribeasync, @ref mqtt_function_unsubscribeasync, + * @ref mqtt_function_subscribesync, @ref mqtt_function_unsubscribesync + * + * An array of these is passed to @ref mqtt_function_subscribeasync and @ref + * mqtt_function_unsubscribeasync. However, #IotMqttSubscription_t.callback and + * and #IotMqttSubscription_t.qos are ignored by @ref mqtt_function_unsubscribeasync. + * + * @initializer{IotMqttSubscription_t,IOT_MQTT_SUBSCRIPTION_INITIALIZER} + * + * @note The lengths of the strings in this struct should not include the NULL + * terminator. Strings in this struct do not need to be NULL-terminated. + * @see #IotMqttCallbackInfo_t for details on setting a callback function. + */ +typedef struct IotMqttSubscription +{ + /** + * @brief QoS of messages delivered on subscription. + * + * Must be `0` or `1`. Ignored by @ref mqtt_function_unsubscribeasync. + */ + IotMqttQos_t qos; + + const char * pTopicFilter; /**< @brief Topic filter of subscription. */ + uint16_t topicFilterLength; /**< @brief Length of #IotMqttSubscription_t.pTopicFilter. */ + + /** + * @brief Callback to invoke when a message is received. + * + * See #IotMqttCallbackInfo_t. Ignored by @ref mqtt_function_unsubscribeasync. + */ + IotMqttCallbackInfo_t callback; +} IotMqttSubscription_t; + +/** + * @ingroup mqtt_datatypes_paramstructs + * @brief MQTT connection details. + * + * @paramfor @ref mqtt_function_connect + * + * Passed as an argument to @ref mqtt_function_connect. Most members of this struct + * correspond to the content of an [MQTT CONNECT packet.] + * (http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/csprd02/mqtt-v3.1.1-csprd02.html#_Toc385349764) + * + * @initializer{IotMqttConnectInfo_t,IOT_MQTT_CONNECT_INFO_INITIALIZER} + * + * @note The lengths of the strings in this struct should not include the NULL + * terminator. Strings in this struct do not need to be NULL-terminated. + */ +typedef struct IotMqttConnectInfo +{ + /** + * @brief Specifies if this MQTT connection is to an AWS IoT MQTT server. + * + * Set this member to `true` when connecting to the AWS IoT MQTT broker or + * `false` otherwise. Additional details about connecting to AWS IoT + * via MQTT are available [here] + * (https://docs.aws.amazon.com/iot/latest/developerguide/mqtt.html) + * + * @attention This setting MUST be `true` when using the AWS IoT MQTT + * server; it MUST be `false` otherwise. + * @note Currently, @ref IOT_MQTT_CONNECT_INFO_INITIALIZER sets this + * this member to `true`. + */ + bool awsIotMqttMode; + + /** + * @brief Whether this connection is a clean session. + * + * MQTT servers can maintain and topic filter subscriptions and unacknowledged + * PUBLISH messages. These form part of an MQTT session, which is identified by + * the [client identifier](@ref IotMqttConnectInfo_t.pClientIdentifier). + * + * Setting this value to `true` establishes a clean session, which causes + * the MQTT server to discard any previous session data for a client identifier. + * When the client disconnects, the server discards all session data. If this + * value is `true`, #IotMqttConnectInfo_t.pPreviousSubscriptions and + * #IotMqttConnectInfo_t.previousSubscriptionCount are ignored. + * + * Setting this value to `false` does one of the following: + * - If no previous session exists, the MQTT server will create a new + * persistent session. The server may maintain subscriptions and + * unacknowledged PUBLISH messages after a client disconnects, to be restored + * once the same client identifier reconnects. + * - If a previous session exists, the MQTT server restores all of the session's + * subscriptions for the client identifier and may immediately transmit any + * unacknowledged PUBLISH packets to the client. + * + * When a client with a persistent session disconnects, the MQTT server + * continues to maintain all subscriptions and unacknowledged PUBLISH messages. + * The client must also remember the session subscriptions to restore them + * upon reconnecting. #IotMqttConnectInfo_t.pPreviousSubscriptions and + * #IotMqttConnectInfo_t.previousSubscriptionCount are used to restore a + * previous session's subscriptions client-side. + */ + bool cleanSession; + + /** + * @brief An array of MQTT subscriptions present in a previous session, if any. + * + * Pointer to the start of an array of subscriptions present a previous session, + * if any. These subscriptions will be immediately restored upon reconnecting. + * + * [Optional] The field can also be used to pass a list of subscriptions to be + * stored locally without a SUBSCRIBE packet being sent to the broker. These subscriptions + * are useful to invoke application level callbacks for messages received on unsolicited + * topics from the broker. + * + * This member is ignored if it is `NULL`. If this member is not `NULL`, + * #IotMqttConnectInfo_t.previousSubscriptionCount must be nonzero. + */ + const IotMqttSubscription_t * pPreviousSubscriptions; + + /** + * @brief The number of MQTT subscriptions present in a previous session, if any. + * + * Number of subscriptions contained in the array + * #IotMqttConnectInfo_t.pPreviousSubscriptions. + * + * This value is ignored if #IotMqttConnectInfo_t.pPreviousSubscriptions + * is `NULL`. If #IotMqttConnectInfo_t.pPreviousSubscriptions is not `NULL`, + * this value must be nonzero. + */ + size_t previousSubscriptionCount; + + /** + * @brief A message to publish if the new MQTT connection is unexpectedly closed. + * + * A Last Will and Testament (LWT) message may be published if this connection is + * closed without sending an MQTT DISCONNECT packet. This pointer should be set to + * an #IotMqttPublishInfo_t representing any LWT message to publish. If an LWT + * is not needed, this member must be set to `NULL`. + * + * Unlike other PUBLISH messages, an LWT message is limited to 65535 bytes in + * length. Additionally, [pWillInfo->retryMs](@ref IotMqttPublishInfo_t.retryMs) + * and [pWillInfo->retryLimit](@ref IotMqttPublishInfo_t.retryLimit) will + * be ignored. + */ + const IotMqttPublishInfo_t * pWillInfo; + + uint16_t keepAliveSeconds; /**< @brief Period of keep-alive messages. Set to 0 to disable keep-alive. */ + + const char * pClientIdentifier; /**< @brief MQTT client identifier. */ + uint16_t clientIdentifierLength; /**< @brief Length of #IotMqttConnectInfo_t.pClientIdentifier. */ + + /* These credentials are not used by AWS IoT and may be ignored if + * awsIotMqttMode is true. */ + const char * pUserName; /**< @brief Username for MQTT connection. */ + uint16_t userNameLength; /**< @brief Length of #IotMqttConnectInfo_t.pUserName. */ + const char * pPassword; /**< @brief Password for MQTT connection. */ + uint16_t passwordLength; /**< @brief Length of #IotMqttConnectInfo_t.pPassword. */ +} IotMqttConnectInfo_t; + +/** + * @ingroup mqtt_datatypes_paramstructs + * @brief MQTT packet details. + * + * @paramfor @ref mqtt_function_deserializeresponse @ref mqtt_function_deserializepublish + * + * Passed as an argument to public low level mqtt deserialize functions. + * + * @initializer{IotMqttPacketInfo_t,IOT_MQTT_PACKET_INFO_INITIALIZER} + * + * @note This structure should be only used while accessing low level MQTT deserialization API. + * The low level serialization/ deserialization API should be only used for implementing + * light weight single threaded mqtt client. + */ +typedef struct IotMqttPacketInfo +{ + uint8_t * pRemainingData; /**< @brief (Input) The remaining data in MQTT packet. */ + size_t remainingLength; /**< @brief (Input) Length of the remaining data in the MQTT packet. */ + uint16_t packetIdentifier; /**< @brief (Output) MQTT packet identifier. */ + uint8_t type; /**< @brief (Input) A value identifying the packet type. */ + IotMqttPublishInfo_t pubInfo; /**< @brief (Output) Publish info in case of deserializing PUBLISH. */ +} IotMqttPacketInfo_t; + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * Forward declaration of the internal MQTT packet structure. + */ +struct _mqttPacket; +/** @endcond */ + +/** + * @brief Get the MQTT packet type from a stream of bytes off the network. + * + * @param[in] pNetworkConnection Reference to the network connection. + * @param[in] pNetworkInterface Function pointers used to interact with the + * network. + */ +typedef uint8_t ( * IotMqttGetPacketType_t )( void * pNetworkConnection, + const IotNetworkInterface_t * pNetworkInterface ); + +/** + * @brief Get the remaining length from a stream of bytes off the network. + * + * @param[in] pNetworkConnection Reference to the network connection. + * @param[in] pNetworkInterface Function pointers used to interact with the + * network. + */ +typedef size_t ( * IotMqttGetRemainingLength_t )( void * pNetworkConnection, + const IotNetworkInterface_t * pNetworkInterface ); + +/** + * @brief Free a packet generated by the serializer. + * + * This function pointer must be set if any other serializer override is set. + * @param[in] uint8_t* The packet to free. + */ +typedef void ( * IotMqttFreePacket_t )( uint8_t * pPacket ); + +/** + * @brief CONNECT packet serializer function. + * @param[in] IotMqttConnectInfo_t* User-provided CONNECT information. + * @param[out] uint8_t** Where the CONNECT packet is written. + * @param[out] size_t* Size of the CONNECT packet. + */ +typedef IotMqttError_t ( * IotMqttSerializeConnect_t )( const IotMqttConnectInfo_t * pConnectInfo, + uint8_t ** pConnectPacket, + size_t * pPacketSize ); + +/** + * @brief PINGREQ packet serializer function. + * @param[out] uint8_t** Where the PINGREQ packet is written. + * @param[out] size_t* Size of the PINGREQ packet. + */ +typedef IotMqttError_t ( * IotMqttSerializePingreq_t )( uint8_t ** pDisconnectPacket, + size_t * pPacketSize ); + +/** + * @brief PUBLISH packet serializer function. + * @param[in] IotMqttPublishInfo_t* User-provided PUBLISH information. + * @param[out] uint8_t** Where the PUBLISH packet is written. + * @param[out] size_t* Size of the PUBLISH packet. + * @param[out] uint16_t* The packet identifier generated for this PUBLISH. + * @param[out] uint8_t** Where the high byte of the packet identifier + * is written. + */ +typedef IotMqttError_t ( * IotMqtt_SerializePublish_t )( const IotMqttPublishInfo_t * pPublishInfo, + uint8_t ** pPublishPacket, + size_t * pPacketSize, + uint16_t * pPacketIdentifier, + uint8_t ** pPacketIdentifierHigh ); + +/** + * @brief SUBSCRIBE/UNSUBSCRIBE packet serializer function. + * @param[in] IotMqttSubscription_t* User-provided array of subscriptions. + * @param[in] size_t Number of elements in the subscription array. + * @param[out] uint8_t** Where the SUBSCRIBE packet is written. + * @param[out] size_t* Size of the SUBSCRIBE packet. + * @param[out] uint16_t* The packet identifier generated for this SUBSCRIBE. + */ +typedef IotMqttError_t ( * IotMqttSerializeSubscribe_t )( const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint8_t ** pSubscribePacket, + size_t * pPacketSize, + uint16_t * pPacketIdentifier ); + +/** + * @brief DISCONNECT packet serializer function. + * @param[out] uint8_t** Where the DISCONNECT packet is written. + * @param[out] size_t* Size of the DISCONNECT packet. + */ +typedef IotMqttError_t ( * IotMqttSerializeDisconnect_t )( uint8_t ** ppDisconnectPacket, + size_t * pPacketSize ); + +/** + * @brief MQTT packet deserializer function. + * @param[in,out] _mqttPacket* Pointer to an MQTT packet structure + */ +typedef IotMqttError_t ( * IotMqttDeserialize_t )( struct _mqttPacket * pMqttPacket ); + +/** + * @brief PUBACK packet serializer function. + * @param[in] uint16_t The packet identifier to place in PUBACK. + * @param[out] uint8_t** Where the PUBACK packet is written. + * @param[out] size_t* Size of the PUBACK packet. + */ +typedef IotMqttError_t ( * IotMqttSerializePuback_t )( uint16_t packetIdentifier, + uint8_t ** pPubackPacket, + size_t * pPacketSize ); + +/** + * @brief Set the `DUP` bit in a QoS `1` PUBLISH packet. + * @param[in] uint8_t* Pointer to the PUBLISH packet to modify. + * @param[in] uint8_t* The high byte of any packet identifier to modify. + * @param[out] uint16_t* New packet identifier (AWS IoT MQTT mode only). + */ +typedef void ( * IotMqttPublishSetDup_t )( uint8_t * pPublishPacket, + uint8_t * pPacketIdentifierHigh, + uint16_t * pNewPacketIdentifier ); + +/** + * @brief Function pointer to read the next available byte on a network connection. + * @param[in] pNetworkContext reference to network connection like socket. + * @param[out] pNextByte Pointer to the byte read from the network. + */ +typedef IotMqttError_t (* IotMqttGetNextByte_t)( void * pNetworkContext, + uint8_t * pNextByte ); + +#if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 + +/** + * @ingroup mqtt_datatypes_paramstructs + * @brief Function pointers for MQTT packet serializer overrides. + * + * These function pointers allow the MQTT serialization and deserialization functions + * to be overridden for an MQTT connection. The compile-time setting + * @ref IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES must be `1` to enable this functionality. + * See the #IotMqttSerializer_t::serialize and #IotMqttSerializer_t::deserialize + * members for a list of functions that can be overridden. In addition, the functions + * for freeing packets and determining the packet type can also be overridden. If + * @ref IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES is `1`, the serializer initialization and + * cleanup functions may be extended. See documentation of + * @ref IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES for more information. + * + * If any function pointers that are `NULL`, then the default implementation of that + * function will be used. + */ + typedef struct IotMqttSerializer + { + /** + * @brief Get the MQTT packet type from a stream of bytes off the network. + * Default implementation: #_IotMqtt_GetPacketType + */ + IotMqttGetPacketType_t getPacketType; + + /** + * @brief Get the remaining length from a stream of bytes off the network. + * Default implementation: #_IotMqtt_GetRemainingLength + */ + IotMqttGetRemainingLength_t getRemainingLength; + + /** + * @brief Free a packet generated by the serializer. + * + * Default implementation: #_IotMqtt_FreePacket + */ + IotMqttFreePacket_t freePacket; + + struct + { + /** + * @brief CONNECT packet serializer function. + * + * Default implementation: #_IotMqtt_SerializeConnect + */ + IotMqttSerializeConnect_t connect; + + /** + * @brief PUBLISH packet serializer function. + * + * Default implementation: #_IotMqtt_SerializePublish + */ + IotMqtt_SerializePublish_t publish; + + /** + * @brief Set the `DUP` bit in a QoS `1` PUBLISH packet. + * + * Default implementation: #_IotMqtt_PublishSetDup + */ + IotMqttPublishSetDup_t publishSetDup; + + /** + * @brief PUBACK packet serializer function. + * + * Default implementation: #_IotMqtt_SerializePuback + */ + IotMqttSerializePuback_t puback; + + /** + * @brief SUBSCRIBE packet serializer function. + * + * Default implementation: #_IotMqtt_SerializeSubscribe + */ + IotMqttSerializeSubscribe_t subscribe; + + /** + * @brief UNSUBSCRIBE packet serializer function. + * + * Default implementation: #_IotMqtt_SerializeUnsubscribe + */ + IotMqttSerializeSubscribe_t unsubscribe; + + /** + * @brief PINGREQ packet serializer function. + * + * Default implementation: #_IotMqtt_SerializePingreq + */ + IotMqttSerializePingreq_t pingreq; + + /** + * @brief DISCONNECT packet serializer function. + * + * Default implementation: #_IotMqtt_SerializeDisconnect + */ + IotMqttSerializeDisconnect_t disconnect; + } serialize; /**< @brief Overrides the packet serialization functions for a single connection. */ + + struct + { + /** + * @brief CONNACK packet deserializer function. + * + * Default implementation: #_IotMqtt_DeserializeConnack + */ + IotMqttDeserialize_t connack; + + /** + * @brief PUBLISH packet deserializer function. + * + * Default implementation: #_IotMqtt_DeserializePublish + */ + IotMqttDeserialize_t publish; + + /** + * @brief PUBACK packet deserializer function. + * + * Default implementation: #_IotMqtt_DeserializePuback + */ + IotMqttDeserialize_t puback; + + /** + * @brief SUBACK packet deserializer function. + * + * Default implementation: #_IotMqtt_DeserializeSuback + */ + IotMqttDeserialize_t suback; + + /** + * @brief UNSUBACK packet deserializer function. + * + * Default implementation: #_IotMqtt_DeserializeUnsuback + */ + IotMqttDeserialize_t unsuback; + + /** + * @brief PINGRESP packet deserializer function. + * + * Default implementation: #_IotMqtt_DeserializePingresp + */ + IotMqttDeserialize_t pingresp; + } deserialize; /**< @brief Overrides the packet deserialization functions for a single connection. */ + } IotMqttSerializer_t; + +#else /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */ + +/* When MQTT packet serializer overrides are disabled, this struct is an + * incomplete type. */ + typedef struct IotMqttSerializer IotMqttSerializer_t; + +#endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */ + +/** + * @ingroup mqtt_datatypes_paramstructs + * @brief MQTT network connection details. + * + * @paramfor @ref mqtt_function_connect + * + * The MQTT library needs to be able to send and receive data over a network. + * This struct provides an interface for interacting with the network. + * + * @initializer{IotMqttNetworkInfo_t,IOT_MQTT_NETWORK_INFO_INITIALIZER} + */ +typedef struct IotMqttNetworkInfo +{ + /** + * @brief Whether a new network connection should be created. + * + * When this value is `true`, a new transport-layer network connection will + * be created along with the MQTT connection. #IotMqttNetworkInfo_t::pNetworkServerInfo + * and #IotMqttNetworkInfo_t::pNetworkCredentialInfo are valid when this value + * is `true`. + * + * When this value is `false`, the MQTT connection will use a transport-layer + * network connection that has already been established. The MQTT library will + * still set the appropriate receive callback even if the network connection + * has been established. + * #IotMqttNetworkInfo_t::pNetworkConnection, which represents an established + * network connection, is valid when this value is `false`. + */ + bool createNetworkConnection; + + union + { + struct + { + /** + * @brief Information on the MQTT server, passed as `pServerInfo` to + * #IotNetworkInterface_t::create. + * + * This member is opaque to the MQTT library. It is passed to the network + * interface when creating a new network connection. It is only valid when + * #IotMqttNetworkInfo_t::createNetworkConnection is `true`. + */ + IotNetworkServerInfo_t pNetworkServerInfo; + + /** + * @brief Credentials for the MQTT server, passed as `pCredentialInfo` to + * #IotNetworkInterface_t::create. + * + * This member is opaque to the MQTT library. It is passed to the network + * interface when creating a new network connection. It is only valid when + * #IotMqttNetworkInfo_t::createNetworkConnection is `true`. + */ + IotNetworkCredentials_t pNetworkCredentialInfo; + } setup; + + /** + * @brief An established transport-layer network connection. + * + * This member is opaque to the MQTT library. It is passed to the network + * interface to reference an established network connection. It is only + * valid when #IotMqttNetworkInfo_t::createNetworkConnection is `false`. + */ + IotNetworkConnection_t pNetworkConnection; + } u /**< @brief Valid member depends of IotMqttNetworkInfo_t.createNetworkConnection. */; + + /** + * @brief The network functions used by the new MQTT connection. + * + * @attention The function pointers of the network interface must remain valid + * for the lifetime of the MQTT connection. + */ + const IotNetworkInterface_t * pNetworkInterface; + + /** + * @brief A callback function to invoke when this MQTT connection is disconnected. + */ + IotMqttCallbackInfo_t disconnectCallback; + + #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 + + /** + * @brief MQTT packet serializer overrides used by the new MQTT connection. + * + * @attention The function pointers of the MQTT serializer overrides must + * remain valid for the lifetime of the MQTT connection. + */ + const IotMqttSerializer_t * pMqttSerializer; + #endif +} IotMqttNetworkInfo_t; + +/*------------------------- MQTT defined constants --------------------------*/ + +/** + * @constantspage{mqtt,MQTT library} + * + * @section mqtt_constants_initializers MQTT Initializers + * @brief Provides default values for the data types of the MQTT library. + * + * @snippet this define_mqtt_initializers + * + * All user-facing data types of the MQTT library should be initialized using + * one of the following. + * + * @warning Failing to initialize an MQTT data type with the appropriate initializer + * may result in undefined behavior! + * @note The initializers may change at any time in future versions, but their + * names will remain the same. + * + * Example + * @code{c} + * IotMqttNetworkInfo_t networkInfo = IOT_MQTT_NETWORK_INFO_INITIALIZER; + * IotMqttSerializer_t serializer = IOT_MQTT_SERIALIZER_INITIALIZER; + * IotMqttConnectInfo_t connectInfo = IOT_MQTT_CONNECT_INFO_INITIALIZER; + * IotMqttPublishInfo_t publishInfo = IOT_MQTT_PUBLISH_INFO_INITIALIZER; + * IotMqttSubscription_t subscription = IOT_MQTT_SUBSCRIPTION_INITIALIZER; + * IotMqttCallbackInfo_t callbackInfo = IOT_MQTT_CALLBACK_INFO_INITIALIZER; + * IotMqttConnection_t connection = IOT_MQTT_CONNECTION_INITIALIZER; + * IotMqttOperation_t operation = IOT_MQTT_OPERATION_INITIALIZER; + * @endcode + * + * @section mqtt_constants_flags MQTT Function Flags + * @brief Flags that modify the behavior of MQTT library functions. + * - #IOT_MQTT_FLAG_WAITABLE
+ * @copybrief IOT_MQTT_FLAG_WAITABLE + * - #IOT_MQTT_FLAG_CLEANUP_ONLY
+ * @copybrief IOT_MQTT_FLAG_CLEANUP_ONLY + * + * Flags should be bitwise-ORed with each other to change the behavior of + * @ref mqtt_function_subscribeasync, @ref mqtt_function_unsubscribeasync, + * @ref mqtt_function_publishasync, their blocking versions; or @ref mqtt_function_disconnect. + * + * @note The values of the flags may change at any time in future versions, but + * their names will remain the same. Additionally, flags that may be used together + * will be bitwise-exclusive of each other. + */ + +/* @[define_mqtt_initializers] */ +/** @brief Initializer for #IotMqttNetworkInfo_t. */ +#define IOT_MQTT_NETWORK_INFO_INITIALIZER { .createNetworkConnection = true } +/** @brief Initializer for #IotMqttSerializer_t. */ +#define IOT_MQTT_SERIALIZER_INITIALIZER { 0 } +/** @brief Initializer for #IotMqttConnectInfo_t. */ +#define IOT_MQTT_CONNECT_INFO_INITIALIZER { .cleanSession = true } +/** @brief Initializer for #IotMqttPublishInfo_t. */ +#define IOT_MQTT_PUBLISH_INFO_INITIALIZER { .qos = IOT_MQTT_QOS_0 } +/** @brief Initializer for #IotMqttSubscription_t. */ +#define IOT_MQTT_SUBSCRIPTION_INITIALIZER { .qos = IOT_MQTT_QOS_0 } +/** @brief Initializer for #IotMqttCallbackInfo_t. */ +#define IOT_MQTT_CALLBACK_INFO_INITIALIZER { 0 } +/** @brief Initializer for #IotMqttConnection_t. */ +#define IOT_MQTT_CONNECTION_INITIALIZER NULL +/** @brief Initializer for #IotMqttOperation_t. */ +#define IOT_MQTT_OPERATION_INITIALIZER NULL +/** @brief Initializer for #IotMqttPacketInfo_t. */ +#define IOT_MQTT_PACKET_INFO_INITIALIZER { .pRemainingData = NULL, remainingLength = 0, packetIdentifier = 0, .type = 0 } +/* @[define_mqtt_initializers] */ + +/** + * @brief Allows the use of @ref mqtt_function_wait for blocking until completion. + * + * This flag is always valid for @ref mqtt_function_subscribeasync and + * @ref mqtt_function_unsubscribeasync. If passed to @ref mqtt_function_publishasync, + * the parameter [pPublishInfo->qos](@ref IotMqttPublishInfo_t.qos) must not be `0`. + * + * An #IotMqttOperation_t MUST be provided if this flag is set. Additionally, an + * #IotMqttCallbackInfo_t MUST NOT be provided. + * + * @note If this flag is set, @ref mqtt_function_wait MUST be called to clean up + * resources. + */ +#define IOT_MQTT_FLAG_WAITABLE ( 0x00000001 ) + +/** + * @brief Causes @ref mqtt_function_disconnect to only free memory and not send + * an MQTT DISCONNECT packet. + * + * This flag is only valid for @ref mqtt_function_disconnect. It should be passed + * to @ref mqtt_function_disconnect if the network goes offline or is otherwise + * unusable. + */ +#define IOT_MQTT_FLAG_CLEANUP_ONLY ( 0x00000001 ) + +#endif /* ifndef IOT_MQTT_TYPES_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_api.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_api.c new file mode 100644 index 000000000..a95a73c32 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_api.c @@ -0,0 +1,2145 @@ +/* + * IoT MQTT V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_mqtt_api.c + * @brief Implements most user-facing functions of the MQTT library. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* Error handling include. */ +#include "iot_error.h" + +/* MQTT internal include. */ +#include "private/iot_mqtt_internal.h" + +/* Platform layer includes. */ +#include "platform/iot_clock.h" +#include "platform/iot_threads.h" + +/* Atomics include. */ +#include "iot_atomic.h" + +/* Validate MQTT configuration settings. */ +#if IOT_MQTT_ENABLE_ASSERTS != 0 && IOT_MQTT_ENABLE_ASSERTS != 1 + #error "IOT_MQTT_ENABLE_ASSERTS must be 0 or 1." +#endif +#if IOT_MQTT_ENABLE_METRICS != 0 && IOT_MQTT_ENABLE_METRICS != 1 + #error "IOT_MQTT_ENABLE_METRICS must be 0 or 1." +#endif +#if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES != 0 && IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES != 1 + #error "IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES must be 0 or 1." +#endif +#if IOT_MQTT_RESPONSE_WAIT_MS <= 0 + #error "IOT_MQTT_RESPONSE_WAIT_MS cannot be 0 or negative." +#endif +#if IOT_MQTT_RETRY_MS_CEILING <= 0 + #error "IOT_MQTT_RETRY_MS_CEILING cannot be 0 or negative." +#endif + +/*-----------------------------------------------------------*/ + +/** + * @brief Uninitialized value for @ref _initCalled. + */ +#define MQTT_LIBRARY_UNINITIALIZED ( ( uint32_t ) 0 ) + +/** + * @brief Initialized value for @ref _initCalled. + */ +#define MQTT_LIBRARY_INITIALIZED ( ( uint32_t ) 1 ) + +/*-----------------------------------------------------------*/ + +/** + * @brief Check if the library is initialized. + * + * @return `true` if IotMqtt_Init was called; `false` otherwise. + */ +static bool _checkInit( void ); + +/** + * @brief Set the unsubscribed flag of an MQTT subscription. + * + * @param[in] pSubscriptionLink Pointer to the link member of an #_mqttSubscription_t. + * @param[in] pMatch Not used. + * + * @return Always returns `true`. + */ +static bool _mqttSubscription_setUnsubscribe( const IotLink_t * pSubscriptionLink, + void * pMatch ); + +/** + * @brief Destroy an MQTT subscription if its reference count is 0. + * + * @param[in] pData The subscription to destroy. This parameter is of type + * `void*` for compatibility with [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ +static void _mqttSubscription_tryDestroy( void * pData ); + +/** + * @brief Decrement the reference count of an MQTT operation and attempt to + * destroy it. + * + * @param[in] pData The operation data to destroy. This parameter is of type + * `void*` for compatibility with [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ +static void _mqttOperation_tryDestroy( void * pData ); + +/** + * @brief Initialize the keep-alive operation for an MQTT connection. + * + * @param[in] pNetworkInfo User-provided network information for the new + * connection. + * @param[in] keepAliveSeconds User-provided keep-alive interval. + * @param[out] pMqttConnection The MQTT connection associated with the keep-alive. + * + * @return `true` if the keep-alive job was successfully created; `false` otherwise. + */ +static bool _createKeepAliveOperation( const IotMqttNetworkInfo_t * pNetworkInfo, + uint16_t keepAliveSeconds, + _mqttConnection_t * pMqttConnection ); + +/** + * @brief Initialize a network connection, creating it if necessary. + * + * @param[in] pNetworkInfo User-provided network information for the connection + * connection. + * @param[out] pNetworkConnection On success, the created and/or initialized network connection. + * @param[out] pCreatedNewNetworkConnection On success, `true` if a new network connection was created; `false` if an existing one will be used. + * + * @return Any #IotNetworkError_t, as defined by the network stack. + */ +static IotNetworkError_t _createNetworkConnection( const IotMqttNetworkInfo_t * pNetworkInfo, + IotNetworkConnection_t * pNetworkConnection, + bool * pCreatedNewNetworkConnection ); + +/** + * @brief Creates a new MQTT connection and initializes its members. + * + * @param[in] awsIotMqttMode Specifies if this connection is to an AWS IoT MQTT server. + * @param[in] pNetworkInfo User-provided network information for the new + * connection. + * @param[in] keepAliveSeconds User-provided keep-alive interval for the new connection. + * + * @return Pointer to a newly-created MQTT connection; `NULL` on failure. + */ +static _mqttConnection_t * _createMqttConnection( bool awsIotMqttMode, + const IotMqttNetworkInfo_t * pNetworkInfo, + uint16_t keepAliveSeconds ); + +/** + * @brief Destroys the members of an MQTT connection. + * + * @param[in] pMqttConnection Which connection to destroy. + */ +static void _destroyMqttConnection( _mqttConnection_t * pMqttConnection ); + +/** + * @brief Common setup function for subscribe and unsubscribe operations. + * + * See @ref mqtt_function_subscribeasync or @ref mqtt_function_unsubscribeasync for a + * description of the parameters and return values. + */ +static IotMqttError_t _subscriptionCommonSetup( IotMqttOperationType_t operation, + IotMqttConnection_t mqttConnection, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + IotMqttOperation_t * const pOperationReference ); + +/** + * @brief Utility function for creating and serializing subscription requests + * + * See @ref mqtt_function_subscribeasync or @ref mqtt_function_unsubscribeasync for a + * description of the parameters and return values. + */ +static IotMqttError_t _subscriptionCreateAndSerialize( IotMqttOperationType_t operation, + IotMqttConnection_t mqttConnection, + IotMqttSerializeSubscribe_t serializeSubscription, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + const IotMqttCallbackInfo_t * pCallbackInfo, + _mqttOperation_t ** ppSubscriptionOperation ); + +/** + * @brief The common component of both @ref mqtt_function_subscribeasync and @ref + * mqtt_function_unsubscribeasync. + * + * See @ref mqtt_function_subscribeasync or @ref mqtt_function_unsubscribeasync for a + * description of the parameters and return values. + */ +static IotMqttError_t _subscriptionCommon( IotMqttOperationType_t operation, + IotMqttConnection_t mqttConnection, + IotMqttSerializeSubscribe_t serializeSubscription, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + const IotMqttCallbackInfo_t * pCallbackInfo, + IotMqttOperation_t * const pOperationReference ); + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * Declaration of local MQTT serializer override selectors + */ +#if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttSerializePingreq_t, + _getMqttPingreqSerializer, + _IotMqtt_SerializePingreq, + serialize.pingreq ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqtt_SerializePublish_t, + _getMqttPublishSerializer, + _IotMqtt_SerializePublish, + serialize.publish ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttFreePacket_t, + _getMqttFreePacketFunc, + _IotMqtt_FreePacket, + freePacket ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttSerializeSubscribe_t, + _getMqttSubscribeSerializer, + _IotMqtt_SerializeSubscribe, + serialize.subscribe ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttSerializeSubscribe_t, + _getMqttUnsubscribeSerializer, + _IotMqtt_SerializeUnsubscribe, + serialize.unsubscribe ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttSerializeConnect_t, + _getMqttConnectSerializer, + _IotMqtt_SerializeConnect, + serialize.connect ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttSerializeDisconnect_t, + _getMqttDisconnectSerializer, + _IotMqtt_SerializeDisconnect, + serialize.disconnect ) +#else /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */ + #define _getMqttPingreqSerializer( pSerializer ) _IotMqtt_SerializePingreq + #define _getMqttPublishSerializer( pSerializer ) _IotMqtt_SerializePublish + #define _getMqttFreePacketFunc( pSerializer ) _IotMqtt_FreePacket + #define _getMqttSubscribeSerializer( pSerializer ) _IotMqtt_SerializeSubscribe + #define _getMqttUnsubscribeSerializer( pSerializer ) _IotMqtt_SerializeUnsubscribe + #define _getMqttConnectSerializer( pSerializer ) _IotMqtt_SerializeConnect + #define _getMqttDisconnectSerializer( pSerializer ) _IotMqtt_SerializeDisconnect +#endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */ +/** @endcond */ + +/*-----------------------------------------------------------*/ + +/** + * @brief Tracks whether @ref mqtt_function_init has been called. + * + * API functions will fail if @ref mqtt_function_init was not called. + */ +static volatile uint32_t _initCalled = MQTT_LIBRARY_UNINITIALIZED; + +/*-----------------------------------------------------------*/ + +static bool _checkInit( void ) +{ + bool status = true; + + if( _initCalled == MQTT_LIBRARY_UNINITIALIZED ) + { + IotLogError( "IotMqtt_Init was not called." ); + + status = false; + } + else + { + EMPTY_ELSE_MARKER; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +static bool _mqttSubscription_setUnsubscribe( const IotLink_t * pSubscriptionLink, + void * pMatch ) +{ + /* Because this function is called from a container function, the given link + * must never be NULL. */ + IotMqtt_Assert( pSubscriptionLink != NULL ); + + _mqttSubscription_t * pSubscription = IotLink_Container( _mqttSubscription_t, + pSubscriptionLink, + link ); + + /* Silence warnings about unused parameters. */ + ( void ) pMatch; + + /* Set the unsubscribed flag. */ + pSubscription->unsubscribed = true; + + return true; +} + +/*-----------------------------------------------------------*/ + +static void _mqttSubscription_tryDestroy( void * pData ) +{ + _mqttSubscription_t * pSubscription = ( _mqttSubscription_t * ) pData; + + /* Reference count must not be negative. */ + IotMqtt_Assert( pSubscription->references >= 0 ); + + /* Unsubscribed flag should be set. */ + IotMqtt_Assert( pSubscription->unsubscribed == true ); + + /* Free the subscription if it has no references. */ + if( pSubscription->references == 0 ) + { + IotMqtt_FreeSubscription( pSubscription ); + } + else + { + EMPTY_ELSE_MARKER; + } +} + +/*-----------------------------------------------------------*/ + +static void _mqttOperation_tryDestroy( void * pData ) +{ + _mqttOperation_t * pOperation = ( _mqttOperation_t * ) pData; + IotTaskPoolError_t taskPoolStatus = IOT_TASKPOOL_SUCCESS; + + /* Incoming PUBLISH operations may always be freed. */ + if( pOperation->incomingPublish == true ) + { + /* Cancel the incoming PUBLISH operation's job. */ + taskPoolStatus = IotTaskPool_TryCancel( IOT_SYSTEM_TASKPOOL, + pOperation->job, + NULL ); + + /* If the operation's job was not canceled, it must be already executing. + * Any other return value is invalid. */ + IotMqtt_Assert( ( taskPoolStatus == IOT_TASKPOOL_SUCCESS ) || + ( taskPoolStatus == IOT_TASKPOOL_CANCEL_FAILED ) ); + + /* Check if the incoming PUBLISH job was canceled. */ + if( taskPoolStatus == IOT_TASKPOOL_SUCCESS ) + { + /* Job was canceled. Process incoming PUBLISH now to clean up. */ + _IotMqtt_ProcessIncomingPublish( IOT_SYSTEM_TASKPOOL, + pOperation->job, + pOperation ); + } + else + { + /* The executing job will process the PUBLISH, so nothing is done here. */ + EMPTY_ELSE_MARKER; + } + } + else + { + /* Decrement reference count and destroy operation if possible. */ + if( _IotMqtt_DecrementOperationReferences( pOperation, true ) == true ) + { + _IotMqtt_DestroyOperation( pOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + } +} + +/*-----------------------------------------------------------*/ + +static bool _createKeepAliveOperation( const IotMqttNetworkInfo_t * pNetworkInfo, + uint16_t keepAliveSeconds, + _mqttConnection_t * pMqttConnection ) +{ + bool status = true; + IotMqttError_t serializeStatus = IOT_MQTT_SUCCESS; + IotTaskPoolError_t jobStatus = IOT_TASKPOOL_SUCCESS; + + /* Network information is not used when MQTT packet serializers are disabled. */ + ( void ) pNetworkInfo; + + /* Set PINGREQ operation members. */ + pMqttConnection->pingreq.u.operation.type = IOT_MQTT_PINGREQ; + + /* Convert the keep-alive interval to milliseconds. */ + pMqttConnection->pingreq.u.operation.periodic.ping.keepAliveMs = keepAliveSeconds * 1000; + pMqttConnection->pingreq.u.operation.periodic.ping.nextPeriodMs = keepAliveSeconds * 1000; + + /* Generate a PINGREQ packet. */ + serializeStatus = _getMqttPingreqSerializer( pMqttConnection->pSerializer )( &( pMqttConnection->pingreq.u.operation.pMqttPacket ), + &( pMqttConnection->pingreq.u.operation.packetSize ) ); + + if( serializeStatus != IOT_MQTT_SUCCESS ) + { + IotLogError( "Failed to allocate PINGREQ packet for new connection." ); + + status = false; + } + else + { + /* Create the task pool job that processes keep-alive. */ + jobStatus = IotTaskPool_CreateJob( _IotMqtt_ProcessKeepAlive, + pMqttConnection, + &( pMqttConnection->pingreq.jobStorage ), + &( pMqttConnection->pingreq.job ) ); + + /* Task pool job creation for a pre-allocated job should never fail. + * Abort the program if it does. */ + if( jobStatus != IOT_TASKPOOL_SUCCESS ) + { + IotLogError( "Failed to create keep-alive job for new connection." ); + + IotMqtt_Assert( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Keep-alive references its MQTT connection, so increment reference. */ + ( pMqttConnection->references )++; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +static IotNetworkError_t _createNetworkConnection( const IotMqttNetworkInfo_t * pNetworkInfo, + IotNetworkConnection_t * pNetworkConnection, + bool * pCreatedNewNetworkConnection ) +{ + IOT_FUNCTION_ENTRY( IotNetworkError_t, IOT_NETWORK_SUCCESS ); + + /* Network info must not be NULL. */ + if( pNetworkInfo == NULL ) + { + IotLogError( "Network information cannot be NULL." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_NETWORK_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Create a new network connection if requested. Otherwise, copy the existing + * network connection. */ + if( pNetworkInfo->createNetworkConnection == true ) + { + status = pNetworkInfo->pNetworkInterface->create( pNetworkInfo->u.setup.pNetworkServerInfo, + pNetworkInfo->u.setup.pNetworkCredentialInfo, + pNetworkConnection ); + + if( status == IOT_NETWORK_SUCCESS ) + { + /* This MQTT connection owns the network connection it created and + * should destroy it on cleanup. */ + *pCreatedNewNetworkConnection = true; + } + else + { + IotLogError( "Failed to create network connection: %d", status ); + + IOT_GOTO_CLEANUP(); + } + } + else + { + /* A connection already exists; the caller should not destroy + * it on cleanup. */ + *pNetworkConnection = pNetworkInfo->u.pNetworkConnection; + *pCreatedNewNetworkConnection = false; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static _mqttConnection_t * _createMqttConnection( bool awsIotMqttMode, + const IotMqttNetworkInfo_t * pNetworkInfo, + uint16_t keepAliveSeconds ) +{ + IOT_FUNCTION_ENTRY( bool, true ); + _mqttConnection_t * pMqttConnection = NULL; + bool referencesMutexCreated = false, subscriptionMutexCreated = false; + + /* Allocate memory for the new MQTT connection. */ + pMqttConnection = IotMqtt_MallocConnection( sizeof( _mqttConnection_t ) ); + + if( pMqttConnection == NULL ) + { + IotLogError( "Failed to allocate memory for new connection." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + /* Clear the MQTT connection, then copy the MQTT server mode, network + * interface, and disconnect callback. */ + ( void ) memset( pMqttConnection, 0x00, sizeof( _mqttConnection_t ) ); + pMqttConnection->awsIotMqttMode = awsIotMqttMode; + pMqttConnection->pNetworkInterface = pNetworkInfo->pNetworkInterface; + pMqttConnection->disconnectCallback = pNetworkInfo->disconnectCallback; + + /* Start a new MQTT connection with a reference count of 1. */ + pMqttConnection->references = 1; + } + + /* Create the references mutex for a new connection. It is a recursive mutex. */ + referencesMutexCreated = IotMutex_Create( &( pMqttConnection->referencesMutex ), true ); + + if( referencesMutexCreated == false ) + { + IotLogError( "Failed to create references mutex for new connection." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Create the subscription mutex for a new connection. */ + subscriptionMutexCreated = IotMutex_Create( &( pMqttConnection->subscriptionMutex ), false ); + + if( subscriptionMutexCreated == false ) + { + IotLogError( "Failed to create subscription mutex for new connection." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Create the new connection's subscription and operation lists. */ + IotListDouble_Create( &( pMqttConnection->subscriptionList ) ); + IotListDouble_Create( &( pMqttConnection->pendingProcessing ) ); + IotListDouble_Create( &( pMqttConnection->pendingResponse ) ); + + /* Check if keep-alive is active for this connection. */ + if( keepAliveSeconds != 0 ) + { + if( _createKeepAliveOperation( pNetworkInfo, + keepAliveSeconds, + pMqttConnection ) == false ) + { + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Clean up mutexes and connection if this function failed. */ + IOT_FUNCTION_CLEANUP_BEGIN(); + + if( status == false ) + { + if( subscriptionMutexCreated == true ) + { + IotMutex_Destroy( &( pMqttConnection->subscriptionMutex ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + + if( referencesMutexCreated == true ) + { + IotMutex_Destroy( &( pMqttConnection->referencesMutex ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + + if( pMqttConnection != NULL ) + { + IotMqtt_FreeConnection( pMqttConnection ); + pMqttConnection = NULL; + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + return pMqttConnection; +} + +/*-----------------------------------------------------------*/ + +static void _destroyMqttConnection( _mqttConnection_t * pMqttConnection ) +{ + IotNetworkError_t networkStatus = IOT_NETWORK_SUCCESS; + + /* Clean up keep-alive if still allocated. */ + if( pMqttConnection->pingreq.u.operation.periodic.ping.keepAliveMs != 0 ) + { + IotLogDebug( "(MQTT connection %p) Cleaning up keep-alive.", pMqttConnection ); + + _getMqttFreePacketFunc( pMqttConnection->pSerializer )( pMqttConnection->pingreq.u.operation.pMqttPacket ); + + /* Clear data about the keep-alive. */ + pMqttConnection->pingreq.u.operation.periodic.ping.keepAliveMs = 0; + pMqttConnection->pingreq.u.operation.pMqttPacket = NULL; + pMqttConnection->pingreq.u.operation.packetSize = 0; + + /* Decrement reference count. */ + pMqttConnection->references--; + } + else + { + EMPTY_ELSE_MARKER; + } + + /* A connection to be destroyed should have no keep-alive and at most 1 + * reference. */ + IotMqtt_Assert( pMqttConnection->references <= 1 ); + IotMqtt_Assert( pMqttConnection->pingreq.u.operation.periodic.ping.keepAliveMs == 0 ); + IotMqtt_Assert( pMqttConnection->pingreq.u.operation.pMqttPacket == NULL ); + IotMqtt_Assert( pMqttConnection->pingreq.u.operation.packetSize == 0 ); + + /* Remove all subscriptions. */ + IotMutex_Lock( &( pMqttConnection->subscriptionMutex ) ); + IotListDouble_RemoveAllMatches( &( pMqttConnection->subscriptionList ), + _mqttSubscription_setUnsubscribe, + NULL, + _mqttSubscription_tryDestroy, + offsetof( _mqttSubscription_t, link ) ); + IotMutex_Unlock( &( pMqttConnection->subscriptionMutex ) ); + + /* Destroy an owned network connection. */ + if( pMqttConnection->ownNetworkConnection == true ) + { + networkStatus = pMqttConnection->pNetworkInterface->destroy( pMqttConnection->pNetworkConnection ); + + if( networkStatus != IOT_NETWORK_SUCCESS ) + { + IotLogWarn( "(MQTT connection %p) Failed to destroy network connection.", + pMqttConnection ); + } + else + { + IotLogInfo( "(MQTT connection %p) Network connection destroyed.", + pMqttConnection ); + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Destroy mutexes. */ + IotMutex_Destroy( &( pMqttConnection->referencesMutex ) ); + IotMutex_Destroy( &( pMqttConnection->subscriptionMutex ) ); + + IotLogDebug( "(MQTT connection %p) Connection destroyed.", pMqttConnection ); + + /* Free connection. */ + IotMqtt_FreeConnection( pMqttConnection ); +} + +/*-----------------------------------------------------------*/ +static IotMqttError_t _subscriptionCommonSetup( IotMqttOperationType_t operation, + IotMqttConnection_t mqttConnection, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + IotMqttOperation_t * const pOperationReference ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + + /* This function should only be called for subscribe or unsubscribe. */ + IotMqtt_Assert( ( operation == IOT_MQTT_SUBSCRIBE ) || + ( operation == IOT_MQTT_UNSUBSCRIBE ) ); + + /* Check that IotMqtt_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NOT_INITIALIZED ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check that all elements in the subscription list are valid. */ + if( _IotMqtt_ValidateSubscriptionList( operation, + mqttConnection->awsIotMqttMode, + pSubscriptionList, + subscriptionCount ) == false ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check that a reference pointer is provided for a waitable operation. */ + if( ( flags & IOT_MQTT_FLAG_WAITABLE ) == IOT_MQTT_FLAG_WAITABLE ) + { + if( pOperationReference == NULL ) + { + IotLogError( "Reference must be provided for a waitable %s.", + IotMqtt_OperationType( operation ) ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static IotMqttError_t _subscriptionCreateAndSerialize( IotMqttOperationType_t operation, + IotMqttConnection_t mqttConnection, + IotMqttSerializeSubscribe_t serializeSubscription, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + const IotMqttCallbackInfo_t * pCallbackInfo, + _mqttOperation_t ** ppSubscriptionOperation ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + _mqttOperation_t * pSubscriptionOperation = NULL; + + /* Create a subscription operation. */ + status = _IotMqtt_CreateOperation( mqttConnection, + flags, + pCallbackInfo, + ppSubscriptionOperation ); + + if( status != IOT_MQTT_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + else + { + pSubscriptionOperation = ( *ppSubscriptionOperation ); + } + + /* Check the subscription operation data and set the operation type. */ + IotMqtt_Assert( pSubscriptionOperation->u.operation.status == IOT_MQTT_STATUS_PENDING ); + IotMqtt_Assert( pSubscriptionOperation->u.operation.periodic.retry.limit == 0 ); + pSubscriptionOperation->u.operation.type = operation; + + /* Generate a subscription packet from the subscription list. */ + status = serializeSubscription( pSubscriptionList, + subscriptionCount, + &( pSubscriptionOperation->u.operation.pMqttPacket ), + &( pSubscriptionOperation->u.operation.packetSize ), + &( pSubscriptionOperation->u.operation.packetIdentifier ) ); + + if( status != IOT_MQTT_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check the serialized MQTT packet. */ + IotMqtt_Assert( pSubscriptionOperation->u.operation.pMqttPacket != NULL ); + IotMqtt_Assert( pSubscriptionOperation->u.operation.packetSize > 0 ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static IotMqttError_t _subscriptionCommon( IotMqttOperationType_t operation, + IotMqttConnection_t mqttConnection, + IotMqttSerializeSubscribe_t serializeSubscription, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + const IotMqttCallbackInfo_t * pCallbackInfo, + IotMqttOperation_t * const pOperationReference ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + _mqttOperation_t * pSubscriptionOperation = NULL; + + /* Create and serialize the subscription operation. */ + status = _subscriptionCreateAndSerialize( operation, + mqttConnection, + serializeSubscription, + pSubscriptionList, + subscriptionCount, + flags, + pCallbackInfo, + &pSubscriptionOperation ); + + if( status != IOT_MQTT_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Add the subscription list for a SUBSCRIBE. */ + if( operation == IOT_MQTT_SUBSCRIBE ) + { + status = _IotMqtt_AddSubscriptions( mqttConnection, + pSubscriptionOperation->u.operation.packetIdentifier, + pSubscriptionList, + subscriptionCount ); + + if( status != IOT_MQTT_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + else + { + EMPTY_ELSE_MARKER; + } + } + + /* Set the reference, if provided. */ + if( pOperationReference != NULL ) + { + *pOperationReference = pSubscriptionOperation; + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Send the SUBSCRIBE packet. */ + if( ( flags & MQTT_INTERNAL_FLAG_BLOCK_ON_SEND ) == MQTT_INTERNAL_FLAG_BLOCK_ON_SEND ) + { + _IotMqtt_ProcessSend( IOT_SYSTEM_TASKPOOL, pSubscriptionOperation->job, pSubscriptionOperation ); + } + else + { + status = _IotMqtt_ScheduleOperation( pSubscriptionOperation, + _IotMqtt_ProcessSend, + 0 ); + + if( status != IOT_MQTT_SUCCESS ) + { + IotLogError( "(MQTT connection %p) Failed to schedule %s for sending.", + mqttConnection, + IotMqtt_OperationType( operation ) ); + + if( operation == IOT_MQTT_SUBSCRIBE ) + { + _IotMqtt_RemoveSubscriptionByPacket( mqttConnection, + pSubscriptionOperation->u.operation.packetIdentifier, + MQTT_REMOVE_ALL_SUBSCRIPTIONS ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Clear the previously set (and now invalid) reference. */ + if( pOperationReference != NULL ) + { + *pOperationReference = IOT_MQTT_OPERATION_INITIALIZER; + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_GOTO_CLEANUP(); + } + } + + /* Clean up if this function failed. */ + IOT_FUNCTION_CLEANUP_BEGIN(); + + if( status != IOT_MQTT_SUCCESS ) + { + if( pSubscriptionOperation != NULL ) + { + _IotMqtt_DestroyOperation( pSubscriptionOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + status = IOT_MQTT_STATUS_PENDING; + + IotLogInfo( "(MQTT connection %p) %s operation scheduled.", + mqttConnection, + IotMqtt_OperationType( operation ) ); + } + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +bool _IotMqtt_IncrementConnectionReferences( _mqttConnection_t * pMqttConnection ) +{ + bool disconnected = false; + + /* Lock the mutex protecting the reference count. */ + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + + /* Reference count must not be negative. */ + IotMqtt_Assert( pMqttConnection->references >= 0 ); + + /* Read connection status. */ + disconnected = pMqttConnection->disconnected; + + /* Increment the connection's reference count if it is not disconnected. */ + if( disconnected == false ) + { + ( pMqttConnection->references )++; + IotLogDebug( "(MQTT connection %p) Reference count changed from %ld to %ld.", + pMqttConnection, + ( long int ) pMqttConnection->references - 1, + ( long int ) pMqttConnection->references ); + } + else + { + IotLogWarn( "(MQTT connection %p) Attempt to use closed connection.", pMqttConnection ); + } + + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + + return( disconnected == false ); +} + +/*-----------------------------------------------------------*/ + +void _IotMqtt_DecrementConnectionReferences( _mqttConnection_t * pMqttConnection ) +{ + bool destroyConnection = false; + + /* Lock the mutex protecting the reference count. */ + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + + /* Decrement reference count. It must not be negative. */ + ( pMqttConnection->references )--; + IotMqtt_Assert( pMqttConnection->references >= 0 ); + + IotLogDebug( "(MQTT connection %p) Reference count changed from %ld to %ld.", + pMqttConnection, + ( long int ) pMqttConnection->references + 1, + ( long int ) pMqttConnection->references ); + + /* Check if this connection may be destroyed. */ + if( pMqttConnection->references == 0 ) + { + destroyConnection = true; + } + else + { + EMPTY_ELSE_MARKER; + } + + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + + /* Destroy an unreferenced MQTT connection. */ + if( destroyConnection == true ) + { + IotLogDebug( "(MQTT connection %p) Connection will be destroyed now.", + pMqttConnection ); + _destroyMqttConnection( pMqttConnection ); + } + else + { + EMPTY_ELSE_MARKER; + } +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_Init( void ) +{ + IotMqttError_t status = IOT_MQTT_SUCCESS; + uint32_t allowInitialization = Atomic_CompareAndSwap_u32( &_initCalled, + MQTT_LIBRARY_INITIALIZED, + MQTT_LIBRARY_UNINITIALIZED ); + + if( allowInitialization == 1 ) + { + /* Call any additional serializer initialization function if serializer + * overrides are enabled. */ + #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 + #ifdef _IotMqtt_InitSerializeAdditional + if( _IotMqtt_InitSerializeAdditional() == false ) + { + /* Log initialization status. */ + IotLogError( "Failed to initialize MQTT library serializer. " ); + + status = IOT_MQTT_INIT_FAILED; + } + else + { + EMPTY_ELSE_MARKER; + } + #endif /* ifdef _IotMqtt_InitSerializeAdditional */ + #endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */ + + if( status == IOT_MQTT_SUCCESS ) + { + IotLogInfo( "MQTT library successfully initialized." ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + IotLogWarn( "IotMqtt_Init called with library already initialized." ); + } + + return status; +} + +/*-----------------------------------------------------------*/ + +void IotMqtt_Cleanup( void ) +{ + uint32_t allowCleanup = Atomic_CompareAndSwap_u32( &_initCalled, + MQTT_LIBRARY_UNINITIALIZED, + MQTT_LIBRARY_INITIALIZED ); + + if( allowCleanup == 1 ) + { + /* Call any additional serializer cleanup initialization function if serializer + * overrides are enabled. */ + #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 + #ifdef _IotMqtt_CleanupSerializeAdditional + _IotMqtt_CleanupSerializeAdditional(); + #endif + #endif + + IotLogInfo( "MQTT library cleanup done." ); + } + else + { + IotLogWarn( "IotMqtt_Init was not called before IotMqtt_Cleanup." ); + } +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_Connect( const IotMqttNetworkInfo_t * pNetworkInfo, + const IotMqttConnectInfo_t * pConnectInfo, + uint32_t timeoutMs, + IotMqttConnection_t * const pMqttConnection ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + bool ownNetworkConnection = false; + IotNetworkError_t networkStatus = IOT_NETWORK_SUCCESS; + IotTaskPoolError_t taskPoolStatus = IOT_TASKPOOL_SUCCESS; + IotNetworkConnection_t pNetworkConnection = { 0 }; + _mqttOperation_t * pOperation = NULL; + _mqttConnection_t * pNewMqttConnection = NULL; + + /* Check that IotMqtt_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NOT_INITIALIZED ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Validate network interface and connect info. */ + if( _IotMqtt_ValidateConnect( pConnectInfo ) == false ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + + networkStatus = _createNetworkConnection( pNetworkInfo, + &pNetworkConnection, + &ownNetworkConnection ); + + if( networkStatus != IOT_NETWORK_SUCCESS ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NETWORK_ERROR ); + } + else + { + EMPTY_ELSE_MARKER; + } + + IotLogInfo( "Establishing new MQTT connection." ); + + /* Initialize a new MQTT connection object. */ + pNewMqttConnection = _createMqttConnection( pConnectInfo->awsIotMqttMode, + pNetworkInfo, + pConnectInfo->keepAliveSeconds ); + + if( pNewMqttConnection == NULL ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY ); + } + else + { + /* Set the network connection associated with the MQTT connection. */ + pNewMqttConnection->pNetworkConnection = pNetworkConnection; + pNewMqttConnection->ownNetworkConnection = ownNetworkConnection; + + /* Set the MQTT packet serializer overrides. */ + #if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 + pNewMqttConnection->pSerializer = pNetworkInfo->pMqttSerializer; + #else + pNewMqttConnection->pSerializer = NULL; + #endif + } + + /* Set the MQTT receive callback. */ + networkStatus = pNewMqttConnection->pNetworkInterface->setReceiveCallback( pNetworkConnection, + IotMqtt_ReceiveCallback, + pNewMqttConnection ); + + if( networkStatus != IOT_NETWORK_SUCCESS ) + { + IotLogError( "Failed to set MQTT network receive callback." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NETWORK_ERROR ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Create a CONNECT operation. */ + status = _IotMqtt_CreateOperation( pNewMqttConnection, + IOT_MQTT_FLAG_WAITABLE, + NULL, + &pOperation ); + + if( status != IOT_MQTT_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Ensure the members set by operation creation and serialization + * are appropriate for a blocking CONNECT. */ + IotMqtt_Assert( pOperation->u.operation.status == IOT_MQTT_STATUS_PENDING ); + IotMqtt_Assert( ( pOperation->u.operation.flags & IOT_MQTT_FLAG_WAITABLE ) + == IOT_MQTT_FLAG_WAITABLE ); + IotMqtt_Assert( pOperation->u.operation.periodic.retry.limit == 0 ); + + /* Set the operation type. */ + pOperation->u.operation.type = IOT_MQTT_CONNECT; + + /* Add previous session subscriptions. */ + if( pConnectInfo->pPreviousSubscriptions != NULL ) + { + /* Previous subscription count should have been validated as nonzero. */ + IotMqtt_Assert( pConnectInfo->previousSubscriptionCount > 0 ); + + status = _IotMqtt_AddSubscriptions( pNewMqttConnection, + 2, + pConnectInfo->pPreviousSubscriptions, + pConnectInfo->previousSubscriptionCount ); + + if( status != IOT_MQTT_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Convert the connect info and will info objects to an MQTT CONNECT packet. */ + status = _getMqttConnectSerializer( pNetworkInfo->pMqttSerializer )( pConnectInfo, + &( pOperation->u.operation.pMqttPacket ), + &( pOperation->u.operation.packetSize ) ); + + if( status != IOT_MQTT_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check the serialized MQTT packet. */ + IotMqtt_Assert( pOperation->u.operation.pMqttPacket != NULL ); + IotMqtt_Assert( pOperation->u.operation.packetSize > 0 ); + + /* Send the CONNECT packet. */ + _IotMqtt_ProcessSend( IOT_SYSTEM_TASKPOOL, pOperation->job, pOperation ); + + /* Wait for the CONNECT operation to complete, i.e. wait for CONNACK. */ + status = IotMqtt_Wait( pOperation, timeoutMs ); + + /* The call to wait cleans up the CONNECT operation, so set the pointer + * to NULL. */ + pOperation = NULL; + + /* When a connection is successfully established, schedule keep-alive job. */ + if( status == IOT_MQTT_SUCCESS ) + { + /* Check if a keep-alive job should be scheduled. */ + if( pNewMqttConnection->pingreq.u.operation.periodic.ping.keepAliveMs != 0 ) + { + IotLogDebug( "Scheduling first MQTT keep-alive job." ); + + taskPoolStatus = IotTaskPool_ScheduleDeferred( IOT_SYSTEM_TASKPOOL, + pNewMqttConnection->pingreq.job, + pNewMqttConnection->pingreq.u.operation.periodic.ping.nextPeriodMs ); + + if( taskPoolStatus != IOT_TASKPOOL_SUCCESS ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_SCHEDULING_ERROR ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_FUNCTION_CLEANUP_BEGIN(); + + if( status != IOT_MQTT_SUCCESS ) + { + IotLogError( "Failed to establish new MQTT connection, error %s.", + IotMqtt_strerror( status ) ); + + /* The network connection must be closed if it was created. */ + if( ownNetworkConnection == true ) + { + networkStatus = pNetworkInfo->pNetworkInterface->close( pNetworkConnection ); + + if( networkStatus != IOT_NETWORK_SUCCESS ) + { + IotLogWarn( "Failed to close network connection." ); + } + else + { + IotLogInfo( "Network connection closed on error." ); + } + } + else + { + EMPTY_ELSE_MARKER; + } + + if( pOperation != NULL ) + { + _IotMqtt_DestroyOperation( pOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + + if( pNewMqttConnection != NULL ) + { + _destroyMqttConnection( pNewMqttConnection ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + IotLogInfo( "New MQTT connection %p established.", pMqttConnection ); + + /* Set the output parameter. */ + *pMqttConnection = pNewMqttConnection; + } + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +void IotMqtt_Disconnect( IotMqttConnection_t mqttConnection, + uint32_t flags ) +{ + bool disconnected = false, initCalled = false; + IotMqttError_t status = IOT_MQTT_STATUS_PENDING; + _mqttOperation_t * pOperation = NULL; + + /* Check that IotMqtt_Init was called. */ + initCalled = _checkInit(); + + if( initCalled == false ) + { + IOT_GOTO_CLEANUP(); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Only send a DISCONNECT packet if the connection is active and the "cleanup only" + * flag is not set. */ + if( ( flags & IOT_MQTT_FLAG_CLEANUP_ONLY ) == IOT_MQTT_FLAG_CLEANUP_ONLY ) + { + IOT_GOTO_CLEANUP(); + } + + /* Read the connection status. */ + IotMutex_Lock( &( mqttConnection->referencesMutex ) ); + disconnected = mqttConnection->disconnected; + IotMutex_Unlock( &( mqttConnection->referencesMutex ) ); + + if( disconnected == true ) + { + IOT_GOTO_CLEANUP(); + } + + IotLogInfo( "(MQTT connection %p) Disconnecting connection.", mqttConnection ); + + /* Create a DISCONNECT operation. This function blocks until the DISCONNECT + * packet is sent, so it sets IOT_MQTT_FLAG_WAITABLE. */ + status = _IotMqtt_CreateOperation( mqttConnection, + IOT_MQTT_FLAG_WAITABLE, + NULL, + &pOperation ); + + if( status == IOT_MQTT_SUCCESS ) + { + /* Ensure that the members set by operation creation and serialization + * are appropriate for a blocking DISCONNECT. */ + IotMqtt_Assert( pOperation->u.operation.status == IOT_MQTT_STATUS_PENDING ); + IotMqtt_Assert( ( pOperation->u.operation.flags & IOT_MQTT_FLAG_WAITABLE ) + == IOT_MQTT_FLAG_WAITABLE ); + IotMqtt_Assert( pOperation->u.operation.periodic.retry.limit == 0 ); + + /* Set the operation type. */ + pOperation->u.operation.type = IOT_MQTT_DISCONNECT; + + /* Generate a DISCONNECT packet. */ + status = _getMqttDisconnectSerializer( mqttConnection->pSerializer )( &( pOperation->u.operation.pMqttPacket ), + &( pOperation->u.operation.packetSize ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + + if( status == IOT_MQTT_SUCCESS ) + { + /* Check the serialized MQTT packet. */ + IotMqtt_Assert( pOperation->u.operation.pMqttPacket != NULL ); + IotMqtt_Assert( pOperation->u.operation.packetSize > 0 ); + + /* Send the DISCONNECT packet. */ + _IotMqtt_ProcessSend( IOT_SYSTEM_TASKPOOL, pOperation->job, pOperation ); + + /* Wait a short time for the DISCONNECT packet to be transmitted. */ + status = IotMqtt_Wait( pOperation, + IOT_MQTT_RESPONSE_WAIT_MS ); + + /* A wait on DISCONNECT should only ever return SUCCESS, TIMEOUT, + * or NETWORK ERROR. */ + if( status == IOT_MQTT_SUCCESS ) + { + IotLogInfo( "(MQTT connection %p) Connection disconnected.", mqttConnection ); + } + else + { + IotMqtt_Assert( ( status == IOT_MQTT_TIMEOUT ) || + ( status == IOT_MQTT_NETWORK_ERROR ) ); + + IotLogWarn( "(MQTT connection %p) DISCONNECT not sent, error %s.", + mqttConnection, + IotMqtt_strerror( status ) ); + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* This function has no return value and no cleanup, but uses the cleanup + * label to exit on error. */ + IOT_FUNCTION_CLEANUP_BEGIN(); + + if( initCalled == true ) + { + /* Close the underlying network connection. This also cleans up keep-alive. */ + _IotMqtt_CloseNetworkConnection( IOT_MQTT_DISCONNECT_CALLED, + mqttConnection ); + + /* Check if the connection may be destroyed. */ + IotMutex_Lock( &( mqttConnection->referencesMutex ) ); + + /* At this point, the connection should be marked disconnected. */ + IotMqtt_Assert( mqttConnection->disconnected == true ); + + /* Attempt cancel and destroy each operation in the connection's lists. */ + IotListDouble_RemoveAll( &( mqttConnection->pendingProcessing ), + _mqttOperation_tryDestroy, + offsetof( _mqttOperation_t, link ) ); + + IotListDouble_RemoveAll( &( mqttConnection->pendingResponse ), + _mqttOperation_tryDestroy, + offsetof( _mqttOperation_t, link ) ); + + IotMutex_Unlock( &( mqttConnection->referencesMutex ) ); + + /* Decrement the connection reference count and destroy it if possible. */ + _IotMqtt_DecrementConnectionReferences( mqttConnection ); + } +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_SubscribeAsync( IotMqttConnection_t mqttConnection, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + const IotMqttCallbackInfo_t * pCallbackInfo, + IotMqttOperation_t * const pSubscribeOperation ) +{ + IotMqttError_t status = _subscriptionCommonSetup( IOT_MQTT_SUBSCRIBE, + mqttConnection, + pSubscriptionList, + subscriptionCount, + flags, + pSubscribeOperation ); + + if( IOT_MQTT_SUCCESS == status ) + { + status = _subscriptionCommon( IOT_MQTT_SUBSCRIBE, + mqttConnection, + _getMqttSubscribeSerializer( mqttConnection->pSerializer ), + pSubscriptionList, + subscriptionCount, + flags, + pCallbackInfo, + pSubscribeOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_SubscribeSync( IotMqttConnection_t mqttConnection, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + uint32_t timeoutMs ) +{ + IotMqttError_t status = IOT_MQTT_STATUS_PENDING; + IotMqttOperation_t subscribeOperation = IOT_MQTT_OPERATION_INITIALIZER; + + /* Flags are not used, but the parameter is present for future compatibility. */ + ( void ) flags; + + /* Call the asynchronous SUBSCRIBE function. */ + status = IotMqtt_SubscribeAsync( mqttConnection, + pSubscriptionList, + subscriptionCount, + IOT_MQTT_FLAG_WAITABLE | MQTT_INTERNAL_FLAG_BLOCK_ON_SEND, + NULL, + &subscribeOperation ); + + /* Wait for the SUBSCRIBE operation to complete. */ + if( status == IOT_MQTT_STATUS_PENDING ) + { + status = IotMqtt_Wait( subscribeOperation, timeoutMs ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Ensure that a status was set. */ + IotMqtt_Assert( status != IOT_MQTT_STATUS_PENDING ); + + return status; +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_UnsubscribeAsync( IotMqttConnection_t mqttConnection, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + const IotMqttCallbackInfo_t * pCallbackInfo, + IotMqttOperation_t * const pUnsubscribeOperation ) +{ + IotMqttError_t status = _subscriptionCommonSetup( IOT_MQTT_UNSUBSCRIBE, + mqttConnection, + pSubscriptionList, + subscriptionCount, + flags, + pUnsubscribeOperation ); + + if( IOT_MQTT_SUCCESS == status ) + { + /* Remove the MQTT subscription list for an UNSUBSCRIBE. */ + _IotMqtt_RemoveSubscriptionByTopicFilter( mqttConnection, + pSubscriptionList, + subscriptionCount ); + + status = _subscriptionCommon( IOT_MQTT_UNSUBSCRIBE, + mqttConnection, + _getMqttUnsubscribeSerializer( mqttConnection->pSerializer ), + pSubscriptionList, + subscriptionCount, + flags, + pCallbackInfo, + pUnsubscribeOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_UnsubscribeSync( IotMqttConnection_t mqttConnection, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint32_t flags, + uint32_t timeoutMs ) +{ + IotMqttError_t status = IOT_MQTT_STATUS_PENDING; + IotMqttOperation_t unsubscribeOperation = IOT_MQTT_OPERATION_INITIALIZER; + + /* Flags are not used, but the parameter is present for future compatibility. */ + ( void ) flags; + + /* Call the asynchronous UNSUBSCRIBE function. */ + status = IotMqtt_UnsubscribeAsync( mqttConnection, + pSubscriptionList, + subscriptionCount, + IOT_MQTT_FLAG_WAITABLE | MQTT_INTERNAL_FLAG_BLOCK_ON_SEND, + NULL, + &unsubscribeOperation ); + + /* Wait for the UNSUBSCRIBE operation to complete. */ + if( status == IOT_MQTT_STATUS_PENDING ) + { + status = IotMqtt_Wait( unsubscribeOperation, timeoutMs ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Ensure that a status was set. */ + IotMqtt_Assert( status != IOT_MQTT_STATUS_PENDING ); + + return status; +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_PublishAsync( IotMqttConnection_t mqttConnection, + const IotMqttPublishInfo_t * pPublishInfo, + uint32_t flags, + const IotMqttCallbackInfo_t * pCallbackInfo, + IotMqttOperation_t * const pPublishOperation ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + _mqttOperation_t * pOperation = NULL; + uint8_t ** pPacketIdentifierHigh = NULL; + + /* Check that IotMqtt_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NOT_INITIALIZED ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check that the PUBLISH information is valid. */ + if( _IotMqtt_ValidatePublish( mqttConnection->awsIotMqttMode, + pPublishInfo ) == false ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check that no notification is requested for a QoS 0 publish. */ + if( pPublishInfo->qos == IOT_MQTT_QOS_0 ) + { + if( pCallbackInfo != NULL ) + { + IotLogError( "QoS 0 PUBLISH should not have notification parameters set." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else if( ( flags & IOT_MQTT_FLAG_WAITABLE ) != 0 ) + { + IotLogError( "QoS 0 PUBLISH should not have notification parameters set." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + + if( pPublishOperation != NULL ) + { + IotLogWarn( "Ignoring reference parameter for QoS 0 publish." ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check that a reference pointer is provided for a waitable operation. */ + if( ( flags & IOT_MQTT_FLAG_WAITABLE ) == IOT_MQTT_FLAG_WAITABLE ) + { + if( pPublishOperation == NULL ) + { + IotLogError( "Reference must be provided for a waitable PUBLISH." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Create a PUBLISH operation. */ + status = _IotMqtt_CreateOperation( mqttConnection, + flags, + pCallbackInfo, + &pOperation ); + + if( status != IOT_MQTT_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check the PUBLISH operation data and set the operation type. */ + IotMqtt_Assert( pOperation->u.operation.status == IOT_MQTT_STATUS_PENDING ); + pOperation->u.operation.type = IOT_MQTT_PUBLISH_TO_SERVER; + + /* In AWS IoT MQTT mode, a pointer to the packet identifier must be saved. */ + if( mqttConnection->awsIotMqttMode == true ) + { + pPacketIdentifierHigh = &( pOperation->u.operation.pPacketIdentifierHigh ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Generate a PUBLISH packet from pPublishInfo. */ + status = _getMqttPublishSerializer( mqttConnection->pSerializer )( pPublishInfo, + &( pOperation->u.operation.pMqttPacket ), + &( pOperation->u.operation.packetSize ), + &( pOperation->u.operation.packetIdentifier ), + pPacketIdentifierHigh ); + + if( status != IOT_MQTT_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check the serialized MQTT packet. */ + IotMqtt_Assert( pOperation->u.operation.pMqttPacket != NULL ); + IotMqtt_Assert( pOperation->u.operation.packetSize > 0 ); + + /* Initialize PUBLISH retry if retryLimit is set. */ + if( pPublishInfo->retryLimit > 0 ) + { + /* A QoS 0 PUBLISH may not be retried. */ + if( pPublishInfo->qos != IOT_MQTT_QOS_0 ) + { + pOperation->u.operation.periodic.retry.limit = pPublishInfo->retryLimit; + pOperation->u.operation.periodic.retry.nextPeriodMs = pPublishInfo->retryMs; + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Set the reference, if provided. */ + if( pPublishInfo->qos != IOT_MQTT_QOS_0 ) + { + if( pPublishOperation != NULL ) + { + *pPublishOperation = pOperation; + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Send the PUBLISH packet. */ + if( ( flags & MQTT_INTERNAL_FLAG_BLOCK_ON_SEND ) == MQTT_INTERNAL_FLAG_BLOCK_ON_SEND ) + { + _IotMqtt_ProcessSend( IOT_SYSTEM_TASKPOOL, pOperation->job, pOperation ); + } + else + { + status = _IotMqtt_ScheduleOperation( pOperation, + _IotMqtt_ProcessSend, + 0 ); + + if( status != IOT_MQTT_SUCCESS ) + { + IotLogError( "(MQTT connection %p) Failed to enqueue PUBLISH for sending.", + mqttConnection ); + + /* Clear the previously set (and now invalid) reference. */ + if( pPublishInfo->qos != IOT_MQTT_QOS_0 ) + { + if( pPublishOperation != NULL ) + { + *pPublishOperation = IOT_MQTT_OPERATION_INITIALIZER; + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_GOTO_CLEANUP(); + } + else + { + EMPTY_ELSE_MARKER; + } + } + + /* Clean up the PUBLISH operation if this function fails. Otherwise, set the + * appropriate return code based on QoS. */ + IOT_FUNCTION_CLEANUP_BEGIN(); + + if( status != IOT_MQTT_SUCCESS ) + { + if( pOperation != NULL ) + { + _IotMqtt_DestroyOperation( pOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + if( pPublishInfo->qos > IOT_MQTT_QOS_0 ) + { + status = IOT_MQTT_STATUS_PENDING; + } + else + { + EMPTY_ELSE_MARKER; + } + + IotLogInfo( "(MQTT connection %p) MQTT PUBLISH operation queued.", + mqttConnection ); + } + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_PublishSync( IotMqttConnection_t mqttConnection, + const IotMqttPublishInfo_t * pPublishInfo, + uint32_t flags, + uint32_t timeoutMs ) +{ + IotMqttError_t status = IOT_MQTT_STATUS_PENDING; + IotMqttOperation_t publishOperation = IOT_MQTT_OPERATION_INITIALIZER, + * pPublishOperation = NULL; + + /* Clear the flags, setting only the "serial" flag. */ + flags = MQTT_INTERNAL_FLAG_BLOCK_ON_SEND; + + /* Set the waitable flag and reference for QoS 1 PUBLISH. */ + if( pPublishInfo->qos == IOT_MQTT_QOS_1 ) + { + flags |= IOT_MQTT_FLAG_WAITABLE; + pPublishOperation = &publishOperation; + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Call the asynchronous PUBLISH function. */ + status = IotMqtt_PublishAsync( mqttConnection, + pPublishInfo, + flags, + NULL, + pPublishOperation ); + + /* Wait for a queued QoS 1 PUBLISH to complete. */ + if( pPublishInfo->qos == IOT_MQTT_QOS_1 ) + { + if( status == IOT_MQTT_STATUS_PENDING ) + { + status = IotMqtt_Wait( publishOperation, timeoutMs ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_Wait( IotMqttOperation_t operation, + uint32_t timeoutMs ) +{ + IotMqttError_t status = IOT_MQTT_SUCCESS; + _mqttConnection_t * pMqttConnection = NULL; + + /* Check that IotMqtt_Init was called. */ + if( _checkInit() == false ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NOT_INITIALIZED ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Validate the given operation reference. */ + if( _IotMqtt_ValidateOperation( operation ) == false ) + { + status = IOT_MQTT_BAD_PARAMETER; + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check the MQTT connection status. */ + pMqttConnection = operation->pMqttConnection; + + if( status == IOT_MQTT_SUCCESS ) + { + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + + if( pMqttConnection->disconnected == true ) + { + IotLogError( "(MQTT connection %p, %s operation %p) MQTT connection is closed. " + "Operation cannot be waited on.", + pMqttConnection, + IotMqtt_OperationType( operation->u.operation.type ), + operation ); + + status = IOT_MQTT_NETWORK_ERROR; + } + else + { + IotLogInfo( "(MQTT connection %p, %s operation %p) Waiting for operation completion.", + pMqttConnection, + IotMqtt_OperationType( operation->u.operation.type ), + operation ); + } + + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + + /* Only wait on an operation if the MQTT connection is active. */ + if( status == IOT_MQTT_SUCCESS ) + { + if( IotSemaphore_TimedWait( &( operation->u.operation.notify.waitSemaphore ), + timeoutMs ) == false ) + { + status = IOT_MQTT_TIMEOUT; + + /* Attempt to cancel the job of the timed out operation. */ + ( void ) _IotMqtt_DecrementOperationReferences( operation, true ); + + /* Clean up lingering subscriptions from a timed-out SUBSCRIBE. */ + if( operation->u.operation.type == IOT_MQTT_SUBSCRIBE ) + { + IotLogDebug( "(MQTT connection %p, SUBSCRIBE operation %p) Cleaning up" + " subscriptions of timed-out SUBSCRIBE.", + pMqttConnection, + operation ); + + _IotMqtt_RemoveSubscriptionByPacket( pMqttConnection, + operation->u.operation.packetIdentifier, + MQTT_REMOVE_ALL_SUBSCRIPTIONS ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + /* Retrieve the status of the completed operation. */ + status = operation->u.operation.status; + } + + IotLogInfo( "(MQTT connection %p, %s operation %p) Wait complete with result %s.", + pMqttConnection, + IotMqtt_OperationType( operation->u.operation.type ), + operation, + IotMqtt_strerror( status ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Wait is finished; decrement operation reference count. */ + if( _IotMqtt_DecrementOperationReferences( operation, false ) == true ) + { + _IotMqtt_DestroyOperation( operation ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +const char * IotMqtt_strerror( IotMqttError_t status ) +{ + const char * pMessage = NULL; + + switch( status ) + { + case IOT_MQTT_SUCCESS: + pMessage = "SUCCESS"; + break; + + case IOT_MQTT_STATUS_PENDING: + pMessage = "PENDING"; + break; + + case IOT_MQTT_INIT_FAILED: + pMessage = "INITIALIZATION FAILED"; + break; + + case IOT_MQTT_BAD_PARAMETER: + pMessage = "BAD PARAMETER"; + break; + + case IOT_MQTT_NO_MEMORY: + pMessage = "NO MEMORY"; + break; + + case IOT_MQTT_NETWORK_ERROR: + pMessage = "NETWORK ERROR"; + break; + + case IOT_MQTT_SCHEDULING_ERROR: + pMessage = "SCHEDULING ERROR"; + break; + + case IOT_MQTT_BAD_RESPONSE: + pMessage = "BAD RESPONSE RECEIVED"; + break; + + case IOT_MQTT_TIMEOUT: + pMessage = "TIMEOUT"; + break; + + case IOT_MQTT_SERVER_REFUSED: + pMessage = "SERVER REFUSED"; + break; + + case IOT_MQTT_RETRY_NO_RESPONSE: + pMessage = "NO RESPONSE"; + break; + + case IOT_MQTT_NOT_INITIALIZED: + pMessage = "NOT INITIALIZED"; + break; + + default: + pMessage = "INVALID STATUS"; + break; + } + + return pMessage; +} + +/*-----------------------------------------------------------*/ + +const char * IotMqtt_OperationType( IotMqttOperationType_t operation ) +{ + const char * pMessage = NULL; + + switch( operation ) + { + case IOT_MQTT_CONNECT: + pMessage = "CONNECT"; + break; + + case IOT_MQTT_PUBLISH_TO_SERVER: + pMessage = "PUBLISH"; + break; + + case IOT_MQTT_PUBACK: + pMessage = "PUBACK"; + break; + + case IOT_MQTT_SUBSCRIBE: + pMessage = "SUBSCRIBE"; + break; + + case IOT_MQTT_UNSUBSCRIBE: + pMessage = "UNSUBSCRIBE"; + break; + + case IOT_MQTT_PINGREQ: + pMessage = "PINGREQ"; + break; + + case IOT_MQTT_DISCONNECT: + pMessage = "DISCONNECT"; + break; + + default: + pMessage = "INVALID OPERATION"; + break; + } + + return pMessage; +} + +/*-----------------------------------------------------------*/ + +/* Provide access to internal functions and variables if testing. */ +#if IOT_BUILD_TESTS == 1 + #include "iot_test_access_mqtt_api.c" +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_network.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_network.c new file mode 100644 index 000000000..ab470b5f1 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_network.c @@ -0,0 +1,884 @@ +/* + * IoT MQTT V2.1.0 + * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_mqtt_network.c + * @brief Implements functions involving transport layer connections. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* Error handling include. */ +#include "iot_error.h" + +/* MQTT internal include. */ +#include "private/iot_mqtt_internal.h" + +/* Platform layer includes. */ +#include "platform/iot_threads.h" + +/* Atomics include. */ +#include "iot_atomic.h" + +/*-----------------------------------------------------------*/ + +/** + * @brief Check if an incoming packet type is valid. + * + * @param[in] packetType The packet type to check. + * + * @return `true` if the packet type is valid; `false` otherwise. + */ +static bool _incomingPacketValid( uint8_t packetType ); + +/** + * @brief Get an incoming MQTT packet from the network. + * + * @param[in] pNetworkConnection Network connection to use for receive, which + * may be different from the network connection associated with the MQTT connection. + * @param[in] pMqttConnection The associated MQTT connection. + * @param[out] pIncomingPacket Output parameter for the incoming packet. + * + * @return #IOT_MQTT_SUCCESS, #IOT_MQTT_NO_MEMORY or #IOT_MQTT_BAD_RESPONSE. + */ +static IotMqttError_t _getIncomingPacket( void * pNetworkConnection, + const _mqttConnection_t * pMqttConnection, + _mqttPacket_t * pIncomingPacket ); + +/** + * @brief Deserialize a packet received from the network. + * + * @param[in] pMqttConnection The associated MQTT connection. + * @param[in] pIncomingPacket The packet received from the network. + * + * @return #IOT_MQTT_SUCCESS, #IOT_MQTT_NO_MEMORY, #IOT_MQTT_NETWORK_ERROR, + * #IOT_MQTT_SCHEDULING_ERROR, #IOT_MQTT_BAD_RESPONSE, or #IOT_MQTT_SERVER_REFUSED. + */ +static IotMqttError_t _deserializeIncomingPacket( _mqttConnection_t * pMqttConnection, + _mqttPacket_t * pIncomingPacket ); + +/** + * @brief Send a PUBACK for a received QoS 1 PUBLISH packet. + * + * @param[in] pMqttConnection Which connection the PUBACK should be sent over. + * @param[in] packetIdentifier Which packet identifier to include in PUBACK. + */ +static void _sendPuback( _mqttConnection_t * pMqttConnection, + uint16_t packetIdentifier ); + +/** + * @brief Flush a packet from the stream of incoming data. + * + * This function is called when memory for a packet cannot be allocated. The + * packet is flushed from the stream of incoming data so that the next packet + * may be read. + * + * @param[in] pNetworkConnection Network connection to use for receive, which + * may be different from the network connection associated with the MQTT connection. + * @param[in] pMqttConnection The associated MQTT connection. + * @param[in] length The length of the packet to flush. + */ +static void _flushPacket( void * pNetworkConnection, + const _mqttConnection_t * pMqttConnection, + size_t length ); + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * Declaration of local MQTT serializer override selectors + */ +#if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttGetPacketType_t, + _getPacketTypeFunc, + _IotMqtt_GetPacketType, + getPacketType ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttGetRemainingLength_t, + _getRemainingLengthFunc, + _IotMqtt_GetRemainingLength, + getRemainingLength ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttDeserialize_t, + _getConnackDeserializer, + _IotMqtt_DeserializeConnack, + deserialize.connack ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttDeserialize_t, + _getPublishDeserializer, + _IotMqtt_DeserializePublish, + deserialize.publish ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttDeserialize_t, + _getPubackDeserializer, + _IotMqtt_DeserializePuback, + deserialize.puback ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttDeserialize_t, + _getSubackDeserializer, + _IotMqtt_DeserializeSuback, + deserialize.suback ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttDeserialize_t, + _getUnsubackDeserializer, + _IotMqtt_DeserializeUnsuback, + deserialize.unsuback ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttDeserialize_t, + _getPingrespDeserializer, + _IotMqtt_DeserializePingresp, + deserialize.pingresp ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttSerializePuback_t, + _getMqttPubackSerializer, + _IotMqtt_SerializePuback, + serialize.puback ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttFreePacket_t, + _getMqttFreePacketFunc, + _IotMqtt_FreePacket, + freePacket ) +#else /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */ + #define _getPacketTypeFunc( pSerializer ) _IotMqtt_GetPacketType + #define _getRemainingLengthFunc( pSerializer ) _IotMqtt_GetRemainingLength + #define _getConnackDeserializer( pSerializer ) _IotMqtt_DeserializeConnack + #define _getPublishDeserializer( pSerializer ) _IotMqtt_DeserializePublish + #define _getPubackDeserializer( pSerializer ) _IotMqtt_DeserializePuback + #define _getSubackDeserializer( pSerializer ) _IotMqtt_DeserializeSuback + #define _getUnsubackDeserializer( pSerializer ) _IotMqtt_DeserializeUnsuback + #define _getPingrespDeserializer( pSerializer ) _IotMqtt_DeserializePingresp + #define _getMqttPubackSerializer( pSerializer ) _IotMqtt_SerializePuback + #define _getMqttFreePacketFunc( pSerializer ) _IotMqtt_FreePacket +#endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */ +/** @endcond */ + +/*-----------------------------------------------------------*/ + +static bool _incomingPacketValid( uint8_t packetType ) +{ + bool status = true; + + /* Check packet type. Mask out lower bits to ignore flags. */ + switch( packetType & 0xf0 ) + { + /* Valid incoming packet types. */ + case MQTT_PACKET_TYPE_CONNACK: + case MQTT_PACKET_TYPE_PUBLISH: + case MQTT_PACKET_TYPE_PUBACK: + case MQTT_PACKET_TYPE_SUBACK: + case MQTT_PACKET_TYPE_UNSUBACK: + case MQTT_PACKET_TYPE_PINGRESP: + break; + + /* Any other packet type is invalid. */ + default: + status = false; + break; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +static IotMqttError_t _getIncomingPacket( void * pNetworkConnection, + const _mqttConnection_t * pMqttConnection, + _mqttPacket_t * pIncomingPacket ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + size_t dataBytesRead = 0; + + /* No buffer for remaining data should be allocated. */ + IotMqtt_Assert( pIncomingPacket->pRemainingData == NULL ); + IotMqtt_Assert( pIncomingPacket->remainingLength == 0 ); + + /* Read the packet type, which is the first byte available. */ + pIncomingPacket->type = _getPacketTypeFunc( pMqttConnection->pSerializer )( pNetworkConnection, + pMqttConnection->pNetworkInterface ); + + /* Check that the incoming packet type is valid. */ + if( _incomingPacketValid( pIncomingPacket->type ) == false ) + { + IotLogError( "(MQTT connection %p) Unknown packet type %02x received.", + pMqttConnection, + pIncomingPacket->type ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Read the remaining length. */ + pIncomingPacket->remainingLength = _getRemainingLengthFunc( pMqttConnection->pSerializer )( pNetworkConnection, + pMqttConnection->pNetworkInterface ); + + if( pIncomingPacket->remainingLength == MQTT_REMAINING_LENGTH_INVALID ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Allocate a buffer for the remaining data and read the data. */ + if( pIncomingPacket->remainingLength > 0 ) + { + pIncomingPacket->pRemainingData = IotMqtt_MallocMessage( pIncomingPacket->remainingLength ); + + if( pIncomingPacket->pRemainingData == NULL ) + { + IotLogError( "(MQTT connection %p) Failed to allocate buffer of length " + "%lu for incoming packet type %lu.", + pMqttConnection, + ( unsigned long ) pIncomingPacket->remainingLength, + ( unsigned long ) pIncomingPacket->type ); + + _flushPacket( pNetworkConnection, pMqttConnection, pIncomingPacket->remainingLength ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY ); + } + else + { + EMPTY_ELSE_MARKER; + } + + dataBytesRead = pMqttConnection->pNetworkInterface->receive( pNetworkConnection, + pIncomingPacket->pRemainingData, + pIncomingPacket->remainingLength ); + + if( dataBytesRead != pIncomingPacket->remainingLength ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Clean up on error. */ + IOT_FUNCTION_CLEANUP_BEGIN(); + + if( status != IOT_MQTT_SUCCESS ) + { + if( pIncomingPacket->pRemainingData != NULL ) + { + IotMqtt_FreeMessage( pIncomingPacket->pRemainingData ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +static IotMqttError_t _deserializeIncomingPacket( _mqttConnection_t * pMqttConnection, + _mqttPacket_t * pIncomingPacket ) +{ + IotMqttError_t status = IOT_MQTT_STATUS_PENDING; + _mqttOperation_t * pOperation = NULL; + + /* A buffer for remaining data must be allocated if remaining length is not 0. */ + IotMqtt_Assert( ( pIncomingPacket->remainingLength > 0 ) == + ( pIncomingPacket->pRemainingData != NULL ) ); + + /* Only valid packets should be given to this function. */ + IotMqtt_Assert( _incomingPacketValid( pIncomingPacket->type ) == true ); + + /* Mask out the low bits of packet type to ignore flags. */ + switch( ( pIncomingPacket->type & 0xf0 ) ) + { + case MQTT_PACKET_TYPE_CONNACK: + IotLogDebug( "(MQTT connection %p) CONNACK in data stream.", pMqttConnection ); + + /* Deserialize CONNACK and notify of result. */ + status = _getConnackDeserializer( pMqttConnection->pSerializer )( pIncomingPacket ); + + pOperation = _IotMqtt_FindOperation( pMqttConnection, + IOT_MQTT_CONNECT, + NULL ); + + if( pOperation != NULL ) + { + pOperation->u.operation.status = status; + _IotMqtt_Notify( pOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + + break; + + case MQTT_PACKET_TYPE_PUBLISH: + IotLogDebug( "(MQTT connection %p) PUBLISH in data stream.", pMqttConnection ); + + /* Allocate memory to handle the incoming PUBLISH. */ + pOperation = IotMqtt_MallocOperation( sizeof( _mqttOperation_t ) ); + + if( pOperation == NULL ) + { + IotLogWarn( "Failed to allocate memory for incoming PUBLISH." ); + status = IOT_MQTT_NO_MEMORY; + + break; + } + else + { + /* Set the members of the incoming PUBLISH operation. */ + ( void ) memset( pOperation, 0x00, sizeof( _mqttOperation_t ) ); + pOperation->incomingPublish = true; + pOperation->pMqttConnection = pMqttConnection; + pIncomingPacket->u.pIncomingPublish = pOperation; + } + + /* Deserialize incoming PUBLISH. */ + status = _getPublishDeserializer( pMqttConnection->pSerializer )( pIncomingPacket ); + + if( status == IOT_MQTT_SUCCESS ) + { + /* Send a PUBACK for QoS 1 PUBLISH. */ + if( pOperation->u.publish.publishInfo.qos == IOT_MQTT_QOS_1 ) + { + _sendPuback( pMqttConnection, pIncomingPacket->packetIdentifier ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Transfer ownership of the received MQTT packet to the PUBLISH operation. */ + pOperation->u.publish.pReceivedData = pIncomingPacket->pRemainingData; + pIncomingPacket->pRemainingData = NULL; + + /* Add the PUBLISH to the list of operations pending processing. */ + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + IotListDouble_InsertHead( &( pMqttConnection->pendingProcessing ), + &( pOperation->link ) ); + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + + /* Increment the MQTT connection reference count before scheduling an + * incoming PUBLISH. */ + if( _IotMqtt_IncrementConnectionReferences( pMqttConnection ) == true ) + { + /* Schedule PUBLISH for callback invocation. */ + status = _IotMqtt_ScheduleOperation( pOperation, _IotMqtt_ProcessIncomingPublish, 0 ); + } + else + { + status = IOT_MQTT_NETWORK_ERROR; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Free PUBLISH operation on error. */ + if( status != IOT_MQTT_SUCCESS ) + { + /* Check ownership of the received MQTT packet. */ + if( pOperation->u.publish.pReceivedData != NULL ) + { + /* Retrieve the pointer MQTT packet pointer so it may be freed later. */ + IotMqtt_Assert( pIncomingPacket->pRemainingData == NULL ); + pIncomingPacket->pRemainingData = ( uint8_t * ) pOperation->u.publish.pReceivedData; + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Remove operation from pending processing list. */ + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + + if( IotLink_IsLinked( &( pOperation->link ) ) == true ) + { + IotListDouble_Remove( &( pOperation->link ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + + IotMqtt_Assert( pOperation != NULL ); + IotMqtt_FreeOperation( pOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + + break; + + case MQTT_PACKET_TYPE_PUBACK: + IotLogDebug( "(MQTT connection %p) PUBACK in data stream.", pMqttConnection ); + + /* Deserialize PUBACK and notify of result. */ + status = _getPubackDeserializer( pMqttConnection->pSerializer )( pIncomingPacket ); + + pOperation = _IotMqtt_FindOperation( pMqttConnection, + IOT_MQTT_PUBLISH_TO_SERVER, + &( pIncomingPacket->packetIdentifier ) ); + + if( pOperation != NULL ) + { + pOperation->u.operation.status = status; + _IotMqtt_Notify( pOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + + break; + + case MQTT_PACKET_TYPE_SUBACK: + IotLogDebug( "(MQTT connection %p) SUBACK in data stream.", pMqttConnection ); + + /* Deserialize SUBACK and notify of result. */ + pIncomingPacket->u.pMqttConnection = pMqttConnection; + + status = _getSubackDeserializer( pMqttConnection->pSerializer )( pIncomingPacket ); + + pOperation = _IotMqtt_FindOperation( pMqttConnection, + IOT_MQTT_SUBSCRIBE, + &( pIncomingPacket->packetIdentifier ) ); + + if( pOperation != NULL ) + { + pOperation->u.operation.status = status; + _IotMqtt_Notify( pOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + + break; + + case MQTT_PACKET_TYPE_UNSUBACK: + IotLogDebug( "(MQTT connection %p) UNSUBACK in data stream.", pMqttConnection ); + + /* Deserialize UNSUBACK and notify of result. */ + status = _getUnsubackDeserializer( pMqttConnection->pSerializer )( pIncomingPacket ); + + pOperation = _IotMqtt_FindOperation( pMqttConnection, + IOT_MQTT_UNSUBSCRIBE, + &( pIncomingPacket->packetIdentifier ) ); + + if( pOperation != NULL ) + { + pOperation->u.operation.status = status; + _IotMqtt_Notify( pOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + + break; + + default: + /* The only remaining valid type is PINGRESP. */ + IotMqtt_Assert( ( pIncomingPacket->type & 0xf0 ) == MQTT_PACKET_TYPE_PINGRESP ); + + IotLogDebug( "(MQTT connection %p) PINGRESP in data stream.", pMqttConnection ); + + /* Deserialize PINGRESP. */ + status = _getPingrespDeserializer( pMqttConnection->pSerializer )( pIncomingPacket ); + + if( status == IOT_MQTT_SUCCESS ) + { + if( Atomic_CompareAndSwap_u32( &( pMqttConnection->pingreq.u.operation.periodic.ping.failure ), + 0, + 1 ) == 1 ) + { + IotLogDebug( "(MQTT connection %p) PINGRESP successfully parsed.", + pMqttConnection ); + } + else + { + IotLogWarn( "(MQTT connection %p) Unexpected PINGRESP received.", + pMqttConnection ); + } + } + else + { + EMPTY_ELSE_MARKER; + } + + break; + } + + if( status != IOT_MQTT_SUCCESS ) + { + IotLogError( "(MQTT connection %p) Packet parser status %s.", + pMqttConnection, + IotMqtt_strerror( status ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +static void _sendPuback( _mqttConnection_t * pMqttConnection, + uint16_t packetIdentifier ) +{ + IotMqttError_t status = IOT_MQTT_STATUS_PENDING; + _mqttOperation_t * pPubackOperation = NULL; + + IotLogDebug( "(MQTT connection %p) Sending PUBACK for received PUBLISH %hu.", + pMqttConnection, + packetIdentifier ); + + /* Create a PUBACK operation. */ + status = _IotMqtt_CreateOperation( pMqttConnection, + 0, + NULL, + &pPubackOperation ); + + if( status != IOT_MQTT_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + + /* Set the operation type. */ + pPubackOperation->u.operation.type = IOT_MQTT_PUBACK; + + /* Generate a PUBACK packet from the packet identifier. */ + status = _getMqttPubackSerializer( pMqttConnection->pSerializer )( packetIdentifier, + &( pPubackOperation->u.operation.pMqttPacket ), + &( pPubackOperation->u.operation.packetSize ) ); + + if( status != IOT_MQTT_SUCCESS ) + { + IOT_GOTO_CLEANUP(); + } + + /* Add the PUBACK operation to the send queue for network transmission. */ + status = _IotMqtt_ScheduleOperation( pPubackOperation, + _IotMqtt_ProcessSend, + 0 ); + + if( status != IOT_MQTT_SUCCESS ) + { + IotLogError( "(MQTT connection %p) Failed to enqueue PUBACK for sending.", + pMqttConnection ); + + IOT_GOTO_CLEANUP(); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Clean up on error. */ + IOT_FUNCTION_CLEANUP_BEGIN(); + + if( status != IOT_MQTT_SUCCESS ) + { + if( pPubackOperation != NULL ) + { + _IotMqtt_DestroyOperation( pPubackOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } +} + +/*-----------------------------------------------------------*/ + +static void _flushPacket( void * pNetworkConnection, + const _mqttConnection_t * pMqttConnection, + size_t length ) +{ + size_t bytesFlushed = 0; + uint8_t receivedByte = 0; + + for( bytesFlushed = 0; bytesFlushed < length; bytesFlushed++ ) + { + ( void ) _IotMqtt_GetNextByte( pNetworkConnection, + pMqttConnection->pNetworkInterface, + &receivedByte ); + } +} + +/*-----------------------------------------------------------*/ + +bool _IotMqtt_GetNextByte( void * pNetworkConnection, + const IotNetworkInterface_t * pNetworkInterface, + uint8_t * pIncomingByte ) +{ + bool status = false; + uint8_t incomingByte = 0; + size_t bytesReceived = 0; + + /* Attempt to read 1 byte. */ + bytesReceived = pNetworkInterface->receive( pNetworkConnection, + &incomingByte, + 1 ); + + /* Set the output parameter and return success if 1 byte was read. */ + if( bytesReceived == 1 ) + { + *pIncomingByte = incomingByte; + status = true; + } + else + { + /* Network receive must return 0 on failure. */ + IotMqtt_Assert( bytesReceived == 0 ); + } + + return status; +} + +/*-----------------------------------------------------------*/ + +void _IotMqtt_CloseNetworkConnection( IotMqttDisconnectReason_t disconnectReason, + _mqttConnection_t * pMqttConnection ) +{ + IotTaskPoolError_t taskPoolStatus = IOT_TASKPOOL_SUCCESS; + IotNetworkError_t closeStatus = IOT_NETWORK_SUCCESS; + IotMqttCallbackParam_t callbackParam = { .u.message = { 0 } }; + void * pNetworkConnection = NULL, * pDisconnectCallbackContext = NULL; + + /* Disconnect callback function. */ + void ( * disconnectCallback )( void *, + IotMqttCallbackParam_t * ) = NULL; + + /* Network close function. */ + IotNetworkError_t ( * closeConnection) ( IotNetworkConnection_t ) = NULL; + + /* Mark the MQTT connection as disconnected and the keep-alive as failed. */ + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + pMqttConnection->disconnected = true; + + if( pMqttConnection->pingreq.u.operation.periodic.ping.keepAliveMs != 0 ) + { + /* Keep-alive must have a PINGREQ allocated. */ + IotMqtt_Assert( pMqttConnection->pingreq.u.operation.pMqttPacket != NULL ); + IotMqtt_Assert( pMqttConnection->pingreq.u.operation.packetSize != 0 ); + + /* PINGREQ provides a reference to the connection, so reference count must + * be nonzero. */ + IotMqtt_Assert( pMqttConnection->references > 0 ); + + /* Attempt to cancel the keep-alive job. */ + taskPoolStatus = IotTaskPool_TryCancel( IOT_SYSTEM_TASKPOOL, + pMqttConnection->pingreq.job, + NULL ); + + /* Clean up keep-alive if its job was successfully canceled. Otherwise, + * the executing keep-alive job will clean up itself. */ + if( taskPoolStatus == IOT_TASKPOOL_SUCCESS ) + { + /* Free the packet */ + _getMqttFreePacketFunc( pMqttConnection->pSerializer )( pMqttConnection->pingreq.u.operation.pMqttPacket ); + + /* Clear data about the keep-alive. */ + pMqttConnection->pingreq.u.operation.periodic.ping.keepAliveMs = 0; + pMqttConnection->pingreq.u.operation.pMqttPacket = NULL; + pMqttConnection->pingreq.u.operation.packetSize = 0; + + /* Keep-alive is cleaned up; decrement reference count. Since this + * function must be followed with a call to DISCONNECT, a check to + * destroy the connection is not done here. */ + pMqttConnection->references--; + + IotLogDebug( "(MQTT connection %p) Keep-alive job canceled and cleaned up.", + pMqttConnection ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Copy the function pointers and contexts, as the MQTT connection may be + * modified after the mutex is released. */ + disconnectCallback = pMqttConnection->disconnectCallback.function; + pDisconnectCallbackContext = pMqttConnection->disconnectCallback.pCallbackContext; + + closeConnection = pMqttConnection->pNetworkInterface->close; + pNetworkConnection = pMqttConnection->pNetworkConnection; + + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + + /* Close the network connection. */ + if( closeConnection != NULL ) + { + closeStatus = closeConnection( pNetworkConnection ); + + if( closeStatus == IOT_NETWORK_SUCCESS ) + { + IotLogInfo( "(MQTT connection %p) Network connection closed.", pMqttConnection ); + } + else + { + IotLogWarn( "(MQTT connection %p) Failed to close network connection, error %d.", + pMqttConnection, + closeStatus ); + } + } + else + { + IotLogWarn( "(MQTT connection %p) No network close function was set. Network connection" + " not closed.", pMqttConnection ); + } + + /* Invoke the disconnect callback. */ + if( disconnectCallback != NULL ) + { + /* Set the members of the callback parameter. */ + callbackParam.mqttConnection = pMqttConnection; + callbackParam.u.disconnectReason = disconnectReason; + + disconnectCallback( pDisconnectCallbackContext, + &callbackParam ); + } + else + { + EMPTY_ELSE_MARKER; + } +} + +/*-----------------------------------------------------------*/ + +void IotMqtt_ReceiveCallback( IotNetworkConnection_t pNetworkConnection, + void * pReceiveContext ) +{ + IotMqttError_t status = IOT_MQTT_SUCCESS; + _mqttPacket_t incomingPacket = { .u.pMqttConnection = NULL }; + + /* Cast context to correct type. */ + _mqttConnection_t * pMqttConnection = ( _mqttConnection_t * ) pReceiveContext; + + /* Read an MQTT packet from the network. */ + status = _getIncomingPacket( pNetworkConnection, + pMqttConnection, + &incomingPacket ); + + if( status == IOT_MQTT_SUCCESS ) + { + /* Deserialize the received packet. */ + status = _deserializeIncomingPacket( pMqttConnection, + &incomingPacket ); + + /* Free any buffers allocated for the MQTT packet. */ + if( incomingPacket.pRemainingData != NULL ) + { + IotMqtt_FreeMessage( incomingPacket.pRemainingData ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Close the network connection on a bad response. */ + if( status == IOT_MQTT_BAD_RESPONSE ) + { + IotLogError( "(MQTT connection %p) Error processing incoming data. Closing connection.", + pMqttConnection ); + + _IotMqtt_CloseNetworkConnection( IOT_MQTT_BAD_PACKET_RECEIVED, + pMqttConnection ); + } + else + { + EMPTY_ELSE_MARKER; + } +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_GetIncomingMQTTPacketTypeAndLength( IotMqttPacketInfo_t * pIncomingPacket, + IotMqttGetNextByte_t getNextByte, + void * pNetworkConnection ) +{ + IotMqttError_t status = IOT_MQTT_SUCCESS; + + /* Read the packet type, which is the first byte available. */ + if( getNextByte( pNetworkConnection, &( pIncomingPacket->type ) ) == IOT_MQTT_SUCCESS ) + { + /* Check that the incoming packet type is valid. */ + if( _incomingPacketValid( pIncomingPacket->type ) == false ) + { + IotLogError( "(MQTT connection) Unknown packet type %02x received.", + pIncomingPacket->type ); + + status = IOT_MQTT_BAD_RESPONSE; + } + else + { + /* Read the remaining length. */ + pIncomingPacket->remainingLength = _IotMqtt_GetRemainingLength_Generic( pNetworkConnection, + getNextByte ); + + if( pIncomingPacket->remainingLength == MQTT_REMAINING_LENGTH_INVALID ) + { + status = IOT_MQTT_BAD_RESPONSE; + } + } + } + else + { + status = IOT_MQTT_NETWORK_ERROR; + } + + return status; +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_operation.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_operation.c new file mode 100644 index 000000000..00a5b53bc --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_operation.c @@ -0,0 +1,1344 @@ +/* + * IoT MQTT V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_mqtt_operation.c + * @brief Implements functions that process MQTT operations. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* Error handling include. */ +#include "iot_error.h" + +/* MQTT internal include. */ +#include "private/iot_mqtt_internal.h" + +/* Platform layer includes. */ +#include "platform/iot_clock.h" +#include "platform/iot_threads.h" + +/* Atomics include. */ +#include "iot_atomic.h" + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * Declaration of local MQTT serializer override selectors + */ +#if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttPublishSetDup_t, + _getMqttPublishSetDupFunc, + _IotMqtt_PublishSetDup, + serialize.publishSetDup ) + _SERIALIZER_OVERRIDE_SELECTOR( IotMqttFreePacket_t, + _getMqttFreePacketFunc, + _IotMqtt_FreePacket, + freePacket ) +#else /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */ + #define _getMqttFreePacketFunc( pSerializer ) _IotMqtt_FreePacket + #define _getMqttPublishSetDupFunc( pSerializer ) _IotMqtt_PublishSetDup +#endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */ +/** @endcond */ + +/*-----------------------------------------------------------*/ + +/** + * @brief First parameter to #_mqttOperation_match. + */ +typedef struct _operationMatchParam +{ + IotMqttOperationType_t type; /**< @brief The type of operation to look for. */ + const uint16_t * pPacketIdentifier; /**< @brief The packet identifier associated with the operation. + * Set to `NULL` to ignore packet identifier. */ +} _operationMatchParam_t; + +/*-----------------------------------------------------------*/ + +/** + * @brief Match an MQTT operation by type and packet identifier. + * + * @param[in] pOperationLink Pointer to the link member of an #_mqttOperation_t. + * @param[in] pMatch Pointer to an #_operationMatchParam_t. + * + * @return `true` if the operation matches the parameters in `pArgument`; `false` + * otherwise. + */ +static bool _mqttOperation_match( const IotLink_t * pOperationLink, + void * pMatch ); + +/** + * @brief Check if an operation with retry has exceeded its retry limit. + * + * If a PUBLISH operation is available for retry, this function also sets any + * necessary DUP flags. + * + * @param[in] pOperation The operation to check. + * + * @return `true` if the operation may be retried; `false` otherwise. + */ +static bool _checkRetryLimit( _mqttOperation_t * pOperation ); + +/** + * @brief Schedule the next send of an operation with retry. + * + * @param[in] pOperation The operation to schedule. + * + * @return `true` if the reschedule succeeded; `false` otherwise. + */ +static bool _scheduleNextRetry( _mqttOperation_t * pOperation ); + +/*-----------------------------------------------------------*/ + +static bool _mqttOperation_match( const IotLink_t * pOperationLink, + void * pMatch ) +{ + bool match = false; + + /* Because this function is called from a container function, the given link + * must never be NULL. */ + IotMqtt_Assert( pOperationLink != NULL ); + + _mqttOperation_t * pOperation = IotLink_Container( _mqttOperation_t, + pOperationLink, + link ); + _operationMatchParam_t * pParam = ( _operationMatchParam_t * ) pMatch; + + /* Check for matching operations. */ + if( pParam->type == pOperation->u.operation.type ) + { + /* Check for matching packet identifiers. */ + if( pParam->pPacketIdentifier == NULL ) + { + match = true; + } + else + { + match = ( *( pParam->pPacketIdentifier ) == pOperation->u.operation.packetIdentifier ); + } + } + else + { + EMPTY_ELSE_MARKER; + } + + return match; +} + +/*-----------------------------------------------------------*/ + +static bool _checkRetryLimit( _mqttOperation_t * pOperation ) +{ + _mqttConnection_t * pMqttConnection = pOperation->pMqttConnection; + bool status = true, setDup = false; + + /* Only PUBLISH may be retried. */ + IotMqtt_Assert( pOperation->u.operation.type == IOT_MQTT_PUBLISH_TO_SERVER ); + + /* Check if the retry limit is exhausted. */ + if( pOperation->u.operation.periodic.retry.count > pOperation->u.operation.periodic.retry.limit ) + { + /* The retry count may be at most one more than the retry limit, which + * accounts for the final check for a PUBACK. */ + IotMqtt_Assert( pOperation->u.operation.periodic.retry.count == + pOperation->u.operation.periodic.retry.limit + 1 ); + + IotLogDebug( "(MQTT connection %p, PUBLISH operation %p) No response received after %lu retries.", + pMqttConnection, + pOperation, + pOperation->u.operation.periodic.retry.limit ); + + status = false; + } + else + { + if( pOperation->u.operation.periodic.retry.count == 1 ) + { + /* The DUP flag should always be set on the first retry. */ + setDup = true; + } + else if( pMqttConnection->awsIotMqttMode == true ) + { + /* In AWS IoT MQTT mode, the DUP flag (really a change to the packet + * identifier) must be reset on every retry. */ + setDup = true; + } + else + { + EMPTY_ELSE_MARKER; + } + + if( setDup == true ) + { + /* In AWS IoT MQTT mode, the references mutex must be locked to + * prevent the packet identifier from being read while it is being + * changed. */ + if( pMqttConnection->awsIotMqttMode == true ) + { + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Set the DUP flag */ + _getMqttPublishSetDupFunc( pMqttConnection->pSerializer )( pOperation->u.operation.pMqttPacket, + pOperation->u.operation.pPacketIdentifierHigh, + &( pOperation->u.operation.packetIdentifier ) ); + + if( pMqttConnection->awsIotMqttMode == true ) + { + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + } + + return status; +} + +/*-----------------------------------------------------------*/ + +static bool _scheduleNextRetry( _mqttOperation_t * pOperation ) +{ + bool firstRetry = false; + uint32_t scheduleDelay = 0; + IotMqttError_t status = IOT_MQTT_STATUS_PENDING; + _mqttConnection_t * pMqttConnection = pOperation->pMqttConnection; + + /* This function should never be called with retry count greater than + * retry limit. */ + IotMqtt_Assert( pOperation->u.operation.periodic.retry.count <= + pOperation->u.operation.periodic.retry.limit ); + + /* Increment the retry count. */ + ( pOperation->u.operation.periodic.retry.count )++; + + /* Check for a response shortly for the final retry. Otherwise, calculate the + * next retry period. */ + if( pOperation->u.operation.periodic.retry.count > + pOperation->u.operation.periodic.retry.limit ) + { + scheduleDelay = IOT_MQTT_RESPONSE_WAIT_MS; + + IotLogDebug( "(MQTT connection %p, PUBLISH operation %p) Final retry was sent. Will check " + "for response in %d ms.", + pMqttConnection, + pOperation, + IOT_MQTT_RESPONSE_WAIT_MS ); + } + else + { + scheduleDelay = pOperation->u.operation.periodic.retry.nextPeriodMs; + + /* Double the retry period, subject to a ceiling value. */ + pOperation->u.operation.periodic.retry.nextPeriodMs *= 2; + + if( pOperation->u.operation.periodic.retry.nextPeriodMs > IOT_MQTT_RETRY_MS_CEILING ) + { + pOperation->u.operation.periodic.retry.nextPeriodMs = IOT_MQTT_RETRY_MS_CEILING; + } + else + { + EMPTY_ELSE_MARKER; + } + + IotLogDebug( "(MQTT connection %p, PUBLISH operation %p) Scheduling retry %lu of %lu in %lu ms.", + pMqttConnection, + pOperation, + ( unsigned long ) pOperation->u.operation.periodic.retry.count, + ( unsigned long ) pOperation->u.operation.periodic.retry.limit, + ( unsigned long ) scheduleDelay ); + + /* Check if this is the first retry. */ + firstRetry = ( pOperation->u.operation.periodic.retry.count == 1 ); + + /* On the first retry, the PUBLISH will be moved from the pending processing + * list to the pending responses list. Lock the connection references mutex + * to manipulate the lists. */ + if( firstRetry == true ) + { + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + + /* Reschedule the PUBLISH for another send. */ + status = _IotMqtt_ScheduleOperation( pOperation, + _IotMqtt_ProcessSend, + scheduleDelay ); + + /* Check for successful reschedule. */ + if( status == IOT_MQTT_SUCCESS ) + { + /* Move a successfully rescheduled PUBLISH from the pending processing + * list to the pending responses list on the first retry. */ + if( firstRetry == true ) + { + if( IotLink_IsLinked( &( pOperation->link ) ) == true ) + { + IotListDouble_Remove( &( pOperation->link ) ); + } + + IotListDouble_InsertHead( &( pMqttConnection->pendingResponse ), + &( pOperation->link ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* The references mutex only needs to be unlocked on the first retry, since + * only the first retry manipulates the connection lists. */ + if( firstRetry == true ) + { + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + + return( status == IOT_MQTT_SUCCESS ); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_CreateOperation( _mqttConnection_t * pMqttConnection, + uint32_t flags, + const IotMqttCallbackInfo_t * pCallbackInfo, + _mqttOperation_t ** pNewOperation ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + bool decrementOnError = false; + _mqttOperation_t * pOperation = NULL; + bool waitable = ( ( flags & IOT_MQTT_FLAG_WAITABLE ) == IOT_MQTT_FLAG_WAITABLE ); + + /* If the waitable flag is set, make sure that there's no callback. */ + if( waitable == true ) + { + if( pCallbackInfo != NULL ) + { + IotLogError( "Callback should not be set for a waitable operation." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + IotLogDebug( "(MQTT connection %p) Creating new operation record.", + pMqttConnection ); + + /* Increment the reference count for the MQTT connection when creating a new + * operation. */ + if( _IotMqtt_IncrementConnectionReferences( pMqttConnection ) == false ) + { + IotLogError( "(MQTT connection %p) New operation record cannot be created" + " for a closed connection", + pMqttConnection ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NETWORK_ERROR ); + } + else + { + /* Reference count will need to be decremented on error. */ + decrementOnError = true; + } + + /* Allocate memory for a new operation. */ + pOperation = IotMqtt_MallocOperation( sizeof( _mqttOperation_t ) ); + + if( pOperation == NULL ) + { + IotLogError( "(MQTT connection %p) Failed to allocate memory for new " + "operation record.", + pMqttConnection ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY ); + } + else + { + /* Clear the operation data. */ + ( void ) memset( pOperation, 0x00, sizeof( _mqttOperation_t ) ); + + /* Initialize some members of the new operation. */ + pOperation->pMqttConnection = pMqttConnection; + pOperation->u.operation.jobReference = 1; + pOperation->u.operation.flags = flags; + pOperation->u.operation.status = IOT_MQTT_STATUS_PENDING; + } + + /* Check if the waitable flag is set. If it is, create a semaphore to + * wait on. */ + if( waitable == true ) + { + /* Create a semaphore to wait on for a waitable operation. */ + if( IotSemaphore_Create( &( pOperation->u.operation.notify.waitSemaphore ), 0, 1 ) == false ) + { + IotLogError( "(MQTT connection %p) Failed to create semaphore for " + "waitable operation.", + pMqttConnection ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY ); + } + else + { + /* A waitable operation is created with an additional reference for the + * Wait function. */ + ( pOperation->u.operation.jobReference )++; + } + } + else + { + /* If the waitable flag isn't set but a callback is, copy the callback + * information. */ + if( pCallbackInfo != NULL ) + { + pOperation->u.operation.notify.callback = *pCallbackInfo; + } + else + { + EMPTY_ELSE_MARKER; + } + } + + /* Add this operation to the MQTT connection's operation list. */ + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + IotListDouble_InsertHead( &( pMqttConnection->pendingProcessing ), + &( pOperation->link ) ); + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + + /* Set the output parameter. */ + *pNewOperation = pOperation; + + /* Clean up operation and decrement reference count if this function failed. */ + IOT_FUNCTION_CLEANUP_BEGIN(); + + if( status != IOT_MQTT_SUCCESS ) + { + if( decrementOnError == true ) + { + _IotMqtt_DecrementConnectionReferences( pMqttConnection ); + } + else + { + EMPTY_ELSE_MARKER; + } + + if( pOperation != NULL ) + { + IotMqtt_FreeOperation( pOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_FUNCTION_CLEANUP_END(); +} + +/*-----------------------------------------------------------*/ + +bool _IotMqtt_DecrementOperationReferences( _mqttOperation_t * pOperation, + bool cancelJob ) +{ + bool destroyOperation = false; + IotTaskPoolError_t taskPoolStatus = IOT_TASKPOOL_SUCCESS; + _mqttConnection_t * pMqttConnection = pOperation->pMqttConnection; + + /* Attempt to cancel the operation's job. */ + if( cancelJob == true ) + { + taskPoolStatus = IotTaskPool_TryCancel( IOT_SYSTEM_TASKPOOL, + pOperation->job, + NULL ); + + if( taskPoolStatus == IOT_TASKPOOL_SUCCESS ) + { + IotLogDebug( "(MQTT connection %p, %s operation %p) Job canceled.", + pMqttConnection, + IotMqtt_OperationType( pOperation->u.operation.type ), + pOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Decrement job reference count. */ + if( taskPoolStatus == IOT_TASKPOOL_SUCCESS ) + { + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + pOperation->u.operation.jobReference--; + + IotLogDebug( "(MQTT connection %p, %s operation %p) Job reference changed" + " from %ld to %ld.", + pMqttConnection, + IotMqtt_OperationType( pOperation->u.operation.type ), + pOperation, + ( long ) ( pOperation->u.operation.jobReference + 1 ), + ( long ) ( pOperation->u.operation.jobReference ) ); + + /* The job reference count must be 0 or 1 after the decrement. */ + IotMqtt_Assert( ( pOperation->u.operation.jobReference == 0 ) || + ( pOperation->u.operation.jobReference == 1 ) ); + + /* This operation may be destroyed if its reference count is 0. */ + if( pOperation->u.operation.jobReference == 0 ) + { + destroyOperation = true; + } + else + { + EMPTY_ELSE_MARKER; + } + + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + + return destroyOperation; +} + +/*-----------------------------------------------------------*/ + +void _IotMqtt_DestroyOperation( _mqttOperation_t * pOperation ) +{ + _mqttConnection_t * pMqttConnection = pOperation->pMqttConnection; + + IotLogDebug( "(MQTT connection %p, %s operation %p) Destroying operation.", + pMqttConnection, + IotMqtt_OperationType( pOperation->u.operation.type ), + pOperation ); + + /* The job reference count must be between 0 and 2. */ + IotMqtt_Assert( ( pOperation->u.operation.jobReference >= 0 ) && + ( pOperation->u.operation.jobReference <= 2 ) ); + + /* Jobs to be destroyed should be removed from the MQTT connection's + * lists. */ + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + + if( IotLink_IsLinked( &( pOperation->link ) ) == true ) + { + IotLogDebug( "(MQTT connection %p, %s operation %p) Removed operation from connection lists.", + pMqttConnection, + IotMqtt_OperationType( pOperation->u.operation.type ), + pOperation, + pMqttConnection ); + + IotListDouble_Remove( &( pOperation->link ) ); + } + else + { + IotLogDebug( "(MQTT connection %p, %s operation %p) Operation was not present in connection lists.", + pMqttConnection, + IotMqtt_OperationType( pOperation->u.operation.type ), + pOperation ); + } + + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + + /* Free any allocated MQTT packet. */ + if( pOperation->u.operation.pMqttPacket != NULL ) + { + _getMqttFreePacketFunc( pMqttConnection->pSerializer )( pOperation->u.operation.pMqttPacket ); + + IotLogDebug( "(MQTT connection %p, %s operation %p) MQTT packet freed.", + pMqttConnection, + IotMqtt_OperationType( pOperation->u.operation.type ), + pOperation ); + } + else + { + IotLogDebug( "(MQTT connection %p, %s operation %p) Operation has no allocated MQTT packet.", + pMqttConnection, + IotMqtt_OperationType( pOperation->u.operation.type ), + pOperation ); + } + + /* Check if a wait semaphore was created for this operation. */ + if( ( pOperation->u.operation.flags & IOT_MQTT_FLAG_WAITABLE ) == IOT_MQTT_FLAG_WAITABLE ) + { + IotSemaphore_Destroy( &( pOperation->u.operation.notify.waitSemaphore ) ); + + IotLogDebug( "(MQTT connection %p, %s operation %p) Wait semaphore destroyed.", + pMqttConnection, + IotMqtt_OperationType( pOperation->u.operation.type ), + pOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + + IotLogDebug( "(MQTT connection %p, %s operation %p) Operation record destroyed.", + pMqttConnection, + IotMqtt_OperationType( pOperation->u.operation.type ), + pOperation ); + + /* Free the memory used to hold operation data. */ + IotMqtt_FreeOperation( pOperation ); + + /* Decrement the MQTT connection's reference count after destroying an + * operation. */ + _IotMqtt_DecrementConnectionReferences( pMqttConnection ); +} + +/*-----------------------------------------------------------*/ + +void _IotMqtt_ProcessKeepAlive( IotTaskPool_t pTaskPool, + IotTaskPoolJob_t pKeepAliveJob, + void * pContext ) +{ + bool status = true; + uint32_t swapStatus = 0; + IotTaskPoolError_t taskPoolStatus = IOT_TASKPOOL_SUCCESS; + size_t bytesSent = 0; + + /* Swap status is not checked when asserts are disabled. */ + ( void ) swapStatus; + + /* Retrieve the MQTT connection from the context. */ + _mqttConnection_t * pMqttConnection = ( _mqttConnection_t * ) pContext; + _mqttOperation_t * pPingreqOperation = &( pMqttConnection->pingreq ); + + /* Check parameters. */ + IotMqtt_Assert( pKeepAliveJob == pPingreqOperation->job ); + + /* Check that keep-alive interval is valid. The MQTT spec states its maximum + * value is 65,535 seconds. */ + IotMqtt_Assert( pPingreqOperation->u.operation.periodic.ping.keepAliveMs <= 65535000 ); + + /* Only two values are valid for the next keep alive job delay. */ + IotMqtt_Assert( ( pPingreqOperation->u.operation.periodic.ping.nextPeriodMs == + pPingreqOperation->u.operation.periodic.ping.keepAliveMs ) || + ( pPingreqOperation->u.operation.periodic.ping.nextPeriodMs + == IOT_MQTT_RESPONSE_WAIT_MS ) ); + + IotLogDebug( "(MQTT connection %p) Keep-alive job started.", pMqttConnection ); + + /* Determine whether to send a PINGREQ or check for PINGRESP. */ + if( pPingreqOperation->u.operation.periodic.ping.nextPeriodMs == + pPingreqOperation->u.operation.periodic.ping.keepAliveMs ) + { + IotLogDebug( "(MQTT connection %p) Sending PINGREQ.", pMqttConnection ); + + /* Because PINGREQ may be used to keep the MQTT connection alive, it is + * more important than other operations. Bypass the queue of jobs for + * operations by directly sending the PINGREQ in this job. */ + bytesSent = pMqttConnection->pNetworkInterface->send( pMqttConnection->pNetworkConnection, + pPingreqOperation->u.operation.pMqttPacket, + pPingreqOperation->u.operation.packetSize ); + + if( bytesSent != pPingreqOperation->u.operation.packetSize ) + { + IotLogError( "(MQTT connection %p) Failed to send PINGREQ.", pMqttConnection ); + status = false; + } + else + { + /* Assume the keep-alive will fail. The network receive callback will + * clear the failure flag upon receiving a PINGRESP. */ + swapStatus = Atomic_CompareAndSwap_u32( &( pPingreqOperation->u.operation.periodic.ping.failure ), + 1, + 0 ); + IotMqtt_Assert( swapStatus == 1 ); + + /* Schedule a check for PINGRESP. */ + pPingreqOperation->u.operation.periodic.ping.nextPeriodMs = IOT_MQTT_RESPONSE_WAIT_MS; + + IotLogDebug( "(MQTT connection %p) PINGREQ sent. Scheduling check for PINGRESP in %d ms.", + pMqttConnection, + IOT_MQTT_RESPONSE_WAIT_MS ); + } + } + else + { + IotLogDebug( "(MQTT connection %p) Checking for PINGRESP.", pMqttConnection ); + + if( Atomic_Add_u32( &( pPingreqOperation->u.operation.periodic.ping.failure ), 0 ) == 0 ) + { + IotLogDebug( "(MQTT connection %p) PINGRESP was received.", pMqttConnection ); + + /* PINGRESP was received. Schedule the next PINGREQ transmission. */ + pPingreqOperation->u.operation.periodic.ping.nextPeriodMs = + pPingreqOperation->u.operation.periodic.ping.keepAliveMs; + } + else + { + IotLogError( "(MQTT connection %p) Failed to receive PINGRESP within %d ms.", + pMqttConnection, + IOT_MQTT_RESPONSE_WAIT_MS ); + + /* The network receive callback did not clear the failure flag. */ + status = false; + } + } + + /* When a PINGREQ is successfully sent, reschedule this job to check for a + * response shortly. */ + if( status == true ) + { + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + + /* Re-create the keep-alive job for rescheduling. This should never fail. */ + taskPoolStatus = IotTaskPool_CreateJob( _IotMqtt_ProcessKeepAlive, + pContext, + IotTaskPool_GetJobStorageFromHandle( pKeepAliveJob ), + &pKeepAliveJob ); + IotMqtt_Assert( taskPoolStatus == IOT_TASKPOOL_SUCCESS ); + + taskPoolStatus = IotTaskPool_ScheduleDeferred( pTaskPool, + pKeepAliveJob, + pPingreqOperation->u.operation.periodic.ping.nextPeriodMs ); + + if( taskPoolStatus == IOT_TASKPOOL_SUCCESS ) + { + IotLogDebug( "(MQTT connection %p) Next keep-alive job in %lu ms.", + pMqttConnection, + ( unsigned long ) pPingreqOperation->u.operation.periodic.ping.nextPeriodMs ); + } + else + { + IotLogError( "(MQTT connection %p) Failed to reschedule keep-alive job, error %s.", + pMqttConnection, + IotTaskPool_strerror( taskPoolStatus ) ); + + status = false; + } + + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Close the connection on failures. */ + if( status == false ) + { + _IotMqtt_CloseNetworkConnection( IOT_MQTT_KEEP_ALIVE_TIMEOUT, + pMqttConnection ); + + /* Keep-alive has failed and will no longer use this MQTT connection. */ + _IotMqtt_DecrementConnectionReferences( pMqttConnection ); + } + else + { + EMPTY_ELSE_MARKER; + } +} + +/*-----------------------------------------------------------*/ + +void _IotMqtt_ProcessIncomingPublish( IotTaskPool_t pTaskPool, + IotTaskPoolJob_t pPublishJob, + void * pContext ) +{ + _mqttOperation_t * pOperation = pContext; + IotMqttCallbackParam_t callbackParam = { .mqttConnection = NULL }; + + /* Check parameters. The task pool and job parameter is not used when asserts + * are disabled. */ + ( void ) pTaskPool; + ( void ) pPublishJob; + IotMqtt_Assert( pOperation->incomingPublish == true ); + IotMqtt_Assert( pPublishJob == pOperation->job ); + + /* Remove the operation from the pending processing list. */ + IotMutex_Lock( &( pOperation->pMqttConnection->referencesMutex ) ); + + if( IotLink_IsLinked( &( pOperation->link ) ) == true ) + { + IotListDouble_Remove( &( pOperation->link ) ); + } + else + { + /* This operation may have already been removed by cleanup of pending + * operations (called from Disconnect). In that case, do nothing here. */ + EMPTY_ELSE_MARKER; + } + + IotMutex_Unlock( &( pOperation->pMqttConnection->referencesMutex ) ); + + /* Process the current PUBLISH. */ + callbackParam.u.message.info = pOperation->u.publish.publishInfo; + + _IotMqtt_InvokeSubscriptionCallback( pOperation->pMqttConnection, + &callbackParam ); + + /* Free buffers associated with the current PUBLISH message. */ + IotMqtt_Assert( pOperation->u.publish.pReceivedData != NULL ); + IotMqtt_FreeMessage( ( void * ) pOperation->u.publish.pReceivedData ); + + /* Free the incoming PUBLISH operation. */ + IotMqtt_FreeOperation( pOperation ); +} + +/*-----------------------------------------------------------*/ + +void _IotMqtt_ProcessSend( IotTaskPool_t pTaskPool, + IotTaskPoolJob_t pSendJob, + void * pContext ) +{ + size_t bytesSent = 0; + bool destroyOperation = false, waitable = false, networkPending = false; + _mqttOperation_t * pOperation = ( _mqttOperation_t * ) pContext; + _mqttConnection_t * pMqttConnection = pOperation->pMqttConnection; + + /* Check parameters. The task pool and job parameter is not used when asserts + * are disabled. */ + ( void ) pTaskPool; + ( void ) pSendJob; + IotMqtt_Assert( pSendJob == pOperation->job ); + + /* The given operation must have an allocated packet and be waiting for a status. */ + IotMqtt_Assert( pOperation->u.operation.pMqttPacket != NULL ); + IotMqtt_Assert( pOperation->u.operation.packetSize != 0 ); + IotMqtt_Assert( pOperation->u.operation.status == IOT_MQTT_STATUS_PENDING ); + + /* Check if this operation is waitable. */ + waitable = ( pOperation->u.operation.flags & IOT_MQTT_FLAG_WAITABLE ) == IOT_MQTT_FLAG_WAITABLE; + + /* Check PUBLISH retry counts and limits. */ + if( pOperation->u.operation.periodic.retry.limit > 0 ) + { + if( _checkRetryLimit( pOperation ) == false ) + { + pOperation->u.operation.status = IOT_MQTT_RETRY_NO_RESPONSE; + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Send an operation that is waiting for a response. */ + if( pOperation->u.operation.status == IOT_MQTT_STATUS_PENDING ) + { + IotLogDebug( "(MQTT connection %p, %s operation %p) Sending MQTT packet.", + pMqttConnection, + IotMqtt_OperationType( pOperation->u.operation.type ), + pOperation ); + + /* Transmit the MQTT packet from the operation over the network. */ + bytesSent = pMqttConnection->pNetworkInterface->send( pMqttConnection->pNetworkConnection, + pOperation->u.operation.pMqttPacket, + pOperation->u.operation.packetSize ); + + /* Check transmission status. */ + if( bytesSent != pOperation->u.operation.packetSize ) + { + pOperation->u.operation.status = IOT_MQTT_NETWORK_ERROR; + } + else + { + /* DISCONNECT operations are considered successful upon successful + * transmission. In addition, non-waitable operations with no callback + * may also be considered successful. */ + if( pOperation->u.operation.type == IOT_MQTT_DISCONNECT ) + { + /* DISCONNECT operations are always waitable. */ + IotMqtt_Assert( waitable == true ); + + pOperation->u.operation.status = IOT_MQTT_SUCCESS; + } + else if( waitable == false ) + { + if( pOperation->u.operation.notify.callback.function == NULL ) + { + pOperation->u.operation.status = IOT_MQTT_SUCCESS; + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check if this operation requires further processing. */ + if( pOperation->u.operation.status == IOT_MQTT_STATUS_PENDING ) + { + /* Check if this operation should be scheduled for retransmission. */ + if( pOperation->u.operation.periodic.retry.limit > 0 ) + { + if( _scheduleNextRetry( pOperation ) == false ) + { + pOperation->u.operation.status = IOT_MQTT_SCHEDULING_ERROR; + } + else + { + /* A successfully scheduled PUBLISH retry is awaiting a response + * from the network. */ + networkPending = true; + } + } + else + { + /* Decrement reference count to signal completion of send job. Check + * if the operation should be destroyed. */ + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + + if( waitable == true ) + { + destroyOperation = _IotMqtt_DecrementOperationReferences( pOperation, false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* If the operation should not be destroyed, transfer it from the + * pending processing to the pending response list. */ + if( destroyOperation == false ) + { + if( IotLink_IsLinked( &( pOperation->link ) ) == true ) + { + IotListDouble_Remove( &( pOperation->link ) ); + } + + IotListDouble_InsertHead( &( pMqttConnection->pendingResponse ), + &( pOperation->link ) ); + + /* This operation is now awaiting a response from the network. */ + networkPending = true; + } + else + { + EMPTY_ELSE_MARKER; + } + + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Destroy the operation or notify of completion if necessary. */ + if( destroyOperation == true ) + { + _IotMqtt_DestroyOperation( pOperation ); + } + else + { + /* Do not check the operation status if a network response is pending, + * since a network response could modify the status. */ + if( networkPending == false ) + { + /* Notify of operation completion if this job set a status. */ + if( pOperation->u.operation.status != IOT_MQTT_STATUS_PENDING ) + { + _IotMqtt_Notify( pOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + } +} + +/*-----------------------------------------------------------*/ + +void _IotMqtt_ProcessCompletedOperation( IotTaskPool_t pTaskPool, + IotTaskPoolJob_t pOperationJob, + void * pContext ) +{ + _mqttOperation_t * pOperation = ( _mqttOperation_t * ) pContext; + IotMqttCallbackParam_t callbackParam = { 0 }; + + /* Check parameters. The task pool and job parameter is not used when asserts + * are disabled. */ + ( void ) pTaskPool; + ( void ) pOperationJob; + IotMqtt_Assert( pOperationJob == pOperation->job ); + + /* The operation's callback function and status must be set. */ + IotMqtt_Assert( pOperation->u.operation.notify.callback.function != NULL ); + IotMqtt_Assert( pOperation->u.operation.status != IOT_MQTT_STATUS_PENDING ); + + callbackParam.mqttConnection = pOperation->pMqttConnection; + callbackParam.u.operation.type = pOperation->u.operation.type; + callbackParam.u.operation.reference = pOperation; + callbackParam.u.operation.result = pOperation->u.operation.status; + + /* Invoke the user callback function. */ + pOperation->u.operation.notify.callback.function( pOperation->u.operation.notify.callback.pCallbackContext, + &callbackParam ); + + /* Attempt to destroy the operation once the user callback returns. */ + if( _IotMqtt_DecrementOperationReferences( pOperation, false ) == true ) + { + _IotMqtt_DestroyOperation( pOperation ); + } + else + { + EMPTY_ELSE_MARKER; + } +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_ScheduleOperation( _mqttOperation_t * pOperation, + IotTaskPoolRoutine_t jobRoutine, + uint32_t delay ) +{ + IotMqttError_t status = IOT_MQTT_SUCCESS; + IotTaskPoolError_t taskPoolStatus = IOT_TASKPOOL_SUCCESS; + + /* Check that job routine is valid. */ + IotMqtt_Assert( ( jobRoutine == _IotMqtt_ProcessSend ) || + ( jobRoutine == _IotMqtt_ProcessCompletedOperation ) || + ( jobRoutine == _IotMqtt_ProcessIncomingPublish ) ); + + /* Creating a new job should never fail when parameters are valid. */ + taskPoolStatus = IotTaskPool_CreateJob( jobRoutine, + pOperation, + &( pOperation->jobStorage ), + &( pOperation->job ) ); + IotMqtt_Assert( taskPoolStatus == IOT_TASKPOOL_SUCCESS ); + + /* Schedule the new job with a delay. */ + taskPoolStatus = IotTaskPool_ScheduleDeferred( IOT_SYSTEM_TASKPOOL, + pOperation->job, + delay ); + + if( taskPoolStatus != IOT_TASKPOOL_SUCCESS ) + { + /* Scheduling a newly-created job should never be invalid or illegal. */ + IotMqtt_Assert( taskPoolStatus != IOT_TASKPOOL_BAD_PARAMETER ); + IotMqtt_Assert( taskPoolStatus != IOT_TASKPOOL_ILLEGAL_OPERATION ); + + IotLogWarn( "(MQTT connection %p, %s operation %p) Failed to schedule operation job, error %s.", + pOperation->pMqttConnection, + IotMqtt_OperationType( pOperation->u.operation.type ), + pOperation, + IotTaskPool_strerror( taskPoolStatus ) ); + + status = IOT_MQTT_SCHEDULING_ERROR; + } + else + { + EMPTY_ELSE_MARKER; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +_mqttOperation_t * _IotMqtt_FindOperation( _mqttConnection_t * pMqttConnection, + IotMqttOperationType_t type, + const uint16_t * pPacketIdentifier ) +{ + bool waitable = false; + IotTaskPoolError_t taskPoolStatus = IOT_TASKPOOL_SUCCESS; + _mqttOperation_t * pResult = NULL; + IotLink_t * pResultLink = NULL; + _operationMatchParam_t operationMatchParams = { 0 }; + + /* Set the members of the search parameter. */ + operationMatchParams.type = type; + operationMatchParams.pPacketIdentifier = pPacketIdentifier; + + if( pPacketIdentifier != NULL ) + { + IotLogDebug( "(MQTT connection %p) Searching for operation %s pending response " + "with packet identifier %hu.", + pMqttConnection, + IotMqtt_OperationType( type ), + *pPacketIdentifier ); + } + else + { + IotLogDebug( "(MQTT connection %p) Searching for operation %s pending response.", + pMqttConnection, + IotMqtt_OperationType( type ) ); + } + + /* Find and remove the first matching element in the list. */ + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + pResultLink = IotListDouble_FindFirstMatch( &( pMqttConnection->pendingResponse ), + NULL, + _mqttOperation_match, + &operationMatchParams ); + + /* Check if a match was found. */ + if( pResultLink != NULL ) + { + /* Get operation pointer and check if it is waitable. */ + pResult = IotLink_Container( _mqttOperation_t, pResultLink, link ); + waitable = ( pResult->u.operation.flags & IOT_MQTT_FLAG_WAITABLE ) == IOT_MQTT_FLAG_WAITABLE; + + /* Check if the matched operation is a PUBLISH with retry. If it is, cancel + * the retry job. */ + if( pResult->u.operation.periodic.retry.limit > 0 ) + { + taskPoolStatus = IotTaskPool_TryCancel( IOT_SYSTEM_TASKPOOL, + pResult->job, + NULL ); + + /* If the retry job could not be canceled, then it is currently + * executing. Ignore the operation. */ + if( taskPoolStatus != IOT_TASKPOOL_SUCCESS ) + { + pResult = NULL; + } + else + { + /* Check job reference counts. A waitable operation should have a + * count of 2; a non-waitable operation should have a count of 1. */ + IotMqtt_Assert( pResult->u.operation.jobReference == ( 1 + ( waitable == true ) ) ); + } + } + else + { + /* An operation with no retry in the pending responses list should + * always have a job reference of 1. */ + IotMqtt_Assert( pResult->u.operation.jobReference == 1 ); + + /* Increment job references of a waitable operation to prevent Wait from + * destroying this operation if it times out. */ + if( waitable == true ) + { + ( pResult->u.operation.jobReference )++; + + IotLogDebug( "(MQTT connection %p, %s operation %p) Job reference changed from %ld to %ld.", + pMqttConnection, + IotMqtt_OperationType( type ), + pResult, + ( long int ) ( pResult->u.operation.jobReference - 1 ), + ( long int ) ( pResult->u.operation.jobReference ) ); + } + } + } + else + { + EMPTY_ELSE_MARKER; + } + + if( pResult != NULL ) + { + IotLogDebug( "(MQTT connection %p) Found operation %s.", + pMqttConnection, + IotMqtt_OperationType( type ) ); + + /* Remove the matched operation from the list. */ + IotListDouble_Remove( &( pResult->link ) ); + } + else + { + IotLogDebug( "(MQTT connection %p) Operation %s not found.", + pMqttConnection, + IotMqtt_OperationType( type ) ); + } + + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + + return pResult; +} + +/*-----------------------------------------------------------*/ + +void _IotMqtt_Notify( _mqttOperation_t * pOperation ) +{ + IotMqttError_t status = IOT_MQTT_SCHEDULING_ERROR; + _mqttConnection_t * pMqttConnection = pOperation->pMqttConnection; + + /* Check if operation is waitable. */ + bool waitable = ( pOperation->u.operation.flags & IOT_MQTT_FLAG_WAITABLE ) == IOT_MQTT_FLAG_WAITABLE; + + /* Remove any lingering subscriptions if a SUBSCRIBE failed. Rejected + * subscriptions are removed by the deserializer, so not removed here. */ + if( pOperation->u.operation.type == IOT_MQTT_SUBSCRIBE ) + { + switch( pOperation->u.operation.status ) + { + case IOT_MQTT_SUCCESS: + break; + + case IOT_MQTT_SERVER_REFUSED: + break; + + default: + _IotMqtt_RemoveSubscriptionByPacket( pOperation->pMqttConnection, + pOperation->u.operation.packetIdentifier, + -1 ); + break; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Schedule callback invocation for non-waitable operation. */ + if( waitable == false ) + { + /* Non-waitable operation should have job reference of 1. */ + IotMqtt_Assert( pOperation->u.operation.jobReference == 1 ); + + /* Schedule an invocation of the callback. */ + if( pOperation->u.operation.notify.callback.function != NULL ) + { + IotMutex_Lock( &( pMqttConnection->referencesMutex ) ); + + status = _IotMqtt_ScheduleOperation( pOperation, + _IotMqtt_ProcessCompletedOperation, + 0 ); + + if( status == IOT_MQTT_SUCCESS ) + { + IotLogDebug( "(MQTT connection %p, %s operation %p) Callback scheduled.", + pOperation->pMqttConnection, + IotMqtt_OperationType( pOperation->u.operation.type ), + pOperation ); + + /* Place the scheduled operation back in the list of operations pending + * processing. */ + if( IotLink_IsLinked( &( pOperation->link ) ) == true ) + { + IotListDouble_Remove( &( pOperation->link ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + + IotListDouble_InsertHead( &( pMqttConnection->pendingProcessing ), + &( pOperation->link ) ); + } + else + { + IotLogWarn( "(MQTT connection %p, %s operation %p) Failed to schedule callback.", + pOperation->pMqttConnection, + IotMqtt_OperationType( pOperation->u.operation.type ), + pOperation ); + } + + IotMutex_Unlock( &( pMqttConnection->referencesMutex ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Operations that weren't scheduled may be destroyed. */ + if( status == IOT_MQTT_SCHEDULING_ERROR ) + { + /* Decrement reference count of operations not scheduled. */ + if( _IotMqtt_DecrementOperationReferences( pOperation, false ) == true ) + { + _IotMqtt_DestroyOperation( pOperation ); + } + else + { + /* Post to a waitable operation's semaphore. */ + if( waitable == true ) + { + IotLogDebug( "(MQTT connection %p, %s operation %p) Waitable operation " + "notified of completion.", + pOperation->pMqttConnection, + IotMqtt_OperationType( pOperation->u.operation.type ), + pOperation ); + + IotSemaphore_Post( &( pOperation->u.operation.notify.waitSemaphore ) ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + } + else + { + IotMqtt_Assert( status == IOT_MQTT_SUCCESS ); + } +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_serialize.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_serialize.c new file mode 100644 index 000000000..28ec46170 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_serialize.c @@ -0,0 +1,2604 @@ +/* + * IoT MQTT V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_mqtt_serialize.c + * @brief Implements functions that generate and decode MQTT network packets. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include + +/* Error handling include. */ +#include "iot_error.h" + +/* MQTT internal includes. */ +#include "private/iot_mqtt_internal.h" + +/* Platform layer includes. */ +#include "platform/iot_threads.h" + +/* Atomic operations. */ +#include "iot_atomic.h" + +/*-----------------------------------------------------------*/ + +/* + * Macros for reading the high and low byte of a 2-byte unsigned int. + */ +#define UINT16_HIGH_BYTE( x ) ( ( uint8_t ) ( x >> 8 ) ) /**< @brief Get high byte. */ +#define UINT16_LOW_BYTE( x ) ( ( uint8_t ) ( x & 0x00ff ) ) /**< @brief Get low byte. */ + +/** + * @brief Macro for decoding a 2-byte unsigned int from a sequence of bytes. + * + * @param[in] ptr A uint8_t* that points to the high byte. + */ +#define UINT16_DECODE( ptr ) \ + ( uint16_t ) ( ( ( ( uint16_t ) ( *( ptr ) ) ) << 8 ) | \ + ( ( uint16_t ) ( *( ptr + 1 ) ) ) ) + +/** + * @brief Macro for setting a bit in a 1-byte unsigned int. + * + * @param[in] x The unsigned int to set. + * @param[in] position Which bit to set. + */ +#define UINT8_SET_BIT( x, position ) ( x = ( uint8_t ) ( x | ( 0x01 << position ) ) ) + +/** + * @brief Macro for checking if a bit is set in a 1-byte unsigned int. + * + * @param[in] x The unsigned int to check. + * @param[in] position Which bit to check. + */ +#define UINT8_CHECK_BIT( x, position ) ( ( x & ( 0x01 << position ) ) == ( 0x01 << position ) ) + +/* + * Positions of each flag in the "Connect Flag" field of an MQTT CONNECT + * packet. + */ +#define MQTT_CONNECT_FLAG_CLEAN ( 1 ) /**< @brief Clean session. */ +#define MQTT_CONNECT_FLAG_WILL ( 2 ) /**< @brief Will present. */ +#define MQTT_CONNECT_FLAG_WILL_QOS1 ( 3 ) /**< @brief Will QoS1. */ +#define MQTT_CONNECT_FLAG_WILL_QOS2 ( 4 ) /**< @brief Will QoS2. */ +#define MQTT_CONNECT_FLAG_WILL_RETAIN ( 5 ) /**< @brief Will retain. */ +#define MQTT_CONNECT_FLAG_PASSWORD ( 6 ) /**< @brief Password present. */ +#define MQTT_CONNECT_FLAG_USERNAME ( 7 ) /**< @brief Username present. */ + +/* + * Positions of each flag in the first byte of an MQTT PUBLISH packet's + * fixed header. + */ +#define MQTT_PUBLISH_FLAG_RETAIN ( 0 ) /**< @brief Message retain flag. */ +#define MQTT_PUBLISH_FLAG_QOS1 ( 1 ) /**< @brief Publish QoS 1. */ +#define MQTT_PUBLISH_FLAG_QOS2 ( 2 ) /**< @brief Publish QoS 2. */ +#define MQTT_PUBLISH_FLAG_DUP ( 3 ) /**< @brief Duplicate message. */ + +/** + * @brief The constant specifying MQTT version 3.1.1. Placed in the CONNECT packet. + */ +#define MQTT_VERSION_3_1_1 ( ( uint8_t ) 4U ) + +/** + * @brief Per the MQTT 3.1.1 spec, the largest "Remaining Length" of an MQTT + * packet is this value. + */ +#define MQTT_MAX_REMAINING_LENGTH ( 268435455UL ) + +/** + * @brief The maximum possible size of a CONNECT packet. + * + * All strings in a CONNECT packet are constrained to 2-byte lengths, giving a + * maximum length smaller than the max "Remaining Length" constant above. + */ +#define MQTT_PACKET_CONNECT_MAX_SIZE ( 327700UL ) + +/* + * Constants relating to CONNACK packets, defined by MQTT 3.1.1 spec. + */ +#define MQTT_PACKET_CONNACK_REMAINING_LENGTH ( ( uint8_t ) 2 ) /**< @brief A CONNACK packet always has a "Remaining length" of 2. */ +#define MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK ( ( uint8_t ) 0x01 ) /**< @brief The "Session Present" bit is always the lowest bit. */ + +/* + * Constants relating to PUBLISH and PUBACK packets, defined by MQTT + * 3.1.1 spec. + */ +#define MQTT_PACKET_PUBACK_SIZE ( 4 ) /**< @brief A PUBACK packet is always 4 bytes in size. */ +#define MQTT_PACKET_PUBACK_REMAINING_LENGTH ( ( uint8_t ) 2 ) /**< @brief A PUBACK packet always has a "Remaining length" of 2. */ + +/* + * Constants relating to SUBACK and UNSUBACK packets, defined by MQTT + * 3.1.1 spec. + */ +#define MQTT_PACKET_SUBACK_MINIMUM_SIZE ( 5 ) /**< @brief The size of the smallest valid SUBACK packet. */ +#define MQTT_PACKET_UNSUBACK_REMAINING_LENGTH ( ( uint8_t ) 2 ) /**< @brief An UNSUBACK packet always has a "Remaining length" of 2. */ + +/* + * Constants relating to PINGREQ and PINGRESP packets, defined by MQTT 3.1.1 spec. + */ +#define MQTT_PACKET_PINGREQ_SIZE ( 2 ) /**< @brief A PINGREQ packet is always 2 bytes in size. */ +#define MQTT_PACKET_PINGRESP_REMAINING_LENGTH ( 0 ) /**< @brief A PINGRESP packet always has a "Remaining length" of 0. */ + +/* + * Constants relating to DISCONNECT packets, defined by MQTT 3.1.1 spec. + */ +#define MQTT_PACKET_DISCONNECT_SIZE ( 2 ) /**< @brief A DISCONNECT packet is always 2 bytes in size. */ + +/* Username for metrics with AWS IoT. */ +#if AWS_IOT_MQTT_ENABLE_METRICS == 1 || DOXYGEN == 1 + #ifndef AWS_IOT_METRICS_USERNAME + +/** + * @brief Specify C SDK and version. + */ + #define AWS_IOT_METRICS_USERNAME "?SDK=C&Version=4.0.0" + +/** + * @brief The length of #AWS_IOT_METRICS_USERNAME. + */ + #define AWS_IOT_METRICS_USERNAME_LENGTH ( ( uint16_t ) sizeof( AWS_IOT_METRICS_USERNAME ) - 1 ) + #endif /* ifndef AWS_IOT_METRICS_USERNAME */ +#endif /* if AWS_IOT_MQTT_ENABLE_METRICS == 1 || DOXYGEN == 1 */ + +/*-----------------------------------------------------------*/ + +/** + * @brief Generate and return a 2-byte packet identifier. + * + * This packet identifier will be nonzero. + * + * @return The packet identifier. + */ +static uint16_t _nextPacketIdentifier( void ); + +/** + * @brief Calculate the number of bytes required to encode an MQTT + * "Remaining length" field. + * + * @param[in] length The value of the "Remaining length" to encode. + * + * @return The size of the encoding of length. This is always `1`, `2`, `3`, or `4`. + */ +static size_t _remainingLengthEncodedSize( size_t length ); + +/** + * @brief Encode the "Remaining length" field per MQTT spec. + * + * @param[out] pDestination Where to write the encoded "Remaining length". + * @param[in] length The "Remaining length" to encode. + * + * @return Pointer to the end of the encoded "Remaining length", which is 1-4 + * bytes greater than `pDestination`. + * + * @warning This function does not check the size of `pDestination`! Ensure that + * `pDestination` is large enough to hold the encoded "Remaining length" using + * the function #_remainingLengthEncodedSize to avoid buffer overflows. + */ +static uint8_t * _encodeRemainingLength( uint8_t * pDestination, + size_t length ); + +/** + * @brief Encode a C string as a UTF-8 string, per MQTT 3.1.1 spec. + * + * @param[out] pDestination Where to write the encoded string. + * @param[in] source The string to encode. + * @param[in] sourceLength The length of source. + * + * @return Pointer to the end of the encoded string, which is `sourceLength+2` + * bytes greater than `pDestination`. + * + * @warning This function does not check the size of `pDestination`! Ensure that + * `pDestination` is large enough to hold `sourceLength+2` bytes to avoid a buffer + * overflow. + */ +static uint8_t * _encodeString( uint8_t * pDestination, + const char * source, + uint16_t sourceLength ); + +/** + * @brief Calculate the size and "Remaining length" of a CONNECT packet generated + * from the given parameters. + * + * @param[in] pConnectInfo User-provided CONNECT information struct. + * @param[out] pRemainingLength Output for calculated "Remaining length" field. + * @param[out] pPacketSize Output for calculated total packet size. + * + * @return `true` if the packet is within the length allowed by MQTT 3.1.1 spec; `false` + * otherwise. If this function returns `false`, the output parameters should be ignored. + */ +static bool _connectPacketSize( const IotMqttConnectInfo_t * pConnectInfo, + size_t * pRemainingLength, + size_t * pPacketSize ); + +/** + * @brief Calculate the size and "Remaining length" of a PUBLISH packet generated + * from the given parameters. + * + * @param[in] pPublishInfo User-provided PUBLISH information struct. + * @param[out] pRemainingLength Output for calculated "Remaining length" field. + * @param[out] pPacketSize Output for calculated total packet size. + * + * @return `true` if the packet is within the length allowed by MQTT 3.1.1 spec; `false` + * otherwise. If this function returns `false`, the output parameters should be ignored. + */ +static bool _publishPacketSize( const IotMqttPublishInfo_t * pPublishInfo, + size_t * pRemainingLength, + size_t * pPacketSize ); + +/** + * @brief Calculate the size and "Remaining length" of a SUBSCRIBE or UNSUBSCRIBE + * packet generated from the given parameters. + * + * @param[in] type Either IOT_MQTT_SUBSCRIBE or IOT_MQTT_UNSUBSCRIBE. + * @param[in] pSubscriptionList User-provided array of subscriptions. + * @param[in] subscriptionCount Size of `pSubscriptionList`. + * @param[out] pRemainingLength Output for calculated "Remaining length" field. + * @param[out] pPacketSize Output for calculated total packet size. + * + * @return `true` if the packet is within the length allowed by MQTT 3.1.1 spec; `false` + * otherwise. If this function returns `false`, the output parameters should be ignored. + */ +static bool _subscriptionPacketSize( IotMqttOperationType_t type, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + size_t * pRemainingLength, + size_t * pPacketSize ); + +/** + * @brief Generate a CONNECT packet from the given parameters. + * + * @param[in] pConnectInfo User-provided CONNECT information. + * @param[in] remainingLength User provided remaining length. + * @param[in, out] pBuffer User provided buffer where the CONNECT packet is written. + * @param[in] connectPacketSize Size of the buffer pointed to by `pBuffer`. + * + */ +void _serializeConnect( const IotMqttConnectInfo_t * pConnectInfo, + size_t remainingLength, + uint8_t * pBuffer, + size_t connectPacketSize ); + +/** + * @brief Generate a PUBLISH packet from the given parameters. + * + * @param[in] pPublishInfo User-provided PUBLISH information. + * @param[in] remainingLength User provided remaining length. + * @param[out] pPacketIdentifier The packet identifier generated for this PUBLISH. + * @param[out] pPacketIdentifierHigh Where the high byte of the packet identifier + * is written. + * @param[in, out] pBuffer User provided buffer where the PUBLISH packet is written. + * @param[in] publishPacketSize Size of buffer pointed to by `pBuffer`. + * + */ +void _serializePublish( const IotMqttPublishInfo_t * pPublishInfo, + size_t remainingLength, + uint16_t * pPacketIdentifier, + uint8_t ** pPacketIdentifierHigh, + uint8_t * pBuffer, + size_t publishPacketSize ); + +/** + * @brief Generate a SUBSCRIBE packet from the given parameters. + * + * @param[in] pSubscriptionList User-provided array of subscriptions. + * @param[in] subscriptionCount Size of `pSubscriptionList`. + * @param[in] remainingLength User provided remaining length. + * @param[out] pPacketIdentifier The packet identifier generated for this SUBSCRIBE. + * @param[in, out] pBuffer User provided buffer where the SUBSCRIBE packet is written. + * @param[in] subscribePacketSize Size of the buffer pointed to by `pBuffer`. + * + */ +void _serializeSubscribe( const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + size_t remainingLength, + uint16_t * pPacketIdentifier, + uint8_t * pBuffer, + size_t subscribePacketSize ); + +/** + * @brief Generate an UNSUBSCRIBE packet from the given parameters. + * + * @param[in] pSubscriptionList User-provided array of subscriptions to remove. + * @param[in] subscriptionCount Size of `pSubscriptionList`. + * @param[in] remainingLength User provided remaining length. + * @param[out] pPacketIdentifier The packet identifier generated for this UNSUBSCRIBE. + * @param[in, out] pBuffer User provided buffer where the UNSUBSCRIBE packet is written. + * @param[in] unsubscribePacketSize size of the buffer pointed to by `pBuffer`. + * + */ +void _serializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + size_t remainingLength, + uint16_t * pPacketIdentifier, + uint8_t * pBuffer, + size_t unsubscribePacketSize ); + +/*-----------------------------------------------------------*/ + +#if LIBRARY_LOG_LEVEL > IOT_LOG_NONE + +/** + * @brief If logging is enabled, define a log configuration that only prints the log + * string. This is used when printing out details of deserialized MQTT packets. + */ + static const IotLogConfig_t _logHideAll = + { + .hideLibraryName = true, + .hideLogLevel = true, + .hideTimestring = true + }; +#endif + +/*-----------------------------------------------------------*/ + +static uint16_t _nextPacketIdentifier( void ) +{ + /* MQTT specifies 2 bytes for the packet identifier; however, operating on + * 32-bit integers is generally faster. */ + static uint32_t nextPacketIdentifier = 1; + + /* The next packet identifier will be greater by 2. This prevents packet + * identifiers from ever being 0, which is not allowed by MQTT 3.1.1. Packet + * identifiers will follow the sequence 1,3,5...65535,1,3,5... */ + return ( uint16_t ) Atomic_Add_u32( &nextPacketIdentifier, 2 ); +} + +/*-----------------------------------------------------------*/ + +static size_t _remainingLengthEncodedSize( size_t length ) +{ + size_t encodedSize = 0; + + /* length should have already been checked before calling this function. */ + IotMqtt_Assert( length <= MQTT_MAX_REMAINING_LENGTH ); + + /* Determine how many bytes are needed to encode length. + * The values below are taken from the MQTT 3.1.1 spec. */ + + /* 1 byte is needed to encode lengths between 0 and 127. */ + if( length < 128 ) + { + encodedSize = 1; + } + /* 2 bytes are needed to encode lengths between 128 and 16,383. */ + else if( length < 16384 ) + { + encodedSize = 2; + } + /* 3 bytes are needed to encode lengths between 16,384 and 2,097,151. */ + else if( length < 2097152 ) + { + encodedSize = 3; + } + /* 4 bytes are needed to encode lengths between 2,097,152 and 268,435,455. */ + else + { + encodedSize = 4; + } + + return encodedSize; +} + +/*-----------------------------------------------------------*/ + +static uint8_t * _encodeRemainingLength( uint8_t * pDestination, + size_t length ) +{ + uint8_t lengthByte = 0, * pLengthEnd = pDestination; + + /* This algorithm is copied from the MQTT v3.1.1 spec. */ + do + { + lengthByte = length % 128; + length = length / 128; + + /* Set the high bit of this byte, indicating that there's more data. */ + if( length > 0 ) + { + UINT8_SET_BIT( lengthByte, 7 ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Output a single encoded byte. */ + *pLengthEnd = lengthByte; + pLengthEnd++; + } while( length > 0 ); + + return pLengthEnd; +} + +/*-----------------------------------------------------------*/ + +static uint8_t * _encodeString( uint8_t * pDestination, + const char * source, + uint16_t sourceLength ) +{ + /* The first byte of a UTF-8 string is the high byte of the string length. */ + *pDestination = UINT16_HIGH_BYTE( sourceLength ); + pDestination++; + + /* The second byte of a UTF-8 string is the low byte of the string length. */ + *pDestination = UINT16_LOW_BYTE( sourceLength ); + pDestination++; + + /* Copy the string into pDestination. */ + ( void ) memcpy( pDestination, source, sourceLength ); + + /* Return the pointer to the end of the encoded string. */ + pDestination += sourceLength; + + return pDestination; +} + +/*-----------------------------------------------------------*/ + +static bool _connectPacketSize( const IotMqttConnectInfo_t * pConnectInfo, + size_t * pRemainingLength, + size_t * pPacketSize ) +{ + bool status = true; + size_t connectPacketSize = 0, remainingLength = 0; + + /* The CONNECT packet will always include a 10-byte variable header. */ + connectPacketSize += 10U; + + /* Add the length of the client identifier if provided. */ + connectPacketSize += pConnectInfo->clientIdentifierLength + sizeof( uint16_t ); + + /* Add the lengths of the will message and topic name if provided. */ + if( pConnectInfo->pWillInfo != NULL ) + { + connectPacketSize += pConnectInfo->pWillInfo->topicNameLength + sizeof( uint16_t ) + + pConnectInfo->pWillInfo->payloadLength + sizeof( uint16_t ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Depending on the status of metrics, add the length of the metrics username + * or the user-provided username. */ + if( pConnectInfo->awsIotMqttMode == true ) + { + #if AWS_IOT_MQTT_ENABLE_METRICS == 1 + connectPacketSize += AWS_IOT_METRICS_USERNAME_LENGTH + sizeof( uint16_t ); + #endif + } + else + { + /* Add the lengths of the username and password if provided and not + * connecting to an AWS IoT MQTT server. */ + if( pConnectInfo->pUserName != NULL ) + { + connectPacketSize += pConnectInfo->userNameLength + sizeof( uint16_t ); + } + else + { + EMPTY_ELSE_MARKER; + } + + if( pConnectInfo->pPassword != NULL ) + { + connectPacketSize += pConnectInfo->passwordLength + sizeof( uint16_t ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + + /* At this point, the "Remaining Length" field of the MQTT CONNECT packet has + * been calculated. */ + remainingLength = connectPacketSize; + + /* Calculate the full size of the MQTT CONNECT packet by adding the size of + * the "Remaining Length" field plus 1 byte for the "Packet Type" field. */ + connectPacketSize += 1 + _remainingLengthEncodedSize( connectPacketSize ); + + /* Check that the CONNECT packet is within the bounds of the MQTT spec. */ + if( connectPacketSize > MQTT_PACKET_CONNECT_MAX_SIZE ) + { + status = false; + } + else + { + *pRemainingLength = remainingLength; + *pPacketSize = connectPacketSize; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +static bool _publishPacketSize( const IotMqttPublishInfo_t * pPublishInfo, + size_t * pRemainingLength, + size_t * pPacketSize ) +{ + bool status = true; + size_t publishPacketSize = 0, payloadLimit = 0; + + /* The variable header of a PUBLISH packet always contains the topic name. */ + publishPacketSize += pPublishInfo->topicNameLength + sizeof( uint16_t ); + + /* The variable header of a QoS 1 or 2 PUBLISH packet contains a 2-byte + * packet identifier. */ + if( pPublishInfo->qos > IOT_MQTT_QOS_0 ) + { + publishPacketSize += sizeof( uint16_t ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Calculate the maximum allowed size of the payload for the given parameters. + * This calculation excludes the "Remaining length" encoding, whose size is not + * yet known. */ + payloadLimit = MQTT_MAX_REMAINING_LENGTH - publishPacketSize - 1; + + /* Ensure that the given payload fits within the calculated limit. */ + if( pPublishInfo->payloadLength > payloadLimit ) + { + status = false; + } + else + { + /* Add the length of the PUBLISH payload. At this point, the "Remaining length" + * has been calculated. */ + publishPacketSize += pPublishInfo->payloadLength; + + /* Now that the "Remaining length" is known, recalculate the payload limit + * based on the size of its encoding. */ + payloadLimit -= _remainingLengthEncodedSize( publishPacketSize ); + + /* Check that the given payload fits within the size allowed by MQTT spec. */ + if( pPublishInfo->payloadLength > payloadLimit ) + { + status = false; + } + else + { + /* Set the "Remaining length" output parameter and calculate the full + * size of the PUBLISH packet. */ + *pRemainingLength = publishPacketSize; + + publishPacketSize += 1 + _remainingLengthEncodedSize( publishPacketSize ); + *pPacketSize = publishPacketSize; + } + } + + return status; +} + +/*-----------------------------------------------------------*/ + +static bool _subscriptionPacketSize( IotMqttOperationType_t type, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + size_t * pRemainingLength, + size_t * pPacketSize ) +{ + bool status = true; + size_t i = 0, subscriptionPacketSize = 0; + + /* Only SUBSCRIBE and UNSUBSCRIBE operations should call this function. */ + IotMqtt_Assert( ( type == IOT_MQTT_SUBSCRIBE ) || ( type == IOT_MQTT_UNSUBSCRIBE ) ); + + /* The variable header of a subscription packet consists of a 2-byte packet + * identifier. */ + subscriptionPacketSize += sizeof( uint16_t ); + + /* Sum the lengths of all subscription topic filters; add 1 byte for each + * subscription's QoS if type is IOT_MQTT_SUBSCRIBE. */ + for( i = 0; i < subscriptionCount; i++ ) + { + /* Add the length of the topic filter. */ + subscriptionPacketSize += pSubscriptionList[ i ].topicFilterLength + sizeof( uint16_t ); + + /* Only SUBSCRIBE packets include the QoS. */ + if( type == IOT_MQTT_SUBSCRIBE ) + { + subscriptionPacketSize += 1; + } + else + { + EMPTY_ELSE_MARKER; + } + } + + /* At this point, the "Remaining length" has been calculated. Return error + * if the "Remaining length" exceeds what is allowed by MQTT 3.1.1. Otherwise, + * set the output parameter.*/ + if( subscriptionPacketSize > MQTT_MAX_REMAINING_LENGTH ) + { + status = false; + } + else + { + *pRemainingLength = subscriptionPacketSize; + + /* Calculate the full size of the subscription packet by adding the size of the + * "Remaining length" field plus 1 byte for the "Packet type" field. Set the + * pPacketSize output parameter. */ + subscriptionPacketSize += 1 + _remainingLengthEncodedSize( subscriptionPacketSize ); + *pPacketSize = subscriptionPacketSize; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +void _serializeConnect( const IotMqttConnectInfo_t * pConnectInfo, + size_t remainingLength, + uint8_t * pBuffer, + size_t connectPacketSize ) +{ + uint8_t connectFlags = 0; + uint8_t * pConnectPacket = pBuffer; + + /* The first byte in the CONNECT packet is the control packet type. */ + *pBuffer = MQTT_PACKET_TYPE_CONNECT; + pBuffer++; + + /* The remaining length of the CONNECT packet is encoded starting from the + * second byte. The remaining length does not include the length of the fixed + * header or the encoding of the remaining length. */ + pBuffer = _encodeRemainingLength( pBuffer, remainingLength ); + + /* The string "MQTT" is placed at the beginning of the CONNECT packet's variable + * header. This string is 4 bytes long. */ + pBuffer = _encodeString( pBuffer, "MQTT", 4 ); + + /* The MQTT protocol version is the second byte of the variable header. */ + *pBuffer = MQTT_VERSION_3_1_1; + pBuffer++; + + /* Set the CONNECT flags based on the given parameters. */ + if( pConnectInfo->cleanSession == true ) + { + UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_CLEAN ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Username and password depend on MQTT mode. */ + if( pConnectInfo->awsIotMqttMode == true ) + { + /* Set the username flag for AWS IoT metrics. The AWS IoT MQTT server + * never uses a password. */ + #if AWS_IOT_MQTT_ENABLE_METRICS == 1 + UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_USERNAME ); + #endif + } + else + { + /* Set the flags for username and password if provided. */ + if( pConnectInfo->pUserName != NULL ) + { + UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_USERNAME ); + } + else + { + EMPTY_ELSE_MARKER; + } + + if( pConnectInfo->pPassword != NULL ) + { + UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_PASSWORD ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + + /* Set will flag if an LWT is provided. */ + if( pConnectInfo->pWillInfo != NULL ) + { + UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL ); + + /* Flags only need to be changed for will QoS 1 and 2. */ + switch( pConnectInfo->pWillInfo->qos ) + { + case IOT_MQTT_QOS_1: + UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS1 ); + break; + + case IOT_MQTT_QOS_2: + UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS2 ); + break; + + default: + break; + } + + if( pConnectInfo->pWillInfo->retain == true ) + { + UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_RETAIN ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + *pBuffer = connectFlags; + pBuffer++; + + /* Write the 2 bytes of the keep alive interval into the CONNECT packet. */ + *pBuffer = UINT16_HIGH_BYTE( pConnectInfo->keepAliveSeconds ); + *( pBuffer + 1 ) = UINT16_LOW_BYTE( pConnectInfo->keepAliveSeconds ); + pBuffer += 2; + + /* Write the client identifier into the CONNECT packet. */ + pBuffer = _encodeString( pBuffer, + pConnectInfo->pClientIdentifier, + pConnectInfo->clientIdentifierLength ); + + /* Write the will topic name and message into the CONNECT packet if provided. */ + if( pConnectInfo->pWillInfo != NULL ) + { + pBuffer = _encodeString( pBuffer, + pConnectInfo->pWillInfo->pTopicName, + pConnectInfo->pWillInfo->topicNameLength ); + + pBuffer = _encodeString( pBuffer, + pConnectInfo->pWillInfo->pPayload, + ( uint16_t ) pConnectInfo->pWillInfo->payloadLength ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* If metrics are enabled, write the metrics username into the CONNECT packet. + * Otherwise, write the username and password only when not connecting to an + * AWS IoT MQTT server. */ + if( pConnectInfo->awsIotMqttMode == true ) + { + #if AWS_IOT_MQTT_ENABLE_METRICS == 1 + IotLogInfo( "Anonymous metrics (SDK language, SDK version) will be provided to AWS IoT. " + "Recompile with AWS_IOT_MQTT_ENABLE_METRICS set to 0 to disable." ); + + pBuffer = _encodeString( pBuffer, + AWS_IOT_METRICS_USERNAME, + AWS_IOT_METRICS_USERNAME_LENGTH ); + #endif + } + else + { + if( pConnectInfo->pUserName != NULL ) + { + pBuffer = _encodeString( pBuffer, + pConnectInfo->pUserName, + pConnectInfo->userNameLength ); + } + else + { + EMPTY_ELSE_MARKER; + } + + if( pConnectInfo->pPassword != NULL ) + { + pBuffer = _encodeString( pBuffer, + pConnectInfo->pPassword, + pConnectInfo->passwordLength ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + + /* Ensure that the difference between the end and beginning of the buffer + * is equal to connectPacketSize, i.e. pBuffer did not overflow. */ + IotMqtt_Assert( ( size_t ) ( pBuffer - pConnectPacket ) == connectPacketSize ); + + /* Print out the serialized CONNECT packet for debugging purposes. */ + IotLog_PrintBuffer( "MQTT CONNECT packet:", pConnectPacket, connectPacketSize ); +} + +/*-----------------------------------------------------------*/ + +void _serializePublish( const IotMqttPublishInfo_t * pPublishInfo, + size_t remainingLength, + uint16_t * pPacketIdentifier, + uint8_t ** pPacketIdentifierHigh, + uint8_t * pBuffer, + size_t publishPacketSize ) +{ + uint8_t publishFlags = 0; + uint16_t packetIdentifier = 0; + uint8_t * pPublishPacket = pBuffer; + + /* The first byte of a PUBLISH packet contains the packet type and flags. */ + publishFlags = MQTT_PACKET_TYPE_PUBLISH; + + if( pPublishInfo->qos == IOT_MQTT_QOS_1 ) + { + UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ); + } + else if( pPublishInfo->qos == IOT_MQTT_QOS_2 ) + { + UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 ); + } + else + { + EMPTY_ELSE_MARKER; + } + + if( pPublishInfo->retain == true ) + { + UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN ); + } + else + { + EMPTY_ELSE_MARKER; + } + + *pBuffer = publishFlags; + pBuffer++; + + /* The "Remaining length" is encoded from the second byte. */ + pBuffer = _encodeRemainingLength( pBuffer, remainingLength ); + + /* The topic name is placed after the "Remaining length". */ + pBuffer = _encodeString( pBuffer, + pPublishInfo->pTopicName, + pPublishInfo->topicNameLength ); + + /* A packet identifier is required for QoS 1 and 2 messages. */ + if( pPublishInfo->qos > IOT_MQTT_QOS_0 ) + { + /* Get the next packet identifier. It should always be nonzero. */ + packetIdentifier = _nextPacketIdentifier(); + IotMqtt_Assert( packetIdentifier != 0 ); + + /* Set the packet identifier output parameters. */ + *pPacketIdentifier = packetIdentifier; + + if( pPacketIdentifierHigh != NULL ) + { + *pPacketIdentifierHigh = pBuffer; + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Place the packet identifier into the PUBLISH packet. */ + *pBuffer = UINT16_HIGH_BYTE( packetIdentifier ); + *( pBuffer + 1 ) = UINT16_LOW_BYTE( packetIdentifier ); + pBuffer += 2; + } + else + { + EMPTY_ELSE_MARKER; + } + + /* The payload is placed after the packet identifier. */ + if( pPublishInfo->payloadLength > 0 ) + { + ( void ) memcpy( pBuffer, pPublishInfo->pPayload, pPublishInfo->payloadLength ); + pBuffer += pPublishInfo->payloadLength; + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Ensure that the difference between the end and beginning of the buffer + * is equal to publishPacketSize, i.e. pBuffer did not overflow. */ + IotMqtt_Assert( ( size_t ) ( pBuffer - pPublishPacket ) == publishPacketSize ); + + /* Print out the serialized PUBLISH packet for debugging purposes. */ + IotLog_PrintBuffer( "MQTT PUBLISH packet:", pPublishPacket, publishPacketSize ); +} + +/*-----------------------------------------------------------*/ + +void _serializeSubscribe( const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + size_t remainingLength, + uint16_t * pPacketIdentifier, + uint8_t * pBuffer, + size_t subscribePacketSize ) +{ + uint16_t packetIdentifier = 0; + size_t i = 0; + uint8_t * pSubscribePacket = pBuffer; + + /* The first byte in SUBSCRIBE is the packet type. */ + *pBuffer = MQTT_PACKET_TYPE_SUBSCRIBE; + pBuffer++; + + /* Encode the "Remaining length" starting from the second byte. */ + pBuffer = _encodeRemainingLength( pBuffer, remainingLength ); + + /* Get the next packet identifier. It should always be nonzero. */ + packetIdentifier = _nextPacketIdentifier(); + *pPacketIdentifier = packetIdentifier; + IotMqtt_Assert( packetIdentifier != 0 ); + + /* Place the packet identifier into the SUBSCRIBE packet. */ + *pBuffer = UINT16_HIGH_BYTE( packetIdentifier ); + *( pBuffer + 1 ) = UINT16_LOW_BYTE( packetIdentifier ); + pBuffer += 2; + + /* Serialize each subscription topic filter and QoS. */ + for( i = 0; i < subscriptionCount; i++ ) + { + pBuffer = _encodeString( pBuffer, + pSubscriptionList[ i ].pTopicFilter, + pSubscriptionList[ i ].topicFilterLength ); + + /* Place the QoS in the SUBSCRIBE packet. */ + *pBuffer = ( uint8_t ) ( pSubscriptionList[ i ].qos ); + pBuffer++; + } + + /* Ensure that the difference between the end and beginning of the buffer + * is equal to subscribePacketSize, i.e. pBuffer did not overflow. */ + IotMqtt_Assert( ( size_t ) ( pBuffer - pSubscribePacket ) == subscribePacketSize ); + + /* Print out the serialized SUBSCRIBE packet for debugging purposes. */ + IotLog_PrintBuffer( "MQTT SUBSCRIBE packet:", pSubscribePacket, subscribePacketSize ); +} + +/*-----------------------------------------------------------*/ + +void _serializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + size_t remainingLength, + uint16_t * pPacketIdentifier, + uint8_t * pBuffer, + size_t unsubscribePacketSize ) +{ + uint16_t packetIdentifier = 0; + size_t i = 0; + uint8_t * pUnsubscribePacket = pBuffer; + + /* The first byte in UNSUBSCRIBE is the packet type. */ + *pBuffer = MQTT_PACKET_TYPE_UNSUBSCRIBE; + pBuffer++; + + /* Encode the "Remaining length" starting from the second byte. */ + pBuffer = _encodeRemainingLength( pBuffer, remainingLength ); + + /* Get the next packet identifier. It should always be nonzero. */ + packetIdentifier = _nextPacketIdentifier(); + *pPacketIdentifier = packetIdentifier; + IotMqtt_Assert( packetIdentifier != 0 ); + + /* Place the packet identifier into the UNSUBSCRIBE packet. */ + *pBuffer = UINT16_HIGH_BYTE( packetIdentifier ); + *( pBuffer + 1 ) = UINT16_LOW_BYTE( packetIdentifier ); + pBuffer += 2; + + /* Serialize each subscription topic filter. */ + for( i = 0; i < subscriptionCount; i++ ) + { + pBuffer = _encodeString( pBuffer, + pSubscriptionList[ i ].pTopicFilter, + pSubscriptionList[ i ].topicFilterLength ); + } + + /* Ensure that the difference between the end and beginning of the buffer + * is equal to unsubscribePacketSize, i.e. pBuffer did not overflow. */ + IotMqtt_Assert( ( size_t ) ( pBuffer - pUnsubscribePacket ) == unsubscribePacketSize ); + + /* Print out the serialized UNSUBSCRIBE packet for debugging purposes. */ + IotLog_PrintBuffer( "MQTT UNSUBSCRIBE packet:", pUnsubscribePacket, unsubscribePacketSize ); +} + +/*-----------------------------------------------------------*/ + +uint8_t _IotMqtt_GetPacketType( void * pNetworkConnection, + const IotNetworkInterface_t * pNetworkInterface ) +{ + uint8_t packetType = 0xff; + + /* The MQTT packet type is in the first byte of the packet. */ + ( void ) _IotMqtt_GetNextByte( pNetworkConnection, + pNetworkInterface, + &packetType ); + + return packetType; +} + +/*-----------------------------------------------------------*/ + +size_t _IotMqtt_GetRemainingLength( void * pNetworkConnection, + const IotNetworkInterface_t * pNetworkInterface ) +{ + uint8_t encodedByte = 0; + size_t remainingLength = 0, multiplier = 1, bytesDecoded = 0, expectedSize = 0; + + /* This algorithm is copied from the MQTT v3.1.1 spec. */ + do + { + if( multiplier > 2097152 ) /* 128 ^ 3 */ + { + remainingLength = MQTT_REMAINING_LENGTH_INVALID; + break; + } + else + { + if( _IotMqtt_GetNextByte( pNetworkConnection, + pNetworkInterface, + &encodedByte ) == true ) + { + remainingLength += ( encodedByte & 0x7F ) * multiplier; + multiplier *= 128; + bytesDecoded++; + } + else + { + remainingLength = MQTT_REMAINING_LENGTH_INVALID; + break; + } + } + } while( ( encodedByte & 0x80 ) != 0 ); + + /* Check that the decoded remaining length conforms to the MQTT specification. */ + if( remainingLength != MQTT_REMAINING_LENGTH_INVALID ) + { + expectedSize = _remainingLengthEncodedSize( remainingLength ); + + if( bytesDecoded != expectedSize ) + { + remainingLength = MQTT_REMAINING_LENGTH_INVALID; + } + else + { + /* Valid remaining length should be at most 4 bytes. */ + IotMqtt_Assert( bytesDecoded <= 4 ); + } + } + else + { + EMPTY_ELSE_MARKER; + } + + return remainingLength; +} + +/*-----------------------------------------------------------*/ + +size_t _IotMqtt_GetRemainingLength_Generic( void * pNetworkConnection, + IotMqttGetNextByte_t getNextByte ) +{ + uint8_t encodedByte = 0; + size_t remainingLength = 0, multiplier = 1, bytesDecoded = 0, expectedSize = 0; + + /* This algorithm is copied from the MQTT v3.1.1 spec. */ + do + { + if( multiplier > 2097152 ) /* 128 ^ 3 */ + { + remainingLength = MQTT_REMAINING_LENGTH_INVALID; + break; + } + else + { + if( getNextByte( pNetworkConnection, &encodedByte ) == IOT_MQTT_SUCCESS ) + { + remainingLength += ( encodedByte & 0x7F ) * multiplier; + multiplier *= 128; + bytesDecoded++; + } + else + { + remainingLength = MQTT_REMAINING_LENGTH_INVALID; + break; + } + } + } while( ( encodedByte & 0x80 ) != 0 ); + + /* Check that the decoded remaining length conforms to the MQTT specification. */ + if( remainingLength != MQTT_REMAINING_LENGTH_INVALID ) + { + expectedSize = _remainingLengthEncodedSize( remainingLength ); + + if( bytesDecoded != expectedSize ) + { + remainingLength = MQTT_REMAINING_LENGTH_INVALID; + } + else + { + /* Valid remaining length should be at most 4 bytes. */ + IotMqtt_Assert( bytesDecoded <= 4 ); + } + } + else + { + EMPTY_ELSE_MARKER; + } + + return remainingLength; +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_SerializeConnect( const IotMqttConnectInfo_t * pConnectInfo, + uint8_t ** pConnectPacket, + size_t * pPacketSize ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + size_t remainingLength = 0, connectPacketSize = 0; + uint8_t * pBuffer = NULL; + + /* Calculate the "Remaining length" field and total packet size. If it exceeds + * what is allowed in the MQTT standard, return an error. */ + if( _connectPacketSize( pConnectInfo, &remainingLength, &connectPacketSize ) == false ) + { + IotLogError( "Connect packet length exceeds %lu, which is the maximum" + " size allowed by MQTT 3.1.1.", + MQTT_PACKET_CONNECT_MAX_SIZE ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Total size of the connect packet should be larger than the "Remaining length" + * field. */ + IotMqtt_Assert( connectPacketSize > remainingLength ); + + /* Allocate memory to hold the CONNECT packet. */ + pBuffer = IotMqtt_MallocMessage( connectPacketSize ); + + /* Check that sufficient memory was allocated. */ + if( pBuffer == NULL ) + { + IotLogError( "Failed to allocate memory for CONNECT packet." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Set the output parameters. The remainder of this function always succeeds. */ + *pConnectPacket = pBuffer; + *pPacketSize = connectPacketSize; + + _serializeConnect( pConnectInfo, remainingLength, pBuffer, connectPacketSize ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_DeserializeConnack( _mqttPacket_t * pConnack ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + const uint8_t * pRemainingData = pConnack->pRemainingData; + + /* If logging is enabled, declare the CONNACK response code strings. The + * fourth byte of CONNACK indexes into this array for the corresponding response. */ + #if LIBRARY_LOG_LEVEL > IOT_LOG_NONE + static const char * pConnackResponses[ 6 ] = + { + "Connection accepted.", /* 0 */ + "Connection refused: unacceptable protocol version.", /* 1 */ + "Connection refused: identifier rejected.", /* 2 */ + "Connection refused: server unavailable", /* 3 */ + "Connection refused: bad user name or password.", /* 4 */ + "Connection refused: not authorized." /* 5 */ + }; + #endif + + /* Check that the control packet type is 0x20. */ + if( pConnack->type != MQTT_PACKET_TYPE_CONNACK ) + { + IotLog( IOT_LOG_ERROR, + &_logHideAll, + "Bad control packet type 0x%02x.", + pConnack->type ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* According to MQTT 3.1.1, the second byte of CONNACK must specify a + * "Remaining length" of 2. */ + if( pConnack->remainingLength != MQTT_PACKET_CONNACK_REMAINING_LENGTH ) + { + IotLog( IOT_LOG_ERROR, + &_logHideAll, + "CONNACK does not have remaining length of %d.", + MQTT_PACKET_CONNACK_REMAINING_LENGTH ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check the reserved bits in CONNACK. The high 7 bits of the second byte + * in CONNACK must be 0. */ + if( ( pRemainingData[ 0 ] | 0x01 ) != 0x01 ) + { + IotLog( IOT_LOG_ERROR, + &_logHideAll, + "Reserved bits in CONNACK incorrect." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Determine if the "Session Present" bit it set. This is the lowest bit of + * the second byte in CONNACK. */ + if( ( pRemainingData[ 0 ] & MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK ) + == MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK ) + { + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "CONNACK session present bit set." ); + + /* MQTT 3.1.1 specifies that the fourth byte in CONNACK must be 0 if the + * "Session Present" bit is set. */ + if( pRemainingData[ 1 ] != 0 ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "CONNACK session present bit not set." ); + } + + /* In MQTT 3.1.1, only values 0 through 5 are valid CONNACK response codes. */ + if( pRemainingData[ 1 ] > 5 ) + { + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "CONNACK response %hhu is not valid.", + pRemainingData[ 1 ] ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Print the appropriate message for the CONNACK response code if logs are + * enabled. */ + #if LIBRARY_LOG_LEVEL > IOT_LOG_NONE + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "%s", + pConnackResponses[ pRemainingData[ 1 ] ] ); + #endif + + /* A nonzero CONNACK response code means the connection was refused. */ + if( pRemainingData[ 1 ] > 0 ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_SERVER_REFUSED ); + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_SerializePublish( const IotMqttPublishInfo_t * pPublishInfo, + uint8_t ** pPublishPacket, + size_t * pPacketSize, + uint16_t * pPacketIdentifier, + uint8_t ** pPacketIdentifierHigh ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + size_t remainingLength = 0, publishPacketSize = 0; + uint8_t * pBuffer = NULL; + + /* Calculate the "Remaining length" field and total packet size. If it exceeds + * what is allowed in the MQTT standard, return an error. */ + if( _publishPacketSize( pPublishInfo, &remainingLength, &publishPacketSize ) == false ) + { + IotLogError( "Publish packet remaining length exceeds %lu, which is the " + "maximum size allowed by MQTT 3.1.1.", + MQTT_MAX_REMAINING_LENGTH ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Total size of the publish packet should be larger than the "Remaining length" + * field. */ + IotMqtt_Assert( publishPacketSize > remainingLength ); + + /* Allocate memory to hold the PUBLISH packet. */ + pBuffer = IotMqtt_MallocMessage( publishPacketSize ); + + /* Check that sufficient memory was allocated. */ + if( pBuffer == NULL ) + { + IotLogError( "Failed to allocate memory for PUBLISH packet." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Set the output parameters. The remainder of this function always succeeds. */ + *pPublishPacket = pBuffer; + *pPacketSize = publishPacketSize; + + /* Serialize publish into buffer pointed to by pBuffer */ + _serializePublish( pPublishInfo, + remainingLength, + pPacketIdentifier, + pPacketIdentifierHigh, + pBuffer, + publishPacketSize ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +void _IotMqtt_PublishSetDup( uint8_t * pPublishPacket, + uint8_t * pPacketIdentifierHigh, + uint16_t * pNewPacketIdentifier ) +{ + uint16_t newPacketIdentifier = 0; + + /* For an AWS IoT MQTT server, change the packet identifier. */ + if( pPacketIdentifierHigh != NULL ) + { + /* Output parameter for new packet identifier must be provided. */ + IotMqtt_Assert( pNewPacketIdentifier != NULL ); + + /* Generate a new packet identifier. */ + newPacketIdentifier = _nextPacketIdentifier(); + + IotLogDebug( "Changing PUBLISH packet identifier %hu to %hu.", + UINT16_DECODE( pPacketIdentifierHigh ), + newPacketIdentifier ); + + /* Replace the packet identifier. */ + *pPacketIdentifierHigh = UINT16_HIGH_BYTE( newPacketIdentifier ); + *( pPacketIdentifierHigh + 1 ) = UINT16_LOW_BYTE( newPacketIdentifier ); + *pNewPacketIdentifier = newPacketIdentifier; + } + else + { + /* For a compliant MQTT 3.1.1 server, set the DUP flag. */ + UINT8_SET_BIT( *pPublishPacket, MQTT_PUBLISH_FLAG_DUP ); + + IotLogDebug( "PUBLISH DUP flag set." ); + } +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_DeserializePublish( _mqttPacket_t * pPublish ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + IotMqttPublishInfo_t * pOutput = &( pPublish->u.pIncomingPublish->u.publish.publishInfo ); + uint8_t publishFlags = 0; + const uint8_t * pVariableHeader = pPublish->pRemainingData, * pPacketIdentifierHigh = NULL; + + /* The flags are the lower 4 bits of the first byte in PUBLISH. */ + publishFlags = pPublish->type; + + /* Parse the Retain bit. */ + pOutput->retain = UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN ); + + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "Retain bit is %d.", pOutput->retain ); + + /* Check for QoS 2. */ + if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 ) == true ) + { + /* PUBLISH packet is invalid if both QoS 1 and QoS 2 bits are set. */ + if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) == true ) + { + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "Bad QoS: 3." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + pOutput->qos = IOT_MQTT_QOS_2; + } + /* Check for QoS 1. */ + else if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) == true ) + { + pOutput->qos = IOT_MQTT_QOS_1; + } + /* If the PUBLISH isn't QoS 1 or 2, then it's QoS 0. */ + else + { + pOutput->qos = IOT_MQTT_QOS_0; + } + + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "QoS is %d.", pOutput->qos ); + + /* Parse the DUP bit. */ + if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP ) == true ) + { + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "DUP is 1." ); + } + else + { + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "DUP is 0." ); + } + + /* Sanity checks for "Remaining length". */ + if( pOutput->qos == IOT_MQTT_QOS_0 ) + { + /* A QoS 0 PUBLISH must have a remaining length of at least 3 to accommodate + * topic name length (2 bytes) and topic name (at least 1 byte). */ + if( pPublish->remainingLength < 3 ) + { + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "QoS 0 PUBLISH cannot have a remaining length less than 3." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + /* A QoS 1 or 2 PUBLISH must have a remaining length of at least 5 to + * accommodate a packet identifier as well as the topic name length and + * topic name. */ + if( pPublish->remainingLength < 5 ) + { + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "QoS 1 or 2 PUBLISH cannot have a remaining length less than 5." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + + /* Extract the topic name starting from the first byte of the variable header. + * The topic name string starts at byte 3 in the variable header. */ + pOutput->topicNameLength = UINT16_DECODE( pVariableHeader ); + + /* Sanity checks for topic name length and "Remaining length". */ + if( pOutput->qos == IOT_MQTT_QOS_0 ) + { + /* Check that the "Remaining length" is at least as large as the variable + * header. */ + if( pPublish->remainingLength < pOutput->topicNameLength + sizeof( uint16_t ) ) + { + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "Remaining length cannot be less than variable header length." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + /* Check that the "Remaining length" is at least as large as the variable + * header. */ + if( pPublish->remainingLength < pOutput->topicNameLength + 2 * sizeof( uint16_t ) ) + { + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "Remaining length cannot be less than variable header length." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + + /* Parse the topic. */ + pOutput->pTopicName = ( const char * ) ( pVariableHeader + sizeof( uint16_t ) ); + + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "Topic name length %hu: %.*s", + pOutput->topicNameLength, + pOutput->topicNameLength, + pOutput->pTopicName ); + + /* Extract the packet identifier for QoS 1 or 2 PUBLISH packets. Packet + * identifier starts immediately after the topic name. */ + pPacketIdentifierHigh = ( const uint8_t * ) ( pOutput->pTopicName + pOutput->topicNameLength ); + + if( pOutput->qos > IOT_MQTT_QOS_0 ) + { + pPublish->packetIdentifier = UINT16_DECODE( pPacketIdentifierHigh ); + + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "Packet identifier %hu.", pPublish->packetIdentifier ); + + /* Packet identifier cannot be 0. */ + if( pPublish->packetIdentifier == 0 ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Calculate the length of the payload. QoS 1 or 2 PUBLISH packets contain + * a packet identifier, but QoS 0 PUBLISH packets do not. */ + if( pOutput->qos == IOT_MQTT_QOS_0 ) + { + pOutput->payloadLength = ( pPublish->remainingLength - pOutput->topicNameLength - sizeof( uint16_t ) ); + pOutput->pPayload = pPacketIdentifierHigh; + } + else + { + pOutput->payloadLength = ( pPublish->remainingLength - pOutput->topicNameLength - 2 * sizeof( uint16_t ) ); + pOutput->pPayload = pPacketIdentifierHigh + sizeof( uint16_t ); + } + + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "Payload length %hu.", pOutput->payloadLength ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_SerializePuback( uint16_t packetIdentifier, + uint8_t ** pPubackPacket, + size_t * pPacketSize ) +{ + IotMqttError_t status = IOT_MQTT_SUCCESS; + + /* Allocate memory for PUBACK. */ + uint8_t * pBuffer = IotMqtt_MallocMessage( MQTT_PACKET_PUBACK_SIZE ); + + if( pBuffer == NULL ) + { + IotLogError( "Failed to allocate memory for PUBACK packet" ); + + status = IOT_MQTT_NO_MEMORY; + } + else + { + /* Set the output parameters. The remainder of this function always succeeds. */ + *pPubackPacket = pBuffer; + *pPacketSize = MQTT_PACKET_PUBACK_SIZE; + + /* Set the 4 bytes in PUBACK. */ + pBuffer[ 0 ] = MQTT_PACKET_TYPE_PUBACK; + pBuffer[ 1 ] = MQTT_PACKET_PUBACK_REMAINING_LENGTH; + pBuffer[ 2 ] = UINT16_HIGH_BYTE( packetIdentifier ); + pBuffer[ 3 ] = UINT16_LOW_BYTE( packetIdentifier ); + + /* Print out the serialized PUBACK packet for debugging purposes. */ + IotLog_PrintBuffer( "MQTT PUBACK packet:", *pPubackPacket, MQTT_PACKET_PUBACK_SIZE ); + } + + return status; +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_DeserializePuback( _mqttPacket_t * pPuback ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + + /* Check the "Remaining length" of the received PUBACK. */ + if( pPuback->remainingLength != MQTT_PACKET_PUBACK_REMAINING_LENGTH ) + { + IotLog( IOT_LOG_ERROR, + &_logHideAll, + "PUBACK does not have remaining length of %d.", + MQTT_PACKET_PUBACK_REMAINING_LENGTH ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Extract the packet identifier (third and fourth bytes) from PUBACK. */ + pPuback->packetIdentifier = UINT16_DECODE( pPuback->pRemainingData ); + + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "Packet identifier %hu.", pPuback->packetIdentifier ); + + /* Packet identifier cannot be 0. */ + if( pPuback->packetIdentifier == 0 ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check that the control packet type is 0x40 (this must be done after the + * packet identifier is parsed). */ + if( pPuback->type != MQTT_PACKET_TYPE_PUBACK ) + { + IotLog( IOT_LOG_ERROR, + &_logHideAll, + "Bad control packet type 0x%02x.", + pPuback->type ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_SerializeSubscribe( const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint8_t ** pSubscribePacket, + size_t * pPacketSize, + uint16_t * pPacketIdentifier ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + size_t subscribePacketSize = 0, remainingLength = 0; + uint8_t * pBuffer = NULL; + + /* Calculate the "Remaining length" field and total packet size. If it exceeds + * what is allowed in the MQTT standard, return an error. */ + if( _subscriptionPacketSize( IOT_MQTT_SUBSCRIBE, + pSubscriptionList, + subscriptionCount, + &remainingLength, + &subscribePacketSize ) == false ) + { + IotLogError( "Subscribe packet remaining length exceeds %lu, which is the " + "maximum size allowed by MQTT 3.1.1.", + MQTT_MAX_REMAINING_LENGTH ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Total size of the subscribe packet should be larger than the "Remaining length" + * field. */ + IotMqtt_Assert( subscribePacketSize > remainingLength ); + + /* Allocate memory to hold the SUBSCRIBE packet. */ + pBuffer = IotMqtt_MallocMessage( subscribePacketSize ); + + /* Check that sufficient memory was allocated. */ + if( pBuffer == NULL ) + { + IotLogError( "Failed to allocate memory for SUBSCRIBE packet." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Set the output parameters. The remainder of this function always succeeds. */ + *pSubscribePacket = pBuffer; + *pPacketSize = subscribePacketSize; + + /* Serialize subscribe into buffer pointed to by pBuffer */ + _serializeSubscribe( pSubscriptionList, + subscriptionCount, + remainingLength, + pPacketIdentifier, + pBuffer, + subscribePacketSize ); + + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_DeserializeSuback( _mqttPacket_t * pSuback ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + size_t i = 0, remainingLength = pSuback->remainingLength; + uint8_t subscriptionStatus = 0; + const uint8_t * pVariableHeader = pSuback->pRemainingData; + + /* A SUBACK must have a remaining length of at least 3 to accommodate the + * packet identifier and at least one return code. */ + if( remainingLength < 3 ) + { + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "SUBACK cannot have a remaining length less than 3." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Extract the packet identifier (first 2 bytes of variable header) from SUBACK. */ + pSuback->packetIdentifier = UINT16_DECODE( pVariableHeader ); + + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "Packet identifier %hu.", pSuback->packetIdentifier ); + + /* Check that the control packet type is 0x90 (this must be done after the + * packet identifier is parsed). */ + if( pSuback->type != MQTT_PACKET_TYPE_SUBACK ) + { + IotLog( IOT_LOG_ERROR, + &_logHideAll, + "Bad control packet type 0x%02x.", + pSuback->type ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Iterate through each status byte in the SUBACK packet. */ + for( i = 0; i < remainingLength - sizeof( uint16_t ); i++ ) + { + /* Read a single status byte in SUBACK. */ + subscriptionStatus = *( pVariableHeader + sizeof( uint16_t ) + i ); + + /* MQTT 3.1.1 defines the following values as status codes. */ + switch( subscriptionStatus ) + { + case 0x00: + case 0x01: + case 0x02: + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "Topic filter %lu accepted, max QoS %hhu.", + ( unsigned long ) i, subscriptionStatus ); + break; + + case 0x80: + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "Topic filter %lu refused.", ( unsigned long ) i ); + + /* Remove a rejected subscription from the subscription manager. */ + _IotMqtt_RemoveSubscriptionByPacket( pSuback->u.pMqttConnection, + pSuback->packetIdentifier, + ( int32_t ) i ); + + status = IOT_MQTT_SERVER_REFUSED; + + break; + + default: + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "Bad SUBSCRIBE status %hhu.", subscriptionStatus ); + + status = IOT_MQTT_BAD_RESPONSE; + + break; + } + + /* Stop parsing the subscription statuses if a bad response was received. */ + if( status == IOT_MQTT_BAD_RESPONSE ) + { + break; + } + else + { + EMPTY_ELSE_MARKER; + } + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_SerializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint8_t ** pUnsubscribePacket, + size_t * pPacketSize, + uint16_t * pPacketIdentifier ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + size_t unsubscribePacketSize = 0, remainingLength = 0; + uint8_t * pBuffer = NULL; + + /* Calculate the "Remaining length" field and total packet size. If it exceeds + * what is allowed in the MQTT standard, return an error. */ + if( _subscriptionPacketSize( IOT_MQTT_UNSUBSCRIBE, + pSubscriptionList, + subscriptionCount, + &remainingLength, + &unsubscribePacketSize ) == false ) + { + IotLogError( "Unsubscribe packet remaining length exceeds %lu, which is the " + "maximum size allowed by MQTT 3.1.1.", + MQTT_MAX_REMAINING_LENGTH ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Total size of the unsubscribe packet should be larger than the "Remaining length" + * field. */ + IotMqtt_Assert( unsubscribePacketSize > remainingLength ); + + /* Allocate memory to hold the UNSUBSCRIBE packet. */ + pBuffer = IotMqtt_MallocMessage( unsubscribePacketSize ); + + /* Check that sufficient memory was allocated. */ + if( pBuffer == NULL ) + { + IotLogError( "Failed to allocate memory for UNSUBSCRIBE packet." ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_NO_MEMORY ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Set the output parameters. The remainder of this function always succeeds. */ + *pUnsubscribePacket = pBuffer; + *pPacketSize = unsubscribePacketSize; + + /* Serialize unsubscribe into buffer pointed to by pBuffer */ + _serializeUnsubscribe( pSubscriptionList, + subscriptionCount, + remainingLength, + pPacketIdentifier, + pBuffer, + unsubscribePacketSize ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_DeserializeUnsuback( _mqttPacket_t * pUnsuback ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + + /* Check the "Remaining length" (second byte) of the received UNSUBACK. */ + if( pUnsuback->remainingLength != MQTT_PACKET_UNSUBACK_REMAINING_LENGTH ) + { + IotLog( IOT_LOG_ERROR, + &_logHideAll, + "UNSUBACK does not have remaining length of %d.", + MQTT_PACKET_UNSUBACK_REMAINING_LENGTH ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Extract the packet identifier (third and fourth bytes) from UNSUBACK. */ + pUnsuback->packetIdentifier = UINT16_DECODE( pUnsuback->pRemainingData ); + + /* Packet identifier cannot be 0. */ + if( pUnsuback->packetIdentifier == 0 ) + { + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + IotLog( IOT_LOG_DEBUG, + &_logHideAll, + "Packet identifier %hu.", pUnsuback->packetIdentifier ); + + /* Check that the control packet type is 0xb0 (this must be done after the + * packet identifier is parsed). */ + if( pUnsuback->type != MQTT_PACKET_TYPE_UNSUBACK ) + { + IotLog( IOT_LOG_ERROR, + &_logHideAll, + "Bad control packet type 0x%02x.", + pUnsuback->type ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_SerializePingreq( uint8_t ** pPingreqPacket, + size_t * pPacketSize ) +{ + /* PINGREQ packets are always the same. */ + static const uint8_t pPingreq[ MQTT_PACKET_PINGREQ_SIZE ] = + { + MQTT_PACKET_TYPE_PINGREQ, + 0x00 + }; + + /* Set the output parameters. */ + *pPingreqPacket = ( uint8_t * ) pPingreq; + *pPacketSize = MQTT_PACKET_PINGREQ_SIZE; + + /* Print out the PINGREQ packet for debugging purposes. */ + IotLog_PrintBuffer( "MQTT PINGREQ packet:", pPingreq, MQTT_PACKET_PINGREQ_SIZE ); + + return IOT_MQTT_SUCCESS; +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_DeserializePingresp( _mqttPacket_t * pPingresp ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + + /* Check that the control packet type is 0xd0. */ + if( pPingresp->type != MQTT_PACKET_TYPE_PINGRESP ) + { + IotLog( IOT_LOG_ERROR, + &_logHideAll, + "Bad control packet type 0x%02x.", + pPingresp->type ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check the "Remaining length" (second byte) of the received PINGRESP. */ + if( pPingresp->remainingLength != MQTT_PACKET_PINGRESP_REMAINING_LENGTH ) + { + IotLog( IOT_LOG_ERROR, + &_logHideAll, + "PINGRESP does not have remaining length of %d.", + MQTT_PACKET_PINGRESP_REMAINING_LENGTH ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_RESPONSE ); + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_SerializeDisconnect( uint8_t ** pDisconnectPacket, + size_t * pPacketSize ) +{ + /* DISCONNECT packets are always the same. */ + static const uint8_t pDisconnect[ MQTT_PACKET_DISCONNECT_SIZE ] = + { + MQTT_PACKET_TYPE_DISCONNECT, + 0x00 + }; + + /* Set the output parameters. */ + *pDisconnectPacket = ( uint8_t * ) pDisconnect; + *pPacketSize = MQTT_PACKET_DISCONNECT_SIZE; + + /* Print out the DISCONNECT packet for debugging purposes. */ + IotLog_PrintBuffer( "MQTT DISCONNECT packet:", pDisconnect, MQTT_PACKET_DISCONNECT_SIZE ); + + return IOT_MQTT_SUCCESS; +} + +/*-----------------------------------------------------------*/ + +void _IotMqtt_FreePacket( uint8_t * pPacket ) +{ + uint8_t packetType = *pPacket; + + /* Don't call free on DISCONNECT and PINGREQ; those are allocated from static + * memory. */ + if( packetType != MQTT_PACKET_TYPE_DISCONNECT ) + { + if( packetType != MQTT_PACKET_TYPE_PINGREQ ) + { + IotMqtt_FreeMessage( pPacket ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } +} + +/*-----------------------------------------------------------*/ + +/* Public interface functions for serialization */ + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_GetConnectPacketSize( const IotMqttConnectInfo_t * pConnectInfo, + size_t * pRemainingLength, + size_t * pPacketSize ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + + if( ( pConnectInfo == NULL ) || ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) ) + { + IotLogError( "IotMqtt_GetConnectPacketSize() called with required parameter(s) set to NULL." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( ( pConnectInfo->clientIdentifierLength == 0 ) || ( pConnectInfo->pClientIdentifier == NULL ) ) + { + IotLogError( "IotMqtt_GetConnectPacketSize() client identifier must be set." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + /* Calculate the "Remaining length" field and total packet size. If it exceeds + * what is allowed in the MQTT standard, return an error. */ + if( _connectPacketSize( pConnectInfo, pRemainingLength, pPacketSize ) == false ) + { + IotLogError( "Connect packet length exceeds %lu, which is the maximum" + " size allowed by MQTT 3.1.1.", + MQTT_PACKET_CONNECT_MAX_SIZE ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Total size of the subscribe packet should be larger than the "Remaining length" + * field. */ + if( ( *pPacketSize ) < ( *pRemainingLength ) ) + { + IotLogError( "Connection packet remaining length (%lu) exceeds packet size (%lu)", + ( *pRemainingLength ), ( *pPacketSize ) ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_SerializeConnect( const IotMqttConnectInfo_t * pConnectInfo, + size_t remainingLength, + uint8_t * pBuffer, + size_t bufferSize ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + + if( ( pBuffer == NULL ) || ( pConnectInfo == NULL ) ) + { + IotLogError( "IotMqtt_SerializeConnect() called with required parameter(s) set to NULL." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( ( pConnectInfo->clientIdentifierLength == 0 ) || ( pConnectInfo->pClientIdentifier == NULL ) ) + { + IotLogError( "IotMqtt_SerializeConnect() client identifier must be set." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( remainingLength > bufferSize ) + { + IotLogError( " Serialize Connect packet remaining length (%lu) exceeds buffer size (%lu)", + remainingLength, bufferSize ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + _serializeConnect( pConnectInfo, + remainingLength, + pBuffer, + bufferSize ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_GetSubscriptionPacketSize( IotMqttOperationType_t type, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + size_t * pRemainingLength, + size_t * pPacketSize ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + + if( ( pSubscriptionList == NULL ) || ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) ) + { + IotLogError( "IotMqtt_GetSubscriptionPacketSize() called with required parameter(s) set to NULL." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( ( type != IOT_MQTT_SUBSCRIBE ) && ( type != IOT_MQTT_UNSUBSCRIBE ) ) + { + IotLogError( "IotMqtt_GetSubscriptionPacketSize() called with unknown type." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( subscriptionCount == 0 ) + { + IotLogError( "IotMqtt_GetSubscriptionPacketSize() called with zero subscription count." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( _subscriptionPacketSize( type, + pSubscriptionList, + subscriptionCount, + pRemainingLength, + pPacketSize ) == false ) + { + IotLogError( "Unsubscribe packet remaining length exceeds %lu, which is the " + "maximum size allowed by MQTT 3.1.1.", + MQTT_MAX_REMAINING_LENGTH ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Total size of the subscribe packet should be larger than the "Remaining length" + * field. */ + if( ( *pPacketSize ) < ( *pRemainingLength ) ) + { + IotLogError( "Subscription packet remaining length (%lu) exceeds packet size (%lu)", + ( *pRemainingLength ), ( *pPacketSize ) ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_SerializeSubscribe( const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + size_t remainingLength, + uint16_t * pPacketIdentifier, + uint8_t * pBuffer, + size_t bufferSize ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + + if( ( pBuffer == NULL ) || ( pSubscriptionList == NULL ) || ( pPacketIdentifier == NULL ) ) + { + IotLogError( "IotMqtt_SerializeSubscribe() called with required parameter(s) set to NULL." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( subscriptionCount == 0 ) + { + IotLogError( "IotMqtt_SerializeSubscribe() called with zero subscription count." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( remainingLength > bufferSize ) + { + IotLogError( " Subscribe packet remaining length (%lu) exceeds buffer size (%lu).", + remainingLength, bufferSize ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + _serializeSubscribe( pSubscriptionList, + subscriptionCount, + remainingLength, + pPacketIdentifier, + pBuffer, + bufferSize ); + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_GetPublishPacketSize( IotMqttPublishInfo_t * pPublishInfo, + size_t * pRemainingLength, + size_t * pPacketSize ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + + if( ( pPublishInfo == NULL ) || ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) ) + { + IotLogError( "IotMqtt_GetPublishPacketSize() called with required parameter(s) set to NULL." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( ( pPublishInfo->pTopicName == NULL ) || ( pPublishInfo->topicNameLength == 0 ) ) + { + IotLogError( "IotMqtt_GetPublishPacketSize() called with no topic." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + /* Calculate the "Remaining length" field and total packet size. If it exceeds + * what is allowed in the MQTT standard, return an error. */ + if( _publishPacketSize( pPublishInfo, pRemainingLength, pPacketSize ) == false ) + { + IotLogError( "Publish packet remaining length exceeds %lu, which is the " + "maximum size allowed by MQTT 3.1.1.", + MQTT_MAX_REMAINING_LENGTH ); + + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Total size of the publish packet should be larger than the "Remaining length" + * field. */ + if( ( *pPacketSize ) < ( *pRemainingLength ) ) + { + IotLogError( "Publish packet remaining length (%lu) exceeds packet size (%lu).", + ( *pRemainingLength ), ( *pPacketSize ) ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_SerializePublish( IotMqttPublishInfo_t * pPublishInfo, + size_t remainingLength, + uint16_t * pPacketIdentifier, + uint8_t ** pPacketIdentifierHigh, + uint8_t * pBuffer, + size_t bufferSize ) + +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + + if( ( pBuffer == NULL ) || ( pPublishInfo == NULL ) || ( pPacketIdentifier == NULL ) ) + { + IotLogError( "IotMqtt_SerializePublish() called with required parameter(s) set to NULL." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( ( pPublishInfo->pTopicName == NULL ) || ( pPublishInfo->topicNameLength == 0 ) ) + { + IotLogError( "IotMqtt_SerializePublish() called with no topic." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( remainingLength > bufferSize ) + { + IotLogError( "Publish packet remaining length (%lu) exceeds buffer size (%lu).", + remainingLength, bufferSize ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + _serializePublish( pPublishInfo, + remainingLength, + pPacketIdentifier, + pPacketIdentifierHigh, + pBuffer, + bufferSize ); + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_SerializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + size_t remainingLength, + uint16_t * pPacketIdentifier, + uint8_t * pBuffer, + size_t bufferSize ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + + if( ( pBuffer == NULL ) || ( pPacketIdentifier == NULL ) || ( pSubscriptionList == NULL ) ) + { + IotLogError( "IotMqtt_SerializeUnsubscribe() called with required parameter(s) set to NULL." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( subscriptionCount == 0 ) + { + IotLogError( "IotMqtt_SerializeUnsubscribe() called with zero subscription count." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( remainingLength > bufferSize ) + { + IotLogError( "Unsubscribe packet remaining length (%lu) exceeds buffer size (%lu).", + remainingLength, bufferSize ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + _serializeUnsubscribe( pSubscriptionList, + subscriptionCount, + remainingLength, + pPacketIdentifier, + pBuffer, + bufferSize ); + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_SerializeDisconnect( uint8_t * pBuffer, + size_t bufferSize ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + uint8_t * pDisconnectPacket = NULL; + size_t remainingLength = 0; + + if( pBuffer == NULL ) + { + IotLogError( "IotMqtt_SerializeDisconnect() called with NULL buffer pointer." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( bufferSize < MQTT_PACKET_DISCONNECT_SIZE ) + { + IotLogError( "Disconnect packet length (%lu) exceeds buffer size (%lu).", + MQTT_PACKET_DISCONNECT_SIZE, bufferSize ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + /* Call internal function with local variables, as disconnect uses + * static memory, there is no need to pass the buffer + * Note: _IotMqtt_SerializeDisconnect always succeeds */ + _IotMqtt_SerializeDisconnect( &pDisconnectPacket, &remainingLength ); + + memcpy( pBuffer, pDisconnectPacket, MQTT_PACKET_DISCONNECT_SIZE ); + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_SerializePingreq( uint8_t * pBuffer, + size_t bufferSize ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + uint8_t * pPingreqPacket = NULL; + size_t packetSize = 0; + + if( pBuffer == NULL ) + { + IotLogError( "IotMqtt_SerializePingreq() called with NULL buffer pointer." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( bufferSize < MQTT_PACKET_PINGREQ_SIZE ) + { + IotLogError( "Pingreq length (%lu) exceeds buffer size (%lu).", + MQTT_PACKET_DISCONNECT_SIZE, bufferSize ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + /* Call internal function with local variables, as ping request uses + * static memory, there is no need to pass the buffer + * Note: _IotMqtt_SerializePingReq always succeeds */ + _IotMqtt_SerializePingreq( &pPingreqPacket, &packetSize ); + memcpy( pBuffer, pPingreqPacket, MQTT_PACKET_PINGREQ_SIZE ); + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_DeserializePublish( IotMqttPacketInfo_t * pMqttPacket ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + /* Internal MQTT packet structure */ + _mqttPacket_t mqttPacket; + /* Internal MQTT operation structure needed for deserializing publish */ + _mqttOperation_t mqttOperation; + + if( pMqttPacket == NULL ) + { + IotLogError( "IotMqtt_DeserializePublish()called with NULL pMqttPacket pointer." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( ( pMqttPacket->type & 0xf0 ) != MQTT_PACKET_TYPE_PUBLISH ) + { + IotLogError( "IotMqtt_DeserializePublish() called with incorrect packet type:(%lu).", pMqttPacket->type ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + /* Set internal mqtt packet parameters. */ + memset( ( void * ) &mqttPacket, 0x00, sizeof( _mqttPacket_t ) ); + mqttPacket.pRemainingData = pMqttPacket->pRemainingData; + mqttPacket.remainingLength = pMqttPacket->remainingLength; + mqttPacket.type = pMqttPacket->type; + + /* Set Publish specific parameters */ + memset( ( void * ) &mqttOperation, 0x00, sizeof( _mqttOperation_t ) ); + mqttOperation.incomingPublish = true; + mqttPacket.u.pIncomingPublish = &mqttOperation; + status = _IotMqtt_DeserializePublish( &mqttPacket ); + + if( status == IOT_MQTT_SUCCESS ) + { + pMqttPacket->pubInfo = mqttOperation.u.publish.publishInfo; + pMqttPacket->packetIdentifier = mqttPacket.packetIdentifier; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t IotMqtt_DeserializeResponse( IotMqttPacketInfo_t * pMqttPacket ) +{ + IOT_FUNCTION_ENTRY( IotMqttError_t, IOT_MQTT_SUCCESS ); + /* Internal MQTT packet structure */ + _mqttPacket_t mqttPacket; + + if( ( pMqttPacket == NULL ) || ( pMqttPacket->pRemainingData == NULL ) ) + { + IotLogError( "IotMqtt_DeserializeResponse() called with NULL pMqttPacket pointer or NULL pRemainingLength." ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + /* Set internal mqtt packet parameters. */ + memset( ( void * ) &mqttPacket, 0x00, sizeof( _mqttPacket_t ) ); + + mqttPacket.pRemainingData = pMqttPacket->pRemainingData; + mqttPacket.remainingLength = pMqttPacket->remainingLength; + mqttPacket.type = pMqttPacket->type; + + /* Call internal deserialize */ + switch( pMqttPacket->type & 0xf0 ) + { + case MQTT_PACKET_TYPE_CONNACK: + status = _IotMqtt_DeserializeConnack( &mqttPacket ); + break; + + case MQTT_PACKET_TYPE_PUBACK: + status = _IotMqtt_DeserializePuback( &mqttPacket ); + break; + + case MQTT_PACKET_TYPE_SUBACK: + status = _IotMqtt_DeserializeSuback( &mqttPacket ); + break; + + case MQTT_PACKET_TYPE_UNSUBACK: + status = _IotMqtt_DeserializeUnsuback( &mqttPacket ); + break; + + case MQTT_PACKET_TYPE_PINGRESP: + status = _IotMqtt_DeserializePingresp( &mqttPacket ); + break; + + /* Any other packet type is invalid. */ + default: + IotLogError( "IotMqtt_DeserializeResponse() called with unknown packet type:(%lu).", pMqttPacket->type ); + IOT_SET_AND_GOTO_CLEANUP( IOT_MQTT_BAD_PARAMETER ); + } + + if( status != IOT_MQTT_SUCCESS ) + { + IOT_SET_AND_GOTO_CLEANUP( status ); + } + else + { + /* Set packetIdentifier only if success is returned. */ + pMqttPacket->packetIdentifier = mqttPacket.packetIdentifier; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_subscription.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_subscription.c new file mode 100644 index 000000000..00b241a7b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_subscription.c @@ -0,0 +1,645 @@ +/* + * IoT MQTT V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_mqtt_subscription.c + * @brief Implements functions that manage subscriptions for an MQTT connection. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Standard includes. */ +#include +#include + +/* Error handling include. */ +#include "iot_error.h" + +/* MQTT internal include. */ +#include "private/iot_mqtt_internal.h" + +/* Platform layer includes. */ +#include "platform/iot_threads.h" + +/*-----------------------------------------------------------*/ + +/** + * @brief First parameter to #_topicMatch. + */ +typedef struct _topicMatchParams +{ + const char * pTopicName; /**< @brief The topic name to parse. */ + uint16_t topicNameLength; /**< @brief Length of #_topicMatchParams_t.pTopicName. */ + bool exactMatchOnly; /**< @brief Whether to allow wildcards or require exact matches. */ +} _topicMatchParams_t; + +/** + * @brief First parameter to #_packetMatch. + */ +typedef struct _packetMatchParams +{ + uint16_t packetIdentifier; /**< Packet identifier to match. */ + int32_t order; /**< Order to match. Set to #MQTT_REMOVE_ALL_SUBSCRIPTIONS to ignore. */ +} _packetMatchParams_t; + +/*-----------------------------------------------------------*/ + +/** + * @brief Matches a topic name (from a publish) with a topic filter (from a + * subscription). + * + * @param[in] pSubscriptionLink Pointer to the link member of an #_mqttSubscription_t. + * @param[in] pMatch Pointer to a #_topicMatchParams_t. + * + * @return `true` if the arguments match the subscription topic filter; `false` + * otherwise. + */ +static bool _topicMatch( const IotLink_t * pSubscriptionLink, + void * pMatch ); + +/** + * @brief Matches a packet identifier and order. + * + * @param[in] pSubscriptionLink Pointer to the link member of an #_mqttSubscription_t. + * @param[in] pMatch Pointer to a #_packetMatchParams_t. + * + * @return `true` if the arguments match the subscription's packet info; `false` + * otherwise. + */ +static bool _packetMatch( const IotLink_t * pSubscriptionLink, + void * pMatch ); + +/*-----------------------------------------------------------*/ + +static bool _topicMatch( const IotLink_t * pSubscriptionLink, + void * pMatch ) +{ + IOT_FUNCTION_ENTRY( bool, false ); + uint16_t nameIndex = 0, filterIndex = 0; + + /* Because this function is called from a container function, the given link + * must never be NULL. */ + IotMqtt_Assert( pSubscriptionLink != NULL ); + + _mqttSubscription_t * pSubscription = IotLink_Container( _mqttSubscription_t, + pSubscriptionLink, + link ); + _topicMatchParams_t * pParam = ( _topicMatchParams_t * ) pMatch; + + /* Extract the relevant strings and lengths from parameters. */ + const char * pTopicName = pParam->pTopicName; + const char * pTopicFilter = pSubscription->pTopicFilter; + const uint16_t topicNameLength = pParam->topicNameLength; + const uint16_t topicFilterLength = pSubscription->topicFilterLength; + + /* Check for an exact match. */ + if( topicNameLength == topicFilterLength ) + { + status = ( strncmp( pTopicName, pTopicFilter, topicNameLength ) == 0 ); + + IOT_GOTO_CLEANUP(); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* If the topic lengths are different but an exact match is required, return + * false. */ + if( pParam->exactMatchOnly == true ) + { + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + while( ( nameIndex < topicNameLength ) && ( filterIndex < topicFilterLength ) ) + { + /* Check if the character in the topic name matches the corresponding + * character in the topic filter string. */ + if( pTopicName[ nameIndex ] == pTopicFilter[ filterIndex ] ) + { + /* Handle special corner cases as documented by the MQTT protocol spec. */ + + /* Filter "sport/#" also matches "sport" since # includes the parent level. */ + if( nameIndex == topicNameLength - 1 ) + { + if( filterIndex == topicFilterLength - 3 ) + { + if( pTopicFilter[ filterIndex + 1 ] == '/' ) + { + if( pTopicFilter[ filterIndex + 2 ] == '#' ) + { + IOT_SET_AND_GOTO_CLEANUP( true ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Filter "sport/+" also matches the "sport/" but not "sport". */ + if( nameIndex == topicNameLength - 1 ) + { + if( filterIndex == topicFilterLength - 2 ) + { + if( pTopicFilter[ filterIndex + 1 ] == '+' ) + { + IOT_SET_AND_GOTO_CLEANUP( true ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + /* Check for wildcards. */ + if( pTopicFilter[ filterIndex ] == '+' ) + { + /* Move topic name index to the end of the current level. + * This is identified by '/'. */ + while( nameIndex < topicNameLength && pTopicName[ nameIndex ] != '/' ) + { + nameIndex++; + } + + /* Increment filter index to skip '/'. */ + filterIndex++; + continue; + } + else if( pTopicFilter[ filterIndex ] == '#' ) + { + /* Subsequent characters don't need to be checked if the for the + * multi-level wildcard. */ + IOT_SET_AND_GOTO_CLEANUP( true ); + } + else + { + /* Any character mismatch other than '+' or '#' means the topic + * name does not match the topic filter. */ + IOT_SET_AND_GOTO_CLEANUP( false ); + } + } + + /* Increment indexes. */ + nameIndex++; + filterIndex++; + } + + /* If the end of both strings has been reached, they match. */ + if( ( nameIndex == topicNameLength ) && ( filterIndex == topicFilterLength ) ) + { + IOT_SET_AND_GOTO_CLEANUP( true ); + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +static bool _packetMatch( const IotLink_t * pSubscriptionLink, + void * pMatch ) +{ + bool match = false; + + /* Because this function is called from a container function, the given link + * must never be NULL. */ + IotMqtt_Assert( pSubscriptionLink != NULL ); + + _mqttSubscription_t * pSubscription = IotLink_Container( _mqttSubscription_t, + pSubscriptionLink, + link ); + _packetMatchParams_t * pParam = ( _packetMatchParams_t * ) pMatch; + + /* Compare packet identifiers. */ + if( pParam->packetIdentifier == pSubscription->packetInfo.identifier ) + { + /* Compare orders if order is not MQTT_REMOVE_ALL_SUBSCRIPTIONS. */ + if( pParam->order == MQTT_REMOVE_ALL_SUBSCRIPTIONS ) + { + match = true; + } + else + { + match = ( ( size_t ) pParam->order ) == pSubscription->packetInfo.order; + } + } + + /* If this subscription should be removed, check the reference count. */ + if( match == true ) + { + /* Reference count must not be negative. */ + IotMqtt_Assert( pSubscription->references >= 0 ); + + /* If the reference count is positive, this subscription cannot be + * removed yet because there are subscription callbacks using it. */ + if( pSubscription->references > 0 ) + { + match = false; + + /* Set the unsubscribed flag. The last active subscription callback + * will remove and clean up this subscription. */ + pSubscription->unsubscribed = true; + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + return match; +} + +/*-----------------------------------------------------------*/ + +IotMqttError_t _IotMqtt_AddSubscriptions( _mqttConnection_t * pMqttConnection, + uint16_t subscribePacketIdentifier, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount ) +{ + IotMqttError_t status = IOT_MQTT_SUCCESS; + size_t i = 0; + _mqttSubscription_t * pNewSubscription = NULL; + IotLink_t * pSubscriptionLink = NULL; + _topicMatchParams_t topicMatchParams = { .exactMatchOnly = true }; + + IotMutex_Lock( &( pMqttConnection->subscriptionMutex ) ); + + for( i = 0; i < subscriptionCount; i++ ) + { + /* Check if this topic filter is already registered. */ + topicMatchParams.pTopicName = pSubscriptionList[ i ].pTopicFilter; + topicMatchParams.topicNameLength = pSubscriptionList[ i ].topicFilterLength; + pSubscriptionLink = IotListDouble_FindFirstMatch( &( pMqttConnection->subscriptionList ), + NULL, + _topicMatch, + &topicMatchParams ); + + if( pSubscriptionLink != NULL ) + { + pNewSubscription = IotLink_Container( _mqttSubscription_t, pSubscriptionLink, link ); + + /* The lengths of exactly matching topic filters must match. */ + IotMqtt_Assert( pNewSubscription->topicFilterLength == pSubscriptionList[ i ].topicFilterLength ); + + /* Replace the callback and packet info with the new parameters. */ + pNewSubscription->callback = pSubscriptionList[ i ].callback; + pNewSubscription->packetInfo.identifier = subscribePacketIdentifier; + pNewSubscription->packetInfo.order = i; + } + else + { + /* Allocate memory for a new subscription. */ + pNewSubscription = IotMqtt_MallocSubscription( sizeof( _mqttSubscription_t ) + + pSubscriptionList[ i ].topicFilterLength ); + + if( pNewSubscription == NULL ) + { + status = IOT_MQTT_NO_MEMORY; + break; + } + else + { + /* Clear the new subscription. */ + ( void ) memset( pNewSubscription, + 0x00, + sizeof( _mqttSubscription_t ) + pSubscriptionList[ i ].topicFilterLength ); + + /* Set the members of the new subscription and add it to the list. */ + pNewSubscription->packetInfo.identifier = subscribePacketIdentifier; + pNewSubscription->packetInfo.order = i; + pNewSubscription->callback = pSubscriptionList[ i ].callback; + pNewSubscription->topicFilterLength = pSubscriptionList[ i ].topicFilterLength; + ( void ) memcpy( pNewSubscription->pTopicFilter, + pSubscriptionList[ i ].pTopicFilter, + ( size_t ) ( pSubscriptionList[ i ].topicFilterLength ) ); + + IotListDouble_InsertHead( &( pMqttConnection->subscriptionList ), + &( pNewSubscription->link ) ); + } + } + } + + IotMutex_Unlock( &( pMqttConnection->subscriptionMutex ) ); + + /* If memory allocation failed, remove all previously added subscriptions. */ + if( status != IOT_MQTT_SUCCESS ) + { + _IotMqtt_RemoveSubscriptionByTopicFilter( pMqttConnection, + pSubscriptionList, + i ); + } + else + { + EMPTY_ELSE_MARKER; + } + + return status; +} + +/*-----------------------------------------------------------*/ + +void _IotMqtt_InvokeSubscriptionCallback( _mqttConnection_t * pMqttConnection, + IotMqttCallbackParam_t * pCallbackParam ) +{ + _mqttSubscription_t * pSubscription = NULL; + IotLink_t * pCurrentLink = NULL, * pNextLink = NULL; + void * pCallbackContext = NULL; + + void ( * callbackFunction )( void *, + IotMqttCallbackParam_t * ) = NULL; + _topicMatchParams_t topicMatchParams = { 0 }; + + /* Set the members of the search parameter. */ + topicMatchParams.pTopicName = pCallbackParam->u.message.info.pTopicName; + topicMatchParams.topicNameLength = pCallbackParam->u.message.info.topicNameLength; + topicMatchParams.exactMatchOnly = false; + + /* Prevent any other thread from modifying the subscription list while this + * function is searching. */ + IotMutex_Lock( &( pMqttConnection->subscriptionMutex ) ); + + /* Search the subscription list for all matching subscriptions starting at + * the list head. */ + while( true ) + { + pCurrentLink = IotListDouble_FindFirstMatch( &( pMqttConnection->subscriptionList ), + pCurrentLink, + _topicMatch, + &topicMatchParams ); + + /* No subscription found. Exit loop. */ + if( pCurrentLink == NULL ) + { + break; + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Subscription found. Calculate pointer to subscription object. */ + pSubscription = IotLink_Container( _mqttSubscription_t, pCurrentLink, link ); + + /* Subscription validation should not have allowed a NULL callback function. */ + IotMqtt_Assert( pSubscription->callback.function != NULL ); + + /* Increment the subscription's reference count. */ + ( pSubscription->references )++; + + /* Copy the necessary members of the subscription before releasing the + * subscription list mutex. */ + pCallbackContext = pSubscription->callback.pCallbackContext; + callbackFunction = pSubscription->callback.function; + + /* Unlock the subscription list mutex. */ + IotMutex_Unlock( &( pMqttConnection->subscriptionMutex ) ); + + /* Set the members of the callback parameter. */ + pCallbackParam->mqttConnection = pMqttConnection; + pCallbackParam->u.message.pTopicFilter = pSubscription->pTopicFilter; + pCallbackParam->u.message.topicFilterLength = pSubscription->topicFilterLength; + + /* Invoke the subscription callback. */ + callbackFunction( pCallbackContext, pCallbackParam ); + + /* Lock the subscription list mutex to decrement the reference count. */ + IotMutex_Lock( &( pMqttConnection->subscriptionMutex ) ); + + /* Decrement the reference count. It must still be positive. */ + ( pSubscription->references )--; + IotMqtt_Assert( pSubscription->references >= 0 ); + + /* Save the pointer to the next link in case this subscription is freed. */ + pNextLink = pCurrentLink->pNext; + + /* Remove this subscription if it has no references and the unsubscribed + * flag is set. */ + if( pSubscription->unsubscribed == true ) + { + /* An unsubscribed subscription should have been removed from the list. */ + IotMqtt_Assert( IotLink_IsLinked( &( pSubscription->link ) ) == false ); + + /* Free subscriptions with no references. */ + if( pSubscription->references == 0 ) + { + IotMqtt_FreeSubscription( pSubscription ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Move current link pointer. */ + pCurrentLink = pNextLink; + } + + IotMutex_Unlock( &( pMqttConnection->subscriptionMutex ) ); + + _IotMqtt_DecrementConnectionReferences( pMqttConnection ); +} + +/*-----------------------------------------------------------*/ + +void _IotMqtt_RemoveSubscriptionByPacket( _mqttConnection_t * pMqttConnection, + uint16_t packetIdentifier, + int32_t order ) +{ + _packetMatchParams_t packetMatchParams = { 0 }; + + /* Set the members of the search parameter. */ + packetMatchParams.packetIdentifier = packetIdentifier; + packetMatchParams.order = order; + + IotMutex_Lock( &( pMqttConnection->subscriptionMutex ) ); + IotListDouble_RemoveAllMatches( &( pMqttConnection->subscriptionList ), + _packetMatch, + ( void * ) ( &packetMatchParams ), + IotMqtt_FreeSubscription, + offsetof( _mqttSubscription_t, link ) ); + IotMutex_Unlock( &( pMqttConnection->subscriptionMutex ) ); +} + +/*-----------------------------------------------------------*/ + +void _IotMqtt_RemoveSubscriptionByTopicFilter( _mqttConnection_t * pMqttConnection, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount ) +{ + size_t i = 0; + _mqttSubscription_t * pSubscription = NULL; + IotLink_t * pSubscriptionLink = NULL; + _topicMatchParams_t topicMatchParams = { 0 }; + + /* Prevent any other thread from modifying the subscription list while this + * function is running. */ + IotMutex_Lock( &( pMqttConnection->subscriptionMutex ) ); + + /* Find and remove each topic filter from the list. */ + for( i = 0; i < subscriptionCount; i++ ) + { + topicMatchParams.pTopicName = pSubscriptionList[ i ].pTopicFilter; + topicMatchParams.topicNameLength = pSubscriptionList[ i ].topicFilterLength; + topicMatchParams.exactMatchOnly = true; + + pSubscriptionLink = IotListDouble_FindFirstMatch( &( pMqttConnection->subscriptionList ), + NULL, + _topicMatch, + &topicMatchParams ); + + if( pSubscriptionLink != NULL ) + { + pSubscription = IotLink_Container( _mqttSubscription_t, pSubscriptionLink, link ); + + /* Reference count must not be negative. */ + IotMqtt_Assert( pSubscription->references >= 0 ); + + /* Remove subscription from list. */ + IotListDouble_Remove( pSubscriptionLink ); + + /* Check the reference count. This subscription cannot be removed if + * there are subscription callbacks using it. */ + if( pSubscription->references > 0 ) + { + /* Set the unsubscribed flag. The last active subscription callback + * will remove and clean up this subscription. */ + pSubscription->unsubscribed = true; + } + else + { + /* Free a subscription with no references. */ + IotMqtt_FreeSubscription( pSubscription ); + } + } + else + { + EMPTY_ELSE_MARKER; + } + } + + IotMutex_Unlock( &( pMqttConnection->subscriptionMutex ) ); +} + +/*-----------------------------------------------------------*/ + +bool IotMqtt_IsSubscribed( IotMqttConnection_t mqttConnection, + const char * pTopicFilter, + uint16_t topicFilterLength, + IotMqttSubscription_t * const pCurrentSubscription ) +{ + bool status = false; + _mqttSubscription_t * pSubscription = NULL; + IotLink_t * pSubscriptionLink = NULL; + _topicMatchParams_t topicMatchParams = { 0 }; + + /* Set the members of the search parameter. */ + topicMatchParams.pTopicName = pTopicFilter; + topicMatchParams.topicNameLength = topicFilterLength; + topicMatchParams.exactMatchOnly = true; + + /* Prevent any other thread from modifying the subscription list while this + * function is running. */ + IotMutex_Lock( &( mqttConnection->subscriptionMutex ) ); + + /* Search for a matching subscription. */ + pSubscriptionLink = IotListDouble_FindFirstMatch( &( mqttConnection->subscriptionList ), + NULL, + _topicMatch, + &topicMatchParams ); + + /* Check if a matching subscription was found. */ + if( pSubscriptionLink != NULL ) + { + pSubscription = IotLink_Container( _mqttSubscription_t, pSubscriptionLink, link ); + + /* Copy the matching subscription to the output parameter. */ + if( pCurrentSubscription != NULL ) + { + pCurrentSubscription->pTopicFilter = pTopicFilter; + pCurrentSubscription->topicFilterLength = topicFilterLength; + pCurrentSubscription->qos = IOT_MQTT_QOS_0; + pCurrentSubscription->callback = pSubscription->callback; + } + else + { + EMPTY_ELSE_MARKER; + } + + status = true; + } + else + { + EMPTY_ELSE_MARKER; + } + + IotMutex_Unlock( &( mqttConnection->subscriptionMutex ) ); + + return status; +} + +/*-----------------------------------------------------------*/ + +/* Provide access to internal functions and variables if testing. */ +#if IOT_BUILD_TESTS == 1 + #include "iot_test_access_mqtt_subscription.c" +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_validate.c b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_validate.c new file mode 100644 index 000000000..eb9a846be --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/iot_mqtt_validate.c @@ -0,0 +1,637 @@ +/* + * IoT MQTT V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_mqtt_validate.c + * @brief Implements functions that validate the structs of the MQTT library. + */ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Error handling include. */ +#include "iot_error.h" + +/* MQTT internal include. */ +#include "private/iot_mqtt_internal.h" + +/** + * @brief Check that an #IotMqttPublishInfo_t is valid. + * + * @param[in] awsIotMqttMode Specifies if this PUBLISH packet is being sent to + * an AWS IoT MQTT server. + * @param[in] maximumPayloadLength Maximum payload length. + * @param[in] pPublishTypeDescription String describing the publish type. + * @param[in] pPublishInfo The #IotMqttPublishInfo_t to validate. + * + * @return `true` if `pPublishInfo` is valid; `false` otherwise. + */ +static bool _validatePublish( bool awsIotMqttMode, + size_t maximumPayloadLength, + const char * pPublishTypeDescription, + const IotMqttPublishInfo_t * pPublishInfo ); + +/*-----------------------------------------------------------*/ + +bool _IotMqtt_ValidateConnect( const IotMqttConnectInfo_t * pConnectInfo ) +{ + IOT_FUNCTION_ENTRY( bool, true ); + uint16_t maxClientIdLength = MQTT_SERVER_MAX_CLIENTID_LENGTH; + bool enforceMaxClientIdLength = false; + + /* Check for NULL. */ + if( pConnectInfo == NULL ) + { + IotLogError( "MQTT connection information cannot be NULL." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check that a client identifier was set. */ + if( pConnectInfo->pClientIdentifier == NULL ) + { + IotLogError( "Client identifier must be set." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check for a zero-length client identifier. Zero-length client identifiers + * are not allowed with clean sessions. */ + if( pConnectInfo->clientIdentifierLength == 0 ) + { + IotLogWarn( "A zero-length client identifier was provided." ); + + if( pConnectInfo->cleanSession == true ) + { + IotLogError( "A zero-length client identifier cannot be used with a clean session." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check that the number of persistent session subscriptions is valid. */ + if( pConnectInfo->pPreviousSubscriptions != NULL ) + { + if( _IotMqtt_ValidateSubscriptionList( IOT_MQTT_SUBSCRIBE, + pConnectInfo->awsIotMqttMode, + pConnectInfo->pPreviousSubscriptions, + pConnectInfo->previousSubscriptionCount ) == false ) + { + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* If will info is provided, check that it is valid. */ + if( pConnectInfo->pWillInfo != NULL ) + { + if( _IotMqtt_ValidateLwtPublish( pConnectInfo->awsIotMqttMode, + pConnectInfo->pWillInfo ) == false ) + { + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* The AWS IoT MQTT service enforces a client ID length limit. */ + if( pConnectInfo->awsIotMqttMode == true ) + { + maxClientIdLength = AWS_IOT_MQTT_SERVER_MAX_CLIENTID_LENGTH; + enforceMaxClientIdLength = true; + } + + if( pConnectInfo->clientIdentifierLength > maxClientIdLength ) + { + if( enforceMaxClientIdLength == false ) + { + IotLogWarn( "A client identifier length of %hu is longer than %hu, " + "which is " + "the longest client identifier a server must accept.", + pConnectInfo->clientIdentifierLength, + maxClientIdLength ); + } + else + { + IotLogError( "A client identifier length of %hu exceeds the " + "maximum supported length of %hu.", + pConnectInfo->clientIdentifierLength, + maxClientIdLength ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ +static bool _validatePublish( bool awsIotMqttMode, + size_t maximumPayloadLength, + const char * pPublishTypeDescription, + const IotMqttPublishInfo_t * pPublishInfo ) +{ + IOT_FUNCTION_ENTRY( bool, true ); + + /* Check for NULL. */ + if( pPublishInfo == NULL ) + { + IotLogError( "Publish information cannot be NULL." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check topic name for NULL or zero-length. */ + if( pPublishInfo->pTopicName == NULL ) + { + IotLogError( "Publish topic name must be set." ); + } + else + { + EMPTY_ELSE_MARKER; + } + + if( pPublishInfo->topicNameLength == 0 ) + { + IotLogError( "Publish topic name length cannot be 0." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + if( pPublishInfo->payloadLength != 0 ) + { + if( pPublishInfo->payloadLength > maximumPayloadLength ) + { + IotLogError( "%s payload size of %zu exceeds maximum length of %zu.", + pPublishTypeDescription, + pPublishInfo->payloadLength, + maximumPayloadLength ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + if( pPublishInfo->pPayload == NULL ) + { + IotLogError( "Nonzero payload length cannot have a NULL payload." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check for a valid QoS. */ + if( pPublishInfo->qos != IOT_MQTT_QOS_0 ) + { + if( pPublishInfo->qos != IOT_MQTT_QOS_1 ) + { + IotLogError( "Publish QoS must be either 0 or 1." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check the retry parameters. */ + if( pPublishInfo->retryLimit > 0 ) + { + if( pPublishInfo->retryMs == 0 ) + { + IotLogError( "Publish retry time must be positive." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check for compatibility with AWS IoT MQTT server. */ + if( awsIotMqttMode == true ) + { + /* Check for retained message. */ + if( pPublishInfo->retain == true ) + { + IotLogError( "AWS IoT does not support retained publish messages." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check topic name length. */ + if( pPublishInfo->topicNameLength > AWS_IOT_MQTT_SERVER_MAX_TOPIC_LENGTH ) + { + IotLogError( "AWS IoT does not support topic names longer than %d bytes.", + AWS_IOT_MQTT_SERVER_MAX_TOPIC_LENGTH ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +bool _IotMqtt_ValidatePublish( bool awsIotMqttMode, + const IotMqttPublishInfo_t * pPublishInfo ) +{ + size_t maximumPayloadLength = MQTT_SERVER_MAX_PUBLISH_PAYLOAD_LENGTH; + + if( awsIotMqttMode == true ) + { + maximumPayloadLength = AWS_IOT_MQTT_SERVER_MAX_PUBLISH_PAYLOAD_LENGTH; + } + else + { + EMPTY_ELSE_MARKER; + } + + return _validatePublish( awsIotMqttMode, + maximumPayloadLength, + "Publish", + pPublishInfo ); +} + +/*-----------------------------------------------------------*/ + +bool _IotMqtt_ValidateLwtPublish( bool awsIotMqttMode, + const IotMqttPublishInfo_t * pLwtPublishInfo ) +{ + return _validatePublish( awsIotMqttMode, + MQTT_SERVER_MAX_LWT_PAYLOAD_LENGTH, + "LWT", + pLwtPublishInfo ); +} + +/*-----------------------------------------------------------*/ + +bool _IotMqtt_ValidateOperation( IotMqttOperation_t operation ) +{ + IOT_FUNCTION_ENTRY( bool, true ); + + /* Check for NULL. */ + if( operation == NULL ) + { + IotLogError( "Operation reference cannot be NULL." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check that reference is waitable. */ + if( ( operation->u.operation.flags & IOT_MQTT_FLAG_WAITABLE ) != IOT_MQTT_FLAG_WAITABLE ) + { + IotLogError( "Operation is not waitable." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ + +bool _IotMqtt_ValidateSubscriptionList( IotMqttOperationType_t operation, + bool awsIotMqttMode, + const IotMqttSubscription_t * pListStart, + size_t listSize ) +{ + IOT_FUNCTION_ENTRY( bool, true ); + size_t i = 0; + uint16_t j = 0; + const IotMqttSubscription_t * pListElement = NULL; + + /* Operation must be either subscribe or unsubscribe. */ + IotMqtt_Assert( ( operation == IOT_MQTT_SUBSCRIBE ) || + ( operation == IOT_MQTT_UNSUBSCRIBE ) ); + + /* Check for empty list. */ + if( pListStart == NULL ) + { + IotLogError( "Subscription list pointer cannot be NULL." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + if( listSize == 0 ) + { + IotLogError( "Empty subscription list." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* AWS IoT supports at most 8 topic filters in a single SUBSCRIBE packet. */ + if( awsIotMqttMode == true ) + { + if( listSize > AWS_IOT_MQTT_SERVER_MAX_TOPIC_FILTERS_PER_SUBSCRIBE ) + { + IotLogError( "AWS IoT does not support more than %d topic filters per " + "subscription request.", + AWS_IOT_MQTT_SERVER_MAX_TOPIC_FILTERS_PER_SUBSCRIBE ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + for( i = 0; i < listSize; i++ ) + { + pListElement = &( pListStart[ i ] ); + + /* Check for a valid QoS and callback function when subscribing. */ + if( operation == IOT_MQTT_SUBSCRIBE ) + { + if( pListElement->qos != IOT_MQTT_QOS_0 ) + { + if( pListElement->qos != IOT_MQTT_QOS_1 ) + { + IotLogError( "Subscription QoS must be either 0 or 1." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + if( pListElement->callback.function == NULL ) + { + IotLogError( "Callback function must be set." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check subscription topic filter. */ + if( pListElement->pTopicFilter == NULL ) + { + IotLogError( "Subscription topic filter cannot be NULL." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + if( pListElement->topicFilterLength == 0 ) + { + IotLogError( "Subscription topic filter length cannot be 0." ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check for compatibility with AWS IoT MQTT server. */ + if( awsIotMqttMode == true ) + { + /* Check topic filter length. */ + if( pListElement->topicFilterLength > AWS_IOT_MQTT_SERVER_MAX_TOPIC_LENGTH ) + { + IotLogError( "AWS IoT does not support topic filters longer than %d bytes.", + AWS_IOT_MQTT_SERVER_MAX_TOPIC_LENGTH ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Check that the wildcards '+' and '#' are being used correctly. */ + for( j = 0; j < pListElement->topicFilterLength; j++ ) + { + switch( pListElement->pTopicFilter[ j ] ) + { + /* Check that the single level wildcard '+' is used correctly. */ + case '+': + + /* Unless '+' is the first character in the filter, it must be preceded by '/'. */ + if( j > 0 ) + { + if( pListElement->pTopicFilter[ j - 1 ] != '/' ) + { + IotLogError( "Invalid topic filter %.*s -- '+' must be preceded by '/'.", + pListElement->topicFilterLength, + pListElement->pTopicFilter ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Unless '+' is the last character in the filter, it must be succeeded by '/'. */ + if( j < pListElement->topicFilterLength - 1 ) + { + if( pListElement->pTopicFilter[ j + 1 ] != '/' ) + { + IotLogError( "Invalid topic filter %.*s -- '+' must be succeeded by '/'.", + pListElement->topicFilterLength, + pListElement->pTopicFilter ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + break; + + /* Check that the multi-level wildcard '#' is used correctly. */ + case '#': + + /* '#' must be the last character in the filter. */ + if( j != pListElement->topicFilterLength - 1 ) + { + IotLogError( "Invalid topic filter %.*s -- '#' must be the last character.", + pListElement->topicFilterLength, + pListElement->pTopicFilter ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + + /* Unless '#' is standalone, it must be preceded by '/'. */ + if( pListElement->topicFilterLength > 1 ) + { + if( pListElement->pTopicFilter[ j - 1 ] != '/' ) + { + IotLogError( "Invalid topic filter %.*s -- '#' must be preceded by '/'.", + pListElement->topicFilterLength, + pListElement->pTopicFilter ); + + IOT_SET_AND_GOTO_CLEANUP( false ); + } + else + { + EMPTY_ELSE_MARKER; + } + } + else + { + EMPTY_ELSE_MARKER; + } + + break; + + default: + break; + } + } + } + + IOT_FUNCTION_EXIT_NO_CLEANUP(); +} + +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/private/iot_mqtt_internal.h b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/private/iot_mqtt_internal.h new file mode 100644 index 000000000..4c1099129 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/c_sdk/standard/mqtt/src/private/iot_mqtt_internal.h @@ -0,0 +1,1038 @@ +/* + * IoT MQTT V2.1.0 + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + */ + +/** + * @file iot_mqtt_internal.h + * @brief Internal header of MQTT library. This header should not be included in + * typical application code. + */ + +#ifndef IOT_MQTT_INTERNAL_H_ +#define IOT_MQTT_INTERNAL_H_ + +/* The config header is always included first. */ +#include "iot_config.h" + +/* Linear containers (lists and queues) include. */ +#include "iot_linear_containers.h" + +/* MQTT include. */ +#include "iot_mqtt.h" + +/* Task pool include. */ +#include "iot_taskpool_freertos.h" + +/** + * @def IotMqtt_Assert( expression ) + * @brief Assertion macro for the MQTT library. + * + * Set @ref IOT_MQTT_ENABLE_ASSERTS to `1` to enable assertions in the MQTT + * library. + * + * @param[in] expression Expression to be evaluated. + */ +#if IOT_MQTT_ENABLE_ASSERTS == 1 + #ifndef IotMqtt_Assert + #ifdef Iot_DefaultAssert + #define IotMqtt_Assert( expression ) Iot_DefaultAssert( expression ) + #else + #error "Asserts are enabled for MQTT, but IotMqtt_Assert is not defined" + #endif + #endif +#else + #define IotMqtt_Assert( expression ) +#endif + +/* Configure logs for MQTT functions. */ +#ifdef IOT_LOG_LEVEL_MQTT + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_MQTT +#else + #ifdef IOT_LOG_LEVEL_GLOBAL + #define LIBRARY_LOG_LEVEL IOT_LOG_LEVEL_GLOBAL + #else + #define LIBRARY_LOG_LEVEL IOT_LOG_NONE + #endif +#endif + +#define LIBRARY_LOG_NAME ( "MQTT" ) +#include "iot_logging_setup.h" + +/* + * Provide default values for undefined memory allocation functions based on + * the usage of dynamic memory allocation. + */ +#if IOT_STATIC_MEMORY_ONLY == 1 + #include "iot_static_memory.h" + +/** + * @brief Allocate an #_mqttConnection_t. This function should have the same + * signature as [malloc] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html). + */ + void * IotMqtt_MallocConnection( size_t size ); + +/** + * @brief Free an #_mqttConnection_t. This function should have the same + * signature as [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ + void IotMqtt_FreeConnection( void * ptr ); + +/** + * @brief Allocate memory for an MQTT packet. This function should have the + * same signature as [malloc] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html). + */ + #define IotMqtt_MallocMessage Iot_MallocMessageBuffer + +/** + * @brief Free an MQTT packet. This function should have the same signature + * as [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ + #define IotMqtt_FreeMessage Iot_FreeMessageBuffer + +/** + * @brief Allocate an #_mqttOperation_t. This function should have the same + * signature as [malloc] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html). + */ + void * IotMqtt_MallocOperation( size_t size ); + +/** + * @brief Free an #_mqttOperation_t. This function should have the same + * signature as [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ + void IotMqtt_FreeOperation( void * ptr ); + +/** + * @brief Allocate an #_mqttSubscription_t. This function should have the + * same signature as [malloc] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html). + */ + void * IotMqtt_MallocSubscription( size_t size ); + +/** + * @brief Free an #_mqttSubscription_t. This function should have the same + * signature as [free] + * (http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html). + */ + void IotMqtt_FreeSubscription( void * ptr ); +#else /* if IOT_STATIC_MEMORY_ONLY == 1 */ + #ifndef IotMqtt_MallocConnection + #ifdef Iot_DefaultMalloc + #define IotMqtt_MallocConnection Iot_DefaultMalloc + #else + #error "No malloc function defined for IotMqtt_MallocConnection" + #endif + #endif + + #ifndef IotMqtt_FreeConnection + #ifdef Iot_DefaultFree + #define IotMqtt_FreeConnection Iot_DefaultFree + #else + #error "No free function defined for IotMqtt_FreeConnection" + #endif + #endif + + #ifndef IotMqtt_MallocMessage + #ifdef Iot_DefaultMalloc + #define IotMqtt_MallocMessage Iot_DefaultMalloc + #else + #error "No malloc function defined for IotMqtt_MallocMessage" + #endif + #endif + + #ifndef IotMqtt_FreeMessage + #ifdef Iot_DefaultFree + #define IotMqtt_FreeMessage Iot_DefaultFree + #else + #error "No free function defined for IotMqtt_FreeMessage" + #endif + #endif + + #ifndef IotMqtt_MallocOperation + #ifdef Iot_DefaultMalloc + #define IotMqtt_MallocOperation Iot_DefaultMalloc + #else + #error "No malloc function defined for IotMqtt_MallocOperation" + #endif + #endif + + #ifndef IotMqtt_FreeOperation + #ifdef Iot_DefaultFree + #define IotMqtt_FreeOperation Iot_DefaultFree + #else + #error "No free function defined for IotMqtt_FreeOperation" + #endif + #endif + + #ifndef IotMqtt_MallocSubscription + #ifdef Iot_DefaultMalloc + #define IotMqtt_MallocSubscription Iot_DefaultMalloc + #else + #error "No malloc function defined for IotMqtt_MallocSubscription" + #endif + #endif + + #ifndef IotMqtt_FreeSubscription + #ifdef Iot_DefaultFree + #define IotMqtt_FreeSubscription Iot_DefaultFree + #else + #error "No free function defined for IotMqtt_FreeSubscription" + #endif + #endif +#endif /* if IOT_STATIC_MEMORY_ONLY == 1 */ + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * Provide default values for undefined configuration constants. + */ +#ifndef AWS_IOT_MQTT_ENABLE_METRICS + #define AWS_IOT_MQTT_ENABLE_METRICS ( 1 ) +#endif +#ifndef IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES + #define IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES ( 0 ) +#endif +#ifndef IOT_MQTT_RESPONSE_WAIT_MS + #define IOT_MQTT_RESPONSE_WAIT_MS ( 1000 ) +#endif +#ifndef IOT_MQTT_RETRY_MS_CEILING + #define IOT_MQTT_RETRY_MS_CEILING ( 60000 ) +#endif +/** @endcond */ + +/** + * @brief Marks the empty statement of an `else` branch. + * + * Does nothing, but allows test coverage to detect branches not taken. By default, + * this is defined to nothing. When running code coverage testing, this is defined + * to an assembly NOP. + */ +#ifndef EMPTY_ELSE_MARKER + #define EMPTY_ELSE_MARKER +#endif + +#define MQTT_SERVER_MAX_CLIENTID_LENGTH ( ( uint16_t ) 23 ) /**< @brief Optional maximum length of client identifier specified by MQTT 3.1.1. */ +#define MQTT_SERVER_MAX_PUBLISH_PAYLOAD_LENGTH ( ( size_t ) ( 268435456 ) ) /**< @brief Maximum publish payload length supported by MQTT 3.1.1. */ +#define MQTT_SERVER_MAX_LWT_PAYLOAD_LENGTH ( ( size_t ) UINT16_MAX ) /**< @brief Maximum LWT payload length supported by MQTT 3.1.1. */ + +/* + * Constants related to limits defined in AWS Service Limits. + * + * For details, see + * https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html + * + * Used to validate parameters if when connecting to an AWS IoT MQTT server. + */ +#define AWS_IOT_MQTT_SERVER_MAX_CLIENTID_LENGTH ( ( uint16_t ) 128 ) /**< @brief Maximum length of client identifier accepted by AWS IoT. */ +#define AWS_IOT_MQTT_SERVER_MAX_TOPIC_LENGTH ( ( uint16_t ) 256 ) /**< @brief Maximum length of topic names or filters accepted by AWS IoT. */ +#define AWS_IOT_MQTT_SERVER_MAX_TOPIC_FILTERS_PER_SUBSCRIBE ( ( size_t ) 8 ) /**< @brief Maximum number of topic filters in a single SUBSCRIBE packet. */ +#define AWS_IOT_MQTT_SERVER_MAX_PUBLISH_PAYLOAD_LENGTH ( ( size_t ) ( 131072 ) ) /**< @brief Maximum publish payload length accepted by AWS IoT. */ + +/* + * MQTT control packet type and flags. Always the first byte of an MQTT + * packet. + * + * For details, see + * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/csprd02/mqtt-v3.1.1-csprd02.html#_Toc385349757 + */ +#define MQTT_PACKET_TYPE_CONNECT ( ( uint8_t ) 0x10U ) /**< @brief CONNECT (client-to-server). */ +#define MQTT_PACKET_TYPE_CONNACK ( ( uint8_t ) 0x20U ) /**< @brief CONNACK (server-to-client). */ +#define MQTT_PACKET_TYPE_PUBLISH ( ( uint8_t ) 0x30U ) /**< @brief PUBLISH (bi-directional). */ +#define MQTT_PACKET_TYPE_PUBACK ( ( uint8_t ) 0x40U ) /**< @brief PUBACK (server-to-client). */ +#define MQTT_PACKET_TYPE_SUBSCRIBE ( ( uint8_t ) 0x82U ) /**< @brief SUBSCRIBE (client-to-server). */ +#define MQTT_PACKET_TYPE_SUBACK ( ( uint8_t ) 0x90U ) /**< @brief SUBACK (server-to-client). */ +#define MQTT_PACKET_TYPE_UNSUBSCRIBE ( ( uint8_t ) 0xa2U ) /**< @brief UNSUBSCRIBE (client-to-server). */ +#define MQTT_PACKET_TYPE_UNSUBACK ( ( uint8_t ) 0xb0U ) /**< @brief UNSUBACK (server-to-client). */ +#define MQTT_PACKET_TYPE_PINGREQ ( ( uint8_t ) 0xc0U ) /**< @brief PINGREQ (client-to-server). */ +#define MQTT_PACKET_TYPE_PINGRESP ( ( uint8_t ) 0xd0U ) /**< @brief PINGRESP (server-to-client). */ +#define MQTT_PACKET_TYPE_DISCONNECT ( ( uint8_t ) 0xe0U ) /**< @brief DISCONNECT (client-to-server). */ + +/** + * @brief A value that represents an invalid remaining length. + * + * This value is greater than what is allowed by the MQTT specification. + */ +#define MQTT_REMAINING_LENGTH_INVALID ( ( size_t ) 268435456 ) + +/** + * @brief When this flag is passed, MQTT functions will execute jobs on the calling + * thread, bypassing the task pool. + * + * This flag is used along with @ref mqtt_constants_flags, but is intended for internal + * use only. Nevertheless, its value must be bitwise exclusive of all conflicting + * @ref mqtt_constants_flags. + */ +#define MQTT_INTERNAL_FLAG_BLOCK_ON_SEND ( 0x80000000 ) + +/** + * @brief When calling #_IotMqtt_RemoveSubscriptionByPacket, use this value + * for `order` to delete all subscriptions for the packet. + * + * This flag is used along with @ref mqtt_constants_flags, but is intended for internal + * use only. + * + * @ref mqtt_constants_flags. + */ +#define MQTT_REMOVE_ALL_SUBSCRIPTIONS ( -1 ) + +/*---------------------- MQTT internal data structures ----------------------*/ + +/** + * @cond DOXYGEN_IGNORE + * Doxygen should ignore this section. + * + * Forward declaration of MQTT connection type. + */ +struct _mqttConnection; +/** @endcond */ + +/** + * @brief Internal structure representing a single MQTT operation, such as + * CONNECT, SUBSCRIBE, PUBLISH, etc. + * + * Queues of these structures keeps track of all in-progress MQTT operations. + */ +typedef struct _mqttOperation +{ + /* Pointers to neighboring queue elements. */ + IotLink_t link; /**< @brief List link member. */ + + bool incomingPublish; /**< @brief Set to true if this operation is an incoming PUBLISH. */ + struct _mqttConnection * pMqttConnection; /**< @brief MQTT connection associated with this operation. */ + + IotTaskPoolJobStorage_t jobStorage; /**< @brief Task pool job storage associated with this operation. */ + IotTaskPoolJob_t job; /**< @brief Task pool job associated with this operation. */ + + union + { + /* If incomingPublish is false, this struct is valid. */ + struct + { + /* Basic operation information. */ + int32_t jobReference; /**< @brief Tracks if a job is using this operation. Must always be 0, 1, or 2. */ + IotMqttOperationType_t type; /**< @brief What operation this structure represents. */ + uint32_t flags; /**< @brief Flags passed to the function that created this operation. */ + uint16_t packetIdentifier; /**< @brief The packet identifier used with this operation. */ + + /* Serialized packet and size. */ + uint8_t * pMqttPacket; /**< @brief The MQTT packet to send over the network. */ + uint8_t * pPacketIdentifierHigh; /**< @brief The location of the high byte of the packet identifier in the MQTT packet. */ + size_t packetSize; /**< @brief Size of `pMqttPacket`. */ + + /* How to notify of an operation's completion. */ + union + { + IotSemaphore_t waitSemaphore; /**< @brief Semaphore to be used with @ref mqtt_function_wait. */ + IotMqttCallbackInfo_t callback; /**< @brief User-provided callback function and parameter. */ + } notify; /**< @brief How to notify of this operation's completion. */ + IotMqttError_t status; /**< @brief Result of this operation. This is reported once a response is received. */ + + union + { + struct + { + uint32_t count; /**< @brief Current number of retries. */ + uint32_t limit; /**< @brief Maximum number of retries allowed. */ + uint32_t nextPeriodMs; /**< @brief Next retry period. */ + } retry; /**< @brief Additional information for PUBLISH retry. */ + + struct + { + uint32_t failure; /**< @brief Flag tracking keep-alive status. */ + uint32_t keepAliveMs; /**< @brief Keep-alive interval in milliseconds. Its max value (per spec) is 65,535,000. */ + uint32_t nextPeriodMs; /**< @brief Relative delay for next keep-alive job. */ + } ping; /**< @brief Additional information for keep-alive pings. */ + } periodic; /**< @brief Additional information for periodic operations. */ + } operation; + + /* If incomingPublish is true, this struct is valid. */ + struct + { + IotMqttPublishInfo_t publishInfo; /**< @brief Deserialized PUBLISH. */ + const void * pReceivedData; /**< @brief Any buffer associated with this PUBLISH that should be freed. */ + } publish; + } u; /**< @brief Valid member depends on _mqttOperation_t.incomingPublish. */ +} _mqttOperation_t; + +/** + * @brief Represents an MQTT connection. + */ +typedef struct _mqttConnection +{ + bool awsIotMqttMode; /**< @brief Specifies if this connection is to an AWS IoT MQTT server. */ + bool ownNetworkConnection; /**< @brief Whether this MQTT connection owns its network connection. */ + void * pNetworkConnection; /**< @brief References the transport-layer network connection. */ + const IotNetworkInterface_t * pNetworkInterface; /**< @brief Network interface provided to @ref mqtt_function_connect. */ + IotMqttCallbackInfo_t disconnectCallback; /**< @brief A function to invoke when this connection is disconnected. */ + + const IotMqttSerializer_t * pSerializer; /**< @brief MQTT packet serializer overrides. */ + + bool disconnected; /**< @brief Tracks if this connection has been disconnected. */ + IotMutex_t referencesMutex; /**< @brief Recursive mutex. Grants access to connection state and operation lists. */ + int32_t references; /**< @brief Counts callbacks and operations using this connection. */ + IotListDouble_t pendingProcessing; /**< @brief List of operations waiting to be processed by a task pool routine. */ + IotListDouble_t pendingResponse; /**< @brief List of processed operations awaiting a server response. */ + + IotListDouble_t subscriptionList; /**< @brief Holds subscriptions associated with this connection. */ + IotMutex_t subscriptionMutex; /**< @brief Grants exclusive access to the subscription list. */ + + _mqttOperation_t pingreq; /**< @brief Operation used for MQTT keep-alive. */ +} _mqttConnection_t; + +/** + * @brief Represents a subscription stored in an MQTT connection. + */ +typedef struct _mqttSubscription +{ + IotLink_t link; /**< @brief List link member. */ + + int32_t references; /**< @brief How many subscription callbacks are using this subscription. */ + + /** + * @brief Tracks whether an unsubscribe function has been called for + * this subscription. + * + * If there are active subscription callbacks, this subscription cannot be removed. + * Instead, this flag will be set, which schedules the removal of this subscription + * once all subscription callbacks terminate. + */ + bool unsubscribed; + + struct + { + uint16_t identifier; /**< @brief Packet identifier. */ + size_t order; /**< @brief Order in the packet's list of subscriptions. */ + } packetInfo; /**< @brief Information about the SUBSCRIBE packet that registered this subscription. */ + + IotMqttCallbackInfo_t callback; /**< @brief Callback information for this subscription. */ + + uint16_t topicFilterLength; /**< @brief Length of #_mqttSubscription_t.pTopicFilter. */ + char pTopicFilter[]; /**< @brief The subscription topic filter. */ +} _mqttSubscription_t; + +/** + * @brief Represents an MQTT packet received from the network. + * + * This struct is used to hold parameters for the deserializers so that all + * deserializers have the same function signature. + */ +typedef struct _mqttPacket +{ + union + { + /** + * @brief (Input) MQTT connection associated with this packet. Only used + * when deserializing SUBACKs. + */ + _mqttConnection_t * pMqttConnection; + + /** + * @brief (Output) Operation representing an incoming PUBLISH. Only used + * when deserializing PUBLISHes. + */ + _mqttOperation_t * pIncomingPublish; + } u; /**< @brief Valid member depends on packet being decoded. */ + + uint8_t * pRemainingData; /**< @brief (Input) The remaining data in MQTT packet. */ + size_t remainingLength; /**< @brief (Input) Length of the remaining data in the MQTT packet. */ + uint16_t packetIdentifier; /**< @brief (Output) MQTT packet identifier. */ + uint8_t type; /**< @brief (Input) A value identifying the packet type. */ +} _mqttPacket_t; + +/*-------------------- MQTT struct validation functions ---------------------*/ + +/** + * @brief Check that an #IotMqttConnectInfo_t is valid. + * + * @param[in] pConnectInfo The #IotMqttConnectInfo_t to validate. + * + * @return `true` if `pConnectInfo` is valid; `false` otherwise. + */ +bool _IotMqtt_ValidateConnect( const IotMqttConnectInfo_t * pConnectInfo ); + +/** + * @brief Check that an #IotMqttPublishInfo_t is valid. + * + * @param[in] awsIotMqttMode Specifies if this PUBLISH packet is being sent to + * an AWS IoT MQTT server. + * @param[in] pPublishInfo The #IotMqttPublishInfo_t to validate. + * + * @return `true` if `pPublishInfo` is valid; `false` otherwise. + */ +bool _IotMqtt_ValidatePublish( bool awsIotMqttMode, + const IotMqttPublishInfo_t * pPublishInfo ); + +/** + * @brief Check that an #IotMqttPublishInfo_t is valid for an LWT publish + * + * @param[in] awsIotMqttMode Specifies if this PUBLISH packet is being sent to + * an AWS IoT MQTT server. + * @param[in] pLwtPublishInfo The #IotMqttPublishInfo_t to validate. + * + * @return `true` if `pLwtPublishInfo` is valid; `false` otherwise. + */ +bool _IotMqtt_ValidateLwtPublish( bool awsIotMqttMode, + const IotMqttPublishInfo_t * pLwtPublishInfo ); + +/** + * @brief Check that an #IotMqttOperation_t is valid and waitable. + * + * @param[in] operation The #IotMqttOperation_t to validate. + * + * @return `true` if `operation` is valid; `false` otherwise. + */ +bool _IotMqtt_ValidateOperation( IotMqttOperation_t operation ); + +/** + * @brief Check that a list of #IotMqttSubscription_t is valid. + * + * @param[in] operation Either #IOT_MQTT_SUBSCRIBE or #IOT_MQTT_UNSUBSCRIBE. + * Some parameters are not validated for #IOT_MQTT_UNSUBSCRIBE. + * @param[in] awsIotMqttMode Specifies if this SUBSCRIBE packet is being sent to + * an AWS IoT MQTT server. + * @param[in] pListStart First element of the list to validate. + * @param[in] listSize Number of elements in the subscription list. + * + * @return `true` if every element in the list is valid; `false` otherwise. + */ +bool _IotMqtt_ValidateSubscriptionList( IotMqttOperationType_t operation, + bool awsIotMqttMode, + const IotMqttSubscription_t * pListStart, + size_t listSize ); + +/*-------------------- MQTT packet serializer functions ---------------------*/ + +/** + * @brief Get the MQTT packet type from a stream of bytes off the network. + * + * @param[in] pNetworkConnection Reference to the network connection. + * @param[in] pNetworkInterface Function pointers used to interact with the + * network. + * + * @return One of the server-to-client MQTT packet types. + * + * @note This function is only used for incoming packets, and may not work + * correctly for outgoing packets. + */ +uint8_t _IotMqtt_GetPacketType( void * pNetworkConnection, + const IotNetworkInterface_t * pNetworkInterface ); + +/** + * @brief Get the remaining length from a stream of bytes off the network. + * + * @param[in] pNetworkConnection Reference to the network connection. + * @param[in] pNetworkInterface Function pointers used to interact with the + * network. + * + * @return The remaining length; #MQTT_REMAINING_LENGTH_INVALID on error. + */ +size_t _IotMqtt_GetRemainingLength( void * pNetworkConnection, + const IotNetworkInterface_t * pNetworkInterface ); + +/** + * @brief Get the remaining length from a stream of bytes off the network. + * + * @param[in] pNetworkConnection Reference to the network connection. + * @param[in] getNextByte Function pointer used to interact with the + * network to get next byte. + * + * @return The remaining length; #MQTT_REMAINING_LENGTH_INVALID on error. + * + * @note This function is similar to _IotMqtt_GetRemainingLength() but it uses + * user provided getNextByte function to parse the stream instead of using + * _IotMqtt_GetNextByte(). pNetworkConnection is implementation dependent and + * user provided function makes use of it. + * + */ +size_t _IotMqtt_GetRemainingLength_Generic( void * pNetworkConnection, + IotMqttGetNextByte_t getNextByte ); + +/** + * @brief Generate a CONNECT packet from the given parameters. + * + * @param[in] pConnectInfo User-provided CONNECT information. + * @param[out] pConnectPacket Where the CONNECT packet is written. + * @param[out] pPacketSize Size of the packet written to `pConnectPacket`. + * + * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY. + */ +IotMqttError_t _IotMqtt_SerializeConnect( const IotMqttConnectInfo_t * pConnectInfo, + uint8_t ** pConnectPacket, + size_t * pPacketSize ); + +/** + * @brief Deserialize a CONNACK packet. + * + * Converts the packet from a stream of bytes to an #IotMqttError_t. Also + * prints out debug log messages about the packet. + * + * @param[in,out] pConnack Pointer to an MQTT packet struct representing a CONNACK. + * + * @return #IOT_MQTT_SUCCESS if CONNACK specifies that CONNECT was accepted; + * #IOT_MQTT_SERVER_REFUSED if CONNACK specifies that CONNECT was rejected; + * #IOT_MQTT_BAD_RESPONSE if the CONNACK packet doesn't follow MQTT spec. + */ +IotMqttError_t _IotMqtt_DeserializeConnack( _mqttPacket_t * pConnack ); + +/** + * @brief Generate a PUBLISH packet from the given parameters. + * + * @param[in] pPublishInfo User-provided PUBLISH information. + * @param[out] pPublishPacket Where the PUBLISH packet is written. + * @param[out] pPacketSize Size of the packet written to `pPublishPacket`. + * @param[out] pPacketIdentifier The packet identifier generated for this PUBLISH. + * @param[out] pPacketIdentifierHigh Where the high byte of the packet identifier + * is written. + * + * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY. + */ +IotMqttError_t _IotMqtt_SerializePublish( const IotMqttPublishInfo_t * pPublishInfo, + uint8_t ** pPublishPacket, + size_t * pPacketSize, + uint16_t * pPacketIdentifier, + uint8_t ** pPacketIdentifierHigh ); + +/** + * @brief Set the DUP bit in a QoS 1 PUBLISH packet. + * + * @param[in] pPublishPacket Pointer to the PUBLISH packet to modify. + * @param[in] pPacketIdentifierHigh The high byte of any packet identifier to modify. + * @param[out] pNewPacketIdentifier Since AWS IoT does not support the DUP flag, + * a new packet identifier is generated and should be written here. This parameter + * is only used when connected to an AWS IoT MQTT server. + * + * @note See #IotMqttPublishInfo_t for caveats with retransmission to the + * AWS IoT MQTT server. + */ +void _IotMqtt_PublishSetDup( uint8_t * pPublishPacket, + uint8_t * pPacketIdentifierHigh, + uint16_t * pNewPacketIdentifier ); + +/** + * @brief Deserialize a PUBLISH packet received from the server. + * + * Converts the packet from a stream of bytes to an #IotMqttPublishInfo_t and + * extracts the packet identifier. Also prints out debug log messages about the + * packet. + * + * @param[in,out] pPublish Pointer to an MQTT packet struct representing a PUBLISH. + * + * @return #IOT_MQTT_SUCCESS if PUBLISH is valid; #IOT_MQTT_BAD_RESPONSE + * if the PUBLISH packet doesn't follow MQTT spec. + */ +IotMqttError_t _IotMqtt_DeserializePublish( _mqttPacket_t * pPublish ); + +/** + * @brief Generate a PUBACK packet for the given packet identifier. + * + * @param[in] packetIdentifier The packet identifier to place in PUBACK. + * @param[out] pPubackPacket Where the PUBACK packet is written. + * @param[out] pPacketSize Size of the packet written to `pPubackPacket`. + * + * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY. + */ +IotMqttError_t _IotMqtt_SerializePuback( uint16_t packetIdentifier, + uint8_t ** pPubackPacket, + size_t * pPacketSize ); + +/** + * @brief Deserialize a PUBACK packet. + * + * Converts the packet from a stream of bytes to an #IotMqttError_t and extracts + * the packet identifier. Also prints out debug log messages about the packet. + * + * @param[in,out] pPuback Pointer to an MQTT packet struct representing a PUBACK. + * + * @return #IOT_MQTT_SUCCESS if PUBACK is valid; #IOT_MQTT_BAD_RESPONSE + * if the PUBACK packet doesn't follow MQTT spec. + */ +IotMqttError_t _IotMqtt_DeserializePuback( _mqttPacket_t * pPuback ); + +/** + * @brief Generate a SUBSCRIBE packet from the given parameters. + * + * @param[in] pSubscriptionList User-provided array of subscriptions. + * @param[in] subscriptionCount Size of `pSubscriptionList`. + * @param[out] pSubscribePacket Where the SUBSCRIBE packet is written. + * @param[out] pPacketSize Size of the packet written to `pSubscribePacket`. + * @param[out] pPacketIdentifier The packet identifier generated for this SUBSCRIBE. + * + * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY. + */ +IotMqttError_t _IotMqtt_SerializeSubscribe( const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint8_t ** pSubscribePacket, + size_t * pPacketSize, + uint16_t * pPacketIdentifier ); + +/** + * @brief Deserialize a SUBACK packet. + * + * Converts the packet from a stream of bytes to an #IotMqttError_t and extracts + * the packet identifier. Also prints out debug log messages about the packet. + * + * @param[in,out] pSuback Pointer to an MQTT packet struct representing a SUBACK. + * + * @return #IOT_MQTT_SUCCESS if SUBACK is valid; #IOT_MQTT_BAD_RESPONSE + * if the SUBACK packet doesn't follow MQTT spec. + */ +IotMqttError_t _IotMqtt_DeserializeSuback( _mqttPacket_t * pSuback ); + +/** + * @brief Generate an UNSUBSCRIBE packet from the given parameters. + * + * @param[in] pSubscriptionList User-provided array of subscriptions to remove. + * @param[in] subscriptionCount Size of `pSubscriptionList`. + * @param[out] pUnsubscribePacket Where the UNSUBSCRIBE packet is written. + * @param[out] pPacketSize Size of the packet written to `pUnsubscribePacket`. + * @param[out] pPacketIdentifier The packet identifier generated for this UNSUBSCRIBE. + * + * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY. + */ +IotMqttError_t _IotMqtt_SerializeUnsubscribe( const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount, + uint8_t ** pUnsubscribePacket, + size_t * pPacketSize, + uint16_t * pPacketIdentifier ); + +/** + * @brief Deserialize a UNSUBACK packet. + * + * Converts the packet from a stream of bytes to an #IotMqttError_t and extracts + * the packet identifier. Also prints out debug log messages about the packet. + * + * @param[in,out] pUnsuback Pointer to an MQTT packet struct representing an UNSUBACK. + * + * @return #IOT_MQTT_SUCCESS if UNSUBACK is valid; #IOT_MQTT_BAD_RESPONSE + * if the UNSUBACK packet doesn't follow MQTT spec. + */ +IotMqttError_t _IotMqtt_DeserializeUnsuback( _mqttPacket_t * pUnsuback ); + +/** + * @brief Generate a PINGREQ packet. + * + * @param[out] pPingreqPacket Where the PINGREQ packet is written. + * @param[out] pPacketSize Size of the packet written to `pPingreqPacket`. + * + * @return Always returns #IOT_MQTT_SUCCESS. + */ +IotMqttError_t _IotMqtt_SerializePingreq( uint8_t ** pPingreqPacket, + size_t * pPacketSize ); + +/** + * @brief Deserialize a PINGRESP packet. + * + * Converts the packet from a stream of bytes to an #IotMqttError_t. Also + * prints out debug log messages about the packet. + * + * @param[in,out] pPingresp Pointer to an MQTT packet struct representing a PINGRESP. + * + * @return #IOT_MQTT_SUCCESS if PINGRESP is valid; #IOT_MQTT_BAD_RESPONSE + * if the PINGRESP packet doesn't follow MQTT spec. + */ +IotMqttError_t _IotMqtt_DeserializePingresp( _mqttPacket_t * pPingresp ); + +/** + * @brief Generate a DISCONNECT packet. + * + * @param[out] pDisconnectPacket Where the DISCONNECT packet is written. + * @param[out] pPacketSize Size of the packet written to `pDisconnectPacket`. + * + * @return Always returns #IOT_MQTT_SUCCESS. + */ +IotMqttError_t _IotMqtt_SerializeDisconnect( uint8_t ** pDisconnectPacket, + size_t * pPacketSize ); + +/** + * @brief Free a packet generated by the serializer. + * + * @param[in] pPacket The packet to free. + */ +void _IotMqtt_FreePacket( uint8_t * pPacket ); + +/*-------------------- MQTT operation record functions ----------------------*/ + +/** + * @brief Create a record for a new in-progress MQTT operation. + * + * @param[in] pMqttConnection The MQTT connection to associate with the operation. + * @param[in] flags Flags variable passed to a user-facing MQTT function. + * @param[in] pCallbackInfo User-provided callback function and parameter. + * @param[out] pNewOperation Set to point to the new operation on success. + * + * @return #IOT_MQTT_SUCCESS, #IOT_MQTT_BAD_PARAMETER, or #IOT_MQTT_NO_MEMORY. + */ +IotMqttError_t _IotMqtt_CreateOperation( _mqttConnection_t * pMqttConnection, + uint32_t flags, + const IotMqttCallbackInfo_t * pCallbackInfo, + _mqttOperation_t ** pNewOperation ); + +/** + * @brief Decrement the job reference count of an MQTT operation and optionally + * cancel its job. + * + * Checks if the operation may be destroyed afterwards. + * + * @param[in] pOperation The MQTT operation with the job to cancel. + * @param[in] cancelJob Whether to attempt cancellation of the operation's job. + * + * @return `true` if the the operation may be safely destroyed; `false` otherwise. + */ +bool _IotMqtt_DecrementOperationReferences( _mqttOperation_t * pOperation, + bool cancelJob ); + +/** + * @brief Free resources used to record an MQTT operation. This is called when + * the operation completes. + * + * @param[in] pOperation The operation which completed. + */ +void _IotMqtt_DestroyOperation( _mqttOperation_t * pOperation ); + +/** + * @brief Task pool routine for processing an MQTT connection's keep-alive. + * + * @param[in] pTaskPool Pointer to the system task pool. + * @param[in] pKeepAliveJob Pointer the an MQTT connection's keep-alive job. + * @param[in] pContext Pointer to an MQTT connection, passed as an opaque context. + */ +void _IotMqtt_ProcessKeepAlive( IotTaskPool_t pTaskPool, + IotTaskPoolJob_t pKeepAliveJob, + void * pContext ); + +/** + * @brief Task pool routine for processing an incoming PUBLISH message. + * + * @param[in] pTaskPool Pointer to the system task pool. + * @param[in] pPublishJob Pointer to the incoming PUBLISH operation's job. + * @param[in] pContext Pointer to the incoming PUBLISH operation, passed as an + * opaque context. + */ +void _IotMqtt_ProcessIncomingPublish( IotTaskPool_t pTaskPool, + IotTaskPoolJob_t pPublishJob, + void * pContext ); + +/** + * @brief Task pool routine for processing an MQTT operation to send. + * + * @param[in] pTaskPool Pointer to the system task pool. + * @param[in] pSendJob Pointer to an operation's job. + * @param[in] pContext Pointer to the operation to send, passed as an opaque + * context. + */ +void _IotMqtt_ProcessSend( IotTaskPool_t pTaskPool, + IotTaskPoolJob_t pSendJob, + void * pContext ); + +/** + * @brief Task pool routine for processing a completed MQTT operation. + * + * @param[in] pTaskPool Pointer to the system task pool. + * @param[in] pOperationJob Pointer to the completed operation's job. + * @param[in] pContext Pointer to the completed operation, passed as an opaque + * context. + */ +void _IotMqtt_ProcessCompletedOperation( IotTaskPool_t pTaskPool, + IotTaskPoolJob_t pOperationJob, + void * pContext ); + +/** + * @brief Schedule an operation for immediate processing. + * + * @param[in] pOperation The operation to schedule. + * @param[in] jobRoutine The routine to run for the job. Must be either + * #_IotMqtt_ProcessSend, #_IotMqtt_ProcessCompletedOperation, or + * #_IotMqtt_ProcessIncomingPublish. + * @param[in] delay A delay before the operation job should be executed. Pass + * `0` to execute ASAP. + * + * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_SCHEDULING_ERROR. + */ +IotMqttError_t _IotMqtt_ScheduleOperation( _mqttOperation_t * pOperation, + IotTaskPoolRoutine_t jobRoutine, + uint32_t delay ); + +/** + * @brief Search a list of MQTT operations pending responses using an operation + * name and packet identifier. Removes a matching operation from the list if found. + * + * @param[in] pMqttConnection The connection associated with the operation. + * @param[in] type The operation type to look for. + * @param[in] pPacketIdentifier A packet identifier to match. Pass `NULL` to ignore. + * + * @return Pointer to any matching operation; `NULL` if no match was found. + */ +_mqttOperation_t * _IotMqtt_FindOperation( _mqttConnection_t * pMqttConnection, + IotMqttOperationType_t type, + const uint16_t * pPacketIdentifier ); + +/** + * @brief Notify of a completed MQTT operation. + * + * @param[in] pOperation The MQTT operation which completed. + * + * Depending on the parameters passed to a user-facing MQTT function, the + * notification will cause @ref mqtt_function_wait to return or invoke a + * user-provided callback. + */ +void _IotMqtt_Notify( _mqttOperation_t * pOperation ); + +/*----------------- MQTT subscription management functions ------------------*/ + +/** + * @brief Add an array of subscriptions to the subscription manager. + * + * @param[in] pMqttConnection The MQTT connection associated with the subscriptions. + * @param[in] subscribePacketIdentifier Packet identifier for the subscriptions' + * SUBSCRIBE packet. + * @param[in] pSubscriptionList The first element in the array. + * @param[in] subscriptionCount Number of elements in `pSubscriptionList`. + * + * @return #IOT_MQTT_SUCCESS or #IOT_MQTT_NO_MEMORY. + */ +IotMqttError_t _IotMqtt_AddSubscriptions( _mqttConnection_t * pMqttConnection, + uint16_t subscribePacketIdentifier, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount ); + +/** + * @brief Process a received PUBLISH from the server, invoking any subscription + * callbacks that have a matching topic filter. + * + * @param[in] pMqttConnection The MQTT connection associated with the received + * PUBLISH. + * @param[in] pCallbackParam The parameter to pass to a PUBLISH callback. + */ +void _IotMqtt_InvokeSubscriptionCallback( _mqttConnection_t * pMqttConnection, + IotMqttCallbackParam_t * pCallbackParam ); + +/** + * @brief Remove a single subscription from the subscription manager by + * packetIdentifier and order. + * + * @param[in] pMqttConnection The MQTT connection associated with the subscriptions. + * @param[in] packetIdentifier The packet identifier associated with the subscription's + * SUBSCRIBE packet. + * @param[in] order The order of the subscription in the SUBSCRIBE packet. + * Pass #MQTT_REMOVE_ALL_SUBSCRIPTIONS to ignore order and remove all subscriptions for `packetIdentifier`. + */ +void _IotMqtt_RemoveSubscriptionByPacket( _mqttConnection_t * pMqttConnection, + uint16_t packetIdentifier, + int32_t order ); + +/** + * @brief Remove an array of subscriptions from the subscription manager by + * topic filter. + * + * @param[in] pMqttConnection The MQTT connection associated with the subscriptions. + * @param[in] pSubscriptionList The first element in the array. + * @param[in] subscriptionCount Number of elements in `pSubscriptionList`. + */ +void _IotMqtt_RemoveSubscriptionByTopicFilter( _mqttConnection_t * pMqttConnection, + const IotMqttSubscription_t * pSubscriptionList, + size_t subscriptionCount ); + +/*------------------ MQTT connection management functions -------------------*/ + +/** + * @brief Attempt to increment the reference count of an MQTT connection. + * + * @param[in] pMqttConnection The referenced MQTT connection. + * + * @return `true` if the reference count was incremented; `false` otherwise. The + * reference count will not be incremented for a disconnected connection. + */ +bool _IotMqtt_IncrementConnectionReferences( _mqttConnection_t * pMqttConnection ); + +/** + * @brief Decrement the reference count of an MQTT connection. + * + * Also destroys an unreferenced MQTT connection. + * + * @param[in] pMqttConnection The referenced MQTT connection. + */ +void _IotMqtt_DecrementConnectionReferences( _mqttConnection_t * pMqttConnection ); + +/** + * @brief Read the next available byte on a network connection. + * + * @param[in] pNetworkConnection Reference to the network connection. + * @param[in] pNetworkInterface Function pointers used to interact with the + * network. + * @param[out] pIncomingByte The byte read from the network. + * + * @return `true` if a byte was successfully received from the network; `false` + * otherwise. + */ +bool _IotMqtt_GetNextByte( void * pNetworkConnection, + const IotNetworkInterface_t * pNetworkInterface, + uint8_t * pIncomingByte ); + +/** + * @brief Closes the network connection associated with an MQTT connection. + * + * A network disconnect function must be set in the network interface for the + * network connection to be closed. + * + * @param[in] disconnectReason A reason to pass to the connection's disconnect + * callback. + * @param[in] pMqttConnection The MQTT connection with the network connection + * to close. + */ +void _IotMqtt_CloseNetworkConnection( IotMqttDisconnectReason_t disconnectReason, + _mqttConnection_t * pMqttConnection ); + +#if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 + +/** + * @brief Utility macro for creating serializer override selector functions + */ + #define _SERIALIZER_OVERRIDE_SELECTOR( _funcType_t, _funcName, _defaultFunc, _serializerMember ) \ + static _funcType_t _funcName( const IotMqttSerializer_t * pSerializer ); \ + static _funcType_t _funcName( const IotMqttSerializer_t * pSerializer ) \ + { \ + _funcType_t _returnValue = _defaultFunc; \ + if( pSerializer != NULL ) \ + { \ + if( pSerializer->_serializerMember != NULL ) \ + { \ + _returnValue = pSerializer->_serializerMember; \ + } \ + else \ + { \ + EMPTY_ELSE_MARKER; \ + } \ + } \ + else \ + { \ + EMPTY_ELSE_MARKER; \ + } \ + return _returnValue; \ + } +#endif /* if IOT_MQTT_ENABLE_SERIALIZER_OVERRIDES == 1 */ + +#endif /* ifndef IOT_MQTT_INTERNAL_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/directories.txt b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/directories.txt new file mode 100644 index 000000000..b22d7e6f0 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/directories.txt @@ -0,0 +1,8 @@ +Base directory for the FreeRTOS IoT Libraries. + ++ abstractions +Contains FreeRTOS specific implementations of abstractions used within the IoT +libraries. + ++ c_sdk +Contains the implementations of the IoT libraries - more will be rolled out soon. diff --git a/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/readme.txt b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/readme.txt new file mode 100644 index 000000000..da1ae90fe --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-IoT-Libraries/readme.txt @@ -0,0 +1,46 @@ +*** INTRODUCTION *** + +This distribution currently contains demos from the FreeRTOS task pool library, +MQTT library, HTTPS Client library, Shadow library, and Jobs library. + +The pre-configured projects use the FreeRTOS kernel Windows port (often +called the Windows simulator) to enable their evaluation using the free Visual +Studio tools and without needing specific microcontroller hardware. + +NOTE: At this time the projects ARE A WORK IN PROGRESS and will be released in +the main FreeRTOS kernel download following full review and completion of the +documentation. + + +*** INSTRUCTIONS *** + +Instructions for configuring and using the FreeRTOS IoT libraries are in the +following links: + + + https://www.FreeRTOS.org/task-pool/ + + https://www.FreeRTOS.org/mqtt/ + + https://www.freertos.org/https/ + + https://www.FreeRTOS.org/shadow/ + + https://www.FreeRTOS.org/jobs/ + + +*** LOCATING THE EXAMPLE PROJECTS *** + +The Visual Studio projects for each of the FreeRTOS IoT library examples are +located in sub-directories of the following top-level directories: + + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs + + +*** ADDITIONAL INFORMATION *** + +See http://www.freertos.org/a00017.html for full details of the FreeRTOS +directory structure + +See also - +http://www.freertos.org/FreeRTOS-quick-start-guide.html +http://www.freertos.org/FAQHelp.html diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/FreeRTOS_CLI.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/FreeRTOS_CLI.c new file mode 100644 index 000000000..6629892a7 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/FreeRTOS_CLI.c @@ -0,0 +1,347 @@ +/* + * FreeRTOS+CLI V1.0.3 (C) 2014 Real Time Engineers ltd. All rights reserved. + * + * This file is part of the FreeRTOS+CLI distribution. The FreeRTOS+CLI license + * terms are different to the FreeRTOS license terms. + * + * FreeRTOS+CLI uses a dual license model that allows the software to be used + * under a standard GPL open source license, or a commercial license. The + * standard GPL license (unlike the modified GPL license under which FreeRTOS + * itself is distributed) requires that all software statically linked with + * FreeRTOS+CLI is also distributed under the same GPL V2 license terms. + * Details of both license options follow: + * + * - Open source licensing - + * FreeRTOS+CLI is a free download and may be used, modified, evaluated and + * distributed without charge provided the user adheres to version two of the + * GNU General Public License (GPL) and does not remove the copyright notice or + * this text. The GPL V2 text is available on the gnu.org web site, and on the + * following URL: http://www.FreeRTOS.org/gpl-2.0.txt. + * + * - Commercial licensing - + * Businesses and individuals that for commercial or other reasons cannot comply + * with the terms of the GPL V2 license must obtain a low cost commercial + * license before incorporating FreeRTOS+CLI into proprietary software for + * distribution in any form. Commercial licenses can be purchased from + * http://shop.freertos.org/cli and do not require any source files to be + * changed. + * + * FreeRTOS+CLI is distributed in the hope that it will be useful. You cannot + * use FreeRTOS+CLI unless you agree that you use the software 'as is'. + * FreeRTOS+CLI is provided WITHOUT ANY WARRANTY; without even the implied + * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they + * implied, expressed, or statutory. + * + * 1 tab == 4 spaces! + * + * http://www.FreeRTOS.org + * http://www.FreeRTOS.org/FreeRTOS-Plus + * + */ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Utils includes. */ +#include "FreeRTOS_CLI.h" + +typedef struct xCOMMAND_INPUT_LIST +{ + const CLI_Command_Definition_t *pxCommandLineDefinition; + struct xCOMMAND_INPUT_LIST *pxNext; +} CLI_Definition_List_Item_t; + +/* + * The callback function that is executed when "help" is entered. This is the + * only default command that is always present. + */ +static BaseType_t prvHelpCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* + * Return the number of parameters that follow the command name. + */ +static int8_t prvGetNumberOfParameters( const char *pcCommandString ); + +/* The definition of the "help" command. This command is always at the front +of the list of registered commands. */ +static const CLI_Command_Definition_t xHelpCommand = +{ + "help", + "\r\nhelp:\r\n Lists all the registered commands\r\n\r\n", + prvHelpCommand, + 0 +}; + +/* The definition of the list of commands. Commands that are registered are +added to this list. */ +static CLI_Definition_List_Item_t xRegisteredCommands = +{ + &xHelpCommand, /* The first command in the list is always the help command, defined in this file. */ + NULL /* The next pointer is initialised to NULL, as there are no other registered commands yet. */ +}; + +/* A buffer into which command outputs can be written is declared here, rather +than in the command console implementation, to allow multiple command consoles +to share the same buffer. For example, an application may allow access to the +command interpreter by UART and by Ethernet. Sharing a buffer is done purely +to save RAM. Note, however, that the command console itself is not re-entrant, +so only one command interpreter interface can be used at any one time. For that +reason, no attempt at providing mutual exclusion to the cOutputBuffer array is +attempted. */ +static char cOutputBuffer[ configCOMMAND_INT_MAX_OUTPUT_SIZE ]; + +/*-----------------------------------------------------------*/ + +BaseType_t FreeRTOS_CLIRegisterCommand( const CLI_Command_Definition_t * const pxCommandToRegister ) +{ +static CLI_Definition_List_Item_t *pxLastCommandInList = &xRegisteredCommands; +CLI_Definition_List_Item_t *pxNewListItem; +BaseType_t xReturn = pdFAIL; + + /* Check the parameter is not NULL. */ + configASSERT( pxCommandToRegister ); + + /* Create a new list item that will reference the command being registered. */ + pxNewListItem = ( CLI_Definition_List_Item_t * ) pvPortMalloc( sizeof( CLI_Definition_List_Item_t ) ); + configASSERT( pxNewListItem ); + + if( pxNewListItem != NULL ) + { + taskENTER_CRITICAL(); + { + /* Reference the command being registered from the newly created + list item. */ + pxNewListItem->pxCommandLineDefinition = pxCommandToRegister; + + /* The new list item will get added to the end of the list, so + pxNext has nowhere to point. */ + pxNewListItem->pxNext = NULL; + + /* Add the newly created list item to the end of the already existing + list. */ + pxLastCommandInList->pxNext = pxNewListItem; + + /* Set the end of list marker to the new list item. */ + pxLastCommandInList = pxNewListItem; + } + taskEXIT_CRITICAL(); + + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t FreeRTOS_CLIProcessCommand( const char * const pcCommandInput, char * pcWriteBuffer, size_t xWriteBufferLen ) +{ +static const CLI_Definition_List_Item_t *pxCommand = NULL; +BaseType_t xReturn = pdTRUE; +const char *pcRegisteredCommandString; +size_t xCommandStringLength; + + /* Note: This function is not re-entrant. It must not be called from more + thank one task. */ + + if( pxCommand == NULL ) + { + /* Search for the command string in the list of registered commands. */ + for( pxCommand = &xRegisteredCommands; pxCommand != NULL; pxCommand = pxCommand->pxNext ) + { + pcRegisteredCommandString = pxCommand->pxCommandLineDefinition->pcCommand; + xCommandStringLength = strlen( pcRegisteredCommandString ); + + /* To ensure the string lengths match exactly, so as not to pick up + a sub-string of a longer command, check the byte after the expected + end of the string is either the end of the string or a space before + a parameter. */ + if( ( pcCommandInput[ xCommandStringLength ] == ' ' ) || ( pcCommandInput[ xCommandStringLength ] == 0x00 ) ) + { + if( strncmp( pcCommandInput, pcRegisteredCommandString, xCommandStringLength ) == 0 ) + { + /* The command has been found. Check it has the expected + number of parameters. If cExpectedNumberOfParameters is -1, + then there could be a variable number of parameters and no + check is made. */ + if( pxCommand->pxCommandLineDefinition->cExpectedNumberOfParameters >= 0 ) + { + if( prvGetNumberOfParameters( pcCommandInput ) != pxCommand->pxCommandLineDefinition->cExpectedNumberOfParameters ) + { + xReturn = pdFALSE; + } + } + + break; + } + } + } + } + + if( ( pxCommand != NULL ) && ( xReturn == pdFALSE ) ) + { + /* The command was found, but the number of parameters with the command + was incorrect. */ + strncpy( pcWriteBuffer, "Incorrect command parameter(s). Enter \"help\" to view a list of available commands.\r\n\r\n", xWriteBufferLen ); + pxCommand = NULL; + } + else if( pxCommand != NULL ) + { + /* Call the callback function that is registered to this command. */ + xReturn = pxCommand->pxCommandLineDefinition->pxCommandInterpreter( pcWriteBuffer, xWriteBufferLen, pcCommandInput ); + + /* If xReturn is pdFALSE, then no further strings will be returned + after this one, and pxCommand can be reset to NULL ready to search + for the next entered command. */ + if( xReturn == pdFALSE ) + { + pxCommand = NULL; + } + } + else + { + /* pxCommand was NULL, the command was not found. */ + strncpy( pcWriteBuffer, "Command not recognised. Enter 'help' to view a list of available commands.\r\n\r\n", xWriteBufferLen ); + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +char *FreeRTOS_CLIGetOutputBuffer( void ) +{ + return cOutputBuffer; +} +/*-----------------------------------------------------------*/ + +const char *FreeRTOS_CLIGetParameter( const char *pcCommandString, UBaseType_t uxWantedParameter, BaseType_t *pxParameterStringLength ) +{ +UBaseType_t uxParametersFound = 0; +const char *pcReturn = NULL; + + *pxParameterStringLength = 0; + + while( uxParametersFound < uxWantedParameter ) + { + /* Index the character pointer past the current word. If this is the start + of the command string then the first word is the command itself. */ + while( ( ( *pcCommandString ) != 0x00 ) && ( ( *pcCommandString ) != ' ' ) ) + { + pcCommandString++; + } + + /* Find the start of the next string. */ + while( ( ( *pcCommandString ) != 0x00 ) && ( ( *pcCommandString ) == ' ' ) ) + { + pcCommandString++; + } + + /* Was a string found? */ + if( *pcCommandString != 0x00 ) + { + /* Is this the start of the required parameter? */ + uxParametersFound++; + + if( uxParametersFound == uxWantedParameter ) + { + /* How long is the parameter? */ + pcReturn = pcCommandString; + while( ( ( *pcCommandString ) != 0x00 ) && ( ( *pcCommandString ) != ' ' ) ) + { + ( *pxParameterStringLength )++; + pcCommandString++; + } + + if( *pxParameterStringLength == 0 ) + { + pcReturn = NULL; + } + + break; + } + } + else + { + break; + } + } + + return pcReturn; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvHelpCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ) +{ +static const CLI_Definition_List_Item_t * pxCommand = NULL; +BaseType_t xReturn; + + ( void ) pcCommandString; + + if( pxCommand == NULL ) + { + /* Reset the pxCommand pointer back to the start of the list. */ + pxCommand = &xRegisteredCommands; + } + + /* Return the next command help string, before moving the pointer on to + the next command in the list. */ + strncpy( pcWriteBuffer, pxCommand->pxCommandLineDefinition->pcHelpString, xWriteBufferLen ); + pxCommand = pxCommand->pxNext; + + if( pxCommand == NULL ) + { + /* There are no more commands in the list, so there will be no more + strings to return after this one and pdFALSE should be returned. */ + xReturn = pdFALSE; + } + else + { + xReturn = pdTRUE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static int8_t prvGetNumberOfParameters( const char *pcCommandString ) +{ +int8_t cParameters = 0; +BaseType_t xLastCharacterWasSpace = pdFALSE; + + /* Count the number of space delimited words in pcCommandString. */ + while( *pcCommandString != 0x00 ) + { + if( ( *pcCommandString ) == ' ' ) + { + if( xLastCharacterWasSpace != pdTRUE ) + { + cParameters++; + xLastCharacterWasSpace = pdTRUE; + } + } + else + { + xLastCharacterWasSpace = pdFALSE; + } + + pcCommandString++; + } + + /* If the command string ended with spaces, then there will have been too + many parameters counted. */ + if( xLastCharacterWasSpace == pdTRUE ) + { + cParameters--; + } + + /* The value returned is one less than the number of space delimited words, + as the first word should be the command itself. */ + return cParameters; +} + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/FreeRTOS_CLI.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/FreeRTOS_CLI.h new file mode 100644 index 000000000..5820bff2f --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/FreeRTOS_CLI.h @@ -0,0 +1,120 @@ +/* + * FreeRTOS+CLI V1.0.3 (C) 2014 Real Time Engineers ltd. All rights reserved. + * + * This file is part of the FreeRTOS+CLI distribution. The FreeRTOS+CLI license + * terms are different to the FreeRTOS license terms. + * + * FreeRTOS+CLI uses a dual license model that allows the software to be used + * under a standard GPL open source license, or a commercial license. The + * standard GPL license (unlike the modified GPL license under which FreeRTOS + * itself is distributed) requires that all software statically linked with + * FreeRTOS+CLI is also distributed under the same GPL V2 license terms. + * Details of both license options follow: + * + * - Open source licensing - + * FreeRTOS+CLI is a free download and may be used, modified, evaluated and + * distributed without charge provided the user adheres to version two of the + * GNU General Public License (GPL) and does not remove the copyright notice or + * this text. The GPL V2 text is available on the gnu.org web site, and on the + * following URL: http://www.FreeRTOS.org/gpl-2.0.txt. + * + * - Commercial licensing - + * Businesses and individuals that for commercial or other reasons cannot comply + * with the terms of the GPL V2 license must obtain a low cost commercial + * license before incorporating FreeRTOS+CLI into proprietary software for + * distribution in any form. Commercial licenses can be purchased from + * http://shop.freertos.org/cli and do not require any source files to be + * changed. + * + * FreeRTOS+CLI is distributed in the hope that it will be useful. You cannot + * use FreeRTOS+CLI unless you agree that you use the software 'as is'. + * FreeRTOS+CLI is provided WITHOUT ANY WARRANTY; without even the implied + * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they + * implied, expressed, or statutory. + * + * 1 tab == 4 spaces! + * + * http://www.FreeRTOS.org + * http://www.FreeRTOS.org/FreeRTOS-Plus + * + */ + +#ifndef COMMAND_INTERPRETER_H +#define COMMAND_INTERPRETER_H + +/* The prototype to which callback functions used to process command line +commands must comply. pcWriteBuffer is a buffer into which the output from +executing the command can be written, xWriteBufferLen is the length, in bytes of +the pcWriteBuffer buffer, and pcCommandString is the entire string as input by +the user (from which parameters can be extracted).*/ +typedef BaseType_t (*pdCOMMAND_LINE_CALLBACK)( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString ); + +/* The structure that defines command line commands. A command line command +should be defined by declaring a const structure of this type. */ +typedef struct xCOMMAND_LINE_INPUT +{ + const char * const pcCommand; /* The command that causes pxCommandInterpreter to be executed. For example "help". Must be all lower case. */ + const char * const pcHelpString; /* String that describes how to use the command. Should start with the command itself, and end with "\r\n". For example "help: Returns a list of all the commands\r\n". */ + const pdCOMMAND_LINE_CALLBACK pxCommandInterpreter; /* A pointer to the callback function that will return the output generated by the command. */ + int8_t cExpectedNumberOfParameters; /* Commands expect a fixed number of parameters, which may be zero. */ +} CLI_Command_Definition_t; + +/* For backward compatibility. */ +#define xCommandLineInput CLI_Command_Definition_t + +/* + * Register the command passed in using the pxCommandToRegister parameter. + * Registering a command adds the command to the list of commands that are + * handled by the command interpreter. Once a command has been registered it + * can be executed from the command line. + */ +BaseType_t FreeRTOS_CLIRegisterCommand( const CLI_Command_Definition_t * const pxCommandToRegister ); + +/* + * Runs the command interpreter for the command string "pcCommandInput". Any + * output generated by running the command will be placed into pcWriteBuffer. + * xWriteBufferLen must indicate the size, in bytes, of the buffer pointed to + * by pcWriteBuffer. + * + * FreeRTOS_CLIProcessCommand should be called repeatedly until it returns pdFALSE. + * + * pcCmdIntProcessCommand is not reentrant. It must not be called from more + * than one task - or at least - by more than one task at a time. + */ +BaseType_t FreeRTOS_CLIProcessCommand( const char * const pcCommandInput, char * pcWriteBuffer, size_t xWriteBufferLen ); + +/*-----------------------------------------------------------*/ + +/* + * A buffer into which command outputs can be written is declared in the + * main command interpreter, rather than in the command console implementation, + * to allow application that provide access to the command console via multiple + * interfaces to share a buffer, and therefore save RAM. Note, however, that + * the command interpreter itself is not re-entrant, so only one command + * console interface can be used at any one time. For that reason, no attempt + * is made to provide any mutual exclusion mechanism on the output buffer. + * + * FreeRTOS_CLIGetOutputBuffer() returns the address of the output buffer. + */ +char *FreeRTOS_CLIGetOutputBuffer( void ); + +/* + * Return a pointer to the xParameterNumber'th word in pcCommandString. + */ +const char *FreeRTOS_CLIGetParameter( const char *pcCommandString, UBaseType_t uxWantedParameter, BaseType_t *pxParameterStringLength ); + +#endif /* COMMAND_INTERPRETER_H */ + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/History.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/History.txt new file mode 100644 index 000000000..39b4668b2 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/History.txt @@ -0,0 +1,27 @@ +Changes between V1.0.2 and V1.0.3 released + + + Previously, and in line with good software engineering practice, the + FreeRTOS coding standard did not permit the use of char types that were + not explicitly qualified as either signed or unsigned. As a result char + pointers used to reference strings required casts, as did the use of any + standard string handling functions. The casts ensured compiler warnings + were not generated by compilers that defaulted unqualified char types to + be signed or compilers that defaulted unqualified char types to be + unsigned. As it has in later MISRA standards, this rule has now been + relaxed, and unqualified char types are now permitted, but only when: + 1) The char is used to point to a human readable text string. + 2) The char is used to hold a single ASCII character. + +Changes between V1.0.1 and V1.0.2 released 14/10/2013 + + + Changed double quotes (") to single quotes (') in the help string to + allow the strings to be used with JSON in FreeRTOS+Nabto. + +Changes between V1.0.0 and V1.0.1 released 05/07/2012 + + + Change the name of the structure used to map a function that implements + a CLI command to the string used to call the command from + xCommandLineInput to CLI_Command_Definition_t, as it was always intended + to be. A #define was added to map the old name to the new name for + reasons of backward compatibility. + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/LICENSE_INFORMATION.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/LICENSE_INFORMATION.txt new file mode 100644 index 000000000..f9e7dff51 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/LICENSE_INFORMATION.txt @@ -0,0 +1,7 @@ +Note the FreeRTOS+CLI license terms are different to the FreeRTOS license terms. + +FreeRTOS+CLI is dual licensed. The files are provided here under an unmodified +open source GNU GPL license. Commercial licenses are also available, and are +provided free for some hardware platforms. See http://www.FreeRTOS.org/cli + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/ReadMe.url b/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/ReadMe.url new file mode 100644 index 000000000..3a76266ab --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/ReadMe.url @@ -0,0 +1,5 @@ +[InternetShortcut] +URL=http://www.freertos.org/cli +IDList= +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,2 diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/readme.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/readme.txt new file mode 100644 index 000000000..0f61b02fd --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-CLI/readme.txt @@ -0,0 +1,4 @@ +Contains source and header files that implement FreeRTOS+CLI. See +http://www.FreeRTOS.org/cli for documentation and license information. + + \ No newline at end of file diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/History.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/History.txt new file mode 100644 index 000000000..c03fc6b0e --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/History.txt @@ -0,0 +1,58 @@ +Changes between 160112 and 160908 releases + + NOTE: The 160908 release is a maintenance release for the 160112 single + interface labs release - not a release of the current development branch. + + + ff-deltree() now correctly handles deleted file entries. + + Simplified mapping of standard library functions to their Visual Studio + equivalents. + + ffconfigMIN_CLUSTERS_FAT32 and ffconfigMIN_CLUSTERS_FAT16 introduced to + allow the minimum disk sizes for the two FAT file system types to be + smaller than is permitted by Windows. + +Changes between 150825 and 160111 releases + + + New device support: Demo applications and example drivers are provided + for Atmel SAM4E and ST STM32F4 microcontrollers. + + Various updates to improve compliance with the FreeRTOS coding standard. + + Modified the stdio tests so they can be executed on SD cards, where the + test files might already exists on power on - previously the tests were + only executed on RAM disks which are always known to be empty on power on. + + Added ff_deltree() implementation, with note of caution about its use as + it uses recursion ( ff_deltree() recursively removes a directory and + everything contained by it). + + Update the Zynq project to use version 2015.4 of the Xilinx SDK. This + driver dynamically recognises all types of memory cards. + + The path cache is cleared when a disk is re-mounted, allowing a disk to be + hot swapped. + + Bug fixes resulting from testing performed while converting the acquired + component to be FreeRTOS+ compliant: + + + Fix bug in FF_FindNext() when using 'ffconfigFINDAPI_ALLOW_WILDCARDS'. + + Fix bug in ff_fat.c when using 'ffconfigFSINFO_TRUSTED' and when the + stored free cluster count equals ~0ul (which means: not filled in) as this + was interpreted as having 4294967295 free clusters. + + FF_Open() now checks file permissions before truncating a file, previously + the file was truncated first. + + Fix typo in source of FF_isEOF(). + + FF_ExtendFile() now only attempts to reserve new clusters if it is + actually necessary. + + FF_Format() now correctly fills in the number of free clusters for FAT32. + + FF_Partition() has been updated to use ffconfigMAX_PARTITIONS in all + cases, whereas previously some legacy code was assuming a fixed maximum + number of partitions. + + FF_DeleteIOManager() now deletes the IO manager! + + +Changes for 150825 (?) + + + Issue fixed in FF_Move(). + + Improved handling of files and directories that start with a '.' character. + + Changed the locking mechanisms from mutexes to an event group. + + Add FF_ERR_DRIVER_NOMEDIUM to better handle media being removed and + re-inserted. + + Fix re-entrancy issue in FF_CheckValid(). + + Remove hashes for deleted files. + + General structural work. + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/History2.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/History2.txt new file mode 100644 index 000000000..17fdd98cc --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/History2.txt @@ -0,0 +1,66 @@ +> is there a repository I should be aware of when it comes to FreeRTOS Labs? + +Unfortunately there isn't. FreeRTOS+FAT has become a bit of an orphan. All time and energy goes to the products in the [AWS/FreeRTOS release](https://github.com/aws/amazon-freertos) +But I am still actively maintaining FreeRTOS+FAT: implementing requests and fixes. + +Please comment your findings with the above +FAT release. + +Here is a complete list of all changes since the 160919 Labs release: + +● `ff_dir.c : FF_MkDir()` +refuse to create a directory with an empty name + +● `ff_fat.c : FF_GetFreeSize()` +in case of an error, return 0 + +● `ff_file.c : FF_FileSize()` +This function returns the size of a file, or a negative number in case of an error. +Hence, the maximum size returned was returned is 2 GB. +We've added a new function: +`FF_Error_t FF_GetFileSize( FF_FILE *pxFile, uint32_t *pulSize );` +which separates the length from the error code. + +● `ff_file.c : FF_ExtendFile()` +Sometimes while building up a file, it may be more efficient not to flush the changes immediately. When defining `ffconfigFILE_EXTEND_FLUSHES_BUFFERS` as `0`, there is no immediate flushing. + +● `ff_file.c : FF_Seek()` +Seeking didn't work for sizes larger than 2 GB. Although the parameter `int32_t lOffset` is signed, it will now be casted to 32-bits unsigned: +`ulPosition = ( uint32_t )lOffset;` +All options (`SET`, `CUR`, and `END` ) re-tested. + +● `ff_file.c : FF_Close()` +`FF_FlushCache()` is now called at the end of the function in order to also write the last changes. + +● `ff_format.c : FF_Format()` +A variable `lRemaining` should have been declared unsigned: `uint32_t`. +Also: a small optimisation for large SD-cards: +"Putting the FAT-table into the second 4MB erase block gives a higher performance and a longer life-time" + +● `ff_format.c : FF_Partition()` +`ulHiddenSectors` must be at least `1` +( see [this post](https://sourceforge.net/p/freertos/discussion/382005/thread/d2b6524a/?limit=250#e1ea) ) + +● `ff_ioman.c : FF_CreateIOManger()` +`FF_CreateEvents` shall only be called in case an `pxIOManager` was successfully created. + +● `ff_ioman.c : FF_DeleteIOManager()` +Added a call to `FF_DeleteEvents()`, which will delete the event group belonging to the I/O manager. + +● `ff_ioman.c : FF_FlushCache()` +Added a user application hook per disk: `fnFlushApplicationHook()`. This is useful for e.g. NAND-drivers. + +● `ff_ioman.c : FF_Mount()` +Make sure that `pcVolumeLabel` is null-terminated. + +● `ff_ioman.c : FF_IncreaseFreeClusters()` +A lock is needed before `ulLastFreeCluster` can be changed. But before taking this lock, check if has already been taken to avoid a dead lock. + +● `ff_locking.c : FF_DeleteEvents` +This is a new function which deletes ( frees up ) the event group belonging to an I/O manager. + +● `ff_stdio.c : ff_filelength()` +This function will now call `FF_GetFileSize()` in order to get the `unsigned` length of a file, increasing the maximum reported size from 2 to 4 GB. + +● `ff_sys.c : *` +This module combines several I/O managers ( = disks ) into a single file system that starts with a root `"/"`. +All code has been re-written ( re-styled ) and re-tested. diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ReadMe.url b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ReadMe.url new file mode 100644 index 000000000..43238eb6a --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ReadMe.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,2 +[InternetShortcut] +URL=http://www.freertos.org/fat +IDList= diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_crc.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_crc.c new file mode 100644 index 000000000..74dc8e5d5 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_crc.c @@ -0,0 +1,256 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_crc.c + * @ingroup CRC + * + * @defgroup CRC CRC Checksums for Strings + * @brief Provides fast hashing functions. + * + **/ + +#include "ff_headers.h" + +/*static*/ const uint32_t crc32_table[ 256 ] = +{ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, + 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, + 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, + 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, + 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, + 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, + 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, + 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, + 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, + 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, + 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, + 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, + 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, + 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, + 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +uint32_t FF_GetCRC32( uint8_t *pbyData, uint32_t stLength ) +{ + + register uint32_t crc = 0xFFFFFFFF; + + while( stLength-- != 0 ) + { + crc = ( ( crc >> 8 ) & 0x00FFFFFF ) ^ crc32_table[ ( crc ^ *( pbyData++ ) ) & 0x000000FF ]; + } + + return crc ^ 0xFFFFFFFF; +} + + + + +static const uint8_t crc16_table_low[ 256 ] = +{ + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041, + 0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040, +}; + +static const uint8_t crc16_table_high[256] = +{ + 0x000, 0x0c0, 0x0c1, 0x001, 0x0c3, 0x003, 0x002, 0x0c2, + 0x0c6, 0x006, 0x007, 0x0c7, 0x005, 0x0c5, 0x0c4, 0x004, + 0x0cc, 0x00c, 0x00d, 0x0cd, 0x00f, 0x0cf, 0x0ce, 0x00e, + 0x00a, 0x0ca, 0x0cb, 0x00b, 0x0c9, 0x009, 0x008, 0x0c8, + 0x0d8, 0x018, 0x019, 0x0d9, 0x01b, 0x0db, 0x0da, 0x01a, + 0x01e, 0x0de, 0x0df, 0x01f, 0x0dd, 0x01d, 0x01c, 0x0dc, + 0x014, 0x0d4, 0x0d5, 0x015, 0x0d7, 0x017, 0x016, 0x0d6, + 0x0d2, 0x012, 0x013, 0x0d3, 0x011, 0x0d1, 0x0d0, 0x010, + 0x0f0, 0x030, 0x031, 0x0f1, 0x033, 0x0f3, 0x0f2, 0x032, + 0x036, 0x0f6, 0x0f7, 0x037, 0x0f5, 0x035, 0x034, 0x0f4, + 0x03c, 0x0fc, 0x0fd, 0x03d, 0x0ff, 0x03f, 0x03e, 0x0fe, + 0x0fa, 0x03a, 0x03b, 0x0fb, 0x039, 0x0f9, 0x0f8, 0x038, + 0x028, 0x0e8, 0x0e9, 0x029, 0x0eb, 0x02b, 0x02a, 0x0ea, + 0x0ee, 0x02e, 0x02f, 0x0ef, 0x02d, 0x0ed, 0x0ec, 0x02c, + 0x0e4, 0x024, 0x025, 0x0e5, 0x027, 0x0e7, 0x0e6, 0x026, + 0x022, 0x0e2, 0x0e3, 0x023, 0x0e1, 0x021, 0x020, 0x0e0, + 0x0a0, 0x060, 0x061, 0x0a1, 0x063, 0x0a3, 0x0a2, 0x062, + 0x066, 0x0a6, 0x0a7, 0x067, 0x0a5, 0x065, 0x064, 0x0a4, + 0x06c, 0x0ac, 0x0ad, 0x06d, 0x0af, 0x06f, 0x06e, 0x0ae, + 0x0aa, 0x06a, 0x06b, 0x0ab, 0x069, 0x0a9, 0x0a8, 0x068, + 0x078, 0x0b8, 0x0b9, 0x079, 0x0bb, 0x07b, 0x07a, 0x0ba, + 0x0be, 0x07e, 0x07f, 0x0bf, 0x07d, 0x0bd, 0x0bc, 0x07c, + 0x0b4, 0x074, 0x075, 0x0b5, 0x077, 0x0b7, 0x0b6, 0x076, + 0x072, 0x0b2, 0x0b3, 0x073, 0x0b1, 0x071, 0x070, 0x0b0, + 0x050, 0x090, 0x091, 0x051, 0x093, 0x053, 0x052, 0x092, + 0x096, 0x056, 0x057, 0x097, 0x055, 0x095, 0x094, 0x054, + 0x09c, 0x05c, 0x05d, 0x09d, 0x05f, 0x09f, 0x09e, 0x05e, + 0x05a, 0x09a, 0x09b, 0x05b, 0x099, 0x059, 0x058, 0x098, + 0x088, 0x048, 0x049, 0x089, 0x04b, 0x08b, 0x08a, 0x04a, + 0x04e, 0x08e, 0x08f, 0x04f, 0x08d, 0x04d, 0x04c, 0x08c, + 0x044, 0x084, 0x085, 0x045, 0x087, 0x047, 0x046, 0x086, + 0x082, 0x042, 0x043, 0x083, 0x041, 0x081, 0x080, 0x040, +}; + +/***************************************************************************** + * Description: Function to 16 bit CRC check a block of memory + + * + * Parameters: pbyData - Pointer to the source data + * stLength - The length to CRC + * + * Return value: The 16 bit CRC value + * + *****************************************************************************/ + +uint16_t FF_GetCRC16( uint8_t *pbyData, uint32_t stLength ) +{ + uint8_t bTableValue; + uint16_t wCRC = 0; + + while( stLength-- != 0 ) + { + bTableValue = ( uint8_t ) ( (wCRC & 0x00FF ) ^ *pbyData++ ); + wCRC = ( uint16_t ) ( ( ( crc16_table_high[ bTableValue ] ) << 8 ) + + ( crc16_table_low[ bTableValue ] ^ ( ( wCRC >> 8 ) & 0x00FF ) ) ); + } + + return wCRC; +} + + +static const uint8_t crc8_table[256] = +{ + 0, 94, 188, 226, 97, 63, 221, 131, + 194, 156, 126, 32, 163, 253, 31, 65, + 157, 195, 33, 127, 252, 162, 64, 30, + 95, 1, 227, 189, 62, 96, 130, 220, + 35, 125, 159, 193, 66, 28, 254, 160, + 225, 191, 93, 3, 128, 222, 60, 98, + 190, 224, 2, 92, 223, 129, 99, 61, + 124, 34, 192, 158, 29, 67, 161, 255, + 70, 24, 250, 164, 39, 121, 155, 197, + 132, 218, 56, 102, 229, 187, 89, 7, + 219, 133, 103, 57, 186, 228, 6, 88, + 25, 71, 165, 251, 120, 38, 196, 154, + 101, 59, 217, 135, 4, 90, 184, 230, + 167, 249, 27, 69, 198, 152, 122, 36, + 248, 166, 68, 26, 153, 199, 37, 123, + 58, 100, 134, 216, 91, 5, 231, 185, + 140, 210, 48, 110, 237, 179, 81, 15, + 78, 16, 242, 172, 47, 113, 147, 205, + 17, 79, 173, 243, 112, 46, 204, 146, + 211, 141, 111, 49, 178, 236, 14, 80, + 175, 241, 19, 77, 206, 144, 114, 44, + 109, 51, 209, 143, 12, 82, 176, 238, + 50, 108, 142, 208, 83, 13, 239, 177, + 240, 174, 76, 18, 145, 207, 45, 115, + 202, 148, 118, 40, 171, 245, 23, 73, + 8, 86, 180, 234, 105, 55, 213, 139, + 87, 9, 235, 181, 54, 104, 138, 212, + 149, 203, 41, 119, 244, 170, 72, 22, + 233, 183, 85, 11, 136, 214, 52, 106, + 43, 117, 151, 201, 74, 20, 246, 168, + 116, 42, 200, 150, 21, 75, 169, 247, + 182, 232, 10, 84, 215, 137, 107, 53 +}; + +/***************************************************************************** + * Description: Function to CRC check a block of memory + * + * Parameters: pbyData - Pointer to the source data + * stLength - The length to CRC + * + * Return value: The 8 bit CRC value + * + *****************************************************************************/ + +uint8_t FF_GetCRC8( uint8_t *pbyData, uint32_t stLength ) +{ + uint8_t byCRC = 0, byData; + while( stLength-- != 0 ) + { + byData = *pbyData++; + byCRC = crc8_table[ ( byCRC ^ byData ) ]; + } + + return byCRC; +} diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_dev_support.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_dev_support.c new file mode 100644 index 000000000..4aee325f5 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_dev_support.c @@ -0,0 +1,235 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "portable.h" + +#include "ff_headers.h" +#include "ff_devices.h" + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE( x ) ( int )( sizeof( x ) / sizeof( x )[ 0 ] ) +#endif + +#if( ffconfigDEV_SUPPORT == 0 ) + #error No use to include this module if ffconfigDEV_SUPPORT is disabled +#endif /* ffconfigDEV_SUPPORT == 0 */ + +struct SFileCache +{ + char pcFileName[16]; + uint32_t ulFileLength; + uint32_t ulFilePointer; +}; + +struct SFileCache xFiles[ 16 ]; + +enum eCACHE_ACTION +{ + eCACHE_LOOKUP, + eCACHE_ADD, + eCACHE_REMOVE, +}; + +const char pcDevicePath[] = ffconfigDEV_PATH; + +struct SFileCache *pxFindFile( const char *pcFname, enum eCACHE_ACTION eAction ) +{ +BaseType_t xIndex, xFreeIndex = -1; +struct SFileCache *pxResult = NULL; + + for( xIndex = 0; xIndex < ARRAY_SIZE( xFiles ); xIndex++ ) + { + if( xFiles[ xIndex ].pcFileName[ 0 ] == '\0' ) + { + if( xFreeIndex < 0 ) + { + xFreeIndex = xIndex; + } + } + else if( strcmp( xFiles[ xIndex ].pcFileName, pcFname ) == 0 ) + { + if( eAction == eCACHE_REMOVE ) + { + xFiles[ xIndex ].pcFileName[ 0 ] = '\0'; + } + + pxResult = xFiles + xIndex; + break; + } + } + + if( ( pxResult == NULL ) && ( eAction == eCACHE_ADD ) && ( xFreeIndex >= 0 ) ) + { + pxResult = xFiles + xFreeIndex; + snprintf( pxResult->pcFileName, sizeof( pxResult->pcFileName ), "%s", pcFname ); + pxResult->ulFileLength = 0; + pxResult->ulFilePointer = 0; + } + + return pxResult; +} + +BaseType_t xCheckDevicePath( const char *pcPath ) +{ +BaseType_t xDevLength; +BaseType_t xPathLength; +BaseType_t xIsDevice; + + xDevLength = sizeof( pcDevicePath ) - 1; + xPathLength = strlen( pcPath ); + + /* System "/dev" should not match with "/device/etc". */ + if( ( xPathLength >= xDevLength ) && + ( memcmp( pcDevicePath, pcPath, xDevLength ) == 0 ) && + ( ( pcPath[ xDevLength ] == '\0' ) || ( pcPath[ xDevLength ] == '/' ) ) ) + { + xIsDevice = FF_DEV_CHAR_DEV; + } + else + { + xIsDevice = FF_DEV_NO_DEV; + } + + return xIsDevice; +} + +BaseType_t FF_Device_Open( const char *pcPath, FF_FILE *pxStream ) +{ +uint8_t ucIsDevice; + + ucIsDevice = xCheckDevicePath( pcPath ); + if( ucIsDevice != pdFALSE ) + { + const char *pcBaseName = pcPath; + + if( memcmp( pcBaseName, pcDevicePath, sizeof( pcDevicePath ) - 1 ) == 0 ) + { + pcBaseName = pcBaseName + sizeof( pcDevicePath ); + } + + pxStream->pxDevNode = pxFindFile( pcBaseName, eCACHE_ADD ); + if( pxStream->pxDevNode != NULL ) + { + pxStream->pxDevNode->ulFilePointer = 0; + if( ( pxStream->ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE ) ) == 0 ) + { + pxStream->ulFileSize = pxStream->pxDevNode->ulFileLength; + } + } + } + + return ucIsDevice; +} + +void FF_Device_Close( FF_FILE * pxStream ) +{ + if( pxStream->pxDevNode != NULL ) + { + pxStream->ulFileSize = 0ul; + pxStream->ulFilePointer = 0ul; + } +} + +size_t FF_Device_Read( void *pvBuf, size_t lSize, size_t lCount, FF_FILE * pxStream ) +{ + lCount *= lSize; + return lCount; +} + +size_t FF_Device_Write( const void *pvBuf, size_t lSize, size_t lCount, FF_FILE * pxStream ) +{ + lCount *= lSize; + + if( pxStream->pxDevNode != NULL ) + { + + pxStream->pxDevNode->ulFilePointer += lCount; + if( pxStream->pxDevNode->ulFileLength < pxStream->pxDevNode->ulFilePointer ) + { + pxStream->pxDevNode->ulFileLength = pxStream->pxDevNode->ulFilePointer; + } + } + return lCount; +} + +int FF_Device_Seek( FF_FILE *pxStream, long lOffset, int iWhence ) +{ + if( pxStream->pxDevNode != NULL ) + { + if( iWhence == FF_SEEK_SET ) + { + pxStream->pxDevNode->ulFilePointer = lOffset; + } + else if( iWhence == FF_SEEK_END ) + { + pxStream->pxDevNode->ulFilePointer = pxStream->pxDevNode->ulFileLength - lOffset; + } + } + + return 0; +} + +int FF_Device_GetDirEnt( const char *pcPath, FF_DirEnt_t *pxDirEnt ) +{ +BaseType_t xIsDotDir = 0; + if( pxDirEnt->pcFileName[ 0 ] == '.' ) + { + if( ( pxDirEnt->pcFileName[ 1 ] == '.' ) && + ( pxDirEnt->pcFileName[ 2 ] == '\0' ) ) + { + xIsDotDir = 2; + } + else if( pxDirEnt->pcFileName[ 1 ] == '\0' ) + { + xIsDotDir = 1; + } + } + if( xIsDotDir == 0 ) + { + struct SFileCache *pxDevNode; + + pxDevNode = pxFindFile( pxDirEnt->pcFileName, eCACHE_LOOKUP ); + + pxDirEnt->ucIsDeviceDir = FF_DEV_CHAR_DEV; + if( pxDevNode != NULL ) + { + pxDirEnt->ulFileSize = pxDevNode->ulFileLength; + } + else if( pxDirEnt->ulFileSize < 2048 ) + { + pxDirEnt->ulFileSize = 2048; + } + } + + return 1024; +} + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_dir.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_dir.c new file mode 100644 index 000000000..77e491f6f --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_dir.c @@ -0,0 +1,3426 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_dir.c + * @ingroup DIR + * + * @defgroup DIR Handles Directory Traversal + * @brief Handles DIR access and traversal. + * + * Provides FindFirst() and FindNext() Interfaces + **/ + +#include "ff_headers.h" + +#include + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +#include +#endif + +#if defined( WIN32 ) + #define wcsicmp _wcsicmp +#else + #define wcsicmp wcscasecmp + #include +#endif + +/* Calculate a simple LFN checmsum. */ +static uint8_t FF_CreateChkSum( const uint8_t *pa_pShortName ); + +static BaseType_t FF_ShortNameExists( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, char *pcShortName, FF_Error_t *pxError ); + +#if( ffconfigSHORTNAME_CASE != 0 ) + /* For short-name entries, NT/XP etc store case information in byte 0x0c + * Use this to show proper case of "README.txt" or "source.H". + */ + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + static void FF_CaseShortName( FF_T_WCHAR *pcName, uint8_t attrib ); + #else + static void FF_CaseShortName( char *pcName, uint8_t attrib ); + #endif +#endif /* ffconfigSHORTNAME_CASE */ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + + /* For unicode, the short name can be expanded to wchar + * by inserting zero's. + */ + static void FF_ShortNameExpand( FF_T_WCHAR * ); + +#endif + +/* + * Transform a name as stored on disk "README__TXT" + * to a nul-terminated string: "README.TXT", "FILE001". + * A dot is only added if an extension is present. + */ +static void FF_ProcessShortName( char *pcName ); + +#if( ffconfigTIME_SUPPORT != 0 ) + static void FF_PlaceTime( uint8_t *pucEntryBuffer, uint32_t Offset, FF_SystemTime_t *pxTime ); + static void FF_PlaceDate( uint8_t *pucEntryBuffer, uint32_t Offset, FF_SystemTime_t *pxTime ); + static void FF_GetTime( FF_SystemTime_t *pxTime, const uint8_t *pucEntryBuffer, uint32_t ulOffset ); + static void FF_GetDate( FF_SystemTime_t *pxTime, const uint8_t *pucEntryBuffer, uint32_t ulOffset ); +#endif /* ffconfigTIME_SUPPORT */ +static FF_Error_t FF_Traverse( FF_IOManager_t *pxIOManager, uint32_t ulEntry, FF_FetchContext_t *pxContext ); +static int32_t FF_FindFreeDirent( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams, uint16_t usSequential ); + +#if( ffconfigLFN_SUPPORT != 0 ) + static int8_t FF_CreateLFNEntry( uint8_t *pucEntryBuffer, uint8_t *pcName, UBaseType_t uxNameLength, UBaseType_t uxLFN, uint8_t ucCheckSum ); +#endif /* ffconfigLFN_SUPPORT */ + +static BaseType_t FF_ValidShortChar( char cChar ); + +#if( ffconfigLFN_SUPPORT != 0 ) + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + static FF_Error_t FF_CreateLFNs( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, FF_T_WCHAR *pcName, uint8_t ucCheckSum, uint16_t usEntry ); + #else + static FF_Error_t FF_CreateLFNs( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, char *pcName, uint8_t ucCheckSum, uint16_t usEntry ); + #endif +#endif + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + static void FF_MakeNameCompliant( FF_T_WCHAR *pcName ); +#else + static void FF_MakeNameCompliant( char *pcName ); +#endif + +#if ( FF_NOSTRCASECMP == 0 ) + static portINLINE unsigned char prvToLower( unsigned char c ) + { + unsigned char cReturnChar; + if( c >= 'A' && c <= 'Z' ) + { + cReturnChar = c + 0x20; + } + else + { + cReturnChar = c; + } + + return cReturnChar; + } + + int strcasecmp( const char *pcString1, const char *pcString2 ) + { + unsigned char c1,c2; + do + { + c1 = *pcString1++; + c2 = *pcString2++; + c1 = ( unsigned char ) prvToLower( ( unsigned char ) c1 ); + c2 = ( unsigned char ) prvToLower( ( unsigned char ) c2 ); + } + while( ( c1 == c2 ) && ( c1 != '\0' ) ); + + return ( int ) c1 - c2; + } /* strcasecmp() */ +#endif +/*-----------------------------------------------------------*/ + +static uint8_t FF_CreateChkSum( const uint8_t *pa_pShortName ) +{ +uint8_t cNameLen; +uint8_t ChkSum = 0; + + for( cNameLen = 11; cNameLen != 0; cNameLen-- ) + { + ChkSum = ( uint8_t ) + ( ( ( ChkSum & 1 ) ? 0x80 : 0 ) + ( ChkSum >> 1 ) + *( pa_pShortName++ ) ); + } + + return ChkSum; +} /* FF_CreateChkSum() */ +/*-----------------------------------------------------------*/ + +/* _HT_ Does not need a wchar version because a short name is treated a normal string of bytes */ +static BaseType_t FF_ShortNameExists( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, char *pcShortName, FF_Error_t *pxError ) +{ +BaseType_t xIndex; +const uint8_t *pucEntryBuffer = NULL; /* initialisation not necessary, just for the compiler */ +uint8_t ucAttrib; +FF_FetchContext_t xFetchContext; +char pcMyShortName[ FF_SIZEOF_DIRECTORY_ENTRY ]; +BaseType_t xResult = -1; + +#if( ffconfigHASH_CACHE != 0 ) + uint32_t ulHash; +#endif + + *pxError = FF_ERR_NONE; + + #if( ffconfigHASH_CACHE != 0 ) + { + if( !FF_DirHashed( pxIOManager, ulDirCluster ) ) + { + /* Hash the directory. */ + FF_HashDir( pxIOManager, ulDirCluster ); + } + + #if ffconfigHASH_FUNCTION == CRC16 + { + ulHash = ( uint32_t ) FF_GetCRC16( ( uint8_t * ) pcShortName, strlen( pcShortName ) ); + } + #else /* ffconfigHASH_FUNCTION == CRC8 */ + { + ulHash = ( uint32_t ) FF_GetCRC8( ( uint8_t * ) pcShortName, strlen( pcShortName ) ); + } + #endif + { + /* FF_CheckDirentHash result: 0 not found, 1 found, -1 directory not hashed */ + xResult = FF_CheckDirentHash( pxIOManager, ulDirCluster, ulHash ); + } + } + #endif + + if( xResult < 0 ) + { + xResult = pdFALSE; + *pxError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext ); + + if( FF_isERR( *pxError ) == pdFALSE ) + { + for( xIndex = 0; xIndex < FF_MAX_ENTRIES_PER_DIRECTORY; xIndex++ ) + { + /* Call FF_FetchEntryWithContext only once for every 512-byte block */ + if( ( xIndex == 0 ) || + ( pucEntryBuffer >= xFetchContext.pxBuffer->pucBuffer + ( FF_SIZEOF_SECTOR - FF_SIZEOF_DIRECTORY_ENTRY ) ) ) + { + *pxError = FF_FetchEntryWithContext( pxIOManager, ( uint32_t ) xIndex, &xFetchContext, NULL ); + if( FF_isERR( *pxError ) ) + { + break; + } + pucEntryBuffer = xFetchContext.pxBuffer->pucBuffer; + } + else + { + /* Advance 32 bytes to get the next directory entry. */ + pucEntryBuffer += FF_SIZEOF_DIRECTORY_ENTRY; + } + + if( FF_isEndOfDir( pucEntryBuffer ) ) + { + break; + } + if( FF_isDeleted( pucEntryBuffer ) == pdFALSE ) + { + ucAttrib = FF_getChar( pucEntryBuffer, FF_FAT_DIRENT_ATTRIB ); + if( ( ucAttrib & FF_FAT_ATTR_LFN ) != FF_FAT_ATTR_LFN ) + { + memcpy( pcMyShortName, pucEntryBuffer, sizeof( pcMyShortName ) ); + FF_ProcessShortName( pcMyShortName ); + if( strcmp( ( const char * )pcShortName, ( const char * )pcMyShortName ) == 0 ) + { + xResult = pdTRUE; + break; + } + } + } + } /* for ( xIndex = 0; xIndex < FF_MAX_ENTRIES_PER_DIRECTORY; xIndex++ ) */ + } + *pxError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + } + + return xResult; +} /* FF_ShortNameExists() */ +/*-----------------------------------------------------------*/ + +/* _HT_ When adding many files to a single directory, FF_FindEntryInDir was sometimes */ +/* _HT_ called 3 times before inserting a single file. With these changes it is called one time only */ +/* _HT_ pxFindParams caches some information: */ +/* _HT_ 1: the first free entry 2: whether the short-name version already exists */ +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +uint32_t FF_FindEntryInDir( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams, const FF_T_WCHAR *pcName, uint8_t pa_Attrib, FF_DirEnt_t *pxDirEntry, FF_Error_t *pxError ) +#else +uint32_t FF_FindEntryInDir( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams, const char *pcName, uint8_t pa_Attrib, FF_DirEnt_t *pxDirEntry, FF_Error_t *pxError ) +#endif +{ +FF_FetchContext_t xFetchContext; +/* const pointer to read from pBuffer */ +const uint8_t *src = NULL; +/* As we're walking through a directory, we might as well +find the first free entry to help FF_FindFreeDirent( ) +The result will be stored in 'pxFindParams->lFreeEntry' */ +BaseType_t entriesNeeded; +BaseType_t freeCount = 0; +FF_Error_t xError; +/* If the file name fits into a short file name +then the existence of that short file name will be checked as well. */ +BaseType_t testShortname; +uint32_t xResult = 0ul; +#if( ffconfigUNICODE_UTF8_SUPPORT == 1 ) + int32_t utf8Error; +#endif + +#if( ffconfigLFN_SUPPORT != 0 ) + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_T_WCHAR *pcCurPtr; /* Pointer to store a LFN. */ + FF_T_WCHAR *pcLastPtr = pxDirEntry->pcFileName + sizeof( pxDirEntry->pcFileName ); + #else + char *pcCurPtr; /* Pointer to store a LFN. */ + char *pcLastPtr = pxDirEntry->pcFileName + sizeof( pxDirEntry->pcFileName ); + #endif /* ffconfigUNICODE_UTF16_SUPPORT */ + + uint16_t lfnItem = 0; + uint8_t ucCheckSum = 0; + BaseType_t xLFNCount = 0; + BaseType_t xLFNTotal = 0; + uint8_t lastAttrib; + + BaseType_t xIndex; +#endif /* ffconfigLFN_SUPPORT */ + + #if( ffconfigLFN_SUPPORT != 0 ) + { + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + BaseType_t NameLen = ( BaseType_t ) wcslen( ( const char * )pcName ); + #else + BaseType_t NameLen = ( BaseType_t ) strlen( ( const char * )pcName ); + #endif + /* Find enough places for the LFNs and the ShortName. */ + entriesNeeded = ( uint8_t )( ( NameLen + 12 ) / 13 ) + 1; + } + #else + { + entriesNeeded = 1; + } + #endif /* ffconfigLFN_SUPPORT */ + + if( ( pxFindParams->ulFlags & FIND_FLAG_FITS_SHORT_OK ) == FIND_FLAG_FITS_SHORT_OK ) + { + testShortname = pdTRUE; + } + else + { + testShortname = pdFALSE; + } + + pxDirEntry->ucAttrib = 0; + + if( ( pxFindParams->ulFlags & FIND_FLAG_CREATE_FLAG ) != 0 ) + { + /* A file is to be created: keep track of the first free entry big enough + to hold this file name. */ + pxFindParams->lFreeEntry = -1; + } + else + { + pxFindParams->lFreeEntry = 0; + } + + xError = FF_InitEntryFetch( pxIOManager, pxFindParams->ulDirCluster, &xFetchContext ); + + if( FF_isERR( xError ) == pdFALSE ) + { + for( pxDirEntry->usCurrentItem = 0; pxDirEntry->usCurrentItem < FF_MAX_ENTRIES_PER_DIRECTORY; pxDirEntry->usCurrentItem++ ) + { + if( ( src == NULL ) || + ( src >= xFetchContext.pxBuffer->pucBuffer + ( FF_SIZEOF_SECTOR - FF_SIZEOF_DIRECTORY_ENTRY ) ) ) + { + xError = FF_FetchEntryWithContext( pxIOManager, pxDirEntry->usCurrentItem, &xFetchContext, NULL ); + + if( FF_isERR( xError ) != pdFALSE ) + { + break; + } + src = xFetchContext.pxBuffer->pucBuffer; + } + else + { + /* Advance 32 bytes. */ + src += FF_SIZEOF_DIRECTORY_ENTRY; + } + + if( FF_isEndOfDir( src ) ) + { + /* 0x00 end-of-dir. */ + break; + } + + if( FF_isDeleted( src ) ) + { + /* Entry not used or deleted. */ + pxDirEntry->ucAttrib = 0; + if( ( pxFindParams->lFreeEntry < 0 ) && ( ++freeCount == entriesNeeded ) ) + { + /* Remember the beginning entry in the sequential sequence. */ + pxFindParams->lFreeEntry = ( pxDirEntry->usCurrentItem - ( entriesNeeded - 1 ) ); + } + continue; + } + + /* The current entry is in use, so reset the free-entry-counter */ + freeCount = 0; + #if( ffconfigLFN_SUPPORT != 0 ) + { + lastAttrib = pxDirEntry->ucAttrib; + } + #endif + + pxDirEntry->ucAttrib = FF_getChar( src, FF_FAT_DIRENT_ATTRIB ); + + if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_LFN ) == FF_FAT_ATTR_LFN ) + { + /* LFN Processing. */ + #if( ffconfigLFN_SUPPORT != 0 ) + { + if( ( xLFNCount == 0 ) || ( lastAttrib & FF_FAT_ATTR_LFN ) != FF_FAT_ATTR_LFN ) + { + xLFNTotal = xLFNCount = ( BaseType_t )( src[ 0 ] & ~0x40 ); + lfnItem = pxDirEntry->usCurrentItem; + ucCheckSum = FF_getChar( src, FF_FAT_LFN_CHECKSUM ); + pcLastPtr[ -1 ] = '\0'; + } + + if( xLFNCount != 0 ) + { + xLFNCount--; + pcCurPtr = pxDirEntry->pcFileName + ( xLFNCount * 13 ); + + /* + This section needs to extract the name and do the comparison + dependent on UNICODE settings in the FreeRTOSFATConfig.h file. + */ + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + { + /* Add UTF-16 Routine here. */ + /* Copy first 5 UTF-16 chars ( 10 bytes ). */ + memcpy( pcCurPtr, &src[ FF_FAT_LFN_NAME_1 ], 10 ); + /* Increment Filename pointer 5 utf16 chars. */ + pcCurPtr += 5; + + /* Copy next 6 chars ( 12 bytes ). */ + memcpy( pcCurPtr, &src[ FF_FAT_LFN_NAME_2 ], 12 ); + pcCurPtr += 6; + + /* You're getting the idea by now! */ + memcpy( pcCurPtr, &src[ FF_FAT_LFN_NAME_3 ], 4 ); + pcCurPtr += 2; + } /* ffconfigUNICODE_UTF16_SUPPORT */ + #elif( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + { + /* UTF-8 Routine here. */ + for( xIndex = 0; ( xIndex < 5 ) && ( pcCurPtr < pcLastPtr ); xIndex++ ) + { + /* Was there a surrogate sequence? -- Add handling here. */ + utf8Error = FF_Utf16ctoUtf8c( ( uint8_t * ) pcCurPtr, ( uint16_t * ) &src[ FF_FAT_LFN_NAME_1 + ( 2 * xIndex ) ], pcLastPtr - pcCurPtr ); + if( utf8Error > 0 ) + { + pcCurPtr += utf8Error; + } + else + { + if( FF_GETERROR( utf8Error ) == FF_ERR_UNICODE_INVALID_SEQUENCE ) + { + /* Handle potential surrogate sequence across entries. */ + } + } + } + + for( xIndex = 0; xIndex < 6 && pcCurPtr < pcLastPtr; xIndex++ ) + { + /* Was there a surrogate sequence? -- To add handling here. */ + utf8Error = FF_Utf16ctoUtf8c( ( uint8_t * ) pcCurPtr, ( uint16_t * ) &src[ FF_FAT_LFN_NAME_2 + ( 2 * xIndex ) ], pcLastPtr - pcCurPtr ); + if( utf8Error > 0 ) + { + pcCurPtr += utf8Error; + } + else + { + if( FF_GETERROR( utf8Error ) == FF_ERR_UNICODE_INVALID_SEQUENCE ) + { + /* Handle potential surrogate sequence across entries. */ + } + } + } + + for( xIndex = 0; xIndex < 2 && pcCurPtr < pcLastPtr; xIndex++ ) + { + /* Was there a surrogate sequence? -- To add handling here. */ + utf8Error = FF_Utf16ctoUtf8c( ( uint8_t * ) pcCurPtr, ( uint16_t * ) &src[ FF_FAT_LFN_NAME_3 + ( 2 * xIndex ) ], pcLastPtr - pcCurPtr ); + if( utf8Error > 0 ) + { + pcCurPtr += utf8Error; + } + else + { + if( FF_GETERROR( utf8Error ) == FF_ERR_UNICODE_INVALID_SEQUENCE ) + { + /* Handle potential surrogate sequence across entries. */ + } + } + } + } /* ffconfigUNICODE_UTF8_SUPPORT */ + #else + { /* use ASCII notation. */ + for( xIndex = 0; ( xIndex < 10 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 ) + { + *( pcCurPtr++ ) = src[ FF_FAT_LFN_NAME_1 + xIndex ]; + } + for( xIndex = 0; ( xIndex < 12 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 ) + { + *( pcCurPtr++ ) = src[ FF_FAT_LFN_NAME_2 + xIndex ]; + } + + for( xIndex = 0; ( xIndex < 4 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 ) + { + *( pcCurPtr++ ) = src[ FF_FAT_LFN_NAME_3 + xIndex ]; + } + } + #endif /* ( ffconfigUNICODE_UTF16_SUPPORT == 0 ) && !( ffconfigUNICODE_UTF8_SUPPORT == 0 ) */ + if( ( xLFNCount == xLFNTotal - 1 ) && ( pcCurPtr < pcLastPtr ) ) + { + *pcCurPtr = '\0'; /* Important when name len is multiple of 13. */ + } + } /* if( xLFNCount ) */ + } + #endif /* ffconfigLFN_SUPPORT */ + continue; + } + + if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_VOLID ) == FF_FAT_ATTR_VOLID ) + { + #if( ffconfigLFN_SUPPORT != 0 ) + { + xLFNTotal = 0; + } + #endif /* ffconfigLFN_SUPPORT */ + continue; + } + + #if( ffconfigLFN_SUPPORT != 0 ) + if( ( xLFNTotal == 0 ) || ( ucCheckSum != FF_CreateChkSum( src ) ) ) + #endif /* ffconfigLFN_SUPPORT */ + { + /* This entry has only a short name, or the checksum isn't correct + * Use the short name for comparison */ + memcpy( pxDirEntry->pcFileName, src, 11 ); + FF_ProcessShortName( ( char * ) pxDirEntry->pcFileName ); + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + { + /* FileName now contains a 8-bit short name + Expand it to a FF_T_WCHAR string. */ + FF_ShortNameExpand( pxDirEntry->pcFileName ); + } + #endif /* ffconfigUNICODE_UTF16_SUPPORT */ + #if( ffconfigLFN_SUPPORT != 0) + { + xLFNTotal = 0; + } + #endif /* ffconfigLFN_SUPPORT */ + } + + /* This function FF_FindEntryInDir( ) is either called with + * pa_Attrib==0 or with pa_Attrib==FF_FAT_ATTR_DIR + * In the last case the caller is looking for a directory */ + if( ( pxDirEntry->ucAttrib & pa_Attrib ) == pa_Attrib ) + { + if( testShortname ) + { + /* Both strings are stored in the directory format + * e.g. "README TXT", without a dot */ + if( memcmp( src, pxFindParams->pcEntryBuffer, 11 ) == 0 ) + { + pxFindParams->ulFlags |= FIND_FLAG_SHORTNAME_CHECKED | FIND_FLAG_SHORTNAME_FOUND; + } + } + + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + if( wcsicmp( ( const char * )pcName, ( const char * )pxDirEntry->pcFileName ) == 0 ) + #else + if( FF_stricmp( ( const char * )pcName, ( const char * )pxDirEntry->pcFileName ) == 0 ) + #endif /* ffconfigUNICODE_UTF16_SUPPORT */ + { + /* Finally get the complete information. */ + #if( ffconfigLFN_SUPPORT != 0 ) + if( xLFNTotal ) + { + xError = FF_PopulateLongDirent( pxIOManager, pxDirEntry, ( uint16_t ) lfnItem, &xFetchContext ); + if( FF_isERR( xError ) ) + { + break; + } + } + else + #endif /* ffconfigLFN_SUPPORT */ + { + FF_PopulateShortDirent( pxIOManager, pxDirEntry, src ); + /* HT: usCurrentItem wasn't increased here. */ + pxDirEntry->usCurrentItem++; + } + /* Object found, the cluster number will be returned. */ + xResult = pxDirEntry->ulObjectCluster; + break; + } + } + #if( ffconfigLFN_SUPPORT != 0 ) + { + xLFNTotal = 0; + } + #endif + } /* for( ; pxDirEntry->usCurrentItem < FF_MAX_ENTRIES_PER_DIRECTORY; pxDirEntry->usCurrentItem++ ) */ + + { + FF_Error_t xTempError; + xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + } /* if( FF_isERR( xError ) == pdFALSE ) */ + + if( FF_isERR( xError ) == pdFALSE ) + { + /* If a free entry wasn't found yet, put it to the current (last) item */ + if( pxFindParams->lFreeEntry < 0 ) + { + pxFindParams->lFreeEntry = pxDirEntry->usCurrentItem; + } + + /* If we were checking the existence of the short-name + set the Checked flag now */ + if( testShortname ) + { + pxFindParams->ulFlags |= FIND_FLAG_SHORTNAME_CHECKED; + } + } + + if( pxError != NULL ) + { + *pxError = xError; + } + + return xResult; +} /* FF_FindEntryInDir() */ +/*-----------------------------------------------------------*/ + + +/** + * @private + **/ +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +uint32_t FF_FindDir( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *pcPath, uint16_t pathLen, FF_Error_t *pxError ) +#else +uint32_t FF_FindDir( FF_IOManager_t *pxIOManager, const char *pcPath, uint16_t pathLen, FF_Error_t *pxError ) +#endif +{ +uint16_t it = 0; /* Re-entrancy Variables for FF_strtok( ). */ +BaseType_t last = pdFALSE; +FF_DirEnt_t xMyDirectory; +FF_FindParams_t xFindParams; +FF_Error_t xError; +BaseType_t xFound; + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_T_WCHAR mytoken[ ffconfigMAX_FILENAME ]; + FF_T_WCHAR *token; +#else + char mytoken[ ffconfigMAX_FILENAME ]; + char *pcToken; +#endif + +#if( ffconfigPATH_CACHE != 0 ) + BaseType_t xIndex; +#endif + + memset( &xFindParams, '\0', sizeof( xFindParams ) ); + xFindParams.ulDirCluster = pxIOManager->xPartition.ulRootDirCluster; + + xError = FF_ERR_NONE; + + if( pathLen <= 1 ) + { + /* Must be the root directory. + 'xFindParams.ulDirCluster' will be returned containing 'pxIOManager->xPartition.ulRootDirCluster'. */ + xFound = pdTRUE; + } + else + { + /* Only the root directory '/' shall have a trailing slash in its name. */ + if( ( pcPath[ pathLen - 1 ] == '\\' ) || ( pcPath[ pathLen - 1 ] == '/' ) ) + { + pathLen--; + } + xFound = pdFALSE; + + #if( ffconfigPATH_CACHE != 0 ) /* Is the requested pcPath in the PATH CACHE? */ + { + FF_PendSemaphore( pxIOManager->pvSemaphore ); /* Thread safety on shared object! */ + { + for( xIndex = 0; xIndex < ffconfigPATH_CACHE_DEPTH; xIndex++ ) + { + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + if( wcslen( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath ) == ( size_t )pathLen ) + #else + if( strlen( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath ) == ( size_t )pathLen ) + #endif + { + if( FF_strmatch( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath, pcPath, pathLen ) ) + { + xFindParams.ulDirCluster = pxIOManager->xPartition.pxPathCache[ xIndex ].ulDirCluster; + xFound = pdTRUE; + break; + } + } + } + } + FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + } + #endif /* ffconfigPATH_CACHE */ + } + if( xFound == pdFALSE ) + { + pcToken = FF_strtok( pcPath, mytoken, &it, &last, pathLen ); + + do + { + xMyDirectory.usCurrentItem = 0; + xFindParams.ulDirCluster = FF_FindEntryInDir( pxIOManager, &xFindParams, pcToken, ( uint8_t ) FF_FAT_ATTR_DIR, &xMyDirectory, &xError ); + + if( xFindParams.ulDirCluster == 0ul ) + { + break; + } + + pcToken = FF_strtok( pcPath, mytoken, &it, &last, pathLen ); + + } while( pcToken != NULL ); + if( ( pcToken != NULL ) && + ( ( FF_isERR( xError ) == pdFALSE ) || ( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR ) ) ) + { + xError = ( FF_Error_t ) ( FF_FINDDIR | FF_ERR_FILE_INVALID_PATH ); + } + #if( ffconfigPATH_CACHE != 0 ) /* Update the PATH CACHE with a new PATH. */ + { + /* Only cache if the dir was actually found! */ + if( ( FF_isERR( xError ) == pdFALSE ) && ( xFindParams.ulDirCluster != 0ul ) ) + { + FF_PendSemaphore( pxIOManager->pvSemaphore ); + { + if( pathLen < ffconfigMAX_FILENAME ) /* Ensure the PATH won't cause a buffer overrun. */ + { + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + { + memcpy( pxIOManager->xPartition.pxPathCache[ pxIOManager->xPartition.ulPCIndex ].pcPath, pcPath, pathLen * sizeof( FF_T_WCHAR ) ); + } + #else + { + memcpy( pxIOManager->xPartition.pxPathCache[ pxIOManager->xPartition.ulPCIndex ].pcPath, pcPath, pathLen ); + } + #endif + + pxIOManager->xPartition.pxPathCache[ pxIOManager->xPartition.ulPCIndex ].pcPath[ pathLen ] = '\0'; + pxIOManager->xPartition.pxPathCache[ pxIOManager->xPartition.ulPCIndex ].ulDirCluster = xFindParams.ulDirCluster; + + pxIOManager->xPartition.ulPCIndex += 1; + if( pxIOManager->xPartition.ulPCIndex >= ffconfigPATH_CACHE_DEPTH ) + { + pxIOManager->xPartition.ulPCIndex = 0; + } + } + } + FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + } + } + #endif /* ffconfigPATH_CACHE */ + } /* if( pathLen > 1 ) */ + + if( pxError != NULL ) + { + *pxError = xError; + } + + return xFindParams.ulDirCluster; +} /* FF_FindDir() */ +/*-----------------------------------------------------------*/ + + +#if( ffconfigSHORTNAME_CASE != 0 ) + /** + * @private + * For short-name entries, NT/XP etc store case information in byte 0x0c + * Use this to show proper case of "README.txt" or "source.H" + **/ + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + static void FF_CaseShortName( FF_T_WCHAR *pcName, uint8_t attrib ) + #else + static void FF_CaseShortName( char *pcName, uint8_t attrib ) + #endif + { + uint8_t testAttrib = FF_FAT_CASE_ATTR_BASE; + + for ( ; *pcName != '\0'; pcName++ ) + { + if( *pcName == '.' ) + { + testAttrib = FF_FAT_CASE_ATTR_EXT; + } + else if ( ( attrib & testAttrib ) != 0 ) + { + if( ( *pcName >= 'A' ) && ( *pcName <= 'Z' ) ) + { + *pcName += 0x20; + } + } + else if( ( *pcName >= 'a' ) && ( *pcName <= 'z' ) ) + { + *pcName -= 0x20; + } + } + } +#endif /* ffconfigSHORTNAME_CASE */ +/*-----------------------------------------------------------*/ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + /** + * @private + * Expand a short-name, adding a zero after each character + **/ + + static void FF_ShortNameExpand( FF_T_WCHAR *pFileName ) + { + int8_t *pSource = ( ( int8_t * ) pFileName ) + 13; + int8_t *pTarget = ( ( int8_t * ) pFileName ) + 26; + /* "aaaaaaaa.eee": 12 characters plus a zero makes 13 + * Copy from the right to the left */ + while( pTarget > ( int8_t * ) pFileName ) + { + pTarget[ -1 ] = 0; + pTarget[ -2 ] = *( --pSource ); + pTarget -= 2; + } + } +#endif /* ffconfigUNICODE_UTF16_SUPPORT */ +/*-----------------------------------------------------------*/ + +/** + * @private + **/ + +static void FF_ProcessShortName( char *pcName ) +{ + char pcShortName[ 13 ]; + char *pcTarget = pcName; + int iSource; + memcpy( pcShortName, pcName, 11 ); + + for( iSource = 0; iSource < 11; iSource++ ) + { + if( pcShortName[ iSource ] == 0x20 ) + { + if( iSource >= 8 ) + { + break; + } + iSource = 7; + } + else + { + if( iSource == 8 ) + { + *( pcTarget++ ) = '.'; + } + *( pcTarget++ ) = pcShortName[ iSource ]; + } + } + *pcTarget = '\0'; +} +/*-----------------------------------------------------------*/ + + +#if( ffconfigTIME_SUPPORT != 0 ) + static void FF_PlaceTime( uint8_t *pucEntryBuffer, uint32_t Offset, FF_SystemTime_t *pxTime ) + { + uint16_t myShort; + + /* HT time changes: + E.g. Unzip needs to use original time rather than + the result of FF_GetSystemTime */ + + myShort = 0; + myShort |= ( ( pxTime->Hour << 11 ) & 0xF800 ); + myShort |= ( ( pxTime->Minute << 5 ) & 0x07E0 ); + myShort |= ( ( pxTime->Second / 2 ) & 0x001F ); + FF_putShort( pucEntryBuffer, ( uint16_t ) Offset, myShort ); + } +#endif /* ffconfigTIME_SUPPORT */ +/*-----------------------------------------------------------*/ + + +#if( ffconfigTIME_SUPPORT != 0 ) + static void FF_PlaceDate( uint8_t *pucEntryBuffer, uint32_t Offset, FF_SystemTime_t *pxTime ) + { + uint16_t myShort; + + /* HT time changes: + Unzip needs to use original date rather than + the current date, so make it a parameter. */ + myShort = 0; + myShort |= ( ( ( pxTime->Year- 1980 ) << 9 ) & 0xFE00 ) ; + myShort |= ( ( pxTime->Month << 5 ) & 0x01E0 ); + myShort |= ( pxTime->Day & 0x001F ); + FF_putShort( pucEntryBuffer, ( uint16_t ) Offset, myShort ); + } +#endif /* ffconfigTIME_SUPPORT */ +/*-----------------------------------------------------------*/ + + +#if( ffconfigTIME_SUPPORT != 0 ) + static void FF_GetTime( FF_SystemTime_t *pxTime, const uint8_t *pucEntryBuffer, uint32_t Offset ) + { + uint16_t myShort; + myShort = FF_getShort( pucEntryBuffer, ( uint16_t ) Offset ); + pxTime->Hour = ( ( ( myShort & 0xF800 ) >> 11 ) & 0x001F ); + pxTime->Minute = ( ( ( myShort & 0x07E0 ) >> 5 ) & 0x003F ); + pxTime->Second = 2 * ( myShort & 0x01F ); + } +#endif /* ffconfigTIME_SUPPORT */ +/*-----------------------------------------------------------*/ + + +#if( ffconfigTIME_SUPPORT != 0 ) + static void FF_GetDate( FF_SystemTime_t *pxTime, const uint8_t *pucEntryBuffer, uint32_t Offset ) + { + uint16_t myShort; + myShort = FF_getShort( pucEntryBuffer, ( uint16_t ) Offset ); + pxTime->Year = 1980 + ( ( ( myShort & 0xFE00 ) >> 9 ) & 0x07F ); + pxTime->Month = ( ( ( myShort & 0x01E0 ) >> 5 ) & 0x000F ); + pxTime->Day = myShort & 0x01F; + } +#endif /* ffconfigTIME_SUPPORT */ +/*-----------------------------------------------------------*/ + +void FF_PopulateShortDirent( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirEntry, const uint8_t *pucEntryBuffer ) +{ + memcpy( pxDirEntry->pcFileName, pucEntryBuffer, 11 ); /* Copy the filename into the Dirent object. */ +#if( ffconfigLFN_SUPPORT != 0 ) && ( ffconfigINCLUDE_SHORT_NAME != 0 ) + memcpy( pxDirEntry->pcShortName, pucEntryBuffer, 11 ); + pxDirEntry->pcShortName[ 11 ] = '\0'; + FF_ProcessShortName( pxDirEntry->pcShortName ); /* For debuggers only. */ +#endif + FF_ProcessShortName( ( char * ) pxDirEntry->pcFileName ); /* Format the shortname, for pleasant viewing. */ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + /* FileName contains a 8-bit short name + * Expand it to a FF_T_WCHAR string */ + FF_ShortNameExpand( pxDirEntry->pcFileName ); +#endif + + ( void )pxIOManager; /* Silence a compiler warning, about not referencing pxIOManager. */ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_tolower( pxDirEntry->pcFileName, ( uint32_t )wcslen( pxDirEntry->pcFileName ) ); +#else + FF_tolower( pxDirEntry->pcFileName, ( uint32_t )strlen( pxDirEntry->pcFileName ) ); +#endif + + /* Get the item's Cluster address. */ + pxDirEntry->ulObjectCluster = + ( ( uint32_t )FF_getShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH ) << 16 ) | + ( uint32_t )FF_getShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW ); +#if( ffconfigTIME_SUPPORT != 0 ) + /* Get the creation Time & Date. */ + FF_GetTime( &pxDirEntry->xCreateTime, pucEntryBuffer, FF_FAT_DIRENT_CREATE_TIME ); + FF_GetDate( &pxDirEntry->xCreateTime, pucEntryBuffer, FF_FAT_DIRENT_CREATE_DATE ); + /* Get the modified Time & Date + HT Here xCreateTime became xModifiedTime: */ + FF_GetTime( &pxDirEntry->xModifiedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME ); + FF_GetDate( &pxDirEntry->xModifiedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE ); + /* Get the last accessed Date. */ + FF_GetDate( &pxDirEntry->xAccessedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTACC_DATE ); + pxDirEntry->xAccessedTime.Hour = 0; + pxDirEntry->xAccessedTime.Minute = 0; + pxDirEntry->xAccessedTime.Second = 0; +#endif + /* Get the filesize. */ + pxDirEntry->ulFileSize = FF_getLong( pucEntryBuffer, ( uint16_t )( FF_FAT_DIRENT_FILESIZE ) ); + /* Get the attribute. */ + pxDirEntry->ucAttrib = FF_getChar( pucEntryBuffer, ( uint16_t )( FF_FAT_DIRENT_ATTRIB ) ); +} +/*-----------------------------------------------------------*/ + + +/* Initialises a context object for FF_FetchEntryWithContext( */ +FF_Error_t FF_InitEntryFetch( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, FF_FetchContext_t *pxContext ) +{ + FF_Error_t xError; + + memset( pxContext, 0, sizeof( FF_FetchContext_t ) ); + + /* Get the total length of the chain. */ + pxContext->ulChainLength = FF_GetChainLength( pxIOManager, ulDirCluster, NULL, &xError ); + + if( FF_isERR( xError ) == pdFALSE ) + { + pxContext->ulDirCluster = ulDirCluster; + pxContext->ulCurrentClusterLCN = ulDirCluster; + + if( pxIOManager->xPartition.ucType != FF_T_FAT32 ) + { + /* Handle Root Dirs that don't have cluster chains! */ + if( pxContext->ulDirCluster == pxIOManager->xPartition.ulRootDirCluster ) + { + /* This is a RootDIR, special consideration needs to be made, because it doesn't have a Cluster chain! */ + pxContext->ulChainLength = pxIOManager->xPartition.ulRootDirSectors / pxIOManager->xPartition.ulSectorsPerCluster; + if( pxContext->ulChainLength == 0 ) /* Some media has ulRootDirSectors < ulSectorsPerCluster. This is wrong, as it should be atleast 1 cluster! */ + { + pxContext->ulChainLength = 1; + } + } + } + } + + return xError; +} /* FF_InitEntryFetch() */ +/*-----------------------------------------------------------*/ + +FF_Error_t FF_CleanupEntryFetch( FF_IOManager_t *pxIOManager, FF_FetchContext_t *pxContext ) +{ + FF_Error_t xError = FF_ERR_NONE; + if( pxContext->pxBuffer ) + { + xError = FF_ReleaseBuffer( pxIOManager, pxContext->pxBuffer ); + pxContext->pxBuffer = NULL; + } + + return xError; +} /* FF_CleanupEntryFetch() */ +/*-----------------------------------------------------------*/ + +/** + * @private + * @brief Find the cluster for a given Entry within a directory + * @brief Make an exception for the root directory ( non FAT32 only ): + * @brief Just calculate the cluster ( don't consult the actual FAT ) + * + * @param pxIOManager FF_IOManager_t object that was created by FF_CreateIOManger( ). + * @param ulEntry The sequence number of the entry of interest + * @param pxContext Context of current search + * + * @Return FF_ERR_NONE on success + * @Return Possible error returned by FF_TraverseFAT( ) or END_OF_DIR + * + * Side effects: + * - pxContext->ulCurrentClusterNum : relative cluster number ( 0 <= Num < ulChainLength ) + * - pxContext->ulCurrentClusterLCN : fysical cluster on the partition + **/ + +static FF_Error_t FF_Traverse( FF_IOManager_t *pxIOManager, uint32_t ulEntry, FF_FetchContext_t *pxContext ) +{ +uint32_t ulClusterNum = FF_getClusterChainNumber( pxIOManager, ulEntry, ( uint16_t ) FF_SIZEOF_DIRECTORY_ENTRY ); +FF_Error_t xError = FF_ERR_NONE; + + /* Check if we're past the last cluster ( ulChainLength is also valid for root sectors ). */ + if( ( ulClusterNum + 1 ) > pxContext->ulChainLength ) + { + xError = FF_ERR_DIR_END_OF_DIR | FF_TRAVERSE; /* End of Dir was reached! */ + } + else if( ( pxIOManager->xPartition.ucType != FF_T_FAT32 ) && + ( pxContext->ulDirCluster == pxIOManager->xPartition.ulRootDirCluster ) ) + { + /* Double-check if the entry number isn't too high. */ + if( ulEntry > ( ( pxIOManager->xPartition.ulRootDirSectors * pxIOManager->xPartition.usBlkSize ) / FF_SIZEOF_DIRECTORY_ENTRY ) ) + { + xError = ( FF_Error_t ) ( FF_ERR_DIR_END_OF_DIR | FF_FETCHENTRYWITHCONTEXT ); + } + else + { + pxContext->ulCurrentClusterLCN = pxContext->ulDirCluster; + } + } + else if( ulClusterNum != pxContext->ulCurrentClusterNum ) + { + /* Traverse the fat gently! */ + if( ulClusterNum > pxContext->ulCurrentClusterNum ) + { + /* Start traverse from the current entry. */ + pxContext->ulCurrentClusterLCN = FF_TraverseFAT( pxIOManager, pxContext->ulCurrentClusterLCN, ( ulClusterNum - pxContext->ulCurrentClusterNum ), &xError ); + } + else + { + /* Start traverse from the beginning. */ + pxContext->ulCurrentClusterLCN = FF_TraverseFAT( pxIOManager, pxContext->ulDirCluster, ulClusterNum, &xError ); + } + } + if( FF_isERR( xError ) == pdFALSE ) + { + pxContext->ulCurrentClusterNum = ulClusterNum; + } + + return xError; +} /* FF_Traverse() */ +/*-----------------------------------------------------------*/ + +FF_Error_t FF_FetchEntryWithContext( FF_IOManager_t *pxIOManager, uint32_t ulEntry, FF_FetchContext_t *pxContext, uint8_t *pEntryBuffer ) +{ + uint32_t ulItemLBA; + uint32_t ulRelItem; + FF_Error_t xError; + + xError = FF_Traverse( pxIOManager, ulEntry, pxContext ); + + if( FF_isERR( xError ) == pdFALSE ) + { + ulRelItem = FF_getMinorBlockEntry ( pxIOManager, ulEntry, ( uint32_t )FF_SIZEOF_DIRECTORY_ENTRY ); + + ulItemLBA = FF_Cluster2LBA ( pxIOManager, pxContext->ulCurrentClusterLCN ) + + FF_getMajorBlockNumber( pxIOManager, ulEntry, ( uint32_t ) FF_SIZEOF_DIRECTORY_ENTRY ); + if( ( pxIOManager->xPartition.ucType != FF_T_FAT32 ) && + ( pxContext->ulDirCluster == pxIOManager->xPartition.ulRootDirCluster ) ) + { + ulItemLBA += ( ulEntry / ( ( pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster ) / + FF_SIZEOF_DIRECTORY_ENTRY ) * pxIOManager->xPartition.ulSectorsPerCluster ); + } + + ulItemLBA = FF_getRealLBA ( pxIOManager, ulItemLBA ) + FF_getMinorBlockNumber( pxIOManager, ulRelItem, ( uint32_t )FF_SIZEOF_DIRECTORY_ENTRY ); + + if( ( pxContext->pxBuffer == NULL ) || + ( pxContext->pxBuffer->ulSector != ulItemLBA ) || + ( ( pxContext->pxBuffer->ucMode & FF_MODE_WRITE ) != 0 ) ) + { + if( pxContext->pxBuffer != NULL ) + { + xError = FF_ReleaseBuffer( pxIOManager, pxContext->pxBuffer ); + pxContext->pxBuffer = NULL; + } + + if( FF_isERR( xError ) == pdFALSE ) + { + pxContext->pxBuffer = FF_GetBuffer( pxIOManager, ulItemLBA, FF_MODE_READ ); + if( pxContext->pxBuffer == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FETCHENTRYWITHCONTEXT ); + } + } + } + + if ( ( pEntryBuffer != NULL ) && ( pxContext->pxBuffer != NULL ) ) + { + memcpy( pEntryBuffer, pxContext->pxBuffer->pucBuffer + ( ulRelItem * FF_SIZEOF_DIRECTORY_ENTRY ), FF_SIZEOF_DIRECTORY_ENTRY ); + } + } + + return xError; +} /* FF_FetchEntryWithContext() */ +/*-----------------------------------------------------------*/ + + +FF_Error_t FF_PushEntryWithContext( FF_IOManager_t *pxIOManager, uint32_t ulEntry, FF_FetchContext_t *pxContext, uint8_t *pEntryBuffer ) +{ + uint32_t ulItemLBA; + uint32_t ulRelItem; + FF_Error_t xError; + + xError = FF_Traverse( pxIOManager, ulEntry, pxContext ); + if( FF_isERR( xError ) == pdFALSE ) + { + ulRelItem = FF_getMinorBlockEntry ( pxIOManager, ulEntry, ( uint32_t ) FF_SIZEOF_DIRECTORY_ENTRY ); + + ulItemLBA = FF_Cluster2LBA ( pxIOManager, pxContext->ulCurrentClusterLCN ) + FF_getMajorBlockNumber( pxIOManager, ulEntry, ( uint32_t ) FF_SIZEOF_DIRECTORY_ENTRY ); + if( ( pxIOManager->xPartition.ucType != FF_T_FAT32 ) && + ( pxContext->ulDirCluster == pxIOManager->xPartition.ulRootDirCluster ) ) + { + ulItemLBA += ( ulEntry / + ( ( pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster ) / FF_SIZEOF_DIRECTORY_ENTRY ) * pxIOManager->xPartition.ulSectorsPerCluster ); + } + + ulItemLBA = FF_getRealLBA ( pxIOManager, ulItemLBA ) + FF_getMinorBlockNumber( pxIOManager, ulRelItem, ( uint32_t )FF_SIZEOF_DIRECTORY_ENTRY ); + + if( ( pxContext->pxBuffer == NULL ) || + ( pxContext->pxBuffer->ulSector != ulItemLBA ) || + ( ( pxContext->pxBuffer->ucMode & FF_MODE_WRITE ) == 0 ) ) + { + if( pxContext->pxBuffer != NULL ) + { + xError = FF_ReleaseBuffer( pxIOManager, pxContext->pxBuffer ); + pxContext->pxBuffer = NULL; + } + if( FF_isERR( xError ) == pdFALSE ) + { + pxContext->pxBuffer = FF_GetBuffer( pxIOManager, ulItemLBA, FF_MODE_WRITE ); + if( pxContext->pxBuffer == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FETCHENTRYWITHCONTEXT ); + } + } + } + + /* Now change the entry: */ + if( pxContext->pxBuffer != NULL ) + { + memcpy( pxContext->pxBuffer->pucBuffer + ( ulRelItem * FF_SIZEOF_DIRECTORY_ENTRY ), pEntryBuffer, FF_SIZEOF_DIRECTORY_ENTRY ); + } + } + + return xError; +} /* FF_PushEntryWithContext() */ +/*-----------------------------------------------------------*/ + + +/** + * @private + **/ +FF_Error_t FF_GetEntry( FF_IOManager_t *pxIOManager, uint16_t usEntry, uint32_t ulDirCluster, FF_DirEnt_t *pxDirEntry ) +{ +/* A 32 byte directory entry. */ +uint8_t ucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ]; +FF_FetchContext_t xFetchContext; +FF_Error_t xError; + +#if( ffconfigLFN_SUPPORT == 0 ) + BaseType_t xLFNCount; +#endif + xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext ); + + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_FetchEntryWithContext( pxIOManager, usEntry, &xFetchContext, ucEntryBuffer ); + + if( ( FF_isERR( xError ) == pdFALSE ) && + ( FF_isDeleted( ucEntryBuffer ) == pdFALSE ) ) + { + if( FF_isEndOfDir( ucEntryBuffer ) != pdFALSE ) + { + xError = ( FF_Error_t ) ( FF_ERR_DIR_END_OF_DIR | FF_GETENTRY ); + } + else + { + pxDirEntry->ucAttrib = FF_getChar( ucEntryBuffer, ( uint16_t )( FF_FAT_DIRENT_ATTRIB ) ); + + if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_LFN ) == FF_FAT_ATTR_LFN ) + { + #if( ffconfigLFN_SUPPORT != 0 ) + xError = FF_PopulateLongDirent( pxIOManager, pxDirEntry, usEntry, &xFetchContext ); + #else + /* LFN Processing. */ + xLFNCount = ( BaseType_t )( ucEntryBuffer[0] & ~0x40 ); + pxDirEntry->usCurrentItem += ( xLFNCount - 1 ); + #endif + } + else if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_VOLID ) != FF_FAT_ATTR_VOLID ) + { + FF_PopulateShortDirent( pxIOManager, pxDirEntry, ucEntryBuffer ); + pxDirEntry->usCurrentItem += 1; + } + } + } + { + FF_Error_t xTempError; + xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + } + + return xError; +} /* FF_GetEntry() */ +/*-----------------------------------------------------------*/ + + +FF_Error_t FF_PopulateLongDirent( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirEntry, uint16_t usEntry, FF_FetchContext_t *pxFetchContext ) +{ +/* First get the entire name as UTF-16 from the LFN's. +Then transform into the API's native string format. */ + +FF_Error_t xError; +BaseType_t xNumLFNs; +uint8_t ucCheckSum; +/* A 32 byte directory entry. */ +uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ]; +char pcShortName[ 13 ]; + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + UBaseType_t uiLfnLength = 0; +#endif + +#if( ffconfigUNICODE_UTF16_SUPPORT == 0 ) + BaseType_t xIndex, y; +#endif + +#if( ffconfigUNICODE_UTF16_SUPPORT == 0 ) && ( ffconfigUNICODE_UTF8_SUPPORT == 0 ) + char *pcLastPtr = pxDirEntry->pcFileName + sizeof( pxDirEntry->pcFileName ); + char *pcCurPtr; +#endif + +#if( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + uint16_t nLfnBegin; + uint16_t usUtf8Len = 0; +#endif /* ffconfigUNICODE_UTF8_SUPPORT */ + + do + { + xError = FF_FetchEntryWithContext( pxIOManager, usEntry++, pxFetchContext, pucEntryBuffer ); + if( FF_isERR( xError ) ) + { + /* After breaking from this do {} while ( pdFALSE ) loop, xResult will be returned. */ + break; + } + + xNumLFNs = ( BaseType_t )( pucEntryBuffer[0] & ~0x40 ); + ucCheckSum = FF_getChar( pucEntryBuffer, FF_FAT_LFN_CHECKSUM ); + + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + { + /* UTF-16 Can simply get segments of the UTF-16 sequence + going forward in the directory entries ( but reversed order ). */ + while( xNumLFNs > 0 ) + { + /* Avoid stack intensive use of a UTF-16 buffer. Stream direct to FileName dirent field in correct format. */ + /* memcpy direct! -UTF-16 support. */ + memcpy( pxDirEntry->pcFileName + ( ( xNumLFNs - 1 ) * 13 ) + 0, &( pucEntryBuffer[ FF_FAT_LFN_NAME_1] ), 10 ); + memcpy( pxDirEntry->pcFileName + ( ( xNumLFNs - 1 ) * 13 ) + 5, &( pucEntryBuffer[ FF_FAT_LFN_NAME_2] ), 12 ); + memcpy( pxDirEntry->pcFileName + ( ( xNumLFNs - 1 ) * 13 ) + 11, &( pucEntryBuffer[ FF_FAT_LFN_NAME_3] ), 4 ); + uiLfnLength += 13; + + xError = FF_FetchEntryWithContext( pxIOManager, usEntry++, pxFetchContext, pucEntryBuffer ); + if( FF_isERR( xError ) ) + { + break; + } + xNumLFNs--; + } + if( FF_isERR( xError ) ) + { + break; + } + pxDirEntry->pcFileName[ uiLfnLength ] = '\0'; + } + #endif /* ffconfigUNICODE_UTF16_SUPPORT */ + + #if ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + { + /* UTF-8 Sequence, we can only convert this from the beginning, must receive entries in reverse. */ + nLfnBegin = usEntry - 1; + + for( xIndex = 0; xIndex < xNumLFNs; xIndex++ ) + { + xError = FF_FetchEntryWithContext( pxIOManager, ( nLfnBegin + ( xNumLFNs - 1 ) - xIndex ), pxFetchContext, pucEntryBuffer ); + if( FF_isERR( xError ) ) + { + break; + } + + /* Now have the first part of the UTF-16 sequence. Stream into a UTF-8 sequence. */ + for( y = 0; y < 5; y++ ) + { + xError = FF_Utf16ctoUtf8c( ( uint8_t * )&pxDirEntry->pcFileName[ usUtf8Len ], + ( uint16_t * )&pucEntryBuffer[ FF_FAT_LFN_NAME_1 + ( y * 2 ) ], sizeof( pxDirEntry->pcFileName ) - usUtf8Len ); + if( xError > 0 ) + { + usUtf8Len += ( uint16_t )xError; + } + } + + for( y = 0; y < 6; y++ ) + { + xError = FF_Utf16ctoUtf8c( ( uint8_t * )&pxDirEntry->pcFileName[ usUtf8Len ], + ( uint16_t * )&pucEntryBuffer[ FF_FAT_LFN_NAME_2 + ( y * 2 ) ], sizeof( pxDirEntry->pcFileName ) - usUtf8Len ); + if( xError > 0 ) + { + usUtf8Len += ( uint16_t )xError; + } + } + + for( y = 0; y < 2; y++ ) + { + xError = FF_Utf16ctoUtf8c( ( uint8_t * )&pxDirEntry->pcFileName[ usUtf8Len ], + ( uint16_t * )&pucEntryBuffer[ FF_FAT_LFN_NAME_3 + ( y * 2 ) ], sizeof( pxDirEntry->pcFileName ) - usUtf8Len ); + if( xError > 0 ) + { + usUtf8Len += ( uint16_t ) xError; + } + } + usEntry++; + } + if( FF_isERR( xError ) ) + { + break; + } + + pxDirEntry->pcFileName[ usUtf8Len ] = '\0'; + + /* Put Entry context to correct position. */ + xError = FF_FetchEntryWithContext( pxIOManager, usEntry-1, pxFetchContext, pucEntryBuffer ); + if( FF_isERR( xError ) ) + { + break; + } + } + #endif /* ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) */ + + #if( ffconfigUNICODE_UTF16_SUPPORT == 0 ) && ( ffconfigUNICODE_UTF8_SUPPORT == 0 ) /* No Unicode, simple ASCII. */ + { + pcLastPtr[ -1 ] = '\0'; + y = xNumLFNs; + while( xNumLFNs-- ) + { + pcCurPtr = pxDirEntry->pcFileName + ( xNumLFNs * 13 ); + for( xIndex = 0; ( xIndex < 10 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 ) + { + *( pcCurPtr++ ) = pucEntryBuffer[ FF_FAT_LFN_NAME_1 + xIndex ]; + } + + for( xIndex = 0; ( xIndex < 12 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 ) + { + *( pcCurPtr++ ) = pucEntryBuffer[ FF_FAT_LFN_NAME_2 + xIndex ]; + } + + for( xIndex = 0; ( xIndex < 4 ) && ( pcCurPtr < pcLastPtr ); xIndex += 2 ) + { + *( pcCurPtr++ ) = pucEntryBuffer[ FF_FAT_LFN_NAME_3 + xIndex ]; + } + if( ( xNumLFNs == ( y - 1 ) ) && ( pcCurPtr < pcLastPtr ) ) + { + *pcCurPtr = '\0'; + } + xError = FF_FetchEntryWithContext( pxIOManager, usEntry++, pxFetchContext, pucEntryBuffer ); + if( FF_isERR( xError ) ) + { + break; + } + } + if( FF_isERR( xError ) ) + { + break; + } + } + #endif /* ( ffconfigUNICODE_UTF16_SUPPORT == 0 ) && ( ffconfigUNICODE_UTF8_SUPPORT == 0 ) */ + + /* Process the Shortname. -- LFN Transformation is now complete. + Process the ShortName Entry. */ + + /* if SHORTNAMES must be included, simple byte copy into shortname buffer. */ + #if( ffconfigLFN_SUPPORT != 0 ) && ( ffconfigINCLUDE_SHORT_NAME != 0 ) + { + memcpy( pxDirEntry->pcShortName, pucEntryBuffer, 11 ); + pxDirEntry->pcShortName[ 11 ] = '\0'; + FF_ProcessShortName( pxDirEntry->pcShortName ); + } + #endif /* ( != 0 ffconfigLFN_SUPPORT ) && ( ffconfigINCLUDE_SHORT_NAME != 0 ) */ + + memcpy( pcShortName, pucEntryBuffer, 11 ); + FF_ProcessShortName( pcShortName ); + if( ucCheckSum != FF_CreateChkSum( pucEntryBuffer ) ) + { + strcpy( pxDirEntry->pcFileName, pcShortName ); + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + { + FF_ShortNameExpand( pxDirEntry->pcFileName ); + } + #endif /* ffconfigUNICODE_UTF16_SUPPORT */ + } + + /* Finally fill in the other details. */ + pxDirEntry->ulObjectCluster = + ( ( uint32_t )FF_getShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH ) << 16 ) | + ( uint32_t )FF_getShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW ); + + #if( ffconfigTIME_SUPPORT != 0 ) + { + /* Get the creation Time & Date. */ + FF_GetTime( &pxDirEntry->xCreateTime, pucEntryBuffer, FF_FAT_DIRENT_CREATE_TIME ); + FF_GetDate( &pxDirEntry->xCreateTime, pucEntryBuffer, FF_FAT_DIRENT_CREATE_DATE ); + /* Get the modified Time & Date. */ + /* HT Here xCreateTime has become xModifiedTime, as it should: */ + FF_GetTime( &pxDirEntry->xModifiedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME ); + FF_GetDate( &pxDirEntry->xModifiedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE ); + /* Get the last accessed Date. */ + FF_GetDate( &pxDirEntry->xAccessedTime, pucEntryBuffer, FF_FAT_DIRENT_LASTACC_DATE ); + /* HT Why should these times be zero'd ? */ + pxDirEntry->xAccessedTime.Hour = 0; + pxDirEntry->xAccessedTime.Minute = 0; + pxDirEntry->xAccessedTime.Second = 0; + } + #endif /* ffconfigTIME_SUPPORT */ + + /* Get the filesize. */ + pxDirEntry->ulFileSize = FF_getLong( pucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_FILESIZE ) ); + /* Get the attribute. */ + pxDirEntry->ucAttrib = FF_getChar( pucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_ATTRIB ) ); + + pxDirEntry->usCurrentItem = usEntry; + } + while ( pdFALSE ); + + return xError; +} /* FF_PopulateLongDirent() */ +/*-----------------------------------------------------------*/ + +/** + * @public + * @brief Find's the first directory entry for the provided path. + * + * All values recorded in pxDirEntry must be preserved to and between calls to + * FF_FindNext( ). + * + * If ffconfigFINDAPI_ALLOW_WILDCARDS is defined, then path will have the following behaviour: + * + * path = "\" - Open the root dir, and iterate through all items. + * path = "\*.c" - Open the root dir, showing only files matching *.c wildcard. + * path = "\sub1\newdir" - Get the DIRENT for the newdir directory in /sub1/ if one exists. + * path = "\sub1\newdir\" - Open the directory /sub1/newdir/ and iterate through all items. + * path = "\sub1\newdir\*.c" - Open the directory /sub1/newdir/ and iterate through all items matching the *.c wildcard. + * + * It is important to distinguish the differences in behaviour between opening a Find operation + * on a path like /sub1 and /sub1/. ( /sub1 gets the sub1 dirent from the / dir, whereas /sub/ opens the sub1 dir ). + * + * Note, as compatible with other similar APIs, FreeRTOS+FAT also accepts \sub1\* for the same behaviour as + * /sub1/. + * + * @param pxIOManager FF_IOManager_t object that was created by FF_CreateIOManger( ). + * @param pxDirEntry FF_DirEnt_t object to store the entry information. + * @param path String to of the path to the Dir being listed. + * + * @Return 0 on success + * @Return FF_ERR_DEVICE_DRIVER_FAILED if device access failed. + * @Return -2 if Dir was not found. + * + **/ +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +FF_Error_t FF_FindFirst( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirEntry, const FF_T_WCHAR *pcPath ) +#else +FF_Error_t FF_FindFirst( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirEntry, const char *pcPath ) +#endif +{ +FF_Error_t xError; +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + uint16_t PathLen = ( uint16_t ) wcslen( pcPath ); +#else + uint16_t PathLen = ( uint16_t ) strlen( pcPath ); +#endif + +#if( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 ) + BaseType_t xIndex = 0; + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + const FF_T_WCHAR *pcWildCard; /* Check for a Wild-card. */ + #else + const char *pcWildCard; /* Check for a Wild-card. */ + #endif +#endif + + memset( pxDirEntry, 0, sizeof( FF_DirEnt_t ) ); + + if( pxIOManager == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_FINDFIRST ); + } +#if( ffconfigREMOVABLE_MEDIA != 0 ) + else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 ) + { + xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_FINDFIRST ); + } +#endif /* ffconfigREMOVABLE_MEDIA */ + else + { + #if( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 ) + { + pxDirEntry->pcWildCard[0] = '\0'; /* WildCard blank if its not a wildCard. */ + + pcWildCard = &pcPath[ PathLen - 1 ]; + + if( PathLen != 0 ) + { + /* Open the dir of the last token. */ + while( ( *pcWildCard != '\\' ) && ( *pcWildCard != '/' ) ) + { + xIndex++; + pcWildCard--; + if( PathLen == xIndex ) + { + break; + } + } + } + + pxDirEntry->ulDirCluster = FF_FindDir( pxIOManager, pcPath, PathLen - xIndex, &xError ); + if( FF_isERR( xError ) == pdFALSE ) + { + if( pxDirEntry->ulDirCluster != 0 ) + { + /* Valid Dir found, copy the wildCard to filename! */ + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + wcsncpy( pxDirEntry->pcWildCard, ++pcWildCard, ffconfigMAX_FILENAME ); + #else + strncpy( pxDirEntry->pcWildCard, ++pcWildCard, ffconfigMAX_FILENAME ); + #endif + if( pxDirEntry->pcWildCard[ xIndex - 1 ] == ':' ) + { + pxDirEntry->xInvertWildCard = pdTRUE; + pxDirEntry->pcWildCard[ xIndex - 1 ] = '\0'; + } + } + } + } + #else /* ffconfigFINDAPI_ALLOW_WILDCARDS */ + { + /* Get the directory cluster, if it exists. */ + pxDirEntry->ulDirCluster = FF_FindDir( pxIOManager, pcPath, PathLen, &xError ); + } + #endif /* ffconfigFINDAPI_ALLOW_WILDCARDS */ + + if( FF_isERR( xError ) == pdFALSE ) + { + if( pxDirEntry->ulDirCluster == 0 ) + { + xError = ( FF_Error_t ) ( FF_ERR_DIR_INVALID_PATH | FF_FINDFIRST ); + } + else + { + /* Initialise the Fetch Context. */ + xError = FF_InitEntryFetch( pxIOManager, pxDirEntry->ulDirCluster, &( pxDirEntry->xFetchContext ) ); + if( FF_isERR( xError ) == pdFALSE ) + { + pxDirEntry->usCurrentItem = 0; + xError = FF_FindNext( pxIOManager, pxDirEntry ); + } + } + } + } + + return xError; +} /* FF_FindFirst() */ +/*-----------------------------------------------------------*/ + +/** + * @public + * @brief Get's the next Entry based on the data recorded in the FF_DirEnt_t object. + * + * All values recorded in pxDirEntry must be preserved to and between calls to + * FF_FindNext( ). Please see @see FF_FindFirst( ) for find initialisation. + * + * @param pxIOManager FF_IOManager_t object that was created by FF_CreateIOManger( ). + * @param pxDirEntry FF_DirEnt_t object to store the entry information. ( As initialised by FF_FindFirst( )). + * + * @Return FF_ERR_DEVICE_DRIVER_FAILED is device access failed. + * + **/ +FF_Error_t FF_FindNext( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirEntry ) +{ +FF_Error_t xError; +BaseType_t xLFNCount; +const uint8_t *pucEntryBuffer = NULL; +#if( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 ) + BaseType_t b; +#endif + + if( pxIOManager == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_FINDNEXT ); + } +#if( ffconfigREMOVABLE_MEDIA != 0 ) + else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 ) + { + xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_FINDNEXT ); + } +#endif /* ffconfigREMOVABLE_MEDIA */ + else + { + xError = FF_ERR_NONE; + for( ; pxDirEntry->usCurrentItem < FF_MAX_ENTRIES_PER_DIRECTORY; pxDirEntry->usCurrentItem++ ) + { + if( ( pucEntryBuffer == NULL ) || + ( pucEntryBuffer >= ( pxDirEntry->xFetchContext.pxBuffer->pucBuffer + ( FF_SIZEOF_SECTOR - FF_SIZEOF_DIRECTORY_ENTRY ) ) ) ) + { + xError = FF_FetchEntryWithContext( pxIOManager, pxDirEntry->usCurrentItem, &( pxDirEntry->xFetchContext ), NULL ); + + if( FF_isERR( xError ) ) + { + break; + } + + if( pucEntryBuffer == NULL ) + { + pucEntryBuffer = pxDirEntry->xFetchContext.pxBuffer->pucBuffer + + ( FF_SIZEOF_DIRECTORY_ENTRY * ( pxDirEntry->usCurrentItem % ( FF_SIZEOF_SECTOR/FF_SIZEOF_DIRECTORY_ENTRY ) ) ); + } + else + { + pucEntryBuffer = pxDirEntry->xFetchContext.pxBuffer->pucBuffer; + } + } + else + { + pucEntryBuffer += FF_SIZEOF_DIRECTORY_ENTRY; + } + + if( FF_isDeleted( pucEntryBuffer ) != pdFALSE ) + { + /* The entry is not in use or deleted. */ + continue; + } + + if( FF_isEndOfDir( pucEntryBuffer ) ) + { + /* End of directory, generate a pseudo error 'DIR_END_OF_DIR'. */ + xError = ( FF_Error_t ) ( FF_ERR_DIR_END_OF_DIR | FF_FINDNEXT ); + break; + } + + pxDirEntry->ucAttrib = FF_getChar( pucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_ATTRIB ) ); + + if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_LFN ) == FF_FAT_ATTR_LFN ) + { + /* LFN Processing. */ + xLFNCount = ( BaseType_t )( pucEntryBuffer[0] & ~0x40 ); + /* Get the shortname and check if it is marked deleted. */ + #if( ffconfigLFN_SUPPORT != 0 ) + { + /* Reserve 32 bytes to hold one directory entry. */ + uint8_t Buffer[ FF_SIZEOF_DIRECTORY_ENTRY ]; + + /* Fetch the shortname, and get it's checksum, or for a deleted item with + orphaned LFN entries. */ + xError = FF_FetchEntryWithContext( pxIOManager, ( uint32_t ) ( pxDirEntry->usCurrentItem + xLFNCount ), &pxDirEntry->xFetchContext, Buffer ); + if( FF_isERR( xError ) ) + { + break; + } + + if( FF_isDeleted( Buffer ) == pdFALSE ) + { + xError = FF_PopulateLongDirent( pxIOManager, pxDirEntry, pxDirEntry->usCurrentItem, &pxDirEntry->xFetchContext ); + if( FF_isERR( xError ) ) + { + break; + } + #if( ffconfigINCLUDE_SHORT_NAME != 0 ) + { + pxDirEntry->ucAttrib |= FF_FAT_ATTR_IS_LFN; + } + #endif + + #if( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 ) + { + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + if( wcscmp( pxDirEntry->pcWildCard, L"" ) ) + #else + if( pxDirEntry->pcWildCard[0] ) + #endif + { + b = FF_wildcompare( pxDirEntry->pcWildCard, pxDirEntry->pcFileName ); + if( pxDirEntry->xInvertWildCard != pdFALSE ) + { + b = !b; + } + if( b != 0 ) + { + break; + } + + /* 'usCurrentItem' has already incremented by FF_PopulateLongDirent(), + this loop will incremente it again. */ + pxDirEntry->usCurrentItem -= 1; + + /* xFetchContext/usCurrentItem have changed. Update + 'pucEntryBuffer' to point to the current buffer position. */ + pucEntryBuffer = pxDirEntry->xFetchContext.pxBuffer->pucBuffer + + ( FF_SIZEOF_DIRECTORY_ENTRY * ( pxDirEntry->usCurrentItem % ( FF_SIZEOF_SECTOR/FF_SIZEOF_DIRECTORY_ENTRY ) ) ); + } + else + { + break; + } + } + #else /* ffconfigFINDAPI_ALLOW_WILDCARDS == 0 */ + { + /* usCurrentItem has been incremented by FF_PopulateLongDirent(). + Entry will be returned. */ + break; + } + #endif + } + } + #else /* ffconfigLFN_SUPPORT */ + { + /* Increment 'usCurrentItem' with (xLFNCount-1), + the loop will do an extra increment. */ + pxDirEntry->usCurrentItem += ( xLFNCount - 1 ); + } + #endif /* ffconfigLFN_SUPPORT */ + } /* ( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_LFN ) == FF_FAT_ATTR_LFN ) */ + else if( ( pxDirEntry->ucAttrib & FF_FAT_ATTR_VOLID ) != FF_FAT_ATTR_VOLID ) + { + /* If it's not a LFN entry, neither a Volume ID, it is a normal short name entry. */ + FF_PopulateShortDirent( pxIOManager, pxDirEntry, pucEntryBuffer ); + #if( ffconfigSHORTNAME_CASE != 0 ) + { + /* Apply NT/XP+ bits to get correct case. */ + FF_CaseShortName( pxDirEntry->pcFileName, FF_getChar( pucEntryBuffer, FF_FAT_CASE_OFFS ) ); + } + #endif + + #if( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 ) + { + if( pxDirEntry->pcWildCard[ 0 ] ) + { + b = FF_wildcompare( pxDirEntry->pcWildCard, pxDirEntry->pcFileName ); + if( pxDirEntry->xInvertWildCard != pdFALSE ) + { + b = !b; + } + if( b != 0 ) + { + pxDirEntry->usCurrentItem += 1; + break; + } + } + else + { + pxDirEntry->usCurrentItem += 1; + break; + } + } + #else /* ffconfigFINDAPI_ALLOW_WILDCARDS */ + { + pxDirEntry->usCurrentItem += 1; + break; + } + #endif + } + } /* for ( ; pxDirEntry->usCurrentItem < FF_MAX_ENTRIES_PER_DIRECTORY; pxDirEntry->usCurrentItem++ ) */ + + if( pxDirEntry->usCurrentItem == FF_MAX_ENTRIES_PER_DIRECTORY ) + { + xError = ( FF_Error_t ) ( FF_ERR_DIR_END_OF_DIR | FF_FINDNEXT ); + } + + { + FF_Error_t xTempError; + xTempError = FF_CleanupEntryFetch( pxIOManager, &pxDirEntry->xFetchContext ); + + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + } + + return xError; +} /* FF_FindNext() */ +/*-----------------------------------------------------------*/ + + +/* + Returns >= 0 for a free dirent entry. + Returns < 0 with and xError code if anything goes wrong. +*/ +static int32_t FF_FindFreeDirent( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams, uint16_t usSequential ) +{ +const uint8_t *pucEntryBuffer = NULL; +uint16_t freeCount = 0; +UBaseType_t uxEntry = 0; +BaseType_t xEntryFound = pdFALSE; +FF_Error_t xError; +uint32_t DirLength; +FF_FetchContext_t xFetchContext; +uint32_t ulDirCluster = pxFindParams->ulDirCluster; + + xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext ); + + if( FF_isERR( xError ) == pdFALSE ) + { + uxEntry = pxFindParams->lFreeEntry >= 0 ? pxFindParams->lFreeEntry : 0; + for ( ; uxEntry < FF_MAX_ENTRIES_PER_DIRECTORY; uxEntry++ ) + { + if( ( pucEntryBuffer == NULL ) || + ( pucEntryBuffer >= xFetchContext.pxBuffer->pucBuffer + ( FF_SIZEOF_SECTOR - FF_SIZEOF_DIRECTORY_ENTRY ) ) ) + { + xError = FF_FetchEntryWithContext( pxIOManager, uxEntry, &xFetchContext, NULL ); + if( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR ) + { + + xError = FF_ExtendDirectory( pxIOManager, ulDirCluster ); + /* The value of xEntryFound will be ignored in case there was an error. */ + xEntryFound = pdTRUE; + break; + } + else if( FF_isERR( xError ) ) + { + break; + } + if( pucEntryBuffer == NULL ) + { + pucEntryBuffer = xFetchContext.pxBuffer->pucBuffer + + ( FF_SIZEOF_DIRECTORY_ENTRY * ( uxEntry % ( FF_SIZEOF_SECTOR / FF_SIZEOF_DIRECTORY_ENTRY ) ) ); + } + else + { + pucEntryBuffer = xFetchContext.pxBuffer->pucBuffer; + } + } + else + { + /* Advance 32 bytes to point to the next directory entry. */ + pucEntryBuffer += FF_SIZEOF_DIRECTORY_ENTRY; + } + if( FF_isEndOfDir( pucEntryBuffer ) ) /* If its the end of the Dir, then FreeDirents from here. */ + { + /* Check if the directory has enough space */ + DirLength = xFetchContext.ulChainLength; + if( ( uxEntry + usSequential ) > + ( ( DirLength * ( ( UBaseType_t )pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->xPartition.usBlkSize ) ) / FF_SIZEOF_DIRECTORY_ENTRY ) ) + { + xError = FF_ExtendDirectory( pxIOManager, ulDirCluster ); + } + xEntryFound = pdTRUE; + break; + } + if( FF_isDeleted( pucEntryBuffer ) ) + { + if( ++freeCount == usSequential ) + { + xError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + xEntryFound = pdTRUE; + uxEntry = ( uxEntry - ( usSequential - 1 ) );/* Return the beginning entry in the sequential sequence. */ + break; + } + } + else + { + freeCount = 0; + } + } /* for ( uxEntry = 0; uxEntry < FF_MAX_ENTRIES_PER_DIRECTORY; uxEntry++ ) */ + + { + FF_Error_t xTempError; + + xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + + } + + if( FF_isERR( xError ) == pdFALSE ) + { + if( xEntryFound != pdFALSE ) + { + /* No error has occurred and a free directory entry has been found. */ + xError = uxEntry; + } + else + { + xError = ( FF_Error_t ) ( FF_ERR_DIR_DIRECTORY_FULL | FF_FINDFREEDIRENT ); + } + } + + return xError; +} /* FF_FindFreeDirent() */ +/*-----------------------------------------------------------*/ + +/* _HT_ Now FF_PutEntry has a new optional parameter *pucContents */ +/* _HT_ so it can be used FF_MkDir( ) to save some code when adding . and .. entries */ +FF_Error_t FF_PutEntry( FF_IOManager_t *pxIOManager, uint16_t usEntry, uint32_t ulDirCluster, FF_DirEnt_t *pxDirEntry, uint8_t *pucContents ) +{ +FF_Error_t xError; +/* Reserve 32 bytes to hold one directory entry. */ +uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ]; +FF_FetchContext_t xFetchContext; + + /* HT: use the standard access routine to get the same logic for root dirs. */ + xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_FetchEntryWithContext( pxIOManager, usEntry, &xFetchContext, pucEntryBuffer ); + if( FF_isERR( xError ) == pdFALSE ) + { + /* Cleanup probably not necessary here? + FF_PushEntryWithContext checks for R/W flag. */ + xError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + if( FF_isERR( xError ) == pdFALSE ) + { + if ( pucContents != NULL ) + { + memcpy ( pucEntryBuffer, pucContents, sizeof( pucEntryBuffer ) ); + } + FF_putChar( pucEntryBuffer, FF_FAT_DIRENT_ATTRIB, ( uint32_t ) pxDirEntry->ucAttrib ); + FF_putShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) ( pxDirEntry->ulObjectCluster >> 16 ) ); + FF_putShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW, ( uint32_t ) ( pxDirEntry->ulObjectCluster ) ); + FF_putLong( pucEntryBuffer, FF_FAT_DIRENT_FILESIZE, pxDirEntry->ulFileSize ); + #if( ffconfigTIME_SUPPORT != 0 ) + { + FF_GetSystemTime( &pxDirEntry->xAccessedTime ); /*/< Date of Last Access. */ + FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_LASTACC_DATE, &pxDirEntry->xAccessedTime ); + FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_LASTACC_DATE, &pxDirEntry->xAccessedTime ); /* Last accessed date. */ + FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_CREATE_TIME, &pxDirEntry->xCreateTime ); + FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_CREATE_DATE, &pxDirEntry->xCreateTime ); + FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME, &pxDirEntry->xModifiedTime ); + FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE, &pxDirEntry->xModifiedTime ); + } + #endif /* ffconfigTIME_SUPPORT */ + xError = FF_PushEntryWithContext( pxIOManager, usEntry, &xFetchContext, pucEntryBuffer ); + } + } + } + + FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + + return xError; +} /* FF_PutEntry() */ +/*-----------------------------------------------------------*/ + +static BaseType_t FF_ValidShortChar( char cChar ) +{ + return ( cChar >= 'A' && cChar <= 'Z' ) || + ( cChar >= 'a' && cChar <= 'z' ) || /* lower-case can be stored using NT/XP attribute. */ + ( cChar >= '0' && cChar <= '9' ) || + strchr ( "$%-_@~`!(){}^#&", cChar ) != NULL; +} /* FF_ValidShortChar() */ +/*-----------------------------------------------------------*/ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +void FF_CreateShortName( FF_FindParams_t *pxFindParams, const FF_T_WCHAR *pcLongName ) +#else +void FF_CreateShortName( FF_FindParams_t *pxFindParams, const char *pcLongName ) +#endif +{ +BaseType_t xIndex, xPosition, xLastDot; +uint16_t NameLen; + +#if( ffconfigSHORTNAME_CASE != 0 ) + uint8_t testAttrib = FF_FAT_CASE_ATTR_BASE; +#endif + + /* Examples: + * "readme.TXT" will get the attribute FF_FAT_CASE_ATTR_BASE + * "README.txt" will get the attribute FF_FAT_CASE_ATTR_EXT + * "Readme.txt" can not be store as a short name */ + + pxFindParams->ucCaseAttrib = 0; /* May get the value FF_FAT_CASE_ATTR_BASE or FF_FAT_CASE_ATTR_EXT */ + pxFindParams->ucFirstTilde = 6; /* The numerical position of the ~ */ + pxFindParams->ulFlags |= FIND_FLAG_SHORTNAME_SET | FIND_FLAG_FITS_SHORT | FIND_FLAG_SIZE_OK; + + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + { + NameLen = ( uint16_t ) wcslen( pcLongName ); + } + #else + { + NameLen = ( uint16_t ) strlen( pcLongName ); + } + #endif + + /* Does pcLongName fit a shortname? */ + + for( xIndex = 0, xPosition = 0, xLastDot = NameLen; xIndex < NameLen; xIndex++ ) + { + if( pcLongName[ xIndex ] != '.' ) + { + xPosition++; + } + else + { + xLastDot = xIndex; + } + } + /* For example: + "FILENAME.EXT": NameLen = 12, xLastDot = 8, xPosition = 11 + ".cproject" : NameLen = 9, xLastDot = 0, xPosition = 8 + */ + + if( ( NameLen > 12 ) || /* If name is longer than 12 characters (8.3). */ + ( NameLen - xPosition > 1 ) || /* If it contains more than 1 dot. */ + ( NameLen - xLastDot > 4 ) || /* If the file name extension is longer than 3 characters. */ + ( xLastDot > 8 ) ) /* If the file name base is too long. */ + { + pxFindParams->ulFlags &= ~FIND_FLAG_SIZE_OK; + } + + for( xIndex = 0, xPosition = 0; xIndex < 11; xPosition++ ) + { + char ch = pcLongName[ xPosition ]; + if( !ch ) + break; + if( ( xIndex == 0 ) && ( ch == '.' ) ) + { + pxFindParams->ulFlags &= ~FIND_FLAG_FITS_SHORT; + continue; + } + if( xPosition == xLastDot ) + { + /* Remember where we put the first space. */ + if ( pxFindParams->ucFirstTilde > xIndex ) + { + pxFindParams->ucFirstTilde = xIndex; + } + while ( xIndex < 8 ) + { + pxFindParams->pcEntryBuffer[ xIndex++ ] = 0x20; + } + #if( ffconfigSHORTNAME_CASE != 0 ) + { + testAttrib = FF_FAT_CASE_ATTR_EXT; + } + #endif + } + else + { + if( xIndex == 8 ) + { + if( xPosition <= xLastDot ) + { + xPosition = xLastDot; + ch = ( int8_t ) pcLongName[ xPosition ]; + if( ch == '\0' ) + { + break; + } + ch = ( int8_t ) pcLongName[ ++xPosition ]; + #if( ffconfigSHORTNAME_CASE != 0 ) + { + testAttrib = FF_FAT_CASE_ATTR_EXT; + } + #endif + } + } + if( !FF_ValidShortChar ( ch ) ) + { + pxFindParams->ulFlags &= ~FIND_FLAG_FITS_SHORT; + continue; + } + #if( ffconfigSHORTNAME_CASE != 0 ) + { + if( ( ch >= 'a' ) && ( ch <= 'z' ) ) + { + ch -= 0x20; + if ( testAttrib ) + { + pxFindParams->ucCaseAttrib |= testAttrib; + } + else + { + pxFindParams->ulFlags &= ~FIND_FLAG_FITS_SHORT; /* We had capital: does not fit. */ + } + } + else if( ( ch >= 'A' ) && ( ch <= 'Z' ) ) + { + if( ( pxFindParams->ucCaseAttrib & testAttrib ) != 0 ) + { + pxFindParams->ulFlags &= ~FIND_FLAG_FITS_SHORT; /* We had lower-case: does not fit. */ + } + testAttrib = 0; + } + } + #else + { + if( ( ch >= 'a' ) && ( ch <= 'z' ) ) + { + ch -= 0x20; + } + } + #endif /* ffconfigSHORTNAME_CASE */ + pxFindParams->pcEntryBuffer[ xIndex++ ] = ch; + } + } + + if( ( xLastDot == 0 ) && ( xIndex < 6 ) ) + { + /* This is a file name like ".info" or ".root" */ + pxFindParams->ucFirstTilde = xIndex; + } + + while ( xIndex < 11 ) + { + pxFindParams->pcEntryBuffer[ xIndex++ ] = 0x20; + } + + if( ( xLastDot < pxFindParams->ucFirstTilde ) && ( xLastDot > 0 ) ) + { + pxFindParams->ucFirstTilde = xLastDot; + } + + if( NameLen < pxFindParams->ucFirstTilde ) /* Names like "Abc" will become "~Abc". */ + { + pxFindParams->ucFirstTilde = ( uint8_t ) NameLen; + } +} /* FF_CreateShortName() */ +/*-----------------------------------------------------------*/ + +int32_t FF_FindShortName( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams ) +{ +char pcMyShortName[ 13 ]; +FF_DirEnt_t xMyDirectory; +FF_Error_t xResult = 0; +BaseType_t xIndex, x, y; +uint16_t NameLen; +char pcNumberBuf[ 12 ]; +uint32_t ulCluster; + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_T_WCHAR pcFileName[ 13 ]; +#else + char *pcFileName = pcMyShortName; +#endif /* ffconfigUNICODE_UTF16_SUPPORT */ + +#if( ipconfigQUICK_SHORT_FILENAME_CREATION != 0 ) + uint16_t usShortHash; + uint32_t ulRand = 0ul; +#endif + + memcpy( pcMyShortName, pxFindParams->pcEntryBuffer, 11 ); + FF_ProcessShortName( pcMyShortName ); + if( ( pxFindParams->ulFlags & FIND_FLAG_FITS_SHORT_OK ) == FIND_FLAG_FITS_SHORT_OK ) + { + /* This entry will not get a LFN entry because it fits + * perfectly into a host name */ + if( ( pxFindParams->ulFlags & FIND_FLAG_SHORTNAME_CHECKED ) != 0 ) + { + if( ( pxFindParams->ulFlags & FIND_FLAG_SHORTNAME_FOUND ) != 0 ) + { + xResult = ( FF_Error_t ) ( FF_ERR_DIR_OBJECT_EXISTS | FF_CREATESHORTNAME ); + } + else + { + xResult = pxFindParams->ucCaseAttrib | 0x01; + } + } + else + { + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + { + memcpy( pcFileName, pcMyShortName, sizeof( pcMyShortName ) ); + FF_ShortNameExpand( pcFileName ); + } + #endif + ulCluster = FF_FindEntryInDir( pxIOManager, pxFindParams, pcFileName, 0x00, &xMyDirectory, &xResult ); + + /* END_OF_DIR is not a fatal error, it only means that the entry was not found. */ + if( ( FF_isERR( xResult ) == pdFALSE ) || ( FF_GETERROR( xResult ) == FF_ERR_DIR_END_OF_DIR ) ) + { + if( ulCluster == 0UL ) + { + xResult = pxFindParams->ucCaseAttrib | 0x01; + } + else + { + xResult = ( FF_Error_t ) ( FF_ERR_DIR_OBJECT_EXISTS | FF_CREATESHORTNAME ); + } + } + else + { + /* There was an error, which will be returned. */ + } + } + } + else + { + for( xIndex = ( ( pxFindParams->ulFlags & FIND_FLAG_SIZE_OK ) ? 0 : 1 ); ; xIndex++ ) + { + if( xIndex != 0 ) + { + #if( ipconfigQUICK_SHORT_FILENAME_CREATION != 0 ) + { + /* In the first round, check if the original name can be used + Makefile will be stored as "makefile" and not as "makefi~1". */ + + /* This method saves a lot of time when creating directories with + many similar file names: when the short name version of a LFN already + exists, try at most 3 entries with a tilde: + README~1.TXT + README~2.TXT + README~3.TXT + After that create entries with pseudo-random 4-digit hex digits: + REA~E7BB.TXT + REA~BA32.TXT + REA~D394.TXT + */ + if( xIndex <= 4 ) + { + snprintf( pcNumberBuf, sizeof( pcNumberBuf ), "%d", ( int ) xIndex ); + } + else + { + if( ulRand == 0ul ) + { + ulRand = pxIOManager->xPartition.ulLastFreeCluster; + usShortHash = FF_GetCRC16( ( uint8_t *)&ulRand, sizeof( ulRand ) ); + } + else + { + usShortHash = FF_GetCRC16( ( uint8_t *)&usShortHash, sizeof( usShortHash ) ); + } + snprintf( pcNumberBuf, sizeof( pcNumberBuf ), "%04X", ( int ) usShortHash ); + } + } + #else + { + snprintf( pcNumberBuf, sizeof( pcNumberBuf ), "%d", ( int ) xIndex ); + } + #endif + + NameLen = ( uint16_t ) strlen( pcNumberBuf ); + x = 7 - NameLen; + if ( x > pxFindParams->ucFirstTilde ) + { + x = pxFindParams->ucFirstTilde; + } + pxFindParams->pcEntryBuffer[ x++ ] = '~'; + for( y = 0; y < NameLen; y++ ) + { + pxFindParams->pcEntryBuffer[ x + y ] = pcNumberBuf[ y ]; + } + } + memcpy( pcMyShortName, pxFindParams->pcEntryBuffer, 11 ); + FF_ProcessShortName( pcMyShortName ); + if( FF_ShortNameExists( pxIOManager, pxFindParams->ulDirCluster, pcMyShortName, &xResult ) == pdFALSE ) + { + break; + } + if( xIndex >= FF_MAX_ENTRIES_PER_DIRECTORY ) + { + xResult = ( FF_Error_t ) ( FF_ERR_DIR_DIRECTORY_FULL | FF_CREATESHORTNAME ); + break; + } + } + /* Add a tail and special number until we're happy :D. */ + } + + return xResult; +} /* FF_FindShortName () */ +/*-----------------------------------------------------------*/ + + +#if( ffconfigLFN_SUPPORT != 0 ) + static int8_t FF_CreateLFNEntry( uint8_t *pucEntryBuffer, uint8_t *pcName, UBaseType_t uxNameLength, UBaseType_t uxLFN, uint8_t ucCheckSum ) + { + /* + * HT for JW: + * Changed *pcName from 16- to of 8-bits + * The caller of this function doesn't need an expensive + * uint16_t usUtf16Name[ffconfigMAX_FILENAME + 1]; + * in case UNICODE isn't used + * Also did quite a bit of optimisation here + * and tested well + */ + UBaseType_t uxIndex, x; + + memset( pucEntryBuffer, 0, FF_SIZEOF_DIRECTORY_ENTRY ); + + FF_putChar( pucEntryBuffer, FF_FAT_LFN_ORD, ( uint8_t )( ( uxLFN & ~0x40 ) ) ); + FF_putChar( pucEntryBuffer, FF_FAT_DIRENT_ATTRIB, ( uint8_t ) FF_FAT_ATTR_LFN ); + FF_putChar( pucEntryBuffer, FF_FAT_LFN_CHECKSUM, ( uint8_t ) ucCheckSum ); + + /* Name_1. */ + uxIndex = 0; + for( x = FF_FAT_LFN_NAME_1; uxIndex < 5u; uxIndex++, x += 2 ) + { + if( uxIndex < uxNameLength ) + { + pucEntryBuffer[ x ] = *( pcName++ ); + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + { + pucEntryBuffer[ x + 1 ] = *( pcName++ ); + } + #endif + } + else if ( uxIndex > uxNameLength ) + { + pucEntryBuffer[ x] = 0xFF; + pucEntryBuffer[ x + 1 ] = 0xFF; + } + } + + /* Name_2. */ + for( x = FF_FAT_LFN_NAME_2; uxIndex < 11u; uxIndex++, x += 2 ) + { + if( uxIndex < uxNameLength ) + { + pucEntryBuffer[ x ] = *( pcName++ ); + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + { + pucEntryBuffer[ x + 1 ] = *( pcName++ ); + } + #endif + } + else if( uxIndex > uxNameLength ) + { + pucEntryBuffer[ x ] = 0xFF; + pucEntryBuffer[ x + 1 ] = 0xFF; + } + } + + /* Name_3. */ + for( x = FF_FAT_LFN_NAME_3; uxIndex < 13u; uxIndex++, x += 2 ) + { + if( uxIndex < uxNameLength ) + { + pucEntryBuffer[ x ] = *( pcName++ ); + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + { + pucEntryBuffer[ x + 1 ] = *( pcName++ ); + } + #endif + } + else if( uxIndex > uxNameLength ) + { + pucEntryBuffer[ x ] = 0xFF; + pucEntryBuffer[ x + 1 ] = 0xFF; + } + } + + return FF_ERR_NONE; + } /* FF_CreateLFNEntry() */ +#endif /* ffconfigLFN_SUPPORT */ +/*-----------------------------------------------------------*/ + +#if( ffconfigLFN_SUPPORT != 0 ) + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + static FF_Error_t FF_CreateLFNs( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, FF_T_WCHAR *pcName, uint8_t ucCheckSum, uint16_t usEntry ) + #else + static FF_Error_t FF_CreateLFNs( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, char *pcName, uint8_t ucCheckSum, uint16_t usEntry ) + #endif + { + FF_Error_t xError = FF_ERR_NONE; + BaseType_t xNumLFNs; + BaseType_t xEndPos; + BaseType_t xIndex, y; + FF_FetchContext_t xFetchContext; + uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ]; + + #if ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + int32_t slRetVal; + #endif + + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + uint16_t usUtf16Name[ ffconfigMAX_FILENAME + 1 ]; + #endif + + #if( ffconfigUNICODE_UTF16_SUPPORT == 0 ) + char *NamePtr; + #else + int16_t *NamePtr; + #endif + + + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + { + #if WCHAR_MAX <= 0xFFFF + { + y = wcslen( pcName ); + if( y > ffconfigMAX_FILENAME ) + { + xError = ( FF_Error_t ) ( FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS ); + } + else + { + wcsncpy( usUtf16Name, pcName, ffconfigMAX_FILENAME ); + } + } + #else + { + xIndex = 0; + y = 0; + while( pcName[ xIndex ] ) + { + FF_Utf32ctoUtf16c( &usUtf16Name[ y ], ( uint32_t ) pcName[xIndex], ffconfigMAX_FILENAME - xIndex ); + y += FF_GetUtf16SequenceLen( usUtf16Name[ y ] ); + xIndex++; + if( y > ffconfigMAX_FILENAME ) + { + xError = ( FF_Error_t ) ( FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS ); + break; + } + } + } + #endif + } + #endif /* ffconfigUNICODE_UTF16_SUPPORT */ + + /* Convert the name into UTF-16 format. */ + #if ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + { + /* Simply convert the UTF8 to UTF16 and be done with it. */ + xIndex = 0; + y = 0; + while( pcName[ xIndex ] != 0 ) + { + slRetVal = FF_Utf8ctoUtf16c( &( usUtf16Name[ y ] ), ( uint8_t * )&( pcName[ xIndex ] ), ffconfigMAX_FILENAME - xIndex ); + if( slRetVal > 0 ) + { + xIndex += slRetVal; + } + else + { + break; /* No more space in the UTF-16 buffer, simply truncate for safety. */ + } + y += FF_GetUtf16SequenceLen( usUtf16Name[ y ] ); + if( y > ffconfigMAX_FILENAME ) + { + xError = ( FF_Error_t ) ( FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS ); + break; + } + } + } + #elif ( ffconfigUNICODE_UTF16_SUPPORT == 0 ) + { + /* Just check the length. */ + y = strlen( pcName ); + if( y > ffconfigMAX_FILENAME ) + { + xError = ( FF_Error_t ) ( FF_ERR_DIR_NAME_TOO_LONG | FF_CREATELFNS ); + } + } + #endif + + /* Whole name is now in a valid UTF-16 format. Lets go make thos LFN's. + At this point, it should a be the length of the name. */ + if( FF_isERR( xError ) == pdFALSE ) + { + xNumLFNs = y / 13; /* Number of LFNs is the total number of UTF-16 units, divided by 13 ( 13 units per LFN ). */ + xEndPos = y % 13; /* The ending position in an LFN, of the last LFN UTF-16 character. */ + + if( xEndPos ) + { + xNumLFNs++; + } + else + { + xEndPos = 13; + } + + xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext ); + if( FF_isERR( xError ) == pdFALSE ) + { + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + { + NamePtr = ( int16_t * ) ( usUtf16Name + 13 * ( xNumLFNs - 1 ) ); + } + #elif ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + { + NamePtr = ( int8_t * ) ( usUtf16Name + 13 * ( xNumLFNs - 1 ) ); + } + #else + { + NamePtr = pcName + 13 * ( xNumLFNs - 1 ); + } + #endif + /* After this point, xIndex is no longer the length of the Filename in UTF-16 units. */ + for( xIndex = xNumLFNs; xIndex > 0; xIndex-- ) + { + if( xIndex == xNumLFNs ) + { + FF_CreateLFNEntry( pucEntryBuffer, ( uint8_t * ) NamePtr, ( UBaseType_t ) xEndPos, ( UBaseType_t ) xIndex, ucCheckSum ); + pucEntryBuffer[0] |= 0x40; + } + else + { + FF_CreateLFNEntry( pucEntryBuffer, ( uint8_t * ) NamePtr, ( UBaseType_t ) 13u, ( UBaseType_t ) xIndex, ucCheckSum ); + } + NamePtr -= 13; + + xError = FF_PushEntryWithContext( pxIOManager, ( uint32_t ) ( usEntry + ( xNumLFNs - xIndex ) ), &xFetchContext, pucEntryBuffer ); + if( FF_isERR( xError ) ) + { + break; + } + } + + { + FF_Error_t xTempError; + + /* Release any buffers that were used. */ + xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + if( FF_isERR( xTempError ) == pdFALSE ) + { + xError = xTempError; + } + } + } + } + + return xError; + } /* FF_CreateLFNs() */ +#endif /* ffconfigLFN_SUPPORT */ +/*-----------------------------------------------------------*/ + +FF_Error_t FF_ExtendDirectory( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster ) +{ +uint32_t xCurrentCluster; +uint32_t xNextCluster = 0UL; +FF_Error_t xError = FF_ERR_NONE; +FF_FATBuffers_t xFATBuffers; + + if( ( ulDirCluster == pxIOManager->xPartition.ulRootDirCluster ) && + ( pxIOManager->xPartition.ucType != FF_T_FAT32 ) ) + { + /* root directories on FAT12 and FAT16 can not be extended. */ + xError = ( FF_Error_t ) ( FF_ERR_DIR_CANT_EXTEND_ROOT_DIR | FF_EXTENDDIRECTORY ); + } + else if( pxIOManager->xPartition.ulFreeClusterCount == 0UL ) + { + /* The number of free clusters was not yet calculated or equal to zero. */ + pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError ); + } + + if( FF_isERR( xError ) == pdFALSE ) + { + if( pxIOManager->xPartition.ulFreeClusterCount == 0UL ) + { + xError = ( FF_Error_t ) ( FF_ERR_FAT_NO_FREE_CLUSTERS | FF_EXTENDDIRECTORY ); + } + else + { + FF_LockFAT( pxIOManager ); + { + xCurrentCluster = FF_FindEndOfChain( pxIOManager, ulDirCluster, &xError ); + if( FF_isERR( xError ) == pdFALSE ) + { + xNextCluster = FF_FindFreeCluster( pxIOManager, &xError, pdTRUE ); + if( FF_isERR( xError ) == pdFALSE ) + { + FF_InitFATBuffers ( &xFATBuffers, FF_MODE_WRITE ); + /* xNextCluster already has been set to 0xFFFFFFFF, + now let xCurrentCluster point to xNextCluster. */ + + xError = FF_putFATEntry( pxIOManager, xCurrentCluster, xNextCluster, &xFATBuffers ); + { + FF_Error_t xTempError; + + xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + + xTempError = FF_DecreaseFreeClusters( pxIOManager, 1 ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + } + } + } + FF_UnlockFAT( pxIOManager ); + + if( FF_isERR( xError ) == pdFALSE ) + { + /* The entire cluster will be filled with zero's, + because it will contain directory data. */ + xError = FF_ClearCluster( pxIOManager, xNextCluster ); + } + } + } + + return xError; +} /* FF_ExtendDirectory() */ +/*-----------------------------------------------------------*/ + +static const uint8_t forbiddenChrs[] = +{ +/* Windows says: don't use these characters: '\/:*?"<>|' + " * / : < > ? '\' ? | */ + 0x22, 0x2A, 0x2F, 0x3A, 0x3C, 0x3E, 0x3F, 0x5C, 0x7F, 0x7C +}; + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +static void FF_MakeNameCompliant( FF_T_WCHAR *pcName ) +#else +static void FF_MakeNameCompliant( char *pcName ) +#endif +{ + BaseType_t index; + if( ( uint8_t ) pcName[ 0 ] == FF_FAT_DELETED ) /* Support Japanese KANJI symbol0xE5. */ + { + pcName[ 0 ] = 0x05; + } + for( ; *pcName; pcName++ ) + { + for( index = 0; index < ( BaseType_t ) sizeof( forbiddenChrs ); index++ ) + { + if( *pcName == forbiddenChrs[index] ) + { + *pcName = '_'; + break; + } + } + } +} /* FF_MakeNameCompliant() */ +/*-----------------------------------------------------------*/ + +FF_Error_t FF_CreateDirent( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams, FF_DirEnt_t *pxDirEntry ) +{ +uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ]; + +BaseType_t xLFNCount; +int32_t lFreeEntry = 0L; +FF_Error_t xReturn = FF_ERR_NONE; +BaseType_t xEntryCount; +FF_FetchContext_t xFetchContext; +uint32_t ulDirCluster = pxFindParams->ulDirCluster; +int32_t lFitShort; + +#if( ffconfigHASH_CACHE != 0 ) + char pcShortName[ 13 ]; +#endif +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + uint16_t NameLen = ( uint16_t ) wcslen( pxDirEntry->pcFileName ); +#else + uint16_t NameLen = ( uint16_t ) strlen( pxDirEntry->pcFileName ); +#endif + +#if( ffconfigLFN_SUPPORT != 0 ) + uint8_t ucCheckSum; +#endif + + /* Round-up the number of LFN's needed: */ + xLFNCount = ( BaseType_t ) ( ( NameLen + 12 ) / 13 ); + + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + { + FF_MakeNameCompliant( pxDirEntry->pcFileName ); /* Ensure we don't break the Dir tables. */ + } + #else + { + FF_MakeNameCompliant( pxDirEntry->pcFileName ); /* Ensure we don't break the Dir tables. */ + } + #endif + memset( pucEntryBuffer, 0, sizeof( pucEntryBuffer ) ); + + #if( ffconfigLFN_SUPPORT != 0 ) + { + /* Create and push the LFN's. */ + /* Find enough places for the LFNs and the ShortName. */ + xEntryCount = xLFNCount + 1; + } + #else + { + xEntryCount = 1; + } + #endif + + /* Create the ShortName. */ + FF_LockDirectory( pxIOManager ); + do + { + /* Open a do {} while( pdFALSE ) loop to allow the use of break statements. */ + /* As FF_FindShortName( ) can fail, it should be called before finding a free directory entry. */ + if( ( pxFindParams->ulFlags & FIND_FLAG_SHORTNAME_SET ) == 0 ) + { + FF_CreateShortName( pxFindParams, pxDirEntry->pcFileName ); + } + lFitShort = FF_FindShortName ( pxIOManager, pxFindParams ); + + memcpy( pucEntryBuffer, pxFindParams->pcEntryBuffer, sizeof( pucEntryBuffer ) ); + + if( FF_isERR( lFitShort ) ) + { + xReturn = lFitShort; + break; + } + if( lFitShort != 0 ) + { + /* There is no need to create a LFN entry because the file name + fits into a normal 32-byte entry.. */ + xLFNCount = 0; + xEntryCount = 1; + } + lFreeEntry = FF_FindFreeDirent( pxIOManager, pxFindParams, ( uint16_t ) xEntryCount ); + + if( FF_isERR( lFreeEntry ) ) + { + xReturn = lFreeEntry; + break; + } + #if( ffconfigLFN_SUPPORT != 0 ) + { + if( xLFNCount > 0 ) + { + ucCheckSum = FF_CreateChkSum( pucEntryBuffer ); + xReturn = FF_CreateLFNs( pxIOManager, ulDirCluster, pxDirEntry->pcFileName, ucCheckSum, ( uint16_t ) lFreeEntry ); + } + } + #else + { + xLFNCount = 0; + } + #endif /* ffconfigLFN_SUPPORT */ + if( FF_isERR( xReturn ) == pdFALSE ) + { + #if( ffconfigTIME_SUPPORT != 0 ) + { + FF_GetSystemTime( &pxDirEntry->xCreateTime ); /* Date and Time Created. */ + pxDirEntry->xModifiedTime = pxDirEntry->xCreateTime; /* Date and Time Modified. */ + pxDirEntry->xAccessedTime = pxDirEntry->xCreateTime; /* Date of Last Access. */ + FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_CREATE_TIME, &pxDirEntry->xCreateTime ); + FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_CREATE_DATE, &pxDirEntry->xCreateTime ); + FF_PlaceTime( pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_TIME, &pxDirEntry->xModifiedTime ); + FF_PlaceDate( pucEntryBuffer, FF_FAT_DIRENT_LASTMOD_DATE, &pxDirEntry->xModifiedTime ); + } + #endif /* ffconfigTIME_SUPPORT */ + + FF_putChar( pucEntryBuffer, FF_FAT_DIRENT_ATTRIB, pxDirEntry->ucAttrib ); + #if( ffconfigSHORTNAME_CASE != 0 ) + FF_putChar( pucEntryBuffer, FF_FAT_CASE_OFFS, ( uint32_t ) lFitShort & ( FF_FAT_CASE_ATTR_BASE | FF_FAT_CASE_ATTR_EXT ) ); + #endif + FF_putShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint16_t )( pxDirEntry->ulObjectCluster >> 16 ) ); + FF_putShort( pucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW, ( uint16_t )( pxDirEntry->ulObjectCluster ) ); + FF_putLong( pucEntryBuffer, FF_FAT_DIRENT_FILESIZE, pxDirEntry->ulFileSize ); + + xReturn = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext ); + if( FF_isERR( xReturn ) ) + { + break; + } + xReturn = FF_PushEntryWithContext( pxIOManager, ( uint16_t ) ( lFreeEntry + xLFNCount ), &xFetchContext, pucEntryBuffer ); + + { + FF_Error_t xTempError; + + xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + if( FF_isERR( xReturn ) == pdFALSE ) + { + xReturn = xTempError; + } + } + if( FF_isERR( xReturn ) ) + { + break; + } + + #if( ffconfigHASH_CACHE != 0 ) + { + if( FF_DirHashed( pxIOManager, ulDirCluster ) == pdFALSE ) + { + /* Hash the directory. */ + FF_HashDir( pxIOManager, ulDirCluster ); + } + memcpy( pcShortName, pucEntryBuffer, 11 ); + FF_ProcessShortName( pcShortName ); /* Format the shortname to 8.3. */ + #if( ffconfigHASH_FUNCTION == CRC16 ) + { + FF_AddDirentHash( pxIOManager, ulDirCluster, ( uint32_t )FF_GetCRC16( ( uint8_t * ) pcShortName, strlen( pcShortName ) ) ); + } + #elif( ffconfigHASH_FUNCTION == CRC8 ) + { + FF_AddDirentHash( pxIOManager, ulDirCluster, ( uint32_t )FF_GetCRC8( ( uint8_t * ) pcShortName, strlen( pcShortName ) ) ); + } + #endif /* ffconfigHASH_FUNCTION */ + } + #endif /* ffconfigHASH_CACHE*/ + } + } + while( pdFALSE ); + + FF_UnlockDirectory( pxIOManager ); + + if( FF_isERR( xReturn ) == pdFALSE ) + { + if( pxDirEntry != NULL ) + { + pxDirEntry->usCurrentItem = ( uint16_t )( lFreeEntry + xLFNCount ); + } + } + + return xReturn; +} /* FF_CreateDirent() */ +/*-----------------------------------------------------------*/ + + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +uint32_t FF_CreateFile( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams, FF_T_WCHAR *pcFileName, FF_DirEnt_t *pxDirEntry, FF_Error_t *pxError ) +#else +uint32_t FF_CreateFile( FF_IOManager_t *pxIOManager, FF_FindParams_t *pxFindParams, char *pcFileName, FF_DirEnt_t *pxDirEntry, FF_Error_t *pxError ) +#endif +{ +FF_DirEnt_t xMyFile; +FF_Error_t xTempError, xError = FF_ERR_NONE; +uint32_t ulResult; + + memset ( &xMyFile, '\0', sizeof( xMyFile ) ); + + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + { + wcsncpy( xMyFile.pcFileName, pcFileName, ffconfigMAX_FILENAME ); + } + #else + { + strncpy( xMyFile.pcFileName, pcFileName, ffconfigMAX_FILENAME ); + } + #endif + + xMyFile.ulObjectCluster = FF_CreateClusterChain( pxIOManager, &xError ); + + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_CreateDirent( pxIOManager, pxFindParams, &xMyFile ); + if( FF_isERR( xError ) == pdFALSE ) + { + /* The new file now has a cluster chain and it has an entry + in its directory. Copy data to a pointer provided by caller: */ + if( pxDirEntry != NULL ) + { + memcpy( pxDirEntry, &xMyFile, sizeof( FF_DirEnt_t ) ); + } + } + else + { + /* An error occurred in FF_CreateDirent(). + Unlink the file's cluster chain: */ + FF_LockFAT( pxIOManager ); + { + FF_UnlinkClusterChain( pxIOManager, xMyFile.ulObjectCluster, 0 ); + xMyFile.ulObjectCluster = 0ul; + } + FF_UnlockFAT( pxIOManager ); + } + /* Now flush all buffers to disk. */ + xTempError = FF_FlushCache( pxIOManager ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + + *pxError = xError; + + if( FF_isERR( xError ) == pdFALSE ) + { + ulResult = xMyFile.ulObjectCluster; + } + else + { + ulResult = 0; + } + + return ulResult; +} /* FF_CreateFile() */ +/*-----------------------------------------------------------*/ + + +/** + * @brief Creates a Directory of the specified path. + * + * @param pxIOManager Pointer to the FF_IOManager_t object. + * @param pcPath Path of the directory to create. + * + * @Return FF_ERR_NULL_POINTER if pxIOManager was NULL. + * @Return FF_ERR_DIR_OBJECT_EXISTS if the object specified by path already exists. + * @Return FF_ERR_DIR_INVALID_PATH + * @Return FF_ERR_NONE on success. + **/ +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +FF_Error_t FF_MkDir( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *pcPath ) +#else +FF_Error_t FF_MkDir( FF_IOManager_t *pxIOManager, const char *pcPath ) +#endif +{ +FF_DirEnt_t xMyDirectory; + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + const FF_T_WCHAR *pcDirName; +#else + const char *pcDirName; +#endif +uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ]; +uint32_t ulObjectCluster; +BaseType_t xIndex; +FF_Error_t xError = FF_ERR_NONE; + +FF_FindParams_t xFindParams; + + memset ( &xFindParams, '\0', sizeof( xFindParams ) ); + /* Inform the functions that the entry will be created if not found */ + xFindParams.ulFlags |= FIND_FLAG_CREATE_FLAG; + + /* Open a do {} while ( pdFALSE ) loop */ + do + { + if( pxIOManager == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_MKDIR ); + break; + } +#if( ffconfigREMOVABLE_MEDIA != 0 ) + if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 ) + { + xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_MKDIR ); + break; + } +#endif /* ffconfigREMOVABLE_MEDIA */ + + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + { + xIndex = ( BaseType_t ) wcslen( pcPath ); + } + #else + { + xIndex = ( BaseType_t ) strlen( pcPath ); + } + #endif + + /* Find the last slash in the path. */ + while( xIndex != 0 ) + { + if( ( pcPath[ xIndex ] == '\\' ) || ( pcPath[ xIndex ] == '/' ) ) + { + break; + } + xIndex--; + } + + pcDirName = pcPath + xIndex + 1; + + if( xIndex == 0 ) + { + xIndex = 1; + } + + if( pcDirName[ 0 ] == '\0' ) + { + xError = ( FF_ERR_DIR_OBJECT_EXISTS | FF_MKDIR ); + break; + } + + xFindParams.ulDirCluster = FF_FindDir( pxIOManager, pcPath, ( uint16_t ) xIndex, &xError ); + + if( FF_isERR( xError ) ) + { + break; + } + + if( xFindParams.ulDirCluster == 0UL ) + { + xError = ( FF_Error_t ) ( FF_ERR_DIR_INVALID_PATH | FF_MKDIR ); + break; + } + memset( &xMyDirectory, '\0', sizeof( xMyDirectory ) ); + + /* Will set flags FIND_FLAG_FITS_SHORT and FIND_FLAG_SIZE_OK */ + FF_CreateShortName( &xFindParams, pcDirName ); + + if( FF_FindEntryInDir( pxIOManager, &xFindParams, pcDirName, 0x00, &xMyDirectory, &xError ) ) + { + if( FF_isERR( xError ) == pdFALSE ) + { + xError = ( FF_Error_t ) ( FF_ERR_DIR_OBJECT_EXISTS | FF_MKDIR ); + } + break; + } + + if( ( FF_isERR( xError ) ) && ( FF_GETERROR( xError ) != FF_ERR_DIR_END_OF_DIR ) ) + { + break; + } + + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + { + wcsncpy( xMyDirectory.pcFileName, pcDirName, ffconfigMAX_FILENAME ); + } + #else + { + strncpy( xMyDirectory.pcFileName, pcDirName, ffconfigMAX_FILENAME ); + } + #endif + + xMyDirectory.ulFileSize = 0; + xMyDirectory.ucAttrib = FF_FAT_ATTR_DIR; + xMyDirectory.ulObjectCluster = FF_CreateClusterChain( pxIOManager, &xError ); + + /* Give all entries a proper time stamp, looks nicer than 1 Jan 1970 */ + #if( ffconfigTIME_SUPPORT != 0 ) + { + FF_GetSystemTime( &xMyDirectory.xCreateTime ); + FF_GetSystemTime( &xMyDirectory.xModifiedTime ); + } + #endif + + if( FF_isERR( xError ) ) + { + break; + } + if( xMyDirectory.ulObjectCluster == 0UL ) + { + /* Couldn't allocate any space for the dir! */ + xError = ( FF_Error_t ) ( FF_ERR_DIR_EXTEND_FAILED | FF_MKDIR ); + break; + } + + xError = FF_ClearCluster( pxIOManager, xMyDirectory.ulObjectCluster ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_CreateDirent( pxIOManager, &xFindParams, &xMyDirectory ); + } + + if( FF_isERR( xError ) ) + { + FF_LockFAT( pxIOManager ); + { + FF_UnlinkClusterChain( pxIOManager, xMyDirectory.ulObjectCluster, 0 ); + } + FF_UnlockFAT( pxIOManager ); + FF_FlushCache( pxIOManager ); /* Don't override error. */ + break; + } + + /* Write 8.3 entry "." */ + pucEntryBuffer[ 0 ] = '.'; + /* folowed by 10 spaces: */ + memset( pucEntryBuffer + 1, ' ', 10 ); + /* Clear the rest of the structure. */ + memset( pucEntryBuffer + 11, 0, FF_SIZEOF_DIRECTORY_ENTRY - 11 ); + + ulObjectCluster = xMyDirectory.ulObjectCluster; + xError = FF_PutEntry( pxIOManager, ( uint16_t ) 0u, ulObjectCluster, &xMyDirectory, pucEntryBuffer ); + + if( FF_isERR( xError ) == pdFALSE ) + { + pucEntryBuffer[ 1 ] = '.'; + + if( xFindParams.ulDirCluster == pxIOManager->xPartition.ulRootDirCluster ) + { + xMyDirectory.ulObjectCluster = 0; + } + else + { + xMyDirectory.ulObjectCluster = xFindParams.ulDirCluster; + } + xError = FF_PutEntry( pxIOManager, 1u, ulObjectCluster, &xMyDirectory, pucEntryBuffer ); + + xMyDirectory.ulObjectCluster = ulObjectCluster; + } + + if( FF_isERR( xError ) ) + { + FF_LockFAT( pxIOManager ); + { + FF_UnlinkClusterChain( pxIOManager, xMyDirectory.ulObjectCluster, 0 ); + } + FF_UnlockFAT( pxIOManager ); + } + FF_FlushCache( pxIOManager ); + } + while( pdFALSE ); + + return xError; +} /* FF_MkDir() */ +/*-----------------------------------------------------------*/ + + +FF_Error_t FF_RmLFNs( FF_IOManager_t *pxIOManager, uint16_t usDirEntry, FF_FetchContext_t *pxContext ) +{ +FF_Error_t xError = FF_ERR_NONE; +uint8_t pucEntryBuffer[ FF_SIZEOF_DIRECTORY_ENTRY ]; + + if( usDirEntry != 0 ) + { + usDirEntry--; + + do + { + xError = FF_FetchEntryWithContext( pxIOManager, usDirEntry, pxContext, pucEntryBuffer ); + if( FF_isERR( xError ) ) + { + break; + } + + if( FF_getChar( pucEntryBuffer, ( uint16_t )( FF_FAT_DIRENT_ATTRIB ) ) == FF_FAT_ATTR_LFN ) + { + FF_putChar( pucEntryBuffer, ( uint16_t ) 0, ( uint8_t ) FF_FAT_DELETED ); + xError = FF_PushEntryWithContext( pxIOManager, usDirEntry, pxContext, pucEntryBuffer ); + if( FF_isERR( xError ) ) + { + break; + } + } + + if( usDirEntry == 0 ) + { + break; + } + usDirEntry--; + } while( FF_getChar( pucEntryBuffer, ( uint16_t )( FF_FAT_DIRENT_ATTRIB ) ) == FF_FAT_ATTR_LFN ); + } + + return xError; +} /* FF_RmLFNs() */ +/*-----------------------------------------------------------*/ + +#if( ffconfigHASH_CACHE != 0 ) + FF_Error_t FF_HashDir( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster ) + { + /* Find most suitable Hash Table to replace! */ + BaseType_t xIndex; + FF_HashTable_t *pxHashCache = NULL; + FF_FetchContext_t xFetchContext; + const uint8_t *pucEntryBuffer = NULL; + uint8_t ucAttrib; + uint32_t ulHash; + FF_Error_t xError; + + for( xIndex = 0; xIndex < ffconfigHASH_CACHE_DEPTH; xIndex++ ) + { + if( pxIOManager->xHashCache[ xIndex ].ulNumHandles == 0 ) + { + if( pxHashCache == NULL ) + { + pxHashCache = &pxIOManager->xHashCache[ xIndex ]; + } + else + { + if( ( pxIOManager->xHashCache[ xIndex ].ulMisses > pxHashCache->ulMisses ) ) + { + pxHashCache = &pxIOManager->xHashCache[ xIndex ]; + } + } + } + } + + if( pxHashCache != NULL ) + { + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_T_WCHAR pcMyShortName[ 13 ]; + #else + char pcMyShortName[ 13 ]; + #endif + /* Clear the hash table! */ + memset( pxHashCache, '\0', sizeof( *pxHashCache ) ); + pxHashCache->ulDirCluster = ulDirCluster; + pxHashCache->ulMisses = 0; + + /* Hash the directory! */ + + xError = FF_InitEntryFetch( pxIOManager, ulDirCluster, &xFetchContext ); + + if( FF_isERR( xError ) == pdFALSE ) + { + for( xIndex = 0; xIndex < FF_MAX_ENTRIES_PER_DIRECTORY; xIndex++ ) + { + if( ( pucEntryBuffer == NULL ) || + ( pucEntryBuffer >= xFetchContext.pxBuffer->pucBuffer + ( FF_SIZEOF_SECTOR - FF_SIZEOF_DIRECTORY_ENTRY ) ) ) + { + xError = FF_FetchEntryWithContext( pxIOManager, ( uint32_t ) xIndex, &xFetchContext, NULL ); + if( FF_isERR( xError ) ) + { + break; + } + pucEntryBuffer = xFetchContext.pxBuffer->pucBuffer; + } + else + { + /* Advance the pointer 32 bytes to the next directory entry. */ + pucEntryBuffer += FF_SIZEOF_DIRECTORY_ENTRY; + } + if( FF_isDeleted( pucEntryBuffer ) == pdFALSE ) + { + ucAttrib = FF_getChar( pucEntryBuffer, FF_FAT_DIRENT_ATTRIB ); + if( ( ( ucAttrib & FF_FAT_ATTR_LFN ) != FF_FAT_ATTR_LFN ) && + ( ( ucAttrib & FF_FAT_ATTR_VOLID ) != FF_FAT_ATTR_VOLID ) ) + { + memcpy ( pcMyShortName, pucEntryBuffer, 11 ); + FF_ProcessShortName( pcMyShortName ); + if( FF_isEndOfDir( pucEntryBuffer ) ) + { + break; + } + + /* Generate the Hash. */ + #if( ffconfigHASH_FUNCTION == CRC16 ) + { + ulHash = FF_GetCRC16( ( uint8_t * ) pcMyShortName, strlen( pcMyShortName ) ); + } + #else /* ffconfigHASH_FUNCTION == CRC8 */ + { + ulHash = FF_GetCRC8( pcMyShortName, strlen( pcMyShortName ) ); + } + #endif + FF_SetHash( pxHashCache, ulHash ); + } + } + } /* for( xIndex = 0; xIndex < FF_MAX_ENTRIES_PER_DIRECTORY; xIndex++ ) */ + { + FF_Error_t xTempError; + xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + } + } /* if( pxHashCache != NULL ) */ + else + { + xError = -1; + } + + return xError; + } /* FF_HashDir() */ +#endif /* ffconfigHASH_CACHE != 0 */ +/*-----------------------------------------------------------*/ + +#if( ffconfigHASH_CACHE != 0 ) + /* FF_UnHashDir() : invalidate the hash tables of a given directory. + It is called when a file or sub-directory is removed or when the + directory itself is removed. */ + void FF_UnHashDir( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster ) + { + FF_HashTable_t *pxHash = pxIOManager->xHashCache; + FF_HashTable_t *pxLast = pxIOManager->xHashCache + ffconfigHASH_CACHE_DEPTH; + + for( ; pxHash < pxLast; pxHash++ ) + { + if( pxHash->ulDirCluster == ulDirCluster ) + { + pxHash->ulDirCluster = 0; + break; + } + } + } /* FF_UnHashDir() */ +#endif /* ffconfigHASH_CACHE */ +/*-----------------------------------------------------------*/ + +#if( ffconfigHASH_CACHE != 0 ) + /** + * + * + **/ + void FF_SetHash( FF_HashTable_t *pxHash, uint32_t ulHash ) + { + uint32_t tblIndex = ( ulHash / 32 ) % FF_HASH_TABLE_ENTRY_COUNT; + uint32_t tblBit = ulHash % 32; + + pxHash->ulBitTable[ tblIndex ] |= ( 0x80000000ul >> tblBit ); + } /* FF_SetHash() */ +#endif /* ffconfigHASH_CACHE */ +/*-----------------------------------------------------------*/ + +#if( ffconfigHASH_CACHE != 0 ) + void FF_ClearHash( FF_HashTable_t *pxHash, uint32_t ulHash ) + { + if( pxHash != NULL ) + { + uint32_t tblIndex = ( ulHash / 32 ) % FF_HASH_TABLE_ENTRY_COUNT; + uint32_t tblBit = ulHash % 32; + + pxHash->ulBitTable[ tblIndex ] &= ~( 0x80000000ul >> tblBit ); + } + } /* FF_ClearHash() */ +#endif /* ffconfigHASH_CACHE */ +/*-----------------------------------------------------------*/ + +#if( ffconfigHASH_CACHE != 0 ) + BaseType_t FF_isHashSet( FF_HashTable_t *pxHash, uint32_t ulHash ) + { + FF_Error_t xResult; + + xResult = pdFALSE; + + if( pxHash != NULL ) + { + uint32_t tblIndex = ( ulHash / 32 ) % FF_HASH_TABLE_ENTRY_COUNT; + uint32_t tblBit = ulHash % 32; + + if( pxHash->ulBitTable[ tblIndex ] & ( 0x80000000ul >> tblBit ) ) + { + xResult = pdTRUE; + } + } + + return xResult; + } /* FF_isHashSet() */ +#endif /* ffconfigHASH_CACHE */ +/*-----------------------------------------------------------*/ + +#if( ffconfigHASH_CACHE != 0 ) + void FF_AddDirentHash( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, uint32_t ulHash ) + { + FF_HashTable_t *pxHash = pxIOManager->xHashCache; + FF_HashTable_t *pxLast = pxIOManager->xHashCache + ffconfigHASH_CACHE_DEPTH; + + for( ; pxHash < pxLast; pxHash++ ) + { + if( pxHash->ulDirCluster == ulDirCluster ) + { + FF_SetHash( pxHash, ulHash ); + break; + } + } + } /* FF_AddDirentHash() */ +#endif /* ffconfigHASH_CACHE*/ +/*-----------------------------------------------------------*/ + +#if( ffconfigHASH_CACHE != 0 ) + BaseType_t FF_CheckDirentHash( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, uint32_t ulHash ) + { + FF_HashTable_t *pxHash = pxIOManager->xHashCache; + FF_HashTable_t *pxLast = pxIOManager->xHashCache + ffconfigHASH_CACHE_DEPTH; + BaseType_t xResult; + + for( ; ; ) + { + if( pxHash->ulDirCluster == ulDirCluster ) + { + xResult = FF_isHashSet( pxHash, ulHash ); + break; + } + pxHash++; + if( pxHash >= pxLast ) + { + xResult = -1; + break; + } + } + + return xResult; + } /* FF_CheckDirentHash() */ +#endif /* ffconfigHASH_CACHE */ +/*-----------------------------------------------------------*/ + +#if( ffconfigHASH_CACHE != 0 ) + BaseType_t FF_DirHashed( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster ) + { + FF_HashTable_t *pxHash = pxIOManager->xHashCache; + FF_HashTable_t *pxLast = pxIOManager->xHashCache + ffconfigHASH_CACHE_DEPTH; + BaseType_t xResult; + + for( ; ; ) + { + if( pxHash->ulDirCluster == ulDirCluster ) + { + xResult = pdTRUE; + break; + } + pxHash++; + if( pxHash >= pxLast ) + { + xResult = pdFALSE; + break; + } + } + + return xResult; + } /* FF_DirHashed() */ +#endif /* ffconfigHASH_CACHE */ +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_error.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_error.c new file mode 100644 index 000000000..7df1a6aa7 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_error.c @@ -0,0 +1,311 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_error.c + * @ingroup ERROR + * + * @defgroup ERR Error Message + * @brief Used to return human readable strings for FreeRTOS+FAT error codes. + * + **/ +#include + +/* _HT_ with the new GNU settings, the prototype of [v]snprintf() +is not included in stdio.h Don't know why. */ +int snprintf( char *, size_t, const char *, ... ); + +#include "ff_headers.h" + +#if !defined( ARRAY_SIZE ) + #define ARRAY_SIZE( x ) ( int )( sizeof( x )/sizeof( x )[ 0 ] ) +#endif + + +/* This if-block spans the rest of the source file.*/ +#if( ffconfigDEBUG != 0 ) + +const struct _FFMODULETAB +{ + const char * const strModuleName; + const uint8_t ucModuleID; +} xFreeRTOSFATModuleTable[] = +{ + { "Unknown Module", 1}, /* 1 here is ok, as the GetError functions start at the end of the table. */ + { "ff_ioman.c", FF_GETMODULE( FF_MODULE_IOMAN ) }, + { "ff_dir.c", FF_GETMODULE( FF_MODULE_DIR ) }, + { "ff_file.c", FF_GETMODULE( FF_MODULE_FILE ) }, + { "ff_fat.c", FF_GETMODULE( FF_MODULE_FAT ) }, + { "ff_crc.c", FF_GETMODULE( FF_MODULE_CRC ) }, + { "ff_format.c", FF_GETMODULE( FF_MODULE_FORMAT ) }, + { "ff_memory.c", FF_GETMODULE( FF_MODULE_MEMORY ) }, + { "ff_string.c", FF_GETMODULE( FF_MODULE_STRING ) }, + { "ff_locking.c", FF_GETMODULE( FF_MODULE_LOCKING ) }, + { "ff_time.c", FF_GETMODULE( FF_MODULE_TIME ) }, + { "Platform Driver", FF_GETMODULE( FF_MODULE_DRIVER ) }, +}; + +#if( ffconfigHAS_FUNCTION_TAB != 0 ) +const struct _FFFUNCTIONTAB +{ + const char * const strFunctionName; + const uint16_t ucFunctionID; +} xFreeRTOSFATFunctionTable[] = +{ + { "Unknown Function", 1}, +/*----- FF_IOManager_t - The FreeRTOS+FAT I/O Manager */ + { "FF_CreateIOManger", FF_GETMOD_FUNC( FF_CREATEIOMAN ) }, + { "FF_DeleteIOManager", FF_GETMOD_FUNC( FF_DESTROYIOMAN ) }, + { "FF_Mount", FF_GETMOD_FUNC( FF_MOUNT ) }, + { "FF_Unmount", FF_GETMOD_FUNC( FF_UNMOUNT ) }, + { "FF_FlushCache", FF_GETMOD_FUNC( FF_FLUSHCACHE ) }, + { "FF_GetPartitionBlockSize", FF_GETMOD_FUNC( FF_GETPARTITIONBLOCKSIZE ) }, + { "FF_BlockRead", FF_GETMOD_FUNC( FF_BLOCKREAD ) }, + { "FF_BlockWrite", FF_GETMOD_FUNC( FF_BLOCKWRITE ) }, + { "FF_DetermineFatType", FF_GETMOD_FUNC( FF_DETERMINEFATTYPE ) }, + { "FF_GetEfiPartitionEntry", FF_GETMOD_FUNC( FF_GETEFIPARTITIONENTRY ) }, + { "FF_UserDriver", FF_GETMOD_FUNC( FF_USERDRIVER ) }, + { "FF_DecreaseFreeClusters", FF_GETMOD_FUNC( FF_DECREASEFREECLUSTERS ) }, + { "FF_IncreaseFreeClusters", FF_GETMOD_FUNC( FF_INCREASEFREECLUSTERS ) }, + { "FF_PartitionSearch", FF_GETMOD_FUNC( FF_PARTITIONSEARCH ) }, + { "FF_ParseExtended", FF_GETMOD_FUNC( FF_PARSEEXTENDED ) }, + + +/*----- FF_DIR - The FreeRTOS+FAT directory handling routines */ + { "FF_FetchEntryWithContext", FF_GETMOD_FUNC( FF_FETCHENTRYWITHCONTEXT ) }, + { "FF_PushEntryWithContext", FF_GETMOD_FUNC( FF_PUSHENTRYWITHCONTEXT ) }, + { "FF_GetEntry", FF_GETMOD_FUNC( FF_GETENTRY ) }, + { "FF_FindFirst", FF_GETMOD_FUNC( FF_FINDFIRST ) }, + { "FF_FindNext", FF_GETMOD_FUNC( FF_FINDNEXT ) }, + { "FF_RewindFind", FF_GETMOD_FUNC( FF_REWINDFIND ) }, + { "FF_FindFreeDirent", FF_GETMOD_FUNC( FF_FINDFREEDIRENT ) }, + { "FF_PutEntry", FF_GETMOD_FUNC( FF_PUTENTRY ) }, + { "FF_CreateShortName", FF_GETMOD_FUNC( FF_CREATESHORTNAME ) }, + { "FF_CreateLFNs", FF_GETMOD_FUNC( FF_CREATELFNS ) }, + { "FF_ExtendDirectory", FF_GETMOD_FUNC( FF_EXTENDDIRECTORY ) }, + { "FF_MkDir", FF_GETMOD_FUNC( FF_MKDIR ) }, + { "FF_Traverse", FF_GETMOD_FUNC( FF_TRAVERSE ) }, + { "FF_FindDir", FF_GETMOD_FUNC( FF_FINDDIR ) }, + +/*----- FF_FILE - The FreeRTOS+FAT file handling routines */ + { "FF_GetModeBits", FF_GETMOD_FUNC( FF_GETMODEBITS ) }, + { "FF_Open", FF_GETMOD_FUNC( FF_OPEN ) }, + { "FF_isDirEmpty", FF_GETMOD_FUNC( FF_ISDIREMPTY ) }, + { "FF_RmDir", FF_GETMOD_FUNC( FF_RMDIR ) }, + { "FF_RmFile", FF_GETMOD_FUNC( FF_RMFILE ) }, + { "FF_Move", FF_GETMOD_FUNC( FF_MOVE ) }, + { "FF_isEOF", FF_GETMOD_FUNC( FF_ISEOF ) }, + { "FF_GetSequentialClusters", FF_GETMOD_FUNC( FF_GETSEQUENTIALCLUSTERS ) }, + { "FF_ReadClusters", FF_GETMOD_FUNC( FF_READCLUSTERS ) }, + { "FF_ExtendFile", FF_GETMOD_FUNC( FF_EXTENDFILE ) }, + { "FF_WriteClusters", FF_GETMOD_FUNC( FF_WRITECLUSTERS ) }, + { "FF_Read", FF_GETMOD_FUNC( FF_READ ) }, + { "FF_GetC", FF_GETMOD_FUNC( FF_GETC ) }, + { "FF_GetLine", FF_GETMOD_FUNC( FF_GETLINE ) }, + { "FF_Tell", FF_GETMOD_FUNC( FF_TELL ) }, + { "FF_Write", FF_GETMOD_FUNC( FF_WRITE ) }, + { "FF_PutC", FF_GETMOD_FUNC( FF_PUTC ) }, + { "FF_Seek", FF_GETMOD_FUNC( FF_SEEK ) }, + { "FF_Invalidate", FF_GETMOD_FUNC( FF_INVALIDATE ) }, + { "FF_CheckValid", FF_GETMOD_FUNC( FF_CHECKVALID ) }, + { "FF_Close", FF_GETMOD_FUNC( FF_CLOSE ) }, + { "FF_SetTime", FF_GETMOD_FUNC( FF_SETTIME ) }, + { "FF_BytesLeft", FF_GETMOD_FUNC( FF_BYTESLEFT ) }, + { "FF_SetFileTime", FF_GETMOD_FUNC( FF_SETFILETIME ) }, + { "FF_InitBuf", FF_GETMOD_FUNC( FF_INITBUF ) }, + +/*----- FF_FAT - The FreeRTOS+FAT FAT handling routines */ + { "FF_getFATEntry", FF_GETMOD_FUNC( FF_GETFATENTRY ) }, + { "FF_ClearCluster", FF_GETMOD_FUNC( FF_CLEARCLUSTER ) }, + { "FF_putFATEntry", FF_GETMOD_FUNC( FF_PUTFATENTRY ) }, + { "FF_FindFreeCluster", FF_GETMOD_FUNC( FF_FINDFREECLUSTER ) }, + { "FF_CountFreeClusters", FF_GETMOD_FUNC( FF_COUNTFREECLUSTERS ) }, + +/*----- FF_UNICODE - The FreeRTOS+FAT hashing routines */ + { "FF_Utf8ctoUtf16c", FF_GETMOD_FUNC( FF_UTF8CTOUTF16C ) }, + { "FF_Utf16ctoUtf8c", FF_GETMOD_FUNC( FF_UTF16CTOUTF8C ) }, + { "FF_Utf32ctoUtf16c", FF_GETMOD_FUNC( FF_UTF32CTOUTF16C ) }, + { "FF_Utf16ctoUtf32c", FF_GETMOD_FUNC( FF_UTF16CTOUTF32C ) }, + +/*----- FF_FORMAT - The FreeRTOS+FAT format routine */ + { "FF_FormatPartition", FF_GETMOD_FUNC( FF_FORMATPARTITION ) }, + +/*----- FF_STDIO - The FreeRTOS+FAT stdio front-end */ + { "ff_chmod", FF_GETMOD_FUNC( FF_CHMOD ) }, + { "ff_stat", FF_GETMOD_FUNC( FF_STAT_FUNC ) }, +}; +#endif /* ffconfigHAS_FUNCTION_TAB */ + +#define TPASTE2( a, b ) a##b + +#if( ffconfigLONG_ERR_MSG != 0 ) + /* To get the full error msg: "Not enough memory (malloc( ) returned NULL )" */ + #define ERR_ENTRY( M, E ) { M, TPASTE2( FF_ERR_, E ) } +#else + /* To get a shorter msg: "NOT_ENOUGH_MEMORY" */ + #define ERR_ENTRY( M, E ) { #E, TPASTE2( FF_ERR_, E ) } +#endif /* ffconfigLONG_ERR_MSG */ + +const struct _FFERRTAB +{ + const char * const strErrorString; + const uint8_t ucErrorCode; /* Currently there are less then 256 errors, so lets keep this table small. */ +} xFreeRTOSFATErrorTable[] = +{ + {"Unknown or Generic Error!", 1}, + ERR_ENTRY( "No Error", NONE ), + ERR_ENTRY( "Null Pointer provided, (probably for IOMAN)", NULL_POINTER ), + ERR_ENTRY( "Not enough memory (malloc() returned NULL)", NOT_ENOUGH_MEMORY ), + ERR_ENTRY( "Device Driver returned a FATAL error!", DEVICE_DRIVER_FAILED ), + ERR_ENTRY( "The blocksize is not 512 multiple", IOMAN_BAD_BLKSIZE ), + ERR_ENTRY( "The memory size, is not a multiple of the blocksize. (Atleast 2 Blocks)", IOMAN_BAD_MEMSIZE ), + ERR_ENTRY( "Device is already registered, use FF_UnregisterBlkDevice() first", IOMAN_DEV_ALREADY_REGD ), + ERR_ENTRY( "No mountable partition was found on the specified device", IOMAN_NO_MOUNTABLE_PARTITION ), + ERR_ENTRY( "The format of the MBR was unrecognised", IOMAN_INVALID_FORMAT ), + ERR_ENTRY( "The provided partition number is out-of-range (0 - 3)", IOMAN_INVALID_PARTITION_NUM ), + ERR_ENTRY( "The selected partition / volume doesn't appear to be FAT formatted", IOMAN_NOT_FAT_FORMATTED ), + ERR_ENTRY( "Cannot register device. (BlkSize not a multiple of 512)", IOMAN_DEV_INVALID_BLKSIZE ), + ERR_ENTRY( "Cannot unregister device, a partition is still mounted", IOMAN_PARTITION_MOUNTED ), + ERR_ENTRY( "Cannot unmount the partition while there are active FILE handles", IOMAN_ACTIVE_HANDLES ), + ERR_ENTRY( "The GPT partition header appears to be corrupt, refusing to mount", IOMAN_GPT_HEADER_CORRUPT ), + ERR_ENTRY( "Disk full", IOMAN_NOT_ENOUGH_FREE_SPACE ), + ERR_ENTRY( "Attempted to Read a sector out of bounds", IOMAN_OUT_OF_BOUNDS_READ ), + ERR_ENTRY( "Attempted to Write a sector out of bounds", IOMAN_OUT_OF_BOUNDS_WRITE ), + ERR_ENTRY( "I/O driver is busy", IOMAN_DRIVER_BUSY ), + ERR_ENTRY( "I/O driver returned fatal error", IOMAN_DRIVER_FATAL_ERROR ), + ERR_ENTRY( "I/O driver returned \"no medium error\"", IOMAN_DRIVER_NOMEDIUM ), + + ERR_ENTRY( "Cannot open the file, file already in use", FILE_ALREADY_OPEN ), + ERR_ENTRY( "The specified file could not be found", FILE_NOT_FOUND ), + ERR_ENTRY( "Cannot open a Directory", FILE_OBJECT_IS_A_DIR ), + ERR_ENTRY( "Cannot open for writing: File is marked as Read-Only", FILE_IS_READ_ONLY ), + ERR_ENTRY( "Path not found", FILE_INVALID_PATH ), + ERR_ENTRY( "File operation failed - the file was not opened for writing", FILE_NOT_OPENED_IN_WRITE_MODE ), + ERR_ENTRY( "File operation failed - the file was not opened for reading", FILE_NOT_OPENED_IN_READ_MODE ), + ERR_ENTRY( "File operation failed - could not extend file", FILE_EXTEND_FAILED ), + ERR_ENTRY( "Destination file already exists", FILE_DESTINATION_EXISTS ), + ERR_ENTRY( "Source file was not found", FILE_SOURCE_NOT_FOUND ), + ERR_ENTRY( "Destination path (dir) was not found", FILE_DIR_NOT_FOUND ), + ERR_ENTRY( "Failed to create the directory Entry", FILE_COULD_NOT_CREATE_DIRENT ), + ERR_ENTRY( "A file handle was invalid", FILE_BAD_HANDLE ), +#if( ffconfigREMOVABLE_MEDIA != 0 ) + ERR_ENTRY( "File handle got invalid because media was removed", FILE_MEDIA_REMOVED ), +#endif /* ffconfigREMOVABLE_MEDIA */ + ERR_ENTRY( "A file or folder of the same name already exists", DIR_OBJECT_EXISTS ), + ERR_ENTRY( "DIR_DIRECTORY_FULL", DIR_DIRECTORY_FULL ), + ERR_ENTRY( "DIR_END_OF_DIR", DIR_END_OF_DIR ), + ERR_ENTRY( "The directory is not empty", DIR_NOT_EMPTY ), + ERR_ENTRY( "Could not extend File or Folder - No Free Space!", FAT_NO_FREE_CLUSTERS ), + ERR_ENTRY( "Could not find the directory specified by the path", DIR_INVALID_PATH ), + ERR_ENTRY( "The Root Dir is full, and cannot be extended on Fat12 or 16 volumes", DIR_CANT_EXTEND_ROOT_DIR ), + ERR_ENTRY( "Not enough space to extend the directory.", DIR_EXTEND_FAILED ), + ERR_ENTRY( "Name exceeds the number of allowed characters for a filename", DIR_NAME_TOO_LONG ), + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + ERR_ENTRY( "An invalid Unicode character was provided!", UNICODE_INVALID_CODE ), + ERR_ENTRY( "Not enough space in the UTF-16 buffer to encode the entire sequence", UNICODE_DEST_TOO_SMALL ), + ERR_ENTRY( "An invalid UTF-16 sequence was encountered", UNICODE_INVALID_SEQUENCE ), + ERR_ENTRY( "Filename exceeds MAX long-filename length when converted to UTF-16", UNICODE_CONVERSION_EXCEEDED ), +#endif /* ffconfigUNICODE_UTF16_SUPPORT */ +}; + +/** + * @public + * @brief Returns a pointer to a string relating to a FreeRTOS+FAT error code. + * + * @param iErrorCode The error code. + * + * @return Pointer to a string describing the error. + * + **/ +const char *FF_GetErrMessage( FF_Error_t iErrorCode ) +{ + uint32_t stCount = ARRAY_SIZE( xFreeRTOSFATErrorTable ); + + while( stCount-- ) + { + if( ( ( UBaseType_t )xFreeRTOSFATErrorTable[ stCount ].ucErrorCode ) == FF_GETERROR( iErrorCode ) ) + { + break; + } + } + return xFreeRTOSFATErrorTable[ stCount ].strErrorString; +} + +const char *FF_GetErrModule( FF_Error_t iErrorCode ) +{ + uint32_t stCount = ARRAY_SIZE( xFreeRTOSFATModuleTable ); + while( stCount-- ) + { + if( xFreeRTOSFATModuleTable[ stCount ].ucModuleID == ( uint8_t )FF_GETMODULE( iErrorCode ) ) + { + break; + } + } + return xFreeRTOSFATModuleTable[ stCount ].strModuleName; +} + +#if( ffconfigHAS_FUNCTION_TAB != 0 ) + const char *FF_GetErrFunction( FF_Error_t iErrorCode ) + { + uint32_t stCount = ARRAY_SIZE( xFreeRTOSFATFunctionTable ); + uint16_t ModuleFunc = FF_GETMOD_FUNC( iErrorCode ); + static char funcCode[32]; + while( stCount-- != 0 ) + { + if( xFreeRTOSFATFunctionTable[ stCount ].ucFunctionID == ModuleFunc ) + { + return xFreeRTOSFATFunctionTable[ stCount ].strFunctionName; + } + } + snprintf( funcCode, sizeof( funcCode ), "Func %X", ModuleFunc ); + return ( const char * )funcCode; + } +#endif /* ffconfigHAS_FUNCTION_TAB */ + +const char *FF_GetErrDescription( FF_Error_t iErrorCode, char *apBuf, int aMaxlen ) +{ + if( FF_isERR( iErrorCode ) ) + { +#if( ffconfigHAS_FUNCTION_TAB != 0 ) + snprintf (apBuf, ( size_t ) aMaxlen, "%s::%s::%s", + FF_GetErrModule( iErrorCode ), + FF_GetErrFunction( iErrorCode ), + FF_GetErrMessage( iErrorCode )); +#else + snprintf (apBuf, ( size_t ) aMaxlen, "%s::%s", + FF_GetErrModule( iErrorCode ), + FF_GetErrMessage( iErrorCode )); +#endif /* ffconfigHAS_FUNCTION_TAB */ + } + else + { + snprintf (apBuf, ( size_t ) aMaxlen, "No error"); + } + return apBuf; +} + +#endif /* ffconfigDEBUG != 0 */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_fat.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_fat.c new file mode 100644 index 000000000..258c2a40b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_fat.c @@ -0,0 +1,1546 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_fat.c + * @ingroup FAT + * + * @defgroup FAT Fat File-System + * @brief Handles FAT access and traversal. + * + * Provides file-system interfaces for the FAT file-system. + **/ + +#include "ff_headers.h" +#include + + +#if ffconfigFAT_USES_STAT + /* This module make use of a buffer caching called 'FF_FATBuffers_t'. + * The struct below may gather statistics about its usage: hits/misses. + */ + struct SFatStat fatStat; +#endif /* ffconfigFAT_USES_STAT */ + + +/* prvGetFromFATBuffers() will see if the FF_Buffer_t pointed to by ppxBuffer contains the + * buffer that is needed, i.e. opened for the same sector and with the correct R/W mode. + * If ppxBuffer is NULL or if it can not be used, a new buffer will be created. + * The buffer pointed to by ppxBuffer will either be released or its pointer will be returned. + */ +FF_Buffer_t *prvGetFromFATBuffers( FF_IOManager_t *pxIOManager, FF_FATBuffers_t *pxFATBuffers, BaseType_t xBufferIndex, uint32_t ulFATSector, + FF_Error_t *pxError, uint8_t ucMode ); + +#if( ffconfigFAT12_SUPPORT != 0 ) + /* A very special case for FAT12: an entry is stored in two sectors. + * Read the two sectors and merge the two values found. + */ + static uint32_t prvGetFAT12Entry( FF_IOManager_t *pxIOManager, FF_Error_t *pxError, FF_FATBuffers_t *pxFATBuffers, uint32_t ulFATSector ); +#endif + +#if( ffconfigFAT12_SUPPORT != 0 ) + /* Same as above: put a FAT12 entry that is spread-out over two sectors. + * Read the current value first to preserve and merge the earlier 4 bits + * of an adjacent FAT12 entry. + */ + static FF_Error_t prvPutFAT12Entry( FF_IOManager_t *pxIOManager, uint32_t ulCluster, uint32_t ulValue, FF_FATBuffers_t *pxFATBuffers, + uint32_t ulFATSector ); +#endif + +#if( ffconfigFAT12_SUPPORT != 0 ) + /* A generic less-optimised way of finding the first free cluster. + * Used for FAT12 only. + */ + static uint32_t prvFindFreeClusterSimple( FF_IOManager_t *pxIOManager, FF_Error_t *pxError ); +#endif /* ffconfigFAT12_SUPPORT */ + +#if( ffconfigFAT12_SUPPORT != 0 ) + /* A generic less-optimised way of counting free clusters. + * Used for FAT12 only. + */ + static uint32_t prvCountFreeClustersSimple( FF_IOManager_t *pxIOManager, FF_Error_t *pxError ); +#endif /* ffconfigFAT12_SUPPORT */ + + + +/* Have a cluster number and translate it to an LBA (Logical Block Address). +'ulSectorsPerCluster' should be seen as 'blocks per cluster', where the length of one +block is defined in the PBR (Partition Boot Record) at FF_FAT_BYTES_PER_SECTOR (offset 0x0B). +*/ +uint32_t FF_Cluster2LBA( FF_IOManager_t *pxIOManager, uint32_t ulCluster ) +{ +uint32_t ulLBA = 0; +FF_Partition_t *pxPartition; + + if( pxIOManager != NULL ) + { + pxPartition = &( pxIOManager->xPartition ); + + if( ulCluster >= 2 ) + { + ulLBA = ( ( ulCluster - 2 ) * pxPartition->ulSectorsPerCluster ) + pxPartition->ulFirstDataSector; + } + else + { + ulLBA = pxPartition->ulClusterBeginLBA; + } + } + + return ulLBA; +} +/*-----------------------------------------------------------*/ + +/* + * Major and Minor sectors/blocks: + * + * A cluster is defined as N "sectors". Those sectors in fact are "major blocks" + * whose size is defined in a field called 'FF_FAT_BYTES_PER_SECTOR' in the PBR. + * + * I/O to the disk takes place in "minor block" of usually 512 byte and the addressing + * is also based on "minor block" sector numbers. + * + * In most cases, Major == Minor == 512 bytes. + * + * Here below some translations are done for 'entries', which can be 1-byte entries + * as well as the 32-byte directory entries. + * + */ + +/* Translate an 'entry number' (ulEntry) to a relative cluster number, +where e.g. 'ulEntry' may be a sequence number of a directory entry for +which ulEntrySize = 32 bytes. +*/ +uint32_t FF_getClusterChainNumber( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize ) +{ +uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster; +uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize ); + + /* E.g. ulBytesPerCluster = 16384, ulEntrySize = 32: 16384 / 32 = 512 entries per cluster. */ + return ulEntry / ulEntriesPerCluster; +} +/*-----------------------------------------------------------*/ + +/* If the above function returns a cluster number, this function +returns a BYTE position within that cluster. */ +uint32_t FF_getClusterPosition( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize ) +{ +uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster; +uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize ); + + /* Return the block offset within the current cluster: */ + return ( ulEntry % ulEntriesPerCluster ) * ulEntrySize; +} +/*-----------------------------------------------------------*/ + +/* Return the block offset (= number of major blocks) within the current cluster: */ +uint32_t FF_getMajorBlockNumber( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize ) +{ +uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster; +uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize ); +uint32_t ulRelClusterEntry; + + /* Calculate the entry number within a cluster: */ + ulRelClusterEntry = ulEntry % ulEntriesPerCluster; + + /* Return the block offset within the current cluster: */ + return ulRelClusterEntry / ( pxIOManager->xPartition.usBlkSize / ulEntrySize ); +} +/*-----------------------------------------------------------*/ + +/* Return the minor block number within the current major block */ +uint32_t FF_getMinorBlockNumber( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize ) +{ +uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster; +uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize ); +uint32_t ulRelClusterEntry; +uint32_t ulRelMajorBlockEntry; + + /* Calculate the entry number within a cluster: */ + ulRelClusterEntry = ulEntry % ulEntriesPerCluster; + + ulRelMajorBlockEntry = ulRelClusterEntry % ( pxIOManager->xPartition.usBlkSize / ulEntrySize ); + + return ulRelMajorBlockEntry / ( pxIOManager->usSectorSize / ulEntrySize ); +} +/*-----------------------------------------------------------*/ + +/* Get the entry number within the minor block */ +uint32_t FF_getMinorBlockEntry( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize ) +{ +uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster; +uint32_t ulEntriesPerCluster = ( ulBytesPerCluster / ulEntrySize ); +uint32_t ulRelClusterEntry; +uint32_t ulRelMajorBlockEntry; + + /* Calculate the entry number within a cluster: */ + ulRelClusterEntry = ulEntry % ulEntriesPerCluster; + + ulRelMajorBlockEntry = ulRelClusterEntry % ( pxIOManager->xPartition.usBlkSize / ulEntrySize ); + + return ulRelMajorBlockEntry % ( pxIOManager->usSectorSize / ulEntrySize ); +} +/*-----------------------------------------------------------*/ + +FF_Error_t FF_ReleaseFATBuffers( FF_IOManager_t *pxIOManager, FF_FATBuffers_t *pxFATBuffers ) +{ +BaseType_t xIndex; +FF_Error_t xError = FF_ERR_NONE; +FF_Buffer_t *pxBuffer; +#if ffconfigBUF_STORE_COUNT != 2 + #warning Only maintaining one FAT table +#endif + /* 'ffconfigBUF_STORE_COUNT' equals to the number of FAT tables. */ + for( xIndex = 0; xIndex < ffconfigBUF_STORE_COUNT; xIndex++ ) + { + pxBuffer = pxFATBuffers->pxBuffers[ xIndex ]; + if( pxBuffer != NULL ) + { + FF_Error_t xTempError = FF_ERR_NONE; + + pxFATBuffers->pxBuffers[ xIndex ] = NULL; + xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + if( FF_isERR( xError ) == pdFALSE ) + { + /* as everywhere, this function will return + the first error that occurred, if any. */ + xError = xTempError; + } + } + } + #if ffconfigFAT_USES_STAT + { + fatStat.clearCount++; + } + #endif /* ffconfigFAT_USES_STAT */ + + return xError; +} +/*-----------------------------------------------------------*/ + +FF_Buffer_t *prvGetFromFATBuffers( FF_IOManager_t *pxIOManager, FF_FATBuffers_t *pxFATBuffers, BaseType_t xBufferIndex, + uint32_t ulFATSector, FF_Error_t *pxError, uint8_t ucMode ) +{ +FF_Error_t xError = FF_ERR_NONE; +FF_Buffer_t *pxBuffer = NULL; + + if( pxFATBuffers != NULL ) + { + /* See if the same buffer can be reused. */ + pxBuffer = pxFATBuffers->pxBuffers[ xBufferIndex ]; + + if( pxBuffer != NULL ) + { + /* Now the buffer is either owned by pxBuffer, + or it has been released, so put it to NULL. */ + pxFATBuffers->pxBuffers[ xBufferIndex ] = NULL; + + if( + ( pxBuffer->ulSector == ulFATSector ) && + ( ( ( ucMode & FF_MODE_WRITE ) == 0 ) || + ( ( pxBuffer->ucMode & FF_MODE_WRITE ) != 0 ) ) + ) + { + /* Same sector, AND + write-permission is not required OR the buffer has write permission: + it can be reused. */ + #if ffconfigFAT_USES_STAT + { + fatStat.reuseCount[ ( ucMode & FF_MODE_WRITE ) ? 1 : 0 ]++; + } + #endif /* ffconfigFAT_USES_STAT */ + } + else + { + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + pxBuffer = NULL; + #if ffconfigFAT_USES_STAT + { + fatStat.missCount[ ( ucMode & FF_MODE_WRITE ) ? 1 : 0 ]++; + } + #endif /* ffconfigFAT_USES_STAT */ + } + } + else + { + #if ffconfigFAT_USES_STAT + { + fatStat.getCount[ ( ucMode & FF_MODE_WRITE ) ? 1 : 0 ]++; + } + #endif /* ffconfigFAT_USES_STAT */ + } + } + + if( ( pxBuffer == NULL ) && ( FF_isERR( xError ) == pdFALSE ) ) + { + pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector, ucMode ); + if( pxBuffer == NULL ) + { + /* Setting an error code without the Module/Function, + will be filled-in by the caller. */ + xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_ERRFLAG ); + } + } + *pxError = xError; + + return pxBuffer; +} + +#if( ffconfigFAT12_SUPPORT != 0 ) + /* A very special case for FAT12: an entry is stored in two sectors. + Read the two sectors and merge the two values found. */ + static uint32_t prvGetFAT12Entry( FF_IOManager_t *pxIOManager, FF_Error_t *pxError, FF_FATBuffers_t *pxFATBuffers, + uint32_t ulFATSector ) + { + FF_Error_t xError = FF_ERR_NONE; + FF_Buffer_t *pxBuffer = NULL; + /* preferred buffer access mode, user might want to update this entry + and set it to FF_MODE_WRITE. */ + uint8_t ucMode = pxFATBuffers ? pxFATBuffers->ucMode : FF_MODE_READ; + /* Collect the two bytes in an array. */ + uint8_t ucBytes[ 2 ]; + /* The function return value. */ + uint32_t ulFATEntry = 0UL; + + pxBuffer = prvGetFromFATBuffers( pxIOManager, pxFATBuffers, 0, ulFATSector, &xError, ucMode ); + + if( FF_isERR( xError ) ) + { + xError = FF_GETERROR( xError ) | FF_GETFATENTRY; + } + else + { + /* Fetch the very last byte of this segment. */ + ucBytes[ 0 ] = FF_getChar( pxBuffer->pucBuffer, ( uint16_t ) ( pxIOManager->usSectorSize - 1 ) ); + + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + + /* release the other buffer as well. */ + if( ( FF_isERR( xError ) == pdFALSE ) && ( pxFATBuffers != NULL ) ) + { + xError = FF_ReleaseFATBuffers( pxIOManager, pxFATBuffers ); + } + + if( FF_isERR( xError ) == pdFALSE ) + { + /* Second Buffer get the first Byte in buffer (second byte of out address)! */ + pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector + 1, ucMode ); + if( pxBuffer == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_GETFATENTRY ); + } + else + { + /* Read the first byte from the subsequent sector. */ + ucBytes[ 1 ] = FF_getChar( pxBuffer->pucBuffer, 0 ); + /* And release that buffer. */ + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + if( FF_isERR( xError ) == pdFALSE ) + { + /* Join the two bytes: */ + ulFATEntry = ( uint32_t ) FF_getShort( ( uint8_t * )ucBytes, 0 ); + } + } + } + } + *pxError = xError; + + return ( int32_t ) ulFATEntry; + } +#endif /* ffconfigFAT12_SUPPORT */ +/*-----------------------------------------------------------*/ + + +/* Get a FAT entry, which is nothing more than a number referring to a sector. */ +uint32_t FF_getFATEntry( FF_IOManager_t *pxIOManager, uint32_t ulCluster, FF_Error_t *pxError, FF_FATBuffers_t *pxFATBuffers ) +{ +FF_Buffer_t *pxBuffer = NULL; +uint32_t ulFATOffset; +uint32_t ulFATSector = 0; +uint32_t ulFATSectorEntry; +/* The function result. */ +uint32_t ulFATEntry = 0; +uint32_t ulLBAAdjust; +uint32_t ulRelClusterEntry = 0; +FF_Error_t xError = FF_ERR_NONE; +/* preferred mode, user might want to update this entry. */ +uint8_t ucMode = pxFATBuffers ? pxFATBuffers->ucMode : FF_MODE_READ; + + FF_Assert_Lock( pxIOManager, FF_FAT_LOCK ); + + if( ulCluster >= pxIOManager->xPartition.ulNumClusters ) + { + /* _HT_ find a more specific error code. + Probably not really important as this is a function internal to the library. */ + xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_GETFATENTRY ); + } + else + { + if( pxIOManager->xPartition.ucType == FF_T_FAT32 ) + { + ulFATOffset = ulCluster * 4; + } + else if( pxIOManager->xPartition.ucType == FF_T_FAT16 ) + { + ulFATOffset = ulCluster * 2; + } + else /* pxIOManager->xPartition.ucType == FF_T_FAT12 */ + { + ulFATOffset = ulCluster + ( ulCluster / 2 ); + } + + ulFATSector = pxIOManager->xPartition.ulFATBeginLBA + ( ulFATOffset / pxIOManager->xPartition.usBlkSize ); + ulFATSectorEntry = ulFATOffset % pxIOManager->xPartition.usBlkSize; + + ulLBAAdjust = ulFATSectorEntry / ( ( uint32_t ) pxIOManager->usSectorSize ); + ulRelClusterEntry = ulFATSectorEntry % pxIOManager->usSectorSize; + + ulFATSector = FF_getRealLBA( pxIOManager, ulFATSector ); + ulFATSector += ulLBAAdjust; + } + +#if( ffconfigFAT12_SUPPORT != 0 ) + if( ( pxIOManager->xPartition.ucType == FF_T_FAT12 ) && + ( FF_isERR( xError ) == pdFALSE ) && + ( ulRelClusterEntry == ( uint32_t ) ( ( pxIOManager->usSectorSize - 1 ) ) ) ) + { + /* Fat Entry SPANS a Sector! + It has 4 bits on one sector and 8 bits on the other sector. + Handle this in a separate function prvGetFAT12Entry(). */ + ulFATEntry = prvGetFAT12Entry( pxIOManager, &xError, pxFATBuffers, ulFATSector ); + + if( ( ulCluster & 0x0001 ) != 0 ) + { + /* For odd clusters, shift the address 4 bits to the right: */ + ulFATEntry = ( ulFATEntry & 0xfff0 ) >> 4; + } + else + { + /* For even clusters, take the lower 12 bits: */ + ulFATEntry = ( ulFATEntry & 0x0fff ); + } + /* Return ulFATEntry, unless xError contains an error. */ + } + else +#endif /* ffconfigFAT12_SUPPORT */ + if( FF_isERR( xError ) == pdFALSE ) + { + /* Handle FAT16, FAT32, and FAT12 (in case the entry lies on a single sector). */ + + pxBuffer = prvGetFromFATBuffers( pxIOManager, pxFATBuffers, 0, ulFATSector, &xError, ucMode ); + if( FF_isERR( xError ) ) + { + xError = FF_GETERROR( xError ) | FF_GETFATENTRY; + } + else + { + switch( pxIOManager->xPartition.ucType ) + { + case FF_T_FAT32: + ulFATEntry = FF_getLong( pxBuffer->pucBuffer, ulRelClusterEntry ); + /* Clear the top 4 bits. */ + ulFATEntry &= 0x0fffffff; + break; + case FF_T_FAT16: + ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulRelClusterEntry ); + break; + #if( ffconfigFAT12_SUPPORT != 0 ) + case FF_T_FAT12: + ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulRelClusterEntry ); + /* Entries are either stored as 4 + 8 bits or as 8 + 4 bits, + depending on the cluster being odd or even. */ + if( ( ulCluster & 0x0001 ) != 0 ) + { + /* For odd clusters, shift the address 4 bits to the right: */ + ulFATEntry = ( ulFATEntry & 0xfff0 ) >> 4; + } + else + { + /* For even clusters, take the lower 12 bits: */ + ulFATEntry = ( ulFATEntry & 0x0fff ); + } + break; + #endif + default: + ulFATEntry = 0; + break; + } + + if( pxFATBuffers != NULL ) + { + /* Store the buffer. */ + pxFATBuffers->pxBuffers[ 0 ] = pxBuffer; + } + else + { + /* Or release it. */ + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + } + } /* if( FF_isERR( xError ) == pdFALSE ) */ + } /* else Handle FAT16, FAT32, and FAT12 (in case the entry lies on a single sector). */ + + if( FF_isERR( xError ) ) + { + /* The sector address 0 is not meaningful and here it is used as the 'error value'. */ + ulFATEntry = 0UL; + } + + if( pxError != NULL ) + { + *pxError = xError; + } + + return ( int32_t )ulFATEntry; +} /* FF_getFATEntry() */ +/*-----------------------------------------------------------*/ + +/* Write all zero's to all sectors of a given cluster. */ +FF_Error_t FF_ClearCluster( FF_IOManager_t *pxIOManager, uint32_t ulCluster ) +{ +FF_Error_t xError = FF_ERR_NONE; +FF_Buffer_t *pxBuffer = NULL; +BaseType_t xIndex; +uint32_t ulBaseLBA; + + /* Calculate from cluster number to a real block address. */ + ulBaseLBA = FF_Cluster2LBA( pxIOManager, ulCluster ); + ulBaseLBA = FF_getRealLBA( pxIOManager, ulBaseLBA ); + + for( xIndex = 0; xIndex < ( BaseType_t ) pxIOManager->xPartition.ulSectorsPerCluster; xIndex++ ) + { + if( xIndex == 0 ) + { + /* When using the FF_MODE_WR_ONLY flag, the data will not be read from disk. + Only in the first round a buffer will be claimed. */ + pxBuffer = FF_GetBuffer( pxIOManager, ulBaseLBA, FF_MODE_WR_ONLY ); + if( pxBuffer == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_CLEARCLUSTER ); + break; + } + memset( pxBuffer->pucBuffer, 0x00, pxIOManager->usSectorSize ); + } + + xError = FF_BlockWrite( pxIOManager, ulBaseLBA + xIndex, 1, pxBuffer->pucBuffer, pdFALSE ); + if( FF_isERR( xError ) ) + { + break; + } + } + + if( pxBuffer != NULL ) + { + FF_Error_t xTempError; + + /* The contents of the buffer (all zero's) has been written explicitly to disk + by calling FF_BlockWrite(). Therefore, the bModified should be cleared. */ + pxBuffer->bModified = pdFALSE; + /* Releasing the handle will not write anything */ + xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + + return xError; +} +/*-----------------------------------------------------------*/ + +/** + * @private + * @brief Returns the Cluster address of the Cluster number from the beginning of a chain. + * + * @param pxIOManager FF_IOManager_t Object + * @param ulStart Cluster address of the first cluster in the chain. + * @param ulCount Number of Cluster in the chain, + * + * + * + **/ +uint32_t FF_TraverseFAT( FF_IOManager_t *pxIOManager, uint32_t ulStart, uint32_t ulCount, FF_Error_t *pxError ) +{ +FF_Error_t xError = FF_ERR_NONE; +uint32_t ulIndex; +uint32_t ulFatEntry = ulStart; +uint32_t ulCurrentCluster = ulStart; +FF_FATBuffers_t xFATBuffers; +BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE; + + /* xFATBuffers is nothing more than an array of FF_Buffer_t's. + One buffer for each FAT copy on disk. */ + FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ ); + + if( xTakeLock ) + { + FF_LockFAT( pxIOManager ); + } + for( ulIndex = 0; ulIndex < ulCount; ulIndex++ ) + { + ulFatEntry = FF_getFATEntry( pxIOManager, ulCurrentCluster, &xError, &xFATBuffers ); + if( FF_isERR( xError ) ) + { + ulFatEntry = 0; + break; + } + + if( FF_isEndOfChain( pxIOManager, ulFatEntry ) ) + { + ulFatEntry = ulCurrentCluster; + break; + } + + ulCurrentCluster = ulFatEntry; + } + if( xTakeLock ) + { + FF_UnlockFAT( pxIOManager ); + } + + { + FF_Error_t xTempError; + + xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + + *pxError = xError; + + return ulFatEntry; +} +/*-----------------------------------------------------------*/ + +uint32_t FF_FindEndOfChain( FF_IOManager_t *pxIOManager, uint32_t ulStart, FF_Error_t *pxError ) +{ +uint32_t ulFatEntry = ulStart; +FF_Error_t xError; + + if( FF_isEndOfChain( pxIOManager, ulStart ) == pdFALSE ) + { + /* Traverse FAT for (2^32-1) items/clusters, + or until end-of-chain is encountered. */ + ulFatEntry = FF_TraverseFAT( pxIOManager, ulStart, ~0UL, &xError ); + } + else + { + xError = FF_ERR_NONE; + } + + *pxError = xError; + + return ulFatEntry; +} +/*-----------------------------------------------------------*/ + +/** + * @private + * @brief Tests if the ulFATEntry is an End of Chain Marker. + * + * @param pxIOManager FF_IOManager_t Object + * @param ulFATEntry The fat entry from the FAT table to be checked. + * + * @return pdTRUE if it is an end of chain, otherwise pdFALSE. + * + **/ +BaseType_t FF_isEndOfChain( FF_IOManager_t *pxIOManager, uint32_t ulFATEntry ) +{ +BaseType_t xResult = pdFALSE; + + if( pxIOManager->xPartition.ucType == FF_T_FAT32 ) + { + if( ( ulFATEntry & 0x0fffffff ) >= 0x0ffffff8 ) + { + xResult = pdTRUE; + } + } + else if( pxIOManager->xPartition.ucType == FF_T_FAT16 ) + { + if( ulFATEntry >= 0x0000fff8 ) + { + xResult = pdTRUE; + } + } + else + { + if( ulFATEntry >= 0x00000ff8 ) + { + xResult = pdTRUE; + } + } + + if( ulFATEntry == 0x00000000 ) + { + xResult = pdTRUE; /* Perhaps trying to read a deleted file! */ + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +#if( ffconfigFAT12_SUPPORT != 0 ) + static FF_Error_t prvPutFAT12Entry( FF_IOManager_t *pxIOManager, uint32_t ulCluster, uint32_t ulValue, FF_FATBuffers_t *pxFATBuffers, + uint32_t ulFATSector ) + { + FF_Buffer_t *pxBuffer = NULL; + /* For FAT12 FAT Table Across sector boundary traversal. */ + uint8_t ucBytes[ 2 ]; + /* The function result value. */ + uint32_t ulFATEntry; + FF_Error_t xError = FF_ERR_NONE; + BaseType_t xIndex; + #if( ffconfigWRITE_BOTH_FATS != 0 ) + const BaseType_t xNumFATs = pxIOManager->xPartition.ucNumFATS; + #else + const BaseType_t xNumFATs = 1; + #endif + + /* This routine will only change 12 out of 16 bits. + Get the current 16-bit value, 4 bits shall be preserved. */ + ulFATEntry = prvGetFAT12Entry( pxIOManager, &xError, pxFATBuffers, ulFATSector ); + + if( FF_isERR( xError ) == pdFALSE ) + { + if( ( ulCluster & 0x0001 ) != 0 ) + { + ulFATEntry &= 0x000F; + ulValue = ( ulValue << 4 ); + ulValue &= 0xFFF0; + } + else + { + ulFATEntry &= 0xF000; + ulValue &= 0x0FFF; + } + ulFATEntry |= ulValue; + + /* Write at offset 0 in the array ucBytes. */ + FF_putShort( ucBytes, 0, ( uint16_t ) ulFATEntry ); + + for( xIndex = 0; + xIndex < xNumFATs; + xIndex++, ulFATSector += pxIOManager->xPartition.ulSectorsPerFAT ) + { + /* Write the last byte in the first sector. */ + pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector, FF_MODE_WRITE ); + { + if( pxBuffer == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_PUTFATENTRY ); + break; + } + FF_putChar( pxBuffer->pucBuffer, ( uint16_t )( pxIOManager->usSectorSize - 1 ), ucBytes[ 0 ] ); + } + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + if( FF_isERR( xError ) ) + { + break; + } + + /* Write the first byte in the subsequent sector. */ + pxBuffer = FF_GetBuffer( pxIOManager, ulFATSector + 1, FF_MODE_WRITE ); + { + if( pxBuffer == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_PUTFATENTRY ); + break; + } + FF_putChar( pxBuffer->pucBuffer, 0x0000, ucBytes[ 1 ] ); + } + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + if( FF_isERR( xError ) ) + { + break; + } + } /* for ( xIndex = 0; xIndex < xNumFATs; xIndex++ ) */ + } + + return xError; + } +#endif + +/** + * @private + * @brief Writes a new Entry to the FAT Tables. + * + * @param pxIOManager IOMAN object. + * @param ulCluster Cluster Number to be modified. + * @param ulValue The value to store. + **/ +FF_Error_t FF_putFATEntry( FF_IOManager_t *pxIOManager, uint32_t ulCluster, uint32_t ulValue, FF_FATBuffers_t *pxFATBuffers ) +{ +FF_Buffer_t *pxBuffer; +uint32_t ulFATOffset; +uint32_t ulFATSector = 0; +uint32_t ulFATSectorEntry; +uint32_t ulFATEntry; +uint32_t ulLBAAdjust; +uint32_t ulRelClusterEntry = 0; +BaseType_t xIndex; +FF_Error_t xError = FF_ERR_NONE; +#if( ffconfigWRITE_BOTH_FATS != 0 ) + const BaseType_t xNumFATs = pxIOManager->xPartition.ucNumFATS; +#else + const BaseType_t xNumFATs = 1; +#endif + + + FF_Assert_Lock( pxIOManager, FF_FAT_LOCK ); + + /* Avoid corrupting the disk. */ + if( ( ulCluster == 0ul ) || ( ulCluster >= pxIOManager->xPartition.ulNumClusters ) ) + { + /* find a more specific error code. */ + xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_PUTFATENTRY ); + } + else + { + if( pxIOManager->xPartition.ucType == FF_T_FAT32 ) + { + ulFATOffset = ulCluster * 4; + } + else if( pxIOManager->xPartition.ucType == FF_T_FAT16 ) + { + ulFATOffset = ulCluster * 2; + } + else /* pxIOManager->xPartition.ucType == FF_T_FAT12 */ + { + ulFATOffset = ulCluster + ( ulCluster / 2 ); + } + + ulFATSector = pxIOManager->xPartition.ulFATBeginLBA + ( ulFATOffset / pxIOManager->xPartition.usBlkSize ); + ulFATSectorEntry = ulFATOffset % pxIOManager->xPartition.usBlkSize; + + ulLBAAdjust = ulFATSectorEntry / ( ( uint32_t ) pxIOManager->usSectorSize ); + ulRelClusterEntry = ulFATSectorEntry % pxIOManager->usSectorSize; + + ulFATSector = FF_getRealLBA( pxIOManager, ulFATSector ); + ulFATSector += ulLBAAdjust; + } + +#if( ffconfigFAT12_SUPPORT != 0 ) + if( ( pxIOManager->xPartition.ucType == FF_T_FAT12 ) && + ( FF_isERR( xError ) == pdFALSE ) && + ( ulRelClusterEntry == ( uint32_t ) ( ( pxIOManager->usSectorSize - 1 ) ) ) ) + { + /* The special case in which one FAT12 entries is divided over 2 sectors. + Treat this in a separate function. */ + xError = prvPutFAT12Entry( pxIOManager, ulCluster, ulValue, pxFATBuffers, ulFATSector ); + /* Return xError. */ + } + else +#endif /* ffconfigFAT12_SUPPORT */ + if( FF_isERR( xError ) == pdFALSE ) + { + /* Handle FAT16, FAT32, and FAT12 (in case the entry lies on a single sector). */ + for( xIndex = 0; + xIndex < xNumFATs; + xIndex++, ulFATSector += pxIOManager->xPartition.ulSectorsPerFAT ) + { + pxBuffer = prvGetFromFATBuffers( pxIOManager, pxFATBuffers, xIndex, ulFATSector, &xError, FF_MODE_WRITE ); + + if( FF_isERR( xError ) ) + { + xError = FF_GETERROR( xError ) | FF_PUTFATENTRY; + break; + } + + if( pxIOManager->xPartition.ucType == FF_T_FAT32 ) + { + /* Clear the top 4 bits. */ + ulValue &= 0x0fffffff; + FF_putLong( pxBuffer->pucBuffer, ulRelClusterEntry, ulValue ); + } + else if( pxIOManager->xPartition.ucType == FF_T_FAT16 ) + { + FF_putShort( pxBuffer->pucBuffer, ulRelClusterEntry, ( uint16_t ) ulValue ); + } + else + { + ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulRelClusterEntry ); + if( ( ulCluster & 0x0001 ) != 0 ) + { + ulFATEntry &= 0x000F; + ulValue = ( ulValue << 4 ); + ulValue &= 0xFFF0; + } + else + { + ulFATEntry &= 0xF000; + ulValue &= 0x0FFF; + } + + FF_putShort( pxBuffer->pucBuffer, ulRelClusterEntry, ( uint16_t ) ( ulFATEntry | ulValue ) ); + } + + if( ( xIndex < ffconfigBUF_STORE_COUNT ) && ( pxFATBuffers != NULL ) ) + { + /* Store it for later use. */ + pxFATBuffers->pxBuffers[ xIndex ] = pxBuffer; + pxFATBuffers->ucMode = FF_MODE_WRITE; + } + else + { + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + if( FF_isERR( xError ) ) + { + break; + } + } + } + } + + /* FF_putFATEntry() returns just an error code, not an address. */ + return xError; +} /* FF_putFATEntry() */ +/*-----------------------------------------------------------*/ + +/** + * @private + * @brief Finds a Free Cluster and returns its number. + * + * @param pxIOManager IOMAN Object. + * + * @return The number of the cluster found to be free. + * @return 0 on error. + **/ +#if( ffconfigFAT12_SUPPORT != 0 ) + static uint32_t prvFindFreeClusterSimple( FF_IOManager_t *pxIOManager, FF_Error_t *pxError ) + { + FF_Error_t xError = FF_ERR_NONE; + uint32_t ulCluster = 0; + uint32_t ulFATEntry; + FF_FATBuffers_t xFATBuffers; + + FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ ); + + for( ulCluster = pxIOManager->xPartition.ulLastFreeCluster; + ulCluster < pxIOManager->xPartition.ulNumClusters; + ulCluster++ ) + { + ulFATEntry = FF_getFATEntry( pxIOManager, ulCluster, &xError, &xFATBuffers ); + if( FF_isERR( xError ) ) + { + break; + } + if( ulFATEntry == 0 ) + { + pxIOManager->xPartition.ulLastFreeCluster = ulCluster; + break; + + } + } + { + FF_Error_t xTempError; + + xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + if( ( FF_isERR( xError ) == pdFALSE ) && + ( ulCluster == pxIOManager->xPartition.ulNumClusters ) ) + { + /* There is no free cluster any more. */ + ulCluster = 0; + xError = FF_FINDFREECLUSTER | FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE; + } + + *pxError = xError; + + return ulCluster; + } +#endif +/*-----------------------------------------------------------*/ + +uint32_t FF_FindFreeCluster( FF_IOManager_t *pxIOManager, FF_Error_t *pxError, BaseType_t xDoClaim ) +{ +FF_Error_t xError = FF_ERR_NONE; +FF_Buffer_t *pxBuffer = NULL; +uint32_t x, ulCluster; +uint32_t ulFATSectorEntry; +uint32_t ulEntriesPerSector; +uint32_t ulFATEntry = 1; +const BaseType_t xEntrySize = ( pxIOManager->xPartition.ucType == FF_T_FAT32 ) ? 4 : 2; +const uint32_t uNumClusters = pxIOManager->xPartition.ulNumClusters; + +BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE; + + if( xTakeLock ) + { + FF_LockFAT( pxIOManager ); + } + + ulCluster = pxIOManager->xPartition.ulLastFreeCluster; + +#if( ffconfigFAT12_SUPPORT != 0 ) + /* FAT12 tables are too small to optimise, and would make it very complicated! */ + if( pxIOManager->xPartition.ucType == FF_T_FAT12 ) + { + ulCluster = prvFindFreeClusterSimple( pxIOManager, &xError ); + } + else +#endif + { + #if( ffconfigFSINFO_TRUSTED != 0 ) + { + /* If 'ffconfigFSINFO_TRUSTED', the contents of the field 'ulLastFreeCluster' is trusted. + Only ready it in case of FAT32 and only during the very first time, i.e. when + ulLastFreeCluster is still zero. */ + if( ( pxIOManager->xPartition.ucType == FF_T_FAT32 ) && ( pxIOManager->xPartition.ulLastFreeCluster == 0ul ) ) + { + pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_READ ); + if( pxBuffer == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FINDFREECLUSTER ); + } + else + { + if( ( FF_getLong(pxBuffer->pucBuffer, 0 ) == 0x41615252 ) && + ( FF_getLong(pxBuffer->pucBuffer, 484 ) == 0x61417272 ) ) + { + ulCluster = FF_getLong( pxBuffer->pucBuffer, 492 ); + } + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + pxBuffer = NULL; + } + + } + } + #endif + if( FF_isERR( xError ) == pdFALSE ) + { + uint32_t ulFATSector; + uint32_t ulFATOffset; + + ulEntriesPerSector = pxIOManager->usSectorSize / xEntrySize; + ulFATOffset = ulCluster * xEntrySize; + + /* Start from a sector where the first free entry is expected, + and iterate through every FAT sector. */ + for( ulFATSector = ( ulFATOffset / pxIOManager->xPartition.usBlkSize ); + ulFATSector < pxIOManager->xPartition.ulSectorsPerFAT; + ulFATSector++ ) + { + pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA + ulFATSector, FF_MODE_READ ); + if( pxBuffer == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_FINDFREECLUSTER ); + break; + } + for( x = ( ulCluster % ulEntriesPerSector ); x < ulEntriesPerSector; x++ ) + { + /* Double-check: don't use non-existing clusters */ + if( ulCluster >= uNumClusters ) + { + xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_FINDFREECLUSTER ); + break; + } + ulFATSectorEntry = ulFATOffset % pxIOManager->xPartition.usBlkSize; + if( pxIOManager->xPartition.ucType == FF_T_FAT32 ) + { + ulFATEntry = FF_getLong( pxBuffer->pucBuffer, ulFATSectorEntry ); + /* Clear the top 4 bits. */ + ulFATEntry &= 0x0fffffff; + } + else + { + ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, ulFATSectorEntry ); + } + if( ulFATEntry == 0x00000000 ) + { + /* Break and return 'ulCluster' */ + break; + } + ulFATOffset += xEntrySize; + ulCluster++; + } + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + pxBuffer = NULL; + if( FF_isERR( xError ) ) + { + break; + } + if( ulFATEntry == 0x00000000 ) + { + /* And break from the outer loop. */ + break; + } + } + if( ( FF_isERR( xError ) == pdFALSE ) && + ( ulFATSector == pxIOManager->xPartition.ulSectorsPerFAT ) ) + { + xError = ( FF_Error_t ) ( FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE | FF_FINDFREECLUSTER ); + } + } /* if( FF_isERR( xError ) == pdFALSE ) */ + } /* if( pxIOManager->xPartition.ucType != FF_T_FAT12 ) */ + + if( FF_isERR( xError ) ) + { + ulCluster = 0UL; + } + if( ( ulCluster != 0UL ) && ( xDoClaim != pdFALSE ) ) + { + FF_Error_t xTempError; + + /* Found a free cluster! */ + pxIOManager->xPartition.ulLastFreeCluster = ulCluster + 1; + + xTempError = FF_putFATEntry( pxIOManager, ulCluster, 0xFFFFFFFF, NULL ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + + if( FF_isERR( xError ) ) + { + ulCluster = 0UL; + } + } + if( xTakeLock ) + { + FF_UnlockFAT( pxIOManager ); + } + *pxError = xError; + + return ulCluster; +} /* FF_FindFreeCluster */ +/*-----------------------------------------------------------*/ + +/** + * @private + * @brief Creates a Cluster Chain + * @return > 0 New created cluster + * @return = 0 See pxError + **/ +uint32_t FF_CreateClusterChain( FF_IOManager_t *pxIOManager, FF_Error_t *pxError ) +{ +uint32_t ulStartCluster; +FF_Error_t xError = FF_ERR_NONE; + + FF_LockFAT( pxIOManager ); + { + ulStartCluster = FF_FindFreeCluster( pxIOManager, &xError, pdTRUE ); + } + FF_UnlockFAT( pxIOManager ); + + if( ulStartCluster != 0L ) + { + xError = FF_DecreaseFreeClusters( pxIOManager, 1 ); + } + *pxError = xError; + + return ulStartCluster; +} +/*-----------------------------------------------------------*/ + +uint32_t FF_GetChainLength( FF_IOManager_t *pxIOManager, uint32_t ulStartCluster, uint32_t *pulEndOfChain, FF_Error_t *pxError ) +{ +uint32_t ulLength = 0; +FF_FATBuffers_t xFATBuffers; +FF_Error_t xError = FF_ERR_NONE; + + FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ ); + + FF_LockFAT( pxIOManager ); + { + while( FF_isEndOfChain( pxIOManager, ulStartCluster ) == pdFALSE ) + { + ulStartCluster = FF_getFATEntry( pxIOManager, ulStartCluster, &xError, &xFATBuffers ); + if( FF_isERR( xError ) ) + { + ulLength = 0; + break; + } + ulLength++; + } + if( pulEndOfChain != NULL ) + { + /* _HT_ + ulStartCluster has just been tested as an end-of-chain token. + Not sure if the caller expects this. */ + *pulEndOfChain = ulStartCluster; + } + xError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers ); + } + FF_UnlockFAT( pxIOManager ); + + *pxError = xError; + + return ulLength; +} +/*-----------------------------------------------------------*/ + +/** + * @private + * @brief Free's Disk space by freeing unused links on Cluster Chains + * + * @param pxIOManager, IOMAN object. + * @param ulStartCluster Cluster Number that starts the chain. + * @param ulCount Number of Clusters from the end of the chain to unlink. + * @param ulCount 0 Means Free the entire chain (delete file). + * @param ulCount 1 Means mark the start cluster with EOF. + * + * @return 0 On Success. + * @return -1 If the device driver failed to provide access. + * + **/ +FF_Error_t FF_UnlinkClusterChain( FF_IOManager_t *pxIOManager, uint32_t ulStartCluster, BaseType_t xDoTruncate ) +{ +uint32_t ulFATEntry; +uint32_t ulCurrentCluster; +uint32_t ulLength = 0; +uint32_t ulLastFree = ulStartCluster; +FF_Error_t xTempError; +FF_Error_t xError = FF_ERR_NONE; +FF_FATBuffers_t xFATBuffers; + +BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE; + + if( xTakeLock ) + { + FF_LockFAT( pxIOManager ); + } + + FF_InitFATBuffers( &xFATBuffers, FF_MODE_WRITE ); + + ulFATEntry = ulStartCluster; + + /* Free all clusters in the chain! */ + ulCurrentCluster = ulStartCluster; + ulFATEntry = ulCurrentCluster; + do + { + /* Sector will now be fetched in write-mode. */ + ulFATEntry = FF_getFATEntry( pxIOManager, ulFATEntry, &xError, &xFATBuffers ); + if( FF_isERR( xError ) ) + { + break; + } + + if( ( xDoTruncate != pdFALSE ) && ( ulCurrentCluster == ulStartCluster ) ) + { + xError = FF_putFATEntry( pxIOManager, ulCurrentCluster, 0xFFFFFFFF, &xFATBuffers ); + } + else + { + xError = FF_putFATEntry( pxIOManager, ulCurrentCluster, 0x00000000, &xFATBuffers ); + ulLength++; + } + if( FF_isERR( xError ) ) + { + break; + } + + if( ulLastFree > ulCurrentCluster ) + { + ulLastFree = ulCurrentCluster; + } + ulCurrentCluster = ulFATEntry; + } while( FF_isEndOfChain( pxIOManager, ulFATEntry ) == pdFALSE ); + + if( FF_isERR( xError ) == pdFALSE ) + { + if( pxIOManager->xPartition.ulLastFreeCluster > ulLastFree ) + { + pxIOManager->xPartition.ulLastFreeCluster = ulLastFree; + } + } + + xTempError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + + if( xTakeLock ) + { + FF_UnlockFAT( pxIOManager ); + } + if( ulLength != 0 ) + { + xTempError = FF_IncreaseFreeClusters( pxIOManager, ulLength ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + + return xError; +} +/*-----------------------------------------------------------*/ + +#if( ffconfigFAT12_SUPPORT != 0 ) + static uint32_t prvCountFreeClustersSimple( FF_IOManager_t *pxIOManager, FF_Error_t *pxError ) + { + FF_Error_t xError = FF_ERR_NONE; + uint32_t ulIndex; + uint32_t ulFATEntry; + uint32_t ulFreeClusters = 0; + const uint32_t xTotalClusters = + pxIOManager->xPartition.ulDataSectors / pxIOManager->xPartition.ulSectorsPerCluster; + + for( ulIndex = 0; ulIndex < xTotalClusters; ulIndex++ ) + { + ulFATEntry = FF_getFATEntry( pxIOManager, ulIndex, &xError, NULL ); + if( FF_isERR( xError) ) + { + break; + } + if( ulFATEntry == 0UL ) + { + ulFreeClusters++; + } + } + + *pxError = xError; + + return ulFreeClusters; + } +#endif +/*-----------------------------------------------------------*/ + + +uint32_t FF_CountFreeClusters( FF_IOManager_t *pxIOManager, FF_Error_t *pxError ) +{ +FF_Error_t xError = FF_ERR_NONE; +FF_Buffer_t *pxBuffer; +uint32_t ulIndex, x; +uint32_t ulFATEntry; +uint32_t ulEntriesPerSector; +uint32_t ulFreeClusters = 0; +uint32_t ClusterNum = 0; +BaseType_t xInfoKnown = pdFALSE; +BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE; + + if( xTakeLock ) + { + FF_LockFAT( pxIOManager ); + } + +#if( ffconfigFAT12_SUPPORT != 0 ) + /* FAT12 tables are too small to optimise, and would make it very complicated! */ + if( pxIOManager->xPartition.ucType == FF_T_FAT12 ) + { + ulFreeClusters = prvCountFreeClustersSimple( pxIOManager, &xError ); + } + else +#endif + { + /* For FAT16 and FAT32 */ + #if( ffconfigFSINFO_TRUSTED != 0 ) + { + /* If 'ffconfigFSINFO_TRUSTED', the contents of the field 'ulFreeClusterCount' is trusted. */ + if( pxIOManager->xPartition.ucType == FF_T_FAT32 ) + { + pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_READ ); + if( pxBuffer == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_COUNTFREECLUSTERS ); + } + else + { + if( ( FF_getLong( pxBuffer->pucBuffer, 0 ) == 0x41615252 ) && + ( FF_getLong( pxBuffer->pucBuffer, 484 ) == 0x61417272 ) ) + { + ulFreeClusters = FF_getLong( pxBuffer->pucBuffer, 488 ); + + if( ulFreeClusters != ~0ul ) + { + xInfoKnown = pdTRUE; + } + else + { + ulFreeClusters = 0ul; + } + } + + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + pxBuffer = NULL; + + if( xInfoKnown != pdFALSE ) + { + pxIOManager->xPartition.ulFreeClusterCount = ulFreeClusters; + } + } + } + } + #endif + if( ( xInfoKnown == pdFALSE ) && ( pxIOManager->xPartition.usBlkSize != 0 ) ) + { + if( pxIOManager->xPartition.ucType == FF_T_FAT32 ) + { + ulEntriesPerSector = pxIOManager->usSectorSize / 4; + } + else + { + ulEntriesPerSector = pxIOManager->usSectorSize / 2; + } + for( ulIndex = 0; ulIndex < pxIOManager->xPartition.ulSectorsPerFAT; ulIndex++ ) + { + pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA + ulIndex, FF_MODE_READ ); + + if( pxBuffer == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_COUNTFREECLUSTERS ); + break; + } + #if USE_SOFT_WDT + { + /* _HT_ : FF_CountFreeClusters was a little too busy, have it call the WDT and sleep */ + clearWDT( ); + if( ( ( ulIndex + 1 ) % 32 ) == 0 ) + { + FF_Sleep( 1 ); + } + } + #endif + for( x = 0; x < ulEntriesPerSector; x++ ) + { + if( pxIOManager->xPartition.ucType == FF_T_FAT32 ) + { + /* Clearing the top 4 bits. */ + ulFATEntry = FF_getLong( pxBuffer->pucBuffer, x * 4 ) & 0x0fffffff; + } + else + { + ulFATEntry = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, x * 2 ); + } + if( ulFATEntry == 0ul ) + { + ulFreeClusters++; + } + /* FAT table might not be cluster aligned. */ + if( ClusterNum > pxIOManager->xPartition.ulNumClusters ) + { + /* Stop counting if that's the case. */ + break; + } + ClusterNum++; + } + + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + pxBuffer = NULL; + if( FF_isERR( xError ) ) + { + break; + } + if( ClusterNum > pxIOManager->xPartition.ulNumClusters ) + { + /* Break out of 2nd loop too ^^ */ + break; + } + /* ulFreeClusters is -2 because the first 2 fat entries in the table are reserved. */ + if( ulFreeClusters > pxIOManager->xPartition.ulNumClusters ) + { + ulFreeClusters = pxIOManager->xPartition.ulNumClusters; + } + } /* for( ulIndex = 0; ulIndex < pxIOManager->xPartition.ulSectorsPerFAT; ulIndex++ ) */ + } + } + + if( xTakeLock ) + { + FF_UnlockFAT( pxIOManager ); + } + + if( FF_isERR( xError ) ) + { + ulFreeClusters = 0; + } + *pxError = xError; + + return ulFreeClusters; +} +/*-----------------------------------------------------------*/ + +#if( ffconfig64_NUM_SUPPORT != 0 ) + uint64_t FF_GetFreeSize( FF_IOManager_t *pxIOManager, FF_Error_t *pxError ) + { + FF_Error_t xError = FF_ERR_NONE; + uint32_t ulFreeClusters; + uint64_t ulFreeSize = 0; + + if( pxIOManager != NULL ) + { + if( pxIOManager->xPartition.ulFreeClusterCount == 0ul ) + { + FF_LockFAT( pxIOManager ); + { + pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError ); + } + FF_UnlockFAT( pxIOManager ); + } + ulFreeClusters = pxIOManager->xPartition.ulFreeClusterCount; + ulFreeSize = ( uint64_t ) + ( ( uint64_t ) ulFreeClusters * ( uint64_t ) + ( ( uint64_t ) pxIOManager->xPartition.ulSectorsPerCluster * + ( uint64_t ) pxIOManager->xPartition.usBlkSize ) ); + } + if( pxError != NULL ) + { + *pxError = xError; + } + + return ulFreeSize; + } +#else + uint32_t FF_GetFreeSize( FF_IOManager_t *pxIOManager, FF_Error_t *pxError ) + { + FF_Error_t xError = FF_ERR_NONE; + uint32_t ulFreeClusters; + uint32_t ulFreeSize = 0; + + if( pxIOManager != NULL ) + { + if( pxIOManager->xPartition.ulFreeClusterCount == 0ul ) + { + FF_LockFAT( pxIOManager ); + { + pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError ); + } + FF_UnlockFAT( pxIOManager ); + } + ulFreeClusters = pxIOManager->xPartition.ulFreeClusterCount; + ulFreeSize = ( uint32_t ) + ( ( uint32_t ) ulFreeClusters * ( uint32_t ) + ( ( uint32_t ) pxIOManager->xPartition.ulSectorsPerCluster * + ( uint32_t ) pxIOManager->xPartition.usBlkSize ) ); + } + + if( pxError != NULL ) + { + *pxError = xError; + } + + return ulFreeSize; + } +#endif /* ffconfig64_NUM_SUPPORT */ +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_file.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_file.c new file mode 100644 index 000000000..8d19c1bb0 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_file.c @@ -0,0 +1,3080 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_file.c + * @ingroup FILEIO + * + * @defgroup FILEIO FILE I/O Access + * @brief Provides an interface to allow File I/O on a mounted IOMAN. + * + * Provides file-system interfaces for the FAT file-system. + **/ + +#include "ff_headers.h" + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +#include +#endif + +static FF_Error_t FF_Truncate( FF_FILE *pxFile, BaseType_t bClosing ); + +static int32_t FF_ReadPartial( FF_FILE *pxFile, uint32_t ulItemLBA, uint32_t ulRelBlockPos, uint32_t ulCount, + uint8_t *pucBuffer, FF_Error_t *pxError ); + +static int32_t FF_WritePartial( FF_FILE *pxFile, uint32_t ulItemLBA, uint32_t ulRelBlockPos, uint32_t ulCount, + const uint8_t *pucBuffer, FF_Error_t *pxError ); + +static uint32_t FF_SetCluster( FF_FILE *pxFile, FF_Error_t *pxError ); +static uint32_t FF_FileLBA( FF_FILE *pxFile ); + +/*-----------------------------------------------------------*/ + +/** + * @public + * @brief Converts STDIO mode strings into the equivalent FreeRTOS+FAT mode. + * + * @param Mode The mode string e.g. "rb" "rb+" "w" "a" "r" "w+" "a+" etc + * + * @return Returns the mode bits that should be passed to the FF_Open function. + **/ +uint8_t FF_GetModeBits( const char *pcMode ) +{ +uint8_t ucModeBits = 0x00; + + while( *pcMode != '\0' ) + { + switch( *pcMode ) + { + case 'r': /* Allow Read. */ + case 'R': + ucModeBits |= FF_MODE_READ; + break; + + case 'w': /* Allow Write. */ + case 'W': + ucModeBits |= FF_MODE_WRITE; + ucModeBits |= FF_MODE_CREATE; /* Create if not exist. */ + ucModeBits |= FF_MODE_TRUNCATE; + break; + + case 'a': /* Append new writes to the end of the file. */ + case 'A': + ucModeBits |= FF_MODE_WRITE; + ucModeBits |= FF_MODE_APPEND; + ucModeBits |= FF_MODE_CREATE; /* Create if not exist. */ + break; + + case '+': /* Update the file, don't Append! */ + ucModeBits |= FF_MODE_READ; + ucModeBits |= FF_MODE_WRITE; /* RW Mode. */ + break; + + case 'D': + /* Internal use only! */ + ucModeBits |= FF_MODE_DIR; + break; + + case 'b': + case 'B': + /* b|B flags not supported (Binary mode is native anyway). */ + break; + + default: + break; + } + + pcMode++; + } + + return ucModeBits; +} /* FF_GetModeBits() */ +/*-----------------------------------------------------------*/ + +static FF_FILE *prvAllocFileHandle( FF_IOManager_t *pxIOManager, FF_Error_t *pxError ) +{ +FF_FILE *pxFile; + + pxFile = ffconfigMALLOC( sizeof( FF_FILE ) ); + if( pxFile == NULL ) + { + *pxError = ( FF_Error_t ) ( FF_ERR_NOT_ENOUGH_MEMORY | FF_OPEN ); + } + else + { + memset( pxFile, 0, sizeof( *pxFile ) ); + + #if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) + { + pxFile->pucBuffer = ( uint8_t * ) ffconfigMALLOC( pxIOManager->usSectorSize ); + if( pxFile->pucBuffer != NULL ) + { + memset( pxFile->pucBuffer, 0, pxIOManager->usSectorSize ); + } + else + { + *pxError = ( FF_Error_t ) ( FF_ERR_NOT_ENOUGH_MEMORY | FF_OPEN ); + ffconfigFREE( pxFile ); + /* Make sure that NULL will be returned. */ + pxFile = NULL; + } + } + #else + { + /* Remove compiler warnings. */ + ( void ) pxIOManager; + } + #endif + } + + return pxFile; +} /* prvAllocFileHandle() */ +/*-----------------------------------------------------------*/ + +/** + * FF_Open() Mode Information + * - FF_MODE_WRITE + * - Allows WRITE access to the file. + * . + * - FF_MODE_READ + * - Allows READ access to the file. + * . + * - FF_MODE_CREATE + * - Create file if it doesn't exist. + * . + * - FF_MODE_TRUNCATE + * - Erase the file if it already exists and overwrite. + * * + * - FF_MODE_APPEND + * - Causes all writes to occur at the end of the file. (Its impossible to overwrite other data in a file with this flag set). + * . + * . + * + * Some sample modes: + * - (FF_MODE_WRITE | FF_MODE_CREATE | FF_MODE_TRUNCATE) + * - Write access to the file. (Equivalent to "w"). + * . + * - (FF_MODE_WRITE | FF_MODE_READ) + * - Read and Write access to the file. (Equivalent to "rb+"). + * . + * - (FF_MODE_WRITE | FF_MODE_READ | FF_MODE_APPEND | FF_MODE_CREATE) + * - Read and Write append mode access to the file. (Equivalent to "a+"). + * . + * . + * Be careful when choosing modes. For those using FF_Open() at the application layer + * its best to use the provided FF_GetModeBits() function, as this complies to the same + * behaviour as the stdio.h fopen() function. + * + **/ + +/** + * @public + * @brief Opens a File for Access + * + * @param pxIOManager FF_IOManager_t object that was created by FF_CreateIOManger(). + * @param pcPath Path to the File or object. + * @param ucMode Access Mode required. Modes are a little complicated, the function FF_GetModeBits() + * @param ucMode will convert a stdio Mode string into the equivalent Mode bits for this parameter. + * @param pxError Pointer to a signed byte for error checking. Can be NULL if not required. + * @param pxError To be checked when a NULL pointer is returned. + * + * @return NULL pointer on error, in which case pxError should be checked for more information. + * @return pxError can be: + **/ +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +FF_FILE *FF_Open( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *pcPath, uint8_t ucMode, FF_Error_t *pxError ) +#else +FF_FILE *FF_Open( FF_IOManager_t *pxIOManager, const char *pcPath, uint8_t ucMode, FF_Error_t *pxError ) +#endif +{ +FF_FILE *pxFile = NULL; +FF_FILE *pxFileChain; +FF_DirEnt_t xDirEntry; +uint32_t ulFileCluster; +FF_Error_t xError; +BaseType_t xIndex; +FF_FindParams_t xFindParams; +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_T_WCHAR pcFileName[ ffconfigMAX_FILENAME ]; +#else + char pcFileName[ ffconfigMAX_FILENAME ]; +#endif + + memset( &xFindParams, '\0', sizeof( xFindParams ) ); + + /* Inform the functions that the entry will be created if not found. */ + if( ( ucMode & FF_MODE_CREATE ) != 0 ) + { + xFindParams.ulFlags |= FIND_FLAG_CREATE_FLAG; + } + + if( pxIOManager == NULL ) + { + /* Use the error function code 'FF_OPEN' as this static + function is only called from that function. */ + xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_OPEN ); + } +#if( ffconfigREMOVABLE_MEDIA != 0 ) + else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 ) + { + xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_OPEN ); + } +#endif /* ffconfigREMOVABLE_MEDIA */ + else + { + xError = FF_ERR_NONE; + + /* Let xIndex point to the last occurrence of '/' or '\', + to separate the path from the file name. */ + xIndex = ( BaseType_t ) STRLEN( pcPath ); + while( xIndex != 0 ) + { + if( ( pcPath[ xIndex ] == '\\' ) || ( pcPath[ xIndex ] == '/' ) ) + { + break; + } + xIndex--; + } + + /* Copy the file name, i.e. the string that comes after the last separator. */ + STRNCPY( pcFileName, pcPath + xIndex + 1, ffconfigMAX_FILENAME ); + + if( xIndex == 0 ) + { + /* Only for the root, the slash is part of the directory name. + 'xIndex' now equals to the length of the path name. */ + xIndex = 1; + } + + /* FF_CreateShortName() might set flags FIND_FLAG_FITS_SHORT and FIND_FLAG_SIZE_OK. */ + FF_CreateShortName( &xFindParams, pcFileName ); + + /* Lookup the path and find the cluster pointing to the directory: */ + xFindParams.ulDirCluster = FF_FindDir( pxIOManager, pcPath, xIndex, &xError ); + if( xFindParams.ulDirCluster == 0ul ) + { + if( ( ucMode & FF_MODE_WRITE ) != 0 ) + { + FF_PRINTF( "FF_Open[%s]: Path not found\n", pcPath ); + } + /* The user tries to open a file but the path leading to the file does not exist. */ + } + else if( FF_isERR( xError ) == pdFALSE ) + { + /* Allocate an empty file handle and buffer space for 'unaligned access'. */ + pxFile = prvAllocFileHandle( pxIOManager, &xError ); + } + } + + if( FF_isERR( xError ) == pdFALSE ) + { + /* Copy the Mode Bits. */ + pxFile->ucMode = ucMode; + + /* See if the file does exist within the given directory. */ + ulFileCluster = FF_FindEntryInDir( pxIOManager, &xFindParams, pcFileName, 0x00, &xDirEntry, &xError ); + + if( ulFileCluster == 0ul ) + { + /* If cluster 0 was returned, it might be because the file has no allocated cluster, + i.e. only a directory entry and no stored data. */ + if( STRLEN( pcFileName ) == STRLEN( xDirEntry.pcFileName ) ) + { + if( ( xDirEntry.ulFileSize == 0 ) && ( FF_strmatch( pcFileName, xDirEntry.pcFileName, ( BaseType_t ) STRLEN( pcFileName ) ) == pdTRUE ) ) + { + /* It is the file, give it a pseudo cluster number '1'. */ + ulFileCluster = 1; + /* And reset any error. */ + xError = FF_ERR_NONE; + } + } + } + + /* Test 'ulFileCluster' again, it might have been changed. */ + if( ulFileCluster == 0ul ) + { + /* The path is found, but it does not contain the file name yet. + Maybe the user wants to create it? */ + if( ( ucMode & FF_MODE_CREATE ) == 0 ) + { + xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_OPEN ); + } + else + { + ulFileCluster = FF_CreateFile( pxIOManager, &xFindParams, pcFileName, &xDirEntry, &xError ); + if( FF_isERR( xError ) == pdFALSE ) + { + xDirEntry.usCurrentItem += 1; + } + } + } + } + + if( FF_isERR( xError ) == pdFALSE ) + { + /* Now the file exists, or it has been created. + Check if the Mode flags are allowed: */ + if( ( xDirEntry.ucAttrib == FF_FAT_ATTR_DIR ) && ( ( ucMode & FF_MODE_DIR ) == 0 ) ) + { + /* Not the object, File Not Found! */ + xError = ( FF_Error_t ) ( FF_ERR_FILE_OBJECT_IS_A_DIR | FF_OPEN ); + } + /*---------- Ensure Read-Only files don't get opened for Writing. */ + else if( ( ( ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND ) ) != 0 ) && ( ( xDirEntry.ucAttrib & FF_FAT_ATTR_READONLY ) != 0 ) ) + { + xError = ( FF_Error_t ) ( FF_ERR_FILE_IS_READ_ONLY | FF_OPEN ); + } + } + + if( FF_isERR( xError ) == pdFALSE ) + { + pxFile->pxIOManager = pxIOManager; + pxFile->ulFilePointer = 0; + /* Despite the warning output by MSVC - it is not possible to get here + if xDirEntry has not been initialised. */ + pxFile->ulObjectCluster = xDirEntry.ulObjectCluster; + pxFile->ulFileSize = xDirEntry.ulFileSize; + pxFile->ulCurrentCluster = 0; + pxFile->ulAddrCurrentCluster = pxFile->ulObjectCluster; + + pxFile->pxNext = NULL; + pxFile->ulDirCluster = xFindParams.ulDirCluster; + pxFile->usDirEntry = xDirEntry.usCurrentItem - 1; + pxFile->ulChainLength = 0; + pxFile->ulEndOfChain = 0; + pxFile->ulValidFlags &= ~( FF_VALID_FLAG_DELETED ); + + /* Add pxFile onto the end of our linked list of FF_FILE objects. + But first make sure that there are not 2 handles with write access + to the same object. */ + FF_PendSemaphore( pxIOManager->pvSemaphore ); + { + pxFileChain = ( FF_FILE * ) pxIOManager->FirstFile; + if( pxFileChain == NULL ) + { + pxIOManager->FirstFile = pxFile; + } + else + { + for( ; ; ) + { + /* See if two file handles point to the same object. */ + if( ( pxFileChain->ulObjectCluster == pxFile->ulObjectCluster ) && + ( pxFileChain->ulDirCluster == pxFile->ulDirCluster ) && + ( pxFileChain->usDirEntry == pxFile->usDirEntry ) ) + { + /* Fail if any of the two has write access to the object. */ + if( ( ( pxFileChain->ucMode | pxFile->ucMode ) & ( FF_MODE_WRITE | FF_MODE_APPEND ) ) != 0 ) + { + /* File is already open! DON'T ALLOW IT! */ + xError = ( FF_Error_t ) ( FF_ERR_FILE_ALREADY_OPEN | FF_OPEN ); + break; + } + } + + if( pxFileChain->pxNext == NULL ) + { + pxFileChain->pxNext = pxFile; + break; + } + + pxFileChain = ( FF_FILE * ) pxFileChain->pxNext; + } + } + } + + FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + } + + if( FF_isERR( xError ) == pdFALSE ) + { + /* If the file is opened with the truncate flag, truncate its contents. */ + if( ( ucMode & FF_MODE_TRUNCATE ) != 0 ) + { + /* Set the current size and position to zero. */ + pxFile->ulFileSize = 0; + pxFile->ulFilePointer = 0; + } + } + + if( FF_isERR( xError ) != pdFALSE ) + { + if( pxFile != NULL ) + { + #if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) + { + ffconfigFREE( pxFile->pucBuffer ); + } + #endif + ffconfigFREE( pxFile ); + } + pxFile = NULL; + } + + if( pxError != NULL ) + { + *pxError = xError; + } + + return pxFile; +} /* FF_Open() */ +/*-----------------------------------------------------------*/ + +/** + * @public + * @brief Tests if a Directory contains any other files or folders. + * + * @param pxIOManager FF_IOManager_t object returned from the FF_CreateIOManger() function. + * + **/ +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +BaseType_t FF_isDirEmpty ( FF_IOManager_t * pxIOManager, const FF_T_WCHAR *pcPath ) +#else +BaseType_t FF_isDirEmpty ( FF_IOManager_t * pxIOManager, const char *pcPath ) +#endif +{ +FF_DirEnt_t xDirEntry; +FF_Error_t xError = FF_ERR_NONE; +BaseType_t xReturn; + + if( pxIOManager == NULL ) + { + xReturn = pdFALSE; + } + else + { + xError = FF_FindFirst( pxIOManager, &xDirEntry, pcPath ); + + /* Assume the directory is empty until a file is + encountered with a name other than ".." or "." */ + xReturn = pdTRUE; + + while( xError == 0 ) + { + /* As we can't be sure the first 2 entries contain + * "." and "..", check it, not just count them + */ + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + if( ( wcscmp( xDirEntry.pcFileName, L".." ) != 0 ) && ( wcscmp( xDirEntry.pcFileName, L"." ) != 0 ) ) + #else + if( ( strcmp( xDirEntry.pcFileName, ".." ) != 0 ) && ( strcmp( xDirEntry.pcFileName, "." ) != 0 ) ) + #endif + { + xReturn = pdFALSE; + break; + } + xError = FF_FindNext( pxIOManager, &xDirEntry ); + } + } + + return xReturn; +} /* FF_isDirEmpty() */ +/*-----------------------------------------------------------*/ + +#if( ffconfigPATH_CACHE != 0 ) + /* _HT_ After a directory has been renamed, the path cache becomes out-of-date */ + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + static void FF_RmPathCache ( FF_IOManager_t * pxIOManager, const FF_T_WCHAR * pcPath ) + #else + static void FF_RmPathCache ( FF_IOManager_t * pxIOManager, const char *pcPath ) + #endif + { + /* + * The directory 'path' will be removed or renamed + * now clear all entries starting with 'path' in the path cache + */ + BaseType_t xIndex; + BaseType_t pathLen = STRLEN( pcPath ); + + FF_PendSemaphore( pxIOManager->pvSemaphore ); + { + for( xIndex = 0; xIndex < ffconfigPATH_CACHE_DEPTH; xIndex++ ) + { + BaseType_t len2 = STRLEN( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath ); + + if( len2 >= pathLen && FF_strmatch( pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath, pcPath, pathLen ) ) + { + pxIOManager->xPartition.pxPathCache[ xIndex ].pcPath[ 0 ] = '\0'; + pxIOManager->xPartition.pxPathCache[ xIndex ].ulDirCluster = 0; + } + } + } + + FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + } +#endif /* ffconfigPATH_CACHE */ +/*-----------------------------------------------------------*/ + + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +FF_Error_t FF_RmDir( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *pcPath ) +#else +FF_Error_t FF_RmDir( FF_IOManager_t *pxIOManager, const char *pcPath ) +#endif +{ +FF_FILE *pxFile; +uint8_t ucEntryBuffer[32]; +FF_FetchContext_t xFetchContext; +FF_Error_t xError = FF_ERR_NONE; + + if( pxIOManager == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_RMDIR ); + } +#if( ffconfigREMOVABLE_MEDIA != 0 ) + else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 ) + { + xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_RMDIR ); + } +#endif /* ffconfigREMOVABLE_MEDIA */ + else + { + pxFile = FF_Open( pxIOManager, pcPath, FF_MODE_DIR, &xError ); + + if( pxFile != NULL ) + { + pxFile->ulValidFlags |= FF_VALID_FLAG_DELETED; + + /* Clear the struct to allow a call to FF_CleanupEntryFetch() in any + state. */ + memset( &xFetchContext, '\0', sizeof( xFetchContext ) ); + + /* This task will get the unique right to change directories. */ + FF_LockDirectory( pxIOManager ); + do /* while( pdFALSE ) */ + { + /* This while loop is only introduced to be able to use break + statements. */ + if( FF_isDirEmpty( pxIOManager, pcPath ) == pdFALSE ) + { + xError = ( FF_ERR_DIR_NOT_EMPTY | FF_RMDIR ); + break; + } + FF_LockFAT( pxIOManager ); + #if( ffconfigHASH_CACHE != 0 ) + { + /* A directory is removed so invalidate any hash table + referring to this directory. */ + FF_UnHashDir( pxIOManager, pxFile->ulObjectCluster ); + } + #endif /* ffconfigHASH_CACHE */ + { + /* Add parameter 0 to delete the entire chain! + The actual directory entries on disk will be freed. */ + xError = FF_UnlinkClusterChain( pxIOManager, pxFile->ulObjectCluster, 0 ); + } + FF_UnlockFAT( pxIOManager ); + if( FF_isERR( xError ) ) + { + break; + } + + /* Now remove this directory from its parent directory. + Initialise the dirent Fetch Context object for faster removal of + dirents. */ + xError = FF_InitEntryFetch( pxIOManager, pxFile->ulDirCluster, &xFetchContext ); + if( FF_isERR( xError ) ) + { + break; + } + + #if( ffconfigHASH_CACHE != 0 ) + { + /* Invalidate any hash table of the parent directory + as well. */ + FF_UnHashDir( pxIOManager, pxFile->ulDirCluster ); + } + #endif /* ffconfigHASH_CACHE */ + + /* Edit the Directory Entry, so it will show as deleted. + First remove the LFN entries: */ + xError = FF_RmLFNs( pxIOManager, pxFile->usDirEntry, &xFetchContext ); + if( FF_isERR( xError ) ) + { + break; + } + + /* And remove the Short file name entry: */ + xError = FF_FetchEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer ); + if( FF_isERR( xError ) == pdFALSE ) + { + ucEntryBuffer[0] = FF_FAT_DELETED; + FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) 0ul ); + FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW, ( uint32_t ) 0ul ); + + xError = FF_PushEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer ); + } + if( FF_isERR( xError ) ) + { + break; + } + + #if( ffconfigPATH_CACHE != 0 ) + { + /* We're removing a directory which might contain + subdirectories. Instead of iterating through all + subdirectories, just clear the path cache. */ + FF_RmPathCache( pxIOManager, pcPath ); + } + #endif + } while( pdFALSE ); + { + FF_Error_t xTempError; + xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + FF_UnlockDirectory( pxIOManager ); + + /* Free the file pointer resources. */ + xTempError = FF_Close( pxFile ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + + xTempError = FF_FlushCache( pxIOManager ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + } /* if( pxFile != NULL ) */ + } /* else if( pxIOManager != NULL ) */ + + return xError; +} /* FF_RmDir() */ +/*-----------------------------------------------------------*/ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +FF_Error_t FF_RmFile( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *pcPath ) +#else +FF_Error_t FF_RmFile( FF_IOManager_t *pxIOManager, const char *pcPath ) +#endif +{ +FF_FILE *pxFile; +FF_Error_t xError = FF_ERR_NONE; +uint8_t ucEntryBuffer[32]; +FF_FetchContext_t xFetchContext; + + /* Opening the file-to-be-deleted in WR mode has two advantages: + 1. The file handle gives all necessary information to delete it such + as the data clusters and directory entries. + 2. The file is now locked, it can not be opened by another task. */ + pxFile = FF_Open( pxIOManager, pcPath, FF_MODE_WRITE, &xError ); + + if( pxFile != NULL ) + { + /* FF_Close() will see this flag and won't do any disc access. */ + pxFile->ulValidFlags |= FF_VALID_FLAG_DELETED; + + /* Ensure there is actually a cluster chain to delete! */ + if( pxFile->ulObjectCluster != 0 ) + { + /* Lock the FAT so its thread-safe. */ + FF_LockFAT( pxIOManager ); + { + /* 0 to delete the entire chain! */ + xError = FF_UnlinkClusterChain( pxIOManager, pxFile->ulObjectCluster, 0 ); + } + FF_UnlockFAT( pxIOManager ); + } + + if( FF_isERR( xError ) == pdFALSE ) + { + /* Clear the struct to allow a call to FF_CleanupEntryFetch() in any + state. */ + memset( &xFetchContext, '\0', sizeof( xFetchContext ) ); + + /* Get sole access to "directory changes" */ + FF_LockDirectory( pxIOManager ); + + /* Edit the Directory Entry! (So it appears as deleted); */ + do { + xError = FF_InitEntryFetch( pxIOManager, pxFile->ulDirCluster, &xFetchContext ); + if( FF_isERR( xError ) ) + { + break; + } + + #if( ffconfigHASH_CACHE != 0 ) + { + FF_UnHashDir( pxIOManager, pxFile->ulDirCluster ); + } + #endif /* ffconfigHASH_CACHE */ + /* Remove LFN entries, if any. */ + xError = FF_RmLFNs( pxIOManager, ( uint16_t ) pxFile->usDirEntry, &xFetchContext ); + if( FF_isERR( xError ) ) + { + break; + } + + /* Remove the Short file name entry. */ + xError = FF_FetchEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer ); + if( FF_isERR( xError ) == pdFALSE ) + { + ucEntryBuffer[0] = FF_FAT_DELETED; + FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) 0ul ); + FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW, ( uint32_t ) 0ul ); + + xError = FF_PushEntryWithContext( pxIOManager, pxFile->usDirEntry, &xFetchContext, ucEntryBuffer ); + } + } while( pdFALSE ); + { + FF_Error_t xTempError; + xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + FF_UnlockDirectory( pxIOManager ); + + /* Free the file pointer resources. */ + xTempError = FF_Close( pxFile ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + + xTempError = FF_FlushCache( pxIOManager ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + } + } /* if( pxFile != NULL ) */ + + return xError; +} /* FF_RmFile() */ +/*-----------------------------------------------------------*/ + +/** + * @public + * @brief Moves a file or directory from source to destination. + * + * @param pxIOManager The FF_IOManager_t object pointer. + * @param szSourceFile String of the source file to be moved or renamed. + * @param szDestinationFile String of the destination file to where the source should be moved or renamed. + * + * @return FF_ERR_NONE on success. + * @return FF_ERR_FILE_DESTINATION_EXISTS if the destination file exists. + * @return FF_ERR_FILE_COULD_NOT_CREATE_DIRENT if dirent creation failed (fatal error!). + * @return FF_ERR_FILE_DIR_NOT_FOUND if destination directory was not found. + * @return FF_ERR_FILE_SOURCE_NOT_FOUND if the source file was not found. + * + **/ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +FF_Error_t FF_Move( FF_IOManager_t *pxIOManager, const FF_T_WCHAR*szSourceFile, + const FF_T_WCHAR *szDestinationFile, BaseType_t xDeleteIfExists ) +#else +FF_Error_t FF_Move( FF_IOManager_t *pxIOManager, const char *szSourceFile, + const char *szDestinationFile, BaseType_t xDeleteIfExists ) +#endif +{ +FF_Error_t xError; +FF_FILE *pSrcFile, *pxDestFile; +FF_DirEnt_t xMyFile; +uint8_t ucEntryBuffer[32]; +BaseType_t xIndex; +uint32_t ulDirCluster = 0ul; +FF_FetchContext_t xFetchContext; +#if( ffconfigPATH_CACHE != 0 ) + BaseType_t xIsDirectory = pdFALSE; +#endif + + memset( &xFetchContext, '\0', sizeof( xFetchContext ) ); + + if( pxIOManager == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_MOVE ); + } +#if( ffconfigREMOVABLE_MEDIA != 0 ) + else if( ( pxIOManager->ucFlags & FF_IOMAN_DEVICE_IS_EXTRACTED ) != 0 ) + { + xError = ( FF_Error_t ) ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_MOVE ); + } +#endif /* ffconfigREMOVABLE_MEDIA */ + else + { + /* Check destination file doesn't exist! */ + pxDestFile = FF_Open( pxIOManager, szDestinationFile, FF_MODE_READ, &xError ); + + if( ( pxDestFile != NULL) || ( FF_GETERROR( xError ) == FF_ERR_FILE_OBJECT_IS_A_DIR ) ) + { + xError = ( FF_Error_t ) ( FF_ERR_FILE_DESTINATION_EXISTS | FF_MOVE ); + if( pxDestFile != NULL ) + { + FF_Close( pxDestFile ); + if( xDeleteIfExists != pdFALSE ) + { + xError = FF_RmFile( pxIOManager, szDestinationFile ); + } + } + } + else + { + /* Discard the error set by FF_Open(). + The target file (or directory) is not found: continue renaming. */ + xError = FF_ERR_NONE; + } + } + + if( FF_isERR( xError ) == pdFALSE ) + { + /* About to move/rename 'szSourceFile'. When opening it with 'FF_MODE_WRITE' + only succeeds if it has no other open handle to it. */ + pSrcFile = FF_Open( pxIOManager, szSourceFile, FF_MODE_WRITE, &xError ); + + if( FF_GETERROR( xError ) == FF_ERR_FILE_OBJECT_IS_A_DIR ) + { + /* Open a directory for moving! */ + pSrcFile = FF_Open( pxIOManager, szSourceFile, FF_MODE_DIR, &xError ); + #if( ffconfigPATH_CACHE != 0 ) + xIsDirectory = pdTRUE; + #endif + } + + if( pSrcFile != NULL ) + { + /* Collect information about the current directory entry. */ + xError = FF_InitEntryFetch( pxIOManager, pSrcFile->ulDirCluster, &xFetchContext ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_FetchEntryWithContext( pxIOManager, pSrcFile->usDirEntry, &xFetchContext, ucEntryBuffer ); + if( FF_isERR( xError ) == pdFALSE ) + { + xMyFile.ucAttrib = FF_getChar( ucEntryBuffer, ( uint16_t ) ( FF_FAT_DIRENT_ATTRIB ) ); + xMyFile.ulFileSize = pSrcFile->ulFileSize; + xMyFile.ulObjectCluster = pSrcFile->ulObjectCluster; + xMyFile.usCurrentItem = 0; + + xIndex = ( BaseType_t ) STRLEN( szDestinationFile ); + + while( xIndex != 0 ) + { + if( ( szDestinationFile[ xIndex ] == '\\' ) || ( szDestinationFile[ xIndex ] == '/' ) ) + { + break; + } + + xIndex--; + } + + /* Copy the base name of the destination file. */ + STRNCPY( xMyFile.pcFileName, ( szDestinationFile + xIndex + 1 ), ffconfigMAX_FILENAME ); + + if( xIndex == 0 ) + { + xIndex = 1; + } + + /* Find the (cluster of the) directory in which the target file will be located. + It must exist before calling FF_Move(). */ + ulDirCluster = FF_FindDir( pxIOManager, szDestinationFile, xIndex, &xError ); + } + } + } + + if( FF_isERR( xError ) == pdFALSE ) + { + if( ulDirCluster != 0ul ) + { + FF_FindParams_t xFindParams; + memset( &xFindParams, '\0', sizeof( xFindParams ) ); + + /* Clean up because FF_CreateDirent might want to write to the same sector. */ + xError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + + if( FF_isERR( xError ) == pdFALSE ) + { + /* Destination directory was found, we can now create the new entry. */ + xFindParams.ulDirCluster = ulDirCluster; + xError = FF_CreateDirent( pxIOManager, &xFindParams, &xMyFile ); + } + + if( FF_isERR( xError ) == pdFALSE ) + { + /* Edit the Directory Entry! (So it appears as deleted); */ + FF_LockDirectory( pxIOManager ); + { + xError = FF_RmLFNs( pxIOManager, pSrcFile->usDirEntry, &xFetchContext ); + + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_FetchEntryWithContext( pxIOManager, pSrcFile->usDirEntry, &xFetchContext, ucEntryBuffer ); + + if( FF_isERR( xError ) == pdFALSE ) + { + FF_Error_t xTempError; + ucEntryBuffer[0] = FF_FAT_DELETED; + FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_HIGH, ( uint32_t ) 0ul ); + FF_putShort( ucEntryBuffer, FF_FAT_DIRENT_CLUS_LOW, ( uint32_t ) 0ul ); + + xError = FF_PushEntryWithContext( pxIOManager, pSrcFile->usDirEntry, &xFetchContext, ucEntryBuffer ); + /* The contents of 'xFetchContext' has changed, flush it to disk now. */ + xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + } + } + FF_UnlockDirectory( pxIOManager ); + } + + #if( ffconfigPATH_CACHE != 0 ) + { + if( xIsDirectory != 0 ) + { + /* We've renamed a directory which might contain + subdirectories. To avoid having false entries, clear + the path cache. */ + FF_RmPathCache( pxIOManager, szSourceFile ); + } + } + #endif + } + else /* ulDirCluster == 0ul */ + { + xError = ( FF_Error_t ) ( FF_ERR_FILE_DIR_NOT_FOUND | FF_MOVE ); + } + } + + if( pSrcFile != NULL ) + { + /* The source file was opened in WRITE mode just to lock it. + Now clear the write flags to avoid writing back any changes. */ + pSrcFile->ucMode &= ~( FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE ); + FF_Close( pSrcFile ); + } + } + + { + FF_Error_t xTempError; + + xTempError = FF_FlushCache( pxIOManager ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + xTempError = FF_CleanupEntryFetch( pxIOManager, &xFetchContext ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + + return xError; +} /* FF_Move() */ +/*-----------------------------------------------------------*/ + + /** + * @public + * @brief Get's the next Entry based on the data recorded in the FF_DirEnt_t object. + * + * @param pxFile FF_FILE object that was created by FF_Open(). + * + * @return pdTRUE if End of File was reached. pdFALSE if not. + * @return pdFALSE if a null pointer was provided. + * + **/ +BaseType_t FF_isEOF( FF_FILE *pxFile ) +{ +BaseType_t xReturn; + + if( ( pxFile != NULL ) && ( pxFile->ulFilePointer >= pxFile->ulFileSize ) ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} /* FF_isEOF() */ +/*-----------------------------------------------------------*/ + +/** + * @public + * @brief Checks the number of bytes left on a read handle + * + * @param pxFile An open file handle + * + * @return Less than zero: an error code + * @return Number of bytes left to read from handle + **/ +int32_t FF_BytesLeft( FF_FILE *pxFile ) +{ +BaseType_t xReturn; + + if( pxFile == NULL ) + { + xReturn = FF_ERR_NULL_POINTER | FF_BYTESLEFT; + } + else if( ( pxFile->ucMode & FF_MODE_READ ) == 0 ) + { + xReturn = FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_BYTESLEFT; + } + else if( pxFile->ulFilePointer >= pxFile->ulFileSize ) + { + xReturn = 0; + } + else + { + xReturn = pxFile->ulFileSize - pxFile->ulFilePointer; + } + + return xReturn; +} /* FF_BytesLeft() */ +/*-----------------------------------------------------------*/ + +/** + * @public + * @brief Returns the file size of a read handle + * + * @param pxFile An open file handle + * + * @return Less than zero: an error code + * @return Number of bytes left to read from handle + **/ +FF_Error_t FF_GetFileSize( FF_FILE *pxFile, uint32_t *pulSize ) /* Writes # of bytes in a file to the parameter. */ +{ +BaseType_t xReturn; + + if( pxFile == NULL ) + { + xReturn = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_BYTESLEFT ); + *( pulSize ) = ( uint32_t ) 0u; + } + else if( FF_isERR( FF_CheckValid( pxFile ) ) ) + { + xReturn = ( FF_Error_t ) ( FF_ERR_FILE_BAD_HANDLE | FF_BYTESLEFT ); + *( pulSize ) = ( uint32_t ) 0u; + } + else + { + xReturn = 0; + *( pulSize ) = pxFile->ulFileSize; + } + + return xReturn; +} /* FF_GetFileSize */ + +int32_t FF_FileSize( FF_FILE *pxFile ) +{ +uint32_t ulLength; +FF_Error_t xResult; + + /* Function is deprecated. Please use FF_GetFileSize(). */ + xResult = FF_GetFileSize( pxFile, &( ulLength ) ); + + if( FF_isERR( xResult ) == 0 ) + { + xResult = ( int32_t ) ulLength; + } + + return ( int32_t ) xResult; +} /* FF_FileSize() */ +/*-----------------------------------------------------------*/ + +static uint32_t FF_GetSequentialClusters( FF_IOManager_t *pxIOManager, uint32_t ulStartCluster, uint32_t ulLimit, FF_Error_t *pxError ) +{ +uint32_t ulCurrentCluster; +uint32_t ulNextCluster = ulStartCluster; +uint32_t ulIndex = 0; + + FF_FATBuffers_t xFATBuffers; + FF_InitFATBuffers( &xFATBuffers, FF_MODE_READ ); + + *pxError = FF_ERR_NONE; + + FF_LockFAT( pxIOManager ); + do + { + ulCurrentCluster = ulNextCluster; + ulNextCluster = FF_getFATEntry( pxIOManager, ulCurrentCluster, pxError, &xFATBuffers ); + if( FF_isERR( *pxError ) ) + { + ulIndex = 0; + break; + } + + if( ulNextCluster == ( ulCurrentCluster + 1 ) ) + { + ulIndex++; + } + else + { + break; + } + + if( ( ulLimit != 0 ) && ( ulIndex == ulLimit ) ) + { + break; + } + } + while( ulNextCluster == ( ulCurrentCluster + 1 ) ); + + FF_UnlockFAT( pxIOManager ); + + *pxError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers ); + + return ulIndex; +} /* FF_GetSequentialClusters() */ +/*-----------------------------------------------------------*/ + +static FF_Error_t FF_ReadClusters( FF_FILE *pxFile, uint32_t ulCount, uint8_t *buffer ) +{ +uint32_t ulSectors; +uint32_t ulSequentialClusters = 0; +uint32_t ulItemLBA; +FF_Error_t xError = FF_ERR_NONE; + + while( ulCount != 0 ) + { + if( ( ulCount - 1 ) > 0 ) + { + ulSequentialClusters = + FF_GetSequentialClusters( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulCount - 1, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + } + + ulSectors = ( ulSequentialClusters + 1 ) * pxFile->pxIOManager->xPartition.ulSectorsPerCluster; + ulItemLBA = FF_Cluster2LBA( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster ); + ulItemLBA = FF_getRealLBA( pxFile->pxIOManager, ulItemLBA ); + + xError = FF_BlockRead( pxFile->pxIOManager, ulItemLBA, ulSectors, buffer, pdFALSE ); + if( FF_isERR( xError ) ) + { + break; + } + + ulCount -= ( ulSequentialClusters + 1 ); + + FF_LockFAT( pxFile->pxIOManager ); + { + pxFile->ulAddrCurrentCluster = + FF_TraverseFAT( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulSequentialClusters + 1, &xError ); + } + FF_UnlockFAT( pxFile->pxIOManager ); + if( FF_isERR( xError ) ) + { + break; + } + + pxFile->ulCurrentCluster += ( ulSequentialClusters + 1 ); + buffer += ulSectors * pxFile->pxIOManager->usSectorSize; + ulSequentialClusters = 0; + } + + return xError; +} /* FF_ReadClusters ()*/ +/*-----------------------------------------------------------*/ + +static FF_Error_t FF_ExtendFile( FF_FILE *pxFile, uint32_t ulSize ) +{ +FF_IOManager_t *pxIOManager = pxFile->pxIOManager; +uint32_t ulBytesPerCluster = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster; +uint32_t ulTotalClustersNeeded = ( ulSize + ulBytesPerCluster - 1 ) / ulBytesPerCluster; +uint32_t ulClusterToExtend; +/* Initialise xIndex just for the compiler. */ +BaseType_t xIndex = 0; +FF_DirEnt_t xOriginalEntry; +FF_Error_t xError = FF_ERR_NONE; +FF_FATBuffers_t xFATBuffers; + + if( ( pxFile->ucMode & FF_MODE_WRITE ) != FF_MODE_WRITE ) + { + xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_EXTENDFILE ); + } + else + { + if( ( pxFile->ulFileSize == 0 ) && ( pxFile->ulObjectCluster == 0 ) ) + { + /* If there is no object cluster yet, create it.*/ + pxFile->ulAddrCurrentCluster = FF_CreateClusterChain( pxFile->pxIOManager, &xError ); + + if( FF_isERR( xError ) == pdFALSE ) + { + /* The directory denotes the address of the first data cluster of every file. + Now change it to 'ulAddrCurrentCluster': */ + xError = FF_GetEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry ); + + if( FF_isERR( xError ) == pdFALSE ) + { + xOriginalEntry.ulObjectCluster = pxFile->ulAddrCurrentCluster; + xError = FF_PutEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL ); + + if( FF_isERR( xError ) == pdFALSE ) + { + pxFile->ulObjectCluster = pxFile->ulAddrCurrentCluster; + pxFile->ulChainLength = 1; + pxFile->ulCurrentCluster = 0; + pxFile->ulEndOfChain = pxFile->ulAddrCurrentCluster; + } + } + } + } + else + { + /* This file already has at least one cluster. */ + } + } + + if( FF_isERR( xError ) == pdFALSE ) + { + if( pxFile->ulChainLength == 0 ) + { + /* This is the first extension requiring the chain length. + Calculate it now: */ + pxFile->ulChainLength = FF_GetChainLength( pxIOManager, pxFile->ulObjectCluster, &pxFile->ulEndOfChain, &xError ); + } + } + + if( ( FF_isERR( xError ) == pdFALSE ) && ( ulTotalClustersNeeded > pxFile->ulChainLength ) ) + { + uint32_t ulCurrentCluster, ulNextCluster; + + ulClusterToExtend = ( ulTotalClustersNeeded - pxFile->ulChainLength ); + /* Now the file has at least 1 cluster, but it needs more clusters. */ + ulNextCluster = pxFile->ulAddrCurrentCluster; + FF_LockFAT( pxIOManager ); + + ulCurrentCluster = FF_FindEndOfChain( pxIOManager, ulNextCluster, &xError ); + + if( FF_isERR( xError ) == pdFALSE ) + { + for( xIndex = 0; xIndex < ( BaseType_t ) ulClusterToExtend; xIndex++ ) + { + /* In FF_ExtendFile() */ + ulNextCluster = FF_FindFreeCluster( pxIOManager, &xError, pdTRUE ); + if( ( FF_isERR( xError ) == pdFALSE ) && ( ulNextCluster == 0UL ) ) + { + xError = ( FF_Error_t ) ( FF_ERR_FAT_NO_FREE_CLUSTERS | FF_EXTENDFILE ); + } + + if( FF_isERR( xError ) ) + { + break; + } + + /* Can not use this buffer earlier because of FF_FindEndOfChain/FF_FindFreeCluster */ + FF_InitFATBuffers( &xFATBuffers, FF_MODE_WRITE ); + xError = FF_putFATEntry( pxIOManager, ulCurrentCluster, ulNextCluster, &xFATBuffers ); + if( FF_isERR( xError ) ) + { + break; + } + xError = FF_ReleaseFATBuffers( pxIOManager, &xFATBuffers ); + if( FF_isERR( xError ) ) + { + break; + } + ulCurrentCluster = ulNextCluster; + } + + if( FF_isERR( xError ) == pdFALSE ) + { + pxFile->ulEndOfChain = ulCurrentCluster; + } + pxFile->ulChainLength += xIndex; + } + FF_UnlockFAT( pxIOManager ); + + { + FF_Error_t xTempError; + xTempError = FF_DecreaseFreeClusters( pxIOManager, ( uint32_t ) xIndex ); /* Keep Tab of Numbers for fast FreeSize() */ + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + + /* We must ensure that the ulAddrCurrentCluster is not out-of-sync with the CurrentCluster number. + This could have occurred in append mode, where the file was opened with a filesize % clustersize == 0 + because of a seek, where the ulAddrCurrentCluster was not updated after extending. This caused the data to + be written to the previous cluster(s). */ + if( ( pxFile->ulCurrentCluster == pxFile->ulChainLength - 1 ) && + ( pxFile->ulAddrCurrentCluster != pxFile->ulEndOfChain ) ) + { + pxFile->ulAddrCurrentCluster = pxFile->ulEndOfChain; + } + + /* By default, 'ffconfigFILE_EXTEND_FLUSHES_BUFFERS' is + defined as 1. + Users may set it to zero in order to increase the + speed of writing to disk. */ + + #if( ffconfigFILE_EXTEND_FLUSHES_BUFFERS != 0 ) + { + FF_Error_t xTempError; + + xTempError = FF_FlushCache( pxIOManager ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + #endif /* ffconfigFILE_EXTEND_FLUSHES_BUFFERS */ + } /* if( ulTotalClustersNeeded > pxFile->ulChainLength ) */ + + return xError; +} /* FF_ExtendFile() */ +/*-----------------------------------------------------------*/ + +static FF_Error_t FF_WriteClusters( FF_FILE *pxFile, uint32_t ulCount, uint8_t *buffer ) +{ +uint32_t ulSectors; +uint32_t ulSequentialClusters = 0; +uint32_t ulItemLBA; +FF_Error_t xError = FF_ERR_NONE; + + while( ulCount != 0 ) + { + if( ( ulCount - 1 ) > 0 ) + { + ulSequentialClusters = + FF_GetSequentialClusters( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulCount - 1, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + } + + ulSectors = ( ulSequentialClusters + 1 ) * pxFile->pxIOManager->xPartition.ulSectorsPerCluster; + ulItemLBA = FF_Cluster2LBA( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster ); + ulItemLBA = FF_getRealLBA( pxFile->pxIOManager, ulItemLBA ); + + xError = FF_BlockWrite( pxFile->pxIOManager, ulItemLBA, ulSectors, buffer, pdFALSE ); + + if( FF_isERR( xError ) ) + { + break; + } + + ulCount -= ulSequentialClusters + 1; + + FF_LockFAT( pxFile->pxIOManager ); + { + pxFile->ulAddrCurrentCluster = + FF_TraverseFAT( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster, ulSequentialClusters + 1, &xError ); + } + FF_UnlockFAT( pxFile->pxIOManager ); + if( FF_isERR( xError ) ) + { + break; + } + + pxFile->ulCurrentCluster += ( ulSequentialClusters + 1 ); + buffer += ulSectors * pxFile->pxIOManager->usSectorSize; + ulSequentialClusters = 0; + } + + return xError; +} /* FF_WriteClusters */ +/*-----------------------------------------------------------*/ + +/** + * @private + * @brief Calculate the Logical Block Address (LBA) + * + * @param pxFile The file handle + * + * @return LBA + * + * Must be set: + * - pxFile->ulFilePointer : byte offset in file + * - pxFile->ulAddrCurrentCluster : physical cluster on the partition + **/ +static uint32_t FF_FileLBA( FF_FILE *pxFile ) +{ + uint32_t ulItemLBA; + ulItemLBA = FF_Cluster2LBA( pxFile->pxIOManager, pxFile->ulAddrCurrentCluster ); + ulItemLBA += FF_getMajorBlockNumber( pxFile->pxIOManager, pxFile->ulFilePointer, 1 ); + ulItemLBA = FF_getRealLBA( pxFile->pxIOManager, ulItemLBA ); + ulItemLBA += FF_getMinorBlockNumber( pxFile->pxIOManager, pxFile->ulFilePointer, 1 ); + + return ulItemLBA; +} /* FF_FileLBA() */ +/*-----------------------------------------------------------*/ + +/** + * @private + * @brief Depending on FilePointer, calculate CurrentCluster + * @brief and traverse the FAT to find the right ulAddrCurrentCluster + * + * @param pxFile The file handle + * + * @return FF_ERR_NONE on success + * @return Possible error returned by FF_TraverseFAT() or END_OF_DIR + * + * Side effects: + * - pxFile->ulCurrentCluster : relative cluster number (0 <= Num < ulChainLength) + * - pxFile->ulAddrCurrentCluster : fysical cluster on the partition + **/ +static uint32_t FF_SetCluster( FF_FILE *pxFile, FF_Error_t *pxError ) +{ +FF_IOManager_t *pxIOManager = pxFile->pxIOManager; +uint32_t ulNewCluster = FF_getClusterChainNumber( pxIOManager, pxFile->ulFilePointer, 1 ); +FF_Error_t xResult = FF_ERR_NONE; +uint32_t ulReturn; + + if( ulNewCluster > pxFile->ulCurrentCluster ) + { + FF_LockFAT( pxIOManager ); + { + pxFile->ulAddrCurrentCluster = FF_TraverseFAT( pxIOManager, pxFile->ulAddrCurrentCluster, + ulNewCluster - pxFile->ulCurrentCluster, &xResult ); + } + FF_UnlockFAT( pxIOManager ); + } + else if( ulNewCluster < pxFile->ulCurrentCluster ) + { + FF_LockFAT( pxIOManager ); + { + pxFile->ulAddrCurrentCluster = FF_TraverseFAT( pxIOManager, pxFile->ulObjectCluster, ulNewCluster, &xResult ); + } + FF_UnlockFAT( pxIOManager ); + } + else + { + /* Well positioned. */ + } + + if( FF_isERR( xResult ) == pdFALSE ) + { + pxFile->ulCurrentCluster = ulNewCluster; + ulReturn = FF_FileLBA( pxFile ); + } + else + { + ulReturn = 0; + } + *pxError = xResult; + + return ulReturn; +} /* FF_SetCluster() */ +/*-----------------------------------------------------------*/ + +static int32_t FF_ReadPartial( FF_FILE *pxFile, uint32_t ulItemLBA, uint32_t ulRelBlockPos, uint32_t ulCount, + uint8_t *pucBuffer, FF_Error_t *pxError ) +{ +FF_Error_t xError = FF_ERR_NONE; +uint32_t ulBytesRead; + + /* Bytes to read are within a block and less than a block size. */ + #if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) + { + BaseType_t xLastRead; + + /* Optimised method: each file handle holds one data block + in cache: 'pxFile->pucBuffer'. */ + /* See if the current block will be accessed after this read: */ + if( ( ulRelBlockPos + ulCount ) >= ( uint32_t ) pxFile->pxIOManager->usSectorSize ) + { + /* After this read, ulFilePointer will point to the next block/sector. */ + xLastRead = pdTRUE; + } + else + { + /* It is not the last read within this block/sector. */ + xLastRead = pdFALSE; + } + + if( ( pxFile->ucState & FF_BUFSTATE_VALID ) == 0 ) + { + xError = FF_BlockRead( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE ); + if( FF_isERR( xError ) == pdFALSE ) + { + pxFile->ucState = FF_BUFSTATE_VALID; + } + } + + if( ( pxFile->ucState & FF_BUFSTATE_VALID ) != 0 ) + { + memcpy( pucBuffer, pxFile->pucBuffer + ulRelBlockPos, ulCount ); + pxFile->ulFilePointer += ulCount; + ulBytesRead = ulCount; + if( ( xLastRead == pdTRUE ) && ( ( pxFile->ucState & FF_BUFSTATE_WRITTEN ) != 0 ) ) + { + /* If the data was changed (file in 'update' mode), store the changes: */ + xError = FF_BlockWrite( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE ); + } + } + else + { + ulBytesRead = 0ul; + } + if( xLastRead == pdTRUE ) + { + /* As the next FF_Read() will go passed the current block, invalidate the buffer now. */ + pxFile->ucState = FF_BUFSTATE_INVALID; + } + } + #else + { + FF_Buffer_t *pxBuffer; + /* Reading in the standard way, using FF_Buffer_t. */ + pxBuffer = FF_GetBuffer( pxFile->pxIOManager, ulItemLBA, FF_MODE_READ ); + if( pxBuffer == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_READ ); + ulBytesRead = 0ul; + } + else + { + memcpy( pucBuffer, pxBuffer->pucBuffer + ulRelBlockPos, ulCount ); + /* Releasing a buffer in FF_MODE_READ mode will not lead to an error, + because no disk access is needed. */ + xError = FF_ReleaseBuffer( pxFile->pxIOManager, pxBuffer ); + pxFile->ulFilePointer += ulCount; + ulBytesRead = ulCount; + } + } + #endif + + *pxError = xError; + + return ulBytesRead; +} /* FF_ReadPartial() */ +/*-----------------------------------------------------------*/ + +/** + * @public + * @brief Equivalent to fread() + * + * @param pxFile FF_FILE object that was created by FF_Open(). + * @param ulElementSize The size of an element to read. + * @param ulCount The number of elements to read. + * @param buffer A pointer to a buffer of adequate size to be filled with the requested data. + * + * @return Number of bytes read. + * + * FF_Read() and FF_Write() work very similar. They both complete their task in 5 steps: + * 1. Read bytes up to a sector border: FF_ReadPartial() + * 2. Read sectors up to cluster border: FF_BlockRead() + * 3. Read complete clusters: FF_ReadClusters() + * 4. Read remaining sectors: FF_BlockRead() + * 5. Read remaining bytes: FF_ReadPartial() + **/ +int32_t FF_Read( FF_FILE *pxFile, uint32_t ulElementSize, uint32_t ulCount, uint8_t *pucBuffer ) +{ +uint32_t ulBytesLeft = ulElementSize * ulCount; +uint32_t ulBytesRead = 0; +uint32_t ulBytesToRead; +FF_IOManager_t *pxIOManager; +uint32_t ulRelBlockPos; +uint32_t ulItemLBA; +int32_t lResult; +uint32_t ulSectors; +uint32_t ulRelClusterPos; +uint32_t ulBytesPerCluster; +FF_Error_t xError; + + if( pxFile == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_READ ); + } + else + { + /* Check validity of the handle and the current position within the file. */ + xError = FF_CheckValid( pxFile ); + if( FF_isERR( xError ) == pdFALSE ) + { + if( ( pxFile->ucMode & FF_MODE_READ ) == 0 ) + { + /* File was not opened with READ mode access. */ + xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_READ ); + } + else if( pxFile->ulFilePointer >= pxFile->ulFileSize ) + { + /* The end-of-file is reached. The error READ_ZERO will not be + returned, it is just used to avoid further processing. */ + xError = ( FF_Error_t ) ( FF_ERR_FILE_READ_ZERO | FF_READ ); + } + else if( ( pxFile->ulFilePointer + ulBytesLeft ) > pxFile->ulFileSize ) + { + /* Note that many bytes can be read. */ + ulBytesLeft = pxFile->ulFileSize - pxFile->ulFilePointer; + } + } + else + { + /* The file handle is not valid. */ + } + } /* else pxFile != NULL */ + + if( FF_isERR( xError ) == pdFALSE ) + { + pxIOManager = pxFile->pxIOManager; + + /* And calculate the Logical Block Address. */ + ulItemLBA = FF_SetCluster( pxFile, &xError ); + + /* Get the position within a block. */ + ulRelBlockPos = FF_getMinorBlockEntry( pxIOManager, pxFile->ulFilePointer, 1 ); + /* Open a do {} while( 0 ) loop to allow easy breaks: */ + do + { + if( ( ulRelBlockPos + ulBytesLeft ) <= ( uint32_t ) pxIOManager->usSectorSize ) + { + /*---------- A small read within the current block only. */ + ulBytesRead = FF_ReadPartial( pxFile, ulItemLBA, ulRelBlockPos, ulBytesLeft, pucBuffer, &xError ); + break; + } + /*---------- Read (memcpy) to a Sector Boundary. */ + if( ulRelBlockPos != 0 ) + { + /* Not on a sector boundary, at this point the LBA is known. */ + ulBytesToRead = pxIOManager->usSectorSize - ulRelBlockPos; + ulBytesRead = FF_ReadPartial( pxFile, ulItemLBA, ulRelBlockPos, ulBytesToRead, pucBuffer, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + ulBytesLeft -= ulBytesRead; + pucBuffer += ulBytesRead; + } + + /*---------- Read sectors, up to a Cluster Boundary. */ + ulBytesPerCluster = ( pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->usSectorSize ); + ulRelClusterPos = pxFile->ulFilePointer % ( ulBytesPerCluster * pxIOManager->xPartition.ucBlkFactor ); + + if( ( ulRelClusterPos != 0 ) && ( ( ulRelClusterPos + ulBytesLeft ) >= ulBytesPerCluster ) ) + { + /* Need to get to cluster boundary. */ + ulItemLBA = FF_SetCluster( pxFile, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + ulSectors = pxIOManager->xPartition.ulSectorsPerCluster - ( ulRelClusterPos / pxIOManager->usSectorSize ); + xError = FF_BlockRead( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE ); + if( FF_isERR( xError ) ) + { + break; + } + ulBytesToRead = ulSectors * pxIOManager->usSectorSize; + ulBytesLeft -= ulBytesToRead; + pucBuffer += ulBytesToRead; + ulBytesRead += ulBytesToRead; + pxFile->ulFilePointer += ulBytesToRead; + } + + /*---------- Read entire clusters. */ + if( ulBytesLeft >= ulBytesPerCluster ) + { + uint32_t ulClusters; + + FF_SetCluster( pxFile, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + + ulClusters = ulBytesLeft / ulBytesPerCluster; + + xError = FF_ReadClusters( pxFile, ulClusters, pucBuffer ); + if( FF_isERR( xError ) ) + { + break; + } + ulBytesToRead = ulBytesPerCluster * ulClusters; + pxFile->ulFilePointer += ulBytesToRead; + ulBytesLeft -= ulBytesToRead; + pucBuffer += ulBytesToRead; + ulBytesRead += ulBytesToRead; + } + + /*---------- Read Remaining Blocks. */ + while( ulBytesLeft >= ( uint32_t ) pxIOManager->usSectorSize ) + { + ulSectors = ulBytesLeft / pxIOManager->usSectorSize; + { + /* HT: I'd leave these pPart/ulOffset for readability */ + /* and shorter code lines */ + FF_Partition_t *pPart = &( pxIOManager->xPartition ); + uint32_t ulOffset = ( pxFile->ulFilePointer / pxIOManager->usSectorSize ) % pPart->ulSectorsPerCluster; + uint32_t ulRemain = pPart->ulSectorsPerCluster - ulOffset; + if( ulSectors > ulRemain ) + { + ulSectors = ulRemain; + } + } + + ulItemLBA = FF_SetCluster( pxFile, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + xError = FF_BlockRead( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE ); + + if( FF_isERR( xError ) ) + { + break; + } + ulBytesToRead = ulSectors * pxIOManager->usSectorSize; + pxFile->ulFilePointer += ulBytesToRead; + ulBytesLeft -= ulBytesToRead; + pucBuffer += ulBytesToRead; + ulBytesRead += ulBytesToRead; + } + + /*---------- Read (memcpy) Remaining Bytes */ + if( ulBytesLeft == 0 ) + { + break; + } + ulItemLBA = FF_SetCluster( pxFile, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + /* Bytes to read are within a block and less than a block size. */ + FF_ReadPartial( pxFile, ulItemLBA, 0, ulBytesLeft, pucBuffer, &xError ); + if( FF_isERR( xError ) == pdFALSE ) + { + ulBytesRead += ulBytesLeft; + } + } + while( pdFALSE ); + } /* if( FF_isERR( xError ) == pdFALSE ) */ + + if( FF_GETERROR( xError ) == FF_ERR_FILE_READ_ZERO ) + { + lResult = 0; + } + else if( FF_isERR( xError ) ) + { + lResult = xError; + } + else + { + lResult = ( int32_t )( ulBytesRead / ulElementSize ); + } + + return lResult; +} /* FF_Read() */ +/*-----------------------------------------------------------*/ + +/** +* @public +* @brief Equivalent to fgetc() +* +* @param pxFile FF_FILE object that was created by FF_Open(). +* +* @return The character that was read (cast as a 32-bit interger). -1 on EOF. +* @return FF_Error_t code. (Check with if(FF_isERR(xRetVal)) {}). +* @return -1 EOF (end of file). +* +**/ +int32_t FF_GetC( FF_FILE *pxFile ) +{ +uint32_t ulItemLBA; +uint8_t ucReturnedChar; +uint32_t ulRelBlockPos; +FF_Error_t xResult; + + if( pxFile == NULL ) + { + xResult = FF_ERR_NULL_POINTER | FF_GETC; /* Ensure this is a signed error. */ + } + else if( ( pxFile->ucMode & FF_MODE_READ ) == 0 ) + { + xResult = FF_ERR_FILE_NOT_OPENED_IN_READ_MODE | FF_GETC; + } + else if( pxFile->ulFilePointer >= pxFile->ulFileSize ) + { + /* The end-of-file is reached. The error READ_ZERO will not be + returned, it is just used to avoid further processing. */ + xResult = FF_ERR_FILE_READ_ZERO | FF_READ; + } + else + { + ulRelBlockPos = FF_getMinorBlockEntry( pxFile->pxIOManager, pxFile->ulFilePointer, 1 ); + + ulItemLBA = FF_SetCluster( pxFile, &xResult ); + if( FF_isERR( xResult ) == pdFALSE ) + { + FF_ReadPartial( pxFile, ulItemLBA, ulRelBlockPos, 1, &ucReturnedChar, &xResult ); + if( FF_isERR( xResult ) == pdFALSE ) + { + xResult = ( int32_t ) ( ( uint32_t ) ucReturnedChar ); + } + } + } + + return ( int32_t ) xResult; +} /* FF_GetC() */ +/*-----------------------------------------------------------*/ + +/** +* @public +* @brief Gets a Line from a Text File, but no more than ulLimit characters. The line will be NULL terminated. +* +* The behaviour of this function is undefined when called on a binary file. +* It should just read in ulLimit bytes of binary, and ZERO terminate the line. +* +* This function works for both UNIX line feeds, and Windows CRLF type files. +* +* @param pxFile The FF_FILE object pointer. +* @param szLine The character buffer where the line should be stored. +* @param ulLimit This should be the max number of characters that szLine can hold. +* +* @return The number of characters read from the line, on success. +* @return 0 when no more lines are available, or when ulLimit is 0. +* @return FF_ERR_NULL_POINTER if pxFile or szLine are NULL; +* +**/ +int32_t FF_GetLine( FF_FILE *pxFile, char *pcLine, uint32_t ulLimit ) +{ +int32_t iChar = 0; +BaseType_t xIndex; +FF_Error_t xResult = FF_ERR_NONE; + + if( ( pxFile == NULL ) || ( pcLine == NULL ) ) + { + xResult = FF_ERR_NULL_POINTER | FF_GETLINE; + } + else + { + for( xIndex = 0; xIndex < ( BaseType_t ) ( ulLimit - 1 ); ++xIndex ) + { + iChar = FF_GetC( pxFile ); + + if( FF_isERR( iChar ) == pdFALSE ) + { + pcLine[ xIndex ] = ( char ) iChar; + + if( iChar == '\n' ) + { + /* Read until the first linefeed. Move xIndex forward so the + null terminator does not overwrite the \n. xIndex must be less + thank ( ulLimit - 1 ), so incrementing it here cannot make it + greater than ulLimit - 1, so the NULL can be inserted without + overflowing the buffer. */ + xIndex++; + break; + } + } + else + { + if( ( FF_GETERROR( iChar ) == FF_ERR_FILE_READ_ZERO ) && ( xIndex > 0 ) ) + { + /* Although FF_GetC() returns an End Of File, + the last few characters will be returned first. */ + iChar = xIndex; + } + break; + } + } + + /* Make sure that the resulting string always ends with a zero: */ + pcLine[ xIndex ] = '\0'; + + /*_RB_ In some paths this will be the second time FF_isERR() is called + on the same value. */ + if( FF_isERR( iChar ) == pdFALSE ) + { + /* Return the number of bytes read. */ + xResult = xIndex; + } + else + { + /* Return iChar as an error code (see FF_GetC()). */ + xResult = iChar; + } + } + + return xResult; +} /* FF_GetLine() */ +/*-----------------------------------------------------------*/ + +static int32_t FF_WritePartial( FF_FILE *pxFile, uint32_t ulItemLBA, uint32_t ulRelBlockPos, uint32_t ulCount, + const uint8_t *pucBuffer, FF_Error_t *pxError ) +{ +FF_Error_t xError; +uint32_t ulBytesWritten; + + #if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) + { + BaseType_t xLastRead; + if( ( ulRelBlockPos + ulCount ) >= ( uint32_t ) pxFile->pxIOManager->usSectorSize ) + { + /* After this read, ulFilePointer will point to the next block/sector. */ + xLastRead = pdTRUE; + } + else + { + /* It is not the last read within this block/sector. */ + xLastRead = pdFALSE; + } + + if( ( ( pxFile->ucState & FF_BUFSTATE_VALID ) == 0 ) && + ( ( ulRelBlockPos != 0 ) || ( pxFile->ulFilePointer < pxFile->ulFileSize ) ) ) + { + xError = FF_BlockRead( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE ); + /* pxFile->ucState will be set later on. */ + } + else + { + xError = FF_ERR_NONE; + /* the buffer is valid or a whole block/sector will be written, so it is + not necessary to read the contents first. */ + } + if( FF_isERR( xError ) == pdFALSE ) + { + memcpy( pxFile->pucBuffer + ulRelBlockPos, pucBuffer, ulCount ); + if( xLastRead == pdTRUE ) + { + xError = FF_BlockWrite( pxFile->pxIOManager, ulItemLBA, 1, pxFile->pucBuffer, pdFALSE ); + pxFile->ucState = FF_BUFSTATE_INVALID; + } + else + { + pxFile->ucState |= FF_BUFSTATE_WRITTEN | FF_BUFSTATE_VALID; + } + } + else + { + pxFile->ucState = FF_BUFSTATE_INVALID; + } + } + #else + { + FF_Buffer_t *pxBuffer; + if( ( ulRelBlockPos == 0 ) && ( pxFile->ulFilePointer >= pxFile->ulFileSize ) ) + { + /* An entire sector will be written. */ + pxBuffer = FF_GetBuffer( pxFile->pxIOManager, ulItemLBA, FF_MODE_WR_ONLY ); + } + else + { + /* A partial write will be done, make sure to read the contents before + changing anything. */ + pxBuffer = FF_GetBuffer( pxFile->pxIOManager, ulItemLBA, FF_MODE_WRITE ); + } + + if( pxBuffer == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_DEVICE_DRIVER_FAILED | FF_WRITE ); + } + else + { + /* Here we copy to the sector boundary. */ + memcpy( ( pxBuffer->pucBuffer + ulRelBlockPos ), pucBuffer, ulCount ); + + xError = FF_ReleaseBuffer( pxFile->pxIOManager, pxBuffer ); + } + } + #endif + if( FF_isERR( xError ) == pdFALSE ) + { + pxFile->ulFilePointer += ulCount; + ulBytesWritten = ulCount; + + if( pxFile->ulFilePointer > pxFile->ulFileSize ) + { + pxFile->ulFileSize = pxFile->ulFilePointer; + } + } + else + { + ulBytesWritten = 0ul; + } + *pxError = xError; + + return ulBytesWritten; +} /* FF_WritePartial() */ +/*-----------------------------------------------------------*/ + +/** + * @public + * @brief Writes data to a File. + * + * @param pxFile FILE Pointer. + * @param ulElementSize Size of an Element of Data to be copied. (in bytes). + * @param ulCount Number of Elements of Data to be copied. (ulElementSize * ulCount must not exceed ((2^31)-1) bytes. (2GB). For best performance, multiples of 512 bytes or Cluster sizes are best. + * @param pucBuffer Byte-wise pucBuffer containing the data to be written. + * + * FF_Read() and FF_Write() work very similar. They both complete their task in 5 steps: + * 1. Write bytes up to a sector border: FF_WritePartial() + * 2. Write sectors up to cluster border: FF_BlockWrite() + * 3. Write complete clusters: FF_WriteClusters() + * 4. Write remaining sectors: FF_BlockWrite() + * 5. Write remaining bytes: FF_WritePartial() + * @return +**/ +int32_t FF_Write( FF_FILE *pxFile, uint32_t ulElementSize, uint32_t ulCount, uint8_t *pucBuffer ) +{ +uint32_t ulBytesLeft = ulElementSize * ulCount; +uint32_t nBytesWritten = 0; +uint32_t nBytesToWrite; +FF_IOManager_t *pxIOManager; +uint32_t ulRelBlockPos; +uint32_t ulItemLBA; +int32_t lResult; +uint32_t ulSectors; +uint32_t ulRelClusterPos; +uint32_t ulBytesPerCluster; +FF_Error_t xError; + + if( pxFile == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_READ ); + } + else + { + /* Check validity of the handle and the current position within the file. */ + xError = FF_CheckValid( pxFile ); + if( FF_isERR( xError ) == pdFALSE ) + { + if( ( pxFile->ucMode & FF_MODE_WRITE ) == 0 ) + { + xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_WRITE ); + } + /* Make sure a write is after the append point. */ + else if( ( pxFile->ucMode & FF_MODE_APPEND ) != 0 ) + { + if( pxFile->ulFilePointer < pxFile->ulFileSize ) + { + xError = FF_Seek( pxFile, 0, FF_SEEK_END ); + } + } + } + } + + if( FF_isERR( xError ) == pdFALSE ) + { + pxIOManager = pxFile->pxIOManager; + + /* Open a do{} while( 0 ) loop to allow the use of breaks */ + do + { + /* Extend File for at least ulBytesLeft! + Handle file-space allocation + + 1 byte because the code assumes there is always a next cluster */ + xError = FF_ExtendFile( pxFile, pxFile->ulFilePointer + ulBytesLeft + 1 ); + if( FF_isERR( xError ) ) + { + /* On every error, break from the while( 0 ) loop. */ + break; + } + + ulRelBlockPos = FF_getMinorBlockEntry( pxIOManager, pxFile->ulFilePointer, 1 ); /* Get the position within a block. */ + ulItemLBA = FF_SetCluster( pxFile, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + + if( ( ulRelBlockPos + ulBytesLeft ) <= ( uint32_t ) pxIOManager->usSectorSize ) + { + /* Bytes to write are within a block and and do not go passed the current block. */ + nBytesWritten = FF_WritePartial( pxFile, ulItemLBA, ulRelBlockPos, ulBytesLeft, pucBuffer, &xError ); + break; + } + + /*---------- Write (memcpy) to a Sector Boundary. */ + if( ulRelBlockPos != 0 ) + { + /* Not writing on a sector boundary, at this point the LBA is known. */ + nBytesToWrite = pxIOManager->usSectorSize - ulRelBlockPos; + nBytesWritten = FF_WritePartial( pxFile, ulItemLBA, ulRelBlockPos, nBytesToWrite, pucBuffer, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + + ulBytesLeft -= nBytesWritten; + pucBuffer += nBytesWritten; + } + + /*---------- Write sectors, up to a Cluster Boundary. */ + ulBytesPerCluster = ( pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->usSectorSize ); + ulRelClusterPos = FF_getClusterPosition( pxIOManager, pxFile->ulFilePointer, 1 ); + + if( ( ulRelClusterPos != 0 ) && ( ( ulRelClusterPos + ulBytesLeft ) >= ulBytesPerCluster ) ) + { + /* Need to get to cluster boundary */ + ulItemLBA = FF_SetCluster( pxFile, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + + ulSectors = pxIOManager->xPartition.ulSectorsPerCluster - ( ulRelClusterPos / pxIOManager->usSectorSize ); + xError = FF_BlockWrite( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE ); + if( FF_isERR( xError ) ) + { + break; + } + + nBytesToWrite = ulSectors * pxIOManager->usSectorSize; + ulBytesLeft -= nBytesToWrite; + pucBuffer += nBytesToWrite; + nBytesWritten += nBytesToWrite; + pxFile->ulFilePointer += nBytesToWrite; + if( pxFile->ulFilePointer > pxFile->ulFileSize ) + { + pxFile->ulFileSize = pxFile->ulFilePointer; + } + } + + /*---------- Write entire Clusters. */ + if( ulBytesLeft >= ulBytesPerCluster ) + { + uint32_t ulClusters; + + FF_SetCluster( pxFile, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + + ulClusters = ( ulBytesLeft / ulBytesPerCluster ); + + xError = FF_WriteClusters( pxFile, ulClusters, pucBuffer ); + if( FF_isERR( xError ) ) + { + break; + } + + nBytesToWrite = ulBytesPerCluster * ulClusters; + ulBytesLeft -= nBytesToWrite; + pucBuffer += nBytesToWrite; + nBytesWritten += nBytesToWrite; + pxFile->ulFilePointer += nBytesToWrite; + if( pxFile->ulFilePointer > pxFile->ulFileSize ) + { + pxFile->ulFileSize = pxFile->ulFilePointer; + } + } + + /*---------- Write Remaining Blocks */ + while( ulBytesLeft >= ( uint32_t ) pxIOManager->usSectorSize ) + { + ulSectors = ulBytesLeft / pxIOManager->usSectorSize; + { + /* HT: I'd leave these pPart/ulOffset for readability... */ + FF_Partition_t *pPart = &( pxIOManager->xPartition ); + uint32_t ulOffset = ( pxFile->ulFilePointer / pxIOManager->usSectorSize ) % pPart->ulSectorsPerCluster; + uint32_t ulRemain = pPart->ulSectorsPerCluster - ulOffset; + if( ulSectors > ulRemain ) + { + ulSectors = ulRemain; + } + } + + ulItemLBA = FF_SetCluster( pxFile, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + + xError = FF_BlockWrite( pxIOManager, ulItemLBA, ulSectors, pucBuffer, pdFALSE ); + if( FF_isERR( xError ) ) + { + break; + } + + nBytesToWrite = ulSectors * pxIOManager->usSectorSize; + ulBytesLeft -= nBytesToWrite; + pucBuffer += nBytesToWrite; + nBytesWritten += nBytesToWrite; + pxFile->ulFilePointer += nBytesToWrite; + if( pxFile->ulFilePointer > pxFile->ulFileSize ) + { + pxFile->ulFileSize = pxFile->ulFilePointer; + } + } + + /*---------- Write (memcpy) Remaining Bytes */ + if( ulBytesLeft == 0 ) + { + break; + } + + ulItemLBA = FF_SetCluster( pxFile, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + FF_WritePartial( pxFile, ulItemLBA, 0, ulBytesLeft, pucBuffer, &xError ); + nBytesWritten += ulBytesLeft; + } + while( pdFALSE ); + } + + if( FF_isERR( xError ) ) + { + lResult = xError; + } + else + { + lResult = ( int32_t )( nBytesWritten / ulElementSize ); + } + + return lResult; +} /* FF_Write() */ +/*-----------------------------------------------------------*/ + +/** +* @public +* @brief Writes a char to a FILE. +* +* @param pxFile FILE Pointer. +* @param ucValue Char to be placed in the file. +* +* @return Returns the value written to the file, or a value less than 0. +* +**/ +int32_t FF_PutC( FF_FILE *pxFile, uint8_t ucValue ) +{ +uint32_t ulItemLBA; +uint32_t ulRelBlockPos; +FF_Error_t xResult; + + if( pxFile == NULL ) + { /* Ensure we don't have a Null file pointer on a Public interface. */ + xResult = FF_ERR_NULL_POINTER | FF_PUTC; + } + else if( ( pxFile->ucMode & FF_MODE_WRITE ) == 0 ) + { + xResult = FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_PUTC; + } + else + { + xResult = FF_ERR_NONE; + do + { + /* Make sure a write is after the append point. */ + if( ( pxFile->ucMode & FF_MODE_APPEND ) != 0 ) + { + if( pxFile->ulFilePointer < pxFile->ulFileSize ) + { + xResult = FF_Seek( pxFile, 0, FF_SEEK_END ); + if( FF_isERR( xResult ) ) + { + break; + } + } + } + + ulRelBlockPos = FF_getMinorBlockEntry( pxFile->pxIOManager, pxFile->ulFilePointer, 1 ); + + /* Handle File Space Allocation. */ + /* We'll write 1 byte and always have a next cluster reserved. */ + xResult = FF_ExtendFile( pxFile, pxFile->ulFilePointer + 2 ); + if( FF_isERR( xResult ) ) + { + break; + } + + ulItemLBA = FF_SetCluster( pxFile, &xResult ); + if( FF_isERR( xResult ) ) + { + break; + } + FF_WritePartial( pxFile, ulItemLBA, ulRelBlockPos, 1, &ucValue, &xResult ); + + if( FF_isERR( xResult ) == pdFALSE ) + { + xResult = ( FF_Error_t ) ucValue; + } + + } while( pdFALSE ); + } + + return xResult; +} /* FF_PutC() */ +/*-----------------------------------------------------------*/ + +/** +* @public +* @brief Equivalent to fseek() +* +* @param pxFile FF_FILE object that was created by FF_Open(). +* @param ulOffset An integer (+/-) to seek to, from the specified origin. +* @param xOrigin Where to seek from. (FF_SEEK_SET seek from start, FF_SEEK_CUR seek from current position, or FF_SEEK_END seek from end of file). +* +* @return 0 on Sucess, +* @return -2 if offset results in an invalid position in the file. +* @return FF_ERR_NULL_POINTER if a FF_FILE pointer was not received. +* @return -3 if an invalid origin was provided. +* +**/ +FF_Error_t FF_Seek( FF_FILE *pxFile, int32_t lOffset, BaseType_t xOrigin ) +{ +FF_Error_t xError; +uint32_t ulPosition = 0ul; + + xError = FF_CheckValid( pxFile ); + + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_FlushCache( pxFile->pxIOManager ); + + #if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) + { + if( FF_isERR( xError ) == pdFALSE ) + { + /* Here we must ensure that if the user tries to seek, and we had data in the file's + write buffer that this is written to disk. */ + if( ( pxFile->ucState & FF_BUFSTATE_WRITTEN ) != 0 ) + { + xError = FF_BlockWrite( pxFile->pxIOManager, FF_FileLBA( pxFile ), 1, pxFile->pucBuffer, pdFALSE ); + } + pxFile->ucState = FF_BUFSTATE_INVALID; + } + } + #endif /* ffconfigOPTIMISE_UNALIGNED_ACCESS */ + + if( FF_isERR( xError ) == pdFALSE ) + { + if( xOrigin == FF_SEEK_SET ) + { + ulPosition = ( uint32_t )lOffset; + } + else if( xOrigin == FF_SEEK_CUR ) + { + if( lOffset >= ( int32_t ) 0 ) + { + ulPosition = pxFile->ulFilePointer + ( ( uint32_t ) lOffset ); + } + else + { + ulPosition = pxFile->ulFilePointer - ( ( uint32_t ) ( -lOffset ) ); + } + } + else if( xOrigin == FF_SEEK_END ) + { + /* 'FF_SEEK_END' only allows zero or negative values. */ + if( lOffset <= ( int32_t ) 0 ) + { + ulPosition = pxFile->ulFileSize - ( ( uint32_t ) ( -lOffset ) ); + } + } + else + { + xError = ( FF_Error_t ) ( FF_SEEK | FF_ERR_FILE_SEEK_INVALID_ORIGIN ); + /* To supress a compiler warning. */ + ulPosition = ( uint32_t ) 0u; + } + + if( FF_isERR( xError ) == pdFALSE ) + { + if( ulPosition <= ( uint32_t ) pxFile->ulFileSize ) + { + if( ulPosition != ( uint32_t ) pxFile->ulFilePointer ) + { + pxFile->ulFilePointer = ulPosition; + FF_SetCluster( pxFile, &xError ); + } + } + else + { + xError = ( FF_Error_t ) ( FF_SEEK | FF_ERR_FILE_SEEK_INVALID_POSITION ); + } + } + } + } + + return xError; +} /* FF_Seek() */ +/*-----------------------------------------------------------*/ + +#if( ffconfigREMOVABLE_MEDIA != 0 ) + /** + * @public + * @brief Invalidate all file handles belonging to pxIOManager + * + * @param pIoMan FF_IOManager_t object that was created by FF_CreateIOManger(). + * + * @return 0 if no handles were open + * @return >0 the amount of handles that were invalidated + * @return <0 probably an invalid FF_IOManager_t pointer + * + **/ + int32_t FF_Invalidate( FF_IOManager_t *pxIOManager ) + { + int32_t xResult; + FF_FILE *pxFileChain; + + if( pxIOManager == NULL ) + { + xResult = FF_ERR_NULL_POINTER | FF_INVALIDATE; + } + else + { + xResult = 0; + FF_PendSemaphore( pxIOManager->pvSemaphore ); + { + pxIOManager->ucFlags |= FF_IOMAN_DEVICE_IS_EXTRACTED; + /* Semaphore is required, or linked list might change */ + pxFileChain = ( FF_FILE * ) pxIOManager->FirstFile; + if( pxFileChain != NULL ) + { + /* Count elements in FirstFile */ + do + { + pxFileChain->ulValidFlags |= FF_VALID_FLAG_INVALID; + xResult++; + pxFileChain = pxFileChain->pxNext; + } + while( pxFileChain != NULL ); + } + } + + FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + } + + return xResult; + } /* FF_Invalidate() */ +#endif /* ffconfigREMOVABLE_MEDIA */ +/*-----------------------------------------------------------*/ + +/** +* @public +* @brief Check validity of file handle +* +* @param pxFile FF_FILE object that was created by FF_Open(). +* +* @return 0 on sucess. +* @return FF_ERR_NULL_POINTER if a null pointer was provided. +* @return FF_ERR_FILE_BAD_HANDLE if handle is not recognized +* @return FF_ERR_FILE_MEDIA_REMOVED please call FF_Close +* +**/ +FF_Error_t FF_CheckValid( FF_FILE *pxFile ) +{ + FF_FILE *pxFileChain; + FF_Error_t xError; + + if( ( pxFile == NULL ) || ( pxFile->pxIOManager == NULL ) ) + { + xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_CHECKVALID ); + } + else + { + FF_PendSemaphore( pxFile->pxIOManager->pvSemaphore ); + { + pxFileChain = ( FF_FILE * ) pxFile->pxIOManager->FirstFile; + xError = ( FF_Error_t ) ( FF_ERR_FILE_BAD_HANDLE | FF_CHECKVALID ); + while( pxFileChain != NULL ) + { + if( pxFileChain == pxFile ) + { + #if( ffconfigREMOVABLE_MEDIA != 0 ) + if( ( pxFileChain->ulValidFlags & FF_VALID_FLAG_INVALID ) != 0 ) + { + /* The medium has been removed while this file handle was open. */ + xError = ( FF_Error_t ) ( FF_ERR_FILE_MEDIA_REMOVED | FF_CHECKVALID ); + } + else + #endif + { + /* Found the handle, so it is a valid / existing handle. */ + xError = FF_ERR_NONE; + } + + break; + } + + pxFileChain = pxFileChain->pxNext; + } + } + FF_ReleaseSemaphore( pxFile->pxIOManager->pvSemaphore ); + } + + return xError; +} /* FF_CheckValid() */ +/*-----------------------------------------------------------*/ + +#if( ffconfigTIME_SUPPORT != 0 ) + /** + * @public + * @brief Set the time-stamp(s) of a file entry + * + * @param pxFile FF_FILE object that was created by FF_Open(). + * @param pxTime FF_SystemTime_t the time stamp + * @param uxWhat UBaseType_t a combination of enum ETimeMask + * + * @return 0 or FF_Error_t + * + **/ + FF_Error_t FF_SetFileTime( FF_FILE *pxFile, FF_SystemTime_t *pxTime, UBaseType_t uxWhat ) + { + FF_DirEnt_t xOriginalEntry; + FF_Error_t xError; + + xError = FF_CheckValid( pxFile ); + if( FF_isERR( xError ) == pdFALSE ) + { + if( pxFile->ulValidFlags & FF_VALID_FLAG_DELETED ) + { /*if (pxFile->FileDeleted) */ + xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETFILETIME ); + } + else if( ( pxFile->ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND ) ) == 0 ) + { + xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_SETFILETIME ); + } + else + { + /* Update the Dirent! */ + xError = FF_GetEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry ); + if( FF_isERR( xError ) == pdFALSE ) + { + if( uxWhat & ETimeCreate ) + { + xOriginalEntry.xCreateTime = *pxTime; /*/< Date and Time Created. */ + } + + if( uxWhat & ETimeMod ) + { + xOriginalEntry.xModifiedTime = *pxTime; /*/< Date and Time Modified. */ + } + + if( uxWhat & ETimeAccess ) + { + xOriginalEntry.xAccessedTime = *pxTime; /*/< Date of Last Access. */ + } + + xError = FF_PutEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL ); + } + + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_FlushCache( pxFile->pxIOManager ); /* Ensure all modfied blocks are flushed to disk! */ + } + } + } + + return xError; + } /* FF_SetFileTime() */ +#endif /* ffconfigTIME_SUPPORT */ +/*-----------------------------------------------------------*/ + +#if( ffconfigTIME_SUPPORT != 0 ) + /** + * @public + * @brief Set the time-stamp(s) of a file entry (by name) + * + * @param pxIOManager FF_IOManager_t device handle + * @param pcPath int8_t/FF_T_WCHAR name of the file + * @param pxTime FF_SystemTime_t the time stamp + * @param uxWhat UBaseType_t a combination of enum ETimeMask + * + * @return 0 or FF_Error_t + * + **/ + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_Error_t FF_SetTime ( FF_IOManager_t * pxIOManager, const FF_T_WCHAR * pcPath, FF_SystemTime_t *pxTime, UBaseType_t uxWhat ) + #else + FF_Error_t FF_SetTime ( FF_IOManager_t * pxIOManager, const char *pcPath, FF_SystemTime_t *pxTime, UBaseType_t uxWhat ) + #endif /* ffconfigUNICODE_UTF16_SUPPORT */ + { + FF_DirEnt_t xOriginalEntry; + FF_Error_t xError; + uint32_t ulFileCluster; + BaseType_t xIndex; + FF_FindParams_t xFindParams; + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_T_WCHAR pcFileName[ffconfigMAX_FILENAME]; + #else + char pcFileName[ffconfigMAX_FILENAME]; + #endif /* ffconfigUNICODE_UTF16_SUPPORT */ + + xIndex = ( BaseType_t ) STRLEN( pcPath ); + + memset( &xFindParams, '\0', sizeof( xFindParams ) ); + + while( xIndex != 0 ) + { + if( pcPath[ xIndex ] == '\\' || pcPath[ xIndex ] == '/' ) + { + break; + } + + xIndex--; + } + + STRNCPY( pcFileName, ( pcPath + xIndex + 1 ), ffconfigMAX_FILENAME ); + + if( xIndex == 0 ) + { + xIndex = 1; + } + + xFindParams.ulDirCluster = FF_FindDir( pxIOManager, pcPath, ( uint16_t ) xIndex, &xError ); + if( FF_isERR( xError ) == pdFALSE ) + { + if( xFindParams.ulDirCluster == 0 ) + { + xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME ); + } + else + { + ulFileCluster = FF_FindEntryInDir( pxIOManager, &xFindParams, pcFileName, 0, &xOriginalEntry, &xError ); + if( ( FF_isERR( xError ) == pdFALSE ) || ( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR ) ) + { + if( ulFileCluster == 0ul ) + { + /*FF_PRINTF ("FF_SetTime: Can not find '%s'\n", pcFileName); */ + xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME ); + } + } + } + } + + if( FF_isERR( xError ) == pdFALSE ) + { + /* Update the Dirent! */ + if( uxWhat & ETimeCreate ) + { + xOriginalEntry.xCreateTime = *pxTime; /*/< Date and Time Created. */ + } + + if( uxWhat & ETimeMod ) + { + xOriginalEntry.xModifiedTime = *pxTime; /*/< Date and Time Modified. */ + } + + if( uxWhat & ETimeAccess ) + { + xOriginalEntry.xAccessedTime = *pxTime; /*/< Date of Last Access. */ + } + + xError = FF_PutEntry( pxIOManager, xOriginalEntry.usCurrentItem - 1, xFindParams.ulDirCluster, &xOriginalEntry, NULL ); + + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_FlushCache( pxIOManager ); /* Ensure all modified blocks are flushed to disk! */ + } + } + + return xError; + } /* FF_SetTime() */ +#endif /* ffconfigTIME_SUPPORT */ +/*-----------------------------------------------------------*/ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +FF_Error_t FF_SetPerm( FF_IOManager_t * pxIOManager, const FF_T_WCHAR * pcPath, UBaseType_t aPerm ) +#else +FF_Error_t FF_SetPerm( FF_IOManager_t * pxIOManager, const char *pcPath, UBaseType_t aPerm ) +#endif +{ +FF_DirEnt_t xOriginalEntry; +FF_Error_t xError; +uint32_t ulFileCluster; +BaseType_t xIndex; +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_T_WCHAR pcFileName[ffconfigMAX_FILENAME]; +#else + char pcFileName[ffconfigMAX_FILENAME]; +#endif +FF_FindParams_t xFindParams; + + xIndex = ( BaseType_t ) STRLEN( pcPath ); + + memset( &xFindParams, '\0', sizeof( xFindParams ) ); + + while( xIndex != 0 ) + { + if( pcPath[ xIndex ] == '\\' || pcPath[ xIndex ] == '/' ) + { + break; + } + + xIndex--; + } + + STRNCPY( pcFileName, ( pcPath + xIndex + 1 ), ffconfigMAX_FILENAME ); + + if( xIndex == 0 ) + { + xIndex = 1; + } + + /* Open a do {} while( pdFALSE ) loop to allow the use of break statements. */ + do + { + xFindParams.ulDirCluster = FF_FindDir( pxIOManager, pcPath, ( uint16_t ) xIndex, &xError ); + if( xError ) + { + break; + } + + if( !xFindParams.ulDirCluster ) + { + xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME ); + break; + } + + ulFileCluster = FF_FindEntryInDir( pxIOManager, &xFindParams, pcFileName, 0, &xOriginalEntry, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + + if( ulFileCluster == 0ul ) + { + /*FF_PRINTF ("FF_SetTime: Can not find '%s'\n", pcFileName); */ + xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_FOUND | FF_SETTIME ); + break; + } + + /* #define FF_FAT_ATTR_READONLY 0x01 */ + /* #define FF_FAT_ATTR_HIDDEN 0x02 */ + /* #define FF_FAT_ATTR_SYSTEM 0x04 */ + /* #define FF_FAT_ATTR_VOLID 0x08 */ + /* #define FF_FAT_ATTR_DIR 0x10 */ + /* #define FF_FAT_ATTR_ARCHIVE 0x20 */ + /* #define FF_FAT_ATTR_LFN 0x0F */ + #define FF_FAT_ATTR_USER ( ( uint8_t ) FF_FAT_ATTR_READONLY | FF_FAT_ATTR_HIDDEN | FF_FAT_ATTR_SYSTEM | FF_FAT_ATTR_ARCHIVE ) + /* Update the Dirent! */ + xOriginalEntry.ucAttrib &= ~FF_FAT_ATTR_USER; + xOriginalEntry.ucAttrib |= ( aPerm & FF_FAT_ATTR_USER ); + xError = FF_PutEntry( pxIOManager, xOriginalEntry.usCurrentItem - 1, xFindParams.ulDirCluster, &xOriginalEntry, NULL ); + + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_FlushCache( pxIOManager ); /* Ensure all modfied blocks are flushed to disk! */ + } + } + while( pdFALSE ); + + return xError; +} /* FF_SetPerm() */ +/*-----------------------------------------------------------*/ + +/** +* @public +* @brief Equivalent to fclose() +* +* @param pxFile FF_FILE object that was created by FF_Open(). +* +* @return 0 on sucess. +* @return -1 if a null pointer was provided. +* +**/ +FF_Error_t FF_Close( FF_FILE *pxFile ) +{ +FF_FILE *pxFileChain; +FF_DirEnt_t xOriginalEntry; +FF_Error_t xError; + + /* Opening a do {} while( 0 ) loop to allow the use of the break statement. */ + do + { + if( pxFile == NULL ) + { + xError = ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_CLOSE ); + break; + } + + /* It is important to check that user doesn't supply invalid + handle or a handle invalid because of "media removed" */ + xError = FF_CheckValid( pxFile ); + + #if( ffconfigREMOVABLE_MEDIA != 0 ) + { + if( FF_GETERROR( xError ) == FF_ERR_FILE_MEDIA_REMOVED ) + { + FF_PendSemaphore( pxFile->pxIOManager->pvSemaphore ); + { + pxFileChain = ( FF_FILE * ) pxFile->pxIOManager->FirstFile; + if( pxFileChain == pxFile ) + { + pxFile->pxIOManager->FirstFile = pxFile->pxNext; + } + else + { + while( pxFileChain ) + { + if( pxFileChain->pxNext == pxFile ) + { + pxFileChain->pxNext = pxFile->pxNext; + break; + } + + pxFileChain = pxFileChain->pxNext; /* Forgot this one */ + } + } + } /* Semaphore released, linked list was shortened! */ + + FF_ReleaseSemaphore( pxFile->pxIOManager->pvSemaphore ); + #if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) + { + ffconfigFREE( pxFile->pucBuffer ); + } + #endif /* ffconfigOPTIMISE_UNALIGNED_ACCESS */ + ffconfigFREE( pxFile ); /* So at least we have freed the pointer. */ + xError = FF_ERR_NONE; + break; + } + } + #endif /* ffconfigREMOVABLE_MEDIA */ + + if( FF_isERR( xError ) ) + { + /* FF_ERR_FILE_BAD_HANDLE or FF_ERR_NULL_POINTER */ + break; + } + + /* So here we have a normal valid file handle. */ + + /* Sometimes FreeRTOS+FAT will leave a trailing cluster on the end of a cluster chain. + To ensure we're compliant we shall now check for this condition and truncate it. */ + if( ( ( pxFile->ulValidFlags & FF_VALID_FLAG_DELETED ) == 0 ) && + ( ( pxFile->ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE ) ) != 0 ) ) + { + uint32_t ulClusterSize; + + /* File is not deleted and it was opened for writing or updating */ + ulClusterSize = pxFile->pxIOManager->xPartition.usBlkSize * pxFile->pxIOManager->xPartition.ulSectorsPerCluster; + + if( ( ( pxFile->ulFileSize % ulClusterSize ) == 0 ) && ( pxFile->ulObjectCluster != 0ul ) ) + { + /* The file's length is a multiple of cluster size. This means + that an extra cluster has been reserved, which wasn't necessary. */ + xError = FF_Truncate( pxFile, pdTRUE ); + } + + /* Get the directory entry and update it to show the new file size */ + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_GetEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry ); + + /* Now update the directory entry */ + if( ( FF_isERR( xError ) == pdFALSE ) && + ( ( pxFile->ulFileSize != xOriginalEntry.ulFileSize ) || ( pxFile->ulFileSize == 0UL ) ) ) + { + if( pxFile->ulFileSize == 0UL ) + { + xOriginalEntry.ulObjectCluster = 0; + } + + xOriginalEntry.ulFileSize = pxFile->ulFileSize; + xError = FF_PutEntry( pxFile->pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL ); + } + } + } + + /* Handle Linked list! */ + FF_PendSemaphore( pxFile->pxIOManager->pvSemaphore ); + { /* Semaphore is required, or linked list could become corrupted. */ + pxFileChain = ( FF_FILE * ) pxFile->pxIOManager->FirstFile; + if( pxFileChain == pxFile ) + { + pxFile->pxIOManager->FirstFile = pxFile->pxNext; + } + else + { + while( pxFileChain ) + { + if( pxFileChain->pxNext == pxFile ) + { + /* Found it, remove it from the list. */ + pxFileChain->pxNext = pxFile->pxNext; + break; + } + pxFileChain = pxFileChain->pxNext; + } + } + } /* Semaphore released, linked list was shortened! */ + FF_ReleaseSemaphore( pxFile->pxIOManager->pvSemaphore ); + + #if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) + { + if( pxFile->pucBuffer != NULL ) + { + /* Ensure any unaligned points are pushed to the disk! */ + if( pxFile->ucState & FF_BUFSTATE_WRITTEN ) + { + FF_Error_t xTempError; + + xTempError = FF_BlockWrite( pxFile->pxIOManager, FF_FileLBA( pxFile ), 1, pxFile->pucBuffer, pdFALSE ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + + ffconfigFREE( pxFile->pucBuffer ); + } + } + #endif + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_FlushCache( pxFile->pxIOManager ); /* Ensure all modified blocks are flushed to disk! */ + } + ffconfigFREE( pxFile ); + } + while( pdFALSE ); + + return xError; +} /* FF_Close() */ +/*-----------------------------------------------------------*/ + +/** +* @public +* @brief Make Filesize equal to the FilePointer and truncates the file to this position +* +* @param pxFile FF_FILE object that was created by FF_Open(). +* +* @return 0 on sucess. +* @return negative if some error occurred +* +**/ +FF_Error_t FF_SetEof( FF_FILE *pxFile ) +{ + FF_Error_t xError; + + /* Check if the file was not deleted and if it was opened with write permissions: */ + if( ( ( pxFile->ulValidFlags & FF_VALID_FLAG_DELETED ) == 0 ) && + ( ( pxFile->ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE ) ) != 0 ) ) + { + pxFile->ulFileSize = pxFile->ulFilePointer; + if( pxFile->ulObjectCluster != 0ul ) + { + xError = FF_Truncate( pxFile, pdFALSE ); + } + else + { + xError = FF_ERR_NONE; + } + } + else + { + xError = ( FF_Error_t ) ( FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE | FF_SETEOF ); + } + + return xError; +} /* FF_SetEof() */ +/*-----------------------------------------------------------*/ + +/** +* @public +* @brief Truncate a file to 'pxFile->ulFileSize' +* +* @param pxFile FF_FILE object that was created by FF_Open(). +* +* @return 0 on sucess. +* @return negative if some error occurred +* +**/ +static FF_Error_t FF_Truncate( FF_FILE *pxFile, BaseType_t bClosing ) +{ +FF_Error_t xError; +FF_IOManager_t *pxIOManager = pxFile->pxIOManager; + +uint32_t ulClusterSize; +uint32_t ulClusterCount; +uint32_t ulClustersNeeded; + + /* The number of bytes contained in a cluster. */ + ulClusterSize = pxIOManager->xPartition.usBlkSize * pxIOManager->xPartition.ulSectorsPerCluster; + + /* See how many clusters have been allocated. */ + ulClusterCount = FF_GetChainLength( pxIOManager, pxFile->ulObjectCluster, NULL, &xError ); + + /* Calculate the actual number of clusters needed, rounding up */ + ulClustersNeeded = ( pxFile->ulFileSize + ulClusterSize - 1 ) / ulClusterSize; + if( bClosing != pdFALSE ) + { + /* The handle will be closed after truncating. This function is called + because Filesize is an exact multiple of ulClusterSize. */ + ulClustersNeeded = pxFile->ulFileSize / ulClusterSize; + } + else + { + /* This function is called to make the file size equal to the current + position within the file. Always keep an extra cluster to write to. */ + ulClustersNeeded = ( pxFile->ulFileSize + ulClusterSize ) / ulClusterSize; + } + + /* First change the FAT chain. */ + if( ( FF_isERR( xError ) == pdFALSE ) && ( ulClusterCount > ulClustersNeeded ) ) + { + if( ulClustersNeeded == 0ul ) + { + FF_LockFAT( pxIOManager ); + { + /* In FF_Truncate() */ + xError = FF_UnlinkClusterChain( pxIOManager, pxFile->ulObjectCluster, 0 ); + } + FF_UnlockFAT( pxIOManager ); + + if( FF_isERR( xError ) == pdFALSE ) + { + FF_DirEnt_t xOriginalEntry; + + /* The directory denotes the address of the first data cluster of every file. + Now change it to 'ulAddrCurrentCluster': */ + xError = FF_GetEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry ); + + if( FF_isERR( xError ) == pdFALSE ) + { + xOriginalEntry.ulObjectCluster = 0ul; + xError = FF_PutEntry( pxIOManager, pxFile->usDirEntry, pxFile->ulDirCluster, &xOriginalEntry, NULL ); + + if( FF_isERR( xError ) == pdFALSE ) + { + pxFile->ulObjectCluster = 0ul; + pxFile->ulChainLength = 0ul; + pxFile->ulCurrentCluster = 0ul; + pxFile->ulEndOfChain = 0ul; + } + } + } + } + else + { + FF_LockFAT( pxIOManager ); + { + uint32_t ulTruncateCluster = FF_TraverseFAT( pxIOManager, pxFile->ulObjectCluster, ulClustersNeeded - 1, &xError ); + + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_UnlinkClusterChain( pxIOManager, ulTruncateCluster, 1 ); + } + } + FF_UnlockFAT( pxIOManager ); + } + } + + return xError; +} /* FF_Truncate() */ +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_format.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_format.c new file mode 100644 index 000000000..e4f6c1c03 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_format.c @@ -0,0 +1,753 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_format.c + * @ingroup FORMAT + * + * @defgroup FAT Fat File-System + * @brief Format a drive, given the number of sectors. + * + **/ + +#include "ff_headers.h" + +#include +#include + +#if defined( __BORLANDC__ ) + #include "ff_windows.h" +#else + #include "FreeRTOS.h" + #include "task.h" /* For FreeRTOS date/time function */ +#endif + + +/*=========================================================================================== */ + +#define OFS_PART_ACTIVE_8 0x000 /* 0x01BE 0x80 if active */ +#define OFS_PART_START_HEAD_8 0x001 /* 0x01BF */ +#define OFS_PART_START_SEC_TRACK_16 0x002 /* 0x01C0 */ +#define OFS_PART_ID_NUMBER_8 0x004 /* 0x01C2 */ +#define OFS_PART_ENDING_HEAD_8 0x005 /* 0x01C3 */ +#define OFS_PART_ENDING_SEC_TRACK_16 0x006 /* 0x01C4 = SectorCount - 1 - ulHiddenSectors */ +#define OFS_PART_STARTING_LBA_32 0x008 /* 0x01C6 = ulHiddenSectors (This is important) */ +#define OFS_PART_LENGTH_32 0x00C /* 0x01CA = SectorCount - 1 - ulHiddenSectors */ + +#define OFS_PTABLE_MACH_CODE 0x000 /* 0x0000 */ +#define OFS_PTABLE_PART_0 0x1BE /* 446 */ +#define OFS_PTABLE_PART_1 0x1CE /* 462 */ +#define OFS_PTABLE_PART_2 0x1DE /* 478 */ +#define OFS_PTABLE_PART_3 0x1FE /* 494 */ +#define OFS_PTABLE_PART_LEN 16 + +/*=========================================================================================== */ + +#define OFS_BPB_jmpBoot_24 0x000 /* uchar jmpBoot[3] "0xEB 0x00 0x90" */ +#define OFS_BPB_OEMName_64 0x003 /* uchar BS_OEMName[8] "MSWIN4.1" */ + +#define OFS_BPB_BytsPerSec_16 0x00B /* Only 512, 1024, 2048 or 4096 */ +#define OFS_BPB_SecPerClus_8 0x00D /* Only 1, 2, 4, 8, 16, 32, 64, 128 */ +#define OFS_BPB_ResvdSecCnt_16 0x00E /* ulFATReservedSectors, e.g. 1 (FAT12/16) or 32 (FAT32) */ + +#define OFS_BPB_NumFATs_8 0x010 /* 2 recommended */ +#define OFS_BPB_RootEntCnt_16 0x011 /* ((iFAT16RootSectors * 512) / 32) 512 (FAT12/16) or 0 (FAT32) */ +#define OFS_BPB_TotSec16_16 0x013 /* xxx (FAT12/16) or 0 (FAT32) */ +#define OFS_BPB_Media_8 0x015 /* 0xF0 (rem media) also in FAT[0] low byte */ + +#define OFS_BPB_FATSz16_16 0x016 +#define OFS_BPB_SecPerTrk_16 0x018 /* n.a. CF has no tracks */ +#define OFS_BPB_NumHeads_16 0x01A /* n.a. 1 ? */ +#define OFS_BPB_HiddSec_32 0x01C /* n.a. 0 for nonparitioned volume */ +#define OFS_BPB_TotSec32_32 0x020 /* >= 0x10000 */ + +#define OFS_BPB_16_DrvNum_8 0x024 /* n.a. */ +#define OFS_BPB_16_Reserved1_8 0x025 /* n.a. */ +#define OFS_BPB_16_BootSig_8 0x026 /* n.a. */ +#define OFS_BPB_16_BS_VolID_32 0x027 /* "unique" number */ +#define OFS_BPB_16_BS_VolLab_88 0x02B /* "NO NAME " */ +#define OFS_BPB_16_FilSysType_64 0x036 /* "FAT12 " */ + +#define OFS_BPB_32_FATSz32_32 0x024 /* Only when BPB_FATSz16 = 0 */ +#define OFS_BPB_32_ExtFlags_16 0x028 /* FAT32 only */ +#define OFS_BPB_32_FSVer_16 0x02A /* 0:0 */ +#define OFS_BPB_32_RootClus_32 0x02C /* See 'iFAT32RootClusters' Normally 2 */ +#define OFS_BPB_32_FSInfo_16 0x030 /* Normally 1 */ +#define OFS_BPB_32_BkBootSec_16 0x032 /* Normally 6 */ +#define OFS_BPB_32_Reserved_96 0x034 /* Zeros */ +#define OFS_BPB_32_DrvNum_8 0x040 /* n.a. */ +#define OFS_BPB_32_Reserved1_8 0x041 /* n.a. */ +#define OFS_BPB_32_BootSig_8 0x042 /* n.a. */ +#define OFS_BPB_32_VolID_32 0x043 /* "unique" number */ +#define OFS_BPB_32_VolLab_88 0x047 /* "NO NAME " */ +#define OFS_BPB_32_FilSysType_64 0x052 /* "FAT12 " */ + +#define OFS_FSI_32_LeadSig 0x000 /* With contents 0x41615252 */ +#define OFS_FSI_32_Reserved1 0x004 /* 480 times 0 */ +#define OFS_FSI_32_StrucSig 0x1E4 /* With contents 0x61417272 */ +#define OFS_FSI_32_Free_Count 0x1E8 /* last known free cluster count on the volume, ~0 for unknown */ +#define OFS_FSI_32_Nxt_Free 0x1EC /* cluster number at which the driver should start looking for free clusters */ +#define OFS_FSI_32_Reserved2 0x1F0 /* zero's */ +#define OFS_FSI_32_TrailSig 0x1FC /* 0xAA550000 (little endian) */ + +#define RESV_COUNT 32 + +#ifdef ffconfigMIN_CLUSTERS_FAT32 + #define MIN_CLUSTER_COUNT_FAT32 ffconfigMIN_CLUSTERS_FAT32 +#else + #define MIN_CLUSTER_COUNT_FAT32 ( 65525 ) +#endif + +#ifdef ffconfigMIN_CLUSTERS_FAT16 + #define MIN_CLUSTERS_FAT16 ffconfigMIN_CLUSTERS_FAT16 +#else + #define MIN_CLUSTERS_FAT16 ( 4085 + 1 ) +#endif + +#ifndef ffconfigFAT16_ROOT_SECTORS + #define ffconfigFAT16_ROOT_SECTORS 32 +#endif + +static portINLINE uint32_t ulMin32( uint32_t a, uint32_t b ) +{ +uint32_t ulReturn; + + if( a <= b ) + { + ulReturn = a; + } + else + { + ulReturn = b; + } + return ulReturn; +} + +/*_RB_ Candidate for splitting into multiple functions? */ +FF_Error_t FF_Format( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber, BaseType_t xPreferFAT16, BaseType_t xSmallClusters ) +{ +uint32_t ulHiddenSectors; /* Space from MBR and partition table */ +const uint32_t ulFSInfo = 1; /* Sector number of FSINFO structure within the reserved area */ +const uint32_t ulBackupBootSector = 6; /* Sector number of "copy of the boot record" within the reserved area */ +const BaseType_t xFATCount = 2; /* Number of FAT's */ +uint32_t ulFATReservedSectors = 0; /* Space between the partition table and FAT table. */ +int32_t iFAT16RootSectors = 0; /* Number of sectors reserved for root directory (FAT16 only) */ +int32_t iFAT32RootClusters = 0; /* Initial amount of clusters claimed for root directory (FAT32 only) */ +uint8_t ucFATType = 0; /* Either 'FF_T_FAT16' or 'FF_T_FAT32' */ +uint32_t ulVolumeID = 0; /* A pseudo Volume ID */ + +uint32_t ulSectorsPerFAT = 0; /* Number of sectors used by a single FAT table */ +uint32_t ulClustersPerFATSector = 0; /* # of clusters which can be described within a sector (256 or 128) */ +uint32_t ulSectorsPerCluster = 0; /* Size of a cluster (# of sectors) */ +uint32_t ulUsableDataSectors = 0; /* Usable data sectors (= SectorCount - (ulHiddenSectors + ulFATReservedSectors)) */ +uint32_t ulUsableDataClusters = 0; /* equals "ulUsableDataSectors / ulSectorsPerCluster" */ +uint32_t ulNonDataSectors = 0; /* ulFATReservedSectors + ulHiddenSectors + iFAT16RootSectors */ +uint32_t ulClusterBeginLBA = 0; /* Sector address of the first data cluster */ +uint32_t ulSectorCount; +uint8_t *pucSectorBuffer = 0; +FF_SPartFound_t xPartitionsFound; +FF_Part_t *pxMyPartition = 0; +FF_IOManager_t *pxIOManager = pxDisk->pxIOManager; + + FF_PartitionSearch( pxIOManager, &xPartitionsFound ); + if( xPartitionNumber >= xPartitionsFound.iCount ) + { + return FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_MODULE_FORMAT; + } + + pxMyPartition = xPartitionsFound.pxPartitions + xPartitionNumber; + ulSectorCount = pxMyPartition->ulSectorCount; + + ulHiddenSectors = pxMyPartition->ulStartLBA; + + if( ( ( xPreferFAT16 == pdFALSE ) && ( ( ulSectorCount - RESV_COUNT ) >= 65536 ) ) || + ( ( ulSectorCount - RESV_COUNT ) >= ( 64 * MIN_CLUSTER_COUNT_FAT32 ) ) ) + { + ucFATType = FF_T_FAT32; + iFAT32RootClusters = 2; + ulFATReservedSectors = RESV_COUNT; + iFAT16RootSectors = 0; + } + else + { + ucFATType = FF_T_FAT16; + iFAT32RootClusters = 0; + ulFATReservedSectors = 1u; + iFAT16RootSectors = ffconfigFAT16_ROOT_SECTORS; /* 32 sectors to get 512 dir entries */ + } + + /* Set start sector and length to allow FF_BlockRead/Write */ + pxIOManager->xPartition.ulTotalSectors = pxMyPartition->ulSectorCount; + pxIOManager->xPartition.ulBeginLBA = pxMyPartition->ulStartLBA; + + /* TODO: Find some solution here to get a unique disk ID */ + ulVolumeID = ( rand() << 16 ) | rand(); /*_RB_ rand() has proven problematic in some environments. */ + + /* Sectors within partition which can not be used */ + ulNonDataSectors = ulFATReservedSectors + iFAT16RootSectors; + + /* A fs dependent constant: */ + if( ucFATType == FF_T_FAT32 ) + { + /* In FAT32, 4 bytes are needed to store the address (LBA) of a cluster. + Each FAT sector of 512 bytes can contain 512 / 4 = 128 entries. */ + ulClustersPerFATSector = 128u; + } + else + { + /* In FAT16, 2 bytes are needed to store the address (LBA) of a cluster. + Each FAT sector of 512 bytes can contain 512 / 2 = 256 entries. */ + ulClustersPerFATSector = 256u; + } + + FF_PRINTF( "FF_Format: Secs %lu Rsvd %lu Hidden %lu Root %lu Data %lu\n", + ulSectorCount, ulFATReservedSectors, ulHiddenSectors, iFAT16RootSectors, ulSectorCount - ulNonDataSectors ); + + /* Either search from small to large or v.v. */ + if( xSmallClusters != 0 ) + { + /* The caller prefers to have small clusters. + Less waste but it can be slower. */ + ulSectorsPerCluster = 1u; + } + else + { + if( ucFATType == FF_T_FAT32 ) + { + ulSectorsPerCluster = 64u; + } + else + { + ulSectorsPerCluster = 32u; + } + } + + for( ;; ) + { + int32_t groupSize; + /* Usable sectors */ + ulUsableDataSectors = ulSectorCount - ulNonDataSectors; + /* Each group consists of 'xFATCount' sectors + 'ulClustersPerFATSector' clusters */ + groupSize = xFATCount + ulClustersPerFATSector * ulSectorsPerCluster; + /* This amount of groups will fit: */ + ulSectorsPerFAT = ( ulUsableDataSectors + groupSize - ulSectorsPerCluster - xFATCount ) / groupSize; + + ulUsableDataClusters = ulMin32( + ( uint32_t ) ( ulUsableDataSectors - xFATCount * ulSectorsPerFAT ) / ulSectorsPerCluster, + ( uint32_t ) ( ulClustersPerFATSector * ulSectorsPerFAT ) ); + ulUsableDataSectors = ulUsableDataClusters * ulSectorsPerCluster; + + if( ( ucFATType == FF_T_FAT16 ) && ( ulUsableDataClusters >= MIN_CLUSTERS_FAT16 ) && ( ulUsableDataClusters < 65536 ) ) + { + break; + } + + if( ( ucFATType == FF_T_FAT32 ) && ( ulUsableDataClusters >= 65536 ) && ( ulUsableDataClusters < 0x0FFFFFEF ) ) + { + break; + } + + /* Was this the last test? */ + if( ( ( xSmallClusters != pdFALSE ) && ( ulSectorsPerCluster == 32 ) ) || + ( ( xSmallClusters == pdFALSE ) && ( ulSectorsPerCluster == 1) ) ) + { + FF_PRINTF( "FF_Format: Can not make a FAT%d (tried %d) with %lu sectors\n", + ucFATType == FF_T_FAT32 ? 32 : 16, xPreferFAT16 ? 16 : 32, ulSectorCount ); + return FF_ERR_IOMAN_BAD_MEMSIZE | FF_MODULE_FORMAT; + } + /* No it wasn't, try next clustersize */ + if( xSmallClusters != pdFALSE ) + { + ulSectorsPerCluster <<= 1; + } + else + { + ulSectorsPerCluster >>= 1; + } + } + + if( ( ucFATType == FF_T_FAT32 ) && ( ulSectorCount >= 0x100000UL ) ) /* Larger than 0.5 GB */ + { + uint32_t ulRemaining; + /* + * Putting the FAT-table into the second 4MB erase block gives + * a higher performance and a longer life-time. + * See e.g. here: + * http://3gfp.com/wp/2014/07/formatting-sd-cards-for-speed-and-lifetime/ + */ + ulFATReservedSectors = 8192 - ulHiddenSectors; + ulNonDataSectors = ulFATReservedSectors + iFAT16RootSectors; + + ulRemaining = (ulNonDataSectors + 2 * ulSectorsPerFAT) % 128; + if( ulRemaining != 0 ) + { + /* In order to get ClusterBeginLBA well aligned (on a 128 sector boundary) */ + ulFATReservedSectors += ( 128 - ulRemaining ); + ulNonDataSectors = ulFATReservedSectors + iFAT16RootSectors; + } + ulUsableDataSectors = ulSectorCount - ulNonDataSectors - 2 * ulSectorsPerFAT; + ulUsableDataClusters = ulUsableDataSectors / ulSectorsPerCluster; + } + ulClusterBeginLBA = ulHiddenSectors + ulFATReservedSectors + 2 * ulSectorsPerFAT; + + pucSectorBuffer = ( uint8_t * ) ffconfigMALLOC( 512 ); + if( pucSectorBuffer == NULL ) + { + return FF_ERR_NOT_ENOUGH_MEMORY | FF_MODULE_FORMAT; + } + +/* ======================================================================================= */ + + memset( pucSectorBuffer, '\0', 512 ); + + memcpy( pucSectorBuffer + OFS_BPB_jmpBoot_24, "\xEB\x00\x90" "FreeRTOS", 11 ); /* Includes OFS_BPB_OEMName_64 */ + + FF_putShort( pucSectorBuffer, OFS_BPB_BytsPerSec_16, 512 ); /* 0x00B / Only 512, 1024, 2048 or 4096 */ + FF_putShort( pucSectorBuffer, OFS_BPB_ResvdSecCnt_16, ( uint32_t ) ulFATReservedSectors ); /* 0x00E / 1 (FAT12/16) or 32 (FAT32) */ + + FF_putChar( pucSectorBuffer, OFS_BPB_NumFATs_8, 2); /* 0x010 / 2 recommended */ + FF_putShort( pucSectorBuffer, OFS_BPB_RootEntCnt_16, ( uint32_t ) ( iFAT16RootSectors * 512 ) / 32 ); /* 0x011 / 512 (FAT12/16) or 0 (FAT32) */ + + /* For FAT12 and FAT16 volumes, this field contains the count of 32- */ + /* byte directory entries in the root directory */ + + FF_putChar( pucSectorBuffer, OFS_BPB_Media_8, 0xF8 ); /* 0x015 / 0xF0 (rem media) also in FAT[0] low byte */ + + FF_putShort( pucSectorBuffer, OFS_BPB_SecPerTrk_16, 0x3F ); /* 0x18 n.a. CF has no tracks */ + FF_putShort( pucSectorBuffer, OFS_BPB_NumHeads_16, 255 ); /* 0x01A / n.a. 1 ? */ + FF_putLong (pucSectorBuffer, OFS_BPB_HiddSec_32, ( uint32_t ) ulHiddenSectors ); /* 0x01C / n.a. 0 for nonparitioned volume */ + { + int32_t fatBeginLBA; + int32_t dirBegin; + + FF_putChar( pucSectorBuffer, OFS_BPB_SecPerClus_8, ( uint32_t ) ulSectorsPerCluster ); /* 0x00D / Only 1, 2, 4, 8, 16, 32, 64, 128 */ + FF_PRINTF("FF_Format: SecCluster %lu DatSec %lu DataClus %lu ulClusterBeginLBA %lu\n", + ulSectorsPerCluster, ulUsableDataSectors, ulUsableDataClusters, ulClusterBeginLBA ); + + /* This field is the new 32-bit total count of sectors on the volume. */ + /* This count includes the count of all sectors in all four regions of the volume */ + FF_putShort( pucSectorBuffer, OFS_BPB_TotSec16_16, 0 ); /* 0x013 / xxx (FAT12/16) or 0 (FAT32) */ + + FF_putLong (pucSectorBuffer, OFS_BPB_TotSec32_32, ulSectorCount ); /* 0x020 / >= 0x10000 */ + + if( ucFATType == FF_T_FAT32 ) + { + FF_putLong( pucSectorBuffer, OFS_BPB_32_FATSz32_32, ulSectorsPerFAT ); /* 0x24 / Only when BPB_FATSz16 = 0 */ + FF_putShort( pucSectorBuffer, OFS_BPB_32_ExtFlags_16, 0 ); /* 0x28 / FAT32 only */ + FF_putShort( pucSectorBuffer, OFS_BPB_32_FSVer_16, 0 ); /* 0x2A / 0:0 */ + FF_putLong( pucSectorBuffer, OFS_BPB_32_RootClus_32, ( uint32_t ) iFAT32RootClusters ); /* 0x2C / Normally 2 */ + FF_putShort( pucSectorBuffer, OFS_BPB_32_FSInfo_16, ulFSInfo ); /* 0x30 / Normally 1 */ + FF_putShort( pucSectorBuffer, OFS_BPB_32_BkBootSec_16, ulBackupBootSector ); /* 0x32 / Normally 6 */ + FF_putChar( pucSectorBuffer, OFS_BPB_32_DrvNum_8, 0 ); /* 0x40 / n.a. */ + FF_putChar( pucSectorBuffer, OFS_BPB_32_BootSig_8, 0x29 ); /* 0x42 / n.a. */ + FF_putLong( pucSectorBuffer, OFS_BPB_32_VolID_32, ( uint32_t ) ulVolumeID ); /* 0x43 / "unique" number */ + memcpy( pucSectorBuffer + OFS_BPB_32_VolLab_88, "MY NAME ", 11 ); /* 0x47 / "NO NAME " */ + memcpy( pucSectorBuffer + OFS_BPB_32_FilSysType_64, "FAT32 ", 8 ); /* 0x52 / "FAT12 " */ + } + else + { + FF_putChar( pucSectorBuffer, OFS_BPB_16_DrvNum_8, 0u ); /* 0x024 / n.a. */ + FF_putChar( pucSectorBuffer, OFS_BPB_16_Reserved1_8, 0 ); /* 0x025 / n.a. */ + FF_putChar( pucSectorBuffer, OFS_BPB_16_BootSig_8, 0x29 ); /* 0x026 / n.a. */ + FF_putLong (pucSectorBuffer, OFS_BPB_16_BS_VolID_32, ( uint32_t ) ulVolumeID ); /* 0x027 / "unique" number */ + + FF_putShort( pucSectorBuffer, OFS_BPB_FATSz16_16, ulSectorsPerFAT ); /* 0x16 */ + + memcpy( pucSectorBuffer + OFS_BPB_16_BS_VolLab_88, "MY NAME ", 11 ); /* 0x02B / "NO NAME " */ + memcpy( pucSectorBuffer + OFS_BPB_16_FilSysType_64, "FAT16 ", 8 ); /* 0x036 / "FAT12 " */ + } + + pucSectorBuffer[510] = 0x55; + pucSectorBuffer[511] = 0xAA; + + FF_BlockWrite( pxIOManager, ulHiddenSectors, 1, pucSectorBuffer, 0u ); + if (ucFATType == FF_T_FAT32) + { + FF_BlockWrite( pxIOManager, ulHiddenSectors + ulBackupBootSector, 1, pucSectorBuffer, pdFALSE ); + } + + if( ucFATType == FF_T_FAT32 ) + { + memset( pucSectorBuffer, '\0', 512 ); + + FF_putLong( pucSectorBuffer, OFS_FSI_32_LeadSig, 0x41615252 ); /* to validate that this is in fact an FSInfo sector. */ + /* OFS_FSI_32_Reserved1 0x004 / 480 times 0 */ + FF_putLong( pucSectorBuffer, OFS_FSI_32_StrucSig, 0x61417272 ); /* Another signature that is more localized in the */ + /* sector to the location of the fields that are used. */ + FF_putLong( pucSectorBuffer, OFS_FSI_32_Free_Count, ulUsableDataClusters ); /* last known free cluster count on the volume, ~0 for unknown */ + FF_putLong( pucSectorBuffer, OFS_FSI_32_Nxt_Free, 2 ); /* cluster number at which the driver should start looking for free clusters */ + /* OFS_FSI_32_Reserved2 0x1F0 / zero's */ + FF_putLong( pucSectorBuffer, OFS_FSI_32_TrailSig, 0xAA550000 ); /* Will correct for endianness */ + + FF_BlockWrite( pxIOManager, ulHiddenSectors + ulFSInfo, 1, pucSectorBuffer, pdFALSE ); + FF_BlockWrite( pxIOManager, ulHiddenSectors + ulFSInfo + ulBackupBootSector, 1, pucSectorBuffer, pdFALSE ); + } + + fatBeginLBA = ulHiddenSectors + ulFATReservedSectors; + memset( pucSectorBuffer, '\0', 512 ); + switch( ucFATType ) + { + case FF_T_FAT16: + FF_putShort( pucSectorBuffer, 0, 0xFFF8 ); /* First FAT entry. */ + FF_putShort( pucSectorBuffer, 2, 0xFFFF ); /* RESERVED alloc. */ + break; + case FF_T_FAT32: + FF_putLong( pucSectorBuffer, 0, 0x0FFFFFF8 ); /* FAT32 FAT sig. */ + FF_putLong( pucSectorBuffer, 4, 0xFFFFFFFF ); /* RESERVED alloc. */ + FF_putLong( pucSectorBuffer, 8, 0x0FFFFFFF ); /* Root dir allocation. */ + break; + default: + break; + } + + FF_BlockWrite( pxIOManager, ( uint32_t ) fatBeginLBA, 1, pucSectorBuffer, pdFALSE ); + FF_BlockWrite( pxIOManager, ( uint32_t ) fatBeginLBA + ulSectorsPerFAT, 1, pucSectorBuffer, pdFALSE ); + + FF_PRINTF( "FF_Format: Clearing entire FAT (2 x %lu sectors):\n", ulSectorsPerFAT ); + { + int32_t addr; + + memset( pucSectorBuffer, '\0', 512 ); + for( addr = fatBeginLBA+1; + addr < ( fatBeginLBA + ( int32_t ) ulSectorsPerFAT ); + addr++ ) + { + FF_BlockWrite( pxIOManager, ( uint32_t ) addr, 1, pucSectorBuffer, pdFALSE ); + FF_BlockWrite( pxIOManager, ( uint32_t ) addr + ulSectorsPerFAT, 1, pucSectorBuffer, pdFALSE ); + } + } + FF_PRINTF( "FF_Format: Clearing done\n" ); + dirBegin = fatBeginLBA + ( 2 * ulSectorsPerFAT ); +#if( ffconfigTIME_SUPPORT != 0 ) + { + FF_SystemTime_t str_t; + int16_t myShort; + + FF_GetSystemTime( &str_t ); + + myShort = ( ( str_t.Hour << 11 ) & 0xF800 ) | + ( ( str_t.Minute << 5 ) & 0x07E0 ) | + ( ( str_t.Second / 2 ) & 0x001F ); + FF_putShort( pucSectorBuffer, 22, ( uint32_t ) myShort ); + + myShort = ( ( ( str_t.Year- 1980 ) << 9 ) & 0xFE00 ) | + ( ( str_t.Month << 5 ) & 0x01E0 ) | + ( str_t.Day & 0x001F ); + FF_putShort( pucSectorBuffer, 24, ( uint32_t ) myShort); + } +#endif /* ffconfigTIME_SUPPORT */ + + memcpy (pucSectorBuffer, "MY_DISK ", 11); + pucSectorBuffer[11] = FF_FAT_ATTR_VOLID; + + { + int32_t lAddress; + int32_t lLastAddress; + + if( iFAT16RootSectors != 0 ) + { + lLastAddress = dirBegin + iFAT16RootSectors; + } + else + { + lLastAddress = dirBegin + ulSectorsPerCluster; + } + + FF_PRINTF("FF_Format: Clearing root directory at %08lX: %lu sectors\n", dirBegin, lLastAddress - dirBegin ); + for( lAddress = dirBegin; lAddress < lLastAddress; lAddress++ ) + { + FF_BlockWrite( pxIOManager, ( uint32_t ) lAddress, 1, pucSectorBuffer, 0u ); + if( lAddress == dirBegin ) + { + memset( pucSectorBuffer, '\0', 512 ); + } + } + } + } + + ffconfigFREE( pucSectorBuffer ); + + return FF_ERR_NONE; +} + +FF_Error_t FF_Partition( FF_Disk_t *pxDisk, FF_PartitionParameters_t *pParams ) +{ + const uint32_t ulInterSpace = pParams->ulInterSpace ? pParams->ulInterSpace : 2048; /* Hidden space between 2 extended partitions */ + BaseType_t xPartitionNumber; + FF_Part_t pxPartitions[ ffconfigMAX_PARTITIONS ]; + uint32_t ulPartitionOffset; /* Pointer within partition table */ + FF_Buffer_t *pxSectorBuffer; + uint8_t *pucBuffer; + uint32_t ulSummedSizes = 0; /* Summed sizes as a percentage or as number of sectors. */ + BaseType_t xPartitionCount = 0; + BaseType_t xNeedExtended; + uint32_t ulReservedSpace; + uint32_t ulAvailable; + FF_IOManager_t *pxIOManager = pxDisk->pxIOManager; + + + /* Clear caching without flushing first. */ + FF_IOMAN_InitBufferDescriptors( pxIOManager ); + + /* Avoid sanity checks by FF_BlockRead/Write. */ + pxIOManager->xPartition.ulTotalSectors = 0; + + /* Get the sum of sizes and number of actual partitions. */ + for( xPartitionNumber = 0; xPartitionNumber < ffconfigMAX_PARTITIONS; xPartitionNumber++ ) + { + if( pParams->xSizes[ xPartitionNumber ] > 0 ) + { + xPartitionCount++; + ulSummedSizes += pParams->xSizes[ xPartitionNumber ]; + } + } + + if( xPartitionCount == 0 ) + { + xPartitionCount = 1; + if( pParams->eSizeType == eSizeIsSectors) + { + pParams->xSizes[ 0 ] = pParams->ulSectorCount; + } + else + { + pParams->xSizes[ 0 ] = 100; + } + + ulSummedSizes = pParams->xSizes[ 0 ]; + } + + /* Correct PrimaryCount if necessary. */ + if( pParams->xPrimaryCount > ( ( xPartitionCount > 4 ) ? 3 : xPartitionCount ) ) + { + pParams->xPrimaryCount = ( xPartitionCount > 4 ) ? 3 : xPartitionCount; + } + + /* Now see if extended is necessary. */ + xNeedExtended = ( xPartitionCount > pParams->xPrimaryCount ); + + if( xNeedExtended != pdFALSE ) + { + if( pParams->ulHiddenSectors < 4096 ) + { + pParams->ulHiddenSectors = 4096; + } + + ulReservedSpace = ulInterSpace * ( xPartitionCount - pParams->xPrimaryCount ); + } + else + { + /* There must be at least 1 hidden sector. */ + if( pParams->ulHiddenSectors < 1 ) + { + pParams->ulHiddenSectors = 1; + } + ulReservedSpace = 0; + } + + ulAvailable = pParams->ulSectorCount - pParams->ulHiddenSectors - ulReservedSpace; + + /* Check validity of Sizes */ + switch( pParams->eSizeType ) + { + case eSizeIsQuota: /* Assign a quotum (sum of Sizes is free, all disk space will be allocated) */ + break; + case eSizeIsPercent: /* Assign a percentage of the available space (sum of Sizes must be <= 100) */ + if( ulSummedSizes > 100 ) + { + return FF_FORMATPARTITION | FF_ERR_IOMAN_BAD_MEMSIZE; + } + ulSummedSizes = 100; + break; + case eSizeIsSectors: /* Assign fixed number of sectors (512 byte each) */ + if( ulSummedSizes > ulAvailable ) + { + return FF_FORMATPARTITION | FF_ERR_IOMAN_BAD_MEMSIZE; + } + break; + } + + { + uint32_t ulRemaining = ulAvailable; + uint32_t ulLBA = pParams->ulHiddenSectors; + + /* Divide the available sectors among the partitions: */ + memset( pxPartitions, '\0', sizeof( pxPartitions ) ); + + for( xPartitionNumber = 0; xPartitionNumber < xPartitionCount; xPartitionNumber++ ) + { + if( pParams->xSizes[ xPartitionNumber ] > 0 ) + { + uint32_t ulSize; + switch( pParams->eSizeType ) + { + case eSizeIsQuota: /* Assign a quotum (sum of Sizes is free, all disk space will be allocated) */ + case eSizeIsPercent: /* Assign a percentage of the available space (sum of Sizes must be <= 100) */ + ulSize = ( uint32_t ) ( ( ( uint64_t ) pParams->xSizes[ xPartitionNumber ] * ulAvailable) / ulSummedSizes ); + break; + case eSizeIsSectors: /* Assign fixed number of sectors (512 byte each) */ + default: /* Just for the compiler(s) */ + ulSize = pParams->xSizes[ xPartitionNumber ]; + break; + } + + if( ulSize > ulRemaining ) + { + ulSize = ulRemaining; + } + + ulRemaining -= ulSize; + pxPartitions[ xPartitionNumber ].ulSectorCount = ulSize; + pxPartitions[ xPartitionNumber ].ucActive = 0x80; + pxPartitions[ xPartitionNumber ].ulStartLBA = ulLBA; /* ulStartLBA might still change for logical partitions */ + pxPartitions[ xPartitionNumber ].ucPartitionID = 0x0B; + ulLBA += ulSize; + } + } + } + + if( xNeedExtended != pdFALSE ) + { + /* Create at least 1 extended/logical partition */ + int index; + /* Start of the big extended partition */ + unsigned extendedLBA = pParams->ulHiddenSectors; + /* Where to write the table */ + uint32_t ulLBA = 0; + /* Contents of the table */ + FF_Part_t writeParts[4]; + + for( index = -1; index < xPartitionCount; index++ ) + { + uint32_t ulNextLBA; + + memset (writeParts, '\0', sizeof( writeParts ) ); + if( index < 0 ) + { + /* we're at secor 0: */ + /* write primary partitions, if any */ + /* create big extended partition */ + uint32_t ulStartLBA = pParams->ulHiddenSectors; + for( xPartitionNumber = 0; xPartitionNumber < pParams->xPrimaryCount; xPartitionNumber++ ) + { + writeParts[ xPartitionNumber ].ulStartLBA = ulStartLBA; + writeParts[ xPartitionNumber ].ulSectorCount = pxPartitions[ xPartitionNumber ].ulSectorCount; + writeParts[ xPartitionNumber ].ucActive = 0x80; + writeParts[ xPartitionNumber ].ucPartitionID = 0x0B; + ulStartLBA += writeParts[ xPartitionNumber ].ulSectorCount; + index++; + } + extendedLBA = ulStartLBA; + writeParts[ xPartitionNumber ].ulStartLBA = ulStartLBA; + writeParts[ xPartitionNumber ].ulSectorCount = pParams->ulSectorCount - ulStartLBA; + writeParts[ xPartitionNumber ].ucActive = 0x80; + writeParts[ xPartitionNumber ].ucPartitionID = 0x05; + ulNextLBA = ulStartLBA; + } + else + { + /* Create a logical partition with "ulSectorCount" sectors: */ + writeParts[ 0 ].ulStartLBA = ulInterSpace; + writeParts[ 0 ].ulSectorCount = pxPartitions[index].ulSectorCount; + writeParts[ 0 ].ucActive = 0x80; + writeParts[ 0 ].ucPartitionID = 0x0B; + if( index < xPartitionCount - 1 ) + { + /* Next extended partition */ + writeParts[ 1 ].ulStartLBA = ulInterSpace + ulLBA - extendedLBA + writeParts[ 0 ].ulSectorCount; + writeParts[ 1 ].ulSectorCount = pxPartitions[index+1].ulSectorCount + ulInterSpace; + writeParts[ 1 ].ucActive = 0x80; + writeParts[ 1 ].ucPartitionID = 0x05; + } + ulNextLBA = writeParts[ 1 ].ulStartLBA + extendedLBA; + } + pxSectorBuffer = FF_GetBuffer(pxIOManager, ( uint32_t ) ulLBA, ( uint8_t ) FF_MODE_WRITE ); + { + if( pxSectorBuffer == NULL ) + { + return FF_ERR_DEVICE_DRIVER_FAILED; + } + } + pucBuffer = pxSectorBuffer->pucBuffer; + memset ( pucBuffer, 0, 512 ); + memcpy ( pucBuffer + OFS_BPB_jmpBoot_24, "\xEB\x00\x90" "FreeRTOS", 11 ); /* Includes OFS_BPB_OEMName_64 */ + + ulPartitionOffset = OFS_PTABLE_PART_0; + for( xPartitionNumber = 0; xPartitionNumber < ffconfigMAX_PARTITIONS; xPartitionNumber++, ulPartitionOffset += 16 ) + { + FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ACTIVE_8, writeParts[ xPartitionNumber ].ucActive ); /* 0x01BE 0x80 if active */ + FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_START_HEAD_8, 1 ); /* 0x001 / 0x01BF */ + FF_putShort(pucBuffer, ulPartitionOffset + OFS_PART_START_SEC_TRACK_16, 1 ); /* 0x002 / 0x01C0 */ + FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ID_NUMBER_8, writeParts[ xPartitionNumber ].ucPartitionID );/* 0x004 / 0x01C2 */ + FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ENDING_HEAD_8, 0xFE ); /* 0x005 / 0x01C3 */ + FF_putShort(pucBuffer, ulPartitionOffset + OFS_PART_ENDING_SEC_TRACK_16, writeParts[ xPartitionNumber ].ulSectorCount );/* 0x006 / 0x01C4 */ + FF_putLong (pucBuffer, ulPartitionOffset + OFS_PART_STARTING_LBA_32, writeParts[ xPartitionNumber ].ulStartLBA ); /* 0x008 / 0x01C6 This is important */ + FF_putLong (pucBuffer, ulPartitionOffset + OFS_PART_LENGTH_32, writeParts[ xPartitionNumber ].ulSectorCount );/* 0x00C / 0x01CA Equal to total sectors */ + } + pucBuffer[510] = 0x55; + pucBuffer[511] = 0xAA; + + FF_ReleaseBuffer(pxIOManager, pxSectorBuffer ); + FF_FlushCache( pxIOManager ); + ulLBA = ulNextLBA; + } + } + else + { + pxSectorBuffer = FF_GetBuffer( pxIOManager, 0, ( uint8_t ) FF_MODE_WRITE ); + { + if( pxSectorBuffer == NULL ) + { + return FF_ERR_DEVICE_DRIVER_FAILED; + } + } + + pucBuffer = pxSectorBuffer->pucBuffer; + memset (pucBuffer, 0, 512 ); + memcpy (pucBuffer + OFS_BPB_jmpBoot_24, "\xEB\x00\x90" "FreeRTOS", 11 ); /* Includes OFS_BPB_OEMName_64 */ + ulPartitionOffset = OFS_PTABLE_PART_0; + + for( xPartitionNumber = 0; xPartitionNumber < ffconfigMAX_PARTITIONS; xPartitionNumber++ ) + { + FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ACTIVE_8, pxPartitions[ xPartitionNumber ].ucActive ); /* 0x01BE 0x80 if active */ + FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_START_HEAD_8, 1 ); /* 0x001 / 0x01BF */ + FF_putShort( pucBuffer, ulPartitionOffset + OFS_PART_START_SEC_TRACK_16, 1 ); /* 0x002 / 0x01C0 */ + FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ID_NUMBER_8, pxPartitions[ xPartitionNumber ].ucPartitionID ); /* 0x004 / 0x01C2 */ + FF_putChar( pucBuffer, ulPartitionOffset + OFS_PART_ENDING_HEAD_8, 0xFE ); /* 0x005 / 0x01C3 */ + FF_putShort( pucBuffer, ulPartitionOffset + OFS_PART_ENDING_SEC_TRACK_16, pxPartitions[ xPartitionNumber ].ulSectorCount ); /* 0x006 / 0x01C4 */ + FF_putLong( pucBuffer, ulPartitionOffset + OFS_PART_STARTING_LBA_32, pxPartitions[ xPartitionNumber ].ulStartLBA ); /* 0x008 / 0x01C6 This is important */ + FF_putLong( pucBuffer, ulPartitionOffset + OFS_PART_LENGTH_32, pxPartitions[ xPartitionNumber ].ulSectorCount ); /* 0x00C / 0x01CA Equal to total sectors */ + ulPartitionOffset += 16; + } + pucBuffer[ 510 ] = 0x55; + pucBuffer[ 511 ] = 0xAA; + + FF_ReleaseBuffer( pxIOManager, pxSectorBuffer ); + FF_FlushCache( pxIOManager ); + } + + return FF_ERR_NONE; +} diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_ioman.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_ioman.c new file mode 100644 index 000000000..094bc07bf --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_ioman.c @@ -0,0 +1,1882 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_ioman.c + * @ingroup IOMAN + * + * @defgroup IOMAN I/O Manager + * @brief Handles IO buffers for FreeRTOS+FAT safely. + * + * Provides a simple static interface to the rest of FreeRTOS+FAT to manage + * buffers. It also defines the public interfaces for Creating and + * Destroying a FreeRTOS+FAT IO object. + **/ + +#include +#include + +#include "ff_headers.h" + +#define FAT16_SECTOR_COUNT_4085 4085 +#define FAT32_SECTOR_COUNT_65525 65525 /* 65536 clusters */ + +/* Some values and offsets describing the special sector FS INFO: */ +#define FS_INFO_SIGNATURE1_0x41615252 0x41615252UL +#define FS_INFO_SIGNATURE2_0x61417272 0x61417272UL +#define FS_INFO_OFFSET_SIGNATURE1_000 0 +#define FS_INFO_OFFSET_SIGNATURE2_484 484 +#define FS_INFO_OFFSET_FREE_COUNT_488 488 +#define FS_INFO_OFFSET_FREE_CLUSTER_492 492 + +/* Inspect the PBR (Partition Boot Record) to determine the type of FAT */ +static FF_Error_t prvDetermineFatType( FF_IOManager_t *pxIOManager ); + +/* Check if a given ID introduces an extended partition. */ +static BaseType_t prvIsExtendedPartition( uint8_t ucPartitionID ); + +/* Return pdTRUE if the media byte in an MBR is valid. */ +static BaseType_t prvIsValidMedia( uint8_t media ); + +/* Read the MBR to see what extended partitions have been defined. +Definitions of extended partitions may be chained. +Walk down the chain to find all extended partitions. */ +static FF_Error_t FF_ParseExtended( FF_IOManager_t *pxIOManager, uint32_t ulFirstSector, uint32_t ulFirstSize, + FF_SPartFound_t *pPartsFound ); + +static FF_Error_t FF_GetEfiPartitionEntry( FF_IOManager_t *pxIOManager, uint32_t ulPartitionNumber ); + +static BaseType_t prvHasActiveHandles( FF_IOManager_t *pxIOManager ); + + +/** + * @public + * @brief Creates an FF_IOManager_t object, to initialise FreeRTOS+FAT + * + * @param pucCacheMem Pointer to a buffer for the cache. (NULL if ok to Malloc). + * @param ulCacheSize The size of the provided buffer, or size of the cache to be created. + * (Must be at least 2 * ulSectorSize). Always a multiple of ulSectorSize. + * @param usSectorSize The block size of devices to be attached. If in doubt use 512. + * @param pError Pointer to a signed byte for error checking. Can be NULL if not required. + * To be checked when a NULL pointer is returned. + * + * @Return Returns a pointer to an FF_IOManager_t type object. NULL on xError, check the contents of + * @Return pError + **/ +FF_IOManager_t *FF_CreateIOManger( FF_CreationParameters_t *pxParameters, FF_Error_t *pError ) +{ +FF_IOManager_t *pxIOManager = NULL; +FF_Error_t xError; +uint32_t ulCacheSize = pxParameters->ulMemorySize; +uint32_t usSectorSize = pxParameters->ulSectorSize; + + /* Normally: + ulSectorSize = 512 + ulCacheSize = N x ulSectorSize. */ + if( ( ( usSectorSize % 512 ) != 0 ) || ( usSectorSize == 0 ) ) + { + /* ulSectorSize Size not a multiple of 512 or it is zero*/ + xError = FF_ERR_IOMAN_BAD_BLKSIZE | FF_CREATEIOMAN; + } + else if( ( ( ulCacheSize % ( uint32_t ) usSectorSize ) != 0 ) || ( ulCacheSize == 0 ) || + ( ulCacheSize == ( uint32_t ) usSectorSize ) ) + { + /* The size of the caching memory (ulCacheSize) must now be atleast 2 * ulSectorSize (or a deadlock will occur). */ + xError = FF_ERR_IOMAN_BAD_MEMSIZE | FF_CREATEIOMAN; + } + else + { + pxIOManager = ( FF_IOManager_t * ) ffconfigMALLOC( sizeof( FF_IOManager_t ) ); + + /* Ensure malloc() succeeded. */ + if( pxIOManager != NULL ) + { + /* Use memset() to clear every single bit. */ + memset( pxIOManager, '\0', sizeof( FF_IOManager_t ) ); + if( FF_CreateEvents( pxIOManager ) != pdFALSE ) + { + xError = FF_ERR_NONE; + } + else + { + /* xEventGroupCreate() probably failed. */ + xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; + } + } + else + { + /* ffconfigMALLOC() failed. */ + xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; + } + } + + if( FF_isERR( xError ) == pdFALSE ) + { + /* pxIOManager is created, FF_CreateEvents() succeeded. */ + if( pxParameters->pucCacheMemory != NULL ) + { + /* The caller has provided a piece of memory, use it. */ + pxIOManager->pucCacheMem = pxParameters->pucCacheMemory; + } + else + { + /* No cache buffer provided, call malloc(). */ + pxIOManager->pucCacheMem = ( uint8_t * ) ffconfigMALLOC( ulCacheSize ); + if( pxIOManager->pucCacheMem != NULL ) + { + /* Indicate that malloc() was used for pucCacheMem. */ + pxIOManager->ucFlags |= FF_IOMAN_ALLOC_BUFFERS; + } + else + { + xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; + } + } + + if( pxIOManager->pucCacheMem != NULL ) + { + memset( pxIOManager->pucCacheMem, '\0', ulCacheSize ); + } + } + + if( FF_isERR( xError ) == pdFALSE ) + { + pxIOManager->usSectorSize = usSectorSize; + pxIOManager->usCacheSize = ( uint16_t ) ( ulCacheSize / ( uint32_t ) usSectorSize ); + + /* Malloc() memory for buffer objects. FreeRTOS+FAT never refers to a + buffer directly but uses buffer objects instead. Allows for thread + safety. */ + pxIOManager->pxBuffers = ( FF_Buffer_t * ) ffconfigMALLOC( sizeof( FF_Buffer_t ) * pxIOManager->usCacheSize ); + + if( pxIOManager->pxBuffers != NULL ) + { + /* From now on a call to FF_IOMAN_InitBufferDescriptors will clear + pxBuffers. */ + pxIOManager->ucFlags |= FF_IOMAN_ALLOC_BUFDESCR; + + FF_IOMAN_InitBufferDescriptors( pxIOManager ); + + /* Finally store the semaphore for Buffer Description modifications. */ + pxIOManager->pvSemaphore = pxParameters->pvSemaphore; + + if( pxParameters->xBlockDeviceIsReentrant != pdFALSE ) + { + pxIOManager->ucFlags |= FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT; + } + + pxIOManager->xBlkDevice.fnpReadBlocks = pxParameters->fnReadBlocks; + pxIOManager->xBlkDevice.fnpWriteBlocks = pxParameters->fnWriteBlocks; + pxIOManager->xBlkDevice.pxDisk = pxParameters->pxDisk; + } + else + { + xError = FF_ERR_NOT_ENOUGH_MEMORY | FF_CREATEIOMAN; + } + } + + if( FF_isERR( xError ) ) + { + if( pxIOManager != NULL ) + { + FF_DeleteIOManager( pxIOManager ); + pxIOManager = NULL; + } + } + + if( pError != NULL ) + { + *pError = xError; + } + + return pxIOManager; +} /* FF_CreateIOManger() */ +/*-----------------------------------------------------------*/ + +/** + * @public + * @brief Destroys an FF_IOManager_t object, and frees all assigned memory. + * + * @param pxIOManager Pointer to an FF_IOManager_t object, as returned from FF_CreateIOManger. + * + * @Return FF_ERR_NONE on sucess, or a documented error code on failure. (FF_ERR_NULL_POINTER) + * + **/ +FF_Error_t FF_DeleteIOManager( FF_IOManager_t *pxIOManager ) +{ +FF_Error_t xError; + + /* Ensure no NULL pointer was provided. */ + if( pxIOManager == NULL ) + { + xError = FF_ERR_NULL_POINTER | FF_DESTROYIOMAN; + } + else + { + xError = FF_ERR_NONE; + + /* Ensure pxBuffers pointer was allocated. */ + if( ( pxIOManager->ucFlags & FF_IOMAN_ALLOC_BUFDESCR ) != 0 ) + { + ffconfigFREE( pxIOManager->pxBuffers ); + } + + /* Ensure pucCacheMem pointer was allocated. */ + if( ( pxIOManager->ucFlags & FF_IOMAN_ALLOC_BUFFERS ) != 0 ) + { + ffconfigFREE( pxIOManager->pucCacheMem ); + } + + /* Delete the event group object within the IO manager before deleting + the manager. */ + FF_DeleteEvents( pxIOManager ); + + /* Finally free the FF_IOManager_t object. */ + ffconfigFREE( pxIOManager ); + } + + return xError; +} /* FF_DeleteIOManager() */ +/*-----------------------------------------------------------*/ + +/** + * @private + * @brief Initialises Buffer Descriptions as part of the FF_IOManager_t object initialisation. + * + * @param pxIOManager IOMAN Object. + * + **/ +void FF_IOMAN_InitBufferDescriptors( FF_IOManager_t *pxIOManager ) +{ +uint8_t *pucBuffer = pxIOManager->pucCacheMem; +FF_Buffer_t *pxBuffer = pxIOManager->pxBuffers; +FF_Buffer_t *pxLastBuffer = pxBuffer + pxIOManager->usCacheSize; + + /* Clear the contents of the buffer descriptors. */ + memset( ( void * ) pxBuffer, '\0', sizeof( FF_Buffer_t ) * pxIOManager->usCacheSize ); + + while( pxBuffer < pxLastBuffer ) + { + pxBuffer->pucBuffer = pucBuffer; + pxBuffer++; + pucBuffer += pxIOManager->usSectorSize; + } +} /* FF_IOMAN_InitBufferDescriptors() */ +/*-----------------------------------------------------------*/ + +/** + * @private + * @brief Flushes all Write cache buffers with no active Handles. + * + * @param pxIOManager IOMAN Object. + * + * @Return FF_ERR_NONE on Success. + **/ +FF_Error_t FF_FlushCache( FF_IOManager_t *pxIOManager ) +{ +BaseType_t xIndex, xIndex2; +FF_Error_t xError; + + if( pxIOManager == NULL ) + { + xError = FF_ERR_NULL_POINTER | FF_FLUSHCACHE; + } + else + { + xError = FF_ERR_NONE; + + FF_PendSemaphore( pxIOManager->pvSemaphore ); + { + for( xIndex = 0; xIndex < pxIOManager->usCacheSize; xIndex++ ) + { + /* If a buffers has no users and if it has been modified... */ + if( ( pxIOManager->pxBuffers[ xIndex ].usNumHandles == 0 ) && ( pxIOManager->pxBuffers[ xIndex ].bModified == pdTRUE ) ) + { + /* The buffer may be flushed to disk. */ + FF_BlockWrite( pxIOManager, pxIOManager->pxBuffers[ xIndex ].ulSector, 1, pxIOManager->pxBuffers[ xIndex ].pucBuffer, pdTRUE ); + + /* Buffer has now been flushed, mark it as a read buffer and unmodified. */ + pxIOManager->pxBuffers[ xIndex ].ucMode = FF_MODE_READ; + pxIOManager->pxBuffers[ xIndex ].bModified = pdFALSE; + + /* Search for other buffers that used this sector, and mark them as modified + So that further requests will result in the new sector being fetched. */ + for( xIndex2 = 0; xIndex2 < pxIOManager->usCacheSize; xIndex2++ ) + { + if( ( xIndex != xIndex2 ) && + ( pxIOManager->pxBuffers[ xIndex2 ].ulSector == pxIOManager->pxBuffers[ xIndex ].ulSector ) && + ( pxIOManager->pxBuffers[ xIndex2 ].ucMode == FF_MODE_READ ) ) + { + pxIOManager->pxBuffers[ xIndex2 ].bModified = pdTRUE; + } + } + } + } + } + if( ( pxIOManager->xBlkDevice.pxDisk != NULL ) && + ( pxIOManager->xBlkDevice.pxDisk->fnFlushApplicationHook != NULL ) ) + { + /* Let the low-level driver also flush data. + See comments in ff_ioman.h. */ + pxIOManager->xBlkDevice.pxDisk->fnFlushApplicationHook( pxIOManager->xBlkDevice.pxDisk ); + } + + FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + } + + return xError; +} /* FF_FlushCache() */ +/*-----------------------------------------------------------*/ + +/* + A new version of FF_GetBuffer() with a simple mechanism for timeout +*/ +#define FF_GETBUFFER_SLEEP_TIME_MS 10 +#define FF_GETBUFFER_WAIT_TIME_MS ( 20000 / FF_GETBUFFER_SLEEP_TIME_MS ) + +FF_Buffer_t *FF_GetBuffer( FF_IOManager_t *pxIOManager, uint32_t ulSector, uint8_t ucMode ) +{ +FF_Buffer_t *pxBuffer; +/* Least Recently Used Buffer */ +FF_Buffer_t *pxRLUBuffer; +FF_Buffer_t *pxMatchingBuffer = NULL; +int32_t lRetVal; +BaseType_t xLoopCount = FF_GETBUFFER_WAIT_TIME_MS; +const FF_Buffer_t *pxLastBuffer = &( pxIOManager->pxBuffers[ pxIOManager->usCacheSize ] ); + + /* 'pxIOManager->usCacheSize' is bigger than zero and it is a multiple of ulSectorSize. */ + + while( pxMatchingBuffer == NULL ) + { + xLoopCount--; + if( xLoopCount == 0 ) + { + break; + } + + FF_PendSemaphore( pxIOManager->pvSemaphore ); + + for( pxBuffer = pxIOManager->pxBuffers; pxBuffer < pxLastBuffer; pxBuffer++ ) + { + if( ( pxBuffer->ulSector == ulSector ) && ( pxBuffer->bValid ) ) + { + pxMatchingBuffer = pxBuffer; + /* Don't look further if you found a perfect match. */ + break; + } + } + + if( pxMatchingBuffer != NULL ) + { + /* A Match was found process! */ + if( ( ucMode == FF_MODE_READ ) && ( pxMatchingBuffer->ucMode == FF_MODE_READ ) ) + { + pxMatchingBuffer->usNumHandles += 1; + pxMatchingBuffer->usPersistance += 1; + break; + } + + if( pxMatchingBuffer->usNumHandles == 0 ) + { + pxMatchingBuffer->ucMode = ( ucMode & FF_MODE_RD_WR ); + if( ( ucMode & FF_MODE_WRITE ) != 0 ) + { + /* This buffer has no attached handles. */ + pxMatchingBuffer->bModified = pdTRUE; + } + + pxMatchingBuffer->usNumHandles = 1; + pxMatchingBuffer->usPersistance += 1; + break; + } + + pxMatchingBuffer = NULL; /* Sector is already in use, keep yielding until its available! */ + } + else + { + /* There is no valid buffer now for the desired sector. + Find a free buffer and use it for that sector. */ + pxRLUBuffer = NULL; + + for( pxBuffer = pxIOManager->pxBuffers; pxBuffer < pxLastBuffer; pxBuffer++ ) + { + if( pxBuffer->usNumHandles != 0 ) + { + continue; /* Occupied */ + } + + pxBuffer->ulLRU += 1; + + if( ( pxRLUBuffer == NULL ) || + ( pxBuffer->ulLRU > pxRLUBuffer->ulLRU ) || + ( ( pxBuffer->ulLRU == pxRLUBuffer->ulLRU ) && ( pxBuffer->usPersistance > pxRLUBuffer->usPersistance ) ) ) + { + pxRLUBuffer = pxBuffer; + } + } + + /* A free buffer with the highest value of 'ulLRU' was found: */ + if( pxRLUBuffer != NULL ) + { + /* Process the suitable candidate. */ + if( pxRLUBuffer->bModified == pdTRUE ) + { + /* Along with the pdTRUE parameter to indicate semaphore has been claimed already. */ + lRetVal = FF_BlockWrite( pxIOManager, pxRLUBuffer->ulSector, 1, pxRLUBuffer->pucBuffer, pdTRUE ); + if( lRetVal < 0 ) + { + /* NULL will be returned because 'pxMatchingBuffer' is still NULL. */ + break; + } + } + + if( ucMode == FF_MODE_WR_ONLY ) + { + memset( pxRLUBuffer->pucBuffer, '\0', pxIOManager->usSectorSize ); + } + else + { + lRetVal = FF_BlockRead( pxIOManager, ulSector, 1, pxRLUBuffer->pucBuffer, pdTRUE ); + if( lRetVal < 0 ) + { + /* 'pxMatchingBuffer' is NULL. */ + break; + } + } + + pxRLUBuffer->ucMode = ( ucMode & FF_MODE_RD_WR ); + pxRLUBuffer->usPersistance = 1; + pxRLUBuffer->ulLRU = 0; + pxRLUBuffer->usNumHandles = 1; + pxRLUBuffer->ulSector = ulSector; + + pxRLUBuffer->bModified = ( ucMode & FF_MODE_WRITE ) != 0; + + pxRLUBuffer->bValid = pdTRUE; + pxMatchingBuffer = pxRLUBuffer; + break; + } /* if( pxRLUBuffer != NULL ) */ + } /* else ( pxMatchingBuffer == NULL ) */ + + FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + + /* Better to go asleep to give low-priority task a chance to release buffer(s). */ + FF_BufferWait( pxIOManager, FF_GETBUFFER_SLEEP_TIME_MS ); + } /* while( pxMatchingBuffer == NULL ) */ + + if( xLoopCount > 0 ) + { + /* If xLoopCount is 0 here, the semaphore was not taken. */ + FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + } + if( pxMatchingBuffer == NULL ) + { + FF_PRINTF( "FF_GetBuffer[0x%X]: failed mode 0x%X\n", ( unsigned )ulSector, ( unsigned )ucMode ); + } + return pxMatchingBuffer; /* Return the Matched Buffer! */ +} /* FF_GetBuffer() */ +/*-----------------------------------------------------------*/ + +/** + * @private + * @brief Releases a buffer resource. + * + * @param pxIOManager Pointer to an FF_IOManager_t object. + * @param pxBuffer Pointer to an FF_Buffer_t object. + * + **/ +FF_Error_t FF_ReleaseBuffer( FF_IOManager_t *pxIOManager, FF_Buffer_t *pxBuffer ) +{ + FF_Error_t xError = FF_ERR_NONE; + + /* Protect description changes with a semaphore. */ + FF_PendSemaphore( pxIOManager->pvSemaphore ); + { +#if( ffconfigCACHE_WRITE_THROUGH != 0 ) + if( pxBuffer->bModified == pdTRUE ) + { + xError = FF_BlockWrite( pxIOManager, pxBuffer->ulSector, 1, pxBuffer->pucBuffer, pdTRUE ); + if( FF_isERR( xError ) == pdFALSE ) + { + /* Ensure if an error occurs its still possible to write the block again. */ + pxBuffer->bModified = pdFALSE; + } + } +#endif + configASSERT( pxBuffer->usNumHandles != 0 ); + + if( pxBuffer->usNumHandles != 0 ) + { + pxBuffer->usNumHandles--; + } + else + { + /*printf ("FF_ReleaseBuffer: buffer not claimed\n"); */ + } + } + + FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + + /* Notify tasks which may be waiting in FF_GetBuffer() */ + FF_BufferProceed( pxIOManager ); + + return xError; +} /* FF_ReleaseBuffer() */ +/*-----------------------------------------------------------*/ + +/* New Interface for FreeRTOS+FAT to read blocks. */ +int32_t FF_BlockRead( FF_IOManager_t *pxIOManager, uint32_t ulSectorLBA, uint32_t ulNumSectors, void *pxBuffer, + BaseType_t xSemLocked ) +{ +int32_t slRetVal = 0; + + if( pxIOManager->xPartition.ulTotalSectors != 0ul ) + { + /* At some point while formatting a partition, ulTotalSectors might be unknown. + In that case this test will be skipped. */ + if( ( ulSectorLBA + ulNumSectors ) > ( pxIOManager->xPartition.ulTotalSectors + pxIOManager->xPartition.ulBeginLBA ) ) + { + slRetVal = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_BLOCKREAD; + } + } + + if( ( slRetVal == 0ul ) && ( pxIOManager->xBlkDevice.fnpReadBlocks != NULL ) ) + { + do + { + /* Make sure we don't execute a NULL. */ + if( ( xSemLocked == pdFALSE ) && + ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) ) + { + FF_PendSemaphore( pxIOManager->pvSemaphore ); + } + + slRetVal = pxIOManager->xBlkDevice.fnpReadBlocks( pxBuffer, ulSectorLBA, ulNumSectors, pxIOManager->xBlkDevice.pxDisk ); + + if( ( xSemLocked == pdFALSE ) && + ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) ) + { + FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + } + + if( FF_GETERROR( slRetVal ) != FF_ERR_DRIVER_BUSY ) + { + break; + } + + FF_Sleep( ffconfigDRIVER_BUSY_SLEEP_MS ); + } while( pdTRUE ); + } + + return slRetVal; +} /* FF_BlockRead() */ +/*-----------------------------------------------------------*/ + +int32_t FF_BlockWrite( FF_IOManager_t *pxIOManager, uint32_t ulSectorLBA, uint32_t ulNumSectors, void *pxBuffer, + BaseType_t xSemLocked ) +{ +int32_t slRetVal = 0; + + if( pxIOManager->xPartition.ulTotalSectors != 0 ) + { + /* At some point while formatting a partition, ulTotalSectors might be unknown. + In that case this test will be skipped. */ + if( ( ulSectorLBA + ulNumSectors ) > ( pxIOManager->xPartition.ulTotalSectors + pxIOManager->xPartition.ulBeginLBA ) ) + { + slRetVal = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_BLOCKWRITE; + } + } + + if( ( slRetVal == 0ul ) && ( pxIOManager->xBlkDevice.fnpWriteBlocks != NULL ) ) + { + do + { /* Make sure we don't execute a NULL. */ + + if( ( xSemLocked == pdFALSE ) && + ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) ) + { + FF_PendSemaphore( pxIOManager->pvSemaphore ); + } + + slRetVal = pxIOManager->xBlkDevice.fnpWriteBlocks( pxBuffer, ulSectorLBA, ulNumSectors, pxIOManager->xBlkDevice.pxDisk ); + + if( ( xSemLocked == pdFALSE ) && + ( ( pxIOManager->ucFlags & FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT ) == pdFALSE ) ) + { + FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + } + + if( FF_GETERROR( slRetVal ) != FF_ERR_DRIVER_BUSY ) + { + break; + } + + FF_Sleep( ffconfigDRIVER_BUSY_SLEEP_MS ); + } while( pdTRUE ); + } + + return slRetVal; +} /* FF_BlockWrite() */ +/*-----------------------------------------------------------*/ + +/* + * This global variable is a kind of expert option: + * It may be set to one of these values: FF_T_FAT[12,16,32] + * just to force the driver to assume a certain FAT type. + */ +uint8_t ucAssumeFATType; + +/* The history of FAT types: + * The Microsoft documents says that the actual type: FAT-12, FAT-16 and FAT-32 + * of a partition can be found by looking at the total number of data clusters: + * + * if( clusters < 4085 ) + * Assume FAT-12 + * else if( clusters < 65525 ) + * Assume FAT-16 + * else + * Assume FAT-32 + * + * In practice however, this does not always seem to be a correct assumption. + * + * The first 12 or 16 bits in the FAT table may also help to determine the + * correct FAT-type: + * + * FAT-12: ( firstWord & 0x3FF ) == 0x3F8 ) + * FAT-16: ( firstWord == 0xFFF8 ) + */ + +static FF_Error_t prvDetermineFatType( FF_IOManager_t *pxIOManager ) +{ +FF_Partition_t *pxPartition; +FF_Buffer_t *pxBuffer; +uint32_t ulFirstWord = 0ul; +FF_Error_t xError = FF_ERR_NONE; + + pxPartition = &( pxIOManager->xPartition ); + if( ucAssumeFATType != 0 ) + { + switch( ucAssumeFATType ) + { + case FF_T_FAT12: + case FF_T_FAT16: + case FF_T_FAT32: + pxPartition->ucType = ucAssumeFATType; + break; + default: + /* An invalid value will be ignored, and the FAT type is determined dynamically. */ + ucAssumeFATType = 0; + break; + } + xError = FF_ERR_NONE; + } + + /* Test again, the value may have become zero now: */ + if( ucAssumeFATType == 0 ) + { + pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA, FF_MODE_READ ); + if( pxBuffer == NULL ) + { + xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_DETERMINEFATTYPE; + } + else + { + ulFirstWord = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, 0x0000 ); + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + } + } + + if( ( ucAssumeFATType == 0 ) && ( FF_isERR( xError ) == pdFALSE ) ) + { + #if( ffconfigFAT12_SUPPORT != 0 ) + if( pxPartition->ulNumClusters < FAT16_SECTOR_COUNT_4085 ) + { + /* FAT12 */ + pxPartition->ucType = FF_T_FAT12; + #if( ffconfigFAT_CHECK != 0 ) + if( ( ulFirstWord & 0x3FF ) != 0x3F8 ) + { + xError = FF_ERR_IOMAN_NOT_FAT_FORMATTED | FF_DETERMINEFATTYPE; + } + else + #endif /* ffconfigFAT_CHECK */ + { + xError = FF_ERR_NONE; + } + } + else + #endif /* ffconfigFAT12_SUPPORT */ + + if( pxPartition->ulNumClusters < FAT32_SECTOR_COUNT_65525 ) + { + /* FAT 16 */ + pxPartition->ucType = FF_T_FAT16; + #if( ffconfigFAT_CHECK != 0 ) + { + if( ulFirstWord == 0xFFF8 ) + { + xError = FF_ERR_NONE; + } + else { + if( ( ulFirstWord & 0x3FF ) != 0x3F8 ) + { + FF_PRINTF( "Part at %lu is probably a FAT12\n", pxIOManager->xPartition.ulFATBeginLBA ); + } + else + { + FF_PRINTF( "Partition at %lu has strange FAT data %08lX\n", + pxIOManager->xPartition.ulFATBeginLBA, ulFirstWord ); + } + xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_DETERMINEFATTYPE; + } + } + #endif /* ffconfigFAT_CHECK */ + } + else + { + /* FAT 32! */ + pxPartition->ucType = FF_T_FAT32; + #if( ffconfigFAT_CHECK != 0 ) + if( ( ( ulFirstWord & 0x0FFFFFF8 ) != 0x0FFFFFF8 ) && + ( ( ulFirstWord & 0x0FFFFFF8 ) != 0x0FFFFFF0 ) ) + { + /* _HT_ + I had an SD-card which worked well in Linux/W32 + but FreeRTOS+FAT returned me this error + So for me I left out this check (just issue a warning for now) + */ + FF_PRINTF( "prvDetermineFatType: firstWord %08lX\n", ulFirstWord ); + xError = FF_ERR_NONE; /* FF_ERR_IOMAN_NOT_FAT_FORMATTED; */ + } + + #endif /* ffconfigFAT_CHECK */ + xError = FF_ERR_NONE; + } + } + + return xError; +} /* prvDetermineFatType() */ +/*-----------------------------------------------------------*/ + +/* Check if ucPartitionID introduces an extended partition. */ +static BaseType_t prvIsExtendedPartition( uint8_t ucPartitionID ) +{ +BaseType_t xResult; + + if( ( ucPartitionID == FF_DOS_EXT_PART ) || + ( ucPartitionID == FF_WIN98_EXT_PART ) || + ( ucPartitionID == FF_LINUX_EXT_PART ) ) + { + xResult = pdTRUE; + } + else + { + xResult = pdFALSE; + } + + return xResult; +} /* prvIsExtendedPartition() */ +/*-----------------------------------------------------------*/ + +/* Check if the media byte in an MBR is valid */ +static BaseType_t prvIsValidMedia( uint8_t media ) +{ +BaseType_t xResult; + /* + * 0xF8 is the standard value for “fixed” (non-removable) media. For + * removable media, 0xF0 is frequently used. The legal values for this + * field are 0xF0, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, and + * 0xFF. The only other important point is that whatever value is put + * in here must also be put in the low byte of the FAT[0] entry. This + * dates back to the old MS-DOS 1.x media determination noted + * earlier and is no longer usually used for anything. + */ + if( ( 0xf8 <= media ) || ( media == 0xf0 ) ) + { + xResult = pdTRUE; + } + else + { + xResult = pdFALSE; + } + + return xResult; +} /* prvIsValidMedia() */ +/*-----------------------------------------------------------*/ + +void FF_ReadParts( uint8_t *pucBuffer, FF_Part_t *pxParts ) +{ +BaseType_t xPartNr; +UBaseType_t uxOffset = FF_FAT_PTBL; + + /* pxParts is expected to be declared as an array of 4 elements: + FF_Part_t pxParts[4]; + FF_ReadParts( pxBuffer->pucBuffer, pxParts ); + */ + for( xPartNr = 0; xPartNr < 4; xPartNr++, uxOffset += 16, pxParts++ ) + { + pxParts->ucActive = FF_getChar( pucBuffer, uxOffset + FF_FAT_PTBL_ACTIVE ); + pxParts->ucPartitionID = FF_getChar( pucBuffer, uxOffset + FF_FAT_PTBL_ID ); + pxParts->ulSectorCount = FF_getLong( pucBuffer, uxOffset + FF_FAT_PTBL_SECT_COUNT ); + pxParts->ulStartLBA = FF_getLong( pucBuffer, uxOffset + FF_FAT_PTBL_LBA ); + } +} +/*-----------------------------------------------------------*/ + +/* This function will traverse through a chain of extended partitions. */ + +/* It is protected against rubbish data by a counter. */ +static FF_Error_t FF_ParseExtended( FF_IOManager_t *pxIOManager, uint32_t ulFirstSector, uint32_t ulFirstSize, + FF_SPartFound_t *pPartsFound ) +{ +uint32_t ulThisSector, ulThisSize; +uint32_t ulSectorSize = pxIOManager->usSectorSize / 512; +uint32_t prevTotalSectors = pxIOManager->xPartition.ulTotalSectors; +FF_Buffer_t *pxBuffer = NULL; +BaseType_t xTryCount = 100; +BaseType_t xPartNr; +BaseType_t xExtendedPartNr; +FF_Error_t xError = FF_ERR_NONE; +FF_Part_t pxPartitions[ 4 ]; + + ulThisSector = ulFirstSector; + ulThisSize = ulFirstSize; + + /* Disable sector checking in FF_BlockRead, because the + exact disk (partition) parameters are not yet known. + Let user driver return an error is appropriate. */ + pxIOManager->xPartition.ulTotalSectors = 0; + + while( xTryCount-- ) + { + if( ( pxBuffer == NULL ) || ( pxBuffer->ulSector != ulThisSector ) ) + { + /* Moving to a different sector. Release the + previous one and allocate a new buffer. */ + if( pxBuffer != NULL ) + { + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + pxBuffer = NULL; + if( FF_isERR( xError ) ) + { + break; + } + } + FF_PRINTF( "FF_ParseExtended: Read sector %u\n", ( unsigned) ulThisSector ); + pxBuffer = FF_GetBuffer( pxIOManager, ulThisSector, FF_MODE_READ ); + if( pxBuffer == NULL ) + { + xError = FF_PARSEEXTENDED | FF_ERR_DEVICE_DRIVER_FAILED; /* | FUNCTION...; */ + break; + } + } + + { + uint8_t a = FF_getChar( pxBuffer->pucBuffer, FF_FAT_MBR_SIGNATURE + 0 ); + uint8_t b = FF_getChar( pxBuffer->pucBuffer, FF_FAT_MBR_SIGNATURE + 1 ); + + if( ( a != 0x55 ) || ( b != 0xAA ) ) + { + FF_PRINTF( "FF_ParseExtended: No signature %02X,%02X\n", a, b ); + break; + } + } + + /* Check for data partition(s), + and remember if there is an extended partition */ + + FF_ReadParts( pxBuffer->pucBuffer, pxPartitions ); + + /* Assume there is no next ext partition. */ + xExtendedPartNr = -1; + + for( xPartNr = 0; xPartNr < 4; xPartNr++ ) + { + uint32_t ulOffset, ulSize, ulNext; + if( pxPartitions[ xPartNr ].ulSectorCount == 0 ) + { + /* Partition is empty */ + continue; + } + + if( prvIsExtendedPartition( pxPartitions[ xPartNr ].ucPartitionID ) ) + { + if( xExtendedPartNr < 0 ) + { + xExtendedPartNr = xPartNr; + } + + continue; /* We'll examine this ext partition later */ + } + + /* Some sanity checks */ + ulOffset = pxPartitions[ xPartNr ].ulStartLBA * ulSectorSize; + ulSize = pxPartitions[ xPartNr ].ulSectorCount * ulSectorSize; + ulNext = ulThisSector + ulOffset; + if( + /* Is it oversized? */ + ( ulOffset + ulSize > ulThisSize ) || + /* or going backward? */ + ( ulNext < ulFirstSector ) || + /* Or outsize the logical partition? */ + ( ulNext > ulFirstSector + ulFirstSize ) + ) + { + FF_PRINTF( "Part %d looks insane: ulThisSector %u ulOffset %u ulNext %u\n", + ( int ) xPartNr, ( unsigned )ulThisSector, ( unsigned )ulOffset, ( unsigned )ulNext ); + continue; + } + + { + /* Store this partition for the caller */ + FF_Part_t *p = &pPartsFound->pxPartitions[ pPartsFound->iCount++ ]; + + /* Copy the whole structure */ + memcpy( p, pxPartitions + xPartNr, sizeof( *p ) ); + + /* and make LBA absolute to sector-0. */ + p->ulStartLBA += ulThisSector; + p->bIsExtended = pdTRUE; + } + + if( pPartsFound->iCount >= ffconfigMAX_PARTITIONS ) + { + break; + } + + xTryCount = 100; + } /* for( xPartNr = 0; xPartNr < 4; xPartNr++ ) */ + + if( xExtendedPartNr < 0 ) + { + FF_PRINTF( "No more extended partitions\n" ); + break; /* nothing left to do */ + } + + /* Examine the ulNext extended partition */ + ulThisSector = ulFirstSector + pxPartitions[ xExtendedPartNr ].ulStartLBA * ulSectorSize; + ulThisSize = pxPartitions[ xExtendedPartNr ].ulSectorCount * ulSectorSize; + } + + if( pxBuffer != NULL ) + { + FF_Error_t xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + + pxIOManager->xPartition.ulTotalSectors = prevTotalSectors; + + return xError; +} /* FF_ParseExtended() */ +/*-----------------------------------------------------------*/ + +/** + * @public + * @brief Searches a disk for all primary and extended/logical partitions + * @brief Previously called FF_PartitionCount + * + * @param pxIOManager FF_IOManager_t object. + * @param pPartsFound Contains an array of ffconfigMAX_PARTITIONS partitions + * + * @Return >=0 Number of partitions found + * @Return <0 error + **/ +FF_Error_t FF_PartitionSearch( FF_IOManager_t *pxIOManager, FF_SPartFound_t *pPartsFound ) +{ +BaseType_t xPartNr; +FF_Buffer_t *pxBuffer; +uint8_t *ucDataBuffer; +BaseType_t isPBR = pdFALSE; +FF_Error_t xError = FF_ERR_NONE; +uint32_t prevTotalSectors = pxIOManager->xPartition.ulTotalSectors; +FF_Part_t pxPartitions[ 4 ]; + + memset( pPartsFound, '\0', sizeof( *pPartsFound ) ); + + do + { + pxBuffer = FF_GetBuffer( pxIOManager, 0, FF_MODE_READ ); + if( pxBuffer == NULL ) + { + xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_PARTITIONSEARCH; + break; + } + + /* Disable sector checking in FF_BlockRead + Let user driver return an error is appropriate. */ + pxIOManager->xPartition.ulTotalSectors = 0; + ucDataBuffer = pxBuffer->pucBuffer; + + /* Check MBR (Master Boot Record) or + PBR (Partition Boot Record) signature. */ + if( ( FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE ) != 0x55 ) && + ( FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE ) != 0xAA ) ) + { + /* No MBR, but is it a PBR ? + Partition Boot Record */ + if( ( FF_getChar( ucDataBuffer, 0 ) == 0xEB ) && /* PBR Byte 0 */ + ( FF_getChar( ucDataBuffer, 2 ) == 0x90 ) ) + { + /* PBR Byte 2 + No MBR but PBR exist then there is only one partition + Handle this later. */ + isPBR = pdTRUE; + } + else + { + FF_PRINTF( "FF_PartitionSearch: [%02X,%02X] No signature (%02X %02X), no PBR neither\n", + FF_getChar( ucDataBuffer, 0 ), + FF_getChar( ucDataBuffer, 2 ), + FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE ), + FF_getChar( ucDataBuffer, FF_FAT_MBR_SIGNATURE + 1 ) ); + + /* No MBR and no PBR then no partition found. */ + xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_PARTITIONSEARCH; + break; + } + } + /* Copy the 4 partition records into 'pxPartitions': */ + FF_ReadParts( ucDataBuffer, pxPartitions ); + + for( xPartNr = 0; ( xPartNr < 4 ) && ( isPBR == pdFALSE ); xPartNr++ ) + { + /* FF_PRINTF ("FF_Part[%d]: id %02X act %02X Start %6lu Len %6lu (sectors)\n", */ + /* xPartNr, pxPartitions[ xPartNr ].ucPartitionID, */ + /* pxPartitions[ xPartNr ].ucActive, */ + /* pxPartitions[ xPartNr ].ulStartLBA, */ + /* pxPartitions[ xPartNr ].ulSectorCount); */ + if( prvIsExtendedPartition( pxPartitions[ xPartNr ].ucPartitionID ) != pdFALSE ) + { + continue; /* Do this later */ + } + + /* The first sector must be a MBR, then check the partition entry in the MBR */ + if( ( pxPartitions[ xPartNr ].ucActive != 0x80 ) && + ( pxPartitions[ xPartNr ].ucActive != 0x00 ) ) + { + if( ( xPartNr == 0 ) && + ( FF_getShort( ucDataBuffer, FF_FAT_RESERVED_SECTORS ) != 0 ) && + ( FF_getChar( ucDataBuffer, FF_FAT_NUMBER_OF_FATS ) != 0 ) ) + { + isPBR = pdTRUE; + } + else + { + xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_PARTITIONSEARCH; + break; + } + } + else if( pxPartitions[ xPartNr ].ulSectorCount ) + { + FF_Part_t *p = &pPartsFound->pxPartitions[ pPartsFound->iCount++ ]; + *p = pxPartitions[ xPartNr ]; + p->bIsExtended = 0; + if( pPartsFound->iCount >= ffconfigMAX_PARTITIONS ) + { + break; + } + } + } + if( FF_isERR( xError ) || ( pPartsFound->iCount >= ffconfigMAX_PARTITIONS ) ) + { + break; + } + for( xPartNr = 0; xPartNr < 4; xPartNr++ ) + { + if( prvIsExtendedPartition( pxPartitions[ xPartNr ].ucPartitionID ) ) + { + xError = FF_ParseExtended( pxIOManager, pxPartitions[ xPartNr ].ulStartLBA, + pxPartitions[ xPartNr ].ulSectorCount, pPartsFound ); + + if( ( FF_isERR( xError ) != pdFALSE ) || ( pPartsFound->iCount >= ffconfigMAX_PARTITIONS ) ) + { + goto done; + } + } + } + + if( pPartsFound->iCount == 0 ) + { + FF_PRINTF( "FF_Part: no partitions, try as PBR\n" ); + isPBR = pdTRUE; + } + + if( isPBR ) + { + uint8_t media = FF_getChar( ucDataBuffer, FF_FAT_MEDIA_TYPE ); + FF_Part_t *p; + if( !prvIsValidMedia( media ) ) + { + FF_PRINTF( "FF_Part: Looks like PBR but media %02X\n", media ); + xError = FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION | FF_PARTITIONSEARCH; + goto done; + } + + /* This looks like a PBR because it has a valid media type */ + p = pPartsFound->pxPartitions; + p->ulStartLBA = 0; /* FF_FAT_PTBL_LBA */ + p->ulSectorCount = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_16_TOTAL_SECTORS ); + if( p->ulSectorCount == 0ul ) + { + p->ulSectorCount = FF_getLong( pxBuffer->pucBuffer, FF_FAT_32_TOTAL_SECTORS ); + } + + p->ucActive = 0x80; /* FF_FAT_PTBL_ACTIVE */ + p->ucPartitionID = 0x0B; /* FF_FAT_PTBL_ID MSDOS data partition */ + p->bIsExtended = 0; + pPartsFound->iCount = 1; + } + } while( pdFALSE ); +done: + if( pxBuffer ) + { + FF_Error_t xTempError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = xTempError; + } + } + + pxIOManager->xPartition.ulTotalSectors = prevTotalSectors; + + return FF_isERR( xError ) ? xError : pPartsFound->iCount; +} /* FF_PartitionSearch() */ +/*-----------------------------------------------------------*/ + +/* + Mount GPT Partition Tables +*/ +#define FF_GPT_HEAD_ENTRY_SIZE 0x54 +#define FF_GPT_HEAD_TOTAL_ENTRIES 0x50 +#define FF_GPT_HEAD_PART_ENTRY_LBA 0x48 +#define FF_GPT_ENTRY_FIRST_SECTOR_LBA 0x20 +#define FF_GPT_HEAD_CRC 0x10 +#define FF_GPT_HEAD_LENGTH 0x0C + +static FF_Error_t FF_GetEfiPartitionEntry( FF_IOManager_t *pxIOManager, uint32_t ulPartitionNumber ) +{ +/* Continuing on from FF_Mount() pPartition->ulBeginLBA should be the sector of the GPT Header */ +FF_Buffer_t *pxBuffer; +FF_Partition_t *pxPartition = &( pxIOManager->xPartition ); + +uint32_t ulBeginGPT; +uint32_t ulEntrySector; +uint32_t ulSectorOffset; +uint32_t ulPartitionEntrySize; +uint32_t ulGPTHeadCRC, ulGPTCrcCheck, ulGPTHeadLength; + +FF_Error_t xError; + + do + { + if( ulPartitionNumber >= 128 ) + { + xError = FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_GETEFIPARTITIONENTRY; + break; + } + pxBuffer = FF_GetBuffer( pxIOManager, pxPartition->ulBeginLBA, FF_MODE_READ ); + if( pxBuffer == NULL ) + { + xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_GETEFIPARTITIONENTRY; + break; + } + + /* Verify this is an EFI header with the text "EFI PART": */ + if( memcmp( pxBuffer->pucBuffer, "EFI PART", 8 ) != 0 ) + { + /* Already returning an error, but this error would override the current one. */ + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_GETEFIPARTITIONENTRY; + } + break; + } + + ulBeginGPT = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_PART_ENTRY_LBA ); + ulPartitionEntrySize = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_ENTRY_SIZE ); + ulGPTHeadCRC = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_CRC ); + ulGPTHeadLength = FF_getLong( pxBuffer->pucBuffer, FF_GPT_HEAD_LENGTH ); + + /* Calculate Head CRC */ + /* Blank CRC field */ + FF_putLong( pxBuffer->pucBuffer, FF_GPT_HEAD_CRC, 0x00000000 ); + + /* Calculate CRC */ + ulGPTCrcCheck = FF_GetCRC32( pxBuffer->pucBuffer, ulGPTHeadLength ); + + /* Restore The CRC field */ + FF_putLong( pxBuffer->pucBuffer, FF_GPT_HEAD_CRC, ulGPTHeadCRC ); + + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + if( FF_isERR( xError ) ) + { + break; + } + + /* Check CRC */ + if( ulGPTHeadCRC != ulGPTCrcCheck ) + { + xError = FF_ERR_IOMAN_GPT_HEADER_CORRUPT | FF_GETEFIPARTITIONENTRY; + break; + } + + /* Calculate Sector Containing the Partition Entry we want to use. */ + ulEntrySector = ( ( ulPartitionNumber * ulPartitionEntrySize ) / pxIOManager->usSectorSize ) + ulBeginGPT; + ulSectorOffset = ( ulPartitionNumber % ( pxIOManager->usSectorSize / ulPartitionEntrySize ) ) * ulPartitionEntrySize; + + pxBuffer = FF_GetBuffer( pxIOManager, ulEntrySector, FF_MODE_READ ); + { + if( pxBuffer == NULL ) + { + xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_GETEFIPARTITIONENTRY; + break; + } + + pxPartition->ulBeginLBA = FF_getLong( pxBuffer->pucBuffer, ulSectorOffset + FF_GPT_ENTRY_FIRST_SECTOR_LBA ); + } + + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + if( FF_isERR( xError ) == pdFALSE ) + { + if( pxPartition->ulBeginLBA == 0ul ) + { + xError = FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_GETEFIPARTITIONENTRY; + } + } + } + while( pdFALSE ); + + return xError; +} /* FF_GetEfiPartitionEntry() */ +/*-----------------------------------------------------------*/ + +/** + * @public + * @brief Mounts the Specified partition, the volume specified by the FF_IOManager_t object provided. + * + * The device drivers must adhere to the specification provided by + * FF_WriteBlocks_t and FF_ReadBlocks_t. + * + * @param pxIOManager FF_IOManager_t object. + * @param PartitionNumber The primary or logical partition number to be mounted, + * ranging between 0 and ffconfigMAX_PARTITIONS-1 (normally 0) + * Note that FF_PartitionSearch can be called in advance to + * enumerate all available partitions + * + * @Return 0 on success. + * @Return FF_ERR_NULL_POINTER if a pxIOManager object wasn't provided. + * @Return FF_ERR_IOMAN_INVALID_PARTITION_NUM if the partition number is out of range. + * @Return FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION if no partition was found. + * @Return FF_ERR_IOMAN_INVALID_FORMAT if the master boot record or partition boot block didn't provide sensible data. + * @Return FF_ERR_IOMAN_NOT_FAT_FORMATTED if the volume or partition couldn't be determined to be FAT. (@see FreeRTOSFATConfig.h) + * + **/ +FF_Error_t FF_Mount( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber ) +{ +FF_Partition_t *pxPartition; +FF_Buffer_t *pxBuffer = 0; +FF_Error_t xError = FF_ERR_NONE; +int16_t rootEntryCount; +FF_IOManager_t *pxIOManager = pxDisk->pxIOManager; + +/* HT TODO: find a method to safely determine the FAT type: 32/16/12 */ +/* other than only counting Clusters */ +/* UBaseType_t fat32Indicator = 0; */ +FF_Part_t *pxMyPartition; +#if( ffconfigHASH_CACHE != 0 ) + BaseType_t i; +#endif +FF_Error_t xPartitionCount = 0; +FF_SPartFound_t partsFound; +partsFound.iCount = 0; + + do + { + if( pxIOManager == NULL ) + { + xError = FF_ERR_NULL_POINTER | FF_MOUNT; + break; + } + + pxPartition = &( pxIOManager->xPartition ); + + #if( ffconfigREMOVABLE_MEDIA != 0 ) + { + pxIOManager->ucFlags &= ( uint8_t ) ( ~ ( FF_IOMAN_DEVICE_IS_EXTRACTED ) ); + } + #endif /* ffconfigREMOVABLE_MEDIA */ + + /* FF_IOMAN_InitBufferDescriptors will clear 'pxBuffers' */ + memset( pxIOManager->pucCacheMem, '\0', ( size_t ) pxIOManager->usSectorSize * pxIOManager->usCacheSize ); + + #if( ffconfigHASH_CACHE != 0 ) + { + memset( pxIOManager->xHashCache, '\0', sizeof( pxIOManager->xHashCache ) ); + for( i = 0; i < ffconfigHASH_CACHE_DEPTH; i++ ) + { + /* _HT_ Check why did JW put it to 100? */ + pxIOManager->xHashCache[ i ].ulMisses = 100; + } + } + #endif + #if( ffconfigPATH_CACHE != 0 ) + { + memset( pxPartition->pxPathCache, '\0', sizeof( pxPartition->pxPathCache ) ); + } + #endif + FF_IOMAN_InitBufferDescriptors( pxIOManager ); + pxIOManager->FirstFile = 0; + + xPartitionCount = FF_PartitionSearch( pxIOManager, &partsFound ); + if( FF_isERR( xPartitionCount ) ) + { + xError = xPartitionCount; + break; + } + + if( xPartitionCount == 0 ) + { + xError = FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION | FF_MOUNT; + break; + } + + if( xPartitionNumber >= xPartitionCount ) + { + xError = FF_ERR_IOMAN_INVALID_PARTITION_NUM | FF_MOUNT; + break; + } + + pxMyPartition = &( partsFound.pxPartitions[ xPartitionNumber ] ); + + pxPartition->ulBeginLBA = pxMyPartition->ulStartLBA; + + if( pxMyPartition->ucPartitionID == 0xEE ) + { + xError = FF_GetEfiPartitionEntry( pxIOManager, xPartitionNumber ); + + if( FF_isERR( xError ) ) + { + break; + } + } + + /* Now we get the Partition sector. */ + pxBuffer = FF_GetBuffer( pxIOManager, pxPartition->ulBeginLBA, FF_MODE_READ ); + if( pxBuffer == NULL ) + { + xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_MOUNT; + break; + } + + pxPartition->usBlkSize = FF_getShort( pxBuffer->pucBuffer, FF_FAT_BYTES_PER_SECTOR ); + if( ( ( pxPartition->usBlkSize % 512 ) != 0 ) || ( pxPartition->usBlkSize == 0 ) ) + { + /* An error here should override the current error, as its likely fatal. */ + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + if( FF_isERR( xError ) == pdFALSE ) + { + xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNT; + } + break; + } + + /* Assume FAT16, then we'll adjust if its FAT32 */ + pxPartition->usReservedSectors = FF_getShort( pxBuffer->pucBuffer, FF_FAT_RESERVED_SECTORS ); + pxPartition->ulFATBeginLBA = pxPartition->ulBeginLBA + pxPartition->usReservedSectors; + + pxPartition->ucNumFATS = ( uint8_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_NUMBER_OF_FATS ); + pxPartition->ulSectorsPerFAT = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_16_SECTORS_PER_FAT ); + + pxPartition->ulSectorsPerCluster = FF_getChar( pxBuffer->pucBuffer, FF_FAT_SECTORS_PER_CLUS ); + + /* Set the BlockFactor (How many real-blocks in a fake block!). */ + pxPartition->ucBlkFactor = ( uint8_t ) ( pxPartition->usBlkSize / pxIOManager->usSectorSize ); + pxPartition->ulTotalSectors = ( uint32_t ) FF_getShort( pxBuffer->pucBuffer, FF_FAT_16_TOTAL_SECTORS ); + if( pxPartition->ulTotalSectors == 0 ) + { + pxPartition->ulTotalSectors = FF_getLong( pxBuffer->pucBuffer, FF_FAT_32_TOTAL_SECTORS ); + } + + if( pxPartition->ulSectorsPerFAT == 0 ) + { /* FAT32 */ + pxPartition->ulSectorsPerFAT = FF_getLong( pxBuffer->pucBuffer, FF_FAT_32_SECTORS_PER_FAT ); + pxPartition->ulRootDirCluster = FF_getLong( pxBuffer->pucBuffer, FF_FAT_ROOT_DIR_CLUSTER ); + memcpy( pxPartition->pcVolumeLabel, pxBuffer->pucBuffer + FF_FAT_32_VOL_LABEL, sizeof( pxPartition->pcVolumeLabel ) - 1 ); + } + else + { /* FAT16 */ + pxPartition->ulRootDirCluster = 1; /* 1st Cluster is RootDir! */ + memcpy( pxPartition->pcVolumeLabel, pxBuffer->pucBuffer + FF_FAT_16_VOL_LABEL, sizeof( pxPartition->pcVolumeLabel ) - 1); + } + + pxPartition->ulClusterBeginLBA = pxPartition->ulFATBeginLBA + ( pxPartition->ucNumFATS * pxPartition->ulSectorsPerFAT ); + #if( ffconfigWRITE_FREE_COUNT != 0 ) + { + pxPartition->ulFSInfoLBA = pxPartition->ulBeginLBA + FF_getShort( pxBuffer->pucBuffer, 48 ); + } + #endif + FF_ReleaseBuffer( pxIOManager, pxBuffer ); /* Release the buffer finally! */ + if( pxPartition->usBlkSize == 0 ) + { + xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNT; + break; + } + + rootEntryCount = FF_getShort( pxBuffer->pucBuffer, FF_FAT_ROOT_ENTRY_COUNT ); + pxPartition->ulRootDirSectors = ( ( rootEntryCount * 32 ) + pxPartition->usBlkSize - 1 ) / pxPartition->usBlkSize; + pxPartition->ulFirstDataSector = pxPartition->ulClusterBeginLBA + pxPartition->ulRootDirSectors; + pxPartition->ulDataSectors = pxPartition->ulTotalSectors - ( pxPartition->usReservedSectors + ( pxPartition->ucNumFATS * pxPartition->ulSectorsPerFAT ) + pxPartition->ulRootDirSectors ); + + /* + * HT: fat32Indicator not yet used + * As there is so much confusion about the FAT types + * I was thinking of collecting indications for either FAT12, 16 or 32 + */ + + /* + if( FF_getShort( pxBuffer->pucBuffer, FF_FAT_EXT_BOOT_SIGNATURE ) == 0x29 ) + fat32Indicator++; + if( rootEntryCount == 0 ) + fat32Indicator++; + */ + if( pxPartition->ulSectorsPerCluster == 0 ) + { + xError = FF_ERR_IOMAN_INVALID_FORMAT | FF_MOUNT; + break; + } + + pxPartition->ulNumClusters = pxPartition->ulDataSectors / pxPartition->ulSectorsPerCluster; + + xError = prvDetermineFatType( pxIOManager ); + if( FF_isERR( xError ) ) + { + break; + } + + if( !rootEntryCount && pxPartition->ucType != FF_T_FAT32 ) + { + FF_PRINTF( "No root dir, must be a FAT32\n" ); + pxPartition->ucType = FF_T_FAT32; + } + + pxPartition->ucPartitionMounted = pdTRUE; + pxPartition->ulLastFreeCluster = 0; + #if( ffconfigMOUNT_FIND_FREE != 0 ) + { + FF_LockFAT( pxIOManager ); + { + /* The parameter 'pdFALSE' means: do not claim the free cluster found. */ + pxPartition->ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE ); + } + FF_UnlockFAT( pxIOManager ); + + if( FF_isERR( xError ) ) + { + if( FF_GETERROR( xError ) == FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE ) + { + pxPartition->ulLastFreeCluster = 0; + } + else + { + break; + } + } + + pxPartition->ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + } + #else + { + pxPartition->ulFreeClusterCount = 0; + } + #endif /* ffconfigMOUNT_FIND_FREE */ + } + while( pdFALSE ); + + if( FF_isERR( xError ) == pdFALSE ) + { + xError = 0; + } + + return xError; +} /* FF_Mount() */ +/*-----------------------------------------------------------*/ + +/** + * @private + * @brief Checks the cache for Active Handles + * + * @param pxIOManager FF_IOManager_t Object. + * + * @Return pdTRUE if an active handle is found, else pdFALSE. + * + * @pre This function must be wrapped with the cache handling semaphore. + **/ +static BaseType_t prvHasActiveHandles( FF_IOManager_t *pxIOManager ) +{ +BaseType_t xResult; +FF_Buffer_t *pxBuffer = pxIOManager->pxBuffers; +FF_Buffer_t *pxLastBuffer = pxBuffer + pxIOManager->usCacheSize; + + for( ; ; ) + { + if( pxBuffer->usNumHandles ) + { + xResult = pdTRUE; + break; + } + pxBuffer++; + if( pxBuffer == pxLastBuffer ) + { + xResult = pdFALSE; + break; + } + } + + return xResult; +} /* prvHasActiveHandles() */ +/*-----------------------------------------------------------*/ + +/** + * @public + * @brief Unmounts the active partition. + * + * @param pxIOManager FF_IOManager_t Object. + * + * @Return FF_ERR_NONE on success. + **/ +FF_Error_t FF_Unmount( FF_Disk_t *pxDisk ) +{ +FF_Error_t xError = FF_ERR_NONE; +FF_IOManager_t *pxIOManager; + +#if( ffconfigMIRROR_FATS_UMOUNT != 0 ) + UBaseType_t uxIndex, y; + FF_Buffer_t *pxBuffer; +#endif + + if( pxDisk->pxIOManager == NULL ) + { + xError = FF_ERR_NULL_POINTER | FF_UNMOUNT; + } + else if( pxDisk->pxIOManager->xPartition.ucPartitionMounted == 0 ) + { + xError = FF_ERR_NONE; + } + else + { + pxIOManager = pxDisk->pxIOManager; + FF_PendSemaphore( pxIOManager->pvSemaphore ); /* Ensure that there are no File Handles */ + { + if( prvHasActiveHandles( pxIOManager ) != 0 ) + { + /* Active handles found on the cache. */ + xError = FF_ERR_IOMAN_ACTIVE_HANDLES | FF_UNMOUNT; + } + else if( pxIOManager->FirstFile != NULL ) + { + /* Open files in this partition. */ + xError = FF_ERR_IOMAN_ACTIVE_HANDLES | FF_UNMOUNT; + } + else + { + /* Release Semaphore to call this function! */ + FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + /* Flush any unwritten sectors to disk. */ + xError = FF_FlushCache( pxIOManager ); + /* Reclaim Semaphore */ + FF_PendSemaphore( pxIOManager->pvSemaphore ); + + if( FF_isERR( xError ) == pdFALSE ) + { + pxIOManager->xPartition.ucPartitionMounted = pdFALSE; + + #if( ffconfigMIRROR_FATS_UMOUNT != 0 ) + { + FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + for( uxIndex = 0; uxIndex < pxIOManager->xPartition.ulSectorsPerFAT; uxIndex++ ) + { + pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFATBeginLBA + uxIndex, FF_MODE_READ ); + if( !pxBuffer ) + { + xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_UNMOUNT; + break; + } + for( y = 0; y < pxIOManager->xPartition.ucNumFATS; y++ ) + { + FF_BlockWrite( pxIOManager, + pxIOManager->xPartition.ulFATBeginLBA + ( y * pxIOManager->xPartition.ulSectorsPerFAT ) + uxIndex, 1, + pxBuffer->pucBuffer, pdFALSE ); + } + } + FF_PendSemaphore( pxIOManager->pvSemaphore ); + } + #endif + } + } + } + FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + } + + return xError; +} /* FF_Unmount() */ +/*-----------------------------------------------------------*/ + +FF_Error_t FF_IncreaseFreeClusters( FF_IOManager_t *pxIOManager, uint32_t Count ) +{ +FF_Error_t xError; + +#if( ffconfigWRITE_FREE_COUNT != 0 ) + FF_Buffer_t *pxBuffer; +#endif + + do + { + /* Open a do {} while( pdFALSE ) loop to allow the use of break statements. */ + if( pxIOManager->xPartition.ulFreeClusterCount == 0ul ) + { + /* Apparently the number of free clusters has not been calculated yet, + or no free cluster was available. Now check it. */ + pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError ); + if( FF_isERR( xError ) ) + { + break; + } + } + else + { + xError = FF_ERR_NONE; + taskENTER_CRITICAL(); + { + pxIOManager->xPartition.ulFreeClusterCount += Count; + } + taskEXIT_CRITICAL(); + } + + if( pxIOManager->xPartition.ulLastFreeCluster == 0 ) + { + BaseType_t xTakeLock = FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE; + + if( xTakeLock ) + { + FF_LockFAT( pxIOManager ); + } + /* Find the an available cluster. */ + pxIOManager->xPartition.ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE ); + if( xTakeLock ) + { + FF_UnlockFAT( pxIOManager ); + } + if( FF_isERR( xError ) ) + { + break; + } + } + + #if( ffconfigWRITE_FREE_COUNT != 0 ) + { + /* FAT32 updates the FSINFO sector. */ + if( pxIOManager->xPartition.ucType == FF_T_FAT32 ) + { + /* Find the FSINFO sector. */ + pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_WRITE ); + if( pxBuffer == NULL ) + { + xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_INCREASEFREECLUSTERS; + } + else + { + uint32_t ulSignature1; + uint32_t ulSignature2; + + ulSignature1 = FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE1_000 ); + ulSignature2 = FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE2_484 ); + + if( ( ulSignature1 == FS_INFO_SIGNATURE1_0x41615252 ) && + ( ulSignature2 == FS_INFO_SIGNATURE2_0x61417272 ) ) + { + /* FSINFO sector magic numbers we're verified. Safe to write. */ + FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_COUNT_488, pxIOManager->xPartition.ulFreeClusterCount ); + FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_CLUSTER_492, pxIOManager->xPartition.ulLastFreeCluster ); + } + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + } + } + } + #endif + } + while( pdFALSE ); + + return xError; +} /* FF_IncreaseFreeClusters() */ +/*-----------------------------------------------------------*/ + +FF_Error_t FF_DecreaseFreeClusters( FF_IOManager_t *pxIOManager, uint32_t Count ) +{ +FF_Error_t xError = FF_ERR_NONE; +#if( ffconfigWRITE_FREE_COUNT != 0 ) + FF_Buffer_t *pxBuffer; +#endif + + if( pxIOManager->xPartition.ulFreeClusterCount == 0ul ) + { + pxIOManager->xPartition.ulFreeClusterCount = FF_CountFreeClusters( pxIOManager, &xError ); + } + else + { + taskENTER_CRITICAL(); + pxIOManager->xPartition.ulFreeClusterCount -= Count; + taskEXIT_CRITICAL(); + } + + if( FF_isERR( xError ) == pdFALSE ) + { + if( pxIOManager->xPartition.ulLastFreeCluster == 0 ) + { + FF_LockFAT( pxIOManager ); + { + pxIOManager->xPartition.ulLastFreeCluster = FF_FindFreeCluster( pxIOManager, &xError, pdFALSE ); + } + FF_UnlockFAT( pxIOManager ); + } + } + if( FF_isERR( xError ) == pdFALSE ) + { + #if( ffconfigWRITE_FREE_COUNT != 0 ) + { + /* FAT32 update the FSINFO sector. */ + if( pxIOManager->xPartition.ucType == FF_T_FAT32 ) + { + /* Find the FSINFO sector. */ + pxBuffer = FF_GetBuffer( pxIOManager, pxIOManager->xPartition.ulFSInfoLBA, FF_MODE_WRITE ); + if( pxBuffer == NULL ) + { + xError = FF_ERR_DEVICE_DRIVER_FAILED | FF_DECREASEFREECLUSTERS; + } + else + { + if( ( FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE1_000 ) == FS_INFO_SIGNATURE1_0x41615252 ) && + ( FF_getLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_SIGNATURE2_484 ) == FS_INFO_SIGNATURE2_0x61417272 ) ) + { + /* FSINFO sector magic nums we're verified. Safe to write. */ + FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_COUNT_488, pxIOManager->xPartition.ulFreeClusterCount ); + FF_putLong( pxBuffer->pucBuffer, FS_INFO_OFFSET_FREE_CLUSTER_492, pxIOManager->xPartition.ulLastFreeCluster ); + } + xError = FF_ReleaseBuffer( pxIOManager, pxBuffer ); + } + } + } + #endif + } + + return xError; +} /* FF_DecreaseFreeClusters() */ +/*-----------------------------------------------------------*/ + +/** + * @brief Returns the Block-size of a mounted Partition + * + * The purpose of this function is to provide API access to information + * that might be useful in special cases. Like USB sticks that require a sector + * knocking sequence for security. After the sector knock, some secure USB + * sticks then present a different BlockSize. + * + * @param pxIOManager FF_IOManager_t Object returned from FF_CreateIOManger() + * + * @Return The blocksize of the partition. A value less than 0 when an error occurs. + * @Return Any negative value can be cast to the FF_Error_t type. + **/ +int32_t FF_GetPartitionBlockSize( FF_IOManager_t *pxIOManager ) +{ +int32_t lReturn; + if( pxIOManager ) + { + lReturn = ( int32_t ) pxIOManager->xPartition.usBlkSize; + } + else + { + lReturn = FF_ERR_NULL_POINTER | FF_GETPARTITIONBLOCKSIZE; + } + + return lReturn; +} /* FF_GetPartitionBlockSize() */ +/*-----------------------------------------------------------*/ + +#if( ffconfig64_NUM_SUPPORT != 0 ) + + /** + * @brief Returns the number of bytes contained within the mounted partition or volume. + * + * @param pxIOManager FF_IOManager_t Object returned from FF_CreateIOManger() + * + * @Return The total number of bytes that the mounted partition or volume contains. + * + **/ + uint64_t FF_GetVolumeSize( FF_IOManager_t *pxIOManager ) + { + uint64_t ullResult; + + if( pxIOManager ) + { + uint32_t TotalClusters = ( pxIOManager->xPartition.ulDataSectors / pxIOManager->xPartition.ulSectorsPerCluster ); + ullResult = ( uint64_t ) + ( + ( uint64_t ) TotalClusters * ( uint64_t ) + ( ( uint64_t ) pxIOManager->xPartition.ulSectorsPerCluster * ( uint64_t ) pxIOManager->xPartition.usBlkSize ) + ); + } + else + { + ullResult = 0ULL; + } + + return ullResult; + } /* FF_GetVolumeSize() */ +#else + uint32_t FF_GetVolumeSize( FF_IOManager_t *pxIOManager ) + { + uint32_t ulResult; + if( pxIOManager ) + { + uint32_t TotalClusters = pxIOManager->xPartition.ulDataSectors / pxIOManager->xPartition.ulSectorsPerCluster; + ulResult = ( uint32_t ) ( TotalClusters * ( pxIOManager->xPartition.ulSectorsPerCluster * pxIOManager->xPartition.usBlkSize ) ); + } + else + { + ulResult = 0UL; + } + + return ulResult; + } /* FF_GetVolumeSize() */ +#endif +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_locking.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_locking.c new file mode 100644 index 000000000..41db9ba32 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_locking.c @@ -0,0 +1,325 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +#include +#include +#include + +/* Scheduler include files. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "ff_headers.h" +#include "event_groups.h" + +#ifndef configUSE_RECURSIVE_MUTEXES + #error configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h +#else + #if( configUSE_RECURSIVE_MUTEXES != 1 ) + #error configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h + #endif +#endif /* configUSE_RECURSIVE_MUTEXES */ + +#if ( INCLUDE_vTaskDelay != 1 ) + #error Missing some FreeRTOS define +#endif + +/* There are two areas which are protected with a semaphore: +Directories and the FAT area. +The masks below are used when calling Group Event functions. */ +#define FF_FAT_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_FAT_LOCK ) +#define FF_DIR_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_DIR_LOCK ) + +/* This is not a real lock: it is a bit (or semaphore) will will be given +each time when a sector buffer is released. */ +#define FF_BUF_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_BUF_LOCK ) + +/*-----------------------------------------------------------*/ + +BaseType_t FF_TrySemaphore( void *pxSemaphore, uint32_t ulTime_ms ) +{ +BaseType_t xReturn; + + /* HT: Actually FF_TrySemaphore is never used. */ + if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING ) + { + return 0; + } + configASSERT( pxSemaphore ); + xReturn = xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) pxSemaphore, pdMS_TO_TICKS( ulTime_ms ) ); + return xReturn; +} +/*-----------------------------------------------------------*/ + +void FF_PendSemaphore( void *pxSemaphore ) +{ + if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING ) + { + /* No need to take the semaphore. */ + return; + } + configASSERT( pxSemaphore ); + xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) pxSemaphore, portMAX_DELAY ); +} +/*-----------------------------------------------------------*/ + +void FF_ReleaseSemaphore( void *pxSemaphore ) +{ + if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING ) + { + /* Scheduler not yet active. */ + return; + } + configASSERT( pxSemaphore ); + xSemaphoreGiveRecursive( ( SemaphoreHandle_t ) pxSemaphore ); +} +/*-----------------------------------------------------------*/ + +void FF_Sleep( uint32_t ulTime_ms ) +{ + if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING ) + { + /* This sleep is used as a kind of yield. + Not necessary while the Scheduler does not run. */ + return; + } + vTaskDelay( pdMS_TO_TICKS( ulTime_ms ) ); +} +/*-----------------------------------------------------------*/ + +void FF_DeleteEvents( FF_IOManager_t *pxIOManager ) +{ + if( pxIOManager->xEventGroup != NULL ) + { + vEventGroupDelete( pxIOManager->xEventGroup ); + } +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_CreateEvents( FF_IOManager_t *pxIOManager ) +{ +BaseType_t xResult; + + pxIOManager->xEventGroup = xEventGroupCreate(); + if( pxIOManager->xEventGroup != NULL ) + { + xEventGroupSetBits( pxIOManager->xEventGroup, + FF_FAT_LOCK_EVENT_BITS | FF_DIR_LOCK_EVENT_BITS | FF_BUF_LOCK_EVENT_BITS ); + xResult = pdTRUE; + } + else + { + xResult = pdFALSE; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +void FF_LockDirectory( FF_IOManager_t *pxIOManager ) +{ + EventBits_t xBits; + + if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING ) + { + /* Scheduler not yet active. */ + return; + } + for( ;; ) + { + /* Called when a task want to make changes to a directory. + First it waits for the desired bit to come high. */ + xEventGroupWaitBits( pxIOManager->xEventGroup, + FF_DIR_LOCK_EVENT_BITS, /* uxBitsToWaitFor */ + ( EventBits_t )0, /* xClearOnExit */ + pdFALSE, /* xWaitForAllBits n.a. */ + pdMS_TO_TICKS( 10000UL ) ); + + /* The next operation will only succeed for 1 task at a time, + because it is an atomary test & set operation: */ + xBits = xEventGroupClearBits( pxIOManager->xEventGroup, FF_DIR_LOCK_EVENT_BITS ); + + if( ( xBits & FF_DIR_LOCK_EVENT_BITS ) != 0 ) + { + /* This task has cleared the desired bit. + It now 'owns' the resource. */ + break; + } + } +} +/*-----------------------------------------------------------*/ + +void FF_UnlockDirectory( FF_IOManager_t *pxIOManager ) +{ + if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING ) + { + /* Scheduler not yet active. */ + return; + } + configASSERT( ( xEventGroupGetBits( pxIOManager->xEventGroup ) & FF_DIR_LOCK_EVENT_BITS ) == 0 ); + xEventGroupSetBits( pxIOManager->xEventGroup, FF_DIR_LOCK_EVENT_BITS ); +} +/*-----------------------------------------------------------*/ + +int FF_Has_Lock( FF_IOManager_t *pxIOManager, uint32_t aBits ) +{ +int iReturn; + + if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING ) + { + /* Scheduler not yet active. */ + return 0; + } + void *handle = xTaskGetCurrentTaskHandle(); + if( ( aBits & FF_FAT_LOCK_EVENT_BITS ) != 0 ) + { + if( ( pxIOManager->pvFATLockHandle != NULL ) && ( pxIOManager->pvFATLockHandle == handle ) ) + { + iReturn = pdTRUE; + } + else + { + iReturn = pdFALSE; + } + } + else + { + iReturn = pdFALSE; + } + return iReturn; +} + +void FF_Assert_Lock( FF_IOManager_t *pxIOManager, uint32_t aBits ) +{ + void *handle; + + if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING ) + { + /* Scheduler not yet active. */ + return; + } + handle = xTaskGetCurrentTaskHandle(); + + if( ( aBits & FF_FAT_LOCK_EVENT_BITS ) != 0 ) + { + configASSERT( ( pxIOManager->pvFATLockHandle != NULL ) && ( pxIOManager->pvFATLockHandle == handle ) ); + + /* In case configASSERT() is not defined. */ + ( void ) pxIOManager; + ( void ) handle; + } +} + +void FF_LockFAT( FF_IOManager_t *pxIOManager ) +{ +EventBits_t xBits; + + if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING ) + { + /* Scheduler not yet active. */ + return; + } + configASSERT( FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE ); + + for( ;; ) + { + /* Called when a task want to make changes to the FAT area. + First it waits for the desired bit to come high. */ + xEventGroupWaitBits( pxIOManager->xEventGroup, + FF_FAT_LOCK_EVENT_BITS, /* uxBitsToWaitFor */ + ( EventBits_t )0, /* xClearOnExit */ + pdFALSE, /* xWaitForAllBits n.a. */ + pdMS_TO_TICKS( 10000UL ) ); + + /* The next operation will only succeed for 1 task at a time, + because it is an atomary test & set operation: */ + xBits = xEventGroupClearBits( pxIOManager->xEventGroup, FF_FAT_LOCK_EVENT_BITS ); + + if( ( xBits & FF_FAT_LOCK_EVENT_BITS ) != 0 ) + { + /* This task has cleared the desired bit. + It now 'owns' the resource. */ + pxIOManager->pvFATLockHandle = xTaskGetCurrentTaskHandle(); + break; + } + } +} +/*-----------------------------------------------------------*/ + +void FF_UnlockFAT( FF_IOManager_t *pxIOManager ) +{ + if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING ) + { + /* Scheduler not yet active. */ + return; + } + configASSERT( ( xEventGroupGetBits( pxIOManager->xEventGroup ) & FF_FAT_LOCK_EVENT_BITS ) == 0 ); + pxIOManager->pvFATLockHandle = NULL; + xEventGroupSetBits( pxIOManager->xEventGroup, FF_FAT_LOCK_EVENT_BITS ); +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_BufferWait( FF_IOManager_t *pxIOManager, uint32_t xWaitMS ) +{ +EventBits_t xBits; +BaseType_t xReturn; + + if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING ) + { + /* Scheduler not yet active. */ + return pdTRUE; + } + /* This function is called when a task is waiting for a sector buffer + to become available. */ + xBits = xEventGroupWaitBits( pxIOManager->xEventGroup, + FF_BUF_LOCK_EVENT_BITS, /* uxBitsToWaitFor */ + FF_BUF_LOCK_EVENT_BITS, /* xClearOnExit */ + pdFALSE, /* xWaitForAllBits n.a. */ + pdMS_TO_TICKS( xWaitMS ) ); + if( ( xBits & FF_BUF_LOCK_EVENT_BITS ) != 0 ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void FF_BufferProceed( FF_IOManager_t *pxIOManager ) +{ + if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING ) + { + /* Scheduler not yet active. */ + return; + } + /* Wake-up all tasks that are waiting for a sector buffer to become available. */ + xEventGroupSetBits( pxIOManager->xEventGroup, FF_BUF_LOCK_EVENT_BITS ); +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_locking.org.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_locking.org.c new file mode 100644 index 000000000..b6d22129e --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_locking.org.c @@ -0,0 +1,262 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +#include +#include +#include + +/* Scheduler include files. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "ff_headers.h" +#include "event_groups.h" + +#ifndef configUSE_RECURSIVE_MUTEXES + #error configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h +#else + #if( configUSE_RECURSIVE_MUTEXES != 1 ) + #error configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h + #endif +#endif /* configUSE_RECURSIVE_MUTEXES */ + +#if ( INCLUDE_vTaskDelay != 1 ) + #error Missing some FreeRTOS define +#endif + +/* There are two areas which are protected with a semaphore: +Directories and the FAT area. +The masks below are used when calling Group Event functions. */ +#define FF_FAT_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_FAT_LOCK ) +#define FF_DIR_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_DIR_LOCK ) + +/* This is not a real lock: it is a bit (or semaphore) will will be given +each time when a sector buffer is released. */ +#define FF_BUF_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_BUF_LOCK ) + +/*-----------------------------------------------------------*/ + +BaseType_t FF_TrySemaphore( void *pxSemaphore, uint32_t ulTime_ms ) +{ +BaseType_t xReturn; + + configASSERT( pxSemaphore ); + xReturn = xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) pxSemaphore, pdMS_TO_TICKS( ulTime_ms ) ); + return xReturn; +} +/*-----------------------------------------------------------*/ + +void FF_PendSemaphore( void *pxSemaphore ) +{ + configASSERT( pxSemaphore ); + xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) pxSemaphore, portMAX_DELAY ); +} +/*-----------------------------------------------------------*/ + +void FF_ReleaseSemaphore( void *pxSemaphore ) +{ + configASSERT( pxSemaphore ); + xSemaphoreGiveRecursive( ( SemaphoreHandle_t ) pxSemaphore ); +} +/*-----------------------------------------------------------*/ + +void FF_Sleep( uint32_t ulTime_ms ) +{ + vTaskDelay( pdMS_TO_TICKS( ulTime_ms ) ); +} +/*-----------------------------------------------------------*/ + +void FF_DeleteEvents( FF_IOManager_t *pxIOManager ) +{ + if( pxIOManager->xEventGroup != NULL ) + { + vEventGroupDelete( pxIOManager->xEventGroup ); + } +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_CreateEvents( FF_IOManager_t *pxIOManager ) +{ +BaseType_t xResult; + + pxIOManager->xEventGroup = xEventGroupCreate(); + if( pxIOManager->xEventGroup != NULL ) + { + xEventGroupSetBits( pxIOManager->xEventGroup, + FF_FAT_LOCK_EVENT_BITS | FF_DIR_LOCK_EVENT_BITS | FF_BUF_LOCK_EVENT_BITS ); + xResult = pdTRUE; + } + else + { + xResult = pdFALSE; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +void FF_LockDirectory( FF_IOManager_t *pxIOManager ) +{ + EventBits_t xBits; + + for( ;; ) + { + /* Called when a task want to make changes to a directory. + First it waits for the desired bit to come high. */ + xEventGroupWaitBits( pxIOManager->xEventGroup, + FF_DIR_LOCK_EVENT_BITS, /* uxBitsToWaitFor */ + ( EventBits_t )0, /* xClearOnExit */ + pdFALSE, /* xWaitForAllBits n.a. */ + pdMS_TO_TICKS( 10000UL ) ); + + /* The next operation will only succeed for 1 task at a time, + because it is an atomary test & set operation: */ + xBits = xEventGroupClearBits( pxIOManager->xEventGroup, FF_DIR_LOCK_EVENT_BITS ); + + if( ( xBits & FF_DIR_LOCK_EVENT_BITS ) != 0 ) + { + /* This task has cleared the desired bit. + It now 'owns' the resource. */ + break; + } + } +} +/*-----------------------------------------------------------*/ + +void FF_UnlockDirectory( FF_IOManager_t *pxIOManager ) +{ + configASSERT( ( xEventGroupGetBits( pxIOManager->xEventGroup ) & FF_DIR_LOCK_EVENT_BITS ) == 0 ); + xEventGroupSetBits( pxIOManager->xEventGroup, FF_DIR_LOCK_EVENT_BITS ); +} +/*-----------------------------------------------------------*/ + +int FF_Has_Lock( FF_IOManager_t *pxIOManager, uint32_t aBits ) +{ +int iReturn; + + void *handle = xTaskGetCurrentTaskHandle(); + if( ( aBits & FF_FAT_LOCK_EVENT_BITS ) != 0 ) + { + if( ( pxIOManager->pvFATLockHandle != NULL ) && ( pxIOManager->pvFATLockHandle == handle ) ) + { + iReturn = pdTRUE; + } + else + { + iReturn = pdFALSE; + } + } + else + { + iReturn = pdFALSE; + } + return iReturn; +} + +void FF_Assert_Lock( FF_IOManager_t *pxIOManager, uint32_t aBits ) +{ + void *handle = xTaskGetCurrentTaskHandle(); + + if( ( aBits & FF_FAT_LOCK_EVENT_BITS ) != 0 ) + { + configASSERT( ( pxIOManager->pvFATLockHandle != NULL ) && ( pxIOManager->pvFATLockHandle == handle ) ); + + /* In case configASSERT() is not defined. */ + ( void ) pxIOManager; + ( void ) handle; + } +} + +void FF_LockFAT( FF_IOManager_t *pxIOManager ) +{ +EventBits_t xBits; + + configASSERT( FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE ); + + for( ;; ) + { + /* Called when a task want to make changes to the FAT area. + First it waits for the desired bit to come high. */ + xEventGroupWaitBits( pxIOManager->xEventGroup, + FF_FAT_LOCK_EVENT_BITS, /* uxBitsToWaitFor */ + ( EventBits_t )0, /* xClearOnExit */ + pdFALSE, /* xWaitForAllBits n.a. */ + pdMS_TO_TICKS( 10000UL ) ); + + /* The next operation will only succeed for 1 task at a time, + because it is an atomary test & set operation: */ + xBits = xEventGroupClearBits( pxIOManager->xEventGroup, FF_FAT_LOCK_EVENT_BITS ); + + if( ( xBits & FF_FAT_LOCK_EVENT_BITS ) != 0 ) + { + /* This task has cleared the desired bit. + It now 'owns' the resource. */ + pxIOManager->pvFATLockHandle = xTaskGetCurrentTaskHandle(); + break; + } + } +} +/*-----------------------------------------------------------*/ + +void FF_UnlockFAT( FF_IOManager_t *pxIOManager ) +{ + configASSERT( ( xEventGroupGetBits( pxIOManager->xEventGroup ) & FF_FAT_LOCK_EVENT_BITS ) == 0 ); + pxIOManager->pvFATLockHandle = NULL; + xEventGroupSetBits( pxIOManager->xEventGroup, FF_FAT_LOCK_EVENT_BITS ); +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_BufferWait( FF_IOManager_t *pxIOManager, uint32_t xWaitMS ) +{ +EventBits_t xBits; +BaseType_t xReturn; + + /* This function is called when a task is waiting for a sector buffer + to become available. */ + xBits = xEventGroupWaitBits( pxIOManager->xEventGroup, + FF_BUF_LOCK_EVENT_BITS, /* uxBitsToWaitFor */ + FF_BUF_LOCK_EVENT_BITS, /* xClearOnExit */ + pdFALSE, /* xWaitForAllBits n.a. */ + pdMS_TO_TICKS( xWaitMS ) ); + if( ( xBits & FF_BUF_LOCK_EVENT_BITS ) != 0 ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void FF_BufferProceed( FF_IOManager_t *pxIOManager ) +{ + /* Wake-up all tasks that are waiting for a sector buffer to become available. */ + xEventGroupSetBits( pxIOManager->xEventGroup, FF_BUF_LOCK_EVENT_BITS ); +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_memory.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_memory.c new file mode 100644 index 000000000..d8ce5bd71 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_memory.c @@ -0,0 +1,108 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_memory.c + * @ingroup MEMORY + * + * @defgroup MEMORY FreeRTOS+FAT Memory Access Routines + * @brief Handles memory access in a portable way. + * + * Provides simple, fast, and portable access to memory routines. + * These are only used to read data from buffers. That are LITTLE ENDIAN + * due to the FAT specification. + * + * These routines may need to be modified to your platform. + * + **/ + +#include "ff_headers.h" + +/* + * Here below 3 x 2 access functions that allow the code + * not to worry about the endianness of the MCU. + */ + + +#if( ffconfigINLINE_MEMORY_ACCESS == 0 ) + +uint8_t FF_getChar( const uint8_t *pBuffer, uint32_t aOffset ) +{ + return ( uint8_t ) ( pBuffer[ aOffset ] ); +} + +uint16_t FF_getShort( const uint8_t *pBuffer, uint32_t aOffset ) +{ +FF_T_UN16 u16; + + pBuffer += aOffset; + u16.bytes.u8_1 = pBuffer[ 1 ]; + u16.bytes.u8_0 = pBuffer[ 0 ]; + + return u16.u16; +} + +uint32_t FF_getLong( const uint8_t *pBuffer, uint32_t aOffset ) +{ +FF_T_UN32 u32; + + pBuffer += aOffset; + u32.bytes.u8_3 = pBuffer[ 3 ]; + u32.bytes.u8_2 = pBuffer[ 2 ]; + u32.bytes.u8_1 = pBuffer[ 1 ]; + u32.bytes.u8_0 = pBuffer[ 0 ]; + + return u32.u32; +} + +void FF_putChar( uint8_t *pBuffer, uint32_t aOffset, uint32_t Value ) +{ + pBuffer[ aOffset ] = ( uint8_t ) Value; +} + +void FF_putShort( uint8_t *pBuffer, uint32_t aOffset, uint32_t Value ) +{ +FF_T_UN16 u16; + + u16.u16 = ( uint16_t ) Value; + pBuffer += aOffset; + pBuffer[ 0 ] = u16.bytes.u8_0; + pBuffer[ 1 ] = u16.bytes.u8_1; +} + +void FF_putLong( uint8_t *pBuffer, uint32_t aOffset, uint32_t Value ) +{ +FF_T_UN32 u32; + + u32.u32 = Value; + pBuffer += aOffset; + pBuffer[ 0 ] = u32.bytes.u8_0; + pBuffer[ 1 ] = u32.bytes.u8_1; + pBuffer[ 2 ] = u32.bytes.u8_2; + pBuffer[ 3 ] = u32.bytes.u8_3; +} + +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_stdio.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_stdio.c new file mode 100644 index 000000000..36a3ee065 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_stdio.c @@ -0,0 +1,2028 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "portable.h" + +/* FreeRTOS+FAT includes. */ +#include "ff_headers.h" +#include "ff_stdio.h" + +#if( ffconfigTIME_SUPPORT != 0 ) + #include +#endif + + +#ifndef SIZE_MAX + #define SIZE_MAX ( ( size_t ) -1 ) +#endif + +/* The number of bytes to write at a time when extending the length of a file +in a call to ff_truncate(). */ +#define stdioTRUNCATE_WRITE_LENGTH 512 + +/* Bits set to indicate whether ".." should be included as well as ".". */ +#define stdioDIR_ENTRY_DOT_1 ( 1U & 0x03U ) +#define stdioDIR_ENTRY_DOT_2 ( 2U & 0x03U ) + +/* The directory entries '.' and '..' will show a file size of 1 KB. */ +#define stdioDOT_ENTRY_FILE_SIZE 1024 + +/*-----------------------------------------------------------*/ + +#if( ffconfigHAS_CWD == 1 ) + + /* FreeRTOS+FAT requires two thread local storage pointers. One for errno + and one for the CWD structure. */ + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS < 2 ) + #error FreeRTOS+FAT requires two thread local storage pointers so configNUM_THREAD_LOCAL_STORAGE_POINTERS must be at least 2 in FreeRTOSConfig.h + #endif + + /* Each task has its own Current Working Directory (CWD). The CWD is used + to extend relative paths to absolute paths. */ + typedef struct WORKING_DIR + { + char pcCWD[ ffconfigMAX_FILENAME ]; /* The current working directory. */ + char pcFileName[ ffconfigMAX_FILENAME ]; /* The created absolute path. */ + } WorkingDirectory_t; + + /* + * Add the CWD to the beginning of a relative path, and copy the resultant + * absolute path into a thread local non const buffer. + */ + /*static*/ const char *prvABSPath( const char *pcPath ); + + /* + * Lookup the CWD of the current task. + */ + static WorkingDirectory_t *pxFindCWD( void ); + + /* + * Convert a string which may contain a relative path into a string that + * will only contain an absolute path. + */ + static const char *prvProcessRelativePaths( const char *pcPath ); + +#else /* ffconfigHAS_CWD */ + + /* FreeRTOS+FAT requires one thread local storage pointers for errno. */ + #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS < 2 ) + #error FreeRTOS+FAT requires one thread local storage pointers so configNUM_THREAD_LOCAL_STORAGE_POINTERS must be at least 1 in FreeRTOSConfig.h + #endif + + /* Only absolute paths are supported so define away the prvABSPath() + function. */ + /*static*/ const char *prvABSPath( const char *pcPath ) + { + return pcPath; + } + +#endif /* ffconfigHAS_CWD */ + + +#if( ffconfigUSE_DELTREE != 0 ) + /* + * Remove all files and directories starting from a certain path. + * This function uses recursion - which breaches the coding standard. USE + * WITH CARE. + */ + static int ff_deltree_recurse( char *pcPath ); +#endif + +/* + * Translate a +FAT error to a value compatible with errno.h + * If the value represents an error, it is negative + * The return value of this function will always be positive + */ +int prvFFErrorToErrno( FF_Error_t xError ); + +/* + * Generate a time stamp for the file. + */ +#if( ffconfigTIME_SUPPORT == 1 ) + static uint32_t prvFileTime( FF_SystemTime_t *pxTime ); +#endif + +/*-----------------------------------------------------------*/ + +FF_FILE *ff_fopen( const char *pcFile, const char *pcMode ) +{ +FF_FILE *pxStream = NULL; +FF_DirHandler_t xHandler; +FF_Error_t xError; +uint8_t ucMode; + + /* Insert the current working directory in front of relative paths. */ + pcFile = prvABSPath( pcFile ); + + /* Look-up the I/O manager for the file system. */ + if( FF_FS_Find( pcFile, &xHandler ) == pdFALSE ) + { + stdioSET_ERRNO( pdFREERTOS_ERRNO_ENXIO ); /* No such device or address. */ + } + else + { + /* Now 'xHandler.pcPath' contains an absolute path within the file system. + Translate a type string "r|w|a[+]" to +FAT's mode bits. */ + ucMode = FF_GetModeBits( pcMode ); + + pxStream = FF_Open( xHandler.pxManager, xHandler.pcPath, ucMode, &xError ); + stdioSET_ERRNO( prvFFErrorToErrno( xError ) ); + + #if( ffconfigUSE_NOTIFY != 0 ) + { + if( ( pxStream != NULL ) && ( ( ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND ) ) != 0 ) ) + { + /*_RB_ Function name needs updating. */ + callFileEvents( pcFile, eFileCreate ); + } + } + #endif /* ffconfigUSE_NOTIFY */ + + #if( ffconfigDEV_SUPPORT != 0 ) + { + if( pxStream != NULL ) + { + FF_Device_Open( pcFile, pxStream ); + } + } + #endif /* ffconfigDEV_SUPPORT */ + } + + return pxStream; +} +/*-----------------------------------------------------------*/ + +int ff_fclose( FF_FILE *pxStream ) +{ +FF_Error_t xError; +int iReturn, ff_errno; + + #if( ffconfigDEV_SUPPORT != 0 ) + { + /* Currently device support is in an experimental state. It will allow + to create virtual files. The I/O data to those files will be redirected + to their connected "drivers". */ + if( pxStream != NULL ) + { + FF_Device_Close( pxStream ); + } + } + #endif + + xError = FF_Close( pxStream ); + ff_errno = prvFFErrorToErrno( xError ); + + if( ff_errno == 0 ) + { + iReturn = 0; + } + else + { + /* Return -1 for error as per normal fclose() semantics. */ + iReturn = -1; + } + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( ff_errno ); + + return iReturn; +} +/*-----------------------------------------------------------*/ + +int ff_fseek( FF_FILE *pxStream, long lOffset, int iWhence ) +{ +FF_Error_t xError; +int iReturn, ff_errno; + +#if( ffconfigDEV_SUPPORT != 0 ) + if( pxStream->pxDevNode != NULL ) + { + xError = FF_Device_Seek( pxStream, lOffset, iWhence ); + } + else +#endif + { + xError = FF_Seek( pxStream, lOffset, iWhence ); + } + + ff_errno = prvFFErrorToErrno( xError ); + + if( ff_errno == 0 ) + { + iReturn = 0; + } + else + { + if( xError == FF_ERR_FILE_SEEK_INVALID_POSITION ) + { + /* Illegal position, outside the file's space */ + ff_errno = pdFREERTOS_ERRNO_ESPIPE; + } + else if( xError == FF_ERR_FILE_SEEK_INVALID_ORIGIN ) + { + /* Illegal parameter value for iWhence: SET,CUR,END. */ + ff_errno = pdFREERTOS_ERRNO_EINVAL; + } + + /* Return -1 for error as per normal fseek() semantics. */ + iReturn = -1; + } + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( ff_errno ); + + return iReturn; +} +/*-----------------------------------------------------------*/ + +void ff_rewind( FF_FILE *pxStream ) +{ + ff_fseek( pxStream, 0, FF_SEEK_SET ); + + /* Rewind is supposed to reset errno unconditionally. Store the errno to + thread local storage. */ + stdioSET_ERRNO( 0 ); +} +/*-----------------------------------------------------------*/ + +long ff_ftell( FF_FILE *pxStream ) +{ +long lResult; + + if( pxStream == NULL ) + { + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( pdFREERTOS_ERRNO_EBADF ); + + /* Return -1 for error as per normal ftell() semantics. */ + lResult = -1; + } + else + { + lResult = ( long ) pxStream->ulFilePointer; + } + + return lResult; +} +/*-----------------------------------------------------------*/ + +int ff_feof( FF_FILE *pxStream ) +{ +int iResult; +FF_Error_t xError; + + xError = FF_CheckValid( pxStream ); + if( FF_isERR( xError ) == pdFALSE ) + { + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( 0 ); + if( pxStream->ulFilePointer >= pxStream->ulFileSize ) + { + iResult = pdTRUE; + } + else + { + iResult = pdFALSE; + } + } + else + { + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( prvFFErrorToErrno( xError ) ); + + /* The file was invalid so a non-zero value cannot be returned. */ + iResult = pdFALSE; + } + + return iResult; +} +/*-----------------------------------------------------------*/ + +size_t ff_fread( void *pvBuffer, size_t xSize, size_t xItems, FF_FILE * pxStream ) +{ +int32_t iReturned; +size_t xReturn; +int ff_errno; + +#if( ffconfigDEV_SUPPORT != 0 ) + if( pxStream->pxDevNode != NULL ) + { + iReturned = FF_Device_Read( pvBuffer, xSize, xItems, pxStream ); + } + else +#endif + { + iReturned = FF_Read( pxStream, xSize, xItems, (uint8_t *)pvBuffer ); + } + + ff_errno = prvFFErrorToErrno( iReturned ); + + if( ff_errno == pdFREERTOS_ERRNO_NONE ) + { + /* As per the standard fread() semantics, the return value is the number + of complete items read, which will only equal the number of bytes + transferred when the item size is 1. */ + xReturn = ( size_t ) iReturned; + } + else + { + xReturn = 0; + } + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( ff_errno ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +size_t ff_fwrite( const void *pvBuffer, size_t xSize, size_t xItems, FF_FILE * pxStream ) +{ +int32_t iReturned; +size_t xReturn; +int ff_errno; + +#if( ffconfigDEV_SUPPORT != 0 ) + if( pxStream->pxDevNode != NULL ) + { + iReturned = FF_Device_Write( pvBuffer, xSize, xItems, pxStream ); + } + else +#endif + { + iReturned = FF_Write( pxStream, xSize, xItems, (uint8_t *)pvBuffer ); + } + + ff_errno = prvFFErrorToErrno( iReturned ); + + if( ff_errno == pdFREERTOS_ERRNO_NONE ) + { + /* As per the standard fwrite() semantics, the return value is the + number of complete items read, which will only equal the number of bytes + transferred when the item size is 1. */ + xReturn = ( size_t ) iReturned; + } + else + { + xReturn = 0; + } + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( ff_errno ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +int ff_fgetc( FF_FILE * pxStream ) +{ +int32_t iResult; +int ff_errno; + + iResult = FF_GetC( pxStream ); + ff_errno = prvFFErrorToErrno( iResult ); + + if( ff_errno != 0 ) + { + iResult = FF_EOF; + } + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( ff_errno ); + + return iResult; +} +/*-----------------------------------------------------------*/ + +int ff_fputc( int iChar, FF_FILE *pxStream ) +{ +int iResult, ff_errno; + + iResult = FF_PutC( pxStream, ( uint8_t ) iChar ); + ff_errno = prvFFErrorToErrno( iResult ); + + if( ff_errno != 0 ) + { + iResult = FF_EOF; + } + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( ff_errno ); + + return iResult; +} +/*-----------------------------------------------------------*/ + +#if( ffconfigFPRINTF_SUPPORT == 1 ) + + int ff_fprintf( FF_FILE * pxStream, const char *pcFormat, ... ) + { + int iCount; + size_t xResult; + char *pcBuffer; + va_list xArgs; + + pcBuffer = ( char * ) ffconfigMALLOC( ffconfigFPRINTF_BUFFER_LENGTH ); + if( pcBuffer == NULL ) + { + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( pdFREERTOS_ERRNO_ENOMEM ); + iCount = -1; + } + else + { + va_start( xArgs, pcFormat ); + iCount = vsnprintf( pcBuffer, ffconfigFPRINTF_BUFFER_LENGTH, pcFormat, xArgs ); + va_end( xArgs ); + + /* ff_fwrite() will set ff_errno. */ + if( iCount > 0 ) + { + xResult = ff_fwrite( pcBuffer, ( size_t ) 1, ( size_t ) iCount, pxStream ); + if( xResult < ( size_t ) iCount ) + { + iCount = -1; + } + } + + ffconfigFREE( pcBuffer ); + } + + return iCount; + } + +#endif +/*-----------------------------------------------------------*/ + +/*_RB_ to comply with the norm, the second parameter should be an int, but size_t +is more appropriate. */ +char *ff_fgets( char *pcBuffer, size_t xCount, FF_FILE *pxStream ) +{ +int32_t xResult; +int ff_errno; + + xResult = FF_GetLine( pxStream, ( char * ) pcBuffer, xCount ); + + /* This call seems to result in errno being incorrectly set to + FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION when an EOF is encountered. */ + ff_errno = prvFFErrorToErrno( xResult ); + + if( ff_errno != 0 ) + { + pcBuffer = NULL; + } + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( ff_errno ); + + return pcBuffer; +} +/*-----------------------------------------------------------*/ + +int ff_seteof( FF_FILE *pxStream ) +{ +FF_Error_t iResult; +int iReturn, ff_errno; + + iResult = FF_SetEof( pxStream ); + + ff_errno = prvFFErrorToErrno( iResult ); + + if( ff_errno == 0 ) + { + iReturn = 0; + } + else + { + iReturn = FF_EOF; + } + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( ff_errno ); + + return iReturn; +} +/*-----------------------------------------------------------*/ + +/*_RB_ The norm would be to return an int, but in either case it is not clear +what state the file is left in (open/closed). */ +FF_FILE *ff_truncate( const char * pcFileName, long lTruncateSize ) +{ +FF_Error_t xResult = 0; +FF_FILE *pxStream; +size_t xReturned; +uint32_t ulLength, ulBytesLeftToAdd, ulBytesToWrite; +char *pcBufferToWrite; + + pxStream = ff_fopen( pcFileName, "a+"); + + if( pxStream != NULL ) + { + ulLength = pxStream->ulFileSize; + } + else + { + ulLength = 0; + } + + if( pxStream == NULL ) + { + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( prvFFErrorToErrno( xResult ) ); + } + else if( ulLength > ( uint32_t ) lTruncateSize ) + { + /* Seek the desired position */ + xResult = FF_Seek( pxStream, lTruncateSize, FF_SEEK_SET ); + + /* Make the current position equal to its length */ + if( FF_isERR( xResult ) == pdFALSE ) + { + xResult = FF_SetEof( pxStream ); + } + + if( FF_isERR( xResult ) != pdFALSE ) + { + ff_fclose( pxStream ); + pxStream = NULL; + } + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( prvFFErrorToErrno( xResult ) ); + } + else if( ulLength == ( uint32_t ) lTruncateSize ) + { + /* Nothing to do, the file has the desired size + and the open handle will be returned. */ + } + else + { + /* lTruncateSize > ulLength. The user wants to open this file with a + larger size than it currently has. Fill it with zeros. */ + pcBufferToWrite = ( char * ) ffconfigMALLOC( stdioTRUNCATE_WRITE_LENGTH ); + + if( pcBufferToWrite == NULL ) + { + ff_fclose( pxStream ); + pxStream = NULL; + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( pdFREERTOS_ERRNO_ENOMEM ); + } + else + { + /* File has to grow */ + ulBytesLeftToAdd = ( ( uint32_t ) lTruncateSize ) - ulLength; + + /* Zeros must be written. */ + memset( pcBufferToWrite, '\0', stdioTRUNCATE_WRITE_LENGTH ); + + while( ulBytesLeftToAdd > 0UL ) + { + if( ( pxStream->ulFileSize % stdioTRUNCATE_WRITE_LENGTH ) != 0 ) + { + /* Although +FAT's FF_Write() can handle any size at any + offset, the driver puts data more efficiently if blocks are + written at block boundaries. */ + ulBytesToWrite = stdioTRUNCATE_WRITE_LENGTH - ( pxStream->ulFileSize % stdioTRUNCATE_WRITE_LENGTH ); + + if( ulBytesToWrite > ulBytesLeftToAdd ) + { + ulBytesToWrite = ulBytesLeftToAdd; + } + } + else + { + ulBytesToWrite = ulBytesLeftToAdd; + + if( ulBytesToWrite > stdioTRUNCATE_WRITE_LENGTH ) + { + ulBytesToWrite = stdioTRUNCATE_WRITE_LENGTH; + } + } + + xReturned = ff_fwrite( pcBufferToWrite, sizeof( char ), ulBytesToWrite, pxStream ); + + if( xReturned != ( size_t ) ulBytesToWrite ) + { + /* Write error. Close the stream and set the proper . + errno. */ + ff_fclose( pxStream ); + pxStream = NULL; + + /* Not setting ff_errno because it has been set by other + functions from this ff_stdio. */ + + break; + } + + ulBytesLeftToAdd -= ulBytesToWrite; + } + + ffconfigFREE( pcBufferToWrite ); + } + } + + return pxStream; +} +/*-----------------------------------------------------------*/ + +#if( ffconfigMKDIR_RECURSIVE == 0 ) + + /* The normal mkdir() : if assumes that the directories leading to the last + element of pcDirectory already exists. For instance: mkdir( "/a/b/c" ) will + succeed if the path "/a/b" already exists. */ + int ff_mkdir( const char *pcDirectory ) + { + int iResult, ff_errno; + FF_DirHandler_t xHandler; + + /* In case a CWD is used, get the absolute path. */ + pcDirectory = prvABSPath( pcDirectory ); + + /* Find the i/o manager for this path */ + if( FF_FS_Find( pcDirectory, &xHandler ) == pdFALSE ) + { + /* No such device or address. */ + stdioSET_ERRNO( pdFREERTOS_ERRNO_ENXIO ); + /* Return -1 for error as per normal mkdir() semantics. */ + iResult = -1; + } + else + { + /* A simple non-recursive make of a directory. */ + iResult = FF_MkDir( xHandler.pxManager, xHandler.pcPath ); + + if( FF_GETERROR( iResult ) == FF_ERR_DIR_OBJECT_EXISTS ) + { + /* No error if the target directory already exists. */ + iResult = FF_ERR_NONE; + } + ff_errno = prvFFErrorToErrno( iResult ); + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( ff_errno ); + + if( ff_errno == pdFREERTOS_ERRNO_NONE ) + { + iResult = 0; + } + else + { + /* Return -1 for error as per normal mkdir() semantics. */ + iResult = -1; + } + } + + return iResult; + } +#else /* ffconfigMKDIR_RECURSIVE */ + + #warning This path is not yet included in the regression tests. + + /* The 'recursive mkdir() : if the parameter 'xRecursive' is non-zero, + the function will try to create the complete path. */ + int ff_mkdir( const char *pcDirectory, int xRecursive ) + { + int32_t lResult; + FF_DirHandler_t xHandler; + + /* In case a CWD is used, get the absolute path. */ + pcDirectory = prvABSPath( pcDirectory ); + + /* Find the i/o manager for this path */ + if( FF_FS_Find( pcDirectory, &xHandler ) == pdFALSE ) + { + /* No such device or address. Store the errno to thread local + storage. */ + stdioSET_ERRNO( pdFREERTOS_ERRNO_ENXIO ); + /* Return -1 for error as per normal mkdir() semantics. */ + lResult = -1; + } + else + { + if( xRecursive == pdFALSE ) + { + /* A simple non-recursive make of a directory. */ + lResult = FF_MkDir( xHandler.pxManager, xHandler.pcPath ); + + if( FF_GETERROR( lResult ) == FF_ERR_DIR_OBJECT_EXISTS ) + { + /* No error if the target directory already exists. */ + lResult = 0; + } + } + else + { + /* The recursive option is used. */ + char pcTempPath[ffconfigMAX_FILENAME]; + FF_Error_t errCode; + int iLength = snprintf( pcTempPath, sizeof( pcTempPath ), "%s", xHandler.pcPath ); + char *pcPtr = pcTempPath + 1, *pcPrev; + const char *pcLast = pcTempPath + iLength; + + lResult = FF_ERR_NONE; + + for( ; ; ) + { + for ( pcPrev = pcPtr; pcPtr < pcLast; pcPtr++ ) + { + if( *pcPtr == '/' ) + { + *pcPtr = '\0'; + break; + } + } + + if( pcPrev == pcPtr ) + { + break; + } + + errCode = FF_MkDir( xHandler.pxManager, pcTempPath ); + + if( FF_isERR( errCode ) && FF_GETERROR( errCode ) != FF_ERR_DIR_OBJECT_EXISTS ) + { + lResult = errCode; + break; + } + + if( pcPtr >= ( pcLast - 1 ) ) + { + break; + } + + *( pcPtr++ ) = '/'; + } + } + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( prvFFErrorToErrno( lResult ) ); + } + + return lResult; + } +#endif /* ffconfigMKDIR_RECURSIVE */ +/*-----------------------------------------------------------*/ + +int ff_rmdir( const char *pcDirectory ) +{ +int32_t lResult; +int iReturn, ff_errno; +FF_DirHandler_t xHandler; + + /* In case a CWD is used, get the absolute path */ + pcDirectory = prvABSPath( pcDirectory ); + + /* Find the i/o manager which can handle this path. */ + if( FF_FS_Find( pcDirectory, &xHandler ) == pdFALSE ) + { + ff_errno = pdFREERTOS_ERRNO_ENXIO; /* No such device or address */ + + /* Return -1 for error as per normal rmdir() semantics. */ + iReturn = -1; + } + else + { + lResult = FF_RmDir( xHandler.pxManager, xHandler.pcPath ); + ff_errno = prvFFErrorToErrno( lResult ); + + if( ff_errno == 0 ) + { + iReturn = 0; + } + else + { + /* Return -1 for error as per normal rmdir() semantics. */ + iReturn = -1; + } + } + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( ff_errno ); + + return iReturn; +} +/*-----------------------------------------------------------*/ + +int ff_remove( const char *pcPath ) +{ +FF_DirHandler_t xHandler; +FF_Error_t xError; +int iReturn, ff_errno; + + /* In case a CWD is used, get the absolute path */ + pcPath = prvABSPath( pcPath ); + + /* Find the i/o manager which can handle this path. */ + if( FF_FS_Find( pcPath, &xHandler ) == pdFALSE ) + { + /* No such device or address */ + ff_errno = pdFREERTOS_ERRNO_ENXIO; + + /* Return -1 for error as per normal remove() semantics. */ + iReturn = -1; + } + else + { + xError = FF_RmFile( xHandler.pxManager, xHandler.pcPath ); + ff_errno = prvFFErrorToErrno( xError ); + + #if ffconfigUSE_NOTIFY + { + if( FF_isERR( xError ) == pdFALSE ) + { + callFileEvents( pcPath, eFileRemove ); + } + } + #endif + + if( ff_errno == 0 ) + { + iReturn = 0; + } + else + { + /* Return -1 for error as per normal remove() semantics. */ + iReturn = -1; + } + } + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( ff_errno ); + return iReturn; +} +/*-----------------------------------------------------------*/ +/*_RB_ Last parameter not documented. */ +int ff_rename( const char *pcOldName, const char *pcNewName, int bDeleteIfExists ) +{ +FF_DirHandler_t xHandlers[ 2 ]; +FF_Error_t xError = FF_ERR_NONE; +int ff_errno = 0, iReturn; +#if( ffconfigHAS_CWD != 0 ) + char *pcOldCopy; + size_t xSize; +#endif + + /* In case a CWD is used, get the absolute path */ + pcOldName = prvABSPath( pcOldName ); + + /* Find the i/o manager which can handle this path */ + if( FF_FS_Find( pcOldName, &xHandlers[ 0 ] ) == pdFALSE ) + { + xError = ( int32_t ) ( FF_ERR_NULL_POINTER | FF_MOVE ); + ff_errno = pdFREERTOS_ERRNO_ENXIO; /* No such device or address */ + } + else + { + #if( ffconfigHAS_CWD != 0 ) + { + xSize = strlen( xHandlers[0].pcPath ) + 1; + pcOldCopy = ( char *)ffconfigMALLOC( xSize ); + + if( pcOldCopy == NULL ) + { + /* Could not allocate space to store a file name. */ + ff_errno = pdFREERTOS_ERRNO_ENOMEM; + xError = ( int32_t ) ( FF_ERR_NOT_ENOUGH_MEMORY | FF_MOVE ); + } + else + { + /* The function prvABSPath() returns a pointer to the task + storage space. Rename needs to call it twice and therefore the + path must be stored before it gets overwritten. */ + memcpy( pcOldCopy, xHandlers[0].pcPath, xSize ); + xHandlers[0].pcPath = pcOldCopy; + } + } + #endif /* ffconfigHAS_CWD != 0 */ + +#if( ffconfigHAS_CWD != 0 ) + if( pcOldCopy != NULL ) +#endif /* ffconfigHAS_CWD != 0 */ + { + pcNewName = prvABSPath( pcNewName ); + + /* Find the i/o manager which can handle this path */ + if( FF_FS_Find( pcNewName, &( xHandlers[ 1 ] ) ) == pdFALSE ) + { + xError = ( int32_t ) ( FF_ERR_NULL_POINTER | FF_MOVE ); + ff_errno = pdFREERTOS_ERRNO_ENXIO; /* No such device or address */ + } + else if( xHandlers[ 0 ].pxManager != xHandlers[ 1 ].pxManager ) + { + xError = ( int32_t ) ( FF_ERR_NULL_POINTER | FF_MOVE ); + /* Cross-device link, which can not be done. */ + ff_errno = pdFREERTOS_ERRNO_EXDEV; + } + else + { + xError = FF_Move( xHandlers[ 0 ].pxManager, xHandlers[ 0 ].pcPath, xHandlers[ 1 ].pcPath, bDeleteIfExists ); + + ff_errno = prvFFErrorToErrno( xError ); + + #if ffconfigUSE_NOTIFY + { + if( FF_isERR( xError ) == pdFALSE ) + { + callFileEvents( pcNewName, eFileChange ); + } + } + #endif + } + + #if( ffconfigHAS_CWD != 0 ) + { + ffconfigFREE( pcOldCopy ); + } + #endif + } + } + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( ff_errno ); + + if( ff_errno == 0 ) + { + iReturn = 0; + } + else + { + /* Return -1 for error as per normal rmdir() semantics. */ + iReturn = -1; + } + + return iReturn; +} +/*-----------------------------------------------------------*/ + +int ff_stat( const char *pcName, FF_Stat_t *pxStatBuffer ) +{ +FF_DirEnt_t xDirEntry; +uint32_t ulFileCluster; +FF_Error_t xError; +int iResult; +FF_DirHandler_t xHandler; +BaseType_t xIndex; +FF_FindParams_t xFindParams; +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + const FF_T_WCHAR *pcFileName = NULL; +#else + /* Initialised to prevent MSVC incorrectly claiming the variable is used + without being initialised. */ + const char *pcFileName = NULL; +#endif + + memset( &xFindParams, '\0', sizeof( xFindParams ) ); + + /* Insert the current working directory in front of relative paths. */ + pcName = prvABSPath( pcName ); + + /* Look-up the I/O manager for the file system. */ + if( FF_FS_Find( pcName, &xHandler ) == pdFALSE ) + { + /* No such device or address. */ + xError = ( FF_Error_t ) ( pdFREERTOS_ERRNO_ENXIO | FF_STAT_FUNC ); + } + else + { + xError = FF_ERR_NONE; + pcName = xHandler.pcPath; + + /* Let xIndex point to the last occurrence of '/' or '\', to separate + the path from the file name. */ + xIndex = ( BaseType_t ) STRLEN( pcName ); + while( xIndex != 0 ) + { + if( ( pcName[ xIndex ] == '\\' ) || ( pcName[ xIndex ] == '/' ) ) + { + break; + } + + xIndex--; + } + + /* Copy the file name, i.e. the string that comes after the last + separator. */ + pcFileName = pcName + xIndex + 1; + + if( xIndex == 0 ) + { + /* Only for the root, the slash is part of the directory name. + 'xIndex' now equals to the length of the path name. */ + xIndex = 1; + } + + /* FF_CreateShortName() might set flags FIND_FLAG_FITS_SHORT and + FIND_FLAG_SIZE_OK. */ + FF_CreateShortName( &xFindParams, pcFileName ); + + /* Lookup the path and find the cluster pointing to the directory: */ + xFindParams.ulDirCluster = FF_FindDir( xHandler.pxManager, pcName, xIndex, &xError ); + } + + if( FF_isERR( xError ) == pdFALSE ) + { + /* See if the file does exist within the given directory. */ + ulFileCluster = FF_FindEntryInDir( xHandler.pxManager, &xFindParams, pcFileName, 0x00, &xDirEntry, &xError ); + + if( ulFileCluster == 0ul ) + { + /* If cluster 0 was returned, it might be because the file has no allocated cluster, + i.e. only a directory entry and no stored data. */ + if( STRLEN( pcFileName ) == STRLEN( xDirEntry.pcFileName ) ) + { + if( ( xDirEntry.ulFileSize == 0 ) && ( FF_strmatch( pcFileName, xDirEntry.pcFileName, ( BaseType_t ) STRLEN( pcFileName ) ) == pdTRUE ) ) + { + /* It is the file, give it a pseudo cluster number '1'. */ + ulFileCluster = 1; + /* And reset any error. */ + xError = FF_ERR_NONE; + } + } + } + + /* Test 'ulFileCluster' again, it might have been changed. */ + if( ulFileCluster == 0ul ) + { + xError = FF_ERR_FILE_NOT_FOUND | FF_STAT_FUNC; + } + } + + if( ( pxStatBuffer != NULL ) && ( FF_isERR( xError ) == pdFALSE ) ) + { + if( ( xDirEntry.ucAttrib & FF_FAT_ATTR_DIR ) != 0 ) + { + pxStatBuffer->st_mode = ( unsigned short ) FF_IFDIR; + } + else + { + pxStatBuffer->st_mode = ( unsigned short ) FF_IFREG; + } + + #if( ffconfigDEV_SUPPORT != 0 ) + { + BaseType_t bIsDeviceDir = xCheckDevicePath( pcFileName ); + + if( bIsDeviceDir != pdFALSE ) + { + FF_Device_GetDirEnt( xHandler.pcPath, &( xDirEntry ) ); + } + } + #endif + + /* Despite the warning output by MSVC - it is not possible to get here + if xDirEntry has not been initialised. */ + pxStatBuffer->st_size = xDirEntry.ulFileSize; + pxStatBuffer->st_ino = xDirEntry.ulObjectCluster; + pxStatBuffer->st_dev = ( short ) xHandler.xFSIndex; + + #if( ffconfigTIME_SUPPORT == 1 ) + { + pxStatBuffer->st_atime = ( unsigned long ) prvFileTime( &( xDirEntry.xAccessedTime ) ); + pxStatBuffer->st_mtime = ( unsigned long ) prvFileTime( &( xDirEntry.xModifiedTime ) ); + pxStatBuffer->st_ctime = ( unsigned long ) prvFileTime( &( xDirEntry.xCreateTime ) ); + } + #endif + } + + stdioSET_ERRNO( prvFFErrorToErrno( xError ) ); + + if( FF_isERR( xError ) == pdFALSE ) + { + iResult = 0; + } + else + { + iResult = -1; + } + + return iResult; +} /* ff_stat() */ +/*-----------------------------------------------------------*/ + +#if( ffconfigHAS_CWD == 1 ) + + int ff_chdir( const char *pcDirectoryName ) + { + int iResult, iLength, iValid = pdFALSE; + WorkingDirectory_t *pxDir = NULL; + + /* Not all paths set an errno. */ + stdioSET_ERRNO( 0 ); + + /* Is there a file system mounted? */ + if( FF_FS_Count() != 0 ) + { + /* In case a CWD is used, get the absolute path. */ + pcDirectoryName = prvABSPath( pcDirectoryName ); + pxDir = pxFindCWD(); + + if( pxDir == NULL ) + { + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( pdFREERTOS_ERRNO_ENOMEM ); + + /* Return -1 for error as per normal chdir() semantics. */ + iResult = -1; + } + else + { + /* The CWD will be stored without a trailing '/'. If "/" + happens to be the CWD, it will be stored as an empty string. */ + iLength = strlen( pcDirectoryName ); + + /* Knock off the trailing / if one exits - being careful not to + remove the trailing slash if this is the root directory. */ + if( ( iLength > 1 ) && ( pxDir->pcFileName[ iLength - 1 ] == '/' ) ) + { + pxDir->pcFileName[ iLength - 1 ] = '\0'; + } + + stdioSET_ERRNO( pdFREERTOS_ERRNO_ENOENT ); + + /* Does the directory exist? */ + if( strcmp( pcDirectoryName, "/" ) == 0 ) + { + /* Moving to the root - which exists. */ + iValid = pdTRUE; + } + else if( ff_finddir( pxDir->pcFileName ) != pdFALSE ) + { + iValid = pdTRUE; + } + } + } + + if( iValid == pdTRUE ) + { + /* The generated name becomes the CWD. No need to test for overflow + as pcPath and pcFileName are the same size. */ + strcpy( pxDir->pcCWD, pxDir->pcFileName ); + + /* chdir returns 0 for success. */ + iResult = FF_ERR_NONE; + } + else + { + /* Return -1 for error as per normal chdir() semantics. */ + iResult = -1; + } + + return iResult; + } + +#endif /* ffconfigHAS_CWD == 1 */ +/*-----------------------------------------------------------*/ + +#if( ffconfigHAS_CWD == 1 ) + + char *ff_getcwd( char *pcBuffer, size_t xBufferLength ) + { + WorkingDirectory_t *pxDir = pxFindCWD(); + + stdioSET_ERRNO( 0 ); + + if( ( pxDir == NULL ) || ( pxDir->pcCWD[0] == '\0' ) ) + { + if( xBufferLength > strlen( "/" ) ) + { + strncpy( pcBuffer, "/", xBufferLength ); + } + else + { + pcBuffer = NULL; + } + } + else + { + if( strlen( pxDir->pcCWD ) < xBufferLength ) + { + strncpy( pcBuffer, pxDir->pcCWD, xBufferLength ); + } + else + { + pcBuffer = NULL; + } + } + + return pcBuffer; + } + +#endif /* ffconfigHAS_CWD */ +/*-----------------------------------------------------------*/ + +int ff_findfirst( const char *pcPath, FF_FindData_t *pxFindData ) +{ +int iIsRootDir, iReturn; +const char *pcDirectory; + + iReturn = 0; + + memset( pxFindData, '\0', sizeof( *pxFindData ) ); + + pxFindData->pcFileName = pxFindData->xDirectoryEntry.pcFileName; + + /* In case a CWD is used, get the absolute path. */ + pcDirectory = prvABSPath( pcPath ); + + if( ( pcDirectory[ 0 ] == '/' ) && ( pcDirectory[ 1 ] == 0x00 ) ) + { + iIsRootDir = pdTRUE; + } + else + { + iIsRootDir = pdFALSE; + } + + /* Find the i/o manager that can handle this path. */ + if( FF_FS_Find( pcDirectory, &( pxFindData->xDirectoryHandler ) ) == pdFALSE ) + { + if( ( iIsRootDir == pdFALSE ) || ( FF_FS_Count() == 0 ) ) + { + stdioSET_ERRNO( prvFFErrorToErrno( ( FF_Error_t ) ( FF_ERR_NULL_POINTER | FF_FINDFIRST ) ) ); + iReturn = -1; + } + } + + /* Check no errors before continuing. */ + if( iReturn == 0 ) + { + #if( ffconfigDEV_SUPPORT != 0 ) + { + pxFindData->bIsDeviceDir = xCheckDevicePath( pcDirectory ); + } + #endif + + if( iIsRootDir != pdFALSE ) + { + /* A listing of the root directory will include pseudo entries + such as /ram /nand. */ + pxFindData->xDirectoryHandler.xFSIndex = FF_FS_Count(); + + /* Only add '.' */ + pxFindData->xDirectoryHandler.u.bits.bAddDotEntries = stdioDIR_ENTRY_DOT_1; + } + else + { + /* This is the root of a sub file system, add "." and ".." */ + pxFindData->xDirectoryHandler.u.bits.bAddDotEntries = stdioDIR_ENTRY_DOT_1 | stdioDIR_ENTRY_DOT_2; + } + + pxFindData->xDirectoryHandler.u.bits.bIsValid = pdTRUE; + iReturn = ff_findnext( pxFindData ); + } + else + { + /* errno has already been set. */ + } + + return iReturn; +} +/*-----------------------------------------------------------*/ + +int ff_findnext( FF_FindData_t *pxFindData ) +{ +FF_Error_t xError; +#if( ffconfigTIME_SUPPORT != 0 ) + BaseType_t xSetTime = 0; +#endif /* ffconfigTIME_SUPPORT */ + + + if( pxFindData->xDirectoryHandler.u.bits.bIsValid == pdFALSE ) + { + xError = ( FF_Error_t ) ( FF_ERR_DIR_INVALID_PARAMETER | FF_FINDNEXT ); + FF_PRINTF("ff_findnext: xDirectoryHandler not valid\n" ); + } + else + { + xError = ( FF_Error_t ) ( FF_ERR_DIR_END_OF_DIR | FF_FINDNEXT ); + if( pxFindData->xDirectoryHandler.pxManager != NULL ) + { + if( pxFindData->xDirectoryHandler.u.bits.bFirstCalled == pdFALSE ) + { + pxFindData->xDirectoryHandler.u.bits.bFirstCalled = pdTRUE; + xError = FF_FindFirst( pxFindData->xDirectoryHandler.pxManager, &( pxFindData->xDirectoryEntry ), + pxFindData->xDirectoryHandler.pcPath ); + } + else if( pxFindData->xDirectoryHandler.u.bits.bEndOfDir == pdFALSE ) + { + xError = FF_FindNext( pxFindData->xDirectoryHandler.pxManager, &( pxFindData->xDirectoryEntry ) ); + } + + if( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR ) + { + /* Stop further calls to FF_FindNext(). */ + pxFindData->xDirectoryHandler.u.bits.bEndOfDir = pdTRUE; + } + + #if( ffconfigDEV_SUPPORT != 0 ) + { + if( pxFindData->bIsDeviceDir != pdFALSE ) + { + FF_Device_GetDirEnt( pxFindData->xDirectoryHandler.pcPath, &( pxFindData->xDirectoryEntry ) ); + } + } + #endif + } + + if( FF_isERR( xError ) == pdFALSE ) + { + /* If an entry is found, see if it is a dot-entry. Dot-entries + ("." and "..") need a time-stamp. */ + if( pxFindData->xDirectoryEntry.pcFileName[ 0 ] == '.' ) + { + if( ( pxFindData->xDirectoryEntry.pcFileName[ 1 ] == '.' ) && + ( pxFindData->xDirectoryEntry.pcFileName[ 2 ] == '\0' ) ) + { + /* This is a directory "..". Clear the flag for DOT_2. */ + pxFindData->xDirectoryHandler.u.bits.bAddDotEntries &= stdioDIR_ENTRY_DOT_1; + #if( ffconfigTIME_SUPPORT != 0 ) + { + /* The dot-entries do not have a proper time stamp, add + it here. */ + xSetTime = pdTRUE; + } + #endif /* ffconfigTIME_SUPPORT */ + } + else if( pxFindData->xDirectoryEntry.pcFileName[ 1 ] == '\0' ) + { + /* This is a directory ".". Clear the flag for DOT_1. */ + pxFindData->xDirectoryHandler.u.bits.bAddDotEntries &= stdioDIR_ENTRY_DOT_2; + #if( ffconfigTIME_SUPPORT != 0 ) + { + xSetTime = pdTRUE; + } + #endif /* ffconfigTIME_SUPPORT */ + } + } + } + + if( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR ) + { + /* No more physical entries were found. Now see if there are FS + entries or dot-entries to be added: */ + while( ( pxFindData->xDirectoryHandler.xFSIndex > 0 ) || + ( pxFindData->xDirectoryHandler.u.bits.bAddDotEntries != 0 ) ) + { + if( pxFindData->xDirectoryHandler.xFSIndex > 0 ) + { + FF_SubSystem_t xSubSystem; + int found; + + pxFindData->xDirectoryHandler.xFSIndex--; + found = FF_FS_Get( pxFindData->xDirectoryHandler.xFSIndex, &xSubSystem ); + + if( ( found == pdFALSE ) || ( xSubSystem.pcPath[ 1 ] == '\0' ) ) + { + continue; + } + snprintf( pxFindData->xDirectoryEntry.pcFileName, sizeof( pxFindData->xDirectoryEntry.pcFileName ), "%s", xSubSystem.pcPath + 1 ); + + if( xSubSystem.pxManager != NULL ) + { + pxFindData->xDirectoryEntry.ulObjectCluster = xSubSystem.pxManager->xPartition.ulRootDirCluster; + } + else + { + pxFindData->xDirectoryEntry.ulObjectCluster = 0; + } + } + else if( ( pxFindData->xDirectoryHandler.u.bits.bAddDotEntries & stdioDIR_ENTRY_DOT_2 ) != 0 ) + { + strcpy( pxFindData->xDirectoryEntry.pcFileName, ".."); + + /* Clear DOT_2 (keep DOT_1). */ + pxFindData->xDirectoryHandler.u.bits.bAddDotEntries &= stdioDIR_ENTRY_DOT_1; + } + else + { + strcpy( pxFindData->xDirectoryEntry.pcFileName, "."); + pxFindData->xDirectoryHandler.u.bits.bAddDotEntries = 0; + } + + pxFindData->xDirectoryEntry.ucAttrib = FF_FAT_ATTR_READONLY | FF_FAT_ATTR_DIR; + pxFindData->xDirectoryEntry.ulFileSize = stdioDOT_ENTRY_FILE_SIZE; + #if( ffconfigTIME_SUPPORT != 0 ) + { + xSetTime = pdTRUE; + } + #endif /* ffconfigTIME_SUPPORT */ + + xError = FF_ERR_NONE; + break; + } + } + + #if( ffconfigTIME_SUPPORT != 0 ) + { + if( xSetTime != pdFALSE ) + { + FF_TimeStruct_t xTimeStruct; + time_t xSeconds; + + xSeconds = FreeRTOS_time( NULL ); + FreeRTOS_gmtime_r( &xSeconds, &xTimeStruct ); + + pxFindData->xDirectoryEntry.xCreateTime.Year = ( uint16_t ) ( xTimeStruct.tm_year + 1900 ); /* Year (e.g. 2009). */ + pxFindData->xDirectoryEntry.xCreateTime.Month = ( uint16_t ) ( xTimeStruct.tm_mon + 1 ); /* Month (e.g. 1 = Jan, 12 = Dec). */ + pxFindData->xDirectoryEntry.xCreateTime.Day = ( uint16_t ) xTimeStruct.tm_mday; /* Day (1 - 31). */ + pxFindData->xDirectoryEntry.xCreateTime.Hour = ( uint16_t ) xTimeStruct.tm_hour; /* Hour (0 - 23). */ + pxFindData->xDirectoryEntry.xCreateTime.Minute = ( uint16_t ) xTimeStruct.tm_min; /* Min (0 - 59). */ + pxFindData->xDirectoryEntry.xCreateTime.Second = ( uint16_t ) xTimeStruct.tm_sec; /* Second (0 - 59). */ + pxFindData->xDirectoryEntry.xModifiedTime = pxFindData->xDirectoryEntry.xCreateTime; /* Date and Time Modified. */ + pxFindData->xDirectoryEntry.xAccessedTime = pxFindData->xDirectoryEntry.xCreateTime; /* Date of Last Access. */ + } + } + #endif /* ffconfigTIME_SUPPORT */ + + if( FF_GETERROR( xError ) == FF_ERR_DIR_END_OF_DIR ) + { + /* FF_ERR_DIR_END_OF_DIR will be returned. */ + pxFindData->xDirectoryHandler.u.bits.bIsValid = 0; + } + + pxFindData->ucAttributes = pxFindData->xDirectoryEntry.ucAttrib; + pxFindData->ulFileSize = pxFindData->xDirectoryEntry.ulFileSize; + } + + stdioSET_ERRNO( prvFFErrorToErrno( xError ) ); + + return xError; +} +/*-----------------------------------------------------------*/ + +/*----------------------------------------------------------- + * ff_isdirempty() returns 1 if a given directory is empty + * (has no entries) + *-----------------------------------------------------------*/ +int ff_isdirempty(const char *pcPath ) +{ + FF_DirHandler_t xHandler; + int iResult; + /* In case a CWD is used, get the absolute path */ + pcPath = prvABSPath( pcPath ); + /* Find the i/o manager which can handle this path */ + if( FF_FS_Find( pcPath, &xHandler ) == pdFALSE ) + { + iResult = ( int ) ( FF_ERR_NULL_POINTER | FF_ISDIREMPTY ); + } + else + { + iResult = FF_isDirEmpty( xHandler.pxManager, xHandler.pcPath ); + } + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( prvFFErrorToErrno( iResult ) ); + return iResult; +} +/*-----------------------------------------------------------*/ + +#if (ffconfig64_NUM_SUPPORT != 0 ) +int64_t ff_diskfree(const char *pcPath, uint32_t *pxSectorCount ) +#else +int32_t ff_diskfree(const char *pcPath, uint32_t *pxSectorCount ) +#endif +{ +FF_DirHandler_t xHandler; +FF_Error_t xError; +#if (ffconfig64_NUM_SUPPORT != 0 ) + #define DISKFREE_RETURN_TYPE int64_t + int64_t lReturn; +#else + #define DISKFREE_RETURN_TYPE int32_t + int32_t lReturn; +#endif + + if( FF_FS_Find( pcPath, &xHandler ) == pdFALSE ) + { + /* Return cluster 0 for error. */ + lReturn = 0ul; + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( pdFREERTOS_ERRNO_ENXIO ); /* No such device or address */ + } + else + { + if (pxSectorCount != NULL ) + { + *pxSectorCount = xHandler.pxManager->xPartition.ulDataSectors; + } + + lReturn = ( DISKFREE_RETURN_TYPE ) FF_GetFreeSize( xHandler.pxManager, &xError ) / 512; + + /* Store the errno to thread local storage. */ + stdioSET_ERRNO( prvFFErrorToErrno( xError ) ); + } + + return lReturn; +} +/*-----------------------------------------------------------*/ + +int ff_finddir(const char *pcPath ) +{ +int iResult; +FF_DirHandler_t xHandler; +FF_Error_t errCode; + + if( FF_FS_Find( pcPath, &xHandler ) == pdFALSE ) + { + /* Return cluster 0 for error. */ + iResult = 0; + } + else + { + iResult = ( int ) FF_FindDir( xHandler.pxManager, xHandler.pcPath, ( uint16_t ) strlen( xHandler.pcPath ), &errCode ); + } + + return iResult; +} +/*-----------------------------------------------------------*/ + +size_t ff_filelength( FF_FILE *pxStream ) +{ +FF_Error_t xReturned; +uint32_t ulLength; + + xReturned = FF_GetFileSize( pxStream, &( ulLength ) ); + + if( FF_isERR( xReturned ) != pdFALSE ) + { + /* An error. */ + ulLength = ( uint32_t ) 0u; + stdioSET_ERRNO( prvFFErrorToErrno( xReturned ) ); + } + else + { + stdioSET_ERRNO( pdFREERTOS_ERRNO_NONE ); + } + + return ( size_t ) ulLength; +} +/*-----------------------------------------------------------*/ + +/*----------------------------------------------------------- + * Delete a directory and, recursively, all of its contents + *-----------------------------------------------------------*/ +#if( ffconfigUSE_DELTREE != 0 ) + int ff_deltree( const char *pcDirectory ) + { + int iResult; + char *pcPath; + + pcPath = ( char * ) ffconfigMALLOC( ffconfigMAX_FILENAME ); + if( pcPath != NULL ) + { + /* In case a CWD is used, get the absolute path */ + pcDirectory = prvABSPath( pcDirectory ); + snprintf (pcPath, ffconfigMAX_FILENAME, "%s", pcDirectory); + /* This recursive function will do all the work */ + iResult = ff_deltree_recurse (pcPath); + if( iResult >= 0 ) + { + iResult = ff_rmdir( pcPath ); + if( iResult ) + { + FF_PRINTF("ff_deltree(%s): %s\n", pcPath, strerror( stdioGET_ERRNO( ) ) ); + } + } + ffconfigFREE( pcPath ); + } + else + { + iResult = -1; + stdioSET_ERRNO( pdFREERTOS_ERRNO_ENOMEM ); + } + return iResult; + } +#endif /* ffconfigUSE_DELTREE */ +/*-----------------------------------------------------------*/ + +#if( ffconfigUSE_DELTREE != 0 ) + static int ff_deltree_recurse( char *pcPath ) + { + FF_FindData_t *pxFindData; + BaseType_t xIsDir, xIsDotDir; + FF_Error_t xError; + int iResult, iNext, iNameLength, pass, iCount = 0; + + pxFindData = ( FF_FindData_t * ) ffconfigMALLOC( sizeof( *pxFindData ) ); + if( pxFindData != NULL ) + { + iNameLength = ( int ) strlen( pcPath ); + /* The directory will be scanned 2 times. First the sub-directories will be + entered and their contents deleted. In the second pass the files in the + current directory will be removed. In this way 'pcPath' can be constantly + used and reused recursively which is cheaper than allocating 'ffconfigMAX_FILENAME' + bytes within each recursion. */ + for( pass = 0; pass < 2; pass++ ) + { + for( iResult = ff_findfirst( pcPath, pxFindData ); + iResult == 0; + iResult = iNext ) + { + xIsDir = ( pxFindData->xDirectoryEntry.ucAttrib & FF_FAT_ATTR_DIR ) != 0; + if( ( pass == 0 ) && ( xIsDir != pdFALSE ) ) + { + /* This entry is a directory. Don't traverse '.' or '..' */ + xIsDotDir = 0; + + if( pxFindData->pcFileName[ 0 ] == '.' ) + { + if( ( pxFindData->pcFileName[ 1 ] == '.' ) && + ( pxFindData->pcFileName[ 2 ] == '\0' ) ) + { + xIsDotDir = 2; + } + else if( pxFindData->pcFileName[ 1 ] == '\0' ) + { + xIsDotDir = 1; + } + } + if( xIsDotDir == 0 ) + { + snprintf( pcPath + iNameLength, ( size_t ) ( ffconfigMAX_FILENAME - iNameLength ) , "%s%s", + pcPath[ iNameLength - 1 ] == '/' ? "" : "/", pxFindData->pcFileName ); + + /* Let pxFindData point to the next element before + the current will get removed. */ + iNext = ff_findnext( pxFindData ); + + /* Remove the contents of this directory. */ + iResult = ff_deltree_recurse( pcPath ); + if( iResult < 0 ) + { + iCount = -1; + break; + } + iCount += iResult; + /* remove the directory itself */ + xError = ff_rmdir( pcPath ); + if( xError != 0 ) + { + FF_PRINTF( "ff_rmdir( %s ): errno %d\n", pcPath, stdioGET_ERRNO() ); + } + else + { + iCount++; + } + } + else + { + iNext = ff_findnext( pxFindData ); + } + } + else if( ( pass == 1 ) && ( xIsDir == pdFALSE ) ) + { + snprintf( pcPath + iNameLength, ( size_t ) ( ffconfigMAX_FILENAME - iNameLength ), "%s%s", + pcPath[ iNameLength - 1 ] == '/' ? "" : "/", pxFindData->pcFileName ); + + /* Let pxFindData point to the next element before + the current will get removed. */ + iNext = ff_findnext( pxFindData ); + + /* Remove a plain file. */ + xError = ff_remove( pcPath ); + if( xError != 0 ) + { + FF_PRINTF( "ff_remove( %s ): errno %d\n", pcPath, stdioGET_ERRNO() ); + } + else + { + iCount++; + } + } + else + { + iNext = ff_findnext( pxFindData ); + } + pcPath[ iNameLength ] = '\0'; + } + + if( FF_GETERROR( iResult ) == FF_ERR_DIR_INVALID_PATH ) + { + break; + } + if( ( FF_GETERROR( iResult ) != FF_ERR_DIR_END_OF_DIR ) && ( FF_GETERROR( iResult ) != FF_ERR_FILE_INVALID_PATH ) ) + { + FF_PRINTF( "ff_deltree_recurse[%s]: %s\n", pcPath, ( const char * ) FF_GetErrMessage( iResult ) ); + } + } + ffconfigFREE( pxFindData ); + } + else + { + iCount = -1; + stdioSET_ERRNO( pdFREERTOS_ERRNO_ENOMEM ); + } + + return iCount; + } +#endif /* ffconfigUSE_DELTREE */ +/*-----------------------------------------------------------*/ + +int prvFFErrorToErrno( FF_Error_t xError ) +{ + if( FF_isERR( xError ) == pdFALSE ) + { + return 0; + } + + /* Store the last +FAT error code received. */ + stdioSET_FF_ERROR( xError ); + + switch( FF_GETERROR( xError ) ) + { + /* Global Error Codes. */ + case FF_ERR_NONE: return 0; /* No Error. */ + + case FF_ERR_NULL_POINTER: return pdFREERTOS_ERRNO_EBADF; /* pxIOManager was NULL. */ + case FF_ERR_NOT_ENOUGH_MEMORY: return pdFREERTOS_ERRNO_ENOMEM; /* malloc() failed! - Could not allocate handle memory. */ + case FF_ERR_DEVICE_DRIVER_FAILED: return pdFREERTOS_ERRNO_EIO; /* The Block Device driver reported a FATAL error, cannot continue. */ + + /* User return codes for Rd/Wr functions:. */ + case FF_ERR_IOMAN_DRIVER_BUSY: return pdFREERTOS_ERRNO_EBUSY; /* 10. */ + case FF_ERR_IOMAN_DRIVER_FATAL_ERROR: return pdFREERTOS_ERRNO_EUNATCH; /* Protocol driver not attached. */ + + /* IOMAN Error Codes. */ + case FF_ERR_IOMAN_BAD_BLKSIZE: return pdFREERTOS_ERRNO_EINVAL; /* The provided blocksize was not a multiple of 512. */ + case FF_ERR_IOMAN_BAD_MEMSIZE: return pdFREERTOS_ERRNO_EINVAL; /* The memory size was not a multiple of the blocksize. */ + case FF_ERR_IOMAN_DEV_ALREADY_REGD: return pdFREERTOS_ERRNO_EADDRINUSE; /* Device was already registered. Use FF_UnRegister() to re-use this IOMAN with another device. */ + case FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION: return pdFREERTOS_ERRNO_ENOMEDIUM; /* A mountable partition could not be found on the device. */ + case FF_ERR_IOMAN_INVALID_FORMAT: return pdFREERTOS_ERRNO_EFTYPE; /* The. */ + case FF_ERR_IOMAN_INVALID_PARTITION_NUM: return pdFREERTOS_ERRNO_EINVAL; /* The partition number provided was out of range. */ + case FF_ERR_IOMAN_NOT_FAT_FORMATTED: return pdFREERTOS_ERRNO_EFTYPE; /* The partition did not look like a FAT partition. */ + case FF_ERR_IOMAN_DEV_INVALID_BLKSIZE: return pdFREERTOS_ERRNO_EINVAL; /* IOMAN object BlkSize is not compatible with the blocksize of this device driver. */ + case FF_ERR_IOMAN_PARTITION_MOUNTED: return pdFREERTOS_ERRNO_EADDRINUSE; /* Device is in use by an actively mounted partition. Unmount the partition first. */ + case FF_ERR_IOMAN_ACTIVE_HANDLES: return pdFREERTOS_ERRNO_EBUSY; /* The partition cannot be unmounted until all active file handles are closed. (There may also be active handles on the cache). */ + case FF_ERR_IOMAN_GPT_HEADER_CORRUPT: return pdFREERTOS_ERRNO_EBADE; /* The GPT partition table appears to be corrupt, refusing to mount. */ + case FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE: return pdFREERTOS_ERRNO_ENOSPC; /* 22. */ + case FF_ERR_IOMAN_OUT_OF_BOUNDS_READ: return pdFREERTOS_ERRNO_ESPIPE; /* 23, return 'Illegal seek'. */ + case FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE: return pdFREERTOS_ERRNO_ESPIPE; /* 24. */ + case FF_ERR_IOMAN_DRIVER_NOMEDIUM: return pdFREERTOS_ERRNO_ENOMEDIUM; /* The medium (e.g. SD-card) has been extracted. */ + + /* File Error Codes 30 +. */ + case FF_ERR_FILE_ALREADY_OPEN: return pdFREERTOS_ERRNO_EALREADY; /* File is in use. */ + case FF_ERR_FILE_NOT_FOUND: return pdFREERTOS_ERRNO_ENOENT; /* File was not found. */ + case FF_ERR_FILE_OBJECT_IS_A_DIR: return pdFREERTOS_ERRNO_EISDIR; /* Tried to FF_Open() a Directory. */ + case FF_ERR_FILE_IS_READ_ONLY: return pdFREERTOS_ERRNO_EROFS; /* Tried to FF_Open() a file marked read only. */ + case FF_ERR_FILE_INVALID_PATH: return pdFREERTOS_ERRNO_ENOTDIR; /* The path of the file was not found. */ + case FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE: return pdFREERTOS_ERRNO_EACCES; /* 35. */ + case FF_ERR_FILE_NOT_OPENED_IN_READ_MODE: return pdFREERTOS_ERRNO_EACCES; /* 36. */ + case FF_ERR_FILE_EXTEND_FAILED: return pdFREERTOS_ERRNO_ENOSPC; /* Could not extend the file. */ + case FF_ERR_FILE_DESTINATION_EXISTS: return pdFREERTOS_ERRNO_EEXIST; /* 38. */ + case FF_ERR_FILE_SOURCE_NOT_FOUND: return pdFREERTOS_ERRNO_ENOENT; /* 39. */ + case FF_ERR_FILE_DIR_NOT_FOUND: return pdFREERTOS_ERRNO_ENOENT; /* 40. */ + case FF_ERR_FILE_COULD_NOT_CREATE_DIRENT: return pdFREERTOS_ERRNO_EIO; /* 41. */ + case FF_ERR_FILE_BAD_HANDLE: return pdFREERTOS_ERRNO_EBADF; /* A file handle was invalid. */ + case FF_ERR_FILE_MEDIA_REMOVED: return pdFREERTOS_ERRNO_ENODEV; /* File handle got invalid because media was removed. */ + case FF_ERR_FILE_SEEK_INVALID_POSITION: return pdFREERTOS_ERRNO_ESPIPE; /* Illegal position, outside the file's space */ + case FF_ERR_FILE_SEEK_INVALID_ORIGIN: return pdFREERTOS_ERRNO_EINVAL; /* Seeking beyond end of file. */ + + /* Directory Error Codes 50 +. */ + case FF_ERR_DIR_OBJECT_EXISTS: return pdFREERTOS_ERRNO_EEXIST; /* A file or folder of the same name already exists in the current directory. */ + case FF_ERR_DIR_DIRECTORY_FULL: return pdFREERTOS_ERRNO_ENOSPC; /* No more items could be added to the directory. */ + case FF_ERR_DIR_END_OF_DIR: return pdFREERTOS_ERRNO_ENMFILE; /*/. */ + case FF_ERR_DIR_NOT_EMPTY: return pdFREERTOS_ERRNO_ENOTEMPTY; /* Cannot delete a directory that contains files or folders. */ + case FF_ERR_DIR_INVALID_PATH: return pdFREERTOS_ERRNO_EINVAL; /* Could not find the directory specified by the path. */ + case FF_ERR_DIR_CANT_EXTEND_ROOT_DIR: return pdFREERTOS_ERRNO_ENOSPC; /* Can't extend the root dir. */ + case FF_ERR_DIR_EXTEND_FAILED: return pdFREERTOS_ERRNO_ENOSPC; /* Not enough space to extend the directory. */ + case FF_ERR_DIR_NAME_TOO_LONG: return pdFREERTOS_ERRNO_ENAMETOOLONG;/* Name exceeds the number of allowed characters for a filename. */ + + /* Fat Error Codes 70 +. */ + case FF_ERR_FAT_NO_FREE_CLUSTERS: return pdFREERTOS_ERRNO_ENOSPC; /* No more free space is available on the disk. */ + + /* UNICODE Error Codes 100 +. */ + case FF_ERR_UNICODE_INVALID_CODE: return pdFREERTOS_ERRNO_EBADE; /* An invalid Unicode character was provided!. */ + case FF_ERR_UNICODE_DEST_TOO_SMALL: return pdFREERTOS_ERRNO_ENOBUFS; /* Not enough space in the UTF-16 buffer to encode the entire sequence as UTF-16. */ + case FF_ERR_UNICODE_INVALID_SEQUENCE: return pdFREERTOS_ERRNO_EILSEQ; /* An invalid UTF-16 sequence was encountered. */ + case FF_ERR_UNICODE_CONVERSION_EXCEEDED: return pdFREERTOS_ERRNO_ENAMETOOLONG;/* Filename exceeds MAX long-filename length when converted to UTF-16. */ + } + + return pdFREERTOS_ERRNO_EFAULT; +} +/*-----------------------------------------------------------*/ + +#if( ffconfigHAS_CWD == 1 ) + + void ff_free_CWD_space( void ) + { + WorkingDirectory_t *pxSpace; + + /* Obtain the CWD used by the current task. */ + pxSpace = ( WorkingDirectory_t * ) pvTaskGetThreadLocalStoragePointer( NULL, stdioCWD_THREAD_LOCAL_OFFSET ); + if( pxSpace != NULL ) + { + vTaskSetThreadLocalStoragePointer( NULL, stdioCWD_THREAD_LOCAL_OFFSET, ( void * ) NULL ); + ffconfigFREE( pxSpace ); + } + } + +#endif /* ffconfigHAS_CWD */ +/*-----------------------------------------------------------*/ + +#if( ffconfigHAS_CWD == 1 ) + + static WorkingDirectory_t *pxFindCWD( void ) + { + WorkingDirectory_t *pxReturn; + + /* Obtain the CWD used by the current task. */ + pxReturn = ( WorkingDirectory_t * ) pvTaskGetThreadLocalStoragePointer( NULL, stdioCWD_THREAD_LOCAL_OFFSET ); + + if( pxReturn == NULL ) + { + /* This task does not yet have a WorkingDirectory_t structure - create and + initialise one now. */ + pxReturn = ( WorkingDirectory_t * ) ffconfigMALLOC( sizeof( WorkingDirectory_t ) ); + + if( pxReturn != NULL ) + { + pxReturn->pcCWD[ 0 ] = '\0'; + vTaskSetThreadLocalStoragePointer( NULL, stdioCWD_THREAD_LOCAL_OFFSET, ( void * ) pxReturn ); + } + } + + return pxReturn; + } + +#endif /* ffconfigHAS_CWD */ +/*-----------------------------------------------------------*/ + +#if( ffconfigHAS_CWD == 1 ) + + static const char *prvProcessRelativePaths( const char *pcPath ) + { + const char *pcReturn; + char *pcChar, *pcTokenStart = NULL, *pcFollowingToken, cPreviousChar = 0x00; + BaseType_t xByte; + + /* Scan the string looking for a relative path. */ + pcReturn = pcPath; + pcChar = ( char * ) pcReturn; + + configASSERT( pcPath ); + + while( *pcChar != 0x00 ) + { + if( *pcChar == '.' ) + { + /* A potential relative path was found. Is this a "." or a "..". */ + if( *( pcChar + 1 ) == '.' ) + { + /* Nothing can be done if this is at the start of the string. */ + if( pcTokenStart != NULL ) + { + /* A ".." was found. Where does the next token start? */ + pcFollowingToken = pcChar + 2; + + if( *pcFollowingToken == '/' ) + { + /* The next token starts after the "../" */ + pcFollowingToken += sizeof( char ); + } + + /* Remove the ".." and the previous token. */ + xByte = 0; + while( pcFollowingToken[ xByte ] != 0x00 ) + { + pcTokenStart[ xByte ] = pcFollowingToken[ xByte ]; + xByte++; + } + + /* Terminate. */ + pcTokenStart[ xByte ] = 0x00; + + /* The pointer to the previous token will now be wrong if + there are multiple if "../.." appears in the string. So + reset the variables to continue scanning. */ + pcChar = ( char * ) pcReturn; + cPreviousChar = 0x00; + pcTokenStart = NULL; + continue; + } + } + else + { + /* A "." was found. Remove it. */ + } + } + + if( cPreviousChar == '/' ) + { + /* This is the start of a new token. */ + pcTokenStart = pcChar; + } + + cPreviousChar = *pcChar; + pcChar++; + } + + /* Make sure there is no / on the end of the string, being careful not to + remove the / at the beginning of the string. */ + if( *( pcChar - 1 ) == '/' ) + { + if( ( pcChar - 1 ) != pcReturn ) + { + *( pcChar - 1 ) = 0x00; + } + } + + return pcReturn; + } + +#endif /* ffconfigHAS_CWD */ +/*-----------------------------------------------------------*/ + +#if( ffconfigHAS_CWD == 1 ) + + /*static*/ const char *prvABSPath( const char *pcPath ) + { + char *pcReturn; + WorkingDirectory_t *pxWorkingDirectory = pxFindCWD(); + + configASSERT( pxWorkingDirectory ); + + if( ( pcPath[ 0 ] ) == '/' ) + { + /* If the path starts with a slash it does not start with a relative + path. Copy the string into a thread local buffer so it can be + manipulated without risk of attempting to write to read only + memory. */ + snprintf( pxWorkingDirectory->pcFileName, sizeof( pxWorkingDirectory->pcFileName ), "%s", pcPath ); + pcReturn = pxWorkingDirectory->pcFileName; + } + else + { + /* Insert the working directory into the front of the path. */ + if( pxWorkingDirectory->pcCWD[ 1 ] == 0x00 ) + { + /* In the root, so don't add a '/' between the CWD and the + file name. */ + snprintf( pxWorkingDirectory->pcFileName, sizeof( pxWorkingDirectory->pcFileName ), "/%s", pcPath ); + } + else + { + snprintf( pxWorkingDirectory->pcFileName, sizeof( pxWorkingDirectory->pcFileName ), "%s/%s", pxWorkingDirectory->pcCWD, pcPath ); + } + + pcReturn = pxWorkingDirectory->pcFileName; + } + + /* Make any adjustments necessitated by relative paths. */ + prvProcessRelativePaths( pcReturn ); + + return pcReturn; + } + +#endif /* ffconfigHAS_CWD */ + +#if( ffconfigTIME_SUPPORT == 1 ) + + static uint32_t prvFileTime( FF_SystemTime_t *pxTime ) + { + FF_TimeStruct_t xTime; + time_t xReturn; + + xTime.tm_sec = pxTime->Second; + xTime.tm_min = pxTime->Minute; + xTime.tm_hour = pxTime->Hour; + xTime.tm_mday = pxTime->Day; + xTime.tm_mon = pxTime->Month - 1; + xTime.tm_year = pxTime->Year - 1900; + + xReturn = FreeRTOS_mktime( &xTime ); + + return xReturn; + } + +#endif +/*-----------------------------------------------------------*/ + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_string.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_string.c new file mode 100644 index 000000000..7c941914f --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_string.c @@ -0,0 +1,716 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_string.c + * @ingroup STRING + * + * @defgroup STRING FreeRTOS+FAT String Library + * @brief Portable String Library for FreeRTOS+FAT + * + * + **/ + +#include +#include +#include + +#include "ff_headers.h" + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + #include + #include +#endif + +/* + * These will eventually be moved into a platform independent string + * library. Which will be optional. (To allow the use of system specific versions). + */ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + void FF_cstrntowcs( FF_T_WCHAR *wcsDest, const int8_t *szpSource, uint32_t ulLength ) + { + while( ( *szpSource != '\0' ) && ( ulLength-- != 0 ) ) + { + *( wcsDest++ ) = *( szpSource++ ); + } + *wcsDest = '\0'; + } +#endif /* ffconfigUNICODE_UTF16_SUPPORT */ +/*-----------------------------------------------------------*/ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + void FF_cstrtowcs( FF_T_WCHAR *wcsDest, const int8_t *szpSource ) + { + while( *szpSource != '\0' ) + { + *wcsDest++ = ( FF_T_WCHAR ) *( szpSource++ ); + } + *wcsDest = '\0'; + } +#endif /* ffconfigUNICODE_UTF16_SUPPORT */ +/*-----------------------------------------------------------*/ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + void FF_wcstocstr( int8_t *szpDest, const FF_T_WCHAR *wcsSource ) + { + while( *wcsSource != '\0' ) + { + *szpDest++ = ( int8_t )*( wcsSource++ ); + } + *szpDest = '\0'; + } +#endif /* ffconfigUNICODE_UTF16_SUPPORT */ +/*-----------------------------------------------------------*/ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + void FF_wcsntocstr( int8_t *szpDest, const FF_T_WCHAR *wcsSource, uint32_t ulLength ) + { + while( ( *wcsSource != '\0' ) && ( ulLength-- != 0 ) ) + { + *( szpDest++ ) = ( int8_t ) *( wcsSource++ ); + } + *szpDest = '\0'; + } +#endif /* ffconfigUNICODE_UTF16_SUPPORT */ +/*-----------------------------------------------------------*/ + +/*-----------------------------------------------------------*/ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + void FF_toupper( FF_T_WCHAR *string, uint32_t ulLength ) + { + uint32_t i; + + for( i = 0; i < ulLength; i++ ) + { + string[ i ] = towupper( string[ i ] ); + } + } + /*-----------------------------------------------------------*/ + + void FF_tolower( FF_T_WCHAR *string, uint32_t ulLength ) + { + uint32_t i; + for( i = 0; i < ulLength; i++ ) + { + string[ i ] = towlower( string[ i ] ); + } + } + /*-----------------------------------------------------------*/ + +#else /* ffconfigUNICODE_UTF16_SUPPORT */ + void FF_toupper( char *string, uint32_t ulLength ) + { + uint32_t i; + + for( i = 0; i < ulLength; i++ ) + { + if( ( string[ i ] >= 'a' ) && ( string[ i ] <= 'z' ) ) + { + string[ i ] -= 32; + } + if( string[ i ] == '\0' ) + { + break; + } + } + } + /*-----------------------------------------------------------*/ + + void FF_tolower( char *string, uint32_t ulLength ) + { + uint32_t i; + + for( i = 0; i < ulLength; i++ ) + { + if( ( string[ i ] >= 'A' ) && ( string[ i ] <= 'Z' ) ) + { + string[ i ] += 32; + } + if( string[ i ] == '\0' ) + { + break; + } + } + } + /*-----------------------------------------------------------*/ + +#endif /* ffconfigUNICODE_UTF16_SUPPORT */ + + +/** + * @private + * @brief Compares 2 strings for the specified length, and returns pdTRUE is they are identical + * otherwise pdFALSE is returned. + * + **/ + +#if( ffconfigUNICODE_UTF16_SUPPORT == 0 ) + BaseType_t FF_strmatch( const char *str1, const char *str2, BaseType_t xLength ) + { + register BaseType_t i; + register char char1, char2; + + if( xLength == 0 ) + { + xLength = strlen( str1 ); + if( xLength != ( BaseType_t )strlen( str2 ) ) + { + return pdFALSE; + } + } + + for( i = 0; i < xLength; i++ ) + { + char1 = str1[ i ]; + char2 = str2[ i ]; + if( ( char1 >= 'A' ) && ( char1 <= 'Z' ) ) + { + char1 += 32; + } + if( ( char2 >= 'A' ) && ( char2 <= 'Z' ) ) + { + char2 += 32; + } + + if( char1 != char2 ) + { + return pdFALSE; + } + } + + return pdTRUE; + } +#else /* ffconfigUNICODE_UTF16_SUPPORT */ + BaseType_t FF_strmatch( const FF_T_WCHAR *str1, const FF_T_WCHAR *str2, BaseType_t xLength ) + { + register BaseType_t i; + register FF_T_WCHAR char1, char2; + + if( xLength == 0 ) + { + xLength = wcslen( str1 ); + if( xLength != wcslen( str2 ) ) + { + return pdFALSE; + } + } + + for( i = 0; i < xLength; i++ ) + { + char1 = towlower( str1[ i ] ); + char2 = towlower( str2[ i ] ); + if( char1 != char2 ) + { + return pdFALSE; + } + } + + return pdTRUE; + } +#endif /* ffconfigUNICODE_UTF16_SUPPORT */ + +/** + * @private + * @brief A re-entrant Strtok function. No documentation is provided :P + * Use at your own risk. (This is for FreeRTOS+FAT's use only). + **/ + +#if( ffconfigUNICODE_UTF16_SUPPORT == 0 ) + char *FF_strtok( const char *string, char *token, uint16_t *tokenNumber, BaseType_t *last, BaseType_t xLength ) + { + uint16_t i,y, tokenStart, tokenEnd = 0; + + i = 0; + y = 0; + + if( ( string[ i ] == '\\' ) || ( string[ i ] == '/' ) ) + { + i++; + } + + tokenStart = i; + + while( i < xLength ) + { + if( ( string[ i ] == '\\' ) || ( string[ i ] == '/' ) ) + { + y++; + if( y == *tokenNumber ) + { + tokenStart = ( uint16_t )( i + 1 ); + } + if( y == ( *tokenNumber + 1 ) ) + { + tokenEnd = i; + break; + } + } + i++; + } + + if( tokenEnd == 0 ) + { + if( *last == pdTRUE ) + { + return NULL; + } + else + { + *last = pdTRUE; + } + tokenEnd = i; + } + if( ( tokenEnd - tokenStart ) < ffconfigMAX_FILENAME ) + { + memcpy( token, ( string + tokenStart ), ( uint32_t )( tokenEnd - tokenStart ) ); + token[ tokenEnd - tokenStart ] = '\0'; + } + else + { + memcpy( token, ( string + tokenStart ), ( uint32_t )( ffconfigMAX_FILENAME ) ); + token[ ffconfigMAX_FILENAME - 1 ] = '\0'; + } + /*token[tokenEnd - tokenStart] = '\0'; */ + *tokenNumber += 1; + + return token; + } +#else /* ffconfigUNICODE_UTF16_SUPPORT */ + FF_T_WCHAR *FF_strtok( const FF_T_WCHAR *string, FF_T_WCHAR *token, uint16_t *tokenNumber, BaseType_t *last, BaseType_t xLength ) + { + uint16_t i,y, tokenStart, tokenEnd = 0; + + i = 0; + y = 0; + + if( ( string[ i ] == '\\' ) || ( string[ i ] == '/' ) ) + { + i++; + } + + tokenStart = i; + + while( i < xLength ) + { + if( ( string[ i ] == '\\' ) || ( string[ i ] == '/' ) ) + { + y++; + if( y == *tokenNumber ) + { + tokenStart = ( uint16_t ) ( i + 1 ); + } + if( y == ( *tokenNumber + 1 ) ) + { + tokenEnd = i; + break; + } + } + i++; + } + + if( tokenEnd == 0 ) + { + if( *last == pdTRUE ) + { + return NULL; + } + else + { + *last = pdTRUE; + } + tokenEnd = i; + } + if( ( tokenEnd - tokenStart ) < ffconfigMAX_FILENAME ) + { + memcpy( token, ( string + tokenStart ), ( uint32_t )( tokenEnd - tokenStart ) * sizeof( FF_T_WCHAR ) ); + token[ tokenEnd - tokenStart ] = '\0'; + } + else + { + memcpy( token, ( string + tokenStart ), ( uint32_t )( ffconfigMAX_FILENAME ) * sizeof( FF_T_WCHAR ) ); + token[ ffconfigMAX_FILENAME - 1 ] = '\0'; + } + /*token[tokenEnd - tokenStart] = '\0'; */ + *tokenNumber += 1; + + return token; + } +#endif /* ffconfigUNICODE_UTF16_SUPPORT */ + +/* UTF-8 Routines */ + +/* + UCS-4 range (hex.) UTF-8 octet sequence (binary) + 0000 0000-0000 007F 0xxxxxxx + 0000 0080-0000 07FF 110xxxxx 10xxxxxx + 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx + + 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE). + 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE). +*/ + +#if ( ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) && ( WCHAR_MAX > 0xFFFF ) ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + UBaseType_t FF_GetUtf16SequenceLen( uint16_t usLeadChar ) + { + UBaseType_t uxReturn; + if( ( usLeadChar & 0xFC00 ) == 0xD800 ) + { + uxReturn = 2; + } + else + { + uxReturn = 1; + } + + return uxReturn; + } /* FF_GetUtf16SequenceLen() */ +#endif +/*-----------------------------------------------------------*/ + +/* + Returns the number of UTF-8 units read. + Will not exceed ulSize UTF-16 units. (ulSize * 2 bytes). +*/ +/* + UCS-4 range (hex.) UTF-8 octet sequence (binary) + 0000 0000-0000 007F 0xxxxxxx + 0000 0080-0000 07FF 110xxxxx 10xxxxxx + 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx + + 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE). + 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE). +*/ +#if ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + int32_t FF_Utf8ctoUtf16c( uint16_t *utf16Dest, const uint8_t *utf8Source, uint32_t ulSize ) + { + uint32_t ulUtf32char; + uint16_t utf16Source = 0; + register int32_t lSequenceNumber = 0; + + /* Count number of set bits before a zero. */ + while( ( ( *utf8Source != '\0' ) & ( 0x80 >> ( lSequenceNumber ) ) ) ) + { + lSequenceNumber++; + } + + if( lSequenceNumber == 0UL ) + { + lSequenceNumber++; + } + + if( ulSize == 0UL ) + { + /* Returned value becomes an error, with the highest bit set. */ + lSequenceNumber = FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF8CTOUTF16C; + } + else + { + switch( lSequenceNumber ) + { + case 1: + utf16Source = (uint16_t) *utf8Source; + memcpy(utf16Dest,&utf16Source,sizeof(uint16_t)); + break; + + case 2: + utf16Source =(uint16_t) ((*utf8Source & 0x1F) << 6) | ((*(utf8Source + 1) & 0x3F)); + memcpy(utf16Dest,&utf16Source,sizeof(uint16_t)); + break; + + case 3: + utf16Source =(uint16_t) ((*utf8Source & 0x0F) << 12) | ((*(utf8Source + 1) & 0x3F) << 6) | ((*(utf8Source + 2) & 0x3F)); + memcpy(utf16Dest,&utf16Source,sizeof(uint16_t)); + break; + + case 4: + if( ulSize < 2 ) + { + /* Returned value becomes an error. */ + lSequenceNumber = FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF8CTOUTF16C; + } + else + { + /* Convert to UTF-32 and then into UTF-16 */ + ulUtf32char = ( uint16_t ) + ( ( *utf8Source & 0x0F ) << 18 ) | + ( ( *( utf8Source + 1 ) & 0x3F ) << 12 ) | + ( ( *( utf8Source + 2 ) & 0x3F ) << 6 ) | + ( ( *( utf8Source + 3 ) & 0x3F ) ); + + utf16Source = ( uint16_t ) ( ( ( ulUtf32char - 0x10000 ) & 0xFFC00 ) >> 10 ) | 0xD800; + memcpy( utf16Dest, &utf16Source, sizeof( uint16_t ) ); + utf16Source = ( uint16_t ) ( ( ( ulUtf32char - 0x10000 ) & 0x003FF ) >> 00 ) | 0xDC00; + memcpy( utf16Dest + 1, &utf16Source, sizeof( uint16_t ) ); + } + break; + + default: + break; + } + } + + return lSequenceNumber; + } /* FF_Utf8ctoUtf16c() */ +#endif /* ffconfigUNICODE_UTF8_SUPPORT */ + +/*-----------------------------------------------------------*/ + +/* + Returns the number of UTF-8 units required to encode the UTF-16 sequence. + Will not exceed ulSize UTF-8 units. (ulSize * 1 bytes). +*/ +#if ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + int32_t FF_Utf16ctoUtf8c( uint8_t *utf8Dest, const uint16_t *utf16Source, uint32_t ulSize ) + { + uint32_t ulUtf32char; + uint16_t ulUtf16char; + int32_t lReturn = 0L; + + do + { + if( ulSize == 0UL ) + { + lReturn = FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF16CTOUTF8C; + break; + } + memcpy( &ulUtf16char, utf16Source, sizeof( uint16_t ) ); + + /* A surrogate sequence was encountered. Must transform to UTF32 first. */ + if( ( ulUtf16char & 0xF800) == 0xD800 ) + { + ulUtf32char = ( ( uint32_t ) ( ulUtf16char & 0x003FF ) << 10 ) + 0x10000; + + memcpy( &ulUtf16char, utf16Source + 1, sizeof( uint16_t ) ); + if( ( ulUtf16char & 0xFC00 ) != 0xDC00 ) + { + /* Invalid UTF-16 sequence. */ + lReturn = FF_ERR_UNICODE_INVALID_SEQUENCE | FF_UTF16CTOUTF8C; + break; + } + ulUtf32char |= ( ( uint32_t ) ( ulUtf16char & 0x003FF ) ); + } + else + { + ulUtf32char = ( uint32_t ) ulUtf16char; + } + + /* Now convert to the UTF-8 sequence. */ + /* Single byte UTF-8 sequence. */ + if( ulUtf32char < 0x00000080 ) + { + *( utf8Dest + 0 ) = ( uint8_t )ulUtf32char; + lReturn = 1; + break; + } + + /* Double byte UTF-8 sequence. */ + if( ulUtf32char < 0x00000800 ) + { + if( ulSize < 2 ) + { + lReturn = FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF16CTOUTF8C; + } + else + { + *( utf8Dest + 0 ) = ( uint8_t ) ( 0xC0 | ( ( ulUtf32char >> 6 ) & 0x1F ) ); + *( utf8Dest + 1 ) = ( uint8_t ) ( 0x80 | ( ( ulUtf32char >> 0 ) & 0x3F ) ); + lReturn = 2; + } + break; + } + + /* Triple byte UTF-8 sequence. */ + if( ulUtf32char < 0x00010000 ) + { + if( ulSize < 3 ) + { + lReturn = FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF16CTOUTF8C; + } + else + { + *( utf8Dest + 0 ) = ( uint8_t ) ( 0xE0 | ( ( ulUtf32char >> 12 ) & 0x0F ) ); + *( utf8Dest + 1 ) = ( uint8_t ) ( 0x80 | ( ( ulUtf32char >> 6 ) & 0x3F ) ); + *( utf8Dest + 2 ) = ( uint8_t ) ( 0x80 | ( ( ulUtf32char >> 0 ) & 0x3F ) ); + lReturn = 3; + } + break; + } + + /* Quadruple byte UTF-8 sequence. */ + if( ulUtf32char < 0x00200000 ) + { + if( ulSize < 4 ) + { + lReturn = FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF16CTOUTF8C; + } + else + { + *( utf8Dest + 0 ) = ( uint8_t ) (0xF0 | ( ( ulUtf32char >> 18 ) & 0x07 ) ); + *( utf8Dest + 1 ) = ( uint8_t ) (0x80 | ( ( ulUtf32char >> 12 ) & 0x3F ) ); + *( utf8Dest + 2 ) = ( uint8_t ) (0x80 | ( ( ulUtf32char >> 6 ) & 0x3F ) ); + *( utf8Dest + 3 ) = ( uint8_t ) (0x80 | ( ( ulUtf32char >> 0 ) & 0x3F ) ); + lReturn = 4; + } + break; + } + lReturn = FF_ERR_UNICODE_INVALID_CODE | FF_UTF16CTOUTF8C; /* Invalid Character */ + } + while( pdFALSE ); + + return lReturn; + } /* FF_Utf16ctoUtf8c() */ +#endif /* ffconfigUNICODE_UTF8_SUPPORT */ +/*-----------------------------------------------------------*/ + +/* UTF-16 Support Functions */ + +/* Converts a UTF-32 Character into its equivalent UTF-16 sequence. */ +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) && ( WCHAR_MAX > 0xFFFF ) + int32_t FF_Utf32ctoUtf16c( uint16_t *utf16Dest, uint32_t utf32char, uint32_t ulSize ) + { + int32_t lReturn; + /* Check that its a valid UTF-32 wide-char! */ + + /* This range is not a valid Unicode code point. */ + if( ( utf32char >= 0xD800 ) && ( utf32char <= 0xDFFF ) ) + { + lReturn = FF_ERR_UNICODE_INVALID_CODE | FF_UTF32CTOUTF16C; /* Invalid character. */ + } + else if( utf32char < 0x10000 ) + { + *utf16Dest = (uint16_t) utf32char; /* Simple conversion! Char comes within UTF-16 space (without surrogates). */ + lReturn = 1; + } + else if( ulSize < 2 ) + { + lReturn FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF32CTOUTF16C; /* Not enough UTF-16 units to record this character. */ + } + else if( utf32char < 0x00200000 ) + { + /* Conversion to a UTF-16 Surrogate pair! */ + /*valueImage = utf32char - 0x10000; */ + *( utf16Dest + 0 ) = ( uint16_t ) ( ( ( utf32char - 0x10000 ) & 0xFFC00 ) >> 10 ) | 0xD800; + *( utf16Dest + 1 ) = ( uint16_t ) ( ( ( utf32char - 0x10000 ) & 0x003FF ) >> 00 ) | 0xDC00; + + lReturn = 2; /* Surrogate pair encoded value. */ + } + else + { + /* Invalid Character */ + lReturn = FF_ERR_UNICODE_INVALID_CODE | FF_UTF32CTOUTF16C; + } + + return lReturn; + } /* FF_Utf32ctoUtf16c() */ +#endif /* #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) && ( WCHAR_MAX > 0xFFFF ) */ +/*-----------------------------------------------------------*/ + +/* Converts a UTF-16 sequence into its equivalent UTF-32 code point. */ +#if( ffconfigNOT_USED_FOR_NOW != 0 ) + int32_t FF_Utf16ctoUtf32c( uint32_t *utf32Dest, const uint16_t *utf16Source ) + { + int32_t lReturn; + + /*Not a surrogate sequence. */ + if( ( *utf16Source & 0xFC00 ) != 0xD800 ) + { + *utf32Dest = ( uint32_t )*utf16Source; + lReturn = 1; /* A single UTF-16 item was used to represent the character. */ + } + else + { + *utf32Dest = ( ( uint32_t) ( * ( utf16Source + 0 ) & 0x003FF ) << 10 ) + 0x10000; + if( ( *(utf16Source + 1) & 0xFC00 ) != 0xDC00 ) + { + lReturn = FF_ERR_UNICODE_INVALID_SEQUENCE | FF_UTF16CTOUTF32C; /* Invalid UTF-16 sequence. */ + } + else + { + *utf32Dest |= ( ( uint32_t ) ( *( utf16Source + 1 ) & 0x003FF ) ); + lReturn = 2; /* 2 utf-16 units make up the Unicode code-point. */ + } + } + + return lReturn; + } /* FF_Utf16ctoUtf32c() */ +#endif /* ffconfigNOT_USED_FOR_NOW */ +/*-----------------------------------------------------------*/ + +/* + Returns the total number of UTF-16 items required to represent + the provided UTF-32 string in UTF-16 form. +*/ +/* +UBaseType_t FF_Utf32GetUtf16Len( const uint32_t *utf32String ) +{ + UBaseType_t utf16len = 0; + + while( *utf32String ) + { + if( *utf32String++ <= 0xFFFF ) + { + utf16len++; + } + else + { + utf16len += 2; + } + } + + return utf16len; +} +*/ +/*-----------------------------------------------------------*/ + + +/* String conversions */ + +#if( ffconfigNOT_USED_FOR_NOW != 0 ) + int32_t FF_Utf32stoUtf8s( uint8_t *Utf8String, uint32_t *Utf32String ) + { + int i = 0,y = 0; + + uint16_t utf16buffer[ 2 ]; + + while( Utf32String[ i ] != '\0' ) + { + /* Convert to a UTF16 char. */ + FF_Utf32ctoUtf16c( utf16buffer, Utf32String[ i ], 2 ); + /* Now convert the UTF16 to UTF8 sequence. */ + y += FF_Utf16ctoUtf8c( &Utf8String[ y ], utf16buffer, 4 ); + i++; + } + + Utf8String[ y ] = '\0'; + + return 0; + } /* FF_Utf32stoUtf8s() */ +#endif /* ffconfigNOT_USED_FOR_NOW */ +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_sys.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_sys.c new file mode 100644 index 000000000..d7c2856ef --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_sys.c @@ -0,0 +1,274 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "portable.h" + +#include "ff_headers.h" +#include "ff_sys.h" + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) ( int )( sizeof( x ) / sizeof( x )[ 0 ] ) +#endif + +/* + * Define a collection of 'file systems' as a simple array + */ +typedef struct xSYSTEM +{ + FF_SubSystem_t xSystems[ ffconfigMAX_FILE_SYS ]; + volatile BaseType_t xFileSystemCount; +} ff_sys_t; + + +static ff_sys_t file_systems; +static const char rootDir[] = "/"; + +int FF_FS_Count( void ) +{ + return ( int )file_systems.xFileSystemCount; +} +/*-----------------------------------------------------------*/ + +void FF_FS_Init( void ) +{ + memset( &file_systems, '\0', sizeof( file_systems ) ); + + /* There is always a root file system, even if it doesn't have a + IO manager. */ + file_systems.xFileSystemCount = ( BaseType_t ) 1; + /* Set to "/", second byte is already zero. */ + file_systems.xSystems[ 0 ].pcPath[ 0 ] = ( char ) '/'; + + file_systems.xSystems[ 0 ].xPathlen = 1; +} +/*-----------------------------------------------------------*/ + +int FF_FS_Add( const char *pcPath, FF_Disk_t *pxDisk ) +{ +int iReturn = pdFALSE; + + configASSERT( pxDisk ); + + if( *pcPath != ( char ) '/' ) + { + FF_PRINTF( "FF_FS_Add: Need a \"/\": '%s'\n", pcPath ); + } + else + { + BaseType_t xUseIndex = -1; + size_t uxPathLength = strlen( pcPath ); + + vTaskSuspendAll(); + { + if( file_systems.xFileSystemCount == ( BaseType_t ) 0 ) + { + FF_FS_Init(); + } + + if( uxPathLength == ( size_t ) 1u ) + { + /* This is the "/" path + * and will always be put at index 0 */ + xUseIndex = ( BaseType_t ) 0; + } + else + { + BaseType_t xIndex, xFreeIndex = -1; + FF_SubSystem_t *pxSubSystem = file_systems.xSystems + 1; /* Skip the root entry */ + + for( xIndex = ( BaseType_t ) 1; xIndex < file_systems.xFileSystemCount; xIndex++, pxSubSystem++ ) + { + if( ( pxSubSystem->xPathlen == ( BaseType_t )uxPathLength ) && + ( memcmp( pxSubSystem->pcPath, pcPath, uxPathLength ) == 0 ) ) + { + /* A system is updated with a new handler. */ + xUseIndex = xIndex; + break; + } + if( ( pxSubSystem->pxManager == NULL ) && ( xFreeIndex < 0 ) ) + { + /* Remember the first free slot. */ + xFreeIndex = xIndex; + } + } + if( xUseIndex < ( BaseType_t ) 0 ) + { + if( xFreeIndex >= ( BaseType_t ) 0 ) + { + /* Use the first free slot. */ + xUseIndex = xFreeIndex; + } + else if( file_systems.xFileSystemCount < ARRAY_SIZE( file_systems.xSystems ) ) + { + /* Fill a new entry. */ + xUseIndex = file_systems.xFileSystemCount++; + } + } + } /* uxPathLength != 1 */ + if( xUseIndex >= ( BaseType_t ) 0 ) + { + iReturn = pdTRUE; + strncpy( file_systems.xSystems[ xUseIndex ].pcPath, pcPath, sizeof( file_systems.xSystems[ xUseIndex ].pcPath ) ); + file_systems.xSystems[ xUseIndex ].xPathlen = uxPathLength; + file_systems.xSystems[ xUseIndex ].pxManager = pxDisk->pxIOManager; + } + } + xTaskResumeAll( ); + if( iReturn == pdFALSE ) + { + FF_PRINTF( "FF_FS_Add: Table full '%s' (max = %d)\n", pcPath, (int)ARRAY_SIZE( file_systems.xSystems ) ); + } + } + + return iReturn; +} +/*-----------------------------------------------------------*/ + +void FF_FS_Remove( const char *pcPath ) +{ +BaseType_t xUseIndex, xIndex; +size_t uxPathLength; + + if( pcPath[ 0 ] == ( char ) '/' ) + { + xUseIndex = -1; + uxPathLength = strlen( pcPath ); + /* Is it the "/" path ? */ + if( uxPathLength == ( size_t ) 1u ) + { + xUseIndex = 0; + } + else + { + FF_SubSystem_t *pxSubSystem = file_systems.xSystems + 1; + for( xIndex = 1; xIndex < file_systems.xFileSystemCount; xIndex++, pxSubSystem++ ) + { + if( ( pxSubSystem->xPathlen == ( BaseType_t ) uxPathLength ) && + ( memcmp( pxSubSystem->pcPath, pcPath, uxPathLength ) == 0 ) ) + { + xUseIndex = xIndex; + break; + } + } + } + if( xUseIndex >= 0 ) + { + vTaskSuspendAll(); + { + file_systems.xSystems[ xUseIndex ].pxManager = NULL; + file_systems.xSystems[ xUseIndex ].xPathlen = ( BaseType_t )0; + for( xIndex = file_systems.xFileSystemCount - 1; xIndex > 0; xIndex-- ) + { + if( file_systems.xSystems[ xIndex ].pxManager != NULL ) + { + /* The slot at 'xIndex' is still in use. */ + break; + } + } + file_systems.xFileSystemCount = xIndex + 1; + } + xTaskResumeAll( ); + } + } +} +/*-----------------------------------------------------------*/ + +int FF_FS_Find( const char *pcPath, FF_DirHandler_t *pxHandler ) +{ +FF_SubSystem_t *pxSubSystem; +size_t uxPathLength; +BaseType_t xUseIndex; +int iReturn; + + pxSubSystem = file_systems.xSystems + 1; + uxPathLength = strlen( pcPath ); + + memset( pxHandler, '\0', sizeof( *pxHandler ) ); + for( xUseIndex = 1; xUseIndex < file_systems.xFileSystemCount; xUseIndex++, pxSubSystem++ ) + { + if( ( uxPathLength >= ( size_t ) pxSubSystem->xPathlen ) && + ( memcmp( pxSubSystem->pcPath, pcPath, ( size_t ) pxSubSystem->xPathlen ) == 0 ) && + ( ( pcPath[ pxSubSystem->xPathlen ] == '\0' ) || ( pcPath[ pxSubSystem->xPathlen ] == '/') ) ) /* System "/ram" should not match with "/ramc/etc". */ + { + if( pcPath[ pxSubSystem->xPathlen ] == '\0') + { + pxHandler->pcPath = rootDir; + } + else + { + pxHandler->pcPath = pcPath + pxSubSystem->xPathlen; + } + + pxHandler->pxManager = pxSubSystem->pxManager; + break; + } + } + + if( xUseIndex == file_systems.xFileSystemCount ) + { + pxHandler->pcPath = pcPath; + pxHandler->pxManager = file_systems.xSystems[ 0 ].pxManager; + } + + if( FF_Mounted( pxHandler->pxManager ) ) + { + iReturn = pdTRUE; + } + else + { + iReturn = pdFALSE; + } + + return iReturn; +} +/*-----------------------------------------------------------*/ + +int FF_FS_Get( int xIndex, FF_SubSystem_t *pxSystem ) +{ +int iReturn; + + /* Get a copy of a fs info. */ + if( ( xIndex < 0 ) || ( xIndex >= file_systems.xFileSystemCount ) ) + { + iReturn = pdFALSE; + } + else + { + /* Note: it will copy the contents of 'FF_SubSystem_t'. */ + *pxSystem = file_systems.xSystems[ xIndex ]; + iReturn = pdTRUE; + } + + return iReturn; +} +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_time.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_time.c new file mode 100644 index 000000000..a5e5856a9 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/ff_time.c @@ -0,0 +1,291 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +#include +#include +#include + +#include "FreeRTOS.h" +#include "task.h" + +#include "ff_time.h" + +/** + * @file ff_time.c + * @ingroup TIME + * + * @defgroup TIME Real-Time Clock Interface + * @brief Allows FreeRTOS+FAT to time-stamp files. + * + * Provides a means for receiving the time on any platform. + **/ + +#if( ffconfigTIME_SUPPORT != 0 ) /* This if-block spans the rest of the source file. */ +/** + * @public + * @brief Populates an FF_SystemTime_t object with the current time from the system. + * + * The developer must modify this function so that it is suitable for their platform. + * The function must return with 0, and if the time is not available all elements of the + * FF_SystemTime_t object must be zero'd, as in the examples provided. + * + * @param pxTime Pointer to an FF_TIME object. + * + * @return Always returns 0. + **/ + +int32_t FF_GetSystemTime( FF_SystemTime_t *pxTime ) +{ + FF_TimeStruct_t xTimeStruct; + + /* Fetch the current time. */ + time_t secs = FreeRTOS_time( NULL ); + + /* Fill the fields in 'xTimeStruct'. */ + FreeRTOS_gmtime_r( &secs, &xTimeStruct ); + + pxTime->Hour = xTimeStruct.tm_hour; + pxTime->Minute = xTimeStruct.tm_min; + pxTime->Second = xTimeStruct.tm_sec; + pxTime->Day = xTimeStruct.tm_mday; + pxTime->Month = xTimeStruct.tm_mon + 1; + pxTime->Year = xTimeStruct.tm_year + 1900; + + return 0; +} /* FF_GetSystemTime() */ +/*-----------------------------------------------------------*/ + +/* + * FreeRTOS+FAT + * Time conversion functions: + * + * FF_TimeStruct_t *FreeRTOS_gmtime_r( const time_t *pxTime, FF_TimeStruct_t *pxTimeBuf ) + * time_t FreeRTOS_mktime(FF_TimeStruct_t *pxTimeBuf) +*/ + +#define GMTIME_FIRST_YEAR ( 1970 ) +#define TM_STRUCT_FIRST_YEAR ( 1900 ) +#define SECONDS_PER_MINUTE ( 60 ) +#define MINUTES_PER_HOUR ( 60 ) +#define HOURS_PER_DAY ( 24 ) +#define SECONDS_PER_HOUR ( MINUTES_PER_HOUR * SECONDS_PER_MINUTE ) +#define SECONDS_PER_DAY ( HOURS_PER_DAY * SECONDS_PER_HOUR ) + +/* The first weekday in 'FF_TimeStruct_t' is Sunday. */ +#define WEEK_DAY_SUNDAY 0 +#define WEEK_DAY_MONNDAY 1 +#define WEEK_DAY_TUESDAY 2 +#define WEEK_DAY_WEDNESDAY 3 +#define WEEK_DAY_THURSDAY 4 +#define WEEK_DAY_FRIDAY 5 +#define WEEK_DAY_SATURDAY 6 + +/* Make a bitmask with a '1' for each 31-day month. */ +#define _MM(month) ( 1u << ( month - 1 ) ) +#define MASK_LONG_MONTHS ( _MM(1) | _MM(3) | _MM(5) | _MM(7) | _MM(8) | _MM(10) | _MM(12) ) + +#define DAYS_UNTIL_1970 ( ( 1970 * 365 ) + ( 1970 / 4 ) - ( 1970 / 100 ) + ( 1970 / 400 ) ) +#define DAYS_BEFORE_MARCH ( 59 ) + +static portINLINE int iIsLeapyear( int iYear ) +{ +int iReturn; + + if( ( iYear % 4 ) != 0 ) + { + /* Not a multiple of 4 years. */ + iReturn = pdFALSE; + } + else if( ( iYear % 400 ) == 0 ) + { + /* Every 4 centuries there is a leap year */ + iReturn = pdTRUE; + } + else if( ( iYear % 100 ) == 0 ) + { + /* Other centuries are not a leap year */ + iReturn = pdFALSE; + } + else + { + /* Otherwise every fourth year. */ + iReturn = pdTRUE; + } + + return iReturn; +} + +static portINLINE unsigned long ulDaysPerYear( int iYear ) +{ +int iDays; + + if( iIsLeapyear( iYear ) ) + { + iDays = 366; + } + else + { + iDays = 365; + } + + return iDays; +} + +static int iDaysPerMonth( int iYear, int iMonth ) +{ +int iDays; + + /* Month is zero-based, 1 is February. */ + if (iMonth != 1 ) + { + /* 30 or 31 days? */ + if( ( MASK_LONG_MONTHS & ( 1u << iMonth ) ) != 0 ) + { + iDays = 31; + } + else + { + iDays = 30; + } + } + else if( iIsLeapyear( iYear ) == pdFALSE ) + { + /* February, non leap year. */ + iDays = 28; + } + else + { + /* February, leap year. */ + iDays = 29; + } + return iDays; +} + +FF_TimeStruct_t *FreeRTOS_gmtime_r( const time_t *pxTime, FF_TimeStruct_t *pxTimeBuf ) +{ +time_t xTime = *pxTime; +unsigned long ulDaySeconds, ulDayNumber; +int iYear = GMTIME_FIRST_YEAR; +int iMonth; + + /* Clear all fields, some might not get set here. */ + memset( ( void * )pxTimeBuf, '\0', sizeof( *pxTimeBuf ) ); + + /* Seconds since last midnight. */ + ulDaySeconds = ( unsigned long ) ( xTime % SECONDS_PER_DAY ) ; + + /* Days since 1 Jan 1970. */ + ulDayNumber = ( unsigned long ) ( xTime / SECONDS_PER_DAY ) ; + + /* Today's HH:MM:SS */ + pxTimeBuf->tm_hour = ulDaySeconds / SECONDS_PER_HOUR; + pxTimeBuf->tm_min = ( ulDaySeconds % SECONDS_PER_HOUR ) / 60; + pxTimeBuf->tm_sec = ulDaySeconds % 60; + + /* Today's week day, knowing that 1-1-1970 was a THursday. */ + pxTimeBuf->tm_wday = ( ulDayNumber + WEEK_DAY_THURSDAY ) % 7; + + for( ; ; ) + { + /* Keep subtracting 365 (or 366) days while possible. */ + unsigned long ulDays = ulDaysPerYear( iYear ); + if( ulDayNumber < ulDays ) + { + break; + } + ulDayNumber -= ulDays; + iYear++; + } + /* Subtract 1900. */ + pxTimeBuf->tm_year = iYear - TM_STRUCT_FIRST_YEAR; + + /* The day within this year. */ + pxTimeBuf->tm_yday = ulDayNumber; + + /* Month are counted as 0..11 */ + iMonth = 0; + for( ; ; ) + { + unsigned long ulDays = iDaysPerMonth( iYear, iMonth ); + /* Keep subtracting 30 (or 28, 29, or 31) days while possible. */ + if( ulDayNumber < ulDays ) + { + break; + } + ulDayNumber -= ulDays; + iMonth++; + } + pxTimeBuf->tm_mon = iMonth; + + /* Month days are counted as 1..31 */ + pxTimeBuf->tm_mday = ulDayNumber + 1; + + return pxTimeBuf; +} + +time_t FreeRTOS_mktime( const FF_TimeStruct_t *pxTimeBuf ) +{ +/* Get year AD. */ +int iYear = 1900 + pxTimeBuf->tm_year; /* 20xx */ +/* Get month zero-based. */ +int iMonth = pxTimeBuf->tm_mon; /* 0..11 */ +uint32_t ulDays; +uint32_t ulResult; + + ulDays = pxTimeBuf->tm_mday - 1; /* 1..31 */ + + /* Make March the first month. */ + iMonth -= 2; + if( iMonth < 0 ) + { + /* January or February: leap day has yet to come for this year. */ + iYear--; + iMonth += 12; + } + + /* Add the number of days past until this month. */ + ulDays += ( ( 306 * iMonth ) + 5 ) / 10; + + /* Add days past before this year: */ + ulDays += + + ( iYear * 365 ) /* Every normal year. */ + + ( iYear / 4 ) /* Plus a day for every leap year. */ + - ( iYear / 100 ) /* Minus the centuries. */ + + ( iYear / 400 ) /* Except every fourth century. */ + - ( DAYS_UNTIL_1970 ) /* Minus the days before 1-1-1970 */ + + ( DAYS_BEFORE_MARCH );/* Because 2 months were subtracted. */ + + ulResult = + ( ulDays * SECONDS_PER_DAY ) + + ( pxTimeBuf->tm_hour * SECONDS_PER_HOUR ) + + ( pxTimeBuf->tm_min * SECONDS_PER_MINUTE ) + + pxTimeBuf->tm_sec; + + return ulResult; +} + +#endif /* ffconfigTIME_SUPPORT */ + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/FreeRTOSFATConfigDefaults.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/FreeRTOSFATConfigDefaults.h new file mode 100644 index 000000000..19acb2014 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/FreeRTOSFATConfigDefaults.h @@ -0,0 +1,427 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +#ifndef FF_DEFAULTCONFIG_H + +/* The error numbers defined in this file will be moved to the core FreeRTOS +code in future versions of FreeRTOS - at which time the following header file +will be removed. */ +#include "FreeRTOS_errno_FAT.h" + +#if !defined( ffconfigBYTE_ORDER ) + /* Must be set to either pdFREERTOS_LITTLE_ENDIAN or pdFREERTOS_BIG_ENDIAN, + depending on the endian of the architecture on which FreeRTOS is running. */ + #error Invalid FreeRTOSFATConfig.h file: ffconfigBYTE_ORDER must be set to either pdFREERTOS_LITTLE_ENDIAN or pdFREERTOS_BIG_ENDIAN +#endif + +#if ( ffconfigBYTE_ORDER != pdFREERTOS_LITTLE_ENDIAN ) && ( ffconfigBYTE_ORDER != pdFREERTOS_BIG_ENDIAN ) + #error Invalid FreeRTOSFATConfig.h file: ffconfigBYTE_ORDER must be set to either pdFREERTOS_LITTLE_ENDIAN or pdFREERTOS_BIG_ENDIAN +#endif + +#if ( pdFREERTOS_LITTLE_ENDIAN != 0 ) || ( pdFREERTOS_BIG_ENDIAN != 1 ) + #error Invalid projdefs.h or FreeRTOS_errno_FAT.h file +#endif + +#if !defined( ffconfigHAS_CWD ) + /* Set to 1 to maintain a current working directory (CWD) for each task that + accesses the file system, allowing relative paths to be used. + + Set to 0 not to use a CWD, in which case full paths must be used for each + file access. */ + #define ffconfigHAS_CWD 0 + + #if !defined( ffconfigCWD_THREAD_LOCAL_INDEX ) + #error ffconfigCWD_THREAD_LOCAL_INDEX must be set to a free position within FreeRTOSs thread local storage pointer array for storage of a pointer to the CWD structure. + #endif + +#endif + +#if !defined( ffconfigLFN_SUPPORT ) + /* Set to 1 to include long file name support. Set to 0 to exclude long + file name support. + + If long file name support is excluded then only 8.3 file names can be used. + Long file names will be recognised but ignored. + + Users should familiarise themselves with any patent issues that may + potentially exist around the use of long file names in FAT file systems + before enabling long file name support. */ + #define ffconfigLFN_SUPPORT 0 +#endif + +#if !defined( ffconfigINCLUDE_SHORT_NAME ) + /* Only used when ffconfigLFN_SUPPORT is set to 1. + + Set to 1 to include a file's short name when listing a directory, i.e. when + calling findfirst()/findnext(). The short name will be stored in the + 'pcShortName' field of FF_DirEnt_t. + + Set to 0 to only include a file's long name. */ + #define ffconfigINCLUDE_SHORT_NAME 0 +#endif + +#if !defined( ffconfigSHORTNAME_CASE ) + /* Set to 1 to recognise and apply the case bits used by Windows XP+ when + using short file names - storing file names such as "readme.TXT" or + "SETUP.exe" in a short-name entry. This is the recommended setting for + maximum compatibility. + + Set to 0 to ignore the case bits. */ + #define ffconfigSHORTNAME_CASE 0 +#endif + +#if !defined( ipconfigQUICK_SHORT_FILENAME_CREATION ) + /* This method saves a lot of time when creating directories with + many similar file names: when the short name version of a LFN already + exists, try at most 3 entries with a tilde: + README~1.TXT + README~2.TXT + README~3.TXT + After that create entries with pseudo-random 4-digit hex digits: + REA~E7BB.TXT + REA~BA32.TXT + REA~D394.TXT + */ + #define ipconfigQUICK_SHORT_FILENAME_CREATION 1 +#endif + + /* ASCII versus UNICODE, UTF-16 versus UTF-8 : + FAT directories, when using Long File Names, always store file and directory + names UTF-16 encoded. + The user can select how these names must be represented internally: + - ASCII (default) + - UTF-8 (ffconfigUNICODE_UTF8_SUPPORT = 1) + - UTF-16 (ffconfigUNICODE_UTF16_SUPPORT = 1) + */ +#if( ffconfigUNICODE_UTF16_SUPPORT == 0 ) + /* Only used when ffconfigLFN_SUPPORT is set to 1. + + Set to 1 to use UTF-16 (wide-characters) for file and directory names. + + Set to 0 to use either 8-bit ASCII or UTF-8 for file and directory names + (see the ffconfigUNICODE_UTF8_SUPPORT). */ + #define ffconfigUNICODE_UTF16_SUPPORT 0 +#endif + +#if !defined( ffconfigUNICODE_UTF8_SUPPORT ) + /* Only used when ffconfigLFN_SUPPORT is set to 1. + + Set to 1 to use UTF-8 encoding for file and directory names. + + Set to 0 to use either 8-bit ASCII or UTF-16 for file and directory + names (see the ffconfig_UTF_16_SUPPORT setting). */ + #define ffconfigUNICODE_UTF8_SUPPORT 0 +#endif + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) && ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + #error Can not use both UTF-16 and UTF-8 +#endif + +#if !defined( ffconfigFAT12_SUPPORT ) + /* Set to 1 to include FAT12 support. + + Set to 0 to exclude FAT12 support. + + FAT16 and FAT32 are always enabled. */ + #define ffconfigFAT12_SUPPORT 0 +#endif + +#if !defined( ffconfigOPTIMISE_UNALIGNED_ACCESS ) + /* When writing and reading data, i/o becomes less efficient if sizes other + than 512 bytes are being used. When set to 1 each file handle will + allocate a 512-byte character buffer to facilitate "unaligned access". */ + #define ffconfigOPTIMISE_UNALIGNED_ACCESS 0 +#endif + +#if !defined( ffconfigCACHE_WRITE_THROUGH ) + /* Input and output to a disk uses buffers that are only flushed at the + following times: + + - When a new buffer is needed and no other buffers are available. + - When opening a buffer in READ mode for a sector that has just been changed. + - After creating, removing or closing a file or a directory. + + Normally this is quick enough and it is efficient. If + ffconfigCACHE_WRITE_THROUGH is set to 1 then buffers will also be flushed each + time a buffer is released - which is less efficient but more secure. */ + #define ffconfigCACHE_WRITE_THROUGH 0 +#endif + +#if !defined( ffconfigWRITE_BOTH_FATS ) + /* In most cases, the FAT table has two identical copies on the disk, + allowing the second copy to be used in the case of a read error. If + + Set to 1 to use both FATs - this is less efficient but more secure. + + Set to 0 to use only one FAT - the second FAT will never be written to. */ + #define ffconfigWRITE_BOTH_FATS 0 +#endif + +#if !defined( ffconfigWRITE_FREE_COUNT ) + /* Set to 1 to have the number of free clusters and the first free cluster + to be written to the FS info sector each time one of those values changes. + + Set to 0 not to store these values in the FS info sector, making booting + slower, but making changes faster. */ + #define ffconfigWRITE_FREE_COUNT 0 +#endif + +#if !defined( ffconfigTIME_SUPPORT ) + /* Set to 1 to maintain file and directory time stamps for creation, modify + and last access. + + Set to 0 to exclude time stamps. + + If time support is used, the following function must be supplied: + + time_t FreeRTOS_time( time_t *pxTime ); + + FreeRTOS_time has the same semantics as the standard time() function. */ + #define ffconfigTIME_SUPPORT 0 +#endif + +#if !defined( ffconfigREMOVABLE_MEDIA ) + /* Set to 1 if the media is removable (such as a memory card). + + Set to 0 if the media is not removable. + + When set to 1 all file handles will be "invalidated" if the media is + extracted. If set to 0 then file handles will not be invalidated. + In that case the user will have to confirm that the media is still present + before every access. */ + #define ffconfigREMOVABLE_MEDIA 0 +#endif + +#if !defined( ffconfigMOUNT_FIND_FREE ) + /* Set to 1 to determine the disk's free space and the disk's first free + cluster when a disk is mounted. + + Set to 0 to find these two values when they are first needed. Determining + the values can take some time. */ + #define ffconfigMOUNT_FIND_FREE 0 +#endif + +#if !defined( ffconfigFSINFO_TRUSTED ) + /* Set to 1 to 'trust' the contents of the 'ulLastFreeCluster' and + ulFreeClusterCount fields. + + Set to 0 not to 'trust' these fields.*/ + #define ffconfigFSINFO_TRUSTED 0 +#endif + +#if !defined( ffconfigFINDAPI_ALLOW_WILDCARDS ) + /* For now must be set to 0. */ + #define ffconfigFINDAPI_ALLOW_WILDCARDS 0 +#endif + +#if !defined( ffconfigWILDCARD_CASE_INSENSITIVE ) + /* For now must be set to 0. */ + #define ffconfigWILDCARD_CASE_INSENSITIVE 0 +#endif + +#if !defined( ffconfigPATH_CACHE ) + /* Set to 1 to store recent paths in a cache, enabling much faster access + when the path is deep within a directory structure at the expense of + additional RAM usage. + + Set to 0 to not use a path cache. */ + #define ffconfigPATH_CACHE 0 +#endif + +#if !defined( ffconfigPATH_CACHE_DEPTH ) + /* Only used if ffconfigPATH_CACHE is 1. + + Sets the maximum number of paths that can exist in the patch cache at any + one time. */ + #define ffconfigPATH_CACHE_DEPTH 5 +#endif + +#if !defined( ffconfigHASH_CACHE ) + /* Set to 1 to calculate a HASH value for each existing short file name. + Use of HASH values can improve performance when working with large + directories, or with files that have a similar name. + + Set to 0 not to calculate a HASH value. */ + #define ffconfigHASH_CACHE 0 +#endif + +#if( ffconfigHASH_CACHE != 0 ) + #if !defined( ffconfigHASH_FUNCTION ) + /* Only used if ffconfigHASH_CACHE is set to 1 + + Set to CRC8 or CRC16 to use 8-bit or 16-bit HASH values respectively. */ + #define ffconfigHASH_FUNCTION CRC16 + #endif + + #if ffconfigHASH_FUNCTION == CRC16 + #define ffconfigHASH_TABLE_SIZE 8192 + #elif ffconfigHASH_FUNCTION == CRC8 + #define ffconfigHASH_TABLE_SIZE 32 + #else + #error Invalid Hashing function selected. CRC16 or CRC8. See your FreeRTOSFATConfig.h. + #endif +#endif /* ffconfigHASH_CACHE != 0 */ + +#if !defined( ffconfigMKDIR_RECURSIVE ) + /* Set to 1 to add a parameter to ff_mkdir() that allows an entire directory + tree to be created in one go, rather than having to create one directory in + the tree at a time. For example mkdir( "/etc/settings/network", pdTRUE );. + + Set to 0 to use the normal mkdir() semantics (without the additional + parameter). */ + #define ffconfigMKDIR_RECURSIVE 0 +#endif + +#if !defined( ffconfigMALLOC ) + /* Set to a function that will be used for all dynamic memory allocations. + Setting to pvPortMalloc() will use the same memory allocator as FreeRTOS. */ + #define ffconfigMALLOC( size ) pvPortMalloc( size ) +#endif + +#if !defined( ffconfigFREE ) + /* Set to a function that matches the above allocator defined with + ffconfigMALLOC. Setting to vPortFree() will use the same memory free + function as FreeRTOS. */ + #define ffconfigFREE( ptr ) vPortFree( ptr ) +#endif + +#if !defined( ffconfig64_NUM_SUPPORT ) + /* Set to 1 to calculate the free size and volume size as a 64-bit number. + + Set to 0 to calculate these values as a 32-bit number. */ + #define ffconfig64_NUM_SUPPORT 0 +#endif + +#if !defined( ffconfigMAX_PARTITIONS ) + /* Defines the maximum number of partitions (and also logical partitions) + that can be recognised. */ + #define ffconfigMAX_PARTITIONS 4 +#endif + +#if !defined( ffconfigMAX_FILE_SYS ) + /* Defines how many drives can be combined in total. Should be set to at + least 2. */ + #define ffconfigMAX_FILE_SYS 4 +#endif + +#if !defined( ffconfigDRIVER_BUSY_SLEEP_MS ) + /* In case the low-level driver returns an error 'FF_ERR_DRIVER_BUSY', + the library will pause for a number of ms, defined in + ffconfigDRIVER_BUSY_SLEEP_MS before re-trying. */ + #define ffconfigDRIVER_BUSY_SLEEP_MS 20 +#endif + +#if !defined( ffconfigFPRINTF_SUPPORT ) + /* Set to 1 to include the ff_fprintf() function. + + Set to 0 to exclude the ff_fprintf() function. + + ff_fprintf() is quite a heavy function because it allocates RAM and + brings in a lot of string and variable argument handling code. If + ff_fprintf() is not being used then the code size can be reduced by setting + ffconfigFPRINTF_SUPPORT to 0. */ + #define ffconfigFPRINTF_SUPPORT 0 +#endif + +#if !defined( ffconfigFPRINTF_BUFFER_LENGTH ) + /* ff_fprintf() will allocate a buffer of this size in which it will create + its formatted string. The buffer will be freed before the function + exits. */ + #define ffconfigFPRINTF_BUFFER_LENGTH 128 +#endif + +#if !defined( ffconfigDEBUG ) + #define ffconfigDEBUG 0 +#endif + +#if !defined( ffconfigLONG_ERR_MSG ) + #define ffconfigLONG_ERR_MSG 0 +#endif + +#if( ffconfigDEBUG != 0 ) + #if !defined( ffconfigHAS_FUNCTION_TAB ) + #define ffconfigHAS_FUNCTION_TAB 1 + #endif +#endif + +#if !defined( ffconfigINLINE_MEMORY_ACCESS ) + /* Set to 1 to inline some internal memory access functions. + + Set to 0 to not inline the memory access functions. */ + #define ffconfigINLINE_MEMORY_ACCESS 0 +#endif + +#if !defined( ffconfigMIRROR_FATS_UMOUNT ) + /*_RB_ not sure. */ + #define ffconfigMIRROR_FATS_UMOUNT 0 +#endif + +#if !defined( ffconfigFAT_CHECK ) + /* Officially the only criteria to determine the FAT type (12, 16, or 32 + bits) is the total number of clusters: + if( ulNumberOfClusters < 4085 ) : Volume is FAT12 + if( ulNumberOfClusters < 65525 ) : Volume is FAT16 + if( ulNumberOfClusters >= 65525 ) : Volume is FAT32 + Not every formatted device follows the above rule. + + Set to 1 to perform additional checks over and above inspecting the + number of clusters on a disk to determine the FAT type. + + Set to 0 to only look at the number of clusters on a disk to determine the + FAT type. */ + #define ffconfigFAT_CHECK 0 +#endif + +#if !defined( ffconfigMAX_FILENAME ) + /* Sets the maximum length for file names, including the path. + Note that the value of this define is directly related to the maximum stack + use of the +FAT library. In some API's, a character buffer of size + 'ffconfigMAX_FILENAME' will be declared on stack. */ + #define ffconfigMAX_FILENAME 129 +#endif + +#if !defined( ffconfigUSE_DELTREE ) + /* By default, do not include the recursive function ff_deltree() as + recursion breaches the coding standard - USE WITH CARE. */ + #define ffconfigUSE_DELTREE 0 +#endif + +#if !defined(ffconfigFILE_EXTEND_FLUSHES_BUFFERS) + /* When writing large files, the contents of the FAT entries will be flushed + after every call to FF_Write(). This flushing can be inhibited, by defining + ffconfigFILE_EXTEND_FLUSHES_BUFFERS as 0. */ + #define ffconfigFILE_EXTEND_FLUSHES_BUFFERS 1 +#endif + +#if !defined( FF_PRINTF ) + #define FF_PRINTF FF_PRINTF + static portINLINE void FF_PRINTF( const char *pcFormat, ... ) + { + ( void ) pcFormat; + } +#endif + +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/FreeRTOS_errno_FAT.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/FreeRTOS_errno_FAT.h new file mode 100644 index 000000000..8e8825d97 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/FreeRTOS_errno_FAT.h @@ -0,0 +1,90 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +#ifndef FREERTOS_ERRNO_FAT +#define FREERTOS_ERRNO_FAT + +/* The following definitions will be included in the core FreeRTOS code in +future versions of FreeRTOS - hence the 'pd' (ProjDefs) prefix - at which time +this file will be removed. */ + +/* The following errno values are used by FreeRTOS+ components, not FreeRTOS +itself. */ + +/* For future compatibility (see comment above), check the definitions have not +already been made. */ +#ifndef pdFREERTOS_ERRNO_NONE + #define pdFREERTOS_ERRNO_NONE 0 /* No errors */ + #define pdFREERTOS_ERRNO_ENOENT 2 /* No such file or directory */ + #define pdFREERTOS_ERRNO_EIO 5 /* I/O error */ + #define pdFREERTOS_ERRNO_ENXIO 6 /* No such device or address */ + #define pdFREERTOS_ERRNO_EBADF 9 /* Bad file number */ + #define pdFREERTOS_ERRNO_EAGAIN 11 /* No more processes */ + #define pdFREERTOS_ERRNO_EWOULDBLOCK 11 /* Operation would block */ + #define pdFREERTOS_ERRNO_ENOMEM 12 /* Not enough memory */ + #define pdFREERTOS_ERRNO_EACCES 13 /* Permission denied */ + #define pdFREERTOS_ERRNO_EFAULT 14 /* Bad address */ + #define pdFREERTOS_ERRNO_EBUSY 16 /* Mount device busy */ + #define pdFREERTOS_ERRNO_EEXIST 17 /* File exists */ + #define pdFREERTOS_ERRNO_EXDEV 18 /* Cross-device link */ + #define pdFREERTOS_ERRNO_ENODEV 19 /* No such device */ + #define pdFREERTOS_ERRNO_ENOTDIR 20 /* Not a directory */ + #define pdFREERTOS_ERRNO_EISDIR 21 /* Is a directory */ + #define pdFREERTOS_ERRNO_EINVAL 22 /* Invalid argument */ + #define pdFREERTOS_ERRNO_ENOSPC 28 /* No space left on device */ + #define pdFREERTOS_ERRNO_ESPIPE 29 /* Illegal seek */ + #define pdFREERTOS_ERRNO_EROFS 30 /* Read only file system */ + #define pdFREERTOS_ERRNO_EUNATCH 42 /* Protocol driver not attached */ + #define pdFREERTOS_ERRNO_EBADE 50 /* Invalid exchange */ + #define pdFREERTOS_ERRNO_EFTYPE 79 /* Inappropriate file type or format */ + #define pdFREERTOS_ERRNO_ENMFILE 89 /* No more files */ + #define pdFREERTOS_ERRNO_ENOTEMPTY 90 /* Directory not empty */ + #define pdFREERTOS_ERRNO_ENAMETOOLONG 91 /* File or path name too long */ + #define pdFREERTOS_ERRNO_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ + #define pdFREERTOS_ERRNO_ENOBUFS 105 /* No buffer space available */ + #define pdFREERTOS_ERRNO_ENOPROTOOPT 109 /* Protocol not available */ + #define pdFREERTOS_ERRNO_EADDRINUSE 112 /* Address already in use */ + #define pdFREERTOS_ERRNO_ETIMEDOUT 116 /* Connection timed out */ + #define pdFREERTOS_ERRNO_EINPROGRESS 119 /* Connection already in progress */ + #define pdFREERTOS_ERRNO_EALREADY 120 /* Socket already connected */ + #define pdFREERTOS_ERRNO_EADDRNOTAVAIL 125 /* Address not available */ + #define pdFREERTOS_ERRNO_EISCONN 127 /* Socket is already connected */ + #define pdFREERTOS_ERRNO_ENOTCONN 128 /* Socket is not connected */ + #define pdFREERTOS_ERRNO_ENOMEDIUM 135 /* No medium inserted */ + #define pdFREERTOS_ERRNO_EILSEQ 138 /* An invalid UTF-16 sequence was encountered. */ + #define pdFREERTOS_ERRNO_ECANCELED 140 /* Operation canceled. */ + + /* The following endian values are used by FreeRTOS+ components, not FreeRTOS + itself. */ + #define pdFREERTOS_LITTLE_ENDIAN 0 + #define pdFREERTOS_BIG_ENDIAN 1 + +#endif /* pdFREERTOS_ERRNO_NONE */ + +#endif /* FREERTOS_ERRNO_FAT */ + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_crc.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_crc.h new file mode 100644 index 000000000..636d62c15 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_crc.h @@ -0,0 +1,42 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_crc.h + * @ingroup CRC + * + **/ + +#ifndef _FF_CRC_H_ + +#define _FF_CRC_H_ + +uint8_t FF_GetCRC8( uint8_t *pbyData, uint32_t stLength ); +uint16_t FF_GetCRC16( uint8_t *pbyData, uint32_t stLength ); +uint32_t FF_GetCRC32( uint8_t *pbyData, uint32_t stLength ); +extern const uint32_t crc32_table[256]; + +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_devices.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_devices.h new file mode 100644 index 000000000..33ff8cade --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_devices.h @@ -0,0 +1,64 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_devices.h + **/ +#ifndef FF_DEVICES_H +#define FF_DEVICES_H + +#ifndef PLUS_FAT_H + #error this header will be included from "plusfat.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define FF_DEV_NO_DEV 0 +#define FF_DEV_CHAR_DEV 1 +#define FF_DEV_BLOCK_DEV 2 + +BaseType_t xCheckDevicePath( const char *pcPath ); + +int FF_Device_Seek( FF_FILE *pxStream, long lOffset, int iWhence ); + +BaseType_t FF_Device_Open( const char *pcPath, FF_FILE * pxStream ); + +void FF_Device_Close( FF_FILE * pxStream ); + +size_t FF_Device_Read( void *pvBuf, size_t lSize, size_t lCount, FF_FILE * pxStream ); + +size_t FF_Device_Write( const void *pvBuf, size_t lSize, size_t lCount, FF_FILE * pxStream ); + + +int FF_Device_GetDirEnt( const char *pcPath, FF_DirEnt_t *pxDirEnt ); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* FF_DEVICES_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_dir.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_dir.h new file mode 100644 index 000000000..0253fb0d8 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_dir.h @@ -0,0 +1,205 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_dir.h + * @ingroup DIR + **/ +#ifndef _FF_DIR_H_ + +#define _FF_DIR_H_ + +#ifndef PLUS_FAT_H + #error this header will be included from "plusfat.h" +#endif + +#define FIND_FLAG_SHORTNAME_SET 0x01u +#define FIND_FLAG_SHORTNAME_CHECKED 0x02u +#define FIND_FLAG_SHORTNAME_FOUND 0x04u +#define FIND_FLAG_FITS_SHORT 0x08u +#define FIND_FLAG_SIZE_OK 0x10u +#define FIND_FLAG_CREATE_FLAG 0x20u + +#define FIND_FLAG_FITS_SHORT_OK ( FIND_FLAG_FITS_SHORT | FIND_FLAG_SIZE_OK ) + +typedef struct +{ + uint32_t ulChainLength; + uint32_t ulDirCluster; + uint32_t ulCurrentClusterLCN; + uint32_t ulCurrentClusterNum; + FF_Buffer_t *pxBuffer; +} FF_FetchContext_t; + +typedef struct +{ + uint32_t ulFileSize; + uint32_t ulObjectCluster; + + /* Book Keeping. */ + uint32_t ulCurrentCluster; + uint32_t ulAddrCurrentCluster; + uint32_t ulDirCluster; + uint16_t usCurrentItem; + /* End Book Keeping. */ + +#if( ffconfigTIME_SUPPORT != 0 ) + FF_SystemTime_t xCreateTime; /* Date and Time Created. */ + FF_SystemTime_t xModifiedTime; /* Date and Time Modified. */ + FF_SystemTime_t xAccessedTime; /* Date of Last Access. */ +#endif + +#if( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 ) + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_T_WCHAR pcWildCard[ ffconfigMAX_FILENAME ]; + #else + char pcWildCard[ ffconfigMAX_FILENAME ]; + #endif + BaseType_t xInvertWildCard; +#endif + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_T_WCHAR pcFileName[ ffconfigMAX_FILENAME ]; +#else + char pcFileName[ ffconfigMAX_FILENAME ]; +#endif + +#if( ffconfigLFN_SUPPORT != 0 ) && ( ffconfigINCLUDE_SHORT_NAME != 0 ) + char pcShortName[ 13 ]; +#endif + uint8_t ucAttrib; +#if( ffconfigDEV_SUPPORT != 0 ) + uint8_t ucIsDeviceDir; +#endif + FF_FetchContext_t xFetchContext; +} FF_DirEnt_t; + + + +/* + * Some public API's, i.e. they're used but ff_stdio.c + */ +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_Error_t FF_FindFirst( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirent, const FF_T_WCHAR *pcPath ); + FF_Error_t FF_MkDir( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *pcPath ); +#else + FF_Error_t FF_FindFirst( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirent, const char *pcPath ); + FF_Error_t FF_MkDir( FF_IOManager_t *pxIOManager, const char *pcPath ); +#endif + +FF_Error_t FF_FindNext( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirent ); + +static portINLINE void FF_RewindFind( FF_DirEnt_t *pxDirent ) +{ + pxDirent->usCurrentItem = 0; +} + +/* + * Some API's internal to the +FAT library. + */ +FF_Error_t FF_GetEntry( FF_IOManager_t *pxIOManager, uint16_t usEntry, uint32_t ulDirCluster, FF_DirEnt_t *pxDirent ); +FF_Error_t FF_PutEntry( FF_IOManager_t *pxIOManager, uint16_t usEntry, uint32_t ulDirCluster, FF_DirEnt_t *pxDirent, uint8_t *pucContents ); +int8_t FF_FindEntry( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, int8_t *Name, FF_DirEnt_t *pxDirent, BaseType_t LFNs ); + +void FF_PopulateShortDirent( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirent, const uint8_t *pucEntryBuffer ); +FF_Error_t FF_PopulateLongDirent( FF_IOManager_t *pxIOManager, FF_DirEnt_t *pxDirent, uint16_t usEntry, FF_FetchContext_t *pFetchContext ); + +FF_Error_t FF_InitEntryFetch( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, FF_FetchContext_t *pContext ); +FF_Error_t FF_FetchEntryWithContext( FF_IOManager_t *pxIOManager, uint32_t ulEntry, FF_FetchContext_t *pContext, uint8_t *pEntryBuffer ); +FF_Error_t FF_PushEntryWithContext( FF_IOManager_t *pxIOManager, uint32_t ulEntry, FF_FetchContext_t *pContext, uint8_t *pEntryBuffer ); +FF_Error_t FF_CleanupEntryFetch( FF_IOManager_t *pxIOManager, FF_FetchContext_t *pContext ); + +int8_t FF_PushEntry( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, uint16_t usEntry, uint8_t *buffer, void *pParam ); + +static portINLINE BaseType_t FF_isEndOfDir( const uint8_t *pucEntryBuffer ) +{ + return pucEntryBuffer[ 0 ] == ( uint8_t ) 0; +} + +static portINLINE BaseType_t FF_isDeleted( const uint8_t *pucEntryBuffer ) +{ + return pucEntryBuffer[ 0 ] == ( uint8_t ) FF_FAT_DELETED; +} + +struct _FF_FIND_PARAMS +{ + uint32_t ulDirCluster; /* The beginning cluster of this directory. */ + int32_t lFreeEntry; /* The first free entry big enough to add the file. */ + uint32_t ulFlags; /* See FIND_FLAG_xxx defines above. */ + char pcEntryBuffer[ 32 ]; /* LFN converted to short name. */ + uint8_t ucCaseAttrib; + uint8_t ucFirstTilde; +}; + +typedef struct _FF_FIND_PARAMS FF_FindParams_t; + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + uint32_t FF_CreateFile( FF_IOManager_t *pxIOManager, FF_FindParams_t *findParams, FF_T_WCHAR *FileName, + FF_DirEnt_t *pxDirent, FF_Error_t *pError ); + + uint32_t FF_FindEntryInDir( FF_IOManager_t *pxIOManager, FF_FindParams_t *findParams, const FF_T_WCHAR *name, + uint8_t pa_Attrib, FF_DirEnt_t *pxDirent, FF_Error_t *pError ); + + uint32_t FF_FindDir( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *pcPath, uint16_t pathLen, FF_Error_t *pError ); + void FF_CreateShortName( FF_FindParams_t *pxFindParams, const FF_T_WCHAR *pcLongName ); +#else + uint32_t FF_CreateFile( FF_IOManager_t *pxIOManager, FF_FindParams_t *findParams, char *FileName, + FF_DirEnt_t *pxDirent, FF_Error_t *pError ); + + uint32_t FF_FindEntryInDir( FF_IOManager_t *pxIOManager, FF_FindParams_t *findParams, const char *name, + uint8_t pa_Attrib, FF_DirEnt_t *pxDirent, FF_Error_t *pError ); + + uint32_t FF_FindDir( FF_IOManager_t *pxIOManager, const char *pcPath, uint16_t pathLen, FF_Error_t *pError ); + void FF_CreateShortName( FF_FindParams_t *pxFindParams, const char *pcLongName ); +#endif + +int32_t FF_FindShortName( FF_IOManager_t *pxIOManager, FF_FindParams_t *findParams ); + +FF_Error_t FF_CreateDirent( FF_IOManager_t *pxIOManager, FF_FindParams_t *findParams, FF_DirEnt_t *pxDirent ); +FF_Error_t FF_ExtendDirectory( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster ); +FF_Error_t FF_RmLFNs( FF_IOManager_t *pxIOManager, uint16_t usDirEntry, FF_FetchContext_t *pContext ); + +#if( ffconfigHASH_CACHE != 0 ) + BaseType_t FF_CheckDirentHash( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, uint32_t ulHash ); + BaseType_t FF_DirHashed( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster ); + void FF_AddDirentHash( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster, uint32_t ulHash ); + FF_Error_t FF_HashDir( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster ); + void FF_UnHashDir( FF_IOManager_t *pxIOManager, uint32_t ulDirCluster ); +#endif + +struct SBuffStats { + unsigned sectorMatch; + unsigned sectorMiss; + unsigned bufCounts; + unsigned bufCalls; +}; + +extern struct SBuffStats buffStats; + +#endif + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_error.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_error.h new file mode 100644 index 000000000..6b631e4c8 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_error.h @@ -0,0 +1,260 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +#ifndef _FF_ERROR_H_ +#define _FF_ERROR_H_ + +/** + * @file ff_error.h + * @ingroup ERROR + **/ + +/** + * Error codes are 32-bit numbers, and consist of three items: + * 1Bit 7Bits 8Bits 16Bits + * . ........ ........ ........ ........ + * [ErrFlag][ModuleID][FunctionID][-- ERROR CODE --] + * + * Error Codes should always have the ErrFlag set, this is the reason why all module + * codes include it. + * + * When returning an error simply return the defined Error Code, OR'd with the function + * name (capitalised) in which the error has occurred. + * + * When receiving an Error code from another layer, do not modify the code, as this will + * prevent the error code from containing the origin of the error, simply pass it to the + * next layer. + * + * Some API's have been defined to provide, useful and meaningful Error messages to the + * the 'userspace' application layer. + * + **/ + +#define FF_MODULE_SHIFT 24 +#define FF_FUNCTION_SHIFT 16 + +#define FF_GETERROR( x ) ( ( ( unsigned ) x ) & 0xFFFF ) +#define FF_GETMODULE( x ) ( ( ( ( unsigned ) x ) >> FF_MODULE_SHIFT ) & 0x7F ) +#define FF_GETFUNCTION( x ) ( ( ( ( unsigned ) x ) >> FF_FUNCTION_SHIFT ) & 0xFF ) +#define FF_GETMOD_FUNC( x ) ( ( ( ( unsigned ) x ) >> FF_FUNCTION_SHIFT ) & 0xFFFF ) +#define FF_ERRFLAG 0x80000000 +#define FF_isERR( x ) ( ( ( x ) & FF_ERRFLAG ) != 0 ) + +/*----- FreeRTOS+FAT Module Identifiers */ +#define FF_MODULE_IOMAN ( ( 1 << FF_MODULE_SHIFT ) | FF_ERRFLAG ) +#define FF_MODULE_DIR ( ( 2 << FF_MODULE_SHIFT ) | FF_ERRFLAG ) +#define FF_MODULE_FILE ( ( 3 << FF_MODULE_SHIFT ) | FF_ERRFLAG ) +#define FF_MODULE_FAT ( ( 4 << FF_MODULE_SHIFT ) | FF_ERRFLAG ) +#define FF_MODULE_CRC ( ( 5 << FF_MODULE_SHIFT ) | FF_ERRFLAG ) +#define FF_MODULE_FORMAT ( ( 6 << FF_MODULE_SHIFT ) | FF_ERRFLAG ) +#define FF_MODULE_MEMORY ( ( 7 << FF_MODULE_SHIFT ) | FF_ERRFLAG ) +#define FF_MODULE_STRING ( ( 8 << FF_MODULE_SHIFT ) | FF_ERRFLAG ) +#define FF_MODULE_LOCKING ( ( 9 << FF_MODULE_SHIFT ) | FF_ERRFLAG ) +#define FF_MODULE_TIME ( ( 10 << FF_MODULE_SHIFT ) | FF_ERRFLAG ) +#define FF_MODULE_DRIVER ( ( 11 << FF_MODULE_SHIFT ) | FF_ERRFLAG ) +#define FF_MODULE_STDIO ( ( 12 << FF_MODULE_SHIFT ) | FF_ERRFLAG ) + +/*----- FreeRTOS+FAT Function Identifiers (In Modular Order) */ +/*----- FF_IOManager_t - The FreeRTOS+FAT I/O Manager. */ +#define FF_CREATEIOMAN ( ( 1 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) +#define FF_DESTROYIOMAN ( ( 2 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) +#define FF_MOUNT ( ( 3 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) +#define FF_UNMOUNT ( ( 4 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) +#define FF_FLUSHCACHE ( ( 5 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) +#define FF_GETPARTITIONBLOCKSIZE ( ( 6 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) +#define FF_BLOCKREAD ( ( 7 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) +#define FF_BLOCKWRITE ( ( 8 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) +#define FF_DETERMINEFATTYPE ( ( 9 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) +#define FF_GETEFIPARTITIONENTRY ( ( 10 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) +#define FF_USERDRIVER ( ( 11 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) +#define FF_DECREASEFREECLUSTERS ( ( 12 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) +#define FF_INCREASEFREECLUSTERS ( ( 13 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) +#define FF_PARTITIONSEARCH ( ( 14 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) +#define FF_PARSEEXTENDED ( ( 15 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN ) + + +/*----- FreeRTOS+FAT Return codes for user Rd/Wr routines */ + +#define FF_ERR_DRIVER_NOMEDIUM ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_USERDRIVER | FF_MODULE_DRIVER ) +#define FF_ERR_DRIVER_BUSY ( FF_ERR_IOMAN_DRIVER_BUSY | FF_USERDRIVER | FF_MODULE_DRIVER ) +#define FF_ERR_DRIVER_FATAL_ERROR ( FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_USERDRIVER | FF_MODULE_DRIVER ) + +/*----- FF_DIR - The FreeRTOS+FAT directory handling routines. */ +#define FF_FETCHENTRYWITHCONTEXT ( ( 1 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR ) +#define FF_PUSHENTRYWITHCONTEXT ( ( 2 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR ) +#define FF_GETENTRY ( ( 3 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR ) +#define FF_FINDFIRST ( ( 4 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR ) +#define FF_FINDNEXT ( ( 5 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR ) +#define FF_REWINDFIND ( ( 6 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR ) +#define FF_FINDFREEDIRENT ( ( 7 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR ) +#define FF_PUTENTRY ( ( 8 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR ) +#define FF_CREATESHORTNAME ( ( 9 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR ) +#define FF_CREATELFNS ( ( 10 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR ) +#define FF_EXTENDDIRECTORY ( ( 11 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR ) +#define FF_MKDIR ( ( 12 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR ) +#define FF_TRAVERSE ( ( 13 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR ) +#define FF_FINDDIR ( ( 14 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR ) + +/*----- FF_FILE - The FreeRTOS+FAT file handling routines. */ +#define FF_GETMODEBITS ( ( 1 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_OPEN ( ( 2 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_ISDIREMPTY ( ( 3 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_RMDIR ( ( 4 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_RMFILE ( ( 5 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_MOVE ( ( 6 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_ISEOF ( ( 7 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_GETSEQUENTIALCLUSTERS ( ( 8 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_READCLUSTERS ( ( 9 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_EXTENDFILE ( ( 10 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_WRITECLUSTERS ( ( 11 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_READ ( ( 12 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_GETC ( ( 13 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_GETLINE ( ( 14 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_TELL ( ( 15 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_WRITE ( ( 16 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_PUTC ( ( 17 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_SEEK ( ( 18 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_INVALIDATE ( ( 19 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_CHECKVALID ( ( 20 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_CLOSE ( ( 21 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_SETTIME ( ( 22 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_BYTESLEFT ( ( 23 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_SETFILETIME ( ( 24 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_INITBUF ( ( 25 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) +#define FF_SETEOF ( ( 26 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE ) + +/*----- FF_FAT - The FreeRTOS+FAT FAT handling routines. */ +#define FF_GETFATENTRY ( ( 1 << FF_FUNCTION_SHIFT ) | FF_MODULE_FAT ) +#define FF_CLEARCLUSTER ( ( 2 << FF_FUNCTION_SHIFT ) | FF_MODULE_FAT ) +#define FF_PUTFATENTRY ( ( 3 << FF_FUNCTION_SHIFT ) | FF_MODULE_FAT ) +#define FF_FINDFREECLUSTER ( ( 4 << FF_FUNCTION_SHIFT ) | FF_MODULE_FAT ) +#define FF_COUNTFREECLUSTERS ( ( 5 << FF_FUNCTION_SHIFT ) | FF_MODULE_FAT ) + +/*----- FF_FORMAT - The FreeRTOS+FAT format routine */ +#define FF_FORMATPARTITION ( ( 1 << FF_FUNCTION_SHIFT ) | FF_MODULE_FORMAT ) + +/*----- FF_UNICODE - The FreeRTOS+FAT unicode routines. */ +#define FF_UTF8CTOUTF16C ( ( 1 << FF_FUNCTION_SHIFT ) | FF_MODULE_STRING ) +#define FF_UTF16CTOUTF8C ( ( 2 << FF_FUNCTION_SHIFT ) | FF_MODULE_STRING ) +#define FF_UTF32CTOUTF16C ( ( 3 << FF_FUNCTION_SHIFT ) | FF_MODULE_STRING ) +#define FF_UTF16CTOUTF32C ( ( 4 << FF_FUNCTION_SHIFT ) | FF_MODULE_STRING ) + + +/*----- FF_STDIO - The stdio-interface to FreeRTOS+FAT. */ +#define FF_CHMOD ( ( 1 << FF_FUNCTION_SHIFT ) | FF_MODULE_STDIO ) +#define FF_STAT_FUNC ( ( 2 << FF_FUNCTION_SHIFT ) | FF_MODULE_STDIO ) + +/* FreeRTOS+FAT defines different Error-Code spaces for each module. This ensures + that all error codes remain unique, and their meaning can be quickly identified. +*/ +/* Global Error Codes */ +#define FF_ERR_NONE 0 /* No Error */ +/*#define FF_ERR_GENERIC 1*/ /* BAD NEVER USE THIS! -- Therefore commented out. */ +#define FF_ERR_NULL_POINTER 2 /* Parameter was NULL. */ +#define FF_ERR_NOT_ENOUGH_MEMORY 3 /* malloc() failed! - Could not allocate handle memory. */ +#define FF_ERR_DEVICE_DRIVER_FAILED 4 /* The Block Device driver reported a FATAL error, cannot continue. */ + +/* User return codes for Rd/Wr functions: */ +#define FF_ERR_IOMAN_DRIVER_NOMEDIUM 8 +#define FF_ERR_IOMAN_DRIVER_BUSY 9 +#define FF_ERR_IOMAN_DRIVER_FATAL_ERROR 10 + +/* IOMAN Error Codes */ +#define FF_ERR_IOMAN_BAD_BLKSIZE 11 /* The provided blocksize was not a multiple of 512. */ +#define FF_ERR_IOMAN_BAD_MEMSIZE 12 /* The memory size was not a multiple of the blocksize. */ +#define FF_ERR_IOMAN_DEV_ALREADY_REGD 13 /* Device was already registered. Use FF_UnRegister() to re-use this IOMAN with another device. */ +#define FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION 14 /* A mountable partition could not be found on the device. */ +#define FF_ERR_IOMAN_INVALID_FORMAT 15 +#define FF_ERR_IOMAN_INVALID_PARTITION_NUM 16 /* The partition number provided was out of range. */ +#define FF_ERR_IOMAN_NOT_FAT_FORMATTED 17 /* The partition did not look like a FAT partition. */ +#define FF_ERR_IOMAN_DEV_INVALID_BLKSIZE 18 /* IOMAN object BlkSize is not compatible with the blocksize of this device driver. */ +#define FF_ERR_IOMAN_PARTITION_MOUNTED 19 /* Device is in use by an actively mounted partition. Unmount the partition first. */ +#define FF_ERR_IOMAN_ACTIVE_HANDLES 20 /* The partition cannot be unmounted until all active file handles are closed. (There may also be active handles on the cache). */ +#define FF_ERR_IOMAN_GPT_HEADER_CORRUPT 21 /* The GPT partition table appears to be corrupt, refusing to mount. */ +#define FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE 22 +#define FF_ERR_IOMAN_OUT_OF_BOUNDS_READ 23 +#define FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE 24 + +/* File Error Codes 30 + */ +#define FF_ERR_FILE_ALREADY_OPEN 30 /* File is in use. */ +#define FF_ERR_FILE_NOT_FOUND 31 /* File was not found. */ +#define FF_ERR_FILE_OBJECT_IS_A_DIR 32 /* Tried to FF_Open() a Directory. */ +#define FF_ERR_FILE_IS_READ_ONLY 33 /* Tried to FF_Open() a file marked read only. */ +#define FF_ERR_FILE_INVALID_PATH 34 /* The path of the file was not found. */ +#define FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE 35 +#define FF_ERR_FILE_NOT_OPENED_IN_READ_MODE 36 +#define FF_ERR_FILE_EXTEND_FAILED 37 /* Could not extend the file. */ +#define FF_ERR_FILE_DESTINATION_EXISTS 38 +#define FF_ERR_FILE_SOURCE_NOT_FOUND 39 +#define FF_ERR_FILE_DIR_NOT_FOUND 40 +#define FF_ERR_FILE_COULD_NOT_CREATE_DIRENT 41 +#define FF_ERR_FILE_BAD_HANDLE 42 /* A file handle was invalid */ +#define FF_ERR_FILE_MEDIA_REMOVED 43 /* File handle got invalid because media was removed */ +#define FF_ERR_FILE_READ_ZERO 44 /* Used internally. */ +#define FF_ERR_FILE_SEEK_INVALID_ORIGIN 45 /* Seeking beyond end of file. */ +#define FF_ERR_FILE_SEEK_INVALID_POSITION 46 /* Bad value for the 'whence' parameter. */ + +/* Directory Error Codes 50 + */ +#define FF_ERR_DIR_OBJECT_EXISTS 50 /* A file or folder of the same name already exists in the current directory. */ +#define FF_ERR_DIR_DIRECTORY_FULL 51 /* No more items could be added to the directory. */ +#define FF_ERR_DIR_END_OF_DIR 52 /*/ */ +#define FF_ERR_DIR_NOT_EMPTY 53 /* Cannot delete a directory that contains files or folders. */ +#define FF_ERR_DIR_INVALID_PATH 54 /* Could not find the directory specified by the path. */ +#define FF_ERR_DIR_INVALID_PARAMETER 55 /* Could not find the directory specified by the path. */ +#define FF_ERR_DIR_CANT_EXTEND_ROOT_DIR 56 /* Can't extend the root dir. */ +#define FF_ERR_DIR_EXTEND_FAILED 57 /* Not enough space to extend the directory. */ +#define FF_ERR_DIR_NAME_TOO_LONG 58 /* Name exceeds the number of allowed characters for a filename. */ + +/* Fat Error Codes 70 + */ +#define FF_ERR_FAT_NO_FREE_CLUSTERS 70 /* No more free space is available on the disk. */ + +/* UNICODE Error Codes 100 + */ +#define FF_ERR_UNICODE_INVALID_CODE 100 /* An invalid Unicode character was provided! */ +#define FF_ERR_UNICODE_DEST_TOO_SMALL 101 /* Not enough space in the UTF-16 buffer to encode the entire sequence as UTF-16. */ +#define FF_ERR_UNICODE_INVALID_SEQUENCE 102 /* An invalid UTF-16 sequence was encountered. */ +#define FF_ERR_UNICODE_CONVERSION_EXCEEDED 103 /* Filename exceeds MAX long-filename length when converted to UTF-16. */ + +typedef int32_t FF_Error_t; + +#if( ffconfigDEBUG != 0 ) + const char *FF_GetErrMessage( FF_Error_t iErrorCode ); + const char *FF_GetErrModule( FF_Error_t iErrorCode ); + const char *FF_GetErrFunction( FF_Error_t iErrorCode ); + const char *FF_GetErrDescription( FF_Error_t iErrorCode, char *pcBuffer, int iMaxLength ); /* Get the complete description */ +#else /* ffconfigDEBUG */ + #define FF_GetErrMessage( X ) "" /* A special MACRO in case FF_GetErrMessage() isn't gated with ffconfigDEBUG */ + #define FF_GetErrModule( X ) "" + #define FF_GetErrFunction( X ) "" + static portINLINE const char *FF_GetErrDescription( FF_Error_t iErrorCode, char *pcBuffer, int iMaxLength ) + { + ( void ) iErrorCode; + ( void ) iMaxLength; + strcpy( pcBuffer, "unknown" ); + return pcBuffer; + } +#endif /* Function call is safely replaced with a NULL string. */ + +#endif /* INCLUDE GUARD END */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_fat.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_fat.h new file mode 100644 index 000000000..2d7e9b0e8 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_fat.h @@ -0,0 +1,128 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_fat.h + * @ingroup FAT + **/ + +#ifndef _FF_FAT_H_ +#define _FF_FAT_H_ + +#ifndef PLUS_FAT_H + #error this header will be included from "plusfat.h" +#endif + +/*---------- ERROR CODES */ + + +/*---------- PROTOTYPES */ + +/* HT statistics Will be taken away after testing: */ +#if( ffconfigFAT_USES_STAT != 0 ) +struct SFatStat +{ + unsigned initCount; + unsigned clearCount; + unsigned getCount[2]; /* Index 0 for READ counts, index 1 for WRITE counts. */ + unsigned reuseCount[2]; + unsigned missCount[2]; +}; + +extern struct SFatStat fatStat; +#endif + +#if( ffconfigWRITE_BOTH_FATS != 0 ) + #define ffconfigBUF_STORE_COUNT 2 +#else + #define ffconfigBUF_STORE_COUNT 1 +#endif + +typedef struct _FatBuffers +{ + FF_Buffer_t *pxBuffers[ffconfigBUF_STORE_COUNT]; + uint8_t ucMode; /* FF_MODE_READ or WRITE. */ +} FF_FATBuffers_t; + +uint32_t FF_getClusterPosition( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize ); +uint32_t FF_getClusterChainNumber( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize ); +uint32_t FF_getMajorBlockNumber( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize ); +uint32_t FF_getMinorBlockNumber( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize ); +uint32_t FF_getMinorBlockEntry( FF_IOManager_t *pxIOManager, uint32_t ulEntry, uint32_t ulEntrySize ); + +/* A partition may define a block size larger than 512 bytes (at offset 0x0B of the PBR). +This function translates a block address to an address based on 'pxIOManager->usBlkSize', +which is usually 512 bytes. +*/ +static portINLINE uint32_t FF_getRealLBA( FF_IOManager_t *pxIOManager, uint32_t LBA ) +{ + return LBA * pxIOManager->xPartition.ucBlkFactor; +} + +uint32_t FF_Cluster2LBA( FF_IOManager_t *pxIOManager, uint32_t ulCluster ); +uint32_t FF_LBA2Cluster( FF_IOManager_t *pxIOManager, uint32_t ulAddress ); +uint32_t FF_getFATEntry( FF_IOManager_t *pxIOManager, uint32_t ulCluster, FF_Error_t *pxError, FF_FATBuffers_t *pxFATBuffers ); +FF_Error_t FF_putFATEntry( FF_IOManager_t *pxIOManager, uint32_t ulCluster, uint32_t ulValue, FF_FATBuffers_t *pxFATBuffers ); +BaseType_t FF_isEndOfChain( FF_IOManager_t *pxIOManager, uint32_t ulFatEntry ); +uint32_t FF_FindFreeCluster( FF_IOManager_t *pxIOManager, FF_Error_t *pxError, BaseType_t aDoClaim ); +uint32_t FF_ExtendClusterChain( FF_IOManager_t *pxIOManager, uint32_t ulStartCluster, uint32_t ulCount ); +FF_Error_t FF_UnlinkClusterChain( FF_IOManager_t *pxIOManager, uint32_t ulStartCluster, BaseType_t xDoTruncate ); +uint32_t FF_TraverseFAT( FF_IOManager_t *pxIOManager, uint32_t ulStart, uint32_t ulCount, FF_Error_t *pxError ); +uint32_t FF_CreateClusterChain( FF_IOManager_t *pxIOManager, FF_Error_t *pxError ); +uint32_t FF_GetChainLength( FF_IOManager_t *pxIOManager, uint32_t pa_nStartCluster, uint32_t *piEndOfChain, FF_Error_t *pxError ); +uint32_t FF_FindEndOfChain( FF_IOManager_t *pxIOManager, uint32_t Start, FF_Error_t *pxError ); +FF_Error_t FF_ClearCluster( FF_IOManager_t *pxIOManager, uint32_t ulCluster ); + +#if( ffconfig64_NUM_SUPPORT != 0 ) + uint64_t FF_GetFreeSize( FF_IOManager_t *pxIOManager, FF_Error_t *pxError ); +#else + uint32_t FF_GetFreeSize( FF_IOManager_t *pxIOManager, FF_Error_t *pxError ); +#endif + +/* WARNING: If this prototype changes, it must be updated in ff_ioman.c also! */ +uint32_t FF_CountFreeClusters( FF_IOManager_t *pxIOManager, FF_Error_t *pxError ); + +FF_Error_t FF_ReleaseFATBuffers( FF_IOManager_t *pxIOManager, FF_FATBuffers_t *pxFATBuffers ); + +static portINLINE void FF_InitFATBuffers( FF_FATBuffers_t *pxFATBuffers, uint8_t ucMode ) +{ + pxFATBuffers->pxBuffers[ 0 ] = NULL; +#if ffconfigBUF_STORE_COUNT > 1 + pxFATBuffers->pxBuffers[ 1 ] = NULL; +#endif +#if ffconfigBUF_STORE_COUNT > 2 + #error Please check this code, maybe it is time to use memset +#endif + pxFATBuffers->ucMode = ucMode; /* FF_MODE_READ/WRITE */ + #if ffconfigFAT_USES_STAT + { + fatStat.initCount++; + } + #endif +} + +#endif + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_fatdef.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_fatdef.h new file mode 100644 index 000000000..7ea4f7b2c --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_fatdef.h @@ -0,0 +1,109 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +#ifndef _FF_FATDEF_H_ +#define _FF_FATDEF_H_ + +/* + This file defines offsets to various data for the FAT specification. +*/ + +/* MBR / PBR Offsets. */ + +#define FF_FAT_BYTES_PER_SECTOR 0x00B +#define FF_FAT_SECTORS_PER_CLUS 0x00D +#define FF_FAT_RESERVED_SECTORS 0x00E +#define FF_FAT_NUMBER_OF_FATS 0x010 +#define FF_FAT_ROOT_ENTRY_COUNT 0x011 +#define FF_FAT_16_TOTAL_SECTORS 0x013 +#define FF_FAT_MEDIA_TYPE 0x015 + +#define FF_FAT_32_TOTAL_SECTORS 0x020 +#define FF_FAT_16_SECTORS_PER_FAT 0x016 +#define FF_FAT_32_SECTORS_PER_FAT 0x024 +#define FF_FAT_ROOT_DIR_CLUSTER 0x02C +#define FF_FAT_EXT_BOOT_SIGNATURE 0x042 + +#define FF_FAT_16_VOL_LABEL 0x02B +#define FF_FAT_32_VOL_LABEL 0x047 + +#define FF_FAT_PTBL 0x1BE +#define FF_FAT_PTBL_LBA 0x008 +#define FF_FAT_PTBL_SECT_COUNT 0x00C +#define FF_FAT_PTBL_ACTIVE 0x000 +#define FF_FAT_PTBL_ID 0x004 + +#define FF_DOS_EXT_PART 0x05 +#define FF_LINUX_EXT_PART 0x85 +#define FF_WIN98_EXT_PART 0x0f + +#define FF_FAT_MBR_SIGNATURE 0x1FE + +#define FF_FAT_DELETED 0xE5 + +/* Directory Entry Offsets. */ +#define FF_FAT_DIRENT_SHORTNAME 0x000 +#define FF_FAT_DIRENT_ATTRIB 0x00B +#define FF_FAT_DIRENT_CREATE_TIME 0x00E /* Creation Time. */ +#define FF_FAT_DIRENT_CREATE_DATE 0x010 /* Creation Date. */ +#define FF_FAT_DIRENT_LASTACC_DATE 0x012 /* Date of Last Access. */ +#define FF_FAT_DIRENT_CLUS_HIGH 0x014 +#define FF_FAT_DIRENT_LASTMOD_TIME 0x016 /* Time of Last modification. */ +#define FF_FAT_DIRENT_LASTMOD_DATE 0x018 /* Date of Last modification. */ +#define FF_FAT_DIRENT_CLUS_LOW 0x01A +#define FF_FAT_DIRENT_FILESIZE 0x01C +#define FF_FAT_LFN_ORD 0x000 +#define FF_FAT_LFN_NAME_1 0x001 +#define FF_FAT_LFN_CHECKSUM 0x00D +#define FF_FAT_LFN_NAME_2 0x00E +#define FF_FAT_LFN_NAME_3 0x01C + +/* Dirent Attributes. */ +#define FF_FAT_ATTR_READONLY 0x01 +#define FF_FAT_ATTR_HIDDEN 0x02 +#define FF_FAT_ATTR_SYSTEM 0x04 +#define FF_FAT_ATTR_VOLID 0x08 +#define FF_FAT_ATTR_DIR 0x10 +#define FF_FAT_ATTR_ARCHIVE 0x20 +#define FF_FAT_ATTR_LFN 0x0F + +/** + * -- Hein_Tibosch additions for mixed case in shortnames -- + * + * Specifically, bit 4 means lowercase extension and bit 3 lowercase basename, + * which allows for combinations such as "example.TXT" or "HELLO.txt" but not "Mixed.txt" + */ + +#define FF_FAT_CASE_OFFS 0x0C /* After NT/XP : 2 case bits. */ +#define FF_FAT_CASE_ATTR_BASE 0x08 +#define FF_FAT_CASE_ATTR_EXT 0x10 + +#if( ffconfigLFN_SUPPORT != 0 ) && ( ffconfigINCLUDE_SHORT_NAME != 0 ) +#define FF_FAT_ATTR_IS_LFN 0x40 /* artificial attribute, for debugging only. */ +#endif + +#endif + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_file.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_file.h new file mode 100644 index 000000000..d267971c7 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_file.h @@ -0,0 +1,163 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_file.h + * @ingroup FILEIO + **/ +#ifndef _FF_FILE_H_ +#define _FF_FILE_H_ + +#ifndef PLUS_FAT_H + #error this header will be included from "plusfat.h" +#endif + +#define FF_SEEK_SET 0 +#define FF_SEEK_CUR 1 +#define FF_SEEK_END 2 + +#if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) + #define FF_BUFSTATE_INVALID 0x00 /* Data in file handle buffer is invalid. */ + #define FF_BUFSTATE_VALID 0x01 /* Valid data in pBuf (Something has been read into it). */ + #define FF_BUFSTATE_WRITTEN 0x02 /* Data was written into pBuf, this must be saved when leaving sector. */ +#endif + +#if( ffconfigDEV_SUPPORT != 0 ) +struct xDEV_NODE +{ + uint8_t + ucIsDevice; +}; +#endif + +typedef struct _FF_FILE +{ + FF_IOManager_t *pxIOManager; /* Ioman Pointer! */ + uint32_t ulFileSize; /* File's Size. */ + uint32_t ulObjectCluster; /* File's Start Cluster. */ + uint32_t ulChainLength; /* Total Length of the File's cluster chain. */ + uint32_t ulCurrentCluster; /* Prevents FAT Thrashing. */ + uint32_t ulAddrCurrentCluster; /* Address of the current cluster. */ + uint32_t ulEndOfChain; /* Address of the last cluster in the chain. */ + uint32_t ulFilePointer; /* Current Position Pointer. */ + uint32_t ulDirCluster; /* Cluster Number that the Dirent is in. */ + uint32_t ulValidFlags; /* Handle validation flags. */ + +#if( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 ) + uint8_t *pucBuffer; /* A buffer for providing fast unaligned access. */ + uint8_t ucState; /* State information about the buffer. */ +#endif + uint8_t ucMode; /* Mode that File Was opened in. */ + uint16_t usDirEntry; /* Dirent Entry Number describing this file. */ + +#if( ffconfigDEV_SUPPORT != 0 ) + struct SFileCache *pxDevNode; +#endif + struct _FF_FILE *pxNext; /* Pointer to the next file object in the linked list. */ +} FF_FILE; + +#define FF_VALID_FLAG_INVALID 0x00000001 +#define FF_VALID_FLAG_DELETED 0x00000002 + +/*---------- PROTOTYPES */ +/* PUBLIC (Interfaces): */ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_FILE *FF_Open( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *path, uint8_t Mode, FF_Error_t *pError ); + BaseType_t FF_isDirEmpty( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *Path ); + FF_Error_t FF_RmFile( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *path ); + FF_Error_t FF_RmDir( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *path ); + FF_Error_t FF_Move( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *szSourceFile, const FF_T_WCHAR *szDestinationFile, + BaseType_t bDeleteIfExists ); +#else /* ffconfigUNICODE_UTF16_SUPPORT */ + FF_FILE *FF_Open( FF_IOManager_t *pxIOManager, const char *path, uint8_t Mode, FF_Error_t *pError ); + BaseType_t FF_isDirEmpty( FF_IOManager_t *pxIOManager, const char *Path ); + FF_Error_t FF_RmFile( FF_IOManager_t *pxIOManager, const char *path ); + FF_Error_t FF_RmDir( FF_IOManager_t *pxIOManager, const char *path ); + FF_Error_t FF_Move( FF_IOManager_t *pxIOManager, const char *szSourceFile, const char *szDestinationFile, + BaseType_t bDeleteIfExists ); +#endif /* ffconfigUNICODE_UTF16_SUPPORT */ + +#if( ffconfigTIME_SUPPORT != 0 ) + enum { + ETimeCreate = 1, + ETimeMod = 2, + ETimeAccess = 4, + ETimeAll = 7 + }; + FF_Error_t FF_SetFileTime( FF_FILE *pFile, FF_SystemTime_t *pxTime, UBaseType_t uxWhat ); + #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_Error_t FF_SetTime( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *path, FF_SystemTime_t *pxTime, UBaseType_t uxWhat ); + #else + FF_Error_t FF_SetTime( FF_IOManager_t *pxIOManager, const char *path, FF_SystemTime_t *pxTime, UBaseType_t uxWhat ); + #endif /* ffconfigUNICODE_UTF16_SUPPORT */ +#endif /* ffconfigTIME_SUPPORT */ + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_Error_t FF_SetPerm( FF_IOManager_t *pxIOManager, const FF_T_WCHAR *path, UBaseType_t aPerm ); +#else + FF_Error_t FF_SetPerm( FF_IOManager_t *pxIOManager, const char *path, UBaseType_t aPerm ); +#endif + +FF_Error_t FF_SetEof( FF_FILE *pFile ); + +FF_Error_t FF_Close( FF_FILE *pFile ); +int32_t FF_GetC( FF_FILE *pFile ); +int32_t FF_GetLine( FF_FILE *pFile, char *szLine, uint32_t ulLimit ); +int32_t FF_Read( FF_FILE *pFile, uint32_t ElementSize, uint32_t Count, uint8_t *buffer ); +int32_t FF_Write( FF_FILE *pFile, uint32_t ElementSize, uint32_t Count, uint8_t *buffer ); +BaseType_t FF_isEOF( FF_FILE *pFile ); +int32_t FF_BytesLeft( FF_FILE *pFile ); /* Returns # of bytes left to read. */ + +/* FF_FileSize is an earlier version of FF_GetFileSize(). For files +equal to or larger than 2GB, the return value is negative. +Function is deprecated. Please use FF_GetFileSize(). */ +int32_t FF_FileSize( FF_FILE *pFile ); /* Returns # of bytes in a file. */ + +/* Use the following function in case files may get larger than 2 GB. +Writes the size of a file to the parameter. +Returns 0 or error code. */ +FF_Error_t FF_GetFileSize( FF_FILE *pFile, uint32_t *pulSize ); + +FF_Error_t FF_Seek( FF_FILE *pFile, int32_t Offset, BaseType_t xOrigin ); +int32_t FF_PutC( FF_FILE *pFile, uint8_t Value ); + +static portINLINE uint32_t FF_Tell( FF_FILE *pFile ) +{ + return pFile ? pFile->ulFilePointer : 0; +} + +uint8_t FF_GetModeBits( const char *Mode ); + +FF_Error_t FF_CheckValid( FF_FILE *pFile ); /* Check if pFile is a valid FF_FILE pointer. */ + +#if( ffconfigREMOVABLE_MEDIA != 0 ) + int32_t FF_Invalidate( FF_IOManager_t *pxIOManager ); /* Invalidate all handles belonging to pxIOManager. */ +#endif + +/* Private : */ + +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_format.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_format.h new file mode 100644 index 000000000..4120226ea --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_format.h @@ -0,0 +1,75 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_format.c + * @ingroup FORMAT + * + **/ + + +#ifndef _FF_FORMAT_H_ +#define _FF_FORMAT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifndef PLUS_FAT_H + #error this header will be included from "plusfat.h" +#endif + +/*---------- PROTOTYPES */ +/* PUBLIC (Interfaces): */ + +typedef enum _FF_SizeType { + eSizeIsQuota, /* Assign a quotum (sum of xSizes is free, all disk space will be allocated) */ + eSizeIsPercent, /* Assign a percentage of the available space (sum of xSizes must be <= 100) */ + eSizeIsSectors, /* Assign fixed number of sectors (sum of xSizes must be < ulSectorCount) */ +} eSizeType_t; + +typedef struct _FF_PartitionParameters { + uint32_t ulSectorCount; /* Total number of sectors on the disk, including hidden/reserved */ + /* Must be obtained from the block driver */ + uint32_t ulHiddenSectors; /* Keep at least these initial sectors free */ + uint32_t ulInterSpace; /* Number of sectors to keep free between partitions (when 0 -> 2048) */ + BaseType_t xSizes[ ffconfigMAX_PARTITIONS ]; /* E.g. 80, 20, 0, 0 (see eSizeType) */ + BaseType_t xPrimaryCount; /* The number of partitions that must be "primary" */ + eSizeType_t eSizeType; +} FF_PartitionParameters_t; + +FF_Error_t FF_Partition( FF_Disk_t *pxDisk, FF_PartitionParameters_t *pParams ); + +FF_Error_t FF_Format( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber, BaseType_t xPreferFAT16, BaseType_t xSmallClusters ); + +/* Private : */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_headers.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_headers.h new file mode 100644 index 000000000..505876b70 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_headers.h @@ -0,0 +1,62 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +#ifndef PLUS_FAT_H +#define PLUS_FAT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +#include "FreeRTOSFATConfig.h" +#include "FreeRTOSFATConfigDefaults.h" +#include "ff_error.h" +#include "ff_ioman.h" +#include "ff_fat.h" +#include "ff_fatdef.h" +#include "ff_memory.h" +#include "ff_time.h" +#include "ff_crc.h" +#include "ff_file.h" +#include "ff_dir.h" +#include "ff_string.h" +#include "ff_format.h" +#include "ff_locking.h" + +/* See if any older defines with a prefix "FF_" are still defined: */ +#include "ff_old_config_defines.h" + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_ioman.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_ioman.h new file mode 100644 index 000000000..77301ed74 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_ioman.h @@ -0,0 +1,383 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_ioman.h + * @ingroup IOMAN + **/ + +#ifndef _FF_IOMAN_H_ +#define _FF_IOMAN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include /* Use of malloc() */ + +#ifndef PLUS_FAT_H + #error this header will be included from "plusfat.h" +#endif + +#define FF_T_FAT12 0x0A +#define FF_T_FAT16 0x0B +#define FF_T_FAT32 0x0C + +#define FF_MODE_READ 0x01 /* Buffer / FILE Mode for Read Access. */ +#define FF_MODE_WRITE 0x02 /* Buffer / FILE Mode for Write Access. */ +#define FF_MODE_APPEND 0x04 /* FILE Mode Append Access. */ +#define FF_MODE_CREATE 0x08 /* FILE Mode Create file if not existing. */ +#define FF_MODE_TRUNCATE 0x10 /* FILE Mode Truncate an Existing file. */ +#define FF_MODE_VIRGIN 0x40 /* Buffer mode: do not fetch content from disk. Used for write-only buffers. */ +#define FF_MODE_DIR 0x80 /* Special Mode to open a Dir. (Internal use ONLY!) */ + +#define FF_MODE_RD_WR ( FF_MODE_READ | FF_MODE_WRITE ) /* Just for bit filtering. */ + +/* The buffer write-only mode saves a fetch from disk. +The write-only mode is used when a buffer is needed just +for clearing sectors. */ +#define FF_MODE_WR_ONLY ( FF_MODE_VIRGIN | FF_MODE_WRITE ) /* Buffer for Write-only Access (Internal use ONLY!) */ + +#define FF_BUF_MAX_HANDLES 0xFFFF /* Maximum number handles sharing a buffer. (16 bit integer, we don't want to overflow it!) */ + +#define FF_MAX_ENTRIES_PER_DIRECTORY 0xFFFF +#define FF_SIZEOF_SECTOR 512 +#define FF_SIZEOF_DIRECTORY_ENTRY 32 + +#ifndef pdTRUE_SIGNED + /* Temporary solution: eventually the defines below will appear + in 'Source\include\projdefs.h' */ + #define pdTRUE_SIGNED pdTRUE + #define pdFALSE_SIGNED pdFALSE + #define pdTRUE_UNSIGNED ( ( UBaseType_t ) 1u ) + #define pdFALSE_UNSIGNED ( ( UBaseType_t ) 0u ) +#endif +/** + * I/O Driver Definitions + * Provide access to any Block Device via the following interfaces. + * Returns the number of blocks actually read or written. + **/ + +/** + * A special information structure for the FreeRTOS+FAT mass storage device + * driver model. + **/ +typedef struct +{ + uint16_t BlkSize; + uint32_t TotalBlocks; +} FF_DeviceInfo_t; + +#if( ffconfigHASH_CACHE != 0 ) + #define FF_HASH_TABLE_ENTRY_COUNT ( ( ffconfigHASH_TABLE_SIZE + 3 ) / 4 ) + + struct xHASH_TABLE + { + uint32_t ulDirCluster; /* The Starting Cluster of the dir that the hash represents. */ + uint32_t ulNumHandles; /* Number of active Handles using this hash table. */ + uint32_t ulMisses; /* Number of times this Hash Table was missed, (i.e. how redundant it is). */ + uint32_t ulBitTable[ FF_HASH_TABLE_ENTRY_COUNT ]; + }; + + typedef struct xHASH_TABLE FF_HashTable_t; + + void FF_ClearHash( FF_HashTable_t *pxHash, uint32_t ulHash ); + void FF_SetHash( FF_HashTable_t *pxHash, uint32_t ulHash ); + BaseType_t FF_isHashSet( FF_HashTable_t *pxHash, uint32_t ulHash ); +#endif /* ffconfigHASH_CACHE */ + +/* A forward declaration for the I/O manager, to be used in 'struct xFFDisk'. */ +struct _FF_IOMAN; +struct xFFDisk; + +typedef void ( *FF_FlushApplicationHook )( struct xFFDisk *pxDisk ); + +/* + * Some low-level drivers also need to flush data to a device. + * Use an Application hook that will be called every time when + * FF_FlushCache() is called. The semaphore will still be taken + * to avoid unwanted reentrancy. + * For example: + * + * void FTL_FlushData( struct xFFDisk *pxDisk ) + * { + * // You may or may not inspect 'pxDisk' + * FTL_FlushTableCache(); + * } + * + * Make sure you bind the function to the disc object, right after creation: + * + * pxDisk->fnFlushApplicationHook = FTL_FlushData; + */ + +/* Structure that contains fields common to all media drivers, and can be +extended to contain additional fields to tailor it for use with a specific media +type. */ +struct xFFDisk +{ + struct + { + /* Flags that can optionally be used by the media driver to ensure the + disk has been initialised, registered and mounted before it is accessed. */ + uint32_t bIsInitialised : 1; + uint32_t bIsMounted : 1; + uint32_t spare0 : 5; + + /* The partition number on the media described by this structure. */ + uint32_t bPartitionNumber : 8; + uint32_t spare1 : 16; + } xStatus; + + /* Provided to allow this structure to be extended to include additional + attributes that are specific to a media type. */ + void * pvTag; + + /* Points to input and output manager used by the disk described by this + structure. */ + struct _FF_IOMAN *pxIOManager; + + /* The number of sectors on the disk. */ + uint32_t ulNumberOfSectors; + + /* See comments here above. */ + FF_FlushApplicationHook fnFlushApplicationHook; + + /* Field that can optionally be set to a signature that is unique to the + media. Read and write functions can check the ulSignature field to validate + the media type before they attempt to access the pvTag field, or perform any + read and write operations. */ + uint32_t ulSignature; +}; + +typedef struct xFFDisk FF_Disk_t; + +typedef int32_t ( *FF_WriteBlocks_t ) ( uint8_t *pucBuffer, uint32_t ulSectorAddress, uint32_t ulCount, FF_Disk_t *pxDisk ); +typedef int32_t ( *FF_ReadBlocks_t ) ( uint8_t *pucBuffer, uint32_t ulSectorAddress, uint32_t ulCount, FF_Disk_t *pxDisk ); + +/** + * @public + * @brief Describes the block device driver interface to FreeRTOS+FAT. + **/ +typedef struct +{ + FF_WriteBlocks_t fnpWriteBlocks; /* Function Pointer, to write a block(s) from a block device. */ + FF_ReadBlocks_t fnpReadBlocks; /* Function Pointer, to read a block(s) from a block device. */ + FF_Disk_t *pxDisk; /* Earlier called 'pParam': pointer to some parameters e.g. for a Low-Level Driver Handle. */ +} FF_BlockDevice_t; + +/** + * @private + * @brief FreeRTOS+FAT handles memory with buffers, described as below. + * @note This may change throughout development. + **/ +typedef struct +{ + uint32_t ulSector; /* The LBA of the Cached sector. */ + uint32_t ulLRU; /* For the Least Recently Used algorithm. */ + uint8_t *pucBuffer; /* Pointer to the cache block. */ + uint32_t ucMode : 8, /* Read or Write mode. */ + bModified : 1, /* If the sector was modified since read. */ + bValid : 1; /* Initially FALSE. */ + uint16_t usNumHandles; /* Number of objects using this buffer. */ + uint16_t usPersistance; /* For the persistance algorithm. */ +} FF_Buffer_t; + +typedef struct +{ +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + FF_T_WCHAR pcPath[ ffconfigMAX_FILENAME ]; +#else + char pcPath[ ffconfigMAX_FILENAME ]; +#endif + uint32_t ulDirCluster; +} FF_PathCache_t; + +/** + * @private + * @brief FreeRTOS+FAT identifies a partition with the following data. + * @note This may shrink as development and optimisation goes on. + **/ +typedef struct +{ + uint32_t ulBeginLBA; /* LBA start address of the partition. */ + uint32_t ulFATBeginLBA; /* LBA of the FAT tables. */ + uint32_t ulSectorsPerFAT; /* Number of sectors per Fat. */ + uint32_t ulTotalSectors; + uint32_t ulDataSectors; +#if( ffconfigWRITE_FREE_COUNT != 0 ) + uint32_t ulFSInfoLBA; /* LBA of the FSINFO sector. */ +#endif + uint32_t ulRootDirSectors; + uint32_t ulFirstDataSector; + uint32_t ulClusterBeginLBA; /* LBA of first cluster. */ + uint32_t ulNumClusters; /* Number of clusters. */ + uint32_t ulRootDirCluster; /* Cluster number of the root directory entry. */ + uint32_t ulLastFreeCluster; + uint32_t ulFreeClusterCount; /* Records free space on mount. */ + uint32_t ulSectorsPerCluster;/* Number of sectors per Cluster. */ + + char pcVolumeLabel[ 12 ];/* Volume Label of the partition. */ + + uint16_t usBlkSize; /* Size of a Sector Block in bytes. */ + uint16_t usReservedSectors; + + uint8_t ucType; /* Partition Type Identifier. */ + uint8_t ucBlkFactor; /* Scale Factor for block sizes above 512! */ + uint8_t ucNumFATS; /* Number of FAT tables. */ + uint8_t ucPartitionMounted; /* pdTRUE if the partition is mounted, otherwise pdFALSE. */ + +#if( ffconfigPATH_CACHE != 0 ) + FF_PathCache_t pxPathCache[ffconfigPATH_CACHE_DEPTH]; + uint32_t ulPCIndex; +#endif +} FF_Partition_t; + + + +/** + * @public + * @brief FF_IOManager_t Object description. + * + * FreeRTOS+FAT functions around an object like this. + **/ +#define FF_FAT_LOCK 0x01 /* Lock bit mask for FAT table locking. */ +#define FF_DIR_LOCK 0x02 /* Lock bit mask for DIR modification locking. */ +#define FF_BUF_LOCK 0x04 /* Lock bit mask for buffers. */ + +/** + * @public + * @brief FF_IOManager_t Object. A developer should not touch these values. + * + **/ +typedef struct _FF_IOMAN +{ + FF_BlockDevice_t xBlkDevice; /* Pointer to a Block device description. */ + FF_Partition_t xPartition; /* A partition description. */ + FF_Buffer_t *pxBuffers; /* Pointer to an array of buffer descriptors. */ + void *pvSemaphore; /* Pointer to a Semaphore object. (For buffer description modifications only!). */ + void *FirstFile; /* Pointer to the first File object. */ + void *xEventGroup; /* An event group, used for locking FAT, DIR and Buffers. Replaces ucLocks. */ + uint8_t *pucCacheMem; /* Pointer to a block of memory for the cache. */ + uint16_t usSectorSize; /* The sector size that IOMAN is configured to. */ + uint16_t usCacheSize; /* Size of the cache in number of Sectors. */ + uint8_t ucPreventFlush; /* Flushing to disk only allowed when 0. */ + uint8_t ucFlags; /* Bit-Mask: identifying allocated pointers and other flags */ +#if( ffconfigHASH_CACHE != 0 ) + FF_HashTable_t xHashCache[ ffconfigHASH_CACHE_DEPTH ]; +#endif + void *pvFATLockHandle; +} FF_IOManager_t; + +/* Bit values for 'FF_IOManager_t::ucFlags': */ +/* Memory Allocation testing and other flags. */ +#define FF_IOMAN_ALLOC_BUFDESCR 0x01 /* Flags the pxBuffers pointer is allocated. */ +#define FF_IOMAN_ALLOC_BUFFERS 0x02 /* Flags the pucCacheMem pointer is allocated. */ +#define FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT 0x10 /* When true, ffRead/ffWrite are not protected by a semaphore. */ +#if( ffconfigREMOVABLE_MEDIA != 0 ) + #define FF_IOMAN_DEVICE_IS_EXTRACTED 0x20 +#endif /* ffconfigREMOVABLE_MEDIA */ + +typedef struct xFF_CREATION_PARAMETERS +{ + uint8_t *pucCacheMemory; /* User provided memory, or use NULL to malloc the cache memory. */ + uint32_t ulMemorySize; /* Size of the cache memory, must be a multiple of 'ulSectorSize'. */ + BaseType_t ulSectorSize; /* Sector size, unit for reading/writing to the disk, normally 512 bytes. */ + FF_WriteBlocks_t fnWriteBlocks; /* A function to write sectors to the device. */ + FF_ReadBlocks_t fnReadBlocks; /* A function to read sectors from the device. */ + FF_Disk_t *pxDisk; /* Some properties of the disk driver. */ + void *pvSemaphore; /* Pointer to a Semaphore object. */ + BaseType_t xBlockDeviceIsReentrant; /* Make non-zero if ffRead/ffWrite are re-entrant. */ +} FF_CreationParameters_t; + +/*---------- PROTOTYPES (in order of appearance). */ + +/* PUBLIC (Interfaces): */ +FF_IOManager_t *FF_CreateIOManger( FF_CreationParameters_t *pxParameters, FF_Error_t *pError ); +FF_Error_t FF_DeleteIOManager( FF_IOManager_t *pxIOManager); +FF_Error_t FF_Mount( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber ); +FF_Error_t FF_Unmount( FF_Disk_t *pxDisk ); +FF_Error_t FF_FlushCache( FF_IOManager_t *pxIOManager ); +static portINLINE BaseType_t FF_Mounted( FF_IOManager_t *pxIOManager ) +{ + return pxIOManager && pxIOManager->xPartition.ucPartitionMounted; +} + +int32_t FF_GetPartitionBlockSize(FF_IOManager_t *pxIOManager); + +#if( ffconfig64_NUM_SUPPORT != 0 ) + uint64_t FF_GetVolumeSize( FF_IOManager_t *pxIOManager ); +#else + uint32_t FF_GetVolumeSize( FF_IOManager_t *pxIOManager ); +#endif + +/* PUBLIC (To FreeRTOS+FAT Only): */ +int32_t FF_BlockRead( FF_IOManager_t *pxIOManager, uint32_t ulSectorLBA, uint32_t ulNumSectors, void *pBuffer, BaseType_t aSemLocked ); +int32_t FF_BlockWrite( FF_IOManager_t *pxIOManager, uint32_t ulSectorLBA, uint32_t ulNumSectors, void *pBuffer, BaseType_t aSemLocked ); +FF_Error_t FF_IncreaseFreeClusters( FF_IOManager_t *pxIOManager, uint32_t Count ); +FF_Error_t FF_DecreaseFreeClusters( FF_IOManager_t *pxIOManager, uint32_t Count ); +FF_Buffer_t *FF_GetBuffer( FF_IOManager_t *pxIOManager, uint32_t ulSector, uint8_t Mode ); +FF_Error_t FF_ReleaseBuffer( FF_IOManager_t *pxIOManager, FF_Buffer_t *pBuffer ); + +/* 'Internal' to FreeRTOS+FAT. */ +typedef struct _SPart +{ + uint32_t ulStartLBA; /* FF_FAT_PTBL_LBA */ + uint32_t ulSectorCount; /* FF_FAT_PTBL_SECT_COUNT */ + uint32_t + ucActive : 8, /* FF_FAT_PTBL_ACTIVE */ + ucPartitionID : 8, /* FF_FAT_PTBL_ID */ + bIsExtended : 1; +} FF_Part_t; + +typedef struct _SPartFound +{ + int iCount; + FF_Part_t pxPartitions[ffconfigMAX_PARTITIONS]; +} FF_SPartFound_t; + +/* This function will parse the 4 entries in a partition table: */ +void FF_ReadParts( uint8_t *pucBuffer, FF_Part_t *pxParts ); + +/* FF_PartitionCount() has now been replaced by FF_PartitionSearch() + * It will enumerate all valid partitions found + * If sector-0 happens to be a valid MBR, 1 partition will be returned + */ +FF_Error_t FF_PartitionSearch( FF_IOManager_t *pxIOManager, FF_SPartFound_t *pPartsFound ); + +/* HT : for debugging only. */ +BaseType_t xIsFatSector( FF_IOManager_t *pxIOManager, uint32_t ulSectorNr ); +BaseType_t xNeedLogging( FF_IOManager_t *pxIOManager ); +BaseType_t xIsRootDirSector( FF_IOManager_t *pxIOManager, uint32_t ulSectorNr ); +const char *pcSectorType( FF_IOManager_t *pxIOManager, uint32_t ulSectorNr ); + +/* Needed to make this public/private to be used in FF_Partition/FF_Format. */ +void FF_IOMAN_InitBufferDescriptors( FF_IOManager_t *pxIOManager ); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_locking.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_locking.h new file mode 100644 index 000000000..067422ccd --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_locking.h @@ -0,0 +1,91 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_locking.h + * @ingroup LOCKING + **/ + +#ifndef _FF_LOCKING_H_ +#define _FF_LOCKING_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/*---------- PROTOTYPES (in order of appearance). */ + +/* PUBLIC: */ + + +/* PRIVATE: */ +void FF_PendSemaphore ( void *pSemaphore ); +BaseType_t FF_TrySemaphore ( void *pSemaphore, uint32_t TimeMs ); +void FF_ReleaseSemaphore ( void *pSemaphore ); +void FF_Sleep ( uint32_t TimeMs ); + +/* Create an event group and bind it to an I/O manager. */ +BaseType_t FF_CreateEvents( FF_IOManager_t *pxIOManager ); + +/* Delete an event group. */ +void FF_DeleteEvents( FF_IOManager_t *pxIOManager ); + +/* Get a lock on all DIR operations for a given I/O manager. */ +void FF_LockDirectory( FF_IOManager_t *pxIOManager ); + +/* Release the lock on all DIR operations. */ +void FF_UnlockDirectory( FF_IOManager_t *pxIOManager ); + +/* Get a lock on all FAT operations for a given I/O manager. */ +void FF_LockFAT( FF_IOManager_t *pxIOManager ); + +/* Release the lock on all FAT operations. */ +void FF_UnlockFAT( FF_IOManager_t *pxIOManager ); + +/* Called from FF_GetBuffer() as long as no buffer is available. */ +BaseType_t FF_BufferWait( FF_IOManager_t *pxIOManager, uint32_t xWaitMS ); + +/* Called from FF_ReleaseBuffer(). */ +void FF_BufferProceed( FF_IOManager_t *pxIOManager ); + +/* Check if the current task already has locked the FAT. */ +int FF_Has_Lock( FF_IOManager_t *pxIOManager, uint32_t aBits ); + +/* + * Throw a configASSERT() in case the FAT has not been locked + * by this task. + */ +/* _HT_ This function is only necessary while testing. */ +void FF_Assert_Lock( FF_IOManager_t *pxIOManager, uint32_t aBits ); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _FF_LOCKING_H_ */ + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_memory.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_memory.h new file mode 100644 index 000000000..f3bae06ce --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_memory.h @@ -0,0 +1,168 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_memory.h + * @ingroup MEMORY + **/ + +#ifndef _FF_MEMORY_H_ +#define _FF_MEMORY_H_ + +/* + * When sector data is written or analysed, some values might be stored unaligned. + * The routines below treat all values as little arrays of either 2 or 4 bytes. + * Also on big endian platforms, the order of bytes will be swapped. + */ +/*---------- PROTOTYPES */ + +#if( ffconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) + /* + * FAT is little endian. + * On a little endian CPU, bytes will be copied to the structures below 1-to-1 : + */ + typedef struct + { + uint8_t u8_0; /* the first byte */ + uint8_t u8_1; /* the second byte */ + } FF_TShort_t; + + typedef struct + { + uint8_t u8_0; + uint8_t u8_1; + uint8_t u8_2; + uint8_t u8_3; + } FF_TLong_t; +#elif( ffconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN ) + /* + * On a big endian CPU, all bytes will be swapped, either 2 or 4 bytes: + */ + typedef struct + { + uint8_t u8_1; /* the second byte */ + uint8_t u8_0; /* the first byte */ + } FF_TShort_t; + + typedef struct + { + uint8_t u8_3; + uint8_t u8_2; + uint8_t u8_1; + uint8_t u8_0; + } FF_TLong_t; +#else + #error Little or Big Endian? - Please set ffconfigBYTE_ORDER to either pdFREERTOS_LITTLE_ENDIAN or pdFREERTOS_BIG_ENDIAN 1 in FreeRTOSFATConfig.h +#endif + +/*! 16-bit union. */ +typedef union +{ + uint16_t u16; + FF_TShort_t bytes; +} FF_T_UN16; + +/*! 32-bit union. */ +typedef union +{ + uint32_t u32; + FF_TLong_t bytes; +} FF_T_UN32; + +/* HT inlined these functions: + */ + +#if( ffconfigINLINE_MEMORY_ACCESS != 0 ) + + static portINLINE uint8_t FF_getChar( const uint8_t *pBuffer, uint32_t aOffset ) + { + return ( uint8_t ) ( pBuffer[ aOffset ] ); + } + + static portINLINE uint16_t FF_getShort( const uint8_t *pBuffer, uint32_t aOffset ) + { + FF_T_UN16 u16; + + pBuffer += aOffset; + u16.bytes.u8_1 = pBuffer[ 1 ]; + u16.bytes.u8_0 = pBuffer[ 0 ]; + + return u16.u16; + } + + static portINLINE uint32_t FF_getLong( const uint8_t *pBuffer, uint32_t aOffset ) + { + FF_T_UN32 u32; + + pBuffer += aOffset; + u32.bytes.u8_3 = pBuffer[ 3 ]; + u32.bytes.u8_2 = pBuffer[ 2 ]; + u32.bytes.u8_1 = pBuffer[ 1 ]; + u32.bytes.u8_0 = pBuffer[ 0 ]; + + return u32.u32; + } + + static portINLINE void FF_putChar( uint8_t *pBuffer, uint32_t aOffset, uint32_t Value ) + { + pBuffer[ aOffset ] = ( uint8_t ) Value; + } + + static portINLINE void FF_putShort( uint8_t *pBuffer, uint32_t aOffset, uint32_t Value ) + { + FF_T_UN16 u16; + + u16.u16 = ( uint16_t ) Value; + pBuffer += aOffset; + pBuffer[ 0 ] = u16.bytes.u8_0; + pBuffer[ 1 ] = u16.bytes.u8_1; + } + + static portINLINE void FF_putLong( uint8_t *pBuffer, uint32_t aOffset, uint32_t Value ) + { + FF_T_UN32 u32; + + u32.u32 = Value; + pBuffer += aOffset; + pBuffer[ 0 ] = u32.bytes.u8_0; + pBuffer[ 1 ] = u32.bytes.u8_1; + pBuffer[ 2 ] = u32.bytes.u8_2; + pBuffer[ 3 ] = u32.bytes.u8_3; + } + +#else /* ffconfigINLINE_MEMORY_ACCESS */ + + uint8_t FF_getChar( const uint8_t *pBuffer, uint32_t aOffset ); + uint16_t FF_getShort( const uint8_t *pBuffer, uint32_t aOffset ); + uint32_t FF_getLong( const uint8_t *pBuffer, uint32_t aOffset ); + void FF_putChar( uint8_t *pBuffer, uint32_t aOffset, uint32_t Value ); + void FF_putShort( uint8_t *pBuffer, uint32_t aOffset, uint32_t Value ); + void FF_putLong( uint8_t *pBuffer, uint32_t aOffset, uint32_t Value ); + +#endif /* ffconfigINLINE_MEMORY_ACCESS */ + +#endif /* _FF_MEMORY_H_ */ + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_old_config_defines.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_old_config_defines.h new file mode 100644 index 000000000..fd0caa6a8 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_old_config_defines.h @@ -0,0 +1,256 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + + /* + As of 15/3/2015 all +FAT configuration items changed their prefix, + e.g. FF_LITTLE_ENDIAN has become ffconfigLITTLE_ENDIAN + This tempoary header file checks for the presence old configuration items + and issue a compiler error if any is defined. +*/ + +#ifdef FF_LITTLE_ENDIAN + #error FF_LITTLE_ENDIAN was dropped and replaced with 'ffconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN' +#endif + +#ifdef FF_BIG_ENDIAN + #error FF_BIG_ENDIAN was dropped and replaced with 'ffconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN' +#endif + +#ifdef ffconfigLITTLE_ENDIAN + #error ffconfigLITTLE_ENDIAN was dropped. +#endif + +#ifdef ffconfigBIG_ENDIAN + #error ffconfigBIG_ENDIAN was dropped. +#endif + +#ifdef FF_HAS_CWD + #error FF_HAS_CWD still defined. Please use ffconfig prefix. +#endif + +#if !defined( pdFREERTOS_LITTLE_ENDIAN ) || !defined( pdFREERTOS_BIG_ENDIAN ) + #error Missing defines from FreeRTOS +#endif + +#ifdef FF_LFN_SUPPORT + #error FF_LFN_SUPPORT still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_INCLUDE_SHORT_NAME + #error FF_INCLUDE_SHORT_NAME still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_SHORTNAME_CASE + #error FF_SHORTNAME_CASE still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_UNICODE_UTF16_SUPPORT + #error FF_UNICODE_UTF16_SUPPORT still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_UNICODE_UTF8_SUPPORT + #error FF_UNICODE_UTF8_SUPPORT still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_FAT12_SUPPORT + #error FF_FAT12_SUPPORT still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_OPTIMISE_UNALIGNED_ACCESS + #error FF_OPTIMISE_UNALIGNED_ACCESS still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_CACHE_WRITE_THROUGH + #error FF_CACHE_WRITE_THROUGH still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_WRITE_BOTH_FATS + #error FF_WRITE_BOTH_FATS still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_WRITE_FREE_COUNT + #error FF_WRITE_FREE_COUNT still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_TIME_SUPPORT + #error FF_TIME_SUPPORT still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_REMOVABLE_MEDIA + #error FF_REMOVABLE_MEDIA still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_MOUNT_FIND_FREE + #error FF_MOUNT_FIND_FREE still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_FINDAPI_ALLOW_WILDCARDS + #error FF_FINDAPI_ALLOW_WILDCARDS still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_WILDCARD_CASE_INSENSITIVE + #error FF_WILDCARD_CASE_INSENSITIVE still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_PATH_CACHE + #error FF_PATH_CACHE still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_PATH_CACHE_DEPTH + #error FF_PATH_CACHE_DEPTH still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_HASH_CACHE + #error FF_HASH_CACHE still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_HASH_FUNCTION + #error FF_HASH_FUNCTION still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_HASH_TABLE_SIZE + #error FF_HASH_TABLE_SIZE still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_HASH_TABLE_SIZE + #error FF_HASH_TABLE_SIZE still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_MKDIR_RECURSIVE + #error FF_MKDIR_RECURSIVE still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_BLKDEV_USES_SEM + #error FF_BLKDEV_USES_SEM is not used any more +#endif + +#ifdef ffconfigBLKDEV_USES_SEM + #error ffconfigBLKDEV_USES_SEM is not used any more +#endif + +#ifdef FF_MALLOC + #error FF_MALLOC still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_FREE + #error FF_FREE still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_64_NUM_SUPPORT + #error FF_64_NUM_SUPPORT still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_MAX_PARTITIONS + #error FF_MAX_PARTITIONS still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_MAX_FILE_SYS + #error FF_MAX_FILE_SYS still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_DRIVER_BUSY_SLEEP_MS + #error FF_DRIVER_BUSY_SLEEP_MS still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_FPRINTF_SUPPORT + #error FF_FPRINTF_SUPPORT still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_FPRINTF_BUFFER_LENGTH + #error FF_FPRINTF_BUFFER_LENGTH still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_DEBUG + #error FF_DEBUG still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_HAS_FUNCTION_TAB + #error FF_HAS_FUNCTION_TAB still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_FAT_CHECK + #error FF_FAT_CHECK still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_MAX_FILENAME + #error FF_MAX_FILENAME still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_PRINTFFF_PRINTF + #error FF_PRINTFFF_PRINTF still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_FAT_USES_STAT + #error FF_FAT_USES_STAT still defined. Please use ffconfig prefix. +#endif + +#ifdef BUF_STORE_COUNT + #error BUF_STORE_COUNT still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_USE_NOTIFY + #error FF_USE_NOTIFY still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_DEV_SUPPORT + #error FF_DEV_SUPPORT still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_FSINFO_TRUSTED + #error FF_FSINFO_TRUSTED still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_LONG_ERR_MSG + #error FF_LONG_ERR_MSG still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_INLINE_MEMORY_ACCESS + #error FF_INLINE_MEMORY_ACCESS still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_MIRROR_FATS_UMOUNT + #error FF_MIRROR_FATS_UMOUNT still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_HASH_CACHE_DEPTH + #error FF_HASH_CACHE_DEPTH still defined. Please use ffconfig prefix. +#endif + +#ifdef FF_HASH_TABLE_SUPPORT + #error FF_HASH_TABLE_SUPPORT was dropped +#endif + +#ifdef FF_INLINE_BLOCK_CALCULATIONS + #error FF_INLINE_BLOCK_CALCULATIONS was dropped +#endif + +#ifdef FF_CWD_THREAD_LOCAL_INDEX + #error FF_CWD_THREAD_LOCAL_INDEX is now called ffconfigCWD_THREAD_LOCAL_INDEX +#endif + +#ifdef FF_DEV_PATH + #error FF_DEV_PATH was dropped +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_stdio.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_stdio.h new file mode 100644 index 000000000..2dad20d99 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_stdio.h @@ -0,0 +1,353 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/* + ff_stdio.h + + An front-end which make +FAT look like the well-known stdio-functions +*/ + +#ifndef FF_STDIO_H +#define FF_STDIO_H + +#if defined(__WIN32__) + #include +#endif + +/* Standard includes. */ +#include +#include + +/* FreeRTOS+FAT includes. */ +#include "ff_headers.h" +#include "ff_sys.h" + +#if( ffconfigDEV_SUPPORT != 0 ) + #include "ff_devices.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Error return from some functions. */ +#define FF_EOF (-1) + +/* Bits used in the FF_Stat_t structure. */ +#define FF_IFDIR 0040000u /* directory */ +#define FF_IFCHR 0020000u /* character special */ +#define FF_IFBLK 0060000u /* block special */ +#define FF_IFREG 0100000u /* regular */ + +/* Bits used in the FF_FindData_t structure. */ +#define FF_FA_NORMAL 0x00 +#define FF_FA_RDONLY 0x01 +#define FF_FA_HIDDEN 0x02 +#define FF_FA_SYSTEM 0x04 +#define FF_FA_LABEL 0x08 +#define FF_FA_DIREC 0x10 +#define FF_FA_ARCH 0x20 + +/* FreeRTOS+FAT uses three thread local buffers. The first stores errno, the +second a pointer to the CWD structure (if one is used), and the third the more +descriptive error code. */ +#define stdioERRNO_THREAD_LOCAL_OFFSET ( ffconfigCWD_THREAD_LOCAL_INDEX + 0 ) +#define stdioCWD_THREAD_LOCAL_OFFSET ( ffconfigCWD_THREAD_LOCAL_INDEX + 1 ) +#define stdioFF_ERROR_THREAD_LOCAL_OFFSET ( ffconfigCWD_THREAD_LOCAL_INDEX + 2 ) + + +/* Structure used with ff_stat(). */ +typedef struct FF_STAT +{ + uint32_t st_ino; /* First data cluster number. */ + uint32_t st_size; /* Size of the object in number of bytes. */ + uint16_t st_dev; /* The device on which the file can be found (see ff_sys.c) */ + uint16_t st_mode; /* The mode (attribute bits) of this file or directory. */ + + #if( ffconfigTIME_SUPPORT == 1 ) + uint32_t st_atime; + uint32_t st_mtime; + uint32_t st_ctime; + #endif /* ffconfigTIME_SUPPORT */ +} FF_Stat_t; + +/* Structure used with ff_findfirst(), ff_findnext(), etc. */ +typedef struct +{ + /* private */ + UBaseType_t + #if( ffconfigDEV_SUPPORT != 0 ) + bIsDeviceDir : 1, + #endif + bEntryPOwner : 1; + struct FF_DIR_HANDLER xDirectoryHandler; + FF_DirEnt_t xDirectoryEntry; + + /* Public fields included so FF_DirEnt_t does not need to be public. */ + const char * pcFileName; + uint32_t ulFileSize; + uint8_t ucAttributes; + +} FF_FindData_t; + +/*----------------------------------------------------------- + * Get and set the task's file system errno + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +/* + int FF_GetErrno( void ); + void FF_SetErrno( int ff_errno ); + + _RB_ comments are incorrect and index should use the stdioERRNO_THREAD_LOCAL_OFFSET offset. +*/ + +/* The errno is stored in a thread local buffer. */ +static portINLINE void stdioSET_ERRNO( int iErrno ) +{ + vTaskSetThreadLocalStoragePointer( NULL, ffconfigCWD_THREAD_LOCAL_INDEX, ( void * ) ( iErrno ) ); +} + +static portINLINE int stdioGET_ERRNO( void ) +{ +void *pvResult; + + pvResult = pvTaskGetThreadLocalStoragePointer( ( TaskHandle_t )NULL, ffconfigCWD_THREAD_LOCAL_INDEX ); + return ( int ) pvResult; +} + +#if( ( configNUM_THREAD_LOCAL_STORAGE_POINTERS - ffconfigCWD_THREAD_LOCAL_INDEX ) < 3 ) + #error Please define space for 3 entries +#endif + +/* + * Store the FreeRTOS+FAT error code, which provides more detail than errno. + */ +static portINLINE void stdioSET_FF_ERROR( FF_Error_t iFF_ERROR ) +{ + vTaskSetThreadLocalStoragePointer( NULL, stdioFF_ERROR_THREAD_LOCAL_OFFSET, ( void * ) ( iFF_ERROR ) ); +} + +/* + * Read back the FreeRTOS+FAT error code, which provides more detail than + * errno. + */ +static portINLINE FF_Error_t stdioGET_FF_ERROR( void ) +{ +void *pvResult; + + pvResult = pvTaskGetThreadLocalStoragePointer( NULL, stdioFF_ERROR_THREAD_LOCAL_OFFSET ); + return ( FF_Error_t ) pvResult; +} + +/*----------------------------------------------------------- + * Open and close a file + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +FF_FILE *ff_fopen( const char *pcFile, const char *pcMode ); +int ff_fclose( FF_FILE *pxStream ); + + +/*----------------------------------------------------------- + * Seek and tell + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +int ff_fseek( FF_FILE *pxStream, long lOffset, int iWhence ); +void ff_rewind( FF_FILE *pxStream ); +long ff_ftell( FF_FILE *pxStream ); +int ff_feof( FF_FILE *pxStream ); + + +/*----------------------------------------------------------- + * Read and write + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +size_t ff_fread( void *pvBuffer, size_t xSize, size_t xItems, FF_FILE * pxStream ); +size_t ff_fwrite( const void *pvBuffer, size_t xSize, size_t xItems, FF_FILE * pxStream ); + +/* Whenever possible, use ellipsis parameter type checking. +_RB_ Compiler specifics need to be moved to the compiler specific header files. */ +#if defined(__GNUC__) + /* The GNU-C compiler will check if the parameters are correct. */ + int ff_fprintf( FF_FILE * pxStream, const char *pcFormat, ... ) + __attribute__ ( ( format ( __printf__, 2, 3 ) ) ); +#else + int ff_fprintf( FF_FILE * pxStream, const char *pcFormat, ... ); +#endif + +int ff_fgetc( FF_FILE * pxStream); +int ff_fputc( int iChar, FF_FILE *pxStream ); +char *ff_fgets( char *pcBuffer, size_t xCount, FF_FILE *pxStream ); + + +/*----------------------------------------------------------- + * Change length of file (truncate) + * File should have been opened in "w" or "a" mode + * The actual length of the file will be made equal to the current writing + * position + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +int ff_seteof( FF_FILE *pxStream ); + +/*----------------------------------------------------------- + * Open a file in append/update mode, truncate its length to a given value, + * or write zero's up until the required length, and return a handle to the open + * file. If NULL is returned, ff_errno contains an error code. + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +FF_FILE *ff_truncate( const char * pcFileName, long lTruncateSize ); + +/*----------------------------------------------------------- + * Flush to disk + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +int ff_fflush( FF_FILE *pxStream ); + + +/*----------------------------------------------------------- + * Create directory, remove and rename files + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +#if( ffconfigMKDIR_RECURSIVE == 0 ) + int ff_mkdir( const char *pcPath ); +#else + /* If the parameter bRecursive is non-zero, the entire path will be checked + and if necessary, created. */ + int ff_mkdir( const char *pcPath, int bRecursive ); +#endif + +/*----------------------------------------------------------- + * Create path specified by the pcPath parameter. + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +int ff_mkpath( const char *pcPath ); + +/*----------------------------------------------------------- + * Remove the directory specified by the pcDirectory parameter. + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +int ff_rmdir( const char *pcDirectory ); + +/*----------------------------------------------------------- + * Delete a directory and, recursively, all of its contents. + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +#if( ffconfigUSE_DELTREE != 0 ) + /* By default, this function will not be compiled. The function will + recursively call itself, which is against the FreeRTOS coding standards, so + IT MUST BE USED WITH CARE. + + The cost of each recursion will be roughly: + Stack : 48 (12 stack words) + Heap : 112 + ffconfigMAX_FILENAME + These numbers may change depending on CPU and compiler. */ + int ff_deltree( const char *pcPath ); +#endif + +/*----------------------------------------------------------- + * Remove/delete a file. + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +int ff_remove( const char *pcPath ); + +/*----------------------------------------------------------- + * Move a file, also cross-directory but not across a file system. + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +int ff_rename( const char *pcOldName, const char *pcNewName, int bDeleteIfExists ); + + +/*----------------------------------------------------------- + * Get the status of a file. + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +int ff_stat( const char *pcFileName, FF_Stat_t *pxStatBuffer ); +/* _HT_ Keep this for a while, until the new ff_stat() is wel tested */ +int ff_old_stat( const char *pcName, FF_Stat_t *pxStatBuffer ); + +/*----------------------------------------------------------- + * Get the length of a file in bytes. + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +size_t ff_filelength( FF_FILE *pxFile ); + +/*----------------------------------------------------------- + * Working directory and iterating through directories. + * The most up to date API documentation is currently provided on the following URL: + * http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html + *-----------------------------------------------------------*/ +#if ffconfigHAS_CWD + int ff_chdir( const char *pcDirectoryName ); + char *ff_getcwd( char *pcBuffer, size_t xBufferLength ); +#endif + +int ff_findfirst( const char *pcDirectory, FF_FindData_t *pxFindData ); +int ff_findnext( FF_FindData_t *pxFindData ); +int ff_isdirempty(const char *pcPath ); + + +/* _RB_ What to do regarding documentation for the definitions below here. */ + +#if( ffconfig64_NUM_SUPPORT != 0 ) + int64_t ff_diskfree(const char *pcPath, uint32_t *pxSectorCount ); +#else + int32_t ff_diskfree(const char *pcPath, uint32_t *pxSectorCount ); +#endif +int ff_finddir( const char *pcPath ); + +#if( ffconfigHAS_CWD == 1 ) + /* Obtain the CWD used by the current task. */ + void ff_free_CWD_space( void ); +#endif + +typedef enum _EFileAction { + eFileCreate, + eFileRemove, + eFileChange, + eFileIsDir = 0x80, +} eFileAction_t; + +void callFileEvents( const char *apPath, eFileAction_t aAction ); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* FF_STDIO_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_string.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_string.h new file mode 100644 index 000000000..d94b7cf5a --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_string.h @@ -0,0 +1,108 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_string.c + * @ingroup STRING + * + * @defgroup STRING FreeRTOS+FAT String Library + * @brief Portable String Library for FreeRTOS+FAT + * + * + **/ + +#ifndef _FF_STRING_H_ +#define _FF_STRING_H_ + +#include "FreeRTOSFATConfig.h" +#include + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) +#include +typedef wchar_t FF_T_WCHAR; /*/< Unicode UTF-16 Character type, for FreeRTOS+FAT when UNICODE is enabled. */ +#endif + +#if defined( _MSC_VER ) && ( _MSC_VER <= 1600 ) + #define FF_stricmp _stricmp +#else + #define FF_stricmp strcasecmp +#endif + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + void FF_tolower ( FF_T_WCHAR *string, uint32_t strLen ); + void FF_toupper ( FF_T_WCHAR *string, uint32_t strLen ); + BaseType_t FF_strmatch ( const FF_T_WCHAR *str1, const FF_T_WCHAR *str2, BaseType_t len ); + FF_T_WCHAR *FF_strtok ( const FF_T_WCHAR *string, FF_T_WCHAR *token, uint16_t *tokenNumber, BaseType_t *last, BaseType_t xLength ); + BaseType_t FF_wildcompare ( const FF_T_WCHAR *pcWildCard, const FF_T_WCHAR *pszString ); + + /* ASCII to UTF16 and UTF16 to ASCII routines. -- These are lossy routines, and are only for converting ASCII to UTF-16 */ + /* and the equivalent back to ASCII. Do not use them for international text. */ + void FF_cstrtowcs(FF_T_WCHAR *wcsDest, const char *szpSource); + void FF_wcstocstr(char *szpDest, const FF_T_WCHAR *wcsSource); + void FF_cstrntowcs(FF_T_WCHAR *wcsDest, const char *szpSource, uint32_t len); + void FF_wcsntocstr(char *szpDest, const FF_T_WCHAR *wcsSource, uint32_t len); +#else + void FF_tolower ( char *string, uint32_t strLen ); + void FF_toupper ( char *string, uint32_t strLen ); + BaseType_t FF_strmatch ( const char *str1, const char *str2, BaseType_t len ); + char *FF_strtok ( const char *string, char *token, uint16_t *tokenNumber, BaseType_t *last, BaseType_t xLength ); + BaseType_t FF_wildcompare ( const char *pcWildCard, const char *pszString ); +#endif /* ffconfigUNICODE_UTF16_SUPPORT */ + +/* UTF8 / UTF16 Transformation Functions. */ + +#if ( ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) && ( WCHAR_MAX > 0xFFFF ) ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + UBaseType_t FF_GetUtf16SequenceLen (uint16_t usLeadChar); +#endif + +#if( ffconfigUNICODE_UTF8_SUPPORT != 0 ) + int32_t FF_Utf8ctoUtf16c (uint16_t *utf16Dest, const uint8_t *utf8Source, uint32_t ulSize); + int32_t FF_Utf16ctoUtf8c (uint8_t *utf8Dest, const uint16_t *utf16Source, uint32_t ulSize); +#endif /* ffconfigUNICODE_UTF8_SUPPORT */ + +/* UTF16 / UTF32 Transformation Functions. */ + +#if( ffconfigNOT_USED_FOR_NOW != 0 ) + int32_t FF_Utf16ctoUtf32c(uint32_t *utf32Dest, const uint16_t *utf16Source); +#endif + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) && ( WCHAR_MAX > 0xFFFF ) + int32_t FF_Utf32ctoUtf16c(uint16_t *utf16Dest, uint32_t utf32char, uint32_t ulSize); +#endif + +/* String transformations. */ +int32_t FF_Utf32stoUtf8s(uint8_t *Utf8String, uint32_t *Utf32String); + +#if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) + #define STRNCPY( target, src, maxlen ) wcsncpy( ( target ), ( src ), ( maxlen ) ) + #define STRLEN( string ) wcslen( ( string ) ) +#else + #define STRNCPY( target, src, maxlen ) strncpy( ( target ), ( src ), ( maxlen ) ); + #define STRLEN( string ) strlen( ( string ) ) +#endif + +#endif + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_sys.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_sys.h new file mode 100644 index 000000000..692d2ca60 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_sys.h @@ -0,0 +1,129 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/* + ff_sys.h + + This module allow to map several separate file-sub-systems into a root directory + + For instance, a system with 3 sub sytems: + + /flash : NAND flash driver + /ram : RAM-disk driver + / : SD-card driver + + In this example, the SD-card driver handles ALL files and directories which + do not match /flash/ * or /ram/ * + + Now for instance a file call "/flash/etc/network.ini" + will be stored as "/etc/network.ini" on the NAND drive + + This module along with ff_stdio.c make translations between absolute + and relative paths +*/ + +#ifndef FF_SYS_H +#define FF_SYS_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct FILE_SUB_SYSTEM +{ + char pcPath[16]; + BaseType_t xPathlen; + FF_IOManager_t *pxManager; +} FF_SubSystem_t; + +typedef struct FF_DIR_HANDLER +{ + union + { + struct + { + unsigned + bEndOfDir : 1, + bFirstCalled : 1, + bIsValid : 1, + bAddDotEntries : 2; + } bits; + unsigned uFlags; + } u; + /* + * path will contain the relative path. It will be used when calling +FAT functions + * like FF_FindFirst() / FF_FindNext() + * For instance, for "/flash/etc" path will become "/etc" + */ + const char *pcPath; + FF_IOManager_t *pxManager; /* Will point to handler of this partition. */ + BaseType_t xFSIndex; /* The index of this entry, where 0 always means: the root system. */ +} FF_DirHandler_t; + +/* + * Initialise (clear) the file system table + * This will also called by FF_FS_Add() + */ +void FF_FS_Init( void ); + +/* + * Add a file system + * The path must be absolute, e.g. start with a slash + * The second argument is the FF_Disk_t structure that is handling the driver + */ +int FF_FS_Add( const char *pcPath, FF_Disk_t *pxDisk ); + +/* + * Remove a file system + * which ws earlier added by ff_fs_ad() + */ +void FF_FS_Remove( const char *pcPath ); + +/* + * Internally used by ff_stdio: + * The ff_dir_handler helps to iterate through a mounte directory + * + * FF_FS_Find() will find a ff_dir_handler for a given path + */ +int FF_FS_Find( const char *pcPath, FF_DirHandler_t *pxHandler ); + +/* + * For internal use: + * Get the file system information, based on an index + */ +int FF_FS_Get( int iIndex, FF_SubSystem_t *pxSystem ); + +/* + * Returns the number of registered + * file systems + */ +int FF_FS_Count( void ); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* FF_SYS_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_time.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_time.h new file mode 100644 index 000000000..06f26bd5e --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/include/ff_time.h @@ -0,0 +1,86 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/** + * @file ff_time.h + * @ingroup TIME + * + * Provides a means for receiving the time on any platform. + **/ + +#ifndef _FF_TIME_H_ +#define _FF_TIME_H_ + +#include + +#include "FreeRTOSFATConfig.h" + +/* _HT_ +The following declarations and functions may be moved to a common directory? + */ +typedef struct xTIME_STRUCT +{ + int tm_sec; /* Seconds */ + int tm_min; /* Minutes */ + int tm_hour; /* Hour (0--23) */ + int tm_mday; /* Day of month (1--31) */ + int tm_mon; /* Month (0--11) */ + int tm_year; /* Year (calendar year minus 1900) */ + int tm_wday; /* Weekday (0--6; Sunday = 0) */ + int tm_yday; /* Day of year (0--365) */ + int tm_isdst; /* 0 if daylight savings time is not in effect) */ +} FF_TimeStruct_t; + +/* Equivalent of time() : returns the number of seconds after 1-1-1970. */ +time_t FreeRTOS_time( time_t *pxTime ); + +/* Equivalent of mktime() : calculates the number of seconds after 1-1-1970. */ +time_t FreeRTOS_mktime( const FF_TimeStruct_t *pxTimeBuf ); + +/* Equivalent of gmtime_r() : Fills a 'struct tm'. */ +FF_TimeStruct_t *FreeRTOS_gmtime_r( const time_t *pxTime, FF_TimeStruct_t *pxTimeBuf ); + +/** + * @public + * @brief A TIME and DATE object for FreeRTOS+FAT. A FreeRTOS+FAT time driver must populate these values. + * + **/ +typedef struct +{ + uint16_t Year; /* Year (e.g. 2009). */ + uint16_t Month; /* Month (e.g. 1 = Jan, 12 = Dec). */ + uint16_t Day; /* Day (1 - 31). */ + uint16_t Hour; /* Hour (0 - 23). */ + uint16_t Minute; /* Min (0 - 59). */ + uint16_t Second; /* Second (0 - 59). */ +} FF_SystemTime_t; + +/*---------- PROTOTYPES */ + +int32_t FF_GetSystemTime(FF_SystemTime_t *pxTime); + +#endif + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/ATSAM4E/ff_sddisk.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/ATSAM4E/ff_sddisk.c new file mode 100644 index 000000000..9b2cc4a12 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/ATSAM4E/ff_sddisk.c @@ -0,0 +1,815 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/* Standard includes. */ +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "portmacro.h" + +/* FreeRTOS+FAT includes. */ +#include "ff_sddisk.h" +#include "ff_sys.h" + +/* Atmel includes. */ +#include +#include + +#include "hr_gettime.h" + +/* Misc definitions. */ +#define sdSIGNATURE 0x41404342UL +#define sdHUNDRED_64_BIT ( 100ull ) +#define sdBYTES_PER_MB ( 1024ull * 1024ull ) +#define sdSECTORS_PER_MB ( sdBYTES_PER_MB / 512ull ) +#define sdIOMAN_MEM_SIZE 4096 +#define xSDCardInfo ( sd_mmc_cards[ 0 ] ) +#define sdAligned( pvAddress ) ( ( ( ( size_t ) ( pvAddress ) ) & ( sizeof( size_t ) - 1 ) ) == 0 ) + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + + /* Define a time-out for all DMA transactions in msec. */ + #ifndef sdMAX_TRANSFER_TIME + #define sdMAX_TRANSFER_TIME 4000 + #endif + + /* Define all possible interrupts of interest. */ + #define sdHSMCI_INTERRUPT_FLAGS \ + HSMCI_IER_NOTBUSY | \ + HSMCI_IER_UNRE | \ + HSMCI_IER_OVRE | \ + HSMCI_IER_DTOE | \ + HSMCI_IER_DCRCE | \ + HSMCI_IER_TXBUFE | \ + HSMCI_IER_RXBUFF | \ + HSMCI_IER_XFRDONE + + #define sdMSMCI_USE_SEMAPHORE 1 + +#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ + +/*-----------------------------------------------------------*/ + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + + static TickType_t xDMARemainingTime; + static TimeOut_t xDMATimeOut; + static volatile uint32_t ulSDInterruptStatus; + static volatile int iWaitForWriting; + + #if( sdMSMCI_USE_SEMAPHORE != 0 ) + static SemaphoreHandle_t xSDSemaphore = NULL; + #else + static TaskHandle_t xSDTaskHandle = NULL; + #endif + +#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ + +/* + * Return pdFALSE if the SD card is not inserted. + */ +static BaseType_t prvSDDetect( void ); + +/* + * Check if the card is present, and if so, print out some info on the card. + */ +static BaseType_t prvSDMMCInit( BaseType_t xDriveNumber ); + +/*-----------------------------------------------------------*/ + +/* + * Mutex for partition. + */ +static SemaphoreHandle_t xPlusFATMutex = NULL; + +/* + * Remembers if the card is currently considered to be present. + */ +static BaseType_t xSDCardStatus = pdFALSE; + +/*-----------------------------------------------------------*/ + +typedef struct { + uint32_t ulStart; + uint32_t ulSize; +} MemoryGroup_t; + +#define ARRAY_SIZE(x) (int)(sizeof(x)/sizeof(x)[0]) + +static const MemoryGroup_t xMemories[] = { + { IRAM_ADDR, IRAM_SIZE }, + { EBI_CS1_ADDR, 512ul * 1024ul }, + { EBI_CS3_ADDR, 512ul * 1024ul }, +}; + +static BaseType_t prvIsInternalRAM( uint8_t *pucBuffer ) +{ +BaseType_t xResult = pdFALSE, xIndex; +uint32_t ulAddress = ( uint32_t ) pucBuffer; + + for( xIndex = 0; xIndex < ARRAY_SIZE( xMemories ); xIndex++ ) + { + if( ( ulAddress >= xMemories[ xIndex].ulStart ) && ( ulAddress < xMemories[ xIndex].ulStart + xMemories[ xIndex].ulSize ) ) + { + xResult = pdTRUE; + break; + } + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ) +{ +int32_t lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG, lResult = pdFALSE; + + if( ( pxDisk != NULL ) && + ( xSDCardStatus == pdPASS ) && + ( pxDisk->ulSignature == sdSIGNATURE ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( ulSectorNumber < pxDisk->ulNumberOfSectors ) && + ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) ) + { + /* As the MCI driver is configured to use DMA, it must be tested that + the buffer is located in internal SRAM ("IRAM") and if it is 4-byte aligned. */ + if( sdAligned( pucBuffer ) && prvIsInternalRAM( pucBuffer ) ) + { + lResult = sd_physical_read( ulSectorNumber, pucBuffer, ulSectorCount ); + } + else + { + uint32_t ulSector; + uint8_t *pucDMABuffer = ffconfigMALLOC( 512ul ); + + /* The buffer is NOT word-aligned, read to an aligned buffer and then + copy the data to the user provided buffer. */ + if( pucDMABuffer != NULL ) + { + for( ulSector = 0; ulSector < ulSectorCount; ulSector++ ) + { + lResult = sd_physical_read( ulSectorNumber + ulSector, pucDMABuffer, 1 ); + if( lResult == pdFALSE ) + { + break; + } + /* Copy to the user-provided buffer. */ + memcpy( pucBuffer + 512ul * ulSector, pucDMABuffer, 512ul ); + } + ffconfigFREE( pucDMABuffer ); + } + else + { + FF_PRINTF( "prvFFRead: malloc failed\n" ); + lResult = pdFALSE; + } + } + + if( lResult != pdFALSE ) + { + lReturnCode = 0L; + } + else + { + /* Some error occurred. */ + FF_PRINTF( "prvFFRead: %lu: %ld\n", ulSectorNumber, lResult ); + } + } + else + { + /* Make sure no random data is in the returned buffer. */ + memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512UL ); + + if( pxDisk->xStatus.bIsInitialised != pdFALSE ) + { + FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors ); + } + } + + return lReturnCode; +} +/*-----------------------------------------------------------*/ + +static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ) +{ +int32_t lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG, lResult = pdFALSE; + + if( ( pxDisk != NULL ) && + ( xSDCardStatus == pdPASS ) && + ( pxDisk->ulSignature == sdSIGNATURE ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( ulSectorNumber < pxDisk->ulNumberOfSectors ) && + ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) ) + { + /* As the MCI driver is configured to use DMA, it must be tested that + the buffer is located in internal SRAM ("IRAM") and if it is 4-byte aligned. */ + if( sdAligned( pucBuffer ) && prvIsInternalRAM( pucBuffer ) ) + { + lResult = sd_physical_write( ulSectorNumber, pucBuffer, ulSectorCount ); + } + else + { + uint32_t ulSector; + uint8_t *pucDMABuffer = ffconfigMALLOC( 512ul ); + + /* The buffer is NOT word-aligned, read to an aligned buffer and then + copy the data to the user provided buffer. */ + if( pucDMABuffer != NULL ) + { + for( ulSector = 0; ulSector < ulSectorCount; ulSector++ ) + { + /* Copy from the user provided buffer to the temporary buffer. */ + memcpy( pucDMABuffer, pucBuffer + 512ul * ulSector, 512ul ); + lResult = sd_physical_write( ulSectorNumber + ulSector, pucDMABuffer, 1 ); + if( lResult == pdFALSE ) + { + break; + } + } + ffconfigFREE( pucDMABuffer ); + } + else + { + FF_PRINTF( "prvFFWrite: malloc failed\n" ); + lResult = pdFALSE; + } + } + + if( lResult != pdFALSE ) + { + /* No errors. */ + lReturnCode = 0L; + } + else + { + FF_PRINTF( "prvFFWrite: %lu: %ld\n", ulSectorNumber, lResult ); + } + } + else + { + if( pxDisk->xStatus.bIsInitialised != pdFALSE ) + { + FF_PRINTF( "prvFFWrite: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors ); + } + } + + return lReturnCode; +} +/*-----------------------------------------------------------*/ + +void FF_SDDiskFlush( FF_Disk_t *pxDisk ) +{ + if( ( pxDisk != NULL ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( pxDisk->pxIOManager != NULL ) ) + { + FF_FlushCache( pxDisk->pxIOManager ); + } +} +/*-----------------------------------------------------------*/ + +/* Initialise the SDIO driver and mount an SD card */ +FF_Disk_t *FF_SDDiskInit( const char *pcName ) +{ +FF_Error_t xFFError; +BaseType_t xPartitionNumber = 0; +FF_CreationParameters_t xParameters; +FF_Disk_t *pxDisk; + + #if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + { + NVIC_SetPriority( HSMCI_IRQn, configHSMCI_INTERRUPT_PRIORITY ); + NVIC_EnableIRQ( HSMCI_IRQn ); + #if( sdMSMCI_USE_SEMAPHORE != 0 ) + { + if( xSDSemaphore == NULL ) + { + xSDSemaphore = xSemaphoreCreateBinary(); + } + } + #endif /* sdMSMCI_USE_SEMAPHORE */ + } + #endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ + + xSDCardStatus = prvSDMMCInit( 0 ); + + if( xSDCardStatus == pdPASS ) + { + pxDisk = (FF_Disk_t *)ffconfigMALLOC( sizeof( *pxDisk ) ); + if( pxDisk != NULL ) + { + /* Initialise the created disk structure. */ + memset( pxDisk, '\0', sizeof( *pxDisk ) ); + + /* The Atmel MMC driver sets capacity as a number of KB. + Divide by two to get the number of 512-byte sectors. */ + pxDisk->ulNumberOfSectors = xSDCardInfo.capacity << 1; + + if( xPlusFATMutex == NULL ) + { + xPlusFATMutex = xSemaphoreCreateRecursiveMutex(); + } + pxDisk->ulSignature = sdSIGNATURE; + + if( xPlusFATMutex != NULL) + { + memset( &xParameters, '\0', sizeof( xParameters ) ); + xParameters.ulMemorySize = sdIOMAN_MEM_SIZE; + xParameters.ulSectorSize = 512; + xParameters.fnWriteBlocks = prvFFWrite; + xParameters.fnReadBlocks = prvFFRead; + xParameters.pxDisk = pxDisk; + + /* prvFFRead()/prvFFWrite() are not re-entrant and must be + protected with the use of a semaphore. */ + xParameters.xBlockDeviceIsReentrant = pdFALSE; + + /* The semaphore will be used to protect critical sections in + the +FAT driver, and also to avoid concurrent calls to + prvFFRead()/prvFFWrite() from different tasks. */ + xParameters.pvSemaphore = ( void * ) xPlusFATMutex; + + pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError ); + + if( pxDisk->pxIOManager == NULL ) + { + FF_PRINTF( "FF_SDDiskInit: FF_CreateIOManger: %s\n", (const char*)FF_GetErrMessage( xFFError ) ); + FF_SDDiskDelete( pxDisk ); + pxDisk = NULL; + } + else + { + pxDisk->xStatus.bIsInitialised = pdTRUE; + pxDisk->xStatus.bPartitionNumber = xPartitionNumber; + if( FF_SDDiskMount( pxDisk ) == 0 ) + { + FF_SDDiskDelete( pxDisk ); + pxDisk = NULL; + } + else + { + if( pcName == NULL ) + { + pcName = "/"; + } + FF_FS_Add( pcName, pxDisk ); + FF_PRINTF( "FF_SDDiskInit: Mounted SD-card as root \"%s\"\n", pcName ); + } + } /* if( pxDisk->pxIOManager != NULL ) */ + } /* if( xPlusFATMutex != NULL) */ + } /* if( pxDisk != NULL ) */ + else + { + FF_PRINTF( "FF_SDDiskInit: Malloc failed\n" ); + } + } /* if( xSDCardStatus == pdPASS ) */ + else + { + FF_PRINTF( "FF_SDDiskInit: prvSDMMC_Init failed\n" ); + pxDisk = NULL; + } + + return pxDisk; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskFormat( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber ) +{ +FF_Error_t xError; +BaseType_t xReturn = pdFAIL; + + xError = FF_Unmount( pxDisk ); + + if( FF_isERR( xError ) != pdFALSE ) + { + FF_PRINTF( "FF_SDDiskFormat: unmount fails: %08x\n", ( unsigned ) xError ); + } + else + { + /* Format the drive - try FAT32 with large clusters. */ + xError = FF_Format( pxDisk, xPartitionNumber, pdFALSE, pdFALSE); + + if( FF_isERR( xError ) ) + { + FF_PRINTF( "FF_SDDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) ); + } + else + { + FF_PRINTF( "FF_SDDiskFormat: OK, now remounting\n" ); + pxDisk->xStatus.bPartitionNumber = xPartitionNumber; + xError = FF_SDDiskMount( pxDisk ); + FF_PRINTF( "FF_SDDiskFormat: rc %08x\n", ( unsigned )xError ); + if( FF_isERR( xError ) == pdFALSE ) + { + xReturn = pdPASS; + } + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskUnmount( FF_Disk_t *pxDisk ) +{ +FF_Error_t xFFError; +BaseType_t xReturn = pdPASS; + + if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsMounted != pdFALSE ) ) + { + pxDisk->xStatus.bIsMounted = pdFALSE; + xFFError = FF_Unmount( pxDisk ); + + if( FF_isERR( xFFError ) ) + { + FF_PRINTF( "FF_SDDiskUnmount: rc %08x\n", ( unsigned )xFFError ); + xReturn = pdFAIL; + } + else + { + FF_PRINTF( "Drive unmounted\n" ); + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskReinit( FF_Disk_t *pxDisk ) +{ +BaseType_t xStatus = prvSDMMCInit( 0 ); /* Hard coded index. */ + + /*_RB_ parameter not used. */ + ( void ) pxDisk; + + FF_PRINTF( "FF_SDDiskReinit: rc %08x\n", ( unsigned ) xStatus ); + return xStatus; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskMount( FF_Disk_t *pxDisk ) +{ +FF_Error_t xFFError; +BaseType_t xReturn; + + /* Mount the partition */ + xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber ); + + if( FF_isERR( xFFError ) ) + { + FF_PRINTF( "FF_SDDiskMount: %08lX\n", xFFError ); + xReturn = pdFAIL; + } + else + { + pxDisk->xStatus.bIsMounted = pdTRUE; + FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors ); + FF_SDDiskShowPartition( pxDisk ); + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +FF_IOManager_t *sddisk_ioman( FF_Disk_t *pxDisk ) +{ +FF_IOManager_t *pxReturn; + + if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) ) + { + pxReturn = pxDisk->pxIOManager; + } + else + { + pxReturn = NULL; + } + return pxReturn; +} +/*-----------------------------------------------------------*/ + +/* Release all resources */ +BaseType_t FF_SDDiskDelete( FF_Disk_t *pxDisk ) +{ + if( pxDisk != NULL ) + { + pxDisk->ulSignature = 0; + pxDisk->xStatus.bIsInitialised = 0; + if( pxDisk->pxIOManager != NULL ) + { + if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE ) + { + FF_Unmount( pxDisk ); + } + FF_DeleteIOManager( pxDisk->pxIOManager ); + } + + vPortFree( pxDisk ); + } + return 1; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskShowPartition( FF_Disk_t *pxDisk ) +{ +FF_Error_t xError; +uint64_t ullFreeSectors; +uint32_t ulTotalSizeMB, ulFreeSizeMB; +int iPercentageFree; +FF_IOManager_t *pxIOManager; +const char *pcTypeName = "unknown type"; +BaseType_t xReturn = pdPASS; + + if( pxDisk == NULL ) + { + xReturn = pdFAIL; + } + else + { + pxIOManager = pxDisk->pxIOManager; + + FF_PRINTF( "Reading FAT and calculating Free Space\n" ); + + switch( pxIOManager->xPartition.ucType ) + { + case FF_T_FAT12: + pcTypeName = "FAT12"; + break; + + case FF_T_FAT16: + pcTypeName = "FAT16"; + break; + + case FF_T_FAT32: + pcTypeName = "FAT32"; + break; + + default: + pcTypeName = "UNKOWN"; + break; + } + + FF_GetFreeSize( pxIOManager, &xError ); + + ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster; + iPercentageFree = ( int ) ( ( sdHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) / + ( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) ); + + ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / sdSECTORS_PER_MB; + ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / sdSECTORS_PER_MB ); + + /* It is better not to use the 64-bit format such as %Lu because it + might not be implemented. */ + FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber ); + FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName ); + FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel ); + FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors ); + FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster ); + FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB ); + FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskDetect( FF_Disk_t *pxDisk ) +{ +BaseType_t xIsPresent; +void *pvSemaphore; + + if( ( pxDisk != NULL ) && ( pxDisk->pxIOManager ) ) + { + pvSemaphore = pxDisk->pxIOManager->pvSemaphore; + } + else + { + pvSemaphore = NULL; + } + + /*_RB_ Can these NULL checks be moved inside the FF_nnnSemaphore() functions? */ + /*_HT_ I'm afraid not, both functions start with configASSERT( pxSemaphore ); */ + if( pvSemaphore != NULL ) + { + FF_PendSemaphore( pvSemaphore ); + } + + xIsPresent = prvSDDetect(); + + if( pvSemaphore != NULL ) + { + FF_ReleaseSemaphore( pvSemaphore ); + } + + return xIsPresent; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvSDDetect( void ) +{ +static BaseType_t xWasPresent; +BaseType_t xIsPresent; +sd_mmc_err_t xSDPresence; + + if( xWasPresent == pdFALSE ) + { + /* Try to initialize SD MMC stack */ + sd_mmc_init(); + xSDPresence = sd_mmc_check( 0 ); + if( ( xSDPresence == SD_MMC_OK ) || ( xSDPresence == SD_MMC_INIT_ONGOING ) ) + { + xIsPresent = pdTRUE; + } + else + { + xIsPresent = pdFALSE; + } + } + else + { + /* See if the card is still present. */ + xSDPresence = sd_mmc_check_status(0); + if( xSDPresence == SD_MMC_OK ) + { + xIsPresent = pdTRUE; + } + else + { + xIsPresent = pdFALSE; + } + } + xWasPresent = xIsPresent; + + return xIsPresent; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvSDMMCInit( BaseType_t xDriveNumber ) +{ +BaseType_t xReturn; + + /* 'xDriveNumber' not yet in use. */ + ( void ) xDriveNumber; + + /* Check if the SD card is plugged in the slot */ + if( prvSDDetect() == pdFALSE ) + { + FF_PRINTF( "No SD card detected\n" ); + xReturn = pdFAIL; + } + else + { + FF_PRINTF( "HAL_SD_Init: type: %s Capacity: %lu MB\n", + xSDCardInfo.type & CARD_TYPE_HC ? "SDHC" : "SD", + ( xSDCardInfo.capacity << 1 ) / 2048 ); + + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + void HSMCI_Handler( void ) + { + uint32_t ulSR; + BaseType_t xSwitchRequired = pdFALSE; + + ulSR = HSMCI->HSMCI_SR & HSMCI->HSMCI_IMR; + HSMCI->HSMCI_IDR = ulSR; + ulSDInterruptStatus |= ulSR; + #if( sdMSMCI_USE_SEMAPHORE != 0 ) + { + if( xSDSemaphore != NULL ) + { + xSemaphoreGiveFromISR( xSDSemaphore, &xSwitchRequired ); + } + } + #else + { + if( xSDTaskHandle != NULL ) + { + vTaskNotifyGiveFromISR( xSDTaskHandle, ( BaseType_t * ) &xSwitchRequired ); + } + } + #endif + if( xSwitchRequired != pdFALSE ) + { + portEND_SWITCHING_ISR( xSwitchRequired ); + } + } +#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ +/*-----------------------------------------------------------*/ + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + void vMCIEventSetupFunction( int iForWriting ) + { + iWaitForWriting = iForWriting != 0; + + #if( sdMSMCI_USE_SEMAPHORE == 0 ) + { + xSDTaskHandle = xTaskGetCurrentTaskHandle(); + } + #endif + ulSDInterruptStatus = 0; + HSMCI->HSMCI_IER = sdHSMCI_INTERRUPT_FLAGS; + + /* A DMA transfer to or from the SD-card is about to start. + Reset the timers that will be used in prvEventWaitFunction() */ + xDMARemainingTime = pdMS_TO_TICKS( sdMAX_TRANSFER_TIME ); + vTaskSetTimeOutState( &xDMATimeOut ); + } +#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ +/*-----------------------------------------------------------*/ + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + void vMCIEventReadyFunction() + { + #if( sdMSMCI_USE_SEMAPHORE == 0 ) + { + xSDTaskHandle = NULL; + } + #endif + ulSDInterruptStatus = 0; + HSMCI->HSMCI_IDR = sdHSMCI_INTERRUPT_FLAGS; + } +#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ +/*-----------------------------------------------------------*/ + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + uint32_t ulMCIEventWaitFunction( uint32_t ulMask ) + { + /* + * It was measured how quickly a DMA interrupt was received. It varied + * between 0 and 4 ms. + * <= 1 ms : 8047 + * <= 2 ms : 1850 + * <= 3 ms : 99 + * <= 4 ms : 79 + * >= 5 ms : 0 times + */ + if( xTaskCheckForTimeOut( &xDMATimeOut, &xDMARemainingTime ) != pdFALSE ) + { + /* The timeout has been reached, no need to block. */ + FF_PRINTF( "ulMCIEventWaitFunction: %s timed out. SR = %08x\n", + iWaitForWriting ? "Write" : "Read", ulSDInterruptStatus ); + } + else + { + /* The timeout has not been reached yet, block on the semaphore. */ + #if( sdMSMCI_USE_SEMAPHORE != 0 ) + { + if( ( ulSDInterruptStatus & ulMask ) == 0ul ) + { + xSemaphoreTake( xSDSemaphore, xDMARemainingTime ); + } + } + #else + { + if( ( ulSDInterruptStatus & ulMask ) == 0ul ) + { + ulTaskNotifyTake( pdFALSE, xDMARemainingTime ); + } + } + #endif + if( xTaskCheckForTimeOut( &xDMATimeOut, &xDMARemainingTime ) != pdFALSE ) + { + FF_PRINTF( "ulMCIEventWaitFunction: %s timed out. SR = %08x\n", + iWaitForWriting ? "Write" : "Read", ulSDInterruptStatus ); + } + } + + return ulSDInterruptStatus; + } +#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/ATSAM4E/ff_sddisk_r.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/ATSAM4E/ff_sddisk_r.c new file mode 100644 index 000000000..32c768c37 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/ATSAM4E/ff_sddisk_r.c @@ -0,0 +1,552 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/* Standard includes. */ +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "portmacro.h" + +/* FreeRTOS+FAT includes. */ +#include "ff_sddisk.h" +#include "ff_sys.h" + +/* Atmel includes. */ +#include + +/* Misc definitions. */ +#define sdSIGNATURE 0x41404342UL +#define sdHUNDRED_64_BIT ( 100ull ) +#define sdBYTES_PER_MB ( 1024ull * 1024ull ) +#define sdSECTORS_PER_MB ( sdBYTES_PER_MB / 512ull ) +#define sdIOMAN_MEM_SIZE 4096 +#define xSDCardInfo ( sd_mmc_cards[ 0 ] ) + +/*-----------------------------------------------------------*/ + +/* + * Return pdFALSE if the SD card is not inserted. + */ +static BaseType_t prvSDDetect( void ); + +/* + * Check if the card is present, and if so, print out some info on the card. + */ +static BaseType_t prvSDMMCInit( BaseType_t xDriveNumber ); + +/*-----------------------------------------------------------*/ + +/* + * Mutex for partition. + */ +static SemaphoreHandle_t xPlusFATMutex = NULL; + +/* + * Remembers if the card is currently considered to be present. + */ +static BaseType_t xSDCardStatus = pdFALSE; + +/*-----------------------------------------------------------*/ + +static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ) +{ +int32_t lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG, lResult; + + if( ( pxDisk != NULL ) && + ( xSDCardStatus == pdPASS ) && + ( pxDisk->ulSignature == sdSIGNATURE ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( ulSectorNumber < pxDisk->ulNumberOfSectors ) && + ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) ) + { + lResult = sd_physical_read( ulSectorNumber, pucBuffer, ulSectorCount); + + if( lResult != pdFALSE ) + { + lReturnCode = 0L; + } + else + { + /* Some error occurred. */ + FF_PRINTF( "prvFFRead: %lu: %lu\n", ulSectorNumber, lResult ); + } + } + else + { + /* Make sure no random data is in the returned buffer. */ + memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512UL ); + + if( pxDisk->xStatus.bIsInitialised != pdFALSE ) + { + FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors ); + } + } + + return lReturnCode; +} +/*-----------------------------------------------------------*/ + +static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ) +{ +int32_t lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG; +BaseType_t xResult; + + if( ( pxDisk != NULL ) && + ( xSDCardStatus == pdPASS ) && + ( pxDisk->ulSignature == sdSIGNATURE ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( ulSectorNumber < pxDisk->ulNumberOfSectors ) && + ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) ) + { + xResult = sd_physical_write( ulSectorNumber, pucBuffer, ulSectorCount ); + + if( xResult != pdFALSE ) + { + /* No errors. */ + lReturnCode = 0L; + } + else + { + FF_PRINTF( "prvFFWrite: %lu: %lu\n", ulSectorNumber, xResult ); + } + } + else + { + if( pxDisk->xStatus.bIsInitialised != pdFALSE ) + { + FF_PRINTF( "prvFFWrite: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors ); + } + } + + return lReturnCode; +} +/*-----------------------------------------------------------*/ + +void FF_SDDiskFlush( FF_Disk_t *pxDisk ) +{ + if( ( pxDisk != NULL ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( pxDisk->pxIOManager != NULL ) ) + { + FF_FlushCache( pxDisk->pxIOManager ); + } +} +/*-----------------------------------------------------------*/ + +/* Initialise the SDIO driver and mount an SD card */ +FF_Disk_t *FF_SDDiskInit( const char *pcName ) +{ +FF_Error_t xFFError; +BaseType_t xPartitionNumber = 0; +FF_CreationParameters_t xParameters; +FF_Disk_t *pxDisk; + + xSDCardStatus = prvSDMMCInit( 0 ); + + if( xSDCardStatus != pdPASS ) + { + FF_PRINTF( "FF_SDDiskInit: prvSDMMCInit failed\n" ); + pxDisk = NULL; + } + else + { + pxDisk = ( FF_Disk_t * )pvPortMalloc( sizeof( *pxDisk ) ); + if( pxDisk == NULL ) + { + FF_PRINTF( "FF_SDDiskInit: Malloc failed\n" ); + } + else + { + /* Initialise the created disk structure. */ + memset( pxDisk, '\0', sizeof( *pxDisk ) ); + + /* The Atmel MMC driver sets capacity as a number of KB. + Divide by two to get the number of 512-byte sectors. */ + pxDisk->ulNumberOfSectors = xSDCardInfo.capacity << 1; + + if( xPlusFATMutex == NULL ) + { + xPlusFATMutex = xSemaphoreCreateRecursiveMutex(); + } + pxDisk->ulSignature = sdSIGNATURE; + + if( xPlusFATMutex != NULL) + { + memset( &xParameters, '\0', sizeof( xParameters ) ); + xParameters.ulMemorySize = sdIOMAN_MEM_SIZE; + xParameters.ulSectorSize = 512; + xParameters.fnWriteBlocks = prvFFWrite; + xParameters.fnReadBlocks = prvFFRead; + xParameters.pxDisk = pxDisk; + + /* prvFFRead()/prvFFWrite() are not re-entrant and must be + protected with the use of a semaphore. */ + xParameters.xBlockDeviceIsReentrant = pdFALSE; + + /* The semaphore will be used to protect critical sections in + the +FAT driver, and also to avoid concurrent calls to + prvFFRead()/prvFFWrite() from different tasks. */ + xParameters.pvSemaphore = ( void * ) xPlusFATMutex; + + pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError ); + + if( pxDisk->pxIOManager == NULL ) + { + FF_PRINTF( "FF_SDDiskInit: FF_CreateIOManger: %s\n", (const char*)FF_GetErrMessage( xFFError ) ); + FF_SDDiskDelete( pxDisk ); + pxDisk = NULL; + } + else + { + pxDisk->xStatus.bIsInitialised = pdTRUE; + pxDisk->xStatus.bPartitionNumber = xPartitionNumber; + if( FF_SDDiskMount( pxDisk ) == 0 ) + { + FF_SDDiskDelete( pxDisk ); + pxDisk = NULL; + } + else + { + if( pcName == NULL ) + { + pcName = "/"; + } + FF_FS_Add( pcName, pxDisk ); + FF_PRINTF( "FF_SDDiskInit: Mounted SD-card as root \"%s\"\n", pcName ); + FF_SDDiskShowPartition( pxDisk ); + } + } /* if( pxDisk->pxIOManager != NULL ) */ + } /* if( xPlusFATMutex != NULL) */ + } /* if( pxDisk != NULL ) */ + } /* if( xSDCardStatus == pdPASS ) */ + + return pxDisk; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskFormat( FF_Disk_t *pxDisk, BaseType_t aPart ) +{ +FF_Error_t xError; +BaseType_t xReturn = pdFAIL; + + xError = FF_Unmount( pxDisk ); + + if( FF_isERR( xError ) != pdFALSE ) + { + FF_PRINTF( "FF_SDDiskFormat: unmount fails: %08x\n", ( unsigned ) xError ); + } + else + { + /* Format the drive - try FAT32 with large clusters. */ + xError = FF_Format( pxDisk, aPart, pdFALSE, pdFALSE); + + if( FF_isERR( xError ) ) + { + FF_PRINTF( "FF_SDDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) ); + } + else + { + FF_PRINTF( "FF_SDDiskFormat: OK, now remounting\n" ); + pxDisk->xStatus.bPartitionNumber = aPart; + xError = FF_SDDiskMount( pxDisk ); + FF_PRINTF( "FF_SDDiskFormat: rc %08x\n", ( unsigned )xError ); + if( FF_isERR( xError ) == pdFALSE ) + { + xReturn = pdPASS; + FF_SDDiskShowPartition( pxDisk ); + } + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskUnmount( FF_Disk_t *pxDisk ) +{ +FF_Error_t xFFError; +BaseType_t xReturn = pdPASS; + + if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsMounted != pdFALSE ) ) + { + pxDisk->xStatus.bIsMounted = pdFALSE; + xFFError = FF_Unmount( pxDisk ); + + if( FF_isERR( xFFError ) ) + { + FF_PRINTF( "FF_SDDiskUnmount: rc %08x\n", ( unsigned )xFFError ); + xReturn = pdFAIL; + } + else + { + FF_PRINTF( "Drive unmounted\n" ); + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskReinit( FF_Disk_t *pxDisk ) +{ +BaseType_t xStatus = prvSDMMCInit( 0 ); /* Hard coded index. */ + + /*_RB_ parameter not used. */ + ( void ) pxDisk; + + FF_PRINTF( "FF_SDDiskReinit: rc %08x\n", ( unsigned ) xStatus ); + return xStatus; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskMount( FF_Disk_t *pxDisk ) +{ +FF_Error_t xFFError; +BaseType_t xReturn; + + /* Mount the partition */ + xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber ); + + if( FF_isERR( xFFError ) ) + { + FF_PRINTF( "FF_SDDiskMount: %08lX\n", xFFError ); + xReturn = pdFAIL; + } + else + { + pxDisk->xStatus.bIsMounted = pdTRUE; + FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors ); + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +FF_IOManager_t *sddisk_ioman( FF_Disk_t *pxDisk ) +{ +FF_IOManager_t *pxReturn; + + if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) ) + { + pxReturn = pxDisk->pxIOManager; + } + else + { + pxReturn = NULL; + } + return pxReturn; +} +/*-----------------------------------------------------------*/ + +/* Release all resources */ +BaseType_t FF_SDDiskDelete( FF_Disk_t *pxDisk ) +{ + if( pxDisk != NULL ) + { + pxDisk->ulSignature = 0; + pxDisk->xStatus.bIsInitialised = 0; + if( pxDisk->pxIOManager != NULL ) + { + if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE ) + { + FF_Unmount( pxDisk ); + } + FF_DeleteIOManager( pxDisk->pxIOManager ); + } + + vPortFree( pxDisk ); + } + return 1; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskShowPartition( FF_Disk_t *pxDisk ) +{ +FF_Error_t xError; +uint64_t ullFreeSectors; +uint32_t ulTotalSizeMB, ulFreeSizeMB; +int iPercentageFree; +FF_IOManager_t *pxIOManager; +const char *pcTypeName = "unknown type"; +BaseType_t xReturn = pdPASS; + + if( pxDisk == NULL ) + { + xReturn = pdFAIL; + } + else + { + pxIOManager = pxDisk->pxIOManager; + + FF_PRINTF( "Reading FAT and calculating Free Space\n" ); + + switch( pxIOManager->xPartition.ucType ) + { + case FF_T_FAT12: + pcTypeName = "FAT12"; + break; + + case FF_T_FAT16: + pcTypeName = "FAT16"; + break; + + case FF_T_FAT32: + pcTypeName = "FAT32"; + break; + + default: + pcTypeName = "UNKOWN"; + break; + } + + FF_GetFreeSize( pxIOManager, &xError ); + + ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster; + iPercentageFree = ( int ) ( ( sdHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) / + ( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) ); + + ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / sdSECTORS_PER_MB; + ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / sdSECTORS_PER_MB ); + + /* It is better not to use the 64-bit format such as %Lu because it + might not be implemented. */ + FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber ); + FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName ); + FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel ); + FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors ); + FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster ); + FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB ); + FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskDetect( FF_Disk_t *pxDisk ) +{ +BaseType_t xIsPresent; +void *pvSemaphore; + + if( ( pxDisk != NULL ) && + ( pxDisk->pxIOManager ) ) + { + pvSemaphore = pxDisk->pxIOManager->pvSemaphore; + } + else + { + pvSemaphore = NULL; + } + + /*_RB_ Can these NULL checks be moved inside the FF_nnnSemaphore() functions? */ + /*_HT_ I'm afraid not, both functions start with configASSERT( pxSemaphore ); */ + if( pvSemaphore != NULL ) + { + FF_PendSemaphore( pvSemaphore ); + } + + xIsPresent = prvSDDetect(); + + if( pvSemaphore != NULL ) + { + FF_ReleaseSemaphore( pvSemaphore ); + } + + return xIsPresent; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvSDDetect( void ) +{ +static BaseType_t xWasPresent; +BaseType_t xIsPresent; +sd_mmc_err_t xSDPresence; + + if( xWasPresent == pdFALSE ) + { + /* Try to initialize SD MMC stack */ + sd_mmc_init(); + xSDPresence = sd_mmc_check( 0 ); + if( ( xSDPresence == SD_MMC_OK ) || ( xSDPresence == SD_MMC_INIT_ONGOING ) ) + { + xIsPresent = pdTRUE; + } + else + { + xIsPresent = pdFALSE; + } + } + else + { + /* See if the card is still present. */ + xSDPresence = sd_mmc_check_status(0); + if( xSDPresence == SD_MMC_OK ) + { + xIsPresent = pdTRUE; + } + else + { + xIsPresent = pdFALSE; + } + } + xWasPresent = xIsPresent; + + return xIsPresent; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvSDMMCInit( BaseType_t xDriveNumber ) +{ +BaseType_t xReturn; + + /* 'xDriveNumber' not yet in use. */ + ( void ) xDriveNumber; + + /* Check if the SD card is plugged in the slot */ + if( prvSDDetect() == pdFALSE ) + { + FF_PRINTF( "No SD card detected\n" ); + xReturn = pdFAIL; + } + else + { + FF_PRINTF( "HAL_SD_Init: type: %s Capacity: %lu MB\n", + xSDCardInfo.type & CARD_TYPE_HC ? "SDHC" : "SD", + ( xSDCardInfo.capacity << 1 ) / 2048 ); + + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/README_DRIVER_DISCLAIMER.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/README_DRIVER_DISCLAIMER.txt new file mode 100644 index 000000000..f762dad63 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/README_DRIVER_DISCLAIMER.txt @@ -0,0 +1,11 @@ +Disk drivers are provided as examples only, and do not form part of the +FreeRTOS+FAT itself. They: + + + May be based on driver code provided by the chip vendors, + + May not have been tested in all possible configurations, + + Will not necessarily be optimised. + + May not necessarily comply with any particular coding standard. + + May have dependencies on chip company libraries. + + May include other hardware board dependencies. + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F4xx/ff_sddisk.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F4xx/ff_sddisk.c new file mode 100644 index 000000000..bb718e030 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F4xx/ff_sddisk.c @@ -0,0 +1,1121 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/* Standard includes. */ +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "portmacro.h" + +/* FreeRTOS+FAT includes. */ +#include "ff_sddisk.h" +#include "ff_sys.h" + +/* ST HAL includes. */ +#include "stm32f4xx_hal.h" + +/* Misc definitions. */ +#define sdSIGNATURE 0x41404342UL +#define sdHUNDRED_64_BIT ( 100ull ) +#define sdBYTES_PER_MB ( 1024ull * 1024ull ) +#define sdSECTORS_PER_MB ( sdBYTES_PER_MB / 512ull ) +#define sdIOMAN_MEM_SIZE 4096 + +/* DMA constants. */ +#define SD_DMAx_Tx_CHANNEL DMA_CHANNEL_4 +#define SD_DMAx_Rx_CHANNEL DMA_CHANNEL_4 +#define SD_DMAx_Tx_STREAM DMA2_Stream6 +#define SD_DMAx_Rx_STREAM DMA2_Stream3 +#define SD_DMAx_Tx_IRQn DMA2_Stream6_IRQn +#define SD_DMAx_Rx_IRQn DMA2_Stream3_IRQn +#define __DMAx_TxRx_CLK_ENABLE __DMA2_CLK_ENABLE +#define configSDIO_DMA_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY ) + +/* Define a time-out for all DMA transactions in msec. */ +#ifndef sdMAX_TIME_TICKS + #define sdMAX_TIME_TICKS pdMS_TO_TICKS( 2000UL ) +#endif + +#ifndef configSD_DETECT_PIN + #error configSD_DETECT_PIN must be defined in FreeRTOSConfig.h to the pin used to detect if the SD card is present. +#endif + +#ifndef configSD_DETECT_GPIO_PORT + #error configSD_DETECT_GPIO_PORT must be defined in FreeRTOSConfig.h to the port on which configSD_DETECT_PIN is located. +#endif + +#ifndef sdCARD_DETECT_DEBOUNCE_TIME_MS + /* Debouncing time is applied only after card gets inserted. */ + #define sdCARD_DETECT_DEBOUNCE_TIME_MS ( 5000 ) +#endif + +#ifndef sdARRAY_SIZE + #define sdARRAY_SIZE( x ) ( int )( sizeof( x ) / sizeof( x )[ 0 ] ) +#endif + +/*-----------------------------------------------------------*/ + +/* + * Return pdFALSE if the SD card is not inserted. This function just reads the + * value of the GPIO C/D pin. + */ +static BaseType_t prvSDDetect( void ); + +/* + * Translate a numeric code like 'SD_TX_UNDERRUN' to a printable string. + */ +static const char *prvSDCodePrintable( uint32_t ulCode ); + +/* + * The following 'hook' must be provided by the user of this module. It will be + * called from a GPIO ISR after every change. Note that during the ISR, the + * value of the GPIO is not stable and it can not be used. All you can do from + * this hook is wake-up some task, which will call FF_SDDiskDetect(). + */ +extern void vApplicationCardDetectChangeHookFromISR( BaseType_t *pxHigherPriorityTaskWoken ); + +/* + * Hardware initialisation. + */ +static void prvSDIO_SD_Init( void ); +static void vGPIO_SD_Init( SD_HandleTypeDef* xSDHandle ); + +/* + * Check if the card is present, and if so, print out some info on the card. + */ +static BaseType_t prvSDMMCInit( BaseType_t xDriveNumber ); + +#if( SDIO_USES_DMA != 0 ) + /* + * Initialise the DMA for SDIO cards. + */ + static void prvSDIO_DMA_Init( void ); +#endif + +#if( SDIO_USES_DMA != 0 ) + /* + * A function will be called at the start of a DMA action. + */ + static void prvEventSetupFunction( SD_HandleTypeDef * pxHandle ); +#endif + +#if( SDIO_USES_DMA != 0 ) + /* + * This function is supposed to wait for an event: SDIO or DMA. + * Return non-zero if a timeout has been reached. + */ + static uint32_t prvEventWaitFunction( SD_HandleTypeDef *pxHandle ); +#endif + +/*-----------------------------------------------------------*/ + +typedef struct +{ + /* Only after a card has been inserted, debouncing is necessary. */ + TickType_t xRemainingTime; + TimeOut_t xTimeOut; + UBaseType_t + bLastPresent : 1, + bStableSignal : 1; +} CardDetect_t; + +/* Used to handle timeouts. */ +static TickType_t xDMARemainingTime; +static TimeOut_t xDMATimeOut; + +/* Used to unblock the task that calls prvEventWaitFunction() after an event has +occurred. */ +static SemaphoreHandle_t xSDCardSemaphore = NULL; + +/* Handle of the SD card being used. */ +static SD_HandleTypeDef xSDHandle; + +/* Holds parameters for the detected SD card. */ +static HAL_SD_CardInfoTypedef xSDCardInfo; + +/* Mutex for partition. */ +static SemaphoreHandle_t xPlusFATMutex = NULL; + +/* Remembers if the card is currently considered to be present. */ +static BaseType_t xSDCardStatus = pdFALSE; + +/* Maintains state for card detection. */ +static CardDetect_t xCardDetect; + +/*-----------------------------------------------------------*/ + +static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ) +{ +int32_t lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG; + + if( ( pxDisk != NULL ) && + ( xSDCardStatus == pdPASS ) && + ( pxDisk->ulSignature == sdSIGNATURE ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( ulSectorNumber < pxDisk->ulNumberOfSectors ) && + ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) ) + { + uint64_t ullReadAddr; + HAL_SD_ErrorTypedef sd_result; + + ullReadAddr = 512ull * ( uint64_t ) ulSectorNumber; + + #if( SDIO_USES_DMA == 0 ) + { + sd_result = HAL_SD_ReadBlocks( &xSDHandle, (uint32_t *) pucBuffer, ullReadAddr, 512ul, ulSectorCount ); + } + #else + { + if( ( ( ( size_t )pucBuffer ) & ( sizeof( size_t ) - 1 ) ) == 0 ) + { + /* The buffer is word-aligned, call DMA read directly. */ + sd_result = HAL_SD_ReadBlocks_DMA( &xSDHandle, (uint32_t *) pucBuffer, ullReadAddr, 512ul, ulSectorCount); + if( sd_result == SD_OK ) + { + sd_result = HAL_SD_CheckReadOperation( &xSDHandle, sdMAX_TIME_TICKS ); + } + } + else + { + uint32_t ulSector; + uint8_t *pucDMABuffer = ffconfigMALLOC( 512ul ); + + /* The buffer is NOT word-aligned, copy first to an aligned buffer. */ + if( pucDMABuffer != NULL ) + { + sd_result = SD_OK; + for( ulSector = 0; ulSector < ulSectorCount; ulSector++ ) + { + ullReadAddr = 512ull * ( ( uint64_t ) ulSectorNumber + ( uint64_t ) ulSector ); + sd_result = HAL_SD_ReadBlocks_DMA( &xSDHandle, ( uint32_t * )pucDMABuffer, ullReadAddr, 512ul, 1 ); + + if( sd_result == SD_OK ) + { + sd_result = HAL_SD_CheckReadOperation( &xSDHandle, sdMAX_TIME_TICKS ); + if( sd_result != SD_OK ) + { + break; + } + memcpy( pucBuffer + 512ul * ulSector, pucDMABuffer, 512ul ); + } + } + ffconfigFREE( pucDMABuffer ); + } + else + { + sd_result = SD_INVALID_PARAMETER; + } + } + } + #endif /* SDIO_USES_DMA */ + + if( sd_result == SD_OK ) + { + lReturnCode = 0L; + } + else + { + /* Some error occurred. */ + FF_PRINTF( "prvFFRead: %lu: %u (%s)\n", ulSectorNumber, sd_result, prvSDCodePrintable( sd_result ) ); + } + } + else + { + /* Make sure no random data is in the returned buffer. */ + memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512UL ); + + if( pxDisk->xStatus.bIsInitialised != pdFALSE ) + { + FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors ); + } + } + + return lReturnCode; +} +/*-----------------------------------------------------------*/ + +static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ) +{ +int32_t lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG; + + if( ( pxDisk != NULL ) && + ( xSDCardStatus == pdPASS ) && + ( pxDisk->ulSignature == sdSIGNATURE ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( ulSectorNumber < pxDisk->ulNumberOfSectors ) && + ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) ) + { + HAL_SD_ErrorTypedef sd_result; + uint64_t ullWriteAddr; + ullWriteAddr = 512ull * ulSectorNumber; + + #if( SDIO_USES_DMA == 0 ) + { + sd_result = HAL_SD_WriteBlocks( &xSDHandle, ( uint32_t * )pucBuffer, ullWriteAddr, 512ul, ulSectorCount ); + } + #else + { + if( ( ( ( size_t )pucBuffer ) & ( sizeof( size_t ) - 1 ) ) == 0 ) + { + /* The buffer is word-aligned, call DMA reawrite directly. */ + sd_result = HAL_SD_WriteBlocks_DMA( &xSDHandle, ( uint32_t * )pucBuffer, ullWriteAddr, 512ul, ulSectorCount ); + if( sd_result == SD_OK ) + { + sd_result = HAL_SD_CheckWriteOperation( &xSDHandle, sdMAX_TIME_TICKS ); + } + } + else + { + uint32_t ulSector; + uint8_t *pucDMABuffer = ffconfigMALLOC( 512ul ); + + /* The buffer is NOT word-aligned, read to an aligned buffer and then + copy the data to the user provided buffer. */ + if( pucDMABuffer != NULL ) + { + sd_result = SD_OK; + for( ulSector = 0; ulSector < ulSectorCount; ulSector++ ) + { + memcpy( pucDMABuffer, pucBuffer + 512ul * ulSector, 512ul ); + ullWriteAddr = 512ull * ( ulSectorNumber + ulSector ); + sd_result = HAL_SD_WriteBlocks_DMA( &xSDHandle, ( uint32_t * )pucDMABuffer, ullWriteAddr, 512ul, 1 ); + if( sd_result == SD_OK ) + { + sd_result = HAL_SD_CheckWriteOperation( &xSDHandle, sdMAX_TIME_TICKS ); + if( sd_result != SD_OK ) + { + break; + } + } + } + ffconfigFREE( pucDMABuffer ); + } + else + { + sd_result = SD_INVALID_PARAMETER; + } + } + } + #endif /* SDIO_USES_DMA */ + + if( sd_result == SD_OK ) + { + /* No errors. */ + lReturnCode = 0L; + } + else + { + FF_PRINTF( "prvFFWrite: %lu: %u (%s)\n", ulSectorNumber, sd_result, prvSDCodePrintable( sd_result ) ); + } + } + else + { + if( pxDisk->xStatus.bIsInitialised != pdFALSE ) + { + FF_PRINTF( "prvFFWrite: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors ); + } + } + + return lReturnCode; +} +/*-----------------------------------------------------------*/ + +void FF_SDDiskFlush( FF_Disk_t *pxDisk ) +{ + if( ( pxDisk != NULL ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( pxDisk->pxIOManager != NULL ) ) + { + FF_FlushCache( pxDisk->pxIOManager ); + } +} +/*-----------------------------------------------------------*/ + +static void vGPIO_SD_Init(SD_HandleTypeDef* xSDHandle) +{ +GPIO_InitTypeDef GPIO_InitStruct; + + if( xSDHandle->Instance == SDIO ) + { + /* Peripheral clock enable */ + __SDIO_CLK_ENABLE(); + + /**SDIO GPIO Configuration + PC8 ------> SDIO_D0 + PC9 ------> SDIO_D1 + PC10 ------> SDIO_D2 + PC11 ------> SDIO_D3 + PC12 ------> SDIO_CK + PD2 ------> SDIO_CMD + */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + #if( BUS_4BITS != 0 ) + { + GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; + } + #else + { + GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_12; + } + #endif + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FAST; + GPIO_InitStruct.Alternate = GPIO_AF12_SDIO; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + __HAL_RCC_GPIOD_CLK_ENABLE(); + GPIO_InitStruct.Pin = GPIO_PIN_2; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_LOW; + GPIO_InitStruct.Alternate = GPIO_AF12_SDIO; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + } +} +/*-----------------------------------------------------------*/ + +FF_Disk_t *FF_SDDiskInit( const char *pcName ) +{ +FF_Error_t xFFError; +BaseType_t xPartitionNumber = 0; +FF_CreationParameters_t xParameters; +FF_Disk_t *pxDisk; + + xSDCardStatus = prvSDMMCInit( 0 ); + + if( xSDCardStatus != pdPASS ) + { + FF_PRINTF( "FF_SDDiskInit: prvSDMMCInit failed\n" ); + pxDisk = NULL; + } + else + { + pxDisk = (FF_Disk_t *)ffconfigMALLOC( sizeof( *pxDisk ) ); + if( pxDisk == NULL ) + { + FF_PRINTF( "FF_SDDiskInit: Malloc failed\n" ); + } + else + { + /* Initialise the created disk structure. */ + memset( pxDisk, '\0', sizeof( *pxDisk ) ); + + pxDisk->ulNumberOfSectors = xSDCardInfo.CardCapacity / 512; + + if( xPlusFATMutex == NULL ) + { + xPlusFATMutex = xSemaphoreCreateRecursiveMutex(); + } + pxDisk->ulSignature = sdSIGNATURE; + + if( xPlusFATMutex != NULL) + { + memset( &xParameters, '\0', sizeof( xParameters ) ); + xParameters.ulMemorySize = sdIOMAN_MEM_SIZE; + xParameters.ulSectorSize = 512; + xParameters.fnWriteBlocks = prvFFWrite; + xParameters.fnReadBlocks = prvFFRead; + xParameters.pxDisk = pxDisk; + + /* prvFFRead()/prvFFWrite() are not re-entrant and must be + protected with the use of a semaphore. */ + xParameters.xBlockDeviceIsReentrant = pdFALSE; + + /* The semaphore will be used to protect critical sections in + the +FAT driver, and also to avoid concurrent calls to + prvFFRead()/prvFFWrite() from different tasks. */ + xParameters.pvSemaphore = ( void * ) xPlusFATMutex; + + pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError ); + + if( pxDisk->pxIOManager == NULL ) + { + FF_PRINTF( "FF_SDDiskInit: FF_CreateIOManger: %s\n", (const char*)FF_GetErrMessage( xFFError ) ); + FF_SDDiskDelete( pxDisk ); + pxDisk = NULL; + } + else + { + pxDisk->xStatus.bIsInitialised = pdTRUE; + pxDisk->xStatus.bPartitionNumber = xPartitionNumber; + if( FF_SDDiskMount( pxDisk ) == 0 ) + { + FF_SDDiskDelete( pxDisk ); + pxDisk = NULL; + } + else + { + if( pcName == NULL ) + { + pcName = "/"; + } + FF_FS_Add( pcName, pxDisk ); + FF_PRINTF( "FF_SDDiskInit: Mounted SD-card as root \"%s\"\n", pcName ); + FF_SDDiskShowPartition( pxDisk ); + } + } /* if( pxDisk->pxIOManager != NULL ) */ + } /* if( xPlusFATMutex != NULL) */ + } /* if( pxDisk != NULL ) */ + } /* if( xSDCardStatus == pdPASS ) */ + + return pxDisk; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskFormat( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber ) +{ +FF_Error_t xError; +BaseType_t xReturn = pdFAIL; + + xError = FF_Unmount( pxDisk ); + + if( FF_isERR( xError ) != pdFALSE ) + { + FF_PRINTF( "FF_SDDiskFormat: unmount fails: %08x\n", ( unsigned ) xError ); + } + else + { + /* Format the drive - try FAT32 with large clusters. */ + xError = FF_Format( pxDisk, xPartitionNumber, pdFALSE, pdFALSE); + + if( FF_isERR( xError ) ) + { + FF_PRINTF( "FF_SDDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) ); + } + else + { + FF_PRINTF( "FF_SDDiskFormat: OK, now remounting\n" ); + pxDisk->xStatus.bPartitionNumber = xPartitionNumber; + xError = FF_SDDiskMount( pxDisk ); + FF_PRINTF( "FF_SDDiskFormat: rc %08x\n", ( unsigned )xError ); + if( FF_isERR( xError ) == pdFALSE ) + { + xReturn = pdPASS; + FF_SDDiskShowPartition( pxDisk ); + } + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskUnmount( FF_Disk_t *pxDisk ) +{ +FF_Error_t xFFError; +BaseType_t xReturn = pdPASS; + + if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsMounted != pdFALSE ) ) + { + pxDisk->xStatus.bIsMounted = pdFALSE; + xFFError = FF_Unmount( pxDisk ); + + if( FF_isERR( xFFError ) ) + { + FF_PRINTF( "FF_SDDiskUnmount: rc %08x\n", ( unsigned )xFFError ); + xReturn = pdFAIL; + } + else + { + FF_PRINTF( "Drive unmounted\n" ); + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskReinit( FF_Disk_t *pxDisk ) +{ +BaseType_t xStatus = prvSDMMCInit( 0 ); /* Hard coded index. */ + + /*_RB_ parameter not used. */ + ( void ) pxDisk; + + FF_PRINTF( "FF_SDDiskReinit: rc %08x\n", ( unsigned ) xStatus ); + return xStatus; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskMount( FF_Disk_t *pxDisk ) +{ +FF_Error_t xFFError; +BaseType_t xReturn; + + /* Mount the partition */ + xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber ); + + if( FF_isERR( xFFError ) ) + { + FF_PRINTF( "FF_SDDiskMount: %08lX\n", xFFError ); + xReturn = pdFAIL; + } + else + { + pxDisk->xStatus.bIsMounted = pdTRUE; + FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors ); + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +FF_IOManager_t *sddisk_ioman( FF_Disk_t *pxDisk ) +{ +FF_IOManager_t *pxReturn; + + if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) ) + { + pxReturn = pxDisk->pxIOManager; + } + else + { + pxReturn = NULL; + } + return pxReturn; +} +/*-----------------------------------------------------------*/ + +/* Release all resources */ +BaseType_t FF_SDDiskDelete( FF_Disk_t *pxDisk ) +{ + if( pxDisk != NULL ) + { + pxDisk->ulSignature = 0; + pxDisk->xStatus.bIsInitialised = 0; + if( pxDisk->pxIOManager != NULL ) + { + if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE ) + { + FF_Unmount( pxDisk ); + } + FF_DeleteIOManager( pxDisk->pxIOManager ); + } + + vPortFree( pxDisk ); + } + return 1; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskShowPartition( FF_Disk_t *pxDisk ) +{ +FF_Error_t xError; +uint64_t ullFreeSectors; +uint32_t ulTotalSizeMB, ulFreeSizeMB; +int iPercentageFree; +FF_IOManager_t *pxIOManager; +const char *pcTypeName = "unknown type"; +BaseType_t xReturn = pdPASS; + + if( pxDisk == NULL ) + { + xReturn = pdFAIL; + } + else + { + pxIOManager = pxDisk->pxIOManager; + + FF_PRINTF( "Reading FAT and calculating Free Space\n" ); + + switch( pxIOManager->xPartition.ucType ) + { + case FF_T_FAT12: + pcTypeName = "FAT12"; + break; + + case FF_T_FAT16: + pcTypeName = "FAT16"; + break; + + case FF_T_FAT32: + pcTypeName = "FAT32"; + break; + + default: + pcTypeName = "UNKOWN"; + break; + } + + FF_GetFreeSize( pxIOManager, &xError ); + + ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster; + iPercentageFree = ( int ) ( ( sdHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) / + ( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) ); + + ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / sdSECTORS_PER_MB; + ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / sdSECTORS_PER_MB ); + + /* It is better not to use the 64-bit format such as %Lu because it + might not be implemented. */ + FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber ); + FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName ); + FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel ); + FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors ); + FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster ); + FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB ); + FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +/* SDIO init function */ +static void prvSDIO_SD_Init( void ) +{ + xSDHandle.Instance = SDIO; + xSDHandle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; + xSDHandle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; + xSDHandle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; + + /* Start as a 1-bit bus and switch to 4-bits later on. */ + xSDHandle.Init.BusWide = SDIO_BUS_WIDE_1B; + + xSDHandle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; + + /* Use fastest CLOCK at 0. */ + xSDHandle.Init.ClockDiv = 32; + + #if( SDIO_USES_DMA != 0 ) + { + xSDHandle.EventSetupFunction = prvEventSetupFunction; + xSDHandle.EventWaitFunction = prvEventWaitFunction; + } + #else + { + xSDHandle.EventSetupFunction = NULL; + xSDHandle.EventWaitFunction = NULL; + } + #endif + __HAL_RCC_SDIO_CLK_ENABLE( ); +} +/*-----------------------------------------------------------*/ + +/* This routine returns true if the SD-card is inserted. After insertion, it +will wait for sdCARD_DETECT_DEBOUNCE_TIME_MS before returning pdTRUE. */ +BaseType_t FF_SDDiskDetect( FF_Disk_t *pxDisk ) +{ +int xReturn; + + xReturn = prvSDDetect(); + + if( xReturn != pdFALSE ) + { + if( xCardDetect.bStableSignal == pdFALSE ) + { + /* The card seems to be present. */ + if( xCardDetect.bLastPresent == pdFALSE ) + { + xCardDetect.bLastPresent = pdTRUE; + xCardDetect.xRemainingTime = pdMS_TO_TICKS( ( TickType_t ) sdCARD_DETECT_DEBOUNCE_TIME_MS ); + /* Fetch the current time. */ + vTaskSetTimeOutState( &xCardDetect.xTimeOut ); + } + /* Has the timeout been reached? */ + if( xTaskCheckForTimeOut( &xCardDetect.xTimeOut, &xCardDetect.xRemainingTime ) != pdFALSE ) + { + xCardDetect.bStableSignal = pdTRUE; + } + else + { + /* keep returning false until de time-out is reached. */ + xReturn = pdFALSE; + } + } + } + else + { + xCardDetect.bLastPresent = pdFALSE; + xCardDetect.bStableSignal = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +/* Raw SD-card detection, just return the GPIO status. */ +static BaseType_t prvSDDetect( void ) +{ +int iReturn; + + /*!< Check GPIO to detect SD */ + if( HAL_GPIO_ReadPin( configSD_DETECT_GPIO_PORT, configSD_DETECT_PIN ) != 0 ) + { + /* The internal pull-up makes the signal high. */ + iReturn = pdFALSE; + } + else + { + /* The card will pull the GPIO signal down. */ + iReturn = pdTRUE; + } + + return iReturn; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvSDMMCInit( BaseType_t xDriveNumber ) +{ + /* 'xDriveNumber' not yet in use. */ + ( void )xDriveNumber; + + if( xSDCardSemaphore == NULL ) + { + xSDCardSemaphore = xSemaphoreCreateBinary(); + } + prvSDIO_SD_Init(); + + vGPIO_SD_Init( &xSDHandle ); + + #if( SDIO_USES_DMA != 0 ) + { + prvSDIO_DMA_Init( ); + } + #endif + + int SD_state = SD_OK; + /* Check if the SD card is plugged in the slot */ + if( prvSDDetect() == pdFALSE ) + { + FF_PRINTF( "No SD card detected\n" ); + return 0; + } + /* When starting up, skip debouncing of the Card Detect signal. */ + xCardDetect.bLastPresent = pdTRUE; + xCardDetect.bStableSignal = pdTRUE; + /* Initialise the SDIO device and read the card parameters. */ + SD_state = HAL_SD_Init( &xSDHandle, &xSDCardInfo ); + #if( BUS_4BITS != 0 ) + { + if( SD_state == SD_OK ) + { + HAL_SD_ErrorTypedef rc; + + xSDHandle.Init.BusWide = SDIO_BUS_WIDE_4B; + rc = HAL_SD_WideBusOperation_Config(&xSDHandle, SDIO_BUS_WIDE_4B); + if( rc != SD_OK ) + { + FF_PRINTF( "HAL_SD_WideBus: %d: %s\n", rc, prvSDCodePrintable( ( uint32_t )rc ) ); + } + } + } + #endif + FF_PRINTF( "HAL_SD_Init: %d: %s type: %s Capacity: %lu MB\n", + SD_state, + prvSDCodePrintable( ( uint32_t )SD_state ), + xSDHandle.CardType == HIGH_CAPACITY_SD_CARD ? "SDHC" : "SD", + xSDCardInfo.CardCapacity / ( 1024 * 1024 ) ); + + return SD_state == SD_OK ? 1 : 0; +} +/*-----------------------------------------------------------*/ + +struct xCODE_NAME +{ + uint32_t ulValue; + const char *pcName; +}; + +const struct xCODE_NAME xSD_CODES[] = +{ + { SD_CMD_CRC_FAIL, "CMD_CRC_FAIL: Command response received (but CRC check failed)" }, + { SD_DATA_CRC_FAIL, "DATA_CRC_FAIL: Data block sent/received (CRC check failed)" }, + { SD_CMD_RSP_TIMEOUT, "CMD_RSP_TIMEOUT: Command response timeout" }, + { SD_DATA_TIMEOUT, "DATA_TIMEOUT: Data timeout" }, + { SD_TX_UNDERRUN, "TX_UNDERRUN: Transmit FIFO underrun" }, + { SD_RX_OVERRUN, "RX_OVERRUN: Receive FIFO overrun" }, + { SD_START_BIT_ERR, "START_BIT_ERR: Start bit not detected on all data signals in wide bus mode" }, + { SD_CMD_OUT_OF_RANGE, "CMD_OUT_OF_RANGE: Command's argument was out of range" }, + { SD_ADDR_MISALIGNED, "ADDR_MISALIGNED: Misaligned address" }, + { SD_BLOCK_LEN_ERR, "BLOCK_LEN_ERR: Transferred block length is not allowed for the card or the number of transferred bytes does not match the block length" }, + { SD_ERASE_SEQ_ERR, "ERASE_SEQ_ERR: An error in the sequence of erase command occurs." }, + { SD_BAD_ERASE_PARAM, "BAD_ERASE_PARAM: An invalid selection for erase groups" }, + { SD_WRITE_PROT_VIOLATION, "WRITE_PROT_VIOLATION: Attempt to program a write protect block" }, + { SD_LOCK_UNLOCK_FAILED, "LOCK_UNLOCK_FAILED: Sequence or password error has been detected in unlock command or if there was an attempt to access a locked card" }, + { SD_COM_CRC_FAILED, "COM_CRC_FAILED: CRC check of the previous command failed" }, + { SD_ILLEGAL_CMD, "ILLEGAL_CMD: Command is not legal for the card state" }, + { SD_CARD_ECC_FAILED, "CARD_ECC_FAILED: Card internal ECC was applied but failed to correct the data" }, + { SD_CC_ERROR, "CC_ERROR: Internal card controller error" }, + { SD_GENERAL_UNKNOWN_ERROR, "GENERAL_UNKNOWN_ERROR: General or unknown error" }, + { SD_STREAM_READ_UNDERRUN, "STREAM_READ_UNDERRUN: The card could not sustain data transfer in stream read operation" }, + { SD_STREAM_WRITE_OVERRUN, "STREAM_WRITE_OVERRUN: The card could not sustain data programming in stream mode" }, + { SD_CID_CSD_OVERWRITE, "CID_CSD_OVERWRITE: CID/CSD overwrite error" }, + { SD_WP_ERASE_SKIP, "WP_ERASE_SKIP: Only partial address space was erased" }, + { SD_CARD_ECC_DISABLED, "CARD_ECC_DISABLED: Command has been executed without using internal ECC" }, + { SD_ERASE_RESET, "ERASE_RESET: Erase sequence was cleared before executing because an out of erase sequence command was received" }, + { SD_AKE_SEQ_ERROR, "AKE_SEQ_ERROR: Error in sequence of authentication" }, + { SD_INVALID_VOLTRANGE, "INVALID_VOLTRANGE" }, + { SD_ADDR_OUT_OF_RANGE, "ADDR_OUT_OF_RANGE" }, + { SD_SWITCH_ERROR, "SWITCH_ERROR" }, + { SD_SDIO_DISABLED, "SDIO_DISABLED" }, + { SD_SDIO_FUNCTION_BUSY, "SDIO_FUNCTION_BUSY" }, + { SD_SDIO_FUNCTION_FAILED, "SDIO_FUNCTION_FAILED" }, + { SD_SDIO_UNKNOWN_FUNCTION, "SDIO_UNKNOWN_FUNCTION" }, + + /** + * @brief Standard error defines + */ + { SD_INTERNAL_ERROR, "INTERNAL_ERROR" }, + { SD_NOT_CONFIGURED, "NOT_CONFIGURED" }, + { SD_REQUEST_PENDING, "REQUEST_PENDING" }, + { SD_REQUEST_NOT_APPLICABLE,"REQUEST_NOT_APPLICABLE" }, + { SD_INVALID_PARAMETER, "INVALID_PARAMETER" }, + { SD_UNSUPPORTED_FEATURE, "UNSUPPORTED_FEATURE" }, + { SD_UNSUPPORTED_HW, "UNSUPPORTED_HW" }, + { SD_ERROR, "ERROR" }, + { SD_OK, "OK" }, +}; +/*-----------------------------------------------------------*/ + +static const char *prvSDCodePrintable( uint32_t ulCode ) +{ +static char retString[32]; +const struct xCODE_NAME *pxCode; + + for( pxCode = xSD_CODES; pxCode <= xSD_CODES + sdARRAY_SIZE( xSD_CODES ) - 1; pxCode++ ) + { + if( pxCode->ulValue == ulCode ) + { + return pxCode->pcName; + } + } + snprintf( retString, sizeof( retString ), "SD code %lu\n", ulCode ); + return retString; +} +/*-----------------------------------------------------------*/ + +#if( SDIO_USES_DMA != 0 ) + + static void prvSDIO_DMA_Init( void ) + { + static DMA_HandleTypeDef xRxDMAHandle; + static DMA_HandleTypeDef xTxDMAHandle; + + /* Enable DMA2 clocks */ + __DMAx_TxRx_CLK_ENABLE(); + + /* NVIC configuration for SDIO interrupts */ + HAL_NVIC_SetPriority(SDIO_IRQn, configSDIO_DMA_INTERRUPT_PRIORITY, 0); + HAL_NVIC_EnableIRQ(SDIO_IRQn); + + /* Configure DMA Rx parameters */ + xRxDMAHandle.Init.Channel = SD_DMAx_Rx_CHANNEL; + xRxDMAHandle.Init.Direction = DMA_PERIPH_TO_MEMORY; + /* Peripheral address is fixed (FIFO). */ + xRxDMAHandle.Init.PeriphInc = DMA_PINC_DISABLE; + /* Memory address increases. */ + xRxDMAHandle.Init.MemInc = DMA_MINC_ENABLE; + xRxDMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + xRxDMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + /* The peripheral has flow-control. */ + xRxDMAHandle.Init.Mode = DMA_PFCTRL; + xRxDMAHandle.Init.Priority = DMA_PRIORITY_VERY_HIGH; + xRxDMAHandle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + xRxDMAHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + xRxDMAHandle.Init.MemBurst = DMA_MBURST_INC4; + xRxDMAHandle.Init.PeriphBurst = DMA_PBURST_INC4; + + /* DMA2_Stream3. */ + xRxDMAHandle.Instance = SD_DMAx_Rx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(&xSDHandle, hdmarx, xRxDMAHandle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&xRxDMAHandle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&xRxDMAHandle); + + /* Configure DMA Tx parameters */ + xTxDMAHandle.Init.Channel = SD_DMAx_Tx_CHANNEL; + xTxDMAHandle.Init.Direction = DMA_MEMORY_TO_PERIPH; + xTxDMAHandle.Init.PeriphInc = DMA_PINC_DISABLE; + xTxDMAHandle.Init.MemInc = DMA_MINC_ENABLE; + xTxDMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + xTxDMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + xTxDMAHandle.Init.Mode = DMA_PFCTRL; + xTxDMAHandle.Init.Priority = DMA_PRIORITY_VERY_HIGH; + xTxDMAHandle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + xTxDMAHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + xTxDMAHandle.Init.MemBurst = DMA_MBURST_SINGLE; + xTxDMAHandle.Init.PeriphBurst = DMA_PBURST_INC4; + + /* DMA2_Stream6. */ + xTxDMAHandle.Instance = SD_DMAx_Tx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(&xSDHandle, hdmatx, xTxDMAHandle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&xTxDMAHandle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&xTxDMAHandle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD_DMAx_Rx_IRQn, configSDIO_DMA_INTERRUPT_PRIORITY + 2, 0); + HAL_NVIC_EnableIRQ(SD_DMAx_Rx_IRQn); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD_DMAx_Tx_IRQn, configSDIO_DMA_INTERRUPT_PRIORITY + 2, 0); + HAL_NVIC_EnableIRQ(SD_DMAx_Tx_IRQn); + } +#endif /* SDIO_USES_DMA */ +/*-----------------------------------------------------------*/ + +#if( SDIO_USES_DMA != 0 ) + void SDIO_IRQHandler(void) + { + BaseType_t xHigherPriorityTaskWoken = 0; + + HAL_SD_IRQHandler( &xSDHandle ); + if( xSDCardSemaphore != NULL ) + { + xSemaphoreGiveFromISR( xSDCardSemaphore, &xHigherPriorityTaskWoken ); + } + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + } + +#endif /* SDIO_USES_DMA */ +/*-----------------------------------------------------------*/ + +#if( SDIO_USES_DMA != 0 ) + + void DMA2_Stream6_IRQHandler(void) + { + BaseType_t xHigherPriorityTaskWoken = 0; + + /* DMA SDIO-TX interrupt handler. */ + HAL_DMA_IRQHandler (xSDHandle.hdmatx); + if( xSDCardSemaphore != NULL ) + { + xSemaphoreGiveFromISR( xSDCardSemaphore, &xHigherPriorityTaskWoken ); + } + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + } + +#endif /* SDIO_USES_DMA */ +/*-----------------------------------------------------------*/ + +#if( SDIO_USES_DMA != 0 ) + + void DMA2_Stream3_IRQHandler(void) + { + BaseType_t xHigherPriorityTaskWoken = 0; + + /* DMA SDIO-RX interrupt handler. */ + HAL_DMA_IRQHandler (xSDHandle.hdmarx); + if( xSDCardSemaphore != NULL ) + { + xSemaphoreGiveFromISR( xSDCardSemaphore, &xHigherPriorityTaskWoken ); + } + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + } + +#endif /* SDIO_USES_DMA */ +/*-----------------------------------------------------------*/ + +#if( SDIO_USES_DMA != 0 ) + + static void prvEventSetupFunction( SD_HandleTypeDef * pxHandle ) + { + /* A DMA transfer to or from the SD-card is about to start. + Reset the timers that will be used in prvEventWaitFunction() */ + xDMARemainingTime = sdMAX_TIME_TICKS; + vTaskSetTimeOutState( &xDMATimeOut ); + } + +#endif /* SDIO_USES_DMA != 0 */ +/*-----------------------------------------------------------*/ + +#if( SDIO_USES_DMA != 0 ) + + static uint32_t prvEventWaitFunction( SD_HandleTypeDef *pxHandle ) + { + uint32_t ulReturn; + + /* + * It was measured how quickly a DMA interrupt was received. It varied + * between 0 and 4 ms. + * <= 1 ms : 8047 + * <= 2 ms : 1850 + * <= 3 ms : 99 + * <= 4 ms : 79 + * >= 5 ms : 0 times + */ + + if( xTaskCheckForTimeOut( &xDMATimeOut, &xDMARemainingTime ) != pdFALSE ) + { + /* The timeout has been reached, no need to block. */ + ulReturn = 1UL; + } + else + { + /* The timeout has not been reached yet, block on the semaphore. */ + xSemaphoreTake( xSDCardSemaphore, xDMARemainingTime ); + if( xTaskCheckForTimeOut( &xDMATimeOut, &xDMARemainingTime ) != pdFALSE ) + { + ulReturn = 1UL; + } + else + { + ulReturn = 0UL; + } + } + + return ulReturn; + } + +#endif /* SDIO_USES_DMA != 0 */ +/*-----------------------------------------------------------*/ + +void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin ) +{ +BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + if( GPIO_Pin == configSD_DETECT_PIN ) + { + vApplicationCardDetectChangeHookFromISR( &xHigherPriorityTaskWoken ); + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + } +} +/*-----------------------------------------------------------*/ + +void EXTI15_10_IRQHandler( void ) +{ + HAL_GPIO_EXTI_IRQHandler( configSD_DETECT_PIN ); /* GPIO PIN H.13 */ +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F4xx/stm32f4xx_hal_sd.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F4xx/stm32f4xx_hal_sd.c new file mode 100644 index 000000000..1c57821ae --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F4xx/stm32f4xx_hal_sd.c @@ -0,0 +1,3561 @@ +/* SD driver provided by ST, modified for use in a FreeRTOS+FAT demo. */ + +/** + ****************************************************************************** + * @file stm32f4xx_hal_sd.c + * @author MCD Application Team + * @version V1.3.2 + * @date 26-June-2015 + * @brief SD card HAL module driver. + * This file provides firmware functions to manage the following + * functionalities of the Secure Digital (SD) peripheral: + * + Initialization and de-initialization functions + * + IO operation functions + * + Peripheral Control functions + * + Peripheral State functions + * + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + This driver implements a high level communication layer for read and write from/to + this memory. The needed STM32 hardware resources (SDIO and GPIO) are performed by + the user in HAL_SD_MspInit() function (MSP layer). + Basically, the MSP layer configuration should be the same as we provide in the + examples. + You can easily tailor this configuration according to hardware resources. + + [..] + This driver is a generic layered driver for SDIO memories which uses the HAL + SDIO driver functions to interface with SD and uSD cards devices. + It is used as follows: + + (#)Initialize the SDIO low level resources by implement the HAL_SD_MspInit() API: + (##) Enable the SDIO interface clock using __HAL_RCC_SDIO_CLK_ENABLE(); + (##) SDIO pins configuration for SD card + (+++) Enable the clock for the SDIO GPIOs using the functions __HAL_RCC_GPIOx_CLK_ENABLE(); + (+++) Configure these SDIO pins as alternate function pull-up using HAL_GPIO_Init() + and according to your pin assignment; + (##) DMA Configuration if you need to use DMA process (HAL_SD_ReadBlocks_DMA() + and HAL_SD_WriteBlocks_DMA() APIs). + (+++) Enable the DMAx interface clock using __HAL_RCC_DMAx_CLK_ENABLE(); + (+++) Configure the DMA using the function HAL_DMA_Init() with predeclared and filled. + (##) NVIC configuration if you need to use interrupt process when using DMA transfer. + (+++) Configure the SDIO and DMA interrupt priorities using functions + HAL_NVIC_SetPriority(); DMA priority is superior to SDIO's priority + (+++) Enable the NVIC DMA and SDIO IRQs using function HAL_NVIC_EnableIRQ() + (+++) SDIO interrupts are managed using the macros __HAL_SD_SDIO_ENABLE_IT() + and __HAL_SD_SDIO_DISABLE_IT() inside the communication process. + (+++) SDIO interrupts pending bits are managed using the macros __HAL_SD_SDIO_GET_IT() + and __HAL_SD_SDIO_CLEAR_IT() + (#) At this stage, you can perform SD read/write/erase operations after SD card initialization + + + *** SD Card Initialization and configuration *** + ================================================ + [..] + To initialize the SD Card, use the HAL_SD_Init() function. It Initializes + the SD Card and put it into Standby State (Ready for data transfer). + This function provide the following operations: + + (#) Apply the SD Card initialization process at 400KHz and check the SD Card + type (Standard Capacity or High Capacity). You can change or adapt this + frequency by adjusting the "ClockDiv" field. + The SD Card frequency (SDIO_CK) is computed as follows: + + SDIO_CK = SDIOCLK / (ClockDiv + 2) + + In initialization mode and according to the SD Card standard, + make sure that the SDIO_CK frequency doesn't exceed 400KHz. + + (#) Get the SD CID and CSD data. All these information are managed by the SDCardInfo + structure. This structure provide also ready computed SD Card capacity + and Block size. + + -@- These information are stored in SD handle structure in case of future use. + + (#) Configure the SD Card Data transfer frequency. By Default, the card transfer + frequency is set to 24MHz. You can change or adapt this frequency by adjusting + the "ClockDiv" field. + In transfer mode and according to the SD Card standard, make sure that the + SDIO_CK frequency doesn't exceed 25MHz and 50MHz in High-speed mode switch. + To be able to use a frequency higher than 24MHz, you should use the SDIO + peripheral in bypass mode. Refer to the corresponding reference manual + for more details. + + (#) Select the corresponding SD Card according to the address read with the step 2. + + (#) Configure the SD Card in wide bus mode: 4-bits data. + + *** SD Card Read operation *** + ============================== + [..] + (+) You can read from SD card in polling mode by using function HAL_SD_ReadBlocks(). + This function support only 512-bytes block length (the block size should be + chosen as 512 bytes). + You can choose either one block read operation or multiple block read operation + by adjusting the "NumberOfBlocks" parameter. + + (+) You can read from SD card in DMA mode by using function HAL_SD_ReadBlocks_DMA(). + This function support only 512-bytes block length (the block size should be + chosen as 512 bytes). + You can choose either one block read operation or multiple block read operation + by adjusting the "NumberOfBlocks" parameter. + After this, you have to call the function HAL_SD_CheckReadOperation(), to insure + that the read transfer is done correctly in both DMA and SD sides. + + *** SD Card Write operation *** + =============================== + [..] + (+) You can write to SD card in polling mode by using function HAL_SD_WriteBlocks(). + This function support only 512-bytes block length (the block size should be + chosen as 512 bytes). + You can choose either one block read operation or multiple block read operation + by adjusting the "NumberOfBlocks" parameter. + + (+) You can write to SD card in DMA mode by using function HAL_SD_WriteBlocks_DMA(). + This function support only 512-bytes block length (the block size should be + chosen as 512 byte). + You can choose either one block read operation or multiple block read operation + by adjusting the "NumberOfBlocks" parameter. + After this, you have to call the function HAL_SD_CheckWriteOperation(), to insure + that the write transfer is done correctly in both DMA and SD sides. + + *** SD card status *** + ====================== + [..] + (+) At any time, you can check the SD Card status and get the SD card state + by using the HAL_SD_GetStatus() function. This function checks first if the + SD card is still connected and then get the internal SD Card transfer state. + (+) You can also get the SD card SD Status register by using the HAL_SD_SendSDStatus() + function. + + *** SD HAL driver macros list *** + ================================== + [..] + Below the list of most used macros in SD HAL driver. + + (+) __HAL_SD_SDIO_ENABLE : Enable the SD device + (+) __HAL_SD_SDIO_DISABLE : Disable the SD device + (+) __HAL_SD_SDIO_DMA_ENABLE: Enable the SDIO DMA transfer + (+) __HAL_SD_SDIO_DMA_DISABLE: Disable the SDIO DMA transfer + (+) __HAL_SD_SDIO_ENABLE_IT: Enable the SD device interrupt + (+) __HAL_SD_SDIO_DISABLE_IT: Disable the SD device interrupt + (+) __HAL_SD_SDIO_GET_FLAG:Check whether the specified SD flag is set or not + (+) __HAL_SD_SDIO_CLEAR_FLAG: Clear the SD's pending flags + + (@) You can refer to the SD HAL driver header file for more useful macros + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + * + ****************************************************************************** + */ + +#include "FreeRTOS.h" +#include "task.h" + +/* This include is not necessary except for including the definition of FF_PRINTF(). */ +#include "ff_headers.h" + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" + +#ifdef HAL_SD_MODULE_ENABLED + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @addtogroup SD + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/** @addtogroup SD_Private_Defines + * @{ + */ +/** + * @brief SDIO Data block size + */ +#define DATA_BLOCK_SIZE ((uint32_t)(9 << 4)) +/** + * @brief SDIO Static flags, Timeout, FIFO Address + */ +#define SDIO_STATIC_FLAGS ((uint32_t)(SDIO_FLAG_CCRCFAIL | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_CTIMEOUT |\ + SDIO_FLAG_DTIMEOUT | SDIO_FLAG_TXUNDERR | SDIO_FLAG_RXOVERR |\ + SDIO_FLAG_CMDREND | SDIO_FLAG_CMDSENT | SDIO_FLAG_DATAEND |\ + SDIO_FLAG_DBCKEND)) + +#define SDIO_CMD0TIMEOUT ((uint32_t)0x00010000) + +/** + * @brief Mask for errors Card Status R1 (OCR Register) + */ +#define SD_OCR_ADDR_OUT_OF_RANGE ((uint32_t)0x80000000) +#define SD_OCR_ADDR_MISALIGNED ((uint32_t)0x40000000) +#define SD_OCR_BLOCK_LEN_ERR ((uint32_t)0x20000000) +#define SD_OCR_ERASE_SEQ_ERR ((uint32_t)0x10000000) +#define SD_OCR_BAD_ERASE_PARAM ((uint32_t)0x08000000) +#define SD_OCR_WRITE_PROT_VIOLATION ((uint32_t)0x04000000) +#define SD_OCR_LOCK_UNLOCK_FAILED ((uint32_t)0x01000000) +#define SD_OCR_COM_CRC_FAILED ((uint32_t)0x00800000) +#define SD_OCR_ILLEGAL_CMD ((uint32_t)0x00400000) +#define SD_OCR_CARD_ECC_FAILED ((uint32_t)0x00200000) +#define SD_OCR_CC_ERROR ((uint32_t)0x00100000) +#define SD_OCR_GENERAL_UNKNOWN_ERROR ((uint32_t)0x00080000) +#define SD_OCR_STREAM_READ_UNDERRUN ((uint32_t)0x00040000) +#define SD_OCR_STREAM_WRITE_OVERRUN ((uint32_t)0x00020000) +#define SD_OCR_CID_CSD_OVERWRITE ((uint32_t)0x00010000) +#define SD_OCR_WP_ERASE_SKIP ((uint32_t)0x00008000) +#define SD_OCR_CARD_ECC_DISABLED ((uint32_t)0x00004000) +#define SD_OCR_ERASE_RESET ((uint32_t)0x00002000) +#define SD_OCR_AKE_SEQ_ERROR ((uint32_t)0x00000008) +#define SD_OCR_ERRORBITS ((uint32_t)0xFDFFE008) + +/** + * @brief Masks for R6 Response + */ +#define SD_R6_GENERAL_UNKNOWN_ERROR ((uint32_t)0x00002000) +#define SD_R6_ILLEGAL_CMD ((uint32_t)0x00004000) +#define SD_R6_COM_CRC_FAILED ((uint32_t)0x00008000) + +#define SD_VOLTAGE_WINDOW_SD ((uint32_t)0x80100000) +#define SD_HIGH_CAPACITY ((uint32_t)0x40000000) +#define SD_STD_CAPACITY ((uint32_t)0x00000000) +#define SD_CHECK_PATTERN ((uint32_t)0x000001AA) + +#define SD_MAX_VOLT_TRIAL ((uint32_t)0x0000FFFF) +#define SD_ALLZERO ((uint32_t)0x00000000) + +#define SD_WIDE_BUS_SUPPORT ((uint32_t)0x00040000) +#define SD_SINGLE_BUS_SUPPORT ((uint32_t)0x00010000) +#define SD_CARD_LOCKED ((uint32_t)0x02000000) + +#define SD_DATATIMEOUT ((uint32_t)0xFFFFFFFF) +#define SD_0TO7BITS ((uint32_t)0x000000FF) +#define SD_8TO15BITS ((uint32_t)0x0000FF00) +#define SD_16TO23BITS ((uint32_t)0x00FF0000) +#define SD_24TO31BITS ((uint32_t)0xFF000000) +#define SD_MAX_DATA_LENGTH ((uint32_t)0x01FFFFFF) + +#define SD_HALFFIFO ((uint32_t)0x00000008) +#define SD_HALFFIFOBYTES ((uint32_t)0x00000020) + +/** + * @brief Command Class Supported + */ +#define SD_CCCC_LOCK_UNLOCK ((uint32_t)0x00000080) +#define SD_CCCC_WRITE_PROT ((uint32_t)0x00000040) +#define SD_CCCC_ERASE ((uint32_t)0x00000020) + +/** + * @brief Following commands are SD Card Specific commands. + * SDIO_APP_CMD should be sent before sending these commands. + */ +#define SD_SDIO_SEND_IF_COND ((uint32_t)SD_CMD_HS_SEND_EXT_CSD) + +/** + * @} + */ + +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/** @addtogroup SD_Private_Functions_Prototypes + * @{ + */ +static HAL_SD_ErrorTypedef SD_Initialize_Cards(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_Select_Deselect(SD_HandleTypeDef *hsd, uint64_t addr); +static HAL_SD_ErrorTypedef SD_PowerON(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_PowerOFF(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_SendStatus(SD_HandleTypeDef *hsd, uint32_t *pCardStatus); +static HAL_SD_CardStateTypedef SD_GetState(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_IsCardProgramming(SD_HandleTypeDef *hsd, uint8_t *pStatus); +static HAL_SD_ErrorTypedef SD_CmdError(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_CmdResp1Error(SD_HandleTypeDef *hsd, uint8_t SD_CMD); +static HAL_SD_ErrorTypedef SD_CmdResp7Error(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_CmdResp3Error(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_CmdResp2Error(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_CmdResp6Error(SD_HandleTypeDef *hsd, uint8_t SD_CMD, uint16_t *pRCA); +static HAL_SD_ErrorTypedef SD_WideBus_Enable(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_WideBus_Disable(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_FindSCR(SD_HandleTypeDef *hsd, uint32_t *pSCR); +static void SD_DMA_RxCplt(DMA_HandleTypeDef *hdma); +static void SD_DMA_RxError(DMA_HandleTypeDef *hdma); +static void SD_DMA_TxCplt(DMA_HandleTypeDef *hdma); +static void SD_DMA_TxError(DMA_HandleTypeDef *hdma); +/** + * @} + */ +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup SD_Exported_Functions + * @{ + */ + +/** @addtogroup SD_Exported_Functions_Group1 + * @brief Initialization and de-initialization functions + * +@verbatim + ============================================================================== + ##### Initialization and de-initialization functions ##### + ============================================================================== + [..] + This section provides functions allowing to initialize/de-initialize the SD + card device to be ready for use. + + +@endverbatim + * @{ + */ + +/** + * @brief Initializes the SD card according to the specified parameters in the + SD_HandleTypeDef and create the associated handle. + * @param hsd: SD handle + * @param SDCardInfo: HAL_SD_CardInfoTypedef structure for SD card information + * @retval HAL SD error state + */ +HAL_SD_ErrorTypedef HAL_SD_Init(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypedef *SDCardInfo) +{ + __IO HAL_SD_ErrorTypedef errorstate = SD_OK; + SD_InitTypeDef tmpinit; + + /* Initialize the low level hardware (MSP) */ + HAL_SD_MspInit(hsd); + + /* Default SDIO peripheral configuration for SD card initialization */ + tmpinit.ClockEdge = SDIO_CLOCK_EDGE_RISING; + tmpinit.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; + tmpinit.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; + #if( BUS_4BITS != 0 ) + { + tmpinit.BusWide = SDIO_BUS_WIDE_4B; + } + #else + { + tmpinit.BusWide = SDIO_BUS_WIDE_1B; + } + #endif + tmpinit.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; + tmpinit.ClockDiv = SDIO_INIT_CLK_DIV; + + /* Initialize SDIO peripheral interface with default configuration */ + SDIO_Init(hsd->Instance, tmpinit); + + /* Identify card operating voltage */ + errorstate = SD_PowerON(hsd); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Initialize the present SDIO card(s) and put them in idle state */ + errorstate = SD_Initialize_Cards(hsd); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Read CSD/CID MSD registers */ + errorstate = HAL_SD_Get_CardInfo(hsd, SDCardInfo); + + if (errorstate == SD_OK) + { + /* Select the Card */ + errorstate = SD_Select_Deselect(hsd, (uint32_t)(((uint32_t)SDCardInfo->RCA) << 16)); + } + + /* Configure SDIO peripheral interface */ + SDIO_Init(hsd->Instance, hsd->Init); + + return errorstate; +} + +/** + * @brief De-Initializes the SD card. + * @param hsd: SD handle + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_DeInit(SD_HandleTypeDef *hsd) +{ + + /* Set SD power state to off */ + SD_PowerOFF(hsd); + + /* De-Initialize the MSP layer */ + HAL_SD_MspDeInit(hsd); + + return HAL_OK; +} + + +/** + * @brief Initializes the SD MSP. + * @param hsd: SD handle + * @retval None + */ +__weak void HAL_SD_MspInit(SD_HandleTypeDef *hsd) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_MspInit could be implemented in the user file + */ +} + +/** + * @brief De-Initialize SD MSP. + * @param hsd: SD handle + * @retval None + */ +__weak void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_MspDeInit could be implemented in the user file + */ +} + +/** + * @} + */ + +/** @addtogroup SD_Exported_Functions_Group2 + * @brief Data transfer functions + * +@verbatim + ============================================================================== + ##### IO operation functions ##### + ============================================================================== + [..] + This subsection provides a set of functions allowing to manage the data + transfer from/to SD card. + +@endverbatim + * @{ + */ + +/** + * @brief Reads block(s) from a specified address in a card. The Data transfer + * is managed by polling mode. + * @param hsd: SD handle + * @param pReadBuffer: pointer to the buffer that will contain the received data + * @param ReadAddr: Address from where data is to be read + * @param BlockSize: SD card Data block size + * @note BlockSize must be 512 bytes. + * @param NumberOfBlocks: Number of SD blocks to read + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + SDIO_DataInitTypeDef sdmmc_datainitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t count = 0, *tempbuff = (uint32_t *)pReadBuffer; + __IO uint32_t *pulFIFO = &( hsd->Instance->FIFO ); + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0; + + if (hsd->CardType == HIGH_CAPACITY_SD_CARD) + { + BlockSize = 512; + ReadAddr /= 512; + } + + /* Set Block Size for Card */ + sdmmc_cmdinitstructure.Argument = (uint32_t) BlockSize; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = NumberOfBlocks * BlockSize; + sdmmc_datainitstructure.DataBlockSize = DATA_BLOCK_SIZE; + sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO; + sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE; + SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure); + + if(NumberOfBlocks > 1) + { + /* Send CMD18 READ_MULT_BLOCK with argument data address */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_READ_MULT_BLOCK; + } + else + { + /* Send CMD17 READ_SINGLE_BLOCK */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_READ_SINGLE_BLOCK; + } + + sdmmc_cmdinitstructure.Argument = (uint32_t)ReadAddr; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, sdmmc_cmdinitstructure.CmdIndex); + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Read block(s) in polling mode */ + if(NumberOfBlocks > 1) + { + /* Poll on SDIO flags */ + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND | SDIO_FLAG_STBITERR)) + { + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF)) + { + /* Read data from SDIO Rx FIFO */ + tempbuff[0] = *( pulFIFO ); + tempbuff[1] = *( pulFIFO ); + tempbuff[2] = *( pulFIFO ); + tempbuff[3] = *( pulFIFO ); + tempbuff[4] = *( pulFIFO ); + tempbuff[5] = *( pulFIFO ); + tempbuff[6] = *( pulFIFO ); + tempbuff[7] = *( pulFIFO ); + + tempbuff += 8; + } + } + } + else + { + /* In case of single block transfer, no need of stop transfer at all */ + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR)) + { + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF)) + { + /* Read data from SDIO Rx FIFO */ + tempbuff[0] = *( pulFIFO ); + tempbuff[1] = *( pulFIFO ); + tempbuff[2] = *( pulFIFO ); + tempbuff[3] = *( pulFIFO ); + tempbuff[4] = *( pulFIFO ); + tempbuff[5] = *( pulFIFO ); + tempbuff[6] = *( pulFIFO ); + tempbuff[7] = *( pulFIFO ); + + tempbuff += 8; + } + } + } + + /* Send stop transmission command in case of multiblock read */ + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DATAEND) && (NumberOfBlocks > 1)) + { + if ((hsd->CardType == STD_CAPACITY_SD_CARD_V1_1) ||\ + (hsd->CardType == STD_CAPACITY_SD_CARD_V2_0) ||\ + (hsd->CardType == HIGH_CAPACITY_SD_CARD)) + { + /* Send stop transmission command */ + errorstate = HAL_SD_StopTransfer(hsd); + } + } + + /* Get error state */ + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DTIMEOUT); + + errorstate = SD_DATA_TIMEOUT; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DCRCFAIL); + + errorstate = SD_DATA_CRC_FAIL; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_RXOVERR); + + errorstate = SD_RX_OVERRUN; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_STBITERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_STBITERR); + + errorstate = SD_START_BIT_ERR; + + return errorstate; + } + else + { + /* No error flag set */ + } + + count = SD_DATATIMEOUT; + + /* Empty FIFO if there is still any data */ + while ((__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXDAVL)) && (count > 0)) + { + *tempbuff = SDIO_ReadFIFO(hsd->Instance); + tempbuff++; + count--; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + return errorstate; +} + +/** + * @brief Allows to write block(s) to a specified address in a card. The Data + * transfer is managed by polling mode. + * @param hsd: SD handle + * @param pWriteBuffer: pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param BlockSize: SD card Data block size + * @note BlockSize must be 512 bytes. + * @param NumberOfBlocks: Number of SD blocks to write + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; +/*SDIO_DataInitTypeDef sdmmc_datainitstructure; */ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t totalnumberofbytes, bytesRemaining; + uint32_t tmpreg; + uint32_t last_sta; + uint32_t *tempbuff = (uint32_t *)pWriteBuffer; + uint8_t cardstate = 0; + __IO uint32_t *pulFIFO = &( hsd->Instance->FIFO ); + uint32_t ulEndFags; + uint32_t ulHasHWFlowControl; + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0; + + if (hsd->CardType == HIGH_CAPACITY_SD_CARD) + { + BlockSize = 512; + WriteAddr /= 512; + } + + /* Set Block Size for Card */ + sdmmc_cmdinitstructure.Argument = (uint32_t)BlockSize; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN); + + if (errorstate != SD_OK) + { + return errorstate; + } + + if(NumberOfBlocks > 1) + { + /* Send CMD25 WRITE_MULT_BLOCK with argument data address */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_MULT_BLOCK; + /* Test for DATAEND : Data end (data counter, SDID count) is zero) */ + ulEndFags = SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND | SDIO_FLAG_STBITERR; + } + else + { + /* Send CMD24 WRITE_SINGLE_BLOCK */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_SINGLE_BLOCK; + /* Test for DBCKEND : Data Block Sent/Received (CRC check passed) */ + ulEndFags = SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR; + } + ulEndFags |= SDIO_FLAG_TXUNDERR; + + sdmmc_cmdinitstructure.Argument = (uint32_t)WriteAddr; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, sdmmc_cmdinitstructure.CmdIndex); + if (errorstate != SD_OK) + { + return errorstate; + } + ulHasHWFlowControl = ( hsd->Instance->CLKCR & SDIO_HARDWARE_FLOW_CONTROL_ENABLE ) != 0; + + /* Set total number of bytes to write */ + totalnumberofbytes = NumberOfBlocks * BlockSize; + bytesRemaining = 4 * ( ( totalnumberofbytes + 3 ) / 4 ); + + /* Configure the SD DPSM (Data Path State Machine) */ +/* + sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = NumberOfBlocks * BlockSize; + sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_512B; + sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_CARD; + sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE; + SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure); +*/ + /* Set the SDIO Data Timeout value */ + hsd->Instance->DTIMER = SD_DATATIMEOUT; + + /* Set the SDIO DataLength value */ + hsd->Instance->DLEN = NumberOfBlocks * BlockSize; + + tmpreg = hsd->Instance->DCTRL & ~( DCTRL_CLEAR_MASK ); + /* Set the SDIO data configuration parameters */ + tmpreg |= (uint32_t)(SDIO_DATABLOCK_SIZE_512B | SDIO_TRANSFER_DIR_TO_CARD | SDIO_TRANSFER_MODE_BLOCK | SDIO_DCTRL_DTEN); + + /* Write to SDIO DCTRL */ + + hsd->Instance->DCTRL = tmpreg; + + for( ;; ) + { + last_sta = hsd->Instance->STA; + if( ( last_sta & ( SDIO_FLAG_TXFIFOHE | SDIO_FLAG_TXFIFOE ) ) != 0 ) + { + /* SDIO_FLAG_TXFIFOHE: Transmit FIFO Half Empty + May write 32 bytes. */ + if( bytesRemaining < 32) + { + /* Write data to SDIO Tx FIFO */ + while( bytesRemaining > 0 ) + { + *pulFIFO = *( tempbuff++ ); + bytesRemaining -= 4; + } + } + else + { + /* Write data to SDIO Tx FIFO */ + *pulFIFO = tempbuff[ 0 ]; + *pulFIFO = tempbuff[ 1 ]; + *pulFIFO = tempbuff[ 2 ]; + *pulFIFO = tempbuff[ 3 ]; + *pulFIFO = tempbuff[ 4 ]; + *pulFIFO = tempbuff[ 5 ]; + *pulFIFO = tempbuff[ 6 ]; + *pulFIFO = tempbuff[ 7 ]; + + tempbuff += 8; + bytesRemaining -= 32; + if( ( last_sta & SDIO_FLAG_TXFIFOE ) != 0 ) + { + /* SDIO_FLAG_TXFIFOE: Transmit FIFO empty + May write 24 or 32 extra bytes, depending on + ulHasHWFlowControl. */ + *pulFIFO = tempbuff[ 0 ]; + *pulFIFO = tempbuff[ 1 ]; + *pulFIFO = tempbuff[ 2 ]; + *pulFIFO = tempbuff[ 3 ]; + *pulFIFO = tempbuff[ 4 ]; + *pulFIFO = tempbuff[ 5 ]; + if( ulHasHWFlowControl != 0 ) + { + tempbuff += 6; + bytesRemaining -= 24; + } + else + { + *pulFIFO = tempbuff[ 6 ]; + *pulFIFO = tempbuff[ 7 ]; + + tempbuff += 8; + bytesRemaining -= 32; + } + } + } + } + if( ( last_sta & ulEndFags ) != 0 ) + { + break; + } + } + if( ( ( last_sta & SDIO_FLAG_TXUNDERR ) != 0 ) || ( bytesRemaining != 0 ) ) + { + FF_PRINTF("TX underflow %lu < %lu\n", bytesRemaining, totalnumberofbytes ); + } + /* Send stop transmission command in case of multiblock write */ + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DATAEND) && (NumberOfBlocks > 1)) + { + if ((hsd->CardType == STD_CAPACITY_SD_CARD_V1_1) || (hsd->CardType == STD_CAPACITY_SD_CARD_V2_0) ||\ + (hsd->CardType == HIGH_CAPACITY_SD_CARD)) + { + /* Send stop transmission command */ + errorstate = HAL_SD_StopTransfer(hsd); + } + } + + /* Get error state */ + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DTIMEOUT); + + errorstate = SD_DATA_TIMEOUT; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DCRCFAIL); + + errorstate = SD_DATA_CRC_FAIL; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_TXUNDERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_TXUNDERR); + + errorstate = SD_TX_UNDERRUN; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_STBITERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_STBITERR); + + errorstate = SD_START_BIT_ERR; + + return errorstate; + } + else + { + /* No error flag set */ + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + /* Wait till the card is in programming state */ + do + { + errorstate = SD_IsCardProgramming(hsd, &cardstate); + } while ((errorstate == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING))); + + return errorstate; +} + +/** + * @brief Reads block(s) from a specified address in a card. The Data transfer + * is managed by DMA mode. + * @note This API should be followed by the function HAL_SD_CheckReadOperation() + * to check the completion of the read process + * @param hsd: SD handle + * @param pReadBuffer: Pointer to the buffer that will contain the received data + * @param ReadAddr: Address from where data is to be read + * @param BlockSize: SD card Data block size + * @note BlockSize must be 512 bytes. + * @param NumberOfBlocks: Number of blocks to read. + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + SDIO_DataInitTypeDef sdmmc_datainitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0; + + /* Initialize handle flags */ + hsd->SdTransferCplt = 0; + hsd->DmaTransferCplt = 0; + hsd->SdTransferErr = SD_OK; + if( hsd->EventSetupFunction != NULL ) + { + hsd->EventSetupFunction( hsd ); + } + + /* Initialize SD Read operation */ + if(NumberOfBlocks > 1) + { + hsd->SdOperation = SD_READ_MULTIPLE_BLOCK; + } + else + { + hsd->SdOperation = SD_READ_SINGLE_BLOCK; + } + + /* Enable transfer interrupts */ + __HAL_SD_SDIO_ENABLE_IT(hsd, (SDIO_IT_DCRCFAIL |\ + SDIO_IT_DTIMEOUT |\ + SDIO_IT_DATAEND |\ + SDIO_IT_RXOVERR |\ + SDIO_IT_STBITERR)); + + /* Enable SDIO DMA transfer */ + __HAL_SD_SDIO_DMA_ENABLE(); + + /* Configure DMA user callbacks */ + hsd->hdmarx->XferCpltCallback = SD_DMA_RxCplt; + hsd->hdmarx->XferErrorCallback = SD_DMA_RxError; + + /* Enable the DMA Stream */ + HAL_DMA_Start_IT(hsd->hdmarx, (uint32_t)&hsd->Instance->FIFO, (uint32_t)pReadBuffer, (uint32_t)(BlockSize * NumberOfBlocks)/4); + + if (hsd->CardType == HIGH_CAPACITY_SD_CARD) + { + BlockSize = 512; + ReadAddr /= 512; + } + + /* Set Block Size for Card */ + sdmmc_cmdinitstructure.Argument = (uint32_t)BlockSize; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = BlockSize * NumberOfBlocks; + sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_512B; + sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO; + sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE; + SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure); + + /* Check number of blocks command */ + if(NumberOfBlocks > 1) + { + /* Send CMD18 READ_MULT_BLOCK with argument data address */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_READ_MULT_BLOCK; + } + else + { + /* Send CMD17 READ_SINGLE_BLOCK */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_READ_SINGLE_BLOCK; + } + + sdmmc_cmdinitstructure.Argument = (uint32_t)ReadAddr; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, sdmmc_cmdinitstructure.CmdIndex); + + /* Update the SD transfer error in SD handle */ + hsd->SdTransferErr = errorstate; + + return errorstate; +} + + +/** + * @brief Writes block(s) to a specified address in a card. The Data transfer + * is managed by DMA mode. + * @note This API should be followed by the function HAL_SD_CheckWriteOperation() + * to check the completion of the write process (by SD current status polling). + * @param hsd: SD handle + * @param pWriteBuffer: pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be read + * @param BlockSize: the SD card Data block size + * @note BlockSize must be 512 bytes. + * @param NumberOfBlocks: Number of blocks to write + * @retval SD Card error state + */ +void FF_Sleep( uint32_t ulTime_ms ); +const char *pcShowEnds( uint8_t *apBuf, uint32_t aSecCount ); +int lUDPLoggingPrintf( const char *pcFormatString, ... ); + +HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; +/*SDIO_DataInitTypeDef sdmmc_datainitstructure;*/ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t tmpreg; + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0; + + /* Initialize handle flags */ + hsd->SdTransferCplt = 0; + hsd->DmaTransferCplt = 0; + hsd->SdTransferErr = SD_OK; + if( hsd->EventSetupFunction != NULL ) + { + hsd->EventSetupFunction( hsd ); + } + + hsd->Instance->DLEN = NumberOfBlocks * BlockSize; + + /* Initialize SD Write operation */ + if(NumberOfBlocks > 1) + { + hsd->SdOperation = SD_WRITE_MULTIPLE_BLOCK; + } + else + { + hsd->SdOperation = SD_WRITE_SINGLE_BLOCK; + } + + /* Enable transfer interrupts */ + __HAL_SD_SDIO_ENABLE_IT(hsd, (SDIO_IT_DCRCFAIL |\ + SDIO_IT_DTIMEOUT |\ + SDIO_IT_DATAEND |\ + SDIO_IT_TXUNDERR |\ + SDIO_IT_STBITERR)); + + /* Configure DMA user callbacks */ + hsd->hdmatx->XferCpltCallback = SD_DMA_TxCplt; + hsd->hdmatx->XferErrorCallback = SD_DMA_TxError; + + /* Enable the DMA Stream */ + HAL_DMA_Start_IT(hsd->hdmatx, (uint32_t)pWriteBuffer, (uint32_t)&hsd->Instance->FIFO, (uint32_t)(BlockSize * NumberOfBlocks)/4); + + /* Enable SDIO DMA transfer */ + __HAL_SD_SDIO_DMA_ENABLE(); + + if (hsd->CardType == HIGH_CAPACITY_SD_CARD) + { + BlockSize = 512; + WriteAddr /= 512; + } + + /* Set Block Size for Card */ + sdmmc_cmdinitstructure.Argument = (uint32_t)BlockSize; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Check number of blocks command */ + if(NumberOfBlocks <= 1) + { + /* Send CMD24 WRITE_SINGLE_BLOCK */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_SINGLE_BLOCK; + } + else + { + /* Send CMD25 WRITE_MULT_BLOCK with argument data address */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_MULT_BLOCK; + } + + sdmmc_cmdinitstructure.Argument = (uint32_t)WriteAddr; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, sdmmc_cmdinitstructure.CmdIndex); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ +/* + sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = BlockSize * NumberOfBlocks; + sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_512B; + sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_CARD; + sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE; + SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure); +*/ + + /* Set the SDIO Data Timeout value */ + hsd->Instance->DTIMER = SD_DATATIMEOUT; + +// /* Set the SDIO DataLength value */ +// hsd->Instance->DLEN = NumberOfBlocks * BlockSize; + + tmpreg = hsd->Instance->DCTRL & ~( DCTRL_CLEAR_MASK ); + /* Set the SDIO data configuration parameters */ + tmpreg |= (uint32_t)(SDIO_DATABLOCK_SIZE_512B | SDIO_TRANSFER_DIR_TO_CARD | SDIO_TRANSFER_MODE_BLOCK | SDIO_DCTRL_DTEN); + + /* Write to SDIO DCTRL */ + hsd->Instance->DCTRL = tmpreg; + + hsd->SdTransferErr = errorstate; + + return errorstate; +} + +/** + * @brief This function waits until the SD DMA data read transfer is finished. + * This API should be called after HAL_SD_ReadBlocks_DMA() function + * to insure that all data sent by the card is already transferred by the + * DMA controller. + * @param hsd: SD handle + * @param Timeout: Timeout duration + * @retval SD Card error state + */ + +HAL_SD_ErrorTypedef HAL_SD_CheckReadOperation(SD_HandleTypeDef *hsd, uint32_t ulMaxTime) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t ulStarted = xTaskGetTickCount( ); + BaseType_t xHadTimeout = pdFALSE; + + /* Wait for DMA/SD transfer end or SD error variables to be in SD handle */ + + while( 1 ) + { + HAL_SD_ErrorTypedef xError; + if( ( hsd->DmaTransferCplt != 0 ) && ( hsd->SdTransferCplt != 0 ) ) + { + HAL_DMA_Abort( hsd->hdmarx ); + break; + } + xError = (HAL_SD_ErrorTypedef)hsd->SdTransferErr; + if( xError != SD_OK ) + { + break; + } + if( hsd->EventWaitFunction != NULL ) + { + if( hsd->EventWaitFunction( ( void * ) hsd ) != 0 ) + { + FF_PRINTF( "EventWaitFunction: RX timeout!\n" ); + /* A timeout is reached. */ + break; + } + } + else + { + if( ( xTaskGetTickCount( ) - ulStarted ) >= ulMaxTime ) + { + xHadTimeout = pdTRUE; + break; + } + } + } + + ulStarted = xTaskGetTickCount( ); + + /* Wait until the Rx transfer is no longer active */ + while(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXACT)) + { + if( ( xTaskGetTickCount( ) - ulStarted ) >= ulMaxTime ) + { + xHadTimeout = pdTRUE; + break; + } + } + + /* Send stop command in multiblock read */ + if (hsd->SdOperation == SD_READ_MULTIPLE_BLOCK) + { + errorstate = HAL_SD_StopTransfer(hsd); + } + + if ((xHadTimeout != pdFALSE) && (errorstate == SD_OK)) + { + errorstate = SD_DATA_TIMEOUT; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + /* Return error state */ + if (hsd->SdTransferErr != SD_OK) + { + return (HAL_SD_ErrorTypedef)hsd->SdTransferErr; + } + + return errorstate; +} + +/** + * @brief This function waits until the SD DMA data write transfer is finished. + * This API should be called after HAL_SD_WriteBlocks_DMA() function + * to insure that all data sent by the card is already transferred by the + * DMA controller. + * @param hsd: SD handle + * @param Timeout: Timeout duration + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_CheckWriteOperation(SD_HandleTypeDef *hsd, uint32_t ulMaxTime) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t ulStarted = 0; + BaseType_t xHadTimeout = pdFALSE; + /* Wait for DMA/SD transfer end or SD error variables to be in SD handle */ + + while( 1 ) + { + HAL_SD_ErrorTypedef xError; + if( ( hsd->DmaTransferCplt != 0 ) && ( hsd->SdTransferCplt != 0 ) ) + { + HAL_DMA_Abort( hsd->hdmatx ); + break; + } + xError = (HAL_SD_ErrorTypedef)hsd->SdTransferErr; + if( xError != SD_OK ) + { + break; + } + if( hsd->EventWaitFunction != NULL ) + { + if( hsd->EventWaitFunction( ( void * ) hsd ) != 0 ) + { + FF_PRINTF( "EventWaitFunction: TX timeout!\n" ); + /* A timeout is reached. */ + break; + } + } + else + { + if( ( xTaskGetTickCount( ) - ulStarted ) >= ulMaxTime ) + { + xHadTimeout = pdTRUE; + break; + } + } + } + + ulStarted = xTaskGetTickCount( ); + + /* Wait until the Tx transfer is no longer active */ + /* while( ( hsd->Instance->STA & SDIO_FLAG_TXACT ) != 0 ) { } */ + while( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_TXACT ) ) + { + if( ( xTaskGetTickCount( ) - ulStarted ) >= ulMaxTime ) + { + xHadTimeout = pdTRUE; + break; + } + } + + /* Send stop command in multiblock write */ + if (hsd->SdOperation == SD_WRITE_MULTIPLE_BLOCK) + { + errorstate = HAL_SD_StopTransfer(hsd); + } + + if( ( xHadTimeout != pdFALSE ) && ( errorstate == SD_OK ) ) + { + errorstate = SD_DATA_TIMEOUT; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + /* Return error state */ + if (hsd->SdTransferErr != SD_OK) + { + errorstate = (HAL_SD_ErrorTypedef)(hsd->SdTransferErr); + } + else + { + /* Wait until write is complete */ + while(HAL_SD_GetStatus(hsd) != SD_TRANSFER_OK) + { + } + } + + return errorstate; +} + +/** + * @brief Erases the specified memory area of the given SD card. + * @param hsd: SD handle + * @param startaddr: Start byte address + * @param endaddr: End byte address + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint64_t startaddr, uint64_t endaddr) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + + uint32_t delay = 0; + __IO uint32_t maxdelay = 0; + uint8_t cardstate = 0; + + /* Check if the card command class supports erase command */ + if (((hsd->CSD[1] >> 20) & SD_CCCC_ERASE) == 0) + { + errorstate = SD_REQUEST_NOT_APPLICABLE; + + return errorstate; + } + + /* Get max delay value */ + maxdelay = 120000 / (((hsd->Instance->CLKCR) & 0xFF) + 2); + + if((SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED) == SD_CARD_LOCKED) + { + errorstate = SD_LOCK_UNLOCK_FAILED; + + return errorstate; + } + + /* Get start and end block for high capacity cards */ + if (hsd->CardType == HIGH_CAPACITY_SD_CARD) + { + startaddr /= 512; + endaddr /= 512; + } + + /* According to sd-card spec 1.0 ERASE_GROUP_START (CMD32) and erase_group_end(CMD33) */ + if ((hsd->CardType == STD_CAPACITY_SD_CARD_V1_1) || (hsd->CardType == STD_CAPACITY_SD_CARD_V2_0) ||\ + (hsd->CardType == HIGH_CAPACITY_SD_CARD)) + { + /* Send CMD32 SD_ERASE_GRP_START with argument as addr */ + sdmmc_cmdinitstructure.Argument =(uint32_t)startaddr; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_ERASE_GRP_START; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SD_ERASE_GRP_START); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Send CMD33 SD_ERASE_GRP_END with argument as addr */ + sdmmc_cmdinitstructure.Argument = (uint32_t)endaddr; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_ERASE_GRP_END; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SD_ERASE_GRP_END); + + if (errorstate != SD_OK) + { + return errorstate; + } + } + + /* Send CMD38 ERASE */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_ERASE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_ERASE); + + if (errorstate != SD_OK) + { + return errorstate; + } + + for (; delay < maxdelay; delay++) + { + } + + /* Wait until the card is in programming state */ + errorstate = SD_IsCardProgramming(hsd, &cardstate); + + delay = SD_DATATIMEOUT; + + while ((delay > 0) && (errorstate == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING))) + { + errorstate = SD_IsCardProgramming(hsd, &cardstate); + delay--; + } + + return errorstate; +} + +/** + * @brief This function handles SD card interrupt request. + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_IRQHandler(SD_HandleTypeDef *hsd) +{ + /* Check for SDIO interrupt flags */ + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_IT_DATAEND)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_IT_DATAEND); + + /* SD transfer is complete */ + hsd->SdTransferCplt = 1; + + /* No transfer error */ + hsd->SdTransferErr = SD_OK; + + HAL_SD_XferCpltCallback(hsd); + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_IT_DCRCFAIL)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DCRCFAIL); + + hsd->SdTransferErr = SD_DATA_CRC_FAIL; + + HAL_SD_XferErrorCallback(hsd); + + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_IT_DTIMEOUT)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DTIMEOUT); + + hsd->SdTransferErr = SD_DATA_TIMEOUT; + + HAL_SD_XferErrorCallback(hsd); + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_IT_RXOVERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_RXOVERR); + + hsd->SdTransferErr = SD_RX_OVERRUN; + + HAL_SD_XferErrorCallback(hsd); + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_IT_TXUNDERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_TXUNDERR); + + hsd->SdTransferErr = SD_TX_UNDERRUN; + + HAL_SD_XferErrorCallback(hsd); + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_IT_STBITERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_STBITERR); + + hsd->SdTransferErr = SD_START_BIT_ERR; + + HAL_SD_XferErrorCallback(hsd); + } + else + { + /* No error flag set */ + } + + /* Disable all SDIO peripheral interrupt sources */ + __HAL_SD_SDIO_DISABLE_IT(hsd, SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND |\ + SDIO_IT_TXFIFOHE | SDIO_IT_RXFIFOHF | SDIO_IT_TXUNDERR |\ + SDIO_IT_RXOVERR | SDIO_IT_STBITERR); +} + + +/** + * @brief SD end of transfer callback. + * @param hsd: SD handle + * @retval None + */ +__weak void HAL_SD_XferCpltCallback(SD_HandleTypeDef *hsd) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_XferCpltCallback could be implemented in the user file + */ +} + +/** + * @brief SD Transfer Error callback. + * @param hsd: SD handle + * @retval None + */ +__weak void HAL_SD_XferErrorCallback(SD_HandleTypeDef *hsd) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_XferErrorCallback could be implemented in the user file + */ +} + +/** + * @brief SD Transfer complete Rx callback in non blocking mode. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +__weak void HAL_SD_DMA_RxCpltCallback(DMA_HandleTypeDef *hdma) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_DMA_RxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief SD DMA transfer complete Rx error callback. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +__weak void HAL_SD_DMA_RxErrorCallback(DMA_HandleTypeDef *hdma) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_DMA_RxErrorCallback could be implemented in the user file + */ +} + +/** + * @brief SD Transfer complete Tx callback in non blocking mode. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +__weak void HAL_SD_DMA_TxCpltCallback(DMA_HandleTypeDef *hdma) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_DMA_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief SD DMA transfer complete error Tx callback. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +__weak void HAL_SD_DMA_TxErrorCallback(DMA_HandleTypeDef *hdma) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_DMA_TxErrorCallback could be implemented in the user file + */ +} + +/** + * @} + */ + +/** @addtogroup SD_Exported_Functions_Group3 + * @brief management functions + * +@verbatim + ============================================================================== + ##### Peripheral Control functions ##### + ============================================================================== + [..] + This subsection provides a set of functions allowing to control the SD card + operations. + +@endverbatim + * @{ + */ + +/** + * @brief Returns information about specific card. + * @param hsd: SD handle + * @param pCardInfo: Pointer to a HAL_SD_CardInfoTypedef structure that + * contains all SD cardinformation + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_Get_CardInfo(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypedef *pCardInfo) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t tmp = 0; + + pCardInfo->CardType = (uint8_t)(hsd->CardType); + pCardInfo->RCA = (uint16_t)(hsd->RCA); + + /* Byte 0 */ + tmp = (hsd->CSD[0] & 0xFF000000) >> 24; + pCardInfo->SD_csd.CSDStruct = (uint8_t)((tmp & 0xC0) >> 6); + pCardInfo->SD_csd.SysSpecVersion = (uint8_t)((tmp & 0x3C) >> 2); + pCardInfo->SD_csd.Reserved1 = tmp & 0x03; + + /* Byte 1 */ + tmp = (hsd->CSD[0] & 0x00FF0000) >> 16; + pCardInfo->SD_csd.TAAC = (uint8_t)tmp; + + /* Byte 2 */ + tmp = (hsd->CSD[0] & 0x0000FF00) >> 8; + pCardInfo->SD_csd.NSAC = (uint8_t)tmp; + + /* Byte 3 */ + tmp = hsd->CSD[0] & 0x000000FF; + pCardInfo->SD_csd.MaxBusClkFrec = (uint8_t)tmp; + + /* Byte 4 */ + tmp = (hsd->CSD[1] & 0xFF000000) >> 24; + pCardInfo->SD_csd.CardComdClasses = (uint16_t)(tmp << 4); + + /* Byte 5 */ + tmp = (hsd->CSD[1] & 0x00FF0000) >> 16; + pCardInfo->SD_csd.CardComdClasses |= (uint16_t)((tmp & 0xF0) >> 4); + pCardInfo->SD_csd.RdBlockLen = (uint8_t)(tmp & 0x0F); + + /* Byte 6 */ + tmp = (hsd->CSD[1] & 0x0000FF00) >> 8; + pCardInfo->SD_csd.PartBlockRead = (uint8_t)((tmp & 0x80) >> 7); + pCardInfo->SD_csd.WrBlockMisalign = (uint8_t)((tmp & 0x40) >> 6); + pCardInfo->SD_csd.RdBlockMisalign = (uint8_t)((tmp & 0x20) >> 5); + pCardInfo->SD_csd.DSRImpl = (uint8_t)((tmp & 0x10) >> 4); + pCardInfo->SD_csd.Reserved2 = 0; /*!< Reserved */ + + if ((hsd->CardType == STD_CAPACITY_SD_CARD_V1_1) || (hsd->CardType == STD_CAPACITY_SD_CARD_V2_0)) + { + pCardInfo->SD_csd.DeviceSize = (tmp & 0x03) << 10; + + /* Byte 7 */ + tmp = (uint8_t)(hsd->CSD[1] & 0x000000FF); + pCardInfo->SD_csd.DeviceSize |= (tmp) << 2; + + /* Byte 8 */ + tmp = (uint8_t)((hsd->CSD[2] & 0xFF000000) >> 24); + pCardInfo->SD_csd.DeviceSize |= (tmp & 0xC0) >> 6; + + pCardInfo->SD_csd.MaxRdCurrentVDDMin = (tmp & 0x38) >> 3; + pCardInfo->SD_csd.MaxRdCurrentVDDMax = (tmp & 0x07); + + /* Byte 9 */ + tmp = (uint8_t)((hsd->CSD[2] & 0x00FF0000) >> 16); + pCardInfo->SD_csd.MaxWrCurrentVDDMin = (tmp & 0xE0) >> 5; + pCardInfo->SD_csd.MaxWrCurrentVDDMax = (tmp & 0x1C) >> 2; + pCardInfo->SD_csd.DeviceSizeMul = (tmp & 0x03) << 1; + /* Byte 10 */ + tmp = (uint8_t)((hsd->CSD[2] & 0x0000FF00) >> 8); + pCardInfo->SD_csd.DeviceSizeMul |= (tmp & 0x80) >> 7; + + pCardInfo->CardCapacity = (pCardInfo->SD_csd.DeviceSize + 1) ; + pCardInfo->CardCapacity *= (1 << (pCardInfo->SD_csd.DeviceSizeMul + 2)); + pCardInfo->CardBlockSize = 1 << (pCardInfo->SD_csd.RdBlockLen); + pCardInfo->CardCapacity *= pCardInfo->CardBlockSize; + } + else if (hsd->CardType == HIGH_CAPACITY_SD_CARD) + { + /* Byte 7 */ + tmp = (uint8_t)(hsd->CSD[1] & 0x000000FF); + pCardInfo->SD_csd.DeviceSize = (tmp & 0x3F) << 16; + + /* Byte 8 */ + tmp = (uint8_t)((hsd->CSD[2] & 0xFF000000) >> 24); + + pCardInfo->SD_csd.DeviceSize |= (tmp << 8); + + /* Byte 9 */ + tmp = (uint8_t)((hsd->CSD[2] & 0x00FF0000) >> 16); + + pCardInfo->SD_csd.DeviceSize |= (tmp); + + /* Byte 10 */ + tmp = (uint8_t)((hsd->CSD[2] & 0x0000FF00) >> 8); + + pCardInfo->CardCapacity = (uint64_t)((((uint64_t)pCardInfo->SD_csd.DeviceSize + 1)) * 512 * 1024); + pCardInfo->CardBlockSize = 512; + } + else + { + /* Not supported card type */ + errorstate = SD_ERROR; + } + + pCardInfo->SD_csd.EraseGrSize = (tmp & 0x40) >> 6; + pCardInfo->SD_csd.EraseGrMul = (tmp & 0x3F) << 1; + + /* Byte 11 */ + tmp = (uint8_t)(hsd->CSD[2] & 0x000000FF); + pCardInfo->SD_csd.EraseGrMul |= (tmp & 0x80) >> 7; + pCardInfo->SD_csd.WrProtectGrSize = (tmp & 0x7F); + + /* Byte 12 */ + tmp = (uint8_t)((hsd->CSD[3] & 0xFF000000) >> 24); + pCardInfo->SD_csd.WrProtectGrEnable = (tmp & 0x80) >> 7; + pCardInfo->SD_csd.ManDeflECC = (tmp & 0x60) >> 5; + pCardInfo->SD_csd.WrSpeedFact = (tmp & 0x1C) >> 2; + pCardInfo->SD_csd.MaxWrBlockLen = (tmp & 0x03) << 2; + + /* Byte 13 */ + tmp = (uint8_t)((hsd->CSD[3] & 0x00FF0000) >> 16); + pCardInfo->SD_csd.MaxWrBlockLen |= (tmp & 0xC0) >> 6; + pCardInfo->SD_csd.WriteBlockPaPartial = (tmp & 0x20) >> 5; + pCardInfo->SD_csd.Reserved3 = 0; + pCardInfo->SD_csd.ContentProtectAppli = (tmp & 0x01); + + /* Byte 14 */ + tmp = (uint8_t)((hsd->CSD[3] & 0x0000FF00) >> 8); + pCardInfo->SD_csd.FileFormatGrouop = (tmp & 0x80) >> 7; + pCardInfo->SD_csd.CopyFlag = (tmp & 0x40) >> 6; + pCardInfo->SD_csd.PermWrProtect = (tmp & 0x20) >> 5; + pCardInfo->SD_csd.TempWrProtect = (tmp & 0x10) >> 4; + pCardInfo->SD_csd.FileFormat = (tmp & 0x0C) >> 2; + pCardInfo->SD_csd.ECC = (tmp & 0x03); + + /* Byte 15 */ + tmp = (uint8_t)(hsd->CSD[3] & 0x000000FF); + pCardInfo->SD_csd.CSD_CRC = (tmp & 0xFE) >> 1; + pCardInfo->SD_csd.Reserved4 = 1; + + /* Byte 0 */ + tmp = (uint8_t)((hsd->CID[0] & 0xFF000000) >> 24); + pCardInfo->SD_cid.ManufacturerID = tmp; + + /* Byte 1 */ + tmp = (uint8_t)((hsd->CID[0] & 0x00FF0000) >> 16); + pCardInfo->SD_cid.OEM_AppliID = tmp << 8; + + /* Byte 2 */ + tmp = (uint8_t)((hsd->CID[0] & 0x000000FF00) >> 8); + pCardInfo->SD_cid.OEM_AppliID |= tmp; + + /* Byte 3 */ + tmp = (uint8_t)(hsd->CID[0] & 0x000000FF); + pCardInfo->SD_cid.ProdName1 = tmp << 24; + + /* Byte 4 */ + tmp = (uint8_t)((hsd->CID[1] & 0xFF000000) >> 24); + pCardInfo->SD_cid.ProdName1 |= tmp << 16; + + /* Byte 5 */ + tmp = (uint8_t)((hsd->CID[1] & 0x00FF0000) >> 16); + pCardInfo->SD_cid.ProdName1 |= tmp << 8; + + /* Byte 6 */ + tmp = (uint8_t)((hsd->CID[1] & 0x0000FF00) >> 8); + pCardInfo->SD_cid.ProdName1 |= tmp; + + /* Byte 7 */ + tmp = (uint8_t)(hsd->CID[1] & 0x000000FF); + pCardInfo->SD_cid.ProdName2 = tmp; + + /* Byte 8 */ + tmp = (uint8_t)((hsd->CID[2] & 0xFF000000) >> 24); + pCardInfo->SD_cid.ProdRev = tmp; + + /* Byte 9 */ + tmp = (uint8_t)((hsd->CID[2] & 0x00FF0000) >> 16); + pCardInfo->SD_cid.ProdSN = tmp << 24; + + /* Byte 10 */ + tmp = (uint8_t)((hsd->CID[2] & 0x0000FF00) >> 8); + pCardInfo->SD_cid.ProdSN |= tmp << 16; + + /* Byte 11 */ + tmp = (uint8_t)(hsd->CID[2] & 0x000000FF); + pCardInfo->SD_cid.ProdSN |= tmp << 8; + + /* Byte 12 */ + tmp = (uint8_t)((hsd->CID[3] & 0xFF000000) >> 24); + pCardInfo->SD_cid.ProdSN |= tmp; + + /* Byte 13 */ + tmp = (uint8_t)((hsd->CID[3] & 0x00FF0000) >> 16); + pCardInfo->SD_cid.Reserved1 |= (tmp & 0xF0) >> 4; + pCardInfo->SD_cid.ManufactDate = (tmp & 0x0F) << 8; + + /* Byte 14 */ + tmp = (uint8_t)((hsd->CID[3] & 0x0000FF00) >> 8); + pCardInfo->SD_cid.ManufactDate |= tmp; + + /* Byte 15 */ + tmp = (uint8_t)(hsd->CID[3] & 0x000000FF); + pCardInfo->SD_cid.CID_CRC = (tmp & 0xFE) >> 1; + pCardInfo->SD_cid.Reserved2 = 1; + + return errorstate; +} + +/** + * @brief Enables wide bus operation for the requested card if supported by + * card. + * @param hsd: SD handle + * @param WideMode: Specifies the SD card wide bus mode + * This parameter can be one of the following values: + * @arg SDIO_BUS_WIDE_8B: 8-bit data transfer (Only for MMC) + * @arg SDIO_BUS_WIDE_4B: 4-bit data transfer + * @arg SDIO_BUS_WIDE_1B: 1-bit data transfer + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_WideBusOperation_Config(SD_HandleTypeDef *hsd, uint32_t WideMode) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + SDIO_InitTypeDef tmpinit; + + /* MMC Card does not support this feature */ + if (hsd->CardType == MULTIMEDIA_CARD) + { + errorstate = SD_UNSUPPORTED_FEATURE; + + return errorstate; + } + else if ((hsd->CardType == STD_CAPACITY_SD_CARD_V1_1) || (hsd->CardType == STD_CAPACITY_SD_CARD_V2_0) ||\ + (hsd->CardType == HIGH_CAPACITY_SD_CARD)) + { + if (WideMode == SDIO_BUS_WIDE_8B) + { + errorstate = SD_UNSUPPORTED_FEATURE; + } + else if (WideMode == SDIO_BUS_WIDE_4B) + { + errorstate = SD_WideBus_Enable(hsd); + } + else if (WideMode == SDIO_BUS_WIDE_1B) + { + errorstate = SD_WideBus_Disable(hsd); + } + else + { + /* WideMode is not a valid argument*/ + errorstate = SD_INVALID_PARAMETER; + } + + if (errorstate == SD_OK) + { + /* Configure the SDIO peripheral */ + tmpinit.ClockEdge = hsd->Init.ClockEdge; + tmpinit.ClockBypass = hsd->Init.ClockBypass; + tmpinit.ClockPowerSave = hsd->Init.ClockPowerSave; + tmpinit.BusWide = WideMode; + tmpinit.HardwareFlowControl = hsd->Init.HardwareFlowControl; + tmpinit.ClockDiv = hsd->Init.ClockDiv; + SDIO_Init(hsd->Instance, tmpinit); + } + } + + return errorstate; +} + +/** + * @brief Aborts an ongoing data transfer. + * @param hsd: SD handle + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_StopTransfer(SD_HandleTypeDef *hsd) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + + /* Send CMD12 STOP_TRANSMISSION */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_STOP_TRANSMISSION; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_STOP_TRANSMISSION); + + return errorstate; +} + +/** + * @brief Switches the SD card to High Speed mode. + * This API must be used after "Transfer State" + * @note This operation should be followed by the configuration + * of PLL to have SDIOCK clock between 67 and 75 MHz + * @param hsd: SD handle + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_HighSpeed (SD_HandleTypeDef *hsd) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + SDIO_DataInitTypeDef sdmmc_datainitstructure; + + uint8_t SD_hs[64] = {0}; + uint32_t SD_scr[2] = {0, 0}; + uint32_t SD_SPEC = 0 ; + uint32_t count = 0, *tempbuff = (uint32_t *)SD_hs; + + /* Initialize the Data control register */ + hsd->Instance->DCTRL = 0; + + /* Get SCR Register */ + errorstate = SD_FindSCR(hsd, SD_scr); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Test the Version supported by the card*/ + SD_SPEC = (SD_scr[1] & 0x01000000) | (SD_scr[1] & 0x02000000); + + if (SD_SPEC != SD_ALLZERO) + { + /* Set Block Size for Card */ + sdmmc_cmdinitstructure.Argument = (uint32_t)64; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = 64; + sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_64B ; + sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO; + sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE; + SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure); + + /* Send CMD6 switch mode */ + sdmmc_cmdinitstructure.Argument = 0x80FFFF01; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_HS_SWITCH; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_HS_SWITCH); + + if (errorstate != SD_OK) + { + return errorstate; + } + + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR)) + { + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF)) + { + for (count = 0; count < 8; count++) + { + *(tempbuff + count) = SDIO_ReadFIFO(hsd->Instance); + } + + tempbuff += 8; + } + } + + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DTIMEOUT); + + errorstate = SD_DATA_TIMEOUT; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DCRCFAIL); + + errorstate = SD_DATA_CRC_FAIL; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_RXOVERR); + + errorstate = SD_RX_OVERRUN; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_STBITERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_STBITERR); + + errorstate = SD_START_BIT_ERR; + + return errorstate; + } + else + { + /* No error flag set */ + } + + count = SD_DATATIMEOUT; + + while ((__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXDAVL)) && (count > 0)) + { + *tempbuff = SDIO_ReadFIFO(hsd->Instance); + tempbuff++; + count--; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + /* Test if the switch mode HS is ok */ + if ((SD_hs[13]& 2) != 2) + { + errorstate = SD_UNSUPPORTED_FEATURE; + } + } + + return errorstate; +} + +/** + * @} + */ + +/** @addtogroup SD_Exported_Functions_Group4 + * @brief Peripheral State functions + * +@verbatim + ============================================================================== + ##### Peripheral State functions ##### + ============================================================================== + [..] + This subsection permits to get in runtime the status of the peripheral + and the data flow. + +@endverbatim + * @{ + */ + +/** + * @brief Returns the current SD card's status. + * @param hsd: SD handle + * @param pSDstatus: Pointer to the buffer that will contain the SD card status + * SD Status register) + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_SendSDStatus(SD_HandleTypeDef *hsd, uint32_t *pSDstatus) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + SDIO_DataInitTypeDef sdmmc_datainitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t count = 0; + + /* Check SD response */ + if ((SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED) == SD_CARD_LOCKED) + { + errorstate = SD_LOCK_UNLOCK_FAILED; + + return errorstate; + } + + /* Set block size for card if it is not equal to current block size for card */ + sdmmc_cmdinitstructure.Argument = 64; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Send CMD55 */ + sdmmc_cmdinitstructure.Argument = (uint32_t)(hsd->RCA << 16); + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_CMD); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = 64; + sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_64B; + sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO; + sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE; + SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure); + + /* Send ACMD13 (SD_APP_STATUS) with argument as card's RCA */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_APP_STATUS; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SD_APP_STATUS); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Get status data */ + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR)) + { + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF)) + { + for (count = 0; count < 8; count++) + { + *(pSDstatus + count) = SDIO_ReadFIFO(hsd->Instance); + } + + pSDstatus += 8; + } + } + + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DTIMEOUT); + + errorstate = SD_DATA_TIMEOUT; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DCRCFAIL); + + errorstate = SD_DATA_CRC_FAIL; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_RXOVERR); + + errorstate = SD_RX_OVERRUN; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_STBITERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_STBITERR); + + errorstate = SD_START_BIT_ERR; + + return errorstate; + } + else + { + /* No error flag set */ + } + + count = SD_DATATIMEOUT; + while ((__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXDAVL)) && (count > 0)) + { + *pSDstatus = SDIO_ReadFIFO(hsd->Instance); + pSDstatus++; + count--; + } + + /* Clear all the static status flags*/ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + return errorstate; +} + +/** + * @brief Gets the current sd card data status. + * @param hsd: SD handle + * @retval Data Transfer state + */ +HAL_SD_TransferStateTypedef HAL_SD_GetStatus(SD_HandleTypeDef *hsd) +{ + HAL_SD_CardStateTypedef cardstate = SD_CARD_TRANSFER; + + /* Get SD card state */ + cardstate = SD_GetState(hsd); + + /* Find SD status according to card state*/ + if (cardstate == SD_CARD_TRANSFER) + { + return SD_TRANSFER_OK; + } + else if(cardstate == SD_CARD_ERROR) + { + return SD_TRANSFER_ERROR; + } + else + { + return SD_TRANSFER_BUSY; + } +} + +/** + * @brief Gets the SD card status. + * @param hsd: SD handle + * @param pCardStatus: Pointer to the HAL_SD_CardStatusTypedef structure that + * will contain the SD card status information + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_GetCardStatus(SD_HandleTypeDef *hsd, HAL_SD_CardStatusTypedef *pCardStatus) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t tmp = 0; + uint32_t sd_status[16]; + + errorstate = HAL_SD_SendSDStatus(hsd, sd_status); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Byte 0 */ + tmp = (sd_status[0] & 0xC0) >> 6; + pCardStatus->DAT_BUS_WIDTH = (uint8_t)tmp; + + /* Byte 0 */ + tmp = (sd_status[0] & 0x20) >> 5; + pCardStatus->SECURED_MODE = (uint8_t)tmp; + + /* Byte 2 */ + tmp = (sd_status[2] & 0xFF); + pCardStatus->SD_CARD_TYPE = (uint8_t)(tmp << 8); + + /* Byte 3 */ + tmp = (sd_status[3] & 0xFF); + pCardStatus->SD_CARD_TYPE |= (uint8_t)tmp; + + /* Byte 4 */ + tmp = (sd_status[4] & 0xFF); + pCardStatus->SIZE_OF_PROTECTED_AREA = (uint8_t)(tmp << 24); + + /* Byte 5 */ + tmp = (sd_status[5] & 0xFF); + pCardStatus->SIZE_OF_PROTECTED_AREA |= (uint8_t)(tmp << 16); + + /* Byte 6 */ + tmp = (sd_status[6] & 0xFF); + pCardStatus->SIZE_OF_PROTECTED_AREA |= (uint8_t)(tmp << 8); + + /* Byte 7 */ + tmp = (sd_status[7] & 0xFF); + pCardStatus->SIZE_OF_PROTECTED_AREA |= (uint8_t)tmp; + + /* Byte 8 */ + tmp = (sd_status[8] & 0xFF); + pCardStatus->SPEED_CLASS = (uint8_t)tmp; + + /* Byte 9 */ + tmp = (sd_status[9] & 0xFF); + pCardStatus->PERFORMANCE_MOVE = (uint8_t)tmp; + + /* Byte 10 */ + tmp = (sd_status[10] & 0xF0) >> 4; + pCardStatus->AU_SIZE = (uint8_t)tmp; + + /* Byte 11 */ + tmp = (sd_status[11] & 0xFF); + pCardStatus->ERASE_SIZE = (uint8_t)(tmp << 8); + + /* Byte 12 */ + tmp = (sd_status[12] & 0xFF); + pCardStatus->ERASE_SIZE |= (uint8_t)tmp; + + /* Byte 13 */ + tmp = (sd_status[13] & 0xFC) >> 2; + pCardStatus->ERASE_TIMEOUT = (uint8_t)tmp; + + /* Byte 13 */ + tmp = (sd_status[13] & 0x3); + pCardStatus->ERASE_OFFSET = (uint8_t)tmp; + + return errorstate; +} + +/** + * @} + */ + +/** + * @} + */ + +/* Private function ----------------------------------------------------------*/ +/** @addtogroup SD_Private_Functions + * @{ + */ + +/** + * @brief SD DMA transfer complete Rx callback. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SD_DMA_RxCplt(DMA_HandleTypeDef *hdma) +{ + SD_HandleTypeDef *hsd = (SD_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; + + /* DMA transfer is complete */ + hsd->DmaTransferCplt = 1; + +// /* Wait until SD transfer is complete */ +// while(hsd->SdTransferCplt == 0) +// { +// } +// +// /* Disable the DMA channel */ +// HAL_DMA_Abort(hdma); + + /* Transfer complete user callback */ + HAL_SD_DMA_RxCpltCallback(hsd->hdmarx); +} + +/** + * @brief SD DMA transfer Error Rx callback. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SD_DMA_RxError(DMA_HandleTypeDef *hdma) +{ + SD_HandleTypeDef *hsd = (SD_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; + + /* Transfer complete user callback */ + HAL_SD_DMA_RxErrorCallback(hsd->hdmarx); +} + +/** + * @brief SD DMA transfer complete Tx callback. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SD_DMA_TxCplt(DMA_HandleTypeDef *hdma) +{ + SD_HandleTypeDef *hsd = (SD_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; + + /* DMA transfer is complete */ + hsd->DmaTransferCplt = 1; + +// /* Wait until SD transfer is complete */ +// while(hsd->SdTransferCplt == 0) +// { +// } +// +// /* Disable the DMA channel */ +// HAL_DMA_Abort(hdma); + + /* Transfer complete user callback */ + HAL_SD_DMA_TxCpltCallback(hsd->hdmatx); +} + +/** + * @brief SD DMA transfer Error Tx callback. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SD_DMA_TxError(DMA_HandleTypeDef *hdma) +{ + SD_HandleTypeDef *hsd = ( SD_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; + + /* Transfer complete user callback */ + HAL_SD_DMA_TxErrorCallback(hsd->hdmatx); +} + +/** + * @brief Returns the SD current state. + * @param hsd: SD handle + * @retval SD card current state + */ +static HAL_SD_CardStateTypedef SD_GetState(SD_HandleTypeDef *hsd) +{ + uint32_t resp1 = 0; + + if (SD_SendStatus(hsd, &resp1) != SD_OK) + { + return SD_CARD_ERROR; + } + else + { + return (HAL_SD_CardStateTypedef)((resp1 >> 9) & 0x0F); + } +} + +/** + * @brief Initializes all cards or single card as the case may be Card(s) come + * into standby state. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_Initialize_Cards(SD_HandleTypeDef *hsd) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint16_t sd_rca = 1; + + if(SDIO_GetPowerState(hsd->Instance) == 0) /* Power off */ + { + errorstate = SD_REQUEST_NOT_APPLICABLE; + + return errorstate; + } + + if(hsd->CardType != SECURE_DIGITAL_IO_CARD) + { + /* Send CMD2 ALL_SEND_CID */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_ALL_SEND_CID; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_LONG; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp2Error(hsd); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Get Card identification number data */ + hsd->CID[0] = SDIO_GetResponse(SDIO_RESP1); + hsd->CID[1] = SDIO_GetResponse(SDIO_RESP2); + hsd->CID[2] = SDIO_GetResponse(SDIO_RESP3); + hsd->CID[3] = SDIO_GetResponse(SDIO_RESP4); + } + + if((hsd->CardType == STD_CAPACITY_SD_CARD_V1_1) || (hsd->CardType == STD_CAPACITY_SD_CARD_V2_0) ||\ + (hsd->CardType == SECURE_DIGITAL_IO_COMBO_CARD) || (hsd->CardType == HIGH_CAPACITY_SD_CARD)) + { + /* Send CMD3 SET_REL_ADDR with argument 0 */ + /* SD Card publishes its RCA. */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_REL_ADDR; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp6Error(hsd, SD_CMD_SET_REL_ADDR, &sd_rca); + + if(errorstate != SD_OK) + { + return errorstate; + } + } + + if (hsd->CardType != SECURE_DIGITAL_IO_CARD) + { + /* Get the SD card RCA */ + hsd->RCA = sd_rca; + + /* Send CMD9 SEND_CSD with argument as card's RCA */ + sdmmc_cmdinitstructure.Argument = (uint32_t)(hsd->RCA << 16); + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SEND_CSD; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_LONG; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp2Error(hsd); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Get Card Specific Data */ + hsd->CSD[0] = SDIO_GetResponse(SDIO_RESP1); + hsd->CSD[1] = SDIO_GetResponse(SDIO_RESP2); + hsd->CSD[2] = SDIO_GetResponse(SDIO_RESP3); + hsd->CSD[3] = SDIO_GetResponse(SDIO_RESP4); + } + + /* All cards are initialized */ + return errorstate; +} + +/** + * @brief Selects of Deselects the corresponding card. + * @param hsd: SD handle + * @param addr: Address of the card to be selected + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_Select_Deselect(SD_HandleTypeDef *hsd, uint64_t addr) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + + /* Send CMD7 SDIO_SEL_DESEL_CARD */ + sdmmc_cmdinitstructure.Argument = (uint32_t)addr; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SEL_DESEL_CARD; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SEL_DESEL_CARD); + + return errorstate; +} + +/** + * @brief Enquires cards about their operating voltage and configures clock + * controls and stores SD information that will be needed in future + * in the SD handle. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_PowerON(SD_HandleTypeDef *hsd) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + __IO HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t response = 0, count = 0, validvoltage = 0; + uint32_t sdtype = SD_STD_CAPACITY; + + /* Power ON Sequence -------------------------------------------------------*/ + /* Disable SDIO Clock */ + __HAL_SD_SDIO_DISABLE(); + + /* Set Power State to ON */ + SDIO_PowerState_ON(hsd->Instance); + + /* 1ms: required power up waiting time before starting the SD initialization + sequence */ + HAL_Delay(1); + + /* Enable SDIO Clock */ + __HAL_SD_SDIO_ENABLE(); + + /* CMD0: GO_IDLE_STATE -----------------------------------------------------*/ + /* No CMD response required */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_GO_IDLE_STATE; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_NO; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdError(hsd); + + if(errorstate != SD_OK) + { + /* CMD Response Timeout (wait for CMDSENT flag) */ + return errorstate; + } + + /* CMD8: SEND_IF_COND ------------------------------------------------------*/ + /* Send CMD8 to verify SD card interface operating condition */ + /* Argument: - [31:12]: Reserved (shall be set to '0') + - [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V) + - [7:0]: Check Pattern (recommended 0xAA) */ + /* CMD Response: R7 */ + sdmmc_cmdinitstructure.Argument = SD_CHECK_PATTERN; + sdmmc_cmdinitstructure.CmdIndex = SD_SDIO_SEND_IF_COND; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp7Error(hsd); + + if (errorstate == SD_OK) + { + /* SD Card 2.0 */ + FF_PRINTF( "It's a 2.0 card, check SDHC\n" ); + hsd->CardType = STD_CAPACITY_SD_CARD_V2_0; + sdtype = SD_HIGH_CAPACITY; + } + + /* Send CMD55 */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_CMD); + + /* If errorstate is Command Timeout, it is a MMC card */ + /* If errorstate is SD_OK it is a SD card: SD card 2.0 (voltage range mismatch) + or SD card 1.x */ + if(errorstate == SD_OK) + { + /* SD CARD */ + /* Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */ + while((!validvoltage) && (count < SD_MAX_VOLT_TRIAL)) + { + + /* SEND CMD55 APP_CMD with RCA as 0 */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_CMD); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Send CMD41 */ + sdmmc_cmdinitstructure.Argument = SD_VOLTAGE_WINDOW_SD | sdtype; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_APP_OP_COND; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp3Error(hsd); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Get command response */ + response = SDIO_GetResponse(SDIO_RESP1); + + /* Get operating voltage*/ + validvoltage = (((response >> 31) == 1) ? 1 : 0); + + if( ( count == 0 ) || ( validvoltage != 0 ) ) + { + FF_PRINTF("Voltage resp: %08x\n", ( unsigned ) response); + } + + count++; + } + + if(count >= SD_MAX_VOLT_TRIAL) + { + FF_PRINTF("Can not agree on Voltage\n"); + errorstate = SD_INVALID_VOLTRANGE; + + return errorstate; + } + + if((response & SD_HIGH_CAPACITY) == SD_HIGH_CAPACITY) /* (response &= SD_HIGH_CAPACITY) */ + { + hsd->CardType = HIGH_CAPACITY_SD_CARD; + } + + } /* else MMC Card */ + + return errorstate; +} + +/** + * @brief Turns the SDIO output signals off. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_PowerOFF(SD_HandleTypeDef *hsd) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + + /* Set Power State to OFF */ + SDIO_PowerState_OFF(hsd->Instance); + + return errorstate; +} + +/** + * @brief Returns the current card's status. + * @param hsd: SD handle + * @param pCardStatus: pointer to the buffer that will contain the SD card + * status (Card Status register) + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_SendStatus(SD_HandleTypeDef *hsd, uint32_t *pCardStatus) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + + if(pCardStatus == NULL) + { + errorstate = SD_INVALID_PARAMETER; + + return errorstate; + } + + /* Send Status command */ + sdmmc_cmdinitstructure.Argument = (uint32_t)(hsd->RCA << 16); + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SEND_STATUS; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SEND_STATUS); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Get SD card status */ + *pCardStatus = SDIO_GetResponse(SDIO_RESP1); + + return errorstate; +} + +/** + * @brief Checks for error conditions for CMD0. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_CmdError(SD_HandleTypeDef *hsd) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; +// uint32_t timeout; + uint32_t tmp; + uint32_t ulStarted = xTaskGetTickCount( ); + uint32_t ulMaxTime = 200; + BaseType_t xHadTimeout = pdFALSE; + +// timeout = SDIO_CMD0TIMEOUT; + + tmp = __HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CMDSENT); + + while( tmp == 0 ) + { + tmp = __HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CMDSENT); + if( ( xTaskGetTickCount( ) - ulStarted ) >= ulMaxTime ) + { + xHadTimeout = pdTRUE; + break; + } + + } + + if( xHadTimeout != pdFALSE ) + { + errorstate = SD_CMD_RSP_TIMEOUT; + return errorstate; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + return errorstate; +} + +/** + * @brief Checks for error conditions for R7 response. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_CmdResp7Error(SD_HandleTypeDef *hsd) +{ + HAL_SD_ErrorTypedef errorstate = SD_ERROR; +// uint32_t timeout = SDIO_CMD0TIMEOUT; + uint32_t tmp; + uint32_t ulStarted = xTaskGetTickCount( ); + uint32_t ulMaxTime = 200; + BaseType_t xHadTimeout = pdFALSE; + + tmp = __HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT); + + while( tmp == 0 ) + { + tmp = __HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT); + if( ( xTaskGetTickCount( ) - ulStarted ) >= ulMaxTime ) + { + xHadTimeout = pdTRUE; + break; + } + } + + tmp = __HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CTIMEOUT); + + if( xHadTimeout != pdFALSE || tmp) + { + /* Card is not V2.0 compliant or card does not support the set voltage range */ + errorstate = SD_CMD_RSP_TIMEOUT; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CTIMEOUT); + + return errorstate; + } + + if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CMDREND)) + { + /* Card is SD V2.0 compliant */ + errorstate = SD_OK; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CMDREND); + + return errorstate; + } + + return errorstate; +} + +/** + * @brief Checks for error conditions for R1 response. + * @param hsd: SD handle + * @param SD_CMD: The sent command index + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_CmdResp1Error(SD_HandleTypeDef *hsd, uint8_t SD_CMD) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t response_r1; + uint32_t remaining_loops = 168000 * 50; + + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) + { + if( ( --remaining_loops ) == 0 ) + { + FF_PRINTF( "SD_CmdResp1Error: times out\n" ); + break; + } + } + + if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CTIMEOUT)) + { + errorstate = SD_CMD_RSP_TIMEOUT; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CTIMEOUT); + + return errorstate; + } + else if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL)) + { + errorstate = SD_CMD_CRC_FAIL; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CCRCFAIL); + + return errorstate; + } + + /* Check response received is of desired command */ + if(SDIO_GetCommandResponse(hsd->Instance) != SD_CMD) + { + FF_PRINTF( "RESPCMD[1] = %08x cmd = %02x\n", ( unsigned ) hsd->Instance->RESPCMD, SD_CMD ); + errorstate = SD_ILLEGAL_CMD; + + return errorstate; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + /* We have received response, retrieve it for analysis */ + response_r1 = SDIO_GetResponse(SDIO_RESP1); + + if((response_r1 & SD_OCR_ERRORBITS) == SD_ALLZERO) + { + return errorstate; + } + + if((response_r1 & SD_OCR_ADDR_OUT_OF_RANGE) == SD_OCR_ADDR_OUT_OF_RANGE) + { + return(SD_ADDR_OUT_OF_RANGE); + } + + if((response_r1 & SD_OCR_ADDR_MISALIGNED) == SD_OCR_ADDR_MISALIGNED) + { + return(SD_ADDR_MISALIGNED); + } + + if((response_r1 & SD_OCR_BLOCK_LEN_ERR) == SD_OCR_BLOCK_LEN_ERR) + { + return(SD_BLOCK_LEN_ERR); + } + + if((response_r1 & SD_OCR_ERASE_SEQ_ERR) == SD_OCR_ERASE_SEQ_ERR) + { + return(SD_ERASE_SEQ_ERR); + } + + if((response_r1 & SD_OCR_BAD_ERASE_PARAM) == SD_OCR_BAD_ERASE_PARAM) + { + return(SD_BAD_ERASE_PARAM); + } + + if((response_r1 & SD_OCR_WRITE_PROT_VIOLATION) == SD_OCR_WRITE_PROT_VIOLATION) + { + return(SD_WRITE_PROT_VIOLATION); + } + + if((response_r1 & SD_OCR_LOCK_UNLOCK_FAILED) == SD_OCR_LOCK_UNLOCK_FAILED) + { + return(SD_LOCK_UNLOCK_FAILED); + } + + if((response_r1 & SD_OCR_COM_CRC_FAILED) == SD_OCR_COM_CRC_FAILED) + { + return(SD_COM_CRC_FAILED); + } + + if((response_r1 & SD_OCR_ILLEGAL_CMD) == SD_OCR_ILLEGAL_CMD) + { + return(SD_ILLEGAL_CMD); + } + + if((response_r1 & SD_OCR_CARD_ECC_FAILED) == SD_OCR_CARD_ECC_FAILED) + { + return(SD_CARD_ECC_FAILED); + } + + if((response_r1 & SD_OCR_CC_ERROR) == SD_OCR_CC_ERROR) + { + return(SD_CC_ERROR); + } + + if((response_r1 & SD_OCR_GENERAL_UNKNOWN_ERROR) == SD_OCR_GENERAL_UNKNOWN_ERROR) + { + return(SD_GENERAL_UNKNOWN_ERROR); + } + + if((response_r1 & SD_OCR_STREAM_READ_UNDERRUN) == SD_OCR_STREAM_READ_UNDERRUN) + { + return(SD_STREAM_READ_UNDERRUN); + } + + if((response_r1 & SD_OCR_STREAM_WRITE_OVERRUN) == SD_OCR_STREAM_WRITE_OVERRUN) + { + return(SD_STREAM_WRITE_OVERRUN); + } + + if((response_r1 & SD_OCR_CID_CSD_OVERWRITE) == SD_OCR_CID_CSD_OVERWRITE) + { + return(SD_CID_CSD_OVERWRITE); + } + + if((response_r1 & SD_OCR_WP_ERASE_SKIP) == SD_OCR_WP_ERASE_SKIP) + { + return(SD_WP_ERASE_SKIP); + } + + if((response_r1 & SD_OCR_CARD_ECC_DISABLED) == SD_OCR_CARD_ECC_DISABLED) + { + return(SD_CARD_ECC_DISABLED); + } + + if((response_r1 & SD_OCR_ERASE_RESET) == SD_OCR_ERASE_RESET) + { + return(SD_ERASE_RESET); + } + + if((response_r1 & SD_OCR_AKE_SEQ_ERROR) == SD_OCR_AKE_SEQ_ERROR) + { + return(SD_AKE_SEQ_ERROR); + } + + return errorstate; +} + +/** + * @brief Checks for error conditions for R3 (OCR) response. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_CmdResp3Error(SD_HandleTypeDef *hsd) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + + while (!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) + { + } + + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CTIMEOUT)) + { + errorstate = SD_CMD_RSP_TIMEOUT; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CTIMEOUT); + + return errorstate; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + return errorstate; +} + +/** + * @brief Checks for error conditions for R2 (CID or CSD) response. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_CmdResp2Error(SD_HandleTypeDef *hsd) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + + while (!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) + { + } + + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CTIMEOUT)) + { + errorstate = SD_CMD_RSP_TIMEOUT; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CTIMEOUT); + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL)) + { + errorstate = SD_CMD_CRC_FAIL; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CCRCFAIL); + + return errorstate; + } + else + { + /* No error flag set */ + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + return errorstate; +} + +/** + * @brief Checks for error conditions for R6 (RCA) response. + * @param hsd: SD handle + * @param SD_CMD: The sent command index + * @param pRCA: Pointer to the variable that will contain the SD card relative + * address RCA + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_CmdResp6Error(SD_HandleTypeDef *hsd, uint8_t SD_CMD, uint16_t *pRCA) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t response_r1; + + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) + { + } + + if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CTIMEOUT)) + { + errorstate = SD_CMD_RSP_TIMEOUT; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CTIMEOUT); + + return errorstate; + } + else if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL)) + { + errorstate = SD_CMD_CRC_FAIL; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CCRCFAIL); + + return errorstate; + } + else + { + /* No error flag set */ + } + + /* Check response received is of desired command */ + if(SDIO_GetCommandResponse(hsd->Instance) != SD_CMD) + { + FF_PRINTF( "RESPCMD[2] = %08x cmd = %02x\n", ( unsigned ) hsd->Instance->RESPCMD, SD_CMD ); + errorstate = SD_ILLEGAL_CMD; + + return errorstate; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + /* We have received response, retrieve it. */ + response_r1 = SDIO_GetResponse(SDIO_RESP1); + + if((response_r1 & (SD_R6_GENERAL_UNKNOWN_ERROR | SD_R6_ILLEGAL_CMD | SD_R6_COM_CRC_FAILED)) == SD_ALLZERO) + { + *pRCA = (uint16_t) (response_r1 >> 16); + + return errorstate; + } + + if((response_r1 & SD_R6_GENERAL_UNKNOWN_ERROR) == SD_R6_GENERAL_UNKNOWN_ERROR) + { + return(SD_GENERAL_UNKNOWN_ERROR); + } + + if((response_r1 & SD_R6_ILLEGAL_CMD) == SD_R6_ILLEGAL_CMD) + { + FF_PRINTF( "response_r1 = %08x cmd = %02x\n", ( unsigned ) hsd->Instance->RESPCMD, ( unsigned ) SD_R6_ILLEGAL_CMD ); + return(SD_ILLEGAL_CMD); + } + + if((response_r1 & SD_R6_COM_CRC_FAILED) == SD_R6_COM_CRC_FAILED) + { + return(SD_COM_CRC_FAILED); + } + + return errorstate; +} + +/** + * @brief Enables the SDIO wide bus mode. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_WideBus_Enable(SD_HandleTypeDef *hsd) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + + uint32_t scr[2] = {0, 0}; + + if((SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED) == SD_CARD_LOCKED) + { + errorstate = SD_LOCK_UNLOCK_FAILED; + + return errorstate; + } + + /* Get SCR Register */ + errorstate = SD_FindSCR(hsd, scr); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* If requested card supports wide bus operation */ + if((scr[1] & SD_WIDE_BUS_SUPPORT) != SD_ALLZERO) + { + /* Send CMD55 APP_CMD with argument as card's RCA.*/ + sdmmc_cmdinitstructure.Argument = (uint32_t)(hsd->RCA << 16); + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_CMD); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Send ACMD6 APP_CMD with argument as 2 for wide bus mode */ + sdmmc_cmdinitstructure.Argument = 2; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_SD_SET_BUSWIDTH; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_SD_SET_BUSWIDTH); + + if(errorstate != SD_OK) + { + return errorstate; + } + + return errorstate; + } + else + { + errorstate = SD_REQUEST_NOT_APPLICABLE; + + return errorstate; + } +} + +/** + * @brief Disables the SDIO wide bus mode. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_WideBus_Disable(SD_HandleTypeDef *hsd) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + + uint32_t scr[2] = {0, 0}; + + if((SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED) == SD_CARD_LOCKED) + { + errorstate = SD_LOCK_UNLOCK_FAILED; + + return errorstate; + } + + /* Get SCR Register */ + errorstate = SD_FindSCR(hsd, scr); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* If requested card supports 1 bit mode operation */ + if((scr[1] & SD_SINGLE_BUS_SUPPORT) != SD_ALLZERO) + { + /* Send CMD55 APP_CMD with argument as card's RCA */ + sdmmc_cmdinitstructure.Argument = (uint32_t)(hsd->RCA << 16); + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_CMD); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Send ACMD6 APP_CMD with argument as 0 for single bus mode */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_SD_SET_BUSWIDTH; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_SD_SET_BUSWIDTH); + + if(errorstate != SD_OK) + { + return errorstate; + } + + return errorstate; + } + else + { + errorstate = SD_REQUEST_NOT_APPLICABLE; + + return errorstate; + } +} + + +/** + * @brief Finds the SD card SCR register value. + * @param hsd: SD handle + * @param pSCR: pointer to the buffer that will contain the SCR value + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_FindSCR(SD_HandleTypeDef *hsd, uint32_t *pSCR) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + SDIO_DataInitTypeDef sdmmc_datainitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t index = 0; + uint32_t tempscr[2] = {0, 0}; + + /* Set Block Size To 8 Bytes */ + /* Send CMD55 APP_CMD with argument as card's RCA */ + sdmmc_cmdinitstructure.Argument = (uint32_t)8; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Send CMD55 APP_CMD with argument as card's RCA */ + sdmmc_cmdinitstructure.Argument = (uint32_t)((hsd->RCA) << 16); + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_CMD); + + if(errorstate != SD_OK) + { + return errorstate; + } + sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = 8; + sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_8B; + sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO; + sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE; + SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure); + + /* Send ACMD51 SD_APP_SEND_SCR with argument as 0 */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_APP_SEND_SCR; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SD_APP_SEND_SCR); + + if(errorstate != SD_OK) + { + return errorstate; + } + + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR)) + { + if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXDAVL)) + { + *(tempscr + index) = SDIO_ReadFIFO(hsd->Instance); + index++; + } + } + + if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DTIMEOUT); + + errorstate = SD_DATA_TIMEOUT; + + return errorstate; + } + else if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DCRCFAIL); + + errorstate = SD_DATA_CRC_FAIL; + + return errorstate; + } + else if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_RXOVERR); + + errorstate = SD_RX_OVERRUN; + + return errorstate; + } + else if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_STBITERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_STBITERR); + + errorstate = SD_START_BIT_ERR; + + return errorstate; + } + else + { + /* No error flag set */ + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + *(pSCR + 1) = ((tempscr[0] & SD_0TO7BITS) << 24) | ((tempscr[0] & SD_8TO15BITS) << 8) |\ + ((tempscr[0] & SD_16TO23BITS) >> 8) | ((tempscr[0] & SD_24TO31BITS) >> 24); + + *(pSCR) = ((tempscr[1] & SD_0TO7BITS) << 24) | ((tempscr[1] & SD_8TO15BITS) << 8) |\ + ((tempscr[1] & SD_16TO23BITS) >> 8) | ((tempscr[1] & SD_24TO31BITS) >> 24); + + return errorstate; +} + +/** + * @brief Checks if the SD card is in programming state. + * @param hsd: SD handle + * @param pStatus: pointer to the variable that will contain the SD card state + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_IsCardProgramming(SD_HandleTypeDef *hsd, uint8_t *pStatus) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + __IO uint32_t responseR1 = 0; + + sdmmc_cmdinitstructure.Argument = (uint32_t)(hsd->RCA << 16); + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SEND_STATUS; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) + { + } + + if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CTIMEOUT)) + { + errorstate = SD_CMD_RSP_TIMEOUT; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CTIMEOUT); + + return errorstate; + } + else if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL)) + { + errorstate = SD_CMD_CRC_FAIL; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CCRCFAIL); + + return errorstate; + } + else + { + /* No error flag set */ + } + + /* Check response received is of desired command */ + if((uint32_t)SDIO_GetCommandResponse(hsd->Instance) != SD_CMD_SEND_STATUS) + { + FF_PRINTF( "RESPCMD[3] = %08x cmd = %02x\n", ( unsigned ) hsd->Instance->RESPCMD, SD_CMD_SEND_STATUS ); + errorstate = SD_ILLEGAL_CMD; + + return errorstate; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + + /* We have received response, retrieve it for analysis */ + responseR1 = SDIO_GetResponse(SDIO_RESP1); + + /* Find out card status */ + *pStatus = (uint8_t)((responseR1 >> 9) & 0x0000000F); + + if((responseR1 & SD_OCR_ERRORBITS) == SD_ALLZERO) + { + return errorstate; + } + + if((responseR1 & SD_OCR_ADDR_OUT_OF_RANGE) == SD_OCR_ADDR_OUT_OF_RANGE) + { + return(SD_ADDR_OUT_OF_RANGE); + } + + if((responseR1 & SD_OCR_ADDR_MISALIGNED) == SD_OCR_ADDR_MISALIGNED) + { + return(SD_ADDR_MISALIGNED); + } + + if((responseR1 & SD_OCR_BLOCK_LEN_ERR) == SD_OCR_BLOCK_LEN_ERR) + { + return(SD_BLOCK_LEN_ERR); + } + + if((responseR1 & SD_OCR_ERASE_SEQ_ERR) == SD_OCR_ERASE_SEQ_ERR) + { + return(SD_ERASE_SEQ_ERR); + } + + if((responseR1 & SD_OCR_BAD_ERASE_PARAM) == SD_OCR_BAD_ERASE_PARAM) + { + return(SD_BAD_ERASE_PARAM); + } + + if((responseR1 & SD_OCR_WRITE_PROT_VIOLATION) == SD_OCR_WRITE_PROT_VIOLATION) + { + return(SD_WRITE_PROT_VIOLATION); + } + + if((responseR1 & SD_OCR_LOCK_UNLOCK_FAILED) == SD_OCR_LOCK_UNLOCK_FAILED) + { + return(SD_LOCK_UNLOCK_FAILED); + } + + if((responseR1 & SD_OCR_COM_CRC_FAILED) == SD_OCR_COM_CRC_FAILED) + { + return(SD_COM_CRC_FAILED); + } + + if((responseR1 & SD_OCR_ILLEGAL_CMD) == SD_OCR_ILLEGAL_CMD) + { + return(SD_ILLEGAL_CMD); + } + + if((responseR1 & SD_OCR_CARD_ECC_FAILED) == SD_OCR_CARD_ECC_FAILED) + { + return(SD_CARD_ECC_FAILED); + } + + if((responseR1 & SD_OCR_CC_ERROR) == SD_OCR_CC_ERROR) + { + return(SD_CC_ERROR); + } + + if((responseR1 & SD_OCR_GENERAL_UNKNOWN_ERROR) == SD_OCR_GENERAL_UNKNOWN_ERROR) + { + return(SD_GENERAL_UNKNOWN_ERROR); + } + + if((responseR1 & SD_OCR_STREAM_READ_UNDERRUN) == SD_OCR_STREAM_READ_UNDERRUN) + { + return(SD_STREAM_READ_UNDERRUN); + } + + if((responseR1 & SD_OCR_STREAM_WRITE_OVERRUN) == SD_OCR_STREAM_WRITE_OVERRUN) + { + return(SD_STREAM_WRITE_OVERRUN); + } + + if((responseR1 & SD_OCR_CID_CSD_OVERWRITE) == SD_OCR_CID_CSD_OVERWRITE) + { + return(SD_CID_CSD_OVERWRITE); + } + + if((responseR1 & SD_OCR_WP_ERASE_SKIP) == SD_OCR_WP_ERASE_SKIP) + { + return(SD_WP_ERASE_SKIP); + } + + if((responseR1 & SD_OCR_CARD_ECC_DISABLED) == SD_OCR_CARD_ECC_DISABLED) + { + return(SD_CARD_ECC_DISABLED); + } + + if((responseR1 & SD_OCR_ERASE_RESET) == SD_OCR_ERASE_RESET) + { + return(SD_ERASE_RESET); + } + + if((responseR1 & SD_OCR_AKE_SEQ_ERROR) == SD_OCR_AKE_SEQ_ERROR) + { + return(SD_AKE_SEQ_ERROR); + } + + return errorstate; +} + +/** + * @} + */ + +#endif /* HAL_SD_MODULE_ENABLED */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F4xx/stm32f4xx_hal_sd.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F4xx/stm32f4xx_hal_sd.h new file mode 100644 index 000000000..3635c4eec --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F4xx/stm32f4xx_hal_sd.h @@ -0,0 +1,802 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_sd.h + * @author MCD Application Team + * @version V1.3.2 + * @date 26-June-2015 + * @brief Header file of SD HAL module. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F4xx_HAL_SD_H +#define __STM32F4xx_HAL_SD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_ll_sdmmc.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @defgroup SD SD + * @brief SD HAL module driver + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup SD_Exported_Types SD Exported Types + * @{ + */ + +/** @defgroup SD_Exported_Types_Group1 SD Handle Structure definition + * @{ + */ +#define SD_InitTypeDef SDIO_InitTypeDef +#define SD_TypeDef SDIO_TypeDef + +struct xSD_Handle; + +/* A function will be called at the start of a DMA action. */ +typedef void ( * SD_EventSetupFunctionTypeDef )( struct xSD_Handle * /* pxhandle */ ); + +/* This function is supposed to wait for an event: SDIO or DMA. + * Return non-zero if a timeout has been reached. */ +typedef uint32_t ( * SD_EventWaitFunctionTypeDef )( struct xSD_Handle * /* pxhandle */ ); + +typedef struct xSD_Handle +{ + SD_TypeDef *Instance; /*!< SDIO register base address */ + + SD_InitTypeDef Init; /*!< SD required parameters */ + + HAL_LockTypeDef Lock; /*!< SD locking object */ + + uint32_t CardType; /*!< SD card type */ + + uint32_t RCA; /*!< SD relative card address */ + + uint32_t CSD[4]; /*!< SD card specific data table */ + + uint32_t CID[4]; /*!< SD card identification number table */ + + __IO uint32_t SdTransferCplt; /*!< SD transfer complete flag in non blocking mode */ + + __IO uint32_t SdTransferErr; /*!< SD transfer error flag in non blocking mode */ + + __IO uint32_t DmaTransferCplt; /*!< SD DMA transfer complete flag */ + + __IO uint32_t SdOperation; /*!< SD transfer operation (read/write) */ + + DMA_HandleTypeDef *hdmarx; /*!< SD Rx DMA handle parameters */ + + DMA_HandleTypeDef *hdmatx; /*!< SD Tx DMA handle parameters */ + + SD_EventSetupFunctionTypeDef EventSetupFunction; + + SD_EventWaitFunctionTypeDef EventWaitFunction; + +}SD_HandleTypeDef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group2 Card Specific Data: CSD Register + * @{ + */ +typedef struct +{ + __IO uint8_t CSDStruct; /*!< CSD structure */ + __IO uint8_t SysSpecVersion; /*!< System specification version */ + __IO uint8_t Reserved1; /*!< Reserved */ + __IO uint8_t TAAC; /*!< Data read access time 1 */ + __IO uint8_t NSAC; /*!< Data read access time 2 in CLK cycles */ + __IO uint8_t MaxBusClkFrec; /*!< Max. bus clock frequency */ + __IO uint16_t CardComdClasses; /*!< Card command classes */ + __IO uint8_t RdBlockLen; /*!< Max. read data block length */ + __IO uint8_t PartBlockRead; /*!< Partial blocks for read allowed */ + __IO uint8_t WrBlockMisalign; /*!< Write block misalignment */ + __IO uint8_t RdBlockMisalign; /*!< Read block misalignment */ + __IO uint8_t DSRImpl; /*!< DSR implemented */ + __IO uint8_t Reserved2; /*!< Reserved */ + __IO uint32_t DeviceSize; /*!< Device Size */ + __IO uint8_t MaxRdCurrentVDDMin; /*!< Max. read current @ VDD min */ + __IO uint8_t MaxRdCurrentVDDMax; /*!< Max. read current @ VDD max */ + __IO uint8_t MaxWrCurrentVDDMin; /*!< Max. write current @ VDD min */ + __IO uint8_t MaxWrCurrentVDDMax; /*!< Max. write current @ VDD max */ + __IO uint8_t DeviceSizeMul; /*!< Device size multiplier */ + __IO uint8_t EraseGrSize; /*!< Erase group size */ + __IO uint8_t EraseGrMul; /*!< Erase group size multiplier */ + __IO uint8_t WrProtectGrSize; /*!< Write protect group size */ + __IO uint8_t WrProtectGrEnable; /*!< Write protect group enable */ + __IO uint8_t ManDeflECC; /*!< Manufacturer default ECC */ + __IO uint8_t WrSpeedFact; /*!< Write speed factor */ + __IO uint8_t MaxWrBlockLen; /*!< Max. write data block length */ + __IO uint8_t WriteBlockPaPartial; /*!< Partial blocks for write allowed */ + __IO uint8_t Reserved3; /*!< Reserved */ + __IO uint8_t ContentProtectAppli; /*!< Content protection application */ + __IO uint8_t FileFormatGrouop; /*!< File format group */ + __IO uint8_t CopyFlag; /*!< Copy flag (OTP) */ + __IO uint8_t PermWrProtect; /*!< Permanent write protection */ + __IO uint8_t TempWrProtect; /*!< Temporary write protection */ + __IO uint8_t FileFormat; /*!< File format */ + __IO uint8_t ECC; /*!< ECC code */ + __IO uint8_t CSD_CRC; /*!< CSD CRC */ + __IO uint8_t Reserved4; /*!< Always 1 */ + +}HAL_SD_CSDTypedef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group3 Card Identification Data: CID Register + * @{ + */ +typedef struct +{ + __IO uint8_t ManufacturerID; /*!< Manufacturer ID */ + __IO uint16_t OEM_AppliID; /*!< OEM/Application ID */ + __IO uint32_t ProdName1; /*!< Product Name part1 */ + __IO uint8_t ProdName2; /*!< Product Name part2 */ + __IO uint8_t ProdRev; /*!< Product Revision */ + __IO uint32_t ProdSN; /*!< Product Serial Number */ + __IO uint8_t Reserved1; /*!< Reserved1 */ + __IO uint16_t ManufactDate; /*!< Manufacturing Date */ + __IO uint8_t CID_CRC; /*!< CID CRC */ + __IO uint8_t Reserved2; /*!< Always 1 */ + +}HAL_SD_CIDTypedef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group4 SD Card Status returned by ACMD13 + * @{ + */ +typedef struct +{ + __IO uint8_t DAT_BUS_WIDTH; /*!< Shows the currently defined data bus width */ + __IO uint8_t SECURED_MODE; /*!< Card is in secured mode of operation */ + __IO uint16_t SD_CARD_TYPE; /*!< Carries information about card type */ + __IO uint32_t SIZE_OF_PROTECTED_AREA; /*!< Carries information about the capacity of protected area */ + __IO uint8_t SPEED_CLASS; /*!< Carries information about the speed class of the card */ + __IO uint8_t PERFORMANCE_MOVE; /*!< Carries information about the card's performance move */ + __IO uint8_t AU_SIZE; /*!< Carries information about the card's allocation unit size */ + __IO uint16_t ERASE_SIZE; /*!< Determines the number of AUs to be erased in one operation */ + __IO uint8_t ERASE_TIMEOUT; /*!< Determines the timeout for any number of AU erase */ + __IO uint8_t ERASE_OFFSET; /*!< Carries information about the erase offset */ + +}HAL_SD_CardStatusTypedef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group5 SD Card information structure + * @{ + */ +typedef struct +{ + HAL_SD_CSDTypedef SD_csd; /*!< SD card specific data register */ + HAL_SD_CIDTypedef SD_cid; /*!< SD card identification number register */ + uint64_t CardCapacity; /*!< Card capacity */ + uint32_t CardBlockSize; /*!< Card block size */ + uint16_t RCA; /*!< SD relative card address */ + uint8_t CardType; /*!< SD card type */ + +}HAL_SD_CardInfoTypedef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group6 SD Error status enumeration Structure definition + * @{ + */ +typedef enum +{ +/** + * @brief SD specific error defines + */ + SD_CMD_CRC_FAIL = (1), /*!< Command response received (but CRC check failed) */ + SD_DATA_CRC_FAIL = (2), /*!< Data block sent/received (CRC check failed) */ + SD_CMD_RSP_TIMEOUT = (3), /*!< Command response timeout */ + SD_DATA_TIMEOUT = (4), /*!< Data timeout */ + SD_TX_UNDERRUN = (5), /*!< Transmit FIFO underrun */ + SD_RX_OVERRUN = (6), /*!< Receive FIFO overrun */ + SD_START_BIT_ERR = (7), /*!< Start bit not detected on all data signals in wide bus mode */ + SD_CMD_OUT_OF_RANGE = (8), /*!< Command's argument was out of range. */ + SD_ADDR_MISALIGNED = (9), /*!< Misaligned address */ + SD_BLOCK_LEN_ERR = (10), /*!< Transferred block length is not allowed for the card or the number of transferred bytes does not match the block length */ + SD_ERASE_SEQ_ERR = (11), /*!< An error in the sequence of erase command occurs. */ + SD_BAD_ERASE_PARAM = (12), /*!< An invalid selection for erase groups */ + SD_WRITE_PROT_VIOLATION = (13), /*!< Attempt to program a write protect block */ + SD_LOCK_UNLOCK_FAILED = (14), /*!< Sequence or password error has been detected in unlock command or if there was an attempt to access a locked card */ + SD_COM_CRC_FAILED = (15), /*!< CRC check of the previous command failed */ + SD_ILLEGAL_CMD = (16), /*!< Command is not legal for the card state */ + SD_CARD_ECC_FAILED = (17), /*!< Card internal ECC was applied but failed to correct the data */ + SD_CC_ERROR = (18), /*!< Internal card controller error */ + SD_GENERAL_UNKNOWN_ERROR = (19), /*!< General or unknown error */ + SD_STREAM_READ_UNDERRUN = (20), /*!< The card could not sustain data transfer in stream read operation. */ + SD_STREAM_WRITE_OVERRUN = (21), /*!< The card could not sustain data programming in stream mode */ + SD_CID_CSD_OVERWRITE = (22), /*!< CID/CSD overwrite error */ + SD_WP_ERASE_SKIP = (23), /*!< Only partial address space was erased */ + SD_CARD_ECC_DISABLED = (24), /*!< Command has been executed without using internal ECC */ + SD_ERASE_RESET = (25), /*!< Erase sequence was cleared before executing because an out of erase sequence command was received */ + SD_AKE_SEQ_ERROR = (26), /*!< Error in sequence of authentication. */ + SD_INVALID_VOLTRANGE = (27), + SD_ADDR_OUT_OF_RANGE = (28), + SD_SWITCH_ERROR = (29), + SD_SDIO_DISABLED = (30), + SD_SDIO_FUNCTION_BUSY = (31), + SD_SDIO_FUNCTION_FAILED = (32), + SD_SDIO_UNKNOWN_FUNCTION = (33), + +/** + * @brief Standard error defines + */ + SD_INTERNAL_ERROR = (34), + SD_NOT_CONFIGURED = (35), + SD_REQUEST_PENDING = (36), + SD_REQUEST_NOT_APPLICABLE = (37), + SD_INVALID_PARAMETER = (38), + SD_UNSUPPORTED_FEATURE = (39), + SD_UNSUPPORTED_HW = (40), + SD_ERROR = (41), + SD_OK = (0) + +}HAL_SD_ErrorTypedef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group7 SD Transfer state enumeration structure + * @{ + */ +typedef enum +{ + SD_TRANSFER_OK = 0, /*!< Transfer success */ + SD_TRANSFER_BUSY = 1, /*!< Transfer is occurring */ + SD_TRANSFER_ERROR = 2 /*!< Transfer failed */ + +}HAL_SD_TransferStateTypedef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group8 SD Card State enumeration structure + * @{ + */ +typedef enum +{ + SD_CARD_READY = ((uint32_t)0x00000001), /*!< Card state is ready */ + SD_CARD_IDENTIFICATION = ((uint32_t)0x00000002), /*!< Card is in identification state */ + SD_CARD_STANDBY = ((uint32_t)0x00000003), /*!< Card is in standby state */ + SD_CARD_TRANSFER = ((uint32_t)0x00000004), /*!< Card is in transfer state */ + SD_CARD_SENDING = ((uint32_t)0x00000005), /*!< Card is sending an operation */ + SD_CARD_RECEIVING = ((uint32_t)0x00000006), /*!< Card is receiving operation information */ + SD_CARD_PROGRAMMING = ((uint32_t)0x00000007), /*!< Card is in programming state */ + SD_CARD_DISCONNECTED = ((uint32_t)0x00000008), /*!< Card is disconnected */ + SD_CARD_ERROR = ((uint32_t)0x000000FF) /*!< Card is in error state */ + +}HAL_SD_CardStateTypedef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group9 SD Operation enumeration structure + * @{ + */ +typedef enum +{ + SD_READ_SINGLE_BLOCK = 0, /*!< Read single block operation */ + SD_READ_MULTIPLE_BLOCK = 1, /*!< Read multiple blocks operation */ + SD_WRITE_SINGLE_BLOCK = 2, /*!< Write single block operation */ + SD_WRITE_MULTIPLE_BLOCK = 3 /*!< Write multiple blocks operation */ + +}HAL_SD_OperationTypedef; +/** + * @} + */ + +/** + * @} + */ + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup SD_Exported_Constants SD Exported Constants + * @{ + */ + +/** + * @brief SD Commands Index + */ +#define SD_CMD_GO_IDLE_STATE ((uint8_t)0) /*!< Resets the SD memory card. */ +#define SD_CMD_SEND_OP_COND ((uint8_t)1) /*!< Sends host capacity support information and activates the card's initialization process. */ +#define SD_CMD_ALL_SEND_CID ((uint8_t)2) /*!< Asks any card connected to the host to send the CID numbers on the CMD line. */ +#define SD_CMD_SET_REL_ADDR ((uint8_t)3) /*!< Asks the card to publish a new relative address (RCA). */ +#define SD_CMD_SET_DSR ((uint8_t)4) /*!< Programs the DSR of all cards. */ +#define SD_CMD_SDIO_SEN_OP_COND ((uint8_t)5) /*!< Sends host capacity support information (HCS) and asks the accessed card to send its + operating condition register (OCR) content in the response on the CMD line. */ +#define SD_CMD_HS_SWITCH ((uint8_t)6) /*!< Checks switchable function (mode 0) and switch card function (mode 1). */ +#define SD_CMD_SEL_DESEL_CARD ((uint8_t)7) /*!< Selects the card by its own relative address and gets deselected by any other address */ +#define SD_CMD_HS_SEND_EXT_CSD ((uint8_t)8) /*!< Sends SD Memory Card interface condition, which includes host supply voltage information + and asks the card whether card supports voltage. */ +#define SD_CMD_SEND_CSD ((uint8_t)9) /*!< Addressed card sends its card specific data (CSD) on the CMD line. */ +#define SD_CMD_SEND_CID ((uint8_t)10) /*!< Addressed card sends its card identification (CID) on the CMD line. */ +#define SD_CMD_READ_DAT_UNTIL_STOP ((uint8_t)11) /*!< SD card doesn't support it. */ +#define SD_CMD_STOP_TRANSMISSION ((uint8_t)12) /*!< Forces the card to stop transmission. */ +#define SD_CMD_SEND_STATUS ((uint8_t)13) /*!< Addressed card sends its status register. */ +#define SD_CMD_HS_BUSTEST_READ ((uint8_t)14) +#define SD_CMD_GO_INACTIVE_STATE ((uint8_t)15) /*!< Sends an addressed card into the inactive state. */ +#define SD_CMD_SET_BLOCKLEN ((uint8_t)16) /*!< Sets the block length (in bytes for SDSC) for all following block commands + (read, write, lock). Default block length is fixed to 512 Bytes. Not effective + for SDHS and SDXC. */ +#define SD_CMD_READ_SINGLE_BLOCK ((uint8_t)17) /*!< Reads single block of size selected by SET_BLOCKLEN in case of SDSC, and a block of + fixed 512 bytes in case of SDHC and SDXC. */ +#define SD_CMD_READ_MULT_BLOCK ((uint8_t)18) /*!< Continuously transfers data blocks from card to host until interrupted by + STOP_TRANSMISSION command. */ +#define SD_CMD_HS_BUSTEST_WRITE ((uint8_t)19) /*!< 64 bytes tuning pattern is sent for SDR50 and SDR104. */ +#define SD_CMD_WRITE_DAT_UNTIL_STOP ((uint8_t)20) /*!< Speed class control command. */ +#define SD_CMD_SET_BLOCK_COUNT ((uint8_t)23) /*!< Specify block count for CMD18 and CMD25. */ +#define SD_CMD_WRITE_SINGLE_BLOCK ((uint8_t)24) /*!< Writes single block of size selected by SET_BLOCKLEN in case of SDSC, and a block of + fixed 512 bytes in case of SDHC and SDXC. */ +#define SD_CMD_WRITE_MULT_BLOCK ((uint8_t)25) /*!< Continuously writes blocks of data until a STOP_TRANSMISSION follows. */ +#define SD_CMD_PROG_CID ((uint8_t)26) /*!< Reserved for manufacturers. */ +#define SD_CMD_PROG_CSD ((uint8_t)27) /*!< Programming of the programmable bits of the CSD. */ +#define SD_CMD_SET_WRITE_PROT ((uint8_t)28) /*!< Sets the write protection bit of the addressed group. */ +#define SD_CMD_CLR_WRITE_PROT ((uint8_t)29) /*!< Clears the write protection bit of the addressed group. */ +#define SD_CMD_SEND_WRITE_PROT ((uint8_t)30) /*!< Asks the card to send the status of the write protection bits. */ +#define SD_CMD_SD_ERASE_GRP_START ((uint8_t)32) /*!< Sets the address of the first write block to be erased. (For SD card only). */ +#define SD_CMD_SD_ERASE_GRP_END ((uint8_t)33) /*!< Sets the address of the last write block of the continuous range to be erased. */ +#define SD_CMD_ERASE_GRP_START ((uint8_t)35) /*!< Sets the address of the first write block to be erased. Reserved for each command + system set by switch function command (CMD6). */ +#define SD_CMD_ERASE_GRP_END ((uint8_t)36) /*!< Sets the address of the last write block of the continuous range to be erased. + Reserved for each command system set by switch function command (CMD6). */ +#define SD_CMD_ERASE ((uint8_t)38) /*!< Reserved for SD security applications. */ +#define SD_CMD_FAST_IO ((uint8_t)39) /*!< SD card doesn't support it (Reserved). */ +#define SD_CMD_GO_IRQ_STATE ((uint8_t)40) /*!< SD card doesn't support it (Reserved). */ +#define SD_CMD_LOCK_UNLOCK ((uint8_t)42) /*!< Sets/resets the password or lock/unlock the card. The size of the data block is set by + the SET_BLOCK_LEN command. */ +#define SD_CMD_APP_CMD ((uint8_t)55) /*!< Indicates to the card that the next command is an application specific command rather + than a standard command. */ +#define SD_CMD_GEN_CMD ((uint8_t)56) /*!< Used either to transfer a data block to the card or to get a data block from the card + for general purpose/application specific commands. */ +#define SD_CMD_NO_CMD ((uint8_t)64) + +/** + * @brief Following commands are SD Card Specific commands. + * SDIO_APP_CMD should be sent before sending these commands. + */ +#define SD_CMD_APP_SD_SET_BUSWIDTH ((uint8_t)6) /*!< (ACMD6) Defines the data bus width to be used for data transfer. The allowed data bus + widths are given in SCR register. */ +#define SD_CMD_SD_APP_STATUS ((uint8_t)13) /*!< (ACMD13) Sends the SD status. */ +#define SD_CMD_SD_APP_SEND_NUM_WRITE_BLOCKS ((uint8_t)22) /*!< (ACMD22) Sends the number of the written (without errors) write blocks. Responds with + 32bit+CRC data block. */ +#define SD_CMD_SD_APP_OP_COND ((uint8_t)41) /*!< (ACMD41) Sends host capacity support information (HCS) and asks the accessed card to + send its operating condition register (OCR) content in the response on the CMD line. */ +#define SD_CMD_SD_APP_SET_CLR_CARD_DETECT ((uint8_t)42) /*!< (ACMD42) Connects/Disconnects the 50 KOhm pull-up resistor on CD/DAT3 (pin 1) of the card. */ +#define SD_CMD_SD_APP_SEND_SCR ((uint8_t)51) /*!< Reads the SD Configuration Register (SCR). */ +#define SD_CMD_SDIO_RW_DIRECT ((uint8_t)52) /*!< For SD I/O card only, reserved for security specification. */ +#define SD_CMD_SDIO_RW_EXTENDED ((uint8_t)53) /*!< For SD I/O card only, reserved for security specification. */ + +/** + * @brief Following commands are SD Card Specific security commands. + * SD_CMD_APP_CMD should be sent before sending these commands. + */ +#define SD_CMD_SD_APP_GET_MKB ((uint8_t)43) /*!< For SD card only */ +#define SD_CMD_SD_APP_GET_MID ((uint8_t)44) /*!< For SD card only */ +#define SD_CMD_SD_APP_SET_CER_RN1 ((uint8_t)45) /*!< For SD card only */ +#define SD_CMD_SD_APP_GET_CER_RN2 ((uint8_t)46) /*!< For SD card only */ +#define SD_CMD_SD_APP_SET_CER_RES2 ((uint8_t)47) /*!< For SD card only */ +#define SD_CMD_SD_APP_GET_CER_RES1 ((uint8_t)48) /*!< For SD card only */ +#define SD_CMD_SD_APP_SECURE_READ_MULTIPLE_BLOCK ((uint8_t)18) /*!< For SD card only */ +#define SD_CMD_SD_APP_SECURE_WRITE_MULTIPLE_BLOCK ((uint8_t)25) /*!< For SD card only */ +#define SD_CMD_SD_APP_SECURE_ERASE ((uint8_t)38) /*!< For SD card only */ +#define SD_CMD_SD_APP_CHANGE_SECURE_AREA ((uint8_t)49) /*!< For SD card only */ +#define SD_CMD_SD_APP_SECURE_WRITE_MKB ((uint8_t)48) /*!< For SD card only */ + +/** + * @brief Supported SD Memory Cards + */ +#define STD_CAPACITY_SD_CARD_V1_1 ((uint32_t)0x00000000) +#define STD_CAPACITY_SD_CARD_V2_0 ((uint32_t)0x00000001) +#define HIGH_CAPACITY_SD_CARD ((uint32_t)0x00000002) +#define MULTIMEDIA_CARD ((uint32_t)0x00000003) +#define SECURE_DIGITAL_IO_CARD ((uint32_t)0x00000004) +#define HIGH_SPEED_MULTIMEDIA_CARD ((uint32_t)0x00000005) +#define SECURE_DIGITAL_IO_COMBO_CARD ((uint32_t)0x00000006) +#define HIGH_CAPACITY_MMC_CARD ((uint32_t)0x00000007) +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/** @defgroup SD_Exported_macros SD Exported Macros + * @brief macros to handle interrupts and specific clock configurations + * @{ + */ + +/** + * @brief Enable the SD device. + * @retval None + */ +#define __HAL_SD_SDIO_ENABLE() __SDIO_ENABLE() + +/** + * @brief Disable the SD device. + * @retval None + */ +#define __HAL_SD_SDIO_DISABLE() __SDIO_DISABLE() + +/** + * @brief Enable the SDIO DMA transfer. + * @retval None + */ +#define __HAL_SD_SDIO_DMA_ENABLE() __SDIO_DMA_ENABLE() + +/** + * @brief Disable the SDIO DMA transfer. + * @retval None + */ +#define __HAL_SD_SDIO_DMA_DISABLE() __SDIO_DMA_DISABLE() + +/** + * @brief Enable the SD device interrupt. + * @param __HANDLE__: SD Handle + * @param __INTERRUPT__: specifies the SDIO interrupt sources to be enabled. + * This parameter can be one or a combination of the following values: + * @arg SDIO_IT_CCRCFAIL: Command response received (CRC check failed) interrupt + * @arg SDIO_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt + * @arg SDIO_IT_CTIMEOUT: Command response timeout interrupt + * @arg SDIO_IT_DTIMEOUT: Data timeout interrupt + * @arg SDIO_IT_TXUNDERR: Transmit FIFO underrun error interrupt + * @arg SDIO_IT_RXOVERR: Received FIFO overrun error interrupt + * @arg SDIO_IT_CMDREND: Command response received (CRC check passed) interrupt + * @arg SDIO_IT_CMDSENT: Command sent (no response required) interrupt + * @arg SDIO_IT_DATAEND: Data end (data counter, SDIDCOUNT, is zero) interrupt + * @arg SDIO_IT_STBITERR: Start bit not detected on all data signals in wide + * bus mode interrupt + * @arg SDIO_IT_DBCKEND: Data block sent/received (CRC check passed) interrupt + * @arg SDIO_IT_CMDACT: Command transfer in progress interrupt + * @arg SDIO_IT_TXACT: Data transmit in progress interrupt + * @arg SDIO_IT_RXACT: Data receive in progress interrupt + * @arg SDIO_IT_TXFIFOHE: Transmit FIFO Half Empty interrupt + * @arg SDIO_IT_RXFIFOHF: Receive FIFO Half Full interrupt + * @arg SDIO_IT_TXFIFOF: Transmit FIFO full interrupt + * @arg SDIO_IT_RXFIFOF: Receive FIFO full interrupt + * @arg SDIO_IT_TXFIFOE: Transmit FIFO empty interrupt + * @arg SDIO_IT_RXFIFOE: Receive FIFO empty interrupt + * @arg SDIO_IT_TXDAVL: Data available in transmit FIFO interrupt + * @arg SDIO_IT_RXDAVL: Data available in receive FIFO interrupt + * @arg SDIO_IT_SDIOIT: SD I/O interrupt received interrupt + * @arg SDIO_IT_CEATAEND: CE-ATA command completion signal received for CMD61 interrupt + * @retval None + */ +#define __HAL_SD_SDIO_ENABLE_IT(__HANDLE__, __INTERRUPT__) __SDIO_ENABLE_IT((__HANDLE__)->Instance, (__INTERRUPT__)) + +/** + * @brief Disable the SD device interrupt. + * @param __HANDLE__: SD Handle + * @param __INTERRUPT__: specifies the SDIO interrupt sources to be disabled. + * This parameter can be one or a combination of the following values: + * @arg SDIO_IT_CCRCFAIL: Command response received (CRC check failed) interrupt + * @arg SDIO_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt + * @arg SDIO_IT_CTIMEOUT: Command response timeout interrupt + * @arg SDIO_IT_DTIMEOUT: Data timeout interrupt + * @arg SDIO_IT_TXUNDERR: Transmit FIFO underrun error interrupt + * @arg SDIO_IT_RXOVERR: Received FIFO overrun error interrupt + * @arg SDIO_IT_CMDREND: Command response received (CRC check passed) interrupt + * @arg SDIO_IT_CMDSENT: Command sent (no response required) interrupt + * @arg SDIO_IT_DATAEND: Data end (data counter, SDIDCOUNT, is zero) interrupt + * @arg SDIO_IT_STBITERR: Start bit not detected on all data signals in wide + * bus mode interrupt + * @arg SDIO_IT_DBCKEND: Data block sent/received (CRC check passed) interrupt + * @arg SDIO_IT_CMDACT: Command transfer in progress interrupt + * @arg SDIO_IT_TXACT: Data transmit in progress interrupt + * @arg SDIO_IT_RXACT: Data receive in progress interrupt + * @arg SDIO_IT_TXFIFOHE: Transmit FIFO Half Empty interrupt + * @arg SDIO_IT_RXFIFOHF: Receive FIFO Half Full interrupt + * @arg SDIO_IT_TXFIFOF: Transmit FIFO full interrupt + * @arg SDIO_IT_RXFIFOF: Receive FIFO full interrupt + * @arg SDIO_IT_TXFIFOE: Transmit FIFO empty interrupt + * @arg SDIO_IT_RXFIFOE: Receive FIFO empty interrupt + * @arg SDIO_IT_TXDAVL: Data available in transmit FIFO interrupt + * @arg SDIO_IT_RXDAVL: Data available in receive FIFO interrupt + * @arg SDIO_IT_SDIOIT: SD I/O interrupt received interrupt + * @arg SDIO_IT_CEATAEND: CE-ATA command completion signal received for CMD61 interrupt + * @retval None + */ +#define __HAL_SD_SDIO_DISABLE_IT(__HANDLE__, __INTERRUPT__) __SDIO_DISABLE_IT((__HANDLE__)->Instance, (__INTERRUPT__)) + +/** + * @brief Check whether the specified SD flag is set or not. + * @param __HANDLE__: SD Handle + * @param __FLAG__: specifies the flag to check. + * This parameter can be one of the following values: + * @arg SDIO_FLAG_CCRCFAIL: Command response received (CRC check failed) + * @arg SDIO_FLAG_DCRCFAIL: Data block sent/received (CRC check failed) + * @arg SDIO_FLAG_CTIMEOUT: Command response timeout + * @arg SDIO_FLAG_DTIMEOUT: Data timeout + * @arg SDIO_FLAG_TXUNDERR: Transmit FIFO underrun error + * @arg SDIO_FLAG_RXOVERR: Received FIFO overrun error + * @arg SDIO_FLAG_CMDREND: Command response received (CRC check passed) + * @arg SDIO_FLAG_CMDSENT: Command sent (no response required) + * @arg SDIO_FLAG_DATAEND: Data end (data counter, SDIDCOUNT, is zero) + * @arg SDIO_FLAG_STBITERR: Start bit not detected on all data signals in wide bus mode. + * @arg SDIO_FLAG_DBCKEND: Data block sent/received (CRC check passed) + * @arg SDIO_FLAG_CMDACT: Command transfer in progress + * @arg SDIO_FLAG_TXACT: Data transmit in progress + * @arg SDIO_FLAG_RXACT: Data receive in progress + * @arg SDIO_FLAG_TXFIFOHE: Transmit FIFO Half Empty + * @arg SDIO_FLAG_RXFIFOHF: Receive FIFO Half Full + * @arg SDIO_FLAG_TXFIFOF: Transmit FIFO full + * @arg SDIO_FLAG_RXFIFOF: Receive FIFO full + * @arg SDIO_FLAG_TXFIFOE: Transmit FIFO empty + * @arg SDIO_FLAG_RXFIFOE: Receive FIFO empty + * @arg SDIO_FLAG_TXDAVL: Data available in transmit FIFO + * @arg SDIO_FLAG_RXDAVL: Data available in receive FIFO + * @arg SDIO_FLAG_SDIOIT: SD I/O interrupt received + * @arg SDIO_FLAG_CEATAEND: CE-ATA command completion signal received for CMD61 + * @retval The new state of SD FLAG (SET or RESET). + */ +#define __HAL_SD_SDIO_GET_FLAG(__HANDLE__, __FLAG__) __SDIO_GET_FLAG((__HANDLE__)->Instance, (__FLAG__)) + +/** + * @brief Clear the SD's pending flags. + * @param __HANDLE__: SD Handle + * @param __FLAG__: specifies the flag to clear. + * This parameter can be one or a combination of the following values: + * @arg SDIO_FLAG_CCRCFAIL: Command response received (CRC check failed) + * @arg SDIO_FLAG_DCRCFAIL: Data block sent/received (CRC check failed) + * @arg SDIO_FLAG_CTIMEOUT: Command response timeout + * @arg SDIO_FLAG_DTIMEOUT: Data timeout + * @arg SDIO_FLAG_TXUNDERR: Transmit FIFO underrun error + * @arg SDIO_FLAG_RXOVERR: Received FIFO overrun error + * @arg SDIO_FLAG_CMDREND: Command response received (CRC check passed) + * @arg SDIO_FLAG_CMDSENT: Command sent (no response required) + * @arg SDIO_FLAG_DATAEND: Data end (data counter, SDIDCOUNT, is zero) + * @arg SDIO_FLAG_STBITERR: Start bit not detected on all data signals in wide bus mode + * @arg SDIO_FLAG_DBCKEND: Data block sent/received (CRC check passed) + * @arg SDIO_FLAG_SDIOIT: SD I/O interrupt received + * @arg SDIO_FLAG_CEATAEND: CE-ATA command completion signal received for CMD61 + * @retval None + */ +#define __HAL_SD_SDIO_CLEAR_FLAG(__HANDLE__, __FLAG__) __SDIO_CLEAR_FLAG((__HANDLE__)->Instance, (__FLAG__)) + +/** + * @brief Check whether the specified SD interrupt has occurred or not. + * @param __HANDLE__: SD Handle + * @param __INTERRUPT__: specifies the SDIO interrupt source to check. + * This parameter can be one of the following values: + * @arg SDIO_IT_CCRCFAIL: Command response received (CRC check failed) interrupt + * @arg SDIO_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt + * @arg SDIO_IT_CTIMEOUT: Command response timeout interrupt + * @arg SDIO_IT_DTIMEOUT: Data timeout interrupt + * @arg SDIO_IT_TXUNDERR: Transmit FIFO underrun error interrupt + * @arg SDIO_IT_RXOVERR: Received FIFO overrun error interrupt + * @arg SDIO_IT_CMDREND: Command response received (CRC check passed) interrupt + * @arg SDIO_IT_CMDSENT: Command sent (no response required) interrupt + * @arg SDIO_IT_DATAEND: Data end (data counter, SDIDCOUNT, is zero) interrupt + * @arg SDIO_IT_STBITERR: Start bit not detected on all data signals in wide + * bus mode interrupt + * @arg SDIO_IT_DBCKEND: Data block sent/received (CRC check passed) interrupt + * @arg SDIO_IT_CMDACT: Command transfer in progress interrupt + * @arg SDIO_IT_TXACT: Data transmit in progress interrupt + * @arg SDIO_IT_RXACT: Data receive in progress interrupt + * @arg SDIO_IT_TXFIFOHE: Transmit FIFO Half Empty interrupt + * @arg SDIO_IT_RXFIFOHF: Receive FIFO Half Full interrupt + * @arg SDIO_IT_TXFIFOF: Transmit FIFO full interrupt + * @arg SDIO_IT_RXFIFOF: Receive FIFO full interrupt + * @arg SDIO_IT_TXFIFOE: Transmit FIFO empty interrupt + * @arg SDIO_IT_RXFIFOE: Receive FIFO empty interrupt + * @arg SDIO_IT_TXDAVL: Data available in transmit FIFO interrupt + * @arg SDIO_IT_RXDAVL: Data available in receive FIFO interrupt + * @arg SDIO_IT_SDIOIT: SD I/O interrupt received interrupt + * @arg SDIO_IT_CEATAEND: CE-ATA command completion signal received for CMD61 interrupt + * @retval The new state of SD IT (SET or RESET). + */ +#define __HAL_SD_SDIO_GET_IT (__HANDLE__, __INTERRUPT__) __SDIO_GET_IT ((__HANDLE__)->Instance, __INTERRUPT__) + +/** + * @brief Clear the SD's interrupt pending bits. + * @param __HANDLE__ : SD Handle + * @param __INTERRUPT__: specifies the interrupt pending bit to clear. + * This parameter can be one or a combination of the following values: + * @arg SDIO_IT_CCRCFAIL: Command response received (CRC check failed) interrupt + * @arg SDIO_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt + * @arg SDIO_IT_CTIMEOUT: Command response timeout interrupt + * @arg SDIO_IT_DTIMEOUT: Data timeout interrupt + * @arg SDIO_IT_TXUNDERR: Transmit FIFO underrun error interrupt + * @arg SDIO_IT_RXOVERR: Received FIFO overrun error interrupt + * @arg SDIO_IT_CMDREND: Command response received (CRC check passed) interrupt + * @arg SDIO_IT_CMDSENT: Command sent (no response required) interrupt + * @arg SDIO_IT_DATAEND: Data end (data counter, SDIO_DCOUNT, is zero) interrupt + * @arg SDIO_IT_STBITERR: Start bit not detected on all data signals in wide + * bus mode interrupt + * @arg SDIO_IT_SDIOIT: SD I/O interrupt received interrupt + * @arg SDIO_IT_CEATAEND: CE-ATA command completion signal received for CMD61 + * @retval None + */ +#define __HAL_SD_SDIO_CLEAR_IT(__HANDLE__, __INTERRUPT__) __SDIO_CLEAR_IT((__HANDLE__)->Instance, (__INTERRUPT__)) +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ +/** @defgroup SD_Exported_Functions SD Exported Functions + * @{ + */ + +/** @defgroup SD_Exported_Functions_Group1 Initialization and de-initialization functions + * @{ + */ +HAL_SD_ErrorTypedef HAL_SD_Init(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypedef *SDCardInfo); +HAL_StatusTypeDef HAL_SD_DeInit (SD_HandleTypeDef *hsd); +void HAL_SD_MspInit(SD_HandleTypeDef *hsd); +void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd); +/** + * @} + */ + +/** @defgroup SD_Exported_Functions_Group2 I/O operation functions + * @{ + */ +/* Blocking mode: Polling */ +HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks); +HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks); +HAL_SD_ErrorTypedef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint64_t startaddr, uint64_t endaddr); + +/* Non-Blocking mode: Interrupt */ +void HAL_SD_IRQHandler(SD_HandleTypeDef *hsd); + +/* Callback in non blocking modes (DMA) */ +void HAL_SD_DMA_RxCpltCallback(DMA_HandleTypeDef *hdma); +void HAL_SD_DMA_RxErrorCallback(DMA_HandleTypeDef *hdma); +void HAL_SD_DMA_TxCpltCallback(DMA_HandleTypeDef *hdma); +void HAL_SD_DMA_TxErrorCallback(DMA_HandleTypeDef *hdma); +void HAL_SD_XferCpltCallback(SD_HandleTypeDef *hsd); +void HAL_SD_XferErrorCallback(SD_HandleTypeDef *hsd); + +/* Non-Blocking mode: DMA */ +HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks); +HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks); +HAL_SD_ErrorTypedef HAL_SD_CheckWriteOperation(SD_HandleTypeDef *hsd, uint32_t Timeout); +HAL_SD_ErrorTypedef HAL_SD_CheckReadOperation(SD_HandleTypeDef *hsd, uint32_t Timeout); +/** + * @} + */ + +/** @defgroup SD_Exported_Functions_Group3 Peripheral Control functions + * @{ + */ +HAL_SD_ErrorTypedef HAL_SD_Get_CardInfo(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypedef *pCardInfo); +HAL_SD_ErrorTypedef HAL_SD_WideBusOperation_Config(SD_HandleTypeDef *hsd, uint32_t WideMode); +HAL_SD_ErrorTypedef HAL_SD_StopTransfer(SD_HandleTypeDef *hsd); +HAL_SD_ErrorTypedef HAL_SD_HighSpeed (SD_HandleTypeDef *hsd); +/** + * @} + */ + +/* Peripheral State functions ************************************************/ +/** @defgroup SD_Exported_Functions_Group4 Peripheral State functions + * @{ + */ +HAL_SD_ErrorTypedef HAL_SD_SendSDStatus(SD_HandleTypeDef *hsd, uint32_t *pSDstatus); +HAL_SD_ErrorTypedef HAL_SD_GetCardStatus(SD_HandleTypeDef *hsd, HAL_SD_CardStatusTypedef *pCardStatus); +HAL_SD_TransferStateTypedef HAL_SD_GetStatus(SD_HandleTypeDef *hsd); +/** + * @} + */ + +/** + * @} + */ + +/* Private types -------------------------------------------------------------*/ +/** @defgroup SD_Private_Types SD Private Types + * @{ + */ + +/** + * @} + */ + +/* Private defines -----------------------------------------------------------*/ +/** @defgroup SD_Private_Defines SD Private Defines + * @{ + */ + +/** + * @} + */ + +/* Private variables ---------------------------------------------------------*/ +/** @defgroup SD_Private_Variables SD Private Variables + * @{ + */ + +/** + * @} + */ + +/* Private constants ---------------------------------------------------------*/ +/** @defgroup SD_Private_Constants SD Private Constants + * @{ + */ + +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup SD_Private_Macros SD Private Macros + * @{ + */ + +/** + * @} + */ + +/* Private functions prototypes ----------------------------------------------*/ +/** @defgroup SD_Private_Functions_Prototypes SD Private Functions Prototypes + * @{ + */ + +/** + * @} + */ + +/* Private functions ---------------------------------------------------------*/ +/** @defgroup SD_Private_Functions SD Private Functions + * @{ + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F4xx_HAL_SD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/ff_sddisk.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/ff_sddisk.c new file mode 100644 index 000000000..35a95d22f --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/ff_sddisk.c @@ -0,0 +1,1204 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/* Standard includes. */ +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "portmacro.h" + +/* FreeRTOS+FAT includes. */ +#include "ff_sddisk.h" +#include "ff_sys.h" + +/* ST HAL includes. */ +#ifdef STM32F7xx + #include "stm32f7xx_hal.h" +#else + #include "stm32f4xx_hal.h" +#endif + +/* Misc definitions. */ +#define sdSIGNATURE 0x41404342UL +#define sdHUNDRED_64_BIT ( 100ull ) +#define sdBYTES_PER_MB ( 1024ull * 1024ull ) +#define sdSECTORS_PER_MB ( sdBYTES_PER_MB / 512ull ) +#define sdIOMAN_MEM_SIZE 4096 + +/* DMA constants. */ +#define SD_DMAx_Tx_CHANNEL DMA_CHANNEL_4 +#define SD_DMAx_Rx_CHANNEL DMA_CHANNEL_4 +#define SD_DMAx_Tx_STREAM DMA2_Stream6 +#define SD_DMAx_Rx_STREAM DMA2_Stream3 +#define SD_DMAx_Tx_IRQn DMA2_Stream6_IRQn +#define SD_DMAx_Rx_IRQn DMA2_Stream3_IRQn +#define __DMAx_TxRx_CLK_ENABLE __DMA2_CLK_ENABLE +#define configSDIO_DMA_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY ) + +/* Define a time-out for all DMA transactions in msec. */ +#ifndef sdMAX_TIME_TICKS + #define sdMAX_TIME_TICKS pdMS_TO_TICKS( 2000UL ) +#endif + +#ifndef configSD_DETECT_PIN + #error configSD_DETECT_PIN must be defined in FreeRTOSConfig.h to the pin used to detect if the SD card is present. +#endif + +#ifndef configSD_DETECT_GPIO_PORT + #error configSD_DETECT_GPIO_PORT must be defined in FreeRTOSConfig.h to the port on which configSD_DETECT_PIN is located. +#endif + +#ifndef sdCARD_DETECT_DEBOUNCE_TIME_MS + /* Debouncing time is applied only after card gets inserted. */ + #define sdCARD_DETECT_DEBOUNCE_TIME_MS ( 5000 ) +#endif + +#ifndef sdARRAY_SIZE + #define sdARRAY_SIZE( x ) ( int )( sizeof( x ) / sizeof( x )[ 0 ] ) +#endif + +#ifdef STM32F7xx + + /* This driver was originally developed for STM32F4xx. + With a few defines it can also be used for STM32F7xx : */ + /* The Instance of the MMC peripheral. */ + #define SDIO SDMMC1 + + #ifdef GPIO_AF12_SDIO + #undef GPIO_AF12_SDIO + #endif + #define GPIO_AF12_SDIO GPIO_AF12_SDMMC1 + + #define SDIO_CLOCK_EDGE_RISING SDMMC_CLOCK_EDGE_RISING + #define SDIO_CLOCK_BYPASS_DISABLE SDMMC_CLOCK_BYPASS_DISABLE + #define SDIO_CLOCK_POWER_SAVE_DISABLE SDMMC_CLOCK_POWER_SAVE_DISABLE + #define SDIO_BUS_WIDE_1B SDMMC_BUS_WIDE_1B + #define SDIO_BUS_WIDE_4B SDMMC_BUS_WIDE_4B + #define SDIO_HARDWARE_FLOW_CONTROL_DISABLE SDMMC_HARDWARE_FLOW_CONTROL_DISABLE + + + #define SD_SDIO_DISABLED SD_SDMMC_DISABLED + #define SD_SDIO_FUNCTION_BUSY SD_SDMMC_FUNCTION_BUSY + #define SD_SDIO_FUNCTION_FAILED SD_SDMMC_FUNCTION_FAILED + #define SD_SDIO_UNKNOWN_FUNCTION SD_SDMMC_UNKNOWN_FUNCTION + + #define SDIO_IRQn SDMMC1_IRQn + +#endif /* STM32F7xx */ + +/*-----------------------------------------------------------*/ + +/* + * Return pdFALSE if the SD card is not inserted. This function just reads the + * value of the GPIO C/D pin. + */ +static BaseType_t prvSDDetect( void ); + +/* + * Translate a numeric code like 'SD_TX_UNDERRUN' to a printable string. + */ +static const char *prvSDCodePrintable( uint32_t ulCode ); + +/* + * The following 'hook' must be provided by the user of this module. It will be + * called from a GPIO ISR after every change. Note that during the ISR, the + * value of the GPIO is not stable and it can not be used. All you can do from + * this hook is wake-up some task, which will call FF_SDDiskDetect(). + */ +extern void vApplicationCardDetectChangeHookFromISR( BaseType_t *pxHigherPriorityTaskWoken ); + +/* + * Hardware initialisation. + */ +static void prvSDIO_SD_Init( void ); +static void vGPIO_SD_Init( SD_HandleTypeDef* xSDHandle ); + +/* + * Check if the card is present, and if so, print out some info on the card. + */ +static BaseType_t prvSDMMCInit( BaseType_t xDriveNumber ); + +#if( SDIO_USES_DMA != 0 ) + /* + * Initialise the DMA for SDIO cards. + */ + static void prvSDIO_DMA_Init( void ); +#endif + +#if( SDIO_USES_DMA != 0 ) + /* + * A function will be called at the start of a DMA action. + */ + static void prvEventSetupFunction( SD_HandleTypeDef * pxHandle ); +#endif + +#if( SDIO_USES_DMA != 0 ) + /* + * This function is supposed to wait for an event: SDIO or DMA. + * Return non-zero if a timeout has been reached. + */ + static uint32_t prvEventWaitFunction( SD_HandleTypeDef *pxHandle ); +#endif + +#ifdef STM32F7xx + static void prvCacheClean( uint32_t *pulAddress, int32_t ulSize ); + static void prvCacheInvalidate( uint32_t *pulAddress, int32_t ulSize ); +#else + /* No cache: empty macro's. */ + #define prvCacheClean( pulAddress, ulSize ) do {} while ( 0 ) + #define prvCacheInvalidate( pulAddress, ulSize ) do {} while ( 0 ) +#endif + +/*-----------------------------------------------------------*/ + +typedef struct +{ + /* Only after a card has been inserted, debouncing is necessary. */ + TickType_t xRemainingTime; + TimeOut_t xTimeOut; + UBaseType_t + bLastPresent : 1, + bStableSignal : 1; +} CardDetect_t; + +/* Used to handle timeouts. */ +static TickType_t xDMARemainingTime; +static TimeOut_t xDMATimeOut; + +/* Used to unblock the task that calls prvEventWaitFunction() after an event has +occurred. */ +static SemaphoreHandle_t xSDCardSemaphore = NULL; + +/* Handle of the SD card being used. */ +static SD_HandleTypeDef xSDHandle; + +/* Holds parameters for the detected SD card. */ +static HAL_SD_CardInfoTypedef xSDCardInfo; + +/* Mutex for partition. */ +static SemaphoreHandle_t xPlusFATMutex = NULL; + +/* Remembers if the card is currently considered to be present. */ +static BaseType_t xSDCardStatus = pdFALSE; + +/* Maintains state for card detection. */ +static CardDetect_t xCardDetect; + +static __attribute__ ((section(".first_data"))) uint8_t pucDMABuffer[ 512 ] __attribute__ ( ( aligned( 32 ) ) ); + +/*-----------------------------------------------------------*/ + +static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ) +{ +int32_t lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG; + + if( ( pxDisk != NULL ) && + ( xSDCardStatus == pdPASS ) && + ( pxDisk->ulSignature == sdSIGNATURE ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( ulSectorNumber < pxDisk->ulNumberOfSectors ) && + ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) ) + { + uint64_t ullReadAddr; + HAL_SD_ErrorTypedef sd_result; + + ullReadAddr = 512ull * ( uint64_t ) ulSectorNumber; + + #if( SDIO_USES_DMA == 0 ) + { + sd_result = HAL_SD_ReadBlocks( &xSDHandle, (uint32_t *) pucBuffer, ullReadAddr, 512ul, ulSectorCount ); + } + #else + { + if( ( ( ( size_t )pucBuffer ) & 0x1Ful ) == 0ul ) + { + /* The buffer is word-aligned, call DMA read directly. */ + sd_result = HAL_SD_ReadBlocks_DMA( &xSDHandle, (uint32_t *) pucBuffer, ullReadAddr, 512ul, ulSectorCount); + if( sd_result == SD_OK ) + { + sd_result = HAL_SD_CheckReadOperation( &xSDHandle, sdMAX_TIME_TICKS ); + prvCacheInvalidate ( ( uint32_t * )pucBuffer, 512ul * ulSectorCount ); + } + } + else + { + uint32_t ulSector; + + /* The buffer is NOT word-aligned, copy first to an aligned buffer. */ + sd_result = SD_OK; + for( ulSector = 0; ulSector < ulSectorCount; ulSector++ ) + { + ullReadAddr = 512ull * ( ( uint64_t ) ulSectorNumber + ( uint64_t ) ulSector ); + sd_result = HAL_SD_ReadBlocks_DMA( &xSDHandle, ( uint32_t * )pucDMABuffer, ullReadAddr, 512ul, 1 ); + + if( sd_result == SD_OK ) + { + sd_result = HAL_SD_CheckReadOperation( &xSDHandle, sdMAX_TIME_TICKS ); + if( sd_result != SD_OK ) + { + break; + } + prvCacheInvalidate ( ( uint32_t * )pucDMABuffer, 512ul * 1 ); + memcpy( pucBuffer + 512ul * ulSector, pucDMABuffer, 512ul ); + } + } + } + } + #endif /* SDIO_USES_DMA */ + + if( sd_result == SD_OK ) + { + lReturnCode = 0L; + } + else + { + /* Some error occurred. */ + FF_PRINTF( "prvFFRead: %lu: %lu (%s)\n", ulSectorNumber, sd_result, prvSDCodePrintable( sd_result ) ); + } + } + else + { + /* Make sure no random data is in the returned buffer. */ + memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512UL ); + + if( pxDisk->xStatus.bIsInitialised != pdFALSE ) + { + FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors ); + } + } + + return lReturnCode; +} +/*-----------------------------------------------------------*/ + +static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ) +{ +int32_t lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG; + + if( ( pxDisk != NULL ) && + ( xSDCardStatus == pdPASS ) && + ( pxDisk->ulSignature == sdSIGNATURE ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( ulSectorNumber < pxDisk->ulNumberOfSectors ) && + ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) ) + { + HAL_SD_ErrorTypedef sd_result; + uint64_t ullWriteAddr; + ullWriteAddr = 512ull * ulSectorNumber; + + #if( SDIO_USES_DMA == 0 ) + { + sd_result = HAL_SD_WriteBlocks( &xSDHandle, ( uint32_t * )pucBuffer, ullWriteAddr, 512ul, ulSectorCount ); + } + #else + { + if( ( ( ( size_t )pucBuffer ) & 0x1Ful ) == 0ul ) + { + /* The buffer is word-aligned, call DMA reawrite directly. */ + prvCacheClean( ( uint32_t * )pucBuffer, 512ul * ulSectorCount ); + sd_result = HAL_SD_WriteBlocks_DMA( &xSDHandle, ( uint32_t * )pucBuffer, ullWriteAddr, 512ul, ulSectorCount ); + if( sd_result == SD_OK ) + { + sd_result = HAL_SD_CheckWriteOperation( &xSDHandle, sdMAX_TIME_TICKS ); + } + } + else + { + uint32_t ulSector; + + /* The buffer is NOT word-aligned, read to an aligned buffer and then + copy the data to the user provided buffer. */ + sd_result = SD_OK; + for( ulSector = 0; ulSector < ulSectorCount; ulSector++ ) + { + memcpy( pucDMABuffer, pucBuffer + 512ul * ulSector, 512ul ); + ullWriteAddr = 512ull * ( ulSectorNumber + ulSector ); + prvCacheClean( ( uint32_t * )pucDMABuffer, 512ul * 1ul ); + sd_result = HAL_SD_WriteBlocks_DMA( &xSDHandle, ( uint32_t * )pucDMABuffer, ullWriteAddr, 512ul, 1 ); + if( sd_result == SD_OK ) + { + sd_result = HAL_SD_CheckWriteOperation( &xSDHandle, sdMAX_TIME_TICKS ); + if( sd_result != SD_OK ) + { + break; + } + } + } + } + } + #endif /* SDIO_USES_DMA */ + + if( sd_result == SD_OK ) + { + /* No errors. */ + lReturnCode = 0L; + } + else + { + FF_PRINTF( "prvFFWrite: %lu: %lu (%s)\n", ulSectorNumber, sd_result, prvSDCodePrintable( sd_result ) ); + } + } + else + { + if( pxDisk->xStatus.bIsInitialised != pdFALSE ) + { + FF_PRINTF( "prvFFWrite: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors ); + } + } + + return lReturnCode; +} +/*-----------------------------------------------------------*/ + +#ifdef STM32F7xx + + static BaseType_t xIsCachable( uint32_t ulAddress ) + { + BaseType_t xReturn = pdFALSE; + + /* Is D-cache enabled? */ + if( ( SCB != NULL ) && ( ( SCB->CCR & (uint32_t)SCB_CCR_DC_Msk ) != 0ul ) ) + { + /* Is this a chacheable area? */ + if( ( ulAddress >= RAMDTCM_BASE + 0x10000 ) && ( ulAddress < RAMDTCM_BASE + 0x4CC00 ) ) + { + xReturn = pdTRUE; + } + } + return xReturn; + } +/*-----------------------------------------------------------*/ +#endif /* STM32F7xx */ + +#ifdef STM32F7xx + static void prvCacheClean( uint32_t *pulAddress, int32_t ulSize ) + { + if( xIsCachable( ( uint32_t ) pulAddress ) ) + { + SCB_CleanDCache_by_Addr( pulAddress, ulSize ); + } + } +/*-----------------------------------------------------------*/ +#endif /* STM32F7xx */ + +#ifdef STM32F7xx + static void prvCacheInvalidate( uint32_t *pulAddress, int32_t ulSize ) + { + if( xIsCachable( ( uint32_t ) pulAddress ) ) + { + SCB_InvalidateDCache_by_Addr( pulAddress, ulSize ); + } + } +/*-----------------------------------------------------------*/ +#endif /* STM32F7xx */ + +void FF_SDDiskFlush( FF_Disk_t *pxDisk ) +{ + if( ( pxDisk != NULL ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( pxDisk->pxIOManager != NULL ) ) + { + FF_FlushCache( pxDisk->pxIOManager ); + } +} +/*-----------------------------------------------------------*/ + +static void vGPIO_SD_Init(SD_HandleTypeDef* xSDHandle) +{ +GPIO_InitTypeDef GPIO_InitStruct; + + if( xSDHandle->Instance == SDIO ) + { + /* Peripheral clock enable */ + __SDIO_CLK_ENABLE(); + + /**SDIO GPIO Configuration + PC8 ------> SDIO_D0 + PC9 ------> SDIO_D1 + PC10 ------> SDIO_D2 + PC11 ------> SDIO_D3 + PC12 ------> SDIO_CK + PD2 ------> SDIO_CMD + */ + /* Enable SDIO clock */ + __HAL_RCC_SDMMC1_CLK_ENABLE(); + + /* Enable DMA2 clocks */ + __DMAx_TxRx_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + + /* GPIOC configuration */ + #if( BUS_4BITS != 0 ) + { + GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; + } + #else + { + GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_12; + } + #endif + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + + /* GPIOD configuration */ + GPIO_InitStruct.Pin = GPIO_PIN_2; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + + } +} +/*-----------------------------------------------------------*/ + +FF_Disk_t *FF_SDDiskInit( const char *pcName ) +{ +FF_Error_t xFFError; +BaseType_t xPartitionNumber = 0; +FF_CreationParameters_t xParameters; +FF_Disk_t *pxDisk; + + xSDCardStatus = prvSDMMCInit( 0 ); + + if( xSDCardStatus != pdPASS ) + { + FF_PRINTF( "FF_SDDiskInit: prvSDMMCInit failed\n" ); + pxDisk = NULL; + } + else + { + pxDisk = (FF_Disk_t *)ffconfigMALLOC( sizeof( *pxDisk ) ); + if( pxDisk == NULL ) + { + FF_PRINTF( "FF_SDDiskInit: Malloc failed\n" ); + } + else + { + /* Initialise the created disk structure. */ + memset( pxDisk, '\0', sizeof( *pxDisk ) ); + + pxDisk->ulNumberOfSectors = xSDCardInfo.CardCapacity / 512; + + if( xPlusFATMutex == NULL ) + { + xPlusFATMutex = xSemaphoreCreateRecursiveMutex(); + } + pxDisk->ulSignature = sdSIGNATURE; + + if( xPlusFATMutex != NULL) + { + memset( &xParameters, '\0', sizeof( xParameters ) ); + xParameters.ulMemorySize = sdIOMAN_MEM_SIZE; + xParameters.ulSectorSize = 512; + xParameters.fnWriteBlocks = prvFFWrite; + xParameters.fnReadBlocks = prvFFRead; + xParameters.pxDisk = pxDisk; + + /* prvFFRead()/prvFFWrite() are not re-entrant and must be + protected with the use of a semaphore. */ + xParameters.xBlockDeviceIsReentrant = pdFALSE; + + /* The semaphore will be used to protect critical sections in + the +FAT driver, and also to avoid concurrent calls to + prvFFRead()/prvFFWrite() from different tasks. */ + xParameters.pvSemaphore = ( void * ) xPlusFATMutex; + + pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError ); + + if( pxDisk->pxIOManager == NULL ) + { + FF_PRINTF( "FF_SDDiskInit: FF_CreateIOManger: %s\n", (const char*)FF_GetErrMessage( xFFError ) ); + FF_SDDiskDelete( pxDisk ); + pxDisk = NULL; + } + else + { + pxDisk->xStatus.bIsInitialised = pdTRUE; + pxDisk->xStatus.bPartitionNumber = xPartitionNumber; + if( FF_SDDiskMount( pxDisk ) == 0 ) + { + FF_SDDiskDelete( pxDisk ); + pxDisk = NULL; + } + else + { + if( pcName == NULL ) + { + pcName = "/"; + } + FF_FS_Add( pcName, pxDisk ); + FF_PRINTF( "FF_SDDiskInit: Mounted SD-card as root \"%s\"\n", pcName ); + FF_SDDiskShowPartition( pxDisk ); + } + } /* if( pxDisk->pxIOManager != NULL ) */ + } /* if( xPlusFATMutex != NULL) */ + } /* if( pxDisk != NULL ) */ + } /* if( xSDCardStatus == pdPASS ) */ + + return pxDisk; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskFormat( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber ) +{ +FF_Error_t xError; +BaseType_t xReturn = pdFAIL; + + xError = FF_Unmount( pxDisk ); + + if( FF_isERR( xError ) != pdFALSE ) + { + FF_PRINTF( "FF_SDDiskFormat: unmount fails: %08x\n", ( unsigned ) xError ); + } + else + { + /* Format the drive - try FAT32 with large clusters. */ + xError = FF_Format( pxDisk, xPartitionNumber, pdFALSE, pdFALSE); + + if( FF_isERR( xError ) ) + { + FF_PRINTF( "FF_SDDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) ); + } + else + { + FF_PRINTF( "FF_SDDiskFormat: OK, now remounting\n" ); + pxDisk->xStatus.bPartitionNumber = xPartitionNumber; + xError = FF_SDDiskMount( pxDisk ); + FF_PRINTF( "FF_SDDiskFormat: rc %08x\n", ( unsigned )xError ); + if( FF_isERR( xError ) == pdFALSE ) + { + xReturn = pdPASS; + FF_SDDiskShowPartition( pxDisk ); + } + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskUnmount( FF_Disk_t *pxDisk ) +{ +FF_Error_t xFFError; +BaseType_t xReturn = pdPASS; + + if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsMounted != pdFALSE ) ) + { + pxDisk->xStatus.bIsMounted = pdFALSE; + xFFError = FF_Unmount( pxDisk ); + + if( FF_isERR( xFFError ) ) + { + FF_PRINTF( "FF_SDDiskUnmount: rc %08x\n", ( unsigned )xFFError ); + xReturn = pdFAIL; + } + else + { + FF_PRINTF( "Drive unmounted\n" ); + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskReinit( FF_Disk_t *pxDisk ) +{ +BaseType_t xStatus = prvSDMMCInit( 0 ); /* Hard coded index. */ + + /*_RB_ parameter not used. */ + ( void ) pxDisk; + + FF_PRINTF( "FF_SDDiskReinit: rc %08x\n", ( unsigned ) xStatus ); + return xStatus; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskMount( FF_Disk_t *pxDisk ) +{ +FF_Error_t xFFError; +BaseType_t xReturn; + + /* Mount the partition */ + xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber ); + + if( FF_isERR( xFFError ) ) + { + FF_PRINTF( "FF_SDDiskMount: %08lX\n", xFFError ); + xReturn = pdFAIL; + } + else + { + pxDisk->xStatus.bIsMounted = pdTRUE; + FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors ); + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +FF_IOManager_t *sddisk_ioman( FF_Disk_t *pxDisk ) +{ +FF_IOManager_t *pxReturn; + + if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) ) + { + pxReturn = pxDisk->pxIOManager; + } + else + { + pxReturn = NULL; + } + return pxReturn; +} +/*-----------------------------------------------------------*/ + +/* Release all resources */ +BaseType_t FF_SDDiskDelete( FF_Disk_t *pxDisk ) +{ + if( pxDisk != NULL ) + { + pxDisk->ulSignature = 0; + pxDisk->xStatus.bIsInitialised = 0; + if( pxDisk->pxIOManager != NULL ) + { + if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE ) + { + FF_Unmount( pxDisk ); + } + FF_DeleteIOManager( pxDisk->pxIOManager ); + } + + vPortFree( pxDisk ); + } + return 1; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskShowPartition( FF_Disk_t *pxDisk ) +{ +FF_Error_t xError; +uint64_t ullFreeSectors; +uint32_t ulTotalSizeMB, ulFreeSizeMB; +int iPercentageFree; +FF_IOManager_t *pxIOManager; +const char *pcTypeName = "unknown type"; +BaseType_t xReturn = pdPASS; + + if( pxDisk == NULL ) + { + xReturn = pdFAIL; + } + else + { + pxIOManager = pxDisk->pxIOManager; + + FF_PRINTF( "Reading FAT and calculating Free Space\n" ); + + switch( pxIOManager->xPartition.ucType ) + { + case FF_T_FAT12: + pcTypeName = "FAT12"; + break; + + case FF_T_FAT16: + pcTypeName = "FAT16"; + break; + + case FF_T_FAT32: + pcTypeName = "FAT32"; + break; + + default: + pcTypeName = "UNKOWN"; + break; + } + + FF_GetFreeSize( pxIOManager, &xError ); + + ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster; + iPercentageFree = ( int ) ( ( sdHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) / + ( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) ); + + ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / sdSECTORS_PER_MB; + ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / sdSECTORS_PER_MB ); + + /* It is better not to use the 64-bit format such as %Lu because it + might not be implemented. */ + FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber ); + FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName ); + FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel ); + FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors ); + FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster ); + FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB ); + FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +/* SDIO init function */ +static void prvSDIO_SD_Init( void ) +{ + xSDHandle.Instance = SDIO; + xSDHandle.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; + xSDHandle.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; + xSDHandle.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; + + /* Start as a 1-bit bus and switch to 4-bits later on. */ + xSDHandle.Init.BusWide = SDIO_BUS_WIDE_1B; + + xSDHandle.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; + + /* Use fastest CLOCK at 0. */ + xSDHandle.Init.ClockDiv = 32; + + #if( SDIO_USES_DMA != 0 ) + { + xSDHandle.EventSetupFunction = prvEventSetupFunction; + xSDHandle.EventWaitFunction = prvEventWaitFunction; + } + #else + { + xSDHandle.EventSetupFunction = NULL; + xSDHandle.EventWaitFunction = NULL; + } + #endif + __HAL_RCC_SDIO_CLK_ENABLE( ); +} +/*-----------------------------------------------------------*/ + +/* This routine returns true if the SD-card is inserted. After insertion, it +will wait for sdCARD_DETECT_DEBOUNCE_TIME_MS before returning pdTRUE. */ +BaseType_t FF_SDDiskDetect( FF_Disk_t *pxDisk ) +{ +int xReturn; + + xReturn = prvSDDetect(); + + if( xReturn != pdFALSE ) + { + if( xCardDetect.bStableSignal == pdFALSE ) + { + /* The card seems to be present. */ + if( xCardDetect.bLastPresent == pdFALSE ) + { + xCardDetect.bLastPresent = pdTRUE; + xCardDetect.xRemainingTime = pdMS_TO_TICKS( ( TickType_t ) sdCARD_DETECT_DEBOUNCE_TIME_MS ); + /* Fetch the current time. */ + vTaskSetTimeOutState( &xCardDetect.xTimeOut ); + } + /* Has the timeout been reached? */ + if( xTaskCheckForTimeOut( &xCardDetect.xTimeOut, &xCardDetect.xRemainingTime ) != pdFALSE ) + { + xCardDetect.bStableSignal = pdTRUE; + } + else + { + /* keep returning false until de time-out is reached. */ + xReturn = pdFALSE; + } + } + } + else + { + xCardDetect.bLastPresent = pdFALSE; + xCardDetect.bStableSignal = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +/* Raw SD-card detection, just return the GPIO status. */ +static BaseType_t prvSDDetect( void ) +{ +int iReturn; + + /*!< Check GPIO to detect SD */ + if( HAL_GPIO_ReadPin( configSD_DETECT_GPIO_PORT, configSD_DETECT_PIN ) != 0 ) + { + /* The internal pull-up makes the signal high. */ + iReturn = pdFALSE; + } + else + { + /* The card will pull the GPIO signal down. */ + iReturn = pdTRUE; + } + + return iReturn; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvSDMMCInit( BaseType_t xDriveNumber ) +{ + /* 'xDriveNumber' not yet in use. */ + ( void )xDriveNumber; + + if( xSDCardSemaphore == NULL ) + { + xSDCardSemaphore = xSemaphoreCreateBinary(); + } + prvSDIO_SD_Init(); + + vGPIO_SD_Init( &xSDHandle ); + + #if( SDIO_USES_DMA != 0 ) + { + prvSDIO_DMA_Init( ); + } + #endif + + int SD_state = SD_OK; + /* Check if the SD card is plugged in the slot */ + if( prvSDDetect() == pdFALSE ) + { + FF_PRINTF( "No SD card detected\n" ); + return 0; + } + /* When starting up, skip debouncing of the Card Detect signal. */ + xCardDetect.bLastPresent = pdTRUE; + xCardDetect.bStableSignal = pdTRUE; + /* Initialise the SDIO device and read the card parameters. */ + SD_state = HAL_SD_Init( &xSDHandle, &xSDCardInfo ); + #if( BUS_4BITS != 0 ) + { + if( SD_state == SD_OK ) + { + HAL_SD_ErrorTypedef rc; + + xSDHandle.Init.BusWide = SDIO_BUS_WIDE_4B; + rc = HAL_SD_WideBusOperation_Config(&xSDHandle, SDIO_BUS_WIDE_4B); + if( rc != SD_OK ) + { + FF_PRINTF( "HAL_SD_WideBus: %d: %s\n", rc, prvSDCodePrintable( ( uint32_t )rc ) ); + } + } + } + #endif + FF_PRINTF( "HAL_SD_Init: %d: %s type: %s Capacity: %lu MB\n", + SD_state, prvSDCodePrintable( ( uint32_t )SD_state ), + xSDHandle.CardType == HIGH_CAPACITY_SD_CARD ? "SDHC" : "SD", + xSDCardInfo.CardCapacity / ( 1024 * 1024 ) ); + + return SD_state == SD_OK ? 1 : 0; +} +/*-----------------------------------------------------------*/ + +struct xCODE_NAME +{ + uint32_t ulValue; + const char *pcName; +}; + +const struct xCODE_NAME xSD_CODES[] = +{ + { SD_CMD_CRC_FAIL, "CMD_CRC_FAIL: Command response received (but CRC check failed)" }, + { SD_DATA_CRC_FAIL, "DATA_CRC_FAIL: Data block sent/received (CRC check failed)" }, + { SD_CMD_RSP_TIMEOUT, "CMD_RSP_TIMEOUT: Command response timeout" }, + { SD_DATA_TIMEOUT, "DATA_TIMEOUT: Data timeout" }, + { SD_TX_UNDERRUN, "TX_UNDERRUN: Transmit FIFO underrun" }, + { SD_RX_OVERRUN, "RX_OVERRUN: Receive FIFO overrun" }, + { SD_START_BIT_ERR, "START_BIT_ERR: Start bit not detected on all data signals in wide bus mode" }, + { SD_CMD_OUT_OF_RANGE, "CMD_OUT_OF_RANGE: Command's argument was out of range" }, + { SD_ADDR_MISALIGNED, "ADDR_MISALIGNED: Misaligned address" }, + { SD_BLOCK_LEN_ERR, "BLOCK_LEN_ERR: Transferred block length is not allowed for the card or the number of transferred bytes does not match the block length" }, + { SD_ERASE_SEQ_ERR, "ERASE_SEQ_ERR: An error in the sequence of erase command occurs." }, + { SD_BAD_ERASE_PARAM, "BAD_ERASE_PARAM: An invalid selection for erase groups" }, + { SD_WRITE_PROT_VIOLATION, "WRITE_PROT_VIOLATION: Attempt to program a write protect block" }, + { SD_LOCK_UNLOCK_FAILED, "LOCK_UNLOCK_FAILED: Sequence or password error has been detected in unlock command or if there was an attempt to access a locked card" }, + { SD_COM_CRC_FAILED, "COM_CRC_FAILED: CRC check of the previous command failed" }, + { SD_ILLEGAL_CMD, "ILLEGAL_CMD: Command is not legal for the card state" }, + { SD_CARD_ECC_FAILED, "CARD_ECC_FAILED: Card internal ECC was applied but failed to correct the data" }, + { SD_CC_ERROR, "CC_ERROR: Internal card controller error" }, + { SD_GENERAL_UNKNOWN_ERROR, "GENERAL_UNKNOWN_ERROR: General or unknown error" }, + { SD_STREAM_READ_UNDERRUN, "STREAM_READ_UNDERRUN: The card could not sustain data transfer in stream read operation" }, + { SD_STREAM_WRITE_OVERRUN, "STREAM_WRITE_OVERRUN: The card could not sustain data programming in stream mode" }, + { SD_CID_CSD_OVERWRITE, "CID_CSD_OVERWRITE: CID/CSD overwrite error" }, + { SD_WP_ERASE_SKIP, "WP_ERASE_SKIP: Only partial address space was erased" }, + { SD_CARD_ECC_DISABLED, "CARD_ECC_DISABLED: Command has been executed without using internal ECC" }, + { SD_ERASE_RESET, "ERASE_RESET: Erase sequence was cleared before executing because an out of erase sequence command was received" }, + { SD_AKE_SEQ_ERROR, "AKE_SEQ_ERROR: Error in sequence of authentication" }, + { SD_INVALID_VOLTRANGE, "INVALID_VOLTRANGE" }, + { SD_ADDR_OUT_OF_RANGE, "ADDR_OUT_OF_RANGE" }, + { SD_SWITCH_ERROR, "SWITCH_ERROR" }, + { SD_SDIO_DISABLED, "SDIO_DISABLED" }, + { SD_SDIO_FUNCTION_BUSY, "SDIO_FUNCTION_BUSY" }, + { SD_SDIO_FUNCTION_FAILED, "SDIO_FUNCTION_FAILED" }, + { SD_SDIO_UNKNOWN_FUNCTION, "SDIO_UNKNOWN_FUNCTION" }, + + /** + * @brief Standard error defines + */ + { SD_INTERNAL_ERROR, "INTERNAL_ERROR" }, + { SD_NOT_CONFIGURED, "NOT_CONFIGURED" }, + { SD_REQUEST_PENDING, "REQUEST_PENDING" }, + { SD_REQUEST_NOT_APPLICABLE,"REQUEST_NOT_APPLICABLE" }, + { SD_INVALID_PARAMETER, "INVALID_PARAMETER" }, + { SD_UNSUPPORTED_FEATURE, "UNSUPPORTED_FEATURE" }, + { SD_UNSUPPORTED_HW, "UNSUPPORTED_HW" }, + { SD_ERROR, "ERROR" }, + { SD_OK, "OK" }, +}; +/*-----------------------------------------------------------*/ + +static const char *prvSDCodePrintable( uint32_t ulCode ) +{ +static char retString[32]; +const struct xCODE_NAME *pxCode; + + for( pxCode = xSD_CODES; pxCode <= xSD_CODES + sdARRAY_SIZE( xSD_CODES ) - 1; pxCode++ ) + { + if( pxCode->ulValue == ulCode ) + { + return pxCode->pcName; + } + } + snprintf( retString, sizeof( retString ), "SD code %lu\n", ulCode ); + return retString; +} +/*-----------------------------------------------------------*/ + +#if( SDIO_USES_DMA != 0 ) + + static void prvSDIO_DMA_Init( void ) + { + static DMA_HandleTypeDef xRxDMAHandle; + static DMA_HandleTypeDef xTxDMAHandle; + + /* Enable DMA2 clocks */ + __DMAx_TxRx_CLK_ENABLE(); + + /* NVIC configuration for SDIO interrupts */ + HAL_NVIC_SetPriority(SDIO_IRQn, configSDIO_DMA_INTERRUPT_PRIORITY, 0); + HAL_NVIC_EnableIRQ(SDIO_IRQn); + + /* Configure DMA Rx parameters */ + xRxDMAHandle.Init.Channel = SD_DMAx_Rx_CHANNEL; + xRxDMAHandle.Init.Direction = DMA_PERIPH_TO_MEMORY; + /* Peripheral address is fixed (FIFO). */ + xRxDMAHandle.Init.PeriphInc = DMA_PINC_DISABLE; + /* Memory address increases. */ + xRxDMAHandle.Init.MemInc = DMA_MINC_ENABLE; + xRxDMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + xRxDMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + /* The peripheral has flow-control. */ + xRxDMAHandle.Init.Mode = DMA_PFCTRL; + xRxDMAHandle.Init.Priority = DMA_PRIORITY_VERY_HIGH; + xRxDMAHandle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + xRxDMAHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + xRxDMAHandle.Init.MemBurst = DMA_MBURST_INC4; + xRxDMAHandle.Init.PeriphBurst = DMA_PBURST_INC4; + + /* DMA2_Stream3. */ + xRxDMAHandle.Instance = SD_DMAx_Rx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(&xSDHandle, hdmarx, xRxDMAHandle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&xRxDMAHandle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&xRxDMAHandle); + + /* Configure DMA Tx parameters */ + xTxDMAHandle.Init.Channel = SD_DMAx_Tx_CHANNEL; + xTxDMAHandle.Init.Direction = DMA_MEMORY_TO_PERIPH; + xTxDMAHandle.Init.PeriphInc = DMA_PINC_DISABLE; + xTxDMAHandle.Init.MemInc = DMA_MINC_ENABLE; + xTxDMAHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; + xTxDMAHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; + xTxDMAHandle.Init.Mode = DMA_PFCTRL; + xTxDMAHandle.Init.Priority = DMA_PRIORITY_VERY_HIGH; + xTxDMAHandle.Init.FIFOMode = DMA_FIFOMODE_ENABLE; + xTxDMAHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; + xTxDMAHandle.Init.MemBurst = DMA_MBURST_SINGLE; + xTxDMAHandle.Init.PeriphBurst = DMA_PBURST_INC4; + + /* DMA2_Stream6. */ + xTxDMAHandle.Instance = SD_DMAx_Tx_STREAM; + + /* Associate the DMA handle */ + __HAL_LINKDMA(&xSDHandle, hdmatx, xTxDMAHandle); + + /* Deinitialize the stream for new transfer */ + HAL_DMA_DeInit(&xTxDMAHandle); + + /* Configure the DMA stream */ + HAL_DMA_Init(&xTxDMAHandle); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD_DMAx_Rx_IRQn, configSDIO_DMA_INTERRUPT_PRIORITY + 2, 0); + HAL_NVIC_EnableIRQ(SD_DMAx_Rx_IRQn); + + /* NVIC configuration for DMA transfer complete interrupt */ + HAL_NVIC_SetPriority(SD_DMAx_Tx_IRQn, configSDIO_DMA_INTERRUPT_PRIORITY + 2, 0); + HAL_NVIC_EnableIRQ(SD_DMAx_Tx_IRQn); + } +#endif /* SDIO_USES_DMA */ +/*-----------------------------------------------------------*/ + +#if( SDIO_USES_DMA != 0 ) +// void SDIO_IRQHandler(void) + void SDMMC1_IRQHandler(void) + { + BaseType_t xHigherPriorityTaskWoken = 0; + + HAL_SD_IRQHandler( &xSDHandle ); + if( xSDCardSemaphore != NULL ) + { + xSemaphoreGiveFromISR( xSDCardSemaphore, &xHigherPriorityTaskWoken ); + } + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + } + +#endif /* SDIO_USES_DMA */ +/*-----------------------------------------------------------*/ + +#if( SDIO_USES_DMA != 0 ) + + void DMA2_Stream6_IRQHandler(void) + { + BaseType_t xHigherPriorityTaskWoken = 0; + + /* DMA SDIO-TX interrupt handler. */ + HAL_DMA_IRQHandler (xSDHandle.hdmatx); + if( xSDCardSemaphore != NULL ) + { + xSemaphoreGiveFromISR( xSDCardSemaphore, &xHigherPriorityTaskWoken ); + } + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + } + +#endif /* SDIO_USES_DMA */ +/*-----------------------------------------------------------*/ + +#if( SDIO_USES_DMA != 0 ) + + void DMA2_Stream3_IRQHandler(void) + { + BaseType_t xHigherPriorityTaskWoken = 0; + + /* DMA SDIO-RX interrupt handler. */ + HAL_DMA_IRQHandler (xSDHandle.hdmarx); + if( xSDCardSemaphore != NULL ) + { + xSemaphoreGiveFromISR( xSDCardSemaphore, &xHigherPriorityTaskWoken ); + } + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + } + +#endif /* SDIO_USES_DMA */ +/*-----------------------------------------------------------*/ + +#if( SDIO_USES_DMA != 0 ) + + static void prvEventSetupFunction( SD_HandleTypeDef * pxHandle ) + { + /* A DMA transfer to or from the SD-card is about to start. + Reset the timers that will be used in prvEventWaitFunction() */ + xDMARemainingTime = sdMAX_TIME_TICKS; + vTaskSetTimeOutState( &xDMATimeOut ); + } + +#endif /* SDIO_USES_DMA != 0 */ +/*-----------------------------------------------------------*/ + +#if( SDIO_USES_DMA != 0 ) + + static uint32_t prvEventWaitFunction( SD_HandleTypeDef *pxHandle ) + { + uint32_t ulReturn; + + /* + * It was measured how quickly a DMA interrupt was received. It varied + * between 0 and 4 ms. + * <= 1 ms : 8047 + * <= 2 ms : 1850 + * <= 3 ms : 99 + * <= 4 ms : 79 + * >= 5 ms : 0 times + */ + + if( xTaskCheckForTimeOut( &xDMATimeOut, &xDMARemainingTime ) != pdFALSE ) + { + /* The timeout has been reached, no need to block. */ + ulReturn = 1UL; + } + else + { + /* The timeout has not been reached yet, block on the semaphore. */ + xSemaphoreTake( xSDCardSemaphore, xDMARemainingTime ); + if( xTaskCheckForTimeOut( &xDMATimeOut, &xDMARemainingTime ) != pdFALSE ) + { + ulReturn = 1UL; + } + else + { + ulReturn = 0UL; + } + } + + return ulReturn; + } + +#endif /* SDIO_USES_DMA != 0 */ +/*-----------------------------------------------------------*/ + +void HAL_GPIO_EXTI_Callback( uint16_t GPIO_Pin ) +{ +BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + if( GPIO_Pin == configSD_DETECT_PIN ) + { + vApplicationCardDetectChangeHookFromISR( &xHigherPriorityTaskWoken ); + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + } +} +/*-----------------------------------------------------------*/ + +void EXTI15_10_IRQHandler( void ) +{ + HAL_GPIO_EXTI_IRQHandler( configSD_DETECT_PIN ); /* GPIO PIN H.13 */ +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/stm32f7xx_hal_sd.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/stm32f7xx_hal_sd.c new file mode 100644 index 000000000..072521727 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/stm32f7xx_hal_sd.c @@ -0,0 +1,3600 @@ +/** + ****************************************************************************** + * @file stm32f7xx_hal_sd.c + * @author MCD Application Team + * @version V1.3.2 + * @date 26-June-2015 + * @brief SD card HAL module driver. + * This file provides firmware functions to manage the following + * functionalities of the Secure Digital (SD) peripheral: + * + Initialization and de-initialization functions + * + IO operation functions + * + Peripheral Control functions + * + Peripheral State functions + * + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + This driver implements a high level communication layer for read and write from/to + this memory. The needed STM32 hardware resources (SDMMC and GPIO) are performed by + the user in HAL_SD_MspInit() function (MSP layer). + Basically, the MSP layer configuration should be the same as we provide in the + examples. + You can easily tailor this configuration according to hardware resources. + + [..] + This driver is a generic layered driver for SDMMC memories which uses the HAL + SDMMC driver functions to interface with SD and uSD cards devices. + It is used as follows: + + (#)Initialize the SDMMC low level resources by implement the HAL_SD_MspInit() API: + (##) Enable the SDMMC interface clock using __HAL_RCC_SDMMC_CLK_ENABLE(); + (##) SDMMC pins configuration for SD card + (+++) Enable the clock for the SDMMC GPIOs using the functions __HAL_RCC_GPIOx_CLK_ENABLE(); + (+++) Configure these SDMMC pins as alternate function pull-up using HAL_GPIO_Init() + and according to your pin assignment; + (##) DMA Configuration if you need to use DMA process (HAL_SD_ReadBlocks_DMA() + and HAL_SD_WriteBlocks_DMA() APIs). + (+++) Enable the DMAx interface clock using __HAL_RCC_DMAx_CLK_ENABLE(); + (+++) Configure the DMA using the function HAL_DMA_Init() with predeclared and filled. + (##) NVIC configuration if you need to use interrupt process when using DMA transfer. + (+++) Configure the SDMMC and DMA interrupt priorities using functions + HAL_NVIC_SetPriority(); DMA priority is superior to SDMMC's priority + (+++) Enable the NVIC DMA and SDMMC IRQs using function HAL_NVIC_EnableIRQ() + (+++) SDMMC interrupts are managed using the macros __HAL_SD_SDMMC_ENABLE_IT() + and __HAL_SD_SDMMC_DISABLE_IT() inside the communication process. + (+++) SDMMC interrupts pending bits are managed using the macros __HAL_SD_SDMMC_GET_IT() + and __HAL_SD_SDMMC_CLEAR_IT() + (#) At this stage, you can perform SD read/write/erase operations after SD card initialization + + + *** SD Card Initialization and configuration *** + ================================================ + [..] + To initialize the SD Card, use the HAL_SD_Init() function. It Initializes + the SD Card and put it into StandBy State (Ready for data transfer). + This function provide the following operations: + + (#) Apply the SD Card initialization process at 400KHz and check the SD Card + type (Standard Capacity or High Capacity). You can change or adapt this + frequency by adjusting the "ClockDiv" field. + The SD Card frequency (SDMMC_CK) is computed as follows: + + SDMMC_CK = SDMMCCLK / (ClockDiv + 2) + + In initialization mode and according to the SD Card standard, + make sure that the SDMMC_CK frequency doesn't exceed 400KHz. + + (#) Get the SD CID and CSD data. All these information are managed by the SDCardInfo + structure. This structure provide also ready computed SD Card capacity + and Block size. + + -@- These information are stored in SD handle structure in case of future use. + + (#) Configure the SD Card Data transfer frequency. By Default, the card transfer + frequency is set to 24MHz. You can change or adapt this frequency by adjusting + the "ClockDiv" field. + In transfer mode and according to the SD Card standard, make sure that the + SDMMC_CK frequency doesn't exceed 25MHz and 50MHz in High-speed mode switch. + To be able to use a frequency higher than 24MHz, you should use the SDMMC + peripheral in bypass mode. Refer to the corresponding reference manual + for more details. + + (#) Select the corresponding SD Card according to the address read with the step 2. + + (#) Configure the SD Card in wide bus mode: 4-bits data. + + *** SD Card Read operation *** + ============================== + [..] + (+) You can read from SD card in polling mode by using function HAL_SD_ReadBlocks(). + This function support only 512-bytes block length (the block size should be + chosen as 512 bytes). + You can choose either one block read operation or multiple block read operation + by adjusting the "NumberOfBlocks" parameter. + + (+) You can read from SD card in DMA mode by using function HAL_SD_ReadBlocks_DMA(). + This function support only 512-bytes block length (the block size should be + chosen as 512 bytes). + You can choose either one block read operation or multiple block read operation + by adjusting the "NumberOfBlocks" parameter. + After this, you have to call the function HAL_SD_CheckReadOperation(), to insure + that the read transfer is done correctly in both DMA and SD sides. + + *** SD Card Write operation *** + =============================== + [..] + (+) You can write to SD card in polling mode by using function HAL_SD_WriteBlocks(). + This function support only 512-bytes block length (the block size should be + chosen as 512 bytes). + You can choose either one block read operation or multiple block read operation + by adjusting the "NumberOfBlocks" parameter. + + (+) You can write to SD card in DMA mode by using function HAL_SD_WriteBlocks_DMA(). + This function support only 512-bytes block length (the block size should be + chosen as 512 byte). + You can choose either one block read operation or multiple block read operation + by adjusting the "NumberOfBlocks" parameter. + After this, you have to call the function HAL_SD_CheckWriteOperation(), to insure + that the write transfer is done correctly in both DMA and SD sides. + + *** SD card status *** + ====================== + [..] + (+) At any time, you can check the SD Card status and get the SD card state + by using the HAL_SD_GetStatus() function. This function checks first if the + SD card is still connected and then get the internal SD Card transfer state. + (+) You can also get the SD card SD Status register by using the HAL_SD_SendSDStatus() + function. + + *** SD HAL driver macros list *** + ================================== + [..] + Below the list of most used macros in SD HAL driver. + + (+) __HAL_SD_SDMMC_ENABLE : Enable the SD device + (+) __HAL_SD_SDMMC_DISABLE : Disable the SD device + (+) __HAL_SD_SDMMC_DMA_ENABLE: Enable the SDMMC DMA transfer + (+) __HAL_SD_SDMMC_DMA_DISABLE: Disable the SDMMC DMA transfer + (+) __HAL_SD_SDMMC_ENABLE_IT: Enable the SD device interrupt + (+) __HAL_SD_SDMMC_DISABLE_IT: Disable the SD device interrupt + (+) __HAL_SD_SDMMC_GET_FLAG:Check whether the specified SD flag is set or not + (+) __HAL_SD_SDMMC_CLEAR_FLAG: Clear the SD's pending flags + + (@) You can refer to the SD HAL driver header file for more useful macros + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + * + ****************************************************************************** + */ + +#include "FreeRTOS.h" +#include "task.h" + +/* This include is not necessary except for including the definition of FF_PRINTF(). */ +#include "ff_headers.h" + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + +#ifdef HAL_SD_MODULE_ENABLED + +/** @addtogroup STM32F7xx_HAL_Driver + * @{ + */ + +/** @addtogroup SD + * @{ + */ + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/** @addtogroup SD_Private_Defines + * @{ + */ +/** + * @brief SDMMC Data block size + */ +#define DATA_BLOCK_SIZE ((uint32_t)(9 << 4)) +/** + * @brief SDMMC Static flags, Timeout, FIFO Address + */ +#define SDMMC_STATIC_FLAGS ((uint32_t)(SDIO_FLAG_CCRCFAIL | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_CTIMEOUT |\ + SDIO_FLAG_DTIMEOUT | SDIO_FLAG_TXUNDERR | SDIO_FLAG_RXOVERR |\ + SDIO_FLAG_CMDREND | SDIO_FLAG_CMDSENT | SDIO_FLAG_DATAEND |\ + SDIO_FLAG_DBCKEND)) + +#define SDMMC_CMD0TIMEOUT ((uint32_t)0x00010000) + +/** + * @brief Mask for errors Card Status R1 (OCR Register) + */ +#define SD_OCR_ADDR_OUT_OF_RANGE ((uint32_t)0x80000000) +#define SD_OCR_ADDR_MISALIGNED ((uint32_t)0x40000000) +#define SD_OCR_BLOCK_LEN_ERR ((uint32_t)0x20000000) +#define SD_OCR_ERASE_SEQ_ERR ((uint32_t)0x10000000) +#define SD_OCR_BAD_ERASE_PARAM ((uint32_t)0x08000000) +#define SD_OCR_WRITE_PROT_VIOLATION ((uint32_t)0x04000000) +#define SD_OCR_LOCK_UNLOCK_FAILED ((uint32_t)0x01000000) +#define SD_OCR_COM_CRC_FAILED ((uint32_t)0x00800000) +#define SD_OCR_ILLEGAL_CMD ((uint32_t)0x00400000) +#define SD_OCR_CARD_ECC_FAILED ((uint32_t)0x00200000) +#define SD_OCR_CC_ERROR ((uint32_t)0x00100000) +#define SD_OCR_GENERAL_UNKNOWN_ERROR ((uint32_t)0x00080000) +#define SD_OCR_STREAM_READ_UNDERRUN ((uint32_t)0x00040000) +#define SD_OCR_STREAM_WRITE_OVERRUN ((uint32_t)0x00020000) +#define SD_OCR_CID_CSD_OVERWRITE ((uint32_t)0x00010000) +#define SD_OCR_WP_ERASE_SKIP ((uint32_t)0x00008000) +#define SD_OCR_CARD_ECC_DISABLED ((uint32_t)0x00004000) +#define SD_OCR_ERASE_RESET ((uint32_t)0x00002000) +#define SD_OCR_AKE_SEQ_ERROR ((uint32_t)0x00000008) +#define SD_OCR_ERRORBITS ((uint32_t)0xFDFFE008) + +/** + * @brief Masks for R6 Response + */ +#define SD_R6_GENERAL_UNKNOWN_ERROR ((uint32_t)0x00002000) +#define SD_R6_ILLEGAL_CMD ((uint32_t)0x00004000) +#define SD_R6_COM_CRC_FAILED ((uint32_t)0x00008000) + +#define SD_VOLTAGE_WINDOW_SD ((uint32_t)0x80100000) +#define SD_HIGH_CAPACITY ((uint32_t)0x40000000) +#define SD_STD_CAPACITY ((uint32_t)0x00000000) +#define SD_CHECK_PATTERN ((uint32_t)0x000001AA) + +#define SD_MAX_VOLT_TRIAL ((uint32_t)0x0000FFFF) +#define SD_ALLZERO ((uint32_t)0x00000000) + +#define SD_WIDE_BUS_SUPPORT ((uint32_t)0x00040000) +#define SD_SINGLE_BUS_SUPPORT ((uint32_t)0x00010000) +#define SD_CARD_LOCKED ((uint32_t)0x02000000) + +#define SD_DATATIMEOUT ((uint32_t)0xFFFFFFFF) +#define SD_0TO7BITS ((uint32_t)0x000000FF) +#define SD_8TO15BITS ((uint32_t)0x0000FF00) +#define SD_16TO23BITS ((uint32_t)0x00FF0000) +#define SD_24TO31BITS ((uint32_t)0xFF000000) +#define SD_MAX_DATA_LENGTH ((uint32_t)0x01FFFFFF) + +#define SD_HALFFIFO ((uint32_t)0x00000008) +#define SD_HALFFIFOBYTES ((uint32_t)0x00000020) + +/** + * @brief Command Class Supported + */ +#define SD_CCCC_LOCK_UNLOCK ((uint32_t)0x00000080) +#define SD_CCCC_WRITE_PROT ((uint32_t)0x00000040) +#define SD_CCCC_ERASE ((uint32_t)0x00000020) + +/** + * @brief Following commands are SD Card Specific commands. + * SDMMC_APP_CMD should be sent before sending these commands. + */ +#define SD_SDMMC_SEND_IF_COND ((uint32_t)SD_CMD_HS_SEND_EXT_CSD) +/** + * @} + */ + +/* Private macro -------------------------------------------------------------*/ + +/* A few macro's that will allow to use the 'SDIO_' macro's that were +used in the earlier SDIO drivers. It makes it easier to compare the +sources. */ + +#define SDIO_FLAG_CCRCFAIL SDMMC_FLAG_CCRCFAIL +#define SDIO_FLAG_DCRCFAIL SDMMC_FLAG_DCRCFAIL +#define SDIO_FLAG_CTIMEOUT SDMMC_FLAG_CTIMEOUT +#define SDIO_FLAG_DTIMEOUT SDMMC_FLAG_DTIMEOUT +#define SDIO_FLAG_TXUNDERR SDMMC_FLAG_TXUNDERR +#define SDIO_FLAG_RXOVERR SDMMC_FLAG_RXOVERR +#define SDIO_FLAG_CMDREND SDMMC_FLAG_CMDREND +#define SDIO_FLAG_CMDSENT SDMMC_FLAG_CMDSENT +#define SDIO_FLAG_DATAEND SDMMC_FLAG_DATAEND +#define SDIO_FLAG_DBCKEND SDMMC_FLAG_DBCKEND +#define SDIO_FLAG_RXDAVL SDMMC_FLAG_RXDAVL +#define SDIO_FLAG_RXFIFOHF SDMMC_FLAG_RXFIFOHF +#define SDIO_FLAG_RXACT SDMMC_FLAG_RXACT +#define SDIO_FLAG_TXACT SDMMC_FLAG_TXACT +#define SDIO_FLAG_TXFIFOHE SDMMC_FLAG_TXFIFOHE +#define SDIO_FLAG_TXFIFOE SDMMC_FLAG_TXFIFOE + +#define SDIO_CmdInitTypeDef SDMMC_CmdInitTypeDef +#define SDIO_DataInitTypeDef SDMMC_DataInitTypeDef +#define SDIO_InitTypeDef SDMMC_InitTypeDef + + +#define SDIO_BUS_WIDE_1B SDMMC_BUS_WIDE_1B +#define SDIO_BUS_WIDE_4B SDMMC_BUS_WIDE_4B +#define SDIO_BUS_WIDE_8B SDMMC_BUS_WIDE_8B +#define SDIO_CLOCK_BYPASS_DISABLE SDMMC_CLOCK_BYPASS_DISABLE +#define SDIO_CLOCK_EDGE_RISING SDMMC_CLOCK_EDGE_RISING +#define SDIO_CLOCK_POWER_SAVE_DISABLE SDMMC_CLOCK_POWER_SAVE_DISABLE +#define SDIO_CPSM_ENABLE SDMMC_CPSM_ENABLE +#define SDIO_DATABLOCK_SIZE_512B SDMMC_DATABLOCK_SIZE_512B +#define SDIO_DATABLOCK_SIZE_64B SDMMC_DATABLOCK_SIZE_64B +#define SDIO_DATABLOCK_SIZE_8B SDMMC_DATABLOCK_SIZE_8B +#define SDIO_DCTRL_DTEN SDMMC_DCTRL_DTEN +#define SDIO_DPSM_ENABLE SDMMC_DPSM_ENABLE +#define SDIO_HARDWARE_FLOW_CONTROL_DISABLE SDMMC_HARDWARE_FLOW_CONTROL_DISABLE +#define SDIO_HARDWARE_FLOW_CONTROL_ENABLE SDMMC_HARDWARE_FLOW_CONTROL_ENABLE +#define SDIO_INIT_CLK_DIV SDMMC_INIT_CLK_DIV +#define SDIO_IT_DATAEND SDMMC_IT_DATAEND +#define SDIO_IT_DCRCFAIL SDMMC_IT_DCRCFAIL +#define SDIO_IT_DTIMEOUT SDMMC_IT_DTIMEOUT +#define SDIO_IT_RXFIFOHF SDMMC_IT_RXFIFOHF +#define SDIO_IT_RXOVERR SDMMC_IT_RXOVERR +#define SDIO_IT_RXOVERR SDMMC_IT_RXOVERR +#define SDIO_IT_TXFIFOHE SDMMC_IT_TXFIFOHE +#define SDIO_IT_TXUNDERR SDMMC_IT_TXUNDERR +#define SDIO_RESP1 SDMMC_RESP1 +#define SDIO_RESP2 SDMMC_RESP2 +#define SDIO_RESP3 SDMMC_RESP3 +#define SDIO_RESP4 SDMMC_RESP4 +#define SDIO_RESPONSE_LONG SDMMC_RESPONSE_LONG +#define SDIO_RESPONSE_NO SDMMC_RESPONSE_NO +#define SDIO_RESPONSE_SHORT SDMMC_RESPONSE_SHORT +#define SDIO_TRANSFER_DIR_TO_CARD SDMMC_TRANSFER_DIR_TO_CARD +#define SDIO_TRANSFER_DIR_TO_SDIO SDMMC_TRANSFER_DIR_TO_SDMMC +#define SDIO_TRANSFER_MODE_BLOCK SDMMC_TRANSFER_MODE_BLOCK +#define SDIO_WAIT_NO SDMMC_WAIT_NO + +#ifdef __HAL_SD_SDIO_CLEAR_FLAG + #undef __HAL_SD_SDIO_CLEAR_FLAG +#endif + +#ifdef __HAL_SD_SDIO_GET_FLAG + #undef __HAL_SD_SDIO_GET_FLAG +#endif + +#ifdef SDIO_ReadFIFO + #undef SDIO_ReadFIFO +#endif + +#define __HAL_SD_SDIO_CLEAR_FLAG __HAL_SD_SDMMC_CLEAR_FLAG +#define __HAL_SD_SDIO_GET_FLAG __HAL_SD_SDMMC_GET_FLAG +#define SDIO_ReadFIFO SDMMC_ReadFIFO +#define SDIO_SendCommand SDMMC_SendCommand +#define SDIO_Init SDMMC_Init +#define SDIO_GetResponse SDMMC_GetResponse +#define SDIO_DataConfig SDMMC_DataConfig +#define SDIO_GetPowerState SDMMC_GetPowerState +#define SDIO_PowerState_ON SDMMC_PowerState_ON +#define SDIO_PowerState_OFF SDMMC_PowerState_OFF +#define SDIO_GetCommandResponse SDMMC_GetCommandResponse + +#define SDIO_STATIC_FLAGS SDMMC_STATIC_FLAGS + +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ +/** @defgroup SD_Private_Functions SD Private Functions + * @{ + */ +static HAL_SD_ErrorTypedef SD_Initialize_Cards(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_Select_Deselect(SD_HandleTypeDef *hsd, uint64_t addr); +static HAL_SD_ErrorTypedef SD_PowerON(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_PowerOFF(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_SendStatus(SD_HandleTypeDef *hsd, uint32_t *pCardStatus); +static HAL_SD_CardStateTypedef SD_GetState(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_IsCardProgramming(SD_HandleTypeDef *hsd, uint8_t *pStatus); +static HAL_SD_ErrorTypedef SD_CmdError(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_CmdResp1Error(SD_HandleTypeDef *hsd, uint8_t SD_CMD); +static HAL_SD_ErrorTypedef SD_CmdResp7Error(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_CmdResp3Error(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_CmdResp2Error(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_CmdResp6Error(SD_HandleTypeDef *hsd, uint8_t SD_CMD, uint16_t *pRCA); +static HAL_SD_ErrorTypedef SD_WideBus_Enable(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_WideBus_Disable(SD_HandleTypeDef *hsd); +static HAL_SD_ErrorTypedef SD_FindSCR(SD_HandleTypeDef *hsd, uint32_t *pSCR); +static void SD_DMA_RxCplt(DMA_HandleTypeDef *hdma); +static void SD_DMA_RxError(DMA_HandleTypeDef *hdma); +static void SD_DMA_TxCplt(DMA_HandleTypeDef *hdma); +static void SD_DMA_TxError(DMA_HandleTypeDef *hdma); +/** + * @} + */ +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup SD_Exported_Functions + * @{ + */ + +/** @addtogroup SD_Exported_Functions_Group1 + * @brief Initialization and de-initialization functions + * +@verbatim + ============================================================================== + ##### Initialization and de-initialization functions ##### + ============================================================================== + [..] + This section provides functions allowing to initialize/de-initialize the SD + card device to be ready for use. + + +@endverbatim + * @{ + */ + +/** + * @brief Initializes the SD card according to the specified parameters in the + SD_HandleTypeDef and create the associated handle. + * @param hsd: SD handle + * @param SDCardInfo: HAL_SD_CardInfoTypedef structure for SD card information + * @retval HAL SD error state + */ +HAL_SD_ErrorTypedef HAL_SD_Init(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypedef *SDCardInfo) +{ + __IO HAL_SD_ErrorTypedef errorstate = SD_OK; + SD_InitTypeDef tmpinit; + + /* Allocate lock resource and initialize it */ + hsd->Lock = HAL_UNLOCKED; + + /* Initialize the low level hardware (MSP) */ + HAL_SD_MspInit(hsd); + + /* Default SDMMC peripheral configuration for SD card initialization */ + tmpinit.ClockEdge = SDIO_CLOCK_EDGE_RISING; + tmpinit.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; + tmpinit.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; + #if( BUS_4BITS != 0 ) + { + #warning Four bits + tmpinit.BusWide = SDIO_BUS_WIDE_4B; + } + #else + { + #warning One bit + tmpinit.BusWide = SDIO_BUS_WIDE_1B; + } + #endif + tmpinit.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE; + tmpinit.ClockDiv = SDIO_INIT_CLK_DIV; + + /* Initialize SDMMC peripheral interface with default configuration */ + SDIO_Init(hsd->Instance, tmpinit); + + /* Identify card operating voltage */ + errorstate = SD_PowerON(hsd); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Initialize the present SDIO card(s) and put them in idle state */ + errorstate = SD_Initialize_Cards(hsd); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Read CSD/CID MSD registers */ + errorstate = HAL_SD_Get_CardInfo(hsd, SDCardInfo); + + if (errorstate == SD_OK) + { + /* Select the Card */ + errorstate = SD_Select_Deselect(hsd, (uint32_t)(((uint32_t)SDCardInfo->RCA) << 16)); + } + + /* Configure SDIO peripheral interface */ + SDIO_Init(hsd->Instance, hsd->Init); + + return errorstate; +} + +/** + * @brief De-Initializes the SD card. + * @param hsd: SD handle + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_DeInit(SD_HandleTypeDef *hsd) +{ + + /* Set SD power state to off */ + SD_PowerOFF(hsd); + + /* De-Initialize the MSP layer */ + HAL_SD_MspDeInit(hsd); + + return HAL_OK; +} + + +/** + * @brief Initializes the SD MSP. + * @param hsd: SD handle + * @retval None + */ +__weak void HAL_SD_MspInit(SD_HandleTypeDef *hsd) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_MspInit could be implemented in the user file + */ +} + +/** + * @brief De-Initialize SD MSP. + * @param hsd: SD handle + * @retval None + */ +__weak void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_MspDeInit could be implemented in the user file + */ +} + +/** + * @} + */ + +/** @addtogroup SD_Exported_Functions_Group2 + * @brief Data transfer functions + * +@verbatim + ============================================================================== + ##### IO operation functions ##### + ============================================================================== + [..] + This subsection provides a set of functions allowing to manage the data + transfer from/to SD card. + +@endverbatim + * @{ + */ + +/** + * @brief Reads block(s) from a specified address in a card. The Data transfer + * is managed by polling mode. + * @param hsd: SD handle + * @param pReadBuffer: pointer to the buffer that will contain the received data + * @param ReadAddr: Address from where data is to be read + * @param BlockSize: SD card Data block size + * @note BlockSize must be 512 bytes. + * @param NumberOfBlocks: Number of SD blocks to read + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + SDIO_DataInitTypeDef sdmmc_datainitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t count = 0, *tempbuff = (uint32_t *)pReadBuffer; + __IO uint32_t *pulFIFO = &( hsd->Instance->FIFO ); + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0; + + if (hsd->CardType == HIGH_CAPACITY_SD_CARD) + { + BlockSize = 512; + ReadAddr /= 512; + } + + /* Set Block Size for Card */ + sdmmc_cmdinitstructure.Argument = (uint32_t) BlockSize; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = NumberOfBlocks * BlockSize; + sdmmc_datainitstructure.DataBlockSize = DATA_BLOCK_SIZE; + sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO; + sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE; + SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure); + + if(NumberOfBlocks > 1) + { + /* Send CMD18 READ_MULT_BLOCK with argument data address */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_READ_MULT_BLOCK; + } + else + { + /* Send CMD17 READ_SINGLE_BLOCK */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_READ_SINGLE_BLOCK; + } + + sdmmc_cmdinitstructure.Argument = (uint32_t)ReadAddr; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, sdmmc_cmdinitstructure.CmdIndex); + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Read block(s) in polling mode */ + if(NumberOfBlocks > 1) + { + /* Poll on SDIO flags */ + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND)) + { + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF)) + { + /* Read data from SDIO Rx FIFO */ + tempbuff[0] = *( pulFIFO ); + tempbuff[1] = *( pulFIFO ); + tempbuff[2] = *( pulFIFO ); + tempbuff[3] = *( pulFIFO ); + tempbuff[4] = *( pulFIFO ); + tempbuff[5] = *( pulFIFO ); + tempbuff[6] = *( pulFIFO ); + tempbuff[7] = *( pulFIFO ); + + tempbuff += 8; + } + } + } + else + { + /* In case of single block transfer, no need of stop transfer at all */ + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND)) + { + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF)) + { + /* Read data from SDIO Rx FIFO */ + tempbuff[0] = *( pulFIFO ); + tempbuff[1] = *( pulFIFO ); + tempbuff[2] = *( pulFIFO ); + tempbuff[3] = *( pulFIFO ); + tempbuff[4] = *( pulFIFO ); + tempbuff[5] = *( pulFIFO ); + tempbuff[6] = *( pulFIFO ); + tempbuff[7] = *( pulFIFO ); + + tempbuff += 8; + } + } + } + + /* Send stop transmission command in case of multiblock read */ + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DATAEND) && (NumberOfBlocks > 1)) + { + if ((hsd->CardType == STD_CAPACITY_SD_CARD_V1_1) ||\ + (hsd->CardType == STD_CAPACITY_SD_CARD_V2_0) ||\ + (hsd->CardType == HIGH_CAPACITY_SD_CARD)) + { + /* Send stop transmission command */ + errorstate = HAL_SD_StopTransfer(hsd); + } + } + + /* Get error state */ + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DTIMEOUT); + + errorstate = SD_DATA_TIMEOUT; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DCRCFAIL); + + errorstate = SD_DATA_CRC_FAIL; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_RXOVERR); + + errorstate = SD_RX_OVERRUN; + + return errorstate; + } + else + { + /* Note that the STM32F7 doesn't have a SDIO_FLAG_STBITERR flag. */ + /* No error flag set */ + } + + count = SD_DATATIMEOUT; + + /* Empty FIFO if there is still any data */ + while ((__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXDAVL)) && (count > 0)) + { + *tempbuff = SDIO_ReadFIFO(hsd->Instance); + tempbuff++; + count--; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + return errorstate; +} + +/** + * @brief Allows to write block(s) to a specified address in a card. The Data + * transfer is managed by polling mode. + * @param hsd: SD handle + * @param pWriteBuffer: pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be written + * @param BlockSize: SD card Data block size + * @note BlockSize must be 512 bytes. + * @param NumberOfBlocks: Number of SD blocks to write + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; +/*SDIO_DataInitTypeDef sdmmc_datainitstructure; */ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t totalnumberofbytes, bytesRemaining; + uint32_t tmpreg; + uint32_t last_sta; + uint32_t *tempbuff = (uint32_t *)pWriteBuffer; + uint8_t cardstate = 0; + __IO uint32_t *pulFIFO = &( hsd->Instance->FIFO ); + uint32_t ulEndFags; + uint32_t ulHasHWFlowControl; + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0; + + if (hsd->CardType == HIGH_CAPACITY_SD_CARD) + { + BlockSize = 512; + WriteAddr /= 512; + } + + /* Set Block Size for Card */ + sdmmc_cmdinitstructure.Argument = (uint32_t)BlockSize; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN); + + if (errorstate != SD_OK) + { + return errorstate; + } + + if(NumberOfBlocks > 1) + { + /* Send CMD25 WRITE_MULT_BLOCK with argument data address */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_MULT_BLOCK; + /* Test for DATAEND : Data end (data counter, SDID count) is zero) */ + ulEndFags = SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND; + } + else + { + /* Send CMD24 WRITE_SINGLE_BLOCK */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_SINGLE_BLOCK; + /* Test for DBCKEND : Data Block Sent/Received (CRC check passed) */ + ulEndFags = SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND; + } + ulEndFags |= SDIO_FLAG_TXUNDERR; + + sdmmc_cmdinitstructure.Argument = (uint32_t)WriteAddr; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, sdmmc_cmdinitstructure.CmdIndex); + if (errorstate != SD_OK) + { + return errorstate; + } + + ulHasHWFlowControl = ( hsd->Instance->CLKCR & SDIO_HARDWARE_FLOW_CONTROL_ENABLE ) != 0; + + /* Set total number of bytes to write */ + totalnumberofbytes = NumberOfBlocks * BlockSize; + bytesRemaining = 4 * ( ( totalnumberofbytes + 3 ) / 4 ); + + /* Configure the SD DPSM (Data Path State Machine) */ +/* + sdio_datainitstructure.DataTimeOut = SD_DATATIMEOUT; + sdio_datainitstructure.DataLength = NumberOfBlocks * BlockSize; + sdio_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_512B; + sdio_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_CARD; + sdio_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + sdio_datainitstructure.DPSM = SDIO_DPSM_ENABLE; + SDIO_DataConfig(hsd->Instance, &sdio_datainitstructure); +*/ + /* Set the SDIO Data Timeout value */ + hsd->Instance->DTIMER = SD_DATATIMEOUT; + + /* Set the SDIO DataLength value */ + hsd->Instance->DLEN = NumberOfBlocks * BlockSize; + + tmpreg = hsd->Instance->DCTRL & ~( DCTRL_CLEAR_MASK ); + /* Set the SDIO data configuration parameters */ + tmpreg |= (uint32_t)(SDIO_DATABLOCK_SIZE_512B | SDIO_TRANSFER_DIR_TO_CARD | SDIO_TRANSFER_MODE_BLOCK | SDIO_DCTRL_DTEN); + + /* Write to SDIO DCTRL */ + + hsd->Instance->DCTRL = tmpreg; + + for( ;; ) + { + last_sta = hsd->Instance->STA; + if( ( last_sta & ( SDIO_FLAG_TXFIFOHE | SDIO_FLAG_TXFIFOE ) ) != 0 ) + { + /* SDIO_FLAG_TXFIFOHE: Transmit FIFO Half Empty + May write 32 bytes. */ + if( bytesRemaining < 32) + { + /* Write data to SDIO Tx FIFO */ + while( bytesRemaining > 0 ) + { + *pulFIFO = *( tempbuff++ ); + bytesRemaining -= 4; + } + } + else + { + /* Write data to SDIO Tx FIFO */ + *pulFIFO = tempbuff[ 0 ]; + *pulFIFO = tempbuff[ 1 ]; + *pulFIFO = tempbuff[ 2 ]; + *pulFIFO = tempbuff[ 3 ]; + *pulFIFO = tempbuff[ 4 ]; + *pulFIFO = tempbuff[ 5 ]; + *pulFIFO = tempbuff[ 6 ]; + *pulFIFO = tempbuff[ 7 ]; + + tempbuff += 8; + bytesRemaining -= 32; + if( ( last_sta & SDIO_FLAG_TXFIFOE ) != 0 ) + { + /* SDIO_FLAG_TXFIFOE: Transmit FIFO empty + May write 24 or 32 extra bytes, depending on + ulHasHWFlowControl. */ + *pulFIFO = tempbuff[ 0 ]; + *pulFIFO = tempbuff[ 1 ]; + *pulFIFO = tempbuff[ 2 ]; + *pulFIFO = tempbuff[ 3 ]; + *pulFIFO = tempbuff[ 4 ]; + *pulFIFO = tempbuff[ 5 ]; + if( ulHasHWFlowControl != 0 ) + { + tempbuff += 6; + bytesRemaining -= 24; + } + else + { + *pulFIFO = tempbuff[ 6 ]; + *pulFIFO = tempbuff[ 7 ]; + + tempbuff += 8; + bytesRemaining -= 32; + } + } + } + } + if( ( last_sta & ulEndFags ) != 0 ) + { + break; + } + } + if( ( ( last_sta & SDIO_FLAG_TXUNDERR ) != 0 ) || ( bytesRemaining != 0 ) ) + { + FF_PRINTF("TX underflow %lu < %lu\n", bytesRemaining, totalnumberofbytes ); + } + /* Send stop transmission command in case of multiblock write */ + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DATAEND) && (NumberOfBlocks > 1)) + { + if ((hsd->CardType == STD_CAPACITY_SD_CARD_V1_1) || (hsd->CardType == STD_CAPACITY_SD_CARD_V2_0) ||\ + (hsd->CardType == HIGH_CAPACITY_SD_CARD)) + { + /* Send stop transmission command */ + errorstate = HAL_SD_StopTransfer(hsd); + } + } + + /* Get error state */ + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DTIMEOUT); + + errorstate = SD_DATA_TIMEOUT; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DCRCFAIL); + + errorstate = SD_DATA_CRC_FAIL; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_TXUNDERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_TXUNDERR); + + errorstate = SD_TX_UNDERRUN; + + return errorstate; + } + else + { + /* Note that the STM32F7 doesn't have a SDIO_FLAG_STBITERR flag. */ + /* No error flag set */ + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + /* Wait till the card is in programming state */ + do + { + errorstate = SD_IsCardProgramming(hsd, &cardstate); + } while ((errorstate == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING))); + + return errorstate; +} + +/** + * @brief Reads block(s) from a specified address in a card. The Data transfer + * is managed by DMA mode. + * @note This API should be followed by the function HAL_SD_CheckReadOperation() + * to check the completion of the read process + * @param hsd: SD handle + * @param pReadBuffer: Pointer to the buffer that will contain the received data + * @param ReadAddr: Address from where data is to be read + * @param BlockSize: SD card Data block size + * @note BlockSize must be 512 bytes. + * @param NumberOfBlocks: Number of blocks to read. + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + SDIO_DataInitTypeDef sdmmc_datainitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0; + + /* Initialize handle flags */ + hsd->SdTransferCplt = 0; + hsd->DmaTransferCplt = 0; + hsd->SdTransferErr = SD_OK; + if( hsd->EventSetupFunction != NULL ) + { + hsd->EventSetupFunction( hsd ); + } + + /* Initialize SD Read operation */ + if(NumberOfBlocks > 1) + { + hsd->SdOperation = SD_READ_MULTIPLE_BLOCK; + } + else + { + hsd->SdOperation = SD_READ_SINGLE_BLOCK; + } + + /* Enable transfer interrupts */ + __HAL_SD_SDIO_ENABLE_IT(hsd, (SDIO_IT_DCRCFAIL |\ + SDIO_IT_DTIMEOUT |\ + SDIO_IT_DATAEND |\ + SDIO_IT_RXOVERR)); + + /* Enable SDIO DMA transfer */ + __HAL_SD_SDIO_DMA_ENABLE(hsd); + + /* Configure DMA user callbacks */ + hsd->hdmarx->XferCpltCallback = SD_DMA_RxCplt; + hsd->hdmarx->XferErrorCallback = SD_DMA_RxError; + + /* Enable the DMA Stream */ + HAL_DMA_Start_IT(hsd->hdmarx, (uint32_t)&hsd->Instance->FIFO, (uint32_t)pReadBuffer, (uint32_t)(BlockSize * NumberOfBlocks)/4); + + if (hsd->CardType == HIGH_CAPACITY_SD_CARD) + { + BlockSize = 512; + ReadAddr /= 512; + } + + /* Set Block Size for Card */ + sdmmc_cmdinitstructure.Argument = (uint32_t)BlockSize; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = BlockSize * NumberOfBlocks; + sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_512B; + sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO; + sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE; + SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure); + + /* Check number of blocks command */ + if(NumberOfBlocks > 1) + { + /* Send CMD18 READ_MULT_BLOCK with argument data address */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_READ_MULT_BLOCK; + } + else + { + /* Send CMD17 READ_SINGLE_BLOCK */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_READ_SINGLE_BLOCK; + } + + sdmmc_cmdinitstructure.Argument = (uint32_t)ReadAddr; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, sdmmc_cmdinitstructure.CmdIndex); + + /* Update the SD transfer error in SD handle */ + hsd->SdTransferErr = errorstate; + + return errorstate; +} + + +/** + * @brief Writes block(s) to a specified address in a card. The Data transfer + * is managed by DMA mode. + * @note This API should be followed by the function HAL_SD_CheckWriteOperation() + * to check the completion of the write process (by SD current status polling). + * @param hsd: SD handle + * @param pWriteBuffer: pointer to the buffer that will contain the data to transmit + * @param WriteAddr: Address from where data is to be read + * @param BlockSize: the SD card Data block size + * @note BlockSize must be 512 bytes. + * @param NumberOfBlocks: Number of blocks to write + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; +/*SDIO_DataInitTypeDef sdmmc_datainitstructure;*/ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t tmpreg; + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0; + + /* Initialize handle flags */ + hsd->SdTransferCplt = 0; + hsd->DmaTransferCplt = 0; + hsd->SdTransferErr = SD_OK; + if( hsd->EventSetupFunction != NULL ) + { + hsd->EventSetupFunction( hsd ); + } + + hsd->Instance->DLEN = NumberOfBlocks * BlockSize; + + /* Initialize SD Write operation */ + if(NumberOfBlocks > 1) + { + hsd->SdOperation = SD_WRITE_MULTIPLE_BLOCK; + } + else + { + hsd->SdOperation = SD_WRITE_SINGLE_BLOCK; + } + + /* Enable transfer interrupts */ + __HAL_SD_SDIO_ENABLE_IT(hsd, (SDIO_IT_DCRCFAIL |\ + SDIO_IT_DTIMEOUT |\ + SDIO_IT_DATAEND |\ + SDIO_IT_TXUNDERR)); + + /* Configure DMA user callbacks */ + hsd->hdmatx->XferCpltCallback = SD_DMA_TxCplt; + hsd->hdmatx->XferErrorCallback = SD_DMA_TxError; + + /* Enable the DMA Stream */ + HAL_DMA_Start_IT(hsd->hdmatx, (uint32_t)pWriteBuffer, (uint32_t)&hsd->Instance->FIFO, (uint32_t)(BlockSize * NumberOfBlocks)/4); + + /* Enable SDIO DMA transfer */ + __HAL_SD_SDIO_DMA_ENABLE(hsd); + + if (hsd->CardType == HIGH_CAPACITY_SD_CARD) + { + BlockSize = 512; + WriteAddr /= 512; + } + + /* Set Block Size for Card */ + sdmmc_cmdinitstructure.Argument = (uint32_t)BlockSize; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Check number of blocks command */ + if(NumberOfBlocks <= 1) + { + /* Send CMD24 WRITE_SINGLE_BLOCK */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_SINGLE_BLOCK; + } + else + { + /* Send CMD25 WRITE_MULT_BLOCK with argument data address */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_WRITE_MULT_BLOCK; + } + + sdmmc_cmdinitstructure.Argument = (uint32_t)WriteAddr; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, sdmmc_cmdinitstructure.CmdIndex); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ +/* + sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = BlockSize * NumberOfBlocks; + sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_512B; + sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_CARD; + sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE; + SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure); +*/ + + /* Set the SDIO Data Timeout value */ + hsd->Instance->DTIMER = SD_DATATIMEOUT; + +// /* Set the SDIO DataLength value */ +// hsd->Instance->DLEN = NumberOfBlocks * BlockSize; + + tmpreg = hsd->Instance->DCTRL & ~( DCTRL_CLEAR_MASK ); + /* Set the SDIO data configuration parameters */ + tmpreg |= (uint32_t)(SDIO_DATABLOCK_SIZE_512B | SDIO_TRANSFER_DIR_TO_CARD | SDIO_TRANSFER_MODE_BLOCK | SDIO_DCTRL_DTEN); + + /* Write to SDIO DCTRL */ + hsd->Instance->DCTRL = tmpreg; + + hsd->SdTransferErr = errorstate; + + return errorstate; +} + +/** + * @brief This function waits until the SD DMA data read transfer is finished. + * This API should be called after HAL_SD_ReadBlocks_DMA() function + * to insure that all data sent by the card is already transferred by the + * DMA controller. + * @param hsd: SD handle + * @param Timeout: Timeout duration + * @retval SD Card error state + */ + +HAL_SD_ErrorTypedef HAL_SD_CheckReadOperation(SD_HandleTypeDef *hsd, uint32_t ulMaxTime) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t ulStarted = xTaskGetTickCount( ); + BaseType_t xHadTimeout = pdFALSE; + + /* Wait for DMA/SD transfer end or SD error variables to be in SD handle */ + + while( 1 ) + { + HAL_SD_ErrorTypedef xError; + if( ( hsd->DmaTransferCplt != 0 ) && ( hsd->SdTransferCplt != 0 ) ) + { + HAL_DMA_Abort( hsd->hdmarx ); + break; + } + xError = (HAL_SD_ErrorTypedef)hsd->SdTransferErr; + if( xError != SD_OK ) + { + break; + } + if( hsd->EventWaitFunction != NULL ) + { + if( hsd->EventWaitFunction( ( void * ) hsd ) != 0 ) + { + FF_PRINTF( "EventWaitFunction: RX timeout!\n" ); + /* A timeout is reached. */ + break; + } + } + else + { + if( ( xTaskGetTickCount( ) - ulStarted ) >= ulMaxTime ) + { + xHadTimeout = pdTRUE; + break; + } + } + } + + ulStarted = xTaskGetTickCount( ); + + /* Wait until the Rx transfer is no longer active */ + while(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXACT)) + { + if( ( xTaskGetTickCount( ) - ulStarted ) >= ulMaxTime ) + { + xHadTimeout = pdTRUE; + break; + } + } + + /* Send stop command in multiblock read */ + if (hsd->SdOperation == SD_READ_MULTIPLE_BLOCK) + { + errorstate = HAL_SD_StopTransfer(hsd); + } + + if ((xHadTimeout != pdFALSE) && (errorstate == SD_OK)) + { + errorstate = SD_DATA_TIMEOUT; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + /* Return error state */ + if (hsd->SdTransferErr != SD_OK) + { + return (HAL_SD_ErrorTypedef)hsd->SdTransferErr; + } + + return errorstate; +} + +/** + * @brief This function waits until the SD DMA data write transfer is finished. + * This API should be called after HAL_SD_WriteBlocks_DMA() function + * to insure that all data sent by the card is already transferred by the + * DMA controller. + * @param hsd: SD handle + * @param Timeout: Timeout duration + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_CheckWriteOperation(SD_HandleTypeDef *hsd, uint32_t ulMaxTime) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t ulStarted = 0; + BaseType_t xHadTimeout = pdFALSE; + /* Wait for DMA/SD transfer end or SD error variables to be in SD handle */ + + while( 1 ) + { + HAL_SD_ErrorTypedef xError; + if( ( hsd->DmaTransferCplt != 0 ) && ( hsd->SdTransferCplt != 0 ) ) + { + HAL_DMA_Abort( hsd->hdmatx ); + break; + } + xError = (HAL_SD_ErrorTypedef)hsd->SdTransferErr; + if( xError != SD_OK ) + { + break; + } + if( hsd->EventWaitFunction != NULL ) + { + if( hsd->EventWaitFunction( ( void * ) hsd ) != 0 ) + { + FF_PRINTF( "EventWaitFunction: TX timeout!\n" ); + /* A timeout is reached. */ + break; + } + } + else + { + if( ( xTaskGetTickCount( ) - ulStarted ) >= ulMaxTime ) + { + xHadTimeout = pdTRUE; + break; + } + } + } + + ulStarted = xTaskGetTickCount( ); + + /* Wait until the Tx transfer is no longer active */ + /* while( ( hsd->Instance->STA & SDIO_FLAG_TXACT ) != 0 ) { } */ + while( __HAL_SD_SDIO_GET_FLAG( hsd, SDIO_FLAG_TXACT ) ) + { + if( ( xTaskGetTickCount( ) - ulStarted ) >= ulMaxTime ) + { + xHadTimeout = pdTRUE; + break; + } + } + + /* Send stop command in multiblock write */ + if (hsd->SdOperation == SD_WRITE_MULTIPLE_BLOCK) + { + errorstate = HAL_SD_StopTransfer(hsd); + } + + if( ( xHadTimeout != pdFALSE ) && ( errorstate == SD_OK ) ) + { + errorstate = SD_DATA_TIMEOUT; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + /* Return error state */ + if (hsd->SdTransferErr != SD_OK) + { + errorstate = (HAL_SD_ErrorTypedef)(hsd->SdTransferErr); + } + else + { + /* Wait until write is complete */ + while(HAL_SD_GetStatus(hsd) != SD_TRANSFER_OK) + { + } + } + + return errorstate; +} + +/** + * @brief Erases the specified memory area of the given SD card. + * @param hsd: SD handle + * @param startaddr: Start byte address + * @param endaddr: End byte address + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint64_t startaddr, uint64_t endaddr) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + + uint32_t delay = 0; + __IO uint32_t maxdelay = 0; + uint8_t cardstate = 0; + + /* Check if the card command class supports erase command */ + if (((hsd->CSD[1] >> 20) & SD_CCCC_ERASE) == 0) + { + errorstate = SD_REQUEST_NOT_APPLICABLE; + + return errorstate; + } + + /* Get max delay value */ + maxdelay = 120000 / (((hsd->Instance->CLKCR) & 0xFF) + 2); + + if((SDIO_GetResponse(hsd->Instance, SDIO_RESP1) & SD_CARD_LOCKED) == SD_CARD_LOCKED) + { + errorstate = SD_LOCK_UNLOCK_FAILED; + + return errorstate; + } + + /* Get start and end block for high capacity cards */ + if (hsd->CardType == HIGH_CAPACITY_SD_CARD) + { + startaddr /= 512; + endaddr /= 512; + } + + /* According to sd-card spec 1.0 ERASE_GROUP_START (CMD32) and erase_group_end(CMD33) */ + if ((hsd->CardType == STD_CAPACITY_SD_CARD_V1_1) || (hsd->CardType == STD_CAPACITY_SD_CARD_V2_0) ||\ + (hsd->CardType == HIGH_CAPACITY_SD_CARD)) + { + /* Send CMD32 SD_ERASE_GRP_START with argument as addr */ + sdmmc_cmdinitstructure.Argument =(uint32_t)startaddr; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_ERASE_GRP_START; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SD_ERASE_GRP_START); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Send CMD33 SD_ERASE_GRP_END with argument as addr */ + sdmmc_cmdinitstructure.Argument = (uint32_t)endaddr; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_ERASE_GRP_END; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SD_ERASE_GRP_END); + + if (errorstate != SD_OK) + { + return errorstate; + } + } + + /* Send CMD38 ERASE */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_ERASE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_ERASE); + + if (errorstate != SD_OK) + { + return errorstate; + } + + for (; delay < maxdelay; delay++) + { + } + + /* Wait until the card is in programming state */ + errorstate = SD_IsCardProgramming(hsd, &cardstate); + + delay = SD_DATATIMEOUT; + + while ((delay > 0) && (errorstate == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) || (cardstate == SD_CARD_RECEIVING))) + { + errorstate = SD_IsCardProgramming(hsd, &cardstate); + delay--; + } + + return errorstate; +} + +/** + * @brief This function handles SD card interrupt request. + * @param hsd: SD handle + * @retval None + */ +void HAL_SD_IRQHandler(SD_HandleTypeDef *hsd) +{ + /* Check for SDIO interrupt flags */ + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_IT_DATAEND)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_IT_DATAEND); + + /* SD transfer is complete */ + hsd->SdTransferCplt = 1; + + /* No transfer error */ + hsd->SdTransferErr = SD_OK; + + HAL_SD_XferCpltCallback(hsd); + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_IT_DCRCFAIL)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DCRCFAIL); + + hsd->SdTransferErr = SD_DATA_CRC_FAIL; + + HAL_SD_XferErrorCallback(hsd); + + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_IT_DTIMEOUT)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DTIMEOUT); + + hsd->SdTransferErr = SD_DATA_TIMEOUT; + + HAL_SD_XferErrorCallback(hsd); + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_IT_RXOVERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_RXOVERR); + + hsd->SdTransferErr = SD_RX_OVERRUN; + + HAL_SD_XferErrorCallback(hsd); + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_IT_TXUNDERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_TXUNDERR); + + hsd->SdTransferErr = SD_TX_UNDERRUN; + + HAL_SD_XferErrorCallback(hsd); + } + else + { + /* No error flag set */ + } + + /* Disable all SDIO peripheral interrupt sources */ + __HAL_SD_SDIO_DISABLE_IT(hsd, SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND |\ + SDIO_IT_TXFIFOHE | SDIO_IT_RXFIFOHF | SDIO_IT_TXUNDERR |\ + SDIO_IT_RXOVERR); +} + + +/** + * @brief SD end of transfer callback. + * @param hsd: SD handle + * @retval None + */ +__weak void HAL_SD_XferCpltCallback(SD_HandleTypeDef *hsd) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_XferCpltCallback could be implemented in the user file + */ +} + +/** + * @brief SD Transfer Error callback. + * @param hsd: SD handle + * @retval None + */ +__weak void HAL_SD_XferErrorCallback(SD_HandleTypeDef *hsd) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_XferErrorCallback could be implemented in the user file + */ +} + +/** + * @brief SD Transfer complete Rx callback in non blocking mode. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +__weak void HAL_SD_DMA_RxCpltCallback(DMA_HandleTypeDef *hdma) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_DMA_RxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief SD DMA transfer complete Rx error callback. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +__weak void HAL_SD_DMA_RxErrorCallback(DMA_HandleTypeDef *hdma) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_DMA_RxErrorCallback could be implemented in the user file + */ +} + +/** + * @brief SD Transfer complete Tx callback in non blocking mode. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +__weak void HAL_SD_DMA_TxCpltCallback(DMA_HandleTypeDef *hdma) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_DMA_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief SD DMA transfer complete error Tx callback. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +__weak void HAL_SD_DMA_TxErrorCallback(DMA_HandleTypeDef *hdma) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_SD_DMA_TxErrorCallback could be implemented in the user file + */ +} + +/** + * @} + */ + +/** @addtogroup SD_Exported_Functions_Group3 + * @brief management functions + * +@verbatim + ============================================================================== + ##### Peripheral Control functions ##### + ============================================================================== + [..] + This subsection provides a set of functions allowing to control the SD card + operations. + +@endverbatim + * @{ + */ + +/** + * @brief Returns information about specific card. + * @param hsd: SD handle + * @param pCardInfo: Pointer to a HAL_SD_CardInfoTypedef structure that + * contains all SD cardinformation + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_Get_CardInfo(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypedef *pCardInfo) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t tmp = 0; + + pCardInfo->CardType = (uint8_t)(hsd->CardType); + pCardInfo->RCA = (uint16_t)(hsd->RCA); + + /* Byte 0 */ + tmp = (hsd->CSD[0] & 0xFF000000) >> 24; + pCardInfo->SD_csd.CSDStruct = (uint8_t)((tmp & 0xC0) >> 6); + pCardInfo->SD_csd.SysSpecVersion = (uint8_t)((tmp & 0x3C) >> 2); + pCardInfo->SD_csd.Reserved1 = tmp & 0x03; + + /* Byte 1 */ + tmp = (hsd->CSD[0] & 0x00FF0000) >> 16; + pCardInfo->SD_csd.TAAC = (uint8_t)tmp; + + /* Byte 2 */ + tmp = (hsd->CSD[0] & 0x0000FF00) >> 8; + pCardInfo->SD_csd.NSAC = (uint8_t)tmp; + + /* Byte 3 */ + tmp = hsd->CSD[0] & 0x000000FF; + pCardInfo->SD_csd.MaxBusClkFrec = (uint8_t)tmp; + + /* Byte 4 */ + tmp = (hsd->CSD[1] & 0xFF000000) >> 24; + pCardInfo->SD_csd.CardComdClasses = (uint16_t)(tmp << 4); + + /* Byte 5 */ + tmp = (hsd->CSD[1] & 0x00FF0000) >> 16; + pCardInfo->SD_csd.CardComdClasses |= (uint16_t)((tmp & 0xF0) >> 4); + pCardInfo->SD_csd.RdBlockLen = (uint8_t)(tmp & 0x0F); + + /* Byte 6 */ + tmp = (hsd->CSD[1] & 0x0000FF00) >> 8; + pCardInfo->SD_csd.PartBlockRead = (uint8_t)((tmp & 0x80) >> 7); + pCardInfo->SD_csd.WrBlockMisalign = (uint8_t)((tmp & 0x40) >> 6); + pCardInfo->SD_csd.RdBlockMisalign = (uint8_t)((tmp & 0x20) >> 5); + pCardInfo->SD_csd.DSRImpl = (uint8_t)((tmp & 0x10) >> 4); + pCardInfo->SD_csd.Reserved2 = 0; /*!< Reserved */ + + if ((hsd->CardType == STD_CAPACITY_SD_CARD_V1_1) || (hsd->CardType == STD_CAPACITY_SD_CARD_V2_0)) + { + pCardInfo->SD_csd.DeviceSize = (tmp & 0x03) << 10; + + /* Byte 7 */ + tmp = (uint8_t)(hsd->CSD[1] & 0x000000FF); + pCardInfo->SD_csd.DeviceSize |= (tmp) << 2; + + /* Byte 8 */ + tmp = (uint8_t)((hsd->CSD[2] & 0xFF000000) >> 24); + pCardInfo->SD_csd.DeviceSize |= (tmp & 0xC0) >> 6; + + pCardInfo->SD_csd.MaxRdCurrentVDDMin = (tmp & 0x38) >> 3; + pCardInfo->SD_csd.MaxRdCurrentVDDMax = (tmp & 0x07); + + /* Byte 9 */ + tmp = (uint8_t)((hsd->CSD[2] & 0x00FF0000) >> 16); + pCardInfo->SD_csd.MaxWrCurrentVDDMin = (tmp & 0xE0) >> 5; + pCardInfo->SD_csd.MaxWrCurrentVDDMax = (tmp & 0x1C) >> 2; + pCardInfo->SD_csd.DeviceSizeMul = (tmp & 0x03) << 1; + /* Byte 10 */ + tmp = (uint8_t)((hsd->CSD[2] & 0x0000FF00) >> 8); + pCardInfo->SD_csd.DeviceSizeMul |= (tmp & 0x80) >> 7; + + pCardInfo->CardCapacity = (pCardInfo->SD_csd.DeviceSize + 1) ; + pCardInfo->CardCapacity *= (1 << (pCardInfo->SD_csd.DeviceSizeMul + 2)); + pCardInfo->CardBlockSize = 1 << (pCardInfo->SD_csd.RdBlockLen); + pCardInfo->CardCapacity *= pCardInfo->CardBlockSize; + } + else if (hsd->CardType == HIGH_CAPACITY_SD_CARD) + { + /* Byte 7 */ + tmp = (uint8_t)(hsd->CSD[1] & 0x000000FF); + pCardInfo->SD_csd.DeviceSize = (tmp & 0x3F) << 16; + + /* Byte 8 */ + tmp = (uint8_t)((hsd->CSD[2] & 0xFF000000) >> 24); + + pCardInfo->SD_csd.DeviceSize |= (tmp << 8); + + /* Byte 9 */ + tmp = (uint8_t)((hsd->CSD[2] & 0x00FF0000) >> 16); + + pCardInfo->SD_csd.DeviceSize |= (tmp); + + /* Byte 10 */ + tmp = (uint8_t)((hsd->CSD[2] & 0x0000FF00) >> 8); + + pCardInfo->CardCapacity = (uint64_t)((((uint64_t)pCardInfo->SD_csd.DeviceSize + 1)) * 512 * 1024); + pCardInfo->CardBlockSize = 512; + } + else + { + /* Not supported card type */ + errorstate = SD_ERROR; + } + + pCardInfo->SD_csd.EraseGrSize = (tmp & 0x40) >> 6; + pCardInfo->SD_csd.EraseGrMul = (tmp & 0x3F) << 1; + + /* Byte 11 */ + tmp = (uint8_t)(hsd->CSD[2] & 0x000000FF); + pCardInfo->SD_csd.EraseGrMul |= (tmp & 0x80) >> 7; + pCardInfo->SD_csd.WrProtectGrSize = (tmp & 0x7F); + + /* Byte 12 */ + tmp = (uint8_t)((hsd->CSD[3] & 0xFF000000) >> 24); + pCardInfo->SD_csd.WrProtectGrEnable = (tmp & 0x80) >> 7; + pCardInfo->SD_csd.ManDeflECC = (tmp & 0x60) >> 5; + pCardInfo->SD_csd.WrSpeedFact = (tmp & 0x1C) >> 2; + pCardInfo->SD_csd.MaxWrBlockLen = (tmp & 0x03) << 2; + + /* Byte 13 */ + tmp = (uint8_t)((hsd->CSD[3] & 0x00FF0000) >> 16); + pCardInfo->SD_csd.MaxWrBlockLen |= (tmp & 0xC0) >> 6; + pCardInfo->SD_csd.WriteBlockPaPartial = (tmp & 0x20) >> 5; + pCardInfo->SD_csd.Reserved3 = 0; + pCardInfo->SD_csd.ContentProtectAppli = (tmp & 0x01); + + /* Byte 14 */ + tmp = (uint8_t)((hsd->CSD[3] & 0x0000FF00) >> 8); + pCardInfo->SD_csd.FileFormatGrouop = (tmp & 0x80) >> 7; + pCardInfo->SD_csd.CopyFlag = (tmp & 0x40) >> 6; + pCardInfo->SD_csd.PermWrProtect = (tmp & 0x20) >> 5; + pCardInfo->SD_csd.TempWrProtect = (tmp & 0x10) >> 4; + pCardInfo->SD_csd.FileFormat = (tmp & 0x0C) >> 2; + pCardInfo->SD_csd.ECC = (tmp & 0x03); + + /* Byte 15 */ + tmp = (uint8_t)(hsd->CSD[3] & 0x000000FF); + pCardInfo->SD_csd.CSD_CRC = (tmp & 0xFE) >> 1; + pCardInfo->SD_csd.Reserved4 = 1; + + /* Byte 0 */ + tmp = (uint8_t)((hsd->CID[0] & 0xFF000000) >> 24); + pCardInfo->SD_cid.ManufacturerID = tmp; + + /* Byte 1 */ + tmp = (uint8_t)((hsd->CID[0] & 0x00FF0000) >> 16); + pCardInfo->SD_cid.OEM_AppliID = tmp << 8; + + /* Byte 2 */ + tmp = (uint8_t)((hsd->CID[0] & 0x000000FF00) >> 8); + pCardInfo->SD_cid.OEM_AppliID |= tmp; + + /* Byte 3 */ + tmp = (uint8_t)(hsd->CID[0] & 0x000000FF); + pCardInfo->SD_cid.ProdName1 = tmp << 24; + + /* Byte 4 */ + tmp = (uint8_t)((hsd->CID[1] & 0xFF000000) >> 24); + pCardInfo->SD_cid.ProdName1 |= tmp << 16; + + /* Byte 5 */ + tmp = (uint8_t)((hsd->CID[1] & 0x00FF0000) >> 16); + pCardInfo->SD_cid.ProdName1 |= tmp << 8; + + /* Byte 6 */ + tmp = (uint8_t)((hsd->CID[1] & 0x0000FF00) >> 8); + pCardInfo->SD_cid.ProdName1 |= tmp; + + /* Byte 7 */ + tmp = (uint8_t)(hsd->CID[1] & 0x000000FF); + pCardInfo->SD_cid.ProdName2 = tmp; + + /* Byte 8 */ + tmp = (uint8_t)((hsd->CID[2] & 0xFF000000) >> 24); + pCardInfo->SD_cid.ProdRev = tmp; + + /* Byte 9 */ + tmp = (uint8_t)((hsd->CID[2] & 0x00FF0000) >> 16); + pCardInfo->SD_cid.ProdSN = tmp << 24; + + /* Byte 10 */ + tmp = (uint8_t)((hsd->CID[2] & 0x0000FF00) >> 8); + pCardInfo->SD_cid.ProdSN |= tmp << 16; + + /* Byte 11 */ + tmp = (uint8_t)(hsd->CID[2] & 0x000000FF); + pCardInfo->SD_cid.ProdSN |= tmp << 8; + + /* Byte 12 */ + tmp = (uint8_t)((hsd->CID[3] & 0xFF000000) >> 24); + pCardInfo->SD_cid.ProdSN |= tmp; + + /* Byte 13 */ + tmp = (uint8_t)((hsd->CID[3] & 0x00FF0000) >> 16); + pCardInfo->SD_cid.Reserved1 |= (tmp & 0xF0) >> 4; + pCardInfo->SD_cid.ManufactDate = (tmp & 0x0F) << 8; + + /* Byte 14 */ + tmp = (uint8_t)((hsd->CID[3] & 0x0000FF00) >> 8); + pCardInfo->SD_cid.ManufactDate |= tmp; + + /* Byte 15 */ + tmp = (uint8_t)(hsd->CID[3] & 0x000000FF); + pCardInfo->SD_cid.CID_CRC = (tmp & 0xFE) >> 1; + pCardInfo->SD_cid.Reserved2 = 1; + + return errorstate; +} + +/** + * @brief Enables wide bus operation for the requested card if supported by + * card. + * @param hsd: SD handle + * @param WideMode: Specifies the SD card wide bus mode + * This parameter can be one of the following values: + * @arg SDIO_BUS_WIDE_8B: 8-bit data transfer (Only for MMC) + * @arg SDIO_BUS_WIDE_4B: 4-bit data transfer + * @arg SDIO_BUS_WIDE_1B: 1-bit data transfer + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_WideBusOperation_Config(SD_HandleTypeDef *hsd, uint32_t WideMode) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + SDIO_InitTypeDef tmpinit; + + /* MMC Card does not support this feature */ + if (hsd->CardType == MULTIMEDIA_CARD) + { + errorstate = SD_UNSUPPORTED_FEATURE; + + return errorstate; + } + else if ((hsd->CardType == STD_CAPACITY_SD_CARD_V1_1) || (hsd->CardType == STD_CAPACITY_SD_CARD_V2_0) ||\ + (hsd->CardType == HIGH_CAPACITY_SD_CARD)) + { + if (WideMode == SDIO_BUS_WIDE_8B) + { + errorstate = SD_UNSUPPORTED_FEATURE; + } + else if (WideMode == SDIO_BUS_WIDE_4B) + { + errorstate = SD_WideBus_Enable(hsd); + } + else if (WideMode == SDIO_BUS_WIDE_1B) + { + errorstate = SD_WideBus_Disable(hsd); + } + else + { + /* WideMode is not a valid argument*/ + errorstate = SD_INVALID_PARAMETER; + } + + if (errorstate == SD_OK) + { + /* Configure the SDIO peripheral */ + tmpinit.ClockEdge = hsd->Init.ClockEdge; + tmpinit.ClockBypass = hsd->Init.ClockBypass; + tmpinit.ClockPowerSave = hsd->Init.ClockPowerSave; + tmpinit.BusWide = WideMode; + tmpinit.HardwareFlowControl = hsd->Init.HardwareFlowControl; + tmpinit.ClockDiv = hsd->Init.ClockDiv; + SDIO_Init(hsd->Instance, tmpinit); + } + } + + return errorstate; +} + +/** + * @brief Aborts an ongoing data transfer. + * @param hsd: SD handle + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_StopTransfer(SD_HandleTypeDef *hsd) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + + /* Send CMD12 STOP_TRANSMISSION */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_STOP_TRANSMISSION; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_STOP_TRANSMISSION); + + return errorstate; +} + +/** + * @brief Switches the SD card to High Speed mode. + * This API must be used after "Transfer State" + * @note This operation should be followed by the configuration + * of PLL to have SDIOCK clock between 67 and 75 MHz + * @param hsd: SD handle + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_HighSpeed (SD_HandleTypeDef *hsd) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + SDIO_DataInitTypeDef sdmmc_datainitstructure; + + uint8_t SD_hs[64] = {0}; + uint32_t SD_scr[2] = {0, 0}; + uint32_t SD_SPEC = 0 ; + uint32_t count = 0, *tempbuff = (uint32_t *)SD_hs; + + /* Initialize the Data control register */ + hsd->Instance->DCTRL = 0; + + /* Get SCR Register */ + errorstate = SD_FindSCR(hsd, SD_scr); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Test the Version supported by the card*/ + SD_SPEC = (SD_scr[1] & 0x01000000) | (SD_scr[1] & 0x02000000); + + if (SD_SPEC != SD_ALLZERO) + { + /* Set Block Size for Card */ + sdmmc_cmdinitstructure.Argument = (uint32_t)64; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = 64; + sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_64B ; + sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO; + sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE; + SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure); + + /* Send CMD6 switch mode */ + sdmmc_cmdinitstructure.Argument = 0x80FFFF01; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_HS_SWITCH; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_HS_SWITCH); + + if (errorstate != SD_OK) + { + return errorstate; + } + + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND)) + { + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF)) + { + for (count = 0; count < 8; count++) + { + *(tempbuff + count) = SDIO_ReadFIFO(hsd->Instance); + } + + tempbuff += 8; + } + } + + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DTIMEOUT); + + errorstate = SD_DATA_TIMEOUT; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DCRCFAIL); + + errorstate = SD_DATA_CRC_FAIL; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_RXOVERR); + + errorstate = SD_RX_OVERRUN; + + return errorstate; + } + else + { + /* No error flag set */ + } + + count = SD_DATATIMEOUT; + + while ((__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXDAVL)) && (count > 0)) + { + *tempbuff = SDIO_ReadFIFO(hsd->Instance); + tempbuff++; + count--; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + /* Test if the switch mode HS is ok */ + if ((SD_hs[13]& 2) != 2) + { + errorstate = SD_UNSUPPORTED_FEATURE; + } + } + + return errorstate; +} + +/** + * @} + */ + +/** @addtogroup SD_Exported_Functions_Group4 + * @brief Peripheral State functions + * +@verbatim + ============================================================================== + ##### Peripheral State functions ##### + ============================================================================== + [..] + This subsection permits to get in runtime the status of the peripheral + and the data flow. + +@endverbatim + * @{ + */ + +/** + * @brief Returns the current SD card's status. + * @param hsd: SD handle + * @param pSDstatus: Pointer to the buffer that will contain the SD card status + * SD Status register) + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_SendSDStatus(SD_HandleTypeDef *hsd, uint32_t *pSDstatus) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + SDIO_DataInitTypeDef sdmmc_datainitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t count = 0; + + /* Check SD response */ + if ((SDIO_GetResponse(hsd->Instance, SDIO_RESP1) & SD_CARD_LOCKED) == SD_CARD_LOCKED) + { + errorstate = SD_LOCK_UNLOCK_FAILED; + + return errorstate; + } + + /* Set block size for card if it is not equal to current block size for card */ + sdmmc_cmdinitstructure.Argument = 64; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Send CMD55 */ + sdmmc_cmdinitstructure.Argument = (uint32_t)(hsd->RCA << 16); + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_CMD); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = 64; + sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_64B; + sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO; + sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE; + SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure); + + /* Send ACMD13 (SD_APP_STAUS) with argument as card's RCA */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_APP_STATUS; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SD_APP_STATUS); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Get status data */ + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND)) + { + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF)) + { + for (count = 0; count < 8; count++) + { + *(pSDstatus + count) = SDIO_ReadFIFO(hsd->Instance); + } + + pSDstatus += 8; + } + } + + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DTIMEOUT); + + errorstate = SD_DATA_TIMEOUT; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DCRCFAIL); + + errorstate = SD_DATA_CRC_FAIL; + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_RXOVERR); + + errorstate = SD_RX_OVERRUN; + + return errorstate; + } + else + { + /* No error flag set */ + } + + count = SD_DATATIMEOUT; + while ((__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXDAVL)) && (count > 0)) + { + *pSDstatus = SDIO_ReadFIFO(hsd->Instance); + pSDstatus++; + count--; + } + + /* Clear all the static status flags*/ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + return errorstate; +} + +/** + * @brief Gets the current sd card data status. + * @param hsd: SD handle + * @retval Data Transfer state + */ +HAL_SD_TransferStateTypedef HAL_SD_GetStatus(SD_HandleTypeDef *hsd) +{ + HAL_SD_CardStateTypedef cardstate = SD_CARD_TRANSFER; + + /* Get SD card state */ + cardstate = SD_GetState(hsd); + + /* Find SD status according to card state*/ + if (cardstate == SD_CARD_TRANSFER) + { + return SD_TRANSFER_OK; + } + else if(cardstate == SD_CARD_ERROR) + { + return SD_TRANSFER_ERROR; + } + else + { + return SD_TRANSFER_BUSY; + } +} + +/** + * @brief Gets the SD card status. + * @param hsd: SD handle + * @param pCardStatus: Pointer to the HAL_SD_CardStatusTypedef structure that + * will contain the SD card status information + * @retval SD Card error state + */ +HAL_SD_ErrorTypedef HAL_SD_GetCardStatus(SD_HandleTypeDef *hsd, HAL_SD_CardStatusTypedef *pCardStatus) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t tmp = 0; + uint32_t sd_status[16]; + + errorstate = HAL_SD_SendSDStatus(hsd, sd_status); + + if (errorstate != SD_OK) + { + return errorstate; + } + + /* Byte 0 */ + tmp = (sd_status[0] & 0xC0) >> 6; + pCardStatus->DAT_BUS_WIDTH = (uint8_t)tmp; + + /* Byte 0 */ + tmp = (sd_status[0] & 0x20) >> 5; + pCardStatus->SECURED_MODE = (uint8_t)tmp; + + /* Byte 2 */ + tmp = (sd_status[2] & 0xFF); + pCardStatus->SD_CARD_TYPE = (uint8_t)(tmp << 8); + + /* Byte 3 */ + tmp = (sd_status[3] & 0xFF); + pCardStatus->SD_CARD_TYPE |= (uint8_t)tmp; + + /* Byte 4 */ + tmp = (sd_status[4] & 0xFF); + pCardStatus->SIZE_OF_PROTECTED_AREA = (uint8_t)(tmp << 24); + + /* Byte 5 */ + tmp = (sd_status[5] & 0xFF); + pCardStatus->SIZE_OF_PROTECTED_AREA |= (uint8_t)(tmp << 16); + + /* Byte 6 */ + tmp = (sd_status[6] & 0xFF); + pCardStatus->SIZE_OF_PROTECTED_AREA |= (uint8_t)(tmp << 8); + + /* Byte 7 */ + tmp = (sd_status[7] & 0xFF); + pCardStatus->SIZE_OF_PROTECTED_AREA |= (uint8_t)tmp; + + /* Byte 8 */ + tmp = (sd_status[8] & 0xFF); + pCardStatus->SPEED_CLASS = (uint8_t)tmp; + + /* Byte 9 */ + tmp = (sd_status[9] & 0xFF); + pCardStatus->PERFORMANCE_MOVE = (uint8_t)tmp; + + /* Byte 10 */ + tmp = (sd_status[10] & 0xF0) >> 4; + pCardStatus->AU_SIZE = (uint8_t)tmp; + + /* Byte 11 */ + tmp = (sd_status[11] & 0xFF); + pCardStatus->ERASE_SIZE = (uint8_t)(tmp << 8); + + /* Byte 12 */ + tmp = (sd_status[12] & 0xFF); + pCardStatus->ERASE_SIZE |= (uint8_t)tmp; + + /* Byte 13 */ + tmp = (sd_status[13] & 0xFC) >> 2; + pCardStatus->ERASE_TIMEOUT = (uint8_t)tmp; + + /* Byte 13 */ + tmp = (sd_status[13] & 0x3); + pCardStatus->ERASE_OFFSET = (uint8_t)tmp; + + return errorstate; +} + +/** + * @} + */ + +/** + * @} + */ + +/* Private function ----------------------------------------------------------*/ +/** @addtogroup SD_Private_Functions + * @{ + */ + +/** + * @brief SD DMA transfer complete Rx callback. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SD_DMA_RxCplt(DMA_HandleTypeDef *hdma) +{ + SD_HandleTypeDef *hsd = (SD_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; + + /* DMA transfer is complete */ + hsd->DmaTransferCplt = 1; + +// /* Wait until SD transfer is complete */ +// while(hsd->SdTransferCplt == 0) +// { +// } +// +// /* Disable the DMA channel */ +// HAL_DMA_Abort(hdma); + + /* Transfer complete user callback */ + HAL_SD_DMA_RxCpltCallback(hsd->hdmarx); +} + +/** + * @brief SD DMA transfer Error Rx callback. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SD_DMA_RxError(DMA_HandleTypeDef *hdma) +{ + SD_HandleTypeDef *hsd = (SD_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; + + /* Transfer complete user callback */ + HAL_SD_DMA_RxErrorCallback(hsd->hdmarx); +} + +/** + * @brief SD DMA transfer complete Tx callback. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SD_DMA_TxCplt(DMA_HandleTypeDef *hdma) +{ + SD_HandleTypeDef *hsd = (SD_HandleTypeDef*)((DMA_HandleTypeDef*)hdma)->Parent; + + /* DMA transfer is complete */ + hsd->DmaTransferCplt = 1; + +// /* Wait until SD transfer is complete */ +// while(hsd->SdTransferCplt == 0) +// { +// } +// +// /* Disable the DMA channel */ +// HAL_DMA_Abort(hdma); + + /* Transfer complete user callback */ + HAL_SD_DMA_TxCpltCallback(hsd->hdmatx); +} + +/** + * @brief SD DMA transfer Error Tx callback. + * @param hdma: pointer to a DMA_HandleTypeDef structure that contains + * the configuration information for the specified DMA module. + * @retval None + */ +static void SD_DMA_TxError(DMA_HandleTypeDef *hdma) +{ + SD_HandleTypeDef *hsd = ( SD_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent; + + /* Transfer complete user callback */ + HAL_SD_DMA_TxErrorCallback(hsd->hdmatx); +} + +/** + * @brief Returns the SD current state. + * @param hsd: SD handle + * @retval SD card current state + */ +static HAL_SD_CardStateTypedef SD_GetState(SD_HandleTypeDef *hsd) +{ + uint32_t resp1 = 0; + + if (SD_SendStatus(hsd, &resp1) != SD_OK) + { + return SD_CARD_ERROR; + } + else + { + return (HAL_SD_CardStateTypedef)((resp1 >> 9) & 0x0F); + } +} + +/** + * @brief Initializes all cards or single card as the case may be Card(s) come + * into standby state. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_Initialize_Cards(SD_HandleTypeDef *hsd) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint16_t sd_rca = 1; + + if(SDIO_GetPowerState(hsd->Instance) == 0) /* Power off */ + { + errorstate = SD_REQUEST_NOT_APPLICABLE; + + return errorstate; + } + + if(hsd->CardType != SECURE_DIGITAL_IO_CARD) + { + /* Send CMD2 ALL_SEND_CID */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_ALL_SEND_CID; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_LONG; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp2Error(hsd); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Get Card identification number data */ + hsd->CID[0] = SDIO_GetResponse(hsd->Instance, SDIO_RESP1); + hsd->CID[1] = SDIO_GetResponse(hsd->Instance, SDIO_RESP2); + hsd->CID[2] = SDIO_GetResponse(hsd->Instance, SDIO_RESP3); + hsd->CID[3] = SDIO_GetResponse(hsd->Instance, SDIO_RESP4); + } + + if((hsd->CardType == STD_CAPACITY_SD_CARD_V1_1) || (hsd->CardType == STD_CAPACITY_SD_CARD_V2_0) ||\ + (hsd->CardType == SECURE_DIGITAL_IO_COMBO_CARD) || (hsd->CardType == HIGH_CAPACITY_SD_CARD)) + { + /* Send CMD3 SET_REL_ADDR with argument 0 */ + /* SD Card publishes its RCA. */ + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_REL_ADDR; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp6Error(hsd, SD_CMD_SET_REL_ADDR, &sd_rca); + + if(errorstate != SD_OK) + { + return errorstate; + } + } + + if (hsd->CardType != SECURE_DIGITAL_IO_CARD) + { + /* Get the SD card RCA */ + hsd->RCA = sd_rca; + + /* Send CMD9 SEND_CSD with argument as card's RCA */ + sdmmc_cmdinitstructure.Argument = (uint32_t)(hsd->RCA << 16); + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SEND_CSD; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_LONG; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp2Error(hsd); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Get Card Specific Data */ + hsd->CSD[0] = SDIO_GetResponse(hsd->Instance, SDIO_RESP1); + hsd->CSD[1] = SDIO_GetResponse(hsd->Instance, SDIO_RESP2); + hsd->CSD[2] = SDIO_GetResponse(hsd->Instance, SDIO_RESP3); + hsd->CSD[3] = SDIO_GetResponse(hsd->Instance, SDIO_RESP4); + } + + /* All cards are initialized */ + return errorstate; +} + +/** + * @brief Selects of Deselects the corresponding card. + * @param hsd: SD handle + * @param addr: Address of the card to be selected + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_Select_Deselect(SD_HandleTypeDef *hsd, uint64_t addr) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + + /* Send CMD7 SDIO_SEL_DESEL_CARD */ + sdmmc_cmdinitstructure.Argument = (uint32_t)addr; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SEL_DESEL_CARD; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SEL_DESEL_CARD); + + return errorstate; +} + +/** + * @brief Enquires cards about their operating voltage and configures clock + * controls and stores SD information that will be needed in future + * in the SD handle. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_PowerON(SD_HandleTypeDef *hsd) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + __IO HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t response = 0, count = 0, validvoltage = 0; + uint32_t sdtype = SD_STD_CAPACITY; + + /* Power ON Sequence -------------------------------------------------------*/ + /* Disable SDMMC Clock */ + __HAL_SD_SDIO_DISABLE(hsd); + + /* Set Power State to ON */ + SDIO_PowerState_ON(hsd->Instance); + + /* 1ms: required power up waiting time before starting the SD initialization + sequence */ + HAL_Delay(1); + + /* Enable SDMMC Clock */ + __HAL_SD_SDIO_ENABLE(hsd); + + /* CMD0: GO_IDLE_STATE -----------------------------------------------------*/ + /* No CMD response required */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_GO_IDLE_STATE; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_NO; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdError(hsd); + + if(errorstate != SD_OK) + { + /* CMD Response Timeout (wait for CMDSENT flag) */ + return errorstate; + } + + /* CMD8: SEND_IF_COND ------------------------------------------------------*/ + /* Send CMD8 to verify SD card interface operating condition */ + /* Argument: - [31:12]: Reserved (shall be set to '0') + - [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V) + - [7:0]: Check Pattern (recommended 0xAA) */ + /* CMD Response: R7 */ + sdmmc_cmdinitstructure.Argument = SD_CHECK_PATTERN; + sdmmc_cmdinitstructure.CmdIndex = SD_SDIO_SEND_IF_COND; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp7Error(hsd); + + if (errorstate == SD_OK) + { + /* SD Card 2.0 */ + FF_PRINTF( "It's a 2.0 card, check SDHC\n" ); + hsd->CardType = STD_CAPACITY_SD_CARD_V2_0; + sdtype = SD_HIGH_CAPACITY; + } + + /* Send CMD55 */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_CMD); + + /* If errorstate is Command Timeout, it is a MMC card */ + /* If errorstate is SD_OK it is a SD card: SD card 2.0 (voltage range mismatch) + or SD card 1.x */ + if(errorstate == SD_OK) + { + /* SD CARD */ + /* Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */ + while((!validvoltage) && (count < SD_MAX_VOLT_TRIAL)) + { + + /* SEND CMD55 APP_CMD with RCA as 0 */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_CMD); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Send CMD41 */ + sdmmc_cmdinitstructure.Argument = SD_VOLTAGE_WINDOW_SD | sdtype; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_APP_OP_COND; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp3Error(hsd); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Get command response */ + response = SDIO_GetResponse(hsd->Instance, SDIO_RESP1); + + /* Get operating voltage*/ + validvoltage = (((response >> 31) == 1) ? 1 : 0); + + if( ( count == 0 ) || ( validvoltage != 0 ) ) + { + FF_PRINTF("Voltage resp: %08x\n", response); + } + + count++; + } + + if(count >= SD_MAX_VOLT_TRIAL) + { + FF_PRINTF("Can not agree on Voltage\n"); + errorstate = SD_INVALID_VOLTRANGE; + + return errorstate; + } + + if((response & SD_HIGH_CAPACITY) == SD_HIGH_CAPACITY) /* (response &= SD_HIGH_CAPACITY) */ + { + hsd->CardType = HIGH_CAPACITY_SD_CARD; + } + + } /* else MMC Card */ + + return errorstate; +} + +/** + * @brief Turns the SDMMC output signals off. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_PowerOFF(SD_HandleTypeDef *hsd) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + + /* Set Power State to OFF */ + SDIO_PowerState_OFF(hsd->Instance); + + return errorstate; +} + +/** + * @brief Returns the current card's status. + * @param hsd: SD handle + * @param pCardStatus: pointer to the buffer that will contain the SD card + * status (Card Status register) + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_SendStatus(SD_HandleTypeDef *hsd, uint32_t *pCardStatus) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + + if(pCardStatus == NULL) + { + errorstate = SD_INVALID_PARAMETER; + + return errorstate; + } + + /* Send Status command */ + sdmmc_cmdinitstructure.Argument = (uint32_t)(hsd->RCA << 16); + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SEND_STATUS; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SEND_STATUS); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Get SD card status */ + *pCardStatus = SDIO_GetResponse(hsd->Instance, SDIO_RESP1); + + return errorstate; +} + +/** + * @brief Checks for error conditions for CMD0. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_CmdError(SD_HandleTypeDef *hsd) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; +// uint32_t timeout; + uint32_t tmp; + uint32_t ulStarted = xTaskGetTickCount( ); + uint32_t ulMaxTime = 200; + BaseType_t xHadTimeout = pdFALSE; + +// timeout = SDIO_CMD0TIMEOUT; + + tmp = __HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CMDSENT); + + while( tmp == 0 ) + { + tmp = __HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CMDSENT); + if( ( xTaskGetTickCount( ) - ulStarted ) >= ulMaxTime ) + { + xHadTimeout = pdTRUE; + break; + } + + } + + if( xHadTimeout != pdFALSE ) + { + errorstate = SD_CMD_RSP_TIMEOUT; + return errorstate; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + return errorstate; +} + +/** + * @brief Checks for error conditions for R7 response. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_CmdResp7Error(SD_HandleTypeDef *hsd) +{ + HAL_SD_ErrorTypedef errorstate = SD_ERROR; +// uint32_t timeout = SDIO_CMD0TIMEOUT; + uint32_t tmp; + uint32_t ulStarted = xTaskGetTickCount( ); + uint32_t ulMaxTime = 200; + BaseType_t xHadTimeout = pdFALSE; + + tmp = __HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT); + + while( tmp == 0 ) + { + tmp = __HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT); + if( ( xTaskGetTickCount( ) - ulStarted ) >= ulMaxTime ) + { + xHadTimeout = pdTRUE; + break; + } + } + + tmp = __HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CTIMEOUT); + + if( xHadTimeout != pdFALSE || tmp) + { + /* Card is not V2.0 compliant or card does not support the set voltage range */ + errorstate = SD_CMD_RSP_TIMEOUT; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CTIMEOUT); + + return errorstate; + } + + if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CMDREND)) + { + /* Card is SD V2.0 compliant */ + errorstate = SD_OK; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CMDREND); + + return errorstate; + } + + return errorstate; +} + +/** + * @brief Checks for error conditions for R1 response. + * @param hsd: SD handle + * @param SD_CMD: The sent command index + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_CmdResp1Error(SD_HandleTypeDef *hsd, uint8_t SD_CMD) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t response_r1; + uint32_t remaining_loops = 168000 * 50; + + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) + { + if( ( --remaining_loops ) == 0 ) + { + FF_PRINTF( "SD_CmdResp1Error: times out\n" ); + break; + } + } + + if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CTIMEOUT)) + { + errorstate = SD_CMD_RSP_TIMEOUT; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CTIMEOUT); + + return errorstate; + } + else if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL)) + { + errorstate = SD_CMD_CRC_FAIL; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CCRCFAIL); + + return errorstate; + } + + /* Check response received is of desired command */ + if(SDIO_GetCommandResponse(hsd->Instance) != SD_CMD) + { + errorstate = SD_ILLEGAL_CMD; + + return errorstate; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + /* We have received response, retrieve it for analysis */ + response_r1 = SDIO_GetResponse(hsd->Instance, SDIO_RESP1); + + if((response_r1 & SD_OCR_ERRORBITS) == SD_ALLZERO) + { + return errorstate; + } + + if((response_r1 & SD_OCR_ADDR_OUT_OF_RANGE) == SD_OCR_ADDR_OUT_OF_RANGE) + { + return(SD_ADDR_OUT_OF_RANGE); + } + + if((response_r1 & SD_OCR_ADDR_MISALIGNED) == SD_OCR_ADDR_MISALIGNED) + { + return(SD_ADDR_MISALIGNED); + } + + if((response_r1 & SD_OCR_BLOCK_LEN_ERR) == SD_OCR_BLOCK_LEN_ERR) + { + return(SD_BLOCK_LEN_ERR); + } + + if((response_r1 & SD_OCR_ERASE_SEQ_ERR) == SD_OCR_ERASE_SEQ_ERR) + { + return(SD_ERASE_SEQ_ERR); + } + + if((response_r1 & SD_OCR_BAD_ERASE_PARAM) == SD_OCR_BAD_ERASE_PARAM) + { + return(SD_BAD_ERASE_PARAM); + } + + if((response_r1 & SD_OCR_WRITE_PROT_VIOLATION) == SD_OCR_WRITE_PROT_VIOLATION) + { + return(SD_WRITE_PROT_VIOLATION); + } + + if((response_r1 & SD_OCR_LOCK_UNLOCK_FAILED) == SD_OCR_LOCK_UNLOCK_FAILED) + { + return(SD_LOCK_UNLOCK_FAILED); + } + + if((response_r1 & SD_OCR_COM_CRC_FAILED) == SD_OCR_COM_CRC_FAILED) + { + return(SD_COM_CRC_FAILED); + } + + if((response_r1 & SD_OCR_ILLEGAL_CMD) == SD_OCR_ILLEGAL_CMD) + { + return(SD_ILLEGAL_CMD); + } + + if((response_r1 & SD_OCR_CARD_ECC_FAILED) == SD_OCR_CARD_ECC_FAILED) + { + return(SD_CARD_ECC_FAILED); + } + + if((response_r1 & SD_OCR_CC_ERROR) == SD_OCR_CC_ERROR) + { + return(SD_CC_ERROR); + } + + if((response_r1 & SD_OCR_GENERAL_UNKNOWN_ERROR) == SD_OCR_GENERAL_UNKNOWN_ERROR) + { + return(SD_GENERAL_UNKNOWN_ERROR); + } + + if((response_r1 & SD_OCR_STREAM_READ_UNDERRUN) == SD_OCR_STREAM_READ_UNDERRUN) + { + return(SD_STREAM_READ_UNDERRUN); + } + + if((response_r1 & SD_OCR_STREAM_WRITE_OVERRUN) == SD_OCR_STREAM_WRITE_OVERRUN) + { + return(SD_STREAM_WRITE_OVERRUN); + } + + if((response_r1 & SD_OCR_CID_CSD_OVERWRITE) == SD_OCR_CID_CSD_OVERWRITE) + { + return(SD_CID_CSD_OVERWRITE); + } + + if((response_r1 & SD_OCR_WP_ERASE_SKIP) == SD_OCR_WP_ERASE_SKIP) + { + return(SD_WP_ERASE_SKIP); + } + + if((response_r1 & SD_OCR_CARD_ECC_DISABLED) == SD_OCR_CARD_ECC_DISABLED) + { + return(SD_CARD_ECC_DISABLED); + } + + if((response_r1 & SD_OCR_ERASE_RESET) == SD_OCR_ERASE_RESET) + { + return(SD_ERASE_RESET); + } + + if((response_r1 & SD_OCR_AKE_SEQ_ERROR) == SD_OCR_AKE_SEQ_ERROR) + { + return(SD_AKE_SEQ_ERROR); + } + + return errorstate; +} + +/** + * @brief Checks for error conditions for R3 (OCR) response. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_CmdResp3Error(SD_HandleTypeDef *hsd) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + + while (!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) + { + } + + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CTIMEOUT)) + { + errorstate = SD_CMD_RSP_TIMEOUT; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CTIMEOUT); + + return errorstate; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + return errorstate; +} + +/** + * @brief Checks for error conditions for R2 (CID or CSD) response. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_CmdResp2Error(SD_HandleTypeDef *hsd) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + + while (!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) + { + } + + if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CTIMEOUT)) + { + errorstate = SD_CMD_RSP_TIMEOUT; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CTIMEOUT); + + return errorstate; + } + else if (__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL)) + { + errorstate = SD_CMD_CRC_FAIL; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CCRCFAIL); + + return errorstate; + } + else + { + /* No error flag set */ + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + return errorstate; +} + +/** + * @brief Checks for error conditions for R6 (RCA) response. + * @param hsd: SD handle + * @param SD_CMD: The sent command index + * @param pRCA: Pointer to the variable that will contain the SD card relative + * address RCA + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_CmdResp6Error(SD_HandleTypeDef *hsd, uint8_t SD_CMD, uint16_t *pRCA) +{ + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t response_r1; + + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) + { + } + + if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CTIMEOUT)) + { + errorstate = SD_CMD_RSP_TIMEOUT; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CTIMEOUT); + + return errorstate; + } + else if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL)) + { + errorstate = SD_CMD_CRC_FAIL; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CCRCFAIL); + + return errorstate; + } + else + { + /* No error flag set */ + } + + /* Check response received is of desired command */ + if(SDIO_GetCommandResponse(hsd->Instance) != SD_CMD) + { + FF_PRINTF( "RESPCMD[2] = %08x cmd = %02x\n", hsd->Instance->RESPCMD, SD_CMD ); + errorstate = SD_ILLEGAL_CMD; + + return errorstate; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + /* We have received response, retrieve it. */ + response_r1 = SDIO_GetResponse(hsd->Instance, SDIO_RESP1); + + if((response_r1 & (SD_R6_GENERAL_UNKNOWN_ERROR | SD_R6_ILLEGAL_CMD | SD_R6_COM_CRC_FAILED)) == SD_ALLZERO) + { + *pRCA = (uint16_t) (response_r1 >> 16); + + return errorstate; + } + + if((response_r1 & SD_R6_GENERAL_UNKNOWN_ERROR) == SD_R6_GENERAL_UNKNOWN_ERROR) + { + return(SD_GENERAL_UNKNOWN_ERROR); + } + + if((response_r1 & SD_R6_ILLEGAL_CMD) == SD_R6_ILLEGAL_CMD) + { + FF_PRINTF( "response_r1 = %08x cmd = %02x\n", hsd->Instance->RESPCMD, SD_R6_ILLEGAL_CMD ); + return(SD_ILLEGAL_CMD); + } + + if((response_r1 & SD_R6_COM_CRC_FAILED) == SD_R6_COM_CRC_FAILED) + { + return(SD_COM_CRC_FAILED); + } + + return errorstate; +} + +/** + * @brief Enables the SDMMC wide bus mode. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_WideBus_Enable(SD_HandleTypeDef *hsd) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + + uint32_t scr[2] = {0, 0}; + + if((SDIO_GetResponse(hsd->Instance, SDIO_RESP1) & SD_CARD_LOCKED) == SD_CARD_LOCKED) + { + errorstate = SD_LOCK_UNLOCK_FAILED; + + return errorstate; + } + + /* Get SCR Register */ + errorstate = SD_FindSCR(hsd, scr); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* If requested card supports wide bus operation */ + if((scr[1] & SD_WIDE_BUS_SUPPORT) != SD_ALLZERO) + { + /* Send CMD55 APP_CMD with argument as card's RCA.*/ + sdmmc_cmdinitstructure.Argument = (uint32_t)(hsd->RCA << 16); + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_CMD); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Send ACMD6 APP_CMD with argument as 2 for wide bus mode */ + sdmmc_cmdinitstructure.Argument = 2; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_SD_SET_BUSWIDTH; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_SD_SET_BUSWIDTH); + + if(errorstate != SD_OK) + { + return errorstate; + } + + return errorstate; + } + else + { + errorstate = SD_REQUEST_NOT_APPLICABLE; + + return errorstate; + } +} + +/** + * @brief Disables the SDMMC wide bus mode. + * @param hsd: SD handle + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_WideBus_Disable(SD_HandleTypeDef *hsd) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + + uint32_t scr[2] = {0, 0}; + + if((SDIO_GetResponse(hsd->Instance, SDIO_RESP1) & SD_CARD_LOCKED) == SD_CARD_LOCKED) + { + errorstate = SD_LOCK_UNLOCK_FAILED; + + return errorstate; + } + + /* Get SCR Register */ + errorstate = SD_FindSCR(hsd, scr); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* If requested card supports 1 bit mode operation */ + if((scr[1] & SD_SINGLE_BUS_SUPPORT) != SD_ALLZERO) + { + /* Send CMD55 APP_CMD with argument as card's RCA */ + sdmmc_cmdinitstructure.Argument = (uint32_t)(hsd->RCA << 16); + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_CMD); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Send ACMD6 APP_CMD with argument as 0 for single bus mode */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_SD_SET_BUSWIDTH; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_SD_SET_BUSWIDTH); + + if(errorstate != SD_OK) + { + return errorstate; + } + + return errorstate; + } + else + { + errorstate = SD_REQUEST_NOT_APPLICABLE; + + return errorstate; + } +} + + +/** + * @brief Finds the SD card SCR register value. + * @param hsd: SD handle + * @param pSCR: pointer to the buffer that will contain the SCR value + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_FindSCR(SD_HandleTypeDef *hsd, uint32_t *pSCR) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + SDIO_DataInitTypeDef sdmmc_datainitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + uint32_t index = 0; + uint32_t tempscr[2] = {0, 0}; + + /* Set Block Size To 8 Bytes */ + /* Send CMD55 APP_CMD with argument as card's RCA */ + sdmmc_cmdinitstructure.Argument = (uint32_t)8; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SET_BLOCKLEN; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SET_BLOCKLEN); + + if(errorstate != SD_OK) + { + return errorstate; + } + + /* Send CMD55 APP_CMD with argument as card's RCA */ + sdmmc_cmdinitstructure.Argument = (uint32_t)((hsd->RCA) << 16); + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_APP_CMD; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_APP_CMD); + + if(errorstate != SD_OK) + { + return errorstate; + } + sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = 8; + sdmmc_datainitstructure.DataBlockSize = SDIO_DATABLOCK_SIZE_8B; + sdmmc_datainitstructure.TransferDir = SDIO_TRANSFER_DIR_TO_SDIO; + sdmmc_datainitstructure.TransferMode = SDIO_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDIO_DPSM_ENABLE; + SDIO_DataConfig(hsd->Instance, &sdmmc_datainitstructure); + + /* Send ACMD51 SD_APP_SEND_SCR with argument as 0 */ + sdmmc_cmdinitstructure.Argument = 0; + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SD_APP_SEND_SCR; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + /* Check for error conditions */ + errorstate = SD_CmdResp1Error(hsd, SD_CMD_SD_APP_SEND_SCR); + + if(errorstate != SD_OK) + { + return errorstate; + } + + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND)) + { + if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXDAVL)) + { + *(tempscr + index) = SDIO_ReadFIFO(hsd->Instance); + index++; + } + } + + if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DTIMEOUT); + + errorstate = SD_DATA_TIMEOUT; + + return errorstate; + } + else if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_DCRCFAIL); + + errorstate = SD_DATA_CRC_FAIL; + + return errorstate; + } + else if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_RXOVERR)) + { + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_RXOVERR); + + errorstate = SD_RX_OVERRUN; + + return errorstate; + } + else + { + /* No error flag set */ + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + *(pSCR + 1) = ((tempscr[0] & SD_0TO7BITS) << 24) | ((tempscr[0] & SD_8TO15BITS) << 8) |\ + ((tempscr[0] & SD_16TO23BITS) >> 8) | ((tempscr[0] & SD_24TO31BITS) >> 24); + + *(pSCR) = ((tempscr[1] & SD_0TO7BITS) << 24) | ((tempscr[1] & SD_8TO15BITS) << 8) |\ + ((tempscr[1] & SD_16TO23BITS) >> 8) | ((tempscr[1] & SD_24TO31BITS) >> 24); + + return errorstate; +} + +/** + * @brief Checks if the SD card is in programming state. + * @param hsd: SD handle + * @param pStatus: pointer to the variable that will contain the SD card state + * @retval SD Card error state + */ +static HAL_SD_ErrorTypedef SD_IsCardProgramming(SD_HandleTypeDef *hsd, uint8_t *pStatus) +{ + SDIO_CmdInitTypeDef sdmmc_cmdinitstructure; + HAL_SD_ErrorTypedef errorstate = SD_OK; + __IO uint32_t responseR1 = 0; + + sdmmc_cmdinitstructure.Argument = (uint32_t)(hsd->RCA << 16); + sdmmc_cmdinitstructure.CmdIndex = SD_CMD_SEND_STATUS; + sdmmc_cmdinitstructure.Response = SDIO_RESPONSE_SHORT; + sdmmc_cmdinitstructure.WaitForInterrupt = SDIO_WAIT_NO; + sdmmc_cmdinitstructure.CPSM = SDIO_CPSM_ENABLE; + SDIO_SendCommand(hsd->Instance, &sdmmc_cmdinitstructure); + + while(!__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)) + { + } + + if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CTIMEOUT)) + { + errorstate = SD_CMD_RSP_TIMEOUT; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CTIMEOUT); + + return errorstate; + } + else if(__HAL_SD_SDIO_GET_FLAG(hsd, SDIO_FLAG_CCRCFAIL)) + { + errorstate = SD_CMD_CRC_FAIL; + + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_FLAG_CCRCFAIL); + + return errorstate; + } + else + { + /* No error flag set */ + } + + /* Check response received is of desired command */ + if((uint32_t)SDIO_GetCommandResponse(hsd->Instance) != SD_CMD_SEND_STATUS) + { + FF_PRINTF( "RESPCMD[3] = %08x cmd = %02x\n", hsd->Instance->RESPCMD, SD_CMD_SEND_STATUS ); + errorstate = SD_ILLEGAL_CMD; + + return errorstate; + } + + /* Clear all the static flags */ + __HAL_SD_SDIO_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS); + + + /* We have received response, retrieve it for analysis */ + responseR1 = SDIO_GetResponse(hsd->Instance, SDIO_RESP1); + + /* Find out card status */ + *pStatus = (uint8_t)((responseR1 >> 9) & 0x0000000F); + + if((responseR1 & SD_OCR_ERRORBITS) == SD_ALLZERO) + { + return errorstate; + } + + if((responseR1 & SD_OCR_ADDR_OUT_OF_RANGE) == SD_OCR_ADDR_OUT_OF_RANGE) + { + return(SD_ADDR_OUT_OF_RANGE); + } + + if((responseR1 & SD_OCR_ADDR_MISALIGNED) == SD_OCR_ADDR_MISALIGNED) + { + return(SD_ADDR_MISALIGNED); + } + + if((responseR1 & SD_OCR_BLOCK_LEN_ERR) == SD_OCR_BLOCK_LEN_ERR) + { + return(SD_BLOCK_LEN_ERR); + } + + if((responseR1 & SD_OCR_ERASE_SEQ_ERR) == SD_OCR_ERASE_SEQ_ERR) + { + return(SD_ERASE_SEQ_ERR); + } + + if((responseR1 & SD_OCR_BAD_ERASE_PARAM) == SD_OCR_BAD_ERASE_PARAM) + { + return(SD_BAD_ERASE_PARAM); + } + + if((responseR1 & SD_OCR_WRITE_PROT_VIOLATION) == SD_OCR_WRITE_PROT_VIOLATION) + { + return(SD_WRITE_PROT_VIOLATION); + } + + if((responseR1 & SD_OCR_LOCK_UNLOCK_FAILED) == SD_OCR_LOCK_UNLOCK_FAILED) + { + return(SD_LOCK_UNLOCK_FAILED); + } + + if((responseR1 & SD_OCR_COM_CRC_FAILED) == SD_OCR_COM_CRC_FAILED) + { + return(SD_COM_CRC_FAILED); + } + + if((responseR1 & SD_OCR_ILLEGAL_CMD) == SD_OCR_ILLEGAL_CMD) + { + return(SD_ILLEGAL_CMD); + } + + if((responseR1 & SD_OCR_CARD_ECC_FAILED) == SD_OCR_CARD_ECC_FAILED) + { + return(SD_CARD_ECC_FAILED); + } + + if((responseR1 & SD_OCR_CC_ERROR) == SD_OCR_CC_ERROR) + { + return(SD_CC_ERROR); + } + + if((responseR1 & SD_OCR_GENERAL_UNKNOWN_ERROR) == SD_OCR_GENERAL_UNKNOWN_ERROR) + { + return(SD_GENERAL_UNKNOWN_ERROR); + } + + if((responseR1 & SD_OCR_STREAM_READ_UNDERRUN) == SD_OCR_STREAM_READ_UNDERRUN) + { + return(SD_STREAM_READ_UNDERRUN); + } + + if((responseR1 & SD_OCR_STREAM_WRITE_OVERRUN) == SD_OCR_STREAM_WRITE_OVERRUN) + { + return(SD_STREAM_WRITE_OVERRUN); + } + + if((responseR1 & SD_OCR_CID_CSD_OVERWRITE) == SD_OCR_CID_CSD_OVERWRITE) + { + return(SD_CID_CSD_OVERWRITE); + } + + if((responseR1 & SD_OCR_WP_ERASE_SKIP) == SD_OCR_WP_ERASE_SKIP) + { + return(SD_WP_ERASE_SKIP); + } + + if((responseR1 & SD_OCR_CARD_ECC_DISABLED) == SD_OCR_CARD_ECC_DISABLED) + { + return(SD_CARD_ECC_DISABLED); + } + + if((responseR1 & SD_OCR_ERASE_RESET) == SD_OCR_ERASE_RESET) + { + return(SD_ERASE_RESET); + } + + if((responseR1 & SD_OCR_AKE_SEQ_ERROR) == SD_OCR_AKE_SEQ_ERROR) + { + return(SD_AKE_SEQ_ERROR); + } + + return errorstate; +} + +/** + * @} + */ + +#endif /* HAL_SD_MODULE_ENABLED */ + +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/stm32f7xx_hal_sd.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/stm32f7xx_hal_sd.h new file mode 100644 index 000000000..ea76fbf70 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/STM32F7xx/stm32f7xx_hal_sd.h @@ -0,0 +1,788 @@ +/** + ****************************************************************************** + * @file stm32f7xx_hal_sd.h + * @author MCD Application Team + * @version V1.0.0 + * @date 12-May-2015 + * @brief Header file of SD HAL module. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7xx_HAL_SD_H +#define __STM32F7xx_HAL_SD_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_ll_sdmmc.h" + +/** @addtogroup STM32F7xx_HAL_Driver + * @{ + */ + +/** @defgroup SD SD + * @brief SD HAL module driver + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup SD_Exported_Types SD Exported Types + * @{ + */ + +/** @defgroup SD_Exported_Types_Group1 SD Handle Structure definition + * @{ + */ +#define SD_InitTypeDef SDMMC_InitTypeDef +#define SD_TypeDef SDMMC_TypeDef + +struct xSD_Handle; + +/* A function will be called at the start of a DMA action. */ +typedef void ( * SD_EventSetupFunctionTypeDef )( struct xSD_Handle * /* pxhandle */ ); + +/* This function is supposed to wait for an event: SDIO or DMA. + * Return non-zero if a timeout has been reached. */ +typedef uint32_t ( * SD_EventWaitFunctionTypeDef )( struct xSD_Handle * /* pxhandle */ ); + + +typedef struct xSD_Handle +{ + SD_TypeDef *Instance; /*!< SDMMC register base address */ + + SD_InitTypeDef Init; /*!< SD required parameters */ + + HAL_LockTypeDef Lock; /*!< SD locking object */ + + uint32_t CardType; /*!< SD card type */ + + uint32_t RCA; /*!< SD relative card address */ + + uint32_t CSD[4]; /*!< SD card specific data table */ + + uint32_t CID[4]; /*!< SD card identification number table */ + + __IO uint32_t SdTransferCplt; /*!< SD transfer complete flag in non blocking mode */ + + __IO uint32_t SdTransferErr; /*!< SD transfer error flag in non blocking mode */ + + __IO uint32_t DmaTransferCplt; /*!< SD DMA transfer complete flag */ + + __IO uint32_t SdOperation; /*!< SD transfer operation (read/write) */ + + DMA_HandleTypeDef *hdmarx; /*!< SD Rx DMA handle parameters */ + + DMA_HandleTypeDef *hdmatx; /*!< SD Tx DMA handle parameters */ + + SD_EventSetupFunctionTypeDef EventSetupFunction; + + SD_EventWaitFunctionTypeDef EventWaitFunction; + +}SD_HandleTypeDef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group2 Card Specific Data: CSD Register + * @{ + */ +typedef struct +{ + __IO uint8_t CSDStruct; /*!< CSD structure */ + __IO uint8_t SysSpecVersion; /*!< System specification version */ + __IO uint8_t Reserved1; /*!< Reserved */ + __IO uint8_t TAAC; /*!< Data read access time 1 */ + __IO uint8_t NSAC; /*!< Data read access time 2 in CLK cycles */ + __IO uint8_t MaxBusClkFrec; /*!< Max. bus clock frequency */ + __IO uint16_t CardComdClasses; /*!< Card command classes */ + __IO uint8_t RdBlockLen; /*!< Max. read data block length */ + __IO uint8_t PartBlockRead; /*!< Partial blocks for read allowed */ + __IO uint8_t WrBlockMisalign; /*!< Write block misalignment */ + __IO uint8_t RdBlockMisalign; /*!< Read block misalignment */ + __IO uint8_t DSRImpl; /*!< DSR implemented */ + __IO uint8_t Reserved2; /*!< Reserved */ + __IO uint32_t DeviceSize; /*!< Device Size */ + __IO uint8_t MaxRdCurrentVDDMin; /*!< Max. read current @ VDD min */ + __IO uint8_t MaxRdCurrentVDDMax; /*!< Max. read current @ VDD max */ + __IO uint8_t MaxWrCurrentVDDMin; /*!< Max. write current @ VDD min */ + __IO uint8_t MaxWrCurrentVDDMax; /*!< Max. write current @ VDD max */ + __IO uint8_t DeviceSizeMul; /*!< Device size multiplier */ + __IO uint8_t EraseGrSize; /*!< Erase group size */ + __IO uint8_t EraseGrMul; /*!< Erase group size multiplier */ + __IO uint8_t WrProtectGrSize; /*!< Write protect group size */ + __IO uint8_t WrProtectGrEnable; /*!< Write protect group enable */ + __IO uint8_t ManDeflECC; /*!< Manufacturer default ECC */ + __IO uint8_t WrSpeedFact; /*!< Write speed factor */ + __IO uint8_t MaxWrBlockLen; /*!< Max. write data block length */ + __IO uint8_t WriteBlockPaPartial; /*!< Partial blocks for write allowed */ + __IO uint8_t Reserved3; /*!< Reserved */ + __IO uint8_t ContentProtectAppli; /*!< Content protection application */ + __IO uint8_t FileFormatGrouop; /*!< File format group */ + __IO uint8_t CopyFlag; /*!< Copy flag (OTP) */ + __IO uint8_t PermWrProtect; /*!< Permanent write protection */ + __IO uint8_t TempWrProtect; /*!< Temporary write protection */ + __IO uint8_t FileFormat; /*!< File format */ + __IO uint8_t ECC; /*!< ECC code */ + __IO uint8_t CSD_CRC; /*!< CSD CRC */ + __IO uint8_t Reserved4; /*!< Always 1 */ + +}HAL_SD_CSDTypedef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group3 Card Identification Data: CID Register + * @{ + */ +typedef struct +{ + __IO uint8_t ManufacturerID; /*!< Manufacturer ID */ + __IO uint16_t OEM_AppliID; /*!< OEM/Application ID */ + __IO uint32_t ProdName1; /*!< Product Name part1 */ + __IO uint8_t ProdName2; /*!< Product Name part2 */ + __IO uint8_t ProdRev; /*!< Product Revision */ + __IO uint32_t ProdSN; /*!< Product Serial Number */ + __IO uint8_t Reserved1; /*!< Reserved1 */ + __IO uint16_t ManufactDate; /*!< Manufacturing Date */ + __IO uint8_t CID_CRC; /*!< CID CRC */ + __IO uint8_t Reserved2; /*!< Always 1 */ + +}HAL_SD_CIDTypedef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group4 SD Card Status returned by ACMD13 + * @{ + */ +typedef struct +{ + __IO uint8_t DAT_BUS_WIDTH; /*!< Shows the currently defined data bus width */ + __IO uint8_t SECURED_MODE; /*!< Card is in secured mode of operation */ + __IO uint16_t SD_CARD_TYPE; /*!< Carries information about card type */ + __IO uint32_t SIZE_OF_PROTECTED_AREA; /*!< Carries information about the capacity of protected area */ + __IO uint8_t SPEED_CLASS; /*!< Carries information about the speed class of the card */ + __IO uint8_t PERFORMANCE_MOVE; /*!< Carries information about the card's performance move */ + __IO uint8_t AU_SIZE; /*!< Carries information about the card's allocation unit size */ + __IO uint16_t ERASE_SIZE; /*!< Determines the number of AUs to be erased in one operation */ + __IO uint8_t ERASE_TIMEOUT; /*!< Determines the timeout for any number of AU erase */ + __IO uint8_t ERASE_OFFSET; /*!< Carries information about the erase offset */ + +}HAL_SD_CardStatusTypedef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group5 SD Card information structure + * @{ + */ +typedef struct +{ + HAL_SD_CSDTypedef SD_csd; /*!< SD card specific data register */ + HAL_SD_CIDTypedef SD_cid; /*!< SD card identification number register */ + uint64_t CardCapacity; /*!< Card capacity */ + uint32_t CardBlockSize; /*!< Card block size */ + uint16_t RCA; /*!< SD relative card address */ + uint8_t CardType; /*!< SD card type */ + +}HAL_SD_CardInfoTypedef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group6 SD Error status enumeration Structure definition + * @{ + */ +typedef enum +{ +/** + * @brief SD specific error defines + */ + SD_CMD_CRC_FAIL = (1), /*!< Command response received (but CRC check failed) */ + SD_DATA_CRC_FAIL = (2), /*!< Data block sent/received (CRC check failed) */ + SD_CMD_RSP_TIMEOUT = (3), /*!< Command response timeout */ + SD_DATA_TIMEOUT = (4), /*!< Data timeout */ + SD_TX_UNDERRUN = (5), /*!< Transmit FIFO underrun */ + SD_RX_OVERRUN = (6), /*!< Receive FIFO overrun */ + SD_START_BIT_ERR = (7), /*!< Start bit not detected on all data signals in wide bus mode */ + SD_CMD_OUT_OF_RANGE = (8), /*!< Command's argument was out of range. */ + SD_ADDR_MISALIGNED = (9), /*!< Misaligned address */ + SD_BLOCK_LEN_ERR = (10), /*!< Transferred block length is not allowed for the card or the number of transferred bytes does not match the block length */ + SD_ERASE_SEQ_ERR = (11), /*!< An error in the sequence of erase command occurs. */ + SD_BAD_ERASE_PARAM = (12), /*!< An invalid selection for erase groups */ + SD_WRITE_PROT_VIOLATION = (13), /*!< Attempt to program a write protect block */ + SD_LOCK_UNLOCK_FAILED = (14), /*!< Sequence or password error has been detected in unlock command or if there was an attempt to access a locked card */ + SD_COM_CRC_FAILED = (15), /*!< CRC check of the previous command failed */ + SD_ILLEGAL_CMD = (16), /*!< Command is not legal for the card state */ + SD_CARD_ECC_FAILED = (17), /*!< Card internal ECC was applied but failed to correct the data */ + SD_CC_ERROR = (18), /*!< Internal card controller error */ + SD_GENERAL_UNKNOWN_ERROR = (19), /*!< General or unknown error */ + SD_STREAM_READ_UNDERRUN = (20), /*!< The card could not sustain data transfer in stream read operation. */ + SD_STREAM_WRITE_OVERRUN = (21), /*!< The card could not sustain data programming in stream mode */ + SD_CID_CSD_OVERWRITE = (22), /*!< CID/CSD overwrite error */ + SD_WP_ERASE_SKIP = (23), /*!< Only partial address space was erased */ + SD_CARD_ECC_DISABLED = (24), /*!< Command has been executed without using internal ECC */ + SD_ERASE_RESET = (25), /*!< Erase sequence was cleared before executing because an out of erase sequence command was received */ + SD_AKE_SEQ_ERROR = (26), /*!< Error in sequence of authentication. */ + SD_INVALID_VOLTRANGE = (27), + SD_ADDR_OUT_OF_RANGE = (28), + SD_SWITCH_ERROR = (29), + SD_SDMMC_DISABLED = (30), + SD_SDMMC_FUNCTION_BUSY = (31), + SD_SDMMC_FUNCTION_FAILED = (32), + SD_SDMMC_UNKNOWN_FUNCTION = (33), + +/** + * @brief Standard error defines + */ + SD_INTERNAL_ERROR = (34), + SD_NOT_CONFIGURED = (35), + SD_REQUEST_PENDING = (36), + SD_REQUEST_NOT_APPLICABLE = (37), + SD_INVALID_PARAMETER = (38), + SD_UNSUPPORTED_FEATURE = (39), + SD_UNSUPPORTED_HW = (40), + SD_ERROR = (41), + SD_OK = (0) + +}HAL_SD_ErrorTypedef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group7 SD Transfer state enumeration structure + * @{ + */ +typedef enum +{ + SD_TRANSFER_OK = 0, /*!< Transfer success */ + SD_TRANSFER_BUSY = 1, /*!< Transfer is occurring */ + SD_TRANSFER_ERROR = 2 /*!< Transfer failed */ + +}HAL_SD_TransferStateTypedef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group8 SD Card State enumeration structure + * @{ + */ +typedef enum +{ + SD_CARD_READY = ((uint32_t)0x00000001), /*!< Card state is ready */ + SD_CARD_IDENTIFICATION = ((uint32_t)0x00000002), /*!< Card is in identification state */ + SD_CARD_STANDBY = ((uint32_t)0x00000003), /*!< Card is in standby state */ + SD_CARD_TRANSFER = ((uint32_t)0x00000004), /*!< Card is in transfer state */ + SD_CARD_SENDING = ((uint32_t)0x00000005), /*!< Card is sending an operation */ + SD_CARD_RECEIVING = ((uint32_t)0x00000006), /*!< Card is receiving operation information */ + SD_CARD_PROGRAMMING = ((uint32_t)0x00000007), /*!< Card is in programming state */ + SD_CARD_DISCONNECTED = ((uint32_t)0x00000008), /*!< Card is disconnected */ + SD_CARD_ERROR = ((uint32_t)0x000000FF) /*!< Card is in error state */ + +}HAL_SD_CardStateTypedef; +/** + * @} + */ + +/** @defgroup SD_Exported_Types_Group9 SD Operation enumeration structure + * @{ + */ +typedef enum +{ + SD_READ_SINGLE_BLOCK = 0, /*!< Read single block operation */ + SD_READ_MULTIPLE_BLOCK = 1, /*!< Read multiple blocks operation */ + SD_WRITE_SINGLE_BLOCK = 2, /*!< Write single block operation */ + SD_WRITE_MULTIPLE_BLOCK = 3 /*!< Write multiple blocks operation */ + +}HAL_SD_OperationTypedef; +/** + * @} + */ + +/** + * @} + */ + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup SD_Exported_Constants SD Exported Constants + * @{ + */ + +/** + * @brief SD Commands Index + */ +#define SD_CMD_GO_IDLE_STATE ((uint8_t)0) /*!< Resets the SD memory card. */ +#define SD_CMD_SEND_OP_COND ((uint8_t)1) /*!< Sends host capacity support information and activates the card's initialization process. */ +#define SD_CMD_ALL_SEND_CID ((uint8_t)2) /*!< Asks any card connected to the host to send the CID numbers on the CMD line. */ +#define SD_CMD_SET_REL_ADDR ((uint8_t)3) /*!< Asks the card to publish a new relative address (RCA). */ +#define SD_CMD_SET_DSR ((uint8_t)4) /*!< Programs the DSR of all cards. */ +#define SD_CMD_SDMMC_SEN_OP_COND ((uint8_t)5) /*!< Sends host capacity support information (HCS) and asks the accessed card to send its + operating condition register (OCR) content in the response on the CMD line. */ +#define SD_CMD_HS_SWITCH ((uint8_t)6) /*!< Checks switchable function (mode 0) and switch card function (mode 1). */ +#define SD_CMD_SEL_DESEL_CARD ((uint8_t)7) /*!< Selects the card by its own relative address and gets deselected by any other address */ +#define SD_CMD_HS_SEND_EXT_CSD ((uint8_t)8) /*!< Sends SD Memory Card interface condition, which includes host supply voltage information + and asks the card whether card supports voltage. */ +#define SD_CMD_SEND_CSD ((uint8_t)9) /*!< Addressed card sends its card specific data (CSD) on the CMD line. */ +#define SD_CMD_SEND_CID ((uint8_t)10) /*!< Addressed card sends its card identification (CID) on the CMD line. */ +#define SD_CMD_READ_DAT_UNTIL_STOP ((uint8_t)11) /*!< SD card doesn't support it. */ +#define SD_CMD_STOP_TRANSMISSION ((uint8_t)12) /*!< Forces the card to stop transmission. */ +#define SD_CMD_SEND_STATUS ((uint8_t)13) /*!< Addressed card sends its status register. */ +#define SD_CMD_HS_BUSTEST_READ ((uint8_t)14) +#define SD_CMD_GO_INACTIVE_STATE ((uint8_t)15) /*!< Sends an addressed card into the inactive state. */ +#define SD_CMD_SET_BLOCKLEN ((uint8_t)16) /*!< Sets the block length (in bytes for SDSC) for all following block commands + (read, write, lock). Default block length is fixed to 512 Bytes. Not effective + for SDHS and SDXC. */ +#define SD_CMD_READ_SINGLE_BLOCK ((uint8_t)17) /*!< Reads single block of size selected by SET_BLOCKLEN in case of SDSC, and a block of + fixed 512 bytes in case of SDHC and SDXC. */ +#define SD_CMD_READ_MULT_BLOCK ((uint8_t)18) /*!< Continuously transfers data blocks from card to host until interrupted by + STOP_TRANSMISSION command. */ +#define SD_CMD_HS_BUSTEST_WRITE ((uint8_t)19) /*!< 64 bytes tuning pattern is sent for SDR50 and SDR104. */ +#define SD_CMD_WRITE_DAT_UNTIL_STOP ((uint8_t)20) /*!< Speed class control command. */ +#define SD_CMD_SET_BLOCK_COUNT ((uint8_t)23) /*!< Specify block count for CMD18 and CMD25. */ +#define SD_CMD_WRITE_SINGLE_BLOCK ((uint8_t)24) /*!< Writes single block of size selected by SET_BLOCKLEN in case of SDSC, and a block of + fixed 512 bytes in case of SDHC and SDXC. */ +#define SD_CMD_WRITE_MULT_BLOCK ((uint8_t)25) /*!< Continuously writes blocks of data until a STOP_TRANSMISSION follows. */ +#define SD_CMD_PROG_CID ((uint8_t)26) /*!< Reserved for manufacturers. */ +#define SD_CMD_PROG_CSD ((uint8_t)27) /*!< Programming of the programmable bits of the CSD. */ +#define SD_CMD_SET_WRITE_PROT ((uint8_t)28) /*!< Sets the write protection bit of the addressed group. */ +#define SD_CMD_CLR_WRITE_PROT ((uint8_t)29) /*!< Clears the write protection bit of the addressed group. */ +#define SD_CMD_SEND_WRITE_PROT ((uint8_t)30) /*!< Asks the card to send the status of the write protection bits. */ +#define SD_CMD_SD_ERASE_GRP_START ((uint8_t)32) /*!< Sets the address of the first write block to be erased. (For SD card only). */ +#define SD_CMD_SD_ERASE_GRP_END ((uint8_t)33) /*!< Sets the address of the last write block of the continuous range to be erased. */ +#define SD_CMD_ERASE_GRP_START ((uint8_t)35) /*!< Sets the address of the first write block to be erased. Reserved for each command + system set by switch function command (CMD6). */ +#define SD_CMD_ERASE_GRP_END ((uint8_t)36) /*!< Sets the address of the last write block of the continuous range to be erased. + Reserved for each command system set by switch function command (CMD6). */ +#define SD_CMD_ERASE ((uint8_t)38) /*!< Reserved for SD security applications. */ +#define SD_CMD_FAST_IO ((uint8_t)39) /*!< SD card doesn't support it (Reserved). */ +#define SD_CMD_GO_IRQ_STATE ((uint8_t)40) /*!< SD card doesn't support it (Reserved). */ +#define SD_CMD_LOCK_UNLOCK ((uint8_t)42) /*!< Sets/resets the password or lock/unlock the card. The size of the data block is set by + the SET_BLOCK_LEN command. */ +#define SD_CMD_APP_CMD ((uint8_t)55) /*!< Indicates to the card that the next command is an application specific command rather + than a standard command. */ +#define SD_CMD_GEN_CMD ((uint8_t)56) /*!< Used either to transfer a data block to the card or to get a data block from the card + for general purpose/application specific commands. */ +#define SD_CMD_NO_CMD ((uint8_t)64) + +/** + * @brief Following commands are SD Card Specific commands. + * SDMMC_APP_CMD should be sent before sending these commands. + */ +#define SD_CMD_APP_SD_SET_BUSWIDTH ((uint8_t)6) /*!< (ACMD6) Defines the data bus width to be used for data transfer. The allowed data bus + widths are given in SCR register. */ +#define SD_CMD_SD_APP_STATUS ((uint8_t)13) /*!< (ACMD13) Sends the SD status. */ +#define SD_CMD_SD_APP_SEND_NUM_WRITE_BLOCKS ((uint8_t)22) /*!< (ACMD22) Sends the number of the written (without errors) write blocks. Responds with + 32bit+CRC data block. */ +#define SD_CMD_SD_APP_OP_COND ((uint8_t)41) /*!< (ACMD41) Sends host capacity support information (HCS) and asks the accessed card to + send its operating condition register (OCR) content in the response on the CMD line. */ +#define SD_CMD_SD_APP_SET_CLR_CARD_DETECT ((uint8_t)42) /*!< (ACMD42) Connects/Disconnects the 50 KOhm pull-up resistor on CD/DAT3 (pin 1) of the card. */ +#define SD_CMD_SD_APP_SEND_SCR ((uint8_t)51) /*!< Reads the SD Configuration Register (SCR). */ +#define SD_CMD_SDMMC_RW_DIRECT ((uint8_t)52) /*!< For SD I/O card only, reserved for security specification. */ +#define SD_CMD_SDMMC_RW_EXTENDED ((uint8_t)53) /*!< For SD I/O card only, reserved for security specification. */ + +/** + * @brief Following commands are SD Card Specific security commands. + * SD_CMD_APP_CMD should be sent before sending these commands. + */ +#define SD_CMD_SD_APP_GET_MKB ((uint8_t)43) /*!< For SD card only */ +#define SD_CMD_SD_APP_GET_MID ((uint8_t)44) /*!< For SD card only */ +#define SD_CMD_SD_APP_SET_CER_RN1 ((uint8_t)45) /*!< For SD card only */ +#define SD_CMD_SD_APP_GET_CER_RN2 ((uint8_t)46) /*!< For SD card only */ +#define SD_CMD_SD_APP_SET_CER_RES2 ((uint8_t)47) /*!< For SD card only */ +#define SD_CMD_SD_APP_GET_CER_RES1 ((uint8_t)48) /*!< For SD card only */ +#define SD_CMD_SD_APP_SECURE_READ_MULTIPLE_BLOCK ((uint8_t)18) /*!< For SD card only */ +#define SD_CMD_SD_APP_SECURE_WRITE_MULTIPLE_BLOCK ((uint8_t)25) /*!< For SD card only */ +#define SD_CMD_SD_APP_SECURE_ERASE ((uint8_t)38) /*!< For SD card only */ +#define SD_CMD_SD_APP_CHANGE_SECURE_AREA ((uint8_t)49) /*!< For SD card only */ +#define SD_CMD_SD_APP_SECURE_WRITE_MKB ((uint8_t)48) /*!< For SD card only */ + +/** + * @brief Supported SD Memory Cards + */ +#define STD_CAPACITY_SD_CARD_V1_1 ((uint32_t)0x00000000) +#define STD_CAPACITY_SD_CARD_V2_0 ((uint32_t)0x00000001) +#define HIGH_CAPACITY_SD_CARD ((uint32_t)0x00000002) +#define MULTIMEDIA_CARD ((uint32_t)0x00000003) +#define SECURE_DIGITAL_IO_CARD ((uint32_t)0x00000004) +#define HIGH_SPEED_MULTIMEDIA_CARD ((uint32_t)0x00000005) +#define SECURE_DIGITAL_IO_COMBO_CARD ((uint32_t)0x00000006) +#define HIGH_CAPACITY_MMC_CARD ((uint32_t)0x00000007) +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/** @defgroup SD_Exported_macros SD Exported Macros + * @brief macros to handle interrupts and specific clock configurations + * @{ + */ + +/** + * @brief Enable the SD device. + * @retval None + */ +#define __HAL_SD_SDMMC_ENABLE(__HANDLE__) __SDMMC_ENABLE((__HANDLE__)->Instance) + +/** + * @brief Disable the SD device. + * @retval None + */ +#define __HAL_SD_SDMMC_DISABLE(__HANDLE__) __SDMMC_DISABLE((__HANDLE__)->Instance) + +/** + * @brief Enable the SDMMC DMA transfer. + * @retval None + */ +#define __HAL_SD_SDMMC_DMA_ENABLE(__HANDLE__) __SDMMC_DMA_ENABLE((__HANDLE__)->Instance) + +/** + * @brief Disable the SDMMC DMA transfer. + * @retval None + */ +#define __HAL_SD_SDMMC_DMA_DISABLE(__HANDLE__) __SDMMC_DMA_DISABLE((__HANDLE__)->Instance) + +/** + * @brief Enable the SD device interrupt. + * @param __HANDLE__: SD Handle + * @param __INTERRUPT__: specifies the SDMMC interrupt sources to be enabled. + * This parameter can be one or a combination of the following values: + * @arg SDMMC_IT_CCRCFAIL: Command response received (CRC check failed) interrupt + * @arg SDMMC_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt + * @arg SDMMC_IT_CTIMEOUT: Command response timeout interrupt + * @arg SDMMC_IT_DTIMEOUT: Data timeout interrupt + * @arg SDMMC_IT_TXUNDERR: Transmit FIFO underrun error interrupt + * @arg SDMMC_IT_RXOVERR: Received FIFO overrun error interrupt + * @arg SDMMC_IT_CMDREND: Command response received (CRC check passed) interrupt + * @arg SDMMC_IT_CMDSENT: Command sent (no response required) interrupt + * @arg SDMMC_IT_DATAEND: Data end (data counter, SDIDCOUNT, is zero) interrupt + * @arg SDMMC_IT_DBCKEND: Data block sent/received (CRC check passed) interrupt + * @arg SDMMC_IT_CMDACT: Command transfer in progress interrupt + * @arg SDMMC_IT_TXACT: Data transmit in progress interrupt + * @arg SDMMC_IT_RXACT: Data receive in progress interrupt + * @arg SDMMC_IT_TXFIFOHE: Transmit FIFO Half Empty interrupt + * @arg SDMMC_IT_RXFIFOHF: Receive FIFO Half Full interrupt + * @arg SDMMC_IT_TXFIFOF: Transmit FIFO full interrupt + * @arg SDMMC_IT_RXFIFOF: Receive FIFO full interrupt + * @arg SDMMC_IT_TXFIFOE: Transmit FIFO empty interrupt + * @arg SDMMC_IT_RXFIFOE: Receive FIFO empty interrupt + * @arg SDMMC_IT_TXDAVL: Data available in transmit FIFO interrupt + * @arg SDMMC_IT_RXDAVL: Data available in receive FIFO interrupt + * @arg SDMMC_IT_SDIOIT: SD I/O interrupt received interrupt + * @retval None + */ +#define __HAL_SD_SDMMC_ENABLE_IT(__HANDLE__, __INTERRUPT__) __SDMMC_ENABLE_IT((__HANDLE__)->Instance, (__INTERRUPT__)) + +/** + * @brief Disable the SD device interrupt. + * @param __HANDLE__: SD Handle + * @param __INTERRUPT__: specifies the SDMMC interrupt sources to be disabled. + * This parameter can be one or a combination of the following values: + * @arg SDMMC_IT_CCRCFAIL: Command response received (CRC check failed) interrupt + * @arg SDMMC_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt + * @arg SDMMC_IT_CTIMEOUT: Command response timeout interrupt + * @arg SDMMC_IT_DTIMEOUT: Data timeout interrupt + * @arg SDMMC_IT_TXUNDERR: Transmit FIFO underrun error interrupt + * @arg SDMMC_IT_RXOVERR: Received FIFO overrun error interrupt + * @arg SDMMC_IT_CMDREND: Command response received (CRC check passed) interrupt + * @arg SDMMC_IT_CMDSENT: Command sent (no response required) interrupt + * @arg SDMMC_IT_DATAEND: Data end (data counter, SDIDCOUNT, is zero) interrupt + * @arg SDMMC_IT_DBCKEND: Data block sent/received (CRC check passed) interrupt + * @arg SDMMC_IT_CMDACT: Command transfer in progress interrupt + * @arg SDMMC_IT_TXACT: Data transmit in progress interrupt + * @arg SDMMC_IT_RXACT: Data receive in progress interrupt + * @arg SDMMC_IT_TXFIFOHE: Transmit FIFO Half Empty interrupt + * @arg SDMMC_IT_RXFIFOHF: Receive FIFO Half Full interrupt + * @arg SDMMC_IT_TXFIFOF: Transmit FIFO full interrupt + * @arg SDMMC_IT_RXFIFOF: Receive FIFO full interrupt + * @arg SDMMC_IT_TXFIFOE: Transmit FIFO empty interrupt + * @arg SDMMC_IT_RXFIFOE: Receive FIFO empty interrupt + * @arg SDMMC_IT_TXDAVL: Data available in transmit FIFO interrupt + * @arg SDMMC_IT_RXDAVL: Data available in receive FIFO interrupt + * @arg SDMMC_IT_SDIOIT: SD I/O interrupt received interrupt + * @retval None + */ +#define __HAL_SD_SDMMC_DISABLE_IT(__HANDLE__, __INTERRUPT__) __SDMMC_DISABLE_IT((__HANDLE__)->Instance, (__INTERRUPT__)) + +/** + * @brief Check whether the specified SD flag is set or not. + * @param __HANDLE__: SD Handle + * @param __FLAG__: specifies the flag to check. + * This parameter can be one of the following values: + * @arg SDMMC_FLAG_CCRCFAIL: Command response received (CRC check failed) + * @arg SDMMC_FLAG_DCRCFAIL: Data block sent/received (CRC check failed) + * @arg SDMMC_FLAG_CTIMEOUT: Command response timeout + * @arg SDMMC_FLAG_DTIMEOUT: Data timeout + * @arg SDMMC_FLAG_TXUNDERR: Transmit FIFO underrun error + * @arg SDMMC_FLAG_RXOVERR: Received FIFO overrun error + * @arg SDMMC_FLAG_CMDREND: Command response received (CRC check passed) + * @arg SDMMC_FLAG_CMDSENT: Command sent (no response required) + * @arg SDMMC_FLAG_DATAEND: Data end (data counter, SDIDCOUNT, is zero) + * @arg SDMMC_FLAG_DBCKEND: Data block sent/received (CRC check passed) + * @arg SDMMC_FLAG_CMDACT: Command transfer in progress + * @arg SDMMC_FLAG_TXACT: Data transmit in progress + * @arg SDMMC_FLAG_RXACT: Data receive in progress + * @arg SDMMC_FLAG_TXFIFOHE: Transmit FIFO Half Empty + * @arg SDMMC_FLAG_RXFIFOHF: Receive FIFO Half Full + * @arg SDMMC_FLAG_TXFIFOF: Transmit FIFO full + * @arg SDMMC_FLAG_RXFIFOF: Receive FIFO full + * @arg SDMMC_FLAG_TXFIFOE: Transmit FIFO empty + * @arg SDMMC_FLAG_RXFIFOE: Receive FIFO empty + * @arg SDMMC_FLAG_TXDAVL: Data available in transmit FIFO + * @arg SDMMC_FLAG_RXDAVL: Data available in receive FIFO + * @arg SDMMC_FLAG_SDIOIT: SD I/O interrupt received + * @retval The new state of SD FLAG (SET or RESET). + */ +#define __HAL_SD_SDMMC_GET_FLAG(__HANDLE__, __FLAG__) __SDMMC_GET_FLAG((__HANDLE__)->Instance, (__FLAG__)) + +/** + * @brief Clear the SD's pending flags. + * @param __HANDLE__: SD Handle + * @param __FLAG__: specifies the flag to clear. + * This parameter can be one or a combination of the following values: + * @arg SDMMC_FLAG_CCRCFAIL: Command response received (CRC check failed) + * @arg SDMMC_FLAG_DCRCFAIL: Data block sent/received (CRC check failed) + * @arg SDMMC_FLAG_CTIMEOUT: Command response timeout + * @arg SDMMC_FLAG_DTIMEOUT: Data timeout + * @arg SDMMC_FLAG_TXUNDERR: Transmit FIFO underrun error + * @arg SDMMC_FLAG_RXOVERR: Received FIFO overrun error + * @arg SDMMC_FLAG_CMDREND: Command response received (CRC check passed) + * @arg SDMMC_FLAG_CMDSENT: Command sent (no response required) + * @arg SDMMC_FLAG_DATAEND: Data end (data counter, SDIDCOUNT, is zero) + * @arg SDMMC_FLAG_DBCKEND: Data block sent/received (CRC check passed) + * @arg SDMMC_FLAG_SDIOIT: SD I/O interrupt received + * @retval None + */ +#define __HAL_SD_SDMMC_CLEAR_FLAG(__HANDLE__, __FLAG__) __SDMMC_CLEAR_FLAG((__HANDLE__)->Instance, (__FLAG__)) + +/** + * @brief Check whether the specified SD interrupt has occurred or not. + * @param __HANDLE__: SD Handle + * @param __INTERRUPT__: specifies the SDMMC interrupt source to check. + * This parameter can be one of the following values: + * @arg SDMMC_IT_CCRCFAIL: Command response received (CRC check failed) interrupt + * @arg SDMMC_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt + * @arg SDMMC_IT_CTIMEOUT: Command response timeout interrupt + * @arg SDMMC_IT_DTIMEOUT: Data timeout interrupt + * @arg SDMMC_IT_TXUNDERR: Transmit FIFO underrun error interrupt + * @arg SDMMC_IT_RXOVERR: Received FIFO overrun error interrupt + * @arg SDMMC_IT_CMDREND: Command response received (CRC check passed) interrupt + * @arg SDMMC_IT_CMDSENT: Command sent (no response required) interrupt + * @arg SDMMC_IT_DATAEND: Data end (data counter, SDIDCOUNT, is zero) interrupt + * @arg SDMMC_IT_DBCKEND: Data block sent/received (CRC check passed) interrupt + * @arg SDMMC_IT_CMDACT: Command transfer in progress interrupt + * @arg SDMMC_IT_TXACT: Data transmit in progress interrupt + * @arg SDMMC_IT_RXACT: Data receive in progress interrupt + * @arg SDMMC_IT_TXFIFOHE: Transmit FIFO Half Empty interrupt + * @arg SDMMC_IT_RXFIFOHF: Receive FIFO Half Full interrupt + * @arg SDMMC_IT_TXFIFOF: Transmit FIFO full interrupt + * @arg SDMMC_IT_RXFIFOF: Receive FIFO full interrupt + * @arg SDMMC_IT_TXFIFOE: Transmit FIFO empty interrupt + * @arg SDMMC_IT_RXFIFOE: Receive FIFO empty interrupt + * @arg SDMMC_IT_TXDAVL: Data available in transmit FIFO interrupt + * @arg SDMMC_IT_RXDAVL: Data available in receive FIFO interrupt + * @arg SDMMC_IT_SDIOIT: SD I/O interrupt received interrupt + * @retval The new state of SD IT (SET or RESET). + */ +#define __HAL_SD_SDMMC_GET_IT(__HANDLE__, __INTERRUPT__) __SDMMC_GET_IT((__HANDLE__)->Instance, (__INTERRUPT__)) + +/** + * @brief Clear the SD's interrupt pending bits. + * @param __HANDLE__ : SD Handle + * @param __INTERRUPT__: specifies the interrupt pending bit to clear. + * This parameter can be one or a combination of the following values: + * @arg SDMMC_IT_CCRCFAIL: Command response received (CRC check failed) interrupt + * @arg SDMMC_IT_DCRCFAIL: Data block sent/received (CRC check failed) interrupt + * @arg SDMMC_IT_CTIMEOUT: Command response timeout interrupt + * @arg SDMMC_IT_DTIMEOUT: Data timeout interrupt + * @arg SDMMC_IT_TXUNDERR: Transmit FIFO underrun error interrupt + * @arg SDMMC_IT_RXOVERR: Received FIFO overrun error interrupt + * @arg SDMMC_IT_CMDREND: Command response received (CRC check passed) interrupt + * @arg SDMMC_IT_CMDSENT: Command sent (no response required) interrupt + * @arg SDMMC_IT_DATAEND: Data end (data counter, SDMMC_DCOUNT, is zero) interrupt + * @arg SDMMC_IT_SDIOIT: SD I/O interrupt received interrupt + * @retval None + */ +#define __HAL_SD_SDMMC_CLEAR_IT(__HANDLE__, __INTERRUPT__) __SDMMC_CLEAR_IT((__HANDLE__)->Instance, (__INTERRUPT__)) +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ +/** @defgroup SD_Exported_Functions SD Exported Functions + * @{ + */ + +/** @defgroup SD_Exported_Functions_Group1 Initialization and de-initialization functions + * @{ + */ +HAL_SD_ErrorTypedef HAL_SD_Init(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypedef *SDCardInfo); +HAL_StatusTypeDef HAL_SD_DeInit (SD_HandleTypeDef *hsd); +void HAL_SD_MspInit(SD_HandleTypeDef *hsd); +void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd); +/** + * @} + */ + +/** @defgroup SD_Exported_Functions_Group2 Input and Output operation functions + * @{ + */ +/* Blocking mode: Polling */ +HAL_SD_ErrorTypedef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks); +HAL_SD_ErrorTypedef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks); +HAL_SD_ErrorTypedef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint64_t startaddr, uint64_t endaddr); + +/* Non-Blocking mode: Interrupt */ +void HAL_SD_IRQHandler(SD_HandleTypeDef *hsd); + +/* Callback in non blocking modes (DMA) */ +void HAL_SD_DMA_RxCpltCallback(DMA_HandleTypeDef *hdma); +void HAL_SD_DMA_RxErrorCallback(DMA_HandleTypeDef *hdma); +void HAL_SD_DMA_TxCpltCallback(DMA_HandleTypeDef *hdma); +void HAL_SD_DMA_TxErrorCallback(DMA_HandleTypeDef *hdma); +void HAL_SD_XferCpltCallback(SD_HandleTypeDef *hsd); +void HAL_SD_XferErrorCallback(SD_HandleTypeDef *hsd); + +/* Non-Blocking mode: DMA */ +HAL_SD_ErrorTypedef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pReadBuffer, uint64_t ReadAddr, uint32_t BlockSize, uint32_t NumberOfBlocks); +HAL_SD_ErrorTypedef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint32_t *pWriteBuffer, uint64_t WriteAddr, uint32_t BlockSize, uint32_t NumberOfBlocks); +HAL_SD_ErrorTypedef HAL_SD_CheckWriteOperation(SD_HandleTypeDef *hsd, uint32_t Timeout); +HAL_SD_ErrorTypedef HAL_SD_CheckReadOperation(SD_HandleTypeDef *hsd, uint32_t Timeout); +/** + * @} + */ + +/** @defgroup SD_Exported_Functions_Group3 Peripheral Control functions + * @{ + */ +HAL_SD_ErrorTypedef HAL_SD_Get_CardInfo(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypedef *pCardInfo); +HAL_SD_ErrorTypedef HAL_SD_WideBusOperation_Config(SD_HandleTypeDef *hsd, uint32_t WideMode); +HAL_SD_ErrorTypedef HAL_SD_StopTransfer(SD_HandleTypeDef *hsd); +HAL_SD_ErrorTypedef HAL_SD_HighSpeed (SD_HandleTypeDef *hsd); +/** + * @} + */ + +/* Peripheral State functions ************************************************/ +/** @defgroup SD_Exported_Functions_Group4 Peripheral State functions + * @{ + */ +HAL_SD_ErrorTypedef HAL_SD_SendSDStatus(SD_HandleTypeDef *hsd, uint32_t *pSDstatus); +HAL_SD_ErrorTypedef HAL_SD_GetCardStatus(SD_HandleTypeDef *hsd, HAL_SD_CardStatusTypedef *pCardStatus); +HAL_SD_TransferStateTypedef HAL_SD_GetStatus(SD_HandleTypeDef *hsd); +/** + * @} + */ + +/** + * @} + */ + +/* Private types -------------------------------------------------------------*/ +/** @defgroup SD_Private_Types SD Private Types + * @{ + */ + +/** + * @} + */ + +/* Private defines -----------------------------------------------------------*/ +/** @defgroup SD_Private_Defines SD Private Defines + * @{ + */ + +/** + * @} + */ + +/* Private variables ---------------------------------------------------------*/ +/** @defgroup SD_Private_Variables SD Private Variables + * @{ + */ + +/** + * @} + */ + +/* Private constants ---------------------------------------------------------*/ +/** @defgroup SD_Private_Constants SD Private Constants + * @{ + */ + +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup SD_Private_Macros SD Private Macros + * @{ + */ + +/** + * @} + */ + +/* Private functions prototypes ----------------------------------------------*/ +/** @defgroup SD_Private_Functions_Prototypes SD Private Functions Prototypes + * @{ + */ + +/** + * @} + */ + +/* Private functions ---------------------------------------------------------*/ +/** @defgroup SD_Private_Functions SD Private Functions + * @{ + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + + +#endif /* __STM32F7xx_HAL_SD_H */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/ff_sddisk.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/ff_sddisk.c new file mode 100644 index 000000000..f60913f43 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/ff_sddisk.c @@ -0,0 +1,894 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/* Standard includes. */ +#include +#include +#include +#include + +/* Xilinx library includes. */ +#include "xparameters.h" +#include "xil_types.h" +#include "xsdps.h" /* SD device driver */ +#include "xsdps_info.h" /* SD info */ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "portmacro.h" + +/* FreeRTOS+FAT includes. */ +#include "ff_headers.h" +#include "ff_sddisk.h" +#include "ff_sys.h" + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + #include "xil_exception.h" + #include "xscugic_hw.h" +#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ + +#include "uncached_memory.h" + +#define sdSIGNATURE 0x41404342 + +#ifndef ARRAY_SIZE + #define ARRAY_SIZE(x) (int) (sizeof(x)/sizeof(x)[0]) +#endif + +#define STA_NOINIT 0x01 /* Drive not initialized */ +#define STA_NODISK 0x02 /* No medium in the drive */ +#define STA_PROTECT 0x04 /* Write protected */ + +#define SD_DEVICE_ID XPAR_XSDPS_0_DEVICE_ID +#define HIGH_SPEED_SUPPORT 0x01 +#define WIDTH_4_BIT_SUPPORT 0x4 +#define SD_CLK_12_MHZ 12000000 +#define SD_CLK_25_MHZ 25000000 +#define SD_CLK_26_MHZ 26000000 +#define SD_CLK_52_MHZ 52000000 +#define EXT_CSD_DEVICE_TYPE_BYTE 196 +#define EXT_CSD_4_BIT_WIDTH_BYTE 183 +#define EXT_CSD_HIGH_SPEED_BYTE 185 +#define EXT_CSD_DEVICE_TYPE_HIGH_SPEED 0x3 + +#define HUNDRED_64_BIT 100ULL +#define BYTES_PER_MB ( 1024ull * 1024ull ) +#define SECTORS_PER_MB ( BYTES_PER_MB / 512ull ) + +#define XSDPS_INTR_NORMAL_ENABLE ( XSDPS_INTR_CC_MASK | XSDPS_INTR_TC_MASK | \ + XSDPS_INTR_DMA_MASK | XSDPS_INTR_CARD_INSRT_MASK | XSDPS_INTR_CARD_REM_MASK | \ + XSDPS_INTR_ERR_MASK ) + +/* Two defines used to set or clear the interrupt */ +#define INTC_BASE_ADDR XPAR_SCUGIC_CPU_BASEADDR +#define INTC_DIST_BASE_ADDR XPAR_SCUGIC_DIST_BASEADDR + +/* Interupt numbers for SDIO units 0 and 1: */ +#define SCUGIC_SDIO_0_INTR 0x38 +#define SCUGIC_SDIO_1_INTR 0x4F + +/* Define a timeout on data transfers for SDIO: */ +#define sdWAIT_INT_TIME_OUT_MS 5000UL + +/* Define a short timeout, used during card-detection only (CMD1): */ +#define sdQUICK_WAIT_INT_TIME_OUT_MS 1000UL + +/* XSdPs xSDCardInstance; */ +static XSdPs *pxSDCardInstance; + +static int sd_disk_status = STA_NOINIT; /* Disk status */ +const int drive_nr = 0; +static SemaphoreHandle_t xPlusFATMutex; +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + /* Create a semaphore for each of the two memory-card slots. */ + static SemaphoreHandle_t xSDSemaphores[ 2 ]; +#endif + +static int vSDMMC_Init( int iDriveNumber ); +static int vSDMMC_Status( int iDriveNumber ); + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + static void vInstallInterrupt( void ); +#endif + +struct xCACHE_MEMORY_INFO +{ + /* Reserve 'uncached' memory for caching sectors, will be passed to the +FAT library. */ + uint8_t pucCacheMemory[ 0x10000 ]; + /* Reserve 'uncached' memory for i/o to the SD-card. */ + uint8_t pucHelpMemory[ 0x40000 ]; + XSdPs xSDCardInstance; +}; + +struct xCACHE_STATS +{ + uint32_t xMemcpyReadCount; + uint32_t xMemcpyWriteCount; + uint32_t xPassReadCount; + uint32_t xPassWriteCount; + uint32_t xFailReadCount; + uint32_t xFailWriteCount; +}; + +struct xCACHE_STATS xCacheStats; +struct xCACHE_MEMORY_INFO *pxCacheMem = NULL; + +static const uint8_t *prvStoreSDCardData( const uint8_t *pucBuffer, uint32_t ulByteCount ); +static uint8_t *prvReadSDCardData( uint8_t *pucBuffer, uint32_t ulByteCount ); + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + void XSdPs_IntrHandler(void *XSdPsPtr); +#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ + +static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ) +{ +int32_t lReturnCode; +int iResult; +uint8_t *pucReadBuffer; + + if( ( pxDisk != NULL ) && /*_RB_ Could this be changed to an assert? */ + ( pxDisk->ulSignature == sdSIGNATURE ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( ulSectorNumber < pxDisk->ulNumberOfSectors ) && + ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) + { + iResult = vSDMMC_Status( drive_nr ); + if( ( iResult & STA_NODISK ) != 0 ) + { + lReturnCode = FF_ERR_DRIVER_NOMEDIUM | FF_ERRFLAG; + FF_PRINTF( "prvFFRead: NOMEDIUM\n" ); + } + else if( ( iResult & STA_NOINIT ) != 0 ) + { + lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG; + FF_PRINTF( "prvFFRead: NOINIT\n" ); + } + else if( ulSectorCount == 0ul ) + { + lReturnCode = 0; + } + else + { + /* Convert LBA to byte address if needed */ + if( pxSDCardInstance->HCS == 0 ) + { + ulSectorNumber *= XSDPS_BLK_SIZE_512_MASK; + } + + pucReadBuffer = prvReadSDCardData( pucBuffer, 512UL * ulSectorCount ); + + if( ucIsCachedMemory( pucReadBuffer ) != pdFALSE ) + { + xCacheStats.xFailReadCount++; + } + + iResult = XSdPs_ReadPolled( pxSDCardInstance, ulSectorNumber, ulSectorCount, pucReadBuffer ); + if( pucBuffer != pucReadBuffer ) + { + xCacheStats.xMemcpyReadCount++; + memcpy( pucBuffer, pucReadBuffer, 512 * ulSectorCount ); + } + else + { + xCacheStats.xPassReadCount++; + } + if( iResult == XST_SUCCESS ) + { + lReturnCode = 0l; + } + else + { + lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG; + } + } + } + else + { + memset( ( void *) pucBuffer, '\0', ulSectorCount * 512 ); + + if( pxDisk->xStatus.bIsInitialised != pdFALSE ) + { + FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors ); + } + + lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG; + } + + return lReturnCode; +} +/*-----------------------------------------------------------*/ + +static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ) +{ +int32_t lReturnCode; + + if( ( pxDisk != NULL ) && + ( pxDisk->ulSignature == sdSIGNATURE ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( ulSectorNumber < pxDisk->ulNumberOfSectors ) && + ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) ) + { + int iResult; + iResult = vSDMMC_Status(drive_nr); + + if( ( iResult & STA_NODISK ) != 0 ) + { + lReturnCode = FF_ERR_DRIVER_NOMEDIUM | FF_ERRFLAG; + FF_PRINTF( "prvFFWrite: NOMEDIUM\n" ); + } + else if( ( iResult & STA_NOINIT ) != 0 ) + { + lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG; + FF_PRINTF( "prvFFWrite: NOINIT\n" ); + } + else + { + if( ulSectorCount == 0ul ) + { + lReturnCode = 0l; + } + else + { + /* Convert LBA to byte address if needed */ + if (!(pxSDCardInstance->HCS)) ulSectorNumber *= XSDPS_BLK_SIZE_512_MASK; + + pucBuffer = ( uint8_t * )prvStoreSDCardData( pucBuffer, 512UL * ulSectorCount ); + + if( ucIsCachedMemory( pucBuffer ) != pdFALSE ) + { + xCacheStats.xFailWriteCount++; + } + + iResult = XSdPs_WritePolled( pxSDCardInstance, ulSectorNumber, ulSectorCount, pucBuffer ); + + if( iResult == XST_SUCCESS ) + { + lReturnCode = 0; + } + else + { + FF_PRINTF( "prvFFWrite[%d]: at 0x%X count %ld : %d\n", + (int)drive_nr, (unsigned)ulSectorNumber, ulSectorCount, iResult ); + lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG; + } + } + } + } + else + { + lReturnCode = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG; + if( pxDisk->xStatus.bIsInitialised ) + { + FF_PRINTF( "prvFFWrite::read: warning: %lu + %lu > %lu\n", + ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors ); + } + } + + return lReturnCode; +} +/*-----------------------------------------------------------*/ + +void FF_SDDiskFlush( FF_Disk_t *pxDisk ) +{ + if( ( pxDisk != NULL ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( pxDisk->pxIOManager != NULL ) ) + { + FF_FlushCache( pxDisk->pxIOManager ); + } +} +/*-----------------------------------------------------------*/ + +static const uint8_t *prvStoreSDCardData( const uint8_t *pucBuffer, uint32_t ulByteCount ) +{ +const uint8_t *pucReturn; + + if( ( ucIsCachedMemory( pucBuffer ) != pdFALSE ) && ( ulByteCount <= sizeof( pxCacheMem->pucHelpMemory ) ) ) + { + memcpy( pxCacheMem->pucHelpMemory, pucBuffer, ulByteCount ); + pucReturn = pxCacheMem->pucHelpMemory; + xCacheStats.xMemcpyWriteCount++; + } + else + { + pucReturn = pucBuffer; + xCacheStats.xPassWriteCount++; + } + + return pucReturn; +} +/*-----------------------------------------------------------*/ + +static uint8_t *prvReadSDCardData( uint8_t *pucBuffer, uint32_t ulByteCount ) +{ +uint8_t *pucReturn; + + if( ( ucIsCachedMemory( pucBuffer ) != pdFALSE ) && ( ulByteCount <= sizeof( pxCacheMem->pucHelpMemory ) ) ) + { + pucReturn = pxCacheMem->pucHelpMemory; + } + else + { + pucReturn = pucBuffer; + } + + return pucReturn; +} +/*-----------------------------------------------------------*/ + +static struct xCACHE_MEMORY_INFO *pucGetSDIOCacheMemory( ) +{ + if( pxCacheMem == NULL ) + { + pxCacheMem = ( struct xCACHE_MEMORY_INFO * ) pucGetUncachedMemory( sizeof( *pxCacheMem ) ); + memset( pxCacheMem, '\0', sizeof( *pxCacheMem ) ); + } + return pxCacheMem; +} +/*-----------------------------------------------------------*/ + +/* Initialise the SDIO driver and mount an SD card */ +FF_Disk_t *FF_SDDiskInit( const char *pcName ) +{ +FF_Error_t xFFError; +BaseType_t xPartitionNumber = 0; +FF_CreationParameters_t xParameters; +FF_Disk_t * pxDisk; +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + int iIndex; +#endif + + pucGetSDIOCacheMemory(); + + pxDisk = (FF_Disk_t *)pvPortMalloc( sizeof( *pxDisk ) ); + if( pxDisk == NULL ) + { + FF_PRINTF( "FF_SDDiskInit: Malloc failed\n" ); + } + else if( pxCacheMem == NULL ) + { + FF_PRINTF( "FF_SDDiskInit: Cached memory failed\n" ); + } + else + { + pxSDCardInstance = &( pxCacheMem->xSDCardInstance ); + + #if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + { + for( iIndex = 0; iIndex < ARRAY_SIZE( xSDSemaphores ); iIndex++ ) + { + if( xSDSemaphores[ iIndex ] == NULL ) + { + xSDSemaphores[ iIndex ] = xSemaphoreCreateBinary(); + configASSERT( xSDSemaphores[ iIndex ] != NULL ); + } + } + } + #endif + + vSDMMC_Init( 0 ); + + /* Initialise the created disk structure. */ + memset( pxDisk, '\0', sizeof( *pxDisk ) ); + + pxDisk->ulNumberOfSectors = myCSD.sd_last_block_address + 1; + + if( xPlusFATMutex == NULL ) + { + xPlusFATMutex = xSemaphoreCreateRecursiveMutex(); + } + pxDisk->ulSignature = sdSIGNATURE; + + if( xPlusFATMutex != NULL) + { + memset( &xParameters, '\0', sizeof( xParameters ) ); + xParameters.pucCacheMemory = pxCacheMem->pucCacheMemory; + xParameters.ulMemorySize = sizeof( pxCacheMem->pucCacheMemory ); + xParameters.ulSectorSize = 512; + xParameters.fnWriteBlocks = prvFFWrite; + xParameters.fnReadBlocks = prvFFRead; + xParameters.pxDisk = pxDisk; + + /* prvFFRead()/prvFFWrite() are not re-entrant and must be protected with + the use of a semaphore. */ + xParameters.xBlockDeviceIsReentrant = pdFALSE; + + /* The semaphore will be used to protect critical sections in the +FAT driver, + and also to avoid concurrent calls to prvFFRead()/prvFFWrite() from different tasks. */ + xParameters.pvSemaphore = ( void * ) xPlusFATMutex; + + pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError ); + if( pxDisk->pxIOManager == NULL ) + { + FF_PRINTF( "FF_SDDiskInit: FF_CreateIOManger: %s\n", (const char*)FF_GetErrMessage( xFFError ) ); + FF_SDDiskDelete( pxDisk ); + pxDisk = NULL; + } + else + { + pxDisk->xStatus.bIsInitialised = pdTRUE; + pxDisk->xStatus.bPartitionNumber = xPartitionNumber; + + if( FF_SDDiskMount( pxDisk ) == 0 ) + { + FF_SDDiskDelete( pxDisk ); + pxDisk = NULL; + } + else + { + if( pcName == NULL ) + { + pcName = "/"; + } + + FF_FS_Add( pcName, pxDisk ); + FF_PRINTF( "FF_SDDiskInit: Mounted SD-card as root \"%s\"\n", pcName ); + FF_SDDiskShowPartition( pxDisk ); + } + } + } + } + + return pxDisk; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskFormat( FF_Disk_t *pxDisk, BaseType_t aPart ) +{ +FF_Error_t xError; +BaseType_t xReturn = 0; + + FF_SDDiskUnmount( pxDisk ); + { + /* Format the drive */ + xError = FF_Format( pxDisk, aPart, pdFALSE, pdFALSE); // Try FAT32 with large clusters + if( FF_isERR( xError ) ) + { + FF_PRINTF( "FF_SDDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) ); + return 0; + } + else + { + FF_PRINTF( "FF_SDDiskFormat: OK, now remounting\n" ); + pxDisk->xStatus.bPartitionNumber = aPart; + xError = FF_SDDiskMount( pxDisk ); + FF_PRINTF( "FF_SDDiskFormat: rc %08x\n", ( unsigned )xError ); + if( FF_isERR( xError ) == pdFALSE ) + { + xReturn = 1; + FF_SDDiskShowPartition( pxDisk ); + } + } + } + return xReturn; +} +/*-----------------------------------------------------------*/ + +/* Unmount the volume */ +BaseType_t FF_SDDiskUnmount( FF_Disk_t *pxDisk ) +{ +FF_Error_t xFFError; +BaseType_t xReturn = 1; + + if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsMounted != pdFALSE ) ) + { + pxDisk->xStatus.bIsMounted = pdFALSE; + xFFError = FF_Unmount( pxDisk ); + FF_PRINTF( "FF_SDDiskUnmount: rc %08x\n", ( unsigned )xFFError ); + if( FF_isERR( xFFError ) ) + { + xReturn = 0; + } + else + { + FF_PRINTF( "Drive unmounted\n" ); + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskReinit( FF_Disk_t *pxDisk ) +{ +int iStatus = vSDMMC_Init( 0 ); /* Hard coded index. */ + + /*_RB_ parameter not used. */ + ( void ) pxDisk; + + FF_PRINTF( "FF_SDDiskReinit: rc %08x\n", ( unsigned )iStatus ); + return iStatus; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskMount( FF_Disk_t *pxDisk ) +{ +FF_Error_t xFFError; +BaseType_t xReturn = 1; + + /* Mount the partition */ + xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber ); + + if( FF_isERR( xFFError ) ) + { + FF_PRINTF( "FF_SDDiskMount: %08lX\n", xFFError ); + xReturn = 0; + } + else + { + pxDisk->xStatus.bIsMounted = pdTRUE; + FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +/* Get a pointer to IOMAN, which can be used for all FreeRTOS+FAT functions */ +FF_IOManager_t *sddisk_ioman( FF_Disk_t *pxDisk ) +{ +FF_IOManager_t *pxReturn; + + if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) ) + { + pxReturn = pxDisk->pxIOManager; + } + else + { + pxReturn = NULL; + } + return pxReturn; +} +/*-----------------------------------------------------------*/ + +/* Release all resources */ +BaseType_t FF_SDDiskDelete( FF_Disk_t *pxDisk ) +{ + if( pxDisk != NULL ) + { + pxDisk->ulSignature = 0; + pxDisk->xStatus.bIsInitialised = 0; + if( pxDisk->pxIOManager != NULL ) + { + if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE ) + { + FF_Unmount( pxDisk ); + } + FF_DeleteIOManager( pxDisk->pxIOManager ); + } + + vPortFree( pxDisk ); + } + return 1; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskShowPartition( FF_Disk_t *pxDisk ) +{ +FF_Error_t xError; +uint64_t ullFreeSectors; +uint32_t ulTotalSizeMB, ulFreeSizeMB; +int iPercentageFree; +FF_IOManager_t *pxIOManager; +const char *pcTypeName = "unknown type"; +BaseType_t xReturn = pdPASS; + + if( pxDisk == NULL ) + { + xReturn = pdFAIL; + } + else + { + pxIOManager = pxDisk->pxIOManager; + + FF_PRINTF( "Reading FAT and calculating Free Space\n" ); + + switch( pxIOManager->xPartition.ucType ) + { + case FF_T_FAT12: + pcTypeName = "FAT12"; + break; + + case FF_T_FAT16: + pcTypeName = "FAT16"; + break; + + case FF_T_FAT32: + pcTypeName = "FAT32"; + break; + + default: + pcTypeName = "UNKOWN"; + break; + } + + FF_GetFreeSize( pxIOManager, &xError ); + + ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster; + iPercentageFree = ( int ) ( ( HUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) / + ( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) ); + + ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / SECTORS_PER_MB; + ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / SECTORS_PER_MB ); + + /* It is better not to use the 64-bit format such as %Lu because it + might not be implemented. */ + FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber ); + FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName ); + FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel ); + FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors ); + FF_PRINTF( "DataSectors %8lu\n", pxIOManager->xPartition.ulDataSectors ); + FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster ); + FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB ); + FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree ); + FF_PRINTF( "BeginLBA %8lu\n", pxIOManager->xPartition.ulBeginLBA ); + FF_PRINTF( "FATBeginLBA %8lu\n", pxIOManager->xPartition.ulFATBeginLBA ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + static void vInstallInterrupt( void ) + { + /* Install an interrupt handler for SDIO_0 */ + XScuGic_RegisterHandler( INTC_BASE_ADDR, SCUGIC_SDIO_0_INTR, + ( Xil_ExceptionHandler )XSdPs_IntrHandler, + ( void * )pxSDCardInstance ); + + /* Enable this interrupt. */ + XScuGic_EnableIntr( INTC_DIST_BASE_ADDR, SCUGIC_SDIO_0_INTR ); + + /* Choose the signals. */ + XSdPs_WriteReg16(pxSDCardInstance->Config.BaseAddress, + XSDPS_NORM_INTR_SIG_EN_OFFSET, + XSDPS_INTR_NORMAL_ENABLE ); + XSdPs_WriteReg16(pxSDCardInstance->Config.BaseAddress, + XSDPS_ERR_INTR_SIG_EN_OFFSET, + 0x0 ); + } +#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ +/*-----------------------------------------------------------*/ + +static int vSDMMC_Init( int iDriveNumber ) +{ +int iReturnCode, iStatus; +XSdPs_Config *SdConfig; + + /*_RB_ Function name not following convention, parameter not used, parameter + using plain int type. */ + + + /* Open a do {} while(0) loop to allow the use of break. */ + do + { + /* Check if card is in the socket */ + iStatus = vSDMMC_Status( iDriveNumber ); + if( ( iStatus & STA_NODISK ) != 0 ) + { + break; + } + + /* Assume that the initialisation will fail: set the 'STA_NOINIT' bit. */ + iStatus |= STA_NOINIT; + + /* Initialize the host controller */ + SdConfig = XSdPs_LookupConfig(SD_DEVICE_ID); + if( SdConfig == NULL ) + { + break; + } + + iReturnCode = XSdPs_CfgInitialize(pxSDCardInstance, SdConfig, SdConfig->BaseAddress); + if( iReturnCode != XST_SUCCESS ) + { + break; + } + + #if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + { + vInstallInterrupt(); + } + #endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ + iReturnCode = XSdPs_CardInitialize( pxSDCardInstance ); + if( iReturnCode != XST_SUCCESS ) + { + break; + } + + /* Disk is initialized OK: clear the 'STA_NOINIT' bit. */ + iStatus &= ~( STA_NOINIT ); + } while( 0 ); + + sd_disk_status = iStatus; + + return iStatus; +} +/*-----------------------------------------------------------*/ + +static int vSDMMC_Status( int iDriveNumber ) +{ +int iStatus = sd_disk_status; +u32 ulStatusReg; + + /*_RB_ Function name not following convention, parameter not used, parameter + using plain int type. */ + ( void ) iDriveNumber; + + ulStatusReg = XSdPs_GetPresentStatusReg( XPAR_XSDPS_0_BASEADDR ); + if( ( ulStatusReg & XSDPS_PSR_CARD_INSRT_MASK ) == 0 ) + { + iStatus = STA_NODISK | STA_NOINIT; + } + else + { + iStatus &= ~STA_NODISK; + if( ( ulStatusReg & XSDPS_PSR_WPS_PL_MASK ) != 0 ) + { + iStatus &= ~STA_PROTECT; + } + else + { + iStatus |= STA_PROTECT; + } + } + + sd_disk_status = iStatus; + return iStatus; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskInserted( BaseType_t xDriveNr ) +{ +BaseType_t xReturn; +int iStatus; + + /* Check if card is in the socket */ + iStatus = vSDMMC_Status( xDriveNr ); + if( ( iStatus & STA_NODISK ) != 0 ) + { + xReturn = pdFALSE; + } + else + { + xReturn = pdTRUE; + } + + return xReturn; +} + +volatile unsigned sd_int_count = 0; + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + volatile u32 ulSDInterruptStatus[2]; + + void XSdPs_IntrHandler(void *XSdPsPtr) + { + XSdPs *InstancePtr = (XSdPs *)XSdPsPtr; + int iIndex = InstancePtr->Config.DeviceId; + uint32_t ulStatusReg; + + configASSERT( iIndex <= 1 ); + sd_int_count++; + + /* Read the current status. */ + ulStatusReg = XSdPs_ReadReg( InstancePtr->Config.BaseAddress, XSDPS_NORM_INTR_STS_OFFSET ); + + /* Write to clear error bits. */ + XSdPs_WriteReg( InstancePtr->Config.BaseAddress, XSDPS_NORM_INTR_STS_OFFSET, ulStatusReg ); + + /* The new value must be OR-ed, if not the + Command Complete (CC) event might get overwritten + by the Transfer Complete (TC) event. */ + ulSDInterruptStatus[ iIndex ] |= ulStatusReg; + + if( ( ulStatusReg & ( XSDPS_INTR_CARD_INSRT_MASK | XSDPS_INTR_CARD_REM_MASK ) ) != 0 ) + { + /* Could wake-up another task. */ + } + if( xSDSemaphores[ iIndex ] != NULL ) + { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + xSemaphoreGiveFromISR( xSDSemaphores[ iIndex ], &xHigherPriorityTaskWoken ); + if( xHigherPriorityTaskWoken != 0 ) + { + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + } + } + } +#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ +/*-----------------------------------------------------------*/ + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + void XSdPs_ClearInterrupt( XSdPs *InstancePtr ) + { + int iIndex = InstancePtr->Config.DeviceId; + + configASSERT( iIndex <= 1 ); + ulSDInterruptStatus[ iIndex ] = 0; + } +#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ +/*-----------------------------------------------------------*/ + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + /* Wait for an interrupt and return the 32 bits of the status register. + A return value of 0 means: time-out. */ + u32 XSdPs_WaitInterrupt( XSdPs *InstancePtr, u32 ulMask, u32 ulWait ) + { + u32 ulStatusReg; + int iIndex = InstancePtr->Config.DeviceId; + TickType_t xRemainingTime = pdMS_TO_TICKS( sdWAIT_INT_TIME_OUT_MS ); + TimeOut_t xTimeOut; + + if( ulWait == 0UL ) + { + xRemainingTime = pdMS_TO_TICKS( sdQUICK_WAIT_INT_TIME_OUT_MS ); + } + + configASSERT( iIndex <= 1 ); + configASSERT( xSDSemaphores[ iIndex ] != 0 ); + vTaskSetTimeOutState( &xTimeOut ); + /* Loop until: + 1. Expected bit (ulMask) becomes high + 2. Time-out reached (normally 2 seconds) + */ + do + { + if( xRemainingTime != 0 ) + { + xSemaphoreTake( xSDSemaphores[ iIndex ], xRemainingTime ); + } + ulStatusReg = ulSDInterruptStatus[ iIndex ]; + if( ( ulStatusReg & XSDPS_INTR_ERR_MASK ) != 0 ) + { + break; + } + } + while( ( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) == pdFALSE ) && + ( ( ulStatusReg & ulMask ) == 0 ) ); + + if( ( ulStatusReg & ulMask ) == 0 ) + { + ulStatusReg = XSdPs_ReadReg( InstancePtr->Config.BaseAddress, XSDPS_NORM_INTR_STS_OFFSET ); + if( ulWait != 0UL ) + { + FF_PRINTF( "XSdPs_WaitInterrupt[ %d ]: Got %08lx, expect %08lx ints: %d\n", + iIndex, + ulStatusReg, + ulMask, + sd_int_count ); + } + } + + return ulStatusReg; + } + +#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps.c new file mode 100644 index 000000000..462260cb0 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps.c @@ -0,0 +1,1577 @@ +/****************************************************************************** +* +* Copyright (C) 2013 - 2015 Xilinx, Inc. All rights reserved. +* +* 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xsdps.c +* @addtogroup sdps_v2_5 +* @{ +* +* Contains the interface functions of the XSdPs driver. +* See xsdps.h for a detailed description of the device and driver. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date     Changes
+* ----- ---    -------- -----------------------------------------------
+* 1.00a hk/sg  10/17/13 Initial release
+* 2.0   hk     12/13/13 Added check for arm to use sleep.h and its API's
+* 2.1   hk     04/18/14 Add sleep for microblaze designs. CR# 781117.
+* 2.2   hk     07/28/14 Make changes to enable use of data cache.
+* 2.3   sk     09/23/14 Send command for relative card address
+*                       when re-initialization is done.CR# 819614.
+*						Use XSdPs_Change_ClkFreq API whenever changing
+*						clock.CR# 816586.
+* 2.4	sk	   12/04/14 Added support for micro SD without
+* 						WP/CD. CR# 810655.
+*						Checked for DAT Inhibit mask instead of CMD
+* 						Inhibit mask in Cmd Transfer API.
+*						Added Support for SD Card v1.0
+* 2.5 	sg	   07/09/15 Added SD 3.0 features
+*       kvn    07/15/15 Modified the code according to MISRAC-2012.
+* 2.6   sk     10/12/15 Added support for SD card v1.0 CR# 840601.
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "xsdps.h" +#include "xsdps_info.h" +#include "xil_cache.h" + +/* + * The header sleep.h and API usleep() can only be used with an arm design. + * MB_Sleep() is used for microblaze design. + */ +#ifdef __arm__ + +#include "sleep.h" + +#endif + +#ifdef __MICROBLAZE__ + +#include "microblaze_sleep.h" + +#endif + +#include +#include "task.h" + +#include "FreeRTOSFATConfig.h" +#include "uncached_memory.h" + +#include "hr_gettime.h" + +/************************** Constant Definitions *****************************/ +#define XSDPS_CMD8_VOL_PATTERN 0x1AAU +#define XSDPS_RESPOCR_READY 0x80000000U +#define XSDPS_ACMD41_HCS 0x40000000U +#define XSDPS_ACMD41_3V3 0x00300000U +#define XSDPS_CMD1_HIGH_VOL 0x00FF8000U +#define XSDPS_CMD1_DUAL_VOL 0x00FF8010U +#define HIGH_SPEED_SUPPORT 0x2U +#define WIDTH_4_BIT_SUPPORT 0x4U +#define SD_CLK_25_MHZ 25000000U +#define SD_CLK_26_MHZ 26000000U +#define EXT_CSD_DEVICE_TYPE_BYTE 196U +#define EXT_CSD_DEVICE_TYPE_HIGH_SPEED 0x2U +#define EXT_CSD_DEVICE_TYPE_DDR_1V8_HIGH_SPEED 0x4U +#define EXT_CSD_DEVICE_TYPE_DDR_1V2_HIGH_SPEED 0x8U +#define EXT_CSD_DEVICE_TYPE_SDR_1V8_HS200 0x10U +#define EXT_CSD_DEVICE_TYPE_SDR_1V2_HS200 0x20U + +/* Note: Remove this once fixed */ +#define UHS_BROKEN + +#ifndef ffconfigWRITE_PAUSE_USEC + #define ffconfigWRITE_PAUSE_USEC 500UL +#endif + +/**************************** Type Definitions *******************************/ + + +/************************** Function Prototypes ******************************/ +u32 XSdPs_FrameCmd(XSdPs *InstancePtr, u32 Cmd); +s32 XSdPs_CmdTransfer(XSdPs *InstancePtr, u32 Cmd, u32 Arg, u32 BlkCnt); +void XSdPs_SetupADMA2DescTbl(XSdPs *InstancePtr, u32 BlkCnt, const u8 *Buff); +extern s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode); +static s32 XSdPs_IdentifyCard(XSdPs *InstancePtr); +#ifndef UHS_BROKEN + static s32 XSdPs_Switch_Voltage(XSdPs *InstancePtr); +#endif + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + /* Declared in ff_sddisk.c : + Function will sleep and get interrupted on a change of + the status register. It will loop until: + 1. Expected bit (ulMask) becomes high + 2. Time-out reached (normally 2 seconds) + */ + extern u32 XSdPs_WaitInterrupt( XSdPs *InstancePtr, u32 ulMask, u32 ulWait ); + /* Clear the interrupt before using it. */ + extern void XSdPs_ClearInterrupt( XSdPs *InstancePtr ); +#else + #error Please define ffconfigSDIO_DRIVER_USES_INTERRUPT +#endif + +/*****************************************************************************/ +/** +* +* Initializes a specific XSdPs instance such that the driver is ready to use. +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* @param ConfigPtr is a reference to a structure containing information +* about a specific SD device. This function initializes an +* InstancePtr object for a specific device specified by the +* contents of Config. +* @param EffectiveAddr is the device base address in the virtual memory +* address space. The caller is responsible for keeping the address +* mapping from EffectiveAddr to the device physical base address +* unchanged once this function is invoked. Unexpected errors may +* occur if the address mapping changes after this function is +* called. If address translation is not used, use +* ConfigPtr->Config.BaseAddress for this device. +* +* @return +* - XST_SUCCESS if successful. +* - XST_DEVICE_IS_STARTED if the device is already started. +* It must be stopped to re-initialize. +* +* @note This function initializes the host controller. +* Initial clock of 400KHz is set. +* Voltage of 3.3V is selected as that is supported by host. +* Interrupts status is enabled and signal disabled by default. +* Default data direction is card to host and +* 32 bit ADMA2 is selected. Defualt Block size is 512 bytes. +* +******************************************************************************/ +s32 XSdPs_CfgInitialize(XSdPs *InstancePtr, XSdPs_Config *ConfigPtr, + u32 EffectiveAddr) +{ + s32 Status; + u8 PowerLevel; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(ConfigPtr != NULL); + + /* Set some default values. */ + InstancePtr->Config.BaseAddress = EffectiveAddr; + InstancePtr->Config.InputClockHz = ConfigPtr->InputClockHz; + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; + InstancePtr->Config.CardDetect = ConfigPtr->CardDetect; + InstancePtr->Config.WriteProtect = ConfigPtr->WriteProtect; + + /* Disable bus power */ + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, + XSDPS_POWER_CTRL_OFFSET, 0U); + + vTaskDelay( pdMS_TO_TICKS( 1000UL ) ); + /* "Software reset for all" is initiated */ + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, XSDPS_SW_RST_OFFSET, + XSDPS_SWRST_ALL_MASK); + + /* + * Proceed with initialization only after reset is complete + */ + while (XSdPs_ReadReg8(InstancePtr->Config.BaseAddress, + XSDPS_SW_RST_OFFSET) & XSDPS_SWRST_ALL_MASK); + /* Host Controller version is read. */ + InstancePtr->HC_Version = + (u8)(XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL_VER_OFFSET) & XSDPS_HC_SPEC_VER_MASK); + + /* + * Read capabilities register and update it in Instance pointer. + * It is sufficient to read this once on power on. + */ + InstancePtr->Host_Caps = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_CAPS_OFFSET); + + /* Select voltage and enable bus power. */ + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, + XSDPS_POWER_CTRL_OFFSET, + XSDPS_PC_BUS_VSEL_3V3_MASK | XSDPS_PC_BUS_PWR_MASK); + + /* Change the clock frequency to 400 KHz */ + Status = XSdPs_Change_ClkFreq(InstancePtr, XSDPS_CLK_400_KHZ); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH ; + } + + if ((InstancePtr->Host_Caps & XSDPS_CAP_VOLT_3V3_MASK) != 0U) { + PowerLevel = XSDPS_PC_BUS_VSEL_3V3_MASK; + } else if ((InstancePtr->Host_Caps & XSDPS_CAP_VOLT_3V0_MASK) != 0U) { + PowerLevel = XSDPS_PC_BUS_VSEL_3V0_MASK; + } else if ((InstancePtr->Host_Caps & XSDPS_CAP_VOLT_1V8_MASK) != 0U) { + PowerLevel = XSDPS_PC_BUS_VSEL_1V8_MASK; + } else { + PowerLevel = 0U; + } + + /* Select voltage based on capability and enable bus power. */ + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, + XSDPS_POWER_CTRL_OFFSET, + PowerLevel | XSDPS_PC_BUS_PWR_MASK); + /* Enable ADMA2 in 64bit mode. */ + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL1_OFFSET, + XSDPS_HC_DMA_ADMA2_32_MASK); + + /* Enable all interrupt status except card interrupt initially */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_EN_OFFSET, + XSDPS_NORM_INTR_ALL_MASK & (~XSDPS_INTR_CARD_MASK)); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_STS_EN_OFFSET, + XSDPS_ERROR_INTR_ALL_MASK); + + /* Disable all interrupt signals by default. */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_SIG_EN_OFFSET, 0x0U); + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_SIG_EN_OFFSET, 0x0U); + + /* + * Transfer mode register - default value + * DMA enabled, block count enabled, data direction card to host(read) + */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_DMA_EN_MASK | XSDPS_TM_BLK_CNT_EN_MASK | + XSDPS_TM_DAT_DIR_SEL_MASK); + + /* Set block size to 512 by default */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET, XSDPS_BLK_SIZE_512_MASK); + + Status = XST_SUCCESS; + +RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* SD initialization is done in this function +* +* +* @param InstancePtr is a pointer to the instance to be worked on. +* +* @return +* - XST_SUCCESS if initialization was successful +* - XST_FAILURE if failure - could be because +* a) SD is already initialized +* b) There is no card inserted +* c) One of the steps (commands) in the + initialization cycle failed +* +* @note This function initializes the SD card by following its +* initialization and identification state diagram. +* CMD0 is sent to reset card. +* CMD8 and ACDM41 are sent to identify voltage and +* high capacity support +* CMD2 and CMD3 are sent to obtain Card ID and +* Relative card address respectively. +* CMD9 is sent to read the card specific data. +* +******************************************************************************/ +s32 XSdPs_SdCardInitialize(XSdPs *InstancePtr) +{ + u32 PresentStateReg; + s32 Status; + u32 RespOCR; + u32 CSD[4]; + u32 Arg; + u8 ReadReg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + if(InstancePtr->Config.CardDetect != 0U) { + /* + * Check the present state register to make sure + * card is inserted and detected by host controller + */ + PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + if ((PresentStateReg & XSDPS_PSR_CARD_INSRT_MASK) == 0U) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + + /* CMD0 no response expected */ + Status = XSdPs_CmdTransfer(InstancePtr, (u32)CMD0, 0U, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * CMD8; response expected + * 0x1AA - Supply Voltage 2.7 - 3.6V and AA is pattern + */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD8, + XSDPS_CMD8_VOL_PATTERN, 0U); + if ((Status != XST_SUCCESS) && (Status != XSDPS_CT_ERROR)) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + if (Status == XSDPS_CT_ERROR) { + /* "Software reset for all" is initiated */ + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, XSDPS_SW_RST_OFFSET, + XSDPS_SWRST_CMD_LINE_MASK); + + /* Proceed with initialization only after reset is complete */ + ReadReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress, + XSDPS_SW_RST_OFFSET); + while ((ReadReg & XSDPS_SWRST_CMD_LINE_MASK) != 0U) { + ReadReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress, + XSDPS_SW_RST_OFFSET); + } + } + + RespOCR = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + if (RespOCR != XSDPS_CMD8_VOL_PATTERN) { + InstancePtr->Card_Version = XSDPS_SD_VER_1_0; + } + else { + InstancePtr->Card_Version = XSDPS_SD_VER_2_0; + } + + RespOCR = 0U; + /* Send ACMD41 while card is still busy with power up */ + while ((RespOCR & XSDPS_RESPOCR_READY) == 0U) { + Status = XSdPs_CmdTransfer(InstancePtr, CMD55, 0U, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Arg = XSDPS_ACMD41_HCS | XSDPS_ACMD41_3V3 | (0x1FFU << 15U); + if (InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) { + Arg |= XSDPS_OCR_S18; + } + + /* 0x40300000 - Host High Capacity support & 3.3V window */ + Status = XSdPs_CmdTransfer(InstancePtr, ACMD41, + Arg, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* Response with card capacity */ + RespOCR = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + } + + /* Update HCS support flag based on card capacity response */ + if ((RespOCR & XSDPS_ACMD41_HCS) != 0U) { + InstancePtr->HCS = 1U; + } + + /* There is no support to switch to 1.8V and use UHS mode on 1.0 silicon */ +#ifndef UHS_BROKEN + if ((RespOCR & XSDPS_OCR_S18) != 0U) { + InstancePtr->Switch1v8 = 1U; + Status = XSdPs_Switch_Voltage(InstancePtr); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + } +#endif + + /* CMD2 for Card ID */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD2, 0U, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + InstancePtr->CardID[0] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, XSDPS_RESP0_OFFSET); + InstancePtr->CardID[1] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, XSDPS_RESP1_OFFSET); + InstancePtr->CardID[2] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, XSDPS_RESP2_OFFSET); + InstancePtr->CardID[3] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, XSDPS_RESP3_OFFSET); + + do + { + Status = XSdPs_CmdTransfer(InstancePtr, CMD3, 0U, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Relative card address is stored as the upper 16 bits + * This is to avoid shifting when sending commands + */ + InstancePtr->RelCardAddr = + XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET) & 0xFFFF0000U; + } while (InstancePtr->RelCardAddr == 0U); + + Status = XSdPs_CmdTransfer(InstancePtr, CMD9, (InstancePtr->RelCardAddr), 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + { + u32 resp[4]; + /* Put the CSD data in a standard order and analyse them */ + resp[0] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, XSDPS_RESP0_OFFSET); + resp[1] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, XSDPS_RESP1_OFFSET); + resp[2] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, XSDPS_RESP2_OFFSET); + resp[3] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, XSDPS_RESP3_OFFSET); + CSD[0] = ( resp[3] << 8 ) | ( resp[2] >> 24 ); + CSD[1] = ( resp[2] << 8 ) | ( resp[1] >> 24 ); + CSD[2] = ( resp[1] << 8 ) | ( resp[0] >> 24 ); + CSD[3] = ( resp[0] << 8 ); + FF_PRINTF( "CSD %08lX %08lX %08lX %08lX\n", CSD[0], CSD[1], CSD[2], CSD[3]); + + sd_decode_csd( &myCSD, ( u32*) CSD ); + } + + { + u32 resp[4]; + /* When analysing the Card ID (CID), a field in CSD must be known: mmca_vsn. */ + resp[0] = ( InstancePtr->CardID[3] >> 8 ); + resp[1] = ( InstancePtr->CardID[3] << 24 ) | ( InstancePtr->CardID[2] >> 8 ); + resp[2] = ( InstancePtr->CardID[2] << 24 ) | ( InstancePtr->CardID[1] >> 8 ); + resp[3] = ( InstancePtr->CardID[1] << 24 ) | ( InstancePtr->CardID[0] >> 8 ); + FF_PRINTF( "CID %08X %08X %08X %08X\n", + ( unsigned )resp[0], + ( unsigned )resp[1], + ( unsigned )resp[2], + ( unsigned )resp[3]); + + mmc_decode_cid( &myCSD, &myCID, resp ); + } + + Status = XST_SUCCESS; + +RETURN_PATH: + return Status; + +} + +/* + * This driver will hang if the SD-card gets extracted while doing i/o. + * The driver waits for either 'XSDPS_INTR_CC_MASK', 'XSDPS_INTR_TC_MASK', + * or 'XSDPS_INTR_ERR_MASK'. + * None of the bits will ever get set and the program gets stuck here. + * The number of polls will be counted, and when a high number is reached, + * an error will be returned. + * This time-out will happen after about 2 seconds. + * + * A better solution is to define 'ffconfigSDIO_DRIVER_USES_INTERRUPT'. The CPU + * won't poll and the task will block while the MMC peripheral is working. + */ + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT == 0 ) + #define POLLCOUNT_MAX 0x800000 +#endif + +/*****************************************************************************/ +/** +* +* Initialize Card with Identification mode sequence +* +* +* @param InstancePtr is a pointer to the instance to be worked on. +* +* @return +* - XST_SUCCESS if initialization was successful +* - XST_FAILURE if failure - could be because +* a) SD is already initialized +* b) There is no card inserted +* c) One of the steps (commands) in the +* initialization cycle failed +* +* +******************************************************************************/ +s32 XSdPs_CardInitialize(XSdPs *InstancePtr) +{ +#ifdef __ICCARM__ +#pragma data_alignment = 32 +static u8 ExtCsd[512]; +#pragma data_alignment = 4 +#else +static u8 ExtCsd[512] __attribute__ ((aligned(32))); +#endif + u8 SCR[8] = { 0U }; + u8 ReadBuff[64] = { 0U }; + s32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* Default settings */ + InstancePtr->BusWidth = XSDPS_1_BIT_WIDTH; + InstancePtr->CardType = XSDPS_CARD_SD; + InstancePtr->Switch1v8 = 0U; + InstancePtr->BusSpeed = XSDPS_CLK_400_KHZ; + + if ((InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) && + ((InstancePtr->Host_Caps & XSDPS_CAPS_SLOT_TYPE_MASK) + == XSDPS_CAPS_EMB_SLOT)) { + InstancePtr->CardType = XSDPS_CHIP_EMMC; + } else { + Status = XSdPs_IdentifyCard(InstancePtr); + if (Status == XST_FAILURE) { + goto RETURN_PATH; + } + } + + if ((InstancePtr->CardType != XSDPS_CARD_SD) && + (InstancePtr->CardType != XSDPS_CARD_MMC) && + (InstancePtr->CardType != XSDPS_CHIP_EMMC)) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + if (InstancePtr->CardType == XSDPS_CARD_SD) { + Status = XSdPs_SdCardInitialize(InstancePtr); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* Change clock to default clock 25MHz */ + InstancePtr->BusSpeed = SD_CLK_25_MHZ; + Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + } else if ((InstancePtr->CardType == XSDPS_CARD_MMC) + || (InstancePtr->CardType == XSDPS_CHIP_EMMC)) { + Status = XSdPs_MmcCardInitialize(InstancePtr); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + /* Change clock to default clock 26MHz */ + InstancePtr->BusSpeed = SD_CLK_26_MHZ; + Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } else { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = XSdPs_Select_Card(InstancePtr); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + if (InstancePtr->CardType == XSDPS_CARD_SD) { + /* Pull-up disconnected during data transfer */ + Status = XSdPs_Pullup(InstancePtr); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = XSdPs_Get_BusWidth(InstancePtr, SCR); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + if ((SCR[1] & WIDTH_4_BIT_SUPPORT) != 0U) { + Status = XSdPs_Change_BusWidth(InstancePtr); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + + if ((InstancePtr->Switch1v8 != 0U) && + (InstancePtr->BusWidth == XSDPS_4_BIT_WIDTH)) { + /* Set UHS-I SDR104 mode */ + Status = XSdPs_Uhs_ModeInit(InstancePtr, + XSDPS_UHS_SPEED_MODE_SDR104); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + } else { + + /* + * card supports CMD6 when SD_SPEC field in SCR register + * indicates that the Physical Layer Specification Version + * is 1.10 or later. So for SD v1.0 cmd6 is not supported. + */ + if (SCR[0] != 0U) { + /* Get speed supported by device */ + Status = XSdPs_Get_BusSpeed(InstancePtr, ReadBuff); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + FF_PRINTF( "SD-card seems OK but 4-bits doesn't work. Dirty contacts ?\n" ); + FF_PRINTF( "Or: SD-card has version v1.0 which does not support cmd6 ?\n" ); + goto RETURN_PATH; + } + + /* Check for high speed support */ + if ((ReadBuff[13] & HIGH_SPEED_SUPPORT) != 0U) { + Status = XSdPs_Change_BusSpeed(InstancePtr); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + } + } + + } else if ((InstancePtr->CardType == XSDPS_CARD_MMC) && + (InstancePtr->HC_Version == XSDPS_HC_SPEC_V2)) { + + Status = XSdPs_Change_BusWidth(InstancePtr); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = XSdPs_Get_Mmc_ExtCsd(InstancePtr, ExtCsd); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + if (ExtCsd[EXT_CSD_BUS_WIDTH_BYTE] != EXT_CSD_BUS_WIDTH_4_BIT) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + if ((ExtCsd[EXT_CSD_DEVICE_TYPE_BYTE] & + EXT_CSD_DEVICE_TYPE_HIGH_SPEED) != 0U) { + Status = XSdPs_Change_BusSpeed(InstancePtr); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = XSdPs_Get_Mmc_ExtCsd(InstancePtr, ExtCsd); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + if (ExtCsd[EXT_CSD_HS_TIMING_BYTE] != EXT_CSD_HS_TIMING_HIGH) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + } else if (InstancePtr->CardType == XSDPS_CHIP_EMMC){ + /* Change bus width to 8-bit */ + Status = XSdPs_Change_BusWidth(InstancePtr); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* Get Extended CSD */ + Status = XSdPs_Get_Mmc_ExtCsd(InstancePtr, ExtCsd); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* Check for 8-bit support */ + if (ExtCsd[EXT_CSD_BUS_WIDTH_BYTE] != EXT_CSD_BUS_WIDTH_8_BIT) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + if ((ExtCsd[EXT_CSD_DEVICE_TYPE_BYTE] & + (EXT_CSD_DEVICE_TYPE_SDR_1V8_HS200 | + EXT_CSD_DEVICE_TYPE_SDR_1V2_HS200)) != 0U) { + Status = XSdPs_Change_BusSpeed(InstancePtr); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = XSdPs_Get_Mmc_ExtCsd(InstancePtr, ExtCsd); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + if (ExtCsd[EXT_CSD_HS_TIMING_BYTE] != EXT_CSD_HS_TIMING_HS200) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + } + + Status = XSdPs_SetBlkSize(InstancePtr, XSDPS_BLK_SIZE_512_MASK); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Identify type of card using CMD0 + CMD1 sequence +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* +******************************************************************************/ +static s32 XSdPs_IdentifyCard(XSdPs *InstancePtr) +{ + s32 Status; + u8 ReadReg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* 74 CLK delay after card is powered up, before the first command. */ +#if defined (__arm__) || defined (__aarch64__) + + usleep(XSDPS_INIT_DELAY); + +#endif + +#ifdef __MICROBLAZE__ + + /* 2 msec delay */ + MB_Sleep(2); + +#endif + + /* CMD0 no response expected */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD0, 0U, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* Host High Capacity support & High voltage window */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD1, + XSDPS_ACMD41_HCS | XSDPS_CMD1_HIGH_VOL, 0U); + if (Status != XST_SUCCESS) { + InstancePtr->CardType = XSDPS_CARD_SD; + } else { + InstancePtr->CardType = XSDPS_CARD_MMC; + } + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET, XSDPS_NORM_INTR_ALL_MASK); + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_STS_OFFSET, XSDPS_ERROR_INTR_ALL_MASK); + + /* "Software reset for all" is initiated */ + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, XSDPS_SW_RST_OFFSET, + XSDPS_SWRST_CMD_LINE_MASK); + + /* Proceed with initialization only after reset is complete */ + ReadReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress, + XSDPS_SW_RST_OFFSET); + while ((ReadReg & XSDPS_SWRST_CMD_LINE_MASK) != 0U) { + ReadReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress, + XSDPS_SW_RST_OFFSET); + } + + Status = XST_SUCCESS; + +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Switches the SD card voltage from 3v3 to 1v8 +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* +******************************************************************************/ +#ifndef UHS_BROKEN +static s32 XSdPs_Switch_Voltage(XSdPs *InstancePtr) +{ + s32 Status; + u16 CtrlReg; + u32 ReadReg; + + /* Send switch voltage command */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD11, 0U, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + } + + /* Wait for CMD and DATA line to go low */ + ReadReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + while ((ReadReg & (XSDPS_PSR_CMD_SG_LVL_MASK | + XSDPS_PSR_DAT30_SG_LVL_MASK)) != 0U) { + ReadReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + } + + /* Stop the clock */ + CtrlReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET); + CtrlReg &= ~(XSDPS_CC_SD_CLK_EN_MASK | XSDPS_CC_INT_CLK_EN_MASK); + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_CLK_CTRL_OFFSET, + CtrlReg); + + /* Wait minimum 5mSec */ +#if defined (__arm__) || defined (__aarch64__) + + (void)usleep(5000U); + +#endif + +#ifdef __MICROBLAZE__ + + MB_Sleep(5U); + +#endif + + /* Enabling 1.8V in controller */ + CtrlReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL2_OFFSET); + CtrlReg |= XSDPS_HC2_1V8_EN_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_HOST_CTRL2_OFFSET, + CtrlReg); + + /* Start clock */ + Status = XSdPs_Change_ClkFreq(InstancePtr, XSDPS_CLK_400_KHZ); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* Wait for CMD and DATA line to go high */ + ReadReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + while ((ReadReg & (XSDPS_PSR_CMD_SG_LVL_MASK | XSDPS_PSR_DAT30_SG_LVL_MASK)) + != (XSDPS_PSR_CMD_SG_LVL_MASK | XSDPS_PSR_DAT30_SG_LVL_MASK)) { + ReadReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + } + +RETURN_PATH: + return Status; +} +#endif /* UHS_BROKEN */ + +s32 XSdPs_Wait_For(XSdPs *InstancePtr, u32 Mask, u32 Wait) +{ + s32 Status = XST_SUCCESS; + u32 StatusReg; +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT == 0 ) + u32 ulPollCount; +#endif + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + StatusReg = XSdPs_WaitInterrupt( InstancePtr, XSDPS_INTR_ERR_MASK | Mask, Wait ); + + if( ( StatusReg & Mask ) == 0 ) + { + Status = XST_FAILURE; + } +#else + /* + * Check for transfer complete + * Polling for response for now + * Limit the time spent here with a simpler counter 'ulPollCount' + */ + ulPollCount = 0; + for ( ;; ) { + StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET); + if ((StatusReg & XSDPS_INTR_ERR_MASK) != 0U) { + /* Write to clear error bits */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_STS_OFFSET, + XSDPS_ERROR_INTR_ALL_MASK); + Status = XST_FAILURE; + break; + } + if((StatusReg & Mask) != 0U) { + /* Write to clear bit */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET, Mask); + /* successful exit */ + break; + } + /* Without some protection the code can easily + get stuck here if the card is withdrawn. */ + ulPollCount++; + if( ulPollCount == POLLCOUNT_MAX ) + { + Status = XST_FAILURE; + break; + } + } + +#endif /* ffconfigSDIO_DRIVER_USES_INTERRUPT */ + + return Status; +} + +/*****************************************************************************/ +/** + +* This function does SD command generation. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param Cmd is the command to be sent. +* @param Arg is the argument to be sent along with the command. +* This could be address or any other information +* @param BlkCnt - Block count passed by the user. +* +* @return +* - XST_SUCCESS if initialization was successful +* - XST_FAILURE if failure - could be because another transfer +* is in progress or command or data inhibit is set +* +******************************************************************************/ +s32 XSdPs_CmdTransfer(XSdPs *InstancePtr, u32 Cmd, u32 Arg, u32 BlkCnt) +{ + u32 PresentStateReg; + u32 CommandReg; + s32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Check the command inhibit to make sure no other + * command transfer is in progress + */ + PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + if ((PresentStateReg & XSDPS_PSR_INHIBIT_CMD_MASK) != 0U) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* Write block count register */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_BLK_CNT_OFFSET, (u16)BlkCnt); + + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, + XSDPS_TIMEOUT_CTRL_OFFSET, 0xEU); + + /* Write argument register */ + XSdPs_WriteReg(InstancePtr->Config.BaseAddress, + XSDPS_ARGMT_OFFSET, Arg); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_NORM_INTR_STS_OFFSET, XSDPS_NORM_INTR_ALL_MASK); + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_ERR_INTR_STS_OFFSET, XSDPS_ERROR_INTR_ALL_MASK); + /* Command register is set to trigger transfer of command */ + CommandReg = XSdPs_FrameCmd(InstancePtr, Cmd); + + /* + * Mask to avoid writing to reserved bits 31-30 + * This is necessary because 0x80000000 is used by this software to + * distinguish between ACMD and CMD of same number + */ + CommandReg = CommandReg & 0x3FFFU; + + /* Check for data inhibit in case of command using DAT lines */ + PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + if (((PresentStateReg & (XSDPS_PSR_INHIBIT_DAT_MASK | XSDPS_PSR_INHIBIT_DAT_MASK)) != 0U) && + ((CommandReg & XSDPS_DAT_PRESENT_SEL_MASK) != 0U)) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + XSdPs_ClearInterrupt( InstancePtr ); +#endif + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_CMD_OFFSET, + (u16)CommandReg); + + Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_CC_MASK, Cmd != CMD1); + +RETURN_PATH: + + return Status; + +} + +/*****************************************************************************/ +/** +* This function frames the Command register for a particular command. +* Note that this generates only the command register value i.e. +* the upper 16 bits of the transfer mode and command register. +* This value is already shifted to be upper 16 bits and can be directly +* OR'ed with transfer mode register value. +* +* @param Command to be sent. +* +* @return Command register value complete with response type and +* data, CRC and index related flags. +* +******************************************************************************/ +u32 XSdPs_FrameCmd(XSdPs *InstancePtr, u32 Cmd) +{ + u32 RetVal; + + RetVal = Cmd; + + switch(Cmd) { + case CMD0: + RetVal |= RESP_NONE; + break; + case CMD1: + RetVal |= RESP_R3; + break; + case CMD2: + RetVal |= RESP_R2; + break; + case CMD3: + RetVal |= RESP_R6; + break; + case CMD4: + RetVal |= RESP_NONE; + break; + case CMD5: + RetVal |= RESP_R1B; + break; + case CMD6: + if (InstancePtr->CardType == XSDPS_CARD_SD) { + RetVal |= RESP_R1 | (u32)XSDPS_DAT_PRESENT_SEL_MASK; + } else { + RetVal |= RESP_R1B; + } + break; + case ACMD6: + RetVal |= RESP_R1; + break; + case CMD7: + RetVal |= RESP_R1; + break; + case CMD8: + if (InstancePtr->CardType == XSDPS_CARD_SD) { + RetVal |= RESP_R1; + } else { + RetVal |= RESP_R1 | (u32)XSDPS_DAT_PRESENT_SEL_MASK; + } + break; + case CMD9: + RetVal |= RESP_R2; + break; + case CMD11: + case CMD10: + case CMD12: + case ACMD13: + case CMD16: + RetVal |= RESP_R1; + break; + case CMD17: + case CMD18: + case CMD19: + case CMD21: + RetVal |= RESP_R1 | (u32)XSDPS_DAT_PRESENT_SEL_MASK; + break; + case CMD23: + case ACMD23: + case CMD24: + case CMD25: + RetVal |= RESP_R1 | (u32)XSDPS_DAT_PRESENT_SEL_MASK; + case ACMD41: + RetVal |= RESP_R3; + break; + case ACMD42: + RetVal |= RESP_R1; + break; + case ACMD51: + RetVal |= RESP_R1 | (u32)XSDPS_DAT_PRESENT_SEL_MASK; + break; + case CMD52: + case CMD55: + RetVal |= RESP_R1; + break; + case CMD58: + break; + default : + RetVal |= Cmd; + break; + } + + return RetVal; +} + +/*****************************************************************************/ +/** +* This function performs SD read in polled mode. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param Arg is the address passed by the user that is to be sent as +* argument along with the command. +* @param BlkCnt - Block count passed by the user. +* @param Buff - Pointer to the data buffer for a DMA transfer. +* +* @return +* - XST_SUCCESS if initialization was successful +* - XST_FAILURE if failure - could be because another transfer +* is in progress or command or data inhibit is set +* +******************************************************************************/ +s32 XSdPs_ReadPolled(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt, u8 *Buff) +{ + s32 Status; + u32 PresentStateReg; + + if(InstancePtr->Config.CardDetect != 0U) { + /* Check status to ensure card is initialized */ + PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + if ((PresentStateReg & XSDPS_PSR_CARD_INSRT_MASK) == 0x0U) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + + /* Set block size to 512 if not already set */ + if( XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET) != XSDPS_BLK_SIZE_512_MASK ) { + Status = XSdPs_SetBlkSize(InstancePtr, + XSDPS_BLK_SIZE_512_MASK); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + + XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, Buff); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_AUTO_CMD12_EN_MASK | + XSDPS_TM_BLK_CNT_EN_MASK | XSDPS_TM_DAT_DIR_SEL_MASK | + XSDPS_TM_DMA_EN_MASK | XSDPS_TM_MUL_SIN_BLK_SEL_MASK); + + if( ucIsCachedMemory( ( const uint8_t *)Buff ) != 0 ) + { + Xil_DCacheInvalidateRange( ( unsigned )Buff, BlkCnt * XSDPS_BLK_SIZE_512_MASK); + } + + /* Send block read command */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD18, Arg, BlkCnt); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE); + if (Status != XST_SUCCESS) { + goto RETURN_PATH; + } + + XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* This function performs SD write in polled mode. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param Arg is the address passed by the user that is to be sent as +* argument along with the command. +* @param BlkCnt - Block count passed by the user. +* @param Buff - Pointer to the data buffer for a DMA transfer. +* +* @return +* - XST_SUCCESS if initialization was successful +* - XST_FAILURE if failure - could be because another transfer +* is in progress or command or data inhibit is set +* +******************************************************************************/ + +uint32_t ulSDWritePause = ffconfigWRITE_PAUSE_USEC; + +u32 XSdPs_ReadStatus(XSdPs *InstancePtr) +{ +u32 Status; + + /* Send block write command */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD13, (InstancePtr->RelCardAddr), 0UL); + if (Status != XST_SUCCESS) { + Status = 0x00UL; + goto RETURN_PATH; + } + Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); +RETURN_PATH: + return Status; +} + +s32 XSdPs_WritePolled(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt, const u8 *Buff) +{ + s32 Status; + u32 PresentStateReg; + + if(InstancePtr->Config.CardDetect != 0U) { + /* Check status to ensure card is initialized */ + PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + if ((PresentStateReg & XSDPS_PSR_CARD_INSRT_MASK) == 0x0U) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + + /* Set block size to 512 if not already set */ + if( XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET) != XSDPS_BLK_SIZE_512_MASK ) { + Status = XSdPs_SetBlkSize(InstancePtr, + XSDPS_BLK_SIZE_512_MASK); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + } + + XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, Buff); + if( ucIsCachedMemory( ( const uint8_t *)Buff ) != 0 ) + { + Xil_DCacheFlushRange( ( unsigned )Buff, BlkCnt * XSDPS_BLK_SIZE_512_MASK); + } + + if( ulSDWritePause != 0ul ) + { + /* Wait for halve a ms. + This 'solution' is still under contruction. */ + uint64_t ullLastTime = ullGetHighResolutionTime(); + uint64_t ullNow; + + XSdPs_ReadStatus(InstancePtr); + for( ;; ) + { + ullNow = ullGetHighResolutionTime(); + if( ( ullNow - ullLastTime ) > ulSDWritePause ) + { + ullLastTime = ullNow; + break; + } + } + XSdPs_ReadStatus(InstancePtr); +// eventLogAdd("Wt %lx %lx%s", Status[0], Status[1], Status[0] != Status[1] ? " DIFF" : ""); + } + else + { + u32 Status = XSdPs_ReadStatus(InstancePtr); +// eventLogAdd("Wt %lx", Status); + } + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_AUTO_CMD12_EN_MASK | + XSDPS_TM_BLK_CNT_EN_MASK | + XSDPS_TM_MUL_SIN_BLK_SEL_MASK | XSDPS_TM_DMA_EN_MASK); + + /* Send block write command */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD25, Arg, BlkCnt); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE); + +RETURN_PATH: + return Status; +} + +/*****************************************************************************/ +/** +* +* Selects card and sets default block size +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +s32 XSdPs_Select_Card (XSdPs *InstancePtr) +{ + s32 Status = 0; + + /* Send CMD7 - Select card */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD7, + InstancePtr->RelCardAddr, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + +RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to setup ADMA2 descriptor table +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* @param BlkCnt - block count. +* @param Buff pointer to data buffer. +* +* @return None +* +* @note None. +* +******************************************************************************/ +void XSdPs_SetupADMA2DescTbl(XSdPs *InstancePtr, u32 BlkCnt, const u8 *Buff) +{ + u32 TotalDescLines = 0U; + u32 DescNum = 0U; + u32 BlkSize = 0U; + + /* Setup ADMA2 - Write descriptor table and point ADMA SAR to it */ + BlkSize = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET); + BlkSize = BlkSize & XSDPS_BLK_SIZE_MASK; + + if((BlkCnt*BlkSize) < XSDPS_DESC_MAX_LENGTH) { + + TotalDescLines = 1U; + + }else { + + TotalDescLines = ((BlkCnt*BlkSize) / XSDPS_DESC_MAX_LENGTH); + if (((BlkCnt * BlkSize) % XSDPS_DESC_MAX_LENGTH) != 0U) { + TotalDescLines += 1U; + } + + } + + for (DescNum = 0U; DescNum < (TotalDescLines-1); DescNum++) { + InstancePtr->Adma2_DescrTbl[DescNum].Address = + (u32)(Buff + (DescNum*XSDPS_DESC_MAX_LENGTH)); + InstancePtr->Adma2_DescrTbl[DescNum].Attribute = + XSDPS_DESC_TRAN | XSDPS_DESC_VALID; + /* This will write '0' to length field which indicates 65536 */ + InstancePtr->Adma2_DescrTbl[DescNum].Length = + (u16)XSDPS_DESC_MAX_LENGTH; + } + + InstancePtr->Adma2_DescrTbl[TotalDescLines-1].Address = + (u32)(Buff + (DescNum*XSDPS_DESC_MAX_LENGTH)); + + InstancePtr->Adma2_DescrTbl[TotalDescLines-1].Attribute = + XSDPS_DESC_TRAN | XSDPS_DESC_END | XSDPS_DESC_VALID; + + InstancePtr->Adma2_DescrTbl[TotalDescLines-1].Length = + (BlkCnt*BlkSize) - (DescNum*XSDPS_DESC_MAX_LENGTH); + + + XSdPs_WriteReg(InstancePtr->Config.BaseAddress, XSDPS_ADMA_SAR_OFFSET, + (u32)&(InstancePtr->Adma2_DescrTbl[0])); + + if( ucIsCachedMemory( ( const uint8_t *)InstancePtr->Adma2_DescrTbl ) != 0 ) + { + Xil_DCacheFlushRange( ( unsigned ) &( InstancePtr->Adma2_DescrTbl[ 0 ] ), + sizeof(XSdPs_Adma2Descriptor) * 32); + } +} + +/*****************************************************************************/ +/** +* Mmc initialization is done in this function +* +* +* @param InstancePtr is a pointer to the instance to be worked on. +* +* @return +* - XST_SUCCESS if initialization was successful +* - XST_FAILURE if failure - could be because +* a) MMC is already initialized +* b) There is no card inserted +* c) One of the steps (commands) in the initialization +* cycle failed +* @note This function initializes the SD card by following its +* initialization and identification state diagram. +* CMD0 is sent to reset card. +* CMD1 sent to identify voltage and high capacity support +* CMD2 and CMD3 are sent to obtain Card ID and +* Relative card address respectively. +* CMD9 is sent to read the card specific data. +* +******************************************************************************/ +s32 XSdPs_MmcCardInitialize(XSdPs *InstancePtr) +{ + u32 PresentStateReg; + s32 Status; + u32 RespOCR; + u32 CSD[4]; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + if(InstancePtr->Config.CardDetect != 0U) { + /* + * Check the present state register to make sure + * card is inserted and detected by host controller + */ + PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + if ((PresentStateReg & XSDPS_PSR_CARD_INSRT_MASK) == 0U) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + + /* CMD0 no response expected */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD0, 0U, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + RespOCR = 0U; + /* Send CMD1 while card is still busy with power up */ + while ((RespOCR & XSDPS_RESPOCR_READY) == 0U) { + + /* Host High Capacity support & High volage window */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD1, + XSDPS_ACMD41_HCS | XSDPS_CMD1_HIGH_VOL, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* Response with card capacity */ + RespOCR = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + } + + /* Update HCS support flag based on card capacity response */ + if ((RespOCR & XSDPS_ACMD41_HCS) != 0U) { + InstancePtr->HCS = 1U; + } + + /* CMD2 for Card ID */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD2, 0U, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + InstancePtr->CardID[0] = + XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + InstancePtr->CardID[1] = + XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_RESP1_OFFSET); + InstancePtr->CardID[2] = + XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_RESP2_OFFSET); + InstancePtr->CardID[3] = + XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_RESP3_OFFSET); + + /* Set relative card address */ + InstancePtr->RelCardAddr = 0x12340000U; + Status = XSdPs_CmdTransfer(InstancePtr, CMD3, (InstancePtr->RelCardAddr), 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* Read Card specific data. */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD9, (InstancePtr->RelCardAddr), 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Card specific data is read. + * Currently not used for any operation. + */ + CSD[0] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + CSD[1] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP1_OFFSET); + CSD[2] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP2_OFFSET); + CSD[3] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP3_OFFSET); + + ( void ) CSD[0]; + + Status = XST_SUCCESS; + +RETURN_PATH: + return Status; + +} +/** @} */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps.h new file mode 100644 index 000000000..c1a077958 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps.h @@ -0,0 +1,221 @@ +/****************************************************************************** +* +* Copyright (C) 2013 - 2015 Xilinx, Inc. All rights reserved. +* +* 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xsdps.h +* @addtogroup sdps_v2_5 +* @{ +* @details +* +* This file contains the implementation of XSdPs driver. +* This driver is used initialize read from and write to the SD card. +* Features such as switching bus width to 4-bit and switching to high speed, +* changing clock frequency, block size etc. are supported. +* SD 2.0 uses 1/4 bus width and speeds of 25/50KHz. Initialization, however +* is done using 1-bit bus width and 400KHz clock frequency. +* SD commands are classified as broadcast and addressed. Commands can be +* those with response only (using only command line) or +* response + data (using command and data lines). +* Only one command can be sent at a time. During a data transfer however, +* when dsta lines are in use, certain commands (which use only the command +* line) can be sent, most often to obtain status. +* This driver does not support multi card slots at present. +* +* Intialization: +* This includes initialization on the host controller side to select +* clock frequency, bus power and default transfer related parameters. +* The default voltage is 3.3V. +* On the SD card side, the initialization and identification state diagram is +* implemented. This resets the card, gives it a unique address/ID and +* identifies key card related specifications. +* +* Data transfer: +* The SD card is put in tranfer state to read from or write to it. +* The default block size is 512 bytes and if supported, +* default bus width is 4-bit and bus speed is High speed. +* The read and write functions are implemented in polled mode using ADMA2. +* +* At any point, when key parameters such as block size or +* clock/speed or bus width are modified, this driver takes care of +* maintaining the same selection on host and card. +* All error bits in host controller are monitored by the driver and in the +* event one of them is set, driver will clear the interrupt status and +* communicate failure to the upper layer. +* +* File system use: +* This driver can be used with xilffs library to read and write files to SD. +* (Please refer to procedure in diskio.c). The file system read/write example +* in polled mode can used for reference. +* +* There is no example for using SD driver without file system at present. +* However, the driver can be used without the file system. The glue layer +* in filesytem can be used as reference for the same. The block count +* passed to the read/write function in one call is limited by the ADMA2 +* descriptor table and hence care will have to be taken to call read/write +* API's in a loop for large file sizes. +* +* Interrupt mode is not supported because it offers no improvement when used +* with file system. +* +* eMMC support: +* SD driver supports SD and eMMC based on the "enable MMC" parameter in SDK. +* The features of eMMC supported by the driver will depend on those supported +* by the host controller. The current driver supports read/write on eMMC card +* using 4-bit and high speed mode currently. +* +* Features not supported include - card write protect, password setting, +* lock/unlock, interrupts, SDMA mode, programmed I/O mode and +* 64-bit addressed ADMA2, erase/pre-erase commands. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date     Changes
+* ----- ---    -------- -----------------------------------------------
+* 1.00a hk/sg  10/17/13 Initial release
+* 2.0   hk      03/07/14 Version number revised.
+* 2.1   hk     04/18/14 Increase sleep for eMMC switch command.
+*                       Add sleep for microblaze designs. CR# 781117.
+* 2.2   hk     07/28/14 Make changes to enable use of data cache.
+* 2.3   sk     09/23/14 Send command for relative card address
+*                       when re-initialization is done.CR# 819614.
+*						Use XSdPs_Change_ClkFreq API whenever changing
+*						clock.CR# 816586.
+* 2.4	sk	   12/04/14 Added support for micro SD without
+* 						WP/CD. CR# 810655.
+*						Checked for DAT Inhibit mask instead of CMD
+* 						Inhibit mask in Cmd Transfer API.
+*						Added Support for SD Card v1.0
+* 2.5 	sg		07/09/15 Added SD 3.0 features
+*       kvn     07/15/15 Modified the code according to MISRAC-2012.
+* 2.6   sk     10/12/15 Added support for SD card v1.0 CR# 840601.
+*
+* 
+* +******************************************************************************/ + + +#ifndef SDPS_H_ +#define SDPS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "xstatus.h" +#include "xsdps_hw.h" +#include + +/************************** Constant Definitions *****************************/ + +#define XSDPS_CT_ERROR 0x2U /**< Command timeout flag */ + +/**************************** Type Definitions *******************************/ +/** + * This typedef contains configuration information for the device. + */ +typedef struct { + u16 DeviceId; /**< Unique ID of device */ + u32 BaseAddress; /**< Base address of the device */ + u32 InputClockHz; /**< Input clock frequency */ + u32 CardDetect; /**< Card Detect */ + u32 WriteProtect; /**< Write Protect */ +} XSdPs_Config; + +/* ADMA2 descriptor table */ +typedef struct { + u16 Attribute; /**< Attributes of descriptor */ + u16 Length; /**< Length of current dma transfer */ + u32 Address; /**< Address of current dma transfer */ +} XSdPs_Adma2Descriptor; + +/** + * The XSdPs driver instance data. The user is required to allocate a + * variable of this type for every SD device in the system. A pointer + * to a variable of this type is then passed to the driver API functions. + */ +typedef struct { + XSdPs_Config Config; /**< Configuration structure */ + u32 IsReady; /**< Device is initialized and ready */ + u32 Host_Caps; /**< Capabilities of host controller */ + u32 Host_CapsExt; /**< Extended Capabilities */ + u32 HCS; /**< High capacity support in card */ + u8 CardType; /**< Type of card - SD/MMC/eMMC */ + u8 Card_Version; /**< Card version */ + u8 HC_Version; /**< Host controller version */ + u8 BusWidth; /**< Current operating bus width */ + u32 BusSpeed; /**< Current operating bus speed */ + u8 Switch1v8; /**< 1.8V Switch support */ + u32 CardID[4]; /**< Card ID Register */ + u32 RelCardAddr; /**< Relative Card Address */ + u32 CardSpecData[4]; /**< Card Specific Data Register */ + u32 SdCardConfig; /**< Sd Card Configuration Register */ + /**< ADMA Descriptors */ +#ifdef __ICCARM__ +#pragma data_alignment = 32 + XSdPs_Adma2Descriptor Adma2_DescrTbl[32]; +#pragma data_alignment = 4 +#else + XSdPs_Adma2Descriptor Adma2_DescrTbl[32] __attribute__ ((aligned(32))); +#endif +} XSdPs; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ +XSdPs_Config *XSdPs_LookupConfig(u16 DeviceId); +s32 XSdPs_CfgInitialize(XSdPs *InstancePtr, XSdPs_Config *ConfigPtr, + u32 EffectiveAddr); +s32 XSdPs_SdCardInitialize(XSdPs *InstancePtr); +s32 XSdPs_ReadPolled(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt, u8 *Buff); +s32 XSdPs_WritePolled(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt, const u8 *Buff); +s32 XSdPs_SetBlkSize(XSdPs *InstancePtr, u16 BlkSize); +s32 XSdPs_Select_Card (XSdPs *InstancePtr); +s32 XSdPs_Change_ClkFreq(XSdPs *InstancePtr, u32 SelFreq); +s32 XSdPs_Change_BusWidth(XSdPs *InstancePtr); +s32 XSdPs_Change_BusSpeed(XSdPs *InstancePtr); +s32 XSdPs_Get_BusWidth(XSdPs *InstancePtr, u8 *SCR); +s32 XSdPs_Get_BusSpeed(XSdPs *InstancePtr, u8 *ReadBuff); +s32 XSdPs_Pullup(XSdPs *InstancePtr); +s32 XSdPs_MmcCardInitialize(XSdPs *InstancePtr); +s32 XSdPs_CardInitialize(XSdPs *InstancePtr); +s32 XSdPs_Get_Mmc_ExtCsd(XSdPs *InstancePtr, u8 *ReadBuff); +/* Wait for Command/Transfer Complete. */ +s32 XSdPs_Wait_For(XSdPs *InstancePtr, u32 Mask, u32 Wait); + +#ifdef __cplusplus +} +#endif + +#endif /* SD_H_ */ +/** @} */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_g.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_g.c new file mode 100644 index 000000000..7301c7ba0 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_g.c @@ -0,0 +1,69 @@ +/****************************************************************************** +* +* Copyright (C) 2013 - 2014 Xilinx, Inc. All rights reserved. +* +* 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX CONSORTIUM 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xsdps_g.c +* +* This file contains a configuration table that specifies the configuration of +* SD devices in the system. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date     Changes
+* ----- ---    -------- -----------------------------------------------
+* 1.00a hk/sg  10/17/13 Initial release
+*
+* 
+* +******************************************************************************/ + + + +#include "xparameters.h" +#include "xsdps.h" + +/* +* The configuration table for devices +*/ + +XSdPs_Config XSdPs_ConfigTable[] = +{ + { + XPAR_XSDPS_0_DEVICE_ID, + XPAR_XSDPS_0_BASEADDR, + XPAR_XSDPS_0_SDIO_CLK_FREQ_HZ, + 0, + 0 + } +}; diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_hw.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_hw.h new file mode 100644 index 000000000..8f66acbba --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_hw.h @@ -0,0 +1,1173 @@ +/****************************************************************************** +* +* Copyright (C) 2013 - 2015 Xilinx, Inc. All rights reserved. +* +* 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xsdps_hw.h +* @addtogroup sdps_v2_5 +* @{ +* +* This header file contains the identifiers and basic HW access driver +* functions (or macros) that can be used to access the device. Other driver +* functions are defined in xsdps.h. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date     Changes
+* ----- ---    -------- -----------------------------------------------
+* 1.00a hk/sg  10/17/13 Initial release
+* 2.5 	sg	   07/09/15 Added SD 3.0 features
+*       kvn    07/15/15 Modified the code according to MISRAC-2012.
+* 
+* +******************************************************************************/ + +#ifndef SD_HW_H_ +#define SD_HW_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xil_io.h" +#include "xparameters.h" + +/************************** Constant Definitions *****************************/ + +/** @name Register Map + * + * Register offsets from the base address of an SD device. + * @{ + */ + +#define XSDPS_SDMA_SYS_ADDR_OFFSET 0x00U /**< SDMA System Address + Register */ +#define XSDPS_SDMA_SYS_ADDR_LO_OFFSET XSDPS_SDMA_SYS_ADDR_OFFSET + /**< SDMA System Address + Low Register */ +#define XSDPS_ARGMT2_LO_OFFSET 0x00U /**< Argument2 Low Register */ +#define XSDPS_SDMA_SYS_ADDR_HI_OFFSET 0x02U /**< SDMA System Address + High Register */ +#define XSDPS_ARGMT2_HI_OFFSET 0x02U /**< Argument2 High Register */ + +#define XSDPS_BLK_SIZE_OFFSET 0x04U /**< Block Size Register */ +#define XSDPS_BLK_CNT_OFFSET 0x06U /**< Block Count Register */ +#define XSDPS_ARGMT_OFFSET 0x08U /**< Argument Register */ +#define XSDPS_ARGMT1_LO_OFFSET XSDPS_ARGMT_OFFSET + /**< Argument1 Register */ +#define XSDPS_ARGMT1_HI_OFFSET 0x0AU /**< Argument1 Register */ + +#define XSDPS_XFER_MODE_OFFSET 0x0CU /**< Transfer Mode Register */ +#define XSDPS_CMD_OFFSET 0x0EU /**< Command Register */ +#define XSDPS_RESP0_OFFSET 0x10U /**< Response0 Register */ +#define XSDPS_RESP1_OFFSET 0x14U /**< Response1 Register */ +#define XSDPS_RESP2_OFFSET 0x18U /**< Response2 Register */ +#define XSDPS_RESP3_OFFSET 0x1CU /**< Response3 Register */ +#define XSDPS_BUF_DAT_PORT_OFFSET 0x20U /**< Buffer Data Port */ +#define XSDPS_PRES_STATE_OFFSET 0x24U /**< Present State */ +#define XSDPS_HOST_CTRL1_OFFSET 0x28U /**< Host Control 1 */ +#define XSDPS_POWER_CTRL_OFFSET 0x29U /**< Power Control */ +#define XSDPS_BLK_GAP_CTRL_OFFSET 0x2AU /**< Block Gap Control */ +#define XSDPS_WAKE_UP_CTRL_OFFSET 0x2BU /**< Wake Up Control */ +#define XSDPS_CLK_CTRL_OFFSET 0x2CU /**< Clock Control */ +#define XSDPS_TIMEOUT_CTRL_OFFSET 0x2EU /**< Timeout Control */ +#define XSDPS_SW_RST_OFFSET 0x2FU /**< Software Reset */ +#define XSDPS_NORM_INTR_STS_OFFSET 0x30U /**< Normal Interrupt + Status Register */ +#define XSDPS_ERR_INTR_STS_OFFSET 0x32U /**< Error Interrupt + Status Register */ +#define XSDPS_NORM_INTR_STS_EN_OFFSET 0x34U /**< Normal Interrupt + Status Enable Register */ +#define XSDPS_ERR_INTR_STS_EN_OFFSET 0x36U /**< Error Interrupt + Status Enable Register */ +#define XSDPS_NORM_INTR_SIG_EN_OFFSET 0x38U /**< Normal Interrupt + Signal Enable Register */ +#define XSDPS_ERR_INTR_SIG_EN_OFFSET 0x3AU /**< Error Interrupt + Signal Enable Register */ + +#define XSDPS_AUTO_CMD12_ERR_STS_OFFSET 0x3CU /**< Auto CMD12 Error Status + Register */ +#define XSDPS_HOST_CTRL2_OFFSET 0x3EU /**< Host Control2 Register */ +#define XSDPS_CAPS_OFFSET 0x40U /**< Capabilities Register */ +#define XSDPS_CAPS_EXT_OFFSET 0x44U /**< Capabilities Extended */ +#define XSDPS_MAX_CURR_CAPS_OFFSET 0x48U /**< Maximum Current + Capabilities Register */ +#define XSDPS_MAX_CURR_CAPS_EXT_OFFSET 0x4CU /**< Maximum Current + Capabilities Ext Register */ +#define XSDPS_FE_ERR_INT_STS_OFFSET 0x52U /**< Force Event for + Error Interrupt Status */ +#define XSDPS_FE_AUTO_CMD12_EIS_OFFSET 0x50U /**< Auto CM12 Error Interrupt + Status Register */ +#define XSDPS_ADMA_ERR_STS_OFFSET 0x54U /**< ADMA Error Status + Register */ +#define XSDPS_ADMA_SAR_OFFSET 0x58U /**< ADMA System Address + Register */ +#define XSDPS_ADMA_SAR_EXT_OFFSET 0x5CU /**< ADMA System Address + Extended Register */ +#define XSDPS_PRE_VAL_1_OFFSET 0x60U /**< Preset Value Register */ +#define XSDPS_PRE_VAL_2_OFFSET 0x64U /**< Preset Value Register */ +#define XSDPS_PRE_VAL_3_OFFSET 0x68U /**< Preset Value Register */ +#define XSDPS_PRE_VAL_4_OFFSET 0x6CU /**< Preset Value Register */ +#define XSDPS_BOOT_TOUT_CTRL_OFFSET 0x70U /**< Boot timeout control + register */ + +#define XSDPS_SHARED_BUS_CTRL_OFFSET 0xE0U /**< Shared Bus Control + Register */ +#define XSDPS_SLOT_INTR_STS_OFFSET 0xFCU /**< Slot Interrupt Status + Register */ +#define XSDPS_HOST_CTRL_VER_OFFSET 0xFEU /**< Host Controller Version + Register */ + +/* @} */ + +/** @name Control Register - Host control, Power control, + * Block Gap control and Wakeup control + * + * This register contains bits for various configuration options of + * the SD host controller. Read/Write apart from the reserved bits. + * @{ + */ + +#define XSDPS_HC_LED_MASK 0x00000001U /**< LED Control */ +#define XSDPS_HC_WIDTH_MASK 0x00000002U /**< Bus width */ +#define XSDPS_HC_BUS_WIDTH_4 0x00000002U +#define XSDPS_HC_SPEED_MASK 0x00000004U /**< High Speed */ +#define XSDPS_HC_DMA_MASK 0x00000018U /**< DMA Mode Select */ +#define XSDPS_HC_DMA_SDMA_MASK 0x00000000U /**< SDMA Mode */ +#define XSDPS_HC_DMA_ADMA1_MASK 0x00000008U /**< ADMA1 Mode */ +#define XSDPS_HC_DMA_ADMA2_32_MASK 0x00000010U /**< ADMA2 Mode - 32 bit */ +#define XSDPS_HC_DMA_ADMA2_64_MASK 0x00000018U /**< ADMA2 Mode - 64 bit */ +#define XSDPS_HC_EXT_BUS_WIDTH 0x00000020U /**< Bus width - 8 bit */ +#define XSDPS_HC_CARD_DET_TL_MASK 0x00000040U /**< Card Detect Tst Lvl */ +#define XSDPS_HC_CARD_DET_SD_MASK 0x00000080U /**< Card Detect Sig Det */ + +#define XSDPS_PC_BUS_PWR_MASK 0x00000001U /**< Bus Power Control */ +#define XSDPS_PC_BUS_VSEL_MASK 0x0000000EU /**< Bus Voltage Select */ +#define XSDPS_PC_BUS_VSEL_3V3_MASK 0x0000000EU /**< Bus Voltage 3.3V */ +#define XSDPS_PC_BUS_VSEL_3V0_MASK 0x0000000CU /**< Bus Voltage 3.0V */ +#define XSDPS_PC_BUS_VSEL_1V8_MASK 0x0000000AU /**< Bus Voltage 1.8V */ +#define XSDPS_PC_EMMC_HW_RST_MASK 0x00000010U /**< HW reset for eMMC */ + +#define XSDPS_BGC_STP_REQ_MASK 0x00000001U /**< Block Gap Stop Req */ +#define XSDPS_BGC_CNT_REQ_MASK 0x00000002U /**< Block Gap Cont Req */ +#define XSDPS_BGC_RWC_MASK 0x00000004U /**< Block Gap Rd Wait */ +#define XSDPS_BGC_INTR_MASK 0x00000008U /**< Block Gap Intr */ +#define XSDPS_BGC_SPI_MODE_MASK 0x00000010U /**< Block Gap SPI Mode */ +#define XSDPS_BGC_BOOT_EN_MASK 0x00000020U /**< Block Gap Boot Enb */ +#define XSDPS_BGC_ALT_BOOT_EN_MASK 0x00000040U /**< Block Gap Alt BootEn */ +#define XSDPS_BGC_BOOT_ACK_MASK 0x00000080U /**< Block Gap Boot Ack */ + +#define XSDPS_WC_WUP_ON_INTR_MASK 0x00000001U /**< Wakeup Card Intr */ +#define XSDPS_WC_WUP_ON_INSRT_MASK 0x00000002U /**< Wakeup Card Insert */ +#define XSDPS_WC_WUP_ON_REM_MASK 0x00000004U /**< Wakeup Card Removal */ + +/* @} */ + +/** @name Control Register - Clock control, Timeout control & Software reset + * + * This register contains bits for configuration options of clock, timeout and + * software reset. + * Read/Write except for Inter_Clock_Stable bit (read only) and reserved bits. + * @{ + */ + +#define XSDPS_CC_INT_CLK_EN_MASK 0x00000001U +#define XSDPS_CC_INT_CLK_STABLE_MASK 0x00000002U +#define XSDPS_CC_SD_CLK_EN_MASK 0x00000004U +#define XSDPS_CC_SD_CLK_GEN_SEL_MASK 0x00000020U +#define XSDPS_CC_SDCLK_FREQ_SEL_EXT_MASK 0x000000C0U +#define XSDPS_CC_SDCLK_FREQ_SEL_MASK 0x0000FF00U +#define XSDPS_CC_SDCLK_FREQ_D256_MASK 0x00008000U +#define XSDPS_CC_SDCLK_FREQ_D128_MASK 0x00004000U +#define XSDPS_CC_SDCLK_FREQ_D64_MASK 0x00002000U +#define XSDPS_CC_SDCLK_FREQ_D32_MASK 0x00001000U +#define XSDPS_CC_SDCLK_FREQ_D16_MASK 0x00000800U +#define XSDPS_CC_SDCLK_FREQ_D8_MASK 0x00000400U +#define XSDPS_CC_SDCLK_FREQ_D4_MASK 0x00000200U +#define XSDPS_CC_SDCLK_FREQ_D2_MASK 0x00000100U +#define XSDPS_CC_SDCLK_FREQ_BASE_MASK 0x00000000U +#define XSDPS_CC_MAX_DIV_CNT 256U +#define XSDPS_CC_EXT_MAX_DIV_CNT 2046U +#define XSDPS_CC_EXT_DIV_SHIFT 6U + +#define XSDPS_TC_CNTR_VAL_MASK 0x0000000FU + +#define XSDPS_SWRST_ALL_MASK 0x00000001U +#define XSDPS_SWRST_CMD_LINE_MASK 0x00000002U +#define XSDPS_SWRST_DAT_LINE_MASK 0x00000004U + +#define XSDPS_CC_MAX_NUM_OF_DIV 9U +#define XSDPS_CC_DIV_SHIFT 8U + +/* @} */ + +/** @name SD Interrupt Registers + * + * Normal and Error Interrupt Status Register + * This register shows the normal and error interrupt status. + * Status enable register affects reads of this register. + * If Signal enable register is set and the corresponding status bit is set, + * interrupt is generated. + * Write to clear except + * Error_interrupt and Card_Interrupt bits - Read only + * + * Normal and Error Interrupt Status Enable Register + * Setting this register bits enables Interrupt status. + * Read/Write except Fixed_to_0 bit (Read only) + * + * Normal and Error Interrupt Signal Enable Register + * This register is used to select which interrupt status is + * indicated to the Host System as the interrupt. + * Read/Write except Fixed_to_0 bit (Read only) + * + * All three registers have same bit definitions + * @{ + */ + +#define XSDPS_INTR_CC_MASK 0x00000001U /**< Command Complete */ +#define XSDPS_INTR_TC_MASK 0x00000002U /**< Transfer Complete */ +#define XSDPS_INTR_BGE_MASK 0x00000004U /**< Block Gap Event */ +#define XSDPS_INTR_DMA_MASK 0x00000008U /**< DMA Interrupt */ +#define XSDPS_INTR_BWR_MASK 0x00000010U /**< Buffer Write Ready */ +#define XSDPS_INTR_BRR_MASK 0x00000020U /**< Buffer Read Ready */ +#define XSDPS_INTR_CARD_INSRT_MASK 0x00000040U /**< Card Insert */ +#define XSDPS_INTR_CARD_REM_MASK 0x00000080U /**< Card Remove */ +#define XSDPS_INTR_CARD_MASK 0x00000100U /**< Card Interrupt */ +#define XSDPS_INTR_INT_A_MASK 0x00000200U /**< INT A Interrupt */ +#define XSDPS_INTR_INT_B_MASK 0x00000400U /**< INT B Interrupt */ +#define XSDPS_INTR_INT_C_MASK 0x00000800U /**< INT C Interrupt */ +#define XSDPS_INTR_RE_TUNING_MASK 0x00001000U /**< Re-Tuning Interrupt */ +#define XSDPS_INTR_BOOT_ACK_RECV_MASK 0x00002000U /**< Boot Ack Recv + Interrupt */ +#define XSDPS_INTR_BOOT_TERM_MASK 0x00004000U /**< Boot Terminate + Interrupt */ +#define XSDPS_INTR_ERR_MASK 0x00008000U /**< Error Interrupt */ +#define XSDPS_NORM_INTR_ALL_MASK 0x0000FFFFU + +#define XSDPS_INTR_ERR_CT_MASK 0x00000001U /**< Command Timeout + Error */ +#define XSDPS_INTR_ERR_CCRC_MASK 0x00000002U /**< Command CRC Error */ +#define XSDPS_INTR_ERR_CEB_MASK 0x00000004U /**< Command End Bit + Error */ +#define XSDPS_INTR_ERR_CI_MASK 0x00000008U /**< Command Index Error */ +#define XSDPS_INTR_ERR_DT_MASK 0x00000010U /**< Data Timeout Error */ +#define XSDPS_INTR_ERR_DCRC_MASK 0x00000020U /**< Data CRC Error */ +#define XSDPS_INTR_ERR_DEB_MASK 0x00000040U /**< Data End Bit Error */ +#define XSDPS_INTR_ERR_CUR_LMT_MASK 0x00000080U /**< Current Limit Error */ +#define XSDPS_INTR_ERR_AUTO_CMD12_MASK 0x00000100U /**< Auto CMD12 Error */ +#define XSDPS_INTR_ERR_ADMA_MASK 0x00000200U /**< ADMA Error */ +#define XSDPS_INTR_ERR_TR_MASK 0x00001000U /**< Tuning Error */ +#define XSDPS_INTR_VEND_SPF_ERR_MASK 0x0000E000U /**< Vendor Specific + Error */ +#define XSDPS_ERROR_INTR_ALL_MASK 0x0000F3FFU /**< Mask for error bits */ +/* @} */ + +/** @name Block Size and Block Count Register + * + * This register contains the block count for current transfer, + * block size and SDMA buffer size. + * Read/Write except for reserved bits. + * @{ + */ + +#define XSDPS_BLK_SIZE_MASK 0x00000FFFU /**< Transfer Block Size */ +#define XSDPS_SDMA_BUFF_SIZE_MASK 0x00007000U /**< Host SDMA Buffer Size */ +#define XSDPS_BLK_SIZE_1024 0x400U +#define XSDPS_BLK_SIZE_2048 0x800U +#define XSDPS_BLK_CNT_MASK 0x0000FFFFU /**< Block Count for + Current Transfer */ + +/* @} */ + +/** @name Transfer Mode and Command Register + * + * The Transfer Mode register is used to control the data transfers and + * Command register is used for command generation + * Read/Write except for reserved bits. + * @{ + */ + +#define XSDPS_TM_DMA_EN_MASK 0x00000001U /**< DMA Enable */ +#define XSDPS_TM_BLK_CNT_EN_MASK 0x00000002U /**< Block Count Enable */ +#define XSDPS_TM_AUTO_CMD12_EN_MASK 0x00000004U /**< Auto CMD12 Enable */ +#define XSDPS_TM_DAT_DIR_SEL_MASK 0x00000010U /**< Data Transfer + Direction Select */ +#define XSDPS_TM_MUL_SIN_BLK_SEL_MASK 0x00000020U /**< Multi/Single + Block Select */ + +#define XSDPS_CMD_RESP_SEL_MASK 0x00000003U /**< Response Type + Select */ +#define XSDPS_CMD_RESP_NONE_MASK 0x00000000U /**< No Response */ +#define XSDPS_CMD_RESP_L136_MASK 0x00000001U /**< Response length 138 */ +#define XSDPS_CMD_RESP_L48_MASK 0x00000002U /**< Response length 48 */ +#define XSDPS_CMD_RESP_L48_BSY_CHK_MASK 0x00000003U /**< Response length 48 & + check busy after + response */ +#define XSDPS_CMD_CRC_CHK_EN_MASK 0x00000008U /**< Command CRC Check + Enable */ +#define XSDPS_CMD_INX_CHK_EN_MASK 0x00000010U /**< Command Index Check + Enable */ +#define XSDPS_DAT_PRESENT_SEL_MASK 0x00000020U /**< Data Present Select */ +#define XSDPS_CMD_TYPE_MASK 0x000000C0U /**< Command Type */ +#define XSDPS_CMD_TYPE_NORM_MASK 0x00000000U /**< CMD Type - Normal */ +#define XSDPS_CMD_TYPE_SUSPEND_MASK 0x00000040U /**< CMD Type - Suspend */ +#define XSDPS_CMD_TYPE_RESUME_MASK 0x00000080U /**< CMD Type - Resume */ +#define XSDPS_CMD_TYPE_ABORT_MASK 0x000000C0U /**< CMD Type - Abort */ +#define XSDPS_CMD_MASK 0x00003F00U /**< Command Index Mask - + Set to CMD0-63, + AMCD0-63 */ + +/* @} */ + +/** @name Auto CMD Error Status Register + * + * This register is read only register which contains + * information about the error status of Auto CMD 12 and 23. + * Read Only + * @{ + */ +#define XSDPS_AUTO_CMD12_NT_EX_MASK 0x0001U /**< Auto CMD12 Not + executed */ +#define XSDPS_AUTO_CMD_TOUT_MASK 0x0002U /**< Auto CMD Timeout + Error */ +#define XSDPS_AUTO_CMD_CRC_MASK 0x0004U /**< Auto CMD CRC Error */ +#define XSDPS_AUTO_CMD_EB_MASK 0x0008U /**< Auto CMD End Bit + Error */ +#define XSDPS_AUTO_CMD_IND_MASK 0x0010U /**< Auto CMD Index Error */ +#define XSDPS_AUTO_CMD_CNI_ERR_MASK 0x0080U /**< Command not issued by + Auto CMD12 Error */ +/* @} */ + +/** @name Host Control2 Register + * + * This register contains extended configuration bits. + * Read Write + * @{ + */ +#define XSDPS_HC2_UHS_MODE_MASK 0x0007U /**< UHS Mode select bits */ +#define XSDPS_HC2_UHS_MODE_SDR12_MASK 0x0000U /**< SDR12 UHS Mode */ +#define XSDPS_HC2_UHS_MODE_SDR25_MASK 0x0001U /**< SDR25 UHS Mode */ +#define XSDPS_HC2_UHS_MODE_SDR50_MASK 0x0002U /**< SDR50 UHS Mode */ +#define XSDPS_HC2_UHS_MODE_SDR104_MASK 0x0003U /**< SDR104 UHS Mode */ +#define XSDPS_HC2_UHS_MODE_DDR50_MASK 0x0004U /**< DDR50 UHS Mode */ +#define XSDPS_HC2_1V8_EN_MASK 0x0008U /**< 1.8V Signal Enable */ +#define XSDPS_HC2_DRV_STR_SEL_MASK 0x0030U /**< Driver Strength + Selection */ +#define XSDPS_HC2_DRV_STR_B_MASK 0x0000U /**< Driver Strength B */ +#define XSDPS_HC2_DRV_STR_A_MASK 0x0010U /**< Driver Strength A */ +#define XSDPS_HC2_DRV_STR_C_MASK 0x0020U /**< Driver Strength C */ +#define XSDPS_HC2_DRV_STR_D_MASK 0x0030U /**< Driver Strength D */ +#define XSDPS_HC2_EXEC_TNG_MASK 0x0040U /**< Execute Tuning */ +#define XSDPS_HC2_SAMP_CLK_SEL_MASK 0x0080U /**< Sampling Clock + Selection */ +#define XSDPS_HC2_ASYNC_INTR_EN_MASK 0x4000U /**< Asynchronous Interrupt + Enable */ +#define XSDPS_HC2_PRE_VAL_EN_MASK 0x8000U /**< Preset Value Enable */ + +/* @} */ + +/** @name Capabilities Register + * + * Capabilities register is a read only register which contains + * information about the host controller. + * Sufficient if read once after power on. + * Read Only + * @{ + */ +#define XSDPS_CAP_TOUT_CLK_FREQ_MASK 0x0000003FU /**< Timeout clock freq + select */ +#define XSDPS_CAP_TOUT_CLK_UNIT_MASK 0x00000080U /**< Timeout clock unit - + MHz/KHz */ +#define XSDPS_CAP_MAX_BLK_LEN_MASK 0x00030000U /**< Max block length */ +#define XSDPS_CAP_MAX_BLK_LEN_512B_MASK 0x00000000U /**< Max block 512 bytes */ +#define XSDPS_CAP_MAX_BL_LN_1024_MASK 0x00010000U /**< Max block 1024 bytes */ +#define XSDPS_CAP_MAX_BL_LN_2048_MASK 0x00020000U /**< Max block 2048 bytes */ +#define XSDPS_CAP_MAX_BL_LN_4096_MASK 0x00030000U /**< Max block 4096 bytes */ + +#define XSDPS_CAP_EXT_MEDIA_BUS_MASK 0x00040000U /**< Extended media bus */ +#define XSDPS_CAP_ADMA2_MASK 0x00080000U /**< ADMA2 support */ +#define XSDPS_CAP_HIGH_SPEED_MASK 0x00200000U /**< High speed support */ +#define XSDPS_CAP_SDMA_MASK 0x00400000U /**< SDMA support */ +#define XSDPS_CAP_SUSP_RESUME_MASK 0x00800000U /**< Suspend/Resume + support */ +#define XSDPS_CAP_VOLT_3V3_MASK 0x01000000U /**< 3.3V support */ +#define XSDPS_CAP_VOLT_3V0_MASK 0x02000000U /**< 3.0V support */ +#define XSDPS_CAP_VOLT_1V8_MASK 0x04000000U /**< 1.8V support */ + +#define XSDPS_CAP_SYS_BUS_64_MASK 0x10000000U /**< 64 bit system bus + support */ +/* Spec 2.0 */ +#define XSDPS_CAP_INTR_MODE_MASK 0x08000000U /**< Interrupt mode + support */ +#define XSDPS_CAP_SPI_MODE_MASK 0x20000000U /**< SPI mode */ +#define XSDPS_CAP_SPI_BLOCK_MODE_MASK 0x40000000U /**< SPI block mode */ + + +/* Spec 3.0 */ +#define XSDPS_CAPS_ASYNC_INTR_MASK 0x20000000U /**< Async Interrupt + support */ +#define XSDPS_CAPS_SLOT_TYPE_MASK 0xC0000000U /**< Slot Type */ +#define XSDPS_CAPS_REM_CARD 0x00000000U /**< Removable Slot */ +#define XSDPS_CAPS_EMB_SLOT 0x40000000U /**< Embedded Slot */ +#define XSDPS_CAPS_SHR_BUS 0x80000000U /**< Shared Bus Slot */ + +#define XSDPS_ECAPS_SDR50_MASK 0x00000001U /**< SDR50 Mode support */ +#define XSDPS_ECAPS_SDR104_MASK 0x00000002U /**< SDR104 Mode support */ +#define XSDPS_ECAPS_DDR50_MASK 0x00000004U /**< DDR50 Mode support */ +#define XSDPS_ECAPS_DRV_TYPE_A_MASK 0x00000010U /**< DriverType A support */ +#define XSDPS_ECAPS_DRV_TYPE_C_MASK 0x00000020U /**< DriverType C support */ +#define XSDPS_ECAPS_DRV_TYPE_D_MASK 0x00000040U /**< DriverType D support */ +#define XSDPS_ECAPS_TMR_CNT_MASK 0x00000F00U /**< Timer Count for + Re-tuning */ +#define XSDPS_ECAPS_USE_TNG_SDR50_MASK 0x00002000U /**< SDR50 Mode needs + tuning */ +#define XSDPS_ECAPS_RE_TNG_MODES_MASK 0x0000C000U /**< Re-tuning modes + support */ +#define XSDPS_ECAPS_RE_TNG_MODE1_MASK 0x00000000U /**< Re-tuning mode 1 */ +#define XSDPS_ECAPS_RE_TNG_MODE2_MASK 0x00004000U /**< Re-tuning mode 2 */ +#define XSDPS_ECAPS_RE_TNG_MODE3_MASK 0x00008000U /**< Re-tuning mode 3 */ +#define XSDPS_ECAPS_CLK_MULT_MASK 0x00FF0000U /**< Clock Multiplier value + for Programmable clock + mode */ +#define XSDPS_ECAPS_SPI_MODE_MASK 0x01000000U /**< SPI mode */ +#define XSDPS_ECAPS_SPI_BLK_MODE_MASK 0x02000000U /**< SPI block mode */ + +/* @} */ + +/** @name Present State Register + * + * Gives the current status of the host controller + * Read Only + * @{ + */ + +#define XSDPS_PSR_INHIBIT_CMD_MASK 0x00000001U /**< Command inhibit - CMD */ +#define XSDPS_PSR_INHIBIT_DAT_MASK 0x00000002U /**< Command Inhibit - DAT */ +#define XSDPS_PSR_DAT_ACTIVE_MASK 0x00000004U /**< DAT line active */ +#define XSDPS_PSR_RE_TUNING_REQ_MASK 0x00000008U /**< Re-tuning request */ +#define XSDPS_PSR_WR_ACTIVE_MASK 0x00000100U /**< Write transfer active */ +#define XSDPS_PSR_RD_ACTIVE_MASK 0x00000200U /**< Read transfer active */ +#define XSDPS_PSR_BUFF_WR_EN_MASK 0x00000400U /**< Buffer write enable */ +#define XSDPS_PSR_BUFF_RD_EN_MASK 0x00000800U /**< Buffer read enable */ +#define XSDPS_PSR_CARD_INSRT_MASK 0x00010000U /**< Card inserted */ +#define XSDPS_PSR_CARD_STABLE_MASK 0x00020000U /**< Card state stable */ +#define XSDPS_PSR_CARD_DPL_MASK 0x00040000U /**< Card detect pin level */ +#define XSDPS_PSR_WPS_PL_MASK 0x00080000U /**< Write protect switch + pin level */ +#define XSDPS_PSR_DAT30_SG_LVL_MASK 0x00F00000U /**< Data 3:0 signal lvl */ +#define XSDPS_PSR_CMD_SG_LVL_MASK 0x01000000U /**< Cmd Line signal lvl */ +#define XSDPS_PSR_DAT74_SG_LVL_MASK 0x1E000000U /**< Data 7:4 signal lvl */ + +/* @} */ + +/** @name Maximum Current Capablities Register + * + * This register is read only register which contains + * information about current capabilities at each voltage levels. + * Read Only + * @{ + */ +#define XSDPS_MAX_CUR_CAPS_1V8_MASK 0x00000F00U /**< Maximum Current + Capability at 1.8V */ +#define XSDPS_MAX_CUR_CAPS_3V0_MASK 0x000000F0U /**< Maximum Current + Capability at 3.0V */ +#define XSDPS_MAX_CUR_CAPS_3V3_MASK 0x0000000FU /**< Maximum Current + Capability at 3.3V */ +/* @} */ + + +/** @name Force Event for Auto CMD Error Status Register + * + * This register is write only register which contains + * control bits to generate events for Auto CMD error status. + * Write Only + * @{ + */ +#define XSDPS_FE_AUTO_CMD12_NT_EX_MASK 0x0001U /**< Auto CMD12 Not + executed */ +#define XSDPS_FE_AUTO_CMD_TOUT_MASK 0x0002U /**< Auto CMD Timeout + Error */ +#define XSDPS_FE_AUTO_CMD_CRC_MASK 0x0004U /**< Auto CMD CRC Error */ +#define XSDPS_FE_AUTO_CMD_EB_MASK 0x0008U /**< Auto CMD End Bit + Error */ +#define XSDPS_FE_AUTO_CMD_IND_MASK 0x0010U /**< Auto CMD Index Error */ +#define XSDPS_FE_AUTO_CMD_CNI_ERR_MASK 0x0080U /**< Command not issued by + Auto CMD12 Error */ +/* @} */ + + + +/** @name Force Event for Error Interrupt Status Register + * + * This register is write only register which contains + * control bits to generate events of error interrupt status register. + * Write Only + * @{ + */ +#define XSDPS_FE_INTR_ERR_CT_MASK 0x0001U /**< Command Timeout + Error */ +#define XSDPS_FE_INTR_ERR_CCRC_MASK 0x0002U /**< Command CRC Error */ +#define XSDPS_FE_INTR_ERR_CEB_MASK 0x0004U /**< Command End Bit + Error */ +#define XSDPS_FE_INTR_ERR_CI_MASK 0x0008U /**< Command Index Error */ +#define XSDPS_FE_INTR_ERR_DT_MASK 0x0010U /**< Data Timeout Error */ +#define XSDPS_FE_INTR_ERR_DCRC_MASK 0x0020U /**< Data CRC Error */ +#define XSDPS_FE_INTR_ERR_DEB_MASK 0x0040U /**< Data End Bit Error */ +#define XSDPS_FE_INTR_ERR_CUR_LMT_MASK 0x0080U /**< Current Limit Error */ +#define XSDPS_FE_INTR_ERR_AUTO_CMD_MASK 0x0100U /**< Auto CMD Error */ +#define XSDPS_FE_INTR_ERR_ADMA_MASK 0x0200U /**< ADMA Error */ +#define XSDPS_FE_INTR_ERR_TR_MASK 0x1000U /**< Target Reponse */ +#define XSDPS_FE_INTR_VEND_SPF_ERR_MASK 0xE000U /**< Vendor Specific + Error */ + +/* @} */ + +/** @name ADMA Error Status Register + * + * This register is read only register which contains + * status information about ADMA errors. + * Read Only + * @{ + */ +#define XSDPS_ADMA_ERR_MM_LEN_MASK 0x04U /**< ADMA Length Mismatch + Error */ +#define XSDPS_ADMA_ERR_STATE_MASK 0x03U /**< ADMA Error State */ +#define XSDPS_ADMA_ERR_STATE_STOP_MASK 0x00U /**< ADMA Error State + STOP */ +#define XSDPS_ADMA_ERR_STATE_FDS_MASK 0x01U /**< ADMA Error State + FDS */ +#define XSDPS_ADMA_ERR_STATE_TFR_MASK 0x03U /**< ADMA Error State + TFR */ +/* @} */ + +/** @name Preset Values Register + * + * This register is read only register which contains + * preset values for each of speed modes. + * Read Only + * @{ + */ +#define XSDPS_PRE_VAL_SDCLK_FSEL_MASK 0x03FFU /**< SDCLK Frequency + Select Value */ +#define XSDPS_PRE_VAL_CLK_GEN_SEL_MASK 0x0400U /**< Clock Generator + Mode Select */ +#define XSDPS_PRE_VAL_DRV_STR_SEL_MASK 0xC000U /**< Driver Strength + Select Value */ + +/* @} */ + +/** @name Slot Interrupt Status Register + * + * This register is read only register which contains + * interrupt slot signal for each slot. + * Read Only + * @{ + */ +#define XSDPS_SLOT_INTR_STS_INT_MASK 0x0007U /**< Interrupt Signal + mask */ + +/* @} */ + +/** @name Host Controller Version Register + * + * This register is read only register which contains + * Host Controller and Vendor Specific version. + * Read Only + * @{ + */ +#define XSDPS_HC_VENDOR_VER 0xFF00U /**< Vendor + Specification + version mask */ +#define XSDPS_HC_SPEC_VER_MASK 0x00FFU /**< Host + Specification + version mask */ +#define XSDPS_HC_SPEC_V3 0x0002U +#define XSDPS_HC_SPEC_V2 0x0001U +#define XSDPS_HC_SPEC_V1 0x0000U + +/** @name Block size mask for 512 bytes + * + * Block size mask for 512 bytes - This is the default block size. + * @{ + */ + +#define XSDPS_BLK_SIZE_512_MASK 0x200U + +/* @} */ + +/** @name Commands + * + * Constant definitions for commands and response related to SD + * @{ + */ + +#define XSDPS_APP_CMD_PREFIX 0x8000U +#define CMD0 0x0000U +#define CMD1 0x0100U +#define CMD2 0x0200U +#define CMD3 0x0300U +#define CMD4 0x0400U +#define CMD5 0x0500U +#define CMD6 0x0600U +#define ACMD6 (XSDPS_APP_CMD_PREFIX + 0x0600U) +#define CMD7 0x0700U +#define CMD8 0x0800U +#define CMD9 0x0900U +#define CMD10 0x0A00U +#define CMD11 0x0B00U +#define CMD12 0x0C00U +#define CMD13 0x0D00U +#define ACMD13 (XSDPS_APP_CMD_PREFIX + 0x0D00U) +#define CMD16 0x1000U +#define CMD17 0x1100U +#define CMD18 0x1200U +#define CMD19 0x1300U +#define CMD21 0x1500U +#define CMD23 0x1700U +#define ACMD23 (XSDPS_APP_CMD_PREFIX + 0x1700U) +#define CMD24 0x1800U +#define CMD25 0x1900U +#define CMD41 0x2900U +#define ACMD41 (XSDPS_APP_CMD_PREFIX + 0x2900U) +#define ACMD42 (XSDPS_APP_CMD_PREFIX + 0x2A00U) +#define ACMD51 (XSDPS_APP_CMD_PREFIX + 0x3300U) +#define CMD52 0x3400U +#define CMD55 0x3700U +#define CMD58 0x3A00U + +#define RESP_NONE (u32)XSDPS_CMD_RESP_NONE_MASK +#define RESP_R1 (u32)XSDPS_CMD_RESP_L48_MASK | (u32)XSDPS_CMD_CRC_CHK_EN_MASK | \ + (u32)XSDPS_CMD_INX_CHK_EN_MASK + +#define RESP_R1B (u32)XSDPS_CMD_RESP_L48_BSY_CHK_MASK | \ + (u32)XSDPS_CMD_CRC_CHK_EN_MASK | (u32)XSDPS_CMD_INX_CHK_EN_MASK + +#define RESP_R2 (u32)XSDPS_CMD_RESP_L136_MASK | (u32)XSDPS_CMD_CRC_CHK_EN_MASK +#define RESP_R3 (u32)XSDPS_CMD_RESP_L48_MASK + +#define RESP_R6 (u32)XSDPS_CMD_RESP_L48_BSY_CHK_MASK | \ + (u32)XSDPS_CMD_CRC_CHK_EN_MASK | (u32)XSDPS_CMD_INX_CHK_EN_MASK + +/* @} */ + +/* Card Interface Conditions Definitions */ +#define XSDPS_CIC_CHK_PATTERN 0xAAU +#define XSDPS_CIC_VOLT_MASK (0xFU<<8) +#define XSDPS_CIC_VOLT_2V7_3V6 (1U<<8) +#define XSDPS_CIC_VOLT_LOW (1U<<9) + +/* Operation Conditions Register Definitions */ +#define XSDPS_OCR_PWRUP_STS (1U<<31) +#define XSDPS_OCR_CC_STS (1U<<30) +#define XSDPS_OCR_S18 (1U<<24) +#define XSDPS_OCR_3V5_3V6 (1U<<23) +#define XSDPS_OCR_3V4_3V5 (1U<<22) +#define XSDPS_OCR_3V3_3V4 (1U<<21) +#define XSDPS_OCR_3V2_3V3 (1U<<20) +#define XSDPS_OCR_3V1_3V2 (1U<<19) +#define XSDPS_OCR_3V0_3V1 (1U<<18) +#define XSDPS_OCR_2V9_3V0 (1U<<17) +#define XSDPS_OCR_2V8_2V9 (1U<<16) +#define XSDPS_OCR_2V7_2V8 (1U<<15) +#define XSDPS_OCR_1V7_1V95 (1U<<7) +#define XSDPS_OCR_HIGH_VOL 0x00FF8000U +#define XSDPS_OCR_LOW_VOL 0x00000080U + +/* SD Card Configuration Register Definitions */ +#define XSDPS_SCR_REG_LEN 8U +#define XSDPS_SCR_STRUCT_MASK (0xFU<<28) +#define XSDPS_SCR_SPEC_MASK (0xFU<<24) +#define XSDPS_SCR_SPEC_1V0 0U +#define XSDPS_SCR_SPEC_1V1 (1U<<24) +#define XSDPS_SCR_SPEC_2V0_3V0 (2U<<24) +#define XSDPS_SCR_MEM_VAL_AF_ERASE (1U<<23) +#define XSDPS_SCR_SEC_SUPP_MASK (7U<<20) +#define XSDPS_SCR_SEC_SUPP_NONE 0U +#define XSDPS_SCR_SEC_SUPP_1V1 (2U<<20) +#define XSDPS_SCR_SEC_SUPP_2V0 (3U<<20) +#define XSDPS_SCR_SEC_SUPP_3V0 (4U<<20) +#define XSDPS_SCR_BUS_WIDTH_MASK (0xFU<<16) +#define XSDPS_SCR_BUS_WIDTH_1 (1U<<16) +#define XSDPS_SCR_BUS_WIDTH_4 (4U<<16) +#define XSDPS_SCR_SPEC3_MASK (1U<<12) +#define XSDPS_SCR_SPEC3_2V0 0U +#define XSDPS_SCR_SPEC3_3V0 (1U<<12) +#define XSDPS_SCR_CMD_SUPP_MASK 0x3U +#define XSDPS_SCR_CMD23_SUPP (1U<<1) +#define XSDPS_SCR_CMD20_SUPP (1U<<0) + +/* Card Status Register Definitions */ +#define XSDPS_CD_STS_OUT_OF_RANGE (1U<<31) +#define XSDPS_CD_STS_ADDR_ERR (1U<<30) +#define XSDPS_CD_STS_BLK_LEN_ERR (1U<<29) +#define XSDPS_CD_STS_ER_SEQ_ERR (1U<<28) +#define XSDPS_CD_STS_ER_PRM_ERR (1U<<27) +#define XSDPS_CD_STS_WP_VIO (1U<<26) +#define XSDPS_CD_STS_IS_LOCKED (1U<<25) +#define XSDPS_CD_STS_LOCK_UNLOCK_FAIL (1U<<24) +#define XSDPS_CD_STS_CMD_CRC_ERR (1U<<23) +#define XSDPS_CD_STS_ILGL_CMD (1U<<22) +#define XSDPS_CD_STS_CARD_ECC_FAIL (1U<<21) +#define XSDPS_CD_STS_CC_ERR (1U<<20) +#define XSDPS_CD_STS_ERR (1U<<19) +#define XSDPS_CD_STS_CSD_OVRWR (1U<<16) +#define XSDPS_CD_STS_WP_ER_SKIP (1U<<15) +#define XSDPS_CD_STS_CARD_ECC_DIS (1U<<14) +#define XSDPS_CD_STS_ER_RST (1U<<13) +#define XSDPS_CD_STS_CUR_STATE (0xFU<<9) +#define XSDPS_CD_STS_RDY_FOR_DATA (1U<<8) +#define XSDPS_CD_STS_APP_CMD (1U<<5) +#define XSDPS_CD_STS_AKE_SEQ_ERR (1U<<2) + +/* Switch Function Definitions CMD6 */ +#define XSDPS_SWITCH_SD_RESP_LEN 64U + +#define XSDPS_SWITCH_FUNC_SWITCH (1U<<31) +#define XSDPS_SWITCH_FUNC_CHECK 0U + +#define XSDPS_MODE_FUNC_GRP1 1U +#define XSDPS_MODE_FUNC_GRP2 2U +#define XSDPS_MODE_FUNC_GRP3 3U +#define XSDPS_MODE_FUNC_GRP4 4U +#define XSDPS_MODE_FUNC_GRP5 5U +#define XSDPS_MODE_FUNC_GRP6 6U + +#define XSDPS_FUNC_GRP_DEF_VAL 0xFU +#define XSDPS_FUNC_ALL_GRP_DEF_VAL 0xFFFFFFU + +#define XSDPS_ACC_MODE_DEF_SDR12 0U +#define XSDPS_ACC_MODE_HS_SDR25 1U +#define XSDPS_ACC_MODE_SDR50 2U +#define XSDPS_ACC_MODE_SDR104 3U +#define XSDPS_ACC_MODE_DDR50 4U + +#define XSDPS_CMD_SYS_ARG_SHIFT 4U +#define XSDPS_CMD_SYS_DEF 0U +#define XSDPS_CMD_SYS_eC 1U +#define XSDPS_CMD_SYS_OTP 3U +#define XSDPS_CMD_SYS_ASSD 4U +#define XSDPS_CMD_SYS_VEND 5U + +#define XSDPS_DRV_TYPE_ARG_SHIFT 8U +#define XSDPS_DRV_TYPE_B 0U +#define XSDPS_DRV_TYPE_A 1U +#define XSDPS_DRV_TYPE_C 2U +#define XSDPS_DRV_TYPE_D 3U + +#define XSDPS_CUR_LIM_ARG_SHIFT 12U +#define XSDPS_CUR_LIM_200 0U +#define XSDPS_CUR_LIM_400 1U +#define XSDPS_CUR_LIM_600 2U +#define XSDPS_CUR_LIM_800 3U + + +/* EXT_CSD field definitions */ +#define XSDPS_EXT_CSD_SIZE 512U + +#define EXT_CSD_WR_REL_PARAM_EN (1U<<2) + +#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40U) +#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10U) +#define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04U) +#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01U) + +#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7U) +#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1U) +#define EXT_CSD_PART_CONFIG_ACC_RPMB (0x3U) +#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4U) + +#define EXT_CSD_PART_SUPPORT_PART_EN (0x1U) + +#define EXT_CSD_CMD_SET_NORMAL (1U<<0) +#define EXT_CSD_CMD_SET_SECURE (1U<<1) +#define EXT_CSD_CMD_SET_CPSECURE (1U<<2) + +#define EXT_CSD_CARD_TYPE_26 (1U<<0) /* Card can run at 26MHz */ +#define EXT_CSD_CARD_TYPE_52 (1U<<1) /* Card can run at 52MHz */ +#define EXT_CSD_CARD_TYPE_MASK 0x3FU /* Mask out reserved bits */ +#define EXT_CSD_CARD_TYPE_DDR_1_8V (1U<<2) /* Card can run at 52MHz */ + /* DDR mode @1.8V or 3V I/O */ +#define EXT_CSD_CARD_TYPE_DDR_1_2V (1U<<3) /* Card can run at 52MHz */ + /* DDR mode @1.2V I/O */ +#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \ + | EXT_CSD_CARD_TYPE_DDR_1_2V) +#define EXT_CSD_CARD_TYPE_SDR_1_8V (1U<<4) /* Card can run at 200MHz */ +#define EXT_CSD_CARD_TYPE_SDR_1_2V (1U<<5) /* Card can run at 200MHz */ + /* SDR mode @1.2V I/O */ +#define EXT_CSD_BUS_WIDTH_BYTE 183U +#define EXT_CSD_BUS_WIDTH_1_BIT 0U /* Card is in 1 bit mode */ +#define EXT_CSD_BUS_WIDTH_4_BIT 1U /* Card is in 4 bit mode */ +#define EXT_CSD_BUS_WIDTH_8_BIT 2U /* Card is in 8 bit mode */ +#define EXT_CSD_BUS_WIDTH_DDR_4_BIT 5U /* Card is in 4 bit DDR mode */ +#define EXT_CSD_BUS_WIDTH_DDR_8_BIT 6U /* Card is in 8 bit DDR mode */ + +#define EXT_CSD_HS_TIMING_BYTE 185U +#define EXT_CSD_HS_TIMING_DEF 0U +#define EXT_CSD_HS_TIMING_HIGH 1U /* Card is in high speed mode */ +#define EXT_CSD_HS_TIMING_HS200 2U /* Card is in HS200 mode */ + + +#define XSDPS_EXT_CSD_CMD_SET 0U +#define XSDPS_EXT_CSD_SET_BITS 1U +#define XSDPS_EXT_CSD_CLR_BITS 2U +#define XSDPS_EXT_CSD_WRITE_BYTE 3U + +#define XSDPS_MMC_DEF_SPEED_ARG (((u32)XSDPS_EXT_CSD_WRITE_BYTE << 24) \ + | ((u32)EXT_CSD_HS_TIMING_BYTE << 16) \ + | ((u32)EXT_CSD_HS_TIMING_DEF << 8)) + +#define XSDPS_MMC_HIGH_SPEED_ARG (((u32)XSDPS_EXT_CSD_WRITE_BYTE << 24) \ + | ((u32)EXT_CSD_HS_TIMING_BYTE << 16) \ + | ((u32)EXT_CSD_HS_TIMING_HIGH << 8)) + +#define XSDPS_MMC_HS200_ARG (((u32)XSDPS_EXT_CSD_WRITE_BYTE << 24) \ + | ((u32)EXT_CSD_HS_TIMING_BYTE << 16) \ + | ((u32)EXT_CSD_HS_TIMING_HS200 << 8)) + +#define XSDPS_MMC_1_BIT_BUS_ARG (((u32)XSDPS_EXT_CSD_WRITE_BYTE << 24) \ + | ((u32)EXT_CSD_BUS_WIDTH_BYTE << 16) \ + | ((u32)EXT_CSD_BUS_WITH_1_BIT << 8)) + +#define XSDPS_MMC_4_BIT_BUS_ARG (((u32)XSDPS_EXT_CSD_WRITE_BYTE << 24) \ + | ((u32)EXT_CSD_BUS_WIDTH_BYTE << 16) \ + | ((u32)EXT_CSD_BUS_WIDTH_4_BIT << 8)) + +#define XSDPS_MMC_8_BIT_BUS_ARG (((u32)XSDPS_EXT_CSD_WRITE_BYTE << 24) \ + | ((u32)EXT_CSD_BUS_WIDTH_BYTE << 16) \ + | ((u32)EXT_CSD_BUS_WIDTH_8_BIT << 8)) + +#define XSDPS_MMC_DDR_4_BIT_BUS_ARG (((u32)XSDPS_EXT_CSD_WRITE_BYTE << 24) \ + | ((u32)EXT_CSD_BUS_WIDTH_BYTE << 16) \ + | ((u32)EXT_CSD_BUS_WIDTH_DDR_4_BIT << 8)) + +#define XSDPS_MMC_DDR_8_BIT_BUS_ARG (((u32)XSDPS_EXT_CSD_WRITE_BYTE << 24) \ + | ((u32)EXT_CSD_BUS_WIDTH_BYTE << 16) \ + | ((u32)EXT_CSD_BUS_WIDTH_DDR_8_BIT << 8)) + +#define XSDPS_MMC_DELAY_FOR_SWITCH 1000U + +/* @} */ + +/* @400KHz, in usec */ +#define XSDPS_74CLK_DELAY 2960U +#define XSDPS_100CLK_DELAY 4000U +#define XSDPS_INIT_DELAY 10000U + +#define XSDPS_DEF_VOLT_LVL XSDPS_PC_BUS_VSEL_3V0_MASK +#define XSDPS_CARD_DEF_ADDR 0x1234U + +#define XSDPS_CARD_SD 1U +#define XSDPS_CARD_MMC 2U +#define XSDPS_CARD_SDIO 3U +#define XSDPS_CARD_SDCOMBO 4U +#define XSDPS_CHIP_EMMC 5U + + +/** @name ADMA2 Descriptor related definitions + * + * ADMA2 Descriptor related definitions + * @{ + */ + +#define XSDPS_DESC_MAX_LENGTH 65536U + +#define XSDPS_DESC_VALID (0x1U << 0) +#define XSDPS_DESC_END (0x1U << 1) +#define XSDPS_DESC_INT (0x1U << 2) +#define XSDPS_DESC_TRAN (0x2U << 4) + +/* @} */ + +/* For changing clock frequencies */ +#define XSDPS_CLK_400_KHZ 400000U /**< 400 KHZ */ +#define XSDPS_CLK_50_MHZ 50000000U /**< 50 MHZ */ +#define XSDPS_CLK_52_MHZ 52000000U /**< 52 MHZ */ +#define XSDPS_SD_VER_1_0 0x1U /**< SD ver 1 */ +#define XSDPS_SD_VER_2_0 0x2U /**< SD ver 2 */ +#define XSDPS_SCR_BLKCNT 1U +#define XSDPS_SCR_BLKSIZE 8U +#define XSDPS_1_BIT_WIDTH 0x1U +#define XSDPS_4_BIT_WIDTH 0x2U +#define XSDPS_8_BIT_WIDTH 0x3U +#define XSDPS_UHS_SPEED_MODE_SDR12 0x0U +#define XSDPS_UHS_SPEED_MODE_SDR25 0x1U +#define XSDPS_UHS_SPEED_MODE_SDR50 0x2U +#define XSDPS_UHS_SPEED_MODE_SDR104 0x3U +#define XSDPS_UHS_SPEED_MODE_DDR50 0x4U +#define XSDPS_SWITCH_CMD_BLKCNT 1U +#define XSDPS_SWITCH_CMD_BLKSIZE 64U +#define XSDPS_SWITCH_CMD_HS_GET 0x00FFFFF0U +#define XSDPS_SWITCH_CMD_HS_SET 0x80FFFFF1U +#define XSDPS_SWITCH_CMD_SDR12_SET 0x80FFFFF0U +#define XSDPS_SWITCH_CMD_SDR25_SET 0x80FFFFF1U +#define XSDPS_SWITCH_CMD_SDR50_SET 0x80FFFFF2U +#define XSDPS_SWITCH_CMD_SDR104_SET 0x80FFFFF3U +#define XSDPS_SWITCH_CMD_DDR50_SET 0x80FFFFF4U +#define XSDPS_EXT_CSD_CMD_BLKCNT 1U +#define XSDPS_EXT_CSD_CMD_BLKSIZE 512U +#define XSDPS_TUNING_CMD_BLKCNT 1U +#define XSDPS_TUNING_CMD_BLKSIZE 64U + +#define XSDPS_HIGH_SPEED_MAX_CLK 50000000U +#define XSDPS_UHS_SDR104_MAX_CLK 208000000U +#define XSDPS_UHS_SDR50_MAX_CLK 100000000U +#define XSDPS_UHS_DDR50_MAX_CLK 50000000U +#define XSDPS_UHS_SDR25_MAX_CLK 50000000U +#define XSDPS_UHS_SDR12_MAX_CLK 25000000U + +#define SD_DRIVER_TYPE_B 0x01U +#define SD_DRIVER_TYPE_A 0x02U +#define SD_DRIVER_TYPE_C 0x04U +#define SD_DRIVER_TYPE_D 0x08U +#define SD_SET_CURRENT_LIMIT_200 0U +#define SD_SET_CURRENT_LIMIT_400 1U +#define SD_SET_CURRENT_LIMIT_600 2U +#define SD_SET_CURRENT_LIMIT_800 3U + +#define SD_MAX_CURRENT_200 (1U << SD_SET_CURRENT_LIMIT_200) +#define SD_MAX_CURRENT_400 (1U << SD_SET_CURRENT_LIMIT_400) +#define SD_MAX_CURRENT_600 (1U << SD_SET_CURRENT_LIMIT_600) +#define SD_MAX_CURRENT_800 (1U << SD_SET_CURRENT_LIMIT_800) + +#define XSDPS_SD_SDR12_MAX_CLK 25000000U +#define XSDPS_SD_SDR25_MAX_CLK 50000000U +#define XSDPS_SD_SDR50_MAX_CLK 100000000U +#define XSDPS_SD_DDR50_MAX_CLK 50000000U +#define XSDPS_SD_SDR104_MAX_CLK 208000000U +#define XSDPS_MMC_HS200_MAX_CLK 200000000U + +#define XSDPS_CARD_STATE_IDLE 0U +#define XSDPS_CARD_STATE_RDY 1U +#define XSDPS_CARD_STATE_IDEN 2U +#define XSDPS_CARD_STATE_STBY 3U +#define XSDPS_CARD_STATE_TRAN 4U +#define XSDPS_CARD_STATE_DATA 5U +#define XSDPS_CARD_STATE_RCV 6U +#define XSDPS_CARD_STATE_PROG 7U +#define XSDPS_CARD_STATE_DIS 8U +#define XSDPS_CARD_STATE_BTST 9U +#define XSDPS_CARD_STATE_SLP 10U + +#define XSDPS_SLOT_REM 0U +#define XSDPS_SLOT_EMB 1U + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ +#define XSdPs_In64 Xil_In64 +#define XSdPs_Out64 Xil_Out64 + +#define XSdPs_In32 Xil_In32 +#define XSdPs_Out32 Xil_Out32 + +#define XSdPs_In16 Xil_In16 +#define XSdPs_Out16 Xil_Out16 + +#define XSdPs_In8 Xil_In8 +#define XSdPs_Out8 Xil_Out8 + +/****************************************************************************/ +/** +* Read a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to the target register. +* +* @return The value read from the register. +* +* @note C-Style signature: +* u32 XSdPs_ReadReg(XSdPs *InstancePtr. s32 RegOffset) +* +******************************************************************************/ +#define XSdPs_ReadReg64(InstancePtr, RegOffset) \ + XSdPs_In64((InstancePtr->Config.BaseAddress) + RegOffset) + +/***************************************************************************/ +/** +* Write to a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to target register. +* @param RegisterValue is the value to be written to the register. +* +* @return None. +* +* @note C-Style signature: +* void XSdPs_WriteReg(XSdPs *InstancePtr, s32 RegOffset, +* u64 RegisterValue) +* +******************************************************************************/ +#define XSdPs_WriteReg64(InstancePtr, RegOffset, RegisterValue) \ + XSdPs_Out64((InstancePtr->Config.BaseAddress) + (RegOffset), \ + (RegisterValue)) + +/****************************************************************************/ +/** +* Read a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to the target register. +* +* @return The value read from the register. +* +* @note C-Style signature: +* u32 XSdPs_ReadReg(u32 BaseAddress. int RegOffset) +* +******************************************************************************/ +#define XSdPs_ReadReg(BaseAddress, RegOffset) \ + XSdPs_In32((BaseAddress) + (RegOffset)) + +/***************************************************************************/ +/** +* Write to a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to target register. +* @param RegisterValue is the value to be written to the register. +* +* @return None. +* +* @note C-Style signature: +* void XSdPs_WriteReg(u32 BaseAddress, int RegOffset, +* u32 RegisterValue) +* +******************************************************************************/ +#define XSdPs_WriteReg(BaseAddress, RegOffset, RegisterValue) \ + XSdPs_Out32((BaseAddress) + (RegOffset), (RegisterValue)) + +/****************************************************************************/ +/** +* Read a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to the target register. +* +* @return The value read from the register. +* +* @note C-Style signature: +* u16 XSdPs_ReadReg(u32 BaseAddress. int RegOffset) +* +******************************************************************************/ +#define XSdPs_ReadReg16(BaseAddress, RegOffset) \ + XSdPs_In16((BaseAddress) + (RegOffset)) + +/***************************************************************************/ +/** +* Write to a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to target register. +* @param RegisterValue is the value to be written to the register. +* +* @return None. +* +* @note C-Style signature: +* void XSdPs_WriteReg(u32 BaseAddress, int RegOffset, +* u16 RegisterValue) +* +******************************************************************************/ +#define XSdPs_WriteReg16(BaseAddress, RegOffset, RegisterValue) \ + XSdPs_Out16((BaseAddress) + (RegOffset), (RegisterValue)) + +/****************************************************************************/ +/** +* Read a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to the target register. +* +* @return The value read from the register. +* +* @note C-Style signature: +* u8 XSdPs_ReadReg(u32 BaseAddress. int RegOffset) +* +******************************************************************************/ +#define XSdPs_ReadReg8(BaseAddress, RegOffset) \ + XSdPs_In8((BaseAddress) + (RegOffset)) + +/***************************************************************************/ +/** +* Write to a register. +* +* @param BaseAddress contains the base address of the device. +* @param RegOffset contains the offset from the 1st register of the +* device to target register. +* @param RegisterValue is the value to be written to the register. +* +* @return None. +* +* @note C-Style signature: +* void XSdPs_WriteReg(u32 BaseAddress, int RegOffset, +* u8 RegisterValue) +* +******************************************************************************/ +#define XSdPs_WriteReg8(BaseAddress, RegOffset, RegisterValue) \ + XSdPs_Out8((BaseAddress) + (RegOffset), (RegisterValue)) + +/***************************************************************************/ +/** +* Macro to get present status register +* +* @param BaseAddress contains the base address of the device. +* +* @return None. +* +* @note C-Style signature: +* void XSdPs_WriteReg(u32 BaseAddress, int RegOffset, +* u8 RegisterValue) +* +******************************************************************************/ +#define XSdPs_GetPresentStatusReg(BaseAddress) \ + XSdPs_In32((BaseAddress) + (XSDPS_PRES_STATE_OFFSET)) + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* SD_HW_H_ */ +/** @} */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_info.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_info.c new file mode 100644 index 000000000..4ea13be80 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_info.c @@ -0,0 +1,300 @@ +/****************************************************************************** + * + * mmc_decode_cid() and sd_decode_csd() + * + * analyse the meta data of an SD-card to read its capacity and some other properties. + * + * CID and CSD Analysis borrowed from the Linux kernel. + * + ******************************************************************************/ + +#include "xsdps.h" + +#include "xparameters.h" +#include "xil_cache.h" + +#include "ff_headers.h" + +#include "xsdps_info.h" + +struct mmc_cid myCID; +struct mmc_csd myCSD; + +u32 UNSTUFF_BITS( u32 *ulResponse, int iFirst, int iSize ) +{ +const u32 ulMask = ( iSize < 32 ? ( 1 << iSize ) : 0 ) - 1; +const int iOffset = 3 - ( iFirst / 32); +const int iShiftCount = iFirst & 31; +u32 ulResult; + + ulResult = ulResponse[ iOffset ] >> iShiftCount; + if( iSize + iShiftCount > 32 ) + { + ulResult |= ulResponse[ iOffset - 1 ] << ( ( 32 - iShiftCount ) % 32 ); + } + return ulResult & ulMask; \ +} + +int mmc_decode_cid( const struct mmc_csd *pxCSD, struct mmc_cid *pxCID, u32 *ulResponse ) +{ +int iResult = 0; + + /* + * The selection of the format here is based upon published + * specs from sandisk and from what people have reported. + */ + + switch( pxCSD->mmca_vsn ) + { + case 0: /* MMC v1.0 - v1.2 */ + case 1: /* MMC v1.4 */ + pxCID->manfid = UNSTUFF_BITS( ulResponse, 104, 24 ); + pxCID->prod_name[ 0 ] = UNSTUFF_BITS( ulResponse, 96, 8 ); + pxCID->prod_name[ 1 ] = UNSTUFF_BITS( ulResponse, 88, 8 ); + pxCID->prod_name[ 2 ] = UNSTUFF_BITS( ulResponse, 80, 8 ); + pxCID->prod_name[ 3 ] = UNSTUFF_BITS( ulResponse, 72, 8 ); + pxCID->prod_name[ 4 ] = UNSTUFF_BITS( ulResponse, 64, 8 ); + pxCID->prod_name[ 5 ] = UNSTUFF_BITS( ulResponse, 56, 8 ); + pxCID->prod_name[ 6 ] = UNSTUFF_BITS( ulResponse, 48, 8 ); + pxCID->hwrev = UNSTUFF_BITS( ulResponse, 44, 4 ); + pxCID->fwrev = UNSTUFF_BITS( ulResponse, 40, 4 ); + pxCID->serial = UNSTUFF_BITS( ulResponse, 16, 24 ); + pxCID->month = UNSTUFF_BITS( ulResponse, 12, 4 ); + pxCID->year = UNSTUFF_BITS( ulResponse, 8, 4 ) + 1997; + break; + + case 2: /* MMC v2.0 - v2.2 */ + case 3: /* MMC v3.1 - v3.3 */ + case 4: /* MMC v4 */ + pxCID->manfid = UNSTUFF_BITS( ulResponse, 120, 8 ); + pxCID->oemid = UNSTUFF_BITS( ulResponse, 104, 16 ); + pxCID->prod_name[ 0 ] = UNSTUFF_BITS( ulResponse, 96, 8 ); + pxCID->prod_name[ 1 ] = UNSTUFF_BITS( ulResponse, 88, 8 ); + pxCID->prod_name[ 2 ] = UNSTUFF_BITS( ulResponse, 80, 8 ); + pxCID->prod_name[ 3 ] = UNSTUFF_BITS( ulResponse, 72, 8 ); + pxCID->prod_name[ 4 ] = UNSTUFF_BITS( ulResponse, 64, 8 ); + pxCID->prod_name[ 5 ] = UNSTUFF_BITS( ulResponse, 56, 8 ); + pxCID->serial = UNSTUFF_BITS( ulResponse, 16, 32 ); + pxCID->month = UNSTUFF_BITS( ulResponse, 12, 4 ); + pxCID->year = UNSTUFF_BITS( ulResponse, 8, 4 ) + 1997; + break; + + default: + FF_PRINTF ("mmc_decode_cid: card has unknown MMCA version %d\n", + pxCSD->mmca_vsn); + iResult = -1; + break; + } + if( iResult >= 0 ) + { + FF_PRINTF ("CID: Manfid %lu (%-8.8s) serial %lu oem %u mon/year %u/%u rev %u fw %u\n", + pxCID->manfid, + pxCID->prod_name, + pxCID->serial, + pxCID->oemid, + pxCID->month, + pxCID->year, + pxCID->hwrev, + pxCID->fwrev); + } + + return iResult; +} + +static const unsigned int tran_exp[] = +{ + 10000, 100000, 1000000, 10000000, + 0, 0, 0, 0 +}; + +static const unsigned char tran_mant[] = +{ + 0, 10, 12, 13, 15, 20, 25, 30, + 35, 40, 45, 50, 55, 60, 70, 80, +}; + +static const unsigned int tacc_exp[] = +{ + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, +}; + +static const unsigned int tacc_mant[] = +{ + 0, 10, 12, 13, 15, 20, 25, 30, + 35, 40, 45, 50, 55, 60, 70, 80, +}; + +char mmc_is_block_addressed; + +/* Given a 128-bit response, decode to our card CSD structure. */ + +static __inline unsigned tobe32( unsigned value ) +{ + return + ( value >> 24 ) | + ( ( value >> 8 ) & 0x0000ff00 ) | + ( ( value << 8 ) & 0x00ff0000 ) | + ( value << 24 ); + +} + +int sd_decode_csd( struct mmc_csd *pxCSD, u32 *ulResponse ) +{ +unsigned int e, m, csd_struct; +int iResult = 0; + + csd_struct = UNSTUFF_BITS( ulResponse, 126, 2 ); + + pxCSD->mmca_vsn = UNSTUFF_BITS( ulResponse, 122, 4 ); + + FF_PRINTF("CSD data: %08x %08x %08x %08x mmca_vsn = %u\n", + ( unsigned )ulResponse[0], + ( unsigned )ulResponse[1], + ( unsigned )ulResponse[2], + ( unsigned )ulResponse[3], + pxCSD->mmca_vsn); +// pxCSD->mmca_vsn = 2; + + // CSD data: 005e0032 5f5a83cb 2db7ffbf 9680000f + // sd_decode_csd: capacity 1989120 (byte addressed) + switch (csd_struct) { + case 0: + m = UNSTUFF_BITS( ulResponse, 115, 4 ); + e = UNSTUFF_BITS( ulResponse, 112, 3 ); + pxCSD->tacc_ns = ( tacc_exp[ e ] * tacc_mant[ m ] + 9 ) / 10; + pxCSD->tacc_clks = UNSTUFF_BITS( ulResponse, 104, 8 ) * 100; + + m = UNSTUFF_BITS( ulResponse, 99, 4 ); + e = UNSTUFF_BITS( ulResponse, 96, 3 ); + pxCSD->max_dtr = tran_exp[ e ] * tran_mant[ m ]; + pxCSD->cmdclass = UNSTUFF_BITS( ulResponse, 84, 12 ); + + e = UNSTUFF_BITS( ulResponse, 47, 3 ); + m = UNSTUFF_BITS( ulResponse, 62, 12 ); + pxCSD->capacity = ( 1 + m ) << ( e + 2 ); + /* + * The CSD capacity field is in units of read_blkbits. + * set_capacity takes units of 512 bytes. + */ + + pxCSD->read_blkbits = UNSTUFF_BITS( ulResponse, 80, 4 ); + pxCSD->read_partial = UNSTUFF_BITS( ulResponse, 79, 1 ); + pxCSD->write_misalign = UNSTUFF_BITS( ulResponse, 78, 1 ); + pxCSD->read_misalign = UNSTUFF_BITS( ulResponse, 77, 1 ); + pxCSD->r2w_factor = UNSTUFF_BITS( ulResponse, 26, 3 ); + pxCSD->write_blkbits = UNSTUFF_BITS( ulResponse, 22, 4 ); + pxCSD->write_partial = UNSTUFF_BITS( ulResponse, 21, 1 ); + + pxCSD->capacity <<= ( pxCSD->read_blkbits - 9 ); + FF_PRINTF ("Capacity: (%u + 1) << (%u + 2) = %u Rd/Wr bits %u/%u\n", + m, e, + ( unsigned )pxCSD->capacity, + ( unsigned )pxCSD->read_blkbits, + ( unsigned )pxCSD->write_blkbits); + + if( UNSTUFF_BITS( ulResponse, 46, 1 ) ) + { + pxCSD->erase_size = 1; + } + else if( pxCSD->write_blkbits >= 9 ) + { + pxCSD->erase_size = UNSTUFF_BITS( ulResponse, 39, 7 ) + 1; + pxCSD->erase_size <<= pxCSD->write_blkbits - 9; + } + else + { + pxCSD->erase_size = 0; // Card is not eraseble + } + break; + + case 1: + /* + * This is a block-addressed SDHC card. Most + * interesting fields are unused and have fixed + * values. To avoid getting tripped by buggy cards, + * we assume those fixed values ourselves. + */ + mmc_is_block_addressed = 1; + + pxCSD->tacc_ns = 0; /* Unused */ + pxCSD->tacc_clks = 0; /* Unused */ + + m = UNSTUFF_BITS( ulResponse, 99, 4 ); + e = UNSTUFF_BITS( ulResponse, 96, 3 ); + // max_dtr gives 25,000,000 + pxCSD->max_dtr = tran_exp[ e ] * tran_mant[ m ]; + // cmdClass gives: 10110110101 (0x5B5) + pxCSD->cmdclass = UNSTUFF_BITS( ulResponse, 84, 12 ); + + m = UNSTUFF_BITS( ulResponse, 48, 22 ); + pxCSD->capacity = ( 1 + m ) << 10; + + FF_PRINTF( "capacity: (1 + %u) << 10 DTR %u Mhz\n", m, pxCSD->max_dtr / 1000000); + + pxCSD->read_blkbits = 9; + pxCSD->read_partial = 0; + pxCSD->write_misalign = 0; + pxCSD->read_misalign = 0; + pxCSD->r2w_factor = 4; /* Unused */ + pxCSD->write_blkbits = 9; + pxCSD->write_partial = 0; + pxCSD->erase_size = 1; + break; + default: + FF_PRINTF ("sd_decode_csd: unrecognised CSD structure version %d\n", csd_struct); + iResult = -1; + break; + } + if( iResult >= 0 ) + { + unsigned int sz; + + FF_PRINTF ("sd_decode_csd: capacity %lu (%s addressed)\n", + pxCSD->capacity, mmc_is_block_addressed ? "block" : "byte"); + + sz = (pxCSD->capacity << (pxCSD->read_blkbits - 9)) >> 11; + if (sz < 128) + { + pxCSD->pref_erase = 512 * 1024 / 512; + } + else if (sz < 512) + { + pxCSD->pref_erase = 1024 * 1024 / 512; + } + else if (sz < 1024) + { + pxCSD->pref_erase = 2 * 1024 * 1024 / 512; + } + else + { + pxCSD->pref_erase = 4 * 1024 * 1024 / 512; + } + + if (pxCSD->pref_erase < pxCSD->erase_size) + { + pxCSD->pref_erase = pxCSD->erase_size; + } + else + { + sz = ( pxCSD->pref_erase % pxCSD->erase_size ); + if( sz != 0 ) + { + pxCSD->pref_erase += ( pxCSD->erase_size - sz ); + } + } + + // compute last block addr + + pxCSD->sd_last_block_address = pxCSD->capacity - 1; + + // compute card capacity in bytes + pxCSD->capacity_bytes = ( ( uint64_t )XSDPS_BLK_SIZE_512_MASK ) * pxCSD->capacity; + + FF_PRINTF( "sd_mmc_spi_get_capacity: Capacity %lu MB Erase %u Pref %lu\n", + ( uint32_t ) ( pxCSD->capacity_bytes / ( 1024LLU * 1024LLU ) ), + pxCSD->erase_size, + pxCSD->pref_erase ); + } + + return iResult; +} diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_info.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_info.h new file mode 100644 index 000000000..94e822f96 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_info.h @@ -0,0 +1,56 @@ +/****************************************************************************** + * + * mmc_decode_cid() and sd_decode_csd() + * + * analyse the meta data of an SD-card to read its capacity and some other properties. + * + * CID and CSD Analysis borrowed from the Linux kernel. + * + ******************************************************************************/ + +#ifndef SDPS_INFO_H_ + +#define SDPS_INFO_H_ 1 + +#include + +struct mmc_cid { + uint32_t manfid; + char prod_name[8]; + uint32_t serial; + uint16_t oemid; + uint16_t year; + uint8_t hwrev; + uint8_t fwrev; + uint8_t month; +}; + +struct mmc_csd { + volatile uint64_t capacity_bytes; + uint32_t sd_last_block_address; + uint8_t mmca_vsn; + uint16_t erase_size; + uint8_t spare; + uint16_t cmdclass; + uint16_t tacc_clks; + int32_t erase_shift; + uint32_t tacc_ns; + uint32_t r2w_factor; + uint32_t max_dtr; + uint32_t read_blkbits; + uint32_t write_blkbits; + uint32_t capacity; + uint32_t pref_erase; + uint32_t read_partial : 1, + read_misalign : 1, + write_partial : 1, + write_misalign : 1; +}; + +extern struct mmc_cid myCID; +extern struct mmc_csd myCSD; + +int mmc_decode_cid( const struct mmc_csd *pxCSD, struct mmc_cid *pxCID, uint32_t *raw_data ); +int sd_decode_csd( struct mmc_csd *pxCSD, uint32_t *ulResponse ); + +#endif /* SDPS_INFO_H_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_options.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_options.c new file mode 100644 index 000000000..117d0a115 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_options.c @@ -0,0 +1,978 @@ +/****************************************************************************** +* +* Copyright (C) 2013 - 2015 Xilinx, Inc. All rights reserved. +* +* 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xsdps_options.c +* @addtogroup sdps_v2_5 +* @{ +* +* Contains API's for changing the various options in host and card. +* See xsdps.h for a detailed description of the device and driver. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date     Changes
+* ----- ---    -------- -----------------------------------------------
+* 1.00a hk/sg  10/17/13 Initial release
+* 2.1   hk     04/18/14 Increase sleep for eMMC switch command.
+*                       Add sleep for microblaze designs. CR# 781117.
+* 2.3   sk     09/23/14 Use XSdPs_Change_ClkFreq API whenever changing
+*						clock.CR# 816586.
+* 2.5 	sg	   07/09/15 Added SD 3.0 features
+*       kvn    07/15/15 Modified the code according to MISRAC-2012.
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "xsdps.h" +#include "xil_cache.h" +/* + * The header sleep.h and API usleep() can only be used with an arm design. + * MB_Sleep() is used for microblaze design. + */ +#if defined (__arm__) || defined (__aarch64__) + +#include "sleep.h" + +#endif + +#ifdef __MICROBLAZE__ + +#include "microblaze_sleep.h" + +#endif + +#include +#include "task.h" + +#include "FreeRTOSFATConfig.h" +#include "uncached_memory.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ +s32 XSdPs_CmdTransfer(XSdPs *InstancePtr, u32 Cmd, u32 Arg, u32 BlkCnt); +void XSdPs_SetupADMA2DescTbl(XSdPs *InstancePtr, u32 BlkCnt, const u8 *Buff); +s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode); +static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr); +s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode); + +#if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 ) + /* Declared in ff_sddisk.c : + Function will sleep and get interrupted on a change of + the status register. It will loop until: + 1. Expected bit (ulMask) becomes high + 2. Time-out reached (normally 2 seconds) + */ + extern u32 XSdPs_WaitInterrupt( XSdPs *InstancePtr, u32 ulMask ); + /* Clear the interrupt before using it. */ + extern void XSdPs_ClearInterrupt( XSdPs *InstancePtr ); +#else + #error Please define ffconfigSDIO_DRIVER_USES_INTERRUPT +#endif + +/*****************************************************************************/ +/** +* Update Block size for read/write operations. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param BlkSize - Block size passed by the user. +* +* @return None +* +******************************************************************************/ +s32 XSdPs_SetBlkSize(XSdPs *InstancePtr, u16 BlkSize) +{ + s32 Status; + u32 PresentStateReg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_PRES_STATE_OFFSET); + + if ((PresentStateReg & ((u32)XSDPS_PSR_INHIBIT_CMD_MASK | + (u32)XSDPS_PSR_INHIBIT_DAT_MASK | + (u32)XSDPS_PSR_WR_ACTIVE_MASK | (u32)XSDPS_PSR_RD_ACTIVE_MASK)) != 0U) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + + /* Send block write command */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD16, BlkSize, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + /* Set block size to the value passed */ + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET, + BlkSize & XSDPS_BLK_SIZE_MASK); + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to get bus width support by card. +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* @param SCR - buffer to store SCR register returned by card. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +s32 XSdPs_Get_BusWidth(XSdPs *InstancePtr, u8 *SCR) +{ + s32 Status; + u16 BlkCnt; + u16 BlkSize; + s32 LoopCnt; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + for (LoopCnt = 0; LoopCnt < 8; LoopCnt++) { + SCR[LoopCnt] = 0U; + } + + /* Send block write command */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD55, + InstancePtr->RelCardAddr, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + BlkCnt = XSDPS_SCR_BLKCNT; + BlkSize = XSDPS_SCR_BLKSIZE; + + /* Set block size to the value passed */ + BlkSize &= XSDPS_BLK_SIZE_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET, BlkSize); + + XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, SCR); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK); + + Xil_DCacheInvalidateRange((u32)SCR, 8); + + Status = XSdPs_CmdTransfer(InstancePtr, ACMD51, 0U, BlkCnt); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Check for transfer complete + */ + Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE); + if (Status != XST_SUCCESS) { + goto RETURN_PATH; + } + + Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to set bus width to 4-bit in card and host +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +s32 XSdPs_Change_BusWidth(XSdPs *InstancePtr) +{ + s32 Status; + u32 StatusReg; + u32 Arg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + + if (InstancePtr->CardType == XSDPS_CARD_SD) { + + Status = XSdPs_CmdTransfer(InstancePtr, CMD55, InstancePtr->RelCardAddr, + 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + InstancePtr->BusWidth = XSDPS_4_BIT_WIDTH; + + Arg = ((u32)InstancePtr->BusWidth); + + Status = XSdPs_CmdTransfer(InstancePtr, ACMD6, Arg, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } else { + + if ((InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) + && (InstancePtr->CardType == XSDPS_CHIP_EMMC)) { + /* in case of eMMC data width 8-bit */ + InstancePtr->BusWidth = XSDPS_8_BIT_WIDTH; + } else { + InstancePtr->BusWidth = XSDPS_4_BIT_WIDTH; + } + + if (InstancePtr->BusWidth == XSDPS_8_BIT_WIDTH) { + Arg = XSDPS_MMC_8_BIT_BUS_ARG; + } else { + Arg = XSDPS_MMC_4_BIT_BUS_ARG; + } + + Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* Check for transfer complete */ + Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE); + if (Status != XST_SUCCESS) { + goto RETURN_PATH; + } + } + +#if defined (__arm__) || defined (__aarch64__) + + usleep(XSDPS_MMC_DELAY_FOR_SWITCH); + +#endif + +#ifdef __MICROBLAZE__ + + /* 2 msec delay */ + MB_Sleep(2); + +#endif + + StatusReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL1_OFFSET); + + /* Width setting in controller */ + if (InstancePtr->BusWidth == XSDPS_8_BIT_WIDTH) { + StatusReg |= XSDPS_HC_EXT_BUS_WIDTH; + } else { + StatusReg |= XSDPS_HC_WIDTH_MASK; + } + + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL1_OFFSET, + (u8)StatusReg); + + Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to get bus speed supported by card. +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* @param ReadBuff - buffer to store function group support data +* returned by card. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +s32 XSdPs_Get_BusSpeed(XSdPs *InstancePtr, u8 *ReadBuff) +{ + s32 Status; + u32 Arg; + u16 BlkCnt; + u16 BlkSize; + s32 LoopCnt; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + for (LoopCnt = 0; LoopCnt < 64; LoopCnt++) { + ReadBuff[LoopCnt] = 0U; + } + + BlkCnt = XSDPS_SWITCH_CMD_BLKCNT; + BlkSize = XSDPS_SWITCH_CMD_BLKSIZE; + BlkSize &= XSDPS_BLK_SIZE_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET, BlkSize); + + XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK); + + Arg = XSDPS_SWITCH_CMD_HS_GET; + + Xil_DCacheInvalidateRange((u32)ReadBuff, 64); + + Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Check for transfer complete + */ + Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE); + if (Status != XST_SUCCESS) { + goto RETURN_PATH; + } + + Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to set high speed in card and host. Changes clock in host accordingly. +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +s32 XSdPs_Change_BusSpeed(XSdPs *InstancePtr) +{ + s32 Status; + u32 StatusReg; + u32 Arg; + u16 BlkCnt; + u16 BlkSize; + u8 ReadBuff[64]; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + if (InstancePtr->CardType == XSDPS_CARD_SD) { + + BlkCnt = XSDPS_SWITCH_CMD_BLKCNT; + BlkSize = XSDPS_SWITCH_CMD_BLKSIZE; + BlkSize &= XSDPS_BLK_SIZE_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET, BlkSize); + + XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff); + + Xil_DCacheFlushRange((u32)ReadBuff, 64); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK); + + Arg = XSDPS_SWITCH_CMD_HS_SET; + + Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Check for transfer complete + */ + Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE); + if (Status != XST_SUCCESS) { + goto RETURN_PATH; + } + + /* Change the clock frequency to 50 MHz */ + InstancePtr->BusSpeed = XSDPS_CLK_50_MHZ; + Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + } else if (InstancePtr->CardType == XSDPS_CARD_MMC) { + Arg = XSDPS_MMC_HIGH_SPEED_ARG; + + Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Check for transfer complete + */ + Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE); + if (Status != XST_SUCCESS) { + goto RETURN_PATH; + } + + /* Change the clock frequency to 52 MHz */ + InstancePtr->BusSpeed = XSDPS_CLK_52_MHZ; + Status = XSdPs_Change_ClkFreq(InstancePtr, XSDPS_CLK_52_MHZ); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } else { + Arg = XSDPS_MMC_HS200_ARG; + + Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Check for transfer complete + */ + Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE); + if (Status != XST_SUCCESS) { + goto RETURN_PATH; + } + + /* Change the clock frequency to 200 MHz */ + InstancePtr->BusSpeed = XSDPS_MMC_HS200_MAX_CLK; + + Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + Status = XSdPs_Execute_Tuning(InstancePtr); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + +#if defined (__arm__) || defined (__aarch64__) + + usleep(XSDPS_MMC_DELAY_FOR_SWITCH); + +#endif + +#ifdef __MICROBLAZE__ + + /* 2 msec delay */ + MB_Sleep(2); + +#endif + + StatusReg = (s32)XSdPs_ReadReg8(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL1_OFFSET); + StatusReg |= XSDPS_HC_SPEED_MASK; + XSdPs_WriteReg8(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL1_OFFSET, (u8)StatusReg); + + Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to change clock freq to given value. +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* @param SelFreq - Clock frequency in Hz. +* +* @return None +* +* @note This API will change clock frequency to the value less than +* or equal to the given value using the permissible dividors. +* +******************************************************************************/ +s32 XSdPs_Change_ClkFreq(XSdPs *InstancePtr, u32 SelFreq) +{ + u16 ClockReg; + u16 DivCnt; + u16 Divisor = 0U; + u16 ExtDivisor; + s32 Status; + u16 ReadReg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* Disable clock */ + ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET); + ClockReg &= ~(XSDPS_CC_SD_CLK_EN_MASK | XSDPS_CC_INT_CLK_EN_MASK); + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET, ClockReg); + + if (InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) { + /* Calculate divisor */ + for (DivCnt = 0x1U; DivCnt <= XSDPS_CC_EXT_MAX_DIV_CNT;DivCnt++) { + if (((InstancePtr->Config.InputClockHz) / DivCnt) <= SelFreq) { + Divisor = DivCnt >> 1; + break; + } + } + + if (DivCnt > XSDPS_CC_EXT_MAX_DIV_CNT) { + /* No valid divisor found for given frequency */ + Status = XST_FAILURE; + goto RETURN_PATH; + } + } else { + /* Calculate divisor */ + DivCnt = 0x1U; + while (DivCnt <= XSDPS_CC_MAX_DIV_CNT) { + if (((InstancePtr->Config.InputClockHz) / DivCnt) <= SelFreq) { + Divisor = DivCnt / 2U; + break; + } + DivCnt = DivCnt << 1U; + } + + if (DivCnt > XSDPS_CC_MAX_DIV_CNT) { + /* No valid divisor found for given frequency */ + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + + /* Set clock divisor */ + if (InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) { + ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET); + ClockReg &= ~(XSDPS_CC_SDCLK_FREQ_SEL_MASK | + XSDPS_CC_SDCLK_FREQ_SEL_EXT_MASK); + + ExtDivisor = Divisor >> 8; + ExtDivisor <<= XSDPS_CC_EXT_DIV_SHIFT; + ExtDivisor &= XSDPS_CC_SDCLK_FREQ_SEL_EXT_MASK; + + Divisor <<= XSDPS_CC_DIV_SHIFT; + Divisor &= XSDPS_CC_SDCLK_FREQ_SEL_MASK; + ClockReg |= Divisor | ExtDivisor | (u16)XSDPS_CC_INT_CLK_EN_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_CLK_CTRL_OFFSET, + ClockReg); + } else { + ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET); + ClockReg &= (~XSDPS_CC_SDCLK_FREQ_SEL_MASK); + + Divisor <<= XSDPS_CC_DIV_SHIFT; + Divisor &= XSDPS_CC_SDCLK_FREQ_SEL_MASK; + ClockReg |= Divisor | (u16)XSDPS_CC_INT_CLK_EN_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_CLK_CTRL_OFFSET, + ClockReg); + } + + /* Wait for internal clock to stabilize */ + ReadReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET); + while((ReadReg & XSDPS_CC_INT_CLK_STABLE_MASK) == 0U) { + ReadReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET);; + } + + /* Enable SD clock */ + ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET); + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_CLK_CTRL_OFFSET, + ClockReg | XSDPS_CC_SD_CLK_EN_MASK); + + Status = XST_SUCCESS; + +RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to send pullup command to card before using DAT line 3(using 4-bit bus) +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +s32 XSdPs_Pullup(XSdPs *InstancePtr) +{ + s32 Status; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Status = XSdPs_CmdTransfer(InstancePtr, CMD55, + InstancePtr->RelCardAddr, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = XSdPs_CmdTransfer(InstancePtr, ACMD42, 0U, 0U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + +/*****************************************************************************/ +/** +* +* API to get EXT_CSD register of eMMC. +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* @param ReadBuff - buffer to store EXT_CSD +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +s32 XSdPs_Get_Mmc_ExtCsd(XSdPs *InstancePtr, u8 *ReadBuff) +{ + s32 Status; + u32 Arg = 0U; + u16 BlkCnt; + u16 BlkSize; + s32 LoopCnt; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + for (LoopCnt = 0; LoopCnt < 512; LoopCnt++) { + ReadBuff[LoopCnt] = 0U; + } + + BlkCnt = XSDPS_EXT_CSD_CMD_BLKCNT; + BlkSize = XSDPS_EXT_CSD_CMD_BLKSIZE; + BlkSize &= XSDPS_BLK_SIZE_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_BLK_SIZE_OFFSET, BlkSize); + + XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff); + + Xil_DCacheInvalidateRange((u32)ReadBuff, 512U); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK); + + + /* Send SEND_EXT_CSD command */ + Status = XSdPs_CmdTransfer(InstancePtr, CMD8, Arg, 1U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Check for transfer complete + */ + Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE); + if (Status != XST_SUCCESS) { + goto RETURN_PATH; + } + + Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress, + XSDPS_RESP0_OFFSET); + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; + +} + + +/*****************************************************************************/ +/** +* +* API to UHS-I mode initialization +* +* +* @param InstancePtr is a pointer to the XSdPs instance. +* @param Mode UHS-I mode +* +* @return +* - XST_SUCCESS if successful. +* - XST_FAILURE if fail. +* +* @note None. +* +******************************************************************************/ +s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode) +{ + s32 Status; + u16 CtrlReg; + u32 Arg; + u16 BlkCnt; + u16 BlkSize; + u8 ReadBuff[64]; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* Drive strength */ + + /* Bus speed mode selection */ + BlkCnt = XSDPS_SWITCH_CMD_BLKCNT; + BlkSize = XSDPS_SWITCH_CMD_BLKSIZE; + BlkSize &= XSDPS_BLK_SIZE_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET, + BlkSize); + + XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff); + + Xil_DCacheFlushRange((u32)ReadBuff, 64); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK); + + switch (Mode) { + case 0U: + Arg = XSDPS_SWITCH_CMD_SDR12_SET; + InstancePtr->BusSpeed = XSDPS_SD_SDR12_MAX_CLK; + break; + case 1U: + Arg = XSDPS_SWITCH_CMD_SDR25_SET; + InstancePtr->BusSpeed = XSDPS_SD_SDR25_MAX_CLK; + break; + case 2U: + Arg = XSDPS_SWITCH_CMD_SDR50_SET; + InstancePtr->BusSpeed = XSDPS_SD_SDR50_MAX_CLK; + break; + case 3U: + Arg = XSDPS_SWITCH_CMD_SDR104_SET; + InstancePtr->BusSpeed = XSDPS_SD_SDR104_MAX_CLK; + break; + case 4U: + Arg = XSDPS_SWITCH_CMD_DDR50_SET; + InstancePtr->BusSpeed = XSDPS_SD_DDR50_MAX_CLK; + break; + default: + Status = XST_FAILURE; + goto RETURN_PATH; + break; + } + + Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1U); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Check for transfer complete + */ + Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE); + if (Status != XST_SUCCESS) { + goto RETURN_PATH; + } + + /* Current limit */ + + /* Set UHS mode in controller */ + CtrlReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL2_OFFSET); + CtrlReg &= (u16)(~XSDPS_HC2_UHS_MODE_MASK); + CtrlReg |= Mode; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, + XSDPS_HOST_CTRL2_OFFSET, CtrlReg); + + /* Change the clock frequency */ + Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + if((Mode == XSDPS_UHS_SPEED_MODE_SDR104) || + (Mode == XSDPS_UHS_SPEED_MODE_DDR50)) { + /* Send tuning pattern */ + Status = XSdPs_Execute_Tuning(InstancePtr); + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + } + + Status = XST_SUCCESS; + + RETURN_PATH: + return Status; +} + +static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr) +{ + s32 Status; + u16 BlkCnt; + u16 BlkSize; + s32 LoopCnt; + u8 ReadBuff[128]; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + BlkCnt = XSDPS_TUNING_CMD_BLKCNT; + BlkSize = XSDPS_TUNING_CMD_BLKSIZE; + if(InstancePtr->BusWidth == XSDPS_8_BIT_WIDTH) + { + BlkSize = BlkSize*2U; + } + BlkSize &= XSDPS_BLK_SIZE_MASK; + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET, + BlkSize); + + for (LoopCnt = 0; LoopCnt < (s32)BlkSize; LoopCnt++) { + ReadBuff[LoopCnt] = 0U; + } + + XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff); + + XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_XFER_MODE_OFFSET, + XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK); + + Xil_DCacheInvalidateRange((u32)ReadBuff, BlkSize); + + if(InstancePtr->CardType == XSDPS_CARD_SD) { + Status = XSdPs_CmdTransfer(InstancePtr, CMD19, 0U, 1U); + } else { + Status = XSdPs_CmdTransfer(InstancePtr, CMD21, 0U, 1U); + } + + if (Status != XST_SUCCESS) { + Status = XST_FAILURE; + goto RETURN_PATH; + } + + /* + * Check for transfer complete + * Polling for response for now + */ + Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE); + if (Status != XST_SUCCESS) { + goto RETURN_PATH; + } + + Status = XST_SUCCESS; + + RETURN_PATH: return Status; + +} +/** @} */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_sinit.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_sinit.c new file mode 100644 index 000000000..fd73fbf18 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_sinit.c @@ -0,0 +1,95 @@ +/****************************************************************************** +* +* Copyright (C) 2013 - 2014 Xilinx, Inc. All rights reserved. +* +* 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX CONSORTIUM 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xsdps_sinit.c +* +* The implementation of the XSdPs component's static initialization +* functionality. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who    Date     Changes
+* ----- ---    -------- -----------------------------------------------
+* 1.00a hk/sg  10/17/13 Initial release
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "xstatus.h" +#include "xsdps.h" +#include "xparameters.h" +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ +extern XSdPs_Config XSdPs_ConfigTable[]; + +/*****************************************************************************/ +/** +* +* Looks up the device configuration based on the unique device ID. A table +* contains the configuration info for each device in the system. +* +* @param DeviceId contains the ID of the device to look up the +* configuration for. +* +* @return +* +* A pointer to the configuration found or NULL if the specified device ID was +* not found. See xsdps.h for the definition of XSdPs_Config. +* +* @note None. +* +******************************************************************************/ +XSdPs_Config *XSdPs_LookupConfig(u16 DeviceId) +{ + XSdPs_Config *CfgPtr = NULL; + int Index; + + for (Index = 0; Index < XPAR_XSDPS_NUM_INSTANCES; Index++) { + if (XSdPs_ConfigTable[Index].DeviceId == DeviceId) { + CfgPtr = &XSdPs_ConfigTable[Index]; + break; + } + } + return CfgPtr; +} diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/avr32_uc3/ff_flush.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/avr32_uc3/ff_flush.c new file mode 100644 index 000000000..b47e01e1e --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/avr32_uc3/ff_flush.c @@ -0,0 +1,75 @@ +// +// +// + +#define SD_MMC_SPI_MEM 1 + +#include "ff_headers.h" + +#include "logbuf.h" +#include "secCache.h" + +#include "ff_flush.h" + +extern BaseType_t FF_SemaphoreTaken( void *pxSemaphore ); + +FF_Error_t FF_FlushWrites( FF_IOManager_t *pxIOManager, BaseType_t xForced ) +{ +FF_Error_t xRetValue; + + if( ( pxIOManager == NULL ) || ( cache_dirt_count() == 0 ) ) + { + xRetValue = FF_ERR_NONE; + } + else if( ( pxIOManager->ucPreventFlush != pdFALSE ) && ( xForced == pdFALSE ) ) + { + xRetValue = FF_ERR_IOMAN_PARTITION_MOUNTED | FF_ERRFLAG; + } + else + { + BaseType_t rc = 0; + if( xForced != pdFALSE ) + { + FF_FlushCache( pxIOManager ); + } + +// if( FF_TrySemaphore( pxIOManager->pvSemaphore, xForced ? 5000 : 0 ) != pdFALSE ) + if( ( xForced != pdFALSE ) || ( FF_SemaphoreTaken( pxIOManager->pvSemaphore ) == pdFALSE ) ) + { + rc = cache_flush( xForced ); +// FF_ReleaseSemaphore( pxIOManager->pvSemaphore ); + } + xRetValue = rc; + } + return xRetValue; +} + +FF_Error_t FF_StopFlush( FF_IOManager_t *pxIOManager, BaseType_t xFlag ) +{ +FF_Error_t xRetValue; + + if( pxIOManager == NULL ) + { + xRetValue = 0; + } + else + { + vTaskSuspendAll(); + { + xRetValue = pxIOManager->ucPreventFlush; + if( xFlag != FLUSH_ENABLE ) + { + xRetValue++; + } + else if ( xRetValue > 0 ) + { + xRetValue--; + } + pxIOManager->ucPreventFlush = xRetValue; + } + xTaskResumeAll(); + + } + + return xRetValue; +} diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/avr32_uc3/ff_flush.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/avr32_uc3/ff_flush.h new file mode 100644 index 000000000..3c01e3ac0 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/avr32_uc3/ff_flush.h @@ -0,0 +1,48 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +#if !defined(__FF_FLUSH_H__) + +#define __FF_FLUSH_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +// HT addition: call FF_FlushCache and in addition call cache_write_flush (see secCache.cpp) +FF_Error_t FF_FlushWrites( FF_IOManager_t *pxIOManager, BaseType_t xForced ); + +#define FLUSH_DISABLE 1 +#define FLUSH_ENABLE 0 + +// HT addition: prevent flushing temporarily FF_StopFlush(pIoMan, true) +FF_Error_t FF_StopFlush( FF_IOManager_t *pxIOManager, BaseType_t xFlag ); +#ifdef __cplusplus +} // extern "C" +#endif + + +#endif // !defined(__FF_FLUSH_H__) diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/avr32_uc3/ff_locking.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/avr32_uc3/ff_locking.c new file mode 100644 index 000000000..5def6eb93 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/avr32_uc3/ff_locking.c @@ -0,0 +1,343 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +#include +#include +#include + +/* Scheduler include files. */ +#include "FreeRTOS.h" +#include "ff_headers.h" +#include "event_groups.h" + + +/* Scheduler include files. */ +#ifdef __WIN32__ + #include "MyMalloc.h" +#else + #include "FreeRTOS.h" + #include "task.h" + #include "semphr.h" + #include "tcpLogging.h" +#endif + +#include "logbuf.h" +#include +#include "bitops.h" +#if USE_SOFT_WDT + #include "softWdt.h" +#endif + +#include "thread_mutex.h" + +#include "event_groups.h" + +#if( FF_DO_TRACE_SEMAPHORE != 0 ) + #include "eventLogging.h" +#endif + +/* There are two areas which are protected with a semaphore: +Directories and the FAT area. +The masks below are used when calling Group Event functions. */ +#define FF_FAT_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_FAT_LOCK ) +#define FF_DIR_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_DIR_LOCK ) + +/* This is not a real lock: it is a bit (or semaphore) will will be given +each time when a sector buffer is released. */ +#define FF_BUF_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_BUF_LOCK ) + +extern void myTaskDelay (unsigned aTime); + +static char cMutexWasCreated = 0; +static pthread_mutex_t xFATMutex; + +static void vCreateFATMutex () +{ + cMutexWasCreated = 1; + pthread_mutex_init ("FreeRTOS+FAT", &xFATMutex, 0); +} + +BaseType_t FF_HasSemaphore (void *pxSemaphore) +{ + // Return pdTRUE if the calling task owns the semaphore + if (!cMutexWasCreated) vCreateFATMutex (); + return pthread_has_mutex (&xFATMutex); +} + + +BaseType_t FF_SemaphoreTaken (void *pxSemaphore) +{ + // Return pdTRUE if the calling task owns the semaphore + if (!cMutexWasCreated) vCreateFATMutex (); + return pthread_mutex_islocked (&xFATMutex); +} + + +#if( FF_DO_TRACE_SEMAPHORE != 0 ) +static char mutex_owner[32]; +#endif + +BaseType_t FF_TrySemaphore( void *pxSemaphore, uint32_t ulTime_ms) +{ +BaseType_t rc; + #if( FF_DO_TRACE_SEMAPHORE != 0 ) + { + eventLogAdd("Pend_%s\n", pcName); + } + #endif /* FF_DO_TRACE_SEMAPHORE */ + if (!cMutexWasCreated) vCreateFATMutex (); + rc = pthread_mutex_lock (&xFATMutex, ulTime_ms); + #if( FF_DO_TRACE_SEMAPHORE != 0 ) + if (rc > 0) { + if(mutex_owner[0] != 0) { + logPrintf("Pend Try: %s overruled\n", mutex_owner); + } + snprintf(mutex_owner, sizeof mutex_owner, pcName); + } + #endif /* FF_DO_TRACE_SEMAPHORE */ + return rc; +} +/*-----------------------------------------------------------*/ + +void FF_PendSemaphore( void *pxSemaphore ) +{ + #if( FF_DO_TRACE_SEMAPHORE != 0 ) + { + eventLogAdd("Pend_%s\n", pcName); + } + #endif /* FF_DO_TRACE_SEMAPHORE */ + + if (!cMutexWasCreated) vCreateFATMutex (); + pthread_mutex_lock (&xFATMutex, 120000); + #if( FF_DO_TRACE_SEMAPHORE != 0 ) + { + if(mutex_owner[0] != 0) { + logPrintf("Pend Enter: %s overruled by %s\n", mutex_owner, pcName); + } + snprintf(mutex_owner, sizeof mutex_owner, pcName); + } + #endif /* FF_DO_TRACE_SEMAPHORE */ +} +/*-----------------------------------------------------------*/ + +void FF_ReleaseSemaphore( void *pxSemaphore ) +{ + #if( FF_DO_TRACE_SEMAPHORE != 0 ) + { + if(strcmp (pcName, mutex_owner) != 0) { + // FF_GetBuffer2 != FF_GetBuffer + logPrintf("Pend Exit: %s owned by %s\n", pcName, mutex_owner); + } + eventLogAdd("Exit_%s\n", pcName); + mutex_owner[0] = '\0'; + } + #endif /* FF_DO_TRACE_SEMAPHORE */ + + if (cMutexWasCreated) { + pthread_mutex_unlock (&xFATMutex); + } +} +/*-----------------------------------------------------------*/ + +void FF_Sleep( uint32_t ulTime_ms ) +{ + myTaskDelay (ulTime_ms); +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_CreateEvents( FF_IOManager_t *pxIOManager ) +{ +BaseType_t xResult; + + pxIOManager->xEventGroup = xEventGroupCreate(); + if( pxIOManager->xEventGroup != NULL ) + { + xEventGroupSetBits( pxIOManager->xEventGroup, + FF_FAT_LOCK_EVENT_BITS | FF_DIR_LOCK_EVENT_BITS | FF_BUF_LOCK_EVENT_BITS ); + xResult = pdTRUE; + } + else + { + xResult = pdFALSE; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +void FF_LockDirectory( FF_IOManager_t *pxIOManager ) +{ + EventBits_t xBits; + + for( ;; ) + { + /* Called when a task want to make changes to a directory. + First it waits for the desired bit to come high. */ + xEventGroupWaitBits( pxIOManager->xEventGroup, + FF_DIR_LOCK_EVENT_BITS, /* uxBitsToWaitFor */ + ( EventBits_t )0, /* xClearOnExit */ + pdFALSE, /* xWaitForAllBits n.a. */ + pdMS_TO_TICKS( 10000UL ) ); + + /* The next operation will only succeed for 1 task at a time, + because it is an atomary test & set operation: */ + xBits = xEventGroupClearBits( pxIOManager->xEventGroup, FF_DIR_LOCK_EVENT_BITS ); + + if( ( xBits & FF_DIR_LOCK_EVENT_BITS ) != 0 ) + { + /* This task has cleared the desired bit. + It now 'owns' the resource. */ + break; + } + } +} +/*-----------------------------------------------------------*/ + +void FF_UnlockDirectory( FF_IOManager_t *pxIOManager ) +{ + configASSERT( ( xEventGroupGetBits( pxIOManager->xEventGroup ) & FF_DIR_LOCK_EVENT_BITS ) == 0 ); + xEventGroupSetBits( pxIOManager->xEventGroup, FF_DIR_LOCK_EVENT_BITS ); +} +/*-----------------------------------------------------------*/ + +int FF_Has_Lock( FF_IOManager_t *pxIOManager, uint32_t aBits ) +{ +int iReturn; + + void *handle = xTaskGetCurrentTaskHandle(); + if( ( aBits & FF_FAT_LOCK_EVENT_BITS ) != 0 ) + { + if( ( pxIOManager->pvFATLockHandle != NULL ) && ( pxIOManager->pvFATLockHandle == handle ) ) + { + iReturn = pdTRUE; + } + else + { + iReturn = pdFALSE; + } + } + else + { + iReturn = pdFALSE; + } + return iReturn; +} + +void FF_Assert_Lock( FF_IOManager_t *pxIOManager, uint32_t aBits ) +{ + void *handle = xTaskGetCurrentTaskHandle(); + + if( ( aBits & FF_FAT_LOCK_EVENT_BITS ) != 0 ) + { + configASSERT( pxIOManager->pvFATLockHandle != NULL && pxIOManager->pvFATLockHandle == handle ); + + /* In case configASSERT() is not defined. */ + ( void ) pxIOManager; + ( void ) handle; + } +} + +void FF_LockFAT( FF_IOManager_t *pxIOManager ) +{ +EventBits_t xBits; + + configASSERT( FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE ); + if (FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) != pdFALSE ) + { + return; + } + + for( ;; ) + { + /* Called when a task want to make changes to the FAT area. + First it waits for the desired bit to come high. */ + xEventGroupWaitBits( pxIOManager->xEventGroup, + FF_FAT_LOCK_EVENT_BITS, /* uxBitsToWaitFor */ + ( EventBits_t )0, /* xClearOnExit */ + pdFALSE, /* xWaitForAllBits n.a. */ + pdMS_TO_TICKS( 10000UL ) ); + + /* The next operation will only succeed for 1 task at a time, + because it is an atomary test & set operation: */ + xBits = xEventGroupClearBits( pxIOManager->xEventGroup, FF_FAT_LOCK_EVENT_BITS ); + + if( ( xBits & FF_FAT_LOCK_EVENT_BITS ) != 0 ) + { + /* This task has cleared the desired bit. + It now 'owns' the resource. */ + pxIOManager->pvFATLockHandle = xTaskGetCurrentTaskHandle(); + break; + } + } +} +/*-----------------------------------------------------------*/ + +void FF_UnlockFAT( FF_IOManager_t *pxIOManager ) +{ + configASSERT( ( xEventGroupGetBits( pxIOManager->xEventGroup ) & FF_FAT_LOCK_EVENT_BITS ) == 0 ); + if (FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) != pdFALSE ) + { + pxIOManager->pvFATLockHandle = NULL; + xEventGroupSetBits( pxIOManager->xEventGroup, FF_FAT_LOCK_EVENT_BITS ); + } + else + { + FF_PRINTF("FF_UnlockFAT: wasn't locked by me\n"); + } +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_BufferWait( FF_IOManager_t *pxIOManager, uint32_t xWaitMS ) +{ +EventBits_t xBits; +BaseType_t xReturn; + + /* This function is called when a task is waiting for a sector buffer + to become available. */ + xBits = xEventGroupWaitBits( pxIOManager->xEventGroup, + FF_BUF_LOCK_EVENT_BITS, /* uxBitsToWaitFor */ + FF_BUF_LOCK_EVENT_BITS, /* xClearOnExit */ + pdFALSE, /* xWaitForAllBits n.a. */ + pdMS_TO_TICKS( xWaitMS ) ); + if( ( xBits & FF_BUF_LOCK_EVENT_BITS ) != 0 ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void FF_BufferProceed( FF_IOManager_t *pxIOManager ) +{ + /* Wake-up all tasks that are waiting for a sector buffer to become available. */ + xEventGroupSetBits( pxIOManager->xEventGroup, FF_BUF_LOCK_EVENT_BITS ); +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.c new file mode 100644 index 000000000..19231393a --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.c @@ -0,0 +1,423 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/* Standard includes. */ +#include +#include +#include +#include + +/* Scheduler include files. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "portmacro.h" + +/* FreeRTOS+FAT includes. */ +#include "ff_headers.h" +#include "ff_ramdisk.h" +#include "ff_sys.h" + +#define ramHIDDEN_SECTOR_COUNT 8 +#define ramPRIMARY_PARTITIONS 1 +#define ramHUNDRED_64_BIT 100ULL +#define ramSECTOR_SIZE 512UL +#define ramPARTITION_NUMBER 0 /* Only a single partition is used. */ +#define ramBYTES_PER_KB ( 1024ull ) +#define ramSECTORS_PER_KB ( ramBYTES_PER_KB / 512ull ) + +/* Used as a magic number to indicate that an FF_Disk_t structure is a RAM +disk. */ +#define ramSIGNATURE 0x41404342 + +/*-----------------------------------------------------------*/ + +/* + * The function that writes to the media - as this is implementing a RAM disk + * the media is just a RAM buffer. + */ +static int32_t prvWriteRAM( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ); + +/* + * The function that reads from the media - as this is implementing a RAM disk + * the media is just a RAM buffer. + */ +static int32_t prvReadRAM( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ); + +/* + * This is the driver for a RAM disk. Unlike most media types, RAM disks are + * volatile so are created anew each time the system is booted. As the disk is + * new and just created, it must also be partitioned and formatted. + */ +static FF_Error_t prvPartitionAndFormatDisk( FF_Disk_t *pxDisk ); + +/*-----------------------------------------------------------*/ + +/* This is the prototype of the function used to initialise the RAM disk driver. +Other media drivers do not have to have the same prototype. + +In this example: + + pcName is the name to give the disk within FreeRTOS+FAT's virtual file system. + + pucDataBuffer is the start of the RAM to use as the disk. + + ulSectorCount is effectively the size of the disk, each sector is 512 bytes. + + xIOManagerCacheSize is the size of the IO manager's cache, which must be a + multiple of the sector size, and at least twice as big as the sector size. +*/ +FF_Disk_t *FF_RAMDiskInit( char *pcName, uint8_t *pucDataBuffer, uint32_t ulSectorCount, size_t xIOManagerCacheSize ) +{ +FF_Error_t xError; +FF_Disk_t *pxDisk = NULL; +FF_CreationParameters_t xParameters; + + /* Check the validity of the xIOManagerCacheSize parameter. */ + configASSERT( ( xIOManagerCacheSize % ramSECTOR_SIZE ) == 0 ); + configASSERT( ( xIOManagerCacheSize >= ( 2 * ramSECTOR_SIZE ) ) ); + + /* Attempt to allocated the FF_Disk_t structure. */ + pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( FF_Disk_t ) ); + + if( pxDisk != NULL ) + { + /* Start with every member of the structure set to zero. */ + memset( pxDisk, '\0', sizeof( FF_Disk_t ) ); + + /* Clear the entire space. */ + memset( pucDataBuffer, '\0', ulSectorCount * ramSECTOR_SIZE ); + + /* The pvTag member of the FF_Disk_t structure allows the structure to be + extended to also include media specific parameters. The only media + specific data that needs to be stored in the FF_Disk_t structure for a + RAM disk is the location of the RAM buffer itself - so this is stored + directly in the FF_Disk_t's pvTag member. */ + pxDisk->pvTag = ( void * ) pucDataBuffer; + + /* The signature is used by the disk read and disk write functions to + ensure the disk being accessed is a RAM disk. */ + pxDisk->ulSignature = ramSIGNATURE; + + /* The number of sectors is recorded for bounds checking in the read and + write functions. */ + pxDisk->ulNumberOfSectors = ulSectorCount; + + /* Create the IO manager that will be used to control the RAM disk. */ + memset( &xParameters, '\0', sizeof( xParameters ) ); + xParameters.pucCacheMemory = NULL; + xParameters.ulMemorySize = xIOManagerCacheSize; + xParameters.ulSectorSize = ramSECTOR_SIZE; + xParameters.fnWriteBlocks = prvWriteRAM; + xParameters.fnReadBlocks = prvReadRAM; + xParameters.pxDisk = pxDisk; + + /* Driver is reentrant so xBlockDeviceIsReentrant can be set to pdTRUE. + In this case the semaphore is only used to protect FAT data + structures. */ + xParameters.pvSemaphore = ( void * ) xSemaphoreCreateRecursiveMutex(); + xParameters.xBlockDeviceIsReentrant = pdFALSE; + + pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xError ); + + if( ( pxDisk->pxIOManager != NULL ) && ( FF_isERR( xError ) == pdFALSE ) ) + { + /* Record that the RAM disk has been initialised. */ + pxDisk->xStatus.bIsInitialised = pdTRUE; + + /* Create a partition on the RAM disk. NOTE! The disk is only + being partitioned here because it is a new RAM disk. It is + known that the disk has not been used before, and cannot already + contain any partitions. Most media drivers will not perform + this step because the media will have already been partitioned. */ + xError = prvPartitionAndFormatDisk( pxDisk ); + + if( FF_isERR( xError ) == pdFALSE ) + { + /* Record the partition number the FF_Disk_t structure is, then + mount the partition. */ + pxDisk->xStatus.bPartitionNumber = ramPARTITION_NUMBER; + + /* Mount the partition. */ + xError = FF_Mount( pxDisk, ramPARTITION_NUMBER ); + FF_PRINTF( "FF_RAMDiskInit: FF_Mount: %s\n", ( const char * ) FF_GetErrMessage( xError ) ); + } + + if( FF_isERR( xError ) == pdFALSE ) + { + /* The partition mounted successfully, add it to the virtual + file system - where it will appear as a directory off the file + system's root directory. */ + FF_FS_Add( pcName, pxDisk ); + } + } + else + { + FF_PRINTF( "FF_RAMDiskInit: FF_CreateIOManger: %s\n", ( const char * ) FF_GetErrMessage( xError ) ); + + /* The disk structure was allocated, but the disk's IO manager could + not be allocated, so free the disk again. */ + FF_RAMDiskDelete( pxDisk ); + pxDisk = NULL; + } + } + else + { + FF_PRINTF( "FF_RAMDiskInit: Malloc failed\n" ); + } + + return pxDisk; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_RAMDiskDelete( FF_Disk_t *pxDisk ) +{ + if( pxDisk != NULL ) + { + pxDisk->ulSignature = 0; + pxDisk->xStatus.bIsInitialised = 0; + if( pxDisk->pxIOManager != NULL ) + { + FF_DeleteIOManager( pxDisk->pxIOManager ); + } + + vPortFree( pxDisk ); + } + + return pdPASS; +} +/*-----------------------------------------------------------*/ + +static int32_t prvReadRAM( uint8_t *pucDestination, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ) +{ +int32_t lReturn; +uint8_t *pucSource; + + if( pxDisk != NULL ) + { + if( pxDisk->ulSignature != ramSIGNATURE ) + { + /* The disk structure is not valid because it doesn't contain a + magic number written to the disk when it was created. */ + lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG; + } + else if( pxDisk->xStatus.bIsInitialised == pdFALSE ) + { + /* The disk has not been initialised. */ + lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG; + } + else if( ulSectorNumber >= pxDisk->ulNumberOfSectors ) + { + /* The start sector is not within the bounds of the disk. */ + lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG ); + } + else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount ) + { + /* The end sector is not within the bounds of the disk. */ + lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG ); + } + else + { + /* Obtain the pointer to the RAM buffer being used as the disk. */ + pucSource = ( uint8_t * ) pxDisk->pvTag; + + /* Move to the start of the sector being read. */ + pucSource += ( ramSECTOR_SIZE * ulSectorNumber ); + + /* Copy the data from the disk. As this is a RAM disk this can be + done using memcpy(). */ + memcpy( ( void * ) pucDestination, + ( void * ) pucSource, + ( size_t ) ( ulSectorCount * ramSECTOR_SIZE ) ); + + lReturn = FF_ERR_NONE; + } + } + else + { + lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG; + } + + return lReturn; +} +/*-----------------------------------------------------------*/ + +static int32_t prvWriteRAM( uint8_t *pucSource, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ) +{ +int32_t lReturn = FF_ERR_NONE; +uint8_t *pucDestination; + + if( pxDisk != NULL ) + { + if( pxDisk->ulSignature != ramSIGNATURE ) + { + /* The disk structure is not valid because it doesn't contain a + magic number written to the disk when it was created. */ + lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG; + } + else if( pxDisk->xStatus.bIsInitialised == pdFALSE ) + { + /* The disk has not been initialised. */ + lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG; + } + else if( ulSectorNumber >= pxDisk->ulNumberOfSectors ) + { + /* The start sector is not within the bounds of the disk. */ + lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG ); + } + else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount ) + { + /* The end sector is not within the bounds of the disk. */ + lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG ); + } + else + { + /* Obtain the location of the RAM being used as the disk. */ + pucDestination = ( uint8_t * ) pxDisk->pvTag; + + /* Move to the sector being written to. */ + pucDestination += ( ramSECTOR_SIZE * ulSectorNumber ); + + /* Write to the disk. As this is a RAM disk the write can use a + memcpy(). */ + memcpy( ( void * ) pucDestination, + ( void * ) pucSource, + ( size_t ) ulSectorCount * ( size_t ) ramSECTOR_SIZE ); + + lReturn = FF_ERR_NONE; + } + } + else + { + lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG; + } + + return lReturn; +} +/*-----------------------------------------------------------*/ + +static FF_Error_t prvPartitionAndFormatDisk( FF_Disk_t *pxDisk ) +{ +FF_PartitionParameters_t xPartition; +FF_Error_t xError; + + /* Create a single partition that fills all available space on the disk. */ + memset( &xPartition, '\0', sizeof( xPartition ) ); + xPartition.ulSectorCount = pxDisk->ulNumberOfSectors; + xPartition.ulHiddenSectors = ramHIDDEN_SECTOR_COUNT; + xPartition.xPrimaryCount = ramPRIMARY_PARTITIONS; + xPartition.eSizeType = eSizeIsQuota; + + /* Partition the disk */ + xError = FF_Partition( pxDisk, &xPartition ); + FF_PRINTF( "FF_Partition: %s\n", ( const char * ) FF_GetErrMessage( xError ) ); + + if( FF_isERR( xError ) == pdFALSE ) + { + /* Format the partition. */ + xError = FF_Format( pxDisk, ramPARTITION_NUMBER, pdTRUE, pdTRUE ); + FF_PRINTF( "FF_RAMDiskInit: FF_Format: %s\n", ( const char * ) FF_GetErrMessage( xError ) ); + } + + return xError; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_RAMDiskShowPartition( FF_Disk_t *pxDisk ) +{ +FF_Error_t xError; +uint64_t ullFreeSectors; +uint32_t ulTotalSizeKB, ulFreeSizeKB; +int iPercentageFree; +FF_IOManager_t *pxIOManager; +const char *pcTypeName = "unknown type"; +BaseType_t xReturn = pdPASS; + + if( pxDisk == NULL ) + { + xReturn = pdFAIL; + } + else + { + pxIOManager = pxDisk->pxIOManager; + + FF_PRINTF( "Reading FAT and calculating Free Space\n" ); + + switch( pxIOManager->xPartition.ucType ) + { + case FF_T_FAT12: + pcTypeName = "FAT12"; + break; + + case FF_T_FAT16: + pcTypeName = "FAT16"; + break; + + case FF_T_FAT32: + pcTypeName = "FAT32"; + break; + + default: + pcTypeName = "UNKOWN"; + break; + } + + FF_GetFreeSize( pxIOManager, &xError ); + + ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster; + if( pxIOManager->xPartition.ulDataSectors == ( uint32_t )0 ) + { + iPercentageFree = 0; + } + else + { + iPercentageFree = ( int ) ( ( ramHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) / + ( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) ); + } + + ulTotalSizeKB = pxIOManager->xPartition.ulDataSectors / ramSECTORS_PER_KB; + ulFreeSizeKB = ( uint32_t ) ( ullFreeSectors / ramSECTORS_PER_KB ); + + /* It is better not to use the 64-bit format such as %Lu because it + might not be implemented. */ + FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber ); + FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName ); + FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel ); + FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors ); + FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster ); + FF_PRINTF( "Size %8lu KB\n", ulTotalSizeKB ); + FF_PRINTF( "FreeSize %8lu KB ( %d perc free )\n", ulFreeSizeKB, iPercentageFree ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void FF_RAMDiskFlush( FF_Disk_t *pxDisk ) +{ + if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != 0 ) && ( pxDisk->pxIOManager != NULL ) ) + { + FF_FlushCache( pxDisk->pxIOManager ); + } +} +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.h new file mode 100644 index 000000000..102d8688d --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_ramdisk.h @@ -0,0 +1,50 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +#ifndef __RAMDISK_H__ + +#define __RAMDISK_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ff_headers.h" + +/* Create a RAM disk, supplying enough memory to hold N sectors of 512 bytes each */ +FF_Disk_t *FF_RAMDiskInit( char *pcName, uint8_t *pucDataBuffer, uint32_t ulSectorCount, size_t xIOManagerCacheSize ); + +/* Release all resources */ +BaseType_t FF_RAMDiskDelete( FF_Disk_t *pxDisk ); + +/* Show some partition information */ +BaseType_t FF_RAMDiskShowPartition( FF_Disk_t *pxDisk ); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __RAMDISK_H__ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_sddisk.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_sddisk.h new file mode 100644 index 000000000..0081ec466 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/common/ff_sddisk.h @@ -0,0 +1,76 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +#ifndef __SDDISK_H__ + +#define __SDDISK_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ff_headers.h" + + +/* Return non-zero if the SD-card is present. +The parameter 'pxDisk' may be null, unless device locking is necessary. */ +BaseType_t FF_SDDiskDetect( FF_Disk_t *pxDisk ); + +/* Create a RAM disk, supplying enough memory to hold N sectors of 512 bytes each */ +FF_Disk_t *FF_SDDiskInit( const char *pcName ); + +BaseType_t FF_SDDiskReinit( FF_Disk_t *pxDisk ); + +/* Unmount the volume */ +BaseType_t FF_SDDiskUnmount( FF_Disk_t *pDisk ); + +/* Mount the volume */ +BaseType_t FF_SDDiskMount( FF_Disk_t *pDisk ); + +/* Release all resources */ +BaseType_t FF_SDDiskDelete( FF_Disk_t *pDisk ); + +/* Show some partition information */ +BaseType_t FF_SDDiskShowPartition( FF_Disk_t *pDisk ); + +/* Flush changes from the driver's buf to disk */ +void FF_SDDiskFlush( FF_Disk_t *pDisk ); + +/* Format a given partition on an SD-card. */ +BaseType_t FF_SDDiskFormat( FF_Disk_t *pxDisk, BaseType_t aPart ); + +/* Return non-zero if an SD-card is detected in a given slot. */ +BaseType_t FF_SDDiskInserted( BaseType_t xDriveNr ); + +/* _RB_ Temporary function - ideally the application would not need the IO +manageer structure, just a handle to a disk. */ +FF_IOManager_t *sddisk_ioman( FF_Disk_t *pxDisk ); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __SDDISK_H__ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/lpc18xx/ff_sddisk.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/lpc18xx/ff_sddisk.c new file mode 100644 index 000000000..aa5b72879 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/lpc18xx/ff_sddisk.c @@ -0,0 +1,532 @@ +/* + * FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab! + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Authors include James Walmsley, Hein Tibosch and Richard Barry + * + * 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. + * + * https://www.FreeRTOS.org + * + */ + +/* Standard includes. */ +#include +#include +#include +#include + +/* LPC18xx includes. */ +#include "chip.h" +#include "board.h" + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" +#include "portmacro.h" + +/* FreeRTOS+FAT includes. */ +#include "ff_sddisk.h" +#include "ff_sys.h" + +#include "hr_gettime.h" + +/* Misc definitions. */ +#define sdSIGNATURE 0x41404342UL +#define sdHUNDRED_64_BIT ( 100ull ) +#define sdBYTES_PER_MB ( 1024ull * 1024ull ) +#define sdSECTORS_PER_MB ( sdBYTES_PER_MB / 512ull ) +#define sdIOMAN_MEM_SIZE 4096 +#define xSDCardInfo ( sd_mmc_cards[ 0 ] ) +#define sdAligned( pvAddress ) ( ( ( ( size_t ) ( pvAddress ) ) & ( sizeof( size_t ) - 1 ) ) == 0 ) + + + +/*-----------------------------------------------------------*/ + +/*_RB_ Functions require comment blocks. */ +static void prvSDMMCSetupWakeup( void *pvInfo ); +static uint32_t prvSDMMCWait( void ); +static void prvSDMMCDelay_ms( uint32_t time ); +static void prvInitialiseCardInfo( void ); +static int32_t prvSDMMC_Init( void ); +static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ); +static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ); + + +/*-----------------------------------------------------------*/ + +/*_RB_ Variables require a comment block where appropriate. */ +static int32_t lSDDetected = 0; +static mci_card_struct xCardInfo; +static volatile int32_t lSDIOWaitExit; +static BaseType_t xSDCardStatus; +static SemaphoreHandle_t xSDCardSemaphore; +static SemaphoreHandle_t xPlusFATMutex; + +/*-----------------------------------------------------------*/ + +#warning Update to make read and write functions static and make use of the FF_Disk_t type. + +static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ) +{ +int32_t iReturn; + + /*_RB_ Many of the comments in this file apply to other functions in the file. */ + + if( ( pxDisk != NULL ) && + ( xSDCardStatus == pdPASS ) && + ( pxDisk->ulSignature == sdSIGNATURE ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( ulSectorNumber < pxDisk->ulNumberOfSectors ) && + ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) ) + { + + iReturn = Chip_SDMMC_ReadBlocks( LPC_SDMMC, pucBuffer, ulSectorNumber, ulSectorCount ); + + /*_RB_ I'm guessing 512 is a sector size, but that needs to be clear. + Is it defined in a header somewhere? If so we can do a search and + replace in files on it as it seems to be used everywhere. */ + if( iReturn == ( ulSectorCount * 512 ) ) /*_RB_ Signed/unsigned mismatch (twice!) */ + { + iReturn = FF_ERR_NONE; + } + else + { + /*_RB_ Signed number used to return bitmap (again below). */ + iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG ); + } + } + else + { + memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512 ); + + if( pxDisk->xStatus.bIsInitialised != 0 ) + { + FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors ); + } + + iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG ); + } + + return iReturn; +} +/*-----------------------------------------------------------*/ + +static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk ) +{ +int32_t iReturn; + + if( ( pxDisk != NULL ) && + ( xSDCardStatus == pdPASS ) && + ( pxDisk->ulSignature == sdSIGNATURE ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( ulSectorNumber < pxDisk->ulNumberOfSectors ) && + ( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) ) + { + iReturn = Chip_SDMMC_WriteBlocks( LPC_SDMMC, pucBuffer, ulSectorNumber, ulSectorCount ); + + if( iReturn == ( ulSectorCount * 512 ) ) /*_RB_ Signed/unsigned mismatch (twice!) */ + { + iReturn = 0; + } + else + { + iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG ); + } + } + else + { + memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512 ); + if( pxDisk->xStatus.bIsInitialised ) + { + FF_PRINTF( "prvFFWrite: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors ); + } + + iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG ); + } + + return iReturn; +} +/*-----------------------------------------------------------*/ + +void FF_SDDiskFlush( FF_Disk_t *pxDisk ) +{ + if( ( pxDisk != NULL ) && + ( pxDisk->xStatus.bIsInitialised != pdFALSE ) && + ( pxDisk->pxIOManager != NULL ) ) + { + FF_FlushCache( pxDisk->pxIOManager ); + } +} +/*-----------------------------------------------------------*/ + +/* Initialise the SDIO driver and mount an SD card */ +FF_Disk_t *FF_SDDiskInit( const char *pcName ) +{ +FF_Error_t xFFError; +BaseType_t xPartitionNumber = 0; +FF_CreationParameters_t xParameters; +FF_Disk_t * pxDisk; + + xSDCardStatus = prvSDMMC_Init(); + if( xSDCardStatus == pdPASS ) + { + pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( *pxDisk ) ); + + if( pxDisk != NULL ) + { + + /* Initialise the created disk structure. */ + memset( pxDisk, '\0', sizeof( *pxDisk ) ); + + + if( xPlusFATMutex == NULL) + { + xPlusFATMutex = xSemaphoreCreateRecursiveMutex(); + } + pxDisk->ulNumberOfSectors = xCardInfo.card_info.blocknr; + pxDisk->ulSignature = sdSIGNATURE; + + if( xPlusFATMutex != NULL) + { + memset( &xParameters, '\0', sizeof( xParameters ) ); + xParameters.ulMemorySize = sdIOMAN_MEM_SIZE; + xParameters.ulSectorSize = 512; + xParameters.fnWriteBlocks = prvFFWrite; + xParameters.fnReadBlocks = prvFFRead; + xParameters.pxDisk = pxDisk; + + /* prvFFRead()/prvFFWrite() are not re-entrant and must be + protected with the use of a semaphore. */ + xParameters.xBlockDeviceIsReentrant = pdFALSE; + + /* The semaphore will be used to protect critical sections in + the +FAT driver, and also to avoid concurrent calls to + prvFFRead()/prvFFWrite() from different tasks. */ + xParameters.pvSemaphore = ( void * ) xPlusFATMutex; + + pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError ); + + if( pxDisk->pxIOManager == NULL ) + { + FF_PRINTF( "FF_SDDiskInit: FF_CreateIOManger: %s\n", ( const char * ) FF_GetErrMessage( xFFError ) ); + FF_SDDiskDelete( pxDisk ); + pxDisk = NULL; + } + else + { + pxDisk->xStatus.bIsInitialised = pdTRUE; + pxDisk->xStatus.bPartitionNumber = xPartitionNumber; + if( FF_SDDiskMount( pxDisk ) == 0 ) + { + FF_SDDiskDelete( pxDisk ); + pxDisk = NULL; + } + else + { + if( pcName == NULL ) + { + pcName = "/"; + } + FF_FS_Add( pcName, pxDisk ); + FF_PRINTF( "FF_SDDiskInit: Mounted SD-card as root \"%s\"\n", pcName ); + FF_SDDiskShowPartition( pxDisk ); + } + } /* if( pxDisk->pxIOManager != NULL ) */ + } /* if( xPlusFATMutex != NULL) */ + } /* if( pxDisk != NULL ) */ + else + { + FF_PRINTF( "FF_SDDiskInit: Malloc failed\n" ); + } + } /* if( xSDCardStatus == pdPASS ) */ + else + { + FF_PRINTF( "FF_SDDiskInit: prvSDMMC_Init failed\n" ); + pxDisk = NULL; + } + + return pxDisk; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskFormat( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber ) +{ +FF_Error_t xError; +BaseType_t xReturn = pdFAIL; + + xError = FF_Unmount( pxDisk ); + + if( FF_isERR( xError ) != pdFALSE ) + { + FF_PRINTF( "FF_SDDiskFormat: unmount fails: %08x\n", ( unsigned ) xError ); + } + else + { + /* Format the drive - try FAT32 with large clusters. */ + xError = FF_Format( pxDisk, xPartitionNumber, pdFALSE, pdFALSE); + + if( FF_isERR( xError ) ) + { + FF_PRINTF( "FF_SDDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) ); + } + else + { + FF_PRINTF( "FF_SDDiskFormat: OK, now remounting\n" ); + pxDisk->xStatus.bPartitionNumber = xPartitionNumber; + xError = FF_SDDiskMount( pxDisk ); + FF_PRINTF( "FF_SDDiskFormat: rc %08x\n", ( unsigned )xError ); + if( FF_isERR( xError ) == pdFALSE ) + { + xReturn = pdPASS; + } + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +/* Get a pointer to IOMAN, which can be used for all FreeRTOS+FAT functions */ +BaseType_t FF_SDDiskMount( FF_Disk_t *pxDisk ) +{ +FF_Error_t xFFError; +BaseType_t xReturn; + + /* Mount the partition */ + xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber ); + + if( FF_isERR( xFFError ) ) + { + FF_PRINTF( "FF_SDDiskMount: %08lX\n", xFFError ); + xReturn = pdFAIL; + } + else + { + pxDisk->xStatus.bIsMounted = pdTRUE; + FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors ); + FF_SDDiskShowPartition( pxDisk ); + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +FF_IOManager_t *sddisk_ioman( FF_Disk_t *pxDisk ) +{ +FF_IOManager_t *pxReturn; + + if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) ) + { + pxReturn = pxDisk->pxIOManager; + } + else + { + pxReturn = NULL; + } + return pxReturn; +} +/*-----------------------------------------------------------*/ + +/* Release all resources */ +BaseType_t FF_SDDiskDelete( FF_Disk_t *pxDisk ) +{ + if( pxDisk != NULL ) + { + pxDisk->ulSignature = 0; + pxDisk->xStatus.bIsInitialised = 0; + if( pxDisk->pxIOManager != NULL ) + { + if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE ) + { + FF_Unmount( pxDisk ); + } + FF_DeleteIOManager( pxDisk->pxIOManager ); + } + + vPortFree( pxDisk ); + } + return 1; +} +/*-----------------------------------------------------------*/ + +BaseType_t FF_SDDiskShowPartition( FF_Disk_t *pxDisk ) +{ +FF_Error_t xError; +uint64_t ullFreeSectors; +uint32_t ulTotalSizeMB, ulFreeSizeMB; +int iPercentageFree; +FF_IOManager_t *pxIOManager; +const char *pcTypeName = "unknown type"; +BaseType_t xReturn = pdPASS; + + if( pxDisk == NULL ) + { + xReturn = pdFAIL; + } + else + { + pxIOManager = pxDisk->pxIOManager; + + FF_PRINTF( "Reading FAT and calculating Free Space\n" ); + + switch( pxIOManager->xPartition.ucType ) + { + case FF_T_FAT12: + pcTypeName = "FAT12"; + break; + + case FF_T_FAT16: + pcTypeName = "FAT16"; + break; + + case FF_T_FAT32: + pcTypeName = "FAT32"; + break; + + default: + pcTypeName = "UNKOWN"; + break; + } + + FF_GetFreeSize( pxIOManager, &xError ); + + ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster; + iPercentageFree = ( int ) ( ( sdHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) / + ( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) ); + + ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / sdSECTORS_PER_MB; + ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / sdSECTORS_PER_MB ); + + /* It is better not to use the 64-bit format such as %Lu because it + might not be implemented. */ + FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber ); + FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName ); + FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel ); + FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors ); + FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster ); + FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB ); + FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void SDIO_IRQHandler( void ) +{ +BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + /* All SD based register handling is done in the callback function. The SDIO + interrupt is not enabled as part of this driver and needs to be + enabled/disabled in the callbacks or application as needed. This is to allow + flexibility with IRQ handling for applications and RTOSes. */ + + /* Set wait exit flag to tell wait function we are ready. In an RTOS, this + would trigger wakeup of a thread waiting for the IRQ. */ + NVIC_DisableIRQ( SDIO_IRQn ); + xSemaphoreGiveFromISR( xSDCardSemaphore, &xHigherPriorityTaskWoken ); + lSDIOWaitExit = 1; + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); +} +/*-----------------------------------------------------------*/ + +/* Sets up the SD event driven wakeup */ +static void prvSDMMCSetupWakeup( void *pvInfo ) +{ +uint32_t *ulWaitStatus = ( uint32_t * ) pvInfo; + + /* Wait for IRQ - for an RTOS, you would pend on an event here with a IRQ + based wakeup. */ + /*_RB_ Don't understand why this is spinning on a block time of 0. Is it + really meant to be != pdFALSE? */ + while( xSemaphoreTake( xSDCardSemaphore, 0 ) != pdFALSE ) + { + } + + NVIC_ClearPendingIRQ( SDIO_IRQn ); + lSDIOWaitExit = 0; + Chip_SDIF_SetIntMask( LPC_SDMMC, *ulWaitStatus ); + NVIC_EnableIRQ( SDIO_IRQn ); +} +/*-----------------------------------------------------------*/ + +static uint32_t prvSDMMCWait( void ) +{ +uint32_t ulStatus; + + /*_RB_ 2000 needs to be defined and use pdMS_TO_TICKS so the delay period + remains constant no matter how the end user sets configTICK_RATE_MS. */ + xSemaphoreTake( xSDCardSemaphore, 2000 ); + + ulStatus = Chip_SDIF_GetIntStatus( LPC_SDMMC ); + if( ( ( ulStatus & MCI_INT_CMD_DONE ) == 0 ) || ( lSDIOWaitExit == 0 ) ) + { + FF_PRINTF( "Wait SD: int32_t %ld ulStatus 0x%02lX\n", lSDIOWaitExit, ulStatus ); + } + + return ulStatus; +} +/*-----------------------------------------------------------*/ + +static void prvSDMMCDelay_ms( uint32_t ulTime ) +{ + /* In an RTOS, the thread would sleep allowing other threads to run. + For standalone operation, just spin on a timer */ + vTaskDelay( pdMS_TO_TICKS( ulTime ) ); +} +/*-----------------------------------------------------------*/ + +static int32_t prvSDMMC_Init( void ) +{ +int32_t lSDCardStatus; + + if( xSDCardSemaphore == NULL ) + { + xSDCardSemaphore = xSemaphoreCreateBinary(); + configASSERT( xSDCardSemaphore ); + xSemaphoreGive( xSDCardSemaphore ); + } + + prvInitialiseCardInfo(); + NVIC_SetPriority( SDIO_IRQn, configSD_INTERRUPT_PRIORITY ); + + /*_RB_ Board_SDMMC_Init() is library specific code that is also specific to + the target development board.The SDMMC peripheral should be initialised from + the application code before this code is called. */ + Board_SDMMC_Init(); + Chip_SDIF_Init( LPC_SDMMC ); + lSDDetected = !Chip_SDIF_CardNDetect( LPC_SDMMC ); + + Chip_SDIF_PowerOn( LPC_SDMMC ); + lSDCardStatus = Chip_SDMMC_Acquire( LPC_SDMMC, &xCardInfo ); + FF_PRINTF( "Acquire: %ld\n", lSDCardStatus ); + + return lSDCardStatus; +} +/*-----------------------------------------------------------*/ + +static void prvInitialiseCardInfo( void ) +{ + memset( &xCardInfo, 0, sizeof( xCardInfo ) ); + xCardInfo.card_info.evsetup_cb = prvSDMMCSetupWakeup; + xCardInfo.card_info.waitfunc_cb = prvSDMMCWait; + xCardInfo.card_info.msdelay_func = prvSDMMCDelay_ms; +} diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c new file mode 100644 index 000000000..fb8a3b4f2 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c @@ -0,0 +1,653 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_ARP.h" +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_DHCP.h" +#if( ipconfigUSE_LLMNR == 1 ) + #include "FreeRTOS_DNS.h" +#endif /* ipconfigUSE_LLMNR */ +#include "NetworkInterface.h" +#include "NetworkBufferManagement.h" + + +/* When the age of an entry in the ARP table reaches this value (it counts down +to zero, so this is an old entry) an ARP request will be sent to see if the +entry is still valid and can therefore be refreshed. */ +#define arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST ( 3 ) + +/* The time between gratuitous ARPs. */ +#ifndef arpGRATUITOUS_ARP_PERIOD + #define arpGRATUITOUS_ARP_PERIOD ( pdMS_TO_TICKS( 20000 ) ) +#endif + +/*-----------------------------------------------------------*/ + +/* + * Lookup an MAC address in the ARP cache from the IP address. + */ +static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup, MACAddress_t * const pxMACAddress ); + +/*-----------------------------------------------------------*/ + +/* The ARP cache. */ +static ARPCacheRow_t xARPCache[ ipconfigARP_CACHE_ENTRIES ]; + +/* The time at which the last gratuitous ARP was sent. Gratuitous ARPs are used +to ensure ARP tables are up to date and to detect IP address conflicts. */ +static TickType_t xLastGratuitousARPTime = ( TickType_t ) 0; + +/* + * IP-clash detection is currently only used internally. When DHCP doesn't respond, the + * driver can try out a random LinkLayer IP address (169.254.x.x). It will send out a + * gratuitos ARP message and, after a period of time, check the variables here below: + */ +#if( ipconfigARP_USE_CLASH_DETECTION != 0 ) + /* Becomes non-zero if another device responded to a gratuitos ARP message. */ + BaseType_t xARPHadIPClash; + /* MAC-address of the other device containing the same IP-address. */ + MACAddress_t xARPClashMacAddress; +#endif /* ipconfigARP_USE_CLASH_DETECTION */ + +/* Part of the Ethernet and ARP headers are always constant when sending an IPv4 +ARP packet. This array defines the constant parts, allowing this part of the +packet to be filled in using a simple memcpy() instead of individual writes. */ +static const uint8_t xDefaultPartARPPacketHeader[] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Ethernet destination address. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source address. */ + 0x08, 0x06, /* Ethernet frame type (ipARP_FRAME_TYPE). */ + 0x00, 0x01, /* usHardwareType (ipARP_HARDWARE_TYPE_ETHERNET). */ + 0x08, 0x00, /* usProtocolType. */ + ipMAC_ADDRESS_LENGTH_BYTES, /* ucHardwareAddressLength. */ + ipIP_ADDRESS_LENGTH_BYTES, /* ucProtocolAddressLength. */ + 0x00, 0x01, /* usOperation (ipARP_REQUEST). */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* xSenderHardwareAddress. */ + 0x00, 0x00, 0x00, 0x00, /* ulSenderProtocolAddress. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* xTargetHardwareAddress. */ +}; + +/*-----------------------------------------------------------*/ + +eFrameProcessingResult_t eARPProcessPacket( ARPPacket_t * const pxARPFrame ) +{ +eFrameProcessingResult_t eReturn = eReleaseBuffer; +ARPHeader_t *pxARPHeader; +uint32_t ulTargetProtocolAddress, ulSenderProtocolAddress; + + pxARPHeader = &( pxARPFrame->xARPHeader ); + + /* The field ulSenderProtocolAddress is badly aligned, copy byte-by-byte. */ + memcpy( ( void *)&( ulSenderProtocolAddress ), ( void * )pxARPHeader->ucSenderProtocolAddress, sizeof( ulSenderProtocolAddress ) ); + /* The field ulTargetProtocolAddress is well-aligned, a 32-bits copy. */ + ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress; + + traceARP_PACKET_RECEIVED(); + + /* Don't do anything if the local IP address is zero because + that means a DHCP request has not completed. */ + if( *ipLOCAL_IP_ADDRESS_POINTER != 0UL ) + { + switch( pxARPHeader->usOperation ) + { + case ipARP_REQUEST : + /* The packet contained an ARP request. Was it for the IP + address of the node running this code? */ + if( ulTargetProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER ) + { + iptraceSENDING_ARP_REPLY( ulSenderProtocolAddress ); + + /* The request is for the address of this node. Add the + entry into the ARP cache, or refresh the entry if it + already exists. */ + vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress ); + + /* Generate a reply payload in the same buffer. */ + pxARPHeader->usOperation = ( uint16_t ) ipARP_REPLY; + if( ulTargetProtocolAddress == ulSenderProtocolAddress ) + { + /* A double IP address is detected! */ + /* Give the sources MAC address the value of the broadcast address, will be swapped later */ + memcpy( pxARPFrame->xEthernetHeader.xSourceAddress.ucBytes, xBroadcastMACAddress.ucBytes, sizeof( xBroadcastMACAddress ) ); + memset( pxARPHeader->xTargetHardwareAddress.ucBytes, '\0', sizeof( MACAddress_t ) ); + pxARPHeader->ulTargetProtocolAddress = 0UL; + } + else + { + memcpy( pxARPHeader->xTargetHardwareAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( MACAddress_t ) ); + pxARPHeader->ulTargetProtocolAddress = ulSenderProtocolAddress; + } + memcpy( pxARPHeader->xSenderHardwareAddress.ucBytes, ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) ); + memcpy( ( void* )pxARPHeader->ucSenderProtocolAddress, ( void* )ipLOCAL_IP_ADDRESS_POINTER, sizeof( pxARPHeader->ucSenderProtocolAddress ) ); + + eReturn = eReturnEthernetFrame; + } + break; + + case ipARP_REPLY : + iptracePROCESSING_RECEIVED_ARP_REPLY( ulTargetProtocolAddress ); + vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress ); + /* Process received ARP frame to see if there is a clash. */ + #if( ipconfigARP_USE_CLASH_DETECTION != 0 ) + { + if( ulSenderProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER ) + { + xARPHadIPClash = pdTRUE; + memcpy( xARPClashMacAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( xARPClashMacAddress.ucBytes ) ); + } + } + #endif /* ipconfigARP_USE_CLASH_DETECTION */ + break; + + default : + /* Invalid. */ + break; + } + } + + return eReturn; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_ARP_REMOVE_ENTRY != 0 ) + + uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress ) + { + BaseType_t x; + uint32_t lResult = 0; + + /* For each entry in the ARP cache table. */ + for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ ) + { + if( ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) ) + { + lResult = xARPCache[ x ].ulIPAddress; + memset( &xARPCache[ x ], '\0', sizeof( xARPCache[ x ] ) ); + break; + } + } + + return lResult; + } + +#endif /* ipconfigUSE_ARP_REMOVE_ENTRY != 0 */ +/*-----------------------------------------------------------*/ + +void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress, const uint32_t ulIPAddress ) +{ +BaseType_t x = 0; +BaseType_t xIpEntry = -1; +BaseType_t xMacEntry = -1; +BaseType_t xUseEntry = 0; +uint8_t ucMinAgeFound = 0U; + + #if( ipconfigARP_STORES_REMOTE_ADDRESSES == 0 ) + /* Only process the IP address if it is on the local network. + Unless: when '*ipLOCAL_IP_ADDRESS_POINTER' equals zero, the IP-address + and netmask are still unknown. */ + if( ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) ) || + ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) ) + #else + /* If ipconfigARP_STORES_REMOTE_ADDRESSES is non-zero, IP addresses with + a different netmask will also be stored. After when replying to a UDP + message from a different netmask, the IP address can be looped up and a + reply sent. This option is useful for systems with multiple gateways, + the reply will surely arrive. If ipconfigARP_STORES_REMOTE_ADDRESSES is + zero the the gateway address is the only option. */ + if( pdTRUE ) + #endif + { + /* Start with the maximum possible number. */ + ucMinAgeFound--; + + /* For each entry in the ARP cache table. */ + for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ ) + { + /* Does this line in the cache table hold an entry for the IP + address being queried? */ + if( xARPCache[ x ].ulIPAddress == ulIPAddress ) + { + if( pxMACAddress == NULL ) + { + /* In case the parameter pxMACAddress is NULL, an entry will be reserved to + indicate that there is an outstanding ARP request, This entry will have + "ucValid == pdFALSE". */ + xIpEntry = x; + break; + } + + /* See if the MAC-address also matches. */ + if( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) + { + /* This function will be called for each received packet + As this is by far the most common path the coding standard + is relaxed in this case and a return is permitted as an + optimisation. */ + xARPCache[ x ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE; + xARPCache[ x ].ucValid = ( uint8_t ) pdTRUE; + return; + } + + /* Found an entry containing ulIPAddress, but the MAC address + doesn't match. Might be an entry with ucValid=pdFALSE, waiting + for an ARP reply. Still want to see if there is match with the + given MAC address.ucBytes. If found, either of the two entries + must be cleared. */ + xIpEntry = x; + } + else if( ( pxMACAddress != NULL ) && ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) ) + { + /* Found an entry with the given MAC-address, but the IP-address + is different. Continue looping to find a possible match with + ulIPAddress. */ + #if( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 ) + /* If ARP stores the MAC address of IP addresses outside the + network, than the MAC address of the gateway should not be + overwritten. */ + BaseType_t bIsLocal[ 2 ]; + bIsLocal[ 0 ] = ( ( xARPCache[ x ].ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) ); + bIsLocal[ 1 ] = ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) ); + if( bIsLocal[ 0 ] == bIsLocal[ 1 ] ) + { + xMacEntry = x; + } + #else + xMacEntry = x; + #endif + } + /* _HT_ + Shouldn't we test for xARPCache[ x ].ucValid == pdFALSE here ? */ + else if( xARPCache[ x ].ucAge < ucMinAgeFound ) + { + /* As the table is traversed, remember the table row that + contains the oldest entry (the lowest age count, as ages are + decremented to zero) so the row can be re-used if this function + needs to add an entry that does not already exist. */ + ucMinAgeFound = xARPCache[ x ].ucAge; + xUseEntry = x; + } + } + + if( xMacEntry >= 0 ) + { + xUseEntry = xMacEntry; + + if( xIpEntry >= 0 ) + { + /* Both the MAC address as well as the IP address were found in + different locations: clear the entry which matches the + IP-address */ + memset( &xARPCache[ xIpEntry ], '\0', sizeof( xARPCache[ xIpEntry ] ) ); + } + } + else if( xIpEntry >= 0 ) + { + /* An entry containing the IP-address was found, but it had a different MAC address */ + xUseEntry = xIpEntry; + } + + /* If the entry was not found, we use the oldest entry and set the IPaddress */ + xARPCache[ xUseEntry ].ulIPAddress = ulIPAddress; + + if( pxMACAddress != NULL ) + { + memcpy( xARPCache[ xUseEntry ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ); + + iptraceARP_TABLE_ENTRY_CREATED( ulIPAddress, (*pxMACAddress) ); + /* And this entry does not need immediate attention */ + xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE; + xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdTRUE; + } + else if( xIpEntry < 0 ) + { + xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_RETRANSMISSIONS; + xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdFALSE; + } + } +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_ARP_REVERSED_LOOKUP == 1 ) + eARPLookupResult_t eARPGetCacheEntryByMac( MACAddress_t * const pxMACAddress, uint32_t *pulIPAddress ) + { + BaseType_t x; + eARPLookupResult_t eReturn = eARPCacheMiss; + + /* Loop through each entry in the ARP cache. */ + for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ ) + { + /* Does this row in the ARP cache table hold an entry for the MAC + address being searched? */ + if( memcmp( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 ) + { + *pulIPAddress = xARPCache[ x ].ulIPAddress; + eReturn = eARPCacheHit; + break; + } + } + + return eReturn; + } +#endif /* ipconfigUSE_ARP_REVERSED_LOOKUP */ + +/*-----------------------------------------------------------*/ + +eARPLookupResult_t eARPGetCacheEntry( uint32_t *pulIPAddress, MACAddress_t * const pxMACAddress ) +{ +eARPLookupResult_t eReturn; +uint32_t ulAddressToLookup; + +#if( ipconfigUSE_LLMNR == 1 ) + if( *pulIPAddress == ipLLMNR_IP_ADDR ) /* Is in network byte order. */ + { + /* The LLMNR IP-address has a fixed virtual MAC address. */ + memcpy( pxMACAddress->ucBytes, xLLMNR_MacAdress.ucBytes, sizeof( MACAddress_t ) ); + eReturn = eARPCacheHit; + } + else +#endif + if( ( *pulIPAddress == ipBROADCAST_IP_ADDRESS ) || /* Is it the general broadcast address 255.255.255.255? */ + ( *pulIPAddress == xNetworkAddressing.ulBroadcastAddress ) )/* Or a local broadcast address, eg 192.168.1.255? */ + { + /* This is a broadcast so uses the broadcast MAC address. */ + memcpy( pxMACAddress->ucBytes, xBroadcastMACAddress.ucBytes, sizeof( MACAddress_t ) ); + eReturn = eARPCacheHit; + } + else if( *ipLOCAL_IP_ADDRESS_POINTER == 0UL ) + { + /* The IP address has not yet been assigned, so there is nothing that + can be done. */ + eReturn = eCantSendPacket; + } + else + { + eReturn = eARPCacheMiss; + + if( ( *pulIPAddress & xNetworkAddressing.ulNetMask ) != ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) ) + { +#if( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 ) + eReturn = prvCacheLookup( *pulIPAddress, pxMACAddress ); + + if( eReturn == eARPCacheHit ) + { + /* The stack is configured to store 'remote IP addresses', i.e. addresses + belonging to a different the netmask. prvCacheLookup() returned a hit, so + the MAC address is known */ + } + else +#endif + { + /* The IP address is off the local network, so look up the + hardware address of the router, if any. */ + if( xNetworkAddressing.ulGatewayAddress != ( uint32_t )0u ) + { + ulAddressToLookup = xNetworkAddressing.ulGatewayAddress; + } + else + { + ulAddressToLookup = *pulIPAddress; + } + } + } + else + { + /* The IP address is on the local network, so lookup the requested + IP address directly. */ + ulAddressToLookup = *pulIPAddress; + } + + if( eReturn == eARPCacheMiss ) + { + if( ulAddressToLookup == 0UL ) + { + /* The address is not on the local network, and there is not a + router. */ + eReturn = eCantSendPacket; + } + else + { + eReturn = prvCacheLookup( ulAddressToLookup, pxMACAddress ); + + if( eReturn == eARPCacheMiss ) + { + /* It might be that the ARP has to go to the gateway. */ + *pulIPAddress = ulAddressToLookup; + } + } + } + } + + return eReturn; +} + +/*-----------------------------------------------------------*/ + +static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup, MACAddress_t * const pxMACAddress ) +{ +BaseType_t x; +eARPLookupResult_t eReturn = eARPCacheMiss; + + /* Loop through each entry in the ARP cache. */ + for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ ) + { + /* Does this row in the ARP cache table hold an entry for the IP address + being queried? */ + if( xARPCache[ x ].ulIPAddress == ulAddressToLookup ) + { + /* A matching valid entry was found. */ + if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE ) + { + /* This entry is waiting an ARP reply, so is not valid. */ + eReturn = eCantSendPacket; + } + else + { + /* A valid entry was found. */ + memcpy( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) ); + eReturn = eARPCacheHit; + } + break; + } + } + + return eReturn; +} +/*-----------------------------------------------------------*/ + +void vARPAgeCache( void ) +{ +BaseType_t x; +TickType_t xTimeNow; + + /* Loop through each entry in the ARP cache. */ + for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ ) + { + /* If the entry is valid (its age is greater than zero). */ + if( xARPCache[ x ].ucAge > 0U ) + { + /* Decrement the age value of the entry in this ARP cache table row. + When the age reaches zero it is no longer considered valid. */ + ( xARPCache[ x ].ucAge )--; + + /* If the entry is not yet valid, then it is waiting an ARP + reply, and the ARP request should be retransmitted. */ + if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE ) + { + FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress ); + } + else if( xARPCache[ x ].ucAge <= ( uint8_t ) arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST ) + { + /* This entry will get removed soon. See if the MAC address is + still valid to prevent this happening. */ + iptraceARP_TABLE_ENTRY_WILL_EXPIRE( xARPCache[ x ].ulIPAddress ); + FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress ); + } + else + { + /* The age has just ticked down, with nothing to do. */ + } + + if( xARPCache[ x ].ucAge == 0u ) + { + /* The entry is no longer valid. Wipe it out. */ + iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress ); + xARPCache[ x ].ulIPAddress = 0UL; + } + } + } + + xTimeNow = xTaskGetTickCount (); + + if( ( xLastGratuitousARPTime == ( TickType_t ) 0 ) || ( ( xTimeNow - xLastGratuitousARPTime ) > ( TickType_t ) arpGRATUITOUS_ARP_PERIOD ) ) + { + FreeRTOS_OutputARPRequest( *ipLOCAL_IP_ADDRESS_POINTER ); + xLastGratuitousARPTime = xTimeNow; + } +} +/*-----------------------------------------------------------*/ + +void vARPSendGratuitous( void ) +{ + /* Setting xLastGratuitousARPTime to 0 will force a gratuitous ARP the next + time vARPAgeCache() is called. */ + xLastGratuitousARPTime = ( TickType_t ) 0; + + /* Let the IP-task call vARPAgeCache(). */ + xSendEventToIPTask( eARPTimerEvent ); +} + +/*-----------------------------------------------------------*/ +void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress ) +{ +NetworkBufferDescriptor_t *pxNetworkBuffer; + + /* This is called from the context of the IP event task, so a block time + must not be used. */ + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( ARPPacket_t ), ( TickType_t ) 0 ); + + if( pxNetworkBuffer != NULL ) + { + pxNetworkBuffer->ulIPAddress = ulIPAddress; + vARPGenerateRequestPacket( pxNetworkBuffer ); + + #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES ) + { + if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES ) + { + BaseType_t xIndex; + + for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ ) + { + pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u; + } + pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; + } + } + #endif + + xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE ); + } +} + +void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ +ARPPacket_t *pxARPPacket; + + pxARPPacket = ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer; + + /* memcpy the const part of the header information into the correct + location in the packet. This copies: + xEthernetHeader.ulDestinationAddress + xEthernetHeader.usFrameType; + xARPHeader.usHardwareType; + xARPHeader.usProtocolType; + xARPHeader.ucHardwareAddressLength; + xARPHeader.ucProtocolAddressLength; + xARPHeader.usOperation; + xARPHeader.xTargetHardwareAddress; + */ + memcpy( ( void * ) pxARPPacket, ( void * ) xDefaultPartARPPacketHeader, sizeof( xDefaultPartARPPacketHeader ) ); + memcpy( ( void * ) pxARPPacket->xEthernetHeader.xSourceAddress.ucBytes , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES ); + memcpy( ( void * ) pxARPPacket->xARPHeader.xSenderHardwareAddress.ucBytes, ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES ); + + memcpy( ( void* )pxARPPacket->xARPHeader.ucSenderProtocolAddress, ( void* )ipLOCAL_IP_ADDRESS_POINTER, sizeof( pxARPPacket->xARPHeader.ucSenderProtocolAddress ) ); + pxARPPacket->xARPHeader.ulTargetProtocolAddress = pxNetworkBuffer->ulIPAddress; + + pxNetworkBuffer->xDataLength = sizeof( ARPPacket_t ); + + iptraceCREATING_ARP_REQUEST( pxNetworkBuffer->ulIPAddress ); +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_ClearARP( void ) +{ + memset( xARPCache, '\0', sizeof( xARPCache ) ); +} +/*-----------------------------------------------------------*/ + +#if( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) + + void FreeRTOS_PrintARPCache( void ) + { + BaseType_t x, xCount = 0; + + /* Loop through each entry in the ARP cache. */ + for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ ) + { + if( ( xARPCache[ x ].ulIPAddress != 0ul ) && ( xARPCache[ x ].ucAge > 0U ) ) + { + /* See if the MAC-address also matches, and we're all happy */ + FreeRTOS_printf( ( "Arp %2ld: %3u - %16lxip : %02x:%02x:%02x : %02x:%02x:%02x\n", + x, + xARPCache[ x ].ucAge, + xARPCache[ x ].ulIPAddress, + xARPCache[ x ].xMACAddress.ucBytes[0], + xARPCache[ x ].xMACAddress.ucBytes[1], + xARPCache[ x ].xMACAddress.ucBytes[2], + xARPCache[ x ].xMACAddress.ucBytes[3], + xARPCache[ x ].xMACAddress.ucBytes[4], + xARPCache[ x ].xMACAddress.ucBytes[5] ) ); + xCount++; + } + } + + FreeRTOS_printf( ( "Arp has %ld entries\n", xCount ) ); + } + +#endif /* ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c new file mode 100644 index 000000000..ea4629b14 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c @@ -0,0 +1,1011 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_TCP_IP.h" +#include "FreeRTOS_DHCP.h" +#include "FreeRTOS_ARP.h" +#include "NetworkInterface.h" +#include "NetworkBufferManagement.h" + +/* Exclude the entire file if DHCP is not enabled. */ +#if( ipconfigUSE_DHCP != 0 ) + +#if ( ipconfigUSE_DHCP != 0 ) && ( ipconfigNETWORK_MTU < 586u ) + /* DHCP must be able to receive an options field of 312 bytes, the fixed + part of the DHCP packet is 240 bytes, and the IP/UDP headers take 28 bytes. */ + #error ipconfigNETWORK_MTU needs to be at least 586 to use DHCP +#endif + +/* Parameter widths in the DHCP packet. */ +#define dhcpCLIENT_HARDWARE_ADDRESS_LENGTH 16 +#define dhcpSERVER_HOST_NAME_LENGTH 64 +#define dhcpBOOT_FILE_NAME_LENGTH 128 + +/* Timer parameters */ +#ifndef dhcpINITIAL_DHCP_TX_PERIOD + #define dhcpINITIAL_TIMER_PERIOD ( pdMS_TO_TICKS( 250 ) ) + #define dhcpINITIAL_DHCP_TX_PERIOD ( pdMS_TO_TICKS( 5000 ) ) +#endif + +/* Codes of interest found in the DHCP options field. */ +#define dhcpZERO_PAD_OPTION_CODE ( 0u ) +#define dhcpSUBNET_MASK_OPTION_CODE ( 1u ) +#define dhcpGATEWAY_OPTION_CODE ( 3u ) +#define dhcpDNS_SERVER_OPTIONS_CODE ( 6u ) +#define dhcpDNS_HOSTNAME_OPTIONS_CODE ( 12u ) +#define dhcpREQUEST_IP_ADDRESS_OPTION_CODE ( 50u ) +#define dhcpLEASE_TIME_OPTION_CODE ( 51u ) +#define dhcpMESSAGE_TYPE_OPTION_CODE ( 53u ) +#define dhcpSERVER_IP_ADDRESS_OPTION_CODE ( 54u ) +#define dhcpPARAMETER_REQUEST_OPTION_CODE ( 55u ) +#define dhcpCLIENT_IDENTIFIER_OPTION_CODE ( 61u ) + +/* The four DHCP message types of interest. */ +#define dhcpMESSAGE_TYPE_DISCOVER ( 1 ) +#define dhcpMESSAGE_TYPE_OFFER ( 2 ) +#define dhcpMESSAGE_TYPE_REQUEST ( 3 ) +#define dhcpMESSAGE_TYPE_ACK ( 5 ) +#define dhcpMESSAGE_TYPE_NACK ( 6 ) + +/* Offsets into the transmitted DHCP options fields at which various parameters +are located. */ +#define dhcpCLIENT_IDENTIFIER_OFFSET ( 5 ) +#define dhcpREQUESTED_IP_ADDRESS_OFFSET ( 13 ) +#define dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ( 19 ) + +/* Values used in the DHCP packets. */ +#define dhcpREQUEST_OPCODE ( 1 ) +#define dhcpREPLY_OPCODE ( 2 ) +#define dhcpADDRESS_TYPE_ETHERNET ( 1 ) +#define dhcpETHERNET_ADDRESS_LENGTH ( 6 ) + +/* If a lease time is not received, use the default of two days. */ +/* 48 hours in ticks. Can not use pdMS_TO_TICKS() as integer overflow can occur. */ +#define dhcpDEFAULT_LEASE_TIME ( ( 48UL * 60UL * 60UL ) * configTICK_RATE_HZ ) + +/* Don't allow the lease time to be too short. */ +#define dhcpMINIMUM_LEASE_TIME ( pdMS_TO_TICKS( 60000UL ) ) /* 60 seconds in ticks. */ + +/* Marks the end of the variable length options field in the DHCP packet. */ +#define dhcpOPTION_END_BYTE 0xffu + +/* Offset into a DHCP message at which the first byte of the options is +located. */ +#define dhcpFIRST_OPTION_BYTE_OFFSET ( 0xf0 ) + +/* Standard DHCP port numbers and magic cookie value. */ +#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) + #define dhcpCLIENT_PORT 0x4400u + #define dhcpSERVER_PORT 0x4300u + #define dhcpCOOKIE 0x63538263ul + #define dhcpBROADCAST 0x0080u +#else + #define dhcpCLIENT_PORT 0x0044u + #define dhcpSERVER_PORT 0x0043u + #define dhcpCOOKIE 0x63825363ul + #define dhcpBROADCAST 0x8000u +#endif /* ipconfigBYTE_ORDER */ + +#include "pack_struct_start.h" +struct xDHCPMessage +{ + uint8_t ucOpcode; + uint8_t ucAddressType; + uint8_t ucAddressLength; + uint8_t ucHops; + uint32_t ulTransactionID; + uint16_t usElapsedTime; + uint16_t usFlags; + uint32_t ulClientIPAddress_ciaddr; + uint32_t ulYourIPAddress_yiaddr; + uint32_t ulServerIPAddress_siaddr; + uint32_t ulRelayAgentIPAddress_giaddr; + uint8_t ucClientHardwareAddress[ dhcpCLIENT_HARDWARE_ADDRESS_LENGTH ]; + uint8_t ucServerHostName[ dhcpSERVER_HOST_NAME_LENGTH ]; + uint8_t ucBootFileName[ dhcpBOOT_FILE_NAME_LENGTH ]; + uint32_t ulDHCPCookie; + uint8_t ucFirstOptionByte; +} +#include "pack_struct_end.h" +typedef struct xDHCPMessage DHCPMessage_t; + +/* DHCP state machine states. */ +typedef enum +{ + eWaitingSendFirstDiscover = 0, /* Initial state. Send a discover the first time it is called, and reset all timers. */ + eWaitingOffer, /* Either resend the discover, or, if the offer is forthcoming, send a request. */ + eWaitingAcknowledge, /* Either resend the request. */ + #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 ) + eGetLinkLayerAddress, /* When DHCP didn't respond, try to obtain a LinkLayer address 168.254.x.x. */ + #endif + eLeasedAddress, /* Resend the request at the appropriate time to renew the lease. */ + eNotUsingLeasedAddress /* DHCP failed, and a default IP address is being used. */ +} eDHCPState_t; + +/* Hold information in between steps in the DHCP state machine. */ +struct xDHCP_DATA +{ + uint32_t ulTransactionId; + uint32_t ulOfferedIPAddress; + uint32_t ulDHCPServerAddress; + uint32_t ulLeaseTime; + /* Hold information on the current timer state. */ + TickType_t xDHCPTxTime; + TickType_t xDHCPTxPeriod; + /* Try both without and with the broadcast flag */ + BaseType_t xUseBroadcast; + /* Maintains the DHCP state machine state. */ + eDHCPState_t eDHCPState; + /* The UDP socket used for all incoming and outgoing DHCP traffic. */ + Socket_t xDHCPSocket; +}; + +typedef struct xDHCP_DATA DHCPData_t; + +#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 ) + /* Define the Link Layer IP address: 169.254.x.x */ + #define LINK_LAYER_ADDRESS_0 169 + #define LINK_LAYER_ADDRESS_1 254 + + /* Define the netmask used: 255.255.0.0 */ + #define LINK_LAYER_NETMASK_0 255 + #define LINK_LAYER_NETMASK_1 255 + #define LINK_LAYER_NETMASK_2 0 + #define LINK_LAYER_NETMASK_3 0 +#endif + + +/* + * Generate a DHCP discover message and send it on the DHCP socket. + */ +static void prvSendDHCPDiscover( void ); + +/* + * Interpret message received on the DHCP socket. + */ +static BaseType_t prvProcessDHCPReplies( BaseType_t xExpectedMessageType ); + +/* + * Generate a DHCP request packet, and send it on the DHCP socket. + */ +static void prvSendDHCPRequest( void ); + +/* + * Prepare to start a DHCP transaction. This initialises some state variables + * and creates the DHCP socket if necessary. + */ +static void prvInitialiseDHCP( void ); + +/* + * Creates the part of outgoing DHCP messages that are common to all outgoing + * DHCP messages. + */ +static uint8_t *prvCreatePartDHCPMessage( struct freertos_sockaddr *pxAddress, BaseType_t xOpcode, const uint8_t * const pucOptionsArray, size_t *pxOptionsArraySize ); + +/* + * Create the DHCP socket, if it has not been created already. + */ +static void prvCreateDHCPSocket( void ); + +/* + * After DHCP has failed to answer, prepare everything to start searching + * for (trying-out) LinkLayer IP-addresses, using the random method: Send + * a gratuitous ARP request and wait if another device responds to it. + */ +#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 ) + static void prvPrepareLinkLayerIPLookUp( void ); +#endif + +/*-----------------------------------------------------------*/ + +/* The next DHCP transaction Id to be used. */ +static DHCPData_t xDHCPData; + +/*-----------------------------------------------------------*/ + +BaseType_t xIsDHCPSocket( Socket_t xSocket ) +{ +BaseType_t xReturn; + + if( xDHCPData.xDHCPSocket == xSocket ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void vDHCPProcess( BaseType_t xReset ) +{ +BaseType_t xGivingUp = pdFALSE; +#if( ipconfigUSE_DHCP_HOOK != 0 ) + eDHCPCallbackAnswer_t eAnswer; +#endif /* ipconfigUSE_DHCP_HOOK */ + + /* Is DHCP starting over? */ + if( xReset != pdFALSE ) + { + xDHCPData.eDHCPState = eWaitingSendFirstDiscover; + } + + switch( xDHCPData.eDHCPState ) + { + case eWaitingSendFirstDiscover : + /* Ask the user if a DHCP discovery is required. */ + #if( ipconfigUSE_DHCP_HOOK != 0 ) + eAnswer = xApplicationDHCPHook( eDHCPPhasePreDiscover, xNetworkAddressing.ulDefaultIPAddress ); + if( eAnswer == eDHCPContinue ) + #endif /* ipconfigUSE_DHCP_HOOK */ + { + /* Initial state. Create the DHCP socket, timer, etc. if they + have not already been created. */ + prvInitialiseDHCP(); + + /* See if prvInitialiseDHCP() has creates a socket. */ + if( xDHCPData.xDHCPSocket == NULL ) + { + xGivingUp = pdTRUE; + break; + } + + *ipLOCAL_IP_ADDRESS_POINTER = 0UL; + + /* Send the first discover request. */ + if( xDHCPData.xDHCPSocket != NULL ) + { + xDHCPData.xDHCPTxTime = xTaskGetTickCount(); + prvSendDHCPDiscover( ); + xDHCPData.eDHCPState = eWaitingOffer; + } + } + #if( ipconfigUSE_DHCP_HOOK != 0 ) + else + { + if( eAnswer == eDHCPUseDefaults ) + { + memcpy( &xNetworkAddressing, &xDefaultAddressing, sizeof( xNetworkAddressing ) ); + } + + /* The user indicates that the DHCP process does not continue. */ + xGivingUp = pdTRUE; + } + #endif /* ipconfigUSE_DHCP_HOOK */ + break; + + case eWaitingOffer : + + xGivingUp = pdFALSE; + + /* Look for offers coming in. */ + if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_OFFER ) == pdPASS ) + { + #if( ipconfigUSE_DHCP_HOOK != 0 ) + /* Ask the user if a DHCP request is required. */ + eAnswer = xApplicationDHCPHook( eDHCPPhasePreRequest, xDHCPData.ulOfferedIPAddress ); + + if( eAnswer == eDHCPContinue ) + #endif /* ipconfigUSE_DHCP_HOOK */ + { + /* An offer has been made, the user wants to continue, + generate the request. */ + xDHCPData.xDHCPTxTime = xTaskGetTickCount(); + xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD; + prvSendDHCPRequest( ); + xDHCPData.eDHCPState = eWaitingAcknowledge; + break; + } + + #if( ipconfigUSE_DHCP_HOOK != 0 ) + if( eAnswer == eDHCPUseDefaults ) + { + memcpy( &xNetworkAddressing, &xDefaultAddressing, sizeof( xNetworkAddressing ) ); + } + + /* The user indicates that the DHCP process does not continue. */ + xGivingUp = pdTRUE; + #endif /* ipconfigUSE_DHCP_HOOK */ + } + else if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod ) + { + /* It is time to send another Discover. Increase the time + period, and if it has not got to the point of giving up - send + another discovery. */ + xDHCPData.xDHCPTxPeriod <<= 1; + + if( xDHCPData.xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD ) + { + xDHCPData.ulTransactionId = ipconfigRAND32( ); + + if( 0 != xDHCPData.ulTransactionId ) + { + xDHCPData.xDHCPTxTime = xTaskGetTickCount( ); + xDHCPData.xUseBroadcast = !xDHCPData.xUseBroadcast; + prvSendDHCPDiscover( ); + FreeRTOS_debug_printf( ( "vDHCPProcess: timeout %lu ticks\n", xDHCPData.xDHCPTxPeriod ) ); + } + else + { + FreeRTOS_debug_printf( ( "vDHCPProcess: failed to generate a random Transaction ID\n" ) ); + } + } + else + { + FreeRTOS_debug_printf( ( "vDHCPProcess: giving up %lu > %lu ticks\n", xDHCPData.xDHCPTxPeriod, ipconfigMAXIMUM_DISCOVER_TX_PERIOD ) ); + + #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 ) + { + /* Only use a fake Ack if the default IP address == 0x00 + and the link local addressing is used. Start searching + a free LinkLayer IP-address. Next state will be + 'eGetLinkLayerAddress'. */ + prvPrepareLinkLayerIPLookUp(); + + /* Setting an IP address manually so set to not using + leased address mode. */ + xDHCPData.eDHCPState = eGetLinkLayerAddress; + } + #else + { + xGivingUp = pdTRUE; + } + #endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */ + } + } + break; + + case eWaitingAcknowledge : + + /* Look for acks coming in. */ + if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_ACK ) == pdPASS ) + { + FreeRTOS_debug_printf( ( "vDHCPProcess: acked %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) ); + + /* DHCP completed. The IP address can now be used, and the + timer set to the lease timeout time. */ + *ipLOCAL_IP_ADDRESS_POINTER = xDHCPData.ulOfferedIPAddress; + + /* Setting the 'local' broadcast address, something like + '192.168.1.255'. */ + xNetworkAddressing.ulBroadcastAddress = ( xDHCPData.ulOfferedIPAddress & xNetworkAddressing.ulNetMask ) | ~xNetworkAddressing.ulNetMask; + xDHCPData.eDHCPState = eLeasedAddress; + + iptraceDHCP_SUCCEDEED( xDHCPData.ulOfferedIPAddress ); + + /* DHCP failed, the default configured IP-address will be used + Now call vIPNetworkUpCalls() to send the network-up event and + start the ARP timer. */ + vIPNetworkUpCalls( ); + + /* Close socket to ensure packets don't queue on it. */ + vSocketClose( xDHCPData.xDHCPSocket ); + xDHCPData.xDHCPSocket = NULL; + + if( xDHCPData.ulLeaseTime == 0UL ) + { + xDHCPData.ulLeaseTime = dhcpDEFAULT_LEASE_TIME; + } + else if( xDHCPData.ulLeaseTime < dhcpMINIMUM_LEASE_TIME ) + { + xDHCPData.ulLeaseTime = dhcpMINIMUM_LEASE_TIME; + } + else + { + /* The lease time is already valid. */ + } + + /* Check for clashes. */ + vARPSendGratuitous(); + vIPReloadDHCPTimer( xDHCPData.ulLeaseTime ); + } + else + { + /* Is it time to send another Discover? */ + if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod ) + { + /* Increase the time period, and if it has not got to the + point of giving up - send another request. */ + xDHCPData.xDHCPTxPeriod <<= 1; + + if( xDHCPData.xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD ) + { + xDHCPData.xDHCPTxTime = xTaskGetTickCount(); + prvSendDHCPRequest( ); + } + else + { + /* Give up, start again. */ + xDHCPData.eDHCPState = eWaitingSendFirstDiscover; + } + } + } + break; + + #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 ) + case eGetLinkLayerAddress: + if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod ) + { + if( xARPHadIPClash == pdFALSE ) + { + /* ARP OK. proceed. */ + iptraceDHCP_SUCCEDEED( xDHCPData.ulOfferedIPAddress ); + + /* Auto-IP succeeded, the default configured IP-address will + be used. Now call vIPNetworkUpCalls() to send the + network-up event and start the ARP timer. */ + vIPNetworkUpCalls( ); + xDHCPData.eDHCPState = eNotUsingLeasedAddress; + } + else + { + /* ARP clashed - try another IP address. */ + prvPrepareLinkLayerIPLookUp(); + + /* Setting an IP address manually so set to not using leased + address mode. */ + xDHCPData.eDHCPState = eGetLinkLayerAddress; + } + } + break; + #endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */ + + case eLeasedAddress : + + /* Resend the request at the appropriate time to renew the lease. */ + prvCreateDHCPSocket(); + + if( xDHCPData.xDHCPSocket != NULL ) + { + xDHCPData.xDHCPTxTime = xTaskGetTickCount(); + xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD; + prvSendDHCPRequest( ); + xDHCPData.eDHCPState = eWaitingAcknowledge; + + /* From now on, we should be called more often */ + vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD ); + } + break; + + case eNotUsingLeasedAddress: + + vIPSetDHCPTimerEnableState( pdFALSE ); + break; + + default: + break; + } + + if( xGivingUp != pdFALSE ) + { + /* xGivingUp became true either because of a time-out, or because + xApplicationDHCPHook() returned another value than 'eDHCPContinue', + meaning that the conversion is canceled from here. */ + + /* Revert to static IP address. */ + taskENTER_CRITICAL(); + { + *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress; + iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS( xNetworkAddressing.ulDefaultIPAddress ); + } + taskEXIT_CRITICAL(); + + xDHCPData.eDHCPState = eNotUsingLeasedAddress; + vIPSetDHCPTimerEnableState( pdFALSE ); + + /* DHCP failed, the default configured IP-address will be used. Now + call vIPNetworkUpCalls() to send the network-up event and start the ARP + timer. */ + vIPNetworkUpCalls( ); + + /* Test if socket was indeed created. */ + if( xDHCPData.xDHCPSocket != NULL ) + { + /* Close socket to ensure packets don't queue on it. */ + vSocketClose( xDHCPData.xDHCPSocket ); + xDHCPData.xDHCPSocket = NULL; + } + } +} +/*-----------------------------------------------------------*/ + +static void prvCreateDHCPSocket( void ) +{ +struct freertos_sockaddr xAddress; +BaseType_t xReturn; +TickType_t xTimeoutTime = ( TickType_t ) 0; + + /* Create the socket, if it has not already been created. */ + if( xDHCPData.xDHCPSocket == NULL ) + { + xDHCPData.xDHCPSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + if( xDHCPData.xDHCPSocket != FREERTOS_INVALID_SOCKET ) + { + + /* Ensure the Rx and Tx timeouts are zero as the DHCP executes in the + context of the IP task. */ + FreeRTOS_setsockopt( xDHCPData.xDHCPSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) ); + FreeRTOS_setsockopt( xDHCPData.xDHCPSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) ); + + /* Bind to the standard DHCP client port. */ + xAddress.sin_port = ( uint16_t ) dhcpCLIENT_PORT; + xReturn = vSocketBind( xDHCPData.xDHCPSocket, &xAddress, sizeof( xAddress ), pdFALSE ); + if( xReturn != 0 ) + { + /* Binding failed, close the socket again. */ + vSocketClose( xDHCPData.xDHCPSocket ); + xDHCPData.xDHCPSocket = NULL; + } + } + else + { + /* Change to NULL for easier testing. */ + xDHCPData.xDHCPSocket = NULL; + } + } +} +/*-----------------------------------------------------------*/ + +static void prvInitialiseDHCP( void ) +{ + /* Initialise the parameters that will be set by the DHCP process. Per + https://www.ietf.org/rfc/rfc2131.txt, Transaction ID should be a random + value chosen by the client. */ + xDHCPData.ulTransactionId = ipconfigRAND32(); + + /* Check for random number generator API failure. */ + if( 0 != xDHCPData.ulTransactionId ) + { + xDHCPData.xUseBroadcast = 0; + xDHCPData.ulOfferedIPAddress = 0UL; + xDHCPData.ulDHCPServerAddress = 0UL; + xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD; + + /* Create the DHCP socket if it has not already been created. */ + prvCreateDHCPSocket(); + FreeRTOS_debug_printf( ( "prvInitialiseDHCP: start after %lu ticks\n", dhcpINITIAL_TIMER_PERIOD ) ); + vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD ); + } +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvProcessDHCPReplies( BaseType_t xExpectedMessageType ) +{ +uint8_t *pucUDPPayload, *pucLastByte; +struct freertos_sockaddr xClient; +uint32_t xClientLength = sizeof( xClient ); +int32_t lBytes; +DHCPMessage_t *pxDHCPMessage; +uint8_t *pucByte, ucOptionCode, ucLength; +uint32_t ulProcessed, ulParameter; +BaseType_t xReturn = pdFALSE; +const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct DHCP message type must be present in the options. */ + + lBytes = FreeRTOS_recvfrom( xDHCPData.xDHCPSocket, ( void * ) &pucUDPPayload, 0ul, FREERTOS_ZERO_COPY, &xClient, &xClientLength ); + + if( lBytes > 0 ) + { + /* Map a DHCP structure onto the received data. */ + pxDHCPMessage = ( DHCPMessage_t * ) ( pucUDPPayload ); + + /* Sanity check. */ + if( ( lBytes >= sizeof( DHCPMessage_t ) ) && + ( pxDHCPMessage->ulDHCPCookie == ( uint32_t ) dhcpCOOKIE ) && + ( pxDHCPMessage->ucOpcode == ( uint8_t ) dhcpREPLY_OPCODE ) && + ( pxDHCPMessage->ulTransactionID == FreeRTOS_htonl( xDHCPData.ulTransactionId ) ) ) + { + if( memcmp( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress ), + ( void * ) ipLOCAL_MAC_ADDRESS, + sizeof( MACAddress_t ) ) == 0 ) + { + /* None of the essential options have been processed yet. */ + ulProcessed = 0ul; + + /* Walk through the options until the dhcpOPTION_END_BYTE byte + is found, taking care not to walk off the end of the options. */ + pucByte = &( pxDHCPMessage->ucFirstOptionByte ); + /* Maintain a pointer to the last valid byte (i.e. not the first + invalid byte). */ + pucLastByte = pucUDPPayload + lBytes - 1; + + while( pucByte <= pucLastByte ) + { + ucOptionCode = pucByte[ 0 ]; + if( ucOptionCode == dhcpOPTION_END_BYTE ) + { + /* Ready, the last byte has been seen. */ + break; + } + if( ucOptionCode == dhcpZERO_PAD_OPTION_CODE ) + { + /* The value zero is used as a pad byte, + it is not followed by a length byte. */ + pucByte += 1; + continue; + } + + /* Stop if the response is malformed. */ + if( pucByte < pucLastByte ) + { + /* There are at least two bytes left. */ + ucLength = pucByte[ 1 ]; + pucByte += 2; + + if( pucByte + ucLength > pucLastByte ) + { + break; + } + } + else + { + break; + } + + /* In most cases, a 4-byte network-endian parameter follows, + just get it once here and use later. */ + if( ucLength >= sizeof( ulParameter ) ) + { + memcpy( ( void * ) &( ulParameter ), + ( void * ) pucByte, + ( size_t ) sizeof( ulParameter ) ); + } + else + { + ulParameter = 0; + } + + /* Option-specific handling. */ + switch( ucOptionCode ) + { + case dhcpMESSAGE_TYPE_OPTION_CODE : + + if( *pucByte == ( uint8_t ) xExpectedMessageType ) + { + /* The message type is the message type the + state machine is expecting. */ + ulProcessed++; + } + else if( *pucByte == ( uint8_t ) dhcpMESSAGE_TYPE_NACK ) + { + if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_ACK ) + { + /* Start again. */ + xDHCPData.eDHCPState = eWaitingSendFirstDiscover; + } + } + else + { + /* Don't process other message types. */ + } + break; + + case dhcpSUBNET_MASK_OPTION_CODE : + + if( ucLength == sizeof( uint32_t ) ) + { + xNetworkAddressing.ulNetMask = ulParameter; + } + break; + + case dhcpGATEWAY_OPTION_CODE : + + if( ucLength == sizeof( uint32_t ) ) + { + /* ulProcessed is not incremented in this case + because the gateway is not essential. */ + xNetworkAddressing.ulGatewayAddress = ulParameter; + } + break; + + case dhcpDNS_SERVER_OPTIONS_CODE : + + /* ulProcessed is not incremented in this case + because the DNS server is not essential. Only the + first DNS server address is taken. */ + xNetworkAddressing.ulDNSServerAddress = ulParameter; + break; + + case dhcpSERVER_IP_ADDRESS_OPTION_CODE : + + if( ucLength == sizeof( uint32_t ) ) + { + if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_OFFER ) + { + /* Offers state the replying server. */ + ulProcessed++; + xDHCPData.ulDHCPServerAddress = ulParameter; + } + else + { + /* The ack must come from the expected server. */ + if( xDHCPData.ulDHCPServerAddress == ulParameter ) + { + ulProcessed++; + } + } + } + break; + + case dhcpLEASE_TIME_OPTION_CODE : + + if( ucLength == sizeof( xDHCPData.ulLeaseTime ) ) + { + /* ulProcessed is not incremented in this case + because the lease time is not essential. */ + /* The DHCP parameter is in seconds, convert + to host-endian format. */ + xDHCPData.ulLeaseTime = FreeRTOS_ntohl( ulParameter ); + + /* Divide the lease time by two to ensure a + renew request is sent before the lease actually + expires. */ + xDHCPData.ulLeaseTime >>= 1UL; + + /* Multiply with configTICK_RATE_HZ to get clock + ticks. */ + xDHCPData.ulLeaseTime = configTICK_RATE_HZ * xDHCPData.ulLeaseTime; + } + break; + + default : + + /* Not interested in this field. */ + + break; + } + + /* Jump over the data to find the next option code. */ + if( ucLength == 0u ) + { + break; + } + else + { + pucByte += ucLength; + } + } + + /* Were all the mandatory options received? */ + if( ulProcessed >= ulMandatoryOptions ) + { + /* HT:endian: used to be network order */ + xDHCPData.ulOfferedIPAddress = pxDHCPMessage->ulYourIPAddress_yiaddr; + FreeRTOS_printf( ( "vDHCPProcess: offer %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) ); + xReturn = pdPASS; + } + } + } + + FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayload ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static uint8_t *prvCreatePartDHCPMessage( struct freertos_sockaddr *pxAddress, BaseType_t xOpcode, const uint8_t * const pucOptionsArray, size_t *pxOptionsArraySize ) +{ +DHCPMessage_t *pxDHCPMessage; +size_t xRequiredBufferSize = sizeof( DHCPMessage_t ) + *pxOptionsArraySize; +uint8_t *pucUDPPayloadBuffer; + +#if( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) + const char *pucHostName = pcApplicationHostnameHook (); + size_t xNameLength = strlen( pucHostName ); + uint8_t *pucPtr; + + xRequiredBufferSize += ( 2 + xNameLength ); +#endif + + /* Get a buffer. This uses a maximum delay, but the delay will be capped + to ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS so the return value still needs to + be test. */ + do + { + } while( ( pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xRequiredBufferSize, portMAX_DELAY ) ) == NULL ); + + pxDHCPMessage = ( DHCPMessage_t * ) pucUDPPayloadBuffer; + + /* Most fields need to be zero. */ + memset( ( void * ) pxDHCPMessage, 0x00, sizeof( DHCPMessage_t ) ); + + /* Create the message. */ + pxDHCPMessage->ucOpcode = ( uint8_t ) xOpcode; + pxDHCPMessage->ucAddressType = ( uint8_t ) dhcpADDRESS_TYPE_ETHERNET; + pxDHCPMessage->ucAddressLength = ( uint8_t ) dhcpETHERNET_ADDRESS_LENGTH; + pxDHCPMessage->ulTransactionID = FreeRTOS_htonl( xDHCPData.ulTransactionId ); + pxDHCPMessage->ulDHCPCookie = ( uint32_t ) dhcpCOOKIE; + if( xDHCPData.xUseBroadcast != pdFALSE ) + { + pxDHCPMessage->usFlags = ( uint16_t ) dhcpBROADCAST; + } + else + { + pxDHCPMessage->usFlags = 0u; + } + + memcpy( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress[ 0 ] ), ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) ); + + /* Copy in the const part of the options options. */ + memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET ] ), ( void * ) pucOptionsArray, *pxOptionsArraySize ); + + #if( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) + { + /* With this option, the hostname can be registered as well which makes + it easier to lookup a device in a router's list of DHCP clients. */ + + /* Point to where the OPTION_END was stored to add data. */ + pucPtr = &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + ( *pxOptionsArraySize - 1 ) ] ); + pucPtr[ 0 ] = dhcpDNS_HOSTNAME_OPTIONS_CODE; + pucPtr[ 1 ] = ( uint8_t ) xNameLength; + memcpy( ( void *) ( pucPtr + 2 ), pucHostName, xNameLength ); + pucPtr[ 2 + xNameLength ] = dhcpOPTION_END_BYTE; + *pxOptionsArraySize += ( 2 + xNameLength ); + } + #endif + + /* Map in the client identifier. */ + memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpCLIENT_IDENTIFIER_OFFSET ] ), + ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) ); + + /* Set the addressing. */ + pxAddress->sin_addr = ipBROADCAST_IP_ADDRESS; + pxAddress->sin_port = ( uint16_t ) dhcpSERVER_PORT; + + return pucUDPPayloadBuffer; +} +/*-----------------------------------------------------------*/ + +static void prvSendDHCPRequest( void ) +{ +uint8_t *pucUDPPayloadBuffer; +struct freertos_sockaddr xAddress; +static const uint8_t ucDHCPRequestOptions[] = +{ + /* Do not change the ordering without also changing + dhcpCLIENT_IDENTIFIER_OFFSET, dhcpREQUESTED_IP_ADDRESS_OFFSET and + dhcpDHCP_SERVER_IP_ADDRESS_OFFSET. */ + dhcpMESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_REQUEST, /* Message type option. */ + dhcpCLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0, /* Client identifier. */ + dhcpREQUEST_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address being requested. */ + dhcpSERVER_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address of the DHCP server. */ + dhcpOPTION_END_BYTE +}; +size_t xOptionsLength = sizeof( ucDHCPRequestOptions ); + + pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, dhcpREQUEST_OPCODE, ucDHCPRequestOptions, &xOptionsLength ); + + /* Copy in the IP address being requested. */ + memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpREQUESTED_IP_ADDRESS_OFFSET ] ), + ( void * ) &( xDHCPData.ulOfferedIPAddress ), sizeof( xDHCPData.ulOfferedIPAddress ) ); + + /* Copy in the address of the DHCP server being used. */ + memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ] ), + ( void * ) &( xDHCPData.ulDHCPServerAddress ), sizeof( xDHCPData.ulDHCPServerAddress ) ); + + FreeRTOS_debug_printf( ( "vDHCPProcess: reply %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) ); + iptraceSENDING_DHCP_REQUEST(); + + /* 'ucFirstOptionByte' is part of DHCP message struct, so subtract one byte. */ + if( FreeRTOS_sendto( xDHCPData.xDHCPSocket, pucUDPPayloadBuffer, ( sizeof( DHCPMessage_t ) + xOptionsLength - 1 ), FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) == 0 ) + { + /* The packet was not successfully queued for sending and must be + returned to the stack. */ + FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer ); + } +} +/*-----------------------------------------------------------*/ + +static void prvSendDHCPDiscover( void ) +{ +uint8_t *pucUDPPayloadBuffer; +struct freertos_sockaddr xAddress; +static const uint8_t ucDHCPDiscoverOptions[] = +{ + /* Do not change the ordering without also changing dhcpCLIENT_IDENTIFIER_OFFSET. */ + dhcpMESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_DISCOVER, /* Message type option. */ + dhcpCLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0, /* Client identifier. */ + dhcpPARAMETER_REQUEST_OPTION_CODE, 3, dhcpSUBNET_MASK_OPTION_CODE, dhcpGATEWAY_OPTION_CODE, dhcpDNS_SERVER_OPTIONS_CODE, /* Parameter request option. */ + dhcpOPTION_END_BYTE +}; +size_t xOptionsLength = sizeof( ucDHCPDiscoverOptions ); + + pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, dhcpREQUEST_OPCODE, ucDHCPDiscoverOptions, &xOptionsLength ); + + FreeRTOS_debug_printf( ( "vDHCPProcess: discover\n" ) ); + iptraceSENDING_DHCP_DISCOVER(); + + /* 'ucFirstOptionByte' is part of DHCP message struct, so subtract one byte. */ + if( FreeRTOS_sendto( xDHCPData.xDHCPSocket, pucUDPPayloadBuffer, ( sizeof( DHCPMessage_t ) + xOptionsLength - 1 ), FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) == 0 ) + { + /* The packet was not successfully queued for sending and must be + returned to the stack. */ + FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer ); + } +} +/*-----------------------------------------------------------*/ + +#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 ) + + static void prvPrepareLinkLayerIPLookUp( void ) + { + uint8_t ucLinkLayerIPAddress[ 2 ]; + + /* After DHCP has failed to answer, prepare everything to start + trying-out LinkLayer IP-addresses, using the random method. */ + xDHCPData.xDHCPTxTime = xTaskGetTickCount(); + + ucLinkLayerIPAddress[ 0 ] = ( uint8_t )1 + ( uint8_t )( ipconfigRAND32() % 0xFDu ); /* get value 1..254 for IP-address 3rd byte of IP address to try. */ + ucLinkLayerIPAddress[ 1 ] = ( uint8_t )1 + ( uint8_t )( ipconfigRAND32() % 0xFDu ); /* get value 1..254 for IP-address 4th byte of IP address to try. */ + + xNetworkAddressing.ulGatewayAddress = FreeRTOS_htonl( 0xA9FE0203 ); + + /* prepare xDHCPData with data to test. */ + xDHCPData.ulOfferedIPAddress = + FreeRTOS_inet_addr_quick( LINK_LAYER_ADDRESS_0, LINK_LAYER_ADDRESS_1, ucLinkLayerIPAddress[ 0 ], ucLinkLayerIPAddress[ 1 ] ); + + xDHCPData.ulLeaseTime = dhcpDEFAULT_LEASE_TIME; /* don't care about lease time. just put anything. */ + + xNetworkAddressing.ulNetMask = + FreeRTOS_inet_addr_quick( LINK_LAYER_NETMASK_0, LINK_LAYER_NETMASK_1, LINK_LAYER_NETMASK_2, LINK_LAYER_NETMASK_3 ); + + /* DHCP completed. The IP address can now be used, and the + timer set to the lease timeout time. */ + *ipLOCAL_IP_ADDRESS_POINTER = xDHCPData.ulOfferedIPAddress; + + /* Setting the 'local' broadcast address, something like 192.168.1.255' */ + xNetworkAddressing.ulBroadcastAddress = ( xDHCPData.ulOfferedIPAddress & xNetworkAddressing.ulNetMask ) | ~xNetworkAddressing.ulNetMask; + + /* Close socket to ensure packets don't queue on it. not needed anymore as DHCP failed. but still need timer for ARP testing. */ + vSocketClose( xDHCPData.xDHCPSocket ); + xDHCPData.xDHCPSocket = NULL; + xDHCPData.xDHCPTxPeriod = pdMS_TO_TICKS( 3000ul + ( ipconfigRAND32() & 0x3fful ) ); /* do ARP test every (3 + 0-1024mS) seconds. */ + + xARPHadIPClash = pdFALSE; /* reset flag that shows if have ARP clash. */ + vARPSendGratuitous(); + } + +#endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */ +/*-----------------------------------------------------------*/ + +#endif /* ipconfigUSE_DHCP != 0 */ + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c new file mode 100644 index 000000000..de53b3eb8 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c @@ -0,0 +1,1422 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "list.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_DNS.h" +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" +#include "IPTraceMacroDefaults.h" + +/* Exclude the entire file if DNS is not enabled. */ +#if( ipconfigUSE_DNS != 0 ) + +#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) + #define dnsDNS_PORT 0x3500 + #define dnsONE_QUESTION 0x0100 + #define dnsOUTGOING_FLAGS 0x0001 /* Standard query. */ + #define dnsRX_FLAGS_MASK 0x0f80 /* The bits of interest in the flags field of incoming DNS messages. */ + #define dnsEXPECTED_RX_FLAGS 0x0080 /* Should be a response, without any errors. */ +#else + #define dnsDNS_PORT 0x0035 + #define dnsONE_QUESTION 0x0001 + #define dnsOUTGOING_FLAGS 0x0100 /* Standard query. */ + #define dnsRX_FLAGS_MASK 0x800f /* The bits of interest in the flags field of incoming DNS messages. */ + #define dnsEXPECTED_RX_FLAGS 0x8000 /* Should be a response, without any errors. */ + +#endif /* ipconfigBYTE_ORDER */ + +/* The maximum number of times a DNS request should be sent out if a response +is not received, before giving up. */ +#ifndef ipconfigDNS_REQUEST_ATTEMPTS + #define ipconfigDNS_REQUEST_ATTEMPTS 5 +#endif + +/* If the top two bits in the first character of a name field are set then the +name field is an offset to the string, rather than the string itself. */ +#define dnsNAME_IS_OFFSET ( ( uint8_t ) 0xc0 ) + +/* NBNS flags. */ +#define dnsNBNS_FLAGS_RESPONSE 0x8000 +#define dnsNBNS_FLAGS_OPCODE_MASK 0x7800 +#define dnsNBNS_FLAGS_OPCODE_QUERY 0x0000 +#define dnsNBNS_FLAGS_OPCODE_REGISTRATION 0x2800 + +/* Host types. */ +#define dnsTYPE_A_HOST 0x01 +#define dnsCLASS_IN 0x01 + +/* LLMNR constants. */ +#define dnsLLMNR_TTL_VALUE 300000 +#define dnsLLMNR_FLAGS_IS_REPONSE 0x8000 + +/* NBNS constants. */ +#define dnsNBNS_TTL_VALUE 3600 /* 1 hour valid */ +#define dnsNBNS_TYPE_NET_BIOS 0x0020 +#define dnsNBNS_CLASS_IN 0x01 +#define dnsNBNS_NAME_FLAGS 0x6000 +#define dnsNBNS_ENCODED_NAME_LENGTH 32 + +/* If the queried NBNS name matches with the device's name, +the query will be responded to with these flags: */ +#define dnsNBNS_QUERY_RESPONSE_FLAGS ( 0x8500 ) + +/* Flag DNS parsing errors in situations where an IPv4 address is the return +type. */ +#define dnsPARSE_ERROR 0UL + +/* + * Create a socket and bind it to the standard DNS port number. Return the + * the created socket - or NULL if the socket could not be created or bound. + */ +static Socket_t prvCreateDNSSocket( void ); + +/* + * Create the DNS message in the zero copy buffer passed in the first parameter. + */ +static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, const char *pcHostName, TickType_t xIdentifier ); + +/* + * Simple routine that jumps over the NAME field of a resource record. + */ +static uint8_t *prvSkipNameField( uint8_t *pucByte, size_t xSourceLen ); + +/* + * Process a response packet from a DNS server. + */ +static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, TickType_t xIdentifier ); + +/* + * Prepare and send a message to a DNS server. 'xReadTimeOut_ms' will be passed as + * zero, in case the user has supplied a call-back function. + */ +static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier, TickType_t xReadTimeOut_ms ); + +/* + * The NBNS and the LLMNR protocol share this reply function. + */ +#if( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) ) + static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer, BaseType_t lNetLength ); +#endif + +#if( ipconfigUSE_NBNS == 1 ) + static portINLINE void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, uint32_t ulIPAddress ); +#endif /* ipconfigUSE_NBNS */ + +#if( ipconfigUSE_DNS_CACHE == 1 ) + static uint8_t *prvReadNameField( uint8_t *pucByte, size_t xSourceLen, char *pcName, size_t xLen ); + static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, uint32_t ulTTL, BaseType_t xLookUp ); + + typedef struct xDNS_CACHE_TABLE_ROW + { + uint32_t ulIPAddress; /* The IP address of an ARP cache entry. */ + char pcName[ ipconfigDNS_CACHE_NAME_LENGTH ]; /* The name of the host */ + uint32_t ulTTL; /* Time-to-Live (in seconds) from the DNS server. */ + uint32_t ulTimeWhenAddedInSeconds; + } DNSCacheRow_t; + + static DNSCacheRow_t xDNSCache[ ipconfigDNS_CACHE_ENTRIES ]; + + void FreeRTOS_dnsclear() + { + memset( xDNSCache, 0x0, sizeof( xDNSCache ) ); + } +#endif /* ipconfigUSE_DNS_CACHE == 1 */ + +#if( ipconfigUSE_LLMNR == 1 ) + const MACAddress_t xLLMNR_MacAdress = { { 0x01, 0x00, 0x5e, 0x00, 0x00, 0xfc } }; +#endif /* ipconfigUSE_LLMNR == 1 */ + +/*-----------------------------------------------------------*/ + +#include "pack_struct_start.h" +struct xDNSMessage +{ + uint16_t usIdentifier; + uint16_t usFlags; + uint16_t usQuestions; + uint16_t usAnswers; + uint16_t usAuthorityRRs; + uint16_t usAdditionalRRs; +} +#include "pack_struct_end.h" +typedef struct xDNSMessage DNSMessage_t; + +/* A DNS query consists of a header, as described in 'struct xDNSMessage' +It is followed by 1 or more queries, each one consisting of a name and a tail, +with two fields: type and class +*/ +#include "pack_struct_start.h" +struct xDNSTail +{ + uint16_t usType; + uint16_t usClass; +} +#include "pack_struct_end.h" +typedef struct xDNSTail DNSTail_t; + +/* DNS answer record header. */ +#include "pack_struct_start.h" +struct xDNSAnswerRecord +{ + uint16_t usType; + uint16_t usClass; + uint32_t ulTTL; + uint16_t usDataLength; +} +#include "pack_struct_end.h" +typedef struct xDNSAnswerRecord DNSAnswerRecord_t; + +#if( ipconfigUSE_LLMNR == 1 ) + + #include "pack_struct_start.h" + struct xLLMNRAnswer + { + uint8_t ucNameCode; + uint8_t ucNameOffset; /* The name is not repeated in the answer, only the offset is given with "0xc0 " */ + uint16_t usType; + uint16_t usClass; + uint32_t ulTTL; + uint16_t usDataLength; + uint32_t ulIPAddress; + } + #include "pack_struct_end.h" + typedef struct xLLMNRAnswer LLMNRAnswer_t; + +#endif /* ipconfigUSE_LLMNR == 1 */ + +#if( ipconfigUSE_NBNS == 1 ) + + #include "pack_struct_start.h" + struct xNBNSRequest + { + uint16_t usRequestId; + uint16_t usFlags; + uint16_t ulRequestCount; + uint16_t usAnswerRSS; + uint16_t usAuthRSS; + uint16_t usAdditionalRSS; + uint8_t ucNameSpace; + uint8_t ucName[ dnsNBNS_ENCODED_NAME_LENGTH ]; + uint8_t ucNameZero; + uint16_t usType; + uint16_t usClass; + } + #include "pack_struct_end.h" + typedef struct xNBNSRequest NBNSRequest_t; + + #include "pack_struct_start.h" + struct xNBNSAnswer + { + uint16_t usType; + uint16_t usClass; + uint32_t ulTTL; + uint16_t usDataLength; + uint16_t usNbFlags; /* NetBIOS flags 0x6000 : IP-address, big-endian */ + uint32_t ulIPAddress; + } + #include "pack_struct_end.h" + typedef struct xNBNSAnswer NBNSAnswer_t; + +#endif /* ipconfigUSE_NBNS == 1 */ + +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_DNS_CACHE == 1 ) + uint32_t FreeRTOS_dnslookup( const char *pcHostName ) + { + uint32_t ulIPAddress = 0UL; + prvProcessDNSCache( pcHostName, &ulIPAddress, 0, pdTRUE ); + return ulIPAddress; + } +#endif /* ipconfigUSE_DNS_CACHE == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigDNS_USE_CALLBACKS != 0 ) + + typedef struct xDNS_Callback { + TickType_t xRemaningTime; /* Timeout in ms */ + FOnDNSEvent pCallbackFunction; /* Function to be called when the address has been found or when a timeout has beeen reached */ + TimeOut_t xTimeoutState; + void *pvSearchID; + struct xLIST_ITEM xListItem; + char pcName[ 1 ]; + } DNSCallback_t; + + static List_t xCallbackList; + + /* Define FreeRTOS_gethostbyname() as a normal blocking call. */ + uint32_t FreeRTOS_gethostbyname( const char *pcHostName ) + { + return FreeRTOS_gethostbyname_a( pcHostName, ( FOnDNSEvent ) NULL, ( void* )NULL, 0 ); + } + /*-----------------------------------------------------------*/ + + /* Initialise the list of call-back structures. */ + void vDNSInitialise( void ); + void vDNSInitialise( void ) + { + vListInitialise( &xCallbackList ); + } + /*-----------------------------------------------------------*/ + + /* Iterate through the list of call-back structures and remove + old entries which have reached a timeout. + As soon as the list hase become empty, the DNS timer will be stopped + In case pvSearchID is supplied, the user wants to cancel a DNS request + */ + void vDNSCheckCallBack( void *pvSearchID ); + void vDNSCheckCallBack( void *pvSearchID ) + { + const ListItem_t *pxIterator; + const MiniListItem_t* xEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xCallbackList ); + + vTaskSuspendAll(); + { + for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd ); + pxIterator != ( const ListItem_t * ) xEnd; + ) + { + DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + /* Move to the next item because we might remove this item */ + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ); + if( ( pvSearchID != NULL ) && ( pvSearchID == pxCallback->pvSearchID ) ) + { + uxListRemove( &pxCallback->xListItem ); + vPortFree( pxCallback ); + } + else if( xTaskCheckForTimeOut( &pxCallback->xTimeoutState, &pxCallback->xRemaningTime ) != pdFALSE ) + { + pxCallback->pCallbackFunction( pxCallback->pcName, pxCallback->pvSearchID, 0 ); + uxListRemove( &pxCallback->xListItem ); + vPortFree( ( void * ) pxCallback ); + } + } + } + xTaskResumeAll(); + + if( listLIST_IS_EMPTY( &xCallbackList ) ) + { + vIPSetDnsTimerEnableState( pdFALSE ); + } + } + /*-----------------------------------------------------------*/ + + void FreeRTOS_gethostbyname_cancel( void *pvSearchID ) + { + /* _HT_ Should better become a new API call to have the IP-task remove the callback */ + vDNSCheckCallBack( pvSearchID ); + } + /*-----------------------------------------------------------*/ + + /* FreeRTOS_gethostbyname_a() was called along with callback parameters. + Store them in a list for later reference. */ + static void vDNSSetCallBack( const char *pcHostName, void *pvSearchID, FOnDNSEvent pCallbackFunction, TickType_t xTimeout, TickType_t xIdentifier ); + static void vDNSSetCallBack( const char *pcHostName, void *pvSearchID, FOnDNSEvent pCallbackFunction, TickType_t xTimeout, TickType_t xIdentifier ) + { + size_t lLength = strlen( pcHostName ); + DNSCallback_t *pxCallback = ( DNSCallback_t * )pvPortMalloc( sizeof( *pxCallback ) + lLength ); + + /* Translate from ms to number of clock ticks. */ + xTimeout /= portTICK_PERIOD_MS; + if( pxCallback != NULL ) + { + if( listLIST_IS_EMPTY( &xCallbackList ) ) + { + /* This is the first one, start the DNS timer to check for timeouts */ + vIPReloadDNSTimer( FreeRTOS_min_uint32( 1000U, xTimeout ) ); + } + strcpy( pxCallback->pcName, pcHostName ); + pxCallback->pCallbackFunction = pCallbackFunction; + pxCallback->pvSearchID = pvSearchID; + pxCallback->xRemaningTime = xTimeout; + vTaskSetTimeOutState( &pxCallback->xTimeoutState ); + listSET_LIST_ITEM_OWNER( &( pxCallback->xListItem ), ( void* ) pxCallback ); + listSET_LIST_ITEM_VALUE( &( pxCallback->xListItem ), xIdentifier ); + vTaskSuspendAll(); + { + vListInsertEnd( &xCallbackList, &pxCallback->xListItem ); + } + xTaskResumeAll(); + } + } + /*-----------------------------------------------------------*/ + + /* A DNS reply was received, see if there is any matching entry and + call the handler. */ + static void vDNSDoCallback( TickType_t xIdentifier, const char *pcName, uint32_t ulIPAddress ); + static void vDNSDoCallback( TickType_t xIdentifier, const char *pcName, uint32_t ulIPAddress ) + { + const ListItem_t *pxIterator; + const MiniListItem_t* xEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xCallbackList ); + + vTaskSuspendAll(); + { + for( pxIterator = ( const ListItem_t * ) listGET_NEXT( xEnd ); + pxIterator != ( const ListItem_t * ) xEnd; + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + if( listGET_LIST_ITEM_VALUE( pxIterator ) == xIdentifier ) + { + DNSCallback_t *pxCallback = ( DNSCallback_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + pxCallback->pCallbackFunction( pcName, pxCallback->pvSearchID, ulIPAddress ); + uxListRemove( &pxCallback->xListItem ); + vPortFree( pxCallback ); + if( listLIST_IS_EMPTY( &xCallbackList ) ) + { + vIPSetDnsTimerEnableState( pdFALSE ); + } + break; + } + } + } + xTaskResumeAll(); + } + +#endif /* ipconfigDNS_USE_CALLBACKS != 0 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigDNS_USE_CALLBACKS == 0 ) +uint32_t FreeRTOS_gethostbyname( const char *pcHostName ) +#else +uint32_t FreeRTOS_gethostbyname_a( const char *pcHostName, FOnDNSEvent pCallback, void *pvSearchID, TickType_t xTimeout ) +#endif +{ +uint32_t ulIPAddress = 0UL; +TickType_t xReadTimeOut_ms = ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME; +TickType_t xIdentifier = 0; + + /* If the supplied hostname is IP address, convert it to uint32_t + and return. */ + #if( ipconfigINCLUDE_FULL_INET_ADDR == 1 ) + { + ulIPAddress = FreeRTOS_inet_addr( pcHostName ); + } + #endif /* ipconfigINCLUDE_FULL_INET_ADDR == 1 */ + + /* If a DNS cache is used then check the cache before issuing another DNS + request. */ + #if( ipconfigUSE_DNS_CACHE == 1 ) + { + if( ulIPAddress == 0UL ) + { + ulIPAddress = FreeRTOS_dnslookup( pcHostName ); + if( ulIPAddress != 0 ) + { + FreeRTOS_debug_printf( ( "FreeRTOS_gethostbyname: found '%s' in cache: %lxip\n", pcHostName, ulIPAddress ) ); + } + else + { + /* prvGetHostByName will be called to start a DNS lookup */ + } + } + } + #endif /* ipconfigUSE_DNS_CACHE == 1 */ + + /* Generate a unique identifier. */ + if( 0 == ulIPAddress ) + { + xIdentifier = ( TickType_t )ipconfigRAND32( ); + } + + #if( ipconfigDNS_USE_CALLBACKS != 0 ) + { + if( pCallback != NULL ) + { + if( ulIPAddress == 0UL ) + { + /* The user has provided a callback function, so do not block on recvfrom() */ + if( 0 != xIdentifier ) + { + xReadTimeOut_ms = 0; + vDNSSetCallBack( pcHostName, pvSearchID, pCallback, xTimeout, ( TickType_t )xIdentifier ); + } + } + else + { + /* The IP address is known, do the call-back now. */ + pCallback( pcHostName, pvSearchID, ulIPAddress ); + } + } + } + #endif + + if( ( ulIPAddress == 0UL ) && ( 0 != xIdentifier ) ) + { + ulIPAddress = prvGetHostByName( pcHostName, xIdentifier, xReadTimeOut_ms ); + } + + return ulIPAddress; +} +/*-----------------------------------------------------------*/ + +static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier, TickType_t xReadTimeOut_ms ) +{ +struct freertos_sockaddr xAddress; +Socket_t xDNSSocket; +uint32_t ulIPAddress = 0UL; +uint8_t *pucUDPPayloadBuffer; +uint32_t ulAddressLength = sizeof( struct freertos_sockaddr ); +BaseType_t xAttempt; +int32_t lBytes; +size_t xPayloadLength, xExpectedPayloadLength; +TickType_t xWriteTimeOut_ms = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME; + +#if( ipconfigUSE_LLMNR == 1 ) + BaseType_t bHasDot = pdFALSE; +#endif /* ipconfigUSE_LLMNR == 1 */ + + /* If LLMNR is being used then determine if the host name includes a '.' - + if not then LLMNR can be used as the lookup method. */ + #if( ipconfigUSE_LLMNR == 1 ) + { + const char *pucPtr; + for( pucPtr = pcHostName; *pucPtr; pucPtr++ ) + { + if( *pucPtr == '.' ) + { + bHasDot = pdTRUE; + break; + } + } + } + #endif /* ipconfigUSE_LLMNR == 1 */ + + /* Two is added at the end for the count of characters in the first + subdomain part and the string end byte. */ + xExpectedPayloadLength = sizeof( DNSMessage_t ) + strlen( pcHostName ) + sizeof( uint16_t ) + sizeof( uint16_t ) + 2u; + + xDNSSocket = prvCreateDNSSocket(); + + if( xDNSSocket != NULL ) + { + FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xWriteTimeOut_ms, sizeof( TickType_t ) ); + FreeRTOS_setsockopt( xDNSSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xReadTimeOut_ms, sizeof( TickType_t ) ); + + for( xAttempt = 0; xAttempt < ipconfigDNS_REQUEST_ATTEMPTS; xAttempt++ ) + { + /* Get a buffer. This uses a maximum delay, but the delay will be + capped to ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS so the return value + still needs to be tested. */ + pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xExpectedPayloadLength, portMAX_DELAY ); + + if( pucUDPPayloadBuffer != NULL ) + { + /* Create the message in the obtained buffer. */ + xPayloadLength = prvCreateDNSMessage( pucUDPPayloadBuffer, pcHostName, xIdentifier ); + + iptraceSENDING_DNS_REQUEST(); + + /* Obtain the DNS server address. */ + FreeRTOS_GetAddressConfiguration( NULL, NULL, NULL, &ulIPAddress ); + + /* Send the DNS message. */ +#if( ipconfigUSE_LLMNR == 1 ) + if( bHasDot == pdFALSE ) + { + /* Use LLMNR addressing. */ + ( ( DNSMessage_t * ) pucUDPPayloadBuffer) -> usFlags = 0; + xAddress.sin_addr = ipLLMNR_IP_ADDR; /* Is in network byte order. */ + xAddress.sin_port = FreeRTOS_ntohs( ipLLMNR_PORT ); + } + else +#endif + { + /* Use DNS server. */ + xAddress.sin_addr = ulIPAddress; + xAddress.sin_port = dnsDNS_PORT; + } + + ulIPAddress = 0UL; + + if( FreeRTOS_sendto( xDNSSocket, pucUDPPayloadBuffer, xPayloadLength, FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) != 0 ) + { + /* Wait for the reply. */ + lBytes = FreeRTOS_recvfrom( xDNSSocket, &pucUDPPayloadBuffer, 0, FREERTOS_ZERO_COPY, &xAddress, &ulAddressLength ); + + if( lBytes > 0 ) + { + /* The reply was received. Process it. */ + ulIPAddress = prvParseDNSReply( pucUDPPayloadBuffer, lBytes, xIdentifier ); + + /* Finished with the buffer. The zero copy interface + is being used, so the buffer must be freed by the + task. */ + FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer ); + + if( ulIPAddress != 0UL ) + { + /* All done. */ + break; + } + } + } + else + { + /* The message was not sent so the stack will not be + releasing the zero copy - it must be released here. */ + FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayloadBuffer ); + } + } + } + + /* Finished with the socket. */ + FreeRTOS_closesocket( xDNSSocket ); + } + + return ulIPAddress; +} +/*-----------------------------------------------------------*/ + +static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, const char *pcHostName, TickType_t xIdentifier ) +{ +DNSMessage_t *pxDNSMessageHeader; +uint8_t *pucStart, *pucByte; +DNSTail_t *pxTail; +static const DNSMessage_t xDefaultPartDNSHeader = +{ + 0, /* The identifier will be overwritten. */ + dnsOUTGOING_FLAGS, /* Flags set for standard query. */ + dnsONE_QUESTION, /* One question is being asked. */ + 0, /* No replies are included. */ + 0, /* No authorities. */ + 0 /* No additional authorities. */ +}; + + /* Copy in the const part of the header. */ + memcpy( ( void * ) pucUDPPayloadBuffer, ( void * ) &xDefaultPartDNSHeader, sizeof( xDefaultPartDNSHeader ) ); + + /* Write in a unique identifier. */ + pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer; + pxDNSMessageHeader->usIdentifier = ( uint16_t ) xIdentifier; + + /* Create the resource record at the end of the header. First + find the end of the header. */ + pucStart = pucUDPPayloadBuffer + sizeof( xDefaultPartDNSHeader ); + + /* Leave a gap for the first length bytes. */ + pucByte = pucStart + 1; + + /* Copy in the host name. */ + strcpy( ( char * ) pucByte, pcHostName ); + + /* Mark the end of the string. */ + pucByte += strlen( pcHostName ); + *pucByte = 0x00u; + + /* Walk the string to replace the '.' characters with byte counts. + pucStart holds the address of the byte count. Walking the string + starts after the byte count position. */ + pucByte = pucStart; + + do + { + pucByte++; + + while( ( *pucByte != 0x00 ) && ( *pucByte != '.' ) ) + { + pucByte++; + } + + /* Fill in the byte count, then move the pucStart pointer up to + the found byte position. */ + *pucStart = ( uint8_t ) ( ( uint32_t ) pucByte - ( uint32_t ) pucStart ); + ( *pucStart )--; + + pucStart = pucByte; + + } while( *pucByte != 0x00 ); + + /* Finish off the record. */ + + pxTail = (DNSTail_t *)( pucByte + 1 ); + + vSetField16( pxTail, DNSTail_t, usType, dnsTYPE_A_HOST ); /* Type A: host */ + vSetField16( pxTail, DNSTail_t, usClass, dnsCLASS_IN ); /* 1: Class IN */ + + /* Return the total size of the generated message, which is the space from + the last written byte to the beginning of the buffer. */ + return ( ( uint32_t ) pucByte - ( uint32_t ) pucUDPPayloadBuffer + 1 ) + sizeof( *pxTail ); +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_DNS_CACHE == 1 ) + + static uint8_t *prvReadNameField( uint8_t *pucByte, size_t xSourceLen, char *pcName, size_t xDestLen ) + { + size_t xNameLen = 0; + BaseType_t xCount; + + if( 0 == xSourceLen ) + { + return NULL; + } + + /* Determine if the name is the fully coded name, or an offset to the name + elsewhere in the message. */ + if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET ) + { + /* Jump over the two byte offset. */ + if( xSourceLen > sizeof( uint16_t ) ) + { + pucByte += sizeof( uint16_t ); + } + else + { + pucByte = NULL; + } + } + else + { + /* pucByte points to the full name. Walk over the string. */ + while( ( NULL != pucByte ) && ( *pucByte != 0x00 ) && ( xSourceLen > 1 ) ) + { + /* If this is not the first time through the loop, then add a + separator in the output. */ + if( ( xNameLen > 0 ) && ( xNameLen < ( xDestLen - 1 ) ) ) + { + pcName[ xNameLen++ ] = '.'; + } + + /* Process the first/next sub-string. */ + for( xCount = *(pucByte++), xSourceLen--; + xCount-- && xSourceLen > 1; + pucByte++, xSourceLen-- ) + { + if( xNameLen < xDestLen - 1 ) + { + pcName[ xNameLen++ ] = *( ( char * )pucByte ); + } + else + { + /* DNS name is too big for the provided buffer. */ + pucByte = NULL; + break; + } + } + } + + /* Confirm that a fully formed name was found. */ + if( NULL != pucByte ) + { + if( 0x00 == *pucByte ) + { + pucByte++; + xSourceLen--; + pcName[ xNameLen++ ] = '\0'; + } + else + { + pucByte = NULL; + } + } + } + + return pucByte; + } +#endif /* ipconfigUSE_DNS_CACHE == 1 */ +/*-----------------------------------------------------------*/ + +static uint8_t *prvSkipNameField( uint8_t *pucByte, size_t xSourceLen ) +{ + size_t xChunkLength; + + if( 0 == xSourceLen ) + { + return NULL; + } + + /* Determine if the name is the fully coded name, or an offset to the name + elsewhere in the message. */ + if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET ) + { + /* Jump over the two byte offset. */ + if( xSourceLen > sizeof( uint16_t ) ) + { + pucByte += sizeof( uint16_t ); + } + else + { + pucByte = NULL; + } + } + else + { + /* pucByte points to the full name. Walk over the string. */ + while( ( *pucByte != 0x00 ) && ( xSourceLen > 1 ) ) + { + xChunkLength = *pucByte + 1; + + if( xSourceLen > xChunkLength ) + { + xSourceLen -= xChunkLength; + pucByte += xChunkLength; + } + else + { + pucByte = NULL; + break; + } + } + + /* Confirm that a fully formed name was found. */ + if( NULL != pucByte ) + { + if( 0x00 == *pucByte ) + { + pucByte++; + } + else + { + pucByte = NULL; + } + } + } + + return pucByte; +} +/*-----------------------------------------------------------*/ + +uint32_t ulDNSHandlePacket( NetworkBufferDescriptor_t *pxNetworkBuffer ) +{ +DNSMessage_t *pxDNSMessageHeader; + + if( pxNetworkBuffer->xDataLength >= sizeof( DNSMessage_t ) ) + { + pxDNSMessageHeader = + ( DNSMessage_t * )( pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t ) ); + + prvParseDNSReply( ( uint8_t * )pxDNSMessageHeader, + pxNetworkBuffer->xDataLength, + ( uint32_t )pxDNSMessageHeader->usIdentifier ); + } + + /* The packet was not consumed. */ + return pdFAIL; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_NBNS == 1 ) + + uint32_t ulNBNSHandlePacket (NetworkBufferDescriptor_t *pxNetworkBuffer ) + { + UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer; + uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t ); + + /* The network buffer data length has already been set to the + length of the UDP payload. */ + prvTreatNBNS( pucUDPPayloadBuffer, + pxNetworkBuffer->xDataLength, + pxUDPPacket->xIPHeader.ulSourceIPAddress ); + + /* The packet was not consumed. */ + return pdFAIL; + } + +#endif /* ipconfigUSE_NBNS */ +/*-----------------------------------------------------------*/ + +static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, TickType_t xIdentifier ) +{ +DNSMessage_t *pxDNSMessageHeader; +DNSAnswerRecord_t *pxDNSAnswerRecord; +uint32_t ulIPAddress = 0UL; +#if( ipconfigUSE_LLMNR == 1 ) + char *pcRequestedName = NULL; +#endif +uint8_t *pucByte; +size_t xSourceBytesRemaining; +uint16_t x, usDataLength, usQuestions; +#if( ipconfigUSE_LLMNR == 1 ) + uint16_t usType = 0, usClass = 0; +#endif +#if( ipconfigUSE_DNS_CACHE == 1 ) + char pcName[ ipconfigDNS_CACHE_NAME_LENGTH ] = ""; +#endif + + /* Ensure that the buffer is of at least minimal DNS message length. */ + if( xBufferLength < sizeof( DNSMessage_t ) ) + { + return dnsPARSE_ERROR; + } + else + { + xSourceBytesRemaining = xBufferLength; + } + + /* Parse the DNS message header. */ + pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer; + + if( pxDNSMessageHeader->usIdentifier == ( uint16_t ) xIdentifier ) + { + /* Start at the first byte after the header. */ + pucByte = pucUDPPayloadBuffer + sizeof( DNSMessage_t ); + xSourceBytesRemaining -= sizeof( DNSMessage_t ); + + /* Skip any question records. */ + usQuestions = FreeRTOS_ntohs( pxDNSMessageHeader->usQuestions ); + for( x = 0; x < usQuestions; x++ ) + { + #if( ipconfigUSE_LLMNR == 1 ) + { + if( x == 0 ) + { + pcRequestedName = ( char * ) pucByte; + } + } + #endif + +#if( ipconfigUSE_DNS_CACHE == 1 ) + if( x == 0 ) + { + pucByte = prvReadNameField( pucByte, + xSourceBytesRemaining, + pcName, + sizeof( pcName ) ); + + /* Check for a malformed response. */ + if( NULL == pucByte ) + { + return dnsPARSE_ERROR; + } + else + { + xSourceBytesRemaining = ( pucUDPPayloadBuffer + xBufferLength ) - pucByte; + } + } + else +#endif /* ipconfigUSE_DNS_CACHE */ + { + /* Skip the variable length pcName field. */ + pucByte = prvSkipNameField( pucByte, + xSourceBytesRemaining ); + + /* Check for a malformed response. */ + if( NULL == pucByte ) + { + return dnsPARSE_ERROR; + } + else + { + xSourceBytesRemaining = pucUDPPayloadBuffer + xBufferLength - pucByte; + } + } + + /* Check the remaining buffer size. */ + if( xSourceBytesRemaining >= sizeof( uint32_t ) ) + { + #if( ipconfigUSE_LLMNR == 1 ) + { + /* usChar2u16 returns value in host endianness */ + usType = usChar2u16( pucByte ); + usClass = usChar2u16( pucByte + 2 ); + } + #endif /* ipconfigUSE_LLMNR */ + + /* Skip the type and class fields. */ + pucByte += sizeof( uint32_t ); + xSourceBytesRemaining -= sizeof( uint32_t ); + } + else + { + /* Malformed response. */ + return dnsPARSE_ERROR; + } + } + + /* Search through the answer records. */ + pxDNSMessageHeader->usAnswers = FreeRTOS_ntohs( pxDNSMessageHeader->usAnswers ); + + if( ( pxDNSMessageHeader->usFlags & dnsRX_FLAGS_MASK ) == dnsEXPECTED_RX_FLAGS ) + { + for( x = 0; x < pxDNSMessageHeader->usAnswers; x++ ) + { + pucByte = prvSkipNameField( pucByte, + xSourceBytesRemaining ); + + /* Check for a malformed response. */ + if( NULL == pucByte ) + { + return dnsPARSE_ERROR; + } + else + { + xSourceBytesRemaining = pucUDPPayloadBuffer + xBufferLength - pucByte; + } + + /* Is there enough data for an IPv4 A record answer and, if so, + is this an A record? */ + if( xSourceBytesRemaining >= sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ) && + usChar2u16( pucByte ) == dnsTYPE_A_HOST ) + { + /* This is the required record type and is of sufficient size. */ + pxDNSAnswerRecord = ( DNSAnswerRecord_t * )pucByte; + + /* Sanity check the data length of an IPv4 answer. */ + if( FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength ) == sizeof( uint32_t ) ) + { + /* Copy the IP address out of the record. */ + memcpy( &ulIPAddress, + pucByte + sizeof( DNSAnswerRecord_t ), + sizeof( uint32_t ) ); + + #if( ipconfigUSE_DNS_CACHE == 1 ) + { + prvProcessDNSCache( pcName, &ulIPAddress, pxDNSAnswerRecord->ulTTL, pdFALSE ); + } + #endif /* ipconfigUSE_DNS_CACHE */ + #if( ipconfigDNS_USE_CALLBACKS != 0 ) + { + /* See if any asynchronous call was made to FreeRTOS_gethostbyname_a() */ + vDNSDoCallback( ( TickType_t ) pxDNSMessageHeader->usIdentifier, pcName, ulIPAddress ); + } + #endif /* ipconfigDNS_USE_CALLBACKS != 0 */ + } + + pucByte += sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ); + xSourceBytesRemaining -= ( sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ) ); + break; + } + else if( xSourceBytesRemaining >= sizeof( DNSAnswerRecord_t ) ) + { + /* It's not an A record, so skip it. Get the header location + and then jump over the header. */ + pxDNSAnswerRecord = ( DNSAnswerRecord_t * )pucByte; + pucByte += sizeof( DNSAnswerRecord_t ); + xSourceBytesRemaining -= sizeof( DNSAnswerRecord_t ); + + /* Determine the length of the answer data from the header. */ + usDataLength = FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength ); + + /* Jump over the answer. */ + if( xSourceBytesRemaining >= usDataLength ) + { + pucByte += usDataLength; + xSourceBytesRemaining -= usDataLength; + } + else + { + /* Malformed response. */ + return dnsPARSE_ERROR; + } + } + } + } +#if( ipconfigUSE_LLMNR == 1 ) + else if( usQuestions && ( usType == dnsTYPE_A_HOST ) && ( usClass == dnsCLASS_IN ) ) + { + /* If this is not a reply to our DNS request, it might an LLMNR + request. */ + if( xApplicationDNSQueryHook ( ( pcRequestedName + 1 ) ) ) + { + int16_t usLength; + NetworkBufferDescriptor_t *pxNewBuffer = NULL; + NetworkBufferDescriptor_t *pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer ); + LLMNRAnswer_t *pxAnswer; + + if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) ) + { + BaseType_t xDataLength = xBufferLength + sizeof( UDPHeader_t ) + sizeof( EthernetHeader_t ) + sizeof( IPHeader_t ); + + /* The field xDataLength was set to the length of the UDP payload. + The answer (reply) will be longer than the request, so the packet + must be duplicaed into a bigger buffer */ + pxNetworkBuffer->xDataLength = xDataLength; + pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + 16 ); + if( pxNewBuffer != NULL ) + { + BaseType_t xOffset1, xOffset2; + + xOffset1 = ( BaseType_t ) ( pucByte - pucUDPPayloadBuffer ); + xOffset2 = ( BaseType_t ) ( ( ( uint8_t * ) pcRequestedName ) - pucUDPPayloadBuffer ); + + pxNetworkBuffer = pxNewBuffer; + pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + ipUDP_PAYLOAD_OFFSET_IPv4; + + pucByte = pucUDPPayloadBuffer + xOffset1; + pcRequestedName = ( char * ) ( pucUDPPayloadBuffer + xOffset2 ); + pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer; + + } + else + { + /* Just to indicate that the message may not be answered. */ + pxNetworkBuffer = NULL; + } + } + if( pxNetworkBuffer != NULL ) + { + pxAnswer = (LLMNRAnswer_t *)pucByte; + + /* We leave 'usIdentifier' and 'usQuestions' untouched */ + vSetField16( pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_REPONSE ); /* Set the response flag */ + vSetField16( pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 ); /* Provide a single answer */ + vSetField16( pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 ); /* No authority */ + vSetField16( pxDNSMessageHeader, DNSMessage_t, usAdditionalRRs, 0 ); /* No additional info */ + + pxAnswer->ucNameCode = dnsNAME_IS_OFFSET; + pxAnswer->ucNameOffset = ( uint8_t )( pcRequestedName - ( char * ) pucUDPPayloadBuffer ); + + vSetField16( pxAnswer, LLMNRAnswer_t, usType, dnsTYPE_A_HOST ); /* Type A: host */ + vSetField16( pxAnswer, LLMNRAnswer_t, usClass, dnsCLASS_IN ); /* 1: Class IN */ + vSetField32( pxAnswer, LLMNRAnswer_t, ulTTL, dnsLLMNR_TTL_VALUE ); + vSetField16( pxAnswer, LLMNRAnswer_t, usDataLength, 4 ); + vSetField32( pxAnswer, LLMNRAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) ); + + usLength = ( int16_t ) ( sizeof( *pxAnswer ) + ( size_t ) ( pucByte - pucUDPPayloadBuffer ) ); + + prvReplyDNSMessage( pxNetworkBuffer, usLength ); + + if( pxNewBuffer != NULL ) + { + vReleaseNetworkBufferAndDescriptor( pxNewBuffer ); + } + } + } + } +#endif /* ipconfigUSE_LLMNR == 1 */ + } + + return ulIPAddress; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_NBNS == 1 ) + + static void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, uint32_t ulIPAddress ) + { + uint16_t usFlags, usType, usClass; + uint8_t *pucSource, *pucTarget; + uint8_t ucByte; + uint8_t ucNBNSName[ 17 ]; + + /* Check for minimum buffer size. */ + if( xBufferLength < sizeof( NBNSRequest_t ) ) + { + return; + } + + /* Read the request flags in host endianness. */ + usFlags = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usFlags ) ); + + if( ( usFlags & dnsNBNS_FLAGS_OPCODE_MASK ) == dnsNBNS_FLAGS_OPCODE_QUERY ) + { + usType = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) ); + usClass = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usClass ) ); + + /* Not used for now */ + ( void )usClass; + /* For NBNS a name is 16 bytes long, written with capitals only. + Make sure that the copy is terminated with a zero. */ + pucTarget = ucNBNSName + sizeof(ucNBNSName ) - 2; + pucTarget[ 1 ] = '\0'; + + /* Start with decoding the last 2 bytes. */ + pucSource = pucUDPPayloadBuffer + ( offsetof( NBNSRequest_t, ucName ) + ( dnsNBNS_ENCODED_NAME_LENGTH - 2 ) ); + + for( ;; ) + { + ucByte = ( uint8_t ) ( ( ( pucSource[ 0 ] - 0x41 ) << 4 ) | ( pucSource[ 1 ] - 0x41 ) ); + + /* Make sure there are no trailing spaces in the name. */ + if( ( ucByte == ' ' ) && ( pucTarget[ 1 ] == '\0' ) ) + { + ucByte = '\0'; + } + + *pucTarget = ucByte; + + if( pucTarget == ucNBNSName ) + { + break; + } + + pucTarget -= 1; + pucSource -= 2; + } + + #if( ipconfigUSE_DNS_CACHE == 1 ) + { + if( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) != 0 ) + { + /* If this is a response from another device, + add the name to the DNS cache */ + prvProcessDNSCache( ( char * ) ucNBNSName, &ulIPAddress, 0, pdFALSE ); + } + } + #else + { + /* Avoid compiler warnings. */ + ( void ) ulIPAddress; + } + #endif /* ipconfigUSE_DNS_CACHE */ + + if( ( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) == 0 ) && + ( usType == dnsNBNS_TYPE_NET_BIOS ) && + ( xApplicationDNSQueryHook( ( const char * ) ucNBNSName ) != pdFALSE ) ) + { + uint16_t usLength; + DNSMessage_t *pxMessage; + NBNSAnswer_t *pxAnswer; + + /* Someone is looking for a device with ucNBNSName, + prepare a positive reply. */ + NetworkBufferDescriptor_t *pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer ); + + if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) ) + { + NetworkBufferDescriptor_t *pxNewBuffer; + BaseType_t xDataLength = pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) + + sizeof( EthernetHeader_t ) + sizeof( IPHeader_t ); + + /* The field xDataLength was set to the length of the UDP payload. + The answer (reply) will be longer than the request, so the packet + must be duplicated into a bigger buffer */ + pxNetworkBuffer->xDataLength = xDataLength; + pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, xDataLength + 16 ); + if( pxNewBuffer != NULL ) + { + pucUDPPayloadBuffer = pxNewBuffer->pucEthernetBuffer + sizeof( UDPPacket_t ); + pxNetworkBuffer = pxNewBuffer; + } + else + { + /* Just prevent that a reply will be sent */ + pxNetworkBuffer = NULL; + } + } + + /* Should not occur: pucUDPPayloadBuffer is part of a xNetworkBufferDescriptor */ + if( pxNetworkBuffer != NULL ) + { + pxMessage = (DNSMessage_t *)pucUDPPayloadBuffer; + + /* As the fields in the structures are not word-aligned, we have to + copy the values byte-by-byte using macro's vSetField16() and vSetField32() */ + vSetField16( pxMessage, DNSMessage_t, usFlags, dnsNBNS_QUERY_RESPONSE_FLAGS ); /* 0x8500 */ + vSetField16( pxMessage, DNSMessage_t, usQuestions, 0 ); + vSetField16( pxMessage, DNSMessage_t, usAnswers, 1 ); + vSetField16( pxMessage, DNSMessage_t, usAuthorityRRs, 0 ); + vSetField16( pxMessage, DNSMessage_t, usAdditionalRRs, 0 ); + + pxAnswer = (NBNSAnswer_t *)( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usType ) ); + + vSetField16( pxAnswer, NBNSAnswer_t, usType, usType ); /* Type */ + vSetField16( pxAnswer, NBNSAnswer_t, usClass, dnsNBNS_CLASS_IN ); /* Class */ + vSetField32( pxAnswer, NBNSAnswer_t, ulTTL, dnsNBNS_TTL_VALUE ); + vSetField16( pxAnswer, NBNSAnswer_t, usDataLength, 6 ); /* 6 bytes including the length field */ + vSetField16( pxAnswer, NBNSAnswer_t, usNbFlags, dnsNBNS_NAME_FLAGS ); + vSetField32( pxAnswer, NBNSAnswer_t, ulIPAddress, FreeRTOS_ntohl( *ipLOCAL_IP_ADDRESS_POINTER ) ); + + usLength = ( uint16_t ) ( offsetof( NBNSRequest_t, usType ) + sizeof( NBNSAnswer_t ) ); + + prvReplyDNSMessage( pxNetworkBuffer, usLength ); + } + } + } + } + +#endif /* ipconfigUSE_NBNS */ +/*-----------------------------------------------------------*/ + +static Socket_t prvCreateDNSSocket( void ) +{ +Socket_t xSocket = NULL; +struct freertos_sockaddr xAddress; +BaseType_t xReturn; +TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 ); + + /* This must be the first time this function has been called. Create + the socket. */ + xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP ); + + /* Auto bind the port. */ + xAddress.sin_port = 0u; + xReturn = FreeRTOS_bind( xSocket, &xAddress, sizeof( xAddress ) ); + + /* Check the bind was successful, and clean up if not. */ + if( xReturn != 0 ) + { + FreeRTOS_closesocket( xSocket ); + xSocket = NULL; + } + else + { + /* Set the send and receive timeouts. */ + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) ); + FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) ); + } + + return xSocket; +} +/*-----------------------------------------------------------*/ + +#if( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) ) + + static void prvReplyDNSMessage( NetworkBufferDescriptor_t *pxNetworkBuffer, BaseType_t lNetLength ) + { + UDPPacket_t *pxUDPPacket; + IPHeader_t *pxIPHeader; + UDPHeader_t *pxUDPHeader; + + pxUDPPacket = (UDPPacket_t *) pxNetworkBuffer->pucEthernetBuffer; + pxIPHeader = &pxUDPPacket->xIPHeader; + pxUDPHeader = &pxUDPPacket->xUDPHeader; + /* HT: started using defines like 'ipSIZE_OF_xxx' */ + pxIPHeader->usLength = FreeRTOS_htons( lNetLength + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER ); + /* HT:endian: should not be translated, copying from packet to packet */ + pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress; + pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER; + pxIPHeader->ucTimeToLive = ipconfigUDP_TIME_TO_LIVE; + pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier ); + usPacketIdentifier++; + pxUDPHeader->usLength = FreeRTOS_htons( lNetLength + ipSIZE_OF_UDP_HEADER ); + vFlip_16( pxUDPPacket->xUDPHeader.usSourcePort, pxUDPPacket->xUDPHeader.usDestinationPort ); + + /* Important: tell NIC driver how many bytes must be sent */ + pxNetworkBuffer->xDataLength = ( size_t ) ( lNetLength + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_UDP_HEADER + ipSIZE_OF_ETH_HEADER ); + + #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) + { + /* calculate the IP header checksum */ + pxIPHeader->usHeaderChecksum = 0x00; + pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER ); + pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); + + /* calculate the UDP checksum for outgoing package */ + usGenerateProtocolChecksum( ( uint8_t* ) pxUDPPacket, pxNetworkBuffer->xDataLength, pdTRUE ); + } + #endif + + /* This function will fill in the eth addresses and send the packet */ + vReturnEthernetFrame( pxNetworkBuffer, pdFALSE ); + } + +#endif /* ipconfigUSE_NBNS == 1 || ipconfigUSE_LLMNR == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_DNS_CACHE == 1 ) + + static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, uint32_t ulTTL, BaseType_t xLookUp ) + { + BaseType_t x; + BaseType_t xFound = pdFALSE; + uint32_t ulCurrentTimeSeconds = ( xTaskGetTickCount() / portTICK_PERIOD_MS ) / 1000; + static BaseType_t xFreeEntry = 0; + configASSERT(pcName); + + + /* For each entry in the DNS cache table. */ + for( x = 0; x < ipconfigDNS_CACHE_ENTRIES; x++ ) + { + if( xDNSCache[ x ].pcName[ 0 ] == 0 ) + { + continue; + } + + if( 0 == strcmp( xDNSCache[ x ].pcName, pcName ) ) + { + /* Is this function called for a lookup or to add/update an IP address? */ + if( xLookUp != pdFALSE ) + { + /* Confirm that the record is still fresh. */ + if( ulCurrentTimeSeconds < ( xDNSCache[ x ].ulTimeWhenAddedInSeconds + FreeRTOS_ntohl( xDNSCache[ x ].ulTTL ) ) ) + { + *pulIP = xDNSCache[ x ].ulIPAddress; + } + else + { + /* Age out the old cached record. */ + xDNSCache[ x ].pcName[ 0 ] = 0; + } + } + else + { + xDNSCache[ x ].ulIPAddress = *pulIP; + xDNSCache[ x ].ulTTL = ulTTL; + xDNSCache[ x ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds; + } + + xFound = pdTRUE; + break; + } + } + + if( xFound == pdFALSE ) + { + if( xLookUp != pdFALSE ) + { + *pulIP = 0; + } + else + { + /* Add or update the item. */ + if( strlen( pcName ) < ipconfigDNS_CACHE_NAME_LENGTH ) + { + strcpy( xDNSCache[ xFreeEntry ].pcName, pcName ); + + xDNSCache[ xFreeEntry ].ulIPAddress = *pulIP; + xDNSCache[ xFreeEntry ].ulTTL = ulTTL; + xDNSCache[ xFreeEntry ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds; + + xFreeEntry++; + if( xFreeEntry == ipconfigDNS_CACHE_ENTRIES ) + { + xFreeEntry = 0; + } + } + } + } + + if( ( xLookUp == 0 ) || ( *pulIP != 0 ) ) + { + FreeRTOS_debug_printf( ( "prvProcessDNSCache: %s: '%s' @ %lxip\n", xLookUp ? "look-up" : "add", pcName, FreeRTOS_ntohl( *pulIP ) ) ); + } + } + +#endif /* ipconfigUSE_DNS_CACHE */ + +#endif /* ipconfigUSE_DNS != 0 */ + +/*-----------------------------------------------------------*/ + +/* Provide access to private members for testing. */ +#ifdef AMAZON_FREERTOS_ENABLE_UNIT_TESTS + #include "iot_freertos_tcp_test_access_dns_define.h" +#endif + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c new file mode 100644 index 000000000..d6c36f31c --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c @@ -0,0 +1,2324 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_ARP.h" +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_TCP_IP.h" +#include "FreeRTOS_DHCP.h" +#include "NetworkInterface.h" +#include "NetworkBufferManagement.h" +#include "FreeRTOS_DNS.h" + + +/* Used to ensure the structure packing is having the desired effect. The +'volatile' is used to prevent compiler warnings about comparing a constant with +a constant. */ +#define ipEXPECTED_EthernetHeader_t_SIZE ( ( size_t ) 14 ) +#define ipEXPECTED_ARPHeader_t_SIZE ( ( size_t ) 28 ) +#define ipEXPECTED_IPHeader_t_SIZE ( ( size_t ) 20 ) +#define ipEXPECTED_IGMPHeader__SIZE ( ( size_t ) 8 ) +#define ipEXPECTED_ICMPHeader_t_SIZE ( ( size_t ) 8 ) +#define ipEXPECTED_UDPHeader_t_SIZE ( ( size_t ) 8 ) +#define ipEXPECTED_TCPHeader_t_SIZE ( ( size_t ) 20 ) + + +/* ICMP protocol definitions. */ +#define ipICMP_ECHO_REQUEST ( ( uint8_t ) 8 ) +#define ipICMP_ECHO_REPLY ( ( uint8_t ) 0 ) + + +/* Time delay between repeated attempts to initialise the network hardware. */ +#define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000 ) ) + +/* Defines how often the ARP timer callback function is executed. The time is +shorted in the Windows simulator as simulated time is not real time. */ +#ifndef ipARP_TIMER_PERIOD_MS + #ifdef _WINDOWS_ + #define ipARP_TIMER_PERIOD_MS ( 500 ) /* For windows simulator builds. */ + #else + #define ipARP_TIMER_PERIOD_MS ( 10000 ) + #endif +#endif + +#ifndef iptraceIP_TASK_STARTING + #define iptraceIP_TASK_STARTING() do {} while( 0 ) +#endif + +#if( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) ) + /* When initialising the TCP timer, + give it an initial time-out of 1 second. */ + #define ipTCP_TIMER_PERIOD_MS ( 1000 ) +#endif + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet +driver will filter incoming packets and only pass the stack those packets it +considers need processing. In this case ipCONSIDER_FRAME_FOR_PROCESSING() can +be #defined away. If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0 +then the Ethernet driver will pass all received packets to the stack, and the +stack must do the filtering itself. In this case ipCONSIDER_FRAME_FOR_PROCESSING +needs to call eConsiderFrameForProcessing. */ +#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) ) +#else + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer +#endif + +/* The character used to fill ICMP echo requests, and therefore also the +character expected to fill ICMP echo replies. */ +#define ipECHO_DATA_FILL_BYTE 'x' + +#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) + /* The bits in the two byte IP header field that make up the fragment offset value. */ + #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0xff0f ) +#else + /* The bits in the two byte IP header field that make up the fragment offset value. */ + #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff ) +#endif /* ipconfigBYTE_ORDER */ + +/* The maximum time the IP task is allowed to remain in the Blocked state if no +events are posted to the network event queue. */ +#ifndef ipconfigMAX_IP_TASK_SLEEP_TIME + #define ipconfigMAX_IP_TASK_SLEEP_TIME ( pdMS_TO_TICKS( 10000UL ) ) +#endif + +/* When a new TCP connection is established, the value of +'ulNextInitialSequenceNumber' will be used as the initial sequence number. It +is very important that at start-up, 'ulNextInitialSequenceNumber' contains a +random value. Also its value must be increased continuously in time, to prevent +a third party guessing the next sequence number and take-over a TCP connection. +It is advised to increment it by 1 ever 4us, which makes about 256 times +per ms: */ +#define ipINITIAL_SEQUENCE_NUMBER_FACTOR 256UL + +/* Returned as the (invalid) checksum when the protocol being checked is not +handled. The value is chosen simply to be easy to spot when debugging. */ +#define ipUNHANDLED_PROTOCOL 0x4321u + +/* Returned to indicate a valid checksum when the checksum does not need to be +calculated. */ +#define ipCORRECT_CRC 0xffffu + +/* Returned as the (invalid) checksum when the length of the data being checked +had an invalid length. */ +#define ipINVALID_LENGTH 0x1234u + +/*-----------------------------------------------------------*/ + +typedef struct xIP_TIMER +{ + uint32_t + bActive : 1, /* This timer is running and must be processed. */ + bExpired : 1; /* Timer has expired and a task must be processed. */ + TimeOut_t xTimeOut; + TickType_t ulRemainingTime; + TickType_t ulReloadTime; +} IPTimer_t; + +/* Used in checksum calculation. */ +typedef union _xUnion32 +{ + uint32_t u32; + uint16_t u16[ 2 ]; + uint8_t u8[ 4 ]; +} xUnion32; + +/* Used in checksum calculation. */ +typedef union _xUnionPtr +{ + uint32_t *u32ptr; + uint16_t *u16ptr; + uint8_t *u8ptr; +} xUnionPtr; + +/*-----------------------------------------------------------*/ + +/* + * The main TCP/IP stack processing task. This task receives commands/events + * from the network hardware drivers and tasks that are using sockets. It also + * maintains a set of protocol timers. + */ +static void prvIPTask( void *pvParameters ); + +/* + * Called when new data is available from the network interface. + */ +static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer ); + +/* + * Process incoming IP packets. + */ +static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer ); + +#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + /* + * Process incoming ICMP packets. + */ + static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket ); +#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */ + +/* + * Turns around an incoming ping request to convert it into a ping reply. + */ +#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) + static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket ); +#endif /* ipconfigREPLY_TO_INCOMING_PINGS */ + +/* + * Processes incoming ping replies. The application callback function + * vApplicationPingReplyHook() is called with the results. + */ +#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket ); +#endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + +/* + * Called to create a network connection when the stack is first started, or + * when the network connection is lost. + */ +static void prvProcessNetworkDownEvent( void ); + +/* + * Checks the ARP, DHCP and TCP timers to see if any periodic or timeout + * processing is required. + */ +static void prvCheckNetworkTimers( void ); + +/* + * Determine how long the IP task can sleep for, which depends on when the next + * periodic or timeout processing must be performed. + */ +static TickType_t prvCalculateSleepTime( void ); + +/* + * The network card driver has received a packet. In the case that it is part + * of a linked packet chain, walk through it to handle every message. + */ +static void prvHandleEthernetPacket( NetworkBufferDescriptor_t *pxBuffer ); + +/* + * Utility functions for the light weight IP timers. + */ +static void prvIPTimerStart( IPTimer_t *pxTimer, TickType_t xTime ); +static BaseType_t prvIPTimerCheck( IPTimer_t *pxTimer ); +static void prvIPTimerReload( IPTimer_t *pxTimer, TickType_t xTime ); + +static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket, + NetworkBufferDescriptor_t * const pxNetworkBuffer, UBaseType_t uxHeaderLength ); + +/*-----------------------------------------------------------*/ + +/* The queue used to pass events into the IP-task for processing. */ +QueueHandle_t xNetworkEventQueue = NULL; + +/*_RB_ Requires comment. */ +uint16_t usPacketIdentifier = 0U; + +/* For convenience, a MAC address of all 0xffs is defined const for quick +reference. */ +const MACAddress_t xBroadcastMACAddress = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } }; + +/* Structure that stores the netmask, gateway address and DNS server addresses. */ +NetworkAddressingParameters_t xNetworkAddressing = { 0, 0, 0, 0, 0 }; + +/* Default values for the above struct in case DHCP +does not lead to a confirmed request. */ +NetworkAddressingParameters_t xDefaultAddressing = { 0, 0, 0, 0, 0 }; + +/* Used to ensure network down events cannot be missed when they cannot be +posted to the network event queue because the network event queue is already +full. */ +static BaseType_t xNetworkDownEventPending = pdFALSE; + +/* Stores the handle of the task that handles the stack. The handle is used +(indirectly) by some utility function to determine if the utility function is +being called by a task (in which case it is ok to block) or by the IP task +itself (in which case it is not ok to block). */ +static TaskHandle_t xIPTaskHandle = NULL; + +#if( ipconfigUSE_TCP != 0 ) + /* Set to a non-zero value if one or more TCP message have been processed + within the last round. */ + static BaseType_t xProcessedTCPMessage; +#endif + +/* Simple set to pdTRUE or pdFALSE depending on whether the network is up or +down (connected, not connected) respectively. */ +static BaseType_t xNetworkUp = pdFALSE; + +/* +A timer for each of the following processes, all of which need attention on a +regular basis: + 1. ARP, to check its table entries + 2. DPHC, to send requests and to renew a reservation + 3. TCP, to check for timeouts, resends + 4. DNS, to check for timeouts when looking-up a domain. + */ +static IPTimer_t xARPTimer; +#if( ipconfigUSE_DHCP != 0 ) + static IPTimer_t xDHCPTimer; +#endif +#if( ipconfigUSE_TCP != 0 ) + static IPTimer_t xTCPTimer; +#endif +#if( ipconfigDNS_USE_CALLBACKS != 0 ) + static IPTimer_t xDNSTimer; +#endif + +/* Set to pdTRUE when the IP task is ready to start processing packets. */ +static BaseType_t xIPTaskInitialised = pdFALSE; + +#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + /* Keep track of the lowest amount of space in 'xNetworkEventQueue'. */ + static UBaseType_t uxQueueMinimumSpace = ipconfigEVENT_QUEUE_LENGTH; +#endif + +/*-----------------------------------------------------------*/ + +static void prvIPTask( void *pvParameters ) +{ +IPStackEvent_t xReceivedEvent; +TickType_t xNextIPSleep; +FreeRTOS_Socket_t *pxSocket; +struct freertos_sockaddr xAddress; + + /* Just to prevent compiler warnings about unused parameters. */ + ( void ) pvParameters; + + /* A possibility to set some additional task properties. */ + iptraceIP_TASK_STARTING(); + + /* Generate a dummy message to say that the network connection has gone + down. This will cause this task to initialise the network interface. After + this it is the responsibility of the network interface hardware driver to + send this message if a previously connected network is disconnected. */ + FreeRTOS_NetworkDown(); + + #if( ipconfigUSE_TCP == 1 ) + { + /* Initialise the TCP timer. */ + prvIPTimerReload( &xTCPTimer, pdMS_TO_TICKS( ipTCP_TIMER_PERIOD_MS ) ); + } + #endif + + /* Initialisation is complete and events can now be processed. */ + xIPTaskInitialised = pdTRUE; + + FreeRTOS_debug_printf( ( "prvIPTask started\n" ) ); + + /* Loop, processing IP events. */ + for( ;; ) + { + ipconfigWATCHDOG_TIMER(); + + /* Check the ARP, DHCP and TCP timers to see if there is any periodic + or timeout processing to perform. */ + prvCheckNetworkTimers(); + + /* Calculate the acceptable maximum sleep time. */ + xNextIPSleep = prvCalculateSleepTime(); + + /* Wait until there is something to do. If the following call exits + * due to a time out rather than a message being received, set a + * 'NoEvent' value. */ + if ( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep ) == pdFALSE ) + { + xReceivedEvent.eEventType = eNoEvent; + } + + #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + { + if( xReceivedEvent.eEventType != eNoEvent ) + { + UBaseType_t uxCount; + + uxCount = uxQueueSpacesAvailable( xNetworkEventQueue ); + if( uxQueueMinimumSpace > uxCount ) + { + uxQueueMinimumSpace = uxCount; + } + } + } + #endif /* ipconfigCHECK_IP_QUEUE_SPACE */ + + iptraceNETWORK_EVENT_RECEIVED( xReceivedEvent.eEventType ); + + switch( xReceivedEvent.eEventType ) + { + case eNetworkDownEvent : + /* Attempt to establish a connection. */ + xNetworkUp = pdFALSE; + prvProcessNetworkDownEvent(); + break; + + case eNetworkRxEvent: + /* The network hardware driver has received a new packet. A + pointer to the received buffer is located in the pvData member + of the received event structure. */ + prvHandleEthernetPacket( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) ); + break; + + case eARPTimerEvent : + /* The ARP timer has expired, process the ARP cache. */ + vARPAgeCache(); + break; + + case eSocketBindEvent: + /* FreeRTOS_bind (a user API) wants the IP-task to bind a socket + to a port. The port number is communicated in the socket field + usLocalPort. vSocketBind() will actually bind the socket and the + API will unblock as soon as the eSOCKET_BOUND event is + triggered. */ + pxSocket = ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData ); + xAddress.sin_addr = 0u; /* For the moment. */ + xAddress.sin_port = FreeRTOS_ntohs( pxSocket->usLocalPort ); + pxSocket->usLocalPort = 0u; + vSocketBind( pxSocket, &xAddress, sizeof( xAddress ), pdFALSE ); + + /* Before 'eSocketBindEvent' was sent it was tested that + ( xEventGroup != NULL ) so it can be used now to wake up the + user. */ + pxSocket->xEventBits |= eSOCKET_BOUND; + vSocketWakeUpUser( pxSocket ); + break; + + case eSocketCloseEvent : + /* The user API FreeRTOS_closesocket() has sent a message to the + IP-task to actually close a socket. This is handled in + vSocketClose(). As the socket gets closed, there is no way to + report back to the API, so the API won't wait for the result */ + vSocketClose( ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData ) ); + break; + + case eStackTxEvent : + /* The network stack has generated a packet to send. A + pointer to the generated buffer is located in the pvData + member of the received event structure. */ + vProcessGeneratedUDPPacket( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) ); + break; + + case eDHCPEvent: + /* The DHCP state machine needs processing. */ + #if( ipconfigUSE_DHCP == 1 ) + { + vDHCPProcess( pdFALSE ); + } + #endif /* ipconfigUSE_DHCP */ + break; + + case eSocketSelectEvent : + /* FreeRTOS_select() has got unblocked by a socket event, + vSocketSelect() will check which sockets actually have an event + and update the socket field xSocketBits. */ + #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + { + vSocketSelect( ( SocketSelect_t * ) ( xReceivedEvent.pvData ) ); + } + #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ + break; + + case eSocketSignalEvent : + #if( ipconfigSUPPORT_SIGNALS != 0 ) + { + /* Some task wants to signal the user of this socket in + order to interrupt a call to recv() or a call to select(). */ + FreeRTOS_SignalSocket( ( Socket_t ) xReceivedEvent.pvData ); + } + #endif /* ipconfigSUPPORT_SIGNALS */ + break; + + case eTCPTimerEvent : + #if( ipconfigUSE_TCP == 1 ) + { + /* Simply mark the TCP timer as expired so it gets processed + the next time prvCheckNetworkTimers() is called. */ + xTCPTimer.bExpired = pdTRUE_UNSIGNED; + } + #endif /* ipconfigUSE_TCP */ + break; + + case eTCPAcceptEvent: + /* The API FreeRTOS_accept() was called, the IP-task will now + check if the listening socket (communicated in pvData) actually + received a new connection. */ + #if( ipconfigUSE_TCP == 1 ) + { + pxSocket = ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData ); + + if( xTCPCheckNewClient( pxSocket ) != pdFALSE ) + { + pxSocket->xEventBits |= eSOCKET_ACCEPT; + vSocketWakeUpUser( pxSocket ); + } + } + #endif /* ipconfigUSE_TCP */ + break; + + case eTCPNetStat: + /* FreeRTOS_netstat() was called to have the IP-task print an + overview of all sockets and their connections */ + #if( ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_PRINTF == 1 ) ) + { + vTCPNetStat(); + } + #endif /* ipconfigUSE_TCP */ + break; + + default : + /* Should not get here. */ + break; + } + + if( xNetworkDownEventPending != pdFALSE ) + { + /* A network down event could not be posted to the network event + queue because the queue was full. Try posting again. */ + FreeRTOS_NetworkDown(); + } + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xIsCallingFromIPTask( void ) +{ +BaseType_t xReturn; + + if( xTaskGetCurrentTaskHandle() == xIPTaskHandle ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static void prvHandleEthernetPacket( NetworkBufferDescriptor_t *pxBuffer ) +{ + #if( ipconfigUSE_LINKED_RX_MESSAGES == 0 ) + { + /* When ipconfigUSE_LINKED_RX_MESSAGES is not set to 0 then only one + buffer will be sent at a time. This is the default way for +TCP to pass + messages from the MAC to the TCP/IP stack. */ + prvProcessEthernetPacket( pxBuffer ); + } + #else /* ipconfigUSE_LINKED_RX_MESSAGES */ + { + NetworkBufferDescriptor_t *pxNextBuffer; + + /* An optimisation that is useful when there is high network traffic. + Instead of passing received packets into the IP task one at a time the + network interface can chain received packets together and pass them into + the IP task in one go. The packets are chained using the pxNextBuffer + member. The loop below walks through the chain processing each packet + in the chain in turn. */ + do + { + /* Store a pointer to the buffer after pxBuffer for use later on. */ + pxNextBuffer = pxBuffer->pxNextBuffer; + + /* Make it NULL to avoid using it later on. */ + pxBuffer->pxNextBuffer = NULL; + + prvProcessEthernetPacket( pxBuffer ); + pxBuffer = pxNextBuffer; + + /* While there is another packet in the chain. */ + } while( pxBuffer != NULL ); + } + #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ +} +/*-----------------------------------------------------------*/ + +static TickType_t prvCalculateSleepTime( void ) +{ +TickType_t xMaximumSleepTime; + + /* Start with the maximum sleep time, then check this against the remaining + time in any other timers that are active. */ + xMaximumSleepTime = ipconfigMAX_IP_TASK_SLEEP_TIME; + + if( xARPTimer.bActive != pdFALSE_UNSIGNED ) + { + if( xARPTimer.ulRemainingTime < xMaximumSleepTime ) + { + xMaximumSleepTime = xARPTimer.ulReloadTime; + } + } + + #if( ipconfigUSE_DHCP == 1 ) + { + if( xDHCPTimer.bActive != pdFALSE_UNSIGNED ) + { + if( xDHCPTimer.ulRemainingTime < xMaximumSleepTime ) + { + xMaximumSleepTime = xDHCPTimer.ulRemainingTime; + } + } + } + #endif /* ipconfigUSE_DHCP */ + + #if( ipconfigUSE_TCP == 1 ) + { + if( xTCPTimer.ulRemainingTime < xMaximumSleepTime ) + { + xMaximumSleepTime = xTCPTimer.ulRemainingTime; + } + } + #endif + + #if( ipconfigDNS_USE_CALLBACKS != 0 ) + { + if( xDNSTimer.bActive != pdFALSE ) + { + if( xDNSTimer.ulRemainingTime < xMaximumSleepTime ) + { + xMaximumSleepTime = xDNSTimer.ulRemainingTime; + } + } + } + #endif + + return xMaximumSleepTime; +} +/*-----------------------------------------------------------*/ + +static void prvCheckNetworkTimers( void ) +{ + /* Is it time for ARP processing? */ + if( prvIPTimerCheck( &xARPTimer ) != pdFALSE ) + { + xSendEventToIPTask( eARPTimerEvent ); + } + + #if( ipconfigUSE_DHCP == 1 ) + { + /* Is it time for DHCP processing? */ + if( prvIPTimerCheck( &xDHCPTimer ) != pdFALSE ) + { + xSendEventToIPTask( eDHCPEvent ); + } + } + #endif /* ipconfigUSE_DHCP */ + + #if( ipconfigDNS_USE_CALLBACKS != 0 ) + { + extern void vDNSCheckCallBack( void *pvSearchID ); + + /* Is it time for DNS processing? */ + if( prvIPTimerCheck( &xDNSTimer ) != pdFALSE ) + { + vDNSCheckCallBack( NULL ); + } + } + #endif /* ipconfigDNS_USE_CALLBACKS */ + + #if( ipconfigUSE_TCP == 1 ) + { + BaseType_t xWillSleep; + TickType_t xNextTime; + BaseType_t xCheckTCPSockets; + + if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0u ) + { + xWillSleep = pdTRUE; + } + else + { + xWillSleep = pdFALSE; + } + + /* Sockets need to be checked if the TCP timer has expired. */ + xCheckTCPSockets = prvIPTimerCheck( &xTCPTimer ); + + /* Sockets will also be checked if there are TCP messages but the + message queue is empty (indicated by xWillSleep being true). */ + if( ( xProcessedTCPMessage != pdFALSE ) && ( xWillSleep != pdFALSE ) ) + { + xCheckTCPSockets = pdTRUE; + } + + if( xCheckTCPSockets != pdFALSE ) + { + /* Attend to the sockets, returning the period after which the + check must be repeated. */ + xNextTime = xTCPTimerCheck( xWillSleep ); + prvIPTimerStart( &xTCPTimer, xNextTime ); + xProcessedTCPMessage = 0; + } + } + #endif /* ipconfigUSE_TCP == 1 */ +} +/*-----------------------------------------------------------*/ + +static void prvIPTimerStart( IPTimer_t *pxTimer, TickType_t xTime ) +{ + vTaskSetTimeOutState( &pxTimer->xTimeOut ); + pxTimer->ulRemainingTime = xTime; + + if( xTime == ( TickType_t ) 0 ) + { + pxTimer->bExpired = pdTRUE_UNSIGNED; + } + else + { + pxTimer->bExpired = pdFALSE_UNSIGNED; + } + + pxTimer->bActive = pdTRUE_UNSIGNED; +} +/*-----------------------------------------------------------*/ + +static void prvIPTimerReload( IPTimer_t *pxTimer, TickType_t xTime ) +{ + pxTimer->ulReloadTime = xTime; + prvIPTimerStart( pxTimer, xTime ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvIPTimerCheck( IPTimer_t *pxTimer ) +{ +BaseType_t xReturn; + + if( pxTimer->bActive == pdFALSE_UNSIGNED ) + { + /* The timer is not enabled. */ + xReturn = pdFALSE; + } + else + { + /* The timer might have set the bExpired flag already, if not, check the + value of xTimeOut against ulRemainingTime. */ + if( ( pxTimer->bExpired != pdFALSE_UNSIGNED ) || + ( xTaskCheckForTimeOut( &( pxTimer->xTimeOut ), &( pxTimer->ulRemainingTime ) ) != pdFALSE ) ) + { + prvIPTimerStart( pxTimer, pxTimer->ulReloadTime ); + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_NetworkDown( void ) +{ +static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL }; +const TickType_t xDontBlock = ( TickType_t ) 0; + + /* Simply send the network task the appropriate event. */ + if( xSendEventStructToIPTask( &xNetworkDownEvent, xDontBlock ) != pdPASS ) + { + /* Could not send the message, so it is still pending. */ + xNetworkDownEventPending = pdTRUE; + } + else + { + /* Message was sent so it is not pending. */ + xNetworkDownEventPending = pdFALSE; + } + + iptraceNETWORK_DOWN(); +} +/*-----------------------------------------------------------*/ + +BaseType_t FreeRTOS_NetworkDownFromISR( void ) +{ +static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL }; +BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + /* Simply send the network task the appropriate event. */ + if( xQueueSendToBackFromISR( xNetworkEventQueue, &xNetworkDownEvent, &xHigherPriorityTaskWoken ) != pdPASS ) + { + xNetworkDownEventPending = pdTRUE; + } + else + { + xNetworkDownEventPending = pdFALSE; + } + + iptraceNETWORK_DOWN(); + + return xHigherPriorityTaskWoken; +} +/*-----------------------------------------------------------*/ + +void *FreeRTOS_GetUDPPayloadBuffer( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks ) +{ +NetworkBufferDescriptor_t *pxNetworkBuffer; +void *pvReturn; + + /* Cap the block time. The reason for this is explained where + ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined (assuming an official + FreeRTOSIPConfig.h header file is being used). */ + if( xBlockTimeTicks > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ) + { + xBlockTimeTicks = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS; + } + + /* Obtain a network buffer with the required amount of storage. */ + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( UDPPacket_t ) + xRequestedSizeBytes, xBlockTimeTicks ); + + if( pxNetworkBuffer != NULL ) + { + /* Set the actual packet size in case a bigger buffer was returned. */ + pxNetworkBuffer->xDataLength = sizeof( UDPPacket_t ) + xRequestedSizeBytes; + + /* Leave space for the UPD header. */ + pvReturn = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ); + } + else + { + pvReturn = NULL; + } + + return ( void * ) pvReturn; +} +/*-----------------------------------------------------------*/ + +NetworkBufferDescriptor_t *pxDuplicateNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer, + BaseType_t xNewLength ) +{ +NetworkBufferDescriptor_t * pxNewBuffer; + + /* This function is only used when 'ipconfigZERO_COPY_TX_DRIVER' is set to 1. + The transmit routine wants to have ownership of the network buffer + descriptor, because it will pass the buffer straight to DMA. */ + pxNewBuffer = pxGetNetworkBufferWithDescriptor( ( size_t ) xNewLength, ( TickType_t ) 0 ); + + if( pxNewBuffer != NULL ) + { + /* Set the actual packet size in case a bigger buffer than requested + was returned. */ + pxNewBuffer->xDataLength = xNewLength; + + /* Copy the original packet information. */ + pxNewBuffer->ulIPAddress = pxNetworkBuffer->ulIPAddress; + pxNewBuffer->usPort = pxNetworkBuffer->usPort; + pxNewBuffer->usBoundPort = pxNetworkBuffer->usBoundPort; + memcpy( pxNewBuffer->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength ); + } + + return pxNewBuffer; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) || ( ipconfigZERO_COPY_RX_DRIVER != 0 ) + + NetworkBufferDescriptor_t *pxPacketBuffer_to_NetworkBuffer( const void *pvBuffer ) + { + uint8_t *pucBuffer; + NetworkBufferDescriptor_t *pxResult; + + if( pvBuffer == NULL ) + { + pxResult = NULL; + } + else + { + /* Obtain the network buffer from the zero copy pointer. */ + pucBuffer = ( uint8_t * ) pvBuffer; + + /* The input here is a pointer to a payload buffer. Subtract the + size of the header in the network buffer, usually 8 + 2 bytes. */ + pucBuffer -= ipBUFFER_PADDING; + + /* Here a pointer was placed to the network descriptor. As a + pointer is dereferenced, make sure it is well aligned. */ + if( ( ( ( uint32_t ) pucBuffer ) & ( sizeof( pucBuffer ) - ( size_t ) 1 ) ) == ( uint32_t ) 0 ) + { + pxResult = * ( ( NetworkBufferDescriptor_t ** ) pucBuffer ); + } + else + { + pxResult = NULL; + } + } + + return pxResult; + } + +#endif /* ipconfigZERO_COPY_TX_DRIVER != 0 */ +/*-----------------------------------------------------------*/ + +NetworkBufferDescriptor_t *pxUDPPayloadBuffer_to_NetworkBuffer( void *pvBuffer ) +{ +uint8_t *pucBuffer; +NetworkBufferDescriptor_t *pxResult; + + if( pvBuffer == NULL ) + { + pxResult = NULL; + } + else + { + /* Obtain the network buffer from the zero copy pointer. */ + pucBuffer = ( uint8_t * ) pvBuffer; + + /* The input here is a pointer to a payload buffer. Subtract + the total size of a UDP/IP header plus the size of the header in + the network buffer, usually 8 + 2 bytes. */ + pucBuffer -= ( sizeof( UDPPacket_t ) + ipBUFFER_PADDING ); + + /* Here a pointer was placed to the network descriptor, + As a pointer is dereferenced, make sure it is well aligned */ + if( ( ( ( uint32_t ) pucBuffer ) & ( sizeof( pucBuffer ) - 1 ) ) == 0 ) + { + /* The following statement may trigger a: + warning: cast increases required alignment of target type [-Wcast-align]. + It has been confirmed though that the alignment is suitable. */ + pxResult = * ( ( NetworkBufferDescriptor_t ** ) pucBuffer ); + } + else + { + pxResult = NULL; + } + } + + return pxResult; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_ReleaseUDPPayloadBuffer( void *pvBuffer ) +{ + vReleaseNetworkBufferAndDescriptor( pxUDPPayloadBuffer_to_NetworkBuffer( pvBuffer ) ); +} +/*-----------------------------------------------------------*/ + +/*_RB_ Should we add an error or assert if the task priorities are set such that the servers won't function as expected? */ +/*_HT_ There was a bug in FreeRTOS_TCP_IP.c that only occurred when the applications' priority was too high. + As that bug has been repaired, there is not an urgent reason to warn. + It is better though to use the advised priority scheme. */ +BaseType_t FreeRTOS_IPInit( const uint8_t ucIPAddress[ ipIP_ADDRESS_LENGTH_BYTES ], const uint8_t ucNetMask[ ipIP_ADDRESS_LENGTH_BYTES ], const uint8_t ucGatewayAddress[ ipIP_ADDRESS_LENGTH_BYTES ], const uint8_t ucDNSServerAddress[ ipIP_ADDRESS_LENGTH_BYTES ], const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] ) +{ +BaseType_t xReturn = pdFALSE; + + /* This function should only be called once. */ + configASSERT( xIPIsNetworkTaskReady() == pdFALSE ); + configASSERT( xNetworkEventQueue == NULL ); + configASSERT( xIPTaskHandle == NULL ); + + /* Check structure packing is correct. */ + configASSERT( sizeof( EthernetHeader_t ) == ipEXPECTED_EthernetHeader_t_SIZE ); + configASSERT( sizeof( ARPHeader_t ) == ipEXPECTED_ARPHeader_t_SIZE ); + configASSERT( sizeof( IPHeader_t ) == ipEXPECTED_IPHeader_t_SIZE ); + configASSERT( sizeof( ICMPHeader_t ) == ipEXPECTED_ICMPHeader_t_SIZE ); + configASSERT( sizeof( UDPHeader_t ) == ipEXPECTED_UDPHeader_t_SIZE ); + + /* Attempt to create the queue used to communicate with the IP task. */ + xNetworkEventQueue = xQueueCreate( ( UBaseType_t ) ipconfigEVENT_QUEUE_LENGTH, ( UBaseType_t ) sizeof( IPStackEvent_t ) ); + configASSERT( xNetworkEventQueue ); + + if( xNetworkEventQueue != NULL ) + { + #if ( configQUEUE_REGISTRY_SIZE > 0 ) + { + /* A queue registry is normally used to assist a kernel aware + debugger. If one is in use then it will be helpful for the debugger + to show information about the network event queue. */ + vQueueAddToRegistry( xNetworkEventQueue, "NetEvnt" ); + } + #endif /* configQUEUE_REGISTRY_SIZE */ + + if( xNetworkBuffersInitialise() == pdPASS ) + { + /* Store the local IP and MAC address. */ + xNetworkAddressing.ulDefaultIPAddress = FreeRTOS_inet_addr_quick( ucIPAddress[ 0 ], ucIPAddress[ 1 ], ucIPAddress[ 2 ], ucIPAddress[ 3 ] ); + xNetworkAddressing.ulNetMask = FreeRTOS_inet_addr_quick( ucNetMask[ 0 ], ucNetMask[ 1 ], ucNetMask[ 2 ], ucNetMask[ 3 ] ); + xNetworkAddressing.ulGatewayAddress = FreeRTOS_inet_addr_quick( ucGatewayAddress[ 0 ], ucGatewayAddress[ 1 ], ucGatewayAddress[ 2 ], ucGatewayAddress[ 3 ] ); + xNetworkAddressing.ulDNSServerAddress = FreeRTOS_inet_addr_quick( ucDNSServerAddress[ 0 ], ucDNSServerAddress[ 1 ], ucDNSServerAddress[ 2 ], ucDNSServerAddress[ 3 ] ); + xNetworkAddressing.ulBroadcastAddress = ( xNetworkAddressing.ulDefaultIPAddress & xNetworkAddressing.ulNetMask ) | ~xNetworkAddressing.ulNetMask; + + memcpy( &xDefaultAddressing, &xNetworkAddressing, sizeof( xDefaultAddressing ) ); + + #if ipconfigUSE_DHCP == 1 + { + /* The IP address is not set until DHCP completes. */ + *ipLOCAL_IP_ADDRESS_POINTER = 0x00UL; + } + #else + { + /* The IP address is set from the value passed in. */ + *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress; + + /* Added to prevent ARP flood to gateway. Ensure the + gateway is on the same subnet as the IP address. */ + configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) ); + } + #endif /* ipconfigUSE_DHCP == 1 */ + + /* The MAC address is stored in the start of the default packet + header fragment, which is used when sending UDP packets. */ + memcpy( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES ); + + /* Prepare the sockets interface. */ + xReturn = vNetworkSocketsInit(); + + if( pdTRUE == xReturn ) + { + /* Create the task that processes Ethernet and stack events. */ + xReturn = xTaskCreate( prvIPTask, "IP-task", ( uint16_t )ipconfigIP_TASK_STACK_SIZE_WORDS, NULL, ( UBaseType_t )ipconfigIP_TASK_PRIORITY, &xIPTaskHandle ); + } + } + else + { + FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: xNetworkBuffersInitialise() failed\n") ); + + /* Clean up. */ + vQueueDelete( xNetworkEventQueue ); + xNetworkEventQueue = NULL; + } + } + else + { + FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: Network event queue could not be created\n") ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_GetAddressConfiguration( uint32_t *pulIPAddress, uint32_t *pulNetMask, uint32_t *pulGatewayAddress, uint32_t *pulDNSServerAddress ) +{ + /* Return the address configuration to the caller. */ + + if( pulIPAddress != NULL ) + { + *pulIPAddress = *ipLOCAL_IP_ADDRESS_POINTER; + } + + if( pulNetMask != NULL ) + { + *pulNetMask = xNetworkAddressing.ulNetMask; + } + + if( pulGatewayAddress != NULL ) + { + *pulGatewayAddress = xNetworkAddressing.ulGatewayAddress; + } + + if( pulDNSServerAddress != NULL ) + { + *pulDNSServerAddress = xNetworkAddressing.ulDNSServerAddress; + } +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_SetAddressConfiguration( const uint32_t *pulIPAddress, const uint32_t *pulNetMask, const uint32_t *pulGatewayAddress, const uint32_t *pulDNSServerAddress ) +{ + /* Update the address configuration. */ + + if( pulIPAddress != NULL ) + { + *ipLOCAL_IP_ADDRESS_POINTER = *pulIPAddress; + } + + if( pulNetMask != NULL ) + { + xNetworkAddressing.ulNetMask = *pulNetMask; + } + + if( pulGatewayAddress != NULL ) + { + xNetworkAddressing.ulGatewayAddress = *pulGatewayAddress; + } + + if( pulDNSServerAddress != NULL ) + { + xNetworkAddressing.ulDNSServerAddress = *pulDNSServerAddress; + } +} +/*-----------------------------------------------------------*/ + +#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + + BaseType_t FreeRTOS_SendPingRequest( uint32_t ulIPAddress, size_t xNumberOfBytesToSend, TickType_t xBlockTimeTicks ) + { + NetworkBufferDescriptor_t *pxNetworkBuffer; + ICMPHeader_t *pxICMPHeader; + BaseType_t xReturn = pdFAIL; + static uint16_t usSequenceNumber = 0; + uint8_t *pucChar; + IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL }; + + if( (xNumberOfBytesToSend >= 1 ) && ( xNumberOfBytesToSend < ( ( ipconfigNETWORK_MTU - sizeof( IPHeader_t ) ) - sizeof( ICMPHeader_t ) ) ) && ( uxGetNumberOfFreeNetworkBuffers() >= 3 ) ) + { + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( xNumberOfBytesToSend + sizeof( ICMPPacket_t ), xBlockTimeTicks ); + + if( pxNetworkBuffer != NULL ) + { + pxICMPHeader = ( ICMPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipIP_PAYLOAD_OFFSET ] ); + usSequenceNumber++; + + /* Fill in the basic header information. */ + pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REQUEST; + pxICMPHeader->ucTypeOfService = 0; + pxICMPHeader->usIdentifier = usSequenceNumber; + pxICMPHeader->usSequenceNumber = usSequenceNumber; + + /* Find the start of the data. */ + pucChar = ( uint8_t * ) pxICMPHeader; + pucChar += sizeof( ICMPHeader_t ); + + /* Just memset the data to a fixed value. */ + memset( ( void * ) pucChar, ( int ) ipECHO_DATA_FILL_BYTE, xNumberOfBytesToSend ); + + /* The message is complete, IP and checksum's are handled by + vProcessGeneratedUDPPacket */ + pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = FREERTOS_SO_UDPCKSUM_OUT; + pxNetworkBuffer->ulIPAddress = ulIPAddress; + pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA; + pxNetworkBuffer->xDataLength = xNumberOfBytesToSend + sizeof( ICMPHeader_t ); + + /* Send to the stack. */ + xStackTxEvent.pvData = pxNetworkBuffer; + + if( xSendEventStructToIPTask( &xStackTxEvent, xBlockTimeTicks) != pdPASS ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT ); + } + else + { + xReturn = usSequenceNumber; + } + } + } + else + { + /* The requested number of bytes will not fit in the available space + in the network buffer. */ + } + + return xReturn; + } + +#endif /* ipconfigSUPPORT_OUTGOING_PINGS == 1 */ +/*-----------------------------------------------------------*/ + +BaseType_t xSendEventToIPTask( eIPEvent_t eEvent ) +{ +IPStackEvent_t xEventMessage; +const TickType_t xDontBlock = ( TickType_t ) 0; + + xEventMessage.eEventType = eEvent; + xEventMessage.pvData = ( void* )NULL; + + return xSendEventStructToIPTask( &xEventMessage, xDontBlock ); +} +/*-----------------------------------------------------------*/ + +BaseType_t xSendEventStructToIPTask( const IPStackEvent_t *pxEvent, TickType_t xTimeout ) +{ +BaseType_t xReturn, xSendMessage; + + if( ( xIPIsNetworkTaskReady() == pdFALSE ) && ( pxEvent->eEventType != eNetworkDownEvent ) ) + { + /* Only allow eNetworkDownEvent events if the IP task is not ready + yet. Not going to attempt to send the message so the send failed. */ + xReturn = pdFAIL; + } + else + { + xSendMessage = pdTRUE; + + #if( ipconfigUSE_TCP == 1 ) + { + if( pxEvent->eEventType == eTCPTimerEvent ) + { + /* TCP timer events are sent to wake the timer task when + xTCPTimer has expired, but there is no point sending them if the + IP task is already awake processing other message. */ + xTCPTimer.bExpired = pdTRUE_UNSIGNED; + + if( uxQueueMessagesWaiting( xNetworkEventQueue ) != 0u ) + { + /* Not actually going to send the message but this is not a + failure as the message didn't need to be sent. */ + xSendMessage = pdFALSE; + } + } + } + #endif /* ipconfigUSE_TCP */ + + if( xSendMessage != pdFALSE ) + { + /* The IP task cannot block itself while waiting for itself to + respond. */ + if( ( xIsCallingFromIPTask() == pdTRUE ) && ( xTimeout > ( TickType_t ) 0 ) ) + { + xTimeout = ( TickType_t ) 0; + } + + xReturn = xQueueSendToBack( xNetworkEventQueue, pxEvent, xTimeout ); + + if( xReturn == pdFAIL ) + { + /* A message should have been sent to the IP task, but wasn't. */ + FreeRTOS_debug_printf( ( "xSendEventStructToIPTask: CAN NOT ADD %d\n", pxEvent->eEventType ) ); + iptraceSTACK_TX_EVENT_LOST( pxEvent->eEventType ); + } + } + else + { + /* It was not necessary to send the message to process the event so + even though the message was not sent the call was successful. */ + xReturn = pdPASS; + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer ) +{ +eFrameProcessingResult_t eReturn; +const EthernetHeader_t *pxEthernetHeader; + + pxEthernetHeader = ( const EthernetHeader_t * ) pucEthernetBuffer; + + if( memcmp( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) &( pxEthernetHeader->xDestinationAddress ), sizeof( MACAddress_t ) ) == 0 ) + { + /* The packet was directed to this node directly - process it. */ + eReturn = eProcessBuffer; + } + else if( memcmp( ( void * ) xBroadcastMACAddress.ucBytes, ( void * ) pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 ) + { + /* The packet was a broadcast - process it. */ + eReturn = eProcessBuffer; + } + else +#if( ipconfigUSE_LLMNR == 1 ) + if( memcmp( ( void * ) xLLMNR_MacAdress.ucBytes, ( void * ) pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 ) + { + /* The packet is a request for LLMNR - process it. */ + eReturn = eProcessBuffer; + } + else +#endif /* ipconfigUSE_LLMNR */ + { + /* The packet was not a broadcast, or for this node, just release + the buffer without taking any other action. */ + eReturn = eReleaseBuffer; + } + + #if( ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 ) + { + uint16_t usFrameType; + + if( eReturn == eProcessBuffer ) + { + usFrameType = pxEthernetHeader->usFrameType; + usFrameType = FreeRTOS_ntohs( usFrameType ); + + if( usFrameType <= 0x600U ) + { + /* Not an Ethernet II frame. */ + eReturn = eReleaseBuffer; + } + } + } + #endif /* ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 */ + + return eReturn; +} +/*-----------------------------------------------------------*/ + +static void prvProcessNetworkDownEvent( void ) +{ + /* Stop the ARP timer while there is no network. */ + xARPTimer.bActive = pdFALSE_UNSIGNED; + + #if ipconfigUSE_NETWORK_EVENT_HOOK == 1 + { + static BaseType_t xCallEventHook = pdFALSE; + + /* The first network down event is generated by the IP stack itself to + initialise the network hardware, so do not call the network down event + the first time through. */ + if( xCallEventHook == pdTRUE ) + { + vApplicationIPNetworkEventHook( eNetworkDown ); + } + xCallEventHook = pdTRUE; + } + #endif + + /* Per the ARP Cache Validation section of https://tools.ietf.org/html/rfc1122, + treat network down as a "delivery problem" and flush the ARP cache for this + interface. */ + FreeRTOS_ClearARP( ); + + /* The network has been disconnected (or is being initialised for the first + time). Perform whatever hardware processing is necessary to bring it up + again, or wait for it to be available again. This is hardware dependent. */ + if( xNetworkInterfaceInitialise() != pdPASS ) + { + /* Ideally the network interface initialisation function will only + return when the network is available. In case this is not the case, + wait a while before retrying the initialisation. */ + vTaskDelay( ipINITIALISATION_RETRY_DELAY ); + FreeRTOS_NetworkDown(); + } + else + { + /* Set remaining time to 0 so it will become active immediately. */ + #if ipconfigUSE_DHCP == 1 + { + /* The network is not up until DHCP has completed. */ + vDHCPProcess( pdTRUE ); + xSendEventToIPTask( eDHCPEvent ); + } + #else + { + /* Perform any necessary 'network up' processing. */ + vIPNetworkUpCalls(); + } + #endif + } +} +/*-----------------------------------------------------------*/ + +void vIPNetworkUpCalls( void ) +{ + xNetworkUp = pdTRUE; + + #if( ipconfigUSE_NETWORK_EVENT_HOOK == 1 ) + { + vApplicationIPNetworkEventHook( eNetworkUp ); + } + #endif /* ipconfigUSE_NETWORK_EVENT_HOOK */ + + #if( ipconfigDNS_USE_CALLBACKS != 0 ) + { + /* The following function is declared in FreeRTOS_DNS.c and 'private' to + this library */ + extern void vDNSInitialise( void ); + vDNSInitialise(); + } + #endif /* ipconfigDNS_USE_CALLBACKS != 0 */ + + /* Set remaining time to 0 so it will become active immediately. */ + prvIPTimerReload( &xARPTimer, pdMS_TO_TICKS( ipARP_TIMER_PERIOD_MS ) ); +} +/*-----------------------------------------------------------*/ + +static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ +EthernetHeader_t *pxEthernetHeader; +eFrameProcessingResult_t eReturned = eReleaseBuffer; + + configASSERT( pxNetworkBuffer ); + + /* Interpret the Ethernet frame. */ + if( pxNetworkBuffer->xDataLength >= sizeof( EthernetHeader_t ) ) + { + eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer ); + pxEthernetHeader = ( EthernetHeader_t * )( pxNetworkBuffer->pucEthernetBuffer ); + + if( eReturned == eProcessBuffer ) + { + /* Interpret the received Ethernet packet. */ + switch( pxEthernetHeader->usFrameType ) + { + case ipARP_FRAME_TYPE: + /* The Ethernet frame contains an ARP packet. */ + if( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) ) + { + eReturned = eARPProcessPacket( ( ARPPacket_t * )pxNetworkBuffer->pucEthernetBuffer ); + } + else + { + eReturned = eReleaseBuffer; + } + break; + + case ipIPv4_FRAME_TYPE: + /* The Ethernet frame contains an IP packet. */ + if( pxNetworkBuffer->xDataLength >= sizeof( IPPacket_t ) ) + { + eReturned = prvProcessIPPacket( ( IPPacket_t * )pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer ); + } + else + { + eReturned = eReleaseBuffer; + } + break; + + default: + /* No other packet types are handled. Nothing to do. */ + eReturned = eReleaseBuffer; + break; + } + } + } + + /* Perform any actions that resulted from processing the Ethernet frame. */ + switch( eReturned ) + { + case eReturnEthernetFrame : + /* The Ethernet frame will have been updated (maybe it was + an ARP request or a PING request?) and should be sent back to + its source. */ + vReturnEthernetFrame( pxNetworkBuffer, pdTRUE ); + /* parameter pdTRUE: the buffer must be released once + the frame has been transmitted */ + break; + + case eFrameConsumed : + /* The frame is in use somewhere, don't release the buffer + yet. */ + break; + + default : + /* The frame is not being used anywhere, and the + NetworkBufferDescriptor_t structure containing the frame should + just be released back to the list of free buffers. */ + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + break; + } +} +/*-----------------------------------------------------------*/ + +static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket, + NetworkBufferDescriptor_t * const pxNetworkBuffer, UBaseType_t uxHeaderLength ) +{ +eFrameProcessingResult_t eReturn = eProcessBuffer; + +#if( ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 ) || ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) ) + const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader ); +#else + /* or else, the parameter won't be used and the function will be optimised + away */ + ( void ) pxIPPacket; +#endif + + #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 ) + { + /* In systems with a very small amount of RAM, it might be advantageous + to have incoming messages checked earlier, by the network card driver. + This method may decrease the usage of sparse network buffers. */ + uint32_t ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress; + + /* Ensure that the incoming packet is not fragmented (only outgoing + packets can be fragmented) as these are the only handled IP frames + currently. */ + if( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) != 0U ) + { + /* Can not handle, fragmented packet. */ + eReturn = eReleaseBuffer; + } + /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes + * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */ + else if( ( pxIPHeader->ucVersionHeaderLength < 0x45u ) || ( pxIPHeader->ucVersionHeaderLength > 0x4Fu ) ) + { + /* Can not handle, unknown or invalid header version. */ + eReturn = eReleaseBuffer; + } + /* Is the packet for this IP address? */ + else if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) && + /* Is it the global broadcast address 255.255.255.255 ? */ + ( ulDestinationIPAddress != ipBROADCAST_IP_ADDRESS ) && + /* Is it a specific broadcast address 192.168.1.255 ? */ + ( ulDestinationIPAddress != xNetworkAddressing.ulBroadcastAddress ) && + #if( ipconfigUSE_LLMNR == 1 ) + /* Is it the LLMNR multicast address? */ + ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) && + #endif + /* Or (during DHCP negotiation) we have no IP-address yet? */ + ( *ipLOCAL_IP_ADDRESS_POINTER != 0UL ) ) + { + /* Packet is not for this node, release it */ + eReturn = eReleaseBuffer; + } + } + #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + + #if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) + { + /* Some drivers of NIC's with checksum-offloading will enable the above + define, so that the checksum won't be checked again here */ + if (eReturn == eProcessBuffer ) + { + /* Is the IP header checksum correct? */ + if( ( pxIPHeader->ucProtocol != ( uint8_t ) ipPROTOCOL_ICMP ) && + ( usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ( size_t ) uxHeaderLength ) != ipCORRECT_CRC ) ) + { + /* Check sum in IP-header not correct. */ + eReturn = eReleaseBuffer; + } + /* Is the upper-layer checksum (TCP/UDP/ICMP) correct? */ + else if( usGenerateProtocolChecksum( ( uint8_t * )( pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer->xDataLength, pdFALSE ) != ipCORRECT_CRC ) + { + /* Protocol checksum not accepted. */ + eReturn = eReleaseBuffer; + } + } + } + #else + { + /* to avoid warning unused parameters */ + ( void ) pxNetworkBuffer; + ( void ) uxHeaderLength; + } + #endif /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 */ + + return eReturn; +} +/*-----------------------------------------------------------*/ + +static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ +eFrameProcessingResult_t eReturn; +IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader ); +UBaseType_t uxHeaderLength = ( UBaseType_t ) ( ( pxIPHeader->ucVersionHeaderLength & 0x0Fu ) << 2 ); +uint8_t ucProtocol; + + /* Bound the calculated header length: take away the Ethernet header size, + then check if the IP header is claiming to be longer than the remaining + total packet size. Also check for minimal header field length. */ + if( ( uxHeaderLength > ( pxNetworkBuffer->xDataLength - ipSIZE_OF_ETH_HEADER ) ) || + ( uxHeaderLength < ipSIZE_OF_IPv4_HEADER ) ) + { + return eReleaseBuffer; + } + + ucProtocol = pxIPPacket->xIPHeader.ucProtocol; + /* Check if the IP headers are acceptable and if it has our destination. */ + eReturn = prvAllowIPPacket( pxIPPacket, pxNetworkBuffer, uxHeaderLength ); + + if( eReturn == eProcessBuffer ) + { + if( uxHeaderLength > ipSIZE_OF_IPv4_HEADER ) + { + /* All structs of headers expect a IP header size of 20 bytes + * IP header options were included, we'll ignore them and cut them out + * Note: IP options are mostly use in Multi-cast protocols */ + const size_t optlen = ( ( size_t ) uxHeaderLength ) - ipSIZE_OF_IPv4_HEADER; + /* From: the previous start of UDP/ICMP/TCP data */ + uint8_t *pucSource = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + uxHeaderLength); + /* To: the usual start of UDP/ICMP/TCP data at offset 20 from IP header */ + uint8_t *pucTarget = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + ipSIZE_OF_IPv4_HEADER); + /* How many: total length minus the options and the lower headers */ + const size_t xMoveLen = pxNetworkBuffer->xDataLength - optlen - ipSIZE_OF_IPv4_HEADER - ipSIZE_OF_ETH_HEADER; + + memmove( pucTarget, pucSource, xMoveLen ); + pxNetworkBuffer->xDataLength -= optlen; + + /* Fix-up new version/header length field in IP packet. */ + pxIPHeader->ucVersionHeaderLength = ( pxIPHeader->ucVersionHeaderLength & 0xF0 ) | /* High nibble is the version. */ + ( ( ipSIZE_OF_IPv4_HEADER >> 2 ) & 0x0F ); /* Low nibble is the header size, in bytes, divided by four. */ + } + + /* Add the IP and MAC addresses to the ARP table if they are not + already there - otherwise refresh the age of the existing + entry. */ + if( ucProtocol != ( uint8_t ) ipPROTOCOL_UDP ) + { + /* Refresh the ARP cache with the IP/MAC-address of the received packet + * For UDP packets, this will be done later in xProcessReceivedUDPPacket() + * as soon as know that the message will be handled by someone + * This will prevent that the ARP cache will get overwritten + * with the IP-address of useless broadcast packets + */ + vARPRefreshCacheEntry( &( pxIPPacket->xEthernetHeader.xSourceAddress ), pxIPHeader->ulSourceIPAddress ); + } + switch( ucProtocol ) + { + case ipPROTOCOL_ICMP : + /* The IP packet contained an ICMP frame. Don't bother + checking the ICMP checksum, as if it is wrong then the + wrong data will also be returned, and the source of the + ping will know something went wrong because it will not + be able to validate what it receives. */ + #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + { + if( pxNetworkBuffer->xDataLength >= sizeof( ICMPPacket_t ) ) + { + ICMPPacket_t *pxICMPPacket = ( ICMPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer ); + if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER ) + { + eReturn = prvProcessICMPPacket( pxICMPPacket ); + } + } + else + { + eReturn = eReleaseBuffer; + } + } + #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */ + break; + + case ipPROTOCOL_UDP : + { + /* The IP packet contained a UDP frame. */ + UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); + + /* Only proceed if the payload length indicated in the header + appears to be valid. */ + if ( pxNetworkBuffer->xDataLength >= sizeof( UDPPacket_t ) ) + { + /* Ensure that downstream UDP packet handling has the lesser + * of: the actual network buffer Ethernet frame length, or + * the sender's UDP packet header payload length, minus the + * size of the UDP header. + * + * The size of the UDP packet structure in this implementation + * includes the size of the Ethernet header, the size of + * the IP header, and the size of the UDP header. + */ + + pxNetworkBuffer->xDataLength -= sizeof( UDPPacket_t ); + if( ( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t ) ) < + pxNetworkBuffer->xDataLength ) + { + pxNetworkBuffer->xDataLength = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t ); + } + + /* Fields in pxNetworkBuffer (usPort, ulIPAddress) are network order. */ + pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort; + pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress; + + /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM: + * In some cases, the upper-layer checksum has been calculated + * by the NIC driver. + * + * Pass the packet payload to the UDP sockets implementation. */ + if( xProcessReceivedUDPPacket( pxNetworkBuffer, + pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS ) + { + eReturn = eFrameConsumed; + } + } + else + { + eReturn = eReleaseBuffer; + } + } + break; + +#if ipconfigUSE_TCP == 1 + case ipPROTOCOL_TCP : + { + + if( xProcessReceivedTCPPacket( pxNetworkBuffer ) == pdPASS ) + { + eReturn = eFrameConsumed; + } + + /* Setting this variable will cause xTCPTimerCheck() + to be called just before the IP-task blocks. */ + xProcessedTCPMessage++; + } + break; +#endif + default : + /* Not a supported frame type. */ + break; + } + } + + return eReturn; +} +/*-----------------------------------------------------------*/ + +#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + + static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket ) + { + ePingReplyStatus_t eStatus = eSuccess; + uint16_t usDataLength, usCount; + uint8_t *pucByte; + + /* Find the total length of the IP packet. */ + usDataLength = pxICMPPacket->xIPHeader.usLength; + usDataLength = FreeRTOS_ntohs( usDataLength ); + + /* Remove the length of the IP headers to obtain the length of the ICMP + message itself. */ + usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_IPv4_HEADER ); + + /* Remove the length of the ICMP header, to obtain the length of + data contained in the ping. */ + usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_ICMP_HEADER ); + + /* Checksum has already been checked before in prvProcessIPPacket */ + + /* Find the first byte of the data within the ICMP packet. */ + pucByte = ( uint8_t * ) pxICMPPacket; + pucByte += sizeof( ICMPPacket_t ); + + /* Check each byte. */ + for( usCount = 0; usCount < usDataLength; usCount++ ) + { + if( *pucByte != ipECHO_DATA_FILL_BYTE ) + { + eStatus = eInvalidData; + break; + } + + pucByte++; + } + + /* Call back into the application to pass it the result. */ + vApplicationPingReplyHook( eStatus, pxICMPPacket->xICMPHeader.usIdentifier ); + } + +#endif +/*-----------------------------------------------------------*/ + +#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) + + static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket ) + { + ICMPHeader_t *pxICMPHeader; + IPHeader_t *pxIPHeader; + uint16_t usRequest; + + pxICMPHeader = &( pxICMPPacket->xICMPHeader ); + pxIPHeader = &( pxICMPPacket->xIPHeader ); + + /* HT:endian: changed back */ + iptraceSENDING_PING_REPLY( pxIPHeader->ulSourceIPAddress ); + + /* The checksum can be checked here - but a ping reply should be + returned even if the checksum is incorrect so the other end can + tell that the ping was received - even if the ping reply contains + invalid data. */ + pxICMPHeader->ucTypeOfMessage = ( uint8_t ) ipICMP_ECHO_REPLY; + pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress; + pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER; + + /* Update the checksum because the ucTypeOfMessage member in the header + has been changed to ipICMP_ECHO_REPLY. This is faster than calling + usGenerateChecksum(). */ + + /* due to compiler warning "integer operation result is out of range" */ + + usRequest = ( uint16_t ) ( ( uint16_t )ipICMP_ECHO_REQUEST << 8 ); + + if( pxICMPHeader->usChecksum >= FreeRTOS_htons( 0xFFFFu - usRequest ) ) + { + pxICMPHeader->usChecksum = ( uint16_t ) + ( ( ( uint32_t ) pxICMPHeader->usChecksum ) + + FreeRTOS_htons( usRequest + 1UL ) ); + } + else + { + pxICMPHeader->usChecksum = ( uint16_t ) + ( ( ( uint32_t ) pxICMPHeader->usChecksum ) + + FreeRTOS_htons( usRequest ) ); + } + return eReturnEthernetFrame; + } + +#endif /* ipconfigREPLY_TO_INCOMING_PINGS == 1 */ +/*-----------------------------------------------------------*/ + +#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + + static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket ) + { + eFrameProcessingResult_t eReturn = eReleaseBuffer; + + iptraceICMP_PACKET_RECEIVED(); + switch( pxICMPPacket->xICMPHeader.ucTypeOfMessage ) + { + case ipICMP_ECHO_REQUEST : + #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) + { + eReturn = prvProcessICMPEchoRequest( pxICMPPacket ); + } + #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) */ + break; + + case ipICMP_ECHO_REPLY : + #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + { + prvProcessICMPEchoReply( pxICMPPacket ); + } + #endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + break; + + default : + break; + } + + return eReturn; + } + +#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */ +/*-----------------------------------------------------------*/ + +uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, size_t uxBufferLength, BaseType_t xOutgoingPacket ) +{ +uint32_t ulLength; +uint16_t usChecksum, *pusChecksum; +const IPPacket_t * pxIPPacket; +UBaseType_t uxIPHeaderLength; +ProtocolPacket_t *pxProtPack; +uint8_t ucProtocol; +#if( ipconfigHAS_DEBUG_PRINTF != 0 ) + const char *pcType; +#endif + + /* Check for minimum packet size. */ + if( uxBufferLength < sizeof( IPPacket_t ) ) + { + return ipINVALID_LENGTH; + } + + /* Parse the packet length. */ + pxIPPacket = ( const IPPacket_t * ) pucEthernetBuffer; + + /* Per https://tools.ietf.org/html/rfc791, the four-bit Internet Header + Length field contains the length of the internet header in 32-bit words. */ + uxIPHeaderLength = ( UBaseType_t ) ( sizeof( uint32_t ) * ( pxIPPacket->xIPHeader.ucVersionHeaderLength & 0x0Fu ) ); + + /* Check for minimum packet size. */ + if( uxBufferLength < sizeof( IPPacket_t ) + uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) + { + return ipINVALID_LENGTH; + } + if( uxBufferLength < ( size_t ) ( ipSIZE_OF_ETH_HEADER + FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) ) ) + { + return ipINVALID_LENGTH; + } + + /* Identify the next protocol. */ + ucProtocol = pxIPPacket->xIPHeader.ucProtocol; + + /* N.B., if this IP packet header includes Options, then the following + assignment results in a pointer into the protocol packet with the Ethernet + and IP headers incorrectly aligned. However, either way, the "third" + protocol (Layer 3 or 4) header will be aligned, which is the convenience + of this calculation. */ + pxProtPack = ( ProtocolPacket_t * ) ( pucEthernetBuffer + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) ); + + /* Switch on the Layer 3/4 protocol. */ + if( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) + { + if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_UDP_HEADER ) ) + { + return ipINVALID_LENGTH; + } + + pusChecksum = ( uint16_t * ) ( &( pxProtPack->xUDPPacket.xUDPHeader.usChecksum ) ); + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + pcType = "UDP"; + } + #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ + } + else if( ucProtocol == ( uint8_t ) ipPROTOCOL_TCP ) + { + if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_TCP_HEADER ) ) + { + return ipINVALID_LENGTH; + } + + pusChecksum = ( uint16_t * ) ( &( pxProtPack->xTCPPacket.xTCPHeader.usChecksum ) ); + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + pcType = "TCP"; + } + #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ + } + else if( ( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) || + ( ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) ) + { + if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_ICMP_HEADER ) ) + { + return ipINVALID_LENGTH; + } + + pusChecksum = ( uint16_t * ) ( &( pxProtPack->xICMPPacket.xICMPHeader.usChecksum ) ); + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + if( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) + { + pcType = "ICMP"; + } + else + { + pcType = "IGMP"; + } + } + #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ + } + else + { + /* Unhandled protocol, other than ICMP, IGMP, UDP, or TCP. */ + return ipUNHANDLED_PROTOCOL; + } + + /* The protocol and checksum field have been identified. Check the direction + of the packet. */ + if( xOutgoingPacket != pdFALSE ) + { + /* This is an outgoing packet. Before calculating the checksum, set it + to zero. */ + *( pusChecksum ) = 0u; + } + else if( ( *pusChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) ) + { + /* Sender hasn't set the checksum, no use to calculate it. */ + return ipCORRECT_CRC; + } + + ulLength = ( uint32_t ) + ( FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) - ( ( uint16_t ) uxIPHeaderLength ) ); /* normally minus 20 */ + + if( ( ulLength < sizeof( pxProtPack->xUDPPacket.xUDPHeader ) ) || + ( ulLength > ( uint32_t )( ipconfigNETWORK_MTU - uxIPHeaderLength ) ) ) + { + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: len invalid: %lu\n", pcType, ulLength ) ); + } + #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ + + /* Again, in a 16-bit return value there is no space to indicate an + error. For incoming packets, 0x1234 will cause dropping of the packet. + For outgoing packets, there is a serious problem with the + format/length */ + return ipINVALID_LENGTH; + } + if( ucProtocol <= ( uint8_t ) ipPROTOCOL_IGMP ) + { + /* ICMP/IGMP do not have a pseudo header for CRC-calculation. */ + usChecksum = ( uint16_t ) + ( ~usGenerateChecksum( 0UL, + ( uint8_t * ) &( pxProtPack->xTCPPacket.xTCPHeader ), ( size_t ) ulLength ) ); + } + else + { + /* For UDP and TCP, sum the pseudo header, i.e. IP protocol + length + fields */ + usChecksum = ( uint16_t ) ( ulLength + ( ( uint16_t ) ucProtocol ) ); + + /* And then continue at the IPv4 source and destination addresses. */ + usChecksum = ( uint16_t ) + ( ~usGenerateChecksum( ( uint32_t ) usChecksum, ( uint8_t * )&( pxIPPacket->xIPHeader.ulSourceIPAddress ), + ( 2u * sizeof( pxIPPacket->xIPHeader.ulSourceIPAddress ) + ulLength ) ) ); + + /* Sum TCP header and data. */ + } + + if( xOutgoingPacket == pdFALSE ) + { + /* This is in incoming packet. If the CRC is correct, it should be zero. */ + if( usChecksum == 0u ) + { + usChecksum = ( uint16_t )ipCORRECT_CRC; + } + } + else + { + if( ( usChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) ) + { + /* In case of UDP, a calculated checksum of 0x0000 is transmitted + as 0xffff. A value of zero would mean that the checksum is not used. */ + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + if( xOutgoingPacket != pdFALSE ) + { + FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: crc swap: %04X\n", pcType, usChecksum ) ); + } + } + #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ + + usChecksum = ( uint16_t )0xffffu; + } + } + usChecksum = FreeRTOS_htons( usChecksum ); + + if( xOutgoingPacket != pdFALSE ) + { + *( pusChecksum ) = usChecksum; + } + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + else if( ( xOutgoingPacket == pdFALSE ) && ( usChecksum != ipCORRECT_CRC ) ) + { + FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: ID %04X: from %lxip to %lxip bad crc: %04X\n", + pcType, + FreeRTOS_ntohs( pxIPPacket->xIPHeader.usIdentification ), + FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulSourceIPAddress ), + FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulDestinationIPAddress ), + FreeRTOS_ntohs( *pusChecksum ) ) ); + } + #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ + + return usChecksum; +} +/*-----------------------------------------------------------*/ + +/** + * This method generates a checksum for a given IPv4 header, per RFC791 (page 14). + * The checksum algorithm is decribed as: + * "[T]he 16 bit one's complement of the one's complement sum of all 16 bit words in the + * header. For purposes of computing the checksum, the value of the checksum field is zero." + * + * In a nutshell, that means that each 16-bit 'word' must be summed, after which + * the number of 'carries' (overflows) is added to the result. If that addition + * produces an overflow, that 'carry' must also be added to the final result. The final checksum + * should be the bitwise 'not' (ones-complement) of the result if the packet is + * meant to be transmitted, but this method simply returns the raw value, probably + * because when a packet is received, the checksum is verified by checking that + * ((received & calculated) == 0) without applying a bitwise 'not' to the 'calculated' checksum. + * + * This logic is optimized for microcontrollers which have limited resources, so the logic looks odd. + * It iterates over the full range of 16-bit words, but it does so by processing several 32-bit + * words at once whenever possible. Its first step is to align the memory pointer to a 32-bit boundary, + * after which it runs a fast loop to process multiple 32-bit words at once and adding their 'carries'. + * Finally, it finishes up by processing any remaining 16-bit words, and adding up all of the 'carries'. + * With 32-bit arithmetic, the number of 16-bit 'carries' produced by sequential additions can be found + * by looking at the 16 most-significant bits of the 32-bit integer, since a 32-bit int will continue + * counting up instead of overflowing after 16 bits. That is why the actual checksum calculations look like: + * union.u32 = ( uint32_t ) union.u16[ 0 ] + union.u16[ 1 ]; + * + * Arguments: + * ulSum: This argument provides a value to initialize the progressive summation + * of the header's values to. It is often 0, but protocols like TCP or UDP + * can have pseudo-header fields which need to be included in the checksum. + * pucNextData: This argument contains the address of the first byte which this + * method should process. The method's memory iterator is initialized to this value. + * uxDataLengthBytes: This argument contains the number of bytes that this method + * should process. + */ +uint16_t usGenerateChecksum( uint32_t ulSum, const uint8_t * pucNextData, size_t uxDataLengthBytes ) +{ +xUnion32 xSum2, xSum, xTerm; +xUnionPtr xSource; /* Points to first byte */ +xUnionPtr xLastSource; /* Points to last byte plus one */ +uint32_t ulAlignBits, ulCarry = 0ul; + + /* Small MCUs often spend up to 30% of the time doing checksum calculations + This function is optimised for 32-bit CPUs; Each time it will try to fetch + 32-bits, sums it with an accumulator and counts the number of carries. */ + + /* Swap the input (little endian platform only). */ + xSum.u32 = FreeRTOS_ntohs( ulSum ); + xTerm.u32 = 0ul; + + xSource.u8ptr = ( uint8_t * ) pucNextData; + ulAlignBits = ( ( ( uint32_t ) pucNextData ) & 0x03u ); /* gives 0, 1, 2, or 3 */ + + /* If byte (8-bit) aligned... */ + if( ( ( ulAlignBits & 1ul ) != 0ul ) && ( uxDataLengthBytes >= ( size_t ) 1 ) ) + { + xTerm.u8[ 1 ] = *( xSource.u8ptr ); + ( xSource.u8ptr )++; + uxDataLengthBytes--; + /* Now xSource is word (16-bit) aligned. */ + } + + /* If half-word (16-bit) aligned... */ + if( ( ( ulAlignBits == 1u ) || ( ulAlignBits == 2u ) ) && ( uxDataLengthBytes >= 2u ) ) + { + xSum.u32 += *(xSource.u16ptr); + ( xSource.u16ptr )++; + uxDataLengthBytes -= 2u; + /* Now xSource is word (32-bit) aligned. */ + } + + /* Word (32-bit) aligned, do the most part. */ + xLastSource.u32ptr = ( xSource.u32ptr + ( uxDataLengthBytes / 4u ) ) - 3u; + + /* In this loop, four 32-bit additions will be done, in total 16 bytes. + Indexing with constants (0,1,2,3) gives faster code than using + post-increments. */ + while( xSource.u32ptr < xLastSource.u32ptr ) + { + /* Use a secondary Sum2, just to see if the addition produced an + overflow. */ + xSum2.u32 = xSum.u32 + xSource.u32ptr[ 0 ]; + if( xSum2.u32 < xSum.u32 ) + { + ulCarry++; + } + + /* Now add the secondary sum to the major sum, and remember if there was + a carry. */ + xSum.u32 = xSum2.u32 + xSource.u32ptr[ 1 ]; + if( xSum2.u32 > xSum.u32 ) + { + ulCarry++; + } + + /* And do the same trick once again for indexes 2 and 3 */ + xSum2.u32 = xSum.u32 + xSource.u32ptr[ 2 ]; + if( xSum2.u32 < xSum.u32 ) + { + ulCarry++; + } + + xSum.u32 = xSum2.u32 + xSource.u32ptr[ 3 ]; + + if( xSum2.u32 > xSum.u32 ) + { + ulCarry++; + } + + /* And finally advance the pointer 4 * 4 = 16 bytes. */ + xSource.u32ptr += 4; + } + + /* Now add all carries. */ + xSum.u32 = ( uint32_t )xSum.u16[ 0 ] + xSum.u16[ 1 ] + ulCarry; + + uxDataLengthBytes %= 16u; + xLastSource.u8ptr = ( uint8_t * ) ( xSource.u8ptr + ( uxDataLengthBytes & ~( ( size_t ) 1 ) ) ); + + /* Half-word aligned. */ + while( xSource.u16ptr < xLastSource.u16ptr ) + { + /* At least one more short. */ + xSum.u32 += xSource.u16ptr[ 0 ]; + xSource.u16ptr++; + } + + if( ( uxDataLengthBytes & ( size_t ) 1 ) != 0u ) /* Maybe one more ? */ + { + xTerm.u8[ 0 ] = xSource.u8ptr[ 0 ]; + } + xSum.u32 += xTerm.u32; + + /* Now add all carries again. */ + xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ]; + + /* The previous summation might have given a 16-bit carry. */ + xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ]; + + if( ( ulAlignBits & 1u ) != 0u ) + { + /* Quite unlikely, but pucNextData might be non-aligned, which would + mean that a checksum is calculated starting at an odd position. */ + xSum.u32 = ( ( xSum.u32 & 0xffu ) << 8 ) | ( ( xSum.u32 & 0xff00u ) >> 8 ); + } + + /* swap the output (little endian platform only). */ + return FreeRTOS_htons( ( (uint16_t) xSum.u32 ) ); +} +/*-----------------------------------------------------------*/ + +void vReturnEthernetFrame( NetworkBufferDescriptor_t * pxNetworkBuffer, BaseType_t xReleaseAfterSend ) +{ +EthernetHeader_t *pxEthernetHeader; + +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + NetworkBufferDescriptor_t *pxNewBuffer; +#endif + + #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES ) + { + if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES ) + { + BaseType_t xIndex; + + FreeRTOS_printf( ( "vReturnEthernetFrame: length %lu\n", ( uint32_t )pxNetworkBuffer->xDataLength ) ); + for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ ) + { + pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u; + } + pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; + } + } + #endif + +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + + if( xReleaseAfterSend == pdFALSE ) + { + pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength ); + xReleaseAfterSend = pdTRUE; + pxNetworkBuffer = pxNewBuffer; + } + + if( pxNetworkBuffer != NULL ) +#endif + { + pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); + + /* Swap source and destination MAC addresses. */ + memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ), sizeof( pxEthernetHeader->xDestinationAddress ) ); + memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES ); + + /* Send! */ + xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend ); + } +} +/*-----------------------------------------------------------*/ + +uint32_t FreeRTOS_GetIPAddress( void ) +{ + /* Returns the IP address of the NIC. */ + return *ipLOCAL_IP_ADDRESS_POINTER; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_SetIPAddress( uint32_t ulIPAddress ) +{ + /* Sets the IP address of the NIC. */ + *ipLOCAL_IP_ADDRESS_POINTER = ulIPAddress; +} +/*-----------------------------------------------------------*/ + +uint32_t FreeRTOS_GetGatewayAddress( void ) +{ + return xNetworkAddressing.ulGatewayAddress; +} +/*-----------------------------------------------------------*/ + +uint32_t FreeRTOS_GetDNSServerAddress( void ) +{ + return xNetworkAddressing.ulDNSServerAddress; +} +/*-----------------------------------------------------------*/ + +uint32_t FreeRTOS_GetNetmask( void ) +{ + return xNetworkAddressing.ulNetMask; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ipMAC_ADDRESS_LENGTH_BYTES] ) +{ + /* Copy the MAC address at the start of the default packet header fragment. */ + memcpy( ( void * )ipLOCAL_MAC_ADDRESS, ( void * )ucMACAddress, ( size_t )ipMAC_ADDRESS_LENGTH_BYTES ); +} +/*-----------------------------------------------------------*/ + +const uint8_t * FreeRTOS_GetMACAddress( void ) +{ + return ipLOCAL_MAC_ADDRESS; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_SetNetmask ( uint32_t ulNetmask ) +{ + xNetworkAddressing.ulNetMask = ulNetmask; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_SetGatewayAddress ( uint32_t ulGatewayAddress ) +{ + xNetworkAddressing.ulGatewayAddress = ulGatewayAddress; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_DHCP == 1 ) + void vIPSetDHCPTimerEnableState( BaseType_t xEnableState ) + { + if( xEnableState != pdFALSE ) + { + xDHCPTimer.bActive = pdTRUE_UNSIGNED; + } + else + { + xDHCPTimer.bActive = pdFALSE_UNSIGNED; + } + } +#endif /* ipconfigUSE_DHCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_DHCP == 1 ) + void vIPReloadDHCPTimer( uint32_t ulLeaseTime ) + { + prvIPTimerReload( &xDHCPTimer, ulLeaseTime ); + } +#endif /* ipconfigUSE_DHCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigDNS_USE_CALLBACKS == 1 ) + void vIPSetDnsTimerEnableState( BaseType_t xEnableState ) + { + if( xEnableState != 0 ) + { + xDNSTimer.bActive = pdTRUE; + } + else + { + xDNSTimer.bActive = pdFALSE; + } + } +#endif /* ipconfigUSE_DHCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigDNS_USE_CALLBACKS != 0 ) + void vIPReloadDNSTimer( uint32_t ulCheckTime ) + { + prvIPTimerReload( &xDNSTimer, ulCheckTime ); + } +#endif /* ipconfigDNS_USE_CALLBACKS != 0 */ +/*-----------------------------------------------------------*/ + +BaseType_t xIPIsNetworkTaskReady( void ) +{ + return xIPTaskInitialised; +} +/*-----------------------------------------------------------*/ + +BaseType_t FreeRTOS_IsNetworkUp( void ) +{ + return xNetworkUp; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + UBaseType_t uxGetMinimumIPQueueSpace( void ) + { + return uxQueueMinimumSpace; + } +#endif +/*-----------------------------------------------------------*/ + +/* Provide access to private members for verification. */ +#ifdef FREERTOS_TCP_ENABLE_VERIFICATION + #include "aws_freertos_ip_verification_access_ip_define.h" +#endif + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c new file mode 100644 index 000000000..13feb832a --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c @@ -0,0 +1,3703 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_DNS.h" +#include "NetworkBufferManagement.h" + +/* The ItemValue of the sockets xBoundSocketListItem member holds the socket's +port number. */ +#define socketSET_SOCKET_PORT( pxSocket, usPort ) listSET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ), ( usPort ) ) +#define socketGET_SOCKET_PORT( pxSocket ) listGET_LIST_ITEM_VALUE( ( &( ( pxSocket )->xBoundSocketListItem ) ) ) + +/* Test if a socket it bound which means it is either included in +xBoundUDPSocketsList or xBoundTCPSocketsList */ +#define socketSOCKET_IS_BOUND( pxSocket ) ( listLIST_ITEM_CONTAINER( & ( pxSocket )->xBoundSocketListItem ) != NULL ) + +/* If FreeRTOS_sendto() is called on a socket that is not bound to a port +number then, depending on the FreeRTOSIPConfig.h settings, it might be that a +port number is automatically generated for the socket. Automatically generated +port numbers will be between socketAUTO_PORT_ALLOCATION_START_NUMBER and +0xffff. + +Per https://tools.ietf.org/html/rfc6056, "the dynamic ports consist of the range +49152-65535. However, ephemeral port selection algorithms should use the whole +range 1024-65535" excluding those already in use (inbound or outbound). */ +#if !defined( socketAUTO_PORT_ALLOCATION_START_NUMBER ) + #define socketAUTO_PORT_ALLOCATION_START_NUMBER ( ( uint16_t ) 0x0400 ) +#endif + +#define socketAUTO_PORT_ALLOCATION_MAX_NUMBER ( ( uint16_t ) 0xffff ) + +/* The number of octets that make up an IP address. */ +#define socketMAX_IP_ADDRESS_OCTETS 4u + +/* A block time of 0 simply means "don't block". */ +#define socketDONT_BLOCK ( ( TickType_t ) 0 ) + +#if( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) ) + #define ipTCP_TIMER_PERIOD_MS ( 1000 ) +#endif + +/* The next private port number to use when binding a client socket is stored in +the usNextPortToUse[] array - which has either 1 or two indexes depending on +whether TCP is being supported. */ +#if( ipconfigUSE_TCP == 1 ) + #define socketPROTOCOL_COUNT 2 +#else + #define socketPROTOCOL_COUNT 1 +#endif + +/* Indexes into the usNextPortToUse[] array for UDP and TCP sockets +respectively. */ +#define socketNEXT_UDP_PORT_NUMBER_INDEX 0 +#define socketNEXT_TCP_PORT_NUMBER_INDEX 1 + +/* Some helper macro's for defining the 20/80 % limits of uxLittleSpace / uxEnoughSpace. */ +#define sock20_PERCENT 20 +#define sock80_PERCENT 80 +#define sock100_PERCENT 100 + + +/*-----------------------------------------------------------*/ + +/* + * Allocate the next port number from the private allocation range. + * TCP and UDP each have their own series of port numbers + * ulProtocol is either ipPROTOCOL_UDP or ipPROTOCOL_TCP + */ +static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol ); + +/* + * Return the list item from within pxList that has an item value of + * xWantedItemValue. If there is no such list item return NULL. + */ +static const ListItem_t * pxListFindListItemWithValue( const List_t *pxList, TickType_t xWantedItemValue ); + +/* + * Return pdTRUE only if pxSocket is valid and bound, as far as can be + * determined. + */ +static BaseType_t prvValidSocket( FreeRTOS_Socket_t *pxSocket, BaseType_t xProtocol, BaseType_t xIsBound ); + +/* + * Before creating a socket, check the validity of the parameters used + * and find the size of the socket space, which is different for UDP and TCP + */ +static BaseType_t prvDetermineSocketSize( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol, size_t *pxSocketSize ); + +#if( ipconfigUSE_TCP == 1 ) + /* + * Create a txStream or a rxStream, depending on the parameter 'xIsInputStream' + */ + static StreamBuffer_t *prvTCPCreateStream (FreeRTOS_Socket_t *pxSocket, BaseType_t xIsInputStream ); +#endif /* ipconfigUSE_TCP == 1 */ + +#if( ipconfigUSE_TCP == 1 ) + /* + * Called from FreeRTOS_send(): some checks which will be done before + * sending a TCP packed. + */ + static int32_t prvTCPSendCheck( FreeRTOS_Socket_t *pxSocket, size_t xDataLength ); +#endif /* ipconfigUSE_TCP */ + +#if( ipconfigUSE_TCP == 1 ) + /* + * When a child socket gets closed, make sure to update the child-count of the parent + */ + static void prvTCPSetSocketCount( FreeRTOS_Socket_t *pxSocketToDelete ); +#endif /* ipconfigUSE_TCP == 1 */ + +#if( ipconfigUSE_TCP == 1 ) + /* + * Called from FreeRTOS_connect(): make some checks and if allowed, send a + * message to the IP-task to start connecting to a remote socket + */ + static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr *pxAddress ); +#endif /* ipconfigUSE_TCP */ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + /* Executed by the IP-task, it will check all sockets belonging to a set */ + static FreeRTOS_Socket_t *prvFindSelectedSocket( SocketSelect_t *pxSocketSet ); + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + +/* The list that contains mappings between sockets and port numbers. Accesses +to this list must be protected by critical sections of one kind or another. */ +List_t xBoundUDPSocketsList; + +#if ipconfigUSE_TCP == 1 + List_t xBoundTCPSocketsList; +#endif /* ipconfigUSE_TCP == 1 */ + +/*-----------------------------------------------------------*/ + +static BaseType_t prvValidSocket( FreeRTOS_Socket_t *pxSocket, BaseType_t xProtocol, BaseType_t xIsBound ) +{ +BaseType_t xReturn = pdTRUE; + + if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) ) + { + xReturn = pdFALSE; + } + else if( ( xIsBound != pdFALSE ) && ( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE ) ) + { + /* The caller expects the socket to be bound, but it isn't. */ + xReturn = pdFALSE; + } + else if( pxSocket->ucProtocol != ( uint8_t ) xProtocol ) + { + /* Socket has a wrong type (UDP != TCP). */ + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t vNetworkSocketsInit( void ) +{ + vListInitialise( &xBoundUDPSocketsList ); + + #if( ipconfigUSE_TCP == 1 ) + { + vListInitialise( &xBoundTCPSocketsList ); + } + #endif /* ipconfigUSE_TCP == 1 */ + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvDetermineSocketSize( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol, size_t *pxSocketSize ) +{ +BaseType_t xReturn = pdPASS; +FreeRTOS_Socket_t *pxSocket; + + /* Asserts must not appear before it has been determined that the network + task is ready - otherwise the asserts will fail. */ + if( xIPIsNetworkTaskReady() == pdFALSE ) + { + xReturn = pdFAIL; + } + else + { + /* Only Ethernet is currently supported. */ + configASSERT( xDomain == FREERTOS_AF_INET ); + + /* Check if the UDP socket-list has been initialised. */ + configASSERT( listLIST_IS_INITIALISED( &xBoundUDPSocketsList ) ); + #if( ipconfigUSE_TCP == 1 ) + { + /* Check if the TCP socket-list has been initialised. */ + configASSERT( listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) ); + } + #endif /* ipconfigUSE_TCP == 1 */ + + if( xProtocol == FREERTOS_IPPROTO_UDP ) + { + if( xType != FREERTOS_SOCK_DGRAM ) + { + xReturn = pdFAIL; + configASSERT( xReturn ); + } + /* In case a UDP socket is created, do not allocate space for TCP data. */ + *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xUDP ); + } +#if( ipconfigUSE_TCP == 1 ) + else if( xProtocol == FREERTOS_IPPROTO_TCP ) + { + if( xType != FREERTOS_SOCK_STREAM ) + { + xReturn = pdFAIL; + configASSERT( xReturn ); + } + + *pxSocketSize = ( sizeof( *pxSocket ) - sizeof( pxSocket->u ) ) + sizeof( pxSocket->u.xTCP ); + } +#endif /* ipconfigUSE_TCP == 1 */ + else + { + xReturn = pdFAIL; + configASSERT( xReturn ); + } + } + /* In case configASSERT() is not used */ + ( void )xDomain; + return xReturn; +} +/*-----------------------------------------------------------*/ + +/* FreeRTOS_socket() allocates and initiates a socket */ +Socket_t FreeRTOS_socket( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol ) +{ +FreeRTOS_Socket_t *pxSocket; +size_t uxSocketSize; +EventGroupHandle_t xEventGroup; +Socket_t xReturn; + + if( prvDetermineSocketSize( xDomain, xType, xProtocol, &uxSocketSize ) == pdFAIL ) + { + xReturn = FREERTOS_INVALID_SOCKET; + } + else + { + /* Allocate the structure that will hold the socket information. The + size depends on the type of socket: UDP sockets need less space. A + define 'pvPortMallocSocket' will used to allocate the necessary space. + By default it points to the FreeRTOS function 'pvPortMalloc()'. */ + pxSocket = ( FreeRTOS_Socket_t * ) pvPortMallocSocket( uxSocketSize ); + + if( pxSocket == NULL ) + { + pxSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET; + iptraceFAILED_TO_CREATE_SOCKET(); + } + else if( ( xEventGroup = xEventGroupCreate() ) == NULL ) + { + vPortFreeSocket( pxSocket ); + pxSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET; + iptraceFAILED_TO_CREATE_EVENT_GROUP(); + } + else + { + /* Clear the entire space to avoid nulling individual entries */ + memset( pxSocket, '\0', uxSocketSize ); + + pxSocket->xEventGroup = xEventGroup; + + /* Initialise the socket's members. The semaphore will be created + if the socket is bound to an address, for now the pointer to the + semaphore is just set to NULL to show it has not been created. */ + if( xProtocol == FREERTOS_IPPROTO_UDP ) + { + vListInitialise( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); + + #if( ipconfigUDP_MAX_RX_PACKETS > 0 ) + { + pxSocket->u.xUDP.uxMaxPackets = ( UBaseType_t ) ipconfigUDP_MAX_RX_PACKETS; + } + #endif /* ipconfigUDP_MAX_RX_PACKETS > 0 */ + } + + vListInitialiseItem( &( pxSocket->xBoundSocketListItem ) ); + listSET_LIST_ITEM_OWNER( &( pxSocket->xBoundSocketListItem ), ( void * ) pxSocket ); + + pxSocket->xReceiveBlockTime = ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME; + pxSocket->xSendBlockTime = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME; + pxSocket->ucSocketOptions = ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT; + pxSocket->ucProtocol = ( uint8_t ) xProtocol; /* protocol: UDP or TCP */ + + #if( ipconfigUSE_TCP == 1 ) + { + if( xProtocol == FREERTOS_IPPROTO_TCP ) + { + /* StreamSize is expressed in number of bytes */ + /* Round up buffer sizes to nearest multiple of MSS */ + pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ipconfigTCP_MSS; + pxSocket->u.xTCP.uxRxStreamSize = ( size_t ) ipconfigTCP_RX_BUFFER_LENGTH; + pxSocket->u.xTCP.uxTxStreamSize = ( size_t ) FreeRTOS_round_up( ipconfigTCP_TX_BUFFER_LENGTH, ipconfigTCP_MSS ); + /* Use half of the buffer size of the TCP windows */ + #if ( ipconfigUSE_TCP_WIN == 1 ) + { + pxSocket->u.xTCP.uxRxWinSize = FreeRTOS_max_uint32( 1UL, ( uint32_t ) ( pxSocket->u.xTCP.uxRxStreamSize / 2 ) / ipconfigTCP_MSS ); + pxSocket->u.xTCP.uxTxWinSize = FreeRTOS_max_uint32( 1UL, ( uint32_t ) ( pxSocket->u.xTCP.uxTxStreamSize / 2 ) / ipconfigTCP_MSS ); + } + #else + { + pxSocket->u.xTCP.uxRxWinSize = 1u; + pxSocket->u.xTCP.uxTxWinSize = 1u; + } + #endif + /* The above values are just defaults, and can be overridden by + calling FreeRTOS_setsockopt(). No buffers will be allocated until a + socket is connected and data is exchanged. */ + } + } + #endif /* ipconfigUSE_TCP == 1 */ + } + + xReturn = ( Socket_t ) pxSocket; + } + + /* Remove compiler warnings in the case the configASSERT() is not defined. */ + ( void ) xDomain; + + return xReturn; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + SocketSet_t FreeRTOS_CreateSocketSet( void ) + { + SocketSelect_t *pxSocketSet; + + pxSocketSet = ( SocketSelect_t * ) pvPortMalloc( sizeof( *pxSocketSet ) ); + + if( pxSocketSet != NULL ) + { + memset( pxSocketSet, '\0', sizeof( *pxSocketSet ) ); + pxSocketSet->xSelectGroup = xEventGroupCreate(); + + if( pxSocketSet->xSelectGroup == NULL ) + { + vPortFree( ( void* ) pxSocketSet ); + pxSocketSet = NULL; + } + } + + return ( SocketSet_t * ) pxSocketSet; + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + void FreeRTOS_DeleteSocketSet( SocketSet_t xSocketSet ) + { + SocketSelect_t *pxSocketSet = ( SocketSelect_t*) xSocketSet; + + vEventGroupDelete( pxSocketSet->xSelectGroup ); + vPortFree( ( void* ) pxSocketSet ); + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + /* Add a socket to a set */ + void FreeRTOS_FD_SET( Socket_t xSocket, SocketSet_t xSocketSet, EventBits_t xSelectBits ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + SocketSelect_t *pxSocketSet = ( SocketSelect_t * ) xSocketSet; + + configASSERT( pxSocket != NULL ); + configASSERT( xSocketSet != NULL ); + + /* Make sure we're not adding bits which are reserved for internal use, + such as eSELECT_CALL_IP */ + pxSocket->xSelectBits |= ( xSelectBits & eSELECT_ALL ); + + if( ( pxSocket->xSelectBits & eSELECT_ALL ) != 0 ) + { + /* Adding a socket to a socket set. */ + pxSocket->pxSocketSet = ( SocketSelect_t * ) xSocketSet; + + /* Now have the IP-task call vSocketSelect() to see if the set contains + any sockets which are 'ready' and set the proper bits. + By setting 'bApiCalled = false', vSocketSelect() knows that it was + not called from a user API */ + pxSocketSet->bApiCalled = pdFALSE; + prvFindSelectedSocket( pxSocketSet ); + } + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + /* Clear select bits for a socket + If the mask becomes 0, remove the socket from the set */ + void FreeRTOS_FD_CLR( Socket_t xSocket, SocketSet_t xSocketSet, EventBits_t xSelectBits ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + + configASSERT( pxSocket != NULL ); + configASSERT( xSocketSet != NULL ); + + pxSocket->xSelectBits &= ~( xSelectBits & eSELECT_ALL ); + if( ( pxSocket->xSelectBits & eSELECT_ALL ) != 0 ) + { + pxSocket->pxSocketSet = ( SocketSelect_t *)xSocketSet; + } + else + { + /* disconnect it from the socket set */ + pxSocket->pxSocketSet = ( SocketSelect_t *)NULL; + } + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + /* Test if a socket belongs to a socket-set */ + EventBits_t FreeRTOS_FD_ISSET( Socket_t xSocket, SocketSet_t xSocketSet ) + { + EventBits_t xReturn; + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + + configASSERT( pxSocket != NULL ); + configASSERT( xSocketSet != NULL ); + + if( xSocketSet == ( SocketSet_t ) pxSocket->pxSocketSet ) + { + /* Make sure we're not adding bits which are reserved for internal + use. */ + xReturn = pxSocket->xSocketBits & eSELECT_ALL; + } + else + { + xReturn = 0; + } + + return xReturn; + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + /* The select() statement: wait for an event to occur on any of the sockets + included in a socket set */ + BaseType_t FreeRTOS_select( SocketSet_t xSocketSet, TickType_t xBlockTimeTicks ) + { + TimeOut_t xTimeOut; + TickType_t xRemainingTime; + SocketSelect_t *pxSocketSet = ( SocketSelect_t*) xSocketSet; + BaseType_t xResult; + + configASSERT( xSocketSet != NULL ); + + /* Only in the first round, check for non-blocking */ + xRemainingTime = xBlockTimeTicks; + + /* Fetch the current time */ + vTaskSetTimeOutState( &xTimeOut ); + + for( ;; ) + { + /* Find a socket which might have triggered the bit + This function might return immediately or block for a limited time */ + xResult = ( BaseType_t ) xEventGroupWaitBits( pxSocketSet->xSelectGroup, eSELECT_ALL, pdFALSE, pdFALSE, xRemainingTime ); + + #if( ipconfigSUPPORT_SIGNALS != 0 ) + { + if( ( xResult & eSELECT_INTR ) != 0u ) + { + xEventGroupClearBits( pxSocketSet->xSelectGroup, eSELECT_INTR ); + FreeRTOS_debug_printf( ( "FreeRTOS_select: interrupted\n" ) ); + break; + } + } + #endif /* ipconfigSUPPORT_SIGNALS */ + + /* Have the IP-task find the socket which had an event */ + pxSocketSet->bApiCalled = pdTRUE; + prvFindSelectedSocket( pxSocketSet ); + + xResult = ( BaseType_t ) xEventGroupGetBits( pxSocketSet->xSelectGroup ); + + if( xResult != 0 ) + { + break; + } + + /* Has the timeout been reached? */ + if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE ) + { + break; + } + } + + return xResult; + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + /* Send a message to the IP-task to have it check all sockets belonging to + 'pxSocketSet' */ + static FreeRTOS_Socket_t *prvFindSelectedSocket( SocketSelect_t *pxSocketSet ) + { + IPStackEvent_t xSelectEvent; + FreeRTOS_Socket_t *xReturn; + + xSelectEvent.eEventType = eSocketSelectEvent; + xSelectEvent.pvData = ( void * ) pxSocketSet; + + /* while the IP-task works on the request, the API will block on + 'eSELECT_CALL_IP'. So clear it first. */ + xEventGroupClearBits( pxSocketSet->xSelectGroup, eSELECT_CALL_IP ); + + /* Now send the socket select event */ + if( xSendEventStructToIPTask( &xSelectEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL ) + { + /* Oops, we failed to wake-up the IP task. No use to wait for it. */ + FreeRTOS_debug_printf( ( "prvFindSelectedSocket: failed\n" ) ); + xReturn = NULL; + } + else + { + /* As soon as the IP-task is ready, it will set 'eSELECT_CALL_IP' to + wakeup the calling API */ + xEventGroupWaitBits( pxSocketSet->xSelectGroup, eSELECT_CALL_IP, pdTRUE, pdFALSE, portMAX_DELAY ); + + /* Return 'pxSocket' which is set by the IP-task */ + xReturn = pxSocketSet->pxSocket; + } + + return xReturn; + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + +/* + * FreeRTOS_recvfrom: receive data from a bound socket + * In this library, the function can only be used with connectionsless sockets + * (UDP) + */ +int32_t FreeRTOS_recvfrom( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength ) +{ +BaseType_t lPacketCount = 0; +NetworkBufferDescriptor_t *pxNetworkBuffer; +FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; +TickType_t xRemainingTime = ( TickType_t ) 0; /* Obsolete assignment, but some compilers output a warning if its not done. */ +BaseType_t xTimed = pdFALSE; +TimeOut_t xTimeOut; +int32_t lReturn; +EventBits_t xEventBits = ( EventBits_t ) 0; + + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_UDP, pdTRUE ) == pdFALSE ) + { + return -pdFREERTOS_ERRNO_EINVAL; + } + + lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); + + /* The function prototype is designed to maintain the expected Berkeley + sockets standard, but this implementation does not use all the parameters. */ + ( void ) pxSourceAddressLength; + + while( lPacketCount == 0 ) + { + if( xTimed == pdFALSE ) + { + /* Check to see if the socket is non blocking on the first + iteration. */ + xRemainingTime = pxSocket->xReceiveBlockTime; + + if( xRemainingTime == ( TickType_t ) 0 ) + { + #if( ipconfigSUPPORT_SIGNALS != 0 ) + { + /* Just check for the interrupt flag. */ + xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_INTR, + pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK ); + } + #endif /* ipconfigSUPPORT_SIGNALS */ + break; + } + + if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 ) + { + break; + } + + /* To ensure this part only executes once. */ + xTimed = pdTRUE; + + /* Fetch the current time. */ + vTaskSetTimeOutState( &xTimeOut ); + } + + /* Wait for arrival of data. While waiting, the IP-task may set the + 'eSOCKET_RECEIVE' bit in 'xEventGroup', if it receives data for this + socket, thus unblocking this API call. */ + xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_RECEIVE | eSOCKET_INTR, + pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); + + #if( ipconfigSUPPORT_SIGNALS != 0 ) + { + if( ( xEventBits & eSOCKET_INTR ) != 0 ) + { + if( ( xEventBits & eSOCKET_RECEIVE ) != 0 ) + { + /* Shouldn't have cleared the eSOCKET_RECEIVE flag. */ + xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_RECEIVE ); + } + break; + } + } + #else + { + ( void ) xEventBits; + } + #endif /* ipconfigSUPPORT_SIGNALS */ + + lPacketCount = ( BaseType_t ) listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); + + if( lPacketCount != 0 ) + { + break; + } + + /* Has the timeout been reached ? */ + if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) ) + { + break; + } + } /* while( lPacketCount == 0 ) */ + + if( lPacketCount != 0 ) + { + taskENTER_CRITICAL(); + { + /* The owner of the list item is the network buffer. */ + pxNetworkBuffer = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); + + if( ( xFlags & FREERTOS_MSG_PEEK ) == 0 ) + { + /* Remove the network buffer from the list of buffers waiting to + be processed by the socket. */ + uxListRemove( &( pxNetworkBuffer->xBufferListItem ) ); + } + } + taskEXIT_CRITICAL(); + + /* The returned value is the data length, which may have been capped to + the receive buffer size. */ + lReturn = ( int32_t ) pxNetworkBuffer->xDataLength; + + if( pxSourceAddress != NULL ) + { + pxSourceAddress->sin_port = pxNetworkBuffer->usPort; + pxSourceAddress->sin_addr = pxNetworkBuffer->ulIPAddress; + } + + if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 ) + { + /* The zero copy flag is not set. Truncate the length if it won't + fit in the provided buffer. */ + if( lReturn > ( int32_t ) xBufferLength ) + { + iptraceRECVFROM_DISCARDING_BYTES( ( xBufferLength - lReturn ) ); + lReturn = ( int32_t )xBufferLength; + } + + /* Copy the received data into the provided buffer, then release the + network buffer. */ + memcpy( pvBuffer, ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ), ( size_t )lReturn ); + + if( ( xFlags & FREERTOS_MSG_PEEK ) == 0 ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + } + else + { + /* The zero copy flag was set. pvBuffer is not a buffer into which + the received data can be copied, but a pointer that must be set to + point to the buffer in which the received data has already been + placed. */ + *( ( void** ) pvBuffer ) = ( void * ) ( &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ) ); + } + + } +#if( ipconfigSUPPORT_SIGNALS != 0 ) + else if( ( xEventBits & eSOCKET_INTR ) != 0 ) + { + lReturn = -pdFREERTOS_ERRNO_EINTR; + iptraceRECVFROM_INTERRUPTED(); + } +#endif /* ipconfigSUPPORT_SIGNALS */ + else + { + lReturn = -pdFREERTOS_ERRNO_EWOULDBLOCK; + iptraceRECVFROM_TIMEOUT(); + } + + return lReturn; +} +/*-----------------------------------------------------------*/ + +int32_t FreeRTOS_sendto( Socket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, BaseType_t xFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength ) +{ +NetworkBufferDescriptor_t *pxNetworkBuffer; +IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL }; +TimeOut_t xTimeOut; +TickType_t xTicksToWait; +int32_t lReturn = 0; +FreeRTOS_Socket_t *pxSocket; + + pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + + /* The function prototype is designed to maintain the expected Berkeley + sockets standard, but this implementation does not use all the + parameters. */ + ( void ) xDestinationAddressLength; + configASSERT( pvBuffer ); + + if( xTotalDataLength <= ( size_t ) ipMAX_UDP_PAYLOAD_LENGTH ) + { + /* If the socket is not already bound to an address, bind it now. + Passing NULL as the address parameter tells FreeRTOS_bind() to select + the address to bind to. */ + if( ( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE ) || + ( FreeRTOS_bind( xSocket, NULL, 0u ) == 0 ) ) + { + xTicksToWait = pxSocket->xSendBlockTime; + + #if( ipconfigUSE_CALLBACKS != 0 ) + { + if( xIsCallingFromIPTask() != pdFALSE ) + { + /* If this send function is called from within a call-back + handler it may not block, otherwise chances would be big to + get a deadlock: the IP-task waiting for itself. */ + xTicksToWait = ( TickType_t )0; + } + } + #endif /* ipconfigUSE_CALLBACKS */ + + if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 ) + { + xTicksToWait = ( TickType_t ) 0; + } + + if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 ) + { + /* Zero copy is not set, so obtain a network buffer into + which the payload will be copied. */ + vTaskSetTimeOutState( &xTimeOut ); + + /* Block until a buffer becomes available, or until a + timeout has been reached */ + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( xTotalDataLength + sizeof( UDPPacket_t ), xTicksToWait ); + + if( pxNetworkBuffer != NULL ) + { + memcpy( ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ), ( void * ) pvBuffer, xTotalDataLength ); + + if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdTRUE ) + { + /* The entire block time has been used up. */ + xTicksToWait = ( TickType_t ) 0; + } + } + } + else + { + /* When zero copy is used, pvBuffer is a pointer to the + payload of a buffer that has already been obtained from the + stack. Obtain the network buffer pointer from the buffer. */ + pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( (void*)pvBuffer ); + } + + if( pxNetworkBuffer != NULL ) + { + pxNetworkBuffer->xDataLength = xTotalDataLength; + pxNetworkBuffer->usPort = pxDestinationAddress->sin_port; + pxNetworkBuffer->usBoundPort = ( uint16_t ) socketGET_SOCKET_PORT( pxSocket ); + pxNetworkBuffer->ulIPAddress = pxDestinationAddress->sin_addr; + + /* The socket options are passed to the IP layer in the + space that will eventually get used by the Ethernet header. */ + pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = pxSocket->ucSocketOptions; + + /* Tell the networking task that the packet needs sending. */ + xStackTxEvent.pvData = pxNetworkBuffer; + + /* Ask the IP-task to send this packet */ + if( xSendEventStructToIPTask( &xStackTxEvent, xTicksToWait ) == pdPASS ) + { + /* The packet was successfully sent to the IP task. */ + lReturn = ( int32_t ) xTotalDataLength; + #if( ipconfigUSE_CALLBACKS == 1 ) + { + if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleSent ) ) + { + pxSocket->u.xUDP.pxHandleSent( (Socket_t *)pxSocket, xTotalDataLength ); + } + } + #endif /* ipconfigUSE_CALLBACKS */ + } + else + { + /* If the buffer was allocated in this function, release + it. */ + if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT ); + } + } + else + { + /* If errno was available, errno would be set to + FREERTOS_ENOPKTS. As it is, the function must return the + number of transmitted bytes, so the calling function knows + how much data was actually sent. */ + iptraceNO_BUFFER_FOR_SENDTO(); + } + } + else + { + iptraceSENDTO_SOCKET_NOT_BOUND(); + } + } + else + { + /* The data is longer than the available buffer space. */ + iptraceSENDTO_DATA_TOO_LONG(); + } + + return lReturn; +} /* Tested */ +/*-----------------------------------------------------------*/ + +/* + * FreeRTOS_bind() : binds a sockt to a local port number. If port 0 is + * provided, a system provided port number will be assigned. This function can + * be used for both UDP and TCP sockets. The actual binding will be performed + * by the IP-task to avoid mutual access to the bound-socket-lists + * (xBoundUDPSocketsList or xBoundTCPSocketsList). + */ +BaseType_t FreeRTOS_bind( Socket_t xSocket, struct freertos_sockaddr * pxAddress, socklen_t xAddressLength ) +{ +IPStackEvent_t xBindEvent; +FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; +BaseType_t xReturn = 0; + + ( void ) xAddressLength; + + if( ( pxSocket == NULL ) || ( pxSocket == FREERTOS_INVALID_SOCKET ) ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + /* Once a socket is bound to a port, it can not be bound to a different + port number */ + else if( socketSOCKET_IS_BOUND( pxSocket) != pdFALSE ) + { + /* The socket is already bound. */ + FreeRTOS_debug_printf( ( "vSocketBind: Socket already bound to %d\n", pxSocket->usLocalPort ) ); + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + /* Prepare a messages to the IP-task in order to perform the binding. + The desired port number will be passed in usLocalPort. */ + xBindEvent.eEventType = eSocketBindEvent; + xBindEvent.pvData = ( void * ) xSocket; + if( pxAddress != NULL ) + { + pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port ); + } + else + { + /* Caller wants to bind to a random port number. */ + pxSocket->usLocalPort = 0u; + } + + /* portMAX_DELAY is used as a the time-out parameter, as binding *must* + succeed before the socket can be used. _RB_ The use of an infinite + block time needs be changed as it could result in the task hanging. */ + if( xSendEventStructToIPTask( &xBindEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL ) + { + /* Failed to wake-up the IP-task, no use to wait for it */ + FreeRTOS_debug_printf( ( "FreeRTOS_bind: send event failed\n" ) ); + xReturn = -pdFREERTOS_ERRNO_ECANCELED; + } + else + { + /* The IP-task will set the 'eSOCKET_BOUND' bit when it has done its + job. */ + xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_BOUND, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, portMAX_DELAY ); + if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + } + } + + return xReturn; +} + +/* + * vSocketBind(): internal version of bind() that should not be called directly. + * 'xInternal' is used for TCP sockets only: it allows to have several + * (connected) child sockets bound to the same server port. + */ +BaseType_t vSocketBind( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr * pxAddress, size_t uxAddressLength, BaseType_t xInternal ) +{ +BaseType_t xReturn = 0; /* In Berkeley sockets, 0 means pass for bind(). */ +List_t *pxSocketList; +#if( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 ) + struct freertos_sockaddr xAddress; +#endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND */ + +#if( ipconfigUSE_TCP == 1 ) + if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + pxSocketList = &xBoundTCPSocketsList; + } + else +#endif /* ipconfigUSE_TCP == 1 */ + { + pxSocketList = &xBoundUDPSocketsList; + } + + /* The function prototype is designed to maintain the expected Berkeley + sockets standard, but this implementation does not use all the parameters. */ + ( void ) uxAddressLength; + + configASSERT( pxSocket ); + configASSERT( pxSocket != FREERTOS_INVALID_SOCKET ); + + #if( ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 ) + { + /* pxAddress will be NULL if sendto() was called on a socket without the + socket being bound to an address. In this case, automatically allocate + an address and port to the socket. */ + if( pxAddress == NULL ) + { + pxAddress = &xAddress; + /* Put the port to zero to be assigned later. */ + pxAddress->sin_port = 0u; + } + } + #endif /* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND == 1 */ + + /* Sockets must be bound before calling FreeRTOS_sendto() if + ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is not set to 1. */ + configASSERT( pxAddress ); + + if( pxAddress != NULL ) + { + if( pxAddress->sin_port == 0u ) + { + pxAddress->sin_port = prvGetPrivatePortNumber( ( BaseType_t )pxSocket->ucProtocol ); + if( 0 == pxAddress->sin_port ) + { + return -pdFREERTOS_ERRNO_EADDRNOTAVAIL; + } + } + + /* If vSocketBind() is called from the API FreeRTOS_bind() it has been + confirmed that the socket was not yet bound to a port. If it is called + from the IP-task, no such check is necessary. */ + + /* Check to ensure the port is not already in use. If the bind is + called internally, a port MAY be used by more than one socket. */ + if( ( ( xInternal == pdFALSE ) || ( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) ) && + ( pxListFindListItemWithValue( pxSocketList, ( TickType_t ) pxAddress->sin_port ) != NULL ) ) + { + FreeRTOS_debug_printf( ( "vSocketBind: %sP port %d in use\n", + pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ? "TC" : "UD", + FreeRTOS_ntohs( pxAddress->sin_port ) ) ); + xReturn = -pdFREERTOS_ERRNO_EADDRINUSE; + } + else + { + /* Allocate the port number to the socket. + This macro will set 'xBoundSocketListItem->xItemValue' */ + socketSET_SOCKET_PORT( pxSocket, pxAddress->sin_port ); + + /* And also store it in a socket field 'usLocalPort' in host-byte-order, + mostly used for logging and debugging purposes */ + pxSocket->usLocalPort = FreeRTOS_ntohs( pxAddress->sin_port ); + + /* Add the socket to the list of bound ports. */ + { + /* If the network driver can iterate through 'xBoundUDPSocketsList', + by calling xPortHasUDPSocket() then the IP-task must temporarily + suspend the scheduler to keep the list in a consistent state. */ + #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) + { + vTaskSuspendAll(); + } + #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + + /* Add the socket to 'xBoundUDPSocketsList' or 'xBoundTCPSocketsList' */ + vListInsertEnd( pxSocketList, &( pxSocket->xBoundSocketListItem ) ); + + #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) + { + xTaskResumeAll(); + } + #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + } + } + } + else + { + xReturn = -pdFREERTOS_ERRNO_EADDRNOTAVAIL; + FreeRTOS_debug_printf( ( "vSocketBind: Socket no addr\n" ) ); + } + + if( xReturn != 0 ) + { + iptraceBIND_FAILED( xSocket, ( FreeRTOS_ntohs( pxAddress->sin_port ) ) ); + } + + return xReturn; +} /* Tested */ +/*-----------------------------------------------------------*/ + +/* + * Close a socket and free the allocated space + * In case of a TCP socket: the connection will not be closed automatically + * Subsequent messages for the closed socket will be responded to with a RST + * The IP-task will actually close the socket, after receiving a 'eSocketCloseEvent' message + */ +BaseType_t FreeRTOS_closesocket( Socket_t xSocket ) +{ +BaseType_t xResult; +#if( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * )xSocket; +#endif +IPStackEvent_t xCloseEvent; +xCloseEvent.eEventType = eSocketCloseEvent; +xCloseEvent.pvData = ( void * ) xSocket; + + if( ( xSocket == NULL ) || ( xSocket == FREERTOS_INVALID_SOCKET ) ) + { + xResult = 0; + } + else + { + #if( ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) ) + { + if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + /* Make sure that IP-task won't call the user callback's anymore */ + pxSocket->u.xTCP.pxHandleConnected = NULL; + pxSocket->u.xTCP.pxHandleReceive = NULL; + pxSocket->u.xTCP.pxHandleSent = NULL; + } + } + #endif /* ( ( ipconfigUSE_TCP == 1 ) && ( ipconfigUSE_CALLBACKS == 1 ) ) */ + + /* Let the IP task close the socket to keep it synchronised with the + packet handling. */ + + /* Note when changing the time-out value below, it must be checked who is calling + this function. If it is called by the IP-task, a deadlock could occur. + The IP-task would only call it in case of a user call-back */ + if( xSendEventStructToIPTask( &xCloseEvent, ( TickType_t ) 0 ) == pdFAIL ) + { + FreeRTOS_debug_printf( ( "FreeRTOS_closesocket: failed\n" ) ); + xResult = -1; + } + else + { + xResult = 1; + } + } + + return xResult; +} + +/* This is the internal version of FreeRTOS_closesocket() + * It will be called by the IPtask only to avoid problems with synchronicity + */ +void *vSocketClose( FreeRTOS_Socket_t *pxSocket ) +{ +NetworkBufferDescriptor_t *pxNetworkBuffer; + + #if( ipconfigUSE_TCP == 1 ) + { + /* For TCP: clean up a little more. */ + if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + #if( ipconfigUSE_TCP_WIN == 1 ) + { + if( pxSocket->u.xTCP.pxAckMessage != NULL ) + { + vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage ); + } + /* Free the resources which were claimed by the tcpWin member */ + vTCPWindowDestroy( &pxSocket->u.xTCP.xTCPWindow ); + } + #endif /* ipconfigUSE_TCP_WIN */ + + /* Free the input and output streams */ + if( pxSocket->u.xTCP.rxStream != NULL ) + { + vPortFreeLarge( pxSocket->u.xTCP.rxStream ); + } + + if( pxSocket->u.xTCP.txStream != NULL ) + { + vPortFreeLarge( pxSocket->u.xTCP.txStream ); + } + + /* In case this is a child socket, make sure the child-count of the + parent socket is decreased. */ + prvTCPSetSocketCount( pxSocket ); + } + } + #endif /* ipconfigUSE_TCP == 1 */ + + /* Socket must be unbound first, to ensure no more packets are queued on + it. */ + if( socketSOCKET_IS_BOUND( pxSocket ) != pdFALSE ) + { + /* If the network driver can iterate through 'xBoundUDPSocketsList', + by calling xPortHasUDPSocket(), then the IP-task must temporarily + suspend the scheduler to keep the list in a consistent state. */ + #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) + { + vTaskSuspendAll(); + } + #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + + uxListRemove( &( pxSocket->xBoundSocketListItem ) ); + + #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) + { + xTaskResumeAll(); + } + #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + } + + /* Now the socket is not bound the list of waiting packets can be + drained. */ + if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP ) + { + while( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U ) + { + pxNetworkBuffer = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &( pxSocket->u.xUDP.xWaitingPacketsList ) ); + uxListRemove( &( pxNetworkBuffer->xBufferListItem ) ); + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + } + + if( pxSocket->xEventGroup ) + { + vEventGroupDelete( pxSocket->xEventGroup ); + } + + #if( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + FreeRTOS_debug_printf( ( "FreeRTOS_closesocket[%u to %lxip:%u]: buffers %lu socks %lu\n", + pxSocket->usLocalPort, + pxSocket->u.xTCP.ulRemoteIP, + pxSocket->u.xTCP.usRemotePort, + uxGetNumberOfFreeNetworkBuffers(), + listCURRENT_LIST_LENGTH( &xBoundTCPSocketsList ) ) ); + } + } + #endif /* ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_DEBUG_PRINTF != 0 ) */ + + /* Anf finally, after all resources have been freed, free the socket space */ + vPortFreeSocket( pxSocket ); + + return 0; +} /* Tested */ + +/*-----------------------------------------------------------*/ + +#if ipconfigUSE_TCP == 1 + + /* + * When a child socket gets closed, make sure to update the child-count of the + * parent. When a listening parent socket is closed, make sure no child-sockets + * keep a pointer to it. + */ + static void prvTCPSetSocketCount( FreeRTOS_Socket_t *pxSocketToDelete ) + { + const ListItem_t *pxIterator; + const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList ); + FreeRTOS_Socket_t *pxOtherSocket; + uint16_t usLocalPort = pxSocketToDelete->usLocalPort; + + for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd ); + pxIterator != ( const ListItem_t * ) pxEnd; + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + pxOtherSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + if( ( pxOtherSocket->u.xTCP.ucTCPState == eTCP_LISTEN ) && + ( pxOtherSocket->usLocalPort == usLocalPort ) && + ( pxOtherSocket->u.xTCP.usChildCount ) ) + { + pxOtherSocket->u.xTCP.usChildCount--; + FreeRTOS_debug_printf( ( "Lost: Socket %u now has %u / %u child%s\n", + pxOtherSocket->usLocalPort, + pxOtherSocket->u.xTCP.usChildCount, + pxOtherSocket->u.xTCP.usBacklog, + pxOtherSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) ); + break; + } + } + } + +#endif /* ipconfigUSE_TCP == 1 */ + +/*-----------------------------------------------------------*/ + +BaseType_t FreeRTOS_setsockopt( Socket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength ) +{ +/* The standard Berkeley function returns 0 for success. */ +BaseType_t xReturn = -pdFREERTOS_ERRNO_EINVAL; +BaseType_t lOptionValue; +FreeRTOS_Socket_t *pxSocket; + + pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + + /* The function prototype is designed to maintain the expected Berkeley + sockets standard, but this implementation does not use all the parameters. */ + ( void ) lLevel; + ( void ) xOptionLength; + + configASSERT( xSocket ); + + switch( lOptionName ) + { + case FREERTOS_SO_RCVTIMEO : + /* Receive time out. */ + pxSocket->xReceiveBlockTime = *( ( TickType_t * ) pvOptionValue ); + xReturn = 0; + break; + + case FREERTOS_SO_SNDTIMEO : + pxSocket->xSendBlockTime = *( ( TickType_t * ) pvOptionValue ); + if( pxSocket->ucProtocol == ( uint8_t ) FREERTOS_IPPROTO_UDP ) + { + /* The send time out is capped for the reason stated in the + comments where ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined + in FreeRTOSIPConfig.h (assuming an official configuration file + is being used. */ + if( pxSocket->xSendBlockTime > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ) + { + pxSocket->xSendBlockTime = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS; + } + } + else + { + /* For TCP socket, it isn't necessary to limit the blocking time + because the FreeRTOS_send() function does not wait for a network + buffer to become available. */ + } + xReturn = 0; + break; + #if( ipconfigUDP_MAX_RX_PACKETS > 0 ) + case FREERTOS_SO_UDP_MAX_RX_PACKETS: + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_UDP ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + pxSocket->u.xUDP.uxMaxPackets = *( ( UBaseType_t * ) pvOptionValue ); + xReturn = 0; + break; + #endif /* ipconfigUDP_MAX_RX_PACKETS */ + + case FREERTOS_SO_UDPCKSUM_OUT : + /* Turn calculating of the UDP checksum on/off for this socket. */ + lOptionValue = ( BaseType_t ) pvOptionValue; + + if( lOptionValue == 0 ) + { + pxSocket->ucSocketOptions &= ( uint8_t ) ~FREERTOS_SO_UDPCKSUM_OUT; + } + else + { + pxSocket->ucSocketOptions |= ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT; + } + xReturn = 0; + break; + + #if( ipconfigUSE_CALLBACKS == 1 ) + #if( ipconfigUSE_TCP == 1 ) + case FREERTOS_SO_TCP_CONN_HANDLER: /* Set a callback for (dis)connection events */ + case FREERTOS_SO_TCP_RECV_HANDLER: /* Install a callback for receiving TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ + case FREERTOS_SO_TCP_SENT_HANDLER: /* Install a callback for sending TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ + #endif /* ipconfigUSE_TCP */ + case FREERTOS_SO_UDP_RECV_HANDLER: /* Install a callback for receiving UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ + case FREERTOS_SO_UDP_SENT_HANDLER: /* Install a callback for sending UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ + { + #if( ipconfigUSE_TCP == 1 ) + { + UBaseType_t uxProtocol; + if( ( lOptionName == FREERTOS_SO_UDP_RECV_HANDLER ) || + ( lOptionName == FREERTOS_SO_UDP_SENT_HANDLER ) ) + { + uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_UDP; + } + else + { + uxProtocol = ( UBaseType_t ) FREERTOS_IPPROTO_TCP; + } + + if( pxSocket->ucProtocol != ( uint8_t ) uxProtocol ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + } + #else + { + /* No need to check if the socket has the right + protocol, because only UDP socket can be created. */ + } + #endif /* ipconfigUSE_TCP */ + + switch( lOptionName ) + { + #if ipconfigUSE_TCP == 1 + case FREERTOS_SO_TCP_CONN_HANDLER: + pxSocket->u.xTCP.pxHandleConnected = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPConnected; + break; + case FREERTOS_SO_TCP_RECV_HANDLER: + pxSocket->u.xTCP.pxHandleReceive = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPReceive; + break; + case FREERTOS_SO_TCP_SENT_HANDLER: + pxSocket->u.xTCP.pxHandleSent = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnTCPSent; + break; + #endif /* ipconfigUSE_TCP */ + case FREERTOS_SO_UDP_RECV_HANDLER: + pxSocket->u.xUDP.pxHandleReceive = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnUDPReceive; + break; + case FREERTOS_SO_UDP_SENT_HANDLER: + pxSocket->u.xUDP.pxHandleSent = ((F_TCP_UDP_Handler_t *)pvOptionValue)->pxOnUDPSent; + break; + default: + break; + } + } + + xReturn = 0; + break; + #endif /* ipconfigUSE_CALLBACKS */ + + #if( ipconfigUSE_TCP != 0 ) + #if( ipconfigSOCKET_HAS_USER_SEMAPHORE != 0 ) + /* Each socket has a semaphore on which the using task normally + sleeps. */ + case FREERTOS_SO_SET_SEMAPHORE: + { + pxSocket->pxUserSemaphore = *( ( SemaphoreHandle_t * ) pvOptionValue ); + xReturn = 0; + } + break; + #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */ + + #if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK != 0 ) || ( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT != 0 ) + case FREERTOS_SO_WAKEUP_CALLBACK: + { + /* Each socket can have a callback function that is executed + when there is an event the socket's owner might want to + process. */ + pxSocket->pxUserWakeCallback = ( SocketWakeupCallback_t ) pvOptionValue; + xReturn = 0; + } + break; + #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */ + + #if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT != 0 ) + case FREERTOS_SO_WAKE_CALLBACK_CONTEXT: + { + /* Each socket wake callback may be passed a user context. */ + pxSocket->pvUserWakeCallbackContext = ( void * ) pvOptionValue; + xReturn = 0; + } + break; + #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT */ + + case FREERTOS_SO_SET_LOW_HIGH_WATER: + { + LowHighWater_t *pxLowHighWater = ( LowHighWater_t * ) pvOptionValue; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + /* It is not allowed to access 'pxSocket->u.xTCP'. */ + FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: wrong socket type\n" ) ); + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + if( ( pxLowHighWater->uxLittleSpace >= pxLowHighWater->uxEnoughSpace ) || + ( pxLowHighWater->uxEnoughSpace > pxSocket->u.xTCP.uxRxStreamSize ) ) + { + /* Impossible values. */ + FreeRTOS_debug_printf( ( "FREERTOS_SO_SET_LOW_HIGH_WATER: bad values\n" ) ); + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + /* Send a STOP when buffer space drops below 'uxLittleSpace' bytes. */ + pxSocket->u.xTCP.uxLittleSpace = pxLowHighWater->uxLittleSpace; + /* Send a GO when buffer space grows above 'uxEnoughSpace' bytes. */ + pxSocket->u.xTCP.uxEnoughSpace = pxLowHighWater->uxEnoughSpace; + xReturn = 0; + } + break; + + case FREERTOS_SO_SNDBUF: /* Set the size of the send buffer, in units of MSS (TCP only) */ + case FREERTOS_SO_RCVBUF: /* Set the size of the receive buffer, in units of MSS (TCP only) */ + { + uint32_t ulNewValue; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + FreeRTOS_debug_printf( ( "Set SO_%sBUF: wrong socket type\n", + ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) ); + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + if( ( ( lOptionName == FREERTOS_SO_SNDBUF ) && ( pxSocket->u.xTCP.txStream != NULL ) ) || + ( ( lOptionName == FREERTOS_SO_RCVBUF ) && ( pxSocket->u.xTCP.rxStream != NULL ) ) ) + { + FreeRTOS_debug_printf( ( "Set SO_%sBUF: buffer already created\n", + ( lOptionName == FREERTOS_SO_SNDBUF ) ? "SND" : "RCV" ) ); + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + ulNewValue = *( ( uint32_t * ) pvOptionValue ); + + if( lOptionName == FREERTOS_SO_SNDBUF ) + { + /* Round up to nearest MSS size */ + ulNewValue = FreeRTOS_round_up( ulNewValue, ( uint32_t ) pxSocket->u.xTCP.usInitMSS ); + pxSocket->u.xTCP.uxTxStreamSize = ulNewValue; + } + else + { + pxSocket->u.xTCP.uxRxStreamSize = ulNewValue; + } + } + xReturn = 0; + break; + + case FREERTOS_SO_WIN_PROPERTIES: /* Set all buffer and window properties in one call, parameter is pointer to WinProperties_t */ + { + WinProperties_t* pxProps; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: wrong socket type\n" ) ); + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + if( ( pxSocket->u.xTCP.txStream != NULL ) || ( pxSocket->u.xTCP.rxStream != NULL ) ) + { + FreeRTOS_debug_printf( ( "Set SO_WIN_PROP: buffer already created\n" ) ); + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + pxProps = ( ( WinProperties_t * ) pvOptionValue ); + + if ( FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDBUF, &( pxProps->lTxBufSize ), sizeof( pxProps->lTxBufSize ) ) != 0 ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + if ( FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVBUF, &( pxProps->lRxBufSize ), sizeof( pxProps->lRxBufSize ) ) != 0 ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + #if( ipconfigUSE_TCP_WIN == 1 ) + { + pxSocket->u.xTCP.uxRxWinSize = ( uint32_t )pxProps->lRxWinSize; /* Fixed value: size of the TCP reception window */ + pxSocket->u.xTCP.uxTxWinSize = ( uint32_t )pxProps->lTxWinSize; /* Fixed value: size of the TCP transmit window */ + } + #else + { + pxSocket->u.xTCP.uxRxWinSize = 1u; + pxSocket->u.xTCP.uxTxWinSize = 1u; + } + #endif + + /* In case the socket has already initialised its tcpWin, + adapt the window size parameters */ + if( pxSocket->u.xTCP.xTCPWindow.u.bits.bHasInit != pdFALSE_UNSIGNED ) + { + pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength = pxSocket->u.xTCP.uxRxWinSize * pxSocket->u.xTCP.usInitMSS; + pxSocket->u.xTCP.xTCPWindow.xSize.ulTxWindowLength = pxSocket->u.xTCP.uxTxWinSize * pxSocket->u.xTCP.usInitMSS; + } + } + + xReturn = 0; + break; + + case FREERTOS_SO_REUSE_LISTEN_SOCKET: /* If true, the server-socket will turn into a connected socket */ + { + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + if( *( ( BaseType_t * ) pvOptionValue ) != 0 ) + { + pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE_UNSIGNED; + } + else + { + pxSocket->u.xTCP.bits.bReuseSocket = pdFALSE_UNSIGNED; + } + } + xReturn = 0; + break; + + case FREERTOS_SO_CLOSE_AFTER_SEND: /* As soon as the last byte has been transmitted, finalise the connection */ + { + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + if( *( ( BaseType_t * ) pvOptionValue ) != 0 ) + { + pxSocket->u.xTCP.bits.bCloseAfterSend = pdTRUE_UNSIGNED; + } + else + { + pxSocket->u.xTCP.bits.bCloseAfterSend = pdFALSE_UNSIGNED; + } + } + xReturn = 0; + break; + + case FREERTOS_SO_SET_FULL_SIZE: /* Refuse to send packets smaller than MSS */ + { + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + if( *( ( BaseType_t * ) pvOptionValue ) != 0 ) + { + pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdTRUE_UNSIGNED; + } + else + { + pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize = pdFALSE_UNSIGNED; + } + + if( ( pxSocket->u.xTCP.xTCPWindow.u.bits.bSendFullSize == pdFALSE_UNSIGNED ) && + ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && + ( FreeRTOS_outstanding( pxSocket ) != 0 ) ) + { + pxSocket->u.xTCP.usTimeout = 1u; /* to set/clear bSendFullSize */ + xSendEventToIPTask( eTCPTimerEvent ); + } + } + xReturn = 0; + break; + + case FREERTOS_SO_STOP_RX: /* Refuse to receive more packts */ + { + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + break; /* will return -pdFREERTOS_ERRNO_EINVAL */ + } + + if( *( ( BaseType_t * ) pvOptionValue ) != 0 ) + { + pxSocket->u.xTCP.bits.bRxStopped = pdTRUE_UNSIGNED; + } + else + { + pxSocket->u.xTCP.bits.bRxStopped = pdFALSE_UNSIGNED; + } + + pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED; + pxSocket->u.xTCP.usTimeout = 1u; /* to set/clear bRxStopped */ + xSendEventToIPTask( eTCPTimerEvent ); + } + xReturn = 0; + break; + + #endif /* ipconfigUSE_TCP == 1 */ + + default : + /* No other options are handled. */ + xReturn = -pdFREERTOS_ERRNO_ENOPROTOOPT; + break; + } + + return xReturn; +} /* Tested */ + +/*-----------------------------------------------------------*/ + +/* Find an available port number per https://tools.ietf.org/html/rfc6056. */ +static uint16_t prvGetPrivatePortNumber( BaseType_t xProtocol ) +{ +const uint16_t usEphemeralPortCount = + socketAUTO_PORT_ALLOCATION_MAX_NUMBER - socketAUTO_PORT_ALLOCATION_START_NUMBER + 1; +uint16_t usIterations = usEphemeralPortCount; +uint32_t ulRandomSeed = 0; +uint16_t usResult = 0; +BaseType_t xGotZeroOnce = pdFALSE; +const List_t *pxList; + +#if ipconfigUSE_TCP == 1 + if( xProtocol == ( BaseType_t ) FREERTOS_IPPROTO_TCP ) + { + pxList = &xBoundTCPSocketsList; + } + else +#endif + { + pxList = &xBoundUDPSocketsList; + } + + /* Avoid compiler warnings if ipconfigUSE_TCP is not defined. */ + ( void ) xProtocol; + + /* Find the next available port using the random seed as a starting + point. */ + do + { + /* Generate a random seed. */ + ulRandomSeed = ipconfigRAND32( ); + + /* Only proceed if the random number generator succeeded. */ + if( 0 == ulRandomSeed ) + { + if( pdFALSE == xGotZeroOnce ) + { + xGotZeroOnce = pdTRUE; + continue; + } + else + { + break; + } + } + + /* Map the random to a candidate port. */ + usResult = + socketAUTO_PORT_ALLOCATION_START_NUMBER + + ( ( ( uint16_t )ulRandomSeed ) % usEphemeralPortCount ); + + /* Check if there's already an open socket with the same protocol + and port. */ + if( NULL == pxListFindListItemWithValue( + pxList, + ( TickType_t )FreeRTOS_htons( usResult ) ) ) + { + usResult = FreeRTOS_htons( usResult ); + break; + } + else + { + usResult = 0; + } + + usIterations--; + } + while( usIterations > 0 ); + + return usResult; +} +/*-----------------------------------------------------------*/ + +/* pxListFindListItemWithValue: find a list item in a bound socket list +'xWantedItemValue' refers to a port number */ +static const ListItem_t * pxListFindListItemWithValue( const List_t *pxList, TickType_t xWantedItemValue ) +{ +const ListItem_t * pxResult = NULL; + + if( ( xIPIsNetworkTaskReady() != pdFALSE ) && ( pxList != NULL ) ) + { + const ListItem_t *pxIterator; + const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( pxList ); + for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd ); + pxIterator != ( const ListItem_t * ) pxEnd; + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + if( listGET_LIST_ITEM_VALUE( pxIterator ) == xWantedItemValue ) + { + pxResult = pxIterator; + break; + } + } + } + + return pxResult; +} /* Tested */ + +/*-----------------------------------------------------------*/ + +FreeRTOS_Socket_t *pxUDPSocketLookup( UBaseType_t uxLocalPort ) +{ +const ListItem_t *pxListItem; +FreeRTOS_Socket_t *pxSocket = NULL; + + /* Looking up a socket is quite simple, find a match with the local port. + + See if there is a list item associated with the port number on the + list of bound sockets. */ + pxListItem = pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) uxLocalPort ); + + if( pxListItem != NULL ) + { + /* The owner of the list item is the socket itself. */ + pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxListItem ); + configASSERT( pxSocket != NULL ); + } + return pxSocket; +} + +/*-----------------------------------------------------------*/ + +#if ipconfigINCLUDE_FULL_INET_ADDR == 1 + + uint32_t FreeRTOS_inet_addr( const char * pcIPAddress ) + { + const uint32_t ulDecimalBase = 10u; + uint8_t ucOctet[ socketMAX_IP_ADDRESS_OCTETS ]; + const char *pcPointerOnEntering; + uint32_t ulReturn = 0UL, ulValue; + UBaseType_t uxOctetNumber; + BaseType_t xResult = pdPASS; + + for( uxOctetNumber = 0u; uxOctetNumber < socketMAX_IP_ADDRESS_OCTETS; uxOctetNumber++ ) + { + ulValue = 0ul; + pcPointerOnEntering = pcIPAddress; + + while( ( *pcIPAddress >= '0' ) && ( *pcIPAddress <= '9' ) ) + { + /* Move previous read characters into the next decimal + position. */ + ulValue *= ulDecimalBase; + + /* Add the binary value of the ascii character. */ + ulValue += ( ( uint32_t ) ( *pcIPAddress ) - ( uint32_t ) '0' ); + + /* Move to next character in the string. */ + pcIPAddress++; + } + + /* Check characters were read. */ + if( pcIPAddress == pcPointerOnEntering ) + { + xResult = pdFAIL; + } + + /* Check the value fits in an 8-bit number. */ + if( ulValue > 0xffUL ) + { + xResult = pdFAIL; + } + else + { + ucOctet[ uxOctetNumber ] = ( uint8_t ) ulValue; + + /* Check the next character is as expected. */ + if( uxOctetNumber < ( socketMAX_IP_ADDRESS_OCTETS - 1u ) ) + { + if( *pcIPAddress != '.' ) + { + xResult = pdFAIL; + } + else + { + /* Move past the dot. */ + pcIPAddress++; + } + } + } + + if( xResult == pdFAIL ) + { + /* No point going on. */ + break; + } + } + + if( *pcIPAddress != ( char ) 0 ) + { + /* Expected the end of the string. */ + xResult = pdFAIL; + } + + if( uxOctetNumber != socketMAX_IP_ADDRESS_OCTETS ) + { + /* Didn't read enough octets. */ + xResult = pdFAIL; + } + + if( xResult == pdPASS ) + { + ulReturn = FreeRTOS_inet_addr_quick( ucOctet[ 0 ], ucOctet[ 1 ], ucOctet[ 2 ], ucOctet[ 3 ] ); + } + + return ulReturn; + } + +#endif /* ipconfigINCLUDE_FULL_INET_ADDR */ + +/*-----------------------------------------------------------*/ + +/* Function to get the local address and IP port */ +size_t FreeRTOS_GetLocalAddress( Socket_t xSocket, struct freertos_sockaddr *pxAddress ) +{ +FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + + /* IP address of local machine. */ + pxAddress->sin_addr = *ipLOCAL_IP_ADDRESS_POINTER; + + /* Local port on this machine. */ + pxAddress->sin_port = FreeRTOS_htons( pxSocket->usLocalPort ); + + return sizeof( *pxAddress ); +} + +/*-----------------------------------------------------------*/ + +void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ) +{ +/* _HT_ must work this out, now vSocketWakeUpUser will be called for any important + * event or transition */ + #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 ) + { + if( pxSocket->pxUserSemaphore != NULL ) + { + xSemaphoreGive( pxSocket->pxUserSemaphore ); + } + } + #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */ + + #if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK == 1 ) + { + if( pxSocket->pxUserWakeCallback != NULL ) + { + pxSocket->pxUserWakeCallback( pxSocket ); + } + } + #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */ + + #if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT == 1 ) + { + if( pxSocket->pxUserWakeCallback != NULL ) + { + pxSocket->pxUserWakeCallback( pxSocket, pxSocket->pvUserWakeCallbackContext ); + } + } + #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT */ + + #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + { + if( pxSocket->pxSocketSet != NULL ) + { + EventBits_t xSelectBits = ( pxSocket->xEventBits >> SOCKET_EVENT_BIT_COUNT ) & eSELECT_ALL; + if( xSelectBits != 0ul ) + { + pxSocket->xSocketBits |= xSelectBits; + xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, xSelectBits ); + } + } + + pxSocket->xEventBits &= eSOCKET_ALL; + } + #endif /* ipconfigSUPPORT_SELECT_FUNCTION */ + + if( ( pxSocket->xEventGroup != NULL ) && ( pxSocket->xEventBits != 0u ) ) + { + xEventGroupSetBits( pxSocket->xEventGroup, pxSocket->xEventBits ); + } + + pxSocket->xEventBits = 0ul; +} + +/*-----------------------------------------------------------*/ + +#if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) + + /* This define makes it possible for network-card drivers to inspect + * UDP message and see if there is any UDP socket bound to a given port + * number. + * This is probably only usefull in systems with a minimum of RAM and + * when lots of anonymous broadcast messages come in + */ + BaseType_t xPortHasUDPSocket( uint16_t usPortNr ) + { + BaseType_t xFound = pdFALSE; + + vTaskSuspendAll(); + { + if( ( pxListFindListItemWithValue( &xBoundUDPSocketsList, ( TickType_t ) usPortNr ) != NULL ) ) + { + xFound = pdTRUE; + } + } + xTaskResumeAll(); + + return xFound; + } + +#endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + static BaseType_t bMayConnect( FreeRTOS_Socket_t *pxSocket ); + static BaseType_t bMayConnect( FreeRTOS_Socket_t *pxSocket ) + { + switch( pxSocket->u.xTCP.ucTCPState ) + { + case eCLOSED: + case eCLOSE_WAIT: return 0; + case eCONNECT_SYN: return -pdFREERTOS_ERRNO_EINPROGRESS; + default: return -pdFREERTOS_ERRNO_EAGAIN; + } + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + static BaseType_t prvTCPConnectStart( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr *pxAddress ) + { + BaseType_t xResult = 0; + + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdFALSE ) + { + /* Not a valid socket or wrong type */ + xResult = -pdFREERTOS_ERRNO_EBADF; + } + else if( FreeRTOS_issocketconnected( pxSocket ) > 0 ) + { + /* The socket is already connected. */ + xResult = -pdFREERTOS_ERRNO_EISCONN; + } + else if( socketSOCKET_IS_BOUND( pxSocket ) == pdFALSE ) + { + /* Bind the socket to the port that the client task will send from. + Non-standard, so the error returned is that returned by bind(). */ + xResult = FreeRTOS_bind( ( Socket_t ) pxSocket, NULL, 0u ); + } + + if( xResult == 0 ) + { + /* Check if it makes any sense to wait for a connect event, this condition + might change while sleeping, so it must be checked within each loop */ + xResult = bMayConnect( pxSocket ); /* -EINPROGRESS, -EAGAIN, or 0 for OK */ + + /* Start the connect procedure, kernel will start working on it */ + if( xResult == 0 ) + { + pxSocket->u.xTCP.bits.bConnPrepared = pdFALSE_UNSIGNED; + pxSocket->u.xTCP.ucRepCount = 0u; + + FreeRTOS_debug_printf( ( "FreeRTOS_connect: %u to %lxip:%u\n", + pxSocket->usLocalPort, FreeRTOS_ntohl( pxAddress->sin_addr ), FreeRTOS_ntohs( pxAddress->sin_port ) ) ); + + /* Port on remote machine. */ + pxSocket->u.xTCP.usRemotePort = FreeRTOS_ntohs( pxAddress->sin_port ); + + /* IP address of remote machine. */ + pxSocket->u.xTCP.ulRemoteIP = FreeRTOS_ntohl( pxAddress->sin_addr ); + + /* (client) internal state: socket wants to send a connect. */ + vTCPStateChange( pxSocket, eCONNECT_SYN ); + + /* To start an active connect. */ + pxSocket->u.xTCP.usTimeout = 1u; + + if( xSendEventToIPTask( eTCPTimerEvent ) != pdPASS ) + { + xResult = -pdFREERTOS_ERRNO_ECANCELED; + } + } + } + + return xResult; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * FreeRTOS_connect: socket wants to connect to a remote port + */ + BaseType_t FreeRTOS_connect( Socket_t xClientSocket, struct freertos_sockaddr *pxAddress, socklen_t xAddressLength ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t* ) xClientSocket; + TickType_t xRemainingTime; + BaseType_t xTimed = pdFALSE; + BaseType_t xResult; + TimeOut_t xTimeOut; + + ( void ) xAddressLength; + + xResult = prvTCPConnectStart( pxSocket, pxAddress ); + + if( xResult == 0 ) + { + /* And wait for the result */ + for( ;; ) + { + if( xTimed == pdFALSE ) + { + /* Only in the first round, check for non-blocking */ + xRemainingTime = pxSocket->xReceiveBlockTime; + if( xRemainingTime == ( TickType_t )0 ) + { + /* Not yet connected, correct state, non-blocking. */ + xResult = -pdFREERTOS_ERRNO_EWOULDBLOCK; + break; + } + + /* Don't get here a second time. */ + xTimed = pdTRUE; + + /* Fetch the current time */ + vTaskSetTimeOutState( &xTimeOut ); + } + + /* Did it get connected while sleeping ? */ + xResult = FreeRTOS_issocketconnected( pxSocket ); + + /* Returns positive when connected, negative means an error */ + if( xResult < 0 ) + { + /* Return the error */ + break; + } + + if( xResult > 0 ) + { + /* Socket now connected, return a zero */ + xResult = 0; + break; + } + + /* Is it allowed to sleep more? */ + if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) ) + { + xResult = -pdFREERTOS_ERRNO_ETIMEDOUT; + break; + } + + /* Go sleeping until we get any down-stream event */ + xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_CONNECT, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); + } + } + + return xResult; + } +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * FreeRTOS_accept: can return a new connected socket + * if the server socket is in listen mode and receives a connection request + * The new socket will be bound already to the same port number as the listing + * socket. + */ + Socket_t FreeRTOS_accept( Socket_t xServerSocket, struct freertos_sockaddr *pxAddress, socklen_t *pxAddressLength ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xServerSocket; + FreeRTOS_Socket_t *pxClientSocket = NULL; + TickType_t xRemainingTime; + BaseType_t xTimed = pdFALSE, xAsk = pdFALSE; + TimeOut_t xTimeOut; + IPStackEvent_t xAskEvent; + + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) + { + /* Not a valid socket or wrong type */ + pxClientSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET; + } + else if( ( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) && + ( pxSocket->u.xTCP.ucTCPState != eTCP_LISTEN ) ) + { + /* Parent socket is not in listening mode */ + pxClientSocket = ( FreeRTOS_Socket_t * ) FREERTOS_INVALID_SOCKET; + } + else + { + /* Loop will stop with breaks. */ + for( ; ; ) + { + /* Is there a new client? */ + vTaskSuspendAll(); + { + if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) + { + pxClientSocket = pxSocket->u.xTCP.pxPeerSocket; + } + else + { + pxClientSocket = pxSocket; + } + if( pxClientSocket != NULL ) + { + pxSocket->u.xTCP.pxPeerSocket = NULL; + + /* Is it still not taken ? */ + if( pxClientSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) + { + pxClientSocket->u.xTCP.bits.bPassAccept = pdFALSE_UNSIGNED; + } + else + { + pxClientSocket = NULL; + } + } + } + xTaskResumeAll(); + + if( pxClientSocket != NULL ) + { + if( pxAddress != NULL ) + { + /* IP address of remote machine. */ + pxAddress->sin_addr = FreeRTOS_ntohl( pxClientSocket->u.xTCP.ulRemoteIP ); + + /* Port on remote machine. */ + pxAddress->sin_port = FreeRTOS_ntohs( pxClientSocket->u.xTCP.usRemotePort ); + } + if( pxAddressLength != NULL ) + { + *pxAddressLength = sizeof( *pxAddress ); + } + + if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) + { + xAsk = pdTRUE; + } + } + + if( xAsk != pdFALSE ) + { + /* Ask to set an event in 'xEventGroup' as soon as a new + client gets connected for this listening socket. */ + xAskEvent.eEventType = eTCPAcceptEvent; + xAskEvent.pvData = ( void * ) pxSocket; + xSendEventStructToIPTask( &xAskEvent, portMAX_DELAY ); + } + + if( pxClientSocket != NULL ) + { + break; + } + + if( xTimed == pdFALSE ) + { + /* Only in the first round, check for non-blocking */ + xRemainingTime = pxSocket->xReceiveBlockTime; + if( xRemainingTime == ( TickType_t ) 0 ) + { + break; + } + + /* Don't get here a second time */ + xTimed = pdTRUE; + + /* Fetch the current time */ + vTaskSetTimeOutState( &xTimeOut ); + } + + /* Has the timeout been reached? */ + if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE ) + { + break; + } + + /* Go sleeping until we get any down-stream event */ + xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_ACCEPT, pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); + } + } + + return ( Socket_t ) pxClientSocket; + } +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * Read incoming data from a TCP socket + * Only after the last byte has been read, a close error might be returned + */ + BaseType_t FreeRTOS_recv( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags ) + { + BaseType_t xByteCount; + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + TickType_t xRemainingTime; + BaseType_t xTimed = pdFALSE; + TimeOut_t xTimeOut; + EventBits_t xEventBits = ( EventBits_t ) 0; + + /* Check if the socket is valid, has type TCP and if it is bound to a + port. */ + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) + { + xByteCount = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + if( pxSocket->u.xTCP.rxStream != NULL ) + { + xByteCount = ( BaseType_t )uxStreamBufferGetSize ( pxSocket->u.xTCP.rxStream ); + } + else + { + xByteCount = 0; + } + + while( xByteCount == 0 ) + { + switch( pxSocket->u.xTCP.ucTCPState ) + { + case eCLOSED: + case eCLOSE_WAIT: /* (server + client) waiting for a connection termination request from the local user. */ + case eCLOSING: /* (server + client) waiting for a connection termination request acknowledgement from the remote TCP. */ + if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED ) + { + /* The no-memory error has priority above the non-connected error. + Both are fatal and will elad to closing the socket. */ + xByteCount = -pdFREERTOS_ERRNO_ENOMEM; + } + else + { + xByteCount = -pdFREERTOS_ERRNO_ENOTCONN; + } + /* Call continue to break out of the switch and also the while + loop. */ + continue; + default: + break; + } + + if( xTimed == pdFALSE ) + { + /* Only in the first round, check for non-blocking. */ + xRemainingTime = pxSocket->xReceiveBlockTime; + + if( xRemainingTime == ( TickType_t ) 0 ) + { + #if( ipconfigSUPPORT_SIGNALS != 0 ) + { + /* Just check for the interrupt flag. */ + xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_INTR, + pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, socketDONT_BLOCK ); + } + #endif /* ipconfigSUPPORT_SIGNALS */ + break; + } + + if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 ) + { + break; + } + + /* Don't get here a second time. */ + xTimed = pdTRUE; + + /* Fetch the current time. */ + vTaskSetTimeOutState( &xTimeOut ); + } + + /* Has the timeout been reached? */ + if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE ) + { + break; + } + + /* Block until there is a down-stream event. */ + xEventBits = xEventGroupWaitBits( pxSocket->xEventGroup, + eSOCKET_RECEIVE | eSOCKET_CLOSED | eSOCKET_INTR, + pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); + #if( ipconfigSUPPORT_SIGNALS != 0 ) + { + if( ( xEventBits & eSOCKET_INTR ) != 0u ) + { + break; + } + } + #else + { + ( void ) xEventBits; + } + #endif /* ipconfigSUPPORT_SIGNALS */ + + if( pxSocket->u.xTCP.rxStream != NULL ) + { + xByteCount = ( BaseType_t ) uxStreamBufferGetSize ( pxSocket->u.xTCP.rxStream ); + } + else + { + xByteCount = 0; + } + } + + #if( ipconfigSUPPORT_SIGNALS != 0 ) + if( ( xEventBits & eSOCKET_INTR ) != 0 ) + { + if( ( xEventBits & ( eSOCKET_RECEIVE | eSOCKET_CLOSED ) ) != 0 ) + { + /* Shouldn't have cleared other flags. */ + xEventBits &= ~eSOCKET_INTR; + xEventGroupSetBits( pxSocket->xEventGroup, xEventBits ); + } + xByteCount = -pdFREERTOS_ERRNO_EINTR; + } + else + #endif /* ipconfigSUPPORT_SIGNALS */ + if( xByteCount > 0 ) + { + if( ( xFlags & FREERTOS_ZERO_COPY ) == 0 ) + { + xByteCount = ( BaseType_t ) uxStreamBufferGet( pxSocket->u.xTCP.rxStream, 0ul, ( uint8_t * ) pvBuffer, ( size_t ) xBufferLength, ( xFlags & FREERTOS_MSG_PEEK ) != 0 ); + if( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) + { + /* We had reached the low-water mark, now see if the flag + can be cleared */ + size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ); + + if( uxFrontSpace >= pxSocket->u.xTCP.uxEnoughSpace ) + { + pxSocket->u.xTCP.bits.bLowWater = pdFALSE_UNSIGNED; + pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED; + pxSocket->u.xTCP.usTimeout = 1u; /* because bLowWater is cleared. */ + xSendEventToIPTask( eTCPTimerEvent ); + } + } + } + else + { + /* Zero-copy reception of data: pvBuffer is a pointer to a pointer. */ + xByteCount = ( BaseType_t ) uxStreamBufferGetPtr( pxSocket->u.xTCP.rxStream, (uint8_t **)pvBuffer ); + } + } + } /* prvValidSocket() */ + + return xByteCount; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + static int32_t prvTCPSendCheck( FreeRTOS_Socket_t *pxSocket, size_t xDataLength ) + { + int32_t xResult = 1; + + /* Is this a socket of type TCP and is it already bound to a port number ? */ + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) + { + xResult = -pdFREERTOS_ERRNO_EINVAL; + } + else if( pxSocket->u.xTCP.bits.bMallocError != pdFALSE_UNSIGNED ) + { + xResult = -pdFREERTOS_ERRNO_ENOMEM; + } + else if( pxSocket->u.xTCP.ucTCPState == eCLOSED || + pxSocket->u.xTCP.ucTCPState == eCLOSE_WAIT || + pxSocket->u.xTCP.ucTCPState == eCLOSING ) + { + xResult = -pdFREERTOS_ERRNO_ENOTCONN; + } + else if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED ) + { + /* This TCP connection is closing already, the FIN flag has been sent. + Maybe it is still delivering or receiving data. + Return OK in order not to get closed/deleted too quickly */ + xResult = 0; + } + else if( xDataLength == 0ul ) + { + /* send() is being called to send zero bytes */ + xResult = 0; + } + else if( pxSocket->u.xTCP.txStream == NULL ) + { + /* Create the outgoing stream only when it is needed */ + prvTCPCreateStream( pxSocket, pdFALSE ); + + if( pxSocket->u.xTCP.txStream == NULL ) + { + xResult = -pdFREERTOS_ERRNO_ENOMEM; + } + } + + return xResult; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* Get a direct pointer to the circular transmit buffer. + '*pxLength' will contain the number of bytes that may be written. */ + uint8_t *FreeRTOS_get_tx_head( Socket_t xSocket, BaseType_t *pxLength ) + { + uint8_t *pucReturn = NULL; + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + StreamBuffer_t *pxBuffer = NULL; + + *pxLength = 0; + + /* Confirm that this is a TCP socket before dereferencing structure + member pointers. */ + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE ) + { + pxBuffer = pxSocket->u.xTCP.txStream; + if( pxBuffer != NULL ) + { + BaseType_t xSpace = ( BaseType_t )uxStreamBufferGetSpace( pxBuffer ); + BaseType_t xRemain = ( BaseType_t )( pxBuffer->LENGTH - pxBuffer->uxHead ); + + *pxLength = FreeRTOS_min_BaseType( xSpace, xRemain ); + pucReturn = pxBuffer->ucArray + pxBuffer->uxHead; + } + } + + return pucReturn; + } +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + /* + * Send data using a TCP socket. It is not necessary to have the socket + * connected already. Outgoing data will be stored and delivered as soon as + * the socket gets connected. + */ + BaseType_t FreeRTOS_send( Socket_t xSocket, const void *pvBuffer, size_t uxDataLength, BaseType_t xFlags ) + { + BaseType_t xByteCount; + BaseType_t xBytesLeft; + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + TickType_t xRemainingTime; + BaseType_t xTimed = pdFALSE; + TimeOut_t xTimeOut; + BaseType_t xCloseAfterSend; + + /* Prevent compiler warnings about unused parameters. The parameter + may be used in future versions. */ + ( void ) xFlags; + + xByteCount = ( BaseType_t ) prvTCPSendCheck( pxSocket, uxDataLength ); + + if( xByteCount > 0 ) + { + /* xBytesLeft is number of bytes to send, will count to zero. */ + xBytesLeft = ( BaseType_t ) uxDataLength; + + /* xByteCount is number of bytes that can be sent now. */ + xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream ); + + /* While there are still bytes to be sent. */ + while( xBytesLeft > 0 ) + { + /* If txStream has space. */ + if( xByteCount > 0 ) + { + /* Don't send more than necessary. */ + if( xByteCount > xBytesLeft ) + { + xByteCount = xBytesLeft; + } + + /* Is the close-after-send flag set and is this really the + last transmission? */ + if( ( pxSocket->u.xTCP.bits.bCloseAfterSend != pdFALSE_UNSIGNED ) && ( xByteCount == xBytesLeft ) ) + { + xCloseAfterSend = pdTRUE; + } + else + { + xCloseAfterSend = pdFALSE; + } + + /* The flag 'bCloseAfterSend' can be set before sending data + using setsockopt() + + When the last data packet is being sent out, a FIN flag will + be included to let the peer know that no more data is to be + expected. The use of 'bCloseAfterSend' is not mandatory, it + is just a faster way of transferring files (e.g. when using + FTP). */ + if( xCloseAfterSend != pdFALSE ) + { + /* Now suspend the scheduler: sending the last data and + setting bCloseRequested must be done together */ + vTaskSuspendAll(); + pxSocket->u.xTCP.bits.bCloseRequested = pdTRUE_UNSIGNED; + } + + xByteCount = ( BaseType_t ) uxStreamBufferAdd( pxSocket->u.xTCP.txStream, 0ul, ( const uint8_t * ) pvBuffer, ( size_t ) xByteCount ); + + if( xCloseAfterSend != pdFALSE ) + { + /* Now when the IP-task transmits the data, it will also + see that bCloseRequested is true and include the FIN + flag to start closure of the connection. */ + xTaskResumeAll(); + } + + /* Send a message to the IP-task so it can work on this + socket. Data is sent, let the IP-task work on it. */ + pxSocket->u.xTCP.usTimeout = 1u; + + if( xIsCallingFromIPTask() == pdFALSE ) + { + /* Only send a TCP timer event when not called from the + IP-task. */ + xSendEventToIPTask( eTCPTimerEvent ); + } + + xBytesLeft -= xByteCount; + + if( xBytesLeft == 0 ) + { + break; + } + + /* As there are still bytes left to be sent, increase the + data pointer. */ + pvBuffer = ( void * ) ( ( ( const uint8_t * ) pvBuffer) + xByteCount ); + } + + /* Not all bytes have been sent. In case the socket is marked as + blocking sleep for a while. */ + if( xTimed == pdFALSE ) + { + /* Only in the first round, check for non-blocking. */ + xRemainingTime = pxSocket->xSendBlockTime; + + #if( ipconfigUSE_CALLBACKS != 0 ) + { + if( xIsCallingFromIPTask() != pdFALSE ) + { + /* If this send function is called from within a + call-back handler it may not block, otherwise + chances would be big to get a deadlock: the IP-task + waiting for itself. */ + xRemainingTime = ( TickType_t ) 0; + } + } + #endif /* ipconfigUSE_CALLBACKS */ + + if( xRemainingTime == ( TickType_t ) 0 ) + { + break; + } + + if( ( xFlags & FREERTOS_MSG_DONTWAIT ) != 0 ) + { + break; + } + + /* Don't get here a second time. */ + xTimed = pdTRUE; + + /* Fetch the current time. */ + vTaskSetTimeOutState( &xTimeOut ); + } + else + { + /* Has the timeout been reached? */ + if( xTaskCheckForTimeOut( &xTimeOut, &xRemainingTime ) != pdFALSE ) + { + break; + } + } + + /* Go sleeping until down-stream events are received. */ + xEventGroupWaitBits( pxSocket->xEventGroup, eSOCKET_SEND | eSOCKET_CLOSED, + pdTRUE /*xClearOnExit*/, pdFALSE /*xWaitAllBits*/, xRemainingTime ); + + xByteCount = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream ); + } + + /* How much was actually sent? */ + xByteCount = ( ( BaseType_t ) uxDataLength ) - xBytesLeft; + + if( xByteCount == 0 ) + { + if( pxSocket->u.xTCP.ucTCPState > eESTABLISHED ) + { + xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOTCONN; + } + else + { + if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) + { + FreeRTOS_debug_printf( ( "FreeRTOS_send: %u -> %lxip:%d: no space\n", + pxSocket->usLocalPort, + pxSocket->u.xTCP.ulRemoteIP, + pxSocket->u.xTCP.usRemotePort ) ); + } + + xByteCount = ( BaseType_t ) -pdFREERTOS_ERRNO_ENOSPC; + } + } + } + + return xByteCount; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * Request to put a socket in listen mode + */ + BaseType_t FreeRTOS_listen( Socket_t xSocket, BaseType_t xBacklog ) + { + FreeRTOS_Socket_t *pxSocket; + BaseType_t xResult = 0; + + pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + + /* listen() is allowed for a valid TCP socket in Closed state and already + bound. */ + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) + { + xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP; + } + else if( ( pxSocket->u.xTCP.ucTCPState != eCLOSED ) && ( pxSocket->u.xTCP.ucTCPState != eCLOSE_WAIT ) ) + { + /* Socket is in a wrong state. */ + xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP; + } + else + { + /* Backlog is interpreted here as "the maximum number of child + sockets. */ + pxSocket->u.xTCP.usBacklog = ( uint16_t )FreeRTOS_min_int32( ( int32_t ) 0xffff, ( int32_t ) xBacklog ); + + /* This cleaning is necessary only if a listening socket is being + reused as it might have had a previous connection. */ + if( pxSocket->u.xTCP.bits.bReuseSocket ) + { + if( pxSocket->u.xTCP.rxStream != NULL ) + { + vStreamBufferClear( pxSocket->u.xTCP.rxStream ); + } + + if( pxSocket->u.xTCP.txStream != NULL ) + { + vStreamBufferClear( pxSocket->u.xTCP.txStream ); + } + + memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) ); + memset( &pxSocket->u.xTCP.xTCPWindow, '\0', sizeof( pxSocket->u.xTCP.xTCPWindow ) ); + memset( &pxSocket->u.xTCP.bits, '\0', sizeof( pxSocket->u.xTCP.bits ) ); + + /* Now set the bReuseSocket flag again, because the bits have + just been cleared. */ + pxSocket->u.xTCP.bits.bReuseSocket = pdTRUE_UNSIGNED; + } + + vTCPStateChange( pxSocket, eTCP_LISTEN ); + } + + return xResult; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* shutdown - shut down part of a full-duplex connection */ + BaseType_t FreeRTOS_shutdown( Socket_t xSocket, BaseType_t xHow ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xResult; + + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdTRUE ) == pdFALSE ) + { + /*_RB_ Is this comment correct? The socket is not of a type that + supports the listen() operation. */ + xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP; + } + else if ( pxSocket->u.xTCP.ucTCPState != eESTABLISHED ) + { + /*_RB_ Is this comment correct? The socket is not of a type that + supports the listen() operation. */ + xResult = -pdFREERTOS_ERRNO_EOPNOTSUPP; + } + else + { + pxSocket->u.xTCP.bits.bUserShutdown = pdTRUE_UNSIGNED; + + /* Let the IP-task perform the shutdown of the connection. */ + pxSocket->u.xTCP.usTimeout = 1u; + xSendEventToIPTask( eTCPTimerEvent ); + xResult = 0; + } + (void) xHow; + + return xResult; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * A TCP timer has expired, now check all TCP sockets for: + * - Active connect + * - Send a delayed ACK + * - Send new data + * - Send a keep-alive packet + * - Check for timeout (in non-connected states only) + */ + TickType_t xTCPTimerCheck( BaseType_t xWillSleep ) + { + FreeRTOS_Socket_t *pxSocket; + TickType_t xShortest = pdMS_TO_TICKS( ( TickType_t ) ipTCP_TIMER_PERIOD_MS ); + TickType_t xNow = xTaskGetTickCount(); + static TickType_t xLastTime = 0u; + TickType_t xDelta = xNow - xLastTime; + ListItem_t* pxEnd = ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList ); + ListItem_t *pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList ); + + xLastTime = xNow; + + if( xDelta == 0u ) + { + xDelta = 1u; + } + + while( pxIterator != pxEnd ) + { + pxSocket = ( FreeRTOS_Socket_t * )listGET_LIST_ITEM_OWNER( pxIterator ); + pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ); + + /* Sockets with 'tmout == 0' do not need any regular attention. */ + if( pxSocket->u.xTCP.usTimeout == 0u ) + { + continue; + } + + if( xDelta < ( TickType_t ) pxSocket->u.xTCP.usTimeout ) + { + pxSocket->u.xTCP.usTimeout = ( uint16_t ) ( ( ( TickType_t ) pxSocket->u.xTCP.usTimeout ) - xDelta ); + } + else + { + int rc ; + pxSocket->u.xTCP.usTimeout = 0u; + rc = xTCPSocketCheck( pxSocket ); + + /* Within this function, the socket might want to send a delayed + ack or send out data or whatever it needs to do. */ + if( rc < 0 ) + { + /* Continue because the socket was deleted. */ + continue; + } + } + + /* In xEventBits the driver may indicate that the socket has + important events for the user. These are only done just before the + IP-task goes to sleep. */ + if( pxSocket->xEventBits != 0u ) + { + if( xWillSleep != pdFALSE ) + { + /* The IP-task is about to go to sleep, so messages can be + sent to the socket owners. */ + vSocketWakeUpUser( pxSocket ); + } + else + { + /* Or else make sure this will be called again to wake-up + the sockets' owner. */ + xShortest = ( TickType_t ) 0; + } + } + + if( ( pxSocket->u.xTCP.usTimeout != 0u ) && ( xShortest > ( TickType_t ) pxSocket->u.xTCP.usTimeout ) ) + { + xShortest = ( TickType_t ) pxSocket->u.xTCP.usTimeout; + } + } + + return xShortest; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * TCP: as multiple sockets may be bound to the same local port number + * looking up a socket is a little more complex: + * Both a local port, and a remote port and IP address are being used + * For a socket in listening mode, the remote port and IP address are both 0 + */ + FreeRTOS_Socket_t *pxTCPSocketLookup( uint32_t ulLocalIP, UBaseType_t uxLocalPort, uint32_t ulRemoteIP, UBaseType_t uxRemotePort ) + { + ListItem_t *pxIterator; + FreeRTOS_Socket_t *pxResult = NULL, *pxListenSocket = NULL; + MiniListItem_t *pxEnd = ( MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList ); + + /* Parameter not yet supported. */ + ( void ) ulLocalIP; + + for( pxIterator = ( ListItem_t * ) listGET_NEXT( pxEnd ); + pxIterator != ( ListItem_t * ) pxEnd; + pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + + if( pxSocket->usLocalPort == ( uint16_t ) uxLocalPort ) + { + if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ) + { + /* If this is a socket listening to uxLocalPort, remember it + in case there is no perfect match. */ + pxListenSocket = pxSocket; + } + else if( ( pxSocket->u.xTCP.usRemotePort == ( uint16_t ) uxRemotePort ) && ( pxSocket->u.xTCP.ulRemoteIP == ulRemoteIP ) ) + { + /* For sockets not in listening mode, find a match with + xLocalPort, ulRemoteIP AND xRemotePort. */ + pxResult = pxSocket; + break; + } + } + } + if( pxResult == NULL ) + { + /* An exact match was not found, maybe a listening socket was + found. */ + pxResult = pxListenSocket; + } + + return pxResult; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + const struct xSTREAM_BUFFER *FreeRTOS_get_rx_buf( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * )xSocket; + struct xSTREAM_BUFFER *pxReturn = NULL; + + /* Confirm that this is a TCP socket before dereferencing structure + member pointers. */ + if( prvValidSocket( pxSocket, FREERTOS_IPPROTO_TCP, pdFALSE ) == pdTRUE ) + { + pxReturn = pxSocket->u.xTCP.rxStream; + } + + return pxReturn; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + static StreamBuffer_t *prvTCPCreateStream ( FreeRTOS_Socket_t *pxSocket, BaseType_t xIsInputStream ) + { + StreamBuffer_t *pxBuffer; + size_t uxLength; + size_t uxSize; + + /* Now that a stream is created, the maximum size is fixed before + creation, it could still be changed with setsockopt(). */ + if( xIsInputStream != pdFALSE ) + { + uxLength = pxSocket->u.xTCP.uxRxStreamSize; + + if( pxSocket->u.xTCP.uxLittleSpace == 0ul ) + { + pxSocket->u.xTCP.uxLittleSpace = ( sock20_PERCENT * pxSocket->u.xTCP.uxRxStreamSize ) / sock100_PERCENT; + } + + if( pxSocket->u.xTCP.uxEnoughSpace == 0ul ) + { + pxSocket->u.xTCP.uxEnoughSpace = ( sock80_PERCENT * pxSocket->u.xTCP.uxRxStreamSize ) / sock100_PERCENT; + } + } + else + { + uxLength = pxSocket->u.xTCP.uxTxStreamSize; + } + + /* Add an extra 4 (or 8) bytes. */ + uxLength += sizeof( size_t ); + + /* And make the length a multiple of sizeof( size_t ). */ + uxLength &= ~( sizeof( size_t ) - 1u ); + + uxSize = sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) + uxLength; + + pxBuffer = ( StreamBuffer_t * )pvPortMallocLarge( uxSize ); + + if( pxBuffer == NULL ) + { + FreeRTOS_debug_printf( ( "prvTCPCreateStream: malloc failed\n" ) ); + pxSocket->u.xTCP.bits.bMallocError = pdTRUE_UNSIGNED; + vTCPStateChange( pxSocket, eCLOSE_WAIT ); + } + else + { + /* Clear the markers of the stream */ + memset( pxBuffer, '\0', sizeof( *pxBuffer ) - sizeof( pxBuffer->ucArray ) ); + pxBuffer->LENGTH = ( size_t ) uxLength ; + + if( xTCPWindowLoggingLevel != 0 ) + { + FreeRTOS_debug_printf( ( "prvTCPCreateStream: %cxStream created %lu bytes (total %lu)\n", xIsInputStream ? 'R' : 'T', uxLength, uxSize ) ); + } + + if( xIsInputStream != 0 ) + { + pxSocket->u.xTCP.rxStream = pxBuffer; + } + else + { + pxSocket->u.xTCP.txStream = pxBuffer; + } + } + + return pxBuffer; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * Add data to the RxStream. When uxOffset > 0, data has come in out-of-order + * and will be put in front of the head so it can not be popped by the user. + */ + int32_t lTCPAddRxdata( FreeRTOS_Socket_t *pxSocket, size_t uxOffset, const uint8_t *pcData, uint32_t ulByteCount ) + { + StreamBuffer_t *pxStream = pxSocket->u.xTCP.rxStream; + int32_t xResult; + #if( ipconfigUSE_CALLBACKS == 1 ) + BaseType_t bHasHandler = ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleReceive ); + const uint8_t *pucBuffer = NULL; + #endif /* ipconfigUSE_CALLBACKS */ + + /* int32_t uxStreamBufferAdd( pxBuffer, uxOffset, pucData, aCount ) + if( pucData != NULL ) copy data the the buffer + if( pucData == NULL ) no copying, just advance rxHead + if( uxOffset != 0 ) Just store data which has come out-of-order + if( uxOffset == 0 ) Also advance rxHead */ + if( pxStream == NULL ) + { + pxStream = prvTCPCreateStream( pxSocket, pdTRUE ); + if( pxStream == NULL ) + { + return -1; + } + } + + #if( ipconfigUSE_CALLBACKS == 1 ) + { + if( ( bHasHandler != pdFALSE ) && ( uxStreamBufferGetSize( pxStream ) == 0u ) && ( uxOffset == 0ul ) && ( pcData != NULL ) ) + { + /* Data can be passed directly to the user */ + pucBuffer = pcData; + + /* Zero-copy for call-back: no need to add the bytes to the + stream, only the pointer will be advanced by uxStreamBufferAdd(). */ + pcData = NULL; + } + } + #endif /* ipconfigUSE_CALLBACKS */ + + xResult = ( int32_t ) uxStreamBufferAdd( pxStream, uxOffset, pcData, ( size_t ) ulByteCount ); + + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + if( xResult != ( int32_t ) ulByteCount ) + { + FreeRTOS_debug_printf( ( "lTCPAddRxdata: at %ld: %ld/%lu bytes (tail %lu head %lu space %lu front %lu)\n", + uxOffset, xResult, ulByteCount, + pxStream->uxTail, + pxStream->uxHead, + uxStreamBufferFrontSpace( pxStream ), + pxStream->uxFront ) ); + } + } + #endif /* ipconfigHAS_DEBUG_PRINTF */ + + if( uxOffset == 0u ) + { + /* Data is being added to rxStream at the head (offs = 0) */ + #if( ipconfigUSE_CALLBACKS == 1 ) + if( bHasHandler != pdFALSE ) + { + /* The socket owner has installed an OnReceive handler. Pass the + Rx data, without copying from the rxStream, to the user. */ + for (;;) + { + uint8_t *ucReadPtr = NULL; + uint32_t ulCount; + if( pucBuffer != NULL ) + { + ucReadPtr = ( uint8_t * )pucBuffer; + ulCount = ulByteCount; + pucBuffer = NULL; + } + else + { + ulCount = ( uint32_t ) uxStreamBufferGetPtr( pxStream, &( ucReadPtr ) ); + } + + if( ulCount == 0ul ) + { + break; + } + + pxSocket->u.xTCP.pxHandleReceive( (Socket_t *)pxSocket, ( void* )ucReadPtr, ( size_t ) ulCount ); + uxStreamBufferGet( pxStream, 0ul, NULL, ( size_t ) ulCount, pdFALSE ); + } + } else + #endif /* ipconfigUSE_CALLBACKS */ + { + /* See if running out of space. */ + if( pxSocket->u.xTCP.bits.bLowWater == pdFALSE_UNSIGNED ) + { + size_t uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ); + if( uxFrontSpace <= pxSocket->u.xTCP.uxLittleSpace ) + { + pxSocket->u.xTCP.bits.bLowWater = pdTRUE_UNSIGNED; + pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED; + + /* bLowWater was reached, send the changed window size. */ + pxSocket->u.xTCP.usTimeout = 1u; + xSendEventToIPTask( eTCPTimerEvent ); + } + } + + /* New incoming data is available, wake up the user. User's + semaphores will be set just before the IP-task goes asleep. */ + pxSocket->xEventBits |= eSOCKET_RECEIVE; + + #if ipconfigSUPPORT_SELECT_FUNCTION == 1 + { + if( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) + { + pxSocket->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT ); + } + } + #endif + } + } + + return xResult; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* Function to get the remote address and IP port */ + BaseType_t FreeRTOS_GetRemoteAddress( Socket_t xSocket, struct freertos_sockaddr *pxAddress ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xResult; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xResult = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + /* BSD style sockets communicate IP and port addresses in network + byte order. + + IP address of remote machine. */ + pxAddress->sin_addr = FreeRTOS_htonl ( pxSocket->u.xTCP.ulRemoteIP ); + + /* Port on remote machine. */ + pxAddress->sin_port = FreeRTOS_htons ( pxSocket->u.xTCP.usRemotePort ); + + xResult = ( BaseType_t ) sizeof( ( *pxAddress ) ); + } + + return xResult; + } + +#endif /* ipconfigUSE_TCP */ + +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* Returns the number of bytes that may be added to txStream */ + BaseType_t FreeRTOS_maywrite( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xResult; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xResult = -pdFREERTOS_ERRNO_EINVAL; + } + else if( pxSocket->u.xTCP.ucTCPState != eESTABLISHED ) + { + if( ( pxSocket->u.xTCP.ucTCPState < eCONNECT_SYN ) || ( pxSocket->u.xTCP.ucTCPState > eESTABLISHED ) ) + { + xResult = -1; + } + else + { + xResult = 0; + } + } + else if( pxSocket->u.xTCP.txStream == NULL ) + { + xResult = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize; + } + else + { + xResult = ( BaseType_t ) uxStreamBufferGetSpace( pxSocket->u.xTCP.txStream ); + } + + return xResult; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP ==1 ) + + BaseType_t FreeRTOS_tx_space( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + if( pxSocket->u.xTCP.txStream != NULL ) + { + xReturn = ( BaseType_t ) uxStreamBufferGetSpace ( pxSocket->u.xTCP.txStream ); + } + else + { + xReturn = ( BaseType_t ) pxSocket->u.xTCP.uxTxStreamSize; + } + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + BaseType_t FreeRTOS_tx_size( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + if( pxSocket->u.xTCP.txStream != NULL ) + { + xReturn = ( BaseType_t ) uxStreamBufferGetSize ( pxSocket->u.xTCP.txStream ); + } + else + { + xReturn = 0; + } + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* Returns pdTRUE if TCP socket is connected. */ + BaseType_t FreeRTOS_issocketconnected( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn = pdFALSE; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) + { + if( pxSocket->u.xTCP.ucTCPState < eCLOSE_WAIT ) + { + xReturn = pdTRUE; + } + } + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* returns the actual size of MSS being used */ + BaseType_t FreeRTOS_mss( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + /* usCurMSS is declared as uint16_t to save space. FreeRTOS_mss() + will often be used in signed native-size expressions cast it to + BaseType_t. */ + xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.usCurMSS ); + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* HT: for internal use only: return the connection status */ + BaseType_t FreeRTOS_connstatus( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else + { + /* Cast it to BaseType_t */ + xReturn = ( BaseType_t ) ( pxSocket->u.xTCP.ucTCPState ); + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + /* + * Returns the number of bytes which can be read. + */ + BaseType_t FreeRTOS_rx_size( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn; + + if( pxSocket->ucProtocol != ( uint8_t ) FREERTOS_IPPROTO_TCP ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else if( pxSocket->u.xTCP.rxStream != NULL ) + { + xReturn = ( BaseType_t ) uxStreamBufferGetSize( pxSocket->u.xTCP.rxStream ); + } + else + { + xReturn = 0; + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP == 1 ) + + void FreeRTOS_netstat( void ) + { + IPStackEvent_t xAskEvent; + + /* Ask the IP-task to call vTCPNetStat() + * to avoid accessing xBoundTCPSocketsList + */ + xAskEvent.eEventType = eTCPNetStat; + xAskEvent.pvData = ( void * ) NULL; + xSendEventStructToIPTask( &xAskEvent, 1000u ); + } + +#endif /* ipconfigUSE_TCP */ +/*-----------------------------------------------------------*/ + +#if( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) ) + + void vTCPNetStat( void ) + { + /* Show a simple listing of all created sockets and their connections */ + ListItem_t *pxIterator; + BaseType_t count = 0; + + if( listLIST_IS_INITIALISED( &xBoundTCPSocketsList ) == pdFALSE ) + { + FreeRTOS_printf( ( "PLUS-TCP not initialized\n" ) ); + } + else + { + FreeRTOS_printf( ( "Prot Port IP-Remote : Port R/T Status Alive tmout Child\n" ) ); + for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList ); + pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList ); + pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + #if( ipconfigTCP_KEEP_ALIVE == 1 ) + TickType_t age = xTaskGetTickCount() - pxSocket->u.xTCP.xLastAliveTime; + #else + TickType_t age = 0u; + #endif + #if( ipconfigUSE_CALLBACKS == 1 ) + void *pxHandleReceive = (void*)pxSocket->u.xTCP.pxHandleReceive; + #else + void *pxHandleReceive = (void*)NULL; + #endif + char ucChildText[16] = ""; + if (pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN) + { + const int32_t copied_len = snprintf( ucChildText, sizeof( ucChildText ), " %d/%d", + ( int ) pxSocket->u.xTCP.usChildCount, + ( int ) pxSocket->u.xTCP.usBacklog); + /* These should never evaluate to false since the buffers are both shorter than 5-6 characters (<=65535) */ + configASSERT( copied_len >= 0 ); + configASSERT( copied_len < sizeof( ucChildText ) ); + } + FreeRTOS_printf( ( "TCP %5d %-16lxip:%5d %d/%d %-13.13s %6lu %6u%s\n", + pxSocket->usLocalPort, /* Local port on this machine */ + pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine */ + pxSocket->u.xTCP.usRemotePort, /* Port on remote machine */ + pxSocket->u.xTCP.rxStream != NULL, + pxSocket->u.xTCP.txStream != NULL, + FreeRTOS_GetTCPStateName( pxSocket->u.xTCP.ucTCPState ), + (age > 999999 ? 999999 : age), /* Format 'age' for printing */ + pxSocket->u.xTCP.usTimeout, + ucChildText ) ); + /* Remove compiler warnings if FreeRTOS_debug_printf() is not defined. */ + ( void ) pxHandleReceive; + count++; + } + + for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundUDPSocketsList ); + pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundUDPSocketsList ); + pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + /* Local port on this machine */ + FreeRTOS_printf( ( "UDP Port %5u\n", + FreeRTOS_ntohs( listGET_LIST_ITEM_VALUE( pxIterator ) ) ) ); + count++; + } + + FreeRTOS_printf( ( "FreeRTOS_netstat: %lu sockets %lu < %lu < %d buffers free\n", + count, + uxGetMinimumFreeNetworkBuffers( ), + uxGetNumberOfFreeNetworkBuffers( ), + ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) ); + } + } + +#endif /* ( ( ipconfigHAS_PRINTF != 0 ) && ( ipconfigUSE_TCP == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + + void vSocketSelect( SocketSelect_t *pxSocketSet ) + { + BaseType_t xRound; + EventBits_t xSocketBits, xBitsToClear; + #if ipconfigUSE_TCP == 1 + BaseType_t xLastRound = 1; + #else + BaseType_t xLastRound = 0; + #endif + + /* These flags will be switched on after checking the socket status. */ + EventBits_t xGroupBits = 0; + pxSocketSet->pxSocket = NULL; + + for( xRound = 0; xRound <= xLastRound; xRound++ ) + { + const ListItem_t *pxIterator; + const MiniListItem_t *pxEnd; + if( xRound == 0 ) + { + pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundUDPSocketsList ); + } + #if ipconfigUSE_TCP == 1 + else + { + pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &xBoundTCPSocketsList ); + } + #endif /* ipconfigUSE_TCP == 1 */ + for( pxIterator = ( const ListItem_t * ) ( listGET_NEXT( pxEnd ) ); + pxIterator != ( const ListItem_t * ) pxEnd; + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + if( pxSocket->pxSocketSet != pxSocketSet ) + { + /* Socket does not belong to this select group. */ + continue; + } + xSocketBits = 0; + + #if( ipconfigUSE_TCP == 1 ) + if( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP ) + { + /* Check if the socket has already been accepted by the + owner. If not, it is useless to return it from a + select(). */ + BaseType_t bAccepted = pdFALSE; + + if( pxSocket->u.xTCP.bits.bPassQueued == pdFALSE_UNSIGNED ) + { + if( pxSocket->u.xTCP.bits.bPassAccept == pdFALSE_UNSIGNED ) + { + bAccepted = pdTRUE; + } + } + + /* Is the set owner interested in READ events? */ + if( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) + { + if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ) + { + if( ( pxSocket->u.xTCP.pxPeerSocket != NULL ) && ( pxSocket->u.xTCP.pxPeerSocket->u.xTCP.bits.bPassAccept != 0 ) ) + { + xSocketBits |= eSELECT_READ; + } + } + else if( ( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) ) + { + /* This socket has the re-use flag. After connecting it turns into + aconnected socket. Set the READ event, so that accept() will be called. */ + xSocketBits |= eSELECT_READ; + } + else if( ( bAccepted != 0 ) && ( FreeRTOS_recvcount( pxSocket ) > 0 ) ) + { + xSocketBits |= eSELECT_READ; + } + } + /* Is the set owner interested in EXCEPTION events? */ + if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 ) + { + if( ( pxSocket->u.xTCP.ucTCPState == eCLOSE_WAIT ) || ( pxSocket->u.xTCP.ucTCPState == eCLOSED ) ) + { + xSocketBits |= eSELECT_EXCEPT; + } + } + + /* Is the set owner interested in WRITE events? */ + if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 ) + { + BaseType_t bMatch = pdFALSE; + + if( bAccepted != 0 ) + { + if( FreeRTOS_tx_space( pxSocket ) > 0 ) + { + bMatch = pdTRUE; + } + } + + if( bMatch == pdFALSE ) + { + if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) && + ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && + ( pxSocket->u.xTCP.bits.bConnPassed == pdFALSE_UNSIGNED ) ) + { + pxSocket->u.xTCP.bits.bConnPassed = pdTRUE_UNSIGNED; + bMatch = pdTRUE; + } + } + + if( bMatch != pdFALSE ) + { + xSocketBits |= eSELECT_WRITE; + } + } + } + else + #endif /* ipconfigUSE_TCP == 1 */ + { + /* Select events for UDP are simpler. */ + if( ( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) && + ( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) > 0U ) ) + { + xSocketBits |= eSELECT_READ; + } + /* The WRITE and EXCEPT bits are not used for UDP */ + } /* if( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP ) */ + + /* Each socket keeps its own event flags, which are looked-up + by FreeRTOS_FD_ISSSET() */ + pxSocket->xSocketBits = xSocketBits; + + /* The ORed value will be used to set the bits in the event + group. */ + xGroupBits |= xSocketBits; + + } /* for( pxIterator ... ) */ + } /* for( xRound = 0; xRound <= xLastRound; xRound++ ) */ + + xBitsToClear = xEventGroupGetBits( pxSocketSet->xSelectGroup ); + + /* Now set the necessary bits. */ + xBitsToClear = ( xBitsToClear & ~xGroupBits ) & eSELECT_ALL; + + #if( ipconfigSUPPORT_SIGNALS != 0 ) + { + /* Maybe the socketset was signalled, but don't + clear the 'eSELECT_INTR' bit here, as it will be used + and cleared in FreeRTOS_select(). */ + xBitsToClear &= ( EventBits_t ) ~eSELECT_INTR; + } + #endif /* ipconfigSUPPORT_SIGNALS */ + + if( xBitsToClear != 0 ) + { + xEventGroupClearBits( pxSocketSet->xSelectGroup, xBitsToClear ); + } + + /* Now include eSELECT_CALL_IP to wakeup the caller. */ + xEventGroupSetBits( pxSocketSet->xSelectGroup, xGroupBits | eSELECT_CALL_IP ); + } + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SIGNALS != 0 ) + + /* Send a signal to the task which reads from this socket. */ + BaseType_t FreeRTOS_SignalSocket( Socket_t xSocket ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn; + + if( pxSocket == NULL ) + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + else + #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + if( ( pxSocket->pxSocketSet != NULL ) && ( pxSocket->pxSocketSet->xSelectGroup != NULL ) ) + { + xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, eSELECT_INTR ); + xReturn = 0; + } + else + #endif /* ipconfigSUPPORT_SELECT_FUNCTION */ + if( pxSocket->xEventGroup != NULL ) + { + xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_INTR ); + xReturn = 0; + } + else + { + xReturn = -pdFREERTOS_ERRNO_EINVAL; + } + + return xReturn; + } + +#endif /* ipconfigSUPPORT_SIGNALS */ +/*-----------------------------------------------------------*/ + +#if( ipconfigSUPPORT_SIGNALS != 0 ) + + /* Send a signal to the task which reads from this socket (FromISR version). */ + BaseType_t FreeRTOS_SignalSocketFromISR( Socket_t xSocket, BaseType_t *pxHigherPriorityTaskWoken ) + { + FreeRTOS_Socket_t *pxSocket = ( FreeRTOS_Socket_t * ) xSocket; + BaseType_t xReturn; + IPStackEvent_t xEvent; + extern QueueHandle_t xNetworkEventQueue; + + configASSERT( pxSocket != NULL ); + configASSERT( pxSocket->ucProtocol == FREERTOS_IPPROTO_TCP ); + configASSERT( pxSocket->xEventGroup ); + + xEvent.eEventType = eSocketSignalEvent; + xEvent.pvData = ( void * )pxSocket; + + /* The IP-task will call FreeRTOS_SignalSocket for this socket. */ + xReturn = xQueueSendToBackFromISR( xNetworkEventQueue, &xEvent, pxHigherPriorityTaskWoken ); + + return xReturn; + } + +#endif /* ipconfigSUPPORT_SIGNALS */ +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c new file mode 100644 index 000000000..994da7384 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c @@ -0,0 +1,199 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" + +/* + * uxStreamBufferAdd( ) + * Adds data to a stream buffer. If uxOffset > 0, data will be written at + * an offset from uxHead while uxHead will not be moved yet. This possibility + * will be used when TCP data is received while earlier data is still missing. + * If 'pucData' equals NULL, the function is called to advance 'uxHead' only. + */ +size_t uxStreamBufferAdd( StreamBuffer_t *pxBuffer, size_t uxOffset, const uint8_t *pucData, size_t uxCount ) +{ +size_t uxSpace, uxNextHead, uxFirst; + + uxSpace = uxStreamBufferGetSpace( pxBuffer ); + + /* If uxOffset > 0, items can be placed in front of uxHead */ + if( uxSpace > uxOffset ) + { + uxSpace -= uxOffset; + } + else + { + uxSpace = 0u; + } + + /* The number of bytes that can be written is the minimum of the number of + bytes requested and the number available. */ + uxCount = FreeRTOS_min_uint32( uxSpace, uxCount ); + + if( uxCount != 0u ) + { + uxNextHead = pxBuffer->uxHead; + + if( uxOffset != 0u ) + { + /* ( uxOffset > 0 ) means: write in front if the uxHead marker */ + uxNextHead += uxOffset; + if( uxNextHead >= pxBuffer->LENGTH ) + { + uxNextHead -= pxBuffer->LENGTH; + } + } + + if( pucData != NULL ) + { + /* Calculate the number of bytes that can be added in the first + write - which may be less than the total number of bytes that need + to be added if the buffer will wrap back to the beginning. */ + uxFirst = FreeRTOS_min_uint32( pxBuffer->LENGTH - uxNextHead, uxCount ); + + /* Write as many bytes as can be written in the first write. */ + memcpy( ( void* ) ( pxBuffer->ucArray + uxNextHead ), pucData, uxFirst ); + + /* If the number of bytes written was less than the number that + could be written in the first write... */ + if( uxCount > uxFirst ) + { + /* ...then write the remaining bytes to the start of the + buffer. */ + memcpy( ( void * )pxBuffer->ucArray, pucData + uxFirst, uxCount - uxFirst ); + } + } + + if( uxOffset == 0u ) + { + /* ( uxOffset == 0 ) means: write at uxHead position */ + uxNextHead += uxCount; + if( uxNextHead >= pxBuffer->LENGTH ) + { + uxNextHead -= pxBuffer->LENGTH; + } + pxBuffer->uxHead = uxNextHead; + } + + if( xStreamBufferLessThenEqual( pxBuffer, pxBuffer->uxFront, uxNextHead ) != pdFALSE ) + { + /* Advance the front pointer */ + pxBuffer->uxFront = uxNextHead; + } + } + + return uxCount; +} +/*-----------------------------------------------------------*/ + +/* + * uxStreamBufferGet( ) + * 'uxOffset' can be used to read data located at a certain offset from 'lTail'. + * If 'pucData' equals NULL, the function is called to advance 'lTail' only. + * if 'xPeek' is pdTRUE, or if 'uxOffset' is non-zero, the 'lTail' pointer will + * not be advanced. + */ +size_t uxStreamBufferGet( StreamBuffer_t *pxBuffer, size_t uxOffset, uint8_t *pucData, size_t uxMaxCount, BaseType_t xPeek ) +{ +size_t uxSize, uxCount, uxFirst, uxNextTail; + + /* How much data is available? */ + uxSize = uxStreamBufferGetSize( pxBuffer ); + + if( uxSize > uxOffset ) + { + uxSize -= uxOffset; + } + else + { + uxSize = 0u; + } + + /* Use the minimum of the wanted bytes and the available bytes. */ + uxCount = FreeRTOS_min_uint32( uxSize, uxMaxCount ); + + if( uxCount > 0u ) + { + uxNextTail = pxBuffer->uxTail; + + if( uxOffset != 0u ) + { + uxNextTail += uxOffset; + if( uxNextTail >= pxBuffer->LENGTH ) + { + uxNextTail -= pxBuffer->LENGTH; + } + } + + if( pucData != NULL ) + { + /* Calculate the number of bytes that can be read - which may be + less than the number wanted if the data wraps around to the start of + the buffer. */ + uxFirst = FreeRTOS_min_uint32( pxBuffer->LENGTH - uxNextTail, uxCount ); + + /* Obtain the number of bytes it is possible to obtain in the first + read. */ + memcpy( pucData, pxBuffer->ucArray + uxNextTail, uxFirst ); + + /* If the total number of wanted bytes is greater than the number + that could be read in the first read... */ + if( uxCount > uxFirst ) + { + /*...then read the remaining bytes from the start of the buffer. */ + memcpy( pucData + uxFirst, pxBuffer->ucArray, uxCount - uxFirst ); + } + } + + if( ( xPeek == pdFALSE ) && ( uxOffset == 0UL ) ) + { + /* Move the tail pointer to effecively remove the data read from + the buffer. */ + uxNextTail += uxCount; + + if( uxNextTail >= pxBuffer->LENGTH ) + { + uxNextTail -= pxBuffer->LENGTH; + } + + pxBuffer->uxTail = uxNextTail; + } + } + + return uxCount; +} + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c new file mode 100644 index 000000000..3b1c5a1e5 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c @@ -0,0 +1,3356 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* + * FreeRTOS_TCP_IP.c + * Module which handles the TCP connections for FreeRTOS+TCP. + * It depends on FreeRTOS_TCP_WIN.c, which handles the TCP windowing + * schemes. + * + * Endianness: in this module all ports and IP addresses are stored in + * host byte-order, except fields in the IP-packets + */ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_TCP_IP.h" +#include "FreeRTOS_DHCP.h" +#include "NetworkInterface.h" +#include "NetworkBufferManagement.h" +#include "FreeRTOS_ARP.h" +#include "FreeRTOS_TCP_WIN.h" + + +/* Just make sure the contents doesn't get compiled if TCP is not enabled. */ +#if ipconfigUSE_TCP == 1 + +/* This compile-time test was moved to here because some macro's +were unknown within 'FreeRTOSIPConfigDefaults.h'. It tests whether +the defined MTU size can contain at least a complete TCP packet. */ + +#if ( ( ipconfigTCP_MSS + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) > ipconfigNETWORK_MTU ) + #error The ipconfigTCP_MSS setting in FreeRTOSIPConfig.h is too large. +#endif + +/* + * The meaning of the TCP flags: + */ +#define ipTCP_FLAG_FIN 0x0001u /* No more data from sender */ +#define ipTCP_FLAG_SYN 0x0002u /* Synchronize sequence numbers */ +#define ipTCP_FLAG_RST 0x0004u /* Reset the connection */ +#define ipTCP_FLAG_PSH 0x0008u /* Push function: please push buffered data to the recv application */ +#define ipTCP_FLAG_ACK 0x0010u /* Acknowledgment field is significant */ +#define ipTCP_FLAG_URG 0x0020u /* Urgent pointer field is significant */ +#define ipTCP_FLAG_ECN 0x0040u /* ECN-Echo */ +#define ipTCP_FLAG_CWR 0x0080u /* Congestion Window Reduced */ +#define ipTCP_FLAG_NS 0x0100u /* ECN-nonce concealment protection */ +#define ipTCP_FLAG_RSV 0x0E00u /* Reserved, keep 0 */ + +/* A mask to filter all protocol flags. */ +#define ipTCP_FLAG_CTRL 0x001Fu + +/* + * A few values of the TCP options: + */ +#define TCP_OPT_END 0u /* End of TCP options list */ +#define TCP_OPT_NOOP 1u /* "No-operation" TCP option */ +#define TCP_OPT_MSS 2u /* Maximum segment size TCP option */ +#define TCP_OPT_WSOPT 3u /* TCP Window Scale Option (3-byte long) */ +#define TCP_OPT_SACK_P 4u /* Advertize that SACK is permitted */ +#define TCP_OPT_SACK_A 5u /* SACK option with first/last */ +#define TCP_OPT_TIMESTAMP 8u /* Time-stamp option */ + +#define TCP_OPT_MSS_LEN 4u /* Length of TCP MSS option. */ +#define TCP_OPT_WSOPT_LEN 3u /* Length of TCP WSOPT option. */ + +#define TCP_OPT_TIMESTAMP_LEN 10 /* fixed length of the time-stamp option */ + +#ifndef ipconfigTCP_ACK_EARLIER_PACKET + #define ipconfigTCP_ACK_EARLIER_PACKET 1 +#endif + +/* + * The macro NOW_CONNECTED() is use to determine if the connection makes a + * transition from connected to non-connected and vice versa. + * NOW_CONNECTED() returns true when the status has one of these values: + * eESTABLISHED, eFIN_WAIT_1, eFIN_WAIT_2, eCLOSING, eLAST_ACK, eTIME_WAIT + * Technically the connection status is closed earlier, but the library wants + * to prevent that the socket will be deleted before the last ACK has been + * and thus causing a 'RST' packet on either side. + */ +#define NOW_CONNECTED( status )\ + ( ( status >= eESTABLISHED ) && ( status != eCLOSE_WAIT ) ) + +/* + * The highest 4 bits in the TCP offset byte indicate the total length of the + * TCP header, divided by 4. + */ +#define VALID_BITS_IN_TCP_OFFSET_BYTE ( 0xF0u ) + +/* + * Acknowledgements to TCP data packets may be delayed as long as more is being expected. + * A normal delay would be 200ms. Here a much shorter delay of 20 ms is being used to + * gain performance. + */ +#define DELAYED_ACK_SHORT_DELAY_MS ( 2 ) +#define DELAYED_ACK_LONGER_DELAY_MS ( 20 ) + +/* + * The MSS (Maximum Segment Size) will be taken as large as possible. However, packets with + * an MSS of 1460 bytes won't be transported through the internet. The MSS will be reduced + * to 1400 bytes. + */ +#define REDUCED_MSS_THROUGH_INTERNET ( 1400 ) + +/* + * When there are no TCP options, the TCP offset equals 20 bytes, which is stored as + * the number 5 (words) in the higher niblle of the TCP-offset byte. + */ +#define TCP_OFFSET_LENGTH_BITS ( 0xf0u ) +#define TCP_OFFSET_STANDARD_LENGTH ( 0x50u ) + +/* + * Each TCP socket is checked regularly to see if it can send data packets. + * By default, the maximum number of packets sent during one check is limited to 8. + * This amount may be further limited by setting the socket's TX window size. + */ +#if( !defined( SEND_REPEATED_COUNT ) ) + #define SEND_REPEATED_COUNT ( 8 ) +#endif /* !defined( SEND_REPEATED_COUNT ) */ + +/* + * Define a maximum perdiod of time (ms) to leave a TCP-socket unattended. + * When a TCP timer expires, retries and keep-alive messages will be checked. + */ +#ifndef tcpMAXIMUM_TCP_WAKEUP_TIME_MS + #define tcpMAXIMUM_TCP_WAKEUP_TIME_MS 20000u +#endif + +/* + * The names of the different TCP states may be useful in logging. + */ +#if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) + static const char *pcStateNames[] = { + "eCLOSED", + "eTCP_LISTEN", + "eCONNECT_SYN", + "eSYN_FIRST", + "eSYN_RECEIVED", + "eESTABLISHED", + "eFIN_WAIT_1", + "eFIN_WAIT_2", + "eCLOSE_WAIT", + "eCLOSING", + "eLAST_ACK", + "eTIME_WAIT", + "eUNKNOWN", +}; +#endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) */ + +/* + * Returns true if the socket must be checked. Non-active sockets are waiting + * for user action, either connect() or close(). + */ +static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus ); + +/* + * Either sends a SYN or calls prvTCPSendRepeated (for regular messages). + */ +static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket ); + +/* + * Try to send a series of messages. + */ +static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer ); + +/* + * Return or send a packet to the other party. + */ +static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, + uint32_t ulLen, BaseType_t xReleaseAfterSend ); + +/* + * Initialise the data structures which keep track of the TCP windowing system. + */ +static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket ); + +/* + * Let ARP look-up the MAC-address of the peer and initialise the first SYN + * packet. + */ +static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket ); + +#if( ipconfigHAS_DEBUG_PRINTF != 0 ) + /* + * For logging and debugging: make a string showing the TCP flags. + */ + static const char *prvTCPFlagMeaning( UBaseType_t xFlags); +#endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ + +/* + * Parse the TCP option(s) received, if present. + */ +static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer ); + +/* + * Set the initial properties in the options fields, like the preferred + * value of MSS and whether SACK allowed. Will be transmitted in the state + * 'eCONNECT_SYN'. + */ +static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket ); + +/* + * For anti-hang protection and TCP keep-alive messages. Called in two places: + * after receiving a packet and after a state change. The socket's alive timer + * may be reset. + */ +static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket ); + +/* + * Prepare an outgoing message, if anything has to be sent. + */ +static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength ); + +/* + * Calculate when this socket needs to be checked to do (re-)transmissions. + */ +static TickType_t prvTCPNextTimeout( FreeRTOS_Socket_t *pxSocket ); + +/* + * The API FreeRTOS_send() adds data to the TX stream. Add + * this data to the windowing system to it can be transmitted. + */ +static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket ); + +/* + * Called to handle the closure of a TCP connection. + */ +static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer ); + +/* + * Called from prvTCPHandleState(). Find the TCP payload data and check and + * return its length. + */ +static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData ); + +/* + * Called from prvTCPHandleState(). Check if the payload data may be accepted. + * If so, it will be added to the socket's reception queue. + */ +static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData, + NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength ); + +/* + * Set the TCP options (if any) for the outgoing packet. + */ +static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer ); + +/* + * Called from prvTCPHandleState() as long as the TCP status is eSYN_RECEIVED to + * eCONNECT_SYN. + */ +static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, + uint32_t ulReceiveLength, UBaseType_t uxOptionsLength ); + +/* + * Called from prvTCPHandleState() as long as the TCP status is eESTABLISHED. + */ +static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, + uint32_t ulReceiveLength, UBaseType_t uxOptionsLength ); + +/* + * Called from prvTCPHandleState(). There is data to be sent. + * If ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will + * be checked if it would better be postponed for efficiency. + */ +static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, + uint32_t ulReceiveLength, BaseType_t xSendLength ); + +/* + * The heart of all: check incoming packet for valid data and acks and do what + * is necessary in each state. + */ +static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer ); + +/* + * Common code for sending a TCP protocol control packet (i.e. no options, no + * payload, just flags). + */ +static BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t *pxNetworkBuffer, + uint8_t ucTCPFlags ); + +/* + * A "challenge ACK" is as per https://tools.ietf.org/html/rfc5961#section-3.2, + * case #3. In summary, an RST was received with a sequence number that is + * unexpected but still within the window. + */ +static BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t *pxNetworkBuffer ); + +/* + * Reply to a peer with the RST flag on, in case a packet can not be handled. + */ +static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer ); + +/* + * Set the initial value for MSS (Maximum Segment Size) to be used. + */ +static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket ); + +/* + * Return either a newly created socket, or the current socket in a connected + * state (depends on the 'bReuseSocket' flag). + */ +static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer ); + +/* + * After a listening socket receives a new connection, it may duplicate itself. + * The copying takes place in prvTCPSocketCopy. + */ +static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket ); + +/* + * prvTCPStatusAgeCheck() will see if the socket has been in a non-connected + * state for too long. If so, the socket will be closed, and -1 will be + * returned. + */ +#if( ipconfigTCP_HANG_PROTECTION == 1 ) + static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket ); +#endif + +static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, + int32_t lDataLen, UBaseType_t uxOptionsLength ); + +#if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) + const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState ); +#endif + +#if( ipconfigUSE_TCP_WIN != 0 ) + static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket ); +#endif + +/* + * Generate a randomized TCP Initial Sequence Number per RFC. + */ +extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress, + uint16_t usSourcePort, + uint32_t ulDestinationAddress, + uint16_t usDestinationPort ); + +/*-----------------------------------------------------------*/ + +/* prvTCPSocketIsActive() returns true if the socket must be checked. + * Non-active sockets are waiting for user action, either connect() + * or close(). */ +static BaseType_t prvTCPSocketIsActive( UBaseType_t uxStatus ) +{ + switch( uxStatus ) + { + case eCLOSED: + case eCLOSE_WAIT: + case eFIN_WAIT_2: + case eCLOSING: + case eTIME_WAIT: + return pdFALSE; + default: + return pdTRUE; + } +} +/*-----------------------------------------------------------*/ + +#if( ipconfigTCP_HANG_PROTECTION == 1 ) + + static BaseType_t prvTCPStatusAgeCheck( FreeRTOS_Socket_t *pxSocket ) + { + BaseType_t xResult; + switch( pxSocket->u.xTCP.ucTCPState ) + { + case eESTABLISHED: + /* If the 'ipconfigTCP_KEEP_ALIVE' option is enabled, sockets in + state ESTABLISHED can be protected using keep-alive messages. */ + xResult = pdFALSE; + break; + case eCLOSED: + case eTCP_LISTEN: + case eCLOSE_WAIT: + /* These 3 states may last for ever, up to the owner. */ + xResult = pdFALSE; + break; + default: + /* All other (non-connected) states will get anti-hanging + protection. */ + xResult = pdTRUE; + break; + } + if( xResult != pdFALSE ) + { + /* How much time has past since the last active moment which is + defined as A) a state change or B) a packet has arrived. */ + TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastActTime; + + /* ipconfigTCP_HANG_PROTECTION_TIME is in units of seconds. */ + if( xAge > ( ipconfigTCP_HANG_PROTECTION_TIME * configTICK_RATE_HZ ) ) + { + #if( ipconfigHAS_DEBUG_PRINTF == 1 ) + { + FreeRTOS_debug_printf( ( "Inactive socket closed: port %u rem %lxip:%u status %s\n", + pxSocket->usLocalPort, + pxSocket->u.xTCP.ulRemoteIP, + pxSocket->u.xTCP.usRemotePort, + FreeRTOS_GetTCPStateName( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) ) ); + } + #endif /* ipconfigHAS_DEBUG_PRINTF */ + + /* Move to eCLOSE_WAIT, user may close the socket. */ + vTCPStateChange( pxSocket, eCLOSE_WAIT ); + + /* When 'bPassQueued' true, this socket is an orphan until it + gets connected. */ + if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) + { + if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) + { + /* As it did not get connected, and the user can never + accept() it anymore, it will be deleted now. Called from + the IP-task, so it's safe to call the internal Close + function: vSocketClose(). */ + vSocketClose( pxSocket ); + } + /* Return a negative value to tell to inform the caller + xTCPTimerCheck() + that the socket got closed and may not be accessed anymore. */ + xResult = -1; + } + } + } + return xResult; + } + /*-----------------------------------------------------------*/ + +#endif + +/* + * As soon as a TCP socket timer expires, this function xTCPSocketCheck + * will be called (from xTCPTimerCheck) + * It can send a delayed ACK or new data + * Sequence of calling (normally) : + * IP-Task: + * xTCPTimerCheck() // Check all sockets ( declared in FreeRTOS_Sockets.c ) + * xTCPSocketCheck() // Either send a delayed ACK or call prvTCPSendPacket() + * prvTCPSendPacket() // Either send a SYN or call prvTCPSendRepeated ( regular messages ) + * prvTCPSendRepeated() // Send at most 8 messages on a row + * prvTCPReturnPacket() // Prepare for returning + * xNetworkInterfaceOutput() // Sends data to the NIC ( declared in portable/NetworkInterface/xxx ) + */ +BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t *pxSocket ) +{ +BaseType_t xResult = 0; +BaseType_t xReady = pdFALSE; + + if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.txStream != NULL ) ) + { + /* The API FreeRTOS_send() might have added data to the TX stream. Add + this data to the windowing system to it can be transmitted. */ + prvTCPAddTxData( pxSocket ); + } + + #if ipconfigUSE_TCP_WIN == 1 + { + if( pxSocket->u.xTCP.pxAckMessage != NULL ) + { + /* The first task of this regular socket check is to send-out delayed + ACK's. */ + if( pxSocket->u.xTCP.bits.bUserShutdown == pdFALSE_UNSIGNED ) + { + /* Earlier data was received but not yet acknowledged. This + function is called when the TCP timer for the socket expires, the + ACK may be sent now. */ + if( pxSocket->u.xTCP.ucTCPState != eCLOSED ) + { + if( xTCPWindowLoggingLevel > 1 && ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) ) + { + FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %u)\n", + pxSocket->usLocalPort, + pxSocket->u.xTCP.usRemotePort, + pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber, + pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber, + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ); + } + + prvTCPReturnPacket( pxSocket, pxSocket->u.xTCP.pxAckMessage, ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER, ipconfigZERO_COPY_TX_DRIVER ); + + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + /* The ownership has been passed to the SEND routine, + clear the pointer to it. */ + pxSocket->u.xTCP.pxAckMessage = NULL; + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + } + if( prvTCPNextTimeout( pxSocket ) > 1 ) + { + /* Tell the code below that this function is ready. */ + xReady = pdTRUE; + } + } + else + { + /* The user wants to perform an active shutdown(), skip sending + the delayed ACK. The function prvTCPSendPacket() will send the + FIN along with the ACK's. */ + } + + if( pxSocket->u.xTCP.pxAckMessage != NULL ) + { + vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage ); + pxSocket->u.xTCP.pxAckMessage = NULL; + } + } + } + #endif /* ipconfigUSE_TCP_WIN */ + + if( xReady == pdFALSE ) + { + /* The second task of this regular socket check is sending out data. */ + if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) || + ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) ) + { + prvTCPSendPacket( pxSocket ); + } + + /* Set the time-out for the next wakeup for this socket. */ + prvTCPNextTimeout( pxSocket ); + + #if( ipconfigTCP_HANG_PROTECTION == 1 ) + { + /* In all (non-connected) states in which keep-alive messages can not be sent + the anti-hang protocol will close sockets that are 'hanging'. */ + xResult = prvTCPStatusAgeCheck( pxSocket ); + } + #endif + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +/* + * prvTCPSendPacket() will be called when the socket time-out has been reached. + * It is only called by xTCPSocketCheck(). + */ +static int32_t prvTCPSendPacket( FreeRTOS_Socket_t *pxSocket ) +{ +int32_t lResult = 0; +UBaseType_t uxOptionsLength; +TCPPacket_t *pxTCPPacket; +NetworkBufferDescriptor_t *pxNetworkBuffer; + + if( pxSocket->u.xTCP.ucTCPState != eCONNECT_SYN ) + { + /* The connection is in s state other than SYN. */ + pxNetworkBuffer = NULL; + + /* prvTCPSendRepeated() will only create a network buffer if necessary, + i.e. when data must be sent to the peer. */ + lResult = prvTCPSendRepeated( pxSocket, &pxNetworkBuffer ); + + if( pxNetworkBuffer != NULL ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + } + else + { + if( pxSocket->u.xTCP.ucRepCount >= 3u ) + { + /* The connection is in the SYN status. The packet will be repeated + to most 3 times. When there is no response, the socket get the + status 'eCLOSE_WAIT'. */ + FreeRTOS_debug_printf( ( "Connect: giving up %lxip:%u\n", + pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */ + pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */ + vTCPStateChange( pxSocket, eCLOSE_WAIT ); + } + else if( ( pxSocket->u.xTCP.bits.bConnPrepared != pdFALSE_UNSIGNED ) || ( prvTCPPrepareConnect( pxSocket ) == pdTRUE ) ) + { + /* Or else, if the connection has been prepared, or can be prepared + now, proceed to send the packet with the SYN flag. + prvTCPPrepareConnect() prepares 'xPacket' and returns pdTRUE if + the Ethernet address of the peer or the gateway is found. */ + pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket; + + /* About to send a SYN packet. Call prvSetSynAckOptions() to set + the proper options: The size of MSS and whether SACK's are + allowed. */ + uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket ); + + /* Return the number of bytes to be sent. */ + lResult = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ); + + /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and + uxOptionsLength is always a multiple of 4. The complete expression + would be: + ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */ + pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); + + /* Repeat Count is used for a connecting socket, to limit the number + of tries. */ + pxSocket->u.xTCP.ucRepCount++; + + /* Send the SYN message to make a connection. The messages is + stored in the socket field 'xPacket'. It will be wrapped in a + pseudo network buffer descriptor before it will be sent. */ + prvTCPReturnPacket( pxSocket, NULL, ( uint32_t ) lResult, pdFALSE ); + } + } + + /* Return the total number of bytes sent. */ + return lResult; +} +/*-----------------------------------------------------------*/ + +/* + * prvTCPSendRepeated will try to send a series of messages, as long as there is + * data to be sent and as long as the transmit window isn't full. + */ +static int32_t prvTCPSendRepeated( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer ) +{ +UBaseType_t uxIndex; +int32_t lResult = 0; +UBaseType_t uxOptionsLength = 0u; +int32_t xSendLength; + + for( uxIndex = 0u; uxIndex < ( UBaseType_t ) SEND_REPEATED_COUNT; uxIndex++ ) + { + /* prvTCPPrepareSend() might allocate a network buffer if there is data + to be sent. */ + xSendLength = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength ); + if( xSendLength <= 0 ) + { + break; + } + + /* And return the packet to the peer. */ + prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER ); + + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + *ppxNetworkBuffer = NULL; + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + + lResult += xSendLength; + } + + /* Return the total number of bytes sent. */ + return lResult; +} +/*-----------------------------------------------------------*/ + +/* + * Return (or send) a packet the the peer. The data is stored in pxBuffer, + * which may either point to a real network buffer or to a TCP socket field + * called 'xTCP.xPacket'. A temporary xNetworkBuffer will be used to pass + * the data to the NIC. + */ +static void prvTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulLen, BaseType_t xReleaseAfterSend ) +{ +TCPPacket_t * pxTCPPacket; +IPHeader_t *pxIPHeader; +EthernetHeader_t *pxEthernetHeader; +uint32_t ulFrontSpace, ulSpace, ulSourceAddress, ulWinSize; +TCPWindow_t *pxTCPWindow; +NetworkBufferDescriptor_t xTempBuffer; +/* For sending, a pseudo network buffer will be used, as explained above. */ + + if( pxNetworkBuffer == NULL ) + { + pxNetworkBuffer = &xTempBuffer; + + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + { + xTempBuffer.pxNextBuffer = NULL; + } + #endif + xTempBuffer.pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket; + xTempBuffer.xDataLength = sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ); + xReleaseAfterSend = pdFALSE; + } + + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + if( xReleaseAfterSend == pdFALSE ) + { + pxNetworkBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength ); + if( pxNetworkBuffer == NULL ) + { + FreeRTOS_debug_printf( ( "prvTCPReturnPacket: duplicate failed\n" ) ); + } + xReleaseAfterSend = pdTRUE; + } + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + + if( pxNetworkBuffer != NULL ) + { + pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); + pxIPHeader = &pxTCPPacket->xIPHeader; + pxEthernetHeader = &pxTCPPacket->xEthernetHeader; + + /* Fill the packet, using hton translations. */ + if( pxSocket != NULL ) + { + /* Calculate the space in the RX buffer in order to advertise the + size of this socket's reception window. */ + pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow ); + + if( pxSocket->u.xTCP.rxStream != NULL ) + { + /* An RX stream was created already, see how much space is + available. */ + ulFrontSpace = ( uint32_t ) uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ); + } + else + { + /* No RX stream has been created, the full stream size is + available. */ + ulFrontSpace = ( uint32_t ) pxSocket->u.xTCP.uxRxStreamSize; + } + + /* Take the minimum of the RX buffer space and the RX window size. */ + ulSpace = FreeRTOS_min_uint32( pxTCPWindow->xSize.ulRxWindowLength, ulFrontSpace ); + + if( ( pxSocket->u.xTCP.bits.bLowWater != pdFALSE_UNSIGNED ) || ( pxSocket->u.xTCP.bits.bRxStopped != pdFALSE_UNSIGNED ) ) + { + /* The low-water mark was reached, meaning there was little + space left. The socket will wait until the application has read + or flushed the incoming data, and 'zero-window' will be + advertised. */ + ulSpace = 0u; + } + + /* If possible, advertise an RX window size of at least 1 MSS, otherwise + the peer might start 'zero window probing', i.e. sending small packets + (1, 2, 4, 8... bytes). */ + if( ( ulSpace < pxSocket->u.xTCP.usCurMSS ) && ( ulFrontSpace >= pxSocket->u.xTCP.usCurMSS ) ) + { + ulSpace = pxSocket->u.xTCP.usCurMSS; + } + + /* Avoid overflow of the 16-bit win field. */ + #if( ipconfigUSE_TCP_WIN != 0 ) + { + ulWinSize = ( ulSpace >> pxSocket->u.xTCP.ucMyWinScaleFactor ); + } + #else + { + ulWinSize = ulSpace; + } + #endif + if( ulWinSize > 0xfffcUL ) + { + ulWinSize = 0xfffcUL; + } + + pxTCPPacket->xTCPHeader.usWindow = FreeRTOS_htons( ( uint16_t ) ulWinSize ); + + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + if( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) + { + if( ( xTCPWindowLoggingLevel != 0 ) && ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) ) + { + size_t uxFrontSpace; + + if(pxSocket->u.xTCP.rxStream != NULL) + { + uxFrontSpace = uxStreamBufferFrontSpace( pxSocket->u.xTCP.rxStream ) ; + } + else + { + uxFrontSpace = 0u; + } + + FreeRTOS_debug_printf( ( "%s: %lxip:%u: [%lu < %lu] winSize %ld\n", + pxSocket->u.xTCP.bits.bLowWater ? "STOP" : "GO ", + pxSocket->u.xTCP.ulRemoteIP, + pxSocket->u.xTCP.usRemotePort, + pxSocket->u.xTCP.bits.bLowWater ? pxSocket->u.xTCP.uxLittleSpace : uxFrontSpace, pxSocket->u.xTCP.uxEnoughSpace, + (int32_t) ( pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulCurrentSequenceNumber ) ) ); + } + } + } + #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ + + /* The new window size has been advertised, switch off the flag. */ + pxSocket->u.xTCP.bits.bWinChange = pdFALSE_UNSIGNED; + + /* Later on, when deciding to delay an ACK, a precise estimate is needed + of the free RX space. At this moment, 'ulHighestRxAllowed' would be the + highest sequence number minus 1 that the socket will accept. */ + pxSocket->u.xTCP.ulHighestRxAllowed = pxTCPWindow->rx.ulCurrentSequenceNumber + ulSpace; + + #if( ipconfigTCP_KEEP_ALIVE == 1 ) + if( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) + { + /* Sending a keep-alive packet, send the current sequence number + minus 1, which will be recognised as a keep-alive packet an + responded to by acknowledging the last byte. */ + pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED; + pxSocket->u.xTCP.bits.bWaitKeepAlive = pdTRUE_UNSIGNED; + + pxTCPPacket->xTCPHeader.ulSequenceNumber = pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - 1UL; + pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxTCPPacket->xTCPHeader.ulSequenceNumber ); + } + else + #endif + { + pxTCPPacket->xTCPHeader.ulSequenceNumber = FreeRTOS_htonl( pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber ); + + if( ( pxTCPPacket->xTCPHeader.ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u ) + { + /* Suppress FIN in case this packet carries earlier data to be + retransmitted. */ + uint32_t ulDataLen = ( uint32_t ) ( ulLen - ( ipSIZE_OF_TCP_HEADER + ipSIZE_OF_IPv4_HEADER ) ); + if( ( pxTCPWindow->ulOurSequenceNumber + ulDataLen ) != pxTCPWindow->tx.ulFINSequenceNumber ) + { + pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_FIN ); + FreeRTOS_debug_printf( ( "Suppress FIN for %lu + %lu < %lu\n", + pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber, + ulDataLen, + pxTCPWindow->tx.ulFINSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber ) ); + } + } + } + + /* Tell which sequence number is expected next time */ + pxTCPPacket->xTCPHeader.ulAckNr = FreeRTOS_htonl( pxTCPWindow->rx.ulCurrentSequenceNumber ); + } + else + { + /* Sending data without a socket, probably replying with a RST flag + Just swap the two sequence numbers. */ + vFlip_32( pxTCPPacket->xTCPHeader.ulSequenceNumber, pxTCPPacket->xTCPHeader.ulAckNr ); + } + + pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE; + pxIPHeader->usLength = FreeRTOS_htons( ulLen ); + if( ( pxSocket == NULL ) || ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) ) + { + /* When pxSocket is NULL, this function is called by prvTCPSendReset() + and the IP-addresses must be swapped. + Also swap the IP-addresses in case the IP-tack doesn't have an + IP-address yet, i.e. when ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ). */ + ulSourceAddress = pxIPHeader->ulDestinationIPAddress; + } + else + { + ulSourceAddress = *ipLOCAL_IP_ADDRESS_POINTER; + } + pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress; + pxIPHeader->ulSourceIPAddress = ulSourceAddress; + vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort ); + + /* Just an increasing number. */ + pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier ); + usPacketIdentifier++; + pxIPHeader->usFragmentOffset = 0u; + + #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) + { + /* calculate the IP header checksum, in case the driver won't do that. */ + pxIPHeader->usHeaderChecksum = 0x00u; + pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER ); + pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); + + /* calculate the TCP checksum for an outgoing packet. */ + usGenerateProtocolChecksum( (uint8_t*)pxTCPPacket, pxNetworkBuffer->xDataLength, pdTRUE ); + + /* A calculated checksum of 0 must be inverted as 0 means the checksum + is disabled. */ + if( pxTCPPacket->xTCPHeader.usChecksum == 0x00u ) + { + pxTCPPacket->xTCPHeader.usChecksum = 0xffffU; + } + } + #endif + + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + pxNetworkBuffer->pxNextBuffer = NULL; + #endif + + /* Important: tell NIC driver how many bytes must be sent. */ + pxNetworkBuffer->xDataLength = ulLen + ipSIZE_OF_ETH_HEADER; + + /* Fill in the destination MAC addresses. */ + memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ), + sizeof( pxEthernetHeader->xDestinationAddress ) ); + + /* The source MAC addresses is fixed to 'ipLOCAL_MAC_ADDRESS'. */ + memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES ); + + #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES ) + { + if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES ) + { + BaseType_t xIndex; + + for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ ) + { + pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u; + } + pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; + } + } + #endif + + /* Send! */ + xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend ); + + if( xReleaseAfterSend == pdFALSE ) + { + /* Swap-back some fields, as pxBuffer probably points to a socket field + containing the packet header. */ + vFlip_16( pxTCPPacket->xTCPHeader.usSourcePort, pxTCPPacket->xTCPHeader.usDestinationPort); + pxTCPPacket->xIPHeader.ulSourceIPAddress = pxTCPPacket->xIPHeader.ulDestinationIPAddress; + memcpy( pxEthernetHeader->xSourceAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES ); + } + else + { + /* Nothing to do: the buffer has been passed to DMA and will be released after use */ + } + } /* if( pxNetworkBuffer != NULL ) */ +} +/*-----------------------------------------------------------*/ + +/* + * The SYN event is very important: the sequence numbers, which have a kind of + * random starting value, are being synchronised. The sliding window manager + * (in FreeRTOS_TCP_WIN.c) needs to know them, along with the Maximum Segment + * Size (MSS) in use. + */ +static void prvTCPCreateWindow( FreeRTOS_Socket_t *pxSocket ) +{ + if( xTCPWindowLoggingLevel ) + FreeRTOS_debug_printf( ( "Limits (using): TCP Win size %lu Water %lu <= %lu <= %lu\n", + pxSocket->u.xTCP.uxRxWinSize * ipconfigTCP_MSS, + pxSocket->u.xTCP.uxLittleSpace , + pxSocket->u.xTCP.uxEnoughSpace, + pxSocket->u.xTCP.uxRxStreamSize ) ); + vTCPWindowCreate( + &pxSocket->u.xTCP.xTCPWindow, + ipconfigTCP_MSS * pxSocket->u.xTCP.uxRxWinSize, + ipconfigTCP_MSS * pxSocket->u.xTCP.uxTxWinSize, + pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber, + pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, + ( uint32_t ) pxSocket->u.xTCP.usInitMSS ); +} +/*-----------------------------------------------------------*/ + +/* + * Connecting sockets have a special state: eCONNECT_SYN. In this phase, + * the Ethernet address of the target will be found using ARP. In case the + * target IP address is not within the netmask, the hardware address of the + * gateway will be used. + */ +static BaseType_t prvTCPPrepareConnect( FreeRTOS_Socket_t *pxSocket ) +{ +TCPPacket_t *pxTCPPacket; +IPHeader_t *pxIPHeader; +eARPLookupResult_t eReturned; +uint32_t ulRemoteIP; +MACAddress_t xEthAddress; +BaseType_t xReturn = pdTRUE; +uint32_t ulInitialSequenceNumber = 0; + + #if( ipconfigHAS_PRINTF != 0 ) + { + /* Only necessary for nicer logging. */ + memset( xEthAddress.ucBytes, '\0', sizeof( xEthAddress.ucBytes ) ); + } + #endif /* ipconfigHAS_PRINTF != 0 */ + + ulRemoteIP = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP ); + + /* Determine the ARP cache status for the requested IP address. */ + eReturned = eARPGetCacheEntry( &( ulRemoteIP ), &( xEthAddress ) ); + + switch( eReturned ) + { + case eARPCacheHit: /* An ARP table lookup found a valid entry. */ + break; /* We can now prepare the SYN packet. */ + case eARPCacheMiss: /* An ARP table lookup did not find a valid entry. */ + case eCantSendPacket: /* There is no IP address, or an ARP is still in progress. */ + default: + /* Count the number of times it couldn't find the ARP address. */ + pxSocket->u.xTCP.ucRepCount++; + + FreeRTOS_debug_printf( ( "ARP for %lxip (using %lxip): rc=%d %02X:%02X:%02X %02X:%02X:%02X\n", + pxSocket->u.xTCP.ulRemoteIP, + FreeRTOS_htonl( ulRemoteIP ), + eReturned, + xEthAddress.ucBytes[ 0 ], + xEthAddress.ucBytes[ 1 ], + xEthAddress.ucBytes[ 2 ], + xEthAddress.ucBytes[ 3 ], + xEthAddress.ucBytes[ 4 ], + xEthAddress.ucBytes[ 5 ] ) ); + + /* And issue a (new) ARP request */ + FreeRTOS_OutputARPRequest( ulRemoteIP ); + + xReturn = pdFALSE; + } + + if( xReturn != pdFALSE ) + { + /* Get a difficult-to-predict initial sequence number for this 4-tuple. */ + ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( *ipLOCAL_IP_ADDRESS_POINTER, + pxSocket->usLocalPort, + pxSocket->u.xTCP.ulRemoteIP, + pxSocket->u.xTCP.usRemotePort ); + + /* Check for a random number generation error. */ + if( 0 == ulInitialSequenceNumber ) + { + xReturn = pdFALSE; + } + } + + if( xReturn != pdFALSE ) + { + /* The MAC-address of the peer (or gateway) has been found, + now prepare the initial TCP packet and some fields in the socket. */ + pxTCPPacket = ( TCPPacket_t * )pxSocket->u.xTCP.xPacket.u.ucLastPacket; + pxIPHeader = &pxTCPPacket->xIPHeader; + + /* reset the retry counter to zero. */ + pxSocket->u.xTCP.ucRepCount = 0u; + + /* And remember that the connect/SYN data are prepared. */ + pxSocket->u.xTCP.bits.bConnPrepared = pdTRUE_UNSIGNED; + + /* Now that the Ethernet address is known, the initial packet can be + prepared. */ + memset( pxSocket->u.xTCP.xPacket.u.ucLastPacket, '\0', sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) ); + + /* Write the Ethernet address in Source, because it will be swapped by + prvTCPReturnPacket(). */ + memcpy( &pxTCPPacket->xEthernetHeader.xSourceAddress, &xEthAddress, sizeof( xEthAddress ) ); + + /* 'ipIPv4_FRAME_TYPE' is already in network-byte-order. */ + pxTCPPacket->xEthernetHeader.usFrameType = ipIPv4_FRAME_TYPE; + + pxIPHeader->ucVersionHeaderLength = 0x45u; + pxIPHeader->usLength = FreeRTOS_htons( sizeof( TCPPacket_t ) - sizeof( pxTCPPacket->xEthernetHeader ) ); + pxIPHeader->ucTimeToLive = ( uint8_t ) ipconfigTCP_TIME_TO_LIVE; + + pxIPHeader->ucProtocol = ( uint8_t ) ipPROTOCOL_TCP; + + /* Addresses and ports will be stored swapped because prvTCPReturnPacket + will swap them back while replying. */ + pxIPHeader->ulDestinationIPAddress = *ipLOCAL_IP_ADDRESS_POINTER; + pxIPHeader->ulSourceIPAddress = FreeRTOS_htonl( pxSocket->u.xTCP.ulRemoteIP ); + + pxTCPPacket->xTCPHeader.usSourcePort = FreeRTOS_htons( pxSocket->u.xTCP.usRemotePort ); + pxTCPPacket->xTCPHeader.usDestinationPort = FreeRTOS_htons( pxSocket->usLocalPort ); + + /* We are actively connecting, so the peer's Initial Sequence Number (ISN) + isn't known yet. */ + pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = 0ul; + + /* Start with ISN (Initial Sequence Number). */ + pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber; + + /* The TCP header size is 20 bytes, divided by 4 equals 5, which is put in + the high nibble of the TCP offset field. */ + pxTCPPacket->xTCPHeader.ucTCPOffset = 0x50u; + + /* Only set the SYN flag. */ + pxTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_SYN; + + /* Set the values of usInitMSS / usCurMSS for this socket. */ + prvSocketSetMSS( pxSocket ); + + /* The initial sequence numbers at our side are known. Later + vTCPWindowInit() will be called to fill in the peer's sequence numbers, but + first wait for a SYN+ACK reply. */ + prvTCPCreateWindow( pxSocket ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +/* For logging and debugging: make a string showing the TCP flags +*/ +#if( ipconfigHAS_DEBUG_PRINTF != 0 ) + + static const char *prvTCPFlagMeaning( UBaseType_t xFlags) + { + static char retString[10]; + snprintf(retString, sizeof( retString ), "%c%c%c%c%c%c%c%c%c", + ( xFlags & ipTCP_FLAG_FIN ) ? 'F' : '.', /* 0x0001: No more data from sender */ + ( xFlags & ipTCP_FLAG_SYN ) ? 'S' : '.', /* 0x0002: Synchronize sequence numbers */ + ( xFlags & ipTCP_FLAG_RST ) ? 'R' : '.', /* 0x0004: Reset the connection */ + ( xFlags & ipTCP_FLAG_PSH ) ? 'P' : '.', /* 0x0008: Push function: please push buffered data to the recv application */ + ( xFlags & ipTCP_FLAG_ACK ) ? 'A' : '.', /* 0x0010: Acknowledgment field is significant */ + ( xFlags & ipTCP_FLAG_URG ) ? 'U' : '.', /* 0x0020: Urgent pointer field is significant */ + ( xFlags & ipTCP_FLAG_ECN ) ? 'E' : '.', /* 0x0040: ECN-Echo */ + ( xFlags & ipTCP_FLAG_CWR ) ? 'C' : '.', /* 0x0080: Congestion Window Reduced */ + ( xFlags & ipTCP_FLAG_NS ) ? 'N' : '.'); /* 0x0100: ECN-nonce concealment protection */ + return retString; + } + /*-----------------------------------------------------------*/ + +#endif /* ipconfigHAS_DEBUG_PRINTF */ + +/* + * Parse the TCP option(s) received, if present. It has already been verified + * that: ((pxTCPHeader->ucTCPOffset & 0xf0) > 0x50), meaning that the TP header + * is longer than the usual 20 (5 x 4) bytes. + */ +static void prvCheckOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer ) +{ +TCPPacket_t * pxTCPPacket; +TCPHeader_t * pxTCPHeader; +const unsigned char *pucPtr; +const unsigned char *pucLast; +TCPWindow_t *pxTCPWindow; +UBaseType_t uxNewMSS; + + pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); + pxTCPHeader = &pxTCPPacket->xTCPHeader; + + /* A character pointer to iterate through the option data */ + pucPtr = pxTCPHeader->ucOptdata; + pucLast = pucPtr + (((pxTCPHeader->ucTCPOffset >> 4) - 5) << 2); + pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow; + + /* Validate options size calculation. */ + if( pucLast > ( pxNetworkBuffer->pucEthernetBuffer + pxNetworkBuffer->xDataLength ) ) + { + return; + } + + /* The comparison with pucLast is only necessary in case the option data are + corrupted, we don't like to run into invalid memory and crash. */ + while( pucPtr < pucLast ) + { + UBaseType_t xRemainingOptionsBytes = pucLast - pucPtr; + + if( pucPtr[ 0 ] == TCP_OPT_END ) + { + /* End of options. */ + break; + } + if( pucPtr[ 0 ] == TCP_OPT_NOOP) + { + /* NOP option, inserted to make the length a multiple of 4. */ + pucPtr++; + continue; + } + + /* Any other well-formed option must be at least two bytes: the option + type byte followed by a length byte. */ + if( xRemainingOptionsBytes < 2 ) + { + break; + } +#if( ipconfigUSE_TCP_WIN != 0 ) + else if( pucPtr[ 0 ] == TCP_OPT_WSOPT ) + { + /* Confirm that the option fits in the remaining buffer space. */ + if( ( xRemainingOptionsBytes < TCP_OPT_WSOPT_LEN ) || ( pucPtr[ 1 ] != TCP_OPT_WSOPT_LEN ) ) + { + break; + } + + pxSocket->u.xTCP.ucPeerWinScaleFactor = pucPtr[ 2 ]; + pxSocket->u.xTCP.bits.bWinScaling = pdTRUE_UNSIGNED; + pucPtr += TCP_OPT_WSOPT_LEN; + } +#endif /* ipconfigUSE_TCP_WIN */ + else if( pucPtr[ 0 ] == TCP_OPT_MSS ) + { + /* Confirm that the option fits in the remaining buffer space. */ + if( ( xRemainingOptionsBytes < TCP_OPT_MSS_LEN )|| ( pucPtr[ 1 ] != TCP_OPT_MSS_LEN ) ) + { + break; + } + + /* An MSS option with the correct option length. FreeRTOS_htons() + is not needed here because usChar2u16() already returns a host + endian number. */ + uxNewMSS = usChar2u16( pucPtr + 2 ); + + if( pxSocket->u.xTCP.usInitMSS != uxNewMSS ) + { + /* Perform a basic check on the the new MSS. */ + if( uxNewMSS == 0 ) + { + break; + } + + FreeRTOS_debug_printf( ( "MSS change %u -> %lu\n", pxSocket->u.xTCP.usInitMSS, uxNewMSS ) ); + } + + if( pxSocket->u.xTCP.usInitMSS > uxNewMSS ) + { + /* our MSS was bigger than the MSS of the other party: adapt it. */ + pxSocket->u.xTCP.bits.bMssChange = pdTRUE_UNSIGNED; + if( ( pxTCPWindow != NULL ) && ( pxSocket->u.xTCP.usCurMSS > uxNewMSS ) ) + { + /* The peer advertises a smaller MSS than this socket was + using. Use that as well. */ + FreeRTOS_debug_printf( ( "Change mss %d => %lu\n", pxSocket->u.xTCP.usCurMSS, uxNewMSS ) ); + pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS; + } + pxTCPWindow->xSize.ulRxWindowLength = ( ( uint32_t ) uxNewMSS ) * ( pxTCPWindow->xSize.ulRxWindowLength / ( ( uint32_t ) uxNewMSS ) ); + pxTCPWindow->usMSSInit = ( uint16_t ) uxNewMSS; + pxTCPWindow->usMSS = ( uint16_t ) uxNewMSS; + pxSocket->u.xTCP.usInitMSS = ( uint16_t ) uxNewMSS; + pxSocket->u.xTCP.usCurMSS = ( uint16_t ) uxNewMSS; + } + + #if( ipconfigUSE_TCP_WIN != 1 ) + /* Without scaled windows, MSS is the only interesting option. */ + break; + #else + /* Or else we continue to check another option: selective ACK. */ + pucPtr += TCP_OPT_MSS_LEN; + #endif /* ipconfigUSE_TCP_WIN != 1 */ + } + else + { + /* All other options have a length field, so that we easily + can skip past them. */ + unsigned char len = pucPtr[ 1 ]; + if( ( len < 2 ) || ( len > xRemainingOptionsBytes ) ) + { + /* If the length field is too small or too big, the options are malformed. + Don't process them further. */ + break; + } + + #if( ipconfigUSE_TCP_WIN == 1 ) + { + /* Selective ACK: the peer has received a packet but it is missing earlier + packets. At least this packet does not need retransmission anymore + ulTCPWindowTxSack( ) takes care of this administration. */ + if( pucPtr[0] == TCP_OPT_SACK_A ) + { + len -= 2; + pucPtr += 2; + + while( len >= 8 ) + { + uint32_t ulFirst = ulChar2u32( pucPtr ); + uint32_t ulLast = ulChar2u32( pucPtr + 4 ); + uint32_t ulCount = ulTCPWindowTxSack( &pxSocket->u.xTCP.xTCPWindow, ulFirst, ulLast ); + /* ulTCPWindowTxSack( ) returns the number of bytes which have been acked + starting from the head position. + Advance the tail pointer in txStream. */ + if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0 ) ) + { + /* Just advancing the tail index, 'ulCount' bytes have been confirmed. */ + uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0, NULL, ( size_t ) ulCount, pdFALSE ); + pxSocket->xEventBits |= eSOCKET_SEND; + + #if ipconfigSUPPORT_SELECT_FUNCTION == 1 + { + if( pxSocket->xSelectBits & eSELECT_WRITE ) + { + /* The field 'xEventBits' is used to store regular socket events (at most 8), + as well as 'select events', which will be left-shifted */ + pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT ); + } + } + #endif + + /* In case the socket owner has installed an OnSent handler, + call it now. */ + #if( ipconfigUSE_CALLBACKS == 1 ) + { + if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) ) + { + pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount ); + } + } + #endif /* ipconfigUSE_CALLBACKS == 1 */ + } + pucPtr += 8; + len -= 8; + } + /* len should be 0 by now. */ + } + } + #endif /* ipconfigUSE_TCP_WIN == 1 */ + + pucPtr += len; + } + } +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN != 0 ) + + static uint8_t prvWinScaleFactor( FreeRTOS_Socket_t *pxSocket ) + { + size_t uxWinSize; + uint8_t ucFactor; + + /* 'xTCP.uxRxWinSize' is the size of the reception window in units of MSS. */ + uxWinSize = pxSocket->u.xTCP.uxRxWinSize * ( size_t ) pxSocket->u.xTCP.usInitMSS; + ucFactor = 0u; + while( uxWinSize > 0xfffful ) + { + /* Divide by two and increase the binary factor by 1. */ + uxWinSize >>= 1; + ucFactor++; + } + + FreeRTOS_debug_printf( ( "prvWinScaleFactor: uxRxWinSize %lu MSS %lu Factor %u\n", + pxSocket->u.xTCP.uxRxWinSize, + pxSocket->u.xTCP.usInitMSS, + ucFactor ) ); + + return ucFactor; + } + +#endif +/*-----------------------------------------------------------*/ + +/* + * When opening a TCP connection, while SYN's are being sent, the parties may + * communicate what MSS (Maximum Segment Size) they intend to use. MSS is the + * nett size of the payload, always smaller than MTU. +*/ +static UBaseType_t prvSetSynAckOptions( FreeRTOS_Socket_t *pxSocket, TCPPacket_t * pxTCPPacket ) +{ +TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader; +uint16_t usMSS = pxSocket->u.xTCP.usInitMSS; +UBaseType_t uxOptionsLength; + + /* We send out the TCP Maximum Segment Size option with our SYN[+ACK]. */ + + pxTCPHeader->ucOptdata[ 0 ] = ( uint8_t ) TCP_OPT_MSS; + pxTCPHeader->ucOptdata[ 1 ] = ( uint8_t ) TCP_OPT_MSS_LEN; + pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( usMSS >> 8 ); + pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( usMSS & 0xffu ); + + #if( ipconfigUSE_TCP_WIN != 0 ) + { + pxSocket->u.xTCP.ucMyWinScaleFactor = prvWinScaleFactor( pxSocket ); + + pxTCPHeader->ucOptdata[ 4 ] = TCP_OPT_NOOP; + pxTCPHeader->ucOptdata[ 5 ] = ( uint8_t ) ( TCP_OPT_WSOPT ); + pxTCPHeader->ucOptdata[ 6 ] = ( uint8_t ) ( TCP_OPT_WSOPT_LEN ); + pxTCPHeader->ucOptdata[ 7 ] = ( uint8_t ) pxSocket->u.xTCP.ucMyWinScaleFactor; + uxOptionsLength = 8u; + } + #else + { + uxOptionsLength = 4u; + } + #endif + + #if( ipconfigUSE_TCP_WIN == 0 ) + { + return uxOptionsLength; + } + #else + { + pxTCPHeader->ucOptdata[ uxOptionsLength + 0 ] = TCP_OPT_NOOP; + pxTCPHeader->ucOptdata[ uxOptionsLength + 1 ] = TCP_OPT_NOOP; + pxTCPHeader->ucOptdata[ uxOptionsLength + 2 ] = TCP_OPT_SACK_P; /* 4: Sack-Permitted Option. */ + pxTCPHeader->ucOptdata[ uxOptionsLength + 3 ] = 2; /* 2: length of this option. */ + uxOptionsLength += 4u; + + return uxOptionsLength; /* bytes, not words. */ + } + #endif /* ipconfigUSE_TCP_WIN == 0 */ +} + +/* + * For anti-hanging protection and TCP keep-alive messages. Called in two + * places: after receiving a packet and after a state change. The socket's + * alive timer may be reset. + */ +static void prvTCPTouchSocket( FreeRTOS_Socket_t *pxSocket ) +{ + #if( ipconfigTCP_HANG_PROTECTION == 1 ) + { + pxSocket->u.xTCP.xLastActTime = xTaskGetTickCount( ); + } + #endif + + #if( ipconfigTCP_KEEP_ALIVE == 1 ) + { + pxSocket->u.xTCP.bits.bWaitKeepAlive = pdFALSE_UNSIGNED; + pxSocket->u.xTCP.bits.bSendKeepAlive = pdFALSE_UNSIGNED; + pxSocket->u.xTCP.ucKeepRepCount = 0u; + pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount(); + } + #endif + + ( void ) pxSocket; +} +/*-----------------------------------------------------------*/ + +/* + * Changing to a new state. Centralised here to do specific actions such as + * resetting the alive timer, calling the user's OnConnect handler to notify + * that a socket has got (dis)connected, and setting bit to unblock a call to + * FreeRTOS_select() + */ +void vTCPStateChange( FreeRTOS_Socket_t *pxSocket, enum eTCP_STATE eTCPState ) +{ +FreeRTOS_Socket_t *xParent = NULL; +BaseType_t bBefore = ( BaseType_t ) NOW_CONNECTED( pxSocket->u.xTCP.ucTCPState ); /* Was it connected ? */ +BaseType_t bAfter = ( BaseType_t ) NOW_CONNECTED( eTCPState ); /* Is it connected now ? */ +#if( ipconfigHAS_DEBUG_PRINTF != 0 ) + BaseType_t xPreviousState = ( BaseType_t ) pxSocket->u.xTCP.ucTCPState; +#endif +#if( ipconfigUSE_CALLBACKS == 1 ) + FreeRTOS_Socket_t *xConnected = NULL; +#endif + + /* Has the connected status changed? */ + if( bBefore != bAfter ) + { + /* Is the socket connected now ? */ + if( bAfter != pdFALSE ) + { + /* if bPassQueued is true, this socket is an orphan until it gets connected. */ + if( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) + { + /* Now that it is connected, find it's parent. */ + if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED ) + { + xParent = pxSocket; + } + else + { + xParent = pxSocket->u.xTCP.pxPeerSocket; + configASSERT( xParent != NULL ); + } + if( xParent != NULL ) + { + if( xParent->u.xTCP.pxPeerSocket == NULL ) + { + xParent->u.xTCP.pxPeerSocket = pxSocket; + } + + xParent->xEventBits |= eSOCKET_ACCEPT; + + #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + { + /* Library support FreeRTOS_select(). Receiving a new + connection is being translated as a READ event. */ + if( ( xParent->xSelectBits & eSELECT_READ ) != 0 ) + { + xParent->xEventBits |= ( eSELECT_READ << SOCKET_EVENT_BIT_COUNT ); + } + } + #endif + + #if( ipconfigUSE_CALLBACKS == 1 ) + { + if( ( ipconfigIS_VALID_PROG_ADDRESS( xParent->u.xTCP.pxHandleConnected ) != pdFALSE ) && + ( xParent->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) ) + { + /* The listening socket does not become connected itself, in stead + a child socket is created. + Postpone a call the OnConnect event until the end of this function. */ + xConnected = xParent; + } + } + #endif + } + + /* Don't need to access the parent socket anymore, so the + reference 'pxPeerSocket' may be cleared. */ + pxSocket->u.xTCP.pxPeerSocket = NULL; + pxSocket->u.xTCP.bits.bPassQueued = pdFALSE_UNSIGNED; + + /* When true, this socket may be returned in a call to accept(). */ + pxSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED; + } + else + { + pxSocket->xEventBits |= eSOCKET_CONNECT; + + #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + { + if( pxSocket->xSelectBits & eSELECT_WRITE ) + { + pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT ); + } + } + #endif + } + } + else /* bAfter == pdFALSE, connection is closed. */ + { + /* Notify/wake-up the socket-owner by setting a semaphore. */ + pxSocket->xEventBits |= eSOCKET_CLOSED; + + #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + { + if( ( pxSocket->xSelectBits & eSELECT_EXCEPT ) != 0 ) + { + pxSocket->xEventBits |= ( eSELECT_EXCEPT << SOCKET_EVENT_BIT_COUNT ); + } + } + #endif + } + #if( ipconfigUSE_CALLBACKS == 1 ) + { + if( ( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleConnected ) != pdFALSE ) && ( xConnected == NULL ) ) + { + /* The 'connected' state has changed, call the user handler. */ + xConnected = pxSocket; + } + } + #endif /* ipconfigUSE_CALLBACKS */ + + if( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE ) + { + /* Now the socket isn't in an active state anymore so it + won't need further attention of the IP-task. + Setting time-out to zero means that the socket won't get checked during + timer events. */ + pxSocket->u.xTCP.usTimeout = 0u; + } + } + else + { + if( eTCPState == eCLOSED ) + { + /* Socket goes to status eCLOSED because of a RST. + When nobody owns the socket yet, delete it. */ + if( ( pxSocket->u.xTCP.bits.bPassQueued != pdFALSE_UNSIGNED ) || + ( pxSocket->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) ) + { + FreeRTOS_debug_printf( ( "vTCPStateChange: Closing socket\n" ) ); + if( pxSocket->u.xTCP.bits.bReuseSocket == pdFALSE_UNSIGNED ) + { + FreeRTOS_closesocket( pxSocket ); + } + } + } + } + + /* Fill in the new state. */ + pxSocket->u.xTCP.ucTCPState = ( uint8_t ) eTCPState; + + /* touch the alive timers because moving to another state. */ + prvTCPTouchSocket( pxSocket ); + + #if( ipconfigHAS_DEBUG_PRINTF == 1 ) + { + if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) ) + FreeRTOS_debug_printf( ( "Socket %d -> %lxip:%u State %s->%s\n", + pxSocket->usLocalPort, + pxSocket->u.xTCP.ulRemoteIP, + pxSocket->u.xTCP.usRemotePort, + FreeRTOS_GetTCPStateName( ( UBaseType_t ) xPreviousState ), + FreeRTOS_GetTCPStateName( ( UBaseType_t ) eTCPState ) ) ); + } + #endif /* ipconfigHAS_DEBUG_PRINTF */ + + #if( ipconfigUSE_CALLBACKS == 1 ) + { + if( xConnected != NULL ) + { + /* The 'connected' state has changed, call the OnConnect handler of the parent. */ + xConnected->u.xTCP.pxHandleConnected( ( Socket_t * ) xConnected, bAfter ); + } + } + #endif + if( xParent != NULL ) + { + vSocketWakeUpUser( xParent ); + } +} +/*-----------------------------------------------------------*/ + +static NetworkBufferDescriptor_t *prvTCPBufferResize( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, + int32_t lDataLen, UBaseType_t uxOptionsLength ) +{ +NetworkBufferDescriptor_t *pxReturn; +int32_t lNeeded; +BaseType_t xResize; + + if( xBufferAllocFixedSize != pdFALSE ) + { + /* Network buffers are created with a fixed size and can hold the largest + MTU. */ + lNeeded = ( int32_t ) ipTOTAL_ETHERNET_FRAME_SIZE; + /* and therefore, the buffer won't be too small. + Only ask for a new network buffer in case none was supplied. */ + xResize = ( pxNetworkBuffer == NULL ); + } + else + { + /* Network buffers are created with a variable size. See if it must + grow. */ + lNeeded = FreeRTOS_max_int32( ( int32_t ) sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ), + ( int32_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + lDataLen ); + /* In case we were called from a TCP timer event, a buffer must be + created. Otherwise, test 'xDataLength' of the provided buffer. */ + xResize = ( pxNetworkBuffer == NULL ) || ( pxNetworkBuffer->xDataLength < (size_t)lNeeded ); + } + + if( xResize != pdFALSE ) + { + /* The caller didn't provide a network buffer or the provided buffer is + too small. As we must send-out a data packet, a buffer will be created + here. */ + pxReturn = pxGetNetworkBufferWithDescriptor( ( uint32_t ) lNeeded, 0u ); + + if( pxReturn != NULL ) + { + /* Set the actual packet size, in case the returned buffer is larger. */ + pxReturn->xDataLength = lNeeded; + + /* Copy the existing data to the new created buffer. */ + if( pxNetworkBuffer ) + { + /* Either from the previous buffer... */ + memcpy( pxReturn->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength ); + + /* ...and release it. */ + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + else + { + /* Or from the socket field 'xTCP.xPacket'. */ + memcpy( pxReturn->pucEthernetBuffer, pxSocket->u.xTCP.xPacket.u.ucLastPacket, sizeof( pxSocket->u.xTCP.xPacket.u.ucLastPacket ) ); + } + } + } + else + { + /* xResize is false, the network buffer provided was big enough. */ + pxReturn = pxNetworkBuffer; + + /* Thanks to Andrey Ivanov from swissEmbedded for reporting that the + xDataLength member must get the correct length too! */ + pxNetworkBuffer->xDataLength = ( size_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ) + ( size_t ) lDataLen; + } + + return pxReturn; +} +/*-----------------------------------------------------------*/ + +/* + * Prepare an outgoing message, in case anything has to be sent. + */ +static int32_t prvTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength ) +{ +int32_t lDataLen; +uint8_t *pucEthernetBuffer, *pucSendData; +TCPPacket_t *pxTCPPacket; +size_t uxOffset; +uint32_t ulDataGot, ulDistance; +TCPWindow_t *pxTCPWindow; +NetworkBufferDescriptor_t *pxNewBuffer; +int32_t lStreamPos; + + if( ( *ppxNetworkBuffer ) != NULL ) + { + /* A network buffer descriptor was already supplied */ + pucEthernetBuffer = ( *ppxNetworkBuffer )->pucEthernetBuffer; + } + else + { + /* For now let it point to the last packet header */ + pucEthernetBuffer = pxSocket->u.xTCP.xPacket.u.ucLastPacket; + } + + pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer ); + pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow; + lDataLen = 0; + lStreamPos = 0; + pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_ACK; + + if( pxSocket->u.xTCP.txStream != NULL ) + { + /* ulTCPWindowTxGet will return the amount of data which may be sent + along with the position in the txStream. + Why check for MSS > 1 ? + Because some TCP-stacks (like uIP) use it for flow-control. */ + if( pxSocket->u.xTCP.usCurMSS > 1u ) + { + lDataLen = ( int32_t ) ulTCPWindowTxGet( pxTCPWindow, pxSocket->u.xTCP.ulWindowSize, &lStreamPos ); + } + + if( lDataLen > 0 ) + { + /* Check if the current network buffer is big enough, if not, + resize it. */ + pxNewBuffer = prvTCPBufferResize( pxSocket, *ppxNetworkBuffer, lDataLen, uxOptionsLength ); + + if( pxNewBuffer != NULL ) + { + *ppxNetworkBuffer = pxNewBuffer; + pucEthernetBuffer = pxNewBuffer->pucEthernetBuffer; + pxTCPPacket = ( TCPPacket_t * ) ( pucEthernetBuffer ); + + pucSendData = pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength; + + /* Translate the position in txStream to an offset from the tail + marker. */ + uxOffset = uxStreamBufferDistance( pxSocket->u.xTCP.txStream, pxSocket->u.xTCP.txStream->uxTail, ( size_t ) lStreamPos ); + + /* Here data is copied from the txStream in 'peek' mode. Only + when the packets are acked, the tail marker will be updated. */ + ulDataGot = ( uint32_t ) uxStreamBufferGet( pxSocket->u.xTCP.txStream, uxOffset, pucSendData, ( size_t ) lDataLen, pdTRUE ); + + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + if( ulDataGot != ( uint32_t ) lDataLen ) + { + FreeRTOS_debug_printf( ( "uxStreamBufferGet: pos %lu offs %lu only %lu != %lu\n", + lStreamPos, uxOffset, ulDataGot, lDataLen ) ); + } + } + #endif + + /* If the owner of the socket requests a closure, add the FIN + flag to the last packet. */ + if( ( pxSocket->u.xTCP.bits.bCloseRequested != pdFALSE_UNSIGNED ) && ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) ) + { + ulDistance = ( uint32_t ) uxStreamBufferDistance( pxSocket->u.xTCP.txStream, ( size_t ) lStreamPos, pxSocket->u.xTCP.txStream->uxHead ); + + if( ulDistance == ulDataGot ) + { + #if (ipconfigHAS_DEBUG_PRINTF == 1) + { + /* the order of volatile accesses is undefined + so such workaround */ + size_t uxHead = pxSocket->u.xTCP.txStream->uxHead; + size_t uxMid = pxSocket->u.xTCP.txStream->uxMid; + size_t uxTail = pxSocket->u.xTCP.txStream->uxTail; + + FreeRTOS_debug_printf( ( "CheckClose %lu <= %lu (%lu <= %lu <= %lu)\n", ulDataGot, ulDistance, + uxTail, uxMid, uxHead ) ); + } + #endif + /* Although the socket sends a FIN, it will stay in + ESTABLISHED until all current data has been received or + delivered. */ + pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN; + pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->ulOurSequenceNumber + ( uint32_t ) lDataLen; + pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED; + } + } + } + else + { + lDataLen = -1; + } + } + } + + if( ( lDataLen >= 0 ) && ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) ) + { + /* See if the socket owner wants to shutdown this connection. */ + if( ( pxSocket->u.xTCP.bits.bUserShutdown != pdFALSE_UNSIGNED ) && + ( xTCPWindowTxDone( pxTCPWindow ) != pdFALSE ) ) + { + pxSocket->u.xTCP.bits.bUserShutdown = pdFALSE_UNSIGNED; + pxTCPPacket->xTCPHeader.ucTCPFlags |= ipTCP_FLAG_FIN; + pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED; + pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED; + pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber; + vTCPStateChange( pxSocket, eFIN_WAIT_1 ); + } + + #if( ipconfigTCP_KEEP_ALIVE != 0 ) + { + if( pxSocket->u.xTCP.ucKeepRepCount > 3u ) + { + FreeRTOS_debug_printf( ( "keep-alive: giving up %lxip:%u\n", + pxSocket->u.xTCP.ulRemoteIP, /* IP address of remote machine. */ + pxSocket->u.xTCP.usRemotePort ) ); /* Port on remote machine. */ + vTCPStateChange( pxSocket, eCLOSE_WAIT ); + lDataLen = -1; + } + if( ( lDataLen == 0 ) && ( pxSocket->u.xTCP.bits.bWinChange == pdFALSE_UNSIGNED ) ) + { + /* If there is no data to be sent, and no window-update message, + we might want to send a keep-alive message. */ + TickType_t xAge = xTaskGetTickCount( ) - pxSocket->u.xTCP.xLastAliveTime; + TickType_t xMax; + xMax = ( ( TickType_t ) ipconfigTCP_KEEP_ALIVE_INTERVAL * configTICK_RATE_HZ ); + if( pxSocket->u.xTCP.ucKeepRepCount ) + { + xMax = ( 3u * configTICK_RATE_HZ ); + } + if( xAge > xMax ) + { + pxSocket->u.xTCP.xLastAliveTime = xTaskGetTickCount( ); + if( xTCPWindowLoggingLevel ) + FreeRTOS_debug_printf( ( "keep-alive: %lxip:%u count %u\n", + pxSocket->u.xTCP.ulRemoteIP, + pxSocket->u.xTCP.usRemotePort, + pxSocket->u.xTCP.ucKeepRepCount ) ); + pxSocket->u.xTCP.bits.bSendKeepAlive = pdTRUE_UNSIGNED; + pxSocket->u.xTCP.usTimeout = ( ( uint16_t ) pdMS_TO_TICKS( 2500 ) ); + pxSocket->u.xTCP.ucKeepRepCount++; + } + } + } + #endif /* ipconfigTCP_KEEP_ALIVE */ + } + + /* Anything to send, a change of the advertised window size, or maybe send a + keep-alive message? */ + if( ( lDataLen > 0 ) || + ( pxSocket->u.xTCP.bits.bWinChange != pdFALSE_UNSIGNED ) || + ( pxSocket->u.xTCP.bits.bSendKeepAlive != pdFALSE_UNSIGNED ) ) + { + pxTCPPacket->xTCPHeader.ucTCPFlags &= ( ( uint8_t ) ~ipTCP_FLAG_PSH ); + pxTCPPacket->xTCPHeader.ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); + + pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_ACK; + + if( lDataLen != 0l ) + { + pxTCPPacket->xTCPHeader.ucTCPFlags |= ( uint8_t ) ipTCP_FLAG_PSH; + } + + lDataLen += ( int32_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ); + } + + return lDataLen; +} +/*-----------------------------------------------------------*/ + +/* + * Calculate after how much time this socket needs to be checked again. + */ +static TickType_t prvTCPNextTimeout ( FreeRTOS_Socket_t *pxSocket ) +{ +TickType_t ulDelayMs = ( TickType_t ) tcpMAXIMUM_TCP_WAKEUP_TIME_MS; + + if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) + { + /* The socket is actively connecting to a peer. */ + if( pxSocket->u.xTCP.bits.bConnPrepared ) + { + /* Ethernet address has been found, use progressive timeout for + active connect(). */ + if( pxSocket->u.xTCP.ucRepCount < 3u ) + { + ulDelayMs = ( 3000UL << ( pxSocket->u.xTCP.ucRepCount - 1u ) ); + } + else + { + ulDelayMs = 11000UL; + } + } + else + { + /* Still in the ARP phase: check every half second. */ + ulDelayMs = 500UL; + } + + FreeRTOS_debug_printf( ( "Connect[%lxip:%u]: next timeout %u: %lu ms\n", + pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort, + pxSocket->u.xTCP.ucRepCount, ulDelayMs ) ); + pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs ); + } + else if( pxSocket->u.xTCP.usTimeout == 0u ) + { + /* Let the sliding window mechanism decide what time-out is appropriate. */ + BaseType_t xResult = xTCPWindowTxHasData( &pxSocket->u.xTCP.xTCPWindow, pxSocket->u.xTCP.ulWindowSize, &ulDelayMs ); + if( ulDelayMs == 0u ) + { + if( xResult != ( BaseType_t )0 ) + { + ulDelayMs = 1UL; + } + else + { + ulDelayMs = tcpMAXIMUM_TCP_WAKEUP_TIME_MS; + } + } + else + { + /* ulDelayMs contains the time to wait before a re-transmission. */ + } + pxSocket->u.xTCP.usTimeout = ( uint16_t )pdMS_TO_MIN_TICKS( ulDelayMs ); + } + else + { + /* field '.usTimeout' has already been set (by the + keep-alive/delayed-ACK mechanism). */ + } + + /* Return the number of clock ticks before the timer expires. */ + return ( TickType_t ) pxSocket->u.xTCP.usTimeout; +} +/*-----------------------------------------------------------*/ + +static void prvTCPAddTxData( FreeRTOS_Socket_t *pxSocket ) +{ +int32_t lCount, lLength; + + /* A txStream has been created already, see if the socket has new data for + the sliding window. + + uxStreamBufferMidSpace() returns the distance between rxHead and rxMid. It contains new + Tx data which has not been passed to the sliding window yet. The oldest + data not-yet-confirmed can be found at rxTail. */ + lLength = ( int32_t ) uxStreamBufferMidSpace( pxSocket->u.xTCP.txStream ); + + if( lLength > 0 ) + { + /* All data between txMid and rxHead will now be passed to the sliding + window manager, so it can start transmitting them. + + Hand over the new data to the sliding window handler. It will be + split-up in chunks of 1460 bytes each (or less, depending on + ipconfigTCP_MSS). */ + lCount = lTCPWindowTxAdd( &pxSocket->u.xTCP.xTCPWindow, + ( uint32_t ) lLength, + ( int32_t ) pxSocket->u.xTCP.txStream->uxMid, + ( int32_t ) pxSocket->u.xTCP.txStream->LENGTH ); + + /* Move the rxMid pointer forward up to rxHead. */ + if( lCount > 0 ) + { + vStreamBufferMoveMid( pxSocket->u.xTCP.txStream, ( size_t ) lCount ); + } + } +} +/*-----------------------------------------------------------*/ + +/* + * prvTCPHandleFin() will be called to handle socket closure + * The Closure starts when either a FIN has been received and accepted, + * Or when the socket has sent a FIN flag to the peer + * Before being called, it has been checked that both reception and transmission + * are complete. + */ +static BaseType_t prvTCPHandleFin( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer ) +{ +TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); +TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader; +uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags; +TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow; +BaseType_t xSendLength = 0; +uint32_t ulAckNr = FreeRTOS_ntohl( pxTCPHeader->ulAckNr ); + + if( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u ) + { + pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulFINSequenceNumber + 1u; + } + if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) + { + /* We haven't yet replied with a FIN, do so now. */ + pxTCPWindow->tx.ulFINSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber; + pxSocket->u.xTCP.bits.bFinSent = pdTRUE_UNSIGNED; + } + else + { + /* We did send a FIN already, see if it's ACK'd. */ + if( ulAckNr == pxTCPWindow->tx.ulFINSequenceNumber + 1u ) + { + pxSocket->u.xTCP.bits.bFinAcked = pdTRUE_UNSIGNED; + } + } + + if( pxSocket->u.xTCP.bits.bFinAcked == pdFALSE_UNSIGNED ) + { + pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber; + pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK | ipTCP_FLAG_FIN; + + /* And wait for the final ACK. */ + vTCPStateChange( pxSocket, eLAST_ACK ); + } + else + { + /* Our FIN has been ACK'd, the outgoing sequence number is now fixed. */ + pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber + 1u; + if( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) + { + /* We have sent out a FIN but the peer hasn't replied with a FIN + yet. Do nothing for the moment. */ + pxTCPHeader->ucTCPFlags = 0u; + } + else + { + if( pxSocket->u.xTCP.bits.bFinLast == pdFALSE_UNSIGNED ) + { + /* This is the third of the three-way hand shake: the last + ACK. */ + pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK; + } + else + { + /* The other party started the closure, so we just wait for the + last ACK. */ + pxTCPHeader->ucTCPFlags = 0u; + } + + /* And wait for the user to close this socket. */ + vTCPStateChange( pxSocket, eCLOSE_WAIT ); + } + } + + pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber; + + if( pxTCPHeader->ucTCPFlags != 0u ) + { + xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength ); + } + + pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + pxTCPWindow->ucOptionLength ) << 2 ); + + if( xTCPWindowLoggingLevel != 0 ) + { + FreeRTOS_debug_printf( ( "TCP: send FIN+ACK (ack %lu, cur/nxt %lu/%lu) ourSeqNr %lu | Rx %lu\n", + ulAckNr - pxTCPWindow->tx.ulFirstSequenceNumber, + pxTCPWindow->tx.ulCurrentSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber, + pxTCPWindow->ulNextTxSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber, + pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber, + pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) ); + } + + return xSendLength; +} +/*-----------------------------------------------------------*/ + +/* + * prvCheckRxData(): called from prvTCPHandleState() + * + * The first thing that will be done is find the TCP payload data + * and check the length of this data. + */ +static BaseType_t prvCheckRxData( NetworkBufferDescriptor_t *pxNetworkBuffer, uint8_t **ppucRecvData ) +{ +TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); +TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader ); +int32_t lLength, lTCPHeaderLength, lReceiveLength, lUrgentLength; + + /* Determine the length and the offset of the user-data sent to this + node. + + The size of the TCP header is given in a multiple of 4-byte words (single + byte, needs no ntoh() translation). A shift-right 2: is the same as + (offset >> 4) * 4. */ + lTCPHeaderLength = ( BaseType_t ) ( ( pxTCPHeader->ucTCPOffset & VALID_BITS_IN_TCP_OFFSET_BYTE ) >> 2 ); + + /* Let pucRecvData point to the first byte received. */ + *ppucRecvData = pxNetworkBuffer->pucEthernetBuffer + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + lTCPHeaderLength; + + /* Calculate lReceiveLength - the length of the TCP data received. This is + equal to the total packet length minus: + ( LinkLayer length (14) + IP header length (20) + size of TCP header(20 +) ).*/ + lReceiveLength = ( ( int32_t ) pxNetworkBuffer->xDataLength ) - ( int32_t ) ipSIZE_OF_ETH_HEADER; + lLength = ( int32_t )FreeRTOS_htons( pxTCPPacket->xIPHeader.usLength ); + + if( lReceiveLength > lLength ) + { + /* More bytes were received than the reported length, often because of + padding bytes at the end. */ + lReceiveLength = lLength; + } + + /* Subtract the size of the TCP and IP headers and the actual data size is + known. */ + if( lReceiveLength > ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER ) ) + { + lReceiveLength -= ( lTCPHeaderLength + ( int32_t ) ipSIZE_OF_IPv4_HEADER ); + } + else + { + lReceiveLength = 0; + } + + /* Urgent Pointer: + This field communicates the current value of the urgent pointer as a + positive offset from the sequence number in this segment. The urgent + pointer points to the sequence number of the octet following the urgent + data. This field is only be interpreted in segments with the URG control + bit set. */ + if( ( pxTCPHeader->ucTCPFlags & ipTCP_FLAG_URG ) != 0u ) + { + /* Although we ignore the urgent data, we have to skip it. */ + lUrgentLength = ( int32_t ) FreeRTOS_htons( pxTCPHeader->usUrgent ); + *ppucRecvData += lUrgentLength; + lReceiveLength -= FreeRTOS_min_int32( lReceiveLength, lUrgentLength ); + } + + return ( BaseType_t ) lReceiveLength; +} +/*-----------------------------------------------------------*/ + +/* + * prvStoreRxData(): called from prvTCPHandleState() + * + * The second thing is to do is check if the payload data may be accepted + * If so, they will be added to the reception queue. + */ +static BaseType_t prvStoreRxData( FreeRTOS_Socket_t *pxSocket, uint8_t *pucRecvData, + NetworkBufferDescriptor_t *pxNetworkBuffer, uint32_t ulReceiveLength ) +{ +TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); +TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader; +TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow; +uint32_t ulSequenceNumber, ulSpace; +int32_t lOffset, lStored; +BaseType_t xResult = 0; + + ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ); + + if( ( ulReceiveLength > 0u ) && ( pxSocket->u.xTCP.ucTCPState >= eSYN_RECEIVED ) ) + { + /* See if way may accept the data contents and forward it to the socket + owner. + + If it can't be "accept"ed it may have to be stored and send a selective + ack (SACK) option to confirm it. In that case, xTCPWindowRxStore() will be + called later to store an out-of-order packet (in case lOffset is + negative). */ + if ( pxSocket->u.xTCP.rxStream ) + { + ulSpace = ( uint32_t )uxStreamBufferGetSpace ( pxSocket->u.xTCP.rxStream ); + } + else + { + ulSpace = ( uint32_t )pxSocket->u.xTCP.uxRxStreamSize; + } + + lOffset = lTCPWindowRxCheck( pxTCPWindow, ulSequenceNumber, ulReceiveLength, ulSpace ); + + if( lOffset >= 0 ) + { + /* New data has arrived and may be made available to the user. See + if the head marker in rxStream may be advanced, only if lOffset == 0. + In case the low-water mark is reached, bLowWater will be set + "low-water" here stands for "little space". */ + lStored = lTCPAddRxdata( pxSocket, ( uint32_t ) lOffset, pucRecvData, ulReceiveLength ); + + if( lStored != ( int32_t ) ulReceiveLength ) + { + FreeRTOS_debug_printf( ( "lTCPAddRxdata: stored %ld / %lu bytes??\n", lStored, ulReceiveLength ) ); + + /* Received data could not be stored. The socket's flag + bMallocError has been set. The socket now has the status + eCLOSE_WAIT and a RST packet will be sent back. */ + prvTCPSendReset( pxNetworkBuffer ); + xResult = -1; + } + } + + /* After a missing packet has come in, higher packets may be passed to + the user. */ + #if( ipconfigUSE_TCP_WIN == 1 ) + { + /* Now lTCPAddRxdata() will move the rxHead pointer forward + so data becomes available to the user immediately + In case the low-water mark is reached, bLowWater will be set. */ + if( ( xResult == 0 ) && ( pxTCPWindow->ulUserDataLength > 0 ) ) + { + lTCPAddRxdata( pxSocket, 0ul, NULL, pxTCPWindow->ulUserDataLength ); + pxTCPWindow->ulUserDataLength = 0; + } + } + #endif /* ipconfigUSE_TCP_WIN */ + } + else + { + pxTCPWindow->ucOptionLength = 0u; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +/* Set the TCP options (if any) for the outgoing packet. */ +static UBaseType_t prvSetOptions( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer ) +{ +TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); +TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader; +TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow; +UBaseType_t uxOptionsLength = pxTCPWindow->ucOptionLength; + + #if( ipconfigUSE_TCP_WIN == 1 ) + if( uxOptionsLength != 0u ) + { + /* TCP options must be sent because a packet which is out-of-order + was received. */ + if( xTCPWindowLoggingLevel >= 0 ) + FreeRTOS_debug_printf( ( "SACK[%d,%d]: optlen %lu sending %lu - %lu\n", + pxSocket->usLocalPort, + pxSocket->u.xTCP.usRemotePort, + uxOptionsLength, + FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 1 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber, + FreeRTOS_ntohl( pxTCPWindow->ulOptionsData[ 2 ] ) - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber ) ); + memcpy( pxTCPHeader->ucOptdata, pxTCPWindow->ulOptionsData, ( size_t ) uxOptionsLength ); + + /* The header length divided by 4, goes into the higher nibble, + effectively a shift-left 2. */ + pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); + } + else + #endif /* ipconfigUSE_TCP_WIN */ + if( ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) && ( pxSocket->u.xTCP.bits.bMssChange != pdFALSE_UNSIGNED ) ) + { + /* TCP options must be sent because the MSS has changed. */ + pxSocket->u.xTCP.bits.bMssChange = pdFALSE_UNSIGNED; + if( xTCPWindowLoggingLevel >= 0 ) + { + FreeRTOS_debug_printf( ( "MSS: sending %d\n", pxSocket->u.xTCP.usCurMSS ) ); + } + + pxTCPHeader->ucOptdata[ 0 ] = TCP_OPT_MSS; + pxTCPHeader->ucOptdata[ 1 ] = TCP_OPT_MSS_LEN; + pxTCPHeader->ucOptdata[ 2 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) >> 8 ); + pxTCPHeader->ucOptdata[ 3 ] = ( uint8_t ) ( ( pxSocket->u.xTCP.usCurMSS ) & 0xffu ); + uxOptionsLength = 4u; + pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); + } + + return uxOptionsLength; +} +/*-----------------------------------------------------------*/ + +/* + * prvHandleSynReceived(): called from prvTCPHandleState() + * + * Called from the states: eSYN_RECEIVED and eCONNECT_SYN + * If the flags received are correct, the socket will move to eESTABLISHED. + */ +static BaseType_t prvHandleSynReceived( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, + uint32_t ulReceiveLength, UBaseType_t uxOptionsLength ) +{ +TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer ); +TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader; +TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow; +uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags; +uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ); +BaseType_t xSendLength = 0; + + /* Either expect a ACK or a SYN+ACK. */ + uint16_t usExpect = ( uint16_t ) ipTCP_FLAG_ACK; + if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) + { + usExpect |= ( uint16_t ) ipTCP_FLAG_SYN; + } + + if( ( ucTCPFlags & 0x17u ) != usExpect ) + { + /* eSYN_RECEIVED: flags 0010 expected, not 0002. */ + /* eSYN_RECEIVED: flags ACK expected, not SYN. */ + FreeRTOS_debug_printf( ( "%s: flags %04X expected, not %04X\n", + pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ? "eSYN_RECEIVED" : "eCONNECT_SYN", + usExpect, ucTCPFlags ) ); + vTCPStateChange( pxSocket, eCLOSE_WAIT ); + pxTCPHeader->ucTCPFlags |= ipTCP_FLAG_RST; + xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ); + pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); + } + else + { + pxTCPWindow->usPeerPortNumber = pxSocket->u.xTCP.usRemotePort; + pxTCPWindow->usOurPortNumber = pxSocket->usLocalPort; + + if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) + { + TCPPacket_t *pxLastTCPPacket = ( TCPPacket_t * ) ( pxSocket->u.xTCP.xPacket.u.ucLastPacket ); + + /* Clear the SYN flag in lastPacket. */ + pxLastTCPPacket->xTCPHeader.ucTCPFlags = ipTCP_FLAG_ACK; + + /* This socket was the one connecting actively so now perofmr the + synchronisation. */ + vTCPWindowInit( &pxSocket->u.xTCP.xTCPWindow, + ulSequenceNumber, pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber, ( uint32_t ) pxSocket->u.xTCP.usCurMSS ); + pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u; + pxTCPWindow->tx.ulCurrentSequenceNumber++; /* because we send a TCP_SYN [ | TCP_ACK ]; */ + pxTCPWindow->ulNextTxSequenceNumber++; + } + else if( ulReceiveLength == 0u ) + { + pxTCPWindow->rx.ulCurrentSequenceNumber = ulSequenceNumber; + } + + /* The SYN+ACK has been confirmed, increase the next sequence number by + 1. */ + pxTCPWindow->ulOurSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u; + + #if( ipconfigUSE_TCP_WIN == 1 ) + { + FreeRTOS_debug_printf( ( "TCP: %s %d => %lxip:%d set ESTAB (scaling %u)\n", + pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ? "active" : "passive", + pxSocket->usLocalPort, + pxSocket->u.xTCP.ulRemoteIP, + pxSocket->u.xTCP.usRemotePort, + ( unsigned ) pxSocket->u.xTCP.bits.bWinScaling ) ); + } + #endif /* ipconfigUSE_TCP_WIN */ + + if( ( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) || ( ulReceiveLength != 0u ) ) + { + pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK; + xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ); + pxTCPHeader->ucTCPOffset = ( uint8_t ) ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); + } + #if( ipconfigUSE_TCP_WIN != 0 ) + { + if( pxSocket->u.xTCP.bits.bWinScaling == pdFALSE_UNSIGNED ) + { + /* The other party did not send a scaling factor. + A shifting factor in this side must be canceled. */ + pxSocket->u.xTCP.ucMyWinScaleFactor = 0; + pxSocket->u.xTCP.ucPeerWinScaleFactor = 0; + } + } + #endif /* ipconfigUSE_TCP_WIN */ + /* This was the third step of connecting: SYN, SYN+ACK, ACK so now the + connection is established. */ + vTCPStateChange( pxSocket, eESTABLISHED ); + } + + return xSendLength; +} +/*-----------------------------------------------------------*/ + +/* + * prvHandleEstablished(): called from prvTCPHandleState() + * + * Called if the status is eESTABLISHED. Data reception has been handled + * earlier. Here the ACK's from peer will be checked, and if a FIN is received, + * the code will check if it may be accepted, i.e. if all expected data has been + * completely received. + */ +static BaseType_t prvHandleEstablished( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, + uint32_t ulReceiveLength, UBaseType_t uxOptionsLength ) +{ +TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer ); +TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader; +TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow; +uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags; +uint32_t ulSequenceNumber = FreeRTOS_ntohl( pxTCPHeader->ulSequenceNumber ), ulCount; +BaseType_t xSendLength = 0, xMayClose = pdFALSE, bRxComplete, bTxDone; +int32_t lDistance, lSendResult; + + /* Remember the window size the peer is advertising. */ + pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPHeader->usWindow ); + #if( ipconfigUSE_TCP_WIN != 0 ) + { + pxSocket->u.xTCP.ulWindowSize = + ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor ); + } + #endif + + if( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_ACK ) != 0u ) + { + ulCount = ulTCPWindowTxAck( pxTCPWindow, FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ) ); + + /* ulTCPWindowTxAck() returns the number of bytes which have been acked, + starting at 'tx.ulCurrentSequenceNumber'. Advance the tail pointer in + txStream. */ + if( ( pxSocket->u.xTCP.txStream != NULL ) && ( ulCount > 0u ) ) + { + /* Just advancing the tail index, 'ulCount' bytes have been + confirmed, and because there is new space in the txStream, the + user/owner should be woken up. */ + /* _HT_ : only in case the socket's waiting? */ + if( uxStreamBufferGet( pxSocket->u.xTCP.txStream, 0u, NULL, ( size_t ) ulCount, pdFALSE ) != 0u ) + { + pxSocket->xEventBits |= eSOCKET_SEND; + + #if ipconfigSUPPORT_SELECT_FUNCTION == 1 + { + if( ( pxSocket->xSelectBits & eSELECT_WRITE ) != 0 ) + { + pxSocket->xEventBits |= ( eSELECT_WRITE << SOCKET_EVENT_BIT_COUNT ); + } + } + #endif + /* In case the socket owner has installed an OnSent handler, + call it now. */ + #if( ipconfigUSE_CALLBACKS == 1 ) + { + if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xTCP.pxHandleSent ) ) + { + pxSocket->u.xTCP.pxHandleSent( (Socket_t *)pxSocket, ulCount ); + } + } + #endif /* ipconfigUSE_CALLBACKS == 1 */ + } + } + } + + /* If this socket has a stream for transmission, add the data to the + outgoing segment(s). */ + if( pxSocket->u.xTCP.txStream != NULL ) + { + prvTCPAddTxData( pxSocket ); + } + + pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber = pxTCPWindow->tx.ulCurrentSequenceNumber; + + if( ( pxSocket->u.xTCP.bits.bFinAccepted != pdFALSE_UNSIGNED ) || ( ( ucTCPFlags & ( uint8_t ) ipTCP_FLAG_FIN ) != 0u ) ) + { + /* Peer is requesting to stop, see if we're really finished. */ + xMayClose = pdTRUE; + + /* Checks are only necessary if we haven't sent a FIN yet. */ + if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) + { + /* xTCPWindowTxDone returns true when all Tx queues are empty. */ + bRxComplete = xTCPWindowRxEmpty( pxTCPWindow ); + bTxDone = xTCPWindowTxDone( pxTCPWindow ); + + if( ( bRxComplete == 0 ) || ( bTxDone == 0 ) ) + { + /* Refusing FIN: Rx incomp 1 optlen 4 tx done 1. */ + FreeRTOS_debug_printf( ( "Refusing FIN[%u,%u]: RxCompl %lu tx done %ld\n", + pxSocket->usLocalPort, + pxSocket->u.xTCP.usRemotePort, + bRxComplete, bTxDone ) ); + xMayClose = pdFALSE; + } + else + { + lDistance = ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulCurrentSequenceNumber ); + + if( lDistance > 1 ) + { + FreeRTOS_debug_printf( ( "Refusing FIN: Rx not complete %ld (cur %lu high %lu)\n", + lDistance, pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber, + pxTCPWindow->rx.ulHighestSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber ) ); + + xMayClose = pdFALSE; + } + } + } + + if( xTCPWindowLoggingLevel > 0 ) + { + FreeRTOS_debug_printf( ( "TCP: FIN received, mayClose = %ld (Rx %lu Len %ld, Tx %lu)\n", + xMayClose, ulSequenceNumber - pxSocket->u.xTCP.xTCPWindow.rx.ulFirstSequenceNumber, ulReceiveLength, + pxTCPWindow->tx.ulCurrentSequenceNumber - pxSocket->u.xTCP.xTCPWindow.tx.ulFirstSequenceNumber ) ); + } + + if( xMayClose != pdFALSE ) + { + pxSocket->u.xTCP.bits.bFinAccepted = pdTRUE_UNSIGNED; + xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer ); + } + } + + if( xMayClose == pdFALSE ) + { + pxTCPHeader->ucTCPFlags = ipTCP_FLAG_ACK; + + if( ulReceiveLength != 0u ) + { + xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ); + /* TCP-offsett equals '( ( length / 4 ) << 4 )', resulting in a shift-left 2 */ + pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); + + if( pxSocket->u.xTCP.bits.bFinSent != pdFALSE_UNSIGNED ) + { + pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->tx.ulFINSequenceNumber; + } + } + + /* Now get data to be transmitted. */ + /* _HT_ patch: since the MTU has be fixed at 1500 in stead of 1526, TCP + can not send-out both TCP options and also a full packet. Sending + options (SACK) is always more urgent than sending data, which can be + sent later. */ + if( uxOptionsLength == 0u ) + { + /* prvTCPPrepareSend might allocate a bigger network buffer, if + necessary. */ + lSendResult = prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength ); + if( lSendResult > 0 ) + { + xSendLength = ( BaseType_t ) lSendResult; + } + } + } + + return xSendLength; +} +/*-----------------------------------------------------------*/ + +/* + * Called from prvTCPHandleState(). There is data to be sent. If + * ipconfigUSE_TCP_WIN is defined, and if only an ACK must be sent, it will be + * checked if it would better be postponed for efficiency. + */ +static BaseType_t prvSendData( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, + uint32_t ulReceiveLength, BaseType_t xSendLength ) +{ +TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer ); +TCPHeader_t *pxTCPHeader = &pxTCPPacket->xTCPHeader; +TCPWindow_t *pxTCPWindow = &pxSocket->u.xTCP.xTCPWindow; +/* Find out what window size we may advertised. */ +int32_t lRxSpace; +#if( ipconfigUSE_TCP_WIN == 1 ) + #if( ipconfigTCP_ACK_EARLIER_PACKET == 0 ) + const int32_t lMinLength = 0; + #else + int32_t lMinLength; + #endif +#endif + + /* Set the time-out field, so that we'll be called by the IP-task in case no + next message will be received. */ + lRxSpace = (int32_t)( pxSocket->u.xTCP.ulHighestRxAllowed - pxTCPWindow->rx.ulCurrentSequenceNumber ); + #if ipconfigUSE_TCP_WIN == 1 + { + + #if( ipconfigTCP_ACK_EARLIER_PACKET != 0 ) + { + lMinLength = ( ( int32_t ) 2 ) * ( ( int32_t ) pxSocket->u.xTCP.usCurMSS ); + } + #endif /* ipconfigTCP_ACK_EARLIER_PACKET */ + + /* In case we're receiving data continuously, we might postpone sending + an ACK to gain performance. */ + if( ( ulReceiveLength > 0 ) && /* Data was sent to this socket. */ + ( lRxSpace >= lMinLength ) && /* There is Rx space for more data. */ + ( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) && /* Not in a closure phase. */ + ( xSendLength == ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) && /* No Tx data or options to be sent. */ + ( pxSocket->u.xTCP.ucTCPState == eESTABLISHED ) && /* Connection established. */ + ( pxTCPHeader->ucTCPFlags == ipTCP_FLAG_ACK ) ) /* There are no other flags than an ACK. */ + { + if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer ) + { + /* There was still a delayed in queue, delete it. */ + if( pxSocket->u.xTCP.pxAckMessage != 0 ) + { + vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage ); + } + + pxSocket->u.xTCP.pxAckMessage = *ppxNetworkBuffer; + } + if( ( ulReceiveLength < ( uint32_t ) pxSocket->u.xTCP.usCurMSS ) || /* Received a small message. */ + ( lRxSpace < ( int32_t ) ( 2U * pxSocket->u.xTCP.usCurMSS ) ) ) /* There are less than 2 x MSS space in the Rx buffer. */ + { + pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_SHORT_DELAY_MS ); + } + else + { + /* Normally a delayed ACK should wait 200 ms for a next incoming + packet. Only wait 20 ms here to gain performance. A slow ACK + for full-size message. */ + pxSocket->u.xTCP.usTimeout = ( uint16_t ) pdMS_TO_MIN_TICKS( DELAYED_ACK_LONGER_DELAY_MS ); + } + + if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) ) + { + FreeRTOS_debug_printf( ( "Send[%u->%u] del ACK %lu SEQ %lu (len %lu) tmout %u d %lu\n", + pxSocket->usLocalPort, + pxSocket->u.xTCP.usRemotePort, + pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber, + pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber, + xSendLength, + pxSocket->u.xTCP.usTimeout, lRxSpace ) ); + } + + *ppxNetworkBuffer = NULL; + xSendLength = 0; + } + else if( pxSocket->u.xTCP.pxAckMessage != NULL ) + { + /* As an ACK is not being delayed, remove any earlier delayed ACK + message. */ + if( pxSocket->u.xTCP.pxAckMessage != *ppxNetworkBuffer ) + { + vReleaseNetworkBufferAndDescriptor( pxSocket->u.xTCP.pxAckMessage ); + } + + pxSocket->u.xTCP.pxAckMessage = NULL; + } + } + #else + { + /* Remove compiler warnings. */ + ( void ) ulReceiveLength; + ( void ) pxTCPHeader; + ( void ) lRxSpace; + } + #endif /* ipconfigUSE_TCP_WIN */ + + if( xSendLength != 0 ) + { + if( ( xTCPWindowLoggingLevel > 1 ) && ( ipconfigTCP_MAY_LOG_PORT( pxSocket->usLocalPort ) != pdFALSE ) ) + { + FreeRTOS_debug_printf( ( "Send[%u->%u] imm ACK %lu SEQ %lu (len %lu)\n", + pxSocket->usLocalPort, + pxSocket->u.xTCP.usRemotePort, + pxTCPWindow->rx.ulCurrentSequenceNumber - pxTCPWindow->rx.ulFirstSequenceNumber, + pxTCPWindow->ulOurSequenceNumber - pxTCPWindow->tx.ulFirstSequenceNumber, + xSendLength ) ); + } + + /* Set the parameter 'xReleaseAfterSend' to the value of + ipconfigZERO_COPY_TX_DRIVER. */ + prvTCPReturnPacket( pxSocket, *ppxNetworkBuffer, ( uint32_t ) xSendLength, ipconfigZERO_COPY_TX_DRIVER ); + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + /* The driver has taken ownership of the Network Buffer. */ + *ppxNetworkBuffer = NULL; + } + #endif + } + + return xSendLength; +} +/*-----------------------------------------------------------*/ + +/* + * prvTCPHandleState() + * is the most important function of this TCP stack + * We've tried to keep it (relatively short) by putting a lot of code in + * the static functions above: + * + * prvCheckRxData() + * prvStoreRxData() + * prvSetOptions() + * prvHandleSynReceived() + * prvHandleEstablished() + * prvSendData() + * + * As these functions are declared static, and they're called from one location + * only, most compilers will inline them, thus avoiding a call and return. + */ +static BaseType_t prvTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer ) +{ +TCPPacket_t *pxTCPPacket = ( TCPPacket_t * ) ( (*ppxNetworkBuffer)->pucEthernetBuffer ); +TCPHeader_t *pxTCPHeader = &( pxTCPPacket->xTCPHeader ); +BaseType_t xSendLength = 0; +uint32_t ulReceiveLength; /* Number of bytes contained in the TCP message. */ +uint8_t *pucRecvData; +uint32_t ulSequenceNumber = FreeRTOS_ntohl (pxTCPHeader->ulSequenceNumber); + + /* uxOptionsLength: the size of the options to be sent (always a multiple of + 4 bytes) + 1. in the SYN phase, we shall communicate the MSS + 2. in case of a SACK, Selective ACK, ack a segment which comes in + out-of-order. */ +UBaseType_t uxOptionsLength = 0u; +uint8_t ucTCPFlags = pxTCPHeader->ucTCPFlags; +TCPWindow_t *pxTCPWindow = &( pxSocket->u.xTCP.xTCPWindow ); + + /* First get the length and the position of the received data, if any. + pucRecvData will point to the first byte of the TCP payload. */ + ulReceiveLength = ( uint32_t ) prvCheckRxData( *ppxNetworkBuffer, &pucRecvData ); + + if( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) + { + if ( pxTCPWindow->rx.ulCurrentSequenceNumber == ulSequenceNumber + 1u ) + { + /* This is most probably a keep-alive message from peer. Setting + 'bWinChange' doesn't cause a window-size-change, the flag is used + here to force sending an immediate ACK. */ + pxSocket->u.xTCP.bits.bWinChange = pdTRUE_UNSIGNED; + } + } + + /* Keep track of the highest sequence number that might be expected within + this connection. */ + if( ( ( int32_t ) ( ulSequenceNumber + ulReceiveLength - pxTCPWindow->rx.ulHighestSequenceNumber ) ) > 0 ) + { + pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + ulReceiveLength; + } + + /* Storing data may result in a fatal error if malloc() fails. */ + if( prvStoreRxData( pxSocket, pucRecvData, *ppxNetworkBuffer, ulReceiveLength ) < 0 ) + { + xSendLength = -1; + } + else + { + uxOptionsLength = prvSetOptions( pxSocket, *ppxNetworkBuffer ); + + if( ( pxSocket->u.xTCP.ucTCPState == eSYN_RECEIVED ) && ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) ) + { + FreeRTOS_debug_printf( ( "eSYN_RECEIVED: ACK expected, not SYN: peer missed our SYN+ACK\n" ) ); + + /* In eSYN_RECEIVED a simple ACK is expected, but apparently the + 'SYN+ACK' didn't arrive. Step back to the previous state in which + a first incoming SYN is handled. The SYN was counted already so + decrease it first. */ + vTCPStateChange( pxSocket, eSYN_FIRST ); + } + + if( ( ( ucTCPFlags & ipTCP_FLAG_FIN ) != 0u ) && ( pxSocket->u.xTCP.bits.bFinRecv == pdFALSE_UNSIGNED ) ) + { + /* It's the first time a FIN has been received, remember its + sequence number. */ + pxTCPWindow->rx.ulFINSequenceNumber = ulSequenceNumber + ulReceiveLength; + pxSocket->u.xTCP.bits.bFinRecv = pdTRUE_UNSIGNED; + + /* Was peer the first one to send a FIN? */ + if( pxSocket->u.xTCP.bits.bFinSent == pdFALSE_UNSIGNED ) + { + /* If so, don't send the-last-ACK. */ + pxSocket->u.xTCP.bits.bFinLast = pdTRUE_UNSIGNED; + } + } + + switch (pxSocket->u.xTCP.ucTCPState) + { + case eCLOSED: /* (server + client) no connection state at all. */ + /* Nothing to do for a closed socket, except waiting for the + owner. */ + break; + + case eTCP_LISTEN: /* (server) waiting for a connection request from + any remote TCP and port. */ + /* The listen state was handled in xProcessReceivedTCPPacket(). + Should not come here. */ + break; + + case eSYN_FIRST: /* (server) Just received a SYN request for a server + socket. */ + { + /* A new socket has been created, reply with a SYN+ACK. + Acknowledge with seq+1 because the SYN is seen as pseudo data + with len = 1. */ + uxOptionsLength = prvSetSynAckOptions( pxSocket, pxTCPPacket ); + pxTCPHeader->ucTCPFlags = ipTCP_FLAG_SYN | ipTCP_FLAG_ACK; + + xSendLength = ( BaseType_t ) ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + uxOptionsLength ); + + /* Set the TCP offset field: ipSIZE_OF_TCP_HEADER equals 20 and + uxOptionsLength is a multiple of 4. The complete expression is: + ucTCPOffset = ( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) / 4 ) << 4 */ + pxTCPHeader->ucTCPOffset = ( uint8_t )( ( ipSIZE_OF_TCP_HEADER + uxOptionsLength ) << 2 ); + vTCPStateChange( pxSocket, eSYN_RECEIVED ); + + pxTCPWindow->rx.ulCurrentSequenceNumber = pxTCPWindow->rx.ulHighestSequenceNumber = ulSequenceNumber + 1u; + pxTCPWindow->tx.ulCurrentSequenceNumber = pxTCPWindow->ulNextTxSequenceNumber = pxTCPWindow->tx.ulFirstSequenceNumber + 1u; /* because we send a TCP_SYN. */ + } + break; + + case eCONNECT_SYN: /* (client) also called SYN_SENT: we've just send a + SYN, expect a SYN+ACK and send a ACK now. */ + /* Fall through */ + case eSYN_RECEIVED: /* (server) we've had a SYN, replied with SYN+SCK + expect a ACK and do nothing. */ + xSendLength = prvHandleSynReceived( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength ); + break; + + case eESTABLISHED: /* (server + client) an open connection, data + received can be delivered to the user. The normal + state for the data transfer phase of the connection + The closing states are also handled here with the + use of some flags. */ + xSendLength = prvHandleEstablished( pxSocket, ppxNetworkBuffer, ulReceiveLength, uxOptionsLength ); + break; + + case eLAST_ACK: /* (server + client) waiting for an acknowledgement + of the connection termination request previously + sent to the remote TCP (which includes an + acknowledgement of its connection termination + request). */ + /* Fall through */ + case eFIN_WAIT_1: /* (server + client) waiting for a connection termination request from the remote TCP, + * or an acknowledgement of the connection termination request previously sent. */ + /* Fall through */ + case eFIN_WAIT_2: /* (server + client) waiting for a connection termination request from the remote TCP. */ + xSendLength = prvTCPHandleFin( pxSocket, *ppxNetworkBuffer ); + break; + + case eCLOSE_WAIT: /* (server + client) waiting for a connection + termination request from the local user. Nothing to + do, connection is closed, wait for owner to close + this socket. */ + break; + + case eCLOSING: /* (server + client) waiting for a connection + termination request acknowledgement from the remote + TCP. */ + break; + + case eTIME_WAIT: /* (either server or client) waiting for enough time + to pass to be sure the remote TCP received the + acknowledgement of its connection termination + request. [According to RFC 793 a connection can stay + in TIME-WAIT for a maximum of four minutes known as + a MSL (maximum segment lifetime).] These states are + implemented implicitly by settings flags like + 'bFinSent', 'bFinRecv', and 'bFinAcked'. */ + break; + default: + break; + } + } + + if( xSendLength > 0 ) + { + xSendLength = prvSendData( pxSocket, ppxNetworkBuffer, ulReceiveLength, xSendLength ); + } + + return xSendLength; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvTCPSendSpecialPacketHelper( NetworkBufferDescriptor_t *pxNetworkBuffer, + uint8_t ucTCPFlags ) +{ +#if( ipconfigIGNORE_UNKNOWN_PACKETS == 0 ) + { + TCPPacket_t *pxTCPPacket = ( TCPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer ); + const BaseType_t xSendLength = ( BaseType_t ) + ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + 0u ); /* Plus 0 options. */ + + pxTCPPacket->xTCPHeader.ucTCPFlags = ucTCPFlags; + pxTCPPacket->xTCPHeader.ucTCPOffset = ( ipSIZE_OF_TCP_HEADER + 0u ) << 2; + + prvTCPReturnPacket( NULL, pxNetworkBuffer, ( uint32_t )xSendLength, pdFALSE ); + } +#endif /* !ipconfigIGNORE_UNKNOWN_PACKETS */ + + /* Remove compiler warnings if ipconfigIGNORE_UNKNOWN_PACKETS == 1. */ + ( void )pxNetworkBuffer; + ( void )ucTCPFlags; + + /* The packet was not consumed. */ + return pdFAIL; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvTCPSendChallengeAck( NetworkBufferDescriptor_t *pxNetworkBuffer ) +{ + return prvTCPSendSpecialPacketHelper( pxNetworkBuffer, ipTCP_FLAG_ACK ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvTCPSendReset( NetworkBufferDescriptor_t *pxNetworkBuffer ) +{ + return prvTCPSendSpecialPacketHelper( pxNetworkBuffer, + ipTCP_FLAG_ACK | ipTCP_FLAG_RST ); +} +/*-----------------------------------------------------------*/ + +static void prvSocketSetMSS( FreeRTOS_Socket_t *pxSocket ) +{ +uint32_t ulMSS = ipconfigTCP_MSS; + + if( ( ( FreeRTOS_ntohl( pxSocket->u.xTCP.ulRemoteIP ) ^ *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) != 0ul ) + { + /* Data for this peer will pass through a router, and maybe through + the internet. Limit the MSS to 1400 bytes or less. */ + ulMSS = FreeRTOS_min_uint32( ( uint32_t ) REDUCED_MSS_THROUGH_INTERNET, ulMSS ); + } + + FreeRTOS_debug_printf( ( "prvSocketSetMSS: %lu bytes for %lxip:%u\n", ulMSS, pxSocket->u.xTCP.ulRemoteIP, pxSocket->u.xTCP.usRemotePort ) ); + + pxSocket->u.xTCP.usInitMSS = pxSocket->u.xTCP.usCurMSS = ( uint16_t ) ulMSS; +} +/*-----------------------------------------------------------*/ + +/* + * FreeRTOS_TCP_IP has only 2 public functions, this is the second one: + * xProcessReceivedTCPPacket() + * prvTCPHandleState() + * prvTCPPrepareSend() + * prvTCPReturnPacket() + * xNetworkInterfaceOutput() // Sends data to the NIC + * prvTCPSendRepeated() + * prvTCPReturnPacket() // Prepare for returning + * xNetworkInterfaceOutput() // Sends data to the NIC +*/ +BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer ) +{ +FreeRTOS_Socket_t *pxSocket; +TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); +uint16_t ucTCPFlags; +uint32_t ulLocalIP; +uint16_t xLocalPort; +uint32_t ulRemoteIP; +uint16_t xRemotePort; +uint32_t ulSequenceNumber; +uint32_t ulAckNumber; +BaseType_t xResult = pdPASS; + + configASSERT( pxNetworkBuffer ); + configASSERT( pxNetworkBuffer->pucEthernetBuffer ); + + /* Check for a minimum packet size. */ + if( pxNetworkBuffer->xDataLength >= ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) ) + { + ucTCPFlags = pxTCPPacket->xTCPHeader.ucTCPFlags; + ulLocalIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulDestinationIPAddress ); + xLocalPort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usDestinationPort ); + ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress ); + xRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort ); + ulSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber ); + ulAckNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulAckNr ); + + /* Find the destination socket, and if not found: return a socket listing to + the destination PORT. */ + pxSocket = ( FreeRTOS_Socket_t * )pxTCPSocketLookup( ulLocalIP, xLocalPort, ulRemoteIP, xRemotePort ); + } + else + { + return pdFAIL; + } + + if( ( pxSocket == NULL ) || ( prvTCPSocketIsActive( ( UBaseType_t ) pxSocket->u.xTCP.ucTCPState ) == pdFALSE ) ) + { + /* A TCP messages is received but either there is no socket with the + given port number or the there is a socket, but it is in one of these + non-active states: eCLOSED, eCLOSE_WAIT, eFIN_WAIT_2, eCLOSING, or + eTIME_WAIT. */ + + FreeRTOS_debug_printf( ( "TCP: No active socket on port %d (%lxip:%d)\n", xLocalPort, ulRemoteIP, xRemotePort ) ); + + /* Send a RST to all packets that can not be handled. As a result + the other party will get a ECONN error. There are two exceptions: + 1) A packet that already has the RST flag set. + 2) A packet that only has the ACK flag set. + A packet with only the ACK flag set might be the last ACK in + a three-way hand-shake that closes a connection. */ + if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_ACK ) && + ( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u ) ) + { + prvTCPSendReset( pxNetworkBuffer ); + } + + /* The packet can't be handled. */ + xResult = pdFAIL; + } + else + { + pxSocket->u.xTCP.ucRepCount = 0u; + + if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ) + { + /* The matching socket is in a listening state. Test if the peer + has set the SYN flag. */ + if( ( ucTCPFlags & ipTCP_FLAG_CTRL ) != ipTCP_FLAG_SYN ) + { + /* What happens: maybe after a reboot, a client doesn't know the + connection had gone. Send a RST in order to get a new connect + request. */ + #if( ipconfigHAS_DEBUG_PRINTF == 1 ) + { + FreeRTOS_debug_printf( ( "TCP: Server can't handle flags: %s from %lxip:%u to port %u\n", + prvTCPFlagMeaning( ( UBaseType_t ) ucTCPFlags ), ulRemoteIP, xRemotePort, xLocalPort ) ); + } + #endif /* ipconfigHAS_DEBUG_PRINTF */ + + if( ( ucTCPFlags & ipTCP_FLAG_RST ) == 0u ) + { + prvTCPSendReset( pxNetworkBuffer ); + } + xResult = pdFAIL; + } + else + { + /* prvHandleListen() will either return a newly created socket + (if bReuseSocket is false), otherwise it returns the current + socket which will later get connected. */ + pxSocket = prvHandleListen( pxSocket, pxNetworkBuffer ); + + if( pxSocket == NULL ) + { + xResult = pdFAIL; + } + } + } /* if( pxSocket->u.xTCP.ucTCPState == eTCP_LISTEN ). */ + else + { + /* This is not a socket in listening mode. Check for the RST + flag. */ + if( ( ucTCPFlags & ipTCP_FLAG_RST ) != 0u ) + { + FreeRTOS_debug_printf( ( "TCP: RST received from %lxip:%u for %u\n", ulRemoteIP, xRemotePort, xLocalPort ) ); + + /* Implement https://tools.ietf.org/html/rfc5961#section-3.2. */ + if( pxSocket->u.xTCP.ucTCPState == eCONNECT_SYN ) + { + /* Per the above RFC, "In the SYN-SENT state ... the RST is + acceptable if the ACK field acknowledges the SYN." */ + if( ulAckNumber == pxSocket->u.xTCP.xTCPWindow.ulOurSequenceNumber + 1 ) + { + vTCPStateChange( pxSocket, eCLOSED ); + } + } + else + { + /* Check whether the packet matches the next expected sequence number. */ + if( ulSequenceNumber == pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber ) + { + vTCPStateChange( pxSocket, eCLOSED ); + } + /* Otherwise, check whether the packet is within the receive window. */ + else if( ulSequenceNumber > pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber && + ulSequenceNumber < ( pxSocket->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber + + pxSocket->u.xTCP.xTCPWindow.xSize.ulRxWindowLength ) ) + { + /* Send a challenge ACK. */ + prvTCPSendChallengeAck( pxNetworkBuffer ); + } + } + + /* Otherwise, do nothing. In any case, the packet cannot be handled. */ + xResult = pdFAIL; + } + else if( ( ( ucTCPFlags & ipTCP_FLAG_CTRL ) == ipTCP_FLAG_SYN ) && ( pxSocket->u.xTCP.ucTCPState >= eESTABLISHED ) ) + { + /* SYN flag while this socket is already connected. */ + FreeRTOS_debug_printf( ( "TCP: SYN unexpected from %lxip:%u\n", ulRemoteIP, xRemotePort ) ); + + /* The packet cannot be handled. */ + xResult = pdFAIL; + } + else + { + /* Update the copy of the TCP header only (skipping eth and IP + headers). It might be used later on, whenever data must be sent + to the peer. */ + const BaseType_t lOffset = ( BaseType_t ) ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv4_HEADER ); + memcpy( pxSocket->u.xTCP.xPacket.u.ucLastPacket + lOffset, pxNetworkBuffer->pucEthernetBuffer + lOffset, ipSIZE_OF_TCP_HEADER ); + } + } + } + + if( xResult != pdFAIL ) + { + /* Touch the alive timers because we received a message for this + socket. */ + prvTCPTouchSocket( pxSocket ); + + /* Parse the TCP option(s), if present. */ + /* _HT_ : if we're in the SYN phase, and peer does not send a MSS option, + then we MUST assume an MSS size of 536 bytes for backward compatibility. */ + + /* When there are no TCP options, the TCP offset equals 20 bytes, which is stored as + the number 5 (words) in the higher niblle of the TCP-offset byte. */ + if( ( pxTCPPacket->xTCPHeader.ucTCPOffset & TCP_OFFSET_LENGTH_BITS ) > TCP_OFFSET_STANDARD_LENGTH ) + { + prvCheckOptions( pxSocket, pxNetworkBuffer ); + } + + + #if( ipconfigUSE_TCP_WIN == 1 ) + { + pxSocket->u.xTCP.ulWindowSize = FreeRTOS_ntohs( pxTCPPacket->xTCPHeader.usWindow ); + pxSocket->u.xTCP.ulWindowSize = + ( pxSocket->u.xTCP.ulWindowSize << pxSocket->u.xTCP.ucPeerWinScaleFactor ); + } + #endif + + /* In prvTCPHandleState() the incoming messages will be handled + depending on the current state of the connection. */ + if( prvTCPHandleState( pxSocket, &pxNetworkBuffer ) > 0 ) + { + /* prvTCPHandleState() has sent a message, see if there are more to + be transmitted. */ + #if( ipconfigUSE_TCP_WIN == 1 ) + { + prvTCPSendRepeated( pxSocket, &pxNetworkBuffer ); + } + #endif /* ipconfigUSE_TCP_WIN */ + } + + if( pxNetworkBuffer != NULL ) + { + /* We must check if the buffer is unequal to NULL, because the + socket might keep a reference to it in case a delayed ACK must be + sent. */ + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + pxNetworkBuffer = NULL; + } + + /* And finally, calculate when this socket wants to be woken up. */ + prvTCPNextTimeout ( pxSocket ); + /* Return pdPASS to tell that the network buffer is 'consumed'. */ + xResult = pdPASS; + } + + /* pdPASS being returned means the buffer has been consumed. */ + return xResult; +} +/*-----------------------------------------------------------*/ + +static FreeRTOS_Socket_t *prvHandleListen( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer ) +{ +TCPPacket_t * pxTCPPacket = ( TCPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); +FreeRTOS_Socket_t *pxReturn = NULL; +uint32_t ulInitialSequenceNumber; + + /* Assume that a new Initial Sequence Number will be required. Request + it now in order to fail out if necessary. */ + ulInitialSequenceNumber = ulApplicationGetNextSequenceNumber( *ipLOCAL_IP_ADDRESS_POINTER, + pxSocket->usLocalPort, + pxTCPPacket->xIPHeader.ulSourceIPAddress, + pxTCPPacket->xTCPHeader.usSourcePort ); + + /* A pure SYN (without ACK) has come in, create a new socket to answer + it. */ + if( 0 != ulInitialSequenceNumber ) + { + if( pxSocket->u.xTCP.bits.bReuseSocket != pdFALSE_UNSIGNED ) + { + /* The flag bReuseSocket indicates that the same instance of the + listening socket should be used for the connection. */ + pxReturn = pxSocket; + pxSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED; + pxSocket->u.xTCP.pxPeerSocket = pxSocket; + } + else + { + /* The socket does not have the bReuseSocket flag set meaning create a + new socket when a connection comes in. */ + pxReturn = NULL; + + if( pxSocket->u.xTCP.usChildCount >= pxSocket->u.xTCP.usBacklog ) + { + FreeRTOS_printf( ( "Check: Socket %u already has %u / %u child%s\n", + pxSocket->usLocalPort, + pxSocket->u.xTCP.usChildCount, + pxSocket->u.xTCP.usBacklog, + pxSocket->u.xTCP.usChildCount == 1 ? "" : "ren" ) ); + prvTCPSendReset( pxNetworkBuffer ); + } + else + { + FreeRTOS_Socket_t *pxNewSocket = ( FreeRTOS_Socket_t * ) + FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP ); + + if( ( pxNewSocket == NULL ) || ( pxNewSocket == FREERTOS_INVALID_SOCKET ) ) + { + FreeRTOS_debug_printf( ( "TCP: Listen: new socket failed\n" ) ); + prvTCPSendReset( pxNetworkBuffer ); + } + else if( prvTCPSocketCopy( pxNewSocket, pxSocket ) != pdFALSE ) + { + /* The socket will be connected immediately, no time for the + owner to setsockopt's, therefore copy properties of the server + socket to the new socket. Only the binding might fail (due to + lack of resources). */ + pxReturn = pxNewSocket; + } + } + } + } + + if( ( 0 != ulInitialSequenceNumber ) && ( pxReturn != NULL ) ) + { + pxReturn->u.xTCP.usRemotePort = FreeRTOS_htons( pxTCPPacket->xTCPHeader.usSourcePort ); + pxReturn->u.xTCP.ulRemoteIP = FreeRTOS_htonl( pxTCPPacket->xIPHeader.ulSourceIPAddress ); + pxReturn->u.xTCP.xTCPWindow.ulOurSequenceNumber = ulInitialSequenceNumber; + + /* Here is the SYN action. */ + pxReturn->u.xTCP.xTCPWindow.rx.ulCurrentSequenceNumber = FreeRTOS_ntohl( pxTCPPacket->xTCPHeader.ulSequenceNumber ); + prvSocketSetMSS( pxReturn ); + + prvTCPCreateWindow( pxReturn ); + + vTCPStateChange( pxReturn, eSYN_FIRST ); + + /* Make a copy of the header up to the TCP header. It is needed later + on, whenever data must be sent to the peer. */ + memcpy( pxReturn->u.xTCP.xPacket.u.ucLastPacket, pxNetworkBuffer->pucEthernetBuffer, sizeof( pxReturn->u.xTCP.xPacket.u.ucLastPacket ) ); + } + return pxReturn; +} +/*-----------------------------------------------------------*/ + +/* + * Duplicates a socket after a listening socket receives a connection. + */ +static BaseType_t prvTCPSocketCopy( FreeRTOS_Socket_t *pxNewSocket, FreeRTOS_Socket_t *pxSocket ) +{ +struct freertos_sockaddr xAddress; + + pxNewSocket->xReceiveBlockTime = pxSocket->xReceiveBlockTime; + pxNewSocket->xSendBlockTime = pxSocket->xSendBlockTime; + pxNewSocket->ucSocketOptions = pxSocket->ucSocketOptions; + pxNewSocket->u.xTCP.uxRxStreamSize = pxSocket->u.xTCP.uxRxStreamSize; + pxNewSocket->u.xTCP.uxTxStreamSize = pxSocket->u.xTCP.uxTxStreamSize; + pxNewSocket->u.xTCP.uxLittleSpace = pxSocket->u.xTCP.uxLittleSpace; + pxNewSocket->u.xTCP.uxEnoughSpace = pxSocket->u.xTCP.uxEnoughSpace; + pxNewSocket->u.xTCP.uxRxWinSize = pxSocket->u.xTCP.uxRxWinSize; + pxNewSocket->u.xTCP.uxTxWinSize = pxSocket->u.xTCP.uxTxWinSize; + + #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 ) + { + pxNewSocket->pxUserSemaphore = pxSocket->pxUserSemaphore; + } + #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */ + + #if( ipconfigUSE_CALLBACKS == 1 ) + { + /* In case call-backs are used, copy them from parent to child. */ + pxNewSocket->u.xTCP.pxHandleConnected = pxSocket->u.xTCP.pxHandleConnected; + pxNewSocket->u.xTCP.pxHandleReceive = pxSocket->u.xTCP.pxHandleReceive; + pxNewSocket->u.xTCP.pxHandleSent = pxSocket->u.xTCP.pxHandleSent; + } + #endif /* ipconfigUSE_CALLBACKS */ + + #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + { + /* Child socket of listening sockets will inherit the Socket Set + Otherwise the owner has no chance of including it into the set. */ + if( pxSocket->pxSocketSet ) + { + pxNewSocket->pxSocketSet = pxSocket->pxSocketSet; + pxNewSocket->xSelectBits = pxSocket->xSelectBits | eSELECT_READ | eSELECT_EXCEPT; + } + } + #endif /* ipconfigSUPPORT_SELECT_FUNCTION */ + + /* And bind it to the same local port as its parent. */ + xAddress.sin_addr = *ipLOCAL_IP_ADDRESS_POINTER; + xAddress.sin_port = FreeRTOS_htons( pxSocket->usLocalPort ); + + #if( ipconfigTCP_HANG_PROTECTION == 1 ) + { + /* Only when there is anti-hanging protection, a socket may become an + orphan temporarily. Once this socket is really connected, the owner of + the server socket will be notified. */ + + /* When bPassQueued is true, the socket is an orphan until it gets + connected. */ + pxNewSocket->u.xTCP.bits.bPassQueued = pdTRUE_UNSIGNED; + pxNewSocket->u.xTCP.pxPeerSocket = pxSocket; + } + #else + { + /* A reference to the new socket may be stored and the socket is marked + as 'passable'. */ + + /* When bPassAccept is pdTRUE_UNSIGNED this socket may be returned in a call to + accept(). */ + pxNewSocket->u.xTCP.bits.bPassAccept = pdTRUE_UNSIGNED; + if(pxSocket->u.xTCP.pxPeerSocket == NULL ) + { + pxSocket->u.xTCP.pxPeerSocket = pxNewSocket; + } + } + #endif + + pxSocket->u.xTCP.usChildCount++; + + FreeRTOS_debug_printf( ( "Gain: Socket %u now has %u / %u child%s\n", + pxSocket->usLocalPort, + pxSocket->u.xTCP.usChildCount, + pxSocket->u.xTCP.usBacklog, + pxSocket->u.xTCP.usChildCount == 1u ? "" : "ren" ) ); + + /* Now bind the child socket to the same port as the listening socket. */ + if( vSocketBind ( pxNewSocket, &xAddress, sizeof( xAddress ), pdTRUE ) != 0 ) + { + FreeRTOS_debug_printf( ( "TCP: Listen: new socket bind error\n" ) ); + vSocketClose( pxNewSocket ); + return pdFALSE; + } + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +#if( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) + + const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState ) + { + if( ulState >= ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) ) + { + ulState = ( UBaseType_t ) ARRAY_SIZE( pcStateNames ) - 1u; + } + return pcStateNames[ ulState ]; + } + +#endif /* ( ( ipconfigHAS_DEBUG_PRINTF != 0 ) || ( ipconfigHAS_PRINTF != 0 ) ) */ +/*-----------------------------------------------------------*/ + +/* + * In the API accept(), the user asks is there is a new client? As API's can + * not walk through the xBoundTCPSocketsList the IP-task will do this. + */ +BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t *pxSocket ) +{ +TickType_t xLocalPort = FreeRTOS_htons( pxSocket->usLocalPort ); +ListItem_t *pxIterator; +FreeRTOS_Socket_t *pxFound; +BaseType_t xResult = pdFALSE; + + /* Here xBoundTCPSocketsList can be accessed safely IP-task is the only one + who has access. */ + for( pxIterator = ( ListItem_t * ) listGET_HEAD_ENTRY( &xBoundTCPSocketsList ); + pxIterator != ( ListItem_t * ) listGET_END_MARKER( &xBoundTCPSocketsList ); + pxIterator = ( ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + if( listGET_LIST_ITEM_VALUE( pxIterator ) == xLocalPort ) + { + pxFound = ( FreeRTOS_Socket_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + if( ( pxFound->ucProtocol == FREERTOS_IPPROTO_TCP ) && ( pxFound->u.xTCP.bits.bPassAccept != pdFALSE_UNSIGNED ) ) + { + pxSocket->u.xTCP.pxPeerSocket = pxFound; + FreeRTOS_debug_printf( ( "xTCPCheckNewClient[0]: client on port %u\n", pxSocket->usLocalPort ) ); + xResult = pdTRUE; + break; + } + } + } + return xResult; +} +/*-----------------------------------------------------------*/ + +#endif /* ipconfigUSE_TCP == 1 */ + +/* Provide access to private members for testing. */ +#ifdef AMAZON_FREERTOS_ENABLE_UNIT_TESTS + #include "iot_freertos_tcp_test_access_tcp_define.h" +#endif + +/* Provide access to private members for verification. */ +#ifdef FREERTOS_TCP_ENABLE_VERIFICATION + #include "aws_freertos_tcp_verification_access_tcp_define.h" +#endif + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c new file mode 100644 index 000000000..f94b181f7 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c @@ -0,0 +1,1998 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* + * FreeRTOS_TCP_WIN.c + * Module which handles the TCP windowing schemes for FreeRTOS+TCP. Many + * functions have two versions - one for FreeRTOS+TCP (full) and one for + * FreeRTOS+TCP (lite). + * + * In this module all ports and IP addresses and sequence numbers are + * being stored in host byte-order. + */ + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkBufferManagement.h" +#include "FreeRTOS_TCP_WIN.h" + +/* Constants used for Smoothed Round Trip Time (SRTT). */ +#define winSRTT_INCREMENT_NEW 2 +#define winSRTT_INCREMENT_CURRENT 6 +#define winSRTT_DECREMENT_NEW 1 +#define winSRTT_DECREMENT_CURRENT 7 +#define winSRTT_CAP_mS 50 + +#if( ipconfigUSE_TCP_WIN == 1 ) + + #define xTCPWindowRxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdTRUE ) + + #define xTCPWindowTxNew( pxWindow, ulSequenceNumber, lCount ) xTCPWindowNew( pxWindow, ulSequenceNumber, lCount, pdFALSE ) + + /* The code to send a single Selective ACK (SACK): + * NOP (0x01), NOP (0x01), SACK (0x05), LEN (0x0a), + * followed by a lower and a higher sequence number, + * where LEN is 2 + 2*4 = 10 bytes. */ + #if( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN ) + #define OPTION_CODE_SINGLE_SACK ( 0x0101050aUL ) + #else + #define OPTION_CODE_SINGLE_SACK ( 0x0a050101UL ) + #endif + + /* Normal retransmission: + * A packet will be retransmitted after a Retransmit Time-Out (RTO). + * Fast retransmission: + * When 3 packets with a higher sequence number have been acknowledged + * by the peer, it is very unlikely a current packet will ever arrive. + * It will be retransmitted far before the RTO. + */ + #define DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ( 3u ) + + /* If there have been several retransmissions (4), decrease the + * size of the transmission window to at most 2 times MSS. + */ + #define MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW ( 4u ) + +#endif /* configUSE_TCP_WIN */ +/*-----------------------------------------------------------*/ + +extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere ); + +/* + * All TCP sockets share a pool of segment descriptors (TCPSegment_t) + * Available descriptors are stored in the 'xSegmentList' + * When a socket owns a descriptor, it will either be stored in + * 'xTxSegments' or 'xRxSegments' + * As soon as a package has been confirmed, the descriptor will be returned + * to the segment pool + */ +#if( ipconfigUSE_TCP_WIN == 1 ) + static BaseType_t prvCreateSectors( void ); +#endif /* ipconfigUSE_TCP_WIN == 1 */ + +/* + * Find a segment with a given sequence number in the list of received + * segments: 'pxWindow->xRxSegments'. + */ +#if( ipconfigUSE_TCP_WIN == 1 ) + static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber ); +#endif /* ipconfigUSE_TCP_WIN == 1 */ + +/* + * Allocate a new segment + * The socket will borrow all segments from a common pool: 'xSegmentList', + * which is a list of 'TCPSegment_t' + */ +#if( ipconfigUSE_TCP_WIN == 1 ) + static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx ); +#endif /* ipconfigUSE_TCP_WIN == 1 */ + +/* When the peer has a close request (FIN flag), the driver will check if + * there are missing packets in the Rx-queue + * It will accept the closure of the connection if both conditions are true: + * - the Rx-queue is empty + * - we've ACK'd the highest Rx sequence number seen + */ +#if( ipconfigUSE_TCP_WIN == 1 ) + BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow ); +#endif /* ipconfigUSE_TCP_WIN == 1 */ + +/* + * Detaches and returns the head of a queue + */ +#if( ipconfigUSE_TCP_WIN == 1 ) + static TCPSegment_t *xTCPWindowGetHead( List_t *pxList ); +#endif /* ipconfigUSE_TCP_WIN == 1 */ + +/* + * Returns the head of a queue but it won't be detached + */ +#if( ipconfigUSE_TCP_WIN == 1 ) + static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList ); +#endif /* ipconfigUSE_TCP_WIN == 1 */ + +/* + * Free entry pxSegment because it's not used anymore + * The ownership will be passed back to the segment pool + */ +#if( ipconfigUSE_TCP_WIN == 1 ) + static void vTCPWindowFree( TCPSegment_t *pxSegment ); +#endif /* ipconfigUSE_TCP_WIN == 1 */ + +/* + * A segment has been received with sequence number 'ulSequenceNumber', where + * 'ulCurrentSequenceNumber == ulSequenceNumber', which means that exactly this + * segment was expected. xTCPWindowRxConfirm() will check if there is already + * another segment with a sequence number between (ulSequenceNumber) and + * (ulSequenceNumber+xLength). Normally none will be found, because the next Rx + * segment should have a sequence number equal to '(ulSequenceNumber+xLength)'. + */ +#if( ipconfigUSE_TCP_WIN == 1 ) + static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength ); +#endif /* ipconfigUSE_TCP_WIN == 1 */ + +/* + * FreeRTOS+TCP stores data in circular buffers. Calculate the next position to + * store. + */ +#if( ipconfigUSE_TCP_WIN == 1 ) + static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount ); +#endif /* ipconfigUSE_TCP_WIN == 1 */ + +/* + * This function will look if there is new transmission data. It will return + * true if there is data to be sent. + */ +#if( ipconfigUSE_TCP_WIN == 1 ) + static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize ); +#endif /* ipconfigUSE_TCP_WIN == 1 */ + +/* + * An acknowledge was received. See if some outstanding data may be removed + * from the transmission queue(s). + */ +#if( ipconfigUSE_TCP_WIN == 1 ) + static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast ); +#endif /* ipconfigUSE_TCP_WIN == 1 */ + +/* + * A higher Tx block has been acknowledged. Now iterate through the xWaitQueue + * to find a possible condition for a FAST retransmission. + */ +#if( ipconfigUSE_TCP_WIN == 1 ) + static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst ); +#endif /* ipconfigUSE_TCP_WIN == 1 */ + +/*-----------------------------------------------------------*/ + +/* TCP segment pool. */ +#if( ipconfigUSE_TCP_WIN == 1 ) + static TCPSegment_t *xTCPSegments = NULL; +#endif /* ipconfigUSE_TCP_WIN == 1 */ + +/* List of free TCP segments. */ +#if( ipconfigUSE_TCP_WIN == 1 ) + static List_t xSegmentList; +#endif + +/* Logging verbosity level. */ +BaseType_t xTCPWindowLoggingLevel = 0; + +#if( ipconfigUSE_TCP_WIN == 1 ) + /* Some 32-bit arithmetic: comparing sequence numbers */ + static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b ); + static portINLINE BaseType_t xSequenceLessThanOrEqual( uint32_t a, uint32_t b ) + { + /* Test if a <= b + Return true if the unsigned subtraction of (b-a) doesn't generate an + arithmetic overflow. */ + return ( ( b - a ) & 0x80000000UL ) == 0UL; + } +#endif /* ipconfigUSE_TCP_WIN */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b ); + static portINLINE BaseType_t xSequenceLessThan( uint32_t a, uint32_t b ) + { + /* Test if a < b */ + return ( ( b - a - 1UL ) & 0x80000000UL ) == 0UL; + } +#endif /* ipconfigUSE_TCP_WIN */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b ); + static portINLINE BaseType_t xSequenceGreaterThan( uint32_t a, uint32_t b ) + { + /* Test if a > b */ + return ( ( a - b - 1UL ) & 0x80000000UL ) == 0UL; + } +#endif /* ipconfigUSE_TCP_WIN */ + +/*-----------------------------------------------------------*/ +static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b ); +static portINLINE BaseType_t xSequenceGreaterThanOrEqual( uint32_t a, uint32_t b ) +{ + /* Test if a >= b */ + return ( ( a - b ) & 0x80000000UL ) == 0UL; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem ); + static portINLINE void vListInsertFifo( List_t * const pxList, ListItem_t * const pxNewListItem ) + { + vListInsertGeneric( pxList, pxNewListItem, &pxList->xListEnd ); + } +#endif +/*-----------------------------------------------------------*/ + +static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer ); +static portINLINE void vTCPTimerSet( TCPTimer_t *pxTimer ) +{ + pxTimer->ulBorn = xTaskGetTickCount ( ); +} +/*-----------------------------------------------------------*/ + +static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer ); +static portINLINE uint32_t ulTimerGetAge( TCPTimer_t *pxTimer ) +{ + return ( ( xTaskGetTickCount() - pxTimer->ulBorn ) * portTICK_PERIOD_MS ); +} +/*-----------------------------------------------------------*/ + +/* _HT_ GCC (using the settings that I'm using) checks for every public function if it is +preceded by a prototype. Later this prototype will be located in list.h? */ + +extern void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere ); + +void vListInsertGeneric( List_t * const pxList, ListItem_t * const pxNewListItem, MiniListItem_t * const pxWhere ) +{ + /* Insert a new list item into pxList, it does not sort the list, + but it puts the item just before xListEnd, so it will be the last item + returned by listGET_HEAD_ENTRY() */ + pxNewListItem->pxNext = (struct xLIST_ITEM * configLIST_VOLATILE)pxWhere; + pxNewListItem->pxPrevious = pxWhere->pxPrevious; + pxWhere->pxPrevious->pxNext = pxNewListItem; + pxWhere->pxPrevious = pxNewListItem; + + /* Remember which list the item is in. */ + listLIST_ITEM_CONTAINER( pxNewListItem ) = ( void * ) pxList; + + ( pxList->uxNumberOfItems )++; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + static BaseType_t prvCreateSectors( void ) + { + BaseType_t xIndex, xReturn; + + /* Allocate space for 'xTCPSegments' and store them in 'xSegmentList'. */ + + vListInitialise( &xSegmentList ); + xTCPSegments = ( TCPSegment_t * ) pvPortMallocLarge( ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ); + + if( xTCPSegments == NULL ) + { + FreeRTOS_debug_printf( ( "prvCreateSectors: malloc %lu failed\n", + ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ) ); + + xReturn = pdFAIL; + } + else + { + /* Clear the allocated space. */ + memset( xTCPSegments, '\0', ipconfigTCP_WIN_SEG_COUNT * sizeof( xTCPSegments[ 0 ] ) ); + + for( xIndex = 0; xIndex < ipconfigTCP_WIN_SEG_COUNT; xIndex++ ) + { + /* Could call vListInitialiseItem here but all data has been + nulled already. Set the owner to a segment descriptor. */ + listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xListItem ), ( void* ) &( xTCPSegments[ xIndex ] ) ); + listSET_LIST_ITEM_OWNER( &( xTCPSegments[ xIndex ].xQueueItem ), ( void* ) &( xTCPSegments[ xIndex ] ) ); + + /* And add it to the pool of available segments */ + vListInsertFifo( &xSegmentList, &( xTCPSegments[xIndex].xListItem ) ); + } + + xReturn = pdPASS; + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + static TCPSegment_t *xTCPWindowRxFind( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber ) + { + const ListItem_t *pxIterator; + const MiniListItem_t* pxEnd; + TCPSegment_t *pxSegment, *pxReturn = NULL; + + /* Find a segment with a given sequence number in the list of received + segments. */ + + pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xRxSegments ); + + for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd ); + pxIterator != ( const ListItem_t * ) pxEnd; + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + + if( pxSegment->ulSequenceNumber == ulSequenceNumber ) + { + pxReturn = pxSegment; + break; + } + } + + return pxReturn; + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + static TCPSegment_t *xTCPWindowNew( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, int32_t lCount, BaseType_t xIsForRx ) + { + TCPSegment_t *pxSegment; + ListItem_t * pxItem; + + /* Allocate a new segment. The socket will borrow all segments from a + common pool: 'xSegmentList', which is a list of 'TCPSegment_t' */ + if( listLIST_IS_EMPTY( &xSegmentList ) != pdFALSE ) + { + /* If the TCP-stack runs out of segments, you might consider + increasing 'ipconfigTCP_WIN_SEG_COUNT'. */ + FreeRTOS_debug_printf( ( "xTCPWindow%cxNew: Error: all segments occupied\n", xIsForRx ? 'R' : 'T' ) ); + pxSegment = NULL; + } + else + { + /* Pop the item at the head of the list. Semaphore protection is + not required as only the IP task will call these functions. */ + pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( &xSegmentList ); + pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem ); + + configASSERT( pxItem != NULL ); + configASSERT( pxSegment != NULL ); + + /* Remove the item from xSegmentList. */ + uxListRemove( pxItem ); + + /* Add it to either the connections' Rx or Tx queue. */ + vListInsertFifo( xIsForRx ? &pxWindow->xRxSegments : &pxWindow->xTxSegments, pxItem ); + + /* And set the segment's timer to zero */ + vTCPTimerSet( &pxSegment->xTransmitTimer ); + + pxSegment->u.ulFlags = 0; + pxSegment->u.bits.bIsForRx = ( xIsForRx != 0 ); + pxSegment->lMaxLength = lCount; + pxSegment->lDataLength = lCount; + pxSegment->ulSequenceNumber = ulSequenceNumber; + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + static UBaseType_t xLowestLength = ipconfigTCP_WIN_SEG_COUNT; + UBaseType_t xLength = listCURRENT_LIST_LENGTH( &xSegmentList ); + + if( xLowestLength > xLength ) + { + xLowestLength = xLength; + } + } + #endif /* ipconfigHAS_DEBUG_PRINTF */ + } + + return pxSegment; + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow ) + { + BaseType_t xReturn; + + /* When the peer has a close request (FIN flag), the driver will check + if there are missing packets in the Rx-queue. It will accept the + closure of the connection if both conditions are true: + - the Rx-queue is empty + - the highest Rx sequence number has been ACK'ed */ + if( listLIST_IS_EMPTY( ( &pxWindow->xRxSegments ) ) == pdFALSE ) + { + /* Rx data has been stored while earlier packets were missing. */ + xReturn = pdFALSE; + } + else if( xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber ) != pdFALSE ) + { + /* No Rx packets are being stored and the highest sequence number + that has been received has been ACKed. */ + xReturn = pdTRUE; + } + else + { + FreeRTOS_debug_printf( ( "xTCPWindowRxEmpty: cur %lu highest %lu (empty)\n", + ( pxWindow->rx.ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ), + ( pxWindow->rx.ulHighestSequenceNumber - pxWindow->rx.ulFirstSequenceNumber ) ) ); + xReturn = pdFALSE; + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + static TCPSegment_t *xTCPWindowGetHead( List_t *pxList ) + { + TCPSegment_t *pxSegment; + ListItem_t * pxItem; + + /* Detaches and returns the head of a queue. */ + if( listLIST_IS_EMPTY( pxList ) != pdFALSE ) + { + pxSegment = NULL; + } + else + { + pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList ); + pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem ); + + uxListRemove( pxItem ); + } + + return pxSegment; + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + static TCPSegment_t *xTCPWindowPeekHead( List_t *pxList ) + { + ListItem_t *pxItem; + TCPSegment_t *pxReturn; + + /* Returns the head of a queue but it won't be detached. */ + if( listLIST_IS_EMPTY( pxList ) != pdFALSE ) + { + pxReturn = NULL; + } + else + { + pxItem = ( ListItem_t * ) listGET_HEAD_ENTRY( pxList ); + pxReturn = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxItem ); + } + + return pxReturn; + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + static void vTCPWindowFree( TCPSegment_t *pxSegment ) + { + /* Free entry pxSegment because it's not used any more. The ownership + will be passed back to the segment pool. + + Unlink it from one of the queues, if any. */ + if( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) + { + uxListRemove( &( pxSegment->xQueueItem ) ); + } + + pxSegment->ulSequenceNumber = 0u; + pxSegment->lDataLength = 0l; + pxSegment->u.ulFlags = 0u; + + /* Take it out of xRxSegments/xTxSegments */ + if( listLIST_ITEM_CONTAINER( &( pxSegment->xListItem ) ) != NULL ) + { + uxListRemove( &( pxSegment->xListItem ) ); + } + + /* Return it to xSegmentList */ + vListInsertFifo( &xSegmentList, &( pxSegment->xListItem ) ); + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + void vTCPWindowDestroy( TCPWindow_t *pxWindow ) + { + List_t * pxSegments; + BaseType_t xRound; + TCPSegment_t *pxSegment; + + /* Destroy a window. A TCP window doesn't serve any more. Return all + owned segments to the pool. In order to save code, it will make 2 rounds, + one to remove the segments from xRxSegments, and a second round to clear + xTxSegments*/ + for( xRound = 0; xRound < 2; xRound++ ) + { + if( xRound != 0 ) + { + pxSegments = &( pxWindow->xRxSegments ); + } + else + { + pxSegments = &( pxWindow->xTxSegments ); + } + + if( listLIST_IS_INITIALISED( pxSegments ) != pdFALSE ) + { + while( listCURRENT_LIST_LENGTH( pxSegments ) > 0U ) + { + pxSegment = ( TCPSegment_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxSegments ); + vTCPWindowFree( pxSegment ); + } + } + } + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +void vTCPWindowCreate( TCPWindow_t *pxWindow, uint32_t ulRxWindowLength, + uint32_t ulTxWindowLength, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS ) +{ + /* Create and initialize a window. */ + + #if( ipconfigUSE_TCP_WIN == 1 ) + { + if( xTCPSegments == NULL ) + { + prvCreateSectors(); + } + + vListInitialise( &pxWindow->xTxSegments ); + vListInitialise( &pxWindow->xRxSegments ); + + vListInitialise( &pxWindow->xPriorityQueue ); /* Priority queue: segments which must be sent immediately */ + vListInitialise( &pxWindow->xTxQueue ); /* Transmit queue: segments queued for transmission */ + vListInitialise( &pxWindow->xWaitQueue ); /* Waiting queue: outstanding segments */ + } + #endif /* ipconfigUSE_TCP_WIN == 1 */ + + if( xTCPWindowLoggingLevel != 0 ) + { + FreeRTOS_debug_printf( ( "vTCPWindowCreate: for WinLen = Rx/Tx: %lu/%lu\n", + ulRxWindowLength, ulTxWindowLength ) ); + } + + pxWindow->xSize.ulRxWindowLength = ulRxWindowLength; + pxWindow->xSize.ulTxWindowLength = ulTxWindowLength; + + vTCPWindowInit( pxWindow, ulAckNumber, ulSequenceNumber, ulMSS ); +} +/*-----------------------------------------------------------*/ + +void vTCPWindowInit( TCPWindow_t *pxWindow, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS ) +{ +const int32_t l500ms = 500; + + pxWindow->u.ulFlags = 0ul; + pxWindow->u.bits.bHasInit = pdTRUE_UNSIGNED; + + if( ulMSS != 0ul ) + { + if( pxWindow->usMSSInit != 0u ) + { + pxWindow->usMSSInit = ( uint16_t ) ulMSS; + } + + if( ( ulMSS < ( uint32_t ) pxWindow->usMSS ) || ( pxWindow->usMSS == 0u ) ) + { + pxWindow->xSize.ulRxWindowLength = ( pxWindow->xSize.ulRxWindowLength / ulMSS ) * ulMSS; + pxWindow->usMSS = ( uint16_t ) ulMSS; + } + } + + #if( ipconfigUSE_TCP_WIN == 0 ) + { + pxWindow->xTxSegment.lMaxLength = ( int32_t ) pxWindow->usMSS; + } + #endif /* ipconfigUSE_TCP_WIN == 1 */ + + /*Start with a timeout of 2 * 500 ms (1 sec). */ + pxWindow->lSRTT = l500ms; + + /* Just for logging, to print relative sequence numbers. */ + pxWindow->rx.ulFirstSequenceNumber = ulAckNumber; + + /* The segment asked for in the next transmission. */ + pxWindow->rx.ulCurrentSequenceNumber = ulAckNumber; + + /* The right-hand side of the receive window. */ + pxWindow->rx.ulHighestSequenceNumber = ulAckNumber; + + pxWindow->tx.ulFirstSequenceNumber = ulSequenceNumber; + + /* The segment asked for in next transmission. */ + pxWindow->tx.ulCurrentSequenceNumber = ulSequenceNumber; + + /* The sequence number given to the next outgoing byte to be added is + maintained by lTCPWindowTxAdd(). */ + pxWindow->ulNextTxSequenceNumber = ulSequenceNumber; + + /* The right-hand side of the transmit window. */ + pxWindow->tx.ulHighestSequenceNumber = ulSequenceNumber; + pxWindow->ulOurSequenceNumber = ulSequenceNumber; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + void vTCPSegmentCleanup( void ) + { + /* Free and clear the TCP segments pointer. This function should only be called + * once FreeRTOS+TCP will no longer be used. No thread-safety is provided for this + * function. */ + if( xTCPSegments != NULL ) + { + vPortFreeLarge( xTCPSegments ); + xTCPSegments = NULL; + } + } + +#endif /* ipconfgiUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +/*============================================================================= + * + * ###### # # + * # # # # + * # # # # + * # # #### + * ###### ## + * # ## #### + * # # # # + * # # # # + * ### ## # # + * Rx functions + * + *=============================================================================*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + static TCPSegment_t *xTCPWindowRxConfirm( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength ) + { + TCPSegment_t *pxBest = NULL; + const ListItem_t *pxIterator; + uint32_t ulNextSequenceNumber = ulSequenceNumber + ulLength; + const MiniListItem_t* pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &pxWindow->xRxSegments ); + TCPSegment_t *pxSegment; + + /* A segment has been received with sequence number 'ulSequenceNumber', + where 'ulCurrentSequenceNumber == ulSequenceNumber', which means that + exactly this segment was expected. xTCPWindowRxConfirm() will check if + there is already another segment with a sequence number between (ulSequenceNumber) + and (ulSequenceNumber+ulLength). Normally none will be found, because + the next RX segment should have a sequence number equal to + '(ulSequenceNumber+ulLength)'. */ + + /* Iterate through all RX segments that are stored: */ + for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd ); + pxIterator != ( const ListItem_t * ) pxEnd; + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ) ) + { + pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + /* And see if there is a segment for which: + 'ulSequenceNumber' <= 'pxSegment->ulSequenceNumber' < 'ulNextSequenceNumber' + If there are more matching segments, the one with the lowest sequence number + shall be taken */ + if( ( xSequenceGreaterThanOrEqual( pxSegment->ulSequenceNumber, ulSequenceNumber ) != 0 ) && + ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulNextSequenceNumber ) != 0 ) ) + { + if( ( pxBest == NULL ) || ( xSequenceLessThan( pxSegment->ulSequenceNumber, pxBest->ulSequenceNumber ) != 0 ) ) + { + pxBest = pxSegment; + } + } + } + + if( ( pxBest != NULL ) && + ( ( pxBest->ulSequenceNumber != ulSequenceNumber ) || ( pxBest->lDataLength != ( int32_t ) ulLength ) ) ) + { + FreeRTOS_flush_logging(); + FreeRTOS_debug_printf( ( "xTCPWindowRxConfirm[%u]: search %lu (+%ld=%lu) found %lu (+%ld=%lu)\n", + pxWindow->usPeerPortNumber, + ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber, + ulLength, + ulSequenceNumber + ulLength - pxWindow->rx.ulFirstSequenceNumber, + pxBest->ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber, + pxBest->lDataLength, + pxBest->ulSequenceNumber + ( ( uint32_t ) pxBest->lDataLength ) - pxWindow->rx.ulFirstSequenceNumber ) ); + } + + return pxBest; + } + +#endif /* ipconfgiUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace ) + { + uint32_t ulCurrentSequenceNumber, ulLast, ulSavedSequenceNumber; + int32_t lReturn, lDistance; + TCPSegment_t *pxFound; + + /* If lTCPWindowRxCheck( ) returns == 0, the packet will be passed + directly to user (segment is expected). If it returns a positive + number, an earlier packet is missing, but this packet may be stored. + If negative, the packet has already been stored, or it is out-of-order, + or there is not enough space. + + As a side-effect, pxWindow->ulUserDataLength will get set to non-zero, + if more Rx data may be passed to the user after this packet. */ + + ulCurrentSequenceNumber = pxWindow->rx.ulCurrentSequenceNumber; + + /* For Selective Ack (SACK), used when out-of-sequence data come in. */ + pxWindow->ucOptionLength = 0u; + + /* Non-zero if TCP-windows contains data which must be popped. */ + pxWindow->ulUserDataLength = 0ul; + + if( ulCurrentSequenceNumber == ulSequenceNumber ) + { + /* This is the packet with the lowest sequence number we're waiting + for. It can be passed directly to the rx stream. */ + if( ulLength > ulSpace ) + { + FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu bytes, due to lack of space (%lu)\n", ulLength, ulSpace ) ); + lReturn = -1; + } + else + { + ulCurrentSequenceNumber += ulLength; + + if( listCURRENT_LIST_LENGTH( &( pxWindow->xRxSegments ) ) != 0 ) + { + ulSavedSequenceNumber = ulCurrentSequenceNumber; + + /* Clean up all sequence received between ulSequenceNumber and ulSequenceNumber + ulLength since they are duplicated. + If the server is forced to retransmit packets several time in a row it might send a batch of concatenated packet for speed. + So we cannot rely on the packets between ulSequenceNumber and ulSequenceNumber + ulLength to be sequential and it is better to just + clean them out. */ + do + { + pxFound = xTCPWindowRxConfirm( pxWindow, ulSequenceNumber, ulLength ); + + if ( pxFound != NULL ) + { + /* Remove it because it will be passed to user directly. */ + vTCPWindowFree( pxFound ); + } + } while ( pxFound ); + + /* Check for following segments that are already in the + queue and increment ulCurrentSequenceNumber. */ + while( ( pxFound = xTCPWindowRxFind( pxWindow, ulCurrentSequenceNumber ) ) != NULL ) + { + ulCurrentSequenceNumber += ( uint32_t ) pxFound->lDataLength; + + /* As all packet below this one have been passed to the + user it can be discarded. */ + vTCPWindowFree( pxFound ); + } + + if( ulSavedSequenceNumber != ulCurrentSequenceNumber ) + { + /* After the current data-package, there is more data + to be popped. */ + pxWindow->ulUserDataLength = ulCurrentSequenceNumber - ulSavedSequenceNumber; + + if( xTCPWindowLoggingLevel >= 1 ) + { + FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: retran %lu (Found %lu bytes at %lu cnt %ld)\n", + pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber, + ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber, + pxWindow->ulUserDataLength, + ulSavedSequenceNumber - pxWindow->rx.ulFirstSequenceNumber, + listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) ); + } + } + } + + pxWindow->rx.ulCurrentSequenceNumber = ulCurrentSequenceNumber; + + /* Packet was expected, may be passed directly to the socket + buffer or application. Store the packet at offset 0. */ + lReturn = 0; + } + } + else if( ulCurrentSequenceNumber == ( ulSequenceNumber + 1UL ) ) + { + /* Looks like a TCP keep-alive message. Do not accept/store Rx data + ulUserDataLength = 0. Not packet out-of-sync. Just reply to it. */ + lReturn = -1; + } + else + { + /* The packet is not the one expected. See if it falls within the Rx + window so it can be stored. */ + + /* An "out-of-sequence" segment was received, must have missed one. + Prepare a SACK (Selective ACK). */ + ulLast = ulSequenceNumber + ulLength; + lDistance = ( int32_t ) ( ulLast - ulCurrentSequenceNumber ); + + if( lDistance <= 0 ) + { + /* An earlier has been received, must be a retransmission of a + packet that has been accepted already. No need to send out a + Selective ACK (SACK). */ + lReturn = -1; + } + else if( lDistance > ( int32_t ) ulSpace ) + { + /* The new segment is ahead of rx.ulCurrentSequenceNumber. The + sequence number of this packet is too far ahead, ignore it. */ + FreeRTOS_debug_printf( ( "lTCPWindowRxCheck: Refuse %lu+%lu bytes, due to lack of space (%lu)\n", lDistance, ulLength, ulSpace ) ); + lReturn = -1; + } + else + { + /* See if there is more data in a contiguous block to make the + SACK describe a longer range of data. */ + + /* TODO: SACK's may also be delayed for a short period + * This is useful because subsequent packets will be SACK'd with + * single one message + */ + while( ( pxFound = xTCPWindowRxFind( pxWindow, ulLast ) ) != NULL ) + { + ulLast += ( uint32_t ) pxFound->lDataLength; + } + + if( xTCPWindowLoggingLevel >= 1 ) + { + FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%d,%d]: seqnr %lu exp %lu (dist %ld) SACK to %lu\n", + pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber, + ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber, + ulCurrentSequenceNumber - pxWindow->rx.ulFirstSequenceNumber, + ( BaseType_t ) ( ulSequenceNumber - ulCurrentSequenceNumber ), /* want this signed */ + ulLast - pxWindow->rx.ulFirstSequenceNumber ) ); + } + + /* Now prepare the SACK message. + Code OPTION_CODE_SINGLE_SACK already in network byte order. */ + pxWindow->ulOptionsData[0] = OPTION_CODE_SINGLE_SACK; + + /* First sequence number that we received. */ + pxWindow->ulOptionsData[1] = FreeRTOS_htonl( ulSequenceNumber ); + + /* Last + 1 */ + pxWindow->ulOptionsData[2] = FreeRTOS_htonl( ulLast ); + + /* Which make 12 (3*4) option bytes. */ + pxWindow->ucOptionLength = 3 * sizeof( pxWindow->ulOptionsData[ 0 ] ); + + pxFound = xTCPWindowRxFind( pxWindow, ulSequenceNumber ); + + if( pxFound != NULL ) + { + /* This out-of-sequence packet has been received for a + second time. It is already stored but do send a SACK + again. */ + lReturn = -1; + } + else + { + pxFound = xTCPWindowRxNew( pxWindow, ulSequenceNumber, ( int32_t ) ulLength ); + + if( pxFound == NULL ) + { + /* Can not send a SACK, because the segment cannot be + stored. */ + pxWindow->ucOptionLength = 0u; + + /* Needs to be stored but there is no segment + available. */ + lReturn = -1; + } + else + { + if( xTCPWindowLoggingLevel != 0 ) + { + FreeRTOS_debug_printf( ( "lTCPWindowRxCheck[%u,%u]: seqnr %lu (cnt %lu)\n", + pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber, ulSequenceNumber - pxWindow->rx.ulFirstSequenceNumber, + listCURRENT_LIST_LENGTH( &pxWindow->xRxSegments ) ) ); + FreeRTOS_flush_logging( ); + } + + /* Return a positive value. The packet may be accepted + and stored but an earlier packet is still missing. */ + lReturn = ( int32_t ) ( ulSequenceNumber - ulCurrentSequenceNumber ); + } + } + } + } + + return lReturn; + } + +#endif /* ipconfgiUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +/*============================================================================= + * + * ######### # # + * # # # # # + * # # # + * # #### + * # ## + * # #### + * # # # + * # # # + * ##### # # + * + * Tx functions + * + *=============================================================================*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + static int32_t lTCPIncrementTxPosition( int32_t lPosition, int32_t lMax, int32_t lCount ) + { + /* +TCP stores data in circular buffers. Calculate the next position to + store. */ + lPosition += lCount; + if( lPosition >= lMax ) + { + lPosition -= lMax; + } + + return lPosition; + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax ) + { + int32_t lBytesLeft = ( int32_t ) ulLength, lToWrite; + int32_t lDone = 0; + TCPSegment_t *pxSegment = pxWindow->pxHeadSegment; + + /* Puts a message in the Tx-window (after buffer size has been + verified). */ + if( pxSegment != NULL ) + { + if( pxSegment->lDataLength < pxSegment->lMaxLength ) + { + if( ( pxSegment->u.bits.bOutstanding == pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength != 0 ) ) + { + /* Adding data to a segment that was already in the TX queue. It + will be filled-up to a maximum of MSS (maximum segment size). */ + lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength - pxSegment->lDataLength ); + + pxSegment->lDataLength += lToWrite; + + if( pxSegment->lDataLength >= pxSegment->lMaxLength ) + { + /* This segment is full, don't add more bytes. */ + pxWindow->pxHeadSegment = NULL; + } + + lBytesLeft -= lToWrite; + + /* ulNextTxSequenceNumber is the sequence number of the next byte to + be stored for transmission. */ + pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite; + + /* Increased the return value. */ + lDone += lToWrite; + + /* Some detailed logging, for those who're interested. */ + if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) ) + { + FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Add %4lu bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n", + ulLength, + pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber, + pxSegment->lDataLength, + pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber, + pxSegment->lStreamPos ) ); + FreeRTOS_flush_logging( ); + } + + /* Calculate the next position in the circular data buffer, knowing + its maximum length 'lMax'. */ + lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite ); + } + } + } + + while( lBytesLeft > 0 ) + { + /* The current transmission segment is full, create new segments as + needed. */ + pxSegment = xTCPWindowTxNew( pxWindow, pxWindow->ulNextTxSequenceNumber, pxWindow->usMSS ); + + if( pxSegment != NULL ) + { + /* Store as many as needed, but no more than the maximum + (MSS). */ + lToWrite = FreeRTOS_min_int32( lBytesLeft, pxSegment->lMaxLength ); + + pxSegment->lDataLength = lToWrite; + pxSegment->lStreamPos = lPosition; + lBytesLeft -= lToWrite; + lPosition = lTCPIncrementTxPosition( lPosition, lMax, lToWrite ); + pxWindow->ulNextTxSequenceNumber += ( uint32_t ) lToWrite; + lDone += lToWrite; + + /* Link this segment in the Tx-Queue. */ + vListInsertFifo( &( pxWindow->xTxQueue ), &( pxSegment->xQueueItem ) ); + + /* Let 'pxHeadSegment' point to this segment if there is still + space. */ + if( pxSegment->lDataLength < pxSegment->lMaxLength ) + { + pxWindow->pxHeadSegment = pxSegment; + } + else + { + pxWindow->pxHeadSegment = NULL; + } + + if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) + { + if( ( xTCPWindowLoggingLevel >= 3 ) || + ( ( xTCPWindowLoggingLevel >= 2 ) && ( pxWindow->pxHeadSegment != NULL ) ) ) + { + FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: New %4ld bytes for seqNr %lu len %4lu (nxt %lu) pos %lu\n", + ulLength, + pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber, + pxSegment->lDataLength, + pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber, + pxSegment->lStreamPos ) ); + FreeRTOS_flush_logging( ); + } + } + } + else + { + /* A sever situation: running out of segments for transmission. + No more data can be sent at the moment. */ + if( lDone != 0 ) + { + FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: Sorry all buffers full (cancel %ld bytes)\n", lBytesLeft ) ); + } + break; + } + } + + return lDone; + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow ) + { + return listLIST_IS_EMPTY( ( &pxWindow->xTxSegments) ); + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize ) + { + uint32_t ulTxOutstanding; + BaseType_t xHasSpace; + TCPSegment_t *pxSegment; + + /* This function will look if there is new transmission data. It will + return true if there is data to be sent. */ + + pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) ); + + if( pxSegment == NULL ) + { + xHasSpace = pdFALSE; + } + else + { + /* How much data is outstanding, i.e. how much data has been sent + but not yet acknowledged ? */ + if( pxWindow->tx.ulHighestSequenceNumber >= pxWindow->tx.ulCurrentSequenceNumber ) + { + ulTxOutstanding = pxWindow->tx.ulHighestSequenceNumber - pxWindow->tx.ulCurrentSequenceNumber; + } + else + { + ulTxOutstanding = 0UL; + } + + /* Subtract this from the peer's space. */ + ulWindowSize -= FreeRTOS_min_uint32( ulWindowSize, ulTxOutstanding ); + + /* See if the next segment may be sent. */ + if( ulWindowSize >= ( uint32_t ) pxSegment->lDataLength ) + { + xHasSpace = pdTRUE; + } + else + { + xHasSpace = pdFALSE; + } + + /* If 'xHasSpace', it looks like the peer has at least space for 1 + more new segment of size MSS. xSize.ulTxWindowLength is the self-imposed + limitation of the transmission window (in case of many resends it + may be decreased). */ + if( ( ulTxOutstanding != 0UL ) && ( pxWindow->xSize.ulTxWindowLength < ulTxOutstanding + ( ( uint32_t ) pxSegment->lDataLength ) ) ) + { + xHasSpace = pdFALSE; + } + } + + return xHasSpace; + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay ) + { + TCPSegment_t *pxSegment; + BaseType_t xReturn; + TickType_t ulAge, ulMaxAge; + + *pulDelay = 0u; + + if( listLIST_IS_EMPTY( &pxWindow->xPriorityQueue ) == pdFALSE ) + { + /* No need to look at retransmissions or new transmission as long as + there are priority segments. *pulDelay equals zero, meaning it must + be sent out immediately. */ + xReturn = pdTRUE; + } + else + { + pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) ); + + if( pxSegment != NULL ) + { + /* There is an outstanding segment, see if it is time to resend + it. */ + ulAge = ulTimerGetAge( &pxSegment->xTransmitTimer ); + + /* After a packet has been sent for the first time, it will wait + '1 * lSRTT' ms for an ACK. A second time it will wait '2 * lSRTT' ms, + each time doubling the time-out */ + ulMaxAge = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT ); + + if( ulMaxAge > ulAge ) + { + /* A segment must be sent after this amount of msecs */ + *pulDelay = ulMaxAge - ulAge; + } + + xReturn = pdTRUE; + } + else + { + /* No priority segment, no outstanding data, see if there is new + transmission data. */ + pxSegment = xTCPWindowPeekHead( &pxWindow->xTxQueue ); + + /* See if it fits in the peer's reception window. */ + if( pxSegment == NULL ) + { + xReturn = pdFALSE; + } + else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE ) + { + /* Too many outstanding messages. */ + xReturn = pdFALSE; + } + else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) ) + { + /* 'bSendFullSize' is a special optimisation. If true, the + driver will only sent completely filled packets (of MSS + bytes). */ + xReturn = pdFALSE; + } + else + { + xReturn = pdTRUE; + } + } + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition ) + { + TCPSegment_t *pxSegment; + uint32_t ulMaxTime; + uint32_t ulReturn = ~0UL; + + + /* Fetches data to be sent-out now. + + Priority messages: segments with a resend need no check current sliding + window size. */ + pxSegment = xTCPWindowGetHead( &( pxWindow->xPriorityQueue ) ); + pxWindow->ulOurSequenceNumber = pxWindow->tx.ulHighestSequenceNumber; + + if( pxSegment == NULL ) + { + /* Waiting messages: outstanding messages with a running timer + neither check peer's reception window size because these packets + have been sent earlier. */ + pxSegment = xTCPWindowPeekHead( &( pxWindow->xWaitQueue ) ); + + if( pxSegment != NULL ) + { + /* Do check the timing. */ + ulMaxTime = ( 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT ); + + if( ulTimerGetAge( &pxSegment->xTransmitTimer ) > ulMaxTime ) + { + /* A normal (non-fast) retransmission. Move it from the + head of the waiting queue. */ + pxSegment = xTCPWindowGetHead( &( pxWindow->xWaitQueue ) ); + pxSegment->u.bits.ucDupAckCount = pdFALSE_UNSIGNED; + + /* Some detailed logging. */ + if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != 0 ) ) + { + FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: WaitQueue %ld bytes for sequence number %lu (%lX)\n", + pxWindow->usPeerPortNumber, + pxWindow->usOurPortNumber, + pxSegment->lDataLength, + pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber, + pxSegment->ulSequenceNumber ) ); + FreeRTOS_flush_logging( ); + } + } + else + { + pxSegment = NULL; + } + } + + if( pxSegment == NULL ) + { + /* New messages: sent-out for the first time. Check current + sliding window size of peer. */ + pxSegment = xTCPWindowPeekHead( &( pxWindow->xTxQueue ) ); + + if( pxSegment == NULL ) + { + /* No segments queued. */ + ulReturn = 0UL; + } + else if( ( pxWindow->u.bits.bSendFullSize != pdFALSE_UNSIGNED ) && ( pxSegment->lDataLength < pxSegment->lMaxLength ) ) + { + /* A segment has been queued but the driver waits until it + has a full size of MSS. */ + ulReturn = 0; + } + else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE ) + { + /* Peer has no more space at this moment. */ + ulReturn = 0; + } + else + { + /* Move it out of the Tx queue. */ + pxSegment = xTCPWindowGetHead( &( pxWindow->xTxQueue ) ); + + /* Don't let pxHeadSegment point to this segment any more, + so no more data will be added. */ + if( pxWindow->pxHeadSegment == pxSegment ) + { + pxWindow->pxHeadSegment = NULL; + } + + /* pxWindow->tx.highest registers the highest sequence + number in our transmission window. */ + pxWindow->tx.ulHighestSequenceNumber = pxSegment->ulSequenceNumber + ( ( uint32_t ) pxSegment->lDataLength ); + + /* ...and more detailed logging */ + if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) ) + { + FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: XmitQueue %ld bytes for sequence number %lu (ws %lu)\n", + pxWindow->usPeerPortNumber, + pxWindow->usOurPortNumber, + pxSegment->lDataLength, + pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber, + ulWindowSize ) ); + FreeRTOS_flush_logging( ); + } + } + } + } + else + { + /* There is a priority segment. It doesn't need any checking for + space or timeouts. */ + if( xTCPWindowLoggingLevel != 0 ) + { + FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u,%u]: PrioQueue %ld bytes for sequence number %lu (ws %lu)\n", + pxWindow->usPeerPortNumber, + pxWindow->usOurPortNumber, + pxSegment->lDataLength, + pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber, + ulWindowSize ) ); + FreeRTOS_flush_logging( ); + } + } + + /* See if it has already been determined to return 0. */ + if( ulReturn != 0UL ) + { + configASSERT( listLIST_ITEM_CONTAINER( &(pxSegment->xQueueItem ) ) == NULL ); + + /* Now that the segment will be transmitted, add it to the tail of + the waiting queue. */ + vListInsertFifo( &pxWindow->xWaitQueue, &pxSegment->xQueueItem ); + + /* And mark it as outstanding. */ + pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED; + + /* Administer the transmit count, needed for fast + retransmissions. */ + ( pxSegment->u.bits.ucTransmitCount )++; + + /* If there have been several retransmissions (4), decrease the + size of the transmission window to at most 2 times MSS. */ + if( pxSegment->u.bits.ucTransmitCount == MAX_TRANSMIT_COUNT_USING_LARGE_WINDOW ) + { + if( pxWindow->xSize.ulTxWindowLength > ( 2U * pxWindow->usMSS ) ) + { + FreeRTOS_debug_printf( ( "ulTCPWindowTxGet[%u - %d]: Change Tx window: %lu -> %u\n", + pxWindow->usPeerPortNumber, pxWindow->usOurPortNumber, + pxWindow->xSize.ulTxWindowLength, 2 * pxWindow->usMSS ) ); + pxWindow->xSize.ulTxWindowLength = ( 2UL * pxWindow->usMSS ); + } + } + + /* Clear the transmit timer. */ + vTCPTimerSet( &( pxSegment->xTransmitTimer ) ); + + pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber; + + /* Inform the caller where to find the data within the queue. */ + *plPosition = pxSegment->lStreamPos; + + /* And return the length of the data segment */ + ulReturn = ( uint32_t ) pxSegment->lDataLength; + } + + return ulReturn; + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + static uint32_t prvTCPWindowTxCheckAck( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast ) + { + uint32_t ulBytesConfirmed = 0u; + uint32_t ulSequenceNumber = ulFirst, ulDataLength; + const ListItem_t *pxIterator; + const MiniListItem_t *pxEnd = ( const MiniListItem_t* )listGET_END_MARKER( &pxWindow->xTxSegments ); + BaseType_t xDoUnlink; + TCPSegment_t *pxSegment; + /* An acknowledgement or a selective ACK (SACK) was received. See if some outstanding data + may be removed from the transmission queue(s). + All TX segments for which + ( ( ulSequenceNumber >= ulFirst ) && ( ulSequenceNumber < ulLast ) in a + contiguous block. Note that the segments are stored in xTxSegments in a + strict sequential order. */ + + /* SRTT[i] = (1-a) * SRTT[i-1] + a * RTT + + 0 < a < 1; usually a = 1/8 + + RTO = 2 * SRTT + + where: + RTT is Round Trip Time + SRTT is Smoothed RTT + RTO is Retransmit timeout + + A Smoothed RTT will increase quickly, but it is conservative when + becoming smaller. */ + + for( + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd ); + ( pxIterator != ( const ListItem_t * ) pxEnd ) && ( xSequenceLessThan( ulSequenceNumber, ulLast ) != 0 ); + ) + { + xDoUnlink = pdFALSE; + pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + + /* Move to the next item because the current item might get + removed. */ + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ); + + /* Continue if this segment does not fall within the ACK'd range. */ + if( xSequenceGreaterThan( ulSequenceNumber, pxSegment->ulSequenceNumber ) != pdFALSE ) + { + continue; + } + + /* Is it ready? */ + if( ulSequenceNumber != pxSegment->ulSequenceNumber ) + { + break; + } + + ulDataLength = ( uint32_t ) pxSegment->lDataLength; + + if( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED ) + { + if( xSequenceGreaterThan( pxSegment->ulSequenceNumber + ( uint32_t )ulDataLength, ulLast ) != pdFALSE ) + { + /* What happens? Only part of this segment was accepted, + probably due to WND limits + + AAAAAAA BBBBBBB << acked + aaaaaaa aaaa << sent */ + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + uint32_t ulFirstSeq = pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber; + FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck[%u.%u]: %lu - %lu Partial sequence number %lu - %lu\n", + pxWindow->usPeerPortNumber, + pxWindow->usOurPortNumber, + ulFirstSeq - pxWindow->tx.ulFirstSequenceNumber, + ulLast - pxWindow->tx.ulFirstSequenceNumber, + ulFirstSeq, ulFirstSeq + ulDataLength ) ); + } + #endif /* ipconfigHAS_DEBUG_PRINTF */ + break; + } + + /* This segment is fully ACK'd, set the flag. */ + pxSegment->u.bits.bAcked = pdTRUE_UNSIGNED; + + /* Calculate the RTT only if the segment was sent-out for the + first time and if this is the last ACK'd segment in a range. */ + if( ( pxSegment->u.bits.ucTransmitCount == 1 ) && ( ( pxSegment->ulSequenceNumber + ulDataLength ) == ulLast ) ) + { + int32_t mS = ( int32_t ) ulTimerGetAge( &( pxSegment->xTransmitTimer ) ); + + if( pxWindow->lSRTT >= mS ) + { + /* RTT becomes smaller: adapt slowly. */ + pxWindow->lSRTT = ( ( winSRTT_DECREMENT_NEW * mS ) + ( winSRTT_DECREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_DECREMENT_NEW + winSRTT_DECREMENT_CURRENT ); + } + else + { + /* RTT becomes larger: adapt quicker */ + pxWindow->lSRTT = ( ( winSRTT_INCREMENT_NEW * mS ) + ( winSRTT_INCREMENT_CURRENT * pxWindow->lSRTT ) ) / ( winSRTT_INCREMENT_NEW + winSRTT_INCREMENT_CURRENT ); + } + + /* Cap to the minimum of 50ms. */ + if( pxWindow->lSRTT < winSRTT_CAP_mS ) + { + pxWindow->lSRTT = winSRTT_CAP_mS; + } + } + + /* Unlink it from the 3 queues, but do not destroy it (yet). */ + xDoUnlink = pdTRUE; + } + + /* pxSegment->u.bits.bAcked is now true. Is it located at the left + side of the transmission queue? If so, it may be freed. */ + if( ulSequenceNumber == pxWindow->tx.ulCurrentSequenceNumber ) + { + if( ( xTCPWindowLoggingLevel >= 2 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) ) + { + FreeRTOS_debug_printf( ( "prvTCPWindowTxCheckAck: %lu - %lu Ready sequence number %lu\n", + ulFirst - pxWindow->tx.ulFirstSequenceNumber, + ulLast - pxWindow->tx.ulFirstSequenceNumber, + pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) ); + } + + /* Increase the left-hand value of the transmission window. */ + pxWindow->tx.ulCurrentSequenceNumber += ulDataLength; + + /* This function will return the number of bytes that the tail + of txStream may be advanced. */ + ulBytesConfirmed += ulDataLength; + + /* All segments below tx.ulCurrentSequenceNumber may be freed. */ + vTCPWindowFree( pxSegment ); + + /* No need to unlink it any more. */ + xDoUnlink = pdFALSE; + } + + if( ( xDoUnlink != pdFALSE ) && ( listLIST_ITEM_CONTAINER( &( pxSegment->xQueueItem ) ) != NULL ) ) + { + /* Remove item from its queues. */ + uxListRemove( &pxSegment->xQueueItem ); + } + + ulSequenceNumber += ulDataLength; + } + + return ulBytesConfirmed; + } +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + static uint32_t prvTCPWindowFastRetransmit( TCPWindow_t *pxWindow, uint32_t ulFirst ) + { + const ListItem_t *pxIterator; + const MiniListItem_t* pxEnd; + TCPSegment_t *pxSegment; + uint32_t ulCount = 0UL; + + /* A higher Tx block has been acknowledged. Now iterate through the + xWaitQueue to find a possible condition for a FAST retransmission. */ + + pxEnd = ( const MiniListItem_t* ) listGET_END_MARKER( &( pxWindow->xWaitQueue ) ); + + for( pxIterator = ( const ListItem_t * ) listGET_NEXT( pxEnd ); + pxIterator != ( const ListItem_t * ) pxEnd; ) + { + /* Get the owner, which is a TCP segment. */ + pxSegment = ( TCPSegment_t * ) listGET_LIST_ITEM_OWNER( pxIterator ); + + /* Hop to the next item before the current gets unlinked. */ + pxIterator = ( const ListItem_t * ) listGET_NEXT( pxIterator ); + + /* Fast retransmission: + When 3 packets with a higher sequence number have been acknowledged + by the peer, it is very unlikely a current packet will ever arrive. + It will be retransmitted far before the RTO. */ + if( ( pxSegment->u.bits.bAcked == pdFALSE_UNSIGNED ) && + ( xSequenceLessThan( pxSegment->ulSequenceNumber, ulFirst ) != pdFALSE ) && + ( ++( pxSegment->u.bits.ucDupAckCount ) == DUPLICATE_ACKS_BEFORE_FAST_RETRANSMIT ) ) + { + pxSegment->u.bits.ucTransmitCount = pdFALSE_UNSIGNED; + + /* Not clearing 'ucDupAckCount' yet as more SACK's might come in + which might lead to a second fast rexmit. */ + if( ( xTCPWindowLoggingLevel >= 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) ) + { + FreeRTOS_debug_printf( ( "prvTCPWindowFastRetransmit: Requeue sequence number %lu < %lu\n", + pxSegment->ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber, + ulFirst - pxWindow->tx.ulFirstSequenceNumber ) ); + FreeRTOS_flush_logging( ); + } + + /* Remove it from xWaitQueue. */ + uxListRemove( &pxSegment->xQueueItem ); + + /* Add this segment to the priority queue so it gets + retransmitted immediately. */ + vListInsertFifo( &( pxWindow->xPriorityQueue ), &( pxSegment->xQueueItem ) ); + ulCount++; + } + } + + return ulCount; + } +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber ) + { + uint32_t ulFirstSequence, ulReturn; + + /* Receive a normal ACK. */ + + ulFirstSequence = pxWindow->tx.ulCurrentSequenceNumber; + + if( xSequenceLessThanOrEqual( ulSequenceNumber, ulFirstSequence ) != pdFALSE ) + { + ulReturn = 0UL; + } + else + { + ulReturn = prvTCPWindowTxCheckAck( pxWindow, ulFirstSequence, ulSequenceNumber ); + } + + return ulReturn; + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 1 ) + + uint32_t ulTCPWindowTxSack( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast ) + { + uint32_t ulAckCount = 0UL; + uint32_t ulCurrentSequenceNumber = pxWindow->tx.ulCurrentSequenceNumber; + + /* Receive a SACK option. */ + ulAckCount = prvTCPWindowTxCheckAck( pxWindow, ulFirst, ulLast ); + prvTCPWindowFastRetransmit( pxWindow, ulFirst ); + + if( ( xTCPWindowLoggingLevel >= 1 ) && ( xSequenceGreaterThan( ulFirst, ulCurrentSequenceNumber ) != pdFALSE ) ) + { + FreeRTOS_debug_printf( ( "ulTCPWindowTxSack[%u,%u]: from %lu to %lu (ack = %lu)\n", + pxWindow->usPeerPortNumber, + pxWindow->usOurPortNumber, + ulFirst - pxWindow->tx.ulFirstSequenceNumber, + ulLast - pxWindow->tx.ulFirstSequenceNumber, + pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber ) ); + FreeRTOS_flush_logging( ); + } + + return ulAckCount; + } + +#endif /* ipconfigUSE_TCP_WIN == 1 */ +/*-----------------------------------------------------------*/ + +/* +##### # ##### #### ###### +# # # # # # # # # # # + # # # # # # + # ### ##### # # # # # # + # # # # # # # # ##### + # # # # # # #### # # # + # # # # # # # # # # + # # # # #### # # # # + #### ##### # # # #### #### #### + # + ### +*/ +#if( ipconfigUSE_TCP_WIN == 0 ) + + int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace ) + { + int32_t iReturn; + + /* Data was received at 'ulSequenceNumber'. See if it was expected + and if there is enough space to store the new data. */ + if( ( pxWindow->rx.ulCurrentSequenceNumber != ulSequenceNumber ) || ( ulSpace < ulLength ) ) + { + iReturn = -1; + } + else + { + pxWindow->rx.ulCurrentSequenceNumber += ( uint32_t ) ulLength; + iReturn = 0; + } + + return iReturn; + } + +#endif /* ipconfigUSE_TCP_WIN == 0 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 0 ) + + int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax ) + { + TCPSegment_t *pxSegment = &( pxWindow->xTxSegment ); + int32_t lResult; + + /* Data is being scheduled for transmission. */ + + /* lMax would indicate the size of the txStream. */ + ( void ) lMax; + /* This is tiny TCP: there is only 1 segment for outgoing data. + As long as 'lDataLength' is unequal to zero, the segment is still occupied. */ + if( pxSegment->lDataLength > 0 ) + { + lResult = 0L; + } + else + { + if( ulLength > ( uint32_t ) pxSegment->lMaxLength ) + { + if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) ) + { + FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: can only store %ld / %ld bytes\n", ulLength, pxSegment->lMaxLength ) ); + } + + ulLength = ( uint32_t ) pxSegment->lMaxLength; + } + + if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) ) + { + FreeRTOS_debug_printf( ( "lTCPWindowTxAdd: SeqNr %ld (%ld) Len %ld\n", + pxWindow->ulNextTxSequenceNumber - pxWindow->tx.ulFirstSequenceNumber, + pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber, + ulLength ) ); + } + + /* The sequence number of the first byte in this packet. */ + pxSegment->ulSequenceNumber = pxWindow->ulNextTxSequenceNumber; + pxSegment->lDataLength = ( int32_t ) ulLength; + pxSegment->lStreamPos = lPosition; + pxSegment->u.ulFlags = 0UL; + vTCPTimerSet( &( pxSegment->xTransmitTimer ) ); + + /* Increase the sequence number of the next data to be stored for + transmission. */ + pxWindow->ulNextTxSequenceNumber += ulLength; + lResult = ( int32_t )ulLength; + } + + return lResult; + } + +#endif /* ipconfigUSE_TCP_WIN == 0 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 0 ) + + uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition ) + { + TCPSegment_t *pxSegment = &( pxWindow->xTxSegment ); + uint32_t ulLength = ( uint32_t ) pxSegment->lDataLength; + uint32_t ulMaxTime; + + if( ulLength != 0UL ) + { + /* _HT_ Still under investigation */ + ( void ) ulWindowSize; + + if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED ) + { + /* As 'ucTransmitCount' has a minimum of 1, take 2 * RTT */ + ulMaxTime = ( ( uint32_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT ); + + if( ulTimerGetAge( &( pxSegment->xTransmitTimer ) ) < ulMaxTime ) + { + ulLength = 0ul; + } + } + + if( ulLength != 0ul ) + { + pxSegment->u.bits.bOutstanding = pdTRUE_UNSIGNED; + pxSegment->u.bits.ucTransmitCount++; + vTCPTimerSet (&pxSegment->xTransmitTimer); + pxWindow->ulOurSequenceNumber = pxSegment->ulSequenceNumber; + *plPosition = pxSegment->lStreamPos; + } + } + + return ulLength; + } + +#endif /* ipconfigUSE_TCP_WIN == 0 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 0 ) + + BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow ) + { + BaseType_t xReturn; + + /* Has the outstanding data been sent because user wants to shutdown? */ + if( pxWindow->xTxSegment.lDataLength == 0 ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP_WIN == 0 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 0 ) + + static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize ); + static BaseType_t prvTCPWindowTxHasSpace( TCPWindow_t *pxWindow, uint32_t ulWindowSize ) + { + BaseType_t xReturn; + + if( ulWindowSize >= pxWindow->usMSSInit ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP_WIN == 0 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 0 ) + + BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay ) + { + TCPSegment_t *pxSegment = &( pxWindow->xTxSegment ); + BaseType_t xReturn; + TickType_t ulAge, ulMaxAge; + + /* Check data to be sent. */ + *pulDelay = ( TickType_t ) 0; + if( pxSegment->lDataLength == 0 ) + { + /* Got nothing to send right now. */ + xReturn = pdFALSE; + } + else + { + if( pxSegment->u.bits.bOutstanding != pdFALSE_UNSIGNED ) + { + ulAge = ulTimerGetAge ( &pxSegment->xTransmitTimer ); + ulMaxAge = ( ( TickType_t ) 1u << pxSegment->u.bits.ucTransmitCount ) * ( ( uint32_t ) pxWindow->lSRTT ); + + if( ulMaxAge > ulAge ) + { + *pulDelay = ulMaxAge - ulAge; + } + + xReturn = pdTRUE; + } + else if( prvTCPWindowTxHasSpace( pxWindow, ulWindowSize ) == pdFALSE ) + { + /* Too many outstanding messages. */ + xReturn = pdFALSE; + } + else + { + xReturn = pdTRUE; + } + } + + return xReturn; + } + +#endif /* ipconfigUSE_TCP_WIN == 0 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 0 ) + + uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber ) + { + TCPSegment_t *pxSegment = &( pxWindow->xTxSegment ); + uint32_t ulDataLength = ( uint32_t ) pxSegment->lDataLength; + + /* Receive a normal ACK */ + + if( ulDataLength != 0ul ) + { + if( ulSequenceNumber < ( pxWindow->tx.ulCurrentSequenceNumber + ulDataLength ) ) + { + if( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) + { + FreeRTOS_debug_printf( ( "win_tx_ack: acked %ld expc %ld len %ld\n", + ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber, + pxWindow->tx.ulCurrentSequenceNumber - pxWindow->tx.ulFirstSequenceNumber, + ulDataLength ) ); + } + + /* Nothing to send right now. */ + ulDataLength = 0ul; + } + else + { + pxWindow->tx.ulCurrentSequenceNumber += ulDataLength; + + if( ( xTCPWindowLoggingLevel != 0 ) && ( ipconfigTCP_MAY_LOG_PORT( pxWindow->usOurPortNumber ) != pdFALSE ) ) + { + FreeRTOS_debug_printf( ( "win_tx_ack: acked seqnr %ld len %ld\n", + ulSequenceNumber - pxWindow->tx.ulFirstSequenceNumber, + ulDataLength ) ); + } + + pxSegment->lDataLength = 0; + } + } + + return ulDataLength; + } + +#endif /* ipconfigUSE_TCP_WIN == 0 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 0 ) + + BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow ) + { + /* Return true if 'ulCurrentSequenceNumber >= ulHighestSequenceNumber' + 'ulCurrentSequenceNumber' is the highest sequence number stored, + 'ulHighestSequenceNumber' is the highest sequence number seen. */ + return xSequenceGreaterThanOrEqual( pxWindow->rx.ulCurrentSequenceNumber, pxWindow->rx.ulHighestSequenceNumber ); + } + +#endif /* ipconfigUSE_TCP_WIN == 0 */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_TCP_WIN == 0 ) + + /* Destroy a window (always returns NULL) */ + void vTCPWindowDestroy( TCPWindow_t *pxWindow ) + { + /* As in tiny TCP there are no shared segments descriptors, there is + nothing to release. */ + ( void ) pxWindow; + } + +#endif /* ipconfigUSE_TCP_WIN == 0 */ +/*-----------------------------------------------------------*/ + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c new file mode 100644 index 000000000..09733a020 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c @@ -0,0 +1,382 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* Standard includes. */ +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_ARP.h" +#include "FreeRTOS_DHCP.h" +#include "NetworkInterface.h" +#include "NetworkBufferManagement.h" + +#if( ipconfigUSE_DNS == 1 ) + #include "FreeRTOS_DNS.h" +#endif + +/* The expected IP version and header length coded into the IP header itself. */ +#define ipIP_VERSION_AND_HEADER_LENGTH_BYTE ( ( uint8_t ) 0x45 ) + +/* Part of the Ethernet and IP headers are always constant when sending an IPv4 +UDP packet. This array defines the constant parts, allowing this part of the +packet to be filled in using a simple memcpy() instead of individual writes. */ +UDPPacketHeader_t xDefaultPartUDPPacketHeader = +{ + /* .ucBytes : */ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source MAC address. */ + 0x08, 0x00, /* Ethernet frame type. */ + ipIP_VERSION_AND_HEADER_LENGTH_BYTE, /* ucVersionHeaderLength. */ + 0x00, /* ucDifferentiatedServicesCode. */ + 0x00, 0x00, /* usLength. */ + 0x00, 0x00, /* usIdentification. */ + 0x00, 0x00, /* usFragmentOffset. */ + ipconfigUDP_TIME_TO_LIVE, /* ucTimeToLive */ + ipPROTOCOL_UDP, /* ucProtocol. */ + 0x00, 0x00, /* usHeaderChecksum. */ + 0x00, 0x00, 0x00, 0x00 /* Source IP address. */ + } +}; +/*-----------------------------------------------------------*/ + +void vProcessGeneratedUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ +UDPPacket_t *pxUDPPacket; +IPHeader_t *pxIPHeader; +eARPLookupResult_t eReturned; +uint32_t ulIPAddress = pxNetworkBuffer->ulIPAddress; + + /* Map the UDP packet onto the start of the frame. */ + pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer; + + /* Determine the ARP cache status for the requested IP address. */ + eReturned = eARPGetCacheEntry( &( ulIPAddress ), &( pxUDPPacket->xEthernetHeader.xDestinationAddress ) ); + + if( eReturned != eCantSendPacket ) + { + if( eReturned == eARPCacheHit ) + { + #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) + uint8_t ucSocketOptions; + #endif + iptraceSENDING_UDP_PACKET( pxNetworkBuffer->ulIPAddress ); + + /* Create short cuts to the data within the packet. */ + pxIPHeader = &( pxUDPPacket->xIPHeader ); + + #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + /* Is it possible that the packet is not actually a UDP packet + after all, but an ICMP packet. */ + if( pxNetworkBuffer->usPort != ipPACKET_CONTAINS_ICMP_DATA ) + #endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + { + UDPHeader_t *pxUDPHeader; + + pxUDPHeader = &( pxUDPPacket->xUDPHeader ); + + pxUDPHeader->usDestinationPort = pxNetworkBuffer->usPort; + pxUDPHeader->usSourcePort = pxNetworkBuffer->usBoundPort; + pxUDPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) ); + pxUDPHeader->usLength = FreeRTOS_htons( pxUDPHeader->usLength ); + pxUDPHeader->usChecksum = 0u; + } + + /* memcpy() the constant parts of the header information into + the correct location within the packet. This fills in: + xEthernetHeader.xSourceAddress + xEthernetHeader.usFrameType + xIPHeader.ucVersionHeaderLength + xIPHeader.ucDifferentiatedServicesCode + xIPHeader.usLength + xIPHeader.usIdentification + xIPHeader.usFragmentOffset + xIPHeader.ucTimeToLive + xIPHeader.ucProtocol + and + xIPHeader.usHeaderChecksum + */ + /* Save options now, as they will be overwritten by memcpy */ + #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) + ucSocketOptions = pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ]; + #endif + /* + * Offset the memcpy by the size of a MAC address to start at the packet's + * Ethernet header 'source' MAC address; the preceding 'destination' should not be altered. + */ + char *pxUdpSrcAddrOffset = ( char *) pxUDPPacket + sizeof( MACAddress_t ); + memcpy( pxUdpSrcAddrOffset, xDefaultPartUDPPacketHeader.ucBytes, sizeof( xDefaultPartUDPPacketHeader ) ); + + #if ipconfigSUPPORT_OUTGOING_PINGS == 1 + if( pxNetworkBuffer->usPort == ipPACKET_CONTAINS_ICMP_DATA ) + { + pxIPHeader->ucProtocol = ipPROTOCOL_ICMP; + pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( IPHeader_t ) ); + } + else + #endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + { + pxIPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength + sizeof( IPHeader_t ) + sizeof( UDPHeader_t ) ); + } + + /* The total transmit size adds on the Ethernet header. */ + pxNetworkBuffer->xDataLength = pxIPHeader->usLength + sizeof( EthernetHeader_t ); + pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength ); + /* HT:endian: changed back to network endian */ + pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress; + + #if( ipconfigUSE_LLMNR == 1 ) + { + /* LLMNR messages are typically used on a LAN and they're + * not supposed to cross routers */ + if( pxNetworkBuffer->ulIPAddress == ipLLMNR_IP_ADDR ) + { + pxIPHeader->ucTimeToLive = 0x01; + } + } + #endif + + #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) + { + pxIPHeader->usHeaderChecksum = 0u; + pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER ); + pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); + + if( ( ucSocketOptions & ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT ) != 0u ) + { + usGenerateProtocolChecksum( (uint8_t*)pxUDPPacket, pxNetworkBuffer->xDataLength, pdTRUE ); + } + else + { + pxUDPPacket->xUDPHeader.usChecksum = 0u; + } + } + #endif + } + else if( eReturned == eARPCacheMiss ) + { + /* Add an entry to the ARP table with a null hardware address. + This allows the ARP timer to know that an ARP reply is + outstanding, and perform retransmissions if necessary. */ + vARPRefreshCacheEntry( NULL, ulIPAddress ); + + /* Generate an ARP for the required IP address. */ + iptracePACKET_DROPPED_TO_GENERATE_ARP( pxNetworkBuffer->ulIPAddress ); + pxNetworkBuffer->ulIPAddress = ulIPAddress; + vARPGenerateRequestPacket( pxNetworkBuffer ); + } + else + { + /* The lookup indicated that an ARP request has already been + sent out for the queried IP address. */ + eReturned = eCantSendPacket; + } + } + + if( eReturned != eCantSendPacket ) + { + /* The network driver is responsible for freeing the network buffer + after the packet has been sent. */ + + #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES ) + { + if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES ) + { + BaseType_t xIndex; + + for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ ) + { + pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u; + } + pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; + } + } + #endif + + xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE ); + } + else + { + /* The packet can't be sent (DHCP not completed?). Just drop the + packet. */ + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xProcessReceivedUDPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort ) +{ +BaseType_t xReturn = pdPASS; +FreeRTOS_Socket_t *pxSocket; +UDPPacket_t *pxUDPPacket; + + configASSERT( pxNetworkBuffer ); + configASSERT( pxNetworkBuffer->pucEthernetBuffer ); + + pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer; + + /* Caller must check for minimum packet size. */ + pxSocket = pxUDPSocketLookup( usPort ); + + if( pxSocket ) + { + + /* When refreshing the ARP cache with received UDP packets we must be + careful; hundreds of broadcast messages may pass and if we're not + handling them, no use to fill the ARP cache with those IP addresses. */ + vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress ); + + #if( ipconfigUSE_CALLBACKS == 1 ) + { + /* Did the owner of this socket register a reception handler ? */ + if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleReceive ) ) + { + struct freertos_sockaddr xSourceAddress, destinationAddress; + void *pcData = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ); + FOnUDPReceive_t xHandler = ( FOnUDPReceive_t ) pxSocket->u.xUDP.pxHandleReceive; + xSourceAddress.sin_port = pxNetworkBuffer->usPort; + xSourceAddress.sin_addr = pxNetworkBuffer->ulIPAddress; + destinationAddress.sin_port = usPort; + destinationAddress.sin_addr = pxUDPPacket->xIPHeader.ulDestinationIPAddress; + + if( xHandler( ( Socket_t * ) pxSocket, ( void* ) pcData, ( size_t ) pxNetworkBuffer->xDataLength, + &xSourceAddress, &destinationAddress ) ) + { + xReturn = pdFAIL; /* FAIL means that we did not consume or release the buffer */ + } + } + } + #endif /* ipconfigUSE_CALLBACKS */ + + #if( ipconfigUDP_MAX_RX_PACKETS > 0 ) + { + if( xReturn == pdPASS ) + { + if ( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) >= pxSocket->u.xUDP.uxMaxPackets ) + { + FreeRTOS_debug_printf( ( "xProcessReceivedUDPPacket: buffer full %ld >= %ld port %u\n", + listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ), + pxSocket->u.xUDP.uxMaxPackets, pxSocket->usLocalPort ) ); + xReturn = pdFAIL; /* we did not consume or release the buffer */ + } + } + } + #endif + + if( xReturn == pdPASS ) + { + vTaskSuspendAll(); + { + if( xReturn == pdPASS ) + { + taskENTER_CRITICAL(); + { + /* Add the network packet to the list of packets to be + processed by the socket. */ + vListInsertEnd( &( pxSocket->u.xUDP.xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) ); + } + taskEXIT_CRITICAL(); + } + } + xTaskResumeAll(); + + /* Set the socket's receive event */ + if( pxSocket->xEventGroup != NULL ) + { + xEventGroupSetBits( pxSocket->xEventGroup, eSOCKET_RECEIVE ); + } + + #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + { + if( ( pxSocket->pxSocketSet != NULL ) && ( ( pxSocket->xSelectBits & eSELECT_READ ) != 0 ) ) + { + xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, eSELECT_READ ); + } + } + #endif + + #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 ) + { + if( pxSocket->pxUserSemaphore != NULL ) + { + xSemaphoreGive( pxSocket->pxUserSemaphore ); + } + } + #endif + + #if( ipconfigUSE_DHCP == 1 ) + { + if( xIsDHCPSocket( pxSocket ) ) + { + xSendEventToIPTask( eDHCPEvent ); + } + } + #endif + } + } + else + { + /* There is no socket listening to the target port, but still it might + be for this node. */ + + #if( ipconfigUSE_LLMNR == 1 ) + /* a LLMNR request, check for the destination port. */ + if( ( usPort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) || + ( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) ) + { + vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress ); + xReturn = ( BaseType_t )ulDNSHandlePacket( pxNetworkBuffer ); + } + else + #endif /* ipconfigUSE_LLMNR */ + + #if( ipconfigUSE_NBNS == 1 ) + /* a NetBIOS request, check for the destination port */ + if( ( usPort == FreeRTOS_ntohs( ipNBNS_PORT ) ) || + ( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipNBNS_PORT ) ) ) + { + vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress ); + xReturn = ( BaseType_t )ulNBNSHandlePacket( pxNetworkBuffer ); + } + else + #endif /* ipconfigUSE_NBNS */ + { + xReturn = pdFAIL; + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/History.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/History.txt new file mode 100644 index 000000000..07ad698a2 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/History.txt @@ -0,0 +1,191 @@ +Changes in V2.0.11 + + + Updates some drivers in the portable layer. + +Changes between 160919 and 180821 releases: + + + Multiple security improvements and fixes in packet parsing routines, DNS + caching, and TCP sequence number and ID generation. + + Disable NBNS and LLMNR by default. + + Add TCP hang protection by default. + + We thank Ori Karliner of Zimperium zLabs Team for reporting these issues. + + + Update FreeRTOS_gethostbyname() to allow an IP address to be passed in - + in which case it is just returned as a uint32_t. + + Introduce ipconfigSOCKET_HAS_USER_WAKE_CALLBACK to FreeRTOS_Sockets.c to + allow a user supposed callback function to be executed when socket events + occur in the same way that the socket semaphore is currently used. + + Update xNetworkBuffersInitialise() to ensure the semaphore created by the + function is not accessed until after the NULL check. + + Improve print messages output by the Win32 port layer version of + prvPrintAvailableNetworkInterfaces(). + +Changes between 160908 and 160919 releases: + + + Add a NULL check before attempting to close the DHCP socket. [Prior to + 160823 the IP task closed the DHCP socket by calling a public API function + - which checked for the socket being NULL. This was changed to call a + local private function, which did not have a NULL check, in place of the + public API function.] + + Various [internal only] naming changes to better comply with the FreeRTOS + naming conventions. + + Improvements to the Zynq network driver. DMA transmission buffers now use + a counting semaphore. When all TX-buffers are in-use, the IP-task will + block momentarily until a TX-buffer becomes available. + + Experimental implementation of the TCP window scaling protocol. The + scaling option will always be offered, at least with a factor 1. If the + TCP sliding window size becomes more than 64KB, the factor will increase + automatically. + + ipconfigETHERNET_MINIMUM_PACKET_BYTES is now applied for every protocol: + TCP, UDP, and ARP. + + Updated the Zynq project to use BufferAllocation_1.c rather than + BufferAllocation_2.c - which is a requirement with its current + configuration (due to the alignment requirements on the combined cache and + DMA configuration). + +Changes between 160823 and 160908 releases: + + + Use ipconfigZERO_COPY_TX_DRIVER as the xReleaseAfterSend() parameter where + prvTCPReturnPacket() is called in prvSendData() to prevent unnecessary + copying of data. + + Remove the use of the uxGetRxEventCount variable, which was used to give + priority to incoming messages, but could result in the IP task starving + application tasks of processing time. + +Changes between 160112 and 160823 releases + + NOTE: The 160908 release is a maintenance release for the 160112 single + interface labs release - not a release of the current development branch. + + + Various minor stability enhancements, including the ability to work with + configTICK_RATE_HZ set to less than 1KHz, closing DHCP sockets directly + rather than via FreeRTOS_closesocket(), and better handling of unknown + TCP packets before an IP address has been assigned. + + ipBUFFER_PADDING is now configurable through the ipconfigBUFFER_PADDING + constant to improve network buffer alignment handling capabilities (expert + users/driver writers only). + + Multiple improvements to the FTP server, including to how read only and + zero length files are handled. + + ipconfigFTP_HAS_USER_PROPERTIES_HOOK (to allow each user to have a + different root directory and access rights) and + ipconfigHTTP_HAS_HANDLE_REQUEST_HOOK (to handle AJAX style data) + introduced, although these are not yet fully tested and the constant names + are likely to change. + + Introduce ipconfigHAS_TX_CRC_OFFLOADING. + + ipconfigUSE_DHCP_HOOK is now called ipconfigUSE_DHCP_HOOK, and the name + of the callback function has also changed. See the web documentation for + details. + + ipconfigTCP_RX_BUF_LEN is now ipconfigTCP_RX_BUFFER_LENGTH, and + ipconfigTCP_TX_BUF_LEN is now ipconfigTCP_TX_BUFFER_LENGTH, which is + actually how they have always been documented. + + Added example TFTP server capable of receiving (not sending) files. + Intended for bootloader type functionality. + + Various variable name changes for consistency (mainly ensuring UDP, TCP, + DNS, etc. always use the same case letters, and type prefixes are correct). + + Various minor edits to improve types used by internal variables. + + Simplified mapping of standard library functions to their Visual Studio + equivalents. + + Improve robustness of network drivers. + + Introduce pxResizeNetworkBufferWithDescriptor(). + + Removed obsolete FreeRTOSIPConfig.h constants from + FreeRTOSIPConfigDefaults.h. + + Added additional asserts() - predominantly to catch incorrect structure + packing. + +Changes between 160112 and 160111 releases + + + Updated the STM32 network driver so checksums are calculated by the + hardware. + + Implemented a simple "quit" command in the TCP command console. + +Changes between 150825 and 160111 releases + + + New device support: Demo applications and example drivers are provided + for Atmel SAM4E and ST STM32F4 microcontrollers. + + Various updates to improve compliance with the FreeRTOS coding standard. + + Added a command console example that uses TCP/IP for input and output (the + pre-existing command console example uses UDP/IP). + + Updated the UDP logging example so it will send log messages to the local + UDP broadcast address if a specific IP address is not provided. This + simplifies configuration, but note not all switches and routers will pass + broadcast messages. + + Add TCP echo client and TCP echo server examples to the Zynq demo. + + Minor updates to the Zynq network driver. + + Update the Zynq project to use version 2015.4 of the Xilinx SDK. + + Introduce FreeRTOS_SignalSocket(), which can be used to interrupt a task + that is blocked while reading from a socket ( FreeRTOS_recv[from] ). + + Make use of FreeRTOS_SignalSocket() in the FTP and HTTP servers. + + Major updates to the NTP client, although this is not included in any of + the pre-configured demo applications yet. + + Added support for DHCP zero pad option. + + Added uxGetMinimumIPQueueSpace(), a function to monitor the minimum amount + of space on the message queue. + + Better handling of zero length files in the FTP server. + + Fixed a bug reported by Andrey Ivanov from swissEmbedded that affects + users of 'ipconfigZERO_COPY_TX_DRIVER'. + + +Changes between 150825 150825 (?) + + + Added xApplicationDHCPUserHook() so a user defined hook will be + called at certain points in the DHCP process if + ipconfigDHCP_USES_USER_HOOK is set to 1. + + Added FreeRTOS_get_tx_head() to improve TCP zero copy behaviour - for + expert use only. + + RST is no longer sent if only the ACK flag is set. + + Previously, an immediate ACK was only sent when buffer space was + exhausted. Now, to improve performance, it is possible to send an + immediate ACK earlier - dependent on the ipconfigTCP_ACK_EARLIER_PACKET + setting. + + LLMNR and NBNS requests can now be sent to locate other devices - + previously these protocols would only be replied to, not generated. + + Added Auto-IP functionality (still in test) in case DHCP fails. Dependent + on the ipconfigDHCP_FALL_BACK_LINK_LAYER_ADDRESS and + ipconfigARP_USE_CLASH_DETECTION settings. + + Added NTP code and demo. + + FTP can now STOR and RETR zero-length files. + + Added LLMNR demo to Win32 demo - so now the Win32 responds to + "ping RTOSDemo". + +Changes between 141019 and 150825 + + + Added FTP server, which uses the new FreeRTOS+FAT component. + + Added basic HTTP server, which uses the new FreeRTOS+FAT component. + + Multiple definitions that are now common with FreeRTOS+FAT have been moved + into FreeRTOS's ProjDefs.h header file, and so prefixed with 'pd'. + + Introduced ipconfigZERO_COPY_TX_DRIVER, which defines who is responsible + for freeing a buffer sent to to the MAC driver for transmission, and + facilitates the development of zero copy drivers. + + Introduced the FREERTOS_MSG_DONTWAIT flag. The flag can be used as a + simpler and faster alternative to using FreeRTOS_setsockopt() to set the + send or receive timeout to 0. + + A few functions that were previously all lower case are now mixed case, as + lower case function names are only used when they are equivalent to a + a Berkeley sockets API function of the same name. + + Introduced uxGetMinimumFreeNetworkBuffers() to return the minimum number + of network buffers that have ever existed since the application started + executing. + + Introduce ipconfigETHERNET_MINIMUM_PACKET_BYTES to allow the application + writer to set their own minimum buffer size should the hardware not be + capable of padding under-sized Ethernet frames. + + vNetworkBufferRelease() renamed vReleaseNetworkBuffer() - just for + consistency with the names of other functions in the same file. + + Grouped DHCP status data into a structure. + + DHCP is now tried both with and without the broadcast flag. + + Replaced occurrences of configASSERT_VOID() with configASSERT(). + + ipconfigDNS_USE_CALLBACKS introduced to allow FreeRTOS_gethostbyname() to + be used without blocking. + + Fix: LLMNR and NBNS behaviour when the reply is in a larger buffer than the + request, and BufferAllocation_2 was used. + + Introduced ipMAX_IP_TASK_SLEEP_TIME to allow the application writer to + override the default value of 10 seconds. + + Fix: Correct error in *pxUDPPayloadBuffer_to_NetworkBuffer(). + + FreeRTOS_recv() now recognises the FREERTOS_ZERO_COPY flag, which, when + set, the void *pvBuffer parameter is interpreted as void **pvBuffer. + + FreeRTOS_listen() now returns an error code. Previously it always + returned 0. + + Fix: Previously if a listening socket was reused, and a connection + failed, the TCP/IP stack closed the socket, now the socket is correctly + left unclosed as it is owned by the application. + + Various other formatting and minor fix alterations. \ No newline at end of file diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/LICENSE_INFORMATION.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/LICENSE_INFORMATION.txt new file mode 100644 index 000000000..24a8f88b1 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/LICENSE_INFORMATION.txt @@ -0,0 +1,19 @@ +FreeRTOS+TCP is released under the following MIT license. + +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +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. diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/ReadMe.url b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/ReadMe.url new file mode 100644 index 000000000..8a8017f6b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/ReadMe.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,2 +[InternetShortcut] +URL=http://www.freertos.org/tcp +IDList= diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h new file mode 100644 index 000000000..96f4f53fb --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOSIPConfigDefaults.h @@ -0,0 +1,568 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +#ifndef FREERTOS_DEFAULT_IP_CONFIG_H +#define FREERTOS_DEFAULT_IP_CONFIG_H + +/* The error numbers defined in this file will be moved to the core FreeRTOS +code in future versions of FreeRTOS - at which time the following header file +will be removed. */ +#include "FreeRTOS_errno_TCP.h" + +/* This file provides default values for configuration options that are missing +from the FreeRTOSIPConfig.h configuration header file. */ + + +/* Ensure defined configuration constants are using the most up to date naming. */ +#ifdef tcpconfigIP_TIME_TO_LIVE + #error now called: ipconfigTCP_TIME_TO_LIVE +#endif + +#ifdef updconfigIP_TIME_TO_LIVE + #error now called: ipconfigUDP_TIME_TO_LIVE +#endif + +#ifdef ipFILLER_SIZE + #error now called: ipconfigPACKET_FILLER_SIZE +#endif + +#ifdef dnsMAX_REQUEST_ATTEMPTS + #error now called: ipconfigDNS_REQUEST_ATTEMPTS +#endif + +#ifdef ipconfigUDP_TASK_PRIORITY + #error now called: ipconfigIP_TASK_PRIORITY +#endif + +#ifdef ipconfigUDP_TASK_STACK_SIZE_WORDS + #error now called: ipconfigIP_TASK_STACK_SIZE_WORDS +#endif + +#ifdef ipconfigDRIVER_INCLUDED_RX_IP_FILTERING + #error now called: ipconfigETHERNET_DRIVER_FILTERS_PACKETS +#endif + +#ifdef ipconfigMAX_SEND_BLOCK_TIME_TICKS + #error now called: ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS +#endif + +#ifdef ipconfigUSE_RECEIVE_CONNECT_CALLBACKS + #error now called: ipconfigUSE_CALLBACKS +#endif + +#ifdef ipconfigNUM_NETWORK_BUFFERS + #error now called: ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS +#endif + +#ifdef ipconfigTCP_HANG_PROT + #error now called: ipconfigTCP_HANG_PROTECTION +#endif + +#ifdef ipconfigTCP_HANG_PROT_TIME + #error now called: ipconfigTCP_HANG_PROTECTION_TIME +#endif + +#ifdef FreeRTOS_lprintf + #error now called: FreeRTOS_debug_printf +#endif + +#if ( ipconfigEVENT_QUEUE_LENGTH < ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) ) + #error The ipconfigEVENT_QUEUE_LENGTH parameter must be at least ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 +#endif + +#if ( ipconfigNETWORK_MTU < 46 ) + #error ipconfigNETWORK_MTU must be at least 46. +#endif + +#ifdef ipconfigBUFFER_ALLOC_FIXED_SIZE + #error ipconfigBUFFER_ALLOC_FIXED_SIZE was dropped and replaced by a const value, declared in BufferAllocation[12].c +#endif + +#ifdef ipconfigNIC_SEND_PASSES_DMA + #error now called: ipconfigZERO_COPY_TX_DRIVER +#endif + +#ifdef HAS_TX_CRC_OFFLOADING + /* _HT_ As these macro names have changed, throw an error + if they're still defined. */ + #error now called: ipconfigHAS_TX_CRC_OFFLOADING +#endif + +#ifdef HAS_RX_CRC_OFFLOADING + #error now called: ipconfigHAS_RX_CRC_OFFLOADING +#endif + +#ifdef ipconfigTCP_RX_BUF_LEN + #error ipconfigTCP_RX_BUF_LEN is now called ipconfigTCP_RX_BUFFER_LENGTH +#endif + +#ifdef ipconfigTCP_TX_BUF_LEN + #error ipconfigTCP_TX_BUF_LEN is now called ipconfigTCP_TX_BUFFER_LENGTH +#endif + +#ifdef ipconfigDHCP_USES_USER_HOOK + #error ipconfigDHCP_USES_USER_HOOK and its associated callback have been superceeded - see http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html#ipconfigUSE_DHCP_HOOK +#endif + +#ifndef ipconfigUSE_TCP + #define ipconfigUSE_TCP ( 1 ) +#endif + +#if ipconfigUSE_TCP + + /* Include support for TCP scaling windows */ + #ifndef ipconfigUSE_TCP_WIN + #define ipconfigUSE_TCP_WIN ( 1 ) + #endif + + #ifndef ipconfigTCP_WIN_SEG_COUNT + #define ipconfigTCP_WIN_SEG_COUNT ( 256 ) + #endif + + #ifndef ipconfigIGNORE_UNKNOWN_PACKETS + /* When non-zero, TCP will not send RST packets in reply to + TCP packets which are unknown, or out-of-order. */ + #define ipconfigIGNORE_UNKNOWN_PACKETS ( 0 ) + #endif +#endif + +/* + * For debuging/logging: check if the port number is used for telnet + * Some events will not be logged for telnet connections + * because it would produce logging about the transmission of the logging... + * This macro will only be used if FreeRTOS_debug_printf() is defined for logging + */ +#ifndef ipconfigTCP_MAY_LOG_PORT + #define ipconfigTCP_MAY_LOG_PORT(xPort) ( ( xPort ) != 23u ) +#endif + + +#ifndef ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME + #define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME portMAX_DELAY +#endif + +#ifndef ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME + #define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME portMAX_DELAY +#endif + +/* + * FreeRTOS debug logging routine (proposal) + * The macro will be called in the printf() style. Users can define + * their own logging routine as: + * + * #define FreeRTOS_debug_printf( MSG ) my_printf MSG + * + * The FreeRTOS_debug_printf() must be thread-safe but does not have to be + * interrupt-safe. + */ +#ifdef ipconfigHAS_DEBUG_PRINTF + #if( ipconfigHAS_DEBUG_PRINTF == 0 ) + #ifdef FreeRTOS_debug_printf + #error Do not define FreeRTOS_debug_print if ipconfigHAS_DEBUG_PRINTF is set to 0 + #endif /* ifdef FreeRTOS_debug_printf */ + #endif /* ( ipconfigHAS_DEBUG_PRINTF == 0 ) */ +#endif /* ifdef ipconfigHAS_DEBUG_PRINTF */ + +#ifndef FreeRTOS_debug_printf + #define FreeRTOS_debug_printf( MSG ) do{} while(0) + #define ipconfigHAS_DEBUG_PRINTF 0 +#endif + +/* + * FreeRTOS general logging routine (proposal) + * Used in some utility functions such as FreeRTOS_netstat() and FreeRTOS_PrintARPCache() + * + * #define FreeRTOS_printf( MSG ) my_printf MSG + * + * The FreeRTOS_printf() must be thread-safe but does not have to be interrupt-safe + */ +#ifdef ipconfigHAS_PRINTF + #if( ipconfigHAS_PRINTF == 0 ) + #ifdef FreeRTOS_printf + #error Do not define FreeRTOS_print if ipconfigHAS_PRINTF is set to 0 + #endif /* ifdef FreeRTOS_debug_printf */ + #endif /* ( ipconfigHAS_PRINTF == 0 ) */ +#endif /* ifdef ipconfigHAS_PRINTF */ + +#ifndef FreeRTOS_printf + #define FreeRTOS_printf( MSG ) do{} while(0) + #define ipconfigHAS_PRINTF 0 +#endif + +/* + * In cases where a lot of logging is produced, FreeRTOS_flush_logging( ) + * will be called to give the logging module a chance to flush the data + * An example of this is the netstat command, which produces many lines of logging + */ +#ifndef FreeRTOS_flush_logging + #define FreeRTOS_flush_logging( ) do{} while(0) +#endif + +/* Malloc functions. Within most applications of FreeRTOS, the couple + * pvPortMalloc()/vPortFree() will be used. + * If there is also SDRAM, the user may decide to use a different memory + * allocator: + * MallocLarge is used to allocate large TCP buffers (for Rx/Tx) + * MallocSocket is used to allocate the space for the sockets + */ +#ifndef pvPortMallocLarge + #define pvPortMallocLarge( x ) pvPortMalloc( x ) +#endif + +#ifndef vPortFreeLarge + #define vPortFreeLarge(ptr) vPortFree(ptr) +#endif + +#ifndef pvPortMallocSocket + #define pvPortMallocSocket( x ) pvPortMalloc( x ) +#endif + +#ifndef vPortFreeSocket + #define vPortFreeSocket(ptr) vPortFree(ptr) +#endif + +/* + * At several places within the library, random numbers are needed: + * - DHCP: For creating a DHCP transaction number + * - TCP: Set the Initial Sequence Number: this is the value of the first outgoing + * sequence number being used when connecting to a peer. + * Having a well randomised ISN is important to avoid spoofing + * - UDP/TCP: for setting the first port number to be used, in case a socket + * uses a 'random' or anonymous port number + */ +#ifndef ipconfigRAND32 + #define ipconfigRAND32() rand() +#endif +/* -------------------------------------------------------- + * End of: HT Added some macro defaults for the PLUS-UDP project + * -------------------------------------------------------- */ + +#ifndef ipconfigUSE_NETWORK_EVENT_HOOK + #define ipconfigUSE_NETWORK_EVENT_HOOK 0 +#endif + +#ifndef ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS + #define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( pdMS_TO_TICKS( 20 ) ) +#endif + +#ifndef ipconfigARP_CACHE_ENTRIES + #define ipconfigARP_CACHE_ENTRIES 10 +#endif + +#ifndef ipconfigMAX_ARP_RETRANSMISSIONS + #define ipconfigMAX_ARP_RETRANSMISSIONS ( 5u ) +#endif + +#ifndef ipconfigMAX_ARP_AGE + #define ipconfigMAX_ARP_AGE 150u +#endif + +#ifndef ipconfigUSE_ARP_REVERSED_LOOKUP + #define ipconfigUSE_ARP_REVERSED_LOOKUP 0 +#endif + +#ifndef ipconfigUSE_ARP_REMOVE_ENTRY + #define ipconfigUSE_ARP_REMOVE_ENTRY 0 +#endif + +#ifndef ipconfigINCLUDE_FULL_INET_ADDR + #define ipconfigINCLUDE_FULL_INET_ADDR 1 +#endif + +#ifndef ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + #define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 45 +#endif + +#ifndef ipconfigEVENT_QUEUE_LENGTH + #define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) +#endif + +#ifndef ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND + #define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1 +#endif + +#ifndef ipconfigUDP_TIME_TO_LIVE + #define ipconfigUDP_TIME_TO_LIVE 128 +#endif + +#ifndef ipconfigTCP_TIME_TO_LIVE + #define ipconfigTCP_TIME_TO_LIVE 128 +#endif + +#ifndef ipconfigUDP_MAX_RX_PACKETS + /* Make postive to define the maximum number of packets which will be buffered + * for each UDP socket. + * Can be overridden with the socket option FREERTOS_SO_UDP_MAX_RX_PACKETS + */ + #define ipconfigUDP_MAX_RX_PACKETS 0u +#endif + +#ifndef ipconfigUSE_DHCP + #define ipconfigUSE_DHCP 1 +#endif + +#ifndef ipconfigUSE_DHCP_HOOK + #define ipconfigUSE_DHCP_HOOK 0 +#endif + +#ifndef ipconfigDHCP_FALL_BACK_AUTO_IP + /* + * Only applicable when DHCP is in use: + * If no DHCP server responds, use "Auto-IP" : the + * device will allocate a random LinkLayer IP address. + */ + #define ipconfigDHCP_FALL_BACK_AUTO_IP ( 0 ) +#endif + +#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 ) + #define ipconfigARP_USE_CLASH_DETECTION 1 +#endif + +#ifndef ipconfigARP_USE_CLASH_DETECTION + #define ipconfigARP_USE_CLASH_DETECTION 0 +#endif + +#ifndef ipconfigNETWORK_MTU + #define ipconfigNETWORK_MTU 1500 +#endif + +#ifndef ipconfigTCP_MSS + #define ipconfigTCP_MSS ( ipconfigNETWORK_MTU - ipSIZE_OF_IPv4_HEADER - ipSIZE_OF_TCP_HEADER ) +#endif + +/* Each TCP socket has circular stream buffers for Rx and Tx, which + * have a fixed maximum size. + * The defaults for these size are defined here, although + * they can be overridden at runtime by using the setsockopt() call */ +#ifndef ipconfigTCP_RX_BUFFER_LENGTH + #define ipconfigTCP_RX_BUFFER_LENGTH ( 4u * ipconfigTCP_MSS ) /* defaults to 5840 bytes */ +#endif + +/* Define the size of Tx stream buffer for TCP sockets */ +#ifndef ipconfigTCP_TX_BUFFER_LENGTH +# define ipconfigTCP_TX_BUFFER_LENGTH ( 4u * ipconfigTCP_MSS ) /* defaults to 5840 bytes */ +#endif + +#ifndef ipconfigMAXIMUM_DISCOVER_TX_PERIOD + #ifdef _WINDOWS_ + #define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( pdMS_TO_TICKS( 999 ) ) + #else + #define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( pdMS_TO_TICKS( 30000 ) ) + #endif /* _WINDOWS_ */ +#endif /* ipconfigMAXIMUM_DISCOVER_TX_PERIOD */ + +#ifndef ipconfigUSE_DNS + #define ipconfigUSE_DNS 1 +#endif + +#ifndef ipconfigDNS_REQUEST_ATTEMPTS + #define ipconfigDNS_REQUEST_ATTEMPTS 5 +#endif + +#ifndef ipconfigUSE_DNS_CACHE + #define ipconfigUSE_DNS_CACHE 0 +#endif + +#if( ipconfigUSE_DNS_CACHE != 0 ) + #ifndef ipconfigDNS_CACHE_NAME_LENGTH + /* Per https://tools.ietf.org/html/rfc1035, 253 is the maximum string length + of a DNS name. The following default accounts for a null terminator. */ + #define ipconfigDNS_CACHE_NAME_LENGTH 254 + #endif + + #ifndef ipconfigDNS_CACHE_ENTRIES + #define ipconfigDNS_CACHE_ENTRIES 1 + #endif +#endif /* ipconfigUSE_DNS_CACHE != 0 */ + +#ifndef ipconfigCHECK_IP_QUEUE_SPACE + #define ipconfigCHECK_IP_QUEUE_SPACE 0 +#endif + +#ifndef ipconfigUSE_LLMNR + /* Include support for LLMNR: Link-local Multicast Name Resolution (non-Microsoft) */ + #define ipconfigUSE_LLMNR ( 0 ) +#endif + +#if( !defined( ipconfigUSE_DNS ) ) + #if( ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) ) + /* LLMNR and NBNS depend on DNS because those protocols share a lot of code. */ + #error When either LLMNR or NBNS is used, ipconfigUSE_DNS must be defined + #endif +#endif + +#ifndef ipconfigREPLY_TO_INCOMING_PINGS + #define ipconfigREPLY_TO_INCOMING_PINGS 1 +#endif + +#ifndef ipconfigSUPPORT_OUTGOING_PINGS + #define ipconfigSUPPORT_OUTGOING_PINGS 0 +#endif + +#ifndef ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES + #define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1 +#endif + +#ifndef ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES + #define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1 +#endif + +#ifndef configINCLUDE_TRACE_RELATED_CLI_COMMANDS + #define ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS 0 +#else + #define ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS configINCLUDE_TRACE_RELATED_CLI_COMMANDS +#endif + +#ifndef ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM + #define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM ( 0 ) +#endif + +#ifndef ipconfigETHERNET_DRIVER_FILTERS_PACKETS + #define ipconfigETHERNET_DRIVER_FILTERS_PACKETS ( 0 ) +#endif + +#ifndef ipconfigWATCHDOG_TIMER + /* This macro will be called in every loop the IP-task makes. It may be + replaced by user-code that triggers a watchdog */ + #define ipconfigWATCHDOG_TIMER() +#endif + +#ifndef ipconfigUSE_CALLBACKS + #define ipconfigUSE_CALLBACKS ( 0 ) +#endif + +#if( ipconfigUSE_CALLBACKS != 0 ) + #ifndef ipconfigIS_VALID_PROG_ADDRESS + /* Replace this macro with a test returning non-zero if the memory pointer to by x + * is valid memory which can contain executable code + * In fact this is an extra safety measure: if a handler points to invalid memory, + * it will not be called + */ + #define ipconfigIS_VALID_PROG_ADDRESS(x) ( ( x ) != NULL ) + #endif +#endif + +#ifndef ipconfigHAS_INLINE_FUNCTIONS + #define ipconfigHAS_INLINE_FUNCTIONS ( 1 ) +#endif + +#ifndef portINLINE + #define portINLINE inline +#endif + +#ifndef ipconfigZERO_COPY_TX_DRIVER + /* When non-zero, the buffers passed to the SEND routine may be passed + to DMA. As soon as sending is ready, the buffers must be released by + calling vReleaseNetworkBufferAndDescriptor(), */ + #define ipconfigZERO_COPY_TX_DRIVER ( 0 ) +#endif + +#ifndef ipconfigZERO_COPY_RX_DRIVER + /* This define doesn't mean much to the driver, except that it makes + sure that pxPacketBuffer_to_NetworkBuffer() will be included. */ + #define ipconfigZERO_COPY_RX_DRIVER ( 0 ) +#endif + +#ifndef ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM + #define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM 0 +#endif + +#ifndef ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM + #define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 0 +#endif + +#ifndef ipconfigDHCP_REGISTER_HOSTNAME + #define ipconfigDHCP_REGISTER_HOSTNAME 0 +#endif + +#ifndef ipconfigSOCKET_HAS_USER_SEMAPHORE + #define ipconfigSOCKET_HAS_USER_SEMAPHORE 0 +#endif + +#ifndef ipconfigSOCKET_HAS_USER_WAKE_CALLBACK + #define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK 0 +#endif + +#ifndef ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT + #define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT 0 +#endif + +#if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK != 0 ) && ( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT != 0 ) + #error ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT cannot be used with ipconfigSOCKET_HAS_USER_WAKE_CALLBACK - undefine one of them +#endif + +#ifndef ipconfigSUPPORT_SELECT_FUNCTION + #define ipconfigSUPPORT_SELECT_FUNCTION 0 +#endif + +#ifndef ipconfigTCP_KEEP_ALIVE + #define ipconfigTCP_KEEP_ALIVE 0 +#endif + +#ifndef ipconfigDNS_USE_CALLBACKS + #define ipconfigDNS_USE_CALLBACKS 0 +#endif + +#ifndef ipconfigSUPPORT_SIGNALS + #define ipconfigSUPPORT_SIGNALS 0 +#endif + +#ifndef ipconfigUSE_NBNS + #define ipconfigUSE_NBNS 0 +#endif + +/* As an attack surface reduction for ports that listen for inbound +connections, hang protection can help reduce the impact of SYN floods. */ +#ifndef ipconfigTCP_HANG_PROTECTION + #define ipconfigTCP_HANG_PROTECTION 1 +#endif + +/* Non-activity timeout is expressed in seconds. */ +#ifndef ipconfigTCP_HANG_PROTECTION_TIME + #define ipconfigTCP_HANG_PROTECTION_TIME 30 +#endif + +#ifndef ipconfigTCP_IP_SANITY + #define ipconfigTCP_IP_SANITY 0 +#endif + +#ifndef ipconfigARP_STORES_REMOTE_ADDRESSES + #define ipconfigARP_STORES_REMOTE_ADDRESSES 0 +#endif + +#ifndef ipconfigBUFFER_PADDING + /* Expert option: define a value for 'ipBUFFER_PADDING'. + When 'ipconfigBUFFER_PADDING' equals 0, + 'ipBUFFER_PADDING' will get a default value of 8 + 2 bytes. */ + #define ipconfigBUFFER_PADDING 0 +#endif + +#ifndef ipconfigPACKET_FILLER_SIZE + #define ipconfigPACKET_FILLER_SIZE 2 +#endif + +#endif /* FREERTOS_DEFAULT_IP_CONFIG_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h new file mode 100644 index 000000000..13ba82089 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_ARP.h @@ -0,0 +1,141 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef FREERTOS_ARP_H +#define FREERTOS_ARP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Application level configuration options. */ +#include "FreeRTOSIPConfig.h" +#include "FreeRTOSIPConfigDefaults.h" +#include "IPTraceMacroDefaults.h" + +/*-----------------------------------------------------------*/ +/* Miscellaneous structure and definitions. */ +/*-----------------------------------------------------------*/ + +typedef struct xARP_CACHE_TABLE_ROW +{ + uint32_t ulIPAddress; /* The IP address of an ARP cache entry. */ + MACAddress_t xMACAddress; /* The MAC address of an ARP cache entry. */ + uint8_t ucAge; /* A value that is periodically decremented but can also be refreshed by active communication. The ARP cache entry is removed if the value reaches zero. */ + uint8_t ucValid; /* pdTRUE: xMACAddress is valid, pdFALSE: waiting for ARP reply */ +} ARPCacheRow_t; + +typedef enum +{ + eARPCacheMiss = 0, /* 0 An ARP table lookup did not find a valid entry. */ + eARPCacheHit, /* 1 An ARP table lookup found a valid entry. */ + eCantSendPacket /* 2 There is no IP address, or an ARP is still in progress, so the packet cannot be sent. */ +} eARPLookupResult_t; + +typedef enum +{ + eNotFragment = 0, /* The IP packet being sent is not part of a fragment. */ + eFirstFragment, /* The IP packet being sent is the first in a set of fragmented packets. */ + eFollowingFragment /* The IP packet being sent is part of a set of fragmented packets. */ +} eIPFragmentStatus_t; + +/* + * If ulIPAddress is already in the ARP cache table then reset the age of the + * entry back to its maximum value. If ulIPAddress is not already in the ARP + * cache table then add it - replacing the oldest current entry if there is not + * a free space available. + */ +void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress, const uint32_t ulIPAddress ); + +#if( ipconfigARP_USE_CLASH_DETECTION != 0 ) + /* Becomes non-zero if another device responded to a gratuitos ARP message. */ + extern BaseType_t xARPHadIPClash; + /* MAC-address of the other device containing the same IP-address. */ + extern MACAddress_t xARPClashMacAddress; +#endif /* ipconfigARP_USE_CLASH_DETECTION */ + +#if( ipconfigUSE_ARP_REMOVE_ENTRY != 0 ) + + /* + * In some rare cases, it might be useful to remove a ARP cache entry of a + * known MAC address to make sure it gets refreshed. + */ + uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress ); + +#endif /* ipconfigUSE_ARP_REMOVE_ENTRY != 0 */ + +/* + * Look for ulIPAddress in the ARP cache. If the IP address exists, copy the + * associated MAC address into pxMACAddress, refresh the ARP cache entry's + * age, and return eARPCacheHit. If the IP address does not exist in the ARP + * cache return eARPCacheMiss. If the packet cannot be sent for any reason + * (maybe DHCP is still in process, or the addressing needs a gateway but there + * isn't a gateway defined) then return eCantSendPacket. + */ +eARPLookupResult_t eARPGetCacheEntry( uint32_t *pulIPAddress, MACAddress_t * const pxMACAddress ); + +#if( ipconfigUSE_ARP_REVERSED_LOOKUP != 0 ) + + /* Lookup an IP-address if only the MAC-address is known */ + eARPLookupResult_t eARPGetCacheEntryByMac( MACAddress_t * const pxMACAddress, uint32_t *pulIPAddress ); + +#endif +/* + * Reduce the age count in each entry within the ARP cache. An entry is no + * longer considered valid and is deleted if its age reaches zero. + */ +void vARPAgeCache( void ); + +/* + * Send out an ARP request for the IP address contained in pxNetworkBuffer, and + * add an entry into the ARP table that indicates that an ARP reply is + * outstanding so re-transmissions can be generated. + */ +void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer ); + +/* + * After DHCP is ready and when changing IP address, force a quick send of our new IP + * address + */ +void vARPSendGratuitous( void ); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* FREERTOS_ARP_H */ + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h new file mode 100644 index 000000000..ab998ed05 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DHCP.h @@ -0,0 +1,87 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef FREERTOS_DHCP_H +#define FREERTOS_DHCP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Application level configuration options. */ +#include "FreeRTOSIPConfig.h" +#include "IPTraceMacroDefaults.h" + +/* Used in the DHCP callback if ipconfigUSE_DHCP_HOOK is set to 1. */ +typedef enum eDHCP_PHASE +{ + eDHCPPhasePreDiscover, /* Driver is about to send a DHCP discovery. */ + eDHCPPhasePreRequest, /* Driver is about to request DHCP an IP address. */ +#if( ipconfigDHCP_SEND_DISCOVER_AFTER_AUTO_IP != 0 ) + eDHCPPhasePreLLA, /* Driver is about to try get an LLA address */ +#endif /* ipconfigDHCP_SEND_DISCOVER_AFTER_AUTO_IP */ +} eDHCPCallbackPhase_t; + +/* Used in the DHCP callback if ipconfigUSE_DHCP_HOOK is set to 1. */ +typedef enum eDHCP_ANSWERS +{ + eDHCPContinue, /* Continue the DHCP process */ + eDHCPUseDefaults, /* Stop DHCP and use the static defaults. */ + eDHCPStopNoChanges, /* Stop DHCP and continue with current settings. */ +} eDHCPCallbackAnswer_t; + +/* + * NOT A PUBLIC API FUNCTION. + */ +void vDHCPProcess( BaseType_t xReset ); + +/* Internal call: returns true if socket is the current DHCP socket */ +BaseType_t xIsDHCPSocket( Socket_t xSocket ); + +/* Prototype of the hook (or callback) function that must be provided by the +application if ipconfigUSE_DHCP_HOOK is set to 1. See the following URL for +usage information: +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html#ipconfigUSE_DHCP_HOOK +*/ +eDHCPCallbackAnswer_t xApplicationDHCPHook( eDHCPCallbackPhase_t eDHCPPhase, uint32_t ulIPAddress ); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* FREERTOS_DHCP_H */ + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h new file mode 100644 index 000000000..c52f3d3b4 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_DNS.h @@ -0,0 +1,137 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef FREERTOS_DNS_H +#define FREERTOS_DNS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Application level configuration options. */ +#include "FreeRTOSIPConfig.h" +#include "IPTraceMacroDefaults.h" + + +/* The Link-local Multicast Name Resolution (LLMNR) + * is included. + * Note that a special MAC address is required in addition to the NIC's actual + * MAC address: 01:00:5E:00:00:FC + * + * The target IP address will be 224.0.0.252 + */ +#if( ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN ) + #define ipLLMNR_IP_ADDR 0xE00000FC +#else + #define ipLLMNR_IP_ADDR 0xFC0000E0 +#endif /* ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN */ + +#define ipLLMNR_PORT 5355 /* Standard LLMNR port. */ +#define ipDNS_PORT 53 /* Standard DNS port. */ +#define ipDHCP_CLIENT 67 +#define ipDHCP_SERVER 68 +#define ipNBNS_PORT 137 /* NetBIOS Name Service. */ +#define ipNBDGM_PORT 138 /* Datagram Service, not included. */ + +/* + * The following function should be provided by the user and return true if it + * matches the domain name. + */ +extern BaseType_t xApplicationDNSQueryHook( const char *pcName ); + +/* + * LLMNR is very similar to DNS, so is handled by the DNS routines. + */ +uint32_t ulDNSHandlePacket( NetworkBufferDescriptor_t *pxNetworkBuffer ); + +#if( ipconfigUSE_LLMNR == 1 ) + extern const MACAddress_t xLLMNR_MacAdress; +#endif /* ipconfigUSE_LLMNR */ + +#if( ipconfigUSE_NBNS != 0 ) + + /* + * Inspect a NetBIOS Names-Service message. If the name matches with ours + * (xApplicationDNSQueryHook returns true) an answer will be sent back. + * Note that LLMNR is a better protocol for name services on a LAN as it is + * less polluted + */ + uint32_t ulNBNSHandlePacket (NetworkBufferDescriptor_t *pxNetworkBuffer ); + +#endif /* ipconfigUSE_NBNS */ + +#if( ipconfigUSE_DNS_CACHE != 0 ) + + /* Look for the indicated host name in the DNS cache. Returns the IPv4 + address if present, or 0x0 otherwise. */ + uint32_t FreeRTOS_dnslookup( const char *pcHostName ); + + /* Remove all entries from the DNS cache. */ + void FreeRTOS_dnsclear(); +#endif /* ipconfigUSE_DNS_CACHE != 0 */ + +#if( ipconfigDNS_USE_CALLBACKS != 0 ) + + /* + * Users may define this type of function as a callback. + * It will be called when a DNS reply is received or when a timeout has been reached. + */ + typedef void (* FOnDNSEvent ) ( const char * /* pcName */, void * /* pvSearchID */, uint32_t /* ulIPAddress */ ); + + /* + * Asynchronous version of gethostbyname() + * xTimeout is in units of ms. + */ + uint32_t FreeRTOS_gethostbyname_a( const char *pcHostName, FOnDNSEvent pCallback, void *pvSearchID, TickType_t xTimeout ); + void FreeRTOS_gethostbyname_cancel( void *pvSearchID ); + +#endif + +/* + * FULL, UP-TO-DATE AND MAINTAINED REFERENCE DOCUMENTATION FOR ALL THESE + * FUNCTIONS IS AVAILABLE ON THE FOLLOWING URL: + * _TBD_ Add URL + */ +uint32_t FreeRTOS_gethostbyname( const char *pcHostName ); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* FREERTOS_DNS_H */ + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h new file mode 100644 index 000000000..f8019a779 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP.h @@ -0,0 +1,328 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef FREERTOS_IP_H +#define FREERTOS_IP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Application level configuration options. */ +#include "FreeRTOSIPConfig.h" +#include "FreeRTOSIPConfigDefaults.h" +#include "IPTraceMacroDefaults.h" + +/* Some constants defining the sizes of several parts of a packet */ +#define ipSIZE_OF_ETH_HEADER 14u +#define ipSIZE_OF_IPv4_HEADER 20u +#define ipSIZE_OF_IGMP_HEADER 8u +#define ipSIZE_OF_ICMP_HEADER 8u +#define ipSIZE_OF_UDP_HEADER 8u +#define ipSIZE_OF_TCP_HEADER 20u + + +/* The number of octets in the MAC and IP addresses respectively. */ +#define ipMAC_ADDRESS_LENGTH_BYTES ( 6 ) +#define ipIP_ADDRESS_LENGTH_BYTES ( 4 ) + +/* IP protocol definitions. */ +#define ipPROTOCOL_ICMP ( 1 ) +#define ipPROTOCOL_IGMP ( 2 ) +#define ipPROTOCOL_TCP ( 6 ) +#define ipPROTOCOL_UDP ( 17 ) + +/* Dimensions the buffers that are filled by received Ethernet frames. */ +#define ipSIZE_OF_ETH_CRC_BYTES ( 4UL ) +#define ipSIZE_OF_ETH_OPTIONAL_802_1Q_TAG_BYTES ( 4UL ) +#define ipTOTAL_ETHERNET_FRAME_SIZE ( ( ( uint32_t ) ipconfigNETWORK_MTU ) + ( ( uint32_t ) ipSIZE_OF_ETH_HEADER ) + ipSIZE_OF_ETH_CRC_BYTES + ipSIZE_OF_ETH_OPTIONAL_802_1Q_TAG_BYTES ) + +/*_RB_ Comment may need updating. */ +/* Space left at the beginning of a network buffer storage area to store a +pointer back to the network buffer. Should be a multiple of 8 to ensure 8 byte +alignment is maintained on architectures that require it. + +In order to get a 32-bit alignment of network packets, an offset of 2 bytes +would be desirable, as defined by ipconfigPACKET_FILLER_SIZE. So the malloc'd +buffer will have the following contents: + uint32_t pointer; // word-aligned + uchar_8 filler[6]; + << ETH-header >> // half-word-aligned + uchar_8 dest[6]; // start of pucEthernetBuffer + uchar_8 dest[6]; + uchar16_t type; + << IP-header >> // word-aligned + uint8_t ucVersionHeaderLength; + etc + */ +#if( ipconfigBUFFER_PADDING != 0 ) + #define ipBUFFER_PADDING ipconfigBUFFER_PADDING +#else + #define ipBUFFER_PADDING ( 8u + ipconfigPACKET_FILLER_SIZE ) +#endif + +/* The structure used to store buffers and pass them around the network stack. +Buffers can be in use by the stack, in use by the network interface hardware +driver, or free (not in use). */ +typedef struct xNETWORK_BUFFER +{ + ListItem_t xBufferListItem; /* Used to reference the buffer form the free buffer list or a socket. */ + uint32_t ulIPAddress; /* Source or destination IP address, depending on usage scenario. */ + uint8_t *pucEthernetBuffer; /* Pointer to the start of the Ethernet frame. */ + size_t xDataLength; /* Starts by holding the total Ethernet frame length, then the UDP/TCP payload length. */ + uint16_t usPort; /* Source or destination port, depending on usage scenario. */ + uint16_t usBoundPort; /* The port to which a transmitting socket is bound. */ + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + struct xNETWORK_BUFFER *pxNextBuffer; /* Possible optimisation for expert users - requires network driver support. */ + #endif +} NetworkBufferDescriptor_t; + +#include "pack_struct_start.h" +struct xMAC_ADDRESS +{ + uint8_t ucBytes[ ipMAC_ADDRESS_LENGTH_BYTES ]; +} +#include "pack_struct_end.h" + +typedef struct xMAC_ADDRESS MACAddress_t; + +typedef enum eNETWORK_EVENTS +{ + eNetworkUp, /* The network is configured. */ + eNetworkDown /* The network connection has been lost. */ +} eIPCallbackEvent_t; + +typedef enum ePING_REPLY_STATUS +{ + eSuccess = 0, /* A correct reply has been received for an outgoing ping. */ + eInvalidChecksum, /* A reply was received for an outgoing ping but the checksum of the reply was incorrect. */ + eInvalidData /* A reply was received to an outgoing ping but the payload of the reply was not correct. */ +} ePingReplyStatus_t; + +typedef enum eNETWORK_ADDRESS_TYPE +{ + eNetWorkAddressTypeIPV4, + eNetWorkAddressTypeIPV6, + eNetWorkAddressTypeHostName +} eNetWorkAddressType_t; + +/* Endian related definitions. */ +#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) + + /* FreeRTOS_htons / FreeRTOS_htonl: some platforms might have built-in versions + using a single instruction so allow these versions to be overridden. */ + #ifndef FreeRTOS_htons + #define FreeRTOS_htons( usIn ) ( (uint16_t) ( ( ( usIn ) << 8U ) | ( ( usIn ) >> 8U ) ) ) + #endif + + #ifndef FreeRTOS_htonl + #define FreeRTOS_htonl( ulIn ) \ + ( \ + ( uint32_t ) \ + ( \ + ( ( ( ( uint32_t ) ( ulIn ) ) ) << 24 ) | \ + ( ( ( ( uint32_t ) ( ulIn ) ) & 0x0000ff00UL ) << 8 ) | \ + ( ( ( ( uint32_t ) ( ulIn ) ) & 0x00ff0000UL ) >> 8 ) | \ + ( ( ( ( uint32_t ) ( ulIn ) ) ) >> 24 ) \ + ) \ + ) + #endif + +#else /* ipconfigBYTE_ORDER */ + + #define FreeRTOS_htons( x ) ( ( uint16_t ) ( x ) ) + #define FreeRTOS_htonl( x ) ( ( uint32_t ) ( x ) ) + +#endif /* ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN */ + +#define FreeRTOS_ntohs( x ) FreeRTOS_htons( x ) +#define FreeRTOS_ntohl( x ) FreeRTOS_htonl( x ) + +#if( ipconfigHAS_INLINE_FUNCTIONS == 1 ) + + static portINLINE int32_t FreeRTOS_max_int32 (int32_t a, int32_t b); + static portINLINE uint32_t FreeRTOS_max_uint32 (uint32_t a, uint32_t b); + static portINLINE int32_t FreeRTOS_min_int32 (int32_t a, int32_t b); + static portINLINE uint32_t FreeRTOS_min_uint32 (uint32_t a, uint32_t b); + static portINLINE uint32_t FreeRTOS_round_up (uint32_t a, uint32_t d); + static portINLINE uint32_t FreeRTOS_round_down (uint32_t a, uint32_t d); + static portINLINE BaseType_t FreeRTOS_min_BaseType (BaseType_t a, BaseType_t b); + static portINLINE BaseType_t FreeRTOS_max_BaseType (BaseType_t a, BaseType_t b); + static portINLINE UBaseType_t FreeRTOS_max_UBaseType (UBaseType_t a, UBaseType_t b); + static portINLINE UBaseType_t FreeRTOS_min_UBaseType (UBaseType_t a, UBaseType_t b); + + + static portINLINE int32_t FreeRTOS_max_int32 (int32_t a, int32_t b) { return a >= b ? a : b; } + static portINLINE uint32_t FreeRTOS_max_uint32 (uint32_t a, uint32_t b) { return a >= b ? a : b; } + static portINLINE int32_t FreeRTOS_min_int32 (int32_t a, int32_t b) { return a <= b ? a : b; } + static portINLINE uint32_t FreeRTOS_min_uint32 (uint32_t a, uint32_t b) { return a <= b ? a : b; } + static portINLINE uint32_t FreeRTOS_round_up (uint32_t a, uint32_t d) { return d * ( ( a + d - 1u ) / d ); } + static portINLINE uint32_t FreeRTOS_round_down (uint32_t a, uint32_t d) { return d * ( a / d ); } + + static portINLINE BaseType_t FreeRTOS_max_BaseType (BaseType_t a, BaseType_t b) { return a >= b ? a : b; } + static portINLINE UBaseType_t FreeRTOS_max_UBaseType (UBaseType_t a, UBaseType_t b) { return a >= b ? a : b; } + static portINLINE BaseType_t FreeRTOS_min_BaseType (BaseType_t a, BaseType_t b) { return a <= b ? a : b; } + static portINLINE UBaseType_t FreeRTOS_min_UBaseType (UBaseType_t a, UBaseType_t b) { return a <= b ? a : b; } + +#else + + #define FreeRTOS_max_int32(a,b) ( ( ( int32_t ) ( a ) ) >= ( ( int32_t ) ( b ) ) ? ( ( int32_t ) ( a ) ) : ( ( int32_t ) ( b ) ) ) + #define FreeRTOS_max_uint32(a,b) ( ( ( uint32_t ) ( a ) ) >= ( ( uint32_t ) ( b ) ) ? ( ( uint32_t ) ( a ) ) : ( ( uint32_t ) ( b ) ) ) + + #define FreeRTOS_min_int32(a,b) ( ( ( int32_t ) a ) <= ( ( int32_t ) b ) ? ( ( int32_t ) a ) : ( ( int32_t ) b ) ) + #define FreeRTOS_min_uint32(a,b) ( ( ( uint32_t ) a ) <= ( ( uint32_t ) b ) ? ( ( uint32_t ) a ) : ( ( uint32_t ) b ) ) + + /* Round-up: a = d * ( ( a + d - 1 ) / d ) */ + #define FreeRTOS_round_up(a,d) ( ( ( uint32_t ) ( d ) ) * ( ( ( ( uint32_t ) ( a ) ) + ( ( uint32_t ) ( d ) ) - 1UL ) / ( ( uint32_t ) ( d ) ) ) ) + #define FreeRTOS_round_down(a,d) ( ( ( uint32_t ) ( d ) ) * ( ( ( uint32_t ) ( a ) ) / ( ( uint32_t ) ( d ) ) ) ) + + #define FreeRTOS_ms_to_tick(ms) ( ( ms * configTICK_RATE_HZ + 500 ) / 1000 ) + + #define FreeRTOS_max_BaseType(a, b) ( ( ( BaseType_t ) ( a ) ) >= ( ( BaseType_t ) ( b ) ) ? ( ( BaseType_t ) ( a ) ) : ( ( BaseType_t ) ( b ) ) ) + #define FreeRTOS_max_UBaseType(a, b) ( ( ( UBaseType_t ) ( a ) ) >= ( ( UBaseType_t ) ( b ) ) ? ( ( UBaseType_t ) ( a ) ) : ( ( UBaseType_t ) ( b ) ) ) + #define FreeRTOS_min_BaseType(a, b) ( ( ( BaseType_t ) ( a ) ) <= ( ( BaseType_t ) ( b ) ) ? ( ( BaseType_t ) ( a ) ) : ( ( BaseType_t ) ( b ) ) ) + #define FreeRTOS_min_UBaseType(a, b) ( ( ( UBaseType_t ) ( a ) ) <= ( ( UBaseType_t ) ( b ) ) ? ( ( UBaseType_t ) ( a ) ) : ( ( UBaseType_t ) ( b ) ) ) + +#endif /* ipconfigHAS_INLINE_FUNCTIONS */ + +#define pdMS_TO_MIN_TICKS( xTimeInMs ) ( pdMS_TO_TICKS( ( xTimeInMs ) ) < ( ( TickType_t ) 1 ) ? ( ( TickType_t ) 1 ) : pdMS_TO_TICKS( ( xTimeInMs ) ) ) + +#ifndef pdTRUE_SIGNED + /* Temporary solution: eventually the defines below will appear in 'Source\include\projdefs.h' */ + #define pdTRUE_SIGNED pdTRUE + #define pdFALSE_SIGNED pdFALSE + #define pdTRUE_UNSIGNED ( ( UBaseType_t ) 1u ) + #define pdFALSE_UNSIGNED ( ( UBaseType_t ) 0u ) +#endif + +/* + * FULL, UP-TO-DATE AND MAINTAINED REFERENCE DOCUMENTATION FOR ALL THESE + * FUNCTIONS IS AVAILABLE ON THE FOLLOWING URL: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/FreeRTOS_TCP_API_Functions.html + */ +BaseType_t FreeRTOS_IPInit( const uint8_t ucIPAddress[ ipIP_ADDRESS_LENGTH_BYTES ], + const uint8_t ucNetMask[ ipIP_ADDRESS_LENGTH_BYTES ], + const uint8_t ucGatewayAddress[ ipIP_ADDRESS_LENGTH_BYTES ], + const uint8_t ucDNSServerAddress[ ipIP_ADDRESS_LENGTH_BYTES ], + const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] ); + +void * FreeRTOS_GetUDPPayloadBuffer( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks ); +void FreeRTOS_GetAddressConfiguration( uint32_t *pulIPAddress, uint32_t *pulNetMask, uint32_t *pulGatewayAddress, uint32_t *pulDNSServerAddress ); +void FreeRTOS_SetAddressConfiguration( const uint32_t *pulIPAddress, const uint32_t *pulNetMask, const uint32_t *pulGatewayAddress, const uint32_t *pulDNSServerAddress ); +BaseType_t FreeRTOS_SendPingRequest( uint32_t ulIPAddress, size_t xNumberOfBytesToSend, TickType_t xBlockTimeTicks ); +void FreeRTOS_ReleaseUDPPayloadBuffer( void *pvBuffer ); +const uint8_t * FreeRTOS_GetMACAddress( void ); +void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ipMAC_ADDRESS_LENGTH_BYTES] ); +void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ); +void vApplicationPingReplyHook( ePingReplyStatus_t eStatus, uint16_t usIdentifier ); +uint32_t FreeRTOS_GetIPAddress( void ); +void FreeRTOS_SetIPAddress( uint32_t ulIPAddress ); +void FreeRTOS_SetNetmask( uint32_t ulNetmask ); +void FreeRTOS_SetGatewayAddress( uint32_t ulGatewayAddress ); +uint32_t FreeRTOS_GetGatewayAddress( void ); +uint32_t FreeRTOS_GetDNSServerAddress( void ); +uint32_t FreeRTOS_GetNetmask( void ); +void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress ); +BaseType_t FreeRTOS_IsNetworkUp( void ); + +#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + UBaseType_t uxGetMinimumIPQueueSpace( void ); +#endif + +/* + * Defined in FreeRTOS_Sockets.c + * //_RB_ Don't think this comment is correct. If this is for internal use only it should appear after all the public API functions and not start with FreeRTOS_. + * Socket has had activity, reset the timer so it will not be closed + * because of inactivity + */ +const char *FreeRTOS_GetTCPStateName( UBaseType_t ulState); + +/* _HT_ Temporary: show all valid ARP entries + */ +void FreeRTOS_PrintARPCache( void ); +void FreeRTOS_ClearARP( void ); + +#if( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) + + /* DHCP has an option for clients to register their hostname. It doesn't + have much use, except that a device can be found in a router along with its + name. If this option is used the callback below must be provided by the + application writer to return a const string, denoting the device's name. */ + const char *pcApplicationHostnameHook( void ); + +#endif /* ipconfigDHCP_REGISTER_HOSTNAME */ + + +/* For backward compatibility define old structure names to the newer equivalent +structure name. */ +#ifndef ipconfigENABLE_BACKWARD_COMPATIBILITY + #define ipconfigENABLE_BACKWARD_COMPATIBILITY 1 +#endif + +#if( ipconfigENABLE_BACKWARD_COMPATIBILITY == 1 ) + #define xIPStackEvent_t IPStackEvent_t + #define xNetworkBufferDescriptor_t NetworkBufferDescriptor_t + #define xMACAddress_t MACAddress_t + #define xWinProperties_t WinProperties_t + #define xSocket_t Socket_t + #define xSocketSet_t SocketSet_t + #define ipSIZE_OF_IP_HEADER ipSIZE_OF_IPv4_HEADER + + /* Since August 2016, the public types and fields below have changed name: + abbreviations TCP/UDP are now written in capitals, and type names now end with "_t". */ + #define FOnConnected FOnConnected_t + #define FOnTcpReceive FOnTCPReceive_t + #define FOnTcpSent FOnTCPSent_t + #define FOnUdpReceive FOnUDPReceive_t + #define FOnUdpSent FOnUDPSent_t + + #define pOnTcpConnected pxOnTCPConnected + #define pOnTcpReceive pxOnTCPReceive + #define pOnTcpSent pxOnTCPSent + #define pOnUdpReceive pxOnUDPReceive + #define pOnUdpSent pxOnUDPSent + + #define FOnUdpSent FOnUDPSent_t + #define FOnTcpSent FOnTCPSent_t +#endif /* ipconfigENABLE_BACKWARD_COMPATIBILITY */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* FREERTOS_IP_H */ + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h new file mode 100644 index 000000000..2563d010a --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_IP_Private.h @@ -0,0 +1,825 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef FREERTOS_IP_PRIVATE_H +#define FREERTOS_IP_PRIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Application level configuration options. */ +#include "FreeRTOSIPConfig.h" +#include "FreeRTOSIPConfigDefaults.h" +#include "FreeRTOS_Sockets.h" +#include "IPTraceMacroDefaults.h" +#include "FreeRTOS_Stream_Buffer.h" +#if( ipconfigUSE_TCP == 1 ) + #include "FreeRTOS_TCP_WIN.h" + #include "FreeRTOS_TCP_IP.h" +#endif + +#if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 ) + #include "semphr.h" +#endif + +#include "event_groups.h" + +typedef struct xNetworkAddressingParameters +{ + uint32_t ulDefaultIPAddress; + uint32_t ulNetMask; + uint32_t ulGatewayAddress; + uint32_t ulDNSServerAddress; + uint32_t ulBroadcastAddress; +} NetworkAddressingParameters_t; + +extern BaseType_t xTCPWindowLoggingLevel; + +/*-----------------------------------------------------------*/ +/* Protocol headers. */ +/*-----------------------------------------------------------*/ + +#include "pack_struct_start.h" +struct xETH_HEADER +{ + MACAddress_t xDestinationAddress; /* 0 + 6 = 6 */ + MACAddress_t xSourceAddress; /* 6 + 6 = 12 */ + uint16_t usFrameType; /* 12 + 2 = 14 */ +} +#include "pack_struct_end.h" +typedef struct xETH_HEADER EthernetHeader_t; + +#include "pack_struct_start.h" +struct xARP_HEADER +{ + uint16_t usHardwareType; /* 0 + 2 = 2 */ + uint16_t usProtocolType; /* 2 + 2 = 4 */ + uint8_t ucHardwareAddressLength; /* 4 + 1 = 5 */ + uint8_t ucProtocolAddressLength; /* 5 + 1 = 6 */ + uint16_t usOperation; /* 6 + 2 = 8 */ + MACAddress_t xSenderHardwareAddress; /* 8 + 6 = 14 */ + uint8_t ucSenderProtocolAddress[ 4 ]; /* 14 + 4 = 18 */ + MACAddress_t xTargetHardwareAddress; /* 18 + 6 = 24 */ + uint32_t ulTargetProtocolAddress; /* 24 + 4 = 28 */ +} +#include "pack_struct_end.h" +typedef struct xARP_HEADER ARPHeader_t; + +#include "pack_struct_start.h" +struct xIP_HEADER +{ + uint8_t ucVersionHeaderLength; /* 0 + 1 = 1 */ + uint8_t ucDifferentiatedServicesCode; /* 1 + 1 = 2 */ + uint16_t usLength; /* 2 + 2 = 4 */ + uint16_t usIdentification; /* 4 + 2 = 6 */ + uint16_t usFragmentOffset; /* 6 + 2 = 8 */ + uint8_t ucTimeToLive; /* 8 + 1 = 9 */ + uint8_t ucProtocol; /* 9 + 1 = 10 */ + uint16_t usHeaderChecksum; /* 10 + 2 = 12 */ + uint32_t ulSourceIPAddress; /* 12 + 4 = 16 */ + uint32_t ulDestinationIPAddress; /* 16 + 4 = 20 */ +} +#include "pack_struct_end.h" +typedef struct xIP_HEADER IPHeader_t; + +#include "pack_struct_start.h" +struct xIGMP_HEADER +{ + uint8_t ucVersionType; /* 0 + 1 = 1 */ + uint8_t ucMaxResponseTime; /* 1 + 1 = 2 */ + uint16_t usChecksum; /* 2 + 2 = 4 */ + uint32_t usGroupAddress; /* 4 + 4 = 8 */ +} +#include "pack_struct_end.h" +typedef struct xIGMP_HEADER IGMPHeader_t; + +#include "pack_struct_start.h" +struct xICMP_HEADER +{ + uint8_t ucTypeOfMessage; /* 0 + 1 = 1 */ + uint8_t ucTypeOfService; /* 1 + 1 = 2 */ + uint16_t usChecksum; /* 2 + 2 = 4 */ + uint16_t usIdentifier; /* 4 + 2 = 6 */ + uint16_t usSequenceNumber; /* 6 + 2 = 8 */ +} +#include "pack_struct_end.h" +typedef struct xICMP_HEADER ICMPHeader_t; + +#include "pack_struct_start.h" +struct xUDP_HEADER +{ + uint16_t usSourcePort; /* 0 + 2 = 2 */ + uint16_t usDestinationPort; /* 2 + 2 = 4 */ + uint16_t usLength; /* 4 + 2 = 6 */ + uint16_t usChecksum; /* 6 + 2 = 8 */ +} +#include "pack_struct_end.h" +typedef struct xUDP_HEADER UDPHeader_t; + +#include "pack_struct_start.h" +struct xTCP_HEADER +{ + uint16_t usSourcePort; /* + 2 = 2 */ + uint16_t usDestinationPort; /* + 2 = 4 */ + uint32_t ulSequenceNumber; /* + 4 = 8 */ + uint32_t ulAckNr; /* + 4 = 12 */ + uint8_t ucTCPOffset; /* + 1 = 13 */ + uint8_t ucTCPFlags; /* + 1 = 14 */ + uint16_t usWindow; /* + 2 = 15 */ + uint16_t usChecksum; /* + 2 = 18 */ + uint16_t usUrgent; /* + 2 = 20 */ +#if ipconfigUSE_TCP == 1 + /* the option data is not a part of the TCP header */ + uint8_t ucOptdata[ipSIZE_TCP_OPTIONS]; /* + 12 = 32 */ +#endif +} +#include "pack_struct_end.h" +typedef struct xTCP_HEADER TCPHeader_t; + +#include "pack_struct_start.h" +struct xPSEUDO_HEADER +{ + uint32_t ulSourceAddress; + uint32_t ulDestinationAddress; + uint8_t ucZeros; + uint8_t ucProtocol; + uint16_t usUDPLength; +} +#include "pack_struct_end.h" +typedef struct xPSEUDO_HEADER PseudoHeader_t; + +/*-----------------------------------------------------------*/ +/* Nested protocol packets. */ +/*-----------------------------------------------------------*/ + +#include "pack_struct_start.h" +struct xARP_PACKET +{ + EthernetHeader_t xEthernetHeader; /* 0 + 14 = 14 */ + ARPHeader_t xARPHeader; /* 14 + 28 = 42 */ +} +#include "pack_struct_end.h" +typedef struct xARP_PACKET ARPPacket_t; + +#include "pack_struct_start.h" +struct xIP_PACKET +{ + EthernetHeader_t xEthernetHeader; + IPHeader_t xIPHeader; +} +#include "pack_struct_end.h" +typedef struct xIP_PACKET IPPacket_t; + +#include "pack_struct_start.h" +struct xICMP_PACKET +{ + EthernetHeader_t xEthernetHeader; + IPHeader_t xIPHeader; + ICMPHeader_t xICMPHeader; +} +#include "pack_struct_end.h" +typedef struct xICMP_PACKET ICMPPacket_t; + +#include "pack_struct_start.h" +struct xUDP_PACKET +{ + EthernetHeader_t xEthernetHeader; /* 0 + 14 = 14 */ + IPHeader_t xIPHeader; /* 14 + 20 = 34 */ + UDPHeader_t xUDPHeader; /* 34 + 8 = 42 */ +} +#include "pack_struct_end.h" +typedef struct xUDP_PACKET UDPPacket_t; + +#include "pack_struct_start.h" +struct xTCP_PACKET +{ + EthernetHeader_t xEthernetHeader; /* 0 + 14 = 14 */ + IPHeader_t xIPHeader; /* 14 + 20 = 34 */ + TCPHeader_t xTCPHeader; /* 34 + 32 = 66 */ +} +#include "pack_struct_end.h" +typedef struct xTCP_PACKET TCPPacket_t; + +typedef union XPROT_PACKET +{ + ARPPacket_t xARPPacket; + TCPPacket_t xTCPPacket; + UDPPacket_t xUDPPacket; + ICMPPacket_t xICMPPacket; +} ProtocolPacket_t; + + +/* The maximum UDP payload length. */ +#define ipMAX_UDP_PAYLOAD_LENGTH ( ( ipconfigNETWORK_MTU - ipSIZE_OF_IPv4_HEADER ) - ipSIZE_OF_UDP_HEADER ) + +typedef enum +{ + eReleaseBuffer = 0, /* Processing the frame did not find anything to do - just release the buffer. */ + eProcessBuffer, /* An Ethernet frame has a valid address - continue process its contents. */ + eReturnEthernetFrame, /* The Ethernet frame contains an ARP or ICMP packet that can be returned to its source. */ + eFrameConsumed /* Processing the Ethernet packet contents resulted in the payload being sent to the stack. */ +} eFrameProcessingResult_t; + +typedef enum +{ + eNoEvent = -1, + eNetworkDownEvent, /* 0: The network interface has been lost and/or needs [re]connecting. */ + eNetworkRxEvent, /* 1: The network interface has queued a received Ethernet frame. */ + eARPTimerEvent, /* 2: The ARP timer expired. */ + eStackTxEvent, /* 3: The software stack has queued a packet to transmit. */ + eDHCPEvent, /* 4: Process the DHCP state machine. */ + eTCPTimerEvent, /* 5: See if any TCP socket needs attention. */ + eTCPAcceptEvent, /* 6: Client API FreeRTOS_accept() waiting for client connections. */ + eTCPNetStat, /* 7: IP-task is asked to produce a netstat listing. */ + eSocketBindEvent, /* 8: Send a message to the IP-task to bind a socket to a port. */ + eSocketCloseEvent, /* 9: Send a message to the IP-task to close a socket. */ + eSocketSelectEvent, /*10: Send a message to the IP-task for select(). */ + eSocketSignalEvent, /*11: A socket must be signalled. */ +} eIPEvent_t; + +typedef struct IP_TASK_COMMANDS +{ + eIPEvent_t eEventType; + void *pvData; +} IPStackEvent_t; + +#define ipBROADCAST_IP_ADDRESS 0xffffffffUL + +/* Offset into the Ethernet frame that is used to temporarily store information +on the fragmentation status of the packet being sent. The value is important, +as it is past the location into which the destination address will get placed. */ +#define ipFRAGMENTATION_PARAMETERS_OFFSET ( 6 ) +#define ipSOCKET_OPTIONS_OFFSET ( 6 ) + +/* Only used when outgoing fragmentation is being used (FreeRTOSIPConfig.h +setting. */ +#define ipGET_UDP_PAYLOAD_OFFSET_FOR_FRAGMENT( usFragmentOffset ) ( ( ( usFragmentOffset ) == 0 ) ? ipUDP_PAYLOAD_OFFSET_IPv4 : ipIP_PAYLOAD_OFFSET ) + +/* The offset into a UDP packet at which the UDP data (payload) starts. */ +#define ipUDP_PAYLOAD_OFFSET_IPv4 ( sizeof( UDPPacket_t ) ) + +/* The offset into an IP packet into which the IP data (payload) starts. */ +#define ipIP_PAYLOAD_OFFSET ( sizeof( IPPacket_t ) ) + +#include "pack_struct_start.h" +struct xUDP_IP_FRAGMENT_PARAMETERS +{ + uint8_t ucSocketOptions; + uint8_t ucPadFor16BitAlignment; + uint16_t usFragmentedPacketOffset; + uint16_t usFragmentLength; + uint16_t usPayloadChecksum; +} +#include "pack_struct_end.h" +typedef struct xUDP_IP_FRAGMENT_PARAMETERS IPFragmentParameters_t; + +#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) + + /* Ethernet frame types. */ + #define ipARP_FRAME_TYPE ( 0x0608U ) + #define ipIPv4_FRAME_TYPE ( 0x0008U ) + + /* ARP related definitions. */ + #define ipARP_PROTOCOL_TYPE ( 0x0008U ) + #define ipARP_HARDWARE_TYPE_ETHERNET ( 0x0100U ) + #define ipARP_REQUEST ( 0x0100U ) + #define ipARP_REPLY ( 0x0200U ) + +#else + + /* Ethernet frame types. */ + #define ipARP_FRAME_TYPE ( 0x0806U ) + #define ipIPv4_FRAME_TYPE ( 0x0800U ) + + /* ARP related definitions. */ + #define ipARP_PROTOCOL_TYPE ( 0x0800U ) + #define ipARP_HARDWARE_TYPE_ETHERNET ( 0x0001U ) + #define ipARP_REQUEST ( 0x0001 ) + #define ipARP_REPLY ( 0x0002 ) + +#endif /* ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN */ + + +/* For convenience, a MAC address of all zeros and another of all 0xffs are +defined const for quick reference. */ +extern const MACAddress_t xBroadcastMACAddress; /* all 0xff's */ +extern uint16_t usPacketIdentifier; + +/* Define a default UDP packet header (declared in FreeRTOS_UDP_IP.c) */ +typedef union xUDPPacketHeader +{ + uint8_t ucBytes[24]; + uint32_t ulWords[6]; +} UDPPacketHeader_t; +extern UDPPacketHeader_t xDefaultPartUDPPacketHeader; + +/* Structure that stores the netmask, gateway address and DNS server addresses. */ +extern NetworkAddressingParameters_t xNetworkAddressing; + +/* Structure that stores the defaults for netmask, gateway address and DNS. +These values will be copied to 'xNetworkAddressing' in case DHCP is not used, +and also in case DHCP does not lead to a confirmed request. */ +extern NetworkAddressingParameters_t xDefaultAddressing; + +/* True when BufferAllocation_1.c was included, false for BufferAllocation_2.c */ +extern const BaseType_t xBufferAllocFixedSize; + +/* Defined in FreeRTOS_Sockets.c */ +#if ( ipconfigUSE_TCP == 1 ) + extern List_t xBoundTCPSocketsList; +#endif + +/* The local IP address is accessed from within xDefaultPartUDPPacketHeader, +rather than duplicated in its own variable. */ +#define ipLOCAL_IP_ADDRESS_POINTER ( ( uint32_t * ) &( xDefaultPartUDPPacketHeader.ulWords[ 20u / sizeof(uint32_t) ] ) ) + +/* The local MAC address is accessed from within xDefaultPartUDPPacketHeader, +rather than duplicated in its own variable. */ +#define ipLOCAL_MAC_ADDRESS ( &xDefaultPartUDPPacketHeader.ucBytes[0] ) + +/* ICMP packets are sent using the same function as UDP packets. The port +number is used to distinguish between the two, as 0 is an invalid UDP port. */ +#define ipPACKET_CONTAINS_ICMP_DATA ( 0 ) + +/* For now, the lower 8 bits in 'xEventBits' will be reserved for the above +socket events. */ +#define SOCKET_EVENT_BIT_COUNT 8 + +#define vSetField16( pxBase, xType, xField, usValue ) \ +{ \ + ( ( uint8_t* )( pxBase ) ) [ offsetof( xType, xField ) + 0 ] = ( uint8_t ) ( ( usValue ) >> 8 ); \ + ( ( uint8_t* )( pxBase ) ) [ offsetof( xType, xField ) + 1 ] = ( uint8_t ) ( ( usValue ) & 0xff ); \ +} + +#define vSetField32( pxBase, xType, xField, ulValue ) \ +{ \ + ( (uint8_t*)( pxBase ) ) [ offsetof( xType, xField ) + 0 ] = ( uint8_t ) ( ( ulValue ) >> 24 ); \ + ( (uint8_t*)( pxBase ) ) [ offsetof( xType, xField ) + 1 ] = ( uint8_t ) ( ( ( ulValue ) >> 16 ) & 0xff ); \ + ( (uint8_t*)( pxBase ) ) [ offsetof( xType, xField ) + 2 ] = ( uint8_t ) ( ( ( ulValue ) >> 8 ) & 0xff ); \ + ( (uint8_t*)( pxBase ) ) [ offsetof( xType, xField ) + 3 ] = ( uint8_t ) ( ( ulValue ) & 0xff ); \ +} + +#define vFlip_16( left, right ) \ + do { \ + uint16_t tmp = (left); \ + (left) = (right); \ + (right) = tmp; \ + } while (0) + +#define vFlip_32( left, right ) \ + do { \ + uint32_t tmp = (left); \ + (left) = (right); \ + (right) = tmp; \ + } while (0) + +#ifndef ARRAY_SIZE + #define ARRAY_SIZE(x) (BaseType_t)(sizeof(x)/sizeof(x)[0]) +#endif + +/* + * A version of FreeRTOS_GetReleaseNetworkBuffer() that can be called from an + * interrupt. If a non zero value is returned, then the calling ISR should + * perform a context switch before exiting the ISR. + */ +BaseType_t FreeRTOS_ReleaseFreeNetworkBufferFromISR( void ); + +/* + * Create a message that contains a command to initialise the network interface. + * This is used during initialisation, and at any time the network interface + * goes down thereafter. The network interface hardware driver is responsible + * for sending the message that contains the network interface down command/ + * event. + * + * Only use the FreeRTOS_NetworkDownFromISR() version if the function is to be + * called from an interrupt service routine. If FreeRTOS_NetworkDownFromISR() + * returns a non-zero value then a context switch should be performed ebfore + * the interrupt is exited. + */ +void FreeRTOS_NetworkDown( void ); +BaseType_t FreeRTOS_NetworkDownFromISR( void ); + +/* + * Processes incoming ARP packets. + */ +eFrameProcessingResult_t eARPProcessPacket( ARPPacket_t * const pxARPFrame ); + +/* + * Inspect an Ethernet frame to see if it contains data that the stack needs to + * process. eProcessBuffer is returned if the frame should be processed by the + * stack. eReleaseBuffer is returned if the frame should be discarded. + */ +eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer ); + +/* + * Return the checksum generated over xDataLengthBytes from pucNextData. + */ +uint16_t usGenerateChecksum( uint32_t ulSum, const uint8_t * pucNextData, size_t uxDataLengthBytes ); + +/* Socket related private functions. */ + +/* + * The caller must ensure that pxNetworkBuffer->xDataLength is the UDP packet + * payload size (excluding packet headers) and that the packet in pucEthernetBuffer + * is at least the size of UDPPacket_t. + */ +BaseType_t xProcessReceivedUDPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer, uint16_t usPort ); + +/* + * Initialize the socket list data structures for TCP and UDP. + */ +BaseType_t vNetworkSocketsInit( void ); + +/* + * Returns pdTRUE if the IP task has been created and is initialised. Otherwise + * returns pdFALSE. + */ +BaseType_t xIPIsNetworkTaskReady( void ); + +#if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK == 1 ) + struct XSOCKET; + typedef void (*SocketWakeupCallback_t)( struct XSOCKET * pxSocket ); +#endif + +#if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT == 1 ) + struct XSOCKET; + typedef void( *SocketWakeupCallback_t )( struct XSOCKET * pxSocket, void * pvContext ); +#endif + +#if( ipconfigUSE_TCP == 1 ) + + /* + * Actually a user thing, but because xBoundTCPSocketsList, let it do by the + * IP-task + */ + void vTCPNetStat( void ); + + /* + * At least one socket needs to check for timeouts + */ + TickType_t xTCPTimerCheck( BaseType_t xWillSleep ); + + /* Every TCP socket has a buffer space just big enough to store + the last TCP header received. + As a reference of this field may be passed to DMA, force the + alignment to 8 bytes. */ + typedef union + { + struct + { + /* Increase the alignment of this union by adding a 64-bit variable. */ + uint64_t ullAlignmentWord; + } a; + struct + { + /* The next field only serves to give 'ucLastPacket' a correct + alignment of 8 + 2. See comments in FreeRTOS_IP.h */ + uint8_t ucFillPacket[ ipconfigPACKET_FILLER_SIZE ]; + uint8_t ucLastPacket[ sizeof( TCPPacket_t ) ]; + } u; + } LastTCPPacket_t; + + /* + * Note that the values of all short and long integers in these structs + * are being stored in the native-endian way + * Translation should take place when accessing any structure which defines + * network packets, such as IPHeader_t and TCPHeader_t + */ + typedef struct TCPSOCKET + { + uint32_t ulRemoteIP; /* IP address of remote machine */ + uint16_t usRemotePort; /* Port on remote machine */ + struct { + /* Most compilers do like bit-flags */ + uint32_t + bMssChange : 1, /* This socket has seen a change in MSS */ + bPassAccept : 1, /* when true, this socket may be returned in a call to accept() */ + bPassQueued : 1, /* when true, this socket is an orphan until it gets connected + * Why an orphan? Because it may not be returned in a accept() call until it + * gets the state eESTABLISHED */ + bReuseSocket : 1, /* When a listening socket gets a connection, do not create a new instance but keep on using it */ + bCloseAfterSend : 1,/* As soon as the last byte has been transmitted, finalise the connection + * Useful in e.g. FTP connections, where the last data bytes are sent along with the FIN flag */ + bUserShutdown : 1, /* User requesting a graceful shutdown */ + bCloseRequested : 1,/* Request to finalise the connection */ + bLowWater : 1, /* high-water level has been reached. Cleared as soon as 'rx-count < lo-water' */ + bWinChange : 1, /* The value of bLowWater has changed, must send a window update */ + bSendKeepAlive : 1, /* When this flag is true, a TCP keep-alive message must be send */ + bWaitKeepAlive : 1, /* When this flag is true, a TCP keep-alive reply is expected */ + bConnPrepared : 1, /* Connecting socket: Message has been prepared */ + #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + bConnPassed : 1, /* Connecting socket: Socket has been passed in a successful select() */ + #endif /* ipconfigSUPPORT_SELECT_FUNCTION */ + bFinAccepted : 1, /* This socket has received (or sent) a FIN and accepted it */ + bFinSent : 1, /* We've sent out a FIN */ + bFinRecv : 1, /* We've received a FIN from our peer */ + bFinAcked : 1, /* Our FIN packet has been acked */ + bFinLast : 1, /* The last ACK (after FIN and FIN+ACK) has been sent or will be sent by the peer */ + bRxStopped : 1, /* Application asked to temporarily stop reception */ + bMallocError : 1, /* There was an error allocating a stream */ + bWinScaling : 1; /* A TCP-Window Scaling option was offered and accepted in the SYN phase. */ + } bits; + uint32_t ulHighestRxAllowed; + /* The highest sequence number that we can receive at any moment */ + uint16_t usTimeout; /* Time (in ticks) after which this socket needs attention */ + uint16_t usCurMSS; /* Current Maximum Segment Size */ + uint16_t usInitMSS; /* Initial maximum segment Size */ + uint16_t usChildCount; /* In case of a listening socket: number of connections on this port number */ + uint16_t usBacklog; /* In case of a listening socket: maximum number of concurrent connections on this port number */ + uint8_t ucRepCount; /* Send repeat count, for retransmissions + * This counter is separate from the xmitCount in the + * TCP win segments */ + uint8_t ucTCPState; /* TCP state: see eTCP_STATE */ + struct XSOCKET *pxPeerSocket; /* for server socket: child, for child socket: parent */ + #if( ipconfigTCP_KEEP_ALIVE == 1 ) + uint8_t ucKeepRepCount; + TickType_t xLastAliveTime; + #endif /* ipconfigTCP_KEEP_ALIVE */ + #if( ipconfigTCP_HANG_PROTECTION == 1 ) + TickType_t xLastActTime; + #endif /* ipconfigTCP_HANG_PROTECTION */ + size_t uxLittleSpace; + size_t uxEnoughSpace; + size_t uxRxStreamSize; + size_t uxTxStreamSize; + StreamBuffer_t *rxStream; + StreamBuffer_t *txStream; + #if( ipconfigUSE_TCP_WIN == 1 ) + NetworkBufferDescriptor_t *pxAckMessage; + #endif /* ipconfigUSE_TCP_WIN */ + /* Buffer space to store the last TCP header received. */ + LastTCPPacket_t xPacket; + uint8_t tcpflags; /* TCP flags */ + #if( ipconfigUSE_TCP_WIN != 0 ) + uint8_t ucMyWinScaleFactor; + uint8_t ucPeerWinScaleFactor; + #endif + #if( ipconfigUSE_CALLBACKS == 1 ) + FOnTCPReceive_t pxHandleReceive; /* + * In case of a TCP socket: + * typedef void (* FOnTCPReceive_t) (Socket_t xSocket, void *pData, size_t xLength ); + */ + FOnTCPSent_t pxHandleSent; + FOnConnected_t pxHandleConnected; /* Actually type: typedef void (* FOnConnected_t) (Socket_t xSocket, BaseType_t ulConnected ); */ + #endif /* ipconfigUSE_CALLBACKS */ + uint32_t ulWindowSize; /* Current Window size advertised by peer */ + size_t uxRxWinSize; /* Fixed value: size of the TCP reception window */ + size_t uxTxWinSize; /* Fixed value: size of the TCP transmit window */ + + TCPWindow_t xTCPWindow; + } IPTCPSocket_t; + +#endif /* ipconfigUSE_TCP */ + +typedef struct UDPSOCKET +{ + List_t xWaitingPacketsList; /* Incoming packets */ + #if( ipconfigUDP_MAX_RX_PACKETS > 0 ) + UBaseType_t uxMaxPackets; /* Protection: limits the number of packets buffered per socket */ + #endif /* ipconfigUDP_MAX_RX_PACKETS */ + #if( ipconfigUSE_CALLBACKS == 1 ) + FOnUDPReceive_t pxHandleReceive; /* + * In case of a UDP socket: + * typedef void (* FOnUDPReceive_t) (Socket_t xSocket, void *pData, size_t xLength, struct freertos_sockaddr *pxAddr ); + */ + FOnUDPSent_t pxHandleSent; + #endif /* ipconfigUSE_CALLBACKS */ +} IPUDPSocket_t; + +typedef enum eSOCKET_EVENT { + eSOCKET_RECEIVE = 0x0001, + eSOCKET_SEND = 0x0002, + eSOCKET_ACCEPT = 0x0004, + eSOCKET_CONNECT = 0x0008, + eSOCKET_BOUND = 0x0010, + eSOCKET_CLOSED = 0x0020, + eSOCKET_INTR = 0x0040, + eSOCKET_ALL = 0x007F, +} eSocketEvent_t; + +typedef struct XSOCKET +{ + EventBits_t xEventBits; + EventGroupHandle_t xEventGroup; + + ListItem_t xBoundSocketListItem; /* Used to reference the socket from a bound sockets list. */ + TickType_t xReceiveBlockTime; /* if recv[to] is called while no data is available, wait this amount of time. Unit in clock-ticks */ + TickType_t xSendBlockTime; /* if send[to] is called while there is not enough space to send, wait this amount of time. Unit in clock-ticks */ + + uint16_t usLocalPort; /* Local port on this machine */ + uint8_t ucSocketOptions; + uint8_t ucProtocol; /* choice of FREERTOS_IPPROTO_UDP/TCP */ + #if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 ) + SemaphoreHandle_t pxUserSemaphore; + #endif /* ipconfigSOCKET_HAS_USER_SEMAPHORE */ + #if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK == 1 ) || ( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT == 1 ) + SocketWakeupCallback_t pxUserWakeCallback; + #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK */ + #if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT == 1 ) + void * pvUserWakeCallbackContext; + #endif /* ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT */ + + #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + struct xSOCKET_SET *pxSocketSet; + /* User may indicate which bits are interesting for this socket. */ + EventBits_t xSelectBits; + /* These bits indicate the events which have actually occurred. + They are maintained by the IP-task */ + EventBits_t xSocketBits; + #endif /* ipconfigSUPPORT_SELECT_FUNCTION */ + /* TCP/UDP specific fields: */ + /* Before accessing any member of this structure, it should be confirmed */ + /* that the protocol corresponds with the type of structure */ + + union + { + IPUDPSocket_t xUDP; + #if( ipconfigUSE_TCP == 1 ) + IPTCPSocket_t xTCP; + /* Make sure that xTCP is 8-bytes aligned by + declaring a 64-bit variable in the same union */ + uint64_t ullTCPAlignment; + #endif /* ipconfigUSE_TCP */ + } u; +} FreeRTOS_Socket_t; + +#if( ipconfigUSE_TCP == 1 ) + /* + * Lookup a TCP socket, using a multiple matching: both port numbers and + * return IP address. + */ + FreeRTOS_Socket_t *pxTCPSocketLookup( uint32_t ulLocalIP, UBaseType_t uxLocalPort, uint32_t ulRemoteIP, UBaseType_t uxRemotePort ); + +#endif /* ipconfigUSE_TCP */ + +/* + * Look up a local socket by finding a match with the local port. + */ +FreeRTOS_Socket_t *pxUDPSocketLookup( UBaseType_t uxLocalPort ); + +/* + * Called when the application has generated a UDP packet to send. + */ +void vProcessGeneratedUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer ); + +/* + * Calculate the upper-layer checksum + * Works both for UDP, ICMP and TCP packages + * bOut = true: checksum will be set in outgoing packets + * bOut = false: checksum will be calculated for incoming packets + * returning 0xffff means: checksum was correct + */ +uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, size_t uxBufferLength, BaseType_t xOutgoingPacket ); + +/* + * An Ethernet frame has been updated (maybe it was an ARP request or a PING + * request?) and is to be sent back to its source. + */ +void vReturnEthernetFrame( NetworkBufferDescriptor_t * pxNetworkBuffer, BaseType_t xReleaseAfterSend ); + +/* + * The internal version of bind() + * If 'ulInternal' is true, it is called by the driver + * The TCP driver needs to bind a socket at the moment a listening socket + * creates a new connected socket + */ +BaseType_t vSocketBind( FreeRTOS_Socket_t *pxSocket, struct freertos_sockaddr * pxAddress, size_t uxAddressLength, BaseType_t xInternal ); + +/* + * Internal function to add streaming data to a TCP socket. If ulIn == true, + * data will be added to the rxStream, otherwise to the tXStream. Normally data + * will be written with ulOffset == 0, meaning: at the end of the FIFO. When + * packet come in out-of-order, an offset will be used to put it in front and + * the head will not change yet. + */ +int32_t lTCPAddRxdata(FreeRTOS_Socket_t *pxSocket, size_t uxOffset, const uint8_t *pcData, uint32_t ulByteCount); + +/* + * Currently called for any important event. + */ +void vSocketWakeUpUser( FreeRTOS_Socket_t *pxSocket ); + +/* + * Some helping function, their meaning should be clear + */ +static portINLINE uint32_t ulChar2u32 (const uint8_t *apChr); +static portINLINE uint32_t ulChar2u32 (const uint8_t *apChr) +{ + return ( ( ( uint32_t )apChr[0] ) << 24) | + ( ( ( uint32_t )apChr[1] ) << 16) | + ( ( ( uint32_t )apChr[2] ) << 8) | + ( ( ( uint32_t )apChr[3] ) ); +} + +static portINLINE uint16_t usChar2u16 (const uint8_t *apChr); +static portINLINE uint16_t usChar2u16 (const uint8_t *apChr) +{ + return ( uint16_t ) + ( ( ( ( uint32_t )apChr[0] ) << 8) | + ( ( ( uint32_t )apChr[1] ) ) ); +} + +/* Check a single socket for retransmissions and timeouts */ +BaseType_t xTCPSocketCheck( FreeRTOS_Socket_t *pxSocket ); + +BaseType_t xTCPCheckNewClient( FreeRTOS_Socket_t *pxSocket ); + +/* Defined in FreeRTOS_Sockets.c + * Close a socket + */ +void *vSocketClose( FreeRTOS_Socket_t *pxSocket ); + +/* + * Send the event eEvent to the IP task event queue, using a block time of + * zero. Return pdPASS if the message was sent successfully, otherwise return + * pdFALSE. +*/ +BaseType_t xSendEventToIPTask( eIPEvent_t eEvent ); + +/* + * The same as above, but a struct as a parameter, containing: + * eIPEvent_t eEventType; + * void *pvData; + */ +BaseType_t xSendEventStructToIPTask( const IPStackEvent_t *pxEvent, TickType_t xTimeout ); + +/* + * Returns a pointer to the original NetworkBuffer from a pointer to a UDP + * payload buffer. + */ +NetworkBufferDescriptor_t *pxUDPPayloadBuffer_to_NetworkBuffer( void *pvBuffer ); + +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + /* + * For the case where the network driver passes a buffer directly to a DMA + * descriptor, this function can be used to translate a 'network buffer' to + * a 'network buffer descriptor'. + */ + NetworkBufferDescriptor_t *pxPacketBuffer_to_NetworkBuffer( const void *pvBuffer ); +#endif + +/* + * Internal: Sets a new state for a TCP socket and performs the necessary + * actions like calling a OnConnected handler to notify the socket owner. + */ +#if( ipconfigUSE_TCP == 1 ) + void vTCPStateChange( FreeRTOS_Socket_t *pxSocket, enum eTCP_STATE eTCPState ); +#endif /* ipconfigUSE_TCP */ + +/*_RB_ Should this be part of the public API? */ +void FreeRTOS_netstat( void ); + +/* Returns pdTRUE is this function is called from the IP-task */ +BaseType_t xIsCallingFromIPTask( void ); + +#if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + +typedef struct xSOCKET_SET +{ + EventGroupHandle_t xSelectGroup; + BaseType_t bApiCalled; /* True if the API was calling the private vSocketSelect */ + FreeRTOS_Socket_t *pxSocket; +} SocketSelect_t; + +extern void vSocketSelect( SocketSelect_t *pxSocketSelect ); + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION */ + +void vIPSetDHCPTimerEnableState( BaseType_t xEnableState ); +void vIPReloadDHCPTimer( uint32_t ulLeaseTime ); +#if( ipconfigDNS_USE_CALLBACKS != 0 ) + void vIPReloadDNSTimer( uint32_t ulCheckTime ); + void vIPSetDnsTimerEnableState( BaseType_t xEnableState ); +#endif + +/* Send the network-up event and start the ARP timer. */ +void vIPNetworkUpCalls( void ); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* FREERTOS_IP_PRIVATE_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h new file mode 100644 index 000000000..69caa0481 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Sockets.h @@ -0,0 +1,391 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef FREERTOS_SOCKETS_H +#define FREERTOS_SOCKETS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Standard includes. */ +#include + +/* Application level configuration options. */ +#include "FreeRTOSIPConfig.h" + +#ifndef FREERTOS_IP_CONFIG_H + #error FreeRTOSIPConfig.h has not been included yet +#endif + +/* Event bit definitions are required by the select functions. */ +#include "event_groups.h" + +#ifndef INC_FREERTOS_H + #error FreeRTOS.h must be included before FreeRTOS_Sockets.h. +#endif + +#ifndef INC_TASK_H + #ifndef TASK_H /* For compatibility with older FreeRTOS versions. */ + #error The FreeRTOS header file task.h must be included before FreeRTOS_Sockets.h. + #endif +#endif + +/* Assigned to an Socket_t variable when the socket is not valid, probably +because it could not be created. */ +#define FREERTOS_INVALID_SOCKET ( ( void * ) ~0U ) + +/* API function error values. As errno is supported, the FreeRTOS sockets +functions return error codes rather than just a pass or fail indication. */ +/* HT: Extended the number of error codes, gave them positive values and if possible +the corresponding found in errno.h +In case of an error, API's will still return negative numbers, e.g. + return -pdFREERTOS_ERRNO_EWOULDBLOCK; +in case an operation would block */ + +/* The following defines are obsolete, please use -pdFREERTOS_ERRNO_Exxx */ + +#define FREERTOS_SOCKET_ERROR ( -1 ) +#define FREERTOS_EWOULDBLOCK ( - pdFREERTOS_ERRNO_EWOULDBLOCK ) +#define FREERTOS_EINVAL ( - pdFREERTOS_ERRNO_EINVAL ) +#define FREERTOS_EADDRNOTAVAIL ( - pdFREERTOS_ERRNO_EADDRNOTAVAIL ) +#define FREERTOS_EADDRINUSE ( - pdFREERTOS_ERRNO_EADDRINUSE ) +#define FREERTOS_ENOBUFS ( - pdFREERTOS_ERRNO_ENOBUFS ) +#define FREERTOS_ENOPROTOOPT ( - pdFREERTOS_ERRNO_ENOPROTOOPT ) +#define FREERTOS_ECLOSED ( - pdFREERTOS_ERRNO_ENOTCONN ) + +/* Values for the parameters to FreeRTOS_socket(), inline with the Berkeley +standard. See the documentation of FreeRTOS_socket() for more information. */ +#define FREERTOS_AF_INET ( 2 ) +#define FREERTOS_AF_INET6 ( 10 ) +#define FREERTOS_SOCK_DGRAM ( 2 ) +#define FREERTOS_IPPROTO_UDP ( 17 ) + +#define FREERTOS_SOCK_STREAM ( 1 ) +#define FREERTOS_IPPROTO_TCP ( 6 ) +/* IP packet of type "Any local network" + * can be used in stead of TCP for testing with sockets in raw mode + */ +#define FREERTOS_IPPROTO_USR_LAN ( 63 ) + +/* A bit value that can be passed into the FreeRTOS_sendto() function as part of +the flags parameter. Setting the FREERTOS_ZERO_COPY in the flags parameter +indicates that the zero copy interface is being used. See the documentation for +FreeRTOS_sockets() for more information. */ +#define FREERTOS_ZERO_COPY ( 1 ) + +/* Values that can be passed in the option name parameter of calls to +FreeRTOS_setsockopt(). */ +#define FREERTOS_SO_RCVTIMEO ( 0 ) /* Used to set the receive time out. */ +#define FREERTOS_SO_SNDTIMEO ( 1 ) /* Used to set the send time out. */ +#define FREERTOS_SO_UDPCKSUM_OUT ( 2 ) /* Used to turn the use of the UDP checksum by a socket on or off. This also doubles as part of an 8-bit bitwise socket option. */ +#if( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 ) + #define FREERTOS_SO_SET_SEMAPHORE ( 3 ) /* Used to set a user's semaphore */ +#endif +#define FREERTOS_SO_SNDBUF ( 4 ) /* Set the size of the send buffer (TCP only) */ +#define FREERTOS_SO_RCVBUF ( 5 ) /* Set the size of the receive buffer (TCP only) */ + +#if ipconfigUSE_CALLBACKS == 1 + #define FREERTOS_SO_TCP_CONN_HANDLER ( 6 ) /* Install a callback for (dis) connection events. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ + #define FREERTOS_SO_TCP_RECV_HANDLER ( 7 ) /* Install a callback for receiving TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ + #define FREERTOS_SO_TCP_SENT_HANDLER ( 8 ) /* Install a callback for sending TCP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ + #define FREERTOS_SO_UDP_RECV_HANDLER ( 9 ) /* Install a callback for receiving UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ + #define FREERTOS_SO_UDP_SENT_HANDLER ( 10 ) /* Install a callback for sending UDP data. Supply pointer to 'F_TCP_UDP_Handler_t' (see below) */ +#endif /* ipconfigUSE_CALLBACKS */ + +#define FREERTOS_SO_REUSE_LISTEN_SOCKET ( 11 ) /* When a listening socket gets connected, do not create a new one but re-use it */ +#define FREERTOS_SO_CLOSE_AFTER_SEND ( 12 ) /* As soon as the last byte has been transmitted, finalise the connection */ +#define FREERTOS_SO_WIN_PROPERTIES ( 13 ) /* Set all buffer and window properties in one call, parameter is pointer to WinProperties_t */ +#define FREERTOS_SO_SET_FULL_SIZE ( 14 ) /* Refuse to send packets smaller than MSS */ + +#define FREERTOS_SO_STOP_RX ( 15 ) /* Temporarily hold up reception, used by streaming client */ + +#if( ipconfigUDP_MAX_RX_PACKETS > 0 ) + #define FREERTOS_SO_UDP_MAX_RX_PACKETS ( 16 ) /* This option helps to limit the maximum number of packets a UDP socket will buffer */ +#endif + +#if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK == 1 ) || ( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT == 1 ) + #define FREERTOS_SO_WAKEUP_CALLBACK ( 17 ) +#endif + +#define FREERTOS_SO_SET_LOW_HIGH_WATER ( 18 ) + +#if( ipconfigSOCKET_HAS_USER_WAKE_CALLBACK_WITH_CONTEXT == 1 ) + #define FREERTOS_SO_WAKE_CALLBACK_CONTEXT ( 19 ) +#endif + +#define FREERTOS_NOT_LAST_IN_FRAGMENTED_PACKET ( 0x80 ) /* For internal use only, but also part of an 8-bit bitwise value. */ +#define FREERTOS_FRAGMENTED_PACKET ( 0x40 ) /* For internal use only, but also part of an 8-bit bitwise value. */ + +/* Values for flag for FreeRTOS_shutdown(). */ +#define FREERTOS_SHUT_RD ( 0 ) /* Not really at this moment, just for compatibility of the interface */ +#define FREERTOS_SHUT_WR ( 1 ) +#define FREERTOS_SHUT_RDWR ( 2 ) + +/* Values for flag for FreeRTOS_recv(). */ +#define FREERTOS_MSG_OOB ( 2 ) /* process out-of-band data */ +#define FREERTOS_MSG_PEEK ( 4 ) /* peek at incoming message */ +#define FREERTOS_MSG_DONTROUTE ( 8 ) /* send without using routing tables */ +#define FREERTOS_MSG_DONTWAIT ( 16 ) /* Can be used with recvfrom(), sendto(), recv(), and send(). */ + +typedef struct xWIN_PROPS { + /* Properties of the Tx buffer and Tx window */ + int32_t lTxBufSize; /* Unit: bytes */ + int32_t lTxWinSize; /* Unit: MSS */ + + /* Properties of the Rx buffer and Rx window */ + int32_t lRxBufSize; /* Unit: bytes */ + int32_t lRxWinSize; /* Unit: MSS */ +} WinProperties_t; + +typedef struct xLOW_HIGH_WATER { + /* Structure to pass for the 'FREERTOS_SO_SET_LOW_HIGH_WATER' option */ + size_t uxLittleSpace; /* Send a STOP when buffer space drops below X bytes */ + size_t uxEnoughSpace; /* Send a GO when buffer space grows above X bytes */ +} LowHighWater_t; + +/* For compatibility with the expected Berkeley sockets naming. */ +#define socklen_t uint32_t + +/* For this limited implementation, only two members are required in the +Berkeley style sockaddr structure. */ +struct freertos_sockaddr +{ + /* _HT_ On 32- and 64-bit architectures, the addition of the two uint8_t + fields doesn't make the structure bigger, due to alignment. + The fields are inserted as a preparation for IPv6. */ + + /* sin_len and sin_family not used in the IPv4-only release. */ + uint8_t sin_len; /* length of this structure. */ + uint8_t sin_family; /* FREERTOS_AF_INET. */ + uint16_t sin_port; + uint32_t sin_addr; +}; + +#if ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN + + #define FreeRTOS_inet_addr_quick( ucOctet0, ucOctet1, ucOctet2, ucOctet3 ) \ + ( ( ( ( uint32_t ) ( ucOctet3 ) ) << 24UL ) | \ + ( ( ( uint32_t ) ( ucOctet2 ) ) << 16UL ) | \ + ( ( ( uint32_t ) ( ucOctet1 ) ) << 8UL ) | \ + ( ( uint32_t ) ( ucOctet0 ) ) ) + + #define FreeRTOS_inet_ntoa( ulIPAddress, pucBuffer ) \ + sprintf( ( char * ) ( pucBuffer ), "%u.%u.%u.%u", \ + ( ( unsigned ) ( ( ulIPAddress ) & 0xffUL ) ), \ + ( ( unsigned ) ( ( ( ulIPAddress ) >> 8 ) & 0xffUL ) ), \ + ( ( unsigned ) ( ( ( ulIPAddress ) >> 16 ) & 0xffUL ) ),\ + ( ( unsigned ) ( ( ulIPAddress ) >> 24 ) ) ) + +#else /* ipconfigBYTE_ORDER */ + + #define FreeRTOS_inet_addr_quick( ucOctet0, ucOctet1, ucOctet2, ucOctet3 ) \ + ( ( ( ( uint32_t ) ( ucOctet0 ) ) << 24UL ) | \ + ( ( ( uint32_t ) ( ucOctet1 ) ) << 16UL ) | \ + ( ( ( uint32_t ) ( ucOctet2 ) ) << 8UL ) | \ + ( ( uint32_t ) ( ucOctet3 ) ) ) + + #define FreeRTOS_inet_ntoa( ulIPAddress, pucBuffer ) \ + sprintf( ( char * ) ( pucBuffer ), "%u.%u.%u.%u", \ + ( ( unsigned ) ( ( ulIPAddress ) >> 24 ) ), \ + ( ( unsigned ) ( ( ( ulIPAddress ) >> 16 ) & 0xffUL ) ),\ + ( ( unsigned ) ( ( ( ulIPAddress ) >> 8 ) & 0xffUL ) ), \ + ( ( unsigned ) ( ( ulIPAddress ) & 0xffUL ) ) ) + +#endif /* ipconfigBYTE_ORDER */ + +/* The socket type itself. */ +typedef void *Socket_t; + +/* The SocketSet_t type is the equivalent to the fd_set type used by the +Berkeley API. */ +typedef void *SocketSet_t; + +/** + * FULL, UP-TO-DATE AND MAINTAINED REFERENCE DOCUMENTATION FOR ALL THESE + * FUNCTIONS IS AVAILABLE ON THE FOLLOWING URL: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/FreeRTOS_TCP_API_Functions.html + */ +Socket_t FreeRTOS_socket( BaseType_t xDomain, BaseType_t xType, BaseType_t xProtocol ); +int32_t FreeRTOS_recvfrom( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags, struct freertos_sockaddr *pxSourceAddress, socklen_t *pxSourceAddressLength ); +int32_t FreeRTOS_sendto( Socket_t xSocket, const void *pvBuffer, size_t xTotalDataLength, BaseType_t xFlags, const struct freertos_sockaddr *pxDestinationAddress, socklen_t xDestinationAddressLength ); +BaseType_t FreeRTOS_bind( Socket_t xSocket, struct freertos_sockaddr *pxAddress, socklen_t xAddressLength ); + +/* function to get the local address and IP port */ +size_t FreeRTOS_GetLocalAddress( Socket_t xSocket, struct freertos_sockaddr *pxAddress ); + +/* Made available when ipconfigETHERNET_DRIVER_FILTERS_PACKETS is set to 1. */ +BaseType_t xPortHasUDPSocket( uint16_t usPortNr ); + +#if ipconfigUSE_TCP == 1 + +BaseType_t FreeRTOS_connect( Socket_t xClientSocket, struct freertos_sockaddr *pxAddress, socklen_t xAddressLength ); +BaseType_t FreeRTOS_listen( Socket_t xSocket, BaseType_t xBacklog ); +BaseType_t FreeRTOS_recv( Socket_t xSocket, void *pvBuffer, size_t xBufferLength, BaseType_t xFlags ); +BaseType_t FreeRTOS_send( Socket_t xSocket, const void *pvBuffer, size_t uxDataLength, BaseType_t xFlags ); +Socket_t FreeRTOS_accept( Socket_t xServerSocket, struct freertos_sockaddr *pxAddress, socklen_t *pxAddressLength ); +BaseType_t FreeRTOS_shutdown (Socket_t xSocket, BaseType_t xHow); + +#if( ipconfigSUPPORT_SIGNALS != 0 ) + /* Send a signal to the task which is waiting for a given socket. */ + BaseType_t FreeRTOS_SignalSocket( Socket_t xSocket ); + + /* Send a signal to the task which reads from this socket (FromISR + version). */ + BaseType_t FreeRTOS_SignalSocketFromISR( Socket_t xSocket, BaseType_t *pxHigherPriorityTaskWoken ); +#endif /* ipconfigSUPPORT_SIGNALS */ + +/* Return the remote address and IP port. */ +BaseType_t FreeRTOS_GetRemoteAddress( Socket_t xSocket, struct freertos_sockaddr *pxAddress ); + +/* returns pdTRUE if TCP socket is connected */ +BaseType_t FreeRTOS_issocketconnected( Socket_t xSocket ); + +/* returns the actual size of MSS being used */ +BaseType_t FreeRTOS_mss( Socket_t xSocket ); + +/* for internal use only: return the connection status */ +BaseType_t FreeRTOS_connstatus( Socket_t xSocket ); + +/* Returns the number of bytes that may be added to txStream */ +BaseType_t FreeRTOS_maywrite( Socket_t xSocket ); + +/* + * Two helper functions, mostly for testing + * rx_size returns the number of bytes available in the Rx buffer + * tx_space returns the free space in the Tx buffer + */ +BaseType_t FreeRTOS_rx_size( Socket_t xSocket ); +BaseType_t FreeRTOS_tx_space( Socket_t xSocket ); +BaseType_t FreeRTOS_tx_size( Socket_t xSocket ); + +/* Returns the number of outstanding bytes in txStream. */ +/* The function FreeRTOS_outstanding() was already implemented +FreeRTOS_tx_size(). */ +#define FreeRTOS_outstanding( xSocket ) FreeRTOS_tx_size( xSocket ) + +/* Returns the number of bytes in the socket's rxStream. */ +/* The function FreeRTOS_recvcount() was already implemented +FreeRTOS_rx_size(). */ +#define FreeRTOS_recvcount( xSocket ) FreeRTOS_rx_size( xSocket ) + +/* + * For advanced applications only: + * Get a direct pointer to the circular transmit buffer. + * '*pxLength' will contain the number of bytes that may be written. + */ +uint8_t *FreeRTOS_get_tx_head( Socket_t xSocket, BaseType_t *pxLength ); + +#endif /* ipconfigUSE_TCP */ + +/* + * Connect / disconnect handler for a TCP socket + * For example: + * static void vMyConnectHandler (Socket_t xSocket, BaseType_t ulConnected) + * { + * } + * F_TCP_UDP_Handler_t xHnd = { vMyConnectHandler }; + * FreeRTOS_setsockopt( sock, 0, FREERTOS_SO_TCP_CONN_HANDLER, ( void * ) &xHnd, sizeof( xHnd ) ); + */ + +typedef void (* FOnConnected_t )( Socket_t /* xSocket */, BaseType_t /* ulConnected */ ); + +/* + * Reception handler for a TCP socket + * A user-proved function will be called on reception of a message + * If the handler returns a positive number, the messages will not be stored + * For example: + * static BaseType_t xOnTCPReceive( Socket_t xSocket, void * pData, size_t xLength ) + * { + * // handle the message + * return 1; + * } + * F_TCP_UDP_Handler_t xHand = { xOnTCPReceive }; + * FreeRTOS_setsockopt( sock, 0, FREERTOS_SO_TCP_RECV_HANDLER, ( void * ) &xHand, sizeof( xHand ) ); + */ +typedef BaseType_t (* FOnTCPReceive_t )( Socket_t /* xSocket */, void * /* pData */, size_t /* xLength */ ); +typedef void (* FOnTCPSent_t )( Socket_t /* xSocket */, size_t /* xLength */ ); + +/* + * Reception handler for a UDP socket + * A user-proved function will be called on reception of a message + * If the handler returns a positive number, the messages will not be stored + */ +typedef BaseType_t (* FOnUDPReceive_t ) (Socket_t /* xSocket */, void * /* pData */, size_t /* xLength */, + const struct freertos_sockaddr * /* pxFrom */, const struct freertos_sockaddr * /* pxDest */ ); +typedef void (* FOnUDPSent_t )( Socket_t /* xSocket */, size_t /* xLength */ ); + + +typedef union xTCP_UDP_HANDLER +{ + FOnConnected_t pxOnTCPConnected; /* FREERTOS_SO_TCP_CONN_HANDLER */ + FOnTCPReceive_t pxOnTCPReceive; /* FREERTOS_SO_TCP_RECV_HANDLER */ + FOnTCPSent_t pxOnTCPSent; /* FREERTOS_SO_TCP_SENT_HANDLER */ + FOnUDPReceive_t pxOnUDPReceive; /* FREERTOS_SO_UDP_RECV_HANDLER */ + FOnUDPSent_t pxOnUDPSent; /* FREERTOS_SO_UDP_SENT_HANDLER */ +} F_TCP_UDP_Handler_t; + +BaseType_t FreeRTOS_setsockopt( Socket_t xSocket, int32_t lLevel, int32_t lOptionName, const void *pvOptionValue, size_t xOptionLength ); +BaseType_t FreeRTOS_closesocket( Socket_t xSocket ); +uint32_t FreeRTOS_gethostbyname( const char *pcHostName ); +uint32_t FreeRTOS_inet_addr( const char * pcIPAddress ); + +/* + * For the web server: borrow the circular Rx buffer for inspection + * HTML driver wants to see if a sequence of 13/10/13/10 is available + */ +const struct xSTREAM_BUFFER *FreeRTOS_get_rx_buf( Socket_t xSocket ); + +void FreeRTOS_netstat( void ); + +#if ipconfigSUPPORT_SELECT_FUNCTION == 1 + + /* For FD_SET and FD_CLR, a combination of the following bits can be used: */ + + typedef enum eSELECT_EVENT { + eSELECT_READ = 0x0001, + eSELECT_WRITE = 0x0002, + eSELECT_EXCEPT = 0x0004, + eSELECT_INTR = 0x0008, + eSELECT_ALL = 0x000F, + /* Reserved for internal use: */ + eSELECT_CALL_IP = 0x0010, + /* end */ + } eSelectEvent_t; + + SocketSet_t FreeRTOS_CreateSocketSet( void ); + void FreeRTOS_DeleteSocketSet( SocketSet_t xSocketSet ); + void FreeRTOS_FD_SET( Socket_t xSocket, SocketSet_t xSocketSet, EventBits_t xBitsToSet ); + void FreeRTOS_FD_CLR( Socket_t xSocket, SocketSet_t xSocketSet, EventBits_t xBitsToClear ); + EventBits_t FreeRTOS_FD_ISSET( Socket_t xSocket, SocketSet_t xSocketSet ); + BaseType_t FreeRTOS_select( SocketSet_t xSocketSet, TickType_t xBlockTimeTicks ); + +#endif /* ipconfigSUPPORT_SELECT_FUNCTION */ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* FREERTOS_SOCKETS_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h new file mode 100644 index 000000000..43d1a9745 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_Stream_Buffer.h @@ -0,0 +1,256 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* + * FreeRTOS_Stream_Buffer.h + * + * A cicular character buffer + * An implementation of a circular buffer without a length field + * If LENGTH defines the size of the buffer, a maximum of (LENGT-1) bytes can be stored + * In order to add or read data from the buffer, memcpy() will be called at most 2 times + */ + +#ifndef FREERTOS_STREAM_BUFFER_H +#define FREERTOS_STREAM_BUFFER_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct xSTREAM_BUFFER { + volatile size_t uxTail; /* next item to read */ + volatile size_t uxMid; /* iterator within the valid items */ + volatile size_t uxHead; /* next position store a new item */ + volatile size_t uxFront; /* iterator within the free space */ + size_t LENGTH; /* const value: number of reserved elements */ + uint8_t ucArray[ sizeof( size_t ) ]; +} StreamBuffer_t; + +static portINLINE void vStreamBufferClear( StreamBuffer_t *pxBuffer ); +static portINLINE void vStreamBufferClear( StreamBuffer_t *pxBuffer ) +{ + /* Make the circular buffer empty */ + pxBuffer->uxHead = 0u; + pxBuffer->uxTail = 0u; + pxBuffer->uxFront = 0u; + pxBuffer->uxMid = 0u; +} +/*-----------------------------------------------------------*/ + +static portINLINE size_t uxStreamBufferSpace( const StreamBuffer_t *pxBuffer, const size_t uxLower, const size_t uxUpper ); +static portINLINE size_t uxStreamBufferSpace( const StreamBuffer_t *pxBuffer, const size_t uxLower, const size_t uxUpper ) +{ +/* Returns the space between uxLower and uxUpper, which equals to the distance minus 1 */ +size_t uxCount; + + uxCount = pxBuffer->LENGTH + uxUpper - uxLower - 1u; + if( uxCount >= pxBuffer->LENGTH ) + { + uxCount -= pxBuffer->LENGTH; + } + + return uxCount; +} +/*-----------------------------------------------------------*/ + +static portINLINE size_t uxStreamBufferDistance( const StreamBuffer_t *pxBuffer, const size_t uxLower, const size_t uxUpper ); +static portINLINE size_t uxStreamBufferDistance( const StreamBuffer_t *pxBuffer, const size_t uxLower, const size_t uxUpper ) +{ +/* Returns the distance between uxLower and uxUpper */ +size_t uxCount; + + uxCount = pxBuffer->LENGTH + uxUpper - uxLower; + if ( uxCount >= pxBuffer->LENGTH ) + { + uxCount -= pxBuffer->LENGTH; + } + + return uxCount; +} +/*-----------------------------------------------------------*/ + +static portINLINE size_t uxStreamBufferGetSpace( const StreamBuffer_t *pxBuffer ); +static portINLINE size_t uxStreamBufferGetSpace( const StreamBuffer_t *pxBuffer ) +{ +/* Returns the number of items which can still be added to uxHead +before hitting on uxTail */ +size_t uxHead = pxBuffer->uxHead; +size_t uxTail = pxBuffer->uxTail; + + return uxStreamBufferSpace( pxBuffer, uxHead, uxTail ); +} +/*-----------------------------------------------------------*/ + +static portINLINE size_t uxStreamBufferFrontSpace( const StreamBuffer_t *pxBuffer ); +static portINLINE size_t uxStreamBufferFrontSpace( const StreamBuffer_t *pxBuffer ) +{ +/* Distance between uxFront and uxTail +or the number of items which can still be added to uxFront, +before hitting on uxTail */ + +size_t uxFront = pxBuffer->uxFront; +size_t uxTail = pxBuffer->uxTail; + + return uxStreamBufferSpace( pxBuffer, uxFront, uxTail ); +} +/*-----------------------------------------------------------*/ + +static portINLINE size_t uxStreamBufferGetSize( const StreamBuffer_t *pxBuffer ); +static portINLINE size_t uxStreamBufferGetSize( const StreamBuffer_t *pxBuffer ) +{ +/* Returns the number of items which can be read from uxTail +before reaching uxHead */ +size_t uxHead = pxBuffer->uxHead; +size_t uxTail = pxBuffer->uxTail; + + return uxStreamBufferDistance( pxBuffer, uxTail, uxHead ); +} +/*-----------------------------------------------------------*/ + +static portINLINE size_t uxStreamBufferMidSpace( const StreamBuffer_t *pxBuffer ); +static portINLINE size_t uxStreamBufferMidSpace( const StreamBuffer_t *pxBuffer ) +{ +/* Returns the distance between uxHead and uxMid */ +size_t uxHead = pxBuffer->uxHead; +size_t uxMid = pxBuffer->uxMid; + + return uxStreamBufferDistance( pxBuffer, uxMid, uxHead ); +} +/*-----------------------------------------------------------*/ + +static portINLINE void vStreamBufferMoveMid( StreamBuffer_t *pxBuffer, size_t uxCount ); +static portINLINE void vStreamBufferMoveMid( StreamBuffer_t *pxBuffer, size_t uxCount ) +{ +/* Increment uxMid, but no further than uxHead */ +size_t uxSize = uxStreamBufferMidSpace( pxBuffer ); + + if( uxCount > uxSize ) + { + uxCount = uxSize; + } + pxBuffer->uxMid += uxCount; + if( pxBuffer->uxMid >= pxBuffer->LENGTH ) + { + pxBuffer->uxMid -= pxBuffer->LENGTH; + } +} +/*-----------------------------------------------------------*/ +static portINLINE BaseType_t xStreamBufferIsEmpty( const StreamBuffer_t *pxBuffer ); +static portINLINE BaseType_t xStreamBufferIsEmpty( const StreamBuffer_t *pxBuffer ) +{ +BaseType_t xReturn; + + /* True if no item is available */ + if( pxBuffer->uxHead == pxBuffer->uxTail ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + return xReturn; +} +/*-----------------------------------------------------------*/ + +static portINLINE BaseType_t xStreamBufferIsFull( const StreamBuffer_t *pxBuffer ); +static portINLINE BaseType_t xStreamBufferIsFull( const StreamBuffer_t *pxBuffer ) +{ + /* True if the available space equals zero. */ + return ( BaseType_t ) ( uxStreamBufferGetSpace( pxBuffer ) == 0u ); +} +/*-----------------------------------------------------------*/ + +static portINLINE BaseType_t xStreamBufferLessThenEqual( const StreamBuffer_t *pxBuffer, const size_t uxLeft, const size_t uxRight ); +static portINLINE BaseType_t xStreamBufferLessThenEqual( const StreamBuffer_t *pxBuffer, const size_t uxLeft, const size_t uxRight ) +{ +BaseType_t xReturn; +size_t uxTail = pxBuffer->uxTail; + + /* Returns true if ( uxLeft < uxRight ) */ + if( ( uxLeft < uxTail ) ^ ( uxRight < uxTail ) ) + { + if( uxRight < uxTail ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + else + { + if( uxLeft <= uxRight ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + return xReturn; +} +/*-----------------------------------------------------------*/ + +static portINLINE size_t uxStreamBufferGetPtr( StreamBuffer_t *pxBuffer, uint8_t **ppucData ); +static portINLINE size_t uxStreamBufferGetPtr( StreamBuffer_t *pxBuffer, uint8_t **ppucData ) +{ +size_t uxNextTail = pxBuffer->uxTail; +size_t uxSize = uxStreamBufferGetSize( pxBuffer ); + + *ppucData = pxBuffer->ucArray + uxNextTail; + + return FreeRTOS_min_uint32( uxSize, pxBuffer->LENGTH - uxNextTail ); +} + +/* + * Add bytes to a stream buffer. + * + * pxBuffer - The buffer to which the bytes will be added. + * uxOffset - If uxOffset > 0, data will be written at an offset from uxHead + * while uxHead will not be moved yet. + * pucData - A pointer to the data to be added. + * uxCount - The number of bytes to add. + */ +size_t uxStreamBufferAdd( StreamBuffer_t *pxBuffer, size_t uxOffset, const uint8_t *pucData, size_t uxCount ); + +/* + * Read bytes from a stream buffer. + * + * pxBuffer - The buffer from which the bytes will be read. + * uxOffset - Can be used to read data located at a certain offset from 'uxTail'. + * pucData - A pointer to the buffer into which data will be read. + * uxMaxCount - The number of bytes to read. + * xPeek - If set to pdTRUE the data will remain in the buffer. + */ +size_t uxStreamBufferGet( StreamBuffer_t *pxBuffer, size_t uxOffset, uint8_t *pucData, size_t uxMaxCount, BaseType_t xPeek ); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* !defined( FREERTOS_STREAM_BUFFER_H ) */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h new file mode 100644 index 000000000..4a94d2d83 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_IP.h @@ -0,0 +1,80 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef FREERTOS_TCP_IP_H +#define FREERTOS_TCP_IP_H + +#ifdef __cplusplus +extern "C" { +#endif + +BaseType_t xProcessReceivedTCPPacket( NetworkBufferDescriptor_t *pxNetworkBuffer ); + +typedef enum eTCP_STATE { + /* Comments about the TCP states are borrowed from the very useful + * Wiki page: + * http://en.wikipedia.org/wiki/Transmission_Control_Protocol */ + eCLOSED = 0u, /* 0 (server + client) no connection state at all. */ + eTCP_LISTEN, /* 1 (server) waiting for a connection request + from any remote TCP and port. */ + eCONNECT_SYN, /* 2 (client) internal state: socket wants to send + a connect */ + eSYN_FIRST, /* 3 (server) Just created, must ACK the SYN request. */ + eSYN_RECEIVED, /* 4 (server) waiting for a confirming connection request + acknowledgement after having both received and sent a connection request. */ + eESTABLISHED, /* 5 (server + client) an open connection, data received can be + delivered to the user. The normal state for the data transfer phase of the connection. */ + eFIN_WAIT_1, /* 6 (server + client) waiting for a connection termination request from the remote TCP, + or an acknowledgement of the connection termination request previously sent. */ + eFIN_WAIT_2, /* 7 (server + client) waiting for a connection termination request from the remote TCP. */ + eCLOSE_WAIT, /* 8 (server + client) waiting for a connection termination request from the local user. */ + eCLOSING, /* (server + client) waiting for a connection termination request acknowledgement from the remote TCP. */ + eLAST_ACK, /* 9 (server + client) waiting for an acknowledgement of the connection termination request + previously sent to the remote TCP + (which includes an acknowledgement of its connection termination request). */ + eTIME_WAIT, /* 10 (either server or client) waiting for enough time to pass to be sure the remote TCP received the + acknowledgement of its connection termination request. [According to RFC 793 a connection can + stay in TIME-WAIT for a maximum of four minutes known as a MSL (maximum segment lifetime).] */ +} eIPTCPState_t; + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* FREERTOS_TCP_IP_H */ + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h new file mode 100644 index 000000000..f1823febc --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_TCP_WIN.h @@ -0,0 +1,213 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* + * FreeRTOS_TCP_WIN.c + * Module which handles the TCP windowing schemes for FreeRTOS-PLUS-TCP + */ + +#ifndef FREERTOS_TCP_WIN_H +#define FREERTOS_TCP_WIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern BaseType_t xTCPWindowLoggingLevel; + +typedef struct xTCPTimer +{ + uint32_t ulBorn; +} TCPTimer_t; + +typedef struct xTCP_SEGMENT +{ + uint32_t ulSequenceNumber; /* The sequence number of the first byte in this packet */ + int32_t lMaxLength; /* Maximum space, number of bytes which can be stored in this segment */ + int32_t lDataLength; /* Actual number of bytes */ + int32_t lStreamPos; /* reference to the [t|r]xStream of the socket */ + TCPTimer_t xTransmitTimer; /* saves a timestamp at the moment this segment gets transmitted (TX only) */ + union + { + struct + { + uint32_t + ucTransmitCount : 8,/* Number of times the segment has been transmitted, used to calculate the RTT */ + ucDupAckCount : 8, /* Counts the number of times that a higher segment was ACK'd. After 3 times a Fast Retransmission takes place */ + bOutstanding : 1, /* It the peer's turn, we're just waiting for an ACK */ + bAcked : 1, /* This segment has been acknowledged */ + bIsForRx : 1; /* pdTRUE if segment is used for reception */ + } bits; + uint32_t ulFlags; + } u; +#if( ipconfigUSE_TCP_WIN != 0 ) + struct xLIST_ITEM xQueueItem; /* TX only: segments can be linked in one of three queues: xPriorityQueue, xTxQueue, and xWaitQueue */ + struct xLIST_ITEM xListItem; /* With this item the segment can be connected to a list, depending on who is owning it */ +#endif +} TCPSegment_t; + +typedef struct xTCP_WINSIZE +{ + uint32_t ulRxWindowLength; + uint32_t ulTxWindowLength; +} TCPWinSize_t; + +/* + * If TCP time-stamps are being used, they will occupy 12 bytes in + * each packet, and thus the message space will become smaller + */ +/* Keep this as a multiple of 4 */ +#if( ipconfigUSE_TCP_WIN == 1 ) + #define ipSIZE_TCP_OPTIONS 16u +#else + #define ipSIZE_TCP_OPTIONS 12u +#endif + +/* + * Every TCP connection owns a TCP window for the administration of all packets + * It owns two sets of segment descriptors, incoming and outgoing + */ +typedef struct xTCP_WINDOW +{ + union + { + struct + { + uint32_t + bHasInit : 1, /* The window structure has been initialised */ + bSendFullSize : 1, /* May only send packets with a size equal to MSS (for optimisation) */ + bTimeStamps : 1; /* Socket is supposed to use TCP time-stamps. This depends on the */ + } bits; /* party which opens the connection */ + uint32_t ulFlags; + } u; + TCPWinSize_t xSize; + struct + { + uint32_t ulFirstSequenceNumber; /* Logging & debug: the first segment received/sent in this connection + * for Tx: initial send sequence number (ISS) + * for Rx: initial receive sequence number (IRS) */ + uint32_t ulCurrentSequenceNumber;/* Tx/Rx: the oldest sequence number not yet confirmed, also SND.UNA / RCV.NXT + * In other words: the sequence number of the left side of the sliding window */ + uint32_t ulFINSequenceNumber; /* The sequence number which carried the FIN flag */ + uint32_t ulHighestSequenceNumber;/* Sequence number of the right-most byte + 1 */ + } rx, tx; + uint32_t ulOurSequenceNumber; /* The SEQ number we're sending out */ + uint32_t ulUserDataLength; /* Number of bytes in Rx buffer which may be passed to the user, after having received a 'missing packet' */ + uint32_t ulNextTxSequenceNumber; /* The sequence number given to the next byte to be added for transmission */ + int32_t lSRTT; /* Smoothed Round Trip Time, it may increment quickly and it decrements slower */ + uint8_t ucOptionLength; /* Number of valid bytes in ulOptionsData[] */ +#if( ipconfigUSE_TCP_WIN == 1 ) + List_t xPriorityQueue; /* Priority queue: segments which must be sent immediately */ + List_t xTxQueue; /* Transmit queue: segments queued for transmission */ + List_t xWaitQueue; /* Waiting queue: outstanding segments */ + TCPSegment_t *pxHeadSegment; /* points to a segment which has not been transmitted and it's size is still growing (user data being added) */ + uint32_t ulOptionsData[ipSIZE_TCP_OPTIONS/sizeof(uint32_t)]; /* Contains the options we send out */ + List_t xTxSegments; /* A linked list of all transmission segments, sorted on sequence number */ + List_t xRxSegments; /* A linked list of reception segments, order depends on sequence of arrival */ +#else + /* For tiny TCP, there is only 1 outstanding TX segment */ + TCPSegment_t xTxSegment; /* Priority queue */ +#endif + uint16_t usOurPortNumber; /* Mostly for debugging/logging: our TCP port number */ + uint16_t usPeerPortNumber; /* debugging/logging: the peer's TCP port number */ + uint16_t usMSS; /* Current accepted MSS */ + uint16_t usMSSInit; /* MSS as configured by the socket owner */ +} TCPWindow_t; + + +/*============================================================================= + * + * Creation and destruction + * + *=============================================================================*/ + +/* Create and initialize a window */ +void vTCPWindowCreate( TCPWindow_t *pxWindow, uint32_t ulRxWindowLength, + uint32_t ulTxWindowLength, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS ); + +/* Destroy a window (always returns NULL) + * It will free some resources: a collection of segments */ +void vTCPWindowDestroy( TCPWindow_t *pxWindow ); + +/* Initialize a window */ +void vTCPWindowInit( TCPWindow_t *pxWindow, uint32_t ulAckNumber, uint32_t ulSequenceNumber, uint32_t ulMSS ); + +/* Clean up allocated segments. Should only be called when FreeRTOS+TCP will no longer be used. */ +void vTCPSegmentCleanup( void ); + +/*============================================================================= + * + * Rx functions + * + *=============================================================================*/ + +/* if true may be passed directly to user (segment expected and window is empty) + * But pxWindow->ackno should always be used to set "BUF->ackno" */ +int32_t lTCPWindowRxCheck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength, uint32_t ulSpace ); + +/* When lTCPWindowRxCheck returned false, please call store for this unexpected data */ +BaseType_t xTCPWindowRxStore( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber, uint32_t ulLength ); + +/* This function will be called as soon as a FIN is received. It will return true + * if there are no 'open' reception segments */ +BaseType_t xTCPWindowRxEmpty( TCPWindow_t *pxWindow ); + +/* _HT_ Temporary function for testing/debugging + * Not used at this moment */ +void vTCPWinShowSegments( TCPWindow_t *pxWindow, BaseType_t bForRx ); + +/*============================================================================= + * + * Tx functions + * + *=============================================================================*/ + +/* Adds data to the Tx-window */ +int32_t lTCPWindowTxAdd( TCPWindow_t *pxWindow, uint32_t ulLength, int32_t lPosition, int32_t lMax ); + +/* Check data to be sent and calculate the time period we may sleep */ +BaseType_t xTCPWindowTxHasData( TCPWindow_t *pxWindow, uint32_t ulWindowSize, TickType_t *pulDelay ); + +/* See if anything is left to be sent + * Function will be called when a FIN has been received. Only when the TX window is clean, + * it will return pdTRUE */ +BaseType_t xTCPWindowTxDone( TCPWindow_t *pxWindow ); + +/* Fetches data to be sent. + * apPos will point to a location with the circular data buffer: txStream */ +uint32_t ulTCPWindowTxGet( TCPWindow_t *pxWindow, uint32_t ulWindowSize, int32_t *plPosition ); + +/* Receive a normal ACK */ +uint32_t ulTCPWindowTxAck( TCPWindow_t *pxWindow, uint32_t ulSequenceNumber ); + +/* Receive a SACK option */ +uint32_t ulTCPWindowTxSack( TCPWindow_t *pxWindow, uint32_t ulFirst, uint32_t ulLast ); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* FREERTOS_TCP_WIN_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h new file mode 100644 index 000000000..0ae5fb5a4 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_UDP_IP.h @@ -0,0 +1,56 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef FREERTOS_UDP_IP_H +#define FREERTOS_UDP_IP_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Application level configuration options. */ +#include "FreeRTOSIPConfig.h" +#include "FreeRTOSIPConfigDefaults.h" +#include "IPTraceMacroDefaults.h" + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* FREERTOS_UDP_IP_H */ + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h new file mode 100644 index 000000000..60708a04b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/FreeRTOS_errno_TCP.h @@ -0,0 +1,90 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef FREERTOS_ERRNO_TCP +#define FREERTOS_ERRNO_TCP + +/* The following definitions will be included in the core FreeRTOS code in +future versions of FreeRTOS - hence the 'pd' (ProjDefs) prefix - at which time +this file will be removed. */ + +/* The following errno values are used by FreeRTOS+ components, not FreeRTOS +itself. */ + +/* For future compatibility (see comment above), check the definitions have not +already been made. */ +#ifndef pdFREERTOS_ERRNO_NONE + #define pdFREERTOS_ERRNO_NONE 0 /* No errors */ + #define pdFREERTOS_ERRNO_ENOENT 2 /* No such file or directory */ + #define pdFREERTOS_ERRNO_EINTR 4 /* Interrupted system call */ + #define pdFREERTOS_ERRNO_EIO 5 /* I/O error */ + #define pdFREERTOS_ERRNO_ENXIO 6 /* No such device or address */ + #define pdFREERTOS_ERRNO_EBADF 9 /* Bad file number */ + #define pdFREERTOS_ERRNO_EAGAIN 11 /* No more processes */ + #define pdFREERTOS_ERRNO_EWOULDBLOCK 11 /* Operation would block */ + #define pdFREERTOS_ERRNO_ENOMEM 12 /* Not enough memory */ + #define pdFREERTOS_ERRNO_EACCES 13 /* Permission denied */ + #define pdFREERTOS_ERRNO_EFAULT 14 /* Bad address */ + #define pdFREERTOS_ERRNO_EBUSY 16 /* Mount device busy */ + #define pdFREERTOS_ERRNO_EEXIST 17 /* File exists */ + #define pdFREERTOS_ERRNO_EXDEV 18 /* Cross-device link */ + #define pdFREERTOS_ERRNO_ENODEV 19 /* No such device */ + #define pdFREERTOS_ERRNO_ENOTDIR 20 /* Not a directory */ + #define pdFREERTOS_ERRNO_EISDIR 21 /* Is a directory */ + #define pdFREERTOS_ERRNO_EINVAL 22 /* Invalid argument */ + #define pdFREERTOS_ERRNO_ENOSPC 28 /* No space left on device */ + #define pdFREERTOS_ERRNO_ESPIPE 29 /* Illegal seek */ + #define pdFREERTOS_ERRNO_EROFS 30 /* Read only file system */ + #define pdFREERTOS_ERRNO_EUNATCH 42 /* Protocol driver not attached */ + #define pdFREERTOS_ERRNO_EBADE 50 /* Invalid exchange */ + #define pdFREERTOS_ERRNO_EFTYPE 79 /* Inappropriate file type or format */ + #define pdFREERTOS_ERRNO_ENMFILE 89 /* No more files */ + #define pdFREERTOS_ERRNO_ENOTEMPTY 90 /* Directory not empty */ + #define pdFREERTOS_ERRNO_ENAMETOOLONG 91 /* File or path name too long */ + #define pdFREERTOS_ERRNO_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ + #define pdFREERTOS_ERRNO_ENOBUFS 105 /* No buffer space available */ + #define pdFREERTOS_ERRNO_ENOPROTOOPT 109 /* Protocol not available */ + #define pdFREERTOS_ERRNO_EADDRINUSE 112 /* Address already in use */ + #define pdFREERTOS_ERRNO_ETIMEDOUT 116 /* Connection timed out */ + #define pdFREERTOS_ERRNO_EINPROGRESS 119 /* Connection already in progress */ + #define pdFREERTOS_ERRNO_EALREADY 120 /* Socket already connected */ + #define pdFREERTOS_ERRNO_EADDRNOTAVAIL 125 /* Address not available */ + #define pdFREERTOS_ERRNO_EISCONN 127 /* Socket is already connected */ + #define pdFREERTOS_ERRNO_ENOTCONN 128 /* Socket is not connected */ + #define pdFREERTOS_ERRNO_ENOMEDIUM 135 /* No medium inserted */ + #define pdFREERTOS_ERRNO_EILSEQ 138 /* An invalid UTF-16 sequence was encountered. */ + #define pdFREERTOS_ERRNO_ECANCELED 140 /* Operation canceled. */ + + /* The following endian values are used by FreeRTOS+ components, not FreeRTOS + itself. */ + #define pdFREERTOS_LITTLE_ENDIAN 0 + #define pdFREERTOS_BIG_ENDIAN 1 + +#endif /* pdFREERTOS_ERRNO_NONE */ + +#endif /* FREERTOS_ERRNO_TCP */ + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h new file mode 100644 index 000000000..d17299d6e --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/IPTraceMacroDefaults.h @@ -0,0 +1,193 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* This file provides default (empty) implementations for any IP trace macros +that are not defined by the user. See +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Trace.html */ + +#ifndef UDP_TRACE_MACRO_DEFAULTS_H +#define UDP_TRACE_MACRO_DEFAULTS_H + +#ifndef iptraceNETWORK_DOWN + #define iptraceNETWORK_DOWN() +#endif + +#ifndef iptraceNETWORK_BUFFER_RELEASED + #define iptraceNETWORK_BUFFER_RELEASED( pxBufferAddress ) +#endif + +#ifndef iptraceNETWORK_BUFFER_OBTAINED + #define iptraceNETWORK_BUFFER_OBTAINED( pxBufferAddress ) +#endif + +#ifndef iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR + #define iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxBufferAddress ) +#endif + +#ifndef iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER + #define iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER() +#endif + +#ifndef iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR + #define iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR() +#endif + +#ifndef iptraceCREATING_ARP_REQUEST + #define iptraceCREATING_ARP_REQUEST( ulIPAddress ) +#endif + +#ifndef iptraceARP_TABLE_ENTRY_WILL_EXPIRE + #define iptraceARP_TABLE_ENTRY_WILL_EXPIRE( ulIPAddress ) +#endif + +#ifndef iptraceARP_TABLE_ENTRY_EXPIRED + #define iptraceARP_TABLE_ENTRY_EXPIRED( ulIPAddress ) +#endif + +#ifndef iptraceARP_TABLE_ENTRY_CREATED + #define iptraceARP_TABLE_ENTRY_CREATED( ulIPAddress, ucMACAddress ) +#endif + +#ifndef iptraceSENDING_UDP_PACKET + #define iptraceSENDING_UDP_PACKET( ulIPAddress ) +#endif + +#ifndef iptracePACKET_DROPPED_TO_GENERATE_ARP + #define iptracePACKET_DROPPED_TO_GENERATE_ARP( ulIPAddress ) +#endif + +#ifndef iptraceICMP_PACKET_RECEIVED + #define iptraceICMP_PACKET_RECEIVED() +#endif + +#ifndef iptraceSENDING_PING_REPLY + #define iptraceSENDING_PING_REPLY( ulIPAddress ) +#endif + +#ifndef traceARP_PACKET_RECEIVED + #define traceARP_PACKET_RECEIVED() +#endif + +#ifndef iptracePROCESSING_RECEIVED_ARP_REPLY + #define iptracePROCESSING_RECEIVED_ARP_REPLY( ulIPAddress ) +#endif + +#ifndef iptraceSENDING_ARP_REPLY + #define iptraceSENDING_ARP_REPLY( ulIPAddress ) +#endif + +#ifndef iptraceFAILED_TO_CREATE_SOCKET + #define iptraceFAILED_TO_CREATE_SOCKET() +#endif + +#ifndef iptraceFAILED_TO_CREATE_EVENT_GROUP + #define iptraceFAILED_TO_CREATE_EVENT_GROUP() +#endif + +#ifndef iptraceRECVFROM_DISCARDING_BYTES + #define iptraceRECVFROM_DISCARDING_BYTES( xNumberOfBytesDiscarded ) +#endif + +#ifndef iptraceETHERNET_RX_EVENT_LOST + #define iptraceETHERNET_RX_EVENT_LOST() +#endif + +#ifndef iptraceSTACK_TX_EVENT_LOST + #define iptraceSTACK_TX_EVENT_LOST( xEvent ) +#endif + +#ifndef iptraceNETWORK_EVENT_RECEIVED + #define iptraceNETWORK_EVENT_RECEIVED( eEvent ) +#endif + +#ifndef iptraceBIND_FAILED + #define iptraceBIND_FAILED( xSocket, usPort ) +#endif + +#ifndef iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS + #define iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS( ulIPAddress ) +#endif + +#ifndef iptraceSENDING_DHCP_DISCOVER + #define iptraceSENDING_DHCP_DISCOVER() +#endif + +#ifndef iptraceSENDING_DHCP_REQUEST + #define iptraceSENDING_DHCP_REQUEST() +#endif + +#ifndef iptraceDHCP_SUCCEDEED + #define iptraceDHCP_SUCCEDEED( address ) +#endif + +#ifndef iptraceNETWORK_INTERFACE_TRANSMIT + #define iptraceNETWORK_INTERFACE_TRANSMIT() +#endif + +#ifndef iptraceNETWORK_INTERFACE_RECEIVE + #define iptraceNETWORK_INTERFACE_RECEIVE() +#endif + +#ifndef iptraceSENDING_DNS_REQUEST + #define iptraceSENDING_DNS_REQUEST() +#endif + +#ifndef iptraceWAITING_FOR_TX_DMA_DESCRIPTOR + #define iptraceWAITING_FOR_TX_DMA_DESCRIPTOR() +#endif + +#ifndef ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS + #define ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS 0 +#endif + +#ifndef iptraceFAILED_TO_NOTIFY_SELECT_GROUP + #define iptraceFAILED_TO_NOTIFY_SELECT_GROUP( xSocket ) +#endif + +#ifndef pvPortMallocSocket + #define pvPortMallocSocket(xSize) pvPortMalloc( ( xSize ) ) +#endif + +#ifndef iptraceRECVFROM_TIMEOUT + #define iptraceRECVFROM_TIMEOUT() +#endif + +#ifndef iptraceRECVFROM_INTERRUPTED + #define iptraceRECVFROM_INTERRUPTED() +#endif + +#ifndef iptraceNO_BUFFER_FOR_SENDTO + #define iptraceNO_BUFFER_FOR_SENDTO() +#endif + +#ifndef iptraceSENDTO_SOCKET_NOT_BOUND + #define iptraceSENDTO_SOCKET_NOT_BOUND() +#endif + +#ifndef iptraceSENDTO_DATA_TOO_LONG + #define iptraceSENDTO_DATA_TOO_LONG() +#endif + +#endif /* UDP_TRACE_MACRO_DEFAULTS_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h new file mode 100644 index 000000000..9543ef447 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/NetworkBufferManagement.h @@ -0,0 +1,70 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef NETWORK_BUFFER_MANAGEMENT_H +#define NETWORK_BUFFER_MANAGEMENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE PUBLIC API FUNCTIONS. */ +BaseType_t xNetworkBuffersInitialise( void ); +NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks ); +NetworkBufferDescriptor_t *pxNetworkBufferGetFromISR( size_t xRequestedSizeBytes ); +void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer ); +BaseType_t vNetworkBufferReleaseFromISR( NetworkBufferDescriptor_t * const pxNetworkBuffer ); +uint8_t *pucGetNetworkBuffer( size_t *pxRequestedSizeBytes ); +void vReleaseNetworkBuffer( uint8_t *pucEthernetBuffer ); + +/* Get the current number of free network buffers. */ +UBaseType_t uxGetNumberOfFreeNetworkBuffers( void ); + +/* Get the lowest number of free network buffers. */ +UBaseType_t uxGetMinimumFreeNetworkBuffers( void ); + +/* Copy a network buffer into a bigger buffer. */ +NetworkBufferDescriptor_t *pxDuplicateNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer, + BaseType_t xNewLength); + +/* Increase the size of a Network Buffer. +In case BufferAllocation_2.c is used, the new space must be allocated. */ +NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, + size_t xNewSizeBytes ); + +#if ipconfigTCP_IP_SANITY + /* + * Check if an address is a valid pointer to a network descriptor + * by looking it up in the array of network descriptors + */ + UBaseType_t bIsValidNetworkDescriptor (const NetworkBufferDescriptor_t * pxDesc); + BaseType_t prvIsFreeBuffer( const NetworkBufferDescriptor_t *pxDescr ); +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* NETWORK_BUFFER_MANAGEMENT_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h new file mode 100644 index 000000000..4e26f7e58 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/include/NetworkInterface.h @@ -0,0 +1,44 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#ifndef NETWORK_INTERFACE_H +#define NETWORK_INTERFACE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* NOTE PUBLIC API FUNCTIONS. */ +BaseType_t xNetworkInterfaceInitialise( void ); +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t xReleaseAfterSend ); +void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ); +BaseType_t xGetPhyLinkStatus( void ); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* NETWORK_INTERFACE_H */ + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c new file mode 100644 index 000000000..3540b15c2 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_1.c @@ -0,0 +1,423 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/****************************************************************************** + * + * See the following web page for essential buffer allocation scheme usage and + * configuration details: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html + * + ******************************************************************************/ + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkInterface.h" +#include "NetworkBufferManagement.h" + +/* For an Ethernet interrupt to be able to obtain a network buffer there must +be at least this number of buffers available. */ +#define baINTERRUPT_BUFFER_GET_THRESHOLD ( 3 ) + +/* A list of free (available) NetworkBufferDescriptor_t structures. */ +static List_t xFreeBuffersList; + +/* Some statistics about the use of buffers. */ +static UBaseType_t uxMinimumFreeNetworkBuffers = 0u; + +/* Declares the pool of NetworkBufferDescriptor_t structures that are available +to the system. All the network buffers referenced from xFreeBuffersList exist +in this array. The array is not accessed directly except during initialisation, +when the xFreeBuffersList is filled (as all the buffers are free when the system +is booted). */ +static NetworkBufferDescriptor_t xNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ]; + +/* This constant is defined as true to let FreeRTOS_TCP_IP.c know that the +network buffers have constant size, large enough to hold the biggest Ethernet +packet. No resizing will be done. */ +const BaseType_t xBufferAllocFixedSize = pdTRUE; + +/* The semaphore used to obtain network buffers. */ +static SemaphoreHandle_t xNetworkBufferSemaphore = NULL; + +#if( ipconfigTCP_IP_SANITY != 0 ) + static char cIsLow = pdFALSE; + UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc ); +#else + static UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc ); +#endif /* ipconfigTCP_IP_SANITY */ + +static void prvShowWarnings( void ); + +/* The user can define their own ipconfigBUFFER_ALLOC_LOCK() and +ipconfigBUFFER_ALLOC_UNLOCK() macros, especially for use form an ISR. If these +are not defined then default them to call the normal enter/exit critical +section macros. */ +#if !defined( ipconfigBUFFER_ALLOC_LOCK ) + + #define ipconfigBUFFER_ALLOC_INIT( ) do {} while (0) + #define ipconfigBUFFER_ALLOC_LOCK_FROM_ISR() \ + UBaseType_t uxSavedInterruptStatus = ( UBaseType_t ) portSET_INTERRUPT_MASK_FROM_ISR(); \ + { + + #define ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR() \ + portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \ + } + + #define ipconfigBUFFER_ALLOC_LOCK() taskENTER_CRITICAL() + #define ipconfigBUFFER_ALLOC_UNLOCK() taskEXIT_CRITICAL() + +#endif /* ipconfigBUFFER_ALLOC_LOCK */ + +/*-----------------------------------------------------------*/ + +#if( ipconfigTCP_IP_SANITY != 0 ) + + /* HT: SANITY code will be removed as soon as the library is stable + * and and ready to become public + * Function below gives information about the use of buffers */ + #define WARN_LOW ( 2 ) + #define WARN_HIGH ( ( 5 * ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) / 10 ) + +#endif /* ipconfigTCP_IP_SANITY */ + +/*-----------------------------------------------------------*/ + +#if( ipconfigTCP_IP_SANITY != 0 ) + + BaseType_t prvIsFreeBuffer( const NetworkBufferDescriptor_t *pxDescr ) + { + return ( bIsValidNetworkDescriptor( pxDescr ) != 0 ) && + ( listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxDescr->xBufferListItem ) ) != 0 ); + } + /*-----------------------------------------------------------*/ + + static void prvShowWarnings( void ) + { + UBaseType_t uxCount = uxGetNumberOfFreeNetworkBuffers( ); + if( ( ( cIsLow == 0 ) && ( uxCount <= WARN_LOW ) ) || ( ( cIsLow != 0 ) && ( uxCount >= WARN_HIGH ) ) ) + { + cIsLow = !cIsLow; + FreeRTOS_debug_printf( ( "*** Warning *** %s %lu buffers left\n", cIsLow ? "only" : "now", uxCount ) ); + } + } + /*-----------------------------------------------------------*/ + + UBaseType_t bIsValidNetworkDescriptor( const NetworkBufferDescriptor_t * pxDesc ) + { + uint32_t offset = ( uint32_t ) ( ((const char *)pxDesc) - ((const char *)xNetworkBuffers) ); + if( ( offset >= sizeof( xNetworkBuffers ) ) || + ( ( offset % sizeof( xNetworkBuffers[0] ) ) != 0 ) ) + return pdFALSE; + return (UBaseType_t) (pxDesc - xNetworkBuffers) + 1; + } + /*-----------------------------------------------------------*/ + +#else + static UBaseType_t bIsValidNetworkDescriptor (const NetworkBufferDescriptor_t * pxDesc) + { + ( void ) pxDesc; + return ( UBaseType_t ) pdTRUE; + } + /*-----------------------------------------------------------*/ + + static void prvShowWarnings( void ) + { + } + /*-----------------------------------------------------------*/ + +#endif /* ipconfigTCP_IP_SANITY */ + +BaseType_t xNetworkBuffersInitialise( void ) +{ +BaseType_t xReturn, x; + + /* Only initialise the buffers and their associated kernel objects if they + have not been initialised before. */ + if( xNetworkBufferSemaphore == NULL ) + { + /* In case alternative locking is used, the mutexes can be initialised + here */ + ipconfigBUFFER_ALLOC_INIT(); + + xNetworkBufferSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ); + configASSERT( xNetworkBufferSemaphore ); + + if( xNetworkBufferSemaphore != NULL ) + { + vListInitialise( &xFreeBuffersList ); + + /* Initialise all the network buffers. The buffer storage comes + from the network interface, and different hardware has different + requirements. */ + vNetworkInterfaceAllocateRAMToBuffers( xNetworkBuffers ); + for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ ) + { + /* Initialise and set the owner of the buffer list items. */ + vListInitialiseItem( &( xNetworkBuffers[ x ].xBufferListItem ) ); + listSET_LIST_ITEM_OWNER( &( xNetworkBuffers[ x ].xBufferListItem ), &xNetworkBuffers[ x ] ); + + /* Currently, all buffers are available for use. */ + vListInsert( &xFreeBuffersList, &( xNetworkBuffers[ x ].xBufferListItem ) ); + } + + uxMinimumFreeNetworkBuffers = ( UBaseType_t ) ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; + } + } + + if( xNetworkBufferSemaphore == NULL ) + { + xReturn = pdFAIL; + } + else + { + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks ) +{ +NetworkBufferDescriptor_t *pxReturn = NULL; +BaseType_t xInvalid = pdFALSE; +UBaseType_t uxCount; + + /* The current implementation only has a single size memory block, so + the requested size parameter is not used (yet). */ + ( void ) xRequestedSizeBytes; + + if( xNetworkBufferSemaphore != NULL ) + { + /* If there is a semaphore available, there is a network buffer + available. */ + if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS ) + { + /* Protect the structure as they are accessed from tasks and + interrupts. */ + ipconfigBUFFER_ALLOC_LOCK(); + { + pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList ); + + if( ( bIsValidNetworkDescriptor( pxReturn ) != pdFALSE_UNSIGNED ) && + listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxReturn->xBufferListItem ) ) ) + { + uxListRemove( &( pxReturn->xBufferListItem ) ); + } + else + { + xInvalid = pdTRUE; + } + } + ipconfigBUFFER_ALLOC_UNLOCK(); + + if( xInvalid == pdTRUE ) + { + /* _RB_ Can printf() be called from an interrupt? (comment + above says this can be called from an interrupt too) */ + /* _HT_ The function shall not be called from an ISR. Comment + was indeed misleading. Hopefully clear now? + So the printf()is OK here. */ + FreeRTOS_debug_printf( ( "pxGetNetworkBufferWithDescriptor: INVALID BUFFER: %p (valid %lu)\n", + pxReturn, bIsValidNetworkDescriptor( pxReturn ) ) ); + pxReturn = NULL; + } + else + { + /* Reading UBaseType_t, no critical section needed. */ + uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList ); + + /* For stats, latch the lowest number of network buffers since + booting. */ + if( uxMinimumFreeNetworkBuffers > uxCount ) + { + uxMinimumFreeNetworkBuffers = uxCount; + } + + pxReturn->xDataLength = xRequestedSizeBytes; + + #if( ipconfigTCP_IP_SANITY != 0 ) + { + prvShowWarnings(); + } + #endif /* ipconfigTCP_IP_SANITY */ + + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + { + /* make sure the buffer is not linked */ + pxReturn->pxNextBuffer = NULL; + } + #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ + + if( xTCPWindowLoggingLevel > 3 ) + { + FreeRTOS_debug_printf( ( "BUF_GET[%ld]: %p (%p)\n", + bIsValidNetworkDescriptor( pxReturn ), + pxReturn, pxReturn->pucEthernetBuffer ) ); + } + } + iptraceNETWORK_BUFFER_OBTAINED( pxReturn ); + } + else + { + iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER(); + } + } + + return pxReturn; +} +/*-----------------------------------------------------------*/ + +NetworkBufferDescriptor_t *pxNetworkBufferGetFromISR( size_t xRequestedSizeBytes ) +{ +NetworkBufferDescriptor_t *pxReturn = NULL; + + /* The current implementation only has a single size memory block, so + the requested size parameter is not used (yet). */ + ( void ) xRequestedSizeBytes; + + /* If there is a semaphore available then there is a buffer available, but, + as this is called from an interrupt, only take a buffer if there are at + least baINTERRUPT_BUFFER_GET_THRESHOLD buffers remaining. This prevents, + to a certain degree at least, a rapidly executing interrupt exhausting + buffer and in so doing preventing tasks from continuing. */ + if( uxQueueMessagesWaitingFromISR( ( QueueHandle_t ) xNetworkBufferSemaphore ) > ( UBaseType_t ) baINTERRUPT_BUFFER_GET_THRESHOLD ) + { + if( xSemaphoreTakeFromISR( xNetworkBufferSemaphore, NULL ) == pdPASS ) + { + /* Protect the structure as it is accessed from tasks and interrupts. */ + ipconfigBUFFER_ALLOC_LOCK_FROM_ISR(); + { + pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList ); + uxListRemove( &( pxReturn->xBufferListItem ) ); + } + ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR(); + + iptraceNETWORK_BUFFER_OBTAINED_FROM_ISR( pxReturn ); + } + } + + if( pxReturn == NULL ) + { + iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER_FROM_ISR(); + } + + return pxReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t vNetworkBufferReleaseFromISR( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ +BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + /* Ensure the buffer is returned to the list of free buffers before the + counting semaphore is 'given' to say a buffer is available. */ + ipconfigBUFFER_ALLOC_LOCK_FROM_ISR(); + { + vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); + } + ipconfigBUFFER_ALLOC_UNLOCK_FROM_ISR(); + + xSemaphoreGiveFromISR( xNetworkBufferSemaphore, &xHigherPriorityTaskWoken ); + iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); + + return xHigherPriorityTaskWoken; +} +/*-----------------------------------------------------------*/ + +void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ +BaseType_t xListItemAlreadyInFreeList; + + if( bIsValidNetworkDescriptor( pxNetworkBuffer ) == pdFALSE_UNSIGNED ) + { + FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: Invalid buffer %p\n", pxNetworkBuffer ) ); + return ; + } + /* Ensure the buffer is returned to the list of free buffers before the + counting semaphore is 'given' to say a buffer is available. */ + ipconfigBUFFER_ALLOC_LOCK(); + { + { + xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); + + if( xListItemAlreadyInFreeList == pdFALSE ) + { + vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); + } + } + } + ipconfigBUFFER_ALLOC_UNLOCK(); + + if( xListItemAlreadyInFreeList ) + { + FreeRTOS_debug_printf( ( "vReleaseNetworkBufferAndDescriptor: %p ALREADY RELEASED (now %lu)\n", + pxNetworkBuffer, uxGetNumberOfFreeNetworkBuffers( ) ) ); + } + if( xListItemAlreadyInFreeList == pdFALSE ) + { + xSemaphoreGive( xNetworkBufferSemaphore ); + prvShowWarnings(); + if( xTCPWindowLoggingLevel > 3 ) + FreeRTOS_debug_printf( ( "BUF_PUT[%ld]: %p (%p) (now %lu)\n", + bIsValidNetworkDescriptor( pxNetworkBuffer ), + pxNetworkBuffer, pxNetworkBuffer->pucEthernetBuffer, + uxGetNumberOfFreeNetworkBuffers( ) ) ); + } + iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxGetMinimumFreeNetworkBuffers( void ) +{ + return uxMinimumFreeNetworkBuffers; +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxGetNumberOfFreeNetworkBuffers( void ) +{ + return listCURRENT_LIST_LENGTH( &xFreeBuffersList ); +} + +NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes ) +{ + /* In BufferAllocation_1.c all network buffer are allocated with a + maximum size of 'ipTOTAL_ETHERNET_FRAME_SIZE'.No need to resize the + network buffer. */ + ( void ) xNewSizeBytes; + return pxNetworkBuffer; +} + +/*#endif */ /* ipconfigINCLUDE_TEST_CODE */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_2.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_2.c new file mode 100644 index 000000000..d6780b511 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/BufferManagement/BufferAllocation_2.c @@ -0,0 +1,393 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/****************************************************************************** + * + * See the following web page for essential buffer allocation scheme usage and + * configuration details: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html + * + ******************************************************************************/ + +/* THIS FILE SHOULD NOT BE USED IF THE PROJECT INCLUDES A MEMORY ALLOCATOR +THAT WILL FRAGMENT THE HEAP MEMORY. For example, heap_2 must not be used, +heap_4 can be used. */ + + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkInterface.h" +#include "NetworkBufferManagement.h" + +/* The obtained network buffer must be large enough to hold a packet that might +replace the packet that was requested to be sent. */ +#if ipconfigUSE_TCP == 1 + #define baMINIMAL_BUFFER_SIZE sizeof( TCPPacket_t ) +#else + #define baMINIMAL_BUFFER_SIZE sizeof( ARPPacket_t ) +#endif /* ipconfigUSE_TCP == 1 */ + +/*_RB_ This is too complex not to have an explanation. */ +#if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES ) + #define ASSERT_CONCAT_(a, b) a##b + #define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b) + #define STATIC_ASSERT(e) \ + ;enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1/(!!(e)) } + + STATIC_ASSERT( ipconfigETHERNET_MINIMUM_PACKET_BYTES <= baMINIMAL_BUFFER_SIZE ); +#endif + +/* A list of free (available) NetworkBufferDescriptor_t structures. */ +static List_t xFreeBuffersList; + +/* Some statistics about the use of buffers. */ +static size_t uxMinimumFreeNetworkBuffers; + +/* Declares the pool of NetworkBufferDescriptor_t structures that are available +to the system. All the network buffers referenced from xFreeBuffersList exist +in this array. The array is not accessed directly except during initialisation, +when the xFreeBuffersList is filled (as all the buffers are free when the system +is booted). */ +static NetworkBufferDescriptor_t xNetworkBufferDescriptors[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ]; + +/* This constant is defined as false to let FreeRTOS_TCP_IP.c know that the +network buffers have a variable size: resizing may be necessary */ +const BaseType_t xBufferAllocFixedSize = pdFALSE; + +/* The semaphore used to obtain network buffers. */ +static SemaphoreHandle_t xNetworkBufferSemaphore = NULL; + +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkBuffersInitialise( void ) +{ +BaseType_t xReturn, x; + + /* Only initialise the buffers and their associated kernel objects if they + have not been initialised before. */ + if( xNetworkBufferSemaphore == NULL ) + { + xNetworkBufferSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ); + configASSERT( xNetworkBufferSemaphore ); + + if( xNetworkBufferSemaphore != NULL ) + { + #if ( configQUEUE_REGISTRY_SIZE > 0 ) + { + vQueueAddToRegistry( xNetworkBufferSemaphore, "NetBufSem" ); + } + #endif /* configQUEUE_REGISTRY_SIZE */ + + /* If the trace recorder code is included name the semaphore for viewing + in FreeRTOS+Trace. */ + #if( ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 ) + { + extern QueueHandle_t xNetworkEventQueue; + vTraceSetQueueName( xNetworkEventQueue, "IPStackEvent" ); + vTraceSetQueueName( xNetworkBufferSemaphore, "NetworkBufferCount" ); + } + #endif /* ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 */ + + vListInitialise( &xFreeBuffersList ); + + /* Initialise all the network buffers. No storage is allocated to + the buffers yet. */ + for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ ) + { + /* Initialise and set the owner of the buffer list items. */ + xNetworkBufferDescriptors[ x ].pucEthernetBuffer = NULL; + vListInitialiseItem( &( xNetworkBufferDescriptors[ x ].xBufferListItem ) ); + listSET_LIST_ITEM_OWNER( &( xNetworkBufferDescriptors[ x ].xBufferListItem ), &xNetworkBufferDescriptors[ x ] ); + + /* Currently, all buffers are available for use. */ + vListInsert( &xFreeBuffersList, &( xNetworkBufferDescriptors[ x ].xBufferListItem ) ); + } + + uxMinimumFreeNetworkBuffers = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; + } + } + + if( xNetworkBufferSemaphore == NULL ) + { + xReturn = pdFAIL; + } + else + { + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +uint8_t *pucGetNetworkBuffer( size_t *pxRequestedSizeBytes ) +{ +uint8_t *pucEthernetBuffer; +size_t xSize = *pxRequestedSizeBytes; + + if( xSize < baMINIMAL_BUFFER_SIZE ) + { + /* Buffers must be at least large enough to hold a TCP-packet with + headers, or an ARP packet, in case TCP is not included. */ + xSize = baMINIMAL_BUFFER_SIZE; + } + + /* Round up xSize to the nearest multiple of N bytes, + where N equals 'sizeof( size_t )'. */ + if( ( xSize & ( sizeof( size_t ) - 1u ) ) != 0u ) + { + xSize = ( xSize | ( sizeof( size_t ) - 1u ) ) + 1u; + } + *pxRequestedSizeBytes = xSize; + + /* Allocate a buffer large enough to store the requested Ethernet frame size + and a pointer to a network buffer structure (hence the addition of + ipBUFFER_PADDING bytes). */ + pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xSize + ipBUFFER_PADDING ); + configASSERT( pucEthernetBuffer ); + + if( pucEthernetBuffer != NULL ) + { + /* Enough space is left at the start of the buffer to place a pointer to + the network buffer structure that references this Ethernet buffer. + Return a pointer to the start of the Ethernet buffer itself. */ + pucEthernetBuffer += ipBUFFER_PADDING; + } + + return pucEthernetBuffer; +} +/*-----------------------------------------------------------*/ + +void vReleaseNetworkBuffer( uint8_t *pucEthernetBuffer ) +{ + /* There is space before the Ethernet buffer in which a pointer to the + network buffer that references this Ethernet buffer is stored. Remove the + space before freeing the buffer. */ + if( pucEthernetBuffer != NULL ) + { + pucEthernetBuffer -= ipBUFFER_PADDING; + vPortFree( ( void * ) pucEthernetBuffer ); + } +} +/*-----------------------------------------------------------*/ + +NetworkBufferDescriptor_t *pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks ) +{ +NetworkBufferDescriptor_t *pxReturn = NULL; +size_t uxCount; + + if( xNetworkBufferSemaphore != NULL ) + { + if( ( xRequestedSizeBytes != 0u ) && ( xRequestedSizeBytes < ( size_t ) baMINIMAL_BUFFER_SIZE ) ) + { + /* ARP packets can replace application packets, so the storage must be + at least large enough to hold an ARP. */ + xRequestedSizeBytes = baMINIMAL_BUFFER_SIZE; + } + + /* Add 2 bytes to xRequestedSizeBytes and round up xRequestedSizeBytes + to the nearest multiple of N bytes, where N equals 'sizeof( size_t )'. */ + xRequestedSizeBytes += 2u; + if( ( xRequestedSizeBytes & ( sizeof( size_t ) - 1u ) ) != 0u ) + { + xRequestedSizeBytes = ( xRequestedSizeBytes | ( sizeof( size_t ) - 1u ) ) + 1u; + } + + /* If there is a semaphore available, there is a network buffer available. */ + if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS ) + { + /* Protect the structure as it is accessed from tasks and interrupts. */ + taskENTER_CRITICAL(); + { + pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList ); + uxListRemove( &( pxReturn->xBufferListItem ) ); + } + taskEXIT_CRITICAL(); + + /* Reading UBaseType_t, no critical section needed. */ + uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList ); + + if( uxMinimumFreeNetworkBuffers > uxCount ) + { + uxMinimumFreeNetworkBuffers = uxCount; + } + + /* Allocate storage of exactly the requested size to the buffer. */ + configASSERT( pxReturn->pucEthernetBuffer == NULL ); + if( xRequestedSizeBytes > 0 ) + { + /* Extra space is obtained so a pointer to the network buffer can + be stored at the beginning of the buffer. */ + pxReturn->pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xRequestedSizeBytes + ipBUFFER_PADDING ); + + if( pxReturn->pucEthernetBuffer == NULL ) + { + /* The attempt to allocate storage for the buffer payload failed, + so the network buffer structure cannot be used and must be + released. */ + vReleaseNetworkBufferAndDescriptor( pxReturn ); + pxReturn = NULL; + } + else + { + /* Store a pointer to the network buffer structure in the + buffer storage area, then move the buffer pointer on past the + stored pointer so the pointer value is not overwritten by the + application when the buffer is used. */ + *( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer ) ) = pxReturn; + pxReturn->pucEthernetBuffer += ipBUFFER_PADDING; + + /* Store the actual size of the allocated buffer, which may be + greater than the original requested size. */ + pxReturn->xDataLength = xRequestedSizeBytes; + + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + { + /* make sure the buffer is not linked */ + pxReturn->pxNextBuffer = NULL; + } + #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ + } + } + else + { + /* A descriptor is being returned without an associated buffer being + allocated. */ + } + } + } + + if( pxReturn == NULL ) + { + iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER(); + } + else + { + iptraceNETWORK_BUFFER_OBTAINED( pxReturn ); + } + + return pxReturn; +} +/*-----------------------------------------------------------*/ + +void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ +BaseType_t xListItemAlreadyInFreeList; + + /* Ensure the buffer is returned to the list of free buffers before the + counting semaphore is 'given' to say a buffer is available. Release the + storage allocated to the buffer payload. THIS FILE SHOULD NOT BE USED + IF THE PROJECT INCLUDES A MEMORY ALLOCATOR THAT WILL FRAGMENT THE HEAP + MEMORY. For example, heap_2 must not be used, heap_4 can be used. */ + vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer ); + pxNetworkBuffer->pucEthernetBuffer = NULL; + + taskENTER_CRITICAL(); + { + xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); + + if( xListItemAlreadyInFreeList == pdFALSE ) + { + vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); + } + } + taskEXIT_CRITICAL(); + + /* + * Update the network state machine, unless the program fails to release its 'xNetworkBufferSemaphore'. + * The program should only try to release its semaphore if 'xListItemAlreadyInFreeList' is false. + */ + if( xListItemAlreadyInFreeList == pdFALSE ) + { + if ( xSemaphoreGive( xNetworkBufferSemaphore ) == pdTRUE ) + { + iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); + } + } + else + { + iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); + } +} +/*-----------------------------------------------------------*/ + +/* + * Returns the number of free network buffers + */ +UBaseType_t uxGetNumberOfFreeNetworkBuffers( void ) +{ + return listCURRENT_LIST_LENGTH( &xFreeBuffersList ); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxGetMinimumFreeNetworkBuffers( void ) +{ + return uxMinimumFreeNetworkBuffers; +} +/*-----------------------------------------------------------*/ + +NetworkBufferDescriptor_t *pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, size_t xNewSizeBytes ) +{ +size_t xOriginalLength; +uint8_t *pucBuffer; + + xOriginalLength = pxNetworkBuffer->xDataLength + ipBUFFER_PADDING; + xNewSizeBytes = xNewSizeBytes + ipBUFFER_PADDING; + + pucBuffer = pucGetNetworkBuffer( &( xNewSizeBytes ) ); + + if( pucBuffer == NULL ) + { + /* In case the allocation fails, return NULL. */ + pxNetworkBuffer = NULL; + } + else + { + pxNetworkBuffer->xDataLength = xNewSizeBytes; + if( xNewSizeBytes > xOriginalLength ) + { + xNewSizeBytes = xOriginalLength; + } + + memcpy( pucBuffer - ipBUFFER_PADDING, pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING, xNewSizeBytes ); + vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer ); + pxNetworkBuffer->pucEthernetBuffer = pucBuffer; + } + + return pxNetworkBuffer; +} + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_end.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_end.h new file mode 100644 index 000000000..d61b8d003 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_end.h @@ -0,0 +1,46 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/***************************************************************************** + * + * See the following URL for an explanation of this file: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html + * + *****************************************************************************/ +__attribute__( (packed) ); + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_start.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_start.h new file mode 100644 index 000000000..5a88f78cf --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC/pack_struct_start.h @@ -0,0 +1,48 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/***************************************************************************** + * + * See the following URL for an explanation of this file: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html + * + *****************************************************************************/ + +/* Nothing to do here. */ + + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_end.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_end.h new file mode 100644 index 000000000..85e670819 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_end.h @@ -0,0 +1,47 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/***************************************************************************** + * + * See the following URL for an explanation of this file: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html + * + *****************************************************************************/ + +; + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_start.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_start.h new file mode 100644 index 000000000..15e6eb69b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/IAR/pack_struct_start.h @@ -0,0 +1,49 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/***************************************************************************** + * + * See the following URL for an explanation of this file: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html + * + *****************************************************************************/ + +__packed + + + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_end.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_end.h new file mode 100644 index 000000000..19a0f39ef --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_end.h @@ -0,0 +1,48 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/***************************************************************************** + * + * See the following URL for an explanation of this file: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html + * + *****************************************************************************/ + +; +#pragma pack( pop ) + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_start.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_start.h new file mode 100644 index 000000000..54a3e6885 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/MSVC/pack_struct_start.h @@ -0,0 +1,47 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/***************************************************************************** + * + * See the following URL for an explanation of this file: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html + * + *****************************************************************************/ + +#pragma pack( push, 1 ) + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_end.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_end.h new file mode 100644 index 000000000..2e6d2f997 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_end.h @@ -0,0 +1,60 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/***************************************************************************** + * + * See the following URL for an explanation of this file: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html + * + *****************************************************************************/ + + +#ifdef _SH + #ifdef __RENESAS__ + ; + #pragma unpack + #endif +#endif +#ifdef __RX + #ifdef __CCRX__ + ; + #pragma packoption + #endif +#endif + + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_start.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_start.h new file mode 100644 index 000000000..7c8750c6a --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/Compiler/Renesas/pack_struct_start.h @@ -0,0 +1,58 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/***************************************************************************** + * + * See the following URL for an explanation of this file: + * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Compiler_Porting.html + * + *****************************************************************************/ + + +#ifdef _SH + #ifdef __RENESAS__ + #pragma pack 1 + #endif +#endif +#ifdef __RX + #ifdef __CCRX__ + #pragma pack + #endif +#endif + + + + + + + + + + + + + + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c new file mode 100644 index 000000000..b869ccc85 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/NetworkInterface.c @@ -0,0 +1,649 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" + +/* Some files from the Atmel Software Framework */ +/*_RB_ The SAM4E portable layer has three different header files called gmac.h! */ +#include "instance/gmac.h" +#include +#include + +#ifndef BMSR_LINK_STATUS + #define BMSR_LINK_STATUS 0x0004 //!< Link status +#endif + +#ifndef PHY_LS_HIGH_CHECK_TIME_MS + /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not + receiving packets. */ + #define PHY_LS_HIGH_CHECK_TIME_MS 15000 +#endif + +#ifndef PHY_LS_LOW_CHECK_TIME_MS + /* Check if the LinkSStatus in the PHY is still low every second. */ + #define PHY_LS_LOW_CHECK_TIME_MS 1000 +#endif + +/* Interrupt events to process. Currently only the Rx event is processed +although code for other events is included to allow for possible future +expansion. */ +#define EMAC_IF_RX_EVENT 1UL +#define EMAC_IF_TX_EVENT 2UL +#define EMAC_IF_ERR_EVENT 4UL +#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT ) + +#define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR + +#define HZ_PER_MHZ ( 1000000UL ) + +#ifndef EMAC_MAX_BLOCK_TIME_MS + #define EMAC_MAX_BLOCK_TIME_MS 100ul +#endif + +#if !defined( GMAC_USES_TX_CALLBACK ) || ( GMAC_USES_TX_CALLBACK != 1 ) + #error Please define GMAC_USES_TX_CALLBACK as 1 +#endif + +#if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + #warning The EMAC of SAM4E has fixed-size RX buffers so ZERO_COPY_RX is not possible +#endif + +/* Default the size of the stack used by the EMAC deferred handler task to 4x +the size of the stack used by the idle task - but allow this to be overridden in +FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */ +#ifndef configEMAC_TASK_STACK_SIZE + #define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE ) +#endif + +/*-----------------------------------------------------------*/ + +/* + * Wait a fixed time for the link status to indicate the network is up. + */ +static BaseType_t xGMACWaitLS( TickType_t xMaxTime ); + +#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 ) + void vGMACGenerateChecksum( uint8_t *apBuffer ); +#endif + +/* + * Called from the ASF GMAC driver. + */ +static void prvRxCallback( uint32_t ulStatus ); +static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer ); + +/* + * A deferred interrupt handler task that processes GMAC interrupts. + */ +static void prvEMACHandlerTask( void *pvParameters ); + +/* + * Initialise the ASF GMAC driver. + */ +static BaseType_t prvGMACInit( void ); + +/* + * Try to obtain an Rx packet from the hardware. + */ +static uint32_t prvEMACRxPoll( void ); + +/*-----------------------------------------------------------*/ + +/* Bit map of outstanding ETH interrupt events for processing. Currently only +the Rx interrupt is handled, although code is included for other events to +enable future expansion. */ +static volatile uint32_t ulISREvents; + +/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */ +static uint32_t ulPHYLinkStatus = 0; +static volatile BaseType_t xGMACSwitchRequired; + +/* ethernet_phy_addr: the address of the PHY in use. +Atmel was a bit ambiguous about it so the address will be stored +in this variable, see ethernet_phy.c */ +extern int ethernet_phy_addr; + +/* LLMNR multicast address. */ +static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC }; + +/* The GMAC object as defined by the ASF drivers. */ +static gmac_device_t gs_gmac_dev; + +/* MAC address to use. */ +extern const uint8_t ucMACAddress[ 6 ]; + +/* Holds the handle of the task used as a deferred interrupt processor. The +handle is used so direct notifications can be sent to the task for all EMAC/DMA +related interrupts. */ +TaskHandle_t xEMACTaskHandle = NULL; + +static QueueHandle_t xTxBufferQueue; +int tx_release_count[ 4 ]; + +/* xTXDescriptorSemaphore is a counting semaphore with +a maximum count of GMAC_TX_BUFFERS, which is the number of +DMA TX descriptors. */ +static SemaphoreHandle_t xTXDescriptorSemaphore = NULL; + +/*-----------------------------------------------------------*/ + +/* + * GMAC interrupt handler. + */ +void GMAC_Handler(void) +{ + xGMACSwitchRequired = pdFALSE; + + /* gmac_handler() may call prvRxCallback() which may change + the value of xGMACSwitchRequired. */ + gmac_handler( &gs_gmac_dev ); + + if( xGMACSwitchRequired != pdFALSE ) + { + portEND_SWITCHING_ISR( xGMACSwitchRequired ); + } +} +/*-----------------------------------------------------------*/ + +static void prvRxCallback( uint32_t ulStatus ) +{ + if( ( ( ulStatus & GMAC_RSR_REC ) != 0 ) && ( xEMACTaskHandle != NULL ) ) + { + /* let the prvEMACHandlerTask know that there was an RX event. */ + ulISREvents |= EMAC_IF_RX_EVENT; + /* Only an RX interrupt can wakeup prvEMACHandlerTask. */ + vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired ); + } +} +/*-----------------------------------------------------------*/ + +static void prvTxCallback( uint32_t ulStatus, uint8_t *puc_buffer ) +{ + if( ( xTxBufferQueue != NULL ) && ( xEMACTaskHandle != NULL ) ) + { + /* let the prvEMACHandlerTask know that there was an RX event. */ + ulISREvents |= EMAC_IF_TX_EVENT; + + vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xGMACSwitchRequired ); + xQueueSendFromISR( xTxBufferQueue, &puc_buffer, ( BaseType_t * ) &xGMACSwitchRequired ); + tx_release_count[ 2 ]++; + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceInitialise( void ) +{ +const TickType_t x5_Seconds = 5000UL; + + if( xEMACTaskHandle == NULL ) + { + prvGMACInit(); + + /* Wait at most 5 seconds for a Link Status in the PHY. */ + xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) ); + + /* The handler task is created at the highest possible priority to + ensure the interrupt handler can return directly to it. */ + xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle ); + configASSERT( xEMACTaskHandle ); + } + + if( xTxBufferQueue == NULL ) + { + xTxBufferQueue = xQueueCreate( GMAC_TX_BUFFERS, sizeof( void * ) ); + configASSERT( xTxBufferQueue ); + } + + if( xTXDescriptorSemaphore == NULL ) + { + xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) GMAC_TX_BUFFERS, ( UBaseType_t ) GMAC_TX_BUFFERS ); + configASSERT( xTXDescriptorSemaphore ); + } + /* When returning non-zero, the stack will become active and + start DHCP (in configured) */ + return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0; +} +/*-----------------------------------------------------------*/ + +BaseType_t xGetPhyLinkStatus( void ) +{ +BaseType_t xResult; + + /* This function returns true if the Link Status in the PHY is high. */ + if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) + { + xResult = pdTRUE; + } + else + { + xResult = pdFALSE; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend ) +{ +/* Do not wait too long for a free TX DMA buffer. */ +const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u ); + + do { + if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 ) + { + /* Do not attempt to send packets as long as the Link Status is low. */ + break; + } + if( xTXDescriptorSemaphore == NULL ) + { + /* Semaphore has not been created yet? */ + break; + } + if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS ) + { + /* Time-out waiting for a free TX descriptor. */ + tx_release_count[ 3 ]++; + break; + } + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + /* Confirm that the pxDescriptor may be kept by the driver. */ + configASSERT( bReleaseAfterSend != pdFALSE ); + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + + gmac_dev_write( &gs_gmac_dev, (void *)pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength, prvTxCallback ); + + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + /* Confirm that the pxDescriptor may be kept by the driver. */ + bReleaseAfterSend = pdFALSE; + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + /* Not interested in a call-back after TX. */ + iptraceNETWORK_INTERFACE_TRANSMIT(); + } while( 0 ); + + if( bReleaseAfterSend != pdFALSE ) + { + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + } + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvGMACInit( void ) +{ +uint32_t ncfgr; + + gmac_options_t gmac_option; + + memset( &gmac_option, '\0', sizeof( gmac_option ) ); + gmac_option.uc_copy_all_frame = 0; + gmac_option.uc_no_boardcast = 0; + memcpy( gmac_option.uc_mac_addr, ucMACAddress, sizeof( gmac_option.uc_mac_addr ) ); + + gs_gmac_dev.p_hw = GMAC; + gmac_dev_init( GMAC, &gs_gmac_dev, &gmac_option ); + + NVIC_SetPriority( GMAC_IRQn, configMAC_INTERRUPT_PRIORITY ); + NVIC_EnableIRQ( GMAC_IRQn ); + + /* Contact the Ethernet PHY and store it's address in 'ethernet_phy_addr' */ + ethernet_phy_init( GMAC, ETHERNET_CONF_PHY_ADDR, sysclk_get_cpu_hz() ); + + ethernet_phy_auto_negotiate( GMAC, ethernet_phy_addr ); + ethernet_phy_set_link( GMAC, ethernet_phy_addr, 1 ); + + /* The GMAC driver will call a hook prvRxCallback(), which + in turn will wake-up the task by calling vTaskNotifyGiveFromISR() */ + gmac_dev_set_rx_callback( &gs_gmac_dev, prvRxCallback ); + gmac_set_address( GMAC, 1, (uint8_t*)llmnr_mac_address ); + + ncfgr = GMAC_NCFGR_SPD | GMAC_NCFGR_FD; + + GMAC->GMAC_NCFGR = ( GMAC->GMAC_NCFGR & ~( GMAC_NCFGR_SPD | GMAC_NCFGR_FD ) ) | ncfgr; + + return 1; +} +/*-----------------------------------------------------------*/ + +static inline unsigned long ulReadMDIO( unsigned /*short*/ usAddress ) +{ +uint32_t ulValue, ulReturn; +int rc; + + gmac_enable_management( GMAC, 1 ); + rc = gmac_phy_read( GMAC, ethernet_phy_addr, usAddress, &ulValue ); + gmac_enable_management( GMAC, 0 ); + if( rc == GMAC_OK ) + { + ulReturn = ulValue; + } + else + { + ulReturn = 0UL; + } + + return ulReturn; +} +/*-----------------------------------------------------------*/ + +static BaseType_t xGMACWaitLS( TickType_t xMaxTime ) +{ +TickType_t xStartTime = xTaskGetTickCount(); +TickType_t xEndTime; +BaseType_t xReturn; +const TickType_t xShortTime = pdMS_TO_TICKS( 100UL ); + + for( ;; ) + { + xEndTime = xTaskGetTickCount(); + + if( ( xEndTime - xStartTime ) > xMaxTime ) + { + /* Wated more than xMaxTime, return. */ + xReturn = pdFALSE; + break; + } + + /* Check the link status again. */ + ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR ); + + if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) + { + /* Link is up - return. */ + xReturn = pdTRUE; + break; + } + + /* Link is down - wait in the Blocked state for a short while (to allow + other tasks to execute) before checking again. */ + vTaskDelay( xShortTime ); + } + + FreeRTOS_printf( ( "xGMACWaitLS: %ld (PHY %d) freq %lu Mz\n", + xReturn, + ethernet_phy_addr, + sysclk_get_cpu_hz() / HZ_PER_MHZ ) ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +//#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 1 ) && ( ipconfigHAS_TX_CRC_OFFLOADING == 0 ) + + void vGMACGenerateChecksum( uint8_t *apBuffer ) + { + ProtocolPacket_t *xProtPacket = (ProtocolPacket_t *)apBuffer; + + if ( xProtPacket->xTCPPacket.xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) + { + IPHeader_t *pxIPHeader = &( xProtPacket->xTCPPacket.xIPHeader ); + + /* Calculate the IP header checksum. */ + pxIPHeader->usHeaderChecksum = 0x00; + pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0u, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER ); + pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); + + /* Calculate the TCP checksum for an outgoing packet. */ + usGenerateProtocolChecksum( ( uint8_t * ) apBuffer, pdTRUE ); + } + } + +//#endif +/*-----------------------------------------------------------*/ + +static uint32_t prvEMACRxPoll( void ) +{ +unsigned char *pucUseBuffer; +uint32_t ulReceiveCount, ulResult, ulReturnValue = 0; +static NetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL; +const UBaseType_t xMinDescriptorsToLeave = 2UL; +const TickType_t xBlockTime = pdMS_TO_TICKS( 100UL ); +static IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; + + for( ;; ) + { + /* If pxNextNetworkBufferDescriptor was not left pointing at a valid + descriptor then allocate one now. */ + if( ( pxNextNetworkBufferDescriptor == NULL ) && ( uxGetNumberOfFreeNetworkBuffers() > xMinDescriptorsToLeave ) ) + { + pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xBlockTime ); + } + + if( pxNextNetworkBufferDescriptor != NULL ) + { + /* Point pucUseBuffer to the buffer pointed to by the descriptor. */ + pucUseBuffer = ( unsigned char* ) ( pxNextNetworkBufferDescriptor->pucEthernetBuffer - ipconfigPACKET_FILLER_SIZE ); + } + else + { + /* As long as pxNextNetworkBufferDescriptor is NULL, the incoming + messages will be flushed and ignored. */ + pucUseBuffer = NULL; + } + + /* Read the next packet from the hardware into pucUseBuffer. */ + ulResult = gmac_dev_read( &gs_gmac_dev, pucUseBuffer, ipTOTAL_ETHERNET_FRAME_SIZE, &ulReceiveCount ); + + if( ( ulResult != GMAC_OK ) || ( ulReceiveCount == 0 ) ) + { + /* No data from the hardware. */ + break; + } + + if( pxNextNetworkBufferDescriptor == NULL ) + { + /* Data was read from the hardware, but no descriptor was available + for it, so it will be dropped. */ + iptraceETHERNET_RX_EVENT_LOST(); + continue; + } + + iptraceNETWORK_INTERFACE_RECEIVE(); + pxNextNetworkBufferDescriptor->xDataLength = ( size_t ) ulReceiveCount; + xRxEvent.pvData = ( void * ) pxNextNetworkBufferDescriptor; + + /* Send the descriptor to the IP task for processing. */ + if( xSendEventStructToIPTask( &xRxEvent, xBlockTime ) != pdTRUE ) + { + /* The buffer could not be sent to the stack so must be released + again. */ + vReleaseNetworkBufferAndDescriptor( pxNextNetworkBufferDescriptor ); + iptraceETHERNET_RX_EVENT_LOST(); + FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) ); + } + + /* Now the buffer has either been passed to the IP-task, + or it has been released in the code above. */ + pxNextNetworkBufferDescriptor = NULL; + ulReturnValue++; + } + + return ulReturnValue; +} +/*-----------------------------------------------------------*/ + +void vCheckBuffersAndQueue( void ) +{ +static UBaseType_t uxLastMinBufferCount = 0; +#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + static UBaseType_t uxLastMinQueueSpace; +#endif +static UBaseType_t uxCurrentCount; + + #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + { + uxCurrentCount = uxGetMinimumIPQueueSpace(); + if( uxLastMinQueueSpace != uxCurrentCount ) + { + /* The logging produced below may be helpful + while tuning +TCP: see how many buffers are in use. */ + uxLastMinQueueSpace = uxCurrentCount; + FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) ); + } + } + #endif /* ipconfigCHECK_IP_QUEUE_SPACE */ + uxCurrentCount = uxGetMinimumFreeNetworkBuffers(); + if( uxLastMinBufferCount != uxCurrentCount ) + { + /* The logging produced below may be helpful + while tuning +TCP: see how many buffers are in use. */ + uxLastMinBufferCount = uxCurrentCount; + FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n", + uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) ); + } + +} + +static void prvEMACHandlerTask( void *pvParameters ) +{ +TimeOut_t xPhyTime; +TickType_t xPhyRemTime; +UBaseType_t uxCount; +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + NetworkBufferDescriptor_t *pxBuffer; +#endif +uint8_t *pucBuffer; +BaseType_t xResult = 0; +uint32_t xStatus; +const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS ); + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + configASSERT( xEMACTaskHandle ); + + vTaskSetTimeOutState( &xPhyTime ); + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS ); + + for( ;; ) + { + vCheckBuffersAndQueue(); + + if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 ) + { + /* No events to process now, wait for the next. */ + ulTaskNotifyTake( pdFALSE, ulMaxBlockTime ); + } + + if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 ) + { + ulISREvents &= ~EMAC_IF_RX_EVENT; + + /* Wait for the EMAC interrupt to indicate that another packet has been + received. */ + xResult = prvEMACRxPoll(); + } + + if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 ) + { + /* Future extension: code to release TX buffers if zero-copy is used. */ + ulISREvents &= ~EMAC_IF_TX_EVENT; + while( xQueueReceive( xTxBufferQueue, &pucBuffer, 0 ) != pdFALSE ) + { + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + pxBuffer = pxPacketBuffer_to_NetworkBuffer( pucBuffer ); + if( pxBuffer != NULL ) + { + vReleaseNetworkBufferAndDescriptor( pxBuffer ); + tx_release_count[ 0 ]++; + } + else + { + tx_release_count[ 1 ]++; + } + } + #else + { + tx_release_count[ 0 ]++; + } + #endif + uxCount = uxQueueMessagesWaiting( ( QueueHandle_t ) xTXDescriptorSemaphore ); + if( uxCount < GMAC_TX_BUFFERS ) + { + /* Tell the counting semaphore that one more TX descriptor is available. */ + xSemaphoreGive( xTXDescriptorSemaphore ); + } + } + } + + if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 ) + { + /* Future extension: logging about errors that occurred. */ + ulISREvents &= ~EMAC_IF_ERR_EVENT; + } + + if( xResult > 0 ) + { + /* A packet was received. No need to check for the PHY status now, + but set a timer to check it later on. */ + vTaskSetTimeOutState( &xPhyTime ); + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS ); + xResult = 0; + } + else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ) + { + /* Check the link status again. */ + xStatus = ulReadMDIO( PHY_REG_01_BMSR ); + + if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) ) + { + ulPHYLinkStatus = xStatus; + FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) ); + } + + vTaskSetTimeOutState( &xPhyTime ); + if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) + { + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS ); + } + else + { + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS ); + } + } + } +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/component/gmac.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/component/gmac.h new file mode 100644 index 000000000..6eb069f55 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/component/gmac.h @@ -0,0 +1,746 @@ +/** + * \file + * + * Copyright (c) 2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _SAM4E_GMAC_COMPONENT_ +#define _SAM4E_GMAC_COMPONENT_ + +/* ============================================================================= */ +/** SOFTWARE API DEFINITION FOR Gigabit Ethernet MAC */ +/* ============================================================================= */ +/** \addtogroup SAM4E_GMAC Gigabit Ethernet MAC */ +/*@{*/ + +#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) +/** \brief GmacSa hardware registers */ +typedef struct { + RwReg GMAC_SAB; /**< \brief (GmacSa Offset: 0x0) Specific Address 1 Bottom [31:0] Register */ + RwReg GMAC_SAT; /**< \brief (GmacSa Offset: 0x4) Specific Address 1 Top [47:32] Register */ +} GmacSa; +/** \brief Gmac hardware registers */ +#define GMACSA_NUMBER 4 +typedef struct { + RwReg GMAC_NCR; /**< \brief (Gmac Offset: 0x000) Network Control Register */ + RwReg GMAC_NCFGR; /**< \brief (Gmac Offset: 0x004) Network Configuration Register */ + RoReg GMAC_NSR; /**< \brief (Gmac Offset: 0x008) Network Status Register */ + RwReg GMAC_UR; /**< \brief (Gmac Offset: 0x00C) User Register */ + RwReg GMAC_DCFGR; /**< \brief (Gmac Offset: 0x010) DMA Configuration Register */ + RwReg GMAC_TSR; /**< \brief (Gmac Offset: 0x014) Transmit Status Register */ + RwReg GMAC_RBQB; /**< \brief (Gmac Offset: 0x018) Receive Buffer Queue Base Address */ + RwReg GMAC_TBQB; /**< \brief (Gmac Offset: 0x01C) Transmit Buffer Queue Base Address */ + RwReg GMAC_RSR; /**< \brief (Gmac Offset: 0x020) Receive Status Register */ + RoReg GMAC_ISR; /**< \brief (Gmac Offset: 0x024) Interrupt Status Register */ + WoReg GMAC_IER; /**< \brief (Gmac Offset: 0x028) Interrupt Enable Register */ + WoReg GMAC_IDR; /**< \brief (Gmac Offset: 0x02C) Interrupt Disable Register */ + RoReg GMAC_IMR; /**< \brief (Gmac Offset: 0x030) Interrupt Mask Register */ + RwReg GMAC_MAN; /**< \brief (Gmac Offset: 0x034) PHY Maintenance Register */ + RoReg GMAC_RPQ; /**< \brief (Gmac Offset: 0x038) Received Pause Quantum Register */ + RwReg GMAC_TPQ; /**< \brief (Gmac Offset: 0x03C) Transmit Pause Quantum Register */ + RwReg GMAC_TPSF; /**< \brief (Gmac Offset: 0x040) TX Partial Store and Forward Register */ + RwReg GMAC_RPSF; /**< \brief (Gmac Offset: 0x044) RX Partial Store and Forward Register */ + RoReg Reserved1[14]; + RwReg GMAC_HRB; /**< \brief (Gmac Offset: 0x080) Hash Register Bottom [31:0] */ + RwReg GMAC_HRT; /**< \brief (Gmac Offset: 0x084) Hash Register Top [63:32] */ + GmacSa GMAC_SA[GMACSA_NUMBER]; /**< \brief (Gmac Offset: 0x088) 1 .. 4 */ + RwReg GMAC_TIDM[4]; /**< \brief (Gmac Offset: 0x0A8) Type ID Match 1 Register */ + RwReg GMAC_WOL; /**< \brief (Gmac Offset: 0x0B8) Wake on LAN Register */ + RwReg GMAC_IPGS; /**< \brief (Gmac Offset: 0x0BC) IPG Stretch Register */ + RwReg GMAC_SVLAN; /**< \brief (Gmac Offset: 0x0C0) Stacked VLAN Register */ + RwReg GMAC_TPFCP; /**< \brief (Gmac Offset: 0x0C4) Transmit PFC Pause Register */ + RwReg GMAC_SAMB1; /**< \brief (Gmac Offset: 0x0C8) Specific Address 1 Mask Bottom [31:0] Register */ + RwReg GMAC_SAMT1; /**< \brief (Gmac Offset: 0x0CC) Specific Address 1 Mask Top [47:32] Register */ + RoReg Reserved2[12]; + RoReg GMAC_OTLO; /**< \brief (Gmac Offset: 0x100) Octets Transmitted [31:0] Register */ + RoReg GMAC_OTHI; /**< \brief (Gmac Offset: 0x104) Octets Transmitted [47:32] Register */ + RoReg GMAC_FT; /**< \brief (Gmac Offset: 0x108) Frames Transmitted Register */ + RoReg GMAC_BCFT; /**< \brief (Gmac Offset: 0x10C) Broadcast Frames Transmitted Register */ + RoReg GMAC_MFT; /**< \brief (Gmac Offset: 0x110) Multicast Frames Transmitted Register */ + RoReg GMAC_PFT; /**< \brief (Gmac Offset: 0x114) Pause Frames Transmitted Register */ + RoReg GMAC_BFT64; /**< \brief (Gmac Offset: 0x118) 64 Byte Frames Transmitted Register */ + RoReg GMAC_TBFT127; /**< \brief (Gmac Offset: 0x11C) 65 to 127 Byte Frames Transmitted Register */ + RoReg GMAC_TBFT255; /**< \brief (Gmac Offset: 0x120) 128 to 255 Byte Frames Transmitted Register */ + RoReg GMAC_TBFT511; /**< \brief (Gmac Offset: 0x124) 256 to 511 Byte Frames Transmitted Register */ + RoReg GMAC_TBFT1023; /**< \brief (Gmac Offset: 0x128) 512 to 1023 Byte Frames Transmitted Register */ + RoReg GMAC_TBFT1518; /**< \brief (Gmac Offset: 0x12C) 1024 to 1518 Byte Frames Transmitted Register */ + RoReg GMAC_GTBFT1518; /**< \brief (Gmac Offset: 0x130) Greater Than 1518 Byte Frames Transmitted Register */ + RoReg GMAC_TUR; /**< \brief (Gmac Offset: 0x134) Transmit Under Runs Register */ + RoReg GMAC_SCF; /**< \brief (Gmac Offset: 0x138) Single Collision Frames Register */ + RoReg GMAC_MCF; /**< \brief (Gmac Offset: 0x13C) Multiple Collision Frames Register */ + RoReg GMAC_EC; /**< \brief (Gmac Offset: 0x140) Excessive Collisions Register */ + RoReg GMAC_LC; /**< \brief (Gmac Offset: 0x144) Late Collisions Register */ + RoReg GMAC_DTF; /**< \brief (Gmac Offset: 0x148) Deferred Transmission Frames Register */ + RoReg GMAC_CSE; /**< \brief (Gmac Offset: 0x14C) Carrier Sense Errors Register */ + RoReg GMAC_ORLO; /**< \brief (Gmac Offset: 0x150) Octets Received [31:0] Received */ + RoReg GMAC_ORHI; /**< \brief (Gmac Offset: 0x154) Octets Received [47:32] Received */ + RoReg GMAC_FR; /**< \brief (Gmac Offset: 0x158) Frames Received Register */ + RoReg GMAC_BCFR; /**< \brief (Gmac Offset: 0x15C) Broadcast Frames Received Register */ + RoReg GMAC_MFR; /**< \brief (Gmac Offset: 0x160) Multicast Frames Received Register */ + RoReg GMAC_PFR; /**< \brief (Gmac Offset: 0x164) Pause Frames Received Register */ + RoReg GMAC_BFR64; /**< \brief (Gmac Offset: 0x168) 64 Byte Frames Received Register */ + RoReg GMAC_TBFR127; /**< \brief (Gmac Offset: 0x16C) 65 to 127 Byte Frames Received Register */ + RoReg GMAC_TBFR255; /**< \brief (Gmac Offset: 0x170) 128 to 255 Byte Frames Received Register */ + RoReg GMAC_TBFR511; /**< \brief (Gmac Offset: 0x174) 256 to 511Byte Frames Received Register */ + RoReg GMAC_TBFR1023; /**< \brief (Gmac Offset: 0x178) 512 to 1023 Byte Frames Received Register */ + RoReg GMAC_TBFR1518; /**< \brief (Gmac Offset: 0x17C) 1024 to 1518 Byte Frames Received Register */ + RoReg GMAC_TMXBFR; /**< \brief (Gmac Offset: 0x180) 1519 to Maximum Byte Frames Received Register */ + RoReg GMAC_UFR; /**< \brief (Gmac Offset: 0x184) Undersize Frames Received Register */ + RoReg GMAC_OFR; /**< \brief (Gmac Offset: 0x188) Oversize Frames Received Register */ + RoReg GMAC_JR; /**< \brief (Gmac Offset: 0x18C) Jabbers Received Register */ + RoReg GMAC_FCSE; /**< \brief (Gmac Offset: 0x190) Frame Check Sequence Errors Register */ + RoReg GMAC_LFFE; /**< \brief (Gmac Offset: 0x194) Length Field Frame Errors Register */ + RoReg GMAC_RSE; /**< \brief (Gmac Offset: 0x198) Receive Symbol Errors Register */ + RoReg GMAC_AE; /**< \brief (Gmac Offset: 0x19C) Alignment Errors Register */ + RoReg GMAC_RRE; /**< \brief (Gmac Offset: 0x1A0) Receive Resource Errors Register */ + RoReg GMAC_ROE; /**< \brief (Gmac Offset: 0x1A4) Receive Overrun Register */ + RoReg GMAC_IHCE; /**< \brief (Gmac Offset: 0x1A8) IP Header Checksum Errors Register */ + RoReg GMAC_TCE; /**< \brief (Gmac Offset: 0x1AC) TCP Checksum Errors Register */ + RoReg GMAC_UCE; /**< \brief (Gmac Offset: 0x1B0) UDP Checksum Errors Register */ + RoReg Reserved3[5]; + RwReg GMAC_TSSS; /**< \brief (Gmac Offset: 0x1C8) 1588 Timer Sync Strobe Seconds Register */ + RwReg GMAC_TSSN; /**< \brief (Gmac Offset: 0x1CC) 1588 Timer Sync Strobe Nanoseconds Register */ + RwReg GMAC_TS; /**< \brief (Gmac Offset: 0x1D0) 1588 Timer Seconds Register */ + RwReg GMAC_TN; /**< \brief (Gmac Offset: 0x1D4) 1588 Timer Nanoseconds Register */ + WoReg GMAC_TA; /**< \brief (Gmac Offset: 0x1D8) 1588 Timer Adjust Register */ + RwReg GMAC_TI; /**< \brief (Gmac Offset: 0x1DC) 1588 Timer Increment Register */ + RoReg GMAC_EFTS; /**< \brief (Gmac Offset: 0x1E0) PTP Event Frame Transmitted Seconds */ + RoReg GMAC_EFTN; /**< \brief (Gmac Offset: 0x1E4) PTP Event Frame Transmitted Nanoseconds */ + RoReg GMAC_EFRS; /**< \brief (Gmac Offset: 0x1E8) PTP Event Frame Received Seconds */ + RoReg GMAC_EFRN; /**< \brief (Gmac Offset: 0x1EC) PTP Event Frame Received Nanoseconds */ + RoReg GMAC_PEFTS; /**< \brief (Gmac Offset: 0x1F0) PTP Peer Event Frame Transmitted Seconds */ + RoReg GMAC_PEFTN; /**< \brief (Gmac Offset: 0x1F4) PTP Peer Event Frame Transmitted Nanoseconds */ + RoReg GMAC_PEFRS; /**< \brief (Gmac Offset: 0x1F8) PTP Peer Event Frame Received Seconds */ + RoReg GMAC_PEFRN; /**< \brief (Gmac Offset: 0x1FC) PTP Peer Event Frame Received Nanoseconds */ + RoReg Reserved4[128]; + RoReg GMAC_ISRPQ[7]; /**< \brief (Gmac Offset: 0x400) Interrupt Status Register Priority Queue */ + RoReg Reserved5[9]; + RwReg GMAC_TBQBAPQ[7]; /**< \brief (Gmac Offset: 0x440) Transmit Buffer Queue Base Address Priority Queue */ + RoReg Reserved6[9]; + RwReg GMAC_RBQBAPQ[7]; /**< \brief (Gmac Offset: 0x480) Receive Buffer Queue Base Address Priority Queue */ + RoReg Reserved7[1]; + RwReg GMAC_RBSRPQ[7]; /**< \brief (Gmac Offset: 0x4A0) Receive Buffer Size Register Priority Queue */ + RoReg Reserved8[17]; + RwReg GMAC_ST1RPQ[16]; /**< \brief (Gmac Offset: 0x500) Screening Type1 Register Priority Queue */ + RwReg GMAC_ST2RPQ[16]; /**< \brief (Gmac Offset: 0x540) Screening Type2 Register Priority Queue */ + RoReg Reserved9[32]; + WoReg GMAC_IERPQ[7]; /**< \brief (Gmac Offset: 0x600) Interrupt Enable Register Priority Queue */ + RoReg Reserved10[1]; + WoReg GMAC_IDRPQ[7]; /**< \brief (Gmac Offset: 0x620) Interrupt Disable Register Priority Queue */ + RoReg Reserved11[1]; + RwReg GMAC_IMRPQ[7]; /**< \brief (Gmac Offset: 0x640) Interrupt Mask Register Priority Queue */ +} Gmac; +#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */ +/* -------- GMAC_NCR : (GMAC Offset: 0x000) Network Control Register -------- */ +#define GMAC_NCR_LB (0x1u << 0) /**< \brief (GMAC_NCR) Loop Back */ +#define GMAC_NCR_LBL (0x1u << 1) /**< \brief (GMAC_NCR) Loop Back Local */ +#define GMAC_NCR_RXEN (0x1u << 2) /**< \brief (GMAC_NCR) Receive Enable */ +#define GMAC_NCR_TXEN (0x1u << 3) /**< \brief (GMAC_NCR) Transmit Enable */ +#define GMAC_NCR_MPE (0x1u << 4) /**< \brief (GMAC_NCR) Management Port Enable */ +#define GMAC_NCR_CLRSTAT (0x1u << 5) /**< \brief (GMAC_NCR) Clear Statistics Registers */ +#define GMAC_NCR_INCSTAT (0x1u << 6) /**< \brief (GMAC_NCR) Increment Statistics Registers */ +#define GMAC_NCR_WESTAT (0x1u << 7) /**< \brief (GMAC_NCR) Write Enable for Statistics Registers */ +#define GMAC_NCR_BP (0x1u << 8) /**< \brief (GMAC_NCR) Back pressure */ +#define GMAC_NCR_TSTART (0x1u << 9) /**< \brief (GMAC_NCR) Start Transmission */ +#define GMAC_NCR_THALT (0x1u << 10) /**< \brief (GMAC_NCR) Transmit Halt */ +#define GMAC_NCR_TXPF (0x1u << 11) /**< \brief (GMAC_NCR) Transmit Pause Frame */ +#define GMAC_NCR_TXZQPF (0x1u << 12) /**< \brief (GMAC_NCR) Transmit Zero Quantum Pause Frame */ +#define GMAC_NCR_RDS (0x1u << 14) /**< \brief (GMAC_NCR) Read Snapshot */ +#define GMAC_NCR_SRTSM (0x1u << 15) /**< \brief (GMAC_NCR) Store Receive Time Stamp to Memory */ +#define GMAC_NCR_ENPBPR (0x1u << 16) /**< \brief (GMAC_NCR) Enable PFC Priority-based Pause Reception */ +#define GMAC_NCR_TXPBPF (0x1u << 17) /**< \brief (GMAC_NCR) Transmit PFC Priority-based Pause Frame */ +#define GMAC_NCR_FNP (0x1u << 18) /**< \brief (GMAC_NCR) Flush Next Packet */ +/* -------- GMAC_NCFGR : (GMAC Offset: 0x004) Network Configuration Register -------- */ +#define GMAC_NCFGR_SPD (0x1u << 0) /**< \brief (GMAC_NCFGR) Speed */ +#define GMAC_NCFGR_FD (0x1u << 1) /**< \brief (GMAC_NCFGR) Full Duplex */ +#define GMAC_NCFGR_DNVLAN (0x1u << 2) /**< \brief (GMAC_NCFGR) Discard Non-VLAN FRAMES */ +#define GMAC_NCFGR_JFRAME (0x1u << 3) /**< \brief (GMAC_NCFGR) Jumbo Frame Size */ +#define GMAC_NCFGR_CAF (0x1u << 4) /**< \brief (GMAC_NCFGR) Copy All Frames */ +#define GMAC_NCFGR_NBC (0x1u << 5) /**< \brief (GMAC_NCFGR) No Broadcast */ +#define GMAC_NCFGR_MTIHEN (0x1u << 6) /**< \brief (GMAC_NCFGR) Multicast Hash Enable */ +#define GMAC_NCFGR_UNIHEN (0x1u << 7) /**< \brief (GMAC_NCFGR) Unicast Hash Enable */ +#define GMAC_NCFGR_MAXFS (0x1u << 8) /**< \brief (GMAC_NCFGR) 1536 Maximum Frame Size */ +#define GMAC_NCFGR_GBE (0x1u << 10) /**< \brief (GMAC_NCFGR) Gigabit Mode Enable */ +#define GMAC_NCFGR_PIS (0x1u << 11) /**< \brief (GMAC_NCFGR) Physical Interface Select */ +#define GMAC_NCFGR_RTY (0x1u << 12) /**< \brief (GMAC_NCFGR) Retry Test */ +#define GMAC_NCFGR_PEN (0x1u << 13) /**< \brief (GMAC_NCFGR) Pause Enable */ +#define GMAC_NCFGR_RXBUFO_Pos 14 +#define GMAC_NCFGR_RXBUFO_Msk (0x3u << GMAC_NCFGR_RXBUFO_Pos) /**< \brief (GMAC_NCFGR) Receive Buffer Offset */ +#define GMAC_NCFGR_RXBUFO(value) ((GMAC_NCFGR_RXBUFO_Msk & ((value) << GMAC_NCFGR_RXBUFO_Pos))) +#define GMAC_NCFGR_LFERD (0x1u << 16) /**< \brief (GMAC_NCFGR) Length Field Error Frame Discard */ +#define GMAC_NCFGR_RFCS (0x1u << 17) /**< \brief (GMAC_NCFGR) Remove FCS */ +#define GMAC_NCFGR_CLK_Pos 18 +#define GMAC_NCFGR_CLK_Msk (0x7u << GMAC_NCFGR_CLK_Pos) /**< \brief (GMAC_NCFGR) MDC CLock Division */ +#define GMAC_NCFGR_CLK_MCK_8 (0x0u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 8 (MCK up to 20 MHz) */ +#define GMAC_NCFGR_CLK_MCK_16 (0x1u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 16 (MCK up to 40 MHz) */ +#define GMAC_NCFGR_CLK_MCK_32 (0x2u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 32 (MCK up to 80 MHz) */ +#define GMAC_NCFGR_CLK_MCK_48 (0x3u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 48 (MCK up to 120MHz) */ +#define GMAC_NCFGR_CLK_MCK_64 (0x4u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 64 (MCK up to 160 MHz) */ +#define GMAC_NCFGR_CLK_MCK_96 (0x5u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 96 (MCK up to 240 MHz) */ +#define GMAC_NCFGR_CLK_MCK_128 (0x6u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 128 (MCK up to 320 MHz) */ +#define GMAC_NCFGR_CLK_MCK_224 (0x7u << 18) /**< \brief (GMAC_NCFGR) MCK divided by 224 (MCK up to 540 MHz) */ +#define GMAC_NCFGR_DBW_Pos 21 +#define GMAC_NCFGR_DBW_Msk (0x3u << GMAC_NCFGR_DBW_Pos) /**< \brief (GMAC_NCFGR) Data Bus Width */ +#define GMAC_NCFGR_DBW_DBW32 (0x0u << 21) /**< \brief (GMAC_NCFGR) 32-bit data bus width */ +#define GMAC_NCFGR_DBW_DBW64 (0x1u << 21) /**< \brief (GMAC_NCFGR) 64-bit data bus width */ +#define GMAC_NCFGR_DCPF (0x1u << 23) /**< \brief (GMAC_NCFGR) Disable Copy of Pause Frames */ +#define GMAC_NCFGR_RXCOEN (0x1u << 24) /**< \brief (GMAC_NCFGR) Receive Checksum Offload Enable */ +#define GMAC_NCFGR_EFRHD (0x1u << 25) /**< \brief (GMAC_NCFGR) Enable Frames Received in Half Duplex */ +#define GMAC_NCFGR_IRXFCS (0x1u << 26) /**< \brief (GMAC_NCFGR) Ignore RX FCS */ +#define GMAC_NCFGR_IPGSEN (0x1u << 28) /**< \brief (GMAC_NCFGR) IP Stretch Enable */ +#define GMAC_NCFGR_RXBP (0x1u << 29) /**< \brief (GMAC_NCFGR) Receive Bad Preamble */ +#define GMAC_NCFGR_IRXER (0x1u << 30) /**< \brief (GMAC_NCFGR) Ignore IPG rx_er */ +/* -------- GMAC_NSR : (GMAC Offset: 0x008) Network Status Register -------- */ +#define GMAC_NSR_MDIO (0x1u << 1) /**< \brief (GMAC_NSR) MDIO Input Status */ +#define GMAC_NSR_IDLE (0x1u << 2) /**< \brief (GMAC_NSR) PHY Management Logic Idle */ +/* -------- GMAC_UR : (GMAC Offset: 0x00C) User Register -------- */ +#define GMAC_UR_RGMII (0x1u << 0) /**< \brief (GMAC_UR) RGMII Mode */ +#define GMAC_UR_HDFC (0x1u << 6) /**< \brief (GMAC_UR) Half Duplex Flow Control */ +#define GMAC_UR_BPDG (0x1u << 7) /**< \brief (GMAC_UR) BPDG Bypass Deglitchers */ +/* -------- GMAC_DCFGR : (GMAC Offset: 0x010) DMA Configuration Register -------- */ +#define GMAC_DCFGR_FBLDO_Pos 0 +#define GMAC_DCFGR_FBLDO_Msk (0x1fu << GMAC_DCFGR_FBLDO_Pos) /**< \brief (GMAC_DCFGR) Fixed Burst Length for DMA Data Operations: */ +#define GMAC_DCFGR_FBLDO_SINGLE (0x1u << 0) /**< \brief (GMAC_DCFGR) 00001: Always use SINGLE AHB bursts */ +#define GMAC_DCFGR_FBLDO_INCR4 (0x4u << 0) /**< \brief (GMAC_DCFGR) 001xx: Attempt to use INCR4 AHB bursts (Default) */ +#define GMAC_DCFGR_FBLDO_INCR8 (0x8u << 0) /**< \brief (GMAC_DCFGR) 01xxx: Attempt to use INCR8 AHB bursts */ +#define GMAC_DCFGR_FBLDO_INCR16 (0x10u << 0) /**< \brief (GMAC_DCFGR) 1xxxx: Attempt to use INCR16 AHB bursts */ +#define GMAC_DCFGR_ESMA (0x1u << 6) /**< \brief (GMAC_DCFGR) Endian Swap Mode Enable for Management Descriptor Accesses */ +#define GMAC_DCFGR_ESPA (0x1u << 7) /**< \brief (GMAC_DCFGR) Endian Swap Mode Enable for Packet Data Accesses */ +#define GMAC_DCFGR_RXBMS_Pos 8 +#define GMAC_DCFGR_RXBMS_Msk (0x3u << GMAC_DCFGR_RXBMS_Pos) /**< \brief (GMAC_DCFGR) Receiver Packet Buffer Memory Size Select */ +#define GMAC_DCFGR_RXBMS_EIGHTH (0x0u << 8) /**< \brief (GMAC_DCFGR) 1 Kbyte Memory Size */ +#define GMAC_DCFGR_RXBMS_QUARTER (0x1u << 8) /**< \brief (GMAC_DCFGR) 2 Kbytes Memory Size */ +#define GMAC_DCFGR_RXBMS_HALF (0x2u << 8) /**< \brief (GMAC_DCFGR) 4 Kbytes Memory Size */ +#define GMAC_DCFGR_RXBMS_FULL (0x3u << 8) /**< \brief (GMAC_DCFGR) 8 Kbytes Memory Size */ +#define GMAC_DCFGR_TXPBMS (0x1u << 10) /**< \brief (GMAC_DCFGR) Transmitter Packet Buffer Memory Size Select */ +#define GMAC_DCFGR_TXCOEN (0x1u << 11) /**< \brief (GMAC_DCFGR) Transmitter Checksum Generation Offload Enable */ +#define GMAC_DCFGR_DRBS_Pos 16 +#define GMAC_DCFGR_DRBS_Msk (0xffu << GMAC_DCFGR_DRBS_Pos) /**< \brief (GMAC_DCFGR) DMA Receive Buffer Size */ +#define GMAC_DCFGR_DRBS(value) ((GMAC_DCFGR_DRBS_Msk & ((value) << GMAC_DCFGR_DRBS_Pos))) +#define GMAC_DCFGR_DDRP (0x1u << 24) /**< \brief (GMAC_DCFGR) DMA Discard Receive Packets */ +/* -------- GMAC_TSR : (GMAC Offset: 0x014) Transmit Status Register -------- */ +#define GMAC_TSR_UBR (0x1u << 0) /**< \brief (GMAC_TSR) Used Bit Read */ +#define GMAC_TSR_COL (0x1u << 1) /**< \brief (GMAC_TSR) Collision Occurred */ +#define GMAC_TSR_RLE (0x1u << 2) /**< \brief (GMAC_TSR) Retry Limit Exceeded */ +#define GMAC_TSR_TXGO (0x1u << 3) /**< \brief (GMAC_TSR) Transmit Go */ +#define GMAC_TSR_TFC (0x1u << 4) /**< \brief (GMAC_TSR) Transmit Frame Corruption due to AHB error */ +#define GMAC_TSR_TXCOMP (0x1u << 5) /**< \brief (GMAC_TSR) Transmit Complete */ +#define GMAC_TSR_UND (0x1u << 6) /**< \brief (GMAC_TSR) Transmit Under Run */ +#define GMAC_TSR_LCO (0x1u << 7) /**< \brief (GMAC_TSR) Late Collision Occurred */ +#define GMAC_TSR_HRESP (0x1u << 8) /**< \brief (GMAC_TSR) HRESP Not OK */ +/* -------- GMAC_RBQB : (GMAC Offset: 0x018) Receive Buffer Queue Base Address -------- */ +#define GMAC_RBQB_ADDR_Pos 2 +#define GMAC_RBQB_ADDR_Msk (0x3fffffffu << GMAC_RBQB_ADDR_Pos) /**< \brief (GMAC_RBQB) Receive buffer queue base address */ +#define GMAC_RBQB_ADDR(value) ((GMAC_RBQB_ADDR_Msk & ((value) << GMAC_RBQB_ADDR_Pos))) +/* -------- GMAC_TBQB : (GMAC Offset: 0x01C) Transmit Buffer Queue Base Address -------- */ +#define GMAC_TBQB_ADDR_Pos 2 +#define GMAC_TBQB_ADDR_Msk (0x3fffffffu << GMAC_TBQB_ADDR_Pos) /**< \brief (GMAC_TBQB) Transmit Buffer Queue Base Address */ +#define GMAC_TBQB_ADDR(value) ((GMAC_TBQB_ADDR_Msk & ((value) << GMAC_TBQB_ADDR_Pos))) +/* -------- GMAC_RSR : (GMAC Offset: 0x020) Receive Status Register -------- */ +#define GMAC_RSR_BNA (0x1u << 0) /**< \brief (GMAC_RSR) Buffer Not Available */ +#define GMAC_RSR_REC (0x1u << 1) /**< \brief (GMAC_RSR) Frame Received */ +#define GMAC_RSR_RXOVR (0x1u << 2) /**< \brief (GMAC_RSR) Receive Overrun */ +#define GMAC_RSR_HNO (0x1u << 3) /**< \brief (GMAC_RSR) HRESP Not OK */ +/* -------- GMAC_ISR : (GMAC Offset: 0x024) Interrupt Status Register -------- */ +#define GMAC_ISR_MFS (0x1u << 0) /**< \brief (GMAC_ISR) Management Frame Sent */ +#define GMAC_ISR_RCOMP (0x1u << 1) /**< \brief (GMAC_ISR) Receive Complete */ +#define GMAC_ISR_RXUBR (0x1u << 2) /**< \brief (GMAC_ISR) RX Used Bit Read */ +#define GMAC_ISR_TXUBR (0x1u << 3) /**< \brief (GMAC_ISR) TX Used Bit Read */ +#define GMAC_ISR_TUR (0x1u << 4) /**< \brief (GMAC_ISR) Transmit Under Run */ +#define GMAC_ISR_RLEX (0x1u << 5) /**< \brief (GMAC_ISR) Retry Limit Exceeded or Late Collision */ +#define GMAC_ISR_TFC (0x1u << 6) /**< \brief (GMAC_ISR) Transmit Frame Corruption due to AHB error */ +#define GMAC_ISR_TCOMP (0x1u << 7) /**< \brief (GMAC_ISR) Transmit Complete */ +#define GMAC_ISR_ROVR (0x1u << 10) /**< \brief (GMAC_ISR) Receive Overrun */ +#define GMAC_ISR_HRESP (0x1u << 11) /**< \brief (GMAC_ISR) HRESP Not OK */ +#define GMAC_ISR_PFNZ (0x1u << 12) /**< \brief (GMAC_ISR) Pause Frame with Non-zero Pause Quantum Received */ +#define GMAC_ISR_PTZ (0x1u << 13) /**< \brief (GMAC_ISR) Pause Time Zero */ +#define GMAC_ISR_PFTR (0x1u << 14) /**< \brief (GMAC_ISR) Pause Frame Transmitted */ +#define GMAC_ISR_EXINT (0x1u << 15) /**< \brief (GMAC_ISR) External Interrupt */ +#define GMAC_ISR_DRQFR (0x1u << 18) /**< \brief (GMAC_ISR) PTP Delay Request Frame Received */ +#define GMAC_ISR_SFR (0x1u << 19) /**< \brief (GMAC_ISR) PTP Sync Frame Received */ +#define GMAC_ISR_DRQFT (0x1u << 20) /**< \brief (GMAC_ISR) PTP Delay Request Frame Transmitted */ +#define GMAC_ISR_SFT (0x1u << 21) /**< \brief (GMAC_ISR) PTP Sync Frame Transmitted */ +#define GMAC_ISR_PDRQFR (0x1u << 22) /**< \brief (GMAC_ISR) PDelay Request Frame Received */ +#define GMAC_ISR_PDRSFR (0x1u << 23) /**< \brief (GMAC_ISR) PDelay Response Frame Received */ +#define GMAC_ISR_PDRQFT (0x1u << 24) /**< \brief (GMAC_ISR) PDelay Request Frame Transmitted */ +#define GMAC_ISR_PDRSFT (0x1u << 25) /**< \brief (GMAC_ISR) PDelay Response Frame Transmitted */ +#define GMAC_ISR_SRI (0x1u << 26) /**< \brief (GMAC_ISR) TSU Seconds Register Increment */ +#define GMAC_ISR_WOL (0x1u << 28) /**< \brief (GMAC_ISR) Wake On LAN */ +/* -------- GMAC_IER : (GMAC Offset: 0x028) Interrupt Enable Register -------- */ +#define GMAC_IER_MFS (0x1u << 0) /**< \brief (GMAC_IER) Management Frame Sent */ +#define GMAC_IER_RCOMP (0x1u << 1) /**< \brief (GMAC_IER) Receive Complete */ +#define GMAC_IER_RXUBR (0x1u << 2) /**< \brief (GMAC_IER) RX Used Bit Read */ +#define GMAC_IER_TXUBR (0x1u << 3) /**< \brief (GMAC_IER) TX Used Bit Read */ +#define GMAC_IER_TUR (0x1u << 4) /**< \brief (GMAC_IER) Transmit Under Run */ +#define GMAC_IER_RLEX (0x1u << 5) /**< \brief (GMAC_IER) Retry Limit Exceeded or Late Collision */ +#define GMAC_IER_TFC (0x1u << 6) /**< \brief (GMAC_IER) Transmit Frame Corruption due to AHB error */ +#define GMAC_IER_TCOMP (0x1u << 7) /**< \brief (GMAC_IER) Transmit Complete */ +#define GMAC_IER_ROVR (0x1u << 10) /**< \brief (GMAC_IER) Receive Overrun */ +#define GMAC_IER_HRESP (0x1u << 11) /**< \brief (GMAC_IER) HRESP Not OK */ +#define GMAC_IER_PFNZ (0x1u << 12) /**< \brief (GMAC_IER) Pause Frame with Non-zero Pause Quantum Received */ +#define GMAC_IER_PTZ (0x1u << 13) /**< \brief (GMAC_IER) Pause Time Zero */ +#define GMAC_IER_PFTR (0x1u << 14) /**< \brief (GMAC_IER) Pause Frame Transmitted */ +#define GMAC_IER_EXINT (0x1u << 15) /**< \brief (GMAC_IER) External Interrupt */ +#define GMAC_IER_DRQFR (0x1u << 18) /**< \brief (GMAC_IER) PTP Delay Request Frame Received */ +#define GMAC_IER_SFR (0x1u << 19) /**< \brief (GMAC_IER) PTP Sync Frame Received */ +#define GMAC_IER_DRQFT (0x1u << 20) /**< \brief (GMAC_IER) PTP Delay Request Frame Transmitted */ +#define GMAC_IER_SFT (0x1u << 21) /**< \brief (GMAC_IER) PTP Sync Frame Transmitted */ +#define GMAC_IER_PDRQFR (0x1u << 22) /**< \brief (GMAC_IER) PDelay Request Frame Received */ +#define GMAC_IER_PDRSFR (0x1u << 23) /**< \brief (GMAC_IER) PDelay Response Frame Received */ +#define GMAC_IER_PDRQFT (0x1u << 24) /**< \brief (GMAC_IER) PDelay Request Frame Transmitted */ +#define GMAC_IER_PDRSFT (0x1u << 25) /**< \brief (GMAC_IER) PDelay Response Frame Transmitted */ +#define GMAC_IER_SRI (0x1u << 26) /**< \brief (GMAC_IER) TSU Seconds Register Increment */ +#define GMAC_IER_WOL (0x1u << 28) /**< \brief (GMAC_IER) Wake On LAN */ +/* -------- GMAC_IDR : (GMAC Offset: 0x02C) Interrupt Disable Register -------- */ +#define GMAC_IDR_MFS (0x1u << 0) /**< \brief (GMAC_IDR) Management Frame Sent */ +#define GMAC_IDR_RCOMP (0x1u << 1) /**< \brief (GMAC_IDR) Receive Complete */ +#define GMAC_IDR_RXUBR (0x1u << 2) /**< \brief (GMAC_IDR) RX Used Bit Read */ +#define GMAC_IDR_TXUBR (0x1u << 3) /**< \brief (GMAC_IDR) TX Used Bit Read */ +#define GMAC_IDR_TUR (0x1u << 4) /**< \brief (GMAC_IDR) Transmit Under Run */ +#define GMAC_IDR_RLEX (0x1u << 5) /**< \brief (GMAC_IDR) Retry Limit Exceeded or Late Collision */ +#define GMAC_IDR_TFC (0x1u << 6) /**< \brief (GMAC_IDR) Transmit Frame Corruption due to AHB error */ +#define GMAC_IDR_TCOMP (0x1u << 7) /**< \brief (GMAC_IDR) Transmit Complete */ +#define GMAC_IDR_ROVR (0x1u << 10) /**< \brief (GMAC_IDR) Receive Overrun */ +#define GMAC_IDR_HRESP (0x1u << 11) /**< \brief (GMAC_IDR) HRESP Not OK */ +#define GMAC_IDR_PFNZ (0x1u << 12) /**< \brief (GMAC_IDR) Pause Frame with Non-zero Pause Quantum Received */ +#define GMAC_IDR_PTZ (0x1u << 13) /**< \brief (GMAC_IDR) Pause Time Zero */ +#define GMAC_IDR_PFTR (0x1u << 14) /**< \brief (GMAC_IDR) Pause Frame Transmitted */ +#define GMAC_IDR_EXINT (0x1u << 15) /**< \brief (GMAC_IDR) External Interrupt */ +#define GMAC_IDR_DRQFR (0x1u << 18) /**< \brief (GMAC_IDR) PTP Delay Request Frame Received */ +#define GMAC_IDR_SFR (0x1u << 19) /**< \brief (GMAC_IDR) PTP Sync Frame Received */ +#define GMAC_IDR_DRQFT (0x1u << 20) /**< \brief (GMAC_IDR) PTP Delay Request Frame Transmitted */ +#define GMAC_IDR_SFT (0x1u << 21) /**< \brief (GMAC_IDR) PTP Sync Frame Transmitted */ +#define GMAC_IDR_PDRQFR (0x1u << 22) /**< \brief (GMAC_IDR) PDelay Request Frame Received */ +#define GMAC_IDR_PDRSFR (0x1u << 23) /**< \brief (GMAC_IDR) PDelay Response Frame Received */ +#define GMAC_IDR_PDRQFT (0x1u << 24) /**< \brief (GMAC_IDR) PDelay Request Frame Transmitted */ +#define GMAC_IDR_PDRSFT (0x1u << 25) /**< \brief (GMAC_IDR) PDelay Response Frame Transmitted */ +#define GMAC_IDR_SRI (0x1u << 26) /**< \brief (GMAC_IDR) TSU Seconds Register Increment */ +#define GMAC_IDR_WOL (0x1u << 28) /**< \brief (GMAC_IDR) Wake On LAN */ +/* -------- GMAC_IMR : (GMAC Offset: 0x030) Interrupt Mask Register -------- */ +#define GMAC_IMR_MFS (0x1u << 0) /**< \brief (GMAC_IMR) Management Frame Sent */ +#define GMAC_IMR_RCOMP (0x1u << 1) /**< \brief (GMAC_IMR) Receive Complete */ +#define GMAC_IMR_RXUBR (0x1u << 2) /**< \brief (GMAC_IMR) RX Used Bit Read */ +#define GMAC_IMR_TXUBR (0x1u << 3) /**< \brief (GMAC_IMR) TX Used Bit Read */ +#define GMAC_IMR_TUR (0x1u << 4) /**< \brief (GMAC_IMR) Transmit Under Run */ +#define GMAC_IMR_RLEX (0x1u << 5) /**< \brief (GMAC_IMR) Retry Limit Exceeded or Late Collision */ +#define GMAC_IMR_TFC (0x1u << 6) /**< \brief (GMAC_IMR) Transmit Frame Corruption due to AHB error */ +#define GMAC_IMR_TCOMP (0x1u << 7) /**< \brief (GMAC_IMR) Transmit Complete */ +#define GMAC_IMR_ROVR (0x1u << 10) /**< \brief (GMAC_IMR) Receive Overrun */ +#define GMAC_IMR_HRESP (0x1u << 11) /**< \brief (GMAC_IMR) HRESP Not OK */ +#define GMAC_IMR_PFNZ (0x1u << 12) /**< \brief (GMAC_IMR) Pause Frame with Non-zero Pause Quantum Received */ +#define GMAC_IMR_PTZ (0x1u << 13) /**< \brief (GMAC_IMR) Pause Time Zero */ +#define GMAC_IMR_PFTR (0x1u << 14) /**< \brief (GMAC_IMR) Pause Frame Transmitted */ +#define GMAC_IMR_EXINT (0x1u << 15) /**< \brief (GMAC_IMR) External Interrupt */ +#define GMAC_IMR_DRQFR (0x1u << 18) /**< \brief (GMAC_IMR) PTP Delay Request Frame Received */ +#define GMAC_IMR_SFR (0x1u << 19) /**< \brief (GMAC_IMR) PTP Sync Frame Received */ +#define GMAC_IMR_DRQFT (0x1u << 20) /**< \brief (GMAC_IMR) PTP Delay Request Frame Transmitted */ +#define GMAC_IMR_SFT (0x1u << 21) /**< \brief (GMAC_IMR) PTP Sync Frame Transmitted */ +#define GMAC_IMR_PDRQFR (0x1u << 22) /**< \brief (GMAC_IMR) PDelay Request Frame Received */ +#define GMAC_IMR_PDRSFR (0x1u << 23) /**< \brief (GMAC_IMR) PDelay Response Frame Received */ +#define GMAC_IMR_PDRQFT (0x1u << 24) /**< \brief (GMAC_IMR) PDelay Request Frame Transmitted */ +#define GMAC_IMR_PDRSFT (0x1u << 25) /**< \brief (GMAC_IMR) PDelay Response Frame Transmitted */ +/* -------- GMAC_MAN : (GMAC Offset: 0x034) PHY Maintenance Register -------- */ +#define GMAC_MAN_DATA_Pos 0 +#define GMAC_MAN_DATA_Msk (0xffffu << GMAC_MAN_DATA_Pos) /**< \brief (GMAC_MAN) PHY Data */ +#define GMAC_MAN_DATA(value) ((GMAC_MAN_DATA_Msk & ((value) << GMAC_MAN_DATA_Pos))) +#define GMAC_MAN_WTN_Pos 16 +#define GMAC_MAN_WTN_Msk (0x3u << GMAC_MAN_WTN_Pos) /**< \brief (GMAC_MAN) Write Ten */ +#define GMAC_MAN_WTN(value) ((GMAC_MAN_WTN_Msk & ((value) << GMAC_MAN_WTN_Pos))) +#define GMAC_MAN_REGA_Pos 18 +#define GMAC_MAN_REGA_Msk (0x1fu << GMAC_MAN_REGA_Pos) /**< \brief (GMAC_MAN) Register Address */ +#define GMAC_MAN_REGA(value) ((GMAC_MAN_REGA_Msk & ((value) << GMAC_MAN_REGA_Pos))) +#define GMAC_MAN_PHYA_Pos 23 +#define GMAC_MAN_PHYA_Msk (0x1fu << GMAC_MAN_PHYA_Pos) /**< \brief (GMAC_MAN) PHY Address */ +#define GMAC_MAN_PHYA(value) ((GMAC_MAN_PHYA_Msk & ((value) << GMAC_MAN_PHYA_Pos))) +#define GMAC_MAN_OP_Pos 28 +#define GMAC_MAN_OP_Msk (0x3u << GMAC_MAN_OP_Pos) /**< \brief (GMAC_MAN) Operation */ +#define GMAC_MAN_OP(value) ((GMAC_MAN_OP_Msk & ((value) << GMAC_MAN_OP_Pos))) +#define GMAC_MAN_CLTTO (0x1u << 30) /**< \brief (GMAC_MAN) Clause 22 Operation */ +#define GMAC_MAN_WZO (0x1u << 31) /**< \brief (GMAC_MAN) Write ZERO */ +/* -------- GMAC_RPQ : (GMAC Offset: 0x038) Received Pause Quantum Register -------- */ +#define GMAC_RPQ_RPQ_Pos 0 +#define GMAC_RPQ_RPQ_Msk (0xffffu << GMAC_RPQ_RPQ_Pos) /**< \brief (GMAC_RPQ) Received Pause Quantum */ +/* -------- GMAC_TPQ : (GMAC Offset: 0x03C) Transmit Pause Quantum Register -------- */ +#define GMAC_TPQ_TPQ_Pos 0 +#define GMAC_TPQ_TPQ_Msk (0xffffu << GMAC_TPQ_TPQ_Pos) /**< \brief (GMAC_TPQ) Transmit Pause Quantum */ +#define GMAC_TPQ_TPQ(value) ((GMAC_TPQ_TPQ_Msk & ((value) << GMAC_TPQ_TPQ_Pos))) +/* -------- GMAC_TPSF : (GMAC Offset: 0x040) TX Partial Store and Forward Register -------- */ +#define GMAC_TPSF_TPB1ADR_Pos 0 +#define GMAC_TPSF_TPB1ADR_Msk (0xfffu << GMAC_TPSF_TPB1ADR_Pos) /**< \brief (GMAC_TPSF) tx_pbuf_addr-1:0 */ +#define GMAC_TPSF_TPB1ADR(value) ((GMAC_TPSF_TPB1ADR_Msk & ((value) << GMAC_TPSF_TPB1ADR_Pos))) +#define GMAC_TPSF_ENTXP (0x1u << 31) /**< \brief (GMAC_TPSF) Enable TX Partial Store and Forward Operation */ +/* -------- GMAC_RPSF : (GMAC Offset: 0x044) RX Partial Store and Forward Register -------- */ +#define GMAC_RPSF_RPB1ADR_Pos 0 +#define GMAC_RPSF_RPB1ADR_Msk (0xfffu << GMAC_RPSF_RPB1ADR_Pos) /**< \brief (GMAC_RPSF) rx_pbuf_addr-1:0 */ +#define GMAC_RPSF_RPB1ADR(value) ((GMAC_RPSF_RPB1ADR_Msk & ((value) << GMAC_RPSF_RPB1ADR_Pos))) +#define GMAC_RPSF_ENRXP (0x1u << 31) /**< \brief (GMAC_RPSF) Enable RX Partial Store and Forward Operation */ +/* -------- GMAC_HRB : (GMAC Offset: 0x080) Hash Register Bottom [31:0] -------- */ +#define GMAC_HRB_ADDR_Pos 0 +#define GMAC_HRB_ADDR_Msk (0xffffffffu << GMAC_HRB_ADDR_Pos) /**< \brief (GMAC_HRB) Hash Address */ +#define GMAC_HRB_ADDR(value) ((GMAC_HRB_ADDR_Msk & ((value) << GMAC_HRB_ADDR_Pos))) +/* -------- GMAC_HRT : (GMAC Offset: 0x084) Hash Register Top [63:32] -------- */ +#define GMAC_HRT_ADDR_Pos 0 +#define GMAC_HRT_ADDR_Msk (0xffffffffu << GMAC_HRT_ADDR_Pos) /**< \brief (GMAC_HRT) Hash Address */ +#define GMAC_HRT_ADDR(value) ((GMAC_HRT_ADDR_Msk & ((value) << GMAC_HRT_ADDR_Pos))) +/* -------- GMAC_SAB1 : (GMAC Offset: 0x088) Specific Address 1 Bottom [31:0] Register -------- */ +#define GMAC_SAB1_ADDR_Pos 0 +#define GMAC_SAB1_ADDR_Msk (0xffffffffu << GMAC_SAB1_ADDR_Pos) /**< \brief (GMAC_SAB1) Specific Address 1 */ +#define GMAC_SAB1_ADDR(value) ((GMAC_SAB1_ADDR_Msk & ((value) << GMAC_SAB1_ADDR_Pos))) +/* -------- GMAC_SAT1 : (GMAC Offset: 0x08C) Specific Address 1 Top [47:32] Register -------- */ +#define GMAC_SAT1_ADDR_Pos 0 +#define GMAC_SAT1_ADDR_Msk (0xffffu << GMAC_SAT1_ADDR_Pos) /**< \brief (GMAC_SAT1) Specific Address 1 */ +#define GMAC_SAT1_ADDR(value) ((GMAC_SAT1_ADDR_Msk & ((value) << GMAC_SAT1_ADDR_Pos))) +/* -------- GMAC_SAB2 : (GMAC Offset: 0x090) Specific Address 2 Bottom [31:0] Register -------- */ +#define GMAC_SAB2_ADDR_Pos 0 +#define GMAC_SAB2_ADDR_Msk (0xffffffffu << GMAC_SAB2_ADDR_Pos) /**< \brief (GMAC_SAB2) Specific Address 2 */ +#define GMAC_SAB2_ADDR(value) ((GMAC_SAB2_ADDR_Msk & ((value) << GMAC_SAB2_ADDR_Pos))) +/* -------- GMAC_SAT2 : (GMAC Offset: 0x094) Specific Address 2 Top [47:32] Register -------- */ +#define GMAC_SAT2_ADDR_Pos 0 +#define GMAC_SAT2_ADDR_Msk (0xffffu << GMAC_SAT2_ADDR_Pos) /**< \brief (GMAC_SAT2) Specific Address 2 */ +#define GMAC_SAT2_ADDR(value) ((GMAC_SAT2_ADDR_Msk & ((value) << GMAC_SAT2_ADDR_Pos))) +/* -------- GMAC_SAB3 : (GMAC Offset: 0x098) Specific Address 3 Bottom [31:0] Register -------- */ +#define GMAC_SAB3_ADDR_Pos 0 +#define GMAC_SAB3_ADDR_Msk (0xffffffffu << GMAC_SAB3_ADDR_Pos) /**< \brief (GMAC_SAB3) Specific Address 3 */ +#define GMAC_SAB3_ADDR(value) ((GMAC_SAB3_ADDR_Msk & ((value) << GMAC_SAB3_ADDR_Pos))) +/* -------- GMAC_SAT3 : (GMAC Offset: 0x09C) Specific Address 3 Top [47:32] Register -------- */ +#define GMAC_SAT3_ADDR_Pos 0 +#define GMAC_SAT3_ADDR_Msk (0xffffu << GMAC_SAT3_ADDR_Pos) /**< \brief (GMAC_SAT3) Specific Address 3 */ +#define GMAC_SAT3_ADDR(value) ((GMAC_SAT3_ADDR_Msk & ((value) << GMAC_SAT3_ADDR_Pos))) +/* -------- GMAC_SAB4 : (GMAC Offset: 0x0A0) Specific Address 4 Bottom [31:0] Register -------- */ +#define GMAC_SAB4_ADDR_Pos 0 +#define GMAC_SAB4_ADDR_Msk (0xffffffffu << GMAC_SAB4_ADDR_Pos) /**< \brief (GMAC_SAB4) Specific Address 4 */ +#define GMAC_SAB4_ADDR(value) ((GMAC_SAB4_ADDR_Msk & ((value) << GMAC_SAB4_ADDR_Pos))) +/* -------- GMAC_SAT4 : (GMAC Offset: 0x0A4) Specific Address 4 Top [47:32] Register -------- */ +#define GMAC_SAT4_ADDR_Pos 0 +#define GMAC_SAT4_ADDR_Msk (0xffffu << GMAC_SAT4_ADDR_Pos) /**< \brief (GMAC_SAT4) Specific Address 4 */ +#define GMAC_SAT4_ADDR(value) ((GMAC_SAT4_ADDR_Msk & ((value) << GMAC_SAT4_ADDR_Pos))) +/* -------- GMAC_TIDM[4] : (GMAC Offset: 0x0A8) Type ID Match 1 Register -------- */ +#define GMAC_TIDM_TID_Pos 0 +#define GMAC_TIDM_TID_Msk (0xffffu << GMAC_TIDM_TID_Pos) /**< \brief (GMAC_TIDM[4]) Type ID Match 1 */ +#define GMAC_TIDM_TID(value) ((GMAC_TIDM_TID_Msk & ((value) << GMAC_TIDM_TID_Pos))) +/* -------- GMAC_WOL : (GMAC Offset: 0x0B8) Wake on LAN Register -------- */ +#define GMAC_WOL_IP_Pos 0 +#define GMAC_WOL_IP_Msk (0xffffu << GMAC_WOL_IP_Pos) /**< \brief (GMAC_WOL) ARP Request IP Address */ +#define GMAC_WOL_IP(value) ((GMAC_WOL_IP_Msk & ((value) << GMAC_WOL_IP_Pos))) +#define GMAC_WOL_MAG (0x1u << 16) /**< \brief (GMAC_WOL) Magic Packet Event Enable */ +#define GMAC_WOL_ARP (0x1u << 17) /**< \brief (GMAC_WOL) ARP Request IP Address */ +#define GMAC_WOL_SA1 (0x1u << 18) /**< \brief (GMAC_WOL) Specific Address Register 1 Event Enable */ +#define GMAC_WOL_MTI (0x1u << 19) /**< \brief (GMAC_WOL) Multicast Hash Event Enable */ +/* -------- GMAC_IPGS : (GMAC Offset: 0x0BC) IPG Stretch Register -------- */ +#define GMAC_IPGS_FL_Pos 0 +#define GMAC_IPGS_FL_Msk (0xffffu << GMAC_IPGS_FL_Pos) /**< \brief (GMAC_IPGS) Frame Length */ +#define GMAC_IPGS_FL(value) ((GMAC_IPGS_FL_Msk & ((value) << GMAC_IPGS_FL_Pos))) +/* -------- GMAC_SVLAN : (GMAC Offset: 0x0C0) Stacked VLAN Register -------- */ +#define GMAC_SVLAN_VLAN_TYPE_Pos 0 +#define GMAC_SVLAN_VLAN_TYPE_Msk (0xffffu << GMAC_SVLAN_VLAN_TYPE_Pos) /**< \brief (GMAC_SVLAN) User Defined VLAN_TYPE Field */ +#define GMAC_SVLAN_VLAN_TYPE(value) ((GMAC_SVLAN_VLAN_TYPE_Msk & ((value) << GMAC_SVLAN_VLAN_TYPE_Pos))) +#define GMAC_SVLAN_ESVLAN (0x1u << 31) /**< \brief (GMAC_SVLAN) Enable Stacked VLAN Processing Mode */ +/* -------- GMAC_TPFCP : (GMAC Offset: 0x0C4) Transmit PFC Pause Register -------- */ +#define GMAC_TPFCP_PEV_Pos 0 +#define GMAC_TPFCP_PEV_Msk (0xffu << GMAC_TPFCP_PEV_Pos) /**< \brief (GMAC_TPFCP) Priority Enable Vector */ +#define GMAC_TPFCP_PEV(value) ((GMAC_TPFCP_PEV_Msk & ((value) << GMAC_TPFCP_PEV_Pos))) +#define GMAC_TPFCP_PQ_Pos 8 +#define GMAC_TPFCP_PQ_Msk (0xffu << GMAC_TPFCP_PQ_Pos) /**< \brief (GMAC_TPFCP) Pause Quantum */ +#define GMAC_TPFCP_PQ(value) ((GMAC_TPFCP_PQ_Msk & ((value) << GMAC_TPFCP_PQ_Pos))) +/* -------- GMAC_SAMB1 : (GMAC Offset: 0x0C8) Specific Address 1 Mask Bottom [31:0] Register -------- */ +#define GMAC_SAMB1_ADDR_Pos 0 +#define GMAC_SAMB1_ADDR_Msk (0xffffffffu << GMAC_SAMB1_ADDR_Pos) /**< \brief (GMAC_SAMB1) Specific Address 1 Mask */ +#define GMAC_SAMB1_ADDR(value) ((GMAC_SAMB1_ADDR_Msk & ((value) << GMAC_SAMB1_ADDR_Pos))) +/* -------- GMAC_SAMT1 : (GMAC Offset: 0x0CC) Specific Address 1 Mask Top [47:32] Register -------- */ +#define GMAC_SAMT1_ADDR_Pos 0 +#define GMAC_SAMT1_ADDR_Msk (0xffffu << GMAC_SAMT1_ADDR_Pos) /**< \brief (GMAC_SAMT1) Specific Address 1 Mask */ +#define GMAC_SAMT1_ADDR(value) ((GMAC_SAMT1_ADDR_Msk & ((value) << GMAC_SAMT1_ADDR_Pos))) +/* -------- GMAC_OTLO : (GMAC Offset: 0x100) Octets Transmitted [31:0] Register -------- */ +#define GMAC_OTLO_TXO_Pos 0 +#define GMAC_OTLO_TXO_Msk (0xffffffffu << GMAC_OTLO_TXO_Pos) /**< \brief (GMAC_OTLO) Transmitted Octets */ +/* -------- GMAC_OTHI : (GMAC Offset: 0x104) Octets Transmitted [47:32] Register -------- */ +#define GMAC_OTHI_TXO_Pos 0 +#define GMAC_OTHI_TXO_Msk (0xffffu << GMAC_OTHI_TXO_Pos) /**< \brief (GMAC_OTHI) Transmitted Octets */ +/* -------- GMAC_FT : (GMAC Offset: 0x108) Frames Transmitted Register -------- */ +#define GMAC_FT_FTX_Pos 0 +#define GMAC_FT_FTX_Msk (0xffffffffu << GMAC_FT_FTX_Pos) /**< \brief (GMAC_FT) Frames Transmitted without Error */ +/* -------- GMAC_BCFT : (GMAC Offset: 0x10C) Broadcast Frames Transmitted Register -------- */ +#define GMAC_BCFT_BFTX_Pos 0 +#define GMAC_BCFT_BFTX_Msk (0xffffffffu << GMAC_BCFT_BFTX_Pos) /**< \brief (GMAC_BCFT) Broadcast Frames Transmitted without Error */ +/* -------- GMAC_MFT : (GMAC Offset: 0x110) Multicast Frames Transmitted Register -------- */ +#define GMAC_MFT_MFTX_Pos 0 +#define GMAC_MFT_MFTX_Msk (0xffffffffu << GMAC_MFT_MFTX_Pos) /**< \brief (GMAC_MFT) Multicast Frames Transmitted without Error */ +/* -------- GMAC_PFT : (GMAC Offset: 0x114) Pause Frames Transmitted Register -------- */ +#define GMAC_PFT_PFTX_Pos 0 +#define GMAC_PFT_PFTX_Msk (0xffffu << GMAC_PFT_PFTX_Pos) /**< \brief (GMAC_PFT) Pause Frames Transmitted Register */ +/* -------- GMAC_BFT64 : (GMAC Offset: 0x118) 64 Byte Frames Transmitted Register -------- */ +#define GMAC_BFT64_NFTX_Pos 0 +#define GMAC_BFT64_NFTX_Msk (0xffffffffu << GMAC_BFT64_NFTX_Pos) /**< \brief (GMAC_BFT64) 64 Byte Frames Transmitted without Error */ +/* -------- GMAC_TBFT127 : (GMAC Offset: 0x11C) 65 to 127 Byte Frames Transmitted Register -------- */ +#define GMAC_TBFT127_NFTX_Pos 0 +#define GMAC_TBFT127_NFTX_Msk (0xffffffffu << GMAC_TBFT127_NFTX_Pos) /**< \brief (GMAC_TBFT127) 65 to 127 Byte Frames Transmitted without Error */ +/* -------- GMAC_TBFT255 : (GMAC Offset: 0x120) 128 to 255 Byte Frames Transmitted Register -------- */ +#define GMAC_TBFT255_NFTX_Pos 0 +#define GMAC_TBFT255_NFTX_Msk (0xffffffffu << GMAC_TBFT255_NFTX_Pos) /**< \brief (GMAC_TBFT255) 128 to 255 Byte Frames Transmitted without Error */ +/* -------- GMAC_TBFT511 : (GMAC Offset: 0x124) 256 to 511 Byte Frames Transmitted Register -------- */ +#define GMAC_TBFT511_NFTX_Pos 0 +#define GMAC_TBFT511_NFTX_Msk (0xffffffffu << GMAC_TBFT511_NFTX_Pos) /**< \brief (GMAC_TBFT511) 256 to 511 Byte Frames Transmitted without Error */ +/* -------- GMAC_TBFT1023 : (GMAC Offset: 0x128) 512 to 1023 Byte Frames Transmitted Register -------- */ +#define GMAC_TBFT1023_NFTX_Pos 0 +#define GMAC_TBFT1023_NFTX_Msk (0xffffffffu << GMAC_TBFT1023_NFTX_Pos) /**< \brief (GMAC_TBFT1023) 512 to 1023 Byte Frames Transmitted without Error */ +/* -------- GMAC_TBFT1518 : (GMAC Offset: 0x12C) 1024 to 1518 Byte Frames Transmitted Register -------- */ +#define GMAC_TBFT1518_NFTX_Pos 0 +#define GMAC_TBFT1518_NFTX_Msk (0xffffffffu << GMAC_TBFT1518_NFTX_Pos) /**< \brief (GMAC_TBFT1518) 1024 to 1518 Byte Frames Transmitted without Error */ +/* -------- GMAC_GTBFT1518 : (GMAC Offset: 0x130) Greater Than 1518 Byte Frames Transmitted Register -------- */ +#define GMAC_GTBFT1518_NFTX_Pos 0 +#define GMAC_GTBFT1518_NFTX_Msk (0xffffffffu << GMAC_GTBFT1518_NFTX_Pos) /**< \brief (GMAC_GTBFT1518) Greater than 1518 Byte Frames Transmitted without Error */ +/* -------- GMAC_TUR : (GMAC Offset: 0x134) Transmit Under Runs Register -------- */ +#define GMAC_TUR_TXUNR_Pos 0 +#define GMAC_TUR_TXUNR_Msk (0x3ffu << GMAC_TUR_TXUNR_Pos) /**< \brief (GMAC_TUR) Transmit Under Runs */ +/* -------- GMAC_SCF : (GMAC Offset: 0x138) Single Collision Frames Register -------- */ +#define GMAC_SCF_SCOL_Pos 0 +#define GMAC_SCF_SCOL_Msk (0x3ffffu << GMAC_SCF_SCOL_Pos) /**< \brief (GMAC_SCF) Single Collision */ +/* -------- GMAC_MCF : (GMAC Offset: 0x13C) Multiple Collision Frames Register -------- */ +#define GMAC_MCF_MCOL_Pos 0 +#define GMAC_MCF_MCOL_Msk (0x3ffffu << GMAC_MCF_MCOL_Pos) /**< \brief (GMAC_MCF) Multiple Collision */ +/* -------- GMAC_EC : (GMAC Offset: 0x140) Excessive Collisions Register -------- */ +#define GMAC_EC_XCOL_Pos 0 +#define GMAC_EC_XCOL_Msk (0x3ffu << GMAC_EC_XCOL_Pos) /**< \brief (GMAC_EC) Excessive Collisions */ +/* -------- GMAC_LC : (GMAC Offset: 0x144) Late Collisions Register -------- */ +#define GMAC_LC_LCOL_Pos 0 +#define GMAC_LC_LCOL_Msk (0x3ffu << GMAC_LC_LCOL_Pos) /**< \brief (GMAC_LC) Late Collisions */ +/* -------- GMAC_DTF : (GMAC Offset: 0x148) Deferred Transmission Frames Register -------- */ +#define GMAC_DTF_DEFT_Pos 0 +#define GMAC_DTF_DEFT_Msk (0x3ffffu << GMAC_DTF_DEFT_Pos) /**< \brief (GMAC_DTF) Deferred Transmission */ +/* -------- GMAC_CSE : (GMAC Offset: 0x14C) Carrier Sense Errors Register -------- */ +#define GMAC_CSE_CSR_Pos 0 +#define GMAC_CSE_CSR_Msk (0x3ffu << GMAC_CSE_CSR_Pos) /**< \brief (GMAC_CSE) Carrier Sense Error */ +/* -------- GMAC_ORLO : (GMAC Offset: 0x150) Octets Received [31:0] Received -------- */ +#define GMAC_ORLO_RXO_Pos 0 +#define GMAC_ORLO_RXO_Msk (0xffffffffu << GMAC_ORLO_RXO_Pos) /**< \brief (GMAC_ORLO) Received Octets */ +/* -------- GMAC_ORHI : (GMAC Offset: 0x154) Octets Received [47:32] Received -------- */ +#define GMAC_ORHI_RXO_Pos 0 +#define GMAC_ORHI_RXO_Msk (0xffffu << GMAC_ORHI_RXO_Pos) /**< \brief (GMAC_ORHI) Received Octets */ +/* -------- GMAC_FR : (GMAC Offset: 0x158) Frames Received Register -------- */ +#define GMAC_FR_FRX_Pos 0 +#define GMAC_FR_FRX_Msk (0xffffffffu << GMAC_FR_FRX_Pos) /**< \brief (GMAC_FR) Frames Received without Error */ +/* -------- GMAC_BCFR : (GMAC Offset: 0x15C) Broadcast Frames Received Register -------- */ +#define GMAC_BCFR_BFRX_Pos 0 +#define GMAC_BCFR_BFRX_Msk (0xffffffffu << GMAC_BCFR_BFRX_Pos) /**< \brief (GMAC_BCFR) Broadcast Frames Received without Error */ +/* -------- GMAC_MFR : (GMAC Offset: 0x160) Multicast Frames Received Register -------- */ +#define GMAC_MFR_MFRX_Pos 0 +#define GMAC_MFR_MFRX_Msk (0xffffffffu << GMAC_MFR_MFRX_Pos) /**< \brief (GMAC_MFR) Multicast Frames Received without Error */ +/* -------- GMAC_PFR : (GMAC Offset: 0x164) Pause Frames Received Register -------- */ +#define GMAC_PFR_PFRX_Pos 0 +#define GMAC_PFR_PFRX_Msk (0xffffu << GMAC_PFR_PFRX_Pos) /**< \brief (GMAC_PFR) Pause Frames Received Register */ +/* -------- GMAC_BFR64 : (GMAC Offset: 0x168) 64 Byte Frames Received Register -------- */ +#define GMAC_BFR64_NFRX_Pos 0 +#define GMAC_BFR64_NFRX_Msk (0xffffffffu << GMAC_BFR64_NFRX_Pos) /**< \brief (GMAC_BFR64) 64 Byte Frames Received without Error */ +/* -------- GMAC_TBFR127 : (GMAC Offset: 0x16C) 65 to 127 Byte Frames Received Register -------- */ +#define GMAC_TBFR127_NFRX_Pos 0 +#define GMAC_TBFR127_NFRX_Msk (0xffffffffu << GMAC_TBFR127_NFRX_Pos) /**< \brief (GMAC_TBFR127) 65 to 127 Byte Frames Received without Error */ +/* -------- GMAC_TBFR255 : (GMAC Offset: 0x170) 128 to 255 Byte Frames Received Register -------- */ +#define GMAC_TBFR255_NFRX_Pos 0 +#define GMAC_TBFR255_NFRX_Msk (0xffffffffu << GMAC_TBFR255_NFRX_Pos) /**< \brief (GMAC_TBFR255) 128 to 255 Byte Frames Received without Error */ +/* -------- GMAC_TBFR511 : (GMAC Offset: 0x174) 256 to 511Byte Frames Received Register -------- */ +#define GMAC_TBFR511_NFRX_Pos 0 +#define GMAC_TBFR511_NFRX_Msk (0xffffffffu << GMAC_TBFR511_NFRX_Pos) /**< \brief (GMAC_TBFR511) 256 to 511 Byte Frames Received without Error */ +/* -------- GMAC_TBFR1023 : (GMAC Offset: 0x178) 512 to 1023 Byte Frames Received Register -------- */ +#define GMAC_TBFR1023_NFRX_Pos 0 +#define GMAC_TBFR1023_NFRX_Msk (0xffffffffu << GMAC_TBFR1023_NFRX_Pos) /**< \brief (GMAC_TBFR1023) 512 to 1023 Byte Frames Received without Error */ +/* -------- GMAC_TBFR1518 : (GMAC Offset: 0x17C) 1024 to 1518 Byte Frames Received Register -------- */ +#define GMAC_TBFR1518_NFRX_Pos 0 +#define GMAC_TBFR1518_NFRX_Msk (0xffffffffu << GMAC_TBFR1518_NFRX_Pos) /**< \brief (GMAC_TBFR1518) 1024 to 1518 Byte Frames Received without Error */ +/* -------- GMAC_TMXBFR : (GMAC Offset: 0x180) 1519 to Maximum Byte Frames Received Register -------- */ +#define GMAC_TMXBFR_NFRX_Pos 0 +#define GMAC_TMXBFR_NFRX_Msk (0xffffffffu << GMAC_TMXBFR_NFRX_Pos) /**< \brief (GMAC_TMXBFR) 1519 to Maximum Byte Frames Received without Error */ +/* -------- GMAC_UFR : (GMAC Offset: 0x184) Undersize Frames Received Register -------- */ +#define GMAC_UFR_UFRX_Pos 0 +#define GMAC_UFR_UFRX_Msk (0x3ffu << GMAC_UFR_UFRX_Pos) /**< \brief (GMAC_UFR) Undersize Frames Received */ +/* -------- GMAC_OFR : (GMAC Offset: 0x188) Oversize Frames Received Register -------- */ +#define GMAC_OFR_OFRX_Pos 0 +#define GMAC_OFR_OFRX_Msk (0x3ffu << GMAC_OFR_OFRX_Pos) /**< \brief (GMAC_OFR) Oversized Frames Received */ +/* -------- GMAC_JR : (GMAC Offset: 0x18C) Jabbers Received Register -------- */ +#define GMAC_JR_JRX_Pos 0 +#define GMAC_JR_JRX_Msk (0x3ffu << GMAC_JR_JRX_Pos) /**< \brief (GMAC_JR) Jabbers Received */ +/* -------- GMAC_FCSE : (GMAC Offset: 0x190) Frame Check Sequence Errors Register -------- */ +#define GMAC_FCSE_FCKR_Pos 0 +#define GMAC_FCSE_FCKR_Msk (0x3ffu << GMAC_FCSE_FCKR_Pos) /**< \brief (GMAC_FCSE) Frame Check Sequence Errors */ +/* -------- GMAC_LFFE : (GMAC Offset: 0x194) Length Field Frame Errors Register -------- */ +#define GMAC_LFFE_LFER_Pos 0 +#define GMAC_LFFE_LFER_Msk (0x3ffu << GMAC_LFFE_LFER_Pos) /**< \brief (GMAC_LFFE) Length Field Frame Errors */ +/* -------- GMAC_RSE : (GMAC Offset: 0x198) Receive Symbol Errors Register -------- */ +#define GMAC_RSE_RXSE_Pos 0 +#define GMAC_RSE_RXSE_Msk (0x3ffu << GMAC_RSE_RXSE_Pos) /**< \brief (GMAC_RSE) Receive Symbol Errors */ +/* -------- GMAC_AE : (GMAC Offset: 0x19C) Alignment Errors Register -------- */ +#define GMAC_AE_AER_Pos 0 +#define GMAC_AE_AER_Msk (0x3ffu << GMAC_AE_AER_Pos) /**< \brief (GMAC_AE) Alignment Errors */ +/* -------- GMAC_RRE : (GMAC Offset: 0x1A0) Receive Resource Errors Register -------- */ +#define GMAC_RRE_RXRER_Pos 0 +#define GMAC_RRE_RXRER_Msk (0x3ffffu << GMAC_RRE_RXRER_Pos) /**< \brief (GMAC_RRE) Receive Resource Errors */ +/* -------- GMAC_ROE : (GMAC Offset: 0x1A4) Receive Overrun Register -------- */ +#define GMAC_ROE_RXOVR_Pos 0 +#define GMAC_ROE_RXOVR_Msk (0x3ffu << GMAC_ROE_RXOVR_Pos) /**< \brief (GMAC_ROE) Receive Overruns */ +/* -------- GMAC_IHCE : (GMAC Offset: 0x1A8) IP Header Checksum Errors Register -------- */ +#define GMAC_IHCE_HCKER_Pos 0 +#define GMAC_IHCE_HCKER_Msk (0xffu << GMAC_IHCE_HCKER_Pos) /**< \brief (GMAC_IHCE) IP Header Checksum Errors */ +/* -------- GMAC_TCE : (GMAC Offset: 0x1AC) TCP Checksum Errors Register -------- */ +#define GMAC_TCE_TCKER_Pos 0 +#define GMAC_TCE_TCKER_Msk (0xffu << GMAC_TCE_TCKER_Pos) /**< \brief (GMAC_TCE) TCP Checksum Errors */ +/* -------- GMAC_UCE : (GMAC Offset: 0x1B0) UDP Checksum Errors Register -------- */ +#define GMAC_UCE_UCKER_Pos 0 +#define GMAC_UCE_UCKER_Msk (0xffu << GMAC_UCE_UCKER_Pos) /**< \brief (GMAC_UCE) UDP Checksum Errors */ +/* -------- GMAC_TSSS : (GMAC Offset: 0x1C8) 1588 Timer Sync Strobe Seconds Register -------- */ +#define GMAC_TSSS_VTS_Pos 0 +#define GMAC_TSSS_VTS_Msk (0xffffffffu << GMAC_TSSS_VTS_Pos) /**< \brief (GMAC_TSSS) Value of Timer Seconds Register Capture */ +#define GMAC_TSSS_VTS(value) ((GMAC_TSSS_VTS_Msk & ((value) << GMAC_TSSS_VTS_Pos))) +/* -------- GMAC_TSSN : (GMAC Offset: 0x1CC) 1588 Timer Sync Strobe Nanoseconds Register -------- */ +#define GMAC_TSSN_VTN_Pos 0 +#define GMAC_TSSN_VTN_Msk (0x3fffffffu << GMAC_TSSN_VTN_Pos) /**< \brief (GMAC_TSSN) Value Timer Nanoseconds Register Capture */ +#define GMAC_TSSN_VTN(value) ((GMAC_TSSN_VTN_Msk & ((value) << GMAC_TSSN_VTN_Pos))) +/* -------- GMAC_TS : (GMAC Offset: 0x1D0) 1588 Timer Seconds Register -------- */ +#define GMAC_TS_TCS_Pos 0 +#define GMAC_TS_TCS_Msk (0xffffffffu << GMAC_TS_TCS_Pos) /**< \brief (GMAC_TS) Timer Count in Seconds */ +#define GMAC_TS_TCS(value) ((GMAC_TS_TCS_Msk & ((value) << GMAC_TS_TCS_Pos))) +/* -------- GMAC_TN : (GMAC Offset: 0x1D4) 1588 Timer Nanoseconds Register -------- */ +#define GMAC_TN_TNS_Pos 0 +#define GMAC_TN_TNS_Msk (0x3fffffffu << GMAC_TN_TNS_Pos) /**< \brief (GMAC_TN) Timer Count in Nanoseconds */ +#define GMAC_TN_TNS(value) ((GMAC_TN_TNS_Msk & ((value) << GMAC_TN_TNS_Pos))) +/* -------- GMAC_TA : (GMAC Offset: 0x1D8) 1588 Timer Adjust Register -------- */ +#define GMAC_TA_ITDT_Pos 0 +#define GMAC_TA_ITDT_Msk (0x3fffffffu << GMAC_TA_ITDT_Pos) /**< \brief (GMAC_TA) Increment/Decrement */ +#define GMAC_TA_ITDT(value) ((GMAC_TA_ITDT_Msk & ((value) << GMAC_TA_ITDT_Pos))) +#define GMAC_TA_ADJ (0x1u << 31) /**< \brief (GMAC_TA) Adjust 1588 Timer */ +/* -------- GMAC_TI : (GMAC Offset: 0x1DC) 1588 Timer Increment Register -------- */ +#define GMAC_TI_CNS_Pos 0 +#define GMAC_TI_CNS_Msk (0xffu << GMAC_TI_CNS_Pos) /**< \brief (GMAC_TI) Count Nanoseconds */ +#define GMAC_TI_CNS(value) ((GMAC_TI_CNS_Msk & ((value) << GMAC_TI_CNS_Pos))) +#define GMAC_TI_ACNS_Pos 8 +#define GMAC_TI_ACNS_Msk (0xffu << GMAC_TI_ACNS_Pos) /**< \brief (GMAC_TI) Alternative Count Nanoseconds */ +#define GMAC_TI_ACNS(value) ((GMAC_TI_ACNS_Msk & ((value) << GMAC_TI_ACNS_Pos))) +#define GMAC_TI_NIT_Pos 16 +#define GMAC_TI_NIT_Msk (0xffu << GMAC_TI_NIT_Pos) /**< \brief (GMAC_TI) Number of Increments */ +#define GMAC_TI_NIT(value) ((GMAC_TI_NIT_Msk & ((value) << GMAC_TI_NIT_Pos))) +/* -------- GMAC_EFTS : (GMAC Offset: 0x1E0) PTP Event Frame Transmitted Seconds -------- */ +#define GMAC_EFTS_RUD_Pos 0 +#define GMAC_EFTS_RUD_Msk (0xffffffffu << GMAC_EFTS_RUD_Pos) /**< \brief (GMAC_EFTS) Register Update */ +/* -------- GMAC_EFTN : (GMAC Offset: 0x1E4) PTP Event Frame Transmitted Nanoseconds -------- */ +#define GMAC_EFTN_RUD_Pos 0 +#define GMAC_EFTN_RUD_Msk (0x3fffffffu << GMAC_EFTN_RUD_Pos) /**< \brief (GMAC_EFTN) Register Update */ +/* -------- GMAC_EFRS : (GMAC Offset: 0x1E8) PTP Event Frame Received Seconds -------- */ +#define GMAC_EFRS_RUD_Pos 0 +#define GMAC_EFRS_RUD_Msk (0xffffffffu << GMAC_EFRS_RUD_Pos) /**< \brief (GMAC_EFRS) Register Update */ +/* -------- GMAC_EFRN : (GMAC Offset: 0x1EC) PTP Event Frame Received Nanoseconds -------- */ +#define GMAC_EFRN_RUD_Pos 0 +#define GMAC_EFRN_RUD_Msk (0x3fffffffu << GMAC_EFRN_RUD_Pos) /**< \brief (GMAC_EFRN) Register Update */ +/* -------- GMAC_PEFTS : (GMAC Offset: 0x1F0) PTP Peer Event Frame Transmitted Seconds -------- */ +#define GMAC_PEFTS_RUD_Pos 0 +#define GMAC_PEFTS_RUD_Msk (0xffffffffu << GMAC_PEFTS_RUD_Pos) /**< \brief (GMAC_PEFTS) Register Update */ +/* -------- GMAC_PEFTN : (GMAC Offset: 0x1F4) PTP Peer Event Frame Transmitted Nanoseconds -------- */ +#define GMAC_PEFTN_RUD_Pos 0 +#define GMAC_PEFTN_RUD_Msk (0x3fffffffu << GMAC_PEFTN_RUD_Pos) /**< \brief (GMAC_PEFTN) Register Update */ +/* -------- GMAC_PEFRS : (GMAC Offset: 0x1F8) PTP Peer Event Frame Received Seconds -------- */ +#define GMAC_PEFRS_RUD_Pos 0 +#define GMAC_PEFRS_RUD_Msk (0xffffffffu << GMAC_PEFRS_RUD_Pos) /**< \brief (GMAC_PEFRS) Register Update */ +/* -------- GMAC_PEFRN : (GMAC Offset: 0x1FC) PTP Peer Event Frame Received Nanoseconds -------- */ +#define GMAC_PEFRN_RUD_Pos 0 +#define GMAC_PEFRN_RUD_Msk (0x3fffffffu << GMAC_PEFRN_RUD_Pos) /**< \brief (GMAC_PEFRN) Register Update */ +/* -------- GMAC_ISRPQ[7] : (GMAC Offset: 0x400) Interrupt Status Register Priority Queue -------- */ +#define GMAC_ISRPQ_RCOMP (0x1u << 1) /**< \brief (GMAC_ISRPQ[7]) Receive Complete */ +#define GMAC_ISRPQ_RXUBR (0x1u << 2) /**< \brief (GMAC_ISRPQ[7]) RX Used Bit Read */ +#define GMAC_ISRPQ_RLEX (0x1u << 5) /**< \brief (GMAC_ISRPQ[7]) Retry Limit Exceeded or Late Collision */ +#define GMAC_ISRPQ_TFC (0x1u << 6) /**< \brief (GMAC_ISRPQ[7]) Transmit Frame Corruption due to AHB error */ +#define GMAC_ISRPQ_TCOMP (0x1u << 7) /**< \brief (GMAC_ISRPQ[7]) Transmit Complete */ +#define GMAC_ISRPQ_ROVR (0x1u << 10) /**< \brief (GMAC_ISRPQ[7]) Receive Overrun */ +#define GMAC_ISRPQ_HRESP (0x1u << 11) /**< \brief (GMAC_ISRPQ[7]) HRESP Not OK */ +/* -------- GMAC_TBQBAPQ[7] : (GMAC Offset: 0x440) Transmit Buffer Queue Base Address Priority Queue -------- */ +#define GMAC_TBQBAPQ_TXBQBA_Pos 2 +#define GMAC_TBQBAPQ_TXBQBA_Msk (0x3fu << GMAC_TBQBAPQ_TXBQBA_Pos) /**< \brief (GMAC_TBQBAPQ[7]) Transmit Buffer Queue Base Address */ +#define GMAC_TBQBAPQ_TXBQBA(value) ((GMAC_TBQBAPQ_TXBQBA_Msk & ((value) << GMAC_TBQBAPQ_TXBQBA_Pos))) +/* -------- GMAC_RBQBAPQ[7] : (GMAC Offset: 0x480) Receive Buffer Queue Base Address Priority Queue -------- */ +#define GMAC_RBQBAPQ_RXBQBA_Pos 2 +#define GMAC_RBQBAPQ_RXBQBA_Msk (0x3fu << GMAC_RBQBAPQ_RXBQBA_Pos) /**< \brief (GMAC_RBQBAPQ[7]) Receive Buffer Queue Base Address */ +#define GMAC_RBQBAPQ_RXBQBA(value) ((GMAC_RBQBAPQ_RXBQBA_Msk & ((value) << GMAC_RBQBAPQ_RXBQBA_Pos))) +/* -------- GMAC_RBSRPQ[7] : (GMAC Offset: 0x4A0) Receive Buffer Size Register Priority Queue -------- */ +#define GMAC_RBSRPQ_RBS_Pos 0 +#define GMAC_RBSRPQ_RBS_Msk (0xffffu << GMAC_RBSRPQ_RBS_Pos) /**< \brief (GMAC_RBSRPQ[7]) Receive Buffer Size */ +#define GMAC_RBSRPQ_RBS(value) ((GMAC_RBSRPQ_RBS_Msk & ((value) << GMAC_RBSRPQ_RBS_Pos))) +/* -------- GMAC_ST1RPQ[16] : (GMAC Offset: 0x500) Screening Type1 Register Priority Queue -------- */ +#define GMAC_ST1RPQ_QNB_Pos 0 +#define GMAC_ST1RPQ_QNB_Msk (0xfu << GMAC_ST1RPQ_QNB_Pos) /**< \brief (GMAC_ST1RPQ[16]) Que Number (0->7) */ +#define GMAC_ST1RPQ_QNB(value) ((GMAC_ST1RPQ_QNB_Msk & ((value) << GMAC_ST1RPQ_QNB_Pos))) +#define GMAC_ST1RPQ_DSTCM_Pos 4 +#define GMAC_ST1RPQ_DSTCM_Msk (0xffu << GMAC_ST1RPQ_DSTCM_Pos) /**< \brief (GMAC_ST1RPQ[16]) Differentiated Services or Traffic Class Match */ +#define GMAC_ST1RPQ_DSTCM(value) ((GMAC_ST1RPQ_DSTCM_Msk & ((value) << GMAC_ST1RPQ_DSTCM_Pos))) +#define GMAC_ST1RPQ_UDPM_Pos 12 +#define GMAC_ST1RPQ_UDPM_Msk (0xffffu << GMAC_ST1RPQ_UDPM_Pos) /**< \brief (GMAC_ST1RPQ[16]) UDP Port Match */ +#define GMAC_ST1RPQ_UDPM(value) ((GMAC_ST1RPQ_UDPM_Msk & ((value) << GMAC_ST1RPQ_UDPM_Pos))) +#define GMAC_ST1RPQ_DSTCE (0x1u << 28) /**< \brief (GMAC_ST1RPQ[16]) Differentiated Services or Traffic Class Match Enable */ +#define GMAC_ST1RPQ_UDPE (0x1u << 29) /**< \brief (GMAC_ST1RPQ[16]) UDP Port Match Enable */ +/* -------- GMAC_ST2RPQ[16] : (GMAC Offset: 0x540) Screening Type2 Register Priority Queue -------- */ +#define GMAC_ST2RPQ_QNB_Pos 0 +#define GMAC_ST2RPQ_QNB_Msk (0xfu << GMAC_ST2RPQ_QNB_Pos) /**< \brief (GMAC_ST2RPQ[16]) Que Number (0->7) */ +#define GMAC_ST2RPQ_QNB(value) ((GMAC_ST2RPQ_QNB_Msk & ((value) << GMAC_ST2RPQ_QNB_Pos))) +#define GMAC_ST2RPQ_VLANP_Pos 4 +#define GMAC_ST2RPQ_VLANP_Msk (0xfu << GMAC_ST2RPQ_VLANP_Pos) /**< \brief (GMAC_ST2RPQ[16]) VLAN Priority */ +#define GMAC_ST2RPQ_VLANP(value) ((GMAC_ST2RPQ_VLANP_Msk & ((value) << GMAC_ST2RPQ_VLANP_Pos))) +#define GMAC_ST2RPQ_VLANE (0x1u << 8) /**< \brief (GMAC_ST2RPQ[16]) VLAN Enable */ +/* -------- GMAC_IERPQ[7] : (GMAC Offset: 0x600) Interrupt Enable Register Priority Queue -------- */ +#define GMAC_IERPQ_RCOMP (0x1u << 1) /**< \brief (GMAC_IERPQ[7]) Receive Complete */ +#define GMAC_IERPQ_RXUBR (0x1u << 2) /**< \brief (GMAC_IERPQ[7]) RX Used Bit Read */ +#define GMAC_IERPQ_RLEX (0x1u << 5) /**< \brief (GMAC_IERPQ[7]) Retry Limit Exceeded or Late Collision */ +#define GMAC_IERPQ_TFC (0x1u << 6) /**< \brief (GMAC_IERPQ[7]) Transmit Frame Corruption due to AHB error */ +#define GMAC_IERPQ_TCOMP (0x1u << 7) /**< \brief (GMAC_IERPQ[7]) Transmit Complete */ +#define GMAC_IERPQ_ROVR (0x1u << 10) /**< \brief (GMAC_IERPQ[7]) Receive Overrun */ +#define GMAC_IERPQ_HRESP (0x1u << 11) /**< \brief (GMAC_IERPQ[7]) HRESP Not OK */ +/* -------- GMAC_IDRPQ[7] : (GMAC Offset: 0x620) Interrupt Disable Register Priority Queue -------- */ +#define GMAC_IDRPQ_RCOMP (0x1u << 1) /**< \brief (GMAC_IDRPQ[7]) Receive Complete */ +#define GMAC_IDRPQ_RXUBR (0x1u << 2) /**< \brief (GMAC_IDRPQ[7]) RX Used Bit Read */ +#define GMAC_IDRPQ_RLEX (0x1u << 5) /**< \brief (GMAC_IDRPQ[7]) Retry Limit Exceeded or Late Collision */ +#define GMAC_IDRPQ_TFC (0x1u << 6) /**< \brief (GMAC_IDRPQ[7]) Transmit Frame Corruption due to AHB error */ +#define GMAC_IDRPQ_TCOMP (0x1u << 7) /**< \brief (GMAC_IDRPQ[7]) Transmit Complete */ +#define GMAC_IDRPQ_ROVR (0x1u << 10) /**< \brief (GMAC_IDRPQ[7]) Receive Overrun */ +#define GMAC_IDRPQ_HRESP (0x1u << 11) /**< \brief (GMAC_IDRPQ[7]) HRESP Not OK */ +/* -------- GMAC_IMRPQ[7] : (GMAC Offset: 0x640) Interrupt Mask Register Priority Queue -------- */ +#define GMAC_IMRPQ_RCOMP (0x1u << 1) /**< \brief (GMAC_IMRPQ[7]) Receive Complete */ +#define GMAC_IMRPQ_RXUBR (0x1u << 2) /**< \brief (GMAC_IMRPQ[7]) RX Used Bit Read */ +#define GMAC_IMRPQ_RLEX (0x1u << 5) /**< \brief (GMAC_IMRPQ[7]) Retry Limit Exceeded or Late Collision */ +#define GMAC_IMRPQ_AHB (0x1u << 6) /**< \brief (GMAC_IMRPQ[7]) AHB Error */ +#define GMAC_IMRPQ_TCOMP (0x1u << 7) /**< \brief (GMAC_IMRPQ[7]) Transmit Complete */ +#define GMAC_IMRPQ_ROVR (0x1u << 10) /**< \brief (GMAC_IMRPQ[7]) Receive Overrun */ +#define GMAC_IMRPQ_HRESP (0x1u << 11) /**< \brief (GMAC_IMRPQ[7]) HRESP Not OK */ + +/*@}*/ + + +#endif /* _SAM4E_GMAC_COMPONENT_ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.c new file mode 100644 index 000000000..fe9e2960f --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.c @@ -0,0 +1,454 @@ + /** + * \file + * + * \brief API driver for KSZ8051MNL PHY component. + * + * Copyright (c) 2013 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "FreeRTOSIPConfig.h" + +#include "ethernet_phy.h" +#include "instance/gmac.h" + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +extern "C" { +#endif +/**INDENT-ON**/ +/// @endcond + +/** + * \defgroup ksz8051mnl_ethernet_phy_group PHY component (KSZ8051MNL) + * + * Driver for the ksz8051mnl component. This driver provides access to the main + * features of the PHY. + * + * \section dependencies Dependencies + * This driver depends on the following modules: + * - \ref gmac_group Ethernet Media Access Controller (GMAC) module. + * + * @{ + */ + +SPhyProps phyProps; + +/* Max PHY number */ +#define ETH_PHY_MAX_ADDR 31 + +/* Ethernet PHY operation max retry count */ +#define ETH_PHY_RETRY_MAX 1000000 + +/* Ethernet PHY operation timeout */ +#define ETH_PHY_TIMEOUT 10 + +/** + * \brief Find a valid PHY Address ( from addrStart to 31 ). + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_phy_addr PHY address. + * \param uc_start_addr Start address of the PHY to be searched. + * + * \return 0xFF when no valid PHY address is found. + */ +int ethernet_phy_addr = 0; +static uint8_t ethernet_phy_find_valid(Gmac *p_gmac, uint8_t uc_phy_addr, + uint8_t uc_start_addr) +{ + uint32_t ul_value = 0; + uint8_t uc_cnt; + uint8_t uc_phy_address = uc_phy_addr; + + gmac_enable_management(p_gmac, true); +/* +#define GMII_OUI_MSB 0x0022 +#define GMII_OUI_LSB 0x05 + +PHYID1 = 0x0022 +PHYID2 = 0x1550 +0001_0101_0101_0000 = 0x1550 <= mask should be 0xFFF0 +*/ + /* Check the current PHY address */ + gmac_phy_read(p_gmac, uc_phy_addr, GMII_PHYID1, &ul_value); + + /* Find another one */ + if (ul_value != GMII_OUI_MSB) { + ethernet_phy_addr = 0xFF; + for (uc_cnt = uc_start_addr; uc_cnt <= ETH_PHY_MAX_ADDR; uc_cnt++) { + uc_phy_address = (uc_phy_address + 1) & 0x1F; + ul_value = 0; + gmac_phy_read(p_gmac, uc_phy_address, GMII_PHYID1, &ul_value); + if (ul_value == GMII_OUI_MSB) { + ethernet_phy_addr = uc_phy_address; + break; + } + } + } + + gmac_enable_management(p_gmac, false); + + if (ethernet_phy_addr != 0xFF) { + gmac_phy_read(p_gmac, uc_phy_address, GMII_BMSR, &ul_value); + } + return ethernet_phy_addr; +} + + +/** + * \brief Perform a HW initialization to the PHY and set up clocks. + * + * This should be called only once to initialize the PHY pre-settings. + * The PHY address is the reset status of CRS, RXD[3:0] (the emacPins' pullups). + * The COL pin is used to select MII mode on reset (pulled up for Reduced MII). + * The RXDV pin is used to select test mode on reset (pulled up for test mode). + * The above pins should be predefined for corresponding settings in resetPins. + * The GMAC peripheral pins are configured after the reset is done. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_phy_addr PHY address. + * \param ul_mck GMAC MCK. + * + * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout. + */ +uint8_t ethernet_phy_init(Gmac *p_gmac, uint8_t uc_phy_addr, uint32_t mck) +{ + uint8_t uc_rc = GMAC_TIMEOUT; + uint8_t uc_phy; + + ethernet_phy_reset(GMAC,uc_phy_addr); + + /* Configure GMAC runtime clock */ + uc_rc = gmac_set_mdc_clock(p_gmac, mck); + if (uc_rc != GMAC_OK) { + return 0; + } + + /* Check PHY Address */ + uc_phy = ethernet_phy_find_valid(p_gmac, uc_phy_addr, 0); + if (uc_phy == 0xFF) { + return 0; + } + if (uc_phy != uc_phy_addr) { + ethernet_phy_reset(p_gmac, uc_phy_addr); + } + phy_props.phy_chn = uc_phy; + return uc_phy; +} + + +/** + * \brief Get the Link & speed settings, and automatically set up the GMAC with the + * settings. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_phy_addr PHY address. + * \param uc_apply_setting_flag Set to 0 to not apply the PHY configurations, else to apply. + * + * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout. + */ +uint8_t ethernet_phy_set_link(Gmac *p_gmac, uint8_t uc_phy_addr, + uint8_t uc_apply_setting_flag) +{ + uint32_t ul_stat1; + uint32_t ul_stat2; + uint8_t uc_phy_address, uc_speed = true, uc_fd = true; + uint8_t uc_rc = GMAC_TIMEOUT; + + gmac_enable_management(p_gmac, true); + + uc_phy_address = uc_phy_addr; + + uc_rc = gmac_phy_read(p_gmac, uc_phy_address, GMII_BMSR, &ul_stat1); + if (uc_rc != GMAC_OK) { + /* Disable PHY management and start the GMAC transfer */ + gmac_enable_management(p_gmac, false); + + return uc_rc; + } + if ((ul_stat1 & GMII_LINK_STATUS) == 0) { + /* Disable PHY management and start the GMAC transfer */ + gmac_enable_management(p_gmac, false); + + return GMAC_INVALID; + } + + if (uc_apply_setting_flag == 0) { + /* Disable PHY management and start the GMAC transfer */ + gmac_enable_management(p_gmac, false); + + return uc_rc; + } + + /* Read advertisement */ + uc_rc = gmac_phy_read(p_gmac, uc_phy_address, GMII_ANAR, &ul_stat2); +phy_props.phy_stat1 = ul_stat1; +phy_props.phy_stat2 = ul_stat2; + if (uc_rc != GMAC_OK) { + /* Disable PHY management and start the GMAC transfer */ + gmac_enable_management(p_gmac, false); + + return uc_rc; + } + + if ((ul_stat1 & GMII_100BASE_TX_FD) && (ul_stat2 & GMII_100TX_FDX)) { + /* Set GMAC for 100BaseTX and Full Duplex */ + uc_speed = true; + uc_fd = true; + } else + if ((ul_stat1 & GMII_100BASE_T4_HD) && (ul_stat2 & GMII_100TX_HDX)) { + /* Set MII for 100BaseTX and Half Duplex */ + uc_speed = true; + uc_fd = false; + } else + if ((ul_stat1 & GMII_10BASE_T_FD) && (ul_stat2 & GMII_10_FDX)) { + /* Set MII for 10BaseT and Full Duplex */ + uc_speed = false; + uc_fd = true; + } else + if ((ul_stat1 & GMII_10BASE_T_HD) && (ul_stat2 & GMII_10_HDX)) { + /* Set MII for 10BaseT and Half Duplex */ + uc_speed = false; + uc_fd = false; + } + + gmac_set_speed(p_gmac, uc_speed); + gmac_enable_full_duplex(p_gmac, uc_fd); + + /* Start the GMAC transfers */ + gmac_enable_management(p_gmac, false); + return uc_rc; +} + +PhyProps_t phy_props; + +/** + * \brief Issue an auto negotiation of the PHY. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_phy_addr PHY address. + * + * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout. + */ +uint8_t ethernet_phy_auto_negotiate(Gmac *p_gmac, uint8_t uc_phy_addr) +{ + uint32_t ul_retry_max = ETH_PHY_RETRY_MAX; + uint32_t ul_value; + uint32_t ul_phy_anar; + uint32_t ul_retry_count = 0; + uint8_t uc_speed = 0; + uint8_t uc_fd=0; + uint8_t uc_rc = GMAC_TIMEOUT; + + gmac_enable_management(p_gmac, true); + + /* Set up control register */ + uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMCR, &ul_value); + if (uc_rc != GMAC_OK) { + gmac_enable_management(p_gmac, false); +phy_props.phy_result = -1; + return uc_rc; + } + + ul_value &= ~(uint32_t)GMII_AUTONEG; /* Remove auto-negotiation enable */ + ul_value &= ~(uint32_t)(GMII_LOOPBACK | GMII_POWER_DOWN); + ul_value |= (uint32_t)GMII_ISOLATE; /* Electrically isolate PHY */ + uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value); + if (uc_rc != GMAC_OK) { + gmac_enable_management(p_gmac, false); +phy_props.phy_result = -2; + return uc_rc; + } + + /* + * Set the Auto_negotiation Advertisement Register. + * MII advertising for Next page. + * 100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3. + */ + ul_phy_anar = GMII_100TX_FDX | GMII_100TX_HDX | GMII_10_FDX | GMII_10_HDX | + GMII_AN_IEEE_802_3; + uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_ANAR, ul_phy_anar); + if (uc_rc != GMAC_OK) { + gmac_enable_management(p_gmac, false); +phy_props.phy_result = -3; + return uc_rc; + } + + /* Read & modify control register */ + uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMCR, &ul_value); + if (uc_rc != GMAC_OK) { + gmac_enable_management(p_gmac, false); +phy_props.phy_result = -4; + return uc_rc; + } + + ul_value |= GMII_SPEED_SELECT | GMII_AUTONEG | GMII_DUPLEX_MODE; + uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value); + if (uc_rc != GMAC_OK) { + gmac_enable_management(p_gmac, false); +phy_props.phy_result = -5; + return uc_rc; + } + + /* Restart auto negotiation */ + ul_value |= (uint32_t)GMII_RESTART_AUTONEG; + ul_value &= ~(uint32_t)GMII_ISOLATE; + uc_rc = gmac_phy_write(p_gmac, uc_phy_addr, GMII_BMCR, ul_value); + if (uc_rc != GMAC_OK) { + gmac_enable_management(p_gmac, false); +phy_props.phy_result = -6; + return uc_rc; + } + + /* Check if auto negotiation is completed */ + while (1) { + uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_BMSR, &ul_value); + if (uc_rc != GMAC_OK) { + gmac_enable_management(p_gmac, false); +phy_props.phy_result = -7; + return uc_rc; + } + /* Done successfully */ + if (ul_value & GMII_AUTONEG_COMP) { + break; + } + + /* Timeout check */ + if (ul_retry_max) { + if (++ul_retry_count >= ul_retry_max) { + gmac_enable_management(p_gmac, false); +phy_props.phy_result = -8; + return GMAC_TIMEOUT; + } + } + } + + /* Get the auto negotiate link partner base page */ + uc_rc = gmac_phy_read(p_gmac, uc_phy_addr, GMII_PCR1, &phy_props.phy_params); + if (uc_rc != GMAC_OK) { + gmac_enable_management(p_gmac, false); +phy_props.phy_result = -9; + return uc_rc; + } + + + /* Set up the GMAC link speed */ + if ((ul_phy_anar & phy_props.phy_params) & GMII_100TX_FDX) { + /* Set MII for 100BaseTX and Full Duplex */ + uc_speed = true; + uc_fd = true; + } else if ((ul_phy_anar & phy_props.phy_params) & GMII_10_FDX) { + /* Set MII for 10BaseT and Full Duplex */ + uc_speed = false; + uc_fd = true; + } else if ((ul_phy_anar & phy_props.phy_params) & GMII_100TX_HDX) { + /* Set MII for 100BaseTX and half Duplex */ + uc_speed = true; + uc_fd = false; + } else if ((ul_phy_anar & phy_props.phy_params) & GMII_10_HDX) { + /* Set MII for 10BaseT and half Duplex */ + uc_speed = false; + uc_fd = false; + } + + gmac_set_speed(p_gmac, uc_speed); + gmac_enable_full_duplex(p_gmac, uc_fd); + + /* Select Media Independent Interface type */ + gmac_select_mii_mode(p_gmac, ETH_PHY_MODE); + + gmac_enable_transmit(GMAC, true); + gmac_enable_receive(GMAC, true); + + gmac_enable_management(p_gmac, false); +phy_props.phy_result = 1; + return uc_rc; +} + +/** + * \brief Issue a SW reset to reset all registers of the PHY. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_phy_addr PHY address. + * + * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout. + */ +uint8_t ethernet_phy_reset(Gmac *p_gmac, uint8_t uc_phy_addr) +{ + uint32_t ul_bmcr = GMII_RESET; + uint8_t uc_phy_address = uc_phy_addr; + uint32_t ul_timeout = ETH_PHY_TIMEOUT; + uint8_t uc_rc = GMAC_TIMEOUT; + + gmac_enable_management(p_gmac, true); + + ul_bmcr = GMII_RESET; + gmac_phy_write(p_gmac, uc_phy_address, GMII_BMCR, ul_bmcr); + + do { + gmac_phy_read(p_gmac, uc_phy_address, GMII_BMCR, &ul_bmcr); + ul_timeout--; + } while ((ul_bmcr & GMII_RESET) && ul_timeout); + + gmac_enable_management(p_gmac, false); + + if (!ul_timeout) { + uc_rc = GMAC_OK; + } + + return (uc_rc); +} + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +} +#endif +/**INDENT-ON**/ +/// @endcond + +/** + * \} + */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.h new file mode 100644 index 000000000..8ea5fa0c7 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/ethernet_phy.h @@ -0,0 +1,281 @@ +/** + * \file + * + * \brief KSZ8051MNL (Ethernet PHY) driver for SAM. + * + * Copyright (c) 2013 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef ETHERNET_PHY_H_INCLUDED +#define ETHERNET_PHY_H_INCLUDED + +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// IEEE defined Registers +#define GMII_BMCR 0x00 // Basic Control +#define GMII_BMSR 0x01 // Basic Status +#define GMII_PHYID1 0x02 // PHY Idendifier 1 +#define GMII_PHYID2 0x03 // PHY Idendifier 2 +#define GMII_ANAR 0x04 // Auto_Negotiation Advertisement +#define GMII_ANLPAR 0x05 // Auto_negotiation Link Partner Ability +#define GMII_ANER 0x06 // Auto-negotiation Expansion +#define GMII_ANNPR 0x07 // Auto-negotiation Next Page +#define GMII_ANLPNPAR 0x08 // Link Partner Next Page Ability +//#define GMII_1000BTCR 9 // 1000Base-T Control // Reserved +//#define GMII_1000BTSR 10 // 1000Base-T Status // Reserved +#define GMII_AFECR1 0x11 // AFE Control 1 +//#define GMII_ERDWR 12 // Extend Register - Data Write Register +//#define GMII_ERDRR 13 // Extend Register - Data Read Register +//14 reserved +#define GMII_RXERCR 0x15 // RXER Counter + + #define PHY_REG_01_BMSR 0x01 // Basic mode status register + #define PHY_REG_02_PHYSID1 0x02 // PHYS ID 1 + #define PHY_REG_03_PHYSID2 0x03 // PHYS ID 2 + #define PHY_REG_04_ADVERTISE 0x04 // Advertisement control reg + #define PHY_REG_05_LPA 0x05 // Link partner ability reg + #define PHY_REG_06_ANER 0x06 // 6 RW Auto-Negotiation Expansion Register + #define PHY_REG_07_ANNPTR 0x07 // 7 RW Auto-Negotiation Next Page TX + #define PHY_REG_08_RESERVED0 0x08 // 0x08..0x0Fh 8-15 RW RESERVED + + #define PHY_REG_10_PHYSTS 0x10 // 16 RO PHY Status Register + #define PHY_REG_11_MICR 0x11 // 17 RW MII Interrupt Control Register + #define PHY_REG_12_MISR 0x12 // 18 RO MII Interrupt Status Register + #define PHY_REG_13_RESERVED1 0x13 // 19 RW RESERVED + #define PHY_REG_14_FCSCR 0x14 // 20 RO False Carrier Sense Counter Register + #define PHY_REG_15_RECR 0x15 // 21 RO Receive Error Counter Register + #define PHY_REG_16_PCSR 0x16 // 22 RW PCS Sub-Layer Configuration and Status Register + #define PHY_REG_17_RBR 0x17 // 23 RW RMII and Bypass Register + #define PHY_REG_18_LEDCR 0x18 // 24 RW LED Direct Control Register + #define PHY_REG_19_PHYCR 0x19 // 25 RW PHY Control Register + #define PHY_REG_1A_10BTSCR 0x1A // 26 RW 10Base-T Status/Control Register + #define PHY_REG_1B_CDCTRL1 0x1B // 27 RW CD Test Control Register and BIST Extensions Register + #define PHY_REG_1B_INT_CTRL 0x1B // 27 RW KSZ8041NL interrupt control + #define PHY_REG_1C_RESERVED2 0x1C // 28 RW RESERVED + #define PHY_REG_1D_EDCR 0x1D // 29 RW Energy Detect Control Register + #define PHY_REG_1E_RESERVED3 0x1E // + #define PHY_REG_1F_RESERVED4 0x1F // 30-31 RW RESERVED + + #define PHY_REG_1E_PHYCR_1 0x1E // + #define PHY_REG_1F_PHYCR_2 0x1F // + + #define PHY_SPEED_10 1 + #define PHY_SPEED_100 2 + #define PHY_SPEED_AUTO (PHY_SPEED_10|PHY_SPEED_100) + + #define PHY_MDIX_DIRECT 1 + #define PHY_MDIX_CROSSED 2 + #define PHY_MDIX_AUTO (PHY_MDIX_CROSSED|PHY_MDIX_DIRECT) + + #define PHY_DUPLEX_HALF 1 + #define PHY_DUPLEX_FULL 2 + #define PHY_DUPLEX_AUTO (PHY_DUPLEX_FULL|PHY_DUPLEX_HALF) + + typedef struct _SPhyProps { + unsigned char speed; + unsigned char mdix; + unsigned char duplex; + unsigned char spare; + } SPhyProps; + + const char *phyPrintable (const SPhyProps *apProps); + + extern SPhyProps phyProps; + +#define GMII_OMSOR 0x16 // Operation Mode Strap Override +#define GMII_OMSSR 0x17 // Operation Mode Strap Status +#define GMII_ECR 0x18 // Expanded Control +//#define GMII_DPPSR 19 // Digital PMA/PCS Status +//20 reserved +//#define GMII_RXERCR 21 // RXER Counter Register +//22-26 reserved +#define GMII_ICSR 0x1B // Interrupt Control/Status +//#define GMII_DDC1R 28 // Digital Debug Control 1 Register +#define GMII_LCSR 0x1D // LinkMD Control/Status + +//29-30 reserved +#define GMII_PCR1 0x1E // PHY Control 1 +#define GMII_PCR2 0x1F // PHY Control 2 + +/* +//Extend Registers +#define GMII_CCR 256 // Common Control Register +#define GMII_SSR 257 // Strap Status Register +#define GMII_OMSOR 258 // Operation Mode Strap Override Register +#define GMII_OMSSR 259 // Operation Mode Strap Status Register +#define GMII_RCCPSR 260 // RGMII Clock and Control Pad Skew Register +#define GMII_RRDPSR 261 // RGMII RX Data Pad Skew Register +#define GMII_ATR 263 // Analog Test Register +*/ + + +// Bit definitions: GMII_BMCR 0x00 Basic Control +#define GMII_RESET (1 << 15) // 1= Software Reset; 0=Normal Operation +#define GMII_LOOPBACK (1 << 14) // 1=loopback Enabled; 0=Normal Operation +#define GMII_SPEED_SELECT (1 << 13) // 1=100Mbps; 0=10Mbps +#define GMII_AUTONEG (1 << 12) // Auto-negotiation Enable +#define GMII_POWER_DOWN (1 << 11) // 1=Power down 0=Normal operation +#define GMII_ISOLATE (1 << 10) // 1 = Isolates 0 = Normal operation +#define GMII_RESTART_AUTONEG (1 << 9) // 1 = Restart auto-negotiation 0 = Normal operation +#define GMII_DUPLEX_MODE (1 << 8) // 1 = Full duplex operation 0 = Normal operation +#define GMII_COLLISION_TEST (1 << 7) // 1 = Enable COL test; 0 = Disable COL test +//#define GMII_SPEED_SELECT_MSB (1 << 6) // Reserved +// Reserved 6 to 0 // Read as 0, ignore on write + +// Bit definitions: GMII_BMSR 0x01 Basic Status +#define GMII_100BASE_T4 (1 << 15) // 100BASE-T4 Capable +#define GMII_100BASE_TX_FD (1 << 14) // 100BASE-TX Full Duplex Capable +#define GMII_100BASE_T4_HD (1 << 13) // 100BASE-TX Half Duplex Capable +#define GMII_10BASE_T_FD (1 << 12) // 10BASE-T Full Duplex Capable +#define GMII_10BASE_T_HD (1 << 11) // 10BASE-T Half Duplex Capable +// Reserved 10 to79 // Read as 0, ignore on write +//#define GMII_EXTEND_STATUS (1 << 8) // 1 = Extend Status Information In Reg 15 +// Reserved 7 +#define GMII_MF_PREAMB_SUPPR (1 << 6) // MII Frame Preamble Suppression +#define GMII_AUTONEG_COMP (1 << 5) // Auto-negotiation Complete +#define GMII_REMOTE_FAULT (1 << 4) // Remote Fault +#define GMII_AUTONEG_ABILITY (1 << 3) // Auto Configuration Ability +#define GMII_LINK_STATUS (1 << 2) // Link Status +#define GMII_JABBER_DETECT (1 << 1) // Jabber Detect +#define GMII_EXTEND_CAPAB (1 << 0) // Extended Capability + + +// Bit definitions: GMII_PHYID1 0x02 PHY Idendifier 1 +// Bit definitions: GMII_PHYID2 0x03 PHY Idendifier 2 +#define GMII_LSB_MASK 0x3F +#define GMII_OUI_MSB 0x0022 +#define GMII_OUI_LSB 0x05 + + +// Bit definitions: GMII_ANAR 0x04 Auto_Negotiation Advertisement +// Bit definitions: GMII_ANLPAR 0x05 Auto_negotiation Link Partner Ability +#define GMII_NP (1 << 15) // Next page Indication +// Reserved 7 +#define GMII_RF (1 << 13) // Remote Fault +// Reserved 12 // Write as 0, ignore on read +#define GMII_PAUSE_MASK (3 << 11) // 0,0 = No Pause 1,0 = Asymmetric Pause(link partner) + // 0,1 = Symmetric Pause 1,1 = Symmetric&Asymmetric Pause(local device) +#define GMII_100T4 (1 << 9) // 100BASE-T4 Support +#define GMII_100TX_FDX (1 << 8) // 100BASE-TX Full Duplex Support +#define GMII_100TX_HDX (1 << 7) // 100BASE-TX Support +#define GMII_10_FDX (1 << 6) // 10BASE-T Full Duplex Support +#define GMII_10_HDX (1 << 5) // 10BASE-T Support +// Selector 4 to 0 // Protocol Selection Bits +#define GMII_AN_IEEE_802_3 0x0001 // [00001] = IEEE 802.3 + + +// Bit definitions: GMII_ANER 0x06 Auto-negotiation Expansion +// Reserved 15 to 5 // Read as 0, ignore on write +#define GMII_PDF (1 << 4) // Local Device Parallel Detection Fault +#define GMII_LP_NP_ABLE (1 << 3) // Link Partner Next Page Able +#define GMII_NP_ABLE (1 << 2) // Local Device Next Page Able +#define GMII_PAGE_RX (1 << 1) // New Page Received +#define GMII_LP_AN_ABLE (1 << 0) // Link Partner Auto-negotiation Able + +/** + * \brief Perform a HW initialization to the PHY and set up clocks. + * + * This should be called only once to initialize the PHY pre-settings. + * The PHY address is the reset status of CRS, RXD[3:0] (the GmacPins' pullups). + * The COL pin is used to select MII mode on reset (pulled up for Reduced MII). + * The RXDV pin is used to select test mode on reset (pulled up for test mode). + * The above pins should be predefined for corresponding settings in resetPins. + * The GMAC peripheral pins are configured after the reset is done. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_phy_addr PHY address. + * \param ul_mck GMAC MCK. + * + * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout. + */ +uint8_t ethernet_phy_init(Gmac *p_gmac, uint8_t uc_phy_addr, uint32_t ul_mck); + + +/** + * \brief Get the Link & speed settings, and automatically set up the GMAC with the + * settings. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_phy_addr PHY address. + * \param uc_apply_setting_flag Set to 0 to not apply the PHY configurations, else to apply. + * + * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout. + */ +uint8_t ethernet_phy_set_link(Gmac *p_gmac, uint8_t uc_phy_addr, + uint8_t uc_apply_setting_flag); + + +/** + * \brief Issue an auto negotiation of the PHY. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_phy_addr PHY address. + * + * Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout. + */ +uint8_t ethernet_phy_auto_negotiate(Gmac *p_gmac, uint8_t uc_phy_addr); + +/** + * \brief Issue a SW reset to reset all registers of the PHY. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_phy_addr PHY address. + * + * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout. + */ +uint8_t ethernet_phy_reset(Gmac *p_gmac, uint8_t uc_phy_addr); + +typedef struct xPHY_PROPS { + signed char phy_result; + uint32_t phy_params; + uint32_t phy_stat1; + uint32_t phy_stat2; + unsigned char phy_chn; +} PhyProps_t; +extern PhyProps_t phy_props; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* #ifndef ETHERNET_PHY_H_INCLUDED */ + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c new file mode 100644 index 000000000..fe73a73ac --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.c @@ -0,0 +1,945 @@ + /** + * \file + * + * \brief GMAC (Ethernet MAC) driver for SAM. + * + * Copyright (c) 2013 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +/* Standard includes. */ +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +#include "FreeRTOSIPConfig.h" + +#include "compiler.h" +#include "instance/gmac.h" +#include "ethernet_phy.h" + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +extern "C" { +#endif +/**INDENT-ON**/ +/// @endcond + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (int)( sizeof(x) / sizeof(x)[0] ) +#endif +/** + * \defgroup gmac_group Ethernet Media Access Controller + * + * See \ref gmac_quickstart. + * + * Driver for the GMAC (Ethernet Media Access Controller). + * This file contains basic functions for the GMAC, with support for all modes, settings + * and clock speeds. + * + * \section dependencies Dependencies + * This driver does not depend on other modules. + * + * @{ + */ + +/** TX descriptor lists */ +COMPILER_ALIGNED(8) +static gmac_tx_descriptor_t gs_tx_desc[ GMAC_TX_BUFFERS ]; +#if( GMAC_USES_TX_CALLBACK != 0 ) +/** TX callback lists */ +static gmac_dev_tx_cb_t gs_tx_callback[ GMAC_TX_BUFFERS ]; +#endif +/** RX descriptors lists */ +COMPILER_ALIGNED(8) +static gmac_rx_descriptor_t gs_rx_desc[ GMAC_RX_BUFFERS ]; + +#if( ipconfigZERO_COPY_TX_DRIVER == 0 ) + /** Send Buffer. Section 3.6 of AMBA 2.0 spec states that burst should not cross the + * 1K Boundaries. Receive buffer manager write operations are burst of 2 words => 3 lsb bits + * of the address shall be set to 0. + */ + COMPILER_ALIGNED(8) + static uint8_t gs_uc_tx_buffer[ GMAC_TX_BUFFERS * GMAC_TX_UNITSIZE ]; +#endif /* ipconfigZERO_COPY_TX_DRIVER */ + +/** Receive Buffer */ +COMPILER_ALIGNED(8) +static uint8_t gs_uc_rx_buffer[ GMAC_RX_BUFFERS * GMAC_RX_UNITSIZE ]; + +/** + * GMAC device memory management struct. + */ +typedef struct gmac_dev_mem { + /* Pointer to allocated buffer for RX. The address should be 8-byte aligned + and the size should be GMAC_RX_UNITSIZE * wRxSize. */ + uint8_t *p_rx_buffer; + /* Pointer to allocated RX descriptor list. */ + gmac_rx_descriptor_t *p_rx_dscr; + /* RX size, in number of registered units (RX descriptors). */ + /* Increased size from 16- to 32-bits, because it's more efficient */ + uint32_t us_rx_size; + /* Pointer to allocated buffer for TX. The address should be 8-byte aligned + and the size should be GMAC_TX_UNITSIZE * wTxSize. */ + uint8_t *p_tx_buffer; + /* Pointer to allocated TX descriptor list. */ + gmac_tx_descriptor_t *p_tx_dscr; + /* TX size, in number of registered units (TX descriptors). */ + uint32_t us_tx_size; +} gmac_dev_mem_t; + +/** Return count in buffer */ +#define CIRC_CNT( head, tail, size ) ( ( ( head ) - ( tail ) ) % ( size ) ) + +/* + * Return space available, from 0 to size-1. + * Always leave one free char as a completely full buffer that has (head == tail), + * which is the same as empty. + */ +#define CIRC_SPACE( head, tail, size ) CIRC_CNT( ( tail ), ( ( head ) + 1 ), ( size ) ) + +/** Circular buffer is empty ? */ +#define CIRC_EMPTY( head, tail ) ( head == tail ) +/** Clear circular buffer */ +#define CIRC_CLEAR( head, tail ) do { ( head ) = 0; ( tail ) = 0; } while( 0 ) + +/** Increment head or tail */ +static __inline void circ_inc32( int32_t *lHeadOrTail, uint32_t ulSize ) +{ + ( *lHeadOrTail ) ++; + if( ( *lHeadOrTail ) >= ( int32_t )ulSize ) + { + ( *lHeadOrTail ) = 0; + } +} + +/** + * \brief Wait PHY operation to be completed. + * + * \param p_gmac HW controller address. + * \param ul_retry The retry times, 0 to wait forever until completeness. + * + * Return GMAC_OK if the operation is completed successfully. + */ +static uint8_t gmac_wait_phy(Gmac* p_gmac, const uint32_t ul_retry) +{ + volatile uint32_t ul_retry_count = 0; + const uint32_t xPHYPollDelay = pdMS_TO_TICKS( 1ul ); + + while (!gmac_is_phy_idle(p_gmac)) { + if (ul_retry == 0) { + continue; + } + + ul_retry_count++; + + if (ul_retry_count >= ul_retry) { + return GMAC_TIMEOUT; + } + + /* Block the task to allow other tasks to execute while the PHY + is not connected. */ + vTaskDelay( xPHYPollDelay ); + } + return GMAC_OK; +} + +/** + * \brief Disable transfer, reset registers and descriptor lists. + * + * \param p_dev Pointer to GMAC driver instance. + * + */ +static void gmac_reset_tx_mem(gmac_device_t* p_dev) +{ + Gmac *p_hw = p_dev->p_hw; + uint8_t *p_tx_buff = p_dev->p_tx_buffer; + gmac_tx_descriptor_t *p_td = p_dev->p_tx_dscr; + + uint32_t ul_index; + uint32_t ul_address; + + /* Disable TX */ + gmac_enable_transmit(p_hw, 0); + + /* Set up the TX descriptors */ + CIRC_CLEAR(p_dev->l_tx_head, p_dev->l_tx_tail); + for( ul_index = 0; ul_index < p_dev->ul_tx_list_size; ul_index++ ) + { + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + ul_address = (uint32_t) 0u; + } + #else + { + ul_address = (uint32_t) (&(p_tx_buff[ul_index * GMAC_TX_UNITSIZE])); + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + p_td[ul_index].addr = ul_address; + p_td[ul_index].status.val = GMAC_TXD_USED; + } + p_td[p_dev->ul_tx_list_size - 1].status.val = + GMAC_TXD_USED | GMAC_TXD_WRAP; + + /* Set transmit buffer queue */ + gmac_set_tx_queue(p_hw, (uint32_t) p_td); +} + +/** + * \brief Disable receiver, reset registers and descriptor list. + * + * \param p_drv Pointer to GMAC Driver instance. + */ +static void gmac_reset_rx_mem(gmac_device_t* p_dev) +{ + Gmac *p_hw = p_dev->p_hw; + uint8_t *p_rx_buff = p_dev->p_rx_buffer; + gmac_rx_descriptor_t *pRd = p_dev->p_rx_dscr; + + uint32_t ul_index; + uint32_t ul_address; + + /* Disable RX */ + gmac_enable_receive(p_hw, 0); + + /* Set up the RX descriptors */ + p_dev->ul_rx_idx = 0; + for( ul_index = 0; ul_index < p_dev->ul_rx_list_size; ul_index++ ) + { + ul_address = (uint32_t) (&(p_rx_buff[ul_index * GMAC_RX_UNITSIZE])); + pRd[ul_index].addr.val = ul_address & GMAC_RXD_ADDR_MASK; + pRd[ul_index].status.val = 0; + } + pRd[p_dev->ul_rx_list_size - 1].addr.val |= GMAC_RXD_WRAP; + + /* Set receive buffer queue */ + gmac_set_rx_queue(p_hw, (uint32_t) pRd); +} + + +/** + * \brief Initialize the allocated buffer lists for GMAC driver to transfer data. + * Must be invoked after gmac_dev_init() but before RX/TX starts. + * + * \note If input address is not 8-byte aligned, the address is automatically + * adjusted and the list size is reduced by one. + * + * \param p_gmac Pointer to GMAC instance. + * \param p_gmac_dev Pointer to GMAC device instance. + * \param p_dev_mm Pointer to the GMAC memory management control block. + * \param p_tx_cb Pointer to allocated TX callback list. + * + * \return GMAC_OK or GMAC_PARAM. + */ +static uint8_t gmac_init_mem(Gmac* p_gmac, gmac_device_t* p_gmac_dev, + gmac_dev_mem_t* p_dev_mm +#if( GMAC_USES_TX_CALLBACK != 0 ) + , gmac_dev_tx_cb_t* p_tx_cb +#endif + ) +{ + if (p_dev_mm->us_rx_size <= 1 || p_dev_mm->us_tx_size <= 1 +#if( GMAC_USES_TX_CALLBACK != 0 ) + || p_tx_cb == NULL +#endif + ) { + return GMAC_PARAM; + } + + /* Assign RX buffers */ + if (((uint32_t) p_dev_mm->p_rx_buffer & 0x7) + || ((uint32_t) p_dev_mm->p_rx_dscr & 0x7)) { + p_dev_mm->us_rx_size--; + } + p_gmac_dev->p_rx_buffer = + (uint8_t *) ((uint32_t) p_dev_mm->p_rx_buffer & 0xFFFFFFF8); + p_gmac_dev->p_rx_dscr = + (gmac_rx_descriptor_t *) ((uint32_t) p_dev_mm->p_rx_dscr + & 0xFFFFFFF8); + p_gmac_dev->ul_rx_list_size = p_dev_mm->us_rx_size; + + /* Assign TX buffers */ + if (((uint32_t) p_dev_mm->p_tx_buffer & 0x7) + || ((uint32_t) p_dev_mm->p_tx_dscr & 0x7)) { + p_dev_mm->us_tx_size--; + } + p_gmac_dev->p_tx_buffer = + (uint8_t *) ((uint32_t) p_dev_mm->p_tx_buffer & 0xFFFFFFF8); + p_gmac_dev->p_tx_dscr = + (gmac_tx_descriptor_t *) ((uint32_t) p_dev_mm->p_tx_dscr + & 0xFFFFFFF8); + p_gmac_dev->ul_tx_list_size = p_dev_mm->us_tx_size; +#if( GMAC_USES_TX_CALLBACK != 0 ) + p_gmac_dev->func_tx_cb_list = p_tx_cb; +#endif + /* Reset TX & RX */ + gmac_reset_rx_mem(p_gmac_dev); + gmac_reset_tx_mem(p_gmac_dev); + + /* Enable Rx and Tx, plus the statistics register */ + gmac_enable_transmit(p_gmac, true); + gmac_enable_receive(p_gmac, true); + gmac_enable_statistics_write(p_gmac, true); + + /* Set up the interrupts for transmission and errors */ + gmac_enable_interrupt(p_gmac, + GMAC_IER_RXUBR | /* Enable receive used bit read interrupt. */ + GMAC_IER_TUR | /* Enable transmit underrun interrupt. */ + GMAC_IER_RLEX | /* Enable retry limit exceeded interrupt. */ + GMAC_IER_TFC | /* Enable transmit buffers exhausted in mid-frame interrupt. */ + GMAC_IER_TCOMP | /* Enable transmit complete interrupt. */ + GMAC_IER_ROVR | /* Enable receive overrun interrupt. */ + GMAC_IER_HRESP | /* Enable Hresp not OK interrupt. */ + GMAC_IER_PFNZ | /* Enable pause frame received interrupt. */ + GMAC_IER_PTZ); /* Enable pause time zero interrupt. */ + + return GMAC_OK; +} + +/** + * \brief Read the PHY register. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_phy_address PHY address. + * \param uc_address Register address. + * \param p_value Pointer to a 32-bit location to store read data. + * + * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout. + */ +uint8_t gmac_phy_read(Gmac* p_gmac, uint8_t uc_phy_address, uint8_t uc_address, + uint32_t* p_value) +{ + gmac_maintain_phy(p_gmac, uc_phy_address, uc_address, 1, 0); + + if (gmac_wait_phy(p_gmac, MAC_PHY_RETRY_MAX) == GMAC_TIMEOUT) { + return GMAC_TIMEOUT; + } + *p_value = gmac_get_phy_data(p_gmac); + return GMAC_OK; +} + +/** + * \brief Write the PHY register. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_phy_address PHY Address. + * \param uc_address Register Address. + * \param ul_value Data to write, actually 16-bit data. + * + * \Return GMAC_OK if successfully, GMAC_TIMEOUT if timeout. + */ +uint8_t gmac_phy_write(Gmac* p_gmac, uint8_t uc_phy_address, + uint8_t uc_address, uint32_t ul_value) +{ + gmac_maintain_phy(p_gmac, uc_phy_address, uc_address, 0, ul_value); + + if (gmac_wait_phy(p_gmac, MAC_PHY_RETRY_MAX) == GMAC_TIMEOUT) { + return GMAC_TIMEOUT; + } + return GMAC_OK; +} + +/** + * \brief Initialize the GMAC driver. + * + * \param p_gmac Pointer to the GMAC instance. + * \param p_gmac_dev Pointer to the GMAC device instance. + * \param p_opt GMAC configure options. + */ +void gmac_dev_init(Gmac* p_gmac, gmac_device_t* p_gmac_dev, + gmac_options_t* p_opt) +{ + gmac_dev_mem_t gmac_dev_mm; + + /* Disable TX & RX and more */ + gmac_network_control(p_gmac, 0); + gmac_disable_interrupt(p_gmac, ~0u); + + + gmac_clear_statistics(p_gmac); + + /* Clear all status bits in the receive status register. */ + gmac_clear_rx_status(p_gmac, GMAC_RSR_RXOVR | GMAC_RSR_REC | GMAC_RSR_BNA); + + /* Clear all status bits in the transmit status register */ + gmac_clear_tx_status(p_gmac, GMAC_TSR_UBR | GMAC_TSR_COL | GMAC_TSR_RLE + | GMAC_TSR_TFC | GMAC_TSR_TXCOMP | GMAC_TSR_UND); + + /* Clear interrupts */ + gmac_get_interrupt_status(p_gmac); +#if !defined(ETHERNET_CONF_DATA_OFFSET) + /* Receive Buffer Offset + * Indicates the number of bytes by which the received data + * is offset from the start of the receive buffer + * which can be handy for alignment reasons */ + /* Note: FreeRTOS+TCP wants to have this offset set to 2 bytes */ + #error ETHERNET_CONF_DATA_OFFSET not defined, assuming 0 +#endif + /* Enable the copy of data into the buffers + ignore broadcasts, and not copy FCS. */ + + gmac_set_configure(p_gmac, + ( gmac_get_configure(p_gmac) & ~GMAC_NCFGR_RXBUFO_Msk ) | + GMAC_NCFGR_RFCS | /* Remove FCS, frame check sequence (last 4 bytes) */ + GMAC_NCFGR_PEN | /* Pause Enable */ + GMAC_NCFGR_RXBUFO( ETHERNET_CONF_DATA_OFFSET ) | + GMAC_RXD_RXCOEN ); + + /* + * GMAC_DCFGR_TXCOEN: (GMAC_DCFGR) Transmitter Checksum Generation Offload Enable. + * Note: tha SAM4E does have RX checksum offloading + * but TX checksum offloading has NOT been implemented. + * http://community.atmel.com/forum/sam4e-gmac-transmit-checksum-offload-enablesolved + */ + + gmac_set_dma(p_gmac, + gmac_get_dma(p_gmac) | GMAC_DCFGR_TXCOEN ); + + gmac_enable_copy_all(p_gmac, p_opt->uc_copy_all_frame); + gmac_disable_broadcast(p_gmac, p_opt->uc_no_boardcast); + + /* Fill in GMAC device memory management */ + gmac_dev_mm.p_rx_buffer = gs_uc_rx_buffer; + gmac_dev_mm.p_rx_dscr = gs_rx_desc; + gmac_dev_mm.us_rx_size = GMAC_RX_BUFFERS; + + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + gmac_dev_mm.p_tx_buffer = NULL; + } + #else + { + gmac_dev_mm.p_tx_buffer = gs_uc_tx_buffer; + } + #endif + gmac_dev_mm.p_tx_dscr = gs_tx_desc; + gmac_dev_mm.us_tx_size = GMAC_TX_BUFFERS; + + gmac_init_mem(p_gmac, p_gmac_dev, &gmac_dev_mm +#if( GMAC_USES_TX_CALLBACK != 0 ) + , gs_tx_callback +#endif + ); + + gmac_set_address(p_gmac, 0, p_opt->uc_mac_addr); +} + +/** + * \brief Frames can be read from the GMAC in multiple sections. + * + * Returns > 0 if a complete frame is available + * It also it cleans up incomplete older frames + */ + +static uint32_t gmac_dev_poll(gmac_device_t* p_gmac_dev) +{ + uint32_t ulReturn = 0; + int32_t ulIndex = p_gmac_dev->ul_rx_idx; + gmac_rx_descriptor_t *pxHead = &p_gmac_dev->p_rx_dscr[ulIndex]; + + /* Discard any incomplete frames */ + while ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) && + (pxHead->status.val & GMAC_RXD_SOF) == 0) { + pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP); + circ_inc32 (&ulIndex, p_gmac_dev->ul_rx_list_size); + pxHead = &p_gmac_dev->p_rx_dscr[ulIndex]; + p_gmac_dev->ul_rx_idx = ulIndex; + #if( GMAC_STATS != 0 ) + { + gmacStats.incompCount++; + } + #endif + } + + while ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) != 0) { + if ((pxHead->status.val & GMAC_RXD_EOF) != 0) { + /* Here a complete frame has been seen with SOF and EOF */ + ulReturn = pxHead->status.bm.len; + break; + } + circ_inc32 (&ulIndex, p_gmac_dev->ul_rx_list_size); + pxHead = &p_gmac_dev->p_rx_dscr[ulIndex]; + if ((pxHead->addr.val & GMAC_RXD_OWNERSHIP) == 0) { + /* CPU is not the owner (yet) */ + break; + } + if ((pxHead->status.val & GMAC_RXD_SOF) != 0) { + /* Strange, we found a new Start Of Frame + * discard previous segments */ + int32_t ulPrev = p_gmac_dev->ul_rx_idx; + pxHead = &p_gmac_dev->p_rx_dscr[ulPrev]; + do { + pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP); + circ_inc32 (&ulPrev, p_gmac_dev->ul_rx_list_size); + pxHead = &p_gmac_dev->p_rx_dscr[ulPrev]; + #if( GMAC_STATS != 0 ) + { + gmacStats.truncCount++; + } + #endif + } while (ulPrev != ulIndex); + p_gmac_dev->ul_rx_idx = ulIndex; + } + } + return ulReturn; +} + +/** + * \brief Frames can be read from the GMAC in multiple sections. + * Read ul_frame_size bytes from the GMAC receive buffers to pcTo. + * p_rcv_size is the size of the entire frame. Generally gmac_read + * will be repeatedly called until the sum of all the ul_frame_size equals + * the value of p_rcv_size. + * + * \param p_gmac_dev Pointer to the GMAC device instance. + * \param p_frame Address of the frame buffer. + * \param ul_frame_size Length of the frame. + * \param p_rcv_size Received frame size. + * + * \return GMAC_OK if receiving frame successfully, otherwise failed. + */ +uint32_t gmac_dev_read(gmac_device_t* p_gmac_dev, uint8_t* p_frame, + uint32_t ul_frame_size, uint32_t* p_rcv_size) +{ + int32_t nextIdx; /* A copy of the Rx-index 'ul_rx_idx' */ + int32_t bytesLeft = gmac_dev_poll (p_gmac_dev); + gmac_rx_descriptor_t *pxHead; + + if (bytesLeft == 0 ) + { + return GMAC_RX_NULL; + } + + /* gmac_dev_poll has confirmed that there is a complete frame at + * the current position 'ul_rx_idx' + */ + nextIdx = p_gmac_dev->ul_rx_idx; + + /* Read +2 bytes because buffers are aligned at -2 bytes */ + bytesLeft = min( bytesLeft + 2, ( int32_t )ul_frame_size ); + + /* The frame will be copied in 1 or 2 memcpy's */ + if( ( p_frame != NULL ) && ( bytesLeft != 0 ) ) + { + const uint8_t *source; + int32_t left; + int32_t toCopy; + + source = p_gmac_dev->p_rx_buffer + nextIdx * GMAC_RX_UNITSIZE; + left = bytesLeft; + toCopy = ( p_gmac_dev->ul_rx_list_size - nextIdx ) * GMAC_RX_UNITSIZE; + if(toCopy > left ) + { + toCopy = left; + } + memcpy (p_frame, source, toCopy); + left -= toCopy; + + if( left != 0ul ) + { + memcpy (p_frame + toCopy, (void*)p_gmac_dev->p_rx_buffer, left); + } + } + + do + { + pxHead = &p_gmac_dev->p_rx_dscr[nextIdx]; + pxHead->addr.val &= ~(GMAC_RXD_OWNERSHIP); + circ_inc32 (&nextIdx, p_gmac_dev->ul_rx_list_size); + } while ((pxHead->status.val & GMAC_RXD_EOF) == 0); + + p_gmac_dev->ul_rx_idx = nextIdx; + + *p_rcv_size = bytesLeft; + + return GMAC_OK; +} + + +extern void vGMACGenerateChecksum( uint8_t *apBuffer ); + +/** + * \brief Send ulLength bytes from pcFrom. This copies the buffer to one of the + * GMAC Tx buffers, and then indicates to the GMAC that the buffer is ready. + * If lEndOfFrame is true then the data being copied is the end of the frame + * and the frame can be transmitted. + * + * \param p_gmac_dev Pointer to the GMAC device instance. + * \param p_buffer Pointer to the data buffer. + * \param ul_size Length of the frame. + * \param func_tx_cb Transmit callback function. + * + * \return Length sent. + */ +uint32_t gmac_dev_write(gmac_device_t* p_gmac_dev, void *p_buffer, + uint32_t ul_size, gmac_dev_tx_cb_t func_tx_cb) +{ + + volatile gmac_tx_descriptor_t *p_tx_td; +#if( GMAC_USES_TX_CALLBACK != 0 ) + volatile gmac_dev_tx_cb_t *p_func_tx_cb; +#endif + + Gmac *p_hw = p_gmac_dev->p_hw; + +#if( GMAC_USES_TX_CALLBACK == 0 ) + ( void )func_tx_cb; +#endif + + /* Check parameter */ + if (ul_size > GMAC_TX_UNITSIZE) { + return GMAC_PARAM; + } + + /* Pointers to the current transmit descriptor */ + p_tx_td = &p_gmac_dev->p_tx_dscr[p_gmac_dev->l_tx_head]; + + /* If no free TxTd, buffer can't be sent, schedule the wakeup callback */ +// if (CIRC_SPACE(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail, +// p_gmac_dev->ul_tx_list_size) == 0) + { + if ((p_tx_td->status.val & GMAC_TXD_USED) == 0) + return GMAC_TX_BUSY; + } +#if( GMAC_USES_TX_CALLBACK != 0 ) + /* Pointers to the current Tx callback */ + p_func_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_head]; +#endif + + /* Set up/copy data to transmission buffer */ + if (p_buffer && ul_size) { + /* Driver manages the ring buffer */ + /* Calculating the checksum here is faster than calculating it from the GMAC buffer + * because withing p_buffer, it is well aligned */ + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + /* Zero-copy... */ + p_tx_td->addr = ( uint32_t ) p_buffer; + } + #else + { + /* Or memcopy... */ + memcpy((void *)p_tx_td->addr, p_buffer, ul_size); + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + vGMACGenerateChecksum( ( uint8_t * ) p_tx_td->addr ); + } + +#if( GMAC_USES_TX_CALLBACK != 0 ) + /* Tx callback */ + *p_func_tx_cb = func_tx_cb; +#endif + + /* Update transmit descriptor status */ + + /* The buffer size defined is the length of ethernet frame, + so it's always the last buffer of the frame. */ + if( p_gmac_dev->l_tx_head == ( int32_t )( p_gmac_dev->ul_tx_list_size - 1 ) ) + { + /* No need to 'and' with GMAC_TXD_LEN_MASK because ul_size has been checked */ + p_tx_td->status.val = + ul_size | GMAC_TXD_LAST | GMAC_TXD_WRAP; + } else { + p_tx_td->status.val = + ul_size | GMAC_TXD_LAST; + } + + circ_inc32( &p_gmac_dev->l_tx_head, p_gmac_dev->ul_tx_list_size ); + + /* Now start to transmit if it is still not done */ + gmac_start_transmission(p_hw); + + return GMAC_OK; +} + +/** + * \brief Get current load of transmit. + * + * \param p_gmac_dev Pointer to the GMAC device instance. + * + * \return Current load of transmit. + */ +#if( GMAC_USES_TX_CALLBACK != 0 ) +/* Without defining GMAC_USES_TX_CALLBACK, l_tx_tail won't be updated */ +uint32_t gmac_dev_get_tx_load(gmac_device_t* p_gmac_dev) +{ + uint16_t us_head = p_gmac_dev->l_tx_head; + uint16_t us_tail = p_gmac_dev->l_tx_tail; + return CIRC_CNT(us_head, us_tail, p_gmac_dev->ul_tx_list_size); +} +#endif + +/** + * \brief Register/Clear RX callback. Callback will be invoked after the next received + * frame. + * + * When gmac_dev_read() returns GMAC_RX_NULL, the application task calls + * gmac_dev_set_rx_callback() to register func_rx_cb() callback and enters suspend state. + * The callback is in charge to resume the task once a new frame has been + * received. The next time gmac_dev_read() is called, it will be successful. + * + * This function is usually invoked from the RX callback itself with NULL + * callback, to unregister. Once the callback has resumed the application task, + * there is no need to invoke the callback again. + * + * \param p_gmac_dev Pointer to the GMAC device instance. + * \param func_tx_cb Receive callback function. + */ +void gmac_dev_set_rx_callback(gmac_device_t* p_gmac_dev, + gmac_dev_rx_cb_t func_rx_cb) +{ + Gmac *p_hw = p_gmac_dev->p_hw; + + if (func_rx_cb == NULL) { + gmac_disable_interrupt(p_hw, GMAC_IDR_RCOMP); + p_gmac_dev->func_rx_cb = NULL; + } else { + p_gmac_dev->func_rx_cb = func_rx_cb; + gmac_enable_interrupt(p_hw, GMAC_IER_RCOMP); + } +} + +/** + * \brief Register/Clear TX wakeup callback. + * + * When gmac_dev_write() returns GMAC_TX_BUSY (all transmit descriptor busy), the application + * task calls gmac_dev_set_tx_wakeup_callback() to register func_wakeup() callback and + * enters suspend state. The callback is in charge to resume the task once + * several transmit descriptors have been released. The next time gmac_dev_write() will be called, + * it shall be successful. + * + * This function is usually invoked with NULL callback from the TX wakeup + * callback itself, to unregister. Once the callback has resumed the + * application task, there is no need to invoke the callback again. + * + * \param p_gmac_dev Pointer to GMAC device instance. + * \param func_wakeup Pointer to wakeup callback function. + * \param uc_threshold Number of free transmit descriptor before wakeup callback invoked. + * + * \return GMAC_OK, GMAC_PARAM on parameter error. + */ +#if( GMAC_USES_WAKEUP_CALLBACK ) +uint8_t gmac_dev_set_tx_wakeup_callback(gmac_device_t* p_gmac_dev, + gmac_dev_wakeup_cb_t func_wakeup_cb, uint8_t uc_threshold) +{ + if (func_wakeup_cb == NULL) { + p_gmac_dev->func_wakeup_cb = NULL; + } else { + if (uc_threshold <= p_gmac_dev->ul_tx_list_size) { + p_gmac_dev->func_wakeup_cb = func_wakeup_cb; + p_gmac_dev->uc_wakeup_threshold = uc_threshold; + } else { + return GMAC_PARAM; + } + } + + return GMAC_OK; +} +#endif /* GMAC_USES_WAKEUP_CALLBACK */ + +/** + * \brief Reset TX & RX queue & statistics. + * + * \param p_gmac_dev Pointer to GMAC device instance. + */ +void gmac_dev_reset(gmac_device_t* p_gmac_dev) +{ + Gmac *p_hw = p_gmac_dev->p_hw; + + gmac_reset_rx_mem(p_gmac_dev); + gmac_reset_tx_mem(p_gmac_dev); + gmac_network_control(p_hw, GMAC_NCR_TXEN | GMAC_NCR_RXEN + | GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT); +} + +void gmac_dev_halt(Gmac* p_gmac); + +void gmac_dev_halt(Gmac* p_gmac) +{ + gmac_network_control(p_gmac, GMAC_NCR_WESTAT | GMAC_NCR_CLRSTAT); + gmac_disable_interrupt(p_gmac, ~0u); +} + + +/** + * \brief GMAC Interrupt handler. + * + * \param p_gmac_dev Pointer to GMAC device instance. + */ + +#if( GMAC_STATS != 0 ) + extern int logPrintf( const char *pcFormat, ... ); + + void gmac_show_irq_counts () + { + int index; + for (index = 0; index < ARRAY_SIZE(intPairs); index++) { + if (gmacStats.intStatus[intPairs[index].index]) { + logPrintf("%s : %6u\n", intPairs[index].name, gmacStats.intStatus[intPairs[index].index]); + } + } + } +#endif + +void gmac_handler(gmac_device_t* p_gmac_dev) +{ + Gmac *p_hw = p_gmac_dev->p_hw; + +#if( GMAC_USES_TX_CALLBACK != 0 ) + gmac_tx_descriptor_t *p_tx_td; + gmac_dev_tx_cb_t *p_tx_cb = NULL; + uint32_t ul_tx_status_flag; +#endif +#if( GMAC_STATS != 0 ) + int index; +#endif + + /* volatile */ uint32_t ul_isr; + /* volatile */ uint32_t ul_rsr; + /* volatile */ uint32_t ul_tsr; + + ul_isr = gmac_get_interrupt_status(p_hw); + ul_rsr = gmac_get_rx_status(p_hw); + ul_tsr = gmac_get_tx_status(p_hw); + +/* Why clear bits that are ignored anyway ? */ +/* ul_isr &= ~(gmac_get_interrupt_mask(p_hw) | 0xF8030300); */ + #if( GMAC_STATS != 0 ) + { + for (index = 0; index < ARRAY_SIZE(intPairs); index++) { + if (ul_isr & intPairs[index].mask) + gmacStats.intStatus[intPairs[index].index]++; + } + } + #endif /* GMAC_STATS != 0 */ + + /* RX packet */ + if ((ul_isr & GMAC_ISR_RCOMP) || (ul_rsr & (GMAC_RSR_REC|GMAC_RSR_RXOVR|GMAC_RSR_BNA))) { + /* Clear status */ + gmac_clear_rx_status(p_hw, ul_rsr); + + if (ul_isr & GMAC_ISR_RCOMP) + ul_rsr |= GMAC_RSR_REC; + /* Invoke callbacks which can be useful to wake op a task */ + if (p_gmac_dev->func_rx_cb) { + p_gmac_dev->func_rx_cb(ul_rsr); + } + } + + /* TX packet */ + if ((ul_isr & GMAC_ISR_TCOMP) || (ul_tsr & (GMAC_TSR_TXCOMP|GMAC_TSR_COL|GMAC_TSR_RLE|GMAC_TSR_UND))) { + +#if( GMAC_USES_TX_CALLBACK != 0 ) + ul_tx_status_flag = GMAC_TSR_TXCOMP; +#endif + /* A frame transmitted */ + + /* Check RLE */ + if (ul_tsr & GMAC_TSR_RLE) { + /* Status RLE & Number of discarded buffers */ +#if( GMAC_USES_TX_CALLBACK != 0 ) + ul_tx_status_flag = GMAC_TSR_RLE | CIRC_CNT(p_gmac_dev->l_tx_head, + p_gmac_dev->l_tx_tail, p_gmac_dev->ul_tx_list_size); + p_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_tail]; +#endif + gmac_reset_tx_mem(p_gmac_dev); + gmac_enable_transmit(p_hw, 1); + } + /* Clear status */ + gmac_clear_tx_status(p_hw, ul_tsr); + +#if( GMAC_USES_TX_CALLBACK != 0 ) + if (!CIRC_EMPTY(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail)) { + /* Check the buffers */ + do { + p_tx_td = &p_gmac_dev->p_tx_dscr[p_gmac_dev->l_tx_tail]; + p_tx_cb = &p_gmac_dev->func_tx_cb_list[p_gmac_dev->l_tx_tail]; + /* Any error? Exit if buffer has not been sent yet */ + if ((p_tx_td->status.val & GMAC_TXD_USED) == 0) { + break; + } + + /* Notify upper layer that a packet has been sent */ + if (*p_tx_cb) { + (*p_tx_cb) (ul_tx_status_flag, (void*)p_tx_td->addr); + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + p_tx_td->addr = 0ul; + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + } + + circ_inc32(&p_gmac_dev->l_tx_tail, p_gmac_dev->ul_tx_list_size); + } while (CIRC_CNT(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail, + p_gmac_dev->ul_tx_list_size)); + } + + if (ul_tsr & GMAC_TSR_RLE) { + /* Notify upper layer RLE */ + if (*p_tx_cb) { + (*p_tx_cb) (ul_tx_status_flag, NULL); + } + } +#endif /* GMAC_USES_TX_CALLBACK */ + +#if( GMAC_USES_WAKEUP_CALLBACK ) + /* If a wakeup has been scheduled, notify upper layer that it can + send other packets, and the sending will be successful. */ + if ((CIRC_SPACE(p_gmac_dev->l_tx_head, p_gmac_dev->l_tx_tail, + p_gmac_dev->ul_tx_list_size) >= p_gmac_dev->uc_wakeup_threshold) + && p_gmac_dev->func_wakeup_cb) { + p_gmac_dev->func_wakeup_cb(); + } +#endif + } +} + +//@} + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +} +#endif +/**INDENT-ON**/ +/// @endcond diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.h new file mode 100644 index 000000000..fca3ece33 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/gmac.h @@ -0,0 +1,1346 @@ + /** + * \file + * + * \brief GMAC (Ethernet MAC) driver for SAM. + * + * Copyright (c) 2013 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef GMAC_H_INCLUDED +#define GMAC_H_INCLUDED + +#include "compiler.h" + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +extern "C" { +#endif +/**INDENT-ON**/ +/// @endcond + +/** The buffer addresses written into the descriptors must be aligned, so the + last few bits are zero. These bits have special meaning for the GMAC + peripheral and cannot be used as part of the address. */ +#define GMAC_RXD_ADDR_MASK 0xFFFFFFFC +#define GMAC_RXD_WRAP (1ul << 1) /**< Wrap bit */ +#define GMAC_RXD_OWNERSHIP (1ul << 0) /**< Ownership bit */ + +#define GMAC_RXD_BROADCAST (1ul << 31) /**< Broadcast detected */ +#define GMAC_RXD_MULTIHASH (1ul << 30) /**< Multicast hash match */ +#define GMAC_RXD_UNIHASH (1ul << 29) /**< Unicast hash match */ +#define GMAC_RXD_ADDR_FOUND (1ul << 27) /**< Specific address match found */ +#define GMAC_RXD_ADDR (3ul << 25) /**< Address match */ +#define GMAC_RXD_RXCOEN (1ul << 24) /**< RXCOEN related function */ +#define GMAC_RXD_TYPE (3ul << 22) /**< Type ID match */ +#define GMAC_RXD_VLAN (1ul << 21) /**< VLAN tag detected */ +#define GMAC_RXD_PRIORITY (1ul << 20) /**< Priority tag detected */ +#define GMAC_RXD_PRIORITY_MASK (3ul << 17) /**< VLAN priority */ +#define GMAC_RXD_CFI (1ul << 16) /**< Concatenation Format Indicator only if bit 21 is set */ +#define GMAC_RXD_EOF (1ul << 15) /**< End of frame */ +#define GMAC_RXD_SOF (1ul << 14) /**< Start of frame */ +#define GMAC_RXD_FCS (1ul << 13) /**< Frame check sequence */ +#define GMAC_RXD_OFFSET_MASK /**< Receive buffer offset */ +#define GMAC_RXD_LEN_MASK (0xFFF) /**< Length of frame including FCS (if selected) */ +#define GMAC_RXD_LENJUMBO_MASK (0x3FFF) /**< Jumbo frame length */ + +#define GMAC_TXD_USED (1ul << 31) /**< Frame is transmitted */ +#define GMAC_TXD_WRAP (1ul << 30) /**< Last descriptor */ +#define GMAC_TXD_ERROR (1ul << 29) /**< Retry limit exceeded, error */ +#define GMAC_TXD_UNDERRUN (1ul << 28) /**< Transmit underrun */ +#define GMAC_TXD_EXHAUSTED (1ul << 27) /**< Buffer exhausted */ +#define GMAC_TXD_LATE (1ul << 26) /**< Late collision,transmit error */ +#define GMAC_TXD_CHECKSUM_ERROR (7ul << 20) /**< Checksum error */ +#define GMAC_TXD_NOCRC (1ul << 16) /**< No CRC */ +#define GMAC_TXD_LAST (1ul << 15) /**< Last buffer in frame */ +#define GMAC_TXD_LEN_MASK (0x1FFF) /**< Length of buffer */ + +/** The MAC can support frame lengths up to 1536 bytes */ +#define GMAC_FRAME_LENTGH_MAX 1536 + +#define GMAC_RX_UNITSIZE 128 /**< Fixed size for RX buffer */ +#define GMAC_TX_UNITSIZE 1518 /**< Size for ETH frame length */ + +/** GMAC clock speed */ +#define GMAC_MCK_SPEED_240MHZ (240*1000*1000) +#define GMAC_MCK_SPEED_160MHZ (160*1000*1000) +#define GMAC_MCK_SPEED_120MHZ (120*1000*1000) +#define GMAC_MCK_SPEED_80MHZ (80*1000*1000) +#define GMAC_MCK_SPEED_40MHZ (40*1000*1000) +#define GMAC_MCK_SPEED_20MHZ (20*1000*1000) + +/** GMAC maintain code default value*/ +#define GMAC_MAN_CODE_VALUE (10) + +/** GMAC maintain start of frame default value*/ +#define GMAC_MAN_SOF_VALUE (1) + +/** GMAC maintain read/write*/ +#define GMAC_MAN_RW_TYPE (2) + +/** GMAC maintain read only*/ +#define GMAC_MAN_READ_ONLY (1) + +/** GMAC address length */ +#define GMAC_ADDR_LENGTH (6) + + +#define GMAC_DUPLEX_HALF 0 +#define GMAC_DUPLEX_FULL 1 + +#define GMAC_SPEED_10M 0 +#define GMAC_SPEED_100M 1 + +/** + * \brief Return codes for GMAC APIs. + */ +typedef enum { + GMAC_OK = 0, /** 0 Operation OK */ + GMAC_TIMEOUT = 1, /** 1 GMAC operation timeout */ + GMAC_TX_BUSY, /** 2 TX in progress */ + GMAC_RX_NULL, /** 3 No data received */ + GMAC_SIZE_TOO_SMALL, /** 4 Buffer size not enough */ + GMAC_PARAM, /** 5 Parameter error, TX packet invalid or RX size too small */ + GMAC_INVALID = 0xFF, /* Invalid */ +} gmac_status_t; + +/** + * \brief Media Independent Interface (MII) type. + */ +typedef enum { + GMAC_PHY_MII = 0, /** MII mode */ + GMAC_PHY_RMII = 1, /** Reduced MII mode */ + GMAC_PHY_INVALID = 0xFF, /* Invalid mode*/ +} gmac_mii_mode_t; + +/** Receive buffer descriptor struct */ +COMPILER_PACK_SET(8) +typedef struct gmac_rx_descriptor { + union gmac_rx_addr { + uint32_t val; + struct gmac_rx_addr_bm { + uint32_t b_ownership:1, /**< User clear, GMAC sets this to 1 once it has successfully written a frame to memory */ + b_wrap:1, /**< Marks last descriptor in receive buffer */ + addr_dw:30; /**< Address in number of DW */ + } bm; + } addr; /**< Address, Wrap & Ownership */ + union gmac_rx_status { + uint32_t val; + struct gmac_rx_status_bm { + uint32_t len:13, /** 0..12 Length of frame including FCS */ + b_fcs:1, /** 13 Receive buffer offset, bits 13:12 of frame length for jumbo frame */ + b_sof:1, /** 14 Start of frame */ + b_eof:1, /** 15 End of frame */ + b_cfi:1, /** 16 Concatenation Format Indicator */ + vlan_priority:3, /** 17..19 VLAN priority (if VLAN detected) */ + b_priority_detected:1, /** 20 Priority tag detected */ + b_vlan_detected:1, /** 21 VLAN tag detected */ + b_type_id_match:2, /** 22..23 Type ID match */ + b_checksumoffload:1, /** 24 Checksum offload specific function */ + b_addrmatch:2, /** 25..26 Address register match */ + b_ext_addr_match:1, /** 27 External address match found */ + reserved:1, /** 28 */ + b_uni_hash_match:1, /** 29 Unicast hash match */ + b_multi_hash_match:1, /** 30 Multicast hash match */ + b_boardcast_detect:1; /** 31 Global broadcast address detected */ + } bm; + } status; +} gmac_rx_descriptor_t; + +/** Transmit buffer descriptor struct */ +COMPILER_PACK_SET(8) +typedef struct gmac_tx_descriptor { + uint32_t addr; + union gmac_tx_status { + uint32_t val; + struct gmac_tx_status_bm { + uint32_t len:14, /** 0..13 Length of buffer */ + reserved:1, /** 14 */ + b_last_buffer:1, /** 15 Last buffer (in the current frame) */ + b_no_crc:1, /** 16 No CRC */ + reserved1:3, /** 17..19 */ + b_checksumoffload:3, /** 20..22 Transmit checksum generation offload errors */ + reserved2:3, /** 23..25 */ + b_lco:1, /** 26 Late collision, transmit error detected */ + b_exhausted:1, /** 27 Buffer exhausted in mid frame */ + b_underrun:1, /** 28 Transmit underrun */ + b_error:1, /** 29 Retry limit exceeded, error detected */ + b_wrap:1, /** 30 Marks last descriptor in TD list */ + b_used:1; /** 31 User clear, GMAC sets this to 1 once a frame has been successfully transmitted */ + } bm; + } status; +} gmac_tx_descriptor_t; + +COMPILER_PACK_RESET() + +/** + * \brief Input parameters when initializing the gmac module mode. + */ +typedef struct gmac_options { + /* Enable/Disable CopyAllFrame */ + uint8_t uc_copy_all_frame; + /* Enable/Disable NoBroadCast */ + uint8_t uc_no_boardcast; + /* MAC address */ + uint8_t uc_mac_addr[GMAC_ADDR_LENGTH]; +} gmac_options_t; + +/** RX callback */ +typedef void (*gmac_dev_tx_cb_t) (uint32_t ul_status); +/** Wakeup callback */ +typedef void (*gmac_dev_wakeup_cb_t) (void); + +/** + * GMAC driver structure. + */ +typedef struct gmac_device { + + /** Pointer to HW register base */ + Gmac *p_hw; + /** + * Pointer to allocated TX buffer. + * Section 3.6 of AMBA 2.0 spec states that burst should not cross + * 1K Boundaries. + * Receive buffer manager writes are burst of 2 words => 3 lsb bits + * of the address shall be set to 0. + */ + uint8_t *p_tx_buffer; + /** Pointer to allocated RX buffer */ + uint8_t *p_rx_buffer; + /** Pointer to Rx TDs (must be 8-byte aligned) */ + gmac_rx_descriptor_t *p_rx_dscr; + /** Pointer to Tx TDs (must be 8-byte aligned) */ + gmac_tx_descriptor_t *p_tx_dscr; + /** Optional callback to be invoked once a frame has been received */ + gmac_dev_tx_cb_t func_rx_cb; +#if( GMAC_USES_WAKEUP_CALLBACK ) + /** Optional callback to be invoked once several TDs have been released */ + gmac_dev_wakeup_cb_t func_wakeup_cb; +#endif +#if( GMAC_USES_TX_CALLBACK != 0 ) + /** Optional callback list to be invoked once TD has been processed */ + gmac_dev_tx_cb_t *func_tx_cb_list; +#endif + /** RX TD list size */ + uint32_t ul_rx_list_size; + /** RX index for current processing TD */ + uint32_t ul_rx_idx; + /** TX TD list size */ + uint32_t ul_tx_list_size; + /** Circular buffer head pointer by upper layer (buffer to be sent) */ + int32_t l_tx_head; + /** Circular buffer tail pointer incremented by handlers (buffer sent) */ + int32_t l_tx_tail; + + /** Number of free TD before wakeup callback is invoked */ + uint32_t uc_wakeup_threshold; +} gmac_device_t; + +/** + * \brief Write network control value. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_ncr Network control value. + */ +static inline void gmac_network_control(Gmac* p_gmac, uint32_t ul_ncr) +{ + p_gmac->GMAC_NCR = ul_ncr; +} + +/** + * \brief Get network control value. + * + * \param p_gmac Pointer to the GMAC instance. + */ + +static inline uint32_t gmac_get_network_control(Gmac* p_gmac) +{ + return p_gmac->GMAC_NCR; +} + +/** + * \brief Enable/Disable GMAC receive. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable GMAC receiver, else to enable it. + */ +static inline void gmac_enable_receive(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_RXEN; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_RXEN; + } +} + +/** + * \brief Enable/Disable GMAC transmit. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable GMAC transmit, else to enable it. + */ +static inline void gmac_enable_transmit(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_TXEN; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_TXEN; + } +} + +/** + * \brief Enable/Disable GMAC management. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable GMAC management, else to enable it. + */ +static inline void gmac_enable_management(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_MPE; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_MPE; + } +} + +/** + * \brief Clear all statistics registers. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_clear_statistics(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_CLRSTAT; +} + +/** + * \brief Increase all statistics registers. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_increase_statistics(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_INCSTAT; +} + +/** + * \brief Enable/Disable statistics registers writing. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the statistics registers writing, else to enable it. + */ +static inline void gmac_enable_statistics_write(Gmac* p_gmac, + uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_WESTAT; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_WESTAT; + } +} + +/** + * \brief In half-duplex mode, forces collisions on all received frames. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the back pressure, else to enable it. + */ +static inline void gmac_enable_back_pressure(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_BP; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_BP; + } +} + +/** + * \brief Start transmission. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_start_transmission(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_TSTART; +} + +/** + * \brief Halt transmission. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_halt_transmission(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_THALT; +} + +/** + * \brief Transmit pause frame. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_tx_pause_frame(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_TXPF; +} + +/** + * \brief Transmit zero quantum pause frame. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_tx_pause_zero_quantum_frame(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_TXZQPF; +} + +/** + * \brief Read snapshot. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_read_snapshot(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_RDS; +} + +/** + * \brief Store receivetime stamp to memory. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to normal operation, else to enable the store. + */ +static inline void gmac_store_rx_time_stamp(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_SRTSM; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_SRTSM; + } +} + +/** + * \brief Enable PFC priority-based pause reception. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 1 to set the reception, 0 to disable. + */ +static inline void gmac_enable_pfc_pause_frame(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_ENPBPR; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_ENPBPR; + } +} + +/** + * \brief Transmit PFC priority-based pause reception. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_transmit_pfc_pause_frame(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_TXPBPF; +} + +/** + * \brief Flush next packet. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_flush_next_packet(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_FNP; +} + +/** + * \brief Set up network configuration register. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_cfg Network configuration value. + */ +static inline void gmac_set_configure(Gmac* p_gmac, uint32_t ul_cfg) +{ + p_gmac->GMAC_NCFGR = ul_cfg; +} + +/** + * \brief Get network configuration. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Network configuration. + */ +static inline uint32_t gmac_get_configure(Gmac* p_gmac) +{ + return p_gmac->GMAC_NCFGR; +} + + +/* Get and set DMA Configuration Register */ +static inline void gmac_set_dma(Gmac* p_gmac, uint32_t ul_cfg) +{ + p_gmac->GMAC_DCFGR = ul_cfg; +} + +static inline uint32_t gmac_get_dma(Gmac* p_gmac) +{ + return p_gmac->GMAC_DCFGR; +} + +/** + * \brief Set speed. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_speed 1 to indicate 100Mbps, 0 to 10Mbps. + */ +static inline void gmac_set_speed(Gmac* p_gmac, uint8_t uc_speed) +{ + if (uc_speed) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_SPD; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_SPD; + } +} + +/** + * \brief Enable/Disable Full-Duplex mode. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the Full-Duplex mode, else to enable it. + */ +static inline void gmac_enable_full_duplex(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_FD; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_FD; + } +} + +/** + * \brief Enable/Disable Copy(Receive) All Valid Frames. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable copying all valid frames, else to enable it. + */ +static inline void gmac_enable_copy_all(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_CAF; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_CAF; + } +} + +/** + * \brief Enable/Disable jumbo frames (up to 10240 bytes). + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the jumbo frames, else to enable it. + */ +static inline void gmac_enable_jumbo_frames(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_JFRAME; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_JFRAME; + } +} + +/** + * \brief Disable/Enable broadcast receiving. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 1 to disable the broadcast, else to enable it. + */ +static inline void gmac_disable_broadcast(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_NBC; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_NBC; + } +} + +/** + * \brief Enable/Disable multicast hash. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the multicast hash, else to enable it. + */ +static inline void gmac_enable_multicast_hash(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_UNIHEN; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_UNIHEN; + } +} + +/** + * \brief Enable/Disable big frames (over 1518, up to 1536). + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable big frames else to enable it. + */ +static inline void gmac_enable_big_frame(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_MAXFS; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_MAXFS; + } +} + +/** + * \brief Set MDC clock divider. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_mck GMAC MCK. + * + * \return GMAC_OK if successfully. + */ +static inline uint8_t gmac_set_mdc_clock(Gmac* p_gmac, uint32_t ul_mck) +{ + uint32_t ul_clk; + + if (ul_mck > GMAC_MCK_SPEED_240MHZ) { + return GMAC_INVALID; + } else if (ul_mck > GMAC_MCK_SPEED_160MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_96; + } else if (ul_mck > GMAC_MCK_SPEED_120MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_64; + } else if (ul_mck > GMAC_MCK_SPEED_80MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_48; + } else if (ul_mck > GMAC_MCK_SPEED_40MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_32; + } else if (ul_mck > GMAC_MCK_SPEED_20MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_16; + } else { + ul_clk = GMAC_NCFGR_CLK_MCK_8; + } + ; + p_gmac->GMAC_NCFGR = (p_gmac->GMAC_NCFGR & ~GMAC_NCFGR_CLK_Msk) | ul_clk; + return GMAC_OK; +} + +/** + * \brief Enable/Disable retry test. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the GMAC receiver, else to enable it. + */ +static inline void gmac_enable_retry_test(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RTY; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RTY; + } +} + +/** + * \brief Enable/Disable pause (when a valid pause frame is received). + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable pause frame, else to enable it. + */ +static inline void gmac_enable_pause_frame(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_PEN; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_PEN; + } +} + +/** + * \brief Set receive buffer offset to 0 ~ 3. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_set_rx_buffer_offset(Gmac* p_gmac, uint8_t uc_offset) +{ + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RXBUFO_Msk; + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RXBUFO(uc_offset); +} + +/** + * \brief Enable/Disable receive length field checking. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable receive length field checking, else to enable it. + */ +static inline void gmac_enable_rx_length_check(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_LFERD; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_LFERD; + } +} + +/** + * \brief Enable/Disable discarding FCS field of received frames. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable discarding FCS field of received frames, else to enable it. + */ +static inline void gmac_enable_discard_fcs(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RFCS; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RFCS; + } +} + + +/** + * \brief Enable/Disable frames to be received in half-duplex mode + * while transmitting. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the received in half-duplex mode, else to enable it. + */ +static inline void gmac_enable_efrhd(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_EFRHD; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_EFRHD; + } +} + +/** + * \brief Enable/Disable ignore RX FCS. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable ignore RX FCS, else to enable it. + */ +static inline void gmac_enable_ignore_rx_fcs(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_IRXFCS; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_IRXFCS; + } +} + +/** + * \brief Get Network Status. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Network status. + */ +static inline uint32_t gmac_get_status(Gmac* p_gmac) +{ + return p_gmac->GMAC_NSR; +} + +/** + * \brief Get MDIO IN pin status. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return MDIO IN pin status. + */ +static inline uint8_t gmac_get_MDIO(Gmac* p_gmac) +{ + return ((p_gmac->GMAC_NSR & GMAC_NSR_MDIO) > 0); +} + +/** + * \brief Check if PHY is idle. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return 1 if PHY is idle. + */ +static inline uint8_t gmac_is_phy_idle(Gmac* p_gmac) +{ + return ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) > 0); +} + +/** + * \brief Return transmit status. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Transmit status. + */ +static inline uint32_t gmac_get_tx_status(Gmac* p_gmac) +{ + return p_gmac->GMAC_TSR; +} + +/** + * \brief Clear transmit status. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_status Transmit status. + */ +static inline void gmac_clear_tx_status(Gmac* p_gmac, uint32_t ul_status) +{ + p_gmac->GMAC_TSR = ul_status; +} + +/** + * \brief Return receive status. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline uint32_t gmac_get_rx_status(Gmac* p_gmac) +{ + return p_gmac->GMAC_RSR; +} + +/** + * \brief Clear receive status. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_status Receive status. + */ +static inline void gmac_clear_rx_status(Gmac* p_gmac, uint32_t ul_status) +{ + p_gmac->GMAC_RSR = ul_status; +} + +/** + * \brief Set Rx Queue. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_addr Rx queue address. + */ +static inline void gmac_set_rx_queue(Gmac* p_gmac, uint32_t ul_addr) +{ + p_gmac->GMAC_RBQB = GMAC_RBQB_ADDR_Msk & ul_addr; +} + +/** + * \brief Get Rx Queue Address. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Rx queue address. + */ +static inline uint32_t gmac_get_rx_queue(Gmac* p_gmac) +{ + return p_gmac->GMAC_RBQB; +} + +/** + * \brief Set Tx Queue. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_addr Tx queue address. + */ +static inline void gmac_set_tx_queue(Gmac* p_gmac, uint32_t ul_addr) +{ + p_gmac->GMAC_TBQB = GMAC_TBQB_ADDR_Msk & ul_addr; +} + +/** + * \brief Get Tx Queue. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Rx queue address. + */ +static inline uint32_t gmac_get_tx_queue(Gmac* p_gmac) +{ + return p_gmac->GMAC_TBQB; +} + +/** + * \brief Enable interrupt(s). + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_source Interrupt source(s) to be enabled. + */ +static inline void gmac_enable_interrupt(Gmac* p_gmac, uint32_t ul_source) +{ + p_gmac->GMAC_IER = ul_source; +} + +/** + * \brief Disable interrupt(s). + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_source Interrupt source(s) to be disabled. + */ +static inline void gmac_disable_interrupt(Gmac* p_gmac, uint32_t ul_source) +{ + p_gmac->GMAC_IDR = ul_source; +} + +/** + * \brief Return interrupt status. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Interrupt status. + */ +static inline uint32_t gmac_get_interrupt_status(Gmac* p_gmac) +{ + return p_gmac->GMAC_ISR; +} + +/** + * \brief Return interrupt mask. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Interrupt mask. + */ +static inline uint32_t gmac_get_interrupt_mask(Gmac* p_gmac) +{ + return p_gmac->GMAC_IMR; +} + +/** + * \brief Execute PHY maintenance command. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_phy_addr PHY address. + * \param uc_reg_addr Register address. + * \param uc_rw 1 to Read, 0 to write. + * \param us_data Data to be performed, write only. + */ +static inline void gmac_maintain_phy(Gmac* p_gmac, + uint8_t uc_phy_addr, uint8_t uc_reg_addr, uint8_t uc_rw, + uint16_t us_data) +{ + /* Wait until bus idle */ + while ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) == 0); + /* Write maintain register */ + p_gmac->GMAC_MAN = GMAC_MAN_WTN(GMAC_MAN_CODE_VALUE) + | GMAC_MAN_CLTTO + | GMAC_MAN_PHYA(uc_phy_addr) + | GMAC_MAN_REGA(uc_reg_addr) + | GMAC_MAN_OP((uc_rw ? GMAC_MAN_RW_TYPE : GMAC_MAN_READ_ONLY)) + | GMAC_MAN_DATA(us_data); +} + +/** + * \brief Get PHY maintenance data returned. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Get PHY data. + */ +static inline uint16_t gmac_get_phy_data(Gmac* p_gmac) +{ + /* Wait until bus idle */ + while ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) == 0); + /* Return data */ + return (uint16_t) (p_gmac->GMAC_MAN & GMAC_MAN_DATA_Msk); +} + +/** + * \brief Set Hash. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_hash_top Hash top. + * \param ul_hash_bottom Hash bottom. + */ +static inline void gmac_set_hash(Gmac* p_gmac, uint32_t ul_hash_top, + uint32_t ul_hash_bottom) +{ + p_gmac->GMAC_HRB = ul_hash_bottom; + p_gmac->GMAC_HRT = ul_hash_top; +} + +/** + * \brief Set 64 bits Hash. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ull_hash 64 bits hash value. + */ +static inline void gmac_set_hash64(Gmac* p_gmac, uint64_t ull_hash) +{ + p_gmac->GMAC_HRB = (uint32_t) ull_hash; + p_gmac->GMAC_HRT = (uint32_t) (ull_hash >> 32); +} + +/** + * \brief Set MAC Address. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_index GMAC specific address register index. + * \param p_mac_addr GMAC address. + */ +static inline void gmac_set_address(Gmac* p_gmac, uint8_t uc_index, + uint8_t* p_mac_addr) +{ + p_gmac->GMAC_SA[uc_index].GMAC_SAB = (p_mac_addr[3] << 24) + | (p_mac_addr[2] << 16) + | (p_mac_addr[1] << 8) + | (p_mac_addr[0]); + p_gmac->GMAC_SA[uc_index].GMAC_SAT = (p_mac_addr[5] << 8) + | (p_mac_addr[4]); +} + +/** + * \brief Set MAC Address via 2 dword. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_index GMAC specific address register index. + * \param ul_mac_top GMAC top address. + * \param ul_mac_bottom GMAC bottom address. + */ +static inline void gmac_set_address32(Gmac* p_gmac, uint8_t uc_index, + uint32_t ul_mac_top, uint32_t ul_mac_bottom) +{ + p_gmac->GMAC_SA[uc_index].GMAC_SAB = ul_mac_bottom; + p_gmac->GMAC_SA[uc_index].GMAC_SAT = ul_mac_top; +} + +/** + * \brief Set MAC Address via int64. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_index GMAC specific address register index. + * \param ull_mac 64-bit GMAC address. + */ +static inline void gmac_set_address64(Gmac* p_gmac, uint8_t uc_index, + uint64_t ull_mac) +{ + p_gmac->GMAC_SA[uc_index].GMAC_SAB = (uint32_t) ull_mac; + p_gmac->GMAC_SA[uc_index].GMAC_SAT = (uint32_t) (ull_mac >> 32); +} + +/** + * \brief Select media independent interface mode. + * + * \param p_gmac Pointer to the GMAC instance. + * \param mode Media independent interface mode. + */ +static inline void gmac_select_mii_mode(Gmac* p_gmac, gmac_mii_mode_t mode) +{ + switch (mode) { + case GMAC_PHY_MII: + case GMAC_PHY_RMII: + p_gmac->GMAC_UR |= GMAC_UR_RMIIMII; + break; + + default: + p_gmac->GMAC_UR &= ~GMAC_UR_RMIIMII; + break; + } +} + +uint8_t gmac_phy_read(Gmac* p_gmac, uint8_t uc_phy_address, uint8_t uc_address, + uint32_t* p_value); +uint8_t gmac_phy_write(Gmac* p_gmac, uint8_t uc_phy_address, + uint8_t uc_address, uint32_t ul_value); +void gmac_dev_init(Gmac* p_gmac, gmac_device_t* p_gmac_dev, + gmac_options_t* p_opt); +uint32_t gmac_dev_read(gmac_device_t* p_gmac_dev, uint8_t* p_frame, + uint32_t ul_frame_size, uint32_t* p_rcv_size); +uint32_t gmac_dev_write(gmac_device_t* p_gmac_dev, void *p_buffer, + uint32_t ul_size, gmac_dev_tx_cb_t func_tx_cb); +uint32_t gmac_dev_get_tx_load(gmac_device_t* p_gmac_dev); +void gmac_dev_set_rx_callback(gmac_device_t* p_gmac_dev, + gmac_dev_tx_cb_t func_rx_cb); +uint8_t gmac_dev_set_tx_wakeup_callback(gmac_device_t* p_gmac_dev, + gmac_dev_wakeup_cb_t func_wakeup, uint8_t uc_threshold); +void gmac_dev_reset(gmac_device_t* p_gmac_dev); +void gmac_handler(gmac_device_t* p_gmac_dev); + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +} +#endif +/**INDENT-ON**/ +/// @endcond + +/** + * \page gmac_quickstart Quickstart guide for GMAC driver. + * + * This is the quickstart guide for the \ref gmac_group "Ethernet MAC", + * with step-by-step instructions on how to configure and use the driver in a + * selection of use cases. + * + * The use cases contain several code fragments. The code fragments in the + * steps for setup can be copied into a custom initialization function, while + * the steps for usage can be copied into, e.g., the main application function. + * + * \section gmac_basic_use_case Basic use case + * In the basic use case, the GMAC driver are configured for: + * - PHY component KSZ8051MNL is used + * - GMAC uses MII mode + * - The number of receive buffer is 16 + * - The number of transfer buffer is 8 + * - MAC address is set to 00-04-25-1c-a0-02 + * - IP address is set to 192.168.0.2 + * - IP address is set to 192.168.0.2 + * - Gateway is set to 192.168.0.1 + * - Network mask is 255.255.255.0 + * - PHY operation max retry count is 1000000 + * - GMAC is configured to not support copy all frame and support broadcast + * - The data will be read from the ethernet + * + * \section gmac_basic_use_case_setup Setup steps + * + * \subsection gmac_basic_use_case_setup_prereq Prerequisites + * -# \ref sysclk_group "System Clock Management (sysclock)" + * -# \ref pmc_group "Power Management Controller (pmc)" + * -# \ref ksz8051mnl_ethernet_phy_group "PHY component (KSZ8051MNL)" + * + * \subsection gmac_basic_use_case_setup_code Example code + * Content of conf_eth.h + * \code + * #define GMAC_RX_BUFFERS 16 + * #define GMAC_TX_BUFFERS 8 + * #define MAC_PHY_RETRY_MAX 1000000 + * #define ETHERNET_CONF_ETHADDR0 0x00 + * #define ETHERNET_CONF_ETHADDR0 0x00 + * #define ETHERNET_CONF_ETHADDR1 0x04 + * #define ETHERNET_CONF_ETHADDR2 0x25 + * #define ETHERNET_CONF_ETHADDR3 0x1C + * #define ETHERNET_CONF_ETHADDR4 0xA0 + * #define ETHERNET_CONF_ETHADDR5 0x02 + * #define ETHERNET_CONF_IPADDR0 192 + * #define ETHERNET_CONF_IPADDR1 168 + * #define ETHERNET_CONF_IPADDR2 0 + * #define ETHERNET_CONF_IPADDR3 2 + * #define ETHERNET_CONF_GATEWAY_ADDR0 192 + * #define ETHERNET_CONF_GATEWAY_ADDR1 168 + * #define ETHERNET_CONF_GATEWAY_ADDR2 0 + * #define ETHERNET_CONF_GATEWAY_ADDR3 1 + * #define ETHERNET_CONF_NET_MASK0 255 + * #define ETHERNET_CONF_NET_MASK1 255 + * #define ETHERNET_CONF_NET_MASK2 255 + * #define ETHERNET_CONF_NET_MASK3 0 + * #define ETH_PHY_MODE ETH_PHY_MODE + * \endcode + * + * A specific gmac device and the receive data buffer must be defined; another ul_frm_size should be defined + * to trace the actual size of the data received. + * \code + * static gmac_device_t gs_gmac_dev; + * static volatile uint8_t gs_uc_eth_buffer[GMAC_FRAME_LENTGH_MAX]; + * + * uint32_t ul_frm_size; + * \endcode + * + * Add to application C-file: + * \code + * void gmac_init(void) + * { + * sysclk_init(); + * + * board_init(); + * + * pmc_enable_periph_clk(ID_GMAC); + * + * gmac_option.uc_copy_all_frame = 0; + * gmac_option.uc_no_boardcast = 0; + * memcpy(gmac_option.uc_mac_addr, gs_uc_mac_address, sizeof(gs_uc_mac_address)); + * gs_gmac_dev.p_hw = GMAC; + * + * gmac_dev_init(GMAC, &gs_gmac_dev, &gmac_option); + * + * NVIC_EnableIRQ(GMAC_IRQn); + * + * ethernet_phy_init(GMAC, BOARD_GMAC_PHY_ADDR, sysclk_get_cpu_hz()); + * + * ethernet_phy_auto_negotiate(GMAC, BOARD_GMAC_PHY_ADDR); + * + * ethernet_phy_set_link(GMAC, BOARD_GMAC_PHY_ADDR, 1); + * \endcode + * + * \subsection gmac_basic_use_case_setup_flow Workflow + * - Ensure that conf_eth.h is present and contains the + * following configuration symbol. This configuration file is used + * by the driver and should not be included by the application. + * -# Define the receiving buffer size used in the internal GMAC driver. + * The buffer size used for RX is GMAC_RX_BUFFERS * 128. + * If it was supposed receiving a large number of frame, the + * GMAC_RX_BUFFERS should be set higher. E.g., the application wants to accept + * a ping echo test of 2048, the GMAC_RX_BUFFERS should be set at least + * (2048/128)=16, and as there are additional frames coming, a preferred + * number is 24 depending on a normal Ethernet throughput. + * - \code + * #define GMAC_RX_BUFFERS 16 + * \endcode + * -# Define the transmitting buffer size used in the internal GMAC driver. + * The buffer size used for TX is GMAC_TX_BUFFERS * 1518. + * - \code + * #define GMAC_TX_BUFFERS 8 + * \endcode + * -# Define maximum retry time for a PHY read/write operation. + * - \code + * #define MAC_PHY_RETRY_MAX 1000000 + * \endcode + * -# Define the MAC address. 00:04:25:1C:A0:02 is the address reserved + * for ATMEL, application should always change this address to its' own. + * - \code + * #define ETHERNET_CONF_ETHADDR0 0x00 + * #define ETHERNET_CONF_ETHADDR1 0x04 + * #define ETHERNET_CONF_ETHADDR2 0x25 + * #define ETHERNET_CONF_ETHADDR3 0x1C + * #define ETHERNET_CONF_ETHADDR4 0xA0 + * #define ETHERNET_CONF_ETHADDR5 0x02 + * \endcode + * -# Define the IP address configration used in the application. When DHCP + * is enabled, this configuration is not effected. + * - \code + * #define ETHERNET_CONF_IPADDR0 192 + * #define ETHERNET_CONF_IPADDR1 168 + * #define ETHERNET_CONF_IPADDR2 0 + * #define ETHERNET_CONF_IPADDR3 2 + * #define ETHERNET_CONF_GATEWAY_ADDR0 192 + * #define ETHERNET_CONF_GATEWAY_ADDR1 168 + * #define ETHERNET_CONF_GATEWAY_ADDR2 0 + * #define ETHERNET_CONF_GATEWAY_ADDR3 1 + * #define ETHERNET_CONF_NET_MASK0 255 + * #define ETHERNET_CONF_NET_MASK1 255 + * #define ETHERNET_CONF_NET_MASK2 255 + * #define ETHERNET_CONF_NET_MASK3 0 + * \endcode + * -# Configure the PHY maintainance interface. + * - \code + * #define ETH_PHY_MODE GMAC_PHY_MII + * \endcode + * -# Enable the system clock: + * - \code sysclk_init(); \endcode + * -# Enable PIO configurations for GMAC: + * - \code board_init(); \endcode + * -# Enable PMC clock for GMAC: + * - \code pmc_enable_periph_clk(ID_GMAC); \endcode + * -# Set the GMAC options; it's set to copy all frame and support broadcast: + * - \code + * gmac_option.uc_copy_all_frame = 0; + * gmac_option.uc_no_boardcast = 0; + * memcpy(gmac_option.uc_mac_addr, gs_uc_mac_address, sizeof(gs_uc_mac_address)); + * gs_gmac_dev.p_hw = GMAC; + * \endcode + * -# Initialize GMAC device with the filled option: + * - \code + * gmac_dev_init(GMAC, &gs_gmac_dev, &gmac_option); + * \endcode + * -# Enable the interrupt service for GMAC: + * - \code + * NVIC_EnableIRQ(GMAC_IRQn); + * \endcode + * -# Initialize the PHY component: + * - \code + * ethernet_phy_init(GMAC, BOARD_GMAC_PHY_ADDR, sysclk_get_cpu_hz()); + * \endcode + * -# The link will be established based on auto negotiation. + * - \code + * ethernet_phy_auto_negotiate(GMAC, BOARD_GMAC_PHY_ADDR); + * \endcode + * -# Establish the ethernet link; the network can be worked from now on: + * - \code + * ethernet_phy_set_link(GMAC, BOARD_GMAC_PHY_ADDR, 1); + * \endcode + * + * \section gmac_basic_use_case_usage Usage steps + * \subsection gmac_basic_use_case_usage_code Example code + * Add to, e.g., main loop in application C-file: + * \code + * gmac_dev_read(&gs_gmac_dev, (uint8_t *) gs_uc_eth_buffer, sizeof(gs_uc_eth_buffer), &ul_frm_size)); + * \endcode + * + * \subsection gmac_basic_use_case_usage_flow Workflow + * -# Start reading the data from the ethernet: + * - \code gmac_dev_read(&gs_gmac_dev, (uint8_t *) gs_uc_eth_buffer, sizeof(gs_uc_eth_buffer), &ul_frm_size)); \endcode + */ + +# define GMAC_STATS 0 + +#if( GMAC_STATS != 0 ) + + /* Here below some code to study the types and + frequencies of GMAC interrupts. */ + #define GMAC_IDX_RXUBR 0 + #define GMAC_IDX_TUR 1 + #define GMAC_IDX_RLEX 2 + #define GMAC_IDX_TFC 3 + #define GMAC_IDX_RCOMP 4 + #define GMAC_IDX_TCOMP 5 + #define GMAC_IDX_ROVR 6 + #define GMAC_IDX_HRESP 7 + #define GMAC_IDX_PFNZ 8 + #define GMAC_IDX_PTZ 9 + + struct SGmacStats { + unsigned recvCount; + unsigned rovrCount; + unsigned bnaCount; + unsigned sendCount; + unsigned sovrCount; + unsigned incompCount; + unsigned truncCount; + + unsigned intStatus[10]; + }; + extern struct SGmacStats gmacStats; + + struct SIntPair { + const char *name; + unsigned mask; + int index; + }; + + #define MK_PAIR( NAME ) #NAME, GMAC_IER_##NAME, GMAC_IDX_##NAME + static const struct SIntPair intPairs[] = { + { MK_PAIR( RXUBR ) }, /* Enable receive used bit read interrupt. */ + { MK_PAIR( TUR ) }, /* Enable transmit underrun interrupt. */ + { MK_PAIR( RLEX ) }, /* Enable retry limit exceeded interrupt. */ + { MK_PAIR( TFC ) }, /* Enable transmit buffers exhausted in mid-frame interrupt. */ + { MK_PAIR( RCOMP ) }, /* Receive complete */ + { MK_PAIR( TCOMP ) }, /* Enable transmit complete interrupt. */ + { MK_PAIR( ROVR ) }, /* Enable receive overrun interrupt. */ + { MK_PAIR( HRESP ) }, /* Enable Hresp not OK interrupt. */ + { MK_PAIR( PFNZ ) }, /* Enable pause frame received interrupt. */ + { MK_PAIR( PTZ ) } /* Enable pause time zero interrupt. */ + }; + + void gmac_show_irq_counts (); + +#endif + +#endif /* GMAC_H_INCLUDED */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/instance/gmac.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/instance/gmac.h new file mode 100644 index 000000000..24d806d94 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ATSAM4E/instance/gmac.h @@ -0,0 +1,1349 @@ + /** + * \file + * + * \brief GMAC (Ethernet MAC) driver for SAM. + * + * Copyright (c) 2013 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef GMAC_H_INCLUDED +#define GMAC_H_INCLUDED + +#include "compiler.h" +#include "component/gmac.h" + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +extern "C" { +#endif +/**INDENT-ON**/ +/// @endcond + +/** The buffer addresses written into the descriptors must be aligned, so the + last few bits are zero. These bits have special meaning for the GMAC + peripheral and cannot be used as part of the address. */ +#define GMAC_RXD_ADDR_MASK 0xFFFFFFFC +#define GMAC_RXD_WRAP (1ul << 1) /**< Wrap bit */ +#define GMAC_RXD_OWNERSHIP (1ul << 0) /**< Ownership bit */ + +#define GMAC_RXD_BROADCAST (1ul << 31) /**< Broadcast detected */ +#define GMAC_RXD_MULTIHASH (1ul << 30) /**< Multicast hash match */ +#define GMAC_RXD_UNIHASH (1ul << 29) /**< Unicast hash match */ +#define GMAC_RXD_ADDR_FOUND (1ul << 27) /**< Specific address match found */ +#define GMAC_RXD_ADDR (3ul << 25) /**< Address match */ +#define GMAC_RXD_RXCOEN (1ul << 24) /**< RXCOEN related function */ +#define GMAC_RXD_TYPE (3ul << 22) /**< Type ID match */ +#define GMAC_RXD_VLAN (1ul << 21) /**< VLAN tag detected */ +#define GMAC_RXD_PRIORITY (1ul << 20) /**< Priority tag detected */ +#define GMAC_RXD_PRIORITY_MASK (3ul << 17) /**< VLAN priority */ +#define GMAC_RXD_CFI (1ul << 16) /**< Concatenation Format Indicator only if bit 21 is set */ +#define GMAC_RXD_EOF (1ul << 15) /**< End of frame */ +#define GMAC_RXD_SOF (1ul << 14) /**< Start of frame */ +#define GMAC_RXD_FCS (1ul << 13) /**< Frame check sequence */ +#define GMAC_RXD_OFFSET_MASK /**< Receive buffer offset */ +#define GMAC_RXD_LEN_MASK (0xFFF) /**< Length of frame including FCS (if selected) */ +#define GMAC_RXD_LENJUMBO_MASK (0x3FFF) /**< Jumbo frame length */ + +#define GMAC_TXD_USED (1ul << 31) /**< Frame is transmitted */ +#define GMAC_TXD_WRAP (1ul << 30) /**< Last descriptor */ +#define GMAC_TXD_ERROR (1ul << 29) /**< Retry limit exceeded, error */ +#define GMAC_TXD_UNDERRUN (1ul << 28) /**< Transmit underrun */ +#define GMAC_TXD_EXHAUSTED (1ul << 27) /**< Buffer exhausted */ +#define GMAC_TXD_LATE (1ul << 26) /**< Late collision,transmit error */ +#define GMAC_TXD_CHECKSUM_ERROR (7ul << 20) /**< Checksum error */ +#define GMAC_TXD_NOCRC (1ul << 16) /**< No CRC */ +#define GMAC_TXD_LAST (1ul << 15) /**< Last buffer in frame */ +#define GMAC_TXD_LEN_MASK (0x1FFF) /**< Length of buffer */ + +/** The MAC can support frame lengths up to 1536 bytes */ +#define GMAC_FRAME_LENTGH_MAX 1536 + +#define GMAC_RX_UNITSIZE 128 /**< Fixed size for RX buffer */ +#define GMAC_TX_UNITSIZE 1518 /**< Size for ETH frame length */ + +/** GMAC clock speed */ +#define GMAC_MCK_SPEED_240MHZ (240*1000*1000) +#define GMAC_MCK_SPEED_160MHZ (160*1000*1000) +#define GMAC_MCK_SPEED_120MHZ (120*1000*1000) +#define GMAC_MCK_SPEED_80MHZ (80*1000*1000) +#define GMAC_MCK_SPEED_40MHZ (40*1000*1000) +#define GMAC_MCK_SPEED_20MHZ (20*1000*1000) + +/** GMAC maintain code default value*/ +#define GMAC_MAN_CODE_VALUE (10) + +/** GMAC maintain start of frame default value*/ +#define GMAC_MAN_SOF_VALUE (1) + +/** GMAC maintain read/write*/ +#define GMAC_MAN_RW_TYPE (2) + +/** GMAC maintain read only*/ +#define GMAC_MAN_READ_ONLY (1) + +/** GMAC address length */ +#define GMAC_ADDR_LENGTH (6) + + +#define GMAC_DUPLEX_HALF 0 +#define GMAC_DUPLEX_FULL 1 + +#define GMAC_SPEED_10M 0 +#define GMAC_SPEED_100M 1 + +/** + * \brief Return codes for GMAC APIs. + */ +typedef enum { + GMAC_OK = 0, /** 0 Operation OK */ + GMAC_TIMEOUT = 1, /** 1 GMAC operation timeout */ + GMAC_TX_BUSY, /** 2 TX in progress */ + GMAC_RX_NULL, /** 3 No data received */ + GMAC_SIZE_TOO_SMALL, /** 4 Buffer size not enough */ + GMAC_PARAM, /** 5 Parameter error, TX packet invalid or RX size too small */ + GMAC_INVALID = 0xFF, /* Invalid */ +} gmac_status_t; + +/** + * \brief Media Independent Interface (MII) type. + */ +typedef enum { + GMAC_PHY_MII = 0, /** MII mode */ + GMAC_PHY_RMII = 1, /** Reduced MII mode */ + GMAC_PHY_INVALID = 0xFF, /* Invalid mode*/ +} gmac_mii_mode_t; + +/** Receive buffer descriptor struct */ +COMPILER_PACK_SET(8) +typedef struct gmac_rx_descriptor { + union gmac_rx_addr { + uint32_t val; + struct gmac_rx_addr_bm { + uint32_t b_ownership:1, /**< User clear, GMAC sets this to 1 once it has successfully written a frame to memory */ + b_wrap:1, /**< Marks last descriptor in receive buffer */ + addr_dw:30; /**< Address in number of DW */ + } bm; + } addr; /**< Address, Wrap & Ownership */ + union gmac_rx_status { + uint32_t val; + struct gmac_rx_status_bm { + uint32_t len:13, /** 0..12 Length of frame including FCS */ + b_fcs:1, /** 13 Receive buffer offset, bits 13:12 of frame length for jumbo frame */ + b_sof:1, /** 14 Start of frame */ + b_eof:1, /** 15 End of frame */ + b_cfi:1, /** 16 Concatenation Format Indicator */ + vlan_priority:3, /** 17..19 VLAN priority (if VLAN detected) */ + b_priority_detected:1, /** 20 Priority tag detected */ + b_vlan_detected:1, /** 21 VLAN tag detected */ + b_type_id_match:2, /** 22..23 Type ID match */ + b_checksumoffload:1, /** 24 Checksum offload specific function */ + b_addrmatch:2, /** 25..26 Address register match */ + b_ext_addr_match:1, /** 27 External address match found */ + reserved:1, /** 28 */ + b_uni_hash_match:1, /** 29 Unicast hash match */ + b_multi_hash_match:1, /** 30 Multicast hash match */ + b_boardcast_detect:1; /** 31 Global broadcast address detected */ + } bm; + } status; +} gmac_rx_descriptor_t; + +/** Transmit buffer descriptor struct */ +COMPILER_PACK_SET(8) +typedef struct gmac_tx_descriptor { + uint32_t addr; + union gmac_tx_status { + uint32_t val; + struct gmac_tx_status_bm { + uint32_t len:14, /** 0..13 Length of buffer */ + reserved:1, /** 14 */ + b_last_buffer:1, /** 15 Last buffer (in the current frame) */ + b_no_crc:1, /** 16 No CRC */ + reserved1:3, /** 17..19 */ + b_checksumoffload:3, /** 20..22 Transmit checksum generation offload errors */ + reserved2:3, /** 23..25 */ + b_lco:1, /** 26 Late collision, transmit error detected */ + b_exhausted:1, /** 27 Buffer exhausted in mid frame */ + b_underrun:1, /** 28 Transmit underrun */ + b_error:1, /** 29 Retry limit exceeded, error detected */ + b_wrap:1, /** 30 Marks last descriptor in TD list */ + b_used:1; /** 31 User clear, GMAC sets this to 1 once a frame has been successfully transmitted */ + } bm; + } status; +} gmac_tx_descriptor_t; + +COMPILER_PACK_RESET() + +/** + * \brief Input parameters when initializing the gmac module mode. + */ +typedef struct gmac_options { + /* Enable/Disable CopyAllFrame */ + uint8_t uc_copy_all_frame; + /* Enable/Disable NoBroadCast */ + uint8_t uc_no_boardcast; + /* MAC address */ + uint8_t uc_mac_addr[GMAC_ADDR_LENGTH]; +} gmac_options_t; + +/** TX callback */ +typedef void (*gmac_dev_tx_cb_t) (uint32_t ul_status, uint8_t *puc_buffer); +/** RX callback */ +typedef void (*gmac_dev_rx_cb_t) (uint32_t ul_status); +/** Wakeup callback */ +typedef void (*gmac_dev_wakeup_cb_t) (void); + +/** + * GMAC driver structure. + */ +typedef struct gmac_device { + + /** Pointer to HW register base */ + Gmac *p_hw; + /** + * Pointer to allocated TX buffer. + * Section 3.6 of AMBA 2.0 spec states that burst should not cross + * 1K Boundaries. + * Receive buffer manager writes are burst of 2 words => 3 lsb bits + * of the address shall be set to 0. + */ + uint8_t *p_tx_buffer; + /** Pointer to allocated RX buffer */ + uint8_t *p_rx_buffer; + /** Pointer to Rx TDs (must be 8-byte aligned) */ + gmac_rx_descriptor_t *p_rx_dscr; + /** Pointer to Tx TDs (must be 8-byte aligned) */ + gmac_tx_descriptor_t *p_tx_dscr; + /** Optional callback to be invoked once a frame has been received */ + gmac_dev_rx_cb_t func_rx_cb; +#if( GMAC_USES_WAKEUP_CALLBACK ) + /** Optional callback to be invoked once several TDs have been released */ + gmac_dev_wakeup_cb_t func_wakeup_cb; +#endif +#if( GMAC_USES_TX_CALLBACK != 0 ) + /** Optional callback list to be invoked once TD has been processed */ + gmac_dev_tx_cb_t *func_tx_cb_list; +#endif + /** RX TD list size */ + uint32_t ul_rx_list_size; + /** RX index for current processing TD */ + uint32_t ul_rx_idx; + /** TX TD list size */ + uint32_t ul_tx_list_size; + /** Circular buffer head pointer by upper layer (buffer to be sent) */ + int32_t l_tx_head; + /** Circular buffer tail pointer incremented by handlers (buffer sent) */ + int32_t l_tx_tail; + + /** Number of free TD before wakeup callback is invoked */ + uint32_t uc_wakeup_threshold; +} gmac_device_t; + +/** + * \brief Write network control value. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_ncr Network control value. + */ +static inline void gmac_network_control(Gmac* p_gmac, uint32_t ul_ncr) +{ + p_gmac->GMAC_NCR = ul_ncr; +} + +/** + * \brief Get network control value. + * + * \param p_gmac Pointer to the GMAC instance. + */ + +static inline uint32_t gmac_get_network_control(Gmac* p_gmac) +{ + return p_gmac->GMAC_NCR; +} + +/** + * \brief Enable/Disable GMAC receive. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable GMAC receiver, else to enable it. + */ +static inline void gmac_enable_receive(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_RXEN; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_RXEN; + } +} + +/** + * \brief Enable/Disable GMAC transmit. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable GMAC transmit, else to enable it. + */ +static inline void gmac_enable_transmit(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_TXEN; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_TXEN; + } +} + +/** + * \brief Enable/Disable GMAC management. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable GMAC management, else to enable it. + */ +static inline void gmac_enable_management(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_MPE; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_MPE; + } +} + +/** + * \brief Clear all statistics registers. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_clear_statistics(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_CLRSTAT; +} + +/** + * \brief Increase all statistics registers. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_increase_statistics(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_INCSTAT; +} + +/** + * \brief Enable/Disable statistics registers writing. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the statistics registers writing, else to enable it. + */ +static inline void gmac_enable_statistics_write(Gmac* p_gmac, + uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_WESTAT; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_WESTAT; + } +} + +/** + * \brief In half-duplex mode, forces collisions on all received frames. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the back pressure, else to enable it. + */ +static inline void gmac_enable_back_pressure(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_BP; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_BP; + } +} + +/** + * \brief Start transmission. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_start_transmission(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_TSTART; +} + +/** + * \brief Halt transmission. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_halt_transmission(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_THALT; +} + +/** + * \brief Transmit pause frame. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_tx_pause_frame(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_TXPF; +} + +/** + * \brief Transmit zero quantum pause frame. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_tx_pause_zero_quantum_frame(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_TXZQPF; +} + +/** + * \brief Read snapshot. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_read_snapshot(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_RDS; +} + +/** + * \brief Store receivetime stamp to memory. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to normal operation, else to enable the store. + */ +static inline void gmac_store_rx_time_stamp(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_SRTSM; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_SRTSM; + } +} + +/** + * \brief Enable PFC priority-based pause reception. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 1 to set the reception, 0 to disable. + */ +static inline void gmac_enable_pfc_pause_frame(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCR |= GMAC_NCR_ENPBPR; + } else { + p_gmac->GMAC_NCR &= ~GMAC_NCR_ENPBPR; + } +} + +/** + * \brief Transmit PFC priority-based pause reception. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_transmit_pfc_pause_frame(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_TXPBPF; +} + +/** + * \brief Flush next packet. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_flush_next_packet(Gmac* p_gmac) +{ + p_gmac->GMAC_NCR |= GMAC_NCR_FNP; +} + +/** + * \brief Set up network configuration register. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_cfg Network configuration value. + */ +static inline void gmac_set_configure(Gmac* p_gmac, uint32_t ul_cfg) +{ + p_gmac->GMAC_NCFGR = ul_cfg; +} + +/** + * \brief Get network configuration. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Network configuration. + */ +static inline uint32_t gmac_get_configure(Gmac* p_gmac) +{ + return p_gmac->GMAC_NCFGR; +} + + +/* Get and set DMA Configuration Register */ +static inline void gmac_set_dma(Gmac* p_gmac, uint32_t ul_cfg) +{ + p_gmac->GMAC_DCFGR = ul_cfg; +} + +static inline uint32_t gmac_get_dma(Gmac* p_gmac) +{ + return p_gmac->GMAC_DCFGR; +} + +/** + * \brief Set speed. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_speed 1 to indicate 100Mbps, 0 to 10Mbps. + */ +static inline void gmac_set_speed(Gmac* p_gmac, uint8_t uc_speed) +{ + if (uc_speed) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_SPD; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_SPD; + } +} + +/** + * \brief Enable/Disable Full-Duplex mode. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the Full-Duplex mode, else to enable it. + */ +static inline void gmac_enable_full_duplex(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_FD; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_FD; + } +} + +/** + * \brief Enable/Disable Copy(Receive) All Valid Frames. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable copying all valid frames, else to enable it. + */ +static inline void gmac_enable_copy_all(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_CAF; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_CAF; + } +} + +/** + * \brief Enable/Disable jumbo frames (up to 10240 bytes). + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the jumbo frames, else to enable it. + */ +static inline void gmac_enable_jumbo_frames(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_JFRAME; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_JFRAME; + } +} + +/** + * \brief Disable/Enable broadcast receiving. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 1 to disable the broadcast, else to enable it. + */ +static inline void gmac_disable_broadcast(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_NBC; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_NBC; + } +} + +/** + * \brief Enable/Disable multicast hash. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the multicast hash, else to enable it. + */ +static inline void gmac_enable_multicast_hash(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_UNIHEN; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_UNIHEN; + } +} + +/** + * \brief Enable/Disable big frames (over 1518, up to 1536). + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable big frames else to enable it. + */ +static inline void gmac_enable_big_frame(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_MAXFS; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_MAXFS; + } +} + +/** + * \brief Set MDC clock divider. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_mck GMAC MCK. + * + * \return GMAC_OK if successfully. + */ +static inline uint8_t gmac_set_mdc_clock(Gmac* p_gmac, uint32_t ul_mck) +{ + uint32_t ul_clk; + + if (ul_mck > GMAC_MCK_SPEED_240MHZ) { + return GMAC_INVALID; + } else if (ul_mck > GMAC_MCK_SPEED_160MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_96; + } else if (ul_mck > GMAC_MCK_SPEED_120MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_64; + } else if (ul_mck > GMAC_MCK_SPEED_80MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_48; + } else if (ul_mck > GMAC_MCK_SPEED_40MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_32; + } else if (ul_mck > GMAC_MCK_SPEED_20MHZ) { + ul_clk = GMAC_NCFGR_CLK_MCK_16; + } else { + ul_clk = GMAC_NCFGR_CLK_MCK_8; + } + ; + p_gmac->GMAC_NCFGR = (p_gmac->GMAC_NCFGR & ~GMAC_NCFGR_CLK_Msk) | ul_clk; + return GMAC_OK; +} + +/** + * \brief Enable/Disable retry test. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the GMAC receiver, else to enable it. + */ +static inline void gmac_enable_retry_test(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RTY; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RTY; + } +} + +/** + * \brief Enable/Disable pause (when a valid pause frame is received). + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable pause frame, else to enable it. + */ +static inline void gmac_enable_pause_frame(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_PEN; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_PEN; + } +} + +/** + * \brief Set receive buffer offset to 0 ~ 3. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline void gmac_set_rx_buffer_offset(Gmac* p_gmac, uint8_t uc_offset) +{ + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RXBUFO_Msk; + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RXBUFO(uc_offset); +} + +/** + * \brief Enable/Disable receive length field checking. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable receive length field checking, else to enable it. + */ +static inline void gmac_enable_rx_length_check(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_LFERD; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_LFERD; + } +} + +/** + * \brief Enable/Disable discarding FCS field of received frames. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable discarding FCS field of received frames, else to enable it. + */ +static inline void gmac_enable_discard_fcs(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_RFCS; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_RFCS; + } +} + + +/** + * \brief Enable/Disable frames to be received in half-duplex mode + * while transmitting. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable the received in half-duplex mode, else to enable it. + */ +static inline void gmac_enable_efrhd(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_EFRHD; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_EFRHD; + } +} + +/** + * \brief Enable/Disable ignore RX FCS. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_enable 0 to disable ignore RX FCS, else to enable it. + */ +static inline void gmac_enable_ignore_rx_fcs(Gmac* p_gmac, uint8_t uc_enable) +{ + if (uc_enable) { + p_gmac->GMAC_NCFGR |= GMAC_NCFGR_IRXFCS; + } else { + p_gmac->GMAC_NCFGR &= ~GMAC_NCFGR_IRXFCS; + } +} + +/** + * \brief Get Network Status. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Network status. + */ +static inline uint32_t gmac_get_status(Gmac* p_gmac) +{ + return p_gmac->GMAC_NSR; +} + +/** + * \brief Get MDIO IN pin status. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return MDIO IN pin status. + */ +static inline uint8_t gmac_get_MDIO(Gmac* p_gmac) +{ + return ((p_gmac->GMAC_NSR & GMAC_NSR_MDIO) > 0); +} + +/** + * \brief Check if PHY is idle. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return 1 if PHY is idle. + */ +static inline uint8_t gmac_is_phy_idle(Gmac* p_gmac) +{ + return ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) > 0); +} + +/** + * \brief Return transmit status. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Transmit status. + */ +static inline uint32_t gmac_get_tx_status(Gmac* p_gmac) +{ + return p_gmac->GMAC_TSR; +} + +/** + * \brief Clear transmit status. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_status Transmit status. + */ +static inline void gmac_clear_tx_status(Gmac* p_gmac, uint32_t ul_status) +{ + p_gmac->GMAC_TSR = ul_status; +} + +/** + * \brief Return receive status. + * + * \param p_gmac Pointer to the GMAC instance. + */ +static inline uint32_t gmac_get_rx_status(Gmac* p_gmac) +{ + return p_gmac->GMAC_RSR; +} + +/** + * \brief Clear receive status. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_status Receive status. + */ +static inline void gmac_clear_rx_status(Gmac* p_gmac, uint32_t ul_status) +{ + p_gmac->GMAC_RSR = ul_status; +} + +/** + * \brief Set Rx Queue. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_addr Rx queue address. + */ +static inline void gmac_set_rx_queue(Gmac* p_gmac, uint32_t ul_addr) +{ + p_gmac->GMAC_RBQB = GMAC_RBQB_ADDR_Msk & ul_addr; +} + +/** + * \brief Get Rx Queue Address. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Rx queue address. + */ +static inline uint32_t gmac_get_rx_queue(Gmac* p_gmac) +{ + return p_gmac->GMAC_RBQB; +} + +/** + * \brief Set Tx Queue. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_addr Tx queue address. + */ +static inline void gmac_set_tx_queue(Gmac* p_gmac, uint32_t ul_addr) +{ + p_gmac->GMAC_TBQB = GMAC_TBQB_ADDR_Msk & ul_addr; +} + +/** + * \brief Get Tx Queue. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Rx queue address. + */ +static inline uint32_t gmac_get_tx_queue(Gmac* p_gmac) +{ + return p_gmac->GMAC_TBQB; +} + +/** + * \brief Enable interrupt(s). + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_source Interrupt source(s) to be enabled. + */ +static inline void gmac_enable_interrupt(Gmac* p_gmac, uint32_t ul_source) +{ + p_gmac->GMAC_IER = ul_source; +} + +/** + * \brief Disable interrupt(s). + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_source Interrupt source(s) to be disabled. + */ +static inline void gmac_disable_interrupt(Gmac* p_gmac, uint32_t ul_source) +{ + p_gmac->GMAC_IDR = ul_source; +} + +/** + * \brief Return interrupt status. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Interrupt status. + */ +static inline uint32_t gmac_get_interrupt_status(Gmac* p_gmac) +{ + return p_gmac->GMAC_ISR; +} + +/** + * \brief Return interrupt mask. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Interrupt mask. + */ +static inline uint32_t gmac_get_interrupt_mask(Gmac* p_gmac) +{ + return p_gmac->GMAC_IMR; +} + +/** + * \brief Execute PHY maintenance command. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_phy_addr PHY address. + * \param uc_reg_addr Register address. + * \param uc_rw 1 to Read, 0 to write. + * \param us_data Data to be performed, write only. + */ +static inline void gmac_maintain_phy(Gmac* p_gmac, + uint8_t uc_phy_addr, uint8_t uc_reg_addr, uint8_t uc_rw, + uint16_t us_data) +{ + /* Wait until bus idle */ + while ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) == 0); + /* Write maintain register */ + p_gmac->GMAC_MAN = GMAC_MAN_WTN(GMAC_MAN_CODE_VALUE) + | GMAC_MAN_CLTTO + | GMAC_MAN_PHYA(uc_phy_addr) + | GMAC_MAN_REGA(uc_reg_addr) + | GMAC_MAN_OP((uc_rw ? GMAC_MAN_RW_TYPE : GMAC_MAN_READ_ONLY)) + | GMAC_MAN_DATA(us_data); +} + +/** + * \brief Get PHY maintenance data returned. + * + * \param p_gmac Pointer to the GMAC instance. + * + * \return Get PHY data. + */ +static inline uint16_t gmac_get_phy_data(Gmac* p_gmac) +{ + /* Wait until bus idle */ + while ((p_gmac->GMAC_NSR & GMAC_NSR_IDLE) == 0); + /* Return data */ + return (uint16_t) (p_gmac->GMAC_MAN & GMAC_MAN_DATA_Msk); +} + +/** + * \brief Set Hash. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ul_hash_top Hash top. + * \param ul_hash_bottom Hash bottom. + */ +static inline void gmac_set_hash(Gmac* p_gmac, uint32_t ul_hash_top, + uint32_t ul_hash_bottom) +{ + p_gmac->GMAC_HRB = ul_hash_bottom; + p_gmac->GMAC_HRT = ul_hash_top; +} + +/** + * \brief Set 64 bits Hash. + * + * \param p_gmac Pointer to the GMAC instance. + * \param ull_hash 64 bits hash value. + */ +static inline void gmac_set_hash64(Gmac* p_gmac, uint64_t ull_hash) +{ + p_gmac->GMAC_HRB = (uint32_t) ull_hash; + p_gmac->GMAC_HRT = (uint32_t) (ull_hash >> 32); +} + +/** + * \brief Set MAC Address. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_index GMAC specific address register index. + * \param p_mac_addr GMAC address. + */ +static inline void gmac_set_address(Gmac* p_gmac, uint8_t uc_index, + uint8_t* p_mac_addr) +{ + p_gmac->GMAC_SA[uc_index].GMAC_SAB = (p_mac_addr[3] << 24) + | (p_mac_addr[2] << 16) + | (p_mac_addr[1] << 8) + | (p_mac_addr[0]); + p_gmac->GMAC_SA[uc_index].GMAC_SAT = (p_mac_addr[5] << 8) + | (p_mac_addr[4]); +} + +/** + * \brief Set MAC Address via 2 dword. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_index GMAC specific address register index. + * \param ul_mac_top GMAC top address. + * \param ul_mac_bottom GMAC bottom address. + */ +static inline void gmac_set_address32(Gmac* p_gmac, uint8_t uc_index, + uint32_t ul_mac_top, uint32_t ul_mac_bottom) +{ + p_gmac->GMAC_SA[uc_index].GMAC_SAB = ul_mac_bottom; + p_gmac->GMAC_SA[uc_index].GMAC_SAT = ul_mac_top; +} + +/** + * \brief Set MAC Address via int64. + * + * \param p_gmac Pointer to the GMAC instance. + * \param uc_index GMAC specific address register index. + * \param ull_mac 64-bit GMAC address. + */ +static inline void gmac_set_address64(Gmac* p_gmac, uint8_t uc_index, + uint64_t ull_mac) +{ + p_gmac->GMAC_SA[uc_index].GMAC_SAB = (uint32_t) ull_mac; + p_gmac->GMAC_SA[uc_index].GMAC_SAT = (uint32_t) (ull_mac >> 32); +} + +/** + * \brief Select media independent interface mode. + * + * \param p_gmac Pointer to the GMAC instance. + * \param mode Media independent interface mode. + */ +static inline void gmac_select_mii_mode(Gmac* p_gmac, gmac_mii_mode_t mode) +{ + switch (mode) { + case GMAC_PHY_MII: + case GMAC_PHY_RMII: + p_gmac->GMAC_UR |= GMAC_UR_RMIIMII; + break; + + default: + p_gmac->GMAC_UR &= ~GMAC_UR_RMIIMII; + break; + } +} + +uint8_t gmac_phy_read(Gmac* p_gmac, uint8_t uc_phy_address, uint8_t uc_address, + uint32_t* p_value); +uint8_t gmac_phy_write(Gmac* p_gmac, uint8_t uc_phy_address, + uint8_t uc_address, uint32_t ul_value); +void gmac_dev_init(Gmac* p_gmac, gmac_device_t* p_gmac_dev, + gmac_options_t* p_opt); +uint32_t gmac_dev_read(gmac_device_t* p_gmac_dev, uint8_t* p_frame, + uint32_t ul_frame_size, uint32_t* p_rcv_size); +uint32_t gmac_dev_write(gmac_device_t* p_gmac_dev, void *p_buffer, + uint32_t ul_size, gmac_dev_tx_cb_t func_tx_cb); +uint32_t gmac_dev_get_tx_load(gmac_device_t* p_gmac_dev); +void gmac_dev_set_rx_callback(gmac_device_t* p_gmac_dev, + gmac_dev_rx_cb_t func_rx_cb); +uint8_t gmac_dev_set_tx_wakeup_callback(gmac_device_t* p_gmac_dev, + gmac_dev_wakeup_cb_t func_wakeup, uint8_t uc_threshold); +void gmac_dev_reset(gmac_device_t* p_gmac_dev); +void gmac_handler(gmac_device_t* p_gmac_dev); + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +} +#endif +/**INDENT-ON**/ +/// @endcond + +/** + * \page gmac_quickstart Quickstart guide for GMAC driver. + * + * This is the quickstart guide for the \ref gmac_group "Ethernet MAC", + * with step-by-step instructions on how to configure and use the driver in a + * selection of use cases. + * + * The use cases contain several code fragments. The code fragments in the + * steps for setup can be copied into a custom initialization function, while + * the steps for usage can be copied into, e.g., the main application function. + * + * \section gmac_basic_use_case Basic use case + * In the basic use case, the GMAC driver are configured for: + * - PHY component KSZ8051MNL is used + * - GMAC uses MII mode + * - The number of receive buffer is 16 + * - The number of transfer buffer is 8 + * - MAC address is set to 00-04-25-1c-a0-02 + * - IP address is set to 192.168.0.2 + * - IP address is set to 192.168.0.2 + * - Gateway is set to 192.168.0.1 + * - Network mask is 255.255.255.0 + * - PHY operation max retry count is 1000000 + * - GMAC is configured to not support copy all frame and support broadcast + * - The data will be read from the ethernet + * + * \section gmac_basic_use_case_setup Setup steps + * + * \subsection gmac_basic_use_case_setup_prereq Prerequisites + * -# \ref sysclk_group "System Clock Management (sysclock)" + * -# \ref pmc_group "Power Management Controller (pmc)" + * -# \ref ksz8051mnl_ethernet_phy_group "PHY component (KSZ8051MNL)" + * + * \subsection gmac_basic_use_case_setup_code Example code + * Content of conf_eth.h + * \code + * #define GMAC_RX_BUFFERS 16 + * #define GMAC_TX_BUFFERS 8 + * #define MAC_PHY_RETRY_MAX 1000000 + * #define ETHERNET_CONF_ETHADDR0 0x00 + * #define ETHERNET_CONF_ETHADDR0 0x00 + * #define ETHERNET_CONF_ETHADDR1 0x04 + * #define ETHERNET_CONF_ETHADDR2 0x25 + * #define ETHERNET_CONF_ETHADDR3 0x1C + * #define ETHERNET_CONF_ETHADDR4 0xA0 + * #define ETHERNET_CONF_ETHADDR5 0x02 + * #define ETHERNET_CONF_IPADDR0 192 + * #define ETHERNET_CONF_IPADDR1 168 + * #define ETHERNET_CONF_IPADDR2 0 + * #define ETHERNET_CONF_IPADDR3 2 + * #define ETHERNET_CONF_GATEWAY_ADDR0 192 + * #define ETHERNET_CONF_GATEWAY_ADDR1 168 + * #define ETHERNET_CONF_GATEWAY_ADDR2 0 + * #define ETHERNET_CONF_GATEWAY_ADDR3 1 + * #define ETHERNET_CONF_NET_MASK0 255 + * #define ETHERNET_CONF_NET_MASK1 255 + * #define ETHERNET_CONF_NET_MASK2 255 + * #define ETHERNET_CONF_NET_MASK3 0 + * #define ETH_PHY_MODE ETH_PHY_MODE + * \endcode + * + * A specific gmac device and the receive data buffer must be defined; another ul_frm_size should be defined + * to trace the actual size of the data received. + * \code + * static gmac_device_t gs_gmac_dev; + * static volatile uint8_t gs_uc_eth_buffer[GMAC_FRAME_LENTGH_MAX]; + * + * uint32_t ul_frm_size; + * \endcode + * + * Add to application C-file: + * \code + * void gmac_init(void) + * { + * sysclk_init(); + * + * board_init(); + * + * pmc_enable_periph_clk(ID_GMAC); + * + * gmac_option.uc_copy_all_frame = 0; + * gmac_option.uc_no_boardcast = 0; + * memcpy(gmac_option.uc_mac_addr, gs_uc_mac_address, sizeof(gs_uc_mac_address)); + * gs_gmac_dev.p_hw = GMAC; + * + * gmac_dev_init(GMAC, &gs_gmac_dev, &gmac_option); + * + * NVIC_EnableIRQ(GMAC_IRQn); + * + * ethernet_phy_init(GMAC, BOARD_GMAC_PHY_ADDR, sysclk_get_cpu_hz()); + * + * ethernet_phy_auto_negotiate(GMAC, BOARD_GMAC_PHY_ADDR); + * + * ethernet_phy_set_link(GMAC, BOARD_GMAC_PHY_ADDR, 1); + * \endcode + * + * \subsection gmac_basic_use_case_setup_flow Workflow + * - Ensure that conf_eth.h is present and contains the + * following configuration symbol. This configuration file is used + * by the driver and should not be included by the application. + * -# Define the receiving buffer size used in the internal GMAC driver. + * The buffer size used for RX is GMAC_RX_BUFFERS * 128. + * If it was supposed receiving a large number of frame, the + * GMAC_RX_BUFFERS should be set higher. E.g., the application wants to accept + * a ping echo test of 2048, the GMAC_RX_BUFFERS should be set at least + * (2048/128)=16, and as there are additional frames coming, a preferred + * number is 24 depending on a normal Ethernet throughput. + * - \code + * #define GMAC_RX_BUFFERS 16 + * \endcode + * -# Define the transmitting buffer size used in the internal GMAC driver. + * The buffer size used for TX is GMAC_TX_BUFFERS * 1518. + * - \code + * #define GMAC_TX_BUFFERS 8 + * \endcode + * -# Define maximum retry time for a PHY read/write operation. + * - \code + * #define MAC_PHY_RETRY_MAX 1000000 + * \endcode + * -# Define the MAC address. 00:04:25:1C:A0:02 is the address reserved + * for ATMEL, application should always change this address to its' own. + * - \code + * #define ETHERNET_CONF_ETHADDR0 0x00 + * #define ETHERNET_CONF_ETHADDR1 0x04 + * #define ETHERNET_CONF_ETHADDR2 0x25 + * #define ETHERNET_CONF_ETHADDR3 0x1C + * #define ETHERNET_CONF_ETHADDR4 0xA0 + * #define ETHERNET_CONF_ETHADDR5 0x02 + * \endcode + * -# Define the IP address configration used in the application. When DHCP + * is enabled, this configuration is not effected. + * - \code + * #define ETHERNET_CONF_IPADDR0 192 + * #define ETHERNET_CONF_IPADDR1 168 + * #define ETHERNET_CONF_IPADDR2 0 + * #define ETHERNET_CONF_IPADDR3 2 + * #define ETHERNET_CONF_GATEWAY_ADDR0 192 + * #define ETHERNET_CONF_GATEWAY_ADDR1 168 + * #define ETHERNET_CONF_GATEWAY_ADDR2 0 + * #define ETHERNET_CONF_GATEWAY_ADDR3 1 + * #define ETHERNET_CONF_NET_MASK0 255 + * #define ETHERNET_CONF_NET_MASK1 255 + * #define ETHERNET_CONF_NET_MASK2 255 + * #define ETHERNET_CONF_NET_MASK3 0 + * \endcode + * -# Configure the PHY maintainance interface. + * - \code + * #define ETH_PHY_MODE GMAC_PHY_MII + * \endcode + * -# Enable the system clock: + * - \code sysclk_init(); \endcode + * -# Enable PIO configurations for GMAC: + * - \code board_init(); \endcode + * -# Enable PMC clock for GMAC: + * - \code pmc_enable_periph_clk(ID_GMAC); \endcode + * -# Set the GMAC options; it's set to copy all frame and support broadcast: + * - \code + * gmac_option.uc_copy_all_frame = 0; + * gmac_option.uc_no_boardcast = 0; + * memcpy(gmac_option.uc_mac_addr, gs_uc_mac_address, sizeof(gs_uc_mac_address)); + * gs_gmac_dev.p_hw = GMAC; + * \endcode + * -# Initialize GMAC device with the filled option: + * - \code + * gmac_dev_init(GMAC, &gs_gmac_dev, &gmac_option); + * \endcode + * -# Enable the interrupt service for GMAC: + * - \code + * NVIC_EnableIRQ(GMAC_IRQn); + * \endcode + * -# Initialize the PHY component: + * - \code + * ethernet_phy_init(GMAC, BOARD_GMAC_PHY_ADDR, sysclk_get_cpu_hz()); + * \endcode + * -# The link will be established based on auto negotiation. + * - \code + * ethernet_phy_auto_negotiate(GMAC, BOARD_GMAC_PHY_ADDR); + * \endcode + * -# Establish the ethernet link; the network can be worked from now on: + * - \code + * ethernet_phy_set_link(GMAC, BOARD_GMAC_PHY_ADDR, 1); + * \endcode + * + * \section gmac_basic_use_case_usage Usage steps + * \subsection gmac_basic_use_case_usage_code Example code + * Add to, e.g., main loop in application C-file: + * \code + * gmac_dev_read(&gs_gmac_dev, (uint8_t *) gs_uc_eth_buffer, sizeof(gs_uc_eth_buffer), &ul_frm_size)); + * \endcode + * + * \subsection gmac_basic_use_case_usage_flow Workflow + * -# Start reading the data from the ethernet: + * - \code gmac_dev_read(&gs_gmac_dev, (uint8_t *) gs_uc_eth_buffer, sizeof(gs_uc_eth_buffer), &ul_frm_size)); \endcode + */ + +# define GMAC_STATS 0 + +#if( GMAC_STATS != 0 ) + + /* Here below some code to study the types and + frequencies of GMAC interrupts. */ + #define GMAC_IDX_RXUBR 0 + #define GMAC_IDX_TUR 1 + #define GMAC_IDX_RLEX 2 + #define GMAC_IDX_TFC 3 + #define GMAC_IDX_RCOMP 4 + #define GMAC_IDX_TCOMP 5 + #define GMAC_IDX_ROVR 6 + #define GMAC_IDX_HRESP 7 + #define GMAC_IDX_PFNZ 8 + #define GMAC_IDX_PTZ 9 + + struct SGmacStats { + unsigned recvCount; + unsigned rovrCount; + unsigned bnaCount; + unsigned sendCount; + unsigned sovrCount; + unsigned incompCount; + unsigned truncCount; + + unsigned intStatus[10]; + }; + extern struct SGmacStats gmacStats; + + struct SIntPair { + const char *name; + unsigned mask; + int index; + }; + + #define MK_PAIR( NAME ) #NAME, GMAC_IER_##NAME, GMAC_IDX_##NAME + static const struct SIntPair intPairs[] = { + { MK_PAIR( RXUBR ) }, /* Enable receive used bit read interrupt. */ + { MK_PAIR( TUR ) }, /* Enable transmit underrun interrupt. */ + { MK_PAIR( RLEX ) }, /* Enable retry limit exceeded interrupt. */ + { MK_PAIR( TFC ) }, /* Enable transmit buffers exhausted in mid-frame interrupt. */ + { MK_PAIR( RCOMP ) }, /* Receive complete */ + { MK_PAIR( TCOMP ) }, /* Enable transmit complete interrupt. */ + { MK_PAIR( ROVR ) }, /* Enable receive overrun interrupt. */ + { MK_PAIR( HRESP ) }, /* Enable Hresp not OK interrupt. */ + { MK_PAIR( PFNZ ) }, /* Enable pause frame received interrupt. */ + { MK_PAIR( PTZ ) } /* Enable pause time zero interrupt. */ + }; + + void gmac_show_irq_counts (); + +#endif + +#endif /* GMAC_H_INCLUDED */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Common/phyHandling.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Common/phyHandling.c new file mode 100644 index 000000000..47757e3bd --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Common/phyHandling.c @@ -0,0 +1,712 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* + * Handling of Ethernet PHY's + * PHY's communicate with an EMAC either through + * a Media-Independent Interface (MII), or a Reduced Media-Independent Interface (RMII). + * The EMAC can poll for PHY ports on 32 different addresses. Each of the PHY ports + * shall be treated independently. + * + */ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" + +#include "phyHandling.h" + +#define phyMIN_PHY_ADDRESS 0 +#define phyMAX_PHY_ADDRESS 31 + +#if defined( PHY_LS_HIGH_CHECK_TIME_MS ) || defined( PHY_LS_LOW_CHECK_TIME_MS ) + #warning please use the new defines with 'ipconfig' prefix +#endif + +#ifndef ipconfigPHY_LS_HIGH_CHECK_TIME_MS + /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not + receiving packets. */ + #define ipconfigPHY_LS_HIGH_CHECK_TIME_MS 15000 +#endif + +#ifndef ipconfigPHY_LS_LOW_CHECK_TIME_MS + /* Check if the LinkSStatus in the PHY is still low every second. */ + #define ipconfigPHY_LS_LOW_CHECK_TIME_MS 1000 +#endif + +/* Naming and numbering of basic PHY registers. */ +#define phyREG_00_BMCR 0x00u /* Basic Mode Control Register. */ +#define phyREG_01_BMSR 0x01u /* Basic Mode Status Register. */ +#define phyREG_02_PHYSID1 0x02u /* PHYS ID 1 */ +#define phyREG_03_PHYSID2 0x03u /* PHYS ID 2 */ +#define phyREG_04_ADVERTISE 0x04u /* Advertisement control reg */ + +/* Naming and numbering of extended PHY registers. */ +#define PHYREG_10_PHYSTS 0x10u /* 16 PHY status register Offset */ +#define phyREG_19_PHYCR 0x19u /* 25 RW PHY Control Register */ +#define phyREG_1F_PHYSPCS 0x1Fu /* 31 RW PHY Special Control Status */ + +/* Bit fields for 'phyREG_00_BMCR', the 'Basic Mode Control Register'. */ +#define phyBMCR_FULL_DUPLEX 0x0100u /* Full duplex. */ +#define phyBMCR_AN_RESTART 0x0200u /* Auto negotiation restart. */ +#define phyBMCR_ISOLATE 0x0400u /* 1 = Isolates 0 = Normal operation. */ +#define phyBMCR_AN_ENABLE 0x1000u /* Enable auto negotiation. */ +#define phyBMCR_SPEED_100 0x2000u /* Select 100Mbps. */ +#define phyBMCR_RESET 0x8000u /* Reset the PHY. */ + +/* Bit fields for 'phyREG_19_PHYCR', the 'PHY Control Register'. */ +#define PHYCR_MDIX_EN 0x8000u /* Enable Auto MDIX. */ +#define PHYCR_MDIX_FORCE 0x4000u /* Force MDIX crossed. */ + +#define phyBMSR_AN_COMPLETE 0x0020u /* Auto-Negotiation process completed */ + +#define phyBMSR_LINK_STATUS 0x0004u + +#define phyPHYSTS_LINK_STATUS 0x0001u /* PHY Link mask */ +#define phyPHYSTS_SPEED_STATUS 0x0002u /* PHY Speed mask */ +#define phyPHYSTS_DUPLEX_STATUS 0x0004u /* PHY Duplex mask */ + +/* Bit fields for 'phyREG_1F_PHYSPCS + 001 = 10BASE-T half-duplex + 101 = 10BASE-T full-duplex + 010 = 100BASE-TX half-duplex + 110 = 100BASE-TX full-duplex +*/ +#define phyPHYSPCS_SPEED_MASK 0x000Cu +#define phyPHYSPCS_SPEED_10 0x0004u +#define phyPHYSPCS_FULL_DUPLEX 0x0010u + +/* + * Description of all capabilities that can be advertised to + * the peer (usually a switch or router). + */ +#define phyADVERTISE_CSMA 0x0001u /* Only selector supported. */ +#define phyADVERTISE_10HALF 0x0020u /* Try for 10mbps half-duplex. */ +#define phyADVERTISE_10FULL 0x0040u /* Try for 10mbps full-duplex. */ +#define phyADVERTISE_100HALF 0x0080u /* Try for 100mbps half-duplex. */ +#define phyADVERTISE_100FULL 0x0100u /* Try for 100mbps full-duplex. */ + +#define phyADVERTISE_ALL ( phyADVERTISE_10HALF | phyADVERTISE_10FULL | \ + phyADVERTISE_100HALF | phyADVERTISE_100FULL ) + +/* Send a reset commando to a set of PHY-ports. */ +static uint32_t xPhyReset( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask ); + +static BaseType_t xHas_1F_PHYSPCS( uint32_t ulPhyID ) +{ +BaseType_t xResult; + + switch( ulPhyID ) + { + case PHY_ID_LAN8720: + case PHY_ID_LAN8742A: + case PHY_ID_KSZ8041: +/* + case PHY_ID_KSZ8051: // same ID as 8041 + case PHY_ID_KSZ8081: // same ID as 8041 +*/ + case PHY_ID_KSZ8081MNXIA: + + case PHY_ID_KSZ8863: + default: + /* Most PHY's have a 1F_PHYSPCS */ + xResult = pdTRUE; + break; + case PHY_ID_DP83848I: + xResult = pdFALSE; + break; + } + return xResult; +} +/*-----------------------------------------------------------*/ + +static BaseType_t xHas_19_PHYCR( uint32_t ulPhyID ) +{ +BaseType_t xResult; + + switch( ulPhyID ) + { + case PHY_ID_LAN8742A: + case PHY_ID_DP83848I: + xResult = pdTRUE; + break; + default: + /* Most PHY's do not have a 19_PHYCR */ + xResult = pdFALSE; + break; + } + return xResult; +} +/*-----------------------------------------------------------*/ + +/* Initialise the struct and assign a PHY-read and -write function. */ +void vPhyInitialise( EthernetPhy_t *pxPhyObject, xApplicationPhyReadHook_t fnPhyRead, xApplicationPhyWriteHook_t fnPhyWrite ) +{ + memset( ( void * )pxPhyObject, '\0', sizeof( *pxPhyObject ) ); + + pxPhyObject->fnPhyRead = fnPhyRead; + pxPhyObject->fnPhyWrite = fnPhyWrite; +} +/*-----------------------------------------------------------*/ + +/* Discover all PHY's connected by polling 32 indexes ( zero-based ) */ +BaseType_t xPhyDiscover( EthernetPhy_t *pxPhyObject ) +{ +BaseType_t xPhyAddress; + + pxPhyObject->xPortCount = 0; + + for( xPhyAddress = phyMIN_PHY_ADDRESS; xPhyAddress <= phyMAX_PHY_ADDRESS; xPhyAddress++ ) + { + uint32_t ulLowerID; + + pxPhyObject->fnPhyRead( xPhyAddress, phyREG_03_PHYSID2, &ulLowerID ); + /* A valid PHY id can not be all zeros or all ones. */ + if( ( ulLowerID != ( uint16_t )~0u ) && ( ulLowerID != ( uint16_t )0u ) ) + { + uint32_t ulUpperID; + uint32_t ulPhyID; + + pxPhyObject->fnPhyRead( xPhyAddress, phyREG_02_PHYSID1, &ulUpperID ); + ulPhyID = ( ( ( uint32_t ) ulUpperID ) << 16 ) | ( ulLowerID & 0xFFF0 ); + + pxPhyObject->ucPhyIndexes[ pxPhyObject->xPortCount ] = xPhyAddress; + pxPhyObject->ulPhyIDs[ pxPhyObject->xPortCount ] = ulPhyID; + + pxPhyObject->xPortCount++; + + /* See if there is more storage space. */ + if( pxPhyObject->xPortCount == ipconfigPHY_MAX_PORTS ) + { + break; + } + } + } + if( pxPhyObject->xPortCount > 0 ) + { + FreeRTOS_printf( ( "PHY ID %lX\n", pxPhyObject->ulPhyIDs[ 0 ] ) ); + } + + return pxPhyObject->xPortCount; +} +/*-----------------------------------------------------------*/ + +/* Send a reset commando to a set of PHY-ports. */ +static uint32_t xPhyReset( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask ) +{ +uint32_t ulDoneMask, ulConfig; +TickType_t xRemainingTime; +TimeOut_t xTimer; +BaseType_t xPhyIndex; + + /* A bit-mask ofPHY ports that are ready. */ + ulDoneMask = 0ul; + + /* Set the RESET bits high. */ + for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ ) + { + BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ]; + + /* Read Control register. */ + pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig ); + pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulConfig | phyBMCR_RESET ); + } + + xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( 1000UL ); + vTaskSetTimeOutState( &xTimer ); + + /* The reset should last less than a second. */ + for( ;; ) + { + for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ ) + { + BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ]; + + pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig ); + if( ( ulConfig & phyBMCR_RESET ) == 0 ) + { + FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET %d ready\n", (int)xPhyIndex ) ); + ulDoneMask |= ( 1ul << xPhyIndex ); + } + } + if( ulDoneMask == ulPhyMask ) + { + break; + } + if( xTaskCheckForTimeOut( &xTimer, &xRemainingTime ) != pdFALSE ) + { + FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET timed out ( done 0x%02lX )\n", ulDoneMask ) ); + break; + } + /* Block for a while */ + vTaskDelay( pdMS_TO_TICKS( 50ul ) ); + } + + /* Clear the reset bits. */ + for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ ) + { + BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ]; + + pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig ); + pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulConfig & ~phyBMCR_RESET ); + } + + vTaskDelay( pdMS_TO_TICKS( 50ul ) ); + + return ulDoneMask; +} +/*-----------------------------------------------------------*/ + +BaseType_t xPhyConfigure( EthernetPhy_t *pxPhyObject, const PhyProperties_t *pxPhyProperties ) +{ +uint32_t ulConfig, ulAdvertise; +BaseType_t xPhyIndex; + + if( pxPhyObject->xPortCount < 1 ) + { + FreeRTOS_printf( ( "xPhyResetAll: No PHY's detected.\n" ) ); + return -1; + } + + /* The expected ID for the 'LAN8742A' is 0x0007c130. */ + /* The expected ID for the 'LAN8720' is 0x0007c0f0. */ + /* The expected ID for the 'DP83848I' is 0x20005C90. */ + + /* Set advertise register. */ + if( ( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO ) && ( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO ) ) + { + ulAdvertise = phyADVERTISE_CSMA | phyADVERTISE_ALL; + /* Reset auto-negotiation capability. */ + } + else + { + ulAdvertise = phyADVERTISE_CSMA; + + if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO ) + { + if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL ) + { + ulAdvertise |= phyADVERTISE_10FULL | phyADVERTISE_100FULL; + } + else + { + ulAdvertise |= phyADVERTISE_10HALF | phyADVERTISE_100HALF; + } + } + else if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO ) + { + if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_10 ) + { + ulAdvertise |= phyADVERTISE_10FULL | phyADVERTISE_10HALF; + } + else + { + ulAdvertise |= phyADVERTISE_100FULL | phyADVERTISE_100HALF; + } + } + else if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_100 ) + { + if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL ) + { + ulAdvertise |= phyADVERTISE_100FULL; + } + else + { + ulAdvertise |= phyADVERTISE_100HALF; + } + } + else + { + if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL ) + { + ulAdvertise |= phyADVERTISE_10FULL; + } + else + { + ulAdvertise |= phyADVERTISE_10HALF; + } + } + } + + /* Send a reset commando to a set of PHY-ports. */ + xPhyReset( pxPhyObject, xPhyGetMask( pxPhyObject ) ); + + for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ ) + { + BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ]; + uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ]; + + /* Write advertise register. */ + pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_04_ADVERTISE, ulAdvertise ); + + /* + AN_EN AN1 AN0 Forced Mode + 0 0 0 10BASE-T, Half-Duplex + 0 0 1 10BASE-T, Full-Duplex + 0 1 0 100BASE-TX, Half-Duplex + 0 1 1 100BASE-TX, Full-Duplex + AN_EN AN1 AN0 Advertised Mode + 1 0 0 10BASE-T, Half/Full-Duplex + 1 0 1 100BASE-TX, Half/Full-Duplex + 1 1 0 10BASE-T Half-Duplex + 100BASE-TX, Half-Duplex + 1 1 1 10BASE-T, Half/Full-Duplex + 100BASE-TX, Half/Full-Duplex + */ + + /* Read Control register. */ + pxPhyObject->fnPhyRead( xPhyAddress, phyREG_00_BMCR, &ulConfig ); + + ulConfig &= ~( phyBMCR_SPEED_100 | phyBMCR_FULL_DUPLEX ); + + ulConfig |= phyBMCR_AN_ENABLE; + + if( ( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_100 ) || ( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_AUTO ) ) + { + ulConfig |= phyBMCR_SPEED_100; + } + else if( pxPhyProperties->ucSpeed == ( uint8_t )PHY_SPEED_10 ) + { + ulConfig &= ~phyBMCR_SPEED_100; + } + + if( ( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_FULL ) || ( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_AUTO ) ) + { + ulConfig |= phyBMCR_FULL_DUPLEX; + } + else if( pxPhyProperties->ucDuplex == ( uint8_t )PHY_DUPLEX_HALF ) + { + ulConfig &= ~phyBMCR_FULL_DUPLEX; + } + + if( xHas_19_PHYCR( ulPhyID ) ) + { + uint32_t ulPhyControl; + /* Read PHY Control register. */ + pxPhyObject->fnPhyRead( xPhyAddress, phyREG_19_PHYCR, &ulPhyControl ); + + /* Clear bits which might get set: */ + ulPhyControl &= ~( PHYCR_MDIX_EN|PHYCR_MDIX_FORCE ); + + if( pxPhyProperties->ucMDI_X == PHY_MDIX_AUTO ) + { + ulPhyControl |= PHYCR_MDIX_EN; + } + else if( pxPhyProperties->ucMDI_X == PHY_MDIX_CROSSED ) + { + /* Force direct link = Use crossed RJ45 cable. */ + ulPhyControl &= ~PHYCR_MDIX_FORCE; + } + else + { + /* Force crossed link = Use direct RJ45 cable. */ + ulPhyControl |= PHYCR_MDIX_FORCE; + } + /* update PHY Control Register. */ + pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_19_PHYCR, ulPhyControl ); + } + + FreeRTOS_printf( ( "+TCP: advertise: %04lX config %04lX\n", ulAdvertise, ulConfig ) ); + } + + /* Keep these values for later use. */ + pxPhyObject->ulBCRValue = ulConfig & ~phyBMCR_ISOLATE; + pxPhyObject->ulACRValue = ulAdvertise; + + return 0; +} +/*-----------------------------------------------------------*/ + +BaseType_t xPhyFixedValue( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask ) +{ +BaseType_t xPhyIndex; +uint32_t ulValue, ulBitMask = ( uint32_t )1u; + + ulValue = ( uint32_t )0u; + + if( pxPhyObject->xPhyPreferences.ucDuplex == PHY_DUPLEX_FULL ) + { + ulValue |= phyBMCR_FULL_DUPLEX; + } + if( pxPhyObject->xPhyPreferences.ucSpeed == PHY_SPEED_100 ) + { + ulValue |= phyBMCR_SPEED_100; + } + + for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 ) + { + if( ( ulPhyMask & ulBitMask ) != 0lu ) + { + BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ]; + + /* Enable Auto-Negotiation. */ + pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, ulValue ); + } + } + return 0; +} +/*-----------------------------------------------------------*/ + +BaseType_t xPhyStartAutoNegotiation( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask ) +{ +uint32_t xPhyIndex, ulDoneMask, ulBitMask; +uint32_t ulPHYLinkStatus, ulRegValue; +TickType_t xRemainingTime; +TimeOut_t xTimer; + + if( ulPhyMask == ( uint32_t )0u ) + { + return 0; + } + for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++ ) + { + if( ( ulPhyMask & ( 1lu << xPhyIndex ) ) != 0lu ) + { + BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ]; + + /* Enable Auto-Negotiation. */ + pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_04_ADVERTISE, pxPhyObject->ulACRValue); + pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, pxPhyObject->ulBCRValue | phyBMCR_AN_RESTART ); + } + } + xRemainingTime = ( TickType_t ) pdMS_TO_TICKS( 3000UL ); + vTaskSetTimeOutState( &xTimer ); + ulDoneMask = 0; + /* Wait until the auto-negotiation will be completed */ + for( ;; ) + { + ulBitMask = ( uint32_t )1u; + for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 ) + { + if( ( ulPhyMask & ulBitMask ) != 0lu ) + { + if( ( ulDoneMask & ulBitMask ) == 0lu ) + { + BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ]; + + pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulRegValue ); + if( ( ulRegValue & phyBMSR_AN_COMPLETE ) != 0 ) + { + ulDoneMask |= ulBitMask; + } + } + } + } + if( ulPhyMask == ulDoneMask ) + { + break; + } + if( xTaskCheckForTimeOut( &xTimer, &xRemainingTime ) != pdFALSE ) + { + FreeRTOS_printf( ( "xPhyReset: phyBMCR_RESET timed out ( done 0x%02lX )\n", ulDoneMask ) ); + break; + } + vTaskDelay( pdMS_TO_TICKS( 50 ) ); + } + + if( ulDoneMask != ( uint32_t)0u ) + { + ulBitMask = ( uint32_t )1u; + pxPhyObject->ulLinkStatusMask &= ~( ulDoneMask ); + for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 ) + { + BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ]; + uint32_t ulPhyID = pxPhyObject->ulPhyIDs[ xPhyIndex ]; + + if( ( ulDoneMask & ulBitMask ) == ( uint32_t )0u ) + { + continue; + } + + /* Clear the 'phyBMCR_AN_RESTART' bit. */ + pxPhyObject->fnPhyWrite( xPhyAddress, phyREG_00_BMCR, pxPhyObject->ulBCRValue ); + + pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulRegValue); + if( ( ulRegValue & phyBMSR_LINK_STATUS ) != 0 ) + { + ulPHYLinkStatus |= phyBMSR_LINK_STATUS; + pxPhyObject->ulLinkStatusMask |= ulBitMask; + } + else + { + ulPHYLinkStatus &= ~( phyBMSR_LINK_STATUS ); + } + + if( ulPhyID == PHY_ID_KSZ8081MNXIA ) + { + uint32_t ulControlStatus; + + pxPhyObject->fnPhyRead( xPhyAddress, 0x1E, &ulControlStatus); + switch( ulControlStatus & 0x07 ) + { + case 0x01: + case 0x05: +// [001] = 10BASE-T half-duplex +// [101] = 10BASE-T full-duplex + /* 10 Mbps. */ + ulRegValue |= phyPHYSTS_SPEED_STATUS; + break; + case 0x02: + case 0x06: +// [010] = 100BASE-TX half-duplex +// [110] = 100BASE-TX full-duplex + break; + } + switch( ulControlStatus & 0x07 ) + { + case 0x05: + case 0x06: +// [101] = 10BASE-T full-duplex +// [110] = 100BASE-TX full-duplex + /* Full duplex. */ + ulRegValue |= phyPHYSTS_DUPLEX_STATUS; + break; + case 0x01: + case 0x02: +// [001] = 10BASE-T half-duplex +// [010] = 100BASE-TX half-duplex + break; + } + } + else if( xHas_1F_PHYSPCS( ulPhyID ) ) + { + /* 31 RW PHY Special Control Status */ + uint32_t ulControlStatus; + + pxPhyObject->fnPhyRead( xPhyAddress, phyREG_1F_PHYSPCS, &ulControlStatus); + ulRegValue = 0; + if( ( ulControlStatus & phyPHYSPCS_FULL_DUPLEX ) != 0 ) + { + ulRegValue |= phyPHYSTS_DUPLEX_STATUS; + } + if( ( ulControlStatus & phyPHYSPCS_SPEED_MASK ) == phyPHYSPCS_SPEED_10 ) + { + ulRegValue |= phyPHYSTS_SPEED_STATUS; + } + } + else + { + /* Read the result of the auto-negotiation. */ + pxPhyObject->fnPhyRead( xPhyAddress, PHYREG_10_PHYSTS, &ulRegValue); + } + + FreeRTOS_printf( ( ">> Autonego ready: %08lx: %s duplex %u mbit %s status\n", + ulRegValue, + ( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) ? "full" : "half", + ( ulRegValue & phyPHYSTS_SPEED_STATUS ) ? 10 : 100, + ( ( ulPHYLinkStatus |= phyBMSR_LINK_STATUS ) != 0) ? "high" : "low" ) ); + if( ( ulRegValue & phyPHYSTS_DUPLEX_STATUS ) != ( uint32_t )0u ) + { + pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_FULL; + } + else + { + pxPhyObject->xPhyProperties.ucDuplex = PHY_DUPLEX_HALF; + } + + if( ( ulRegValue & phyPHYSTS_SPEED_STATUS ) != 0 ) + { + pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_10; + } + else + { + pxPhyObject->xPhyProperties.ucSpeed = PHY_SPEED_100; + } + } + } /* if( ulDoneMask != ( uint32_t)0u ) */ + + return 0; +} +/*-----------------------------------------------------------*/ + +BaseType_t xPhyCheckLinkStatus( EthernetPhy_t *pxPhyObject, BaseType_t xHadReception ) +{ +uint32_t ulStatus, ulBitMask = 1u; +BaseType_t xPhyIndex; +BaseType_t xNeedCheck = pdFALSE; + + if( xHadReception > 0 ) + { + /* A packet was received. No need to check for the PHY status now, + but set a timer to check it later on. */ + vTaskSetTimeOutState( &( pxPhyObject->xLinkStatusTimer ) ); + pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS ); + for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 ) + { + if( ( pxPhyObject->ulLinkStatusMask & ulBitMask ) == 0ul ) + { + pxPhyObject->ulLinkStatusMask |= ulBitMask; + FreeRTOS_printf( ( "xPhyCheckLinkStatus: PHY LS now %02lX\n", pxPhyObject->ulLinkStatusMask ) ); + xNeedCheck = pdTRUE; + } + } + } + else if( xTaskCheckForTimeOut( &( pxPhyObject->xLinkStatusTimer ), &( pxPhyObject->xLinkStatusRemaining ) ) != pdFALSE ) + { + for( xPhyIndex = 0; xPhyIndex < pxPhyObject->xPortCount; xPhyIndex++, ulBitMask <<= 1 ) + { + BaseType_t xPhyAddress = pxPhyObject->ucPhyIndexes[ xPhyIndex ]; + + if( pxPhyObject->fnPhyRead( xPhyAddress, phyREG_01_BMSR, &ulStatus ) == 0 ) + { + if( !!( pxPhyObject->ulLinkStatusMask & ulBitMask ) != !!( ulStatus & phyBMSR_LINK_STATUS ) ) + { + if( ( ulStatus & phyBMSR_LINK_STATUS ) != 0 ) + { + pxPhyObject->ulLinkStatusMask |= ulBitMask; + } + else + { + pxPhyObject->ulLinkStatusMask &= ~( ulBitMask ); + } + FreeRTOS_printf( ( "xPhyCheckLinkStatus: PHY LS now %02lX\n", pxPhyObject->ulLinkStatusMask ) ); + xNeedCheck = pdTRUE; + } + } + } + vTaskSetTimeOutState( &( pxPhyObject->xLinkStatusTimer ) ); + if( ( pxPhyObject->ulLinkStatusMask & phyBMSR_LINK_STATUS ) != 0 ) + { + pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_HIGH_CHECK_TIME_MS ); + } + else + { + pxPhyObject->xLinkStatusRemaining = pdMS_TO_TICKS( ipconfigPHY_LS_LOW_CHECK_TIME_MS ); + } + } + return xNeedCheck; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c new file mode 100644 index 000000000..e0d04e454 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC17xx/NetworkInterface.c @@ -0,0 +1,267 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* Hardware abstraction. */ +#include "FreeRTOS_IO.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_Sockets.h" +#include "NetworkBufferManagement.h" + +/* Driver includes. */ +#include "lpc17xx_emac.h" +#include "lpc17xx_pinsel.h" + +/* Demo includes. */ +#include "NetworkInterface.h" + +#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1 + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer +#else + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) ) +#endif + +/* When a packet is ready to be sent, if it cannot be sent immediately then the +task performing the transmit will block for niTX_BUFFER_FREE_WAIT +milliseconds. It will do this a maximum of niMAX_TX_ATTEMPTS before giving +up. */ +#define niTX_BUFFER_FREE_WAIT ( pdMS_TO_TICKS( 2UL ) ) +#define niMAX_TX_ATTEMPTS ( 5 ) + +/* The length of the queue used to send interrupt status words from the +interrupt handler to the deferred handler task. */ +#define niINTERRUPT_QUEUE_LENGTH ( 10 ) + +/*-----------------------------------------------------------*/ + +/* + * A deferred interrupt handler task that processes + */ +static void prvEMACHandlerTask( void *pvParameters ); + +/*-----------------------------------------------------------*/ + +/* The queue used to communicate Ethernet events with the IP task. */ +extern QueueHandle_t xNetworkEventQueue; + +/* The semaphore used to wake the deferred interrupt handler task when an Rx +interrupt is received. */ +static SemaphoreHandle_t xEMACRxEventSemaphore = NULL; +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceInitialise( void ) +{ +EMAC_CFG_Type Emac_Config; +PINSEL_CFG_Type xPinConfig; +BaseType_t xStatus, xReturn; +extern uint8_t ucMACAddress[ 6 ]; + + /* Enable Ethernet Pins */ + boardCONFIGURE_ENET_PINS( xPinConfig ); + + Emac_Config.Mode = EMAC_MODE_AUTO; + Emac_Config.pbEMAC_Addr = ucMACAddress; + xStatus = EMAC_Init( &Emac_Config ); + + LPC_EMAC->IntEnable &= ~( EMAC_INT_TX_DONE ); + + if( xStatus != ERROR ) + { + vSemaphoreCreateBinary( xEMACRxEventSemaphore ); + configASSERT( xEMACRxEventSemaphore ); + + /* The handler task is created at the highest possible priority to + ensure the interrupt handler can return directly to it. */ + xTaskCreate( prvEMACHandlerTask, "EMAC", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL ); + + /* Enable the interrupt and set its priority to the minimum + interrupt priority. */ + NVIC_SetPriority( ENET_IRQn, configMAC_INTERRUPT_PRIORITY ); + NVIC_EnableIRQ( ENET_IRQn ); + + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + configASSERT( xStatus != ERROR ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ +BaseType_t xReturn = pdFAIL; +int32_t x; +extern void EMAC_StartTransmitNextBuffer( uint32_t ulLength ); +extern void EMAC_SetNextPacketToSend( uint8_t * pucBuffer ); + + + /* Attempt to obtain access to a Tx buffer. */ + for( x = 0; x < niMAX_TX_ATTEMPTS; x++ ) + { + if( EMAC_CheckTransmitIndex() == TRUE ) + { + /* Will the data fit in the Tx buffer? */ + if( pxNetworkBuffer->xDataLength < EMAC_ETH_MAX_FLEN ) /*_RB_ The size needs to come from FreeRTOSIPConfig.h. */ + { + /* Assign the buffer to the Tx descriptor that is now known to + be free. */ + EMAC_SetNextPacketToSend( pxNetworkBuffer->pucBuffer ); + + /* The EMAC now owns the buffer. */ + pxNetworkBuffer->pucBuffer = NULL; + + /* Initiate the Tx. */ + EMAC_StartTransmitNextBuffer( pxNetworkBuffer->xDataLength ); + iptraceNETWORK_INTERFACE_TRANSMIT(); + + /* The Tx has been initiated. */ + xReturn = pdPASS; + } + break; + } + else + { + vTaskDelay( niTX_BUFFER_FREE_WAIT ); + } + } + + /* Finished with the network buffer. */ + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void ENET_IRQHandler( void ) +{ +uint32_t ulInterruptCause; + + while( ( ulInterruptCause = LPC_EMAC->IntStatus ) != 0 ) + { + /* Clear the interrupt. */ + LPC_EMAC->IntClear = ulInterruptCause; + + /* Clear fatal error conditions. NOTE: The driver does not clear all + errors, only those actually experienced. For future reference, range + errors are not actually errors so can be ignored. */ + if( ( ulInterruptCause & EMAC_INT_TX_UNDERRUN ) != 0U ) + { + LPC_EMAC->Command |= EMAC_CR_TX_RES; + } + + /* Unblock the deferred interrupt handler task if the event was an + Rx. */ + if( ( ulInterruptCause & EMAC_INT_RX_DONE ) != 0UL ) + { + xSemaphoreGiveFromISR( xEMACRxEventSemaphore, NULL ); + } + } + + /* ulInterruptCause is used for convenience here. A context switch is + wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a + compiler warning. */ + portEND_SWITCHING_ISR( ulInterruptCause ); +} +/*-----------------------------------------------------------*/ + +static void prvEMACHandlerTask( void *pvParameters ) +{ +size_t xDataLength; +const uint16_t usCRCLength = 4; +NetworkBufferDescriptor_t *pxNetworkBuffer; +IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; + +/* This is not included in the header file for some reason. */ +extern uint8_t *EMAC_NextPacketToRead( void ); + + ( void ) pvParameters; + configASSERT( xEMACRxEventSemaphore ); + + for( ;; ) + { + /* Wait for the EMAC interrupt to indicate that another packet has been + received. The while() loop is only needed if INCLUDE_vTaskSuspend is + set to 0 in FreeRTOSConfig.h. */ + while( xSemaphoreTake( xEMACRxEventSemaphore, portMAX_DELAY ) == pdFALSE ); + + /* At least one packet has been received. */ + while( EMAC_CheckReceiveIndex() != FALSE ) + { + /* Obtain the length, minus the CRC. The CRC is four bytes + but the length is already minus 1. */ + xDataLength = ( size_t ) EMAC_GetReceiveDataSize() - ( usCRCLength - 1U ); + + if( xDataLength > 0U ) + { + /* Obtain a network buffer to pass this data into the + stack. No storage is required as the network buffer + will point directly to the buffer that already holds + the received data. */ + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( 0, ( TickType_t ) 0 ); + + if( pxNetworkBuffer != NULL ) + { + pxNetworkBuffer->pucBuffer = EMAC_NextPacketToRead(); + pxNetworkBuffer->xDataLength = xDataLength; + xRxEvent.pvData = ( void * ) pxNetworkBuffer; + + /* Data was received and stored. Send a message to the IP + task to let it know. */ + if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + iptraceETHERNET_RX_EVENT_LOST(); + } + } + else + { + iptraceETHERNET_RX_EVENT_LOST(); + } + + iptraceNETWORK_INTERFACE_RECEIVE(); + } + + /* Release the frame. */ + EMAC_UpdateRxConsumeIndex(); + } + } +} +/*-----------------------------------------------------------*/ + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c new file mode 100644 index 000000000..ac01d41af --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c @@ -0,0 +1,1068 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" + +/* LPCOpen includes. */ +#include "chip.h" +#include "lpc_phy.h" + +/* The size of the stack allocated to the task that handles Rx packets. */ +#define nwRX_TASK_STACK_SIZE 140 + +#ifndef PHY_LS_HIGH_CHECK_TIME_MS + /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not + receiving packets. */ + #define PHY_LS_HIGH_CHECK_TIME_MS 15000 +#endif + +#ifndef PHY_LS_LOW_CHECK_TIME_MS + /* Check if the LinkSStatus in the PHY is still low every second. */ + #define PHY_LS_LOW_CHECK_TIME_MS 1000 +#endif + +#ifndef configUSE_RMII + #define configUSE_RMII 1 +#endif + +#ifndef configNUM_RX_DESCRIPTORS + #error please define configNUM_RX_DESCRIPTORS in your FreeRTOSIPConfig.h +#endif + +#ifndef configNUM_TX_DESCRIPTORS + #error please define configNUM_TX_DESCRIPTORS in your FreeRTOSIPConfig.h +#endif + +#ifndef NETWORK_IRQHandler + #error NETWORK_IRQHandler must be defined to the name of the function that is installed in the interrupt vector table to handle Ethernet interrupts. +#endif + +#if !defined( MAC_FF_HMC ) + /* Hash for multicast. */ + #define MAC_FF_HMC ( 1UL << 2UL ) +#endif + +#ifndef iptraceEMAC_TASK_STARTING + #define iptraceEMAC_TASK_STARTING() do { } while( 0 ) +#endif + +/* Define the bits of .STATUS that indicate a reception error. */ +#define nwRX_STATUS_ERROR_BITS \ + ( RDES_CE /* CRC Error */ | \ + RDES_RE /* Receive Error */ | \ + RDES_DE /* Descriptor Error */ | \ + RDES_RWT /* Receive Watchdog Timeout */ | \ + RDES_LC /* Late Collision */ | \ + RDES_OE /* Overflow Error */ | \ + RDES_SAF /* Source Address Filter Fail */ | \ + RDES_AFM /* Destination Address Filter Fail */ | \ + RDES_LE /* Length Error */ ) + +/* Define the EMAC status bits that should trigger an interrupt. */ +#define nwDMA_INTERRUPT_MASK \ + ( DMA_IE_TIE /* Transmit interrupt enable */ | \ + DMA_IE_TSE /* Transmit stopped enable */ | \ + DMA_IE_OVE /* Overflow interrupt enable */ | \ + DMA_IE_RIE /* Receive interrupt enable */ | \ + DMA_IE_NIE /* Normal interrupt summary enable */ | \ + DMA_IE_AIE /* Abnormal interrupt summary enable */ | \ + DMA_IE_RUE /* Receive buffer unavailable enable */ | \ + DMA_IE_UNE /* Underflow interrupt enable. */ | \ + DMA_IE_TJE /* Transmit jabber timeout enable */ | \ + DMA_IE_RSE /* Received stopped enable */ | \ + DMA_IE_RWE /* Receive watchdog timeout enable */ | \ + DMA_IE_FBE )/* Fatal bus error enable */ + +/* Interrupt events to process. Currently only the RX/TX events are processed +although code for other events is included to allow for possible future +expansion. */ +#define EMAC_IF_RX_EVENT 1UL +#define EMAC_IF_TX_EVENT 2UL +#define EMAC_IF_ERR_EVENT 4UL +#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT ) + + /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet + driver will filter incoming packets and only pass the stack those packets it + considers need processing. */ + #if( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 ) + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer + #else + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) ) + #endif + +#if( ipconfigZERO_COPY_RX_DRIVER == 0 ) || ( ipconfigZERO_COPY_TX_DRIVER == 0 ) + #warning It is adviced to enable both macros +#endif + +#ifndef configPLACE_IN_SECTION_RAM + #define configPLACE_IN_SECTION_RAM +/* + #define configPLACE_IN_SECTION_RAM __attribute__ ((section(".ramfunc"))) +*/ +#endif + +/*-----------------------------------------------------------*/ + +/* + * Delay function passed into the library. The implementation uses FreeRTOS + * calls so the scheduler must be started before the driver can be used. + */ +static void prvDelay( uint32_t ulMilliSeconds ); + +/* + * Initialises the Tx and Rx descriptors respectively. + */ +static void prvSetupTxDescriptors( void ); +static void prvSetupRxDescriptors( void ); + +/* + * A task that processes received frames. + */ +static void prvEMACHandlerTask( void *pvParameters ); + +/* + * Sets up the MAC with the results of an auto-negotiation. + */ +static BaseType_t prvSetLinkSpeed( void ); + +/* + * Generates a CRC for a MAC address that is then used to generate a hash index. + */ +static uint32_t prvGenerateCRC32( const uint8_t *ucAddress ); + +/* + * Generates a hash index when setting a filter to permit a MAC address. + */ +static uint32_t prvGetHashIndex( const uint8_t *ucAddress ); + +/* + * Update the hash table to allow a MAC address. + */ +static void prvAddMACAddress( const uint8_t* ucMacAddress ); + +/* + * Sometimes the DMA will report received data as being longer than the actual + * received from length. This function checks the reported length and corrects + * if if necessary. + */ +static void prvRemoveTrailingBytes( NetworkBufferDescriptor_t *pxDescriptor ); + +/*-----------------------------------------------------------*/ + +/* Bit map of outstanding ETH interrupt events for processing. Currently only +the Rx and Tx interrupt is handled, although code is included for other events +to enable future expansion. */ +static volatile uint32_t ulISREvents; + +/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */ +static uint32_t ulPHYLinkStatus = 0; + +/* Tx descriptors and index. */ +static ENET_ENHTXDESC_T xDMATxDescriptors[ configNUM_TX_DESCRIPTORS ]; + +/* ulNextFreeTxDescriptor is declared volatile, because it is accessed from +to different tasks. */ +static volatile uint32_t ulNextFreeTxDescriptor; +static uint32_t ulTxDescriptorToClear; + +/* Rx descriptors and index. */ +static ENET_ENHRXDESC_T xDMARxDescriptors[ configNUM_RX_DESCRIPTORS ]; +static uint32_t ulNextRxDescriptorToProcess; + +/* Must be defined externally - the demo applications define this in main.c. */ +extern uint8_t ucMACAddress[ 6 ]; + +/* The handle of the task that processes Rx packets. The handle is required so +the task can be notified when new packets arrive. */ +static TaskHandle_t xRxHanderTask = NULL; + +#if( ipconfigUSE_LLMNR == 1 ) + static const uint8_t xLLMNR_MACAddress[] = { '\x01', '\x00', '\x5E', '\x00', '\x00', '\xFC' }; +#endif /* ipconfigUSE_LLMNR == 1 */ + +/* xTXDescriptorSemaphore is a counting semaphore with +a maximum count of ETH_TXBUFNB, which is the number of +DMA TX descriptors. */ +static SemaphoreHandle_t xTXDescriptorSemaphore = NULL; + +/*-----------------------------------------------------------*/ + + +BaseType_t xNetworkInterfaceInitialise( void ) +{ +BaseType_t xReturn = pdPASS; + + /* The interrupt will be turned on when a link is established. */ + NVIC_DisableIRQ( ETHERNET_IRQn ); + + /* Disable receive and transmit DMA processes. */ + LPC_ETHERNET->DMA_OP_MODE &= ~( DMA_OM_ST | DMA_OM_SR ); + + /* Disable packet reception. */ + LPC_ETHERNET->MAC_CONFIG &= ~( MAC_CFG_RE | MAC_CFG_TE ); + + /* Call the LPCOpen function to initialise the hardware. */ + Chip_ENET_Init( LPC_ETHERNET ); + + /* Save MAC address. */ + Chip_ENET_SetADDR( LPC_ETHERNET, ucMACAddress ); + + /* Clear all MAC address hash entries. */ + LPC_ETHERNET->MAC_HASHTABLE_HIGH = 0; + LPC_ETHERNET->MAC_HASHTABLE_LOW = 0; + + #if( ipconfigUSE_LLMNR == 1 ) + { + prvAddMACAddress( xLLMNR_MACAddress ); + } + #endif /* ipconfigUSE_LLMNR == 1 */ + + /* Promiscuous flag (PR) and Receive All flag (RA) set to zero. The + registers MAC_HASHTABLE_[LOW|HIGH] will be loaded to allow certain + multi-cast addresses. */ + LPC_ETHERNET->MAC_FRAME_FILTER = MAC_FF_HMC; + + #if( configUSE_RMII == 1 ) + { + if( lpc_phy_init( pdTRUE, prvDelay ) != SUCCESS ) + { + xReturn = pdFAIL; + } + } + #else + { + #warning This path has not been tested. + if( lpc_phy_init( pdFALSE, prvDelay ) != SUCCESS ) + { + xReturn = pdFAIL; + } + } + #endif + + if( xReturn == pdPASS ) + { + /* Guard against the task being created more than once and the + descriptors being initialised more than once. */ + if( xRxHanderTask == NULL ) + { + xReturn = xTaskCreate( prvEMACHandlerTask, "EMAC", nwRX_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xRxHanderTask ); + configASSERT( xReturn ); + } + + if( xTXDescriptorSemaphore == NULL ) + { + /* Create a counting semaphore, with a value of 'configNUM_TX_DESCRIPTORS' + and a maximum of 'configNUM_TX_DESCRIPTORS'. */ + xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) configNUM_TX_DESCRIPTORS, ( UBaseType_t ) configNUM_TX_DESCRIPTORS ); + configASSERT( xTXDescriptorSemaphore ); + } + + /* Enable MAC interrupts. */ + LPC_ETHERNET->DMA_INT_EN = nwDMA_INTERRUPT_MASK; + } + + if( xReturn != pdFAIL ) + { + /* Auto-negotiate was already started. Wait for it to complete. */ + xReturn = prvSetLinkSpeed(); + + if( xReturn == pdPASS ) + { + /* Initialise the descriptors. */ + prvSetupTxDescriptors(); + prvSetupRxDescriptors(); + + /* Clear all interrupts. */ + LPC_ETHERNET->DMA_STAT = DMA_ST_ALL; + + /* Enable receive and transmit DMA processes. */ + LPC_ETHERNET->DMA_OP_MODE |= DMA_OM_ST | DMA_OM_SR; + + /* Set Receiver / Transmitter Enable. */ + LPC_ETHERNET->MAC_CONFIG |= MAC_CFG_RE | MAC_CFG_TE; + + /* Start receive polling. */ + LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1; + + /* Enable interrupts in the NVIC. */ + NVIC_SetPriority( ETHERNET_IRQn, configMAC_INTERRUPT_PRIORITY ); + NVIC_EnableIRQ( ETHERNET_IRQn ); + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +#define niBUFFER_1_PACKET_SIZE 1536 + +static __attribute__ ((section("._ramAHB32"))) uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) ); + +void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) +{ + +uint8_t *ucRAMBuffer = ucNetworkPackets; +uint32_t ul; + + for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ ) + { + pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING; + *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) ); + ucRAMBuffer += niBUFFER_1_PACKET_SIZE; + } +} +/*-----------------------------------------------------------*/ + +configPLACE_IN_SECTION_RAM +static void vClearTXBuffers() +{ +uint32_t ulLastDescriptor = ulNextFreeTxDescriptor; +size_t uxCount = ( ( size_t ) configNUM_TX_DESCRIPTORS ) - uxSemaphoreGetCount( xTXDescriptorSemaphore ); +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + NetworkBufferDescriptor_t *pxNetworkBuffer; + uint8_t *ucPayLoad; +#endif + + /* This function is called after a TX-completion interrupt. + It will release each Network Buffer used in xNetworkInterfaceOutput(). + 'uxCount' represents the number of descriptors given to DMA for transmission. + After sending a packet, the DMA will clear the 'TDES_OWN' bit. */ + while( ( uxCount > ( size_t ) 0u ) && ( ( xDMATxDescriptors[ ulTxDescriptorToClear ].CTRLSTAT & TDES_OWN ) == 0 ) ) + { + if( ( ulTxDescriptorToClear == ulLastDescriptor ) && ( uxCount != ( size_t ) configNUM_TX_DESCRIPTORS ) ) + { + break; + } + + + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + ucPayLoad = ( uint8_t * )xDMATxDescriptors[ ulTxDescriptorToClear ].B1ADD; + if( ucPayLoad != NULL ) + { + /* B1ADD points to a pucEthernetBuffer of a Network Buffer descriptor. */ + pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad ); + + configASSERT( pxNetworkBuffer != NULL ); + + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ; + xDMATxDescriptors[ ulTxDescriptorToClear ].B1ADD = ( uint32_t )0u; + } + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + + /* Move onto the next descriptor, wrapping if necessary. */ + ulTxDescriptorToClear++; + if( ulTxDescriptorToClear >= configNUM_TX_DESCRIPTORS ) + { + ulTxDescriptorToClear = 0; + } + + uxCount--; + /* Tell the counting semaphore that one more TX descriptor is available. */ + xSemaphoreGive( xTXDescriptorSemaphore ); + } +} + +/*-----------------------------------------------------------*/ + +configPLACE_IN_SECTION_RAM +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend ) +{ +BaseType_t xReturn = pdFAIL; +const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50 ); + + /* Attempt to obtain access to a Tx descriptor. */ + do + { + if( xTXDescriptorSemaphore == NULL ) + { + break; + } + if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS ) + { + /* Time-out waiting for a free TX descriptor. */ + break; + } + + /* If the descriptor is still owned by the DMA it can't be used. */ + if( ( xDMATxDescriptors[ ulNextFreeTxDescriptor ].CTRLSTAT & TDES_OWN ) != 0 ) + { + /* The semaphore was taken, the TX DMA-descriptor is still not available. + Actually that should not occur, the 'TDES_OWN' was already confirmed low in vClearTXBuffers(). */ + xSemaphoreGive( xTXDescriptorSemaphore ); + } + else + { + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + /* bReleaseAfterSend should always be set when using the zero + copy driver. */ + configASSERT( bReleaseAfterSend != pdFALSE ); + + /* The DMA's descriptor to point directly to the data in the + network buffer descriptor. The data is not copied. */ + xDMATxDescriptors[ ulNextFreeTxDescriptor ].B1ADD = ( uint32_t ) pxDescriptor->pucEthernetBuffer; + + /* The DMA descriptor will 'own' this Network Buffer, + until it has been sent. So don't release it now. */ + bReleaseAfterSend = false; + } + #else + { + /* The data is copied from the network buffer descriptor into + the DMA's descriptor. */ + memcpy( ( void * ) xDMATxDescriptors[ ulNextFreeTxDescriptor ].B1ADD, ( void * ) pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength ); + } + #endif + + xDMATxDescriptors[ ulNextFreeTxDescriptor ].BSIZE = ( uint32_t ) TDES_ENH_BS1( pxDescriptor->xDataLength ); + + /* This descriptor is given back to the DMA. */ + xDMATxDescriptors[ ulNextFreeTxDescriptor ].CTRLSTAT |= TDES_OWN; + + /* Ensure the DMA is polling Tx descriptors. */ + LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1; + + iptraceNETWORK_INTERFACE_TRANSMIT(); + + /* Move onto the next descriptor, wrapping if necessary. */ + ulNextFreeTxDescriptor++; + if( ulNextFreeTxDescriptor >= configNUM_TX_DESCRIPTORS ) + { + ulNextFreeTxDescriptor = 0; + } + + /* The Tx has been initiated. */ + xReturn = pdPASS; + } + } while( 0 ); + + /* The buffer has been sent so can be released. */ + if( bReleaseAfterSend != pdFALSE ) + { + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static void prvDelay( uint32_t ulMilliSeconds ) +{ + /* Ensure the scheduler was started before attempting to use the scheduler to + create a delay. */ + configASSERT( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING ); + + vTaskDelay( pdMS_TO_TICKS( ulMilliSeconds ) ); +} +/*-----------------------------------------------------------*/ + +static void prvSetupTxDescriptors( void ) +{ +BaseType_t x; + + /* Start with Tx descriptors clear. */ + memset( ( void * ) xDMATxDescriptors, 0, sizeof( xDMATxDescriptors ) ); + + /* Index to the next Tx descriptor to use. */ + ulNextFreeTxDescriptor = 0ul; + + /* Index to the next Tx descriptor to clear ( after transmission ). */ + ulTxDescriptorToClear = 0ul; + + for( x = 0; x < configNUM_TX_DESCRIPTORS; x++ ) + { + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + /* Nothing to do, B1ADD will be set when data is ready to transmit. + Currently the memset above will have set it to NULL. */ + } + #else + { + /* Allocate a buffer to the Tx descriptor. This is the most basic + way of creating a driver as the data is then copied into the + buffer. */ + xDMATxDescriptors[ x ].B1ADD = ( uint32_t ) pvPortMalloc( ipTOTAL_ETHERNET_FRAME_SIZE ); + + /* Use an assert to check the allocation as +TCP applications will + often not use a malloc() failed hook as the TCP stack will recover + from allocation failures. */ + configASSERT( xDMATxDescriptors[ x ].B1ADD ); + } + #endif + + /* Buffers hold an entire frame so all buffers are both the start and + end of a frame. */ + /* TDES_ENH_TCH Second Address Chained. */ + /* TDES_ENH_CIC(n) Checksum Insertion Control, tried but it does not work for the LPC18xx... */ + /* TDES_ENH_FS First Segment. */ + /* TDES_ENH_LS Last Segment. */ + /* TDES_ENH_IC Interrupt on Completion. */ + xDMATxDescriptors[ x ].CTRLSTAT = TDES_ENH_TCH | TDES_ENH_CIC( 3 ) | TDES_ENH_FS | TDES_ENH_LS | TDES_ENH_IC; + xDMATxDescriptors[ x ].B2ADD = ( uint32_t ) &xDMATxDescriptors[ x + 1 ]; + } + + xDMATxDescriptors[ configNUM_TX_DESCRIPTORS - 1 ].CTRLSTAT |= TDES_ENH_TER; + xDMATxDescriptors[ configNUM_TX_DESCRIPTORS - 1 ].B2ADD = ( uint32_t ) &xDMATxDescriptors[ 0 ]; + + /* Point the DMA to the base of the descriptor list. */ + LPC_ETHERNET->DMA_TRANS_DES_ADDR = ( uint32_t ) xDMATxDescriptors; +} +/*-----------------------------------------------------------*/ + +static void prvSetupRxDescriptors( void ) +{ +BaseType_t x; +#if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + NetworkBufferDescriptor_t *pxNetworkBuffer; +#endif + + /* Index to the next Rx descriptor to use. */ + ulNextRxDescriptorToProcess = 0; + + /* Clear RX descriptor list. */ + memset( ( void * ) xDMARxDescriptors, 0, sizeof( xDMARxDescriptors ) ); + + for( x = 0; x < configNUM_RX_DESCRIPTORS; x++ ) + { + /* Allocate a buffer of the largest possible frame size as it is not + known what size received frames will be. */ + + #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + { + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, 0 ); + + /* During start-up there should be enough Network Buffers available, + so it is safe to use configASSERT(). + In case this assert fails, please check: configNUM_RX_DESCRIPTORS, + ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, and in case BufferAllocation_2.c + is included, check the amount of available heap. */ + configASSERT( pxNetworkBuffer != NULL ); + + /* Pass the actual buffer to DMA. */ + xDMARxDescriptors[ x ].B1ADD = ( uint32_t ) pxNetworkBuffer->pucEthernetBuffer; + } + #else + { + /* All DMA descriptors are populated with permanent memory blocks. + Their contents will be copy to Network Buffers. */ + xDMARxDescriptors[ x ].B1ADD = ( uint32_t ) pvPortMalloc( ipTOTAL_ETHERNET_FRAME_SIZE ); + } + #endif /* ipconfigZERO_COPY_RX_DRIVER */ + + /* Use an assert to check the allocation as +TCP applications will often + not use a malloc failed hook as the TCP stack will recover from + allocation failures. */ + configASSERT( xDMARxDescriptors[ x ].B1ADD ); + + xDMARxDescriptors[ x ].B2ADD = ( uint32_t ) &( xDMARxDescriptors[ x + 1 ] ); + xDMARxDescriptors[ x ].CTRL = ( uint32_t ) RDES_ENH_BS1( ipTOTAL_ETHERNET_FRAME_SIZE ) | RDES_ENH_RCH; + + /* The descriptor is available for use by the DMA. */ + xDMARxDescriptors[ x ].STATUS = RDES_OWN; + } + + /* RDES_ENH_RER Receive End of Ring. */ + xDMARxDescriptors[ ( configNUM_RX_DESCRIPTORS - 1 ) ].CTRL |= RDES_ENH_RER; + xDMARxDescriptors[ configNUM_RX_DESCRIPTORS - 1 ].B2ADD = ( uint32_t ) &( xDMARxDescriptors[ 0 ] ); + + /* Point the DMA to the base of the descriptor list. */ + LPC_ETHERNET->DMA_REC_DES_ADDR = ( uint32_t ) xDMARxDescriptors; +} +/*-----------------------------------------------------------*/ +configPLACE_IN_SECTION_RAM +static void prvRemoveTrailingBytes( NetworkBufferDescriptor_t *pxDescriptor ) +{ +size_t xExpectedLength; +IPPacket_t *pxIPPacket; + + pxIPPacket = ( IPPacket_t * ) pxDescriptor->pucEthernetBuffer; + /* Look at the actual length of the packet, translate it to a host-endial notation. */ + xExpectedLength = sizeof( EthernetHeader_t ) + ( size_t ) FreeRTOS_htons( pxIPPacket->xIPHeader.usLength ); + + if( xExpectedLength == ( pxDescriptor->xDataLength + 4 ) ) + { + pxDescriptor->xDataLength -= 4; + } + else + { + if( pxDescriptor->xDataLength > xExpectedLength ) + { + pxDescriptor->xDataLength = ( size_t ) xExpectedLength; + } + } +} +/*-----------------------------------------------------------*/ +configPLACE_IN_SECTION_RAM +BaseType_t xGetPhyLinkStatus( void ) +{ +BaseType_t xReturn; + + if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) == 0 ) + { + xReturn = pdFALSE; + } + else + { + xReturn = pdTRUE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +uint32_t ulDataAvailable; + +configPLACE_IN_SECTION_RAM +static BaseType_t prvNetworkInterfaceInput() +{ +BaseType_t xResult = pdFALSE; +uint32_t ulStatus; +eFrameProcessingResult_t eResult; +const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 ); +const UBaseType_t uxMinimumBuffersRemaining = 3UL; +uint16_t usLength; +NetworkBufferDescriptor_t *pxDescriptor; +#if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + NetworkBufferDescriptor_t *pxNewDescriptor; +#endif /* ipconfigZERO_COPY_RX_DRIVER */ +#if( ipconfigUSE_LINKED_RX_MESSAGES == 0 ) + IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; +#endif + + /* Process each descriptor that is not still in use by the DMA. */ + ulStatus = xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS; + if( ( ulStatus & RDES_OWN ) == 0 ) + { + /* Check packet for errors */ + if( ( ulStatus & nwRX_STATUS_ERROR_BITS ) != 0 ) + { + /* There is some reception error. */ + intCount[ 3 ]++; + /* Clear error bits. */ + ulStatus &= ~( ( uint32_t )nwRX_STATUS_ERROR_BITS ); + } + else + { + xResult++; + + eResult = ipCONSIDER_FRAME_FOR_PROCESSING( ( const uint8_t * const ) ( xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD ) ); + if( eResult == eProcessBuffer ) + { + if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) == 0 ) + { + ulPHYLinkStatus |= PHY_LINK_CONNECTED; + FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d (message received)\n", ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 ) ); + } + + #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + if( uxGetNumberOfFreeNetworkBuffers() > uxMinimumBuffersRemaining ) + { + pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xDescriptorWaitTime ); + } + else + { + /* Too risky to allocate a new Network Buffer. */ + pxNewDescriptor = NULL; + } + if( pxNewDescriptor != NULL ) + #else + if( uxGetNumberOfFreeNetworkBuffers() > uxMinimumBuffersRemaining ) + #endif /* ipconfigZERO_COPY_RX_DRIVER */ + { + #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + const uint8_t *pucBuffer; + #endif + + /* Get the actual length. */ + usLength = RDES_FLMSK( ulStatus ); + + #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + { + /* Replace the character buffer 'B1ADD'. */ + pucBuffer = ( const uint8_t * const ) ( xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD ); + xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD = ( uint32_t ) pxNewDescriptor->pucEthernetBuffer; + + /* 'B1ADD' contained the address of a 'pucEthernetBuffer' that + belongs to a Network Buffer. Find the original Network Buffer. */ + pxDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer ); + /* This zero-copy driver makes sure that every 'xDMARxDescriptors' contains + a reference to a Network Buffer at any time. + In case it runs out of Network Buffers, a DMA buffer won't be replaced, + and the received messages is dropped. */ + configASSERT( pxDescriptor != NULL ); + } + #else + { + /* Create a buffer of exactly the required length. */ + pxDescriptor = pxGetNetworkBufferWithDescriptor( usLength, xDescriptorWaitTime ); + } + #endif /* ipconfigZERO_COPY_RX_DRIVER */ + + if( pxDescriptor != NULL ) + { + pxDescriptor->xDataLength = ( size_t ) usLength; + #if( ipconfigZERO_COPY_RX_DRIVER == 0 ) + { + /* Copy the data into the allocated buffer. */ + memcpy( ( void * ) pxDescriptor->pucEthernetBuffer, ( void * ) xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD, usLength ); + } + #endif /* ipconfigZERO_COPY_RX_DRIVER */ + /* It is possible that more data was copied than + actually makes up the frame. If this is the case + adjust the length to remove any trailing bytes. */ + prvRemoveTrailingBytes( pxDescriptor ); + + /* Pass the data to the TCP/IP task for processing. */ + xRxEvent.pvData = ( void * ) pxDescriptor; + if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE ) + { + /* Could not send the descriptor into the TCP/IP + stack, it must be released. */ + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + } + else + { + iptraceNETWORK_INTERFACE_RECEIVE(); + + /* The data that was available at the top of this + loop has been sent, so is no longer available. */ + ulDataAvailable = pdFALSE; + } + } + } + } + else + { + /* The packet is discarded as uninteresting. */ + ulDataAvailable = pdFALSE; + } + /* Got here because received data was sent to the IP task or the + data contained an error and was discarded. Give the descriptor + back to the DMA. */ + xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS = ulStatus | RDES_OWN; + + /* Move onto the next descriptor. */ + ulNextRxDescriptorToProcess++; + if( ulNextRxDescriptorToProcess >= configNUM_RX_DESCRIPTORS ) + { + ulNextRxDescriptorToProcess = 0; + } + + ulStatus = xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS; + } /* if( ( ulStatus & nwRX_STATUS_ERROR_BITS ) != 0 ) */ + } /* if( ( ulStatus & RDES_OWN ) == 0 ) */ + + /* Restart receive polling. */ + LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1; + + return xResult; +} +/*-----------------------------------------------------------*/ + +configPLACE_IN_SECTION_RAM +void NETWORK_IRQHandler( void ) +{ +BaseType_t xHigherPriorityTaskWoken = pdFALSE; +uint32_t ulDMAStatus; +const uint32_t ulRxInterruptMask = + DMA_ST_RI | /* Receive interrupt */ + DMA_ST_RU; /* Receive buffer unavailable */ +const uint32_t ulTxInterruptMask = + DMA_ST_TI | /* Transmit interrupt */ + DMA_ST_TPS; /* Transmit process stopped */ + + configASSERT( xRxHanderTask ); + + /* Get pending interrupts. */ + ulDMAStatus = LPC_ETHERNET->DMA_STAT; + + /* RX group interrupt(s). */ + if( ( ulDMAStatus & ulRxInterruptMask ) != 0x00 ) + { + /* Remember that an RX event has happened. */ + ulISREvents |= EMAC_IF_RX_EVENT; + vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken ); + intCount[ 0 ]++; + } + + /* TX group interrupt(s). */ + if( ( ulDMAStatus & ulTxInterruptMask ) != 0x00 ) + { + /* Remember that a TX event has happened. */ + ulISREvents |= EMAC_IF_TX_EVENT; + vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken ); + intCount[ 1 ]++; + } + + /* Test for 'Abnormal interrupt summary'. */ + if( ( ulDMAStatus & DMA_ST_AIE ) != 0x00 ) + { + /* The trace macro must be written such that it can be called from + an interrupt. */ + iptraceETHERNET_RX_EVENT_LOST(); + } + + /* Clear pending interrupts */ + LPC_ETHERNET->DMA_STAT = ulDMAStatus; + + /* Context switch needed? */ + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvSetLinkSpeed( void ) +{ +BaseType_t xReturn = pdFAIL; +TickType_t xTimeOnEntering; +uint32_t ulPhyStatus; +const TickType_t xAutoNegotiateDelay = pdMS_TO_TICKS( 5000UL ); + + /* Ensure polling does not starve lower priority tasks by temporarily + setting the priority of this task to that of the idle task. */ + vTaskPrioritySet( NULL, tskIDLE_PRIORITY ); + + xTimeOnEntering = xTaskGetTickCount(); + do + { + ulPhyStatus = lpcPHYStsPoll(); + if( ( ulPhyStatus & PHY_LINK_CONNECTED ) != 0x00 ) + { + /* Set interface speed and duplex. */ + if( ( ulPhyStatus & PHY_LINK_SPEED100 ) != 0x00 ) + { + Chip_ENET_SetSpeed( LPC_ETHERNET, 1 ); + } + else + { + Chip_ENET_SetSpeed( LPC_ETHERNET, 0 ); + } + + if( ( ulPhyStatus & PHY_LINK_FULLDUPLX ) != 0x00 ) + { + Chip_ENET_SetDuplex( LPC_ETHERNET, true ); + } + else + { + Chip_ENET_SetDuplex( LPC_ETHERNET, false ); + } + + xReturn = pdPASS; + break; + } + } while( ( xTaskGetTickCount() - xTimeOnEntering ) < xAutoNegotiateDelay ); + + /* Reset the priority of this task back to its original value. */ + vTaskPrioritySet( NULL, ipconfigIP_TASK_PRIORITY ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static uint32_t prvGenerateCRC32( const uint8_t *ucAddress ) +{ +unsigned int j; +const uint32_t Polynomial = 0xEDB88320; +uint32_t crc = ~0ul; +const uint8_t *pucCurrent = ( const uint8_t * ) ucAddress; +const uint8_t *pucLast = pucCurrent + 6; + + /* Calculate normal CRC32 */ + while( pucCurrent < pucLast ) + { + crc ^= *( pucCurrent++ ); + for( j = 0; j < 8; j++ ) + { + if( ( crc & 1 ) != 0 ) + { + crc = (crc >> 1) ^ Polynomial; + } + else + { + crc >>= 1; + } + } + } + return ~crc; +} +/*-----------------------------------------------------------*/ + +static uint32_t prvGetHashIndex( const uint8_t *ucAddress ) +{ +uint32_t ulCrc = prvGenerateCRC32( ucAddress ); +uint32_t ulIndex = 0ul; +BaseType_t xCount = 6; + + /* Take the lowest 6 bits of the CRC32 and reverse them */ + while( xCount-- ) + { + ulIndex <<= 1; + ulIndex |= ( ulCrc & 1 ); + ulCrc >>= 1; + } + + /* This is the has value of 'ucAddress' */ + return ulIndex; +} +/*-----------------------------------------------------------*/ + +static void prvAddMACAddress( const uint8_t* ucMacAddress ) +{ +BaseType_t xIndex; + + xIndex = prvGetHashIndex( ucMacAddress ); + if( xIndex >= 32 ) + { + LPC_ETHERNET->MAC_HASHTABLE_HIGH |= ( 1u << ( xIndex - 32 ) ); + } + else + { + LPC_ETHERNET->MAC_HASHTABLE_LOW |= ( 1u << xIndex ); + } +} +/*-----------------------------------------------------------*/ + +configPLACE_IN_SECTION_RAM +static void prvEMACHandlerTask( void *pvParameters ) +{ +TimeOut_t xPhyTime; +TickType_t xPhyRemTime; +UBaseType_t uxLastMinBufferCount = 0; +UBaseType_t uxCurrentCount; +BaseType_t xResult = 0; +uint32_t ulStatus; +const TickType_t xBlockTime = pdMS_TO_TICKS( 5000ul ); + + /* Remove compiler warning about unused parameter. */ + ( void ) pvParameters; + + /* A possibility to set some additional task properties. */ + iptraceEMAC_TASK_STARTING(); + + vTaskSetTimeOutState( &xPhyTime ); + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS ); + + for( ;; ) + { + uxCurrentCount = uxGetMinimumFreeNetworkBuffers(); + if( uxLastMinBufferCount != uxCurrentCount ) + { + /* The logging produced below may be helpful + while tuning +TCP: see how many buffers are in use. */ + uxLastMinBufferCount = uxCurrentCount; + FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n", + uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) ); + } + + #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + { + static UBaseType_t uxLastMinQueueSpace = 0; + + uxCurrentCount = uxGetMinimumIPQueueSpace(); + if( uxLastMinQueueSpace != uxCurrentCount ) + { + /* The logging produced below may be helpful + while tuning +TCP: see how many buffers are in use. */ + uxLastMinQueueSpace = uxCurrentCount; + FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) ); + } + } + #endif /* ipconfigCHECK_IP_QUEUE_SPACE */ + + ulTaskNotifyTake( pdTRUE, xBlockTime ); + + xResult = ( BaseType_t ) 0; + + if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 ) + { + /* Code to release TX buffers if zero-copy is used. */ + ulISREvents &= ~EMAC_IF_TX_EVENT; + { + /* Check if DMA packets have been delivered. */ + vClearTXBuffers(); + } + } + + if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 ) + { + ulISREvents &= ~EMAC_IF_RX_EVENT; + + xResult = prvNetworkInterfaceInput(); + if( xResult > 0 ) + { + while( prvNetworkInterfaceInput() > 0 ) + { + } + } + } + + if( xResult > 0 ) + { + /* A packet was received. No need to check for the PHY status now, + but set a timer to check it later on. */ + vTaskSetTimeOutState( &xPhyTime ); + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS ); + xResult = 0; + } + else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ) + { + ulStatus = lpcPHYStsPoll(); + + if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != ( ulStatus & PHY_LINK_CONNECTED ) ) + { + ulPHYLinkStatus = ulStatus; + FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d (polled PHY)\n", ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 ) ); + } + + vTaskSetTimeOutState( &xPhyTime ); + if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 ) + { + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS ); + } + else + { + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS ); + } + } + } +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/ReadMe.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/ReadMe.txt new file mode 100644 index 000000000..86a7f9121 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/ReadMe.txt @@ -0,0 +1,3 @@ +NetworkInterface.c: +Requires NXP's LPCOpen library and was developed on an LPC1830 and LPC1835 Xplorer +boards from NGX. \ No newline at end of file diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/README_DRIVER_DISCLAIMER.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/README_DRIVER_DISCLAIMER.txt new file mode 100644 index 000000000..347bb113e --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/README_DRIVER_DISCLAIMER.txt @@ -0,0 +1,10 @@ +Network drivers are provided as examples only, and do not form part of the +FreeRTOS+TCP stack itself. They: + + + May be based on driver code provided by the chip vendors, + + May not have been tested in all possible configurations, + + Will not necessarily be optimised. + + May have a dependency on a particular PHY part number. + + May not necessarily comply with any particular coding standard. + + May have dependencies on chip company libraries. + + May include other hardware board dependencies. diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c new file mode 100644 index 000000000..44d19f3a9 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/SH2A/NetworkInterface.c @@ -0,0 +1,118 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_Sockets.h" +#include "NetworkBufferManagement.h" + +/* Hardware includes. */ +#include "hwEthernet.h" + +/* Demo includes. */ +#include "NetworkInterface.h" + +#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1 + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer +#else + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) ) +#endif + +/* When a packet is ready to be sent, if it cannot be sent immediately then the +task performing the transmit will block for niTX_BUFFER_FREE_WAIT +milliseconds. It will do this a maximum of niMAX_TX_ATTEMPTS before giving +up. */ +#define niTX_BUFFER_FREE_WAIT ( ( TickType_t ) 2UL / portTICK_PERIOD_MS ) +#define niMAX_TX_ATTEMPTS ( 5 ) + +/* The length of the queue used to send interrupt status words from the +interrupt handler to the deferred handler task. */ +#define niINTERRUPT_QUEUE_LENGTH ( 10 ) + +/*-----------------------------------------------------------*/ + +/* + * A deferred interrupt handler task that processes + */ +extern void vEMACHandlerTask( void *pvParameters ); + +/*-----------------------------------------------------------*/ + +/* The queue used to communicate Ethernet events with the IP task. */ +extern QueueHandle_t xNetworkEventQueue; + +/* The semaphore used to wake the deferred interrupt handler task when an Rx +interrupt is received. */ +SemaphoreHandle_t xEMACRxEventSemaphore = NULL; +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceInitialise( void ) +{ +BaseType_t xStatus, xReturn; +extern uint8_t ucMACAddress[ 6 ]; + + /* Initialise the MAC. */ + vInitEmac(); + + while( lEMACWaitForLink() != pdPASS ) + { + vTaskDelay( 20 ); + } + + vSemaphoreCreateBinary( xEMACRxEventSemaphore ); + configASSERT( xEMACRxEventSemaphore ); + + /* The handler task is created at the highest possible priority to + ensure the interrupt handler can return directly to it. */ + xTaskCreate( vEMACHandlerTask, "EMAC", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL ); + xReturn = pdPASS; + + return xReturn; +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ +extern void vEMACCopyWrite( uint8_t * pucBuffer, uint16_t usLength ); + + vEMACCopyWrite( pxNetworkBuffer->pucBuffer, pxNetworkBuffer->xDataLength ); + + /* Finished with the network buffer. */ + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/NetworkInterface.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/NetworkInterface.c new file mode 100644 index 000000000..ec58eb36e --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/NetworkInterface.c @@ -0,0 +1,1193 @@ +/* + * Some constants, hardware definitions and comments taken from ST's HAL driver + * library, COPYRIGHT(c) 2015 STMicroelectronics. + */ + +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_DNS.h" +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" + +#include "phyHandling.h" + +/* ST includes. */ +#ifdef STM32F7xx + #include "stm32f7xx_hal.h" +#else + #include "stm32f4xx_hal.h" +#endif + +/* Interrupt events to process. Currently only the Rx event is processed +although code for other events is included to allow for possible future +expansion. */ +#define EMAC_IF_RX_EVENT 1UL +#define EMAC_IF_TX_EVENT 2UL +#define EMAC_IF_ERR_EVENT 4UL +#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT ) + +#define ETH_DMA_ALL_INTS \ + ( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | ETH_DMA_IT_ER | \ + ETH_DMA_IT_FBE | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \ + ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T ) + + + +#define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */ + +/* + * Most users will want a PHY that negotiates about + * the connection properties: speed, dmix and duplex. + * On some rare cases, you want to select what is being + * advertised, properties like MDIX and duplex. + */ + +#if !defined( ipconfigETHERNET_AN_ENABLE ) + /* Enable auto-negotiation */ + #define ipconfigETHERNET_AN_ENABLE 1 +#endif + +#if !defined( ipconfigETHERNET_AUTO_CROSS_ENABLE ) + #define ipconfigETHERNET_AUTO_CROSS_ENABLE 1 +#endif + +#if( ipconfigETHERNET_AN_ENABLE == 0 ) + /* + * The following three defines are only used in case there + * is no auto-negotiation. + */ + #if !defined( ipconfigETHERNET_CROSSED_LINK ) + #define ipconfigETHERNET_CROSSED_LINK 1 + #endif + + #if !defined( ipconfigETHERNET_USE_100MB ) + #define ipconfigETHERNET_USE_100MB 1 + #endif + + #if !defined( ipconfigETHERNET_USE_FULL_DUPLEX ) + #define ipconfigETHERNET_USE_FULL_DUPLEX 1 + #endif +#endif /* ipconfigETHERNET_AN_ENABLE == 0 */ + +/* Default the size of the stack used by the EMAC deferred handler task to twice +the size of the stack used by the idle task - but allow this to be overridden in +FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */ +#ifndef configEMAC_TASK_STACK_SIZE + #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE ) +#endif + +/* Two choices must be made: RMII versus MII, +and the index of the PHY in use ( between 0 and 31 ). */ +#ifndef ipconfigUSE_RMII + #ifdef STM32F7xx + #define ipconfigUSE_RMII 1 + #else + #define ipconfigUSE_RMII 0 + #endif /* STM32F7xx */ +#endif /* ipconfigUSE_RMII */ + +#ifndef ipconfigPHY_INDEX + #ifdef STM32F7xx + #define ipconfigPHY_INDEX 0 + #else + #define ipconfigPHY_INDEX 1 + #endif /* STM32F7xx */ +#endif /* ipconfigPHY_INDEX */ + + +/*-----------------------------------------------------------*/ + +/* + * A deferred interrupt handler task that processes + */ +static void prvEMACHandlerTask( void *pvParameters ); + +/* + * Force a negotiation with the Switch or Router and wait for LS. + */ +static void prvEthernetUpdateConfig( BaseType_t xForce ); + +/* + * See if there is a new packet and forward it to the IP-task. + */ +static BaseType_t prvNetworkInterfaceInput( void ); + +#if( ipconfigUSE_LLMNR != 0 ) + /* + * For LLMNR, an extra MAC-address must be configured to + * be able to receive the multicast messages. + */ + static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr); +#endif + +/* + * Check if a given packet should be accepted. + */ +static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer ); + +/* + * Initialise the TX descriptors. + */ +static void prvDMATxDescListInit( void ); + +/* + * Initialise the RX descriptors. + */ +static void prvDMARxDescListInit( void ); + +/* After packets have been sent, the network +buffers will be released. */ +static void vClearTXBuffers( void ); + +/*-----------------------------------------------------------*/ + +/* Bit map of outstanding ETH interrupt events for processing. Currently only +the Rx interrupt is handled, although code is included for other events to +enable future expansion. */ +static volatile uint32_t ulISREvents; + +#if( ipconfigUSE_LLMNR == 1 ) + static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC }; +#endif + +static EthernetPhy_t xPhyObject; + +/* Ethernet handle. */ +static ETH_HandleTypeDef xETH; + +/* xTXDescriptorSemaphore is a counting semaphore with +a maximum count of ETH_TXBUFNB, which is the number of +DMA TX descriptors. */ +static SemaphoreHandle_t xTXDescriptorSemaphore = NULL; + +/* + * Note: it is adviced to define both + * + * #define ipconfigZERO_COPY_RX_DRIVER 1 + * #define ipconfigZERO_COPY_TX_DRIVER 1 + * + * The method using memcpy is slower and probaly uses more RAM memory. + * The possibility is left in the code just for comparison. + * + * It is adviced to define ETH_TXBUFNB at least 4. Note that no + * TX buffers are allocated in a zero-copy driver. + */ +/* MAC buffers: ---------------------------------------------------------*/ + +/* Put the DMA descriptors in '.first_data'. +This is important for STM32F7, which has an L1 data cache. +The first 64KB of the SRAM is not cached. */ + +/* Ethernet Rx MA Descriptor */ +__attribute__ ((aligned (32))) +__attribute__ ((section(".first_data"))) + ETH_DMADescTypeDef DMARxDscrTab[ ETH_RXBUFNB ]; + +#if( ipconfigZERO_COPY_RX_DRIVER == 0 ) + /* Ethernet Receive Buffer */ + __ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END; +#endif + +/* Ethernet Tx DMA Descriptor */ +__attribute__ ((aligned (32))) +__attribute__ ((section(".first_data"))) + ETH_DMADescTypeDef DMATxDscrTab[ ETH_TXBUFNB ]; + +#if( ipconfigZERO_COPY_TX_DRIVER == 0 ) + /* Ethernet Transmit Buffer */ + __ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END; +#endif + +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + /* DMATxDescToClear points to the next TX DMA descriptor + that must be cleared by vClearTXBuffers(). */ + static __IO ETH_DMADescTypeDef *DMATxDescToClear; +#endif + +/* ucMACAddress as it appears in main.c */ +extern const uint8_t ucMACAddress[ 6 ]; + +/* Holds the handle of the task used as a deferred interrupt processor. The +handle is used so direct notifications can be sent to the task for all EMAC/DMA +related interrupts. */ +static TaskHandle_t xEMACTaskHandle = NULL; + +/* For local use only: describe the PHY's properties: */ +const PhyProperties_t xPHYProperties = +{ + #if( ipconfigETHERNET_AN_ENABLE != 0 ) + .ucSpeed = PHY_SPEED_AUTO, + .ucDuplex = PHY_DUPLEX_AUTO, + #else + #if( ipconfigETHERNET_USE_100MB != 0 ) + .ucSpeed = PHY_SPEED_100, + #else + .ucSpeed = PHY_SPEED_10, + #endif + + #if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 ) + .duplex = PHY_DUPLEX_FULL, + #else + .duplex = PHY_DUPLEX_HALF, + #endif + #endif + + #if( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 ) + .ucMDI_X = PHY_MDIX_AUTO, + #elif( ipconfigETHERNET_CROSSED_LINK != 0 ) + .ucMDI_X = PHY_MDIX_CROSSED, + #else + .ucMDI_X = PHY_MDIX_DIRECT, + #endif +}; + +/*-----------------------------------------------------------*/ + +void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef *heth ) +{ +BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + /* Ethernet RX-Complete callback function, elsewhere declared as weak. */ + ulISREvents |= EMAC_IF_RX_EVENT; + /* Wakeup the prvEMACHandlerTask. */ + if( xEMACTaskHandle != NULL ) + { + vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken ); + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + } +} +/*-----------------------------------------------------------*/ + +void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth ) +{ +BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + /* This call-back is only useful in case packets are being sent + zero-copy. Once they're sent, the buffers will be released + by the function vClearTXBuffers(). */ + ulISREvents |= EMAC_IF_TX_EVENT; + /* Wakeup the prvEMACHandlerTask. */ + if( xEMACTaskHandle != NULL ) + { + vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken ); + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + } + +} +/*-----------------------------------------------------------*/ + +static void vClearTXBuffers() +{ +__IO ETH_DMADescTypeDef *txLastDescriptor = xETH.TxDesc; +size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore ); +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + NetworkBufferDescriptor_t *pxNetworkBuffer; + uint8_t *ucPayLoad; +#endif + + /* This function is called after a TX-completion interrupt. + It will release each Network Buffer used in xNetworkInterfaceOutput(). + 'uxCount' represents the number of descriptors given to DMA for transmission. + After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */ + while( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) ) + { + if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) ) + { + break; + } + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr; + + if( ucPayLoad != NULL ) + { + pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad ); + if( pxNetworkBuffer != NULL ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ; + } + DMATxDescToClear->Buffer1Addr = ( uint32_t )0u; + } + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + + DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr ); + + uxCount--; + /* Tell the counting semaphore that one more TX descriptor is available. */ + xSemaphoreGive( xTXDescriptorSemaphore ); + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceInitialise( void ) +{ +HAL_StatusTypeDef hal_eth_init_status; +BaseType_t xResult; + + if( xEMACTaskHandle == NULL ) + { + if( xTXDescriptorSemaphore == NULL ) + { + xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB ); + configASSERT( xTXDescriptorSemaphore ); + } + + /* Initialise ETH */ + + xETH.Instance = ETH; +//#warning Enable auto-nego again + xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE; +// xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_DISABLE; + xETH.Init.Speed = ETH_SPEED_100M; + xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX; + xETH.Init.PhyAddress = ipconfigPHY_INDEX; + + xETH.Init.MACAddr = ( uint8_t *) ucMACAddress; + xETH.Init.RxMode = ETH_RXINTERRUPT_MODE; + + /* using the ETH_CHECKSUM_BY_HARDWARE option: + both the IP and the protocol checksums will be calculated + by the peripheral. */ + xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE; + + #if( ipconfigUSE_RMII != 0 ) + { + xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII; + } + #else + { + xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII; + } + #endif /* ipconfigUSE_RMII */ + + hal_eth_init_status = HAL_ETH_Init( &xETH ); + + /* Only for inspection by debugger. */ + ( void ) hal_eth_init_status; + + /* Set the TxDesc and RxDesc pointers. */ + xETH.TxDesc = DMATxDscrTab; + xETH.RxDesc = DMARxDscrTab; + + /* Make sure that all unused fields are cleared. */ + memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) ); + memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) ); + + /* Initialize Tx Descriptors list: Chain Mode */ + DMATxDescToClear = DMATxDscrTab; + + /* Initialise TX-descriptors. */ + prvDMATxDescListInit(); + + /* Initialise RX-descriptors. */ + prvDMARxDescListInit(); + + #if( ipconfigUSE_LLMNR != 0 ) + { + /* Program the LLMNR address at index 1. */ + prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress ); + } + #endif + + /* Force a negotiation with the Switch or Router and wait for LS. */ + prvEthernetUpdateConfig( pdTRUE ); + + /* The deferred interrupt handler task is created at the highest + possible priority to ensure the interrupt handler can return directly + to it. The task's handle is stored in xEMACTaskHandle so interrupts can + notify the task when there is something to process. */ + xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle ); + } /* if( xEMACTaskHandle == NULL ) */ + + if( xPhyObject.ulLinkStatusMask != 0 ) + { + xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS; + xResult = pdPASS; + FreeRTOS_printf( ( "Link Status is high\n" ) ) ; + } + else + { + /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running + and it will keep on checking the PHY and set 'ulLinkStatusMask' when necessary. */ + xResult = pdFAIL; + FreeRTOS_printf( ( "Link Status still low\n" ) ) ; + } + /* When returning non-zero, the stack will become active and + start DHCP (in configured) */ + return xResult; +} +/*-----------------------------------------------------------*/ + +static void prvDMATxDescListInit() +{ +ETH_DMADescTypeDef *pxDMADescriptor; +BaseType_t xIndex; + + /* Get the pointer on the first member of the descriptor list */ + pxDMADescriptor = DMATxDscrTab; + + /* Fill each DMA descriptor with the right values */ + for( xIndex = 0; xIndex < ETH_TXBUFNB; xIndex++, pxDMADescriptor++ ) + { + /* Set Second Address Chained bit */ + pxDMADescriptor->Status = ETH_DMATXDESC_TCH; + + #if( ipconfigZERO_COPY_TX_DRIVER == 0 ) + { + /* Set Buffer1 address pointer */ + pxDMADescriptor->Buffer1Addr = ( uint32_t )( Tx_Buff[ xIndex ] ); + } + #endif + + if( xETH.Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE ) + { + /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */ + pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL; + } + + /* Initialize the next descriptor with the Next Descriptor Polling Enable */ + if( xIndex < ETH_TXBUFNB - 1 ) + { + /* Set next descriptor address register with next descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMADescriptor + 1 ); + } + else + { + /* For last descriptor, set next descriptor address register equal to the first descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMATxDscrTab; + } + } + + /* Set Transmit Descriptor List Address Register */ + xETH.Instance->DMATDLAR = ( uint32_t ) DMATxDscrTab; +} +/*-----------------------------------------------------------*/ + +static void prvDMARxDescListInit() +{ +ETH_DMADescTypeDef *pxDMADescriptor; +BaseType_t xIndex; + /* + * RX-descriptors. + */ + + /* Get the pointer on the first member of the descriptor list */ + pxDMADescriptor = DMARxDscrTab; + + /* Fill each DMA descriptor with the right values */ + for( xIndex = 0; xIndex < ETH_RXBUFNB; xIndex++, pxDMADescriptor++ ) + { + + /* Set Buffer1 size and Second Address Chained bit */ + pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE; + + #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + { + /* Set Buffer1 address pointer */ + NetworkBufferDescriptor_t *pxBuffer; + + pxBuffer = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, 100ul ); + /* If the assert below fails, make sure that there are at least 'ETH_RXBUFNB' + Network Buffers available during start-up ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) */ + configASSERT( pxBuffer != NULL ); + if( pxBuffer != NULL ) + { + pxDMADescriptor->Buffer1Addr = (uint32_t)pxBuffer->pucEthernetBuffer; + pxDMADescriptor->Status = ETH_DMARXDESC_OWN; + } + } + #else + { + /* Set Buffer1 address pointer */ + pxDMADescriptor->Buffer1Addr = ( uint32_t )( Rx_Buff[ xIndex ] ); + /* Set Own bit of the Rx descriptor Status */ + pxDMADescriptor->Status = ETH_DMARXDESC_OWN; + } + #endif + + /* Initialize the next descriptor with the Next Descriptor Polling Enable */ + if( xIndex < ETH_RXBUFNB - 1 ) + { + /* Set next descriptor address register with next descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t )( pxDMADescriptor + 1 ); + } + else + { + /* For last descriptor, set next descriptor address register equal to the first descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMARxDscrTab; + } + + } + /* Set Receive Descriptor List Address Register */ + xETH.Instance->DMARDLAR = ( uint32_t ) DMARxDscrTab; +} +/*-----------------------------------------------------------*/ + +static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr) +{ +uint32_t ulTempReg; + + /* Calculate the selected MAC address high register. */ + ulTempReg = 0x80000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ]; + + /* Load the selected MAC address high register. */ + ( *(__IO uint32_t *)( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + ulIndex ) ) ) = ulTempReg; + + /* Calculate the selected MAC address low register. */ + ulTempReg = ( ( uint32_t ) Addr[ 3 ] << 24 ) | ( ( uint32_t ) Addr[ 2 ] << 16 ) | ( ( uint32_t ) Addr[ 1 ] << 8 ) | Addr[ 0 ]; + + /* Load the selected MAC address low register */ + ( *(__IO uint32_t *) ( ( uint32_t ) ( ETH_MAC_ADDR_LBASE + ulIndex ) ) ) = ulTempReg; +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend ) +{ +BaseType_t xReturn = pdFAIL; +uint32_t ulTransmitSize = 0; +__IO ETH_DMADescTypeDef *pxDmaTxDesc; +/* Do not wait too long for a free TX DMA buffer. */ +const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u ); + + #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) + { + ProtocolPacket_t *pxPacket; + + #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + { + configASSERT( bReleaseAfterSend != 0 ); + } + #endif /* ipconfigZERO_COPY_RX_DRIVER */ + + /* If the peripheral must calculate the checksum, it wants + the protocol checksum to have a value of zero. */ + pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer ); + + if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP ) + { + pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u; + } + } + #endif + + /* Open a do {} while ( 0 ) loop to be able to call break. */ + do + { + if( xPhyObject.ulLinkStatusMask != 0 ) + { + if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS ) + { + /* Time-out waiting for a free TX descriptor. */ + break; + } + + /* This function does the actual transmission of the packet. The packet is + contained in 'pxDescriptor' that is passed to the function. */ + pxDmaTxDesc = xETH.TxDesc; + + /* Is this buffer available? */ + configASSERT ( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 ); + + { + /* Is this buffer available? */ + /* Get bytes in current buffer. */ + ulTransmitSize = pxDescriptor->xDataLength; + + if( ulTransmitSize > ETH_TX_BUF_SIZE ) + { + ulTransmitSize = ETH_TX_BUF_SIZE; + } + + #if( ipconfigZERO_COPY_TX_DRIVER == 0 ) + { + /* Copy the bytes. */ + memcpy( ( void * ) pxDmaTxDesc->Buffer1Addr, pxDescriptor->pucEthernetBuffer, ulTransmitSize ); + } + #else + { + /* Move the buffer. */ + pxDmaTxDesc->Buffer1Addr = ( uint32_t )pxDescriptor->pucEthernetBuffer; + /* The Network Buffer has been passed to DMA, no need to release it. */ + bReleaseAfterSend = pdFALSE_UNSIGNED; + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + + /* Ask to set the IPv4 checksum. + Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */ + pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC; + + /* Prepare transmit descriptors to give to DMA. */ + + /* Set LAST and FIRST segment */ + pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS; + /* Set frame size */ + pxDmaTxDesc->ControlBufferSize = ( ulTransmitSize & ETH_DMATXDESC_TBS1 ); + /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ + pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN; + + /* Point to next descriptor */ + xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( xETH.TxDesc->Buffer2NextDescAddr ); + /* Ensure completion of memory access */ + __DSB(); + /* Resume DMA transmission*/ + xETH.Instance->DMATPDR = 0; + iptraceNETWORK_INTERFACE_TRANSMIT(); + xReturn = pdPASS; + } + } + else + { + /* The PHY has no Link Status, packet shall be dropped. */ + } + } while( 0 ); + /* The buffer has been sent so can be released. */ + if( bReleaseAfterSend != pdFALSE ) + { + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer ) +{ +const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer; + + switch( pxProtPacket->xTCPPacket.xEthernetHeader.usFrameType ) + { + case ipARP_FRAME_TYPE: + /* Check it later. */ + return pdTRUE; + case ipIPv4_FRAME_TYPE: + /* Check it here. */ + break; + default: + /* Refuse the packet. */ + return pdFALSE; + } + + #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) + { + const IPHeader_t *pxIPHeader = &(pxProtPacket->xTCPPacket.xIPHeader); + uint32_t ulDestinationIPAddress; + + /* Ensure that the incoming packet is not fragmented (only outgoing packets + * can be fragmented) as these are the only handled IP frames currently. */ + if( ( pxIPHeader->usFragmentOffset & FreeRTOS_ntohs( ipFRAGMENT_OFFSET_BIT_MASK ) ) != 0U ) + { + return pdFALSE; + } + /* HT: Might want to make the following configurable because + * most IP messages have a standard length of 20 bytes */ + + /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes + * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */ + if( pxIPHeader->ucVersionHeaderLength < 0x45 || pxIPHeader->ucVersionHeaderLength > 0x4F ) + { + return pdFALSE; + } + + ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress; + /* Is the packet for this node? */ + if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) && + /* Is it a broadcast address x.x.x.255 ? */ + ( ( FreeRTOS_ntohl( ulDestinationIPAddress ) & 0xff ) != 0xff ) && + #if( ipconfigUSE_LLMNR == 1 ) + ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) && + #endif + ( *ipLOCAL_IP_ADDRESS_POINTER != 0 ) ) { + FreeRTOS_printf( ( "Drop IP %lxip\n", FreeRTOS_ntohl( ulDestinationIPAddress ) ) ); + return pdFALSE; + } + + if( pxIPHeader->ucProtocol == ipPROTOCOL_UDP ) + { + uint16_t port = pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort; + + if( ( xPortHasUDPSocket( port ) == pdFALSE ) + #if ipconfigUSE_LLMNR == 1 + && ( port != FreeRTOS_ntohs( ipLLMNR_PORT ) ) + #endif + #if ipconfigUSE_NBNS == 1 + && ( port != FreeRTOS_ntohs( ipNBNS_PORT ) ) + #endif + #if ipconfigUSE_DNS == 1 + && ( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort != FreeRTOS_ntohs( ipDNS_PORT ) ) + #endif + ) { + /* Drop this packet, not for this device. */ + return pdFALSE; + } + } + } + #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvNetworkInterfaceInput( void ) +{ +NetworkBufferDescriptor_t *pxCurDescriptor; +NetworkBufferDescriptor_t *pxNewDescriptor = NULL; +BaseType_t xReceivedLength, xAccepted; +__IO ETH_DMADescTypeDef *pxDMARxDescriptor; +xIPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; +const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 ); +uint8_t *pucBuffer; + + pxDMARxDescriptor = xETH.RxDesc; + + if( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN) == 0 ) + { + /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */ + xReceivedLength = ( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4; + + pucBuffer = (uint8_t *) pxDMARxDescriptor->Buffer1Addr; + + /* Update the ETHERNET DMA global Rx descriptor with next Rx descriptor */ + /* Chained Mode */ + /* Selects the next DMA Rx descriptor list for next buffer to read */ + xETH.RxDesc = ( ETH_DMADescTypeDef* )pxDMARxDescriptor->Buffer2NextDescAddr; + } + else + { + xReceivedLength = 0; + } + + /* Obtain the size of the packet and put it into the "usReceivedLength" variable. */ + + /* get received frame */ + if( xReceivedLength > 0ul ) + { + /* In order to make the code easier and faster, only packets in a single buffer + will be accepted. This can be done by making the buffers large enough to + hold a complete Ethernet packet (1536 bytes). + Therefore, two sanity checks: */ + configASSERT( xReceivedLength <= ETH_RX_BUF_SIZE ); + + if( ( pxDMARxDescriptor->Status & ( ETH_DMARXDESC_CE | ETH_DMARXDESC_IPV4HCE | ETH_DMARXDESC_FT ) ) != ETH_DMARXDESC_FT ) + { + /* Not an Ethernet frame-type or a checmsum error. */ + xAccepted = pdFALSE; + } + else + { + /* See if this packet must be handled. */ + xAccepted = xMayAcceptPacket( pucBuffer ); + } + + if( xAccepted != pdFALSE ) + { + /* The packet wil be accepted, but check first if a new Network Buffer can + be obtained. If not, the packet will still be dropped. */ + pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, xDescriptorWaitTime ); + + if( pxNewDescriptor == NULL ) + { + /* A new descriptor can not be allocated now. This packet will be dropped. */ + xAccepted = pdFALSE; + } + } + #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + { + /* Find out which Network Buffer was originally passed to the descriptor. */ + pxCurDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer ); + configASSERT( pxCurDescriptor != NULL ); + } + #else + { + /* In this mode, the two descriptors are the same. */ + pxCurDescriptor = pxNewDescriptor; + if( pxNewDescriptor != NULL ) + { + /* The packet is acepted and a new Network Buffer was created, + copy data to the Network Bufffer. */ + memcpy( pxNewDescriptor->pucEthernetBuffer, pucBuffer, xReceivedLength ); + } + } + #endif + + if( xAccepted != pdFALSE ) + { + pxCurDescriptor->xDataLength = xReceivedLength; + xRxEvent.pvData = ( void * ) pxCurDescriptor; + + /* Pass the data to the TCP/IP task for processing. */ + if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE ) + { + /* Could not send the descriptor into the TCP/IP stack, it + must be released. */ + vReleaseNetworkBufferAndDescriptor( pxCurDescriptor ); + iptraceETHERNET_RX_EVENT_LOST(); + } + else + { + iptraceNETWORK_INTERFACE_RECEIVE(); + } + } + + /* Release descriptors to DMA */ + #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + { + /* Set Buffer1 address pointer */ + if( pxNewDescriptor != NULL ) + { + pxDMARxDescriptor->Buffer1Addr = (uint32_t)pxNewDescriptor->pucEthernetBuffer; + } + else + { + /* The packet was dropped and the same Network + Buffer will be used to receive a new packet. */ + } + } + #endif /* ipconfigZERO_COPY_RX_DRIVER */ + + /* Set Buffer1 size and Second Address Chained bit */ + pxDMARxDescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE; + pxDMARxDescriptor->Status = ETH_DMARXDESC_OWN; + + /* Ensure completion of memory access */ + __DSB(); + /* When Rx Buffer unavailable flag is set clear it and resume + reception. */ + if( ( xETH.Instance->DMASR & ETH_DMASR_RBUS ) != 0 ) + { + /* Clear RBUS ETHERNET DMA flag. */ + xETH.Instance->DMASR = ETH_DMASR_RBUS; + + /* Resume DMA reception. */ + xETH.Instance->DMARPDR = 0; + } + } + + return ( xReceivedLength > 0 ); +} +/*-----------------------------------------------------------*/ + + +BaseType_t xSTM32_PhyRead( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue ) +{ +uint16_t usPrevAddress = xETH.Init.PhyAddress; +BaseType_t xResult; +HAL_StatusTypeDef xHALResult; + + xETH.Init.PhyAddress = xAddress; + xHALResult = HAL_ETH_ReadPHYRegister( &xETH, ( uint16_t )xRegister, pulValue ); + xETH.Init.PhyAddress = usPrevAddress; + + if( xHALResult == HAL_OK ) + { + xResult = 0; + } + else + { + xResult = -1; + } + return xResult; +} +/*-----------------------------------------------------------*/ + +BaseType_t xSTM32_PhyWrite( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue ) +{ +uint16_t usPrevAddress = xETH.Init.PhyAddress; +BaseType_t xResult; +HAL_StatusTypeDef xHALResult; + + xETH.Init.PhyAddress = xAddress; + xHALResult = HAL_ETH_WritePHYRegister( &xETH, ( uint16_t )xRegister, ulValue ); + xETH.Init.PhyAddress = usPrevAddress; + + if( xHALResult == HAL_OK ) + { + xResult = 0; + } + else + { + xResult = -1; + } + return xResult; +} +/*-----------------------------------------------------------*/ + +void phy_test() +{ +BaseType_t xPhyCount; +BaseType_t xPhyIndex; + + vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite ); + xPhyCount = xPhyDiscover( &xPhyObject ); + FreeRTOS_printf( ( "PHY count %ld\n", xPhyCount ) ); + for( xPhyIndex = 0; xPhyIndex < xPhyCount; xPhyIndex++ ) + { + FreeRTOS_printf( ( "PHY[%d] at address %d ( 0x%08X )\n", + xPhyIndex, + xPhyObject.ucPhyIndexes[ xPhyIndex ], + xPhyObject.ulPhyIDs[ xPhyIndex ] ) ); + + } + +} + +void vMACBProbePhy( void ) +{ + vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite ); + xPhyDiscover( &xPhyObject ); + xPhyConfigure( &xPhyObject, &xPHYProperties ); +} +/*-----------------------------------------------------------*/ + +static void prvEthernetUpdateConfig( BaseType_t xForce ) +{ + FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS mask %02X Force %d\n", + xPhyObject.ulLinkStatusMask, + ( int )xForce ) ); + + if( ( xForce != pdFALSE ) || ( xPhyObject.ulLinkStatusMask != 0 ) ) + { + /* Restart the auto-negotiation. */ + if( xETH.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE ) + { + xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) ); + + /* Configure the MAC with the Duplex Mode fixed by the + auto-negotiation process. */ + if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL ) + { + xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX; + } + else + { + xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX; + } + + /* Configure the MAC with the speed fixed by the + auto-negotiation process. */ + if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 ) + { + xETH.Init.Speed = ETH_SPEED_10M; + } + else + { + xETH.Init.Speed = ETH_SPEED_100M; + } + } + else /* AutoNegotiation Disable */ + { + /* Check parameters */ + assert_param( IS_ETH_SPEED( xETH.Init.Speed ) ); + assert_param( IS_ETH_DUPLEX_MODE( xETH.Init.DuplexMode ) ); + + if( xETH.Init.DuplexMode == ETH_MODE_FULLDUPLEX ) + { + xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_HALF; + } + else + { + xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_FULL; + } + + if( xETH.Init.Speed == ETH_SPEED_10M ) + { + xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_10; + } + else + { + xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_100; + } + + xPhyObject.xPhyPreferences.ucMDI_X = PHY_MDIX_AUTO; + + /* Use predefined (fixed) configuration. */ + xPhyFixedValue( &xPhyObject, xPhyGetMask( &xPhyObject ) ); + } + + /* ETHERNET MAC Re-Configuration */ + HAL_ETH_ConfigMAC( &xETH, (ETH_MACInitTypeDef *) NULL); + + /* Restart MAC interface */ + HAL_ETH_Start( &xETH); + } + else + { + /* Stop MAC interface */ + HAL_ETH_Stop( &xETH ); + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xGetPhyLinkStatus( void ) +{ +BaseType_t xReturn; + + if( xPhyObject.ulLinkStatusMask != 0 ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +#define niBUFFER_1_PACKET_SIZE 1536 + +static __attribute__ ((section(".first_data"))) uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) ); + +void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) +{ + +uint8_t *ucRAMBuffer = ucNetworkPackets; +uint32_t ul; + + for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ ) + { + pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING; + *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) ); + ucRAMBuffer += niBUFFER_1_PACKET_SIZE; + } +} +/*-----------------------------------------------------------*/ + +static void prvEMACHandlerTask( void *pvParameters ) +{ +UBaseType_t uxLastMinBufferCount = 0; +#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) +UBaseType_t uxLastMinQueueSpace = 0; +#endif +UBaseType_t uxCurrentCount; +BaseType_t xResult; +const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL ); + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + for( ;; ) + { + xResult = 0; + uxCurrentCount = uxGetMinimumFreeNetworkBuffers(); + if( uxLastMinBufferCount != uxCurrentCount ) + { + /* The logging produced below may be helpful + while tuning +TCP: see how many buffers are in use. */ + uxLastMinBufferCount = uxCurrentCount; + FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n", + uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) ); + } + + if( xTXDescriptorSemaphore != NULL ) + { + static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1; + + uxCurrentCount = uxSemaphoreGetCount( xTXDescriptorSemaphore ); + if( uxLowestSemCount > uxCurrentCount ) + { + uxLowestSemCount = uxCurrentCount; + FreeRTOS_printf( ( "TX DMA buffers: lowest %lu\n", uxLowestSemCount ) ); + } + + } + + #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + { + uxCurrentCount = uxGetMinimumIPQueueSpace(); + if( uxLastMinQueueSpace != uxCurrentCount ) + { + /* The logging produced below may be helpful + while tuning +TCP: see how many buffers are in use. */ + uxLastMinQueueSpace = uxCurrentCount; + FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) ); + } + } + #endif /* ipconfigCHECK_IP_QUEUE_SPACE */ + + if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 ) + { + /* No events to process now, wait for the next. */ + ulTaskNotifyTake( pdFALSE, ulMaxBlockTime ); + } + + if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 ) + { + ulISREvents &= ~EMAC_IF_RX_EVENT; + + xResult = prvNetworkInterfaceInput(); + if( xResult > 0 ) + { + while( prvNetworkInterfaceInput() > 0 ) + { + } + } + } + + if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 ) + { + /* Code to release TX buffers if zero-copy is used. */ + ulISREvents &= ~EMAC_IF_TX_EVENT; + /* Check if DMA packets have been delivered. */ + vClearTXBuffers(); + } + + if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 ) + { + /* Future extension: logging about errors that occurred. */ + ulISREvents &= ~EMAC_IF_ERR_EVENT; + } + if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 ) + { + /* Something has changed to a Link Status, need re-check. */ + prvEthernetUpdateConfig( pdFALSE ); + } + } +} +/*-----------------------------------------------------------*/ + +void ETH_IRQHandler( void ) +{ + HAL_ETH_IRQHandler( &xETH ); +} + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/stm32f7xx_hal_eth.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/stm32f7xx_hal_eth.c new file mode 100644 index 000000000..6f335c512 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/stm32f7xx_hal_eth.c @@ -0,0 +1,1835 @@ +/** + ****************************************************************************** + * @file stm32f7xx_hal_eth.c + * @author MCD Application Team + * @version V1.3.2 + * @date 26-June-2015 + * @brief ETH HAL module driver. + * This file provides firmware functions to manage the following + * functionalities of the Ethernet (ETH) peripheral: + * + Initialization and de-initialization functions + * + IO operation functions + * + Peripheral Control functions + * + Peripheral State and Errors functions + * + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + (#)Declare a ETH_HandleTypeDef handle structure, for example: + ETH_HandleTypeDef heth; + + (#)Fill parameters of Init structure in heth handle + + (#)Call HAL_ETH_Init() API to initialize the Ethernet peripheral (MAC, DMA, ...) + + (#)Initialize the ETH low level resources through the HAL_ETH_MspInit() API: + (##) Enable the Ethernet interface clock using + (+++) __HAL_RCC_ETHMAC_CLK_ENABLE(); + (+++) __HAL_RCC_ETHMACTX_CLK_ENABLE(); + (+++) __HAL_RCC_ETHMACRX_CLK_ENABLE(); + + (##) Initialize the related GPIO clocks + (##) Configure Ethernet pin-out + (##) Configure Ethernet NVIC interrupt (IT mode) + + (#)Initialize Ethernet DMA Descriptors in chain mode and point to allocated buffers: + (##) HAL_ETH_DMATxDescListInit(); for Transmission process + (##) HAL_ETH_DMARxDescListInit(); for Reception process + + (#)Enable MAC and DMA transmission and reception: + (##) HAL_ETH_Start(); + + (#)Prepare ETH DMA TX Descriptors and give the hand to ETH DMA to transfer + the frame to MAC TX FIFO: + (##) HAL_ETH_TransmitFrame(); + + (#)Poll for a received frame in ETH RX DMA Descriptors and get received + frame parameters + (##) HAL_ETH_GetReceivedFrame(); (should be called into an infinite loop) + + (#) Get a received frame when an ETH RX interrupt occurs: + (##) HAL_ETH_GetReceivedFrame_IT(); (called in IT mode only) + + (#) Communicate with external PHY device: + (##) Read a specific register from the PHY + HAL_ETH_ReadPHYRegister(); + (##) Write data to a specific RHY register: + HAL_ETH_WritePHYRegister(); + + (#) Configure the Ethernet MAC after ETH peripheral initialization + HAL_ETH_ConfigMAC(); all MAC parameters should be filled. + + (#) Configure the Ethernet DMA after ETH peripheral initialization + HAL_ETH_ConfigDMA(); all DMA parameters should be filled. + + -@- The PTP protocol and the DMA descriptors ring mode are not supported + in this driver + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal.h" + + +int lUDPLoggingPrintf( const char *pcFormatString, ... ); + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @defgroup ETH ETH + * @brief ETH HAL module driver + * @{ + */ + +#if !defined( ARRAY_SIZE ) + #define ARRAY_SIZE( x ) ( sizeof ( x ) / sizeof ( x )[ 0 ] ) +#endif + +#ifdef HAL_ETH_MODULE_ENABLED + +#if defined(STM32F7xx) + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/** @defgroup ETH_Private_Constants ETH Private Constants + * @{ + */ +#define LINKED_STATE_TIMEOUT_VALUE ((uint32_t)2000) /* 2000 ms */ +#define AUTONEGO_COMPLETED_TIMEOUT_VALUE ((uint32_t)1000) /* 1000 ms */ + +/** + * @} + */ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/** @defgroup ETH_Private_Functions ETH Private Functions + * @{ + */ +static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err); +static void ETH_MACAddressConfig(ETH_HandleTypeDef *heth, uint32_t MacAddr, uint8_t *Addr); +static void ETH_MACReceptionEnable(ETH_HandleTypeDef *heth); +static void ETH_MACReceptionDisable(ETH_HandleTypeDef *heth); +static void ETH_MACTransmissionEnable(ETH_HandleTypeDef *heth); +static void ETH_MACTransmissionDisable(ETH_HandleTypeDef *heth); +static void ETH_DMATransmissionEnable(ETH_HandleTypeDef *heth); +static void ETH_DMATransmissionDisable(ETH_HandleTypeDef *heth); +static void ETH_DMAReceptionEnable(ETH_HandleTypeDef *heth); +static void ETH_DMAReceptionDisable(ETH_HandleTypeDef *heth); +static void ETH_FlushTransmitFIFO(ETH_HandleTypeDef *heth); + +/** + * @} + */ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup ETH_Exported_Functions ETH Exported Functions + * @{ + */ + +/** @defgroup ETH_Exported_Functions_Group1 Initialization and de-initialization functions + * @brief Initialization and Configuration functions + * + @verbatim + =============================================================================== + ##### Initialization and de-initialization functions ##### + =============================================================================== + [..] This section provides functions allowing to: + (+) Initialize and configure the Ethernet peripheral + (+) De-initialize the Ethernet peripheral + + @endverbatim + * @{ + */ +extern void vMACBProbePhy ( void ); + +/** + * @brief Initializes the Ethernet MAC and DMA according to default + * parameters. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_Init(ETH_HandleTypeDef *heth) +{ + uint32_t tmpreg = 0; + uint32_t hclk = 60000000; + uint32_t err = ETH_SUCCESS; + + /* Check the ETH peripheral state */ + if( heth == NULL ) + { + return HAL_ERROR; + } + + /* Check parameters */ + assert_param(IS_ETH_AUTONEGOTIATION(heth->Init.AutoNegotiation)); + assert_param(IS_ETH_RX_MODE(heth->Init.RxMode)); + assert_param(IS_ETH_CHECKSUM_MODE(heth->Init.ChecksumMode)); + assert_param(IS_ETH_MEDIA_INTERFACE(heth->Init.MediaInterface)); + + if( heth->State == HAL_ETH_STATE_RESET ) + { + /* Init the low level hardware : GPIO, CLOCK, NVIC. */ + HAL_ETH_MspInit( heth ); + } + + /* Enable SYSCFG Clock */ + __HAL_RCC_SYSCFG_CLK_ENABLE(); + + /* Select MII or RMII Mode*/ + SYSCFG->PMC &= ~(SYSCFG_PMC_MII_RMII_SEL); + SYSCFG->PMC |= (uint32_t)heth->Init.MediaInterface; + + /* Ethernet Software reset */ + /* Set the SWR bit: resets all MAC subsystem internal registers and logic */ + /* After reset all the registers holds their respective reset values */ + /* Also enable EDFE: Enhanced descriptor format enable. */ +// heth->Instance->DMABMR |= ETH_DMABMR_SR | ETH_DMABMR_EDE; + heth->Instance->DMABMR |= ETH_DMABMR_SR; + + /* Wait for software reset */ + while ((heth->Instance->DMABMR & ETH_DMABMR_SR) != (uint32_t)RESET) + { + } + + /*-------------------------------- MAC Initialization ----------------------*/ + /* Get the ETHERNET MACMIIAR value */ + tmpreg = heth->Instance->MACMIIAR; + /* Clear CSR Clock Range CR[2:0] bits */ + tmpreg &= ETH_MACMIIAR_CR_MASK; + + /* Get hclk frequency value (168,000,000) */ + hclk = HAL_RCC_GetHCLKFreq(); + + /* Set CR bits depending on hclk value */ + if( ( hclk >= 20000000 ) && ( hclk < 35000000 ) ) + { + /* CSR Clock Range between 20-35 MHz */ + tmpreg |= (uint32_t) ETH_MACMIIAR_CR_Div16; + } + else if( ( hclk >= 35000000 ) && ( hclk < 60000000 ) ) + { + /* CSR Clock Range between 35-60 MHz */ + tmpreg |= ( uint32_t ) ETH_MACMIIAR_CR_Div26; + } + else if((hclk >= 60000000 ) && ( hclk < 100000000 ) ) + { + /* CSR Clock Range between 60-100 MHz */ + tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div42; + } + else if((hclk >= 100000000 ) && ( hclk < 150000000)) + { + /* CSR Clock Range between 100-150 MHz */ + tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div62; + } + else /* ((hclk >= 150000000 ) && ( hclk <= 168000000)) */ + { + /* CSR Clock Range between 150-168 MHz */ + tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div102; + } + + /* Write to ETHERNET MAC MIIAR: Configure the ETHERNET CSR Clock Range */ + heth->Instance->MACMIIAR = (uint32_t)tmpreg; + + /* Initialise the MACB and set all PHY properties */ + vMACBProbePhy(); + + /* Config MAC and DMA */ + ETH_MACDMAConfig(heth, err); + + /* Set ETH HAL State to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief De-Initializes the ETH peripheral. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_DeInit(ETH_HandleTypeDef *heth) +{ + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* De-Init the low level hardware : GPIO, CLOCK, NVIC. */ + HAL_ETH_MspDeInit( heth ); + + /* Set ETH HAL state to Disabled */ + heth->State= HAL_ETH_STATE_RESET; + + /* Release Lock */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Initializes the DMA Tx descriptors in chain mode. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param DMATxDescTab: Pointer to the first Tx desc list + * @param TxBuff: Pointer to the first TxBuffer list + * @param TxBuffCount: Number of the used Tx desc in the list + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_DMATxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *pxDMATable, uint8_t *ucDataBuffer, uint32_t ulBufferCount) +{ + uint32_t i = 0; + ETH_DMADescTypeDef *pxDMADescriptor; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Set the TxDesc pointer with the first one of the pxDMATable list */ + heth->TxDesc = pxDMATable; + + /* Fill each DMA descriptor with the right values */ + for( i=0; i < ulBufferCount; i++ ) + { + /* Get the pointer on the ith member of the descriptor list */ + pxDMADescriptor = pxDMATable + i; + + /* Set Second Address Chained bit */ + pxDMADescriptor->Status = ETH_DMATXDESC_TCH; + + pxDMADescriptor->ControlBufferSize = 0; + + /* Set Buffer1 address pointer */ + if( ucDataBuffer != NULL ) + { + pxDMADescriptor->Buffer1Addr = ( uint32_t )( &ucDataBuffer[ i * ETH_TX_BUF_SIZE ] ); + } + else + { + /* Buffer space is not provided because it uses zero-copy transmissions. */ + pxDMADescriptor->Buffer1Addr = ( uint32_t )0u; + } + + if (heth->Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE) + { + /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */ + pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL; + } + + /* Initialize the next descriptor with the Next Descriptor Polling Enable */ + if(i < ( ulBufferCount - 1 ) ) + { + /* Set next descriptor address register with next descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMATable + i + 1 ); + } + else + { + /* For last descriptor, set next descriptor address register equal to the first descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) pxDMATable; + } + } + + /* Set Transmit Descriptor List Address Register */ + heth->Instance->DMATDLAR = ( uint32_t ) pxDMATable; + + /* Set ETH HAL State to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Initializes the DMA Rx descriptors in chain mode. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param DMARxDescTab: Pointer to the first Rx desc list + * @param RxBuff: Pointer to the first RxBuffer list + * @param RxBuffCount: Number of the used Rx desc in the list + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_DMARxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *pxDMATable, uint8_t *ucDataBuffer, uint32_t ulBufferCount) +{ + uint32_t i = 0; + ETH_DMADescTypeDef *pxDMADescriptor; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Set the RxDesc pointer with the first one of the pxDMATable list */ + heth->RxDesc = pxDMATable; + + /* Fill each DMA descriptor with the right values */ + for(i=0; i < ulBufferCount; i++) + { + /* Get the pointer on the ith member of the descriptor list */ + pxDMADescriptor = pxDMATable+i; + + /* Set Own bit of the Rx descriptor Status */ + pxDMADescriptor->Status = ETH_DMARXDESC_OWN; + + /* Set Buffer1 size and Second Address Chained bit */ + pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | ETH_RX_BUF_SIZE; + + /* Set Buffer1 address pointer */ + if( ucDataBuffer != NULL ) + { + pxDMADescriptor->Buffer1Addr = ( uint32_t )( &ucDataBuffer[ i * ETH_RX_BUF_SIZE ] ); + } + else + { + /* Buffer space is not provided because it uses zero-copy reception. */ + pxDMADescriptor->Buffer1Addr = ( uint32_t )0u; + } + + if( heth->Init.RxMode == ETH_RXINTERRUPT_MODE ) + { + /* Enable Ethernet DMA Rx Descriptor interrupt */ + pxDMADescriptor->ControlBufferSize &= ~ETH_DMARXDESC_DIC; + } + + /* Initialize the next descriptor with the Next Descriptor Polling Enable */ + if(i < (ulBufferCount-1)) + { + /* Set next descriptor address register with next descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = (uint32_t)(pxDMATable+i+1); + } + else + { + /* For last descriptor, set next descriptor address register equal to the first descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) pxDMATable; + } + } + + /* Set Receive Descriptor List Address Register */ + heth->Instance->DMARDLAR = ( uint32_t ) pxDMATable; + + /* Set ETH HAL State to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Initializes the ETH MSP. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_MspInit could be implemented in the user file + */ +} + +/** + * @brief DeInitializes ETH MSP. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_MspDeInit could be implemented in the user file + */ +} + +/** + * @} + */ + +/** @defgroup ETH_Exported_Functions_Group2 IO operation functions + * @brief Data transfers functions + * + @verbatim + ============================================================================== + ##### IO operation functions ##### + ============================================================================== + [..] This section provides functions allowing to: + (+) Transmit a frame + HAL_ETH_TransmitFrame(); + (+) Receive a frame + HAL_ETH_GetReceivedFrame(); + HAL_ETH_GetReceivedFrame_IT(); + (+) Read from an External PHY register + HAL_ETH_ReadPHYRegister(); + (+) Write to an External PHY register + HAL_ETH_WritePHYRegister(); + + @endverbatim + + * @{ + */ + +/** + * @brief Sends an Ethernet frame. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param FrameLength: Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_TransmitFrame(ETH_HandleTypeDef *heth, uint32_t FrameLength) +{ + uint32_t bufcount = 0, size = 0, i = 0; + __IO ETH_DMADescTypeDef *pxDmaTxDesc = heth->TxDesc; + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + if( FrameLength == 0 ) + { + /* Set ETH HAL state to READY */ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + return HAL_ERROR; + } + + /* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */ + if( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) != ( uint32_t ) RESET ) + { + /* OWN bit set */ + heth->State = HAL_ETH_STATE_BUSY_TX; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + return HAL_ERROR; + } + + /* Get the number of needed Tx buffers for the current frame, rounding up. */ + bufcount = ( FrameLength + ETH_TX_BUF_SIZE - 1 ) / ETH_TX_BUF_SIZE; + + if (bufcount == 1) + { + /* Set LAST and FIRST segment */ + pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS; + /* Set frame size */ + pxDmaTxDesc->ControlBufferSize = ( FrameLength & ETH_DMATXDESC_TBS1 ); + /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ + pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN; + /* Point to next descriptor */ + heth->TxDesc = ( ETH_DMADescTypeDef * ) ( heth->TxDesc->Buffer2NextDescAddr ); + } + else + { + for( i = 0; i < bufcount; i++ ) + { + /* Clear FIRST and LAST segment bits */ + uint32_t ulStatus = heth->TxDesc->Status & ~( ETH_DMATXDESC_FS | ETH_DMATXDESC_LS ); + + if( i == 0 ) + { + /* Setting the first segment bit */ + heth->TxDesc->Status = ulStatus | ETH_DMATXDESC_FS; + } + + /* Program size */ + if (i < (bufcount-1)) + { + heth->TxDesc->ControlBufferSize = (ETH_TX_BUF_SIZE & ETH_DMATXDESC_TBS1); + } + else + { + /* Setting the last segment bit */ + heth->TxDesc->Status = ulStatus | ETH_DMATXDESC_LS; + size = FrameLength - (bufcount-1)*ETH_TX_BUF_SIZE; + heth->TxDesc->ControlBufferSize = (size & ETH_DMATXDESC_TBS1); + } + + /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ + heth->TxDesc->Status |= ETH_DMATXDESC_OWN; + /* point to next descriptor */ + heth->TxDesc = (ETH_DMADescTypeDef *)( heth->TxDesc->Buffer2NextDescAddr ); + } + } + + __DSB(); + + /* When Tx Buffer unavailable flag is set: clear it and resume transmission */ + if( ( heth->Instance->DMASR & ETH_DMASR_TBUS ) != ( uint32_t )RESET ) + { + heth->Instance->DMACHTDR = ( uint32_t )pxDmaTxDesc; + + /* Clear TBUS ETHERNET DMA flag */ + heth->Instance->DMASR = ETH_DMASR_TBUS; + /* Resume DMA transmission*/ + heth->Instance->DMATPDR = 0; + } + + /* Set ETH HAL State to Ready */ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Checks for received frames. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_GetReceivedFrame_IT( ETH_HandleTypeDef *heth ) +{ + return HAL_ETH_GetReceivedFrame( heth ); +} + +HAL_StatusTypeDef HAL_ETH_GetReceivedFrame( ETH_HandleTypeDef *heth ) +{ +uint32_t ulCounter = 0; +ETH_DMADescTypeDef *pxDescriptor = heth->RxDesc; +HAL_StatusTypeDef xResult = HAL_ERROR; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Check the ETH state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Scan descriptors owned by CPU */ + while( ( ( pxDescriptor->Status & ETH_DMARXDESC_OWN ) == 0ul ) && ( ulCounter < ETH_RXBUFNB ) ) + { + uint32_t ulStatus = pxDescriptor->Status; + + /* Just for security. */ + ulCounter++; + + if( ( ulStatus & ( ETH_DMARXDESC_FS | ETH_DMARXDESC_LS ) ) == ( uint32_t )ETH_DMARXDESC_FS ) + { + /* First segment in frame, but not the last. */ + heth->RxFrameInfos.FSRxDesc = pxDescriptor; + heth->RxFrameInfos.LSRxDesc = ( ETH_DMADescTypeDef *)NULL; + heth->RxFrameInfos.SegCount = 1; + /* Point to next descriptor. */ + pxDescriptor = (ETH_DMADescTypeDef*) (pxDescriptor->Buffer2NextDescAddr); + heth->RxDesc = pxDescriptor; + } + else if( ( ulStatus & ( ETH_DMARXDESC_LS | ETH_DMARXDESC_FS ) ) == 0ul ) + { + /* This is an intermediate segment, not first, not last. */ + /* Increment segment count. */ + heth->RxFrameInfos.SegCount++; + /* Move to the next descriptor. */ + pxDescriptor = ( ETH_DMADescTypeDef * ) ( pxDescriptor->Buffer2NextDescAddr ); + heth->RxDesc = pxDescriptor; + } + /* Must be a last segment */ + else + { + /* This is the last segment. */ + /* Check if last segment is first segment: one segment contains the frame */ + if( heth->RxFrameInfos.SegCount == 0 ) + { + /* Remember the first segment. */ + heth->RxFrameInfos.FSRxDesc = pxDescriptor; + } + + /* Increment segment count */ + heth->RxFrameInfos.SegCount++; + + /* Remember the last segment. */ + heth->RxFrameInfos.LSRxDesc = pxDescriptor; + + /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */ + heth->RxFrameInfos.length = + ( ( ulStatus & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4; + + /* Get the address of the buffer start address */ + heth->RxFrameInfos.buffer = heth->RxFrameInfos.FSRxDesc->Buffer1Addr; + + /* Point to next descriptor */ + heth->RxDesc = ( ETH_DMADescTypeDef * ) pxDescriptor->Buffer2NextDescAddr; + + /* Return OK status: a packet was received. */ + xResult = HAL_OK; + break; + } + } + + /* Set ETH HAL State to Ready */ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return xResult; +} + +#if( STM32_ETHERNET_STATS != 0 ) + + volatile int rx_count, tx_count, int_count; + /** + * @brief This function handles ETH interrupt request. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ + volatile int int_counts[32]; + volatile int tx_status[8]; + volatile unsigned sr_history[32]; + volatile int sr_head; + #define STM32_STAT_INC( x ) do { ( x )++; } while( 0 ) + +#else + #define STM32_STAT_INC( x ) do { } while( 0 ) +#endif /* STM32_ETHERNET_STATS */ + +#define ETH_DMA_ALL_INTS \ + ( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | ETH_DMA_IT_AIS | ETH_DMA_IT_ER | \ + ETH_DMA_IT_FBE | ETH_DMA_IT_ET | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \ + ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T ) + +//#define ETH_DMA_ALL_INTS ETH_DMA_IT_RBU | ETH_DMA_FLAG_T | ETH_DMA_FLAG_AIS + +#define INT_MASK ( ( uint32_t ) ~ ( ETH_DMA_IT_TBU ) ) +void HAL_ETH_IRQHandler(ETH_HandleTypeDef *heth) +{ + uint32_t dmasr; + + STM32_STAT_INC( int_count ); + + dmasr = heth->Instance->DMASR & ETH_DMA_ALL_INTS; + heth->Instance->DMASR = dmasr; + +#if( STM32_ETHERNET_STATS != 0 ) + if( sr_head < ARRAY_SIZE( sr_history ) ) + { + sr_history[ sr_head++ ] = dmasr; + } + + { + int i; + for (i = 0; i < 32; i++) { + if (dmasr & (1u << i)) { + int_counts[i]++; + } + } + tx_status[ ( dmasr >> 20 ) & 0x07 ]++; + } +#endif + + /* Frame received */ + if( ( dmasr & ( ETH_DMA_FLAG_R | ETH_DMA_IT_RBU ) ) != 0 ) + { + /* Receive complete callback */ + HAL_ETH_RxCpltCallback( heth ); + STM32_STAT_INC( rx_count ); + } + /* Frame transmitted */ + if( ( dmasr & ( ETH_DMA_FLAG_T ) ) != 0 ) + { + /* Transfer complete callback */ + HAL_ETH_TxCpltCallback( heth ); + STM32_STAT_INC( tx_count ); + } + + /* ETH DMA Error */ + if( ( dmasr & ( ETH_DMA_FLAG_AIS ) ) != 0 ) + { + /* Ethernet Error callback */ + HAL_ETH_ErrorCallback( heth ); + } +} + +/** + * @brief Tx Transfer completed callbacks. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Rx Transfer completed callbacks. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Ethernet transfer error callbacks + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Reads a PHY register + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param PHYReg: PHY register address, is the index of one of the 32 PHY register. + * This parameter can be one of the following values: + * PHY_BCR: Transceiver Basic Control Register, + * PHY_BSR: Transceiver Basic Status Register. + * More PHY register could be read depending on the used PHY + * @param RegValue: PHY register value + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_ReadPHYRegister(ETH_HandleTypeDef *heth, uint16_t PHYReg, uint32_t *RegValue) +{ +uint32_t tmpreg = 0; +uint32_t tickstart = 0; +HAL_StatusTypeDef xResult; + + /* Check parameters */ + assert_param(IS_ETH_PHY_ADDRESS(heth->Init.PhyAddress)); + + /* Check the ETH peripheral state */ + if( heth->State == HAL_ETH_STATE_BUSY_RD ) + { + xResult = HAL_BUSY; + } + else + { + __HAL_LOCK( heth ); + + /* Set ETH HAL State to BUSY_RD */ + heth->State = HAL_ETH_STATE_BUSY_RD; + + /* Get the ETHERNET MACMIIAR value */ + tmpreg = heth->Instance->MACMIIAR; + + /* Keep only the CSR Clock Range CR[2:0] bits value */ + tmpreg &= ~ETH_MACMIIAR_CR_MASK; + + /* Prepare the MII address register value */ + tmpreg |= ( ( ( uint32_t )heth->Init.PhyAddress << 11) & ETH_MACMIIAR_PA ); /* Set the PHY device address */ + tmpreg |= ( ( ( uint32_t )PHYReg << 6 ) & ETH_MACMIIAR_MR ); /* Set the PHY register address */ + tmpreg &= ~ETH_MACMIIAR_MW; /* Set the read mode */ + tmpreg |= ETH_MACMIIAR_MB; /* Set the MII Busy bit */ + + /* Write the result value into the MII Address register */ + heth->Instance->MACMIIAR = tmpreg; + + /* Get tick */ + tickstart = HAL_GetTick(); + + /* Check for the Busy flag */ + while( 1 ) + { + tmpreg = heth->Instance->MACMIIAR; + + if( ( tmpreg & ETH_MACMIIAR_MB ) == 0ul ) + { + /* Get MACMIIDR value */ + *RegValue = ( uint32_t ) heth->Instance->MACMIIDR; + xResult = HAL_OK; + break; + } + /* Check for the Timeout */ + if( ( HAL_GetTick( ) - tickstart ) > PHY_READ_TO ) + { + xResult = HAL_TIMEOUT; + break; + } + + } + + /* Set ETH HAL State to READY */ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + } + + if( xResult != HAL_OK ) + { + lUDPLoggingPrintf( "ReadPHY: %d\n", xResult ); + } + /* Return function status */ + return xResult; +} + +/** + * @brief Writes to a PHY register. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param PHYReg: PHY register address, is the index of one of the 32 PHY register. + * This parameter can be one of the following values: + * PHY_BCR: Transceiver Control Register. + * More PHY register could be written depending on the used PHY + * @param RegValue: the value to write + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_WritePHYRegister(ETH_HandleTypeDef *heth, uint16_t PHYReg, uint32_t RegValue) +{ +uint32_t tmpreg = 0; +uint32_t tickstart = 0; +HAL_StatusTypeDef xResult; + + /* Check parameters */ + assert_param( IS_ETH_PHY_ADDRESS( heth->Init.PhyAddress ) ); + + /* Check the ETH peripheral state */ + if( heth->State == HAL_ETH_STATE_BUSY_WR ) + { + xResult = HAL_BUSY; + } + else + { + __HAL_LOCK( heth ); + + /* Set ETH HAL State to BUSY_WR */ + heth->State = HAL_ETH_STATE_BUSY_WR; + + /* Get the ETHERNET MACMIIAR value */ + tmpreg = heth->Instance->MACMIIAR; + + /* Keep only the CSR Clock Range CR[2:0] bits value */ + tmpreg &= ~ETH_MACMIIAR_CR_MASK; + + /* Prepare the MII register address value */ + tmpreg |= ( ( ( uint32_t ) heth->Init.PhyAddress << 11 ) & ETH_MACMIIAR_PA ); /* Set the PHY device address */ + tmpreg |= ( ( ( uint32_t ) PHYReg << 6 ) & ETH_MACMIIAR_MR ); /* Set the PHY register address */ + tmpreg |= ETH_MACMIIAR_MW; /* Set the write mode */ + tmpreg |= ETH_MACMIIAR_MB; /* Set the MII Busy bit */ + + /* Give the value to the MII data register */ + heth->Instance->MACMIIDR = ( uint16_t ) RegValue; + + /* Write the result value into the MII Address register */ + heth->Instance->MACMIIAR = tmpreg; + + /* Get tick */ + tickstart = HAL_GetTick(); + + /* Check for the Busy flag */ + while( 1 ) + { + tmpreg = heth->Instance->MACMIIAR; + + if( ( tmpreg & ETH_MACMIIAR_MB ) == 0ul ) + { + xResult = HAL_OK; + break; + } + /* Check for the Timeout */ + if( ( HAL_GetTick( ) - tickstart ) > PHY_WRITE_TO ) + { + xResult = HAL_TIMEOUT; + break; + } + } + + /* Set ETH HAL State to READY */ + heth->State = HAL_ETH_STATE_READY; + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + } + + if( xResult != HAL_OK ) + { + lUDPLoggingPrintf( "WritePHY: %d\n", xResult ); + } + /* Return function status */ + return xResult; +} + +/** + * @} + */ + +/** @defgroup ETH_Exported_Functions_Group3 Peripheral Control functions + * @brief Peripheral Control functions + * +@verbatim + =============================================================================== + ##### Peripheral Control functions ##### + =============================================================================== + [..] This section provides functions allowing to: + (+) Enable MAC and DMA transmission and reception. + HAL_ETH_Start(); + (+) Disable MAC and DMA transmission and reception. + HAL_ETH_Stop(); + (+) Set the MAC configuration in runtime mode + HAL_ETH_ConfigMAC(); + (+) Set the DMA configuration in runtime mode + HAL_ETH_ConfigDMA(); + +@endverbatim + * @{ + */ + + /** + * @brief Enables Ethernet MAC and DMA reception/transmission + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_Start( ETH_HandleTypeDef *heth ) +{ + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Enable transmit state machine of the MAC for transmission on the MII */ + ETH_MACTransmissionEnable( heth ); + + /* Enable receive state machine of the MAC for reception from the MII */ + ETH_MACReceptionEnable( heth ); + + /* Flush Transmit FIFO */ + ETH_FlushTransmitFIFO( heth ); + + /* Start DMA transmission */ + ETH_DMATransmissionEnable( heth ); + + /* Start DMA reception */ + ETH_DMAReceptionEnable( heth ); + + /* Set the ETH state to READY*/ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Stop Ethernet MAC and DMA reception/transmission + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_Stop(ETH_HandleTypeDef *heth) +{ + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Stop DMA transmission */ + ETH_DMATransmissionDisable( heth ); + + /* Stop DMA reception */ + ETH_DMAReceptionDisable( heth ); + + /* Disable receive state machine of the MAC for reception from the MII */ + ETH_MACReceptionDisable( heth ); + + /* Flush Transmit FIFO */ + ETH_FlushTransmitFIFO( heth ); + + /* Disable transmit state machine of the MAC for transmission on the MII */ + ETH_MACTransmissionDisable( heth ); + + /* Set the ETH state*/ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +static void prvWriteMACFCR( ETH_HandleTypeDef *heth, uint32_t ulValue) +{ + /* Enable the MAC transmission */ + heth->Instance->MACFCR = ulValue; + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles. + Read it back, wait a ms and */ + ( void ) heth->Instance->MACFCR; + + HAL_Delay( ETH_REG_WRITE_DELAY ); + + heth->Instance->MACFCR = ulValue; +} + +static void prvWriteDMAOMR( ETH_HandleTypeDef *heth, uint32_t ulValue) +{ + /* Enable the MAC transmission */ + heth->Instance->DMAOMR = ulValue; + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles. + Read it back, wait a ms and */ + ( void ) heth->Instance->DMAOMR; + + HAL_Delay( ETH_REG_WRITE_DELAY ); + + heth->Instance->DMAOMR = ulValue; +} + +static void prvWriteMACCR( ETH_HandleTypeDef *heth, uint32_t ulValue) +{ + /* Enable the MAC transmission */ + heth->Instance->MACCR = ulValue; + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles. + Read it back, wait a ms and */ + ( void ) heth->Instance->MACCR; + + HAL_Delay( ETH_REG_WRITE_DELAY ); + + heth->Instance->MACCR = ulValue; +} + +/** + * @brief Set ETH MAC Configuration. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param macconf: MAC Configuration structure + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_ConfigMAC(ETH_HandleTypeDef *heth, ETH_MACInitTypeDef *macconf) +{ + uint32_t tmpreg = 0; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State= HAL_ETH_STATE_BUSY; + + assert_param(IS_ETH_SPEED(heth->Init.Speed)); + assert_param(IS_ETH_DUPLEX_MODE(heth->Init.DuplexMode)); + + if (macconf != NULL) + { + /* Check the parameters */ + assert_param(IS_ETH_WATCHDOG(macconf->Watchdog)); + assert_param(IS_ETH_JABBER(macconf->Jabber)); + assert_param(IS_ETH_INTER_FRAME_GAP(macconf->InterFrameGap)); + assert_param(IS_ETH_CARRIER_SENSE(macconf->CarrierSense)); + assert_param(IS_ETH_RECEIVE_OWN(macconf->ReceiveOwn)); + assert_param(IS_ETH_LOOPBACK_MODE(macconf->LoopbackMode)); + assert_param(IS_ETH_CHECKSUM_OFFLOAD(macconf->ChecksumOffload)); + assert_param(IS_ETH_RETRY_TRANSMISSION(macconf->RetryTransmission)); + assert_param(IS_ETH_AUTOMATIC_PADCRC_STRIP(macconf->AutomaticPadCRCStrip)); + assert_param(IS_ETH_BACKOFF_LIMIT(macconf->BackOffLimit)); + assert_param(IS_ETH_DEFERRAL_CHECK(macconf->DeferralCheck)); + assert_param(IS_ETH_RECEIVE_ALL(macconf->ReceiveAll)); + assert_param(IS_ETH_SOURCE_ADDR_FILTER(macconf->SourceAddrFilter)); + assert_param(IS_ETH_CONTROL_FRAMES(macconf->PassControlFrames)); + assert_param(IS_ETH_BROADCAST_FRAMES_RECEPTION(macconf->BroadcastFramesReception)); + assert_param(IS_ETH_DESTINATION_ADDR_FILTER(macconf->DestinationAddrFilter)); + assert_param(IS_ETH_PROMISCUOUS_MODE(macconf->PromiscuousMode)); + assert_param(IS_ETH_MULTICAST_FRAMES_FILTER(macconf->MulticastFramesFilter)); + assert_param(IS_ETH_UNICAST_FRAMES_FILTER(macconf->UnicastFramesFilter)); + assert_param(IS_ETH_PAUSE_TIME(macconf->PauseTime)); + assert_param(IS_ETH_ZEROQUANTA_PAUSE(macconf->ZeroQuantaPause)); + assert_param(IS_ETH_PAUSE_LOW_THRESHOLD(macconf->PauseLowThreshold)); + assert_param(IS_ETH_UNICAST_PAUSE_FRAME_DETECT(macconf->UnicastPauseFrameDetect)); + assert_param(IS_ETH_RECEIVE_FLOWCONTROL(macconf->ReceiveFlowControl)); + assert_param(IS_ETH_TRANSMIT_FLOWCONTROL(macconf->TransmitFlowControl)); + assert_param(IS_ETH_VLAN_TAG_COMPARISON(macconf->VLANTagComparison)); + assert_param(IS_ETH_VLAN_TAG_IDENTIFIER(macconf->VLANTagIdentifier)); + + /*------------------------ ETHERNET MACCR Configuration --------------------*/ + /* Get the ETHERNET MACCR value */ + tmpreg = heth->Instance->MACCR; + /* Clear WD, PCE, PS, TE and RE bits */ + tmpreg &= ETH_MACCR_CLEAR_MASK; + + tmpreg |= (uint32_t)( + macconf->Watchdog | + macconf->Jabber | + macconf->InterFrameGap | + macconf->CarrierSense | + heth->Init.Speed | + macconf->ReceiveOwn | + macconf->LoopbackMode | + heth->Init.DuplexMode | + macconf->ChecksumOffload | + macconf->RetryTransmission | + macconf->AutomaticPadCRCStrip | + macconf->BackOffLimit | + macconf->DeferralCheck); + + /* Write to ETHERNET MACCR */ + prvWriteMACCR( heth, tmpreg ); + + /*----------------------- ETHERNET MACFFR Configuration --------------------*/ + /* Write to ETHERNET MACFFR */ + heth->Instance->MACFFR = (uint32_t)( + macconf->ReceiveAll | + macconf->SourceAddrFilter | + macconf->PassControlFrames | + macconf->BroadcastFramesReception | + macconf->DestinationAddrFilter | + macconf->PromiscuousMode | + macconf->MulticastFramesFilter | + macconf->UnicastFramesFilter); + + /* Wait until the write operation will be taken into account : + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->MACFFR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->MACFFR = tmpreg; + + /*--------------- ETHERNET MACHTHR and MACHTLR Configuration ---------------*/ + /* Write to ETHERNET MACHTHR */ + heth->Instance->MACHTHR = (uint32_t)macconf->HashTableHigh; + + /* Write to ETHERNET MACHTLR */ + heth->Instance->MACHTLR = (uint32_t)macconf->HashTableLow; + /*----------------------- ETHERNET MACFCR Configuration --------------------*/ + + /* Get the ETHERNET MACFCR value */ + tmpreg = heth->Instance->MACFCR; + /* Clear xx bits */ + tmpreg &= ETH_MACFCR_CLEAR_MASK; + + tmpreg |= (uint32_t)(( + macconf->PauseTime << 16) | + macconf->ZeroQuantaPause | + macconf->PauseLowThreshold | + macconf->UnicastPauseFrameDetect | + macconf->ReceiveFlowControl | + macconf->TransmitFlowControl); + + /* Write to ETHERNET MACFCR */ + prvWriteMACFCR( heth, tmpreg ); + + /*----------------------- ETHERNET MACVLANTR Configuration -----------------*/ + heth->Instance->MACVLANTR = (uint32_t)(macconf->VLANTagComparison | + macconf->VLANTagIdentifier); + + /* Wait until the write operation will be taken into account : + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->MACVLANTR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->MACVLANTR = tmpreg; + } + else /* macconf == NULL : here we just configure Speed and Duplex mode */ + { + /*------------------------ ETHERNET MACCR Configuration --------------------*/ + /* Get the ETHERNET MACCR value */ + tmpreg = heth->Instance->MACCR; + + /* Clear FES and DM bits */ + tmpreg &= ~((uint32_t)0x00004800); + + tmpreg |= (uint32_t)(heth->Init.Speed | heth->Init.DuplexMode); + + /* Write to ETHERNET MACCR */ + prvWriteMACCR( heth, tmpreg ); + } + + /* Set the ETH state to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Sets ETH DMA Configuration. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param dmaconf: DMA Configuration structure + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_ConfigDMA(ETH_HandleTypeDef *heth, ETH_DMAInitTypeDef *dmaconf) +{ + uint32_t tmpreg = 0; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State= HAL_ETH_STATE_BUSY; + + /* Check parameters */ + assert_param(IS_ETH_DROP_TCPIP_CHECKSUM_FRAME(dmaconf->DropTCPIPChecksumErrorFrame)); + assert_param(IS_ETH_RECEIVE_STORE_FORWARD(dmaconf->ReceiveStoreForward)); + assert_param(IS_ETH_FLUSH_RECEIVE_FRAME(dmaconf->FlushReceivedFrame)); + assert_param(IS_ETH_TRANSMIT_STORE_FORWARD(dmaconf->TransmitStoreForward)); + assert_param(IS_ETH_TRANSMIT_THRESHOLD_CONTROL(dmaconf->TransmitThresholdControl)); + assert_param(IS_ETH_FORWARD_ERROR_FRAMES(dmaconf->ForwardErrorFrames)); + assert_param(IS_ETH_FORWARD_UNDERSIZED_GOOD_FRAMES(dmaconf->ForwardUndersizedGoodFrames)); + assert_param(IS_ETH_RECEIVE_THRESHOLD_CONTROL(dmaconf->ReceiveThresholdControl)); + assert_param(IS_ETH_SECOND_FRAME_OPERATE(dmaconf->SecondFrameOperate)); + assert_param(IS_ETH_ADDRESS_ALIGNED_BEATS(dmaconf->AddressAlignedBeats)); + assert_param(IS_ETH_FIXED_BURST(dmaconf->FixedBurst)); + assert_param(IS_ETH_RXDMA_BURST_LENGTH(dmaconf->RxDMABurstLength)); + assert_param(IS_ETH_TXDMA_BURST_LENGTH(dmaconf->TxDMABurstLength)); + assert_param(IS_ETH_ENHANCED_DESCRIPTOR_FORMAT(dmaconf->EnhancedDescriptorFormat)); + assert_param(IS_ETH_DMA_DESC_SKIP_LENGTH(dmaconf->DescriptorSkipLength)); + assert_param(IS_ETH_DMA_ARBITRATION_ROUNDROBIN_RXTX(dmaconf->DMAArbitration)); + + /*----------------------- ETHERNET DMAOMR Configuration --------------------*/ + /* Get the ETHERNET DMAOMR value */ + tmpreg = heth->Instance->DMAOMR; + /* Clear xx bits */ + tmpreg &= ETH_DMAOMR_CLEAR_MASK; + + tmpreg |= (uint32_t)( + dmaconf->DropTCPIPChecksumErrorFrame | + dmaconf->ReceiveStoreForward | + dmaconf->FlushReceivedFrame | + dmaconf->TransmitStoreForward | + dmaconf->TransmitThresholdControl | + dmaconf->ForwardErrorFrames | + dmaconf->ForwardUndersizedGoodFrames | + dmaconf->ReceiveThresholdControl | + dmaconf->SecondFrameOperate); + + /* Write to ETHERNET DMAOMR */ + prvWriteDMAOMR( heth, tmpreg ); + + /*----------------------- ETHERNET DMABMR Configuration --------------------*/ + heth->Instance->DMABMR = (uint32_t)(dmaconf->AddressAlignedBeats | + dmaconf->FixedBurst | + dmaconf->RxDMABurstLength | /* !! if 4xPBL is selected for Tx or Rx it is applied for the other */ + dmaconf->TxDMABurstLength | + dmaconf->EnhancedDescriptorFormat | + (dmaconf->DescriptorSkipLength << 2) | + dmaconf->DMAArbitration | + ETH_DMABMR_USP); /* Enable use of separate PBL for Rx and Tx */ + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->DMABMR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->DMABMR = tmpreg; + + /* Set the ETH state to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @} + */ + +/** @defgroup ETH_Exported_Functions_Group4 Peripheral State functions + * @brief Peripheral State functions + * + @verbatim + =============================================================================== + ##### Peripheral State functions ##### + =============================================================================== + [..] + This subsection permits to get in run-time the status of the peripheral + and the data flow. + (+) Get the ETH handle state: + HAL_ETH_GetState(); + + + @endverbatim + * @{ + */ + +/** + * @brief Return the ETH HAL state + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL state + */ +HAL_ETH_StateTypeDef HAL_ETH_GetState(ETH_HandleTypeDef *heth) +{ + /* Return ETH state */ + return heth->State; +} + +/** + * @} + */ + +/** + * @} + */ + +/** @addtogroup ETH_Private_Functions + * @{ + */ + +/** + * @brief Configures Ethernet MAC and DMA with default parameters. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param err: Ethernet Init error + * @retval HAL status + */ +static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err) +{ + ETH_MACInitTypeDef macinit; + ETH_DMAInitTypeDef dmainit; + uint32_t tmpreg = 0; + + if (err != ETH_SUCCESS) /* Auto-negotiation failed */ + { + /* Set Ethernet duplex mode to Full-duplex */ + heth->Init.DuplexMode = ETH_MODE_FULLDUPLEX; + + /* Set Ethernet speed to 100M */ + heth->Init.Speed = ETH_SPEED_100M; + } + + /* Ethernet MAC default initialization **************************************/ + macinit.Watchdog = ETH_WATCHDOG_ENABLE; + macinit.Jabber = ETH_JABBER_ENABLE; + macinit.InterFrameGap = ETH_INTERFRAMEGAP_96BIT; + macinit.CarrierSense = ETH_CARRIERSENCE_ENABLE; + macinit.ReceiveOwn = ETH_RECEIVEOWN_ENABLE; + macinit.LoopbackMode = ETH_LOOPBACKMODE_DISABLE; + if(heth->Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE) + { + macinit.ChecksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE; + } + else + { + macinit.ChecksumOffload = ETH_CHECKSUMOFFLAOD_DISABLE; + } + macinit.RetryTransmission = ETH_RETRYTRANSMISSION_DISABLE; + macinit.AutomaticPadCRCStrip = ETH_AUTOMATICPADCRCSTRIP_DISABLE; + macinit.BackOffLimit = ETH_BACKOFFLIMIT_10; + macinit.DeferralCheck = ETH_DEFFERRALCHECK_DISABLE; + macinit.ReceiveAll = ETH_RECEIVEAll_DISABLE; + macinit.SourceAddrFilter = ETH_SOURCEADDRFILTER_DISABLE; + macinit.PassControlFrames = ETH_PASSCONTROLFRAMES_BLOCKALL; + macinit.BroadcastFramesReception = ETH_BROADCASTFRAMESRECEPTION_ENABLE; + macinit.DestinationAddrFilter = ETH_DESTINATIONADDRFILTER_NORMAL; + macinit.PromiscuousMode = ETH_PROMISCUOUS_MODE_DISABLE; + macinit.MulticastFramesFilter = ETH_MULTICASTFRAMESFILTER_PERFECT; + macinit.UnicastFramesFilter = ETH_UNICASTFRAMESFILTER_PERFECT; + macinit.HashTableHigh = 0x0; + macinit.HashTableLow = 0x0; + macinit.PauseTime = 0x0; + macinit.ZeroQuantaPause = ETH_ZEROQUANTAPAUSE_DISABLE; + macinit.PauseLowThreshold = ETH_PAUSELOWTHRESHOLD_MINUS4; + macinit.UnicastPauseFrameDetect = ETH_UNICASTPAUSEFRAMEDETECT_DISABLE; + macinit.ReceiveFlowControl = ETH_RECEIVEFLOWCONTROL_DISABLE; + macinit.TransmitFlowControl = ETH_TRANSMITFLOWCONTROL_DISABLE; + macinit.VLANTagComparison = ETH_VLANTAGCOMPARISON_16BIT; + macinit.VLANTagIdentifier = 0x0; + + /*------------------------ ETHERNET MACCR Configuration --------------------*/ + /* Get the ETHERNET MACCR value */ + tmpreg = heth->Instance->MACCR; + /* Clear WD, PCE, PS, TE and RE bits */ + tmpreg &= ETH_MACCR_CLEAR_MASK; + /* Set the WD bit according to ETH Watchdog value */ + /* Set the JD: bit according to ETH Jabber value */ + /* Set the IFG bit according to ETH InterFrameGap value */ + /* Set the DCRS bit according to ETH CarrierSense value */ + /* Set the FES bit according to ETH Speed value */ + /* Set the DO bit according to ETH ReceiveOwn value */ + /* Set the LM bit according to ETH LoopbackMode value */ + /* Set the DM bit according to ETH Mode value */ + /* Set the IPCO bit according to ETH ChecksumOffload value */ + /* Set the DR bit according to ETH RetryTransmission value */ + /* Set the ACS bit according to ETH AutomaticPadCRCStrip value */ + /* Set the BL bit according to ETH BackOffLimit value */ + /* Set the DC bit according to ETH DeferralCheck value */ + tmpreg |= (uint32_t)(macinit.Watchdog | + macinit.Jabber | + macinit.InterFrameGap | + macinit.CarrierSense | + heth->Init.Speed | + macinit.ReceiveOwn | + macinit.LoopbackMode | + heth->Init.DuplexMode | + macinit.ChecksumOffload | + macinit.RetryTransmission | + macinit.AutomaticPadCRCStrip | + macinit.BackOffLimit | + macinit.DeferralCheck); + + /* Write to ETHERNET MACCR */ + prvWriteMACCR( heth, tmpreg ); + + /*----------------------- ETHERNET MACFFR Configuration --------------------*/ + /* Set the RA bit according to ETH ReceiveAll value */ + /* Set the SAF and SAIF bits according to ETH SourceAddrFilter value */ + /* Set the PCF bit according to ETH PassControlFrames value */ + /* Set the DBF bit according to ETH BroadcastFramesReception value */ + /* Set the DAIF bit according to ETH DestinationAddrFilter value */ + /* Set the PR bit according to ETH PromiscuousMode value */ + /* Set the PM, HMC and HPF bits according to ETH MulticastFramesFilter value */ + /* Set the HUC and HPF bits according to ETH UnicastFramesFilter value */ + /* Write to ETHERNET MACFFR */ + heth->Instance->MACFFR = (uint32_t)(macinit.ReceiveAll | + macinit.SourceAddrFilter | + macinit.PassControlFrames | + macinit.BroadcastFramesReception | + macinit.DestinationAddrFilter | + macinit.PromiscuousMode | + macinit.MulticastFramesFilter | + macinit.UnicastFramesFilter); + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->MACFFR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->MACFFR = tmpreg; + + /*--------------- ETHERNET MACHTHR and MACHTLR Configuration --------------*/ + /* Write to ETHERNET MACHTHR */ + heth->Instance->MACHTHR = (uint32_t)macinit.HashTableHigh; + + /* Write to ETHERNET MACHTLR */ + heth->Instance->MACHTLR = (uint32_t)macinit.HashTableLow; + /*----------------------- ETHERNET MACFCR Configuration -------------------*/ + + /* Get the ETHERNET MACFCR value */ + tmpreg = heth->Instance->MACFCR; + /* Clear xx bits */ + tmpreg &= ETH_MACFCR_CLEAR_MASK; + + /* Set the PT bit according to ETH PauseTime value */ + /* Set the DZPQ bit according to ETH ZeroQuantaPause value */ + /* Set the PLT bit according to ETH PauseLowThreshold value */ + /* Set the UP bit according to ETH UnicastPauseFrameDetect value */ + /* Set the RFE bit according to ETH ReceiveFlowControl value */ + /* Set the TFE bit according to ETH TransmitFlowControl value */ + tmpreg |= (uint32_t)((macinit.PauseTime << 16) | + macinit.ZeroQuantaPause | + macinit.PauseLowThreshold | + macinit.UnicastPauseFrameDetect | + macinit.ReceiveFlowControl | + macinit.TransmitFlowControl); + + /* Write to ETHERNET MACFCR */ + prvWriteMACFCR( heth, tmpreg ); + + /*----------------------- ETHERNET MACVLANTR Configuration ----------------*/ + /* Set the ETV bit according to ETH VLANTagComparison value */ + /* Set the VL bit according to ETH VLANTagIdentifier value */ + heth->Instance->MACVLANTR = (uint32_t)(macinit.VLANTagComparison | + macinit.VLANTagIdentifier); + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->MACVLANTR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->MACVLANTR = tmpreg; + + /* Ethernet DMA default initialization ************************************/ + dmainit.DropTCPIPChecksumErrorFrame = ETH_DROPTCPIPCHECKSUMERRORFRAME_ENABLE; + dmainit.ReceiveStoreForward = ETH_RECEIVESTOREFORWARD_ENABLE; + dmainit.FlushReceivedFrame = ETH_FLUSHRECEIVEDFRAME_ENABLE; + dmainit.TransmitStoreForward = ETH_TRANSMITSTOREFORWARD_ENABLE; + dmainit.TransmitThresholdControl = ETH_TRANSMITTHRESHOLDCONTROL_64BYTES; + dmainit.ForwardErrorFrames = ETH_FORWARDERRORFRAMES_DISABLE; + dmainit.ForwardUndersizedGoodFrames = ETH_FORWARDUNDERSIZEDGOODFRAMES_DISABLE; + dmainit.ReceiveThresholdControl = ETH_RECEIVEDTHRESHOLDCONTROL_64BYTES; + dmainit.SecondFrameOperate = ETH_SECONDFRAMEOPERARTE_ENABLE; + dmainit.AddressAlignedBeats = ETH_ADDRESSALIGNEDBEATS_ENABLE; + dmainit.FixedBurst = ETH_FIXEDBURST_ENABLE; + dmainit.RxDMABurstLength = ETH_RXDMABURSTLENGTH_32BEAT; + dmainit.TxDMABurstLength = ETH_TXDMABURSTLENGTH_32BEAT; + dmainit.EnhancedDescriptorFormat = ETH_DMAENHANCEDDESCRIPTOR_ENABLE; + dmainit.DescriptorSkipLength = 0x0; + dmainit.DMAArbitration = ETH_DMAARBITRATION_ROUNDROBIN_RXTX_1_1; + + /* Get the ETHERNET DMAOMR value */ + tmpreg = heth->Instance->DMAOMR; + /* Clear xx bits */ + tmpreg &= ETH_DMAOMR_CLEAR_MASK; + + /* Set the DT bit according to ETH DropTCPIPChecksumErrorFrame value */ + /* Set the RSF bit according to ETH ReceiveStoreForward value */ + /* Set the DFF bit according to ETH FlushReceivedFrame value */ + /* Set the TSF bit according to ETH TransmitStoreForward value */ + /* Set the TTC bit according to ETH TransmitThresholdControl value */ + /* Set the FEF bit according to ETH ForwardErrorFrames value */ + /* Set the FUF bit according to ETH ForwardUndersizedGoodFrames value */ + /* Set the RTC bit according to ETH ReceiveThresholdControl value */ + /* Set the OSF bit according to ETH SecondFrameOperate value */ + tmpreg |= (uint32_t)(dmainit.DropTCPIPChecksumErrorFrame | + dmainit.ReceiveStoreForward | + dmainit.FlushReceivedFrame | + dmainit.TransmitStoreForward | + dmainit.TransmitThresholdControl | + dmainit.ForwardErrorFrames | + dmainit.ForwardUndersizedGoodFrames | + dmainit.ReceiveThresholdControl | + dmainit.SecondFrameOperate); + + /* Write to ETHERNET DMAOMR */ + prvWriteDMAOMR( heth, tmpreg ); + + /*----------------------- ETHERNET DMABMR Configuration ------------------*/ + /* Set the AAL bit according to ETH AddressAlignedBeats value */ + /* Set the FB bit according to ETH FixedBurst value */ + /* Set the RPBL and 4*PBL bits according to ETH RxDMABurstLength value */ + /* Set the PBL and 4*PBL bits according to ETH TxDMABurstLength value */ + /* Set the Enhanced DMA descriptors bit according to ETH EnhancedDescriptorFormat value*/ + /* Set the DSL bit according to ETH DesciptorSkipLength value */ + /* Set the PR and DA bits according to ETH DMAArbitration value */ + heth->Instance->DMABMR = (uint32_t)(dmainit.AddressAlignedBeats | + dmainit.FixedBurst | + dmainit.RxDMABurstLength | /* !! if 4xPBL is selected for Tx or Rx it is applied for the other */ + dmainit.TxDMABurstLength | + dmainit.EnhancedDescriptorFormat | + (dmainit.DescriptorSkipLength << 2) | + dmainit.DMAArbitration | + ETH_DMABMR_USP); /* Enable use of separate PBL for Rx and Tx */ + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->DMABMR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->DMABMR = tmpreg; + + if(heth->Init.RxMode == ETH_RXINTERRUPT_MODE) + { + /* Enable the Ethernet Rx Interrupt */ + __HAL_ETH_DMA_ENABLE_IT(( heth ), ETH_DMA_IT_NIS | ETH_DMA_IT_R); + } + + /* Initialize MAC address in ethernet MAC */ + ETH_MACAddressConfig(heth, ETH_MAC_ADDRESS0, heth->Init.MACAddr); +} + +/** + * @brief Configures the selected MAC address. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param MacAddr: The MAC address to configure + * This parameter can be one of the following values: + * @arg ETH_MAC_Address0: MAC Address0 + * @arg ETH_MAC_Address1: MAC Address1 + * @arg ETH_MAC_Address2: MAC Address2 + * @arg ETH_MAC_Address3: MAC Address3 + * @param Addr: Pointer to MAC address buffer data (6 bytes) + * @retval HAL status + */ +static void ETH_MACAddressConfig(ETH_HandleTypeDef *heth, uint32_t MacAddr, uint8_t *Addr) +{ + uint32_t tmpreg; + + /* Check the parameters */ + assert_param( IS_ETH_MAC_ADDRESS0123( MacAddr ) ); + + /* Calculate the selected MAC address high register */ + tmpreg = 0x80000000ul | ( ( uint32_t )Addr[ 5 ] << 8) | (uint32_t)Addr[ 4 ]; + /* Load the selected MAC address high register */ + ( * ( __IO uint32_t * ) ( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + MacAddr ) ) ) = tmpreg; + /* Calculate the selected MAC address low register */ + tmpreg = ( ( uint32_t )Addr[ 3 ] << 24 ) | ( ( uint32_t )Addr[ 2 ] << 16 ) | ( ( uint32_t )Addr[ 1 ] << 8 ) | Addr[ 0 ]; + + /* Load the selected MAC address low register */ + ( * ( __IO uint32_t * ) ( ( uint32_t ) ( ETH_MAC_ADDR_LBASE + MacAddr ) ) ) = tmpreg; +} + +/** + * @brief Enables the MAC transmission. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_MACTransmissionEnable(ETH_HandleTypeDef *heth) +{ + uint32_t tmpreg = heth->Instance->MACCR | ETH_MACCR_TE; + + prvWriteMACCR( heth, tmpreg ); +} + +/** + * @brief Disables the MAC transmission. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_MACTransmissionDisable(ETH_HandleTypeDef *heth) +{ + uint32_t tmpreg = heth->Instance->MACCR & ~( ETH_MACCR_TE ); + + prvWriteMACCR( heth, tmpreg ); +} + +/** + * @brief Enables the MAC reception. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_MACReceptionEnable(ETH_HandleTypeDef *heth) +{ + __IO uint32_t tmpreg = heth->Instance->MACCR | ETH_MACCR_RE; + + prvWriteMACCR( heth, tmpreg ); +} + +/** + * @brief Disables the MAC reception. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_MACReceptionDisable(ETH_HandleTypeDef *heth) +{ + __IO uint32_t tmpreg = heth->Instance->MACCR & ~( ETH_MACCR_RE ); + + prvWriteMACCR( heth, tmpreg ); +} + +/** + * @brief Enables the DMA transmission. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_DMATransmissionEnable(ETH_HandleTypeDef *heth) +{ + /* Enable the DMA transmission */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR | ETH_DMAOMR_ST; + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @brief Disables the DMA transmission. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_DMATransmissionDisable(ETH_HandleTypeDef *heth) +{ + /* Disable the DMA transmission */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR & ~( ETH_DMAOMR_ST ); + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @brief Enables the DMA reception. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_DMAReceptionEnable(ETH_HandleTypeDef *heth) +{ + /* Enable the DMA reception */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR | ETH_DMAOMR_SR; + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @brief Disables the DMA reception. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_DMAReceptionDisable(ETH_HandleTypeDef *heth) +{ + /* Disable the DMA reception */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR & ~( ETH_DMAOMR_SR ); + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @brief Clears the ETHERNET transmit FIFO. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_FlushTransmitFIFO(ETH_HandleTypeDef *heth) +{ + /* Set the Flush Transmit FIFO bit */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR | ETH_DMAOMR_FTF; + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @} + */ + +#endif /* STM32F7xx */ +#endif /* HAL_ETH_MODULE_ENABLED */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/stm32f7xx_hal_eth.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/stm32f7xx_hal_eth.h new file mode 100644 index 000000000..0c401936b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32F7xx/stm32f7xx_hal_eth.h @@ -0,0 +1,2214 @@ +/** + ****************************************************************************** + * @file stm32f7xx_hal_eth.h + * @author MCD Application Team + * @version V1.2.2 + * @date 14-April-2017 + * @brief Header file of ETH HAL module. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * 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. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32F7xx_HAL_ETH_H +#define __STM32F7xx_HAL_ETH_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f7xx_hal_def.h" + +/** @addtogroup STM32F7xx_HAL_Driver + * @{ + */ + +/** @addtogroup ETH + * @{ + */ + +/** @addtogroup ETH_Private_Macros + * @{ + */ +#define IS_ETH_PHY_ADDRESS(ADDRESS) ((ADDRESS) <= 0x20) +#define IS_ETH_AUTONEGOTIATION(CMD) (((CMD) == ETH_AUTONEGOTIATION_ENABLE) || \ + ((CMD) == ETH_AUTONEGOTIATION_DISABLE)) +#define IS_ETH_SPEED(SPEED) (((SPEED) == ETH_SPEED_10M) || \ + ((SPEED) == ETH_SPEED_100M)) +#define IS_ETH_DUPLEX_MODE(MODE) (((MODE) == ETH_MODE_FULLDUPLEX) || \ + ((MODE) == ETH_MODE_HALFDUPLEX)) +#define IS_ETH_RX_MODE(MODE) (((MODE) == ETH_RXPOLLING_MODE) || \ + ((MODE) == ETH_RXINTERRUPT_MODE)) +#define IS_ETH_CHECKSUM_MODE(MODE) (((MODE) == ETH_CHECKSUM_BY_HARDWARE) || \ + ((MODE) == ETH_CHECKSUM_BY_SOFTWARE)) +#define IS_ETH_MEDIA_INTERFACE(MODE) (((MODE) == ETH_MEDIA_INTERFACE_MII) || \ + ((MODE) == ETH_MEDIA_INTERFACE_RMII)) +#define IS_ETH_WATCHDOG(CMD) (((CMD) == ETH_WATCHDOG_ENABLE) || \ + ((CMD) == ETH_WATCHDOG_DISABLE)) +#define IS_ETH_JABBER(CMD) (((CMD) == ETH_JABBER_ENABLE) || \ + ((CMD) == ETH_JABBER_DISABLE)) +#define IS_ETH_INTER_FRAME_GAP(GAP) (((GAP) == ETH_INTERFRAMEGAP_96BIT) || \ + ((GAP) == ETH_INTERFRAMEGAP_88BIT) || \ + ((GAP) == ETH_INTERFRAMEGAP_80BIT) || \ + ((GAP) == ETH_INTERFRAMEGAP_72BIT) || \ + ((GAP) == ETH_INTERFRAMEGAP_64BIT) || \ + ((GAP) == ETH_INTERFRAMEGAP_56BIT) || \ + ((GAP) == ETH_INTERFRAMEGAP_48BIT) || \ + ((GAP) == ETH_INTERFRAMEGAP_40BIT)) +#define IS_ETH_CARRIER_SENSE(CMD) (((CMD) == ETH_CARRIERSENCE_ENABLE) || \ + ((CMD) == ETH_CARRIERSENCE_DISABLE)) +#define IS_ETH_RECEIVE_OWN(CMD) (((CMD) == ETH_RECEIVEOWN_ENABLE) || \ + ((CMD) == ETH_RECEIVEOWN_DISABLE)) +#define IS_ETH_LOOPBACK_MODE(CMD) (((CMD) == ETH_LOOPBACKMODE_ENABLE) || \ + ((CMD) == ETH_LOOPBACKMODE_DISABLE)) +#define IS_ETH_CHECKSUM_OFFLOAD(CMD) (((CMD) == ETH_CHECKSUMOFFLAOD_ENABLE) || \ + ((CMD) == ETH_CHECKSUMOFFLAOD_DISABLE)) +#define IS_ETH_RETRY_TRANSMISSION(CMD) (((CMD) == ETH_RETRYTRANSMISSION_ENABLE) || \ + ((CMD) == ETH_RETRYTRANSMISSION_DISABLE)) +#define IS_ETH_AUTOMATIC_PADCRC_STRIP(CMD) (((CMD) == ETH_AUTOMATICPADCRCSTRIP_ENABLE) || \ + ((CMD) == ETH_AUTOMATICPADCRCSTRIP_DISABLE)) +#define IS_ETH_BACKOFF_LIMIT(LIMIT) (((LIMIT) == ETH_BACKOFFLIMIT_10) || \ + ((LIMIT) == ETH_BACKOFFLIMIT_8) || \ + ((LIMIT) == ETH_BACKOFFLIMIT_4) || \ + ((LIMIT) == ETH_BACKOFFLIMIT_1)) +#define IS_ETH_DEFERRAL_CHECK(CMD) (((CMD) == ETH_DEFFERRALCHECK_ENABLE) || \ + ((CMD) == ETH_DEFFERRALCHECK_DISABLE)) +#define IS_ETH_RECEIVE_ALL(CMD) (((CMD) == ETH_RECEIVEALL_ENABLE) || \ + ((CMD) == ETH_RECEIVEAll_DISABLE)) +#define IS_ETH_SOURCE_ADDR_FILTER(CMD) (((CMD) == ETH_SOURCEADDRFILTER_NORMAL_ENABLE) || \ + ((CMD) == ETH_SOURCEADDRFILTER_INVERSE_ENABLE) || \ + ((CMD) == ETH_SOURCEADDRFILTER_DISABLE)) +#define IS_ETH_CONTROL_FRAMES(PASS) (((PASS) == ETH_PASSCONTROLFRAMES_BLOCKALL) || \ + ((PASS) == ETH_PASSCONTROLFRAMES_FORWARDALL) || \ + ((PASS) == ETH_PASSCONTROLFRAMES_FORWARDPASSEDADDRFILTER)) +#define IS_ETH_BROADCAST_FRAMES_RECEPTION(CMD) (((CMD) == ETH_BROADCASTFRAMESRECEPTION_ENABLE) || \ + ((CMD) == ETH_BROADCASTFRAMESRECEPTION_DISABLE)) +#define IS_ETH_DESTINATION_ADDR_FILTER(FILTER) (((FILTER) == ETH_DESTINATIONADDRFILTER_NORMAL) || \ + ((FILTER) == ETH_DESTINATIONADDRFILTER_INVERSE)) +#define IS_ETH_PROMISCUOUS_MODE(CMD) (((CMD) == ETH_PROMISCUOUS_MODE_ENABLE) || \ + ((CMD) == ETH_PROMISCUOUS_MODE_DISABLE)) +#define IS_ETH_MULTICAST_FRAMES_FILTER(FILTER) (((FILTER) == ETH_MULTICASTFRAMESFILTER_PERFECTHASHTABLE) || \ + ((FILTER) == ETH_MULTICASTFRAMESFILTER_HASHTABLE) || \ + ((FILTER) == ETH_MULTICASTFRAMESFILTER_PERFECT) || \ + ((FILTER) == ETH_MULTICASTFRAMESFILTER_NONE)) +#define IS_ETH_UNICAST_FRAMES_FILTER(FILTER) (((FILTER) == ETH_UNICASTFRAMESFILTER_PERFECTHASHTABLE) || \ + ((FILTER) == ETH_UNICASTFRAMESFILTER_HASHTABLE) || \ + ((FILTER) == ETH_UNICASTFRAMESFILTER_PERFECT)) +#define IS_ETH_PAUSE_TIME(TIME) ((TIME) <= 0xFFFF) +#define IS_ETH_ZEROQUANTA_PAUSE(CMD) (((CMD) == ETH_ZEROQUANTAPAUSE_ENABLE) || \ + ((CMD) == ETH_ZEROQUANTAPAUSE_DISABLE)) +#define IS_ETH_PAUSE_LOW_THRESHOLD(THRESHOLD) (((THRESHOLD) == ETH_PAUSELOWTHRESHOLD_MINUS4) || \ + ((THRESHOLD) == ETH_PAUSELOWTHRESHOLD_MINUS28) || \ + ((THRESHOLD) == ETH_PAUSELOWTHRESHOLD_MINUS144) || \ + ((THRESHOLD) == ETH_PAUSELOWTHRESHOLD_MINUS256)) +#define IS_ETH_UNICAST_PAUSE_FRAME_DETECT(CMD) (((CMD) == ETH_UNICASTPAUSEFRAMEDETECT_ENABLE) || \ + ((CMD) == ETH_UNICASTPAUSEFRAMEDETECT_DISABLE)) +#define IS_ETH_RECEIVE_FLOWCONTROL(CMD) (((CMD) == ETH_RECEIVEFLOWCONTROL_ENABLE) || \ + ((CMD) == ETH_RECEIVEFLOWCONTROL_DISABLE)) +#define IS_ETH_TRANSMIT_FLOWCONTROL(CMD) (((CMD) == ETH_TRANSMITFLOWCONTROL_ENABLE) || \ + ((CMD) == ETH_TRANSMITFLOWCONTROL_DISABLE)) +#define IS_ETH_VLAN_TAG_COMPARISON(COMPARISON) (((COMPARISON) == ETH_VLANTAGCOMPARISON_12BIT) || \ + ((COMPARISON) == ETH_VLANTAGCOMPARISON_16BIT)) +#define IS_ETH_VLAN_TAG_IDENTIFIER(IDENTIFIER) ((IDENTIFIER) <= 0xFFFF) +#define IS_ETH_MAC_ADDRESS0123(ADDRESS) (((ADDRESS) == ETH_MAC_ADDRESS0) || \ + ((ADDRESS) == ETH_MAC_ADDRESS1) || \ + ((ADDRESS) == ETH_MAC_ADDRESS2) || \ + ((ADDRESS) == ETH_MAC_ADDRESS3)) +#define IS_ETH_MAC_ADDRESS123(ADDRESS) (((ADDRESS) == ETH_MAC_ADDRESS1) || \ + ((ADDRESS) == ETH_MAC_ADDRESS2) || \ + ((ADDRESS) == ETH_MAC_ADDRESS3)) +#define IS_ETH_MAC_ADDRESS_FILTER(FILTER) (((FILTER) == ETH_MAC_ADDRESSFILTER_SA) || \ + ((FILTER) == ETH_MAC_ADDRESSFILTER_DA)) +#define IS_ETH_MAC_ADDRESS_MASK(MASK) (((MASK) == ETH_MAC_ADDRESSMASK_BYTE6) || \ + ((MASK) == ETH_MAC_ADDRESSMASK_BYTE5) || \ + ((MASK) == ETH_MAC_ADDRESSMASK_BYTE4) || \ + ((MASK) == ETH_MAC_ADDRESSMASK_BYTE3) || \ + ((MASK) == ETH_MAC_ADDRESSMASK_BYTE2) || \ + ((MASK) == ETH_MAC_ADDRESSMASK_BYTE1)) +#define IS_ETH_DROP_TCPIP_CHECKSUM_FRAME(CMD) (((CMD) == ETH_DROPTCPIPCHECKSUMERRORFRAME_ENABLE) || \ + ((CMD) == ETH_DROPTCPIPCHECKSUMERRORFRAME_DISABLE)) +#define IS_ETH_RECEIVE_STORE_FORWARD(CMD) (((CMD) == ETH_RECEIVESTOREFORWARD_ENABLE) || \ + ((CMD) == ETH_RECEIVESTOREFORWARD_DISABLE)) +#define IS_ETH_FLUSH_RECEIVE_FRAME(CMD) (((CMD) == ETH_FLUSHRECEIVEDFRAME_ENABLE) || \ + ((CMD) == ETH_FLUSHRECEIVEDFRAME_DISABLE)) +#define IS_ETH_TRANSMIT_STORE_FORWARD(CMD) (((CMD) == ETH_TRANSMITSTOREFORWARD_ENABLE) || \ + ((CMD) == ETH_TRANSMITSTOREFORWARD_DISABLE)) +#define IS_ETH_TRANSMIT_THRESHOLD_CONTROL(THRESHOLD) (((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_64BYTES) || \ + ((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_128BYTES) || \ + ((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_192BYTES) || \ + ((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_256BYTES) || \ + ((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_40BYTES) || \ + ((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_32BYTES) || \ + ((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_24BYTES) || \ + ((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_16BYTES)) +#define IS_ETH_FORWARD_ERROR_FRAMES(CMD) (((CMD) == ETH_FORWARDERRORFRAMES_ENABLE) || \ + ((CMD) == ETH_FORWARDERRORFRAMES_DISABLE)) +#define IS_ETH_FORWARD_UNDERSIZED_GOOD_FRAMES(CMD) (((CMD) == ETH_FORWARDUNDERSIZEDGOODFRAMES_ENABLE) || \ + ((CMD) == ETH_FORWARDUNDERSIZEDGOODFRAMES_DISABLE)) +#define IS_ETH_RECEIVE_THRESHOLD_CONTROL(THRESHOLD) (((THRESHOLD) == ETH_RECEIVEDTHRESHOLDCONTROL_64BYTES) || \ + ((THRESHOLD) == ETH_RECEIVEDTHRESHOLDCONTROL_32BYTES) || \ + ((THRESHOLD) == ETH_RECEIVEDTHRESHOLDCONTROL_96BYTES) || \ + ((THRESHOLD) == ETH_RECEIVEDTHRESHOLDCONTROL_128BYTES)) +#define IS_ETH_SECOND_FRAME_OPERATE(CMD) (((CMD) == ETH_SECONDFRAMEOPERARTE_ENABLE) || \ + ((CMD) == ETH_SECONDFRAMEOPERARTE_DISABLE)) +#define IS_ETH_ADDRESS_ALIGNED_BEATS(CMD) (((CMD) == ETH_ADDRESSALIGNEDBEATS_ENABLE) || \ + ((CMD) == ETH_ADDRESSALIGNEDBEATS_DISABLE)) +#define IS_ETH_FIXED_BURST(CMD) (((CMD) == ETH_FIXEDBURST_ENABLE) || \ + ((CMD) == ETH_FIXEDBURST_DISABLE)) +#define IS_ETH_RXDMA_BURST_LENGTH(LENGTH) (((LENGTH) == ETH_RXDMABURSTLENGTH_1BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_2BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_4BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_8BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_16BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_32BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_4XPBL_4BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_4XPBL_8BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_4XPBL_16BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_4XPBL_32BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_4XPBL_64BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_4XPBL_128BEAT)) +#define IS_ETH_TXDMA_BURST_LENGTH(LENGTH) (((LENGTH) == ETH_TXDMABURSTLENGTH_1BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_2BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_4BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_8BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_16BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_32BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_4XPBL_4BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_4XPBL_8BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_4XPBL_16BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_4XPBL_32BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_4XPBL_64BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_4XPBL_128BEAT)) +#define IS_ETH_DMA_DESC_SKIP_LENGTH(LENGTH) ((LENGTH) <= 0x1F) +#define IS_ETH_DMA_ARBITRATION_ROUNDROBIN_RXTX(RATIO) (((RATIO) == ETH_DMAARBITRATION_ROUNDROBIN_RXTX_1_1) || \ + ((RATIO) == ETH_DMAARBITRATION_ROUNDROBIN_RXTX_2_1) || \ + ((RATIO) == ETH_DMAARBITRATION_ROUNDROBIN_RXTX_3_1) || \ + ((RATIO) == ETH_DMAARBITRATION_ROUNDROBIN_RXTX_4_1) || \ + ((RATIO) == ETH_DMAARBITRATION_RXPRIORTX)) +#define IS_ETH_DMATXDESC_GET_FLAG(FLAG) (((FLAG) == ETH_DMATXDESC_OWN) || \ + ((FLAG) == ETH_DMATXDESC_IC) || \ + ((FLAG) == ETH_DMATXDESC_LS) || \ + ((FLAG) == ETH_DMATXDESC_FS) || \ + ((FLAG) == ETH_DMATXDESC_DC) || \ + ((FLAG) == ETH_DMATXDESC_DP) || \ + ((FLAG) == ETH_DMATXDESC_TTSE) || \ + ((FLAG) == ETH_DMATXDESC_TER) || \ + ((FLAG) == ETH_DMATXDESC_TCH) || \ + ((FLAG) == ETH_DMATXDESC_TTSS) || \ + ((FLAG) == ETH_DMATXDESC_IHE) || \ + ((FLAG) == ETH_DMATXDESC_ES) || \ + ((FLAG) == ETH_DMATXDESC_JT) || \ + ((FLAG) == ETH_DMATXDESC_FF) || \ + ((FLAG) == ETH_DMATXDESC_PCE) || \ + ((FLAG) == ETH_DMATXDESC_LCA) || \ + ((FLAG) == ETH_DMATXDESC_NC) || \ + ((FLAG) == ETH_DMATXDESC_LCO) || \ + ((FLAG) == ETH_DMATXDESC_EC) || \ + ((FLAG) == ETH_DMATXDESC_VF) || \ + ((FLAG) == ETH_DMATXDESC_CC) || \ + ((FLAG) == ETH_DMATXDESC_ED) || \ + ((FLAG) == ETH_DMATXDESC_UF) || \ + ((FLAG) == ETH_DMATXDESC_DB)) +#define IS_ETH_DMA_TXDESC_SEGMENT(SEGMENT) (((SEGMENT) == ETH_DMATXDESC_LASTSEGMENTS) || \ + ((SEGMENT) == ETH_DMATXDESC_FIRSTSEGMENT)) +#define IS_ETH_DMA_TXDESC_CHECKSUM(CHECKSUM) (((CHECKSUM) == ETH_DMATXDESC_CHECKSUMBYPASS) || \ + ((CHECKSUM) == ETH_DMATXDESC_CHECKSUMIPV4HEADER) || \ + ((CHECKSUM) == ETH_DMATXDESC_CHECKSUMTCPUDPICMPSEGMENT) || \ + ((CHECKSUM) == ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL)) +#define IS_ETH_DMATXDESC_BUFFER_SIZE(SIZE) ((SIZE) <= 0x1FFF) +#define IS_ETH_DMARXDESC_GET_FLAG(FLAG) (((FLAG) == ETH_DMARXDESC_OWN) || \ + ((FLAG) == ETH_DMARXDESC_AFM) || \ + ((FLAG) == ETH_DMARXDESC_ES) || \ + ((FLAG) == ETH_DMARXDESC_DE) || \ + ((FLAG) == ETH_DMARXDESC_SAF) || \ + ((FLAG) == ETH_DMARXDESC_LE) || \ + ((FLAG) == ETH_DMARXDESC_OE) || \ + ((FLAG) == ETH_DMARXDESC_VLAN) || \ + ((FLAG) == ETH_DMARXDESC_FS) || \ + ((FLAG) == ETH_DMARXDESC_LS) || \ + ((FLAG) == ETH_DMARXDESC_IPV4HCE) || \ + ((FLAG) == ETH_DMARXDESC_LC) || \ + ((FLAG) == ETH_DMARXDESC_FT) || \ + ((FLAG) == ETH_DMARXDESC_RWT) || \ + ((FLAG) == ETH_DMARXDESC_RE) || \ + ((FLAG) == ETH_DMARXDESC_DBE) || \ + ((FLAG) == ETH_DMARXDESC_CE) || \ + ((FLAG) == ETH_DMARXDESC_MAMPCE)) +#define IS_ETH_DMA_RXDESC_BUFFER(BUFFER) (((BUFFER) == ETH_DMARXDESC_BUFFER1) || \ + ((BUFFER) == ETH_DMARXDESC_BUFFER2)) +#define IS_ETH_PMT_GET_FLAG(FLAG) (((FLAG) == ETH_PMT_FLAG_WUFR) || \ + ((FLAG) == ETH_PMT_FLAG_MPR)) +#define IS_ETH_DMA_FLAG(FLAG) ((((FLAG) & (uint32_t)0xC7FE1800) == 0x00) && ((FLAG) != 0x00)) +#define IS_ETH_DMA_GET_FLAG(FLAG) (((FLAG) == ETH_DMA_FLAG_TST) || ((FLAG) == ETH_DMA_FLAG_PMT) || \ + ((FLAG) == ETH_DMA_FLAG_MMC) || ((FLAG) == ETH_DMA_FLAG_DATATRANSFERERROR) || \ + ((FLAG) == ETH_DMA_FLAG_READWRITEERROR) || ((FLAG) == ETH_DMA_FLAG_ACCESSERROR) || \ + ((FLAG) == ETH_DMA_FLAG_NIS) || ((FLAG) == ETH_DMA_FLAG_AIS) || \ + ((FLAG) == ETH_DMA_FLAG_ER) || ((FLAG) == ETH_DMA_FLAG_FBE) || \ + ((FLAG) == ETH_DMA_FLAG_ET) || ((FLAG) == ETH_DMA_FLAG_RWT) || \ + ((FLAG) == ETH_DMA_FLAG_RPS) || ((FLAG) == ETH_DMA_FLAG_RBU) || \ + ((FLAG) == ETH_DMA_FLAG_R) || ((FLAG) == ETH_DMA_FLAG_TU) || \ + ((FLAG) == ETH_DMA_FLAG_RO) || ((FLAG) == ETH_DMA_FLAG_TJT) || \ + ((FLAG) == ETH_DMA_FLAG_TBU) || ((FLAG) == ETH_DMA_FLAG_TPS) || \ + ((FLAG) == ETH_DMA_FLAG_T)) +#define IS_ETH_MAC_IT(IT) ((((IT) & (uint32_t)0xFFFFFDF1) == 0x00) && ((IT) != 0x00)) +#define IS_ETH_MAC_GET_IT(IT) (((IT) == ETH_MAC_IT_TST) || ((IT) == ETH_MAC_IT_MMCT) || \ + ((IT) == ETH_MAC_IT_MMCR) || ((IT) == ETH_MAC_IT_MMC) || \ + ((IT) == ETH_MAC_IT_PMT)) +#define IS_ETH_MAC_GET_FLAG(FLAG) (((FLAG) == ETH_MAC_FLAG_TST) || ((FLAG) == ETH_MAC_FLAG_MMCT) || \ + ((FLAG) == ETH_MAC_FLAG_MMCR) || ((FLAG) == ETH_MAC_FLAG_MMC) || \ + ((FLAG) == ETH_MAC_FLAG_PMT)) +#define IS_ETH_DMA_IT(IT) ((((IT) & (uint32_t)0xC7FE1800) == 0x00) && ((IT) != 0x00)) +#define IS_ETH_DMA_GET_IT(IT) (((IT) == ETH_DMA_IT_TST) || ((IT) == ETH_DMA_IT_PMT) || \ + ((IT) == ETH_DMA_IT_MMC) || ((IT) == ETH_DMA_IT_NIS) || \ + ((IT) == ETH_DMA_IT_AIS) || ((IT) == ETH_DMA_IT_ER) || \ + ((IT) == ETH_DMA_IT_FBE) || ((IT) == ETH_DMA_IT_ET) || \ + ((IT) == ETH_DMA_IT_RWT) || ((IT) == ETH_DMA_IT_RPS) || \ + ((IT) == ETH_DMA_IT_RBU) || ((IT) == ETH_DMA_IT_R) || \ + ((IT) == ETH_DMA_IT_TU) || ((IT) == ETH_DMA_IT_RO) || \ + ((IT) == ETH_DMA_IT_TJT) || ((IT) == ETH_DMA_IT_TBU) || \ + ((IT) == ETH_DMA_IT_TPS) || ((IT) == ETH_DMA_IT_T)) +#define IS_ETH_DMA_GET_OVERFLOW(OVERFLOW) (((OVERFLOW) == ETH_DMA_OVERFLOW_RXFIFOCOUNTER) || \ + ((OVERFLOW) == ETH_DMA_OVERFLOW_MISSEDFRAMECOUNTER)) +#define IS_ETH_MMC_IT(IT) (((((IT) & (uint32_t)0xFFDF3FFF) == 0x00) || (((IT) & (uint32_t)0xEFFDFF9F) == 0x00)) && \ + ((IT) != 0x00)) +#define IS_ETH_MMC_GET_IT(IT) (((IT) == ETH_MMC_IT_TGF) || ((IT) == ETH_MMC_IT_TGFMSC) || \ + ((IT) == ETH_MMC_IT_TGFSC) || ((IT) == ETH_MMC_IT_RGUF) || \ + ((IT) == ETH_MMC_IT_RFAE) || ((IT) == ETH_MMC_IT_RFCE)) +#define IS_ETH_ENHANCED_DESCRIPTOR_FORMAT(CMD) (((CMD) == ETH_DMAENHANCEDDESCRIPTOR_ENABLE) || \ + ((CMD) == ETH_DMAENHANCEDDESCRIPTOR_DISABLE)) + + +/** + * @} + */ + +/** @addtogroup ETH_Private_Defines + * @{ + */ +/* Delay to wait when writing to some Ethernet registers */ +#define ETH_REG_WRITE_DELAY ((uint32_t)0x00000001U) + +/* Ethernet Errors */ +#define ETH_SUCCESS ((uint32_t)0U) +#define ETH_ERROR ((uint32_t)1U) + +/* Ethernet DMA Tx descriptors Collision Count Shift */ +#define ETH_DMATXDESC_COLLISION_COUNTSHIFT ((uint32_t)3U) + +/* Ethernet DMA Tx descriptors Buffer2 Size Shift */ +#define ETH_DMATXDESC_BUFFER2_SIZESHIFT ((uint32_t)16U) + +/* Ethernet DMA Rx descriptors Frame Length Shift */ +#define ETH_DMARXDESC_FRAME_LENGTHSHIFT ((uint32_t)16U) + +/* Ethernet DMA Rx descriptors Buffer2 Size Shift */ +#define ETH_DMARXDESC_BUFFER2_SIZESHIFT ((uint32_t)16U) + +/* Ethernet DMA Rx descriptors Frame length Shift */ +#define ETH_DMARXDESC_FRAMELENGTHSHIFT ((uint32_t)16) + +/* Ethernet MAC address offsets */ +#define ETH_MAC_ADDR_HBASE (uint32_t)(ETH_MAC_BASE + (uint32_t)0x40U) /* Ethernet MAC address high offset */ +#define ETH_MAC_ADDR_LBASE (uint32_t)(ETH_MAC_BASE + (uint32_t)0x44U) /* Ethernet MAC address low offset */ + +/* Ethernet MACMIIAR register Mask */ +#define ETH_MACMIIAR_CR_MASK ((uint32_t)0xFFFFFFE3U) + +/* Ethernet MACCR register Mask */ +#define ETH_MACCR_CLEAR_MASK ((uint32_t)0xFF20810FU) + +/* Ethernet MACFCR register Mask */ +#define ETH_MACFCR_CLEAR_MASK ((uint32_t)0x0000FF41U) + +/* Ethernet DMAOMR register Mask */ +#define ETH_DMAOMR_CLEAR_MASK ((uint32_t)0xF8DE3F23U) + +/* Ethernet Remote Wake-up frame register length */ +#define ETH_WAKEUP_REGISTER_LENGTH 8U + +/* Ethernet Missed frames counter Shift */ +#define ETH_DMA_RX_OVERFLOW_MISSEDFRAMES_COUNTERSHIFT 17U + /** + * @} + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup ETH_Exported_Types ETH Exported Types + * @{ + */ + +/** + * @brief HAL State structures definition + */ +typedef enum +{ + HAL_ETH_STATE_RESET = 0x00U, /*!< Peripheral not yet Initialized or disabled */ + HAL_ETH_STATE_READY = 0x01U, /*!< Peripheral Initialized and ready for use */ + HAL_ETH_STATE_BUSY = 0x02U, /*!< an internal process is ongoing */ + HAL_ETH_STATE_BUSY_TX = 0x12U, /*!< Data Transmission process is ongoing */ + HAL_ETH_STATE_BUSY_RX = 0x22U, /*!< Data Reception process is ongoing */ + HAL_ETH_STATE_BUSY_TX_RX = 0x32U, /*!< Data Transmission and Reception process is ongoing */ + HAL_ETH_STATE_BUSY_WR = 0x42U, /*!< Write process is ongoing */ + HAL_ETH_STATE_BUSY_RD = 0x82U, /*!< Read process is ongoing */ + HAL_ETH_STATE_TIMEOUT = 0x03U, /*!< Timeout state */ + HAL_ETH_STATE_ERROR = 0x04U /*!< Reception process is ongoing */ +}HAL_ETH_StateTypeDef; + +/** + * @brief ETH Init Structure definition + */ + +typedef struct +{ + uint32_t AutoNegotiation; /*!< Selects or not the AutoNegotiation mode for the external PHY + The AutoNegotiation allows an automatic setting of the Speed (10/100Mbps) + and the mode (half/full-duplex). + This parameter can be a value of @ref ETH_AutoNegotiation */ + + uint32_t Speed; /*!< Sets the Ethernet speed: 10/100 Mbps. + This parameter can be a value of @ref ETH_Speed */ + + uint32_t DuplexMode; /*!< Selects the MAC duplex mode: Half-Duplex or Full-Duplex mode + This parameter can be a value of @ref ETH_Duplex_Mode */ + + uint16_t PhyAddress; /*!< Ethernet PHY address. + This parameter must be a number between Min_Data = 0 and Max_Data = 32 */ + + uint8_t *MACAddr; /*!< MAC Address of used Hardware: must be pointer on an array of 6 bytes */ + + uint32_t RxMode; /*!< Selects the Ethernet Rx mode: Polling mode, Interrupt mode. + This parameter can be a value of @ref ETH_Rx_Mode */ + + uint32_t ChecksumMode; /*!< Selects if the checksum is check by hardware or by software. + This parameter can be a value of @ref ETH_Checksum_Mode */ + + uint32_t MediaInterface ; /*!< Selects the media-independent interface or the reduced media-independent interface. + This parameter can be a value of @ref ETH_Media_Interface */ + +} ETH_InitTypeDef; + + + /** + * @brief ETH MAC Configuration Structure definition + */ + +typedef struct +{ + uint32_t Watchdog; /*!< Selects or not the Watchdog timer + When enabled, the MAC allows no more then 2048 bytes to be received. + When disabled, the MAC can receive up to 16384 bytes. + This parameter can be a value of @ref ETH_Watchdog */ + + uint32_t Jabber; /*!< Selects or not Jabber timer + When enabled, the MAC allows no more then 2048 bytes to be sent. + When disabled, the MAC can send up to 16384 bytes. + This parameter can be a value of @ref ETH_Jabber */ + + uint32_t InterFrameGap; /*!< Selects the minimum IFG between frames during transmission. + This parameter can be a value of @ref ETH_Inter_Frame_Gap */ + + uint32_t CarrierSense; /*!< Selects or not the Carrier Sense. + This parameter can be a value of @ref ETH_Carrier_Sense */ + + uint32_t ReceiveOwn; /*!< Selects or not the ReceiveOwn, + ReceiveOwn allows the reception of frames when the TX_EN signal is asserted + in Half-Duplex mode. + This parameter can be a value of @ref ETH_Receive_Own */ + + uint32_t LoopbackMode; /*!< Selects or not the internal MAC MII Loopback mode. + This parameter can be a value of @ref ETH_Loop_Back_Mode */ + + uint32_t ChecksumOffload; /*!< Selects or not the IPv4 checksum checking for received frame payloads' TCP/UDP/ICMP headers. + This parameter can be a value of @ref ETH_Checksum_Offload */ + + uint32_t RetryTransmission; /*!< Selects or not the MAC attempt retries transmission, based on the settings of BL, + when a collision occurs (Half-Duplex mode). + This parameter can be a value of @ref ETH_Retry_Transmission */ + + uint32_t AutomaticPadCRCStrip; /*!< Selects or not the Automatic MAC Pad/CRC Stripping. + This parameter can be a value of @ref ETH_Automatic_Pad_CRC_Strip */ + + uint32_t BackOffLimit; /*!< Selects the BackOff limit value. + This parameter can be a value of @ref ETH_Back_Off_Limit */ + + uint32_t DeferralCheck; /*!< Selects or not the deferral check function (Half-Duplex mode). + This parameter can be a value of @ref ETH_Deferral_Check */ + + uint32_t ReceiveAll; /*!< Selects or not all frames reception by the MAC (No filtering). + This parameter can be a value of @ref ETH_Receive_All */ + + uint32_t SourceAddrFilter; /*!< Selects the Source Address Filter mode. + This parameter can be a value of @ref ETH_Source_Addr_Filter */ + + uint32_t PassControlFrames; /*!< Sets the forwarding mode of the control frames (including unicast and multicast PAUSE frames) + This parameter can be a value of @ref ETH_Pass_Control_Frames */ + + uint32_t BroadcastFramesReception; /*!< Selects or not the reception of Broadcast Frames. + This parameter can be a value of @ref ETH_Broadcast_Frames_Reception */ + + uint32_t DestinationAddrFilter; /*!< Sets the destination filter mode for both unicast and multicast frames. + This parameter can be a value of @ref ETH_Destination_Addr_Filter */ + + uint32_t PromiscuousMode; /*!< Selects or not the Promiscuous Mode + This parameter can be a value of @ref ETH_Promiscuous_Mode */ + + uint32_t MulticastFramesFilter; /*!< Selects the Multicast Frames filter mode: None/HashTableFilter/PerfectFilter/PerfectHashTableFilter. + This parameter can be a value of @ref ETH_Multicast_Frames_Filter */ + + uint32_t UnicastFramesFilter; /*!< Selects the Unicast Frames filter mode: HashTableFilter/PerfectFilter/PerfectHashTableFilter. + This parameter can be a value of @ref ETH_Unicast_Frames_Filter */ + + uint32_t HashTableHigh; /*!< This field holds the higher 32 bits of Hash table. + This parameter must be a number between Min_Data = 0x0 and Max_Data = 0xFFFFFFFF */ + + uint32_t HashTableLow; /*!< This field holds the lower 32 bits of Hash table. + This parameter must be a number between Min_Data = 0x0 and Max_Data = 0xFFFFFFFF */ + + uint32_t PauseTime; /*!< This field holds the value to be used in the Pause Time field in the transmit control frame. + This parameter must be a number between Min_Data = 0x0 and Max_Data = 0xFFFF */ + + uint32_t ZeroQuantaPause; /*!< Selects or not the automatic generation of Zero-Quanta Pause Control frames. + This parameter can be a value of @ref ETH_Zero_Quanta_Pause */ + + uint32_t PauseLowThreshold; /*!< This field configures the threshold of the PAUSE to be checked for + automatic retransmission of PAUSE Frame. + This parameter can be a value of @ref ETH_Pause_Low_Threshold */ + + uint32_t UnicastPauseFrameDetect; /*!< Selects or not the MAC detection of the Pause frames (with MAC Address0 + unicast address and unique multicast address). + This parameter can be a value of @ref ETH_Unicast_Pause_Frame_Detect */ + + uint32_t ReceiveFlowControl; /*!< Enables or disables the MAC to decode the received Pause frame and + disable its transmitter for a specified time (Pause Time) + This parameter can be a value of @ref ETH_Receive_Flow_Control */ + + uint32_t TransmitFlowControl; /*!< Enables or disables the MAC to transmit Pause frames (Full-Duplex mode) + or the MAC back-pressure operation (Half-Duplex mode) + This parameter can be a value of @ref ETH_Transmit_Flow_Control */ + + uint32_t VLANTagComparison; /*!< Selects the 12-bit VLAN identifier or the complete 16-bit VLAN tag for + comparison and filtering. + This parameter can be a value of @ref ETH_VLAN_Tag_Comparison */ + + uint32_t VLANTagIdentifier; /*!< Holds the VLAN tag identifier for receive frames */ + +} ETH_MACInitTypeDef; + + +/** + * @brief ETH DMA Configuration Structure definition + */ + +typedef struct +{ + uint32_t DropTCPIPChecksumErrorFrame; /*!< Selects or not the Dropping of TCP/IP Checksum Error Frames. + This parameter can be a value of @ref ETH_Drop_TCP_IP_Checksum_Error_Frame */ + + uint32_t ReceiveStoreForward; /*!< Enables or disables the Receive store and forward mode. + This parameter can be a value of @ref ETH_Receive_Store_Forward */ + + uint32_t FlushReceivedFrame; /*!< Enables or disables the flushing of received frames. + This parameter can be a value of @ref ETH_Flush_Received_Frame */ + + uint32_t TransmitStoreForward; /*!< Enables or disables Transmit store and forward mode. + This parameter can be a value of @ref ETH_Transmit_Store_Forward */ + + uint32_t TransmitThresholdControl; /*!< Selects or not the Transmit Threshold Control. + This parameter can be a value of @ref ETH_Transmit_Threshold_Control */ + + uint32_t ForwardErrorFrames; /*!< Selects or not the forward to the DMA of erroneous frames. + This parameter can be a value of @ref ETH_Forward_Error_Frames */ + + uint32_t ForwardUndersizedGoodFrames; /*!< Enables or disables the Rx FIFO to forward Undersized frames (frames with no Error + and length less than 64 bytes) including pad-bytes and CRC) + This parameter can be a value of @ref ETH_Forward_Undersized_Good_Frames */ + + uint32_t ReceiveThresholdControl; /*!< Selects the threshold level of the Receive FIFO. + This parameter can be a value of @ref ETH_Receive_Threshold_Control */ + + uint32_t SecondFrameOperate; /*!< Selects or not the Operate on second frame mode, which allows the DMA to process a second + frame of Transmit data even before obtaining the status for the first frame. + This parameter can be a value of @ref ETH_Second_Frame_Operate */ + + uint32_t AddressAlignedBeats; /*!< Enables or disables the Address Aligned Beats. + This parameter can be a value of @ref ETH_Address_Aligned_Beats */ + + uint32_t FixedBurst; /*!< Enables or disables the AHB Master interface fixed burst transfers. + This parameter can be a value of @ref ETH_Fixed_Burst */ + + uint32_t RxDMABurstLength; /*!< Indicates the maximum number of beats to be transferred in one Rx DMA transaction. + This parameter can be a value of @ref ETH_Rx_DMA_Burst_Length */ + + uint32_t TxDMABurstLength; /*!< Indicates the maximum number of beats to be transferred in one Tx DMA transaction. + This parameter can be a value of @ref ETH_Tx_DMA_Burst_Length */ + + uint32_t EnhancedDescriptorFormat; /*!< Enables the enhanced descriptor format. + This parameter can be a value of @ref ETH_DMA_Enhanced_descriptor_format */ + + uint32_t DescriptorSkipLength; /*!< Specifies the number of word to skip between two unchained descriptors (Ring mode) + This parameter must be a number between Min_Data = 0 and Max_Data = 32 */ + + uint32_t DMAArbitration; /*!< Selects the DMA Tx/Rx arbitration. + This parameter can be a value of @ref ETH_DMA_Arbitration */ +} ETH_DMAInitTypeDef; + + +/** + * @brief ETH DMA Descriptors data structure definition + */ + +typedef struct +{ + __IO uint32_t Status; /*!< Status */ + + uint32_t ControlBufferSize; /*!< Control and Buffer1, Buffer2 lengths */ + + uint32_t Buffer1Addr; /*!< Buffer1 address pointer */ + + uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */ + + /*!< Enhanced Ethernet DMA PTP Descriptors */ + uint32_t ExtendedStatus; /*!< Extended status for PTP receive descriptor */ + + uint32_t Reserved1; /*!< Reserved */ + + uint32_t TimeStampLow; /*!< Time Stamp Low value for transmit and receive */ + + uint32_t TimeStampHigh; /*!< Time Stamp High value for transmit and receive */ + +} ETH_DMADescTypeDef; + + +/** + * @brief Received Frame Informations structure definition + */ +typedef struct +{ + ETH_DMADescTypeDef *FSRxDesc; /*!< First Segment Rx Desc */ + + ETH_DMADescTypeDef *LSRxDesc; /*!< Last Segment Rx Desc */ + + uint32_t SegCount; /*!< Segment count */ + + uint32_t length; /*!< Frame length */ + + uint32_t buffer; /*!< Frame buffer */ + +} ETH_DMARxFrameInfos; + + +/** + * @brief ETH Handle Structure definition + */ + +typedef struct +{ + ETH_TypeDef *Instance; /*!< Register base address */ + + ETH_InitTypeDef Init; /*!< Ethernet Init Configuration */ + + uint32_t LinkStatus; /*!< Ethernet link status */ + + ETH_DMADescTypeDef *RxDesc; /*!< Rx descriptor to Get */ + + ETH_DMADescTypeDef *TxDesc; /*!< Tx descriptor to Set */ + + ETH_DMARxFrameInfos RxFrameInfos; /*!< last Rx frame infos */ + + __IO HAL_ETH_StateTypeDef State; /*!< ETH communication state */ + + HAL_LockTypeDef Lock; /*!< ETH Lock */ + +} ETH_HandleTypeDef; + + /** + * @} + */ + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup ETH_Exported_Constants ETH Exported Constants + * @{ + */ + +/** @defgroup ETH_Buffers_setting ETH Buffers setting + * @{ + */ +#define ETH_MAX_PACKET_SIZE ((uint32_t)1524U) /*!< ETH_HEADER + ETH_EXTRA + ETH_VLAN_TAG + ETH_MAX_ETH_PAYLOAD + ETH_CRC */ +#define ETH_HEADER ((uint32_t)14U) /*!< 6 byte Dest addr, 6 byte Src addr, 2 byte length/type */ +#define ETH_CRC ((uint32_t)4U) /*!< Ethernet CRC */ +#define ETH_EXTRA ((uint32_t)2U) /*!< Extra bytes in some cases */ +#define ETH_VLAN_TAG ((uint32_t)4U) /*!< optional 802.1q VLAN Tag */ +#define ETH_MIN_ETH_PAYLOAD ((uint32_t)46U) /*!< Minimum Ethernet payload size */ +#define ETH_MAX_ETH_PAYLOAD ((uint32_t)1500U) /*!< Maximum Ethernet payload size */ +#define ETH_JUMBO_FRAME_PAYLOAD ((uint32_t)9000U) /*!< Jumbo frame payload size */ + + /* Ethernet driver receive buffers are organized in a chained linked-list, when + an Ethernet packet is received, the Rx-DMA will transfer the packet from RxFIFO + to the driver receive buffers memory. + + Depending on the size of the received Ethernet packet and the size of + each Ethernet driver receive buffer, the received packet can take one or more + Ethernet driver receive buffer. + + In below are defined the size of one Ethernet driver receive buffer ETH_RX_BUF_SIZE + and the total count of the driver receive buffers ETH_RXBUFNB. + + The configured value for ETH_RX_BUF_SIZE and ETH_RXBUFNB are only provided as + example, they can be reconfigured in the application layer to fit the application + needs */ + +/* Here we configure each Ethernet driver receive buffer to fit the Max size Ethernet + packet */ +#ifndef ETH_RX_BUF_SIZE + #define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE +#endif + +/* 5 Ethernet driver receive buffers are used (in a chained linked list)*/ +#ifndef ETH_RXBUFNB + #define ETH_RXBUFNB ((uint32_t)5U) /* 5 Rx buffers of size ETH_RX_BUF_SIZE */ +#endif + + + /* Ethernet driver transmit buffers are organized in a chained linked-list, when + an Ethernet packet is transmitted, Tx-DMA will transfer the packet from the + driver transmit buffers memory to the TxFIFO. + + Depending on the size of the Ethernet packet to be transmitted and the size of + each Ethernet driver transmit buffer, the packet to be transmitted can take + one or more Ethernet driver transmit buffer. + + In below are defined the size of one Ethernet driver transmit buffer ETH_TX_BUF_SIZE + and the total count of the driver transmit buffers ETH_TXBUFNB. + + The configured value for ETH_TX_BUF_SIZE and ETH_TXBUFNB are only provided as + example, they can be reconfigured in the application layer to fit the application + needs */ + +/* Here we configure each Ethernet driver transmit buffer to fit the Max size Ethernet + packet */ +#ifndef ETH_TX_BUF_SIZE + #define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE +#endif + +/* 5 Ethernet driver transmit buffers are used (in a chained linked list)*/ +#ifndef ETH_TXBUFNB + #define ETH_TXBUFNB ((uint32_t)5U) /* 5 Tx buffers of size ETH_TX_BUF_SIZE */ +#endif + + /** + * @} + */ + +/** @defgroup ETH_DMA_TX_Descriptor ETH DMA TX Descriptor + * @{ + */ + +/* + DMA Tx Descriptor + ----------------------------------------------------------------------------------------------- + TDES0 | OWN(31) | CTRL[30:26] | Reserved[25:24] | CTRL[23:20] | Reserved[19:17] | Status[16:0] | + ----------------------------------------------------------------------------------------------- + TDES1 | Reserved[31:29] | Buffer2 ByteCount[28:16] | Reserved[15:13] | Buffer1 ByteCount[12:0] | + ----------------------------------------------------------------------------------------------- + TDES2 | Buffer1 Address [31:0] | + ----------------------------------------------------------------------------------------------- + TDES3 | Buffer2 Address [31:0] / Next Descriptor Address [31:0] | + ----------------------------------------------------------------------------------------------- +*/ + +/** + * @brief Bit definition of TDES0 register: DMA Tx descriptor status register + */ +#define ETH_DMATXDESC_OWN ((uint32_t)0x80000000U) /*!< OWN bit: descriptor is owned by DMA engine */ +#define ETH_DMATXDESC_IC ((uint32_t)0x40000000U) /*!< Interrupt on Completion */ +#define ETH_DMATXDESC_LS ((uint32_t)0x20000000U) /*!< Last Segment */ +#define ETH_DMATXDESC_FS ((uint32_t)0x10000000U) /*!< First Segment */ +#define ETH_DMATXDESC_DC ((uint32_t)0x08000000U) /*!< Disable CRC */ +#define ETH_DMATXDESC_DP ((uint32_t)0x04000000U) /*!< Disable Padding */ +#define ETH_DMATXDESC_TTSE ((uint32_t)0x02000000U) /*!< Transmit Time Stamp Enable */ +#define ETH_DMATXDESC_CIC ((uint32_t)0x00C00000U) /*!< Checksum Insertion Control: 4 cases */ +#define ETH_DMATXDESC_CIC_BYPASS ((uint32_t)0x00000000U) /*!< Do Nothing: Checksum Engine is bypassed */ +#define ETH_DMATXDESC_CIC_IPV4HEADER ((uint32_t)0x00400000U) /*!< IPV4 header Checksum Insertion */ +#define ETH_DMATXDESC_CIC_TCPUDPICMP_SEGMENT ((uint32_t)0x00800000U) /*!< TCP/UDP/ICMP Checksum Insertion calculated over segment only */ +#define ETH_DMATXDESC_CIC_TCPUDPICMP_FULL ((uint32_t)0x00C00000U) /*!< TCP/UDP/ICMP Checksum Insertion fully calculated */ +#define ETH_DMATXDESC_TER ((uint32_t)0x00200000U) /*!< Transmit End of Ring */ +#define ETH_DMATXDESC_TCH ((uint32_t)0x00100000U) /*!< Second Address Chained */ +#define ETH_DMATXDESC_TTSS ((uint32_t)0x00020000U) /*!< Tx Time Stamp Status */ +#define ETH_DMATXDESC_IHE ((uint32_t)0x00010000U) /*!< IP Header Error */ +#define ETH_DMATXDESC_ES ((uint32_t)0x00008000U) /*!< Error summary: OR of the following bits: UE || ED || EC || LCO || NC || LCA || FF || JT */ +#define ETH_DMATXDESC_JT ((uint32_t)0x00004000U) /*!< Jabber Timeout */ +#define ETH_DMATXDESC_FF ((uint32_t)0x00002000U) /*!< Frame Flushed: DMA/MTL flushed the frame due to SW flush */ +#define ETH_DMATXDESC_PCE ((uint32_t)0x00001000U) /*!< Payload Checksum Error */ +#define ETH_DMATXDESC_LCA ((uint32_t)0x00000800U) /*!< Loss of Carrier: carrier lost during transmission */ +#define ETH_DMATXDESC_NC ((uint32_t)0x00000400U) /*!< No Carrier: no carrier signal from the transceiver */ +#define ETH_DMATXDESC_LCO ((uint32_t)0x00000200U) /*!< Late Collision: transmission aborted due to collision */ +#define ETH_DMATXDESC_EC ((uint32_t)0x00000100U) /*!< Excessive Collision: transmission aborted after 16 collisions */ +#define ETH_DMATXDESC_VF ((uint32_t)0x00000080U) /*!< VLAN Frame */ +#define ETH_DMATXDESC_CC ((uint32_t)0x00000078U) /*!< Collision Count */ +#define ETH_DMATXDESC_ED ((uint32_t)0x00000004U) /*!< Excessive Deferral */ +#define ETH_DMATXDESC_UF ((uint32_t)0x00000002U) /*!< Underflow Error: late data arrival from the memory */ +#define ETH_DMATXDESC_DB ((uint32_t)0x00000001U) /*!< Deferred Bit */ + +/** + * @brief Bit definition of TDES1 register + */ +#define ETH_DMATXDESC_TBS2 ((uint32_t)0x1FFF0000U) /*!< Transmit Buffer2 Size */ +#define ETH_DMATXDESC_TBS1 ((uint32_t)0x00001FFFU) /*!< Transmit Buffer1 Size */ + +/** + * @brief Bit definition of TDES2 register + */ +#define ETH_DMATXDESC_B1AP ((uint32_t)0xFFFFFFFFU) /*!< Buffer1 Address Pointer */ + +/** + * @brief Bit definition of TDES3 register + */ +#define ETH_DMATXDESC_B2AP ((uint32_t)0xFFFFFFFFU) /*!< Buffer2 Address Pointer */ + + /*--------------------------------------------------------------------------------------------- + TDES6 | Transmit Time Stamp Low [31:0] | + ----------------------------------------------------------------------------------------------- + TDES7 | Transmit Time Stamp High [31:0] | + ----------------------------------------------------------------------------------------------*/ + +/* Bit definition of TDES6 register */ + #define ETH_DMAPTPTXDESC_TTSL ((uint32_t)0xFFFFFFFFU) /* Transmit Time Stamp Low */ + +/* Bit definition of TDES7 register */ + #define ETH_DMAPTPTXDESC_TTSH ((uint32_t)0xFFFFFFFFU) /* Transmit Time Stamp High */ + +/** + * @} + */ +/** @defgroup ETH_DMA_RX_Descriptor ETH DMA RX Descriptor + * @{ + */ + +/* + DMA Rx Descriptor + -------------------------------------------------------------------------------------------------------------------- + RDES0 | OWN(31) | Status [30:0] | + --------------------------------------------------------------------------------------------------------------------- + RDES1 | CTRL(31) | Reserved[30:29] | Buffer2 ByteCount[28:16] | CTRL[15:14] | Reserved(13) | Buffer1 ByteCount[12:0] | + --------------------------------------------------------------------------------------------------------------------- + RDES2 | Buffer1 Address [31:0] | + --------------------------------------------------------------------------------------------------------------------- + RDES3 | Buffer2 Address [31:0] / Next Descriptor Address [31:0] | + --------------------------------------------------------------------------------------------------------------------- +*/ + +/** + * @brief Bit definition of RDES0 register: DMA Rx descriptor status register + */ +#define ETH_DMARXDESC_OWN ((uint32_t)0x80000000U) /*!< OWN bit: descriptor is owned by DMA engine */ +#define ETH_DMARXDESC_AFM ((uint32_t)0x40000000U) /*!< DA Filter Fail for the rx frame */ +#define ETH_DMARXDESC_FL ((uint32_t)0x3FFF0000U) /*!< Receive descriptor frame length */ +#define ETH_DMARXDESC_ES ((uint32_t)0x00008000U) /*!< Error summary: OR of the following bits: DE || OE || IPC || LC || RWT || RE || CE */ +#define ETH_DMARXDESC_DE ((uint32_t)0x00004000U) /*!< Descriptor error: no more descriptors for receive frame */ +#define ETH_DMARXDESC_SAF ((uint32_t)0x00002000U) /*!< SA Filter Fail for the received frame */ +#define ETH_DMARXDESC_LE ((uint32_t)0x00001000U) /*!< Frame size not matching with length field */ +#define ETH_DMARXDESC_OE ((uint32_t)0x00000800U) /*!< Overflow Error: Frame was damaged due to buffer overflow */ +#define ETH_DMARXDESC_VLAN ((uint32_t)0x00000400U) /*!< VLAN Tag: received frame is a VLAN frame */ +#define ETH_DMARXDESC_FS ((uint32_t)0x00000200U) /*!< First descriptor of the frame */ +#define ETH_DMARXDESC_LS ((uint32_t)0x00000100U) /*!< Last descriptor of the frame */ +#define ETH_DMARXDESC_IPV4HCE ((uint32_t)0x00000080U) /*!< IPC Checksum Error: Rx Ipv4 header checksum error */ +#define ETH_DMARXDESC_LC ((uint32_t)0x00000040U) /*!< Late collision occurred during reception */ +#define ETH_DMARXDESC_FT ((uint32_t)0x00000020U) /*!< Frame type - Ethernet, otherwise 802.3 */ +#define ETH_DMARXDESC_RWT ((uint32_t)0x00000010U) /*!< Receive Watchdog Timeout: watchdog timer expired during reception */ +#define ETH_DMARXDESC_RE ((uint32_t)0x00000008U) /*!< Receive error: error reported by MII interface */ +#define ETH_DMARXDESC_DBE ((uint32_t)0x00000004U) /*!< Dribble bit error: frame contains non int multiple of 8 bits */ +#define ETH_DMARXDESC_CE ((uint32_t)0x00000002U) /*!< CRC error */ +#define ETH_DMARXDESC_MAMPCE ((uint32_t)0x00000001U) /*!< Rx MAC Address/Payload Checksum Error: Rx MAC address matched/ Rx Payload Checksum Error */ + +/** + * @brief Bit definition of RDES1 register + */ +#define ETH_DMARXDESC_DIC ((uint32_t)0x80000000U) /*!< Disable Interrupt on Completion */ +#define ETH_DMARXDESC_RBS2 ((uint32_t)0x1FFF0000U) /*!< Receive Buffer2 Size */ +#define ETH_DMARXDESC_RER ((uint32_t)0x00008000U) /*!< Receive End of Ring */ +#define ETH_DMARXDESC_RCH ((uint32_t)0x00004000U) /*!< Second Address Chained */ +#define ETH_DMARXDESC_RBS1 ((uint32_t)0x00001FFFU) /*!< Receive Buffer1 Size */ + +/** + * @brief Bit definition of RDES2 register + */ +#define ETH_DMARXDESC_B1AP ((uint32_t)0xFFFFFFFFU) /*!< Buffer1 Address Pointer */ + +/** + * @brief Bit definition of RDES3 register + */ +#define ETH_DMARXDESC_B2AP ((uint32_t)0xFFFFFFFFU) /*!< Buffer2 Address Pointer */ + +/*--------------------------------------------------------------------------------------------------------------------- + RDES4 | Reserved[31:15] | Extended Status [14:0] | + --------------------------------------------------------------------------------------------------------------------- + RDES5 | Reserved[31:0] | + --------------------------------------------------------------------------------------------------------------------- + RDES6 | Receive Time Stamp Low [31:0] | + --------------------------------------------------------------------------------------------------------------------- + RDES7 | Receive Time Stamp High [31:0] | + --------------------------------------------------------------------------------------------------------------------*/ + +/* Bit definition of RDES4 register */ +#define ETH_DMAPTPRXDESC_PTPV ((uint32_t)0x00002000U) /* PTP Version */ +#define ETH_DMAPTPRXDESC_PTPFT ((uint32_t)0x00001000U) /* PTP Frame Type */ +#define ETH_DMAPTPRXDESC_PTPMT ((uint32_t)0x00000F00U) /* PTP Message Type */ +#define ETH_DMAPTPRXDESC_PTPMT_SYNC ((uint32_t)0x00000100U) /* SYNC message (all clock types) */ +#define ETH_DMAPTPRXDESC_PTPMT_FOLLOWUP ((uint32_t)0x00000200U) /* FollowUp message (all clock types) */ +#define ETH_DMAPTPRXDESC_PTPMT_DELAYREQ ((uint32_t)0x00000300U) /* DelayReq message (all clock types) */ +#define ETH_DMAPTPRXDESC_PTPMT_DELAYRESP ((uint32_t)0x00000400U) /* DelayResp message (all clock types) */ +#define ETH_DMAPTPRXDESC_PTPMT_PDELAYREQ_ANNOUNCE ((uint32_t)0x00000500U) /* PdelayReq message (peer-to-peer transparent clock) or Announce message (Ordinary or Boundary clock) */ +#define ETH_DMAPTPRXDESC_PTPMT_PDELAYRESP_MANAG ((uint32_t)0x00000600U) /* PdelayResp message (peer-to-peer transparent clock) or Management message (Ordinary or Boundary clock) */ +#define ETH_DMAPTPRXDESC_PTPMT_PDELAYRESPFOLLOWUP_SIGNAL ((uint32_t)0x00000700U) /* PdelayRespFollowUp message (peer-to-peer transparent clock) or Signaling message (Ordinary or Boundary clock) */ +#define ETH_DMAPTPRXDESC_IPV6PR ((uint32_t)0x00000080U) /* IPv6 Packet Received */ +#define ETH_DMAPTPRXDESC_IPV4PR ((uint32_t)0x00000040U) /* IPv4 Packet Received */ +#define ETH_DMAPTPRXDESC_IPCB ((uint32_t)0x00000020U) /* IP Checksum Bypassed */ +#define ETH_DMAPTPRXDESC_IPPE ((uint32_t)0x00000010U) /* IP Payload Error */ +#define ETH_DMAPTPRXDESC_IPHE ((uint32_t)0x00000008U) /* IP Header Error */ +#define ETH_DMAPTPRXDESC_IPPT ((uint32_t)0x00000007U) /* IP Payload Type */ +#define ETH_DMAPTPRXDESC_IPPT_UDP ((uint32_t)0x00000001U) /* UDP payload encapsulated in the IP datagram */ +#define ETH_DMAPTPRXDESC_IPPT_TCP ((uint32_t)0x00000002U) /* TCP payload encapsulated in the IP datagram */ +#define ETH_DMAPTPRXDESC_IPPT_ICMP ((uint32_t)0x00000003U) /* ICMP payload encapsulated in the IP datagram */ + +/* Bit definition of RDES6 register */ +#define ETH_DMAPTPRXDESC_RTSL ((uint32_t)0xFFFFFFFFU) /* Receive Time Stamp Low */ + +/* Bit definition of RDES7 register */ +#define ETH_DMAPTPRXDESC_RTSH ((uint32_t)0xFFFFFFFFU) /* Receive Time Stamp High */ +/** + * @} + */ + /** @defgroup ETH_AutoNegotiation ETH AutoNegotiation + * @{ + */ +#define ETH_AUTONEGOTIATION_ENABLE ((uint32_t)0x00000001U) +#define ETH_AUTONEGOTIATION_DISABLE ((uint32_t)0x00000000U) + +/** + * @} + */ +/** @defgroup ETH_Speed ETH Speed + * @{ + */ +#define ETH_SPEED_10M ((uint32_t)0x00000000U) +#define ETH_SPEED_100M ((uint32_t)0x00004000U) + +/** + * @} + */ +/** @defgroup ETH_Duplex_Mode ETH Duplex Mode + * @{ + */ +#define ETH_MODE_FULLDUPLEX ((uint32_t)0x00000800U) +#define ETH_MODE_HALFDUPLEX ((uint32_t)0x00000000U) +/** + * @} + */ +/** @defgroup ETH_Rx_Mode ETH Rx Mode + * @{ + */ +#define ETH_RXPOLLING_MODE ((uint32_t)0x00000000U) +#define ETH_RXINTERRUPT_MODE ((uint32_t)0x00000001U) +/** + * @} + */ + +/** @defgroup ETH_Checksum_Mode ETH Checksum Mode + * @{ + */ +#define ETH_CHECKSUM_BY_HARDWARE ((uint32_t)0x00000000U) +#define ETH_CHECKSUM_BY_SOFTWARE ((uint32_t)0x00000001U) +/** + * @} + */ + +/** @defgroup ETH_Media_Interface ETH Media Interface + * @{ + */ +#define ETH_MEDIA_INTERFACE_MII ((uint32_t)0x00000000U) +#define ETH_MEDIA_INTERFACE_RMII ((uint32_t)SYSCFG_PMC_MII_RMII_SEL) +/** + * @} + */ + +/** @defgroup ETH_Watchdog ETH Watchdog + * @{ + */ +#define ETH_WATCHDOG_ENABLE ((uint32_t)0x00000000U) +#define ETH_WATCHDOG_DISABLE ((uint32_t)0x00800000U) +/** + * @} + */ + +/** @defgroup ETH_Jabber ETH Jabber + * @{ + */ +#define ETH_JABBER_ENABLE ((uint32_t)0x00000000U) +#define ETH_JABBER_DISABLE ((uint32_t)0x00400000U) +/** + * @} + */ + +/** @defgroup ETH_Inter_Frame_Gap ETH Inter Frame Gap + * @{ + */ +#define ETH_INTERFRAMEGAP_96BIT ((uint32_t)0x00000000U) /*!< minimum IFG between frames during transmission is 96Bit */ +#define ETH_INTERFRAMEGAP_88BIT ((uint32_t)0x00020000U) /*!< minimum IFG between frames during transmission is 88Bit */ +#define ETH_INTERFRAMEGAP_80BIT ((uint32_t)0x00040000U) /*!< minimum IFG between frames during transmission is 80Bit */ +#define ETH_INTERFRAMEGAP_72BIT ((uint32_t)0x00060000U) /*!< minimum IFG between frames during transmission is 72Bit */ +#define ETH_INTERFRAMEGAP_64BIT ((uint32_t)0x00080000U) /*!< minimum IFG between frames during transmission is 64Bit */ +#define ETH_INTERFRAMEGAP_56BIT ((uint32_t)0x000A0000U) /*!< minimum IFG between frames during transmission is 56Bit */ +#define ETH_INTERFRAMEGAP_48BIT ((uint32_t)0x000C0000U) /*!< minimum IFG between frames during transmission is 48Bit */ +#define ETH_INTERFRAMEGAP_40BIT ((uint32_t)0x000E0000U) /*!< minimum IFG between frames during transmission is 40Bit */ +/** + * @} + */ + +/** @defgroup ETH_Carrier_Sense ETH Carrier Sense + * @{ + */ +#define ETH_CARRIERSENCE_ENABLE ((uint32_t)0x00000000U) +#define ETH_CARRIERSENCE_DISABLE ((uint32_t)0x00010000U) +/** + * @} + */ + +/** @defgroup ETH_Receive_Own ETH Receive Own + * @{ + */ +#define ETH_RECEIVEOWN_ENABLE ((uint32_t)0x00000000U) +#define ETH_RECEIVEOWN_DISABLE ((uint32_t)0x00002000U) +/** + * @} + */ + +/** @defgroup ETH_Loop_Back_Mode ETH Loop Back Mode + * @{ + */ +#define ETH_LOOPBACKMODE_ENABLE ((uint32_t)0x00001000U) +#define ETH_LOOPBACKMODE_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Checksum_Offload ETH Checksum Offload + * @{ + */ +#define ETH_CHECKSUMOFFLAOD_ENABLE ((uint32_t)0x00000400U) +#define ETH_CHECKSUMOFFLAOD_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Retry_Transmission ETH Retry Transmission + * @{ + */ +#define ETH_RETRYTRANSMISSION_ENABLE ((uint32_t)0x00000000U) +#define ETH_RETRYTRANSMISSION_DISABLE ((uint32_t)0x00000200U) +/** + * @} + */ + +/** @defgroup ETH_Automatic_Pad_CRC_Strip ETH Automatic Pad CRC Strip + * @{ + */ +#define ETH_AUTOMATICPADCRCSTRIP_ENABLE ((uint32_t)0x00000080U) +#define ETH_AUTOMATICPADCRCSTRIP_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Back_Off_Limit ETH Back Off Limit + * @{ + */ +#define ETH_BACKOFFLIMIT_10 ((uint32_t)0x00000000U) +#define ETH_BACKOFFLIMIT_8 ((uint32_t)0x00000020U) +#define ETH_BACKOFFLIMIT_4 ((uint32_t)0x00000040U) +#define ETH_BACKOFFLIMIT_1 ((uint32_t)0x00000060U) +/** + * @} + */ + +/** @defgroup ETH_Deferral_Check ETH Deferral Check + * @{ + */ +#define ETH_DEFFERRALCHECK_ENABLE ((uint32_t)0x00000010U) +#define ETH_DEFFERRALCHECK_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Receive_All ETH Receive All + * @{ + */ +#define ETH_RECEIVEALL_ENABLE ((uint32_t)0x80000000U) +#define ETH_RECEIVEAll_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Source_Addr_Filter ETH Source Addr Filter + * @{ + */ +#define ETH_SOURCEADDRFILTER_NORMAL_ENABLE ((uint32_t)0x00000200U) +#define ETH_SOURCEADDRFILTER_INVERSE_ENABLE ((uint32_t)0x00000300U) +#define ETH_SOURCEADDRFILTER_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Pass_Control_Frames ETH Pass Control Frames + * @{ + */ +#define ETH_PASSCONTROLFRAMES_BLOCKALL ((uint32_t)0x00000040U) /*!< MAC filters all control frames from reaching the application */ +#define ETH_PASSCONTROLFRAMES_FORWARDALL ((uint32_t)0x00000080U) /*!< MAC forwards all control frames to application even if they fail the Address Filter */ +#define ETH_PASSCONTROLFRAMES_FORWARDPASSEDADDRFILTER ((uint32_t)0x000000C0U) /*!< MAC forwards control frames that pass the Address Filter. */ +/** + * @} + */ + +/** @defgroup ETH_Broadcast_Frames_Reception ETH Broadcast Frames Reception + * @{ + */ +#define ETH_BROADCASTFRAMESRECEPTION_ENABLE ((uint32_t)0x00000000U) +#define ETH_BROADCASTFRAMESRECEPTION_DISABLE ((uint32_t)0x00000020U) +/** + * @} + */ + +/** @defgroup ETH_Destination_Addr_Filter ETH Destination Addr Filter + * @{ + */ +#define ETH_DESTINATIONADDRFILTER_NORMAL ((uint32_t)0x00000000U) +#define ETH_DESTINATIONADDRFILTER_INVERSE ((uint32_t)0x00000008U) +/** + * @} + */ + +/** @defgroup ETH_Promiscuous_Mode ETH Promiscuous Mode + * @{ + */ +#define ETH_PROMISCUOUS_MODE_ENABLE ((uint32_t)0x00000001U) +#define ETH_PROMISCUOUS_MODE_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Multicast_Frames_Filter ETH Multicast Frames Filter + * @{ + */ +#define ETH_MULTICASTFRAMESFILTER_PERFECTHASHTABLE ((uint32_t)0x00000404U) +#define ETH_MULTICASTFRAMESFILTER_HASHTABLE ((uint32_t)0x00000004U) +#define ETH_MULTICASTFRAMESFILTER_PERFECT ((uint32_t)0x00000000U) +#define ETH_MULTICASTFRAMESFILTER_NONE ((uint32_t)0x00000010U) +/** + * @} + */ + +/** @defgroup ETH_Unicast_Frames_Filter ETH Unicast Frames Filter + * @{ + */ +#define ETH_UNICASTFRAMESFILTER_PERFECTHASHTABLE ((uint32_t)0x00000402U) +#define ETH_UNICASTFRAMESFILTER_HASHTABLE ((uint32_t)0x00000002U) +#define ETH_UNICASTFRAMESFILTER_PERFECT ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Zero_Quanta_Pause ETH Zero Quanta Pause + * @{ + */ +#define ETH_ZEROQUANTAPAUSE_ENABLE ((uint32_t)0x00000000U) +#define ETH_ZEROQUANTAPAUSE_DISABLE ((uint32_t)0x00000080U) +/** + * @} + */ + +/** @defgroup ETH_Pause_Low_Threshold ETH Pause Low Threshold + * @{ + */ +#define ETH_PAUSELOWTHRESHOLD_MINUS4 ((uint32_t)0x00000000U) /*!< Pause time minus 4 slot times */ +#define ETH_PAUSELOWTHRESHOLD_MINUS28 ((uint32_t)0x00000010U) /*!< Pause time minus 28 slot times */ +#define ETH_PAUSELOWTHRESHOLD_MINUS144 ((uint32_t)0x00000020U) /*!< Pause time minus 144 slot times */ +#define ETH_PAUSELOWTHRESHOLD_MINUS256 ((uint32_t)0x00000030U) /*!< Pause time minus 256 slot times */ +/** + * @} + */ + +/** @defgroup ETH_Unicast_Pause_Frame_Detect ETH Unicast Pause Frame Detect + * @{ + */ +#define ETH_UNICASTPAUSEFRAMEDETECT_ENABLE ((uint32_t)0x00000008U) +#define ETH_UNICASTPAUSEFRAMEDETECT_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Receive_Flow_Control ETH Receive Flow Control + * @{ + */ +#define ETH_RECEIVEFLOWCONTROL_ENABLE ((uint32_t)0x00000004U) +#define ETH_RECEIVEFLOWCONTROL_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Transmit_Flow_Control ETH Transmit Flow Control + * @{ + */ +#define ETH_TRANSMITFLOWCONTROL_ENABLE ((uint32_t)0x00000002U) +#define ETH_TRANSMITFLOWCONTROL_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_VLAN_Tag_Comparison ETH VLAN Tag Comparison + * @{ + */ +#define ETH_VLANTAGCOMPARISON_12BIT ((uint32_t)0x00010000U) +#define ETH_VLANTAGCOMPARISON_16BIT ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_MAC_addresses ETH MAC addresses + * @{ + */ +#define ETH_MAC_ADDRESS0 ((uint32_t)0x00000000U) +#define ETH_MAC_ADDRESS1 ((uint32_t)0x00000008U) +#define ETH_MAC_ADDRESS2 ((uint32_t)0x00000010U) +#define ETH_MAC_ADDRESS3 ((uint32_t)0x00000018U) +/** + * @} + */ + +/** @defgroup ETH_MAC_addresses_filter_SA_DA ETH MAC addresses filter SA DA + * @{ + */ +#define ETH_MAC_ADDRESSFILTER_SA ((uint32_t)0x00000000U) +#define ETH_MAC_ADDRESSFILTER_DA ((uint32_t)0x00000008U) +/** + * @} + */ + +/** @defgroup ETH_MAC_addresses_filter_Mask_bytes ETH MAC addresses filter Mask bytes + * @{ + */ +#define ETH_MAC_ADDRESSMASK_BYTE6 ((uint32_t)0x20000000U) /*!< Mask MAC Address high reg bits [15:8] */ +#define ETH_MAC_ADDRESSMASK_BYTE5 ((uint32_t)0x10000000U) /*!< Mask MAC Address high reg bits [7:0] */ +#define ETH_MAC_ADDRESSMASK_BYTE4 ((uint32_t)0x08000000U) /*!< Mask MAC Address low reg bits [31:24] */ +#define ETH_MAC_ADDRESSMASK_BYTE3 ((uint32_t)0x04000000U) /*!< Mask MAC Address low reg bits [23:16] */ +#define ETH_MAC_ADDRESSMASK_BYTE2 ((uint32_t)0x02000000U) /*!< Mask MAC Address low reg bits [15:8] */ +#define ETH_MAC_ADDRESSMASK_BYTE1 ((uint32_t)0x01000000U) /*!< Mask MAC Address low reg bits [70] */ +/** + * @} + */ + +/** @defgroup ETH_MAC_Debug_flags ETH MAC Debug flags + * @{ + */ +#define ETH_MAC_TXFIFO_FULL ((uint32_t)0x02000000) /* Tx FIFO full */ +#define ETH_MAC_TXFIFONOT_EMPTY ((uint32_t)0x01000000) /* Tx FIFO not empty */ +#define ETH_MAC_TXFIFO_WRITE_ACTIVE ((uint32_t)0x00400000) /* Tx FIFO write active */ +#define ETH_MAC_TXFIFO_IDLE ((uint32_t)0x00000000) /* Tx FIFO read status: Idle */ +#define ETH_MAC_TXFIFO_READ ((uint32_t)0x00100000) /* Tx FIFO read status: Read (transferring data to the MAC transmitter) */ +#define ETH_MAC_TXFIFO_WAITING ((uint32_t)0x00200000) /* Tx FIFO read status: Waiting for TxStatus from MAC transmitter */ +#define ETH_MAC_TXFIFO_WRITING ((uint32_t)0x00300000) /* Tx FIFO read status: Writing the received TxStatus or flushing the TxFIFO */ +#define ETH_MAC_TRANSMISSION_PAUSE ((uint32_t)0x00080000) /* MAC transmitter in pause */ +#define ETH_MAC_TRANSMITFRAMECONTROLLER_IDLE ((uint32_t)0x00000000) /* MAC transmit frame controller: Idle */ +#define ETH_MAC_TRANSMITFRAMECONTROLLER_WAITING ((uint32_t)0x00020000) /* MAC transmit frame controller: Waiting for Status of previous frame or IFG/backoff period to be over */ +#define ETH_MAC_TRANSMITFRAMECONTROLLER_GENRATING_PCF ((uint32_t)0x00040000) /* MAC transmit frame controller: Generating and transmitting a Pause control frame (in full duplex mode) */ +#define ETH_MAC_TRANSMITFRAMECONTROLLER_TRANSFERRING ((uint32_t)0x00060000) /* MAC transmit frame controller: Transferring input frame for transmission */ +#define ETH_MAC_MII_TRANSMIT_ACTIVE ((uint32_t)0x00010000) /* MAC MII transmit engine active */ +#define ETH_MAC_RXFIFO_EMPTY ((uint32_t)0x00000000) /* Rx FIFO fill level: empty */ +#define ETH_MAC_RXFIFO_BELOW_THRESHOLD ((uint32_t)0x00000100) /* Rx FIFO fill level: fill-level below flow-control de-activate threshold */ +#define ETH_MAC_RXFIFO_ABOVE_THRESHOLD ((uint32_t)0x00000200) /* Rx FIFO fill level: fill-level above flow-control activate threshold */ +#define ETH_MAC_RXFIFO_FULL ((uint32_t)0x00000300) /* Rx FIFO fill level: full */ +#define ETH_MAC_READCONTROLLER_IDLE ((uint32_t)0x00000060) /* Rx FIFO read controller IDLE state */ +#define ETH_MAC_READCONTROLLER_READING_DATA ((uint32_t)0x00000060) /* Rx FIFO read controller Reading frame data */ +#define ETH_MAC_READCONTROLLER_READING_STATUS ((uint32_t)0x00000060) /* Rx FIFO read controller Reading frame status (or time-stamp) */ +#define ETH_MAC_READCONTROLLER_ FLUSHING ((uint32_t)0x00000060) /* Rx FIFO read controller Flushing the frame data and status */ +#define ETH_MAC_RXFIFO_WRITE_ACTIVE ((uint32_t)0x00000010) /* Rx FIFO write controller active */ +#define ETH_MAC_SMALL_FIFO_NOTACTIVE ((uint32_t)0x00000000) /* MAC small FIFO read / write controllers not active */ +#define ETH_MAC_SMALL_FIFO_READ_ACTIVE ((uint32_t)0x00000002) /* MAC small FIFO read controller active */ +#define ETH_MAC_SMALL_FIFO_WRITE_ACTIVE ((uint32_t)0x00000004) /* MAC small FIFO write controller active */ +#define ETH_MAC_SMALL_FIFO_RW_ACTIVE ((uint32_t)0x00000006) /* MAC small FIFO read / write controllers active */ +#define ETH_MAC_MII_RECEIVE_PROTOCOL_ACTIVE ((uint32_t)0x00000001) /* MAC MII receive protocol engine active */ +/** + * @} + */ + +/** @defgroup ETH_Drop_TCP_IP_Checksum_Error_Frame ETH Drop TCP IP Checksum Error Frame + * @{ + */ +#define ETH_DROPTCPIPCHECKSUMERRORFRAME_ENABLE ((uint32_t)0x00000000U) +#define ETH_DROPTCPIPCHECKSUMERRORFRAME_DISABLE ((uint32_t)0x04000000U) +/** + * @} + */ + +/** @defgroup ETH_Receive_Store_Forward ETH Receive Store Forward + * @{ + */ +#define ETH_RECEIVESTOREFORWARD_ENABLE ((uint32_t)0x02000000U) +#define ETH_RECEIVESTOREFORWARD_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Flush_Received_Frame ETH Flush Received Frame + * @{ + */ +#define ETH_FLUSHRECEIVEDFRAME_ENABLE ((uint32_t)0x00000000U) +#define ETH_FLUSHRECEIVEDFRAME_DISABLE ((uint32_t)0x01000000U) +/** + * @} + */ + +/** @defgroup ETH_Transmit_Store_Forward ETH Transmit Store Forward + * @{ + */ +#define ETH_TRANSMITSTOREFORWARD_ENABLE ((uint32_t)0x00200000U) +#define ETH_TRANSMITSTOREFORWARD_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Transmit_Threshold_Control ETH Transmit Threshold Control + * @{ + */ +#define ETH_TRANSMITTHRESHOLDCONTROL_64BYTES ((uint32_t)0x00000000U) /*!< threshold level of the MTL Transmit FIFO is 64 Bytes */ +#define ETH_TRANSMITTHRESHOLDCONTROL_128BYTES ((uint32_t)0x00004000U) /*!< threshold level of the MTL Transmit FIFO is 128 Bytes */ +#define ETH_TRANSMITTHRESHOLDCONTROL_192BYTES ((uint32_t)0x00008000U) /*!< threshold level of the MTL Transmit FIFO is 192 Bytes */ +#define ETH_TRANSMITTHRESHOLDCONTROL_256BYTES ((uint32_t)0x0000C000U) /*!< threshold level of the MTL Transmit FIFO is 256 Bytes */ +#define ETH_TRANSMITTHRESHOLDCONTROL_40BYTES ((uint32_t)0x00010000U) /*!< threshold level of the MTL Transmit FIFO is 40 Bytes */ +#define ETH_TRANSMITTHRESHOLDCONTROL_32BYTES ((uint32_t)0x00014000U) /*!< threshold level of the MTL Transmit FIFO is 32 Bytes */ +#define ETH_TRANSMITTHRESHOLDCONTROL_24BYTES ((uint32_t)0x00018000U) /*!< threshold level of the MTL Transmit FIFO is 24 Bytes */ +#define ETH_TRANSMITTHRESHOLDCONTROL_16BYTES ((uint32_t)0x0001C000U) /*!< threshold level of the MTL Transmit FIFO is 16 Bytes */ +/** + * @} + */ + +/** @defgroup ETH_Forward_Error_Frames ETH Forward Error Frames + * @{ + */ +#define ETH_FORWARDERRORFRAMES_ENABLE ((uint32_t)0x00000080U) +#define ETH_FORWARDERRORFRAMES_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Forward_Undersized_Good_Frames ETH Forward Undersized Good Frames + * @{ + */ +#define ETH_FORWARDUNDERSIZEDGOODFRAMES_ENABLE ((uint32_t)0x00000040U) +#define ETH_FORWARDUNDERSIZEDGOODFRAMES_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Receive_Threshold_Control ETH Receive Threshold Control + * @{ + */ +#define ETH_RECEIVEDTHRESHOLDCONTROL_64BYTES ((uint32_t)0x00000000U) /*!< threshold level of the MTL Receive FIFO is 64 Bytes */ +#define ETH_RECEIVEDTHRESHOLDCONTROL_32BYTES ((uint32_t)0x00000008U) /*!< threshold level of the MTL Receive FIFO is 32 Bytes */ +#define ETH_RECEIVEDTHRESHOLDCONTROL_96BYTES ((uint32_t)0x00000010U) /*!< threshold level of the MTL Receive FIFO is 96 Bytes */ +#define ETH_RECEIVEDTHRESHOLDCONTROL_128BYTES ((uint32_t)0x00000018U) /*!< threshold level of the MTL Receive FIFO is 128 Bytes */ +/** + * @} + */ + +/** @defgroup ETH_Second_Frame_Operate ETH Second Frame Operate + * @{ + */ +#define ETH_SECONDFRAMEOPERARTE_ENABLE ((uint32_t)0x00000004U) +#define ETH_SECONDFRAMEOPERARTE_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Address_Aligned_Beats ETH Address Aligned Beats + * @{ + */ +#define ETH_ADDRESSALIGNEDBEATS_ENABLE ((uint32_t)0x02000000U) +#define ETH_ADDRESSALIGNEDBEATS_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Fixed_Burst ETH Fixed Burst + * @{ + */ +#define ETH_FIXEDBURST_ENABLE ((uint32_t)0x00010000U) +#define ETH_FIXEDBURST_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Rx_DMA_Burst_Length ETH Rx DMA Burst Length + * @{ + */ +#define ETH_RXDMABURSTLENGTH_1BEAT ((uint32_t)0x00020000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 1 */ +#define ETH_RXDMABURSTLENGTH_2BEAT ((uint32_t)0x00040000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 2 */ +#define ETH_RXDMABURSTLENGTH_4BEAT ((uint32_t)0x00080000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 4 */ +#define ETH_RXDMABURSTLENGTH_8BEAT ((uint32_t)0x00100000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 8 */ +#define ETH_RXDMABURSTLENGTH_16BEAT ((uint32_t)0x00200000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 16 */ +#define ETH_RXDMABURSTLENGTH_32BEAT ((uint32_t)0x00400000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 32 */ +#define ETH_RXDMABURSTLENGTH_4XPBL_4BEAT ((uint32_t)0x01020000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 4 */ +#define ETH_RXDMABURSTLENGTH_4XPBL_8BEAT ((uint32_t)0x01040000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 8 */ +#define ETH_RXDMABURSTLENGTH_4XPBL_16BEAT ((uint32_t)0x01080000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 16 */ +#define ETH_RXDMABURSTLENGTH_4XPBL_32BEAT ((uint32_t)0x01100000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 32 */ +#define ETH_RXDMABURSTLENGTH_4XPBL_64BEAT ((uint32_t)0x01200000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 64 */ +#define ETH_RXDMABURSTLENGTH_4XPBL_128BEAT ((uint32_t)0x01400000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 128 */ +/** + * @} + */ + +/** @defgroup ETH_Tx_DMA_Burst_Length ETH Tx DMA Burst Length + * @{ + */ +#define ETH_TXDMABURSTLENGTH_1BEAT ((uint32_t)0x00000100U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 1 */ +#define ETH_TXDMABURSTLENGTH_2BEAT ((uint32_t)0x00000200U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 2 */ +#define ETH_TXDMABURSTLENGTH_4BEAT ((uint32_t)0x00000400U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 4 */ +#define ETH_TXDMABURSTLENGTH_8BEAT ((uint32_t)0x00000800U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 8 */ +#define ETH_TXDMABURSTLENGTH_16BEAT ((uint32_t)0x00001000U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 16 */ +#define ETH_TXDMABURSTLENGTH_32BEAT ((uint32_t)0x00002000U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 32 */ +#define ETH_TXDMABURSTLENGTH_4XPBL_4BEAT ((uint32_t)0x01000100U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 4 */ +#define ETH_TXDMABURSTLENGTH_4XPBL_8BEAT ((uint32_t)0x01000200U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 8 */ +#define ETH_TXDMABURSTLENGTH_4XPBL_16BEAT ((uint32_t)0x01000400U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 16 */ +#define ETH_TXDMABURSTLENGTH_4XPBL_32BEAT ((uint32_t)0x01000800U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 32 */ +#define ETH_TXDMABURSTLENGTH_4XPBL_64BEAT ((uint32_t)0x01001000U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 64 */ +#define ETH_TXDMABURSTLENGTH_4XPBL_128BEAT ((uint32_t)0x01002000U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 128 */ +/** + * @} + */ + +/** @defgroup ETH_DMA_Enhanced_descriptor_format ETH DMA Enhanced descriptor format + * @{ + */ +#define ETH_DMAENHANCEDDESCRIPTOR_ENABLE ((uint32_t)0x00000080U) +#define ETH_DMAENHANCEDDESCRIPTOR_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_DMA_Arbitration ETH DMA Arbitration + * @{ + */ +#define ETH_DMAARBITRATION_ROUNDROBIN_RXTX_1_1 ((uint32_t)0x00000000U) +#define ETH_DMAARBITRATION_ROUNDROBIN_RXTX_2_1 ((uint32_t)0x00004000U) +#define ETH_DMAARBITRATION_ROUNDROBIN_RXTX_3_1 ((uint32_t)0x00008000U) +#define ETH_DMAARBITRATION_ROUNDROBIN_RXTX_4_1 ((uint32_t)0x0000C000U) +#define ETH_DMAARBITRATION_RXPRIORTX ((uint32_t)0x00000002U) +/** + * @} + */ + +/** @defgroup ETH_DMA_Tx_descriptor_segment ETH DMA Tx descriptor segment + * @{ + */ +#define ETH_DMATXDESC_LASTSEGMENTS ((uint32_t)0x40000000U) /*!< Last Segment */ +#define ETH_DMATXDESC_FIRSTSEGMENT ((uint32_t)0x20000000U) /*!< First Segment */ +/** + * @} + */ + +/** @defgroup ETH_DMA_Tx_descriptor_Checksum_Insertion_Control ETH DMA Tx descriptor Checksum Insertion Control + * @{ + */ +#define ETH_DMATXDESC_CHECKSUMBYPASS ((uint32_t)0x00000000U) /*!< Checksum engine bypass */ +#define ETH_DMATXDESC_CHECKSUMIPV4HEADER ((uint32_t)0x00400000U) /*!< IPv4 header checksum insertion */ +#define ETH_DMATXDESC_CHECKSUMTCPUDPICMPSEGMENT ((uint32_t)0x00800000U) /*!< TCP/UDP/ICMP checksum insertion. Pseudo header checksum is assumed to be present */ +#define ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL ((uint32_t)0x00C00000U) /*!< TCP/UDP/ICMP checksum fully in hardware including pseudo header */ +/** + * @} + */ + +/** @defgroup ETH_DMA_Rx_descriptor_buffers ETH DMA Rx descriptor buffers + * @{ + */ +#define ETH_DMARXDESC_BUFFER1 ((uint32_t)0x00000000U) /*!< DMA Rx Desc Buffer1 */ +#define ETH_DMARXDESC_BUFFER2 ((uint32_t)0x00000001U) /*!< DMA Rx Desc Buffer2 */ +/** + * @} + */ + +/** @defgroup ETH_PMT_Flags ETH PMT Flags + * @{ + */ +#define ETH_PMT_FLAG_WUFFRPR ((uint32_t)0x80000000U) /*!< Wake-Up Frame Filter Register Pointer Reset */ +#define ETH_PMT_FLAG_WUFR ((uint32_t)0x00000040U) /*!< Wake-Up Frame Received */ +#define ETH_PMT_FLAG_MPR ((uint32_t)0x00000020U) /*!< Magic Packet Received */ +/** + * @} + */ + +/** @defgroup ETH_MMC_Tx_Interrupts ETH MMC Tx Interrupts + * @{ + */ +#define ETH_MMC_IT_TGF ((uint32_t)0x00200000U) /*!< When Tx good frame counter reaches half the maximum value */ +#define ETH_MMC_IT_TGFMSC ((uint32_t)0x00008000U) /*!< When Tx good multi col counter reaches half the maximum value */ +#define ETH_MMC_IT_TGFSC ((uint32_t)0x00004000U) /*!< When Tx good single col counter reaches half the maximum value */ +/** + * @} + */ + +/** @defgroup ETH_MMC_Rx_Interrupts ETH MMC Rx Interrupts + * @{ + */ +#define ETH_MMC_IT_RGUF ((uint32_t)0x10020000U) /*!< When Rx good unicast frames counter reaches half the maximum value */ +#define ETH_MMC_IT_RFAE ((uint32_t)0x10000040U) /*!< When Rx alignment error counter reaches half the maximum value */ +#define ETH_MMC_IT_RFCE ((uint32_t)0x10000020U) /*!< When Rx crc error counter reaches half the maximum value */ +/** + * @} + */ + +/** @defgroup ETH_MAC_Flags ETH MAC Flags + * @{ + */ +#define ETH_MAC_FLAG_TST ((uint32_t)0x00000200U) /*!< Time stamp trigger flag (on MAC) */ +#define ETH_MAC_FLAG_MMCT ((uint32_t)0x00000040U) /*!< MMC transmit flag */ +#define ETH_MAC_FLAG_MMCR ((uint32_t)0x00000020U) /*!< MMC receive flag */ +#define ETH_MAC_FLAG_MMC ((uint32_t)0x00000010U) /*!< MMC flag (on MAC) */ +#define ETH_MAC_FLAG_PMT ((uint32_t)0x00000008U) /*!< PMT flag (on MAC) */ +/** + * @} + */ + +/** @defgroup ETH_DMA_Flags ETH DMA Flags + * @{ + */ +#define ETH_DMA_FLAG_TST ((uint32_t)0x20000000U) /*!< Time-stamp trigger interrupt (on DMA) */ +#define ETH_DMA_FLAG_PMT ((uint32_t)0x10000000U) /*!< PMT interrupt (on DMA) */ +#define ETH_DMA_FLAG_MMC ((uint32_t)0x08000000U) /*!< MMC interrupt (on DMA) */ +#define ETH_DMA_FLAG_DATATRANSFERERROR ((uint32_t)0x00800000U) /*!< Error bits 0-Rx DMA, 1-Tx DMA */ +#define ETH_DMA_FLAG_READWRITEERROR ((uint32_t)0x01000000U) /*!< Error bits 0-write transfer, 1-read transfer */ +#define ETH_DMA_FLAG_ACCESSERROR ((uint32_t)0x02000000U) /*!< Error bits 0-data buffer, 1-desc. access */ +#define ETH_DMA_FLAG_NIS ((uint32_t)0x00010000U) /*!< Normal interrupt summary flag */ +#define ETH_DMA_FLAG_AIS ((uint32_t)0x00008000U) /*!< Abnormal interrupt summary flag */ +#define ETH_DMA_FLAG_ER ((uint32_t)0x00004000U) /*!< Early receive flag */ +#define ETH_DMA_FLAG_FBE ((uint32_t)0x00002000U) /*!< Fatal bus error flag */ +#define ETH_DMA_FLAG_ET ((uint32_t)0x00000400U) /*!< Early transmit flag */ +#define ETH_DMA_FLAG_RWT ((uint32_t)0x00000200U) /*!< Receive watchdog timeout flag */ +#define ETH_DMA_FLAG_RPS ((uint32_t)0x00000100U) /*!< Receive process stopped flag */ +#define ETH_DMA_FLAG_RBU ((uint32_t)0x00000080U) /*!< Receive buffer unavailable flag */ +#define ETH_DMA_FLAG_R ((uint32_t)0x00000040U) /*!< Receive flag */ +#define ETH_DMA_FLAG_TU ((uint32_t)0x00000020U) /*!< Underflow flag */ +#define ETH_DMA_FLAG_RO ((uint32_t)0x00000010U) /*!< Overflow flag */ +#define ETH_DMA_FLAG_TJT ((uint32_t)0x00000008U) /*!< Transmit jabber timeout flag */ +#define ETH_DMA_FLAG_TBU ((uint32_t)0x00000004U) /*!< Transmit buffer unavailable flag */ +#define ETH_DMA_FLAG_TPS ((uint32_t)0x00000002U) /*!< Transmit process stopped flag */ +#define ETH_DMA_FLAG_T ((uint32_t)0x00000001U) /*!< Transmit flag */ +/** + * @} + */ + +/** @defgroup ETH_MAC_Interrupts ETH MAC Interrupts + * @{ + */ +#define ETH_MAC_IT_TST ((uint32_t)0x00000200U) /*!< Time stamp trigger interrupt (on MAC) */ +#define ETH_MAC_IT_MMCT ((uint32_t)0x00000040U) /*!< MMC transmit interrupt */ +#define ETH_MAC_IT_MMCR ((uint32_t)0x00000020U) /*!< MMC receive interrupt */ +#define ETH_MAC_IT_MMC ((uint32_t)0x00000010U) /*!< MMC interrupt (on MAC) */ +#define ETH_MAC_IT_PMT ((uint32_t)0x00000008U) /*!< PMT interrupt (on MAC) */ +/** + * @} + */ + +/** @defgroup ETH_DMA_Interrupts ETH DMA Interrupts + * @{ + */ +#define ETH_DMA_IT_TST ((uint32_t)0x20000000U) /*!< Time-stamp trigger interrupt (on DMA) */ +#define ETH_DMA_IT_PMT ((uint32_t)0x10000000U) /*!< PMT interrupt (on DMA) */ +#define ETH_DMA_IT_MMC ((uint32_t)0x08000000U) /*!< MMC interrupt (on DMA) */ +#define ETH_DMA_IT_NIS ((uint32_t)0x00010000U) /*!< Normal interrupt summary */ +#define ETH_DMA_IT_AIS ((uint32_t)0x00008000U) /*!< Abnormal interrupt summary */ +#define ETH_DMA_IT_ER ((uint32_t)0x00004000U) /*!< Early receive interrupt */ +#define ETH_DMA_IT_FBE ((uint32_t)0x00002000U) /*!< Fatal bus error interrupt */ +#define ETH_DMA_IT_ET ((uint32_t)0x00000400U) /*!< Early transmit interrupt */ +#define ETH_DMA_IT_RWT ((uint32_t)0x00000200U) /*!< Receive watchdog timeout interrupt */ +#define ETH_DMA_IT_RPS ((uint32_t)0x00000100U) /*!< Receive process stopped interrupt */ +#define ETH_DMA_IT_RBU ((uint32_t)0x00000080U) /*!< Receive buffer unavailable interrupt */ +#define ETH_DMA_IT_R ((uint32_t)0x00000040U) /*!< Receive interrupt */ +#define ETH_DMA_IT_TU ((uint32_t)0x00000020U) /*!< Underflow interrupt */ +#define ETH_DMA_IT_RO ((uint32_t)0x00000010U) /*!< Overflow interrupt */ +#define ETH_DMA_IT_TJT ((uint32_t)0x00000008U) /*!< Transmit jabber timeout interrupt */ +#define ETH_DMA_IT_TBU ((uint32_t)0x00000004U) /*!< Transmit buffer unavailable interrupt */ +#define ETH_DMA_IT_TPS ((uint32_t)0x00000002U) /*!< Transmit process stopped interrupt */ +#define ETH_DMA_IT_T ((uint32_t)0x00000001U) /*!< Transmit interrupt */ +/** + * @} + */ + +/** @defgroup ETH_DMA_transmit_process_state ETH DMA transmit process state + * @{ + */ +#define ETH_DMA_TRANSMITPROCESS_STOPPED ((uint32_t)0x00000000U) /*!< Stopped - Reset or Stop Tx Command issued */ +#define ETH_DMA_TRANSMITPROCESS_FETCHING ((uint32_t)0x00100000U) /*!< Running - fetching the Tx descriptor */ +#define ETH_DMA_TRANSMITPROCESS_WAITING ((uint32_t)0x00200000U) /*!< Running - waiting for status */ +#define ETH_DMA_TRANSMITPROCESS_READING ((uint32_t)0x00300000U) /*!< Running - reading the data from host memory */ +#define ETH_DMA_TRANSMITPROCESS_SUSPENDED ((uint32_t)0x00600000U) /*!< Suspended - Tx Descriptor unavailable */ +#define ETH_DMA_TRANSMITPROCESS_CLOSING ((uint32_t)0x00700000U) /*!< Running - closing Rx descriptor */ + +/** + * @} + */ + + +/** @defgroup ETH_DMA_receive_process_state ETH DMA receive process state + * @{ + */ +#define ETH_DMA_RECEIVEPROCESS_STOPPED ((uint32_t)0x00000000U) /*!< Stopped - Reset or Stop Rx Command issued */ +#define ETH_DMA_RECEIVEPROCESS_FETCHING ((uint32_t)0x00020000U) /*!< Running - fetching the Rx descriptor */ +#define ETH_DMA_RECEIVEPROCESS_WAITING ((uint32_t)0x00060000U) /*!< Running - waiting for packet */ +#define ETH_DMA_RECEIVEPROCESS_SUSPENDED ((uint32_t)0x00080000U) /*!< Suspended - Rx Descriptor unavailable */ +#define ETH_DMA_RECEIVEPROCESS_CLOSING ((uint32_t)0x000A0000U) /*!< Running - closing descriptor */ +#define ETH_DMA_RECEIVEPROCESS_QUEUING ((uint32_t)0x000E0000U) /*!< Running - queuing the receive frame into host memory */ + +/** + * @} + */ + +/** @defgroup ETH_DMA_overflow ETH DMA overflow + * @{ + */ +#define ETH_DMA_OVERFLOW_RXFIFOCOUNTER ((uint32_t)0x10000000U) /*!< Overflow bit for FIFO overflow counter */ +#define ETH_DMA_OVERFLOW_MISSEDFRAMECOUNTER ((uint32_t)0x00010000U) /*!< Overflow bit for missed frame counter */ +/** + * @} + */ + +/** @defgroup ETH_EXTI_LINE_WAKEUP ETH EXTI LINE WAKEUP + * @{ + */ +#define ETH_EXTI_LINE_WAKEUP ((uint32_t)0x00080000U) /*!< External interrupt line 19 Connected to the ETH EXTI Line */ + +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/** @defgroup ETH_Exported_Macros ETH Exported Macros + * @brief macros to handle interrupts and specific clock configurations + * @{ + */ + +/** @brief Reset ETH handle state + * @param __HANDLE__: specifies the ETH handle. + * @retval None + */ +#define __HAL_ETH_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = HAL_ETH_STATE_RESET) + +/** + * @brief Checks whether the specified Ethernet DMA Tx Desc flag is set or not. + * @param __HANDLE__: ETH Handle + * @param __FLAG__: specifies the flag of TDES0 to check. + * @retval the ETH_DMATxDescFlag (SET or RESET). + */ +#define __HAL_ETH_DMATXDESC_GET_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->TxDesc->Status & (__FLAG__) == (__FLAG__)) + +/** + * @brief Checks whether the specified Ethernet DMA Rx Desc flag is set or not. + * @param __HANDLE__: ETH Handle + * @param __FLAG__: specifies the flag of RDES0 to check. + * @retval the ETH_DMATxDescFlag (SET or RESET). + */ +#define __HAL_ETH_DMARXDESC_GET_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->RxDesc->Status & (__FLAG__) == (__FLAG__)) + +/** + * @brief Enables the specified DMA Rx Desc receive interrupt. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMARXDESC_ENABLE_IT(__HANDLE__) ((__HANDLE__)->RxDesc->ControlBufferSize &=(~(uint32_t)ETH_DMARXDESC_DIC)) + +/** + * @brief Disables the specified DMA Rx Desc receive interrupt. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMARXDESC_DISABLE_IT(__HANDLE__) ((__HANDLE__)->RxDesc->ControlBufferSize |= ETH_DMARXDESC_DIC) + +/** + * @brief Set the specified DMA Rx Desc Own bit. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMARXDESC_SET_OWN_BIT(__HANDLE__) ((__HANDLE__)->RxDesc->Status |= ETH_DMARXDESC_OWN) + +/** + * @brief Returns the specified Ethernet DMA Tx Desc collision count. + * @param __HANDLE__: ETH Handle + * @retval The Transmit descriptor collision counter value. + */ +#define __HAL_ETH_DMATXDESC_GET_COLLISION_COUNT(__HANDLE__) (((__HANDLE__)->TxDesc->Status & ETH_DMATXDESC_CC) >> ETH_DMATXDESC_COLLISION_COUNTSHIFT) + +/** + * @brief Set the specified DMA Tx Desc Own bit. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMATXDESC_SET_OWN_BIT(__HANDLE__) ((__HANDLE__)->TxDesc->Status |= ETH_DMATXDESC_OWN) + +/** + * @brief Enables the specified DMA Tx Desc Transmit interrupt. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMATXDESC_ENABLE_IT(__HANDLE__) ((__HANDLE__)->TxDesc->Status |= ETH_DMATXDESC_IC) + +/** + * @brief Disables the specified DMA Tx Desc Transmit interrupt. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMATXDESC_DISABLE_IT(__HANDLE__) ((__HANDLE__)->TxDesc->Status &= ~ETH_DMATXDESC_IC) + +/** + * @brief Selects the specified Ethernet DMA Tx Desc Checksum Insertion. + * @param __HANDLE__: ETH Handle + * @param __CHECKSUM__: specifies is the DMA Tx desc checksum insertion. + * This parameter can be one of the following values: + * @arg ETH_DMATXDESC_CHECKSUMBYPASS : Checksum bypass + * @arg ETH_DMATXDESC_CHECKSUMIPV4HEADER : IPv4 header checksum + * @arg ETH_DMATXDESC_CHECKSUMTCPUDPICMPSEGMENT : TCP/UDP/ICMP checksum. Pseudo header checksum is assumed to be present + * @arg ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL : TCP/UDP/ICMP checksum fully in hardware including pseudo header + * @retval None + */ +#define __HAL_ETH_DMATXDESC_CHECKSUM_INSERTION(__HANDLE__, __CHECKSUM__) ((__HANDLE__)->TxDesc->Status |= (__CHECKSUM__)) + +/** + * @brief Enables the DMA Tx Desc CRC. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMATXDESC_CRC_ENABLE(__HANDLE__) ((__HANDLE__)->TxDesc->Status &= ~ETH_DMATXDESC_DC) + +/** + * @brief Disables the DMA Tx Desc CRC. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMATXDESC_CRC_DISABLE(__HANDLE__) ((__HANDLE__)->TxDesc->Status |= ETH_DMATXDESC_DC) + +/** + * @brief Enables the DMA Tx Desc padding for frame shorter than 64 bytes. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMATXDESC_SHORT_FRAME_PADDING_ENABLE(__HANDLE__) ((__HANDLE__)->TxDesc->Status &= ~ETH_DMATXDESC_DP) + +/** + * @brief Disables the DMA Tx Desc padding for frame shorter than 64 bytes. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMATXDESC_SHORT_FRAME_PADDING_DISABLE(__HANDLE__) ((__HANDLE__)->TxDesc->Status |= ETH_DMATXDESC_DP) + +/** + * @brief Enables the specified Ethernet MAC interrupts. + * @param __HANDLE__ : ETH Handle + * @param __INTERRUPT__: specifies the Ethernet MAC interrupt sources to be + * enabled or disabled. + * This parameter can be any combination of the following values: + * @arg ETH_MAC_IT_TST : Time stamp trigger interrupt + * @arg ETH_MAC_IT_PMT : PMT interrupt + * @retval None + */ +#define __HAL_ETH_MAC_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->MACIMR |= (__INTERRUPT__)) + +/** + * @brief Disables the specified Ethernet MAC interrupts. + * @param __HANDLE__ : ETH Handle + * @param __INTERRUPT__: specifies the Ethernet MAC interrupt sources to be + * enabled or disabled. + * This parameter can be any combination of the following values: + * @arg ETH_MAC_IT_TST : Time stamp trigger interrupt + * @arg ETH_MAC_IT_PMT : PMT interrupt + * @retval None + */ +#define __HAL_ETH_MAC_DISABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->MACIMR &= ~(__INTERRUPT__)) + +/** + * @brief Initiate a Pause Control Frame (Full-duplex only). + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_INITIATE_PAUSE_CONTROL_FRAME(__HANDLE__) ((__HANDLE__)->Instance->MACFCR |= ETH_MACFCR_FCBBPA) + +/** + * @brief Checks whether the Ethernet flow control busy bit is set or not. + * @param __HANDLE__: ETH Handle + * @retval The new state of flow control busy status bit (SET or RESET). + */ +#define __HAL_ETH_GET_FLOW_CONTROL_BUSY_STATUS(__HANDLE__) (((__HANDLE__)->Instance->MACFCR & ETH_MACFCR_FCBBPA) == ETH_MACFCR_FCBBPA) + +/** + * @brief Enables the MAC Back Pressure operation activation (Half-duplex only). + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_BACK_PRESSURE_ACTIVATION_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MACFCR |= ETH_MACFCR_FCBBPA) + +/** + * @brief Disables the MAC BackPressure operation activation (Half-duplex only). + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_BACK_PRESSURE_ACTIVATION_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MACFCR &= ~ETH_MACFCR_FCBBPA) + +/** + * @brief Checks whether the specified Ethernet MAC flag is set or not. + * @param __HANDLE__: ETH Handle + * @param __FLAG__: specifies the flag to check. + * This parameter can be one of the following values: + * @arg ETH_MAC_FLAG_TST : Time stamp trigger flag + * @arg ETH_MAC_FLAG_MMCT : MMC transmit flag + * @arg ETH_MAC_FLAG_MMCR : MMC receive flag + * @arg ETH_MAC_FLAG_MMC : MMC flag + * @arg ETH_MAC_FLAG_PMT : PMT flag + * @retval The state of Ethernet MAC flag. + */ +#define __HAL_ETH_MAC_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->MACSR &( __FLAG__)) == ( __FLAG__)) + +/** + * @brief Enables the specified Ethernet DMA interrupts. + * @param __HANDLE__ : ETH Handle + * @param __INTERRUPT__: specifies the Ethernet DMA interrupt sources to be + * enabled @ref ETH_DMA_Interrupts + * @retval None + */ +#define __HAL_ETH_DMA_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->DMAIER |= (__INTERRUPT__)) + +/** + * @brief Disables the specified Ethernet DMA interrupts. + * @param __HANDLE__ : ETH Handle + * @param __INTERRUPT__: specifies the Ethernet DMA interrupt sources to be + * disabled. @ref ETH_DMA_Interrupts + * @retval None + */ +#define __HAL_ETH_DMA_DISABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->DMAIER &= ~(__INTERRUPT__)) + +/** + * @brief Clears the Ethernet DMA IT pending bit. + * @param __HANDLE__ : ETH Handle + * @param __INTERRUPT__: specifies the interrupt pending bit to clear. @ref ETH_DMA_Interrupts + * @retval None + */ +#define __HAL_ETH_DMA_CLEAR_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->DMASR =(__INTERRUPT__)) + +/** + * @brief Checks whether the specified Ethernet DMA flag is set or not. +* @param __HANDLE__: ETH Handle + * @param __FLAG__: specifies the flag to check. @ref ETH_DMA_Flags + * @retval The new state of ETH_DMA_FLAG (SET or RESET). + */ +#define __HAL_ETH_DMA_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->DMASR &( __FLAG__)) == ( __FLAG__)) + +/** + * @brief Checks whether the specified Ethernet DMA flag is set or not. + * @param __HANDLE__: ETH Handle + * @param __FLAG__: specifies the flag to clear. @ref ETH_DMA_Flags + * @retval The new state of ETH_DMA_FLAG (SET or RESET). + */ +#define __HAL_ETH_DMA_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->DMASR = (__FLAG__)) + +/** + * @brief Checks whether the specified Ethernet DMA overflow flag is set or not. + * @param __HANDLE__: ETH Handle + * @param __OVERFLOW__: specifies the DMA overflow flag to check. + * This parameter can be one of the following values: + * @arg ETH_DMA_OVERFLOW_RXFIFOCOUNTER : Overflow for FIFO Overflows Counter + * @arg ETH_DMA_OVERFLOW_MISSEDFRAMECOUNTER : Overflow for Buffer Unavailable Missed Frame Counter + * @retval The state of Ethernet DMA overflow Flag (SET or RESET). + */ +#define __HAL_ETH_GET_DMA_OVERFLOW_STATUS(__HANDLE__, __OVERFLOW__) (((__HANDLE__)->Instance->DMAMFBOCR & (__OVERFLOW__)) == (__OVERFLOW__)) + +/** + * @brief Set the DMA Receive status watchdog timer register value + * @param __HANDLE__: ETH Handle + * @param __VALUE__: DMA Receive status watchdog timer register value + * @retval None + */ +#define __HAL_ETH_SET_RECEIVE_WATCHDOG_TIMER(__HANDLE__, __VALUE__) ((__HANDLE__)->Instance->DMARSWTR = (__VALUE__)) + +/** + * @brief Enables any unicast packet filtered by the MAC address + * recognition to be a wake-up frame. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_GLOBAL_UNICAST_WAKEUP_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR |= ETH_MACPMTCSR_GU) + +/** + * @brief Disables any unicast packet filtered by the MAC address + * recognition to be a wake-up frame. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_GLOBAL_UNICAST_WAKEUP_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR &= ~ETH_MACPMTCSR_GU) + +/** + * @brief Enables the MAC Wake-Up Frame Detection. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_WAKEUP_FRAME_DETECTION_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR |= ETH_MACPMTCSR_WFE) + +/** + * @brief Disables the MAC Wake-Up Frame Detection. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_WAKEUP_FRAME_DETECTION_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR &= ~ETH_MACPMTCSR_WFE) + +/** + * @brief Enables the MAC Magic Packet Detection. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_MAGIC_PACKET_DETECTION_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR |= ETH_MACPMTCSR_MPE) + +/** + * @brief Disables the MAC Magic Packet Detection. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_MAGIC_PACKET_DETECTION_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR &= ~ETH_MACPMTCSR_WFE) + +/** + * @brief Enables the MAC Power Down. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_POWER_DOWN_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR |= ETH_MACPMTCSR_PD) + +/** + * @brief Disables the MAC Power Down. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_POWER_DOWN_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR &= ~ETH_MACPMTCSR_PD) + +/** + * @brief Checks whether the specified Ethernet PMT flag is set or not. + * @param __HANDLE__: ETH Handle. + * @param __FLAG__: specifies the flag to check. + * This parameter can be one of the following values: + * @arg ETH_PMT_FLAG_WUFFRPR : Wake-Up Frame Filter Register Pointer Reset + * @arg ETH_PMT_FLAG_WUFR : Wake-Up Frame Received + * @arg ETH_PMT_FLAG_MPR : Magic Packet Received + * @retval The new state of Ethernet PMT Flag (SET or RESET). + */ +#define __HAL_ETH_GET_PMT_FLAG_STATUS(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->MACPMTCSR &( __FLAG__)) == ( __FLAG__)) + +/** + * @brief Preset and Initialize the MMC counters to almost-full value: 0xFFFF_FFF0 (full - 16) + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_MMC_COUNTER_FULL_PRESET(__HANDLE__) ((__HANDLE__)->Instance->MMCCR |= (ETH_MMCCR_MCFHP | ETH_MMCCR_MCP)) + +/** + * @brief Preset and Initialize the MMC counters to almost-half value: 0x7FFF_FFF0 (half - 16) + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_MMC_COUNTER_HALF_PRESET(__HANDLE__) do{(__HANDLE__)->Instance->MMCCR &= ~ETH_MMCCR_MCFHP;\ + (__HANDLE__)->Instance->MMCCR |= ETH_MMCCR_MCP;} while (0) + +/** + * @brief Enables the MMC Counter Freeze. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_MMC_COUNTER_FREEZE_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MMCCR |= ETH_MMCCR_MCF) + +/** + * @brief Disables the MMC Counter Freeze. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_MMC_COUNTER_FREEZE_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MMCCR &= ~ETH_MMCCR_MCF) + +/** + * @brief Enables the MMC Reset On Read. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_ETH_MMC_RESET_ONREAD_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MMCCR |= ETH_MMCCR_ROR) + +/** + * @brief Disables the MMC Reset On Read. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_ETH_MMC_RESET_ONREAD_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MMCCR &= ~ETH_MMCCR_ROR) + +/** + * @brief Enables the MMC Counter Stop Rollover. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_ETH_MMC_COUNTER_ROLLOVER_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MMCCR &= ~ETH_MMCCR_CSR) + +/** + * @brief Disables the MMC Counter Stop Rollover. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_ETH_MMC_COUNTER_ROLLOVER_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MMCCR |= ETH_MMCCR_CSR) + +/** + * @brief Resets the MMC Counters. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_MMC_COUNTERS_RESET(__HANDLE__) ((__HANDLE__)->Instance->MMCCR |= ETH_MMCCR_CR) + +/** + * @brief Enables the specified Ethernet MMC Rx interrupts. + * @param __HANDLE__: ETH Handle. + * @param __INTERRUPT__: specifies the Ethernet MMC interrupt sources to be enabled or disabled. + * This parameter can be one of the following values: + * @arg ETH_MMC_IT_RGUF : When Rx good unicast frames counter reaches half the maximum value + * @arg ETH_MMC_IT_RFAE : When Rx alignment error counter reaches half the maximum value + * @arg ETH_MMC_IT_RFCE : When Rx crc error counter reaches half the maximum value + * @retval None + */ +#define __HAL_ETH_MMC_RX_IT_ENABLE(__HANDLE__, __INTERRUPT__) (__HANDLE__)->Instance->MMCRIMR &= ~((__INTERRUPT__) & 0xEFFFFFFF) +/** + * @brief Disables the specified Ethernet MMC Rx interrupts. + * @param __HANDLE__: ETH Handle. + * @param __INTERRUPT__: specifies the Ethernet MMC interrupt sources to be enabled or disabled. + * This parameter can be one of the following values: + * @arg ETH_MMC_IT_RGUF : When Rx good unicast frames counter reaches half the maximum value + * @arg ETH_MMC_IT_RFAE : When Rx alignment error counter reaches half the maximum value + * @arg ETH_MMC_IT_RFCE : When Rx crc error counter reaches half the maximum value + * @retval None + */ +#define __HAL_ETH_MMC_RX_IT_DISABLE(__HANDLE__, __INTERRUPT__) (__HANDLE__)->Instance->MMCRIMR |= ((__INTERRUPT__) & 0xEFFFFFFF) +/** + * @brief Enables the specified Ethernet MMC Tx interrupts. + * @param __HANDLE__: ETH Handle. + * @param __INTERRUPT__: specifies the Ethernet MMC interrupt sources to be enabled or disabled. + * This parameter can be one of the following values: + * @arg ETH_MMC_IT_TGF : When Tx good frame counter reaches half the maximum value + * @arg ETH_MMC_IT_TGFMSC: When Tx good multi col counter reaches half the maximum value + * @arg ETH_MMC_IT_TGFSC : When Tx good single col counter reaches half the maximum value + * @retval None + */ +#define __HAL_ETH_MMC_TX_IT_ENABLE(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->MMCRIMR &= ~ (__INTERRUPT__)) + +/** + * @brief Disables the specified Ethernet MMC Tx interrupts. + * @param __HANDLE__: ETH Handle. + * @param __INTERRUPT__: specifies the Ethernet MMC interrupt sources to be enabled or disabled. + * This parameter can be one of the following values: + * @arg ETH_MMC_IT_TGF : When Tx good frame counter reaches half the maximum value + * @arg ETH_MMC_IT_TGFMSC: When Tx good multi col counter reaches half the maximum value + * @arg ETH_MMC_IT_TGFSC : When Tx good single col counter reaches half the maximum value + * @retval None + */ +#define __HAL_ETH_MMC_TX_IT_DISABLE(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->MMCRIMR |= (__INTERRUPT__)) + +/** + * @brief Enables the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_ENABLE_IT() EXTI->IMR |= (ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Disables the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_DISABLE_IT() EXTI->IMR &= ~(ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Enable event on ETH External event line. + * @retval None. + */ +#define __HAL_ETH_WAKEUP_EXTI_ENABLE_EVENT() EXTI->EMR |= (ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Disable event on ETH External event line + * @retval None. + */ +#define __HAL_ETH_WAKEUP_EXTI_DISABLE_EVENT() EXTI->EMR &= ~(ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Get flag of the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_GET_FLAG() EXTI->PR & (ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Clear flag of the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_CLEAR_FLAG() EXTI->PR = (ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Enables rising edge trigger to the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_ENABLE_RISING_EDGE_TRIGGER() EXTI->RTSR |= ETH_EXTI_LINE_WAKEUP + +/** + * @brief Disables the rising edge trigger to the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_DISABLE_RISING_EDGE_TRIGGER() EXTI->RTSR &= ~(ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Enables falling edge trigger to the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_ENABLE_FALLING_EDGE_TRIGGER() EXTI->FTSR |= (ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Disables falling edge trigger to the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_DISABLE_FALLING_EDGE_TRIGGER() EXTI->FTSR &= ~(ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Enables rising/falling edge trigger to the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_ENABLE_FALLINGRISING_TRIGGER() EXTI->RTSR |= ETH_EXTI_LINE_WAKEUP;\ + EXTI->FTSR |= ETH_EXTI_LINE_WAKEUP + +/** + * @brief Disables rising/falling edge trigger to the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_DISABLE_FALLINGRISING_TRIGGER() EXTI->RTSR &= ~(ETH_EXTI_LINE_WAKEUP);\ + EXTI->FTSR &= ~(ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Generate a Software interrupt on selected EXTI line. + * @retval None. + */ +#define __HAL_ETH_WAKEUP_EXTI_GENERATE_SWIT() EXTI->SWIER|= ETH_EXTI_LINE_WAKEUP + +/** + * @} + */ +/* Exported functions --------------------------------------------------------*/ + +/** @addtogroup ETH_Exported_Functions + * @{ + */ + +/* Initialization and de-initialization functions ****************************/ + +/** @addtogroup ETH_Exported_Functions_Group1 + * @{ + */ +HAL_StatusTypeDef HAL_ETH_Init(ETH_HandleTypeDef *heth); +HAL_StatusTypeDef HAL_ETH_DeInit(ETH_HandleTypeDef *heth); +void HAL_ETH_MspInit(ETH_HandleTypeDef *heth); +void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth); +HAL_StatusTypeDef HAL_ETH_DMATxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *DMATxDescTab, uint8_t* TxBuff, uint32_t TxBuffCount); +HAL_StatusTypeDef HAL_ETH_DMARxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *DMARxDescTab, uint8_t *RxBuff, uint32_t RxBuffCount); + +/** + * @} + */ +/* IO operation functions ****************************************************/ + +/** @addtogroup ETH_Exported_Functions_Group2 + * @{ + */ +HAL_StatusTypeDef HAL_ETH_TransmitFrame(ETH_HandleTypeDef *heth, uint32_t FrameLength); +HAL_StatusTypeDef HAL_ETH_GetReceivedFrame(ETH_HandleTypeDef *heth); +/* Communication with PHY functions*/ +HAL_StatusTypeDef HAL_ETH_ReadPHYRegister(ETH_HandleTypeDef *heth, uint16_t PHYReg, uint32_t *RegValue); +HAL_StatusTypeDef HAL_ETH_WritePHYRegister(ETH_HandleTypeDef *heth, uint16_t PHYReg, uint32_t RegValue); +/* Non-Blocking mode: Interrupt */ +HAL_StatusTypeDef HAL_ETH_GetReceivedFrame_IT(ETH_HandleTypeDef *heth); +void HAL_ETH_IRQHandler(ETH_HandleTypeDef *heth); +/* Callback in non blocking modes (Interrupt) */ +void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth); +void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth); +void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth); +/** + * @} + */ + +/* Peripheral Control functions **********************************************/ + +/** @addtogroup ETH_Exported_Functions_Group3 + * @{ + */ + +HAL_StatusTypeDef HAL_ETH_Start(ETH_HandleTypeDef *heth); +HAL_StatusTypeDef HAL_ETH_Stop(ETH_HandleTypeDef *heth); +HAL_StatusTypeDef HAL_ETH_ConfigMAC(ETH_HandleTypeDef *heth, ETH_MACInitTypeDef *macconf); +HAL_StatusTypeDef HAL_ETH_ConfigDMA(ETH_HandleTypeDef *heth, ETH_DMAInitTypeDef *dmaconf); +/** + * @} + */ + +/* Peripheral State functions ************************************************/ + +/** @addtogroup ETH_Exported_Functions_Group4 + * @{ + */ +HAL_ETH_StateTypeDef HAL_ETH_GetState(ETH_HandleTypeDef *heth); +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +#ifdef __cplusplus +} +#endif + +#endif /* __STM32F7xx_HAL_ETH_H */ + + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c new file mode 100644 index 000000000..7b98a93ee --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/NetworkInterface.c @@ -0,0 +1,1181 @@ +/* + * Some constants, hardware definitions and comments taken from ST's HAL driver + * library, COPYRIGHT(c) 2015 STMicroelectronics. + */ + +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org +*/ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_DNS.h" +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" +#include "phyHandling.h" + +#define __STM32_HAL_LEGACY 1 + +/* ST includes. */ +#if defined( STM32F7xx ) + #include "stm32f7xx_hal.h" +#elif defined( STM32F4xx ) + #include "stm32f4xx_hal.h" +#elif defined( STM32F2xx ) + #include "stm32f2xx_hal.h" +#else + #error What part? +#endif + +#include "stm32fxx_hal_eth.h" + +/* Interrupt events to process. Currently only the Rx event is processed +although code for other events is included to allow for possible future +expansion. */ +#define EMAC_IF_RX_EVENT 1UL +#define EMAC_IF_TX_EVENT 2UL +#define EMAC_IF_ERR_EVENT 4UL +#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT ) + +#define ETH_DMA_ALL_INTS \ + ( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | ETH_DMA_IT_ER | \ + ETH_DMA_IT_FBE | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \ + ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T ) + +#ifndef niEMAC_HANDLER_TASK_PRIORITY + #define niEMAC_HANDLER_TASK_PRIORITY configMAX_PRIORITIES - 1 +#endif + +#define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff ) /* The bits in the two byte IP header field that make up the fragment offset value. */ + +/* + * Most users will want a PHY that negotiates about + * the connection properties: speed, dmix and duplex. + * On some rare cases, you want to select what is being + * advertised, properties like MDIX and duplex. + */ + +#if !defined( ipconfigETHERNET_AN_ENABLE ) + /* Enable auto-negotiation */ + #define ipconfigETHERNET_AN_ENABLE 1 +#endif + +#if !defined( ipconfigETHERNET_AUTO_CROSS_ENABLE ) + #define ipconfigETHERNET_AUTO_CROSS_ENABLE 1 +#endif + +#if( ipconfigETHERNET_AN_ENABLE == 0 ) + /* + * The following three defines are only used in case there + * is no auto-negotiation. + */ + #if !defined( ipconfigETHERNET_CROSSED_LINK ) + #define ipconfigETHERNET_CROSSED_LINK 1 + #endif + + #if !defined( ipconfigETHERNET_USE_100MB ) + #define ipconfigETHERNET_USE_100MB 1 + #endif + + #if !defined( ipconfigETHERNET_USE_FULL_DUPLEX ) + #define ipconfigETHERNET_USE_FULL_DUPLEX 1 + #endif +#endif /* ipconfigETHERNET_AN_ENABLE == 0 */ + +/* Default the size of the stack used by the EMAC deferred handler task to twice +the size of the stack used by the idle task - but allow this to be overridden in +FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */ +#ifndef configEMAC_TASK_STACK_SIZE + #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE ) +#endif + +/* Two choices must be made: RMII versus MII, +and the index of the PHY in use ( between 0 and 31 ). */ +#ifndef ipconfigUSE_RMII + #ifdef STM32F7xx + #define ipconfigUSE_RMII 1 + #else + #define ipconfigUSE_RMII 0 + #endif /* STM32F7xx */ +#endif /* ipconfigUSE_RMII */ + +#if( ipconfigUSE_RMII != 0 ) + #warning Using RMII, make sure if this is correct +#else + #warning Using MII, make sure if this is correct +#endif + +/*-----------------------------------------------------------*/ + +/* + * A deferred interrupt handler task that processes + */ +static void prvEMACHandlerTask( void *pvParameters ); + +/* + * Force a negotiation with the Switch or Router and wait for LS. + */ +static void prvEthernetUpdateConfig( BaseType_t xForce ); + +/* + * See if there is a new packet and forward it to the IP-task. + */ +static BaseType_t prvNetworkInterfaceInput( void ); + +#if( ipconfigUSE_LLMNR != 0 ) + /* + * For LLMNR, an extra MAC-address must be configured to + * be able to receive the multicast messages. + */ + static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr); +#endif + +/* + * Check if a given packet should be accepted. + */ +static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer ); + +/* + * Initialise the TX descriptors. + */ +static void prvDMATxDescListInit( void ); + +/* + * Initialise the RX descriptors. + */ +static void prvDMARxDescListInit( void ); + + /* After packets have been sent, the network + buffers will be released. */ + static void vClearTXBuffers( void ); + +/*-----------------------------------------------------------*/ + +/* Bit map of outstanding ETH interrupt events for processing. Currently only +the Rx interrupt is handled, although code is included for other events to +enable future expansion. */ +static volatile uint32_t ulISREvents; + +#if( ipconfigUSE_LLMNR == 1 ) + static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC }; +#endif + +static EthernetPhy_t xPhyObject; + +/* Ethernet handle. */ +static ETH_HandleTypeDef xETH; + + /* xTXDescriptorSemaphore is a counting semaphore with + a maximum count of ETH_TXBUFNB, which is the number of + DMA TX descriptors. */ + static SemaphoreHandle_t xTXDescriptorSemaphore = NULL; + +/* + * Note: it is adviced to define both + * + * #define ipconfigZERO_COPY_RX_DRIVER 1 + * #define ipconfigZERO_COPY_TX_DRIVER 1 + * + * The method using memcpy is slower and probaly uses more RAM memory. + * The possibility is left in the code just for comparison. + * + * It is adviced to define ETH_TXBUFNB at least 4. Note that no + * TX buffers are allocated in a zero-copy driver. + */ +/* MAC buffers: ---------------------------------------------------------*/ + +/* Put the DMA descriptors in '.first_data'. +This is important for STM32F7, which has an L1 data cache. +The first 64KB of the SRAM is not cached. */ + +/* Ethernet Rx MA Descriptor */ +__attribute__ ((aligned (32))) +__attribute__ ((section(".first_data"))) + ETH_DMADescTypeDef DMARxDscrTab[ ETH_RXBUFNB ]; + +#if( ipconfigZERO_COPY_RX_DRIVER == 0 ) + /* Ethernet Receive Buffer */ + __ALIGN_BEGIN uint8_t Rx_Buff[ ETH_RXBUFNB ][ ETH_RX_BUF_SIZE ] __ALIGN_END; +#endif + +/* Ethernet Tx DMA Descriptor */ +__attribute__ ((aligned (32))) +__attribute__ ((section(".first_data"))) + ETH_DMADescTypeDef DMATxDscrTab[ ETH_TXBUFNB ]; + +#if( ipconfigZERO_COPY_TX_DRIVER == 0 ) + /* Ethernet Transmit Buffer */ + __ALIGN_BEGIN uint8_t Tx_Buff[ ETH_TXBUFNB ][ ETH_TX_BUF_SIZE ] __ALIGN_END; +#endif + +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + /* DMATxDescToClear points to the next TX DMA descriptor + that must be cleared by vClearTXBuffers(). */ + static __IO ETH_DMADescTypeDef *DMATxDescToClear; +#endif + +/* Holds the handle of the task used as a deferred interrupt processor. The +handle is used so direct notifications can be sent to the task for all EMAC/DMA +related interrupts. */ +static TaskHandle_t xEMACTaskHandle = NULL; + +/* For local use only: describe the PHY's properties: */ +const PhyProperties_t xPHYProperties = +{ + #if( ipconfigETHERNET_AN_ENABLE != 0 ) + .ucSpeed = PHY_SPEED_AUTO, + .ucDuplex = PHY_DUPLEX_AUTO, + #else + #if( ipconfigETHERNET_USE_100MB != 0 ) + .ucSpeed = PHY_SPEED_100, + #else + .ucSpeed = PHY_SPEED_10, + #endif + + #if( ipconfigETHERNET_USE_FULL_DUPLEX != 0 ) + .duplex = PHY_DUPLEX_FULL, + #else + .duplex = PHY_DUPLEX_HALF, + #endif + #endif + + #if( ipconfigETHERNET_AN_ENABLE != 0 ) && ( ipconfigETHERNET_AUTO_CROSS_ENABLE != 0 ) + .ucMDI_X = PHY_MDIX_AUTO, + #elif( ipconfigETHERNET_CROSSED_LINK != 0 ) + .ucMDI_X = PHY_MDIX_CROSSED, + #else + .ucMDI_X = PHY_MDIX_DIRECT, + #endif +}; + +/*-----------------------------------------------------------*/ + +void HAL_ETH_RxCpltCallback( ETH_HandleTypeDef *heth ) +{ +BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + /* Ethernet RX-Complete callback function, elsewhere declared as weak. */ + ulISREvents |= EMAC_IF_RX_EVENT; + /* Wakeup the prvEMACHandlerTask. */ + if( xEMACTaskHandle != NULL ) + { + vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken ); + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + } +} +/*-----------------------------------------------------------*/ + + void HAL_ETH_TxCpltCallback( ETH_HandleTypeDef *heth ) + { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + /* This call-back is only useful in case packets are being sent + zero-copy. Once they're sent, the buffers will be released + by the function vClearTXBuffers(). */ + ulISREvents |= EMAC_IF_TX_EVENT; + /* Wakeup the prvEMACHandlerTask. */ + if( xEMACTaskHandle != NULL ) + { + vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken ); + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + } + + } +/*-----------------------------------------------------------*/ + + static void vClearTXBuffers() + { + __IO ETH_DMADescTypeDef *txLastDescriptor = xETH.TxDesc; +size_t uxCount = ( ( UBaseType_t ) ETH_TXBUFNB ) - uxSemaphoreGetCount( xTXDescriptorSemaphore ); +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + NetworkBufferDescriptor_t *pxNetworkBuffer; + uint8_t *ucPayLoad; +#endif + + /* This function is called after a TX-completion interrupt. + It will release each Network Buffer used in xNetworkInterfaceOutput(). + 'uxCount' represents the number of descriptors given to DMA for transmission. + After sending a packet, the DMA will clear the 'ETH_DMATXDESC_OWN' bit. */ + while( ( uxCount > 0 ) && ( ( DMATxDescToClear->Status & ETH_DMATXDESC_OWN ) == 0 ) ) + { + if( ( DMATxDescToClear == txLastDescriptor ) && ( uxCount != ETH_TXBUFNB ) ) + { + break; + } + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + ucPayLoad = ( uint8_t * )DMATxDescToClear->Buffer1Addr; + + if( ucPayLoad != NULL ) + { + pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad ); + if( pxNetworkBuffer != NULL ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ; + } + DMATxDescToClear->Buffer1Addr = ( uint32_t )0u; + } + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + + DMATxDescToClear = ( ETH_DMADescTypeDef * )( DMATxDescToClear->Buffer2NextDescAddr ); + + uxCount--; + /* Tell the counting semaphore that one more TX descriptor is available. */ + xSemaphoreGive( xTXDescriptorSemaphore ); + } + } +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceInitialise( void ) +{ +HAL_StatusTypeDef hal_eth_init_status; +BaseType_t xResult; + + if( xEMACTaskHandle == NULL ) + { + if( xTXDescriptorSemaphore == NULL ) + { + xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ETH_TXBUFNB, ( UBaseType_t ) ETH_TXBUFNB ); + configASSERT( xTXDescriptorSemaphore ); + } + + /* Initialise ETH */ + + xETH.Instance = ETH; + xETH.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE; + xETH.Init.Speed = ETH_SPEED_100M; + xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX; + /* Value of PhyAddress doesn't matter, will be probed for. */ + xETH.Init.PhyAddress = 0; + + xETH.Init.MACAddr = ( uint8_t *)FreeRTOS_GetMACAddress(); + xETH.Init.RxMode = ETH_RXINTERRUPT_MODE; + + /* using the ETH_CHECKSUM_BY_HARDWARE option: + both the IP and the protocol checksums will be calculated + by the peripheral. */ + xETH.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE; + + #if( ipconfigUSE_RMII != 0 ) + { + xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII; + } + #else + { + xETH.Init.MediaInterface = ETH_MEDIA_INTERFACE_MII; + } + #endif /* ipconfigUSE_RMII */ + + hal_eth_init_status = HAL_ETH_Init( &xETH ); + + /* Only for inspection by debugger. */ + ( void ) hal_eth_init_status; + + /* Set the TxDesc and RxDesc pointers. */ + xETH.TxDesc = DMATxDscrTab; + xETH.RxDesc = DMARxDscrTab; + + /* Make sure that all unused fields are cleared. */ + memset( &DMATxDscrTab, '\0', sizeof( DMATxDscrTab ) ); + memset( &DMARxDscrTab, '\0', sizeof( DMARxDscrTab ) ); + + /* Initialize Tx Descriptors list: Chain Mode */ + DMATxDescToClear = DMATxDscrTab; + + /* Initialise TX-descriptors. */ + prvDMATxDescListInit(); + + /* Initialise RX-descriptors. */ + prvDMARxDescListInit(); + + #if( ipconfigUSE_LLMNR != 0 ) + { + /* Program the LLMNR address at index 1. */ + prvMACAddressConfig( &xETH, ETH_MAC_ADDRESS1, ( uint8_t *) xLLMNR_MACAddress ); + } + #endif + + /* Force a negotiation with the Switch or Router and wait for LS. */ + prvEthernetUpdateConfig( pdTRUE ); + + /* The deferred interrupt handler task is created at the highest + possible priority to ensure the interrupt handler can return directly + to it. The task's handle is stored in xEMACTaskHandle so interrupts can + notify the task when there is something to process. */ + xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle ); + } /* if( xEMACTaskHandle == NULL ) */ + + if( xPhyObject.ulLinkStatusMask != 0 ) + { + xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS; + xResult = pdPASS; + FreeRTOS_printf( ( "Link Status is high\n" ) ) ; + } + else + { + /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running + and it will keep on checking the PHY and set 'ulLinkStatusMask' when necessary. */ + xResult = pdFAIL; + } + /* When returning non-zero, the stack will become active and + start DHCP (in configured) */ + return xResult; +} +/*-----------------------------------------------------------*/ + +static void prvDMATxDescListInit() +{ +ETH_DMADescTypeDef *pxDMADescriptor; +BaseType_t xIndex; + + /* Get the pointer on the first member of the descriptor list */ + pxDMADescriptor = DMATxDscrTab; + + /* Fill each DMA descriptor with the right values */ + for( xIndex = 0; xIndex < ETH_TXBUFNB; xIndex++, pxDMADescriptor++ ) + { + /* Set Second Address Chained bit */ + pxDMADescriptor->Status = ETH_DMATXDESC_TCH; + + #if( ipconfigZERO_COPY_TX_DRIVER == 0 ) + { + /* Set Buffer1 address pointer */ + pxDMADescriptor->Buffer1Addr = ( uint32_t )( Tx_Buff[ xIndex ] ); + } + #endif + + if( xETH.Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE ) + { + /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */ + pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL; + } + + /* Initialize the next descriptor with the Next Descriptor Polling Enable */ + if( xIndex < ETH_TXBUFNB - 1 ) + { + /* Set next descriptor address register with next descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMADescriptor + 1 ); + } + else + { + /* For last descriptor, set next descriptor address register equal to the first descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMATxDscrTab; + } + } + + /* Set Transmit Descriptor List Address Register */ + xETH.Instance->DMATDLAR = ( uint32_t ) DMATxDscrTab; +} +/*-----------------------------------------------------------*/ + +static void prvDMARxDescListInit() +{ +ETH_DMADescTypeDef *pxDMADescriptor; +BaseType_t xIndex; + /* + * RX-descriptors. + */ + + /* Get the pointer on the first member of the descriptor list */ + pxDMADescriptor = DMARxDscrTab; + + /* Fill each DMA descriptor with the right values */ + for( xIndex = 0; xIndex < ETH_RXBUFNB; xIndex++, pxDMADescriptor++ ) + { + + /* Set Buffer1 size and Second Address Chained bit */ + pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE; + + #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + { + /* Set Buffer1 address pointer */ + NetworkBufferDescriptor_t *pxBuffer; + + pxBuffer = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, 100ul ); + /* If the assert below fails, make sure that there are at least 'ETH_RXBUFNB' + Network Buffers available during start-up ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ) */ + configASSERT( pxBuffer != NULL ); + if( pxBuffer != NULL ) + { + pxDMADescriptor->Buffer1Addr = (uint32_t)pxBuffer->pucEthernetBuffer; + pxDMADescriptor->Status = ETH_DMARXDESC_OWN; + } + } + #else + { + /* Set Buffer1 address pointer */ + pxDMADescriptor->Buffer1Addr = ( uint32_t )( Rx_Buff[ xIndex ] ); + /* Set Own bit of the Rx descriptor Status */ + pxDMADescriptor->Status = ETH_DMARXDESC_OWN; + } + #endif + + /* Initialize the next descriptor with the Next Descriptor Polling Enable */ + if( xIndex < ETH_RXBUFNB - 1 ) + { + /* Set next descriptor address register with next descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t )( pxDMADescriptor + 1 ); + } + else + { + /* For last descriptor, set next descriptor address register equal to the first descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) DMARxDscrTab; + } + + } + /* Set Receive Descriptor List Address Register */ + xETH.Instance->DMARDLAR = ( uint32_t ) DMARxDscrTab; +} +/*-----------------------------------------------------------*/ + +static void prvMACAddressConfig(ETH_HandleTypeDef *heth, uint32_t ulIndex, uint8_t *Addr) +{ +uint32_t ulTempReg; + + /* Calculate the selected MAC address high register. */ + ulTempReg = 0x80000000ul | ( ( uint32_t ) Addr[ 5 ] << 8 ) | ( uint32_t ) Addr[ 4 ]; + + /* Load the selected MAC address high register. */ + ( *(__IO uint32_t *)( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + ulIndex ) ) ) = ulTempReg; + + /* Calculate the selected MAC address low register. */ + ulTempReg = ( ( uint32_t ) Addr[ 3 ] << 24 ) | ( ( uint32_t ) Addr[ 2 ] << 16 ) | ( ( uint32_t ) Addr[ 1 ] << 8 ) | Addr[ 0 ]; + + /* Load the selected MAC address low register */ + ( *(__IO uint32_t *) ( ( uint32_t ) ( ETH_MAC_ADDR_LBASE + ulIndex ) ) ) = ulTempReg; +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend ) +{ +BaseType_t xReturn = pdFAIL; +uint32_t ulTransmitSize = 0; +__IO ETH_DMADescTypeDef *pxDmaTxDesc; +/* Do not wait too long for a free TX DMA buffer. */ +const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50u ); + + /* Open a do {} while ( 0 ) loop to be able to call break. */ + do + { + #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) + { + ProtocolPacket_t *pxPacket; + + #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + { + configASSERT( bReleaseAfterSend != 0 ); + } + #endif /* ipconfigZERO_COPY_RX_DRIVER */ + + /* If the peripheral must calculate the checksum, it wants + the protocol checksum to have a value of zero. */ + pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer ); + + if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP ) + { + pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u; + } + } + #endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */ + if( xPhyObject.ulLinkStatusMask != 0 ) + { + if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS ) + { + /* Time-out waiting for a free TX descriptor. */ + break; + } + + /* This function does the actual transmission of the packet. The packet is + contained in 'pxDescriptor' that is passed to the function. */ + pxDmaTxDesc = xETH.TxDesc; + + /* Is this buffer available? */ + configASSERT ( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) == 0 ); + + { + /* Is this buffer available? */ + /* Get bytes in current buffer. */ + ulTransmitSize = pxDescriptor->xDataLength; + + if( ulTransmitSize > ETH_TX_BUF_SIZE ) + { + ulTransmitSize = ETH_TX_BUF_SIZE; + } + + #if( ipconfigZERO_COPY_TX_DRIVER == 0 ) + { + /* Copy the bytes. */ + memcpy( ( void * ) pxDmaTxDesc->Buffer1Addr, pxDescriptor->pucEthernetBuffer, ulTransmitSize ); + } + #else + { + /* Move the buffer. */ + pxDmaTxDesc->Buffer1Addr = ( uint32_t )pxDescriptor->pucEthernetBuffer; + /* The Network Buffer has been passed to DMA, no need to release it. */ + bReleaseAfterSend = pdFALSE_UNSIGNED; + } + #endif /* ipconfigZERO_COPY_TX_DRIVER */ + + /* Ask to set the IPv4 checksum. + Also need an Interrupt on Completion so that 'vClearTXBuffers()' will be called.. */ + pxDmaTxDesc->Status |= ETH_DMATXDESC_CIC_TCPUDPICMP_FULL | ETH_DMATXDESC_IC; + + /* Prepare transmit descriptors to give to DMA. */ + + /* Set LAST and FIRST segment */ + pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS; + /* Set frame size */ + pxDmaTxDesc->ControlBufferSize = ( ulTransmitSize & ETH_DMATXDESC_TBS1 ); + + #if( NETWORK_BUFFERS_CACHED != 0 ) + { + BaseType_t xlength = CACHE_LINE_SIZE * ( ( ulTransmitSize + NETWORK_BUFFER_HEADER_SIZE + CACHE_LINE_SIZE - 1 ) / CACHE_LINE_SIZE ); + uint32_t *pulBuffer = ( uint32_t )( pxDescriptor->pucEthernetBuffer - NETWORK_BUFFER_HEADER_SIZE ); + cache_clean_invalidate_by_addr( pulBuffer, xlength ); + } + #endif + + /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ + pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN; + + /* Point to next descriptor */ + xETH.TxDesc = ( ETH_DMADescTypeDef * ) ( xETH.TxDesc->Buffer2NextDescAddr ); + /* Ensure completion of memory access */ + __DSB(); + /* Resume DMA transmission*/ + xETH.Instance->DMATPDR = 0; + iptraceNETWORK_INTERFACE_TRANSMIT(); + xReturn = pdPASS; + } + } + else + { + /* The PHY has no Link Status, packet shall be dropped. */ + } + } while( 0 ); + /* The buffer has been sent so can be released. */ + if( bReleaseAfterSend != pdFALSE ) + { + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static BaseType_t xMayAcceptPacket( uint8_t *pcBuffer ) +{ +const ProtocolPacket_t *pxProtPacket = ( const ProtocolPacket_t * )pcBuffer; + + switch( pxProtPacket->xTCPPacket.xEthernetHeader.usFrameType ) + { + case ipARP_FRAME_TYPE: + /* Check it later. */ + return pdTRUE; + case ipIPv4_FRAME_TYPE: + /* Check it here. */ + break; + default: + /* Refuse the packet. */ + return pdFALSE; + } + + #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 1 ) + { + const IPHeader_t *pxIPHeader = &(pxProtPacket->xTCPPacket.xIPHeader); + uint32_t ulDestinationIPAddress; + + /* Ensure that the incoming packet is not fragmented (only outgoing packets + * can be fragmented) as these are the only handled IP frames currently. */ + if( ( pxIPHeader->usFragmentOffset & FreeRTOS_ntohs( ipFRAGMENT_OFFSET_BIT_MASK ) ) != 0U ) + { + return pdFALSE; + } + /* HT: Might want to make the following configurable because + * most IP messages have a standard length of 20 bytes */ + + /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes + * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */ + if( pxIPHeader->ucVersionHeaderLength < 0x45 || pxIPHeader->ucVersionHeaderLength > 0x4F ) + { + return pdFALSE; + } + + ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress; + /* Is the packet for this node? */ + if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) && + /* Is it a broadcast address x.x.x.255 ? */ + ( ( FreeRTOS_ntohl( ulDestinationIPAddress ) & 0xff ) != 0xff ) && + #if( ipconfigUSE_LLMNR == 1 ) + ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) && + #endif + ( *ipLOCAL_IP_ADDRESS_POINTER != 0 ) ) { + FreeRTOS_printf( ( "Drop IP %lxip\n", FreeRTOS_ntohl( ulDestinationIPAddress ) ) ); + return pdFALSE; + } + + if( pxIPHeader->ucProtocol == ipPROTOCOL_UDP ) + { + uint16_t port = pxProtPacket->xUDPPacket.xUDPHeader.usDestinationPort; + + if( ( xPortHasUDPSocket( port ) == pdFALSE ) + #if ipconfigUSE_LLMNR == 1 + && ( port != FreeRTOS_ntohs( ipLLMNR_PORT ) ) + #endif + #if ipconfigUSE_NBNS == 1 + && ( port != FreeRTOS_ntohs( ipNBNS_PORT ) ) + #endif + #if ipconfigUSE_DNS == 1 + && ( pxProtPacket->xUDPPacket.xUDPHeader.usSourcePort != FreeRTOS_ntohs( ipDNS_PORT ) ) + #endif + ) { + /* Drop this packet, not for this device. */ + return pdFALSE; + } + } + } + #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvNetworkInterfaceInput( void ) +{ +NetworkBufferDescriptor_t *pxCurDescriptor; +NetworkBufferDescriptor_t *pxNewDescriptor = NULL; +BaseType_t xReceivedLength, xAccepted; +__IO ETH_DMADescTypeDef *pxDMARxDescriptor; +xIPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; +const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 ); +uint8_t *pucBuffer; + + pxDMARxDescriptor = xETH.RxDesc; + + if( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_OWN) == 0 ) + { + /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */ + xReceivedLength = ( ( pxDMARxDescriptor->Status & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4; + + pucBuffer = (uint8_t *) pxDMARxDescriptor->Buffer1Addr; + + /* Update the ETHERNET DMA global Rx descriptor with next Rx descriptor */ + /* Chained Mode */ + /* Selects the next DMA Rx descriptor list for next buffer to read */ + xETH.RxDesc = ( ETH_DMADescTypeDef* )pxDMARxDescriptor->Buffer2NextDescAddr; + } + else + { + xReceivedLength = 0; + } + + /* Obtain the size of the packet and put it into the "usReceivedLength" variable. */ + + /* get received frame */ + if( xReceivedLength > 0ul ) + { + /* In order to make the code easier and faster, only packets in a single buffer + will be accepted. This can be done by making the buffers large enough to + hold a complete Ethernet packet (1536 bytes). + Therefore, two sanity checks: */ + configASSERT( xReceivedLength <= ETH_RX_BUF_SIZE ); + + if( ( pxDMARxDescriptor->Status & ( ETH_DMARXDESC_CE | ETH_DMARXDESC_IPV4HCE | ETH_DMARXDESC_FT ) ) != ETH_DMARXDESC_FT ) + { + /* Not an Ethernet frame-type or a checmsum error. */ + xAccepted = pdFALSE; + } + else + { + /* See if this packet must be handled. */ + xAccepted = xMayAcceptPacket( pucBuffer ); + } + + if( xAccepted != pdFALSE ) + { + /* The packet wil be accepted, but check first if a new Network Buffer can + be obtained. If not, the packet will still be dropped. */ + pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ETH_RX_BUF_SIZE, xDescriptorWaitTime ); + + if( pxNewDescriptor == NULL ) + { + /* A new descriptor can not be allocated now. This packet will be dropped. */ + xAccepted = pdFALSE; + } + } + #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + { + /* Find out which Network Buffer was originally passed to the descriptor. */ + pxCurDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer ); + configASSERT( pxCurDescriptor != NULL ); + } + #else + { + /* In this mode, the two descriptors are the same. */ + pxCurDescriptor = pxNewDescriptor; + if( pxNewDescriptor != NULL ) + { + /* The packet is acepted and a new Network Buffer was created, + copy data to the Network Bufffer. */ + memcpy( pxNewDescriptor->pucEthernetBuffer, pucBuffer, xReceivedLength ); + } + } + #endif + + if( xAccepted != pdFALSE ) + { + pxCurDescriptor->xDataLength = xReceivedLength; + xRxEvent.pvData = ( void * ) pxCurDescriptor; + + /* Pass the data to the TCP/IP task for processing. */ + if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE ) + { + /* Could not send the descriptor into the TCP/IP stack, it + must be released. */ + vReleaseNetworkBufferAndDescriptor( pxCurDescriptor ); + iptraceETHERNET_RX_EVENT_LOST(); + } + else + { + iptraceNETWORK_INTERFACE_RECEIVE(); + } + } + + /* Release descriptors to DMA */ + #if( ipconfigZERO_COPY_RX_DRIVER != 0 ) + { + /* Set Buffer1 address pointer */ + if( pxNewDescriptor != NULL ) + { + pxDMARxDescriptor->Buffer1Addr = (uint32_t)pxNewDescriptor->pucEthernetBuffer; + } + else + { + /* The packet was dropped and the same Network + Buffer will be used to receive a new packet. */ + } + } + #endif /* ipconfigZERO_COPY_RX_DRIVER */ + + /* Set Buffer1 size and Second Address Chained bit */ + pxDMARxDescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | (uint32_t)ETH_RX_BUF_SIZE; + pxDMARxDescriptor->Status = ETH_DMARXDESC_OWN; + + /* Ensure completion of memory access */ + __DSB(); + /* When Rx Buffer unavailable flag is set clear it and resume + reception. */ + if( ( xETH.Instance->DMASR & ETH_DMASR_RBUS ) != 0 ) + { + /* Clear RBUS ETHERNET DMA flag. */ + xETH.Instance->DMASR = ETH_DMASR_RBUS; + + /* Resume DMA reception. */ + xETH.Instance->DMARPDR = 0; + } + } + + return ( xReceivedLength > 0 ); +} +/*-----------------------------------------------------------*/ + + +BaseType_t xSTM32_PhyRead( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue ) + { +uint16_t usPrevAddress = xETH.Init.PhyAddress; +BaseType_t xResult; +HAL_StatusTypeDef xHALResult; + + xETH.Init.PhyAddress = xAddress; + xHALResult = HAL_ETH_ReadPHYRegister( &xETH, ( uint16_t )xRegister, pulValue ); + xETH.Init.PhyAddress = usPrevAddress; + + if( xHALResult == HAL_OK ) + { + xResult = 0; + } + else + { + xResult = -1; + } + return xResult; + } +/*-----------------------------------------------------------*/ + +BaseType_t xSTM32_PhyWrite( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue ) + { +uint16_t usPrevAddress = xETH.Init.PhyAddress; +BaseType_t xResult; +HAL_StatusTypeDef xHALResult; + + xETH.Init.PhyAddress = xAddress; + xHALResult = HAL_ETH_WritePHYRegister( &xETH, ( uint16_t )xRegister, ulValue ); + xETH.Init.PhyAddress = usPrevAddress; + + if( xHALResult == HAL_OK ) + { + xResult = 0; + } + else + { + xResult = -1; + } + return xResult; + } +/*-----------------------------------------------------------*/ + +void vMACBProbePhy( void ) +{ + vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite ); + xPhyDiscover( &xPhyObject ); + xPhyConfigure( &xPhyObject, &xPHYProperties ); +} +/*-----------------------------------------------------------*/ + +static void prvEthernetUpdateConfig( BaseType_t xForce ) +{ + FreeRTOS_printf( ( "prvEthernetUpdateConfig: LS mask %02lX Force %d\n", + xPhyObject.ulLinkStatusMask, + ( int )xForce ) ); + + if( ( xForce != pdFALSE ) || ( xPhyObject.ulLinkStatusMask != 0 ) ) + { + /* Restart the auto-negotiation. */ + if( xETH.Init.AutoNegotiation != ETH_AUTONEGOTIATION_DISABLE ) + { + xPhyStartAutoNegotiation( &xPhyObject, xPhyGetMask( &xPhyObject ) ); + + /* Configure the MAC with the Duplex Mode fixed by the + auto-negotiation process. */ + if( xPhyObject.xPhyProperties.ucDuplex == PHY_DUPLEX_FULL ) + { + xETH.Init.DuplexMode = ETH_MODE_FULLDUPLEX; + } + else + { + xETH.Init.DuplexMode = ETH_MODE_HALFDUPLEX; + } + + /* Configure the MAC with the speed fixed by the + auto-negotiation process. */ + if( xPhyObject.xPhyProperties.ucSpeed == PHY_SPEED_10 ) + { + xETH.Init.Speed = ETH_SPEED_10M; + } + else + { + xETH.Init.Speed = ETH_SPEED_100M; + } + } + else /* AutoNegotiation Disable */ + { + /* Check parameters */ + assert_param( IS_ETH_SPEED( xETH.Init.Speed ) ); + assert_param( IS_ETH_DUPLEX_MODE( xETH.Init.DuplexMode ) ); + + if( xETH.Init.DuplexMode == ETH_MODE_FULLDUPLEX ) + { + xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_HALF; + } + else + { + xPhyObject.xPhyPreferences.ucDuplex = PHY_DUPLEX_FULL; + } + + if( xETH.Init.Speed == ETH_SPEED_10M ) + { + xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_10; + } + else + { + xPhyObject.xPhyPreferences.ucSpeed = PHY_SPEED_100; + } + + xPhyObject.xPhyPreferences.ucMDI_X = PHY_MDIX_AUTO; + + /* Use predefined (fixed) configuration. */ + xPhyFixedValue( &xPhyObject, xPhyGetMask( &xPhyObject ) ); + } + + /* ETHERNET MAC Re-Configuration */ + HAL_ETH_ConfigMAC( &xETH, (ETH_MACInitTypeDef *) NULL); + + /* Restart MAC interface */ + HAL_ETH_Start( &xETH); + } + else + { + /* Stop MAC interface */ + HAL_ETH_Stop( &xETH ); + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xGetPhyLinkStatus( void ) +{ +BaseType_t xReturn; + + if( xPhyObject.ulLinkStatusMask != 0 ) + { + xReturn = pdPASS; + } + else + { + xReturn = pdFAIL; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +/* Uncomment this in case BufferAllocation_1.c is used. */ + +#define niBUFFER_1_PACKET_SIZE 1536 + +void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) +{ +static __attribute__ ((section(".first_data"))) uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) ); +uint8_t *ucRAMBuffer = ucNetworkPackets; +uint32_t ul; + + for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ ) + { + pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING; + *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) ); + ucRAMBuffer += niBUFFER_1_PACKET_SIZE; + } +} +/*-----------------------------------------------------------*/ + +static void prvEMACHandlerTask( void *pvParameters ) +{ +UBaseType_t uxLastMinBufferCount = 0; +#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) +UBaseType_t uxLastMinQueueSpace = 0; +#endif +UBaseType_t uxCurrentCount; +BaseType_t xResult; +const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL ); + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + for( ;; ) + { + xResult = 0; + uxCurrentCount = uxGetMinimumFreeNetworkBuffers(); + if( uxLastMinBufferCount != uxCurrentCount ) + { + /* The logging produced below may be helpful + while tuning +TCP: see how many buffers are in use. */ + uxLastMinBufferCount = uxCurrentCount; + FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n", + uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) ); + } + + if( xTXDescriptorSemaphore != NULL ) + { + static UBaseType_t uxLowestSemCount = ( UBaseType_t ) ETH_TXBUFNB - 1; + + uxCurrentCount = uxSemaphoreGetCount( xTXDescriptorSemaphore ); + if( uxLowestSemCount > uxCurrentCount ) + { + uxLowestSemCount = uxCurrentCount; + FreeRTOS_printf( ( "TX DMA buffers: lowest %lu\n", uxLowestSemCount ) ); + } + + } + + #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + { + uxCurrentCount = uxGetMinimumIPQueueSpace(); + if( uxLastMinQueueSpace != uxCurrentCount ) + { + /* The logging produced below may be helpful + while tuning +TCP: see how many buffers are in use. */ + uxLastMinQueueSpace = uxCurrentCount; + FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) ); + } + } + #endif /* ipconfigCHECK_IP_QUEUE_SPACE */ + + if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 ) + { + /* No events to process now, wait for the next. */ + ulTaskNotifyTake( pdFALSE, ulMaxBlockTime ); + } + + if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 ) + { + ulISREvents &= ~EMAC_IF_RX_EVENT; + + xResult = prvNetworkInterfaceInput(); + if( xResult > 0 ) + { + while( prvNetworkInterfaceInput() > 0 ) + { + } + } + } + + if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 ) + { + /* Code to release TX buffers if zero-copy is used. */ + ulISREvents &= ~EMAC_IF_TX_EVENT; + /* Check if DMA packets have been delivered. */ + vClearTXBuffers(); + } + + if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 ) + { + /* Future extension: logging about errors that occurred. */ + ulISREvents &= ~EMAC_IF_ERR_EVENT; + } + if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 ) + { + /* Something has changed to a Link Status, need re-check. */ + prvEthernetUpdateConfig( pdFALSE ); + } + } +} +/*-----------------------------------------------------------*/ + +void ETH_IRQHandler( void ) +{ + HAL_ETH_IRQHandler( &xETH ); +} + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/readme.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/readme.txt new file mode 100644 index 000000000..73fd553a0 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/readme.txt @@ -0,0 +1,20 @@ +This is a FreeeRTOS+TCP driver that works for both STM32F4xx and STM32F7xx parts. + +The code of stm32fxx_hal_eth.c is based on both drivers as provided by ST. + +These modules should be included: + + NetworkInterface.c + stm32fxx_hal_eth.c + +It is assumed that one of these words are defined: + + STM32F7xx + STM32F407xx + STM32F417xx + STM32F427xx + STM32F437xx + STM32F429xx + STM32F439xx + +The driver has been tested on both Eval and Discovery boards with both STM32F4 and STM32F7. diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f2xx_hal_eth.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f2xx_hal_eth.h new file mode 100644 index 000000000..93b9caff0 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f2xx_hal_eth.h @@ -0,0 +1,6 @@ +/* + * The Ethernet header files for STM32F2, STM32F4 and STM32F7 have been merged to + * a single module that works for both parts: "stm32fxx_hal_eth" + */ + +#include "stm32fxx_hal_eth.h" diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f4xx_hal_eth.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f4xx_hal_eth.c new file mode 100644 index 000000000..4388d1277 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f4xx_hal_eth.c @@ -0,0 +1,1833 @@ +/** + ****************************************************************************** + * @file stm32f4xx_hal_eth.c + * @author MCD Application Team + * @version V1.3.2 + * @date 26-June-2015 + * @brief ETH HAL module driver. + * This file provides firmware functions to manage the following + * functionalities of the Ethernet (ETH) peripheral: + * + Initialization and de-initialization functions + * + IO operation functions + * + Peripheral Control functions + * + Peripheral State and Errors functions + * + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + (#)Declare a ETH_HandleTypeDef handle structure, for example: + ETH_HandleTypeDef heth; + + (#)Fill parameters of Init structure in heth handle + + (#)Call HAL_ETH_Init() API to initialize the Ethernet peripheral (MAC, DMA, ...) + + (#)Initialize the ETH low level resources through the HAL_ETH_MspInit() API: + (##) Enable the Ethernet interface clock using + (+++) __HAL_RCC_ETHMAC_CLK_ENABLE(); + (+++) __HAL_RCC_ETHMACTX_CLK_ENABLE(); + (+++) __HAL_RCC_ETHMACRX_CLK_ENABLE(); + + (##) Initialize the related GPIO clocks + (##) Configure Ethernet pin-out + (##) Configure Ethernet NVIC interrupt (IT mode) + + (#)Initialize Ethernet DMA Descriptors in chain mode and point to allocated buffers: + (##) HAL_ETH_DMATxDescListInit(); for Transmission process + (##) HAL_ETH_DMARxDescListInit(); for Reception process + + (#)Enable MAC and DMA transmission and reception: + (##) HAL_ETH_Start(); + + (#)Prepare ETH DMA TX Descriptors and give the hand to ETH DMA to transfer + the frame to MAC TX FIFO: + (##) HAL_ETH_TransmitFrame(); + + (#)Poll for a received frame in ETH RX DMA Descriptors and get received + frame parameters + (##) HAL_ETH_GetReceivedFrame(); (should be called into an infinite loop) + + (#) Get a received frame when an ETH RX interrupt occurs: + (##) HAL_ETH_GetReceivedFrame_IT(); (called in IT mode only) + + (#) Communicate with external PHY device: + (##) Read a specific register from the PHY + HAL_ETH_ReadPHYRegister(); + (##) Write data to a specific RHY register: + HAL_ETH_WritePHYRegister(); + + (#) Configure the Ethernet MAC after ETH peripheral initialization + HAL_ETH_ConfigMAC(); all MAC parameters should be filled. + + (#) Configure the Ethernet DMA after ETH peripheral initialization + HAL_ETH_ConfigDMA(); all DMA parameters should be filled. + + -@- The PTP protocol and the DMA descriptors ring mode are not supported + in this driver + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32f4xx_hal.h" + +int lUDPLoggingPrintf( const char *pcFormatString, ... ); + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @defgroup ETH ETH + * @brief ETH HAL module driver + * @{ + */ + +#if !defined( ARRAY_SIZE ) + #define ARRAY_SIZE( x ) ( sizeof ( x ) / sizeof ( x )[ 0 ] ) +#endif + +#ifdef HAL_ETH_MODULE_ENABLED + +#if defined(STM32F407xx) || defined(STM32F417xx) || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/** @defgroup ETH_Private_Constants ETH Private Constants + * @{ + */ +#define LINKED_STATE_TIMEOUT_VALUE ((uint32_t)2000) /* 2000 ms */ +#define AUTONEGO_COMPLETED_TIMEOUT_VALUE ((uint32_t)1000) /* 1000 ms */ + +/** + * @} + */ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/** @defgroup ETH_Private_Functions ETH Private Functions + * @{ + */ +static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err); +static void ETH_MACAddressConfig(ETH_HandleTypeDef *heth, uint32_t MacAddr, uint8_t *Addr); +static void ETH_MACReceptionEnable(ETH_HandleTypeDef *heth); +static void ETH_MACReceptionDisable(ETH_HandleTypeDef *heth); +static void ETH_MACTransmissionEnable(ETH_HandleTypeDef *heth); +static void ETH_MACTransmissionDisable(ETH_HandleTypeDef *heth); +static void ETH_DMATransmissionEnable(ETH_HandleTypeDef *heth); +static void ETH_DMATransmissionDisable(ETH_HandleTypeDef *heth); +static void ETH_DMAReceptionEnable(ETH_HandleTypeDef *heth); +static void ETH_DMAReceptionDisable(ETH_HandleTypeDef *heth); +static void ETH_FlushTransmitFIFO(ETH_HandleTypeDef *heth); + +/** + * @} + */ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup ETH_Exported_Functions ETH Exported Functions + * @{ + */ + +/** @defgroup ETH_Exported_Functions_Group1 Initialization and de-initialization functions + * @brief Initialization and Configuration functions + * + @verbatim + =============================================================================== + ##### Initialization and de-initialization functions ##### + =============================================================================== + [..] This section provides functions allowing to: + (+) Initialize and configure the Ethernet peripheral + (+) De-initialize the Ethernet peripheral + + @endverbatim + * @{ + */ +extern void vMACBProbePhy ( void ); + +/** + * @brief Initializes the Ethernet MAC and DMA according to default + * parameters. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_Init(ETH_HandleTypeDef *heth) +{ + uint32_t tmpreg = 0; + uint32_t hclk = 60000000; + uint32_t err = ETH_SUCCESS; + + /* Check the ETH peripheral state */ + if( heth == NULL ) + { + return HAL_ERROR; + } + + /* Check parameters */ + assert_param(IS_ETH_AUTONEGOTIATION(heth->Init.AutoNegotiation)); + assert_param(IS_ETH_RX_MODE(heth->Init.RxMode)); + assert_param(IS_ETH_CHECKSUM_MODE(heth->Init.ChecksumMode)); + assert_param(IS_ETH_MEDIA_INTERFACE(heth->Init.MediaInterface)); + + if( heth->State == HAL_ETH_STATE_RESET ) + { + /* Init the low level hardware : GPIO, CLOCK, NVIC. */ + HAL_ETH_MspInit( heth ); + } + + /* Enable SYSCFG Clock */ + __HAL_RCC_SYSCFG_CLK_ENABLE(); + + /* Select MII or RMII Mode*/ + SYSCFG->PMC &= ~(SYSCFG_PMC_MII_RMII_SEL); + SYSCFG->PMC |= (uint32_t)heth->Init.MediaInterface; + + /* Ethernet Software reset */ + /* Set the SWR bit: resets all MAC subsystem internal registers and logic */ + /* After reset all the registers holds their respective reset values */ + /* Also enable EDFE: Enhanced descriptor format enable. */ + heth->Instance->DMABMR |= ETH_DMABMR_SR | ETH_DMABMR_EDE; + + /* Wait for software reset */ + while ((heth->Instance->DMABMR & ETH_DMABMR_SR) != (uint32_t)RESET) + { + } + + /*-------------------------------- MAC Initialization ----------------------*/ + /* Get the ETHERNET MACMIIAR value */ + tmpreg = heth->Instance->MACMIIAR; + /* Clear CSR Clock Range CR[2:0] bits */ + tmpreg &= ETH_MACMIIAR_CR_MASK; + + /* Get hclk frequency value (168,000,000) */ + hclk = HAL_RCC_GetHCLKFreq(); + + /* Set CR bits depending on hclk value */ + if( ( hclk >= 20000000 ) && ( hclk < 35000000 ) ) + { + /* CSR Clock Range between 20-35 MHz */ + tmpreg |= (uint32_t) ETH_MACMIIAR_CR_Div16; + } + else if( ( hclk >= 35000000 ) && ( hclk < 60000000 ) ) + { + /* CSR Clock Range between 35-60 MHz */ + tmpreg |= ( uint32_t ) ETH_MACMIIAR_CR_Div26; + } + else if((hclk >= 60000000 ) && ( hclk < 100000000 ) ) + { + /* CSR Clock Range between 60-100 MHz */ + tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div42; + } + else if((hclk >= 100000000 ) && ( hclk < 150000000)) + { + /* CSR Clock Range between 100-150 MHz */ + tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div62; + } + else /* ((hclk >= 150000000 ) && ( hclk <= 168000000)) */ + { + /* CSR Clock Range between 150-168 MHz */ + tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div102; + } + + /* Write to ETHERNET MAC MIIAR: Configure the ETHERNET CSR Clock Range */ + heth->Instance->MACMIIAR = (uint32_t)tmpreg; + + /* Initialise the MACB and set all PHY properties */ + vMACBProbePhy(); + + /* Config MAC and DMA */ + ETH_MACDMAConfig(heth, err); + + /* Set ETH HAL State to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief De-Initializes the ETH peripheral. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_DeInit(ETH_HandleTypeDef *heth) +{ + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* De-Init the low level hardware : GPIO, CLOCK, NVIC. */ + HAL_ETH_MspDeInit( heth ); + + /* Set ETH HAL state to Disabled */ + heth->State= HAL_ETH_STATE_RESET; + + /* Release Lock */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Initializes the DMA Tx descriptors in chain mode. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param DMATxDescTab: Pointer to the first Tx desc list + * @param TxBuff: Pointer to the first TxBuffer list + * @param TxBuffCount: Number of the used Tx desc in the list + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_DMATxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *pxDMATable, uint8_t *ucDataBuffer, uint32_t ulBufferCount) +{ + uint32_t i = 0; + ETH_DMADescTypeDef *pxDMADescriptor; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Set the TxDesc pointer with the first one of the pxDMATable list */ + heth->TxDesc = pxDMATable; + + /* Fill each DMA descriptor with the right values */ + for( i=0; i < ulBufferCount; i++ ) + { + /* Get the pointer on the ith member of the descriptor list */ + pxDMADescriptor = pxDMATable + i; + + /* Set Second Address Chained bit */ + pxDMADescriptor->Status = ETH_DMATXDESC_TCH; + + pxDMADescriptor->ControlBufferSize = 0; + + /* Set Buffer1 address pointer */ + if( ucDataBuffer != NULL ) + { + pxDMADescriptor->Buffer1Addr = ( uint32_t )( &ucDataBuffer[ i * ETH_TX_BUF_SIZE ] ); + } + else + { + /* Buffer space is not provided because it uses zero-copy transmissions. */ + pxDMADescriptor->Buffer1Addr = ( uint32_t )0u; + } + + if (heth->Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE) + { + /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */ + pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL; + } + + /* Initialize the next descriptor with the Next Descriptor Polling Enable */ + if(i < ( ulBufferCount - 1 ) ) + { + /* Set next descriptor address register with next descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMATable + i + 1 ); + } + else + { + /* For last descriptor, set next descriptor address register equal to the first descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) pxDMATable; + } + } + + /* Set Transmit Descriptor List Address Register */ + heth->Instance->DMATDLAR = ( uint32_t ) pxDMATable; + + /* Set ETH HAL State to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Initializes the DMA Rx descriptors in chain mode. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param DMARxDescTab: Pointer to the first Rx desc list + * @param RxBuff: Pointer to the first RxBuffer list + * @param RxBuffCount: Number of the used Rx desc in the list + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_DMARxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *pxDMATable, uint8_t *ucDataBuffer, uint32_t ulBufferCount) +{ + uint32_t i = 0; + ETH_DMADescTypeDef *pxDMADescriptor; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Set the RxDesc pointer with the first one of the pxDMATable list */ + heth->RxDesc = pxDMATable; + + /* Fill each DMA descriptor with the right values */ + for(i=0; i < ulBufferCount; i++) + { + /* Get the pointer on the ith member of the descriptor list */ + pxDMADescriptor = pxDMATable+i; + + /* Set Own bit of the Rx descriptor Status */ + pxDMADescriptor->Status = ETH_DMARXDESC_OWN; + + /* Set Buffer1 size and Second Address Chained bit */ + pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | ETH_RX_BUF_SIZE; + + /* Set Buffer1 address pointer */ + if( ucDataBuffer != NULL ) + { + pxDMADescriptor->Buffer1Addr = ( uint32_t )( &ucDataBuffer[ i * ETH_RX_BUF_SIZE ] ); + } + else + { + /* Buffer space is not provided because it uses zero-copy reception. */ + pxDMADescriptor->Buffer1Addr = ( uint32_t )0u; + } + + if( heth->Init.RxMode == ETH_RXINTERRUPT_MODE ) + { + /* Enable Ethernet DMA Rx Descriptor interrupt */ + pxDMADescriptor->ControlBufferSize &= ~ETH_DMARXDESC_DIC; + } + + /* Initialize the next descriptor with the Next Descriptor Polling Enable */ + if(i < (ulBufferCount-1)) + { + /* Set next descriptor address register with next descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = (uint32_t)(pxDMATable+i+1); + } + else + { + /* For last descriptor, set next descriptor address register equal to the first descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) pxDMATable; + } + } + + /* Set Receive Descriptor List Address Register */ + heth->Instance->DMARDLAR = ( uint32_t ) pxDMATable; + + /* Set ETH HAL State to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Initializes the ETH MSP. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_MspInit could be implemented in the user file + */ +} + +/** + * @brief DeInitializes ETH MSP. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_MspDeInit could be implemented in the user file + */ +} + +/** + * @} + */ + +/** @defgroup ETH_Exported_Functions_Group2 IO operation functions + * @brief Data transfers functions + * + @verbatim + ============================================================================== + ##### IO operation functions ##### + ============================================================================== + [..] This section provides functions allowing to: + (+) Transmit a frame + HAL_ETH_TransmitFrame(); + (+) Receive a frame + HAL_ETH_GetReceivedFrame(); + HAL_ETH_GetReceivedFrame_IT(); + (+) Read from an External PHY register + HAL_ETH_ReadPHYRegister(); + (+) Write to an External PHY register + HAL_ETH_WritePHYRegister(); + + @endverbatim + + * @{ + */ + +/** + * @brief Sends an Ethernet frame. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param FrameLength: Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_TransmitFrame(ETH_HandleTypeDef *heth, uint32_t FrameLength) +{ + uint32_t bufcount = 0, size = 0, i = 0; + __IO ETH_DMADescTypeDef *pxDmaTxDesc = heth->TxDesc; + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + if( FrameLength == 0 ) + { + /* Set ETH HAL state to READY */ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + return HAL_ERROR; + } + + /* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */ + if( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) != ( uint32_t ) RESET ) + { + /* OWN bit set */ + heth->State = HAL_ETH_STATE_BUSY_TX; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + return HAL_ERROR; + } + + /* Get the number of needed Tx buffers for the current frame, rounding up. */ + bufcount = ( FrameLength + ETH_TX_BUF_SIZE - 1 ) / ETH_TX_BUF_SIZE; + + if (bufcount == 1) + { + /* Set LAST and FIRST segment */ + pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS; + /* Set frame size */ + pxDmaTxDesc->ControlBufferSize = ( FrameLength & ETH_DMATXDESC_TBS1 ); + /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ + pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN; + /* Point to next descriptor */ + heth->TxDesc = ( ETH_DMADescTypeDef * ) ( heth->TxDesc->Buffer2NextDescAddr ); + } + else + { + for( i = 0; i < bufcount; i++ ) + { + /* Clear FIRST and LAST segment bits */ + uint32_t ulStatus = heth->TxDesc->Status & ~( ETH_DMATXDESC_FS | ETH_DMATXDESC_LS ); + + if( i == 0 ) + { + /* Setting the first segment bit */ + heth->TxDesc->Status = ulStatus | ETH_DMATXDESC_FS; + } + + /* Program size */ + if (i < (bufcount-1)) + { + heth->TxDesc->ControlBufferSize = (ETH_TX_BUF_SIZE & ETH_DMATXDESC_TBS1); + } + else + { + /* Setting the last segment bit */ + heth->TxDesc->Status = ulStatus | ETH_DMATXDESC_LS; + size = FrameLength - (bufcount-1)*ETH_TX_BUF_SIZE; + heth->TxDesc->ControlBufferSize = (size & ETH_DMATXDESC_TBS1); + } + + /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ + heth->TxDesc->Status |= ETH_DMATXDESC_OWN; + /* point to next descriptor */ + heth->TxDesc = (ETH_DMADescTypeDef *)( heth->TxDesc->Buffer2NextDescAddr ); + } + } + + __DSB(); + + /* When Tx Buffer unavailable flag is set: clear it and resume transmission */ + if( ( heth->Instance->DMASR & ETH_DMASR_TBUS ) != ( uint32_t )RESET ) + { + heth->Instance->DMACHTDR = ( uint32_t )pxDmaTxDesc; + + /* Clear TBUS ETHERNET DMA flag */ + heth->Instance->DMASR = ETH_DMASR_TBUS; + /* Resume DMA transmission*/ + heth->Instance->DMATPDR = 0; + } + + /* Set ETH HAL State to Ready */ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Checks for received frames. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_GetReceivedFrame_IT( ETH_HandleTypeDef *heth ) +{ + return HAL_ETH_GetReceivedFrame( heth ); +} + +HAL_StatusTypeDef HAL_ETH_GetReceivedFrame( ETH_HandleTypeDef *heth ) +{ +uint32_t ulCounter = 0; +ETH_DMADescTypeDef *pxDescriptor = heth->RxDesc; +HAL_StatusTypeDef xResult = HAL_ERROR; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Check the ETH state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Scan descriptors owned by CPU */ + while( ( ( pxDescriptor->Status & ETH_DMARXDESC_OWN ) == 0ul ) && ( ulCounter < ETH_RXBUFNB ) ) + { + uint32_t ulStatus = pxDescriptor->Status; + + /* Just for security. */ + ulCounter++; + + if( ( ulStatus & ( ETH_DMARXDESC_FS | ETH_DMARXDESC_LS ) ) == ( uint32_t )ETH_DMARXDESC_FS ) + { + /* First segment in frame, but not the last. */ + heth->RxFrameInfos.FSRxDesc = pxDescriptor; + heth->RxFrameInfos.LSRxDesc = ( ETH_DMADescTypeDef *)NULL; + heth->RxFrameInfos.SegCount = 1; + /* Point to next descriptor. */ + pxDescriptor = (ETH_DMADescTypeDef*) (pxDescriptor->Buffer2NextDescAddr); + heth->RxDesc = pxDescriptor; + } + else if( ( ulStatus & ( ETH_DMARXDESC_LS | ETH_DMARXDESC_FS ) ) == 0ul ) + { + /* This is an intermediate segment, not first, not last. */ + /* Increment segment count. */ + heth->RxFrameInfos.SegCount++; + /* Move to the next descriptor. */ + pxDescriptor = ( ETH_DMADescTypeDef * ) ( pxDescriptor->Buffer2NextDescAddr ); + heth->RxDesc = pxDescriptor; + } + /* Must be a last segment */ + else + { + /* This is the last segment. */ + /* Check if last segment is first segment: one segment contains the frame */ + if( heth->RxFrameInfos.SegCount == 0 ) + { + /* Remember the first segment. */ + heth->RxFrameInfos.FSRxDesc = pxDescriptor; + } + + /* Increment segment count */ + heth->RxFrameInfos.SegCount++; + + /* Remember the last segment. */ + heth->RxFrameInfos.LSRxDesc = pxDescriptor; + + /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */ + heth->RxFrameInfos.length = + ( ( ulStatus & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4; + + /* Get the address of the buffer start address */ + heth->RxFrameInfos.buffer = heth->RxFrameInfos.FSRxDesc->Buffer1Addr; + + /* Point to next descriptor */ + heth->RxDesc = ( ETH_DMADescTypeDef * ) pxDescriptor->Buffer2NextDescAddr; + + /* Return OK status: a packet was received. */ + xResult = HAL_OK; + break; + } + } + + /* Set ETH HAL State to Ready */ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return xResult; +} + +#if( STM32_ETHERNET_STATS != 0 ) + + volatile int rx_count, tx_count, int_count; + /** + * @brief This function handles ETH interrupt request. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ + volatile int int_counts[32]; + volatile int tx_status[8]; + volatile unsigned sr_history[32]; + volatile int sr_head; + #define STM32_STAT_INC( x ) do { ( x )++; } while( 0 ) + +#else + #define STM32_STAT_INC( x ) do { } while( 0 ) +#endif /* STM32_ETHERNET_STATS */ + +#define ETH_DMA_ALL_INTS \ + ( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | ETH_DMA_IT_AIS | ETH_DMA_IT_ER | \ + ETH_DMA_IT_FBE | ETH_DMA_IT_ET | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \ + ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T ) + +//#define ETH_DMA_ALL_INTS ETH_DMA_IT_RBU | ETH_DMA_FLAG_T | ETH_DMA_FLAG_AIS + +#define INT_MASK ( ( uint32_t ) ~ ( ETH_DMA_IT_TBU ) ) +void HAL_ETH_IRQHandler(ETH_HandleTypeDef *heth) +{ + uint32_t dmasr; + + STM32_STAT_INC( int_count ); + + dmasr = heth->Instance->DMASR & ETH_DMA_ALL_INTS; + heth->Instance->DMASR = dmasr; + +#if( STM32_ETHERNET_STATS != 0 ) + if( sr_head < ARRAY_SIZE( sr_history ) ) + { + sr_history[ sr_head++ ] = dmasr; + } + + { + int i; + for (i = 0; i < 32; i++) { + if (dmasr & (1u << i)) { + int_counts[i]++; + } + } + tx_status[ ( dmasr >> 20 ) & 0x07 ]++; + } +#endif + + /* Frame received */ + if( ( dmasr & ( ETH_DMA_FLAG_R | ETH_DMA_IT_RBU ) ) != 0 ) + { + /* Receive complete callback */ + HAL_ETH_RxCpltCallback( heth ); + STM32_STAT_INC( rx_count ); + } + /* Frame transmitted */ + if( ( dmasr & ( ETH_DMA_FLAG_T ) ) != 0 ) + { + /* Transfer complete callback */ + HAL_ETH_TxCpltCallback( heth ); + STM32_STAT_INC( tx_count ); + } + + /* ETH DMA Error */ + if( ( dmasr & ( ETH_DMA_FLAG_AIS ) ) != 0 ) + { + /* Ethernet Error callback */ + HAL_ETH_ErrorCallback( heth ); + } +} + +/** + * @brief Tx Transfer completed callbacks. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Rx Transfer completed callbacks. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Ethernet transfer error callbacks + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Reads a PHY register + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param PHYReg: PHY register address, is the index of one of the 32 PHY register. + * This parameter can be one of the following values: + * PHY_BCR: Transceiver Basic Control Register, + * PHY_BSR: Transceiver Basic Status Register. + * More PHY register could be read depending on the used PHY + * @param RegValue: PHY register value + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_ReadPHYRegister(ETH_HandleTypeDef *heth, uint16_t PHYReg, uint32_t *RegValue) +{ +uint32_t tmpreg = 0; +uint32_t tickstart = 0; +HAL_StatusTypeDef xResult; + + /* Check parameters */ + assert_param(IS_ETH_PHY_ADDRESS(heth->Init.PhyAddress)); + + /* Check the ETH peripheral state */ + if( heth->State == HAL_ETH_STATE_BUSY_RD ) + { + xResult = HAL_BUSY; + } + else + { + __HAL_LOCK( heth ); + + /* Set ETH HAL State to BUSY_RD */ + heth->State = HAL_ETH_STATE_BUSY_RD; + + /* Get the ETHERNET MACMIIAR value */ + tmpreg = heth->Instance->MACMIIAR; + + /* Keep only the CSR Clock Range CR[2:0] bits value */ + tmpreg &= ~ETH_MACMIIAR_CR_MASK; + + /* Prepare the MII address register value */ + tmpreg |= ( ( ( uint32_t )heth->Init.PhyAddress << 11) & ETH_MACMIIAR_PA ); /* Set the PHY device address */ + tmpreg |= ( ( ( uint32_t )PHYReg << 6 ) & ETH_MACMIIAR_MR ); /* Set the PHY register address */ + tmpreg &= ~ETH_MACMIIAR_MW; /* Set the read mode */ + tmpreg |= ETH_MACMIIAR_MB; /* Set the MII Busy bit */ + + /* Write the result value into the MII Address register */ + heth->Instance->MACMIIAR = tmpreg; + + /* Get tick */ + tickstart = HAL_GetTick(); + + /* Check for the Busy flag */ + while( 1 ) + { + tmpreg = heth->Instance->MACMIIAR; + + if( ( tmpreg & ETH_MACMIIAR_MB ) == 0ul ) + { + /* Get MACMIIDR value */ + *RegValue = ( uint32_t ) heth->Instance->MACMIIDR; + xResult = HAL_OK; + break; + } + /* Check for the Timeout */ + if( ( HAL_GetTick( ) - tickstart ) > PHY_READ_TO ) + { + xResult = HAL_TIMEOUT; + break; + } + + } + + /* Set ETH HAL State to READY */ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + } + + if( xResult != HAL_OK ) + { + lUDPLoggingPrintf( "ReadPHY: %d\n", xResult ); + } + /* Return function status */ + return xResult; +} + +/** + * @brief Writes to a PHY register. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param PHYReg: PHY register address, is the index of one of the 32 PHY register. + * This parameter can be one of the following values: + * PHY_BCR: Transceiver Control Register. + * More PHY register could be written depending on the used PHY + * @param RegValue: the value to write + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_WritePHYRegister(ETH_HandleTypeDef *heth, uint16_t PHYReg, uint32_t RegValue) +{ +uint32_t tmpreg = 0; +uint32_t tickstart = 0; +HAL_StatusTypeDef xResult; + + /* Check parameters */ + assert_param( IS_ETH_PHY_ADDRESS( heth->Init.PhyAddress ) ); + + /* Check the ETH peripheral state */ + if( heth->State == HAL_ETH_STATE_BUSY_WR ) + { + xResult = HAL_BUSY; + } + else + { + __HAL_LOCK( heth ); + + /* Set ETH HAL State to BUSY_WR */ + heth->State = HAL_ETH_STATE_BUSY_WR; + + /* Get the ETHERNET MACMIIAR value */ + tmpreg = heth->Instance->MACMIIAR; + + /* Keep only the CSR Clock Range CR[2:0] bits value */ + tmpreg &= ~ETH_MACMIIAR_CR_MASK; + + /* Prepare the MII register address value */ + tmpreg |= ( ( ( uint32_t ) heth->Init.PhyAddress << 11 ) & ETH_MACMIIAR_PA ); /* Set the PHY device address */ + tmpreg |= ( ( ( uint32_t ) PHYReg << 6 ) & ETH_MACMIIAR_MR ); /* Set the PHY register address */ + tmpreg |= ETH_MACMIIAR_MW; /* Set the write mode */ + tmpreg |= ETH_MACMIIAR_MB; /* Set the MII Busy bit */ + + /* Give the value to the MII data register */ + heth->Instance->MACMIIDR = ( uint16_t ) RegValue; + + /* Write the result value into the MII Address register */ + heth->Instance->MACMIIAR = tmpreg; + + /* Get tick */ + tickstart = HAL_GetTick(); + + /* Check for the Busy flag */ + while( 1 ) + { + tmpreg = heth->Instance->MACMIIAR; + + if( ( tmpreg & ETH_MACMIIAR_MB ) == 0ul ) + { + xResult = HAL_OK; + break; + } + /* Check for the Timeout */ + if( ( HAL_GetTick( ) - tickstart ) > PHY_WRITE_TO ) + { + xResult = HAL_TIMEOUT; + break; + } + } + + /* Set ETH HAL State to READY */ + heth->State = HAL_ETH_STATE_READY; + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + } + + if( xResult != HAL_OK ) + { + lUDPLoggingPrintf( "WritePHY: %d\n", xResult ); + } + /* Return function status */ + return xResult; +} + +/** + * @} + */ + +/** @defgroup ETH_Exported_Functions_Group3 Peripheral Control functions + * @brief Peripheral Control functions + * +@verbatim + =============================================================================== + ##### Peripheral Control functions ##### + =============================================================================== + [..] This section provides functions allowing to: + (+) Enable MAC and DMA transmission and reception. + HAL_ETH_Start(); + (+) Disable MAC and DMA transmission and reception. + HAL_ETH_Stop(); + (+) Set the MAC configuration in runtime mode + HAL_ETH_ConfigMAC(); + (+) Set the DMA configuration in runtime mode + HAL_ETH_ConfigDMA(); + +@endverbatim + * @{ + */ + + /** + * @brief Enables Ethernet MAC and DMA reception/transmission + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_Start( ETH_HandleTypeDef *heth ) +{ + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Enable transmit state machine of the MAC for transmission on the MII */ + ETH_MACTransmissionEnable( heth ); + + /* Enable receive state machine of the MAC for reception from the MII */ + ETH_MACReceptionEnable( heth ); + + /* Flush Transmit FIFO */ + ETH_FlushTransmitFIFO( heth ); + + /* Start DMA transmission */ + ETH_DMATransmissionEnable( heth ); + + /* Start DMA reception */ + ETH_DMAReceptionEnable( heth ); + + /* Set the ETH state to READY*/ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Stop Ethernet MAC and DMA reception/transmission + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_Stop(ETH_HandleTypeDef *heth) +{ + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Stop DMA transmission */ + ETH_DMATransmissionDisable( heth ); + + /* Stop DMA reception */ + ETH_DMAReceptionDisable( heth ); + + /* Disable receive state machine of the MAC for reception from the MII */ + ETH_MACReceptionDisable( heth ); + + /* Flush Transmit FIFO */ + ETH_FlushTransmitFIFO( heth ); + + /* Disable transmit state machine of the MAC for transmission on the MII */ + ETH_MACTransmissionDisable( heth ); + + /* Set the ETH state*/ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +static void prvWriteMACFCR( ETH_HandleTypeDef *heth, uint32_t ulValue) +{ + /* Enable the MAC transmission */ + heth->Instance->MACFCR = ulValue; + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles. + Read it back, wait a ms and */ + ( void ) heth->Instance->MACFCR; + + HAL_Delay( ETH_REG_WRITE_DELAY ); + + heth->Instance->MACFCR = ulValue; +} + +static void prvWriteDMAOMR( ETH_HandleTypeDef *heth, uint32_t ulValue) +{ + /* Enable the MAC transmission */ + heth->Instance->DMAOMR = ulValue; + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles. + Read it back, wait a ms and */ + ( void ) heth->Instance->DMAOMR; + + HAL_Delay( ETH_REG_WRITE_DELAY ); + + heth->Instance->DMAOMR = ulValue; +} + +static void prvWriteMACCR( ETH_HandleTypeDef *heth, uint32_t ulValue) +{ + /* Enable the MAC transmission */ + heth->Instance->MACCR = ulValue; + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles. + Read it back, wait a ms and */ + ( void ) heth->Instance->MACCR; + + HAL_Delay( ETH_REG_WRITE_DELAY ); + + heth->Instance->MACCR = ulValue; +} + +/** + * @brief Set ETH MAC Configuration. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param macconf: MAC Configuration structure + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_ConfigMAC(ETH_HandleTypeDef *heth, ETH_MACInitTypeDef *macconf) +{ + uint32_t tmpreg = 0; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State= HAL_ETH_STATE_BUSY; + + assert_param(IS_ETH_SPEED(heth->Init.Speed)); + assert_param(IS_ETH_DUPLEX_MODE(heth->Init.DuplexMode)); + + if (macconf != NULL) + { + /* Check the parameters */ + assert_param(IS_ETH_WATCHDOG(macconf->Watchdog)); + assert_param(IS_ETH_JABBER(macconf->Jabber)); + assert_param(IS_ETH_INTER_FRAME_GAP(macconf->InterFrameGap)); + assert_param(IS_ETH_CARRIER_SENSE(macconf->CarrierSense)); + assert_param(IS_ETH_RECEIVE_OWN(macconf->ReceiveOwn)); + assert_param(IS_ETH_LOOPBACK_MODE(macconf->LoopbackMode)); + assert_param(IS_ETH_CHECKSUM_OFFLOAD(macconf->ChecksumOffload)); + assert_param(IS_ETH_RETRY_TRANSMISSION(macconf->RetryTransmission)); + assert_param(IS_ETH_AUTOMATIC_PADCRC_STRIP(macconf->AutomaticPadCRCStrip)); + assert_param(IS_ETH_BACKOFF_LIMIT(macconf->BackOffLimit)); + assert_param(IS_ETH_DEFERRAL_CHECK(macconf->DeferralCheck)); + assert_param(IS_ETH_RECEIVE_ALL(macconf->ReceiveAll)); + assert_param(IS_ETH_SOURCE_ADDR_FILTER(macconf->SourceAddrFilter)); + assert_param(IS_ETH_CONTROL_FRAMES(macconf->PassControlFrames)); + assert_param(IS_ETH_BROADCAST_FRAMES_RECEPTION(macconf->BroadcastFramesReception)); + assert_param(IS_ETH_DESTINATION_ADDR_FILTER(macconf->DestinationAddrFilter)); + assert_param(IS_ETH_PROMISCUOUS_MODE(macconf->PromiscuousMode)); + assert_param(IS_ETH_MULTICAST_FRAMES_FILTER(macconf->MulticastFramesFilter)); + assert_param(IS_ETH_UNICAST_FRAMES_FILTER(macconf->UnicastFramesFilter)); + assert_param(IS_ETH_PAUSE_TIME(macconf->PauseTime)); + assert_param(IS_ETH_ZEROQUANTA_PAUSE(macconf->ZeroQuantaPause)); + assert_param(IS_ETH_PAUSE_LOW_THRESHOLD(macconf->PauseLowThreshold)); + assert_param(IS_ETH_UNICAST_PAUSE_FRAME_DETECT(macconf->UnicastPauseFrameDetect)); + assert_param(IS_ETH_RECEIVE_FLOWCONTROL(macconf->ReceiveFlowControl)); + assert_param(IS_ETH_TRANSMIT_FLOWCONTROL(macconf->TransmitFlowControl)); + assert_param(IS_ETH_VLAN_TAG_COMPARISON(macconf->VLANTagComparison)); + assert_param(IS_ETH_VLAN_TAG_IDENTIFIER(macconf->VLANTagIdentifier)); + + /*------------------------ ETHERNET MACCR Configuration --------------------*/ + /* Get the ETHERNET MACCR value */ + tmpreg = heth->Instance->MACCR; + /* Clear WD, PCE, PS, TE and RE bits */ + tmpreg &= ETH_MACCR_CLEAR_MASK; + + tmpreg |= (uint32_t)( + macconf->Watchdog | + macconf->Jabber | + macconf->InterFrameGap | + macconf->CarrierSense | + heth->Init.Speed | + macconf->ReceiveOwn | + macconf->LoopbackMode | + heth->Init.DuplexMode | + macconf->ChecksumOffload | + macconf->RetryTransmission | + macconf->AutomaticPadCRCStrip | + macconf->BackOffLimit | + macconf->DeferralCheck); + + /* Write to ETHERNET MACCR */ + prvWriteMACCR( heth, tmpreg ); + + /*----------------------- ETHERNET MACFFR Configuration --------------------*/ + /* Write to ETHERNET MACFFR */ + heth->Instance->MACFFR = (uint32_t)( + macconf->ReceiveAll | + macconf->SourceAddrFilter | + macconf->PassControlFrames | + macconf->BroadcastFramesReception | + macconf->DestinationAddrFilter | + macconf->PromiscuousMode | + macconf->MulticastFramesFilter | + macconf->UnicastFramesFilter); + + /* Wait until the write operation will be taken into account : + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->MACFFR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->MACFFR = tmpreg; + + /*--------------- ETHERNET MACHTHR and MACHTLR Configuration ---------------*/ + /* Write to ETHERNET MACHTHR */ + heth->Instance->MACHTHR = (uint32_t)macconf->HashTableHigh; + + /* Write to ETHERNET MACHTLR */ + heth->Instance->MACHTLR = (uint32_t)macconf->HashTableLow; + /*----------------------- ETHERNET MACFCR Configuration --------------------*/ + + /* Get the ETHERNET MACFCR value */ + tmpreg = heth->Instance->MACFCR; + /* Clear xx bits */ + tmpreg &= ETH_MACFCR_CLEAR_MASK; + + tmpreg |= (uint32_t)(( + macconf->PauseTime << 16) | + macconf->ZeroQuantaPause | + macconf->PauseLowThreshold | + macconf->UnicastPauseFrameDetect | + macconf->ReceiveFlowControl | + macconf->TransmitFlowControl); + + /* Write to ETHERNET MACFCR */ + prvWriteMACFCR( heth, tmpreg ); + + /*----------------------- ETHERNET MACVLANTR Configuration -----------------*/ + heth->Instance->MACVLANTR = (uint32_t)(macconf->VLANTagComparison | + macconf->VLANTagIdentifier); + + /* Wait until the write operation will be taken into account : + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->MACVLANTR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->MACVLANTR = tmpreg; + } + else /* macconf == NULL : here we just configure Speed and Duplex mode */ + { + /*------------------------ ETHERNET MACCR Configuration --------------------*/ + /* Get the ETHERNET MACCR value */ + tmpreg = heth->Instance->MACCR; + + /* Clear FES and DM bits */ + tmpreg &= ~((uint32_t)0x00004800); + + tmpreg |= (uint32_t)(heth->Init.Speed | heth->Init.DuplexMode); + + /* Write to ETHERNET MACCR */ + prvWriteMACCR( heth, tmpreg ); + } + + /* Set the ETH state to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Sets ETH DMA Configuration. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param dmaconf: DMA Configuration structure + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_ConfigDMA(ETH_HandleTypeDef *heth, ETH_DMAInitTypeDef *dmaconf) +{ + uint32_t tmpreg = 0; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State= HAL_ETH_STATE_BUSY; + + /* Check parameters */ + assert_param(IS_ETH_DROP_TCPIP_CHECKSUM_FRAME(dmaconf->DropTCPIPChecksumErrorFrame)); + assert_param(IS_ETH_RECEIVE_STORE_FORWARD(dmaconf->ReceiveStoreForward)); + assert_param(IS_ETH_FLUSH_RECEIVE_FRAME(dmaconf->FlushReceivedFrame)); + assert_param(IS_ETH_TRANSMIT_STORE_FORWARD(dmaconf->TransmitStoreForward)); + assert_param(IS_ETH_TRANSMIT_THRESHOLD_CONTROL(dmaconf->TransmitThresholdControl)); + assert_param(IS_ETH_FORWARD_ERROR_FRAMES(dmaconf->ForwardErrorFrames)); + assert_param(IS_ETH_FORWARD_UNDERSIZED_GOOD_FRAMES(dmaconf->ForwardUndersizedGoodFrames)); + assert_param(IS_ETH_RECEIVE_THRESHOLD_CONTROL(dmaconf->ReceiveThresholdControl)); + assert_param(IS_ETH_SECOND_FRAME_OPERATE(dmaconf->SecondFrameOperate)); + assert_param(IS_ETH_ADDRESS_ALIGNED_BEATS(dmaconf->AddressAlignedBeats)); + assert_param(IS_ETH_FIXED_BURST(dmaconf->FixedBurst)); + assert_param(IS_ETH_RXDMA_BURST_LENGTH(dmaconf->RxDMABurstLength)); + assert_param(IS_ETH_TXDMA_BURST_LENGTH(dmaconf->TxDMABurstLength)); + assert_param(IS_ETH_ENHANCED_DESCRIPTOR_FORMAT(dmaconf->EnhancedDescriptorFormat)); + assert_param(IS_ETH_DMA_DESC_SKIP_LENGTH(dmaconf->DescriptorSkipLength)); + assert_param(IS_ETH_DMA_ARBITRATION_ROUNDROBIN_RXTX(dmaconf->DMAArbitration)); + + /*----------------------- ETHERNET DMAOMR Configuration --------------------*/ + /* Get the ETHERNET DMAOMR value */ + tmpreg = heth->Instance->DMAOMR; + /* Clear xx bits */ + tmpreg &= ETH_DMAOMR_CLEAR_MASK; + + tmpreg |= (uint32_t)( + dmaconf->DropTCPIPChecksumErrorFrame | + dmaconf->ReceiveStoreForward | + dmaconf->FlushReceivedFrame | + dmaconf->TransmitStoreForward | + dmaconf->TransmitThresholdControl | + dmaconf->ForwardErrorFrames | + dmaconf->ForwardUndersizedGoodFrames | + dmaconf->ReceiveThresholdControl | + dmaconf->SecondFrameOperate); + + /* Write to ETHERNET DMAOMR */ + prvWriteDMAOMR( heth, tmpreg ); + + /*----------------------- ETHERNET DMABMR Configuration --------------------*/ + heth->Instance->DMABMR = (uint32_t)(dmaconf->AddressAlignedBeats | + dmaconf->FixedBurst | + dmaconf->RxDMABurstLength | /* !! if 4xPBL is selected for Tx or Rx it is applied for the other */ + dmaconf->TxDMABurstLength | + dmaconf->EnhancedDescriptorFormat | + (dmaconf->DescriptorSkipLength << 2) | + dmaconf->DMAArbitration | + ETH_DMABMR_USP); /* Enable use of separate PBL for Rx and Tx */ + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->DMABMR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->DMABMR = tmpreg; + + /* Set the ETH state to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @} + */ + +/** @defgroup ETH_Exported_Functions_Group4 Peripheral State functions + * @brief Peripheral State functions + * + @verbatim + =============================================================================== + ##### Peripheral State functions ##### + =============================================================================== + [..] + This subsection permits to get in run-time the status of the peripheral + and the data flow. + (+) Get the ETH handle state: + HAL_ETH_GetState(); + + + @endverbatim + * @{ + */ + +/** + * @brief Return the ETH HAL state + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL state + */ +HAL_ETH_StateTypeDef HAL_ETH_GetState(ETH_HandleTypeDef *heth) +{ + /* Return ETH state */ + return heth->State; +} + +/** + * @} + */ + +/** + * @} + */ + +/** @addtogroup ETH_Private_Functions + * @{ + */ + +/** + * @brief Configures Ethernet MAC and DMA with default parameters. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param err: Ethernet Init error + * @retval HAL status + */ +static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err) +{ + ETH_MACInitTypeDef macinit; + ETH_DMAInitTypeDef dmainit; + uint32_t tmpreg = 0; + + if (err != ETH_SUCCESS) /* Auto-negotiation failed */ + { + /* Set Ethernet duplex mode to Full-duplex */ + heth->Init.DuplexMode = ETH_MODE_FULLDUPLEX; + + /* Set Ethernet speed to 100M */ + heth->Init.Speed = ETH_SPEED_100M; + } + + /* Ethernet MAC default initialization **************************************/ + macinit.Watchdog = ETH_WATCHDOG_ENABLE; + macinit.Jabber = ETH_JABBER_ENABLE; + macinit.InterFrameGap = ETH_INTERFRAMEGAP_96BIT; + macinit.CarrierSense = ETH_CARRIERSENCE_ENABLE; + macinit.ReceiveOwn = ETH_RECEIVEOWN_ENABLE; + macinit.LoopbackMode = ETH_LOOPBACKMODE_DISABLE; + if(heth->Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE) + { + macinit.ChecksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE; + } + else + { + macinit.ChecksumOffload = ETH_CHECKSUMOFFLAOD_DISABLE; + } + macinit.RetryTransmission = ETH_RETRYTRANSMISSION_DISABLE; + macinit.AutomaticPadCRCStrip = ETH_AUTOMATICPADCRCSTRIP_DISABLE; + macinit.BackOffLimit = ETH_BACKOFFLIMIT_10; + macinit.DeferralCheck = ETH_DEFFERRALCHECK_DISABLE; + macinit.ReceiveAll = ETH_RECEIVEAll_DISABLE; + macinit.SourceAddrFilter = ETH_SOURCEADDRFILTER_DISABLE; + macinit.PassControlFrames = ETH_PASSCONTROLFRAMES_BLOCKALL; + macinit.BroadcastFramesReception = ETH_BROADCASTFRAMESRECEPTION_ENABLE; + macinit.DestinationAddrFilter = ETH_DESTINATIONADDRFILTER_NORMAL; + macinit.PromiscuousMode = ETH_PROMISCUOUS_MODE_DISABLE; + macinit.MulticastFramesFilter = ETH_MULTICASTFRAMESFILTER_PERFECT; + macinit.UnicastFramesFilter = ETH_UNICASTFRAMESFILTER_PERFECT; + macinit.HashTableHigh = 0x0; + macinit.HashTableLow = 0x0; + macinit.PauseTime = 0x0; + macinit.ZeroQuantaPause = ETH_ZEROQUANTAPAUSE_DISABLE; + macinit.PauseLowThreshold = ETH_PAUSELOWTHRESHOLD_MINUS4; + macinit.UnicastPauseFrameDetect = ETH_UNICASTPAUSEFRAMEDETECT_DISABLE; + macinit.ReceiveFlowControl = ETH_RECEIVEFLOWCONTROL_DISABLE; + macinit.TransmitFlowControl = ETH_TRANSMITFLOWCONTROL_DISABLE; + macinit.VLANTagComparison = ETH_VLANTAGCOMPARISON_16BIT; + macinit.VLANTagIdentifier = 0x0; + + /*------------------------ ETHERNET MACCR Configuration --------------------*/ + /* Get the ETHERNET MACCR value */ + tmpreg = heth->Instance->MACCR; + /* Clear WD, PCE, PS, TE and RE bits */ + tmpreg &= ETH_MACCR_CLEAR_MASK; + /* Set the WD bit according to ETH Watchdog value */ + /* Set the JD: bit according to ETH Jabber value */ + /* Set the IFG bit according to ETH InterFrameGap value */ + /* Set the DCRS bit according to ETH CarrierSense value */ + /* Set the FES bit according to ETH Speed value */ + /* Set the DO bit according to ETH ReceiveOwn value */ + /* Set the LM bit according to ETH LoopbackMode value */ + /* Set the DM bit according to ETH Mode value */ + /* Set the IPCO bit according to ETH ChecksumOffload value */ + /* Set the DR bit according to ETH RetryTransmission value */ + /* Set the ACS bit according to ETH AutomaticPadCRCStrip value */ + /* Set the BL bit according to ETH BackOffLimit value */ + /* Set the DC bit according to ETH DeferralCheck value */ + tmpreg |= (uint32_t)(macinit.Watchdog | + macinit.Jabber | + macinit.InterFrameGap | + macinit.CarrierSense | + heth->Init.Speed | + macinit.ReceiveOwn | + macinit.LoopbackMode | + heth->Init.DuplexMode | + macinit.ChecksumOffload | + macinit.RetryTransmission | + macinit.AutomaticPadCRCStrip | + macinit.BackOffLimit | + macinit.DeferralCheck); + + /* Write to ETHERNET MACCR */ + prvWriteMACCR( heth, tmpreg ); + + /*----------------------- ETHERNET MACFFR Configuration --------------------*/ + /* Set the RA bit according to ETH ReceiveAll value */ + /* Set the SAF and SAIF bits according to ETH SourceAddrFilter value */ + /* Set the PCF bit according to ETH PassControlFrames value */ + /* Set the DBF bit according to ETH BroadcastFramesReception value */ + /* Set the DAIF bit according to ETH DestinationAddrFilter value */ + /* Set the PR bit according to ETH PromiscuousMode value */ + /* Set the PM, HMC and HPF bits according to ETH MulticastFramesFilter value */ + /* Set the HUC and HPF bits according to ETH UnicastFramesFilter value */ + /* Write to ETHERNET MACFFR */ + heth->Instance->MACFFR = (uint32_t)(macinit.ReceiveAll | + macinit.SourceAddrFilter | + macinit.PassControlFrames | + macinit.BroadcastFramesReception | + macinit.DestinationAddrFilter | + macinit.PromiscuousMode | + macinit.MulticastFramesFilter | + macinit.UnicastFramesFilter); + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->MACFFR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->MACFFR = tmpreg; + + /*--------------- ETHERNET MACHTHR and MACHTLR Configuration --------------*/ + /* Write to ETHERNET MACHTHR */ + heth->Instance->MACHTHR = (uint32_t)macinit.HashTableHigh; + + /* Write to ETHERNET MACHTLR */ + heth->Instance->MACHTLR = (uint32_t)macinit.HashTableLow; + /*----------------------- ETHERNET MACFCR Configuration -------------------*/ + + /* Get the ETHERNET MACFCR value */ + tmpreg = heth->Instance->MACFCR; + /* Clear xx bits */ + tmpreg &= ETH_MACFCR_CLEAR_MASK; + + /* Set the PT bit according to ETH PauseTime value */ + /* Set the DZPQ bit according to ETH ZeroQuantaPause value */ + /* Set the PLT bit according to ETH PauseLowThreshold value */ + /* Set the UP bit according to ETH UnicastPauseFrameDetect value */ + /* Set the RFE bit according to ETH ReceiveFlowControl value */ + /* Set the TFE bit according to ETH TransmitFlowControl value */ + tmpreg |= (uint32_t)((macinit.PauseTime << 16) | + macinit.ZeroQuantaPause | + macinit.PauseLowThreshold | + macinit.UnicastPauseFrameDetect | + macinit.ReceiveFlowControl | + macinit.TransmitFlowControl); + + /* Write to ETHERNET MACFCR */ + prvWriteMACFCR( heth, tmpreg ); + + /*----------------------- ETHERNET MACVLANTR Configuration ----------------*/ + /* Set the ETV bit according to ETH VLANTagComparison value */ + /* Set the VL bit according to ETH VLANTagIdentifier value */ + heth->Instance->MACVLANTR = (uint32_t)(macinit.VLANTagComparison | + macinit.VLANTagIdentifier); + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->MACVLANTR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->MACVLANTR = tmpreg; + + /* Ethernet DMA default initialization ************************************/ + dmainit.DropTCPIPChecksumErrorFrame = ETH_DROPTCPIPCHECKSUMERRORFRAME_ENABLE; + dmainit.ReceiveStoreForward = ETH_RECEIVESTOREFORWARD_ENABLE; + dmainit.FlushReceivedFrame = ETH_FLUSHRECEIVEDFRAME_ENABLE; + dmainit.TransmitStoreForward = ETH_TRANSMITSTOREFORWARD_ENABLE; + dmainit.TransmitThresholdControl = ETH_TRANSMITTHRESHOLDCONTROL_64BYTES; + dmainit.ForwardErrorFrames = ETH_FORWARDERRORFRAMES_DISABLE; + dmainit.ForwardUndersizedGoodFrames = ETH_FORWARDUNDERSIZEDGOODFRAMES_DISABLE; + dmainit.ReceiveThresholdControl = ETH_RECEIVEDTHRESHOLDCONTROL_64BYTES; + dmainit.SecondFrameOperate = ETH_SECONDFRAMEOPERARTE_ENABLE; + dmainit.AddressAlignedBeats = ETH_ADDRESSALIGNEDBEATS_ENABLE; + dmainit.FixedBurst = ETH_FIXEDBURST_ENABLE; + dmainit.RxDMABurstLength = ETH_RXDMABURSTLENGTH_32BEAT; + dmainit.TxDMABurstLength = ETH_TXDMABURSTLENGTH_32BEAT; + dmainit.EnhancedDescriptorFormat = ETH_DMAENHANCEDDESCRIPTOR_ENABLE; + dmainit.DescriptorSkipLength = 0x0; + dmainit.DMAArbitration = ETH_DMAARBITRATION_ROUNDROBIN_RXTX_1_1; + + /* Get the ETHERNET DMAOMR value */ + tmpreg = heth->Instance->DMAOMR; + /* Clear xx bits */ + tmpreg &= ETH_DMAOMR_CLEAR_MASK; + + /* Set the DT bit according to ETH DropTCPIPChecksumErrorFrame value */ + /* Set the RSF bit according to ETH ReceiveStoreForward value */ + /* Set the DFF bit according to ETH FlushReceivedFrame value */ + /* Set the TSF bit according to ETH TransmitStoreForward value */ + /* Set the TTC bit according to ETH TransmitThresholdControl value */ + /* Set the FEF bit according to ETH ForwardErrorFrames value */ + /* Set the FUF bit according to ETH ForwardUndersizedGoodFrames value */ + /* Set the RTC bit according to ETH ReceiveThresholdControl value */ + /* Set the OSF bit according to ETH SecondFrameOperate value */ + tmpreg |= (uint32_t)(dmainit.DropTCPIPChecksumErrorFrame | + dmainit.ReceiveStoreForward | + dmainit.FlushReceivedFrame | + dmainit.TransmitStoreForward | + dmainit.TransmitThresholdControl | + dmainit.ForwardErrorFrames | + dmainit.ForwardUndersizedGoodFrames | + dmainit.ReceiveThresholdControl | + dmainit.SecondFrameOperate); + + /* Write to ETHERNET DMAOMR */ + prvWriteDMAOMR( heth, tmpreg ); + + /*----------------------- ETHERNET DMABMR Configuration ------------------*/ + /* Set the AAL bit according to ETH AddressAlignedBeats value */ + /* Set the FB bit according to ETH FixedBurst value */ + /* Set the RPBL and 4*PBL bits according to ETH RxDMABurstLength value */ + /* Set the PBL and 4*PBL bits according to ETH TxDMABurstLength value */ + /* Set the Enhanced DMA descriptors bit according to ETH EnhancedDescriptorFormat value*/ + /* Set the DSL bit according to ETH DesciptorSkipLength value */ + /* Set the PR and DA bits according to ETH DMAArbitration value */ + heth->Instance->DMABMR = (uint32_t)(dmainit.AddressAlignedBeats | + dmainit.FixedBurst | + dmainit.RxDMABurstLength | /* !! if 4xPBL is selected for Tx or Rx it is applied for the other */ + dmainit.TxDMABurstLength | + dmainit.EnhancedDescriptorFormat | + (dmainit.DescriptorSkipLength << 2) | + dmainit.DMAArbitration | + ETH_DMABMR_USP); /* Enable use of separate PBL for Rx and Tx */ + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->DMABMR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->DMABMR = tmpreg; + + if(heth->Init.RxMode == ETH_RXINTERRUPT_MODE) + { + /* Enable the Ethernet Rx Interrupt */ + __HAL_ETH_DMA_ENABLE_IT(( heth ), ETH_DMA_IT_NIS | ETH_DMA_IT_R); + } + + /* Initialize MAC address in ethernet MAC */ + ETH_MACAddressConfig(heth, ETH_MAC_ADDRESS0, heth->Init.MACAddr); +} + +/** + * @brief Configures the selected MAC address. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param MacAddr: The MAC address to configure + * This parameter can be one of the following values: + * @arg ETH_MAC_Address0: MAC Address0 + * @arg ETH_MAC_Address1: MAC Address1 + * @arg ETH_MAC_Address2: MAC Address2 + * @arg ETH_MAC_Address3: MAC Address3 + * @param Addr: Pointer to MAC address buffer data (6 bytes) + * @retval HAL status + */ +static void ETH_MACAddressConfig(ETH_HandleTypeDef *heth, uint32_t MacAddr, uint8_t *Addr) +{ + uint32_t tmpreg; + + /* Check the parameters */ + assert_param( IS_ETH_MAC_ADDRESS0123( MacAddr ) ); + + /* Calculate the selected MAC address high register */ + tmpreg = 0x80000000ul | ( ( uint32_t )Addr[ 5 ] << 8) | (uint32_t)Addr[ 4 ]; + /* Load the selected MAC address high register */ + ( * ( __IO uint32_t * ) ( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + MacAddr ) ) ) = tmpreg; + /* Calculate the selected MAC address low register */ + tmpreg = ( ( uint32_t )Addr[ 3 ] << 24 ) | ( ( uint32_t )Addr[ 2 ] << 16 ) | ( ( uint32_t )Addr[ 1 ] << 8 ) | Addr[ 0 ]; + + /* Load the selected MAC address low register */ + ( * ( __IO uint32_t * ) ( ( uint32_t ) ( ETH_MAC_ADDR_LBASE + MacAddr ) ) ) = tmpreg; +} + +/** + * @brief Enables the MAC transmission. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_MACTransmissionEnable(ETH_HandleTypeDef *heth) +{ + uint32_t tmpreg = heth->Instance->MACCR | ETH_MACCR_TE; + + prvWriteMACCR( heth, tmpreg ); +} + +/** + * @brief Disables the MAC transmission. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_MACTransmissionDisable(ETH_HandleTypeDef *heth) +{ + uint32_t tmpreg = heth->Instance->MACCR & ~( ETH_MACCR_TE ); + + prvWriteMACCR( heth, tmpreg ); +} + +/** + * @brief Enables the MAC reception. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_MACReceptionEnable(ETH_HandleTypeDef *heth) +{ + __IO uint32_t tmpreg = heth->Instance->MACCR | ETH_MACCR_RE; + + prvWriteMACCR( heth, tmpreg ); +} + +/** + * @brief Disables the MAC reception. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_MACReceptionDisable(ETH_HandleTypeDef *heth) +{ + __IO uint32_t tmpreg = heth->Instance->MACCR & ~( ETH_MACCR_RE ); + + prvWriteMACCR( heth, tmpreg ); +} + +/** + * @brief Enables the DMA transmission. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_DMATransmissionEnable(ETH_HandleTypeDef *heth) +{ + /* Enable the DMA transmission */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR | ETH_DMAOMR_ST; + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @brief Disables the DMA transmission. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_DMATransmissionDisable(ETH_HandleTypeDef *heth) +{ + /* Disable the DMA transmission */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR & ~( ETH_DMAOMR_ST ); + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @brief Enables the DMA reception. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_DMAReceptionEnable(ETH_HandleTypeDef *heth) +{ + /* Enable the DMA reception */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR | ETH_DMAOMR_SR; + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @brief Disables the DMA reception. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_DMAReceptionDisable(ETH_HandleTypeDef *heth) +{ + /* Disable the DMA reception */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR & ~( ETH_DMAOMR_SR ); + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @brief Clears the ETHERNET transmit FIFO. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_FlushTransmitFIFO(ETH_HandleTypeDef *heth) +{ + /* Set the Flush Transmit FIFO bit */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR | ETH_DMAOMR_FTF; + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @} + */ + +#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx || STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx */ +#endif /* HAL_ETH_MODULE_ENABLED */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f4xx_hal_eth.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f4xx_hal_eth.h new file mode 100644 index 000000000..93b9caff0 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f4xx_hal_eth.h @@ -0,0 +1,6 @@ +/* + * The Ethernet header files for STM32F2, STM32F4 and STM32F7 have been merged to + * a single module that works for both parts: "stm32fxx_hal_eth" + */ + +#include "stm32fxx_hal_eth.h" diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f7xx_hal_eth.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f7xx_hal_eth.h new file mode 100644 index 000000000..93b9caff0 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32f7xx_hal_eth.h @@ -0,0 +1,6 @@ +/* + * The Ethernet header files for STM32F2, STM32F4 and STM32F7 have been merged to + * a single module that works for both parts: "stm32fxx_hal_eth" + */ + +#include "stm32fxx_hal_eth.h" diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.c new file mode 100644 index 000000000..c67ad1901 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.c @@ -0,0 +1,1800 @@ +/** + ****************************************************************************** + * @file stm32fxx_hal_eth.c + * @author MCD Application Team + * @version V1.3.2 + * @date 26-June-2015 + * @brief ETH HAL module driver. + * This file provides firmware functions to manage the following + * functionalities of the Ethernet (ETH) peripheral: + * + Initialization and de-initialization functions + * + IO operation functions + * + Peripheral Control functions + * + Peripheral State and Errors functions + * + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + (#)Declare a ETH_HandleTypeDef handle structure, for example: + ETH_HandleTypeDef heth; + + (#)Fill parameters of Init structure in heth handle + + (#)Call HAL_ETH_Init() API to initialize the Ethernet peripheral (MAC, DMA, ...) + + (#)Initialize the ETH low level resources through the HAL_ETH_MspInit() API: + (##) Enable the Ethernet interface clock using + (+++) __HAL_RCC_ETHMAC_CLK_ENABLE(); + (+++) __HAL_RCC_ETHMACTX_CLK_ENABLE(); + (+++) __HAL_RCC_ETHMACRX_CLK_ENABLE(); + + (##) Initialize the related GPIO clocks + (##) Configure Ethernet pin-out + (##) Configure Ethernet NVIC interrupt (IT mode) + + (#)Initialize Ethernet DMA Descriptors in chain mode and point to allocated buffers: + (##) HAL_ETH_DMATxDescListInit(); for Transmission process + (##) HAL_ETH_DMARxDescListInit(); for Reception process + + (#)Enable MAC and DMA transmission and reception: + (##) HAL_ETH_Start(); + + (#)Prepare ETH DMA TX Descriptors and give the hand to ETH DMA to transfer + the frame to MAC TX FIFO: + (##) HAL_ETH_TransmitFrame(); + + (#)Poll for a received frame in ETH RX DMA Descriptors and get received + frame parameters + (##) HAL_ETH_GetReceivedFrame(); (should be called into an infinite loop) + + (#) Get a received frame when an ETH RX interrupt occurs: + (##) HAL_ETH_GetReceivedFrame_IT(); (called in IT mode only) + + (#) Communicate with external PHY device: + (##) Read a specific register from the PHY + HAL_ETH_ReadPHYRegister(); + (##) Write data to a specific RHY register: + HAL_ETH_WritePHYRegister(); + + (#) Configure the Ethernet MAC after ETH peripheral initialization + HAL_ETH_ConfigMAC(); all MAC parameters should be filled. + + (#) Configure the Ethernet DMA after ETH peripheral initialization + HAL_ETH_ConfigDMA(); all DMA parameters should be filled. + + -@- The PTP protocol and the DMA descriptors ring mode are not supported + in this driver + + @endverbatim + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2015 STMicroelectronics

+ * + * 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. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#define __STM32_HAL_LEGACY 1 + +#if defined(STM32F7xx) + #include "stm32f7xx_hal.h" + #include "stm32f7xx_hal_def.h" + #define stm_is_F7 1 +#elif defined(STM32F407xx) || defined(STM32F417xx) || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) + #include "stm32f4xx_hal.h" + #include "stm32f4xx_hal_def.h" + #define stm_is_F4 1 +#elif defined(STM32F2xx) + #include "stm32f2xx_hal.h" + #include "stm32f2xx_hal_def.h" + #define stm_is_F2 1 +#else + #error For what part should this be compiled? +#endif + +#include "stm32fxx_hal_eth.h" + +/** @addtogroup STM32F4xx_HAL_Driver + * @{ + */ + +/** @defgroup ETH ETH + * @brief ETH HAL module driver + * @{ + */ + +#if !defined( ARRAY_SIZE ) + #define ARRAY_SIZE( x ) ( sizeof ( x ) / sizeof ( x )[ 0 ] ) +#endif + +#ifdef HAL_ETH_MODULE_ENABLED + +#if( stm_is_F2 != 0 || stm_is_F4 != 0 || stm_is_F7 ) + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/** @defgroup ETH_Private_Constants ETH Private Constants + * @{ + */ + +/** + * @} + */ +/* Private macro -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/** @defgroup ETH_Private_Functions ETH Private Functions + * @{ + */ +static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err); +static void ETH_MACAddressConfig(ETH_HandleTypeDef *heth, uint32_t MacAddr, uint8_t *Addr); +static void ETH_MACReceptionEnable(ETH_HandleTypeDef *heth); +static void ETH_MACReceptionDisable(ETH_HandleTypeDef *heth); +static void ETH_MACTransmissionEnable(ETH_HandleTypeDef *heth); +static void ETH_MACTransmissionDisable(ETH_HandleTypeDef *heth); +static void ETH_DMATransmissionEnable(ETH_HandleTypeDef *heth); +static void ETH_DMATransmissionDisable(ETH_HandleTypeDef *heth); +static void ETH_DMAReceptionEnable(ETH_HandleTypeDef *heth); +static void ETH_DMAReceptionDisable(ETH_HandleTypeDef *heth); +static void ETH_FlushTransmitFIFO(ETH_HandleTypeDef *heth); + +/** + * @} + */ +/* Private functions ---------------------------------------------------------*/ + +/** @defgroup ETH_Exported_Functions ETH Exported Functions + * @{ + */ + +/** @defgroup ETH_Exported_Functions_Group1 Initialization and de-initialization functions + * @brief Initialization and Configuration functions + * + @verbatim + =============================================================================== + ##### Initialization and de-initialization functions ##### + =============================================================================== + [..] This section provides functions allowing to: + (+) Initialize and configure the Ethernet peripheral + (+) De-initialize the Ethernet peripheral + + @endverbatim + * @{ + */ +extern void vMACBProbePhy ( void ); + +/** + * @brief Initializes the Ethernet MAC and DMA according to default + * parameters. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_Init(ETH_HandleTypeDef *heth) +{ + uint32_t tmpreg = 0; + uint32_t hclk = 60000000; + uint32_t err = ETH_SUCCESS; + + /* Check the ETH peripheral state */ + if( heth == NULL ) + { + return HAL_ERROR; + } + + /* Check parameters */ + assert_param(IS_ETH_AUTONEGOTIATION(heth->Init.AutoNegotiation)); + assert_param(IS_ETH_RX_MODE(heth->Init.RxMode)); + assert_param(IS_ETH_CHECKSUM_MODE(heth->Init.ChecksumMode)); + assert_param(IS_ETH_MEDIA_INTERFACE(heth->Init.MediaInterface)); + + if( heth->State == HAL_ETH_STATE_RESET ) + { + /* Init the low level hardware : GPIO, CLOCK, NVIC. */ + HAL_ETH_MspInit( heth ); + } + + /* Enable SYSCFG Clock */ + __HAL_RCC_SYSCFG_CLK_ENABLE(); + + /* Select MII or RMII Mode*/ + SYSCFG->PMC &= ~(SYSCFG_PMC_MII_RMII_SEL); + SYSCFG->PMC |= (uint32_t)heth->Init.MediaInterface; + + /* Ethernet Software reset */ + /* Set the SWR bit: resets all MAC subsystem internal registers and logic */ + /* After reset all the registers holds their respective reset values */ + /* Also enable EDFE: Enhanced descriptor format enable. */ + heth->Instance->DMABMR |= ETH_DMABMR_SR | ETH_DMABMR_EDE; + + /* Wait for software reset */ + while ((heth->Instance->DMABMR & ETH_DMABMR_SR) != (uint32_t)RESET) + { + /* If your program hangs here, please check the value of 'ipconfigUSE_RMII'. */ + } + + /*-------------------------------- MAC Initialization ----------------------*/ + /* Get the ETHERNET MACMIIAR value */ + tmpreg = heth->Instance->MACMIIAR; + /* Clear CSR Clock Range CR[2:0] bits */ + tmpreg &= ETH_MACMIIAR_CR_MASK; + + /* Get hclk frequency value (168,000,000) */ + hclk = HAL_RCC_GetHCLKFreq(); + + /* Set CR bits depending on hclk value */ + if( ( hclk >= 20000000 ) && ( hclk < 35000000 ) ) + { + /* CSR Clock Range between 20-35 MHz */ + tmpreg |= (uint32_t) ETH_MACMIIAR_CR_Div16; + } + else if( ( hclk >= 35000000 ) && ( hclk < 60000000 ) ) + { + /* CSR Clock Range between 35-60 MHz */ + tmpreg |= ( uint32_t ) ETH_MACMIIAR_CR_Div26; + } + else if((hclk >= 60000000 ) && ( hclk < 100000000 ) ) + { + /* CSR Clock Range between 60-100 MHz */ + tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div42; + } + else if((hclk >= 100000000 ) && ( hclk < 150000000)) + { + /* CSR Clock Range between 100-150 MHz */ + tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div62; + } + else /* ((hclk >= 150000000 ) && ( hclk <= 168000000)) */ + { + /* CSR Clock Range between 150-168 MHz */ + tmpreg |= (uint32_t)ETH_MACMIIAR_CR_Div102; + } + + /* Write to ETHERNET MAC MIIAR: Configure the ETHERNET CSR Clock Range */ + heth->Instance->MACMIIAR = (uint32_t)tmpreg; + + /* Initialise the MACB and set all PHY properties */ + vMACBProbePhy(); + + /* Config MAC and DMA */ + ETH_MACDMAConfig(heth, err); + + /* Set ETH HAL State to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief De-Initializes the ETH peripheral. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_DeInit(ETH_HandleTypeDef *heth) +{ + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* De-Init the low level hardware : GPIO, CLOCK, NVIC. */ + HAL_ETH_MspDeInit( heth ); + + /* Set ETH HAL state to Disabled */ + heth->State= HAL_ETH_STATE_RESET; + + /* Release Lock */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Initializes the DMA Tx descriptors in chain mode. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param DMATxDescTab: Pointer to the first Tx desc list + * @param TxBuff: Pointer to the first TxBuffer list + * @param TxBuffCount: Number of the used Tx desc in the list + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_DMATxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *pxDMATable, uint8_t *ucDataBuffer, uint32_t ulBufferCount) +{ + uint32_t i = 0; + ETH_DMADescTypeDef *pxDMADescriptor; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Set the TxDesc pointer with the first one of the pxDMATable list */ + heth->TxDesc = pxDMATable; + + /* Fill each DMA descriptor with the right values */ + for( i=0; i < ulBufferCount; i++ ) + { + /* Get the pointer on the ith member of the descriptor list */ + pxDMADescriptor = pxDMATable + i; + + /* Set Second Address Chained bit */ + pxDMADescriptor->Status = ETH_DMATXDESC_TCH; + + pxDMADescriptor->ControlBufferSize = 0; + + /* Set Buffer1 address pointer */ + if( ucDataBuffer != NULL ) + { + pxDMADescriptor->Buffer1Addr = ( uint32_t )( &ucDataBuffer[ i * ETH_TX_BUF_SIZE ] ); + } + else + { + /* Buffer space is not provided because it uses zero-copy transmissions. */ + pxDMADescriptor->Buffer1Addr = ( uint32_t )0u; + } + + if (heth->Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE) + { + /* Set the DMA Tx descriptors checksum insertion for TCP, UDP, and ICMP */ + pxDMADescriptor->Status |= ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL; + } + + /* Initialize the next descriptor with the Next Descriptor Polling Enable */ + if(i < ( ulBufferCount - 1 ) ) + { + /* Set next descriptor address register with next descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) ( pxDMATable + i + 1 ); + } + else + { + /* For last descriptor, set next descriptor address register equal to the first descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) pxDMATable; + } + } + + /* Set Transmit Descriptor List Address Register */ + heth->Instance->DMATDLAR = ( uint32_t ) pxDMATable; + + /* Set ETH HAL State to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Initializes the DMA Rx descriptors in chain mode. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param DMARxDescTab: Pointer to the first Rx desc list + * @param RxBuff: Pointer to the first RxBuffer list + * @param RxBuffCount: Number of the used Rx desc in the list + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_DMARxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *pxDMATable, uint8_t *ucDataBuffer, uint32_t ulBufferCount) +{ + uint32_t i = 0; + ETH_DMADescTypeDef *pxDMADescriptor; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Set the RxDesc pointer with the first one of the pxDMATable list */ + heth->RxDesc = pxDMATable; + + /* Fill each DMA descriptor with the right values */ + for(i=0; i < ulBufferCount; i++) + { + /* Get the pointer on the ith member of the descriptor list */ + pxDMADescriptor = pxDMATable+i; + + /* Set Own bit of the Rx descriptor Status */ + pxDMADescriptor->Status = ETH_DMARXDESC_OWN; + + /* Set Buffer1 size and Second Address Chained bit */ + pxDMADescriptor->ControlBufferSize = ETH_DMARXDESC_RCH | ETH_RX_BUF_SIZE; + + /* Set Buffer1 address pointer */ + if( ucDataBuffer != NULL ) + { + pxDMADescriptor->Buffer1Addr = ( uint32_t )( &ucDataBuffer[ i * ETH_RX_BUF_SIZE ] ); + } + else + { + /* Buffer space is not provided because it uses zero-copy reception. */ + pxDMADescriptor->Buffer1Addr = ( uint32_t )0u; + } + + if( heth->Init.RxMode == ETH_RXINTERRUPT_MODE ) + { + /* Enable Ethernet DMA Rx Descriptor interrupt */ + pxDMADescriptor->ControlBufferSize &= ~ETH_DMARXDESC_DIC; + } + + /* Initialize the next descriptor with the Next Descriptor Polling Enable */ + if(i < (ulBufferCount-1)) + { + /* Set next descriptor address register with next descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = (uint32_t)(pxDMATable+i+1); + } + else + { + /* For last descriptor, set next descriptor address register equal to the first descriptor base address */ + pxDMADescriptor->Buffer2NextDescAddr = ( uint32_t ) pxDMATable; + } + } + + /* Set Receive Descriptor List Address Register */ + heth->Instance->DMARDLAR = ( uint32_t ) pxDMATable; + + /* Set ETH HAL State to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Initializes the ETH MSP. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_MspInit(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_MspInit could be implemented in the user file + */ +} + +/** + * @brief DeInitializes ETH MSP. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_MspDeInit could be implemented in the user file + */ +} + +/** + * @} + */ + +/** @defgroup ETH_Exported_Functions_Group2 IO operation functions + * @brief Data transfers functions + * + @verbatim + ============================================================================== + ##### IO operation functions ##### + ============================================================================== + [..] This section provides functions allowing to: + (+) Transmit a frame + HAL_ETH_TransmitFrame(); + (+) Receive a frame + HAL_ETH_GetReceivedFrame(); + HAL_ETH_GetReceivedFrame_IT(); + (+) Read from an External PHY register + HAL_ETH_ReadPHYRegister(); + (+) Write to an External PHY register + HAL_ETH_WritePHYRegister(); + + @endverbatim + + * @{ + */ + +/** + * @brief Sends an Ethernet frame. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param FrameLength: Amount of data to be sent + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_TransmitFrame(ETH_HandleTypeDef *heth, uint32_t FrameLength) +{ + uint32_t bufcount = 0, size = 0, i = 0; + __IO ETH_DMADescTypeDef *pxDmaTxDesc = heth->TxDesc; + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + if( FrameLength == 0 ) + { + /* Set ETH HAL state to READY */ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + return HAL_ERROR; + } + + /* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */ + if( ( pxDmaTxDesc->Status & ETH_DMATXDESC_OWN ) != ( uint32_t ) RESET ) + { + /* OWN bit set */ + heth->State = HAL_ETH_STATE_BUSY_TX; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + return HAL_ERROR; + } + + /* Get the number of needed Tx buffers for the current frame, rounding up. */ + bufcount = ( FrameLength + ETH_TX_BUF_SIZE - 1 ) / ETH_TX_BUF_SIZE; + + if (bufcount == 1) + { + /* Set LAST and FIRST segment */ + pxDmaTxDesc->Status |= ETH_DMATXDESC_FS | ETH_DMATXDESC_LS; + /* Set frame size */ + pxDmaTxDesc->ControlBufferSize = ( FrameLength & ETH_DMATXDESC_TBS1 ); + /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ + pxDmaTxDesc->Status |= ETH_DMATXDESC_OWN; + /* Point to next descriptor */ + heth->TxDesc = ( ETH_DMADescTypeDef * ) ( heth->TxDesc->Buffer2NextDescAddr ); + } + else + { + for( i = 0; i < bufcount; i++ ) + { + /* Clear FIRST and LAST segment bits */ + uint32_t ulStatus = heth->TxDesc->Status & ~( ETH_DMATXDESC_FS | ETH_DMATXDESC_LS ); + + if( i == 0 ) + { + /* Setting the first segment bit */ + heth->TxDesc->Status = ulStatus | ETH_DMATXDESC_FS; + } + + /* Program size */ + if (i < (bufcount-1)) + { + heth->TxDesc->ControlBufferSize = (ETH_TX_BUF_SIZE & ETH_DMATXDESC_TBS1); + } + else + { + /* Setting the last segment bit */ + heth->TxDesc->Status = ulStatus | ETH_DMATXDESC_LS; + size = FrameLength - (bufcount-1)*ETH_TX_BUF_SIZE; + heth->TxDesc->ControlBufferSize = (size & ETH_DMATXDESC_TBS1); + } + + /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */ + heth->TxDesc->Status |= ETH_DMATXDESC_OWN; + /* point to next descriptor */ + heth->TxDesc = (ETH_DMADescTypeDef *)( heth->TxDesc->Buffer2NextDescAddr ); + } + } + + __DSB(); + + /* When Tx Buffer unavailable flag is set: clear it and resume transmission */ + if( ( heth->Instance->DMASR & ETH_DMASR_TBUS ) != ( uint32_t )RESET ) + { + heth->Instance->DMACHTDR = ( uint32_t )pxDmaTxDesc; + + /* Clear TBUS ETHERNET DMA flag */ + heth->Instance->DMASR = ETH_DMASR_TBUS; + /* Resume DMA transmission*/ + heth->Instance->DMATPDR = 0; + } + + /* Set ETH HAL State to Ready */ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Checks for received frames. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_GetReceivedFrame_IT( ETH_HandleTypeDef *heth ) +{ + return HAL_ETH_GetReceivedFrame( heth ); +} + +HAL_StatusTypeDef HAL_ETH_GetReceivedFrame( ETH_HandleTypeDef *heth ) +{ +uint32_t ulCounter = 0; +ETH_DMADescTypeDef *pxDescriptor = heth->RxDesc; +HAL_StatusTypeDef xResult = HAL_ERROR; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Check the ETH state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Scan descriptors owned by CPU */ + while( ( ( pxDescriptor->Status & ETH_DMARXDESC_OWN ) == 0ul ) && ( ulCounter < ETH_RXBUFNB ) ) + { + uint32_t ulStatus = pxDescriptor->Status; + + /* Just for security. */ + ulCounter++; + + if( ( ulStatus & ( ETH_DMARXDESC_FS | ETH_DMARXDESC_LS ) ) == ( uint32_t )ETH_DMARXDESC_FS ) + { + /* First segment in frame, but not the last. */ + heth->RxFrameInfos.FSRxDesc = pxDescriptor; + heth->RxFrameInfos.LSRxDesc = ( ETH_DMADescTypeDef *)NULL; + heth->RxFrameInfos.SegCount = 1; + /* Point to next descriptor. */ + pxDescriptor = (ETH_DMADescTypeDef*) (pxDescriptor->Buffer2NextDescAddr); + heth->RxDesc = pxDescriptor; + } + else if( ( ulStatus & ( ETH_DMARXDESC_LS | ETH_DMARXDESC_FS ) ) == 0ul ) + { + /* This is an intermediate segment, not first, not last. */ + /* Increment segment count. */ + heth->RxFrameInfos.SegCount++; + /* Move to the next descriptor. */ + pxDescriptor = ( ETH_DMADescTypeDef * ) ( pxDescriptor->Buffer2NextDescAddr ); + heth->RxDesc = pxDescriptor; + } + /* Must be a last segment */ + else + { + /* This is the last segment. */ + /* Check if last segment is first segment: one segment contains the frame */ + if( heth->RxFrameInfos.SegCount == 0 ) + { + /* Remember the first segment. */ + heth->RxFrameInfos.FSRxDesc = pxDescriptor; + } + + /* Increment segment count */ + heth->RxFrameInfos.SegCount++; + + /* Remember the last segment. */ + heth->RxFrameInfos.LSRxDesc = pxDescriptor; + + /* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */ + heth->RxFrameInfos.length = + ( ( ulStatus & ETH_DMARXDESC_FL ) >> ETH_DMARXDESC_FRAMELENGTHSHIFT ) - 4; + + /* Get the address of the buffer start address */ + heth->RxFrameInfos.buffer = heth->RxFrameInfos.FSRxDesc->Buffer1Addr; + + /* Point to next descriptor */ + heth->RxDesc = ( ETH_DMADescTypeDef * ) pxDescriptor->Buffer2NextDescAddr; + + /* Return OK status: a packet was received. */ + xResult = HAL_OK; + break; + } + } + + /* Set ETH HAL State to Ready */ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return xResult; +} + +#define ETH_DMA_ALL_INTS \ + ( ETH_DMA_IT_TST | ETH_DMA_IT_PMT | ETH_DMA_IT_MMC | ETH_DMA_IT_NIS | ETH_DMA_IT_AIS | ETH_DMA_IT_ER | \ + ETH_DMA_IT_FBE | ETH_DMA_IT_ET | ETH_DMA_IT_RWT | ETH_DMA_IT_RPS | ETH_DMA_IT_RBU | ETH_DMA_IT_R | \ + ETH_DMA_IT_TU | ETH_DMA_IT_RO | ETH_DMA_IT_TJT | ETH_DMA_IT_TPS | ETH_DMA_IT_T ) + +//#define ETH_DMA_ALL_INTS ETH_DMA_IT_RBU | ETH_DMA_FLAG_T | ETH_DMA_FLAG_AIS + +#define INT_MASK ( ( uint32_t ) ~ ( ETH_DMA_IT_TBU ) ) +void HAL_ETH_IRQHandler(ETH_HandleTypeDef *heth) +{ + uint32_t dmasr; + + dmasr = heth->Instance->DMASR & ETH_DMA_ALL_INTS; + heth->Instance->DMASR = dmasr; + + /* Frame received */ + if( ( dmasr & ( ETH_DMA_FLAG_R | ETH_DMA_IT_RBU ) ) != 0 ) + { + /* Receive complete callback */ + HAL_ETH_RxCpltCallback( heth ); + } + /* Frame transmitted */ + if( ( dmasr & ( ETH_DMA_FLAG_T ) ) != 0 ) + { + /* Transfer complete callback */ + HAL_ETH_TxCpltCallback( heth ); + } + + /* ETH DMA Error */ + if( ( dmasr & ( ETH_DMA_FLAG_AIS ) ) != 0 ) + { + /* Ethernet Error callback */ + HAL_ETH_ErrorCallback( heth ); + } +} + +/** + * @brief Tx Transfer completed callbacks. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Rx Transfer completed callbacks. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Ethernet transfer error callbacks + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +__weak void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth) +{ + /* NOTE : This function Should not be modified, when the callback is needed, + the HAL_ETH_TxCpltCallback could be implemented in the user file + */ +} + +/** + * @brief Reads a PHY register + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param PHYReg: PHY register address, is the index of one of the 32 PHY register. + * This parameter can be one of the following values: + * PHY_BCR: Transceiver Basic Control Register, + * PHY_BSR: Transceiver Basic Status Register. + * More PHY register could be read depending on the used PHY + * @param RegValue: PHY register value + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_ReadPHYRegister(ETH_HandleTypeDef *heth, uint16_t PHYReg, uint32_t *RegValue) +{ +uint32_t tmpreg = 0; +uint32_t tickstart = 0; +HAL_StatusTypeDef xResult; + + /* Check parameters */ + assert_param(IS_ETH_PHY_ADDRESS(heth->Init.PhyAddress)); + + /* Check the ETH peripheral state */ + if( heth->State == HAL_ETH_STATE_BUSY_RD ) + { + xResult = HAL_BUSY; + } + else + { + __HAL_LOCK( heth ); + + /* Set ETH HAL State to BUSY_RD */ + heth->State = HAL_ETH_STATE_BUSY_RD; + + /* Get the ETHERNET MACMIIAR value */ + tmpreg = heth->Instance->MACMIIAR; + + /* Keep only the CSR Clock Range CR[2:0] bits value */ + tmpreg &= ~ETH_MACMIIAR_CR_MASK; + + /* Prepare the MII address register value */ + tmpreg |= ( ( ( uint32_t )heth->Init.PhyAddress << 11) & ETH_MACMIIAR_PA ); /* Set the PHY device address */ + tmpreg |= ( ( ( uint32_t )PHYReg << 6 ) & ETH_MACMIIAR_MR ); /* Set the PHY register address */ + tmpreg &= ~ETH_MACMIIAR_MW; /* Set the read mode */ + tmpreg |= ETH_MACMIIAR_MB; /* Set the MII Busy bit */ + + /* Write the result value into the MII Address register */ + heth->Instance->MACMIIAR = tmpreg; + + /* Get tick */ + tickstart = HAL_GetTick(); + + /* Check for the Busy flag */ + while( 1 ) + { + tmpreg = heth->Instance->MACMIIAR; + + if( ( tmpreg & ETH_MACMIIAR_MB ) == 0ul ) + { + /* Get MACMIIDR value */ + *RegValue = ( uint32_t ) heth->Instance->MACMIIDR; + xResult = HAL_OK; + break; + } + /* Check for the Timeout */ + if( ( HAL_GetTick( ) - tickstart ) > PHY_READ_TO ) + { + xResult = HAL_TIMEOUT; + break; + } + + } + + /* Set ETH HAL State to READY */ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + } + + /* Return function status */ + return xResult; +} + +/** + * @brief Writes to a PHY register. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param PHYReg: PHY register address, is the index of one of the 32 PHY register. + * This parameter can be one of the following values: + * PHY_BCR: Transceiver Control Register. + * More PHY register could be written depending on the used PHY + * @param RegValue: the value to write + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_WritePHYRegister(ETH_HandleTypeDef *heth, uint16_t PHYReg, uint32_t RegValue) +{ +uint32_t tmpreg = 0; +uint32_t tickstart = 0; +HAL_StatusTypeDef xResult; + + /* Check parameters */ + assert_param( IS_ETH_PHY_ADDRESS( heth->Init.PhyAddress ) ); + + /* Check the ETH peripheral state */ + if( heth->State == HAL_ETH_STATE_BUSY_WR ) + { + xResult = HAL_BUSY; + } + else + { + __HAL_LOCK( heth ); + + /* Set ETH HAL State to BUSY_WR */ + heth->State = HAL_ETH_STATE_BUSY_WR; + + /* Get the ETHERNET MACMIIAR value */ + tmpreg = heth->Instance->MACMIIAR; + + /* Keep only the CSR Clock Range CR[2:0] bits value */ + tmpreg &= ~ETH_MACMIIAR_CR_MASK; + + /* Prepare the MII register address value */ + tmpreg |= ( ( ( uint32_t ) heth->Init.PhyAddress << 11 ) & ETH_MACMIIAR_PA ); /* Set the PHY device address */ + tmpreg |= ( ( ( uint32_t ) PHYReg << 6 ) & ETH_MACMIIAR_MR ); /* Set the PHY register address */ + tmpreg |= ETH_MACMIIAR_MW; /* Set the write mode */ + tmpreg |= ETH_MACMIIAR_MB; /* Set the MII Busy bit */ + + /* Give the value to the MII data register */ + heth->Instance->MACMIIDR = ( uint16_t ) RegValue; + + /* Write the result value into the MII Address register */ + heth->Instance->MACMIIAR = tmpreg; + + /* Get tick */ + tickstart = HAL_GetTick(); + + /* Check for the Busy flag */ + while( 1 ) + { + tmpreg = heth->Instance->MACMIIAR; + + if( ( tmpreg & ETH_MACMIIAR_MB ) == 0ul ) + { + xResult = HAL_OK; + break; + } + /* Check for the Timeout */ + if( ( HAL_GetTick( ) - tickstart ) > PHY_WRITE_TO ) + { + xResult = HAL_TIMEOUT; + break; + } + } + + /* Set ETH HAL State to READY */ + heth->State = HAL_ETH_STATE_READY; + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + } + + /* Return function status */ + return xResult; +} + +/** + * @} + */ + +/** @defgroup ETH_Exported_Functions_Group3 Peripheral Control functions + * @brief Peripheral Control functions + * +@verbatim + =============================================================================== + ##### Peripheral Control functions ##### + =============================================================================== + [..] This section provides functions allowing to: + (+) Enable MAC and DMA transmission and reception. + HAL_ETH_Start(); + (+) Disable MAC and DMA transmission and reception. + HAL_ETH_Stop(); + (+) Set the MAC configuration in runtime mode + HAL_ETH_ConfigMAC(); + (+) Set the DMA configuration in runtime mode + HAL_ETH_ConfigDMA(); + +@endverbatim + * @{ + */ + + /** + * @brief Enables Ethernet MAC and DMA reception/transmission + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_Start( ETH_HandleTypeDef *heth ) +{ + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Enable transmit state machine of the MAC for transmission on the MII */ + ETH_MACTransmissionEnable( heth ); + + /* Enable receive state machine of the MAC for reception from the MII */ + ETH_MACReceptionEnable( heth ); + + /* Flush Transmit FIFO */ + ETH_FlushTransmitFIFO( heth ); + + /* Start DMA transmission */ + ETH_DMATransmissionEnable( heth ); + + /* Start DMA reception */ + ETH_DMAReceptionEnable( heth ); + + /* Set the ETH state to READY*/ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Stop Ethernet MAC and DMA reception/transmission + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_Stop(ETH_HandleTypeDef *heth) +{ + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State = HAL_ETH_STATE_BUSY; + + /* Stop DMA transmission */ + ETH_DMATransmissionDisable( heth ); + + /* Stop DMA reception */ + ETH_DMAReceptionDisable( heth ); + + /* Disable receive state machine of the MAC for reception from the MII */ + ETH_MACReceptionDisable( heth ); + + /* Flush Transmit FIFO */ + ETH_FlushTransmitFIFO( heth ); + + /* Disable transmit state machine of the MAC for transmission on the MII */ + ETH_MACTransmissionDisable( heth ); + + /* Set the ETH state*/ + heth->State = HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +static void prvWriteMACFCR( ETH_HandleTypeDef *heth, uint32_t ulValue) +{ + /* Enable the MAC transmission */ + heth->Instance->MACFCR = ulValue; + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles. + Read it back, wait a ms and */ + ( void ) heth->Instance->MACFCR; + + HAL_Delay( ETH_REG_WRITE_DELAY ); + + heth->Instance->MACFCR = ulValue; +} + +static void prvWriteDMAOMR( ETH_HandleTypeDef *heth, uint32_t ulValue) +{ + /* Enable the MAC transmission */ + heth->Instance->DMAOMR = ulValue; + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles. + Read it back, wait a ms and */ + ( void ) heth->Instance->DMAOMR; + + HAL_Delay( ETH_REG_WRITE_DELAY ); + + heth->Instance->DMAOMR = ulValue; +} + +static void prvWriteMACCR( ETH_HandleTypeDef *heth, uint32_t ulValue) +{ + /* Enable the MAC transmission */ + heth->Instance->MACCR = ulValue; + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles. + Read it back, wait a ms and */ + ( void ) heth->Instance->MACCR; + + HAL_Delay( ETH_REG_WRITE_DELAY ); + + heth->Instance->MACCR = ulValue; +} + +/** + * @brief Set ETH MAC Configuration. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param macconf: MAC Configuration structure + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_ConfigMAC(ETH_HandleTypeDef *heth, ETH_MACInitTypeDef *macconf) +{ + uint32_t tmpreg = 0; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State= HAL_ETH_STATE_BUSY; + + assert_param(IS_ETH_SPEED(heth->Init.Speed)); + assert_param(IS_ETH_DUPLEX_MODE(heth->Init.DuplexMode)); + + if (macconf != NULL) + { + /* Check the parameters */ + assert_param(IS_ETH_WATCHDOG(macconf->Watchdog)); + assert_param(IS_ETH_JABBER(macconf->Jabber)); + assert_param(IS_ETH_INTER_FRAME_GAP(macconf->InterFrameGap)); + assert_param(IS_ETH_CARRIER_SENSE(macconf->CarrierSense)); + assert_param(IS_ETH_RECEIVE_OWN(macconf->ReceiveOwn)); + assert_param(IS_ETH_LOOPBACK_MODE(macconf->LoopbackMode)); + assert_param(IS_ETH_CHECKSUM_OFFLOAD(macconf->ChecksumOffload)); + assert_param(IS_ETH_RETRY_TRANSMISSION(macconf->RetryTransmission)); + assert_param(IS_ETH_AUTOMATIC_PADCRC_STRIP(macconf->AutomaticPadCRCStrip)); + assert_param(IS_ETH_BACKOFF_LIMIT(macconf->BackOffLimit)); + assert_param(IS_ETH_DEFERRAL_CHECK(macconf->DeferralCheck)); + assert_param(IS_ETH_RECEIVE_ALL(macconf->ReceiveAll)); + assert_param(IS_ETH_SOURCE_ADDR_FILTER(macconf->SourceAddrFilter)); + assert_param(IS_ETH_CONTROL_FRAMES(macconf->PassControlFrames)); + assert_param(IS_ETH_BROADCAST_FRAMES_RECEPTION(macconf->BroadcastFramesReception)); + assert_param(IS_ETH_DESTINATION_ADDR_FILTER(macconf->DestinationAddrFilter)); + assert_param(IS_ETH_PROMISCUOUS_MODE(macconf->PromiscuousMode)); + assert_param(IS_ETH_MULTICAST_FRAMES_FILTER(macconf->MulticastFramesFilter)); + assert_param(IS_ETH_UNICAST_FRAMES_FILTER(macconf->UnicastFramesFilter)); + assert_param(IS_ETH_PAUSE_TIME(macconf->PauseTime)); + assert_param(IS_ETH_ZEROQUANTA_PAUSE(macconf->ZeroQuantaPause)); + assert_param(IS_ETH_PAUSE_LOW_THRESHOLD(macconf->PauseLowThreshold)); + assert_param(IS_ETH_UNICAST_PAUSE_FRAME_DETECT(macconf->UnicastPauseFrameDetect)); + assert_param(IS_ETH_RECEIVE_FLOWCONTROL(macconf->ReceiveFlowControl)); + assert_param(IS_ETH_TRANSMIT_FLOWCONTROL(macconf->TransmitFlowControl)); + assert_param(IS_ETH_VLAN_TAG_COMPARISON(macconf->VLANTagComparison)); + assert_param(IS_ETH_VLAN_TAG_IDENTIFIER(macconf->VLANTagIdentifier)); + + /*------------------------ ETHERNET MACCR Configuration --------------------*/ + /* Get the ETHERNET MACCR value */ + tmpreg = heth->Instance->MACCR; + /* Clear WD, PCE, PS, TE and RE bits */ + tmpreg &= ETH_MACCR_CLEAR_MASK; + + tmpreg |= (uint32_t)( + macconf->Watchdog | + macconf->Jabber | + macconf->InterFrameGap | + macconf->CarrierSense | + heth->Init.Speed | + macconf->ReceiveOwn | + macconf->LoopbackMode | + heth->Init.DuplexMode | + macconf->ChecksumOffload | + macconf->RetryTransmission | + macconf->AutomaticPadCRCStrip | + macconf->BackOffLimit | + macconf->DeferralCheck); + + /* Write to ETHERNET MACCR */ + prvWriteMACCR( heth, tmpreg ); + + /*----------------------- ETHERNET MACFFR Configuration --------------------*/ + /* Write to ETHERNET MACFFR */ + heth->Instance->MACFFR = (uint32_t)( + macconf->ReceiveAll | + macconf->SourceAddrFilter | + macconf->PassControlFrames | + macconf->BroadcastFramesReception | + macconf->DestinationAddrFilter | + macconf->PromiscuousMode | + macconf->MulticastFramesFilter | + macconf->UnicastFramesFilter); + + /* Wait until the write operation will be taken into account : + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->MACFFR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->MACFFR = tmpreg; + + /*--------------- ETHERNET MACHTHR and MACHTLR Configuration ---------------*/ + /* Write to ETHERNET MACHTHR */ + heth->Instance->MACHTHR = (uint32_t)macconf->HashTableHigh; + + /* Write to ETHERNET MACHTLR */ + heth->Instance->MACHTLR = (uint32_t)macconf->HashTableLow; + /*----------------------- ETHERNET MACFCR Configuration --------------------*/ + + /* Get the ETHERNET MACFCR value */ + tmpreg = heth->Instance->MACFCR; + /* Clear xx bits */ + tmpreg &= ETH_MACFCR_CLEAR_MASK; + + tmpreg |= (uint32_t)(( + macconf->PauseTime << 16) | + macconf->ZeroQuantaPause | + macconf->PauseLowThreshold | + macconf->UnicastPauseFrameDetect | + macconf->ReceiveFlowControl | + macconf->TransmitFlowControl); + + /* Write to ETHERNET MACFCR */ + prvWriteMACFCR( heth, tmpreg ); + + /*----------------------- ETHERNET MACVLANTR Configuration -----------------*/ + heth->Instance->MACVLANTR = (uint32_t)(macconf->VLANTagComparison | + macconf->VLANTagIdentifier); + + /* Wait until the write operation will be taken into account : + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->MACVLANTR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->MACVLANTR = tmpreg; + } + else /* macconf == NULL : here we just configure Speed and Duplex mode */ + { + /*------------------------ ETHERNET MACCR Configuration --------------------*/ + /* Get the ETHERNET MACCR value */ + tmpreg = heth->Instance->MACCR; + + /* Clear FES and DM bits */ + tmpreg &= ~((uint32_t)0x00004800); + + tmpreg |= (uint32_t)(heth->Init.Speed | heth->Init.DuplexMode); + + /* Write to ETHERNET MACCR */ + prvWriteMACCR( heth, tmpreg ); + } + + /* Set the ETH state to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @brief Sets ETH DMA Configuration. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param dmaconf: DMA Configuration structure + * @retval HAL status + */ +HAL_StatusTypeDef HAL_ETH_ConfigDMA(ETH_HandleTypeDef *heth, ETH_DMAInitTypeDef *dmaconf) +{ + uint32_t tmpreg = 0; + + /* Process Locked */ + __HAL_LOCK( heth ); + + /* Set the ETH peripheral state to BUSY */ + heth->State= HAL_ETH_STATE_BUSY; + + /* Check parameters */ + assert_param(IS_ETH_DROP_TCPIP_CHECKSUM_FRAME(dmaconf->DropTCPIPChecksumErrorFrame)); + assert_param(IS_ETH_RECEIVE_STORE_FORWARD(dmaconf->ReceiveStoreForward)); + assert_param(IS_ETH_FLUSH_RECEIVE_FRAME(dmaconf->FlushReceivedFrame)); + assert_param(IS_ETH_TRANSMIT_STORE_FORWARD(dmaconf->TransmitStoreForward)); + assert_param(IS_ETH_TRANSMIT_THRESHOLD_CONTROL(dmaconf->TransmitThresholdControl)); + assert_param(IS_ETH_FORWARD_ERROR_FRAMES(dmaconf->ForwardErrorFrames)); + assert_param(IS_ETH_FORWARD_UNDERSIZED_GOOD_FRAMES(dmaconf->ForwardUndersizedGoodFrames)); + assert_param(IS_ETH_RECEIVE_THRESHOLD_CONTROL(dmaconf->ReceiveThresholdControl)); + assert_param(IS_ETH_SECOND_FRAME_OPERATE(dmaconf->SecondFrameOperate)); + assert_param(IS_ETH_ADDRESS_ALIGNED_BEATS(dmaconf->AddressAlignedBeats)); + assert_param(IS_ETH_FIXED_BURST(dmaconf->FixedBurst)); + assert_param(IS_ETH_RXDMA_BURST_LENGTH(dmaconf->RxDMABurstLength)); + assert_param(IS_ETH_TXDMA_BURST_LENGTH(dmaconf->TxDMABurstLength)); + assert_param(IS_ETH_ENHANCED_DESCRIPTOR_FORMAT(dmaconf->EnhancedDescriptorFormat)); + assert_param(IS_ETH_DMA_DESC_SKIP_LENGTH(dmaconf->DescriptorSkipLength)); + assert_param(IS_ETH_DMA_ARBITRATION_ROUNDROBIN_RXTX(dmaconf->DMAArbitration)); + + /*----------------------- ETHERNET DMAOMR Configuration --------------------*/ + /* Get the ETHERNET DMAOMR value */ + tmpreg = heth->Instance->DMAOMR; + /* Clear xx bits */ + tmpreg &= ETH_DMAOMR_CLEAR_MASK; + + tmpreg |= (uint32_t)( + dmaconf->DropTCPIPChecksumErrorFrame | + dmaconf->ReceiveStoreForward | + dmaconf->FlushReceivedFrame | + dmaconf->TransmitStoreForward | + dmaconf->TransmitThresholdControl | + dmaconf->ForwardErrorFrames | + dmaconf->ForwardUndersizedGoodFrames | + dmaconf->ReceiveThresholdControl | + dmaconf->SecondFrameOperate); + + /* Write to ETHERNET DMAOMR */ + prvWriteDMAOMR( heth, tmpreg ); + + /*----------------------- ETHERNET DMABMR Configuration --------------------*/ + heth->Instance->DMABMR = (uint32_t)(dmaconf->AddressAlignedBeats | + dmaconf->FixedBurst | + dmaconf->RxDMABurstLength | /* !! if 4xPBL is selected for Tx or Rx it is applied for the other */ + dmaconf->TxDMABurstLength | + dmaconf->EnhancedDescriptorFormat | + (dmaconf->DescriptorSkipLength << 2) | + dmaconf->DMAArbitration | + ETH_DMABMR_USP); /* Enable use of separate PBL for Rx and Tx */ + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->DMABMR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->DMABMR = tmpreg; + + /* Set the ETH state to Ready */ + heth->State= HAL_ETH_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK( heth ); + + /* Return function status */ + return HAL_OK; +} + +/** + * @} + */ + +/** @defgroup ETH_Exported_Functions_Group4 Peripheral State functions + * @brief Peripheral State functions + * + @verbatim + =============================================================================== + ##### Peripheral State functions ##### + =============================================================================== + [..] + This subsection permits to get in run-time the status of the peripheral + and the data flow. + (+) Get the ETH handle state: + HAL_ETH_GetState(); + + + @endverbatim + * @{ + */ + +/** + * @brief Return the ETH HAL state + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval HAL state + */ +HAL_ETH_StateTypeDef HAL_ETH_GetState(ETH_HandleTypeDef *heth) +{ + /* Return ETH state */ + return heth->State; +} + +/** + * @} + */ + +/** + * @} + */ + +/** @addtogroup ETH_Private_Functions + * @{ + */ + +/** + * @brief Configures Ethernet MAC and DMA with default parameters. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param err: Ethernet Init error + * @retval HAL status + */ +static void ETH_MACDMAConfig(ETH_HandleTypeDef *heth, uint32_t err) +{ + ETH_MACInitTypeDef macinit; + ETH_DMAInitTypeDef dmainit; + uint32_t tmpreg = 0; + + if (err != ETH_SUCCESS) /* Auto-negotiation failed */ + { + /* Set Ethernet duplex mode to Full-duplex */ + heth->Init.DuplexMode = ETH_MODE_FULLDUPLEX; + + /* Set Ethernet speed to 100M */ + heth->Init.Speed = ETH_SPEED_100M; + } + + /* Ethernet MAC default initialization **************************************/ + macinit.Watchdog = ETH_WATCHDOG_ENABLE; + macinit.Jabber = ETH_JABBER_ENABLE; + macinit.InterFrameGap = ETH_INTERFRAMEGAP_96BIT; + macinit.CarrierSense = ETH_CARRIERSENCE_ENABLE; + macinit.ReceiveOwn = ETH_RECEIVEOWN_ENABLE; + macinit.LoopbackMode = ETH_LOOPBACKMODE_DISABLE; + if(heth->Init.ChecksumMode == ETH_CHECKSUM_BY_HARDWARE) + { + macinit.ChecksumOffload = ETH_CHECKSUMOFFLAOD_ENABLE; + } + else + { + macinit.ChecksumOffload = ETH_CHECKSUMOFFLAOD_DISABLE; + } + macinit.RetryTransmission = ETH_RETRYTRANSMISSION_DISABLE; + macinit.AutomaticPadCRCStrip = ETH_AUTOMATICPADCRCSTRIP_DISABLE; + macinit.BackOffLimit = ETH_BACKOFFLIMIT_10; + macinit.DeferralCheck = ETH_DEFFERRALCHECK_DISABLE; + macinit.ReceiveAll = ETH_RECEIVEAll_DISABLE; + macinit.SourceAddrFilter = ETH_SOURCEADDRFILTER_DISABLE; + macinit.PassControlFrames = ETH_PASSCONTROLFRAMES_BLOCKALL; + macinit.BroadcastFramesReception = ETH_BROADCASTFRAMESRECEPTION_ENABLE; + macinit.DestinationAddrFilter = ETH_DESTINATIONADDRFILTER_NORMAL; + macinit.PromiscuousMode = ETH_PROMISCUOUS_MODE_DISABLE; + macinit.MulticastFramesFilter = ETH_MULTICASTFRAMESFILTER_PERFECT; + macinit.UnicastFramesFilter = ETH_UNICASTFRAMESFILTER_PERFECT; + macinit.HashTableHigh = 0x0; + macinit.HashTableLow = 0x0; + macinit.PauseTime = 0x0; + macinit.ZeroQuantaPause = ETH_ZEROQUANTAPAUSE_DISABLE; + macinit.PauseLowThreshold = ETH_PAUSELOWTHRESHOLD_MINUS4; + macinit.UnicastPauseFrameDetect = ETH_UNICASTPAUSEFRAMEDETECT_DISABLE; + macinit.ReceiveFlowControl = ETH_RECEIVEFLOWCONTROL_DISABLE; + macinit.TransmitFlowControl = ETH_TRANSMITFLOWCONTROL_DISABLE; + macinit.VLANTagComparison = ETH_VLANTAGCOMPARISON_16BIT; + macinit.VLANTagIdentifier = 0x0; + + /*------------------------ ETHERNET MACCR Configuration --------------------*/ + /* Get the ETHERNET MACCR value */ + tmpreg = heth->Instance->MACCR; + /* Clear WD, PCE, PS, TE and RE bits */ + tmpreg &= ETH_MACCR_CLEAR_MASK; + /* Set the WD bit according to ETH Watchdog value */ + /* Set the JD: bit according to ETH Jabber value */ + /* Set the IFG bit according to ETH InterFrameGap value */ + /* Set the DCRS bit according to ETH CarrierSense value */ + /* Set the FES bit according to ETH Speed value */ + /* Set the DO bit according to ETH ReceiveOwn value */ + /* Set the LM bit according to ETH LoopbackMode value */ + /* Set the DM bit according to ETH Mode value */ + /* Set the IPCO bit according to ETH ChecksumOffload value */ + /* Set the DR bit according to ETH RetryTransmission value */ + /* Set the ACS bit according to ETH AutomaticPadCRCStrip value */ + /* Set the BL bit according to ETH BackOffLimit value */ + /* Set the DC bit according to ETH DeferralCheck value */ + tmpreg |= (uint32_t)(macinit.Watchdog | + macinit.Jabber | + macinit.InterFrameGap | + macinit.CarrierSense | + heth->Init.Speed | + macinit.ReceiveOwn | + macinit.LoopbackMode | + heth->Init.DuplexMode | + macinit.ChecksumOffload | + macinit.RetryTransmission | + macinit.AutomaticPadCRCStrip | + macinit.BackOffLimit | + macinit.DeferralCheck); + + /* Write to ETHERNET MACCR */ + prvWriteMACCR( heth, tmpreg ); + + /*----------------------- ETHERNET MACFFR Configuration --------------------*/ + /* Set the RA bit according to ETH ReceiveAll value */ + /* Set the SAF and SAIF bits according to ETH SourceAddrFilter value */ + /* Set the PCF bit according to ETH PassControlFrames value */ + /* Set the DBF bit according to ETH BroadcastFramesReception value */ + /* Set the DAIF bit according to ETH DestinationAddrFilter value */ + /* Set the PR bit according to ETH PromiscuousMode value */ + /* Set the PM, HMC and HPF bits according to ETH MulticastFramesFilter value */ + /* Set the HUC and HPF bits according to ETH UnicastFramesFilter value */ + /* Write to ETHERNET MACFFR */ + heth->Instance->MACFFR = (uint32_t)(macinit.ReceiveAll | + macinit.SourceAddrFilter | + macinit.PassControlFrames | + macinit.BroadcastFramesReception | + macinit.DestinationAddrFilter | + macinit.PromiscuousMode | + macinit.MulticastFramesFilter | + macinit.UnicastFramesFilter); + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->MACFFR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->MACFFR = tmpreg; + + /*--------------- ETHERNET MACHTHR and MACHTLR Configuration --------------*/ + /* Write to ETHERNET MACHTHR */ + heth->Instance->MACHTHR = (uint32_t)macinit.HashTableHigh; + + /* Write to ETHERNET MACHTLR */ + heth->Instance->MACHTLR = (uint32_t)macinit.HashTableLow; + /*----------------------- ETHERNET MACFCR Configuration -------------------*/ + + /* Get the ETHERNET MACFCR value */ + tmpreg = heth->Instance->MACFCR; + /* Clear xx bits */ + tmpreg &= ETH_MACFCR_CLEAR_MASK; + + /* Set the PT bit according to ETH PauseTime value */ + /* Set the DZPQ bit according to ETH ZeroQuantaPause value */ + /* Set the PLT bit according to ETH PauseLowThreshold value */ + /* Set the UP bit according to ETH UnicastPauseFrameDetect value */ + /* Set the RFE bit according to ETH ReceiveFlowControl value */ + /* Set the TFE bit according to ETH TransmitFlowControl value */ + tmpreg |= (uint32_t)((macinit.PauseTime << 16) | + macinit.ZeroQuantaPause | + macinit.PauseLowThreshold | + macinit.UnicastPauseFrameDetect | + macinit.ReceiveFlowControl | + macinit.TransmitFlowControl); + + /* Write to ETHERNET MACFCR */ + prvWriteMACFCR( heth, tmpreg ); + + /*----------------------- ETHERNET MACVLANTR Configuration ----------------*/ + /* Set the ETV bit according to ETH VLANTagComparison value */ + /* Set the VL bit according to ETH VLANTagIdentifier value */ + heth->Instance->MACVLANTR = (uint32_t)(macinit.VLANTagComparison | + macinit.VLANTagIdentifier); + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->MACVLANTR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->MACVLANTR = tmpreg; + + /* Ethernet DMA default initialization ************************************/ + dmainit.DropTCPIPChecksumErrorFrame = ETH_DROPTCPIPCHECKSUMERRORFRAME_ENABLE; + dmainit.ReceiveStoreForward = ETH_RECEIVESTOREFORWARD_ENABLE; + dmainit.FlushReceivedFrame = ETH_FLUSHRECEIVEDFRAME_ENABLE; + dmainit.TransmitStoreForward = ETH_TRANSMITSTOREFORWARD_ENABLE; + dmainit.TransmitThresholdControl = ETH_TRANSMITTHRESHOLDCONTROL_64BYTES; + dmainit.ForwardErrorFrames = ETH_FORWARDERRORFRAMES_DISABLE; + dmainit.ForwardUndersizedGoodFrames = ETH_FORWARDUNDERSIZEDGOODFRAMES_DISABLE; + dmainit.ReceiveThresholdControl = ETH_RECEIVEDTHRESHOLDCONTROL_64BYTES; + dmainit.SecondFrameOperate = ETH_SECONDFRAMEOPERARTE_ENABLE; + dmainit.AddressAlignedBeats = ETH_ADDRESSALIGNEDBEATS_ENABLE; + dmainit.FixedBurst = ETH_FIXEDBURST_ENABLE; + dmainit.RxDMABurstLength = ETH_RXDMABURSTLENGTH_32BEAT; + dmainit.TxDMABurstLength = ETH_TXDMABURSTLENGTH_32BEAT; + dmainit.EnhancedDescriptorFormat = ETH_DMAENHANCEDDESCRIPTOR_ENABLE; + dmainit.DescriptorSkipLength = 0x0; + dmainit.DMAArbitration = ETH_DMAARBITRATION_ROUNDROBIN_RXTX_1_1; + + /* Get the ETHERNET DMAOMR value */ + tmpreg = heth->Instance->DMAOMR; + /* Clear xx bits */ + tmpreg &= ETH_DMAOMR_CLEAR_MASK; + + /* Set the DT bit according to ETH DropTCPIPChecksumErrorFrame value */ + /* Set the RSF bit according to ETH ReceiveStoreForward value */ + /* Set the DFF bit according to ETH FlushReceivedFrame value */ + /* Set the TSF bit according to ETH TransmitStoreForward value */ + /* Set the TTC bit according to ETH TransmitThresholdControl value */ + /* Set the FEF bit according to ETH ForwardErrorFrames value */ + /* Set the FUF bit according to ETH ForwardUndersizedGoodFrames value */ + /* Set the RTC bit according to ETH ReceiveThresholdControl value */ + /* Set the OSF bit according to ETH SecondFrameOperate value */ + tmpreg |= (uint32_t)(dmainit.DropTCPIPChecksumErrorFrame | + dmainit.ReceiveStoreForward | + dmainit.FlushReceivedFrame | + dmainit.TransmitStoreForward | + dmainit.TransmitThresholdControl | + dmainit.ForwardErrorFrames | + dmainit.ForwardUndersizedGoodFrames | + dmainit.ReceiveThresholdControl | + dmainit.SecondFrameOperate); + + /* Write to ETHERNET DMAOMR */ + prvWriteDMAOMR( heth, tmpreg ); + + /*----------------------- ETHERNET DMABMR Configuration ------------------*/ + /* Set the AAL bit according to ETH AddressAlignedBeats value */ + /* Set the FB bit according to ETH FixedBurst value */ + /* Set the RPBL and 4*PBL bits according to ETH RxDMABurstLength value */ + /* Set the PBL and 4*PBL bits according to ETH TxDMABurstLength value */ + /* Set the Enhanced DMA descriptors bit according to ETH EnhancedDescriptorFormat value*/ + /* Set the DSL bit according to ETH DesciptorSkipLength value */ + /* Set the PR and DA bits according to ETH DMAArbitration value */ + heth->Instance->DMABMR = (uint32_t)(dmainit.AddressAlignedBeats | + dmainit.FixedBurst | + dmainit.RxDMABurstLength | /* !! if 4xPBL is selected for Tx or Rx it is applied for the other */ + dmainit.TxDMABurstLength | + dmainit.EnhancedDescriptorFormat | + (dmainit.DescriptorSkipLength << 2) | + dmainit.DMAArbitration | + ETH_DMABMR_USP); /* Enable use of separate PBL for Rx and Tx */ + + /* Wait until the write operation will be taken into account: + at least four TX_CLK/RX_CLK clock cycles */ + tmpreg = heth->Instance->DMABMR; + HAL_Delay(ETH_REG_WRITE_DELAY); + heth->Instance->DMABMR = tmpreg; + + if(heth->Init.RxMode == ETH_RXINTERRUPT_MODE) + { + /* Enable the Ethernet Rx Interrupt */ + __HAL_ETH_DMA_ENABLE_IT(( heth ), ETH_DMA_IT_NIS | ETH_DMA_IT_R); + } + + /* Initialize MAC address in ethernet MAC */ + ETH_MACAddressConfig(heth, ETH_MAC_ADDRESS0, heth->Init.MACAddr); +} + +/** + * @brief Configures the selected MAC address. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @param MacAddr: The MAC address to configure + * This parameter can be one of the following values: + * @arg ETH_MAC_Address0: MAC Address0 + * @arg ETH_MAC_Address1: MAC Address1 + * @arg ETH_MAC_Address2: MAC Address2 + * @arg ETH_MAC_Address3: MAC Address3 + * @param Addr: Pointer to MAC address buffer data (6 bytes) + * @retval HAL status + */ +static void ETH_MACAddressConfig(ETH_HandleTypeDef *heth, uint32_t MacAddr, uint8_t *Addr) +{ + uint32_t tmpreg; + + /* Check the parameters */ + assert_param( IS_ETH_MAC_ADDRESS0123( MacAddr ) ); + + /* Calculate the selected MAC address high register */ + tmpreg = 0x80000000ul | ( ( uint32_t )Addr[ 5 ] << 8) | (uint32_t)Addr[ 4 ]; + /* Load the selected MAC address high register */ + ( * ( __IO uint32_t * ) ( ( uint32_t ) ( ETH_MAC_ADDR_HBASE + MacAddr ) ) ) = tmpreg; + /* Calculate the selected MAC address low register */ + tmpreg = ( ( uint32_t )Addr[ 3 ] << 24 ) | ( ( uint32_t )Addr[ 2 ] << 16 ) | ( ( uint32_t )Addr[ 1 ] << 8 ) | Addr[ 0 ]; + + /* Load the selected MAC address low register */ + ( * ( __IO uint32_t * ) ( ( uint32_t ) ( ETH_MAC_ADDR_LBASE + MacAddr ) ) ) = tmpreg; +} + +/** + * @brief Enables the MAC transmission. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_MACTransmissionEnable(ETH_HandleTypeDef *heth) +{ + uint32_t tmpreg = heth->Instance->MACCR | ETH_MACCR_TE; + + prvWriteMACCR( heth, tmpreg ); +} + +/** + * @brief Disables the MAC transmission. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_MACTransmissionDisable(ETH_HandleTypeDef *heth) +{ + uint32_t tmpreg = heth->Instance->MACCR & ~( ETH_MACCR_TE ); + + prvWriteMACCR( heth, tmpreg ); +} + +/** + * @brief Enables the MAC reception. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_MACReceptionEnable(ETH_HandleTypeDef *heth) +{ + __IO uint32_t tmpreg = heth->Instance->MACCR | ETH_MACCR_RE; + + prvWriteMACCR( heth, tmpreg ); +} + +/** + * @brief Disables the MAC reception. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_MACReceptionDisable(ETH_HandleTypeDef *heth) +{ + __IO uint32_t tmpreg = heth->Instance->MACCR & ~( ETH_MACCR_RE ); + + prvWriteMACCR( heth, tmpreg ); +} + +/** + * @brief Enables the DMA transmission. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_DMATransmissionEnable(ETH_HandleTypeDef *heth) +{ + /* Enable the DMA transmission */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR | ETH_DMAOMR_ST; + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @brief Disables the DMA transmission. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_DMATransmissionDisable(ETH_HandleTypeDef *heth) +{ + /* Disable the DMA transmission */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR & ~( ETH_DMAOMR_ST ); + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @brief Enables the DMA reception. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_DMAReceptionEnable(ETH_HandleTypeDef *heth) +{ + /* Enable the DMA reception */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR | ETH_DMAOMR_SR; + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @brief Disables the DMA reception. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_DMAReceptionDisable(ETH_HandleTypeDef *heth) +{ + /* Disable the DMA reception */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR & ~( ETH_DMAOMR_SR ); + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @brief Clears the ETHERNET transmit FIFO. + * @param heth: pointer to a ETH_HandleTypeDef structure that contains + * the configuration information for ETHERNET module + * @retval None + */ +static void ETH_FlushTransmitFIFO(ETH_HandleTypeDef *heth) +{ + /* Set the Flush Transmit FIFO bit */ + __IO uint32_t tmpreg = heth->Instance->DMAOMR | ETH_DMAOMR_FTF; + + prvWriteDMAOMR( heth, tmpreg ); +} + +/** + * @} + */ +#endif /* stm_is_F2 != 0 || stm_is_F4 != 0 || stm_is_F7 */ + +#endif /* HAL_ETH_MODULE_ENABLED */ +/** + * @} + */ + +/** + * @} + */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.h new file mode 100644 index 000000000..f4b74d226 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/STM32Fxx/stm32fxx_hal_eth.h @@ -0,0 +1,2223 @@ +/** + ****************************************************************************** + * @file stm32fxx_hal_eth.h + * @author MCD Application Team + * @version V1.2.2 + * @date 14-April-2017 + * @brief Header file of ETH HAL module. + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * 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. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 to prevent recursive inclusion -------------------------------------*/ +#ifndef __STM32Fxx_HAL_ETH_H +#define __STM32Fxx_HAL_ETH_H + +/* make sure that the original ETH headers files won't be included after this. */ +#define __STM32F2xx_HAL_ETH_H +#define __STM32F4xx_HAL_ETH_H +#define __STM32F7xx_HAL_ETH_H + +#ifdef __cplusplus + extern "C" { +#endif + +/** @addtogroup STM32Fxx_HAL_Driver + * @{ + */ + +/** @addtogroup ETH + * @{ + */ + +/** @addtogroup ETH_Private_Macros + * @{ + */ +#define IS_ETH_PHY_ADDRESS(ADDRESS) ((ADDRESS) <= 0x20) +#define IS_ETH_AUTONEGOTIATION(CMD) (((CMD) == ETH_AUTONEGOTIATION_ENABLE) || \ + ((CMD) == ETH_AUTONEGOTIATION_DISABLE)) +#define IS_ETH_SPEED(SPEED) (((SPEED) == ETH_SPEED_10M) || \ + ((SPEED) == ETH_SPEED_100M)) +#define IS_ETH_DUPLEX_MODE(MODE) (((MODE) == ETH_MODE_FULLDUPLEX) || \ + ((MODE) == ETH_MODE_HALFDUPLEX)) +#define IS_ETH_DUPLEX_MODE(MODE) (((MODE) == ETH_MODE_FULLDUPLEX) || \ + ((MODE) == ETH_MODE_HALFDUPLEX)) +#define IS_ETH_RX_MODE(MODE) (((MODE) == ETH_RXPOLLING_MODE) || \ + ((MODE) == ETH_RXINTERRUPT_MODE)) +#define IS_ETH_RX_MODE(MODE) (((MODE) == ETH_RXPOLLING_MODE) || \ + ((MODE) == ETH_RXINTERRUPT_MODE)) +#define IS_ETH_RX_MODE(MODE) (((MODE) == ETH_RXPOLLING_MODE) || \ + ((MODE) == ETH_RXINTERRUPT_MODE)) +#define IS_ETH_CHECKSUM_MODE(MODE) (((MODE) == ETH_CHECKSUM_BY_HARDWARE) || \ + ((MODE) == ETH_CHECKSUM_BY_SOFTWARE)) +#define IS_ETH_MEDIA_INTERFACE(MODE) (((MODE) == ETH_MEDIA_INTERFACE_MII) || \ + ((MODE) == ETH_MEDIA_INTERFACE_RMII)) +#define IS_ETH_WATCHDOG(CMD) (((CMD) == ETH_WATCHDOG_ENABLE) || \ + ((CMD) == ETH_WATCHDOG_DISABLE)) +#define IS_ETH_JABBER(CMD) (((CMD) == ETH_JABBER_ENABLE) || \ + ((CMD) == ETH_JABBER_DISABLE)) +#define IS_ETH_INTER_FRAME_GAP(GAP) (((GAP) == ETH_INTERFRAMEGAP_96BIT) || \ + ((GAP) == ETH_INTERFRAMEGAP_88BIT) || \ + ((GAP) == ETH_INTERFRAMEGAP_80BIT) || \ + ((GAP) == ETH_INTERFRAMEGAP_72BIT) || \ + ((GAP) == ETH_INTERFRAMEGAP_64BIT) || \ + ((GAP) == ETH_INTERFRAMEGAP_56BIT) || \ + ((GAP) == ETH_INTERFRAMEGAP_48BIT) || \ + ((GAP) == ETH_INTERFRAMEGAP_40BIT)) +#define IS_ETH_CARRIER_SENSE(CMD) (((CMD) == ETH_CARRIERSENCE_ENABLE) || \ + ((CMD) == ETH_CARRIERSENCE_DISABLE)) +#define IS_ETH_RECEIVE_OWN(CMD) (((CMD) == ETH_RECEIVEOWN_ENABLE) || \ + ((CMD) == ETH_RECEIVEOWN_DISABLE)) +#define IS_ETH_LOOPBACK_MODE(CMD) (((CMD) == ETH_LOOPBACKMODE_ENABLE) || \ + ((CMD) == ETH_LOOPBACKMODE_DISABLE)) +#define IS_ETH_CHECKSUM_OFFLOAD(CMD) (((CMD) == ETH_CHECKSUMOFFLAOD_ENABLE) || \ + ((CMD) == ETH_CHECKSUMOFFLAOD_DISABLE)) +#define IS_ETH_RETRY_TRANSMISSION(CMD) (((CMD) == ETH_RETRYTRANSMISSION_ENABLE) || \ + ((CMD) == ETH_RETRYTRANSMISSION_DISABLE)) +#define IS_ETH_AUTOMATIC_PADCRC_STRIP(CMD) (((CMD) == ETH_AUTOMATICPADCRCSTRIP_ENABLE) || \ + ((CMD) == ETH_AUTOMATICPADCRCSTRIP_DISABLE)) +#define IS_ETH_BACKOFF_LIMIT(LIMIT) (((LIMIT) == ETH_BACKOFFLIMIT_10) || \ + ((LIMIT) == ETH_BACKOFFLIMIT_8) || \ + ((LIMIT) == ETH_BACKOFFLIMIT_4) || \ + ((LIMIT) == ETH_BACKOFFLIMIT_1)) +#define IS_ETH_DEFERRAL_CHECK(CMD) (((CMD) == ETH_DEFFERRALCHECK_ENABLE) || \ + ((CMD) == ETH_DEFFERRALCHECK_DISABLE)) +#define IS_ETH_RECEIVE_ALL(CMD) (((CMD) == ETH_RECEIVEALL_ENABLE) || \ + ((CMD) == ETH_RECEIVEAll_DISABLE)) +#define IS_ETH_SOURCE_ADDR_FILTER(CMD) (((CMD) == ETH_SOURCEADDRFILTER_NORMAL_ENABLE) || \ + ((CMD) == ETH_SOURCEADDRFILTER_INVERSE_ENABLE) || \ + ((CMD) == ETH_SOURCEADDRFILTER_DISABLE)) +#define IS_ETH_CONTROL_FRAMES(PASS) (((PASS) == ETH_PASSCONTROLFRAMES_BLOCKALL) || \ + ((PASS) == ETH_PASSCONTROLFRAMES_FORWARDALL) || \ + ((PASS) == ETH_PASSCONTROLFRAMES_FORWARDPASSEDADDRFILTER)) +#define IS_ETH_BROADCAST_FRAMES_RECEPTION(CMD) (((CMD) == ETH_BROADCASTFRAMESRECEPTION_ENABLE) || \ + ((CMD) == ETH_BROADCASTFRAMESRECEPTION_DISABLE)) +#define IS_ETH_DESTINATION_ADDR_FILTER(FILTER) (((FILTER) == ETH_DESTINATIONADDRFILTER_NORMAL) || \ + ((FILTER) == ETH_DESTINATIONADDRFILTER_INVERSE)) +#define IS_ETH_PROMISCUOUS_MODE(CMD) (((CMD) == ETH_PROMISCUOUS_MODE_ENABLE) || \ + ((CMD) == ETH_PROMISCUOUS_MODE_DISABLE)) +#define IS_ETH_MULTICAST_FRAMES_FILTER(FILTER) (((FILTER) == ETH_MULTICASTFRAMESFILTER_PERFECTHASHTABLE) || \ + ((FILTER) == ETH_MULTICASTFRAMESFILTER_HASHTABLE) || \ + ((FILTER) == ETH_MULTICASTFRAMESFILTER_PERFECT) || \ + ((FILTER) == ETH_MULTICASTFRAMESFILTER_NONE)) +#define IS_ETH_UNICAST_FRAMES_FILTER(FILTER) (((FILTER) == ETH_UNICASTFRAMESFILTER_PERFECTHASHTABLE) || \ + ((FILTER) == ETH_UNICASTFRAMESFILTER_HASHTABLE) || \ + ((FILTER) == ETH_UNICASTFRAMESFILTER_PERFECT)) +#define IS_ETH_PAUSE_TIME(TIME) ((TIME) <= 0xFFFF) +#define IS_ETH_ZEROQUANTA_PAUSE(CMD) (((CMD) == ETH_ZEROQUANTAPAUSE_ENABLE) || \ + ((CMD) == ETH_ZEROQUANTAPAUSE_DISABLE)) +#define IS_ETH_PAUSE_LOW_THRESHOLD(THRESHOLD) (((THRESHOLD) == ETH_PAUSELOWTHRESHOLD_MINUS4) || \ + ((THRESHOLD) == ETH_PAUSELOWTHRESHOLD_MINUS28) || \ + ((THRESHOLD) == ETH_PAUSELOWTHRESHOLD_MINUS144) || \ + ((THRESHOLD) == ETH_PAUSELOWTHRESHOLD_MINUS256)) +#define IS_ETH_UNICAST_PAUSE_FRAME_DETECT(CMD) (((CMD) == ETH_UNICASTPAUSEFRAMEDETECT_ENABLE) || \ + ((CMD) == ETH_UNICASTPAUSEFRAMEDETECT_DISABLE)) +#define IS_ETH_RECEIVE_FLOWCONTROL(CMD) (((CMD) == ETH_RECEIVEFLOWCONTROL_ENABLE) || \ + ((CMD) == ETH_RECEIVEFLOWCONTROL_DISABLE)) +#define IS_ETH_TRANSMIT_FLOWCONTROL(CMD) (((CMD) == ETH_TRANSMITFLOWCONTROL_ENABLE) || \ + ((CMD) == ETH_TRANSMITFLOWCONTROL_DISABLE)) +#define IS_ETH_VLAN_TAG_COMPARISON(COMPARISON) (((COMPARISON) == ETH_VLANTAGCOMPARISON_12BIT) || \ + ((COMPARISON) == ETH_VLANTAGCOMPARISON_16BIT)) +#define IS_ETH_VLAN_TAG_IDENTIFIER(IDENTIFIER) ((IDENTIFIER) <= 0xFFFF) +#define IS_ETH_MAC_ADDRESS0123(ADDRESS) (((ADDRESS) == ETH_MAC_ADDRESS0) || \ + ((ADDRESS) == ETH_MAC_ADDRESS1) || \ + ((ADDRESS) == ETH_MAC_ADDRESS2) || \ + ((ADDRESS) == ETH_MAC_ADDRESS3)) +#define IS_ETH_MAC_ADDRESS123(ADDRESS) (((ADDRESS) == ETH_MAC_ADDRESS1) || \ + ((ADDRESS) == ETH_MAC_ADDRESS2) || \ + ((ADDRESS) == ETH_MAC_ADDRESS3)) +#define IS_ETH_MAC_ADDRESS_FILTER(FILTER) (((FILTER) == ETH_MAC_ADDRESSFILTER_SA) || \ + ((FILTER) == ETH_MAC_ADDRESSFILTER_DA)) +#define IS_ETH_MAC_ADDRESS_MASK(MASK) (((MASK) == ETH_MAC_ADDRESSMASK_BYTE6) || \ + ((MASK) == ETH_MAC_ADDRESSMASK_BYTE5) || \ + ((MASK) == ETH_MAC_ADDRESSMASK_BYTE4) || \ + ((MASK) == ETH_MAC_ADDRESSMASK_BYTE3) || \ + ((MASK) == ETH_MAC_ADDRESSMASK_BYTE2) || \ + ((MASK) == ETH_MAC_ADDRESSMASK_BYTE1)) +#define IS_ETH_DROP_TCPIP_CHECKSUM_FRAME(CMD) (((CMD) == ETH_DROPTCPIPCHECKSUMERRORFRAME_ENABLE) || \ + ((CMD) == ETH_DROPTCPIPCHECKSUMERRORFRAME_DISABLE)) +#define IS_ETH_RECEIVE_STORE_FORWARD(CMD) (((CMD) == ETH_RECEIVESTOREFORWARD_ENABLE) || \ + ((CMD) == ETH_RECEIVESTOREFORWARD_DISABLE)) +#define IS_ETH_FLUSH_RECEIVE_FRAME(CMD) (((CMD) == ETH_FLUSHRECEIVEDFRAME_ENABLE) || \ + ((CMD) == ETH_FLUSHRECEIVEDFRAME_DISABLE)) +#define IS_ETH_TRANSMIT_STORE_FORWARD(CMD) (((CMD) == ETH_TRANSMITSTOREFORWARD_ENABLE) || \ + ((CMD) == ETH_TRANSMITSTOREFORWARD_DISABLE)) +#define IS_ETH_TRANSMIT_THRESHOLD_CONTROL(THRESHOLD) (((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_64BYTES) || \ + ((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_128BYTES) || \ + ((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_192BYTES) || \ + ((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_256BYTES) || \ + ((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_40BYTES) || \ + ((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_32BYTES) || \ + ((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_24BYTES) || \ + ((THRESHOLD) == ETH_TRANSMITTHRESHOLDCONTROL_16BYTES)) +#define IS_ETH_FORWARD_ERROR_FRAMES(CMD) (((CMD) == ETH_FORWARDERRORFRAMES_ENABLE) || \ + ((CMD) == ETH_FORWARDERRORFRAMES_DISABLE)) +#define IS_ETH_FORWARD_UNDERSIZED_GOOD_FRAMES(CMD) (((CMD) == ETH_FORWARDUNDERSIZEDGOODFRAMES_ENABLE) || \ + ((CMD) == ETH_FORWARDUNDERSIZEDGOODFRAMES_DISABLE)) +#define IS_ETH_RECEIVE_THRESHOLD_CONTROL(THRESHOLD) (((THRESHOLD) == ETH_RECEIVEDTHRESHOLDCONTROL_64BYTES) || \ + ((THRESHOLD) == ETH_RECEIVEDTHRESHOLDCONTROL_32BYTES) || \ + ((THRESHOLD) == ETH_RECEIVEDTHRESHOLDCONTROL_96BYTES) || \ + ((THRESHOLD) == ETH_RECEIVEDTHRESHOLDCONTROL_128BYTES)) +#define IS_ETH_SECOND_FRAME_OPERATE(CMD) (((CMD) == ETH_SECONDFRAMEOPERARTE_ENABLE) || \ + ((CMD) == ETH_SECONDFRAMEOPERARTE_DISABLE)) +#define IS_ETH_ADDRESS_ALIGNED_BEATS(CMD) (((CMD) == ETH_ADDRESSALIGNEDBEATS_ENABLE) || \ + ((CMD) == ETH_ADDRESSALIGNEDBEATS_DISABLE)) +#define IS_ETH_FIXED_BURST(CMD) (((CMD) == ETH_FIXEDBURST_ENABLE) || \ + ((CMD) == ETH_FIXEDBURST_DISABLE)) +#define IS_ETH_RXDMA_BURST_LENGTH(LENGTH) (((LENGTH) == ETH_RXDMABURSTLENGTH_1BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_2BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_4BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_8BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_16BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_32BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_4XPBL_4BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_4XPBL_8BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_4XPBL_16BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_4XPBL_32BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_4XPBL_64BEAT) || \ + ((LENGTH) == ETH_RXDMABURSTLENGTH_4XPBL_128BEAT)) +#define IS_ETH_TXDMA_BURST_LENGTH(LENGTH) (((LENGTH) == ETH_TXDMABURSTLENGTH_1BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_2BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_4BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_8BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_16BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_32BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_4XPBL_4BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_4XPBL_8BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_4XPBL_16BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_4XPBL_32BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_4XPBL_64BEAT) || \ + ((LENGTH) == ETH_TXDMABURSTLENGTH_4XPBL_128BEAT)) +#define IS_ETH_DMA_DESC_SKIP_LENGTH(LENGTH) ((LENGTH) <= 0x1F) +#define IS_ETH_DMA_ARBITRATION_ROUNDROBIN_RXTX(RATIO) (((RATIO) == ETH_DMAARBITRATION_ROUNDROBIN_RXTX_1_1) || \ + ((RATIO) == ETH_DMAARBITRATION_ROUNDROBIN_RXTX_2_1) || \ + ((RATIO) == ETH_DMAARBITRATION_ROUNDROBIN_RXTX_3_1) || \ + ((RATIO) == ETH_DMAARBITRATION_ROUNDROBIN_RXTX_4_1) || \ + ((RATIO) == ETH_DMAARBITRATION_RXPRIORTX)) +#define IS_ETH_DMATXDESC_GET_FLAG(FLAG) (((FLAG) == ETH_DMATXDESC_OWN) || \ + ((FLAG) == ETH_DMATXDESC_IC) || \ + ((FLAG) == ETH_DMATXDESC_LS) || \ + ((FLAG) == ETH_DMATXDESC_FS) || \ + ((FLAG) == ETH_DMATXDESC_DC) || \ + ((FLAG) == ETH_DMATXDESC_DP) || \ + ((FLAG) == ETH_DMATXDESC_TTSE) || \ + ((FLAG) == ETH_DMATXDESC_TER) || \ + ((FLAG) == ETH_DMATXDESC_TCH) || \ + ((FLAG) == ETH_DMATXDESC_TTSS) || \ + ((FLAG) == ETH_DMATXDESC_IHE) || \ + ((FLAG) == ETH_DMATXDESC_ES) || \ + ((FLAG) == ETH_DMATXDESC_JT) || \ + ((FLAG) == ETH_DMATXDESC_FF) || \ + ((FLAG) == ETH_DMATXDESC_PCE) || \ + ((FLAG) == ETH_DMATXDESC_LCA) || \ + ((FLAG) == ETH_DMATXDESC_NC) || \ + ((FLAG) == ETH_DMATXDESC_LCO) || \ + ((FLAG) == ETH_DMATXDESC_EC) || \ + ((FLAG) == ETH_DMATXDESC_VF) || \ + ((FLAG) == ETH_DMATXDESC_CC) || \ + ((FLAG) == ETH_DMATXDESC_ED) || \ + ((FLAG) == ETH_DMATXDESC_UF) || \ + ((FLAG) == ETH_DMATXDESC_DB)) +#define IS_ETH_DMA_TXDESC_SEGMENT(SEGMENT) (((SEGMENT) == ETH_DMATXDESC_LASTSEGMENTS) || \ + ((SEGMENT) == ETH_DMATXDESC_FIRSTSEGMENT)) +#define IS_ETH_DMA_TXDESC_CHECKSUM(CHECKSUM) (((CHECKSUM) == ETH_DMATXDESC_CHECKSUMBYPASS) || \ + ((CHECKSUM) == ETH_DMATXDESC_CHECKSUMIPV4HEADER) || \ + ((CHECKSUM) == ETH_DMATXDESC_CHECKSUMTCPUDPICMPSEGMENT) || \ + ((CHECKSUM) == ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL)) +#define IS_ETH_DMATXDESC_BUFFER_SIZE(SIZE) ((SIZE) <= 0x1FFF) +#define IS_ETH_DMARXDESC_GET_FLAG(FLAG) (((FLAG) == ETH_DMARXDESC_OWN) || \ + ((FLAG) == ETH_DMARXDESC_AFM) || \ + ((FLAG) == ETH_DMARXDESC_ES) || \ + ((FLAG) == ETH_DMARXDESC_DE) || \ + ((FLAG) == ETH_DMARXDESC_SAF) || \ + ((FLAG) == ETH_DMARXDESC_LE) || \ + ((FLAG) == ETH_DMARXDESC_OE) || \ + ((FLAG) == ETH_DMARXDESC_VLAN) || \ + ((FLAG) == ETH_DMARXDESC_FS) || \ + ((FLAG) == ETH_DMARXDESC_LS) || \ + ((FLAG) == ETH_DMARXDESC_IPV4HCE) || \ + ((FLAG) == ETH_DMARXDESC_LC) || \ + ((FLAG) == ETH_DMARXDESC_FT) || \ + ((FLAG) == ETH_DMARXDESC_RWT) || \ + ((FLAG) == ETH_DMARXDESC_RE) || \ + ((FLAG) == ETH_DMARXDESC_DBE) || \ + ((FLAG) == ETH_DMARXDESC_CE) || \ + ((FLAG) == ETH_DMARXDESC_MAMPCE)) +#define IS_ETH_DMA_RXDESC_BUFFER(BUFFER) (((BUFFER) == ETH_DMARXDESC_BUFFER1) || \ + ((BUFFER) == ETH_DMARXDESC_BUFFER2)) +#define IS_ETH_PMT_GET_FLAG(FLAG) (((FLAG) == ETH_PMT_FLAG_WUFR) || \ + ((FLAG) == ETH_PMT_FLAG_MPR)) +#define IS_ETH_DMA_FLAG(FLAG) ((((FLAG) & (uint32_t)0xC7FE1800) == 0x00) && ((FLAG) != 0x00)) +#define IS_ETH_DMA_GET_FLAG(FLAG) (((FLAG) == ETH_DMA_FLAG_TST) || ((FLAG) == ETH_DMA_FLAG_PMT) || \ + ((FLAG) == ETH_DMA_FLAG_MMC) || ((FLAG) == ETH_DMA_FLAG_DATATRANSFERERROR) || \ + ((FLAG) == ETH_DMA_FLAG_READWRITEERROR) || ((FLAG) == ETH_DMA_FLAG_ACCESSERROR) || \ + ((FLAG) == ETH_DMA_FLAG_NIS) || ((FLAG) == ETH_DMA_FLAG_AIS) || \ + ((FLAG) == ETH_DMA_FLAG_ER) || ((FLAG) == ETH_DMA_FLAG_FBE) || \ + ((FLAG) == ETH_DMA_FLAG_ET) || ((FLAG) == ETH_DMA_FLAG_RWT) || \ + ((FLAG) == ETH_DMA_FLAG_RPS) || ((FLAG) == ETH_DMA_FLAG_RBU) || \ + ((FLAG) == ETH_DMA_FLAG_R) || ((FLAG) == ETH_DMA_FLAG_TU) || \ + ((FLAG) == ETH_DMA_FLAG_RO) || ((FLAG) == ETH_DMA_FLAG_TJT) || \ + ((FLAG) == ETH_DMA_FLAG_TBU) || ((FLAG) == ETH_DMA_FLAG_TPS) || \ + ((FLAG) == ETH_DMA_FLAG_T)) +#define IS_ETH_MAC_IT(IT) ((((IT) & (uint32_t)0xFFFFFDF1) == 0x00) && ((IT) != 0x00)) +#define IS_ETH_MAC_GET_IT(IT) (((IT) == ETH_MAC_IT_TST) || ((IT) == ETH_MAC_IT_MMCT) || \ + ((IT) == ETH_MAC_IT_MMCR) || ((IT) == ETH_MAC_IT_MMC) || \ + ((IT) == ETH_MAC_IT_PMT)) +#define IS_ETH_MAC_GET_FLAG(FLAG) (((FLAG) == ETH_MAC_FLAG_TST) || ((FLAG) == ETH_MAC_FLAG_MMCT) || \ + ((FLAG) == ETH_MAC_FLAG_MMCR) || ((FLAG) == ETH_MAC_FLAG_MMC) || \ + ((FLAG) == ETH_MAC_FLAG_PMT)) +#define IS_ETH_DMA_IT(IT) ((((IT) & (uint32_t)0xC7FE1800) == 0x00) && ((IT) != 0x00)) +#define IS_ETH_DMA_GET_IT(IT) (((IT) == ETH_DMA_IT_TST) || ((IT) == ETH_DMA_IT_PMT) || \ + ((IT) == ETH_DMA_IT_MMC) || ((IT) == ETH_DMA_IT_NIS) || \ + ((IT) == ETH_DMA_IT_AIS) || ((IT) == ETH_DMA_IT_ER) || \ + ((IT) == ETH_DMA_IT_FBE) || ((IT) == ETH_DMA_IT_ET) || \ + ((IT) == ETH_DMA_IT_RWT) || ((IT) == ETH_DMA_IT_RPS) || \ + ((IT) == ETH_DMA_IT_RBU) || ((IT) == ETH_DMA_IT_R) || \ + ((IT) == ETH_DMA_IT_TU) || ((IT) == ETH_DMA_IT_RO) || \ + ((IT) == ETH_DMA_IT_TJT) || ((IT) == ETH_DMA_IT_TBU) || \ + ((IT) == ETH_DMA_IT_TPS) || ((IT) == ETH_DMA_IT_T)) +#define IS_ETH_DMA_GET_OVERFLOW(OVERFLOW) (((OVERFLOW) == ETH_DMA_OVERFLOW_RXFIFOCOUNTER) || \ + ((OVERFLOW) == ETH_DMA_OVERFLOW_MISSEDFRAMECOUNTER)) +#define IS_ETH_MMC_IT(IT) (((((IT) & (uint32_t)0xFFDF3FFF) == 0x00) || (((IT) & (uint32_t)0xEFFDFF9F) == 0x00)) && \ + ((IT) != 0x00)) +#define IS_ETH_MMC_GET_IT(IT) (((IT) == ETH_MMC_IT_TGF) || ((IT) == ETH_MMC_IT_TGFMSC) || \ + ((IT) == ETH_MMC_IT_TGFSC) || ((IT) == ETH_MMC_IT_RGUF) || \ + ((IT) == ETH_MMC_IT_RFAE) || ((IT) == ETH_MMC_IT_RFCE)) +#define IS_ETH_ENHANCED_DESCRIPTOR_FORMAT(CMD) (((CMD) == ETH_DMAENHANCEDDESCRIPTOR_ENABLE) || \ + ((CMD) == ETH_DMAENHANCEDDESCRIPTOR_DISABLE)) + + +/** + * @} + */ + +/** @addtogroup ETH_Private_Defines + * @{ + */ +/* Delay to wait when writing to some Ethernet registers */ +#define ETH_REG_WRITE_DELAY ((uint32_t)0x00000001U) + +/* Ethernet Errors */ +#define ETH_SUCCESS ((uint32_t)0U) +#define ETH_ERROR ((uint32_t)1U) + +/* Ethernet DMA Tx descriptors Collision Count Shift */ +#define ETH_DMATXDESC_COLLISION_COUNTSHIFT ((uint32_t)3U) + +/* Ethernet DMA Tx descriptors Buffer2 Size Shift */ +#define ETH_DMATXDESC_BUFFER2_SIZESHIFT ((uint32_t)16U) + +/* Ethernet DMA Rx descriptors Frame Length Shift */ +#define ETH_DMARXDESC_FRAME_LENGTHSHIFT ((uint32_t)16U) + +/* Ethernet DMA Rx descriptors Buffer2 Size Shift */ +#define ETH_DMARXDESC_BUFFER2_SIZESHIFT ((uint32_t)16U) + +/* Ethernet DMA Rx descriptors Frame length Shift */ +#define ETH_DMARXDESC_FRAMELENGTHSHIFT ((uint32_t)16U) + +/* Ethernet MAC address offsets */ +#define ETH_MAC_ADDR_HBASE (uint32_t)(ETH_MAC_BASE + (uint32_t)0x40U) /* Ethernet MAC address high offset */ +#define ETH_MAC_ADDR_LBASE (uint32_t)(ETH_MAC_BASE + (uint32_t)0x44U) /* Ethernet MAC address low offset */ + +/* Ethernet MACMIIAR register Mask */ +#define ETH_MACMIIAR_CR_MASK ((uint32_t)0xFFFFFFE3U) + +/* Ethernet MACCR register Mask */ +#define ETH_MACCR_CLEAR_MASK ((uint32_t)0xFF20810FU) + +/* Ethernet MACFCR register Mask */ +#define ETH_MACFCR_CLEAR_MASK ((uint32_t)0x0000FF41U) + +/* Ethernet DMAOMR register Mask */ +#define ETH_DMAOMR_CLEAR_MASK ((uint32_t)0xF8DE3F23U) + +/* Ethernet Remote Wake-up frame register length */ +#define ETH_WAKEUP_REGISTER_LENGTH 8U + +/* Ethernet Missed frames counter Shift */ +#define ETH_DMA_RX_OVERFLOW_MISSEDFRAMES_COUNTERSHIFT 17U + /** + * @} + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup ETH_Exported_Types ETH Exported Types + * @{ + */ + +/** + * @brief HAL State structures definition + */ +typedef enum +{ + HAL_ETH_STATE_RESET = 0x00U, /*!< Peripheral not yet Initialized or disabled */ + HAL_ETH_STATE_READY = 0x01U, /*!< Peripheral Initialized and ready for use */ + HAL_ETH_STATE_BUSY = 0x02U, /*!< an internal process is ongoing */ + HAL_ETH_STATE_BUSY_TX = 0x12U, /*!< Data Transmission process is ongoing */ + HAL_ETH_STATE_BUSY_RX = 0x22U, /*!< Data Reception process is ongoing */ + HAL_ETH_STATE_BUSY_TX_RX = 0x32U, /*!< Data Transmission and Reception process is ongoing */ + HAL_ETH_STATE_BUSY_WR = 0x42U, /*!< Write process is ongoing */ + HAL_ETH_STATE_BUSY_RD = 0x82U, /*!< Read process is ongoing */ + HAL_ETH_STATE_TIMEOUT = 0x03U, /*!< Timeout state */ + HAL_ETH_STATE_ERROR = 0x04U /*!< Reception process is ongoing */ +}HAL_ETH_StateTypeDef; + +/** + * @brief ETH Init Structure definition + */ + +typedef struct +{ + uint32_t AutoNegotiation; /*!< Selects or not the AutoNegotiation mode for the external PHY + The AutoNegotiation allows an automatic setting of the Speed (10/100Mbps) + and the mode (half/full-duplex). + This parameter can be a value of @ref ETH_AutoNegotiation */ + + uint32_t Speed; /*!< Sets the Ethernet speed: 10/100 Mbps. + This parameter can be a value of @ref ETH_Speed */ + + uint32_t DuplexMode; /*!< Selects the MAC duplex mode: Half-Duplex or Full-Duplex mode + This parameter can be a value of @ref ETH_Duplex_Mode */ + + uint16_t PhyAddress; /*!< Ethernet PHY address. + This parameter must be a number between Min_Data = 0 and Max_Data = 32 */ + + uint8_t *MACAddr; /*!< MAC Address of used Hardware: must be pointer on an array of 6 bytes */ + + uint32_t RxMode; /*!< Selects the Ethernet Rx mode: Polling mode, Interrupt mode. + This parameter can be a value of @ref ETH_Rx_Mode */ + + uint32_t ChecksumMode; /*!< Selects if the checksum is check by hardware or by software. + This parameter can be a value of @ref ETH_Checksum_Mode */ + + uint32_t MediaInterface ; /*!< Selects the media-independent interface or the reduced media-independent interface. + This parameter can be a value of @ref ETH_Media_Interface */ + +} ETH_InitTypeDef; + + + /** + * @brief ETH MAC Configuration Structure definition + */ + +typedef struct +{ + uint32_t Watchdog; /*!< Selects or not the Watchdog timer + When enabled, the MAC allows no more then 2048 bytes to be received. + When disabled, the MAC can receive up to 16384 bytes. + This parameter can be a value of @ref ETH_Watchdog */ + + uint32_t Jabber; /*!< Selects or not Jabber timer + When enabled, the MAC allows no more then 2048 bytes to be sent. + When disabled, the MAC can send up to 16384 bytes. + This parameter can be a value of @ref ETH_Jabber */ + + uint32_t InterFrameGap; /*!< Selects the minimum IFG between frames during transmission. + This parameter can be a value of @ref ETH_Inter_Frame_Gap */ + + uint32_t CarrierSense; /*!< Selects or not the Carrier Sense. + This parameter can be a value of @ref ETH_Carrier_Sense */ + + uint32_t ReceiveOwn; /*!< Selects or not the ReceiveOwn, + ReceiveOwn allows the reception of frames when the TX_EN signal is asserted + in Half-Duplex mode. + This parameter can be a value of @ref ETH_Receive_Own */ + + uint32_t LoopbackMode; /*!< Selects or not the internal MAC MII Loopback mode. + This parameter can be a value of @ref ETH_Loop_Back_Mode */ + + uint32_t ChecksumOffload; /*!< Selects or not the IPv4 checksum checking for received frame payloads' TCP/UDP/ICMP headers. + This parameter can be a value of @ref ETH_Checksum_Offload */ + + uint32_t RetryTransmission; /*!< Selects or not the MAC attempt retries transmission, based on the settings of BL, + when a collision occurs (Half-Duplex mode). + This parameter can be a value of @ref ETH_Retry_Transmission */ + + uint32_t AutomaticPadCRCStrip; /*!< Selects or not the Automatic MAC Pad/CRC Stripping. + This parameter can be a value of @ref ETH_Automatic_Pad_CRC_Strip */ + + uint32_t BackOffLimit; /*!< Selects the BackOff limit value. + This parameter can be a value of @ref ETH_Back_Off_Limit */ + + uint32_t DeferralCheck; /*!< Selects or not the deferral check function (Half-Duplex mode). + This parameter can be a value of @ref ETH_Deferral_Check */ + + uint32_t ReceiveAll; /*!< Selects or not all frames reception by the MAC (No filtering). + This parameter can be a value of @ref ETH_Receive_All */ + + uint32_t SourceAddrFilter; /*!< Selects the Source Address Filter mode. + This parameter can be a value of @ref ETH_Source_Addr_Filter */ + + uint32_t PassControlFrames; /*!< Sets the forwarding mode of the control frames (including unicast and multicast PAUSE frames) + This parameter can be a value of @ref ETH_Pass_Control_Frames */ + + uint32_t BroadcastFramesReception; /*!< Selects or not the reception of Broadcast Frames. + This parameter can be a value of @ref ETH_Broadcast_Frames_Reception */ + + uint32_t DestinationAddrFilter; /*!< Sets the destination filter mode for both unicast and multicast frames. + This parameter can be a value of @ref ETH_Destination_Addr_Filter */ + + uint32_t PromiscuousMode; /*!< Selects or not the Promiscuous Mode + This parameter can be a value of @ref ETH_Promiscuous_Mode */ + + uint32_t MulticastFramesFilter; /*!< Selects the Multicast Frames filter mode: None/HashTableFilter/PerfectFilter/PerfectHashTableFilter. + This parameter can be a value of @ref ETH_Multicast_Frames_Filter */ + + uint32_t UnicastFramesFilter; /*!< Selects the Unicast Frames filter mode: HashTableFilter/PerfectFilter/PerfectHashTableFilter. + This parameter can be a value of @ref ETH_Unicast_Frames_Filter */ + + uint32_t HashTableHigh; /*!< This field holds the higher 32 bits of Hash table. + This parameter must be a number between Min_Data = 0x0 and Max_Data = 0xFFFFFFFF */ + + uint32_t HashTableLow; /*!< This field holds the lower 32 bits of Hash table. + This parameter must be a number between Min_Data = 0x0 and Max_Data = 0xFFFFFFFF */ + + uint32_t PauseTime; /*!< This field holds the value to be used in the Pause Time field in the transmit control frame. + This parameter must be a number between Min_Data = 0x0 and Max_Data = 0xFFFF */ + + uint32_t ZeroQuantaPause; /*!< Selects or not the automatic generation of Zero-Quanta Pause Control frames. + This parameter can be a value of @ref ETH_Zero_Quanta_Pause */ + + uint32_t PauseLowThreshold; /*!< This field configures the threshold of the PAUSE to be checked for + automatic retransmission of PAUSE Frame. + This parameter can be a value of @ref ETH_Pause_Low_Threshold */ + + uint32_t UnicastPauseFrameDetect; /*!< Selects or not the MAC detection of the Pause frames (with MAC Address0 + unicast address and unique multicast address). + This parameter can be a value of @ref ETH_Unicast_Pause_Frame_Detect */ + + uint32_t ReceiveFlowControl; /*!< Enables or disables the MAC to decode the received Pause frame and + disable its transmitter for a specified time (Pause Time) + This parameter can be a value of @ref ETH_Receive_Flow_Control */ + + uint32_t TransmitFlowControl; /*!< Enables or disables the MAC to transmit Pause frames (Full-Duplex mode) + or the MAC back-pressure operation (Half-Duplex mode) + This parameter can be a value of @ref ETH_Transmit_Flow_Control */ + + uint32_t VLANTagComparison; /*!< Selects the 12-bit VLAN identifier or the complete 16-bit VLAN tag for + comparison and filtering. + This parameter can be a value of @ref ETH_VLAN_Tag_Comparison */ + + uint32_t VLANTagIdentifier; /*!< Holds the VLAN tag identifier for receive frames */ + +} ETH_MACInitTypeDef; + + +/** + * @brief ETH DMA Configuration Structure definition + */ + +typedef struct +{ + uint32_t DropTCPIPChecksumErrorFrame; /*!< Selects or not the Dropping of TCP/IP Checksum Error Frames. + This parameter can be a value of @ref ETH_Drop_TCP_IP_Checksum_Error_Frame */ + + uint32_t ReceiveStoreForward; /*!< Enables or disables the Receive store and forward mode. + This parameter can be a value of @ref ETH_Receive_Store_Forward */ + + uint32_t FlushReceivedFrame; /*!< Enables or disables the flushing of received frames. + This parameter can be a value of @ref ETH_Flush_Received_Frame */ + + uint32_t TransmitStoreForward; /*!< Enables or disables Transmit store and forward mode. + This parameter can be a value of @ref ETH_Transmit_Store_Forward */ + + uint32_t TransmitThresholdControl; /*!< Selects or not the Transmit Threshold Control. + This parameter can be a value of @ref ETH_Transmit_Threshold_Control */ + + uint32_t ForwardErrorFrames; /*!< Selects or not the forward to the DMA of erroneous frames. + This parameter can be a value of @ref ETH_Forward_Error_Frames */ + + uint32_t ForwardUndersizedGoodFrames; /*!< Enables or disables the Rx FIFO to forward Undersized frames (frames with no Error + and length less than 64 bytes) including pad-bytes and CRC) + This parameter can be a value of @ref ETH_Forward_Undersized_Good_Frames */ + + uint32_t ReceiveThresholdControl; /*!< Selects the threshold level of the Receive FIFO. + This parameter can be a value of @ref ETH_Receive_Threshold_Control */ + + uint32_t SecondFrameOperate; /*!< Selects or not the Operate on second frame mode, which allows the DMA to process a second + frame of Transmit data even before obtaining the status for the first frame. + This parameter can be a value of @ref ETH_Second_Frame_Operate */ + + uint32_t AddressAlignedBeats; /*!< Enables or disables the Address Aligned Beats. + This parameter can be a value of @ref ETH_Address_Aligned_Beats */ + + uint32_t FixedBurst; /*!< Enables or disables the AHB Master interface fixed burst transfers. + This parameter can be a value of @ref ETH_Fixed_Burst */ + + uint32_t RxDMABurstLength; /*!< Indicates the maximum number of beats to be transferred in one Rx DMA transaction. + This parameter can be a value of @ref ETH_Rx_DMA_Burst_Length */ + + uint32_t TxDMABurstLength; /*!< Indicates the maximum number of beats to be transferred in one Tx DMA transaction. + This parameter can be a value of @ref ETH_Tx_DMA_Burst_Length */ + + uint32_t EnhancedDescriptorFormat; /*!< Enables the enhanced descriptor format. + This parameter can be a value of @ref ETH_DMA_Enhanced_descriptor_format */ + + uint32_t DescriptorSkipLength; /*!< Specifies the number of word to skip between two unchained descriptors (Ring mode) + This parameter must be a number between Min_Data = 0 and Max_Data = 32 */ + + uint32_t DMAArbitration; /*!< Selects the DMA Tx/Rx arbitration. + This parameter can be a value of @ref ETH_DMA_Arbitration */ +} ETH_DMAInitTypeDef; + + +/** + * @brief ETH DMA Descriptors data structure definition + */ + +typedef struct +{ + __IO uint32_t Status; /*!< Status */ + + uint32_t ControlBufferSize; /*!< Control and Buffer1, Buffer2 lengths */ + + uint32_t Buffer1Addr; /*!< Buffer1 address pointer */ + + uint32_t Buffer2NextDescAddr; /*!< Buffer2 or next descriptor address pointer */ + + /*!< Enhanced Ethernet DMA PTP Descriptors */ + uint32_t ExtendedStatus; /*!< Extended status for PTP receive descriptor */ + + uint32_t Reserved1; /*!< Reserved */ + + uint32_t TimeStampLow; /*!< Time Stamp Low value for transmit and receive */ + + uint32_t TimeStampHigh; /*!< Time Stamp High value for transmit and receive */ + +} ETH_DMADescTypeDef; + + +/** + * @brief Received Frame Informations structure definition + */ +typedef struct +{ + ETH_DMADescTypeDef *FSRxDesc; /*!< First Segment Rx Desc */ + + ETH_DMADescTypeDef *LSRxDesc; /*!< Last Segment Rx Desc */ + + uint32_t SegCount; /*!< Segment count */ + + uint32_t length; /*!< Frame length */ + + uint32_t buffer; /*!< Frame buffer */ + +} ETH_DMARxFrameInfos; + + +/** + * @brief ETH Handle Structure definition + */ + +typedef struct +{ + ETH_TypeDef *Instance; /*!< Register base address */ + + ETH_InitTypeDef Init; /*!< Ethernet Init Configuration */ + + uint32_t LinkStatus; /*!< Ethernet link status */ + + ETH_DMADescTypeDef *RxDesc; /*!< Rx descriptor to Get */ + + ETH_DMADescTypeDef *TxDesc; /*!< Tx descriptor to Set */ + + ETH_DMARxFrameInfos RxFrameInfos; /*!< last Rx frame infos */ + + __IO HAL_ETH_StateTypeDef State; /*!< ETH communication state */ + + HAL_LockTypeDef Lock; /*!< ETH Lock */ + +} ETH_HandleTypeDef; + + /** + * @} + */ + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup ETH_Exported_Constants ETH Exported Constants + * @{ + */ + +/** @defgroup ETH_Buffers_setting ETH Buffers setting + * @{ + */ +#define ETH_MAX_PACKET_SIZE ((uint32_t)1536U) /*!< ETH_HEADER + ETH_EXTRA + ETH_VLAN_TAG + ETH_MAX_ETH_PAYLOAD + ETH_CRC */ +#define ETH_HEADER ((uint32_t)14U) /*!< 6 byte Dest addr, 6 byte Src addr, 2 byte length/type */ +#define ETH_CRC ((uint32_t)4U) /*!< Ethernet CRC */ +#define ETH_EXTRA ((uint32_t)2U) /*!< Extra bytes in some cases */ +#define ETH_VLAN_TAG ((uint32_t)4U) /*!< optional 802.1q VLAN Tag */ +#define ETH_MIN_ETH_PAYLOAD ((uint32_t)46U) /*!< Minimum Ethernet payload size */ +#define ETH_MAX_ETH_PAYLOAD ((uint32_t)1500U) /*!< Maximum Ethernet payload size */ +#define ETH_JUMBO_FRAME_PAYLOAD ((uint32_t)9000U) /*!< Jumbo frame payload size */ + + /* Ethernet driver receive buffers are organized in a chained linked-list, when + an Ethernet packet is received, the Rx-DMA will transfer the packet from RxFIFO + to the driver receive buffers memory. + + Depending on the size of the received Ethernet packet and the size of + each Ethernet driver receive buffer, the received packet can take one or more + Ethernet driver receive buffer. + + In below are defined the size of one Ethernet driver receive buffer ETH_RX_BUF_SIZE + and the total count of the driver receive buffers ETH_RXBUFNB. + + The configured value for ETH_RX_BUF_SIZE and ETH_RXBUFNB are only provided as + example, they can be reconfigured in the application layer to fit the application + needs */ + +/* Here we configure each Ethernet driver receive buffer to fit the Max size Ethernet + packet */ +#ifndef ETH_RX_BUF_SIZE + #error please define ETH_RX_BUF_SIZE + #define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE +#endif + +/* 5 Ethernet driver receive buffers are used (in a chained linked list)*/ +#ifndef ETH_RXBUFNB + #define ETH_RXBUFNB ((uint32_t)5U) /* 5 Rx buffers of size ETH_RX_BUF_SIZE */ +#endif + + + /* Ethernet driver transmit buffers are organized in a chained linked-list, when + an Ethernet packet is transmitted, Tx-DMA will transfer the packet from the + driver transmit buffers memory to the TxFIFO. + + Depending on the size of the Ethernet packet to be transmitted and the size of + each Ethernet driver transmit buffer, the packet to be transmitted can take + one or more Ethernet driver transmit buffer. + + In below are defined the size of one Ethernet driver transmit buffer ETH_TX_BUF_SIZE + and the total count of the driver transmit buffers ETH_TXBUFNB. + + The configured value for ETH_TX_BUF_SIZE and ETH_TXBUFNB are only provided as + example, they can be reconfigured in the application layer to fit the application + needs */ + +/* Here we configure each Ethernet driver transmit buffer to fit the Max size Ethernet + packet */ +#ifndef ETH_TX_BUF_SIZE + #error please define ETH_TX_BUF_SIZE + #define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE +#endif + +/* 5 Ethernet driver transmit buffers are used (in a chained linked list)*/ +#ifndef ETH_TXBUFNB + #define ETH_TXBUFNB ((uint32_t)5U) /* 5 Tx buffers of size ETH_TX_BUF_SIZE */ +#endif + + /** + * @} + */ + +/** @defgroup ETH_DMA_TX_Descriptor ETH DMA TX Descriptor + * @{ + */ + +/* + DMA Tx Descriptor + ----------------------------------------------------------------------------------------------- + TDES0 | OWN(31) | CTRL[30:26] | Reserved[25:24] | CTRL[23:20] | Reserved[19:17] | Status[16:0] | + ----------------------------------------------------------------------------------------------- + TDES1 | Reserved[31:29] | Buffer2 ByteCount[28:16] | Reserved[15:13] | Buffer1 ByteCount[12:0] | + ----------------------------------------------------------------------------------------------- + TDES2 | Buffer1 Address [31:0] | + ----------------------------------------------------------------------------------------------- + TDES3 | Buffer2 Address [31:0] / Next Descriptor Address [31:0] | + ----------------------------------------------------------------------------------------------- +*/ + +/** + * @brief Bit definition of TDES0 register: DMA Tx descriptor status register + */ +#define ETH_DMATXDESC_OWN ((uint32_t)0x80000000U) /*!< OWN bit: descriptor is owned by DMA engine */ +#define ETH_DMATXDESC_IC ((uint32_t)0x40000000U) /*!< Interrupt on Completion */ +#define ETH_DMATXDESC_LS ((uint32_t)0x20000000U) /*!< Last Segment */ +#define ETH_DMATXDESC_FS ((uint32_t)0x10000000U) /*!< First Segment */ +#define ETH_DMATXDESC_DC ((uint32_t)0x08000000U) /*!< Disable CRC */ +#define ETH_DMATXDESC_DP ((uint32_t)0x04000000U) /*!< Disable Padding */ +#define ETH_DMATXDESC_TTSE ((uint32_t)0x02000000U) /*!< Transmit Time Stamp Enable */ +#define ETH_DMATXDESC_CIC ((uint32_t)0x00C00000U) /*!< Checksum Insertion Control: 4 cases */ +#define ETH_DMATXDESC_CIC_BYPASS ((uint32_t)0x00000000U) /*!< Do Nothing: Checksum Engine is bypassed */ +#define ETH_DMATXDESC_CIC_IPV4HEADER ((uint32_t)0x00400000U) /*!< IPV4 header Checksum Insertion */ +#define ETH_DMATXDESC_CIC_TCPUDPICMP_SEGMENT ((uint32_t)0x00800000U) /*!< TCP/UDP/ICMP Checksum Insertion calculated over segment only */ +#define ETH_DMATXDESC_CIC_TCPUDPICMP_FULL ((uint32_t)0x00C00000U) /*!< TCP/UDP/ICMP Checksum Insertion fully calculated */ +#define ETH_DMATXDESC_TER ((uint32_t)0x00200000U) /*!< Transmit End of Ring */ +#define ETH_DMATXDESC_TCH ((uint32_t)0x00100000U) /*!< Second Address Chained */ +#define ETH_DMATXDESC_TTSS ((uint32_t)0x00020000U) /*!< Tx Time Stamp Status */ +#define ETH_DMATXDESC_IHE ((uint32_t)0x00010000U) /*!< IP Header Error */ +#define ETH_DMATXDESC_ES ((uint32_t)0x00008000U) /*!< Error summary: OR of the following bits: UE || ED || EC || LCO || NC || LCA || FF || JT */ +#define ETH_DMATXDESC_JT ((uint32_t)0x00004000U) /*!< Jabber Timeout */ +#define ETH_DMATXDESC_FF ((uint32_t)0x00002000U) /*!< Frame Flushed: DMA/MTL flushed the frame due to SW flush */ +#define ETH_DMATXDESC_PCE ((uint32_t)0x00001000U) /*!< Payload Checksum Error */ +#define ETH_DMATXDESC_LCA ((uint32_t)0x00000800U) /*!< Loss of Carrier: carrier lost during transmission */ +#define ETH_DMATXDESC_NC ((uint32_t)0x00000400U) /*!< No Carrier: no carrier signal from the transceiver */ +#define ETH_DMATXDESC_LCO ((uint32_t)0x00000200U) /*!< Late Collision: transmission aborted due to collision */ +#define ETH_DMATXDESC_EC ((uint32_t)0x00000100U) /*!< Excessive Collision: transmission aborted after 16 collisions */ +#define ETH_DMATXDESC_VF ((uint32_t)0x00000080U) /*!< VLAN Frame */ +#define ETH_DMATXDESC_CC ((uint32_t)0x00000078U) /*!< Collision Count */ +#define ETH_DMATXDESC_ED ((uint32_t)0x00000004U) /*!< Excessive Deferral */ +#define ETH_DMATXDESC_UF ((uint32_t)0x00000002U) /*!< Underflow Error: late data arrival from the memory */ +#define ETH_DMATXDESC_DB ((uint32_t)0x00000001U) /*!< Deferred Bit */ + +/** + * @brief Bit definition of TDES1 register + */ +#define ETH_DMATXDESC_TBS2 ((uint32_t)0x1FFF0000U) /*!< Transmit Buffer2 Size */ +#define ETH_DMATXDESC_TBS1 ((uint32_t)0x00001FFFU) /*!< Transmit Buffer1 Size */ + +/** + * @brief Bit definition of TDES2 register + */ +#define ETH_DMATXDESC_B1AP ((uint32_t)0xFFFFFFFFU) /*!< Buffer1 Address Pointer */ + +/** + * @brief Bit definition of TDES3 register + */ +#define ETH_DMATXDESC_B2AP ((uint32_t)0xFFFFFFFFU) /*!< Buffer2 Address Pointer */ + + /*--------------------------------------------------------------------------------------------- + TDES6 | Transmit Time Stamp Low [31:0] | + ----------------------------------------------------------------------------------------------- + TDES7 | Transmit Time Stamp High [31:0] | + ----------------------------------------------------------------------------------------------*/ + +/* Bit definition of TDES6 register */ + #define ETH_DMAPTPTXDESC_TTSL ((uint32_t)0xFFFFFFFFU) /* Transmit Time Stamp Low */ + +/* Bit definition of TDES7 register */ + #define ETH_DMAPTPTXDESC_TTSH ((uint32_t)0xFFFFFFFFU) /* Transmit Time Stamp High */ + +/** + * @} + */ +/** @defgroup ETH_DMA_RX_Descriptor ETH DMA RX Descriptor + * @{ + */ + +/* + DMA Rx Descriptor + -------------------------------------------------------------------------------------------------------------------- + RDES0 | OWN(31) | Status [30:0] | + --------------------------------------------------------------------------------------------------------------------- + RDES1 | CTRL(31) | Reserved[30:29] | Buffer2 ByteCount[28:16] | CTRL[15:14] | Reserved(13) | Buffer1 ByteCount[12:0] | + --------------------------------------------------------------------------------------------------------------------- + RDES2 | Buffer1 Address [31:0] | + --------------------------------------------------------------------------------------------------------------------- + RDES3 | Buffer2 Address [31:0] / Next Descriptor Address [31:0] | + --------------------------------------------------------------------------------------------------------------------- +*/ + +/** + * @brief Bit definition of RDES0 register: DMA Rx descriptor status register + */ +#define ETH_DMARXDESC_OWN ((uint32_t)0x80000000U) /*!< OWN bit: descriptor is owned by DMA engine */ +#define ETH_DMARXDESC_AFM ((uint32_t)0x40000000U) /*!< DA Filter Fail for the rx frame */ +#define ETH_DMARXDESC_FL ((uint32_t)0x3FFF0000U) /*!< Receive descriptor frame length */ +#define ETH_DMARXDESC_ES ((uint32_t)0x00008000U) /*!< Error summary: OR of the following bits: DE || OE || IPC || LC || RWT || RE || CE */ +#define ETH_DMARXDESC_DE ((uint32_t)0x00004000U) /*!< Descriptor error: no more descriptors for receive frame */ +#define ETH_DMARXDESC_SAF ((uint32_t)0x00002000U) /*!< SA Filter Fail for the received frame */ +#define ETH_DMARXDESC_LE ((uint32_t)0x00001000U) /*!< Frame size not matching with length field */ +#define ETH_DMARXDESC_OE ((uint32_t)0x00000800U) /*!< Overflow Error: Frame was damaged due to buffer overflow */ +#define ETH_DMARXDESC_VLAN ((uint32_t)0x00000400U) /*!< VLAN Tag: received frame is a VLAN frame */ +#define ETH_DMARXDESC_FS ((uint32_t)0x00000200U) /*!< First descriptor of the frame */ +#define ETH_DMARXDESC_LS ((uint32_t)0x00000100U) /*!< Last descriptor of the frame */ +#define ETH_DMARXDESC_IPV4HCE ((uint32_t)0x00000080U) /*!< IPC Checksum Error: Rx Ipv4 header checksum error */ +#define ETH_DMARXDESC_LC ((uint32_t)0x00000040U) /*!< Late collision occurred during reception */ +#define ETH_DMARXDESC_FT ((uint32_t)0x00000020U) /*!< Frame type - Ethernet, otherwise 802.3 */ +#define ETH_DMARXDESC_RWT ((uint32_t)0x00000010U) /*!< Receive Watchdog Timeout: watchdog timer expired during reception */ +#define ETH_DMARXDESC_RE ((uint32_t)0x00000008U) /*!< Receive error: error reported by MII interface */ +#define ETH_DMARXDESC_DBE ((uint32_t)0x00000004U) /*!< Dribble bit error: frame contains non int multiple of 8 bits */ +#define ETH_DMARXDESC_CE ((uint32_t)0x00000002U) /*!< CRC error */ +#define ETH_DMARXDESC_MAMPCE ((uint32_t)0x00000001U) /*!< Rx MAC Address/Payload Checksum Error: Rx MAC address matched/ Rx Payload Checksum Error */ + +/** + * @brief Bit definition of RDES1 register + */ +#define ETH_DMARXDESC_DIC ((uint32_t)0x80000000U) /*!< Disable Interrupt on Completion */ +#define ETH_DMARXDESC_RBS2 ((uint32_t)0x1FFF0000U) /*!< Receive Buffer2 Size */ +#define ETH_DMARXDESC_RER ((uint32_t)0x00008000U) /*!< Receive End of Ring */ +#define ETH_DMARXDESC_RCH ((uint32_t)0x00004000U) /*!< Second Address Chained */ +#define ETH_DMARXDESC_RBS1 ((uint32_t)0x00001FFFU) /*!< Receive Buffer1 Size */ + +/** + * @brief Bit definition of RDES2 register + */ +#define ETH_DMARXDESC_B1AP ((uint32_t)0xFFFFFFFFU) /*!< Buffer1 Address Pointer */ + +/** + * @brief Bit definition of RDES3 register + */ +#define ETH_DMARXDESC_B2AP ((uint32_t)0xFFFFFFFFU) /*!< Buffer2 Address Pointer */ + +/*--------------------------------------------------------------------------------------------------------------------- + RDES4 | Reserved[31:15] | Extended Status [14:0] | + --------------------------------------------------------------------------------------------------------------------- + RDES5 | Reserved[31:0] | + --------------------------------------------------------------------------------------------------------------------- + RDES6 | Receive Time Stamp Low [31:0] | + --------------------------------------------------------------------------------------------------------------------- + RDES7 | Receive Time Stamp High [31:0] | + --------------------------------------------------------------------------------------------------------------------*/ + +/* Bit definition of RDES4 register */ +#define ETH_DMAPTPRXDESC_PTPV ((uint32_t)0x00002000U) /* PTP Version */ +#define ETH_DMAPTPRXDESC_PTPFT ((uint32_t)0x00001000U) /* PTP Frame Type */ +#define ETH_DMAPTPRXDESC_PTPMT ((uint32_t)0x00000F00U) /* PTP Message Type */ + #define ETH_DMAPTPRXDESC_PTPMT_SYNC ((uint32_t)0x00000100U) /* SYNC message (all clock types) */ + #define ETH_DMAPTPRXDESC_PTPMT_FOLLOWUP ((uint32_t)0x00000200U) /* FollowUp message (all clock types) */ + #define ETH_DMAPTPRXDESC_PTPMT_DELAYREQ ((uint32_t)0x00000300U) /* DelayReq message (all clock types) */ + #define ETH_DMAPTPRXDESC_PTPMT_DELAYRESP ((uint32_t)0x00000400U) /* DelayResp message (all clock types) */ + #define ETH_DMAPTPRXDESC_PTPMT_PDELAYREQ_ANNOUNCE ((uint32_t)0x00000500U) /* PdelayReq message (peer-to-peer transparent clock) or Announce message (Ordinary or Boundary clock) */ + #define ETH_DMAPTPRXDESC_PTPMT_PDELAYRESP_MANAG ((uint32_t)0x00000600U) /* PdelayResp message (peer-to-peer transparent clock) or Management message (Ordinary or Boundary clock) */ + #define ETH_DMAPTPRXDESC_PTPMT_PDELAYRESPFOLLOWUP_SIGNAL ((uint32_t)0x00000700U) /* PdelayRespFollowUp message (peer-to-peer transparent clock) or Signaling message (Ordinary or Boundary clock) */ +#define ETH_DMAPTPRXDESC_IPV6PR ((uint32_t)0x00000080U) /* IPv6 Packet Received */ +#define ETH_DMAPTPRXDESC_IPV4PR ((uint32_t)0x00000040U) /* IPv4 Packet Received */ +#define ETH_DMAPTPRXDESC_IPCB ((uint32_t)0x00000020U) /* IP Checksum Bypassed */ +#define ETH_DMAPTPRXDESC_IPPE ((uint32_t)0x00000010U) /* IP Payload Error */ +#define ETH_DMAPTPRXDESC_IPHE ((uint32_t)0x00000008U) /* IP Header Error */ +#define ETH_DMAPTPRXDESC_IPPT ((uint32_t)0x00000007U) /* IP Payload Type */ + #define ETH_DMAPTPRXDESC_IPPT_UDP ((uint32_t)0x00000001U) /* UDP payload encapsulated in the IP datagram */ + #define ETH_DMAPTPRXDESC_IPPT_TCP ((uint32_t)0x00000002U) /* TCP payload encapsulated in the IP datagram */ + #define ETH_DMAPTPRXDESC_IPPT_ICMP ((uint32_t)0x00000003U) /* ICMP payload encapsulated in the IP datagram */ + +/* Bit definition of RDES6 register */ +#define ETH_DMAPTPRXDESC_RTSL ((uint32_t)0xFFFFFFFFU) /* Receive Time Stamp Low */ + +/* Bit definition of RDES7 register */ +#define ETH_DMAPTPRXDESC_RTSH ((uint32_t)0xFFFFFFFFU) /* Receive Time Stamp High */ +/** + * @} + */ + /** @defgroup ETH_AutoNegotiation ETH AutoNegotiation + * @{ + */ +#define ETH_AUTONEGOTIATION_ENABLE ((uint32_t)0x00000001U) +#define ETH_AUTONEGOTIATION_DISABLE ((uint32_t)0x00000000U) + +/** + * @} + */ +/** @defgroup ETH_Speed ETH Speed + * @{ + */ +#define ETH_SPEED_10M ((uint32_t)0x00000000U) +#define ETH_SPEED_100M ((uint32_t)0x00004000U) + +/** + * @} + */ +/** @defgroup ETH_Duplex_Mode ETH Duplex Mode + * @{ + */ +#define ETH_MODE_FULLDUPLEX ((uint32_t)0x00000800U) +#define ETH_MODE_HALFDUPLEX ((uint32_t)0x00000000U) +/** + * @} + */ +/** @defgroup ETH_Rx_Mode ETH Rx Mode + * @{ + */ +#define ETH_RXPOLLING_MODE ((uint32_t)0x00000000U) +#define ETH_RXINTERRUPT_MODE ((uint32_t)0x00000001U) +/** + * @} + */ + +/** @defgroup ETH_Checksum_Mode ETH Checksum Mode + * @{ + */ +#define ETH_CHECKSUM_BY_HARDWARE ((uint32_t)0x00000000U) +#define ETH_CHECKSUM_BY_SOFTWARE ((uint32_t)0x00000001U) +/** + * @} + */ + +/** @defgroup ETH_Media_Interface ETH Media Interface + * @{ + */ +#define ETH_MEDIA_INTERFACE_MII ((uint32_t)0x00000000U) +#define ETH_MEDIA_INTERFACE_RMII ((uint32_t)SYSCFG_PMC_MII_RMII_SEL) +/** + * @} + */ + +/** @defgroup ETH_Watchdog ETH Watchdog + * @{ + */ +#define ETH_WATCHDOG_ENABLE ((uint32_t)0x00000000U) +#define ETH_WATCHDOG_DISABLE ((uint32_t)0x00800000U) +/** + * @} + */ + +/** @defgroup ETH_Jabber ETH Jabber + * @{ + */ +#define ETH_JABBER_ENABLE ((uint32_t)0x00000000U) +#define ETH_JABBER_DISABLE ((uint32_t)0x00400000U) +/** + * @} + */ + +/** @defgroup ETH_Inter_Frame_Gap ETH Inter Frame Gap + * @{ + */ +#define ETH_INTERFRAMEGAP_96BIT ((uint32_t)0x00000000U) /*!< minimum IFG between frames during transmission is 96Bit */ +#define ETH_INTERFRAMEGAP_88BIT ((uint32_t)0x00020000U) /*!< minimum IFG between frames during transmission is 88Bit */ +#define ETH_INTERFRAMEGAP_80BIT ((uint32_t)0x00040000U) /*!< minimum IFG between frames during transmission is 80Bit */ +#define ETH_INTERFRAMEGAP_72BIT ((uint32_t)0x00060000U) /*!< minimum IFG between frames during transmission is 72Bit */ +#define ETH_INTERFRAMEGAP_64BIT ((uint32_t)0x00080000U) /*!< minimum IFG between frames during transmission is 64Bit */ +#define ETH_INTERFRAMEGAP_56BIT ((uint32_t)0x000A0000U) /*!< minimum IFG between frames during transmission is 56Bit */ +#define ETH_INTERFRAMEGAP_48BIT ((uint32_t)0x000C0000U) /*!< minimum IFG between frames during transmission is 48Bit */ +#define ETH_INTERFRAMEGAP_40BIT ((uint32_t)0x000E0000U) /*!< minimum IFG between frames during transmission is 40Bit */ +/** + * @} + */ + +/** @defgroup ETH_Carrier_Sense ETH Carrier Sense + * @{ + */ +#define ETH_CARRIERSENCE_ENABLE ((uint32_t)0x00000000U) +#define ETH_CARRIERSENCE_DISABLE ((uint32_t)0x00010000U) +/** + * @} + */ + +/** @defgroup ETH_Receive_Own ETH Receive Own + * @{ + */ +#define ETH_RECEIVEOWN_ENABLE ((uint32_t)0x00000000U) +#define ETH_RECEIVEOWN_DISABLE ((uint32_t)0x00002000U) +/** + * @} + */ + +/** @defgroup ETH_Loop_Back_Mode ETH Loop Back Mode + * @{ + */ +#define ETH_LOOPBACKMODE_ENABLE ((uint32_t)0x00001000U) +#define ETH_LOOPBACKMODE_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Checksum_Offload ETH Checksum Offload + * @{ + */ +#define ETH_CHECKSUMOFFLAOD_ENABLE ((uint32_t)0x00000400U) +#define ETH_CHECKSUMOFFLAOD_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Retry_Transmission ETH Retry Transmission + * @{ + */ +#define ETH_RETRYTRANSMISSION_ENABLE ((uint32_t)0x00000000U) +#define ETH_RETRYTRANSMISSION_DISABLE ((uint32_t)0x00000200U) +/** + * @} + */ + +/** @defgroup ETH_Automatic_Pad_CRC_Strip ETH Automatic Pad CRC Strip + * @{ + */ +#define ETH_AUTOMATICPADCRCSTRIP_ENABLE ((uint32_t)0x00000080U) +#define ETH_AUTOMATICPADCRCSTRIP_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Back_Off_Limit ETH Back Off Limit + * @{ + */ +#define ETH_BACKOFFLIMIT_10 ((uint32_t)0x00000000U) +#define ETH_BACKOFFLIMIT_8 ((uint32_t)0x00000020U) +#define ETH_BACKOFFLIMIT_4 ((uint32_t)0x00000040U) +#define ETH_BACKOFFLIMIT_1 ((uint32_t)0x00000060U) +/** + * @} + */ + +/** @defgroup ETH_Deferral_Check ETH Deferral Check + * @{ + */ +#define ETH_DEFFERRALCHECK_ENABLE ((uint32_t)0x00000010U) +#define ETH_DEFFERRALCHECK_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Receive_All ETH Receive All + * @{ + */ +#define ETH_RECEIVEALL_ENABLE ((uint32_t)0x80000000U) +#define ETH_RECEIVEAll_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Source_Addr_Filter ETH Source Addr Filter + * @{ + */ +#define ETH_SOURCEADDRFILTER_NORMAL_ENABLE ((uint32_t)0x00000200U) +#define ETH_SOURCEADDRFILTER_INVERSE_ENABLE ((uint32_t)0x00000300U) +#define ETH_SOURCEADDRFILTER_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Pass_Control_Frames ETH Pass Control Frames + * @{ + */ +#define ETH_PASSCONTROLFRAMES_BLOCKALL ((uint32_t)0x00000040U) /*!< MAC filters all control frames from reaching the application */ +#define ETH_PASSCONTROLFRAMES_FORWARDALL ((uint32_t)0x00000080U) /*!< MAC forwards all control frames to application even if they fail the Address Filter */ +#define ETH_PASSCONTROLFRAMES_FORWARDPASSEDADDRFILTER ((uint32_t)0x000000C0U) /*!< MAC forwards control frames that pass the Address Filter. */ +/** + * @} + */ + +/** @defgroup ETH_Broadcast_Frames_Reception ETH Broadcast Frames Reception + * @{ + */ +#define ETH_BROADCASTFRAMESRECEPTION_ENABLE ((uint32_t)0x00000000U) +#define ETH_BROADCASTFRAMESRECEPTION_DISABLE ((uint32_t)0x00000020U) +/** + * @} + */ + +/** @defgroup ETH_Destination_Addr_Filter ETH Destination Addr Filter + * @{ + */ +#define ETH_DESTINATIONADDRFILTER_NORMAL ((uint32_t)0x00000000U) +#define ETH_DESTINATIONADDRFILTER_INVERSE ((uint32_t)0x00000008U) +/** + * @} + */ + +/** @defgroup ETH_Promiscuous_Mode ETH Promiscuous Mode + * @{ + */ +#define ETH_PROMISCUOUS_MODE_ENABLE ((uint32_t)0x00000001U) +#define ETH_PROMISCUOUS_MODE_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Multicast_Frames_Filter ETH Multicast Frames Filter + * @{ + */ +#define ETH_MULTICASTFRAMESFILTER_PERFECTHASHTABLE ((uint32_t)0x00000404U) +#define ETH_MULTICASTFRAMESFILTER_HASHTABLE ((uint32_t)0x00000004U) +#define ETH_MULTICASTFRAMESFILTER_PERFECT ((uint32_t)0x00000000U) +#define ETH_MULTICASTFRAMESFILTER_NONE ((uint32_t)0x00000010U) +/** + * @} + */ + +/** @defgroup ETH_Unicast_Frames_Filter ETH Unicast Frames Filter + * @{ + */ +#define ETH_UNICASTFRAMESFILTER_PERFECTHASHTABLE ((uint32_t)0x00000402U) +#define ETH_UNICASTFRAMESFILTER_HASHTABLE ((uint32_t)0x00000002U) +#define ETH_UNICASTFRAMESFILTER_PERFECT ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Zero_Quanta_Pause ETH Zero Quanta Pause + * @{ + */ +#define ETH_ZEROQUANTAPAUSE_ENABLE ((uint32_t)0x00000000U) +#define ETH_ZEROQUANTAPAUSE_DISABLE ((uint32_t)0x00000080U) +/** + * @} + */ + +/** @defgroup ETH_Pause_Low_Threshold ETH Pause Low Threshold + * @{ + */ +#define ETH_PAUSELOWTHRESHOLD_MINUS4 ((uint32_t)0x00000000U) /*!< Pause time minus 4 slot times */ +#define ETH_PAUSELOWTHRESHOLD_MINUS28 ((uint32_t)0x00000010U) /*!< Pause time minus 28 slot times */ +#define ETH_PAUSELOWTHRESHOLD_MINUS144 ((uint32_t)0x00000020U) /*!< Pause time minus 144 slot times */ +#define ETH_PAUSELOWTHRESHOLD_MINUS256 ((uint32_t)0x00000030U) /*!< Pause time minus 256 slot times */ +/** + * @} + */ + +/** @defgroup ETH_Unicast_Pause_Frame_Detect ETH Unicast Pause Frame Detect + * @{ + */ +#define ETH_UNICASTPAUSEFRAMEDETECT_ENABLE ((uint32_t)0x00000008U) +#define ETH_UNICASTPAUSEFRAMEDETECT_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Receive_Flow_Control ETH Receive Flow Control + * @{ + */ +#define ETH_RECEIVEFLOWCONTROL_ENABLE ((uint32_t)0x00000004U) +#define ETH_RECEIVEFLOWCONTROL_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Transmit_Flow_Control ETH Transmit Flow Control + * @{ + */ +#define ETH_TRANSMITFLOWCONTROL_ENABLE ((uint32_t)0x00000002U) +#define ETH_TRANSMITFLOWCONTROL_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_VLAN_Tag_Comparison ETH VLAN Tag Comparison + * @{ + */ +#define ETH_VLANTAGCOMPARISON_12BIT ((uint32_t)0x00010000U) +#define ETH_VLANTAGCOMPARISON_16BIT ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_MAC_addresses ETH MAC addresses + * @{ + */ +#define ETH_MAC_ADDRESS0 ((uint32_t)0x00000000U) +#define ETH_MAC_ADDRESS1 ((uint32_t)0x00000008U) +#define ETH_MAC_ADDRESS2 ((uint32_t)0x00000010U) +#define ETH_MAC_ADDRESS3 ((uint32_t)0x00000018U) +/** + * @} + */ + +/** @defgroup ETH_MAC_addresses_filter_SA_DA ETH MAC addresses filter SA DA + * @{ + */ +#define ETH_MAC_ADDRESSFILTER_SA ((uint32_t)0x00000000U) +#define ETH_MAC_ADDRESSFILTER_DA ((uint32_t)0x00000008U) +/** + * @} + */ + +/** @defgroup ETH_MAC_addresses_filter_Mask_bytes ETH MAC addresses filter Mask bytes + * @{ + */ +#define ETH_MAC_ADDRESSMASK_BYTE6 ((uint32_t)0x20000000U) /*!< Mask MAC Address high reg bits [15:8] */ +#define ETH_MAC_ADDRESSMASK_BYTE5 ((uint32_t)0x10000000U) /*!< Mask MAC Address high reg bits [7:0] */ +#define ETH_MAC_ADDRESSMASK_BYTE4 ((uint32_t)0x08000000U) /*!< Mask MAC Address low reg bits [31:24] */ +#define ETH_MAC_ADDRESSMASK_BYTE3 ((uint32_t)0x04000000U) /*!< Mask MAC Address low reg bits [23:16] */ +#define ETH_MAC_ADDRESSMASK_BYTE2 ((uint32_t)0x02000000U) /*!< Mask MAC Address low reg bits [15:8] */ +#define ETH_MAC_ADDRESSMASK_BYTE1 ((uint32_t)0x01000000U) /*!< Mask MAC Address low reg bits [70] */ +/** + * @} + */ + +/** @defgroup ETH_MAC_Debug_flags ETH MAC Debug flags + * @{ + */ +#define ETH_MAC_TXFIFO_FULL ((uint32_t)0x02000000) /* Tx FIFO full */ +#define ETH_MAC_TXFIFONOT_EMPTY ((uint32_t)0x01000000) /* Tx FIFO not empty */ +#define ETH_MAC_TXFIFO_WRITE_ACTIVE ((uint32_t)0x00400000) /* Tx FIFO write active */ +#define ETH_MAC_TXFIFO_IDLE ((uint32_t)0x00000000) /* Tx FIFO read status: Idle */ +#define ETH_MAC_TXFIFO_READ ((uint32_t)0x00100000) /* Tx FIFO read status: Read (transferring data to the MAC transmitter) */ +#define ETH_MAC_TXFIFO_WAITING ((uint32_t)0x00200000) /* Tx FIFO read status: Waiting for TxStatus from MAC transmitter */ +#define ETH_MAC_TXFIFO_WRITING ((uint32_t)0x00300000) /* Tx FIFO read status: Writing the received TxStatus or flushing the TxFIFO */ +#define ETH_MAC_TRANSMISSION_PAUSE ((uint32_t)0x00080000) /* MAC transmitter in pause */ +#define ETH_MAC_TRANSMITFRAMECONTROLLER_IDLE ((uint32_t)0x00000000) /* MAC transmit frame controller: Idle */ +#define ETH_MAC_TRANSMITFRAMECONTROLLER_WAITING ((uint32_t)0x00020000) /* MAC transmit frame controller: Waiting for Status of previous frame or IFG/backoff period to be over */ +#define ETH_MAC_TRANSMITFRAMECONTROLLER_GENRATING_PCF ((uint32_t)0x00040000) /* MAC transmit frame controller: Generating and transmitting a Pause control frame (in full duplex mode) */ +#define ETH_MAC_TRANSMITFRAMECONTROLLER_TRANSFERRING ((uint32_t)0x00060000) /* MAC transmit frame controller: Transferring input frame for transmission */ +#define ETH_MAC_MII_TRANSMIT_ACTIVE ((uint32_t)0x00010000) /* MAC MII transmit engine active */ +#define ETH_MAC_RXFIFO_EMPTY ((uint32_t)0x00000000) /* Rx FIFO fill level: empty */ +#define ETH_MAC_RXFIFO_BELOW_THRESHOLD ((uint32_t)0x00000100) /* Rx FIFO fill level: fill-level below flow-control de-activate threshold */ +#define ETH_MAC_RXFIFO_ABOVE_THRESHOLD ((uint32_t)0x00000200) /* Rx FIFO fill level: fill-level above flow-control activate threshold */ +#define ETH_MAC_RXFIFO_FULL ((uint32_t)0x00000300) /* Rx FIFO fill level: full */ +#define ETH_MAC_READCONTROLLER_IDLE ((uint32_t)0x00000060) /* Rx FIFO read controller IDLE state */ +#define ETH_MAC_READCONTROLLER_READING_DATA ((uint32_t)0x00000060) /* Rx FIFO read controller Reading frame data */ +#define ETH_MAC_READCONTROLLER_READING_STATUS ((uint32_t)0x00000060) /* Rx FIFO read controller Reading frame status (or time-stamp) */ +#define ETH_MAC_READCONTROLLER_ FLUSHING ((uint32_t)0x00000060) /* Rx FIFO read controller Flushing the frame data and status */ +#define ETH_MAC_RXFIFO_WRITE_ACTIVE ((uint32_t)0x00000010) /* Rx FIFO write controller active */ +#define ETH_MAC_SMALL_FIFO_NOTACTIVE ((uint32_t)0x00000000) /* MAC small FIFO read / write controllers not active */ +#define ETH_MAC_SMALL_FIFO_READ_ACTIVE ((uint32_t)0x00000002) /* MAC small FIFO read controller active */ +#define ETH_MAC_SMALL_FIFO_WRITE_ACTIVE ((uint32_t)0x00000004) /* MAC small FIFO write controller active */ +#define ETH_MAC_SMALL_FIFO_RW_ACTIVE ((uint32_t)0x00000006) /* MAC small FIFO read / write controllers active */ +#define ETH_MAC_MII_RECEIVE_PROTOCOL_ACTIVE ((uint32_t)0x00000001) /* MAC MII receive protocol engine active */ +/** + * @} + */ + +/** @defgroup ETH_Drop_TCP_IP_Checksum_Error_Frame ETH Drop TCP IP Checksum Error Frame + * @{ + */ +#define ETH_DROPTCPIPCHECKSUMERRORFRAME_ENABLE ((uint32_t)0x00000000U) +#define ETH_DROPTCPIPCHECKSUMERRORFRAME_DISABLE ((uint32_t)0x04000000U) +/** + * @} + */ + +/** @defgroup ETH_Receive_Store_Forward ETH Receive Store Forward + * @{ + */ +#define ETH_RECEIVESTOREFORWARD_ENABLE ((uint32_t)0x02000000U) +#define ETH_RECEIVESTOREFORWARD_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Flush_Received_Frame ETH Flush Received Frame + * @{ + */ +#define ETH_FLUSHRECEIVEDFRAME_ENABLE ((uint32_t)0x00000000U) +#define ETH_FLUSHRECEIVEDFRAME_DISABLE ((uint32_t)0x01000000U) +/** + * @} + */ + +/** @defgroup ETH_Transmit_Store_Forward ETH Transmit Store Forward + * @{ + */ +#define ETH_TRANSMITSTOREFORWARD_ENABLE ((uint32_t)0x00200000U) +#define ETH_TRANSMITSTOREFORWARD_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Transmit_Threshold_Control ETH Transmit Threshold Control + * @{ + */ +#define ETH_TRANSMITTHRESHOLDCONTROL_64BYTES ((uint32_t)0x00000000U) /*!< threshold level of the MTL Transmit FIFO is 64 Bytes */ +#define ETH_TRANSMITTHRESHOLDCONTROL_128BYTES ((uint32_t)0x00004000U) /*!< threshold level of the MTL Transmit FIFO is 128 Bytes */ +#define ETH_TRANSMITTHRESHOLDCONTROL_192BYTES ((uint32_t)0x00008000U) /*!< threshold level of the MTL Transmit FIFO is 192 Bytes */ +#define ETH_TRANSMITTHRESHOLDCONTROL_256BYTES ((uint32_t)0x0000C000U) /*!< threshold level of the MTL Transmit FIFO is 256 Bytes */ +#define ETH_TRANSMITTHRESHOLDCONTROL_40BYTES ((uint32_t)0x00010000U) /*!< threshold level of the MTL Transmit FIFO is 40 Bytes */ +#define ETH_TRANSMITTHRESHOLDCONTROL_32BYTES ((uint32_t)0x00014000U) /*!< threshold level of the MTL Transmit FIFO is 32 Bytes */ +#define ETH_TRANSMITTHRESHOLDCONTROL_24BYTES ((uint32_t)0x00018000U) /*!< threshold level of the MTL Transmit FIFO is 24 Bytes */ +#define ETH_TRANSMITTHRESHOLDCONTROL_16BYTES ((uint32_t)0x0001C000U) /*!< threshold level of the MTL Transmit FIFO is 16 Bytes */ +/** + * @} + */ + +/** @defgroup ETH_Forward_Error_Frames ETH Forward Error Frames + * @{ + */ +#define ETH_FORWARDERRORFRAMES_ENABLE ((uint32_t)0x00000080U) +#define ETH_FORWARDERRORFRAMES_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Forward_Undersized_Good_Frames ETH Forward Undersized Good Frames + * @{ + */ +#define ETH_FORWARDUNDERSIZEDGOODFRAMES_ENABLE ((uint32_t)0x00000040U) +#define ETH_FORWARDUNDERSIZEDGOODFRAMES_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Receive_Threshold_Control ETH Receive Threshold Control + * @{ + */ +#define ETH_RECEIVEDTHRESHOLDCONTROL_64BYTES ((uint32_t)0x00000000U) /*!< threshold level of the MTL Receive FIFO is 64 Bytes */ +#define ETH_RECEIVEDTHRESHOLDCONTROL_32BYTES ((uint32_t)0x00000008U) /*!< threshold level of the MTL Receive FIFO is 32 Bytes */ +#define ETH_RECEIVEDTHRESHOLDCONTROL_96BYTES ((uint32_t)0x00000010U) /*!< threshold level of the MTL Receive FIFO is 96 Bytes */ +#define ETH_RECEIVEDTHRESHOLDCONTROL_128BYTES ((uint32_t)0x00000018U) /*!< threshold level of the MTL Receive FIFO is 128 Bytes */ +/** + * @} + */ + +/** @defgroup ETH_Second_Frame_Operate ETH Second Frame Operate + * @{ + */ +#define ETH_SECONDFRAMEOPERARTE_ENABLE ((uint32_t)0x00000004U) +#define ETH_SECONDFRAMEOPERARTE_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Address_Aligned_Beats ETH Address Aligned Beats + * @{ + */ +#define ETH_ADDRESSALIGNEDBEATS_ENABLE ((uint32_t)0x02000000U) +#define ETH_ADDRESSALIGNEDBEATS_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Fixed_Burst ETH Fixed Burst + * @{ + */ +#define ETH_FIXEDBURST_ENABLE ((uint32_t)0x00010000U) +#define ETH_FIXEDBURST_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_Rx_DMA_Burst_Length ETH Rx DMA Burst Length + * @{ + */ +#define ETH_RXDMABURSTLENGTH_1BEAT ((uint32_t)0x00020000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 1 */ +#define ETH_RXDMABURSTLENGTH_2BEAT ((uint32_t)0x00040000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 2 */ +#define ETH_RXDMABURSTLENGTH_4BEAT ((uint32_t)0x00080000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 4 */ +#define ETH_RXDMABURSTLENGTH_8BEAT ((uint32_t)0x00100000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 8 */ +#define ETH_RXDMABURSTLENGTH_16BEAT ((uint32_t)0x00200000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 16 */ +#define ETH_RXDMABURSTLENGTH_32BEAT ((uint32_t)0x00400000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 32 */ +#define ETH_RXDMABURSTLENGTH_4XPBL_4BEAT ((uint32_t)0x01020000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 4 */ +#define ETH_RXDMABURSTLENGTH_4XPBL_8BEAT ((uint32_t)0x01040000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 8 */ +#define ETH_RXDMABURSTLENGTH_4XPBL_16BEAT ((uint32_t)0x01080000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 16 */ +#define ETH_RXDMABURSTLENGTH_4XPBL_32BEAT ((uint32_t)0x01100000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 32 */ +#define ETH_RXDMABURSTLENGTH_4XPBL_64BEAT ((uint32_t)0x01200000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 64 */ +#define ETH_RXDMABURSTLENGTH_4XPBL_128BEAT ((uint32_t)0x01400000U) /*!< maximum number of beats to be transferred in one RxDMA transaction is 128 */ +/** + * @} + */ + +/** @defgroup ETH_Tx_DMA_Burst_Length ETH Tx DMA Burst Length + * @{ + */ +#define ETH_TXDMABURSTLENGTH_1BEAT ((uint32_t)0x00000100U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 1 */ +#define ETH_TXDMABURSTLENGTH_2BEAT ((uint32_t)0x00000200U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 2 */ +#define ETH_TXDMABURSTLENGTH_4BEAT ((uint32_t)0x00000400U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 4 */ +#define ETH_TXDMABURSTLENGTH_8BEAT ((uint32_t)0x00000800U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 8 */ +#define ETH_TXDMABURSTLENGTH_16BEAT ((uint32_t)0x00001000U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 16 */ +#define ETH_TXDMABURSTLENGTH_32BEAT ((uint32_t)0x00002000U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 32 */ +#define ETH_TXDMABURSTLENGTH_4XPBL_4BEAT ((uint32_t)0x01000100U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 4 */ +#define ETH_TXDMABURSTLENGTH_4XPBL_8BEAT ((uint32_t)0x01000200U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 8 */ +#define ETH_TXDMABURSTLENGTH_4XPBL_16BEAT ((uint32_t)0x01000400U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 16 */ +#define ETH_TXDMABURSTLENGTH_4XPBL_32BEAT ((uint32_t)0x01000800U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 32 */ +#define ETH_TXDMABURSTLENGTH_4XPBL_64BEAT ((uint32_t)0x01001000U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 64 */ +#define ETH_TXDMABURSTLENGTH_4XPBL_128BEAT ((uint32_t)0x01002000U) /*!< maximum number of beats to be transferred in one TxDMA (or both) transaction is 128 */ +/** + * @} + */ + +/** @defgroup ETH_DMA_Enhanced_descriptor_format ETH DMA Enhanced descriptor format + * @{ + */ +#define ETH_DMAENHANCEDDESCRIPTOR_ENABLE ((uint32_t)0x00000080U) +#define ETH_DMAENHANCEDDESCRIPTOR_DISABLE ((uint32_t)0x00000000U) +/** + * @} + */ + +/** @defgroup ETH_DMA_Arbitration ETH DMA Arbitration + * @{ + */ +#define ETH_DMAARBITRATION_ROUNDROBIN_RXTX_1_1 ((uint32_t)0x00000000U) +#define ETH_DMAARBITRATION_ROUNDROBIN_RXTX_2_1 ((uint32_t)0x00004000U) +#define ETH_DMAARBITRATION_ROUNDROBIN_RXTX_3_1 ((uint32_t)0x00008000U) +#define ETH_DMAARBITRATION_ROUNDROBIN_RXTX_4_1 ((uint32_t)0x0000C000U) +#define ETH_DMAARBITRATION_RXPRIORTX ((uint32_t)0x00000002U) +/** + * @} + */ + +/** @defgroup ETH_DMA_Tx_descriptor_segment ETH DMA Tx descriptor segment + * @{ + */ +#define ETH_DMATXDESC_LASTSEGMENTS ((uint32_t)0x40000000U) /*!< Last Segment */ +#define ETH_DMATXDESC_FIRSTSEGMENT ((uint32_t)0x20000000U) /*!< First Segment */ +/** + * @} + */ + +/** @defgroup ETH_DMA_Tx_descriptor_Checksum_Insertion_Control ETH DMA Tx descriptor Checksum Insertion Control + * @{ + */ +#define ETH_DMATXDESC_CHECKSUMBYPASS ((uint32_t)0x00000000U) /*!< Checksum engine bypass */ +#define ETH_DMATXDESC_CHECKSUMIPV4HEADER ((uint32_t)0x00400000U) /*!< IPv4 header checksum insertion */ +#define ETH_DMATXDESC_CHECKSUMTCPUDPICMPSEGMENT ((uint32_t)0x00800000U) /*!< TCP/UDP/ICMP checksum insertion. Pseudo header checksum is assumed to be present */ +#define ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL ((uint32_t)0x00C00000U) /*!< TCP/UDP/ICMP checksum fully in hardware including pseudo header */ +/** + * @} + */ + +/** @defgroup ETH_DMA_Rx_descriptor_buffers ETH DMA Rx descriptor buffers + * @{ + */ +#define ETH_DMARXDESC_BUFFER1 ((uint32_t)0x00000000U) /*!< DMA Rx Desc Buffer1 */ +#define ETH_DMARXDESC_BUFFER2 ((uint32_t)0x00000001U) /*!< DMA Rx Desc Buffer2 */ +/** + * @} + */ + +/** @defgroup ETH_PMT_Flags ETH PMT Flags + * @{ + */ +#define ETH_PMT_FLAG_WUFFRPR ((uint32_t)0x80000000U) /*!< Wake-Up Frame Filter Register Pointer Reset */ +#define ETH_PMT_FLAG_WUFR ((uint32_t)0x00000040U) /*!< Wake-Up Frame Received */ +#define ETH_PMT_FLAG_MPR ((uint32_t)0x00000020U) /*!< Magic Packet Received */ +/** + * @} + */ + +/** @defgroup ETH_MMC_Tx_Interrupts ETH MMC Tx Interrupts + * @{ + */ +#define ETH_MMC_IT_TGF ((uint32_t)0x00200000U) /*!< When Tx good frame counter reaches half the maximum value */ +#define ETH_MMC_IT_TGFMSC ((uint32_t)0x00008000U) /*!< When Tx good multi col counter reaches half the maximum value */ +#define ETH_MMC_IT_TGFSC ((uint32_t)0x00004000U) /*!< When Tx good single col counter reaches half the maximum value */ +/** + * @} + */ + +/** @defgroup ETH_MMC_Rx_Interrupts ETH MMC Rx Interrupts + * @{ + */ +#define ETH_MMC_IT_RGUF ((uint32_t)0x10020000U) /*!< When Rx good unicast frames counter reaches half the maximum value */ +#define ETH_MMC_IT_RFAE ((uint32_t)0x10000040U) /*!< When Rx alignment error counter reaches half the maximum value */ +#define ETH_MMC_IT_RFCE ((uint32_t)0x10000020U) /*!< When Rx crc error counter reaches half the maximum value */ +/** + * @} + */ + +/** @defgroup ETH_MAC_Flags ETH MAC Flags + * @{ + */ +#define ETH_MAC_FLAG_TST ((uint32_t)0x00000200U) /*!< Time stamp trigger flag (on MAC) */ +#define ETH_MAC_FLAG_MMCT ((uint32_t)0x00000040U) /*!< MMC transmit flag */ +#define ETH_MAC_FLAG_MMCR ((uint32_t)0x00000020U) /*!< MMC receive flag */ +#define ETH_MAC_FLAG_MMC ((uint32_t)0x00000010U) /*!< MMC flag (on MAC) */ +#define ETH_MAC_FLAG_PMT ((uint32_t)0x00000008U) /*!< PMT flag (on MAC) */ +/** + * @} + */ + +/** @defgroup ETH_DMA_Flags ETH DMA Flags + * @{ + */ +#define ETH_DMA_FLAG_TST ((uint32_t)0x20000000U) /*!< Time-stamp trigger interrupt (on DMA) */ +#define ETH_DMA_FLAG_PMT ((uint32_t)0x10000000U) /*!< PMT interrupt (on DMA) */ +#define ETH_DMA_FLAG_MMC ((uint32_t)0x08000000U) /*!< MMC interrupt (on DMA) */ +#define ETH_DMA_FLAG_DATATRANSFERERROR ((uint32_t)0x00800000U) /*!< Error bits 0-Rx DMA, 1-Tx DMA */ +#define ETH_DMA_FLAG_READWRITEERROR ((uint32_t)0x01000000U) /*!< Error bits 0-write transfer, 1-read transfer */ +#define ETH_DMA_FLAG_ACCESSERROR ((uint32_t)0x02000000U) /*!< Error bits 0-data buffer, 1-desc. access */ +#define ETH_DMA_FLAG_NIS ((uint32_t)0x00010000U) /*!< Normal interrupt summary flag */ +#define ETH_DMA_FLAG_AIS ((uint32_t)0x00008000U) /*!< Abnormal interrupt summary flag */ +#define ETH_DMA_FLAG_ER ((uint32_t)0x00004000U) /*!< Early receive flag */ +#define ETH_DMA_FLAG_FBE ((uint32_t)0x00002000U) /*!< Fatal bus error flag */ +#define ETH_DMA_FLAG_ET ((uint32_t)0x00000400U) /*!< Early transmit flag */ +#define ETH_DMA_FLAG_RWT ((uint32_t)0x00000200U) /*!< Receive watchdog timeout flag */ +#define ETH_DMA_FLAG_RPS ((uint32_t)0x00000100U) /*!< Receive process stopped flag */ +#define ETH_DMA_FLAG_RBU ((uint32_t)0x00000080U) /*!< Receive buffer unavailable flag */ +#define ETH_DMA_FLAG_R ((uint32_t)0x00000040U) /*!< Receive flag */ +#define ETH_DMA_FLAG_TU ((uint32_t)0x00000020U) /*!< Underflow flag */ +#define ETH_DMA_FLAG_RO ((uint32_t)0x00000010U) /*!< Overflow flag */ +#define ETH_DMA_FLAG_TJT ((uint32_t)0x00000008U) /*!< Transmit jabber timeout flag */ +#define ETH_DMA_FLAG_TBU ((uint32_t)0x00000004U) /*!< Transmit buffer unavailable flag */ +#define ETH_DMA_FLAG_TPS ((uint32_t)0x00000002U) /*!< Transmit process stopped flag */ +#define ETH_DMA_FLAG_T ((uint32_t)0x00000001U) /*!< Transmit flag */ +/** + * @} + */ + +/** @defgroup ETH_MAC_Interrupts ETH MAC Interrupts + * @{ + */ +#define ETH_MAC_IT_TST ((uint32_t)0x00000200U) /*!< Time stamp trigger interrupt (on MAC) */ +#define ETH_MAC_IT_MMCT ((uint32_t)0x00000040U) /*!< MMC transmit interrupt */ +#define ETH_MAC_IT_MMCR ((uint32_t)0x00000020U) /*!< MMC receive interrupt */ +#define ETH_MAC_IT_MMC ((uint32_t)0x00000010U) /*!< MMC interrupt (on MAC) */ +#define ETH_MAC_IT_PMT ((uint32_t)0x00000008U) /*!< PMT interrupt (on MAC) */ +/** + * @} + */ + +/** @defgroup ETH_DMA_Interrupts ETH DMA Interrupts + * @{ + */ +#define ETH_DMA_IT_TST ((uint32_t)0x20000000U) /*!< Time-stamp trigger interrupt (on DMA) */ +#define ETH_DMA_IT_PMT ((uint32_t)0x10000000U) /*!< PMT interrupt (on DMA) */ +#define ETH_DMA_IT_MMC ((uint32_t)0x08000000U) /*!< MMC interrupt (on DMA) */ +#define ETH_DMA_IT_NIS ((uint32_t)0x00010000U) /*!< Normal interrupt summary */ +#define ETH_DMA_IT_AIS ((uint32_t)0x00008000U) /*!< Abnormal interrupt summary */ +#define ETH_DMA_IT_ER ((uint32_t)0x00004000U) /*!< Early receive interrupt */ +#define ETH_DMA_IT_FBE ((uint32_t)0x00002000U) /*!< Fatal bus error interrupt */ +#define ETH_DMA_IT_ET ((uint32_t)0x00000400U) /*!< Early transmit interrupt */ +#define ETH_DMA_IT_RWT ((uint32_t)0x00000200U) /*!< Receive watchdog timeout interrupt */ +#define ETH_DMA_IT_RPS ((uint32_t)0x00000100U) /*!< Receive process stopped interrupt */ +#define ETH_DMA_IT_RBU ((uint32_t)0x00000080U) /*!< Receive buffer unavailable interrupt */ +#define ETH_DMA_IT_R ((uint32_t)0x00000040U) /*!< Receive interrupt */ +#define ETH_DMA_IT_TU ((uint32_t)0x00000020U) /*!< Underflow interrupt */ +#define ETH_DMA_IT_RO ((uint32_t)0x00000010U) /*!< Overflow interrupt */ +#define ETH_DMA_IT_TJT ((uint32_t)0x00000008U) /*!< Transmit jabber timeout interrupt */ +#define ETH_DMA_IT_TBU ((uint32_t)0x00000004U) /*!< Transmit buffer unavailable interrupt */ +#define ETH_DMA_IT_TPS ((uint32_t)0x00000002U) /*!< Transmit process stopped interrupt */ +#define ETH_DMA_IT_T ((uint32_t)0x00000001U) /*!< Transmit interrupt */ +/** + * @} + */ + +/** @defgroup ETH_DMA_transmit_process_state ETH DMA transmit process state + * @{ + */ +#define ETH_DMA_TRANSMITPROCESS_STOPPED ((uint32_t)0x00000000U) /*!< Stopped - Reset or Stop Tx Command issued */ +#define ETH_DMA_TRANSMITPROCESS_FETCHING ((uint32_t)0x00100000U) /*!< Running - fetching the Tx descriptor */ +#define ETH_DMA_TRANSMITPROCESS_WAITING ((uint32_t)0x00200000U) /*!< Running - waiting for status */ +#define ETH_DMA_TRANSMITPROCESS_READING ((uint32_t)0x00300000U) /*!< Running - reading the data from host memory */ +#define ETH_DMA_TRANSMITPROCESS_SUSPENDED ((uint32_t)0x00600000U) /*!< Suspended - Tx Descriptor unavailable */ +#define ETH_DMA_TRANSMITPROCESS_CLOSING ((uint32_t)0x00700000U) /*!< Running - closing Rx descriptor */ + +/** + * @} + */ + + +/** @defgroup ETH_DMA_receive_process_state ETH DMA receive process state + * @{ + */ +#define ETH_DMA_RECEIVEPROCESS_STOPPED ((uint32_t)0x00000000U) /*!< Stopped - Reset or Stop Rx Command issued */ +#define ETH_DMA_RECEIVEPROCESS_FETCHING ((uint32_t)0x00020000U) /*!< Running - fetching the Rx descriptor */ +#define ETH_DMA_RECEIVEPROCESS_WAITING ((uint32_t)0x00060000U) /*!< Running - waiting for packet */ +#define ETH_DMA_RECEIVEPROCESS_SUSPENDED ((uint32_t)0x00080000U) /*!< Suspended - Rx Descriptor unavailable */ +#define ETH_DMA_RECEIVEPROCESS_CLOSING ((uint32_t)0x000A0000U) /*!< Running - closing descriptor */ +#define ETH_DMA_RECEIVEPROCESS_QUEUING ((uint32_t)0x000E0000U) /*!< Running - queuing the receive frame into host memory */ + +/** + * @} + */ + +/** @defgroup ETH_DMA_overflow ETH DMA overflow + * @{ + */ +#define ETH_DMA_OVERFLOW_RXFIFOCOUNTER ((uint32_t)0x10000000U) /*!< Overflow bit for FIFO overflow counter */ +#define ETH_DMA_OVERFLOW_MISSEDFRAMECOUNTER ((uint32_t)0x00010000U) /*!< Overflow bit for missed frame counter */ +/** + * @} + */ + +/** @defgroup ETH_EXTI_LINE_WAKEUP ETH EXTI LINE WAKEUP + * @{ + */ +#define ETH_EXTI_LINE_WAKEUP ((uint32_t)0x00080000U) /*!< External interrupt line 19 Connected to the ETH EXTI Line */ + +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/** @defgroup ETH_Exported_Macros ETH Exported Macros + * @brief macros to handle interrupts and specific clock configurations + * @{ + */ + +/** @brief Reset ETH handle state + * @param __HANDLE__: specifies the ETH handle. + * @retval None + */ +#define __HAL_ETH_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = HAL_ETH_STATE_RESET) + +/** + * @brief Checks whether the specified Ethernet DMA Tx Desc flag is set or not. + * @param __HANDLE__: ETH Handle + * @param __FLAG__: specifies the flag of TDES0 to check. + * @retval the ETH_DMATxDescFlag (SET or RESET). + */ +#define __HAL_ETH_DMATXDESC_GET_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->TxDesc->Status & (__FLAG__) == (__FLAG__)) + +/** + * @brief Checks whether the specified Ethernet DMA Rx Desc flag is set or not. + * @param __HANDLE__: ETH Handle + * @param __FLAG__: specifies the flag of RDES0 to check. + * @retval the ETH_DMATxDescFlag (SET or RESET). + */ +#define __HAL_ETH_DMARXDESC_GET_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->RxDesc->Status & (__FLAG__) == (__FLAG__)) + +/** + * @brief Enables the specified DMA Rx Desc receive interrupt. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMARXDESC_ENABLE_IT(__HANDLE__) ((__HANDLE__)->RxDesc->ControlBufferSize &=(~(uint32_t)ETH_DMARXDESC_DIC)) + +/** + * @brief Disables the specified DMA Rx Desc receive interrupt. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMARXDESC_DISABLE_IT(__HANDLE__) ((__HANDLE__)->RxDesc->ControlBufferSize |= ETH_DMARXDESC_DIC) + +/** + * @brief Set the specified DMA Rx Desc Own bit. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMARXDESC_SET_OWN_BIT(__HANDLE__) ((__HANDLE__)->RxDesc->Status |= ETH_DMARXDESC_OWN) + +/** + * @brief Returns the specified Ethernet DMA Tx Desc collision count. + * @param __HANDLE__: ETH Handle + * @retval The Transmit descriptor collision counter value. + */ +#define __HAL_ETH_DMATXDESC_GET_COLLISION_COUNT(__HANDLE__) (((__HANDLE__)->TxDesc->Status & ETH_DMATXDESC_CC) >> ETH_DMATXDESC_COLLISION_COUNTSHIFT) + +/** + * @brief Set the specified DMA Tx Desc Own bit. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMATXDESC_SET_OWN_BIT(__HANDLE__) ((__HANDLE__)->TxDesc->Status |= ETH_DMATXDESC_OWN) + +/** + * @brief Enables the specified DMA Tx Desc Transmit interrupt. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMATXDESC_ENABLE_IT(__HANDLE__) ((__HANDLE__)->TxDesc->Status |= ETH_DMATXDESC_IC) + +/** + * @brief Disables the specified DMA Tx Desc Transmit interrupt. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMATXDESC_DISABLE_IT(__HANDLE__) ((__HANDLE__)->TxDesc->Status &= ~ETH_DMATXDESC_IC) + +/** + * @brief Selects the specified Ethernet DMA Tx Desc Checksum Insertion. + * @param __HANDLE__: ETH Handle + * @param __CHECKSUM__: specifies is the DMA Tx desc checksum insertion. + * This parameter can be one of the following values: + * @arg ETH_DMATXDESC_CHECKSUMBYPASS : Checksum bypass + * @arg ETH_DMATXDESC_CHECKSUMIPV4HEADER : IPv4 header checksum + * @arg ETH_DMATXDESC_CHECKSUMTCPUDPICMPSEGMENT : TCP/UDP/ICMP checksum. Pseudo header checksum is assumed to be present + * @arg ETH_DMATXDESC_CHECKSUMTCPUDPICMPFULL : TCP/UDP/ICMP checksum fully in hardware including pseudo header + * @retval None + */ +#define __HAL_ETH_DMATXDESC_CHECKSUM_INSERTION(__HANDLE__, __CHECKSUM__) ((__HANDLE__)->TxDesc->Status |= (__CHECKSUM__)) + +/** + * @brief Enables the DMA Tx Desc CRC. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMATXDESC_CRC_ENABLE(__HANDLE__) ((__HANDLE__)->TxDesc->Status &= ~ETH_DMATXDESC_DC) + +/** + * @brief Disables the DMA Tx Desc CRC. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMATXDESC_CRC_DISABLE(__HANDLE__) ((__HANDLE__)->TxDesc->Status |= ETH_DMATXDESC_DC) + +/** + * @brief Enables the DMA Tx Desc padding for frame shorter than 64 bytes. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMATXDESC_SHORT_FRAME_PADDING_ENABLE(__HANDLE__) ((__HANDLE__)->TxDesc->Status &= ~ETH_DMATXDESC_DP) + +/** + * @brief Disables the DMA Tx Desc padding for frame shorter than 64 bytes. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_DMATXDESC_SHORT_FRAME_PADDING_DISABLE(__HANDLE__) ((__HANDLE__)->TxDesc->Status |= ETH_DMATXDESC_DP) + +/** + * @brief Enables the specified Ethernet MAC interrupts. + * @param __HANDLE__ : ETH Handle + * @param __INTERRUPT__: specifies the Ethernet MAC interrupt sources to be + * enabled or disabled. + * This parameter can be any combination of the following values: + * @arg ETH_MAC_IT_TST : Time stamp trigger interrupt + * @arg ETH_MAC_IT_PMT : PMT interrupt + * @retval None + */ +#define __HAL_ETH_MAC_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->MACIMR |= (__INTERRUPT__)) + +/** + * @brief Disables the specified Ethernet MAC interrupts. + * @param __HANDLE__ : ETH Handle + * @param __INTERRUPT__: specifies the Ethernet MAC interrupt sources to be + * enabled or disabled. + * This parameter can be any combination of the following values: + * @arg ETH_MAC_IT_TST : Time stamp trigger interrupt + * @arg ETH_MAC_IT_PMT : PMT interrupt + * @retval None + */ +#define __HAL_ETH_MAC_DISABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->MACIMR &= ~(__INTERRUPT__)) + +/** + * @brief Initiate a Pause Control Frame (Full-duplex only). + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_INITIATE_PAUSE_CONTROL_FRAME(__HANDLE__) ((__HANDLE__)->Instance->MACFCR |= ETH_MACFCR_FCBBPA) + +/** + * @brief Checks whether the Ethernet flow control busy bit is set or not. + * @param __HANDLE__: ETH Handle + * @retval The new state of flow control busy status bit (SET or RESET). + */ +#define __HAL_ETH_GET_FLOW_CONTROL_BUSY_STATUS(__HANDLE__) (((__HANDLE__)->Instance->MACFCR & ETH_MACFCR_FCBBPA) == ETH_MACFCR_FCBBPA) + +/** + * @brief Enables the MAC Back Pressure operation activation (Half-duplex only). + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_BACK_PRESSURE_ACTIVATION_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MACFCR |= ETH_MACFCR_FCBBPA) + +/** + * @brief Disables the MAC BackPressure operation activation (Half-duplex only). + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_BACK_PRESSURE_ACTIVATION_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MACFCR &= ~ETH_MACFCR_FCBBPA) + +/** + * @brief Checks whether the specified Ethernet MAC flag is set or not. + * @param __HANDLE__: ETH Handle + * @param __FLAG__: specifies the flag to check. + * This parameter can be one of the following values: + * @arg ETH_MAC_FLAG_TST : Time stamp trigger flag + * @arg ETH_MAC_FLAG_MMCT : MMC transmit flag + * @arg ETH_MAC_FLAG_MMCR : MMC receive flag + * @arg ETH_MAC_FLAG_MMC : MMC flag + * @arg ETH_MAC_FLAG_PMT : PMT flag + * @retval The state of Ethernet MAC flag. + */ +#define __HAL_ETH_MAC_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->MACSR &( __FLAG__)) == ( __FLAG__)) + +/** + * @brief Enables the specified Ethernet DMA interrupts. + * @param __HANDLE__ : ETH Handle + * @param __INTERRUPT__: specifies the Ethernet DMA interrupt sources to be + * enabled @ref ETH_DMA_Interrupts + * @retval None + */ +#define __HAL_ETH_DMA_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->DMAIER |= (__INTERRUPT__)) + +/** + * @brief Disables the specified Ethernet DMA interrupts. + * @param __HANDLE__ : ETH Handle + * @param __INTERRUPT__: specifies the Ethernet DMA interrupt sources to be + * disabled. @ref ETH_DMA_Interrupts + * @retval None + */ +#define __HAL_ETH_DMA_DISABLE_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->DMAIER &= ~(__INTERRUPT__)) + +/** + * @brief Clears the Ethernet DMA IT pending bit. + * @param __HANDLE__ : ETH Handle + * @param __INTERRUPT__: specifies the interrupt pending bit to clear. @ref ETH_DMA_Interrupts + * @retval None + */ +#define __HAL_ETH_DMA_CLEAR_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->DMASR =(__INTERRUPT__)) + +/** + * @brief Checks whether the specified Ethernet DMA flag is set or not. +* @param __HANDLE__: ETH Handle + * @param __FLAG__: specifies the flag to check. @ref ETH_DMA_Flags + * @retval The new state of ETH_DMA_FLAG (SET or RESET). + */ +#define __HAL_ETH_DMA_GET_FLAG(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->DMASR &( __FLAG__)) == ( __FLAG__)) + +/** + * @brief Checks whether the specified Ethernet DMA flag is set or not. + * @param __HANDLE__: ETH Handle + * @param __FLAG__: specifies the flag to clear. @ref ETH_DMA_Flags + * @retval The new state of ETH_DMA_FLAG (SET or RESET). + */ +#define __HAL_ETH_DMA_CLEAR_FLAG(__HANDLE__, __FLAG__) ((__HANDLE__)->Instance->DMASR = (__FLAG__)) + +/** + * @brief Checks whether the specified Ethernet DMA overflow flag is set or not. + * @param __HANDLE__: ETH Handle + * @param __OVERFLOW__: specifies the DMA overflow flag to check. + * This parameter can be one of the following values: + * @arg ETH_DMA_OVERFLOW_RXFIFOCOUNTER : Overflow for FIFO Overflows Counter + * @arg ETH_DMA_OVERFLOW_MISSEDFRAMECOUNTER : Overflow for Buffer Unavailable Missed Frame Counter + * @retval The state of Ethernet DMA overflow Flag (SET or RESET). + */ +#define __HAL_ETH_GET_DMA_OVERFLOW_STATUS(__HANDLE__, __OVERFLOW__) (((__HANDLE__)->Instance->DMAMFBOCR & (__OVERFLOW__)) == (__OVERFLOW__)) + +/** + * @brief Set the DMA Receive status watchdog timer register value + * @param __HANDLE__: ETH Handle + * @param __VALUE__: DMA Receive status watchdog timer register value + * @retval None + */ +#define __HAL_ETH_SET_RECEIVE_WATCHDOG_TIMER(__HANDLE__, __VALUE__) ((__HANDLE__)->Instance->DMARSWTR = (__VALUE__)) + +/** + * @brief Enables any unicast packet filtered by the MAC address + * recognition to be a wake-up frame. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_GLOBAL_UNICAST_WAKEUP_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR |= ETH_MACPMTCSR_GU) + +/** + * @brief Disables any unicast packet filtered by the MAC address + * recognition to be a wake-up frame. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_GLOBAL_UNICAST_WAKEUP_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR &= ~ETH_MACPMTCSR_GU) + +/** + * @brief Enables the MAC Wake-Up Frame Detection. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_WAKEUP_FRAME_DETECTION_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR |= ETH_MACPMTCSR_WFE) + +/** + * @brief Disables the MAC Wake-Up Frame Detection. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_WAKEUP_FRAME_DETECTION_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR &= ~ETH_MACPMTCSR_WFE) + +/** + * @brief Enables the MAC Magic Packet Detection. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_MAGIC_PACKET_DETECTION_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR |= ETH_MACPMTCSR_MPE) + +/** + * @brief Disables the MAC Magic Packet Detection. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_MAGIC_PACKET_DETECTION_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR &= ~ETH_MACPMTCSR_WFE) + +/** + * @brief Enables the MAC Power Down. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_POWER_DOWN_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR |= ETH_MACPMTCSR_PD) + +/** + * @brief Disables the MAC Power Down. + * @param __HANDLE__: ETH Handle + * @retval None + */ +#define __HAL_ETH_POWER_DOWN_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MACPMTCSR &= ~ETH_MACPMTCSR_PD) + +/** + * @brief Checks whether the specified Ethernet PMT flag is set or not. + * @param __HANDLE__: ETH Handle. + * @param __FLAG__: specifies the flag to check. + * This parameter can be one of the following values: + * @arg ETH_PMT_FLAG_WUFFRPR : Wake-Up Frame Filter Register Pointer Reset + * @arg ETH_PMT_FLAG_WUFR : Wake-Up Frame Received + * @arg ETH_PMT_FLAG_MPR : Magic Packet Received + * @retval The new state of Ethernet PMT Flag (SET or RESET). + */ +#define __HAL_ETH_GET_PMT_FLAG_STATUS(__HANDLE__, __FLAG__) (((__HANDLE__)->Instance->MACPMTCSR &( __FLAG__)) == ( __FLAG__)) + +/** + * @brief Preset and Initialize the MMC counters to almost-full value: 0xFFFF_FFF0 (full - 16) + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_MMC_COUNTER_FULL_PRESET(__HANDLE__) ((__HANDLE__)->Instance->MMCCR |= (ETH_MMCCR_MCFHP | ETH_MMCCR_MCP)) + +/** + * @brief Preset and Initialize the MMC counters to almost-half value: 0x7FFF_FFF0 (half - 16) + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_MMC_COUNTER_HALF_PRESET(__HANDLE__) do{(__HANDLE__)->Instance->MMCCR &= ~ETH_MMCCR_MCFHP;\ + (__HANDLE__)->Instance->MMCCR |= ETH_MMCCR_MCP;} while (0) + +/** + * @brief Enables the MMC Counter Freeze. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_MMC_COUNTER_FREEZE_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MMCCR |= ETH_MMCCR_MCF) + +/** + * @brief Disables the MMC Counter Freeze. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_MMC_COUNTER_FREEZE_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MMCCR &= ~ETH_MMCCR_MCF) + +/** + * @brief Enables the MMC Reset On Read. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_ETH_MMC_RESET_ONREAD_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MMCCR |= ETH_MMCCR_ROR) + +/** + * @brief Disables the MMC Reset On Read. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_ETH_MMC_RESET_ONREAD_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MMCCR &= ~ETH_MMCCR_ROR) + +/** + * @brief Enables the MMC Counter Stop Rollover. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_ETH_MMC_COUNTER_ROLLOVER_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->MMCCR &= ~ETH_MMCCR_CSR) + +/** + * @brief Disables the MMC Counter Stop Rollover. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_ETH_MMC_COUNTER_ROLLOVER_DISABLE(__HANDLE__) ((__HANDLE__)->Instance->MMCCR |= ETH_MMCCR_CSR) + +/** + * @brief Resets the MMC Counters. + * @param __HANDLE__: ETH Handle. + * @retval None + */ +#define __HAL_ETH_MMC_COUNTERS_RESET(__HANDLE__) ((__HANDLE__)->Instance->MMCCR |= ETH_MMCCR_CR) + +/** + * @brief Enables the specified Ethernet MMC Rx interrupts. + * @param __HANDLE__: ETH Handle. + * @param __INTERRUPT__: specifies the Ethernet MMC interrupt sources to be enabled or disabled. + * This parameter can be one of the following values: + * @arg ETH_MMC_IT_RGUF : When Rx good unicast frames counter reaches half the maximum value + * @arg ETH_MMC_IT_RFAE : When Rx alignment error counter reaches half the maximum value + * @arg ETH_MMC_IT_RFCE : When Rx crc error counter reaches half the maximum value + * @retval None + */ +#define __HAL_ETH_MMC_RX_IT_ENABLE(__HANDLE__, __INTERRUPT__) (__HANDLE__)->Instance->MMCRIMR &= ~((__INTERRUPT__) & 0xEFFFFFFF) +/** + * @brief Disables the specified Ethernet MMC Rx interrupts. + * @param __HANDLE__: ETH Handle. + * @param __INTERRUPT__: specifies the Ethernet MMC interrupt sources to be enabled or disabled. + * This parameter can be one of the following values: + * @arg ETH_MMC_IT_RGUF : When Rx good unicast frames counter reaches half the maximum value + * @arg ETH_MMC_IT_RFAE : When Rx alignment error counter reaches half the maximum value + * @arg ETH_MMC_IT_RFCE : When Rx crc error counter reaches half the maximum value + * @retval None + */ +#define __HAL_ETH_MMC_RX_IT_DISABLE(__HANDLE__, __INTERRUPT__) (__HANDLE__)->Instance->MMCRIMR |= ((__INTERRUPT__) & 0xEFFFFFFF) +/** + * @brief Enables the specified Ethernet MMC Tx interrupts. + * @param __HANDLE__: ETH Handle. + * @param __INTERRUPT__: specifies the Ethernet MMC interrupt sources to be enabled or disabled. + * This parameter can be one of the following values: + * @arg ETH_MMC_IT_TGF : When Tx good frame counter reaches half the maximum value + * @arg ETH_MMC_IT_TGFMSC: When Tx good multi col counter reaches half the maximum value + * @arg ETH_MMC_IT_TGFSC : When Tx good single col counter reaches half the maximum value + * @retval None + */ +#define __HAL_ETH_MMC_TX_IT_ENABLE(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->MMCRIMR &= ~ (__INTERRUPT__)) + +/** + * @brief Disables the specified Ethernet MMC Tx interrupts. + * @param __HANDLE__: ETH Handle. + * @param __INTERRUPT__: specifies the Ethernet MMC interrupt sources to be enabled or disabled. + * This parameter can be one of the following values: + * @arg ETH_MMC_IT_TGF : When Tx good frame counter reaches half the maximum value + * @arg ETH_MMC_IT_TGFMSC: When Tx good multi col counter reaches half the maximum value + * @arg ETH_MMC_IT_TGFSC : When Tx good single col counter reaches half the maximum value + * @retval None + */ +#define __HAL_ETH_MMC_TX_IT_DISABLE(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->MMCRIMR |= (__INTERRUPT__)) + +/** + * @brief Enables the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_ENABLE_IT() EXTI->IMR |= (ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Disables the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_DISABLE_IT() EXTI->IMR &= ~(ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Enable event on ETH External event line. + * @retval None. + */ +#define __HAL_ETH_WAKEUP_EXTI_ENABLE_EVENT() EXTI->EMR |= (ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Disable event on ETH External event line + * @retval None. + */ +#define __HAL_ETH_WAKEUP_EXTI_DISABLE_EVENT() EXTI->EMR &= ~(ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Get flag of the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_GET_FLAG() EXTI->PR & (ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Clear flag of the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_CLEAR_FLAG() EXTI->PR = (ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Enables rising edge trigger to the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_ENABLE_RISING_EDGE_TRIGGER() EXTI->RTSR |= ETH_EXTI_LINE_WAKEUP + +/** + * @brief Disables the rising edge trigger to the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_DISABLE_RISING_EDGE_TRIGGER() EXTI->RTSR &= ~(ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Enables falling edge trigger to the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_ENABLE_FALLING_EDGE_TRIGGER() EXTI->FTSR |= (ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Disables falling edge trigger to the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_DISABLE_FALLING_EDGE_TRIGGER() EXTI->FTSR &= ~(ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Enables rising/falling edge trigger to the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_ENABLE_FALLINGRISING_TRIGGER() EXTI->RTSR |= ETH_EXTI_LINE_WAKEUP;\ + EXTI->FTSR |= ETH_EXTI_LINE_WAKEUP + +/** + * @brief Disables rising/falling edge trigger to the ETH External interrupt line. + * @retval None + */ +#define __HAL_ETH_WAKEUP_EXTI_DISABLE_FALLINGRISING_TRIGGER() EXTI->RTSR &= ~(ETH_EXTI_LINE_WAKEUP);\ + EXTI->FTSR &= ~(ETH_EXTI_LINE_WAKEUP) + +/** + * @brief Generate a Software interrupt on selected EXTI line. + * @retval None. + */ +#define __HAL_ETH_WAKEUP_EXTI_GENERATE_SWIT() EXTI->SWIER|= ETH_EXTI_LINE_WAKEUP + +/** + * @} + */ +/* Exported functions --------------------------------------------------------*/ + +/** @addtogroup ETH_Exported_Functions + * @{ + */ + +/* Initialization and de-initialization functions ****************************/ + +/** @addtogroup ETH_Exported_Functions_Group1 + * @{ + */ +HAL_StatusTypeDef HAL_ETH_Init(ETH_HandleTypeDef *heth); +HAL_StatusTypeDef HAL_ETH_DeInit(ETH_HandleTypeDef *heth); +void HAL_ETH_MspInit(ETH_HandleTypeDef *heth); +void HAL_ETH_MspDeInit(ETH_HandleTypeDef *heth); +HAL_StatusTypeDef HAL_ETH_DMATxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *DMATxDescTab, uint8_t* TxBuff, uint32_t TxBuffCount); +HAL_StatusTypeDef HAL_ETH_DMARxDescListInit(ETH_HandleTypeDef *heth, ETH_DMADescTypeDef *DMARxDescTab, uint8_t *RxBuff, uint32_t RxBuffCount); + +/** + * @} + */ +/* IO operation functions ****************************************************/ + +/** @addtogroup ETH_Exported_Functions_Group2 + * @{ + */ +HAL_StatusTypeDef HAL_ETH_TransmitFrame(ETH_HandleTypeDef *heth, uint32_t FrameLength); +HAL_StatusTypeDef HAL_ETH_GetReceivedFrame(ETH_HandleTypeDef *heth); +/* Communication with PHY functions*/ +HAL_StatusTypeDef HAL_ETH_ReadPHYRegister(ETH_HandleTypeDef *heth, uint16_t PHYReg, uint32_t *RegValue); +HAL_StatusTypeDef HAL_ETH_WritePHYRegister(ETH_HandleTypeDef *heth, uint16_t PHYReg, uint32_t RegValue); +/* Non-Blocking mode: Interrupt */ +HAL_StatusTypeDef HAL_ETH_GetReceivedFrame_IT(ETH_HandleTypeDef *heth); +void HAL_ETH_IRQHandler(ETH_HandleTypeDef *heth); +/* Callback in non blocking modes (Interrupt) */ +void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *heth); +void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth); +void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *heth); +/** + * @} + */ + +/* Peripheral Control functions **********************************************/ + +/** @addtogroup ETH_Exported_Functions_Group3 + * @{ + */ + +HAL_StatusTypeDef HAL_ETH_Start(ETH_HandleTypeDef *heth); +HAL_StatusTypeDef HAL_ETH_Stop(ETH_HandleTypeDef *heth); +HAL_StatusTypeDef HAL_ETH_ConfigMAC(ETH_HandleTypeDef *heth, ETH_MACInitTypeDef *macconf); +HAL_StatusTypeDef HAL_ETH_ConfigDMA(ETH_HandleTypeDef *heth, ETH_DMAInitTypeDef *dmaconf); +/** + * @} + */ + +/* Peripheral State functions ************************************************/ + +/** @addtogroup ETH_Exported_Functions_Group4 + * @{ + */ +HAL_ETH_StateTypeDef HAL_ETH_GetState(ETH_HandleTypeDef *heth); +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +#ifdef __cplusplus +} +#endif + +#endif /* __STM32Fxx_HAL_ETH_H */ + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/FaultInjection.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/FaultInjection.c new file mode 100644 index 000000000..e100a4e97 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/FaultInjection.c @@ -0,0 +1,173 @@ +#define xBUFFER_CACHE_SIZE 10 +#define xMAX_FAULT_INJECTION_RATE 15 +#define xMIN_FAULT_INJECTION_RATE 3 +#define xNUM_FAULT_TYPES 1 + +static NetworkBufferDescriptor_t *xNetworkBufferCache[ xBUFFER_CACHE_SIZE ] = { 0 }; + +#define xFAULT_LOG_SIZE 2048 +uint32_t ulInjectedFault[ xFAULT_LOG_SIZE ]; +uint32_t ulFaultLogIndex = 0; + +static BaseType_t prvCachePacket( NetworkBufferDescriptor_t *pxNetworkBufferIn ) +{ +BaseType_t x, xReturn = pdFALSE; + + for( x = 0; x < xBUFFER_CACHE_SIZE; x++ ) + { + if( xNetworkBufferCache[ x ] == NULL ) + { + xNetworkBufferCache[ x ] = pxNetworkBufferIn; + xReturn = pdTRUE; + break; + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static NetworkBufferDescriptor_t *prvGetCachedPacket( void ) +{ +BaseType_t x; +NetworkBufferDescriptor_t *pxReturn = NULL; + + for( x = ( xBUFFER_CACHE_SIZE - 1 ); x >= 0; x-- ) + { + if( xNetworkBufferCache[ x ] != NULL ) + { + pxReturn = xNetworkBufferCache[ x ]; + xNetworkBufferCache[ x ] = NULL; + break; + } + } + + return pxReturn; +} +/*-----------------------------------------------------------*/ + +static NetworkBufferDescriptor_t *prvDuplicatePacket( NetworkBufferDescriptor_t * pxOriginalPacket, const uint8_t *pucPacketData ) +{ +NetworkBufferDescriptor_t *pxReturn; + + /* Obtain a new descriptor. */ + pxReturn = pxGetNetworkBufferWithDescriptor( pxOriginalPacket->xDataLength, 0 ); + + if( pxReturn != NULL ) + { + /* Copy in the packet data. */ + pxReturn->xDataLength = pxOriginalPacket->xDataLength; + memcpy( pxReturn->pucEthernetBuffer, pucPacketData, pxOriginalPacket->xDataLength ); + } + + return pxReturn; +} +/*-----------------------------------------------------------*/ + +static NetworkBufferDescriptor_t *prvRxFaultInjection( NetworkBufferDescriptor_t *pxNetworkBufferIn, const uint8_t *pucPacketData ) +{ +static uint32_t ulCallCount = 0, ulNextFaultCallCount = 0; +NetworkBufferDescriptor_t *pxReturn = pxNetworkBufferIn; +IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; +uint32_t ulFault; + +return pxNetworkBufferIn; + + ulCallCount++; + + if( ulCallCount > ulNextFaultCallCount ) + { + ulNextFaultCallCount = ipconfigRAND32() % xMAX_FAULT_INJECTION_RATE; + if( ulNextFaultCallCount < xMIN_FAULT_INJECTION_RATE ) + { + ulNextFaultCallCount = xMIN_FAULT_INJECTION_RATE; + } + + ulCallCount = 0; + + ulFault = ipconfigRAND32() % xNUM_FAULT_TYPES; + + if( ulFaultLogIndex < xFAULT_LOG_SIZE ) + { + ulInjectedFault[ ulFaultLogIndex ] = ulFault; + ulFaultLogIndex++; + } + + switch( ulFault ) + { + case 0: + /* Just drop the packet. */ + vReleaseNetworkBufferAndDescriptor( pxNetworkBufferIn ); + pxReturn = NULL; + break; + + case 1: + /* Store the packet in the cache for later. */ + if( prvCachePacket( pxNetworkBufferIn ) == pdTRUE ) + { + /* The packet may get sent later, it is not being sent + now. */ + pxReturn = NULL; + } + break; + + case 2: + /* Send a cached packet. */ + pxReturn = prvGetCachedPacket(); + if( pxReturn != NULL ) + { + /* A cached packet was obtained so drop the original + packet. */ + vReleaseNetworkBufferAndDescriptor( pxNetworkBufferIn ); + } + else + { + /* Could not obtain a packet from the cache so just return + the packet that was passed in. */ + pxReturn = pxNetworkBufferIn; + } + break; + + case 4: + + /* Send a duplicate of the packet right away. */ + pxReturn = prvDuplicatePacket( pxNetworkBufferIn, pucPacketData ); + + /* Send the original packet to the stack. */ + xRxEvent.pvData = ( void * ) pxNetworkBufferIn; + if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBufferIn ); + } + break; + + case 5: + + /* Send both a cached packet and the current packet. */ + xRxEvent.pvData = ( void * ) prvGetCachedPacket(); + if( xRxEvent.pvData != NULL ) + { + if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBufferIn ); + } + } + break; + + case 6: + case 7: + case 8: + /* Store the packet in the cache for later. */ + if( prvCachePacket( pxNetworkBufferIn ) == pdTRUE ) + { + /* The packet may get sent later, it is not being sent + now. */ + pxReturn = NULL; + } + break; + } + } + + return pxReturn; +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c new file mode 100644 index 000000000..474629e46 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/WinPCap/NetworkInterface.c @@ -0,0 +1,634 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/* WinPCap includes. */ +#define HAVE_REMOTE +#include "pcap.h" + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkBufferManagement.h" + +/* Thread-safe circular buffers are being used to pass data to and from the PCAP +access functions. */ +#include "Win32-Extensions.h" +#include "FreeRTOS_Stream_Buffer.h" + +/* Sizes of the thread safe circular buffers used to pass data to and from the +WinPCAP Windows threads. */ +#define xSEND_BUFFER_SIZE 32768 +#define xRECV_BUFFER_SIZE 32768 + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet +driver will filter incoming packets and only pass the stack those packets it +considers need processing. */ +#if( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 ) + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer +#else + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) ) +#endif + +/* Used to insert test code only. */ +#define niDISRUPT_PACKETS 0 + +/*-----------------------------------------------------------*/ + +/* + * Windows threads that are outside of the control of the FreeRTOS simulator are + * used to interface with the WinPCAP libraries. + */ +DWORD WINAPI prvWinPcapRecvThread( void *pvParam ); +DWORD WINAPI prvWinPcapSendThread( void *pvParam ); + +/* + * Print out a numbered list of network interfaces that are available on the + * host computer. + */ +static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ); + +/* + * Open the network interface. The number of the interface to be opened is set + * by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. + */ +static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ); +static int prvOpenInterface( const char *pucName ); + +/* + * Configure the capture filter to allow blocking reads, and to filter out + * packets that are not of interest to this demo. + */ +static void prvConfigureCaptureBehaviour( void ); + +/* + * A function that simulates Ethernet interrupts by periodically polling the + * WinPCap interface for new data. + */ +static void prvInterruptSimulatorTask( void *pvParameters ); + +/* + * Create the buffers that are used to pass data between the FreeRTOS simulator + * and the Win32 threads that manage WinPCAP. + */ +static void prvCreateThreadSafeBuffers( void ); + +/* + * Utility function used to format print messages only. + */ +static const char *prvRemoveSpaces( char *pcBuffer, int aBuflen, const char *pcMessage ); + +/*-----------------------------------------------------------*/ + +/* Required by the WinPCap library. */ +static char cErrorBuffer[ PCAP_ERRBUF_SIZE ]; + +/* An event used to wake up the Win32 thread that sends data through the WinPCAP +library. */ +static void *pvSendEvent = NULL; + +/* _HT_ made the PCAP interface number configurable through the program's +parameters in order to test in different machines. */ +static BaseType_t xConfigNetworkInterfaceToUse = configNETWORK_INTERFACE_TO_USE; + +/* Handles to the Windows threads that handle the PCAP IO. */ +static HANDLE vWinPcapRecvThreadHandle = NULL; +static HANDLE vWinPcapSendThreadHandle = NULL;; + +/* The interface being used by WinPCap. */ +static pcap_t *pxOpenedInterfaceHandle = NULL; + +/* Circular buffers used by the PCAP Win32 threads. */ +static StreamBuffer_t *xSendBuffer = NULL; +static StreamBuffer_t *xRecvBuffer = NULL; + +/* The MAC address initially set to the constants defined in FreeRTOSConfig.h. */ +extern uint8_t ucMACAddress[ 6 ]; + +/* Logs the number of WinPCAP send failures, for viewing in the debugger only. */ +static volatile uint32_t ulWinPCAPSendFailures = 0; + +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceInitialise( void ) +{ +BaseType_t xReturn = pdFALSE; +pcap_if_t *pxAllNetworkInterfaces; + + /* Query the computer the simulation is being executed on to find the + network interfaces it has installed. */ + pxAllNetworkInterfaces = prvPrintAvailableNetworkInterfaces(); + + /* Open the network interface. The number of the interface to be opened is + set by the configNETWORK_INTERFACE_TO_USE constant in FreeRTOSConfig.h. + Calling this function will set the pxOpenedInterfaceHandle variable. If, + after calling this function, pxOpenedInterfaceHandle is equal to NULL, then + the interface could not be opened. */ + if( pxAllNetworkInterfaces != NULL ) + { + prvOpenSelectedNetworkInterface( pxAllNetworkInterfaces ); + } + + if( pxOpenedInterfaceHandle != NULL ) + { + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static void prvCreateThreadSafeBuffers( void ) +{ + /* The buffer used to pass data to be transmitted from a FreeRTOS task to + the Win32 thread that sends via the WinPCAP library. */ + if( xSendBuffer == NULL) + { + xSendBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) + xSEND_BUFFER_SIZE + 1 ); + configASSERT( xSendBuffer ); + memset( xSendBuffer, '\0', sizeof( *xSendBuffer ) - sizeof( xSendBuffer->ucArray ) ); + xSendBuffer->LENGTH = xSEND_BUFFER_SIZE + 1; + } + + /* The buffer used to pass received data from the Win32 thread that receives + via the WinPCAP library to the FreeRTOS task. */ + if( xRecvBuffer == NULL) + { + xRecvBuffer = ( StreamBuffer_t * ) malloc( sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) + xRECV_BUFFER_SIZE + 1 ); + configASSERT( xRecvBuffer ); + memset( xRecvBuffer, '\0', sizeof( *xRecvBuffer ) - sizeof( xRecvBuffer->ucArray ) ); + xRecvBuffer->LENGTH = xRECV_BUFFER_SIZE + 1; + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t bReleaseAfterSend ) +{ +size_t xSpace; + + iptraceNETWORK_INTERFACE_TRANSMIT(); + configASSERT( xIsCallingFromIPTask() == pdTRUE ); + + /* Both the length of the data being sent and the actual data being sent + are placed in the thread safe buffer used to pass data between the FreeRTOS + tasks and the Win32 thread that sends data via the WinPCAP library. Drop + the packet if there is insufficient space in the buffer to hold both. */ + xSpace = uxStreamBufferGetSpace( xSendBuffer ); + + if( ( pxNetworkBuffer->xDataLength <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) && + ( xSpace >= ( pxNetworkBuffer->xDataLength + sizeof( pxNetworkBuffer->xDataLength ) ) ) ) + { + /* First write in the length of the data, then write in the data + itself. */ + uxStreamBufferAdd( xSendBuffer, 0, ( const uint8_t * ) &( pxNetworkBuffer->xDataLength ), sizeof( pxNetworkBuffer->xDataLength ) ); + uxStreamBufferAdd( xSendBuffer, 0, ( const uint8_t * ) pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength ); + } + else + { + FreeRTOS_debug_printf( ( "xNetworkInterfaceOutput: send buffers full to store %lu\n", pxNetworkBuffer->xDataLength ) ); + } + + /* Kick the Tx task in either case in case it doesn't know the buffer is + full. */ + SetEvent( pvSendEvent ); + + /* The buffer has been sent so can be released. */ + if( bReleaseAfterSend != pdFALSE ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + + return pdPASS; +} +/*-----------------------------------------------------------*/ + +static pcap_if_t * prvPrintAvailableNetworkInterfaces( void ) +{ +pcap_if_t * pxAllNetworkInterfaces = NULL, *xInterface; +int32_t lInterfaceNumber = 1; +char cBuffer[ 512 ]; +static BaseType_t xInvalidInterfaceDetected = pdFALSE; + + if( xInvalidInterfaceDetected == pdFALSE ) + { + if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &pxAllNetworkInterfaces, cErrorBuffer ) == -1 ) + { + printf( "Could not obtain a list of network interfaces\n%s\n", cErrorBuffer ); + pxAllNetworkInterfaces = NULL; + } + else + { + printf( "\r\n\r\nThe following network interfaces are available:\r\n\r\n" ); + } + + if( pxAllNetworkInterfaces != NULL ) + { + /* Print out the list of network interfaces. The first in the list + is interface '1', not interface '0'. */ + for( xInterface = pxAllNetworkInterfaces; xInterface != NULL; xInterface = xInterface->next ) + { + /* The descriptions of the devices can be full of spaces, clean them + a little. printf() can only be used here because the network is not + up yet - so no other network tasks will be running. */ + printf( "Interface %d - %s\n", lInterfaceNumber, prvRemoveSpaces( cBuffer, sizeof( cBuffer ), xInterface->name ) ); + printf( " (%s)\n", prvRemoveSpaces(cBuffer, sizeof( cBuffer ), xInterface->description ? xInterface->description : "No description" ) ); + printf( "\n" ); + lInterfaceNumber++; + } + } + + if( lInterfaceNumber == 1 ) + { + /* The interface number was never incremented, so the above for() loop + did not execute meaning no interfaces were found. */ + printf( " \nNo network interfaces were found.\n" ); + pxAllNetworkInterfaces = NULL; + } + + printf( "\r\nThe interface that will be opened is set by " ); + printf( "\"configNETWORK_INTERFACE_TO_USE\", which\r\nshould be defined in FreeRTOSConfig.h\r\n" ); + + if( ( xConfigNetworkInterfaceToUse < 1L ) || ( xConfigNetworkInterfaceToUse >= lInterfaceNumber ) ) + { + printf( "\r\nERROR: configNETWORK_INTERFACE_TO_USE is set to %d, which is an invalid value.\r\n", xConfigNetworkInterfaceToUse ); + printf( "Please set configNETWORK_INTERFACE_TO_USE to one of the interface numbers listed above,\r\n" ); + printf( "then re-compile and re-start the application. Only Ethernet (as opposed to WiFi)\r\n" ); + printf( "interfaces are supported.\r\n\r\nHALTING\r\n\r\n\r\n" ); + xInvalidInterfaceDetected = pdTRUE; + + if( pxAllNetworkInterfaces != NULL ) + { + /* Free the device list, as no devices are going to be opened. */ + pcap_freealldevs( pxAllNetworkInterfaces ); + pxAllNetworkInterfaces = NULL; + } + } + else + { + printf( "Attempting to open interface number %d.\n", xConfigNetworkInterfaceToUse ); + } + } + + return pxAllNetworkInterfaces; +} +/*-----------------------------------------------------------*/ + +static int prvOpenInterface( const char *pucName ) +{ +static char pucInterfaceName[ 256 ]; + + if( pucName != NULL ) + { + strncpy( pucInterfaceName, pucName, sizeof( pucInterfaceName ) ); + } + + pxOpenedInterfaceHandle = pcap_open( pucInterfaceName, /* The name of the selected interface. */ + ipTOTAL_ETHERNET_FRAME_SIZE, /* The size of the packet to capture. */ + PCAP_OPENFLAG_PROMISCUOUS, /* Open in promiscuous mode as the MAC and + IP address is going to be "simulated", and + not be the real MAC and IP address. This allows + traffic to the simulated IP address to be routed + to uIP, and traffic to the real IP address to be + routed to the Windows TCP/IP stack. */ + 100, + NULL, /* No authentication is required as this is + not a remote capture session. */ + cErrorBuffer + ); + + if ( pxOpenedInterfaceHandle == NULL ) + { + printf( "\n%s is not supported by WinPcap and cannot be opened\n", pucInterfaceName ); + return 1; + } + else + { + /* Configure the capture filter to allow blocking reads, and to filter + out packets that are not of interest to this demo. */ + prvConfigureCaptureBehaviour(); + } + return 0; +} +/*-----------------------------------------------------------*/ + +static void prvOpenSelectedNetworkInterface( pcap_if_t *pxAllNetworkInterfaces ) +{ +pcap_if_t *pxInterface; +int32_t x; + + /* Walk the list of devices until the selected device is located. */ + pxInterface = pxAllNetworkInterfaces; + for( x = 0L; x < ( xConfigNetworkInterfaceToUse - 1L ); x++ ) + { + pxInterface = pxInterface->next; + } + + /* Open the selected interface. */ + if( prvOpenInterface( pxInterface->name ) == 0 ) + { + printf( "Successfully opened interface number %d.\n", x + 1 ); + } + else + { + printf( "Failed to open interface number %d.\n", x + 1 ); + } + + /* The device list is no longer required. */ + pcap_freealldevs( pxAllNetworkInterfaces ); +} +/*-----------------------------------------------------------*/ + +static void prvConfigureCaptureBehaviour( void ) +{ +struct bpf_program xFilterCode; +uint32_t ulNetMask; + + /* Set up a filter so only the packets of interest are passed to the IP + stack. cErrorBuffer is used for convenience to create the string. Don't + confuse this with an error message. */ + sprintf( cErrorBuffer, "broadcast or multicast or ether host %x:%x:%x:%x:%x:%x", + ucMACAddress[0], ucMACAddress[1], ucMACAddress[2], ucMACAddress[3], ucMACAddress[4], ucMACAddress[5] ); + + ulNetMask = ( configNET_MASK3 << 24UL ) | ( configNET_MASK2 << 16UL ) | ( configNET_MASK1 << 8L ) | configNET_MASK0; + + if( pcap_compile( pxOpenedInterfaceHandle, &xFilterCode, cErrorBuffer, 1, ulNetMask ) < 0 ) + { + printf( "\nThe packet filter string is invalid\n" ); + } + else + { + if( pcap_setfilter( pxOpenedInterfaceHandle, &xFilterCode ) < 0 ) + { + printf( "\nAn error occurred setting the packet filter.\n" ); + } + /* When pcap_compile() succeeds, it allocates memory for the memory pointed to by the bpf_program struct + parameter.pcap_freecode() will free that memory. */ + pcap_freecode( &xFilterCode ); + } + + /* Create the buffers used to pass packets between the FreeRTOS simulator + and the Win32 threads that are handling WinPCAP. */ + prvCreateThreadSafeBuffers(); + + if( pvSendEvent == NULL ) + { + /* Create event used to signal the Win32 WinPCAP Tx thread. */ + pvSendEvent = CreateEvent( NULL, FALSE, TRUE, NULL ); + + /* Create the Win32 thread that handles WinPCAP Rx. */ + vWinPcapRecvThreadHandle = CreateThread( + NULL, /* Pointer to thread security attributes. */ + 0, /* Initial thread stack size, in bytes. */ + prvWinPcapRecvThread, /* Pointer to thread function. */ + NULL, /* Argument for new thread. */ + 0, /* Creation flags. */ + NULL ); + + /* Use the cores that are not used by the FreeRTOS tasks. */ + SetThreadAffinityMask( vWinPcapRecvThreadHandle, ~0x01u ); + + /* Create the Win32 thread that handlers WinPCAP Tx. */ + vWinPcapSendThreadHandle = CreateThread( + NULL, /* Pointer to thread security attributes. */ + 0, /* initial thread stack size, in bytes. */ + prvWinPcapSendThread, /* Pointer to thread function. */ + NULL, /* Argument for new thread. */ + 0, /* Creation flags. */ + NULL ); + + /* Use the cores that are not used by the FreeRTOS tasks. */ + SetThreadAffinityMask( vWinPcapSendThreadHandle, ~0x01u ); + + /* Create a task that simulates an interrupt in a real system. This will + block waiting for packets, then send a message to the IP task when data + is available. */ + xTaskCreate( prvInterruptSimulatorTask, "MAC_ISR", configMINIMAL_STACK_SIZE, NULL, configMAC_ISR_SIMULATOR_PRIORITY, NULL ); + } +} +/*-----------------------------------------------------------*/ + +/* WinPCAP function. */ +void pcap_callback( u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data ) +{ + (void)user; + + /* THIS IS CALLED FROM A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS + OR TO PRINT OUT MESSAGES HERE. */ + + /* Pass data to the FreeRTOS simulator on a thread safe circular buffer. */ + if( ( pkt_header->caplen <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) && + ( uxStreamBufferGetSpace( xRecvBuffer ) >= ( ( ( size_t ) pkt_header->caplen ) + sizeof( *pkt_header ) ) ) ) + { + uxStreamBufferAdd( xRecvBuffer, 0, ( const uint8_t* ) pkt_header, sizeof( *pkt_header ) ); + uxStreamBufferAdd( xRecvBuffer, 0, ( const uint8_t* ) pkt_data, ( size_t ) pkt_header->caplen ); + } +} +/*-----------------------------------------------------------*/ + +DWORD WINAPI prvWinPcapRecvThread ( void *pvParam ) +{ + ( void ) pvParam; + + /* THIS IS A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS OR TO PRINT + OUT MESSAGES HERE. */ + + for( ;; ) + { + pcap_dispatch( pxOpenedInterfaceHandle, 1, pcap_callback, ( u_char * ) "mydata" ); + } +} +/*-----------------------------------------------------------*/ + +DWORD WINAPI prvWinPcapSendThread( void *pvParam ) +{ +size_t xLength; +uint8_t ucBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ]; +static char cErrorMessage[ 1024 ]; +const DWORD xMaxMSToWait = 1000; + + /* THIS IS A WINDOWS THREAD - DO NOT ATTEMPT ANY FREERTOS CALLS OR TO PRINT + OUT MESSAGES HERE. */ + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParam; + + for( ;; ) + { + /* Wait until notified of something to send. */ + WaitForSingleObject( pvSendEvent, xMaxMSToWait ); + + /* Is there more than the length value stored in the circular buffer + used to pass data from the FreeRTOS simulator into this Win32 thread? */ + while( uxStreamBufferGetSize( xSendBuffer ) > sizeof( xLength ) ) + { + uxStreamBufferGet( xSendBuffer, 0, ( uint8_t * ) &xLength, sizeof( xLength ), pdFALSE ); + uxStreamBufferGet( xSendBuffer, 0, ( uint8_t* ) ucBuffer, xLength, pdFALSE ); + if( pcap_sendpacket( pxOpenedInterfaceHandle, ucBuffer, xLength ) != 0 ) + { + ulWinPCAPSendFailures++; + } + } + } +} +/*-----------------------------------------------------------*/ + +static void prvInterruptSimulatorTask( void *pvParameters ) +{ +struct pcap_pkthdr xHeader; +static struct pcap_pkthdr *pxHeader; +const uint8_t *pucPacketData; +uint8_t ucRecvBuffer[ ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ]; +NetworkBufferDescriptor_t *pxNetworkBuffer; +IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; +eFrameProcessingResult_t eResult; + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + for( ;; ) + { + /* Does the circular buffer used to pass data from the Win32 thread that + handles WinPCAP Rx into the FreeRTOS simulator contain another packet? */ + if( uxStreamBufferGetSize( xRecvBuffer ) > sizeof( xHeader ) ) + { + /* Get the next packet. */ + uxStreamBufferGet( xRecvBuffer, 0, (uint8_t*)&xHeader, sizeof( xHeader ), pdFALSE ); + uxStreamBufferGet( xRecvBuffer, 0, (uint8_t*)ucRecvBuffer, ( size_t ) xHeader.len, pdFALSE ); + pucPacketData = ucRecvBuffer; + pxHeader = &xHeader; + + iptraceNETWORK_INTERFACE_RECEIVE(); + + /* Check for minimal size. */ + if( pxHeader->len >= sizeof( EthernetHeader_t ) ) + { + eResult = ipCONSIDER_FRAME_FOR_PROCESSING( pucPacketData ); + } + else + { + eResult = eReleaseBuffer; + } + + if( eResult == eProcessBuffer ) + { + /* Will the data fit into the frame buffer? */ + if( pxHeader->len <= ipTOTAL_ETHERNET_FRAME_SIZE ) + { + /* Obtain a buffer into which the data can be placed. This + is only an interrupt simulator, not a real interrupt, so it + is ok to call the task level function here, but note that + some buffer implementations cannot be called from a real + interrupt. */ + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( pxHeader->len, 0 ); + + if( pxNetworkBuffer != NULL ) + { + memcpy( pxNetworkBuffer->pucEthernetBuffer, pucPacketData, pxHeader->len ); + pxNetworkBuffer->xDataLength = ( size_t ) pxHeader->len; + + #if( niDISRUPT_PACKETS == 1 ) + { + pxNetworkBuffer = vRxFaultInjection( pxNetworkBuffer, pucPacketData ); + } + #endif /* niDISRUPT_PACKETS */ + + if( pxNetworkBuffer != NULL ) + { + xRxEvent.pvData = ( void * ) pxNetworkBuffer; + + /* Data was received and stored. Send a message to + the IP task to let it know. */ + if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 0 ) == pdFAIL ) + { + /* The buffer could not be sent to the stack so + must be released again. This is only an + interrupt simulator, not a real interrupt, so it + is ok to use the task level function here, but + note no all buffer implementations will allow + this function to be executed from a real + interrupt. */ + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + iptraceETHERNET_RX_EVENT_LOST(); + } + } + else + { + /* The packet was already released or stored inside + vRxFaultInjection(). Don't release it here. */ + } + } + else + { + iptraceETHERNET_RX_EVENT_LOST(); + } + } + else + { + /* Log that a packet was dropped because it would have + overflowed the buffer, but there may be more buffers to + process. */ + } + } + } + else + { + /* There is no real way of simulating an interrupt. Make sure + other tasks can run. */ + vTaskDelay( configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ); + } + } +} +/*-----------------------------------------------------------*/ + +static const char *prvRemoveSpaces( char *pcBuffer, int aBuflen, const char *pcMessage ) +{ + char *pcTarget = pcBuffer; + + /* Utility function used to formap messages being printed only. */ + while( ( *pcMessage != 0 ) && ( pcTarget < ( pcBuffer + aBuflen - 1 ) ) ) + { + *( pcTarget++ ) = *pcMessage; + + if( isspace( *pcMessage ) != pdFALSE ) + { + while( isspace( *pcMessage ) != pdFALSE ) + { + pcMessage++; + } + } + else + { + pcMessage++; + } + } + + *pcTarget = '\0'; + + return pcBuffer; +} diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c new file mode 100644 index 000000000..b13b11571 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/NetworkInterface.c @@ -0,0 +1,424 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" + +/* Xilinx library files. */ +#include +#include "Zynq/x_topology.h" +#include "Zynq/x_emacpsif.h" +#include "Zynq/x_emacpsif_hw.h" + +/* Provided memory configured as uncached. */ +#include "uncached_memory.h" + +#ifndef niEMAC_HANDLER_TASK_PRIORITY + #define niEMAC_HANDLER_TASK_PRIORITY configMAX_PRIORITIES - 1 +#endif + +#define niBMSR_LINK_STATUS 0x0004UL + +#ifndef PHY_LS_HIGH_CHECK_TIME_MS + /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not + receiving packets. */ + #define PHY_LS_HIGH_CHECK_TIME_MS 15000 +#endif + +#ifndef PHY_LS_LOW_CHECK_TIME_MS + /* Check if the LinkSStatus in the PHY is still low every second. */ + #define PHY_LS_LOW_CHECK_TIME_MS 1000 +#endif + +/* The size of each buffer when BufferAllocation_1 is used: +http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html */ +#define niBUFFER_1_PACKET_SIZE 1536 + +/* Naming and numbering of PHY registers. */ +#define PHY_REG_01_BMSR 0x01 /* Basic mode status register */ + +#ifndef iptraceEMAC_TASK_STARTING + #define iptraceEMAC_TASK_STARTING() do { } while( 0 ) +#endif + +/* Default the size of the stack used by the EMAC deferred handler task to twice +the size of the stack used by the idle task - but allow this to be overridden in +FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */ +#ifndef configEMAC_TASK_STACK_SIZE + #define configEMAC_TASK_STACK_SIZE ( 2 * configMINIMAL_STACK_SIZE ) +#endif + +/*-----------------------------------------------------------*/ + +/* + * Look for the link to be up every few milliseconds until either xMaxTime time + * has passed or a link is found. + */ +static BaseType_t prvGMACWaitLS( TickType_t xMaxTime ); + +/* + * A deferred interrupt handler for all MAC/DMA interrupt sources. + */ +static void prvEMACHandlerTask( void *pvParameters ); + +/*-----------------------------------------------------------*/ + +/* EMAC data/descriptions. */ +static xemacpsif_s xEMACpsif; +struct xtopology_t xXTopology = +{ + .emac_baseaddr = XPAR_PS7_ETHERNET_0_BASEADDR, + .emac_type = xemac_type_emacps, + .intc_baseaddr = 0x0, + .intc_emac_intr = 0x0, + .scugic_baseaddr = XPAR_PS7_SCUGIC_0_BASEADDR, + .scugic_emac_intr = 0x36, +}; + +XEmacPs_Config mac_config = +{ + .DeviceId = XPAR_PS7_ETHERNET_0_DEVICE_ID, /**< Unique ID of device */ + .BaseAddress = XPAR_PS7_ETHERNET_0_BASEADDR /**< Physical base address of IPIF registers */ +}; + +extern int phy_detected; + +/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */ +static uint32_t ulPHYLinkStatus = 0; + +#if( ipconfigUSE_LLMNR == 1 ) + static const uint8_t xLLMNR_MACAddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC }; +#endif + +/* ucMACAddress as it appears in main.c */ +extern const uint8_t ucMACAddress[ 6 ]; + +/* Holds the handle of the task used as a deferred interrupt processor. The +handle is used so direct notifications can be sent to the task for all EMAC/DMA +related interrupts. */ +TaskHandle_t xEMACTaskHandle = NULL; + +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceInitialise( void ) +{ +uint32_t ulLinkSpeed, ulDMAReg; +BaseType_t xStatus, xLinkStatus; +XEmacPs *pxEMAC_PS; +const TickType_t xWaitLinkDelay = pdMS_TO_TICKS( 7000UL ), xWaitRelinkDelay = pdMS_TO_TICKS( 1000UL ); + + /* Guard against the init function being called more than once. */ + if( xEMACTaskHandle == NULL ) + { + pxEMAC_PS = &( xEMACpsif.emacps ); + memset( &xEMACpsif, '\0', sizeof( xEMACpsif ) ); + + xStatus = XEmacPs_CfgInitialize( pxEMAC_PS, &mac_config, mac_config.BaseAddress); + if( xStatus != XST_SUCCESS ) + { + FreeRTOS_printf( ( "xEMACInit: EmacPs Configuration Failed....\n" ) ); + } + + /* Initialize the mac and set the MAC address. */ + XEmacPs_SetMacAddress( pxEMAC_PS, ( void * ) ucMACAddress, 1 ); + + #if( ipconfigUSE_LLMNR == 1 ) + { + /* Also add LLMNR multicast MAC address. */ + XEmacPs_SetMacAddress( pxEMAC_PS, ( void * )xLLMNR_MACAddress, 2 ); + } + #endif /* ipconfigUSE_LLMNR == 1 */ + + XEmacPs_SetMdioDivisor( pxEMAC_PS, MDC_DIV_224 ); + ulLinkSpeed = Phy_Setup( pxEMAC_PS ); + XEmacPs_SetOperatingSpeed( pxEMAC_PS, ulLinkSpeed); + + /* Setting the operating speed of the MAC needs a delay. */ + vTaskDelay( pdMS_TO_TICKS( 25UL ) ); + + ulDMAReg = XEmacPs_ReadReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_DMACR_OFFSET); + + /* DISC_WHEN_NO_AHB: when set, the GEM DMA will automatically discard receive + packets from the receiver packet buffer memory when no AHB resource is available. */ + XEmacPs_WriteReg( pxEMAC_PS->Config.BaseAddress, XEMACPS_DMACR_OFFSET, + ulDMAReg | XEMACPS_DMACR_DISC_WHEN_NO_AHB_MASK); + + setup_isr( &xEMACpsif ); + init_dma( &xEMACpsif ); + start_emacps( &xEMACpsif ); + + prvGMACWaitLS( xWaitLinkDelay ); + + /* The deferred interrupt handler task is created at the highest + possible priority to ensure the interrupt handler can return directly + to it. The task's handle is stored in xEMACTaskHandle so interrupts can + notify the task when there is something to process. */ + xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, niEMAC_HANDLER_TASK_PRIORITY, &xEMACTaskHandle ); + } + else + { + /* Initialisation was already performed, just wait for the link. */ + prvGMACWaitLS( xWaitRelinkDelay ); + } + + /* Only return pdTRUE when the Link Status of the PHY is high, otherwise the + DHCP process and all other communication will fail. */ + xLinkStatus = xGetPhyLinkStatus(); + + return ( xLinkStatus != pdFALSE ); +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxBuffer, BaseType_t bReleaseAfterSend ) +{ + #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) + { + ProtocolPacket_t *pxPacket; + + /* If the peripheral must calculate the checksum, it wants + the protocol checksum to have a value of zero. */ + pxPacket = ( ProtocolPacket_t * ) ( pxBuffer->pucEthernetBuffer ); + if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP ) + { + IPHeader_t *pxIPHeader = &( pxPacket->xUDPPacket.xIPHeader ); + + pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t )0u; + pxIPHeader->usHeaderChecksum = 0u; + pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER ); + pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); + + usGenerateProtocolChecksum( (uint8_t*)&( pxPacket->xUDPPacket ), pxBuffer->xDataLength, pdTRUE ); + } + } + #endif /* ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM */ + if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 ) + { + iptraceNETWORK_INTERFACE_TRANSMIT(); + emacps_send_message( &xEMACpsif, pxBuffer, bReleaseAfterSend ); + } + else if( bReleaseAfterSend != pdFALSE ) + { + /* No link. */ + vReleaseNetworkBufferAndDescriptor( pxBuffer ); + } + + return pdTRUE; +} +/*-----------------------------------------------------------*/ + +static inline unsigned long ulReadMDIO( unsigned ulRegister ) +{ +uint16_t usValue; + + XEmacPs_PhyRead( &( xEMACpsif.emacps ), phy_detected, ulRegister, &usValue ); + return usValue; +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvGMACWaitLS( TickType_t xMaxTime ) +{ +TickType_t xStartTime, xEndTime; +const TickType_t xShortDelay = pdMS_TO_TICKS( 20UL ); +BaseType_t xReturn; + + xStartTime = xTaskGetTickCount(); + + for( ;; ) + { + xEndTime = xTaskGetTickCount(); + + if( xEndTime - xStartTime > xMaxTime ) + { + xReturn = pdFALSE; + break; + } + ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR ); + + if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 ) + { + xReturn = pdTRUE; + break; + } + + vTaskDelay( xShortDelay ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) +{ +static uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) ); +uint8_t *ucRAMBuffer = ucNetworkPackets; +uint32_t ul; + + for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ ) + { + pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING; + *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) ); + ucRAMBuffer += niBUFFER_1_PACKET_SIZE; + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xGetPhyLinkStatus( void ) +{ +BaseType_t xReturn; + + if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) == 0 ) + { + xReturn = pdFALSE; + } + else + { + xReturn = pdTRUE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static void prvEMACHandlerTask( void *pvParameters ) +{ +TimeOut_t xPhyTime; +TickType_t xPhyRemTime; +UBaseType_t uxCurrentCount; +BaseType_t xResult = 0; +uint32_t xStatus; +const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL ); +UBaseType_t uxLastMinBufferCount = 0; +UBaseType_t uxCurrentBufferCount = 0; + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + /* A possibility to set some additional task properties like calling + portTASK_USES_FLOATING_POINT() */ + iptraceEMAC_TASK_STARTING(); + + vTaskSetTimeOutState( &xPhyTime ); + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS ); + + for( ;; ) + { + uxCurrentBufferCount = uxGetMinimumFreeNetworkBuffers(); + if( uxLastMinBufferCount != uxCurrentBufferCount ) + { + /* The logging produced below may be helpful + while tuning +TCP: see how many buffers are in use. */ + uxLastMinBufferCount = uxCurrentBufferCount; + FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n", + uxGetNumberOfFreeNetworkBuffers(), uxCurrentBufferCount ) ); + } + + #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + { + static UBaseType_t uxLastMinQueueSpace = 0; + + uxCurrentCount = uxGetMinimumIPQueueSpace(); + if( uxLastMinQueueSpace != uxCurrentCount ) + { + /* The logging produced below may be helpful + while tuning +TCP: see how many buffers are in use. */ + uxLastMinQueueSpace = uxCurrentCount; + FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) ); + } + } + #endif /* ipconfigCHECK_IP_QUEUE_SPACE */ + + if( ( xEMACpsif.isr_events & EMAC_IF_ALL_EVENT ) == 0 ) + { + /* No events to process now, wait for the next. */ + ulTaskNotifyTake( pdFALSE, ulMaxBlockTime ); + } + + if( ( xEMACpsif.isr_events & EMAC_IF_RX_EVENT ) != 0 ) + { + xEMACpsif.isr_events &= ~EMAC_IF_RX_EVENT; + xResult = emacps_check_rx( &xEMACpsif ); + } + + if( ( xEMACpsif.isr_events & EMAC_IF_TX_EVENT ) != 0 ) + { + xEMACpsif.isr_events &= ~EMAC_IF_TX_EVENT; + emacps_check_tx( &xEMACpsif ); + } + + if( ( xEMACpsif.isr_events & EMAC_IF_ERR_EVENT ) != 0 ) + { + xEMACpsif.isr_events &= ~EMAC_IF_ERR_EVENT; + emacps_check_errors( &xEMACpsif ); + } + + if( xResult > 0 ) + { + /* A packet was received. No need to check for the PHY status now, + but set a timer to check it later on. */ + vTaskSetTimeOutState( &xPhyTime ); + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS ); + xResult = 0; + /* Indicate that the Link Status is high, so that + xNetworkInterfaceOutput() can send packets. */ + ulPHYLinkStatus |= niBMSR_LINK_STATUS; + } + else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ) + { + xStatus = ulReadMDIO( PHY_REG_01_BMSR ); + + if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != ( xStatus & niBMSR_LINK_STATUS ) ) + { + ulPHYLinkStatus = xStatus; + FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 ) ); + } + + vTaskSetTimeOutState( &xPhyTime ); + if( ( ulPHYLinkStatus & niBMSR_LINK_STATUS ) != 0 ) + { + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS ); + } + else + { + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS ); + } + } + } +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/README.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/README.txt new file mode 100644 index 000000000..74b241dcf --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/README.txt @@ -0,0 +1,25 @@ + + +NetworkInterface for Xilinx' Zynq + +Please include the following source files: + + $(PLUS_TCP_PATH)/portable/NetworkInterface/Zynq/NetworkInterface.c + $(PLUS_TCP_PATH)/portable/NetworkInterface/Zynq/x_emacpsif_dma.c + $(PLUS_TCP_PATH)/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c + $(PLUS_TCP_PATH)/portable/NetworkInterface/Zynq/x_emacpsif_hw.c + +And include the following source files from the Xilinx library: + + $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps.c + $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_control.c + $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_g.c + $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_intr.c + + E.g. ps7_cortexa9_0/libsrc/emacps_v2_0/src/xemacps_intr.c + +The following source files are NOT used for the FreeRTOS+TCP interface: + + $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_bdring.c + $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_hw.c + $(CPU_PATH)/$(PROCESSOR)/libsrc/emacps_v2_0/src/xemacps_sinit.c diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/uncached_memory.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/uncached_memory.c new file mode 100644 index 000000000..b43e50ec2 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/uncached_memory.c @@ -0,0 +1,132 @@ +/* + * uncached_memory.c + * + * This module will declare 1 MB of memory and switch off the caching for it. + * + * pucGetUncachedMemory( ulSize ) returns a trunc of this memory with a length + * rounded up to a multiple of 4 KB + * + * ucIsCachedMemory( pucBuffer ) returns non-zero if a given pointer is NOT + * within the range of the 1 MB non-cached memory. + * + */ + +/* + * After "_end", 1 MB of uncached memory will be allocated for DMA transfers. + * Both the DMA descriptors as well as all EMAC TX-buffers will be allocated in + * uncached memory. + */ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" + +#include "Zynq/x_emacpsif.h" +#include "Zynq/x_topology.h" +#include "xstatus.h" + +#include "xparameters.h" +#include "xparameters_ps.h" +#include "xil_exception.h" +#include "xil_mmu.h" + +#include "uncached_memory.h" + +#define UNCACHED_MEMORY_SIZE 0x100000ul + +#define DDR_MEMORY_END (XPAR_PS7_DDR_0_S_AXI_HIGHADDR+1) + +static void vInitialiseUncachedMemory( void ); + +static uint8_t *pucHeadOfMemory; +static uint32_t ulMemorySize; +static uint8_t *pucStartOfMemory = NULL; + +uint8_t ucIsCachedMemory( const uint8_t *pucBuffer ) +{ +uint8_t ucReturn; + + if( ( pucStartOfMemory != NULL ) && + ( pucBuffer >= pucStartOfMemory ) && + ( pucBuffer < ( pucStartOfMemory + UNCACHED_MEMORY_SIZE ) ) ) + { + ucReturn = pdFALSE; + } + else + { + ucReturn = pdTRUE; + } + + return ucReturn; +} + +uint8_t *pucGetUncachedMemory( uint32_t ulSize ) +{ +uint8_t *pucReturn; + + if( pucStartOfMemory == NULL ) + { + vInitialiseUncachedMemory( ); + } + if( ( pucStartOfMemory == NULL ) || ( ulSize > ulMemorySize ) ) + { + pucReturn = NULL; + } + else + { + uint32_t ulSkipSize; + + pucReturn = pucHeadOfMemory; + ulSkipSize = ( ulSize + 0x1000ul ) & ~0xffful; + pucHeadOfMemory += ulSkipSize; + ulMemorySize -= ulSkipSize; + } + + return pucReturn; +} + +extern u8 _end; + +static void vInitialiseUncachedMemory( ) +{ + /* At the end of program's space... */ + pucStartOfMemory = (uint8_t *) &_end; + /* + * Align the start address to 1 MB boundary. + */ + pucStartOfMemory = (uint8_t *)( ( ( uint32_t )pucStartOfMemory + UNCACHED_MEMORY_SIZE ) & ( ~( UNCACHED_MEMORY_SIZE - 1 ) ) ); + + if( ( ( u32 )pucStartOfMemory ) + UNCACHED_MEMORY_SIZE > DDR_MEMORY_END ) + { +// vLoggingPrintf("vInitialiseUncachedMemory: Can not allocate uncached memory\n" ); + } + else + { + /* + * Some objects want to be stored in uncached memory. Hence the 1 MB + * address range that starts after "_end" is made uncached + * by setting appropriate attributes in the translation table. + */ + /* FIXME claudio rossi. Modified to prevent data abort exception (misaligned access) + * when application is compiled with -O1 or more optimization flag. + */ +/* Xil_SetTlbAttributes( ( uint32_t )pucStartOfMemory, 0xc02 ); // addr, attr */ + Xil_SetTlbAttributes( ( uint32_t )pucStartOfMemory, 0x1c02 ); // addr, attr + + /* For experiments in the SDIO driver, make the remaining uncached memory public */ + pucHeadOfMemory = pucStartOfMemory; + ulMemorySize = UNCACHED_MEMORY_SIZE; + memset( pucStartOfMemory, '\0', UNCACHED_MEMORY_SIZE ); + } +} diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/uncached_memory.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/uncached_memory.h new file mode 100644 index 000000000..5a8e5f37f --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/uncached_memory.h @@ -0,0 +1,23 @@ +/* + * uncached_memory.h + * + * This module will declare 1 MB of memory and switch off the caching for it. + * + * pucGetUncachedMemory( ulSize ) returns a trunc of this memory with a length + * rounded up to a multiple of 4 KB + * + * ucIsCachedMemory( pucBuffer ) returns non-zero if a given pointer is NOT + * within the range of the 1 MB non-cached memory. + * + */ + +#ifndef UNCACHEMEMORY_H + +#define UNCACHEMEMORY_H + +uint8_t *pucGetUncachedMemory( uint32_t ulSize ); + +uint8_t ucIsCachedMemory( const uint8_t *pucBuffer ); + +#endif /* UNCACHEMEMORY_H */ + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif.h new file mode 100644 index 000000000..a38ec81d7 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2010-2013 Xilinx, Inc. All rights reserved. + * + * Xilinx, Inc. + * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A + * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS + * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR + * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION + * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE + * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. + * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO + * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO + * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE + * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __NETIF_XEMACPSIF_H__ +#define __NETIF_XEMACPSIF_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "xstatus.h" +#include "sleep.h" +#include "xparameters.h" +#include "xparameters_ps.h" /* defines XPAR values */ +#include "xil_types.h" +#include "xil_assert.h" +#include "xil_io.h" +#include "xil_exception.h" +#include "xpseudo_asm.h" +#include "xil_cache.h" +#include "xuartps.h" +#include "xscugic.h" +#include "xemacps.h" /* defines XEmacPs API */ + +//#include "netif/xpqueue.h" +//#include "xlwipconfig.h" + +void xemacpsif_setmac(uint32_t index, uint8_t *addr); +uint8_t* xemacpsif_getmac(uint32_t index); +//int xemacpsif_init(struct netif *netif); +//int xemacpsif_input(struct netif *netif); +#ifdef NOTNOW_BHILL +unsigned get_IEEE_phy_speed(XLlTemac *xlltemacp); +#endif + +/* xaxiemacif_hw.c */ +void xemacps_error_handler(XEmacPs * Temac); + +struct xBD_TYPE { + uint32_t address; + uint32_t flags; +}; + +/* + * Missing declaration in 'src/xemacps_hw.h' : + * When set, the GEM DMA will automatically + * discard receive packets from the receiver packet + * buffer memory when no AHB resource is + * available. + * When low, then received packets will remain to be + * stored in the SRAM based packet buffer until + * AHB buffer resource next becomes available. + */ +#define XEMACPS_DMACR_DISC_WHEN_NO_AHB_MASK 0x01000000 + +#define EMAC_IF_RX_EVENT 1 +#define EMAC_IF_TX_EVENT 2 +#define EMAC_IF_ERR_EVENT 4 +#define EMAC_IF_ALL_EVENT 7 + +/* structure within each netif, encapsulating all information required for + * using a particular temac instance + */ +typedef struct { + XEmacPs emacps; + + /* pointers to memory holding buffer descriptors (used only with SDMA) */ + struct xBD_TYPE *rxSegments; + struct xBD_TYPE *txSegments; + + unsigned char *tx_space; + unsigned uTxUnitSize; + + char *remain_mem; + unsigned remain_siz; + + volatile int rxHead, rxTail; + volatile int txHead, txTail; + + volatile int txBusy; + + volatile uint32_t isr_events; + + unsigned int last_rx_frms_cntr; + +} xemacpsif_s; + +//extern xemacpsif_s xemacpsif; + +int is_tx_space_available(xemacpsif_s *emac); + +/* xaxiemacif_dma.c */ + +struct xNETWORK_BUFFER; + +int emacps_check_rx( xemacpsif_s *xemacpsif ); +void emacps_check_tx( xemacpsif_s *xemacpsif ); +int emacps_check_errors( xemacpsif_s *xemacps ); +void emacps_set_rx_buffers( xemacpsif_s *xemacpsif, u32 ulCount ); + +extern XStatus emacps_send_message(xemacpsif_s *xemacpsif, struct xNETWORK_BUFFER *pxBuffer, int iReleaseAfterSend ); +extern unsigned Phy_Setup( XEmacPs *xemacpsp ); +extern void setup_isr( xemacpsif_s *xemacpsif ); +extern XStatus init_dma( xemacpsif_s *xemacpsif ); +extern void start_emacps( xemacpsif_s *xemacpsif ); + +void EmacEnableIntr(void); +void EmacDisableIntr(void); + +XStatus init_axi_dma(xemacpsif_s *xemacpsif); +void process_sent_bds( xemacpsif_s *xemacpsif ); + +void emacps_send_handler(void *arg); +void emacps_recv_handler(void *arg); +void emacps_error_handler(void *arg,u8 Direction, u32 ErrorWord); +void HandleTxErrors(xemacpsif_s *xemacpsif); +XEmacPs_Config *xemacps_lookup_config(unsigned mac_base); + +void clean_dma_txdescs(xemacpsif_s *xemacpsif); +void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif); + +#ifdef __cplusplus +} +#endif + +#endif /* __NETIF_XAXIEMACIF_H__ */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c new file mode 100644 index 000000000..d71331c0e --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c @@ -0,0 +1,647 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +#include "FreeRTOS.h" +#include "task.h" +#include "timers.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkBufferManagement.h" + +#include "Zynq/x_emacpsif.h" +#include "Zynq/x_topology.h" +#include "xstatus.h" + +#include "xparameters.h" +#include "xparameters_ps.h" +#include "xil_exception.h" +#include "xil_mmu.h" + +#include "uncached_memory.h" + +/* Two defines used to set or clear the EMAC interrupt */ +#define INTC_BASE_ADDR XPAR_SCUGIC_CPU_BASEADDR +#define INTC_DIST_BASE_ADDR XPAR_SCUGIC_DIST_BASEADDR + + + +#if( ipconfigPACKET_FILLER_SIZE != 2 ) + #error Please define ipconfigPACKET_FILLER_SIZE as the value '2' +#endif +#define TX_OFFSET ipconfigPACKET_FILLER_SIZE + +/* Defined in NetworkInterface.c */ +extern TaskHandle_t xEMACTaskHandle; + +/* + pxDMA_tx_buffers: these are character arrays, each one is big enough to hold 1 MTU. + The actual TX buffers are located in uncached RAM. +*/ +static unsigned char *pxDMA_tx_buffers[ ipconfigNIC_N_TX_DESC ] = { NULL }; + +/* + pxDMA_rx_buffers: these are pointers to 'NetworkBufferDescriptor_t'. + Once a message has been received by the EMAC, the descriptor can be passed + immediately to the IP-task. +*/ +static NetworkBufferDescriptor_t *pxDMA_rx_buffers[ ipconfigNIC_N_RX_DESC ] = { NULL }; + +/* + The FreeRTOS+TCP port is using a fixed 'topology', which is declared in + ./portable/NetworkInterface/Zynq/NetworkInterface.c +*/ +extern struct xtopology_t xXTopology; + +static SemaphoreHandle_t xTXDescriptorSemaphore = NULL; + +/* + The FreeRTOS+TCP port does not make use of "src/xemacps_bdring.c". + In stead 'struct xemacpsif_s' has a "head" and a "tail" index. + "head" is the next index to be written, used. + "tail" is the next index to be read, freed. +*/ + +int is_tx_space_available( xemacpsif_s *xemacpsif ) +{ +size_t uxCount; + + if( xTXDescriptorSemaphore != NULL ) + { + uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore ); + } + else + { + uxCount = ( UBaseType_t ) 0u; + } + + return uxCount; +} + +void emacps_check_tx( xemacpsif_s *xemacpsif ) +{ +int tail = xemacpsif->txTail; +int head = xemacpsif->txHead; +size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore ); + + /* uxCount is the number of TX descriptors that are in use by the DMA. */ + /* When done, "TXBUF_USED" will be set. */ + + while( ( uxCount > 0 ) && ( ( xemacpsif->txSegments[ tail ].flags & XEMACPS_TXBUF_USED_MASK ) != 0 ) ) + { + if( ( tail == head ) && ( uxCount != ipconfigNIC_N_TX_DESC ) ) + { + break; + } +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + void *pvBuffer = pxDMA_tx_buffers[ tail ]; + NetworkBufferDescriptor_t *pxBuffer; + + if( pvBuffer != NULL ) + { + pxDMA_tx_buffers[ tail ] = NULL; + pxBuffer = pxPacketBuffer_to_NetworkBuffer( pvBuffer ); + if( pxBuffer != NULL ) + { + vReleaseNetworkBufferAndDescriptor( pxBuffer ); + } + else + { + FreeRTOS_printf( ( "emacps_check_tx: Can not find network buffer\n" ) ); + } + } + } +#endif + /* Clear all but the "used" and "wrap" bits. */ + if( tail < ipconfigNIC_N_TX_DESC - 1 ) + { + xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK; + } + else + { + xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK; + } + uxCount--; + /* Tell the counting semaphore that one more TX descriptor is available. */ + xSemaphoreGive( xTXDescriptorSemaphore ); + if( ++tail == ipconfigNIC_N_TX_DESC ) + { + tail = 0; + } + xemacpsif->txTail = tail; + } + + return; +} + +void emacps_send_handler(void *arg) +{ +xemacpsif_s *xemacpsif; +BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + xemacpsif = (xemacpsif_s *)(arg); + + /* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in + "isr_events". The task in NetworkInterface will wake-up and do the necessary work. + */ + xemacpsif->isr_events |= EMAC_IF_TX_EVENT; + xemacpsif->txBusy = pdFALSE; + + if( xEMACTaskHandle != NULL ) + { + vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken ); + } + + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); +} + +static BaseType_t xValidLength( BaseType_t xLength ) +{ +BaseType_t xReturn; + + if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= ipTOTAL_ETHERNET_FRAME_SIZE ) ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} + +XStatus emacps_send_message(xemacpsif_s *xemacpsif, NetworkBufferDescriptor_t *pxBuffer, int iReleaseAfterSend ) +{ +int head = xemacpsif->txHead; +int iHasSent = 0; +uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress; +TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u ); + + #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + { + /* This driver wants to own all network buffers which are to be transmitted. */ + configASSERT( iReleaseAfterSend != pdFALSE ); + } + #endif + + /* Open a do {} while ( 0 ) loop to be able to call break. */ + do + { + uint32_t ulFlags = 0; + + if( xValidLength( pxBuffer->xDataLength ) != pdTRUE ) + { + break; + } + + if( xTXDescriptorSemaphore == NULL ) + { + break; + } + + if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS ) + { + FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) ); + break; + } + +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + /* Pass the pointer (and its ownership) directly to DMA. */ + pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer; + if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 ) + { + Xil_DCacheFlushRange( ( unsigned )pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength ); + } + /* Buffer has been transferred, do not release it. */ + iReleaseAfterSend = pdFALSE; +#else + if( pxDMA_tx_buffers[ head ] == NULL ) + { + FreeRTOS_printf( ( "emacps_send_message: pxDMA_tx_buffers[ %d ] == NULL\n", head ) ); + break; + } + /* Copy the message to unbuffered space in RAM. */ + memcpy( pxDMA_tx_buffers[ head ], pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength ); +#endif + /* Packets will be sent one-by-one, so for each packet + the TXBUF_LAST bit will be set. */ + ulFlags |= XEMACPS_TXBUF_LAST_MASK; + ulFlags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK ); + if( head == ( ipconfigNIC_N_TX_DESC - 1 ) ) + { + ulFlags |= XEMACPS_TXBUF_WRAP_MASK; + } + + /* Copy the address of the buffer and set the flags. */ + xemacpsif->txSegments[ head ].address = ( uint32_t )pxDMA_tx_buffers[ head ]; + xemacpsif->txSegments[ head ].flags = ulFlags; + + iHasSent = pdTRUE; + if( ++head == ipconfigNIC_N_TX_DESC ) + { + head = 0; + } + /* Update the TX-head index. These variable are declared volatile so they will be + accessed as little as possible. */ + xemacpsif->txHead = head; + } while( pdFALSE ); + + if( iReleaseAfterSend != pdFALSE ) + { + vReleaseNetworkBufferAndDescriptor( pxBuffer ); + pxBuffer = NULL; + } + + /* Data Synchronization Barrier */ + dsb(); + + if( iHasSent != pdFALSE ) + { + /* Make STARTTX high */ + uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET); + /* Start transmit */ + xemacpsif->txBusy = pdTRUE; + XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) ); + /* Reading it back is important compiler is optimised. */ + XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET ); + } + dsb(); + + return 0; +} + +void emacps_recv_handler(void *arg) +{ + xemacpsif_s *xemacpsif; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + xemacpsif = (xemacpsif_s *)(arg); + xemacpsif->isr_events |= EMAC_IF_RX_EVENT; + + if( xEMACTaskHandle != NULL ) + { + vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken ); + } + + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); +} + +static void prvPassEthMessages( NetworkBufferDescriptor_t *pxDescriptor ) +{ +IPStackEvent_t xRxEvent; + + xRxEvent.eEventType = eNetworkRxEvent; + xRxEvent.pvData = ( void * ) pxDescriptor; + + if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS ) + { + /* The buffer could not be sent to the stack so must be released again. + This is a deferred handler taskr, not a real interrupt, so it is ok to + use the task level function here. */ + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + { + do + { + NetworkBufferDescriptor_t *pxNext = pxDescriptor->pxNextBuffer; + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + pxDescriptor = pxNext; + } while( pxDescriptor != NULL ); + } + #else + { + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + } + #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ + iptraceETHERNET_RX_EVENT_LOST(); + FreeRTOS_printf( ( "prvPassEthMessages: Can not queue return packet!\n" ) ); + } +} + +int emacps_check_rx( xemacpsif_s *xemacpsif ) +{ +NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer; +int rx_bytes; +volatile int msgCount = 0; +int head = xemacpsif->rxHead; +#if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + NetworkBufferDescriptor_t *pxFirstDescriptor = NULL; + NetworkBufferDescriptor_t *pxLastDescriptor = NULL; +#endif /* ipconfigUSE_LINKED_RX_MESSAGES */ + + /* There seems to be an issue (SI# 692601), see comments below. */ + resetrx_on_no_rxdata(xemacpsif); + + /* This FreeRTOS+TCP driver shall be compiled with the option + "ipconfigUSE_LINKED_RX_MESSAGES" enabled. It allows the driver to send a + chain of RX messages within one message to the IP-task. */ + for( ;; ) + { + if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) || + ( pxDMA_rx_buffers[ head ] == NULL ) ) + { + break; + } + + pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 ); + if( pxNewBuffer == NULL ) + { + /* A packet has been received, but there is no replacement for this Network Buffer. + The packet will be dropped, and it Network Buffer will stay in place. */ + FreeRTOS_printf( ("emacps_check_rx: unable to allocate a Netwrok Buffer\n" ) ); + pxNewBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ]; + } + else + { + pxBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ]; + + /* Just avoiding to use or refer to the same buffer again */ + pxDMA_rx_buffers[ head ] = pxNewBuffer; + + /* + * Adjust the buffer size to the actual number of bytes received. + */ + rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK; + + pxBuffer->xDataLength = rx_bytes; + if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 ) + { + Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)rx_bytes ); + } + + /* store it in the receive queue, where it'll be processed by a + different handler. */ + iptraceNETWORK_INTERFACE_RECEIVE(); + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + { + pxBuffer->pxNextBuffer = NULL; + + if( pxFirstDescriptor == NULL ) + { + // Becomes the first message + pxFirstDescriptor = pxBuffer; + } + else if( pxLastDescriptor != NULL ) + { + // Add to the tail + pxLastDescriptor->pxNextBuffer = pxBuffer; + } + + pxLastDescriptor = pxBuffer; + } + #else + { + prvPassEthMessages( pxBuffer ); + } + #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ + + msgCount++; + } + { + if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 ) + { + Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE ); + } + { + uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK; + if( head == ( ipconfigNIC_N_RX_DESC - 1 ) ) + { + addr |= XEMACPS_RXBUF_WRAP_MASK; + } + /* Clearing 'XEMACPS_RXBUF_NEW_MASK' 0x00000001 *< Used bit.. */ + xemacpsif->rxSegments[ head ].flags = 0; + xemacpsif->rxSegments[ head ].address = addr; + if (xemacpsif->rxSegments[ head ].address) + { + // Just to read it + } + } + } + + if( ++head == ipconfigNIC_N_RX_DESC ) + { + head = 0; + } + xemacpsif->rxHead = head; + } + + #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + { + if( pxFirstDescriptor != NULL ) + { + prvPassEthMessages( pxFirstDescriptor ); + } + } + #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ + + return msgCount; +} + +void clean_dma_txdescs(xemacpsif_s *xemacpsif) +{ +int index; +unsigned char *ucTxBuffer; + + /* Clear all TX descriptors and assign uncached memory to each descriptor. + "tx_space" points to the first available TX buffer. */ + ucTxBuffer = xemacpsif->tx_space; + + for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ ) + { + xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer; + xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK; +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + pxDMA_tx_buffers[ index ] = ( unsigned char * )NULL; +#else + pxDMA_tx_buffers[ index ] = ( unsigned char * )( ucTxBuffer + TX_OFFSET ); +#endif + ucTxBuffer += xemacpsif->uTxUnitSize; + } + xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags = + XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK; +} + +XStatus init_dma(xemacpsif_s *xemacpsif) +{ + NetworkBufferDescriptor_t *pxBuffer; + + int iIndex; + UBaseType_t xRxSize; + UBaseType_t xTxSize; + struct xtopology_t *xtopologyp = &xXTopology; + + xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] ); + + xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] ); + + /* Also round-up to 4KB */ + xemacpsif->uTxUnitSize = ( ipTOTAL_ETHERNET_FRAME_SIZE + 0x1000ul ) & ~0xffful; + /* + * We allocate 65536 bytes for RX BDs which can accommodate a + * maximum of 8192 BDs which is much more than any application + * will ever need. + */ + xemacpsif->rxSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xRxSize ) ); + xemacpsif->txSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xTxSize ) ); + xemacpsif->tx_space = ( unsigned char * )( pucGetUncachedMemory ( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) ); + + /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */ + xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments; + xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments; + + if( xTXDescriptorSemaphore == NULL ) + { + xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC ); + configASSERT( xTXDescriptorSemaphore ); + } + /* + * Allocate RX descriptors, 1 RxBD at a time. + */ + for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ ) + { + pxBuffer = pxDMA_rx_buffers[ iIndex ]; + if( pxBuffer == NULL ) + { + pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 ); + if( pxBuffer == NULL ) + { + FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) ); + return -1; + } + } + + xemacpsif->rxSegments[ iIndex ].flags = 0; + xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK; + + pxDMA_rx_buffers[ iIndex ] = pxBuffer; + /* Make sure this memory is not in cache for now. */ + if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 ) + { + Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, + (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE ); + } + } + + xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK; + + memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ); + + clean_dma_txdescs( xemacpsif ); + + { + uint32_t value; + value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET ); + + // 1xxxx: Attempt to use INCR16 AHB bursts + value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST; +#if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) + value |= XEMACPS_DMACR_TCPCKSUM_MASK; +#else +#warning Are you sure the EMAC should not calculate outgoing checksums? + value &= ~XEMACPS_DMACR_TCPCKSUM_MASK; +#endif + XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value ); + } + { + uint32_t value; + value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET ); + + /* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ). + Now tell the EMAC that received messages should be stored at "address + 2". */ + value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000; + +#if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 ) + value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK; +#else +#warning Are you sure the EMAC should not calculate incoming checksums? + value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK; +#endif + XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value ); + } + + /* + * Connect the device driver handler that will be called when an + * interrupt for the device occurs, the handler defined above performs + * the specific interrupt processing for the device. + */ + XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr, + (Xil_ExceptionHandler)XEmacPs_IntrHandler, + (void *)&xemacpsif->emacps); + /* + * Enable the interrupt for emacps. + */ + EmacEnableIntr( ); + + return 0; +} + +/* + * resetrx_on_no_rxdata(): + * + * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata + * called by the user. + * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic. + * Under heavy Rx traffic because of the HW bug there are times when the Rx path + * becomes unresponsive. The workaround for it is to check for the Rx path for + * traffic (by reading the stats registers regularly). If the stats register + * does not increment for sometime (proving no Rx traffic), the function resets + * the Rx data path. + * + */ + +void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif) +{ + unsigned long regctrl; + unsigned long tempcntr; + + tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET ); + if ( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) ) + { + regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET); + regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK); + XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, regctrl); + regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET); + regctrl |= (XEMACPS_NWCTRL_RXEN_MASK); + XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl); + } + xemacpsif->last_rx_frms_cntr = tempcntr; +} + +void EmacDisableIntr(void) +{ + XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr); +} + +void EmacEnableIntr(void) +{ + XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr); +} + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.c new file mode 100644 index 000000000..3d835d9a2 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2010-2013 Xilinx, Inc. All rights reserved. + * + * Xilinx, Inc. + * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A + * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS + * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR + * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION + * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE + * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. + * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO + * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO + * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE + * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" + +#include "Zynq/x_emacpsif.h" + +extern TaskHandle_t xEMACTaskHandle; + +/*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c + *** to run it on a PEEP board + ***/ + +void setup_isr( xemacpsif_s *xemacpsif ) +{ + /* + * Setup callbacks + */ + XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMASEND, + (void *) emacps_send_handler, + (void *) xemacpsif); + + XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMARECV, + (void *) emacps_recv_handler, + (void *) xemacpsif); + + XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_ERROR, + (void *) emacps_error_handler, + (void *) xemacpsif); +} + +void start_emacps (xemacpsif_s *xemacps) +{ + /* start the temac */ + XEmacPs_Start(&xemacps->emacps); +} + +extern struct xtopology_t xXTopology; + +volatile int error_msg_count = 0; +volatile const char *last_err_msg = ""; + +struct xERROR_MSG { + void *arg; + u8 Direction; + u32 ErrorWord; +}; + +static struct xERROR_MSG xErrorList[ 8 ]; +static BaseType_t xErrorHead, xErrorTail; + +void emacps_error_handler(void *arg, u8 Direction, u32 ErrorWord) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xemacpsif_s *xemacpsif; + BaseType_t xNextHead = xErrorHead; + + xemacpsif = (xemacpsif_s *)(arg); + + if( ( Direction != XEMACPS_SEND ) || (ErrorWord != XEMACPS_TXSR_USEDREAD_MASK ) ) + { + if( ++xNextHead == ( sizeof( xErrorList ) / sizeof( xErrorList[ 0 ] ) ) ) + xNextHead = 0; + if( xNextHead != xErrorTail ) + { + + xErrorList[ xErrorHead ].arg = arg; + xErrorList[ xErrorHead ].Direction = Direction; + xErrorList[ xErrorHead ].ErrorWord = ErrorWord; + + xErrorHead = xNextHead; + + xemacpsif = (xemacpsif_s *)(arg); + xemacpsif->isr_events |= EMAC_IF_ERR_EVENT; + } + + if( xEMACTaskHandle != NULL ) + { + vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken ); + } + + } + + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); +} + +static void emacps_handle_error(void *arg, u8 Direction, u32 ErrorWord); + +int emacps_check_errors( xemacpsif_s *xemacps ) +{ +int xResult; + + ( void ) xemacps; + + if( xErrorHead == xErrorTail ) + { + xResult = 0; + } + else + { + xResult = 1; + emacps_handle_error( + xErrorList[ xErrorTail ].arg, + xErrorList[ xErrorTail ].Direction, + xErrorList[ xErrorTail ].ErrorWord ); + } + + return xResult; +} + +static void emacps_handle_error(void *arg, u8 Direction, u32 ErrorWord) +{ + xemacpsif_s *xemacpsif; + struct xtopology_t *xtopologyp; + XEmacPs *xemacps; + + xemacpsif = (xemacpsif_s *)(arg); + + xtopologyp = &xXTopology; + + xemacps = &xemacpsif->emacps; + + /* Do not appear to be used. */ + ( void ) xemacps; + ( void ) xtopologyp; + + last_err_msg = NULL; + + if( ErrorWord != 0 ) + { + switch (Direction) { + case XEMACPS_RECV: + if( ( ErrorWord & XEMACPS_RXSR_HRESPNOK_MASK ) != 0 ) + { + last_err_msg = "Receive DMA error"; + xNetworkInterfaceInitialise( ); + } + if( ( ErrorWord & XEMACPS_RXSR_RXOVR_MASK ) != 0 ) + { + last_err_msg = "Receive over run"; + emacps_recv_handler(arg); + } + if( ( ErrorWord & XEMACPS_RXSR_BUFFNA_MASK ) != 0 ) + { + last_err_msg = "Receive buffer not available"; + emacps_recv_handler(arg); + } + break; + case XEMACPS_SEND: + if( ( ErrorWord & XEMACPS_TXSR_HRESPNOK_MASK ) != 0 ) + { + last_err_msg = "Transmit DMA error"; + xNetworkInterfaceInitialise( ); + } + if( ( ErrorWord & XEMACPS_TXSR_URUN_MASK ) != 0 ) + { + last_err_msg = "Transmit under run"; + HandleTxErrors( xemacpsif ); + } + if( ( ErrorWord & XEMACPS_TXSR_BUFEXH_MASK ) != 0 ) + { + last_err_msg = "Transmit buffer exhausted"; + HandleTxErrors( xemacpsif ); + } + if( ( ErrorWord & XEMACPS_TXSR_RXOVR_MASK ) != 0 ) + { + last_err_msg = "Transmit retry excessed limits"; + HandleTxErrors( xemacpsif ); + } + if( ( ErrorWord & XEMACPS_TXSR_FRAMERX_MASK ) != 0 ) + { + last_err_msg = "Transmit collision"; + emacps_check_tx( xemacpsif ); + } + break; + } + } + // Break on this statement and inspect error_msg if you like + if( last_err_msg != NULL ) + { + error_msg_count++; + FreeRTOS_printf( ( "emacps_handle_error: %s\n", last_err_msg ) ); + } +} + +void HandleTxErrors(xemacpsif_s *xemacpsif) +{ + u32 netctrlreg; + + //taskENTER_CRITICAL() + { + netctrlreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET); + netctrlreg = netctrlreg & (~XEMACPS_NWCTRL_TXEN_MASK); + XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, netctrlreg); + + clean_dma_txdescs( xemacpsif ); + netctrlreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET); + netctrlreg = netctrlreg | (XEMACPS_NWCTRL_TXEN_MASK); + XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, netctrlreg); + } + //taskEXIT_CRITICAL( ); +} diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.h new file mode 100644 index 000000000..f3c424a4b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_hw.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2010-2013 Xilinx, Inc. All rights reserved. + * + * Xilinx, Inc. + * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A + * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS + * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR + * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION + * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE + * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. + * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO + * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO + * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE + * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __XEMACPSIF_HW_H_ +#define __XEMACPSIF_HW_H_ + +#include "Zynq/x_emacpsif.h" +//#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +XEmacPs_Config * lookup_config(unsigned mac_base); + +//void init_emacps(xemacpsif_s *xemacpsif, struct netif *netif); + +int emacps_check_errors( xemacpsif_s *xemacps ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c new file mode 100644 index 000000000..d1999a73e --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_physpeed.c @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2007-2008, Advanced Micro Devices, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Advanced Micro Devices, Inc. nor the names + * of its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + */ + +/* + * Some portions copyright (c) 2010-2013 Xilinx, Inc. All rights reserved. + * + * Xilinx, Inc. + * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A + * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS + * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR + * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION + * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE + * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. + * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO + * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO + * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE + * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +/* Standard includes. */ +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkBufferManagement.h" + +#include "Zynq/x_emacpsif.h" +#include "xparameters_ps.h" +#include "xparameters.h" + + +int phy_detected = 0; + +/*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c + *** to run it on a PEEP board + ***/ + +/* Advertisement control register. */ +#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ +#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ +#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ +#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ + +#define ADVERTISE_100_AND_10 (ADVERTISE_10FULL | ADVERTISE_100FULL | \ + ADVERTISE_10HALF | ADVERTISE_100HALF) +#define ADVERTISE_100 (ADVERTISE_100FULL | ADVERTISE_100HALF) +#define ADVERTISE_10 (ADVERTISE_10FULL | ADVERTISE_10HALF) + +#define ADVERTISE_1000 0x0300 + + +//#define PHY_REG_00_BMCR 0x00 // Basic mode control register +//#define PHY_REG_01_BMSR 0x01 // Basic mode status register +//#define PHY_REG_02_PHYSID1 0x02 // PHYS ID 1 +//#define PHY_REG_03_PHYSID2 0x03 // PHYS ID 2 +//#define PHY_REG_04_ADVERTISE 0x04 // Advertisement control reg + +#define IEEE_CONTROL_REG_OFFSET 0 +#define IEEE_STATUS_REG_OFFSET 1 +#define IEEE_PHYSID1_OFFSET 2 +#define IEEE_PHYSID2_OFFSET 3 +#define IEEE_AUTONEGO_ADVERTISE_REG 4 +#define IEEE_PARTNER_ABILITIES_1_REG_OFFSET 5 +#define IEEE_1000_ADVERTISE_REG_OFFSET 9 +#define IEEE_PARTNER_ABILITIES_3_REG_OFFSET 10 +#define IEEE_COPPER_SPECIFIC_CONTROL_REG 16 +#define IEEE_SPECIFIC_STATUS_REG 17 +#define IEEE_COPPER_SPECIFIC_STATUS_REG_2 19 +#define IEEE_CONTROL_REG_MAC 21 +#define IEEE_PAGE_ADDRESS_REGISTER 22 + + +#define IEEE_CTRL_1GBPS_LINKSPEED_MASK 0x2040 +#define IEEE_CTRL_LINKSPEED_MASK 0x0040 +#define IEEE_CTRL_LINKSPEED_1000M 0x0040 +#define IEEE_CTRL_LINKSPEED_100M 0x2000 +#define IEEE_CTRL_LINKSPEED_10M 0x0000 +#define IEEE_CTRL_RESET_MASK 0x8000 +#define IEEE_CTRL_AUTONEGOTIATE_ENABLE 0x1000 +#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1 +#define IEEE_CTRL_RESET 0x9140 +#define IEEE_CTRL_ISOLATE_DISABLE 0xFBFF +#endif +#define IEEE_STAT_AUTONEGOTIATE_CAPABLE 0x0008 +#define IEEE_STAT_AUTONEGOTIATE_COMPLETE 0x0020 +#define IEEE_STAT_AUTONEGOTIATE_RESTART 0x0200 +#define IEEE_STAT_1GBPS_EXTENSIONS 0x0100 +#define IEEE_AN1_ABILITY_MASK 0x1FE0 +#define IEEE_AN3_ABILITY_MASK_1GBPS 0x0C00 +#define IEEE_AN1_ABILITY_MASK_100MBPS 0x0380 +#define IEEE_AN1_ABILITY_MASK_10MBPS 0x0060 +#define IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK 0x0030 + +#define IEEE_ASYMMETRIC_PAUSE_MASK 0x0800 +#define IEEE_PAUSE_MASK 0x0400 +#define IEEE_AUTONEG_ERROR_MASK 0x8000 + +#define XEMACPS_GMII2RGMII_SPEED1000_FD 0x140 +#define XEMACPS_GMII2RGMII_SPEED100_FD 0x2100 +#define XEMACPS_GMII2RGMII_SPEED10_FD 0x100 +#define XEMACPS_GMII2RGMII_REG_NUM 0x10 + +/* Frequency setting */ +#define SLCR_LOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x4) +#define SLCR_UNLOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x8) +#define SLCR_GEM0_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x140) +#define SLCR_GEM1_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x144) +#ifdef PEEP +#define SLCR_GEM_10M_CLK_CTRL_VALUE 0x00103031 +#define SLCR_GEM_100M_CLK_CTRL_VALUE 0x00103001 +#define SLCR_GEM_1G_CLK_CTRL_VALUE 0x00103011 +#endif +#define SLCR_LOCK_KEY_VALUE 0x767B +#define SLCR_UNLOCK_KEY_VALUE 0xDF0D +#define SLCR_ADDR_GEM_RST_CTRL (XPS_SYS_CTRL_BASEADDR + 0x214) +#define EMACPS_SLCR_DIV_MASK 0xFC0FC0FF + +#define EMAC0_BASE_ADDRESS 0xE000B000 +#define EMAC1_BASE_ADDRESS 0xE000C000 + +static int detect_phy(XEmacPs *xemacpsp) +{ + u16 id_lower, id_upper; + u32 phy_addr, id; + + for (phy_addr = 0; phy_addr < 32; phy_addr++) { + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PHYSID1_OFFSET, &id_lower); + + if ((id_lower != ( u16 )0xFFFFu) && (id_lower != ( u16 )0x0u)) { + + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PHYSID2_OFFSET, &id_upper); + id = ( ( ( uint32_t ) id_upper ) << 16 ) | ( id_lower & 0xFFF0 ); + FreeRTOS_printf( ("XEmacPs detect_phy: %04lX at address %d.\n", id, phy_addr ) ); + phy_detected = phy_addr; + return phy_addr; + } + } + + FreeRTOS_printf( ("XEmacPs detect_phy: No PHY detected. Assuming a PHY at address 0\n" ) ); + + /* default to zero */ + return 0; +} + +#ifdef PEEP +unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp) +{ + + u16 control; + u16 status; + u16 partner_capabilities; + u16 partner_capabilities_1000; + u16 phylinkspeed; + u32 phy_addr = detect_phy(xemacpsp); + + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, + ADVERTISE_1000); + /* Advertise PHY speed of 100 and 10 Mbps */ + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, + ADVERTISE_100_AND_10); + + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, + &control); + control |= (IEEE_CTRL_AUTONEGOTIATE_ENABLE | + IEEE_STAT_AUTONEGOTIATE_RESTART); + + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control); + + /* Read PHY control and status registers is successful. */ + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control); + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status); + + if ((control & IEEE_CTRL_AUTONEGOTIATE_ENABLE) && (status & + IEEE_STAT_AUTONEGOTIATE_CAPABLE)) { + + while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) { + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, + &status); + } + + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_1_REG_OFFSET, + &partner_capabilities); + + if (status & IEEE_STAT_1GBPS_EXTENSIONS) { + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_3_REG_OFFSET, + &partner_capabilities_1000); + if (partner_capabilities_1000 & IEEE_AN3_ABILITY_MASK_1GBPS) + return 1000; + } + + if (partner_capabilities & IEEE_AN1_ABILITY_MASK_100MBPS) + return 100; + if (partner_capabilities & IEEE_AN1_ABILITY_MASK_10MBPS) + return 10; + + FreeRTOS_printf( ( "%s: unknown PHY link speed, setting TEMAC speed to be 10 Mbps\n", + __FUNCTION__ ) ); + return 10; + + } else { + + /* Update TEMAC speed accordingly */ + if (status & IEEE_STAT_1GBPS_EXTENSIONS) { + /* Get commanded link speed */ + phylinkspeed = control & IEEE_CTRL_1GBPS_LINKSPEED_MASK; + + switch (phylinkspeed) { + case (IEEE_CTRL_LINKSPEED_1000M): + return 1000; + case (IEEE_CTRL_LINKSPEED_100M): + return 100; + case (IEEE_CTRL_LINKSPEED_10M): + return 10; + default: + FreeRTOS_printf( ( "%s: unknown PHY link speed (%d), setting TEMAC speed to be 10 Mbps\n", + __FUNCTION__, phylinkspeed ) ); + return 10; + } + + } else { + + return (control & IEEE_CTRL_LINKSPEED_MASK) ? 100 : 10; + + } + } +} + +#else /* Zynq */ +unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp) +{ + u16 temp; + u16 control; + u16 status; + u16 partner_capabilities; +#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1 + u32 phy_addr = XPAR_PCSPMA_SGMII_PHYADDR; +#else + u32 phy_addr = detect_phy(xemacpsp); +#endif + FreeRTOS_printf( ( "Start PHY autonegotiation \n" ) ); + +#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1 +#else + XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2); + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control); + control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK; + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control); + + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0); + + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control); + control |= IEEE_ASYMMETRIC_PAUSE_MASK; + control |= IEEE_PAUSE_MASK; + control |= ADVERTISE_100; + control |= ADVERTISE_10; + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control); + + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, + &control); + control |= ADVERTISE_1000; + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, + control); + + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0); + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG, + &control); + control |= (7 << 12); /* max number of gigabit attempts */ + control |= (1 << 11); /* enable downshift */ + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG, + control); +#endif + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control); + control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE; + control |= IEEE_STAT_AUTONEGOTIATE_RESTART; +#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1 + control &= IEEE_CTRL_ISOLATE_DISABLE; +#endif + + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control); + + +#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1 +#else + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control); + control |= IEEE_CTRL_RESET_MASK; + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control); + + while (1) { + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control); + if (control & IEEE_CTRL_RESET_MASK) + continue; + else + break; + } +#endif + FreeRTOS_printf( ( "Waiting for PHY to complete autonegotiation.\n" ) ); + + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status); + while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) { + vTaskDelay(1); +#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1 +#else + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2, + &temp); + if (temp & IEEE_AUTONEG_ERROR_MASK) { + FreeRTOS_printf( ( "Auto negotiation error \n" ) ); + } +#endif + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, + &status); + } + + FreeRTOS_printf( ( "autonegotiation complete \n" ) ); + +#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1 +#else + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_SPECIFIC_STATUS_REG, &partner_capabilities); +#endif + +#if XPAR_GIGE_PCS_PMA_CORE_PRESENT == 1 + FreeRTOS_printf( ( "Waiting for Link to be up; Polling for SGMII core Reg \n" ) ); + XEmacPs_PhyRead(xemacpsp, phy_addr, 5, &temp); + while(!(temp & 0x8000)) { + XEmacPs_PhyRead(xemacpsp, phy_addr, 5, &temp); + } + if((temp & 0x0C00) == 0x0800) { + XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp); + return 1000; + } + else if((temp & 0x0C00) == 0x0400) { + XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp); + return 100; + } + else if((temp & 0x0C00) == 0x0000) { + XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp); + return 10; + } else { + FreeRTOS_printf( ( "get_IEEE_phy_speed(): Invalid speed bit value, Deafulting to Speed = 10 Mbps\n" ) ); + XEmacPs_PhyRead(xemacpsp, phy_addr, 0, &temp); + XEmacPs_PhyWrite(xemacpsp, phy_addr, 0, 0x0100); + return 10; + } +#else + if ( ((partner_capabilities >> 14) & 3) == 2)/* 1000Mbps */ + return 1000; + else if ( ((partner_capabilities >> 14) & 3) == 1)/* 100Mbps */ + return 100; + else /* 10Mbps */ + return 10; +#endif +} +#endif + +unsigned configure_IEEE_phy_speed(XEmacPs *xemacpsp, unsigned speed) +{ + u16 control; + u32 phy_addr = detect_phy(xemacpsp); + + XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2); + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control); + control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK; + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control); + + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0); + + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control); + control |= IEEE_ASYMMETRIC_PAUSE_MASK; + control |= IEEE_PAUSE_MASK; + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control); + + XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control); + control &= ~IEEE_CTRL_LINKSPEED_1000M; + control &= ~IEEE_CTRL_LINKSPEED_100M; + control &= ~IEEE_CTRL_LINKSPEED_10M; + + if (speed == 1000) { + control |= IEEE_CTRL_LINKSPEED_1000M; + } + + else if (speed == 100) { + control |= IEEE_CTRL_LINKSPEED_100M; + /* Dont advertise PHY speed of 1000 Mbps */ + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, 0); + /* Dont advertise PHY speed of 10 Mbps */ + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, + ADVERTISE_100); + } + + else if (speed == 10) { + control |= IEEE_CTRL_LINKSPEED_10M; + /* Dont advertise PHY speed of 1000 Mbps */ + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, + 0); + /* Dont advertise PHY speed of 100 Mbps */ + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, + ADVERTISE_10); + } + + XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, + control | IEEE_CTRL_RESET_MASK); + { + volatile int wait; + for (wait=0; wait < 100000; wait++); + } + return 0; +} + +static void SetUpSLCRDivisors(int mac_baseaddr, int speed) +{ + volatile u32 slcrBaseAddress; +#ifndef PEEP + u32 SlcrDiv0; + u32 SlcrDiv1=0; + u32 SlcrTxClkCntrl; +#endif + + *(volatile unsigned int *)(SLCR_UNLOCK_ADDR) = SLCR_UNLOCK_KEY_VALUE; + + if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) { + slcrBaseAddress = SLCR_GEM0_CLK_CTRL_ADDR; + } else { + slcrBaseAddress = SLCR_GEM1_CLK_CTRL_ADDR; + } +#ifdef PEEP + if (speed == 1000) { + *(volatile unsigned int *)(slcrBaseAddress) = + SLCR_GEM_1G_CLK_CTRL_VALUE; + } else if (speed == 100) { + *(volatile unsigned int *)(slcrBaseAddress) = + SLCR_GEM_100M_CLK_CTRL_VALUE; + } else { + *(volatile unsigned int *)(slcrBaseAddress) = + SLCR_GEM_10M_CLK_CTRL_VALUE; + } +#else + if (speed == 1000) { + if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) { +#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 + SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0; + SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1; +#endif + } else { +#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0 + SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0; + SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1; +#endif + } + } else if (speed == 100) { + if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) { +#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 + SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0; + SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1; +#endif + } else { +#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0 + SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0; + SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV1; +#endif + } + } else { + if ((unsigned long)mac_baseaddr == EMAC0_BASE_ADDRESS) { +#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0 + SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0; + SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1; +#endif + } else { +#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0 + SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0; + SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV1; +#endif + } + } + SlcrTxClkCntrl = *(volatile unsigned int *)(slcrBaseAddress); + SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK; + SlcrTxClkCntrl |= (SlcrDiv1 << 20); + SlcrTxClkCntrl |= (SlcrDiv0 << 8); + *(volatile unsigned int *)(slcrBaseAddress) = SlcrTxClkCntrl; +#endif + *(volatile unsigned int *)(SLCR_LOCK_ADDR) = SLCR_LOCK_KEY_VALUE; + return; +} + + +unsigned link_speed; +unsigned Phy_Setup (XEmacPs *xemacpsp) +{ + unsigned long conv_present = 0; + unsigned long convspeeddupsetting = 0; + unsigned long convphyaddr = 0; + +#ifdef XPAR_GMII2RGMIICON_0N_ETH0_ADDR + convphyaddr = XPAR_GMII2RGMIICON_0N_ETH0_ADDR; + conv_present = 1; +#else +#ifdef XPAR_GMII2RGMIICON_0N_ETH1_ADDR + convphyaddr = XPAR_GMII2RGMIICON_0N_ETH1_ADDR; + conv_present = 1; +#endif +#endif + +#ifdef ipconfigNIC_LINKSPEED_AUTODETECT + link_speed = get_IEEE_phy_speed(xemacpsp); + if (link_speed == 1000) { + SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000); + convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD; + } else if (link_speed == 100) { + SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100); + convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD; + } else { + SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10); + convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD; + } +#elif defined(ipconfigNIC_LINKSPEED1000) + SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000); + link_speed = 1000; + configure_IEEE_phy_speed(xemacpsp, link_speed); + convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD; + vTaskDelay(1); +#elif defined(ipconfigNIC_LINKSPEED100) + SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100); + link_speed = 100; + configure_IEEE_phy_speed(xemacpsp, link_speed); + convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD; + vTaskDelay(1); +#elif defined(ipconfigNIC_LINKSPEED10) + SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10); + link_speed = 10; + configure_IEEE_phy_speed(xemacpsp, link_speed); + convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD; + vTaskDelay(1); +#endif + if (conv_present) { + XEmacPs_PhyWrite(xemacpsp, convphyaddr, + XEMACPS_GMII2RGMII_REG_NUM, convspeeddupsetting); + } + + FreeRTOS_printf( ( "link speed: %d\n", link_speed ) ); + return link_speed; +} + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_topology.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_topology.h new file mode 100644 index 000000000..bb5178346 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_topology.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2007-2013 Xilinx, Inc. All rights reserved. + * + * Xilinx, Inc. + * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A + * COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS + * ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR + * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION + * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE + * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. + * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO + * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO + * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE + * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __XTOPOLOGY_H_ +#define __XTOPOLOGY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +enum xemac_types { xemac_type_unknown = -1, xemac_type_xps_emaclite, xemac_type_xps_ll_temac, xemac_type_axi_ethernet, xemac_type_emacps }; + +struct xtopology_t { + unsigned emac_baseaddr; + enum xemac_types emac_type; + unsigned intc_baseaddr; + unsigned intc_emac_intr; /* valid only for xemac_type_xps_emaclite */ + unsigned scugic_baseaddr; /* valid only for Zynq */ + unsigned scugic_emac_intr; /* valid only for GEM */ +}; + +extern int x_topology_n_emacs; +extern struct xtopology_t x_topology[]; + +int x_topology_find_index(unsigned base); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/include/phyHandling.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/include/phyHandling.h new file mode 100644 index 000000000..d8e7e8de8 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/include/phyHandling.h @@ -0,0 +1,144 @@ +/* + * FreeRTOS+TCP 191100 experimental + * Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * 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. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* + * Handling of Ethernet PHY's + * PHY's communicate with an EMAC either through + * a Media-Independent Interface (MII), or a Reduced Media-Independent Interface (RMII). + * The EMAC can poll for PHY ports on 32 different addresses. Each of the PHY ports + * shall be treated independently. + * + */ + +#ifndef PHYHANDLING_H + +#define PHYHANDLING_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifndef ipconfigPHY_MAX_PORTS + /* There can be at most 32 PHY ports, but in most cases there are 4 or less. */ + #define ipconfigPHY_MAX_PORTS 4 +#endif + +/* A generic user-provided function that reads from the PHY-port at 'xAddress'( 0-based ). A 16-bit value shall be stored in + '*pusValue'. xRegister is the register number ( 0 .. 31 ). In fact all PHY registers are 16-bit. + Return non-zero in case the action failed. */ +typedef BaseType_t ( *xApplicationPhyReadHook_t )( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue ); + +/* A generic user-provided function that writes 'usValue' to the + PHY-port at 'xAddress' ( 0-based ). xRegister is the register number ( 0 .. 31 ). + Return non-zero in case the action failed. */ +typedef BaseType_t ( *xApplicationPhyWriteHook_t )( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue ); + +typedef struct xPhyProperties +{ + uint8_t ucSpeed; + uint8_t ucMDI_X; /* MDI-X : Medium Dependent Interface - Crossover */ + uint8_t ucDuplex; + uint8_t ucSpare; +} PhyProperties_t; + +typedef struct xEthernetPhy +{ + xApplicationPhyReadHook_t fnPhyRead; + xApplicationPhyWriteHook_t fnPhyWrite; + uint32_t ulPhyIDs[ ipconfigPHY_MAX_PORTS ]; + uint8_t ucPhyIndexes[ ipconfigPHY_MAX_PORTS ]; + TimeOut_t xLinkStatusTimer; + TickType_t xLinkStatusRemaining; + BaseType_t xPortCount; + uint32_t ulBCRValue; + uint32_t ulACRValue; + uint32_t ulLinkStatusMask; + PhyProperties_t xPhyPreferences; + PhyProperties_t xPhyProperties; +} EthernetPhy_t; + +/* Some defines used internally here to indicate preferences about speed, MDIX +(wired direct or crossed), and duplex (half or full). */ + +/* Values for PhyProperties_t::ucSpeed : */ +#define PHY_SPEED_10 1 +#define PHY_SPEED_100 2 +#define PHY_SPEED_AUTO 3 + +/* Values for PhyProperties_t::ucMDI_X : */ +#define PHY_MDIX_DIRECT 1 +#define PHY_MDIX_CROSSED 2 +#define PHY_MDIX_AUTO 3 + +/* Values for PhyProperties_t::ucDuplex : */ +#define PHY_DUPLEX_HALF 1 +#define PHY_DUPLEX_FULL 2 +#define PHY_DUPLEX_AUTO 3 + +/* ID's of supported PHY's : */ +#define PHY_ID_LAN8742A 0x0007c130 +#define PHY_ID_LAN8720 0x0007c0f0 + +#define PHY_ID_KSZ8041 0x000010A1 +#define PHY_ID_KSZ8051 0x000010A1 +#define PHY_ID_KSZ8081 0x000010A1 + +#define PHY_ID_KSZ8863 0x00221430 +#define PHY_ID_KSZ8081MNXIA 0x00221560 + +#define PHY_ID_DP83848I 0x20005C90 + + +/* Initialise the struct and assign a PHY-read and -write function. */ +void vPhyInitialise( EthernetPhy_t *pxPhyObject, xApplicationPhyReadHook_t fnPhyRead, xApplicationPhyWriteHook_t fnPhyWrite ); + +/* Discover all PHY's connected by polling 32 indexes ( zero-based ) */ +BaseType_t xPhyDiscover( EthernetPhy_t *pxPhyObject ); + +/* Send a reset commando to the connected PHY ports and send configuration. */ +BaseType_t xPhyConfigure( EthernetPhy_t *pxPhyObject, const PhyProperties_t *pxPhyProperties ); + +/* Give a commando to start auto negotiation on a set of PHY port's. */ +BaseType_t xPhyStartAutoNegotiation( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask ); + +/* Do not use auto negotiation but use predefined values from 'pxPhyObject->xPhyPreferences'. */ +BaseType_t xPhyFixedValue( EthernetPhy_t *pxPhyObject, uint32_t ulPhyMask ); + +/* Check the current Link Status. +'xHadReception' : make this true if a packet has been received since the +last call to this function. */ +BaseType_t xPhyCheckLinkStatus( EthernetPhy_t *pxPhyObject, BaseType_t xHadReception ); + +static __inline uint32_t xPhyGetMask( EthernetPhy_t *pxPhyObject ) +{ + return ( ( ( uint32_t ) 1u ) << pxPhyObject-> xPortCount ) - 1; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c new file mode 100644 index 000000000..544e5ba09 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c @@ -0,0 +1,1272 @@ +/* +FreeRTOS+TCP V2.0.11 +Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + + http://aws.amazon.com/freertos + http://www.FreeRTOS.org +*/ + +/* Standard includes. */ +#include +#include +#include +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkBufferManagement.h" +#include "NetworkInterface.h" + +#include "sam4e_xplained_pro.h" +#include "hr_gettime.h" +#include "conf_eth.h" +#include "ksz8851snl.h" +#include "ksz8851snl_reg.h" + +/* Some files from the Atmel Software Framework */ +#include +#include +#include + +/* + Sending a packet: + + 1) Called by UP-task, add buffer to the TX-list: + xNetworkInterfaceOutput() + tx_buffers[ us_tx_head ] = pxNetworkBuffer; + tx_busy[ us_tx_head ] = pdTRUE; + us_tx_head++; + + 2) Called by EMAC-Task: start SPI transfer + ksz8851snl_update() + if( ul_spi_pdc_status == SPI_PDC_IDLE ) + { + if( ( tx_busy[ us_tx_tail ] != pdFALSE ) && + ( us_pending_frame == 0 ) && + ( ul_had_intn_interrupt == 0 ) ) + { + // disable all interrupts. + ksz8851_reg_write( REG_INT_MASK, 0 ); + Bring KSZ8851SNL_CSN_GPIO low + ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength ); + ul_spi_pdc_status = SPI_PDC_TX_START; + tx_cur_buffer = pxNetworkBuffer; + } + } + 3) Wait for SPI RXBUFF interrupt + SPI_Handler() + if( ul_spi_pdc_status == SPI_PDC_TX_START ) + { + if( SPI_Status & SPI_SR_RXBUFF ) + { + ul_spi_pdc_status = SPI_PDC_TX_COMPLETE; + } + } + + 4) Called by EMAC-Task: finish SPI transfer + ksz8851snl_update() + if( ul_spi_pdc_status == SPI_PDC_TX_COMPLETE ) + { + ul_spi_pdc_status = SPI_PDC_IDLE; + Bring KSZ8851SNL_CSN_GPIO high + // TX step12: disable TXQ write access. + ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START ); + // TX step12.1: enqueue frame in TXQ. + ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE ); + + // RX step13: enable INT_RX flag. + ksz8851_reg_write( REG_INT_MASK, INT_RX ); + + // Buffer sent, free the corresponding buffer and mark descriptor as owned by software. + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + + tx_buffers[ us_tx_tail ] = NULL; + tx_busy[ us_tx_tail ] = pdFALSE; + us_tx_tail++ + } + + Receiving a packet: + + 1) Wait for a INTN interrupt + INTN_Handler() + ul_had_intn_interrupt = 1 + vTaskNotifyGiveFromISR(); // Wake up the EMAC task + + 2) Called by EMAC-Task: check for new fragments and start SPI transfer + ksz8851snl_update() + if( ul_spi_pdc_status == SPI_PDC_IDLE ) + { + if( ( ul_had_intn_interrupt != 0 ) || ( us_pending_frame > 0 ) ) + { + if( us_pending_frame == 0 ) + { + us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8; + if( us_pending_frame == 0 ) + { + break; + } + } + // RX step2: disable all interrupts. + ksz8851_reg_write( REG_INT_MASK, 0 ); + Check if there is a valid packet: REG_RX_FHR_STATUS + Read the length of the next fragment: REG_RX_FHR_BYTE_CNT + ul_spi_pdc_status = SPI_PDC_RX_START; + gpio_set_pin_low(KSZ8851SNL_CSN_GPIO); + // Start SPI data transfer + ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer, xReadLength ); + } + } + + 3) Wait for SPI RXBUFF interrupt + SPI_Handler() + if( ul_spi_pdc_status == SPI_PDC_RX_START: + { + if( ( ulCurrentSPIStatus & SPI_SR_RXBUFF ) != 0 ) + { + // Transfer complete, disable SPI RXBUFF interrupt. + spi_disable_interrupt( KSZ8851SNL_SPI, SPI_IDR_RXBUFF ); + + ul_spi_pdc_status = SPI_PDC_RX_COMPLETE; + } + } + } + + 4) Finish SPI transfer + ksz8851snl_update() + if( ul_spi_pdc_status == SPI_PDC_RX_COMPLETE ) + { + ul_spi_pdc_status = SPI_PDC_IDLE; + Bring KSZ8851SNL_CSN_GPIO high + // RX step21: end RXQ read access. + ksz8851_reg_clrbits(REG_RXQ_CMD, RXQ_START); + // RX step22-23: update frame count to be read. + us_pending_frame-- + // RX step24: enable INT_RX flag if transfer complete. + if( us_pending_frame == 0 ) + { + // Allow more RX interrupts. + ksz8851_reg_write( REG_INT_MASK, INT_RX ); + } + + // Mark descriptor ready to be read. + rx_ready[ rxHead ] = pdTRUE; + rxHead++ + } +*/ + +#define PHY_REG_00_BMCR 0x00 // Basic mode control register +#define PHY_REG_01_BMSR 0x01 // Basic mode status register +#define PHY_REG_02_PHYSID1 0x02 // PHYS ID 1 +#define PHY_REG_03_PHYSID2 0x03 // PHYS ID 2 +#define PHY_REG_04_ADVERTISE 0x04 // Advertisement control reg +#define PHY_REG_05_LPA 0x05 // Link partner ability reg +#define PHY_REG_06_ANER 0x06 // 6 RW Auto-Negotiation Expansion Register +#define PHY_REG_07_ANNPTR 0x07 // 7 RW Auto-Negotiation Next Page TX +#define PHY_REG_08_RESERVED0 0x08 // 0x08..0x0Fh 8-15 RW RESERVED + +#define BMSR_LINK_STATUS 0x0004 //!< Link status + +#ifndef PHY_LS_HIGH_CHECK_TIME_MS + /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not + receiving packets. */ + #define PHY_LS_HIGH_CHECK_TIME_MS 15000 +#endif + +#ifndef PHY_LS_LOW_CHECK_TIME_MS + /* Check if the LinkSStatus in the PHY is still low every second. */ + #define PHY_LS_LOW_CHECK_TIME_MS 1000 +#endif + +/* Interrupt events to process. Currently only the Rx event is processed +although code for other events is included to allow for possible future +expansion. */ +#define EMAC_IF_RX_EVENT 1UL +#define EMAC_IF_TX_EVENT 2UL +#define EMAC_IF_ERR_EVENT 4UL +#define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT ) + +#define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR + +#ifdef ipconfigHAS_TX_CRC_OFFLOADING + #undef ipconfigHAS_TX_CRC_OFFLOADING +#endif +/* Override this define because the KSZ8851 is programmed to set all outgoing CRC's */ +#define ipconfigHAS_TX_CRC_OFFLOADING 1 + +#ifndef EMAC_MAX_BLOCK_TIME_MS + #define EMAC_MAX_BLOCK_TIME_MS 100ul +#endif + +/* Default the size of the stack used by the EMAC deferred handler task to 4x +the size of the stack used by the idle task - but allow this to be overridden in +FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */ +#ifndef configEMAC_TASK_STACK_SIZE + #define configEMAC_TASK_STACK_SIZE ( 6 * configMINIMAL_STACK_SIZE ) +#endif + +#define SPI_PDC_IDLE 0 +#define SPI_PDC_RX_START 1 +#define SPI_PDC_TX_ERROR 2 +#define SPI_PDC_RX_COMPLETE 3 +#define SPI_PDC_TX_START 4 +#define SPI_PDC_RX_ERROR 5 +#define SPI_PDC_TX_COMPLETE 6 + +/** + * ksz8851snl driver structure. + */ +typedef struct { + /** Set to 1 when owner is software (ready to read), 0 for Micrel. */ + uint32_t rx_ready[MICREL_RX_BUFFERS]; + /** Set to 1 when owner is Micrel, 0 for software. */ + uint32_t tx_busy[MICREL_TX_BUFFERS]; + /** RX NetworkBufferDescriptor_t pointer list */ + NetworkBufferDescriptor_t *rx_buffers[MICREL_RX_BUFFERS]; + /** TX NetworkBufferDescriptor_t pointer list */ + NetworkBufferDescriptor_t *tx_buffers[MICREL_TX_BUFFERS]; + NetworkBufferDescriptor_t *tx_cur_buffer; + + /** Circular buffer head pointer for packet received. */ + uint32_t us_rx_head; + /** Circular buffer tail pointer for packet to be read. */ + uint32_t us_rx_tail; + /** Circular buffer head pointer by upper layer (buffer to be sent). */ + uint32_t us_tx_head; + /** Circular buffer tail pointer incremented by handlers (buffer sent). */ + uint32_t us_tx_tail; + + uint32_t ul_total_tx; + uint32_t ul_total_rx; + uint32_t tx_space; + + /** Still experimental: hash table to allow certain multicast addresses. */ + uint16_t pusHashTable[ 4 ]; + + /* ul_spi_pdc_status has "SPI_PDC_xxx" values. */ + volatile uint32_t ul_spi_pdc_status; + + /* ul_had_intn_interrupt becomes true within the INTN interrupt. */ + volatile uint32_t ul_had_intn_interrupt; + + uint16_t us_pending_frame; +} xKSZ8851_Device_t; + +/* SPI PDC register base. +Declared in ASF\sam\components\ksz8851snl\ksz8851snl.c */ +extern Pdc *g_p_spi_pdc; + +/* Temporary buffer for PDC reception. +declared in ASF\sam\components\ksz8851snl\ksz8851snl.c */ +extern uint8_t tmpbuf[1536]; + +COMPILER_ALIGNED(8) +static xKSZ8851_Device_t xMicrelDevice; + +static TaskHandle_t xTransmitHandle; + +/*-----------------------------------------------------------*/ + +/* + * Wait a fixed time for the link status to indicate the network is up. + */ +static BaseType_t xGMACWaitLS( TickType_t xMaxTime ); + +/* + * A deferred interrupt handler task that processes GMAC interrupts. + */ +static void prvEMACHandlerTask( void *pvParameters ); + +/* + * Try to obtain an Rx packet from the hardware. + */ +static uint32_t prvEMACRxPoll( void ); + +static inline unsigned long ulReadMDIO( unsigned uAddress ); + +static void ksz8851snl_low_level_init( void ); + +static NetworkBufferDescriptor_t *ksz8851snl_low_level_input( void ); + +/*-----------------------------------------------------------*/ + +/* Bit map of outstanding ETH interrupt events for processing. Currently only +the Rx interrupt is handled, although code is included for other events to +enable future expansion. */ +static volatile uint32_t ulISREvents; + +/* A copy of PHY register 1: 'PHY_REG_01_BMSR' */ +static uint32_t ulPHYLinkStatus = 0; +static volatile BaseType_t xGMACSwitchRequired; + +static void ksz8851snl_update( void ); + +static void ksz8851snl_rx_init( void ); + +static void ksz8851snl_tx_init( void ); + +/* Holds the handle of the task used as a deferred interrupt processor. The +handle is used so direct notifications can be sent to the task for all EMAC/DMA +related interrupts. */ +TaskHandle_t xEMACTaskHandle = NULL; + + +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceInitialise( void ) +{ +const TickType_t x5_Seconds = 5000UL; + + if( xEMACTaskHandle == NULL ) + { + ksz8851snl_low_level_init(); + + /* Wait at most 5 seconds for a Link Status in the PHY. */ + xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) ); + + /* The handler task is created at the highest possible priority to + ensure the interrupt handler can return directly to it. */ + xTaskCreate( prvEMACHandlerTask, "KSZ8851", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle ); + configASSERT( xEMACTaskHandle ); + } + + /* When returning non-zero, the stack will become active and + start DHCP (in configured) */ + ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR ); + + return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0; +} +/*-----------------------------------------------------------*/ + +BaseType_t xGetPhyLinkStatus( void ) +{ +BaseType_t xResult; + + /* This function returns true if the Link Status in the PHY is high. */ + if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) + { + xResult = pdTRUE; + } + else + { + xResult = pdFALSE; + } + + return xResult; +} +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t bReleaseAfterSend ) +{ +BaseType_t xResult = pdFALSE; +int txHead = xMicrelDevice.us_tx_head; + + /* Make sure the next descriptor is free. */ + if( xMicrelDevice.tx_busy[ txHead ] != pdFALSE ) + { + /* All TX buffers busy. */ + } + else if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 ) + { + /* Output: LS low. */ + } + else + { + /* Pass the packet. */ + xMicrelDevice.tx_buffers[ txHead ] = pxNetworkBuffer; + /* The descriptor is now owned by Micrel. */ + xMicrelDevice.tx_busy[ txHead ] = pdTRUE; + + /* Move the head pointer. */ + if( ++txHead == MICREL_TX_BUFFERS ) + { + txHead = 0; + } + xMicrelDevice.us_tx_head = txHead; + if( xEMACTaskHandle != NULL ) + { + xTaskNotifyGive( xEMACTaskHandle ); + } + + #if( ipconfigZERO_COPY_TX_DRIVER != 1 ) + #warning Please ipconfigZERO_COPY_TX_DRIVER as 1 + #endif + configASSERT( bReleaseAfterSend != pdFALSE ); + xResult = pdTRUE; + } + if( ( xResult == pdFALSE ) && ( bReleaseAfterSend != pdFALSE ) ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + return xResult; +} +/*-----------------------------------------------------------*/ + +/* This Micrel has numbered it's PHY registers in a different way. +Translate the register index. */ +static int ks8851_phy_reg( int reg ) +{ + switch (reg) { + case PHY_REG_00_BMCR: + return REG_PHY_CNTL; // P1MBCR; + case PHY_REG_01_BMSR: + return REG_PHY_STATUS; + case PHY_REG_02_PHYSID1: + return REG_PHY_ID_LOW; + case PHY_REG_03_PHYSID2: + return REG_PHY_ID_HIGH; + case PHY_REG_04_ADVERTISE: + return REG_PHY_AUTO_NEGOTIATION; + case PHY_REG_05_LPA: + return REG_PHY_REMOTE_CAPABILITY; + } + + return 0x0; +} +/*-----------------------------------------------------------*/ + +static inline unsigned long ulReadMDIO( unsigned uAddress ) +{ +uint16_t usPHYStatus; +int ks8851_reg = ks8851_phy_reg( uAddress ); + + if( ks8851_reg != 0 ) + { + usPHYStatus = ksz8851_reg_read( ks8851_reg ); + } + else + { + /* Other addresses not yet implemented. */ + usPHYStatus = 0; + } + return usPHYStatus; +} +/*-----------------------------------------------------------*/ + +static BaseType_t xGMACWaitLS( TickType_t xMaxTime ) +{ +TickType_t xStartTime = xTaskGetTickCount(); +TickType_t xEndTime; +BaseType_t xReturn; +const TickType_t xShortTime = pdMS_TO_TICKS( 100UL ); +const uint32_t ulHz_Per_MHz = 1000000UL; + + for( ;; ) + { + xEndTime = xTaskGetTickCount(); + + if( ( xEndTime - xStartTime ) > xMaxTime ) + { + /* Wated more than xMaxTime, return. */ + xReturn = pdFALSE; + break; + } + + /* Check the link status again. */ + ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR ); + + if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) + { + /* Link is up - return. */ + xReturn = pdTRUE; + break; + } + + /* Link is down - wait in the Blocked state for a short while (to allow + other tasks to execute) before checking again. */ + vTaskDelay( xShortTime ); + } + + FreeRTOS_printf( ( "xGMACWaitLS: %ld freq %lu Mz\n", + xReturn, + sysclk_get_cpu_hz() / ulHz_Per_MHz ) ); + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static void vPioSetPinHigh(uint32_t ul_pin) +{ + Pio *p_pio = (Pio *)((uint32_t)PIOA + (PIO_DELTA * (ul_pin >> 5))); + // Value to be driven on the I/O line: 1. + p_pio->PIO_SODR = 1 << (ul_pin & 0x1F); +} + +/** + * \brief Handler for SPI interrupt. + */ +void SPI_Handler(void) +{ +BaseType_t xDoWakeup = pdFALSE; +BaseType_t xKSZTaskWoken = pdFALSE; +uint32_t ulCurrentSPIStatus; +uint32_t ulEnabledSPIStatus; + + ulCurrentSPIStatus = spi_read_status( KSZ8851SNL_SPI ); + ulEnabledSPIStatus = spi_read_interrupt_mask( KSZ8851SNL_SPI ); + ulCurrentSPIStatus &= ulEnabledSPIStatus; + spi_disable_interrupt( KSZ8851SNL_SPI, ulCurrentSPIStatus ); + + + switch( xMicrelDevice.ul_spi_pdc_status ) + { + case SPI_PDC_RX_START: + { + if( ( ulCurrentSPIStatus & SPI_SR_OVRES ) != 0 ) + { + pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); + xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_ERROR; + xDoWakeup = pdTRUE; + } + else + { + if( ( ulCurrentSPIStatus & SPI_SR_RXBUFF ) != 0 ) + { + xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_COMPLETE; + xDoWakeup = pdTRUE; + } + } + } + break; + + case SPI_PDC_TX_START: + { + /* Middle of TX. */ + if( ( ulCurrentSPIStatus & SPI_SR_OVRES ) != 0 ) + { + pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); + xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_ERROR; + xDoWakeup = pdTRUE; + } + else + { + if( ( ulCurrentSPIStatus & SPI_SR_ENDRX ) != 0 ) + { + /* Enable RX complete interrupt. */ + spi_enable_interrupt( KSZ8851SNL_SPI, SPI_IER_RXBUFF ); + } + /* End of TX. */ + if( ( ulCurrentSPIStatus & SPI_END_OF_TX ) != 0 ) + { + xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_COMPLETE; + xDoWakeup = pdTRUE; + } + } + } + break; + } /* switch( xMicrelDevice.ul_spi_pdc_status ) */ + + if( xDoWakeup != pdFALSE ) + { + if( xEMACTaskHandle != NULL ) + { + vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xKSZTaskWoken ); + } + } + else + { + } + portEND_SWITCHING_ISR( xKSZTaskWoken ); +} +/*-----------------------------------------------------------*/ + +static void INTN_Handler(uint32_t id, uint32_t mask) +{ +BaseType_t xKSZTaskWoken = pdFALSE; + + if( ( id == INTN_ID ) && + ( mask == INTN_PIN_MSK ) ) + { + /* Clear the PIO interrupt flags. */ + pio_get_interrupt_status( INTN_PIO ); + + /* Set the INTN flag. */ + xMicrelDevice.ul_had_intn_interrupt++; + if( xEMACTaskHandle != NULL ) + { + vTaskNotifyGiveFromISR( xEMACTaskHandle, &( xKSZTaskWoken ) ); + } + } + portEND_SWITCHING_ISR( xKSZTaskWoken ); +} +/*-----------------------------------------------------------*/ + +/** + * \brief Populate the RX descriptor ring buffers with pbufs. + * + * \param p_ksz8851snl_dev Pointer to driver data structure. + */ +static void ksz8851snl_rx_populate_queue( void ) +{ + uint32_t ul_index = 0; + NetworkBufferDescriptor_t *pxNetworkBuffer; + + /* Set up the RX descriptors */ + for (ul_index = 0; ul_index < MICREL_RX_BUFFERS; ul_index++) { + if( xMicrelDevice.rx_buffers[ ul_index ] == NULL ) + { + /* Allocate a new NetworkBufferDescriptor_t with the maximum size. */ + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ipconfigNETWORK_MTU + 36, 100 ); + if( pxNetworkBuffer == NULL ) + { + FreeRTOS_printf( ( "ksz8851snl_rx_populate_queue: NetworkBufferDescriptor_t allocation failure\n" ) ); + configASSERT( 1 == 2 ); + } + + /* Make sure lwIP is well configured so one NetworkBufferDescriptor_t can contain the maximum packet size. */ + //LWIP_ASSERT("ksz8851snl_rx_populate_queue: NetworkBufferDescriptor_t size too small!", pbuf_clen(pxNetworkBuffer) <= 1); + + /* Save NetworkBufferDescriptor_t pointer to be sent to lwIP upper layer. */ + xMicrelDevice.rx_buffers[ ul_index ] = pxNetworkBuffer; + /* Pass it to Micrel for reception. */ + xMicrelDevice.rx_ready[ ul_index ] = pdFALSE; + } + } +} + +unsigned tx_space, wait_tx_space, tx_status, fhr_status; +unsigned rx_debug = 0; +/** + * \brief Update Micrel state machine and perform required actions. + * + * \param netif the lwIP network interface structure for this ethernetif. + */ +static void ksz8851snl_update() +{ + uint16_t txmir = 0; + +/* Check for free PDC. */ + switch( xMicrelDevice.ul_spi_pdc_status ) + { + case SPI_PDC_TX_ERROR: + { + uint32_t ulValue; + // /* TX step11: end TX transfer. */ + gpio_set_pin_high( KSZ8851SNL_CSN_GPIO ); + + vTaskDelay( 2 ); gpio_set_pin_low( KSZ8851SNL_CSN_GPIO ); + vTaskDelay( 1 ); gpio_set_pin_high( KSZ8851SNL_CSN_GPIO ); + vTaskDelay( 1 ); + + /* Disable asynchronous transfer mode. */ + xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE; + + /* TX step12: disable TXQ write access. */ + ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START ); + + ulValue = ksz8851snl_reset_tx(); + + xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK; + + FreeRTOS_printf( ("SPI_PDC_TX_ERROR %02X\n", ulValue ) ); + } + break; + + case SPI_PDC_RX_ERROR: + { + uint32_t ulValue; + /* TX step11: end TX transfer. */ + gpio_set_pin_high( KSZ8851SNL_CSN_GPIO ); + + vTaskDelay( 2 ); gpio_set_pin_low( KSZ8851SNL_CSN_GPIO ); + vTaskDelay( 1 ); gpio_set_pin_high( KSZ8851SNL_CSN_GPIO ); + vTaskDelay( 1 ); + + /* Disable asynchronous transfer mode. */ + xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE; + + /* TX step12: disable TXQ write access. */ + ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START ); + + //ulValue = ksz8851snl_reset_rx(); + ulValue = ksz8851snl_reinit(); + + xGMACWaitLS( pdMS_TO_TICKS( 5000UL ) ); + + FreeRTOS_printf( ("SPI_PDC_RX_ERROR %02X\n", ulValue ) ); + } + break; + } + switch( xMicrelDevice.ul_spi_pdc_status ) + { + case SPI_PDC_IDLE: + { + int txTail = xMicrelDevice.us_tx_tail; + + /* + * ========================== Handle RX ========================== + */ + if( ( xMicrelDevice.ul_had_intn_interrupt != 0 ) || ( xMicrelDevice.us_pending_frame > 0 ) ) + { + int rxHead = xMicrelDevice.us_rx_head; + NetworkBufferDescriptor_t *pxNetworkBuffer; +#warning try + xMicrelDevice.ul_had_intn_interrupt = 0; + + if( xMicrelDevice.us_pending_frame == 0 ) + { + uint16_t int_status; + /* RX step1: read interrupt status for INT_RX flag. */ + int_status = ksz8851_reg_read( REG_INT_STATUS ); + + + /* RX step2: disable all interrupts. */ + ksz8851_reg_write( REG_INT_MASK, 0 ); + + /* RX step3: clear INT_RX flag. */ + ksz8851_reg_setbits( REG_INT_STATUS, INT_RX ); + + /* RX step4-5: check for received frames. */ + xMicrelDevice.us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8; + if( xMicrelDevice.us_pending_frame == 0 ) + { + /* RX step24: enable INT_RX flag. */ + ksz8851_reg_write(REG_INT_MASK, INT_RX); + return; + } + } +#warning try + xMicrelDevice.ul_had_intn_interrupt = 0; + + /* Now xMicrelDevice.us_pending_frame != 0 */ + + /* Don't break Micrel state machine, wait for a free descriptor first! */ + if( xMicrelDevice.rx_ready[ rxHead ] != pdFALSE ) + { + FreeRTOS_printf( ( "ksz8851snl_update: out of free descriptor! [tail=%u head=%u]\n", + xMicrelDevice.us_rx_tail, rxHead ) ); + return; + } + pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxHead ]; + + if( pxNetworkBuffer == NULL ) + { + ksz8851snl_rx_populate_queue(); + FreeRTOS_printf( ( "ksz8851snl_update: no buffer set [head=%u]\n", rxHead ) ); + return; + } + + /* RX step6: get RX packet status. */ + fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS ); + if( ( ( fhr_status & RX_VALID ) == 0 ) || ( ( fhr_status & RX_ERRORS ) != 0 ) ) + { + ksz8851_reg_setbits(REG_RXQ_CMD, RXQ_CMD_FREE_PACKET); + FreeRTOS_printf( ( "ksz8851snl_update: RX packet error!\n" ) ); + + /* RX step4-5: check for received frames. */ + xMicrelDevice.us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8; + if( xMicrelDevice.us_pending_frame == 0 ) + { + /* RX step24: enable INT_RX flag. */ + ksz8851_reg_write(REG_INT_MASK, INT_RX); + } + ulISREvents |= EMAC_IF_ERR_EVENT; + } + else + { + size_t xLength; + /* RX step7: read frame length. */ + xLength = ksz8851_reg_read(REG_RX_FHR_BYTE_CNT) & RX_BYTE_CNT_MASK; + + /* RX step8: Drop packet if len is invalid or no descriptor available. */ + if( xLength == 0 ) + { + ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_CMD_FREE_PACKET ); + FreeRTOS_printf( ( "ksz8851snl_update: RX bad len!\n" ) ); + ulISREvents |= EMAC_IF_ERR_EVENT; + } + else + { + size_t xReadLength = xLength; + + xMicrelDevice.ul_total_rx++; + /* RX step9: reset RX frame pointer. */ + ksz8851_reg_clrbits(REG_RX_ADDR_PTR, ADDR_PTR_MASK); + + /* RX step10: start RXQ read access. */ + ksz8851_reg_setbits(REG_RXQ_CMD, RXQ_START); + /* RX step11-17: start asynchronous FIFO read operation. */ + xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_START; + gpio_set_pin_low( KSZ8851SNL_CSN_GPIO ); + if( ( xReadLength & ( sizeof( size_t ) - 1 ) ) != 0 ) + { + xReadLength = ( xReadLength | ( sizeof( size_t ) - 1 ) ) + 1; + } + + /* Pass the buffer minus 2 bytes, see ksz8851snl.c: RXQ_TWOBYTE_OFFSET. */ + ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer - 2, xReadLength ); + /* Remove CRC and update buffer length. */ + xLength -= 4; + pxNetworkBuffer->xDataLength = xLength; + /* Wait for SPI interrupt to set status 'SPI_PDC_RX_COMPLETE'. */ + } + } + break; + } /* ul_had_intn_interrupt || us_pending_frame */ + /* + * ========================== Handle TX ========================== + */ + + /* Fetch next packet to be sent. */ + if( ( xMicrelDevice.tx_busy[ txTail ] != pdFALSE ) && + ( xMicrelDevice.us_pending_frame == 0 ) && + ( xMicrelDevice.ul_had_intn_interrupt == 0 ) ) + { + NetworkBufferDescriptor_t *pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ]; + size_t xLength = pxNetworkBuffer->xDataLength; + int iIndex = xLength; + + xLength = 4 * ( ( xLength + 3 ) / 4 ); + while( iIndex < ( int ) xLength ) + { + pxNetworkBuffer->pucEthernetBuffer[ iIndex ] = '\0'; + iIndex++; + } + pxNetworkBuffer->xDataLength = xLength; + + /* TX step1: check if TXQ memory size is available for transmit. */ + txmir = ksz8851_reg_read( REG_TX_MEM_INFO ); + txmir = txmir & TX_MEM_AVAILABLE_MASK; + + if( txmir < ( xLength + 8 ) ) + { + if( wait_tx_space == pdFALSE ) + { + tx_status = ksz8851_reg_read( REG_TX_STATUS ); + fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS ); + wait_tx_space = pdTRUE; + } + //return; + rx_debug = 1; + tx_space = txmir; + } + else + { + tx_space = txmir; + + /* TX step2: disable all interrupts. */ + ksz8851_reg_write( REG_INT_MASK, 0 ); + + xMicrelDevice.tx_space -= xLength; + + /* TX step3: enable TXQ write access. */ + ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_START ); + /* TX step4-8: perform FIFO write operation. */ + xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_START; + xMicrelDevice.tx_cur_buffer = pxNetworkBuffer; + /* Bring SPI SS low. */ + gpio_set_pin_low( KSZ8851SNL_CSN_GPIO ); + xMicrelDevice.ul_total_tx++; + + ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength ); + } + } + } + break; /* SPI_PDC_IDLE */ + + case SPI_PDC_RX_COMPLETE: + { + int rxHead = xMicrelDevice.us_rx_head; + /* RX step18-19: pad with dummy data to keep dword alignment. */ + /* Packet lengths will be rounded up to a multiple of "sizeof size_t". */ +// xLength = xMicrelDevice.rx_buffers[ rxHead ]->xDataLength & 3; +// if( xLength != 0 ) +// { +// ksz8851_fifo_dummy( 4 - xLength ); +// } + + /* RX step20: end RX transfer. */ + gpio_set_pin_high( KSZ8851SNL_CSN_GPIO ); + + /* Disable asynchronous transfer mode. */ + xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE; + + /* RX step21: end RXQ read access. */ + ksz8851_reg_clrbits(REG_RXQ_CMD, RXQ_START); + + /* RX step22-23: update frame count to be read. */ + xMicrelDevice.us_pending_frame -= 1; + + /* RX step24: enable INT_RX flag if transfer complete. */ + if( xMicrelDevice.us_pending_frame == 0 ) + { + ksz8851_reg_write(REG_INT_MASK, INT_RX); + } + + /* Mark descriptor ready to be read. */ + xMicrelDevice.rx_ready[ rxHead ] = pdTRUE; + if( ++rxHead == MICREL_RX_BUFFERS ) + { + rxHead = 0; + } + xMicrelDevice.us_rx_head = rxHead; + if( rx_debug != 0 ) + { + uint32_t txmir; + rx_debug = 0; + txmir = ksz8851_reg_read( REG_TX_MEM_INFO ); + txmir = txmir & TX_MEM_AVAILABLE_MASK; + } + /* Tell prvEMACHandlerTask that RX packets are available. */ + ulISREvents |= EMAC_IF_RX_EVENT; + } /* case SPI_PDC_RX_COMPLETE */ + break; + + case SPI_PDC_TX_COMPLETE: + { + int txTail = xMicrelDevice.us_tx_tail; + NetworkBufferDescriptor_t *pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ]; + + size_t xLength; + /* TX step9-10: pad with dummy data to keep dword alignment. */ + /* Not necessary: length is already a multiple of 4. */ + xLength = pxNetworkBuffer->xDataLength & 3; + if( xLength != 0 ) + { +// ksz8851_fifo_dummy( 4 - xLength ); + } + +// /* TX step11: end TX transfer. */ + gpio_set_pin_high( KSZ8851SNL_CSN_GPIO ); + + /* Disable asynchronous transfer mode. */ + xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE; + + /* TX step12: disable TXQ write access. */ + ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START ); + + xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK; + + /* TX step12.1: enqueue frame in TXQ. */ + ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE ); + + /* RX step13: enable INT_RX flag. */ +// ksz8851_reg_write( REG_INT_MASK, INT_RX ); + /* Buffer sent, free the corresponding buffer and mark descriptor as owned by software. */ + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + + xMicrelDevice.tx_buffers[ txTail ] = NULL; + xMicrelDevice.tx_busy[ txTail ] = pdFALSE; + if( ++txTail == MICREL_TX_BUFFERS ) + { + txTail = 0; + } + + xMicrelDevice.us_tx_tail = txTail; + /* Experiment. */ + //xMicrelDevice.ul_had_intn_interrupt = 1; + if( xTransmitHandle != NULL ) + { + xTaskNotifyGive( xTransmitHandle ); + } +#warning moved downward + /* RX step13: enable INT_RX flag. */ + ksz8851_reg_write( REG_INT_MASK, INT_RX ); + /* Prevent the EMAC task from sleeping a single time. */ + ulISREvents |= EMAC_IF_TX_EVENT; + } /* case SPI_PDC_TX_COMPLETE */ + break; + } /* switch( xMicrelDevice.ul_spi_pdc_status ) */ +} + +/** + * \brief Set up the RX descriptor ring buffers. + * + * This function sets up the descriptor list used for RX packets. + * + */ +static void ksz8851snl_rx_init() +{ + uint32_t ul_index = 0; + + /* Init pointer index. */ + xMicrelDevice.us_rx_head = 0; + xMicrelDevice.us_rx_tail = 0; + + /* Set up the RX descriptors. */ + for (ul_index = 0; ul_index < MICREL_RX_BUFFERS; ul_index++) { + xMicrelDevice.rx_buffers[ul_index] = NULL; + xMicrelDevice.rx_ready[ul_index] = pdFALSE; + } + + /* Build RX buffer and descriptors. */ + ksz8851snl_rx_populate_queue(); +} + +/** + * \brief Set up the TX descriptor ring buffers. + * + * This function sets up the descriptor list used for TX packets. + * + */ +static void ksz8851snl_tx_init() +{ + uint32_t ul_index = 0; + + /* Init TX index pointer. */ + xMicrelDevice.us_tx_head = 0; + xMicrelDevice.us_tx_tail = 0; + + /* Set up the TX descriptors */ + for( ul_index = 0; ul_index < MICREL_TX_BUFFERS; ul_index++ ) + { + xMicrelDevice.tx_busy[ul_index] = pdFALSE; + } + xMicrelDevice.tx_space = 6144; +} + +/** + * \brief Initialize ksz8851snl ethernet controller. + * + * \note Called from ethernetif_init(). + * + * \param netif the lwIP network interface structure for this ethernetif. + */ +static void ksz8851snl_low_level_init( void ) +{ + ksz8851snl_rx_init(); + ksz8851snl_tx_init(); + + /* Enable NVIC interrupts. */ + NVIC_SetPriority(SPI_IRQn, INT_PRIORITY_SPI); + NVIC_EnableIRQ(SPI_IRQn); + + /* Initialize SPI link. */ + if( ksz8851snl_init() < 0 ) + { + FreeRTOS_printf( ( "ksz8851snl_low_level_init: failed to initialize the Micrel driver!\n" ) ); + configASSERT(0 == 1); + } + memset( xMicrelDevice.pusHashTable, 255, sizeof( xMicrelDevice.pusHashTable ) ); + ksz8851_reg_write( REG_MAC_HASH_0, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 0 ] ) ); + ksz8851_reg_write( REG_MAC_HASH_2, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 1 ] ) ); + ksz8851_reg_write( REG_MAC_HASH_4, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 2 ] ) ); + ksz8851_reg_write( REG_MAC_HASH_6, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 3 ] ) ); + + /* Initialize interrupt line INTN. */ + configure_intn( INTN_Handler ); +} + +/** + * \brief Use pre-allocated pbuf as DMA source and return the incoming packet. + * + * \param netif the lwIP network interface structure for this ethernetif. + * + * \return a pbuf filled with the received packet (including MAC header). + * 0 on memory error. + */ +static NetworkBufferDescriptor_t *ksz8851snl_low_level_input( void ) +{ +NetworkBufferDescriptor_t *pxNetworkBuffer = NULL; +int rxTail = xMicrelDevice.us_rx_tail; + + /* Check that descriptor is owned by software (ie packet received). */ + if( xMicrelDevice.rx_ready[ rxTail ] != pdFALSE ) + { + + /* Fetch pre-allocated buffer */ + pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxTail ]; + + /* Remove this pbuf from its descriptor. */ + xMicrelDevice.rx_buffers[ rxTail ] = NULL; + + /* Clears rx_ready and sets rx_buffers. */ + ksz8851snl_rx_populate_queue(); + + if( ++rxTail == MICREL_RX_BUFFERS ) + { + rxTail = 0; + } + xMicrelDevice.us_rx_tail = rxTail; + } + + return pxNetworkBuffer; +} +/*-----------------------------------------------------------*/ + +static uint32_t prvEMACRxPoll( void ) +{ +NetworkBufferDescriptor_t *pxNetworkBuffer; +IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; +uint32_t ulReturnValue = 0; + + for( ;; ) + { + /* Only for logging. */ + int rxTail = xMicrelDevice.us_rx_tail; + EthernetHeader_t *pxEthernetHeader; + + pxNetworkBuffer = ksz8851snl_low_level_input(); + + if( pxNetworkBuffer == NULL ) + { + break; + } + pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); + + if( ( pxEthernetHeader->usFrameType != ipIPv4_FRAME_TYPE ) && + ( pxEthernetHeader->usFrameType != ipARP_FRAME_TYPE ) ) + { + FreeRTOS_printf( ( "Frame type %02X received\n", pxEthernetHeader->usFrameType ) ); + } + ulReturnValue++; + + xRxEvent.pvData = ( void * )pxNetworkBuffer; + /* Send the descriptor to the IP task for processing. */ + if( xSendEventStructToIPTask( &xRxEvent, 100UL ) != pdTRUE ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + iptraceETHERNET_RX_EVENT_LOST(); + FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) ); + } + } + + return ulReturnValue; +} +/*-----------------------------------------------------------*/ + +static void prvEMACHandlerTask( void *pvParameters ) +{ +TimeOut_t xPhyTime; +TickType_t xPhyRemTime; +TickType_t xLoggingTime; +UBaseType_t uxLastMinBufferCount = 0; +UBaseType_t uxCurrentCount; +BaseType_t xResult = 0; +uint32_t xStatus; +const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS ); +#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + UBaseType_t uxLastMinQueueSpace = 0; +#endif + + /* Remove compiler warnings about unused parameters. */ + ( void ) pvParameters; + + configASSERT( xEMACTaskHandle ); + + vTaskSetTimeOutState( &xPhyTime ); + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS ); + xLoggingTime = xTaskGetTickCount(); + + for( ;; ) + { + uxCurrentCount = uxGetMinimumFreeNetworkBuffers(); + if( uxLastMinBufferCount != uxCurrentCount ) + { + /* The logging produced below may be helpful + while tuning +TCP: see how many buffers are in use. */ + uxLastMinBufferCount = uxCurrentCount; + FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n", + uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) ); + } + + #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + { + uxCurrentCount = uxGetMinimumIPQueueSpace(); + if( uxLastMinQueueSpace != uxCurrentCount ) + { + /* The logging produced below may be helpful + while tuning +TCP: see how many buffers are in use. */ + uxLastMinQueueSpace = uxCurrentCount; + FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) ); + } + } + #endif /* ipconfigCHECK_IP_QUEUE_SPACE */ + + /* Run the state-machine of the ksz8851 driver. */ + ksz8851snl_update(); + + if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 ) + { + /* No events to process now, wait for the next. */ + ulTaskNotifyTake( pdTRUE, ulMaxBlockTime ); + } + + if( ( xTaskGetTickCount() - xLoggingTime ) > 10000 ) + { + xLoggingTime += 10000; + FreeRTOS_printf( ( "Now Tx/Rx %7d /%7d\n", + xMicrelDevice.ul_total_tx, xMicrelDevice.ul_total_rx ) ); + } + + if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 ) + { + ulISREvents &= ~EMAC_IF_RX_EVENT; + + /* Wait for the EMAC interrupt to indicate that another packet has been + received. */ + xResult = prvEMACRxPoll(); + } + + if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 ) + { + /* Future extension: code to release TX buffers if zero-copy is used. */ + ulISREvents &= ~EMAC_IF_TX_EVENT; + } + + if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 ) + { + /* Future extension: logging about errors that occurred. */ + ulISREvents &= ~EMAC_IF_ERR_EVENT; + } + + if( xResult > 0 ) + { + /* As long as packets are being received, assume that + the Link Status is high. */ + ulPHYLinkStatus |= BMSR_LINK_STATUS; + /* A packet was received. No need to check for the PHY status now, + but set a timer to check it later on. */ + vTaskSetTimeOutState( &xPhyTime ); + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS ); + xResult = 0; + } + else if( ( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ) && + ( xMicrelDevice.ul_spi_pdc_status == SPI_PDC_IDLE ) ) + { + /* Check the link status again. */ + xStatus = ulReadMDIO( PHY_REG_01_BMSR ); + + if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) ) + { + ulPHYLinkStatus = xStatus; + FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) ); + } + + vTaskSetTimeOutState( &xPhyTime ); + if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) + { + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS ); + } + else + { + xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS ); + } + } + } +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/ksz8851snl.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/ksz8851snl.c new file mode 100644 index 000000000..1579863fe --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/ksz8851snl.c @@ -0,0 +1,610 @@ +/** + * + * \file + * + * \brief KS8851SNL driver for SAM. + * + * Copyright (c) 2013-2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Atmel Support + */ + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" + +#include "spi_master.h" +#include "ksz8851snl.h" +#include "ksz8851snl_reg.h" +#include "delay.h" +#include "pio.h" +#include "pio_handler.h" +#include "pdc.h" +#include "conf_eth.h" + +/* Clock polarity. */ +#define SPI_CLK_POLARITY 0 + +/* Clock phase. */ +#define SPI_CLK_PHASE 1 + +/* SPI PDC register base. */ +Pdc *g_p_spi_pdc = 0; + +int lUDPLoggingPrintf( const char *pcFormatString, ... ); + +/* Temporary buffer for PDC reception. */ +uint8_t tmpbuf[1536] __attribute__ ((aligned (16))); + +union { + uint64_t ul[2]; + uint8_t uc[16]; +} cmdBuf, respBuf; + +void dbg_add_line( const char *pcFormat, ... ); + +static void spi_clear_ovres( void ); + +/** + * \brief Read register content, set bitmask and write back to register. + * + * \param reg the register address to modify. + * \param bits_to_set bitmask to apply. + */ +void ksz8851_reg_setbits(uint16_t reg, uint16_t bits_to_set) +{ + uint16_t temp; + + temp = ksz8851_reg_read(reg); + temp |= bits_to_set; + ksz8851_reg_write(reg, temp); +} + +/** + * \brief Read register content, clear bitmask and write back to register. + * + * \param reg the register address to modify. + * \param bits_to_set bitmask to apply. + */ +void ksz8851_reg_clrbits(uint16_t reg, uint16_t bits_to_clr) +{ + uint16_t temp; + + temp = ksz8851_reg_read(reg); + temp &= ~(uint32_t) bits_to_clr; + ksz8851_reg_write(reg, temp); +} + +/** + * \brief Configure the INTN interrupt. + */ +void configure_intn(void (*p_handler) (uint32_t, uint32_t)) +{ +// gpio_configure_pin(KSZ8851SNL_INTN_GPIO, PIO_INPUT); +// pio_set_input(PIOA, PIO_PA11_IDX, PIO_PULLUP); + + /* Configure PIO clock. */ + pmc_enable_periph_clk(INTN_ID); + + /* Adjust PIO debounce filter parameters, uses 10 Hz filter. */ + pio_set_debounce_filter(INTN_PIO, INTN_PIN_MSK, 10); + + /* Initialize PIO interrupt handlers, see PIO definition in board.h. */ + pio_handler_set(INTN_PIO, INTN_ID, INTN_PIN_MSK, + INTN_ATTR, p_handler); + + /* Enable NVIC interrupts. */ + NVIC_SetPriority(INTN_IRQn, INT_PRIORITY_PIO); + NVIC_EnableIRQ((IRQn_Type)INTN_ID); + + /* Enable PIO interrupts. */ + pio_enable_interrupt(INTN_PIO, INTN_PIN_MSK); +} + +/** + * \brief Read a register value. + * + * \param reg the register address to modify. + * + * \return the register value. + */ +uint16_t ksz8851_reg_read(uint16_t reg) +{ +pdc_packet_t g_pdc_spi_tx_packet; +pdc_packet_t g_pdc_spi_rx_packet; +uint16_t cmd = 0; +uint16_t res = 0; +int iTryCount = 3; + + while( iTryCount-- > 0 ) + { + uint32_t ulStatus; + + spi_clear_ovres(); + /* Move register address to cmd bits 9-2, make 32-bit address. */ + cmd = (reg << 2) & REG_ADDR_MASK; + + /* Last 2 bits still under "don't care bits" handled with byte enable. */ + /* Select byte enable for command. */ + if (reg & 2) { + /* Odd word address writes bytes 2 and 3 */ + cmd |= (0xc << 10); + } else { + /* Even word address write bytes 0 and 1 */ + cmd |= (0x3 << 10); + } + + /* Add command read code. */ + cmd |= CMD_READ; + cmdBuf.uc[0] = cmd >> 8; + cmdBuf.uc[1] = cmd & 0xff; + cmdBuf.uc[2] = CONFIG_SPI_MASTER_DUMMY; + cmdBuf.uc[3] = CONFIG_SPI_MASTER_DUMMY; + + /* Prepare PDC transfer. */ + g_pdc_spi_tx_packet.ul_addr = (uint32_t) cmdBuf.uc; + g_pdc_spi_tx_packet.ul_size = 4; + g_pdc_spi_rx_packet.ul_addr = (uint32_t) tmpbuf; + g_pdc_spi_rx_packet.ul_size = 4; + pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); + pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, NULL); + pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, NULL); + gpio_set_pin_low(KSZ8851SNL_CSN_GPIO); + + spi_disable_interrupt( KSZ8851SNL_SPI, ~0ul ); + pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN); + for( ;; ) + { + ulStatus = spi_read_status( KSZ8851SNL_SPI ); + if( ( ulStatus & ( SPI_SR_OVRES | SPI_SR_ENDRX ) ) != 0 ) + { + break; + } + } + gpio_set_pin_high( KSZ8851SNL_CSN_GPIO ); + if( ( ulStatus & SPI_SR_OVRES ) == 0 ) + { + break; + } + pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); + lUDPLoggingPrintf( "ksz8851_reg_read: SPI_SR_OVRES\n" ); + } + + res = (tmpbuf[3] << 8) | tmpbuf[2]; + return res; +} + +/** + * \brief Write a register value. + * + * \param reg the register address to modify. + * \param wrdata the new register value. + */ +void ksz8851_reg_write(uint16_t reg, uint16_t wrdata) +{ +pdc_packet_t g_pdc_spi_tx_packet; +pdc_packet_t g_pdc_spi_rx_packet; +uint16_t cmd = 0; +int iTryCount = 3; + + while( iTryCount-- > 0 ) + { + uint32_t ulStatus; + + + spi_clear_ovres(); + /* Move register address to cmd bits 9-2, make 32-bit address. */ + cmd = (reg << 2) & REG_ADDR_MASK; + + /* Last 2 bits still under "don't care bits" handled with byte enable. */ + /* Select byte enable for command. */ + if (reg & 2) { + /* Odd word address writes bytes 2 and 3 */ + cmd |= (0xc << 10); + } else { + /* Even word address write bytes 0 and 1 */ + cmd |= (0x3 << 10); + } + + /* Add command write code. */ + cmd |= CMD_WRITE; + cmdBuf.uc[0] = cmd >> 8; + cmdBuf.uc[1] = cmd & 0xff; + cmdBuf.uc[2] = wrdata & 0xff; + cmdBuf.uc[3] = wrdata >> 8; + + /* Prepare PDC transfer. */ + g_pdc_spi_tx_packet.ul_addr = (uint32_t) cmdBuf.uc; + g_pdc_spi_tx_packet.ul_size = 4; + g_pdc_spi_rx_packet.ul_addr = (uint32_t) tmpbuf; + g_pdc_spi_rx_packet.ul_size = 4; + pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); + pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, NULL); + pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, NULL); + gpio_set_pin_low(KSZ8851SNL_CSN_GPIO); + + spi_disable_interrupt( KSZ8851SNL_SPI, ~0ul ); + + pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN); + for( ;; ) + { + ulStatus = spi_read_status( KSZ8851SNL_SPI ); + if( ( ulStatus & ( SPI_SR_OVRES | SPI_SR_ENDRX ) ) != 0 ) + { + break; + } + } + gpio_set_pin_high( KSZ8851SNL_CSN_GPIO ); + if( ( ulStatus & SPI_SR_OVRES ) == 0 ) + { + break; + } + pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); + lUDPLoggingPrintf( "ksz8851_reg_write: SPI_SR_OVRES\n" ); + } +} + +static void spi_clear_ovres( void ) +{ +volatile uint32_t rc; + rc = KSZ8851SNL_SPI->SPI_RDR; + + spi_read_status( KSZ8851SNL_SPI ); +} + +/** + * \brief Read internal fifo buffer. + * + * \param buf the buffer to store the data from the fifo buffer. + * \param len the amount of data to read. + */ +void ksz8851_fifo_read(uint8_t *buf, uint32_t len) +{ + pdc_packet_t g_pdc_spi_tx_packet; + pdc_packet_t g_pdc_spi_rx_packet; + pdc_packet_t g_pdc_spi_tx_npacket; + pdc_packet_t g_pdc_spi_rx_npacket; + + memset( cmdBuf.uc, '\0', sizeof cmdBuf ); + cmdBuf.uc[0] = FIFO_READ; + spi_clear_ovres(); + + /* Prepare PDC transfer. */ + g_pdc_spi_tx_packet.ul_addr = (uint32_t) cmdBuf.uc; + g_pdc_spi_tx_packet.ul_size = 9; + g_pdc_spi_rx_packet.ul_addr = (uint32_t) respBuf.uc; + g_pdc_spi_rx_packet.ul_size = 9; + + g_pdc_spi_tx_npacket.ul_addr = (uint32_t) buf; + g_pdc_spi_tx_npacket.ul_size = len; + g_pdc_spi_rx_npacket.ul_addr = (uint32_t) buf; + g_pdc_spi_rx_npacket.ul_size = len; + pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); + pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, &g_pdc_spi_tx_npacket); + pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, &g_pdc_spi_rx_npacket); + +spi_enable_interrupt(KSZ8851SNL_SPI, SPI_IER_RXBUFF | SPI_IER_OVRES); + + pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN); +} + +/** + * \brief Write internal fifo buffer. + * + * \param buf the buffer to send to the fifo buffer. + * \param ulActualLength the total amount of data to write. + * \param ulFIFOLength the size of the first pbuf to write from the pbuf chain. + */ +void ksz8851_fifo_write(uint8_t *buf, uint32_t ulActualLength, uint32_t ulFIFOLength) +{ + static uint8_t frameID = 0; + + pdc_packet_t g_pdc_spi_tx_packet; + pdc_packet_t g_pdc_spi_rx_packet; + pdc_packet_t g_pdc_spi_tx_npacket; + pdc_packet_t g_pdc_spi_rx_npacket; + + /* Prepare control word and byte count. */ + cmdBuf.uc[0] = FIFO_WRITE; + cmdBuf.uc[1] = frameID++ & 0x3f; + cmdBuf.uc[2] = 0; + cmdBuf.uc[3] = ulActualLength & 0xff; + cmdBuf.uc[4] = ulActualLength >> 8; + + spi_clear_ovres(); + + /* Prepare PDC transfer. */ + g_pdc_spi_tx_packet.ul_addr = (uint32_t) cmdBuf.uc; + g_pdc_spi_tx_packet.ul_size = 5; + + g_pdc_spi_rx_packet.ul_addr = (uint32_t) respBuf.uc; + g_pdc_spi_rx_packet.ul_size = 5; + + g_pdc_spi_tx_npacket.ul_addr = (uint32_t) buf; + g_pdc_spi_tx_npacket.ul_size = ulFIFOLength; + + g_pdc_spi_rx_npacket.ul_addr = (uint32_t) tmpbuf; + g_pdc_spi_rx_npacket.ul_size = ulFIFOLength; + + pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); + pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, &g_pdc_spi_tx_npacket); + #if( TX_USES_RECV == 1 ) + pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, &g_pdc_spi_rx_npacket); + spi_enable_interrupt(KSZ8851SNL_SPI, SPI_IER_ENDRX | SPI_IER_OVRES); + pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN); + #else + spi_enable_interrupt(KSZ8851SNL_SPI, SPI_SR_TXBUFE | SPI_IER_OVRES); + pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_TXTEN); + #endif +} + +/** + * \brief Write dummy data to the internal fifo buffer. + * + * \param len the amount of dummy data to write. + */ +void ksz8851_fifo_dummy(uint32_t len) +{ + pdc_packet_t g_pdc_spi_tx_packet; + pdc_packet_t g_pdc_spi_rx_packet; + + /* Prepare PDC transfer. */ + g_pdc_spi_tx_packet.ul_addr = (uint32_t) tmpbuf; + g_pdc_spi_tx_packet.ul_size = len; + g_pdc_spi_rx_packet.ul_addr = (uint32_t) tmpbuf; + g_pdc_spi_rx_packet.ul_size = len; + pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS); + pdc_tx_init(g_p_spi_pdc, &g_pdc_spi_tx_packet, NULL); + pdc_rx_init(g_p_spi_pdc, &g_pdc_spi_rx_packet, NULL); + pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN); + + while (!(spi_read_status(KSZ8851SNL_SPI) & SPI_SR_ENDRX)) + ; +} + +void ksz8851snl_set_registers(void) +{ + /* Init step2-4: write QMU MAC address (low, middle then high). */ + ksz8851_reg_write(REG_MAC_ADDR_0, (ETHERNET_CONF_ETHADDR4 << 8) | ETHERNET_CONF_ETHADDR5); + ksz8851_reg_write(REG_MAC_ADDR_2, (ETHERNET_CONF_ETHADDR2 << 8) | ETHERNET_CONF_ETHADDR3); + ksz8851_reg_write(REG_MAC_ADDR_4, (ETHERNET_CONF_ETHADDR0 << 8) | ETHERNET_CONF_ETHADDR1); + + /* Init step5: enable QMU Transmit Frame Data Pointer Auto Increment. */ + ksz8851_reg_write(REG_TX_ADDR_PTR, ADDR_PTR_AUTO_INC); + + /* Init step6: configure QMU transmit control register. */ + ksz8851_reg_write(REG_TX_CTRL, + TX_CTRL_ICMP_CHECKSUM | + TX_CTRL_UDP_CHECKSUM | + TX_CTRL_TCP_CHECKSUM | + TX_CTRL_IP_CHECKSUM | + TX_CTRL_FLOW_ENABLE | + TX_CTRL_PAD_ENABLE | + TX_CTRL_CRC_ENABLE + ); + + /* Init step7: enable QMU Receive Frame Data Pointer Auto Increment. */ + ksz8851_reg_write(REG_RX_ADDR_PTR, ADDR_PTR_AUTO_INC); + + /* Init step8: configure QMU Receive Frame Threshold for one frame. */ + ksz8851_reg_write(REG_RX_FRAME_CNT_THRES, 1); + + /* Init step9: configure QMU receive control register1. */ + ksz8851_reg_write(REG_RX_CTRL1, + RX_CTRL_UDP_CHECKSUM | + RX_CTRL_TCP_CHECKSUM | + RX_CTRL_IP_CHECKSUM | + RX_CTRL_MAC_FILTER | + RX_CTRL_FLOW_ENABLE | + RX_CTRL_BROADCAST | + RX_CTRL_ALL_MULTICAST| + RX_CTRL_UNICAST); +// ksz8851_reg_write(REG_RX_CTRL1, +// RX_CTRL_UDP_CHECKSUM | +// RX_CTRL_TCP_CHECKSUM | +// RX_CTRL_IP_CHECKSUM | +// RX_CTRL_FLOW_ENABLE | +// RX_CTRL_PROMISCUOUS); + + ksz8851_reg_write(REG_RX_CTRL2, + RX_CTRL_IPV6_UDP_NOCHECKSUM | + RX_CTRL_UDP_LITE_CHECKSUM | + RX_CTRL_ICMP_CHECKSUM | + RX_CTRL_BURST_LEN_FRAME); + + +//#define RXQ_TWOBYTE_OFFSET (0x0200) /* Enable adding 2-byte before frame header for IP aligned with DWORD */ +#warning Remember to try the above option to get a 2-byte offset + + /* Init step11: configure QMU receive queue: trigger INT and auto-dequeue frame. */ + ksz8851_reg_write( REG_RXQ_CMD, RXQ_CMD_CNTL | RXQ_TWOBYTE_OFFSET ); + + /* Init step12: adjust SPI data output delay. */ + ksz8851_reg_write(REG_BUS_CLOCK_CTRL, BUS_CLOCK_166 | BUS_CLOCK_DIVIDEDBY_1); + + /* Init step13: restart auto-negotiation. */ + ksz8851_reg_setbits(REG_PORT_CTRL, PORT_AUTO_NEG_RESTART); + + /* Init step13.1: force link in half duplex if auto-negotiation failed. */ + if ((ksz8851_reg_read(REG_PORT_CTRL) & PORT_AUTO_NEG_RESTART) != PORT_AUTO_NEG_RESTART) + { + ksz8851_reg_clrbits(REG_PORT_CTRL, PORT_FORCE_FULL_DUPLEX); + } + + /* Init step14: clear interrupt status. */ + ksz8851_reg_write(REG_INT_STATUS, 0xFFFF); + + /* Init step15: set interrupt mask. */ + ksz8851_reg_write(REG_INT_MASK, INT_RX); + + /* Init step16: enable QMU Transmit. */ + ksz8851_reg_setbits(REG_TX_CTRL, TX_CTRL_ENABLE); + + /* Init step17: enable QMU Receive. */ + ksz8851_reg_setbits(REG_RX_CTRL1, RX_CTRL_ENABLE); +} +/** + * \brief KSZ8851SNL initialization function. + * + * \return 0 on success, 1 on communication error. + */ +uint32_t ksz8851snl_init(void) +{ +uint32_t count = 10; +uint16_t dev_id = 0; +uint8_t id_ok = 0; + + /* Configure the SPI peripheral. */ + spi_enable_clock(KSZ8851SNL_SPI); + spi_disable(KSZ8851SNL_SPI); + spi_reset(KSZ8851SNL_SPI); + spi_set_master_mode(KSZ8851SNL_SPI); + spi_disable_mode_fault_detect(KSZ8851SNL_SPI); + spi_set_peripheral_chip_select_value(KSZ8851SNL_SPI, ~(uint32_t)(1UL << KSZ8851SNL_CS_PIN)); +spi_set_fixed_peripheral_select(KSZ8851SNL_SPI); +//spi_disable_peripheral_select_decode(KSZ8851SNL_SPI); + + spi_set_clock_polarity(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, SPI_CLK_POLARITY); + spi_set_clock_phase(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, SPI_CLK_PHASE); + spi_set_bits_per_transfer(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, + SPI_CSR_BITS_8_BIT); + spi_set_baudrate_div(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, (sysclk_get_cpu_hz() / KSZ8851SNL_CLOCK_SPEED)); +// spi_set_transfer_delay(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, CONFIG_SPI_MASTER_DELAY_BS, +// CONFIG_SPI_MASTER_DELAY_BCT); + + + spi_set_transfer_delay(KSZ8851SNL_SPI, KSZ8851SNL_CS_PIN, 0, 0); + + spi_enable(KSZ8851SNL_SPI); + + /* Get pointer to UART PDC register base. */ + g_p_spi_pdc = spi_get_pdc_base(KSZ8851SNL_SPI); + pdc_enable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTEN | PERIPH_PTCR_TXTEN); + + /* Control RSTN and CSN pin from the driver. */ + gpio_configure_pin(KSZ8851SNL_CSN_GPIO, KSZ8851SNL_CSN_FLAGS); + gpio_set_pin_high(KSZ8851SNL_CSN_GPIO); + gpio_configure_pin(KSZ8851SNL_RSTN_GPIO, KSZ8851SNL_RSTN_FLAGS); + + /* Reset the Micrel in a proper state. */ + while( count-- ) + { + /* Perform hardware reset with respect to the reset timing from the datasheet. */ + gpio_set_pin_low(KSZ8851SNL_RSTN_GPIO); + vTaskDelay(2); + gpio_set_pin_high(KSZ8851SNL_RSTN_GPIO); + vTaskDelay(2); + + /* Init step1: read chip ID. */ + dev_id = ksz8851_reg_read(REG_CHIP_ID); + if( ( dev_id & 0xFFF0 ) == CHIP_ID_8851_16 ) + { + id_ok = 1; + break; + } + } + if( id_ok != 0 ) + { + ksz8851snl_set_registers(); + } + + return id_ok ? 1 : -1; +} + +uint32_t ksz8851snl_reinit(void) +{ +uint32_t count = 10; +uint16_t dev_id = 0; +uint8_t id_ok = 0; + /* Reset the Micrel in a proper state. */ + while( count-- ) + { + /* Perform hardware reset with respect to the reset timing from the datasheet. */ + gpio_set_pin_low(KSZ8851SNL_RSTN_GPIO); + vTaskDelay(2); + gpio_set_pin_high(KSZ8851SNL_RSTN_GPIO); + vTaskDelay(2); + + /* Init step1: read chip ID. */ + dev_id = ksz8851_reg_read(REG_CHIP_ID); + if( ( dev_id & 0xFFF0 ) == CHIP_ID_8851_16 ) + { + id_ok = 1; + break; + } + } + if( id_ok != 0 ) + { + ksz8851snl_set_registers(); + } + + return id_ok ? 1 : -1; +} + +uint32_t ksz8851snl_reset_rx( void ) +{ +uint16_t usValue; + + usValue = ksz8851_reg_read(REG_RX_CTRL1); + + usValue &= ~( ( uint16_t ) RX_CTRL_ENABLE | RX_CTRL_FLUSH_QUEUE ); + + ksz8851_reg_write( REG_RX_CTRL1, usValue ); vTaskDelay( 2 ); + ksz8851_reg_write( REG_RX_CTRL1, usValue | RX_CTRL_FLUSH_QUEUE ); vTaskDelay( 1 ); + ksz8851_reg_write( REG_RX_CTRL1, usValue ); vTaskDelay( 1 ); + ksz8851_reg_write( REG_RX_CTRL1, usValue | RX_CTRL_ENABLE ); vTaskDelay( 1 ); + + return ( uint32_t )usValue; +} + +uint32_t ksz8851snl_reset_tx( void ) +{ +uint16_t usValue; + + usValue = ksz8851_reg_read( REG_TX_CTRL ); + + usValue &= ~( ( uint16_t ) TX_CTRL_ENABLE | TX_CTRL_FLUSH_QUEUE ); + + ksz8851_reg_write( REG_TX_CTRL, usValue ); vTaskDelay( 2 ); + ksz8851_reg_write( REG_TX_CTRL, usValue | TX_CTRL_FLUSH_QUEUE ); vTaskDelay( 1 ); + ksz8851_reg_write( REG_TX_CTRL, usValue ); vTaskDelay( 1 ); + ksz8851_reg_write( REG_TX_CTRL, usValue | TX_CTRL_ENABLE ); vTaskDelay( 1 ); + + return ( uint32_t )usValue; +} diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/ksz8851snl.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/ksz8851snl.h new file mode 100644 index 000000000..7952dc241 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/ksz8851snl.h @@ -0,0 +1,67 @@ +/** + * + * \file + * + * \brief KS8851SNL driver for SAM. + * + * Copyright (c) 2013-2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Atmel Support + */ + +#ifndef KSZ8851SNL_H_INCLUDED +#define KSZ8851SNL_H_INCLUDED + +#include "gpio.h" + +void configure_intn(void (*p_handler) (uint32_t, uint32_t)); +void ksz8851_reg_setbits(uint16_t reg, uint16_t bits_to_set); +void ksz8851_reg_clrbits(uint16_t reg, uint16_t bits_to_clr); +void ksz8851_fifo_read(uint8_t *buf, uint32_t len); +void ksz8851_fifo_write(uint8_t *buf, uint32_t ulActualLength, uint32_t ulFIFOLength); +void ksz8851_fifo_dummy(uint32_t len); +void ksz8851_reg_write(uint16_t reg, uint16_t wrdata); +uint16_t ksz8851_reg_read(uint16_t reg); +uint32_t ksz8851snl_init(void); +uint32_t ksz8851snl_reinit(void); + +uint32_t ksz8851snl_reset_rx( void ); +uint32_t ksz8851snl_reset_tx( void ); + +#endif /* KSZ8851SNL_H_INCLUDED */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/ksz8851snl_reg.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/ksz8851snl_reg.h new file mode 100644 index 000000000..3102fcc42 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/ksz8851snl_reg.h @@ -0,0 +1,473 @@ +/** + * + * \file + * + * \brief KS8851SNL registers definitions. + * + * Copyright (c) 2013-2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Atmel Support + */ + +#ifndef KSZ8851SNL_REG_H_INCLUDED +#define KSZ8851SNL_REG_H_INCLUDED + +#define REG_ADDR_MASK (0x3F0) /* Register address mask */ +#define OPCODE_MASK (3 << 14) +#define CMD_READ (0 << 14) +#define CMD_WRITE (1 << 14) +#define FIFO_READ (0x80) +#define FIFO_WRITE (0xC0) + +/* + * MAC Registers + * (Offset 0x00 - 0x25) + */ +#define REG_BUS_ERROR_STATUS (0x06) /* BESR */ +#define BUS_ERROR_IBEC (0x8000) +#define BUS_ERROR_IBECV_MASK (0x7800) /* Default IPSec clock at 166Mhz */ + +#define REG_CHIP_CFG_STATUS (0x08) /* CCFG */ +#define LITTLE_ENDIAN_BUS_MODE (0x0400) /* Bus in little endian mode */ +#define EEPROM_PRESENCE (0x0200) /* External EEPROM is used */ +#define SPI_BUS_MODE (0x0100) /* In SPI bus mode */ +#define DATA_BUS_8BIT (0x0080) /* In 8-bit bus mode operation */ +#define DATA_BUS_16BIT (0x0040) /* In 16-bit bus mode operation */ +#define DATA_BUS_32BIT (0x0020) /* In 32-bit bus mode operation */ +#define MULTIPLEX_MODE (0x0010) /* Data and address bus are shared */ +#define CHIP_PACKAGE_128PIN (0x0008) /* 128-pin package */ +#define CHIP_PACKAGE_80PIN (0x0004) /* 80-pin package */ +#define CHIP_PACKAGE_48PIN (0x0002) /* 48-pin package */ +#define CHIP_PACKAGE_32PIN (0x0001) /* 32-pin package for SPI host interface only */ + +#define REG_MAC_ADDR_0 (0x10) /* MARL */ +#define REG_MAC_ADDR_1 (0x11) /* MARL */ +#define REG_MAC_ADDR_2 (0x12) /* MARM */ +#define REG_MAC_ADDR_3 (0x13) /* MARM */ +#define REG_MAC_ADDR_4 (0x14) /* MARH */ +#define REG_MAC_ADDR_5 (0x15) /* MARH */ + +#define REG_BUS_CLOCK_CTRL (0x20) /* OBCR */ +#define BUS_CLOCK_166 (0x0004) /* 166 MHz on-chip bus clock (defaul is 125MHz) */ +#define BUS_CLOCK_DIVIDEDBY_5 (0x0003) /* Bus clock devided by 5 */ +#define BUS_CLOCK_DIVIDEDBY_3 (0x0002) /* Bus clock devided by 3 */ +#define BUS_CLOCK_DIVIDEDBY_2 (0x0001) /* Bus clock devided by 2 */ +#define BUS_CLOCK_DIVIDEDBY_1 (0x0000) /* Bus clock devided by 1 */ +#define BUS_CLOCK_DIVIDED_MASK (0x0003) /* Bus clock devider mask */ + +#define BUS_SPEED_166_MHZ (0x0004) /* Set bus speed to 166 MHz */ +#define BUS_SPEED_125_MHZ (0x0000) /* Set bus speed to 125 MHz */ +#define BUS_SPEED_83_MHZ (0x0005) /* Set bus speed to 83 MHz (166/2)*/ +#define BUS_SPEED_62_5_MHZ (0x0001) /* Set bus speed to 62.5 MHz (125/2) */ +#define BUS_SPEED_53_3_MHZ (0x0006) /* Set bus speed to 53.3 MHz (166/3) */ +#define BUS_SPEED_41_7_MHZ (0x0002) /* Set bus speed to 41.67 MHz (125/3) */ +#define BUS_SPEED_33_2_MHZ (0x0007) /* Set bus speed to 33.2 MHz (166/5) */ +#define BUS_SPEED_25_MHZ (0x0003) /* Set bus speed to 25 MHz (125/5) */ + +#define REG_EEPROM_CTRL (0x22) /* EEPCR */ +#define EEPROM_ACCESS_ENABLE (0x0010) /* Enable software to access EEPROM through bit 3 to bit 0 */ +#define EEPROM_DATA_IN (0x0008) /* Data receive from EEPROM (EEDI pin) */ +#define EEPROM_DATA_OUT (0x0004) /* Data transmit to EEPROM (EEDO pin) */ +#define EEPROM_SERIAL_CLOCK (0x0002) /* Serial clock (EESK pin) */ +#define EEPROM_CHIP_SELECT (0x0001) /* EEPROM chip select (EECS pin) */ + +#define REG_MEM_BIST_INFO (0x24) /* MBIR */ +#define TX_MEM_TEST_FINISHED (0x1000) /* TX memeory BIST test finish */ +#define TX_MEM_TEST_FAILED (0x0800) /* TX memory BIST test fail */ +#define TX_MEM_TEST_FAILED_COUNT (0x0700) /* TX memory BIST test fail count */ +#define RX_MEM_TEST_FINISHED (0x0010) /* RX memory BIST test finish */ +#define RX_MEM_TEST_FAILED (0x0008) /* RX memory BIST test fail */ +#define RX_MEM_TEST_FAILED_COUNT (0x0003) /* RX memory BIST test fail count */ + +#define REG_RESET_CTRL (0x26) /* GRR */ +#define QMU_SOFTWARE_RESET (0x0002) /* QMU soft reset (clear TxQ, RxQ) */ +#define GLOBAL_SOFTWARE_RESET (0x0001) /* Global soft reset (PHY, MAC, QMU) */ + +/* + * Wake On Lan Control Registers + * (Offset 0x2A - 0x6B) + */ +#define REG_WOL_CTRL (0x2A) /* WFCR */ +#define WOL_MAGIC_ENABLE (0x0080) /* Enable the magic packet pattern detection */ +#define WOL_FRAME3_ENABLE (0x0008) /* Enable the wake up frame 3 pattern detection */ +#define WOL_FRAME2_ENABLE (0x0004) /* Enable the wake up frame 2 pattern detection */ +#define WOL_FRAME1_ENABLE (0x0002) /* Enable the wake up frame 1 pattern detection */ +#define WOL_FRAME0_ENABLE (0x0001) /* Enable the wake up frame 0 pattern detection */ + +#define REG_WOL_FRAME0_CRC0 (0x30) /* WF0CRC0 */ +#define REG_WOL_FRAME0_CRC1 (0x32) /* WF0CRC1 */ +#define REG_WOL_FRAME0_BYTE_MASK0 (0x34) /* WF0BM0 */ +#define REG_WOL_FRAME0_BYTE_MASK1 (0x36) /* WF0BM1 */ +#define REG_WOL_FRAME0_BYTE_MASK2 (0x38) /* WF0BM2 */ +#define REG_WOL_FRAME0_BYTE_MASK3 (0x3A) /* WF0BM3 */ + +#define REG_WOL_FRAME1_CRC0 (0x40) /* WF1CRC0 */ +#define REG_WOL_FRAME1_CRC1 (0x42) /* WF1CRC1 */ +#define REG_WOL_FRAME1_BYTE_MASK0 (0x44) /* WF1BM0 */ +#define REG_WOL_FRAME1_BYTE_MASK1 (0x46) /* WF1BM1 */ +#define REG_WOL_FRAME1_BYTE_MASK2 (0x48) /* WF1BM2 */ +#define REG_WOL_FRAME1_BYTE_MASK3 (0x4A) /* WF1BM3 */ + +#define REG_WOL_FRAME2_CRC0 (0x50) /* WF2CRC0 */ +#define REG_WOL_FRAME2_CRC1 (0x52) /* WF2CRC1 */ +#define REG_WOL_FRAME2_BYTE_MASK0 (0x54) /* WF2BM0 */ +#define REG_WOL_FRAME2_BYTE_MASK1 (0x56) /* WF2BM1 */ +#define REG_WOL_FRAME2_BYTE_MASK2 (0x58) /* WF2BM2 */ +#define REG_WOL_FRAME2_BYTE_MASK3 (0x5A) /* WF2BM3 */ + +#define REG_WOL_FRAME3_CRC0 (0x60) /* WF3CRC0 */ +#define REG_WOL_FRAME3_CRC1 (0x62) /* WF3CRC1 */ +#define REG_WOL_FRAME3_BYTE_MASK0 (0x64) /* WF3BM0 */ +#define REG_WOL_FRAME3_BYTE_MASK1 (0x66) /* WF3BM1 */ +#define REG_WOL_FRAME3_BYTE_MASK2 (0x68) /* WF3BM2 */ +#define REG_WOL_FRAME3_BYTE_MASK3 (0x6A) /* WF3BM3 */ + +/* + * Transmit/Receive Control Registers + * (Offset 0x70 - 0x9F) + */ + +/* Transmit Frame Header */ +#define REG_QDR_DUMMY (0x00) /* Dummy address to access QMU RxQ, TxQ */ +#define TX_CTRL_INTERRUPT_ON (0x8000) /* Transmit Interrupt on Completion */ + +#define REG_TX_CTRL (0x70) /* TXCR */ +#define TX_CTRL_ICMP_CHECKSUM (0x0100) /* Enable ICMP frame checksum generation */ +#define TX_CTRL_UDP_CHECKSUM (0x0080) /* Enable UDP frame checksum generation */ +#define TX_CTRL_TCP_CHECKSUM (0x0040) /* Enable TCP frame checksum generation */ +#define TX_CTRL_IP_CHECKSUM (0x0020) /* Enable IP frame checksum generation */ +#define TX_CTRL_FLUSH_QUEUE (0x0010) /* Clear transmit queue, reset tx frame pointer */ +#define TX_CTRL_FLOW_ENABLE (0x0008) /* Enable transmit flow control */ +#define TX_CTRL_PAD_ENABLE (0x0004) /* Eanble adding a padding to a packet shorter than 64 bytes */ +#define TX_CTRL_CRC_ENABLE (0x0002) /* Enable adding a CRC to the end of transmit frame */ +#define TX_CTRL_ENABLE (0x0001) /* Enable tranmsit */ + +#define REG_TX_STATUS (0x72) /* TXSR */ +#define TX_STAT_LATE_COL (0x2000) /* Tranmsit late collision occurs */ +#define TX_STAT_MAX_COL (0x1000) /* Tranmsit maximum collision is reached */ +#define TX_FRAME_ID_MASK (0x003F) /* Transmit frame ID mask */ +#define TX_STAT_ERRORS ( TX_STAT_MAX_COL | TX_STAT_LATE_COL ) + +#define REG_RX_CTRL1 (0x74) /* RXCR1 */ +#define RX_CTRL_FLUSH_QUEUE (0x8000) /* Clear receive queue, reset rx frame pointer */ +#define RX_CTRL_UDP_CHECKSUM (0x4000) /* Enable UDP frame checksum verification */ +#define RX_CTRL_TCP_CHECKSUM (0x2000) /* Enable TCP frame checksum verification */ +#define RX_CTRL_IP_CHECKSUM (0x1000) /* Enable IP frame checksum verification */ +#define RX_CTRL_MAC_FILTER (0x0800) /* Receive with address that pass MAC address filtering */ +#define RX_CTRL_FLOW_ENABLE (0x0400) /* Enable receive flow control */ +#define RX_CTRL_BAD_PACKET (0x0200) /* Eanble receive CRC error frames */ +#define RX_CTRL_MULTICAST (0x0100) /* Receive multicast frames that pass the CRC hash filtering */ +#define RX_CTRL_BROADCAST (0x0080) /* Receive all the broadcast frames */ +#define RX_CTRL_ALL_MULTICAST (0x0040) /* Receive all the multicast frames (including broadcast frames) */ +#define RX_CTRL_UNICAST (0x0020) /* Receive unicast frames that match the device MAC address */ +#define RX_CTRL_PROMISCUOUS (0x0010) /* Receive all incoming frames, regardless of frame's DA */ +#define RX_CTRL_STRIP_CRC (0x0008) /* Enable strip CRC on the received frames */ +#define RX_CTRL_INVERSE_FILTER (0x0002) /* Receive with address check in inverse filtering mode */ +#define RX_CTRL_ENABLE (0x0001) /* Enable receive */ + +/* Address filtering scheme mask */ +#define RX_CTRL_FILTER_MASK ( RX_CTRL_INVERSE_FILTER | RX_CTRL_PROMISCUOUS | RX_CTRL_MULTICAST | RX_CTRL_MAC_FILTER ) + +#define REG_RX_CTRL2 (0x76) /* RXCR2 */ +#define RX_CTRL_IPV6_UDP_NOCHECKSUM (0x0010) /* No checksum generation and verification if IPv6 UDP is fragment */ +#define RX_CTRL_IPV6_UDP_CHECKSUM (0x0008) /* Receive pass IPv6 UDP frame with UDP checksum is zero */ +#define RX_CTRL_UDP_LITE_CHECKSUM (0x0004) /* Enable UDP Lite frame checksum generation and verification */ +#define RX_CTRL_ICMP_CHECKSUM (0x0002) /* Enable ICMP frame checksum verification */ +#define RX_CTRL_BLOCK_MAC (0x0001) /* Receive drop frame if the SA is same as device MAC address */ +#define RX_CTRL_BURST_LEN_MASK (0x00e0) /* SRDBL SPI Receive Data Burst Length */ +#define RX_CTRL_BURST_LEN_4 (0x0000) +#define RX_CTRL_BURST_LEN_8 (0x0020) +#define RX_CTRL_BURST_LEN_16 (0x0040) +#define RX_CTRL_BURST_LEN_32 (0x0060) +#define RX_CTRL_BURST_LEN_FRAME (0x0080) + +#define REG_TX_MEM_INFO (0x78) /* TXMIR */ +#define TX_MEM_AVAILABLE_MASK (0x1FFF) /* The amount of memory available in TXQ */ + +#define REG_RX_FHR_STATUS (0x7C) /* RXFHSR */ +#define RX_VALID (0x8000) /* Frame in the receive packet memory is valid */ +#define RX_ICMP_ERROR (0x2000) /* ICMP checksum field doesn't match */ +#define RX_IP_ERROR (0x1000) /* IP checksum field doesn't match */ +#define RX_TCP_ERROR (0x0800) /* TCP checksum field doesn't match */ +#define RX_UDP_ERROR (0x0400) /* UDP checksum field doesn't match */ +#define RX_BROADCAST (0x0080) /* Received frame is a broadcast frame */ +#define RX_MULTICAST (0x0040) /* Received frame is a multicast frame */ +#define RX_UNICAST (0x0020) /* Received frame is a unicast frame */ +#define RX_PHY_ERROR (0x0010) /* Received frame has runt error */ +#define RX_FRAME_ETHER (0x0008) /* Received frame is an Ethernet-type frame */ +#define RX_TOO_LONG (0x0004) /* Received frame length exceeds max size 0f 2048 bytes */ +#define RX_RUNT_ERROR (0x0002) /* Received frame was demaged by a collision */ +#define RX_BAD_CRC (0x0001) /* Received frame has a CRC error */ +#define RX_ERRORS ( RX_BAD_CRC | RX_TOO_LONG | RX_RUNT_ERROR | RX_PHY_ERROR | \ + RX_ICMP_ERROR | RX_IP_ERROR | RX_TCP_ERROR | RX_UDP_ERROR ) + +#define REG_RX_FHR_BYTE_CNT (0x7E) /* RXFHBCR */ +#define RX_BYTE_CNT_MASK (0x0FFF) /* Received frame byte size mask */ + +#define REG_TXQ_CMD (0x80) /* TXQCR */ +#define TXQ_AUTO_ENQUEUE (0x0004) /* Enable enqueue tx frames from tx buffer automatically */ +#define TXQ_MEM_AVAILABLE_INT (0x0002) /* Enable generate interrupt when tx memory is available */ +#define TXQ_ENQUEUE (0x0001) /* Enable enqueue tx frames one frame at a time */ + +#define REG_RXQ_CMD (0x82) /* RXQCR */ +#define RXQ_STAT_TIME_INT (0x1000) /* RX interrupt is occured by timer duration */ +#define RXQ_STAT_BYTE_CNT_INT (0x0800) /* RX interrupt is occured by byte count threshold */ +#define RXQ_STAT_FRAME_CNT_INT (0x0400) /* RX interrupt is occured by frame count threshold */ +#define RXQ_TWOBYTE_OFFSET (0x0200) /* Enable adding 2-byte before frame header for IP aligned with DWORD */ +#define RXQ_TIME_INT (0x0080) /* Enable RX interrupt by timer duration */ +#define RXQ_BYTE_CNT_INT (0x0040) /* Enable RX interrupt by byte count threshold */ +#define RXQ_FRAME_CNT_INT (0x0020) /* Enable RX interrupt by frame count threshold */ +#define RXQ_AUTO_DEQUEUE (0x0010) /* Enable release rx frames from rx buffer automatically */ +#define RXQ_START (0x0008) /* Start QMU transfer operation */ +#define RXQ_CMD_FREE_PACKET (0x0001) /* Manual dequeue (release the current frame from RxQ) */ + +#define RXQ_CMD_CNTL (RXQ_FRAME_CNT_INT|RXQ_AUTO_DEQUEUE) + +#define REG_TX_ADDR_PTR (0x84) /* TXFDPR */ +#define REG_RX_ADDR_PTR (0x86) /* RXFDPR */ +#define ADDR_PTR_AUTO_INC (0x4000) /* Enable Frame data pointer increments automatically */ +#define ADDR_PTR_MASK (0x03ff) /* Address pointer mask */ + +#define REG_RX_TIME_THRES (0x8C) /* RXDTTR */ +#define RX_TIME_THRESHOLD_MASK (0xFFFF) /* Set receive timer duration threshold */ + +#define REG_RX_BYTE_CNT_THRES (0x8E) /* RXDBCTR */ +#define RX_BYTE_THRESHOLD_MASK (0xFFFF) /* Set receive byte count threshold */ + +#define REG_INT_MASK (0x90) /* IER */ +#define INT_PHY (0x8000) /* Enable link change interrupt */ +#define INT_TX (0x4000) /* Enable transmit done interrupt */ +#define INT_RX (0x2000) /* Enable receive interrupt */ +#define INT_RX_OVERRUN (0x0800) /* Enable receive overrun interrupt */ +#define INT_TX_STOPPED (0x0200) /* Enable transmit process stopped interrupt */ +#define INT_RX_STOPPED (0x0100) /* Enable receive process stopped interrupt */ +#define INT_TX_SPACE (0x0040) /* Enable transmit space available interrupt */ +#define INT_RX_WOL_FRAME (0x0020) /* Enable WOL on receive wake-up frame detect interrupt */ +#define INT_RX_WOL_MAGIC (0x0010) /* Enable WOL on receive magic packet detect interrupt */ +#define INT_RX_WOL_LINKUP (0x0008) /* Enable WOL on link up detect interrupt */ +#define INT_RX_WOL_ENERGY (0x0004) /* Enable WOL on energy detect interrupt */ +#define INT_RX_SPI_ERROR (0x0002) /* Enable receive SPI bus error interrupt */ +#define INT_RX_WOL_DELAY_ENERGY (0x0001) /* Enable WOL on delay energy detect interrupt */ +#define INT_MASK ( INT_RX | INT_TX | INT_PHY ) + +#define REG_INT_STATUS (0x92) /* ISR */ + +#define REG_RX_FRAME_CNT_THRES (0x9C) /* RXFCTFC */ +#define RX_FRAME_CNT_MASK (0xFF00) /* Received frame count mask */ +#define RX_FRAME_THRESHOLD_MASK (0x00FF) /* Set receive frame count threshold mask */ + +#define REG_TX_TOTAL_FRAME_SIZE (0x9E) /* TXNTFSR */ +#define TX_TOTAL_FRAME_SIZE_MASK (0xFFFF) /* Set next total tx frame size mask */ + +/* + * MAC Address Hash Table Control Registers + * (Offset 0xA0 - 0xA7) + */ +#define REG_MAC_HASH_0 (0xA0) /* MAHTR0 */ +#define REG_MAC_HASH_1 (0xA1) + +#define REG_MAC_HASH_2 (0xA2) /* MAHTR1 */ +#define REG_MAC_HASH_3 (0xA3) + +#define REG_MAC_HASH_4 (0xA4) /* MAHTR2 */ +#define REG_MAC_HASH_5 (0xA5) + +#define REG_MAC_HASH_6 (0xA6) /* MAHTR3 */ +#define REG_MAC_HASH_7 (0xA7) + +/* + * QMU Receive Queue Watermark Control Registers + * (Offset 0xB0 - 0xB5) + */ +#define REG_RX_LOW_WATERMARK (0xB0) /* FCLWR */ +#define RX_LOW_WATERMARK_MASK (0x0FFF) /* Set QMU RxQ low watermark mask */ + +#define REG_RX_HIGH_WATERMARK (0xB2) /* FCHWR */ +#define RX_HIGH_WATERMARK_MASK (0x0FFF) /* Set QMU RxQ high watermark mask */ + +#define REG_RX_OVERRUN_WATERMARK (0xB4) /* FCOWR */ +#define RX_OVERRUN_WATERMARK_MASK (0x0FFF) /* Set QMU RxQ overrun watermark mask */ + +/* + * Global Control Registers + * (Offset 0xC0 - 0xD3) + */ +#define REG_CHIP_ID (0xC0) /* CIDER */ +#define CHIP_ID_MASK (0xFFF0) /* Family ID and chip ID mask */ +#define REVISION_MASK (0x000E) /* Chip revision mask */ +#define CHIP_ID_SHIFT (4) +#define REVISION_SHIFT (1) +#define CHIP_ID_8851_16 (0x8870) /* KS8851-16/32MQL chip ID */ + +#define REG_LED_CTRL (0xC6) /* CGCR */ +#define LED_CTRL_SEL1 (0x8000) /* Select LED3/LED2/LED1/LED0 indication */ +#define LED_CTRL_SEL0 (0x0200) /* Select LED3/LED2/LED1/LED0 indication */ + +#define REG_IND_IACR (0xC8) /* IACR */ +#define TABLE_READ (0x1000) /* Indirect read */ +#define TABLE_MIB (0x0C00) /* Select MIB counter table */ +#define TABLE_ENTRY_MASK (0x001F) /* Set table entry to access */ + +#define REG_IND_DATA_LOW (0xD0) /* IADLR */ +#define REG_IND_DATA_HIGH (0xD2) /* IADHR */ + +/* + * Power Management Control Registers + * (Offset 0xD4 - 0xD7) + */ +#define REG_POWER_CNTL (0xD4) /* PMECR */ +#define PME_DELAY_ENABLE (0x4000) /* Enable the PME output pin assertion delay */ +#define PME_ACTIVE_HIGHT (0x1000) /* PME output pin is active high */ +#define PME_FROM_WKFRAME (0x0800) /* PME asserted when wake-up frame is detected */ +#define PME_FROM_MAGIC (0x0400) /* PME asserted when magic packet is detected */ +#define PME_FROM_LINKUP (0x0200) /* PME asserted when link up is detected */ +#define PME_FROM_ENERGY (0x0100) /* PME asserted when energy is detected */ +#define PME_EVENT_MASK (0x0F00) /* PME asserted event mask */ +#define WAKEUP_AUTO_ENABLE (0x0080) /* Enable auto wake-up in energy mode */ +#define WAKEUP_NORMAL_AUTO_ENABLE (0x0040) /* Enable auto goto normal mode from energy detecion mode */ +#define WAKEUP_FROM_WKFRAME (0x0020) /* Wake-up from wake-up frame event detected */ +#define WAKEUP_FROM_MAGIC (0x0010) /* Wake-up from magic packet event detected */ +#define WAKEUP_FROM_LINKUP (0x0008) /* Wake-up from link up event detected */ +#define WAKEUP_FROM_ENERGY (0x0004) /* Wake-up from energy event detected */ +#define WAKEUP_EVENT_MASK (0x003C) /* Wake-up event mask */ +#define POWER_STATE_D1 (0x0003) /* Power saving mode */ +#define POWER_STATE_D3 (0x0002) /* Power down mode */ +#define POWER_STATE_D2 (0x0001) /* Power detection mode */ +#define POWER_STATE_D0 (0x0000) /* Normal operation mode (default) */ +#define POWER_STATE_MASK (0x0003) /* Power management mode mask */ + +#define REG_WAKEUP_TIME (0xD6) /* GSWUTR */ +#define WAKEUP_TIME (0xFF00) /* Min time (sec) wake-uo after detected energy */ +#define GOSLEEP_TIME (0x00FF) /* Min time (sec) before goto sleep when in energy mode */ + +/* + * PHY Control Registers + * (Offset 0xD8 - 0xF9) + */ +#define REG_PHY_RESET (0xD8) /* PHYRR */ +#define PHY_RESET (0x0001) /* Reset PHY */ + +#define REG_PHY_CNTL (0xE4) /* P1MBCR */ +#define PHY_SPEED_100MBIT (0x2000) /* Force PHY 100Mbps */ +#define PHY_AUTO_NEG_ENABLE (0x1000) /* Enable PHY auto-negotiation */ +#define PHY_POWER_DOWN (0x0800) /* Set PHY power-down */ +#define PHY_AUTO_NEG_RESTART (0x0200) /* Restart PHY auto-negotiation */ +#define PHY_FULL_DUPLEX (0x0100) /* Force PHY in full duplex mode */ +#define PHY_HP_MDIX (0x0020) /* Set PHY in HP auto MDI-X mode */ +#define PHY_FORCE_MDIX (0x0010) /* Force MDI-X */ +#define PHY_AUTO_MDIX_DISABLE (0x0008) /* Disable auto MDI-X */ +#define PHY_TRANSMIT_DISABLE (0x0002) /* Disable PHY transmit */ +#define PHY_LED_DISABLE (0x0001) /* Disable PHY LED */ + +#define REG_PHY_STATUS (0xE6) /* P1MBSR */ +#define PHY_100BT4_CAPABLE (0x8000) /* 100 BASE-T4 capable */ +#define PHY_100BTX_FD_CAPABLE (0x4000) /* 100BASE-TX full duplex capable */ +#define PHY_100BTX_CAPABLE (0x2000) /* 100BASE-TX half duplex capable */ +#define PHY_10BT_FD_CAPABLE (0x1000) /* 10BASE-TX full duplex capable */ +#define PHY_10BT_CAPABLE (0x0800) /* 10BASE-TX half duplex capable */ +#define PHY_AUTO_NEG_ACKNOWLEDGE (0x0020) /* Auto-negotiation complete */ +#define PHY_AUTO_NEG_CAPABLE (0x0008) /* Auto-negotiation capable */ +#define PHY_LINK_UP (0x0004) /* PHY link is up */ +#define PHY_EXTENDED_CAPABILITY (0x0001) /* PHY extended register capable */ + +#define REG_PHY_ID_LOW (0xE8) /* PHY1ILR */ +#define REG_PHY_ID_HIGH (0xEA) /* PHY1IHR */ + +#define REG_PHY_AUTO_NEGOTIATION (0xEC) /* P1ANAR */ +#define PHY_AUTO_NEG_SYM_PAUSE (0x0400) /* Advertise pause capability */ +#define PHY_AUTO_NEG_100BTX_FD (0x0100) /* Advertise 100 full-duplex capability */ +#define PHY_AUTO_NEG_100BTX (0x0080) /* Advertise 100 half-duplex capability */ +#define PHY_AUTO_NEG_10BT_FD (0x0040) /* Advertise 10 full-duplex capability */ +#define PHY_AUTO_NEG_10BT (0x0020) /* Advertise 10 half-duplex capability */ +#define PHY_AUTO_NEG_SELECTOR (0x001F) /* Selector field mask */ +#define PHY_AUTO_NEG_802_3 (0x0001) /* 802.3 */ + +#define REG_PHY_REMOTE_CAPABILITY (0xEE) /* P1ANLPR */ +#define PHY_REMOTE_SYM_PAUSE (0x0400) /* Link partner pause capability */ +#define PHY_REMOTE_100BTX_FD (0x0100) /* Link partner 100 full-duplex capability */ +#define PHY_REMOTE_100BTX (0x0080) /* Link partner 100 half-duplex capability */ +#define PHY_REMOTE_10BT_FD (0x0040) /* Link partner 10 full-duplex capability */ +#define PHY_REMOTE_10BT (0x0020) /* Link partner 10 half-duplex capability */ + +#define REG_PORT_LINK_MD (0xF4) /* P1SCLMD */ +#define PORT_CABLE_10M_SHORT (0x8000) /* Cable length is less than 10m short */ +#define PORT_CABLE_STAT_FAILED (0x6000) /* Cable diagnostic test fail */ +#define PORT_CABLE_STAT_SHORT (0x4000) /* Short condition detected in the cable */ +#define PORT_CABLE_STAT_OPEN (0x2000) /* Open condition detected in the cable */ +#define PORT_CABLE_STAT_NORMAL (0x0000) /* Normal condition */ +#define PORT_CABLE_DIAG_RESULT (0x6000) /* Cable diagnostic test result mask */ +#define PORT_START_CABLE_DIAG (0x1000) /* Enable cable diagnostic test */ +#define PORT_FORCE_LINK (0x0800) /* Enable force link pass */ +#define PORT_POWER_SAVING (0x0400) /* Disable power saving */ +#define PORT_REMOTE_LOOPBACK (0x0200) /* Enable remote loopback at PHY */ +#define PORT_CABLE_FAULT_COUNTER (0x01FF) /* Cable length distance to the fault */ + +#define REG_PORT_CTRL (0xF6) /* P1CR */ +#define PORT_LED_OFF (0x8000) /* Turn off all the port LEDs (LED3/LED2/LED1/LED0) */ +#define PORT_TX_DISABLE (0x4000) /* Disable port transmit */ +#define PORT_AUTO_NEG_RESTART (0x2000) /* Restart auto-negotiation */ +#define PORT_POWER_DOWN (0x0800) /* Set port power-down */ +#define PORT_AUTO_MDIX_DISABLE (0x0400) /* Disable auto MDI-X */ +#define PORT_FORCE_MDIX (0x0200) /* Force MDI-X */ +#define PORT_AUTO_NEG_ENABLE (0x0080) /* Enable auto-negotiation */ +#define PORT_FORCE_100_MBIT (0x0040) /* Force PHY 100Mbps */ +#define PORT_FORCE_FULL_DUPLEX (0x0020) /* Force PHY in full duplex mode */ +#define PORT_AUTO_NEG_SYM_PAUSE (0x0010) /* Advertise pause capability */ +#define PORT_AUTO_NEG_100BTX_FD (0x0008) /* Advertise 100 full-duplex capability */ +#define PORT_AUTO_NEG_100BTX (0x0004) /* Advertise 100 half-duplex capability */ +#define PORT_AUTO_NEG_10BT_FD (0x0002) /* Advertise 10 full-duplex capability */ +#define PORT_AUTO_NEG_10BT (0x0001) /* Advertise 10 half-duplex capability */ + +#define REG_PORT_STATUS (0xF8) /* P1SR */ +#define PORT_HP_MDIX (0x8000) /* Set PHY in HP auto MDI-X mode */ +#define PORT_REVERSED_POLARITY (0x2000) /* Polarity is reversed */ +#define PORT_RX_FLOW_CTRL (0x1000) /* Reeive flow control feature is active */ +#define PORT_TX_FLOW_CTRL (0x0800) /* Transmit flow control feature is active */ +#define PORT_STAT_SPEED_100MBIT (0x0400) /* Link is 100Mbps */ +#define PORT_STAT_FULL_DUPLEX (0x0200) /* Link is full duplex mode */ +#define PORT_MDIX_STATUS (0x0080) /* Is MDI */ +#define PORT_AUTO_NEG_COMPLETE (0x0040) /* Auto-negotiation complete */ +#define PORT_STATUS_LINK_GOOD (0x0020) /* PHY link is up */ +#define PORT_REMOTE_SYM_PAUSE (0x0010) /* Link partner pause capability */ +#define PORT_REMOTE_100BTX_FD (0x0008) /* Link partner 100 full-duplex capability */ +#define PORT_REMOTE_100BTX (0x0004) /* Link partner 100 half-duplex capability */ +#define PORT_REMOTE_10BT_FD (0x0002) /* Link partner 10 full-duplex capability */ +#define PORT_REMOTE_10BT (0x0001) /* Link partner 10 half-duplex capability */ + +#endif /* KSZ8851SNL_REG_H_INCLUDED */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/BufferAllocation_2.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/BufferAllocation_2.c new file mode 100644 index 000000000..531e878ea --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/BufferAllocation_2.c @@ -0,0 +1,620 @@ +/* + * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd. + * Authors include Hein Tibosch and Richard Barry + * + ******************************************************************************* + ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE *** + *** *** + *** *** + *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP *** + *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs *** + *** download): *** + *** *** + *** FreeRTOS+TCP is functional and has been used in commercial products *** + *** for some time. Be aware however that we are still refining its *** + *** design, the source code does not yet quite conform to the strict *** + *** coding and style standards mandated by Real Time Engineers ltd., and *** + *** the documentation and testing is not necessarily complete. *** + *** *** + *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE *** + *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at *** + *** the sole discretion of Real Time Engineers Ltd., be offered versions *** + *** under a license other than that described below. *** + *** *** + *** *** + ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE *** + ******************************************************************************* + * + * FreeRTOS+TCP can be used under two different free open source licenses. The + * license that applies is dependent on the processor on which FreeRTOS+TCP is + * executed, as follows: + * + * If FreeRTOS+TCP is executed on one of the processors listed under the Special + * License Arrangements heading of the FreeRTOS+TCP license information web + * page, then it can be used under the terms of the FreeRTOS Open Source + * License. If FreeRTOS+TCP is used on any other processor, then it can be used + * under the terms of the GNU General Public License V2. Links to the relevant + * licenses follow: + * + * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license + * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license + * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt + * + * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot + * use FreeRTOS+TCP unless you agree that you use the software 'as is'. + * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied + * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they + * implied, expressed, or statutory. + * + * 1 tab == 4 spaces! + * + * http://www.FreeRTOS.org + * http://www.FreeRTOS.org/plus + * http://www.FreeRTOS.org/labs + * + */ + +/****************************************************************************** +* +* See the following web page for essential buffer allocation scheme usage and +* configuration details: +* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html +* +******************************************************************************/ + +/* THIS FILE SHOULD NOT BE USED IF THE PROJECT INCLUDES A MEMORY ALLOCATOR + * THAT WILL FRAGMENT THE HEAP MEMORY. For example, heap_2 must not be used, + * heap_4 can be used. */ + +/* Standard includes. */ +#include + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_IP_Private.h" +#include "NetworkInterface.h" +#include "NetworkBufferManagement.h" + +#include "tcpip/tcpip.h" +#include "tcpip/src/tcpip_private.h" + +#include "NetworkConfig.h" + +/* The obtained network buffer must be large enough to hold a packet that might + * replace the packet that was requested to be sent. */ +#if ipconfigUSE_TCP == 1 + #define baMINIMAL_BUFFER_SIZE sizeof( TCPPacket_t ) +#else + #define baMINIMAL_BUFFER_SIZE sizeof( ARPPacket_t ) +#endif /* ipconfigUSE_TCP == 1 */ + +/*_RB_ This is too complex not to have an explanation. */ +#if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES ) + #define ASSERT_CONCAT_( a, b ) a ## b + #define ASSERT_CONCAT( a, b ) ASSERT_CONCAT_( a, b ) + #define STATIC_ASSERT( e ) \ + ; enum { ASSERT_CONCAT( assert_line_, __LINE__ ) = 1 / ( !!( e ) ) } + + STATIC_ASSERT( ipconfigETHERNET_MINIMUM_PACKET_BYTES <= baMINIMAL_BUFFER_SIZE ); +#endif + +/* A list of free (available) NetworkBufferDescriptor_t structures. */ +static List_t xFreeBuffersList; + +/* Some statistics about the use of buffers. */ +static size_t uxMinimumFreeNetworkBuffers; + +/* Declares the pool of NetworkBufferDescriptor_t structures that are available + * to the system. All the network buffers referenced from xFreeBuffersList exist + * in this array. The array is not accessed directly except during initialisation, + * when the xFreeBuffersList is filled (as all the buffers are free when the system + * is booted). */ +static NetworkBufferDescriptor_t xNetworkBufferDescriptors[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ]; + +/* This constant is defined as false to let FreeRTOS_TCP_IP.c know that the + * network buffers have a variable size: resizing may be necessary */ +const BaseType_t xBufferAllocFixedSize = pdFALSE; + +/* The semaphore used to obtain network buffers. */ +static SemaphoreHandle_t xNetworkBufferSemaphore = NULL; + +/*-----------------------------------------------------------*/ + +#ifdef PIC32_USE_ETHERNET + + /* PIC32 specific stuff */ + /* */ + + /* MAC packet acknowledgment, once MAC is done with it */ + static bool PIC32_MacPacketAcknowledge( TCPIP_MAC_PACKET * pPkt, + const void * param ); + + /* allocates a MAC packet that holds a data buffer that can be used by both: */ + /* - the FreeRTOSIP (NetworkBufferDescriptor_t->pucEthernetBuffer) */ + /* - the Harmony MAC driver: TCPIP_MAC_PACKET->pDSeg->segLoad */ + /* from the beginning of the buffer: */ + /* - 4 bytes pointer to the network descriptor (FreeRTOS) */ + /* - 4 bytes pointer to the MAC packet (pic32_NetworkInterface.c) */ + /* - 2 bytes offset from the MAC packet (Harmony MAC driver: segLoadOffset) */ + /* */ + /* NOTE: segLoadLen should NOT include: */ + /* - the TCPIP_MAC_FRAME_OFFSET (== ipBUFFER_PADDING which should be == 10!) */ + /* - the sizeof(TCPIP_MAC_ETHERNET_HEADER) */ + /* These are added by the MAC packet allocation! */ + /* */ + static uint8_t * PIC32_PktAlloc( uint16_t pktLen, + uint16_t segLoadLen, + TCPIP_MAC_PACKET_ACK_FUNC ackF, + TCPIP_MAC_PACKET ** pPtrPkt ) + { + uint8_t * pBuff = 0; + + /* allocate standard packet */ + TCPIP_MAC_PACKET * pPkt = TCPIP_PKT_PacketAlloc( pktLen, segLoadLen, 0 ); + + /* set the MAC packet pointer in the packet */ + if( pPkt != 0 ) + { + pBuff = pPkt->pDSeg->segLoad; + TCPIP_MAC_PACKET ** ppkt = ( TCPIP_MAC_PACKET ** ) ( pBuff - PIC32_BUFFER_PKT_PTR_OSSET ); + configASSERT( ( ( uint32_t ) ppkt & ( sizeof( uint32_t ) - 1 ) ) == 0 ); + *ppkt = pPkt; /* store the packet it comes from */ + pPkt->ackFunc = ackF; + pPkt->ackParam = 0; + } + + if( pPtrPkt != 0 ) + { + *pPtrPkt = pPkt; + } + + return pBuff; + } + + + + /* standard PIC32 MAC allocation function for a MAC packet */ + /* this packet saves room for the FreeRTOS network descriptor */ + /* at the beginning of the data buffer */ + /* see NetworkBufferAllocate */ + /* Note: flags parameter is ignored since that's used in the Harmony stack only */ + TCPIP_MAC_PACKET * PIC32_MacPacketAllocate( uint16_t pktLen, + uint16_t segLoadLen, + TCPIP_MAC_PACKET_FLAGS flags ) + { + TCPIP_MAC_PACKET * pPkt; + + PIC32_PktAlloc( pktLen, segLoadLen, 0, &pPkt ); + + return pPkt; + } + + /* standard PIC32 MAC packet acknowledgment */ + /* function called once MAC is done with it */ + static bool PIC32_MacPacketAcknowledge( TCPIP_MAC_PACKET * pPkt, + const void * param ) + { + configASSERT( ( pPkt != 0 ) ); + + TCPIP_PKT_PacketFree( pPkt ); + + return false; + } + + /* associates the current MAC packet with a network descriptor */ + /* mainly for RX packet */ + void PIC32_MacAssociate( TCPIP_MAC_PACKET * pRxPkt, + NetworkBufferDescriptor_t * pxBufferDescriptor, + size_t pktLength ) + { + uint8_t * pPktBuff = pRxPkt->pDSeg->segLoad; + + pxBufferDescriptor->pucEthernetBuffer = pPktBuff; + pxBufferDescriptor->xDataLength = pktLength; + + /* make sure this is a properly allocated packet */ + TCPIP_MAC_PACKET ** ppkt = ( TCPIP_MAC_PACKET ** ) ( pPktBuff - PIC32_BUFFER_PKT_PTR_OSSET ); + configASSERT( ( ( uint32_t ) ppkt & ( sizeof( uint32_t ) - 1 ) ) == 0 ); + + if( *ppkt != pRxPkt ) + { + configASSERT( false ); + } + + /* set the proper descriptor info */ + NetworkBufferDescriptor_t ** ppDcpt = ( NetworkBufferDescriptor_t ** ) ( pPktBuff - ipBUFFER_PADDING ); + configASSERT( ( ( uint32_t ) ppDcpt & ( sizeof( uint32_t ) - 1 ) ) == 0 ); + *ppDcpt = pxBufferDescriptor; + } + + /* debug functionality */ + void PIC32_MacPacketOrphan( TCPIP_MAC_PACKET * pPkt ) + { + TCPIP_PKT_PacketFree( pPkt ); + configASSERT( false ); + } + + /* FreeRTOS allocation functions */ + + /* allocates a buffer that can be used by both: */ + /* - the FreeRTOSIP (NetworkBufferDescriptor_t->pucEthernetBuffer) */ + /* - the Harmony MAC driver: TCPIP_MAC_PACKET */ + /* See PIC32_PktAlloc for details */ + /* */ + /* NOTE: reqLength should NOT include the ipBUFFER_PADDING (which should be == 10!) */ + /* or the sizeof(TCPIP_MAC_ETHERNET_HEADER) */ + /* These are added by the MAC packet allocation! */ + /* */ + uint8_t * NetworkBufferAllocate( size_t reqLength ) + { + return PIC32_PktAlloc( sizeof( TCPIP_MAC_PACKET ), reqLength, PIC32_MacPacketAcknowledge, 0 ); + } + + /* deallocates a network buffer previously allocated */ + /* with NetworkBufferAllocate */ + void NetworkBufferFree( uint8_t * pNetworkBuffer ) + { + if( pNetworkBuffer != 0 ) + { + TCPIP_MAC_PACKET ** ppkt = ( TCPIP_MAC_PACKET ** ) ( pNetworkBuffer - PIC32_BUFFER_PKT_PTR_OSSET ); + configASSERT( ( ( uint32_t ) ppkt & ( sizeof( uint32_t ) - 1 ) ) == 0 ); + TCPIP_MAC_PACKET * pPkt = *ppkt; + configASSERT( ( pPkt != 0 ) ); + + if( pPkt->ackFunc != 0 ) + { + ( *pPkt->ackFunc )( pPkt, pPkt->ackParam ); + } + else + { /* ??? */ + PIC32_MacPacketOrphan( pPkt ); + } + } + } + +#endif /* #ifdef PIC32_USE_ETHERNET */ + +/*-----------------------------------------------------------*/ + +BaseType_t xNetworkBuffersInitialise( void ) +{ + BaseType_t xReturn, x; + + /* Only initialise the buffers and their associated kernel objects if they + * have not been initialised before. */ + if( xNetworkBufferSemaphore == NULL ) + { + xNetworkBufferSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ); + configASSERT( xNetworkBufferSemaphore ); + + if( xNetworkBufferSemaphore != NULL ) + { + #if ( configQUEUE_REGISTRY_SIZE > 0 ) + { + vQueueAddToRegistry( xNetworkBufferSemaphore, "NetBufSem" ); + } + #endif /* configQUEUE_REGISTRY_SIZE */ + + /* If the trace recorder code is included name the semaphore for viewing + * in FreeRTOS+Trace. */ + #if ( ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 ) + { + extern QueueHandle_t xNetworkEventQueue; + vTraceSetQueueName( xNetworkEventQueue, "IPStackEvent" ); + vTraceSetQueueName( xNetworkBufferSemaphore, "NetworkBufferCount" ); + } + #endif /* ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 */ + + vListInitialise( &xFreeBuffersList ); + + /* Initialise all the network buffers. No storage is allocated to + * the buffers yet. */ + for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ ) + { + /* Initialise and set the owner of the buffer list items. */ + xNetworkBufferDescriptors[ x ].pucEthernetBuffer = NULL; + vListInitialiseItem( &( xNetworkBufferDescriptors[ x ].xBufferListItem ) ); + listSET_LIST_ITEM_OWNER( &( xNetworkBufferDescriptors[ x ].xBufferListItem ), &xNetworkBufferDescriptors[ x ] ); + + /* Currently, all buffers are available for use. */ + vListInsert( &xFreeBuffersList, &( xNetworkBufferDescriptors[ x ].xBufferListItem ) ); + } + + uxMinimumFreeNetworkBuffers = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; + } + } + + if( xNetworkBufferSemaphore == NULL ) + { + xReturn = pdFAIL; + } + else + { + xReturn = pdPASS; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +uint8_t * pucGetNetworkBuffer( size_t * pxRequestedSizeBytes ) +{ + uint8_t * pucEthernetBuffer; + size_t xSize = *pxRequestedSizeBytes; + + if( xSize < baMINIMAL_BUFFER_SIZE ) + { + /* Buffers must be at least large enough to hold a TCP-packet with + * headers, or an ARP packet, in case TCP is not included. */ + xSize = baMINIMAL_BUFFER_SIZE; + } + + /* Round up xSize to the nearest multiple of N bytes, + * where N equals 'sizeof( size_t )'. */ + if( ( xSize & ( sizeof( size_t ) - 1u ) ) != 0u ) + { + xSize = ( xSize | ( sizeof( size_t ) - 1u ) ) + 1u; + } + + *pxRequestedSizeBytes = xSize; + + /* Allocate a buffer large enough to store the requested Ethernet frame size + * and a pointer to a network buffer structure (hence the addition of + * ipBUFFER_PADDING bytes). */ + + #ifdef PIC32_USE_ETHERNET + pucEthernetBuffer = NetworkBufferAllocate( xSize - sizeof( TCPIP_MAC_ETHERNET_HEADER ) ); + #else + pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xSize + ipBUFFER_PADDING ); + #endif /* #ifdef PIC32_USE_ETHERNET */ + + configASSERT( pucEthernetBuffer ); + + if( pucEthernetBuffer != NULL ) + { + /* Enough space is left at the start of the buffer to place a pointer to + * the network buffer structure that references this Ethernet buffer. + * Return a pointer to the start of the Ethernet buffer itself. */ + #ifndef PIC32_USE_ETHERNET + pucEthernetBuffer += ipBUFFER_PADDING; + #endif /* #ifndef PIC32_USE_ETHERNET */ + } + + return pucEthernetBuffer; +} +/*-----------------------------------------------------------*/ + +void vReleaseNetworkBuffer( uint8_t * pucEthernetBuffer ) +{ + /* There is space before the Ethernet buffer in which a pointer to the + * network buffer that references this Ethernet buffer is stored. Remove the + * space before freeing the buffer. */ + #ifdef PIC32_USE_ETHERNET + NetworkBufferFree( pucEthernetBuffer ); + #else + if( pucEthernetBuffer != NULL ) + { + pucEthernetBuffer -= ipBUFFER_PADDING; + vPortFree( ( void * ) pucEthernetBuffer ); + } + #endif /* #ifdef PIC32_USE_ETHERNET */ +} +/*-----------------------------------------------------------*/ + +NetworkBufferDescriptor_t * pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes, + TickType_t xBlockTimeTicks ) +{ + NetworkBufferDescriptor_t * pxReturn = NULL; + size_t uxCount; + + if( ( xRequestedSizeBytes != 0u ) && ( xRequestedSizeBytes < ( size_t ) baMINIMAL_BUFFER_SIZE ) ) + { + /* ARP packets can replace application packets, so the storage must be + * at least large enough to hold an ARP. */ + xRequestedSizeBytes = baMINIMAL_BUFFER_SIZE; + } + + #ifdef PIC32_USE_ETHERNET + if( xRequestedSizeBytes != 0u ) + { + #endif /* #ifdef PIC32_USE_ETHERNET */ + xRequestedSizeBytes += 2u; + + if( ( xRequestedSizeBytes & ( sizeof( size_t ) - 1u ) ) != 0u ) + { + xRequestedSizeBytes = ( xRequestedSizeBytes | ( sizeof( size_t ) - 1u ) ) + 1u; + } + #ifdef PIC32_USE_ETHERNET + } + #endif /* #ifdef PIC32_USE_ETHERNET */ + + /* If there is a semaphore available, there is a network buffer available. */ + if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS ) + { + /* Protect the structure as it is accessed from tasks and interrupts. */ + taskENTER_CRITICAL(); + { + pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList ); + uxListRemove( &( pxReturn->xBufferListItem ) ); + } + taskEXIT_CRITICAL(); + + /* Reading UBaseType_t, no critical section needed. */ + uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList ); + + if( uxMinimumFreeNetworkBuffers > uxCount ) + { + uxMinimumFreeNetworkBuffers = uxCount; + } + + /* Allocate storage of exactly the requested size to the buffer. */ + configASSERT( pxReturn->pucEthernetBuffer == NULL ); + + if( xRequestedSizeBytes > 0 ) + { + /* Extra space is obtained so a pointer to the network buffer can + * be stored at the beginning of the buffer. */ + + #ifdef PIC32_USE_ETHERNET + pxReturn->pucEthernetBuffer = NetworkBufferAllocate( xRequestedSizeBytes - sizeof( TCPIP_MAC_ETHERNET_HEADER ) ); + #else + pxReturn->pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xRequestedSizeBytes + ipBUFFER_PADDING ); + #endif /* #ifdef PIC32_USE_ETHERNET */ + + if( pxReturn->pucEthernetBuffer == NULL ) + { + /* The attempt to allocate storage for the buffer payload failed, + * so the network buffer structure cannot be used and must be + * released. */ + vReleaseNetworkBufferAndDescriptor( pxReturn ); + pxReturn = NULL; + } + else + { + /* Store a pointer to the network buffer structure in the + * buffer storage area, then move the buffer pointer on past the + * stored pointer so the pointer value is not overwritten by the + * application when the buffer is used. */ + #ifdef PIC32_USE_ETHERNET + *( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer - ipBUFFER_PADDING ) ) = pxReturn; + #else + *( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer ) ) = pxReturn; + pxReturn->pucEthernetBuffer += ipBUFFER_PADDING; + #endif /* #ifdef PIC32_USE_ETHERNET */ + + /* Store the actual size of the allocated buffer, which may be + * greater than the original requested size. */ + pxReturn->xDataLength = xRequestedSizeBytes; + + #if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 ) + { + /* make sure the buffer is not linked */ + pxReturn->pxNextBuffer = NULL; + } + #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ + } + } + else + { + /* A descriptor is being returned without an associated buffer being + * allocated. */ + } + } + + if( pxReturn == NULL ) + { + iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER(); + } + else + { + iptraceNETWORK_BUFFER_OBTAINED( pxReturn ); + } + + return pxReturn; +} +/*-----------------------------------------------------------*/ + +void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ + BaseType_t xListItemAlreadyInFreeList; + + /* Ensure the buffer is returned to the list of free buffers before the + * counting semaphore is 'given' to say a buffer is available. Release the + * storage allocated to the buffer payload. THIS FILE SHOULD NOT BE USED + * IF THE PROJECT INCLUDES A MEMORY ALLOCATOR THAT WILL FRAGMENT THE HEAP + * MEMORY. For example, heap_2 must not be used, heap_4 can be used. */ + vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer ); + pxNetworkBuffer->pucEthernetBuffer = NULL; + + taskENTER_CRITICAL(); + { + xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); + + if( xListItemAlreadyInFreeList == pdFALSE ) + { + vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) ); + } + } + taskEXIT_CRITICAL(); + + /* + * Update the network state machine, unless the program fails to release its 'xNetworkBufferSemaphore'. + * The program should only try to release its semaphore if 'xListItemAlreadyInFreeList' is false. + */ + if( xListItemAlreadyInFreeList == pdFALSE ) + { + if ( xSemaphoreGive( xNetworkBufferSemaphore ) == pdTRUE ) + { + iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); + } + } + else + { + iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer ); + } +} +/*-----------------------------------------------------------*/ + +/* + * Returns the number of free network buffers + */ +UBaseType_t uxGetNumberOfFreeNetworkBuffers( void ) +{ + return listCURRENT_LIST_LENGTH( &xFreeBuffersList ); +} +/*-----------------------------------------------------------*/ + +UBaseType_t uxGetMinimumFreeNetworkBuffers( void ) +{ + return uxMinimumFreeNetworkBuffers; +} +/*-----------------------------------------------------------*/ + +NetworkBufferDescriptor_t * pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer, + size_t xNewSizeBytes ) +{ + size_t xOriginalLength; + uint8_t * pucBuffer; + + #ifdef PIC32_USE_ETHERNET + xOriginalLength = pxNetworkBuffer->xDataLength; + #else + xOriginalLength = pxNetworkBuffer->xDataLength + ipBUFFER_PADDING; + xNewSizeBytes = xNewSizeBytes + ipBUFFER_PADDING; + #endif /* #ifdef PIC32_USE_ETHERNET */ + + pucBuffer = pucGetNetworkBuffer( &( xNewSizeBytes ) ); + + if( pucBuffer == NULL ) + { + /* In case the allocation fails, return NULL. */ + pxNetworkBuffer = NULL; + } + else + { + pxNetworkBuffer->xDataLength = xNewSizeBytes; + if( xNewSizeBytes > xOriginalLength ) + { + xNewSizeBytes = xOriginalLength; + } + + #ifdef PIC32_USE_ETHERNET + memcpy( pucBuffer, pxNetworkBuffer->pucEthernetBuffer, xNewSizeBytes ); + *( ( NetworkBufferDescriptor_t ** ) ( pucBuffer - ipBUFFER_PADDING ) ) = pxNetworkBuffer; + #else + memcpy( pucBuffer - ipBUFFER_PADDING, pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING, xNewSizeBytes ); + #endif /* #ifdef PIC32_USE_ETHERNET */ + + vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer ); + pxNetworkBuffer->pucEthernetBuffer = pucBuffer; + } + + return pxNetworkBuffer; +} diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/NetworkInterface_eth.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/NetworkInterface_eth.c new file mode 100644 index 000000000..1b7584c44 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/NetworkInterface_eth.c @@ -0,0 +1,889 @@ +/******************************************************************************* +* Network Interface file +* +* Summary: +* Network Interface file for FreeRTOS-Plus-TCP stack +* +* Description: +* - Interfaces PIC32 to the FreeRTOS TCP/IP stack +*******************************************************************************/ + +/******************************************************************************* +* File Name: pic32_NetworkInterface.c +* Copyright 2017 Microchip Technology Incorporated and its subsidiaries. +* +* 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 +*******************************************************************************/ +#include + +#include "FreeRTOS.h" +#include "semphr.h" +#include "event_groups.h" +#include "FreeRTOS_IP.h" +#include "FreeRTOS_IP_Private.h" + +#include "NetworkInterface.h" +#include "NetworkBufferManagement.h" + + +#include "NetworkInterface.h" +#include "NetworkConfig.h" + +#include "peripheral/eth/plib_eth.h" + +#include "system_config.h" +#include "system/console/sys_console.h" +#include "system/debug/sys_debug.h" +#include "system/command/sys_command.h" + +#include "driver/ethmac/drv_ethmac.h" +#include "driver/miim/drv_miim.h" + +#include "tcpip/tcpip.h" +#include "tcpip/src/tcpip_private.h" +#include "tcpip/src/link_list.h" + +#ifdef PIC32_USE_ETHERNET + + /* local definitions and data */ + + /* debug messages */ + #if ( PIC32_MAC_DEBUG_MESSAGES != 0 ) + #define PIC32_MAC_DbgPrint( format, ... ) SYS_CONSOLE_PRINT( format, ## __VA_ARGS__ ) + #else + #define PIC32_MAC_DbgPrint( format, ... ) + #endif /* (PIC32_MAC_DEBUG_MESSAGES != 0) */ + + typedef enum + { + PIC32_MAC_EVENT_INIT_NONE = 0x000, /* no event/invalid */ + + PIC32_MAC_EVENT_INIT_DONE = 0x001, /* initialization done event */ + PIC32_MAC_EVENT_TIMEOUT = 0x002, /* periodic timeout event */ + PIC32_MAC_EVENT_IF_PENDING = 0x004, /* an interface event signal: RX, TX, errors. etc. */ + } PIC32_MAC_EVENT_TYPE; + + typedef enum + { + eMACInit, /* Must initialise MAC. */ + eMACPass, /* Initialisation was successful. */ + eMACFailed, /* Initialisation failed. */ + } eMAC_INIT_STATUS_TYPE; + + static TCPIP_STACK_HEAP_HANDLE macHeapHandle; + + static const TCPIP_MAC_OBJECT * macObject; /* the one and only MAC object; */ + + static SYS_MODULE_OBJ macObjHandle; /* the MAC object instance, obtained at initialization */ + static TCPIP_MAC_HANDLE macCliHandle; /* client handle */ + static volatile SYS_STATUS macObjStatus; /* current MAC status */ + + static TaskHandle_t macTaskHandle; + + static TimerHandle_t macTmrHandle; + + static bool macLinkStatus; /* true if link is ON */ + + static eMAC_INIT_STATUS_TYPE xMacInitStatus = eMACInit; + + /* local prototypes */ + static bool StartInitMac( void ); + static void StartInitCleanup( void ); + + static void SetMacCtrl( TCPIP_MAC_MODULE_CTRL * pMacCtrl ); + + static bool MacSyncFunction( void * synchHandle, + TCPIP_MAC_SYNCH_REQUEST req ); + + /* the PIC32 MAC task function */ + static void MacHandlerTask( void * params ); + + /* MAC interrupt event function */ + static void MAC_EventFunction( TCPIP_MAC_EVENT event, + const void * eventParam ); + + /* timer callback for link maintenance, etc; */ + static void MacTmrCallback( TimerHandle_t xTimer ); + + /* MAC RX packets functions */ + static void MacRxPackets( void ); + static void MacProcessRxPacket( TCPIP_MAC_PACKET * pRxPkt ); + + + /* memory allocation mapping to FreeRTOS */ + static void * _malloc( size_t nBytes ) + { + return pvPortMalloc( nBytes ); + } + + /*-----------------------------------------------------------*/ + + static void * _calloc( size_t nElems, + size_t elemSize ) + { + size_t nBytes = nElems * elemSize; + + void * ptr = pvPortMalloc( nBytes ); + + if( ptr != 0 ) + { + memset( ptr, 0, nBytes ); + } + + return ptr; + } + + /*-----------------------------------------------------------*/ + + static void _free( void * pBuff ) + { + vPortFree( pBuff ); + } + + /* extern references */ + /* */ + /* use the configuration data from the system_init.c */ + extern const TCPIP_NETWORK_CONFIG TCPIP_HOSTS_CONFIGURATION[]; + + /* BufferAllocation_2.c:: packet allocation function */ + extern TCPIP_MAC_PACKET * PIC32_MacPacketAllocate( uint16_t pktLen, + uint16_t segLoadLen, + TCPIP_MAC_PACKET_FLAGS flags ); + + extern void PIC32_MacAssociate( TCPIP_MAC_PACKET * pRxPkt, + NetworkBufferDescriptor_t * pxBufferDescriptor, + size_t pktLength ); + extern void PIC32_MacPacketOrphan( TCPIP_MAC_PACKET * pPkt ); + + /* cannot use the system_init.c::tcpipHeapConfig because FreeRTOS does not have a calloc function! */ + /* we build it here! */ + + /* make sure we're running with external heap! Redirect to FreeRTOS. */ + #if !defined( TCPIP_STACK_USE_EXTERNAL_HEAP ) || defined( TCPIP_STACK_USE_INTERNAL_HEAP ) || defined( TCPIP_STACK_USE_INTERNAL_HEAP_POOL ) + #error "TCPIP_STACK_USE_EXTERNAL_HEAP should be defined for this project!" + #endif + + static const TCPIP_STACK_HEAP_EXTERNAL_CONFIG tcpipHeapConfig = + { + .heapType = TCPIP_STACK_HEAP_TYPE_EXTERNAL_HEAP, + .heapFlags = TCPIP_STACK_HEAP_FLAG_ALLOC_UNCACHED | TCPIP_STACK_HEAP_FLAG_NO_MTHREAD_SYNC, + .heapUsage = TCPIP_STACK_HEAP_USE_DEFAULT, + .malloc_fnc = _malloc, + .calloc_fnc = _calloc, + .free_fnc = _free, + }; + + #if ( PIC32_MAC_DEBUG_COMMANDS != 0 ) + static int _Command_MacInfo( SYS_CMD_DEVICE_NODE * pCmdIO, + int argc, + char ** argv ); + static int _Command_NetInfo( SYS_CMD_DEVICE_NODE * pCmdIO, + int argc, + char ** argv ); + static int _Command_Version( SYS_CMD_DEVICE_NODE * pCmdIO, + int argc, + char ** argv ); + + static const SYS_CMD_DESCRIPTOR macCmdTbl[] = + { + { "macinfo", _Command_MacInfo, ": Check MAC statistics" }, + { "netinfo", _Command_NetInfo, ": Net info" }, + { "version", _Command_Version, ": Version info" }, + }; + #endif /* (PIC32_MAC_DEBUG_COMMANDS != 0) */ + + + /* FreeRTOS implementation functions */ + BaseType_t xNetworkInterfaceInitialise( void ) + { + BaseType_t xResult; + + if( xMacInitStatus == eMACInit ) + { + /* This is the first time this function is called. */ + if( StartInitMac() != false ) + { + /* Indicate that the MAC initialisation succeeded. */ + xMacInitStatus = eMACPass; + } + else + { + xMacInitStatus = eMACFailed; + } + } + + if( xMacInitStatus == eMACPass ) + { + xResult = xGetPhyLinkStatus(); + } + else + { + xResult = pdFAIL; + } + + PIC32_MAC_DbgPrint( "xNetworkInterfaceInitialise: %d %d\r\n", ( int ) xMacInitStatus, ( int ) xResult ); + + return xResult; + } + + + /*-----------------------------------------------------------*/ + + BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, + BaseType_t xReleaseAfterSend ) + { + TCPIP_MAC_RES macRes; + TCPIP_MAC_PACKET * pTxPkt; + + BaseType_t retRes = pdFALSE; + + + if( ( pxDescriptor != 0 ) && ( pxDescriptor->pucEthernetBuffer != 0 ) && ( pxDescriptor->xDataLength != 0 ) ) + { + TCPIP_MAC_PACKET ** ppkt = ( TCPIP_MAC_PACKET ** ) ( pxDescriptor->pucEthernetBuffer - PIC32_BUFFER_PKT_PTR_OSSET ); + configASSERT( ( ( uint32_t ) ppkt & ( sizeof( uint32_t ) - 1 ) ) == 0 ); + pTxPkt = *ppkt; + configASSERT( pTxPkt != 0 ); + + /* prepare the packet for transmission */ + /* set the correct data length: */ + configASSERT( pTxPkt->pDSeg->segSize >= pTxPkt->pDSeg->segLen ); + pTxPkt->pDSeg->segLen = pxDescriptor->xDataLength; + pTxPkt->next = 0; /* unlink it */ + macRes = ( macObject->TCPIP_MAC_PacketTx )( macCliHandle, pTxPkt ); + + if( macRes >= 0 ) + { + retRes = pdTRUE; + pxDescriptor->pucEthernetBuffer = 0; /* it will be released by the MAC driver once it's transmitted */ + iptraceNETWORK_INTERFACE_TRANSMIT(); + } + + /* else same error occurred; this normally should not happen! But the buffer is left in there so it shold be freed! */ + + /* The buffer has been sent so can be released. */ + if( xReleaseAfterSend != pdFALSE ) + { + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + } + } + + return retRes; + } + + + /************************************* Section: helper functions ************************************************** */ + /* */ + + void PIC32_GetMACAddress( uint8_t macAdd[ 6 ] ) + { + #if defined( __PIC32MZ__ ) || defined( __PIC32MX__ ) + PLIB_ETH_MACGetAddress( ETH_ID_0, macAdd ); + #else + #error "MAC Address: not supported architecture!" + #endif + } + + + /*-----------------------------------------------------------*/ + + const void * const PIC32_GetMacConfigData( void ) + { + #if defined( __PIC32MZ__ ) || defined( __PIC32MX__ ) + extern const TCPIP_MODULE_MAC_PIC32INT_CONFIG tcpipMACPIC32INTInitData; + + return &tcpipMACPIC32INTInitData; + #else + #error "MAC Address: not supported architecture!" + #endif + } + + /************************************* Section: worker code ************************************************** */ + /* */ + + + static bool StartInitMac( void ) + { + TCPIP_MAC_MODULE_CTRL macCtrl; + SYS_MODULE_INIT moduleInit; + EventBits_t evBits; + + + /* perform some initialization of all variables so that we can cleanup what failed */ + /* if something failed, the routine will be called again and again by FreeRTOS! */ + macHeapHandle = 0; + macObjHandle = 0; + macCliHandle = 0; + macTmrHandle = 0; + macTaskHandle = 0; + macObject = TCPIP_HOSTS_CONFIGURATION[ 0 ].pMacObject; /* the MAC object we use */ + macObjStatus = SYS_STATUS_UNINITIALIZED; + macLinkStatus = false; + + int netUpFail = 0; + + while( true ) + { + /* start the allocator */ + macHeapHandle = TCPIP_HEAP_Create( ( const TCPIP_STACK_HEAP_CONFIG * ) &tcpipHeapConfig, 0 ); + + if( macHeapHandle == 0 ) + { + netUpFail = 1; + break; + } + + if( TCPIP_PKT_Initialize( macHeapHandle, 0, 0 ) == false ) + { + netUpFail = 2; + break; + } + + moduleInit.sys.powerState = SYS_MODULE_POWER_RUN_FULL; + + /* Initialize the MAC. MAC address is defined to 0x000000000000 in + * FreeRTOSConfig.h and therefore it will be initialized to the + * factory programmed MAC address. */ + SetMacCtrl( &macCtrl ); + /* Set the mac address in the FreeRTOS+TCP stack. */ + FreeRTOS_UpdateMACAddress( macCtrl.ifPhyAddress.v ); + + TCPIP_MAC_INIT macInit = + { + .moduleInit = { moduleInit.value }, + .macControl = &macCtrl, + .moduleData = PIC32_GetMacConfigData(), + }; + + macObjHandle = ( macObject->TCPIP_MAC_Initialize )( TCPIP_MODULE_MAC_PIC32INT, &macInit.moduleInit ); + + if( macObjHandle == SYS_MODULE_OBJ_INVALID ) + { + macObjHandle = 0; + netUpFail = 4; + break; + } + + /* open the MAC */ + macCliHandle = ( macObject->TCPIP_MAC_Open )( TCPIP_MODULE_MAC_PIC32INT, DRV_IO_INTENT_READWRITE ); + + if( macCliHandle == DRV_HANDLE_INVALID ) + { + macCliHandle = 0; + netUpFail = 5; + break; + } + + if( !( macObject->TCPIP_MAC_EventMaskSet )( macCliHandle, ( TCPIP_MAC_EV_RX_DONE | TCPIP_MAC_EV_TX_DONE | TCPIP_MAC_EV_RXTX_ERRORS ), true ) ) + { + netUpFail = 6; + break; + } + + /* completed the MAC initialization */ + /* continue the initialization */ + macTmrHandle = xTimerCreate( PIC32_MAC_TIMER_NAME, PIC32_MAC_TIMER_PERIOD, pdTRUE, 0, MacTmrCallback ); + + if( ( macTmrHandle == 0 ) || ( xTimerStart( macTmrHandle, 0 ) != pdPASS ) ) + { + netUpFail = 8; + break; + } + + /* spawn the PIC32 MAC task function */ + /* and wait for its event signal */ + macObjStatus = SYS_STATUS_BUSY; + + if( xTaskCreate( MacHandlerTask, PIC32_MAC_TASK_NAME, PIC32_MAC_TASK_STACK_SIZE, xTaskGetCurrentTaskHandle(), PIC32_MAC_TASK_PRI, &macTaskHandle ) != pdPASS ) + { /* failed */ + netUpFail = 9; + break; + } + + xTaskNotifyWait( PIC32_MAC_EVENT_INIT_DONE, PIC32_MAC_EVENT_INIT_DONE, &evBits, PIC32_MAC_INIT_TIMEOUT ); + + if( ( evBits & PIC32_MAC_EVENT_INIT_DONE ) == 0 ) + { /* timed out */ + netUpFail = 10; + break; + } + + if( macObjStatus != SYS_STATUS_READY ) + { /* failed somehow ??? */ + netUpFail = 11; + break; + } + + netUpFail = 0; + break; + } + + if( netUpFail == 0 ) + { + PIC32_MAC_DbgPrint( " MAC Init success!\r\n" ); + + #if ( PIC32_MAC_DEBUG_COMMANDS != 0 ) + /* create command group */ + if( !SYS_CMD_ADDGRP( macCmdTbl, sizeof( macCmdTbl ) / sizeof( *macCmdTbl ), "mac", ": mac commands" ) ) + { + PIC32_MAC_DbgPrint( "Failed to create MAC Commands\r\n" ); + } + #endif /* (PIC32_MAC_DEBUG_COMMANDS != 0) */ + + return true; + } + else + { + StartInitCleanup(); + PIC32_MAC_DbgPrint( "MAC Init failed: %d!\r\n", netUpFail ); + + return false; + } + } + + /*-----------------------------------------------------------*/ + + static void StartInitCleanup( void ) + { + if( macHeapHandle != 0 ) + { + TCPIP_HEAP_Delete( macHeapHandle ); + macHeapHandle = 0; + } + + if( macObjHandle != 0 ) + { + ( macObject->TCPIP_MAC_Deinitialize )( macObjHandle ); + macObjHandle = 0; + } + + if( macTmrHandle != 0 ) + { + xTimerDelete( macTmrHandle, portMAX_DELAY ); + macTmrHandle = 0; + } + + if( macTaskHandle != 0 ) + { + vTaskDelete( macTaskHandle ); + macTaskHandle = 0; + } + } + + /*-----------------------------------------------------------*/ + + static void SetMacCtrl( TCPIP_MAC_MODULE_CTRL * pMacCtrl ) + { + TCPIP_MAC_ADDR macAdd; + uint8_t unsetMACAddr[ 6 ] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /* not set MAC address */ + + pMacCtrl->nIfs = 1; + + pMacCtrl->mallocF = TCPIP_HEAP_MallocOutline; + pMacCtrl->callocF = TCPIP_HEAP_CallocOutline; + pMacCtrl->freeF = TCPIP_HEAP_FreeOutline; + pMacCtrl->memH = macHeapHandle; + + + pMacCtrl->pktAllocF = PIC32_MacPacketAllocate; + pMacCtrl->pktFreeF = ( TCPIP_MAC_PKT_FreeF ) _TCPIP_PKT_FREE_FNC; + pMacCtrl->pktAckF = ( TCPIP_MAC_PKT_AckF ) _TCPIP_PKT_ACK_FNC; + + pMacCtrl->synchF = MacSyncFunction; + + pMacCtrl->eventF = MAC_EventFunction; + pMacCtrl->eventParam = 0; + + pMacCtrl->moduleId = TCPIP_MODULE_MAC_PIC32INT; + pMacCtrl->netIx = 0; + pMacCtrl->macAction = TCPIP_MAC_ACTION_INIT; + pMacCtrl->powerMode = TCPIP_MAC_POWER_FULL; + + macAdd.v[ 0 ] = configMAC_ADDR0; + macAdd.v[ 1 ] = configMAC_ADDR1; + macAdd.v[ 2 ] = configMAC_ADDR2; + macAdd.v[ 3 ] = configMAC_ADDR3; + macAdd.v[ 4 ] = configMAC_ADDR4; + macAdd.v[ 5 ] = configMAC_ADDR5; + + if( memcmp( macAdd.v, unsetMACAddr, sizeof( unsetMACAddr ) ) == 0 ) + { /* if unspecified we use the factory pre-programmed address */ + PIC32_GetMACAddress( pMacCtrl->ifPhyAddress.v ); + } + else + { /* use the config suggested one */ + memcpy( pMacCtrl->ifPhyAddress.v, macAdd.v, sizeof( macAdd ) ); + } + } + + /*-----------------------------------------------------------*/ + + static bool MacSyncFunction( void * synchHandle, + TCPIP_MAC_SYNCH_REQUEST req ) + { + switch( req ) + { + case TCPIP_MAC_SYNCH_REQUEST_OBJ_CREATE: + vSemaphoreCreateBinary( *( SemaphoreHandle_t * ) synchHandle ); + + return ( *( SemaphoreHandle_t * ) synchHandle == NULL ) ? false : true; + + case TCPIP_MAC_SYNCH_REQUEST_OBJ_DELETE: + vSemaphoreDelete( *( SemaphoreHandle_t * ) synchHandle ); + *( SemaphoreHandle_t * ) synchHandle = NULL; + + return true; + + case TCPIP_MAC_SYNCH_REQUEST_OBJ_LOCK: + + return ( xSemaphoreTake( *( SemaphoreHandle_t * ) synchHandle, portMAX_DELAY ) == pdTRUE ) ? true : false; + + case TCPIP_MAC_SYNCH_REQUEST_OBJ_UNLOCK: + + return ( xSemaphoreGive( *( SemaphoreHandle_t * ) synchHandle ) == pdTRUE ) ? true : false; + + case TCPIP_MAC_SYNCH_REQUEST_CRIT_ENTER: + vTaskSuspendAll(); + + return true; + + case TCPIP_MAC_SYNCH_REQUEST_CRIT_LEAVE: + xTaskResumeAll(); + + return true; + + default: + + return false; + } + } + + + /*-----------------------------------------------------------*/ + + static void MacHandlerTask( void * params ) + { + EventBits_t evBits; + + /* perform the MAC initialization */ + while( macObjStatus == SYS_STATUS_BUSY ) + { + /* process the underlying MAC module tasks */ + ( macObject->TCPIP_MAC_Tasks )( macObjHandle ); + + SYS_STATUS macStatus = ( macObject->TCPIP_MAC_Status )( macObjHandle ); + + if( macStatus == SYS_STATUS_BUSY ) + { /* still pending */ + vTaskDelay( PIC32_MAC_TASK_INIT_PENDING_DELAY ); + } + else + { /* completed ...somehow */ + macObjStatus = macStatus; + + xTaskNotify( ( TaskHandle_t ) params, PIC32_MAC_EVENT_INIT_DONE, eSetBits ); + + if( macStatus != SYS_STATUS_READY ) + { /* failed miserably */ + vTaskDelete( 0 ); + } + + /* done, up and running */ + } + } + + while( true ) + { + xTaskNotifyWait( PIC32_MAC_EVENT_TIMEOUT | PIC32_MAC_EVENT_IF_PENDING, PIC32_MAC_EVENT_TIMEOUT | PIC32_MAC_EVENT_IF_PENDING, &evBits, portMAX_DELAY ); + + if( ( evBits & PIC32_MAC_EVENT_TIMEOUT ) != 0 ) + { /* timeout occurred... */ + ( macObject->TCPIP_MAC_Tasks )( macObjHandle ); + bool linkCurr = ( macObject->TCPIP_MAC_LinkCheck )( macCliHandle ); /* check link status */ + + if( macLinkStatus != linkCurr ) + { /* link status changed; some event could ve fired here if needed */ + PIC32_MAC_DbgPrint( " MAC link: %s!\r\n", linkCurr ? "ON" : "OFF" ); + macLinkStatus = linkCurr; + } + } + + if( ( evBits & PIC32_MAC_EVENT_IF_PENDING ) != 0 ) + { /* IF events signal */ + TCPIP_MAC_EVENT activeEvents = ( macObject->TCPIP_MAC_EventPendingGet )( macCliHandle ); + + if( activeEvents != TCPIP_MAC_EV_NONE ) + { + /* acknowledge the events */ + ( macObject->TCPIP_MAC_EventAcknowledge )( macCliHandle, activeEvents ); + + /* check for RX */ + if( ( activeEvents & ( TCPIP_MAC_EV_RX_DONE | TCPIP_MAC_EV_RX_OVFLOW | TCPIP_MAC_EV_RX_BUFNA ) ) != 0 ) + { /* RX packets available */ + MacRxPackets(); + } + + /* call the driver process function; */ + /* PIC32 driver requests it through TCPIP_MAC_ParametersGet() which is bypassed here! */ + ( macObject->TCPIP_MAC_Process )( macCliHandle ); + } + } + + /* do what you have to do and then wait for another event... */ + } + } + + /*-----------------------------------------------------------*/ + + static void MacTmrCallback( TimerHandle_t xTimer ) + { + xTaskNotify( macTaskHandle, PIC32_MAC_EVENT_TIMEOUT, eSetBits ); + } + + /* MAC interrupt event function */ + /* MAC signals an event, probably from within ISR */ + /* we care just for RX related events */ + static void MAC_EventFunction( TCPIP_MAC_EVENT event, + const void * eventParam ) + { + BaseType_t xHigherPriorityTaskWoken; + + if( ( event & ( TCPIP_MAC_EV_RX_DONE | TCPIP_MAC_EV_TX_DONE | TCPIP_MAC_EV_RXTX_ERRORS ) ) != 0 ) + { + xHigherPriorityTaskWoken = pdFALSE; + xTaskNotifyFromISR( macTaskHandle, PIC32_MAC_EVENT_IF_PENDING, eSetBits, &xHigherPriorityTaskWoken ); + + if( xHigherPriorityTaskWoken ) + { + portEND_SWITCHING_ISR( xHigherPriorityTaskWoken ); + } + } + } + + /*-----------------------------------------------------------*/ + + BaseType_t xGetPhyLinkStatus( void ) + { + return macLinkStatus == true ? pdPASS : pdFAIL; + } + + + /* receive packets from the MAC driver */ + static void MacRxPackets( void ) + { + TCPIP_MAC_PACKET * pRxPkt; + + /* get all the new MAC packets */ + while( ( pRxPkt = ( macObject->TCPIP_MAC_PacketRx )( macCliHandle, 0, 0 ) ) != 0 ) + { + MacProcessRxPacket( pRxPkt ); + } + } + + /*-----------------------------------------------------------*/ + + static void MacProcessRxPacket( TCPIP_MAC_PACKET * pRxPkt ) + { + bool pktSuccess, pktLost; + size_t pktLength; + TCPIP_MAC_DATA_SEGMENT * pSeg; + uint8_t * pPktBuff; + NetworkBufferDescriptor_t * pxBufferDescriptor; + IPStackEvent_t xRxEvent; + + pxBufferDescriptor = 0; + pktSuccess = pktLost = false; + + while( true ) + { + pktLength = 0; + int nSegs = 0; + pSeg = pRxPkt->pDSeg; + pPktBuff = pSeg->segLoad; + + /* calculate the packet size */ + do + { + pktLength += pSeg->segLen; + pSeg = pSeg->next; + nSegs++; + } while( pSeg != 0 ); + + if( nSegs > 1 ) + { /* no support in FreeRTOS for multi segment packets! */ + break; + } + + /* sizeof(TCPIP_MAC_ETHERNET_HEADER) is subtracted by the driver */ + /* but FreeRTOS needs the whole frame! */ + pktLength += sizeof( TCPIP_MAC_ETHERNET_HEADER ); + + if( eConsiderFrameForProcessing( pPktBuff ) != eProcessBuffer ) + { + break; + } + + /* get the network descriptor (no data buffer) to hold this packet */ + pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( 0, 0 ); + + if( pxBufferDescriptor == 0 ) + { + pktLost = true; + break; + } + + PIC32_MacAssociate( pRxPkt, pxBufferDescriptor, pktLength ); + + xRxEvent.eEventType = eNetworkRxEvent; + xRxEvent.pvData = ( void * ) pxBufferDescriptor; + + /* Send the data to the TCP/IP stack */ + if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE ) + { /* failed */ + pktLost = true; + } + else + { /* success */ + pktSuccess = true; + iptraceNETWORK_INTERFACE_RECEIVE(); + } + + break; + } + + if( !pktSuccess ) + { /* smth went wrong; nothing sent to the */ + if( pxBufferDescriptor != 0 ) + { + pxBufferDescriptor->pucEthernetBuffer = 0; + vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor ); + } + + if( pktLost ) + { + iptraceETHERNET_RX_EVENT_LOST(); + } + + /* acknowledge the packet to the MAC driver */ + if( pRxPkt->ackFunc ) + { + ( *pRxPkt->ackFunc )( pRxPkt, pRxPkt->ackParam ); + } + else + { + PIC32_MacPacketOrphan( pRxPkt ); + } + } + } + + #if ( PIC32_MAC_DEBUG_COMMANDS != 0 ) + /* */ + static int _Command_MacInfo( SYS_CMD_DEVICE_NODE * pCmdIO, + int argc, + char ** argv ) + { + TCPIP_MAC_RES macRes; + TCPIP_MAC_RX_STATISTICS rxStatistics; + TCPIP_MAC_TX_STATISTICS txStatistics; + TCPIP_MAC_STATISTICS_REG_ENTRY regEntries[ 8 ]; + TCPIP_MAC_STATISTICS_REG_ENTRY * pRegEntry; + int jx, hwEntries; + char entryName[ sizeof( pRegEntry->registerName ) + 1 ]; + + const void * cmdIoParam = pCmdIO->cmdIoParam; + + if( argc != 1 ) + { + ( *pCmdIO->pCmdApi->msg )( cmdIoParam, "Usage: macinfo \r\n" ); + ( *pCmdIO->pCmdApi->msg )( cmdIoParam, "Ex: macinfo \r\n" ); + + return false; + } + + ( *pCmdIO->pCmdApi->print )( cmdIoParam, "Interface: %s driver statistics\r\n", macObject->macName ); + macRes = ( macObject->TCPIP_MAC_StatisticsGet )( macCliHandle, &rxStatistics, &txStatistics ); + + if( macRes == TCPIP_MAC_RES_OK ) + { + ( *pCmdIO->pCmdApi->print )( cmdIoParam, "\tnRxOkPackets: %d, nRxPendBuffers: %d, nRxSchedBuffers: %d, ", + rxStatistics.nRxOkPackets, rxStatistics.nRxPendBuffers, rxStatistics.nRxSchedBuffers ); + ( *pCmdIO->pCmdApi->print )( cmdIoParam, "nRxErrorPackets: %d, nRxFragmentErrors: %d\r\n", rxStatistics.nRxErrorPackets, rxStatistics.nRxFragmentErrors ); + ( *pCmdIO->pCmdApi->print )( cmdIoParam, "\tnTxOkPackets: %d, nTxPendBuffers: %d, nTxErrorPackets: %d, nTxQueueFull: %d\r\n", + txStatistics.nTxOkPackets, txStatistics.nTxPendBuffers, txStatistics.nTxErrorPackets, txStatistics.nTxQueueFull ); + } + else + { + ( *pCmdIO->pCmdApi->msg )( cmdIoParam, "\tnot supported\r\n" ); + } + + ( *pCmdIO->pCmdApi->print )( cmdIoParam, "Interface: %s hardware statistics\r\n", macObject->macName ); + macRes = ( macObject->TCPIP_MAC_RegisterStatisticsGet )( macCliHandle, regEntries, sizeof( regEntries ) / sizeof( *regEntries ), &hwEntries ); + + if( macRes == TCPIP_MAC_RES_OK ) + { + entryName[ sizeof( entryName ) - 1 ] = 0; + + for( jx = 0, pRegEntry = regEntries; jx < hwEntries && jx < sizeof( regEntries ) / sizeof( *regEntries ); jx++, pRegEntry++ ) + { + strncpy( entryName, pRegEntry->registerName, sizeof( entryName ) - 1 ); + ( *pCmdIO->pCmdApi->print )( cmdIoParam, "\t%s: 0x%8x\r\n", entryName, pRegEntry->registerValue ); + } + } + else + { + ( *pCmdIO->pCmdApi->msg )( cmdIoParam, "\tnot supported\r\n" ); + } + + return true; + } + + /*-----------------------------------------------------------*/ + + static int _Command_NetInfo( SYS_CMD_DEVICE_NODE * pCmdIO, + int argc, + char ** argv ) + { + const void * cmdIoParam = pCmdIO->cmdIoParam; + + union + { + uint32_t ul; + uint8_t b[ 4 ]; + } + sUl; + + sUl.ul = FreeRTOS_GetIPAddress(); + + bool linkUp = FreeRTOS_IsNetworkUp() == pdTRUE; + + ( *pCmdIO->pCmdApi->print )( cmdIoParam, "IP address: %d.%d.%d.%d\r\n", sUl.b[ 0 ], sUl.b[ 1 ], sUl.b[ 2 ], sUl.b[ 3 ] ); + ( *pCmdIO->pCmdApi->print )( cmdIoParam, "Link is: %s\r\n", linkUp ? "Up" : "Down" ); + + return true; + } + +#include "aws_application_version.h" + +static int _Command_Version(SYS_CMD_DEVICE_NODE* pCmdIO, int argc, char** argv) +{ + configPRINTF( ( "App version - maj: %d, min: %d, build: %d\r\n", xAppFirmwareVersion.u.x.ucMajor, xAppFirmwareVersion.u.x.ucMinor, xAppFirmwareVersion.u.x.usBuild) ); + return 0; +} + + #endif /* (PIC32_MAC_DEBUG_COMMANDS != 0) */ +#endif /* #ifdef PIC32_USE_ETHERNET */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/NetworkInterface_wifi.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/NetworkInterface_wifi.c new file mode 100644 index 000000000..a24cfe8ad --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/pic32mzef/NetworkInterface_wifi.c @@ -0,0 +1,192 @@ +/******************************************************************************* +* Network Interface file +* +* Summary: +* Network Interface file for FreeRTOS-Plus-TCP stack +* +* Description: +* - Interfaces PIC32 to the FreeRTOS TCP/IP stack +*******************************************************************************/ + +/******************************************************************************* +* File Name: pic32_NetworkInterface.c +* Copyright 2017 Microchip Technology Incorporated and its subsidiaries. +* +* 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 +*******************************************************************************/ +#ifndef PIC32_USE_ETHERNET +#include + +#include "FreeRTOS.h" +#include "semphr.h" +#include "event_groups.h" +#include "FreeRTOS_IP.h" +#include "FreeRTOS_IP_Private.h" + +#include "NetworkInterface.h" +#include "NetworkBufferManagement.h" +#include "peripheral/eth/plib_eth.h" + +#include "system_config.h" +#include "system/console/sys_console.h" +#include "system/debug/sys_debug.h" +#include "system/command/sys_command.h" + +#include "driver/ethmac/drv_ethmac.h" +#include "driver/miim/drv_miim.h" +#include "m2m_types.h" + +#include "tcpip/tcpip.h" +#include "tcpip/src/tcpip_private.h" +#include "tcpip/src/link_list.h" +#include "wilc1000_task.h" + +#include "NetworkConfig.h" + + + #include "iot_wifi.h" + + /* local definitions and data */ + + + /* FreeRTOS implementation functions */ + BaseType_t xNetworkInterfaceInitialise( void ) + { + WIFINetworkParams_t xNetworkParams; + + xNetworkParams.pcSSID = clientcredentialWIFI_SSID; + xNetworkParams.ucSSIDLength = sizeof( clientcredentialWIFI_SSID ); + xNetworkParams.pcPassword = clientcredentialWIFI_PASSWORD; + xNetworkParams.ucPasswordLength = sizeof( clientcredentialWIFI_PASSWORD ); + xNetworkParams.xSecurity = clientcredentialWIFI_SECURITY; + xNetworkParams.cChannel = M2M_WIFI_CH_ALL; /* Scan all channels (255) */ + + /*Turn WiFi ON */ + if( WIFI_On() != eWiFiSuccess ) + { + return pdFAIL; + } + + /* Connect to the AP */ + if( WIFI_ConnectAP( &xNetworkParams ) != eWiFiSuccess ) + { + return pdFAIL; + } + + return pdPASS; + } + + + /*-----------------------------------------------------------*/ + + BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, + BaseType_t xReleaseAfterSend ) + { + BaseType_t retRes = pdFALSE; + + if( ( pxDescriptor != 0 ) && ( pxDescriptor->pucEthernetBuffer != 0 ) && ( pxDescriptor->xDataLength != 0 ) ) + { + /* There you go */ + if( WDRV_EXT_DataSend( pxDescriptor->xDataLength, pxDescriptor->pucEthernetBuffer ) == 0 ) + { + retRes = pdTRUE; + } + + /* The buffer has been sent so can be released. */ + if( xReleaseAfterSend != pdFALSE ) + { + vReleaseNetworkBufferAndDescriptor( pxDescriptor ); + } + } + + return retRes; + } + + + /************************************* Section: helper functions ************************************************** */ + /* */ + + + + /************************************* Section: worker code ************************************************** */ + /* */ + + void xNetworkFrameReceived( uint32_t len, + uint8_t const * const frame ) + { + bool pktSuccess, pktLost; + NetworkBufferDescriptor_t * pxNetworkBuffer = NULL; + IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL }; + + pktSuccess = pktLost = false; + + while( true ) + { + if( eConsiderFrameForProcessing( frame ) != eProcessBuffer ) + { + break; + } + + /* get the network descriptor (no data buffer) to hold this packet */ + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( len, 0 ); + + if( pxNetworkBuffer == NULL ) + { + pktLost = true; + break; + } + + /* Set the actual packet length, in case a larger buffer was + returned. */ + pxNetworkBuffer->xDataLength = len; + + /* Copy the packet. */ + memcpy( pxNetworkBuffer->pucEthernetBuffer, frame, len ); + + /* Send the data to the TCP/IP stack. */ + xRxEvent.pvData = ( void * ) pxNetworkBuffer; + + if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE ) + { /* failed */ + pktLost = true; + } + else + { /* success */ + pktSuccess = true; + iptraceNETWORK_INTERFACE_RECEIVE(); + } + + break; + } + + if( !pktSuccess ) + { /* smth went wrong; nothing sent to the */ + if( pxNetworkBuffer != NULL ) + { + pxNetworkBuffer->pucEthernetBuffer = 0; + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + } + + if( pktLost ) + { + iptraceETHERNET_RX_EVENT_LOST(); + } + } + } + +#endif /* #ifndef PIC32_USE_ETHERNET */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/readme.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/readme.txt new file mode 100644 index 000000000..a90fb9e17 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-TCP/readme.txt @@ -0,0 +1,18 @@ +Contains the files that implement FreeRTOS+TCP. + +User documentation, including an API reference is available on: +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/ + +A description of the source code organisation is available on: +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_Networking_Tutorial.html + +The porting guide is available on: +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/FreeRTOS_TCP_Porting.html + +License information is available on: +http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/FreeRTOS_Plus_TCP_License.html + +At this time it is recommended to use BufferAllocation_2.c in which case it is +essential to use the heap_4.c memory allocation scheme: +http://www.FreeRTOS.org/a00111.html + diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcHardwarePort.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcHardwarePort.h new file mode 100644 index 000000000..6bd981c4c --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcHardwarePort.h @@ -0,0 +1,478 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * trcHardwarePort.h + * + * The hardware abstraction layer for the trace recorder. + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_HARDWARE_PORT_H +#define TRC_HARDWARE_PORT_H + +#include "trcPortDefines.h" + + +#if (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_NOT_SET) + #error "TRC_CFG_HARDWARE_PORT not selected - see trcConfig.h" +#endif + +/******************************************************************************* + * TRC_IRQ_PRIORITY_ORDER + * + * Macro which should be defined as an integer of 0 or 1. + * + * This should be 0 if lower IRQ priority values implies higher priority + * levels, such as on ARM Cortex M. If the opposite scheme is used, i.e., + * if higher IRQ priority values means higher priority, this should be 1. + * + * This setting is not critical. It is used only to sort and colorize the + * interrupts in priority order, in case you record interrupts using + * the vTraceStoreISRBegin and vTraceStoreISREnd routines. + * + ****************************************************************************** + * + * HWTC Macros + * + * These macros provides a hardware isolation layer representing the + * hardware timer/counter used for the event timestamping. + * + * TRC_HWTC_COUNT: How to read the current value of the timer/counter. + * + * TRC_HWTC_TYPE: Tells the type of timer/counter used for TRC_HWTC_COUNT: + * + * - TRC_FREE_RUNNING_32BIT_INCR: + * Free-running 32-bit timer/counter, counting upwards from 0. + * + * - TRC_FREE_RUNNING_32BIT_DECR + * Free-running 32-bit timer/counter, counting downwards from 0xFFFFFFFF. + * + * - TRC_OS_TIMER_INCR + * Periodic timer that drives the OS tick interrupt, counting upwards + * from 0 until (TRC_HWTC_PERIOD-1). + * + * - TRC_OS_TIMER_DECR + * Periodic timer that drives the OS tick interrupt, counting downwards + * from TRC_HWTC_PERIOD-1 until 0. + * + * - TRC_CUSTOM_TIMER_INCR + * A custom timer or counter independent of the OS tick, counting + * downwards from TRC_HWTC_PERIOD-1 until 0. (Currently only supported + * in streaming mode). + * + * - TRC_CUSTOM_TIMER_DECR + * A custom timer independent of the OS tick, counting downwards + * from TRC_HWTC_PERIOD-1 until 0. (Currently only supported + * in streaming mode). + * + * TRC_HWTC_PERIOD: The number of HWTC_COUNT ticks until the timer wraps + * around. If using TRC_FREE_RUNNING_32BIT_INCR/DECR, this should be 0. + * + * TRC_HWTC_FREQ_HZ: The clock rate of the TRC_HWTC_COUNT counter in Hz. If using + * TRC_OS_TIMER_INCR/DECR, this is should be TRC_HWTC_PERIOD * TRACE_TICK_RATE_HZ. + * If using a free-running timer, this is often TRACE_CPU_CLOCK_HZ (if running at + * the core clock rate). If using TRC_CUSTOM_TIMER_INCR/DECR, this should match + * the clock rate of your custom timer (i.e., TRC_HWTC_COUNT). If the default value + * of TRC_HWTC_FREQ_HZ is incorrect for your setup, you can override it by calling + * vTraceSetFrequency before calling vTraceEnable. + * + * TRC_HWTC_DIVISOR (used in snapshot mode only): + * In snapshot mode, the timestamp resolution is TRC_HWTC_FREQ_HZ/TRC_HWTC_DIVISOR. + * If the timer frequency is very high (hundreds of MHz), we recommend increasing + * the TRC_HWTC_DIVISOR prescaler, to reduce the bandwidth needed to store + * timestamps. This since extra "XTS" events are inserted if the time since the + * previous event exceeds a certain limit (255 or 65535 depending on event type). + * It is advised to keep the time between most events below 65535 native ticks + * (after division by TRC_HWTC_DIVISOR) to avoid frequent XTS events. + ******************************************************************************/ + +#if (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_NOT_SET) + #error "TRC_CFG_HARDWARE_PORT not selected - see trcConfig.h" +#endif + +#if (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_Win32) + /* This can be used as a template for any free-running 32-bit counter */ + #define TRC_HWTC_TYPE TRC_FREE_RUNNING_32BIT_INCR + #define TRC_HWTC_COUNT (ulGetRunTimeCounterValue()) + #define TRC_HWTC_PERIOD 0 + #define TRC_HWTC_DIVISOR 1 + #define TRC_HWTC_FREQ_HZ 100000 + + #define TRC_IRQ_PRIORITY_ORDER 1 + + #define TRC_PORT_SPECIFIC_INIT() + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_HWIndependent) + /* Timestamping by OS tick only (typically 1 ms resolution) */ + #define TRC_HWTC_TYPE TRC_OS_TIMER_INCR + #define TRC_HWTC_COUNT 0 + #define TRC_HWTC_PERIOD 1 + #define TRC_HWTC_DIVISOR 1 + #define TRC_HWTC_FREQ_HZ TRACE_TICK_RATE_HZ + + /* Set the meaning of IRQ priorities in ISR tracing - see above */ + #define TRC_IRQ_PRIORITY_ORDER NOT_SET + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M) + + #ifndef __CORTEX_M + #error "Can't find the CMSIS API. Please include your processor's header file in trcConfig.h" + #endif + + /************************************************************************** + * For Cortex-M3, M4 and M7, the DWT cycle counter is used for timestamping. + * For Cortex-M0 and M0+, the SysTick timer is used since DWT is not + * available. Systick timestamping can also be forced on Cortex-M3, M4 and + * M7 by defining the preprocessor directive TRC_CFG_ARM_CM_USE_SYSTICK, + * either directly below or in trcConfig.h. + * + * #define TRC_CFG_ARM_CM_USE_SYSTICK + **************************************************************************/ + + #if ((__CORTEX_M >= 0x03) && (! defined TRC_CFG_ARM_CM_USE_SYSTICK)) + + void prvTraceInitCortexM(void); + + #define TRC_REG_DEMCR (*(volatile uint32_t*)0xE000EDFC) + #define TRC_REG_DWT_CTRL (*(volatile uint32_t*)0xE0001000) + #define TRC_REG_DWT_CYCCNT (*(volatile uint32_t*)0xE0001004) + #define TRC_REG_DWT_EXCCNT (*(volatile uint32_t*)0xE000100C) + + #define TRC_REG_ITM_LOCKACCESS (*(volatile uint32_t*)0xE0001FB0) + #define TRC_ITM_LOCKACCESS_UNLOCK (0xC5ACCE55) + + /* Bit mask for TRCENA bit in DEMCR - Global enable for DWT and ITM */ + #define TRC_DEMCR_TRCENA (1 << 24) + + /* Bit mask for NOPRFCNT bit in DWT_CTRL. If 1, DWT_EXCCNT is not supported */ + #define TRC_DWT_CTRL_NOPRFCNT (1 << 24) + + /* Bit mask for NOCYCCNT bit in DWT_CTRL. If 1, DWT_CYCCNT is not supported */ + #define TRC_DWT_CTRL_NOCYCCNT (1 << 25) + + /* Bit mask for EXCEVTENA_ bit in DWT_CTRL. Set to 1 to enable DWT_EXCCNT */ + #define TRC_DWT_CTRL_EXCEVTENA (1 << 18) + + /* Bit mask for EXCEVTENA_ bit in DWT_CTRL. Set to 1 to enable DWT_CYCCNT */ + #define TRC_DWT_CTRL_CYCCNTENA (1) + + #define TRC_PORT_SPECIFIC_INIT() prvTraceInitCortexM() + + #define TRC_HWTC_TYPE TRC_FREE_RUNNING_32BIT_INCR + #define TRC_HWTC_COUNT TRC_REG_DWT_CYCCNT + #define TRC_HWTC_PERIOD 0 + #define TRC_HWTC_DIVISOR 4 + #define TRC_HWTC_FREQ_HZ TRACE_CPU_CLOCK_HZ + #define TRC_IRQ_PRIORITY_ORDER 0 + + #else + + #define TRC_HWTC_TYPE TRC_OS_TIMER_DECR + #define TRC_HWTC_COUNT (*((volatile uint32_t*)0xE000E018)) + #define TRC_HWTC_PERIOD ((*((volatile uint32_t*)0xE000E014)) + 1) + #define TRC_HWTC_DIVISOR 4 + #define TRC_HWTC_FREQ_HZ TRACE_CPU_CLOCK_HZ + #define TRC_IRQ_PRIORITY_ORDER 0 + + #endif + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_Renesas_RX600) + + #include "iodefine.h" + + #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) + + #define TRC_HWTC_TYPE TRC_OS_TIMER_INCR + #define TRC_HWTC_COUNT (CMT0.CMCNT) + + #elif (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) + + /* Decreasing counters better for Tickless Idle? */ + #define TRC_HWTC_TYPE TRC_OS_TIMER_DECR + #define TRC_HWTC_COUNT (CMT0.CMCOR - CMT0.CMCNT) + + #endif + + #define TRC_HWTC_PERIOD (CMT0.CMCOR + 1) + #define TRC_HWTC_DIVISOR 1 + #define TRC_HWTC_FREQ_HZ (TRACE_TICK_RATE_HZ * TRC_HWTC_PERIOD) + #define TRC_IRQ_PRIORITY_ORDER 1 + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_MICROCHIP_PIC24_PIC32) + + #define TRC_HWTC_TYPE TRC_OS_TIMER_INCR + #define TRC_HWTC_COUNT (TMR1) + #define TRC_HWTC_PERIOD (PR1 + 1) + #define TRC_HWTC_DIVISOR 1 + #define TRC_HWTC_FREQ_HZ (TRACE_TICK_RATE_HZ * TRC_HWTC_PERIOD) + #define TRC_IRQ_PRIORITY_ORDER 0 + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_TEXAS_INSTRUMENTS_TMS570_RM48) + + #define TRC_RTIFRC0 *((uint32_t *)0xFFFFFC10) + #define TRC_RTICOMP0 *((uint32_t *)0xFFFFFC50) + #define TRC_RTIUDCP0 *((uint32_t *)0xFFFFFC54) + + #define TRC_HWTC_TYPE TRC_OS_TIMER_INCR + #define TRC_HWTC_COUNT (TRC_RTIFRC0 - (TRC_RTICOMP0 - TRC_RTIUDCP0)) + #define TRC_HWTC_PERIOD (TRC_RTIUDCP0) + #define TRC_HWTC_DIVISOR 1 + #define TRC_HWTC_FREQ_HZ (TRACE_TICK_RATE_HZ * TRC_HWTC_PERIOD) + #define TRC_IRQ_PRIORITY_ORDER 0 + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_Atmel_AT91SAM7) + + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + #define TRC_HWTC_TYPE TRC_OS_TIMER_INCR + #define TRC_HWTC_COUNT ((uint32_t)(AT91C_BASE_PITC->PITC_PIIR & 0xFFFFF)) + #define TRC_HWTC_PERIOD ((uint32_t)(AT91C_BASE_PITC->PITC_PIMR + 1)) + #define TRC_HWTC_DIVISOR 1 + #define TRC_HWTC_FREQ_HZ (TRACE_TICK_RATE_HZ * TRC_HWTC_PERIOD) + #define TRC_IRQ_PRIORITY_ORDER 1 + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_Atmel_UC3A0) + + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO*/ + + /* For Atmel AVR32 (AT32UC3A) */ + + #define TRC_HWTC_TYPE TRC_OS_TIMER_INCR + #define TRC_HWTC_COUNT ((uint32_t)sysreg_read(AVR32_COUNT)) + #define TRC_HWTC_PERIOD ((uint32_t)(sysreg_read(AVR32_COMPARE) + 1)) + #define TRC_HWTC_DIVISOR 1 + #define TRC_HWTC_FREQ_HZ (TRACE_TICK_RATE_HZ * TRC_HWTC_PERIOD) + #define TRC_IRQ_PRIORITY_ORDER 1 + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_NXP_LPC210X) + + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + /* Tested with LPC2106, but should work with most LPC21XX chips. */ + + #define TRC_HWTC_TYPE TRC_OS_TIMER_INCR + #define TRC_HWTC_COUNT *((uint32_t *)0xE0004008 ) + #define TRC_HWTC_PERIOD *((uint32_t *)0xE0004018 ) + #define TRC_HWTC_DIVISOR 1 + #define TRC_HWTC_FREQ_HZ (TRACE_TICK_RATE_HZ * TRC_HWTC_PERIOD) + #define TRC_IRQ_PRIORITY_ORDER 0 + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_TEXAS_INSTRUMENTS_MSP430) + + /* UNOFFICIAL PORT - NOT YET VERIFIED */ + + #define TRC_HWTC_TYPE TRC_OS_TIMER_INCR + #define TRC_HWTC_COUNT (TA0R) + #define TRC_HWTC_PERIOD (((uint16_t)TACCR0)+1) + #define TRC_HWTC_DIVISOR 1 + #define TRC_HWTC_FREQ_HZ (TRACE_TICK_RATE_HZ * TRC_HWTC_PERIOD) + #define TRC_IRQ_PRIORITY_ORDER 1 + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_XILINX_PPC405) + + /* UNOFFICIAL PORT - NOT YET VERIFIED */ + + #define TRC_HWTC_TYPE TRC_OS_TIMER_DECR + #define TRC_HWTC_COUNT mfspr(0x3db) + #define TRC_HWTC_PERIOD (TRACE_CPU_CLOCK_HZ / TRACE_TICK_RATE_HZ) + #define TRC_HWTC_DIVISOR 1 + #define TRC_HWTC_FREQ_HZ (TRACE_TICK_RATE_HZ * TRC_HWTC_PERIOD) + #define TRC_IRQ_PRIORITY_ORDER 0 + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_XILINX_PPC440) + + /* UNOFFICIAL PORT */ + + /* This should work with most PowerPC chips */ + + #define TRC_HWTC_TYPE TRC_OS_TIMER_DECR + #define TRC_HWTC_COUNT mfspr(0x016) + #define TRC_HWTC_PERIOD (TRACE_CPU_CLOCK_HZ / TRACE_TICK_RATE_HZ) + #define TRC_HWTC_DIVISOR 1 + #define TRC_HWTC_FREQ_HZ (TRACE_TICK_RATE_HZ * TRC_HWTC_PERIOD) + #define TRC_IRQ_PRIORITY_ORDER 0 + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_XILINX_MICROBLAZE) + + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + /* This should work with most Microblaze configurations. + * It uses the AXI Timer 0 - the tick interrupt source. + * If an AXI Timer 0 peripheral is available on your hardware platform, no modifications are required. + */ + #include "xtmrctr_l.h" + + #define TRC_HWTC_TYPE TRC_OS_TIMER_DECR + #define TRC_HWTC_COUNT XTmrCtr_GetTimerCounterReg( XPAR_TMRCTR_0_BASEADDR, 0 ) + #define TRC_HWTC_PERIOD (XTmrCtr_mGetLoadReg( XPAR_TMRCTR_0_BASEADDR, 0) + 1) + #define TRC_HWTC_DIVISOR 16 + #define TRC_HWTC_FREQ_HZ (TRACE_TICK_RATE_HZ * TRC_HWTC_PERIOD) + #define TRC_IRQ_PRIORITY_ORDER 0 + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_Altera_NiosII) + + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + #include "system.h" + #include "sys/alt_timestamp.h" + + #define TRC_HWTC_TYPE TRC_OS_TIMER_INCR + #define TRC_HWTC_COUNT (uint32_t)alt_timestamp() + #define TRC_HWTC_PERIOD 0xFFFFFFFF + #define TRC_HWTC_FREQ_HZ TIMESTAMP_TIMER_FREQ + #define TRC_HWTC_DIVISOR 1 + #define TRC_IRQ_PRIORITY_ORDER 0 + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_CORTEX_A9) + + /* INPUT YOUR PERIPHERAL BASE ADDRESS HERE */ + #define TRC_CA9_MPCORE_PERIPHERAL_BASE_ADDRESS 0xSOMETHING + + #define TRC_CA9_MPCORE_PRIVATE_MEMORY_OFFSET 0x0600 + #define TRC_CA9_MPCORE_PRIVCTR_PERIOD_REG (*(volatile uint32_t*)(TRC_CA9_MPCORE_PERIPHERAL_BASE_ADDRESS + TRC_CA9_MPCORE_PRIVATE_MEMORY_OFFSET + 0x00)) + #define TRC_CA9_MPCORE_PRIVCTR_COUNTER_REG (*(volatile uint32_t*)(TRC_CA9_MPCORE_PERIPHERAL_BASE_ADDRESS + TRC_CA9_MPCORE_PRIVATE_MEMORY_OFFSET + 0x04)) + #define TRC_CA9_MPCORE_PRIVCTR_CONTROL_REG (*(volatile uint32_t*)(TRC_CA9_MPCORE_PERIPHERAL_BASE_ADDRESS + TRC_CA9_MPCORE_PRIVATE_MEMORY_OFFSET + 0x08)) + + #define TRC_CA9_MPCORE_PRIVCTR_CONTROL_PRESCALER_MASK 0x0000FF00 + #define TRC_CA9_MPCORE_PRIVCTR_CONTROL_PRESCALER_SHIFT 8 + #define TRC_CA9_MPCORE_PRIVCTR_PRESCALER (((TRC_CA9_MPCORE_PRIVCTR_CONTROL_REG & TRC_CA9_MPCORE_PRIVCTR_CONTROL_PRESCALER_MASK) >> TRC_CA9_MPCORE_PRIVCTR_CONTROL_PRESCALER_SHIFT) + 1) + + #define TRC_HWTC_TYPE TRC_OS_TIMER_DECR + #define TRC_HWTC_COUNT TRC_CA9_MPCORE_PRIVCTR_COUNTER_REG + #define TRC_HWTC_PERIOD (TRC_CA9_MPCORE_PRIVCTR_PERIOD_REG + 1) + + /**************************************************************************************** + NOTE: The private timer ticks with a very high frequency (half the core-clock usually), + depending on the prescaler used. If a low prescaler is used, the number of HW ticks between + the trace events gets large, and thereby inefficient to store (sometimes extra events are + needed). To improve efficiency, you may use the TRC_HWTC_DIVISOR as an additional prescaler. + *****************************************************************************************/ + #define TRC_HWTC_DIVISOR 1 + + #define TRC_HWTC_FREQ_HZ (TRACE_TICK_RATE_HZ * TRC_HWTC_PERIOD) + #define TRC_IRQ_PRIORITY_ORDER 0 + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_POWERPC_Z4) + + /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ + + #define TRC_HWTC_TYPE TRC_OS_TIMER_DECR + //#define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING + #define TRC_HWTC_COUNT PIT.TIMER[configTICK_PIT_CHANNEL].CVAL.R // must be the PIT channel used for the systick + #define TRC_HWTC_PERIOD ((configPIT_CLOCK_HZ / configTICK_RATE_HZ) - 1U) // TODO FIXME or maybe not -1? what's the right "period" value? + #define TRC_HWTC_FREQ_HZ configPIT_CLOCK_HZ + #define TRC_HWTC_DIVISOR 1 + #define TRC_IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant + +#elif (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_APPLICATION_DEFINED) + + #if !( defined (TRC_HWTC_TYPE) && defined (TRC_HWTC_COUNT) && defined (TRC_HWTC_PERIOD) && defined (TRC_HWTC_FREQ_HZ) && defined (TRC_IRQ_PRIORITY_ORDER) ) + #error "The hardware port is not completely defined!" + #endif + +#elif (TRC_CFG_HARDWARE_PORT != TRC_HARDWARE_PORT_NOT_SET) + + #error "TRC_CFG_HARDWARE_PORT had unsupported value!" + #define TRC_CFG_HARDWARE_PORT TRC_HARDWARE_PORT_NOT_SET + +#endif + +#ifndef TRC_HWTC_DIVISOR + #define TRC_HWTC_DIVISOR 1 +#endif + +#ifndef TRC_PORT_SPECIFIC_INIT + #define TRC_PORT_SPECIFIC_INIT() +#endif + +/* If Win32 port */ +#ifdef WIN32 + + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0600 + + /* Standard includes. */ + #include + #include + #include + + /*************************************************************************** + * The Win32 port by default saves the trace to file and then kills the + * program when the recorder is stopped, to facilitate quick, simple tests + * of the recorder. + ***************************************************************************/ + #define WIN32_PORT_SAVE_WHEN_STOPPED 1 + #define WIN32_PORT_EXIT_WHEN_STOPPED 1 + +#endif + +#if (TRC_CFG_HARDWARE_PORT != TRC_HARDWARE_PORT_NOT_SET) + + #ifndef TRC_HWTC_TYPE + #error "TRC_HWTC_TYPE is not set!" + #endif + + #ifndef TRC_HWTC_COUNT + #error "TRC_HWTC_COUNT is not set!" + #endif + + #ifndef TRC_HWTC_PERIOD + #error "TRC_HWTC_PERIOD is not set!" + #endif + + #ifndef TRC_HWTC_DIVISOR + #error "TRC_HWTC_DIVISOR is not set!" + #endif + + #ifndef TRC_IRQ_PRIORITY_ORDER + #error "TRC_IRQ_PRIORITY_ORDER is not set!" + #elif (TRC_IRQ_PRIORITY_ORDER != 0) && (TRC_IRQ_PRIORITY_ORDER != 1) + #error "TRC_IRQ_PRIORITY_ORDER has bad value!" + #endif + + #if (TRC_HWTC_DIVISOR < 1) + #error "TRC_HWTC_DIVISOR must be a non-zero positive value!" + #endif + + #ifndef TRC_HWTC_FREQ_HZ + #error "TRC_HWTC_FREQ_HZ not defined!" + #endif + +#endif + +#endif /*TRC_SNAPSHOT_HARDWARE_PORT_H*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort - Copy with task notification array.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort - Copy with task notification array.h new file mode 100644 index 000000000..19d678b4d --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort - Copy with task notification array.h @@ -0,0 +1,2565 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * FreeRTOS-specific definitions needed by the trace recorder + * + * + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_KERNEL_PORT_H +#define TRC_KERNEL_PORT_H + +#include "FreeRTOS.h" /* Defines configUSE_TRACE_FACILITY */ +#include "trcPortDefines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define TRC_USE_TRACEALYZER_RECORDER configUSE_TRACE_FACILITY + +/*** FreeRTOS version codes **************************************************/ +#define FREERTOS_VERSION_NOT_SET 0 +#define TRC_FREERTOS_VERSION_7_3 1 /* v7.3 is earliest supported.*/ +#define TRC_FREERTOS_VERSION_7_4 2 +#define TRC_FREERTOS_VERSION_7_5_OR_7_6 3 +#define TRC_FREERTOS_VERSION_8_X 4 /* Any v8.x.x*/ +#define TRC_FREERTOS_VERSION_9_0_0 5 +#define TRC_FREERTOS_VERSION_9_0_1 6 +#define TRC_FREERTOS_VERSION_9_0_2 7 +#define TRC_FREERTOS_VERSION_10_0_0 8 /* If using FreeRTOS v10.0.0 or later version */ + +#define TRC_FREERTOS_VERSION_9_X 42 /* Not allowed anymore */ + +#if (TRC_CFG_FREERTOS_VERSION == TRC_FREERTOS_VERSION_9_X) +/* This setting for TRC_CFG_FREERTOS_VERSION is no longer allowed as v9.0.1 needs special handling. */ +#error "Please specify your exact FreeRTOS version in trcConfig.h, from the options listed above." +#endif + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +#define prvGetStreamBufferType(x) ((( StreamBuffer_t * )x )->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER) +#else +#define prvGetStreamBufferType(x) 0 +#endif + +/* Added mainly for our internal testing. This makes it easier to create test applications that + runs on multiple FreeRTOS versions. */ +#if (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_8_X) + /* FreeRTOS v7.0 and later */ + #define STRING_CAST(x) ( (signed char*) x ) + #define TickType portTickType +#else + /* FreeRTOS v8.0 and later */ + #define STRING_CAST(x) x + #define TickType TickType_t +#endif + +#if (defined(TRC_USE_TRACEALYZER_RECORDER)) && (TRC_USE_TRACEALYZER_RECORDER == 1) + +/******************************************************************************* + * INCLUDE_xTaskGetCurrentTaskHandle must be set to 1 for tracing to work properly + ******************************************************************************/ +#undef INCLUDE_xTaskGetCurrentTaskHandle +#define INCLUDE_xTaskGetCurrentTaskHandle 1 + +#if (TRC_CFG_SCHEDULING_ONLY == 0) +/******************************************************************************* + * vTraceSetQueueName(void* object, const char* name) + * + * Parameter object: pointer to the Queue that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for Queue objects for display in Tracealyzer. + ******************************************************************************/ +void vTraceSetQueueName(void* object, const char* name); + +/******************************************************************************* + * vTraceSetSemaphoreName(void* object, const char* name) + * + * Parameter object: pointer to the Semaphore that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for Semaphore objects for display in Tracealyzer. + ******************************************************************************/ +void vTraceSetSemaphoreName(void* object, const char* name); + +/******************************************************************************* + * vTraceSetMutexName(void* object, const char* name) + * + * Parameter object: pointer to the Mutex that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for Semaphore objects for display in Tracealyzer. + ******************************************************************************/ +void vTraceSetMutexName(void* object, const char* name); + +#if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1) +/******************************************************************************* +* vTraceSetEventGroupName(void* object, const char* name) +* +* Parameter object: pointer to the EventGroup that shall be named +* Parameter name: the name to set (const string literal) +* +* Sets a name for EventGroup objects for display in Tracealyzer. +******************************************************************************/ +void vTraceSetEventGroupName(void* object, const char* name); +#else /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1) */ +#define vTraceSetEventGroupName(object, name) /* Do nothing */ +#endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1) */ + +#if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) +/******************************************************************************* +* vTraceSetStreamBufferName(void* object, const char* name) +* +* Parameter object: pointer to the StreamBuffer that shall be named +* Parameter name: the name to set (const string literal) +* +* Sets a name for StreamBuffer objects for display in Tracealyzer. +******************************************************************************/ +void vTraceSetStreamBufferName(void* object, const char* name); +#else /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) */ +#define vTraceSetStreamBufferName(object, name) /* Do nothing */ +#endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) */ + +#if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) +/******************************************************************************* + * vTraceSetMessageBufferName(void* object, const char* name) + * + * Parameter object: pointer to the MessageBuffer that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for MessageBuffer objects for display in Tracealyzer. + ******************************************************************************/ +void vTraceSetMessageBufferName(void* object, const char* name); +#else /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) */ +#define vTraceSetMessageBufferName(object, name) /* Do nothing */ +#endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) */ + +#else /* (TRC_CFG_SCHEDULING_ONLY == 0) */ + +#define vTraceSetQueueName(object, name) /* Do nothing */ +#define vTraceSetSemaphoreName(object, name) /* Do nothing */ +#define vTraceSetMutexName(object, name) /* Do nothing */ +#define vTraceSetEventGroupName(object, name) /* Do nothing */ +#define vTraceSetStreamBufferName(object, name) /* Do nothing */ +#define vTraceSetMessageBufferName(object, name) /* Do nothing */ + +#endif /* (TRC_CFG_SCHEDULING_ONLY == 0) */ + +/******************************************************************************* + * Note: Setting names for event groups is difficult to support, this has been + * excluded intentionally. This since we don't know if event_groups.c is + * included in the build, so referencing it from the recorder may cause errors. + ******************************************************************************/ + +/* Gives the currently executing task (wrapper for RTOS-specific function) */ +void* prvTraceGetCurrentTaskHandle(void); + +#if (((TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) && (TRC_CFG_INCLUDE_ISR_TRACING == 1)) || (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)) +/* Tells if the scheduler currently is suspended (task-switches can't occur) */ +unsigned char prvTraceIsSchedulerSuspended(void); + +/******************************************************************************* + * INCLUDE_xTaskGetSchedulerState must be set to 1 for tracing to work properly + ******************************************************************************/ +#undef INCLUDE_xTaskGetSchedulerState +#define INCLUDE_xTaskGetSchedulerState 1 + +#endif /* (((TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) && (TRC_CFG_INCLUDE_ISR_TRACING == 1)) || (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)) */ + +#define TRACE_KERNEL_VERSION 0x1AA1 +#define TRACE_TICK_RATE_HZ configTICK_RATE_HZ /* Defined in "FreeRTOS.h" */ +#define TRACE_CPU_CLOCK_HZ configCPU_CLOCK_HZ /* Defined in "FreeRTOSConfig.h" */ +#define TRACE_GET_CURRENT_TASK() prvTraceGetCurrentTaskHandle() + +#define TRACE_GET_OS_TICKS() (uiTraceTickCount) /* Streaming only */ + +/* If using dynamic allocation of snapshot trace buffer... */ +#define TRACE_MALLOC(size) pvPortMalloc(size) + +#if defined(configUSE_TIMERS) +#if (configUSE_TIMERS == 1) +#undef INCLUDE_xTimerGetTimerDaemonTaskHandle +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1 +#endif /* configUSE_TIMERS == 1*/ +#endif /* configUSE_TIMERS */ + +/* For ARM Cortex-M devices - assumes the ARM CMSIS API is available */ +#if (defined (__CORTEX_M)) + #define TRACE_ALLOC_CRITICAL_SECTION() uint32_t __irq_status; + #define TRACE_ENTER_CRITICAL_SECTION() {__irq_status = __get_PRIMASK(); __set_PRIMASK(1);} /* PRIMASK disables ALL interrupts - allows for tracing in any ISR */ + #define TRACE_EXIT_CRITICAL_SECTION() {__set_PRIMASK(__irq_status);} +#endif + +#if ((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_CORTEX_A9) || (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_Renesas_RX600) || (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_MICROCHIP_PIC24_PIC32) || (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_Altera_NiosII)) + #define TRACE_ALLOC_CRITICAL_SECTION() int __irq_status; + #define TRACE_ENTER_CRITICAL_SECTION() {__irq_status = portSET_INTERRUPT_MASK_FROM_ISR();} + #define TRACE_EXIT_CRITICAL_SECTION() {portCLEAR_INTERRUPT_MASK_FROM_ISR(__irq_status);} +#endif + +#if (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_Win32) + /* In the Win32 port, there are no real interrupts, so we can use the normal critical sections */ + #define TRACE_ALLOC_CRITICAL_SECTION() + #define TRACE_ENTER_CRITICAL_SECTION() portENTER_CRITICAL() + #define TRACE_EXIT_CRITICAL_SECTION() portEXIT_CRITICAL() +#endif + +#if (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_POWERPC_Z4) +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) + /* FreeRTOS v8.0 or later */ + #define TRACE_ALLOC_CRITICAL_SECTION() UBaseType_t __irq_status; + #define TRACE_ENTER_CRITICAL_SECTION() {__irq_status = portSET_INTERRUPT_MASK_FROM_ISR();} + #define TRACE_EXIT_CRITICAL_SECTION() {portCLEAR_INTERRUPT_MASK_FROM_ISR(__irq_status);} +#else + /* FreeRTOS v7.x */ + #define TRACE_ALLOC_CRITICAL_SECTION() unsigned portBASE_TYPE __irq_status; + #define TRACE_ENTER_CRITICAL_SECTION() {__irq_status = portSET_INTERRUPT_MASK_FROM_ISR();} + #define TRACE_EXIT_CRITICAL_SECTION() {portCLEAR_INTERRUPT_MASK_FROM_ISR(__irq_status);} +#endif +#endif + +#ifndef TRACE_ENTER_CRITICAL_SECTION + #error "This hardware port has no definition for critical sections! See http://percepio.com/2014/10/27/how-to-define-critical-sections-for-the-recorder/" +#endif + + +#if (TRC_CFG_FREERTOS_VERSION == TRC_FREERTOS_VERSION_9_0_1) + /****************************************************************************** + * Fix for FreeRTOS v9.0.1 to correctly identify xQueuePeek events. + * + * In FreeRTOS v9.0.1, the below trace hooks are incorrectly used from three + * different functions. This as the earlier function xQueueGenericReceive + * has been replaced by xQueuePeek, xQueueSemaphoreTake and xQueueReceive. + * + * xQueueGenericReceive had a parameter "xJustPeeking", used by the trace hooks + * to tell between xQueuePeek events and others. This is no longer present, so + * we need another way to correctly identify peek events. Since all three + * functions call the same trace macros, the context of these macro is unknown. + * + * We therefore check the __LINE__ macro inside of the trace macros. This gives + * the line number of queue.c, where the macros are used. This can be used to + * tell if the context is xQueuePeek or another function. + * __LINE__ is a standard compiler feature since ancient times, so it should + * work on all common compilers. + * + * This might seem as a quite brittle and unusual solution, but works in this + * particular case and is only for FreeRTOS v9.0.1. + * Future versions of FreeRTOS should not need this fix, as we have submitted + * a correction of queue.c with individual trace macros for each function. + ******************************************************************************/ +#define isQueueReceiveHookActuallyPeek (__LINE__ > 1674) /* Half way between the closes trace points */ + +#elif (TRC_CFG_FREERTOS_VERSION <= TRC_FREERTOS_VERSION_9_0_0) +#define isQueueReceiveHookActuallyPeek xJustPeeking + +#elif (TRC_CFG_FREERTOS_VERSION > TRC_FREERTOS_VERSION_9_0_1) +#define isQueueReceiveHookActuallyPeek (__LINE__ < 0) /* instead of pdFALSE to fix a warning of "constant condition" */ + +#endif + +extern uint16_t CurrentFilterMask; + +extern uint16_t CurrentFilterGroup; + +uint8_t prvTraceGetQueueType(void* handle); + +uint16_t prvTraceGetTaskNumberLow16(void* handle); +uint16_t prvTraceGetTaskNumberHigh16(void* handle); +void prvTraceSetTaskNumberLow16(void* handle, uint16_t value); +void prvTraceSetTaskNumberHigh16(void* handle, uint16_t value); + +uint16_t prvTraceGetQueueNumberLow16(void* handle); +uint16_t prvTraceGetQueueNumberHigh16(void* handle); +void prvTraceSetQueueNumberLow16(void* handle, uint16_t value); +void prvTraceSetQueueNumberHigh16(void* handle, uint16_t value); + +#if (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +uint16_t prvTraceGetTimerNumberLow16(void* handle); +uint16_t prvTraceGetTimerNumberHigh16(void* handle); +void prvTraceSetTimerNumberLow16(void* handle, uint16_t value); +void prvTraceSetTimerNumberHigh16(void* handle, uint16_t value); +#endif /* (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +uint16_t prvTraceGetEventGroupNumberLow16(void* handle); +uint16_t prvTraceGetEventGroupNumberHigh16(void* handle); +void prvTraceSetEventGroupNumberLow16(void* handle, uint16_t value); +void prvTraceSetEventGroupNumberHigh16(void* handle, uint16_t value); +#endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +uint16_t prvTraceGetStreamBufferNumberLow16(void* handle); +uint16_t prvTraceGetStreamBufferNumberHigh16(void* handle); +void prvTraceSetStreamBufferNumberLow16(void* handle, uint16_t value); +void prvTraceSetStreamBufferNumberHigh16(void* handle, uint16_t value); +#endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#define TRACE_GET_TASK_FILTER(pxTask) prvTraceGetTaskNumberHigh16((void*)pxTask) +#define TRACE_SET_TASK_FILTER(pxTask, group) prvTraceSetTaskNumberHigh16((void*)pxTask, group) + +#define TRACE_GET_QUEUE_FILTER(pxObject) prvTraceGetQueueNumberHigh16((void*)pxObject) +#define TRACE_SET_QUEUE_FILTER(pxObject, group) prvTraceSetQueueNumberHigh16((void*)pxObject, group) + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +#define TRACE_GET_EVENTGROUP_FILTER(pxObject) prvTraceGetEventGroupNumberHigh16((void*)pxObject) +#define TRACE_SET_EVENTGROUP_FILTER(pxObject, group) prvTraceSetEventGroupNumberHigh16((void*)pxObject, group) +#else /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ +/* FreeRTOS versions before v10.0 does not support filtering for event groups */ +#define TRACE_GET_EVENTGROUP_FILTER(pxObject) 1 +#define TRACE_SET_EVENTGROUP_FILTER(pxObject, group) +#endif /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +#define TRACE_GET_TIMER_FILTER(pxObject) prvTraceGetTimerNumberHigh16((void*)pxObject) +#define TRACE_SET_TIMER_FILTER(pxObject, group) prvTraceSetTimerNumberHigh16((void*)pxObject, group) +#else /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ +/* FreeRTOS versions before v10.0 does not support filtering for timers */ +#define TRACE_GET_TIMER_FILTER(pxObject) 1 +#define TRACE_SET_TIMER_FILTER(pxObject, group) +#endif /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#define TRACE_GET_STREAMBUFFER_FILTER(pxObject) prvTraceGetStreamBufferNumberHigh16((void*)pxObject) +#define TRACE_SET_STREAMBUFFER_FILTER(pxObject, group) prvTraceSetStreamBufferNumberHigh16((void*)pxObject, group) + +/* We can only support filtering if FreeRTOS is at least v7.4 */ +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_7_4) +#define TRACE_GET_OBJECT_FILTER(CLASS, pxObject) TRACE_GET_##CLASS##_FILTER(pxObject) +#define TRACE_SET_OBJECT_FILTER(CLASS, pxObject, group) TRACE_SET_##CLASS##_FILTER(pxObject, group) +#else /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_7_4) */ +#define TRACE_GET_OBJECT_FILTER(CLASS, pxObject) 1 +#define TRACE_SET_OBJECT_FILTER(CLASS, pxObject, group) +#endif /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_7_4) */ + +/******************************************************************************/ +/*** Definitions for Snapshot mode ********************************************/ +/******************************************************************************/ +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) + +/*** The object classes *******************************************************/ + +#define TRACE_NCLASSES 9 +#define TRACE_CLASS_QUEUE ((traceObjectClass)0) +#define TRACE_CLASS_SEMAPHORE ((traceObjectClass)1) +#define TRACE_CLASS_MUTEX ((traceObjectClass)2) +#define TRACE_CLASS_TASK ((traceObjectClass)3) +#define TRACE_CLASS_ISR ((traceObjectClass)4) +#define TRACE_CLASS_TIMER ((traceObjectClass)5) +#define TRACE_CLASS_EVENTGROUP ((traceObjectClass)6) +#define TRACE_CLASS_STREAMBUFFER ((traceObjectClass)7) +#define TRACE_CLASS_MESSAGEBUFFER ((traceObjectClass)8) + +/*** Definitions for Object Table ********************************************/ +#define TRACE_KERNEL_OBJECT_COUNT ((TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER) + (TRC_CFG_NEVENTGROUP) + (TRC_CFG_NSTREAMBUFFER) + (TRC_CFG_NMESSAGEBUFFER)) + +/* Queue properties (except name): current number of message in queue */ +#define PropertyTableSizeQueue ((TRC_CFG_NAME_LEN_QUEUE) + 1) + +/* Semaphore properties (except name): state (signaled = 1, cleared = 0) */ +#define PropertyTableSizeSemaphore ((TRC_CFG_NAME_LEN_SEMAPHORE) + 1) + +/* Mutex properties (except name): owner (task handle, 0 = free) */ +#define PropertyTableSizeMutex ((TRC_CFG_NAME_LEN_MUTEX) + 1) + +/* Task properties (except name): Byte 0: Current priority + Byte 1: state (if already active) + Byte 2: legacy, not used + Byte 3: legacy, not used */ +#define PropertyTableSizeTask ((TRC_CFG_NAME_LEN_TASK) + 4) + +/* ISR properties: Byte 0: priority + Byte 1: state (if already active) */ +#define PropertyTableSizeISR ((TRC_CFG_NAME_LEN_ISR) + 2) + +/* TRC_CFG_NTIMER properties: Byte 0: state (unused for now) */ +#define PropertyTableSizeTimer ((TRC_CFG_NAME_LEN_TIMER) + 1) + +/* TRC_CFG_NEVENTGROUP properties: Byte 0-3: state (unused for now)*/ +#define PropertyTableSizeEventGroup ((TRC_CFG_NAME_LEN_EVENTGROUP) + 4) + +/* TRC_CFG_NSTREAMBUFFER properties: Byte 0-3: state (unused for now)*/ +#define PropertyTableSizeStreamBuffer ((TRC_CFG_NAME_LEN_STREAMBUFFER) + 4) + +/* TRC_CFG_NMESSAGEBUFFER properties: Byte 0-3: state (unused for now)*/ +#define PropertyTableSizeMessageBuffer ((TRC_CFG_NAME_LEN_MESSAGEBUFFER) + 4) + + +/* The layout of the byte array representing the Object Property Table */ +#define StartIndexQueue (0) +#define StartIndexSemaphore (StartIndexQueue + (TRC_CFG_NQUEUE) * PropertyTableSizeQueue) +#define StartIndexMutex (StartIndexSemaphore + (TRC_CFG_NSEMAPHORE) * PropertyTableSizeSemaphore) +#define StartIndexTask (StartIndexMutex + (TRC_CFG_NMUTEX) * PropertyTableSizeMutex) +#define StartIndexISR (StartIndexTask + (TRC_CFG_NTASK) * PropertyTableSizeTask) +#define StartIndexTimer (StartIndexISR + (TRC_CFG_NISR) * PropertyTableSizeISR) +#define StartIndexEventGroup (StartIndexTimer + (TRC_CFG_NTIMER) * PropertyTableSizeTimer) +#define StartIndexStreamBuffer (StartIndexEventGroup + (TRC_CFG_NEVENTGROUP) * PropertyTableSizeEventGroup) +#define StartIndexMessageBuffer (StartIndexStreamBuffer + (TRC_CFG_NSTREAMBUFFER) * PropertyTableSizeStreamBuffer) + +/* Number of bytes used by the object table */ +#define TRACE_OBJECT_TABLE_SIZE (StartIndexMessageBuffer + (TRC_CFG_NMESSAGEBUFFER) * PropertyTableSizeMessageBuffer) + +/* Flag to tell the context of tracePEND_FUNC_CALL_FROM_ISR */ +extern int uiInEventGroupSetBitsFromISR; + +/* Initialization of the object property table */ +void vTraceInitObjectPropertyTable(void); + +/* Initialization of the handle mechanism, see e.g, prvTraceGetObjectHandle */ +void vTraceInitObjectHandleStack(void); + +/* Returns the "Not enough handles" error message for the specified object class */ +const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass); + +void* prvTraceGetCurrentTaskHandle(void); + +/****************************************************************************** + * TraceQueueClassTable + * Translates a FreeRTOS QueueType into trace objects classes (TRACE_CLASS_). + * Has one entry for each QueueType, gives TRACE_CLASS ID. + ******************************************************************************/ +extern traceObjectClass TraceQueueClassTable[5]; + + +/*** Event codes for snapshot mode - must match Tracealyzer config files ******/ + +#define NULL_EVENT (0x00UL) + +/******************************************************************************* + * EVENTGROUP_DIV + * + * Miscellaneous events. + ******************************************************************************/ +#define EVENTGROUP_DIV (NULL_EVENT + 1UL) /*0x01*/ +#define DIV_XPS (EVENTGROUP_DIV + 0UL) /*0x01*/ +#define DIV_TASK_READY (EVENTGROUP_DIV + 1UL) /*0x02*/ +#define DIV_NEW_TIME (EVENTGROUP_DIV + 2UL) /*0x03*/ + +/******************************************************************************* + * EVENTGROUP_TS + * + * Events for storing task-switches and interrupts. The RESUME events are + * generated if the task/interrupt is already marked active. + ******************************************************************************/ +#define EVENTGROUP_TS (EVENTGROUP_DIV + 3UL) /*0x04*/ +#define TS_ISR_BEGIN (EVENTGROUP_TS + 0UL) /*0x04*/ +#define TS_ISR_RESUME (EVENTGROUP_TS + 1UL) /*0x05*/ +#define TS_TASK_BEGIN (EVENTGROUP_TS + 2UL) /*0x06*/ +#define TS_TASK_RESUME (EVENTGROUP_TS + 3UL) /*0x07*/ + +/******************************************************************************* + * EVENTGROUP_OBJCLOSE_NAME + * + * About Close Events + * When an object is evicted from the object property table (object close), two + * internal events are stored (EVENTGROUP_OBJCLOSE_NAME and + * EVENTGROUP_OBJCLOSE_PROP), containing the handle-name mapping and object + * properties valid up to this point. + ******************************************************************************/ +#define EVENTGROUP_OBJCLOSE_NAME_TRCSUCCESS (EVENTGROUP_TS + 4UL) /*0x08*/ + +/******************************************************************************* + * EVENTGROUP_OBJCLOSE_PROP + * + * The internal event carrying properties of deleted objects + * The handle and object class of the closed object is not stored in this event, + * but is assumed to be the same as in the preceding CLOSE event. Thus, these + * two events must be generated from within a critical section. + * When queues are closed, arg1 is the "state" property (i.e., number of + * buffered messages/signals). + * When actors are closed, arg1 is priority, arg2 is handle of the "instance + * finish" event, and arg3 is event code of the "instance finish" event. + * In this case, the lower three bits is the object class of the instance finish + * handle. The lower three bits are not used (always zero) when queues are + * closed since the queue type is given in the previous OBJCLOSE_NAME event. + ******************************************************************************/ +#define EVENTGROUP_OBJCLOSE_PROP_TRCSUCCESS (EVENTGROUP_OBJCLOSE_NAME_TRCSUCCESS + 8UL) /*0x10*/ + +/******************************************************************************* + * EVENTGROUP_CREATE + * + * The events in this group are used to log Kernel object creations. + * The lower three bits in the event code gives the object class, i.e., type of + * create operation (task, queue, semaphore, etc). + ******************************************************************************/ +#define EVENTGROUP_CREATE_OBJ_TRCSUCCESS (EVENTGROUP_OBJCLOSE_PROP_TRCSUCCESS + 8UL) /*0x18*/ + +/******************************************************************************* + * EVENTGROUP_SEND + * + * The events in this group are used to log Send/Give events on queues, + * semaphores and mutexes The lower three bits in the event code gives the + * object class, i.e., what type of object that is operated on (queue, semaphore + * or mutex). + ******************************************************************************/ +#define EVENTGROUP_SEND_TRCSUCCESS (EVENTGROUP_CREATE_OBJ_TRCSUCCESS + 8UL) /*0x20*/ + +/******************************************************************************* + * EVENTGROUP_RECEIVE + * + * The events in this group are used to log Receive/Take events on queues, + * semaphores and mutexes. The lower three bits in the event code gives the + * object class, i.e., what type of object that is operated on (queue, semaphore + * or mutex). + ******************************************************************************/ +#define EVENTGROUP_RECEIVE_TRCSUCCESS (EVENTGROUP_SEND_TRCSUCCESS + 8UL) /*0x28*/ + +/* Send/Give operations, from ISR */ +#define EVENTGROUP_SEND_FROM_ISR_TRCSUCCESS \ + (EVENTGROUP_RECEIVE_TRCSUCCESS + 8UL) /*0x30*/ + +/* Receive/Take operations, from ISR */ +#define EVENTGROUP_RECEIVE_FROM_ISR_TRCSUCCESS \ + (EVENTGROUP_SEND_FROM_ISR_TRCSUCCESS + 8UL) /*0x38*/ + +/* "Failed" event type versions of above (timeout, failed allocation, etc) */ +#define EVENTGROUP_KSE_TRCFAILED \ + (EVENTGROUP_RECEIVE_FROM_ISR_TRCSUCCESS + 8UL) /*0x40*/ + +/* Failed create calls - memory allocation failed */ +#define EVENTGROUP_CREATE_OBJ_TRCFAILED (EVENTGROUP_KSE_TRCFAILED) /*0x40*/ + +/* Failed send/give - timeout! */ +#define EVENTGROUP_SEND_TRCFAILED (EVENTGROUP_CREATE_OBJ_TRCFAILED + 8UL) /*0x48*/ + +/* Failed receive/take - timeout! */ +#define EVENTGROUP_RECEIVE_TRCFAILED (EVENTGROUP_SEND_TRCFAILED + 8UL) /*0x50*/ + +/* Failed non-blocking send/give - queue full */ +#define EVENTGROUP_SEND_FROM_ISR_TRCFAILED (EVENTGROUP_RECEIVE_TRCFAILED + 8UL) /*0x58*/ + +/* Failed non-blocking receive/take - queue empty */ +#define EVENTGROUP_RECEIVE_FROM_ISR_TRCFAILED \ + (EVENTGROUP_SEND_FROM_ISR_TRCFAILED + 8UL) /*0x60*/ + +/* Events when blocking on receive/take */ +#define EVENTGROUP_RECEIVE_TRCBLOCK \ + (EVENTGROUP_RECEIVE_FROM_ISR_TRCFAILED + 8UL) /*0x68*/ + +/* Events when blocking on send/give */ +#define EVENTGROUP_SEND_TRCBLOCK (EVENTGROUP_RECEIVE_TRCBLOCK + 8UL) /*0x70*/ + +/* Events on queue peek (receive) */ +#define EVENTGROUP_PEEK_TRCSUCCESS (EVENTGROUP_SEND_TRCBLOCK + 8UL) /*0x78*/ + +/* Events on object delete (vTaskDelete or vQueueDelete) */ +#define EVENTGROUP_DELETE_OBJ_TRCSUCCESS (EVENTGROUP_PEEK_TRCSUCCESS + 8UL) /*0x80*/ + +/* Other events - object class is implied: TASK */ +#define EVENTGROUP_OTHERS (EVENTGROUP_DELETE_OBJ_TRCSUCCESS + 8UL) /*0x88*/ +#define TASK_DELAY_UNTIL (EVENTGROUP_OTHERS + 0UL) /*0x88*/ +#define TASK_DELAY (EVENTGROUP_OTHERS + 1UL) /*0x89*/ +#define TASK_SUSPEND (EVENTGROUP_OTHERS + 2UL) /*0x8A*/ +#define TASK_RESUME (EVENTGROUP_OTHERS + 3UL) /*0x8B*/ +#define TASK_RESUME_FROM_ISR (EVENTGROUP_OTHERS + 4UL) /*0x8C*/ +#define TASK_PRIORITY_SET (EVENTGROUP_OTHERS + 5UL) /*0x8D*/ +#define TASK_PRIORITY_INHERIT (EVENTGROUP_OTHERS + 6UL) /*0x8E*/ +#define TASK_PRIORITY_DISINHERIT (EVENTGROUP_OTHERS + 7UL) /*0x8F*/ + +#define EVENTGROUP_MISC_PLACEHOLDER (EVENTGROUP_OTHERS + 8UL) /*0x90*/ +#define PEND_FUNC_CALL (EVENTGROUP_MISC_PLACEHOLDER+0UL) /*0x90*/ +#define PEND_FUNC_CALL_FROM_ISR (EVENTGROUP_MISC_PLACEHOLDER+1UL) /*0x91*/ +#define PEND_FUNC_CALL_TRCFAILED (EVENTGROUP_MISC_PLACEHOLDER+2UL) /*0x92*/ +#define PEND_FUNC_CALL_FROM_ISR_TRCFAILED (EVENTGROUP_MISC_PLACEHOLDER+3UL) /*0x93*/ +#define MEM_MALLOC_SIZE (EVENTGROUP_MISC_PLACEHOLDER+4UL) /*0x94*/ +#define MEM_MALLOC_ADDR (EVENTGROUP_MISC_PLACEHOLDER+5UL) /*0x95*/ +#define MEM_FREE_SIZE (EVENTGROUP_MISC_PLACEHOLDER+6UL) /*0x96*/ +#define MEM_FREE_ADDR (EVENTGROUP_MISC_PLACEHOLDER+7UL) /*0x97*/ + +/* User events */ +#define EVENTGROUP_USEREVENT (EVENTGROUP_MISC_PLACEHOLDER + 8UL) /*0x98*/ +#define USER_EVENT (EVENTGROUP_USEREVENT + 0UL) + +/* Allow for 0-15 arguments (the number of args is added to event code) */ +#define USER_EVENT_LAST (EVENTGROUP_USEREVENT + 15UL) /*0xA7*/ + +/******************************************************************************* + * XTS Event - eXtended TimeStamp events + * The timestamps used in the recorder are "differential timestamps" (DTS), i.e. + * the time since the last stored event. The DTS fields are either 1 or 2 bytes + * in the other events, depending on the bytes available in the event struct. + * If the time since the last event (the DTS) is larger than allowed for by + * the DTS field of the current event, an XTS event is inserted immediately + * before the original event. The XTS event contains up to 3 additional bytes + * of the DTS value - the higher bytes of the true DTS value. The lower 1-2 + * bytes are stored in the normal DTS field. + * There are two types of XTS events, XTS8 and XTS16. An XTS8 event is stored + * when there is only room for 1 byte (8 bit) DTS data in the original event, + * which means a limit of 0xFF (255UL). The XTS16 is used when the original event + * has a 16 bit DTS field and thereby can handle values up to 0xFFFF (65535UL). + * + * Using a very high frequency time base can result in many XTS events. + * Preferably, the time between two OS ticks should fit in 16 bits, i.e., + * at most 65535. If your time base has a higher frequency, you can define + * the TRACE + ******************************************************************************/ + +#define EVENTGROUP_SYS (EVENTGROUP_USEREVENT + 16UL) /*0xA8*/ +#define XTS8 (EVENTGROUP_SYS + 0UL) /*0xA8*/ +#define XTS16 (EVENTGROUP_SYS + 1UL) /*0xA9*/ +#define EVENT_BEING_WRITTEN (EVENTGROUP_SYS + 2UL) /*0xAA*/ +#define RESERVED_DUMMY_CODE (EVENTGROUP_SYS + 3UL) /*0xAB*/ +#define LOW_POWER_BEGIN (EVENTGROUP_SYS + 4UL) /*0xAC*/ +#define LOW_POWER_END (EVENTGROUP_SYS + 5UL) /*0xAD*/ +#define XID (EVENTGROUP_SYS + 6UL) /*0xAE*/ +#define XTS16L (EVENTGROUP_SYS + 7UL) /*0xAF*/ + +#define EVENTGROUP_TIMER (EVENTGROUP_SYS + 8UL) /*0xB0*/ +#define TIMER_CREATE (EVENTGROUP_TIMER + 0UL) /*0xB0*/ +#define TIMER_START (EVENTGROUP_TIMER + 1UL) /*0xB1*/ +#define TIMER_RST (EVENTGROUP_TIMER + 2UL) /*0xB2*/ +#define TIMER_STOP (EVENTGROUP_TIMER + 3UL) /*0xB3*/ +#define TIMER_CHANGE_PERIOD (EVENTGROUP_TIMER + 4UL) /*0xB4*/ +#define TIMER_DELETE_OBJ (EVENTGROUP_TIMER + 5UL) /*0xB5*/ +#define TIMER_START_FROM_ISR (EVENTGROUP_TIMER + 6UL) /*0xB6*/ +#define TIMER_RESET_FROM_ISR (EVENTGROUP_TIMER + 7UL) /*0xB7*/ +#define TIMER_STOP_FROM_ISR (EVENTGROUP_TIMER + 8UL) /*0xB8*/ + +#define TIMER_CREATE_TRCFAILED (EVENTGROUP_TIMER + 9UL) /*0xB9*/ +#define TIMER_START_TRCFAILED (EVENTGROUP_TIMER + 10UL) /*0xBA*/ +#define TIMER_RESET_TRCFAILED (EVENTGROUP_TIMER + 11UL) /*0xBB*/ +#define TIMER_STOP_TRCFAILED (EVENTGROUP_TIMER + 12UL) /*0xBC*/ +#define TIMER_CHANGE_PERIOD_TRCFAILED (EVENTGROUP_TIMER + 13UL) /*0xBD*/ +#define TIMER_DELETE_TRCFAILED (EVENTGROUP_TIMER + 14UL) /*0xBE*/ +#define TIMER_START_FROM_ISR_TRCFAILED (EVENTGROUP_TIMER + 15UL) /*0xBF*/ +#define TIMER_RESET_FROM_ISR_TRCFAILED (EVENTGROUP_TIMER + 16UL) /*0xC0*/ +#define TIMER_STOP_FROM_ISR_TRCFAILED (EVENTGROUP_TIMER + 17UL) /*0xC1*/ + +#define EVENTGROUP_EG (EVENTGROUP_TIMER + 18UL) /*0xC2*/ +#define EVENT_GROUP_CREATE (EVENTGROUP_EG + 0UL) /*0xC2*/ +#define EVENT_GROUP_CREATE_TRCFAILED (EVENTGROUP_EG + 1UL) /*0xC3*/ +#define EVENT_GROUP_SYNC_TRCBLOCK (EVENTGROUP_EG + 2UL) /*0xC4*/ +#define EVENT_GROUP_SYNC_END (EVENTGROUP_EG + 3UL) /*0xC5*/ +#define EVENT_GROUP_WAIT_BITS_TRCBLOCK (EVENTGROUP_EG + 4UL) /*0xC6*/ +#define EVENT_GROUP_WAIT_BITS_END (EVENTGROUP_EG + 5UL) /*0xC7*/ +#define EVENT_GROUP_CLEAR_BITS (EVENTGROUP_EG + 6UL) /*0xC8*/ +#define EVENT_GROUP_CLEAR_BITS_FROM_ISR (EVENTGROUP_EG + 7UL) /*0xC9*/ +#define EVENT_GROUP_SET_BITS (EVENTGROUP_EG + 8UL) /*0xCA*/ +#define EVENT_GROUP_DELETE_OBJ (EVENTGROUP_EG + 9UL) /*0xCB*/ +#define EVENT_GROUP_SYNC_END_TRCFAILED (EVENTGROUP_EG + 10UL) /*0xCC*/ +#define EVENT_GROUP_WAIT_BITS_END_TRCFAILED (EVENTGROUP_EG + 11UL) /*0xCD*/ +#define EVENT_GROUP_SET_BITS_FROM_ISR (EVENTGROUP_EG + 12UL) /*0xCE*/ +#define EVENT_GROUP_SET_BITS_FROM_ISR_TRCFAILED (EVENTGROUP_EG + 13UL) /*0xCF*/ + +#define TASK_INSTANCE_FINISHED_NEXT_KSE (EVENTGROUP_EG + 14UL) /*0xD0*/ +#define TASK_INSTANCE_FINISHED_DIRECT (EVENTGROUP_EG + 15UL) /*0xD1*/ + +#define TRACE_TASK_NOTIFY_GROUP (EVENTGROUP_EG + 16UL) /*0xD2*/ +#define TRACE_TASK_NOTIFY (TRACE_TASK_NOTIFY_GROUP + 0UL) /*0xD2*/ +#define TRACE_TASK_NOTIFY_TAKE (TRACE_TASK_NOTIFY_GROUP + 1UL) /*0xD3*/ +#define TRACE_TASK_NOTIFY_TAKE_TRCBLOCK (TRACE_TASK_NOTIFY_GROUP + 2UL) /*0xD4*/ +#define TRACE_TASK_NOTIFY_TAKE_TRCFAILED (TRACE_TASK_NOTIFY_GROUP + 3UL) /*0xD5*/ +#define TRACE_TASK_NOTIFY_WAIT (TRACE_TASK_NOTIFY_GROUP + 4UL) /*0xD6*/ +#define TRACE_TASK_NOTIFY_WAIT_TRCBLOCK (TRACE_TASK_NOTIFY_GROUP + 5UL) /*0xD7*/ +#define TRACE_TASK_NOTIFY_WAIT_TRCFAILED (TRACE_TASK_NOTIFY_GROUP + 6UL) /*0xD8*/ +#define TRACE_TASK_NOTIFY_FROM_ISR (TRACE_TASK_NOTIFY_GROUP + 7UL) /*0xD9*/ +#define TRACE_TASK_NOTIFY_GIVE_FROM_ISR (TRACE_TASK_NOTIFY_GROUP + 8UL) /*0xDA*/ + +#define TIMER_EXPIRED (TRACE_TASK_NOTIFY_GROUP + 9UL) /* 0xDB */ + + /* Events on queue peek (receive) */ +#define EVENTGROUP_PEEK_TRCBLOCK (TRACE_TASK_NOTIFY_GROUP + 10UL) /*0xDC*/ +/* peek block on queue: 0xDC */ +/* peek block on semaphore: 0xDD */ +/* peek block on mutex: 0xDE */ + +/* Events on queue peek (receive) */ +#define EVENTGROUP_PEEK_TRCFAILED (EVENTGROUP_PEEK_TRCBLOCK + 3UL) /*0xDF*/ +/* peek failed on queue: 0xDF */ +/* peek failed on semaphore: 0xE0 */ +/* peek failed on mutex: 0xE1 */ + +#define EVENTGROUP_STREAMBUFFER_DIV (EVENTGROUP_PEEK_TRCFAILED + 3UL) /*0xE2*/ +#define TRACE_STREAMBUFFER_RESET (EVENTGROUP_STREAMBUFFER_DIV + 0) /*0xE2*/ +#define TRACE_MESSAGEBUFFER_RESET (EVENTGROUP_STREAMBUFFER_DIV + 1UL) /*0xE3*/ +#define TRACE_STREAMBUFFER_OBJCLOSE_NAME_TRCSUCCESS (EVENTGROUP_STREAMBUFFER_DIV + 2UL) /*0xE4*/ +#define TRACE_MESSAGEBUFFER_OBJCLOSE_NAME_TRCSUCCESS (EVENTGROUP_STREAMBUFFER_DIV + 3UL) /*0xE5*/ +#define TRACE_STREAMBUFFER_OBJCLOSE_PROP_TRCSUCCESS (EVENTGROUP_STREAMBUFFER_DIV + 4UL) /*0xE6*/ +#define TRACE_MESSAGEBUFFER_OBJCLOSE_PROP_TRCSUCCESS (EVENTGROUP_STREAMBUFFER_DIV + 5UL) /*0xE7*/ + +/* The following are using previously "lost" event codes */ +#define TRACE_STREAMBUFFER_CREATE_OBJ_TRCSUCCESS (EVENTGROUP_CREATE_OBJ_TRCSUCCESS + 4UL) /*0x1C*/ +#define TRACE_STREAMBUFFER_CREATE_OBJ_TRCFAILED (EVENTGROUP_CREATE_OBJ_TRCFAILED + 4UL) /*0x44*/ +#define TRACE_STREAMBUFFER_DELETE_OBJ_TRCSUCCESS (EVENTGROUP_DELETE_OBJ_TRCSUCCESS + 4UL) /*0x84*/ +#define TRACE_STREAMBUFFER_SEND_TRCSUCCESS (EVENTGROUP_SEND_TRCSUCCESS + 3UL) /*0x23*/ +#define TRACE_STREAMBUFFER_SEND_TRCBLOCK (EVENTGROUP_SEND_TRCBLOCK + 3UL) /*0x73*/ +#define TRACE_STREAMBUFFER_SEND_TRCFAILED (EVENTGROUP_SEND_TRCFAILED + 3UL) /*0x4B*/ +#define TRACE_STREAMBUFFER_RECEIVE_TRCSUCCESS (EVENTGROUP_RECEIVE_TRCSUCCESS + 3UL) /*0x2B*/ +#define TRACE_STREAMBUFFER_RECEIVE_TRCBLOCK (EVENTGROUP_RECEIVE_TRCBLOCK + 3UL) /*0x6B*/ +#define TRACE_STREAMBUFFER_RECEIVE_TRCFAILED (EVENTGROUP_RECEIVE_TRCFAILED + 3UL) /*0x53*/ +#define TRACE_STREAMBUFFER_SEND_FROM_ISR_TRCSUCCESS (EVENTGROUP_SEND_FROM_ISR_TRCSUCCESS + 3UL) /*0x33*/ +#define TRACE_STREAMBUFFER_SEND_FROM_ISR_TRCFAILED (EVENTGROUP_SEND_FROM_ISR_TRCFAILED + 3UL) /*0x5B*/ +#define TRACE_STREAMBUFFER_RECEIVE_FROM_ISR_TRCSUCCESS (EVENTGROUP_RECEIVE_FROM_ISR_TRCSUCCESS + 3UL) /*0x3B*/ +#define TRACE_STREAMBUFFER_RECEIVE_FROM_ISR_TRCFAILED (EVENTGROUP_RECEIVE_FROM_ISR_TRCFAILED + 3UL) /*0x63*/ + +/* The following are using previously "lost" event codes. These macros aren't even directly referenced, instead we do (equivalent STREAMBUFFER code) + 1. */ +#define TRACE_MESSAGEBUFFER_CREATE_OBJ_TRCSUCCESS (EVENTGROUP_CREATE_OBJ_TRCSUCCESS + 5UL) /*0x1D*/ +#define TRACE_MESSAGEBUFFER_CREATE_OBJ_TRCFAILED (EVENTGROUP_CREATE_OBJ_TRCFAILED + 5UL) /*0x45*/ +#define TRACE_MESSAGEBUFFER_DELETE_OBJ_TRCSUCCESS (EVENTGROUP_DELETE_OBJ_TRCSUCCESS + 5UL) /*0x85*/ +#define TRACE_MESSAGEBUFFER_SEND_TRCSUCCESS (EVENTGROUP_SEND_TRCSUCCESS + 4UL) /*0x24*/ +#define TRACE_MESSAGEBUFFER_SEND_TRCBLOCK (EVENTGROUP_SEND_TRCBLOCK + 4UL) /*0x74*/ +#define TRACE_MESSAGEBUFFER_SEND_TRCFAILED (EVENTGROUP_SEND_TRCFAILED + 4UL) /*0x4C*/ +#define TRACE_MESSAGEBUFFER_RECEIVE_TRCSUCCESS (EVENTGROUP_RECEIVE_TRCSUCCESS + 4UL) /*0x2C*/ +#define TRACE_MESSAGEBUFFER_RECEIVE_TRCBLOCK (EVENTGROUP_RECEIVE_TRCBLOCK + 4UL) /*0x6C*/ +#define TRACE_MESSAGEBUFFER_RECEIVE_TRCFAILED (EVENTGROUP_RECEIVE_TRCFAILED + 4UL) /*0x54*/ +#define TRACE_MESSAGEBUFFER_SEND_FROM_ISR_TRCSUCCESS (EVENTGROUP_SEND_FROM_ISR_TRCSUCCESS + 4UL) /*0x34*/ +#define TRACE_MESSAGEBUFFER_SEND_FROM_ISR_TRCFAILED (EVENTGROUP_SEND_FROM_ISR_TRCFAILED + 4UL) /*0x5C*/ +#define TRACE_MESSAGEBUFFER_RECEIVE_FROM_ISR_TRCSUCCESS (EVENTGROUP_RECEIVE_FROM_ISR_TRCSUCCESS + 4UL) /*0x3C*/ +#define TRACE_MESSAGEBUFFER_RECEIVE_FROM_ISR_TRCFAILED (EVENTGROUP_RECEIVE_FROM_ISR_TRCFAILED + 4UL) /*0x64*/ + +/* LAST EVENT (0xE7) */ + +/**************************** +* MACROS TO GET TRACE CLASS * +****************************/ +#define TRACE_GET_TRACE_CLASS_FROM_TASK_CLASS(kernelClass) (TRACE_CLASS_TASK) +#define TRACE_GET_TRACE_CLASS_FROM_TASK_OBJECT(pxObject) (TRACE_CLASS_TASK) + +#define TRACE_GET_TRACE_CLASS_FROM_QUEUE_CLASS(kernelClass) TraceQueueClassTable[kernelClass] +#define TRACE_GET_TRACE_CLASS_FROM_QUEUE_OBJECT(pxObject) TRACE_GET_TRACE_CLASS_FROM_QUEUE_CLASS(prvTraceGetQueueType(pxObject)) + +#define TRACE_GET_TRACE_CLASS_FROM_TIMER_CLASS(kernelClass) (TRACE_CLASS_TIMER) +#define TRACE_GET_TRACE_CLASS_FROM_TIMER_OBJECT(pxObject) (TRACE_CLASS_TIMER) + +#define TRACE_GET_TRACE_CLASS_FROM_EVENTGROUP_CLASS(kernelClass) (TRACE_CLASS_EVENTGROUP) +#define TRACE_GET_TRACE_CLASS_FROM_EVENTGROUP_OBJECT(pxObject) (TRACE_CLASS_EVENTGROUP) + +/* TRACE_GET_TRACE_CLASS_FROM_STREAMBUFFER_CLASS can only be accessed with a parameter indicating if it is a MessageBuffer */ +#define TRACE_GET_TRACE_CLASS_FROM_STREAMBUFFER_CLASS(xIsMessageBuffer) (xIsMessageBuffer == 1 ? TRACE_CLASS_MESSAGEBUFFER : TRACE_CLASS_STREAMBUFFER) +#define TRACE_GET_TRACE_CLASS_FROM_STREAMBUFFER_OBJECT(pxObject) (prvGetStreamBufferType(pxObject) == 1 ? TRACE_CLASS_MESSAGEBUFFER : TRACE_CLASS_STREAMBUFFER) + +/* Generic versions */ +#define TRACE_GET_CLASS_TRACE_CLASS(CLASS, kernelClass) TRACE_GET_TRACE_CLASS_FROM_##CLASS##_CLASS(kernelClass) +#define TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject) TRACE_GET_TRACE_CLASS_FROM_##CLASS##_OBJECT(pxObject) + +/****************************** +* MACROS TO GET OBJECT NUMBER * +******************************/ +#define TRACE_GET_TASK_NUMBER(pxTCB) (traceHandle)(prvTraceGetTaskNumberLow16(pxTCB)) +#define TRACE_SET_TASK_NUMBER(pxTCB) prvTraceSetTaskNumberLow16(pxTCB, prvTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(TASK, pxTCB))); + +#define TRACE_GET_QUEUE_NUMBER(queue) ( ( traceHandle ) prvTraceGetQueueNumberLow16(queue) ) +#define TRACE_SET_QUEUE_NUMBER(queue) prvTraceSetQueueNumberLow16(queue, (uint16_t)prvTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(QUEUE, queue))); + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +#define TRACE_GET_TIMER_NUMBER(tmr) ( ( traceHandle ) prvTraceGetTimerNumberLow16(tmr) ) +#define TRACE_SET_TIMER_NUMBER(tmr) prvTraceSetTimerNumberLow16(tmr, (uint16_t)prvTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(TIMER, tmr))); +#else /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ +#define TRACE_GET_TIMER_NUMBER(tmr) ( ( traceHandle ) ((Timer_t*)tmr)->uxTimerNumber ) +#define TRACE_SET_TIMER_NUMBER(tmr) ((Timer_t*)tmr)->uxTimerNumber = prvTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(TIMER, tmr)); +#endif /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +#define TRACE_GET_EVENTGROUP_NUMBER(eg) ( ( traceHandle ) prvTraceGetEventGroupNumberLow16(eg) ) +#define TRACE_SET_EVENTGROUP_NUMBER(eg) prvTraceSetEventGroupNumberLow16(eg, (uint16_t)prvTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(EVENTGROUP, eg))); +#else /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ +#define TRACE_GET_EVENTGROUP_NUMBER(eg) ( ( traceHandle ) uxEventGroupGetNumber(eg) ) +#define TRACE_SET_EVENTGROUP_NUMBER(eg) ((EventGroup_t*)eg)->uxEventGroupNumber = prvTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(EVENTGROUP, eg)); +#endif /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + + +#define TRACE_GET_STREAMBUFFER_NUMBER(sb) ( ( traceHandle ) prvTraceGetStreamBufferNumberLow16(sb) ) +#define TRACE_SET_STREAMBUFFER_NUMBER(sb) prvTraceSetStreamBufferNumberLow16(sb, (uint16_t)prvTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(STREAMBUFFER, sb))); + +/* Generic versions */ +#define TRACE_GET_OBJECT_NUMBER(CLASS, pxObject) TRACE_GET_##CLASS##_NUMBER(pxObject) +#define TRACE_SET_OBJECT_NUMBER(CLASS, pxObject) TRACE_SET_##CLASS##_NUMBER(pxObject) + +/****************************** +* MACROS TO GET EVENT CODES * +******************************/ +#define TRACE_GET_TASK_CLASS_EVENT_CODE(SERVICE, RESULT, kernelClass) (uint8_t)(EVENTGROUP_##SERVICE##_##RESULT + TRACE_GET_CLASS_TRACE_CLASS(TASK, kernelClass)) +#define TRACE_GET_QUEUE_CLASS_EVENT_CODE(SERVICE, RESULT, kernelClass) (uint8_t)(EVENTGROUP_##SERVICE##_##RESULT + TRACE_GET_CLASS_TRACE_CLASS(QUEUE, kernelClass)) +#define TRACE_GET_TIMER_CLASS_EVENT_CODE(SERVICE, RESULT, kernelClass) -- THIS IS NOT USED -- +#define TRACE_GET_EVENTGROUP_CLASS_EVENT_CODE(SERVICE, RESULT, kernelClass) -- THIS IS NOT USED -- +#define TRACE_GET_STREAMBUFFER_CLASS_EVENT_CODE(SERVICE, RESULT, isMessageBuffer) (uint8_t)(TRACE_STREAMBUFFER_##SERVICE##_##RESULT + (uint8_t)isMessageBuffer) + +#define TRACE_GET_TASK_OBJECT_EVENT_CODE(SERVICE, RESULT, pxTCB) (uint8_t)(EVENTGROUP_##SERVICE##_##RESULT + TRACE_CLASS_TASK) +#define TRACE_GET_QUEUE_OBJECT_EVENT_CODE(SERVICE, RESULT, pxObject) (uint8_t)(EVENTGROUP_##SERVICE##_##RESULT + TRACE_GET_OBJECT_TRACE_CLASS(QUEUE, pxObject)) +#define TRACE_GET_TIMER_OBJECT_EVENT_CODE(SERVICE, RESULT, UNUSED) -- THIS IS NOT USED -- +#define TRACE_GET_EVENTGROUP_OBJECT_EVENT_CODE(SERVICE, RESULT, UNUSED) -- THIS IS NOT USED -- +#define TRACE_GET_STREAMBUFFER_OBJECT_EVENT_CODE(SERVICE, RESULT, pxObject) (uint8_t)(TRACE_STREAMBUFFER_##SERVICE##_##RESULT + prvGetStreamBufferType(pxObject)) + +/* Generic versions */ +#define TRACE_GET_CLASS_EVENT_CODE(SERVICE, RESULT, CLASS, kernelClass) TRACE_GET_##CLASS##_CLASS_EVENT_CODE(SERVICE, RESULT, kernelClass) +#define TRACE_GET_OBJECT_EVENT_CODE(SERVICE, RESULT, CLASS, pxObject) TRACE_GET_##CLASS##_OBJECT_EVENT_CODE(SERVICE, RESULT, pxObject) + +/****************************** +* SPECIAL MACROS FOR TASKS * +******************************/ +#define TRACE_GET_TASK_PRIORITY(pxTCB) ((uint8_t)pxTCB->uxPriority) +#define TRACE_GET_TASK_NAME(pxTCB) ((char*)pxTCB->pcTaskName) + +/*** The trace macros for snapshot mode **************************************/ + +/* A macro that will update the tick count when returning from tickless idle */ +#undef traceINCREASE_TICK_COUNT +#define traceINCREASE_TICK_COUNT( xCount ) + +/* Called for each task that becomes ready */ +#undef traceMOVED_TASK_TO_READY_STATE +#define traceMOVED_TASK_TO_READY_STATE( pxTCB ) \ + trcKERNEL_HOOKS_MOVED_TASK_TO_READY_STATE(pxTCB); + +/* Called on each OS tick. Will call uiPortGetTimestamp to make sure it is called at least once every OS tick. */ +#undef traceTASK_INCREMENT_TICK + +#if (TRC_CFG_FREERTOS_VERSION <= TRC_FREERTOS_VERSION_7_4) + +#define traceTASK_INCREMENT_TICK( xTickCount ) \ + if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdTRUE || uxMissedTicks == 0) { trcKERNEL_HOOKS_INCREMENT_TICK(); } \ + if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE) { trcKERNEL_HOOKS_NEW_TIME(DIV_NEW_TIME, xTickCount + 1); } + +#else + +#define traceTASK_INCREMENT_TICK( xTickCount ) \ + if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdTRUE || xPendedTicks == 0) { trcKERNEL_HOOKS_INCREMENT_TICK(); } \ + if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE) { trcKERNEL_HOOKS_NEW_TIME(DIV_NEW_TIME, xTickCount + 1); } + +#endif + +/* Called on each task-switch */ +#undef traceTASK_SWITCHED_IN +#define traceTASK_SWITCHED_IN() \ + trcKERNEL_HOOKS_TASK_SWITCH(TRACE_GET_CURRENT_TASK()); + +/* Called on vTaskCreate */ +#undef traceTASK_CREATE +#define traceTASK_CREATE(pxNewTCB) \ + if (pxNewTCB != NULL) \ + { \ + trcKERNEL_HOOKS_TASK_CREATE(TRACE_GET_OBJECT_EVENT_CODE(CREATE_OBJ, TRCSUCCESS, TASK, pxNewTCB), TASK, pxNewTCB); \ + } + +/* Called in vTaskCreate, if it fails (typically if the stack can not be allocated) */ +#undef traceTASK_CREATE_FAILED +#define traceTASK_CREATE_FAILED() \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY(TRACE_GET_CLASS_EVENT_CODE(CREATE_OBJ, TRCFAILED, TASK, NOT_USED), 0); + +/* Called on vTaskDelete */ +#undef traceTASK_DELETE +#define traceTASK_DELETE( pxTaskToDelete ) \ + { TRACE_ALLOC_CRITICAL_SECTION(); \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_TASK_DELETE(TRACE_GET_OBJECT_EVENT_CODE(DELETE_OBJ, TRCSUCCESS, TASK, pxTaskToDelete), TRACE_GET_OBJECT_EVENT_CODE(OBJCLOSE_NAME, TRCSUCCESS, TASK, pxTaskToDelete), TRACE_GET_OBJECT_EVENT_CODE(OBJCLOSE_PROP, TRCSUCCESS, TASK, pxTaskToDelete), pxTaskToDelete); \ + TRACE_EXIT_CRITICAL_SECTION(); } + +#if (TRC_CFG_SCHEDULING_ONLY == 0) + +#if defined(configUSE_TICKLESS_IDLE) +#if (configUSE_TICKLESS_IDLE != 0) + +#undef traceLOW_POWER_IDLE_BEGIN +#define traceLOW_POWER_IDLE_BEGIN() \ + { \ + extern uint32_t trace_disable_timestamp; \ + prvTraceStoreLowPower(0); \ + trace_disable_timestamp = 1; \ + } + +#undef traceLOW_POWER_IDLE_END +#define traceLOW_POWER_IDLE_END() \ + { \ + extern uint32_t trace_disable_timestamp; \ + trace_disable_timestamp = 0; \ + prvTraceStoreLowPower(1); \ + } + +#endif /* (configUSE_TICKLESS_IDLE != 0) */ +#endif /* defined(configUSE_TICKLESS_IDLE) */ + +/* Called on vTaskSuspend */ +#undef traceTASK_SUSPEND +#define traceTASK_SUSPEND( pxTaskToSuspend ) \ + trcKERNEL_HOOKS_TASK_SUSPEND(TASK_SUSPEND, pxTaskToSuspend); + +/* Called from special case with timer only */ +#undef traceTASK_DELAY_SUSPEND +#define traceTASK_DELAY_SUSPEND( pxTaskToSuspend ) \ + trcKERNEL_HOOKS_TASK_SUSPEND(TASK_SUSPEND, pxTaskToSuspend); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); + +/* Called on vTaskDelay - note the use of FreeRTOS variable xTicksToDelay */ +#undef traceTASK_DELAY +#define traceTASK_DELAY() \ + trcKERNEL_HOOKS_TASK_DELAY(TASK_DELAY, pxCurrentTCB, xTicksToDelay); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); + +/* Called on vTaskDelayUntil - note the use of FreeRTOS variable xTimeToWake */ +#undef traceTASK_DELAY_UNTIL +#if TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 +#define traceTASK_DELAY_UNTIL(xTimeToWake) \ + trcKERNEL_HOOKS_TASK_DELAY(TASK_DELAY_UNTIL, pxCurrentTCB, xTimeToWake); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); +#else /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ +#define traceTASK_DELAY_UNTIL() \ + trcKERNEL_HOOKS_TASK_DELAY(TASK_DELAY_UNTIL, pxCurrentTCB, xTimeToWake); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ + +/* Called in xQueueCreate, and thereby for all other object based on queues, such as semaphores. */ +#undef traceQUEUE_CREATE +#define traceQUEUE_CREATE( pxNewQueue ) \ + trcKERNEL_HOOKS_OBJECT_CREATE(TRACE_GET_OBJECT_EVENT_CODE(CREATE_OBJ, TRCSUCCESS, QUEUE, pxNewQueue), QUEUE, pxNewQueue); + +/* Called in xQueueCreate, if the queue creation fails */ +#undef traceQUEUE_CREATE_FAILED +#define traceQUEUE_CREATE_FAILED( queueType ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY(TRACE_GET_CLASS_EVENT_CODE(CREATE_OBJ, TRCFAILED, QUEUE, queueType), 0); + +/* Called on vQueueDelete */ +#undef traceQUEUE_DELETE +#define traceQUEUE_DELETE( pxQueue ) \ + { TRACE_ALLOC_CRITICAL_SECTION(); \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_OBJECT_DELETE(TRACE_GET_OBJECT_EVENT_CODE(DELETE_OBJ, TRCSUCCESS, QUEUE, pxQueue), TRACE_GET_OBJECT_EVENT_CODE(OBJCLOSE_NAME, TRCSUCCESS, QUEUE, pxQueue), TRACE_GET_OBJECT_EVENT_CODE(OBJCLOSE_PROP, TRCSUCCESS, QUEUE, pxQueue), QUEUE, pxQueue); \ + TRACE_EXIT_CRITICAL_SECTION(); } + +/* This macro is not necessary as of FreeRTOS v9.0.0 */ +#if (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) +/* Called in xQueueCreateMutex, and thereby also from xSemaphoreCreateMutex and xSemaphoreCreateRecursiveMutex */ +#undef traceCREATE_MUTEX +#define traceCREATE_MUTEX( pxNewQueue ) \ + trcKERNEL_HOOKS_OBJECT_CREATE(TRACE_GET_OBJECT_EVENT_CODE(CREATE_OBJ, TRCSUCCESS, QUEUE, pxNewQueue), QUEUE, pxNewQueue); + +/* Called in xQueueCreateMutex when the operation fails (when memory allocation fails) */ +#undef traceCREATE_MUTEX_FAILED +#define traceCREATE_MUTEX_FAILED() \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY(TRACE_GET_CLASS_EVENT_CODE(CREATE_OBJ, TRCFAILED, QUEUE, queueQUEUE_TYPE_MUTEX), 0); +#endif /* (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) */ + +/* Called when the Mutex can not be given, since not holder */ +#undef traceGIVE_MUTEX_RECURSIVE_FAILED +#define traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(SEND, TRCFAILED, QUEUE, pxMutex), QUEUE, pxMutex); + +/* Called when a message is sent to a queue */ /* CS IS NEW ! */ +#undef traceQUEUE_SEND +#define traceQUEUE_SEND( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(SEND, TRCSUCCESS, QUEUE, pxQueue), QUEUE, pxQueue); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(QUEUE, pxQueue, TRACE_GET_OBJECT_TRACE_CLASS(QUEUE, pxQueue) == TRACE_CLASS_MUTEX ? (uint8_t)0 : (uint8_t)(pxQueue->uxMessagesWaiting + 1)); + +/* Called when a message failed to be sent to a queue (timeout) */ +#undef traceQUEUE_SEND_FAILED +#define traceQUEUE_SEND_FAILED( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(SEND, TRCFAILED, QUEUE, pxQueue), QUEUE, pxQueue); + +/* Called when the task is blocked due to a send operation on a full queue */ +#undef traceBLOCKING_ON_QUEUE_SEND +#define traceBLOCKING_ON_QUEUE_SEND( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(SEND, TRCBLOCK, QUEUE, pxQueue), QUEUE, pxQueue); + +/* Called when a message is received from a queue */ +#undef traceQUEUE_RECEIVE +#define traceQUEUE_RECEIVE( pxQueue ) \ + if (isQueueReceiveHookActuallyPeek) \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(PEEK, TRCSUCCESS, QUEUE, pxQueue), QUEUE, pxQueue); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE, TRCSUCCESS, QUEUE, pxQueue), QUEUE, pxQueue); \ + } \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(QUEUE, pxQueue, TRACE_GET_OBJECT_TRACE_CLASS(QUEUE, pxQueue) == TRACE_CLASS_MUTEX ? (uint8_t)TRACE_GET_TASK_NUMBER(TRACE_GET_CURRENT_TASK()) : (uint8_t)(pxQueue->uxMessagesWaiting - 1)); + +/* Called when a receive operation on a queue fails (timeout) */ +#undef traceQUEUE_RECEIVE_FAILED +#define traceQUEUE_RECEIVE_FAILED( pxQueue ) \ + if (isQueueReceiveHookActuallyPeek) \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(PEEK, TRCFAILED, QUEUE, pxQueue), QUEUE, pxQueue); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE, TRCFAILED, QUEUE, pxQueue), QUEUE, pxQueue); \ + } + +/* Called when the task is blocked due to a receive operation on an empty queue */ +#undef traceBLOCKING_ON_QUEUE_RECEIVE +#define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ) \ + if (isQueueReceiveHookActuallyPeek) \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(PEEK, TRCBLOCK, QUEUE, pxQueue), QUEUE, pxQueue); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE, TRCBLOCK, QUEUE, pxQueue), QUEUE, pxQueue); \ + } \ + if (TRACE_GET_OBJECT_TRACE_CLASS(QUEUE, pxQueue) != TRACE_CLASS_MUTEX) \ + { \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); \ + } + +/* Called on xQueuePeek */ +#undef traceQUEUE_PEEK +#define traceQUEUE_PEEK( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(PEEK, TRCSUCCESS, QUEUE, pxQueue), QUEUE, pxQueue); + +/* Called on xQueuePeek fail/timeout (added in FreeRTOS v9.0.2) */ +#undef traceQUEUE_PEEK_FAILED +#define traceQUEUE_PEEK_FAILED( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(PEEK, TRCFAILED, QUEUE, pxQueue), QUEUE, pxQueue); + +/* Called on xQueuePeek blocking (added in FreeRTOS v9.0.2) */ +#undef traceBLOCKING_ON_QUEUE_PEEK +#define traceBLOCKING_ON_QUEUE_PEEK( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(PEEK, TRCBLOCK, QUEUE, pxQueue), QUEUE, pxQueue); \ + if (TRACE_GET_OBJECT_TRACE_CLASS(QUEUE, pxQueue) != TRACE_CLASS_MUTEX) \ + { \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); \ + } + +/* Called when a message is sent from interrupt context, e.g., using xQueueSendFromISR */ +#undef traceQUEUE_SEND_FROM_ISR +#define traceQUEUE_SEND_FROM_ISR( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(SEND_FROM_ISR, TRCSUCCESS, QUEUE, pxQueue), QUEUE, pxQueue); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(QUEUE, pxQueue, (uint8_t)(pxQueue->uxMessagesWaiting + 1)); + +/* Called when a message send from interrupt context fails (since the queue was full) */ +#undef traceQUEUE_SEND_FROM_ISR_FAILED +#define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(SEND_FROM_ISR, TRCFAILED, QUEUE, pxQueue), QUEUE, pxQueue); + +/* Called when a message is received in interrupt context, e.g., using xQueueReceiveFromISR */ +#undef traceQUEUE_RECEIVE_FROM_ISR +#define traceQUEUE_RECEIVE_FROM_ISR( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE_FROM_ISR, TRCSUCCESS, QUEUE, pxQueue), QUEUE, pxQueue); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(QUEUE, pxQueue, (uint8_t)(pxQueue->uxMessagesWaiting - 1)); + +/* Called when a message receive from interrupt context fails (since the queue was empty) */ +#undef traceQUEUE_RECEIVE_FROM_ISR_FAILED +#define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE_FROM_ISR, TRCFAILED, QUEUE, pxQueue), QUEUE, pxQueue); + +#undef traceQUEUE_REGISTRY_ADD +#define traceQUEUE_REGISTRY_ADD(object, name) prvTraceSetObjectName(TRACE_GET_OBJECT_TRACE_CLASS(QUEUE, object), TRACE_GET_OBJECT_NUMBER(QUEUE, object), name); + +/* Called in vTaskPrioritySet */ +#undef traceTASK_PRIORITY_SET +#define traceTASK_PRIORITY_SET( pxTask, uxNewPriority ) \ + trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE(TASK_PRIORITY_SET, pxTask, uxNewPriority); + +/* Called in vTaskPriorityInherit, which is called by Mutex operations */ +#undef traceTASK_PRIORITY_INHERIT +#define traceTASK_PRIORITY_INHERIT( pxTask, uxNewPriority ) \ + trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE(TASK_PRIORITY_INHERIT, pxTask, uxNewPriority); + +/* Called in vTaskPriorityDisinherit, which is called by Mutex operations */ +#undef traceTASK_PRIORITY_DISINHERIT +#define traceTASK_PRIORITY_DISINHERIT( pxTask, uxNewPriority ) \ + trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE(TASK_PRIORITY_DISINHERIT, pxTask, uxNewPriority); + +/* Called in vTaskResume */ +#undef traceTASK_RESUME +#define traceTASK_RESUME( pxTaskToResume ) \ + trcKERNEL_HOOKS_TASK_RESUME(TASK_RESUME, pxTaskToResume); + +/* Called in vTaskResumeFromISR */ +#undef traceTASK_RESUME_FROM_ISR +#define traceTASK_RESUME_FROM_ISR( pxTaskToResume ) \ + trcKERNEL_HOOKS_TASK_RESUME_FROM_ISR(TASK_RESUME_FROM_ISR, pxTaskToResume); + + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) + +#if (TRC_CFG_INCLUDE_MEMMANG_EVENTS == 1) + +extern void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, int32_t size); + +/* MALLOC and FREE are always stored, no matter if they happen inside filtered task */ +#undef traceMALLOC +#define traceMALLOC( pvAddress, uiSize ) \ + if (pvAddress != 0) \ + vTraceStoreMemMangEvent(MEM_MALLOC_SIZE, ( uint32_t ) pvAddress, (int32_t)uiSize); + +#undef traceFREE +#define traceFREE( pvAddress, uiSize ) \ + vTraceStoreMemMangEvent(MEM_FREE_SIZE, ( uint32_t ) pvAddress, -((int32_t)uiSize)); + +#endif /* (TRC_CFG_INCLUDE_MEMMANG_EVENTS == 1) */ + +#if (TRC_CFG_INCLUDE_TIMER_EVENTS == 1) + +/* Called in timer.c - xTimerCreate */ +#undef traceTIMER_CREATE +#define traceTIMER_CREATE(tmr) \ + trcKERNEL_HOOKS_OBJECT_CREATE(TIMER_CREATE, TIMER, tmr); + +#undef traceTIMER_CREATE_FAILED +#define traceTIMER_CREATE_FAILED() \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY(TIMER_CREATE_TRCFAILED, 0); + +/* Note that xCommandID can never be tmrCOMMAND_EXECUTE_CALLBACK (-1) since the trace macro is not called in that case */ +#undef traceTIMER_COMMAND_SEND +#define traceTIMER_COMMAND_SEND(tmr, xCommandID, xOptionalValue, xReturn) \ + if (xCommandID > tmrCOMMAND_START_DONT_TRACE) \ + { \ + if (xCommandID == tmrCOMMAND_CHANGE_PERIOD) \ + { \ + if (xReturn == pdPASS) { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TIMER_CHANGE_PERIOD, TIMER, tmr, xOptionalValue); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TIMER_CHANGE_PERIOD_TRCFAILED, TIMER, tmr, xOptionalValue); \ + } \ + } \ + else if ((xCommandID == tmrCOMMAND_DELETE) && (xReturn == pdPASS)) \ + { \ + trcKERNEL_HOOKS_OBJECT_DELETE(TIMER_DELETE_OBJ, EVENTGROUP_OBJCLOSE_NAME_TRCSUCCESS + TRACE_GET_OBJECT_TRACE_CLASS(TIMER, tmr), EVENTGROUP_OBJCLOSE_PROP_TRCSUCCESS + TRACE_GET_OBJECT_TRACE_CLASS(TIMER, tmr), TIMER, tmr); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENTGROUP_TIMER + (uint32_t)xCommandID + ((xReturn == pdPASS) ? 0 : (TIMER_CREATE_TRCFAILED - TIMER_CREATE)), TIMER, tmr, xOptionalValue); \ + }\ + } + +#undef traceTIMER_EXPIRED +#define traceTIMER_EXPIRED(tmr) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TIMER_EXPIRED, TIMER, tmr); + +#endif /* (TRC_CFG_INCLUDE_TIMER_EVENTS == 1) */ + +#if (TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS == 1) + +#undef tracePEND_FUNC_CALL +#define tracePEND_FUNC_CALL(func, arg1, arg2, ret) \ + if (ret == pdPASS){ \ + trcKERNEL_HOOKS_KERNEL_SERVICE(PEND_FUNC_CALL, TASK, xTimerGetTimerDaemonTaskHandle() ); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE(PEND_FUNC_CALL_TRCFAILED, TASK, xTimerGetTimerDaemonTaskHandle() ); \ + } + +#undef tracePEND_FUNC_CALL_FROM_ISR +#define tracePEND_FUNC_CALL_FROM_ISR(func, arg1, arg2, ret) \ + if (! uiInEventGroupSetBitsFromISR) \ + prvTraceStoreKernelCall(PEND_FUNC_CALL_FROM_ISR, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(xTimerGetTimerDaemonTaskHandle()) ); \ + uiInEventGroupSetBitsFromISR = 0; + +#endif /* (TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS == 1) */ + +#endif /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) */ + +#if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1) + +#undef traceEVENT_GROUP_CREATE +#define traceEVENT_GROUP_CREATE(eg) \ + trcKERNEL_HOOKS_OBJECT_CREATE(EVENT_GROUP_CREATE, EVENTGROUP, eg); + +#undef traceEVENT_GROUP_CREATE_FAILED +#define traceEVENT_GROUP_CREATE_FAILED() \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY(EVENT_GROUP_CREATE_TRCFAILED, 0); + +#undef traceEVENT_GROUP_DELETE +#define traceEVENT_GROUP_DELETE(eg) \ + { TRACE_ALLOC_CRITICAL_SECTION(); \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_OBJECT_DELETE(EVENT_GROUP_DELETE_OBJ, EVENTGROUP_OBJCLOSE_NAME_TRCSUCCESS + TRACE_GET_OBJECT_TRACE_CLASS(EVENTGROUP, eg), EVENTGROUP_OBJCLOSE_NAME_TRCSUCCESS + TRACE_GET_OBJECT_TRACE_CLASS(EVENTGROUP, eg), EVENTGROUP, eg); \ + TRACE_EXIT_CRITICAL_SECTION(); } + +#undef traceEVENT_GROUP_SYNC_BLOCK +#define traceEVENT_GROUP_SYNC_BLOCK(eg, bitsToSet, bitsToWaitFor) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_SYNC_TRCBLOCK, EVENTGROUP, eg, bitsToWaitFor); + +#undef traceEVENT_GROUP_SYNC_END +#define traceEVENT_GROUP_SYNC_END(eg, bitsToSet, bitsToWaitFor, wasTimeout) \ + if (wasTimeout) \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_SYNC_END_TRCFAILED, EVENTGROUP, eg, bitsToWaitFor); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_SYNC_END, EVENTGROUP, eg, bitsToWaitFor); \ + } + +#undef traceEVENT_GROUP_WAIT_BITS_BLOCK +#define traceEVENT_GROUP_WAIT_BITS_BLOCK(eg, bitsToWaitFor) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_WAIT_BITS_TRCBLOCK, EVENTGROUP, eg, bitsToWaitFor); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); + +#undef traceEVENT_GROUP_WAIT_BITS_END +#define traceEVENT_GROUP_WAIT_BITS_END(eg, bitsToWaitFor, wasTimeout) \ + if (wasTimeout) \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_WAIT_BITS_END_TRCFAILED, EVENTGROUP, eg, bitsToWaitFor); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_WAIT_BITS_END, EVENTGROUP, eg, bitsToWaitFor); \ + } + +#undef traceEVENT_GROUP_CLEAR_BITS +#define traceEVENT_GROUP_CLEAR_BITS(eg, bitsToClear) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_CLEAR_BITS, EVENTGROUP, eg, bitsToClear); + +#undef traceEVENT_GROUP_CLEAR_BITS_FROM_ISR +#define traceEVENT_GROUP_CLEAR_BITS_FROM_ISR(eg, bitsToClear) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM_FROM_ISR(EVENT_GROUP_CLEAR_BITS_FROM_ISR, EVENTGROUP, eg, bitsToClear); + +#undef traceEVENT_GROUP_SET_BITS +#define traceEVENT_GROUP_SET_BITS(eg, bitsToSet) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_SET_BITS, EVENTGROUP, eg, bitsToSet); + +#undef traceEVENT_GROUP_SET_BITS_FROM_ISR +#define traceEVENT_GROUP_SET_BITS_FROM_ISR(eg, bitsToSet) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM_FROM_ISR(EVENT_GROUP_SET_BITS_FROM_ISR, EVENTGROUP, eg, bitsToSet); \ + uiInEventGroupSetBitsFromISR = 1; + +#endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1) */ + +#undef traceTASK_NOTIFY_TAKE +#if (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) +#define traceTASK_NOTIFY_TAKE() \ + if (pxCurrentTCB->eNotifyState == eNotified){ \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TRACE_TASK_NOTIFY_TAKE, TASK, pxCurrentTCB, xTicksToWait); \ + } \ + else{ \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TRACE_TASK_NOTIFY_TAKE_TRCFAILED, TASK, pxCurrentTCB, xTicksToWait); \ + } +#else /* TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0 */ +#define traceTASK_NOTIFY_TAKE() \ + if (pxCurrentTCB->ucNotifyState[ uxIndexToWait ] == taskNOTIFICATION_RECEIVED){ \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TRACE_TASK_NOTIFY_TAKE, TASK, pxCurrentTCB, xTicksToWait); \ + }else{ \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TRACE_TASK_NOTIFY_TAKE_TRCFAILED, TASK, pxCurrentTCB, xTicksToWait);} +#endif /* TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0 */ + +#undef traceTASK_NOTIFY_TAKE_BLOCK +#define traceTASK_NOTIFY_TAKE_BLOCK() \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TRACE_TASK_NOTIFY_TAKE_TRCBLOCK, TASK, pxCurrentTCB, xTicksToWait); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); + +#undef traceTASK_NOTIFY_WAIT +#if (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) +#define traceTASK_NOTIFY_WAIT() \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxCurrentTCB) & CurrentFilterMask) \ + { \ + if (pxCurrentTCB->eNotifyState == eNotified) \ + prvTraceStoreKernelCallWithParam(TRACE_TASK_NOTIFY_WAIT, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxCurrentTCB), xTicksToWait); \ + else \ + prvTraceStoreKernelCallWithParam(TRACE_TASK_NOTIFY_WAIT_TRCFAILED, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxCurrentTCB), xTicksToWait); \ + } +#else /* TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0 */ +#define traceTASK_NOTIFY_WAIT() \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxCurrentTCB) & CurrentFilterMask) \ + { \ + if (pxCurrentTCB->ucNotifyState[ uxIndexToWait ] == taskNOTIFICATION_RECEIVED) \ + prvTraceStoreKernelCallWithParam(TRACE_TASK_NOTIFY_WAIT, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxCurrentTCB), xTicksToWait); \ + else \ + prvTraceStoreKernelCallWithParam(TRACE_TASK_NOTIFY_WAIT_TRCFAILED, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxCurrentTCB), xTicksToWait); \ + } +#endif /* TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0 */ + +#undef traceTASK_NOTIFY_WAIT_BLOCK +#define traceTASK_NOTIFY_WAIT_BLOCK() \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxCurrentTCB) & CurrentFilterMask) \ + prvTraceStoreKernelCallWithParam(TRACE_TASK_NOTIFY_WAIT_TRCBLOCK, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxCurrentTCB), xTicksToWait); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); + +#undef traceTASK_NOTIFY +#define traceTASK_NOTIFY() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, xTaskToNotify) & CurrentFilterMask) \ + prvTraceStoreKernelCall(TRACE_TASK_NOTIFY, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(xTaskToNotify)); + +#undef traceTASK_NOTIFY_FROM_ISR +#define traceTASK_NOTIFY_FROM_ISR() \ + if (TRACE_GET_OBJECT_FILTER(TASK, xTaskToNotify) & CurrentFilterMask) \ + prvTraceStoreKernelCall(TRACE_TASK_NOTIFY_FROM_ISR, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(xTaskToNotify)); + +#undef traceTASK_NOTIFY_GIVE_FROM_ISR +#define traceTASK_NOTIFY_GIVE_FROM_ISR() \ + if (TRACE_GET_OBJECT_FILTER(TASK, xTaskToNotify) & CurrentFilterMask) \ + prvTraceStoreKernelCall(TRACE_TASK_NOTIFY_GIVE_FROM_ISR, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(xTaskToNotify)); + +#if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) + +#undef traceSTREAM_BUFFER_CREATE +#define traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer ) \ + trcKERNEL_HOOKS_OBJECT_CREATE(TRACE_GET_OBJECT_EVENT_CODE(CREATE_OBJ, TRCSUCCESS, STREAMBUFFER, pxStreamBuffer), STREAMBUFFER, pxStreamBuffer); + +#undef traceSTREAM_BUFFER_CREATE_FAILED +#define traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY(TRACE_GET_CLASS_EVENT_CODE(CREATE_OBJ, TRCFAILED, STREAMBUFFER, xIsMessageBuffer), 0); + +#undef traceSTREAM_BUFFER_CREATE_STATIC_FAILED +#define traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer ) \ + traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer ) + +#undef traceSTREAM_BUFFER_DELETE +#define traceSTREAM_BUFFER_DELETE( xStreamBuffer ) \ + trcKERNEL_HOOKS_OBJECT_DELETE(TRACE_GET_OBJECT_EVENT_CODE(DELETE_OBJ, TRCSUCCESS, STREAMBUFFER, xStreamBuffer), TRACE_GET_OBJECT_EVENT_CODE(OBJCLOSE_NAME, TRCSUCCESS, STREAMBUFFER, xStreamBuffer), TRACE_GET_OBJECT_EVENT_CODE(OBJCLOSE_PROP, TRCSUCCESS, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); + +#undef traceSTREAM_BUFFER_RESET +#define traceSTREAM_BUFFER_RESET( xStreamBuffer ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(prvGetStreamBufferType(xStreamBuffer) > 0 ? TRACE_MESSAGEBUFFER_RESET : TRACE_STREAMBUFFER_RESET, STREAMBUFFER, xStreamBuffer); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(STREAMBUFFER, xStreamBuffer, 0); + +#undef traceSTREAM_BUFFER_SEND +#define traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(SEND, TRCSUCCESS, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(STREAMBUFFER, xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); + +#undef traceBLOCKING_ON_STREAM_BUFFER_SEND +#define traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(SEND, TRCBLOCK, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); + +#undef traceSTREAM_BUFFER_SEND_FAILED +#define traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(SEND, TRCFAILED, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); + +#undef traceSTREAM_BUFFER_RECEIVE +#define traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE, TRCSUCCESS, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(STREAMBUFFER, xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); + + +#undef traceBLOCKING_ON_STREAM_BUFFER_RECEIVE +#define traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE, TRCBLOCK, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); + +#undef traceSTREAM_BUFFER_RECEIVE_FAILED +#define traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE, TRCFAILED, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); + +#undef traceSTREAM_BUFFER_SEND_FROM_ISR +#define traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn ) \ + if( xReturn > ( size_t ) 0 ) \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(SEND_FROM_ISR, TRCSUCCESS, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(STREAMBUFFER, xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(SEND_FROM_ISR, TRCFAILED, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); \ + } + +#undef traceSTREAM_BUFFER_RECEIVE_FROM_ISR +#define traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength ) \ + if( xReceivedLength > ( size_t ) 0 ) \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE_FROM_ISR, TRCSUCCESS, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(STREAMBUFFER, xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE_FROM_ISR, TRCFAILED, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); \ + } + +#endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) */ + +#endif /* (TRC_CFG_SCHEDULING_ONLY == 0) */ + +#endif /*#if TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT */ + +/******************************************************************************/ +/*** Definitions for Streaming mode *******************************************/ +/******************************************************************************/ +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) + +/******************************************************************************* +* vTraceStoreKernelObjectName +* +* Set the name for a kernel object (defined by its address). +******************************************************************************/ +void vTraceStoreKernelObjectName(void* object, const char* name); + +/******************************************************************************* +* prvIsNewTCB +* +* Tells if this task is already executing, or if there has been a task-switch. +* Assumed to be called within a trace hook in kernel context. +*******************************************************************************/ +uint32_t prvIsNewTCB(void* pNewTCB); + +#define TRACE_GET_CURRENT_TASK() prvTraceGetCurrentTaskHandle() + +/*************************************************************************/ +/* KERNEL SPECIFIC OBJECT CONFIGURATION */ +/*************************************************************************/ + +/******************************************************************************* + * The event codes - should match the offline config file. + ******************************************************************************/ + +/*** Event codes for streaming - should match the Tracealyzer config file *****/ +#define PSF_EVENT_NULL_EVENT 0x00 + +#define PSF_EVENT_TRACE_START 0x01 +#define PSF_EVENT_TS_CONFIG 0x02 +#define PSF_EVENT_OBJ_NAME 0x03 +#define PSF_EVENT_TASK_PRIORITY 0x04 +#define PSF_EVENT_TASK_PRIO_INHERIT 0x05 +#define PSF_EVENT_TASK_PRIO_DISINHERIT 0x06 +#define PSF_EVENT_DEFINE_ISR 0x07 + +#define PSF_EVENT_TASK_CREATE 0x10 +#define PSF_EVENT_QUEUE_CREATE 0x11 +#define PSF_EVENT_SEMAPHORE_BINARY_CREATE 0x12 +#define PSF_EVENT_MUTEX_CREATE 0x13 +#define PSF_EVENT_TIMER_CREATE 0x14 +#define PSF_EVENT_EVENTGROUP_CREATE 0x15 +#define PSF_EVENT_SEMAPHORE_COUNTING_CREATE 0x16 +#define PSF_EVENT_MUTEX_RECURSIVE_CREATE 0x17 +#define PSF_EVENT_STREAMBUFFER_CREATE 0x18 +#define PSF_EVENT_MESSAGEBUFFER_CREATE 0x19 + +#define PSF_EVENT_TASK_DELETE 0x20 +#define PSF_EVENT_QUEUE_DELETE 0x21 +#define PSF_EVENT_SEMAPHORE_DELETE 0x22 +#define PSF_EVENT_MUTEX_DELETE 0x23 +#define PSF_EVENT_TIMER_DELETE 0x24 +#define PSF_EVENT_EVENTGROUP_DELETE 0x25 +#define PSF_EVENT_STREAMBUFFER_DELETE 0x28 +#define PSF_EVENT_MESSAGEBUFFER_DELETE 0x29 + +#define PSF_EVENT_TASK_READY 0x30 +#define PSF_EVENT_NEW_TIME 0x31 +#define PSF_EVENT_NEW_TIME_SCHEDULER_SUSPENDED 0x32 +#define PSF_EVENT_ISR_BEGIN 0x33 +#define PSF_EVENT_ISR_RESUME 0x34 +#define PSF_EVENT_TS_BEGIN 0x35 +#define PSF_EVENT_TS_RESUME 0x36 +#define PSF_EVENT_TASK_ACTIVATE 0x37 + +#define PSF_EVENT_MALLOC 0x38 +#define PSF_EVENT_FREE 0x39 + +#define PSF_EVENT_LOWPOWER_BEGIN 0x3A +#define PSF_EVENT_LOWPOWER_END 0x3B + +#define PSF_EVENT_IFE_NEXT 0x3C +#define PSF_EVENT_IFE_DIRECT 0x3D + +#define PSF_EVENT_TASK_CREATE_FAILED 0x40 +#define PSF_EVENT_QUEUE_CREATE_FAILED 0x41 +#define PSF_EVENT_SEMAPHORE_BINARY_CREATE_FAILED 0x42 +#define PSF_EVENT_MUTEX_CREATE_FAILED 0x43 +#define PSF_EVENT_TIMER_CREATE_FAILED 0x44 +#define PSF_EVENT_EVENTGROUP_CREATE_FAILED 0x45 +#define PSF_EVENT_SEMAPHORE_COUNTING_CREATE_FAILED 0x46 +#define PSF_EVENT_MUTEX_RECURSIVE_CREATE_FAILED 0x47 +#define PSF_EVENT_STREAMBUFFER_CREATE_FAILED 0x49 +#define PSF_EVENT_MESSAGEBUFFER_CREATE_FAILED 0x4A + +#define PSF_EVENT_TIMER_DELETE_FAILED 0x48 + +#define PSF_EVENT_QUEUE_SEND 0x50 +#define PSF_EVENT_SEMAPHORE_GIVE 0x51 +#define PSF_EVENT_MUTEX_GIVE 0x52 + +#define PSF_EVENT_QUEUE_SEND_FAILED 0x53 +#define PSF_EVENT_SEMAPHORE_GIVE_FAILED 0x54 +#define PSF_EVENT_MUTEX_GIVE_FAILED 0x55 + +#define PSF_EVENT_QUEUE_SEND_BLOCK 0x56 +#define PSF_EVENT_SEMAPHORE_GIVE_BLOCK 0x57 +#define PSF_EVENT_MUTEX_GIVE_BLOCK 0x58 + +#define PSF_EVENT_QUEUE_SEND_FROMISR 0x59 +#define PSF_EVENT_SEMAPHORE_GIVE_FROMISR 0x5A + +#define PSF_EVENT_QUEUE_SEND_FROMISR_FAILED 0x5C +#define PSF_EVENT_SEMAPHORE_GIVE_FROMISR_FAILED 0x5D + +#define PSF_EVENT_QUEUE_RECEIVE 0x60 +#define PSF_EVENT_SEMAPHORE_TAKE 0x61 +#define PSF_EVENT_MUTEX_TAKE 0x62 + +#define PSF_EVENT_QUEUE_RECEIVE_FAILED 0x63 +#define PSF_EVENT_SEMAPHORE_TAKE_FAILED 0x64 +#define PSF_EVENT_MUTEX_TAKE_FAILED 0x65 + +#define PSF_EVENT_QUEUE_RECEIVE_BLOCK 0x66 +#define PSF_EVENT_SEMAPHORE_TAKE_BLOCK 0x67 +#define PSF_EVENT_MUTEX_TAKE_BLOCK 0x68 + +#define PSF_EVENT_QUEUE_RECEIVE_FROMISR 0x69 +#define PSF_EVENT_SEMAPHORE_TAKE_FROMISR 0x6A + +#define PSF_EVENT_QUEUE_RECEIVE_FROMISR_FAILED 0x6C +#define PSF_EVENT_SEMAPHORE_TAKE_FROMISR_FAILED 0x6D + +#define PSF_EVENT_QUEUE_PEEK 0x70 +#define PSF_EVENT_SEMAPHORE_PEEK 0x71 +#define PSF_EVENT_MUTEX_PEEK 0x72 + +#define PSF_EVENT_QUEUE_PEEK_FAILED 0x73 +#define PSF_EVENT_SEMAPHORE_PEEK_FAILED 0x74 +#define PSF_EVENT_MUTEX_PEEK_FAILED 0x75 + +#define PSF_EVENT_QUEUE_PEEK_BLOCK 0x76 +#define PSF_EVENT_SEMAPHORE_PEEK_BLOCK 0x77 +#define PSF_EVENT_MUTEX_PEEK_BLOCK 0x78 + +#define PSF_EVENT_TASK_DELAY_UNTIL 0x79 +#define PSF_EVENT_TASK_DELAY 0x7A +#define PSF_EVENT_TASK_SUSPEND 0x7B +#define PSF_EVENT_TASK_RESUME 0x7C +#define PSF_EVENT_TASK_RESUME_FROMISR 0x7D + +#define PSF_EVENT_TIMER_PENDFUNCCALL 0x80 +#define PSF_EVENT_TIMER_PENDFUNCCALL_FROMISR 0x81 +#define PSF_EVENT_TIMER_PENDFUNCCALL_FAILED 0x82 +#define PSF_EVENT_TIMER_PENDFUNCCALL_FROMISR_FAILED 0x83 + +#define PSF_EVENT_USER_EVENT 0x90 + +#define PSF_EVENT_TIMER_START 0xA0 +#define PSF_EVENT_TIMER_RESET 0xA1 +#define PSF_EVENT_TIMER_STOP 0xA2 +#define PSF_EVENT_TIMER_CHANGEPERIOD 0xA3 +#define PSF_EVENT_TIMER_START_FROMISR 0xA4 +#define PSF_EVENT_TIMER_RESET_FROMISR 0xA5 +#define PSF_EVENT_TIMER_STOP_FROMISR 0xA6 +#define PSF_EVENT_TIMER_CHANGEPERIOD_FROMISR 0xA7 +#define PSF_EVENT_TIMER_START_FAILED 0xA8 +#define PSF_EVENT_TIMER_RESET_FAILED 0xA9 +#define PSF_EVENT_TIMER_STOP_FAILED 0xAA +#define PSF_EVENT_TIMER_CHANGEPERIOD_FAILED 0xAB +#define PSF_EVENT_TIMER_START_FROMISR_FAILED 0xAC +#define PSF_EVENT_TIMER_RESET_FROMISR_FAILED 0xAD +#define PSF_EVENT_TIMER_STOP_FROMISR_FAILED 0xAE +#define PSF_EVENT_TIMER_CHANGEPERIOD_FROMISR_FAILED 0xAF + +#define PSF_EVENT_EVENTGROUP_SYNC 0xB0 +#define PSF_EVENT_EVENTGROUP_WAITBITS 0xB1 +#define PSF_EVENT_EVENTGROUP_CLEARBITS 0xB2 +#define PSF_EVENT_EVENTGROUP_CLEARBITS_FROMISR 0xB3 +#define PSF_EVENT_EVENTGROUP_SETBITS 0xB4 +#define PSF_EVENT_EVENTGROUP_SETBITS_FROMISR 0xB5 +#define PSF_EVENT_EVENTGROUP_SYNC_BLOCK 0xB6 +#define PSF_EVENT_EVENTGROUP_WAITBITS_BLOCK 0xB7 +#define PSF_EVENT_EVENTGROUP_SYNC_FAILED 0xB8 +#define PSF_EVENT_EVENTGROUP_WAITBITS_FAILED 0xB9 + +#define PSF_EVENT_QUEUE_SEND_FRONT 0xC0 +#define PSF_EVENT_QUEUE_SEND_FRONT_FAILED 0xC1 +#define PSF_EVENT_QUEUE_SEND_FRONT_BLOCK 0xC2 +#define PSF_EVENT_QUEUE_SEND_FRONT_FROMISR 0xC3 +#define PSF_EVENT_QUEUE_SEND_FRONT_FROMISR_FAILED 0xC4 +#define PSF_EVENT_MUTEX_GIVE_RECURSIVE 0xC5 +#define PSF_EVENT_MUTEX_GIVE_RECURSIVE_FAILED 0xC6 +#define PSF_EVENT_MUTEX_TAKE_RECURSIVE 0xC7 +#define PSF_EVENT_MUTEX_TAKE_RECURSIVE_FAILED 0xC8 + +#define PSF_EVENT_TASK_NOTIFY 0xC9 +#define PSF_EVENT_TASK_NOTIFY_TAKE 0xCA +#define PSF_EVENT_TASK_NOTIFY_TAKE_BLOCK 0xCB +#define PSF_EVENT_TASK_NOTIFY_TAKE_FAILED 0xCC +#define PSF_EVENT_TASK_NOTIFY_WAIT 0xCD +#define PSF_EVENT_TASK_NOTIFY_WAIT_BLOCK 0xCE +#define PSF_EVENT_TASK_NOTIFY_WAIT_FAILED 0xCF +#define PSF_EVENT_TASK_NOTIFY_FROM_ISR 0xD0 +#define PSF_EVENT_TASK_NOTIFY_GIVE_FROM_ISR 0xD1 + +#define PSF_EVENT_TIMER_EXPIRED 0xD2 + +#define PSF_EVENT_STREAMBUFFER_SEND 0xD3 +#define PSF_EVENT_STREAMBUFFER_SEND_BLOCK 0xD4 +#define PSF_EVENT_STREAMBUFFER_SEND_FAILED 0xD5 +#define PSF_EVENT_STREAMBUFFER_RECEIVE 0xD6 +#define PSF_EVENT_STREAMBUFFER_RECEIVE_BLOCK 0xD7 +#define PSF_EVENT_STREAMBUFFER_RECEIVE_FAILED 0xD8 +#define PSF_EVENT_STREAMBUFFER_SEND_FROM_ISR 0xD9 +#define PSF_EVENT_STREAMBUFFER_SEND_FROM_ISR_FAILED 0xDA +#define PSF_EVENT_STREAMBUFFER_RECEIVE_FROM_ISR 0xDB +#define PSF_EVENT_STREAMBUFFER_RECEIVE_FROM_ISR_FAILED 0xDC +#define PSF_EVENT_STREAMBUFFER_RESET 0xDD + +#define PSF_EVENT_MESSAGEBUFFER_SEND 0xDE +#define PSF_EVENT_MESSAGEBUFFER_SEND_BLOCK 0xDF +#define PSF_EVENT_MESSAGEBUFFER_SEND_FAILED 0xE0 +#define PSF_EVENT_MESSAGEBUFFER_RECEIVE 0xE1 +#define PSF_EVENT_MESSAGEBUFFER_RECEIVE_BLOCK 0xE2 +#define PSF_EVENT_MESSAGEBUFFER_RECEIVE_FAILED 0xE3 +#define PSF_EVENT_MESSAGEBUFFER_SEND_FROM_ISR 0xE4 +#define PSF_EVENT_MESSAGEBUFFER_SEND_FROM_ISR_FAILED 0xE5 +#define PSF_EVENT_MESSAGEBUFFER_RECEIVE_FROM_ISR 0xE6 +#define PSF_EVENT_MESSAGEBUFFER_RECEIVE_FROM_ISR_FAILED 0xE7 +#define PSF_EVENT_MESSAGEBUFFER_RESET 0xE8 + +/*** The trace macros for streaming ******************************************/ + +/* A macro that will update the tick count when returning from tickless idle */ +#undef traceINCREASE_TICK_COUNT +/* Note: This can handle time adjustments of max 2^32 ticks, i.e., 35 seconds at 120 MHz. Thus, tick-less idle periods longer than 2^32 ticks will appear "compressed" on the time line.*/ +#define traceINCREASE_TICK_COUNT( xCount ) { extern uint32_t uiTraceTickCount; uiTraceTickCount += xCount; } + +#if (TRC_CFG_INCLUDE_OSTICK_EVENTS == 1) +#define OS_TICK_EVENT(uxSchedulerSuspended, xTickCount) if (uxSchedulerSuspended == (unsigned portBASE_TYPE) pdFALSE) { prvTraceStoreEvent1(PSF_EVENT_NEW_TIME, (uint32_t)(xTickCount + 1)); } +#else +#define OS_TICK_EVENT(uxSchedulerSuspended, xTickCount) +#endif + +/* Called on each OS tick. Will call uiPortGetTimestamp to make sure it is called at least once every OS tick. */ +#undef traceTASK_INCREMENT_TICK +#if TRC_CFG_FREERTOS_VERSION <= TRC_FREERTOS_VERSION_7_4 +#define traceTASK_INCREMENT_TICK( xTickCount ) \ + if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdTRUE || uxMissedTicks == 0) { extern uint32_t uiTraceTickCount; uiTraceTickCount++; } \ + OS_TICK_EVENT(uxSchedulerSuspended, xTickCount) +#else +#define traceTASK_INCREMENT_TICK( xTickCount ) \ + if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdTRUE || uxPendedTicks == 0) { extern uint32_t uiTraceTickCount; uiTraceTickCount++; } \ + OS_TICK_EVENT(uxSchedulerSuspended, xTickCount) +#endif /* TRC_CFG_FREERTOS_VERSION <= TRC_FREERTOS_VERSION_7_4 */ + +/* Called on each task-switch */ +#undef traceTASK_SWITCHED_IN +#define traceTASK_SWITCHED_IN() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + { \ + if (prvIsNewTCB(pxCurrentTCB)) \ + { \ + prvTraceStoreEvent2(PSF_EVENT_TASK_ACTIVATE, (uint32_t)pxCurrentTCB, pxCurrentTCB->uxPriority); \ + } \ + } + +/* Called for each task that becomes ready */ +#if (TRC_CFG_INCLUDE_READY_EVENTS == 1) +#undef traceMOVED_TASK_TO_READY_STATE +#define traceMOVED_TASK_TO_READY_STATE( pxTCB ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_READY, (uint32_t)pxTCB); +#endif + +#undef traceTASK_CREATE +#if TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 +#define traceTASK_CREATE(pxNewTCB) \ + if (pxNewTCB != NULL) \ + { \ + prvTraceSaveSymbol(pxNewTCB, pxNewTCB->pcTaskName); \ + prvTraceSaveObjectData(pxNewTCB, pxNewTCB->uxPriority); \ + prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, pxNewTCB->pcTaskName, pxNewTCB); \ + TRACE_SET_OBJECT_FILTER(TASK, pxNewTCB, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxNewTCB) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_CREATE, (uint32_t)pxNewTCB, pxNewTCB->uxPriority); \ + } +#else /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ +#define traceTASK_CREATE(pxNewTCB) \ + if (pxNewTCB != NULL) \ + { \ + prvTraceSaveSymbol(pxNewTCB, (const char*)pcName); \ + prvTraceSaveObjectData(pxNewTCB, uxPriority); \ + prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, (const char*)pcName, pxNewTCB); \ + TRACE_SET_OBJECT_FILTER(TASK, pxNewTCB, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxNewTCB) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_CREATE, (uint32_t)pxNewTCB, uxPriority); \ + } +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ + +/* Called in vTaskCreate, if it fails (typically if the stack can not be allocated) */ +#undef traceTASK_CREATE_FAILED +#define traceTASK_CREATE_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent0(PSF_EVENT_TASK_CREATE_FAILED); + +/* Called on vTaskDelete */ +#undef traceTASK_DELETE // We don't allow for filtering out "delete" events. They are important and not very frequent. Moreover, we can't exclude create events, so this should be symmetrical. +#define traceTASK_DELETE( pxTaskToDelete ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTaskToDelete) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_DELETE, (uint32_t)pxTaskToDelete, (pxTaskToDelete != NULL) ? (pxTaskToDelete->uxPriority) : 0); \ + prvTraceDeleteSymbol(pxTaskToDelete); \ + prvTraceDeleteObjectData(pxTaskToDelete); + +#if (TRC_CFG_SCHEDULING_ONLY == 0) + +#if (defined(configUSE_TICKLESS_IDLE) && configUSE_TICKLESS_IDLE != 0) + +#undef traceLOW_POWER_IDLE_BEGIN +#define traceLOW_POWER_IDLE_BEGIN() \ + { \ + prvTraceStoreEvent1(PSF_EVENT_LOWPOWER_BEGIN, xExpectedIdleTime); \ + } + +#undef traceLOW_POWER_IDLE_END +#define traceLOW_POWER_IDLE_END() \ + { \ + prvTraceStoreEvent0(PSF_EVENT_LOWPOWER_END); \ + } + +#endif /* (defined(configUSE_TICKLESS_IDLE) && configUSE_TICKLESS_IDLE != 0) */ + +/* Called on vTaskSuspend */ +#undef traceTASK_SUSPEND +#define traceTASK_SUSPEND( pxTaskToSuspend ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTaskToSuspend) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_SUSPEND, (uint32_t)pxTaskToSuspend); + +/* Called on vTaskDelay - note the use of FreeRTOS variable xTicksToDelay */ +#undef traceTASK_DELAY +#define traceTASK_DELAY() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_DELAY, xTicksToDelay); + +/* Called on vTaskDelayUntil - note the use of FreeRTOS variable xTimeToWake */ +#undef traceTASK_DELAY_UNTIL +#if TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 +#define traceTASK_DELAY_UNTIL(xTimeToWake) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_DELAY_UNTIL, (uint32_t)xTimeToWake); +#else /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ +#define traceTASK_DELAY_UNTIL() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_DELAY_UNTIL, (uint32_t)xTimeToWake); +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0) +#define traceQUEUE_CREATE_HELPER() \ + case queueQUEUE_TYPE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_CREATE, (uint32_t)pxNewQueue); \ + break; \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_RECURSIVE_CREATE, (uint32_t)pxNewQueue); \ + break; +#else +#define traceQUEUE_CREATE_HELPER() +#endif /* (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) */ + +/* Called in xQueueCreate, and thereby for all other object based on queues, such as semaphores. */ +#undef traceQUEUE_CREATE +#define traceQUEUE_CREATE( pxNewQueue )\ + TRACE_SET_OBJECT_FILTER(QUEUE, pxNewQueue, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + { \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxNewQueue) & CurrentFilterMask) \ + { \ + switch (pxNewQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(PSF_EVENT_QUEUE_CREATE, (uint32_t)pxNewQueue, uxQueueLength); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + prvTraceStoreEvent1(PSF_EVENT_SEMAPHORE_BINARY_CREATE, (uint32_t)pxNewQueue); \ + break; \ + traceQUEUE_CREATE_HELPER() \ + } \ + } \ + } + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0) +#define traceQUEUE_CREATE_FAILED_HELPER() \ + case queueQUEUE_TYPE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_CREATE_FAILED, 0); \ + break; \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_RECURSIVE_CREATE_FAILED, 0); \ + break; +#else +#define traceQUEUE_CREATE_FAILED_HELPER() +#endif /* (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) */ + +/* Called in xQueueCreate, if the queue creation fails */ +#undef traceQUEUE_CREATE_FAILED +#define traceQUEUE_CREATE_FAILED( queueType ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + { \ + switch (queueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(PSF_EVENT_QUEUE_CREATE_FAILED, 0, uxQueueLength); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + prvTraceStoreEvent1(PSF_EVENT_SEMAPHORE_BINARY_CREATE_FAILED, 0); \ + break; \ + traceQUEUE_CREATE_FAILED_HELPER() \ + } \ + } + +#undef traceQUEUE_DELETE // We don't allow for filtering out "delete" events. They are important and not very frequent. Moreover, we can't exclude create events, so this should be symmetrical. +#define traceQUEUE_DELETE( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + { \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + { \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(PSF_EVENT_QUEUE_DELETE, (uint32_t)pxQueue, (pxQueue != NULL) ? (pxQueue->uxMessagesWaiting) : 0); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent2(PSF_EVENT_MUTEX_DELETE, (uint32_t)pxQueue, (pxQueue != NULL) ? (pxQueue->uxMessagesWaiting) : 0); \ + break; \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_DELETE, (uint32_t)pxQueue, (pxQueue != NULL) ? (pxQueue->uxMessagesWaiting) : 0); \ + break; \ + } \ + } \ + } \ + prvTraceDeleteSymbol(pxQueue); + +/* Called in xQueueCreateCountingSemaphore, if the queue creation fails */ +#undef traceCREATE_COUNTING_SEMAPHORE +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) +#define traceCREATE_COUNTING_SEMAPHORE() \ + TRACE_SET_OBJECT_FILTER(QUEUE, xHandle, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, xHandle) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE, (uint32_t)xHandle, uxMaxCount) +#elif (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_7_5_OR_7_6) +#define traceCREATE_COUNTING_SEMAPHORE() \ + TRACE_SET_OBJECT_FILTER(QUEUE, xHandle, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, xHandle) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE, (uint32_t)xHandle, uxInitialCount); +#elif (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_7_4) +#define traceCREATE_COUNTING_SEMAPHORE() \ + TRACE_SET_OBJECT_FILTER(QUEUE, xHandle, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, xHandle) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE, (uint32_t)xHandle, uxCountValue); +#else +#define traceCREATE_COUNTING_SEMAPHORE() \ + TRACE_SET_OBJECT_FILTER(QUEUE, pxHandle, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxHandle) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE, (uint32_t)pxHandle, uxCountValue); +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X */ + +#undef traceCREATE_COUNTING_SEMAPHORE_FAILED +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) +#define traceCREATE_COUNTING_SEMAPHORE_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE_FAILED, 0, uxMaxCount); +#elif (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_7_5_OR_7_6) +#define traceCREATE_COUNTING_SEMAPHORE_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE_FAILED, 0, uxInitialCount); +#elif (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_7_4) +#define traceCREATE_COUNTING_SEMAPHORE_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE_FAILED, 0, uxCountValue); +#else +#define traceCREATE_COUNTING_SEMAPHORE_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE_FAILED, 0, uxCountValue); +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X */ + + +/* This macro is not necessary as of FreeRTOS v9.0.0 */ +#if (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) +/* Called in xQueueCreateMutex, and thereby also from xSemaphoreCreateMutex and xSemaphoreCreateRecursiveMutex */ +#undef traceCREATE_MUTEX +#define traceCREATE_MUTEX( pxNewQueue ) \ + TRACE_SET_OBJECT_FILTER(QUEUE, pxNewQueue, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + { \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxNewQueue) & CurrentFilterMask) \ + { \ + switch (pxNewQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_CREATE, (uint32_t)pxNewQueue); \ + break; \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_RECURSIVE_CREATE, (uint32_t)pxNewQueue); \ + break; \ + } \ + }\ + } + +/* Called in xQueueCreateMutex when the operation fails (when memory allocation fails) */ +#undef traceCREATE_MUTEX_FAILED +#define traceCREATE_MUTEX_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_CREATE_FAILED, 0); +#endif /* (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) */ + +/* Called when a message is sent to a queue */ /* CS IS NEW ! */ +#undef traceQUEUE_SEND +#define traceQUEUE_SEND( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(xCopyPosition == queueSEND_TO_BACK ? PSF_EVENT_QUEUE_SEND : PSF_EVENT_QUEUE_SEND_FRONT, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting + 1); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_GIVE, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting + 1); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_GIVE, (uint32_t)pxQueue); \ + break; \ + } + +/* Called when a message failed to be sent to a queue (timeout) */ +#undef traceQUEUE_SEND_FAILED +#define traceQUEUE_SEND_FAILED( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(xCopyPosition == queueSEND_TO_BACK ? PSF_EVENT_QUEUE_SEND_FAILED : PSF_EVENT_QUEUE_SEND_FRONT_FAILED, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_GIVE_FAILED, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_GIVE_FAILED, (uint32_t)pxQueue); \ + break; \ + } + +/* Called when the task is blocked due to a send operation on a full queue */ +#undef traceBLOCKING_ON_QUEUE_SEND +#define traceBLOCKING_ON_QUEUE_SEND( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(xCopyPosition == queueSEND_TO_BACK ? PSF_EVENT_QUEUE_SEND_BLOCK : PSF_EVENT_QUEUE_SEND_FRONT_BLOCK, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_GIVE_BLOCK, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_GIVE_BLOCK, (uint32_t)pxQueue); \ + break; \ + } + +/**************************************************************************/ +/* Makes sure xQueueGiveFromISR also has a xCopyPosition parameter */ +/**************************************************************************/ +/* Helpers needed to correctly expand names */ +#define TZ__CAT2(a,b) a ## b +#define TZ__CAT(a,b) TZ__CAT2(a, b) + +/* Expands name if this header is included... uxQueueType must be a macro that only exists in queue.c or whatever, and it must expand to nothing or to something that's valid in identifiers */ +#define xQueueGiveFromISR(a,b) TZ__CAT(xQueueGiveFromISR__, uxQueueType) (a,b) + +/* If in queue.c, the "uxQueueType" macro expands to "pcHead". queueSEND_TO_BACK is the value we need to send in */ +#define xQueueGiveFromISR__pcHead(__a, __b) MyWrapper(__a, __b, const BaseType_t xCopyPosition); \ +BaseType_t xQueueGiveFromISR(__a, __b) { return MyWrapper(xQueue, pxHigherPriorityTaskWoken, queueSEND_TO_BACK); } \ +BaseType_t MyWrapper(__a, __b, const BaseType_t xCopyPosition) + +/* If not in queue.c, "uxQueueType" isn't expanded */ +#define xQueueGiveFromISR__uxQueueType(__a, __b) xQueueGiveFromISR(__a,__b) + +/**************************************************************************/ +/* End of xQueueGiveFromISR fix */ +/**************************************************************************/ + +/* Called when a message is sent from interrupt context, e.g., using xQueueSendFromISR */ +#undef traceQUEUE_SEND_FROM_ISR +#define traceQUEUE_SEND_FROM_ISR( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(xCopyPosition == queueSEND_TO_BACK ? PSF_EVENT_QUEUE_SEND_FROMISR : PSF_EVENT_QUEUE_SEND_FRONT_FROMISR, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting + 1); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_GIVE_FROMISR, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting + 1); \ + break; \ + } + +/* Called when a message send from interrupt context fails (since the queue was full) */ +#undef traceQUEUE_SEND_FROM_ISR_FAILED +#define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(xCopyPosition == queueSEND_TO_BACK ? PSF_EVENT_QUEUE_SEND_FROMISR_FAILED : PSF_EVENT_QUEUE_SEND_FRONT_FROMISR_FAILED, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_GIVE_FROMISR_FAILED, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + } + +/* Called when a message is received from a queue */ +#undef traceQUEUE_RECEIVE +#define traceQUEUE_RECEIVE( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + if (isQueueReceiveHookActuallyPeek) \ + prvTraceStoreEvent3(PSF_EVENT_QUEUE_PEEK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting - 1); \ + else\ + prvTraceStoreEvent3(PSF_EVENT_QUEUE_RECEIVE, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting - 1); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + if (isQueueReceiveHookActuallyPeek) \ + prvTraceStoreEvent3(PSF_EVENT_SEMAPHORE_PEEK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting - 1); \ + else \ + prvTraceStoreEvent3(PSF_EVENT_SEMAPHORE_TAKE, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting - 1); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + if (isQueueReceiveHookActuallyPeek) \ + prvTraceStoreEvent2(PSF_EVENT_MUTEX_PEEK, (uint32_t)pxQueue, xTicksToWait); \ + else \ + prvTraceStoreEvent2(PSF_EVENT_MUTEX_TAKE, (uint32_t)pxQueue, xTicksToWait); \ + break; \ + } + +/* Called when a receive operation on a queue fails (timeout) */ +#undef traceQUEUE_RECEIVE_FAILED +#define traceQUEUE_RECEIVE_FAILED( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent3(isQueueReceiveHookActuallyPeek ? PSF_EVENT_QUEUE_PEEK_FAILED : PSF_EVENT_QUEUE_RECEIVE_FAILED, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent3(isQueueReceiveHookActuallyPeek ? PSF_EVENT_SEMAPHORE_PEEK_FAILED : PSF_EVENT_SEMAPHORE_TAKE_FAILED, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent2(isQueueReceiveHookActuallyPeek ? PSF_EVENT_MUTEX_PEEK_FAILED : PSF_EVENT_MUTEX_TAKE_FAILED, (uint32_t)pxQueue, xTicksToWait); \ + break; \ + } + +/* Called when the task is blocked due to a receive operation on an empty queue */ +#undef traceBLOCKING_ON_QUEUE_RECEIVE +#define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent3(isQueueReceiveHookActuallyPeek ? PSF_EVENT_QUEUE_PEEK_BLOCK : PSF_EVENT_QUEUE_RECEIVE_BLOCK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent3(isQueueReceiveHookActuallyPeek ? PSF_EVENT_SEMAPHORE_PEEK_BLOCK : PSF_EVENT_SEMAPHORE_TAKE_BLOCK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent2(isQueueReceiveHookActuallyPeek ? PSF_EVENT_MUTEX_PEEK_BLOCK : PSF_EVENT_MUTEX_TAKE_BLOCK, (uint32_t)pxQueue, xTicksToWait); \ + break; \ + } + +#if (TRC_CFG_FREERTOS_VERSION > TRC_FREERTOS_VERSION_9_0_1) +/* Called when a peek operation on a queue fails (timeout) */ +#undef traceQUEUE_PEEK_FAILED +#define traceQUEUE_PEEK_FAILED( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent3(PSF_EVENT_QUEUE_PEEK_FAILED, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent3(PSF_EVENT_SEMAPHORE_PEEK_FAILED, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent2(PSF_EVENT_MUTEX_PEEK_FAILED, (uint32_t)pxQueue, xTicksToWait); \ + break; \ + } + +/* Called when the task is blocked due to a peek operation on an empty queue */ +#undef traceBLOCKING_ON_QUEUE_PEEK +#define traceBLOCKING_ON_QUEUE_PEEK( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent3(PSF_EVENT_QUEUE_PEEK_BLOCK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent3(PSF_EVENT_SEMAPHORE_PEEK_BLOCK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent2(PSF_EVENT_MUTEX_PEEK_BLOCK, (uint32_t)pxQueue, xTicksToWait); \ + break; \ + } + +#endif /* (TRC_CFG_FREERTOS_VERSION > TRC_FREERTOS_VERSION_9_0_1) */ + +/* Called when a message is received in interrupt context, e.g., using xQueueReceiveFromISR */ +#undef traceQUEUE_RECEIVE_FROM_ISR +#define traceQUEUE_RECEIVE_FROM_ISR( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(PSF_EVENT_QUEUE_RECEIVE_FROMISR, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting - 1); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_TAKE_FROMISR, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting - 1); \ + break; \ + } + +/* Called when a message receive from interrupt context fails (since the queue was empty) */ +#undef traceQUEUE_RECEIVE_FROM_ISR_FAILED +#define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(PSF_EVENT_QUEUE_RECEIVE_FROMISR_FAILED, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_TAKE_FROMISR_FAILED, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + } + +/* Called on xQueuePeek */ +#undef traceQUEUE_PEEK +#define traceQUEUE_PEEK( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent3(PSF_EVENT_QUEUE_PEEK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent3(PSF_EVENT_SEMAPHORE_PEEK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_PEEK, (uint32_t)pxQueue); \ + break; \ + } + +/* Called in vTaskPrioritySet */ +#undef traceTASK_PRIORITY_SET +#define traceTASK_PRIORITY_SET( pxTask, uxNewPriority ) \ + prvTraceSaveObjectData(pxTask, uxNewPriority); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTask) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_PRIORITY, (uint32_t)pxTask, uxNewPriority); + +/* Called in vTaskPriorityInherit, which is called by Mutex operations */ +#undef traceTASK_PRIORITY_INHERIT +#define traceTASK_PRIORITY_INHERIT( pxTask, uxNewPriority ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTask) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_PRIO_INHERIT, (uint32_t)pxTask, uxNewPriority); + +/* Called in vTaskPriorityDisinherit, which is called by Mutex operations */ +#undef traceTASK_PRIORITY_DISINHERIT +#define traceTASK_PRIORITY_DISINHERIT( pxTask, uxNewPriority ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTask) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_PRIO_DISINHERIT, (uint32_t)pxTask, uxNewPriority); + +/* Called in vTaskResume */ +#undef traceTASK_RESUME +#define traceTASK_RESUME( pxTaskToResume ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTaskToResume) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_RESUME, (uint32_t)pxTaskToResume); + +/* Called in vTaskResumeFromISR */ +#undef traceTASK_RESUME_FROM_ISR +#define traceTASK_RESUME_FROM_ISR( pxTaskToResume ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTaskToResume) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_RESUME_FROMISR, (uint32_t)pxTaskToResume); + +#if (TRC_CFG_INCLUDE_MEMMANG_EVENTS == 1) + +#undef traceMALLOC +#define traceMALLOC( pvAddress, uiSize ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_MALLOC, (uint32_t)pvAddress, uiSize); + +#undef traceFREE +#define traceFREE( pvAddress, uiSize ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_FREE, (uint32_t)pvAddress, (uint32_t)(0 - uiSize)); /* "0 -" instead of just "-" to get rid of a warning... */ + +#endif /* (TRC_CFG_INCLUDE_MEMMANG_EVENTS == 1) */ + +#if (TRC_CFG_INCLUDE_TIMER_EVENTS == 1) + +/* Called in timer.c - xTimerCreate */ +#undef traceTIMER_CREATE +#define traceTIMER_CREATE(tmr) \ + TRACE_SET_OBJECT_FILTER(TIMER, tmr, CurrentFilterGroup); \ + prvTraceSaveSymbol(tmr, tmr->pcTimerName); \ + prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, tmr->pcTimerName, tmr); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TIMER, tmr) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TIMER_CREATE, (uint32_t)tmr, tmr->xTimerPeriodInTicks); + +#undef traceTIMER_CREATE_FAILED +#define traceTIMER_CREATE_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent0(PSF_EVENT_TIMER_CREATE_FAILED); + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) +#define traceTIMER_COMMAND_SEND_8_0_CASES(tmr) \ + case tmrCOMMAND_RESET: \ + prvTraceStoreEvent2((xReturn == pdPASS) ? PSF_EVENT_TIMER_RESET : PSF_EVENT_TIMER_RESET_FAILED, (uint32_t)tmr, xOptionalValue); \ + break; \ + case tmrCOMMAND_START_FROM_ISR: \ + prvTraceStoreEvent2((xReturn == pdPASS) ? PSF_EVENT_TIMER_START_FROMISR : PSF_EVENT_TIMER_START_FROMISR_FAILED, (uint32_t)tmr, xOptionalValue); \ + break; \ + case tmrCOMMAND_RESET_FROM_ISR: \ + prvTraceStoreEvent2((xReturn == pdPASS) ? PSF_EVENT_TIMER_RESET_FROMISR : PSF_EVENT_TIMER_RESET_FROMISR_FAILED, (uint32_t)tmr, xOptionalValue); \ + break; \ + case tmrCOMMAND_STOP_FROM_ISR: \ + prvTraceStoreEvent2((xReturn == pdPASS) ? PSF_EVENT_TIMER_STOP_FROMISR : PSF_EVENT_TIMER_STOP_FROMISR_FAILED, (uint32_t)tmr, xOptionalValue); \ + break; \ + case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR: \ + prvTraceStoreEvent2((xReturn == pdPASS) ? PSF_EVENT_TIMER_CHANGEPERIOD_FROMISR : PSF_EVENT_TIMER_CHANGEPERIOD_FROMISR_FAILED, (uint32_t)tmr, xOptionalValue); \ + break; +#else /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X */ +#define traceTIMER_COMMAND_SEND_8_0_CASES(tmr) +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X */ + +/* Note that xCommandID can never be tmrCOMMAND_EXECUTE_CALLBACK (-1) since the trace macro is not called in that case */ +#undef traceTIMER_COMMAND_SEND +#define traceTIMER_COMMAND_SEND(tmr, xCommandID, xOptionalValue, xReturn) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TIMER, tmr) & CurrentFilterMask) \ + switch(xCommandID) \ + { \ + case tmrCOMMAND_START: \ + prvTraceStoreEvent1((xReturn == pdPASS) ? PSF_EVENT_TIMER_START : PSF_EVENT_TIMER_START_FAILED, (uint32_t)tmr); \ + break; \ + case tmrCOMMAND_STOP: \ + prvTraceStoreEvent1((xReturn == pdPASS) ? PSF_EVENT_TIMER_STOP : PSF_EVENT_TIMER_STOP_FAILED, (uint32_t)tmr); \ + break; \ + case tmrCOMMAND_CHANGE_PERIOD: \ + prvTraceStoreEvent2((xReturn == pdPASS) ? PSF_EVENT_TIMER_CHANGEPERIOD : PSF_EVENT_TIMER_CHANGEPERIOD_FAILED, (uint32_t)tmr, xOptionalValue); \ + break; \ + case tmrCOMMAND_DELETE: \ + prvTraceStoreEvent1((xReturn == pdPASS) ? PSF_EVENT_TIMER_DELETE : PSF_EVENT_TIMER_DELETE_FAILED, (uint32_t)tmr); \ + break; \ + traceTIMER_COMMAND_SEND_8_0_CASES(tmr) \ + } + +#undef traceTIMER_EXPIRED +#define traceTIMER_EXPIRED(tmr) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TIMER, tmr) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TIMER_EXPIRED, (uint32_t)tmr->pxCallbackFunction, (uint32_t)tmr->pvTimerID); + +#endif /* #if (TRC_CFG_INCLUDE_TIMER_EVENTS == 1) */ + + +#if (TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS == 1) + +#undef tracePEND_FUNC_CALL +#define tracePEND_FUNC_CALL(func, arg1, arg2, ret) \ + prvTraceStoreEvent1((ret == pdPASS) ? PSF_EVENT_TIMER_PENDFUNCCALL : PSF_EVENT_TIMER_PENDFUNCCALL_FAILED, (uint32_t)func); + +#undef tracePEND_FUNC_CALL_FROM_ISR +#define tracePEND_FUNC_CALL_FROM_ISR(func, arg1, arg2, ret) \ + prvTraceStoreEvent1((ret == pdPASS) ? PSF_EVENT_TIMER_PENDFUNCCALL_FROMISR : PSF_EVENT_TIMER_PENDFUNCCALL_FROMISR_FAILED, (uint32_t)func); + +#endif /* (TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS == 1) */ + +#if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1) + +#undef traceEVENT_GROUP_CREATE +#define traceEVENT_GROUP_CREATE(eg) \ + TRACE_SET_OBJECT_FILTER(EVENTGROUP, eg, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_EVENTGROUP_CREATE, (uint32_t)eg); + +#undef traceEVENT_GROUP_DELETE +#define traceEVENT_GROUP_DELETE(eg) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_EVENTGROUP_DELETE, (uint32_t)eg); \ + prvTraceDeleteSymbol(eg); + +#undef traceEVENT_GROUP_CREATE_FAILED +#define traceEVENT_GROUP_CREATE_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent0(PSF_EVENT_EVENTGROUP_CREATE_FAILED); + +#undef traceEVENT_GROUP_SYNC_BLOCK +#define traceEVENT_GROUP_SYNC_BLOCK(eg, bitsToSet, bitsToWaitFor) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_EVENTGROUP_SYNC_BLOCK, (uint32_t)eg, bitsToWaitFor); + +#undef traceEVENT_GROUP_SYNC_END +#define traceEVENT_GROUP_SYNC_END(eg, bitsToSet, bitsToWaitFor, wasTimeout) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2((wasTimeout != pdTRUE) ? PSF_EVENT_EVENTGROUP_SYNC : PSF_EVENT_EVENTGROUP_SYNC_FAILED, (uint32_t)eg, bitsToWaitFor); + +#undef traceEVENT_GROUP_WAIT_BITS_BLOCK +#define traceEVENT_GROUP_WAIT_BITS_BLOCK(eg, bitsToWaitFor) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_EVENTGROUP_WAITBITS_BLOCK, (uint32_t)eg, bitsToWaitFor); + +#undef traceEVENT_GROUP_WAIT_BITS_END +#define traceEVENT_GROUP_WAIT_BITS_END(eg, bitsToWaitFor, wasTimeout) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2((wasTimeout != pdTRUE) ? PSF_EVENT_EVENTGROUP_WAITBITS : PSF_EVENT_EVENTGROUP_WAITBITS_FAILED, (uint32_t)eg, bitsToWaitFor); + +#undef traceEVENT_GROUP_CLEAR_BITS +#define traceEVENT_GROUP_CLEAR_BITS(eg, bitsToClear) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_EVENTGROUP_CLEARBITS, (uint32_t)eg, bitsToClear); + +#undef traceEVENT_GROUP_CLEAR_BITS_FROM_ISR +#define traceEVENT_GROUP_CLEAR_BITS_FROM_ISR(eg, bitsToClear) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_EVENTGROUP_CLEARBITS_FROMISR, (uint32_t)eg, bitsToClear); + +#undef traceEVENT_GROUP_SET_BITS +#define traceEVENT_GROUP_SET_BITS(eg, bitsToSet) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_EVENTGROUP_SETBITS, (uint32_t)eg, bitsToSet); + +#undef traceEVENT_GROUP_SET_BITS_FROM_ISR +#define traceEVENT_GROUP_SET_BITS_FROM_ISR(eg, bitsToSet) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_EVENTGROUP_SETBITS_FROMISR, (uint32_t)eg, bitsToSet); + +#endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1) */ + +#undef traceTASK_NOTIFY_TAKE +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0) +#define traceTASK_NOTIFY_TAKE() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask){ \ + if (pxCurrentTCB->ucNotifyState == taskNOTIFICATION_RECEIVED) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_TAKE, (uint32_t)pxCurrentTCB, xTicksToWait); \ + else \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_TAKE_FAILED, (uint32_t)pxCurrentTCB, xTicksToWait);} +#else /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ +#define traceTASK_NOTIFY_TAKE() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask){ \ + if (pxCurrentTCB->eNotifyState == eNotified) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_TAKE, (uint32_t)pxCurrentTCB, xTicksToWait); \ + else \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_TAKE_FAILED, (uint32_t)pxCurrentTCB, xTicksToWait);} +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ + +#undef traceTASK_NOTIFY_TAKE_BLOCK +#define traceTASK_NOTIFY_TAKE_BLOCK() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_TAKE_BLOCK, (uint32_t)pxCurrentTCB, xTicksToWait); + +#undef traceTASK_NOTIFY_WAIT +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0) +#define traceTASK_NOTIFY_WAIT() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask){ \ + if (pxCurrentTCB->ucNotifyState == taskNOTIFICATION_RECEIVED) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_WAIT, (uint32_t)pxCurrentTCB, xTicksToWait); \ + else \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_WAIT_FAILED, (uint32_t)pxCurrentTCB, xTicksToWait);} +#else /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ +#define traceTASK_NOTIFY_WAIT() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask){ \ + if (pxCurrentTCB->eNotifyState == eNotified) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_WAIT, (uint32_t)pxCurrentTCB, xTicksToWait); \ + else \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_WAIT_FAILED, (uint32_t)pxCurrentTCB, xTicksToWait);} +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ + +#undef traceTASK_NOTIFY_WAIT_BLOCK +#define traceTASK_NOTIFY_WAIT_BLOCK() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_WAIT_BLOCK, (uint32_t)pxCurrentTCB, xTicksToWait); + +#undef traceTASK_NOTIFY +#define traceTASK_NOTIFY() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, xTaskToNotify) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_NOTIFY, (uint32_t)xTaskToNotify); + +#undef traceTASK_NOTIFY_FROM_ISR +#define traceTASK_NOTIFY_FROM_ISR() \ + if (TRACE_GET_OBJECT_FILTER(TASK, xTaskToNotify) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_NOTIFY_FROM_ISR, (uint32_t)xTaskToNotify); + +#undef traceTASK_NOTIFY_GIVE_FROM_ISR +#define traceTASK_NOTIFY_GIVE_FROM_ISR() \ + if (TRACE_GET_OBJECT_FILTER(TASK, xTaskToNotify) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_NOTIFY_GIVE_FROM_ISR, (uint32_t)xTaskToNotify); + +#undef traceQUEUE_REGISTRY_ADD +#define traceQUEUE_REGISTRY_ADD(object, name) \ + prvTraceSaveSymbol(object, (const char*)name); \ + prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, name, object); + +#if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) + +#undef traceSTREAM_BUFFER_CREATE +#define traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer ) \ + TRACE_SET_OBJECT_FILTER(STREAMBUFFER, pxStreamBuffer, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, pxStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent2(xIsMessageBuffer == 1 ? PSF_EVENT_MESSAGEBUFFER_CREATE : PSF_EVENT_STREAMBUFFER_CREATE, (uint32_t)pxStreamBuffer, xBufferSizeBytes); + +#undef traceSTREAM_BUFFER_CREATE_FAILED +#define traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(xIsMessageBuffer == 1 ? PSF_EVENT_MESSAGEBUFFER_CREATE_FAILED : PSF_EVENT_STREAMBUFFER_CREATE_FAILED, 0 , xBufferSizeBytes); + +#undef traceSTREAM_BUFFER_CREATE_STATIC_FAILED +#define traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer ) \ + traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer ) + +#undef traceSTREAM_BUFFER_DELETE +#define traceSTREAM_BUFFER_DELETE( xStreamBuffer ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, pxStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent2(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_DELETE : PSF_EVENT_STREAMBUFFER_DELETE, (uint32_t)xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); \ + prvTraceDeleteSymbol(xStreamBuffer); + +#undef traceSTREAM_BUFFER_RESET +#define traceSTREAM_BUFFER_RESET( xStreamBuffer ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent2(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_RESET : PSF_EVENT_STREAMBUFFER_RESET, (uint32_t)xStreamBuffer, 0); + +#undef traceSTREAM_BUFFER_SEND +#define traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent2(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_SEND : PSF_EVENT_STREAMBUFFER_SEND, (uint32_t)xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); + +#undef traceBLOCKING_ON_STREAM_BUFFER_SEND +#define traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent1(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_SEND_BLOCK : PSF_EVENT_STREAMBUFFER_SEND_BLOCK, (uint32_t)xStreamBuffer); + +#undef traceSTREAM_BUFFER_SEND_FAILED +#define traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent1(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_SEND_FAILED : PSF_EVENT_STREAMBUFFER_SEND_FAILED, (uint32_t)xStreamBuffer); + +#undef traceSTREAM_BUFFER_RECEIVE +#define traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent2(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_RECEIVE: PSF_EVENT_STREAMBUFFER_RECEIVE, (uint32_t)xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); + +#undef traceBLOCKING_ON_STREAM_BUFFER_RECEIVE +#define traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent1(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_RECEIVE_BLOCK: PSF_EVENT_STREAMBUFFER_RECEIVE_BLOCK, (uint32_t)xStreamBuffer); + +#undef traceSTREAM_BUFFER_RECEIVE_FAILED +#define traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent1(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_RECEIVE_FAILED: PSF_EVENT_STREAMBUFFER_RECEIVE_FAILED, (uint32_t)xStreamBuffer); + +#undef traceSTREAM_BUFFER_SEND_FROM_ISR +#define traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn ) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + { \ + if ( xReturn > ( size_t ) 0 ) \ + { \ + prvTraceStoreEvent2(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_SEND_FROM_ISR : PSF_EVENT_STREAMBUFFER_SEND_FROM_ISR, (uint32_t)xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); \ + } \ + else \ + { \ + prvTraceStoreEvent1(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_SEND_FROM_ISR_FAILED : PSF_EVENT_STREAMBUFFER_SEND_FROM_ISR_FAILED, (uint32_t)xStreamBuffer); \ + } \ + } + +#undef traceSTREAM_BUFFER_RECEIVE_FROM_ISR +#define traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength ) \ +if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + { \ + if ( xReceivedLength > ( size_t ) 0 ) \ + { \ + prvTraceStoreEvent2(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_RECEIVE_FROM_ISR : PSF_EVENT_STREAMBUFFER_RECEIVE_FROM_ISR, (uint32_t)xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); \ + } \ + else \ + { \ + prvTraceStoreEvent1(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_RECEIVE_FROM_ISR_FAILED : PSF_EVENT_STREAMBUFFER_RECEIVE_FROM_ISR_FAILED, (uint32_t)xStreamBuffer); \ + } \ + } + +#endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) */ + +#endif /* (TRC_CFG_SCHEDULING_ONLY == 0) */ + +#endif /* (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) */ + +#else /* (TRC_USE_TRACEALYZER_RECORDER == 1) */ + +/* When recorder is disabled */ +#define vTraceSetQueueName(object, name) +#define vTraceSetSemaphoreName(object, name) +#define vTraceSetMutexName(object, name) +#define vTraceSetEventGroupName(object, name) +#define vTraceSetStreamBufferName(object, name) +#define vTraceSetMessageBufferName(object, name) + +#endif /* (TRC_USE_TRACEALYZER_RECORDER == 1) */ + +#ifdef __cplusplus +} +#endif + +#endif /* TRC_KERNEL_PORT_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h new file mode 100644 index 000000000..2cfcbbfd5 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcKernelPort.h @@ -0,0 +1,2565 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * FreeRTOS-specific definitions needed by the trace recorder + * + * + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_KERNEL_PORT_H +#define TRC_KERNEL_PORT_H + +#include "FreeRTOS.h" /* Defines configUSE_TRACE_FACILITY */ +#include "trcPortDefines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define TRC_USE_TRACEALYZER_RECORDER configUSE_TRACE_FACILITY + +/*** FreeRTOS version codes **************************************************/ +#define FREERTOS_VERSION_NOT_SET 0 +#define TRC_FREERTOS_VERSION_7_3 1 /* v7.3 is earliest supported.*/ +#define TRC_FREERTOS_VERSION_7_4 2 +#define TRC_FREERTOS_VERSION_7_5_OR_7_6 3 +#define TRC_FREERTOS_VERSION_8_X 4 /* Any v8.x.x*/ +#define TRC_FREERTOS_VERSION_9_0_0 5 +#define TRC_FREERTOS_VERSION_9_0_1 6 +#define TRC_FREERTOS_VERSION_9_0_2 7 +#define TRC_FREERTOS_VERSION_10_0_0 8 /* If using FreeRTOS v10.0.0 or later version */ + +#define TRC_FREERTOS_VERSION_9_X 42 /* Not allowed anymore */ + +#if (TRC_CFG_FREERTOS_VERSION == TRC_FREERTOS_VERSION_9_X) +/* This setting for TRC_CFG_FREERTOS_VERSION is no longer allowed as v9.0.1 needs special handling. */ +#error "Please specify your exact FreeRTOS version in trcConfig.h, from the options listed above." +#endif + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +#define prvGetStreamBufferType(x) ((( StreamBuffer_t * )x )->ucFlags & sbFLAGS_IS_MESSAGE_BUFFER) +#else +#define prvGetStreamBufferType(x) 0 +#endif + +/* Added mainly for our internal testing. This makes it easier to create test applications that + runs on multiple FreeRTOS versions. */ +#if (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_8_X) + /* FreeRTOS v7.0 and later */ + #define STRING_CAST(x) ( (signed char*) x ) + #define TickType portTickType +#else + /* FreeRTOS v8.0 and later */ + #define STRING_CAST(x) x + #define TickType TickType_t +#endif + +#if (defined(TRC_USE_TRACEALYZER_RECORDER)) && (TRC_USE_TRACEALYZER_RECORDER == 1) + +/******************************************************************************* + * INCLUDE_xTaskGetCurrentTaskHandle must be set to 1 for tracing to work properly + ******************************************************************************/ +#undef INCLUDE_xTaskGetCurrentTaskHandle +#define INCLUDE_xTaskGetCurrentTaskHandle 1 + +#if (TRC_CFG_SCHEDULING_ONLY == 0) +/******************************************************************************* + * vTraceSetQueueName(void* object, const char* name) + * + * Parameter object: pointer to the Queue that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for Queue objects for display in Tracealyzer. + ******************************************************************************/ +void vTraceSetQueueName(void* object, const char* name); + +/******************************************************************************* + * vTraceSetSemaphoreName(void* object, const char* name) + * + * Parameter object: pointer to the Semaphore that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for Semaphore objects for display in Tracealyzer. + ******************************************************************************/ +void vTraceSetSemaphoreName(void* object, const char* name); + +/******************************************************************************* + * vTraceSetMutexName(void* object, const char* name) + * + * Parameter object: pointer to the Mutex that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for Semaphore objects for display in Tracealyzer. + ******************************************************************************/ +void vTraceSetMutexName(void* object, const char* name); + +#if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1) +/******************************************************************************* +* vTraceSetEventGroupName(void* object, const char* name) +* +* Parameter object: pointer to the EventGroup that shall be named +* Parameter name: the name to set (const string literal) +* +* Sets a name for EventGroup objects for display in Tracealyzer. +******************************************************************************/ +void vTraceSetEventGroupName(void* object, const char* name); +#else /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1) */ +#define vTraceSetEventGroupName(object, name) /* Do nothing */ +#endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1) */ + +#if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) +/******************************************************************************* +* vTraceSetStreamBufferName(void* object, const char* name) +* +* Parameter object: pointer to the StreamBuffer that shall be named +* Parameter name: the name to set (const string literal) +* +* Sets a name for StreamBuffer objects for display in Tracealyzer. +******************************************************************************/ +void vTraceSetStreamBufferName(void* object, const char* name); +#else /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) */ +#define vTraceSetStreamBufferName(object, name) /* Do nothing */ +#endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) */ + +#if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) +/******************************************************************************* + * vTraceSetMessageBufferName(void* object, const char* name) + * + * Parameter object: pointer to the MessageBuffer that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for MessageBuffer objects for display in Tracealyzer. + ******************************************************************************/ +void vTraceSetMessageBufferName(void* object, const char* name); +#else /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) */ +#define vTraceSetMessageBufferName(object, name) /* Do nothing */ +#endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) */ + +#else /* (TRC_CFG_SCHEDULING_ONLY == 0) */ + +#define vTraceSetQueueName(object, name) /* Do nothing */ +#define vTraceSetSemaphoreName(object, name) /* Do nothing */ +#define vTraceSetMutexName(object, name) /* Do nothing */ +#define vTraceSetEventGroupName(object, name) /* Do nothing */ +#define vTraceSetStreamBufferName(object, name) /* Do nothing */ +#define vTraceSetMessageBufferName(object, name) /* Do nothing */ + +#endif /* (TRC_CFG_SCHEDULING_ONLY == 0) */ + +/******************************************************************************* + * Note: Setting names for event groups is difficult to support, this has been + * excluded intentionally. This since we don't know if event_groups.c is + * included in the build, so referencing it from the recorder may cause errors. + ******************************************************************************/ + +/* Gives the currently executing task (wrapper for RTOS-specific function) */ +void* prvTraceGetCurrentTaskHandle(void); + +#if (((TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) && (TRC_CFG_INCLUDE_ISR_TRACING == 1)) || (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)) +/* Tells if the scheduler currently is suspended (task-switches can't occur) */ +unsigned char prvTraceIsSchedulerSuspended(void); + +/******************************************************************************* + * INCLUDE_xTaskGetSchedulerState must be set to 1 for tracing to work properly + ******************************************************************************/ +#undef INCLUDE_xTaskGetSchedulerState +#define INCLUDE_xTaskGetSchedulerState 1 + +#endif /* (((TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) && (TRC_CFG_INCLUDE_ISR_TRACING == 1)) || (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)) */ + +#define TRACE_KERNEL_VERSION 0x1AA1 +#define TRACE_TICK_RATE_HZ configTICK_RATE_HZ /* Defined in "FreeRTOS.h" */ +#define TRACE_CPU_CLOCK_HZ configCPU_CLOCK_HZ /* Defined in "FreeRTOSConfig.h" */ +#define TRACE_GET_CURRENT_TASK() prvTraceGetCurrentTaskHandle() + +#define TRACE_GET_OS_TICKS() (uiTraceTickCount) /* Streaming only */ + +/* If using dynamic allocation of snapshot trace buffer... */ +#define TRACE_MALLOC(size) pvPortMalloc(size) + +#if defined(configUSE_TIMERS) +#if (configUSE_TIMERS == 1) +#undef INCLUDE_xTimerGetTimerDaemonTaskHandle +#define INCLUDE_xTimerGetTimerDaemonTaskHandle 1 +#endif /* configUSE_TIMERS == 1*/ +#endif /* configUSE_TIMERS */ + +/* For ARM Cortex-M devices - assumes the ARM CMSIS API is available */ +#if (defined (__CORTEX_M)) + #define TRACE_ALLOC_CRITICAL_SECTION() uint32_t __irq_status; + #define TRACE_ENTER_CRITICAL_SECTION() {__irq_status = __get_PRIMASK(); __set_PRIMASK(1);} /* PRIMASK disables ALL interrupts - allows for tracing in any ISR */ + #define TRACE_EXIT_CRITICAL_SECTION() {__set_PRIMASK(__irq_status);} +#endif + +#if ((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_CORTEX_A9) || (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_Renesas_RX600) || (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_MICROCHIP_PIC24_PIC32) || (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_Altera_NiosII)) + #define TRACE_ALLOC_CRITICAL_SECTION() int __irq_status; + #define TRACE_ENTER_CRITICAL_SECTION() {__irq_status = portSET_INTERRUPT_MASK_FROM_ISR();} + #define TRACE_EXIT_CRITICAL_SECTION() {portCLEAR_INTERRUPT_MASK_FROM_ISR(__irq_status);} +#endif + +#if (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_Win32) + /* In the Win32 port, there are no real interrupts, so we can use the normal critical sections */ + #define TRACE_ALLOC_CRITICAL_SECTION() + #define TRACE_ENTER_CRITICAL_SECTION() portENTER_CRITICAL() + #define TRACE_EXIT_CRITICAL_SECTION() portEXIT_CRITICAL() +#endif + +#if (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_POWERPC_Z4) +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) + /* FreeRTOS v8.0 or later */ + #define TRACE_ALLOC_CRITICAL_SECTION() UBaseType_t __irq_status; + #define TRACE_ENTER_CRITICAL_SECTION() {__irq_status = portSET_INTERRUPT_MASK_FROM_ISR();} + #define TRACE_EXIT_CRITICAL_SECTION() {portCLEAR_INTERRUPT_MASK_FROM_ISR(__irq_status);} +#else + /* FreeRTOS v7.x */ + #define TRACE_ALLOC_CRITICAL_SECTION() unsigned portBASE_TYPE __irq_status; + #define TRACE_ENTER_CRITICAL_SECTION() {__irq_status = portSET_INTERRUPT_MASK_FROM_ISR();} + #define TRACE_EXIT_CRITICAL_SECTION() {portCLEAR_INTERRUPT_MASK_FROM_ISR(__irq_status);} +#endif +#endif + +#ifndef TRACE_ENTER_CRITICAL_SECTION + #error "This hardware port has no definition for critical sections! See http://percepio.com/2014/10/27/how-to-define-critical-sections-for-the-recorder/" +#endif + + +#if (TRC_CFG_FREERTOS_VERSION == TRC_FREERTOS_VERSION_9_0_1) + /****************************************************************************** + * Fix for FreeRTOS v9.0.1 to correctly identify xQueuePeek events. + * + * In FreeRTOS v9.0.1, the below trace hooks are incorrectly used from three + * different functions. This as the earlier function xQueueGenericReceive + * has been replaced by xQueuePeek, xQueueSemaphoreTake and xQueueReceive. + * + * xQueueGenericReceive had a parameter "xJustPeeking", used by the trace hooks + * to tell between xQueuePeek events and others. This is no longer present, so + * we need another way to correctly identify peek events. Since all three + * functions call the same trace macros, the context of these macro is unknown. + * + * We therefore check the __LINE__ macro inside of the trace macros. This gives + * the line number of queue.c, where the macros are used. This can be used to + * tell if the context is xQueuePeek or another function. + * __LINE__ is a standard compiler feature since ancient times, so it should + * work on all common compilers. + * + * This might seem as a quite brittle and unusual solution, but works in this + * particular case and is only for FreeRTOS v9.0.1. + * Future versions of FreeRTOS should not need this fix, as we have submitted + * a correction of queue.c with individual trace macros for each function. + ******************************************************************************/ +#define isQueueReceiveHookActuallyPeek (__LINE__ > 1674) /* Half way between the closes trace points */ + +#elif (TRC_CFG_FREERTOS_VERSION <= TRC_FREERTOS_VERSION_9_0_0) +#define isQueueReceiveHookActuallyPeek xJustPeeking + +#elif (TRC_CFG_FREERTOS_VERSION > TRC_FREERTOS_VERSION_9_0_1) +#define isQueueReceiveHookActuallyPeek (__LINE__ < 0) /* instead of pdFALSE to fix a warning of "constant condition" */ + +#endif + +extern uint16_t CurrentFilterMask; + +extern uint16_t CurrentFilterGroup; + +uint8_t prvTraceGetQueueType(void* handle); + +uint16_t prvTraceGetTaskNumberLow16(void* handle); +uint16_t prvTraceGetTaskNumberHigh16(void* handle); +void prvTraceSetTaskNumberLow16(void* handle, uint16_t value); +void prvTraceSetTaskNumberHigh16(void* handle, uint16_t value); + +uint16_t prvTraceGetQueueNumberLow16(void* handle); +uint16_t prvTraceGetQueueNumberHigh16(void* handle); +void prvTraceSetQueueNumberLow16(void* handle, uint16_t value); +void prvTraceSetQueueNumberHigh16(void* handle, uint16_t value); + +#if (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +uint16_t prvTraceGetTimerNumberLow16(void* handle); +uint16_t prvTraceGetTimerNumberHigh16(void* handle); +void prvTraceSetTimerNumberLow16(void* handle, uint16_t value); +void prvTraceSetTimerNumberHigh16(void* handle, uint16_t value); +#endif /* (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +uint16_t prvTraceGetEventGroupNumberLow16(void* handle); +uint16_t prvTraceGetEventGroupNumberHigh16(void* handle); +void prvTraceSetEventGroupNumberLow16(void* handle, uint16_t value); +void prvTraceSetEventGroupNumberHigh16(void* handle, uint16_t value); +#endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +uint16_t prvTraceGetStreamBufferNumberLow16(void* handle); +uint16_t prvTraceGetStreamBufferNumberHigh16(void* handle); +void prvTraceSetStreamBufferNumberLow16(void* handle, uint16_t value); +void prvTraceSetStreamBufferNumberHigh16(void* handle, uint16_t value); +#endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#define TRACE_GET_TASK_FILTER(pxTask) prvTraceGetTaskNumberHigh16((void*)pxTask) +#define TRACE_SET_TASK_FILTER(pxTask, group) prvTraceSetTaskNumberHigh16((void*)pxTask, group) + +#define TRACE_GET_QUEUE_FILTER(pxObject) prvTraceGetQueueNumberHigh16((void*)pxObject) +#define TRACE_SET_QUEUE_FILTER(pxObject, group) prvTraceSetQueueNumberHigh16((void*)pxObject, group) + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +#define TRACE_GET_EVENTGROUP_FILTER(pxObject) prvTraceGetEventGroupNumberHigh16((void*)pxObject) +#define TRACE_SET_EVENTGROUP_FILTER(pxObject, group) prvTraceSetEventGroupNumberHigh16((void*)pxObject, group) +#else /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ +/* FreeRTOS versions before v10.0 does not support filtering for event groups */ +#define TRACE_GET_EVENTGROUP_FILTER(pxObject) 1 +#define TRACE_SET_EVENTGROUP_FILTER(pxObject, group) +#endif /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +#define TRACE_GET_TIMER_FILTER(pxObject) prvTraceGetTimerNumberHigh16((void*)pxObject) +#define TRACE_SET_TIMER_FILTER(pxObject, group) prvTraceSetTimerNumberHigh16((void*)pxObject, group) +#else /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ +/* FreeRTOS versions before v10.0 does not support filtering for timers */ +#define TRACE_GET_TIMER_FILTER(pxObject) 1 +#define TRACE_SET_TIMER_FILTER(pxObject, group) +#endif /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#define TRACE_GET_STREAMBUFFER_FILTER(pxObject) prvTraceGetStreamBufferNumberHigh16((void*)pxObject) +#define TRACE_SET_STREAMBUFFER_FILTER(pxObject, group) prvTraceSetStreamBufferNumberHigh16((void*)pxObject, group) + +/* We can only support filtering if FreeRTOS is at least v7.4 */ +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_7_4) +#define TRACE_GET_OBJECT_FILTER(CLASS, pxObject) TRACE_GET_##CLASS##_FILTER(pxObject) +#define TRACE_SET_OBJECT_FILTER(CLASS, pxObject, group) TRACE_SET_##CLASS##_FILTER(pxObject, group) +#else /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_7_4) */ +#define TRACE_GET_OBJECT_FILTER(CLASS, pxObject) 1 +#define TRACE_SET_OBJECT_FILTER(CLASS, pxObject, group) +#endif /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_7_4) */ + +/******************************************************************************/ +/*** Definitions for Snapshot mode ********************************************/ +/******************************************************************************/ +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) + +/*** The object classes *******************************************************/ + +#define TRACE_NCLASSES 9 +#define TRACE_CLASS_QUEUE ((traceObjectClass)0) +#define TRACE_CLASS_SEMAPHORE ((traceObjectClass)1) +#define TRACE_CLASS_MUTEX ((traceObjectClass)2) +#define TRACE_CLASS_TASK ((traceObjectClass)3) +#define TRACE_CLASS_ISR ((traceObjectClass)4) +#define TRACE_CLASS_TIMER ((traceObjectClass)5) +#define TRACE_CLASS_EVENTGROUP ((traceObjectClass)6) +#define TRACE_CLASS_STREAMBUFFER ((traceObjectClass)7) +#define TRACE_CLASS_MESSAGEBUFFER ((traceObjectClass)8) + +/*** Definitions for Object Table ********************************************/ +#define TRACE_KERNEL_OBJECT_COUNT ((TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER) + (TRC_CFG_NEVENTGROUP) + (TRC_CFG_NSTREAMBUFFER) + (TRC_CFG_NMESSAGEBUFFER)) + +/* Queue properties (except name): current number of message in queue */ +#define PropertyTableSizeQueue ((TRC_CFG_NAME_LEN_QUEUE) + 1) + +/* Semaphore properties (except name): state (signaled = 1, cleared = 0) */ +#define PropertyTableSizeSemaphore ((TRC_CFG_NAME_LEN_SEMAPHORE) + 1) + +/* Mutex properties (except name): owner (task handle, 0 = free) */ +#define PropertyTableSizeMutex ((TRC_CFG_NAME_LEN_MUTEX) + 1) + +/* Task properties (except name): Byte 0: Current priority + Byte 1: state (if already active) + Byte 2: legacy, not used + Byte 3: legacy, not used */ +#define PropertyTableSizeTask ((TRC_CFG_NAME_LEN_TASK) + 4) + +/* ISR properties: Byte 0: priority + Byte 1: state (if already active) */ +#define PropertyTableSizeISR ((TRC_CFG_NAME_LEN_ISR) + 2) + +/* TRC_CFG_NTIMER properties: Byte 0: state (unused for now) */ +#define PropertyTableSizeTimer ((TRC_CFG_NAME_LEN_TIMER) + 1) + +/* TRC_CFG_NEVENTGROUP properties: Byte 0-3: state (unused for now)*/ +#define PropertyTableSizeEventGroup ((TRC_CFG_NAME_LEN_EVENTGROUP) + 4) + +/* TRC_CFG_NSTREAMBUFFER properties: Byte 0-3: state (unused for now)*/ +#define PropertyTableSizeStreamBuffer ((TRC_CFG_NAME_LEN_STREAMBUFFER) + 4) + +/* TRC_CFG_NMESSAGEBUFFER properties: Byte 0-3: state (unused for now)*/ +#define PropertyTableSizeMessageBuffer ((TRC_CFG_NAME_LEN_MESSAGEBUFFER) + 4) + + +/* The layout of the byte array representing the Object Property Table */ +#define StartIndexQueue (0) +#define StartIndexSemaphore (StartIndexQueue + (TRC_CFG_NQUEUE) * PropertyTableSizeQueue) +#define StartIndexMutex (StartIndexSemaphore + (TRC_CFG_NSEMAPHORE) * PropertyTableSizeSemaphore) +#define StartIndexTask (StartIndexMutex + (TRC_CFG_NMUTEX) * PropertyTableSizeMutex) +#define StartIndexISR (StartIndexTask + (TRC_CFG_NTASK) * PropertyTableSizeTask) +#define StartIndexTimer (StartIndexISR + (TRC_CFG_NISR) * PropertyTableSizeISR) +#define StartIndexEventGroup (StartIndexTimer + (TRC_CFG_NTIMER) * PropertyTableSizeTimer) +#define StartIndexStreamBuffer (StartIndexEventGroup + (TRC_CFG_NEVENTGROUP) * PropertyTableSizeEventGroup) +#define StartIndexMessageBuffer (StartIndexStreamBuffer + (TRC_CFG_NSTREAMBUFFER) * PropertyTableSizeStreamBuffer) + +/* Number of bytes used by the object table */ +#define TRACE_OBJECT_TABLE_SIZE (StartIndexMessageBuffer + (TRC_CFG_NMESSAGEBUFFER) * PropertyTableSizeMessageBuffer) + +/* Flag to tell the context of tracePEND_FUNC_CALL_FROM_ISR */ +extern int uiInEventGroupSetBitsFromISR; + +/* Initialization of the object property table */ +void vTraceInitObjectPropertyTable(void); + +/* Initialization of the handle mechanism, see e.g, prvTraceGetObjectHandle */ +void vTraceInitObjectHandleStack(void); + +/* Returns the "Not enough handles" error message for the specified object class */ +const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass); + +void* prvTraceGetCurrentTaskHandle(void); + +/****************************************************************************** + * TraceQueueClassTable + * Translates a FreeRTOS QueueType into trace objects classes (TRACE_CLASS_). + * Has one entry for each QueueType, gives TRACE_CLASS ID. + ******************************************************************************/ +extern traceObjectClass TraceQueueClassTable[5]; + + +/*** Event codes for snapshot mode - must match Tracealyzer config files ******/ + +#define NULL_EVENT (0x00UL) + +/******************************************************************************* + * EVENTGROUP_DIV + * + * Miscellaneous events. + ******************************************************************************/ +#define EVENTGROUP_DIV (NULL_EVENT + 1UL) /*0x01*/ +#define DIV_XPS (EVENTGROUP_DIV + 0UL) /*0x01*/ +#define DIV_TASK_READY (EVENTGROUP_DIV + 1UL) /*0x02*/ +#define DIV_NEW_TIME (EVENTGROUP_DIV + 2UL) /*0x03*/ + +/******************************************************************************* + * EVENTGROUP_TS + * + * Events for storing task-switches and interrupts. The RESUME events are + * generated if the task/interrupt is already marked active. + ******************************************************************************/ +#define EVENTGROUP_TS (EVENTGROUP_DIV + 3UL) /*0x04*/ +#define TS_ISR_BEGIN (EVENTGROUP_TS + 0UL) /*0x04*/ +#define TS_ISR_RESUME (EVENTGROUP_TS + 1UL) /*0x05*/ +#define TS_TASK_BEGIN (EVENTGROUP_TS + 2UL) /*0x06*/ +#define TS_TASK_RESUME (EVENTGROUP_TS + 3UL) /*0x07*/ + +/******************************************************************************* + * EVENTGROUP_OBJCLOSE_NAME + * + * About Close Events + * When an object is evicted from the object property table (object close), two + * internal events are stored (EVENTGROUP_OBJCLOSE_NAME and + * EVENTGROUP_OBJCLOSE_PROP), containing the handle-name mapping and object + * properties valid up to this point. + ******************************************************************************/ +#define EVENTGROUP_OBJCLOSE_NAME_TRCSUCCESS (EVENTGROUP_TS + 4UL) /*0x08*/ + +/******************************************************************************* + * EVENTGROUP_OBJCLOSE_PROP + * + * The internal event carrying properties of deleted objects + * The handle and object class of the closed object is not stored in this event, + * but is assumed to be the same as in the preceding CLOSE event. Thus, these + * two events must be generated from within a critical section. + * When queues are closed, arg1 is the "state" property (i.e., number of + * buffered messages/signals). + * When actors are closed, arg1 is priority, arg2 is handle of the "instance + * finish" event, and arg3 is event code of the "instance finish" event. + * In this case, the lower three bits is the object class of the instance finish + * handle. The lower three bits are not used (always zero) when queues are + * closed since the queue type is given in the previous OBJCLOSE_NAME event. + ******************************************************************************/ +#define EVENTGROUP_OBJCLOSE_PROP_TRCSUCCESS (EVENTGROUP_OBJCLOSE_NAME_TRCSUCCESS + 8UL) /*0x10*/ + +/******************************************************************************* + * EVENTGROUP_CREATE + * + * The events in this group are used to log Kernel object creations. + * The lower three bits in the event code gives the object class, i.e., type of + * create operation (task, queue, semaphore, etc). + ******************************************************************************/ +#define EVENTGROUP_CREATE_OBJ_TRCSUCCESS (EVENTGROUP_OBJCLOSE_PROP_TRCSUCCESS + 8UL) /*0x18*/ + +/******************************************************************************* + * EVENTGROUP_SEND + * + * The events in this group are used to log Send/Give events on queues, + * semaphores and mutexes The lower three bits in the event code gives the + * object class, i.e., what type of object that is operated on (queue, semaphore + * or mutex). + ******************************************************************************/ +#define EVENTGROUP_SEND_TRCSUCCESS (EVENTGROUP_CREATE_OBJ_TRCSUCCESS + 8UL) /*0x20*/ + +/******************************************************************************* + * EVENTGROUP_RECEIVE + * + * The events in this group are used to log Receive/Take events on queues, + * semaphores and mutexes. The lower three bits in the event code gives the + * object class, i.e., what type of object that is operated on (queue, semaphore + * or mutex). + ******************************************************************************/ +#define EVENTGROUP_RECEIVE_TRCSUCCESS (EVENTGROUP_SEND_TRCSUCCESS + 8UL) /*0x28*/ + +/* Send/Give operations, from ISR */ +#define EVENTGROUP_SEND_FROM_ISR_TRCSUCCESS \ + (EVENTGROUP_RECEIVE_TRCSUCCESS + 8UL) /*0x30*/ + +/* Receive/Take operations, from ISR */ +#define EVENTGROUP_RECEIVE_FROM_ISR_TRCSUCCESS \ + (EVENTGROUP_SEND_FROM_ISR_TRCSUCCESS + 8UL) /*0x38*/ + +/* "Failed" event type versions of above (timeout, failed allocation, etc) */ +#define EVENTGROUP_KSE_TRCFAILED \ + (EVENTGROUP_RECEIVE_FROM_ISR_TRCSUCCESS + 8UL) /*0x40*/ + +/* Failed create calls - memory allocation failed */ +#define EVENTGROUP_CREATE_OBJ_TRCFAILED (EVENTGROUP_KSE_TRCFAILED) /*0x40*/ + +/* Failed send/give - timeout! */ +#define EVENTGROUP_SEND_TRCFAILED (EVENTGROUP_CREATE_OBJ_TRCFAILED + 8UL) /*0x48*/ + +/* Failed receive/take - timeout! */ +#define EVENTGROUP_RECEIVE_TRCFAILED (EVENTGROUP_SEND_TRCFAILED + 8UL) /*0x50*/ + +/* Failed non-blocking send/give - queue full */ +#define EVENTGROUP_SEND_FROM_ISR_TRCFAILED (EVENTGROUP_RECEIVE_TRCFAILED + 8UL) /*0x58*/ + +/* Failed non-blocking receive/take - queue empty */ +#define EVENTGROUP_RECEIVE_FROM_ISR_TRCFAILED \ + (EVENTGROUP_SEND_FROM_ISR_TRCFAILED + 8UL) /*0x60*/ + +/* Events when blocking on receive/take */ +#define EVENTGROUP_RECEIVE_TRCBLOCK \ + (EVENTGROUP_RECEIVE_FROM_ISR_TRCFAILED + 8UL) /*0x68*/ + +/* Events when blocking on send/give */ +#define EVENTGROUP_SEND_TRCBLOCK (EVENTGROUP_RECEIVE_TRCBLOCK + 8UL) /*0x70*/ + +/* Events on queue peek (receive) */ +#define EVENTGROUP_PEEK_TRCSUCCESS (EVENTGROUP_SEND_TRCBLOCK + 8UL) /*0x78*/ + +/* Events on object delete (vTaskDelete or vQueueDelete) */ +#define EVENTGROUP_DELETE_OBJ_TRCSUCCESS (EVENTGROUP_PEEK_TRCSUCCESS + 8UL) /*0x80*/ + +/* Other events - object class is implied: TASK */ +#define EVENTGROUP_OTHERS (EVENTGROUP_DELETE_OBJ_TRCSUCCESS + 8UL) /*0x88*/ +#define TASK_DELAY_UNTIL (EVENTGROUP_OTHERS + 0UL) /*0x88*/ +#define TASK_DELAY (EVENTGROUP_OTHERS + 1UL) /*0x89*/ +#define TASK_SUSPEND (EVENTGROUP_OTHERS + 2UL) /*0x8A*/ +#define TASK_RESUME (EVENTGROUP_OTHERS + 3UL) /*0x8B*/ +#define TASK_RESUME_FROM_ISR (EVENTGROUP_OTHERS + 4UL) /*0x8C*/ +#define TASK_PRIORITY_SET (EVENTGROUP_OTHERS + 5UL) /*0x8D*/ +#define TASK_PRIORITY_INHERIT (EVENTGROUP_OTHERS + 6UL) /*0x8E*/ +#define TASK_PRIORITY_DISINHERIT (EVENTGROUP_OTHERS + 7UL) /*0x8F*/ + +#define EVENTGROUP_MISC_PLACEHOLDER (EVENTGROUP_OTHERS + 8UL) /*0x90*/ +#define PEND_FUNC_CALL (EVENTGROUP_MISC_PLACEHOLDER+0UL) /*0x90*/ +#define PEND_FUNC_CALL_FROM_ISR (EVENTGROUP_MISC_PLACEHOLDER+1UL) /*0x91*/ +#define PEND_FUNC_CALL_TRCFAILED (EVENTGROUP_MISC_PLACEHOLDER+2UL) /*0x92*/ +#define PEND_FUNC_CALL_FROM_ISR_TRCFAILED (EVENTGROUP_MISC_PLACEHOLDER+3UL) /*0x93*/ +#define MEM_MALLOC_SIZE (EVENTGROUP_MISC_PLACEHOLDER+4UL) /*0x94*/ +#define MEM_MALLOC_ADDR (EVENTGROUP_MISC_PLACEHOLDER+5UL) /*0x95*/ +#define MEM_FREE_SIZE (EVENTGROUP_MISC_PLACEHOLDER+6UL) /*0x96*/ +#define MEM_FREE_ADDR (EVENTGROUP_MISC_PLACEHOLDER+7UL) /*0x97*/ + +/* User events */ +#define EVENTGROUP_USEREVENT (EVENTGROUP_MISC_PLACEHOLDER + 8UL) /*0x98*/ +#define USER_EVENT (EVENTGROUP_USEREVENT + 0UL) + +/* Allow for 0-15 arguments (the number of args is added to event code) */ +#define USER_EVENT_LAST (EVENTGROUP_USEREVENT + 15UL) /*0xA7*/ + +/******************************************************************************* + * XTS Event - eXtended TimeStamp events + * The timestamps used in the recorder are "differential timestamps" (DTS), i.e. + * the time since the last stored event. The DTS fields are either 1 or 2 bytes + * in the other events, depending on the bytes available in the event struct. + * If the time since the last event (the DTS) is larger than allowed for by + * the DTS field of the current event, an XTS event is inserted immediately + * before the original event. The XTS event contains up to 3 additional bytes + * of the DTS value - the higher bytes of the true DTS value. The lower 1-2 + * bytes are stored in the normal DTS field. + * There are two types of XTS events, XTS8 and XTS16. An XTS8 event is stored + * when there is only room for 1 byte (8 bit) DTS data in the original event, + * which means a limit of 0xFF (255UL). The XTS16 is used when the original event + * has a 16 bit DTS field and thereby can handle values up to 0xFFFF (65535UL). + * + * Using a very high frequency time base can result in many XTS events. + * Preferably, the time between two OS ticks should fit in 16 bits, i.e., + * at most 65535. If your time base has a higher frequency, you can define + * the TRACE + ******************************************************************************/ + +#define EVENTGROUP_SYS (EVENTGROUP_USEREVENT + 16UL) /*0xA8*/ +#define XTS8 (EVENTGROUP_SYS + 0UL) /*0xA8*/ +#define XTS16 (EVENTGROUP_SYS + 1UL) /*0xA9*/ +#define EVENT_BEING_WRITTEN (EVENTGROUP_SYS + 2UL) /*0xAA*/ +#define RESERVED_DUMMY_CODE (EVENTGROUP_SYS + 3UL) /*0xAB*/ +#define LOW_POWER_BEGIN (EVENTGROUP_SYS + 4UL) /*0xAC*/ +#define LOW_POWER_END (EVENTGROUP_SYS + 5UL) /*0xAD*/ +#define XID (EVENTGROUP_SYS + 6UL) /*0xAE*/ +#define XTS16L (EVENTGROUP_SYS + 7UL) /*0xAF*/ + +#define EVENTGROUP_TIMER (EVENTGROUP_SYS + 8UL) /*0xB0*/ +#define TIMER_CREATE (EVENTGROUP_TIMER + 0UL) /*0xB0*/ +#define TIMER_START (EVENTGROUP_TIMER + 1UL) /*0xB1*/ +#define TIMER_RST (EVENTGROUP_TIMER + 2UL) /*0xB2*/ +#define TIMER_STOP (EVENTGROUP_TIMER + 3UL) /*0xB3*/ +#define TIMER_CHANGE_PERIOD (EVENTGROUP_TIMER + 4UL) /*0xB4*/ +#define TIMER_DELETE_OBJ (EVENTGROUP_TIMER + 5UL) /*0xB5*/ +#define TIMER_START_FROM_ISR (EVENTGROUP_TIMER + 6UL) /*0xB6*/ +#define TIMER_RESET_FROM_ISR (EVENTGROUP_TIMER + 7UL) /*0xB7*/ +#define TIMER_STOP_FROM_ISR (EVENTGROUP_TIMER + 8UL) /*0xB8*/ + +#define TIMER_CREATE_TRCFAILED (EVENTGROUP_TIMER + 9UL) /*0xB9*/ +#define TIMER_START_TRCFAILED (EVENTGROUP_TIMER + 10UL) /*0xBA*/ +#define TIMER_RESET_TRCFAILED (EVENTGROUP_TIMER + 11UL) /*0xBB*/ +#define TIMER_STOP_TRCFAILED (EVENTGROUP_TIMER + 12UL) /*0xBC*/ +#define TIMER_CHANGE_PERIOD_TRCFAILED (EVENTGROUP_TIMER + 13UL) /*0xBD*/ +#define TIMER_DELETE_TRCFAILED (EVENTGROUP_TIMER + 14UL) /*0xBE*/ +#define TIMER_START_FROM_ISR_TRCFAILED (EVENTGROUP_TIMER + 15UL) /*0xBF*/ +#define TIMER_RESET_FROM_ISR_TRCFAILED (EVENTGROUP_TIMER + 16UL) /*0xC0*/ +#define TIMER_STOP_FROM_ISR_TRCFAILED (EVENTGROUP_TIMER + 17UL) /*0xC1*/ + +#define EVENTGROUP_EG (EVENTGROUP_TIMER + 18UL) /*0xC2*/ +#define EVENT_GROUP_CREATE (EVENTGROUP_EG + 0UL) /*0xC2*/ +#define EVENT_GROUP_CREATE_TRCFAILED (EVENTGROUP_EG + 1UL) /*0xC3*/ +#define EVENT_GROUP_SYNC_TRCBLOCK (EVENTGROUP_EG + 2UL) /*0xC4*/ +#define EVENT_GROUP_SYNC_END (EVENTGROUP_EG + 3UL) /*0xC5*/ +#define EVENT_GROUP_WAIT_BITS_TRCBLOCK (EVENTGROUP_EG + 4UL) /*0xC6*/ +#define EVENT_GROUP_WAIT_BITS_END (EVENTGROUP_EG + 5UL) /*0xC7*/ +#define EVENT_GROUP_CLEAR_BITS (EVENTGROUP_EG + 6UL) /*0xC8*/ +#define EVENT_GROUP_CLEAR_BITS_FROM_ISR (EVENTGROUP_EG + 7UL) /*0xC9*/ +#define EVENT_GROUP_SET_BITS (EVENTGROUP_EG + 8UL) /*0xCA*/ +#define EVENT_GROUP_DELETE_OBJ (EVENTGROUP_EG + 9UL) /*0xCB*/ +#define EVENT_GROUP_SYNC_END_TRCFAILED (EVENTGROUP_EG + 10UL) /*0xCC*/ +#define EVENT_GROUP_WAIT_BITS_END_TRCFAILED (EVENTGROUP_EG + 11UL) /*0xCD*/ +#define EVENT_GROUP_SET_BITS_FROM_ISR (EVENTGROUP_EG + 12UL) /*0xCE*/ +#define EVENT_GROUP_SET_BITS_FROM_ISR_TRCFAILED (EVENTGROUP_EG + 13UL) /*0xCF*/ + +#define TASK_INSTANCE_FINISHED_NEXT_KSE (EVENTGROUP_EG + 14UL) /*0xD0*/ +#define TASK_INSTANCE_FINISHED_DIRECT (EVENTGROUP_EG + 15UL) /*0xD1*/ + +#define TRACE_TASK_NOTIFY_GROUP (EVENTGROUP_EG + 16UL) /*0xD2*/ +#define TRACE_TASK_NOTIFY (TRACE_TASK_NOTIFY_GROUP + 0UL) /*0xD2*/ +#define TRACE_TASK_NOTIFY_TAKE (TRACE_TASK_NOTIFY_GROUP + 1UL) /*0xD3*/ +#define TRACE_TASK_NOTIFY_TAKE_TRCBLOCK (TRACE_TASK_NOTIFY_GROUP + 2UL) /*0xD4*/ +#define TRACE_TASK_NOTIFY_TAKE_TRCFAILED (TRACE_TASK_NOTIFY_GROUP + 3UL) /*0xD5*/ +#define TRACE_TASK_NOTIFY_WAIT (TRACE_TASK_NOTIFY_GROUP + 4UL) /*0xD6*/ +#define TRACE_TASK_NOTIFY_WAIT_TRCBLOCK (TRACE_TASK_NOTIFY_GROUP + 5UL) /*0xD7*/ +#define TRACE_TASK_NOTIFY_WAIT_TRCFAILED (TRACE_TASK_NOTIFY_GROUP + 6UL) /*0xD8*/ +#define TRACE_TASK_NOTIFY_FROM_ISR (TRACE_TASK_NOTIFY_GROUP + 7UL) /*0xD9*/ +#define TRACE_TASK_NOTIFY_GIVE_FROM_ISR (TRACE_TASK_NOTIFY_GROUP + 8UL) /*0xDA*/ + +#define TIMER_EXPIRED (TRACE_TASK_NOTIFY_GROUP + 9UL) /* 0xDB */ + + /* Events on queue peek (receive) */ +#define EVENTGROUP_PEEK_TRCBLOCK (TRACE_TASK_NOTIFY_GROUP + 10UL) /*0xDC*/ +/* peek block on queue: 0xDC */ +/* peek block on semaphore: 0xDD */ +/* peek block on mutex: 0xDE */ + +/* Events on queue peek (receive) */ +#define EVENTGROUP_PEEK_TRCFAILED (EVENTGROUP_PEEK_TRCBLOCK + 3UL) /*0xDF*/ +/* peek failed on queue: 0xDF */ +/* peek failed on semaphore: 0xE0 */ +/* peek failed on mutex: 0xE1 */ + +#define EVENTGROUP_STREAMBUFFER_DIV (EVENTGROUP_PEEK_TRCFAILED + 3UL) /*0xE2*/ +#define TRACE_STREAMBUFFER_RESET (EVENTGROUP_STREAMBUFFER_DIV + 0) /*0xE2*/ +#define TRACE_MESSAGEBUFFER_RESET (EVENTGROUP_STREAMBUFFER_DIV + 1UL) /*0xE3*/ +#define TRACE_STREAMBUFFER_OBJCLOSE_NAME_TRCSUCCESS (EVENTGROUP_STREAMBUFFER_DIV + 2UL) /*0xE4*/ +#define TRACE_MESSAGEBUFFER_OBJCLOSE_NAME_TRCSUCCESS (EVENTGROUP_STREAMBUFFER_DIV + 3UL) /*0xE5*/ +#define TRACE_STREAMBUFFER_OBJCLOSE_PROP_TRCSUCCESS (EVENTGROUP_STREAMBUFFER_DIV + 4UL) /*0xE6*/ +#define TRACE_MESSAGEBUFFER_OBJCLOSE_PROP_TRCSUCCESS (EVENTGROUP_STREAMBUFFER_DIV + 5UL) /*0xE7*/ + +/* The following are using previously "lost" event codes */ +#define TRACE_STREAMBUFFER_CREATE_OBJ_TRCSUCCESS (EVENTGROUP_CREATE_OBJ_TRCSUCCESS + 4UL) /*0x1C*/ +#define TRACE_STREAMBUFFER_CREATE_OBJ_TRCFAILED (EVENTGROUP_CREATE_OBJ_TRCFAILED + 4UL) /*0x44*/ +#define TRACE_STREAMBUFFER_DELETE_OBJ_TRCSUCCESS (EVENTGROUP_DELETE_OBJ_TRCSUCCESS + 4UL) /*0x84*/ +#define TRACE_STREAMBUFFER_SEND_TRCSUCCESS (EVENTGROUP_SEND_TRCSUCCESS + 3UL) /*0x23*/ +#define TRACE_STREAMBUFFER_SEND_TRCBLOCK (EVENTGROUP_SEND_TRCBLOCK + 3UL) /*0x73*/ +#define TRACE_STREAMBUFFER_SEND_TRCFAILED (EVENTGROUP_SEND_TRCFAILED + 3UL) /*0x4B*/ +#define TRACE_STREAMBUFFER_RECEIVE_TRCSUCCESS (EVENTGROUP_RECEIVE_TRCSUCCESS + 3UL) /*0x2B*/ +#define TRACE_STREAMBUFFER_RECEIVE_TRCBLOCK (EVENTGROUP_RECEIVE_TRCBLOCK + 3UL) /*0x6B*/ +#define TRACE_STREAMBUFFER_RECEIVE_TRCFAILED (EVENTGROUP_RECEIVE_TRCFAILED + 3UL) /*0x53*/ +#define TRACE_STREAMBUFFER_SEND_FROM_ISR_TRCSUCCESS (EVENTGROUP_SEND_FROM_ISR_TRCSUCCESS + 3UL) /*0x33*/ +#define TRACE_STREAMBUFFER_SEND_FROM_ISR_TRCFAILED (EVENTGROUP_SEND_FROM_ISR_TRCFAILED + 3UL) /*0x5B*/ +#define TRACE_STREAMBUFFER_RECEIVE_FROM_ISR_TRCSUCCESS (EVENTGROUP_RECEIVE_FROM_ISR_TRCSUCCESS + 3UL) /*0x3B*/ +#define TRACE_STREAMBUFFER_RECEIVE_FROM_ISR_TRCFAILED (EVENTGROUP_RECEIVE_FROM_ISR_TRCFAILED + 3UL) /*0x63*/ + +/* The following are using previously "lost" event codes. These macros aren't even directly referenced, instead we do (equivalent STREAMBUFFER code) + 1. */ +#define TRACE_MESSAGEBUFFER_CREATE_OBJ_TRCSUCCESS (EVENTGROUP_CREATE_OBJ_TRCSUCCESS + 5UL) /*0x1D*/ +#define TRACE_MESSAGEBUFFER_CREATE_OBJ_TRCFAILED (EVENTGROUP_CREATE_OBJ_TRCFAILED + 5UL) /*0x45*/ +#define TRACE_MESSAGEBUFFER_DELETE_OBJ_TRCSUCCESS (EVENTGROUP_DELETE_OBJ_TRCSUCCESS + 5UL) /*0x85*/ +#define TRACE_MESSAGEBUFFER_SEND_TRCSUCCESS (EVENTGROUP_SEND_TRCSUCCESS + 4UL) /*0x24*/ +#define TRACE_MESSAGEBUFFER_SEND_TRCBLOCK (EVENTGROUP_SEND_TRCBLOCK + 4UL) /*0x74*/ +#define TRACE_MESSAGEBUFFER_SEND_TRCFAILED (EVENTGROUP_SEND_TRCFAILED + 4UL) /*0x4C*/ +#define TRACE_MESSAGEBUFFER_RECEIVE_TRCSUCCESS (EVENTGROUP_RECEIVE_TRCSUCCESS + 4UL) /*0x2C*/ +#define TRACE_MESSAGEBUFFER_RECEIVE_TRCBLOCK (EVENTGROUP_RECEIVE_TRCBLOCK + 4UL) /*0x6C*/ +#define TRACE_MESSAGEBUFFER_RECEIVE_TRCFAILED (EVENTGROUP_RECEIVE_TRCFAILED + 4UL) /*0x54*/ +#define TRACE_MESSAGEBUFFER_SEND_FROM_ISR_TRCSUCCESS (EVENTGROUP_SEND_FROM_ISR_TRCSUCCESS + 4UL) /*0x34*/ +#define TRACE_MESSAGEBUFFER_SEND_FROM_ISR_TRCFAILED (EVENTGROUP_SEND_FROM_ISR_TRCFAILED + 4UL) /*0x5C*/ +#define TRACE_MESSAGEBUFFER_RECEIVE_FROM_ISR_TRCSUCCESS (EVENTGROUP_RECEIVE_FROM_ISR_TRCSUCCESS + 4UL) /*0x3C*/ +#define TRACE_MESSAGEBUFFER_RECEIVE_FROM_ISR_TRCFAILED (EVENTGROUP_RECEIVE_FROM_ISR_TRCFAILED + 4UL) /*0x64*/ + +/* LAST EVENT (0xE7) */ + +/**************************** +* MACROS TO GET TRACE CLASS * +****************************/ +#define TRACE_GET_TRACE_CLASS_FROM_TASK_CLASS(kernelClass) (TRACE_CLASS_TASK) +#define TRACE_GET_TRACE_CLASS_FROM_TASK_OBJECT(pxObject) (TRACE_CLASS_TASK) + +#define TRACE_GET_TRACE_CLASS_FROM_QUEUE_CLASS(kernelClass) TraceQueueClassTable[kernelClass] +#define TRACE_GET_TRACE_CLASS_FROM_QUEUE_OBJECT(pxObject) TRACE_GET_TRACE_CLASS_FROM_QUEUE_CLASS(prvTraceGetQueueType(pxObject)) + +#define TRACE_GET_TRACE_CLASS_FROM_TIMER_CLASS(kernelClass) (TRACE_CLASS_TIMER) +#define TRACE_GET_TRACE_CLASS_FROM_TIMER_OBJECT(pxObject) (TRACE_CLASS_TIMER) + +#define TRACE_GET_TRACE_CLASS_FROM_EVENTGROUP_CLASS(kernelClass) (TRACE_CLASS_EVENTGROUP) +#define TRACE_GET_TRACE_CLASS_FROM_EVENTGROUP_OBJECT(pxObject) (TRACE_CLASS_EVENTGROUP) + +/* TRACE_GET_TRACE_CLASS_FROM_STREAMBUFFER_CLASS can only be accessed with a parameter indicating if it is a MessageBuffer */ +#define TRACE_GET_TRACE_CLASS_FROM_STREAMBUFFER_CLASS(xIsMessageBuffer) (xIsMessageBuffer == 1 ? TRACE_CLASS_MESSAGEBUFFER : TRACE_CLASS_STREAMBUFFER) +#define TRACE_GET_TRACE_CLASS_FROM_STREAMBUFFER_OBJECT(pxObject) (prvGetStreamBufferType(pxObject) == 1 ? TRACE_CLASS_MESSAGEBUFFER : TRACE_CLASS_STREAMBUFFER) + +/* Generic versions */ +#define TRACE_GET_CLASS_TRACE_CLASS(CLASS, kernelClass) TRACE_GET_TRACE_CLASS_FROM_##CLASS##_CLASS(kernelClass) +#define TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject) TRACE_GET_TRACE_CLASS_FROM_##CLASS##_OBJECT(pxObject) + +/****************************** +* MACROS TO GET OBJECT NUMBER * +******************************/ +#define TRACE_GET_TASK_NUMBER(pxTCB) (traceHandle)(prvTraceGetTaskNumberLow16(pxTCB)) +#define TRACE_SET_TASK_NUMBER(pxTCB) prvTraceSetTaskNumberLow16(pxTCB, prvTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(TASK, pxTCB))); + +#define TRACE_GET_QUEUE_NUMBER(queue) ( ( traceHandle ) prvTraceGetQueueNumberLow16(queue) ) +#define TRACE_SET_QUEUE_NUMBER(queue) prvTraceSetQueueNumberLow16(queue, (uint16_t)prvTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(QUEUE, queue))); + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +#define TRACE_GET_TIMER_NUMBER(tmr) ( ( traceHandle ) prvTraceGetTimerNumberLow16(tmr) ) +#define TRACE_SET_TIMER_NUMBER(tmr) prvTraceSetTimerNumberLow16(tmr, (uint16_t)prvTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(TIMER, tmr))); +#else /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ +#define TRACE_GET_TIMER_NUMBER(tmr) ( ( traceHandle ) ((Timer_t*)tmr)->uxTimerNumber ) +#define TRACE_SET_TIMER_NUMBER(tmr) ((Timer_t*)tmr)->uxTimerNumber = prvTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(TIMER, tmr)); +#endif /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +#define TRACE_GET_EVENTGROUP_NUMBER(eg) ( ( traceHandle ) prvTraceGetEventGroupNumberLow16(eg) ) +#define TRACE_SET_EVENTGROUP_NUMBER(eg) prvTraceSetEventGroupNumberLow16(eg, (uint16_t)prvTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(EVENTGROUP, eg))); +#else /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ +#define TRACE_GET_EVENTGROUP_NUMBER(eg) ( ( traceHandle ) uxEventGroupGetNumber(eg) ) +#define TRACE_SET_EVENTGROUP_NUMBER(eg) ((EventGroup_t*)eg)->uxEventGroupNumber = prvTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(EVENTGROUP, eg)); +#endif /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + + +#define TRACE_GET_STREAMBUFFER_NUMBER(sb) ( ( traceHandle ) prvTraceGetStreamBufferNumberLow16(sb) ) +#define TRACE_SET_STREAMBUFFER_NUMBER(sb) prvTraceSetStreamBufferNumberLow16(sb, (uint16_t)prvTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(STREAMBUFFER, sb))); + +/* Generic versions */ +#define TRACE_GET_OBJECT_NUMBER(CLASS, pxObject) TRACE_GET_##CLASS##_NUMBER(pxObject) +#define TRACE_SET_OBJECT_NUMBER(CLASS, pxObject) TRACE_SET_##CLASS##_NUMBER(pxObject) + +/****************************** +* MACROS TO GET EVENT CODES * +******************************/ +#define TRACE_GET_TASK_CLASS_EVENT_CODE(SERVICE, RESULT, kernelClass) (uint8_t)(EVENTGROUP_##SERVICE##_##RESULT + TRACE_GET_CLASS_TRACE_CLASS(TASK, kernelClass)) +#define TRACE_GET_QUEUE_CLASS_EVENT_CODE(SERVICE, RESULT, kernelClass) (uint8_t)(EVENTGROUP_##SERVICE##_##RESULT + TRACE_GET_CLASS_TRACE_CLASS(QUEUE, kernelClass)) +#define TRACE_GET_TIMER_CLASS_EVENT_CODE(SERVICE, RESULT, kernelClass) -- THIS IS NOT USED -- +#define TRACE_GET_EVENTGROUP_CLASS_EVENT_CODE(SERVICE, RESULT, kernelClass) -- THIS IS NOT USED -- +#define TRACE_GET_STREAMBUFFER_CLASS_EVENT_CODE(SERVICE, RESULT, isMessageBuffer) (uint8_t)(TRACE_STREAMBUFFER_##SERVICE##_##RESULT + (uint8_t)isMessageBuffer) + +#define TRACE_GET_TASK_OBJECT_EVENT_CODE(SERVICE, RESULT, pxTCB) (uint8_t)(EVENTGROUP_##SERVICE##_##RESULT + TRACE_CLASS_TASK) +#define TRACE_GET_QUEUE_OBJECT_EVENT_CODE(SERVICE, RESULT, pxObject) (uint8_t)(EVENTGROUP_##SERVICE##_##RESULT + TRACE_GET_OBJECT_TRACE_CLASS(QUEUE, pxObject)) +#define TRACE_GET_TIMER_OBJECT_EVENT_CODE(SERVICE, RESULT, UNUSED) -- THIS IS NOT USED -- +#define TRACE_GET_EVENTGROUP_OBJECT_EVENT_CODE(SERVICE, RESULT, UNUSED) -- THIS IS NOT USED -- +#define TRACE_GET_STREAMBUFFER_OBJECT_EVENT_CODE(SERVICE, RESULT, pxObject) (uint8_t)(TRACE_STREAMBUFFER_##SERVICE##_##RESULT + prvGetStreamBufferType(pxObject)) + +/* Generic versions */ +#define TRACE_GET_CLASS_EVENT_CODE(SERVICE, RESULT, CLASS, kernelClass) TRACE_GET_##CLASS##_CLASS_EVENT_CODE(SERVICE, RESULT, kernelClass) +#define TRACE_GET_OBJECT_EVENT_CODE(SERVICE, RESULT, CLASS, pxObject) TRACE_GET_##CLASS##_OBJECT_EVENT_CODE(SERVICE, RESULT, pxObject) + +/****************************** +* SPECIAL MACROS FOR TASKS * +******************************/ +#define TRACE_GET_TASK_PRIORITY(pxTCB) ((uint8_t)pxTCB->uxPriority) +#define TRACE_GET_TASK_NAME(pxTCB) ((char*)pxTCB->pcTaskName) + +/*** The trace macros for snapshot mode **************************************/ + +/* A macro that will update the tick count when returning from tickless idle */ +#undef traceINCREASE_TICK_COUNT +#define traceINCREASE_TICK_COUNT( xCount ) + +/* Called for each task that becomes ready */ +#undef traceMOVED_TASK_TO_READY_STATE +#define traceMOVED_TASK_TO_READY_STATE( pxTCB ) \ + trcKERNEL_HOOKS_MOVED_TASK_TO_READY_STATE(pxTCB); + +/* Called on each OS tick. Will call uiPortGetTimestamp to make sure it is called at least once every OS tick. */ +#undef traceTASK_INCREMENT_TICK + +#if (TRC_CFG_FREERTOS_VERSION <= TRC_FREERTOS_VERSION_7_4) + +#define traceTASK_INCREMENT_TICK( xTickCount ) \ + if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdTRUE || uxMissedTicks == 0) { trcKERNEL_HOOKS_INCREMENT_TICK(); } \ + if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE) { trcKERNEL_HOOKS_NEW_TIME(DIV_NEW_TIME, xTickCount + 1); } + +#else + +#define traceTASK_INCREMENT_TICK( xTickCount ) \ + if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdTRUE || xPendedTicks == 0) { trcKERNEL_HOOKS_INCREMENT_TICK(); } \ + if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE) { trcKERNEL_HOOKS_NEW_TIME(DIV_NEW_TIME, xTickCount + 1); } + +#endif + +/* Called on each task-switch */ +#undef traceTASK_SWITCHED_IN +#define traceTASK_SWITCHED_IN() \ + trcKERNEL_HOOKS_TASK_SWITCH(TRACE_GET_CURRENT_TASK()); + +/* Called on vTaskCreate */ +#undef traceTASK_CREATE +#define traceTASK_CREATE(pxNewTCB) \ + if (pxNewTCB != NULL) \ + { \ + trcKERNEL_HOOKS_TASK_CREATE(TRACE_GET_OBJECT_EVENT_CODE(CREATE_OBJ, TRCSUCCESS, TASK, pxNewTCB), TASK, pxNewTCB); \ + } + +/* Called in vTaskCreate, if it fails (typically if the stack can not be allocated) */ +#undef traceTASK_CREATE_FAILED +#define traceTASK_CREATE_FAILED() \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY(TRACE_GET_CLASS_EVENT_CODE(CREATE_OBJ, TRCFAILED, TASK, NOT_USED), 0); + +/* Called on vTaskDelete */ +#undef traceTASK_DELETE +#define traceTASK_DELETE( pxTaskToDelete ) \ + { TRACE_ALLOC_CRITICAL_SECTION(); \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_TASK_DELETE(TRACE_GET_OBJECT_EVENT_CODE(DELETE_OBJ, TRCSUCCESS, TASK, pxTaskToDelete), TRACE_GET_OBJECT_EVENT_CODE(OBJCLOSE_NAME, TRCSUCCESS, TASK, pxTaskToDelete), TRACE_GET_OBJECT_EVENT_CODE(OBJCLOSE_PROP, TRCSUCCESS, TASK, pxTaskToDelete), pxTaskToDelete); \ + TRACE_EXIT_CRITICAL_SECTION(); } + +#if (TRC_CFG_SCHEDULING_ONLY == 0) + +#if defined(configUSE_TICKLESS_IDLE) +#if (configUSE_TICKLESS_IDLE != 0) + +#undef traceLOW_POWER_IDLE_BEGIN +#define traceLOW_POWER_IDLE_BEGIN() \ + { \ + extern uint32_t trace_disable_timestamp; \ + prvTraceStoreLowPower(0); \ + trace_disable_timestamp = 1; \ + } + +#undef traceLOW_POWER_IDLE_END +#define traceLOW_POWER_IDLE_END() \ + { \ + extern uint32_t trace_disable_timestamp; \ + trace_disable_timestamp = 0; \ + prvTraceStoreLowPower(1); \ + } + +#endif /* (configUSE_TICKLESS_IDLE != 0) */ +#endif /* defined(configUSE_TICKLESS_IDLE) */ + +/* Called on vTaskSuspend */ +#undef traceTASK_SUSPEND +#define traceTASK_SUSPEND( pxTaskToSuspend ) \ + trcKERNEL_HOOKS_TASK_SUSPEND(TASK_SUSPEND, pxTaskToSuspend); + +/* Called from special case with timer only */ +#undef traceTASK_DELAY_SUSPEND +#define traceTASK_DELAY_SUSPEND( pxTaskToSuspend ) \ + trcKERNEL_HOOKS_TASK_SUSPEND(TASK_SUSPEND, pxTaskToSuspend); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); + +/* Called on vTaskDelay - note the use of FreeRTOS variable xTicksToDelay */ +#undef traceTASK_DELAY +#define traceTASK_DELAY() \ + trcKERNEL_HOOKS_TASK_DELAY(TASK_DELAY, pxCurrentTCB, xTicksToDelay); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); + +/* Called on vTaskDelayUntil - note the use of FreeRTOS variable xTimeToWake */ +#undef traceTASK_DELAY_UNTIL +#if TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 +#define traceTASK_DELAY_UNTIL(xTimeToWake) \ + trcKERNEL_HOOKS_TASK_DELAY(TASK_DELAY_UNTIL, pxCurrentTCB, xTimeToWake); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); +#else /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ +#define traceTASK_DELAY_UNTIL() \ + trcKERNEL_HOOKS_TASK_DELAY(TASK_DELAY_UNTIL, pxCurrentTCB, xTimeToWake); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ + +/* Called in xQueueCreate, and thereby for all other object based on queues, such as semaphores. */ +#undef traceQUEUE_CREATE +#define traceQUEUE_CREATE( pxNewQueue ) \ + trcKERNEL_HOOKS_OBJECT_CREATE(TRACE_GET_OBJECT_EVENT_CODE(CREATE_OBJ, TRCSUCCESS, QUEUE, pxNewQueue), QUEUE, pxNewQueue); + +/* Called in xQueueCreate, if the queue creation fails */ +#undef traceQUEUE_CREATE_FAILED +#define traceQUEUE_CREATE_FAILED( queueType ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY(TRACE_GET_CLASS_EVENT_CODE(CREATE_OBJ, TRCFAILED, QUEUE, queueType), 0); + +/* Called on vQueueDelete */ +#undef traceQUEUE_DELETE +#define traceQUEUE_DELETE( pxQueue ) \ + { TRACE_ALLOC_CRITICAL_SECTION(); \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_OBJECT_DELETE(TRACE_GET_OBJECT_EVENT_CODE(DELETE_OBJ, TRCSUCCESS, QUEUE, pxQueue), TRACE_GET_OBJECT_EVENT_CODE(OBJCLOSE_NAME, TRCSUCCESS, QUEUE, pxQueue), TRACE_GET_OBJECT_EVENT_CODE(OBJCLOSE_PROP, TRCSUCCESS, QUEUE, pxQueue), QUEUE, pxQueue); \ + TRACE_EXIT_CRITICAL_SECTION(); } + +/* This macro is not necessary as of FreeRTOS v9.0.0 */ +#if (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) +/* Called in xQueueCreateMutex, and thereby also from xSemaphoreCreateMutex and xSemaphoreCreateRecursiveMutex */ +#undef traceCREATE_MUTEX +#define traceCREATE_MUTEX( pxNewQueue ) \ + trcKERNEL_HOOKS_OBJECT_CREATE(TRACE_GET_OBJECT_EVENT_CODE(CREATE_OBJ, TRCSUCCESS, QUEUE, pxNewQueue), QUEUE, pxNewQueue); + +/* Called in xQueueCreateMutex when the operation fails (when memory allocation fails) */ +#undef traceCREATE_MUTEX_FAILED +#define traceCREATE_MUTEX_FAILED() \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY(TRACE_GET_CLASS_EVENT_CODE(CREATE_OBJ, TRCFAILED, QUEUE, queueQUEUE_TYPE_MUTEX), 0); +#endif /* (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) */ + +/* Called when the Mutex can not be given, since not holder */ +#undef traceGIVE_MUTEX_RECURSIVE_FAILED +#define traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(SEND, TRCFAILED, QUEUE, pxMutex), QUEUE, pxMutex); + +/* Called when a message is sent to a queue */ /* CS IS NEW ! */ +#undef traceQUEUE_SEND +#define traceQUEUE_SEND( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(SEND, TRCSUCCESS, QUEUE, pxQueue), QUEUE, pxQueue); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(QUEUE, pxQueue, TRACE_GET_OBJECT_TRACE_CLASS(QUEUE, pxQueue) == TRACE_CLASS_MUTEX ? (uint8_t)0 : (uint8_t)(pxQueue->uxMessagesWaiting + 1)); + +/* Called when a message failed to be sent to a queue (timeout) */ +#undef traceQUEUE_SEND_FAILED +#define traceQUEUE_SEND_FAILED( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(SEND, TRCFAILED, QUEUE, pxQueue), QUEUE, pxQueue); + +/* Called when the task is blocked due to a send operation on a full queue */ +#undef traceBLOCKING_ON_QUEUE_SEND +#define traceBLOCKING_ON_QUEUE_SEND( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(SEND, TRCBLOCK, QUEUE, pxQueue), QUEUE, pxQueue); + +/* Called when a message is received from a queue */ +#undef traceQUEUE_RECEIVE +#define traceQUEUE_RECEIVE( pxQueue ) \ + if (isQueueReceiveHookActuallyPeek) \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(PEEK, TRCSUCCESS, QUEUE, pxQueue), QUEUE, pxQueue); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE, TRCSUCCESS, QUEUE, pxQueue), QUEUE, pxQueue); \ + } \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(QUEUE, pxQueue, TRACE_GET_OBJECT_TRACE_CLASS(QUEUE, pxQueue) == TRACE_CLASS_MUTEX ? (uint8_t)TRACE_GET_TASK_NUMBER(TRACE_GET_CURRENT_TASK()) : (uint8_t)(pxQueue->uxMessagesWaiting - 1)); + +/* Called when a receive operation on a queue fails (timeout) */ +#undef traceQUEUE_RECEIVE_FAILED +#define traceQUEUE_RECEIVE_FAILED( pxQueue ) \ + if (isQueueReceiveHookActuallyPeek) \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(PEEK, TRCFAILED, QUEUE, pxQueue), QUEUE, pxQueue); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE, TRCFAILED, QUEUE, pxQueue), QUEUE, pxQueue); \ + } + +/* Called when the task is blocked due to a receive operation on an empty queue */ +#undef traceBLOCKING_ON_QUEUE_RECEIVE +#define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ) \ + if (isQueueReceiveHookActuallyPeek) \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(PEEK, TRCBLOCK, QUEUE, pxQueue), QUEUE, pxQueue); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE, TRCBLOCK, QUEUE, pxQueue), QUEUE, pxQueue); \ + } \ + if (TRACE_GET_OBJECT_TRACE_CLASS(QUEUE, pxQueue) != TRACE_CLASS_MUTEX) \ + { \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); \ + } + +/* Called on xQueuePeek */ +#undef traceQUEUE_PEEK +#define traceQUEUE_PEEK( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(PEEK, TRCSUCCESS, QUEUE, pxQueue), QUEUE, pxQueue); + +/* Called on xQueuePeek fail/timeout (added in FreeRTOS v9.0.2) */ +#undef traceQUEUE_PEEK_FAILED +#define traceQUEUE_PEEK_FAILED( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(PEEK, TRCFAILED, QUEUE, pxQueue), QUEUE, pxQueue); + +/* Called on xQueuePeek blocking (added in FreeRTOS v9.0.2) */ +#undef traceBLOCKING_ON_QUEUE_PEEK +#define traceBLOCKING_ON_QUEUE_PEEK( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(PEEK, TRCBLOCK, QUEUE, pxQueue), QUEUE, pxQueue); \ + if (TRACE_GET_OBJECT_TRACE_CLASS(QUEUE, pxQueue) != TRACE_CLASS_MUTEX) \ + { \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); \ + } + +/* Called when a message is sent from interrupt context, e.g., using xQueueSendFromISR */ +#undef traceQUEUE_SEND_FROM_ISR +#define traceQUEUE_SEND_FROM_ISR( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(SEND_FROM_ISR, TRCSUCCESS, QUEUE, pxQueue), QUEUE, pxQueue); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(QUEUE, pxQueue, (uint8_t)(pxQueue->uxMessagesWaiting + 1)); + +/* Called when a message send from interrupt context fails (since the queue was full) */ +#undef traceQUEUE_SEND_FROM_ISR_FAILED +#define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(SEND_FROM_ISR, TRCFAILED, QUEUE, pxQueue), QUEUE, pxQueue); + +/* Called when a message is received in interrupt context, e.g., using xQueueReceiveFromISR */ +#undef traceQUEUE_RECEIVE_FROM_ISR +#define traceQUEUE_RECEIVE_FROM_ISR( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE_FROM_ISR, TRCSUCCESS, QUEUE, pxQueue), QUEUE, pxQueue); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(QUEUE, pxQueue, (uint8_t)(pxQueue->uxMessagesWaiting - 1)); + +/* Called when a message receive from interrupt context fails (since the queue was empty) */ +#undef traceQUEUE_RECEIVE_FROM_ISR_FAILED +#define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE_FROM_ISR, TRCFAILED, QUEUE, pxQueue), QUEUE, pxQueue); + +#undef traceQUEUE_REGISTRY_ADD +#define traceQUEUE_REGISTRY_ADD(object, name) prvTraceSetObjectName(TRACE_GET_OBJECT_TRACE_CLASS(QUEUE, object), TRACE_GET_OBJECT_NUMBER(QUEUE, object), name); + +/* Called in vTaskPrioritySet */ +#undef traceTASK_PRIORITY_SET +#define traceTASK_PRIORITY_SET( pxTask, uxNewPriority ) \ + trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE(TASK_PRIORITY_SET, pxTask, uxNewPriority); + +/* Called in vTaskPriorityInherit, which is called by Mutex operations */ +#undef traceTASK_PRIORITY_INHERIT +#define traceTASK_PRIORITY_INHERIT( pxTask, uxNewPriority ) \ + trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE(TASK_PRIORITY_INHERIT, pxTask, uxNewPriority); + +/* Called in vTaskPriorityDisinherit, which is called by Mutex operations */ +#undef traceTASK_PRIORITY_DISINHERIT +#define traceTASK_PRIORITY_DISINHERIT( pxTask, uxNewPriority ) \ + trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE(TASK_PRIORITY_DISINHERIT, pxTask, uxNewPriority); + +/* Called in vTaskResume */ +#undef traceTASK_RESUME +#define traceTASK_RESUME( pxTaskToResume ) \ + trcKERNEL_HOOKS_TASK_RESUME(TASK_RESUME, pxTaskToResume); + +/* Called in vTaskResumeFromISR */ +#undef traceTASK_RESUME_FROM_ISR +#define traceTASK_RESUME_FROM_ISR( pxTaskToResume ) \ + trcKERNEL_HOOKS_TASK_RESUME_FROM_ISR(TASK_RESUME_FROM_ISR, pxTaskToResume); + + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) + +#if (TRC_CFG_INCLUDE_MEMMANG_EVENTS == 1) + +extern void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, int32_t size); + +/* MALLOC and FREE are always stored, no matter if they happen inside filtered task */ +#undef traceMALLOC +#define traceMALLOC( pvAddress, uiSize ) \ + if (pvAddress != 0) \ + vTraceStoreMemMangEvent(MEM_MALLOC_SIZE, ( uint32_t ) pvAddress, (int32_t)uiSize); + +#undef traceFREE +#define traceFREE( pvAddress, uiSize ) \ + vTraceStoreMemMangEvent(MEM_FREE_SIZE, ( uint32_t ) pvAddress, -((int32_t)uiSize)); + +#endif /* (TRC_CFG_INCLUDE_MEMMANG_EVENTS == 1) */ + +#if (TRC_CFG_INCLUDE_TIMER_EVENTS == 1) + +/* Called in timer.c - xTimerCreate */ +#undef traceTIMER_CREATE +#define traceTIMER_CREATE(tmr) \ + trcKERNEL_HOOKS_OBJECT_CREATE(TIMER_CREATE, TIMER, tmr); + +#undef traceTIMER_CREATE_FAILED +#define traceTIMER_CREATE_FAILED() \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY(TIMER_CREATE_TRCFAILED, 0); + +/* Note that xCommandID can never be tmrCOMMAND_EXECUTE_CALLBACK (-1) since the trace macro is not called in that case */ +#undef traceTIMER_COMMAND_SEND +#define traceTIMER_COMMAND_SEND(tmr, xCommandID, xOptionalValue, xReturn) \ + if (xCommandID > tmrCOMMAND_START_DONT_TRACE) \ + { \ + if (xCommandID == tmrCOMMAND_CHANGE_PERIOD) \ + { \ + if (xReturn == pdPASS) { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TIMER_CHANGE_PERIOD, TIMER, tmr, xOptionalValue); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TIMER_CHANGE_PERIOD_TRCFAILED, TIMER, tmr, xOptionalValue); \ + } \ + } \ + else if ((xCommandID == tmrCOMMAND_DELETE) && (xReturn == pdPASS)) \ + { \ + trcKERNEL_HOOKS_OBJECT_DELETE(TIMER_DELETE_OBJ, EVENTGROUP_OBJCLOSE_NAME_TRCSUCCESS + TRACE_GET_OBJECT_TRACE_CLASS(TIMER, tmr), EVENTGROUP_OBJCLOSE_PROP_TRCSUCCESS + TRACE_GET_OBJECT_TRACE_CLASS(TIMER, tmr), TIMER, tmr); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENTGROUP_TIMER + (uint32_t)xCommandID + ((xReturn == pdPASS) ? 0 : (TIMER_CREATE_TRCFAILED - TIMER_CREATE)), TIMER, tmr, xOptionalValue); \ + }\ + } + +#undef traceTIMER_EXPIRED +#define traceTIMER_EXPIRED(tmr) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TIMER_EXPIRED, TIMER, tmr); + +#endif /* (TRC_CFG_INCLUDE_TIMER_EVENTS == 1) */ + +#if (TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS == 1) + +#undef tracePEND_FUNC_CALL +#define tracePEND_FUNC_CALL(func, arg1, arg2, ret) \ + if (ret == pdPASS){ \ + trcKERNEL_HOOKS_KERNEL_SERVICE(PEND_FUNC_CALL, TASK, xTimerGetTimerDaemonTaskHandle() ); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE(PEND_FUNC_CALL_TRCFAILED, TASK, xTimerGetTimerDaemonTaskHandle() ); \ + } + +#undef tracePEND_FUNC_CALL_FROM_ISR +#define tracePEND_FUNC_CALL_FROM_ISR(func, arg1, arg2, ret) \ + if (! uiInEventGroupSetBitsFromISR) \ + prvTraceStoreKernelCall(PEND_FUNC_CALL_FROM_ISR, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(xTimerGetTimerDaemonTaskHandle()) ); \ + uiInEventGroupSetBitsFromISR = 0; + +#endif /* (TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS == 1) */ + +#endif /* (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) */ + +#if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1) + +#undef traceEVENT_GROUP_CREATE +#define traceEVENT_GROUP_CREATE(eg) \ + trcKERNEL_HOOKS_OBJECT_CREATE(EVENT_GROUP_CREATE, EVENTGROUP, eg); + +#undef traceEVENT_GROUP_CREATE_FAILED +#define traceEVENT_GROUP_CREATE_FAILED() \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY(EVENT_GROUP_CREATE_TRCFAILED, 0); + +#undef traceEVENT_GROUP_DELETE +#define traceEVENT_GROUP_DELETE(eg) \ + { TRACE_ALLOC_CRITICAL_SECTION(); \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_OBJECT_DELETE(EVENT_GROUP_DELETE_OBJ, EVENTGROUP_OBJCLOSE_NAME_TRCSUCCESS + TRACE_GET_OBJECT_TRACE_CLASS(EVENTGROUP, eg), EVENTGROUP_OBJCLOSE_NAME_TRCSUCCESS + TRACE_GET_OBJECT_TRACE_CLASS(EVENTGROUP, eg), EVENTGROUP, eg); \ + TRACE_EXIT_CRITICAL_SECTION(); } + +#undef traceEVENT_GROUP_SYNC_BLOCK +#define traceEVENT_GROUP_SYNC_BLOCK(eg, bitsToSet, bitsToWaitFor) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_SYNC_TRCBLOCK, EVENTGROUP, eg, bitsToWaitFor); + +#undef traceEVENT_GROUP_SYNC_END +#define traceEVENT_GROUP_SYNC_END(eg, bitsToSet, bitsToWaitFor, wasTimeout) \ + if (wasTimeout) \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_SYNC_END_TRCFAILED, EVENTGROUP, eg, bitsToWaitFor); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_SYNC_END, EVENTGROUP, eg, bitsToWaitFor); \ + } + +#undef traceEVENT_GROUP_WAIT_BITS_BLOCK +#define traceEVENT_GROUP_WAIT_BITS_BLOCK(eg, bitsToWaitFor) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_WAIT_BITS_TRCBLOCK, EVENTGROUP, eg, bitsToWaitFor); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); + +#undef traceEVENT_GROUP_WAIT_BITS_END +#define traceEVENT_GROUP_WAIT_BITS_END(eg, bitsToWaitFor, wasTimeout) \ + if (wasTimeout) \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_WAIT_BITS_END_TRCFAILED, EVENTGROUP, eg, bitsToWaitFor); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_WAIT_BITS_END, EVENTGROUP, eg, bitsToWaitFor); \ + } + +#undef traceEVENT_GROUP_CLEAR_BITS +#define traceEVENT_GROUP_CLEAR_BITS(eg, bitsToClear) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_CLEAR_BITS, EVENTGROUP, eg, bitsToClear); + +#undef traceEVENT_GROUP_CLEAR_BITS_FROM_ISR +#define traceEVENT_GROUP_CLEAR_BITS_FROM_ISR(eg, bitsToClear) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM_FROM_ISR(EVENT_GROUP_CLEAR_BITS_FROM_ISR, EVENTGROUP, eg, bitsToClear); + +#undef traceEVENT_GROUP_SET_BITS +#define traceEVENT_GROUP_SET_BITS(eg, bitsToSet) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(EVENT_GROUP_SET_BITS, EVENTGROUP, eg, bitsToSet); + +#undef traceEVENT_GROUP_SET_BITS_FROM_ISR +#define traceEVENT_GROUP_SET_BITS_FROM_ISR(eg, bitsToSet) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM_FROM_ISR(EVENT_GROUP_SET_BITS_FROM_ISR, EVENTGROUP, eg, bitsToSet); \ + uiInEventGroupSetBitsFromISR = 1; + +#endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1) */ + +#undef traceTASK_NOTIFY_TAKE +#if (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) +#define traceTASK_NOTIFY_TAKE() \ + if (pxCurrentTCB->eNotifyState == eNotified){ \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TRACE_TASK_NOTIFY_TAKE, TASK, pxCurrentTCB, xTicksToWait); \ + } \ + else{ \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TRACE_TASK_NOTIFY_TAKE_TRCFAILED, TASK, pxCurrentTCB, xTicksToWait); \ + } +#else /* TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0 */ +#define traceTASK_NOTIFY_TAKE() \ + if (pxCurrentTCB->ucNotifyState == taskNOTIFICATION_RECEIVED){ \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TRACE_TASK_NOTIFY_TAKE, TASK, pxCurrentTCB, xTicksToWait); \ + }else{ \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TRACE_TASK_NOTIFY_TAKE_TRCFAILED, TASK, pxCurrentTCB, xTicksToWait);} +#endif /* TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0 */ + +#undef traceTASK_NOTIFY_TAKE_BLOCK +#define traceTASK_NOTIFY_TAKE_BLOCK() \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(TRACE_TASK_NOTIFY_TAKE_TRCBLOCK, TASK, pxCurrentTCB, xTicksToWait); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); + +#undef traceTASK_NOTIFY_WAIT +#if (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) +#define traceTASK_NOTIFY_WAIT() \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxCurrentTCB) & CurrentFilterMask) \ + { \ + if (pxCurrentTCB->eNotifyState == eNotified) \ + prvTraceStoreKernelCallWithParam(TRACE_TASK_NOTIFY_WAIT, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxCurrentTCB), xTicksToWait); \ + else \ + prvTraceStoreKernelCallWithParam(TRACE_TASK_NOTIFY_WAIT_TRCFAILED, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxCurrentTCB), xTicksToWait); \ + } +#else /* TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0 */ +#define traceTASK_NOTIFY_WAIT() \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxCurrentTCB) & CurrentFilterMask) \ + { \ + if (pxCurrentTCB->ucNotifyState == taskNOTIFICATION_RECEIVED) \ + prvTraceStoreKernelCallWithParam(TRACE_TASK_NOTIFY_WAIT, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxCurrentTCB), xTicksToWait); \ + else \ + prvTraceStoreKernelCallWithParam(TRACE_TASK_NOTIFY_WAIT_TRCFAILED, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxCurrentTCB), xTicksToWait); \ + } +#endif /* TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0 */ + +#undef traceTASK_NOTIFY_WAIT_BLOCK +#define traceTASK_NOTIFY_WAIT_BLOCK() \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxCurrentTCB) & CurrentFilterMask) \ + prvTraceStoreKernelCallWithParam(TRACE_TASK_NOTIFY_WAIT_TRCBLOCK, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxCurrentTCB), xTicksToWait); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(); + +#undef traceTASK_NOTIFY +#define traceTASK_NOTIFY() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, xTaskToNotify) & CurrentFilterMask) \ + prvTraceStoreKernelCall(TRACE_TASK_NOTIFY, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(xTaskToNotify)); + +#undef traceTASK_NOTIFY_FROM_ISR +#define traceTASK_NOTIFY_FROM_ISR() \ + if (TRACE_GET_OBJECT_FILTER(TASK, xTaskToNotify) & CurrentFilterMask) \ + prvTraceStoreKernelCall(TRACE_TASK_NOTIFY_FROM_ISR, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(xTaskToNotify)); + +#undef traceTASK_NOTIFY_GIVE_FROM_ISR +#define traceTASK_NOTIFY_GIVE_FROM_ISR() \ + if (TRACE_GET_OBJECT_FILTER(TASK, xTaskToNotify) & CurrentFilterMask) \ + prvTraceStoreKernelCall(TRACE_TASK_NOTIFY_GIVE_FROM_ISR, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(xTaskToNotify)); + +#if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) + +#undef traceSTREAM_BUFFER_CREATE +#define traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer ) \ + trcKERNEL_HOOKS_OBJECT_CREATE(TRACE_GET_OBJECT_EVENT_CODE(CREATE_OBJ, TRCSUCCESS, STREAMBUFFER, pxStreamBuffer), STREAMBUFFER, pxStreamBuffer); + +#undef traceSTREAM_BUFFER_CREATE_FAILED +#define traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY(TRACE_GET_CLASS_EVENT_CODE(CREATE_OBJ, TRCFAILED, STREAMBUFFER, xIsMessageBuffer), 0); + +#undef traceSTREAM_BUFFER_CREATE_STATIC_FAILED +#define traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer ) \ + traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer ) + +#undef traceSTREAM_BUFFER_DELETE +#define traceSTREAM_BUFFER_DELETE( xStreamBuffer ) \ + trcKERNEL_HOOKS_OBJECT_DELETE(TRACE_GET_OBJECT_EVENT_CODE(DELETE_OBJ, TRCSUCCESS, STREAMBUFFER, xStreamBuffer), TRACE_GET_OBJECT_EVENT_CODE(OBJCLOSE_NAME, TRCSUCCESS, STREAMBUFFER, xStreamBuffer), TRACE_GET_OBJECT_EVENT_CODE(OBJCLOSE_PROP, TRCSUCCESS, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); + +#undef traceSTREAM_BUFFER_RESET +#define traceSTREAM_BUFFER_RESET( xStreamBuffer ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(prvGetStreamBufferType(xStreamBuffer) > 0 ? TRACE_MESSAGEBUFFER_RESET : TRACE_STREAMBUFFER_RESET, STREAMBUFFER, xStreamBuffer); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(STREAMBUFFER, xStreamBuffer, 0); + +#undef traceSTREAM_BUFFER_SEND +#define traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(SEND, TRCSUCCESS, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(STREAMBUFFER, xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); + +#undef traceBLOCKING_ON_STREAM_BUFFER_SEND +#define traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(SEND, TRCBLOCK, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); + +#undef traceSTREAM_BUFFER_SEND_FAILED +#define traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(SEND, TRCFAILED, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); + +#undef traceSTREAM_BUFFER_RECEIVE +#define traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE, TRCSUCCESS, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(STREAMBUFFER, xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); + + +#undef traceBLOCKING_ON_STREAM_BUFFER_RECEIVE +#define traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE, TRCBLOCK, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); + +#undef traceSTREAM_BUFFER_RECEIVE_FAILED +#define traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE, TRCFAILED, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); + +#undef traceSTREAM_BUFFER_SEND_FROM_ISR +#define traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn ) \ + if( xReturn > ( size_t ) 0 ) \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(SEND_FROM_ISR, TRCSUCCESS, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(STREAMBUFFER, xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(SEND_FROM_ISR, TRCFAILED, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); \ + } + +#undef traceSTREAM_BUFFER_RECEIVE_FROM_ISR +#define traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength ) \ + if( xReceivedLength > ( size_t ) 0 ) \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE_FROM_ISR, TRCSUCCESS, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(STREAMBUFFER, xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); \ + } \ + else \ + { \ + trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(TRACE_GET_OBJECT_EVENT_CODE(RECEIVE_FROM_ISR, TRCFAILED, STREAMBUFFER, xStreamBuffer), STREAMBUFFER, xStreamBuffer); \ + } + +#endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) */ + +#endif /* (TRC_CFG_SCHEDULING_ONLY == 0) */ + +#endif /*#if TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT */ + +/******************************************************************************/ +/*** Definitions for Streaming mode *******************************************/ +/******************************************************************************/ +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) + +/******************************************************************************* +* vTraceStoreKernelObjectName +* +* Set the name for a kernel object (defined by its address). +******************************************************************************/ +void vTraceStoreKernelObjectName(void* object, const char* name); + +/******************************************************************************* +* prvIsNewTCB +* +* Tells if this task is already executing, or if there has been a task-switch. +* Assumed to be called within a trace hook in kernel context. +*******************************************************************************/ +uint32_t prvIsNewTCB(void* pNewTCB); + +#define TRACE_GET_CURRENT_TASK() prvTraceGetCurrentTaskHandle() + +/*************************************************************************/ +/* KERNEL SPECIFIC OBJECT CONFIGURATION */ +/*************************************************************************/ + +/******************************************************************************* + * The event codes - should match the offline config file. + ******************************************************************************/ + +/*** Event codes for streaming - should match the Tracealyzer config file *****/ +#define PSF_EVENT_NULL_EVENT 0x00 + +#define PSF_EVENT_TRACE_START 0x01 +#define PSF_EVENT_TS_CONFIG 0x02 +#define PSF_EVENT_OBJ_NAME 0x03 +#define PSF_EVENT_TASK_PRIORITY 0x04 +#define PSF_EVENT_TASK_PRIO_INHERIT 0x05 +#define PSF_EVENT_TASK_PRIO_DISINHERIT 0x06 +#define PSF_EVENT_DEFINE_ISR 0x07 + +#define PSF_EVENT_TASK_CREATE 0x10 +#define PSF_EVENT_QUEUE_CREATE 0x11 +#define PSF_EVENT_SEMAPHORE_BINARY_CREATE 0x12 +#define PSF_EVENT_MUTEX_CREATE 0x13 +#define PSF_EVENT_TIMER_CREATE 0x14 +#define PSF_EVENT_EVENTGROUP_CREATE 0x15 +#define PSF_EVENT_SEMAPHORE_COUNTING_CREATE 0x16 +#define PSF_EVENT_MUTEX_RECURSIVE_CREATE 0x17 +#define PSF_EVENT_STREAMBUFFER_CREATE 0x18 +#define PSF_EVENT_MESSAGEBUFFER_CREATE 0x19 + +#define PSF_EVENT_TASK_DELETE 0x20 +#define PSF_EVENT_QUEUE_DELETE 0x21 +#define PSF_EVENT_SEMAPHORE_DELETE 0x22 +#define PSF_EVENT_MUTEX_DELETE 0x23 +#define PSF_EVENT_TIMER_DELETE 0x24 +#define PSF_EVENT_EVENTGROUP_DELETE 0x25 +#define PSF_EVENT_STREAMBUFFER_DELETE 0x28 +#define PSF_EVENT_MESSAGEBUFFER_DELETE 0x29 + +#define PSF_EVENT_TASK_READY 0x30 +#define PSF_EVENT_NEW_TIME 0x31 +#define PSF_EVENT_NEW_TIME_SCHEDULER_SUSPENDED 0x32 +#define PSF_EVENT_ISR_BEGIN 0x33 +#define PSF_EVENT_ISR_RESUME 0x34 +#define PSF_EVENT_TS_BEGIN 0x35 +#define PSF_EVENT_TS_RESUME 0x36 +#define PSF_EVENT_TASK_ACTIVATE 0x37 + +#define PSF_EVENT_MALLOC 0x38 +#define PSF_EVENT_FREE 0x39 + +#define PSF_EVENT_LOWPOWER_BEGIN 0x3A +#define PSF_EVENT_LOWPOWER_END 0x3B + +#define PSF_EVENT_IFE_NEXT 0x3C +#define PSF_EVENT_IFE_DIRECT 0x3D + +#define PSF_EVENT_TASK_CREATE_FAILED 0x40 +#define PSF_EVENT_QUEUE_CREATE_FAILED 0x41 +#define PSF_EVENT_SEMAPHORE_BINARY_CREATE_FAILED 0x42 +#define PSF_EVENT_MUTEX_CREATE_FAILED 0x43 +#define PSF_EVENT_TIMER_CREATE_FAILED 0x44 +#define PSF_EVENT_EVENTGROUP_CREATE_FAILED 0x45 +#define PSF_EVENT_SEMAPHORE_COUNTING_CREATE_FAILED 0x46 +#define PSF_EVENT_MUTEX_RECURSIVE_CREATE_FAILED 0x47 +#define PSF_EVENT_STREAMBUFFER_CREATE_FAILED 0x49 +#define PSF_EVENT_MESSAGEBUFFER_CREATE_FAILED 0x4A + +#define PSF_EVENT_TIMER_DELETE_FAILED 0x48 + +#define PSF_EVENT_QUEUE_SEND 0x50 +#define PSF_EVENT_SEMAPHORE_GIVE 0x51 +#define PSF_EVENT_MUTEX_GIVE 0x52 + +#define PSF_EVENT_QUEUE_SEND_FAILED 0x53 +#define PSF_EVENT_SEMAPHORE_GIVE_FAILED 0x54 +#define PSF_EVENT_MUTEX_GIVE_FAILED 0x55 + +#define PSF_EVENT_QUEUE_SEND_BLOCK 0x56 +#define PSF_EVENT_SEMAPHORE_GIVE_BLOCK 0x57 +#define PSF_EVENT_MUTEX_GIVE_BLOCK 0x58 + +#define PSF_EVENT_QUEUE_SEND_FROMISR 0x59 +#define PSF_EVENT_SEMAPHORE_GIVE_FROMISR 0x5A + +#define PSF_EVENT_QUEUE_SEND_FROMISR_FAILED 0x5C +#define PSF_EVENT_SEMAPHORE_GIVE_FROMISR_FAILED 0x5D + +#define PSF_EVENT_QUEUE_RECEIVE 0x60 +#define PSF_EVENT_SEMAPHORE_TAKE 0x61 +#define PSF_EVENT_MUTEX_TAKE 0x62 + +#define PSF_EVENT_QUEUE_RECEIVE_FAILED 0x63 +#define PSF_EVENT_SEMAPHORE_TAKE_FAILED 0x64 +#define PSF_EVENT_MUTEX_TAKE_FAILED 0x65 + +#define PSF_EVENT_QUEUE_RECEIVE_BLOCK 0x66 +#define PSF_EVENT_SEMAPHORE_TAKE_BLOCK 0x67 +#define PSF_EVENT_MUTEX_TAKE_BLOCK 0x68 + +#define PSF_EVENT_QUEUE_RECEIVE_FROMISR 0x69 +#define PSF_EVENT_SEMAPHORE_TAKE_FROMISR 0x6A + +#define PSF_EVENT_QUEUE_RECEIVE_FROMISR_FAILED 0x6C +#define PSF_EVENT_SEMAPHORE_TAKE_FROMISR_FAILED 0x6D + +#define PSF_EVENT_QUEUE_PEEK 0x70 +#define PSF_EVENT_SEMAPHORE_PEEK 0x71 +#define PSF_EVENT_MUTEX_PEEK 0x72 + +#define PSF_EVENT_QUEUE_PEEK_FAILED 0x73 +#define PSF_EVENT_SEMAPHORE_PEEK_FAILED 0x74 +#define PSF_EVENT_MUTEX_PEEK_FAILED 0x75 + +#define PSF_EVENT_QUEUE_PEEK_BLOCK 0x76 +#define PSF_EVENT_SEMAPHORE_PEEK_BLOCK 0x77 +#define PSF_EVENT_MUTEX_PEEK_BLOCK 0x78 + +#define PSF_EVENT_TASK_DELAY_UNTIL 0x79 +#define PSF_EVENT_TASK_DELAY 0x7A +#define PSF_EVENT_TASK_SUSPEND 0x7B +#define PSF_EVENT_TASK_RESUME 0x7C +#define PSF_EVENT_TASK_RESUME_FROMISR 0x7D + +#define PSF_EVENT_TIMER_PENDFUNCCALL 0x80 +#define PSF_EVENT_TIMER_PENDFUNCCALL_FROMISR 0x81 +#define PSF_EVENT_TIMER_PENDFUNCCALL_FAILED 0x82 +#define PSF_EVENT_TIMER_PENDFUNCCALL_FROMISR_FAILED 0x83 + +#define PSF_EVENT_USER_EVENT 0x90 + +#define PSF_EVENT_TIMER_START 0xA0 +#define PSF_EVENT_TIMER_RESET 0xA1 +#define PSF_EVENT_TIMER_STOP 0xA2 +#define PSF_EVENT_TIMER_CHANGEPERIOD 0xA3 +#define PSF_EVENT_TIMER_START_FROMISR 0xA4 +#define PSF_EVENT_TIMER_RESET_FROMISR 0xA5 +#define PSF_EVENT_TIMER_STOP_FROMISR 0xA6 +#define PSF_EVENT_TIMER_CHANGEPERIOD_FROMISR 0xA7 +#define PSF_EVENT_TIMER_START_FAILED 0xA8 +#define PSF_EVENT_TIMER_RESET_FAILED 0xA9 +#define PSF_EVENT_TIMER_STOP_FAILED 0xAA +#define PSF_EVENT_TIMER_CHANGEPERIOD_FAILED 0xAB +#define PSF_EVENT_TIMER_START_FROMISR_FAILED 0xAC +#define PSF_EVENT_TIMER_RESET_FROMISR_FAILED 0xAD +#define PSF_EVENT_TIMER_STOP_FROMISR_FAILED 0xAE +#define PSF_EVENT_TIMER_CHANGEPERIOD_FROMISR_FAILED 0xAF + +#define PSF_EVENT_EVENTGROUP_SYNC 0xB0 +#define PSF_EVENT_EVENTGROUP_WAITBITS 0xB1 +#define PSF_EVENT_EVENTGROUP_CLEARBITS 0xB2 +#define PSF_EVENT_EVENTGROUP_CLEARBITS_FROMISR 0xB3 +#define PSF_EVENT_EVENTGROUP_SETBITS 0xB4 +#define PSF_EVENT_EVENTGROUP_SETBITS_FROMISR 0xB5 +#define PSF_EVENT_EVENTGROUP_SYNC_BLOCK 0xB6 +#define PSF_EVENT_EVENTGROUP_WAITBITS_BLOCK 0xB7 +#define PSF_EVENT_EVENTGROUP_SYNC_FAILED 0xB8 +#define PSF_EVENT_EVENTGROUP_WAITBITS_FAILED 0xB9 + +#define PSF_EVENT_QUEUE_SEND_FRONT 0xC0 +#define PSF_EVENT_QUEUE_SEND_FRONT_FAILED 0xC1 +#define PSF_EVENT_QUEUE_SEND_FRONT_BLOCK 0xC2 +#define PSF_EVENT_QUEUE_SEND_FRONT_FROMISR 0xC3 +#define PSF_EVENT_QUEUE_SEND_FRONT_FROMISR_FAILED 0xC4 +#define PSF_EVENT_MUTEX_GIVE_RECURSIVE 0xC5 +#define PSF_EVENT_MUTEX_GIVE_RECURSIVE_FAILED 0xC6 +#define PSF_EVENT_MUTEX_TAKE_RECURSIVE 0xC7 +#define PSF_EVENT_MUTEX_TAKE_RECURSIVE_FAILED 0xC8 + +#define PSF_EVENT_TASK_NOTIFY 0xC9 +#define PSF_EVENT_TASK_NOTIFY_TAKE 0xCA +#define PSF_EVENT_TASK_NOTIFY_TAKE_BLOCK 0xCB +#define PSF_EVENT_TASK_NOTIFY_TAKE_FAILED 0xCC +#define PSF_EVENT_TASK_NOTIFY_WAIT 0xCD +#define PSF_EVENT_TASK_NOTIFY_WAIT_BLOCK 0xCE +#define PSF_EVENT_TASK_NOTIFY_WAIT_FAILED 0xCF +#define PSF_EVENT_TASK_NOTIFY_FROM_ISR 0xD0 +#define PSF_EVENT_TASK_NOTIFY_GIVE_FROM_ISR 0xD1 + +#define PSF_EVENT_TIMER_EXPIRED 0xD2 + +#define PSF_EVENT_STREAMBUFFER_SEND 0xD3 +#define PSF_EVENT_STREAMBUFFER_SEND_BLOCK 0xD4 +#define PSF_EVENT_STREAMBUFFER_SEND_FAILED 0xD5 +#define PSF_EVENT_STREAMBUFFER_RECEIVE 0xD6 +#define PSF_EVENT_STREAMBUFFER_RECEIVE_BLOCK 0xD7 +#define PSF_EVENT_STREAMBUFFER_RECEIVE_FAILED 0xD8 +#define PSF_EVENT_STREAMBUFFER_SEND_FROM_ISR 0xD9 +#define PSF_EVENT_STREAMBUFFER_SEND_FROM_ISR_FAILED 0xDA +#define PSF_EVENT_STREAMBUFFER_RECEIVE_FROM_ISR 0xDB +#define PSF_EVENT_STREAMBUFFER_RECEIVE_FROM_ISR_FAILED 0xDC +#define PSF_EVENT_STREAMBUFFER_RESET 0xDD + +#define PSF_EVENT_MESSAGEBUFFER_SEND 0xDE +#define PSF_EVENT_MESSAGEBUFFER_SEND_BLOCK 0xDF +#define PSF_EVENT_MESSAGEBUFFER_SEND_FAILED 0xE0 +#define PSF_EVENT_MESSAGEBUFFER_RECEIVE 0xE1 +#define PSF_EVENT_MESSAGEBUFFER_RECEIVE_BLOCK 0xE2 +#define PSF_EVENT_MESSAGEBUFFER_RECEIVE_FAILED 0xE3 +#define PSF_EVENT_MESSAGEBUFFER_SEND_FROM_ISR 0xE4 +#define PSF_EVENT_MESSAGEBUFFER_SEND_FROM_ISR_FAILED 0xE5 +#define PSF_EVENT_MESSAGEBUFFER_RECEIVE_FROM_ISR 0xE6 +#define PSF_EVENT_MESSAGEBUFFER_RECEIVE_FROM_ISR_FAILED 0xE7 +#define PSF_EVENT_MESSAGEBUFFER_RESET 0xE8 + +/*** The trace macros for streaming ******************************************/ + +/* A macro that will update the tick count when returning from tickless idle */ +#undef traceINCREASE_TICK_COUNT +/* Note: This can handle time adjustments of max 2^32 ticks, i.e., 35 seconds at 120 MHz. Thus, tick-less idle periods longer than 2^32 ticks will appear "compressed" on the time line.*/ +#define traceINCREASE_TICK_COUNT( xCount ) { extern uint32_t uiTraceTickCount; uiTraceTickCount += xCount; } + +#if (TRC_CFG_INCLUDE_OSTICK_EVENTS == 1) +#define OS_TICK_EVENT(uxSchedulerSuspended, xTickCount) if (uxSchedulerSuspended == (unsigned portBASE_TYPE) pdFALSE) { prvTraceStoreEvent1(PSF_EVENT_NEW_TIME, (uint32_t)(xTickCount + 1)); } +#else +#define OS_TICK_EVENT(uxSchedulerSuspended, xTickCount) +#endif + +/* Called on each OS tick. Will call uiPortGetTimestamp to make sure it is called at least once every OS tick. */ +#undef traceTASK_INCREMENT_TICK +#if TRC_CFG_FREERTOS_VERSION <= TRC_FREERTOS_VERSION_7_4 +#define traceTASK_INCREMENT_TICK( xTickCount ) \ + if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdTRUE || uxMissedTicks == 0) { extern uint32_t uiTraceTickCount; uiTraceTickCount++; } \ + OS_TICK_EVENT(uxSchedulerSuspended, xTickCount) +#else +#define traceTASK_INCREMENT_TICK( xTickCount ) \ + if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdTRUE || uxPendedTicks == 0) { extern uint32_t uiTraceTickCount; uiTraceTickCount++; } \ + OS_TICK_EVENT(uxSchedulerSuspended, xTickCount) +#endif /* TRC_CFG_FREERTOS_VERSION <= TRC_FREERTOS_VERSION_7_4 */ + +/* Called on each task-switch */ +#undef traceTASK_SWITCHED_IN +#define traceTASK_SWITCHED_IN() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + { \ + if (prvIsNewTCB(pxCurrentTCB)) \ + { \ + prvTraceStoreEvent2(PSF_EVENT_TASK_ACTIVATE, (uint32_t)pxCurrentTCB, pxCurrentTCB->uxPriority); \ + } \ + } + +/* Called for each task that becomes ready */ +#if (TRC_CFG_INCLUDE_READY_EVENTS == 1) +#undef traceMOVED_TASK_TO_READY_STATE +#define traceMOVED_TASK_TO_READY_STATE( pxTCB ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_READY, (uint32_t)pxTCB); +#endif + +#undef traceTASK_CREATE +#if TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 +#define traceTASK_CREATE(pxNewTCB) \ + if (pxNewTCB != NULL) \ + { \ + prvTraceSaveSymbol(pxNewTCB, pxNewTCB->pcTaskName); \ + prvTraceSaveObjectData(pxNewTCB, pxNewTCB->uxPriority); \ + prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, pxNewTCB->pcTaskName, pxNewTCB); \ + TRACE_SET_OBJECT_FILTER(TASK, pxNewTCB, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxNewTCB) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_CREATE, (uint32_t)pxNewTCB, pxNewTCB->uxPriority); \ + } +#else /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ +#define traceTASK_CREATE(pxNewTCB) \ + if (pxNewTCB != NULL) \ + { \ + prvTraceSaveSymbol(pxNewTCB, (const char*)pcName); \ + prvTraceSaveObjectData(pxNewTCB, uxPriority); \ + prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, (const char*)pcName, pxNewTCB); \ + TRACE_SET_OBJECT_FILTER(TASK, pxNewTCB, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxNewTCB) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_CREATE, (uint32_t)pxNewTCB, uxPriority); \ + } +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ + +/* Called in vTaskCreate, if it fails (typically if the stack can not be allocated) */ +#undef traceTASK_CREATE_FAILED +#define traceTASK_CREATE_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent0(PSF_EVENT_TASK_CREATE_FAILED); + +/* Called on vTaskDelete */ +#undef traceTASK_DELETE // We don't allow for filtering out "delete" events. They are important and not very frequent. Moreover, we can't exclude create events, so this should be symmetrical. +#define traceTASK_DELETE( pxTaskToDelete ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTaskToDelete) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_DELETE, (uint32_t)pxTaskToDelete, (pxTaskToDelete != NULL) ? (pxTaskToDelete->uxPriority) : 0); \ + prvTraceDeleteSymbol(pxTaskToDelete); \ + prvTraceDeleteObjectData(pxTaskToDelete); + +#if (TRC_CFG_SCHEDULING_ONLY == 0) + +#if (defined(configUSE_TICKLESS_IDLE) && configUSE_TICKLESS_IDLE != 0) + +#undef traceLOW_POWER_IDLE_BEGIN +#define traceLOW_POWER_IDLE_BEGIN() \ + { \ + prvTraceStoreEvent1(PSF_EVENT_LOWPOWER_BEGIN, xExpectedIdleTime); \ + } + +#undef traceLOW_POWER_IDLE_END +#define traceLOW_POWER_IDLE_END() \ + { \ + prvTraceStoreEvent0(PSF_EVENT_LOWPOWER_END); \ + } + +#endif /* (defined(configUSE_TICKLESS_IDLE) && configUSE_TICKLESS_IDLE != 0) */ + +/* Called on vTaskSuspend */ +#undef traceTASK_SUSPEND +#define traceTASK_SUSPEND( pxTaskToSuspend ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTaskToSuspend) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_SUSPEND, (uint32_t)pxTaskToSuspend); + +/* Called on vTaskDelay - note the use of FreeRTOS variable xTicksToDelay */ +#undef traceTASK_DELAY +#define traceTASK_DELAY() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_DELAY, xTicksToDelay); + +/* Called on vTaskDelayUntil - note the use of FreeRTOS variable xTimeToWake */ +#undef traceTASK_DELAY_UNTIL +#if TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 +#define traceTASK_DELAY_UNTIL(xTimeToWake) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_DELAY_UNTIL, (uint32_t)xTimeToWake); +#else /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ +#define traceTASK_DELAY_UNTIL() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_DELAY_UNTIL, (uint32_t)xTimeToWake); +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0) +#define traceQUEUE_CREATE_HELPER() \ + case queueQUEUE_TYPE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_CREATE, (uint32_t)pxNewQueue); \ + break; \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_RECURSIVE_CREATE, (uint32_t)pxNewQueue); \ + break; +#else +#define traceQUEUE_CREATE_HELPER() +#endif /* (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) */ + +/* Called in xQueueCreate, and thereby for all other object based on queues, such as semaphores. */ +#undef traceQUEUE_CREATE +#define traceQUEUE_CREATE( pxNewQueue )\ + TRACE_SET_OBJECT_FILTER(QUEUE, pxNewQueue, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + { \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxNewQueue) & CurrentFilterMask) \ + { \ + switch (pxNewQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(PSF_EVENT_QUEUE_CREATE, (uint32_t)pxNewQueue, uxQueueLength); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + prvTraceStoreEvent1(PSF_EVENT_SEMAPHORE_BINARY_CREATE, (uint32_t)pxNewQueue); \ + break; \ + traceQUEUE_CREATE_HELPER() \ + } \ + } \ + } + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0) +#define traceQUEUE_CREATE_FAILED_HELPER() \ + case queueQUEUE_TYPE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_CREATE_FAILED, 0); \ + break; \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_RECURSIVE_CREATE_FAILED, 0); \ + break; +#else +#define traceQUEUE_CREATE_FAILED_HELPER() +#endif /* (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) */ + +/* Called in xQueueCreate, if the queue creation fails */ +#undef traceQUEUE_CREATE_FAILED +#define traceQUEUE_CREATE_FAILED( queueType ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + { \ + switch (queueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(PSF_EVENT_QUEUE_CREATE_FAILED, 0, uxQueueLength); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + prvTraceStoreEvent1(PSF_EVENT_SEMAPHORE_BINARY_CREATE_FAILED, 0); \ + break; \ + traceQUEUE_CREATE_FAILED_HELPER() \ + } \ + } + +#undef traceQUEUE_DELETE // We don't allow for filtering out "delete" events. They are important and not very frequent. Moreover, we can't exclude create events, so this should be symmetrical. +#define traceQUEUE_DELETE( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + { \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + { \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(PSF_EVENT_QUEUE_DELETE, (uint32_t)pxQueue, (pxQueue != NULL) ? (pxQueue->uxMessagesWaiting) : 0); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent2(PSF_EVENT_MUTEX_DELETE, (uint32_t)pxQueue, (pxQueue != NULL) ? (pxQueue->uxMessagesWaiting) : 0); \ + break; \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_DELETE, (uint32_t)pxQueue, (pxQueue != NULL) ? (pxQueue->uxMessagesWaiting) : 0); \ + break; \ + } \ + } \ + } \ + prvTraceDeleteSymbol(pxQueue); + +/* Called in xQueueCreateCountingSemaphore, if the queue creation fails */ +#undef traceCREATE_COUNTING_SEMAPHORE +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) +#define traceCREATE_COUNTING_SEMAPHORE() \ + TRACE_SET_OBJECT_FILTER(QUEUE, xHandle, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, xHandle) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE, (uint32_t)xHandle, uxMaxCount) +#elif (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_7_5_OR_7_6) +#define traceCREATE_COUNTING_SEMAPHORE() \ + TRACE_SET_OBJECT_FILTER(QUEUE, xHandle, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, xHandle) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE, (uint32_t)xHandle, uxInitialCount); +#elif (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_7_4) +#define traceCREATE_COUNTING_SEMAPHORE() \ + TRACE_SET_OBJECT_FILTER(QUEUE, xHandle, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, xHandle) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE, (uint32_t)xHandle, uxCountValue); +#else +#define traceCREATE_COUNTING_SEMAPHORE() \ + TRACE_SET_OBJECT_FILTER(QUEUE, pxHandle, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxHandle) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE, (uint32_t)pxHandle, uxCountValue); +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X */ + +#undef traceCREATE_COUNTING_SEMAPHORE_FAILED +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) +#define traceCREATE_COUNTING_SEMAPHORE_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE_FAILED, 0, uxMaxCount); +#elif (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_7_5_OR_7_6) +#define traceCREATE_COUNTING_SEMAPHORE_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE_FAILED, 0, uxInitialCount); +#elif (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_7_4) +#define traceCREATE_COUNTING_SEMAPHORE_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE_FAILED, 0, uxCountValue); +#else +#define traceCREATE_COUNTING_SEMAPHORE_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_COUNTING_CREATE_FAILED, 0, uxCountValue); +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X */ + + +/* This macro is not necessary as of FreeRTOS v9.0.0 */ +#if (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) +/* Called in xQueueCreateMutex, and thereby also from xSemaphoreCreateMutex and xSemaphoreCreateRecursiveMutex */ +#undef traceCREATE_MUTEX +#define traceCREATE_MUTEX( pxNewQueue ) \ + TRACE_SET_OBJECT_FILTER(QUEUE, pxNewQueue, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + { \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxNewQueue) & CurrentFilterMask) \ + { \ + switch (pxNewQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_CREATE, (uint32_t)pxNewQueue); \ + break; \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_RECURSIVE_CREATE, (uint32_t)pxNewQueue); \ + break; \ + } \ + }\ + } + +/* Called in xQueueCreateMutex when the operation fails (when memory allocation fails) */ +#undef traceCREATE_MUTEX_FAILED +#define traceCREATE_MUTEX_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_CREATE_FAILED, 0); +#endif /* (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_9_0_0) */ + +/* Called when a message is sent to a queue */ /* CS IS NEW ! */ +#undef traceQUEUE_SEND +#define traceQUEUE_SEND( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(xCopyPosition == queueSEND_TO_BACK ? PSF_EVENT_QUEUE_SEND : PSF_EVENT_QUEUE_SEND_FRONT, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting + 1); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_GIVE, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting + 1); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_GIVE, (uint32_t)pxQueue); \ + break; \ + } + +/* Called when a message failed to be sent to a queue (timeout) */ +#undef traceQUEUE_SEND_FAILED +#define traceQUEUE_SEND_FAILED( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(xCopyPosition == queueSEND_TO_BACK ? PSF_EVENT_QUEUE_SEND_FAILED : PSF_EVENT_QUEUE_SEND_FRONT_FAILED, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_GIVE_FAILED, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_GIVE_FAILED, (uint32_t)pxQueue); \ + break; \ + } + +/* Called when the task is blocked due to a send operation on a full queue */ +#undef traceBLOCKING_ON_QUEUE_SEND +#define traceBLOCKING_ON_QUEUE_SEND( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(xCopyPosition == queueSEND_TO_BACK ? PSF_EVENT_QUEUE_SEND_BLOCK : PSF_EVENT_QUEUE_SEND_FRONT_BLOCK, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_GIVE_BLOCK, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_GIVE_BLOCK, (uint32_t)pxQueue); \ + break; \ + } + +/**************************************************************************/ +/* Makes sure xQueueGiveFromISR also has a xCopyPosition parameter */ +/**************************************************************************/ +/* Helpers needed to correctly expand names */ +#define TZ__CAT2(a,b) a ## b +#define TZ__CAT(a,b) TZ__CAT2(a, b) + +/* Expands name if this header is included... uxQueueType must be a macro that only exists in queue.c or whatever, and it must expand to nothing or to something that's valid in identifiers */ +#define xQueueGiveFromISR(a,b) TZ__CAT(xQueueGiveFromISR__, uxQueueType) (a,b) + +/* If in queue.c, the "uxQueueType" macro expands to "pcHead". queueSEND_TO_BACK is the value we need to send in */ +#define xQueueGiveFromISR__pcHead(__a, __b) MyWrapper(__a, __b, const BaseType_t xCopyPosition); \ +BaseType_t xQueueGiveFromISR(__a, __b) { return MyWrapper(xQueue, pxHigherPriorityTaskWoken, queueSEND_TO_BACK); } \ +BaseType_t MyWrapper(__a, __b, const BaseType_t xCopyPosition) + +/* If not in queue.c, "uxQueueType" isn't expanded */ +#define xQueueGiveFromISR__uxQueueType(__a, __b) xQueueGiveFromISR(__a,__b) + +/**************************************************************************/ +/* End of xQueueGiveFromISR fix */ +/**************************************************************************/ + +/* Called when a message is sent from interrupt context, e.g., using xQueueSendFromISR */ +#undef traceQUEUE_SEND_FROM_ISR +#define traceQUEUE_SEND_FROM_ISR( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(xCopyPosition == queueSEND_TO_BACK ? PSF_EVENT_QUEUE_SEND_FROMISR : PSF_EVENT_QUEUE_SEND_FRONT_FROMISR, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting + 1); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_GIVE_FROMISR, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting + 1); \ + break; \ + } + +/* Called when a message send from interrupt context fails (since the queue was full) */ +#undef traceQUEUE_SEND_FROM_ISR_FAILED +#define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(xCopyPosition == queueSEND_TO_BACK ? PSF_EVENT_QUEUE_SEND_FROMISR_FAILED : PSF_EVENT_QUEUE_SEND_FRONT_FROMISR_FAILED, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_GIVE_FROMISR_FAILED, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + } + +/* Called when a message is received from a queue */ +#undef traceQUEUE_RECEIVE +#define traceQUEUE_RECEIVE( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + if (isQueueReceiveHookActuallyPeek) \ + prvTraceStoreEvent3(PSF_EVENT_QUEUE_PEEK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting - 1); \ + else\ + prvTraceStoreEvent3(PSF_EVENT_QUEUE_RECEIVE, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting - 1); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + if (isQueueReceiveHookActuallyPeek) \ + prvTraceStoreEvent3(PSF_EVENT_SEMAPHORE_PEEK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting - 1); \ + else \ + prvTraceStoreEvent3(PSF_EVENT_SEMAPHORE_TAKE, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting - 1); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + if (isQueueReceiveHookActuallyPeek) \ + prvTraceStoreEvent2(PSF_EVENT_MUTEX_PEEK, (uint32_t)pxQueue, xTicksToWait); \ + else \ + prvTraceStoreEvent2(PSF_EVENT_MUTEX_TAKE, (uint32_t)pxQueue, xTicksToWait); \ + break; \ + } + +/* Called when a receive operation on a queue fails (timeout) */ +#undef traceQUEUE_RECEIVE_FAILED +#define traceQUEUE_RECEIVE_FAILED( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent3(isQueueReceiveHookActuallyPeek ? PSF_EVENT_QUEUE_PEEK_FAILED : PSF_EVENT_QUEUE_RECEIVE_FAILED, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent3(isQueueReceiveHookActuallyPeek ? PSF_EVENT_SEMAPHORE_PEEK_FAILED : PSF_EVENT_SEMAPHORE_TAKE_FAILED, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent2(isQueueReceiveHookActuallyPeek ? PSF_EVENT_MUTEX_PEEK_FAILED : PSF_EVENT_MUTEX_TAKE_FAILED, (uint32_t)pxQueue, xTicksToWait); \ + break; \ + } + +/* Called when the task is blocked due to a receive operation on an empty queue */ +#undef traceBLOCKING_ON_QUEUE_RECEIVE +#define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent3(isQueueReceiveHookActuallyPeek ? PSF_EVENT_QUEUE_PEEK_BLOCK : PSF_EVENT_QUEUE_RECEIVE_BLOCK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent3(isQueueReceiveHookActuallyPeek ? PSF_EVENT_SEMAPHORE_PEEK_BLOCK : PSF_EVENT_SEMAPHORE_TAKE_BLOCK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent2(isQueueReceiveHookActuallyPeek ? PSF_EVENT_MUTEX_PEEK_BLOCK : PSF_EVENT_MUTEX_TAKE_BLOCK, (uint32_t)pxQueue, xTicksToWait); \ + break; \ + } + +#if (TRC_CFG_FREERTOS_VERSION > TRC_FREERTOS_VERSION_9_0_1) +/* Called when a peek operation on a queue fails (timeout) */ +#undef traceQUEUE_PEEK_FAILED +#define traceQUEUE_PEEK_FAILED( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent3(PSF_EVENT_QUEUE_PEEK_FAILED, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent3(PSF_EVENT_SEMAPHORE_PEEK_FAILED, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent2(PSF_EVENT_MUTEX_PEEK_FAILED, (uint32_t)pxQueue, xTicksToWait); \ + break; \ + } + +/* Called when the task is blocked due to a peek operation on an empty queue */ +#undef traceBLOCKING_ON_QUEUE_PEEK +#define traceBLOCKING_ON_QUEUE_PEEK( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent3(PSF_EVENT_QUEUE_PEEK_BLOCK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent3(PSF_EVENT_SEMAPHORE_PEEK_BLOCK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent2(PSF_EVENT_MUTEX_PEEK_BLOCK, (uint32_t)pxQueue, xTicksToWait); \ + break; \ + } + +#endif /* (TRC_CFG_FREERTOS_VERSION > TRC_FREERTOS_VERSION_9_0_1) */ + +/* Called when a message is received in interrupt context, e.g., using xQueueReceiveFromISR */ +#undef traceQUEUE_RECEIVE_FROM_ISR +#define traceQUEUE_RECEIVE_FROM_ISR( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(PSF_EVENT_QUEUE_RECEIVE_FROMISR, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting - 1); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_TAKE_FROMISR, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting - 1); \ + break; \ + } + +/* Called when a message receive from interrupt context fails (since the queue was empty) */ +#undef traceQUEUE_RECEIVE_FROM_ISR_FAILED +#define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent2(PSF_EVENT_QUEUE_RECEIVE_FROMISR_FAILED, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent2(PSF_EVENT_SEMAPHORE_TAKE_FROMISR_FAILED, (uint32_t)pxQueue, pxQueue->uxMessagesWaiting); \ + break; \ + } + +/* Called on xQueuePeek */ +#undef traceQUEUE_PEEK +#define traceQUEUE_PEEK( pxQueue ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(QUEUE, pxQueue) & CurrentFilterMask) \ + switch (pxQueue->ucQueueType) \ + { \ + case queueQUEUE_TYPE_BASE: \ + prvTraceStoreEvent3(PSF_EVENT_QUEUE_PEEK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_BINARY_SEMAPHORE: \ + case queueQUEUE_TYPE_COUNTING_SEMAPHORE: \ + prvTraceStoreEvent3(PSF_EVENT_SEMAPHORE_PEEK, (uint32_t)pxQueue, xTicksToWait, pxQueue->uxMessagesWaiting); \ + break; \ + case queueQUEUE_TYPE_MUTEX: \ + case queueQUEUE_TYPE_RECURSIVE_MUTEX: \ + prvTraceStoreEvent1(PSF_EVENT_MUTEX_PEEK, (uint32_t)pxQueue); \ + break; \ + } + +/* Called in vTaskPrioritySet */ +#undef traceTASK_PRIORITY_SET +#define traceTASK_PRIORITY_SET( pxTask, uxNewPriority ) \ + prvTraceSaveObjectData(pxTask, uxNewPriority); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTask) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_PRIORITY, (uint32_t)pxTask, uxNewPriority); + +/* Called in vTaskPriorityInherit, which is called by Mutex operations */ +#undef traceTASK_PRIORITY_INHERIT +#define traceTASK_PRIORITY_INHERIT( pxTask, uxNewPriority ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTask) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_PRIO_INHERIT, (uint32_t)pxTask, uxNewPriority); + +/* Called in vTaskPriorityDisinherit, which is called by Mutex operations */ +#undef traceTASK_PRIORITY_DISINHERIT +#define traceTASK_PRIORITY_DISINHERIT( pxTask, uxNewPriority ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTask) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_PRIO_DISINHERIT, (uint32_t)pxTask, uxNewPriority); + +/* Called in vTaskResume */ +#undef traceTASK_RESUME +#define traceTASK_RESUME( pxTaskToResume ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTaskToResume) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_RESUME, (uint32_t)pxTaskToResume); + +/* Called in vTaskResumeFromISR */ +#undef traceTASK_RESUME_FROM_ISR +#define traceTASK_RESUME_FROM_ISR( pxTaskToResume ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTaskToResume) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_RESUME_FROMISR, (uint32_t)pxTaskToResume); + +#if (TRC_CFG_INCLUDE_MEMMANG_EVENTS == 1) + +#undef traceMALLOC +#define traceMALLOC( pvAddress, uiSize ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_MALLOC, (uint32_t)pvAddress, uiSize); + +#undef traceFREE +#define traceFREE( pvAddress, uiSize ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_FREE, (uint32_t)pvAddress, (uint32_t)(0 - uiSize)); /* "0 -" instead of just "-" to get rid of a warning... */ + +#endif /* (TRC_CFG_INCLUDE_MEMMANG_EVENTS == 1) */ + +#if (TRC_CFG_INCLUDE_TIMER_EVENTS == 1) + +/* Called in timer.c - xTimerCreate */ +#undef traceTIMER_CREATE +#define traceTIMER_CREATE(tmr) \ + TRACE_SET_OBJECT_FILTER(TIMER, tmr, CurrentFilterGroup); \ + prvTraceSaveSymbol(tmr, tmr->pcTimerName); \ + prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, tmr->pcTimerName, tmr); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TIMER, tmr) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TIMER_CREATE, (uint32_t)tmr, tmr->xTimerPeriodInTicks); + +#undef traceTIMER_CREATE_FAILED +#define traceTIMER_CREATE_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent0(PSF_EVENT_TIMER_CREATE_FAILED); + +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) +#define traceTIMER_COMMAND_SEND_8_0_CASES(tmr) \ + case tmrCOMMAND_RESET: \ + prvTraceStoreEvent2((xReturn == pdPASS) ? PSF_EVENT_TIMER_RESET : PSF_EVENT_TIMER_RESET_FAILED, (uint32_t)tmr, xOptionalValue); \ + break; \ + case tmrCOMMAND_START_FROM_ISR: \ + prvTraceStoreEvent2((xReturn == pdPASS) ? PSF_EVENT_TIMER_START_FROMISR : PSF_EVENT_TIMER_START_FROMISR_FAILED, (uint32_t)tmr, xOptionalValue); \ + break; \ + case tmrCOMMAND_RESET_FROM_ISR: \ + prvTraceStoreEvent2((xReturn == pdPASS) ? PSF_EVENT_TIMER_RESET_FROMISR : PSF_EVENT_TIMER_RESET_FROMISR_FAILED, (uint32_t)tmr, xOptionalValue); \ + break; \ + case tmrCOMMAND_STOP_FROM_ISR: \ + prvTraceStoreEvent2((xReturn == pdPASS) ? PSF_EVENT_TIMER_STOP_FROMISR : PSF_EVENT_TIMER_STOP_FROMISR_FAILED, (uint32_t)tmr, xOptionalValue); \ + break; \ + case tmrCOMMAND_CHANGE_PERIOD_FROM_ISR: \ + prvTraceStoreEvent2((xReturn == pdPASS) ? PSF_EVENT_TIMER_CHANGEPERIOD_FROMISR : PSF_EVENT_TIMER_CHANGEPERIOD_FROMISR_FAILED, (uint32_t)tmr, xOptionalValue); \ + break; +#else /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X */ +#define traceTIMER_COMMAND_SEND_8_0_CASES(tmr) +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X */ + +/* Note that xCommandID can never be tmrCOMMAND_EXECUTE_CALLBACK (-1) since the trace macro is not called in that case */ +#undef traceTIMER_COMMAND_SEND +#define traceTIMER_COMMAND_SEND(tmr, xCommandID, xOptionalValue, xReturn) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TIMER, tmr) & CurrentFilterMask) \ + switch(xCommandID) \ + { \ + case tmrCOMMAND_START: \ + prvTraceStoreEvent1((xReturn == pdPASS) ? PSF_EVENT_TIMER_START : PSF_EVENT_TIMER_START_FAILED, (uint32_t)tmr); \ + break; \ + case tmrCOMMAND_STOP: \ + prvTraceStoreEvent1((xReturn == pdPASS) ? PSF_EVENT_TIMER_STOP : PSF_EVENT_TIMER_STOP_FAILED, (uint32_t)tmr); \ + break; \ + case tmrCOMMAND_CHANGE_PERIOD: \ + prvTraceStoreEvent2((xReturn == pdPASS) ? PSF_EVENT_TIMER_CHANGEPERIOD : PSF_EVENT_TIMER_CHANGEPERIOD_FAILED, (uint32_t)tmr, xOptionalValue); \ + break; \ + case tmrCOMMAND_DELETE: \ + prvTraceStoreEvent1((xReturn == pdPASS) ? PSF_EVENT_TIMER_DELETE : PSF_EVENT_TIMER_DELETE_FAILED, (uint32_t)tmr); \ + break; \ + traceTIMER_COMMAND_SEND_8_0_CASES(tmr) \ + } + +#undef traceTIMER_EXPIRED +#define traceTIMER_EXPIRED(tmr) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TIMER, tmr) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TIMER_EXPIRED, (uint32_t)tmr->pxCallbackFunction, (uint32_t)tmr->pvTimerID); + +#endif /* #if (TRC_CFG_INCLUDE_TIMER_EVENTS == 1) */ + + +#if (TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS == 1) + +#undef tracePEND_FUNC_CALL +#define tracePEND_FUNC_CALL(func, arg1, arg2, ret) \ + prvTraceStoreEvent1((ret == pdPASS) ? PSF_EVENT_TIMER_PENDFUNCCALL : PSF_EVENT_TIMER_PENDFUNCCALL_FAILED, (uint32_t)func); + +#undef tracePEND_FUNC_CALL_FROM_ISR +#define tracePEND_FUNC_CALL_FROM_ISR(func, arg1, arg2, ret) \ + prvTraceStoreEvent1((ret == pdPASS) ? PSF_EVENT_TIMER_PENDFUNCCALL_FROMISR : PSF_EVENT_TIMER_PENDFUNCCALL_FROMISR_FAILED, (uint32_t)func); + +#endif /* (TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS == 1) */ + +#if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1) + +#undef traceEVENT_GROUP_CREATE +#define traceEVENT_GROUP_CREATE(eg) \ + TRACE_SET_OBJECT_FILTER(EVENTGROUP, eg, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_EVENTGROUP_CREATE, (uint32_t)eg); + +#undef traceEVENT_GROUP_DELETE +#define traceEVENT_GROUP_DELETE(eg) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_EVENTGROUP_DELETE, (uint32_t)eg); \ + prvTraceDeleteSymbol(eg); + +#undef traceEVENT_GROUP_CREATE_FAILED +#define traceEVENT_GROUP_CREATE_FAILED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent0(PSF_EVENT_EVENTGROUP_CREATE_FAILED); + +#undef traceEVENT_GROUP_SYNC_BLOCK +#define traceEVENT_GROUP_SYNC_BLOCK(eg, bitsToSet, bitsToWaitFor) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_EVENTGROUP_SYNC_BLOCK, (uint32_t)eg, bitsToWaitFor); + +#undef traceEVENT_GROUP_SYNC_END +#define traceEVENT_GROUP_SYNC_END(eg, bitsToSet, bitsToWaitFor, wasTimeout) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2((wasTimeout != pdTRUE) ? PSF_EVENT_EVENTGROUP_SYNC : PSF_EVENT_EVENTGROUP_SYNC_FAILED, (uint32_t)eg, bitsToWaitFor); + +#undef traceEVENT_GROUP_WAIT_BITS_BLOCK +#define traceEVENT_GROUP_WAIT_BITS_BLOCK(eg, bitsToWaitFor) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_EVENTGROUP_WAITBITS_BLOCK, (uint32_t)eg, bitsToWaitFor); + +#undef traceEVENT_GROUP_WAIT_BITS_END +#define traceEVENT_GROUP_WAIT_BITS_END(eg, bitsToWaitFor, wasTimeout) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2((wasTimeout != pdTRUE) ? PSF_EVENT_EVENTGROUP_WAITBITS : PSF_EVENT_EVENTGROUP_WAITBITS_FAILED, (uint32_t)eg, bitsToWaitFor); + +#undef traceEVENT_GROUP_CLEAR_BITS +#define traceEVENT_GROUP_CLEAR_BITS(eg, bitsToClear) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_EVENTGROUP_CLEARBITS, (uint32_t)eg, bitsToClear); + +#undef traceEVENT_GROUP_CLEAR_BITS_FROM_ISR +#define traceEVENT_GROUP_CLEAR_BITS_FROM_ISR(eg, bitsToClear) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_EVENTGROUP_CLEARBITS_FROMISR, (uint32_t)eg, bitsToClear); + +#undef traceEVENT_GROUP_SET_BITS +#define traceEVENT_GROUP_SET_BITS(eg, bitsToSet) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_EVENTGROUP_SETBITS, (uint32_t)eg, bitsToSet); + +#undef traceEVENT_GROUP_SET_BITS_FROM_ISR +#define traceEVENT_GROUP_SET_BITS_FROM_ISR(eg, bitsToSet) \ + if (TRACE_GET_OBJECT_FILTER(EVENTGROUP, eg) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_EVENTGROUP_SETBITS_FROMISR, (uint32_t)eg, bitsToSet); + +#endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1) */ + +#undef traceTASK_NOTIFY_TAKE +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0) +#define traceTASK_NOTIFY_TAKE() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask){ \ + if (pxCurrentTCB->ucNotifyState == taskNOTIFICATION_RECEIVED) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_TAKE, (uint32_t)pxCurrentTCB, xTicksToWait); \ + else \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_TAKE_FAILED, (uint32_t)pxCurrentTCB, xTicksToWait);} +#else /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ +#define traceTASK_NOTIFY_TAKE() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask){ \ + if (pxCurrentTCB->eNotifyState == eNotified) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_TAKE, (uint32_t)pxCurrentTCB, xTicksToWait); \ + else \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_TAKE_FAILED, (uint32_t)pxCurrentTCB, xTicksToWait);} +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ + +#undef traceTASK_NOTIFY_TAKE_BLOCK +#define traceTASK_NOTIFY_TAKE_BLOCK() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_TAKE_BLOCK, (uint32_t)pxCurrentTCB, xTicksToWait); + +#undef traceTASK_NOTIFY_WAIT +#if (TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0) +#define traceTASK_NOTIFY_WAIT() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask){ \ + if (pxCurrentTCB->ucNotifyState == taskNOTIFICATION_RECEIVED) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_WAIT, (uint32_t)pxCurrentTCB, xTicksToWait); \ + else \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_WAIT_FAILED, (uint32_t)pxCurrentTCB, xTicksToWait);} +#else /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ +#define traceTASK_NOTIFY_WAIT() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask){ \ + if (pxCurrentTCB->eNotifyState == eNotified) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_WAIT, (uint32_t)pxCurrentTCB, xTicksToWait); \ + else \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_WAIT_FAILED, (uint32_t)pxCurrentTCB, xTicksToWait);} +#endif /* TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_9_0_0 */ + +#undef traceTASK_NOTIFY_WAIT_BLOCK +#define traceTASK_NOTIFY_WAIT_BLOCK() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(PSF_EVENT_TASK_NOTIFY_WAIT_BLOCK, (uint32_t)pxCurrentTCB, xTicksToWait); + +#undef traceTASK_NOTIFY +#define traceTASK_NOTIFY() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, xTaskToNotify) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_NOTIFY, (uint32_t)xTaskToNotify); + +#undef traceTASK_NOTIFY_FROM_ISR +#define traceTASK_NOTIFY_FROM_ISR() \ + if (TRACE_GET_OBJECT_FILTER(TASK, xTaskToNotify) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_NOTIFY_FROM_ISR, (uint32_t)xTaskToNotify); + +#undef traceTASK_NOTIFY_GIVE_FROM_ISR +#define traceTASK_NOTIFY_GIVE_FROM_ISR() \ + if (TRACE_GET_OBJECT_FILTER(TASK, xTaskToNotify) & CurrentFilterMask) \ + prvTraceStoreEvent1(PSF_EVENT_TASK_NOTIFY_GIVE_FROM_ISR, (uint32_t)xTaskToNotify); + +#undef traceQUEUE_REGISTRY_ADD +#define traceQUEUE_REGISTRY_ADD(object, name) \ + prvTraceSaveSymbol(object, (const char*)name); \ + prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, name, object); + +#if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) + +#undef traceSTREAM_BUFFER_CREATE +#define traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer ) \ + TRACE_SET_OBJECT_FILTER(STREAMBUFFER, pxStreamBuffer, CurrentFilterGroup); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, pxStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent2(xIsMessageBuffer == 1 ? PSF_EVENT_MESSAGEBUFFER_CREATE : PSF_EVENT_STREAMBUFFER_CREATE, (uint32_t)pxStreamBuffer, xBufferSizeBytes); + +#undef traceSTREAM_BUFFER_CREATE_FAILED +#define traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreEvent2(xIsMessageBuffer == 1 ? PSF_EVENT_MESSAGEBUFFER_CREATE_FAILED : PSF_EVENT_STREAMBUFFER_CREATE_FAILED, 0 , xBufferSizeBytes); + +#undef traceSTREAM_BUFFER_CREATE_STATIC_FAILED +#define traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer ) \ + traceSTREAM_BUFFER_CREATE_FAILED( xIsMessageBuffer ) + +#undef traceSTREAM_BUFFER_DELETE +#define traceSTREAM_BUFFER_DELETE( xStreamBuffer ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, pxStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent2(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_DELETE : PSF_EVENT_STREAMBUFFER_DELETE, (uint32_t)xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); \ + prvTraceDeleteSymbol(xStreamBuffer); + +#undef traceSTREAM_BUFFER_RESET +#define traceSTREAM_BUFFER_RESET( xStreamBuffer ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent2(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_RESET : PSF_EVENT_STREAMBUFFER_RESET, (uint32_t)xStreamBuffer, 0); + +#undef traceSTREAM_BUFFER_SEND +#define traceSTREAM_BUFFER_SEND( xStreamBuffer, xReturn ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent2(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_SEND : PSF_EVENT_STREAMBUFFER_SEND, (uint32_t)xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); + +#undef traceBLOCKING_ON_STREAM_BUFFER_SEND +#define traceBLOCKING_ON_STREAM_BUFFER_SEND( xStreamBuffer ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent1(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_SEND_BLOCK : PSF_EVENT_STREAMBUFFER_SEND_BLOCK, (uint32_t)xStreamBuffer); + +#undef traceSTREAM_BUFFER_SEND_FAILED +#define traceSTREAM_BUFFER_SEND_FAILED( xStreamBuffer ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent1(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_SEND_FAILED : PSF_EVENT_STREAMBUFFER_SEND_FAILED, (uint32_t)xStreamBuffer); + +#undef traceSTREAM_BUFFER_RECEIVE +#define traceSTREAM_BUFFER_RECEIVE( xStreamBuffer, xReceivedLength ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent2(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_RECEIVE: PSF_EVENT_STREAMBUFFER_RECEIVE, (uint32_t)xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); + +#undef traceBLOCKING_ON_STREAM_BUFFER_RECEIVE +#define traceBLOCKING_ON_STREAM_BUFFER_RECEIVE( xStreamBuffer ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent1(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_RECEIVE_BLOCK: PSF_EVENT_STREAMBUFFER_RECEIVE_BLOCK, (uint32_t)xStreamBuffer); + +#undef traceSTREAM_BUFFER_RECEIVE_FAILED +#define traceSTREAM_BUFFER_RECEIVE_FAILED( xStreamBuffer ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + prvTraceStoreEvent1(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_RECEIVE_FAILED: PSF_EVENT_STREAMBUFFER_RECEIVE_FAILED, (uint32_t)xStreamBuffer); + +#undef traceSTREAM_BUFFER_SEND_FROM_ISR +#define traceSTREAM_BUFFER_SEND_FROM_ISR( xStreamBuffer, xReturn ) \ + if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + { \ + if ( xReturn > ( size_t ) 0 ) \ + { \ + prvTraceStoreEvent2(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_SEND_FROM_ISR : PSF_EVENT_STREAMBUFFER_SEND_FROM_ISR, (uint32_t)xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); \ + } \ + else \ + { \ + prvTraceStoreEvent1(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_SEND_FROM_ISR_FAILED : PSF_EVENT_STREAMBUFFER_SEND_FROM_ISR_FAILED, (uint32_t)xStreamBuffer); \ + } \ + } + +#undef traceSTREAM_BUFFER_RECEIVE_FROM_ISR +#define traceSTREAM_BUFFER_RECEIVE_FROM_ISR( xStreamBuffer, xReceivedLength ) \ +if (TRACE_GET_OBJECT_FILTER(STREAMBUFFER, xStreamBuffer) & CurrentFilterMask) \ + { \ + if ( xReceivedLength > ( size_t ) 0 ) \ + { \ + prvTraceStoreEvent2(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_RECEIVE_FROM_ISR : PSF_EVENT_STREAMBUFFER_RECEIVE_FROM_ISR, (uint32_t)xStreamBuffer, prvBytesInBuffer(xStreamBuffer)); \ + } \ + else \ + { \ + prvTraceStoreEvent1(prvGetStreamBufferType(xStreamBuffer) > 0 ? PSF_EVENT_MESSAGEBUFFER_RECEIVE_FROM_ISR_FAILED : PSF_EVENT_STREAMBUFFER_RECEIVE_FROM_ISR_FAILED, (uint32_t)xStreamBuffer); \ + } \ + } + +#endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1) */ + +#endif /* (TRC_CFG_SCHEDULING_ONLY == 0) */ + +#endif /* (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) */ + +#else /* (TRC_USE_TRACEALYZER_RECORDER == 1) */ + +/* When recorder is disabled */ +#define vTraceSetQueueName(object, name) +#define vTraceSetSemaphoreName(object, name) +#define vTraceSetMutexName(object, name) +#define vTraceSetEventGroupName(object, name) +#define vTraceSetStreamBufferName(object, name) +#define vTraceSetMessageBufferName(object, name) + +#endif /* (TRC_USE_TRACEALYZER_RECORDER == 1) */ + +#ifdef __cplusplus +} +#endif + +#endif /* TRC_KERNEL_PORT_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcPortDefines.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcPortDefines.h new file mode 100644 index 000000000..258bf220a --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcPortDefines.h @@ -0,0 +1,137 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * trcPortDefines.h + * + * Some common defines for the trace recorder. + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_PORTDEFINES_H +#define TRC_PORTDEFINES_H + +#define TRC_FREE_RUNNING_32BIT_INCR 1 +#define TRC_FREE_RUNNING_32BIT_DECR 2 +#define TRC_OS_TIMER_INCR 3 +#define TRC_OS_TIMER_DECR 4 +#define TRC_CUSTOM_TIMER_INCR 5 +#define TRC_CUSTOM_TIMER_DECR 6 + +/* Start options for vTraceEnable. */ +#define TRC_INIT 0 +#define TRC_START 1 +#define TRC_START_AWAIT_HOST 2 + +/* Command codes for TzCtrl task */ +#define CMD_SET_ACTIVE 1 /* Start (param1 = 1) or Stop (param1 = 0) */ + +/* The final command code, used to validate commands. */ +#define CMD_LAST_COMMAND 1 + +#define TRC_RECORDER_MODE_SNAPSHOT 0 +#define TRC_RECORDER_MODE_STREAMING 1 + +#define TRC_RECORDER_BUFFER_ALLOCATION_STATIC (0x00) +#define TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC (0x01) +#define TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM (0x02) + +/* Filter Groups */ +#define FilterGroup0 (uint16_t)0x0001 +#define FilterGroup1 (uint16_t)0x0002 +#define FilterGroup2 (uint16_t)0x0004 +#define FilterGroup3 (uint16_t)0x0008 +#define FilterGroup4 (uint16_t)0x0010 +#define FilterGroup5 (uint16_t)0x0020 +#define FilterGroup6 (uint16_t)0x0040 +#define FilterGroup7 (uint16_t)0x0080 +#define FilterGroup8 (uint16_t)0x0100 +#define FilterGroup9 (uint16_t)0x0200 +#define FilterGroup10 (uint16_t)0x0400 +#define FilterGroup11 (uint16_t)0x0800 +#define FilterGroup12 (uint16_t)0x1000 +#define FilterGroup13 (uint16_t)0x2000 +#define FilterGroup14 (uint16_t)0x4000 +#define FilterGroup15 (uint16_t)0x8000 + +/****************************************************************************** + * Supported ports + * + * TRC_HARDWARE_PORT_HWIndependent + * A hardware independent fallback option for event timestamping. Provides low + * resolution timestamps based on the OS tick. + * This may be used on the Win32 port, but may also be used on embedded hardware + * platforms. All time durations will be truncated to the OS tick frequency, + * typically 1 KHz. This means that a task or ISR that executes in less than + * 1 ms get an execution time of zero. + * + * TRC_HARDWARE_PORT_APPLICATION_DEFINED + * Allows for defining the port macros in other source code files. + * + * TRC_HARDWARE_PORT_Win32 + * "Accurate" timestamping based on the Windows performance counter for Win32 + * builds. Note that this gives the host machine time, not the kernel time. + * + * Hardware specific ports + * To get accurate timestamping, a hardware timer is necessary. Below are the + * available ports. Some of these are "unofficial", meaning that + * they have not yet been verified by Percepio but have been contributed by + * external developers. They should work, otherwise let us know by emailing + * support@percepio.com. Some work on any OS platform, while other are specific + * to a certain operating system. + *****************************************************************************/ + +/****** Port Name ************************************* Code ** Official ** OS Platform *********/ +#define TRC_HARDWARE_PORT_APPLICATION_DEFINED 98 /* - - */ +#define TRC_HARDWARE_PORT_NOT_SET 99 /* - - */ +#define TRC_HARDWARE_PORT_HWIndependent 0 /* Yes Any */ +#define TRC_HARDWARE_PORT_Win32 1 /* Yes FreeRTOS on Win32 */ +#define TRC_HARDWARE_PORT_Atmel_AT91SAM7 2 /* No Any */ +#define TRC_HARDWARE_PORT_Atmel_UC3A0 3 /* No Any */ +#define TRC_HARDWARE_PORT_ARM_Cortex_M 4 /* Yes Any */ +#define TRC_HARDWARE_PORT_Renesas_RX600 6 /* Yes Any */ +#define TRC_HARDWARE_PORT_MICROCHIP_PIC24_PIC32 7 /* Yes Any */ +#define TRC_HARDWARE_PORT_TEXAS_INSTRUMENTS_TMS570_RM48 8 /* Yes Any */ +#define TRC_HARDWARE_PORT_TEXAS_INSTRUMENTS_MSP430 9 /* No Any */ +#define TRC_HARDWARE_PORT_XILINX_PPC405 11 /* No FreeRTOS */ +#define TRC_HARDWARE_PORT_XILINX_PPC440 12 /* No FreeRTOS */ +#define TRC_HARDWARE_PORT_XILINX_MICROBLAZE 13 /* No Any */ +#define TRC_HARDWARE_PORT_NXP_LPC210X 14 /* No Any */ +#define TRC_HARDWARE_PORT_ARM_CORTEX_A9 15 /* Yes Any */ +#define TRC_HARDWARE_PORT_POWERPC_Z4 16 /* No FreeRTOS */ +#define TRC_HARDWARE_PORT_Altera_NiosII 17 /* No Any */ +#endif /*TRC_PORTDEFINES_H*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcRecorder.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcRecorder.h new file mode 100644 index 000000000..edcd5f0ae --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/Include/trcRecorder.h @@ -0,0 +1,1789 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * trcRecorder.h + * + * The public API of the trace recorder. + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_RECORDER_H +#define TRC_RECORDER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#include "trcConfig.h" +#include "trcPortDefines.h" + + +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) +typedef uint16_t traceString; +typedef uint8_t traceUBChannel; +typedef uint8_t traceObjectClass; + +#if (TRC_CFG_USE_16BIT_OBJECT_HANDLES == 1) +typedef uint16_t traceHandle; +#else +typedef uint8_t traceHandle; +#endif + +#include "trcHardwarePort.h" +#include "trcKernelPort.h" + +// Not available in snapshot mode +#define vTraceConsoleChannelPrintF(fmt, ...) + +#endif + +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) + +typedef const char* traceString; +typedef const void* traceHandle; + +#include "trcHardwarePort.h" +#include "trcStreamingPort.h" +#include "trcKernelPort.h" + +#endif + +#if (TRC_USE_TRACEALYZER_RECORDER == 1) + +/* The user event channel for recorder warnings, must be defined in trcKernelPort.c */ +extern traceString trcWarningChannel; + +#define TRACE_GET_LOW16(value) ((uint16_t)((value) & 0x0000FFFF)) +#define TRACE_GET_HIGH16(value) ((uint16_t)(((value) >> 16) & 0x0000FFFF)) +#define TRACE_SET_LOW16(current, value) (((current) & 0xFFFF0000) | (value)) +#define TRACE_SET_HIGH16(current, value) (((current) & 0x0000FFFF) | (((uint32_t)(value)) << 16)) + +/******************************************************************************/ +/*** Common API - both Snapshot and Streaming mode ****************************/ +/******************************************************************************/ + +/****************************************************************************** +* vTraceEnable(int startOption); +* +* Initializes and optionally starts the trace, depending on the start option. +* To use the trace recorder, the startup must call vTraceEnable before any RTOS +* calls are made (including "create" calls). Three start options are provided: +* +* TRC_START: Starts the tracing directly. In snapshot mode this allows for +* starting the trace at any point in your code, assuming vTraceEnable(TRC_INIT) +* has been called in the startup. +* Can also be used for streaming without Tracealyzer control, e.g. to a local +* flash file system (assuming such a "stream port", see trcStreamingPort.h). +* +* TRC_START_AWAIT_HOST: For streaming mode only. Initializes the trace recorder +* if necessary and waits for a Start command from Tracealyzer ("Start Recording" +* button). This call is intentionally blocking! By calling vTraceEnable with +* this option from the startup code, you start tracing at this point and capture +* the early events. +* +* TRC_INIT: Initializes the trace recorder, but does not start the tracing. +* In snapshot mode, this must be followed by a vTraceEnable(TRC_START) sometime +* later. +* +* Usage examples: +* +* Snapshot trace, from startup: +* +* vTraceEnable(TRC_START); +* +* +* Snapshot trace, from a later point: +* +* vTraceEnable(TRC_INIT); +* +* ... +* vTraceEnable(TRC_START); // e.g., in task context, at some relevant event +* +* Streaming trace, from startup: +* +* vTraceEnable(TRC_START_AWAIT_HOST); // Blocks! +* +* +* Streaming trace, from a later point: +* +* vTraceEnable(TRC_INIT); +* +* +******************************************************************************/ +void vTraceEnable(int startOption); + +/****************************************************************************** + * vTracePrintF + * + * Generates "User Events", with formatted text and data, similar to a "printf". + * User Events can be used for very efficient logging from your application code. + * It is very fast since the actual string formatting is done on the host side, + * when the trace is displayed. The execution time is just some microseconds on + * a 32-bit MCU. + * + * User Events are shown as yellow labels in the main trace view of $PNAME. + * + * An advantage of User Events is that data can be plotted in the "User Event + * Signal Plot" view, visualizing any data you log as User Events, discrete + * states or control system signals (e.g. system inputs or outputs). + * + * You may group User Events into User Event Channels. The yellow User Event + * labels show the logged string, preceded by the channel name within brackets. + * + * Example: + * + * "[MyChannel] Hello World!" + * + * The User Event Channels are shown in the View Filter, which makes it easy to + * select what User Events you wish to display. User Event Channels are created + * using xTraceRegisterString(). + * + * Example: + * + * traceString adc_uechannel = xTraceRegisterString("ADC User Events"); + * ... + * vTracePrintF(adc_uechannel, + * "ADC channel %d: %d volts", + * ch, adc_reading); + * + * The following format specifiers are supported in both modes: + * %d - signed integer. + * %u - unsigned integer. + * %X - hexadecimal, uppercase. + * %x - hexadecimal, lowercase. + * %s - string (see comment below) + * + * For integer formats (%d, %u, %x, %X) you may also use width and padding. + * If using -42 as data argument, two examples are: + * "%05d" -> "-0042" + * "%5d" -> " -42". + * + * String arguments are supported in both snapshot and streaming, but in streaming + * mode you need to use xTraceRegisterString and use the returned traceString as + * the argument. In snapshot you simply provide a char* as argument. + * + * Snapshot: vTracePrintF(myChn, "my string: %s", str); + * Streaming: vTracePrintF(myChn, "my string: %s", xTraceRegisterString(str)); + * + * In snapshot mode you can specify 8-bit or 16-bit arguments to reduce RAM usage: + * %hd -> 16 bit (h) signed integer (d). + * %bu -> 8 bit (b) unsigned integer (u). + * + * However, in streaming mode all data arguments are assumed to be 32 bit wide. + * Width specifiers (e.g. %hd) are accepted but ignored (%hd treated like %d). + * + * The maximum event size also differs between the modes. In streaming this is + * limited by a maximum payload size of 52 bytes, including format string and + * data arguments. So if using one data argument, the format string is limited + * to 48 byte, etc. If this is exceeded, the format string is truncated and you + * get a warning in Tracealyzer. + * + * In snapshot mode you are limited to maximum 15 arguments, that must not exceed + * 32 bytes in total (not counting the format string). If exceeded, the recorder + * logs an internal error (displayed when opening the trace) and stops recording. + ******************************************************************************/ +#if (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) +void vTracePrintF(traceString chn, const char* fmt, ...); +#else +#define vTracePrintF(chn, ...) (void)chn +#endif + + /****************************************************************************** +* vTracePrint +* +* A faster version of vTracePrintF, that only allows for logging a string. +* +* Example: +* +* traceString chn = xTraceRegisterString("MyChannel"); +* ... +* vTracePrint(chn, "Hello World!"); +******************************************************************************/ +#if (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) +void vTracePrint(traceString chn, const char* str); +#else +#define vTracePrint(chn, ...) (void)chn +#endif + + +/******************************************************************************* +* vTraceConsoleChannelPrintF +* +* Wrapper for vTracePrint, using the default channel. Can be used as a drop-in +* replacement for printf and similar functions, e.g. in a debug logging macro. +* +* Example: +* +* // Old: #define LogString debug_console_printf +* +* // New, log to Tracealyzer instead: +* #define LogString vTraceConsoleChannelPrintF +* ... +* LogString("My value is: %d", myValue); +******************************************************************************/ +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) +void vTraceConsoleChannelPrintF(const char* fmt, ...); +#endif + +/******************************************************************************* +* xTraceRegisterString +* +* Register strings in the recorder, e.g. for names of user event channels. +* +* Example: +* myEventHandle = xTraceRegisterString("MyUserEvent"); +* ... +* vTracePrintF(myEventHandle, "My value is: %d", myValue); +******************************************************************************/ +#if (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) +traceString xTraceRegisterString(const char* name); +#else +#define xTraceRegisterString(x) (x) +#endif + +/******************************************************************************* + * vTraceSet...Name(void* object, const char* name) + * + * Parameter object: pointer to the kernel object that shall be named + * Parameter name: the name to set + * + * Kernel-specific functions for setting names of kernel objects, for display in + * Tracealyzer. + ******************************************************************************/ +/* See trcKernelPort.h for details (kernel-specific) */ + +/******************************************************************************* + * xTraceSetISRProperties + * + * Stores a name and priority level for an Interrupt Service Routine, to allow + * for better visualization. Returns a traceHandle used by vTraceStoreISRBegin. + * + * Example: + * #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt + * ... + * traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(Timer1Handle); + * ... + * vTraceStoreISREnd(0); + * } + ******************************************************************************/ +traceHandle xTraceSetISRProperties(const char* name, uint8_t priority); + +/******************************************************************************* + * vTraceStoreISRBegin + * + * Registers the beginning of an Interrupt Service Routine, using a traceHandle + * provided by xTraceSetISRProperties. + * + * Example: + * #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt + * ... + * traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(Timer1Handle); + * ... + * vTraceStoreISREnd(0); + * } + ******************************************************************************/ +void vTraceStoreISRBegin(traceHandle handle); + +/******************************************************************************* + * vTraceStoreISREnd + * + * Registers the end of an Interrupt Service Routine. + * + * The parameter pendingISR indicates if the interrupt has requested a + * task-switch (= 1), e.g., by signaling a semaphore. Otherwise (= 0) the + * interrupt is assumed to return to the previous context. + * + * Example: + * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt + * traceHandle traceHandleIsrTimer1 = 0; // The ID set by the recorder + * ... + * traceHandleIsrTimer1 = xTraceSetISRProperties("ISRTimer1", PRIO_OF_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(traceHandleIsrTimer1); + * ... + * vTraceStoreISREnd(0); + * } + ******************************************************************************/ +void vTraceStoreISREnd(int isTaskSwitchRequired); + +/******************************************************************************* + * vTraceInstanceFinishNow + * + * Creates an event that ends the current task instance at this very instant. + * This makes the viewer to splits the current fragment at this point and begin + * a new actor instance, even if no task-switch has occurred. + *****************************************************************************/ +void vTraceInstanceFinishedNow(void); + +/******************************************************************************* + * vTraceInstanceFinishedNext + * + * Marks the current "task instance" as finished on the next kernel call. + * + * If that kernel call is blocking, the instance ends after the blocking event + * and the corresponding return event is then the start of the next instance. + * If the kernel call is not blocking, the viewer instead splits the current + * fragment right before the kernel call, which makes this call the first event + * of the next instance. + *****************************************************************************/ +void vTraceInstanceFinishedNext(void); + +/******************************************************************************* + * xTraceGetLastError + * + * Returns the last error or warning as a string, or NULL if none. + *****************************************************************************/ +const char* xTraceGetLastError(void); + +/******************************************************************************* + * vTraceClearError + * + * Clears any errors. + *****************************************************************************/ +void vTraceClearError(void); + +/******************************************************************************* +* vTraceStop +* +* Stops the recording. Intended for snapshot mode or if streaming without +* Tracealyzer control (e.g., to a device file system). +******************************************************************************/ +void vTraceStop(void); + +/****************************************************************************** +* vTraceSetFrequency +* +* Registers the clock rate of the time source for the event timestamping. +* This is normally not required, but if the default value (TRC_HWTC_FREQ_HZ) +* should be incorrect for your setup, you can override it using this function. +* +* Must be called prior to vTraceEnable, and the time source is assumed to +* have a fixed clock frequency after the startup. +* +* Note that, in snapshot mode, the value is divided by the TRC_HWTC_DIVISOR. +* This is a software "prescaler" that is also applied on the timestamps. +*****************************************************************************/ +void vTraceSetFrequency(uint32_t frequency); + +/******************************************************************************* +* vTraceSetRecorderDataBuffer +* +* The trcConfig.h setting TRC_CFG_RECORDER_BUFFER_ALLOCATION allows for selecting +* custom allocation (TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM), which allows you to +* control where the recorder trace buffer is allocated. +* +* When custom allocation is selected, use TRC_ALLOC_CUSTOM_BUFFER to make the +* allocation (in global context) and then call vTraceSetRecorderDataBuffer to +* register the allocated buffer. This supports both snapshot and streaming, +* and has no effect if using other allocation modes than CUSTOM. +* +* NOTE: vTraceSetRecorderDataBuffer must be called before vTraceEnable. +******************************************************************************/ +#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM) +void vTraceSetRecorderDataBuffer(void* pRecorderData); +#else +#define vTraceSetRecorderDataBuffer(pRecorderData) +#endif + + +/******************************************************************************* +* TRC_ALLOC_CUSTOM_BUFFER +* +* If using custom allocation of the trace buffer (i.e., your trcConfig.h has the +* setting TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM), this macro allows you to declare +* the trace buffer in a portable way that works both in snapshot and streaming. +* +* This macro has no effect if using another allocation mode, so you can easily +* switch between different recording modes and configurations, using the same +* initialization code. +* +* This translates to a single static allocation, on which you can apply linker +* directives to place it in a particular memory region. +* +* - Snapshot mode: "RecorderDataType " +* +* - Streaming mode: "char []", +* where is defined in trcStreamingConfig.h. +* +* Example: +* +* // GCC example: place myTraceBuffer in section .tz, defined in the .ld file. +* TRC_ALLOC_CUSTOM_BUFFER(myTraceBuffer) __attribute__((section(".tz"))); +* +* int main(void) +* { +* ... +* vTraceSetRecorderDataBuffer(&myTraceBuffer); // Note the "&" +* ... +* vTraceEnable(TRC_INIT); // Initialize the data structure +******************************************************************************/ +#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM) + #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) + #define TRC_ALLOC_CUSTOM_BUFFER(bufname) RecorderDataType bufname; + #elif (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) + #ifdef TRC_CFG_RTT_BUFFER_SIZE_UP /* J-Link RTT */ + #define TRC_ALLOC_CUSTOM_BUFFER(bufname) char bufname [TRC_CFG_RTT_BUFFER_SIZE_UP]; /* Not static in this case, since declared in user code */ + #else + #define TRC_ALLOC_CUSTOM_BUFFER(bufname) char bufname [(TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT) * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)]; + #endif + #endif +#else + #define TRC_ALLOC_CUSTOM_BUFFER(bufname) +#endif + +/****************************************************************************** +* xTraceIsRecordingEnabled +* +* Returns true (1) if the recorder is enabled (i.e. is recording), otherwise 0. +******************************************************************************/ +int xTraceIsRecordingEnabled(void); + +/******************************************************************************* +* vTraceSetFilterGroup +* +* Sets the "filter group" to assign when creating RTOS objects, such as tasks, +* queues, semaphores and mutexes. This together with vTraceSetFilterMask +* allows you to control what events that are recorded, based on the +* objects they refer to. +* +* There are 16 filter groups named FilterGroup0 .. FilterGroup15. +* +* Note: We don't recommend filtering out the Idle task, so make sure to call +* vTraceSetFilterGroup just before initializing the RTOS, in order to assign +* such "default" objects to the right Filter Group (typically group 0). +* +* Example: +* +* // Assign tasks T1 to FilterGroup0 (default) +* +* +* // Assign Q1 and Q2 to FilterGroup1 +* vTraceSetFilterGroup(FilterGroup1); +* +* +* +* // Assigns Q3 to FilterGroup2 +* vTraceSetFilterGroup(FilterGroup2); +* +* +* // Only include FilterGroup0 and FilterGroup2, exclude FilterGroup1 (Q1 and Q2) from the trace +* vTraceSetFilterMask( FilterGroup0 | FilterGroup2 ); +* +* // Assign the default RTOS objects (e.g. Idle task) to FilterGroup0 +* vTraceSetFilterGroup(FilterGroup0); +* +* +* Note that you may define your own names for the filter groups using +* preprocessor definitions, to make the code easier to understand. +* +* Example: +* +* #define BASE FilterGroup0 +* #define USB_EVENTS FilterGroup1 +* #define CAN_EVENTS FilterGroup2 +* +* Note that filtering per event type (regardless of object) is also available +* in trcConfig.h. +******************************************************************************/ +void vTraceSetFilterGroup(uint16_t filterGroup); + +/****************************************************************************** +* vTraceSetFilterMask +* +* Sets the "filter mask" that is used to filter the events by object. This can +* be used to reduce the trace data rate, i.e., if your streaming interface is +* a bottleneck or if you want longer snapshot traces without increasing the +* buffer size. +* +* Note: There are two kinds of filters in the recorder. The other filter type +* excludes all events of certain kinds (e.g., OS ticks). See trcConfig.h. +* +* The filtering is based on bitwise AND with the Filter Group ID, assigned +* to RTOS objects such as tasks, queues, semaphores and mutexes. +* This together with vTraceSetFilterGroup allows you to control what +* events that are recorded, based on the objects they refer to. +* +* See example for vTraceSetFilterGroup. +******************************************************************************/ +void vTraceSetFilterMask(uint16_t filterMask); + +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) + +/******************************************************************************/ +/*** Extended API for Snapshot mode *******************************************/ +/******************************************************************************/ + +/****************************************************************************** +* TRACE_STOP_HOOK - Hook Pointer Data Type +* +* Declares a data type for a call back function that will be invoked whenever +* the recorder is stopped. +* +* Snapshot mode only! +******************************************************************************/ +typedef void(*TRACE_STOP_HOOK)(void); + +/******************************************************************************* +* vTraceStopHookPtr +* +* Points to a call back function that is called from vTraceStop(). +* +* Snapshot mode only! +******************************************************************************/ +extern TRACE_STOP_HOOK vTraceStopHookPtr; + +/******************************************************************************* +* vTraceSetStopHook +* +* Sets a function to be called when the recorder is stopped. +* +* Snapshot mode only! +******************************************************************************/ +void vTraceSetStopHook(TRACE_STOP_HOOK stopHookFunction); + +/******************************************************************************* +* uiTraceStart +* +* [DEPRECATED] Use vTraceEnable instead. +* +* Starts the recorder. The recorder will not be started if an error has been +* indicated using prvTraceError, e.g. if any of the Nx constants in +* trcSnapshotConfig.h has a too small value (TRC_CFG_NTASK, TRC_CFG_NQUEUE, etc). +* +* Returns 1 if the recorder was started successfully. +* Returns 0 if the recorder start was prevented due to a previous internal +* error. In that case, check xTraceGetLastError to get the error message. +* Any error message is also presented when opening a trace file. +* +* Snapshot mode only! +******************************************************************************/ +uint32_t uiTraceStart(void); + +/******************************************************************************* +* vTraceStart +* +* [DEPRECATED] Use vTraceEnable instead. +* +* Starts the recorder. The recorder will not be started if an error has been +* indicated using prvTraceError, e.g. if any of the Nx constants in +* trcSnapshotConfig.h has a too small value (TRC_CFG_NTASK, TRC_CFG_NQUEUE, etc). +* +* Snapshot mode only! +******************************************************************************/ +void vTraceStart(void); + +/******************************************************************************* +* vTraceClear +* +* Resets the recorder. Only necessary if a restart is desired - this is not +* needed in the startup initialization. +* +* Snapshot mode only! +******************************************************************************/ +void vTraceClear(void); + + +/*****************************************************************************/ +/*** INTERNAL SNAPSHOT FUNCTIONS *********************************************/ +/*****************************************************************************/ + +#define TRC_UNUSED + +#ifndef TRC_CFG_INCLUDE_OBJECT_DELETE +#define TRC_CFG_INCLUDE_OBJECT_DELETE 0 +#endif + +#ifndef TRC_CFG_INCLUDE_READY_EVENTS +#define TRC_CFG_INCLUDE_READY_EVENTS 1 +#endif + +#ifndef TRC_CFG_INCLUDE_OSTICK_EVENTS +#define TRC_CFG_INCLUDE_OSTICK_EVENTS 0 +#endif + +/* This macro will create a task in the object table */ +#undef trcKERNEL_HOOKS_TASK_CREATE +#define trcKERNEL_HOOKS_TASK_CREATE(SERVICE, CLASS, pxTCB) \ + TRACE_SET_OBJECT_NUMBER(TASK, pxTCB); \ + TRACE_SET_OBJECT_FILTER(TASK, pxTCB, CurrentFilterGroup); \ + prvTraceSetObjectName(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_GET_TASK_NAME(pxTCB)); \ + prvTraceSetPriorityProperty(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_GET_TASK_PRIORITY(pxTCB)); \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ + prvTraceStoreKernelCall(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); + +/* This macro will remove the task and store it in the event buffer */ +#undef trcKERNEL_HOOKS_TASK_DELETE +#define trcKERNEL_HOOKS_TASK_DELETE(SERVICE, SERVICE_NAME, SERVICE_PROP, pxTCB) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ + prvTraceStoreKernelCall(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); \ + prvTraceStoreObjectNameOnCloseEvent(SERVICE_NAME, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_CLASS_TASK); \ + prvTraceStoreObjectPropertiesOnCloseEvent(SERVICE_PROP, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_CLASS_TASK); \ + prvTraceSetPriorityProperty(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_GET_TASK_PRIORITY(pxTCB)); \ + prvTraceSetObjectState(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), TASK_STATE_INSTANCE_NOT_ACTIVE); \ + prvTraceFreeObjectHandle(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); + + +/* This macro will setup a task in the object table */ +#undef trcKERNEL_HOOKS_OBJECT_CREATE +#define trcKERNEL_HOOKS_OBJECT_CREATE(SERVICE, CLASS, pxObject)\ + TRACE_SET_OBJECT_NUMBER(CLASS, pxObject);\ + TRACE_SET_OBJECT_FILTER(CLASS, pxObject, CurrentFilterGroup); \ + prvMarkObjectAsUsed(TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject));\ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(CLASS, pxObject) & CurrentFilterMask) \ + prvTraceStoreKernelCall(SERVICE, TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject)); \ + prvTraceSetObjectState(TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), 0); + +/* This macro will remove the object and store it in the event buffer */ +#undef trcKERNEL_HOOKS_OBJECT_DELETE +#define trcKERNEL_HOOKS_OBJECT_DELETE(SERVICE, SERVICE_NAME, SERVICE_PROP, CLASS, pxObject) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(CLASS, pxObject) & CurrentFilterMask) \ + prvTraceStoreKernelCall(SERVICE, TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject)); \ + prvTraceStoreObjectNameOnCloseEvent(SERVICE_NAME, TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject)); \ + prvTraceStoreObjectPropertiesOnCloseEvent(SERVICE_PROP, TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject)); \ + prvTraceFreeObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject)); + +/* This macro will create a call to a kernel service with a certain result, with an object as parameter */ +#undef trcKERNEL_HOOKS_KERNEL_SERVICE +#define trcKERNEL_HOOKS_KERNEL_SERVICE(SERVICE, CLASS, pxObject) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(CLASS, pxObject) & CurrentFilterMask) \ + prvTraceStoreKernelCall(SERVICE, TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject)); + +/* This macro will create a call to a kernel service with a certain result, with a null object as parameter */ +#undef trcKERNEL_HOOKS_KERNEL_SERVICE_NULL_OBJECT +#define trcKERNEL_HOOKS_KERNEL_SERVICE_NULL_OBJECT(SERVICE, TRACECLASS) \ + if (TRACE_GET_TASK_FILTER(TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreKernelCall(SERVICE, TRACECLASS, 0); + +/* This macro will create a call to a kernel service with a certain result, with an object as parameter */ +#undef trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM +#define trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(SERVICE, CLASS, pxObject, param) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(CLASS, pxObject) & CurrentFilterMask) \ + prvTraceStoreKernelCallWithParam(SERVICE, TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), (uint32_t)param); + +/* This macro will create a call to a kernel service with a certain result, with a null object and other value as parameter */ +#undef trcKERNEL_HOOKS_KERNEL_SERVICE_NULL_OBJECT_WITH_PARAM +#define trcKERNEL_HOOKS_KERNEL_SERVICE_NULL_OBJECT_WITH_PARAM(SERVICE, TRACECLASS, param) \ + if (TRACE_GET_TASK_FILTER(TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreKernelCallWithParam(SERVICE, TRACECLASS, 0, param); + +/* This macro will create a call to a kernel service with a certain result, with an object as parameter */ +#undef trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY +#define trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY(SERVICE, param) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceStoreKernelCallWithNumericParamOnly(SERVICE, (uint32_t)param); + +/* This macro will create a call to a kernel service with a certain result, with an object as parameter */ +#undef trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR +#define trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(SERVICE, CLASS, pxObject) \ + if (TRACE_GET_OBJECT_FILTER(CLASS, pxObject) & CurrentFilterMask) \ + prvTraceStoreKernelCall(SERVICE, TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject)); + +/* This macro will create a call to a kernel service with a certain result, with an object as parameter */ +#undef trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM_FROM_ISR +#define trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM_FROM_ISR(SERVICE, CLASS, pxObject, param) \ + if (TRACE_GET_OBJECT_FILTER(CLASS, pxObject) & CurrentFilterMask) \ + prvTraceStoreKernelCallWithParam(SERVICE, TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), (uint32_t)param); + +/* This macro will create a call to a kernel service with a certain result, with an object as parameter */ +#undef trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY_FROM_ISR +#define trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY_FROM_ISR(SERVICE, param) \ + prvTraceStoreKernelCallWithNumericParamOnly(SERVICE, (uint32_t)param); + +/* This macro will set the state for an object */ +#undef trcKERNEL_HOOKS_SET_OBJECT_STATE +#define trcKERNEL_HOOKS_SET_OBJECT_STATE(CLASS, pxObject, STATE) \ + prvTraceSetObjectState(TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), (uint8_t)STATE); + +/* This macro will flag a certain task as a finished instance */ +#undef trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED +#define trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED() \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + prvTraceSetTaskInstanceFinished(TRACE_GET_TASK_NUMBER(TRACE_GET_CURRENT_TASK())); + +#if (TRC_CFG_INCLUDE_READY_EVENTS == 1) +/* This macro will create an event to indicate that a task became Ready */ +#undef trcKERNEL_HOOKS_MOVED_TASK_TO_READY_STATE +#define trcKERNEL_HOOKS_MOVED_TASK_TO_READY_STATE(pxTCB) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ + prvTraceStoreTaskReady(TRACE_GET_TASK_NUMBER(pxTCB)); +#else /*(TRC_CFG_INCLUDE_READY_EVENTS == 1)*/ +#undef trcKERNEL_HOOKS_MOVED_TASK_TO_READY_STATE +#define trcKERNEL_HOOKS_MOVED_TASK_TO_READY_STATE(pxTCB) +#endif /*(TRC_CFG_INCLUDE_READY_EVENTS == 1)*/ + +/* This macro will update the internal tick counter and call prvTracePortGetTimeStamp(0) to update the internal counters */ +#undef trcKERNEL_HOOKS_INCREMENT_TICK +#define trcKERNEL_HOOKS_INCREMENT_TICK() \ + { \ + extern uint32_t uiTraceTickCount; \ + uiTraceTickCount++; \ + prvTracePortGetTimeStamp(0); \ + } + +#if (TRC_CFG_INCLUDE_OSTICK_EVENTS == 1) +/* This macro will create an event indicating that the OS tick count has increased */ +#undef trcKERNEL_HOOKS_NEW_TIME +#define trcKERNEL_HOOKS_NEW_TIME(SERVICE, xValue) \ + prvTraceStoreKernelCallWithNumericParamOnly(SERVICE, xValue); +#else /*(TRC_CFG_INCLUDE_OSTICK_EVENTS == 1)*/ +#undef trcKERNEL_HOOKS_NEW_TIME +#define trcKERNEL_HOOKS_NEW_TIME(SERVICE, xValue) +#endif /*(TRC_CFG_INCLUDE_OSTICK_EVENTS == 1)*/ + +/* This macro will create a task switch event to the currently executing task */ +#undef trcKERNEL_HOOKS_TASK_SWITCH +#define trcKERNEL_HOOKS_TASK_SWITCH( pxTCB ) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ + prvTraceStoreTaskswitch(TRACE_GET_TASK_NUMBER(pxTCB)); + +/* This macro will create an event to indicate that the task has been suspended */ +#undef trcKERNEL_HOOKS_TASK_SUSPEND +#define trcKERNEL_HOOKS_TASK_SUSPEND(SERVICE, pxTCB) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ + prvTraceStoreKernelCall(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); \ + prvTraceSetTaskInstanceFinished((uint8_t)TRACE_GET_TASK_NUMBER(pxTCB)); + +/* This macro will create an event to indicate that a task has called a wait/delay function */ +#undef trcKERNEL_HOOKS_TASK_DELAY +#define trcKERNEL_HOOKS_TASK_DELAY(SERVICE, pxTCB, xValue) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ + { \ + prvTraceStoreKernelCallWithNumericParamOnly(SERVICE, xValue); \ + prvTraceSetTaskInstanceFinished((uint8_t)TRACE_GET_TASK_NUMBER(pxTCB)); \ + } + +/* This macro will create an event to indicate that a task has gotten its priority changed */ +#undef trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE +#define trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE(SERVICE, pxTCB, uxNewPriority) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ + { \ + prvTraceStoreKernelCallWithParam(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), prvTraceGetPriorityProperty(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)));\ + prvTraceSetPriorityProperty(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), (uint8_t)uxNewPriority); \ + } + +/* This macro will create an event to indicate that the task has been resumed */ +#undef trcKERNEL_HOOKS_TASK_RESUME +#define trcKERNEL_HOOKS_TASK_RESUME(SERVICE, pxTCB) \ + if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ + prvTraceStoreKernelCall(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); + +#undef trcKERNEL_HOOKS_TASK_RESUME_FROM_ISR +#define trcKERNEL_HOOKS_TASK_RESUME_FROM_ISR(SERVICE, pxTCB) \ + if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ + prvTraceStoreKernelCall(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); + +#if !defined TRC_CFG_INCLUDE_READY_EVENTS || TRC_CFG_INCLUDE_READY_EVENTS == 1 + void prvTraceSetReadyEventsEnabled(int status); + void prvTraceStoreTaskReady(traceHandle handle); +#else + #define prvTraceSetReadyEventsEnabled(status) +#endif + +void prvTraceStoreLowPower(uint32_t flag); + +void prvTraceStoreTaskswitch(traceHandle task_handle); + + +#if (TRC_CFG_SCHEDULING_ONLY == 0) + +void prvTraceStoreKernelCall(uint32_t eventcode, traceObjectClass objectClass, uint32_t byteParam); + +void prvTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint32_t param); + +void prvTraceStoreKernelCallWithParam(uint32_t evtcode, traceObjectClass objectClass, + uint32_t objectNumber, uint32_t param); +#else + +#define prvTraceStoreKernelCall(eventcode, objectClass, byteParam) {} +#define prvTraceStoreKernelCallWithNumericParamOnly(evtcode, param) {} +#define prvTraceStoreKernelCallWithParam(evtcode, objectClass, objectNumber, param) {} + +#endif + +void prvTraceSetTaskInstanceFinished(traceHandle handle); + +void prvTraceSetPriorityProperty(uint8_t objectclass, traceHandle id, uint8_t value); + +uint8_t prvTraceGetPriorityProperty(uint8_t objectclass, traceHandle id); + +void prvTraceSetObjectState(uint8_t objectclass, traceHandle id, uint8_t value); + +void prvMarkObjectAsUsed(traceObjectClass objectclass, traceHandle handle); + +void prvTraceStoreObjectNameOnCloseEvent(uint8_t evtcode, traceHandle handle, + traceObjectClass objectclass); + +void prvTraceStoreObjectPropertiesOnCloseEvent(uint8_t evtcode, traceHandle handle, + traceObjectClass objectclass); + +/* Internal constants for task state */ +#define TASK_STATE_INSTANCE_NOT_ACTIVE 0 +#define TASK_STATE_INSTANCE_ACTIVE 1 + + +#if (TRC_CFG_INCLUDE_ISR_TRACING == 0) + +#undef vTraceSetISRProperties +#define vTraceSetISRProperties(handle, name, priority) + +#undef vTraceStoreISRBegin +#define vTraceStoreISRBegin(x) (void)x + +#undef vTraceStoreISREnd +#define vTraceStoreISREnd(x) (void)x + +#undef xTraceSetISRProperties +#define xTraceSetISRProperties(name, priority) 0 + +#endif /*(TRC_CFG_INCLUDE_ISR_TRACING == 0)*/ + +/******************************************************************************* + * xTraceGetTraceBuffer + * + * Returns a pointer to the recorder data structure. Use this together with + * uiTraceGetTraceBufferSize if you wish to implement an own store/upload + * solution, e.g., in case a debugger connection is not available for uploading + * the data. + ******************************************************************************/ +void* xTraceGetTraceBuffer(void); + +/******************************************************************************* + * uiTraceGetTraceBufferSize + * + * Gets the size of the recorder data structure. For use together with + * vTraceGetTraceBuffer if you wish to implement an own store/upload solution, + * e.g., in case a debugger connection is not available for uploading the data. + ******************************************************************************/ +uint32_t uiTraceGetTraceBufferSize(void); + +#if (TRC_CFG_SCHEDULING_ONLY == 1) +#undef TRC_CFG_INCLUDE_USER_EVENTS +#define TRC_CFG_INCLUDE_USER_EVENTS 0 +#endif /*(TRC_CFG_SCHEDULING_ONLY == 1)*/ + +#if ((TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)) + +#if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1) +traceUBChannel xTraceRegisterUBChannel(traceString channel, traceString formatStr); +void vTraceUBData(traceUBChannel channel, ...); +void vTraceUBEvent(traceUBChannel channel); +#endif /*(TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)*/ + +#else /*((TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_SCHEDULING_ONLY == 0))*/ + +#undef vTracePrint +#define vTracePrint(chn, ...) (void)chn +#undef vTracePrintF +#define vTracePrintF(chn, ...) (void)chn +#undef xTraceRegisterString +#define xTraceRegisterString(x) 0; (void)x; +#undef xTraceRegisterChannelFormat +#define xTraceRegisterChannelFormat(eventLabel, formatStr) 0 +#undef vTraceUBData +#define vTraceUBData(label, ...) {} +#undef vTraceChannelPrint +#define vTraceChannelPrint(label) {} + +#endif /*(TRC_CFG_INCLUDE_USER_EVENTS == 1)*/ + +#define NEventCodes 0x100 + +/* Our local critical sections for the recorder */ +#define trcCRITICAL_SECTION_BEGIN() {TRACE_ENTER_CRITICAL_SECTION(); recorder_busy++;} +#define trcCRITICAL_SECTION_END() {recorder_busy--; TRACE_EXIT_CRITICAL_SECTION();} + +#if (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M) + #define trcSR_ALLOC_CRITICAL_SECTION_ON_CORTEX_M_ONLY TRACE_ALLOC_CRITICAL_SECTION + #define trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY trcCRITICAL_SECTION_BEGIN + #define trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY trcCRITICAL_SECTION_END +#else + #define trcSR_ALLOC_CRITICAL_SECTION_ON_CORTEX_M_ONLY() {} + #define trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY() recorder_busy++; + #define trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY() recorder_busy--; +#endif + +/****************************************************************************** + * ObjectHandleStack + * This data-structure is used to provide a mechanism for 1-byte trace object + * handles. This way, only 1 byte is necessary instead of 4 bytes (a pointer) + * when storing a reference to an object. This allows for up to 255 objects of + * each object class active at any given moment. There can be more "historic" + * objects, that have been deleted - that number is only limited by the size of + * the symbol table. + * + * Note that handle zero (0) is not used, it is a code for an invalid handle. + * + * This data structure keeps track of the FREE handles, not the handles in use. + * This data structure contains one stack per object class. When a handle is + * allocated to an object, the next free handle is popped from the stack. When + * a handle is released (on object delete), it is pushed back on the stack. + * Note that there is no initialization code that pushed the free handles + * initially, that is not necessary due to the following optimization: + * + * The stack of handles (objectHandles) is initially all zeros. Since zero + * is not a valid handle, that is a signal of additional handles needed. + * If a zero is received when popping a new handle, it is replaced by the + * index of the popped handle instead. + *****************************************************************************/ +typedef struct +{ + /* For each object class, the index of the next handle to allocate */ + uint16_t indexOfNextAvailableHandle[ TRACE_NCLASSES ]; + + /* The lowest index of this class (constant) */ + uint16_t lowestIndexOfClass[ TRACE_NCLASSES ]; + + /* The highest index of this class (constant) */ + uint16_t highestIndexOfClass[ TRACE_NCLASSES ]; + + /* The highest use count for this class (for statistics) */ + uint16_t handleCountWaterMarksOfClass[ TRACE_NCLASSES ]; + + /* The free object handles - a set of stacks within this array */ + traceHandle objectHandles[ TRACE_KERNEL_OBJECT_COUNT ]; + +} objectHandleStackType; + +extern objectHandleStackType objectHandleStacks; + +/****************************************************************************** + * Object Property Table + * The Object Table contains name and other properties of the objects (tasks, + * queues, mutexes, etc). The below data structures defines the properties of + * each object class and are used to cast the byte buffer into a cleaner format. + * + * The values in the object table are continuously overwritten and always + * represent the current state. If a property is changed during runtime, the OLD + * value should be stored in the trace buffer, not the new value (since the new + * value is found in the Object Property Table). + * + * For close events this mechanism is the old names are stored in the symbol + * table), for "priority set" (the old priority is stored in the event data) + * and for "isActive", where the value decides if the task switch event type + * should be "new" or "resume". + ******************************************************************************/ + +typedef struct +{ + /* = NCLASSES */ + uint32_t NumberOfObjectClasses; + + uint32_t ObjectPropertyTableSizeInBytes; + + /* This is used to calculate the index in the dynamic object table + (handle - 1 - nofStaticObjects = index)*/ +#if (TRC_CFG_USE_16BIT_OBJECT_HANDLES == 1) + traceHandle NumberOfObjectsPerClass[2*((TRACE_NCLASSES+1)/2)]; +#else + traceHandle NumberOfObjectsPerClass[4*((TRACE_NCLASSES+3)/4)]; +#endif + + /* Allocation size rounded up to the closest multiple of 4 */ + uint8_t NameLengthPerClass[ 4*((TRACE_NCLASSES+3)/4) ]; + + uint8_t TotalPropertyBytesPerClass[ 4*((TRACE_NCLASSES+3)/4) ]; + + /* Allocation size rounded up to the closest multiple of 2 */ + uint16_t StartIndexOfClass[ 2*((TRACE_NCLASSES+1)/2) ]; + + /* The actual handles issued, should be Initiated to all zeros */ + uint8_t objbytes[ 4*((TRACE_OBJECT_TABLE_SIZE+3)/4) ]; +} ObjectPropertyTableType; + +/* Symbol table data structure */ +typedef struct +{ + /* = SYMBOL_HISTORY_TABLE_SIZE_IN_BYTES */ + uint32_t symTableSize; + + /* Entry 0 is reserved. Any reference to entry 0 implies NULL*/ + uint32_t nextFreeSymbolIndex; + + /* Size rounded up to closest multiple of 4, to avoid alignment issues*/ + uint8_t symbytes[4*(((TRC_CFG_SYMBOL_TABLE_SIZE)+3)/4)]; + + /* Used for lookups - Up to 64 linked lists within the symbol table + connecting all entries with the same 6 bit checksum. + This field holds the current list heads. Should be initiated to zeros */ + uint16_t latestEntryOfChecksum[64]; +} symbolTableType; + + +/******************************************************************************* + * The data structures of the different events, all 4 bytes long + ******************************************************************************/ + +typedef struct +{ + uint8_t type; + uint8_t objHandle; + uint16_t dts; /* differential timestamp - time since last event */ +} TSEvent, TREvent; + +typedef struct +{ + uint8_t type; + uint8_t dummy; + uint16_t dts; /* differential timestamp - time since last event */ +} LPEvent; + +typedef struct +{ + uint8_t type; + uint8_t objHandle; + uint16_t dts; /* differential timestamp - time since last event */ +} KernelCall; + +typedef struct +{ + uint8_t type; + uint8_t objHandle; + uint8_t param; + uint8_t dts; /* differential timestamp - time since last event */ +} KernelCallWithParamAndHandle; + +typedef struct +{ + uint8_t type; + uint8_t dts; /* differential timestamp - time since last event */ + uint16_t param; +} KernelCallWithParam16; + +typedef struct +{ + uint8_t type; + uint8_t objHandle; /* the handle of the closed object */ + uint16_t symbolIndex; /* the name of the closed object */ +} ObjCloseNameEvent; + +typedef struct +{ + uint8_t type; + uint8_t arg1; + uint8_t arg2; + uint8_t arg3; +} ObjClosePropEvent; + +typedef struct +{ + uint8_t type; + uint8_t unused1; + uint8_t unused2; + uint8_t dts; +} TaskInstanceStatusEvent; + +typedef struct +{ + uint8_t type; + uint8_t dts; + uint16_t payload; /* the name of the user event */ +} UserEvent; + +typedef struct +{ + uint8_t type; + + /* 8 bits extra for storing DTS, if it does not fit in ordinary event + (this one is always MSB if used) */ + uint8_t xts_8; + + /* 16 bits extra for storing DTS, if it does not fit in ordinary event. */ + uint16_t xts_16; +} XTSEvent; + +typedef struct +{ + uint8_t type; + + uint8_t xps_8; + uint16_t xps_16; +} XPSEvent; + +typedef struct{ + uint8_t type; + uint8_t dts; + uint16_t size; +} MemEventSize; + +typedef struct{ + uint8_t type; + uint8_t addr_high; + uint16_t addr_low; +} MemEventAddr; + +/******************************************************************************* + * The separate user event buffer structure. Can be enabled in trcConfig.h. + ******************************************************************************/ + +#if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1) +typedef struct +{ + traceString name; + traceString defaultFormat; +} ChannelFormatPair; + +typedef struct +{ + uint16_t bufferID; + uint16_t version; + uint32_t wraparoundCounter; + uint32_t numberOfSlots; + uint32_t nextSlotToWrite; + uint8_t numberOfChannels; + uint8_t padding1; + uint8_t padding2; + uint8_t padding3; + ChannelFormatPair channels[(TRC_CFG_UB_CHANNELS)+1]; + uint8_t channelBuffer[((TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) + 3) & 0xFFFFFFFC]; /* 1 byte per slot, with padding for 4 byte alignment */ + uint8_t dataBuffer[(TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) * 4]; /* 4 bytes per slot */ + +} UserEventBuffer; +#endif + +/******************************************************************************* + * The main data structure, read by Tracealyzer from the RAM dump + ******************************************************************************/ + +typedef struct +{ + volatile uint8_t startmarker0; /* Volatile is important, see init code. */ + volatile uint8_t startmarker1; + volatile uint8_t startmarker2; + volatile uint8_t startmarker3; + volatile uint8_t startmarker4; + volatile uint8_t startmarker5; + volatile uint8_t startmarker6; + volatile uint8_t startmarker7; + volatile uint8_t startmarker8; + volatile uint8_t startmarker9; + volatile uint8_t startmarker10; + volatile uint8_t startmarker11; + + /* Used to determine Kernel and Endianess */ + uint16_t version; + + /* Currently 5 */ + uint8_t minor_version; + + /* This should be 0 if lower IRQ priority values implies higher priority + levels, such as on ARM Cortex M. If the opposite scheme is used, i.e., + if higher IRQ priority values means higher priority, this should be 1. */ + uint8_t irq_priority_order; + + /* sizeof(RecorderDataType) - just for control */ + uint32_t filesize; + + /* Current number of events recorded */ + uint32_t numEvents; + + /* The buffer size, in number of event records */ + uint32_t maxEvents; + + /* The event buffer index, where to write the next event */ + uint32_t nextFreeIndex; + + /* 1 if the buffer is full, 0 otherwise */ + uint32_t bufferIsFull; + + /* The frequency of the clock/timer/counter used as time base */ + uint32_t frequency; + + /* The absolute timestamp of the last stored event, in the native + timebase, modulo frequency! */ + uint32_t absTimeLastEvent; + + /* The number of seconds in total - lasts for 136 years */ + uint32_t absTimeLastEventSecond; + + /* 1 if the recorder has been started, 0 if not yet started or stopped. + This is a 32 bit variable due to alignment issues. */ + uint32_t recorderActive; + + /* If > 0, tells the maximum time between two traced ISRs that execute + back-to-back. If the time between vTraceStoreISREnd and a directly + following vTraceISRBegin is above isrTailchainingThreshold, we assume a + return to the previous context in between the ISRs, otherwise we assume + the have executed back-to-back and don't show any fragment of the previous + context in between. */ + uint32_t isrTailchainingThreshold; + + /* Not used, remains for compatibility and future use */ + uint8_t notused[24]; + + /* The amount of heap memory remaining at the last malloc or free event */ + uint32_t heapMemUsage; + + /* 0xF0F0F0F0 - for control only */ + int32_t debugMarker0; + + /* Set to value of TRC_CFG_USE_16BIT_OBJECT_HANDLES */ + uint32_t isUsing16bitHandles; + + /* The Object Property Table holds information about currently active + tasks, queues, and other recorded objects. This is updated on each + create call and includes object name and other properties. */ + ObjectPropertyTableType ObjectPropertyTable; + + /* 0xF1F1F1F1 - for control only */ + int32_t debugMarker1; + + /* The Symbol Table stores strings for User Events and is also used to + store names of deleted objects, which still may be in the trace but no + longer are available. */ + symbolTableType SymbolTable; + + /* For inclusion of float support, and for endian detection of floats. + The value should be (float)1 or (uint32_t)0 */ +#if (TRC_CFG_INCLUDE_FLOAT_SUPPORT == 1) + float exampleFloatEncoding; +#else + uint32_t exampleFloatEncoding; +#endif + /* This is non-zero if an internal error occurred in the recorder, e.g., if + one of the Nxxx constants was too small. The systemInfo string will then + contain an error message that is displayed when attempting to view the + trace file. */ + uint32_t internalErrorOccured; + + /* 0xF2F2F2F2 - for control only */ + int32_t debugMarker2; + + /* Error messages from the recorder. */ + char systemInfo[80]; + + /* 0xF3F3F3F3 - for control only */ + int32_t debugMarker3; + + /* The event data, in 4-byte records */ + uint8_t eventData[ (TRC_CFG_EVENT_BUFFER_SIZE) * 4 ]; + +#if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1) + UserEventBuffer userEventBuffer; +#endif + + /* This should always be 0 */ + uint32_t endOfSecondaryBlocks; + + uint8_t endmarker0; + uint8_t endmarker1; + uint8_t endmarker2; + uint8_t endmarker3; + uint8_t endmarker4; + uint8_t endmarker5; + uint8_t endmarker6; + uint8_t endmarker7; + uint8_t endmarker8; + uint8_t endmarker9; + uint8_t endmarker10; + uint8_t endmarker11; +} RecorderDataType; + +extern RecorderDataType* RecorderDataPtr; + +/* Internal functions */ + +/* Signal an error. */ +void prvTraceError(const char* msg); + +/******************************************************************************* + * prvTracePortGetTimeStamp + * + * Returns the current time based on the HWTC macros which provide a hardware + * isolation layer towards the hardware timer/counter. + * + * The HWTC macros and prvTracePortGetTimeStamp is the main porting issue + * or the trace recorder library. Typically you should not need to change + * the code of prvTracePortGetTimeStamp if using the HWTC macros. + * + ******************************************************************************/ +void prvTracePortGetTimeStamp(uint32_t *puiTimestamp); + +traceHandle prvTraceGetObjectHandle(traceObjectClass objectclass); + +void prvTraceFreeObjectHandle(traceObjectClass objectclass, + traceHandle handle); + +/* Private function. Use the public functions in trcKernelPort.h */ +void prvTraceSetObjectName(traceObjectClass objectclass, + traceHandle handle, + const char* name); + +/* Internal macros */ + +#define TRACE_PROPERTY_NAME_GET(objectclass, objecthandle) \ +(const char*)(& RecorderDataPtr->ObjectPropertyTable.objbytes \ +[uiIndexOfObject(objecthandle, objectclass)]) + +#define TRACE_PROPERTY_OBJECT_STATE(objectclass, handle) \ +RecorderDataPtr->ObjectPropertyTable.objbytes[uiIndexOfObject(handle, objectclass) \ ++ RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[objectclass]] + +#define TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, handle) \ +RecorderDataPtr->ObjectPropertyTable.objbytes[uiIndexOfObject(handle, objectclass) \ ++ RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[objectclass] + 1] + +/* DEBUG ASSERTS */ +#if defined TRC_CFG_USE_TRACE_ASSERT && TRC_CFG_USE_TRACE_ASSERT != 0 +#define TRACE_ASSERT(eval, msg, defRetVal) \ +if (!(eval)) \ +{ \ + prvTraceError("TRACE_ASSERT: " msg); \ + return defRetVal; \ +} +#else +#define TRACE_ASSERT(eval, msg, defRetVal) +#endif + +#endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)*/ + +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) + +/****************************************************************************** + * Default values for STREAM PORT macros + * + * As a normal user, this is nothing you don't need to bother about. This is + * only important if you want to define your own custom streaming interface. + * + * You may override these in your own trcStreamingPort.h to create a custom + * stream port, and thereby stream the trace on any host-target interface. + * These default values are suitable for most cases, except the J-Link port. + ******************************************************************************/ + +/****************************************************************************** + * TRC_STREAM_PORT_USE_INTERNAL_BUFFER + * + * There are two kinds of stream ports, those that store the event to the + * internal buffer (with periodic flushing by the TzCtrl task) and those that + * write directly to the streaming interface. Most stream ports use the + * recorder's internal buffer, except for the SEGGER J-Link port (also uses a + * RAM buffer, but one defined in the SEGGER code). + * + * If the stream port (trcStreamingPort.h) defines this as zero (0), it is + * expected to transmit the data directly using TRC_STREAM_PORT_COMMIT_EVENT. + * Otherwise it is expected that the trace data is stored in the internal buffer + * and the TzCtrl task will then send the buffer pages when they become full. + ******************************************************************************/ +#ifndef TRC_STREAM_PORT_USE_INTERNAL_BUFFER +#define TRC_STREAM_PORT_USE_INTERNAL_BUFFER 1 +#endif + + /****************************************************************************** + * TRC_STREAM_PORT_ON_TRACE_BEGIN + * + * Defining any actions needed in the stream port when the recording is activated. + *******************************************************************************/ +#ifndef TRC_STREAM_PORT_ON_TRACE_BEGIN + #define TRC_STREAM_PORT_ON_TRACE_BEGIN() /* Do nothing */ +#endif + + /****************************************************************************** + * TRC_STREAM_PORT_ON_TRACE_BEGIN + * + * Defining any actions needed in the stream port when the tracing stops. + * Empty by default. + *******************************************************************************/ +#ifndef TRC_STREAM_PORT_ON_TRACE_END +#define TRC_STREAM_PORT_ON_TRACE_END() /* Do nothing */ +#endif + + /****************************************************************************** + * TRC_STREAM_PORT_ALLOCATE_EVENT + * + * This macro is used to allocate memory for each event record, just before + * assigning the record fields. + * Depending on "TRC_STREAM_PORT_USE_INTERNAL_BUFFER", this either allocates + * space in the paged event buffer, or on the local stack. In the latter case, + * the COMMIT event is used to write the data to the streaming interface. + ******************************************************************************/ +#ifndef TRC_STREAM_PORT_ALLOCATE_EVENT +#if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1) + #define TRC_STREAM_PORT_ALLOCATE_EVENT(_type, _ptrData, _size) _type* _ptrData; _ptrData = (_type*)prvPagedEventBufferGetWritePointer(_size); +#else + #define TRC_STREAM_PORT_ALLOCATE_EVENT(_type, _ptrData, _size) _type _tmpArray[_size / sizeof(_type)]; _type* _ptrData = _tmpArray; +#endif +#endif + + /****************************************************************************** + * TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT + * + * This macro is used to allocate memory for each event record, just before + * assigning the record fields. + * This has the same purpose as TRC_STREAM_PORT_ALLOCATE_EVENT and by default + * it has the same definition as TRC_STREAM_PORT_ALLOCATE_EVENT. This is used + * for events carrying variable-sized payload, such as strings. + * In the SEGGER RTT port, we need this in order to make a worst-case + * allocation on the stack. + ******************************************************************************/ +#ifndef TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT +#if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1) + #define TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(_type, _ptrData, _size) TRC_STREAM_PORT_ALLOCATE_EVENT(_type, _ptrData, _size) /* We do the same thing as for non-dynamic event sizes */ +#else + #define TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(_type, _ptrData, _size) _type _tmpArray[sizeof(largestEventType) / sizeof(_type)]; _type* _ptrData = _tmpArray; +#endif +#endif + + /****************************************************************************** + * TRC_STREAM_PORT_COMMIT_EVENT + * + * The COMMIT macro is used to write a single event record directly to the + * streaming inteface, without first storing the event in the internal buffer. + * This is currently only used in the SEGGER J-Link RTT port. + * + * This relies on the TRC_STREAM_PORT_WRITE_DATA macro, defined in by the + * stream port in trcStreamingPort.h. The COMMIT macro calls + * prvTraceWarning(TRC_STREAM_PORT_WRITE_DATA) if a non-zero value is returned + * from TRC_STREAM_PORT_WRITE_DATA. If zero (0) is returned, it is assumed + * that all data was successfully written. + * + * In ports using the internal buffer, this macro has no purpose as the events + * are written to the internal buffer instead. They are then flushed to the + * streaming interface in the TzCtrl task using TRC_STREAM_PORT_WRITE_DATA. + ******************************************************************************/ +#ifndef TRC_STREAM_PORT_COMMIT_EVENT +#if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1) + #define TRC_STREAM_PORT_COMMIT_EVENT(_ptrData, _size) /* Not used */ +#else + #define TRC_STREAM_PORT_COMMIT_EVENT(_ptrData, _size) \ + { \ + if (TRC_STREAM_PORT_WRITE_DATA(_ptrData, _size, 0) != 0)\ + prvTraceWarning(PSF_WARNING_STREAM_PORT_WRITE); \ + } +#endif +#endif + +/****************************************************************************** + * TRC_STREAM_PORT_READ_DATA (defined in trcStreamingPort.h) + * + * Defining how to read data from host (commands from Tracealyzer). + * + * If there is no direct interface to host (e.g., if streaming to a file + * system) this should be defined as 0. Instead use vTraceEnable(TRC_START) and + * vTraceStop() to control the recording from target. + * + * Parameters: + * + * - _ptrData: a pointer to a data buffer, where the received data shall be + * stored (TracealyzerCommandType*). + * + * - _size: the number of bytes to read (int). + * + * - _ptrBytesRead: a pointer to an integer (int), that should be assigned + * with the number of bytes that was received. + * + * Example: + * + * int32_t myRead(void* ptrData, uint32_t size, int32_t* ptrBytesRead); + * + * #define TRC_STREAM_PORT_READ_DATA(_ptrData, _size, _ptrBytesRead) \ + * myRead(_ptrData, _size, _ptrBytesRead) + * + * Your "myRead" function should return 0 if successful, i.e. if at least some + * bytes were received. A non-zero value should be returned if the streaming + * interface returned an error (e.g. a closed socket), which results in the + * recorder calling prvTraceWarning with the error code + * PSF_WARNING_STREAM_PORT_WRITE. + * + * If developing your own custom stream port and using the default internal + * buffer, it is important that the _ptrBytesRead parameter is assigned + * correctly by "myRead", i.e. with the number of bytes actually written. + * Otherwise the data stream may get out of sync in case the streaming interface + * can't swallow all data at once. + ******************************************************************************/ +#ifndef TRC_STREAM_PORT_READ_DATA +#error "No definition for TRC_STREAM_PORT_READ_DATA (should be in trcStreamingPort.h)" +#endif + +/****************************************************************************** + * TRC_STREAM_PORT_WRITE_DATA (defined in trcStreamingPort.h) + * + * Defining how to write trace data to the streaming interface. + * + * Parameters: + * + * - _ptrData: a pointer (void*) to the data to write. + * + * - _size: the number of bytes to write (uint32_t). + * + * - _ptrBytesWritten: a pointer to an integer (int32_t), that should be + * assigned with the number of bytes actually written. + * + * Example: + * + * int32_t myWrite(void* ptrData, uint32_t size, int32_t* ptrBytesWritten); + * + * #define TRC_STREAM_PORT_WRITE_DATA(_ptrData, _size, _ptrBytesWritten) \ + * myWrite(_ptrData, _size, _ptrBytesWritten) + * + * Your "myWrite" function should return 0 if successful, i.e. if at least some + * bytes were sent. A non-zero value should be returned if the streaming interface + * returned an error (e.g. a closed socket), which results in the recorder calling + * prvTraceWarning with the error code PSF_WARNING_STREAM_PORT_WRITE. + * + * If developing your own custom stream port and using the default internal + * buffer, it is important that the _ptrBytesWritten parameter is assigned + * correctly by "myWrite", i.e. with the number of bytes actually written. + * Otherwise the data stream may get out of sync in case the streaming interface + * can't swallow all data at once. + * + * Assuming TRC_STREAM_PORT_USE_INTERNAL_BUFFER is 1 (default), the TzCtrl task + * will use this macro to send one buffer page at a time. In case all data can't + * be written at once (if _ptrBytesWritten is less than _size), the TzCtrl task + * is smart enough to make repeated calls (with updated parameters) in order to + * send the remaining data. + * + * However, if TRC_STREAM_PORT_USE_INTERNAL_BUFFER is 0, this is used from the + * COMMIT macro, directly in the "event functions". In that case, the + * _ptrBytesWritten parameter will be NULL and should be ignored by the write + * function. In this case, it is assumed that all data can be sent in a single + * call, otherwise the write function should return a non-zero error code. + ******************************************************************************/ +#ifndef TRC_STREAM_PORT_WRITE_DATA +#error "No definition for TRC_STREAM_PORT_WRITE_DATA (should be in trcStreamingPort.h)" +#endif + +/****************************************************************************** +* Data structure declaration, depending on TRC_CFG_RECORDER_BUFFER_ALLOCATION +*******************************************************************************/ +#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_STATIC) + + /* Static allocation. */ + + /* If not defined in trcStreamingPort.h */ + #ifndef TRC_STREAM_PORT_ALLOCATE_FIELDS + #define TRC_STREAM_PORT_ALLOCATE_FIELDS() \ + char _TzTraceData[(TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT) * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)]; + extern char _TzTraceData[(TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT) * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)]; + #endif + + /* If not defined in trcStreamingPort.h */ + #ifndef TRC_STREAM_PORT_MALLOC + #define TRC_STREAM_PORT_MALLOC() /* Static allocation. Not used. */ + #endif +#else + /* For Dynamic or Custom Allocation mode */ + + /* If not defined in trcStreamingPort.h */ + #ifndef TRC_STREAM_PORT_ALLOCATE_FIELDS + #define TRC_STREAM_PORT_ALLOCATE_FIELDS() char* _TzTraceData = NULL; + extern char* _TzTraceData; + #endif + + /* If not defined in trcStreamingPort.h */ + #ifndef TRC_STREAM_PORT_MALLOC + #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC) + #define TRC_STREAM_PORT_MALLOC() \ + _TzTraceData = TRC_PORT_MALLOC((TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT) * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)); + extern char* _TzTraceData; + #else + #define TRC_STREAM_PORT_MALLOC() /* Custom allocation. Not used. */ + #endif + #endif +#endif + +#ifndef TRC_STREAM_PORT_INIT + #define TRC_STREAM_PORT_INIT() \ + TRC_STREAM_PORT_MALLOC(); /* Empty if static allocation mode */ \ + prvPagedEventBufferInit(_TzTraceData); +#endif + + +/* Signal an error. */ +void prvTraceError(int errCode); + +/* Signal an warning (does not stop the recorder). */ +void prvTraceWarning(int errCode); + +/******************************************************************************/ +/*** ERROR AND WARNING CODES (check using xTraceGetLastError) *****************/ +/******************************************************************************/ + +#define PSF_ERROR_NONE 0 +#define PSF_ERROR_EVENT_CODE_TOO_LARGE 1 +#define PSF_ERROR_ISR_NESTING_OVERFLOW 2 +#define PSF_ERROR_DWT_NOT_SUPPORTED 3 +#define PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED 4 +#define PSF_ERROR_TZCTRLTASK_NOT_CREATED 5 + +#define PSF_WARNING_SYMBOL_TABLE_SLOTS 101 +#define PSF_WARNING_SYMBOL_MAX_LENGTH 102 +#define PSF_WARNING_OBJECT_DATA_SLOTS 103 +#define PSF_WARNING_STRING_TOO_LONG 104 +#define PSF_WARNING_STREAM_PORT_READ 105 +#define PSF_WARNING_STREAM_PORT_WRITE 106 + +/******************************************************************************/ +/*** INTERNAL STREAMING FUNCTIONS *********************************************/ +/******************************************************************************/ + +/* Saves a symbol name (task name etc.) in symbol table */ +void prvTraceSaveSymbol(const void *address, const char *name); + +/* Deletes a symbol name (task name etc.) from symbol table */ +void prvTraceDeleteSymbol(void *address); + +/* Saves an object data entry (task base priority) in object data table */ +void prvTraceSaveObjectData(const void *address, uint32_t data); + +/* Removes an object data entry (task base priority) from object data table */ +void prvTraceDeleteObjectData(void *address); + +/* Store an event with zero parameters (event ID only) */ +void prvTraceStoreEvent0(uint16_t eventID); + +/* Store an event with one 32-bit parameter (pointer address or an int) */ +void prvTraceStoreEvent1(uint16_t eventID, + uint32_t param1); + +/* Store an event with two 32-bit parameters */ +void prvTraceStoreEvent2(uint16_t eventID, + uint32_t param1, + uint32_t param2); + +/* Store an event with three 32-bit parameters */ +void prvTraceStoreEvent3(uint16_t eventID, + uint32_t param1, + uint32_t param2, + uint32_t param3); + +/* Stores an event with 32-bit integer parameters */ +void prvTraceStoreEvent(int nParam, uint16_t EventID, ...); + +/* Stories an event with a string and 32-bit integer parameters */ +void prvTraceStoreStringEvent(int nArgs, uint16_t eventID, const char* str, ...); + +/* Initializes the paged event buffer used by certain stream ports */ +void prvPagedEventBufferInit(char* buffer); + +/* Retrieve a pointer to the paged event buffer */ +void* prvPagedEventBufferGetWritePointer(int sizeOfEvent); + +/* Transfer a full buffer page */ +uint32_t prvPagedEventBufferTransfer(void); + +/* The data structure for commands (a bit overkill) */ +typedef struct +{ + unsigned char cmdCode; + unsigned char param1; + unsigned char param2; + unsigned char param3; + unsigned char param4; + unsigned char param5; + unsigned char checksumLSB; + unsigned char checksumMSB; +} TracealyzerCommandType; + +/* Checks if the provided command is a valid command */ +int prvIsValidCommand(TracealyzerCommandType* cmd); + +/* Executed the received command (Start or Stop) */ +void prvProcessCommand(TracealyzerCommandType* cmd); + +#define vTraceSetStopHook(x) + +#endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/ + +#else /* when TRC_USE_TRACEALYZER_RECORDER == 0 */ + +#define vTraceEnable(x) +#define xTraceRegisterString(x) 0; (void)x; +#define vTracePrint(chn, ...) (void)chn +#define vTracePrintF(chn, ...) (void)chn +#define vTraceInstanceFinishedNow() +#define vTraceInstanceFinishedNext() +#define vTraceStoreISRBegin(x) (void)x +#define vTraceStoreISREnd(x) (void)x +#define xTraceSetISRProperties(a, b) 0 +#define vTraceStoreKernelObjectName(a, b) +#define xTraceRegisterChannelFormat(eventLabel, formatStr) 0 +#define vTraceChannelPrint(label) +#define vTraceUBData(label, ...) + +#define vTraceSetFilterGroup(x) +#define vTraceSetFilterMask(x) + +#define prvTraceSetReadyEventsEnabled(status) + +#define vTraceExcludeTask(handle) + +#define uiTraceStart() (1) +#define vTraceStart() +#define vTraceStop() + +#ifndef vTraceSetRecorderDataBuffer +#define vTraceSetRecorderDataBuffer(pRecorderData) +#endif + +#define vTraceConsoleChannelPrintF(fmt, ...) + +#ifndef TRC_ALLOC_CUSTOM_BUFFER +#define TRC_ALLOC_CUSTOM_BUFFER(bufname) +#endif + +#define xTraceIsRecordingEnabled() (0) + +#define vTraceSetStopHook(x) + +#endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/ + +#ifdef __cplusplus +} +#endif + +#endif /* TRC_RECORDER_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/ReadMe.url b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/ReadMe.url new file mode 100644 index 000000000..251da66aa --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/ReadMe.url @@ -0,0 +1,5 @@ +[InternetShortcut] +URL=http://www.freertos.org/trace +IDList= +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,2 diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/config/trcConfig.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/config/trcConfig.h new file mode 100644 index 000000000..dceb6d85b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/config/trcConfig.h @@ -0,0 +1,301 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.4 + * Percepio AB, www.percepio.com + * + * trcConfig.h + * + * Main configuration parameters for the trace recorder library. + * More settings can be found in trcStreamingConfig.h and trcSnapshotConfig.h. + * + * Read more at http://percepio.com/2016/10/05/rtos-tracing/ + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_CONFIG_H +#define TRC_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "trcPortDefines.h" + +/****************************************************************************** + * Include of processor header file + * + * Here you may need to include the header file for your processor. This is + * required at least for the ARM Cortex-M port, that uses the ARM CMSIS API. + * Try that in case of build problems. Otherwise, remove the #error line below. + *****************************************************************************/ +#error "Trace Recorder: Please include your processor's header file here and remove this line." + +/******************************************************************************* + * Configuration Macro: TRC_CFG_HARDWARE_PORT + * + * Specify what hardware port to use (i.e., the "timestamping driver"). + * + * All ARM Cortex-M MCUs are supported by "TRC_HARDWARE_PORT_ARM_Cortex_M". + * This port uses the DWT cycle counter for Cortex-M3/M4/M7 devices, which is + * available on most such devices. In case your device don't have DWT support, + * you will get an error message opening the trace. In that case, you may + * force the recorder to use SysTick timestamping instead, using this define: + * + * #define TRC_CFG_ARM_CM_USE_SYSTICK + * + * For ARM Cortex-M0/M0+ devices, SysTick mode is used automatically. + * + * See trcHardwarePort.h for available ports and information on how to + * define your own port, if not already present. + ******************************************************************************/ +#define TRC_CFG_HARDWARE_PORT TRC_HARDWARE_PORT_NOT_SET + +/******************************************************************************* + * Configuration Macro: TRC_CFG_RECORDER_MODE + * + * Specify what recording mode to use. Snapshot means that the data is saved in + * an internal RAM buffer, for later upload. Streaming means that the data is + * transferred continuously to the host PC. + * + * For more information, see http://percepio.com/2016/10/05/rtos-tracing/ + * and the Tracealyzer User Manual. + * + * Values: + * TRC_RECORDER_MODE_SNAPSHOT + * TRC_RECORDER_MODE_STREAMING + ******************************************************************************/ +#define TRC_CFG_RECORDER_MODE TRC_RECORDER_MODE_SNAPSHOT + +/****************************************************************************** + * TRC_CFG_FREERTOS_VERSION + * + * Specify what version of FreeRTOS that is used (don't change unless using the + * trace recorder library with an older version of FreeRTOS). + * + * TRC_FREERTOS_VERSION_7_3 If using FreeRTOS v7.3.x + * TRC_FREERTOS_VERSION_7_4 If using FreeRTOS v7.4.x + * TRC_FREERTOS_VERSION_7_5_OR_7_6 If using FreeRTOS v7.5.0 - v7.6.0 + * TRC_FREERTOS_VERSION_8_X If using FreeRTOS v8.X.X + * TRC_FREERTOS_VERSION_9_0_0 If using FreeRTOS v9.0.0 + * TRC_FREERTOS_VERSION_9_0_1 If using FreeRTOS v9.0.1 + * TRC_FREERTOS_VERSION_9_0_2 If using FreeRTOS v9.0.2 + * TRC_FREERTOS_VERSION_10_0_0 If using FreeRTOS v10.0.0 or later + *****************************************************************************/ +#define TRC_CFG_FREERTOS_VERSION TRC_FREERTOS_VERSION_10_0_0 + +/******************************************************************************* + * TRC_CFG_SCHEDULING_ONLY + * + * Macro which should be defined as an integer value. + * + * If this setting is enabled (= 1), only scheduling events are recorded. + * If disabled (= 0), all events are recorded (unless filtered in other ways). + * + * Default value is 0 (= include additional events). + ******************************************************************************/ +#define TRC_CFG_SCHEDULING_ONLY 0 + + /****************************************************************************** + * TRC_CFG_INCLUDE_MEMMANG_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * This controls if malloc and free calls should be traced. Set this to zero (0) + * to exclude malloc/free calls, or one (1) to include such events in the trace. + * + * Default value is 1. + *****************************************************************************/ +#define TRC_CFG_INCLUDE_MEMMANG_EVENTS 1 + + /****************************************************************************** + * TRC_CFG_INCLUDE_USER_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), all code related to User Events is excluded in order + * to reduce code size. Any attempts of storing User Events are then silently + * ignored. + * + * User Events are application-generated events, like "printf" but for the + * trace log, generated using vTracePrint and vTracePrintF. + * The formatting is done on host-side, by Tracealyzer. User Events are + * therefore much faster than a console printf and can often be used + * in timing critical code without problems. + * + * Note: In streaming mode, User Events are used to provide error messages + * and warnings from the recorder (in case of incorrect configuration) for + * display in Tracealyzer. Disabling user events will also disable these + * warnings. You can however still catch them by calling xTraceGetLastError + * or by putting breakpoints in prvTraceError and prvTraceWarning. + * + * Default value is 1. + *****************************************************************************/ +#define TRC_CFG_INCLUDE_USER_EVENTS 1 + + /***************************************************************************** + * TRC_CFG_INCLUDE_ISR_TRACING + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the code for recording Interrupt Service Routines is + * excluded, in order to reduce code size. + * + * Default value is 1. + * + * Note: tracing ISRs requires that you insert calls to vTraceStoreISRBegin + * and vTraceStoreISREnd in your interrupt handlers. + *****************************************************************************/ +#define TRC_CFG_INCLUDE_ISR_TRACING 1 + + /***************************************************************************** + * TRC_CFG_INCLUDE_READY_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * If one (1), events are recorded when tasks enter scheduling state "ready". + * This allows Tracealyzer to show the initial pending time before tasks enter + * the execution state, and present accurate response times. + * If zero (0), "ready events" are not created, which allows for recording + * longer traces in the same amount of RAM. + * + * Default value is 1. + *****************************************************************************/ +#define TRC_CFG_INCLUDE_READY_EVENTS 1 + + /***************************************************************************** + * TRC_CFG_INCLUDE_OSTICK_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is one (1), events will be generated whenever the OS clock is + * increased. If zero (0), OS tick events are not generated, which allows for + * recording longer traces in the same amount of RAM. + * + * Default value is 1. + *****************************************************************************/ +#define TRC_CFG_INCLUDE_OSTICK_EVENTS 1 + + /***************************************************************************** + * TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the trace will exclude any "event group" events. + * + * Default value is 0 (excluded) since dependent on event_groups.c + *****************************************************************************/ +#define TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS 0 + + /***************************************************************************** + * TRC_CFG_INCLUDE_TIMER_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the trace will exclude any Timer events. + * + * Default value is 0 since dependent on timers.c + *****************************************************************************/ +#define TRC_CFG_INCLUDE_TIMER_EVENTS 0 + + /***************************************************************************** + * TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the trace will exclude any "pending function call" + * events, such as xTimerPendFunctionCall(). + * + * Default value is 0 since dependent on timers.c + *****************************************************************************/ +#define TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS 0 + +/******************************************************************************* + * Configuration Macro: TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the trace will exclude any stream buffer or message + * buffer events. + * + * Default value is 0 since dependent on stream_buffer.c (new in FreeRTOS v10) + ******************************************************************************/ +#define TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS 0 + +/******************************************************************************* + * Configuration Macro: TRC_CFG_RECORDER_BUFFER_ALLOCATION + * + * Specifies how the recorder buffer is allocated (also in case of streaming, in + * port using the recorder's internal temporary buffer) + * + * Values: + * TRC_RECORDER_BUFFER_ALLOCATION_STATIC - Static allocation (internal) + * TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC - Malloc in vTraceEnable + * TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM - Use vTraceSetRecorderDataBuffer + * + * Static and dynamic mode does the allocation for you, either in compile time + * (static) or in runtime (malloc). + * The custom mode allows you to control how and where the allocation is made, + * for details see TRC_ALLOC_CUSTOM_BUFFER and vTraceSetRecorderDataBuffer(). + ******************************************************************************/ +#define TRC_CFG_RECORDER_BUFFER_ALLOCATION TRC_RECORDER_BUFFER_ALLOCATION_STATIC + +/****************************************************************************** + * TRC_CFG_MAX_ISR_NESTING + * + * Defines how many levels of interrupt nesting the recorder can handle, in + * case multiple ISRs are traced and ISR nesting is possible. If this + * is exceeded, the particular ISR will not be traced and the recorder then + * logs an error message. This setting is used to allocate an internal stack + * for keeping track of the previous execution context (4 byte per entry). + * + * This value must be a non-zero positive constant, at least 1. + * + * Default value: 8 + *****************************************************************************/ +#define TRC_CFG_MAX_ISR_NESTING 8 + +/* Specific configuration, depending on Streaming/Snapshot mode */ +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) +#include "trcSnapshotConfig.h" +#elif (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) +#include "trcStreamingConfig.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _TRC_CONFIG_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/config/trcSnapshotConfig.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/config/trcSnapshotConfig.h new file mode 100644 index 000000000..5ce12fcaa --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/config/trcSnapshotConfig.h @@ -0,0 +1,377 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.4 + * Percepio AB, www.percepio.com + * + * trcSnapshotConfig.h + * + * Configuration parameters for trace recorder library in snapshot mode. + * Read more at http://percepio.com/2016/10/05/rtos-tracing/ + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_SNAPSHOT_CONFIG_H +#define TRC_SNAPSHOT_CONFIG_H + +#define TRC_SNAPSHOT_MODE_RING_BUFFER (0x01) +#define TRC_SNAPSHOT_MODE_STOP_WHEN_FULL (0x02) + +/****************************************************************************** + * TRC_CFG_SNAPSHOT_MODE + * + * Macro which should be defined as one of: + * - TRC_SNAPSHOT_MODE_RING_BUFFER + * - TRC_SNAPSHOT_MODE_STOP_WHEN_FULL + * Default is TRC_SNAPSHOT_MODE_RING_BUFFER. + * + * With TRC_CFG_SNAPSHOT_MODE set to TRC_SNAPSHOT_MODE_RING_BUFFER, the + * events are stored in a ring buffer, i.e., where the oldest events are + * overwritten when the buffer becomes full. This allows you to get the last + * events leading up to an interesting state, e.g., an error, without having + * to store the whole run since startup. + * + * When TRC_CFG_SNAPSHOT_MODE is TRC_SNAPSHOT_MODE_STOP_WHEN_FULL, the + * recording is stopped when the buffer becomes full. This is useful for + * recording events following a specific state, e.g., the startup sequence. + *****************************************************************************/ +#define TRC_CFG_SNAPSHOT_MODE TRC_SNAPSHOT_MODE_RING_BUFFER + +/******************************************************************************* + * TRC_CFG_EVENT_BUFFER_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the event buffer, i.e., the number of records + * it may store. Most events use one record (4 byte), although some events + * require multiple 4-byte records. You should adjust this to the amount of RAM + * available in the target system. + * + * Default value is 1000, which means that 4000 bytes is allocated for the + * event buffer. + ******************************************************************************/ +#define TRC_CFG_EVENT_BUFFER_SIZE 1000 + +/******************************************************************************* + * TRC_CFG_NTASK, TRC_CFG_NISR, TRC_CFG_NQUEUE, TRC_CFG_NSEMAPHORE... + * + * A group of macros which should be defined as integer values, zero or larger. + * + * These define the capacity of the Object Property Table, i.e., the maximum + * number of objects active at any given point, within each object class (e.g., + * task, queue, semaphore, ...). + * + * If tasks or other objects are deleted in your system, this + * setting does not limit the total amount of objects created, only the number + * of objects that have been successfully created but not yet deleted. + * + * Using too small values will cause vTraceError to be called, which stores an + * error message in the trace that is shown when opening the trace file. The + * error message can also be retrieved using xTraceGetLastError. + * + * It can be wise to start with large values for these constants, + * unless you are very confident on these numbers. Then do a recording and + * check the actual usage by selecting View menu -> Trace Details -> + * Resource Usage -> Object Table. + ******************************************************************************/ +#define TRC_CFG_NTASK 15 +#define TRC_CFG_NISR 5 +#define TRC_CFG_NQUEUE 10 +#define TRC_CFG_NSEMAPHORE 10 +#define TRC_CFG_NMUTEX 10 +#define TRC_CFG_NTIMER 5 +#define TRC_CFG_NEVENTGROUP 5 +#define TRC_CFG_NSTREAMBUFFER 5 +#define TRC_CFG_NMESSAGEBUFFER 5 + +/****************************************************************************** + * TRC_CFG_INCLUDE_FLOAT_SUPPORT + * + * Macro which should be defined as either zero (0) or one (1). + * + * If this is zero (0), the support for logging floating point values in + * vTracePrintF is stripped out, in case floating point values are not used or + * supported by the platform used. + * + * Floating point values are only used in vTracePrintF and its subroutines, to + * allow for storing float (%f) or double (%lf) arguments. + * + * vTracePrintF can be used with integer and string arguments in either case. + * + * Default value is 0. + *****************************************************************************/ +#define TRC_CFG_INCLUDE_FLOAT_SUPPORT 0 + +/******************************************************************************* + * TRC_CFG_SYMBOL_TABLE_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the symbol table, in bytes. This symbol table + * stores User Events labels and names of deleted tasks, queues, or other kernel + * objects. If you don't use User Events or delete any kernel + * objects you set this to a very low value. The minimum recommended value is 4. + * A size of zero (0) is not allowed since a zero-sized array may result in a + * 32-bit pointer, i.e., using 4 bytes rather than 0. + * + * Default value is 800. + ******************************************************************************/ +#define TRC_CFG_SYMBOL_TABLE_SIZE 800 + +#if (TRC_CFG_SYMBOL_TABLE_SIZE == 0) +#error "TRC_CFG_SYMBOL_TABLE_SIZE may not be zero!" +#endif + +/****************************************************************************** + * TRC_CFG_NAME_LEN_TASK, TRC_CFG_NAME_LEN_QUEUE, ... + * + * Macros that specify the maximum lengths (number of characters) for names of + * kernel objects, such as tasks and queues. If longer names are used, they will + * be truncated when stored in the recorder. + *****************************************************************************/ +#define TRC_CFG_NAME_LEN_TASK 15 +#define TRC_CFG_NAME_LEN_ISR 15 +#define TRC_CFG_NAME_LEN_QUEUE 15 +#define TRC_CFG_NAME_LEN_SEMAPHORE 15 +#define TRC_CFG_NAME_LEN_MUTEX 15 +#define TRC_CFG_NAME_LEN_TIMER 15 +#define TRC_CFG_NAME_LEN_EVENTGROUP 15 +#define TRC_CFG_NAME_LEN_STREAMBUFFER 15 +#define TRC_CFG_NAME_LEN_MESSAGEBUFFER 15 + +/****************************************************************************** + *** ADVANCED SETTINGS ******************************************************** + ****************************************************************************** + * The remaining settings are not necessary to modify but allows for optimizing + * the recorder setup for your specific needs, e.g., to exclude events that you + * are not interested in, in order to get longer traces. + *****************************************************************************/ + +/****************************************************************************** +* TRC_CFG_HEAP_SIZE_BELOW_16M +* +* An integer constant that can be used to reduce the buffer usage of memory +* allocation events (malloc/free). This value should be 1 if the heap size is +* below 16 MB (2^24 byte), and you can live with reported addresses showing the +* lower 24 bits only. If 0, you get the full 32-bit addresses. +* +* Default value is 0. +******************************************************************************/ +#define TRC_CFG_HEAP_SIZE_BELOW_16M 0 + +/****************************************************************************** + * TRC_CFG_USE_IMPLICIT_IFE_RULES + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * Tracealyzer groups the events into "instances" based on Instance Finish + * Events (IFEs), produced either by default rules or calls to the recorder + * functions vTraceInstanceFinishedNow and vTraceInstanceFinishedNext. + * + * If TRC_CFG_USE_IMPLICIT_IFE_RULES is one (1), the default IFE rules is + * used, resulting in a "typical" grouping of events into instances. + * If these rules don't give appropriate instances in your case, you can + * override the default rules using vTraceInstanceFinishedNow/Next for one + * or several tasks. The default IFE rules are then disabled for those tasks. + * + * If TRC_CFG_USE_IMPLICIT_IFE_RULES is zero (0), the implicit IFE rules are + * disabled globally. You must then call vTraceInstanceFinishedNow or + * vTraceInstanceFinishedNext to manually group the events into instances, + * otherwise the tasks will appear a single long instance. + * + * The default IFE rules count the following events as "instance finished": + * - Task delay, delay until + * - Task suspend + * - Blocking on "input" operations, i.e., when the task is waiting for the + * next a message/signal/event. But only if this event is blocking. + * + * For details, see trcSnapshotKernelPort.h and look for references to the + * macro trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED. + *****************************************************************************/ +#define TRC_CFG_USE_IMPLICIT_IFE_RULES 1 + +/****************************************************************************** + * TRC_CFG_USE_16BIT_OBJECT_HANDLES + * + * Macro which should be defined as either zero (0) or one (1). + * + * If set to 0 (zero), the recorder uses 8-bit handles to identify kernel + * objects such as tasks and queues. This limits the supported number of + * concurrently active objects to 255 of each type (tasks, queues, mutexes, + * etc.) Note: 255, not 256, since handle 0 is reserved. + * + * If set to 1 (one), the recorder uses 16-bit handles to identify kernel + * objects such as tasks and queues. This limits the supported number of + * concurrent objects to 65535 of each type (object class). However, since the + * object property table is limited to 64 KB, the practical limit is about + * 3000 objects in total. + * + * Default is 0 (8-bit handles) + * + * NOTE: An object with handle above 255 will use an extra 4-byte record in + * the event buffer whenever the object is referenced. Moreover, some internal + * tables in the recorder gets slightly larger when using 16-bit handles. + *****************************************************************************/ +#define TRC_CFG_USE_16BIT_OBJECT_HANDLES 0 + +/****************************************************************************** + * TRC_CFG_USE_TRACE_ASSERT + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 1. + * + * If this is one (1), the TRACE_ASSERT macro (used at various locations in the + * trace recorder) will verify that a relevant condition is true. + * If the condition is false, prvTraceError() will be called, which stops the + * recording and stores an error message that is displayed when opening the + * trace in Tracealyzer. + * + * This is used on several places in the recorder code for sanity checks on + * parameters. Can be switched off to reduce the footprint of the tracing, but + * we recommend to have it enabled initially. + *****************************************************************************/ +#define TRC_CFG_USE_TRACE_ASSERT 1 + +/******************************************************************************* + * TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER + * + * Macro which should be defined as an integer value. + * + * Set TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER to 1 to enable the + * separate user event buffer (UB). + * In this mode, user events are stored separately from other events, + * e.g., RTOS events. Thereby you can get a much longer history of + * user events as they don't need to share the buffer space with more + * frequent events. + * + * The UB is typically used with the snapshot ring-buffer mode, so the + * recording can continue when the main buffer gets full. And since the + * main buffer then overwrites the earliest events, Tracealyzer displays + * "Unknown Actor" instead of task scheduling for periods with UB data only. + * + * In UB mode, user events are structured as UB channels, which contains + * a channel name and a default format string. Register a UB channel using + * xTraceRegisterUBChannel. + * + * Events and data arguments are written using vTraceUBEvent and + * vTraceUBData. They are designed to provide efficient logging of + * repeating events, using the same format string within each channel. + * + * Examples: + * + * traceString chn1 = xTraceRegisterString("Channel 1"); + * traceString fmt1 = xTraceRegisterString("Event!"); + * traceUBChannel UBCh1 = xTraceRegisterUBChannel(chn1, fmt1); + * + * traceString chn2 = xTraceRegisterString("Channel 2"); + * traceString fmt2 = xTraceRegisterString("X: %d, Y: %d"); + * traceUBChannel UBCh2 = xTraceRegisterUBChannel(chn2, fmt2); + * + * // Result in "[Channel 1] Event!" + * vTraceUBEvent(UBCh1); + * + * // Result in "[Channel 2] X: 23, Y: 19" + * vTraceUBData(UBCh2, 23, 19); + * + * You can also use the other user event functions, like vTracePrintF. + * as they are then rerouted to the UB instead of the main event buffer. + * vTracePrintF then looks up the correct UB channel based on the + * provided channel name and format string, or creates a new UB channel + * if no match is found. The format string should therefore not contain + * "random" messages but mainly format specifiers. Random strings should + * be stored using %s and with the string as an argument. + * + * // Creates a new UB channel ("Channel 2", "%Z: %d") + * vTracePrintF(chn2, "%Z: %d", value1); + * + * // Finds the existing UB channel + * vTracePrintF(chn2, "%Z: %d", value2); + + ******************************************************************************/ +#define TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER 0 + +/******************************************************************************* + * TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the user event buffer (UB), in number of slots. + * A single user event can use multiple slots, depending on the arguments. + * + * Only applicable if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER is 1. + ******************************************************************************/ +#define TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE 200 + +/******************************************************************************* + * TRC_CFG_UB_CHANNELS + * + * Macro which should be defined as an integer value. + * + * This defines the number of User Event Buffer Channels (UB channels). + * These are used to structure the events when using the separate user + * event buffer, and contains both a User Event Channel (the name) and + * a default format string for the channel. + * + * Only applicable if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER is 1. + ******************************************************************************/ +#define TRC_CFG_UB_CHANNELS 32 + +/******************************************************************************* + * TRC_CFG_ISR_TAILCHAINING_THRESHOLD + * + * Macro which should be defined as an integer value. + * + * If tracing multiple ISRs, this setting allows for accurate display of the + * context-switching also in cases when the ISRs execute in direct sequence. + * + * vTraceStoreISREnd normally assumes that the ISR returns to the previous + * context, i.e., a task or a preempted ISR. But if another traced ISR + * executes in direct sequence, Tracealyzer may incorrectly display a minimal + * fragment of the previous context in between the ISRs. + * + * By using TRC_CFG_ISR_TAILCHAINING_THRESHOLD you can avoid this. This is + * however a threshold value that must be measured for your specific setup. + * See http://percepio.com/2014/03/21/isr_tailchaining_threshold/ + * + * The default setting is 0, meaning "disabled" and that you may get an + * extra fragments of the previous context in between tail-chained ISRs. + * + * Note: This setting has separate definitions in trcSnapshotConfig.h and + * trcStreamingConfig.h, since it is affected by the recorder mode. + ******************************************************************************/ +#define TRC_CFG_ISR_TAILCHAINING_THRESHOLD 0 + +#endif /*TRC_SNAPSHOT_CONFIG_H*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/config/trcStreamingConfig.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/config/trcStreamingConfig.h new file mode 100644 index 000000000..f578f10ec --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/config/trcStreamingConfig.h @@ -0,0 +1,170 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.4 + * Percepio AB, www.percepio.com + * + * trcStreamingConfig.h + * + * Configuration parameters for the trace recorder library in streaming mode. + * Read more at http://percepio.com/2016/10/05/rtos-tracing/ + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_STREAMING_CONFIG_H +#define TRC_STREAMING_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + * Configuration Macro: TRC_CFG_SYMBOL_TABLE_SLOTS + * + * The maximum number of symbols names that can be stored. This includes: + * - Task names + * - Named ISRs (vTraceSetISRProperties) + * - Named kernel objects (vTraceStoreKernelObjectName) + * - User event channels (xTraceRegisterString) + * + * If this value is too small, not all symbol names will be stored and the + * trace display will be affected. In that case, there will be warnings + * (as User Events) from TzCtrl task, that monitors this. + ******************************************************************************/ +#define TRC_CFG_SYMBOL_TABLE_SLOTS 40 + +/******************************************************************************* + * Configuration Macro: TRC_CFG_SYMBOL_MAX_LENGTH + * + * The maximum length of symbol names, including: + * - Task names + * - Named ISRs (vTraceSetISRProperties) + * - Named kernel objects (vTraceStoreKernelObjectName) + * - User event channel names (xTraceRegisterString) + * + * If longer symbol names are used, they will be truncated by the recorder, + * which will affect the trace display. In that case, there will be warnings + * (as User Events) from TzCtrl task, that monitors this. + ******************************************************************************/ +#define TRC_CFG_SYMBOL_MAX_LENGTH 25 + +/******************************************************************************* + * Configuration Macro: TRC_CFG_OBJECT_DATA_SLOTS + * + * The maximum number of object data entries (used for task priorities) that can + * be stored at the same time. Must be sufficient for all tasks, otherwise there + * will be warnings (as User Events) from TzCtrl task, that monitors this. + ******************************************************************************/ +#define TRC_CFG_OBJECT_DATA_SLOTS 40 + +/******************************************************************************* + * Configuration Macro: TRC_CFG_CTRL_TASK_STACK_SIZE + * + * The stack size of the TzCtrl task, that receive commands. + * We are aiming to remove this extra task in future versions. + ******************************************************************************/ +#define TRC_CFG_CTRL_TASK_STACK_SIZE (configMINIMAL_STACK_SIZE * 2) + +/******************************************************************************* + * Configuration Macro: TRC_CFG_CTRL_TASK_PRIORITY + * + * The priority of the TzCtrl task, that receive commands from Tracealyzer. + * Most stream ports also rely on the TzCtrl task to transmit the data from the + * internal buffer to the stream interface (all except for the J-Link port). + * For such ports, make sure the TzCtrl priority is high enough to ensure + * reliable periodic execution and transfer of the data. + ******************************************************************************/ +#define TRC_CFG_CTRL_TASK_PRIORITY 1 + +/******************************************************************************* + * Configuration Macro: TRC_CFG_CTRL_TASK_DELAY + * + * The delay between every loop of the TzCtrl task. A high delay will reduce the + * CPU load, but may cause missed events if the TzCtrl task is performing the + * trace transfer. + ******************************************************************************/ +#define TRC_CFG_CTRL_TASK_DELAY ((10 * configTICK_RATE_HZ) / 1000) + +/******************************************************************************* + * Configuration Macro: TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT + * + * Specifies the number of pages used by the paged event buffer. + * This may need to be increased if there are a lot of missed events. + * + * Note: not used by the J-Link RTT stream port (see trcStreamingPort.h instead) + ******************************************************************************/ +#define TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT 2 + +/******************************************************************************* + * Configuration Macro: TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE + * + * Specifies the size of each page in the paged event buffer. This can be tuned + * to match any internal low-level buffers used by the streaming interface, like + * the Ethernet MTU (Maximum Transmission Unit). + * + * Note: not used by the J-Link RTT stream port (see trcStreamingPort.h instead) + ******************************************************************************/ +#define TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE 2500 + +/******************************************************************************* + * TRC_CFG_ISR_TAILCHAINING_THRESHOLD + * + * Macro which should be defined as an integer value. + * + * If tracing multiple ISRs, this setting allows for accurate display of the + * context-switching also in cases when the ISRs execute in direct sequence. + * + * vTraceStoreISREnd normally assumes that the ISR returns to the previous + * context, i.e., a task or a preempted ISR. But if another traced ISR + * executes in direct sequence, Tracealyzer may incorrectly display a minimal + * fragment of the previous context in between the ISRs. + * + * By using TRC_CFG_ISR_TAILCHAINING_THRESHOLD you can avoid this. This is + * however a threshold value that must be measured for your specific setup. + * See http://percepio.com/2014/03/21/isr_tailchaining_threshold/ + * + * The default setting is 0, meaning "disabled" and that you may get an + * extra fragments of the previous context in between tail-chained ISRs. + * + * Note: This setting has separate definitions in trcSnapshotConfig.h and + * trcStreamingConfig.h, since it is affected by the recorder mode. + ******************************************************************************/ +#define TRC_CFG_ISR_TAILCHAINING_THRESHOLD 0 + +#ifdef __cplusplus +} +#endif + +#endif /* TRC_STREAMING_CONFIG_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/readme.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/readme.txt new file mode 100644 index 000000000..79b64006d --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/readme.txt @@ -0,0 +1,152 @@ +------------------------------------------------------------------------------- + Tracealyzer for FreeRTOS - Trace Recorder Library v3.1.1 +------------------------------------------------------------------------------- + +Tracealyzer for FreeRTOS is a sophisticated tool for tracing and visualization +of FreeRTOS-based systems. Tracealyzer gives an unprecedented insight into the +runtime behavior, which speeds up debugging, validation and optimization. + +To learn more about this, see + + - Getting Started (videos etc): http://percepio.com/gettingstarted/tz-freertos/ + + - User Manual (incl. Recorder API): http://percepio.com/docs/FreeRTOS/manual + + - FAQ: http://percepio.com/category/faq/ + +In case you have any questions, don't hesitate to contact support@percepio.com + +------------------------------------------------------------------------------- + +Changes, v3.1.1 -> v3.1.2 + +- Fixed two bugs related to User Events, one in vTracePrintF and other in vTracePrint. + +- Fixed a build problem related to a single reference of the old FreeRTOS type "xTaskHandle", in trcKernelPort.c. + Changed to "TaskHandle_t", unless if using an older FreeRTOS kernel or the "compatibility mode". + +- Removed traceCREATE_MUTEX hook for FreeRTOS v9 or later (no longer required) + +- Updated the User Manual regarding snapshot trace via IAR Embedded Workbench. + +- Renamed vTraceGetTraceBuffer to xTraceGetTraceBuffer, since returning a pointer. + +------------------------------------------------------------------------------- + +Changes, v3.1.0 -> v3.1.1 + +After the major changes in the v3.1.0 trace recorder library, this update +corrects a number of minor issues. Only minor functional improvements. + +- You can now use TRC_ALLOC_CUSTOM_BUFFER to declare a trace buffer on a custom + location (using linker directives). + The related function vTraceSetRecorderDataBuffer has been promoted to the + Common API (previously only supported in snapshot mode, but custom allocation + is now generally supported also in streaming mode). + +- Removed TRC_CFG_USE_LINKER_PRAGMA. No longer necessary thanks to the custom + allocation mode. + +- Added support for timestamping from custom periodic timers, required for + accurate timestamping on Cortex-M0/M0+ devices when using tickless idle. + Only for streaming mode so far. See TRC_CUSTOM_TIMER_INCR / DECR. + +- ARM Cortex-M port: Made sure the DWT unit is initialized properly, in case + the debugger doesn't handle this. + +- ARM Cortex-M port: Added possibility to use Systick timestamping also on + Cortex-M3/M4/M7 devices (that otherwise use DWT timestamping by default). + To use this option, define the macro TRC_CFG_ARM_CM_USE_SYSTICK. + +- J-Link streaming: The default RTT buffer has been changed from 0 to 1. + +- J-Link streaming: The RTT buffer settings for buffer 1 and higher, are now + found in trcStreamingPort.h. Note: These settings don't apply to buffer 0. + +- vTracePrint has been optimized for better performance in string logging. + +- Minor performance improvement related to symbol table transfer in streaming mode. + +- Timer names now registered also in streaming mode. + +- Timer start and stop event are now traced. + +- Implemented support for queue registry (traceQUEUE_REGISTRY_ADD) also for streaming. + +- Fixed a bug related to repeated calls of vTraceEnable. + +- Fixed a bug where task-switches seemed to occur even though the scheduler was disabled. + +- Renamed HARDWARE_PORT_TEXAS_INSTRUMENTS_TMS570_RM48, added prefix TRC. + +- Fixed several language issues in the comments and documentation. + +- Fixed several minor issues and warnings from different compilers + (including PowerPC/gcc) and configurations. + +------------------------------------------------------------------------------- + +Changes, v3.0.9 -> v3.1.0 + +- Merge of previously separated snapshot and streaming recorders into a single + recorder supporting both streaming and snapshot as different modes. + +- New common API for supporting both streaming and snapshot modes. + +- New integration guide, see the User Manual. + +- Major improvement of API documentation in source files and User Manual. + +- New concept of "stream ports", giving a better structure defining streaming + interfaces, and restructured the J-Link and TCP/IP streaming as stream ports. + +- Added a stream port for USB CDC connections, with STM32 as example. + Since Tracealyzer now can receive serial data on Windows COM ports, this is + really easy to use. + +- Added a warning (#error) for cases where FreeRTOS tickless idle mode is used + together with timestamping using SysTick or other periodic interrupt timers, + Tracing with tickless idle requires an independent time source to correctly + capture the length of the idle periods. + +- Major changes in the recorder API. Important examples are: + + * Some configuration macros have changed names, e.g. for "hardware port". + Make sure to remove any old "trcConfig.h" files if upgrading from an + earlier version! + + * Recorder configuration in trcConfig.h has been minimized and now only + includes the important settings that are independent of recorder mode. + Advanced settings for each mode are found in trcSnapshotConfig.h and + trcStreamingConfig.h. + + * vTraceEnable replaces Trace_Init and vTraceInitTraceData, as well as + vTraceStart and uiTraceStart. + + * vTraceStop now part of the common API and thereby available also in + streaming. And since vTraceEnable can start the streaming directly + you have the option control the tracing from target, e.g., for + streaming to a device file system. + + * vTraceStoreKernelObjectName from old streaming recorder has been replaced + by vTraceSetQueueName, vTraceSetSemaphoreName, etc. + + * vTraceSetISRProperties now returns a "traceHandle" that should be passed as + parameter to vTraceStoreISRBegin and vTraceStoreISREnd. + + * xTraceRegisterString has replaced the old functions xTraceOpenLabel and + vTraceStoreUserEventChannelName. This now returns a "traceString" for use + as "channel" parameter in vTracePrintF, and in other places where strings + are stored. + + * Removed vTraceStoreISREndManual and vTraceStoreISREndAuto, use + vTraceStoreISREnd instead. + + * Renamed the functions for saving User Events in a separate buffer: + - xTraceRegisterChannelFormat -> xTraceRegisterUBChannel + - vTraceChannelPrintF -> vTraceUBData + - vTraceChannelUserEvent -> vTraceUBEvent + + +------------------------------------------------------------------------------- +Copyright Percepio AB, 2017. \ No newline at end of file diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/Keil-uVision-Tracealyzer-ITM-Exporter.ini b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/Keil-uVision-Tracealyzer-ITM-Exporter.ini new file mode 100644 index 000000000..5e2c8b99b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/Keil-uVision-Tracealyzer-ITM-Exporter.ini @@ -0,0 +1,52 @@ +/************************************************************ +* Percepio Tracealyzer - ITM Trace Exporter for Keil uVision +* Copyright (c) 2018, Percepio AB. +* https://percepio.com +************************************************************/ + +FUNC void tzSetEnable(int enable) +{ + if (enable == 1) + { + printf("Starting Tracealyzer recorder\n"); + + // Forward the ITM data to file + exec("ITMLOG 1 > .\\tracealyzer.psf"); + + // Send start command to Tracealyzer (not required if using vTraceEnable(TRC_START)) + exec("E CHAR tz_host_command_data = 1, 1, 0, 0, 0, 0, 0xFD, 0xFF"); + exec("tz_host_command_bytes_to_read = 8"); + } + else if (enable == 0) + { + printf("Stopping Tracealyzer recorder...\n"); + + // Send stop command to Tracealyzer, to stop writing ITM data. + exec("E CHAR tz_host_command_data = 1, 0, 0, 0, 0, 0, 0xFE, 0xFF"); + exec("tz_host_command_bytes_to_read = 8"); + + _sleep_(2000); // Wait a while to let all data be written the host file. + + // Stop forwarding the ITM data to file and close the file. + exec("ITMLOG 1 OFF"); + + printf("Tracealyzer recorder stopped.\n"); + + } + else printf("Usage: tzSetEnable(0 or 1), where 0 is disable (stops recorder) and 1 enable (starts recording)"); + +} + + +// The Tracealyzer ITM stream port for Keil µVision can be used in two ways. +// +// 1. Start tracing directly from startup. +// Make sure tzSetEnable(1) is called below and vTraceEnable(TRC_START) in your target startup. +// +// 2. Start the trace manually, using the "Start Recording" button in Keil µVision. +// In this case, comment out the below call to tzSetEnable and make sure you call vTraceEnable(TRC_INIT) in your target startup (not TRC_START). + +tzSetEnable(1); + +DEFINE BUTTON "Start Recording", "tzSetEnable(1)"; +DEFINE BUTTON "Stop Recording", "tzSetEnable(0)"; \ No newline at end of file diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/Readme-ARM_ITM.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/Readme-ARM_ITM.txt new file mode 100644 index 000000000..0802b5331 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/Readme-ARM_ITM.txt @@ -0,0 +1,28 @@ +Tracealyzer Stream Port for ARM Cortex-M ITM +-------------------------------------------- +2018-05-04 + +This directory contains a "stream port" for the Tracealyzer recorder library, +i.e., the specific code needed to use a particular interface for streaming a +Tracealyzer RTOS trace. The stream port is defined by a set of macros in +trcStreamingPort.h, found in the "include" directory. + +This particular stream port targets ARM's ITM interface, which together with +a fast debug probe such as a Keil ULINKpro or ULINKplus provides excellent +performance. This stream port does not use any RAM buffer for the trace, but +writes the data directly to the ITM registers. This is very fast. + +To setup Keil uVision for ITM tracing with a Keil ULINKpro (or ULINKplus), +see Percepio Application Note PA-021 https://percepio.com/2018/05/04/keil-itm-support/ + +Learning more: + - Tracealyzer User Manual (Help -> User Manual) + - https://percepio.com/gettingstarted + - Percepio Application Note PA-021 https://percepio.com/2018/05/04/keil-itm-support/ + - About ITM trace, https://percepio.com/2016/06/09/arm-itm/ + - About the recorder and custom streaming, http://percepio.com/2016/10/05/rtos-tracing + +For questions, please contact support@percepio.com + +Percepio AB +www.percepio.com \ No newline at end of file diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/include/trcStreamingPort.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/include/trcStreamingPort.h new file mode 100644 index 000000000..ca20ae753 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/include/trcStreamingPort.h @@ -0,0 +1,91 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * trcStreamingPort.h + * + * The interface definitions for trace streaming ("stream ports"). + * This "stream port" sets up the recorder to use ARM ITM as streaming channel. + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_STREAMING_PORT_H +#define TRC_STREAMING_PORT_H + +#ifdef __cplusplus +extern "C" { +#endif + + +int32_t itm_write(void* ptrData, uint32_t size, int32_t* ptrBytesWritten); +int32_t read_from_host(void* ptrData, uint32_t size, int32_t* ptrBytesRead); + +/******************************************************************************* + * TRC_CFG_ITM_PORT + * + * Possible values: 0 - 31 + * + * What ITM port to use for the ITM software events. Make sure the IDE is + * configured for the same channel. + * + * Default: 1 (0 is typically terminal output and 31 is used by Keil) + * + ******************************************************************************/ +#define TRC_CFG_ITM_PORT 1 + +#if (TRC_CFG_ITM_PORT < 0) || (TRC_CFG_ITM_PORT > 31) +#error "Bad ITM port selected." +#endif + +// Not used for ITM - no RAM buffer... +#define TRC_STREAM_PORT_ALLOCATE_FIELDS() + +// Not used for ITM - assume the IDE configures the ITM setup +#define TRC_STREAM_PORT_INIT() + +/* Important for the ITM port - no RAM buffer, direct writes. In most other ports this can be skipped (default is 1) */ +#define TRC_STREAM_PORT_USE_INTERNAL_BUFFER 0 + +#define TRC_STREAM_PORT_WRITE_DATA(_ptrData, _size, _ptrBytesWritten) itm_write(_ptrData, _size, _ptrBytesWritten) + +#define TRC_STREAM_PORT_READ_DATA(_ptrData, _size, _ptrBytesRead) read_from_host(_ptrData, _size, _ptrBytesRead) + +#ifdef __cplusplus +} +#endif + +#endif /* TRC_STREAMING_PORT_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/trcStreamingPort.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/trcStreamingPort.c new file mode 100644 index 000000000..0d36b4ab3 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/ARM_ITM/trcStreamingPort.c @@ -0,0 +1,71 @@ + +#include "trcRecorder.h" + +#if (TRC_USE_TRACEALYZER_RECORDER == 1) +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) + +static void itm_write_32(uint32_t data); + +volatile int32_t tz_host_command_bytes_to_read = 0; // This is set by the Tracealyzer host application (to the number of bytes written), after having written to tz_host_commands. Set to zero by the read function after the message in tz_host_commands has been read. +volatile char tz_host_command_data[32]; + +/* This reads "command" data from a RAM buffer, written by a host macro in the debugger */ +int32_t read_from_host(void* ptrData, uint32_t size, int32_t* ptrBytesRead) +{ + if ( tz_host_command_bytes_to_read > 0) + { + int i; + uint8_t * bytesBuffer = (uint8_t*) ptrData; + + if (ptrBytesRead != NULL) + *ptrBytesRead = (int32_t)tz_host_command_bytes_to_read; + + if (tz_host_command_bytes_to_read != size) + { + return -1; + } + + for (i=0; i < tz_host_command_bytes_to_read; i++) + { + bytesBuffer[i] = tz_host_command_data[i]; + } + + tz_host_command_bytes_to_read = 0; + } + + return 0; +} + +static void itm_write_32(uint32_t data) +{ + if ((CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk) && // Trace enabled + (ITM->TCR & ITM_TCR_ITMENA_Msk) && // ITM enabled + (ITM->TER & (1UL << TRC_CFG_ITM_PORT))) // ITM port enabled + { + while (ITM->PORT[TRC_CFG_ITM_PORT].u32 == 0); // Block until room in ITM FIFO - This stream port is always in "blocking mode", since intended for high-speed ITM! + ITM->PORT[TRC_CFG_ITM_PORT].u32 = data; // Write the data + } +} + +/* This is assumed to execute from within the recorder, with interrupts disabled */ +int32_t itm_write(void* ptrData, uint32_t size, int32_t* ptrBytesWritten) +{ + uint32_t bytesWritten = 0; + uint32_t* ptr32 = (uint32_t*)ptrData; + + if (size % 4 != 0) return -2; + + while(bytesWritten < size) + { + itm_write_32(*ptr32); + ptr32++; + bytesWritten += 4; + } + + *ptrBytesWritten = bytesWritten; + + return 0; +} + +#endif +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/File/Readme-Streamport.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/File/Readme-Streamport.txt new file mode 100644 index 000000000..afc5a0951 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/File/Readme-Streamport.txt @@ -0,0 +1,19 @@ +Tracealyzer Stream Port for Files +------------------------------------------------- + +This directory contains a "stream port" for the Tracealyzer recorder library, +i.e., the specific code needed to use a particular interface for streaming a +Tracealyzer RTOS trace. The stream port is defined by a set of macros in +trcStreamingPort.h, found in the "include" directory. + +This particular stream port is for streaming to a file via stdio.h (fwrite). + +To use this stream port, make sure that include/trcStreamingPort.h is found +by the compiler (i.e., add this folder to your project's include paths) and +add all included source files to your build. Make sure no other versions of +trcStreamingPort.h are included by mistake! + +See also http://percepio.com/2016/10/05/rtos-tracing. + +Percepio AB +www.percepio.com \ No newline at end of file diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/File/include/trcStreamingPort.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/File/include/trcStreamingPort.h new file mode 100644 index 000000000..2897b7ce2 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/File/include/trcStreamingPort.h @@ -0,0 +1,87 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * trcStreamingPort.h + * + * The interface definitions for trace streaming ("stream ports"). + * This "stream port" sets up the recorder to stream the trace to file. + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_STREAMING_PORT_H +#define TRC_STREAMING_PORT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t writeToFile(void* data, uint32_t size, int32_t *ptrBytesWritten); + +void closeFile(void); + +void openFile(char* fileName); + +/* This define will determine whether to use the internal PagedEventBuffer or not. +If file writing creates additional trace events (i.e. it uses semaphores or mutexes), +then the paged event buffer must be enabled to avoid infinite recursion. */ +#define TRC_STREAM_PORT_USE_INTERNAL_BUFFER 1 + +#define TRC_STREAM_PORT_READ_DATA(_ptrData, _size, _ptrBytesRead) 0 /* Does not read commands from Tz (yet) */ + +#define TRC_STREAM_PORT_WRITE_DATA(_ptrData, _size, _ptrBytesSent) writeToFile(_ptrData, _size, _ptrBytesSent) + +#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC) +#define TRC_STREAM_PORT_MALLOC() \ + _TzTraceData = TRC_PORT_MALLOC((TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT) * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)); +extern char* _TzTraceData; +#else +#define TRC_STREAM_PORT_MALLOC() /* Custom or static allocation. Not used. */ +#endif +#define TRC_STREAM_PORT_INIT() \ + TRC_STREAM_PORT_MALLOC(); \ + openFile("trace.psf") + +#define TRC_STREAM_PORT_ON_TRACE_END() closeFile() + +#ifdef __cplusplus +} +#endif + +#endif /* TRC_STREAMING_PORT_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/File/trcStreamingPort.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/File/trcStreamingPort.c new file mode 100644 index 000000000..a019791cd --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/File/trcStreamingPort.c @@ -0,0 +1,103 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * trcStreamingPort.c + * + * Supporting functions for trace streaming, used by the "stream ports" + * for reading and writing data to the interface. + * Existing ports can easily be modified to fit another setup, e.g., a + * different TCP/IP stack, or to define your own stream port. + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#include "trcRecorder.h" + +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) +#if (TRC_USE_TRACEALYZER_RECORDER == 1) + +FILE* traceFile = NULL; + +void openFile(char* fileName) +{ + if (traceFile == NULL) + { + errno_t err = fopen_s(&traceFile, fileName, "wb"); + if (err != 0) + { + printf("Could not open trace file, error code %d.\n", err); + exit(-1); + } + else { + printf("Trace file created.\n"); + } + } +} + +int32_t writeToFile(void* data, uint32_t size, int32_t *ptrBytesWritten) +{ + int32_t written = 0; + if (traceFile != NULL) + { + written = fwrite(data, 1, size, traceFile); + } + else + { + written = 0; + } + + if (ptrBytesWritten != 0) + *ptrBytesWritten = written; + + if ((int32_t)size == written) + return 0; + else + return -1; +} + +void closeFile(void) +{ + if (traceFile != NULL) + { + fclose(traceFile); + traceFile = NULL; + printf("Trace file closed.\n"); + } +} + +#endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/ +#endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/Readme-Streamport.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/Readme-Streamport.txt new file mode 100644 index 000000000..cae5e8ecc --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/Readme-Streamport.txt @@ -0,0 +1,22 @@ +Tracealyzer Stream Port for SEGGER J-Link +----------------------------------------- + +This directory contains a "stream port" for the Tracealyzer recorder library, +i.e., the specific code needed to use a particular interface for streaming a +Tracealyzer RTOS trace. The stream port is defined by a set of macros in +trcStreamingPort.h, found in the "include" directory. + +This particular stream port targets SEGGER J-Link debug probes, using the RTT +interface provided by SEGGER. + +To use this stream port, make sure that include/trcStreamingPort.h is found +by the compiler (i.e., add this folder to your project's include paths) and +add all included source files to your build. Make sure no other versions of +trcStreamingPort.h are included by mistake! + +Note that this stream port also contains SEGGER's RTT driver. + +See also http://percepio.com/2016/10/05/rtos-tracing. + +Percepio AB +www.percepio.com \ No newline at end of file diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/SEGGER_RTT.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/SEGGER_RTT.c new file mode 100644 index 000000000..3ff3ba9ae --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/SEGGER_RTT.c @@ -0,0 +1,1447 @@ +/********************************************************************* +* SEGGER MICROCONTROLLER GmbH & Co. KG * +* Solutions for real time microcontroller applications * +********************************************************************** +* * +* (c) 2014 - 2016 SEGGER Microcontroller GmbH & Co. KG * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER RTT * Real Time Transfer for embedded targets * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* * This software may in its unmodified form be freely redistributed * +* in source, linkable, or executable form. * +* * The source code may be modified, provided the source code * +* retains the above copyright notice, this list of conditions and * +* the following disclaimer. * +* * Modified versions of this software in source, executable, or * +* linkable form may not be distributed without prior consent of * +* SEGGER. * +* * This software may only be used for communication with SEGGER * +* J-Link debug probes. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* RTT version: 6.00e * +* * +********************************************************************** +---------------------------END-OF-HEADER------------------------------ +File : SEGGER_RTT.c +Purpose : Implementation of SEGGER real-time transfer (RTT) which + allows real-time communication on targets which support + debugger memory accesses while the CPU is running. +Revision: $Rev: 4079 $ + +Additional information: + Type "int" is assumed to be 32-bits in size + H->T Host to target communication + T->H Target to host communication + + RTT channel 0 is always present and reserved for Terminal usage. + Name is fixed to "Terminal" + + Effective buffer size: SizeOfBuffer - 1 + + WrOff == RdOff: Buffer is empty + WrOff == (RdOff - 1): Buffer is full + WrOff > RdOff: Free space includes wrap-around + WrOff < RdOff: Used space includes wrap-around + (WrOff == (SizeOfBuffer - 1)) && (RdOff == 0): + Buffer full and wrap-around after next byte + + +---------------------------------------------------------------------- +*/ + +#include "SEGGER_RTT.h" + +#include // for memcpy + +/********************************************************************* +* +* Configuration, default values +* +********************************************************************** +*/ + +#ifndef BUFFER_SIZE_UP + #define BUFFER_SIZE_UP 1024 // Size of the buffer for terminal output of target, up to host +#endif + +#ifndef BUFFER_SIZE_DOWN + #define BUFFER_SIZE_DOWN 16 // Size of the buffer for terminal input to target from host (Usually keyboard input) +#endif + +#ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS + #define SEGGER_RTT_MAX_NUM_UP_BUFFERS 2 // Number of up-buffers (T->H) available on this target +#endif + +#ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS + #define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS 2 // Number of down-buffers (H->T) available on this target +#endif + +#ifndef SEGGER_RTT_BUFFER_SECTION + #if defined(SEGGER_RTT_SECTION) + #define SEGGER_RTT_BUFFER_SECTION SEGGER_RTT_SECTION + #endif +#endif + +#ifndef SEGGER_RTT_ALIGNMENT + #define SEGGER_RTT_ALIGNMENT 0 +#endif + +#ifndef SEGGER_RTT_BUFFER_ALIGNMENT + #define SEGGER_RTT_BUFFER_ALIGNMENT 0 +#endif + +#ifndef SEGGER_RTT_MODE_DEFAULT + #define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP +#endif + +#ifndef SEGGER_RTT_LOCK + #define SEGGER_RTT_LOCK() +#endif + +#ifndef SEGGER_RTT_UNLOCK + #define SEGGER_RTT_UNLOCK() +#endif + +#ifndef STRLEN + #define STRLEN(a) strlen((a)) +#endif + +#ifndef MEMCPY + #define MEMCPY(pDest, pSrc, NumBytes) memcpy((pDest), (pSrc), (NumBytes)) +#endif + +#ifndef MIN + #define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX + #define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif +// +// For some environments, NULL may not be defined until certain headers are included +// +#ifndef NULL + #define NULL 0 +#endif + +/********************************************************************* +* +* Defines, fixed +* +********************************************************************** +*/ +#if (defined __ICCARM__) || (defined __ICCRX__) + #define RTT_PRAGMA(P) _Pragma(#P) +#endif + +#if SEGGER_RTT_ALIGNMENT || SEGGER_RTT_BUFFER_ALIGNMENT + #if (defined __GNUC__) + #define SEGGER_RTT_ALIGN(Var, Alignment) Var __attribute__ ((aligned (Alignment))) + #elif (defined __ICCARM__) || (defined __ICCRX__) + #define PRAGMA(A) _Pragma(#A) +#define SEGGER_RTT_ALIGN(Var, Alignment) RTT_PRAGMA(data_alignment=Alignment) \ + Var + #elif (defined __CC_ARM__) + #define SEGGER_RTT_ALIGN(Var, Alignment) Var __attribute__ ((aligned (Alignment))) + #else + #error "Alignment not supported for this compiler." + #endif +#else + #define SEGGER_RTT_ALIGN(Var, Alignment) Var +#endif + +#if defined(SEGGER_RTT_SECTION) || defined (SEGGER_RTT_BUFFER_SECTION) + #if (defined __GNUC__) + #define SEGGER_RTT_PUT_SECTION(Var, Section) __attribute__ ((section (Section))) Var + #elif (defined __ICCARM__) || (defined __ICCRX__) +#define SEGGER_RTT_PUT_SECTION(Var, Section) RTT_PRAGMA(location=Section) \ + Var + #elif (defined __CC_ARM__) + #define SEGGER_RTT_PUT_SECTION(Var, Section) __attribute__ ((section (Section), zero_init)) Var + #else + #error "Section placement not supported for this compiler." + #endif +#else + #define SEGGER_RTT_PUT_SECTION(Var, Section) Var +#endif + + +#if SEGGER_RTT_ALIGNMENT + #define SEGGER_RTT_CB_ALIGN(Var) SEGGER_RTT_ALIGN(Var, SEGGER_RTT_ALIGNMENT) +#else + #define SEGGER_RTT_CB_ALIGN(Var) Var +#endif + +#if SEGGER_RTT_BUFFER_ALIGNMENT + #define SEGGER_RTT_BUFFER_ALIGN(Var) SEGGER_RTT_ALIGN(Var, SEGGER_RTT_BUFFER_ALIGNMENT) +#else + #define SEGGER_RTT_BUFFER_ALIGN(Var) Var +#endif + + +#if defined(SEGGER_RTT_SECTION) + #define SEGGER_RTT_PUT_CB_SECTION(Var) SEGGER_RTT_PUT_SECTION(Var, SEGGER_RTT_SECTION) +#else + #define SEGGER_RTT_PUT_CB_SECTION(Var) Var +#endif + +#if defined(SEGGER_RTT_BUFFER_SECTION) + #define SEGGER_RTT_PUT_BUFFER_SECTION(Var) SEGGER_RTT_PUT_SECTION(Var, SEGGER_RTT_BUFFER_SECTION) +#else + #define SEGGER_RTT_PUT_BUFFER_SECTION(Var) Var +#endif + +/********************************************************************* +* +* Static const data +* +********************************************************************** +*/ + +static unsigned char _aTerminalId[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + +/********************************************************************* +* +* Static data +* +********************************************************************** +*/ +// +// RTT Control Block and allocate buffers for channel 0 +// +SEGGER_RTT_PUT_CB_SECTION(SEGGER_RTT_CB_ALIGN(SEGGER_RTT_CB _SEGGER_RTT)); + +SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acUpBuffer [BUFFER_SIZE_UP])); +SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acDownBuffer[BUFFER_SIZE_DOWN])); + +static char _ActiveTerminal; + +/********************************************************************* +* +* Static functions +* +********************************************************************** +*/ + +/********************************************************************* +* +* _DoInit() +* +* Function description +* Initializes the control block an buffers. +* May only be called via INIT() to avoid overriding settings. +* +*/ +#define INIT() do { \ + if (_SEGGER_RTT.acID[0] == '\0') { _DoInit(); } \ + } while (0) +static void _DoInit(void) { + SEGGER_RTT_CB* p; + // + // Initialize control block + // + p = &_SEGGER_RTT; + p->MaxNumUpBuffers = SEGGER_RTT_MAX_NUM_UP_BUFFERS; + p->MaxNumDownBuffers = SEGGER_RTT_MAX_NUM_DOWN_BUFFERS; + // + // Initialize up buffer 0 + // + p->aUp[0].sName = "Terminal"; + p->aUp[0].pBuffer = _acUpBuffer; + p->aUp[0].SizeOfBuffer = sizeof(_acUpBuffer); + p->aUp[0].RdOff = 0u; + p->aUp[0].WrOff = 0u; + p->aUp[0].Flags = SEGGER_RTT_MODE_DEFAULT; + // + // Initialize down buffer 0 + // + p->aDown[0].sName = "Terminal"; + p->aDown[0].pBuffer = _acDownBuffer; + p->aDown[0].SizeOfBuffer = sizeof(_acDownBuffer); + p->aDown[0].RdOff = 0u; + p->aDown[0].WrOff = 0u; + p->aDown[0].Flags = SEGGER_RTT_MODE_DEFAULT; + // + // Finish initialization of the control block. + // Copy Id string in three steps to make sure "SEGGER RTT" is not found + // in initializer memory (usually flash) by J-Link + // + strcpy(&p->acID[7], "RTT"); + strcpy(&p->acID[0], "SEGGER"); + p->acID[6] = ' '; +} + +/********************************************************************* +* +* _WriteBlocking() +* +* Function description +* Stores a specified number of characters in SEGGER RTT ring buffer +* and updates the associated write pointer which is periodically +* read by the host. +* The caller is responsible for managing the write chunk sizes as +* _WriteBlocking() will block until all data has been posted successfully. +* +* Parameters +* pRing Ring buffer to post to. +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Return value +* >= 0 - Number of bytes written into buffer. +*/ +static unsigned _WriteBlocking(SEGGER_RTT_BUFFER_UP* pRing, const char* pBuffer, unsigned NumBytes) { + unsigned NumBytesToWrite; + unsigned NumBytesWritten; + unsigned RdOff; + unsigned WrOff; + // + // Write data to buffer and handle wrap-around if necessary + // + NumBytesWritten = 0u; + WrOff = pRing->WrOff; + do { + RdOff = pRing->RdOff; // May be changed by host (debug probe) in the meantime + if (RdOff > WrOff) { + NumBytesToWrite = RdOff - WrOff - 1u; + } else { + NumBytesToWrite = pRing->SizeOfBuffer - (WrOff - RdOff + 1u); + } + NumBytesToWrite = MIN(NumBytesToWrite, (pRing->SizeOfBuffer - WrOff)); // Number of bytes that can be written until buffer wrap-around + NumBytesToWrite = MIN(NumBytesToWrite, NumBytes); + memcpy(pRing->pBuffer + WrOff, pBuffer, NumBytesToWrite); + NumBytesWritten += NumBytesToWrite; + pBuffer += NumBytesToWrite; + NumBytes -= NumBytesToWrite; + WrOff += NumBytesToWrite; + if (WrOff == pRing->SizeOfBuffer) { + WrOff = 0u; + } + pRing->WrOff = WrOff; + } while (NumBytes); + // + return NumBytesWritten; +} + +/********************************************************************* +* +* _WriteNoCheck() +* +* Function description +* Stores a specified number of characters in SEGGER RTT ring buffer +* and updates the associated write pointer which is periodically +* read by the host. +* It is callers responsibility to make sure data actually fits in buffer. +* +* Parameters +* pRing Ring buffer to post to. +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Notes +* (1) If there might not be enough space in the "Up"-buffer, call _WriteBlocking +*/ +static void _WriteNoCheck(SEGGER_RTT_BUFFER_UP* pRing, const char* pData, unsigned NumBytes) { + unsigned NumBytesAtOnce; + unsigned WrOff; + unsigned Rem; + + WrOff = pRing->WrOff; + Rem = pRing->SizeOfBuffer - WrOff; + if (Rem > NumBytes) { + // + // All data fits before wrap around + // + memcpy(pRing->pBuffer + WrOff, pData, NumBytes); + pRing->WrOff = WrOff + NumBytes; + } else { + // + // We reach the end of the buffer, so need to wrap around + // + NumBytesAtOnce = Rem; + memcpy(pRing->pBuffer + WrOff, pData, NumBytesAtOnce); + NumBytesAtOnce = NumBytes - Rem; + memcpy(pRing->pBuffer, pData + Rem, NumBytesAtOnce); + pRing->WrOff = NumBytesAtOnce; + } +} + +/********************************************************************* +* +* _PostTerminalSwitch() +* +* Function description +* Switch terminal to the given terminal ID. It is the caller's +* responsibility to ensure the terminal ID is correct and there is +* enough space in the buffer for this to complete successfully. +* +* Parameters +* pRing Ring buffer to post to. +* TerminalId Terminal ID to switch to. +*/ +static void _PostTerminalSwitch(SEGGER_RTT_BUFFER_UP* pRing, unsigned char TerminalId) { + char ac[2]; + + ac[0] = 0xFFu; + ac[1] = _aTerminalId[TerminalId]; // Caller made already sure that TerminalId does not exceed our terminal limit + _WriteBlocking(pRing, ac, 2u); +} + +/********************************************************************* +* +* _GetAvailWriteSpace() +* +* Function description +* Returns the number of bytes that can be written to the ring +* buffer without blocking. +* +* Parameters +* pRing Ring buffer to check. +* +* Return value +* Number of bytes that are free in the buffer. +*/ +static unsigned _GetAvailWriteSpace(SEGGER_RTT_BUFFER_UP* pRing) { + unsigned RdOff; + unsigned WrOff; + unsigned r; + // + // Avoid warnings regarding volatile access order. It's not a problem + // in this case, but dampen compiler enthusiasm. + // + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + if (RdOff <= WrOff) { + r = pRing->SizeOfBuffer - 1u - WrOff + RdOff; + } else { + r = RdOff - WrOff - 1u; + } + return r; +} + +/********************************************************************* +* +* Public code +* +********************************************************************** +*/ +/********************************************************************* +* +* SEGGER_RTT_ReadNoLock() +* +* Function description +* Reads characters from SEGGER real-time-terminal control block +* which have been previously stored by the host. +* Do not lock against interrupts and multiple access. +* +* Parameters +* BufferIndex Index of Down-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to. +* BufferSize Size of the target application buffer. +* +* Return value +* Number of bytes that have been read. +*/ +unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize) { + unsigned NumBytesRem; + unsigned NumBytesRead; + unsigned RdOff; + unsigned WrOff; + unsigned char* pBuffer; + SEGGER_RTT_BUFFER_DOWN* pRing; + // + INIT(); + pRing = &_SEGGER_RTT.aDown[BufferIndex]; + pBuffer = (unsigned char*)pData; + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + NumBytesRead = 0u; + // + // Read from current read position to wrap-around of buffer, first + // + if (RdOff > WrOff) { + NumBytesRem = pRing->SizeOfBuffer - RdOff; + NumBytesRem = MIN(NumBytesRem, BufferSize); + memcpy(pBuffer, pRing->pBuffer + RdOff, NumBytesRem); + NumBytesRead += NumBytesRem; + pBuffer += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; + // + // Handle wrap-around of buffer + // + if (RdOff == pRing->SizeOfBuffer) { + RdOff = 0u; + } + } + // + // Read remaining items of buffer + // + NumBytesRem = WrOff - RdOff; + NumBytesRem = MIN(NumBytesRem, BufferSize); + if (NumBytesRem > 0u) { + memcpy(pBuffer, pRing->pBuffer + RdOff, NumBytesRem); + NumBytesRead += NumBytesRem; + pBuffer += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; + } + if (NumBytesRead) { + pRing->RdOff = RdOff; + } + // + return NumBytesRead; +} + +/********************************************************************* +* +* SEGGER_RTT_Read +* +* Function description +* Reads characters from SEGGER real-time-terminal control block +* which have been previously stored by the host. +* +* Parameters +* BufferIndex Index of Down-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to buffer provided by target application, to copy characters from RTT-down-buffer to. +* BufferSize Size of the target application buffer. +* +* Return value +* Number of bytes that have been read. +*/ +unsigned SEGGER_RTT_Read(unsigned BufferIndex, void* pBuffer, unsigned BufferSize) { + unsigned NumBytesRead; + // + SEGGER_RTT_LOCK(); + // + // Call the non-locking read function + // + NumBytesRead = SEGGER_RTT_ReadNoLock(BufferIndex, pBuffer, BufferSize); + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + // + return NumBytesRead; +} + +/********************************************************************* +* +* SEGGER_RTT_WriteWithOverwriteNoLock +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block. +* SEGGER_RTT_WriteWithOverwriteNoLock does not lock the application +* and overwrites data if the data does not fit into the buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Notes +* (1) If there is not enough space in the "Up"-buffer, data is overwritten. +* (2) For performance reasons this function does not call Init() +* and may only be called after RTT has been initialized. +* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. +* (3) Do not use SEGGER_RTT_WriteWithOverwriteNoLock if a J-Link +* connection reads RTT data. +*/ +void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + unsigned Avail; + + pData = (const char *)pBuffer; + // + // Get "to-host" ring buffer and copy some elements into local variables. + // + pRing = &_SEGGER_RTT.aUp[BufferIndex]; + // + // Check if we will overwrite data and need to adjust the RdOff. + // + if (pRing->WrOff == pRing->RdOff) { + Avail = pRing->SizeOfBuffer - 1u; + } else if ( pRing->WrOff < pRing->RdOff) { + Avail = pRing->RdOff - pRing->WrOff - 1u; + } else { + Avail = pRing->RdOff - pRing->WrOff - 1u + pRing->SizeOfBuffer; + } + if (NumBytes > Avail) { + pRing->RdOff += (NumBytes - Avail); + while (pRing->RdOff >= pRing->SizeOfBuffer) { + pRing->RdOff -= pRing->SizeOfBuffer; + } + } + // + // Write all data, no need to check the RdOff, but possibly handle multiple wrap-arounds + // + Avail = pRing->SizeOfBuffer - pRing->WrOff; + do { + if (Avail > NumBytes) { + // + // Last round + // +#if 1 // memcpy() is good for large amounts of data, but the overhead is too big for small amounts. Use a simple byte loop instead. + char* pDst; + pDst = pRing->pBuffer + pRing->WrOff; + pRing->WrOff += NumBytes; + do { + *pDst++ = *pData++; + } while (--NumBytes); +#else + memcpy(pRing->pBuffer + WrOff, pData, NumBytes); + pRing->WrOff += NumBytes; +#endif + break; //Alternatively: NumBytes = 0; + } else { + // + // Wrap-around necessary, write until wrap-around and reset WrOff + // + memcpy(pRing->pBuffer + pRing->WrOff, pData, Avail); + pData += Avail; + pRing->WrOff = 0; + NumBytes -= Avail; + Avail = (pRing->SizeOfBuffer - 1); + } + } while (NumBytes); +} + +/********************************************************************* +* +* SEGGER_RTT_WriteSkipNoLock +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block which is then read by the host. +* SEGGER_RTT_WriteSkipNoLock does not lock the application and +* skips all data, if the data does not fit into the buffer. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) If there is not enough space in the "Up"-buffer, all data is dropped. +* (2) For performance reasons this function does not call Init() +* and may only be called after RTT has been initialized. +* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. +*/ +unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + unsigned Avail; + unsigned RdOff; + unsigned WrOff; + unsigned Rem; + + pData = (const char *)pBuffer; + // + // Get "to-host" ring buffer and copy some elements into local variables. + // + pRing = &_SEGGER_RTT.aUp[BufferIndex]; + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + // + // Handle the most common cases fastest. + // Which is: + // RdOff <= WrOff -> Space until wrap around is free. + // AND + // WrOff + NumBytes < SizeOfBuffer -> No Wrap around necessary. + // + // OR + // + // RdOff > WrOff -> Space until RdOff - 1 is free. + // AND + // WrOff + NumBytes < RdOff -> Data fits into buffer + // + if (RdOff <= WrOff) { + // + // Get space until WrOff will be at wrap around. + // + Avail = pRing->SizeOfBuffer - 1u - WrOff ; + if (Avail >= NumBytes) { +#if 1 // memcpy() is good for large amounts of data, but the overhead is too big for small amounts. Use a simple byte loop instead. + char* pDst; + pDst = pRing->pBuffer + WrOff; + WrOff += NumBytes; + do { + *pDst++ = *pData++; + } while (--NumBytes); + pRing->WrOff = WrOff + NumBytes; +#else + memcpy(pRing->pBuffer + WrOff, pData, NumBytes); + pRing->WrOff = WrOff + NumBytes; +#endif + return 1; + } + // + // If data did not fit into space until wrap around calculate complete space in buffer. + // + Avail += RdOff; + // + // If there is still no space for the whole of this output, don't bother. + // + if (Avail >= NumBytes) { + // + // OK, we have enough space in buffer. Copy in one or 2 chunks + // + Rem = pRing->SizeOfBuffer - WrOff; // Space until end of buffer + if (Rem > NumBytes) { + memcpy(pRing->pBuffer + WrOff, pData, NumBytes); + pRing->WrOff = WrOff + NumBytes; + } else { + // + // We reach the end of the buffer, so need to wrap around + // + memcpy(pRing->pBuffer + WrOff, pData, Rem); + memcpy(pRing->pBuffer, pData + Rem, NumBytes - Rem); + pRing->WrOff = NumBytes - Rem; + } + return 1; + } + } else { + Avail = RdOff - WrOff - 1u; + if (Avail >= NumBytes) { + memcpy(pRing->pBuffer + WrOff, pData, NumBytes); + pRing->WrOff = WrOff + NumBytes; + return 1; + } + } + // + // If we reach this point no data has been written + // + return 0; +} + +/********************************************************************* +* +* SEGGER_RTT_WriteNoLock +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block which is then read by the host. +* SEGGER_RTT_WriteNoLock does not lock the application. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) If there is not enough space in the "Up"-buffer, remaining characters of pBuffer are dropped. +* (2) For performance reasons this function does not call Init() +* and may only be called after RTT has been initialized. +* Either by calling SEGGER_RTT_Init() or calling another RTT API function first. +*/ +unsigned SEGGER_RTT_WriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + unsigned Status; + unsigned Avail; + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + + pData = (const char *)pBuffer; + // + // Get "to-host" ring buffer. + // + pRing = &_SEGGER_RTT.aUp[BufferIndex]; + // + // How we output depends upon the mode... + // + switch (pRing->Flags) { + case SEGGER_RTT_MODE_NO_BLOCK_SKIP: + // + // If we are in skip mode and there is no space for the whole + // of this output, don't bother. + // + Avail = _GetAvailWriteSpace(pRing); + if (Avail < NumBytes) { + Status = 0u; + } else { + Status = NumBytes; + _WriteNoCheck(pRing, pData, NumBytes); + } + break; + case SEGGER_RTT_MODE_NO_BLOCK_TRIM: + // + // If we are in trim mode, trim to what we can output without blocking. + // + Avail = _GetAvailWriteSpace(pRing); + Status = Avail < NumBytes ? Avail : NumBytes; + _WriteNoCheck(pRing, pData, Status); + break; + case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: + // + // If we are in blocking mode, output everything. + // + Status = _WriteBlocking(pRing, pData, NumBytes); + break; + default: + Status = 0u; + break; + } + // + // Finish up. + // + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_Write +* +* Function description +* Stores a specified number of characters in SEGGER RTT +* control block which is then read by the host. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* pBuffer Pointer to character array. Does not need to point to a \0 terminated string. +* NumBytes Number of bytes to be stored in the SEGGER RTT control block. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) If there is not enough space in the "Up"-buffer, remaining characters of pBuffer are dropped. +*/ +unsigned SEGGER_RTT_Write(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) { + unsigned Status; + // + INIT(); + SEGGER_RTT_LOCK(); + // + // Call the non-locking write function + // + Status = SEGGER_RTT_WriteNoLock(BufferIndex, pBuffer, NumBytes); + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + // + return Status; +} + +/********************************************************************* +* +* SEGGER_RTT_WriteString +* +* Function description +* Stores string in SEGGER RTT control block. +* This data is read by the host. +* +* Parameters +* BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). +* s Pointer to string. +* +* Return value +* Number of bytes which have been stored in the "Up"-buffer. +* +* Notes +* (1) If there is not enough space in the "Up"-buffer, depending on configuration, +* remaining characters may be dropped or RTT module waits until there is more space in the buffer. +* (2) String passed to this function has to be \0 terminated +* (3) \0 termination character is *not* stored in RTT buffer +*/ +unsigned SEGGER_RTT_WriteString(unsigned BufferIndex, const char* s) { + unsigned Len; + + Len = STRLEN(s); + return SEGGER_RTT_Write(BufferIndex, s, Len); +} + +/********************************************************************* +* +* SEGGER_RTT_GetKey +* +* Function description +* Reads one character from the SEGGER RTT buffer. +* Host has previously stored data there. +* +* Return value +* < 0 - No character available (buffer empty). +* >= 0 - Character which has been read. (Possible values: 0 - 255) +* +* Notes +* (1) This function is only specified for accesses to RTT buffer 0. +*/ +int SEGGER_RTT_GetKey(void) { + char c; + int r; + + r = (int)SEGGER_RTT_Read(0u, &c, 1u); + if (r == 1) { + r = (int)(unsigned char)c; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_WaitKey +* +* Function description +* Waits until at least one character is avaible in the SEGGER RTT buffer. +* Once a character is available, it is read and this function returns. +* +* Return value +* >=0 - Character which has been read. +* +* Notes +* (1) This function is only specified for accesses to RTT buffer 0 +* (2) This function is blocking if no character is present in RTT buffer +*/ +int SEGGER_RTT_WaitKey(void) { + int r; + + do { + r = SEGGER_RTT_GetKey(); + } while (r < 0); + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_HasKey +* +* Function description +* Checks if at least one character for reading is available in the SEGGER RTT buffer. +* +* Return value +* == 0 - No characters are available to read. +* == 1 - At least one character is available. +* +* Notes +* (1) This function is only specified for accesses to RTT buffer 0 +*/ +int SEGGER_RTT_HasKey(void) { + unsigned RdOff; + int r; + + INIT(); + RdOff = _SEGGER_RTT.aDown[0].RdOff; + if (RdOff != _SEGGER_RTT.aDown[0].WrOff) { + r = 1; + } else { + r = 0; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_HasData +* +* Function description +* Check if there is data from the host in the given buffer. +* +* Return value: +* ==0: No data +* !=0: Data in buffer +* +*/ +unsigned SEGGER_RTT_HasData(unsigned BufferIndex) { + SEGGER_RTT_BUFFER_DOWN* pRing; + unsigned v; + + pRing = &_SEGGER_RTT.aDown[BufferIndex]; + v = pRing->WrOff; + return v - pRing->RdOff; +} + +/********************************************************************* +* +* SEGGER_RTT_AllocDownBuffer +* +* Function description +* Run-time configuration of the next down-buffer (H->T). +* The next buffer, which is not used yet is configured. +* This includes: Buffer address, size, name, flags, ... +* +* Parameters +* sName Pointer to a constant name string. +* pBuffer Pointer to a buffer to be used. +* BufferSize Size of the buffer. +* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* +* Return value +* >= 0 - O.K. Buffer Index +* < 0 - Error +*/ +int SEGGER_RTT_AllocDownBuffer(const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { + int BufferIndex; + + INIT(); + SEGGER_RTT_LOCK(); + BufferIndex = 0; + do { + if (_SEGGER_RTT.aDown[BufferIndex].pBuffer == NULL) { + break; + } + BufferIndex++; + } while (BufferIndex < _SEGGER_RTT.MaxNumDownBuffers); + if (BufferIndex < _SEGGER_RTT.MaxNumDownBuffers) { + _SEGGER_RTT.aDown[BufferIndex].sName = sName; + _SEGGER_RTT.aDown[BufferIndex].pBuffer = (char*)pBuffer; + _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer = BufferSize; + _SEGGER_RTT.aDown[BufferIndex].RdOff = 0u; + _SEGGER_RTT.aDown[BufferIndex].WrOff = 0u; + _SEGGER_RTT.aDown[BufferIndex].Flags = Flags; + } else { + BufferIndex = -1; + } + SEGGER_RTT_UNLOCK(); + return BufferIndex; +} + +/********************************************************************* +* +* SEGGER_RTT_AllocUpBuffer +* +* Function description +* Run-time configuration of the next up-buffer (T->H). +* The next buffer, which is not used yet is configured. +* This includes: Buffer address, size, name, flags, ... +* +* Parameters +* sName Pointer to a constant name string. +* pBuffer Pointer to a buffer to be used. +* BufferSize Size of the buffer. +* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* +* Return value +* >= 0 - O.K. Buffer Index +* < 0 - Error +*/ +int SEGGER_RTT_AllocUpBuffer(const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { + int BufferIndex; + + INIT(); + SEGGER_RTT_LOCK(); + BufferIndex = 0; + do { + if (_SEGGER_RTT.aUp[BufferIndex].pBuffer == NULL) { + break; + } + BufferIndex++; + } while (BufferIndex < _SEGGER_RTT.MaxNumUpBuffers); + if (BufferIndex < _SEGGER_RTT.MaxNumUpBuffers) { + _SEGGER_RTT.aUp[BufferIndex].sName = sName; + _SEGGER_RTT.aUp[BufferIndex].pBuffer = (char*)pBuffer; + _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer = BufferSize; + _SEGGER_RTT.aUp[BufferIndex].RdOff = 0u; + _SEGGER_RTT.aUp[BufferIndex].WrOff = 0u; + _SEGGER_RTT.aUp[BufferIndex].Flags = Flags; + } else { + BufferIndex = -1; + } + SEGGER_RTT_UNLOCK(); + return BufferIndex; +} + +/********************************************************************* +* +* SEGGER_RTT_ConfigUpBuffer +* +* Function description +* Run-time configuration of a specific up-buffer (T->H). +* Buffer to be configured is specified by index. +* This includes: Buffer address, size, name, flags, ... +* +* Parameters +* BufferIndex Index of the buffer to configure. +* sName Pointer to a constant name string. +* pBuffer Pointer to a buffer to be used. +* BufferSize Size of the buffer. +* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* +* Return value +* >= 0 - O.K. +* < 0 - Error +* +* Additional information +* Buffer 0 is configured on compile-time. +* May only be called once per buffer. +* Buffer name and flags can be reconfigured using the appropriate functions. +*/ +int SEGGER_RTT_ConfigUpBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { + int r; + + INIT(); + if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) { + SEGGER_RTT_LOCK(); + if (BufferIndex > 0u) { + _SEGGER_RTT.aUp[BufferIndex].sName = sName; + _SEGGER_RTT.aUp[BufferIndex].pBuffer = (char*)pBuffer; + _SEGGER_RTT.aUp[BufferIndex].SizeOfBuffer = BufferSize; + _SEGGER_RTT.aUp[BufferIndex].RdOff = 0u; + _SEGGER_RTT.aUp[BufferIndex].WrOff = 0u; + } + _SEGGER_RTT.aUp[BufferIndex].Flags = Flags; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_ConfigDownBuffer +* +* Function description +* Run-time configuration of a specific down-buffer (H->T). +* Buffer to be configured is specified by index. +* This includes: Buffer address, size, name, flags, ... +* +* Parameters +* BufferIndex Index of the buffer to configure. +* sName Pointer to a constant name string. +* pBuffer Pointer to a buffer to be used. +* BufferSize Size of the buffer. +* Flags Operating modes. Define behavior if buffer is full (not enough space for entire message). +* +* Return value +* >= 0 O.K. +* < 0 Error +* +* Additional information +* Buffer 0 is configured on compile-time. +* May only be called once per buffer. +* Buffer name and flags can be reconfigured using the appropriate functions. +*/ +int SEGGER_RTT_ConfigDownBuffer(unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) { + int r; + + INIT(); + if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) { + SEGGER_RTT_LOCK(); + if (BufferIndex > 0u) { + _SEGGER_RTT.aDown[BufferIndex].sName = sName; + _SEGGER_RTT.aDown[BufferIndex].pBuffer = (char*)pBuffer; + _SEGGER_RTT.aDown[BufferIndex].SizeOfBuffer = BufferSize; + _SEGGER_RTT.aDown[BufferIndex].RdOff = 0u; + _SEGGER_RTT.aDown[BufferIndex].WrOff = 0u; + } + _SEGGER_RTT.aDown[BufferIndex].Flags = Flags; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_SetNameUpBuffer +* +* Function description +* Run-time configuration of a specific up-buffer name (T->H). +* Buffer to be configured is specified by index. +* +* Parameters +* BufferIndex Index of the buffer to renamed. +* sName Pointer to a constant name string. +* +* Return value +* >= 0 O.K. +* < 0 Error +*/ +int SEGGER_RTT_SetNameUpBuffer(unsigned BufferIndex, const char* sName) { + int r; + + INIT(); + if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) { + SEGGER_RTT_LOCK(); + _SEGGER_RTT.aUp[BufferIndex].sName = sName; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_SetNameDownBuffer +* +* Function description +* Run-time configuration of a specific Down-buffer name (T->H). +* Buffer to be configured is specified by index. +* +* Parameters +* BufferIndex Index of the buffer to renamed. +* sName Pointer to a constant name string. +* +* Return value +* >= 0 O.K. +* < 0 Error +*/ +int SEGGER_RTT_SetNameDownBuffer(unsigned BufferIndex, const char* sName) { + int r; + + INIT(); + if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) { + SEGGER_RTT_LOCK(); + _SEGGER_RTT.aDown[BufferIndex].sName = sName; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_SetFlagsUpBuffer +* +* Function description +* Run-time configuration of specific up-buffer flags (T->H). +* Buffer to be configured is specified by index. +* +* Parameters +* BufferIndex Index of the buffer. +* Flags Flags to set for the buffer. +* +* Return value +* >= 0 O.K. +* < 0 Error +*/ +int SEGGER_RTT_SetFlagsUpBuffer(unsigned BufferIndex, unsigned Flags) { + int r; + + INIT(); + if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumUpBuffers) { + SEGGER_RTT_LOCK(); + _SEGGER_RTT.aUp[BufferIndex].Flags = Flags; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_SetFlagsDownBuffer +* +* Function description +* Run-time configuration of specific Down-buffer flags (T->H). +* Buffer to be configured is specified by index. +* +* Parameters +* BufferIndex Index of the buffer to renamed. +* Flags Flags to set for the buffer. +* +* Return value +* >= 0 O.K. +* < 0 Error +*/ +int SEGGER_RTT_SetFlagsDownBuffer(unsigned BufferIndex, unsigned Flags) { + int r; + + INIT(); + if (BufferIndex < (unsigned)_SEGGER_RTT.MaxNumDownBuffers) { + SEGGER_RTT_LOCK(); + _SEGGER_RTT.aDown[BufferIndex].Flags = Flags; + SEGGER_RTT_UNLOCK(); + r = 0; + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_Init +* +* Function description +* Initializes the RTT Control Block. +* Should be used in RAM targets, at start of the application. +* +*/ +void SEGGER_RTT_Init (void) { + _DoInit(); +} + +/********************************************************************* +* +* SEGGER_RTT_SetTerminal +* +* Function description +* Sets the terminal to be used for output on channel 0. +* +* Parameters +* TerminalId Index of the terminal. +* +* Return value +* >= 0 O.K. +* < 0 Error (e.g. if RTT is configured for non-blocking mode and there was no space in the buffer to set the new terminal Id) +*/ +int SEGGER_RTT_SetTerminal (char TerminalId) { + char ac[2]; + SEGGER_RTT_BUFFER_UP* pRing; + unsigned Avail; + int r; + // + INIT(); + // + r = 0; + ac[0] = 0xFFU; + if ((unsigned char)TerminalId < (unsigned char)sizeof(_aTerminalId)) { // We only support a certain number of channels + ac[1] = _aTerminalId[(unsigned char)TerminalId]; + pRing = &_SEGGER_RTT.aUp[0]; // Buffer 0 is always reserved for terminal I/O, so we can use index 0 here, fixed + SEGGER_RTT_LOCK(); // Lock to make sure that no other task is writing into buffer, while we are and number of free bytes in buffer does not change downwards after checking and before writing + if ((pRing->Flags & SEGGER_RTT_MODE_MASK) == SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) { + _ActiveTerminal = TerminalId; + _WriteBlocking(pRing, ac, 2u); + } else { // Skipping mode or trim mode? => We cannot trim this command so handling is the same for both modes + Avail = _GetAvailWriteSpace(pRing); + if (Avail >= 2) { + _ActiveTerminal = TerminalId; // Only change active terminal in case of success + _WriteNoCheck(pRing, ac, 2u); + } else { + r = -1; + } + } + SEGGER_RTT_UNLOCK(); + } else { + r = -1; + } + return r; +} + +/********************************************************************* +* +* SEGGER_RTT_TerminalOut +* +* Function description +* Writes a string to the given terminal +* without changing the terminal for channel 0. +* +* Parameters +* TerminalId Index of the terminal. +* s String to be printed on the terminal. +* +* Return value +* >= 0 - Number of bytes written. +* < 0 - Error. +* +*/ +int SEGGER_RTT_TerminalOut (char TerminalId, const char* s) { + int Status; + unsigned FragLen; + unsigned Avail; + SEGGER_RTT_BUFFER_UP* pRing; + // + INIT(); + // + // Validate terminal ID. + // + if (TerminalId < (char)sizeof(_aTerminalId)) { // We only support a certain number of channels + // + // Get "to-host" ring buffer. + // + pRing = &_SEGGER_RTT.aUp[0]; + // + // Need to be able to change terminal, write data, change back. + // Compute the fixed and variable sizes. + // + FragLen = strlen(s); + // + // How we output depends upon the mode... + // + SEGGER_RTT_LOCK(); + Avail = _GetAvailWriteSpace(pRing); + switch (pRing->Flags & SEGGER_RTT_MODE_MASK) { + case SEGGER_RTT_MODE_NO_BLOCK_SKIP: + // + // If we are in skip mode and there is no space for the whole + // of this output, don't bother switching terminals at all. + // + if (Avail < (FragLen + 4u)) { + Status = 0; + } else { + _PostTerminalSwitch(pRing, TerminalId); + Status = (int)_WriteBlocking(pRing, s, FragLen); + _PostTerminalSwitch(pRing, _ActiveTerminal); + } + break; + case SEGGER_RTT_MODE_NO_BLOCK_TRIM: + // + // If we are in trim mode and there is not enough space for everything, + // trim the output but always include the terminal switch. If no room + // for terminal switch, skip that totally. + // + if (Avail < 4u) { + Status = -1; + } else { + _PostTerminalSwitch(pRing, TerminalId); + Status = (int)_WriteBlocking(pRing, s, (FragLen < (Avail - 4u)) ? FragLen : (Avail - 4u)); + _PostTerminalSwitch(pRing, _ActiveTerminal); + } + break; + case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: + // + // If we are in blocking mode, output everything. + // + _PostTerminalSwitch(pRing, TerminalId); + Status = (int)_WriteBlocking(pRing, s, FragLen); + _PostTerminalSwitch(pRing, _ActiveTerminal); + break; + default: + Status = -1; + break; + } + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + } else { + Status = -1; + } + return Status; +} + + +/*************************** End of file ****************************/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/include/SEGGER_RTT.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/include/SEGGER_RTT.h new file mode 100644 index 000000000..cdd6270d5 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/include/SEGGER_RTT.h @@ -0,0 +1,238 @@ +/********************************************************************* +* SEGGER MICROCONTROLLER GmbH & Co. KG * +* Solutions for real time microcontroller applications * +********************************************************************** +* * +* (c) 2014 - 2016 SEGGER Microcontroller GmbH & Co. KG * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER RTT * Real Time Transfer for embedded targets * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* * This software may in its unmodified form be freely redistributed * +* in source, linkable, or executable form. * +* * The source code may be modified, provided the source code * +* retains the above copyright notice, this list of conditions and * +* the following disclaimer. * +* * Modified versions of this software in source, executable, or * +* linkable form may not be distributed without prior consent of * +* SEGGER. * +* * This software may only be used for communication with SEGGER * +* J-Link debug probes. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* RTT version: 6.00e * +* * +********************************************************************** +---------------------------END-OF-HEADER------------------------------ +File : SEGGER_RTT.h +Purpose : Implementation of SEGGER real-time transfer which allows + real-time communication on targets which support debugger + memory accesses while the CPU is running. +Revision: $Rev: 4079 $ +---------------------------------------------------------------------- +*/ + +#ifndef SEGGER_RTT_H +#define SEGGER_RTT_H + +#include "SEGGER_RTT_Conf.h" + +/********************************************************************* +* +* Defines, fixed +* +********************************************************************** +*/ + +/********************************************************************* +* +* Types +* +********************************************************************** +*/ + +// +// Description for a circular buffer (also called "ring buffer") +// which is used as up-buffer (T->H) +// +typedef struct { + const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4" + char* pBuffer; // Pointer to start of buffer + unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty. + unsigned WrOff; // Position of next item to be written by either target. + volatile unsigned RdOff; // Position of next item to be read by host. Must be volatile since it may be modified by host. + unsigned Flags; // Contains configuration flags +} SEGGER_RTT_BUFFER_UP; + +// +// Description for a circular buffer (also called "ring buffer") +// which is used as down-buffer (H->T) +// +typedef struct { + const char* sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4" + char* pBuffer; // Pointer to start of buffer + unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this implementation does not fill up the buffer in order to avoid the problem of being unable to distinguish between full and empty. + volatile unsigned WrOff; // Position of next item to be written by host. Must be volatile since it may be modified by host. + unsigned RdOff; // Position of next item to be read by target (down-buffer). + unsigned Flags; // Contains configuration flags +} SEGGER_RTT_BUFFER_DOWN; + +// +// RTT control block which describes the number of buffers available +// as well as the configuration for each buffer +// +// +typedef struct { + char acID[16]; // Initialized to "SEGGER RTT" + int MaxNumUpBuffers; // Initialized to SEGGER_RTT_MAX_NUM_UP_BUFFERS (type. 2) + int MaxNumDownBuffers; // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2) + SEGGER_RTT_BUFFER_UP aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS]; // Up buffers, transferring information up from target via debug probe to host + SEGGER_RTT_BUFFER_DOWN aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS]; // Down buffers, transferring information down from host via debug probe to target +} SEGGER_RTT_CB; + +/********************************************************************* +* +* Global data +* +********************************************************************** +*/ +extern SEGGER_RTT_CB _SEGGER_RTT; + +/********************************************************************* +* +* RTT API functions +* +********************************************************************** +*/ +#ifdef __cplusplus + extern "C" { +#endif +int SEGGER_RTT_AllocDownBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); +int SEGGER_RTT_AllocUpBuffer (const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); +int SEGGER_RTT_ConfigUpBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); +int SEGGER_RTT_ConfigDownBuffer (unsigned BufferIndex, const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags); +int SEGGER_RTT_GetKey (void); +unsigned SEGGER_RTT_HasData (unsigned BufferIndex); +int SEGGER_RTT_HasKey (void); +void SEGGER_RTT_Init (void); +unsigned SEGGER_RTT_Read (unsigned BufferIndex, void* pBuffer, unsigned BufferSize); +unsigned SEGGER_RTT_ReadNoLock (unsigned BufferIndex, void* pData, unsigned BufferSize); +int SEGGER_RTT_SetNameDownBuffer (unsigned BufferIndex, const char* sName); +int SEGGER_RTT_SetNameUpBuffer (unsigned BufferIndex, const char* sName); +int SEGGER_RTT_SetFlagsDownBuffer (unsigned BufferIndex, unsigned Flags); +int SEGGER_RTT_SetFlagsUpBuffer (unsigned BufferIndex, unsigned Flags); +int SEGGER_RTT_WaitKey (void); +unsigned SEGGER_RTT_Write (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_WriteNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_WriteSkipNoLock (unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +unsigned SEGGER_RTT_WriteString (unsigned BufferIndex, const char* s); +void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); +// +// Function macro for performance optimization +// +#define SEGGER_RTT_HASDATA(n) (_SEGGER_RTT.aDown[n].WrOff - _SEGGER_RTT.aDown[n].RdOff) + +/********************************************************************* +* +* RTT "Terminal" API functions +* +********************************************************************** +*/ +int SEGGER_RTT_SetTerminal (char TerminalId); +int SEGGER_RTT_TerminalOut (char TerminalId, const char* s); + +/********************************************************************* +* +* RTT printf functions (require SEGGER_RTT_printf.c) +* +********************************************************************** +*/ +int SEGGER_RTT_printf(unsigned BufferIndex, const char * sFormat, ...); +#ifdef __cplusplus + } +#endif + +/********************************************************************* +* +* Defines +* +********************************************************************** +*/ + +// +// Operating modes. Define behavior if buffer is full (not enough space for entire message) +// +#define SEGGER_RTT_MODE_NO_BLOCK_SKIP (0U) // Skip. Do not block, output nothing. (Default) +#define SEGGER_RTT_MODE_NO_BLOCK_TRIM (1U) // Trim: Do not block, output as much as fits. +#define SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL (2U) // Block: Wait until there is space in the buffer. +#define SEGGER_RTT_MODE_MASK (3U) + +// +// Control sequences, based on ANSI. +// Can be used to control color, and clear the screen +// +#define RTT_CTRL_RESET "" // Reset to default colors +#define RTT_CTRL_CLEAR "" // Clear screen, reposition cursor to top left + +#define RTT_CTRL_TEXT_BLACK "" +#define RTT_CTRL_TEXT_RED "" +#define RTT_CTRL_TEXT_GREEN "" +#define RTT_CTRL_TEXT_YELLOW "" +#define RTT_CTRL_TEXT_BLUE "" +#define RTT_CTRL_TEXT_MAGENTA "" +#define RTT_CTRL_TEXT_CYAN "" +#define RTT_CTRL_TEXT_WHITE "" + +#define RTT_CTRL_TEXT_BRIGHT_BLACK "" +#define RTT_CTRL_TEXT_BRIGHT_RED "" +#define RTT_CTRL_TEXT_BRIGHT_GREEN "" +#define RTT_CTRL_TEXT_BRIGHT_YELLOW "" +#define RTT_CTRL_TEXT_BRIGHT_BLUE "" +#define RTT_CTRL_TEXT_BRIGHT_MAGENTA "" +#define RTT_CTRL_TEXT_BRIGHT_CYAN "" +#define RTT_CTRL_TEXT_BRIGHT_WHITE "" + +#define RTT_CTRL_BG_BLACK "" +#define RTT_CTRL_BG_RED "" +#define RTT_CTRL_BG_GREEN "" +#define RTT_CTRL_BG_YELLOW "" +#define RTT_CTRL_BG_BLUE "" +#define RTT_CTRL_BG_MAGENTA "" +#define RTT_CTRL_BG_CYAN "" +#define RTT_CTRL_BG_WHITE "" + +#define RTT_CTRL_BG_BRIGHT_BLACK "" +#define RTT_CTRL_BG_BRIGHT_RED "" +#define RTT_CTRL_BG_BRIGHT_GREEN "" +#define RTT_CTRL_BG_BRIGHT_YELLOW "" +#define RTT_CTRL_BG_BRIGHT_BLUE "" +#define RTT_CTRL_BG_BRIGHT_MAGENTA "" +#define RTT_CTRL_BG_BRIGHT_CYAN "" +#define RTT_CTRL_BG_BRIGHT_WHITE "" + + +#endif + +/*************************** End of file ****************************/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/include/SEGGER_RTT_Conf.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/include/SEGGER_RTT_Conf.h new file mode 100644 index 000000000..4f7f4cc3c --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/include/SEGGER_RTT_Conf.h @@ -0,0 +1,259 @@ +/********************************************************************* +* SEGGER MICROCONTROLLER GmbH & Co. KG * +* Solutions for real time microcontroller applications * +********************************************************************** +* * +* (c) 2014 - 2016 SEGGER Microcontroller GmbH & Co. KG * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER RTT * Real Time Transfer for embedded targets * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* * This software may in its unmodified form be freely redistributed * +* in source, linkable, or executable form. * +* * The source code may be modified, provided the source code * +* retains the above copyright notice, this list of conditions and * +* the following disclaimer. * +* * Modified versions of this software in source, executable, or * +* linkable form may not be distributed without prior consent of * +* SEGGER. * +* * This software may only be used for communication with SEGGER * +* J-Link debug probes. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 SEGGER Microcontroller 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. * +* * +********************************************************************** +* * +* RTT version: 6.00e * +* * +********************************************************************** +---------------------------------------------------------------------- +File : SEGGER_RTT_Conf.h +Purpose : Implementation of SEGGER real-time transfer (RTT) which + allows real-time communication on targets which support + debugger memory accesses while the CPU is running. +Revision: $Rev: 3892 $ +---------------------------END-OF-HEADER------------------------------ +*/ + +#ifndef SEGGER_RTT_CONF_H +#define SEGGER_RTT_CONF_H + +#ifdef __IAR_SYSTEMS_ICC__ + #include +#endif + +/********************************************************************* +* +* Defines, configurable +* +********************************************************************** +*/ + +#define SEGGER_RTT_MAX_NUM_UP_BUFFERS (3) // Max. number of up-buffers (T->H) available on this target (Default: 3) +#define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (3) // Max. number of down-buffers (H->T) available on this target (Default: 3) + +#define BUFFER_SIZE_UP (64) // Size of the buffer for terminal output of target, up to host (Default: 1k) +#define BUFFER_SIZE_DOWN (16) // Size of the buffer for terminal input to target from host (Usually keyboard input) (Default: 16) + +#define SEGGER_RTT_PRINTF_BUFFER_SIZE (64u) // Size of buffer for RTT printf to bulk-send chars via RTT (Default: 64) + +#define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP // Mode for pre-initialized terminal channel (buffer 0) + +// +// Target is not allowed to perform other RTT operations while string still has not been stored completely. +// Otherwise we would probably end up with a mixed string in the buffer. +// If using RTT from within interrupts, multiple tasks or multi processors, define the SEGGER_RTT_LOCK() and SEGGER_RTT_UNLOCK() function here. +// +// SEGGER_RTT_MAX_INTERRUPT_PRIORITY can be used in the sample lock routines on Cortex-M3/4. +// Make sure to mask all interrupts which can send RTT data, i.e. generate SystemView events, or cause task switches. +// When high-priority interrupts must not be masked while sending RTT data, SEGGER_RTT_MAX_INTERRUPT_PRIORITY needs to be adjusted accordingly. +// (Higher priority = lower priority number) +// Default value for embOS: 128u +// Default configuration in FreeRTOS: configMAX_SYSCALL_INTERRUPT_PRIORITY: ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) +// In case of doubt mask all interrupts: 1 << (8 - BASEPRI_PRIO_BITS) i.e. 1 << 5 when 3 bits are implemented in NVIC +// or define SEGGER_RTT_LOCK() to completely disable interrupts. +// + +#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) // Interrupt priority to lock on SEGGER_RTT_LOCK on Cortex-M3/4 (Default: 0x20) + +/********************************************************************* +* +* RTT lock configuration for SEGGER Embedded Studio, +* Rowley CrossStudio and GCC +*/ +#if (defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__) + #ifdef __ARM_ARCH_6M__ + #define SEGGER_RTT_LOCK() { \ + unsigned int LockState; \ + __asm volatile ("mrs %0, primask \n\t" \ + "mov r1, $1 \n\t" \ + "msr primask, r1 \n\t" \ + : "=r" (LockState) \ + : \ + : "r1" \ + ); + + #define SEGGER_RTT_UNLOCK() __asm volatile ("msr primask, %0 \n\t" \ + : \ + : "r" (LockState) \ + : \ + ); \ + } + + #elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)) + #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY + #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) + #endif + #define SEGGER_RTT_LOCK() { \ + unsigned int LockState; \ + __asm volatile ("mrs %0, basepri \n\t" \ + "mov r1, %1 \n\t" \ + "msr basepri, r1 \n\t" \ + : "=r" (LockState) \ + : "i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY) \ + : "r1" \ + ); + + #define SEGGER_RTT_UNLOCK() __asm volatile ("msr basepri, %0 \n\t" \ + : \ + : "r" (LockState) \ + : \ + ); \ + } + + #elif defined(__ARM_ARCH_7A__) + #define SEGGER_RTT_LOCK() { \ + unsigned int LockState; \ + __asm volatile ("mrs r1, CPSR \n\t" \ + "mov %0, r1 \n\t" \ + "orr r1, r1, #0xC0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : "=r" (LockState) \ + : \ + : "r1" \ + ); + + #define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t" \ + "mrs r1, CPSR \n\t" \ + "bic r1, r1, #0xC0 \n\t" \ + "and r0, r0, #0xC0 \n\t" \ + "orr r1, r1, r0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : \ + : "r" (LockState) \ + : "r0", "r1" \ + ); \ + } +#else + #define SEGGER_RTT_LOCK() + #define SEGGER_RTT_UNLOCK() + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration for IAR EWARM +*/ +#ifdef __ICCARM__ + #if (defined (__ARM6M__) && (__CORE__ == __ARM6M__)) + #define SEGGER_RTT_LOCK() { \ + unsigned int LockState; \ + LockState = __get_PRIMASK(); \ + __set_PRIMASK(1); + + #define SEGGER_RTT_UNLOCK() __set_PRIMASK(LockState); \ + } + #elif ((defined (__ARM7EM__) && (__CORE__ == __ARM7EM__)) || (defined (__ARM7M__) && (__CORE__ == __ARM7M__))) + #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY + #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) + #endif + #define SEGGER_RTT_LOCK() { \ + unsigned int LockState; \ + LockState = __get_BASEPRI(); \ + __set_BASEPRI(SEGGER_RTT_MAX_INTERRUPT_PRIORITY); + + #define SEGGER_RTT_UNLOCK() __set_BASEPRI(LockState); \ + } + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration for IAR RX +*/ +#ifdef __ICCRX__ + #define SEGGER_RTT_LOCK() { \ + unsigned long LockState; \ + LockState = __get_interrupt_state(); \ + __disable_interrupt(); + + #define SEGGER_RTT_UNLOCK() __set_interrupt_state(LockState); \ + } +#endif + +/********************************************************************* +* +* RTT lock configuration for KEIL ARM +*/ +#ifdef __CC_ARM + #if (defined __TARGET_ARCH_6S_M) + #define SEGGER_RTT_LOCK() { \ + unsigned int LockState; \ + register unsigned char PRIMASK __asm( "primask"); \ + LockState = PRIMASK; \ + PRIMASK = 1u; \ + __schedule_barrier(); + + #define SEGGER_RTT_UNLOCK() PRIMASK = LockState; \ + __schedule_barrier(); \ + } + #elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M)) + #ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY + #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) + #endif + #define SEGGER_RTT_LOCK() { \ + unsigned int LockState; \ + register unsigned char BASEPRI __asm( "basepri"); \ + LockState = BASEPRI; \ + BASEPRI = SEGGER_RTT_MAX_INTERRUPT_PRIORITY; \ + __schedule_barrier(); + + #define SEGGER_RTT_UNLOCK() BASEPRI = LockState; \ + __schedule_barrier(); \ + } + #endif +#endif + +/********************************************************************* +* +* RTT lock configuration fallback +*/ +#ifndef SEGGER_RTT_LOCK + #define SEGGER_RTT_LOCK() // Lock RTT (nestable) (i.e. disable interrupts) +#endif + +#ifndef SEGGER_RTT_UNLOCK + #define SEGGER_RTT_UNLOCK() // Unlock RTT (nestable) (i.e. enable previous interrupt lock state) +#endif + +#endif +/*************************** End of file ****************************/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/include/trcStreamingPort.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/include/trcStreamingPort.h new file mode 100644 index 000000000..b1074b424 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/include/trcStreamingPort.h @@ -0,0 +1,196 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * trcStreamingPort.h + * + * The interface definitions for trace streaming ("stream ports"). + * This "stream port" sets up the recorder to use SEGGER RTT as streaming channel. + * + * Note that this stream port is more complex than the typical case, since + * the J-Link interface uses a separate RAM buffer in SEGGER_RTT.c, instead + * of the default buffer included in the recorder core. The other stream ports + * offer more typical examples of how to define a custom streaming interface. + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_STREAMING_PORT_H +#define TRC_STREAMING_PORT_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/******************************************************************************* + * Configuration Macro: TRC_CFG_RTT_BUFFER_SIZE_UP + * + * Defines the size of the "up" RTT buffer (target -> host) to use for writing + * the trace data, for RTT buffer 1 or higher. + * + * This setting is ignored for RTT buffer 0, which can't be reconfigured + * in runtime and therefore hard-coded to use the defines in SEGGER_RTT_Conf.h. + * + * Default buffer size for Tracealyzer is 5000 bytes. + * + * If you have a stand-alone J-Link probe, the can be decreased to around 1 KB. + * But integrated J-Link OB interfaces are slower and needs about 5-10 KB, + * depending on the amount of data produced. + ******************************************************************************/ +#define TRC_CFG_RTT_BUFFER_SIZE_UP 5000 + +/******************************************************************************* + * Configuration Macro: TRC_CFG_RTT_BUFFER_SIZE_DOWN + * + * Defines the size of the "down" RTT buffer (host -> target) to use for reading + * commands from Tracealyzer, for RTT buffer 1 or higher. + * + * Default buffer size for Tracealyzer is 32 bytes. + * + * This setting is ignored for RTT buffer 0, which can't be reconfigured + * in runtime and therefore hard-coded to use the defines in SEGGER_RTT_Conf.h. + ******************************************************************************/ +#define TRC_CFG_RTT_BUFFER_SIZE_DOWN 32 + +/******************************************************************************* + * Configuration Macro: TRC_CFG_RTT_UP_BUFFER_INDEX + * + * Defines the RTT buffer to use for writing the trace data. Make sure that + * the PC application has the same setting (File->Settings). + * + * Default: 1 + * + * We don't recommend using RTT buffer 0, since mainly intended for terminals. + * If you prefer to use buffer 0, it must be configured in SEGGER_RTT_Conf.h. + ******************************************************************************/ +#define TRC_CFG_RTT_UP_BUFFER_INDEX 1 + +/******************************************************************************* + * Configuration Macro: TRC_CFG_RTT_DOWN_BUFFER_INDEX + * + * Defines the RTT buffer to use for reading the trace data. Make sure that + * the PC application has the same setting (File->Settings). + * + * Default: 1 + * + * We don't recommend using RTT buffer 0, since mainly intended for terminals. + * If you prefer to use buffer 0, it must be configured in SEGGER_RTT_Conf.h. + ******************************************************************************/ +#define TRC_CFG_RTT_DOWN_BUFFER_INDEX 1 + +/******************************************************************************* + * TRC_CFG_RTT_MODE + * This stream port for J-Link streaming relies on SEGGER RTT, that contains an + * internal RAM buffer read by the J-Link probes during execution. + * + * Possible values: + * - SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL + * - SEGGER_RTT_MODE_NO_BLOCK_SKIP (default) + * + * Using SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL ensure that you get a + * complete and valid trace. This may however cause blocking if your streaming + * interface isn't fast enough, which may disturb the real-time behavior. + * + * We therefore recommend SEGGER_RTT_MODE_NO_BLOCK_SKIP. In this mode, + * Tracealyzer will report lost events if the transfer is not + * fast enough. In that case, try increasing the size of the "up buffer". + ******************************************************************************/ +#define TRC_CFG_RTT_MODE SEGGER_RTT_MODE_NO_BLOCK_SKIP + +#include "SEGGER_RTT_Conf.h" +#include "SEGGER_RTT.h" + +#if (TRC_CFG_RTT_UP_BUFFER_INDEX >= SEGGER_RTT_MAX_NUM_UP_BUFFERS) +#error "TRC_CFG_RTT_UP_BUFFER_INDEX must be smaller than SEGGER_RTT_MAX_NUM_UP_BUFFERS" +#endif + +#if (TRC_CFG_RTT_DOWN_BUFFER_INDEX >= SEGGER_RTT_MAX_NUM_DOWN_BUFFERS) +#error "TRC_CFG_RTT_DOWN_BUFFER_INDEX must be smaller than SEGGER_RTT_MAX_NUM_DOWN_BUFFERS" +#endif + +/* If index is defined as 0, the internal RTT buffers will be used instead of this. */ +#if TRC_CFG_RTT_UP_BUFFER_INDEX == 0 +#define TRC_RTT_ALLOC_UP() static char* _TzTraceData = NULL; /* Not actually used. Ignore allocation method. */ +#define TRC_STREAM_PORT_MALLOC() /* Static allocation. Not used. */ +#else +#if TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_STATIC +#define TRC_RTT_ALLOC_UP() char _TzTraceData[TRC_CFG_RTT_BUFFER_SIZE_UP]; /* Static allocation */ +#define TRC_STREAM_PORT_MALLOC() /* Static allocation. Not used. */ +#endif +#if TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC +#define TRC_RTT_ALLOC_UP() char* _TzTraceData = NULL; /* Dynamic allocation */ +#define TRC_STREAM_PORT_MALLOC() _TzTraceData = TRC_PORT_MALLOC(TRC_CFG_RTT_BUFFER_SIZE_UP); +#endif +#if TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM +#define TRC_RTT_ALLOC_UP() char* _TzTraceData = NULL; /* Custom allocation, user needs to call vTraceSetRecorderDataBuffer before vTraceEnable, to assign this */ +#define TRC_STREAM_PORT_MALLOC() /* Not used in custom mode */ +#endif +#endif + +/* Down-buffer. If index is defined as 0, the internal RTT buffers will be used instead of this. */ \ +#if TRC_CFG_RTT_DOWN_BUFFER_INDEX == 0 +#define TRC_RTT_ALLOC_DOWN() static char* _TzCtrlData = NULL; /* Not actually used. Ignore allocation method. */ +#else +#define TRC_RTT_ALLOC_DOWN() static char _TzCtrlData[TRC_CFG_RTT_BUFFER_SIZE_DOWN]; /* Always static allocation, since usually small. */ +#endif + +#define TRC_STREAM_PORT_ALLOCATE_FIELDS() \ + TRC_RTT_ALLOC_UP() /* Macro that will result in proper UP buffer allocation */ \ + TRC_RTT_ALLOC_DOWN() /* Macro that will result in proper DOWN buffer allocation */ + +int32_t readFromRTT(void* ptrData, uint32_t size, int32_t* ptrBytesRead); + +int32_t writeToRTT(void* ptrData, uint32_t size, int32_t* ptrBytesWritten); + + +#define TRC_STREAM_PORT_INIT() \ + TRC_STREAM_PORT_MALLOC(); /*Dynamic allocation or empty if static */ \ + SEGGER_RTT_ConfigUpBuffer(TRC_CFG_RTT_UP_BUFFER_INDEX, "TzData", _TzTraceData, TRC_CFG_RTT_BUFFER_SIZE_UP, TRC_CFG_RTT_MODE ); \ + SEGGER_RTT_ConfigDownBuffer(TRC_CFG_RTT_DOWN_BUFFER_INDEX, "TzCtrl", _TzCtrlData, TRC_CFG_RTT_BUFFER_SIZE_DOWN, TRC_CFG_RTT_MODE); + +/* Important for the J-Link port, in most other ports this can be skipped (default is 1) */ +#define TRC_STREAM_PORT_USE_INTERNAL_BUFFER 0 + +#define TRC_STREAM_PORT_WRITE_DATA(_ptrData, _size, _ptrBytesWritten) writeToRTT(_ptrData, _size, _ptrBytesWritten) + +#define TRC_STREAM_PORT_READ_DATA(_ptrData, _size, _ptrBytesRead) readFromRTT(_ptrData, _size, _ptrBytesRead) + +#ifdef __cplusplus +} +#endif + +#endif /* TRC_STREAMING_PORT_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/trcStreamingPort.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/trcStreamingPort.c new file mode 100644 index 000000000..d279f83b9 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/Jlink_RTT/trcStreamingPort.c @@ -0,0 +1,44 @@ + +#include "trcRecorder.h" + +#if (TRC_USE_TRACEALYZER_RECORDER == 1) +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) + +int32_t readFromRTT(void* ptrData, uint32_t size, int32_t* ptrBytesRead) +{ + uint32_t bytesRead = 0; + + if (SEGGER_RTT_HASDATA(TRC_CFG_RTT_DOWN_BUFFER_INDEX)) + { + bytesRead = SEGGER_RTT_Read((TRC_CFG_RTT_DOWN_BUFFER_INDEX), (char*)ptrData, size); + + if (ptrBytesRead != NULL) + *ptrBytesRead = (int32_t)bytesRead; + + if (bytesRead != size) + { + return -1; + } + + } + + return 0; +} + +int32_t writeToRTT(void* ptrData, uint32_t size, int32_t* ptrBytesWritten) +{ + uint32_t bytesWritten = SEGGER_RTT_Write((TRC_CFG_RTT_UP_BUFFER_INDEX), (const char*)ptrData, size); + + if (ptrBytesWritten != NULL) + *ptrBytesWritten = (int32_t)bytesWritten; + + if (bytesWritten != size) + { + return -1; + } + + return 0; +} + +#endif +#endif diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/TCPIP/Readme-Streamport.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/TCPIP/Readme-Streamport.txt new file mode 100644 index 000000000..f8f097baa --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/TCPIP/Readme-Streamport.txt @@ -0,0 +1,22 @@ +Tracealyzer Stream Port for TCP/IP (lwIP example) +------------------------------------------------- + +This directory contains a "stream port" for the Tracealyzer recorder library, +i.e., the specific code needed to use a particular interface for streaming a +Tracealyzer RTOS trace. The stream port is defined by a set of macros in +trcStreamingPort.h, found in the "include" directory. + +This particular stream port targets TCP/IP. This example assumes lwIP but is +easy to modify for other TCP/IP stacks. + +To use this stream port, make sure that include/trcStreamingPort.h is found +by the compiler (i.e., add this folder to your project's include paths) and +add all included source files to your build. Make sure no other versions of +trcStreamingPort.h are included by mistake! + +Note that lwIP is not included, but assumed to exist in the project already. + +See also http://percepio.com/2016/10/05/rtos-tracing. + +Percepio AB +www.percepio.com \ No newline at end of file diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/TCPIP/include/trcStreamingPort.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/TCPIP/include/trcStreamingPort.h new file mode 100644 index 000000000..51e52e862 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/TCPIP/include/trcStreamingPort.h @@ -0,0 +1,66 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * trcStreamingPort.h + * + * The interface definitions for trace streaming ("stream ports"). + * This "stream port" sets up the recorder to use TCP/IP as streaming channel. + * The example is for lwIP. + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_STREAMING_PORT_H +#define TRC_STREAMING_PORT_H + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t trcTcpRead(void* data, uint32_t size, int32_t *ptrBytesRead); + +int32_t trcTcpWrite(void* data, uint32_t size, int32_t *ptrBytesWritten); + +#define TRC_STREAM_PORT_READ_DATA(_ptrData, _size, _ptrBytesRead) trcTcpRead(_ptrData, _size, _ptrBytesRead) + +#define TRC_STREAM_PORT_WRITE_DATA(_ptrData, _size, _ptrBytesSent) trcTcpWrite(_ptrData, _size, _ptrBytesSent) + +#ifdef __cplusplus +} +#endif + +#endif /* TRC_STREAMING_PORT_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/TCPIP/trcStreamingPort.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/TCPIP/trcStreamingPort.c new file mode 100644 index 000000000..d420d121a --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/TCPIP/trcStreamingPort.c @@ -0,0 +1,186 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * trcStreamingPort.c + * + * Supporting functions for trace streaming, used by the "stream ports" + * for reading and writing data to the interface. + * Existing ports can easily be modified to fit another setup, e.g., a + * different TCP/IP stack, or to define your own stream port. + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#include "trcRecorder.h" + +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) +#if (TRC_USE_TRACEALYZER_RECORDER == 1) + +/* TCP/IP includes - for lwIP in this case */ +#include "lwip/tcpip.h" +#include "lwip/sockets.h" + +int errno; + +#define TRC_TCPIP_PORT 12000 + +int sock = -1, new_sd = -1; +int flags = 0; +int remoteSize; +struct sockaddr_in address, remote; + +int32_t trcSocketSend( void* data, int32_t size, int32_t* bytesWritten ) +{ + if (new_sd < 0) + return -1; + + if (bytesWritten == NULL) + return -1; + + *bytesWritten = send( new_sd, data, size, 0 ); + if (*bytesWritten < 0) + { + /* EWOULDBLOCK may be expected when buffers are full */ + if (errno != 0 && errno != EWOULDBLOCK) + { + closesocket(new_sd); + new_sd = -1; + return -1; + } + else + *bytesWritten = 0; + } + + return 0; +} + +int32_t trcSocketReceive( void* data, int32_t size, int32_t* bytesRead ) +{ + if (new_sd < 0) + return -1; + + *bytesRead = recv( new_sd, data, size, 0 ); + if ( *bytesRead < 0 ) + { + /* EWOULDBLOCK may be expected when there is no data to receive */ + if (errno != 0 && errno != EWOULDBLOCK) + { + closesocket(new_sd); + new_sd = -1; + return -1; + } + else + *bytesRead = 0; + } + + return 0; +} + +int32_t trcSocketInitializeListener() +{ + if (sock >= 0) + return 0; + + sock = lwip_socket(AF_INET, SOCK_STREAM, 0); + + if (sock < 0) + return -1; + + address.sin_family = AF_INET; + address.sin_port = htons( TRC_TCPIP_PORT ); + address.sin_addr.s_addr = INADDR_ANY; + + if (bind(sock, (struct sockaddr *)&address, sizeof (address)) < 0) + { + closesocket(sock); + sock = -1; + return -1; + } + + if (lwip_listen(sock, 5) < 0) + { + closesocket(sock); + sock = -1; + return -1; + } + + return 0; +} + +int32_t trcSocketAccept() +{ + if (sock < 0) + return -1; + + if (new_sd >= 0) + return 0; + + remoteSize = sizeof( remote ); + new_sd = accept( sock, (struct sockaddr *)&remote, (socklen_t*)&remoteSize ); + + flags = fcntl( new_sd, F_GETFL, 0 ); + fcntl( new_sd, F_SETFL, flags | O_NONBLOCK ); + + if( new_sd < 0 ) + { + closesocket(new_sd); + new_sd = -1; + closesocket(sock); + sock = -1; + return -1; + } + + return 0; +} +/************** MODIFY THE ABOVE PART TO USE YOUR TPC/IP STACK ****************/ + +int32_t trcTcpWrite(void* data, uint32_t size, int32_t *ptrBytesWritten) +{ + return trcSocketSend(data, size, ptrBytesWritten); +} + +int32_t trcTcpRead(void* data, uint32_t size, int32_t *ptrBytesRead) +{ + trcSocketInitializeListener(); + + trcSocketAccept(); + + return trcSocketReceive(data, size, ptrBytesRead); +} + +#endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/ +#endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/USB_CDC/Readme-Streamport.txt b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/USB_CDC/Readme-Streamport.txt new file mode 100644 index 000000000..260f12ace --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/USB_CDC/Readme-Streamport.txt @@ -0,0 +1,27 @@ +Tracealyzer Stream Port for USB CDC (STM32 example) +--------------------------------------------------- + +This directory contains a "stream port" for the Tracealyzer recorder library, +i.e., the specific code needed to use a particular interface for streaming a +Tracealyzer RTOS trace. The stream port is defined by a set of macros in +trcStreamingPort.h, found in the "include" directory. + +This particular stream port targets USB CDC. This is an example for the STM32 USB +stack (from the STM32CubeMX code generation tool, v1.4.1) and has been tested on +a STM32F767ZI device on a Nucleo board. See this blog post: + +http://percepio.com/2017/02/03/usb-trace-streaming-st-nucleo-f767zi-board/ + +However, it should be straight-forward to modify this for other USB stacks. + +To use this stream port, make sure that include/trcStreamingPort.h is found +by the compiler (i.e., add this folder to your project's include paths) and +add all included source files to your build. Make sure no other versions of +trcStreamingPort.h are included by mistake! + +Note that the USB stack not included, but assumed to exist in the project already. + +See also http://percepio.com/2016/10/05/rtos-tracing. + +Percepio AB +www.percepio.com \ No newline at end of file diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/USB_CDC/include/trcStreamingPort.h b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/USB_CDC/include/trcStreamingPort.h new file mode 100644 index 000000000..6940b4d6d --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/USB_CDC/include/trcStreamingPort.h @@ -0,0 +1,83 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * trcStreamingPort.h + * + * The interface definitions for trace streaming ("stream ports"). + * This "stream port" sets up the recorder to use USB CDC as streaming channel. + * The example is for STM32 using STM32Cube. + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#ifndef TRC_STREAMING_PORT_H +#define TRC_STREAMING_PORT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Include files as needed, in this case it is files from STM32Cube FW_F7 V1.4.1 */ +#include "usb_device.h" +#include "usbd_cdc.h" +#include "usbd_CDC_if.h" +#include "usb_device.h" + +/* Tested on STM32 devices using Keil/CMSIS USB stack */ + +extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS; + +uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len); + +int32_t trcCDCReceive(void *data, uint32_t size, int32_t* NumBytes); + +int32_t trcCDCTransmit(void* data, uint32_t size, int32_t * noOfBytesSent ); + +#define TRC_STREAM_PORT_INIT() \ + MX_USB_DEVICE_Init(); \ + TRC_STREAM_PORT_MALLOC(); /*Dynamic allocation or empty if static */ + +#define TRC_STREAM_PORT_READ_DATA(_ptrData, _size, _ptrBytesRead) trcCDCReceive(_ptrData, _size, _ptrBytesRead) + +#define TRC_STREAM_PORT_WRITE_DATA(_ptrData, _size, _ptrBytesSent) trcCDCTransmit(_ptrData, _size, _ptrBytesSent) + + +#ifdef __cplusplus +} +#endif + +#endif /* TRC_STREAMING_PORT_H */ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/USB_CDC/trcStreamingPort.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/USB_CDC/trcStreamingPort.c new file mode 100644 index 000000000..800022a1b --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/streamports/USB_CDC/trcStreamingPort.c @@ -0,0 +1,246 @@ + +#include "trcRecorder.h" + +#if (TRC_USE_TRACEALYZER_RECORDER == 1) +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) + +#include "stdint.h" + +/* Include files as needed, in this case it is files from STM32Cube FW_F7 V1.4.1 */ +#include "usb_device.h" +#include "usbd_cdc.h" +#include "usbd_CDC_if.h" +#include "usb_device.h" + +#define BUFSIZE 64 + +typedef struct{ + uint32_t idx; + uint8_t data[BUFSIZE]; +}recBuf; + +/* Define size for the receive and transmit buffer over CDC */ +#define APP_RX_DATA_SIZE 8 +#define APP_TX_DATA_SIZE 64 + +/* Received Data over USB are stored in this buffer */ +uint8_t UserRxBufferFS[APP_RX_DATA_SIZE]; + +/* Send Data over USB CDC are stored in this buffer */ +uint8_t UserTxBufferFS[APP_TX_DATA_SIZE]; + +extern USBD_HandleTypeDef hUsbDeviceFS; + +extern PCD_HandleTypeDef hpcd_USB_OTG_FS; + +recBuf commandBuffer; + +static int8_t CDC_Init_FS (void); +static int8_t CDC_DeInit_FS (void); +static int8_t CDC_Control_FS (uint8_t cmd, uint8_t* pbuf, uint16_t length); +static int8_t CDC_Receive_FS (uint8_t* pbuf, uint32_t *Len); + +USBD_CDC_ItfTypeDef USBD_Interface_fops_FS = +{ + CDC_Init_FS, + CDC_DeInit_FS, + CDC_Control_FS, + CDC_Receive_FS +}; + +/* Private functions ---------------------------------------------------------*/ +/** + * @brief CDC_Init_FS + * Initializes the CDC media low layer over the FS USB IP + * @param None + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_Init_FS(void) +{ + /* Set Application Buffers */ + USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0); + USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); + return (USBD_OK); +} + +/** + * @brief CDC_DeInit_FS + * DeInitializes the CDC media low layer + * @param None + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_DeInit_FS(void) +{ + return (USBD_OK); +} + +/** + * @brief CDC_Control_FS + * Manage the CDC class requests + * @param cmd: Command code + * @param pbuf: Buffer containing command data (request parameters) + * @param length: Number of data to be sent (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_Control_FS (uint8_t cmd, uint8_t* pbuf, uint16_t length) +{ + switch (cmd) + { + case CDC_SEND_ENCAPSULATED_COMMAND: + break; + + case CDC_GET_ENCAPSULATED_RESPONSE: + break; + + case CDC_SET_COMM_FEATURE: + break; + + case CDC_GET_COMM_FEATURE: + break; + + case CDC_CLEAR_COMM_FEATURE: + break; + + /*******************************************************************************/ + /* Line Coding Structure */ + /*-----------------------------------------------------------------------------*/ + /* Offset | Field | Size | Value | Description */ + /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/ + /* 4 | bCharFormat | 1 | Number | Stop bits */ + /* 0 - 1 Stop bit */ + /* 1 - 1.5 Stop bits */ + /* 2 - 2 Stop bits */ + /* 5 | bParityType | 1 | Number | Parity */ + /* 0 - None */ + /* 1 - Odd */ + /* 2 - Even */ + /* 3 - Mark */ + /* 4 - Space */ + /* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */ + /*******************************************************************************/ + case CDC_SET_LINE_CODING: + break; + + case CDC_GET_LINE_CODING: + break; + + case CDC_SET_CONTROL_LINE_STATE: + break; + + case CDC_SEND_BREAK: + break; + + default: + break; + } + return (USBD_OK); +} + +/** + * @brief CDC_Receive_FS + * Data received over USB OUT endpoint are sent over CDC interface + * through this function. + * + * @note + * This function will block any OUT packet reception on USB endpoint + * until exiting this function. If you exit this function before transfer + * is complete on CDC interface (i.e. using DMA controller) it will result + * in receiving more data while previous ones are still not sent. + * + * @param Buf: Buffer of data to be received + * @param Len: Number of data received (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL + */ +static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) +{ + for( uint32_t i=0;i<* Len;i++) + { + commandBuffer.data[commandBuffer.idx]=Buf[i]; + commandBuffer.idx++; + } + USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); + USBD_CDC_ReceivePacket(&hUsbDeviceFS); + + return (USBD_OK); +} + +/** + * @brief CDC_Transmit_FS + * Data send over USB IN endpoint are sent over CDC interface + * through this function. + * @note + * + * + * @param Buf: Buffer of data to be send + * @param Len: Number of data to be send (in bytes) + * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY + */ +uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) +{ + uint8_t result = USBD_OK; + USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData; + if (hcdc->TxState != 0){ + return USBD_BUSY; + } + USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len); + result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); + return result; +} + +/* The READ function, used in trcStreamingPort.h */ +int32_t trcCDCReceive(void *data, uint32_t size, int32_t* NumBytes) +{ + uint32_t i,diff; + + if(commandBuffer.idx>0) + { + if (size >= commandBuffer.idx) // more than what is stored, number of bytes will be .idx + { + memcpy(data,commandBuffer.data, commandBuffer.idx); + *NumBytes=commandBuffer.idx; + commandBuffer.idx=0; // Make the buffer ready for a new command + } + else //If some data in the buffer is not read + { + diff = commandBuffer.idx-size; + memcpy(data,commandBuffer.data, size); + for(i=0;i v4.1.5 + +- Fixed a bug in the ITM stream port, that required Port 0 to be enabled. +- Added missing include of stdio.h (needed by vTraceConsoleChannelPrintF). +- Moved standard includes from trcRecorder.h into the .c files needing them. + +------------------------------------------------------------------------------- + +Changes, v4.1.2 -> v4.1.4 + +- Fixed a compile error when certain FreeRTOS settings were used +- Disabled filter support for FreeRTOS v7.3 since it uses "char" for object id + +------------------------------------------------------------------------------- + +Changes, v4.1.0 -> v4.1.2 + +- Added vTraceConsoleChannelPrintF(...) + +------------------------------------------------------------------------------- + +Changes, v4.0.3 -> v4.1.0 + +- Improved performance of User Events +- Fixed handling of format strings ending with '%' +- Improved handling of creative user configuration macros + +------------------------------------------------------------------------------- + +Changes, v4.0.2 -> v4.0.3 + +- Minor fix for TCP/IP stream port. +- Corrected default RTT mode setting. + +------------------------------------------------------------------------------- + +Changes, v4.0.1 -> v4.0.2 + +- Memory allocation trace events now ignore filters. + +------------------------------------------------------------------------------- + +Changes, v4.0.0 -> v4.0.1 + +- Minor fixes to default values. + +------------------------------------------------------------------------------- + +Changes, v3.3.0 -> v4.0.0 + +- Fixed some issues with filters. + +------------------------------------------------------------------------------- + +Changes, v3.2.0 -> v3.3.0 + +- Added support for FreeRTOS v10, including the new object types Message Buffer + and Stream Buffer. + +- Improved the object-level filtering to also support Timer, Event Group, + Message Buffer and Stream Buffer objects. + +- Fixed a few remaining build problems with older FreeRTOS versions (v7.x). + +- vTraceStoreISRBegin now reports an error on invalid handles, i.e., if the + initialization of the handle (xTraceSetISRProperties) had not been made. + +------------------------------------------------------------------------------- + +Changes, v3.1.2 -> v3.2.0 + +- Added new filtering system - that works in both snapshot and streaming mode. + Filtering was previously not supported in streaming mode, but can be very + useful for slower streaming interfaces. By exluding irrelevant events, the + amount of data produced can be reduced a lot. + + * New functions vTraceSetFilterGroup and vTraceSetFilterMask allows for + excluding all events from specific objects (like a semaphore or queue). + + * Added new "generic" filters (preprocessor level) to trcConfig.h, that + exclude all events of a particular types. + - TRC_CFG_INCLUDE_NOTIFY_EVENTS + - TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS + - TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS + - TRC_CFG_INCLUDE_TIMER_EVENTS + + * Upgraded some previous filters from "Snapshot only" to the Common API + and thereby moved them from trcSnapshotConfig.h to trcConfig.h. + - TRC_CFG_SCHEDULING_ONLY + - TRC_CFG_INCLUDE_MEMMANG_EVENTS + - TRC_CFG_INCLUDE_USER_EVENTS + - TRC_CFG_INCLUDE_ISR_TRACING + - TRC_CFG_INCLUDE_READY_EVENTS + - TRC_CFG_INCLUDE_OSTICK_EVENTS + + * Removed the old filter system from trcSnapshotRecorder.c. + +- Improved streaming interface - Now only two (2) macros are needed to be + defined in most cases, read and write. This makes it a lot easier to make + custom stream ports. + + * Many definitions that were identical in most stream ports, have been + replaced by default definitions in the recorder core. If needed, they + can be overriden by custom definitions in trcStreamingPort.h. + + * Stream ports are now assumed to use recorder's internal event buffer. + Other stream ports that writes directly to the streaming interface + (like J-Link) should define TRC_STREAM_PORT_USE_INTERNAL_BUFFER + as zero (0) to make it work correctly. + + * Macro TRC_STREAM_PORT_PERIODIC_SEND_DATA has been replaced by + TRC_STREAM_PORT_WRITE_DATA. Together with TRC_STREAM_PORT_READ_DATA, + this is all that is necessary for a typical stream port. + + * Return values from the stream port macros READ_DATA and WRITE_DATA are + now checked. Expects 0 on success, anything else produces a warning + that can be retrived using xTraceGetLastError() and also seen in + Tracealyzer if a trace was produced. + + * Stream ports should no longer call prvPagedEventBufferInit explicitly + (e.g. in TRC_STREAM_PORT_ON_TRACE_BEGIN). This is now called + automatically if TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1. + + * Macros TRC_STREAM_PORT_ON_TRACE_BEGIN and TRC_STREAM_PORT_ON_TRACE_END + are now unused by default and don't need to be defined. + You can however use them to hook in some own function at these events. + +- Added two new stream ports + + * TCPIP-Win32: allows for testing the streaming on Windows ports of your + RTOS, using Winsock. + + * File: example of streaming to a local file system (tested on Windows, + but easy to modify). + +- Added support for FreeRTOS v9.0.1 + + * Replaced FreeRTOS version code TRC_FREERTOS_VERSION_9_X with + - TRC_FREERTOS_VERSION_9_0_0 + - TRC_FREERTOS_VERSION_9_0_1 + + * Using TRC_FREERTOS_VERSION_9_X is no longer allowed. + +- Added additional events for xQueuePeek, for blocking and timeouts events. + +- Added event for traceTIMER_EXPIRED, showing when the timer callback + function is called. + +- Improved diagnostics in streaming mode, in case of errors in the recorder. + + * Added prvTraceWarning() - registers a "warning" error code, without + stopping the recorder. Called if READ_DATA or WRITE_DATA returns a + non-zero value, and in several other cases where the recorder + configuration is incorrect (e.g., too small symbol table). + + * Added several new warning codes (PSF_WARNING_XYZ), corresponding to the + issues detected by prvCheckRecorderStatus. + + * Fixed duplicate definitions of warning messages, so the warnings reported + to Tracealyzer are the same as those provided in xTraceGetLastError(). + + * Added better explainations of warning/error messages in the body of + xTraceGetLastError (in streaming mode). + +- Added xTraceIsRecordingEnabled() to Common API. + +- Added "unofficial" hardware port for Altera Nios-II. + This is a user contribition, not yet verified by Percerpio. + +- Fixed bug in vTraceEnable - option TRC_START_AWAIT_HOST was ignored if already initialized. + +- Fixed a few remaining compiler warnings. + +- Changed order of some settings in trcConfig.h - moved advanced stuff to the + bottom. + +- Removed SEGGER_RTT_Printf.c from the J-Link stream port since not required + for Tracealyzer. + +------------------------------------------------------------------------------- + +Changes, v3.1.1 -> v3.1.2 +- Fixed two bugs related to User Events, one in vTracePrintF and other in vTracePrint. + +- Fixed a build problem related to a single reference of the old FreeRTOS type "xTaskHandle", in trcKernelPort.c. + Changed to "TaskHandle_t", unless if using an older FreeRTOS kernel or the "compatibility mode". + +- Removed traceCREATE_MUTEX hook for FreeRTOS v9 or later (no longer required) + +- Updated the User Manual regarding snapshot trace via IAR Embedded Workbench. + +- Renamed vTraceGetTraceBuffer to xTraceGetTraceBuffer, since returning a pointer. + +------------------------------------------------------------------------------- + +Changes, v3.1.0 -> v3.1.1 + +After the major changes in the v3.1.0 trace recorder library, this update +corrects a number of minor issues. Only minor functional improvements. + +- You can now use TRC_ALLOC_CUSTOM_BUFFER to declare a trace buffer on a custom + location (using linker directives). + The related function vTraceSetRecorderDataBuffer has been promoted to the + Common API (previously only supported in snapshot mode, but custom allocation + is now generally supported also in streaming mode). + +- Removed TRC_CFG_USE_LINKER_PRAGMA. No longer necessary thanks to the custom + allocation mode. + +- Added support for timestamping from custom periodic timers, required for + accurate timestamping on Cortex-M0/M0+ devices when using tickless idle. + Only for streaming mode so far. See TRC_CUSTOM_TIMER_INCR / DECR. + +- ARM Cortex-M port: Made sure the DWT unit is initialized properly, in case + the debugger doesn't handle this. + +- ARM Cortex-M port: Added possibility to use Systick timestamping also on + Cortex-M3/M4/M7 devices (that otherwise use DWT timestamping by default). + To use this option, define the macro TRC_CFG_ARM_CM_USE_SYSTICK. + +- J-Link streaming: The default RTT buffer has been changed from 0 to 1. + +- J-Link streaming: The RTT buffer settings for buffer 1 and higher, are now + found in trcStreamingPort.h. Note: These settings don't apply to buffer 0. + +- vTracePrint has been optimized for better performance in string logging. + +- Minor performance improvement related to symbol table transfer in streaming mode. + +- Timer names now registered also in streaming mode. + +- Timer start and stop event are now traced. + +- Implemented support for queue registry (traceQUEUE_REGISTRY_ADD) also for streaming. + +- Fixed a bug related to repeated calls of vTraceEnable. + +- Fixed a bug where task-switches seemed to occur even though the scheduler was disabled. + +- Renamed HARDWARE_PORT_TEXAS_INSTRUMENTS_TMS570_RM48, added prefix TRC. + +- Fixed several language issues in the comments and documentation. + +- Fixed several minor issues and warnings from different compilers + (including PowerPC/gcc) and configurations. + +------------------------------------------------------------------------------- + +Changes, v3.0.9 -> v3.1.0 + +- Merge of previously separated snapshot and streaming recorders into a single + recorder supporting both streaming and snapshot as different modes. + +- New common API for supporting both streaming and snapshot modes. + +- New integration guide, see the User Manual. + +- Major improvement of API documentation in source files and User Manual. + +- New concept of "stream ports", giving a better structure defining streaming + interfaces, and restructured the J-Link and TCP/IP streaming as stream ports. + +- Added a stream port for USB CDC connections, with STM32 as example. + Since Tracealyzer now can receive serial data on Windows COM ports, this is + really easy to use. + +- Added a warning (#error) for cases where FreeRTOS tickless idle mode is used + together with timestamping using SysTick or other periodic interrupt timers, + Tracing with tickless idle requires an independent time source to correctly + capture the length of the idle periods. + +- Major changes in the recorder API. Important examples are: + + * Some configuration macros have changed names, e.g. for "hardware port". + Make sure to remove any old "trcConfig.h" files if upgrading from an + earlier version! + + * Recorder configuration in trcConfig.h has been minimized and now only + includes the important settings that are independent of recorder mode. + Advanced settings for each mode are found in trcSnapshotConfig.h and + trcStreamingConfig.h. + + * vTraceEnable replaces Trace_Init and vTraceInitTraceData, as well as + vTraceStart and uiTraceStart. + + * vTraceStop now part of the common API and thereby available also in + streaming. And since vTraceEnable can start the streaming directly + you have the option control the tracing from target, e.g., for + streaming to a device file system. + + * vTraceStoreKernelObjectName from old streaming recorder has been replaced + by vTraceSetQueueName, vTraceSetSemaphoreName, etc. + + * vTraceSetISRProperties now returns a "traceHandle" that should be passed as + parameter to vTraceStoreISRBegin and vTraceStoreISREnd. + + * xTraceRegisterString has replaced the old functions xTraceOpenLabel and + vTraceStoreUserEventChannelName. This now returns a "traceString" for use + as "channel" parameter in vTracePrintF, and in other places where strings + are stored. + + * Removed vTraceStoreISREndManual and vTraceStoreISREndAuto, use + vTraceStoreISREnd instead. + + * Renamed the functions for saving User Events in a separate buffer: + - xTraceRegisterChannelFormat -> xTraceRegisterUBChannel + - vTraceChannelPrintF -> vTraceUBData + - vTraceChannelUserEvent -> vTraceUBEvent + + +------------------------------------------------------------------------------- +Copyright Percepio AB, 2018. \ No newline at end of file diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/trcKernelPort.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/trcKernelPort.c new file mode 100644 index 000000000..d41b52687 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/trcKernelPort.c @@ -0,0 +1,833 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * trcKernelPort.c + * + * The FreeRTOS-specific parts of the trace recorder + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#include "FreeRTOS.h" + +#if (!defined(TRC_USE_TRACEALYZER_RECORDER) && configUSE_TRACE_FACILITY == 1) +#error Trace Recorder: You need to include trcRecorder.h at the end of your FreeRTOSConfig.h! +#endif + +#if (defined(TRC_USE_TRACEALYZER_RECORDER) && TRC_USE_TRACEALYZER_RECORDER == 1) + +#ifndef TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS + /* TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS is missing in trcConfig.h. */ +#error "TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS must be defined in trcConfig.h." +#endif + +#ifndef TRC_CFG_INCLUDE_TIMER_EVENTS + /* TRC_CFG_INCLUDE_TIMER_EVENTS is missing in trcConfig.h. */ +#error "TRC_CFG_INCLUDE_TIMER_EVENTS must be defined in trcConfig.h." +#endif + +#ifndef TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS + /* TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS is missing in trcConfig.h. */ +#error "TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS must be defined in trcConfig.h." +#endif + +#ifndef TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS + /* TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS is missing in trcConfig.h. Define this as 1 if using FreeRTOS v10 or later and like to trace stream buffer or message buffer events, otherwise 0. */ +#error "TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS must be defined in trcConfig.h." +#endif + +#if (configUSE_TICKLESS_IDLE != 0 && (TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR)) + /* + The below error message is to alert you on the following issue: + + The hardware port selected in trcConfig.h uses the operating system timer for the + timestamping, i.e., the periodic interrupt timer that drives the OS tick interrupt. + + When using "tickless idle" mode, the recorder needs an independent time source in + order to correctly record the durations of the idle times. Otherwise, the trace may appear + to have a different length than in reality, and the reported CPU load is also affected. + + You may override this warning by defining the TRC_CFG_ACKNOWLEDGE_TICKLESS_IDLE_WARNING + macro in your trcConfig.h file. But then the time scale may be incorrect during + tickless idle periods. + + To get this correct, override the default timestamping by setting TRC_CFG_HARDWARE_PORT + in trcConfig.h to TRC_HARDWARE_PORT_APPLICATION_DEFINED and define the HWTC macros + accordingly, using a free running counter or an independent periodic interrupt timer. + See trcHardwarePort.h for details. + + For ARM Cortex-M3, M4 and M7 MCUs this is not an issue, since the recorder uses the + DWT cycle counter for timestamping in these cases. + */ + + #ifndef TRC_CFG_ACKNOWLEDGE_TICKLESS_IDLE_WARNING + #error Trace Recorder: This timestamping mode is not recommended with Tickless Idle. + #endif +#endif /* (configUSE_TICKLESS_IDLE != 0 && (TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR)) */ + +#include "task.h" +#include "queue.h" + +#if (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) +/* If the project does not include the FreeRTOS timers, TRC_CFG_INCLUDE_TIMER_EVENTS must be set to 0 */ +#include "timers.h" +#endif /* (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) */ + +#if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) +/* If the project does not include the FreeRTOS event groups, TRC_CFG_INCLUDE_TIMER_EVENTS must be set to 0 */ +#include "event_groups.h" +#endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) */ + +#if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +/* If the project does not include the FreeRTOS stream buffers, TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS must be set to 0 */ +#include "stream_buffer.h" +#endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +uint32_t prvTraceGetQueueNumber(void* handle); + +#if (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_8_X) + +extern unsigned char ucQueueGetQueueNumber( xQueueHandle pxQueue ); +extern void vQueueSetQueueNumber( xQueueHandle pxQueue, unsigned char ucQueueNumber ); +extern unsigned char ucQueueGetQueueType( xQueueHandle pxQueue ); + +uint32_t prvTraceGetQueueNumber(void* handle) +{ + return (uint32_t)ucQueueGetQueueNumber(handle); +} +#else +uint32_t prvTraceGetQueueNumber(void* handle) +{ + return (uint32_t)uxQueueGetQueueNumber(handle); +} +#endif /* (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_8_X) */ + +uint8_t prvTraceGetQueueType(void* handle) +{ + // This is either declared in header file in FreeRTOS 8 and later, or as extern above + return ucQueueGetQueueType(handle); +} + +/* Tasks */ +uint16_t prvTraceGetTaskNumberLow16(void* handle) +{ + return TRACE_GET_LOW16(uxTaskGetTaskNumber(handle)); +} + +uint16_t prvTraceGetTaskNumberHigh16(void* handle) +{ + return TRACE_GET_HIGH16(uxTaskGetTaskNumber(handle)); +} + +void prvTraceSetTaskNumberLow16(void* handle, uint16_t value) +{ + vTaskSetTaskNumber(handle, TRACE_SET_LOW16(uxTaskGetTaskNumber(handle), value)); +} + +void prvTraceSetTaskNumberHigh16(void* handle, uint16_t value) +{ + vTaskSetTaskNumber(handle, TRACE_SET_HIGH16(uxTaskGetTaskNumber(handle), value)); +} + +uint16_t prvTraceGetQueueNumberLow16(void* handle) +{ + return TRACE_GET_LOW16(prvTraceGetQueueNumber(handle)); +} + +uint16_t prvTraceGetQueueNumberHigh16(void* handle) +{ + return TRACE_GET_HIGH16(prvTraceGetQueueNumber(handle)); +} + +void prvTraceSetQueueNumberLow16(void* handle, uint16_t value) +{ + vQueueSetQueueNumber(handle, TRACE_SET_LOW16(prvTraceGetQueueNumber(handle), value)); +} + +void prvTraceSetQueueNumberHigh16(void* handle, uint16_t value) +{ + vQueueSetQueueNumber(handle, TRACE_SET_HIGH16(prvTraceGetQueueNumber(handle), value)); +} + +#if (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) + +uint16_t prvTraceGetTimerNumberLow16(void* handle) +{ + return TRACE_GET_LOW16(uxTimerGetTimerNumber(handle)); +} + +uint16_t prvTraceGetTimerNumberHigh16(void* handle) +{ + return TRACE_GET_HIGH16(uxTimerGetTimerNumber(handle)); +} + +void prvTraceSetTimerNumberLow16(void* handle, uint16_t value) +{ + vTimerSetTimerNumber(handle, TRACE_SET_LOW16(uxTimerGetTimerNumber(handle), value)); +} + +void prvTraceSetTimerNumberHigh16(void* handle, uint16_t value) +{ + vTimerSetTimerNumber(handle, TRACE_SET_HIGH16(uxTimerGetTimerNumber(handle), value)); +} +#endif /* (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) + +uint16_t prvTraceGetEventGroupNumberLow16(void* handle) +{ + return TRACE_GET_LOW16(uxEventGroupGetNumber(handle)); +} + +uint16_t prvTraceGetEventGroupNumberHigh16(void* handle) +{ + return TRACE_GET_HIGH16(uxEventGroupGetNumber(handle)); +} + +void prvTraceSetEventGroupNumberLow16(void* handle, uint16_t value) +{ + vEventGroupSetNumber(handle, TRACE_SET_LOW16(uxEventGroupGetNumber(handle), value)); +} + +void prvTraceSetEventGroupNumberHigh16(void* handle, uint16_t value) +{ + vEventGroupSetNumber(handle, TRACE_SET_HIGH16(uxEventGroupGetNumber(handle), value)); +} +#endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) + +uint16_t prvTraceGetStreamBufferNumberLow16(void* handle) +{ + return TRACE_GET_LOW16(uxStreamBufferGetStreamBufferNumber(handle)); +} + +uint16_t prvTraceGetStreamBufferNumberHigh16(void* handle) +{ + return TRACE_GET_HIGH16(uxStreamBufferGetStreamBufferNumber(handle)); +} + +void prvTraceSetStreamBufferNumberLow16(void* handle, uint16_t value) +{ + vStreamBufferSetStreamBufferNumber(handle, TRACE_SET_LOW16(uxStreamBufferGetStreamBufferNumber(handle), value)); +} + +void prvTraceSetStreamBufferNumberHigh16(void* handle, uint16_t value) +{ + vStreamBufferSetStreamBufferNumber(handle, TRACE_SET_HIGH16(uxStreamBufferGetStreamBufferNumber(handle), value)); +} +#endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) + +static void* pCurrentTCB = NULL; +#if (defined(configENABLE_BACKWARD_COMPATIBILITY) && configENABLE_BACKWARD_COMPATIBILITY == 0) +/* We're explicitly not using compatibility mode */ +static TaskHandle_t HandleTzCtrl = NULL; /* TzCtrl task TCB */ +#else +/* We're using compatibility mode, or we're running an old kernel */ +static xTaskHandle HandleTzCtrl = NULL; /* TzCtrl task TCB */ +#endif + +#if defined(configSUPPORT_STATIC_ALLOCATION) +#if (configSUPPORT_STATIC_ALLOCATION == 1) +static StackType_t stackTzCtrl[TRC_CFG_CTRL_TASK_STACK_SIZE]; +static StaticTask_t tcbTzCtrl; +#endif +#endif + +/* Monitored by TzCtrl task, that give warnings as User Events */ +extern volatile uint32_t NoRoomForSymbol; +extern volatile uint32_t NoRoomForObjectData; +extern volatile uint32_t LongestSymbolName; +extern volatile uint32_t MaxBytesTruncated; + +/* Keeps track of previous values, to only react on changes. */ +static uint32_t NoRoomForSymbol_last = 0; +static uint32_t NoRoomForObjectData_last = 0; +static uint32_t LongestSymbolName_last = 0; +static uint32_t MaxBytesTruncated_last = 0; + +/* User Event Channel for giving warnings regarding NoRoomForSymbol etc. */ +traceString trcWarningChannel; + +#define TRC_PORT_MALLOC(size) pvPortMalloc(size) + +TRC_STREAM_PORT_ALLOCATE_FIELDS() + +/* Called by TzCtrl task periodically (Normally every 100 ms) */ +static void prvCheckRecorderStatus(void); + +extern void prvTraceWarning(int errCode); + +/* The TzCtrl task - receives commands from Tracealyzer (start/stop) */ +static portTASK_FUNCTION( TzCtrl, pvParameters ); + +/******************************************************************************* + * vTraceEnable + * + * Function that enables the tracing and creates the control task. It will halt + * execution until a Start command has been received if haltUntilStart is true. + * + ******************************************************************************/ +void vTraceEnable(int startOption) +{ + int32_t bytes = 0; + int32_t status; + extern uint32_t RecorderEnabled; + TracealyzerCommandType msg; + + /* Only do this first time...*/ + if (HandleTzCtrl == NULL) + { + TRC_STREAM_PORT_INIT(); + + /* Note: Requires that TRC_CFG_INCLUDE_USER_EVENTS is 1. */ + trcWarningChannel = xTraceRegisterString("Warnings from Recorder"); + + /* Creates the TzCtrl task - receives trace commands (start, stop, ...) */ + #if defined(configSUPPORT_STATIC_ALLOCATION) && (configSUPPORT_STATIC_ALLOCATION == 1) + HandleTzCtrl = xTaskCreateStatic(TzCtrl, STRING_CAST("TzCtrl"), TRC_CFG_CTRL_TASK_STACK_SIZE, NULL, TRC_CFG_CTRL_TASK_PRIORITY, stackTzCtrl, &tcbTzCtrl); + #else + xTaskCreate( TzCtrl, STRING_CAST("TzCtrl"), TRC_CFG_CTRL_TASK_STACK_SIZE, NULL, TRC_CFG_CTRL_TASK_PRIORITY, &HandleTzCtrl ); + #endif + + if (HandleTzCtrl == NULL) + { + prvTraceError(PSF_ERROR_TZCTRLTASK_NOT_CREATED); + } + } + + if (startOption == TRC_START_AWAIT_HOST) + { + /* We keep trying to read commands until the recorder has been started */ + do + { + bytes = 0; + + status = TRC_STREAM_PORT_READ_DATA(&msg, sizeof(TracealyzerCommandType), (int32_t*)&bytes); + + if (status != 0) + { + prvTraceWarning(PSF_WARNING_STREAM_PORT_READ); + } + + if ((status == 0) && (bytes == sizeof(TracealyzerCommandType))) + { + if (prvIsValidCommand(&msg)) + { + if (msg.cmdCode == CMD_SET_ACTIVE && msg.param1 == 1) + { + /* On start, init and reset the timestamping */ + TRC_PORT_SPECIFIC_INIT(); + } + + prvProcessCommand(&msg); + } + } + } + while (RecorderEnabled == 0); + } + else if (startOption == TRC_START) + { + /* We start streaming directly - this assumes that the interface is ready! */ + TRC_PORT_SPECIFIC_INIT(); + + msg.cmdCode = CMD_SET_ACTIVE; + msg.param1 = 1; + prvProcessCommand(&msg); + } + else + { + /* On TRC_INIT */ + TRC_PORT_SPECIFIC_INIT(); + } +} + +#if (TRC_CFG_SCHEDULING_ONLY == 0) +/******************************************************************************* + * vTraceSetQueueName(void* object, const char* name) + * + * Parameter object: pointer to the Queue that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for Queue objects for display in Tracealyzer. + ******************************************************************************/ +void vTraceSetQueueName(void* object, const char* name) +{ + vTraceStoreKernelObjectName(object, name); +} + +/******************************************************************************* + * vTraceSetSemaphoreName(void* object, const char* name) + * + * Parameter object: pointer to the Semaphore that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for Semaphore objects for display in Tracealyzer. + ******************************************************************************/ +void vTraceSetSemaphoreName(void* object, const char* name) +{ + vTraceStoreKernelObjectName(object, name); +} + +/******************************************************************************* + * vTraceSetMutexName(void* object, const char* name) + * + * Parameter object: pointer to the Mutex that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for Mutex objects for display in Tracealyzer. + ******************************************************************************/ +void vTraceSetMutexName(void* object, const char* name) +{ + vTraceStoreKernelObjectName(object, name); +} + +#if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) +/******************************************************************************* +* vTraceSetEventGroupName(void* object, const char* name) +* +* Parameter object: pointer to the vTraceSetEventGroupName that shall be named +* Parameter name: the name to set (const string literal) +* +* Sets a name for EventGroup objects for display in Tracealyzer. +******************************************************************************/ +void vTraceSetEventGroupName(void* object, const char* name) +{ + vTraceStoreKernelObjectName(object, name); +} +#endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) */ + +#if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +/******************************************************************************* +* vTraceSetStreamBufferName(void* object, const char* name) +* +* Parameter object: pointer to the StreamBuffer that shall be named +* Parameter name: the name to set (const string literal) +* +* Sets a name for StreamBuffer objects for display in Tracealyzer. +******************************************************************************/ +void vTraceSetStreamBufferName(void* object, const char* name) +{ + vTraceStoreKernelObjectName(object, name); +} + +/******************************************************************************* +* vTraceSetMessageBufferName(void* object, const char* name) +* +* Parameter object: pointer to the MessageBuffer that shall be named +* Parameter name: the name to set (const string literal) +* +* Sets a name for MessageBuffer objects for display in Tracealyzer. +******************************************************************************/ +void vTraceSetMessageBufferName(void* object, const char* name) +{ + vTraceStoreKernelObjectName(object, name); +} +#endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#endif /* (TRC_CFG_SCHEDULING_ONLY == 0) */ + +/******************************************************************************* + * prvGetCurrentTaskHandle + * + * Function that returns the handle to the currently executing task. + * + ******************************************************************************/ +void* prvTraceGetCurrentTaskHandle(void) +{ + return xTaskGetCurrentTaskHandle(); +} + +/******************************************************************************* + * prvIsNewTCB + * + * Tells if this task is already executing, or if there has been a task-switch. + * Assumed to be called within a trace hook in kernel context. + ******************************************************************************/ +uint32_t prvIsNewTCB(void* pNewTCB) +{ + if (pCurrentTCB != pNewTCB) + { + pCurrentTCB = pNewTCB; + return 1; + } + return 0; +} + +/******************************************************************************* + * prvTraceIsSchedulerSuspended + * + * Returns true if the RTOS scheduler currently is disabled, thus preventing any + * task-switches from occurring. Only called from vTraceStoreISREnd. + ******************************************************************************/ +unsigned char prvTraceIsSchedulerSuspended(void) +{ + /* Assumed to be available in FreeRTOS. According to the FreeRTOS docs, + INCLUDE_xTaskGetSchedulerState or configUSE_TIMERS must be set to 1 in + FreeRTOSConfig.h for this function to be available. */ + + return xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED; +} + + +/******************************************************************************* + * prvCheckRecorderStatus + * + * Called by TzCtrl task periodically (every 100 ms - seems reasonable). + * Checks a number of diagnostic variables and give warnings as user events, + * in most cases including a suggested solution. + ******************************************************************************/ +static void prvCheckRecorderStatus(void) +{ + if (NoRoomForSymbol > NoRoomForSymbol_last) + { + if (NoRoomForSymbol > 0) + { + prvTraceWarning(PSF_WARNING_SYMBOL_TABLE_SLOTS); + } + NoRoomForSymbol_last = NoRoomForSymbol; + } + + if (NoRoomForObjectData > NoRoomForObjectData_last) + { + if (NoRoomForObjectData > 0) + { + prvTraceWarning(PSF_WARNING_OBJECT_DATA_SLOTS); + } + NoRoomForObjectData_last = NoRoomForObjectData; + } + + if (LongestSymbolName > LongestSymbolName_last) + { + if (LongestSymbolName > (TRC_CFG_SYMBOL_MAX_LENGTH)) + { + prvTraceWarning(PSF_WARNING_SYMBOL_MAX_LENGTH); + } + LongestSymbolName_last = LongestSymbolName; + } + + if (MaxBytesTruncated > MaxBytesTruncated_last) + { + if (MaxBytesTruncated > 0) + { + prvTraceWarning(PSF_WARNING_STRING_TOO_LONG); + } + MaxBytesTruncated_last = MaxBytesTruncated; + } +} + +/******************************************************************************* + * TzCtrl + * + * Task for sending the trace data from the internal buffer to the stream + * interface (assuming TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1) and for + * receiving commands from Tracealyzer. Also does some diagnostics. + ******************************************************************************/ +static portTASK_FUNCTION( TzCtrl, pvParameters ) +{ + TracealyzerCommandType msg; + int32_t bytes = 0; + int32_t status = 0; + (void)pvParameters; + + while (1) + { + do + { + /* Listen for new commands */ + bytes = 0; + status = TRC_STREAM_PORT_READ_DATA(&msg, sizeof(TracealyzerCommandType), (int32_t*)&bytes); + + if (status != 0) + { + prvTraceWarning(PSF_WARNING_STREAM_PORT_READ); + } + + if ((status == 0) && (bytes == sizeof(TracealyzerCommandType))) + { + if (prvIsValidCommand(&msg)) + { + prvProcessCommand(&msg); /* Start or Stop currently... */ + } + } + +/* If the internal buffer is disabled, the COMMIT macro instead sends the data directly + from the "event functions" (using TRC_STREAM_PORT_WRITE_DATA). */ +#if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1) + /* If there is a buffer page, this sends it to the streaming interface using TRC_STREAM_PORT_WRITE_DATA. */ + bytes = prvPagedEventBufferTransfer(); +#endif + + /* If there was data sent or received (bytes != 0), loop around and repeat, if there is more data to send or receive. + Otherwise, step out of this loop and sleep for a while. */ + + } while (bytes != 0); + + prvCheckRecorderStatus(); + + vTaskDelay(TRC_CFG_CTRL_TASK_DELAY); + } +} + +#endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/ + + +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) + +/* Internal flag to tell the context of tracePEND_FUNC_CALL_FROM_ISR */ +int uiInEventGroupSetBitsFromISR = 0; + +/****************************************************************************** + * TraceQueueClassTable + * Translates a FreeRTOS QueueType into trace objects classes (TRACE_CLASS_). + * Has one entry for each QueueType, gives TRACE_CLASS ID. + ******************************************************************************/ +traceObjectClass TraceQueueClassTable[5] = { + TRACE_CLASS_QUEUE, + TRACE_CLASS_MUTEX, + TRACE_CLASS_SEMAPHORE, + TRACE_CLASS_SEMAPHORE, + TRACE_CLASS_MUTEX +}; + +#if (TRC_CFG_SCHEDULING_ONLY == 0) +/******************************************************************************* + * vTraceSetQueueName(void* object, const char* name) + * + * Parameter object: pointer to the Queue that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for Queue objects for display in Tracealyzer. + ******************************************************************************/ +void vTraceSetQueueName(void* object, const char* name) +{ + prvTraceSetObjectName(TRACE_CLASS_QUEUE, TRACE_GET_OBJECT_NUMBER(QUEUE, object), name); +} + +/******************************************************************************* + * vTraceSetSemaphoreName(void* object, const char* name) + * + * Parameter object: pointer to the Semaphore that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for Semaphore objects for display in Tracealyzer. + ******************************************************************************/ +void vTraceSetSemaphoreName(void* object, const char* name) +{ + prvTraceSetObjectName(TRACE_CLASS_SEMAPHORE, TRACE_GET_OBJECT_NUMBER(QUEUE, object), name); +} + +/******************************************************************************* + * vTraceSetMutexName(void* object, const char* name) + * + * Parameter object: pointer to the Mutex that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for Semaphore objects for display in Tracealyzer. + ******************************************************************************/ +void vTraceSetMutexName(void* object, const char* name) +{ + prvTraceSetObjectName(TRACE_CLASS_MUTEX, TRACE_GET_OBJECT_NUMBER(QUEUE, object), name); +} + +#if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) +/******************************************************************************* +* vTraceSetEventGroupName(void* object, const char* name) +* +* Parameter object: pointer to the EventGroup that shall be named +* Parameter name: the name to set (const string literal) +* +* Sets a name for EventGroup objects for display in Tracealyzer. +******************************************************************************/ +void vTraceSetEventGroupName(void* object, const char* name) +{ + prvTraceSetObjectName(TRACE_CLASS_EVENTGROUP, TRACE_GET_OBJECT_NUMBER(EVENTGROUP, object), name); +} +#endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) */ + +#if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) +/******************************************************************************* +* vTraceSetStreamBufferName(void* object, const char* name) +* +* Parameter object: pointer to the StreamBuffer that shall be named +* Parameter name: the name to set (const string literal) +* +* Sets a name for StreamBuffer objects for display in Tracealyzer. +******************************************************************************/ +void vTraceSetStreamBufferName(void* object, const char* name) +{ + prvTraceSetObjectName(TRACE_CLASS_STREAMBUFFER, TRACE_GET_OBJECT_NUMBER(STREAMBUFFER, object), name); +} + +/******************************************************************************* +* vTraceSetMessageBufferName(void* object, const char* name) +* +* Parameter object: pointer to the MessageBuffer that shall be named +* Parameter name: the name to set (const string literal) +* +* Sets a name for MessageBuffer objects for display in Tracealyzer. +******************************************************************************/ +void vTraceSetMessageBufferName(void* object, const char* name) +{ + prvTraceSetObjectName(TRACE_CLASS_MESSAGEBUFFER, TRACE_GET_OBJECT_NUMBER(STREAMBUFFER, object), name); +} +#endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */ + +#endif /* (TRC_CFG_SCHEDULING_ONLY == 0) */ + +void* prvTraceGetCurrentTaskHandle() +{ + return xTaskGetCurrentTaskHandle(); +} + +/* Initialization of the object property table */ +void vTraceInitObjectPropertyTable() +{ + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectClasses = TRACE_NCLASSES; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[0] = TRC_CFG_NQUEUE; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[1] = TRC_CFG_NSEMAPHORE; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[2] = TRC_CFG_NMUTEX; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[3] = TRC_CFG_NTASK; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[4] = TRC_CFG_NISR; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[5] = TRC_CFG_NTIMER; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[6] = TRC_CFG_NEVENTGROUP; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[7] = TRC_CFG_NSTREAMBUFFER; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[8] = TRC_CFG_NMESSAGEBUFFER; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[0] = TRC_CFG_NAME_LEN_QUEUE; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[1] = TRC_CFG_NAME_LEN_SEMAPHORE; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[2] = TRC_CFG_NAME_LEN_MUTEX; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[3] = TRC_CFG_NAME_LEN_TASK; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[4] = TRC_CFG_NAME_LEN_ISR; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[5] = TRC_CFG_NAME_LEN_TIMER; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[6] = TRC_CFG_NAME_LEN_EVENTGROUP; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[7] = TRC_CFG_NAME_LEN_STREAMBUFFER; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[8] = TRC_CFG_NAME_LEN_MESSAGEBUFFER; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[0] = PropertyTableSizeQueue; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[1] = PropertyTableSizeSemaphore; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[2] = PropertyTableSizeMutex; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[3] = PropertyTableSizeTask; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[4] = PropertyTableSizeISR; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[5] = PropertyTableSizeTimer; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[6] = PropertyTableSizeEventGroup; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[7] = PropertyTableSizeStreamBuffer; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[8] = PropertyTableSizeMessageBuffer; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[0] = StartIndexQueue; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[1] = StartIndexSemaphore; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[2] = StartIndexMutex; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[3] = StartIndexTask; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[4] = StartIndexISR; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[5] = StartIndexTimer; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[6] = StartIndexEventGroup; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[7] = StartIndexStreamBuffer; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[8] = StartIndexMessageBuffer; + RecorderDataPtr->ObjectPropertyTable.ObjectPropertyTableSizeInBytes = TRACE_OBJECT_TABLE_SIZE; +} + +/* Initialization of the handle mechanism, see e.g, prvTraceGetObjectHandle */ +void vTraceInitObjectHandleStack() +{ + objectHandleStacks.indexOfNextAvailableHandle[0] = objectHandleStacks.lowestIndexOfClass[0] = 0; + objectHandleStacks.indexOfNextAvailableHandle[1] = objectHandleStacks.lowestIndexOfClass[1] = (TRC_CFG_NQUEUE); + objectHandleStacks.indexOfNextAvailableHandle[2] = objectHandleStacks.lowestIndexOfClass[2] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE); + objectHandleStacks.indexOfNextAvailableHandle[3] = objectHandleStacks.lowestIndexOfClass[3] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX); + objectHandleStacks.indexOfNextAvailableHandle[4] = objectHandleStacks.lowestIndexOfClass[4] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK); + objectHandleStacks.indexOfNextAvailableHandle[5] = objectHandleStacks.lowestIndexOfClass[5] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR); + objectHandleStacks.indexOfNextAvailableHandle[6] = objectHandleStacks.lowestIndexOfClass[6] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER); + objectHandleStacks.indexOfNextAvailableHandle[7] = objectHandleStacks.lowestIndexOfClass[7] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER) + (TRC_CFG_NEVENTGROUP); + objectHandleStacks.indexOfNextAvailableHandle[8] = objectHandleStacks.lowestIndexOfClass[8] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER) + (TRC_CFG_NEVENTGROUP) + (TRC_CFG_NSTREAMBUFFER); + + objectHandleStacks.highestIndexOfClass[0] = (TRC_CFG_NQUEUE) - 1; + objectHandleStacks.highestIndexOfClass[1] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) - 1; + objectHandleStacks.highestIndexOfClass[2] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) - 1; + objectHandleStacks.highestIndexOfClass[3] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) - 1; + objectHandleStacks.highestIndexOfClass[4] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) - 1; + objectHandleStacks.highestIndexOfClass[5] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER) - 1; + objectHandleStacks.highestIndexOfClass[6] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER) + (TRC_CFG_NEVENTGROUP) - 1; + objectHandleStacks.highestIndexOfClass[7] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER) + (TRC_CFG_NEVENTGROUP) + (TRC_CFG_NSTREAMBUFFER) - 1; + objectHandleStacks.highestIndexOfClass[8] = (TRC_CFG_NQUEUE) + (TRC_CFG_NSEMAPHORE) + (TRC_CFG_NMUTEX) + (TRC_CFG_NTASK) + (TRC_CFG_NISR) + (TRC_CFG_NTIMER) + (TRC_CFG_NEVENTGROUP) + (TRC_CFG_NSTREAMBUFFER) + (TRC_CFG_NMESSAGEBUFFER) - 1; +} + +/* Returns the "Not enough handles" error message for this object class */ +const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass) +{ + switch(objectclass) + { + case TRACE_CLASS_TASK: + return "Not enough TASK handles - increase TRC_CFG_NTASK in trcSnapshotConfig.h"; + case TRACE_CLASS_ISR: + return "Not enough ISR handles - increase TRC_CFG_NISR in trcSnapshotConfig.h"; + case TRACE_CLASS_SEMAPHORE: + return "Not enough SEMAPHORE handles - increase TRC_CFG_NSEMAPHORE in trcSnapshotConfig.h"; + case TRACE_CLASS_MUTEX: + return "Not enough MUTEX handles - increase TRC_CFG_NMUTEX in trcSnapshotConfig.h"; + case TRACE_CLASS_QUEUE: + return "Not enough QUEUE handles - increase TRC_CFG_NQUEUE in trcSnapshotConfig.h"; + case TRACE_CLASS_TIMER: + return "Not enough TIMER handles - increase TRC_CFG_NTIMER in trcSnapshotConfig.h"; + case TRACE_CLASS_EVENTGROUP: + return "Not enough EVENTGROUP handles - increase TRC_CFG_NEVENTGROUP in trcSnapshotConfig.h"; + case TRACE_CLASS_STREAMBUFFER: + return "Not enough STREAMBUFFER handles - increase TRC_CFG_NSTREAMBUFFER in trcSnapshotConfig.h"; + case TRACE_CLASS_MESSAGEBUFFER: + return "Not enough MESSAGEBUFFER handles - increase TRC_CFG_NMESSAGEBUFFER in trcSnapshotConfig.h"; + default: + return "pszTraceGetErrorHandles: Invalid objectclass!"; + } +} + +/******************************************************************************* + * prvTraceIsSchedulerSuspended + * + * Returns true if the RTOS scheduler currently is disabled, thus preventing any + * task-switches from occurring. Only called from vTraceStoreISREnd. + ******************************************************************************/ +#if (TRC_CFG_INCLUDE_ISR_TRACING == 1) +unsigned char prvTraceIsSchedulerSuspended(void) +{ + /* Assumed to be available in FreeRTOS. According to the FreeRTOS docs, + INCLUDE_xTaskGetSchedulerState or configUSE_TIMERS must be set to 1 in + FreeRTOSConfig.h for this function to be available. */ + + return xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED; +} +#endif + +#endif /* Snapshot mode */ + +#endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/trcSnapshotRecorder.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/trcSnapshotRecorder.c new file mode 100644 index 000000000..9eec9d2ed --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/trcSnapshotRecorder.c @@ -0,0 +1,3105 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * trcSnapshotRecorder.c + * + * The generic core of the trace recorder's snapshot mode. + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#include "trcRecorder.h" + +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) + +#if (TRC_USE_TRACEALYZER_RECORDER == 1) + +#include +#include +#include + +#if ((TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR)) + #error "CUSTOM timestamping mode is not (yet) supported in snapshot mode!" +#endif + +/* DO NOT CHANGE */ +#define TRACE_MINOR_VERSION 5 +#if (TRC_CFG_INCLUDE_ISR_TRACING == 1) +static traceHandle isrstack[TRC_CFG_MAX_ISR_NESTING]; +int32_t isPendingContextSwitch = 0; +#endif /* (TRC_CFG_INCLUDE_ISR_TRACING == 1) */ + +#if !defined TRC_CFG_INCLUDE_READY_EVENTS || TRC_CFG_INCLUDE_READY_EVENTS == 1 +static int readyEventsEnabled = 1; +#endif /*!defined TRC_CFG_INCLUDE_READY_EVENTS || TRC_CFG_INCLUDE_READY_EVENTS == 1*/ + +/******************************************************************************* + * uiTraceTickCount + * + * This variable is should be updated by the Kernel tick interrupt. This does + * not need to be modified when developing a new timer port. It is preferred to + * keep any timer port changes in the HWTC macro definitions, which typically + * give sufficient flexibility. + ******************************************************************************/ +uint32_t uiTraceTickCount = 0; + +uint32_t trace_disable_timestamp = 0; + +static uint32_t last_timestamp = 0; + +/* Flag that shows if inside a critical section of the recorder */ +volatile int recorder_busy = 0; + +/* Holds the value set by vTraceSetFrequency */ +uint32_t timestampFrequency = 0; + +/* The last error message of the recorder. NULL if no error message. */ +const char* traceErrorMessage = NULL; + +int8_t nISRactive = 0; + +traceHandle handle_of_last_logged_task = 0; + +/* Called when the recorder is stopped, set by vTraceSetStopHook. */ +TRACE_STOP_HOOK vTraceStopHookPtr = (TRACE_STOP_HOOK)0; + +uint16_t CurrentFilterMask = 0xFFFF; + +uint16_t CurrentFilterGroup = FilterGroup0; + +extern int8_t nISRactive; + +extern traceHandle handle_of_last_logged_task; + +/*************** Private Functions *******************************************/ +static void prvStrncpy(char* dst, const char* src, uint32_t maxLength); +static uint8_t prvTraceGetObjectState(uint8_t objectclass, traceHandle id); +static void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength); +static void* prvTraceNextFreeEventBufferSlot(void); +static uint16_t prvTraceGetDTS(uint16_t param_maxDTS); +static traceString prvTraceOpenSymbol(const char* name, traceString userEventChannel); +static void prvTraceUpdateCounters(void); + +void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, int32_t signed_size); + +#if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER) +static void prvCheckDataToBeOverwrittenForMultiEntryEvents(uint8_t nEntries); +#endif + +static traceString prvTraceCreateSymbolTableEntry(const char* name, + uint8_t crc6, + uint8_t len, + traceString channel); + +static traceString prvTraceLookupSymbolTableEntry(const char* name, + uint8_t crc6, + uint8_t len, + traceString channel); + + +#if (TRC_CFG_INCLUDE_ISR_TRACING == 0) +/* ISR tracing is turned off */ +void prvTraceIncreaseISRActive(void); +void prvTraceDecreaseISRActive(void); +#endif /*(TRC_CFG_INCLUDE_ISR_TRACING == 0)*/ + +#if (TRC_CFG_USE_16BIT_OBJECT_HANDLES == 1) +static uint8_t prvTraceGet8BitHandle(traceHandle handle); +#else +#define prvTraceGet8BitHandle(x) ((uint8_t)x) +#endif + + +#if (TRC_CFG_INCLUDE_MEMMANG_EVENTS == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) +static uint32_t heapMemUsage = 0; +#endif + +#if (TRC_CFG_SCHEDULING_ONLY == 0) +static uint32_t prvTraceGetParam(uint32_t, uint32_t); +#endif + +/******************************************************************************* + * prvTraceInitTraceData + * + * Allocates and initializes the recorder data structure, based on the constants + * in trcConfig.h. This allows for allocating the data on the heap, instead of + * using a static declaration. + ******************************************************************************/ +static void prvTraceInitTraceData(void); + +/******************************************************************************* + * prvTracePortGetTimeStamp + * + * Returns the current time based on the HWTC macros which provide a hardware + * isolation layer towards the hardware timer/counter. + * + * The HWTC macros and prvTracePortGetTimeStamp is the main porting issue + * or the trace recorder library. Typically you should not need to change + * the code of prvTracePortGetTimeStamp if using the HWTC macros. + * + ******************************************************************************/ +void prvTracePortGetTimeStamp(uint32_t *puiTimestamp); + +static void prvTraceTaskInstanceFinish(int8_t direct); + +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) +static void vTracePrintF_Helper(traceString eventLabel, const char* formatStr, va_list vl); + +#if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1) +static void vTraceUBData_Helper(traceUBChannel channelPair, va_list vl); +static void prvTraceUBHelper1(traceUBChannel channel, traceString eventLabel, traceString formatLabel, va_list vl); +static void prvTraceUBHelper2(traceUBChannel channel, uint32_t* data, uint32_t noOfSlots); +#endif /*(TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)*/ +#endif /* ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) */ + +/********* Public Functions **************************************************/ + +uint16_t uiIndexOfObject(traceHandle objecthandle, uint8_t objectclass); + +/******************************************************************************* + * prvTraceError + * + * Called by various parts in the recorder. Stops the recorder and stores a + * pointer to an error message, which is printed by the monitor task. + ******************************************************************************/ +void prvTraceError(const char* msg); + +/****************************************************************************** +* vTraceEnable(int startOption) - snapshot mode +* +* Initializes and optionally starts the trace, depending on the start option. +* To use the trace recorder, the startup must call vTraceEnable before any RTOS +* calls are made (including "create" calls). Three start options are provided: +* +* TRC_START: Starts the tracing directly. In snapshot mode this allows for +* starting the trace at any point in your code, assuming vTraceEnable(TRC_INIT) +* has been called in the startup. +* Can also be used for streaming without Tracealyzer control, e.g. to a local +* flash file system (assuming such a "stream port", see trcStreamingPort.h). +* +* TRC_INIT: Initializes the trace recorder, but does not start the tracing. +* In snapshot mode, this must be followed by a vTraceEnable(TRC_START) sometime +* later. +* +* Usage examples, in snapshot mode: +* +* Snapshot trace, from startup: +* +* vTraceEnable(TRC_START); +* +* +* Snapshot trace, from a later point: +* +* vTraceEnable(TRC_INIT); +* +* ... +* vTraceEnable(TRC_START); // e.g., in task context, at some relevant event +* +* +* Note: See other implementation of vTraceEnable in trcStreamingRecorder.c +******************************************************************************/ +void vTraceEnable(int startOption) +{ + prvTraceInitTraceData(); + + if (startOption == TRC_START) + { + vTraceStart(); + } + else if (startOption == TRC_START_AWAIT_HOST) + { + prvTraceError("vTraceEnable(TRC_START_AWAIT_HOST) not allowed in Snapshot mode"); + } + else if (startOption != TRC_INIT) + { + prvTraceError("Unexpected argument to vTraceEnable (snapshot mode)"); + } +} + +/******************************************************************************* + * vTraceSetRecorderDataBuffer + * + * If custom allocation is used, this function must be called so the recorder + * library knows where to save the trace data. + ******************************************************************************/ +#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM) +void vTraceSetRecorderDataBuffer(void* pRecorderData) +{ + TRACE_ASSERT(pRecorderData != NULL, "vTraceSetRecorderDataBuffer, pRecorderData == NULL", TRC_UNUSED); + RecorderDataPtr = pRecorderData; +} +#endif + +/******************************************************************************* + * vTraceSetStopHook + * + * Sets a function to be called when the recorder is stopped. This can be used + * to save the trace to a file system, if available. This is only implemented + * for snapshot mode. + ******************************************************************************/ +void vTraceSetStopHook(TRACE_STOP_HOOK stopHookFunction) +{ + vTraceStopHookPtr = stopHookFunction; +} + +/******************************************************************************* + * vTraceClear + * + * Resets the recorder. Only necessary if a restart is desired - this is not + * needed in the startup initialization. + ******************************************************************************/ +void vTraceClear(void) +{ + TRACE_ALLOC_CRITICAL_SECTION(); + trcCRITICAL_SECTION_BEGIN(); + RecorderDataPtr->absTimeLastEventSecond = 0; + RecorderDataPtr->absTimeLastEvent = 0; + RecorderDataPtr->nextFreeIndex = 0; + RecorderDataPtr->numEvents = 0; + RecorderDataPtr->bufferIsFull = 0; + traceErrorMessage = NULL; + RecorderDataPtr->internalErrorOccured = 0; + (void)memset(RecorderDataPtr->eventData, 0, RecorderDataPtr->maxEvents * 4); + handle_of_last_logged_task = 0; + trcCRITICAL_SECTION_END(); +} + +/******************************************************************************* + * uiTraceStart + * + * Starts the recorder. The recorder will not be started if an error has been + * indicated using prvTraceError, e.g. if any of the Nx constants in trcConfig.h + * has a too small value (TRC_CFG_NTASK, TRC_CFG_NQUEUE, etc). + * + * Returns 1 if the recorder was started successfully. + * Returns 0 if the recorder start was prevented due to a previous internal + * error. In that case, check xTraceGetLastError to get the error message. + * Any error message is also presented when opening a trace file. + * + * This function is obsolete, but has been saved for backwards compatibility. + * We recommend using vTraceEnable instead. + ******************************************************************************/ +uint32_t uiTraceStart(void) +{ + traceHandle handle; + TRACE_ALLOC_CRITICAL_SECTION(); + + handle = 0; + + if (RecorderDataPtr == NULL) + { + TRACE_ASSERT(RecorderDataPtr != NULL, "Recorder not initialized. Use vTraceEnable() instead!", 0); + return 0; + } + + if (RecorderDataPtr->recorderActive == 1) + return 1; /* Already running */ + + if (traceErrorMessage == NULL) + { + trcCRITICAL_SECTION_BEGIN(); + RecorderDataPtr->recorderActive = 1; + + handle = TRACE_GET_TASK_NUMBER(TRACE_GET_CURRENT_TASK()); + if (handle == 0) + { + /* This occurs if the scheduler is not yet started. + This creates a dummy "(startup)" task entry internally in the + recorder */ + handle = prvTraceGetObjectHandle(TRACE_CLASS_TASK); + prvTraceSetObjectName(TRACE_CLASS_TASK, handle, "(startup)"); + + prvTraceSetPriorityProperty(TRACE_CLASS_TASK, handle, 0); + } + + prvTraceStoreTaskswitch(handle); /* Register the currently running task */ + trcCRITICAL_SECTION_END(); + } + + return RecorderDataPtr->recorderActive; +} + +/******************************************************************************* + * vTraceStart + * + * Starts the recorder. The recorder will not be started if an error has been + * indicated using prvTraceError, e.g. if any of the Nx constants in trcConfig.h + * has a too small value (TRC_CFG_NTASK, TRC_CFG_NQUEUE, etc). + * + * This function is obsolete, but has been saved for backwards compatibility. + * We recommend using vTraceEnable instead. + ******************************************************************************/ +void vTraceStart(void) +{ + (void)uiTraceStart(); +} + +/******************************************************************************* + * vTraceStop + * + * Stops the recorder. The recording can be resumed by calling vTraceStart. + * This does not reset the recorder. Use vTraceClear if that is desired. + ******************************************************************************/ +void vTraceStop(void) +{ + if (RecorderDataPtr != NULL) + { + RecorderDataPtr->recorderActive = 0; + } + + if (vTraceStopHookPtr != (TRACE_STOP_HOOK)0) + { + (*vTraceStopHookPtr)(); /* An application call-back function. */ + } +} + +/******************************************************************************* +* xTraceIsRecordingEnabled +* Returns true (1) if the recorder is enabled (i.e. is recording), otherwise 0. +******************************************************************************/ +int xTraceIsRecordingEnabled(void) +{ + if (RecorderDataPtr != NULL) + { + return (int)RecorderDataPtr->recorderActive; + } + else + { + return 0; + } +} + +/******************************************************************************* + * xTraceGetLastError + * + * Gives the last error message, if any. NULL if no error message is stored. + * Any error message is also presented when opening a trace file. + ******************************************************************************/ +const char* xTraceGetLastError(void) +{ + return traceErrorMessage; +} + +/******************************************************************************* +* vTraceClearError +* +* Removes any previous error message generated by recorder calling prvTraceError. +* By calling this function, it may be possible to start/restart the trace +* despite errors in the recorder, but there is no guarantee that the trace +* recorder will work correctly in that case, depending on the type of error. +******************************************************************************/ +void vTraceClearError(void) +{ + traceErrorMessage = NULL; + if (RecorderDataPtr != NULL) + { + RecorderDataPtr->internalErrorOccured = 0; + } +} + +/******************************************************************************* + * xTraceGetTraceBuffer + * + * Returns a pointer to the recorder data structure. Use this together with + * uiTraceGetTraceBufferSize if you wish to implement an own store/upload + * solution, e.g., in case a debugger connection is not available for uploading + * the data. + ******************************************************************************/ +void* xTraceGetTraceBuffer(void) +{ + return RecorderDataPtr; +} + +/******************************************************************************* + * uiTraceGetTraceBufferSize + * + * Gets the size of the recorder data structure. For use together with + * vTraceGetTraceBuffer if you wish to implement an own store/upload solution, + * e.g., in case a debugger connection is not available for uploading the data. + ******************************************************************************/ +uint32_t uiTraceGetTraceBufferSize(void) +{ + return sizeof(RecorderDataType); +} + +/****************************************************************************** + * prvTraceTaskInstanceFinish + * + * Private common function for the vTraceTaskInstanceFinishXXX functions. + *****************************************************************************/ +static void prvTraceTaskInstanceFinish(int8_t direct) +{ + TaskInstanceStatusEvent* tis; + uint8_t dts45; + + TRACE_ALLOC_CRITICAL_SECTION(); + + trcCRITICAL_SECTION_BEGIN(); + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) + { + dts45 = (uint8_t)prvTraceGetDTS(0xFF); + tis = (TaskInstanceStatusEvent*) prvTraceNextFreeEventBufferSlot(); + if (tis != NULL) + { + if (direct == 0) + tis->type = TASK_INSTANCE_FINISHED_NEXT_KSE; + else + tis->type = TASK_INSTANCE_FINISHED_DIRECT; + + tis->dts = dts45; + prvTraceUpdateCounters(); + } + } + trcCRITICAL_SECTION_END(); +} + +/****************************************************************************** + * vTraceInstanceFinishedNext(void) + * + * Marks the current task instance as finished on the next kernel call. + * + * If that kernel call is blocking, the instance ends after the blocking event + * and the corresponding return event is then the start of the next instance. + * If the kernel call is not blocking, the viewer instead splits the current + * fragment right before the kernel call, which makes this call the first event + * of the next instance. + * + * See also TRC_CFG_USE_IMPLICIT_IFE_RULES in trcConfig.h + * + * Example: + * + * while(1) + * { + * xQueueReceive(CommandQueue, &command, timeoutDuration); + * processCommand(command); + * vTraceInstanceFinishedNext(); + * } + *****************************************************************************/ +void vTraceInstanceFinishedNext(void) +{ + prvTraceTaskInstanceFinish(0); +} + +/****************************************************************************** + * vTraceInstanceFinishedNow(void) + * + * Marks the current task instance as finished at this very instant. + * This makes the viewer to splits the current fragment at this point and begin + * a new actor instance. + * + * See also TRC_CFG_USE_IMPLICIT_IFE_RULES in trcConfig.h + * + * Example: + * + * This example will generate two instances for each loop iteration. + * The first instance ends at vTraceInstanceFinishedNow(), while the second + * instance ends at the next xQueueReceive call. + * + * while (1) + * { + * xQueueReceive(CommandQueue, &command, timeoutDuration); + * ProcessCommand(command); + * vTraceInstanceFinishedNow(); + * DoSometingElse(); + * vTraceInstanceFinishedNext(); + * } + *****************************************************************************/ +void vTraceInstanceFinishedNow(void) +{ + prvTraceTaskInstanceFinish(1); +} + +/******************************************************************************* + * Interrupt recording functions + ******************************************************************************/ + +#if (TRC_CFG_INCLUDE_ISR_TRACING == 1) + +/******************************************************************************* + * xTraceSetISRProperties + * + * Stores a name and priority level for an Interrupt Service Routine, to allow + * for better visualization. Returns a traceHandle used by vTraceStoreISRBegin. + * + * Example: + * #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt + * ... + * traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(Timer1Handle); + * ... + * vTraceStoreISREnd(0); + * } + ******************************************************************************/ + traceHandle xTraceSetISRProperties(const char* name, uint8_t priority) +{ + static traceHandle handle = 0; + TRACE_ASSERT(RecorderDataPtr != NULL, "Recorder not initialized, call vTraceEnable() first!", (traceHandle)0); + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "xTraceSetISRProperties: Invalid value for handle", 0); + TRACE_ASSERT(name != NULL, "xTraceSetISRProperties: name == NULL", 0); + + handle++; + + prvTraceSetObjectName(TRACE_CLASS_ISR, handle, name); + prvTraceSetPriorityProperty(TRACE_CLASS_ISR, handle, priority); + + return handle; +} + +/******************************************************************************* + * vTraceStoreISRBegin + * + * Registers the beginning of an Interrupt Service Routine, using a traceHandle + * provided by xTraceSetISRProperties. + * + * Example: + * #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt + * ... + * traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(Timer1Handle); + * ... + * vTraceStoreISREnd(0); + * } + ******************************************************************************/ +void vTraceStoreISRBegin(traceHandle handle) +{ + TRACE_ALLOC_CRITICAL_SECTION(); + + if (recorder_busy) + { + /************************************************************************* + * This occurs if an ISR calls a trace function, preempting a previous + * trace call that is being processed in a different ISR or task. + * If this occurs, there is probably a problem in the definition of the + * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and + * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt + * and any other ISRs that calls the trace recorder directly or via + * traced kernel functions. The ARM port disables all interrupts using the + * PRIMASK register to avoid this issue. + *************************************************************************/ + prvTraceError("vTraceStoreISRBegin - recorder busy! See code comment."); + return; + } + trcCRITICAL_SECTION_BEGIN(); + + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) + { + uint16_t dts4; + + TRACE_ASSERT(handle != 0, "vTraceStoreISRBegin: Invalid ISR handle (NULL)", TRC_UNUSED); + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "vTraceStoreISRBegin: Invalid ISR handle (> NISR)", TRC_UNUSED); + + dts4 = (uint16_t)prvTraceGetDTS(0xFFFF); + + if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + { + if (nISRactive < TRC_CFG_MAX_ISR_NESTING) + { + TSEvent* ts; + uint8_t hnd8 = prvTraceGet8BitHandle(handle); + isrstack[nISRactive] = handle; + nISRactive++; + ts = (TSEvent*)prvTraceNextFreeEventBufferSlot(); + if (ts != NULL) + { + ts->type = TS_ISR_BEGIN; + ts->dts = dts4; + ts->objHandle = hnd8; + prvTraceUpdateCounters(); + } + } + else + { + /* This should not occur unless something is very wrong */ + prvTraceError("Too many nested interrupts!"); + } + } + } + trcCRITICAL_SECTION_END(); +} + +/******************************************************************************* + * vTraceStoreISREnd + * + * Registers the end of an Interrupt Service Routine. + * + * The parameter pendingISR indicates if the interrupt has requested a + * task-switch (= 1), e.g., by signaling a semaphore. Otherwise (= 0) the + * interrupt is assumed to return to the previous context. + * + * Example: + * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt + * traceHandle traceHandleIsrTimer1 = 0; // The ID set by the recorder + * ... + * traceHandleIsrTimer1 = xTraceSetISRProperties("ISRTimer1", PRIO_OF_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(traceHandleIsrTimer1); + * ... + * vTraceStoreISREnd(0); + * } + ******************************************************************************/ +void vTraceStoreISREnd(int pendingISR) +{ + TSEvent* ts; + uint16_t dts5; + uint8_t hnd8 = 0, type = 0; + + TRACE_ALLOC_CRITICAL_SECTION(); + + if (! RecorderDataPtr->recorderActive || ! handle_of_last_logged_task) + { + return; + } + + if (recorder_busy) + { + /************************************************************************* + * This occurs if an ISR calls a trace function, preempting a previous + * trace call that is being processed in a different ISR or task. + * If this occurs, there is probably a problem in the definition of the + * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and + * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt + * and any other ISRs that calls the trace recorder directly or via + * traced kernel functions. The ARM port disables all interrupts using the + * PRIMASK register to avoid this issue. + *************************************************************************/ + prvTraceError("vTraceStoreISREnd - recorder busy! See code comment."); + return; + } + + if (nISRactive == 0) + { + prvTraceError("Unmatched call to vTraceStoreISREnd (nISRactive == 0, expected > 0)"); + return; + } + + trcCRITICAL_SECTION_BEGIN(); + isPendingContextSwitch |= pendingISR; /* Is there a pending context switch right now? */ + nISRactive--; + if (nISRactive > 0) + { + /* Return to another ISR */ + type = TS_ISR_RESUME; + hnd8 = prvTraceGet8BitHandle(isrstack[nISRactive - 1]); /* isrstack[nISRactive] is the handle of the ISR we're currently exiting. isrstack[nISRactive - 1] is the handle of the ISR that was executing previously. */ + } + else if ((isPendingContextSwitch == 0) || (prvTraceIsSchedulerSuspended())) + { + /* Return to interrupted task, if no context switch will occur in between. */ + type = TS_TASK_RESUME; + hnd8 = prvTraceGet8BitHandle(handle_of_last_logged_task); + } + + if (type != 0) + { + dts5 = (uint16_t)prvTraceGetDTS(0xFFFF); + ts = (TSEvent*)prvTraceNextFreeEventBufferSlot(); + if (ts != NULL) + { + ts->type = type; + ts->objHandle = hnd8; + ts->dts = dts5; + prvTraceUpdateCounters(); + } + } + + trcCRITICAL_SECTION_END(); +} + +#else + +/* ISR tracing is turned off */ +void prvTraceIncreaseISRActive(void) +{ + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) + nISRactive++; +} + +void prvTraceDecreaseISRActive(void) +{ + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) + nISRactive--; +} +#endif /* (TRC_CFG_INCLUDE_ISR_TRACING == 1)*/ + + +/********************************************************************************/ +/* User Event functions */ +/********************************************************************************/ + +#define MAX_ARG_SIZE (4+32) + +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) +static uint8_t writeInt8(void * buffer, uint8_t i, uint8_t value) +{ + TRACE_ASSERT(buffer != NULL, "writeInt8: buffer == NULL", 0); + + if (i >= MAX_ARG_SIZE) + { + return 255; + } + + ((uint8_t*)buffer)[i] = value; + + if (i + 1 > MAX_ARG_SIZE) + { + return 255; + } + + return ((uint8_t) (i + 1)); +} +#endif + +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) +static uint8_t writeInt16(void * buffer, uint8_t i, uint16_t value) +{ + TRACE_ASSERT(buffer != NULL, "writeInt16: buffer == NULL", 0); + + /* Align to multiple of 2 */ + while ((i % 2) != 0) + { + if (i >= MAX_ARG_SIZE) + { + return 255; + } + + ((uint8_t*)buffer)[i] = 0; + i++; + } + + if (i + 2 > MAX_ARG_SIZE) + { + return 255; + } + + ((uint16_t*)buffer)[i/2] = value; + + return ((uint8_t) (i + 2)); +} +#endif + +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) +static uint8_t writeInt32(void * buffer, uint8_t i, uint32_t value) +{ + TRACE_ASSERT(buffer != NULL, "writeInt32: buffer == NULL", 0); + + /* A 32 bit value should begin at an even 4-byte address */ + while ((i % 4) != 0) + { + if (i >= MAX_ARG_SIZE) + { + return 255; + } + + ((uint8_t*)buffer)[i] = 0; + i++; + } + + if (i + 4 > MAX_ARG_SIZE) + { + return 255; + } + + ((uint32_t*)buffer)[i/4] = value; + + return ((uint8_t) (i + 4)); +} +#endif + +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_INCLUDE_FLOAT_SUPPORT)) +static uint8_t writeFloat(void * buffer, uint8_t i, float value) +{ + TRACE_ASSERT(buffer != NULL, "writeFloat: buffer == NULL", 0); + + /* A 32 bit value should begin at an even 4-byte address */ + while ((i % 4) != 0) + { + if (i >= MAX_ARG_SIZE) + { + return 255; + } + + ((uint8_t*)buffer)[i] = 0; + i++; + } + + if (i + 4 > MAX_ARG_SIZE) + { + return 255; + } + + ((float*)buffer)[i/4] = value; + + return i + 4; +} +#endif + +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_INCLUDE_FLOAT_SUPPORT)) +static uint8_t writeDouble(void * buffer, uint8_t i, double value) +{ + uint32_t * dest; + uint32_t * src = (uint32_t*)&value; + + TRACE_ASSERT(buffer != NULL, "writeDouble: buffer == NULL", 0); + + /* The double is written as two 32 bit values, and should begin at an even + 4-byte address (to avoid having to align with 8 byte) */ + while (i % 4 != 0) + { + if (i >= MAX_ARG_SIZE) + { + return 255; + } + + ((uint8_t*)buffer)[i] = 0; + i++; + } + + if (i + 8 > MAX_ARG_SIZE) + { + return 255; + } + + dest = &(((uint32_t *)buffer)[i/4]); + + dest[0] = src[0]; + dest[1] = src[1]; + + return i + 8; +} +#endif + +/******************************************************************************* + * prvTraceUserEventFormat + * + * Parses the format string and stores the arguments in the buffer. + ******************************************************************************/ +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) +static uint8_t prvTraceUserEventFormat(const char* formatStr, va_list vl, uint8_t* buffer, uint8_t byteOffset) +{ + uint16_t formatStrIndex = 0; + uint8_t argCounter = 0; + uint8_t i = byteOffset; + + while (formatStr[formatStrIndex] != '\0') + { + if (formatStr[formatStrIndex] == '%') + { + argCounter++; + + if (argCounter > 15) + { + prvTraceError("vTracePrintF - Too many arguments, max 15 allowed!"); + return 0; + } + + formatStrIndex++; + + while ((formatStr[formatStrIndex] >= '0' && formatStr[formatStrIndex] <= '9') || formatStr[formatStrIndex] == '#' || formatStr[formatStrIndex] == '.') + formatStrIndex++; + + if (formatStr[formatStrIndex] != '\0') + { + switch (formatStr[formatStrIndex]) + { + case 'd': i = writeInt32( buffer, + i, + (uint32_t)va_arg(vl, uint32_t)); + break; + case 'x': + case 'X': + case 'u': i = writeInt32( buffer, + i, + (uint32_t)va_arg(vl, uint32_t)); + break; + case 's': i = writeInt16( buffer, + i, + xTraceRegisterString((char*)va_arg(vl, char*))); + break; + +#if (TRC_CFG_INCLUDE_FLOAT_SUPPORT) + /* Yes, "double" as type also in the float + case. This since "float" is promoted into "double" + by the va_arg stuff. */ + case 'f': i = writeFloat( buffer, + i, + (float)va_arg(vl, double)); + break; +#else + /* No support for floats, but attempt to store a float user event + avoid a possible crash due to float reference. Instead store the + data on uint_32 format (will not be displayed anyway). This is just + to keep va_arg and i consistent. */ + + case 'f': i = writeInt32( buffer, + i, + (uint32_t)va_arg(vl, double)); + break; +#endif + case 'l': + formatStrIndex++; + switch (formatStr[formatStrIndex]) + { +#if (TRC_CFG_INCLUDE_FLOAT_SUPPORT) + case 'f': i = writeDouble(buffer, + i, + (double)va_arg(vl, double)); + break; +#else + /* No support for floats, but attempt to store a float user event + avoid a possible crash due to float reference. Instead store the + data on uint_32 format (will not be displayed anyway). This is just + to keep va_arg and i consistent. */ + case 'f': i = writeInt32( buffer, /* In this case, the value will not be shown anyway */ + i, + (uint32_t)va_arg(vl, double)); + + i = writeInt32( buffer, /* Do it twice, to write in total 8 bytes */ + i, + (uint32_t)va_arg(vl, double)); + break; +#endif + + } + break; + case 'h': + formatStrIndex++; + switch (formatStr[formatStrIndex]) + { + case 'd': i = writeInt16( buffer, + i, + (uint16_t)va_arg(vl, uint32_t)); + break; + case 'u': i = writeInt16( buffer, + i, + (uint16_t)va_arg(vl, uint32_t)); + break; + } + break; + case 'b': + formatStrIndex++; + switch (formatStr[formatStrIndex]) + { + case 'd': i = writeInt8( buffer, + i, + (uint8_t)va_arg(vl, uint32_t)); + break; + + case 'u': i = writeInt8( buffer, + i, + (uint8_t)va_arg(vl, uint32_t)); + break; + } + break; + } + } + else + break; + } + formatStrIndex++; + if (i == 255) + { + prvTraceError("vTracePrintF - Too large arguments, max 32 byte allowed!"); + return 0; + } + } + return (uint8_t)(i+3)/4; +} +#endif + +/******************************************************************************* + * prvTraceClearChannelBuffer + * + * Clears a number of items in the channel buffer, starting from nextSlotToWrite. + ******************************************************************************/ +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)) +static void prvTraceClearChannelBuffer(uint32_t count) +{ + uint32_t slots; + + TRACE_ASSERT((TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) >= count, + "prvTraceClearChannelBuffer: TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE is too small to handle this event.", TRC_UNUSED); + + /* Check if we're close to the end of the buffer */ + if (RecorderDataPtr->userEventBuffer.nextSlotToWrite + count > (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE)) + { + slots = (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) - RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Number of slots before end of buffer */ + (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite], 0, slots); + (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[0], 0, (count - slots)); + } + else + (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite], 0, count); +} +#endif + +/******************************************************************************* + * prvTraceCopyToDataBuffer + * + * Copies a number of items to the data buffer, starting from nextSlotToWrite. + ******************************************************************************/ +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)) +static void prvTraceCopyToDataBuffer(uint32_t* data, uint32_t count) +{ + uint32_t slots; + + TRACE_ASSERT(data != NULL, + "prvTraceCopyToDataBuffer: data == NULL.", TRC_UNUSED); + TRACE_ASSERT(count <= (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE), + "prvTraceCopyToDataBuffer: TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE is too small to handle this event.", TRC_UNUSED); + /* Check if we're close to the end of the buffer */ + if (RecorderDataPtr->userEventBuffer.nextSlotToWrite + count > (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE)) + { + slots = (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) - RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Number of slots before end of buffer */ + (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite * 4], data, slots * 4); + (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[0], data + slots, (count - slots) * 4); + } + else + { + (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite * 4], data, count * 4); + } +} +#endif + +/******************************************************************************* + * prvTraceUBHelper1 + * + * Calls on prvTraceUserEventFormat() to do the actual formatting, then goes on + * to the next helper function. + ******************************************************************************/ +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)) +static void prvTraceUBHelper1(traceUBChannel channel, traceString eventLabel, traceString formatLabel, va_list vl) +{ + uint32_t data[(3 + MAX_ARG_SIZE) / 4]; + uint8_t byteOffset = 4; /* Need room for timestamp */ + uint8_t noOfSlots; + + if (channel == 0) + { + /* We are dealing with an unknown channel format pair */ + byteOffset = (uint8_t)(byteOffset + 4); /* Also need room for channel and format */ + ((uint16_t*)data)[2] = eventLabel; + ((uint16_t*)data)[3] = formatLabel; + } + + noOfSlots = prvTraceUserEventFormat((char*)&(RecorderDataPtr->SymbolTable.symbytes[formatLabel+4]), vl, (uint8_t*)data, byteOffset); + + prvTraceUBHelper2(channel, data, noOfSlots); +} +#endif + +/******************************************************************************* + * prvTraceUBHelper2 + * + * This function simply copies the data buffer to the actual user event buffer. + ******************************************************************************/ +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)) +static void prvTraceUBHelper2(traceUBChannel channel, uint32_t* data, uint32_t noOfSlots) +{ + static uint32_t old_timestamp = 0; + uint32_t old_nextSlotToWrite = 0; + + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ASSERT((TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) >= noOfSlots, "prvTraceUBHelper2: TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE is too small to handle this event.", TRC_UNUSED); + + trcCRITICAL_SECTION_BEGIN(); + /* Store the timestamp */ + prvTracePortGetTimeStamp(data); + + if (*data < old_timestamp) + { + RecorderDataPtr->userEventBuffer.wraparoundCounter++; + } + + old_timestamp = *data; + + /* Start by erasing any information in the channel buffer */ + prvTraceClearChannelBuffer(noOfSlots); + + prvTraceCopyToDataBuffer(data, noOfSlots); /* Will wrap around the data if necessary */ + + old_nextSlotToWrite = RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Save the index that we want to write the channel data at when we're done */ + RecorderDataPtr->userEventBuffer.nextSlotToWrite = (RecorderDataPtr->userEventBuffer.nextSlotToWrite + noOfSlots) % (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE); /* Make sure we never end up outside the buffer */ + + /* Write to the channel buffer to indicate that this user event is ready to be used */ + if (channel != 0) + { + RecorderDataPtr->userEventBuffer.channelBuffer[old_nextSlotToWrite] = channel; + } + else + { + /* 0xFF indicates that this is not a normal channel id */ + RecorderDataPtr->userEventBuffer.channelBuffer[old_nextSlotToWrite] = (traceUBChannel)0xFF; + } + trcCRITICAL_SECTION_END(); +} +#endif + +/******************************************************************************* + * xTraceRegisterUBChannel + * + * Registers a channel for Separated User Events, i.e., those stored in the + * separate user event buffer. + * + * Note: Only available if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER is enabled in + * trcSnapshotConfig.h + ******************************************************************************/ +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)) +traceUBChannel xTraceRegisterUBChannel(traceString channel, traceString formatStr) +{ + uint8_t i; + traceUBChannel retVal = 0; + + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ASSERT(formatStr != 0, "xTraceRegisterChannelFormat: formatStr == 0", (traceUBChannel)0); + + trcCRITICAL_SECTION_BEGIN(); + for (i = 1; i <= (TRC_CFG_UB_CHANNELS); i++) /* Size of the channels buffer is TRC_CFG_UB_CHANNELS + 1. Index 0 is unused. */ + { + if(RecorderDataPtr->userEventBuffer.channels[i].name == 0 && RecorderDataPtr->userEventBuffer.channels[i].defaultFormat == 0) + { + /* Found empty slot */ + RecorderDataPtr->userEventBuffer.channels[i].name = channel; + RecorderDataPtr->userEventBuffer.channels[i].defaultFormat = formatStr; + retVal = (traceUBChannel)i; + break; + } + + if (RecorderDataPtr->userEventBuffer.channels[i].name == channel && RecorderDataPtr->userEventBuffer.channels[i].defaultFormat == formatStr) + { + /* Found a match */ + retVal = (traceUBChannel)i; + break; + } + } + trcCRITICAL_SECTION_END(); + + return retVal; +} +#endif + +/****************************************************************************** + * vTraceUBData + * + * Slightly faster version of vTracePrintF() due to no lookups. + * + * Note: This is only available if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER is + * enabled in trcSnapshotConfig.h + ******************************************************************************/ +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)) +void vTraceUBData(traceUBChannel channelPair, ...) +{ + va_list vl; + + TRACE_ASSERT(channelPair != 0, "vTraceUBData: Not a valid traceUBChannel!", TRC_UNUSED); + + va_start(vl, channelPair); + vTraceUBData_Helper(channelPair, vl); + va_end(vl); +} +#endif + +/* Extracts the channel name and format string from the traceUBChannel, then calls prvTraceUBHelper1. */ +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)) +void vTraceUBData_Helper(traceUBChannel channelPair, va_list vl) +{ + traceString channel; + traceString formatStr; + + TRACE_ASSERT(channelPair != 0, "vTraceUBData_Helper: channelPair == 0", TRC_UNUSED); + TRACE_ASSERT(channelPair <= (TRC_CFG_UB_CHANNELS), "vTraceUBData_Helper: ", TRC_UNUSED); + + channel = RecorderDataPtr->userEventBuffer.channels[channelPair].name; + formatStr = RecorderDataPtr->userEventBuffer.channels[channelPair].defaultFormat; + + prvTraceUBHelper1(channelPair, channel, formatStr, vl); +} +#endif + +/****************************************************************************** + * vTraceUBEvent + * + * Slightly faster version of ... due to no lookups. + ******************************************************************************/ +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)) +void vTraceUBEvent(traceUBChannel channelPair) +{ + uint32_t data[(3 + MAX_ARG_SIZE) / 4]; + + TRACE_ASSERT(channelPair != 0, "vTraceUBEvent: channelPair == 0", TRC_UNUSED); + TRACE_ASSERT(channelPair <= (TRC_CFG_UB_CHANNELS), "vTraceUBEvent: ", TRC_UNUSED); + + prvTraceUBHelper2(channelPair, data, 1); /* Only need one slot for timestamp */ +} +#endif + +/****************************************************************************** + * vTracePrintF + * + * Generates User Event with formatted text and data, similar to a "printf". + * It is very fast compared to a normal "printf" since this function only + * stores the arguments. The actual formatting is done + * on the host PC when the trace is displayed in the viewer tool. + * + * User Event labels are created using xTraceRegisterString. + * Example: + * + * traceString adc_uechannel = xTraceRegisterString("ADC User Events"); + * ... + * vTracePrintF(adc_uechannel, + * "ADC channel %d: %lf volts", + * ch, (double)adc_reading/(double)scale); + * + * This can be combined into one line, if desired, but this is slower: + * + * vTracePrintF(xTraceRegisterString("ADC User Events"), + * "ADC channel %d: %lf volts", + * ch, (double)adc_reading/(double)scale); + * + * Calling xTraceRegisterString multiple times will not create duplicate entries, but + * it is of course faster to just do it once, and then keep the handle for later + * use. If you don't have any data arguments, only a text label/string, it is + * better to use vTracePrint - it is faster. + * + * Format specifiers supported: + * %d - 32 bit signed integer + * %u - 32 bit unsigned integer + * %f - 32 bit float + * %s - string (is copied to the recorder symbol table) + * %hd - 16 bit signed integer + * %hu - 16 bit unsigned integer + * %bd - 8 bit signed integer + * %bu - 8 bit unsigned integer + * %lf - double-precision float (Note! See below...) + * + * Up to 15 data arguments are allowed, with a total size of maximum 32 byte. + * In case this is exceeded, the user event is changed into an error message. + * + * The data is stored in trace buffer, and is packed to allow storing multiple + * smaller data entries in the same 4-byte record, e.g., four 8-bit values. + * A string requires two bytes, as the symbol table is limited to 64K. Storing + * a double (%lf) uses two records, so this is quite costly. Use float (%f) + * unless the higher precision is really necessary. + * + * Note that the double-precision float (%lf) assumes a 64 bit double + * representation. This does not seem to be the case on e.g. PIC24 and PIC32. + * Before using a %lf argument on a 16-bit MCU, please verify that + * "sizeof(double)" actually gives 8 as expected. If not, use %f instead. + ******************************************************************************/ +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) +void vTracePrintF(traceString eventLabel, const char* formatStr, ...) +{ + va_list vl; + + va_start(vl, formatStr); + vTracePrintF_Helper(eventLabel, formatStr, vl); + va_end(vl); +} +#endif + +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) +void vTracePrintF_Helper(traceString eventLabel, const char* formatStr, va_list vl) +{ +#if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 0) + uint32_t noOfSlots; + UserEvent* ue1; + uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4]; + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ASSERT(formatStr != NULL, "vTracePrintF_Helper: formatStr == NULL", TRC_UNUSED); + + trcCRITICAL_SECTION_BEGIN(); + + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) + { + /* First, write the "primary" user event entry in the local buffer, but + let the event type be "EVENT_BEING_WRITTEN" for now...*/ + + ue1 = (UserEvent*)(&tempDataBuffer[0]); + + ue1->type = EVENT_BEING_WRITTEN; /* Update this as the last step */ + + noOfSlots = prvTraceUserEventFormat(formatStr, vl, (uint8_t*)tempDataBuffer, 4); + + /* Store the format string, with a reference to the channel symbol */ + ue1->payload = prvTraceOpenSymbol(formatStr, eventLabel); + + ue1->dts = (uint8_t)prvTraceGetDTS(0xFF); + + /* prvTraceGetDTS might stop the recorder in some cases... */ + if (RecorderDataPtr->recorderActive) + { + + /* If the data does not fit in the remaining main buffer, wrap around to + 0 if allowed, otherwise stop the recorder and quit). */ + if (RecorderDataPtr->nextFreeIndex + noOfSlots > RecorderDataPtr->maxEvents) + { + #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER) + (void)memset(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4], + 0, + (RecorderDataPtr->maxEvents - RecorderDataPtr->nextFreeIndex)*4); + RecorderDataPtr->nextFreeIndex = 0; + RecorderDataPtr->bufferIsFull = 1; + #else + + /* Stop recorder, since the event data will not fit in the + buffer and not circular buffer in this case... */ + vTraceStop(); + #endif + } + + /* Check if recorder has been stopped (i.e., vTraceStop above) */ + if (RecorderDataPtr->recorderActive) + { + /* Check that the buffer to be overwritten does not contain any user + events that would be partially overwritten. If so, they must be "killed" + by replacing the user event and following data with NULL events (i.e., + using a memset to zero).*/ + #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER) + prvCheckDataToBeOverwrittenForMultiEntryEvents((uint8_t)noOfSlots); + #endif + /* Copy the local buffer to the main buffer */ + (void)memcpy(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4], + tempDataBuffer, + noOfSlots * 4); + + /* Update the event type, i.e., number of data entries following the + main USER_EVENT entry (Note: important that this is after the memcpy, + but within the critical section!)*/ + RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4] = + (uint8_t) ( USER_EVENT + noOfSlots - 1 ); + + /* Update the main buffer event index (already checked that it fits in + the buffer, so no need to check for wrapping)*/ + + RecorderDataPtr->nextFreeIndex += noOfSlots; + RecorderDataPtr->numEvents += noOfSlots; + + if (RecorderDataPtr->nextFreeIndex >= (TRC_CFG_EVENT_BUFFER_SIZE)) + { + #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER) + /* We have reached the end, but this is a ring buffer. Start from the beginning again. */ + RecorderDataPtr->bufferIsFull = 1; + RecorderDataPtr->nextFreeIndex = 0; + #else + /* We have reached the end so we stop. */ + vTraceStop(); + #endif + } + } + + #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER) + /* Make sure the next entry is cleared correctly */ + prvCheckDataToBeOverwrittenForMultiEntryEvents(1); + #endif + + } + } + trcCRITICAL_SECTION_END(); + +#elif (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1) + /* Use the separate user event buffer */ + traceString formatLabel; + traceUBChannel channel; + + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) + { + formatLabel = xTraceRegisterString(formatStr); + + channel = xTraceRegisterUBChannel(eventLabel, formatLabel); + + prvTraceUBHelper1(channel, eventLabel, formatLabel, vl); + } +#endif +} +#endif + +/****************************************************************************** + * vTracePrint + * + * Basic user event + * + * Generates a User Event with a text label. The label is created/looked up + * in the symbol table using xTraceRegisterString. + ******************************************************************************/ +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) +void vTracePrint(traceString chn, const char* str) +{ +#if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 0) + UserEvent* ue; + uint8_t dts1; + TRACE_ALLOC_CRITICAL_SECTION(); + + trcCRITICAL_SECTION_BEGIN(); + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) + { + dts1 = (uint8_t)prvTraceGetDTS(0xFF); + ue = (UserEvent*) prvTraceNextFreeEventBufferSlot(); + if (ue != NULL) + { + ue->dts = dts1; + ue->type = USER_EVENT; + ue->payload = prvTraceOpenSymbol(str, chn); + prvTraceUpdateCounters(); + } + } + trcCRITICAL_SECTION_END(); + +#elif (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1) + traceUBChannel channel; + uint32_t noOfSlots = 1; + uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4]; + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) + { + traceString trcStr = prvTraceOpenSymbol(str, chn); + channel = xTraceRegisterUBChannel(chn, trcStr); + + if (channel == 0) + { + /* We are dealing with an unknown channel format pair */ + noOfSlots++; /* Also need room for channel and format */ + ((uint16_t*)tempDataBuffer)[2] = chn; + ((uint16_t*)tempDataBuffer)[3] = trcStr; + } + + prvTraceUBHelper2(channel, tempDataBuffer, noOfSlots); + } +#endif +} +#endif + +/******************************************************************************* + * xTraceRegisterString + * + * Register strings in the recorder, e.g. for names of user event channels. + * + * Example: + * myEventHandle = xTraceRegisterString("MyUserEvent"); + * ... + * vTracePrintF(myEventHandle, "My value is: %d", myValue); + ******************************************************************************/ +#if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) +traceString xTraceRegisterString(const char* label) +{ + TRACE_ASSERT(label != NULL, "xTraceRegisterString: label == NULL", (traceString)0); + TRACE_ASSERT(RecorderDataPtr != NULL, "Recorder not initialized, call vTraceEnable() first!", (traceHandle)0); + return prvTraceOpenSymbol(label, 0); +} +#endif + + +#if ((!defined TRC_CFG_INCLUDE_READY_EVENTS) || (TRC_CFG_INCLUDE_READY_EVENTS == 1)) + +void prvTraceSetReadyEventsEnabled(int status) +{ + readyEventsEnabled = status; +} + +/******************************************************************************* + * prvTraceStoreTaskReady + * + * This function stores a ready state for the task handle sent in as parameter. + ******************************************************************************/ +void prvTraceStoreTaskReady(traceHandle handle) +{ + uint16_t dts3; + TREvent* tr; + uint8_t hnd8; + + TRACE_ALLOC_CRITICAL_SECTION(); + + if (handle == 0) + { + /* On FreeRTOS v7.3.0, this occurs when creating tasks due to a bad + placement of the trace macro. In that case, the events are ignored. */ + return; + } + + if (! readyEventsEnabled) + { + /* When creating tasks, ready events are also created. If creating + a "hidden" (not traced) task, we must therefore disable recording + of ready events to avoid an undesired ready event... */ + return; + } + + TRACE_ASSERT(handle <= (TRC_CFG_NTASK), "prvTraceStoreTaskReady: Invalid value for handle", TRC_UNUSED); + + if (recorder_busy) + { + /************************************************************************* + * This occurs if an ISR calls a trace function, preempting a previous + * trace call that is being processed in a different ISR or task. + * If this occurs, there is probably a problem in the definition of the + * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and + * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt + * and any other ISRs that calls the trace recorder directly or via + * traced kernel functions. The ARM port disables all interrupts using the + * PRIMASK register to avoid this issue. + *************************************************************************/ + prvTraceError("Recorder busy - high priority ISR using syscall? (1)"); + return; + } + + trcCRITICAL_SECTION_BEGIN(); + if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + { + dts3 = (uint16_t)prvTraceGetDTS(0xFFFF); + hnd8 = prvTraceGet8BitHandle(handle); + tr = (TREvent*)prvTraceNextFreeEventBufferSlot(); + if (tr != NULL) + { + tr->type = DIV_TASK_READY; + tr->dts = dts3; + tr->objHandle = hnd8; + prvTraceUpdateCounters(); + } + } + trcCRITICAL_SECTION_END(); +} +#endif + +/******************************************************************************* + * prvTraceStoreLowPower + * + * This function stores a low power state. + ******************************************************************************/ +void prvTraceStoreLowPower(uint32_t flag) +{ + uint16_t dts; + LPEvent* lp; + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ASSERT(flag <= 1, "prvTraceStoreLowPower: Invalid flag value", TRC_UNUSED); + + if (recorder_busy) + { + /************************************************************************* + * This occurs if an ISR calls a trace function, preempting a previous + * trace call that is being processed in a different ISR or task. + * If this occurs, there is probably a problem in the definition of the + * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and + * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt + * and any other ISRs that calls the trace recorder directly or via + * traced kernel functions. The ARM port disables all interrupts using the + * PRIMASK register to avoid this issue. + *************************************************************************/ + prvTraceError("Recorder busy - high priority ISR using syscall? (1)"); + return; + } + + trcCRITICAL_SECTION_BEGIN(); + if (RecorderDataPtr->recorderActive) + { + dts = (uint16_t)prvTraceGetDTS(0xFFFF); + lp = (LPEvent*)prvTraceNextFreeEventBufferSlot(); + if (lp != NULL) + { + lp->type = (uint8_t) (LOW_POWER_BEGIN + ( uint8_t ) flag); /* BEGIN or END depending on flag */ + lp->dts = dts; + prvTraceUpdateCounters(); + } + } + trcCRITICAL_SECTION_END(); +} + +/******************************************************************************* + * vTraceStoreMemMangEvent + * + * This function stores malloc and free events. Each call requires two records, + * for size and address respectively. The event code parameter (ecode) is applied + * to the first record (size) and the following address record gets event + * code "ecode + 1", so make sure this is respected in the event code table. + * Note: On "free" calls, the signed_size parameter should be negative. + ******************************************************************************/ +#if (TRC_CFG_INCLUDE_MEMMANG_EVENTS == 1) +#if (TRC_CFG_SCHEDULING_ONLY == 0) +void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, int32_t signed_size) +{ + uint8_t dts1; + MemEventSize * ms; + MemEventAddr * ma; + uint16_t size_low; + uint16_t addr_low; + uint8_t addr_high; + uint32_t size; + TRACE_ALLOC_CRITICAL_SECTION(); + + if (RecorderDataPtr == NULL) + { + /* Occurs in vTraceInitTraceData, if using dynamic allocation. */ + return; + } + + if (signed_size < 0) + size = (uint32_t)(- signed_size); + else + size = (uint32_t)(signed_size); + + trcCRITICAL_SECTION_BEGIN(); + + heapMemUsage = heapMemUsage + (uint32_t)signed_size; + + if (RecorderDataPtr->recorderActive) + { + dts1 = (uint8_t)prvTraceGetDTS(0xFF); + size_low = (uint16_t)prvTraceGetParam(0xFFFF, size); + ms = (MemEventSize *)prvTraceNextFreeEventBufferSlot(); + + if (ms != NULL) + { + ms->dts = dts1; + ms->type = NULL_EVENT; /* Updated when all events are written */ + ms->size = size_low; + prvTraceUpdateCounters(); + + /* Storing a second record with address (signals "failed" if null) */ + #if (TRC_CFG_HEAP_SIZE_BELOW_16M) + /* If the heap address range is within 16 MB, i.e., the upper 8 bits + of addresses are constant, this optimization avoids storing an extra + event record by ignoring the upper 8 bit of the address */ + addr_low = address & 0xFFFF; + addr_high = (address >> 16) & 0xFF; + #else + /* The whole 32 bit address is stored using a second event record + for the upper 16 bit */ + addr_low = (uint16_t)prvTraceGetParam(0xFFFF, address); + addr_high = 0; + #endif + + ma = (MemEventAddr *) prvTraceNextFreeEventBufferSlot(); + if (ma != NULL) + { + ma->addr_low = addr_low; + ma->addr_high = addr_high; + ma->type = (uint8_t) (ecode + 1); /* Note this! */ + ms->type = (uint8_t) ecode; + prvTraceUpdateCounters(); + RecorderDataPtr->heapMemUsage = heapMemUsage; + } + } + } + trcCRITICAL_SECTION_END(); +} +#endif /* TRC_CFG_SCHEDULING_ONLY */ +#endif + +/******************************************************************************* + * prvTraceStoreKernelCall + * + * This is the main integration point for storing kernel calls, and + * is called by the hooks in trcKernelHooks.h (see trcKernelPort.h for event codes). + ******************************************************************************/ +#if (TRC_CFG_SCHEDULING_ONLY == 0) +void prvTraceStoreKernelCall(uint32_t ecode, traceObjectClass objectClass, uint32_t objectNumber) +{ + KernelCall * kse; + uint16_t dts1; + uint8_t hnd8; + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ASSERT(ecode < 0xFF, "prvTraceStoreKernelCall: ecode >= 0xFF", TRC_UNUSED); + TRACE_ASSERT(objectClass < TRACE_NCLASSES, "prvTraceStoreKernelCall: objectClass >= TRACE_NCLASSES", TRC_UNUSED); + TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "prvTraceStoreKernelCall: Invalid value for objectNumber", TRC_UNUSED); + + if (recorder_busy) + { + /************************************************************************* + * This occurs if an ISR calls a trace function, preempting a previous + * trace call that is being processed in a different ISR or task. + * If this occurs, there is probably a problem in the definition of the + * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and + * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt + * and any other ISRs that calls the trace recorder directly or via + * traced kernel functions. The ARM port disables all interrupts using the + * PRIMASK register to avoid this issue. + *************************************************************************/ + prvTraceError("Recorder busy - high priority ISR using syscall? (2)"); + return; + } + + if (handle_of_last_logged_task == 0) + { + return; + } + + trcCRITICAL_SECTION_BEGIN(); + if (RecorderDataPtr->recorderActive) + { + dts1 = (uint16_t)prvTraceGetDTS(0xFFFF); + hnd8 = prvTraceGet8BitHandle((traceHandle)objectNumber); + kse = (KernelCall*) prvTraceNextFreeEventBufferSlot(); + if (kse != NULL) + { + kse->dts = dts1; + kse->type = (uint8_t)ecode; + kse->objHandle = hnd8; + prvTraceUpdateCounters(); + } + } + trcCRITICAL_SECTION_END(); +} +#endif /* TRC_CFG_SCHEDULING_ONLY */ + +/******************************************************************************* + * prvTraceStoreKernelCallWithParam + * + * Used for storing kernel calls with a handle and a numeric parameter. If the + * numeric parameter does not fit in one byte, and extra XPS event is inserted + * before the kernel call event containing the three upper bytes. + ******************************************************************************/ +#if (TRC_CFG_SCHEDULING_ONLY == 0) +void prvTraceStoreKernelCallWithParam(uint32_t evtcode, + traceObjectClass objectClass, + uint32_t objectNumber, + uint32_t param) +{ + KernelCallWithParamAndHandle * kse; + uint8_t dts2; + uint8_t hnd8; + uint8_t p8; + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ASSERT(evtcode < 0xFF, "prvTraceStoreKernelCallWithParam: evtcode >= 0xFF", TRC_UNUSED); + TRACE_ASSERT(objectClass < TRACE_NCLASSES, "prvTraceStoreKernelCallWithParam: objectClass >= TRACE_NCLASSES", TRC_UNUSED); + TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "prvTraceStoreKernelCallWithParam: Invalid value for objectNumber", TRC_UNUSED); + + if (recorder_busy) + { + /************************************************************************* + * This occurs if an ISR calls a trace function, preempting a previous + * trace call that is being processed in a different ISR or task. + * If this occurs, there is probably a problem in the definition of the + * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and + * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt + * and any other ISRs that calls the trace recorder directly or via + * traced kernel functions. The ARM port disables all interrupts using the + * PRIMASK register to avoid this issue. + *************************************************************************/ + prvTraceError("Recorder busy - high priority ISR using syscall? (3)"); + return; + } + + trcCRITICAL_SECTION_BEGIN(); + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) + { + dts2 = (uint8_t)prvTraceGetDTS(0xFF); + p8 = (uint8_t) prvTraceGetParam(0xFF, param); + hnd8 = prvTraceGet8BitHandle((traceHandle)objectNumber); + kse = (KernelCallWithParamAndHandle*) prvTraceNextFreeEventBufferSlot(); + if (kse != NULL) + { + kse->dts = dts2; + kse->type = (uint8_t)evtcode; + kse->objHandle = hnd8; + kse->param = p8; + prvTraceUpdateCounters(); + } + } + trcCRITICAL_SECTION_END(); +} +#endif /* TRC_CFG_SCHEDULING_ONLY */ + + +/******************************************************************************* + * prvTraceGetParam + * + * Used for storing extra bytes for kernel calls with numeric parameters. + * + * May only be called within a critical section! + ******************************************************************************/ +#if (TRC_CFG_SCHEDULING_ONLY == 0) +static uint32_t prvTraceGetParam(uint32_t param_max, uint32_t param) +{ + XPSEvent* xps; + + TRACE_ASSERT(param_max == 0xFF || param_max == 0xFFFF, + "prvTraceGetParam: Invalid value for param_max", param); + + if (param <= param_max) + { + return param; + } + else + { + xps = (XPSEvent*) prvTraceNextFreeEventBufferSlot(); + if (xps != NULL) + { + xps->type = DIV_XPS; + xps->xps_8 = (uint8_t)((param & (0xFF00 & ~param_max)) >> 8); + xps->xps_16 = (uint16_t)((param & (0xFFFF0000 & ~param_max)) >> 16); + prvTraceUpdateCounters(); + } + + return param & param_max; + } +} +#endif + +/******************************************************************************* + * prvTraceStoreKernelCallWithNumericParamOnly + * + * Used for storing kernel calls with numeric parameters only. This is + * only used for traceTASK_DELAY and traceDELAY_UNTIL at the moment. + ******************************************************************************/ +#if (TRC_CFG_SCHEDULING_ONLY == 0) +void prvTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint32_t param) +{ + KernelCallWithParam16 * kse; + uint8_t dts6; + uint16_t restParam; + TRACE_ALLOC_CRITICAL_SECTION(); + + restParam = 0; + + TRACE_ASSERT(evtcode < 0xFF, "prvTraceStoreKernelCallWithNumericParamOnly: Invalid value for evtcode", TRC_UNUSED); + + if (recorder_busy) + { + /************************************************************************* + * This occurs if an ISR calls a trace function, preempting a previous + * trace call that is being processed in a different ISR or task. + * If this occurs, there is probably a problem in the definition of the + * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and + * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt + * and any other ISRs that calls the trace recorder directly or via + * traced kernel functions. The ARM port disables all interrupts using the + * PRIMASK register to avoid this issue. + *************************************************************************/ + prvTraceError("Recorder busy - high priority ISR using syscall? (4)"); + return; + } + + trcCRITICAL_SECTION_BEGIN(); + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) + { + dts6 = (uint8_t)prvTraceGetDTS(0xFF); + restParam = (uint16_t)prvTraceGetParam(0xFFFF, param); + kse = (KernelCallWithParam16*) prvTraceNextFreeEventBufferSlot(); + if (kse != NULL) + { + kse->dts = dts6; + kse->type = (uint8_t)evtcode; + kse->param = restParam; + prvTraceUpdateCounters(); + } + } + trcCRITICAL_SECTION_END(); +} +#endif /* TRC_CFG_SCHEDULING_ONLY */ + +/******************************************************************************* + * prvTraceStoreTaskswitch + * Called by the scheduler from the SWITCHED_OUT hook, and by uiTraceStart. + * At this point interrupts are assumed to be disabled! + ******************************************************************************/ +void prvTraceStoreTaskswitch(traceHandle task_handle) +{ + uint16_t dts3; + TSEvent* ts; + uint8_t hnd8; +#if (TRC_CFG_INCLUDE_ISR_TRACING == 1) + extern int32_t isPendingContextSwitch; +#endif + trcSR_ALLOC_CRITICAL_SECTION_ON_CORTEX_M_ONLY(); + + TRACE_ASSERT(task_handle <= (TRC_CFG_NTASK), + "prvTraceStoreTaskswitch: Invalid value for task_handle", TRC_UNUSED); + + trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY(); + + if ((task_handle != handle_of_last_logged_task) && (RecorderDataPtr->recorderActive)) + { +#if (TRC_CFG_INCLUDE_ISR_TRACING == 1) + isPendingContextSwitch = 0; +#endif + + dts3 = (uint16_t)prvTraceGetDTS(0xFFFF); + handle_of_last_logged_task = task_handle; + hnd8 = prvTraceGet8BitHandle(handle_of_last_logged_task); + ts = (TSEvent*)prvTraceNextFreeEventBufferSlot(); + + if (ts != NULL) + { + if (prvTraceGetObjectState(TRACE_CLASS_TASK, + handle_of_last_logged_task) == TASK_STATE_INSTANCE_ACTIVE) + { + ts->type = TS_TASK_RESUME; + } + else + { + ts->type = TS_TASK_BEGIN; + } + + ts->dts = dts3; + ts->objHandle = hnd8; + + prvTraceSetObjectState(TRACE_CLASS_TASK, + handle_of_last_logged_task, + TASK_STATE_INSTANCE_ACTIVE); + + prvTraceUpdateCounters(); + } + } + + trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY(); +} + +/******************************************************************************* + * prvTraceStoreObjectNameOnCloseEvent + * + * Updates the symbol table with the name of this object from the dynamic + * objects table and stores a "close" event, holding the mapping between handle + * and name (a symbol table handle). The stored name-handle mapping is thus the + * "old" one, valid up until this point. + ******************************************************************************/ +void prvTraceStoreObjectNameOnCloseEvent(uint8_t evtcode, traceHandle handle, + traceObjectClass objectclass) +{ + ObjCloseNameEvent * ce; + const char * name; + traceString idx; + + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "prvTraceStoreObjectNameOnCloseEvent: objectclass >= TRACE_NCLASSES", TRC_UNUSED); + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "prvTraceStoreObjectNameOnCloseEvent: Invalid value for handle", TRC_UNUSED); + + if (RecorderDataPtr->recorderActive) + { + uint8_t hnd8 = prvTraceGet8BitHandle(handle); + name = TRACE_PROPERTY_NAME_GET(objectclass, handle); + idx = prvTraceOpenSymbol(name, 0); + + // Interrupt disable not necessary, already done in trcHooks.h macro + ce = (ObjCloseNameEvent*) prvTraceNextFreeEventBufferSlot(); + if (ce != NULL) + { + ce->type = (uint8_t) evtcode; + ce->objHandle = hnd8; + ce->symbolIndex = idx; + prvTraceUpdateCounters(); + } + } +} + +void prvTraceStoreObjectPropertiesOnCloseEvent(uint8_t evtcode, traceHandle handle, + traceObjectClass objectclass) +{ + ObjClosePropEvent * pe; + + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "prvTraceStoreObjectPropertiesOnCloseEvent: objectclass >= TRACE_NCLASSES", TRC_UNUSED); + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "prvTraceStoreObjectPropertiesOnCloseEvent: Invalid value for handle", TRC_UNUSED); + + if (RecorderDataPtr->recorderActive) + { + // Interrupt disable not necessary, already done in trcHooks.h macro + pe = (ObjClosePropEvent*) prvTraceNextFreeEventBufferSlot(); + if (pe != NULL) + { + if (objectclass == TRACE_CLASS_TASK) + { + pe->arg1 = TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, handle); + } + else + { + pe->arg1 = TRACE_PROPERTY_OBJECT_STATE(objectclass, handle); + } + pe->type = evtcode; + prvTraceUpdateCounters(); + } + } +} + +void prvTraceSetPriorityProperty(uint8_t objectclass, traceHandle id, uint8_t value) +{ + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "prvTraceSetPriorityProperty: objectclass >= TRACE_NCLASSES", TRC_UNUSED); + TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "prvTraceSetPriorityProperty: Invalid value for id", TRC_UNUSED); + + TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id) = value; +} + +uint8_t prvTraceGetPriorityProperty(uint8_t objectclass, traceHandle id) +{ + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "prvTraceGetPriorityProperty: objectclass >= TRACE_NCLASSES", 0); + TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "prvTraceGetPriorityProperty: Invalid value for id", 0); + + return TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id); +} + +void prvTraceSetObjectState(uint8_t objectclass, traceHandle id, uint8_t value) +{ + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "prvTraceSetObjectState: objectclass >= TRACE_NCLASSES", TRC_UNUSED); + TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "prvTraceSetObjectState: Invalid value for id", TRC_UNUSED); + + TRACE_PROPERTY_OBJECT_STATE(objectclass, id) = value; +} + +uint8_t prvTraceGetObjectState(uint8_t objectclass, traceHandle id) +{ + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "prvTraceGetObjectState: objectclass >= TRACE_NCLASSES", 0); + TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "prvTraceGetObjectState: Invalid value for id", 0); + + return TRACE_PROPERTY_OBJECT_STATE(objectclass, id); +} + +void prvTraceSetTaskInstanceFinished(traceHandle handle) +{ + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_TASK], + "prvTraceSetTaskInstanceFinished: Invalid value for handle", TRC_UNUSED); + +#if (TRC_CFG_USE_IMPLICIT_IFE_RULES == 1) + TRACE_PROPERTY_OBJECT_STATE(TRACE_CLASS_TASK, handle) = 0; +#endif +} + +/******************************************************************************* + * Static data initializations + ******************************************************************************/ + +/* A set of stacks that keeps track of available object handles for each class. +The stacks are empty initially, meaning that allocation of new handles will be +based on a counter (for each object class). Any delete operation will +return the handle to the corresponding stack, for reuse on the next allocate.*/ +objectHandleStackType objectHandleStacks = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }; + +/* Initial TRC_HWTC_COUNT value, for detecting if the time-stamping source is +enabled. If using the OS periodic timer for time-stamping, this might not +have been configured on the earliest events during the startup. */ +uint32_t init_hwtc_count; + +/******************************************************************************* + * RecorderData + * + * The main data structure in snapshot mode, when using the default static memory + * allocation (TRC_RECORDER_BUFFER_ALLOCATION_STATIC). The recorder uses a pointer + * RecorderDataPtr to access the data, to also allow for dynamic or custom data + * allocation (see TRC_CFG_RECORDER_BUFFER_ALLOCATION). + ******************************************************************************/ +#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_STATIC) +RecorderDataType RecorderData; +#endif + +/******************************************************************************* + * RecorderDataPtr + * + * Pointer to the main data structure, when in snapshot mode. + ******************************************************************************/ +RecorderDataType* RecorderDataPtr = NULL; + +/* This version of the function dynamically allocates the trace data */ +void prvTraceInitTraceData() +{ + + if (RecorderDataPtr == NULL) + { +#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_STATIC) + RecorderDataPtr = &RecorderData; +#elif (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC) + RecorderDataPtr = (RecorderDataType*)TRACE_MALLOC(sizeof(RecorderDataType)); + if (! RecorderDataPtr) + { + prvTraceError("Failed allocating recorder buffer!"); + return; + } +#elif (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM) + if (! RecorderDataPtr) + { + prvTraceError("Recorder data pointer not set! Use vTraceSetRecorderDataBuffer()."); + return; + } +#endif + } + else + { + if (RecorderDataPtr->startmarker0 == 1) + { + /* Already initialized */ + return; + } + } + + init_hwtc_count = TRC_HWTC_COUNT; + + (void)memset(RecorderDataPtr, 0, sizeof(RecorderDataType)); + + RecorderDataPtr->version = TRACE_KERNEL_VERSION; + RecorderDataPtr->minor_version = TRACE_MINOR_VERSION; + RecorderDataPtr->irq_priority_order = TRC_IRQ_PRIORITY_ORDER; + RecorderDataPtr->filesize = sizeof(RecorderDataType); + RecorderDataPtr->maxEvents = (TRC_CFG_EVENT_BUFFER_SIZE); + RecorderDataPtr->debugMarker0 = (int32_t) 0xF0F0F0F0; + RecorderDataPtr->isUsing16bitHandles = TRC_CFG_USE_16BIT_OBJECT_HANDLES; + RecorderDataPtr->isrTailchainingThreshold = TRC_CFG_ISR_TAILCHAINING_THRESHOLD; + + /* This function is kernel specific */ + vTraceInitObjectPropertyTable(); + + RecorderDataPtr->debugMarker1 = (int32_t)0xF1F1F1F1; + RecorderDataPtr->SymbolTable.symTableSize = (TRC_CFG_SYMBOL_TABLE_SIZE); + RecorderDataPtr->SymbolTable.nextFreeSymbolIndex = 1; +#if (TRC_CFG_INCLUDE_FLOAT_SUPPORT == 1) + RecorderDataPtr->exampleFloatEncoding = 1.0f; /* otherwise already zero */ +#endif + RecorderDataPtr->debugMarker2 = (int32_t)0xF2F2F2F2; + prvStrncpy(RecorderDataPtr->systemInfo, "Trace Recorder Demo", 80); + RecorderDataPtr->debugMarker3 = (int32_t)0xF3F3F3F3; + RecorderDataPtr->endmarker0 = 0x0A; + RecorderDataPtr->endmarker1 = 0x0B; + RecorderDataPtr->endmarker2 = 0x0C; + RecorderDataPtr->endmarker3 = 0x0D; + RecorderDataPtr->endmarker4 = 0x71; + RecorderDataPtr->endmarker5 = 0x72; + RecorderDataPtr->endmarker6 = 0x73; + RecorderDataPtr->endmarker7 = 0x74; + RecorderDataPtr->endmarker8 = 0xF1; + RecorderDataPtr->endmarker9 = 0xF2; + RecorderDataPtr->endmarker10 = 0xF3; + RecorderDataPtr->endmarker11 = 0xF4; + +#if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER + RecorderDataPtr->userEventBuffer.bufferID = 1; + RecorderDataPtr->userEventBuffer.version = 0; + RecorderDataPtr->userEventBuffer.numberOfSlots = (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE); + RecorderDataPtr->userEventBuffer.numberOfChannels = (TRC_CFG_UB_CHANNELS) + 1; +#endif + + /* Kernel specific initialization of the objectHandleStacks variable */ + vTraceInitObjectHandleStack(); + + + /* Finally, the 12-byte "start markers" are initialized, allowing for + Tracealyzer to find the trace data in a larger RAM dump. + + The start and end markers must be unique, but without proper precautions there + might be a risk of accidental duplicates of the start/end markers, e.g., due to + compiler optimizations. + + The below initialization of the start marker is therefore made in reverse order + and the fields are volatile to ensure this assignment order. This to avoid any + chance of accidental duplicates of this elsewhere in memory. + + Moreover, the fields are set byte-by-byte to avoid endian issues.*/ + + RecorderDataPtr->startmarker11 = 0xF4; + RecorderDataPtr->startmarker10 = 0xF3; + RecorderDataPtr->startmarker9 = 0xF2; + RecorderDataPtr->startmarker8 = 0xF1; + RecorderDataPtr->startmarker7 = 0x74; + RecorderDataPtr->startmarker6 = 0x73; + RecorderDataPtr->startmarker5 = 0x72; + RecorderDataPtr->startmarker4 = 0x71; + RecorderDataPtr->startmarker3 = 0x04; + RecorderDataPtr->startmarker2 = 0x03; + RecorderDataPtr->startmarker1 = 0x02; + RecorderDataPtr->startmarker0 = 0x01; + + if (traceErrorMessage != NULL) + { + // An error was detected before vTraceEnable was called, make sure this is stored in the trace data. + prvStrncpy(RecorderDataPtr->systemInfo, traceErrorMessage, 80); + RecorderDataPtr->internalErrorOccured = 1; + vTraceStop(); + } + + + +#ifdef TRC_PORT_SPECIFIC_INIT + TRC_PORT_SPECIFIC_INIT(); +#endif +} + + +void* prvTraceNextFreeEventBufferSlot(void) +{ + if (! RecorderDataPtr->recorderActive) + { + /* If an XTS or XPS event prior to the main event has filled the buffer + before saving the main event, and store mode is "stop when full". */ + return NULL; + } + + if (RecorderDataPtr->nextFreeIndex >= (TRC_CFG_EVENT_BUFFER_SIZE)) + { + prvTraceError("Attempt to index outside event buffer!"); + return NULL; + } + return (void*)(&RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex*4]); +} + +uint16_t uiIndexOfObject(traceHandle objecthandle, uint8_t objectclass) +{ + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "uiIndexOfObject: Invalid value for objectclass", 0); + TRACE_ASSERT(objecthandle > 0 && objecthandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "uiIndexOfObject: Invalid value for objecthandle", 0); + + if ((objectclass < TRACE_NCLASSES) && (objecthandle > 0) && + (objecthandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass])) + { + return (uint16_t)(RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[objectclass] + + (RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[objectclass] * (objecthandle-1))); + } + + prvTraceError("Object table lookup with invalid object handle or object class!"); + return 0; +} + +traceHandle prvTraceGetObjectHandle(traceObjectClass objectclass) +{ + traceHandle handle; + static int indexOfHandle; + + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ASSERT(RecorderDataPtr != NULL, "Recorder not initialized, call vTraceEnable() first!", (traceHandle)0); + + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "prvTraceGetObjectHandle: Invalid value for objectclass", (traceHandle)0); + + trcCRITICAL_SECTION_BEGIN(); + indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass]; + if (objectHandleStacks.objectHandles[indexOfHandle] == 0) + { + /* Zero is used to indicate a never before used handle, i.e., + new slots in the handle stack. The handle slot needs to + be initialized here (starts at 1). */ + objectHandleStacks.objectHandles[indexOfHandle] = + (traceHandle)(1 + indexOfHandle - + objectHandleStacks.lowestIndexOfClass[objectclass]); + } + + handle = objectHandleStacks.objectHandles[indexOfHandle]; + + if (objectHandleStacks.indexOfNextAvailableHandle[objectclass] + > objectHandleStacks.highestIndexOfClass[objectclass]) + { + prvTraceError(pszTraceGetErrorNotEnoughHandles(objectclass)); + handle = 0; + } + else + { + int hndCount; + objectHandleStacks.indexOfNextAvailableHandle[objectclass]++; + + hndCount = objectHandleStacks.indexOfNextAvailableHandle[objectclass] - + objectHandleStacks.lowestIndexOfClass[objectclass]; + + if (hndCount > + objectHandleStacks.handleCountWaterMarksOfClass[objectclass]) + { + objectHandleStacks.handleCountWaterMarksOfClass[objectclass] = + (traceHandle)hndCount; + } + } + trcCRITICAL_SECTION_END(); + + return handle; +} + +void prvTraceFreeObjectHandle(traceObjectClass objectclass, traceHandle handle) +{ + int indexOfHandle; + + TRACE_ASSERT(objectclass < TRACE_NCLASSES, + "prvTraceFreeObjectHandle: Invalid value for objectclass", TRC_UNUSED); + TRACE_ASSERT(handle > 0 && handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], + "prvTraceFreeObjectHandle: Invalid value for handle", TRC_UNUSED); + + /* Check that there is room to push the handle on the stack */ + if ((objectHandleStacks.indexOfNextAvailableHandle[objectclass] - 1) < + objectHandleStacks.lowestIndexOfClass[objectclass]) + { + /* Error */ + prvTraceError("Attempt to free more handles than allocated!"); + } + else + { + objectHandleStacks.indexOfNextAvailableHandle[objectclass]--; + indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass]; + objectHandleStacks.objectHandles[indexOfHandle] = handle; + } +} + +/******************************************************************************* + * prvMarkObjectAsUsed + * + * Sets an "is used flag" on object creation, using the first byte of the name + * field. This allows for counting the number of used Object Table slots, even + * if no names have been set. + ******************************************************************************/ +void prvMarkObjectAsUsed(traceObjectClass objectclass, traceHandle handle) +{ + uint16_t idx = uiIndexOfObject(handle, objectclass); + RecorderDataPtr->ObjectPropertyTable.objbytes[idx] = 1; +} + +/******************************************************************************* + * prvStrncpy + * + * Private string copy function, to improve portability between compilers. + ******************************************************************************/ +static void prvStrncpy(char* dst, const char* src, uint32_t maxLength) +{ + uint32_t i; + for (i = 0; i < maxLength; i++) + { + dst[i] = src[i]; + if (src[i] == 0) + break; + } +} + +/******************************************************************************* + * prvTraceSetObjectName + * + * Registers the names of queues, semaphores and other kernel objects in the + * recorder's Object Property Table, at the given handle and object class. + ******************************************************************************/ +void prvTraceSetObjectName(traceObjectClass objectclass, + traceHandle handle, + const char* name) +{ + static uint16_t idx; + + TRACE_ASSERT(name != NULL, "prvTraceSetObjectName: name == NULL", TRC_UNUSED); + + if (objectclass >= TRACE_NCLASSES) + { + prvTraceError("Illegal object class in prvTraceSetObjectName"); + return; + } + + if (handle == 0) + { + prvTraceError("Illegal handle (0) in prvTraceSetObjectName."); + return; + } + + if (handle > RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass]) + { + /* ERROR */ + prvTraceError(pszTraceGetErrorNotEnoughHandles(objectclass)); + } + else + { + idx = uiIndexOfObject(handle, objectclass); + + if (traceErrorMessage == NULL) + { + prvStrncpy((char*)&(RecorderDataPtr->ObjectPropertyTable.objbytes[idx]), + name, + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[ objectclass ]); + } + } +} + +traceString prvTraceOpenSymbol(const char* name, traceString userEventChannel) +{ + uint16_t result; + uint8_t len; + uint8_t crc; + TRACE_ALLOC_CRITICAL_SECTION(); + + len = 0; + crc = 0; + + TRACE_ASSERT(name != NULL, "prvTraceOpenSymbol: name == NULL", (traceString)0); + + prvTraceGetChecksum(name, &crc, &len); + + trcCRITICAL_SECTION_BEGIN(); + result = prvTraceLookupSymbolTableEntry(name, crc, len, userEventChannel); + if (!result) + { + result = prvTraceCreateSymbolTableEntry(name, crc, len, userEventChannel); + } + trcCRITICAL_SECTION_END(); + + return result; +} + + +/****************************************************************************** +* vTraceSetFrequency +* +* Registers the clock rate of the time source for the event timestamping. +* This is normally not required, but if the default value (TRC_HWTC_FREQ_HZ) +* should be incorrect for your setup, you can override it using this function. +* +* Must be called prior to vTraceEnable, and the time source is assumed to +* have a fixed clock frequency after the startup. +* +* Note that, in snapshot mode, the value is divided by the TRC_HWTC_DIVISOR. +* This is a software "prescaler" that is also applied on the timestamps. +*****************************************************************************/ +void vTraceSetFrequency(uint32_t frequency) +{ + timestampFrequency = frequency; +} + +/******************************************************************************* + * Supporting functions + ******************************************************************************/ + +/******************************************************************************* + * prvTraceError + * + * Called by various parts in the recorder. Stops the recorder and stores a + * pointer to an error message, which is printed by the monitor task. + * If you are not using the monitor task, you may use xTraceGetLastError() + * from your application to check if the recorder is OK. + * + * Note: If a recorder error is registered before vTraceStart is called, the + * trace start will be aborted. This can occur if any of the Nxxxx constants + * (e.g., TRC_CFG_NTASK) in trcConfig.h is too small. + ******************************************************************************/ +void prvTraceError(const char* msg) +{ + /* Stop the recorder */ + if (RecorderDataPtr != NULL) + { + vTraceStop(); + } + + /* If first error only... */ + if (traceErrorMessage == NULL) + { + traceErrorMessage = (char*)(intptr_t) msg; + if (RecorderDataPtr != NULL) + { + prvStrncpy(RecorderDataPtr->systemInfo, traceErrorMessage, 80); + RecorderDataPtr->internalErrorOccured = 1; + } + } +} + +void vTraceSetFilterMask(uint16_t filterMask) +{ + CurrentFilterMask = filterMask; +} + +void vTraceSetFilterGroup(uint16_t filterGroup) +{ + CurrentFilterGroup = filterGroup; +} + +/****************************************************************************** + * prvCheckDataToBeOverwrittenForMultiEntryEvents + * + * This checks if the next event to be overwritten is a multi-entry user event, + * i.e., a USER_EVENT followed by data entries. + * Such data entries do not have an event code at byte 0, as other events. + * All 4 bytes are user data, so the first byte of such data events must + * not be interpreted as type field. The number of data entries following + * a USER_EVENT is given in the event code of the USER_EVENT. + * Therefore, when overwriting a USER_EVENT (when using in ring-buffer mode) + * any data entries following must be replaced with NULL events (code 0). + * + * This is assumed to execute within a critical section... + *****************************************************************************/ + +#if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER) +void prvCheckDataToBeOverwrittenForMultiEntryEvents(uint8_t nofEntriesToCheck) +{ + /* Generic "int" type is desired - should be 16 bit variable on 16 bit HW */ + unsigned int i = 0; + unsigned int e = 0; + + TRACE_ASSERT(nofEntriesToCheck != 0, + "prvCheckDataToBeOverwrittenForMultiEntryEvents: nofEntriesToCheck == 0", TRC_UNUSED); + + while (i < nofEntriesToCheck) + { + e = RecorderDataPtr->nextFreeIndex + i; + if ((RecorderDataPtr->eventData[e*4] > USER_EVENT) && + (RecorderDataPtr->eventData[e*4] < USER_EVENT + 16)) + { + uint8_t nDataEvents = (uint8_t)(RecorderDataPtr->eventData[e*4] - USER_EVENT); + if ((e + nDataEvents) < RecorderDataPtr->maxEvents) + { + (void)memset(& RecorderDataPtr->eventData[e*4], 0, (size_t) (4 + 4 * nDataEvents)); + } + } + else if (RecorderDataPtr->eventData[e*4] == DIV_XPS) + { + if ((e + 1) < RecorderDataPtr->maxEvents) + { + /* Clear 8 bytes */ + (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4 + 4); + } + else + { + /* Clear 8 bytes, 4 first and 4 last */ + (void)memset(& RecorderDataPtr->eventData[0], 0, 4); + (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4); + } + } + i++; + } +} +#endif + +/******************************************************************************* + * prvTraceUpdateCounters + * + * Updates the index of the event buffer. + ******************************************************************************/ +void prvTraceUpdateCounters(void) +{ + if (RecorderDataPtr->recorderActive == 0) + { + return; + } + + RecorderDataPtr->numEvents++; + + RecorderDataPtr->nextFreeIndex++; + + if (RecorderDataPtr->nextFreeIndex >= (TRC_CFG_EVENT_BUFFER_SIZE)) + { +#if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER) + RecorderDataPtr->bufferIsFull = 1; + RecorderDataPtr->nextFreeIndex = 0; +#else + vTraceStop(); +#endif + } + +#if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER) + prvCheckDataToBeOverwrittenForMultiEntryEvents(1); +#endif +} + +/****************************************************************************** + * prvTraceGetDTS + * + * Returns a differential timestamp (DTS), i.e., the time since + * last event, and creates an XTS event if the DTS does not fit in the + * number of bits given. The XTS event holds the MSB bytes of the DTS. + * + * The parameter param_maxDTS should be 0xFF for 8-bit dts or 0xFFFF for + * events with 16-bit dts fields. + *****************************************************************************/ +uint16_t prvTraceGetDTS(uint16_t param_maxDTS) +{ + static uint32_t old_timestamp = 0; + XTSEvent* xts = 0; + uint32_t dts = 0; + uint32_t timestamp = 0; + + TRACE_ASSERT(param_maxDTS == 0xFF || param_maxDTS == 0xFFFF, "prvTraceGetDTS: Invalid value for param_maxDTS", 0); + + + if (RecorderDataPtr->frequency == 0) + { + if (timestampFrequency != 0) + { + /* If to override default TRC_HWTC_FREQ_HZ value with value set by vTraceSetFrequency */ + RecorderDataPtr->frequency = timestampFrequency / (TRC_HWTC_DIVISOR); + } + else if (init_hwtc_count != (TRC_HWTC_COUNT)) + { + /* If using default value and timer has been started. + Note: If the default frequency value set here would be incorrect, e.g., + if the timer has actually not been configured yet, override this + with vTraceSetFrequency. + */ + RecorderDataPtr->frequency = (TRC_HWTC_FREQ_HZ) / (TRC_HWTC_DIVISOR); + } + /* If no override (vTraceSetFrequency) and timer inactive -> no action */ + } + + /************************************************************************** + * The below statements read the timestamp from the timer port module. + * If necessary, whole seconds are extracted using division while the rest + * comes from the modulo operation. + **************************************************************************/ + + prvTracePortGetTimeStamp(×tamp); + + /*************************************************************************** + * Since dts is unsigned the result will be correct even if timestamp has + * wrapped around. + ***************************************************************************/ + dts = timestamp - old_timestamp; + old_timestamp = timestamp; + + if (RecorderDataPtr->frequency > 0) + { + /* Check if dts > 1 second */ + if (dts > RecorderDataPtr->frequency) + { + /* More than 1 second has passed */ + RecorderDataPtr->absTimeLastEventSecond += dts / RecorderDataPtr->frequency; + /* The part that is not an entire second is added to absTimeLastEvent */ + RecorderDataPtr->absTimeLastEvent += dts % RecorderDataPtr->frequency; + } + else + { + RecorderDataPtr->absTimeLastEvent += dts; + } + + /* Check if absTimeLastEvent >= 1 second */ + if (RecorderDataPtr->absTimeLastEvent >= RecorderDataPtr->frequency) + { + /* RecorderDataPtr->absTimeLastEvent is more than or equal to 1 second, but always less than 2 seconds */ + RecorderDataPtr->absTimeLastEventSecond++; + RecorderDataPtr->absTimeLastEvent -= RecorderDataPtr->frequency; + /* RecorderDataPtr->absTimeLastEvent is now less than 1 second */ + } + } + else + { + /* Special case if the recorder has not yet started (frequency may be uninitialized, i.e., zero) */ + RecorderDataPtr->absTimeLastEvent = timestamp; + } + + /* If the dts (time since last event) does not fit in event->dts (only 8 or 16 bits) */ + if (dts > param_maxDTS) + { + /* Create an XTS event (eXtended TimeStamp) containing the higher dts bits*/ + xts = (XTSEvent*) prvTraceNextFreeEventBufferSlot(); + + if (xts != NULL) + { + if (param_maxDTS == 0xFFFF) + { + xts->type = XTS16; + xts->xts_16 = (uint16_t)((dts / 0x10000) & 0xFFFF); + xts->xts_8 = 0; + } + else if (param_maxDTS == 0xFF) + { + xts->type = XTS8; + xts->xts_16 = (uint16_t)((dts / 0x100) & 0xFFFF); + xts->xts_8 = (uint8_t)((dts / 0x1000000) & 0xFF); + } + else + { + prvTraceError("Bad param_maxDTS in prvTraceGetDTS"); + } + prvTraceUpdateCounters(); + } + } + + return (uint16_t)dts & param_maxDTS; +} + +/******************************************************************************* + * prvTraceLookupSymbolTableEntry + * + * Find an entry in the symbol table, return 0 if not present. + * + * The strings are stored in a byte pool, with four bytes of "meta-data" for + * every string. + * byte 0-1: index of next entry with same checksum (for fast lookup). + * byte 2-3: reference to a symbol table entry, a label for vTracePrintF + * format strings only (the handle of the destination channel). + * byte 4..(4 + length): the string (object name or user event label), with + * zero-termination + ******************************************************************************/ +traceString prvTraceLookupSymbolTableEntry(const char* name, + uint8_t crc6, + uint8_t len, + traceString chn) +{ + uint16_t i = RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ]; + + TRACE_ASSERT(name != NULL, "prvTraceLookupSymbolTableEntry: name == NULL", (traceString)0); + TRACE_ASSERT(len != 0, "prvTraceLookupSymbolTableEntry: len == 0", (traceString)0); + + while (i != 0) + { + if (RecorderDataPtr->SymbolTable.symbytes[i + 2] == (chn & 0x00FF)) + { + if (RecorderDataPtr->SymbolTable.symbytes[i + 3] == (chn / 0x100)) + { + if (RecorderDataPtr->SymbolTable.symbytes[i + 4 + len] == '\0') + { + if (strncmp((char*)(& RecorderDataPtr->SymbolTable.symbytes[i + 4]), name, len) == 0) + { + break; /* found */ + } + } + } + } + i = (uint16_t)(RecorderDataPtr->SymbolTable.symbytes[i] + (RecorderDataPtr->SymbolTable.symbytes[i + 1] * 0x100)); + } + return i; +} + +/******************************************************************************* + * prvTraceCreateSymbolTableEntry + * + * Creates an entry in the symbol table, independent if it exists already. + * + * The strings are stored in a byte pool, with four bytes of "meta-data" for + * every string. + * byte 0-1: index of next entry with same checksum (for fast lookup). + * byte 2-3: reference to a symbol table entry, a label for vTracePrintF + * format strings only (the handle of the destination channel). + * byte 4..(4 + length): the string (object name or user event label), with + * zero-termination + ******************************************************************************/ +uint16_t prvTraceCreateSymbolTableEntry(const char* name, + uint8_t crc6, + uint8_t len, + traceString channel) +{ + uint16_t ret = 0; + + TRACE_ASSERT(name != NULL, "prvTraceCreateSymbolTableEntry: name == NULL", 0); + TRACE_ASSERT(len != 0, "prvTraceCreateSymbolTableEntry: len == 0", 0); + + if (RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + len + 4 >= (TRC_CFG_SYMBOL_TABLE_SIZE)) + { + prvTraceError("Symbol table full. Increase TRC_CFG_SYMBOL_TABLE_SIZE in trcConfig.h"); + ret = 0; + } + else + { + + RecorderDataPtr->SymbolTable.symbytes + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex] = + (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] & 0x00FF); + + RecorderDataPtr->SymbolTable.symbytes + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 1] = + (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] / 0x100); + + RecorderDataPtr->SymbolTable.symbytes + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 2] = + (uint8_t)(channel & 0x00FF); + + RecorderDataPtr->SymbolTable.symbytes + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 3] = + (uint8_t)(channel / 0x100); + + /* set name (bytes 4...4+len-1) */ + prvStrncpy((char*)&(RecorderDataPtr->SymbolTable.symbytes + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4]), name, len); + + /* Set zero termination (at offset 4+len) */ + RecorderDataPtr->SymbolTable.symbytes + [RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4 + len] = '\0'; + + /* store index of entry (for return value, and as head of LL[crc6]) */ + RecorderDataPtr->SymbolTable.latestEntryOfChecksum + [ crc6 ] = (uint16_t)RecorderDataPtr->SymbolTable.nextFreeSymbolIndex; + + RecorderDataPtr->SymbolTable.nextFreeSymbolIndex += (uint32_t) (len + 5); + + ret = (uint16_t)(RecorderDataPtr->SymbolTable.nextFreeSymbolIndex - (uint8_t)(len + 5)); + } + + return ret; +} + + +/******************************************************************************* + * prvTraceGetChecksum + * + * Calculates a simple 6-bit checksum from a string, used to index the string + * for fast symbol table lookup. + ******************************************************************************/ +void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength) +{ + unsigned char c; + int length = 1; /* Should be 1 to account for '\0' */ + int crc = 0; + + TRACE_ASSERT(pname != NULL, "prvTraceGetChecksum: pname == NULL", TRC_UNUSED); + TRACE_ASSERT(pcrc != NULL, "prvTraceGetChecksum: pcrc == NULL", TRC_UNUSED); + TRACE_ASSERT(plength != NULL, "prvTraceGetChecksum: plength == NULL", TRC_UNUSED); + + if (pname != (const char *) 0) + { + for (; (c = (unsigned char) *pname++) != '\0';) + { + crc += c; + length++; + } + } + *pcrc = (uint8_t)(crc & 0x3F); + *plength = (uint8_t)length; +} + +#if (TRC_CFG_USE_16BIT_OBJECT_HANDLES == 1) + +static void prvTraceStoreXID(traceHandle handle); + +/****************************************************************************** + * prvTraceStoreXID + * + * Stores an XID (eXtended IDentifier) event. + * This is used if an object/task handle is larger than 255. + * The parameter "handle" is the full (16 bit) handle, assumed to be 256 or + * larger. Handles below 256 should not use this function. + * + * NOTE: this function MUST be called from within a critical section. + *****************************************************************************/ +static void prvTraceStoreXID(traceHandle handle) +{ + XPSEvent* xid; + + TRACE_ASSERT(handle >= 256, "prvTraceStoreXID: Handle < 256", TRC_UNUSED); + + xid = (XPSEvent*)prvTraceNextFreeEventBufferSlot(); + + if (xid != NULL) + { + xid->type = XID; + + /* This function is (only) used when traceHandle is 16 bit... */ + xid->xps_16 = handle; + + prvTraceUpdateCounters(); + } +} + +static uint8_t prvTraceGet8BitHandle(traceHandle handle) +{ + if (handle > 255) + { + prvTraceStoreXID(handle); + /* The full handle (16 bit) is stored in the XID event. + This code (255) is used instead of zero (which is an error code).*/ + return 255; + } + return (uint8_t)(handle & 0xFF); +} +#endif /*(TRC_CFG_USE_16BIT_OBJECT_HANDLES == 1)*/ + + +/* If using DWT timestamping (default on ARM Cortex-M3, M4 and M7), make sure the DWT unit is initialized. */ +#ifndef TRC_CFG_ARM_CM_USE_SYSTICK +#if ((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M) && (defined (__CORTEX_M) && (__CORTEX_M >= 0x03))) +void prvTraceInitCortexM() +{ + /* Ensure that the DWT registers are unlocked and can be modified. */ + TRC_REG_ITM_LOCKACCESS = TRC_ITM_LOCKACCESS_UNLOCK; + + /* Make sure DWT is enabled, if supported */ + TRC_REG_DEMCR |= TRC_DEMCR_TRCENA; + + do{ + /* Verify that DWT is supported */ + if (TRC_REG_DEMCR == 0) + { + /* This function is called on Cortex-M3, M4 and M7 devices to initialize + the DWT unit, assumed present. The DWT cycle counter is used for timestamping. + + If the below error is produced, the DWT unit does not seem to be available. + + In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build + to use SysTick timestamping instead, or define your own timestamping by + setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED + and make the necessary definitions, as explained in trcHardwarePort.h.*/ + + prvTraceError("DWT unit not available, see code comment."); + break; + } + + /* Verify that DWT_CYCCNT is supported */ + if (TRC_REG_DWT_CTRL & TRC_DWT_CTRL_NOCYCCNT) + { + /* This function is called on Cortex-M3, M4 and M7 devices to initialize + the DWT unit, assumed present. The DWT cycle counter is used for timestamping. + + If the below error is produced, the cycle counter does not seem to be available. + + In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build + to use SysTick timestamping instead, or define your own timestamping by + setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED + and make the necessary definitions, as explained in trcHardwarePort.h.*/ + + prvTraceError("DWT_CYCCNT not available, see code comment."); + break; + } + + /* Reset the cycle counter */ + TRC_REG_DWT_CYCCNT = 0; + + /* Enable the cycle counter */ + TRC_REG_DWT_CTRL |= TRC_DWT_CTRL_CYCCNTENA; + + }while(0); /* breaks above jump here */ +} +#endif +#endif + +/****************************************************************************** + * prvTracePortGetTimeStamp + * + * Returns the current time based on the HWTC macros which provide a hardware + * isolation layer towards the hardware timer/counter. + * + * The HWTC macros and prvTracePortGetTimeStamp is the main porting issue + * or the trace recorder library. Typically you should not need to change + * the code of prvTracePortGetTimeStamp if using the HWTC macros. + * + ******************************************************************************/ +void prvTracePortGetTimeStamp(uint32_t *pTimestamp) +{ + static uint32_t last_hwtc_count = 0; + uint32_t hwtc_count = 0; + +#if TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR + /* systick based timer */ + static uint32_t last_traceTickCount = 0; + uint32_t traceTickCount = 0; +#else /*TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR*/ + /* Free running timer */ + static uint32_t last_hwtc_rest = 0; + uint32_t diff = 0; + uint32_t diff_scaled = 0; +#endif /*TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR*/ + + if (trace_disable_timestamp == 1) + { + if (pTimestamp) + *pTimestamp = last_timestamp; + return; + } + + /* Retrieve TRC_HWTC_COUNT only once since the same value should be used all throughout this function. */ +#if (TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_INCR) + /* Get the increasing tick count */ + hwtc_count = (TRC_HWTC_COUNT); +#elif (TRC_HWTC_TYPE == TRC_OS_TIMER_DECR || TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_DECR) + /* Convert decreasing tick count into increasing tick count */ + hwtc_count = (TRC_HWTC_PERIOD) - (TRC_HWTC_COUNT); +#else + #error "TRC_HWTC_TYPE has unexpected value" +#endif + +#if (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_Win32) + /* The Win32 port uses ulGetRunTimeCounterValue for timestamping, which in turn + uses QueryPerformanceCounter. That function is not always reliable when used over + multiple threads. We must therefore handle rare cases where the timestamp is less + than the previous. In practice, this should "never" roll over since the + performance counter is 64 bit wide. */ + + if (last_hwtc_count > hwtc_count) + { + hwtc_count = last_hwtc_count; + } +#endif + +#if (TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR) + /* Timestamping is based on a timer that wraps at TRC_HWTC_PERIOD */ + if (last_traceTickCount - uiTraceTickCount - 1 < 0x80000000) + { + /* This means last_traceTickCount is higher than uiTraceTickCount, + so we have previously compensated for a missed tick. + Therefore we use the last stored value because that is more accurate. */ + traceTickCount = last_traceTickCount; + } + else + { + /* Business as usual */ + traceTickCount = uiTraceTickCount; + } + + /* Check for overflow. May occur if the update of uiTraceTickCount has been + delayed due to disabled interrupts. */ + if (traceTickCount == last_traceTickCount && hwtc_count < last_hwtc_count) + { + /* A trace tick has occurred but not been executed by the kernel, so we compensate manually. */ + traceTickCount++; + } + + /* Check if the return address is OK, then we perform the calculation. */ + if (pTimestamp) + { + /* Get timestamp from trace ticks. Scale down the period to avoid unwanted overflows. */ + last_timestamp = traceTickCount * ((TRC_HWTC_PERIOD) / (TRC_HWTC_DIVISOR)); + /* Increase timestamp by (hwtc_count + "lost hardware ticks from scaling down period") / TRC_HWTC_DIVISOR. */ + last_timestamp += (hwtc_count + traceTickCount * ((TRC_HWTC_PERIOD) % (TRC_HWTC_DIVISOR))) / (TRC_HWTC_DIVISOR); + } + /* Store the previous value */ + last_traceTickCount = traceTickCount; + +#else /*(TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR)*/ + + /* Timestamping is based on a free running timer */ + /* This part handles free running clocks that can be scaled down to avoid too large DTS values. + Without this, the scaled timestamp will incorrectly wrap at (2^32 / TRC_HWTC_DIVISOR) ticks. + The scaled timestamp returned from this function is supposed to go from 0 -> 2^32, which in real time would represent (0 -> 2^32 * TRC_HWTC_DIVISOR) ticks. */ + + /* First we see how long time has passed since the last timestamp call, and we also add the ticks that was lost when we scaled down the last time. */ + diff = (hwtc_count - last_hwtc_count) + last_hwtc_rest; + + /* Scale down the diff */ + diff_scaled = diff / (TRC_HWTC_DIVISOR); + + /* Find out how many ticks were lost when scaling down, so we can add them the next time */ + last_hwtc_rest = diff % (TRC_HWTC_DIVISOR); + + /* We increase the scaled timestamp by the scaled amount */ + last_timestamp += diff_scaled; +#endif /*(TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR)*/ + + /* Is anyone interested in the results? */ + if (pTimestamp) + *pTimestamp = last_timestamp; + + /* Store the previous value */ + last_hwtc_count = hwtc_count; +} + +#endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/ + +#endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)*/ diff --git a/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/trcStreamingRecorder.c b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/trcStreamingRecorder.c new file mode 100644 index 000000000..dc1b87865 --- /dev/null +++ b/FreeRTOS-Labs/Source/FreeRTOS-Plus-Trace/trcStreamingRecorder.c @@ -0,0 +1,1896 @@ +/******************************************************************************* + * Trace Recorder Library for Tracealyzer v4.1.5 + * Percepio AB, www.percepio.com + * + * trcStreamingRecorder.c + * + * The generic core of the trace recorder's streaming mode. + * + * Terms of Use + * This file is part of the trace recorder library (RECORDER), which is the + * intellectual property of Percepio AB (PERCEPIO) and provided under a + * license as follows. + * The RECORDER may be used free of charge for the purpose of recording data + * intended for analysis in PERCEPIO products. It may not be used or modified + * for other purposes without explicit permission from PERCEPIO. + * You may distribute the RECORDER in its original source code form, assuming + * this text (terms of use, disclaimer, copyright notice) is unchanged. You are + * allowed to distribute the RECORDER with minor modifications intended for + * configuration or porting of the RECORDER, e.g., to allow using it on a + * specific processor, processor family or with a specific communication + * interface. Any such modifications should be documented directly below + * this comment block. + * + * Disclaimer + * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty + * as to its use or performance. PERCEPIO does not and cannot warrant the + * performance or results you may obtain by using the RECORDER or documentation. + * PERCEPIO make no warranties, express or implied, as to noninfringement of + * third party rights, merchantability, or fitness for any particular purpose. + * In no event will PERCEPIO, its technology partners, or distributors be liable + * to you for any consequential, incidental or special damages, including any + * lost profits or lost savings, even if a representative of PERCEPIO has been + * advised of the possibility of such damages, or for any claim by any third + * party. Some jurisdictions do not allow the exclusion or limitation of + * incidental, consequential or special damages, or the exclusion of implied + * warranties or limitations on how long an implied warranty may last, so the + * above limitations may not apply to you. + * + * Tabs are used for indent in this file (1 tab = 4 spaces) + * + * Copyright Percepio AB, 2018. + * www.percepio.com + ******************************************************************************/ + +#include "trcRecorder.h" + +#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) + +#if (TRC_USE_TRACEALYZER_RECORDER == 1) + +#include +#include + +typedef struct{ + uint16_t EventID; + uint16_t EventCount; + uint32_t TS; +} BaseEvent; + +typedef struct{ + BaseEvent base; + uint32_t param1; +} EventWithParam_1; + +typedef struct{ + BaseEvent base; + uint32_t param1; + uint32_t param2; +} EventWithParam_2; + +typedef struct{ + BaseEvent base; + uint32_t param1; + uint32_t param2; + uint32_t param3; +} EventWithParam_3; + +/* Used in event functions with variable number of parameters. */ +typedef struct +{ + BaseEvent base; + uint32_t data[15]; /* maximum payload size */ +} largestEventType; + +typedef struct{ + uint32_t psf; + uint16_t version; + uint16_t platform; + uint32_t options; + uint16_t symbolSize; + uint16_t symbolCount; + uint16_t objectDataSize; + uint16_t objectDataCount; +} PSFHeaderInfo; + + +/* The size of each slot in the Symbol Table */ +#define SYMBOL_TABLE_SLOT_SIZE (sizeof(uint32_t) + (((TRC_CFG_SYMBOL_MAX_LENGTH)+(sizeof(uint32_t)-1))/sizeof(uint32_t))*sizeof(uint32_t)) + +#define OBJECT_DATA_SLOT_SIZE (sizeof(uint32_t) + sizeof(uint32_t)) + +/* The total size of the Symbol Table */ +#define SYMBOL_TABLE_BUFFER_SIZE ((TRC_CFG_SYMBOL_TABLE_SLOTS) * SYMBOL_TABLE_SLOT_SIZE) + +/* The total size of the Object Data Table */ +#define OBJECT_DATA_TABLE_BUFFER_SIZE ((TRC_CFG_OBJECT_DATA_SLOTS) * OBJECT_DATA_SLOT_SIZE) + +/* The Symbol Table type - just a byte array */ +typedef struct{ + union + { + uint32_t pSymbolTableBufferUINT32[SYMBOL_TABLE_BUFFER_SIZE / sizeof(uint32_t)]; + uint8_t pSymbolTableBufferUINT8[SYMBOL_TABLE_BUFFER_SIZE]; + } SymbolTableBuffer; +} SymbolTable; + +/* The Object Data Table type - just a byte array */ +typedef struct{ + union + { + uint32_t pObjectDataTableBufferUINT32[OBJECT_DATA_TABLE_BUFFER_SIZE / sizeof(uint32_t)]; + uint8_t pObjectDataTableBufferUINT8[OBJECT_DATA_TABLE_BUFFER_SIZE]; + } ObjectDataTableBuffer; +} ObjectDataTable; + +typedef struct{ + uint16_t Status; /* 16 bit to avoid implicit padding (warnings) */ + uint16_t BytesRemaining; + char* WritePointer; +} PageType; + +/* Code used for "task address" when no task has started. (NULL = idle task) */ +#define HANDLE_NO_TASK 2 + +#define PAGE_STATUS_FREE 0 +#define PAGE_STATUS_WRITE 1 +#define PAGE_STATUS_READ 2 + +#define PSF_ASSERT(_assert, _err) if (! (_assert)){ prvTraceError(_err); return; } + +/* Part of the PSF format - encodes the number of 32-bit params in an event */ +#define PARAM_COUNT(n) ((n & 0xF) << 12) + +/* The Symbol Table instance - keeps names of tasks and other named objects. */ +static SymbolTable symbolTable = { { { 0 } } }; + +/* This points to the first unused entry in the symbol table. */ +static uint32_t firstFreeSymbolTableIndex = 0; + +/* The Object Data Table instance - keeps initial priorities of tasks. */ +static ObjectDataTable objectDataTable = { { { 0 } } }; + +/* This points to the first unused entry in the object data table. */ +static uint32_t firstFreeObjectDataTableIndex = 0; + +/* Keeps track of ISR nesting */ +static uint32_t ISR_stack[TRC_CFG_MAX_ISR_NESTING]; + +/* Keeps track of ISR nesting */ +static int8_t ISR_stack_index = -1; + +/* Any error that occurred in the recorder (also creates User Event) */ +static int errorCode = 0; + +/* Counts the number of trace sessions (not yet used) */ +static uint32_t SessionCounter = 0u; + +/* Master switch for recording (0 => Disabled, 1 => Enabled) */ +uint32_t RecorderEnabled = 0u; + +/* Used to determine endian of data (big/little) */ +static uint32_t PSFEndianessIdentifier = 0x50534600; + +/* Used to interpret the data format */ +static uint16_t FormatVersion = 0x0004; + +/* The number of events stored. Used as event sequence number. */ +static uint32_t eventCounter = 0; + +/* Remembers if an earlier ISR in a sequence of adjacent ISRs has triggered a task switch. +In that case, vTraceStoreISREnd does not store a return to the previously executing task. */ +int32_t isPendingContextSwitch = 0; + +uint32_t uiTraceTickCount = 0; +uint32_t timestampFrequency = 0; +uint32_t DroppedEventCounter = 0; +uint32_t TotalBytesRemaining_LowWaterMark = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT) * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE); +uint32_t TotalBytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT) * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE); + +PageType PageInfo[TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT]; + +char* EventBuffer = NULL; + +/******************************************************************************* + * NoRoomForSymbol + * + * Incremented on prvTraceSaveSymbol if no room for saving the symbol name. This + * is used for storing the names of: + * - Tasks + * - Named ISRs (xTraceSetISRProperties) + * - Named kernel objects (vTraceStoreKernelObjectName) + * - User event channels (xTraceRegisterString) + * + * This variable should be zero. If not, it shows the number of missing slots so + * far. In that case, increment SYMBOL_TABLE_SLOTS with (at least) this value. + ******************************************************************************/ +volatile uint32_t NoRoomForSymbol = 0; + +/******************************************************************************* + * NoRoomForObjectData + * + * Incremented on prvTraceSaveObjectData if no room for saving the object data, + * i.e., the base priorities of tasks. There must be one slot for each task. + * If not, this variable will show the difference. + * + * This variable should be zero. If not, it shows the number of missing slots so + * far. In that case, increment OBJECT_DATA_SLOTS with (at least) this value. + ******************************************************************************/ +volatile uint32_t NoRoomForObjectData = 0; + +/******************************************************************************* + * LongestSymbolName + * + * Updated in prvTraceSaveSymbol. Should not exceed TRC_CFG_SYMBOL_MAX_LENGTH, + * otherwise symbol names will be truncated. In that case, set + * TRC_CFG_SYMBOL_MAX_LENGTH to (at least) this value. + ******************************************************************************/ +volatile uint32_t LongestSymbolName = 0; + +/******************************************************************************* + * MaxBytesTruncated + * + * Set in prvTraceStoreStringEvent if the total data payload exceeds 60 bytes, + * including data arguments and the string. For user events, that is 52 bytes + * for string and data arguments. In that is exceeded, the event is truncated + * (usually only the string, unless more than 15 parameters) and this variable + * holds the maximum number of truncated bytes, from any event. + ******************************************************************************/ +volatile uint32_t MaxBytesTruncated = 0; + +uint16_t CurrentFilterMask = 0xFFFF; + +uint16_t CurrentFilterGroup = FilterGroup0; + +/* Internal common function for storing string events */ +static void prvTraceStoreStringEventHelper( int nArgs, + uint16_t eventID, + traceString userEvtChannel, + int len, + const char* str, + va_list* vl); + +/* Not static to avoid warnings from SysGCC/PPC */ +void prvTraceStoreSimpleStringEventHelper(traceString userEvtChannel, + const char* str); + + +/* Stores the header information on Start */ +static void prvTraceStoreHeader(void); + +/* Stores the symbol table on Start */ +static void prvTraceStoreSymbolTable(void); + +/* Stores the object table on Start */ +static void prvTraceStoreObjectDataTable(void); + +/* Store the Timestamp Config on Start */ +static void prvTraceStoreTSConfig(void); + +/* Store the current warnings */ +static void prvTraceStoreWarnings(void); + +/* Internal function for starting/stopping the recorder. */ +static void prvSetRecorderEnabled(uint32_t isEnabled); + +/* Mark the page read as complete. */ +static void prvPageReadComplete(int pageIndex); + +/* Retrieve a buffer page to write to. */ +static int prvAllocateBufferPage(int prevPage); + +/* Get the current buffer page index (return value) and the number +of valid bytes in the buffer page (bytesUsed). */ +static int prvGetBufferPage(int32_t* bytesUsed); + +/* Performs timestamping using definitions in trcHardwarePort.h */ +static uint32_t prvGetTimestamp32(void); + +/* Signal an error. */ +void prvTraceError(int errCode); + +/* Signal an warning (does not stop the recorder). */ +void prvTraceWarning(int errCode); + +/****************************************************************************** + * vTraceInstanceFinishedNow + * + * Creates an event that ends the current task instance at this very instant. + * This makes the viewer to splits the current fragment at this point and begin + * a new actor instance, even if no task-switch has occurred. + *****************************************************************************/ +void vTraceInstanceFinishedNow(void) +{ + prvTraceStoreEvent0(PSF_EVENT_IFE_DIRECT); +} + +/****************************************************************************** + * vTraceInstanceFinishedNext + * + * Marks the current "task instance" as finished on the next kernel call. + * + * If that kernel call is blocking, the instance ends after the blocking event + * and the corresponding return event is then the start of the next instance. + * If the kernel call is not blocking, the viewer instead splits the current + * fragment right before the kernel call, which makes this call the first event + * of the next instance. + *****************************************************************************/ +void vTraceInstanceFinishedNext(void) +{ + prvTraceStoreEvent0(PSF_EVENT_IFE_NEXT); +} + +/******************************************************************************* + * vTraceStoreKernelObjectName + * + * Parameter object: pointer to the Event Group that shall be named + * Parameter name: the name to set (const string literal) + * + * Sets a name for a kernel object for display in Tracealyzer. + ******************************************************************************/ +void vTraceStoreKernelObjectName(void* object, const char* name) +{ + /* Always save in symbol table, if the recording has not yet started */ + prvTraceSaveSymbol(object, name); + + prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, name, (uint32_t)object); +} + + +/****************************************************************************** +* vTraceSetFrequency +* +* Registers the clock rate of the time source for the event timestamping. +* This is normally not required, but if the default value (TRC_HWTC_FREQ_HZ) +* should be incorrect for your setup, you can override it using this function. +* +* Must be called prior to vTraceEnable, and the time source is assumed to +* have a fixed clock frequency after the startup. +*****************************************************************************/ +void vTraceSetFrequency(uint32_t frequency) +{ + timestampFrequency = frequency; +} + +#if (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) + +/******************************************************************************* +* xTraceRegisterString +* +* Stores a name for a user event channel, returns the handle. +******************************************************************************/ +traceString xTraceRegisterString(const char* name) +{ + prvTraceSaveSymbol((const void*)name, name); + + /* Always save in symbol table, if the recording has not yet started */ + prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, (const char*)name, (uint32_t)name); + + return (traceString)name; +} + +/****************************************************************************** + * vTracePrint + * + * Generates "User Events", with unformatted text. + * + * User Events can be used for very efficient application logging, and are shown + * as yellow labels in the main trace view. + * + * You may group User Events into User Event Channels. The yellow User Event + * labels shows the logged string, preceded by the channel name within + * brackets. For example: + * + * "[MyChannel] Hello World!" + * + * The User Event Channels are shown in the View Filter, which makes it easy to + * select what User Events you wish to display. User Event Channels are created + * using xTraceRegisterString(). + * + * Example: + * + * traceString chn = xTraceRegisterString("MyChannel"); + * ... + * vTracePrint(chn, "Hello World!"); + * + ******************************************************************************/ +void vTracePrint(traceString chn, const char* str) +{ + prvTraceStoreSimpleStringEventHelper(chn, str); +} + + +/******************************************************************************* +* vTraceConsoleChannelPrintF +* +* Wrapper for vTracePrint, using the default channel. Can be used as a drop-in +* replacement for printf and similar functions, e.g. in a debug logging macro. +* +* Example: +* +* // Old: #define LogString debug_console_printf +* +* // New, log to Tracealyzer instead: +* #define LogString vTraceConsoleChannelPrintF +* ... +* LogString("My value is: %d", myValue); +******************************************************************************/ +void vTraceConsoleChannelPrintF(const char* fmt, ...) +{ + va_list vl; + char tempBuf[60]; + static traceString consoleChannel = NULL; + + if (consoleChannel == NULL) + consoleChannel = xTraceRegisterString("Debug Console"); + + va_start(vl, fmt); + vsnprintf(tempBuf, 60, fmt, vl); + vTracePrint(consoleChannel, tempBuf); + va_end(vl); +} + +/****************************************************************************** + * vTracePrintF + * + * Generates "User Events", with formatted text and data, similar to a "printf". + * It is very fast since the actual formatting is done on the host side when the + * trace is displayed. + * + * User Events can be used for very efficient application logging, and are shown + * as yellow labels in the main trace view. + * An advantage of User Events is that data can be plotted in the "User Event + * Signal Plot" view, visualizing any data you log as User Events, discrete + * states or control system signals (e.g. system inputs or outputs). + * + * You may group User Events into User Event Channels. The yellow User Event + * labels show the logged string, preceded by the channel name within brackets. + * + * Example: + * + * "[MyChannel] Hello World!" + * + * The User Event Channels are shown in the View Filter, which makes it easy to + * select what User Events you wish to display. User Event Channels are created + * using xTraceRegisterString(). + * + * Example: + * + * traceString adc_uechannel = xTraceRegisterString("ADC User Events"); + * ... + * vTracePrintF(adc_uechannel, + * "ADC channel %d: %d volts", + * ch, adc_reading); + * + * All data arguments are assumed to be 32 bit wide. The following formats are + * supported: + * %d - signed integer. The following width and padding format is supported: "%05d" -> "-0042" and "%5d" -> " -42" + * %u - unsigned integer. The following width and padding format is supported: "%05u" -> "00042" and "%5u" -> " 42" + * %X - hexadecimal (uppercase). The following width and padding format is supported: "%04X" -> "002A" and "%4X" -> " 2A" + * %x - hexadecimal (lowercase). The following width and padding format is supported: "%04x" -> "002a" and "%4x" -> " 2a" + * %s - string (currently, this must be an earlier stored symbol name) + * + * Up to 15 data arguments are allowed, with a total size of maximum 60 byte + * including 8 byte for the base event fields and the format string. So with + * one data argument, the maximum string length is 48 chars. If this is exceeded + * the string is truncated (4 bytes at a time). + * + ******************************************************************************/ +void vTracePrintF(traceString chn, const char* fmt, ...) +{ + va_list vl; + int i = 0; + + int nArgs = 0; + + /* Count the number of arguments in the format string (e.g., %d) */ + for (i = 0; (fmt[i] != 0) && (i < 52); i++) + { + if (fmt[i] == '%') + { + if (fmt[i + 1] != 0 && fmt[i + 1] != '%') + { + nArgs++; /* Found an argument */ + } + + i++; /* Move past format specifier or non-argument '%' */ + } + } + + va_start(vl, fmt); + + if (chn != NULL) + { + prvTraceStoreStringEventHelper(nArgs, (uint16_t)(PSF_EVENT_USER_EVENT + nArgs + 1), chn, i, fmt, &vl); + } + else + { + prvTraceStoreStringEventHelper(nArgs, (uint16_t)(PSF_EVENT_USER_EVENT + nArgs), chn, i, fmt, &vl); + } + va_end(vl); +} +#endif /* (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) */ + +/******************************************************************************* + * xTraceSetISRProperties + * + * Stores a name and priority level for an Interrupt Service Routine, to allow + * for better visualization. Returns a traceHandle used by vTraceStoreISRBegin. + * + * Example: + * #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt + * ... + * traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(Timer1Handle); + * ... + * vTraceStoreISREnd(0); + * } + * + ******************************************************************************/ +traceHandle xTraceSetISRProperties(const char* name, uint8_t priority) +{ + /* Save object data in object data table */ + prvTraceSaveObjectData((const void*)name, priority); + + /* Note: "name" is used both as a string argument, and the address as ID */ + prvTraceStoreStringEvent(2, PSF_EVENT_DEFINE_ISR, name, name, priority); + + /* Always save in symbol table, if the recording has not yet started */ + prvTraceSaveSymbol((const void*)name, name); + + return (traceHandle)name; +} + +/******************************************************************************* + * vTraceStoreISRBegin + * + * Registers the beginning of an Interrupt Service Routine, using a traceHandle + * provided by xTraceSetISRProperties. + * + * Example: + * #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt + * ... + * traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(Timer1Handle); + * ... + * vTraceStoreISREnd(0); + * } + * + ******************************************************************************/ +void vTraceStoreISRBegin(traceHandle handle) +{ + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ENTER_CRITICAL_SECTION(); + + /* We are at the start of a possible ISR chain. + No context switches should have been triggered now. */ + if (ISR_stack_index == -1) + isPendingContextSwitch = 0; + + if (ISR_stack_index < (TRC_CFG_MAX_ISR_NESTING) - 1) + { + ISR_stack_index++; + ISR_stack[ISR_stack_index] = (uint32_t)handle; +#if (TRC_CFG_INCLUDE_ISR_TRACING == 1) + prvTraceStoreEvent1(PSF_EVENT_ISR_BEGIN, (uint32_t)handle); +#endif + TRACE_EXIT_CRITICAL_SECTION(); + } + else + { + TRACE_EXIT_CRITICAL_SECTION(); + prvTraceError(PSF_ERROR_ISR_NESTING_OVERFLOW); + } +} + +/******************************************************************************* + * vTraceStoreISREnd + * + * Registers the end of an Interrupt Service Routine. + * + * The parameter pendingISR indicates if the interrupt has requested a + * task-switch (= 1), e.g., by signaling a semaphore. Otherwise (= 0) the + * interrupt is assumed to return to the previous context. + * + * Example: + * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt + * traceHandle traceHandleIsrTimer1 = 0; // The ID set by the recorder + * ... + * traceHandleIsrTimer1 = xTraceSetISRProperties("ISRTimer1", PRIO_OF_ISR_TIMER1); + * ... + * void ISR_handler() + * { + * vTraceStoreISRBegin(traceHandleIsrTimer1); + * ... + * vTraceStoreISREnd(0); + * } + * + ******************************************************************************/ +void vTraceStoreISREnd(int isTaskSwitchRequired) +{ + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ENTER_CRITICAL_SECTION(); + + (void)ISR_stack; + + /* Is there a pending task-switch? (perhaps from an earlier ISR) */ + isPendingContextSwitch |= isTaskSwitchRequired; + + if (ISR_stack_index > 0) + { + ISR_stack_index--; + +#if (TRC_CFG_INCLUDE_ISR_TRACING == 1) + /* Store return to interrupted ISR (if nested ISRs)*/ + prvTraceStoreEvent1(PSF_EVENT_ISR_RESUME, (uint32_t)ISR_stack[ISR_stack_index]); +#endif + } + else + { + ISR_stack_index--; + + /* Store return to interrupted task, if no context switch will occur in between. */ + if ((isPendingContextSwitch == 0) || (prvTraceIsSchedulerSuspended())) + { +#if (TRC_CFG_INCLUDE_ISR_TRACING == 1) + prvTraceStoreEvent1(PSF_EVENT_TS_RESUME, (uint32_t)TRACE_GET_CURRENT_TASK()); +#endif + } + } + + TRACE_EXIT_CRITICAL_SECTION(); +} + + +/******************************************************************************* + * xTraceGetLastError + * + * Returns the last error or warning, as a string, or NULL if none. + *****************************************************************************/ +const char* xTraceGetLastError(void) +{ + /* Note: the error messages are short, in order to fit in a User Event. + Instead, the users can read more in the below comments.*/ + + switch (errorCode) + { + + case PSF_WARNING_SYMBOL_TABLE_SLOTS: + /* There was not enough symbol table slots for storing symbol names. + The number of missing slots is counted by NoRoomForSymbol. Inspect this + variable and increase TRC_CFG_SYMBOL_TABLE_SLOTS by at least that value. */ + + return "Exceeded SYMBOL_TABLE_SLOTS (see xTraceGetLastError)"; + + case PSF_WARNING_SYMBOL_MAX_LENGTH: + /* A symbol name exceeded TRC_CFG_SYMBOL_MAX_LENGTH in length. + Make sure the symbol names are at most TRC_CFG_SYMBOL_MAX_LENGTH, + or inspect LongestSymbolName and increase TRC_CFG_SYMBOL_MAX_LENGTH + to at least this value. */ + + return "Exceeded SYMBOL_MAX_LENGTH (see xTraceGetLastError)"; + + case PSF_WARNING_OBJECT_DATA_SLOTS: + /* There was not enough symbol object table slots for storing object + properties, such as task priorites. The number of missing slots is + counted by NoRoomForObjectData. Inspect this variable and increase + TRC_CFG_OBJECT_DATA_SLOTS by at least that value. */ + + return "Exceeded OBJECT_DATA_SLOTS (see xTraceGetLastError)"; + + case PSF_WARNING_STRING_TOO_LONG: + /* Some string argument was longer than the maximum payload size + and has been truncated by "MaxBytesTruncated" bytes. + + This may happen for the following functions: + - vTracePrint + - vTracePrintF + - vTraceStoreKernelObjectName + - xTraceRegisterString + - vTraceSetISRProperties + + A PSF event may store maximum 60 bytes payload, including data + arguments and string characters. For User Events, also the User + Event Channel (4 bytes) must be squeezed in, if a channel is + specified (can be NULL). */ + + return "String too long (see xTraceGetLastError)"; + + case PSF_WARNING_STREAM_PORT_READ: + /* TRC_STREAM_PORT_READ_DATA is expected to return 0 when completed successfully. + This means there is an error in the communication with host/Tracealyzer. */ + + return "TRC_STREAM_PORT_READ_DATA returned error (!= 0)."; + + case PSF_WARNING_STREAM_PORT_WRITE: + /* TRC_STREAM_PORT_WRITE_DATA is expected to return 0 when completed successfully. + This means there is an error in the communication with host/Tracealyzer. */ + + return "TRC_STREAM_PORT_WRITE_DATA returned error (!= 0)."; + + case PSF_ERROR_EVENT_CODE_TOO_LARGE: + /* The highest allowed event code is 4095, anything higher is an unexpected error. + Please contact support@percepio.com for assistance.*/ + + return "Invalid event code (see xTraceGetLastError)"; + + case PSF_ERROR_ISR_NESTING_OVERFLOW: + /* Nesting of ISR trace calls exceeded the limit (TRC_CFG_MAX_ISR_NESTING). + If this is unlikely, make sure that you call vTraceStoreISRExit in the end + of all ISR handlers. Or increase TRC_CFG_MAX_ISR_NESTING. */ + + return "Exceeded ISR nesting (see xTraceGetLastError)"; + + case PSF_ERROR_DWT_NOT_SUPPORTED: + /* On ARM Cortex-M only - failed to initialize DWT Cycle Counter since not supported by this chip. + DWT timestamping is selected automatically for ART Cortex-M3, M4 and higher, based on the __CORTEX_M + macro normally set by ARM's CMSIS library, since typically available. You can however select + SysTick timestamping instead by defining adding "#define TRC_CFG_ARM_CM_USE_SYSTICK".*/ + + return "DWT not supported (see xTraceGetLastError)"; + + case PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED: + /* On ARM Cortex-M only - failed to initialize DWT Cycle Counter since not supported by this chip. + DWT timestamping is selected automatically for ART Cortex-M3, M4 and higher, based on the __CORTEX_M + macro normally set by ARM's CMSIS library, since typically available. You can however select + SysTick timestamping instead by defining adding "#define TRC_CFG_ARM_CM_USE_SYSTICK".*/ + + return "DWT_CYCCNT not supported (see xTraceGetLastError)"; + + case PSF_ERROR_TZCTRLTASK_NOT_CREATED: + /* vTraceEnable failed creating the trace control task (TzCtrl) - incorrect parameters (priority?) + or insufficient heap size? */ + return "Could not create TzCtrl (see xTraceGetLastError)"; + + } + + return NULL; +} + +/******************************************************************************* + * vTraceClearError + * + * Clears any errors. + *****************************************************************************/ +void vTraceClearError(void) +{ + NoRoomForSymbol = 0; + LongestSymbolName = 0; + NoRoomForObjectData = 0; + MaxBytesTruncated = 0; + errorCode = PSF_ERROR_NONE; +} + +/******************************************************************************* + * vTraceStop + * + * Stops the tracing. + *****************************************************************************/ +void vTraceStop(void) +{ + prvSetRecorderEnabled(0); +} + +/******************************************************************************* + * vTraceSetRecorderDataBuffer + * + * If custom allocation is used, this function must be called so the recorder + * library knows where to save the trace data. + ******************************************************************************/ +#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM) + +extern char* _TzTraceData; + +void vTraceSetRecorderDataBuffer(void* pRecorderData) +{ + _TzTraceData = pRecorderData; +} +#endif + + +/******************************************************************************* +* xTraceIsRecordingEnabled +* Returns true (1) if the recorder is enabled (i.e. is recording), otherwise 0. +******************************************************************************/ +int xTraceIsRecordingEnabled(void) +{ + return (int)RecorderEnabled; +} + +void vTraceSetFilterMask(uint16_t filterMask) +{ + CurrentFilterMask = filterMask; +} + +void vTraceSetFilterGroup(uint16_t filterGroup) +{ + CurrentFilterGroup = filterGroup; +} + + +/******************************************************************************/ +/*** INTERNAL FUNCTIONS *******************************************************/ +/******************************************************************************/ + +/* Internal function for starting/stopping the recorder. */ +static void prvSetRecorderEnabled(uint32_t isEnabled) +{ + void* currentTask; + + TRACE_ALLOC_CRITICAL_SECTION(); + + if (RecorderEnabled == isEnabled) + { + return; + } + + currentTask = TRACE_GET_CURRENT_TASK(); + + TRACE_ENTER_CRITICAL_SECTION(); + + RecorderEnabled = isEnabled; + + if (currentTask == NULL) + { + currentTask = (void*)HANDLE_NO_TASK; + } + + if (RecorderEnabled) + { + TRC_STREAM_PORT_ON_TRACE_BEGIN(); + + #if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1) + prvPagedEventBufferInit(_TzTraceData); + #endif + + eventCounter = 0; + ISR_stack_index = -1; + prvTraceStoreHeader(); + prvTraceStoreSymbolTable(); + prvTraceStoreObjectDataTable(); + prvTraceStoreEvent3( PSF_EVENT_TRACE_START, + (uint32_t)TRACE_GET_OS_TICKS(), + (uint32_t)currentTask, + SessionCounter++); + prvTraceStoreTSConfig(); + prvTraceStoreWarnings(); + } + else + { + TRC_STREAM_PORT_ON_TRACE_END(); + } + + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Stores the symbol table on Start */ +static void prvTraceStoreSymbolTable(void) +{ + uint32_t i = 0; + uint32_t j = 0; + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ENTER_CRITICAL_SECTION(); + + if (RecorderEnabled) + { + for (i = 0; i < (sizeof(SymbolTable) / sizeof(uint32_t)); i += (SYMBOL_TABLE_SLOT_SIZE / sizeof(uint32_t))) + { + TRC_STREAM_PORT_ALLOCATE_EVENT(uint32_t, data, SYMBOL_TABLE_SLOT_SIZE); + if (data != NULL) + { + for (j = 0; j < (SYMBOL_TABLE_SLOT_SIZE / sizeof(uint32_t)); j++) + { + data[j] = symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i+j]; + } + TRC_STREAM_PORT_COMMIT_EVENT(data, SYMBOL_TABLE_SLOT_SIZE); + } + } + } + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Stores the object table on Start */ +static void prvTraceStoreObjectDataTable(void) +{ + uint32_t i = 0; + uint32_t j = 0; + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ENTER_CRITICAL_SECTION(); + + if (RecorderEnabled) + { + for (i = 0; i < (sizeof(ObjectDataTable) / sizeof(uint32_t)); i += (OBJECT_DATA_SLOT_SIZE / sizeof(uint32_t))) + { + TRC_STREAM_PORT_ALLOCATE_EVENT(uint32_t, data, OBJECT_DATA_SLOT_SIZE); + if (data != NULL) + { + for (j = 0; j < (OBJECT_DATA_SLOT_SIZE / sizeof(uint32_t)); j++) + { + data[j] = objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i+j]; + } + TRC_STREAM_PORT_COMMIT_EVENT(data, OBJECT_DATA_SLOT_SIZE); + } + } + } + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Stores the header information on Start */ +static void prvTraceStoreHeader(void) +{ + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ENTER_CRITICAL_SECTION(); + + if (RecorderEnabled) + { + TRC_STREAM_PORT_ALLOCATE_EVENT(PSFHeaderInfo, header, sizeof(PSFHeaderInfo)); + if (header != NULL) + { + header->psf = PSFEndianessIdentifier; + header->version = FormatVersion; + header->platform = TRACE_KERNEL_VERSION; + header->options = 0; + /* Lowest bit used for TRC_IRQ_PRIORITY_ORDER */ + header->options = header->options | (TRC_IRQ_PRIORITY_ORDER << 0); + header->symbolSize = SYMBOL_TABLE_SLOT_SIZE; + header->symbolCount = (TRC_CFG_SYMBOL_TABLE_SLOTS); + header->objectDataSize = 8; + header->objectDataCount = (TRC_CFG_OBJECT_DATA_SLOTS); + TRC_STREAM_PORT_COMMIT_EVENT(header, sizeof(PSFHeaderInfo)); + } + } + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Store the current warnings */ +static void prvTraceStoreWarnings(void) +{ + if (RecorderEnabled) + { + const char* errStr = xTraceGetLastError(); + + if (errStr != NULL) + { + vTracePrint(trcWarningChannel, errStr); + } + } +} + +/* Store an event with zero parameters (event ID only) */ +void prvTraceStoreEvent0(uint16_t eventID) +{ + TRACE_ALLOC_CRITICAL_SECTION(); + + PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE); + + TRACE_ENTER_CRITICAL_SECTION(); + + if (RecorderEnabled) + { + eventCounter++; + + { + TRC_STREAM_PORT_ALLOCATE_EVENT(BaseEvent, event, sizeof(BaseEvent)); + if (event != NULL) + { + event->EventID = eventID | PARAM_COUNT(0); + event->EventCount = (uint16_t)eventCounter; + event->TS = prvGetTimestamp32(); + TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(BaseEvent)); + } + } + } + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Store an event with one 32-bit parameter (pointer address or an int) */ +void prvTraceStoreEvent1(uint16_t eventID, uint32_t param1) +{ + TRACE_ALLOC_CRITICAL_SECTION(); + + PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE); + + TRACE_ENTER_CRITICAL_SECTION(); + + if (RecorderEnabled) + { + eventCounter++; + + { + TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_1, event, sizeof(EventWithParam_1)); + if (event != NULL) + { + event->base.EventID = eventID | PARAM_COUNT(1); + event->base.EventCount = (uint16_t)eventCounter; + event->base.TS = prvGetTimestamp32(); + event->param1 = (uint32_t)param1; + TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_1)); + } + } + } + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Store an event with two 32-bit parameters */ +void prvTraceStoreEvent2(uint16_t eventID, uint32_t param1, uint32_t param2) +{ + TRACE_ALLOC_CRITICAL_SECTION(); + + PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE); + + TRACE_ENTER_CRITICAL_SECTION(); + + if (RecorderEnabled) + { + eventCounter++; + + { + TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_2, event, sizeof(EventWithParam_2)); + if (event != NULL) + { + event->base.EventID = eventID | PARAM_COUNT(2); + event->base.EventCount = (uint16_t)eventCounter; + event->base.TS = prvGetTimestamp32(); + event->param1 = (uint32_t)param1; + event->param2 = param2; + TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_2)); + } + } + } + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Store an event with three 32-bit parameters */ +void prvTraceStoreEvent3( uint16_t eventID, + uint32_t param1, + uint32_t param2, + uint32_t param3) +{ + TRACE_ALLOC_CRITICAL_SECTION(); + + PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE); + + TRACE_ENTER_CRITICAL_SECTION(); + + if (RecorderEnabled) + { + eventCounter++; + + { + TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_3, event, sizeof(EventWithParam_3)); + if (event != NULL) + { + event->base.EventID = eventID | PARAM_COUNT(3); + event->base.EventCount = (uint16_t)eventCounter; + event->base.TS = prvGetTimestamp32(); + event->param1 = (uint32_t)param1; + event->param2 = param2; + event->param3 = param3; + TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_3)); + } + } + } + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Stores an event with 32-bit integer parameters */ +void prvTraceStoreEvent(int nParam, uint16_t eventID, ...) +{ + va_list vl; + int i; + TRACE_ALLOC_CRITICAL_SECTION(); + + PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE); + + TRACE_ENTER_CRITICAL_SECTION(); + + if (RecorderEnabled) + { + int eventSize = (int)sizeof(BaseEvent) + nParam * (int)sizeof(uint32_t); + + eventCounter++; + + { + TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize); + if (event != NULL) + { + event->base.EventID = eventID | (uint16_t)PARAM_COUNT(nParam); + event->base.EventCount = (uint16_t)eventCounter; + event->base.TS = prvGetTimestamp32(); + + va_start(vl, eventID); + for (i = 0; i < nParam; i++) + { + uint32_t* tmp = (uint32_t*) &(event->data[i]); + *tmp = va_arg(vl, uint32_t); + } + va_end(vl); + + TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize); + } + } + } + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Stories an event with a string and 32-bit integer parameters */ +void prvTraceStoreStringEvent(int nArgs, uint16_t eventID, const char* str, ...) +{ + int len; + va_list vl; + + for (len = 0; (str[len] != 0) && (len < 52); len++); /* empty loop */ + + va_start(vl, str); + prvTraceStoreStringEventHelper(nArgs, eventID, NULL, len, str, &vl); + va_end(vl); +} + +/* Internal common function for storing string events */ +static void prvTraceStoreStringEventHelper(int nArgs, + uint16_t eventID, + traceString userEvtChannel, + int len, + const char* str, + va_list* vl) +{ + int nWords; + int nStrWords; + int i; + int offset = 0; + TRACE_ALLOC_CRITICAL_SECTION(); + + PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE); + + /* The string length in multiples of 32 bit words (+1 for null character) */ + nStrWords = (len+1+3)/4; + + /* If a user event channel is specified, add in the list */ + if (userEvtChannel) + nArgs++; + + offset = nArgs * 4; + + /* The total number of 32-bit words needed for the whole payload */ + nWords = nStrWords + nArgs; + + if (nWords > 15) /* if attempting to store more than 60 byte (= max) */ + { + /* Truncate event if too large. The string characters are stored + last, so usually only the string is truncated, unless there a lot + of parameters... */ + + /* Diagnostics ... */ + uint32_t bytesTruncated = (uint32_t)(nWords - 15) * 4; + + if (bytesTruncated > MaxBytesTruncated) + { + MaxBytesTruncated = bytesTruncated; + } + + nWords = 15; + len = 15 * 4 - offset; + } + + TRACE_ENTER_CRITICAL_SECTION(); + + if (RecorderEnabled) + { + int eventSize = (int)sizeof(BaseEvent) + nWords * (int)sizeof(uint32_t); + + eventCounter++; + + { + TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize); + if (event != NULL) + { + uint32_t* data32; + uint8_t* data8; + event->base.EventID = (eventID) | (uint16_t)PARAM_COUNT(nWords); + event->base.EventCount = (uint16_t)eventCounter; + event->base.TS = prvGetTimestamp32(); + + /* 32-bit write-pointer for the data argument */ + data32 = (uint32_t*) &(event->data[0]); + + for (i = 0; i < nArgs; i++) + { + if ((userEvtChannel != NULL) && (i == 0)) + { + /* First, add the User Event Channel if not NULL */ + data32[i] = (uint32_t)userEvtChannel; + } + else + { + /* Add data arguments... */ + data32[i] = va_arg(*vl, uint32_t); + } + } + data8 = (uint8_t*)&(event->data[0]); + for (i = 0; i < len; i++) + { + data8[offset + i] = str[i]; + } + + if (len < (15 * 4 - offset)) + data8[offset + len] = 0; /* Only truncate if we don't fill up the buffer completely */ + TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize); + } + } + } + + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Internal common function for storing string events without additional arguments */ +void prvTraceStoreSimpleStringEventHelper(traceString userEvtChannel, + const char* str) +{ + int len; + int nWords; + int nStrWords; + int i; + int nArgs = 0; + int offset = 0; + uint16_t eventID = PSF_EVENT_USER_EVENT; + TRACE_ALLOC_CRITICAL_SECTION(); + + PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE); + + for (len = 0; (str[len] != 0) && (len < 52); len++); /* empty loop */ + + /* The string length in multiples of 32 bit words (+1 for null character) */ + nStrWords = (len+1+3)/4; + + /* If a user event channel is specified, add in the list */ + if (userEvtChannel) + { + nArgs++; + eventID++; + } + + offset = nArgs * 4; + + /* The total number of 32-bit words needed for the whole payload */ + nWords = nStrWords + nArgs; + + if (nWords > 15) /* if attempting to store more than 60 byte (= max) */ + { + /* Truncate event if too large. The string characters are stored + last, so usually only the string is truncated, unless there a lot + of parameters... */ + + /* Diagnostics ... */ + uint32_t bytesTruncated = (uint32_t)(nWords - 15) * 4; + + if (bytesTruncated > MaxBytesTruncated) + { + MaxBytesTruncated = bytesTruncated; + } + + nWords = 15; + len = 15 * 4 - offset; + } + + TRACE_ENTER_CRITICAL_SECTION(); + + if (RecorderEnabled) + { + int eventSize = (int)sizeof(BaseEvent) + nWords * (int)sizeof(uint32_t); + + eventCounter++; + + { + TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize); + if (event != NULL) + { + uint32_t* data32; + uint8_t* data8; + event->base.EventID = (eventID) | (uint16_t)PARAM_COUNT(nWords); + event->base.EventCount = (uint16_t)eventCounter; + event->base.TS = prvGetTimestamp32(); + + /* 32-bit write-pointer for the data argument */ + data32 = (uint32_t*) &(event->data[0]); + + if (userEvtChannel != NULL) + { + /* First, add the User Event Channel if not NULL */ + data32[0] = (uint32_t)userEvtChannel; + } + + data8 = (uint8_t*) &(event->data[0]); + for (i = 0; i < len; i++) + { + data8[offset + i] = str[i]; + } + + if (len < (15 * 4 - offset)) + data8[offset + len] = 0; /* Only truncate if we don't fill up the buffer completely */ + TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize); + } + } + } + + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Saves a symbol name (task name etc.) in symbol table */ +void prvTraceSaveSymbol(const void *address, const char *name) +{ + uint32_t i; + uint32_t foundSlot; + uint32_t *ptrAddress; + uint8_t *ptrSymbol; + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ENTER_CRITICAL_SECTION(); + + foundSlot = firstFreeSymbolTableIndex; + + /* First look for previous entries using this address */ + for (i = 0; i < firstFreeSymbolTableIndex; i += SYMBOL_TABLE_SLOT_SIZE) + { + /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */ + ptrAddress = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i / sizeof(uint32_t)]; + if (*ptrAddress == (uint32_t)address) + { + foundSlot = i; + break; + } + } + + if (foundSlot < SYMBOL_TABLE_BUFFER_SIZE) + { + /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */ + symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[foundSlot / sizeof(uint32_t)] = (uint32_t)address; + + /* We access the symbol table via the union member pSymbolTableBufferUINT8 to avoid strict-aliasing issues */ + ptrSymbol = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT8[foundSlot + sizeof(uint32_t)]; + for (i = 0; i < (TRC_CFG_SYMBOL_MAX_LENGTH); i++) + { + ptrSymbol[i] = (uint8_t)name[i]; /* We do this first to ensure we also get the 0 termination, if there is one */ + + if (name[i] == 0) + break; + } + + /* Check the length of "name", if longer than SYMBOL_MAX_LENGTH */ + while ((name[i] != 0) && i < 128) + { + i++; + } + + /* Remember the longest symbol name, for diagnostic purposes */ + if (i > LongestSymbolName) + { + LongestSymbolName = i; + } + + /* Is this the last entry in the symbol table? */ + if (foundSlot == firstFreeSymbolTableIndex) + { + firstFreeSymbolTableIndex += SYMBOL_TABLE_SLOT_SIZE; + } + } + else + { + NoRoomForSymbol++; + } + + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Deletes a symbol name (task name etc.) from symbol table */ +void prvTraceDeleteSymbol(void *address) +{ + uint32_t i, j; + uint32_t *ptr, *lastEntryPtr; + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ENTER_CRITICAL_SECTION(); + + for (i = 0; i < firstFreeSymbolTableIndex; i += SYMBOL_TABLE_SLOT_SIZE) + { + /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */ + ptr = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i / sizeof(uint32_t)]; + if (*ptr == (uint32_t)address) + { + /* See if we have another entry in the table, and that this isn't already the last entry */ + if (firstFreeSymbolTableIndex > SYMBOL_TABLE_SLOT_SIZE && i != (firstFreeSymbolTableIndex - SYMBOL_TABLE_SLOT_SIZE)) + { + /* Another entry is available, get pointer to the last one */ + /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */ + lastEntryPtr = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[(firstFreeSymbolTableIndex - SYMBOL_TABLE_SLOT_SIZE) / sizeof(uint32_t)]; + + /* Copy last entry to this position */ + for (j = 0; j < (SYMBOL_TABLE_SLOT_SIZE) / sizeof(uint32_t); j++) + { + ptr[j] = lastEntryPtr[j]; + } + + /* For good measure we also zero out the original position */ + *lastEntryPtr = 0; + } + else + *ptr = 0; /* No other entry found, or this is the last entry */ + + /* Lower index */ + firstFreeSymbolTableIndex -= SYMBOL_TABLE_SLOT_SIZE; + + break; + } + } + + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Saves an object data entry (current task priority) in object data table */ +void prvTraceSaveObjectData(const void *address, uint32_t data) +{ + uint32_t i; + uint32_t foundSlot; + uint32_t *ptr; + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ENTER_CRITICAL_SECTION(); + + foundSlot = firstFreeObjectDataTableIndex; + + /* First look for previous entries using this address */ + for (i = 0; i < firstFreeObjectDataTableIndex; i += OBJECT_DATA_SLOT_SIZE) + { + /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */ + ptr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i / sizeof(uint32_t)]; + if (*ptr == (uint32_t)address) + { + foundSlot = i; + break; + } + } + + if (foundSlot < OBJECT_DATA_TABLE_BUFFER_SIZE) + { + /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */ + objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[foundSlot / sizeof(uint32_t)] = (uint32_t)address; + objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[foundSlot / sizeof(uint32_t) + 1] = data; + + /* Is this the last entry in the object data table? */ + if (foundSlot == firstFreeObjectDataTableIndex) + { + firstFreeObjectDataTableIndex += OBJECT_DATA_SLOT_SIZE; + } + } + else + { + NoRoomForObjectData++; + } + + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Removes an object data entry (task base priority) from object data table */ +void prvTraceDeleteObjectData(void *address) +{ + uint32_t i, j; + uint32_t *ptr, *lastEntryPtr; + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ENTER_CRITICAL_SECTION(); + + for (i = 0; i < firstFreeObjectDataTableIndex; i += OBJECT_DATA_SLOT_SIZE) + { + /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */ + ptr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i / sizeof(uint32_t)]; + if (*ptr == (uint32_t)address) + { + /* See if we have another entry in the table, and that this isn't already the last entry */ + if (firstFreeObjectDataTableIndex > OBJECT_DATA_SLOT_SIZE && i != (firstFreeObjectDataTableIndex - OBJECT_DATA_SLOT_SIZE)) + { + /* Another entry is available, get pointer to the last one */ + /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */ + lastEntryPtr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[(firstFreeObjectDataTableIndex - OBJECT_DATA_SLOT_SIZE) / sizeof(uint32_t)]; + + /* Copy last entry to this position */ + for (j = 0; j < (OBJECT_DATA_SLOT_SIZE) / sizeof(uint32_t); j++) + { + ptr[j] = lastEntryPtr[j]; + } + + /* For good measure we also zero out the original position */ + *lastEntryPtr = 0; + } + else + *ptr = 0; /* No other entry found, or this is the last entry */ + + /* Lower index */ + firstFreeObjectDataTableIndex -= OBJECT_DATA_SLOT_SIZE; + + break; + } + } + + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Checks if the provided command is a valid command */ +int prvIsValidCommand(TracealyzerCommandType* cmd) +{ + uint16_t checksum = (uint16_t)(0xFFFF - ( cmd->cmdCode + + cmd->param1 + + cmd->param2 + + cmd->param3 + + cmd->param4 + + cmd->param5)); + + if (cmd->checksumMSB != (unsigned char)(checksum >> 8)) + return 0; + + if (cmd->checksumLSB != (unsigned char)(checksum & 0xFF)) + return 0; + + if (cmd->cmdCode > CMD_LAST_COMMAND) + return 0; + + return 1; +} + +/* Executed the received command (Start or Stop) */ +void prvProcessCommand(TracealyzerCommandType* cmd) +{ + switch(cmd->cmdCode) + { + case CMD_SET_ACTIVE: + prvSetRecorderEnabled(cmd->param1); + break; + default: + break; + } +} + +/* Called on warnings, when the recording can continue. */ +void prvTraceWarning(int errCode) +{ + if (!errorCode) + { + errorCode = errCode; + prvTraceStoreWarnings(); + } +} + +/* Called on critical errors in the recorder. Stops the recorder! */ +void prvTraceError(int errCode) +{ + if (! errorCode) + { + errorCode = errCode; + prvTraceStoreWarnings(); + vTracePrintF(trcWarningChannel, "Recorder stopped in prvTraceError()"); + + prvSetRecorderEnabled(0); + } +} + +/* If using DWT timestamping (default on ARM Cortex-M3, M4 and M7), make sure the DWT unit is initialized. */ +#ifndef TRC_CFG_ARM_CM_USE_SYSTICK +#if ((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M) && (defined (__CORTEX_M) && (__CORTEX_M >= 0x03))) + +void prvTraceInitCortexM() +{ + /* Make sure the DWT registers are unlocked, in case the debugger doesn't do this. */ + TRC_REG_ITM_LOCKACCESS = TRC_ITM_LOCKACCESS_UNLOCK; + + /* Make sure DWT is enabled is enabled, if supported */ + TRC_REG_DEMCR |= TRC_DEMCR_TRCENA; + + do + { + /* Verify that DWT is supported */ + if (TRC_REG_DEMCR == 0) + { + /* This function is called on Cortex-M3, M4 and M7 devices to initialize + the DWT unit, assumed present. The DWT cycle counter is used for timestamping. + + If the below error is produced, the DWT unit does not seem to be available. + + In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build + to use SysTick timestamping instead, or define your own timestamping by + setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED + and make the necessary definitions, as explained in trcHardwarePort.h.*/ + + prvTraceError(PSF_ERROR_DWT_NOT_SUPPORTED); + break; + } + + /* Verify that DWT_CYCCNT is supported */ + if (TRC_REG_DWT_CTRL & TRC_DWT_CTRL_NOCYCCNT) + { + /* This function is called on Cortex-M3, M4 and M7 devices to initialize + the DWT unit, assumed present. The DWT cycle counter is used for timestamping. + + If the below error is produced, the cycle counter does not seem to be available. + + In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build + to use SysTick timestamping instead, or define your own timestamping by + setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED + and make the necessary definitions, as explained in trcHardwarePort.h.*/ + + prvTraceError(PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED); + break; + } + + /* Reset the cycle counter */ + TRC_REG_DWT_CYCCNT = 0; + + /* Enable the cycle counter */ + TRC_REG_DWT_CTRL |= TRC_DWT_CTRL_CYCCNTENA; + + } while(0); /* breaks above jump here */ +} +#endif +#endif + +/* Performs timestamping using definitions in trcHardwarePort.h */ +static uint32_t prvGetTimestamp32(void) +{ +#if ((TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_INCR) || (TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_DECR)) + return TRC_HWTC_COUNT; +#endif + +#if ((TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR)) + return TRC_HWTC_COUNT; +#endif + +#if ((TRC_HWTC_TYPE == TRC_OS_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_OS_TIMER_DECR)) + uint32_t ticks = TRACE_GET_OS_TICKS(); + return ((TRC_HWTC_COUNT) & 0x00FFFFFFU) + ((ticks & 0x000000FFU) << 24); +#endif +} + +/* Store the Timestamp Config event */ +static void prvTraceStoreTSConfig(void) +{ + /* If not overridden using vTraceSetFrequency, use default value */ + if (timestampFrequency == 0) + { + timestampFrequency = TRC_HWTC_FREQ_HZ; + } + + #if (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR || TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR) + + prvTraceStoreEvent(5, + PSF_EVENT_TS_CONFIG, + (uint32_t)timestampFrequency, + (uint32_t)(TRACE_TICK_RATE_HZ), + (uint32_t)(TRC_HWTC_TYPE), + (uint32_t)(TRC_CFG_ISR_TAILCHAINING_THRESHOLD), + (uint32_t)(TRC_HWTC_PERIOD)); + + #else + + prvTraceStoreEvent(4, + PSF_EVENT_TS_CONFIG, + (uint32_t)timestampFrequency, + (uint32_t)(TRACE_TICK_RATE_HZ), + (uint32_t)(TRC_HWTC_TYPE), + (uint32_t)(TRC_CFG_ISR_TAILCHAINING_THRESHOLD)); + #endif +} + +/* Retrieve a buffer page to write to. */ +static int prvAllocateBufferPage(int prevPage) +{ + int index; + int count = 0; + + index = (prevPage + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT); + + while((PageInfo[index].Status != PAGE_STATUS_FREE) && (count ++ < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT))) + { + index = (index + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT); + } + + if (PageInfo[index].Status == PAGE_STATUS_FREE) + { + return index; + } + + return -1; +} + +/* Mark the page read as complete. */ +static void prvPageReadComplete(int pageIndex) +{ + TRACE_ALLOC_CRITICAL_SECTION(); + + TRACE_ENTER_CRITICAL_SECTION(); + PageInfo[pageIndex].BytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE); + PageInfo[pageIndex].WritePointer = &EventBuffer[pageIndex * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)]; + PageInfo[pageIndex].Status = PAGE_STATUS_FREE; + + TotalBytesRemaining += (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE); + + TRACE_EXIT_CRITICAL_SECTION(); +} + +/* Get the current buffer page index and remaining number of bytes. */ +static int prvGetBufferPage(int32_t* bytesUsed) +{ + static int8_t lastPage = -1; + int count = 0; + int8_t index = (int8_t) ((lastPage + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)); + + while((PageInfo[index].Status != PAGE_STATUS_READ) && (count++ < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT))) + { + index = (int8_t)((index + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)); + } + + if (PageInfo[index].Status == PAGE_STATUS_READ) + { + *bytesUsed = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE) - PageInfo[index].BytesRemaining; + lastPage = index; + return index; + } + + *bytesUsed = 0; + + return -1; +} + +/******************************************************************************* + * uint32_t prvPagedEventBufferTransfer(void) + * + * Transfers one buffer page of trace data, if a full page is available, using + * the macro TRC_STREAM_PORT_WRITE_DATA as defined in trcStreamingPort.h. + * + * This function is intended to be called the periodic TzCtrl task with a suitable + * delay (e.g. 10-100 ms). + * + * Returns the number of bytes sent. If non-zero, it is good to call this + * again, in order to send any additional data waiting in the buffer. + * If zero, wait a while before calling again. + * + * In case of errors from the streaming interface, it registers a warning + * (PSF_WARNING_STREAM_PORT_WRITE) provided by xTraceGetLastError(). + * + *******************************************************************************/ +uint32_t prvPagedEventBufferTransfer(void) +{ + int8_t pageToTransfer = -1; + int32_t bytesTransferredTotal = 0; + int32_t bytesTransferredNow = 0; + int32_t bytesToTransfer; + + pageToTransfer = (int8_t)prvGetBufferPage(&bytesToTransfer); + + /* bytesToTransfer now contains the number of "valid" bytes in the buffer page, that should be transmitted. + There might be some unused junk bytes in the end, that must be ignored. */ + + if (pageToTransfer > -1) + { + while (1) /* Keep going until we have transferred all that we intended to */ + { + if (TRC_STREAM_PORT_WRITE_DATA( + &EventBuffer[pageToTransfer * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE) + bytesTransferredTotal], + (uint32_t)(bytesToTransfer - bytesTransferredTotal), + &bytesTransferredNow) == 0) + { + /* Write was successful. Update the number of transferred bytes. */ + bytesTransferredTotal += bytesTransferredNow; + + if (bytesTransferredTotal == bytesToTransfer) + { + /* All bytes have been transferred. Mark the buffer page as "Read Complete" (so it can be written to) and return OK. */ + prvPageReadComplete(pageToTransfer); + return (uint32_t)bytesTransferredTotal; + } + } + else + { + /* Some error from the streaming interface... */ + prvTraceWarning(PSF_WARNING_STREAM_PORT_WRITE); + return 0; + } + } + } + return 0; +} + +/******************************************************************************* + * void* prvPagedEventBufferGetWritePointer(int sizeOfEvent) + * + * Returns a pointer to an available location in the buffer able to store the + * requested size. + * + * Return value: The pointer. + * + * Parameters: + * - sizeOfEvent: The size of the event that is to be placed in the buffer. + * +*******************************************************************************/ +void* prvPagedEventBufferGetWritePointer(int sizeOfEvent) +{ + void* ret; + static int currentWritePage = -1; + + if (currentWritePage == -1) + { + currentWritePage = prvAllocateBufferPage(currentWritePage); + if (currentWritePage == -1) + { + DroppedEventCounter++; + return NULL; + } + } + + if (PageInfo[currentWritePage].BytesRemaining - sizeOfEvent < 0) + { + PageInfo[currentWritePage].Status = PAGE_STATUS_READ; + + TotalBytesRemaining -= PageInfo[currentWritePage].BytesRemaining; // Last trailing bytes + + if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark) + TotalBytesRemaining_LowWaterMark = TotalBytesRemaining; + + currentWritePage = prvAllocateBufferPage(currentWritePage); + if (currentWritePage == -1) + { + DroppedEventCounter++; + return NULL; + } + } + ret = PageInfo[currentWritePage].WritePointer; + PageInfo[currentWritePage].WritePointer += sizeOfEvent; + PageInfo[currentWritePage].BytesRemaining = (uint16_t)(PageInfo[currentWritePage].BytesRemaining -sizeOfEvent); + + TotalBytesRemaining = (TotalBytesRemaining-(uint16_t)sizeOfEvent); + + if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark) + TotalBytesRemaining_LowWaterMark = TotalBytesRemaining; + + return ret; +} + +/******************************************************************************* + * void prvPagedEventBufferInit(char* buffer) + * + * Assigns the buffer to use and initializes the PageInfo structure. + * + * Return value: void + * + * Parameters: + * - char* buffer: pointer to the trace data buffer, allocated by the caller. + * +*******************************************************************************/ +void prvPagedEventBufferInit(char* buffer) +{ + int i; + TRACE_ALLOC_CRITICAL_SECTION(); + + EventBuffer = buffer; + + TRACE_ENTER_CRITICAL_SECTION(); + for (i = 0; i < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT); i++) + { + PageInfo[i].BytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE); + PageInfo[i].WritePointer = &EventBuffer[i * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)]; + PageInfo[i].Status = PAGE_STATUS_FREE; + } + TRACE_EXIT_CRITICAL_SECTION(); + +} + +#endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/ + +#endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/ diff --git a/FreeRTOS-Labs/Source/http-parser/LICENSE-MIT b/FreeRTOS-Labs/Source/http-parser/LICENSE-MIT new file mode 100644 index 000000000..9fd5ade4f --- /dev/null +++ b/FreeRTOS-Labs/Source/http-parser/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright Joyent, Inc. and other Node contributors. + +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. diff --git a/FreeRTOS-Labs/Source/http-parser/http_parser.c b/FreeRTOS-Labs/Source/http-parser/http_parser.c new file mode 100644 index 000000000..4de6c91da --- /dev/null +++ b/FreeRTOS-Labs/Source/http-parser/http_parser.c @@ -0,0 +1,2498 @@ +/* Copyright Joyent, Inc. and other Node contributors. + * + * 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. + */ +#include "http_parser.h" +#include +#include +#include +#include +#include + +static uint32_t max_header_size = HTTP_MAX_HEADER_SIZE; + +#ifndef ULLONG_MAX +# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ +#endif + +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + +#ifndef BIT_AT +# define BIT_AT(a, i) \ + (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ + (1 << ((unsigned int) (i) & 7)))) +#endif + +#ifndef ELEM_AT +# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) +#endif + +#define SET_ERRNO(e) \ +do { \ + parser->nread = nread; \ + parser->http_errno = (e); \ +} while(0) + +#define CURRENT_STATE() p_state +#define UPDATE_STATE(V) p_state = (enum state) (V); +#define RETURN(V) \ +do { \ + parser->nread = nread; \ + parser->state = CURRENT_STATE(); \ + return (V); \ +} while (0); +#define REEXECUTE() \ + goto reexecute; \ + + +#ifdef __GNUC__ +# define LIKELY(X) __builtin_expect(!!(X), 1) +# define UNLIKELY(X) __builtin_expect(!!(X), 0) +#else +# define LIKELY(X) (X) +# define UNLIKELY(X) (X) +#endif + + +/* Run the notify callback FOR, returning ER if it fails */ +#define CALLBACK_NOTIFY_(FOR, ER) \ +do { \ + assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ + \ + if (LIKELY(settings->on_##FOR)) { \ + parser->state = CURRENT_STATE(); \ + if (UNLIKELY(0 != settings->on_##FOR(parser))) { \ + SET_ERRNO(HPE_CB_##FOR); \ + } \ + UPDATE_STATE(parser->state); \ + \ + /* We either errored above or got paused; get out */ \ + if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ + return (ER); \ + } \ + } \ +} while (0) + +/* Run the notify callback FOR and consume the current byte */ +#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) + +/* Run the notify callback FOR and don't consume the current byte */ +#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) + +/* Run data callback FOR with LEN bytes, returning ER if it fails */ +#define CALLBACK_DATA_(FOR, LEN, ER) \ +do { \ + assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ + \ + if (FOR##_mark) { \ + if (LIKELY(settings->on_##FOR)) { \ + parser->state = CURRENT_STATE(); \ + if (UNLIKELY(0 != \ + settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \ + SET_ERRNO(HPE_CB_##FOR); \ + } \ + UPDATE_STATE(parser->state); \ + \ + /* We either errored above or got paused; get out */ \ + if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ + return (ER); \ + } \ + } \ + FOR##_mark = NULL; \ + } \ +} while (0) + +/* Run the data callback FOR and consume the current byte */ +#define CALLBACK_DATA(FOR) \ + CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) + +/* Run the data callback FOR and don't consume the current byte */ +#define CALLBACK_DATA_NOADVANCE(FOR) \ + CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) + +/* Set the mark FOR; non-destructive if mark is already set */ +#define MARK(FOR) \ +do { \ + if (!FOR##_mark) { \ + FOR##_mark = p; \ + } \ +} while (0) + +/* Don't allow the total size of the HTTP headers (including the status + * line) to exceed max_header_size. This check is here to protect + * embedders against denial-of-service attacks where the attacker feeds + * us a never-ending header that the embedder keeps buffering. + * + * This check is arguably the responsibility of embedders but we're doing + * it on the embedder's behalf because most won't bother and this way we + * make the web a little safer. max_header_size is still far bigger + * than any reasonable request or response so this should never affect + * day-to-day operation. + */ +#define COUNT_HEADER_SIZE(V) \ +do { \ + nread += (uint32_t)(V); \ + if (UNLIKELY(nread > max_header_size)) { \ + SET_ERRNO(HPE_HEADER_OVERFLOW); \ + goto error; \ + } \ +} while (0) + + +#define PROXY_CONNECTION "proxy-connection" +#define CONNECTION "connection" +#define CONTENT_LENGTH "content-length" +#define TRANSFER_ENCODING "transfer-encoding" +#define UPGRADE "upgrade" +#define CHUNKED "chunked" +#define KEEP_ALIVE "keep-alive" +#define CLOSE "close" + + +static const char *method_strings[] = + { +#define XX(num, name, string) #string, + HTTP_METHOD_MAP(XX) +#undef XX + }; + + +/* Tokens as defined by rfc 2616. Also lowercases them. + * token = 1* + * separators = "(" | ")" | "<" | ">" | "@" + * | "," | ";" | ":" | "\" | <"> + * | "/" | "[" | "]" | "?" | "=" + * | "{" | "}" | SP | HT + */ +static const char tokens[256] = { +/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ + 0, 0, 0, 0, 0, 0, 0, 0, +/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ + ' ', '!', 0, '#', '$', '%', '&', '\'', +/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ + 0, 0, '*', '+', 0, '-', '.', 0, +/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ + '0', '1', '2', '3', '4', '5', '6', '7', +/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ + '8', '9', 0, 0, 0, 0, 0, 0, +/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ + 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', +/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', +/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', +/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ + 'x', 'y', 'z', 0, 0, 0, '^', '_', +/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', +/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', +/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', +/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ + 'x', 'y', 'z', 0, '|', 0, '~', 0 }; + + +static const int8_t unhex[256] = + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + }; + + +#if HTTP_PARSER_STRICT +# define T(v) 0 +#else +# define T(v) v +#endif + + +static const uint8_t normal_url_char[32] = { +/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, +/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ + 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, +/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, +/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ + 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, +/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ + 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, +/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, +/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, +/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ + 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, }; + +#undef T + +enum state + { s_dead = 1 /* important that this is > 0 */ + + , s_start_req_or_res + , s_res_or_resp_H + , s_start_res + , s_res_H + , s_res_HT + , s_res_HTT + , s_res_HTTP + , s_res_http_major + , s_res_http_dot + , s_res_http_minor + , s_res_http_end + , s_res_first_status_code + , s_res_status_code + , s_res_status_start + , s_res_status + , s_res_line_almost_done + + , s_start_req + + , s_req_method + , s_req_spaces_before_url + , s_req_schema + , s_req_schema_slash + , s_req_schema_slash_slash + , s_req_server_start + , s_req_server + , s_req_server_with_at + , s_req_path + , s_req_query_string_start + , s_req_query_string + , s_req_fragment_start + , s_req_fragment + , s_req_http_start + , s_req_http_H + , s_req_http_HT + , s_req_http_HTT + , s_req_http_HTTP + , s_req_http_I + , s_req_http_IC + , s_req_http_major + , s_req_http_dot + , s_req_http_minor + , s_req_http_end + , s_req_line_almost_done + + , s_header_field_start + , s_header_field + , s_header_value_discard_ws + , s_header_value_discard_ws_almost_done + , s_header_value_discard_lws + , s_header_value_start + , s_header_value + , s_header_value_lws + + , s_header_almost_done + + , s_chunk_size_start + , s_chunk_size + , s_chunk_parameters + , s_chunk_size_almost_done + + , s_headers_almost_done + , s_headers_done + + /* Important: 's_headers_done' must be the last 'header' state. All + * states beyond this must be 'body' states. It is used for overflow + * checking. See the PARSING_HEADER() macro. + */ + + , s_chunk_data + , s_chunk_data_almost_done + , s_chunk_data_done + + , s_body_identity + , s_body_identity_eof + + , s_message_done + }; + + +#define PARSING_HEADER(state) (state <= s_headers_done) + + +enum header_states + { h_general = 0 + , h_C + , h_CO + , h_CON + + , h_matching_connection + , h_matching_proxy_connection + , h_matching_content_length + , h_matching_transfer_encoding + , h_matching_upgrade + + , h_connection + , h_content_length + , h_content_length_num + , h_content_length_ws + , h_transfer_encoding + , h_upgrade + + , h_matching_transfer_encoding_chunked + , h_matching_connection_token_start + , h_matching_connection_keep_alive + , h_matching_connection_close + , h_matching_connection_upgrade + , h_matching_connection_token + + , h_transfer_encoding_chunked + , h_connection_keep_alive + , h_connection_close + , h_connection_upgrade + }; + +enum http_host_state + { + s_http_host_dead = 1 + , s_http_userinfo_start + , s_http_userinfo + , s_http_host_start + , s_http_host_v6_start + , s_http_host + , s_http_host_v6 + , s_http_host_v6_end + , s_http_host_v6_zone_start + , s_http_host_v6_zone + , s_http_host_port_start + , s_http_host_port +}; + +/* Macros for character classes; depends on strict-mode */ +#define CR '\r' +#define LF '\n' +#define LOWER(c) (unsigned char)(c | 0x20) +#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') +#define IS_NUM(c) ((c) >= '0' && (c) <= '9') +#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) +#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) +#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ + (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ + (c) == ')') +#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ + (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ + (c) == '$' || (c) == ',') + +#define STRICT_TOKEN(c) ((c == ' ') ? 0 : tokens[(unsigned char)c]) + +#if HTTP_PARSER_STRICT +#define TOKEN(c) STRICT_TOKEN(c) +#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) +#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') +#else +#define TOKEN(c) tokens[(unsigned char)c] +#define IS_URL_CHAR(c) \ + (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) +#define IS_HOST_CHAR(c) \ + (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') +#endif + +/** + * Verify that a char is a valid visible (printable) US-ASCII + * character or %x80-FF + **/ +#define IS_HEADER_CHAR(ch) \ + (ch == CR || ch == LF || ch == 9 || ((unsigned char)ch > 31 && ch != 127)) + +#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) + + +#if HTTP_PARSER_STRICT +# define STRICT_CHECK(cond) \ +do { \ + if (cond) { \ + SET_ERRNO(HPE_STRICT); \ + goto error; \ + } \ +} while (0) +# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) +#else +# define STRICT_CHECK(cond) +# define NEW_MESSAGE() start_state +#endif + + +/* Map errno values to strings for human-readable output */ +#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, +static struct { + const char *name; + const char *description; +} http_strerror_tab[] = { + HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) +}; +#undef HTTP_STRERROR_GEN + +int http_message_needs_eof(const http_parser *parser); + +/* Our URL parser. + * + * This is designed to be shared by http_parser_execute() for URL validation, + * hence it has a state transition + byte-for-byte interface. In addition, it + * is meant to be embedded in http_parser_parse_url(), which does the dirty + * work of turning state transitions URL components for its API. + * + * This function should only be invoked with non-space characters. It is + * assumed that the caller cares about (and can detect) the transition between + * URL and non-URL states by looking for these. + */ +static enum state +parse_url_char(enum state s, const char ch) +{ + if (ch == ' ' || ch == '\r' || ch == '\n') { + return s_dead; + } + +#if HTTP_PARSER_STRICT + if (ch == '\t' || ch == '\f') { + return s_dead; + } +#endif + + switch (s) { + case s_req_spaces_before_url: + /* Proxied requests are followed by scheme of an absolute URI (alpha). + * All methods except CONNECT are followed by '/' or '*'. + */ + + if (ch == '/' || ch == '*') { + return s_req_path; + } + + if (IS_ALPHA(ch)) { + return s_req_schema; + } + + break; + + case s_req_schema: + if (IS_ALPHA(ch)) { + return s; + } + + if (ch == ':') { + return s_req_schema_slash; + } + + break; + + case s_req_schema_slash: + if (ch == '/') { + return s_req_schema_slash_slash; + } + + break; + + case s_req_schema_slash_slash: + if (ch == '/') { + return s_req_server_start; + } + + break; + + case s_req_server_with_at: + if (ch == '@') { + return s_dead; + } + + /* fall through */ + case s_req_server_start: + case s_req_server: + if (ch == '/') { + return s_req_path; + } + + if (ch == '?') { + return s_req_query_string_start; + } + + if (ch == '@') { + return s_req_server_with_at; + } + + if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { + return s_req_server; + } + + break; + + case s_req_path: + if (IS_URL_CHAR(ch)) { + return s; + } + + switch (ch) { + case '?': + return s_req_query_string_start; + + case '#': + return s_req_fragment_start; + } + + break; + + case s_req_query_string_start: + case s_req_query_string: + if (IS_URL_CHAR(ch)) { + return s_req_query_string; + } + + switch (ch) { + case '?': + /* allow extra '?' in query string */ + return s_req_query_string; + + case '#': + return s_req_fragment_start; + } + + break; + + case s_req_fragment_start: + if (IS_URL_CHAR(ch)) { + return s_req_fragment; + } + + switch (ch) { + case '?': + return s_req_fragment; + + case '#': + return s; + } + + break; + + case s_req_fragment: + if (IS_URL_CHAR(ch)) { + return s; + } + + switch (ch) { + case '?': + case '#': + return s; + } + + break; + + default: + break; + } + + /* We should never fall out of the switch above unless there's an error */ + return s_dead; +} + +size_t http_parser_execute (http_parser *parser, + const http_parser_settings *settings, + const char *data, + size_t len) +{ + char c, ch; + int8_t unhex_val; + const char *p = data; + const char *header_field_mark = 0; + const char *header_value_mark = 0; + const char *url_mark = 0; + const char *body_mark = 0; + const char *status_mark = 0; + enum state p_state = (enum state) parser->state; + const unsigned int lenient = parser->lenient_http_headers; + uint32_t nread = parser->nread; + + /* We're in an error state. Don't bother doing anything. */ + if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { + return 0; + } + + if (len == 0) { + switch (CURRENT_STATE()) { + case s_body_identity_eof: + /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if + * we got paused. + */ + CALLBACK_NOTIFY_NOADVANCE(message_complete); + return 0; + + case s_dead: + case s_start_req_or_res: + case s_start_res: + case s_start_req: + return 0; + + default: + SET_ERRNO(HPE_INVALID_EOF_STATE); + return 1; + } + } + + + if (CURRENT_STATE() == s_header_field) + header_field_mark = data; + if (CURRENT_STATE() == s_header_value) + header_value_mark = data; + switch (CURRENT_STATE()) { + case s_req_path: + case s_req_schema: + case s_req_schema_slash: + case s_req_schema_slash_slash: + case s_req_server_start: + case s_req_server: + case s_req_server_with_at: + case s_req_query_string_start: + case s_req_query_string: + case s_req_fragment_start: + case s_req_fragment: + url_mark = data; + break; + case s_res_status: + status_mark = data; + break; + default: + break; + } + + for (p=data; p != data + len; p++) { + ch = *p; + + if (PARSING_HEADER(CURRENT_STATE())) + COUNT_HEADER_SIZE(1); + +reexecute: + switch (CURRENT_STATE()) { + + case s_dead: + /* this state is used after a 'Connection: close' message + * the parser will error out if it reads another message + */ + if (LIKELY(ch == CR || ch == LF)) + break; + + SET_ERRNO(HPE_CLOSED_CONNECTION); + goto error; + + case s_start_req_or_res: + { + if (ch == CR || ch == LF) + break; + parser->flags = 0; + parser->content_length = ULLONG_MAX; + + if (ch == 'H') { + UPDATE_STATE(s_res_or_resp_H); + + CALLBACK_NOTIFY(message_begin); + } else { + parser->type = HTTP_REQUEST; + UPDATE_STATE(s_start_req); + REEXECUTE(); + } + + break; + } + + case s_res_or_resp_H: + if (ch == 'T') { + parser->type = HTTP_RESPONSE; + UPDATE_STATE(s_res_HT); + } else { + if (UNLIKELY(ch != 'E')) { + SET_ERRNO(HPE_INVALID_CONSTANT); + goto error; + } + + parser->type = HTTP_REQUEST; + parser->method = HTTP_HEAD; + parser->index = 2; + UPDATE_STATE(s_req_method); + } + break; + + case s_start_res: + { + if (ch == CR || ch == LF) + break; + parser->flags = 0; + parser->content_length = ULLONG_MAX; + + if (ch == 'H') { + UPDATE_STATE(s_res_H); + } else { + SET_ERRNO(HPE_INVALID_CONSTANT); + goto error; + } + + CALLBACK_NOTIFY(message_begin); + break; + } + + case s_res_H: + STRICT_CHECK(ch != 'T'); + UPDATE_STATE(s_res_HT); + break; + + case s_res_HT: + STRICT_CHECK(ch != 'T'); + UPDATE_STATE(s_res_HTT); + break; + + case s_res_HTT: + STRICT_CHECK(ch != 'P'); + UPDATE_STATE(s_res_HTTP); + break; + + case s_res_HTTP: + STRICT_CHECK(ch != '/'); + UPDATE_STATE(s_res_http_major); + break; + + case s_res_http_major: + if (UNLIKELY(!IS_NUM(ch))) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_major = ch - '0'; + UPDATE_STATE(s_res_http_dot); + break; + + case s_res_http_dot: + { + if (UNLIKELY(ch != '.')) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + UPDATE_STATE(s_res_http_minor); + break; + } + + case s_res_http_minor: + if (UNLIKELY(!IS_NUM(ch))) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_minor = ch - '0'; + UPDATE_STATE(s_res_http_end); + break; + + case s_res_http_end: + { + if (UNLIKELY(ch != ' ')) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + UPDATE_STATE(s_res_first_status_code); + break; + } + + case s_res_first_status_code: + { + if (!IS_NUM(ch)) { + if (ch == ' ') { + break; + } + + SET_ERRNO(HPE_INVALID_STATUS); + goto error; + } + parser->status_code = ch - '0'; + UPDATE_STATE(s_res_status_code); + break; + } + + case s_res_status_code: + { + if (!IS_NUM(ch)) { + switch (ch) { + case ' ': + UPDATE_STATE(s_res_status_start); + break; + case CR: + case LF: + UPDATE_STATE(s_res_status_start); + REEXECUTE(); + break; + default: + SET_ERRNO(HPE_INVALID_STATUS); + goto error; + } + break; + } + + parser->status_code *= 10; + parser->status_code += ch - '0'; + + if (UNLIKELY(parser->status_code > 999)) { + SET_ERRNO(HPE_INVALID_STATUS); + goto error; + } + + break; + } + + case s_res_status_start: + { + MARK(status); + UPDATE_STATE(s_res_status); + parser->index = 0; + + if (ch == CR || ch == LF) + REEXECUTE(); + + break; + } + + case s_res_status: + if (ch == CR) { + UPDATE_STATE(s_res_line_almost_done); + CALLBACK_DATA(status); + break; + } + + if (ch == LF) { + UPDATE_STATE(s_header_field_start); + CALLBACK_DATA(status); + break; + } + + break; + + case s_res_line_almost_done: + STRICT_CHECK(ch != LF); + UPDATE_STATE(s_header_field_start); + break; + + case s_start_req: + { + if (ch == CR || ch == LF) + break; + parser->flags = 0; + parser->content_length = ULLONG_MAX; + + if (UNLIKELY(!IS_ALPHA(ch))) { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + + parser->method = (enum http_method) 0; + parser->index = 1; + switch (ch) { + case 'A': parser->method = HTTP_ACL; break; + case 'B': parser->method = HTTP_BIND; break; + case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; + case 'D': parser->method = HTTP_DELETE; break; + case 'G': parser->method = HTTP_GET; break; + case 'H': parser->method = HTTP_HEAD; break; + case 'L': parser->method = HTTP_LOCK; /* or LINK */ break; + case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break; + case 'N': parser->method = HTTP_NOTIFY; break; + case 'O': parser->method = HTTP_OPTIONS; break; + case 'P': parser->method = HTTP_POST; + /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ + break; + case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break; + case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH, SOURCE */ break; + case 'T': parser->method = HTTP_TRACE; break; + case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break; + default: + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + UPDATE_STATE(s_req_method); + + CALLBACK_NOTIFY(message_begin); + + break; + } + + case s_req_method: + { + const char *matcher; + if (UNLIKELY(ch == '\0')) { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + + matcher = method_strings[parser->method]; + if (ch == ' ' && matcher[parser->index] == '\0') { + UPDATE_STATE(s_req_spaces_before_url); + } else if (ch == matcher[parser->index]) { + ; /* nada */ + } else if ((ch >= 'A' && ch <= 'Z') || ch == '-') { + + switch (parser->method << 16 | parser->index << 8 | ch) { +#define XX(meth, pos, ch, new_meth) \ + case (HTTP_##meth << 16 | pos << 8 | ch): \ + parser->method = HTTP_##new_meth; break; + + XX(POST, 1, 'U', PUT) + XX(POST, 1, 'A', PATCH) + XX(POST, 1, 'R', PROPFIND) + XX(PUT, 2, 'R', PURGE) + XX(CONNECT, 1, 'H', CHECKOUT) + XX(CONNECT, 2, 'P', COPY) + XX(MKCOL, 1, 'O', MOVE) + XX(MKCOL, 1, 'E', MERGE) + XX(MKCOL, 1, '-', MSEARCH) + XX(MKCOL, 2, 'A', MKACTIVITY) + XX(MKCOL, 3, 'A', MKCALENDAR) + XX(SUBSCRIBE, 1, 'E', SEARCH) + XX(SUBSCRIBE, 1, 'O', SOURCE) + XX(REPORT, 2, 'B', REBIND) + XX(PROPFIND, 4, 'P', PROPPATCH) + XX(LOCK, 1, 'I', LINK) + XX(UNLOCK, 2, 'S', UNSUBSCRIBE) + XX(UNLOCK, 2, 'B', UNBIND) + XX(UNLOCK, 3, 'I', UNLINK) +#undef XX + default: + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + } else { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; + } + + ++parser->index; + break; + } + + case s_req_spaces_before_url: + { + if (ch == ' ') break; + + MARK(url); + if (parser->method == HTTP_CONNECT) { + UPDATE_STATE(s_req_server_start); + } + + UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); + if (UNLIKELY(CURRENT_STATE() == s_dead)) { + SET_ERRNO(HPE_INVALID_URL); + goto error; + } + + break; + } + + case s_req_schema: + case s_req_schema_slash: + case s_req_schema_slash_slash: + case s_req_server_start: + { + switch (ch) { + /* No whitespace allowed here */ + case ' ': + case CR: + case LF: + SET_ERRNO(HPE_INVALID_URL); + goto error; + default: + UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); + if (UNLIKELY(CURRENT_STATE() == s_dead)) { + SET_ERRNO(HPE_INVALID_URL); + goto error; + } + } + + break; + } + + case s_req_server: + case s_req_server_with_at: + case s_req_path: + case s_req_query_string_start: + case s_req_query_string: + case s_req_fragment_start: + case s_req_fragment: + { + switch (ch) { + case ' ': + UPDATE_STATE(s_req_http_start); + CALLBACK_DATA(url); + break; + case CR: + case LF: + parser->http_major = 0; + parser->http_minor = 9; + UPDATE_STATE((ch == CR) ? + s_req_line_almost_done : + s_header_field_start); + CALLBACK_DATA(url); + break; + default: + UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); + if (UNLIKELY(CURRENT_STATE() == s_dead)) { + SET_ERRNO(HPE_INVALID_URL); + goto error; + } + } + break; + } + + case s_req_http_start: + switch (ch) { + case ' ': + break; + case 'H': + UPDATE_STATE(s_req_http_H); + break; + case 'I': + if (parser->method == HTTP_SOURCE) { + UPDATE_STATE(s_req_http_I); + break; + } + /* fall through */ + default: + SET_ERRNO(HPE_INVALID_CONSTANT); + goto error; + } + break; + + case s_req_http_H: + STRICT_CHECK(ch != 'T'); + UPDATE_STATE(s_req_http_HT); + break; + + case s_req_http_HT: + STRICT_CHECK(ch != 'T'); + UPDATE_STATE(s_req_http_HTT); + break; + + case s_req_http_HTT: + STRICT_CHECK(ch != 'P'); + UPDATE_STATE(s_req_http_HTTP); + break; + + case s_req_http_I: + STRICT_CHECK(ch != 'C'); + UPDATE_STATE(s_req_http_IC); + break; + + case s_req_http_IC: + STRICT_CHECK(ch != 'E'); + UPDATE_STATE(s_req_http_HTTP); /* Treat "ICE" as "HTTP". */ + break; + + case s_req_http_HTTP: + STRICT_CHECK(ch != '/'); + UPDATE_STATE(s_req_http_major); + break; + + case s_req_http_major: + if (UNLIKELY(!IS_NUM(ch))) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_major = ch - '0'; + UPDATE_STATE(s_req_http_dot); + break; + + case s_req_http_dot: + { + if (UNLIKELY(ch != '.')) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + UPDATE_STATE(s_req_http_minor); + break; + } + + case s_req_http_minor: + if (UNLIKELY(!IS_NUM(ch))) { + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + } + + parser->http_minor = ch - '0'; + UPDATE_STATE(s_req_http_end); + break; + + case s_req_http_end: + { + if (ch == CR) { + UPDATE_STATE(s_req_line_almost_done); + break; + } + + if (ch == LF) { + UPDATE_STATE(s_header_field_start); + break; + } + + SET_ERRNO(HPE_INVALID_VERSION); + goto error; + break; + } + + /* end of request line */ + case s_req_line_almost_done: + { + if (UNLIKELY(ch != LF)) { + SET_ERRNO(HPE_LF_EXPECTED); + goto error; + } + + UPDATE_STATE(s_header_field_start); + break; + } + + case s_header_field_start: + { + if (ch == CR) { + UPDATE_STATE(s_headers_almost_done); + break; + } + + if (ch == LF) { + /* they might be just sending \n instead of \r\n so this would be + * the second \n to denote the end of headers*/ + UPDATE_STATE(s_headers_almost_done); + REEXECUTE(); + } + + c = TOKEN(ch); + + if (UNLIKELY(!c)) { + SET_ERRNO(HPE_INVALID_HEADER_TOKEN); + goto error; + } + + MARK(header_field); + + parser->index = 0; + UPDATE_STATE(s_header_field); + + switch (c) { + case 'c': + parser->header_state = h_C; + break; + + case 'p': + parser->header_state = h_matching_proxy_connection; + break; + + case 't': + parser->header_state = h_matching_transfer_encoding; + break; + + case 'u': + parser->header_state = h_matching_upgrade; + break; + + default: + parser->header_state = h_general; + break; + } + break; + } + + case s_header_field: + { + const char* start = p; + for (; p != data + len; p++) { + ch = *p; + c = TOKEN(ch); + + if (!c) + break; + + switch (parser->header_state) { + case h_general: { + size_t left = data + len - p; + const char* pe = p + MIN(left, max_header_size); + while (p+1 < pe && TOKEN(p[1])) { + p++; + } + break; + } + + case h_C: + parser->index++; + parser->header_state = (c == 'o' ? h_CO : h_general); + break; + + case h_CO: + parser->index++; + parser->header_state = (c == 'n' ? h_CON : h_general); + break; + + case h_CON: + parser->index++; + switch (c) { + case 'n': + parser->header_state = h_matching_connection; + break; + case 't': + parser->header_state = h_matching_content_length; + break; + default: + parser->header_state = h_general; + break; + } + break; + + /* connection */ + + case h_matching_connection: + parser->index++; + if (parser->index > sizeof(CONNECTION)-1 + || c != CONNECTION[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(CONNECTION)-2) { + parser->header_state = h_connection; + } + break; + + /* proxy-connection */ + + case h_matching_proxy_connection: + parser->index++; + if (parser->index > sizeof(PROXY_CONNECTION)-1 + || c != PROXY_CONNECTION[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { + parser->header_state = h_connection; + } + break; + + /* content-length */ + + case h_matching_content_length: + parser->index++; + if (parser->index > sizeof(CONTENT_LENGTH)-1 + || c != CONTENT_LENGTH[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { + parser->header_state = h_content_length; + } + break; + + /* transfer-encoding */ + + case h_matching_transfer_encoding: + parser->index++; + if (parser->index > sizeof(TRANSFER_ENCODING)-1 + || c != TRANSFER_ENCODING[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { + parser->header_state = h_transfer_encoding; + } + break; + + /* upgrade */ + + case h_matching_upgrade: + parser->index++; + if (parser->index > sizeof(UPGRADE)-1 + || c != UPGRADE[parser->index]) { + parser->header_state = h_general; + } else if (parser->index == sizeof(UPGRADE)-2) { + parser->header_state = h_upgrade; + } + break; + + case h_connection: + case h_content_length: + case h_transfer_encoding: + case h_upgrade: + if (ch != ' ') parser->header_state = h_general; + break; + + default: + assert(0 && "Unknown header_state"); + break; + } + } + + if (p == data + len) { + --p; + COUNT_HEADER_SIZE(p - start); + break; + } + + COUNT_HEADER_SIZE(p - start); + + if (ch == ':') { + UPDATE_STATE(s_header_value_discard_ws); + CALLBACK_DATA(header_field); + break; + } + + SET_ERRNO(HPE_INVALID_HEADER_TOKEN); + goto error; + } + + case s_header_value_discard_ws: + if (ch == ' ' || ch == '\t') break; + + if (ch == CR) { + UPDATE_STATE(s_header_value_discard_ws_almost_done); + break; + } + + if (ch == LF) { + UPDATE_STATE(s_header_value_discard_lws); + break; + } + + /* fall through */ + + case s_header_value_start: + { + MARK(header_value); + + UPDATE_STATE(s_header_value); + parser->index = 0; + + c = LOWER(ch); + + switch (parser->header_state) { + case h_upgrade: + parser->flags |= F_UPGRADE; + parser->header_state = h_general; + break; + + case h_transfer_encoding: + /* looking for 'Transfer-Encoding: chunked' */ + if ('c' == c) { + parser->header_state = h_matching_transfer_encoding_chunked; + } else { + parser->header_state = h_general; + } + break; + + case h_content_length: + if (UNLIKELY(!IS_NUM(ch))) { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + goto error; + } + + if (parser->flags & F_CONTENTLENGTH) { + SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); + goto error; + } + + parser->flags |= F_CONTENTLENGTH; + parser->content_length = ch - '0'; + parser->header_state = h_content_length_num; + break; + + /* when obsolete line folding is encountered for content length + * continue to the s_header_value state */ + case h_content_length_ws: + break; + + case h_connection: + /* looking for 'Connection: keep-alive' */ + if (c == 'k') { + parser->header_state = h_matching_connection_keep_alive; + /* looking for 'Connection: close' */ + } else if (c == 'c') { + parser->header_state = h_matching_connection_close; + } else if (c == 'u') { + parser->header_state = h_matching_connection_upgrade; + } else { + parser->header_state = h_matching_connection_token; + } + break; + + /* Multi-value `Connection` header */ + case h_matching_connection_token_start: + break; + + default: + parser->header_state = h_general; + break; + } + break; + } + + case s_header_value: + { + const char* start = p; + enum header_states h_state = (enum header_states) parser->header_state; + for (; p != data + len; p++) { + ch = *p; + if (ch == CR) { + UPDATE_STATE(s_header_almost_done); + parser->header_state = h_state; + CALLBACK_DATA(header_value); + break; + } + + if (ch == LF) { + UPDATE_STATE(s_header_almost_done); + COUNT_HEADER_SIZE(p - start); + parser->header_state = h_state; + CALLBACK_DATA_NOADVANCE(header_value); + REEXECUTE(); + } + + if (!lenient && !IS_HEADER_CHAR(ch)) { + SET_ERRNO(HPE_INVALID_HEADER_TOKEN); + goto error; + } + + c = LOWER(ch); + + switch (h_state) { + case h_general: + { + size_t left = data + len - p; + const char* pe = p + MIN(left, max_header_size); + + for (; p != pe; p++) { + ch = *p; + if (ch == CR || ch == LF) { + --p; + break; + } + if (!lenient && !IS_HEADER_CHAR(ch)) { + SET_ERRNO(HPE_INVALID_HEADER_TOKEN); + goto error; + } + } + if (p == data + len) + --p; + break; + } + + case h_connection: + case h_transfer_encoding: + assert(0 && "Shouldn't get here."); + break; + + case h_content_length: + if (ch == ' ') break; + h_state = h_content_length_num; + /* fall through */ + + case h_content_length_num: + { + uint64_t t; + + if (ch == ' ') { + h_state = h_content_length_ws; + break; + } + + if (UNLIKELY(!IS_NUM(ch))) { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + parser->header_state = h_state; + goto error; + } + + t = parser->content_length; + t *= 10; + t += ch - '0'; + + /* Overflow? Test against a conservative limit for simplicity. */ + if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + parser->header_state = h_state; + goto error; + } + + parser->content_length = t; + break; + } + + case h_content_length_ws: + if (ch == ' ') break; + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + parser->header_state = h_state; + goto error; + + /* Transfer-Encoding: chunked */ + case h_matching_transfer_encoding_chunked: + parser->index++; + if (parser->index > sizeof(CHUNKED)-1 + || c != CHUNKED[parser->index]) { + h_state = h_general; + } else if (parser->index == sizeof(CHUNKED)-2) { + h_state = h_transfer_encoding_chunked; + } + break; + + case h_matching_connection_token_start: + /* looking for 'Connection: keep-alive' */ + if (c == 'k') { + h_state = h_matching_connection_keep_alive; + /* looking for 'Connection: close' */ + } else if (c == 'c') { + h_state = h_matching_connection_close; + } else if (c == 'u') { + h_state = h_matching_connection_upgrade; + } else if (STRICT_TOKEN(c)) { + h_state = h_matching_connection_token; + } else if (c == ' ' || c == '\t') { + /* Skip lws */ + } else { + h_state = h_general; + } + break; + + /* looking for 'Connection: keep-alive' */ + case h_matching_connection_keep_alive: + parser->index++; + if (parser->index > sizeof(KEEP_ALIVE)-1 + || c != KEEP_ALIVE[parser->index]) { + h_state = h_matching_connection_token; + } else if (parser->index == sizeof(KEEP_ALIVE)-2) { + h_state = h_connection_keep_alive; + } + break; + + /* looking for 'Connection: close' */ + case h_matching_connection_close: + parser->index++; + if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { + h_state = h_matching_connection_token; + } else if (parser->index == sizeof(CLOSE)-2) { + h_state = h_connection_close; + } + break; + + /* looking for 'Connection: upgrade' */ + case h_matching_connection_upgrade: + parser->index++; + if (parser->index > sizeof(UPGRADE) - 1 || + c != UPGRADE[parser->index]) { + h_state = h_matching_connection_token; + } else if (parser->index == sizeof(UPGRADE)-2) { + h_state = h_connection_upgrade; + } + break; + + case h_matching_connection_token: + if (ch == ',') { + h_state = h_matching_connection_token_start; + parser->index = 0; + } + break; + + case h_transfer_encoding_chunked: + if (ch != ' ') h_state = h_general; + break; + + case h_connection_keep_alive: + case h_connection_close: + case h_connection_upgrade: + if (ch == ',') { + if (h_state == h_connection_keep_alive) { + parser->flags |= F_CONNECTION_KEEP_ALIVE; + } else if (h_state == h_connection_close) { + parser->flags |= F_CONNECTION_CLOSE; + } else if (h_state == h_connection_upgrade) { + parser->flags |= F_CONNECTION_UPGRADE; + } + h_state = h_matching_connection_token_start; + parser->index = 0; + } else if (ch != ' ') { + h_state = h_matching_connection_token; + } + break; + + default: + UPDATE_STATE(s_header_value); + h_state = h_general; + break; + } + } + parser->header_state = h_state; + + if (p == data + len) + --p; + + COUNT_HEADER_SIZE(p - start); + break; + } + + case s_header_almost_done: + { + if (UNLIKELY(ch != LF)) { + SET_ERRNO(HPE_LF_EXPECTED); + goto error; + } + + UPDATE_STATE(s_header_value_lws); + break; + } + + case s_header_value_lws: + { + if (ch == ' ' || ch == '\t') { + if (parser->header_state == h_content_length_num) { + /* treat obsolete line folding as space */ + parser->header_state = h_content_length_ws; + } + UPDATE_STATE(s_header_value_start); + REEXECUTE(); + } + + /* finished the header */ + switch (parser->header_state) { + case h_connection_keep_alive: + parser->flags |= F_CONNECTION_KEEP_ALIVE; + break; + case h_connection_close: + parser->flags |= F_CONNECTION_CLOSE; + break; + case h_transfer_encoding_chunked: + parser->flags |= F_CHUNKED; + break; + case h_connection_upgrade: + parser->flags |= F_CONNECTION_UPGRADE; + break; + default: + break; + } + + UPDATE_STATE(s_header_field_start); + REEXECUTE(); + } + + case s_header_value_discard_ws_almost_done: + { + STRICT_CHECK(ch != LF); + UPDATE_STATE(s_header_value_discard_lws); + break; + } + + case s_header_value_discard_lws: + { + if (ch == ' ' || ch == '\t') { + UPDATE_STATE(s_header_value_discard_ws); + break; + } else { + switch (parser->header_state) { + case h_connection_keep_alive: + parser->flags |= F_CONNECTION_KEEP_ALIVE; + break; + case h_connection_close: + parser->flags |= F_CONNECTION_CLOSE; + break; + case h_connection_upgrade: + parser->flags |= F_CONNECTION_UPGRADE; + break; + case h_transfer_encoding_chunked: + parser->flags |= F_CHUNKED; + break; + case h_content_length: + /* do not allow empty content length */ + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + goto error; + break; + default: + break; + } + + /* header value was empty */ + MARK(header_value); + UPDATE_STATE(s_header_field_start); + CALLBACK_DATA_NOADVANCE(header_value); + REEXECUTE(); + } + } + + case s_headers_almost_done: + { + STRICT_CHECK(ch != LF); + + if (parser->flags & F_TRAILING) { + /* End of a chunked request */ + UPDATE_STATE(s_message_done); + CALLBACK_NOTIFY_NOADVANCE(chunk_complete); + REEXECUTE(); + } + + /* Cannot use chunked encoding and a content-length header together + per the HTTP specification. */ + if ((parser->flags & F_CHUNKED) && + (parser->flags & F_CONTENTLENGTH)) { + SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); + goto error; + } + + UPDATE_STATE(s_headers_done); + + /* Set this here so that on_headers_complete() callbacks can see it */ + if ((parser->flags & F_UPGRADE) && + (parser->flags & F_CONNECTION_UPGRADE)) { + /* For responses, "Upgrade: foo" and "Connection: upgrade" are + * mandatory only when it is a 101 Switching Protocols response, + * otherwise it is purely informational, to announce support. + */ + parser->upgrade = + (parser->type == HTTP_REQUEST || parser->status_code == 101); + } else { + parser->upgrade = (parser->method == HTTP_CONNECT); + } + + /* Here we call the headers_complete callback. This is somewhat + * different than other callbacks because if the user returns 1, we + * will interpret that as saying that this message has no body. This + * is needed for the annoying case of recieving a response to a HEAD + * request. + * + * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so + * we have to simulate it by handling a change in errno below. + */ + if (settings->on_headers_complete) { + switch (settings->on_headers_complete(parser)) { + case 0: + break; + + case 2: + parser->upgrade = 1; + + /* fall through */ + case 1: + parser->flags |= F_SKIPBODY; + break; + + default: + SET_ERRNO(HPE_CB_headers_complete); + RETURN(p - data); /* Error */ + } + } + + if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { + RETURN(p - data); + } + + REEXECUTE(); + } + + case s_headers_done: + { + int hasBody; + STRICT_CHECK(ch != LF); + + parser->nread = 0; + nread = 0; + + hasBody = parser->flags & F_CHUNKED || + (parser->content_length > 0 && parser->content_length != ULLONG_MAX); + if (parser->upgrade && (parser->method == HTTP_CONNECT || + (parser->flags & F_SKIPBODY) || !hasBody)) { + /* Exit, the rest of the message is in a different protocol. */ + UPDATE_STATE(NEW_MESSAGE()); + CALLBACK_NOTIFY(message_complete); + RETURN((p - data) + 1); + } + + if (parser->flags & F_SKIPBODY) { + UPDATE_STATE(NEW_MESSAGE()); + CALLBACK_NOTIFY(message_complete); + } else if (parser->flags & F_CHUNKED) { + /* chunked encoding - ignore Content-Length header */ + UPDATE_STATE(s_chunk_size_start); + } else { + if (parser->content_length == 0) { + /* Content-Length header given but zero: Content-Length: 0\r\n */ + UPDATE_STATE(NEW_MESSAGE()); + CALLBACK_NOTIFY(message_complete); + } else if (parser->content_length != ULLONG_MAX) { + /* Content-Length header given and non-zero */ + UPDATE_STATE(s_body_identity); + } else { + if (!http_message_needs_eof(parser)) { + /* Assume content-length 0 - read the next */ + UPDATE_STATE(NEW_MESSAGE()); + CALLBACK_NOTIFY(message_complete); + } else { + /* Read body until EOF */ + UPDATE_STATE(s_body_identity_eof); + } + } + } + + break; + } + + case s_body_identity: + { + uint64_t to_read = MIN(parser->content_length, + (uint64_t) ((data + len) - p)); + + assert(parser->content_length != 0 + && parser->content_length != ULLONG_MAX); + + /* The difference between advancing content_length and p is because + * the latter will automaticaly advance on the next loop iteration. + * Further, if content_length ends up at 0, we want to see the last + * byte again for our message complete callback. + */ + MARK(body); + parser->content_length -= to_read; + p += to_read - 1; + + if (parser->content_length == 0) { + UPDATE_STATE(s_message_done); + + /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. + * + * The alternative to doing this is to wait for the next byte to + * trigger the data callback, just as in every other case. The + * problem with this is that this makes it difficult for the test + * harness to distinguish between complete-on-EOF and + * complete-on-length. It's not clear that this distinction is + * important for applications, but let's keep it for now. + */ + CALLBACK_DATA_(body, p - body_mark + 1, p - data); + REEXECUTE(); + } + + break; + } + + /* read until EOF */ + case s_body_identity_eof: + MARK(body); + p = data + len - 1; + + break; + + case s_message_done: + UPDATE_STATE(NEW_MESSAGE()); + CALLBACK_NOTIFY(message_complete); + if (parser->upgrade) { + /* Exit, the rest of the message is in a different protocol. */ + RETURN((p - data) + 1); + } + break; + + case s_chunk_size_start: + { + assert(nread == 1); + assert(parser->flags & F_CHUNKED); + + unhex_val = unhex[(unsigned char)ch]; + if (UNLIKELY(unhex_val == -1)) { + SET_ERRNO(HPE_INVALID_CHUNK_SIZE); + goto error; + } + + parser->content_length = unhex_val; + UPDATE_STATE(s_chunk_size); + break; + } + + case s_chunk_size: + { + uint64_t t; + + assert(parser->flags & F_CHUNKED); + + if (ch == CR) { + UPDATE_STATE(s_chunk_size_almost_done); + break; + } + + unhex_val = unhex[(unsigned char)ch]; + + if (unhex_val == -1) { + if (ch == ';' || ch == ' ') { + UPDATE_STATE(s_chunk_parameters); + break; + } + + SET_ERRNO(HPE_INVALID_CHUNK_SIZE); + goto error; + } + + t = parser->content_length; + t *= 16; + t += unhex_val; + + /* Overflow? Test against a conservative limit for simplicity. */ + if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) { + SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); + goto error; + } + + parser->content_length = t; + break; + } + + case s_chunk_parameters: + { + assert(parser->flags & F_CHUNKED); + /* just ignore this shit. TODO check for overflow */ + if (ch == CR) { + UPDATE_STATE(s_chunk_size_almost_done); + break; + } + break; + } + + case s_chunk_size_almost_done: + { + assert(parser->flags & F_CHUNKED); + STRICT_CHECK(ch != LF); + + parser->nread = 0; + nread = 0; + + if (parser->content_length == 0) { + parser->flags |= F_TRAILING; + UPDATE_STATE(s_header_field_start); + } else { + UPDATE_STATE(s_chunk_data); + } + CALLBACK_NOTIFY(chunk_header); + break; + } + + case s_chunk_data: + { + uint64_t to_read = MIN(parser->content_length, + (uint64_t) ((data + len) - p)); + + assert(parser->flags & F_CHUNKED); + assert(parser->content_length != 0 + && parser->content_length != ULLONG_MAX); + + /* See the explanation in s_body_identity for why the content + * length and data pointers are managed this way. + */ + MARK(body); + parser->content_length -= to_read; + p += to_read - 1; + + if (parser->content_length == 0) { + UPDATE_STATE(s_chunk_data_almost_done); + } + + break; + } + + case s_chunk_data_almost_done: + assert(parser->flags & F_CHUNKED); + assert(parser->content_length == 0); + STRICT_CHECK(ch != CR); + UPDATE_STATE(s_chunk_data_done); + CALLBACK_DATA(body); + break; + + case s_chunk_data_done: + assert(parser->flags & F_CHUNKED); + STRICT_CHECK(ch != LF); + parser->nread = 0; + nread = 0; + UPDATE_STATE(s_chunk_size_start); + CALLBACK_NOTIFY(chunk_complete); + break; + + default: + assert(0 && "unhandled state"); + SET_ERRNO(HPE_INVALID_INTERNAL_STATE); + goto error; + } + } + + /* Run callbacks for any marks that we have leftover after we ran out of + * bytes. There should be at most one of these set, so it's OK to invoke + * them in series (unset marks will not result in callbacks). + * + * We use the NOADVANCE() variety of callbacks here because 'p' has already + * overflowed 'data' and this allows us to correct for the off-by-one that + * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' + * value that's in-bounds). + */ + + assert(((header_field_mark ? 1 : 0) + + (header_value_mark ? 1 : 0) + + (url_mark ? 1 : 0) + + (body_mark ? 1 : 0) + + (status_mark ? 1 : 0)) <= 1); + + CALLBACK_DATA_NOADVANCE(header_field); + CALLBACK_DATA_NOADVANCE(header_value); + CALLBACK_DATA_NOADVANCE(url); + CALLBACK_DATA_NOADVANCE(body); + CALLBACK_DATA_NOADVANCE(status); + + RETURN(len); + +error: + if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { + SET_ERRNO(HPE_UNKNOWN); + } + + RETURN(p - data); +} + + +/* Does the parser need to see an EOF to find the end of the message? */ +int +http_message_needs_eof (const http_parser *parser) +{ + if (parser->type == HTTP_REQUEST) { + return 0; + } + + /* See RFC 2616 section 4.4 */ + if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ + parser->status_code == 204 || /* No Content */ + parser->status_code == 304 || /* Not Modified */ + parser->flags & F_SKIPBODY) { /* response to a HEAD request */ + return 0; + } + + if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { + return 0; + } + + return 1; +} + + +int +http_should_keep_alive (const http_parser *parser) +{ + if (parser->http_major > 0 && parser->http_minor > 0) { + /* HTTP/1.1 */ + if (parser->flags & F_CONNECTION_CLOSE) { + return 0; + } + } else { + /* HTTP/1.0 or earlier */ + if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { + return 0; + } + } + + return !http_message_needs_eof(parser); +} + + +const char * +http_method_str (enum http_method m) +{ + return ELEM_AT(method_strings, m, ""); +} + +const char * +http_status_str (enum http_status s) +{ + switch (s) { +#define XX(num, name, string) case HTTP_STATUS_##name: return #string; + HTTP_STATUS_MAP(XX) +#undef XX + default: return ""; + } +} + +void +http_parser_init (http_parser *parser, enum http_parser_type t) +{ + void *data = parser->data; /* preserve application data */ + memset(parser, 0, sizeof(*parser)); + parser->data = data; + parser->type = t; + parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); + parser->http_errno = HPE_OK; +} + +void +http_parser_settings_init(http_parser_settings *settings) +{ + memset(settings, 0, sizeof(*settings)); +} + +const char * +http_errno_name(enum http_errno err) { + assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); + return http_strerror_tab[err].name; +} + +const char * +http_errno_description(enum http_errno err) { + assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); + return http_strerror_tab[err].description; +} + +static enum http_host_state +http_parse_host_char(enum http_host_state s, const char ch) { + switch(s) { + case s_http_userinfo: + case s_http_userinfo_start: + if (ch == '@') { + return s_http_host_start; + } + + if (IS_USERINFO_CHAR(ch)) { + return s_http_userinfo; + } + break; + + case s_http_host_start: + if (ch == '[') { + return s_http_host_v6_start; + } + + if (IS_HOST_CHAR(ch)) { + return s_http_host; + } + + break; + + case s_http_host: + if (IS_HOST_CHAR(ch)) { + return s_http_host; + } + + /* fall through */ + case s_http_host_v6_end: + if (ch == ':') { + return s_http_host_port_start; + } + + break; + + case s_http_host_v6: + if (ch == ']') { + return s_http_host_v6_end; + } + + /* fall through */ + case s_http_host_v6_start: + if (IS_HEX(ch) || ch == ':' || ch == '.') { + return s_http_host_v6; + } + + if (s == s_http_host_v6 && ch == '%') { + return s_http_host_v6_zone_start; + } + break; + + case s_http_host_v6_zone: + if (ch == ']') { + return s_http_host_v6_end; + } + + /* fall through */ + case s_http_host_v6_zone_start: + /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */ + if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' || + ch == '~') { + return s_http_host_v6_zone; + } + break; + + case s_http_host_port: + case s_http_host_port_start: + if (IS_NUM(ch)) { + return s_http_host_port; + } + + break; + + default: + break; + } + return s_http_host_dead; +} + +static int +http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { + enum http_host_state s; + + const char *p; + size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; + + assert(u->field_set & (1 << UF_HOST)); + + u->field_data[UF_HOST].len = 0; + + s = found_at ? s_http_userinfo_start : s_http_host_start; + + for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { + enum http_host_state new_s = http_parse_host_char(s, *p); + + if (new_s == s_http_host_dead) { + return 1; + } + + switch(new_s) { + case s_http_host: + if (s != s_http_host) { + u->field_data[UF_HOST].off = (uint16_t)(p - buf); + } + u->field_data[UF_HOST].len++; + break; + + case s_http_host_v6: + if (s != s_http_host_v6) { + u->field_data[UF_HOST].off = (uint16_t)(p - buf); + } + u->field_data[UF_HOST].len++; + break; + + case s_http_host_v6_zone_start: + case s_http_host_v6_zone: + u->field_data[UF_HOST].len++; + break; + + case s_http_host_port: + if (s != s_http_host_port) { + u->field_data[UF_PORT].off = (uint16_t)(p - buf); + u->field_data[UF_PORT].len = 0; + u->field_set |= (1 << UF_PORT); + } + u->field_data[UF_PORT].len++; + break; + + case s_http_userinfo: + if (s != s_http_userinfo) { + u->field_data[UF_USERINFO].off = (uint16_t)(p - buf); + u->field_data[UF_USERINFO].len = 0; + u->field_set |= (1 << UF_USERINFO); + } + u->field_data[UF_USERINFO].len++; + break; + + default: + break; + } + s = new_s; + } + + /* Make sure we don't end somewhere unexpected */ + switch (s) { + case s_http_host_start: + case s_http_host_v6_start: + case s_http_host_v6: + case s_http_host_v6_zone_start: + case s_http_host_v6_zone: + case s_http_host_port_start: + case s_http_userinfo: + case s_http_userinfo_start: + return 1; + default: + break; + } + + return 0; +} + +void +http_parser_url_init(struct http_parser_url *u) { + memset(u, 0, sizeof(*u)); +} + +int +http_parser_parse_url(const char *buf, size_t buflen, int is_connect, + struct http_parser_url *u) +{ + enum state s; + const char *p; + enum http_parser_url_fields uf, old_uf; + int found_at = 0; + + if (buflen == 0) { + return 1; + } + + u->port = u->field_set = 0; + s = is_connect ? s_req_server_start : s_req_spaces_before_url; + old_uf = UF_MAX; + + for (p = buf; p < buf + buflen; p++) { + s = parse_url_char(s, *p); + + /* Figure out the next field that we're operating on */ + switch (s) { + case s_dead: + return 1; + + /* Skip delimeters */ + case s_req_schema_slash: + case s_req_schema_slash_slash: + case s_req_server_start: + case s_req_query_string_start: + case s_req_fragment_start: + continue; + + case s_req_schema: + uf = UF_SCHEMA; + break; + + case s_req_server_with_at: + found_at = 1; + + /* fall through */ + case s_req_server: + uf = UF_HOST; + break; + + case s_req_path: + uf = UF_PATH; + break; + + case s_req_query_string: + uf = UF_QUERY; + break; + + case s_req_fragment: + uf = UF_FRAGMENT; + break; + + default: + assert(!"Unexpected state"); + return 1; + } + + /* Nothing's changed; soldier on */ + if (uf == old_uf) { + u->field_data[uf].len++; + continue; + } + + u->field_data[uf].off = (uint16_t)(p - buf); + u->field_data[uf].len = 1; + + u->field_set |= (1 << uf); + old_uf = uf; + } + + /* host must be present if there is a schema */ + /* parsing http:///toto will fail */ + if ((u->field_set & (1 << UF_SCHEMA)) && + (u->field_set & (1 << UF_HOST)) == 0) { + return 1; + } + + if (u->field_set & (1 << UF_HOST)) { + if (http_parse_host(buf, u, found_at) != 0) { + return 1; + } + } + + /* CONNECT requests can only contain "hostname:port" */ + if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { + return 1; + } + + if (u->field_set & (1 << UF_PORT)) { + uint16_t off; + uint16_t len; + const char* p; + const char* end; + unsigned long v; + + off = u->field_data[UF_PORT].off; + len = u->field_data[UF_PORT].len; + end = buf + off + len; + + /* NOTE: The characters are already validated and are in the [0-9] range */ + assert(off + len <= buflen && "Port number overflow"); + v = 0; + for (p = buf + off; p < end; p++) { + v *= 10; + v += *p - '0'; + + /* Ports have a max value of 2^16 */ + if (v > 0xffff) { + return 1; + } + } + + u->port = (uint16_t) v; + } + + return 0; +} + +void +http_parser_pause(http_parser *parser, int paused) { + /* Users should only be pausing/unpausing a parser that is not in an error + * state. In non-debug builds, there's not much that we can do about this + * other than ignore it. + */ + if (HTTP_PARSER_ERRNO(parser) == HPE_OK || + HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { + uint32_t nread = parser->nread; /* used by the SET_ERRNO macro */ + SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); + } else { + assert(0 && "Attempting to pause parser in error state"); + } +} + +int +http_body_is_final(const struct http_parser *parser) { + return parser->state == s_message_done; +} + +unsigned long +http_parser_version(void) { + return HTTP_PARSER_VERSION_MAJOR * 0x10000 | + HTTP_PARSER_VERSION_MINOR * 0x00100 | + HTTP_PARSER_VERSION_PATCH * 0x00001; +} + +void +http_parser_set_max_header_size(uint32_t size) { + max_header_size = size; +} diff --git a/FreeRTOS-Labs/Source/http-parser/http_parser.h b/FreeRTOS-Labs/Source/http-parser/http_parser.h new file mode 100644 index 000000000..51c90da59 --- /dev/null +++ b/FreeRTOS-Labs/Source/http-parser/http_parser.h @@ -0,0 +1,439 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * 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. + */ +#ifndef http_parser_h +#define http_parser_h +#ifdef __cplusplus +extern "C" { +#endif + +/* Also update SONAME in the Makefile whenever you change these. */ +#define HTTP_PARSER_VERSION_MAJOR 2 +#define HTTP_PARSER_VERSION_MINOR 9 +#define HTTP_PARSER_VERSION_PATCH 2 + +#include +#if defined(_WIN32) && !defined(__MINGW32__) && \ + (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__) +#include +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run + * faster + */ +#ifndef HTTP_PARSER_STRICT +# define HTTP_PARSER_STRICT 1 +#endif + +/* Maximium header size allowed. If the macro is not defined + * before including this header then the default is used. To + * change the maximum header size, define the macro in the build + * environment (e.g. -DHTTP_MAX_HEADER_SIZE=). To remove + * the effective limit on the size of the header, define the macro + * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff) + */ +#ifndef HTTP_MAX_HEADER_SIZE +# define HTTP_MAX_HEADER_SIZE (80*1024) +#endif + +typedef struct http_parser http_parser; +typedef struct http_parser_settings http_parser_settings; + + +/* Callbacks should return non-zero to indicate an error. The parser will + * then halt execution. + * + * The one exception is on_headers_complete. In a HTTP_RESPONSE parser + * returning '1' from on_headers_complete will tell the parser that it + * should not expect a body. This is used when receiving a response to a + * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: + * chunked' headers that indicate the presence of a body. + * + * Returning `2` from on_headers_complete will tell parser that it should not + * expect neither a body nor any futher responses on this connection. This is + * useful for handling responses to a CONNECT request which may not contain + * `Upgrade` or `Connection: upgrade` headers. + * + * http_data_cb does not return data chunks. It will be called arbitrarily + * many times for each string. E.G. you might get 10 callbacks for "on_url" + * each providing just a few characters more data. + */ +typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); +typedef int (*http_cb) (http_parser*); + + +/* Status Codes */ +#define HTTP_STATUS_MAP(XX) \ + XX(100, CONTINUE, Continue) \ + XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \ + XX(102, PROCESSING, Processing) \ + XX(200, OK, OK) \ + XX(201, CREATED, Created) \ + XX(202, ACCEPTED, Accepted) \ + XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \ + XX(204, NO_CONTENT, No Content) \ + XX(205, RESET_CONTENT, Reset Content) \ + XX(206, PARTIAL_CONTENT, Partial Content) \ + XX(207, MULTI_STATUS, Multi-Status) \ + XX(208, ALREADY_REPORTED, Already Reported) \ + XX(226, IM_USED, IM Used) \ + XX(300, MULTIPLE_CHOICES, Multiple Choices) \ + XX(301, MOVED_PERMANENTLY, Moved Permanently) \ + XX(302, FOUND, Found) \ + XX(303, SEE_OTHER, See Other) \ + XX(304, NOT_MODIFIED, Not Modified) \ + XX(305, USE_PROXY, Use Proxy) \ + XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \ + XX(308, PERMANENT_REDIRECT, Permanent Redirect) \ + XX(400, BAD_REQUEST, Bad Request) \ + XX(401, UNAUTHORIZED, Unauthorized) \ + XX(402, PAYMENT_REQUIRED, Payment Required) \ + XX(403, FORBIDDEN, Forbidden) \ + XX(404, NOT_FOUND, Not Found) \ + XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \ + XX(406, NOT_ACCEPTABLE, Not Acceptable) \ + XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \ + XX(408, REQUEST_TIMEOUT, Request Timeout) \ + XX(409, CONFLICT, Conflict) \ + XX(410, GONE, Gone) \ + XX(411, LENGTH_REQUIRED, Length Required) \ + XX(412, PRECONDITION_FAILED, Precondition Failed) \ + XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \ + XX(414, URI_TOO_LONG, URI Too Long) \ + XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \ + XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \ + XX(417, EXPECTATION_FAILED, Expectation Failed) \ + XX(421, MISDIRECTED_REQUEST, Misdirected Request) \ + XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \ + XX(423, LOCKED, Locked) \ + XX(424, FAILED_DEPENDENCY, Failed Dependency) \ + XX(426, UPGRADE_REQUIRED, Upgrade Required) \ + XX(428, PRECONDITION_REQUIRED, Precondition Required) \ + XX(429, TOO_MANY_REQUESTS, Too Many Requests) \ + XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \ + XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \ + XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \ + XX(501, NOT_IMPLEMENTED, Not Implemented) \ + XX(502, BAD_GATEWAY, Bad Gateway) \ + XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \ + XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \ + XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \ + XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \ + XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \ + XX(508, LOOP_DETECTED, Loop Detected) \ + XX(510, NOT_EXTENDED, Not Extended) \ + XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \ + +enum http_status + { +#define XX(num, name, string) HTTP_STATUS_##name = num, + HTTP_STATUS_MAP(XX) +#undef XX + }; + + +/* Request Methods */ +#define HTTP_METHOD_MAP(XX) \ + XX(0, DELETE, DELETE) \ + XX(1, GET, GET) \ + XX(2, HEAD, HEAD) \ + XX(3, POST, POST) \ + XX(4, PUT, PUT) \ + /* pathological */ \ + XX(5, CONNECT, CONNECT) \ + XX(6, OPTIONS, OPTIONS) \ + XX(7, TRACE, TRACE) \ + /* WebDAV */ \ + XX(8, COPY, COPY) \ + XX(9, LOCK, LOCK) \ + XX(10, MKCOL, MKCOL) \ + XX(11, MOVE, MOVE) \ + XX(12, PROPFIND, PROPFIND) \ + XX(13, PROPPATCH, PROPPATCH) \ + XX(14, SEARCH, SEARCH) \ + XX(15, UNLOCK, UNLOCK) \ + XX(16, BIND, BIND) \ + XX(17, REBIND, REBIND) \ + XX(18, UNBIND, UNBIND) \ + XX(19, ACL, ACL) \ + /* subversion */ \ + XX(20, REPORT, REPORT) \ + XX(21, MKACTIVITY, MKACTIVITY) \ + XX(22, CHECKOUT, CHECKOUT) \ + XX(23, MERGE, MERGE) \ + /* upnp */ \ + XX(24, MSEARCH, M-SEARCH) \ + XX(25, NOTIFY, NOTIFY) \ + XX(26, SUBSCRIBE, SUBSCRIBE) \ + XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ + /* RFC-5789 */ \ + XX(28, PATCH, PATCH) \ + XX(29, PURGE, PURGE) \ + /* CalDAV */ \ + XX(30, MKCALENDAR, MKCALENDAR) \ + /* RFC-2068, section 19.6.1.2 */ \ + XX(31, LINK, LINK) \ + XX(32, UNLINK, UNLINK) \ + /* icecast */ \ + XX(33, SOURCE, SOURCE) \ + +enum http_method + { +#define XX(num, name, string) HTTP_##name = num, + HTTP_METHOD_MAP(XX) +#undef XX + }; + + +enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; + + +/* Flag values for http_parser.flags field */ +enum flags + { F_CHUNKED = 1 << 0 + , F_CONNECTION_KEEP_ALIVE = 1 << 1 + , F_CONNECTION_CLOSE = 1 << 2 + , F_CONNECTION_UPGRADE = 1 << 3 + , F_TRAILING = 1 << 4 + , F_UPGRADE = 1 << 5 + , F_SKIPBODY = 1 << 6 + , F_CONTENTLENGTH = 1 << 7 + }; + + +/* Map for errno-related constants + * + * The provided argument should be a macro that takes 2 arguments. + */ +#define HTTP_ERRNO_MAP(XX) \ + /* No error */ \ + XX(OK, "success") \ + \ + /* Callback-related errors */ \ + XX(CB_message_begin, "the on_message_begin callback failed") \ + XX(CB_url, "the on_url callback failed") \ + XX(CB_header_field, "the on_header_field callback failed") \ + XX(CB_header_value, "the on_header_value callback failed") \ + XX(CB_headers_complete, "the on_headers_complete callback failed") \ + XX(CB_body, "the on_body callback failed") \ + XX(CB_message_complete, "the on_message_complete callback failed") \ + XX(CB_status, "the on_status callback failed") \ + XX(CB_chunk_header, "the on_chunk_header callback failed") \ + XX(CB_chunk_complete, "the on_chunk_complete callback failed") \ + \ + /* Parsing-related errors */ \ + XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ + XX(HEADER_OVERFLOW, \ + "too many header bytes seen; overflow detected") \ + XX(CLOSED_CONNECTION, \ + "data received after completed connection: close message") \ + XX(INVALID_VERSION, "invalid HTTP version") \ + XX(INVALID_STATUS, "invalid HTTP status code") \ + XX(INVALID_METHOD, "invalid HTTP method") \ + XX(INVALID_URL, "invalid URL") \ + XX(INVALID_HOST, "invalid host") \ + XX(INVALID_PORT, "invalid port") \ + XX(INVALID_PATH, "invalid path") \ + XX(INVALID_QUERY_STRING, "invalid query string") \ + XX(INVALID_FRAGMENT, "invalid fragment") \ + XX(LF_EXPECTED, "LF character expected") \ + XX(INVALID_HEADER_TOKEN, "invalid character in header") \ + XX(INVALID_CONTENT_LENGTH, \ + "invalid character in content-length header") \ + XX(UNEXPECTED_CONTENT_LENGTH, \ + "unexpected content-length header") \ + XX(INVALID_CHUNK_SIZE, \ + "invalid character in chunk size header") \ + XX(INVALID_CONSTANT, "invalid constant string") \ + XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ + XX(STRICT, "strict mode assertion failed") \ + XX(PAUSED, "parser is paused") \ + XX(UNKNOWN, "an unknown error occurred") + + +/* Define HPE_* values for each errno value above */ +#define HTTP_ERRNO_GEN(n, s) HPE_##n, +enum http_errno { + HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) +}; +#undef HTTP_ERRNO_GEN + + +/* Get an http_errno value from an http_parser */ +#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) + + +struct http_parser { + /** PRIVATE **/ + unsigned int type : 2; /* enum http_parser_type */ + unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */ + unsigned int state : 7; /* enum state from http_parser.c */ + unsigned int header_state : 7; /* enum header_state from http_parser.c */ + unsigned int index : 7; /* index into current matcher */ + unsigned int lenient_http_headers : 1; + + uint32_t nread; /* # bytes read in various scenarios */ + uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ + + /** READ-ONLY **/ + unsigned short http_major; + unsigned short http_minor; + unsigned int status_code : 16; /* responses only */ + unsigned int method : 8; /* requests only */ + unsigned int http_errno : 7; + + /* 1 = Upgrade header was present and the parser has exited because of that. + * 0 = No upgrade header present. + * Should be checked when http_parser_execute() returns in addition to + * error checking. + */ + unsigned int upgrade : 1; + + /** PUBLIC **/ + void *data; /* A pointer to get hook to the "connection" or "socket" object */ +}; + + +struct http_parser_settings { + http_cb on_message_begin; + http_data_cb on_url; + http_data_cb on_status; + http_data_cb on_header_field; + http_data_cb on_header_value; + http_cb on_headers_complete; + http_data_cb on_body; + http_cb on_message_complete; + /* When on_chunk_header is called, the current chunk length is stored + * in parser->content_length. + */ + http_cb on_chunk_header; + http_cb on_chunk_complete; +}; + + +enum http_parser_url_fields + { UF_SCHEMA = 0 + , UF_HOST = 1 + , UF_PORT = 2 + , UF_PATH = 3 + , UF_QUERY = 4 + , UF_FRAGMENT = 5 + , UF_USERINFO = 6 + , UF_MAX = 7 + }; + + +/* Result structure for http_parser_parse_url(). + * + * Callers should index into field_data[] with UF_* values iff field_set + * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and + * because we probably have padding left over), we convert any port to + * a uint16_t. + */ +struct http_parser_url { + uint16_t field_set; /* Bitmask of (1 << UF_*) values */ + uint16_t port; /* Converted UF_PORT string */ + + struct { + uint16_t off; /* Offset into buffer in which field starts */ + uint16_t len; /* Length of run in buffer */ + } field_data[UF_MAX]; +}; + + +/* Returns the library version. Bits 16-23 contain the major version number, + * bits 8-15 the minor version number and bits 0-7 the patch level. + * Usage example: + * + * unsigned long version = http_parser_version(); + * unsigned major = (version >> 16) & 255; + * unsigned minor = (version >> 8) & 255; + * unsigned patch = version & 255; + * printf("http_parser v%u.%u.%u\n", major, minor, patch); + */ +unsigned long http_parser_version(void); + +void http_parser_init(http_parser *parser, enum http_parser_type type); + + +/* Initialize http_parser_settings members to 0 + */ +void http_parser_settings_init(http_parser_settings *settings); + + +/* Executes the parser. Returns number of parsed bytes. Sets + * `parser->http_errno` on error. */ +size_t http_parser_execute(http_parser *parser, + const http_parser_settings *settings, + const char *data, + size_t len); + + +/* If http_should_keep_alive() in the on_headers_complete or + * on_message_complete callback returns 0, then this should be + * the last message on the connection. + * If you are the server, respond with the "Connection: close" header. + * If you are the client, close the connection. + */ +int http_should_keep_alive(const http_parser *parser); + +/* Returns a string version of the HTTP method. */ +const char *http_method_str(enum http_method m); + +/* Returns a string version of the HTTP status code. */ +const char *http_status_str(enum http_status s); + +/* Return a string name of the given error */ +const char *http_errno_name(enum http_errno err); + +/* Return a string description of the given error */ +const char *http_errno_description(enum http_errno err); + +/* Initialize all http_parser_url members to 0 */ +void http_parser_url_init(struct http_parser_url *u); + +/* Parse a URL; return nonzero on failure */ +int http_parser_parse_url(const char *buf, size_t buflen, + int is_connect, + struct http_parser_url *u); + +/* Pause or un-pause the parser; a nonzero value pauses */ +void http_parser_pause(http_parser *parser, int paused); + +/* Checks if this is the final chunk of the body. */ +int http_body_is_final(const http_parser *parser); + +/* Change the maximum header size provided at compile time. */ +void http_parser_set_max_header_size(uint32_t size); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/aes.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/aes.h new file mode 100644 index 000000000..4131f1d98 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/aes.h @@ -0,0 +1,674 @@ +/** + * \file aes.h + * + * \brief This file contains AES definitions and functions. + * + * The Advanced Encryption Standard (AES) specifies a FIPS-approved + * cryptographic algorithm that can be used to protect electronic + * data. + * + * The AES algorithm is a symmetric block cipher that can + * encrypt and decrypt information. For more information, see + * FIPS Publication 197: Advanced Encryption Standard and + * ISO/IEC 18033-2:2006: Information technology -- Security + * techniques -- Encryption algorithms -- Part 2: Asymmetric + * ciphers. + * + * The AES-XTS block mode is standardized by NIST SP 800-38E + * + * and described in detail by IEEE P1619 + * . + */ + +/* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_AES_H +#define MBEDTLS_AES_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +/* padlock.c and aesni.c rely on these values! */ +#define MBEDTLS_AES_ENCRYPT 1 /**< AES encryption. */ +#define MBEDTLS_AES_DECRYPT 0 /**< AES decryption. */ + +/* Error codes in range 0x0020-0x0022 */ +#define MBEDTLS_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ +#define MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ + +/* Error codes in range 0x0021-0x0025 */ +#define MBEDTLS_ERR_AES_BAD_INPUT_DATA -0x0021 /**< Invalid input data. */ + +/* MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE is deprecated and should not be used. */ +#define MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE -0x0023 /**< Feature not available. For example, an unsupported AES key size. */ + +/* MBEDTLS_ERR_AES_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_AES_HW_ACCEL_FAILED -0x0025 /**< AES hardware accelerator failed. */ + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_AES_ALT) +// Regular implementation +// + +/** + * \brief The AES context-type definition. + */ +typedef struct mbedtls_aes_context +{ + int nr; /*!< The number of rounds. */ + uint32_t *rk; /*!< AES round keys. */ + uint32_t buf[68]; /*!< Unaligned data buffer. This buffer can + hold 32 extra Bytes, which can be used for + one of the following purposes: +
  • Alignment if VIA padlock is + used.
  • +
  • Simplifying key expansion in the 256-bit + case by generating an extra round key. +
*/ +} +mbedtls_aes_context; + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief The AES XTS context-type definition. + */ +typedef struct mbedtls_aes_xts_context +{ + mbedtls_aes_context crypt; /*!< The AES context to use for AES block + encryption or decryption. */ + mbedtls_aes_context tweak; /*!< The AES context used for tweak + computation. */ +} mbedtls_aes_xts_context; +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#else /* MBEDTLS_AES_ALT */ +#include "aes_alt.h" +#endif /* MBEDTLS_AES_ALT */ + +/** + * \brief This function initializes the specified AES context. + * + * It must be the first API called before using + * the context. + * + * \param ctx The AES context to initialize. This must not be \c NULL. + */ +void mbedtls_aes_init( mbedtls_aes_context *ctx ); + +/** + * \brief This function releases and clears the specified AES context. + * + * \param ctx The AES context to clear. + * If this is \c NULL, this function does nothing. + * Otherwise, the context must have been at least initialized. + */ +void mbedtls_aes_free( mbedtls_aes_context *ctx ); + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief This function initializes the specified AES XTS context. + * + * It must be the first API called before using + * the context. + * + * \param ctx The AES XTS context to initialize. This must not be \c NULL. + */ +void mbedtls_aes_xts_init( mbedtls_aes_xts_context *ctx ); + +/** + * \brief This function releases and clears the specified AES XTS context. + * + * \param ctx The AES XTS context to clear. + * If this is \c NULL, this function does nothing. + * Otherwise, the context must have been at least initialized. + */ +void mbedtls_aes_xts_free( mbedtls_aes_xts_context *ctx ); +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +/** + * \brief This function sets the encryption key. + * + * \param ctx The AES context to which the key should be bound. + * It must be initialized. + * \param key The encryption key. + * This must be a readable buffer of size \p keybits bits. + * \param keybits The size of data passed in bits. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief This function sets the decryption key. + * + * \param ctx The AES context to which the key should be bound. + * It must be initialized. + * \param key The decryption key. + * This must be a readable buffer of size \p keybits bits. + * \param keybits The size of data passed. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ); + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief This function prepares an XTS context for encryption and + * sets the encryption key. + * + * \param ctx The AES XTS context to which the key should be bound. + * It must be initialized. + * \param key The encryption key. This is comprised of the XTS key1 + * concatenated with the XTS key2. + * This must be a readable buffer of size \p keybits bits. + * \param keybits The size of \p key passed in bits. Valid options are: + *
  • 256 bits (each of key1 and key2 is a 128-bit key)
  • + *
  • 512 bits (each of key1 and key2 is a 256-bit key)
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +int mbedtls_aes_xts_setkey_enc( mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief This function prepares an XTS context for decryption and + * sets the decryption key. + * + * \param ctx The AES XTS context to which the key should be bound. + * It must be initialized. + * \param key The decryption key. This is comprised of the XTS key1 + * concatenated with the XTS key2. + * This must be a readable buffer of size \p keybits bits. + * \param keybits The size of \p key passed in bits. Valid options are: + *
  • 256 bits (each of key1 and key2 is a 128-bit key)
  • + *
  • 512 bits (each of key1 and key2 is a 256-bit key)
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +int mbedtls_aes_xts_setkey_dec( mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits ); +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +/** + * \brief This function performs an AES single-block encryption or + * decryption operation. + * + * It performs the operation defined in the \p mode parameter + * (encrypt or decrypt), on the input data buffer defined in + * the \p input parameter. + * + * mbedtls_aes_init(), and either mbedtls_aes_setkey_enc() or + * mbedtls_aes_setkey_dec() must be called before the first + * call to this API with the same context. + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or + * #MBEDTLS_AES_DECRYPT. + * \param input The buffer holding the input data. + * It must be readable and at least \c 16 Bytes long. + * \param output The buffer where the output data will be written. + * It must be writeable and at least \c 16 Bytes long. + + * \return \c 0 on success. + */ +int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief This function performs an AES-CBC encryption or decryption operation + * on full blocks. + * + * It performs the operation defined in the \p mode + * parameter (encrypt/decrypt), on the input data buffer defined in + * the \p input parameter. + * + * It can be called as many times as needed, until all the input + * data is processed. mbedtls_aes_init(), and either + * mbedtls_aes_setkey_enc() or mbedtls_aes_setkey_dec() must be called + * before the first call to this API with the same context. + * + * \note This function operates on full blocks, that is, the input size + * must be a multiple of the AES block size of \c 16 Bytes. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the IV, you should + * either save it manually or use the cipher module instead. + * + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or + * #MBEDTLS_AES_DECRYPT. + * \param length The length of the input data in Bytes. This must be a + * multiple of the block size (\c 16 Bytes). + * \param iv Initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. + * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. + * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH + * on failure. + */ +int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief This function performs an AES-XTS encryption or decryption + * operation for an entire XTS data unit. + * + * AES-XTS encrypts or decrypts blocks based on their location as + * defined by a data unit number. The data unit number must be + * provided by \p data_unit. + * + * NIST SP 800-38E limits the maximum size of a data unit to 2^20 + * AES blocks. If the data unit is larger than this, this function + * returns #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH. + * + * \param ctx The AES XTS context to use for AES XTS operations. + * It must be initialized and bound to a key. + * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or + * #MBEDTLS_AES_DECRYPT. + * \param length The length of a data unit in Bytes. This can be any + * length between 16 bytes and 2^24 bytes inclusive + * (between 1 and 2^20 block cipher blocks). + * \param data_unit The address of the data unit encoded as an array of 16 + * bytes in little-endian format. For disk encryption, this + * is typically the index of the block device sector that + * contains the data. + * \param input The buffer holding the input data (which is an entire + * data unit). This function reads \p length Bytes from \p + * input. + * \param output The buffer holding the output data (which is an entire + * data unit). This function writes \p length Bytes to \p + * output. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH if \p length is + * smaller than an AES block in size (16 Bytes) or if \p + * length is larger than 2^20 blocks (16 MiB). + */ +int mbedtls_aes_crypt_xts( mbedtls_aes_xts_context *ctx, + int mode, + size_t length, + const unsigned char data_unit[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief This function performs an AES-CFB128 encryption or decryption + * operation. + * + * It performs the operation defined in the \p mode + * parameter (encrypt or decrypt), on the input data buffer + * defined in the \p input parameter. + * + * For CFB, you must set up the context with mbedtls_aes_setkey_enc(), + * regardless of whether you are performing an encryption or decryption + * operation, that is, regardless of the \p mode parameter. This is + * because CFB mode uses the same key schedule for encryption and + * decryption. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the + * IV, you must either save it manually or use the cipher + * module instead. + * + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or + * #MBEDTLS_AES_DECRYPT. + * \param length The length of the input data in Bytes. + * \param iv_off The offset in IV (updated after use). + * It must point to a valid \c size_t. + * \param iv The initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. + * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. + * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. + * + * \return \c 0 on success. + */ +int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function performs an AES-CFB8 encryption or decryption + * operation. + * + * It performs the operation defined in the \p mode + * parameter (encrypt/decrypt), on the input data buffer defined + * in the \p input parameter. + * + * Due to the nature of CFB, you must use the same key schedule for + * both encryption and decryption operations. Therefore, you must + * use the context initialized with mbedtls_aes_setkey_enc() for + * both #MBEDTLS_AES_ENCRYPT and #MBEDTLS_AES_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or + * #MBEDTLS_AES_DECRYPT + * \param length The length of the input data. + * \param iv The initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. + * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. + * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. + * + * \return \c 0 on success. + */ +int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +/** + * \brief This function performs an AES-OFB (Output Feedback Mode) + * encryption or decryption operation. + * + * For OFB, you must set up the context with + * mbedtls_aes_setkey_enc(), regardless of whether you are + * performing an encryption or decryption operation. This is + * because OFB mode uses the same key schedule for encryption and + * decryption. + * + * The OFB operation is identical for encryption or decryption, + * therefore no operation mode needs to be specified. + * + * \note Upon exit, the content of iv, the Initialisation Vector, is + * updated so that you can call the same function again on the next + * block(s) of data and get the same result as if it was encrypted + * in one call. This allows a "streaming" usage, by initialising + * iv_off to 0 before the first call, and preserving its value + * between calls. + * + * For non-streaming use, the iv should be initialised on each call + * to a unique value, and iv_off set to 0 on each call. + * + * If you need to retain the contents of the initialisation vector, + * you must either save it manually or use the cipher module + * instead. + * + * \warning For the OFB mode, the initialisation vector must be unique + * every encryption operation. Reuse of an initialisation vector + * will compromise security. + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param length The length of the input data. + * \param iv_off The offset in IV (updated after use). + * It must point to a valid \c size_t. + * \param iv The initialization vector (updated after use). + * It must be a readable and writeable buffer of \c 16 Bytes. + * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. + * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. + * + * \return \c 0 on success. + */ +int mbedtls_aes_crypt_ofb( mbedtls_aes_context *ctx, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief This function performs an AES-CTR encryption or decryption + * operation. + * + * This function performs the operation defined in the \p mode + * parameter (encrypt/decrypt), on the input data buffer + * defined in the \p input parameter. + * + * Due to the nature of CTR, you must use the same key schedule + * for both encryption and decryption operations. Therefore, you + * must use the context initialized with mbedtls_aes_setkey_enc() + * for both #MBEDTLS_AES_ENCRYPT and #MBEDTLS_AES_DECRYPT. + * + * \warning You must never reuse a nonce value with the same key. Doing so + * would void the encryption for the two messages encrypted with + * the same nonce and key. + * + * There are two common strategies for managing nonces with CTR: + * + * 1. You can handle everything as a single message processed over + * successive calls to this function. In that case, you want to + * set \p nonce_counter and \p nc_off to 0 for the first call, and + * then preserve the values of \p nonce_counter, \p nc_off and \p + * stream_block across calls to this function as they will be + * updated by this function. + * + * With this strategy, you must not encrypt more than 2**128 + * blocks of data with the same key. + * + * 2. You can encrypt separate messages by dividing the \p + * nonce_counter buffer in two areas: the first one used for a + * per-message nonce, handled by yourself, and the second one + * updated by this function internally. + * + * For example, you might reserve the first 12 bytes for the + * per-message nonce, and the last 4 bytes for internal use. In that + * case, before calling this function on a new message you need to + * set the first 12 bytes of \p nonce_counter to your chosen nonce + * value, the last 4 to 0, and \p nc_off to 0 (which will cause \p + * stream_block to be ignored). That way, you can encrypt at most + * 2**96 messages of up to 2**32 blocks each with the same key. + * + * The per-message nonce (or information sufficient to reconstruct + * it) needs to be communicated with the ciphertext and must be unique. + * The recommended way to ensure uniqueness is to use a message + * counter. An alternative is to generate random nonces, but this + * limits the number of messages that can be securely encrypted: + * for example, with 96-bit random nonces, you should not encrypt + * more than 2**32 messages with the same key. + * + * Note that for both stategies, sizes are measured in blocks and + * that an AES block is 16 bytes. + * + * \warning Upon return, \p stream_block contains sensitive data. Its + * content must not be written to insecure storage and should be + * securely discarded as soon as it's no longer needed. + * + * \param ctx The AES context to use for encryption or decryption. + * It must be initialized and bound to a key. + * \param length The length of the input data. + * \param nc_off The offset in the current \p stream_block, for + * resuming within the current cipher stream. The + * offset pointer should be 0 at the start of a stream. + * It must point to a valid \c size_t. + * \param nonce_counter The 128-bit nonce and counter. + * It must be a readable-writeable buffer of \c 16 Bytes. + * \param stream_block The saved stream block for resuming. This is + * overwritten by the function. + * It must be a readable-writeable buffer of \c 16 Bytes. + * \param input The buffer holding the input data. + * It must be readable and of size \p length Bytes. + * \param output The buffer holding the output data. + * It must be writeable and of size \p length Bytes. + * + * \return \c 0 on success. + */ +int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +/** + * \brief Internal AES block encryption function. This is only + * exposed to allow overriding it using + * \c MBEDTLS_AES_ENCRYPT_ALT. + * + * \param ctx The AES context to use for encryption. + * \param input The plaintext block. + * \param output The output (ciphertext) block. + * + * \return \c 0 on success. + */ +int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief Internal AES block decryption function. This is only + * exposed to allow overriding it using see + * \c MBEDTLS_AES_DECRYPT_ALT. + * + * \param ctx The AES context to use for decryption. + * \param input The ciphertext block. + * \param output The output (plaintext) block. + * + * \return \c 0 on success. + */ +int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief Deprecated internal AES block encryption function + * without return value. + * + * \deprecated Superseded by mbedtls_internal_aes_encrypt() + * + * \param ctx The AES context to use for encryption. + * \param input Plaintext block. + * \param output Output (ciphertext) block. + */ +MBEDTLS_DEPRECATED void mbedtls_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief Deprecated internal AES block decryption function + * without return value. + * + * \deprecated Superseded by mbedtls_internal_aes_decrypt() + * + * \param ctx The AES context to use for decryption. + * \param input Ciphertext block. + * \param output Output (plaintext) block. + */ +MBEDTLS_DEPRECATED void mbedtls_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_aes_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* aes.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/aesni.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/aesni.h new file mode 100644 index 000000000..513401a6d --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/aesni.h @@ -0,0 +1,138 @@ +/** + * \file aesni.h + * + * \brief AES-NI for hardware AES acceleration on some Intel processors + * + * \warning These functions are only for internal use by other library + * functions; you must not call them directly. + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_AESNI_H +#define MBEDTLS_AESNI_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "aes.h" + +#define MBEDTLS_AESNI_AES 0x02000000u +#define MBEDTLS_AESNI_CLMUL 0x00000002u + +#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && \ + ( defined(__amd64__) || defined(__x86_64__) ) && \ + ! defined(MBEDTLS_HAVE_X86_64) +#define MBEDTLS_HAVE_X86_64 +#endif + +#if defined(MBEDTLS_HAVE_X86_64) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Internal function to detect the AES-NI feature in CPUs. + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. + * + * \param what The feature to detect + * (MBEDTLS_AESNI_AES or MBEDTLS_AESNI_CLMUL) + * + * \return 1 if CPU has support for the feature, 0 otherwise + */ +int mbedtls_aesni_has_support( unsigned int what ); + +/** + * \brief Internal AES-NI AES-ECB block encryption and decryption + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 on success (cannot fail) + */ +int mbedtls_aesni_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief Internal GCM multiplication: c = a * b in GF(2^128) + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. + * + * \param c Result + * \param a First operand + * \param b Second operand + * + * \note Both operands and result are bit strings interpreted as + * elements of GF(2^128) as per the GCM spec. + */ +void mbedtls_aesni_gcm_mult( unsigned char c[16], + const unsigned char a[16], + const unsigned char b[16] ); + +/** + * \brief Internal round key inversion. This function computes + * decryption round keys from the encryption round keys. + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. + * + * \param invkey Round keys for the equivalent inverse cipher + * \param fwdkey Original round keys (for encryption) + * \param nr Number of rounds (that is, number of round keys minus one) + */ +void mbedtls_aesni_inverse_key( unsigned char *invkey, + const unsigned char *fwdkey, + int nr ); + +/** + * \brief Internal key expansion for encryption + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. + * + * \param rk Destination buffer where the round keys are written + * \param key Encryption key + * \param bits Key size in bits (must be 128, 192 or 256) + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aesni_setkey_enc( unsigned char *rk, + const unsigned char *key, + size_t bits ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_HAVE_X86_64 */ + +#endif /* MBEDTLS_AESNI_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/arc4.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/arc4.h new file mode 100644 index 000000000..40ffc1c6c --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/arc4.h @@ -0,0 +1,146 @@ +/** + * \file arc4.h + * + * \brief The ARCFOUR stream cipher + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers instead. + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + * + */ +#ifndef MBEDTLS_ARC4_H +#define MBEDTLS_ARC4_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +/* MBEDTLS_ERR_ARC4_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_ARC4_HW_ACCEL_FAILED -0x0019 /**< ARC4 hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_ARC4_ALT) +// Regular implementation +// + +/** + * \brief ARC4 context structure + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers instead. + * + */ +typedef struct mbedtls_arc4_context +{ + int x; /*!< permutation index */ + int y; /*!< permutation index */ + unsigned char m[256]; /*!< permutation table */ +} +mbedtls_arc4_context; + +#else /* MBEDTLS_ARC4_ALT */ +#include "arc4_alt.h" +#endif /* MBEDTLS_ARC4_ALT */ + +/** + * \brief Initialize ARC4 context + * + * \param ctx ARC4 context to be initialized + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + * + */ +void mbedtls_arc4_init( mbedtls_arc4_context *ctx ); + +/** + * \brief Clear ARC4 context + * + * \param ctx ARC4 context to be cleared + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + * + */ +void mbedtls_arc4_free( mbedtls_arc4_context *ctx ); + +/** + * \brief ARC4 key schedule + * + * \param ctx ARC4 context to be setup + * \param key the secret key + * \param keylen length of the key, in bytes + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + * + */ +void mbedtls_arc4_setup( mbedtls_arc4_context *ctx, const unsigned char *key, + unsigned int keylen ); + +/** + * \brief ARC4 cipher function + * + * \param ctx ARC4 context + * \param length length of the input data + * \param input buffer holding the input data + * \param output buffer for the output data + * + * \return 0 if successful + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + * + */ +int mbedtls_arc4_crypt( mbedtls_arc4_context *ctx, size_t length, const unsigned char *input, + unsigned char *output ); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + * + */ +int mbedtls_arc4_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* arc4.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/aria.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/aria.h new file mode 100644 index 000000000..148889aeb --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/aria.h @@ -0,0 +1,370 @@ +/** + * \file aria.h + * + * \brief ARIA block cipher + * + * The ARIA algorithm is a symmetric block cipher that can encrypt and + * decrypt information. It is defined by the Korean Agency for + * Technology and Standards (KATS) in KS X 1213:2004 (in + * Korean, but see http://210.104.33.10/ARIA/index-e.html in English) + * and also described by the IETF in RFC 5794. + */ +/* Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_ARIA_H +#define MBEDTLS_ARIA_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#include "platform_util.h" + +#define MBEDTLS_ARIA_ENCRYPT 1 /**< ARIA encryption. */ +#define MBEDTLS_ARIA_DECRYPT 0 /**< ARIA decryption. */ + +#define MBEDTLS_ARIA_BLOCKSIZE 16 /**< ARIA block size in bytes. */ +#define MBEDTLS_ARIA_MAX_ROUNDS 16 /**< Maxiumum number of rounds in ARIA. */ +#define MBEDTLS_ARIA_MAX_KEYSIZE 32 /**< Maximum size of an ARIA key in bytes. */ + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#define MBEDTLS_ERR_ARIA_INVALID_KEY_LENGTH MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( -0x005C ) +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ +#define MBEDTLS_ERR_ARIA_BAD_INPUT_DATA -0x005C /**< Bad input data. */ + +#define MBEDTLS_ERR_ARIA_INVALID_INPUT_LENGTH -0x005E /**< Invalid data input length. */ + +/* MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE is deprecated and should not be used. + */ +#define MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE -0x005A /**< Feature not available. For example, an unsupported ARIA key size. */ + +/* MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED -0x0058 /**< ARIA hardware accelerator failed. */ + +#if !defined(MBEDTLS_ARIA_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief The ARIA context-type definition. + */ +typedef struct mbedtls_aria_context +{ + unsigned char nr; /*!< The number of rounds (12, 14 or 16) */ + /*! The ARIA round keys. */ + uint32_t rk[MBEDTLS_ARIA_MAX_ROUNDS + 1][MBEDTLS_ARIA_BLOCKSIZE / 4]; +} +mbedtls_aria_context; + +#else /* MBEDTLS_ARIA_ALT */ +#include "aria_alt.h" +#endif /* MBEDTLS_ARIA_ALT */ + +/** + * \brief This function initializes the specified ARIA context. + * + * It must be the first API called before using + * the context. + * + * \param ctx The ARIA context to initialize. This must not be \c NULL. + */ +void mbedtls_aria_init( mbedtls_aria_context *ctx ); + +/** + * \brief This function releases and clears the specified ARIA context. + * + * \param ctx The ARIA context to clear. This may be \c NULL, in which + * case this function returns immediately. If it is not \c NULL, + * it must point to an initialized ARIA context. + */ +void mbedtls_aria_free( mbedtls_aria_context *ctx ); + +/** + * \brief This function sets the encryption key. + * + * \param ctx The ARIA context to which the key should be bound. + * This must be initialized. + * \param key The encryption key. This must be a readable buffer + * of size \p keybits Bits. + * \param keybits The size of \p key in Bits. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_setkey_enc( mbedtls_aria_context *ctx, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief This function sets the decryption key. + * + * \param ctx The ARIA context to which the key should be bound. + * This must be initialized. + * \param key The decryption key. This must be a readable buffer + * of size \p keybits Bits. + * \param keybits The size of data passed. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_setkey_dec( mbedtls_aria_context *ctx, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief This function performs an ARIA single-block encryption or + * decryption operation. + * + * It performs encryption or decryption (depending on whether + * the key was set for encryption on decryption) on the input + * data buffer defined in the \p input parameter. + * + * mbedtls_aria_init(), and either mbedtls_aria_setkey_enc() or + * mbedtls_aria_setkey_dec() must be called before the first + * call to this API with the same context. + * + * \param ctx The ARIA context to use for encryption or decryption. + * This must be initialized and bound to a key. + * \param input The 16-Byte buffer holding the input data. + * \param output The 16-Byte buffer holding the output data. + + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_crypt_ecb( mbedtls_aria_context *ctx, + const unsigned char input[MBEDTLS_ARIA_BLOCKSIZE], + unsigned char output[MBEDTLS_ARIA_BLOCKSIZE] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief This function performs an ARIA-CBC encryption or decryption operation + * on full blocks. + * + * It performs the operation defined in the \p mode + * parameter (encrypt/decrypt), on the input data buffer defined in + * the \p input parameter. + * + * It can be called as many times as needed, until all the input + * data is processed. mbedtls_aria_init(), and either + * mbedtls_aria_setkey_enc() or mbedtls_aria_setkey_dec() must be called + * before the first call to this API with the same context. + * + * \note This function operates on aligned blocks, that is, the input size + * must be a multiple of the ARIA block size of 16 Bytes. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the IV, you should + * either save it manually or use the cipher module instead. + * + * + * \param ctx The ARIA context to use for encryption or decryption. + * This must be initialized and bound to a key. + * \param mode The mode of operation. This must be either + * #MBEDTLS_ARIA_ENCRYPT for encryption, or + * #MBEDTLS_ARIA_DECRYPT for decryption. + * \param length The length of the input data in Bytes. This must be a + * multiple of the block size (16 Bytes). + * \param iv Initialization vector (updated after use). + * This must be a readable buffer of size 16 Bytes. + * \param input The buffer holding the input data. This must + * be a readable buffer of length \p length Bytes. + * \param output The buffer holding the output data. This must + * be a writable buffer of length \p length Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_crypt_cbc( mbedtls_aria_context *ctx, + int mode, + size_t length, + unsigned char iv[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief This function performs an ARIA-CFB128 encryption or decryption + * operation. + * + * It performs the operation defined in the \p mode + * parameter (encrypt or decrypt), on the input data buffer + * defined in the \p input parameter. + * + * For CFB, you must set up the context with mbedtls_aria_setkey_enc(), + * regardless of whether you are performing an encryption or decryption + * operation, that is, regardless of the \p mode parameter. This is + * because CFB mode uses the same key schedule for encryption and + * decryption. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the + * IV, you must either save it manually or use the cipher + * module instead. + * + * + * \param ctx The ARIA context to use for encryption or decryption. + * This must be initialized and bound to a key. + * \param mode The mode of operation. This must be either + * #MBEDTLS_ARIA_ENCRYPT for encryption, or + * #MBEDTLS_ARIA_DECRYPT for decryption. + * \param length The length of the input data \p input in Bytes. + * \param iv_off The offset in IV (updated after use). + * This must not be larger than 15. + * \param iv The initialization vector (updated after use). + * This must be a readable buffer of size 16 Bytes. + * \param input The buffer holding the input data. This must + * be a readable buffer of length \p length Bytes. + * \param output The buffer holding the output data. This must + * be a writable buffer of length \p length Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_crypt_cfb128( mbedtls_aria_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief This function performs an ARIA-CTR encryption or decryption + * operation. + * + * This function performs the operation defined in the \p mode + * parameter (encrypt/decrypt), on the input data buffer + * defined in the \p input parameter. + * + * Due to the nature of CTR, you must use the same key schedule + * for both encryption and decryption operations. Therefore, you + * must use the context initialized with mbedtls_aria_setkey_enc() + * for both #MBEDTLS_ARIA_ENCRYPT and #MBEDTLS_ARIA_DECRYPT. + * + * \warning You must never reuse a nonce value with the same key. Doing so + * would void the encryption for the two messages encrypted with + * the same nonce and key. + * + * There are two common strategies for managing nonces with CTR: + * + * 1. You can handle everything as a single message processed over + * successive calls to this function. In that case, you want to + * set \p nonce_counter and \p nc_off to 0 for the first call, and + * then preserve the values of \p nonce_counter, \p nc_off and \p + * stream_block across calls to this function as they will be + * updated by this function. + * + * With this strategy, you must not encrypt more than 2**128 + * blocks of data with the same key. + * + * 2. You can encrypt separate messages by dividing the \p + * nonce_counter buffer in two areas: the first one used for a + * per-message nonce, handled by yourself, and the second one + * updated by this function internally. + * + * For example, you might reserve the first 12 bytes for the + * per-message nonce, and the last 4 bytes for internal use. In that + * case, before calling this function on a new message you need to + * set the first 12 bytes of \p nonce_counter to your chosen nonce + * value, the last 4 to 0, and \p nc_off to 0 (which will cause \p + * stream_block to be ignored). That way, you can encrypt at most + * 2**96 messages of up to 2**32 blocks each with the same key. + * + * The per-message nonce (or information sufficient to reconstruct + * it) needs to be communicated with the ciphertext and must be unique. + * The recommended way to ensure uniqueness is to use a message + * counter. An alternative is to generate random nonces, but this + * limits the number of messages that can be securely encrypted: + * for example, with 96-bit random nonces, you should not encrypt + * more than 2**32 messages with the same key. + * + * Note that for both stategies, sizes are measured in blocks and + * that an ARIA block is 16 bytes. + * + * \warning Upon return, \p stream_block contains sensitive data. Its + * content must not be written to insecure storage and should be + * securely discarded as soon as it's no longer needed. + * + * \param ctx The ARIA context to use for encryption or decryption. + * This must be initialized and bound to a key. + * \param length The length of the input data \p input in Bytes. + * \param nc_off The offset in Bytes in the current \p stream_block, + * for resuming within the current cipher stream. The + * offset pointer should be \c 0 at the start of a + * stream. This must not be larger than \c 15 Bytes. + * \param nonce_counter The 128-bit nonce and counter. This must point to + * a read/write buffer of length \c 16 bytes. + * \param stream_block The saved stream block for resuming. This must + * point to a read/write buffer of length \c 16 bytes. + * This is overwritten by the function. + * \param input The buffer holding the input data. This must + * be a readable buffer of length \p length Bytes. + * \param output The buffer holding the output data. This must + * be a writable buffer of length \p length Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_aria_crypt_ctr( mbedtls_aria_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[MBEDTLS_ARIA_BLOCKSIZE], + unsigned char stream_block[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine. + * + * \return \c 0 on success, or \c 1 on failure. + */ +int mbedtls_aria_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* aria.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/asn1.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/asn1.h new file mode 100644 index 000000000..42a2050c1 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/asn1.h @@ -0,0 +1,358 @@ +/** + * \file asn1.h + * + * \brief Generic ASN.1 parsing + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ASN1_H +#define MBEDTLS_ASN1_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_BIGNUM_C) +#include "bignum.h" +#endif + +/** + * \addtogroup asn1_module + * \{ + */ + +/** + * \name ASN1 Error codes + * These error codes are OR'ed to X509 error codes for + * higher error granularity. + * ASN1 is a standard to specify data structures. + * \{ + */ +#define MBEDTLS_ERR_ASN1_OUT_OF_DATA -0x0060 /**< Out of data when parsing an ASN1 data structure. */ +#define MBEDTLS_ERR_ASN1_UNEXPECTED_TAG -0x0062 /**< ASN1 tag was of an unexpected value. */ +#define MBEDTLS_ERR_ASN1_INVALID_LENGTH -0x0064 /**< Error when trying to determine the length or invalid length. */ +#define MBEDTLS_ERR_ASN1_LENGTH_MISMATCH -0x0066 /**< Actual length differs from expected length. */ +#define MBEDTLS_ERR_ASN1_INVALID_DATA -0x0068 /**< Data is invalid. (not used) */ +#define MBEDTLS_ERR_ASN1_ALLOC_FAILED -0x006A /**< Memory allocation failed */ +#define MBEDTLS_ERR_ASN1_BUF_TOO_SMALL -0x006C /**< Buffer too small when writing ASN.1 data structure. */ + +/* \} name */ + +/** + * \name DER constants + * These constants comply with the DER encoded ASN.1 type tags. + * DER encoding uses hexadecimal representation. + * An example DER sequence is:\n + * - 0x02 -- tag indicating INTEGER + * - 0x01 -- length in octets + * - 0x05 -- value + * Such sequences are typically read into \c ::mbedtls_x509_buf. + * \{ + */ +#define MBEDTLS_ASN1_BOOLEAN 0x01 +#define MBEDTLS_ASN1_INTEGER 0x02 +#define MBEDTLS_ASN1_BIT_STRING 0x03 +#define MBEDTLS_ASN1_OCTET_STRING 0x04 +#define MBEDTLS_ASN1_NULL 0x05 +#define MBEDTLS_ASN1_OID 0x06 +#define MBEDTLS_ASN1_UTF8_STRING 0x0C +#define MBEDTLS_ASN1_SEQUENCE 0x10 +#define MBEDTLS_ASN1_SET 0x11 +#define MBEDTLS_ASN1_PRINTABLE_STRING 0x13 +#define MBEDTLS_ASN1_T61_STRING 0x14 +#define MBEDTLS_ASN1_IA5_STRING 0x16 +#define MBEDTLS_ASN1_UTC_TIME 0x17 +#define MBEDTLS_ASN1_GENERALIZED_TIME 0x18 +#define MBEDTLS_ASN1_UNIVERSAL_STRING 0x1C +#define MBEDTLS_ASN1_BMP_STRING 0x1E +#define MBEDTLS_ASN1_PRIMITIVE 0x00 +#define MBEDTLS_ASN1_CONSTRUCTED 0x20 +#define MBEDTLS_ASN1_CONTEXT_SPECIFIC 0x80 + +/* + * Bit masks for each of the components of an ASN.1 tag as specified in + * ITU X.690 (08/2015), section 8.1 "General rules for encoding", + * paragraph 8.1.2.2: + * + * Bit 8 7 6 5 1 + * +-------+-----+------------+ + * | Class | P/C | Tag number | + * +-------+-----+------------+ + */ +#define MBEDTLS_ASN1_TAG_CLASS_MASK 0xC0 +#define MBEDTLS_ASN1_TAG_PC_MASK 0x20 +#define MBEDTLS_ASN1_TAG_VALUE_MASK 0x1F + +/* \} name */ +/* \} addtogroup asn1_module */ + +/** Returns the size of the binary string, without the trailing \\0 */ +#define MBEDTLS_OID_SIZE(x) (sizeof(x) - 1) + +/** + * Compares an mbedtls_asn1_buf structure to a reference OID. + * + * Only works for 'defined' oid_str values (MBEDTLS_OID_HMAC_SHA1), you cannot use a + * 'unsigned char *oid' here! + */ +#define MBEDTLS_OID_CMP(oid_str, oid_buf) \ + ( ( MBEDTLS_OID_SIZE(oid_str) != (oid_buf)->len ) || \ + memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) != 0 ) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Functions to parse ASN.1 data structures + * \{ + */ + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef struct mbedtls_asn1_buf +{ + int tag; /**< ASN1 type, e.g. MBEDTLS_ASN1_UTF8_STRING. */ + size_t len; /**< ASN1 length, in octets. */ + unsigned char *p; /**< ASN1 data, e.g. in ASCII. */ +} +mbedtls_asn1_buf; + +/** + * Container for ASN1 bit strings. + */ +typedef struct mbedtls_asn1_bitstring +{ + size_t len; /**< ASN1 length, in octets. */ + unsigned char unused_bits; /**< Number of unused bits at the end of the string */ + unsigned char *p; /**< Raw ASN1 data for the bit string */ +} +mbedtls_asn1_bitstring; + +/** + * Container for a sequence of ASN.1 items + */ +typedef struct mbedtls_asn1_sequence +{ + mbedtls_asn1_buf buf; /**< Buffer containing the given ASN.1 item. */ + struct mbedtls_asn1_sequence *next; /**< The next entry in the sequence. */ +} +mbedtls_asn1_sequence; + +/** + * Container for a sequence or list of 'named' ASN.1 data items + */ +typedef struct mbedtls_asn1_named_data +{ + mbedtls_asn1_buf oid; /**< The object identifier. */ + mbedtls_asn1_buf val; /**< The named value. */ + struct mbedtls_asn1_named_data *next; /**< The next entry in the sequence. */ + unsigned char next_merged; /**< Merge next item into the current one? */ +} +mbedtls_asn1_named_data; + +/** + * \brief Get the length of an ASN.1 element. + * Updates the pointer to immediately behind the length. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len The variable that will receive the value + * + * \return 0 if successful, MBEDTLS_ERR_ASN1_OUT_OF_DATA on reaching + * end of data, MBEDTLS_ERR_ASN1_INVALID_LENGTH if length is + * unparseable. + */ +int mbedtls_asn1_get_len( unsigned char **p, + const unsigned char *end, + size_t *len ); + +/** + * \brief Get the tag and length of the tag. Check for the requested tag. + * Updates the pointer to immediately behind the tag and length. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len The variable that will receive the length + * \param tag The expected tag + * + * \return 0 if successful, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG if tag did + * not match requested tag, or another specific ASN.1 error code. + */ +int mbedtls_asn1_get_tag( unsigned char **p, + const unsigned char *end, + size_t *len, int tag ); + +/** + * \brief Retrieve a boolean ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param val The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_bool( unsigned char **p, + const unsigned char *end, + int *val ); + +/** + * \brief Retrieve an integer ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param val The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_int( unsigned char **p, + const unsigned char *end, + int *val ); + +/** + * \brief Retrieve a bitstring ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param bs The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end, + mbedtls_asn1_bitstring *bs); + +/** + * \brief Retrieve a bitstring ASN.1 tag without unused bits and its + * value. + * Updates the pointer to the beginning of the bit/octet string. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len Length of the actual bit/octect string in bytes + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end, + size_t *len ); + +/** + * \brief Parses and splits an ASN.1 "SEQUENCE OF " + * Updated the pointer to immediately behind the full sequence tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param cur First variable in the chain to fill + * \param tag Type of sequence + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_sequence_of( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_sequence *cur, + int tag); + +#if defined(MBEDTLS_BIGNUM_C) +/** + * \brief Retrieve a MPI value from an integer ASN.1 tag. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param X The MPI that will receive the value + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int mbedtls_asn1_get_mpi( unsigned char **p, + const unsigned char *end, + mbedtls_mpi *X ); +#endif /* MBEDTLS_BIGNUM_C */ + +/** + * \brief Retrieve an AlgorithmIdentifier ASN.1 sequence. + * Updates the pointer to immediately behind the full + * AlgorithmIdentifier. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param alg The buffer to receive the OID + * \param params The buffer to receive the params (if any) + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int mbedtls_asn1_get_alg( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params ); + +/** + * \brief Retrieve an AlgorithmIdentifier ASN.1 sequence with NULL or no + * params. + * Updates the pointer to immediately behind the full + * AlgorithmIdentifier. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param alg The buffer to receive the OID + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int mbedtls_asn1_get_alg_null( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg ); + +/** + * \brief Find a specific named_data entry in a sequence or list based on + * the OID. + * + * \param list The list to seek through + * \param oid The OID to look for + * \param len Size of the OID + * + * \return NULL if not found, or a pointer to the existing entry. + */ +mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list, + const char *oid, size_t len ); + +/** + * \brief Free a mbedtls_asn1_named_data entry + * + * \param entry The named data entry to free + */ +void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *entry ); + +/** + * \brief Free all entries in a mbedtls_asn1_named_data list + * Head will be set to NULL + * + * \param head Pointer to the head of the list of named data entries to free + */ +void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head ); + +#ifdef __cplusplus +} +#endif + +#endif /* asn1.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/asn1write.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/asn1write.h new file mode 100644 index 000000000..b9e93a5bf --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/asn1write.h @@ -0,0 +1,351 @@ +/** + * \file asn1write.h + * + * \brief ASN.1 buffer writing functionality + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ASN1_WRITE_H +#define MBEDTLS_ASN1_WRITE_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "asn1.h" + +#define MBEDTLS_ASN1_CHK_ADD(g, f) \ + do \ + { \ + if( ( ret = (f) ) < 0 ) \ + return( ret ); \ + else \ + (g) += ret; \ + } while( 0 ) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Write a length field in ASN.1 format. + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param len The length value to write. + * + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, + size_t len ); +/** + * \brief Write an ASN.1 tag in ASN.1 format. + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param tag The tag to write. + * + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, + unsigned char tag ); + +/** + * \brief Write raw buffer data. + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param buf The data buffer to write. + * \param size The length of the data buffer. + * + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ); + +#if defined(MBEDTLS_BIGNUM_C) +/** + * \brief Write a arbitrary-precision number (#MBEDTLS_ASN1_INTEGER) + * in ASN.1 format. + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param X The MPI to write. + * + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, + const mbedtls_mpi *X ); +#endif /* MBEDTLS_BIGNUM_C */ + +/** + * \brief Write a NULL tag (#MBEDTLS_ASN1_NULL) with zero data + * in ASN.1 format. + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start ); + +/** + * \brief Write an OID tag (#MBEDTLS_ASN1_OID) and data + * in ASN.1 format. + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param oid The OID to write. + * \param oid_len The length of the OID. + * + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len ); + +/** + * \brief Write an AlgorithmIdentifier sequence in ASN.1 format. + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param oid The OID of the algorithm to write. + * \param oid_len The length of the algorithm's OID. + * \param par_len The length of the parameters, which must be already written. + * If 0, NULL parameters are added + * + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, + unsigned char *start, + const char *oid, size_t oid_len, + size_t par_len ); + +/** + * \brief Write a boolean tag (#MBEDTLS_ASN1_BOOLEAN) and value + * in ASN.1 format. + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param boolean The boolean value to write, either \c 0 or \c 1. + * + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, + int boolean ); + +/** + * \brief Write an int tag (#MBEDTLS_ASN1_INTEGER) and value + * in ASN.1 format. + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param val The integer value to write. + * + * \return The number of bytes written to \p p on success. + * \return A negative \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val ); + +/** + * \brief Write a string in ASN.1 format using a specific + * string encoding tag. + + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param tag The string encoding tag to write, e.g. + * #MBEDTLS_ASN1_UTF8_STRING. + * \param text The string to write. + * \param text_len The length of \p text in bytes (which might + * be strictly larger than the number of characters). + * + * \return The number of bytes written to \p p on success. + * \return A negative error code on failure. + */ +int mbedtls_asn1_write_tagged_string( unsigned char **p, unsigned char *start, + int tag, const char *text, + size_t text_len ); + +/** + * \brief Write a string in ASN.1 format using the PrintableString + * string encoding tag (#MBEDTLS_ASN1_PRINTABLE_STRING). + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param text The string to write. + * \param text_len The length of \p text in bytes (which might + * be strictly larger than the number of characters). + * + * \return The number of bytes written to \p p on success. + * \return A negative error code on failure. + */ +int mbedtls_asn1_write_printable_string( unsigned char **p, + unsigned char *start, + const char *text, size_t text_len ); + +/** + * \brief Write a UTF8 string in ASN.1 format using the UTF8String + * string encoding tag (#MBEDTLS_ASN1_PRINTABLE_STRING). + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param text The string to write. + * \param text_len The length of \p text in bytes (which might + * be strictly larger than the number of characters). + * + * \return The number of bytes written to \p p on success. + * \return A negative error code on failure. + */ +int mbedtls_asn1_write_utf8_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ); + +/** + * \brief Write a string in ASN.1 format using the IA5String + * string encoding tag (#MBEDTLS_ASN1_IA5_STRING). + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param text The string to write. + * \param text_len The length of \p text in bytes (which might + * be strictly larger than the number of characters). + * + * \return The number of bytes written to \p p on success. + * \return A negative error code on failure. + */ +int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ); + +/** + * \brief Write a bitstring tag (#MBEDTLS_ASN1_BIT_STRING) and + * value in ASN.1 format. + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param buf The bitstring to write. + * \param bits The total number of bits in the bitstring. + * + * \return The number of bytes written to \p p on success. + * \return A negative error code on failure. + */ +int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t bits ); + +/** + * \brief This function writes a named bitstring tag + * (#MBEDTLS_ASN1_BIT_STRING) and value in ASN.1 format. + * + * As stated in RFC 5280 Appendix B, trailing zeroes are + * omitted when encoding named bitstrings in DER. + * + * \note This function works backwards within the data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer which is used for bounds-checking. + * \param buf The bitstring to write. + * \param bits The total number of bits in the bitstring. + * + * \return The number of bytes written to \p p on success. + * \return A negative error code on failure. + */ +int mbedtls_asn1_write_named_bitstring( unsigned char **p, + unsigned char *start, + const unsigned char *buf, + size_t bits ); + +/** + * \brief Write an octet string tag (#MBEDTLS_ASN1_OCTET_STRING) + * and value in ASN.1 format. + * + * \note This function works backwards in data buffer. + * + * \param p The reference to the current position pointer. + * \param start The start of the buffer, for bounds-checking. + * \param buf The buffer holding the data to write. + * \param size The length of the data buffer \p buf. + * + * \return The number of bytes written to \p p on success. + * \return A negative error code on failure. + */ +int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ); + +/** + * \brief Create or find a specific named_data entry for writing in a + * sequence or list based on the OID. If not already in there, + * a new entry is added to the head of the list. + * Warning: Destructive behaviour for the val data! + * + * \param list The pointer to the location of the head of the list to seek + * through (will be updated in case of a new entry). + * \param oid The OID to look for. + * \param oid_len The size of the OID. + * \param val The data to store (can be \c NULL if you want to fill + * it by hand). + * \param val_len The minimum length of the data buffer needed. + * + * \return A pointer to the new / existing entry on success. + * \return \c NULL if if there was a memory allocation error. + */ +mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data **list, + const char *oid, size_t oid_len, + const unsigned char *val, + size_t val_len ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_ASN1_WRITE_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/base64.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/base64.h new file mode 100644 index 000000000..ed23538bf --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/base64.h @@ -0,0 +1,98 @@ +/** + * \file base64.h + * + * \brief RFC 1521 base64 encoding/decoding + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_BASE64_H +#define MBEDTLS_BASE64_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#define MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL -0x002A /**< Output buffer too small. */ +#define MBEDTLS_ERR_BASE64_INVALID_CHARACTER -0x002C /**< Invalid character in input. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encode a buffer into base64 format + * + * \param dst destination buffer + * \param dlen size of the destination buffer + * \param olen number of bytes written + * \param src source buffer + * \param slen amount of data to be encoded + * + * \return 0 if successful, or MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL. + * *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * If that length cannot be represented, then no data is + * written to the buffer and *olen is set to the maximum + * length representable as a size_t. + * + * \note Call this function with dlen = 0 to obtain the + * required buffer size in *olen + */ +int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ); + +/** + * \brief Decode a base64-formatted buffer + * + * \param dst destination buffer (can be NULL for checking size) + * \param dlen size of the destination buffer + * \param olen number of bytes written + * \param src source buffer + * \param slen amount of data to be decoded + * + * \return 0 if successful, MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL, or + * MBEDTLS_ERR_BASE64_INVALID_CHARACTER if the input data is + * not correct. *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *dst = NULL or dlen = 0 to obtain + * the required buffer size in *olen + */ +int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_base64_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* base64.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/bignum.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/bignum.h new file mode 100644 index 000000000..7ec6e62e8 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/bignum.h @@ -0,0 +1,1000 @@ +/** + * \file bignum.h + * + * \brief Multi-precision integer library + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_BIGNUM_H +#define MBEDTLS_BIGNUM_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#define MBEDTLS_ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */ +#define MBEDTLS_ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */ +#define MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The buffer is too small to write to. */ +#define MBEDTLS_ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */ +#define MBEDTLS_ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */ +#define MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */ +#define MBEDTLS_ERR_MPI_ALLOC_FAILED -0x0010 /**< Memory allocation failed. */ + +#define MBEDTLS_MPI_CHK(f) \ + do \ + { \ + if( ( ret = (f) ) != 0 ) \ + goto cleanup; \ + } while( 0 ) + +/* + * Maximum size MPIs are allowed to grow to in number of limbs. + */ +#define MBEDTLS_MPI_MAX_LIMBS 10000 + +#if !defined(MBEDTLS_MPI_WINDOW_SIZE) +/* + * Maximum window size used for modular exponentiation. Default: 6 + * Minimum value: 1. Maximum value: 6. + * + * Result is an array of ( 2 << MBEDTLS_MPI_WINDOW_SIZE ) MPIs used + * for the sliding window calculation. (So 64 by default) + * + * Reduction in size, reduces speed. + */ +#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +#endif /* !MBEDTLS_MPI_WINDOW_SIZE */ + +#if !defined(MBEDTLS_MPI_MAX_SIZE) +/* + * Maximum size of MPIs allowed in bits and bytes for user-MPIs. + * ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits ) + * + * Note: Calculations can temporarily result in larger MPIs. So the number + * of limbs required (MBEDTLS_MPI_MAX_LIMBS) is higher. + */ +#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ +#endif /* !MBEDTLS_MPI_MAX_SIZE */ + +#define MBEDTLS_MPI_MAX_BITS ( 8 * MBEDTLS_MPI_MAX_SIZE ) /**< Maximum number of bits for usable MPIs. */ + +/* + * When reading from files with mbedtls_mpi_read_file() and writing to files with + * mbedtls_mpi_write_file() the buffer should have space + * for a (short) label, the MPI (in the provided radix), the newline + * characters and the '\0'. + * + * By default we assume at least a 10 char label, a minimum radix of 10 + * (decimal) and a maximum of 4096 bit numbers (1234 decimal chars). + * Autosized at compile time for at least a 10 char label, a minimum radix + * of 10 (decimal) for a number of MBEDTLS_MPI_MAX_BITS size. + * + * This used to be statically sized to 1250 for a maximum of 4096 bit + * numbers (1234 decimal chars). + * + * Calculate using the formula: + * MBEDTLS_MPI_RW_BUFFER_SIZE = ceil(MBEDTLS_MPI_MAX_BITS / ln(10) * ln(2)) + + * LabelSize + 6 + */ +#define MBEDTLS_MPI_MAX_BITS_SCALE100 ( 100 * MBEDTLS_MPI_MAX_BITS ) +#define MBEDTLS_LN_2_DIV_LN_10_SCALE100 332 +#define MBEDTLS_MPI_RW_BUFFER_SIZE ( ((MBEDTLS_MPI_MAX_BITS_SCALE100 + MBEDTLS_LN_2_DIV_LN_10_SCALE100 - 1) / MBEDTLS_LN_2_DIV_LN_10_SCALE100) + 10 + 6 ) + +/* + * Define the base integer type, architecture-wise. + * + * 32 or 64-bit integer types can be forced regardless of the underlying + * architecture by defining MBEDTLS_HAVE_INT32 or MBEDTLS_HAVE_INT64 + * respectively and undefining MBEDTLS_HAVE_ASM. + * + * Double-width integers (e.g. 128-bit in 64-bit architectures) can be + * disabled by defining MBEDTLS_NO_UDBL_DIVISION. + */ +#if !defined(MBEDTLS_HAVE_INT32) + #if defined(_MSC_VER) && defined(_M_AMD64) + /* Always choose 64-bit when using MSC */ + #if !defined(MBEDTLS_HAVE_INT64) + #define MBEDTLS_HAVE_INT64 + #endif /* !MBEDTLS_HAVE_INT64 */ + typedef int64_t mbedtls_mpi_sint; + typedef uint64_t mbedtls_mpi_uint; + #elif defined(__GNUC__) && ( \ + defined(__amd64__) || defined(__x86_64__) || \ + defined(__ppc64__) || defined(__powerpc64__) || \ + defined(__ia64__) || defined(__alpha__) || \ + ( defined(__sparc__) && defined(__arch64__) ) || \ + defined(__s390x__) || defined(__mips64) ) + #if !defined(MBEDTLS_HAVE_INT64) + #define MBEDTLS_HAVE_INT64 + #endif /* MBEDTLS_HAVE_INT64 */ + typedef int64_t mbedtls_mpi_sint; + typedef uint64_t mbedtls_mpi_uint; + #if !defined(MBEDTLS_NO_UDBL_DIVISION) + /* mbedtls_t_udbl defined as 128-bit unsigned int */ + typedef unsigned int mbedtls_t_udbl __attribute__((mode(TI))); + #define MBEDTLS_HAVE_UDBL + #endif /* !MBEDTLS_NO_UDBL_DIVISION */ + #elif defined(__ARMCC_VERSION) && defined(__aarch64__) + /* + * __ARMCC_VERSION is defined for both armcc and armclang and + * __aarch64__ is only defined by armclang when compiling 64-bit code + */ + #if !defined(MBEDTLS_HAVE_INT64) + #define MBEDTLS_HAVE_INT64 + #endif /* !MBEDTLS_HAVE_INT64 */ + typedef int64_t mbedtls_mpi_sint; + typedef uint64_t mbedtls_mpi_uint; + #if !defined(MBEDTLS_NO_UDBL_DIVISION) + /* mbedtls_t_udbl defined as 128-bit unsigned int */ + typedef __uint128_t mbedtls_t_udbl; + #define MBEDTLS_HAVE_UDBL + #endif /* !MBEDTLS_NO_UDBL_DIVISION */ + #elif defined(MBEDTLS_HAVE_INT64) + /* Force 64-bit integers with unknown compiler */ + typedef int64_t mbedtls_mpi_sint; + typedef uint64_t mbedtls_mpi_uint; + #endif +#endif /* !MBEDTLS_HAVE_INT32 */ + +#if !defined(MBEDTLS_HAVE_INT64) + /* Default to 32-bit compilation */ + #if !defined(MBEDTLS_HAVE_INT32) + #define MBEDTLS_HAVE_INT32 + #endif /* !MBEDTLS_HAVE_INT32 */ + typedef int32_t mbedtls_mpi_sint; + typedef uint32_t mbedtls_mpi_uint; + #if !defined(MBEDTLS_NO_UDBL_DIVISION) + typedef uint64_t mbedtls_t_udbl; + #define MBEDTLS_HAVE_UDBL + #endif /* !MBEDTLS_NO_UDBL_DIVISION */ +#endif /* !MBEDTLS_HAVE_INT64 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MPI structure + */ +typedef struct mbedtls_mpi +{ + int s; /*!< integer sign */ + size_t n; /*!< total # of limbs */ + mbedtls_mpi_uint *p; /*!< pointer to limbs */ +} +mbedtls_mpi; + +/** + * \brief Initialize an MPI context. + * + * This makes the MPI ready to be set or freed, + * but does not define a value for the MPI. + * + * \param X The MPI context to initialize. This must not be \c NULL. + */ +void mbedtls_mpi_init( mbedtls_mpi *X ); + +/** + * \brief This function frees the components of an MPI context. + * + * \param X The MPI context to be cleared. This may be \c NULL, + * in which case this function is a no-op. If it is + * not \c NULL, it must point to an initialized MPI. + */ +void mbedtls_mpi_free( mbedtls_mpi *X ); + +/** + * \brief Enlarge an MPI to the specified number of limbs. + * + * \note This function does nothing if the MPI is + * already large enough. + * + * \param X The MPI to grow. It must be initialized. + * \param nblimbs The target number of limbs. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs ); + +/** + * \brief This function resizes an MPI downwards, keeping at least the + * specified number of limbs. + * + * If \c X is smaller than \c nblimbs, it is resized up + * instead. + * + * \param X The MPI to shrink. This must point to an initialized MPI. + * \param nblimbs The minimum number of limbs to keep. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * (this can only happen when resizing up). + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ); + +/** + * \brief Make a copy of an MPI. + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param Y The source MPI. This must point to an initialized MPI. + * + * \note The limb-buffer in the destination MPI is enlarged + * if necessary to hold the value in the source MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Swap the contents of two MPIs. + * + * \param X The first MPI. It must be initialized. + * \param Y The second MPI. It must be initialized. + */ +void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ); + +/** + * \brief Perform a safe conditional copy of MPI which doesn't + * reveal whether the condition was true or not. + * + * \param X The MPI to conditionally assign to. This must point + * to an initialized MPI. + * \param Y The MPI to be assigned from. This must point to an + * initialized MPI. + * \param assign The condition deciding whether to perform the + * assignment or not. Possible values: + * * \c 1: Perform the assignment `X = Y`. + * * \c 0: Keep the original value of \p X. + * + * \note This function is equivalent to + * `if( assign ) mbedtls_mpi_copy( X, Y );` + * except that it avoids leaking any information about whether + * the assignment was done or not (the above code may leak + * information through branch prediction and/or memory access + * patterns analysis). + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ); + +/** + * \brief Perform a safe conditional swap which doesn't + * reveal whether the condition was true or not. + * + * \param X The first MPI. This must be initialized. + * \param Y The second MPI. This must be initialized. + * \param assign The condition deciding whether to perform + * the swap or not. Possible values: + * * \c 1: Swap the values of \p X and \p Y. + * * \c 0: Keep the original values of \p X and \p Y. + * + * \note This function is equivalent to + * if( assign ) mbedtls_mpi_swap( X, Y ); + * except that it avoids leaking any information about whether + * the assignment was done or not (the above code may leak + * information through branch prediction and/or memory access + * patterns analysis). + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. + * + */ +int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char assign ); + +/** + * \brief Store integer value in MPI. + * + * \param X The MPI to set. This must be initialized. + * \param z The value to use. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ); + +/** + * \brief Get a specific bit from an MPI. + * + * \param X The MPI to query. This must be initialized. + * \param pos Zero-based index of the bit to query. + * + * \return \c 0 or \c 1 on success, depending on whether bit \c pos + * of \c X is unset or set. + * \return A negative error code on failure. + */ +int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos ); + +/** + * \brief Modify a specific bit in an MPI. + * + * \note This function will grow the target MPI if necessary to set a + * bit to \c 1 in a not yet existing limb. It will not grow if + * the bit should be set to \c 0. + * + * \param X The MPI to modify. This must be initialized. + * \param pos Zero-based index of the bit to modify. + * \param val The desired value of bit \c pos: \c 0 or \c 1. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val ); + +/** + * \brief Return the number of bits of value \c 0 before the + * least significant bit of value \c 1. + * + * \note This is the same as the zero-based index of + * the least significant bit of value \c 1. + * + * \param X The MPI to query. + * + * \return The number of bits of value \c 0 before the least significant + * bit of value \c 1 in \p X. + */ +size_t mbedtls_mpi_lsb( const mbedtls_mpi *X ); + +/** + * \brief Return the number of bits up to and including the most + * significant bit of value \c 1. + * + * * \note This is same as the one-based index of the most + * significant bit of value \c 1. + * + * \param X The MPI to query. This must point to an initialized MPI. + * + * \return The number of bits up to and including the most + * significant bit of value \c 1. + */ +size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X ); + +/** + * \brief Return the total size of an MPI value in bytes. + * + * \param X The MPI to use. This must point to an initialized MPI. + * + * \note The value returned by this function may be less than + * the number of bytes used to store \p X internally. + * This happens if and only if there are trailing bytes + * of value zero. + * + * \return The least number of bytes capable of storing + * the absolute value of \p X. + */ +size_t mbedtls_mpi_size( const mbedtls_mpi *X ); + +/** + * \brief Import an MPI from an ASCII string. + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param radix The numeric base of the input string. + * \param s Null-terminated string buffer. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s ); + +/** + * \brief Export an MPI to an ASCII string. + * + * \param X The source MPI. This must point to an initialized MPI. + * \param radix The numeric base of the output string. + * \param buf The buffer to write the string to. This must be writable + * buffer of length \p buflen Bytes. + * \param buflen The available size in Bytes of \p buf. + * \param olen The address at which to store the length of the string + * written, including the final \c NULL byte. This must + * not be \c NULL. + * + * \note You can call this function with `buflen == 0` to obtain the + * minimum required buffer size in `*olen`. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if the target buffer \p buf + * is too small to hold the value of \p X in the desired base. + * In this case, `*olen` is nonetheless updated to contain the + * size of \p buf required for a successful call. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix, + char *buf, size_t buflen, size_t *olen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Read an MPI from a line in an opened file. + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param radix The numeric base of the string representation used + * in the source line. + * \param fin The input file handle to use. This must not be \c NULL. + * + * \note On success, this function advances the file stream + * to the end of the current line or to EOF. + * + * The function returns \c 0 on an empty line. + * + * Leading whitespaces are ignored, as is a + * '0x' prefix for radix \c 16. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if the file read buffer + * is too small. + * \return Another negative error code on failure. + */ +int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin ); + +/** + * \brief Export an MPI into an opened file. + * + * \param p A string prefix to emit prior to the MPI data. + * For example, this might be a label, or "0x" when + * printing in base \c 16. This may be \c NULL if no prefix + * is needed. + * \param X The source MPI. This must point to an initialized MPI. + * \param radix The numeric base to be used in the emitted string. + * \param fout The output file handle. This may be \c NULL, in which case + * the output is written to \c stdout. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, + int radix, FILE *fout ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Import an MPI from unsigned big endian binary data. + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param buf The input buffer. This must be a readable buffer of length + * \p buflen Bytes. + * \param buflen The length of the input buffer \p p in Bytes. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, + size_t buflen ); + +/** + * \brief Import X from unsigned binary data, little endian + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param buf The input buffer. This must be a readable buffer of length + * \p buflen Bytes. + * \param buflen The length of the input buffer \p p in Bytes. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_read_binary_le( mbedtls_mpi *X, + const unsigned char *buf, size_t buflen ); + +/** + * \brief Export X into unsigned binary data, big endian. + * Always fills the whole buffer, which will start with zeros + * if the number is smaller. + * + * \param X The source MPI. This must point to an initialized MPI. + * \param buf The output buffer. This must be a writable buffer of length + * \p buflen Bytes. + * \param buflen The size of the output buffer \p buf in Bytes. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p buf isn't + * large enough to hold the value of \p X. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, + size_t buflen ); + +/** + * \brief Export X into unsigned binary data, little endian. + * Always fills the whole buffer, which will end with zeros + * if the number is smaller. + * + * \param X The source MPI. This must point to an initialized MPI. + * \param buf The output buffer. This must be a writable buffer of length + * \p buflen Bytes. + * \param buflen The size of the output buffer \p buf in Bytes. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if \p buf isn't + * large enough to hold the value of \p X. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_write_binary_le( const mbedtls_mpi *X, + unsigned char *buf, size_t buflen ); + +/** + * \brief Perform a left-shift on an MPI: X <<= count + * + * \param X The MPI to shift. This must point to an initialized MPI. + * \param count The number of bits to shift by. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count ); + +/** + * \brief Perform a right-shift on an MPI: X >>= count + * + * \param X The MPI to shift. This must point to an initialized MPI. + * \param count The number of bits to shift by. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count ); + +/** + * \brief Compare the absolute values of two MPIs. + * + * \param X The left-hand MPI. This must point to an initialized MPI. + * \param Y The right-hand MPI. This must point to an initialized MPI. + * + * \return \c 1 if `|X|` is greater than `|Y|`. + * \return \c -1 if `|X|` is lesser than `|Y|`. + * \return \c 0 if `|X|` is equal to `|Y|`. + */ +int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Compare two MPIs. + * + * \param X The left-hand MPI. This must point to an initialized MPI. + * \param Y The right-hand MPI. This must point to an initialized MPI. + * + * \return \c 1 if \p X is greater than \p Y. + * \return \c -1 if \p X is lesser than \p Y. + * \return \c 0 if \p X is equal to \p Y. + */ +int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Compare an MPI with an integer. + * + * \param X The left-hand MPI. This must point to an initialized MPI. + * \param z The integer value to compare \p X to. + * + * \return \c 1 if \p X is greater than \p z. + * \return \c -1 if \p X is lesser than \p z. + * \return \c 0 if \p X is equal to \p z. + */ +int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z ); + +/** + * \brief Perform an unsigned addition of MPIs: X = |A| + |B| + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first summand. This must point to an initialized MPI. + * \param B The second summand. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B ); + +/** + * \brief Perform an unsigned subtraction of MPIs: X = |A| - |B| + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The minuend. This must point to an initialized MPI. + * \param B The subtrahend. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_NEGATIVE_VALUE if \p B is greater than \p A. + * \return Another negative error code on different kinds of failure. + * + */ +int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B ); + +/** + * \brief Perform a signed addition of MPIs: X = A + B + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first summand. This must point to an initialized MPI. + * \param B The second summand. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B ); + +/** + * \brief Perform a signed subtraction of MPIs: X = A - B + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The minuend. This must point to an initialized MPI. + * \param B The subtrahend. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B ); + +/** + * \brief Perform a signed addition of an MPI and an integer: X = A + b + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first summand. This must point to an initialized MPI. + * \param b The second summand. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, + mbedtls_mpi_sint b ); + +/** + * \brief Perform a signed subtraction of an MPI and an integer: + * X = A - b + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The minuend. This must point to an initialized MPI. + * \param b The subtrahend. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, + mbedtls_mpi_sint b ); + +/** + * \brief Perform a multiplication of two MPIs: X = A * B + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first factor. This must point to an initialized MPI. + * \param B The second factor. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + * + */ +int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *B ); + +/** + * \brief Perform a multiplication of an MPI with an unsigned integer: + * X = A * b + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The first factor. This must point to an initialized MPI. + * \param b The second factor. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + * + */ +int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, + mbedtls_mpi_uint b ); + +/** + * \brief Perform a division with remainder of two MPIs: + * A = Q * B + R + * + * \param Q The destination MPI for the quotient. + * This may be \c NULL if the value of the + * quotient is not needed. + * \param R The destination MPI for the remainder value. + * This may be \c NULL if the value of the + * remainder is not needed. + * \param A The dividend. This must point to an initialized MPi. + * \param B The divisor. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return #MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if \p B equals zero. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, + const mbedtls_mpi *B ); + +/** + * \brief Perform a division with remainder of an MPI by an integer: + * A = Q * b + R + * + * \param Q The destination MPI for the quotient. + * This may be \c NULL if the value of the + * quotient is not needed. + * \param R The destination MPI for the remainder value. + * This may be \c NULL if the value of the + * remainder is not needed. + * \param A The dividend. This must point to an initialized MPi. + * \param b The divisor. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return #MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if \p b equals zero. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, + mbedtls_mpi_sint b ); + +/** + * \brief Perform a modular reduction. R = A mod B + * + * \param R The destination MPI for the residue value. + * This must point to an initialized MPI. + * \param A The MPI to compute the residue of. + * This must point to an initialized MPI. + * \param B The base of the modular reduction. + * This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if \p B equals zero. + * \return #MBEDTLS_ERR_MPI_NEGATIVE_VALUE if \p B is negative. + * \return Another negative error code on different kinds of failure. + * + */ +int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, + const mbedtls_mpi *B ); + +/** + * \brief Perform a modular reduction with respect to an integer. + * r = A mod b + * + * \param r The address at which to store the residue. + * This must not be \c NULL. + * \param A The MPI to compute the residue of. + * This must point to an initialized MPi. + * \param b The integer base of the modular reduction. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if \p b equals zero. + * \return #MBEDTLS_ERR_MPI_NEGATIVE_VALUE if \p b is negative. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, + mbedtls_mpi_sint b ); + +/** + * \brief Perform a sliding-window exponentiation: X = A^E mod N + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The base of the exponentiation. + * This must point to an initialized MPI. + * \param E The exponent MPI. This must point to an initialized MPI. + * \param N The base for the modular reduction. This must point to an + * initialized MPI. + * \param _RR A helper MPI depending solely on \p N which can be used to + * speed-up multiple modular exponentiations for the same value + * of \p N. This may be \c NULL. If it is not \c NULL, it must + * point to an initialized MPI. If it hasn't been used after + * the call to mbedtls_mpi_init(), this function will compute + * the helper value and store it in \p _RR for reuse on + * subsequent calls to this function. Otherwise, the function + * will assume that \p _RR holds the helper value set by a + * previous call to mbedtls_mpi_exp_mod(), and reuse it. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \c N is negative or + * even, or if \c E is negative. + * \return Another negative error code on different kinds of failures. + * + */ +int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *E, const mbedtls_mpi *N, + mbedtls_mpi *_RR ); + +/** + * \brief Fill an MPI with a number of random bytes. + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param size The number of random bytes to generate. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on failure. + * + * \note The bytes obtained from the RNG are interpreted + * as a big-endian representation of an MPI; this can + * be relevant in applications like deterministic ECDSA. + */ +int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Compute the greatest common divisor: G = gcd(A, B) + * + * \param G The destination MPI. This must point to an initialized MPI. + * \param A The first operand. This must point to an initialized MPI. + * \param B The second operand. This must point to an initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, + const mbedtls_mpi *B ); + +/** + * \brief Compute the modular inverse: X = A^-1 mod N + * + * \param X The destination MPI. This must point to an initialized MPI. + * \param A The MPI to calculate the modular inverse of. This must point + * to an initialized MPI. + * \param N The base of the modular inversion. This must point to an + * initialized MPI. + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if \p N is less than + * or equal to one. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if \p has no modular inverse + * with respect to \p N. + */ +int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *N ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief Perform a Miller-Rabin primality test with error + * probability of 2-80. + * + * \deprecated Superseded by mbedtls_mpi_is_prime_ext() which allows + * specifying the number of Miller-Rabin rounds. + * + * \param X The MPI to check for primality. + * This must point to an initialized MPI. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * This may be \c NULL if \p f_rng doesn't use a + * context parameter. + * + * \return \c 0 if successful, i.e. \p X is probably prime. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if \p X is not prime. + * \return Another negative error code on other kinds of failure. + */ +MBEDTLS_DEPRECATED int mbedtls_mpi_is_prime( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Miller-Rabin primality test. + * + * \warning If \p X is potentially generated by an adversary, for example + * when validating cryptographic parameters that you didn't + * generate yourself and that are supposed to be prime, then + * \p rounds should be at least the half of the security + * strength of the cryptographic algorithm. On the other hand, + * if \p X is chosen uniformly or non-adversially (as is the + * case when mbedtls_mpi_gen_prime calls this function), then + * \p rounds can be much lower. + * + * \param X The MPI to check for primality. + * This must point to an initialized MPI. + * \param rounds The number of bases to perform the Miller-Rabin primality + * test for. The probability of returning 0 on a composite is + * at most 2-2*\p rounds. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * This may be \c NULL if \p f_rng doesn't use + * a context parameter. + * + * \return \c 0 if successful, i.e. \p X is probably prime. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if \p X is not prime. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_mpi_is_prime_ext( const mbedtls_mpi *X, int rounds, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +/** + * \brief Flags for mbedtls_mpi_gen_prime() + * + * Each of these flags is a constraint on the result X returned by + * mbedtls_mpi_gen_prime(). + */ +typedef enum { + MBEDTLS_MPI_GEN_PRIME_FLAG_DH = 0x0001, /**< (X-1)/2 is prime too */ + MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR = 0x0002, /**< lower error rate from 2-80 to 2-128 */ +} mbedtls_mpi_gen_prime_flag_t; + +/** + * \brief Generate a prime number. + * + * \param X The destination MPI to store the generated prime in. + * This must point to an initialized MPi. + * \param nbits The required size of the destination MPI in bits. + * This must be between \c 3 and #MBEDTLS_MPI_MAX_BITS. + * \param flags A mask of flags of type #mbedtls_mpi_gen_prime_flag_t. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. + * This may be \c NULL if \p f_rng doesn't use + * a context parameter. + * + * \return \c 0 if successful, in which case \p X holds a + * probably prime number. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if a memory allocation failed. + * \return #MBEDTLS_ERR_MPI_BAD_INPUT_DATA if `nbits` is not between + * \c 3 and #MBEDTLS_MPI_MAX_BITS. + */ +int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int flags, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_mpi_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* bignum.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/blowfish.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/blowfish.h new file mode 100644 index 000000000..b0d76f846 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/blowfish.h @@ -0,0 +1,287 @@ +/** + * \file blowfish.h + * + * \brief Blowfish block cipher + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_BLOWFISH_H +#define MBEDTLS_BLOWFISH_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#include "platform_util.h" + +#define MBEDTLS_BLOWFISH_ENCRYPT 1 +#define MBEDTLS_BLOWFISH_DECRYPT 0 +#define MBEDTLS_BLOWFISH_MAX_KEY_BITS 448 +#define MBEDTLS_BLOWFISH_MIN_KEY_BITS 32 +#define MBEDTLS_BLOWFISH_ROUNDS 16 /**< Rounds to use. When increasing this value, make sure to extend the initialisation vectors */ +#define MBEDTLS_BLOWFISH_BLOCKSIZE 8 /* Blowfish uses 64 bit blocks */ + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#define MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( -0x0016 ) +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ +#define MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA -0x0016 /**< Bad input data. */ + +#define MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH -0x0018 /**< Invalid data input length. */ + +/* MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED is deprecated and should not be used. + */ +#define MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED -0x0017 /**< Blowfish hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_BLOWFISH_ALT) +// Regular implementation +// + +/** + * \brief Blowfish context structure + */ +typedef struct mbedtls_blowfish_context +{ + uint32_t P[MBEDTLS_BLOWFISH_ROUNDS + 2]; /*!< Blowfish round keys */ + uint32_t S[4][256]; /*!< key dependent S-boxes */ +} +mbedtls_blowfish_context; + +#else /* MBEDTLS_BLOWFISH_ALT */ +#include "blowfish_alt.h" +#endif /* MBEDTLS_BLOWFISH_ALT */ + +/** + * \brief Initialize a Blowfish context. + * + * \param ctx The Blowfish context to be initialized. + * This must not be \c NULL. + */ +void mbedtls_blowfish_init( mbedtls_blowfish_context *ctx ); + +/** + * \brief Clear a Blowfish context. + * + * \param ctx The Blowfish context to be cleared. + * This may be \c NULL, in which case this function + * returns immediately. If it is not \c NULL, it must + * point to an initialized Blowfish context. + */ +void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx ); + +/** + * \brief Perform a Blowfish key schedule operation. + * + * \param ctx The Blowfish context to perform the key schedule on. + * \param key The encryption key. This must be a readable buffer of + * length \p keybits Bits. + * \param keybits The length of \p key in Bits. This must be between + * \c 32 and \c 448 and a multiple of \c 8. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_blowfish_setkey( mbedtls_blowfish_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief Perform a Blowfish-ECB block encryption/decryption operation. + * + * \param ctx The Blowfish context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. Possible values are + * #MBEDTLS_BLOWFISH_ENCRYPT for encryption, or + * #MBEDTLS_BLOWFISH_DECRYPT for decryption. + * \param input The input block. This must be a readable buffer + * of size \c 8 Bytes. + * \param output The output block. This must be a writable buffer + * of size \c 8 Bytes. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_blowfish_crypt_ecb( mbedtls_blowfish_context *ctx, + int mode, + const unsigned char input[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char output[MBEDTLS_BLOWFISH_BLOCKSIZE] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief Perform a Blowfish-CBC buffer encryption/decryption operation. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx The Blowfish context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. Possible values are + * #MBEDTLS_BLOWFISH_ENCRYPT for encryption, or + * #MBEDTLS_BLOWFISH_DECRYPT for decryption. + * \param length The length of the input data in Bytes. This must be + * multiple of \c 8. + * \param iv The initialization vector. This must be a read/write buffer + * of length \c 8 Bytes. It is updated by this function. + * \param input The input data. This must be a readable buffer of length + * \p length Bytes. + * \param output The output data. This must be a writable buffer of length + * \p length Bytes. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_blowfish_crypt_cbc( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief Perform a Blowfish CFB buffer encryption/decryption operation. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx The Blowfish context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. Possible values are + * #MBEDTLS_BLOWFISH_ENCRYPT for encryption, or + * #MBEDTLS_BLOWFISH_DECRYPT for decryption. + * \param length The length of the input data in Bytes. + * \param iv_off The offset in the initialiation vector. + * The value pointed to must be smaller than \c 8 Bytes. + * It is updated by this function to support the aforementioned + * streaming usage. + * \param iv The initialization vector. This must be a read/write buffer + * of size \c 8 Bytes. It is updated after use. + * \param input The input data. This must be a readable buffer of length + * \p length Bytes. + * \param output The output data. This must be a writable buffer of length + * \p length Bytes. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_blowfish_crypt_cfb64( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief Perform a Blowfish-CTR buffer encryption/decryption operation. + * + * \warning You must never reuse a nonce value with the same key. Doing so + * would void the encryption for the two messages encrypted with + * the same nonce and key. + * + * There are two common strategies for managing nonces with CTR: + * + * 1. You can handle everything as a single message processed over + * successive calls to this function. In that case, you want to + * set \p nonce_counter and \p nc_off to 0 for the first call, and + * then preserve the values of \p nonce_counter, \p nc_off and \p + * stream_block across calls to this function as they will be + * updated by this function. + * + * With this strategy, you must not encrypt more than 2**64 + * blocks of data with the same key. + * + * 2. You can encrypt separate messages by dividing the \p + * nonce_counter buffer in two areas: the first one used for a + * per-message nonce, handled by yourself, and the second one + * updated by this function internally. + * + * For example, you might reserve the first 4 bytes for the + * per-message nonce, and the last 4 bytes for internal use. In that + * case, before calling this function on a new message you need to + * set the first 4 bytes of \p nonce_counter to your chosen nonce + * value, the last 4 to 0, and \p nc_off to 0 (which will cause \p + * stream_block to be ignored). That way, you can encrypt at most + * 2**32 messages of up to 2**32 blocks each with the same key. + * + * The per-message nonce (or information sufficient to reconstruct + * it) needs to be communicated with the ciphertext and must be unique. + * The recommended way to ensure uniqueness is to use a message + * counter. + * + * Note that for both stategies, sizes are measured in blocks and + * that a Blowfish block is 8 bytes. + * + * \warning Upon return, \p stream_block contains sensitive data. Its + * content must not be written to insecure storage and should be + * securely discarded as soon as it's no longer needed. + * + * \param ctx The Blowfish context to use. This must be initialized + * and bound to a key. + * \param length The length of the input data in Bytes. + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer + * should be \c 0 at the start of a stream and must be + * smaller than \c 8. It is updated by this function. + * \param nonce_counter The 64-bit nonce and counter. This must point to a + * read/write buffer of length \c 8 Bytes. + * \param stream_block The saved stream-block for resuming. This must point to + * a read/write buffer of length \c 8 Bytes. + * \param input The input data. This must be a readable buffer of + * length \p length Bytes. + * \param output The output data. This must be a writable buffer of + * length \p length Bytes. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_blowfish_crypt_ctr( mbedtls_blowfish_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char stream_block[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#ifdef __cplusplus +} +#endif + +#endif /* blowfish.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/bn_mul.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/bn_mul.h new file mode 100644 index 000000000..74f3a8ab7 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/bn_mul.h @@ -0,0 +1,915 @@ +/** + * \file bn_mul.h + * + * \brief Multi-precision integer library + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * Multiply source vector [s] with b, add result + * to destination vector [d] and set carry c. + * + * Currently supports: + * + * . IA-32 (386+) . AMD64 / EM64T + * . IA-32 (SSE2) . Motorola 68000 + * . PowerPC, 32-bit . MicroBlaze + * . PowerPC, 64-bit . TriCore + * . SPARC v8 . ARM v3+ + * . Alpha . MIPS32 + * . C, longlong . C, generic + */ +#ifndef MBEDTLS_BN_MUL_H +#define MBEDTLS_BN_MUL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "bignum.h" + +#if defined(MBEDTLS_HAVE_ASM) + +#ifndef asm +#define asm __asm +#endif + +/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ +#if defined(__GNUC__) && \ + ( !defined(__ARMCC_VERSION) || __ARMCC_VERSION >= 6000000 ) + +/* + * Disable use of the i386 assembly code below if option -O0, to disable all + * compiler optimisations, is passed, detected with __OPTIMIZE__ + * This is done as the number of registers used in the assembly code doesn't + * work with the -O0 option. + */ +#if defined(__i386__) && defined(__OPTIMIZE__) + +#define MULADDC_INIT \ + asm( \ + "movl %%ebx, %0 \n\t" \ + "movl %5, %%esi \n\t" \ + "movl %6, %%edi \n\t" \ + "movl %7, %%ecx \n\t" \ + "movl %8, %%ebx \n\t" + +#define MULADDC_CORE \ + "lodsl \n\t" \ + "mull %%ebx \n\t" \ + "addl %%ecx, %%eax \n\t" \ + "adcl $0, %%edx \n\t" \ + "addl (%%edi), %%eax \n\t" \ + "adcl $0, %%edx \n\t" \ + "movl %%edx, %%ecx \n\t" \ + "stosl \n\t" + +#if defined(MBEDTLS_HAVE_SSE2) + +#define MULADDC_HUIT \ + "movd %%ecx, %%mm1 \n\t" \ + "movd %%ebx, %%mm0 \n\t" \ + "movd (%%edi), %%mm3 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd (%%esi), %%mm2 \n\t" \ + "pmuludq %%mm0, %%mm2 \n\t" \ + "movd 4(%%esi), %%mm4 \n\t" \ + "pmuludq %%mm0, %%mm4 \n\t" \ + "movd 8(%%esi), %%mm6 \n\t" \ + "pmuludq %%mm0, %%mm6 \n\t" \ + "movd 12(%%esi), %%mm7 \n\t" \ + "pmuludq %%mm0, %%mm7 \n\t" \ + "paddq %%mm2, %%mm1 \n\t" \ + "movd 4(%%edi), %%mm3 \n\t" \ + "paddq %%mm4, %%mm3 \n\t" \ + "movd 8(%%edi), %%mm5 \n\t" \ + "paddq %%mm6, %%mm5 \n\t" \ + "movd 12(%%edi), %%mm4 \n\t" \ + "paddq %%mm4, %%mm7 \n\t" \ + "movd %%mm1, (%%edi) \n\t" \ + "movd 16(%%esi), %%mm2 \n\t" \ + "pmuludq %%mm0, %%mm2 \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd 20(%%esi), %%mm4 \n\t" \ + "pmuludq %%mm0, %%mm4 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd 24(%%esi), %%mm6 \n\t" \ + "pmuludq %%mm0, %%mm6 \n\t" \ + "movd %%mm1, 4(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd 28(%%esi), %%mm3 \n\t" \ + "pmuludq %%mm0, %%mm3 \n\t" \ + "paddq %%mm5, %%mm1 \n\t" \ + "movd 16(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm2 \n\t" \ + "movd %%mm1, 8(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm7, %%mm1 \n\t" \ + "movd 20(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm4 \n\t" \ + "movd %%mm1, 12(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm2, %%mm1 \n\t" \ + "movd 24(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm6 \n\t" \ + "movd %%mm1, 16(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm4, %%mm1 \n\t" \ + "movd 28(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm3 \n\t" \ + "movd %%mm1, 20(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm6, %%mm1 \n\t" \ + "movd %%mm1, 24(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd %%mm1, 28(%%edi) \n\t" \ + "addl $32, %%edi \n\t" \ + "addl $32, %%esi \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd %%mm1, %%ecx \n\t" + +#define MULADDC_STOP \ + "emms \n\t" \ + "movl %4, %%ebx \n\t" \ + "movl %%ecx, %1 \n\t" \ + "movl %%edi, %2 \n\t" \ + "movl %%esi, %3 \n\t" \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ebx", "ecx", "edx", "esi", "edi" \ + ); + +#else + +#define MULADDC_STOP \ + "movl %4, %%ebx \n\t" \ + "movl %%ecx, %1 \n\t" \ + "movl %%edi, %2 \n\t" \ + "movl %%esi, %3 \n\t" \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ebx", "ecx", "edx", "esi", "edi" \ + ); +#endif /* SSE2 */ +#endif /* i386 */ + +#if defined(__amd64__) || defined (__x86_64__) + +#define MULADDC_INIT \ + asm( \ + "xorq %%r8, %%r8\n" + +#define MULADDC_CORE \ + "movq (%%rsi), %%rax\n" \ + "mulq %%rbx\n" \ + "addq $8, %%rsi\n" \ + "addq %%rcx, %%rax\n" \ + "movq %%r8, %%rcx\n" \ + "adcq $0, %%rdx\n" \ + "nop \n" \ + "addq %%rax, (%%rdi)\n" \ + "adcq %%rdx, %%rcx\n" \ + "addq $8, %%rdi\n" + +#define MULADDC_STOP \ + : "+c" (c), "+D" (d), "+S" (s) \ + : "b" (b) \ + : "rax", "rdx", "r8" \ + ); + +#endif /* AMD64 */ + +#if defined(__mc68020__) || defined(__mcpu32__) + +#define MULADDC_INIT \ + asm( \ + "movl %3, %%a2 \n\t" \ + "movl %4, %%a3 \n\t" \ + "movl %5, %%d3 \n\t" \ + "movl %6, %%d2 \n\t" \ + "moveq #0, %%d0 \n\t" + +#define MULADDC_CORE \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "moveq #0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "addxl %%d4, %%d3 \n\t" + +#define MULADDC_STOP \ + "movl %%d3, %0 \n\t" \ + "movl %%a3, %1 \n\t" \ + "movl %%a2, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "d0", "d1", "d2", "d3", "d4", "a2", "a3" \ + ); + +#define MULADDC_HUIT \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "addxl %%d0, %%d3 \n\t" + +#endif /* MC68000 */ + +#if defined(__powerpc64__) || defined(__ppc64__) + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( \ + "ld r3, %3 \n\t" \ + "ld r4, %4 \n\t" \ + "ld r5, %5 \n\t" \ + "ld r6, %6 \n\t" \ + "addi r3, r3, -8 \n\t" \ + "addi r4, r4, -8 \n\t" \ + "addic r5, r5, 0 \n\t" + +#define MULADDC_CORE \ + "ldu r7, 8(r3) \n\t" \ + "mulld r8, r7, r6 \n\t" \ + "mulhdu r9, r7, r6 \n\t" \ + "adde r8, r8, r5 \n\t" \ + "ld r7, 8(r4) \n\t" \ + "addze r5, r9 \n\t" \ + "addc r8, r8, r7 \n\t" \ + "stdu r8, 8(r4) \n\t" + +#define MULADDC_STOP \ + "addze r5, r5 \n\t" \ + "addi r4, r4, 8 \n\t" \ + "addi r3, r3, 8 \n\t" \ + "std r5, %0 \n\t" \ + "std r4, %1 \n\t" \ + "std r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + + +#else /* __MACH__ && __APPLE__ */ + +#define MULADDC_INIT \ + asm( \ + "ld %%r3, %3 \n\t" \ + "ld %%r4, %4 \n\t" \ + "ld %%r5, %5 \n\t" \ + "ld %%r6, %6 \n\t" \ + "addi %%r3, %%r3, -8 \n\t" \ + "addi %%r4, %%r4, -8 \n\t" \ + "addic %%r5, %%r5, 0 \n\t" + +#define MULADDC_CORE \ + "ldu %%r7, 8(%%r3) \n\t" \ + "mulld %%r8, %%r7, %%r6 \n\t" \ + "mulhdu %%r9, %%r7, %%r6 \n\t" \ + "adde %%r8, %%r8, %%r5 \n\t" \ + "ld %%r7, 8(%%r4) \n\t" \ + "addze %%r5, %%r9 \n\t" \ + "addc %%r8, %%r8, %%r7 \n\t" \ + "stdu %%r8, 8(%%r4) \n\t" + +#define MULADDC_STOP \ + "addze %%r5, %%r5 \n\t" \ + "addi %%r4, %%r4, 8 \n\t" \ + "addi %%r3, %%r3, 8 \n\t" \ + "std %%r5, %0 \n\t" \ + "std %%r4, %1 \n\t" \ + "std %%r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#endif /* __MACH__ && __APPLE__ */ + +#elif defined(__powerpc__) || defined(__ppc__) /* end PPC64/begin PPC32 */ + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( \ + "lwz r3, %3 \n\t" \ + "lwz r4, %4 \n\t" \ + "lwz r5, %5 \n\t" \ + "lwz r6, %6 \n\t" \ + "addi r3, r3, -4 \n\t" \ + "addi r4, r4, -4 \n\t" \ + "addic r5, r5, 0 \n\t" + +#define MULADDC_CORE \ + "lwzu r7, 4(r3) \n\t" \ + "mullw r8, r7, r6 \n\t" \ + "mulhwu r9, r7, r6 \n\t" \ + "adde r8, r8, r5 \n\t" \ + "lwz r7, 4(r4) \n\t" \ + "addze r5, r9 \n\t" \ + "addc r8, r8, r7 \n\t" \ + "stwu r8, 4(r4) \n\t" + +#define MULADDC_STOP \ + "addze r5, r5 \n\t" \ + "addi r4, r4, 4 \n\t" \ + "addi r3, r3, 4 \n\t" \ + "stw r5, %0 \n\t" \ + "stw r4, %1 \n\t" \ + "stw r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#else /* __MACH__ && __APPLE__ */ + +#define MULADDC_INIT \ + asm( \ + "lwz %%r3, %3 \n\t" \ + "lwz %%r4, %4 \n\t" \ + "lwz %%r5, %5 \n\t" \ + "lwz %%r6, %6 \n\t" \ + "addi %%r3, %%r3, -4 \n\t" \ + "addi %%r4, %%r4, -4 \n\t" \ + "addic %%r5, %%r5, 0 \n\t" + +#define MULADDC_CORE \ + "lwzu %%r7, 4(%%r3) \n\t" \ + "mullw %%r8, %%r7, %%r6 \n\t" \ + "mulhwu %%r9, %%r7, %%r6 \n\t" \ + "adde %%r8, %%r8, %%r5 \n\t" \ + "lwz %%r7, 4(%%r4) \n\t" \ + "addze %%r5, %%r9 \n\t" \ + "addc %%r8, %%r8, %%r7 \n\t" \ + "stwu %%r8, 4(%%r4) \n\t" + +#define MULADDC_STOP \ + "addze %%r5, %%r5 \n\t" \ + "addi %%r4, %%r4, 4 \n\t" \ + "addi %%r3, %%r3, 4 \n\t" \ + "stw %%r5, %0 \n\t" \ + "stw %%r4, %1 \n\t" \ + "stw %%r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#endif /* __MACH__ && __APPLE__ */ + +#endif /* PPC32 */ + +/* + * The Sparc(64) assembly is reported to be broken. + * Disable it for now, until we're able to fix it. + */ +#if 0 && defined(__sparc__) +#if defined(__sparc64__) + +#define MULADDC_INIT \ + asm( \ + "ldx %3, %%o0 \n\t" \ + "ldx %4, %%o1 \n\t" \ + "ld %5, %%o2 \n\t" \ + "ld %6, %%o3 \n\t" + +#define MULADDC_CORE \ + "ld [%%o0], %%o4 \n\t" \ + "inc 4, %%o0 \n\t" \ + "ld [%%o1], %%o5 \n\t" \ + "umul %%o3, %%o4, %%o4 \n\t" \ + "addcc %%o4, %%o2, %%o4 \n\t" \ + "rd %%y, %%g1 \n\t" \ + "addx %%g1, 0, %%g1 \n\t" \ + "addcc %%o4, %%o5, %%o4 \n\t" \ + "st %%o4, [%%o1] \n\t" \ + "addx %%g1, 0, %%o2 \n\t" \ + "inc 4, %%o1 \n\t" + + #define MULADDC_STOP \ + "st %%o2, %0 \n\t" \ + "stx %%o1, %1 \n\t" \ + "stx %%o0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "g1", "o0", "o1", "o2", "o3", "o4", \ + "o5" \ + ); + +#else /* __sparc64__ */ + +#define MULADDC_INIT \ + asm( \ + "ld %3, %%o0 \n\t" \ + "ld %4, %%o1 \n\t" \ + "ld %5, %%o2 \n\t" \ + "ld %6, %%o3 \n\t" + +#define MULADDC_CORE \ + "ld [%%o0], %%o4 \n\t" \ + "inc 4, %%o0 \n\t" \ + "ld [%%o1], %%o5 \n\t" \ + "umul %%o3, %%o4, %%o4 \n\t" \ + "addcc %%o4, %%o2, %%o4 \n\t" \ + "rd %%y, %%g1 \n\t" \ + "addx %%g1, 0, %%g1 \n\t" \ + "addcc %%o4, %%o5, %%o4 \n\t" \ + "st %%o4, [%%o1] \n\t" \ + "addx %%g1, 0, %%o2 \n\t" \ + "inc 4, %%o1 \n\t" + +#define MULADDC_STOP \ + "st %%o2, %0 \n\t" \ + "st %%o1, %1 \n\t" \ + "st %%o0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "g1", "o0", "o1", "o2", "o3", "o4", \ + "o5" \ + ); + +#endif /* __sparc64__ */ +#endif /* __sparc__ */ + +#if defined(__microblaze__) || defined(microblaze) + +#define MULADDC_INIT \ + asm( \ + "lwi r3, %3 \n\t" \ + "lwi r4, %4 \n\t" \ + "lwi r5, %5 \n\t" \ + "lwi r6, %6 \n\t" \ + "andi r7, r6, 0xffff \n\t" \ + "bsrli r6, r6, 16 \n\t" + +#define MULADDC_CORE \ + "lhui r8, r3, 0 \n\t" \ + "addi r3, r3, 2 \n\t" \ + "lhui r9, r3, 0 \n\t" \ + "addi r3, r3, 2 \n\t" \ + "mul r10, r9, r6 \n\t" \ + "mul r11, r8, r7 \n\t" \ + "mul r12, r9, r7 \n\t" \ + "mul r13, r8, r6 \n\t" \ + "bsrli r8, r10, 16 \n\t" \ + "bsrli r9, r11, 16 \n\t" \ + "add r13, r13, r8 \n\t" \ + "add r13, r13, r9 \n\t" \ + "bslli r10, r10, 16 \n\t" \ + "bslli r11, r11, 16 \n\t" \ + "add r12, r12, r10 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "add r12, r12, r11 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "lwi r10, r4, 0 \n\t" \ + "add r12, r12, r10 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "add r12, r12, r5 \n\t" \ + "addc r5, r13, r0 \n\t" \ + "swi r12, r4, 0 \n\t" \ + "addi r4, r4, 4 \n\t" + +#define MULADDC_STOP \ + "swi r5, %0 \n\t" \ + "swi r4, %1 \n\t" \ + "swi r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", \ + "r9", "r10", "r11", "r12", "r13" \ + ); + +#endif /* MicroBlaze */ + +#if defined(__tricore__) + +#define MULADDC_INIT \ + asm( \ + "ld.a %%a2, %3 \n\t" \ + "ld.a %%a3, %4 \n\t" \ + "ld.w %%d4, %5 \n\t" \ + "ld.w %%d1, %6 \n\t" \ + "xor %%d5, %%d5 \n\t" + +#define MULADDC_CORE \ + "ld.w %%d0, [%%a2+] \n\t" \ + "madd.u %%e2, %%e4, %%d0, %%d1 \n\t" \ + "ld.w %%d0, [%%a3] \n\t" \ + "addx %%d2, %%d2, %%d0 \n\t" \ + "addc %%d3, %%d3, 0 \n\t" \ + "mov %%d4, %%d3 \n\t" \ + "st.w [%%a3+], %%d2 \n\t" + +#define MULADDC_STOP \ + "st.w %0, %%d4 \n\t" \ + "st.a %1, %%a3 \n\t" \ + "st.a %2, %%a2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "d0", "d1", "e2", "d4", "a2", "a3" \ + ); + +#endif /* TriCore */ + +/* + * Note, gcc -O0 by default uses r7 for the frame pointer, so it complains about + * our use of r7 below, unless -fomit-frame-pointer is passed. + * + * On the other hand, -fomit-frame-pointer is implied by any -Ox options with + * x !=0, which we can detect using __OPTIMIZE__ (which is also defined by + * clang and armcc5 under the same conditions). + * + * So, only use the optimized assembly below for optimized build, which avoids + * the build error and is pretty reasonable anyway. + */ +#if defined(__GNUC__) && !defined(__OPTIMIZE__) +#define MULADDC_CANNOT_USE_R7 +#endif + +#if defined(__arm__) && !defined(MULADDC_CANNOT_USE_R7) + +#if defined(__thumb__) && !defined(__thumb2__) + +#define MULADDC_INIT \ + asm( \ + "ldr r0, %3 \n\t" \ + "ldr r1, %4 \n\t" \ + "ldr r2, %5 \n\t" \ + "ldr r3, %6 \n\t" \ + "lsr r7, r3, #16 \n\t" \ + "mov r9, r7 \n\t" \ + "lsl r7, r3, #16 \n\t" \ + "lsr r7, r7, #16 \n\t" \ + "mov r8, r7 \n\t" + +#define MULADDC_CORE \ + "ldmia r0!, {r6} \n\t" \ + "lsr r7, r6, #16 \n\t" \ + "lsl r6, r6, #16 \n\t" \ + "lsr r6, r6, #16 \n\t" \ + "mov r4, r8 \n\t" \ + "mul r4, r6 \n\t" \ + "mov r3, r9 \n\t" \ + "mul r6, r3 \n\t" \ + "mov r5, r9 \n\t" \ + "mul r5, r7 \n\t" \ + "mov r3, r8 \n\t" \ + "mul r7, r3 \n\t" \ + "lsr r3, r6, #16 \n\t" \ + "add r5, r5, r3 \n\t" \ + "lsr r3, r7, #16 \n\t" \ + "add r5, r5, r3 \n\t" \ + "add r4, r4, r2 \n\t" \ + "mov r2, #0 \n\t" \ + "adc r5, r2 \n\t" \ + "lsl r3, r6, #16 \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r5, r2 \n\t" \ + "lsl r3, r7, #16 \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r5, r2 \n\t" \ + "ldr r3, [r1] \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r2, r5 \n\t" \ + "stmia r1!, {r4} \n\t" + +#define MULADDC_STOP \ + "str r2, %0 \n\t" \ + "str r1, %1 \n\t" \ + "str r0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "r8", "r9", "cc" \ + ); + +#elif defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1) + +#define MULADDC_INIT \ + asm( + +#define MULADDC_CORE \ + "ldr r0, [%0], #4 \n\t" \ + "ldr r1, [%1] \n\t" \ + "umaal r1, %2, %3, r0 \n\t" \ + "str r1, [%1], #4 \n\t" + +#define MULADDC_STOP \ + : "=r" (s), "=r" (d), "=r" (c) \ + : "r" (b), "0" (s), "1" (d), "2" (c) \ + : "r0", "r1", "memory" \ + ); + +#else + +#define MULADDC_INIT \ + asm( \ + "ldr r0, %3 \n\t" \ + "ldr r1, %4 \n\t" \ + "ldr r2, %5 \n\t" \ + "ldr r3, %6 \n\t" + +#define MULADDC_CORE \ + "ldr r4, [r0], #4 \n\t" \ + "mov r5, #0 \n\t" \ + "ldr r6, [r1] \n\t" \ + "umlal r2, r5, r3, r4 \n\t" \ + "adds r7, r6, r2 \n\t" \ + "adc r2, r5, #0 \n\t" \ + "str r7, [r1], #4 \n\t" + +#define MULADDC_STOP \ + "str r2, %0 \n\t" \ + "str r1, %1 \n\t" \ + "str r0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "cc" \ + ); + +#endif /* Thumb */ + +#endif /* ARMv3 */ + +#if defined(__alpha__) + +#define MULADDC_INIT \ + asm( \ + "ldq $1, %3 \n\t" \ + "ldq $2, %4 \n\t" \ + "ldq $3, %5 \n\t" \ + "ldq $4, %6 \n\t" + +#define MULADDC_CORE \ + "ldq $6, 0($1) \n\t" \ + "addq $1, 8, $1 \n\t" \ + "mulq $6, $4, $7 \n\t" \ + "umulh $6, $4, $6 \n\t" \ + "addq $7, $3, $7 \n\t" \ + "cmpult $7, $3, $3 \n\t" \ + "ldq $5, 0($2) \n\t" \ + "addq $7, $5, $7 \n\t" \ + "cmpult $7, $5, $5 \n\t" \ + "stq $7, 0($2) \n\t" \ + "addq $2, 8, $2 \n\t" \ + "addq $6, $3, $3 \n\t" \ + "addq $5, $3, $3 \n\t" + +#define MULADDC_STOP \ + "stq $3, %0 \n\t" \ + "stq $2, %1 \n\t" \ + "stq $1, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "$1", "$2", "$3", "$4", "$5", "$6", "$7" \ + ); +#endif /* Alpha */ + +#if defined(__mips__) && !defined(__mips64) + +#define MULADDC_INIT \ + asm( \ + "lw $10, %3 \n\t" \ + "lw $11, %4 \n\t" \ + "lw $12, %5 \n\t" \ + "lw $13, %6 \n\t" + +#define MULADDC_CORE \ + "lw $14, 0($10) \n\t" \ + "multu $13, $14 \n\t" \ + "addi $10, $10, 4 \n\t" \ + "mflo $14 \n\t" \ + "mfhi $9 \n\t" \ + "addu $14, $12, $14 \n\t" \ + "lw $15, 0($11) \n\t" \ + "sltu $12, $14, $12 \n\t" \ + "addu $15, $14, $15 \n\t" \ + "sltu $14, $15, $14 \n\t" \ + "addu $12, $12, $9 \n\t" \ + "sw $15, 0($11) \n\t" \ + "addu $12, $12, $14 \n\t" \ + "addi $11, $11, 4 \n\t" + +#define MULADDC_STOP \ + "sw $12, %0 \n\t" \ + "sw $11, %1 \n\t" \ + "sw $10, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "$9", "$10", "$11", "$12", "$13", "$14", "$15", "lo", "hi" \ + ); + +#endif /* MIPS */ +#endif /* GNUC */ + +#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) + +#define MULADDC_INIT \ + __asm mov esi, s \ + __asm mov edi, d \ + __asm mov ecx, c \ + __asm mov ebx, b + +#define MULADDC_CORE \ + __asm lodsd \ + __asm mul ebx \ + __asm add eax, ecx \ + __asm adc edx, 0 \ + __asm add eax, [edi] \ + __asm adc edx, 0 \ + __asm mov ecx, edx \ + __asm stosd + +#if defined(MBEDTLS_HAVE_SSE2) + +#define EMIT __asm _emit + +#define MULADDC_HUIT \ + EMIT 0x0F EMIT 0x6E EMIT 0xC9 \ + EMIT 0x0F EMIT 0x6E EMIT 0xC3 \ + EMIT 0x0F EMIT 0x6E EMIT 0x1F \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x16 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xEE \ + EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xFC \ + EMIT 0x0F EMIT 0x7E EMIT 0x0F \ + EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCD \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCF \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDD \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCE \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \ + EMIT 0x83 EMIT 0xC7 EMIT 0x20 \ + EMIT 0x83 EMIT 0xC6 EMIT 0x20 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x7E EMIT 0xC9 + +#define MULADDC_STOP \ + EMIT 0x0F EMIT 0x77 \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#else + +#define MULADDC_STOP \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#endif /* SSE2 */ +#endif /* MSVC */ + +#endif /* MBEDTLS_HAVE_ASM */ + +#if !defined(MULADDC_CORE) +#if defined(MBEDTLS_HAVE_UDBL) + +#define MULADDC_INIT \ +{ \ + mbedtls_t_udbl r; \ + mbedtls_mpi_uint r0, r1; + +#define MULADDC_CORE \ + r = *(s++) * (mbedtls_t_udbl) b; \ + r0 = (mbedtls_mpi_uint) r; \ + r1 = (mbedtls_mpi_uint)( r >> biL ); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#else +#define MULADDC_INIT \ +{ \ + mbedtls_mpi_uint s0, s1, b0, b1; \ + mbedtls_mpi_uint r0, r1, rx, ry; \ + b0 = ( b << biH ) >> biH; \ + b1 = ( b >> biH ); + +#define MULADDC_CORE \ + s0 = ( *s << biH ) >> biH; \ + s1 = ( *s >> biH ); s++; \ + rx = s0 * b1; r0 = s0 * b0; \ + ry = s1 * b0; r1 = s1 * b1; \ + r1 += ( rx >> biH ); \ + r1 += ( ry >> biH ); \ + rx <<= biH; ry <<= biH; \ + r0 += rx; r1 += (r0 < rx); \ + r0 += ry; r1 += (r0 < ry); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#endif /* C (generic) */ +#endif /* C (longlong) */ + +#endif /* bn_mul.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/camellia.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/camellia.h new file mode 100644 index 000000000..b9e10cd55 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/camellia.h @@ -0,0 +1,326 @@ +/** + * \file camellia.h + * + * \brief Camellia block cipher + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CAMELLIA_H +#define MBEDTLS_CAMELLIA_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#include "platform_util.h" + +#define MBEDTLS_CAMELLIA_ENCRYPT 1 +#define MBEDTLS_CAMELLIA_DECRYPT 0 + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#define MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( -0x0024 ) +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ +#define MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA -0x0024 /**< Bad input data. */ + +#define MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH -0x0026 /**< Invalid data input length. */ + +/* MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED is deprecated and should not be used. + */ +#define MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED -0x0027 /**< Camellia hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_CAMELLIA_ALT) +// Regular implementation +// + +/** + * \brief CAMELLIA context structure + */ +typedef struct mbedtls_camellia_context +{ + int nr; /*!< number of rounds */ + uint32_t rk[68]; /*!< CAMELLIA round keys */ +} +mbedtls_camellia_context; + +#else /* MBEDTLS_CAMELLIA_ALT */ +#include "camellia_alt.h" +#endif /* MBEDTLS_CAMELLIA_ALT */ + +/** + * \brief Initialize a CAMELLIA context. + * + * \param ctx The CAMELLIA context to be initialized. + * This must not be \c NULL. + */ +void mbedtls_camellia_init( mbedtls_camellia_context *ctx ); + +/** + * \brief Clear a CAMELLIA context. + * + * \param ctx The CAMELLIA context to be cleared. This may be \c NULL, + * in which case this function returns immediately. If it is not + * \c NULL, it must be initialized. + */ +void mbedtls_camellia_free( mbedtls_camellia_context *ctx ); + +/** + * \brief Perform a CAMELLIA key schedule operation for encryption. + * + * \param ctx The CAMELLIA context to use. This must be initialized. + * \param key The encryption key to use. This must be a readable buffer + * of size \p keybits Bits. + * \param keybits The length of \p key in Bits. This must be either \c 128, + * \c 192 or \c 256. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief Perform a CAMELLIA key schedule operation for decryption. + * + * \param ctx The CAMELLIA context to use. This must be initialized. + * \param key The decryption key. This must be a readable buffer + * of size \p keybits Bits. + * \param keybits The length of \p key in Bits. This must be either \c 128, + * \c 192 or \c 256. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_camellia_setkey_dec( mbedtls_camellia_context *ctx, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief Perform a CAMELLIA-ECB block encryption/decryption operation. + * + * \param ctx The CAMELLIA context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. This must be either + * #MBEDTLS_CAMELLIA_ENCRYPT or #MBEDTLS_CAMELLIA_DECRYPT. + * \param input The input block. This must be a readable buffer + * of size \c 16 Bytes. + * \param output The output block. This must be a writable buffer + * of size \c 16 Bytes. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_camellia_crypt_ecb( mbedtls_camellia_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief Perform a CAMELLIA-CBC buffer encryption/decryption operation. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx The CAMELLIA context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. This must be either + * #MBEDTLS_CAMELLIA_ENCRYPT or #MBEDTLS_CAMELLIA_DECRYPT. + * \param length The length in Bytes of the input data \p input. + * This must be a multiple of \c 16 Bytes. + * \param iv The initialization vector. This must be a read/write buffer + * of length \c 16 Bytes. It is updated to allow streaming + * use as explained above. + * \param input The buffer holding the input data. This must point to a + * readable buffer of length \p length Bytes. + * \param output The buffer holding the output data. This must point to a + * writable buffer of length \p length Bytes. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_camellia_crypt_cbc( mbedtls_camellia_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief Perform a CAMELLIA-CFB128 buffer encryption/decryption + * operation. + * + * \note Due to the nature of CFB mode, you should use the same + * key for both encryption and decryption. In particular, calls + * to this function should be preceded by a key-schedule via + * mbedtls_camellia_setkey_enc() regardless of whether \p mode + * is #MBEDTLS_CAMELLIA_ENCRYPT or #MBEDTLS_CAMELLIA_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx The CAMELLIA context to use. This must be initialized + * and bound to a key. + * \param mode The mode of operation. This must be either + * #MBEDTLS_CAMELLIA_ENCRYPT or #MBEDTLS_CAMELLIA_DECRYPT. + * \param length The length of the input data \p input. Any value is allowed. + * \param iv_off The current offset in the IV. This must be smaller + * than \c 16 Bytes. It is updated after this call to allow + * the aforementioned streaming usage. + * \param iv The initialization vector. This must be a read/write buffer + * of length \c 16 Bytes. It is updated after this call to + * allow the aforementioned streaming usage. + * \param input The buffer holding the input data. This must be a readable + * buffer of size \p length Bytes. + * \param output The buffer to hold the output data. This must be a writable + * buffer of length \p length Bytes. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_camellia_crypt_cfb128( mbedtls_camellia_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief Perform a CAMELLIA-CTR buffer encryption/decryption operation. + * + * *note Due to the nature of CTR mode, you should use the same + * key for both encryption and decryption. In particular, calls + * to this function should be preceded by a key-schedule via + * mbedtls_camellia_setkey_enc() regardless of whether \p mode + * is #MBEDTLS_CAMELLIA_ENCRYPT or #MBEDTLS_CAMELLIA_DECRYPT. + * + * \warning You must never reuse a nonce value with the same key. Doing so + * would void the encryption for the two messages encrypted with + * the same nonce and key. + * + * There are two common strategies for managing nonces with CTR: + * + * 1. You can handle everything as a single message processed over + * successive calls to this function. In that case, you want to + * set \p nonce_counter and \p nc_off to 0 for the first call, and + * then preserve the values of \p nonce_counter, \p nc_off and \p + * stream_block across calls to this function as they will be + * updated by this function. + * + * With this strategy, you must not encrypt more than 2**128 + * blocks of data with the same key. + * + * 2. You can encrypt separate messages by dividing the \p + * nonce_counter buffer in two areas: the first one used for a + * per-message nonce, handled by yourself, and the second one + * updated by this function internally. + * + * For example, you might reserve the first \c 12 Bytes for the + * per-message nonce, and the last \c 4 Bytes for internal use. + * In that case, before calling this function on a new message you + * need to set the first \c 12 Bytes of \p nonce_counter to your + * chosen nonce value, the last four to \c 0, and \p nc_off to \c 0 + * (which will cause \p stream_block to be ignored). That way, you + * can encrypt at most \c 2**96 messages of up to \c 2**32 blocks + * each with the same key. + * + * The per-message nonce (or information sufficient to reconstruct + * it) needs to be communicated with the ciphertext and must be + * unique. The recommended way to ensure uniqueness is to use a + * message counter. An alternative is to generate random nonces, + * but this limits the number of messages that can be securely + * encrypted: for example, with 96-bit random nonces, you should + * not encrypt more than 2**32 messages with the same key. + * + * Note that for both stategies, sizes are measured in blocks and + * that a CAMELLIA block is \c 16 Bytes. + * + * \warning Upon return, \p stream_block contains sensitive data. Its + * content must not be written to insecure storage and should be + * securely discarded as soon as it's no longer needed. + * + * \param ctx The CAMELLIA context to use. This must be initialized + * and bound to a key. + * \param length The length of the input data \p input in Bytes. + * Any value is allowed. + * \param nc_off The offset in the current \p stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be \c 0 at the start of a stream. It is updated + * at the end of this call. + * \param nonce_counter The 128-bit nonce and counter. This must be a read/write + * buffer of length \c 16 Bytes. + * \param stream_block The saved stream-block for resuming. This must be a + * read/write buffer of length \c 16 Bytes. + * \param input The input data stream. This must be a readable buffer of + * size \p length Bytes. + * \param output The output data stream. This must be a writable buffer + * of size \p length Bytes. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_camellia_crypt_ctr( mbedtls_camellia_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_camellia_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* camellia.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ccm.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ccm.h new file mode 100644 index 000000000..688dbd73e --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ccm.h @@ -0,0 +1,310 @@ +/** + * \file ccm.h + * + * \brief This file provides an API for the CCM authenticated encryption + * mode for block ciphers. + * + * CCM combines Counter mode encryption with CBC-MAC authentication + * for 128-bit block ciphers. + * + * Input to CCM includes the following elements: + *
  • Payload - data that is both authenticated and encrypted.
  • + *
  • Associated data (Adata) - data that is authenticated but not + * encrypted, For example, a header.
  • + *
  • Nonce - A unique value that is assigned to the payload and the + * associated data.
+ * + * Definition of CCM: + * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf + * RFC 3610 "Counter with CBC-MAC (CCM)" + * + * Related: + * RFC 5116 "An Interface and Algorithms for Authenticated Encryption" + * + * Definition of CCM*: + * IEEE 802.15.4 - IEEE Standard for Local and metropolitan area networks + * Integer representation is fixed most-significant-octet-first order and + * the representation of octets is most-significant-bit-first order. This is + * consistent with RFC 3610. + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CCM_H +#define MBEDTLS_CCM_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "cipher.h" + +#define MBEDTLS_ERR_CCM_BAD_INPUT -0x000D /**< Bad input parameters to the function. */ +#define MBEDTLS_ERR_CCM_AUTH_FAILED -0x000F /**< Authenticated decryption failed. */ + +/* MBEDTLS_ERR_CCM_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_CCM_HW_ACCEL_FAILED -0x0011 /**< CCM hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_CCM_ALT) +// Regular implementation +// + +/** + * \brief The CCM context-type definition. The CCM context is passed + * to the APIs called. + */ +typedef struct mbedtls_ccm_context +{ + mbedtls_cipher_context_t cipher_ctx; /*!< The cipher context used. */ +} +mbedtls_ccm_context; + +#else /* MBEDTLS_CCM_ALT */ +#include "ccm_alt.h" +#endif /* MBEDTLS_CCM_ALT */ + +/** + * \brief This function initializes the specified CCM context, + * to make references valid, and prepare the context + * for mbedtls_ccm_setkey() or mbedtls_ccm_free(). + * + * \param ctx The CCM context to initialize. This must not be \c NULL. + */ +void mbedtls_ccm_init( mbedtls_ccm_context *ctx ); + +/** + * \brief This function initializes the CCM context set in the + * \p ctx parameter and sets the encryption key. + * + * \param ctx The CCM context to initialize. This must be an initialized + * context. + * \param cipher The 128-bit block cipher to use. + * \param key The encryption key. This must not be \c NULL. + * \param keybits The key size in bits. This must be acceptable by the cipher. + * + * \return \c 0 on success. + * \return A CCM or cipher-specific error code on failure. + */ +int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief This function releases and clears the specified CCM context + * and underlying cipher sub-context. + * + * \param ctx The CCM context to clear. If this is \c NULL, the function + * has no effect. Otherwise, this must be initialized. + */ +void mbedtls_ccm_free( mbedtls_ccm_context *ctx ); + +/** + * \brief This function encrypts a buffer using CCM. + * + * \note The tag is written to a separate buffer. To concatenate + * the \p tag with the \p output, as done in RFC-3610: + * Counter with CBC-MAC (CCM), use + * \p tag = \p output + \p length, and make sure that the + * output buffer is at least \p length + \p tag_len wide. + * + * \param ctx The CCM context to use for encryption. This must be + * initialized and bound to a key. + * \param length The length of the input data in Bytes. + * \param iv The initialization vector (nonce). This must be a readable + * buffer of at least \p iv_len Bytes. + * \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12, + * or 13. The length L of the message length field is + * 15 - \p iv_len. + * \param add The additional data field. If \p add_len is greater than + * zero, \p add must be a readable buffer of at least that + * length. + * \param add_len The length of additional data in Bytes. + * This must be less than `2^16 - 2^8`. + * \param input The buffer holding the input data. If \p length is greater + * than zero, \p input must be a readable buffer of at least + * that length. + * \param output The buffer holding the output data. If \p length is greater + * than zero, \p output must be a writable buffer of at least + * that length. + * \param tag The buffer holding the authentication field. This must be a + * readable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the authentication field to generate in Bytes: + * 4, 6, 8, 10, 12, 14 or 16. + * + * \return \c 0 on success. + * \return A CCM or cipher-specific error code on failure. + */ +int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ); + +/** + * \brief This function encrypts a buffer using CCM*. + * + * \note The tag is written to a separate buffer. To concatenate + * the \p tag with the \p output, as done in RFC-3610: + * Counter with CBC-MAC (CCM), use + * \p tag = \p output + \p length, and make sure that the + * output buffer is at least \p length + \p tag_len wide. + * + * \note When using this function in a variable tag length context, + * the tag length has to be encoded into the \p iv passed to + * this function. + * + * \param ctx The CCM context to use for encryption. This must be + * initialized and bound to a key. + * \param length The length of the input data in Bytes. + * \param iv The initialization vector (nonce). This must be a readable + * buffer of at least \p iv_len Bytes. + * \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12, + * or 13. The length L of the message length field is + * 15 - \p iv_len. + * \param add The additional data field. This must be a readable buffer of + * at least \p add_len Bytes. + * \param add_len The length of additional data in Bytes. + * This must be less than 2^16 - 2^8. + * \param input The buffer holding the input data. If \p length is greater + * than zero, \p input must be a readable buffer of at least + * that length. + * \param output The buffer holding the output data. If \p length is greater + * than zero, \p output must be a writable buffer of at least + * that length. + * \param tag The buffer holding the authentication field. This must be a + * readable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the authentication field to generate in Bytes: + * 0, 4, 6, 8, 10, 12, 14 or 16. + * + * \warning Passing \c 0 as \p tag_len means that the message is no + * longer authenticated. + * + * \return \c 0 on success. + * \return A CCM or cipher-specific error code on failure. + */ +int mbedtls_ccm_star_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ); + +/** + * \brief This function performs a CCM authenticated decryption of a + * buffer. + * + * \param ctx The CCM context to use for decryption. This must be + * initialized and bound to a key. + * \param length The length of the input data in Bytes. + * \param iv The initialization vector (nonce). This must be a readable + * buffer of at least \p iv_len Bytes. + * \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12, + * or 13. The length L of the message length field is + * 15 - \p iv_len. + * \param add The additional data field. This must be a readable buffer + * of at least that \p add_len Bytes.. + * \param add_len The length of additional data in Bytes. + * This must be less than 2^16 - 2^8. + * \param input The buffer holding the input data. If \p length is greater + * than zero, \p input must be a readable buffer of at least + * that length. + * \param output The buffer holding the output data. If \p length is greater + * than zero, \p output must be a writable buffer of at least + * that length. + * \param tag The buffer holding the authentication field. This must be a + * readable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the authentication field to generate in Bytes: + * 4, 6, 8, 10, 12, 14 or 16. + * + * \return \c 0 on success. This indicates that the message is authentic. + * \return #MBEDTLS_ERR_CCM_AUTH_FAILED if the tag does not match. + * \return A cipher-specific error code on calculation failure. + */ +int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len ); + +/** + * \brief This function performs a CCM* authenticated decryption of a + * buffer. + * + * \note When using this function in a variable tag length context, + * the tag length has to be decoded from \p iv and passed to + * this function as \p tag_len. (\p tag needs to be adjusted + * accordingly.) + * + * \param ctx The CCM context to use for decryption. This must be + * initialized and bound to a key. + * \param length The length of the input data in Bytes. + * \param iv The initialization vector (nonce). This must be a readable + * buffer of at least \p iv_len Bytes. + * \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12, + * or 13. The length L of the message length field is + * 15 - \p iv_len. + * \param add The additional data field. This must be a readable buffer of + * at least that \p add_len Bytes. + * \param add_len The length of additional data in Bytes. + * This must be less than 2^16 - 2^8. + * \param input The buffer holding the input data. If \p length is greater + * than zero, \p input must be a readable buffer of at least + * that length. + * \param output The buffer holding the output data. If \p length is greater + * than zero, \p output must be a writable buffer of at least + * that length. + * \param tag The buffer holding the authentication field. This must be a + * readable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the authentication field in Bytes. + * 0, 4, 6, 8, 10, 12, 14 or 16. + * + * \warning Passing \c 0 as \p tag_len means that the message is nos + * longer authenticated. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CCM_AUTH_FAILED if the tag does not match. + * \return A cipher-specific error code on calculation failure. + */ +int mbedtls_ccm_star_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len ); + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/** + * \brief The CCM checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_ccm_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CCM_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/certs.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/certs.h new file mode 100644 index 000000000..4caa20af7 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/certs.h @@ -0,0 +1,106 @@ +/** + * \file certs.h + * + * \brief Sample certificates and DHM parameters for testing + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CERTS_H +#define MBEDTLS_CERTS_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) +/* Concatenation of all CA certificates in PEM format if available */ +extern const char mbedtls_test_cas_pem[]; +extern const size_t mbedtls_test_cas_pem_len; +#endif + +/* List of all CA certificates, terminated by NULL */ +extern const char * mbedtls_test_cas[]; +extern const size_t mbedtls_test_cas_len[]; + +/* + * Convenience for users who just want a certificate: + * RSA by default, or ECDSA if RSA is not available + */ +extern const char * mbedtls_test_ca_crt; +extern const size_t mbedtls_test_ca_crt_len; +extern const char * mbedtls_test_ca_key; +extern const size_t mbedtls_test_ca_key_len; +extern const char * mbedtls_test_ca_pwd; +extern const size_t mbedtls_test_ca_pwd_len; +extern const char * mbedtls_test_srv_crt; +extern const size_t mbedtls_test_srv_crt_len; +extern const char * mbedtls_test_srv_key; +extern const size_t mbedtls_test_srv_key_len; +extern const char * mbedtls_test_cli_crt; +extern const size_t mbedtls_test_cli_crt_len; +extern const char * mbedtls_test_cli_key; +extern const size_t mbedtls_test_cli_key_len; + +#if defined(MBEDTLS_ECDSA_C) +extern const char mbedtls_test_ca_crt_ec[]; +extern const size_t mbedtls_test_ca_crt_ec_len; +extern const char mbedtls_test_ca_key_ec[]; +extern const size_t mbedtls_test_ca_key_ec_len; +extern const char mbedtls_test_ca_pwd_ec[]; +extern const size_t mbedtls_test_ca_pwd_ec_len; +extern const char mbedtls_test_srv_crt_ec[]; +extern const size_t mbedtls_test_srv_crt_ec_len; +extern const char mbedtls_test_srv_key_ec[]; +extern const size_t mbedtls_test_srv_key_ec_len; +extern const char mbedtls_test_cli_crt_ec[]; +extern const size_t mbedtls_test_cli_crt_ec_len; +extern const char mbedtls_test_cli_key_ec[]; +extern const size_t mbedtls_test_cli_key_ec_len; +#endif + +#if defined(MBEDTLS_RSA_C) +extern const char mbedtls_test_ca_crt_rsa[]; +extern const size_t mbedtls_test_ca_crt_rsa_len; +extern const char mbedtls_test_ca_key_rsa[]; +extern const size_t mbedtls_test_ca_key_rsa_len; +extern const char mbedtls_test_ca_pwd_rsa[]; +extern const size_t mbedtls_test_ca_pwd_rsa_len; +extern const char mbedtls_test_srv_crt_rsa[]; +extern const size_t mbedtls_test_srv_crt_rsa_len; +extern const char mbedtls_test_srv_key_rsa[]; +extern const size_t mbedtls_test_srv_key_rsa_len; +extern const char mbedtls_test_cli_crt_rsa[]; +extern const size_t mbedtls_test_cli_crt_rsa_len; +extern const char mbedtls_test_cli_key_rsa[]; +extern const size_t mbedtls_test_cli_key_rsa_len; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* certs.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/chacha20.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/chacha20.h new file mode 100644 index 000000000..d1a97cfc7 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/chacha20.h @@ -0,0 +1,226 @@ +/** + * \file chacha20.h + * + * \brief This file contains ChaCha20 definitions and functions. + * + * ChaCha20 is a stream cipher that can encrypt and decrypt + * information. ChaCha was created by Daniel Bernstein as a variant of + * its Salsa cipher https://cr.yp.to/chacha/chacha-20080128.pdf + * ChaCha20 is the variant with 20 rounds, that was also standardized + * in RFC 7539. + * + * \author Daniel King + */ + +/* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CHACHA20_H +#define MBEDTLS_CHACHA20_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA -0x0051 /**< Invalid input parameter(s). */ + +/* MBEDTLS_ERR_CHACHA20_FEATURE_UNAVAILABLE is deprecated and should not be + * used. */ +#define MBEDTLS_ERR_CHACHA20_FEATURE_UNAVAILABLE -0x0053 /**< Feature not available. For example, s part of the API is not implemented. */ + +/* MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED is deprecated and should not be used. + */ +#define MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED -0x0055 /**< Chacha20 hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_CHACHA20_ALT) + +typedef struct mbedtls_chacha20_context +{ + uint32_t state[16]; /*! The state (before round operations). */ + uint8_t keystream8[64]; /*! Leftover keystream bytes. */ + size_t keystream_bytes_used; /*! Number of keystream bytes already used. */ +} +mbedtls_chacha20_context; + +#else /* MBEDTLS_CHACHA20_ALT */ +#include "chacha20_alt.h" +#endif /* MBEDTLS_CHACHA20_ALT */ + +/** + * \brief This function initializes the specified ChaCha20 context. + * + * It must be the first API called before using + * the context. + * + * It is usually followed by calls to + * \c mbedtls_chacha20_setkey() and + * \c mbedtls_chacha20_starts(), then one or more calls to + * to \c mbedtls_chacha20_update(), and finally to + * \c mbedtls_chacha20_free(). + * + * \param ctx The ChaCha20 context to initialize. + * This must not be \c NULL. + */ +void mbedtls_chacha20_init( mbedtls_chacha20_context *ctx ); + +/** + * \brief This function releases and clears the specified + * ChaCha20 context. + * + * \param ctx The ChaCha20 context to clear. This may be \c NULL, + * in which case this function is a no-op. If it is not + * \c NULL, it must point to an initialized context. + * + */ +void mbedtls_chacha20_free( mbedtls_chacha20_context *ctx ); + +/** + * \brief This function sets the encryption/decryption key. + * + * \note After using this function, you must also call + * \c mbedtls_chacha20_starts() to set a nonce before you + * start encrypting/decrypting data with + * \c mbedtls_chacha_update(). + * + * \param ctx The ChaCha20 context to which the key should be bound. + * It must be initialized. + * \param key The encryption/decryption key. This must be \c 32 Bytes + * in length. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA if ctx or key is NULL. + */ +int mbedtls_chacha20_setkey( mbedtls_chacha20_context *ctx, + const unsigned char key[32] ); + +/** + * \brief This function sets the nonce and initial counter value. + * + * \note A ChaCha20 context can be re-used with the same key by + * calling this function to change the nonce. + * + * \warning You must never use the same nonce twice with the same key. + * This would void any confidentiality guarantees for the + * messages encrypted with the same nonce and key. + * + * \param ctx The ChaCha20 context to which the nonce should be bound. + * It must be initialized and bound to a key. + * \param nonce The nonce. This must be \c 12 Bytes in size. + * \param counter The initial counter value. This is usually \c 0. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA if ctx or nonce is + * NULL. + */ +int mbedtls_chacha20_starts( mbedtls_chacha20_context* ctx, + const unsigned char nonce[12], + uint32_t counter ); + +/** + * \brief This function encrypts or decrypts data. + * + * Since ChaCha20 is a stream cipher, the same operation is + * used for encrypting and decrypting data. + * + * \note The \p input and \p output pointers must either be equal or + * point to non-overlapping buffers. + * + * \note \c mbedtls_chacha20_setkey() and + * \c mbedtls_chacha20_starts() must be called at least once + * to setup the context before this function can be called. + * + * \note This function can be called multiple times in a row in + * order to encrypt of decrypt data piecewise with the same + * key and nonce. + * + * \param ctx The ChaCha20 context to use for encryption or decryption. + * It must be initialized and bound to a key and nonce. + * \param size The length of the input data in Bytes. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `size == 0`. + * \param output The buffer holding the output data. + * This must be able to hold \p size Bytes. + * This pointer can be \c NULL if `size == 0`. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chacha20_update( mbedtls_chacha20_context *ctx, + size_t size, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function encrypts or decrypts data with ChaCha20 and + * the given key and nonce. + * + * Since ChaCha20 is a stream cipher, the same operation is + * used for encrypting and decrypting data. + * + * \warning You must never use the same (key, nonce) pair more than + * once. This would void any confidentiality guarantees for + * the messages encrypted with the same nonce and key. + * + * \note The \p input and \p output pointers must either be equal or + * point to non-overlapping buffers. + * + * \param key The encryption/decryption key. + * This must be \c 32 Bytes in length. + * \param nonce The nonce. This must be \c 12 Bytes in size. + * \param counter The initial counter value. This is usually \c 0. + * \param size The length of the input data in Bytes. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `size == 0`. + * \param output The buffer holding the output data. + * This must be able to hold \p size Bytes. + * This pointer can be \c NULL if `size == 0`. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chacha20_crypt( const unsigned char key[32], + const unsigned char nonce[12], + uint32_t counter, + size_t size, + const unsigned char* input, + unsigned char* output ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief The ChaCha20 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_chacha20_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CHACHA20_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/chachapoly.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/chachapoly.h new file mode 100644 index 000000000..39b1af03c --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/chachapoly.h @@ -0,0 +1,358 @@ +/** + * \file chachapoly.h + * + * \brief This file contains the AEAD-ChaCha20-Poly1305 definitions and + * functions. + * + * ChaCha20-Poly1305 is an algorithm for Authenticated Encryption + * with Associated Data (AEAD) that can be used to encrypt and + * authenticate data. It is based on ChaCha20 and Poly1305 by Daniel + * Bernstein and was standardized in RFC 7539. + * + * \author Daniel King + */ + +/* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CHACHAPOLY_H +#define MBEDTLS_CHACHAPOLY_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/* for shared error codes */ +#include "poly1305.h" + +#define MBEDTLS_ERR_CHACHAPOLY_BAD_STATE -0x0054 /**< The requested operation is not permitted in the current state. */ +#define MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED -0x0056 /**< Authenticated decryption failed: data was not authentic. */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + MBEDTLS_CHACHAPOLY_ENCRYPT, /**< The mode value for performing encryption. */ + MBEDTLS_CHACHAPOLY_DECRYPT /**< The mode value for performing decryption. */ +} +mbedtls_chachapoly_mode_t; + +#if !defined(MBEDTLS_CHACHAPOLY_ALT) + +#include "chacha20.h" + +typedef struct mbedtls_chachapoly_context +{ + mbedtls_chacha20_context chacha20_ctx; /**< The ChaCha20 context. */ + mbedtls_poly1305_context poly1305_ctx; /**< The Poly1305 context. */ + uint64_t aad_len; /**< The length (bytes) of the Additional Authenticated Data. */ + uint64_t ciphertext_len; /**< The length (bytes) of the ciphertext. */ + int state; /**< The current state of the context. */ + mbedtls_chachapoly_mode_t mode; /**< Cipher mode (encrypt or decrypt). */ +} +mbedtls_chachapoly_context; + +#else /* !MBEDTLS_CHACHAPOLY_ALT */ +#include "chachapoly_alt.h" +#endif /* !MBEDTLS_CHACHAPOLY_ALT */ + +/** + * \brief This function initializes the specified ChaCha20-Poly1305 context. + * + * It must be the first API called before using + * the context. It must be followed by a call to + * \c mbedtls_chachapoly_setkey() before any operation can be + * done, and to \c mbedtls_chachapoly_free() once all + * operations with that context have been finished. + * + * In order to encrypt or decrypt full messages at once, for + * each message you should make a single call to + * \c mbedtls_chachapoly_crypt_and_tag() or + * \c mbedtls_chachapoly_auth_decrypt(). + * + * In order to encrypt messages piecewise, for each + * message you should make a call to + * \c mbedtls_chachapoly_starts(), then 0 or more calls to + * \c mbedtls_chachapoly_update_aad(), then 0 or more calls to + * \c mbedtls_chachapoly_update(), then one call to + * \c mbedtls_chachapoly_finish(). + * + * \warning Decryption with the piecewise API is discouraged! Always + * use \c mbedtls_chachapoly_auth_decrypt() when possible! + * + * If however this is not possible because the data is too + * large to fit in memory, you need to: + * + * - call \c mbedtls_chachapoly_starts() and (if needed) + * \c mbedtls_chachapoly_update_aad() as above, + * - call \c mbedtls_chachapoly_update() multiple times and + * ensure its output (the plaintext) is NOT used in any other + * way than placing it in temporary storage at this point, + * - call \c mbedtls_chachapoly_finish() to compute the + * authentication tag and compared it in constant time to the + * tag received with the ciphertext. + * + * If the tags are not equal, you must immediately discard + * all previous outputs of \c mbedtls_chachapoly_update(), + * otherwise you can now safely use the plaintext. + * + * \param ctx The ChachaPoly context to initialize. Must not be \c NULL. + */ +void mbedtls_chachapoly_init( mbedtls_chachapoly_context *ctx ); + +/** + * \brief This function releases and clears the specified + * ChaCha20-Poly1305 context. + * + * \param ctx The ChachaPoly context to clear. This may be \c NULL, in which + * case this function is a no-op. + */ +void mbedtls_chachapoly_free( mbedtls_chachapoly_context *ctx ); + +/** + * \brief This function sets the ChaCha20-Poly1305 + * symmetric encryption key. + * + * \param ctx The ChaCha20-Poly1305 context to which the key should be + * bound. This must be initialized. + * \param key The \c 256 Bit (\c 32 Bytes) key. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chachapoly_setkey( mbedtls_chachapoly_context *ctx, + const unsigned char key[32] ); + +/** + * \brief This function starts a ChaCha20-Poly1305 encryption or + * decryption operation. + * + * \warning You must never use the same nonce twice with the same key. + * This would void any confidentiality and authenticity + * guarantees for the messages encrypted with the same nonce + * and key. + * + * \note If the context is being used for AAD only (no data to + * encrypt or decrypt) then \p mode can be set to any value. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \param ctx The ChaCha20-Poly1305 context. This must be initialized + * and bound to a key. + * \param nonce The nonce/IV to use for the message. + * This must be a redable buffer of length \c 12 Bytes. + * \param mode The operation to perform: #MBEDTLS_CHACHAPOLY_ENCRYPT or + * #MBEDTLS_CHACHAPOLY_DECRYPT (discouraged, see warning). + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chachapoly_starts( mbedtls_chachapoly_context *ctx, + const unsigned char nonce[12], + mbedtls_chachapoly_mode_t mode ); + +/** + * \brief This function feeds additional data to be authenticated + * into an ongoing ChaCha20-Poly1305 operation. + * + * The Additional Authenticated Data (AAD), also called + * Associated Data (AD) is only authenticated but not + * encrypted nor included in the encrypted output. It is + * usually transmitted separately from the ciphertext or + * computed locally by each party. + * + * \note This function is called before data is encrypted/decrypted. + * I.e. call this function to process the AAD before calling + * \c mbedtls_chachapoly_update(). + * + * You may call this function multiple times to process + * an arbitrary amount of AAD. It is permitted to call + * this function 0 times, if no AAD is used. + * + * This function cannot be called any more if data has + * been processed by \c mbedtls_chachapoly_update(), + * or if the context has been finished. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \param ctx The ChaCha20-Poly1305 context. This must be initialized + * and bound to a key. + * \param aad_len The length in Bytes of the AAD. The length has no + * restrictions. + * \param aad Buffer containing the AAD. + * This pointer can be \c NULL if `aad_len == 0`. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA + * if \p ctx or \p aad are NULL. + * \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE + * if the operations has not been started or has been + * finished, or if the AAD has been finished. + */ +int mbedtls_chachapoly_update_aad( mbedtls_chachapoly_context *ctx, + const unsigned char *aad, + size_t aad_len ); + +/** + * \brief Thus function feeds data to be encrypted or decrypted + * into an on-going ChaCha20-Poly1305 + * operation. + * + * The direction (encryption or decryption) depends on the + * mode that was given when calling + * \c mbedtls_chachapoly_starts(). + * + * You may call this function multiple times to process + * an arbitrary amount of data. It is permitted to call + * this function 0 times, if no data is to be encrypted + * or decrypted. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \param ctx The ChaCha20-Poly1305 context to use. This must be initialized. + * \param len The length (in bytes) of the data to encrypt or decrypt. + * \param input The buffer containing the data to encrypt or decrypt. + * This pointer can be \c NULL if `len == 0`. + * \param output The buffer to where the encrypted or decrypted data is + * written. This must be able to hold \p len bytes. + * This pointer can be \c NULL if `len == 0`. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE + * if the operation has not been started or has been + * finished. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_chachapoly_update( mbedtls_chachapoly_context *ctx, + size_t len, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function finished the ChaCha20-Poly1305 operation and + * generates the MAC (authentication tag). + * + * \param ctx The ChaCha20-Poly1305 context to use. This must be initialized. + * \param mac The buffer to where the 128-bit (16 bytes) MAC is written. + * + * \warning Decryption with the piecewise API is discouraged, see the + * warning on \c mbedtls_chachapoly_init(). + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHAPOLY_BAD_STATE + * if the operation has not been started or has been + * finished. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx, + unsigned char mac[16] ); + +/** + * \brief This function performs a complete ChaCha20-Poly1305 + * authenticated encryption with the previously-set key. + * + * \note Before using this function, you must set the key with + * \c mbedtls_chachapoly_setkey(). + * + * \warning You must never use the same nonce twice with the same key. + * This would void any confidentiality and authenticity + * guarantees for the messages encrypted with the same nonce + * and key. + * + * \param ctx The ChaCha20-Poly1305 context to use (holds the key). + * This must be initialized. + * \param length The length (in bytes) of the data to encrypt or decrypt. + * \param nonce The 96-bit (12 bytes) nonce/IV to use. + * \param aad The buffer containing the additional authenticated + * data (AAD). This pointer can be \c NULL if `aad_len == 0`. + * \param aad_len The length (in bytes) of the AAD data to process. + * \param input The buffer containing the data to encrypt or decrypt. + * This pointer can be \c NULL if `ilen == 0`. + * \param output The buffer to where the encrypted or decrypted data + * is written. This pointer can be \c NULL if `ilen == 0`. + * \param tag The buffer to where the computed 128-bit (16 bytes) MAC + * is written. This must not be \c NULL. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_chachapoly_encrypt_and_tag( mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char *input, + unsigned char *output, + unsigned char tag[16] ); + +/** + * \brief This function performs a complete ChaCha20-Poly1305 + * authenticated decryption with the previously-set key. + * + * \note Before using this function, you must set the key with + * \c mbedtls_chachapoly_setkey(). + * + * \param ctx The ChaCha20-Poly1305 context to use (holds the key). + * \param length The length (in Bytes) of the data to decrypt. + * \param nonce The \c 96 Bit (\c 12 bytes) nonce/IV to use. + * \param aad The buffer containing the additional authenticated data (AAD). + * This pointer can be \c NULL if `aad_len == 0`. + * \param aad_len The length (in bytes) of the AAD data to process. + * \param tag The buffer holding the authentication tag. + * This must be a readable buffer of length \c 16 Bytes. + * \param input The buffer containing the data to decrypt. + * This pointer can be \c NULL if `ilen == 0`. + * \param output The buffer to where the decrypted data is written. + * This pointer can be \c NULL if `ilen == 0`. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED + * if the data was not authentic. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_chachapoly_auth_decrypt( mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char tag[16], + const unsigned char *input, + unsigned char *output ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief The ChaCha20-Poly1305 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_chachapoly_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CHACHAPOLY_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/check_config.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/check_config.h new file mode 100644 index 000000000..0d2d9967b --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/check_config.h @@ -0,0 +1,769 @@ +/** + * \file check_config.h + * + * \brief Consistency checks for configuration options + */ +/* + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * It is recommended to include this file from your config.h + * in order to catch dependency issues early. + */ + +#ifndef MBEDTLS_CHECK_CONFIG_H +#define MBEDTLS_CHECK_CONFIG_H + +/* + * We assume CHAR_BIT is 8 in many places. In practice, this is true on our + * target platforms, so not an issue, but let's just be extra sure. + */ +#include +#if CHAR_BIT != 8 +#error "mbed TLS requires a platform with 8-bit chars" +#endif + +#if defined(_WIN32) +#if !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_C is required on Windows" +#endif + +/* Fix the config here. Not convenient to put an #ifdef _WIN32 in config.h as + * it would confuse config.pl. */ +#if !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && \ + !defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) +#define MBEDTLS_PLATFORM_SNPRINTF_ALT +#endif + +#if !defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT) && \ + !defined(MBEDTLS_PLATFORM_VSNPRINTF_MACRO) +#define MBEDTLS_PLATFORM_VSNPRINTF_ALT +#endif +#endif /* _WIN32 */ + +#if defined(TARGET_LIKE_MBED) && \ + ( defined(MBEDTLS_NET_C) || defined(MBEDTLS_TIMING_C) ) +#error "The NET and TIMING modules are not available for mbed OS - please use the network and timing functions provided by mbed OS" +#endif + +#if defined(MBEDTLS_DEPRECATED_WARNING) && \ + !defined(__GNUC__) && !defined(__clang__) +#error "MBEDTLS_DEPRECATED_WARNING only works with GCC and Clang" +#endif + +#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_HAVE_TIME) +#error "MBEDTLS_HAVE_TIME_DATE without MBEDTLS_HAVE_TIME does not make sense" +#endif + +#if defined(MBEDTLS_AESNI_C) && !defined(MBEDTLS_HAVE_ASM) +#error "MBEDTLS_AESNI_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_AES_C) +#error "MBEDTLS_CTR_DRBG_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_DHM_C) && !defined(MBEDTLS_BIGNUM_C) +#error "MBEDTLS_DHM_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT) && !defined(MBEDTLS_SSL_TRUNCATED_HMAC) +#error "MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_CMAC_C) && \ + !defined(MBEDTLS_AES_C) && !defined(MBEDTLS_DES_C) +#error "MBEDTLS_CMAC_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_NIST_KW_C) && \ + ( !defined(MBEDTLS_AES_C) || !defined(MBEDTLS_CIPHER_C) ) +#error "MBEDTLS_NIST_KW_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECDH_C) && !defined(MBEDTLS_ECP_C) +#error "MBEDTLS_ECDH_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECDSA_C) && \ + ( !defined(MBEDTLS_ECP_C) || \ + !defined(MBEDTLS_ASN1_PARSE_C) || \ + !defined(MBEDTLS_ASN1_WRITE_C) ) +#error "MBEDTLS_ECDSA_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECJPAKE_C) && \ + ( !defined(MBEDTLS_ECP_C) || !defined(MBEDTLS_MD_C) ) +#error "MBEDTLS_ECJPAKE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + ( defined(MBEDTLS_USE_PSA_CRYPTO) || \ + defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) || \ + defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT) || \ + defined(MBEDTLS_ECDSA_SIGN_ALT) || \ + defined(MBEDTLS_ECDSA_VERIFY_ALT) || \ + defined(MBEDTLS_ECDSA_GENKEY_ALT) || \ + defined(MBEDTLS_ECP_INTERNAL_ALT) || \ + defined(MBEDTLS_ECP_ALT) ) +#error "MBEDTLS_ECP_RESTARTABLE defined, but it cannot coexist with an alternative or PSA-based ECP implementation" +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + ! defined(MBEDTLS_ECDH_LEGACY_CONTEXT) +#error "MBEDTLS_ECP_RESTARTABLE defined, but not MBEDTLS_ECDH_LEGACY_CONTEXT" +#endif + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) && !defined(MBEDTLS_HMAC_DRBG_C) +#error "MBEDTLS_ECDSA_DETERMINISTIC defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_C) && ( !defined(MBEDTLS_BIGNUM_C) || ( \ + !defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) ) ) +#error "MBEDTLS_ECP_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_PARSE_C) && !defined(MBEDTLS_ASN1_PARSE_C) +#error "MBEDTLS_PK_PARSE_C defined, but not all prerequesites" +#endif + +#if defined(MBEDTLS_ENTROPY_C) && (!defined(MBEDTLS_SHA512_C) && \ + !defined(MBEDTLS_SHA256_C)) +#error "MBEDTLS_ENTROPY_C defined, but not all prerequisites" +#endif +#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_SHA512_C) && \ + defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 64) +#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high" +#endif +#if defined(MBEDTLS_ENTROPY_C) && \ + ( !defined(MBEDTLS_SHA512_C) || defined(MBEDTLS_ENTROPY_FORCE_SHA256) ) \ + && defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 32) +#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high" +#endif +#if defined(MBEDTLS_ENTROPY_C) && \ + defined(MBEDTLS_ENTROPY_FORCE_SHA256) && !defined(MBEDTLS_SHA256_C) +#error "MBEDTLS_ENTROPY_FORCE_SHA256 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_TEST_NULL_ENTROPY) && \ + ( !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) ) +#error "MBEDTLS_TEST_NULL_ENTROPY defined, but not all prerequisites" +#endif +#if defined(MBEDTLS_TEST_NULL_ENTROPY) && \ + ( defined(MBEDTLS_ENTROPY_NV_SEED) || defined(MBEDTLS_ENTROPY_HARDWARE_ALT) || \ + defined(MBEDTLS_HAVEGE_C) ) +#error "MBEDTLS_TEST_NULL_ENTROPY defined, but entropy sources too" +#endif + +#if defined(MBEDTLS_GCM_C) && ( \ + !defined(MBEDTLS_AES_C) && !defined(MBEDTLS_CAMELLIA_C) ) +#error "MBEDTLS_GCM_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_RANDOMIZE_JAC_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_ADD_MIXED_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_DOUBLE_JAC_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_NORMALIZE_JAC_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_RANDOMIZE_MXZ_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_NORMALIZE_MXZ_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_HAVEGE_C) && !defined(MBEDTLS_TIMING_C) +#error "MBEDTLS_HAVEGE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_HKDF_C) && !defined(MBEDTLS_MD_C) +#error "MBEDTLS_HKDF_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_HMAC_DRBG_C) && !defined(MBEDTLS_MD_C) +#error "MBEDTLS_HMAC_DRBG_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) && !defined(MBEDTLS_DHM_C) +#error "MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) && \ + !defined(MBEDTLS_ECDH_C) +#error "MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ + ( !defined(MBEDTLS_DHM_C) || !defined(MBEDTLS_RSA_C) || \ + !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_RSA_C) || \ + !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_ECDSA_C) || \ + !defined(MBEDTLS_X509_CRT_PARSE_C) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) && \ + ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \ + !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \ + !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \ + ( !defined(MBEDTLS_ECJPAKE_C) || !defined(MBEDTLS_SHA256_C) || \ + !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) ) +#error "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) && \ + !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) && \ + ( !defined(MBEDTLS_SHA256_C) && \ + !defined(MBEDTLS_SHA512_C) && \ + !defined(MBEDTLS_SHA1_C) ) +#error "!MBEDTLS_SSL_KEEP_PEER_CERTIFICATE requires MBEDTLS_SHA512_C, MBEDTLS_SHA256_C or MBEDTLS_SHA1_C" +#endif + +#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && \ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PADLOCK_C) && !defined(MBEDTLS_HAVE_ASM) +#error "MBEDTLS_PADLOCK_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) && !defined(MBEDTLS_BASE64_C) +#error "MBEDTLS_PEM_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PEM_WRITE_C) && !defined(MBEDTLS_BASE64_C) +#error "MBEDTLS_PEM_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_C) && \ + ( !defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_ECP_C) ) +#error "MBEDTLS_PK_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_PARSE_C) && !defined(MBEDTLS_PK_C) +#error "MBEDTLS_PK_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_WRITE_C) && !defined(MBEDTLS_PK_C) +#error "MBEDTLS_PK_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PKCS11_C) && !defined(MBEDTLS_PK_C) +#error "MBEDTLS_PKCS11_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_EXIT_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_EXIT_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_EXIT) ||\ + defined(MBEDTLS_PLATFORM_EXIT_ALT) ) +#error "MBEDTLS_PLATFORM_EXIT_MACRO and MBEDTLS_PLATFORM_STD_EXIT/MBEDTLS_PLATFORM_EXIT_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_ALT) &&\ + ( !defined(MBEDTLS_PLATFORM_C) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_TIME_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_TIME_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_TIME) ||\ + defined(MBEDTLS_PLATFORM_TIME_ALT) ) +#error "MBEDTLS_PLATFORM_TIME_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_TIME) ||\ + defined(MBEDTLS_PLATFORM_TIME_ALT) ) +#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_FPRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_FPRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_FPRINTF) ||\ + defined(MBEDTLS_PLATFORM_FPRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_FPRINTF_MACRO and MBEDTLS_PLATFORM_STD_FPRINTF/MBEDTLS_PLATFORM_FPRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_PLATFORM_FREE_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\ + defined(MBEDTLS_PLATFORM_STD_FREE) +#error "MBEDTLS_PLATFORM_FREE_MACRO and MBEDTLS_PLATFORM_STD_FREE cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && !defined(MBEDTLS_PLATFORM_CALLOC_MACRO) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO must be defined if MBEDTLS_PLATFORM_FREE_MACRO is" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\ + defined(MBEDTLS_PLATFORM_STD_CALLOC) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_STD_CALLOC cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && !defined(MBEDTLS_PLATFORM_FREE_MACRO) +#error "MBEDTLS_PLATFORM_FREE_MACRO must be defined if MBEDTLS_PLATFORM_CALLOC_MACRO is" +#endif + +#if defined(MBEDTLS_PLATFORM_MEMORY) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_MEMORY defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_PRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_PRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_PRINTF) ||\ + defined(MBEDTLS_PLATFORM_PRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_PRINTF_MACRO and MBEDTLS_PLATFORM_STD_PRINTF/MBEDTLS_PLATFORM_PRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_SNPRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_SNPRINTF) ||\ + defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_SNPRINTF/MBEDTLS_PLATFORM_SNPRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) &&\ + !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) +#error "MBEDTLS_PLATFORM_STD_MEM_HDR defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY) +#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY) +#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_FREE) && !defined(MBEDTLS_PLATFORM_MEMORY) +#error "MBEDTLS_PLATFORM_STD_FREE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_EXIT) &&\ + !defined(MBEDTLS_PLATFORM_EXIT_ALT) +#error "MBEDTLS_PLATFORM_STD_EXIT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_TIME) &&\ + ( !defined(MBEDTLS_PLATFORM_TIME_ALT) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_STD_TIME defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_FPRINTF) &&\ + !defined(MBEDTLS_PLATFORM_FPRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_FPRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_PRINTF) &&\ + !defined(MBEDTLS_PLATFORM_PRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_PRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_SNPRINTF) &&\ + !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_SNPRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ENTROPY_NV_SEED) &&\ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_ENTROPY_C) ) +#error "MBEDTLS_ENTROPY_NV_SEED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) &&\ + !defined(MBEDTLS_ENTROPY_NV_SEED) +#error "MBEDTLS_PLATFORM_NV_SEED_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) &&\ + !defined(MBEDTLS_PLATFORM_NV_SEED_ALT) +#error "MBEDTLS_PLATFORM_STD_NV_SEED_READ defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) &&\ + !defined(MBEDTLS_PLATFORM_NV_SEED_ALT) +#error "MBEDTLS_PLATFORM_STD_NV_SEED_WRITE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) ||\ + defined(MBEDTLS_PLATFORM_NV_SEED_ALT) ) +#error "MBEDTLS_PLATFORM_NV_SEED_READ_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_READ cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) ||\ + defined(MBEDTLS_PLATFORM_NV_SEED_ALT) ) +#error "MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_WRITE cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_C) && \ + !( defined(MBEDTLS_CTR_DRBG_C) && \ + defined(MBEDTLS_ENTROPY_C) ) +#error "MBEDTLS_PSA_CRYPTO_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_SPM) && !defined(MBEDTLS_PSA_CRYPTO_C) +#error "MBEDTLS_PSA_CRYPTO_SPM defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) && \ + ! defined(MBEDTLS_PSA_CRYPTO_C) +#error "MBEDTLS_PSA_CRYPTO_STORAGE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PSA_INJECT_ENTROPY) && \ + !( defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) && \ + defined(MBEDTLS_ENTROPY_NV_SEED) ) +#error "MBEDTLS_PSA_INJECT_ENTROPY defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PSA_INJECT_ENTROPY) && \ + !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) +#error "MBEDTLS_PSA_INJECT_ENTROPY is not compatible with actual entropy sources" +#endif + +#if defined(MBEDTLS_PSA_ITS_FILE_C) && \ + !defined(MBEDTLS_FS_IO) +#error "MBEDTLS_PSA_ITS_FILE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_BIGNUM_C) || \ + !defined(MBEDTLS_OID_C) ) +#error "MBEDTLS_RSA_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_PKCS1_V21) && \ + !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_RSA_C defined, but none of the PKCS1 versions enabled" +#endif + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) && \ + ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_PKCS1_V21) ) +#error "MBEDTLS_X509_RSASSA_PSS_SUPPORT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_SSL3) && ( !defined(MBEDTLS_MD5_C) || \ + !defined(MBEDTLS_SHA1_C) ) +#error "MBEDTLS_SSL_PROTO_SSL3 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1) && ( !defined(MBEDTLS_MD5_C) || \ + !defined(MBEDTLS_SHA1_C) ) +#error "MBEDTLS_SSL_PROTO_TLS1 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) && ( !defined(MBEDTLS_MD5_C) || \ + !defined(MBEDTLS_SHA1_C) ) +#error "MBEDTLS_SSL_PROTO_TLS1_1 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && ( !defined(MBEDTLS_SHA1_C) && \ + !defined(MBEDTLS_SHA256_C) && !defined(MBEDTLS_SHA512_C) ) +#error "MBEDTLS_SSL_PROTO_TLS1_2 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2) +#error "MBEDTLS_SSL_PROTO_DTLS defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_CLI_C) && !defined(MBEDTLS_SSL_TLS_C) +#error "MBEDTLS_SSL_CLI_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && ( !defined(MBEDTLS_CIPHER_C) || \ + !defined(MBEDTLS_MD_C) ) +#error "MBEDTLS_SSL_TLS_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_SRV_C) && !defined(MBEDTLS_SSL_TLS_C) +#error "MBEDTLS_SSL_SRV_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (!defined(MBEDTLS_SSL_PROTO_SSL3) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1) && !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2)) +#error "MBEDTLS_SSL_TLS_C defined, but no protocols are active" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) && !defined(MBEDTLS_SSL_PROTO_TLS1)) +#error "Illegal protocol selection" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_TLS1) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) && !defined(MBEDTLS_SSL_PROTO_TLS1_1)) +#error "Illegal protocol selection" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) && (!defined(MBEDTLS_SSL_PROTO_TLS1) || \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1))) +#error "Illegal protocol selection" +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && !defined(MBEDTLS_SSL_PROTO_DTLS) +#error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && \ + !defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) +#error "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) && \ + ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) ) +#error "MBEDTLS_SSL_DTLS_ANTI_REPLAY defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) && \ + ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) ) +#error "MBEDTLS_SSL_DTLS_CONNECTION_ID defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) && \ + defined(MBEDTLS_SSL_CID_IN_LEN_MAX) && \ + MBEDTLS_SSL_CID_IN_LEN_MAX > 255 +#error "MBEDTLS_SSL_CID_IN_LEN_MAX too large (max 255)" +#endif + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) && \ + defined(MBEDTLS_SSL_CID_OUT_LEN_MAX) && \ + MBEDTLS_SSL_CID_OUT_LEN_MAX > 255 +#error "MBEDTLS_SSL_CID_OUT_LEN_MAX too large (max 255)" +#endif + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) && \ + ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) ) +#error "MBEDTLS_SSL_DTLS_BADMAC_LIMIT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2) +#error "MBEDTLS_SSL_ENCRYPT_THEN_MAC defined, but not all prerequsites" +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2) +#error "MBEDTLS_SSL_EXTENDED_MASTER_SECRET defined, but not all prerequsites" +#endif + +#if defined(MBEDTLS_SSL_TICKET_C) && !defined(MBEDTLS_CIPHER_C) +#error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) && \ + !defined(MBEDTLS_SSL_PROTO_SSL3) && !defined(MBEDTLS_SSL_PROTO_TLS1) +#error "MBEDTLS_SSL_CBC_RECORD_SPLITTING defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && \ + !defined(MBEDTLS_X509_CRT_PARSE_C) +#error "MBEDTLS_SSL_SERVER_NAME_INDICATION defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_THREADING_PTHREAD) +#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_PTHREAD defined, but not all prerequisites" +#endif +#define MBEDTLS_THREADING_IMPL +#endif + +#if defined(MBEDTLS_THREADING_ALT) +#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_ALT defined, but not all prerequisites" +#endif +#define MBEDTLS_THREADING_IMPL +#endif + +#if defined(MBEDTLS_THREADING_C) && !defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_C defined, single threading implementation required" +#endif +#undef MBEDTLS_THREADING_IMPL + +#if defined(MBEDTLS_USE_PSA_CRYPTO) && !defined(MBEDTLS_PSA_CRYPTO_C) +#error "MBEDTLS_USE_PSA_CRYPTO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_VERSION_FEATURES) && !defined(MBEDTLS_VERSION_C) +#error "MBEDTLS_VERSION_FEATURES defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_USE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \ + !defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_PARSE_C) || \ + !defined(MBEDTLS_PK_PARSE_C) ) +#error "MBEDTLS_X509_USE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CREATE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \ + !defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_WRITE_C) || \ + !defined(MBEDTLS_PK_WRITE_C) ) +#error "MBEDTLS_X509_CREATE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) ) +#error "MBEDTLS_X509_CRT_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CRL_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) ) +#error "MBEDTLS_X509_CRL_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CSR_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) ) +#error "MBEDTLS_X509_CSR_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CRT_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) ) +#error "MBEDTLS_X509_CRT_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CSR_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) ) +#error "MBEDTLS_X509_CSR_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_HAVE_INT32) && defined(MBEDTLS_HAVE_INT64) +#error "MBEDTLS_HAVE_INT32 and MBEDTLS_HAVE_INT64 cannot be defined simultaneously" +#endif /* MBEDTLS_HAVE_INT32 && MBEDTLS_HAVE_INT64 */ + +#if ( defined(MBEDTLS_HAVE_INT32) || defined(MBEDTLS_HAVE_INT64) ) && \ + defined(MBEDTLS_HAVE_ASM) +#error "MBEDTLS_HAVE_INT32/MBEDTLS_HAVE_INT64 and MBEDTLS_HAVE_ASM cannot be defined simultaneously" +#endif /* (MBEDTLS_HAVE_INT32 || MBEDTLS_HAVE_INT64) && MBEDTLS_HAVE_ASM */ + +/* + * Avoid warning from -pedantic. This is a convenient place for this + * workaround since this is included by every single file before the + * #if defined(MBEDTLS_xxx_C) that results in empty translation units. + */ +typedef int mbedtls_iso_c_forbids_empty_translation_units; + +#endif /* MBEDTLS_CHECK_CONFIG_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/cipher.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/cipher.h new file mode 100644 index 000000000..f878a53ec --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/cipher.h @@ -0,0 +1,926 @@ +/** + * \file cipher.h + * + * \brief This file contains an abstraction interface for use with the cipher + * primitives provided by the library. It provides a common interface to all of + * the available cipher operations. + * + * \author Adriaan de Jong + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CIPHER_H +#define MBEDTLS_CIPHER_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include "platform_util.h" + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +#define MBEDTLS_CIPHER_MODE_AEAD +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#define MBEDTLS_CIPHER_MODE_WITH_PADDING +#endif + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) || \ + defined(MBEDTLS_CHACHA20_C) +#define MBEDTLS_CIPHER_MODE_STREAM +#endif + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#define MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE -0x6080 /**< The selected feature is not available. */ +#define MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA -0x6100 /**< Bad input parameters. */ +#define MBEDTLS_ERR_CIPHER_ALLOC_FAILED -0x6180 /**< Failed to allocate memory. */ +#define MBEDTLS_ERR_CIPHER_INVALID_PADDING -0x6200 /**< Input data contains invalid padding and is rejected. */ +#define MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED -0x6280 /**< Decryption of block requires a full block. */ +#define MBEDTLS_ERR_CIPHER_AUTH_FAILED -0x6300 /**< Authentication failed (for AEAD modes). */ +#define MBEDTLS_ERR_CIPHER_INVALID_CONTEXT -0x6380 /**< The context is invalid. For example, because it was freed. */ + +/* MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED -0x6400 /**< Cipher hardware accelerator failed. */ + +#define MBEDTLS_CIPHER_VARIABLE_IV_LEN 0x01 /**< Cipher accepts IVs of variable length. */ +#define MBEDTLS_CIPHER_VARIABLE_KEY_LEN 0x02 /**< Cipher accepts keys of variable length. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Supported cipher types. + * + * \warning RC4 and DES are considered weak ciphers and their use + * constitutes a security risk. Arm recommends considering stronger + * ciphers instead. + */ +typedef enum { + MBEDTLS_CIPHER_ID_NONE = 0, /**< Placeholder to mark the end of cipher ID lists. */ + MBEDTLS_CIPHER_ID_NULL, /**< The identity cipher, treated as a stream cipher. */ + MBEDTLS_CIPHER_ID_AES, /**< The AES cipher. */ + MBEDTLS_CIPHER_ID_DES, /**< The DES cipher. */ + MBEDTLS_CIPHER_ID_3DES, /**< The Triple DES cipher. */ + MBEDTLS_CIPHER_ID_CAMELLIA, /**< The Camellia cipher. */ + MBEDTLS_CIPHER_ID_BLOWFISH, /**< The Blowfish cipher. */ + MBEDTLS_CIPHER_ID_ARC4, /**< The RC4 cipher. */ + MBEDTLS_CIPHER_ID_ARIA, /**< The Aria cipher. */ + MBEDTLS_CIPHER_ID_CHACHA20, /**< The ChaCha20 cipher. */ +} mbedtls_cipher_id_t; + +/** + * \brief Supported {cipher type, cipher mode} pairs. + * + * \warning RC4 and DES are considered weak ciphers and their use + * constitutes a security risk. Arm recommends considering stronger + * ciphers instead. + */ +typedef enum { + MBEDTLS_CIPHER_NONE = 0, /**< Placeholder to mark the end of cipher-pair lists. */ + MBEDTLS_CIPHER_NULL, /**< The identity stream cipher. */ + MBEDTLS_CIPHER_AES_128_ECB, /**< AES cipher with 128-bit ECB mode. */ + MBEDTLS_CIPHER_AES_192_ECB, /**< AES cipher with 192-bit ECB mode. */ + MBEDTLS_CIPHER_AES_256_ECB, /**< AES cipher with 256-bit ECB mode. */ + MBEDTLS_CIPHER_AES_128_CBC, /**< AES cipher with 128-bit CBC mode. */ + MBEDTLS_CIPHER_AES_192_CBC, /**< AES cipher with 192-bit CBC mode. */ + MBEDTLS_CIPHER_AES_256_CBC, /**< AES cipher with 256-bit CBC mode. */ + MBEDTLS_CIPHER_AES_128_CFB128, /**< AES cipher with 128-bit CFB128 mode. */ + MBEDTLS_CIPHER_AES_192_CFB128, /**< AES cipher with 192-bit CFB128 mode. */ + MBEDTLS_CIPHER_AES_256_CFB128, /**< AES cipher with 256-bit CFB128 mode. */ + MBEDTLS_CIPHER_AES_128_CTR, /**< AES cipher with 128-bit CTR mode. */ + MBEDTLS_CIPHER_AES_192_CTR, /**< AES cipher with 192-bit CTR mode. */ + MBEDTLS_CIPHER_AES_256_CTR, /**< AES cipher with 256-bit CTR mode. */ + MBEDTLS_CIPHER_AES_128_GCM, /**< AES cipher with 128-bit GCM mode. */ + MBEDTLS_CIPHER_AES_192_GCM, /**< AES cipher with 192-bit GCM mode. */ + MBEDTLS_CIPHER_AES_256_GCM, /**< AES cipher with 256-bit GCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_ECB, /**< Camellia cipher with 128-bit ECB mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_ECB, /**< Camellia cipher with 192-bit ECB mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_ECB, /**< Camellia cipher with 256-bit ECB mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CBC, /**< Camellia cipher with 128-bit CBC mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CBC, /**< Camellia cipher with 192-bit CBC mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CBC, /**< Camellia cipher with 256-bit CBC mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CFB128, /**< Camellia cipher with 128-bit CFB128 mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CFB128, /**< Camellia cipher with 192-bit CFB128 mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CFB128, /**< Camellia cipher with 256-bit CFB128 mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CTR, /**< Camellia cipher with 128-bit CTR mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CTR, /**< Camellia cipher with 192-bit CTR mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CTR, /**< Camellia cipher with 256-bit CTR mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_GCM, /**< Camellia cipher with 128-bit GCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_GCM, /**< Camellia cipher with 192-bit GCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_GCM, /**< Camellia cipher with 256-bit GCM mode. */ + MBEDTLS_CIPHER_DES_ECB, /**< DES cipher with ECB mode. */ + MBEDTLS_CIPHER_DES_CBC, /**< DES cipher with CBC mode. */ + MBEDTLS_CIPHER_DES_EDE_ECB, /**< DES cipher with EDE ECB mode. */ + MBEDTLS_CIPHER_DES_EDE_CBC, /**< DES cipher with EDE CBC mode. */ + MBEDTLS_CIPHER_DES_EDE3_ECB, /**< DES cipher with EDE3 ECB mode. */ + MBEDTLS_CIPHER_DES_EDE3_CBC, /**< DES cipher with EDE3 CBC mode. */ + MBEDTLS_CIPHER_BLOWFISH_ECB, /**< Blowfish cipher with ECB mode. */ + MBEDTLS_CIPHER_BLOWFISH_CBC, /**< Blowfish cipher with CBC mode. */ + MBEDTLS_CIPHER_BLOWFISH_CFB64, /**< Blowfish cipher with CFB64 mode. */ + MBEDTLS_CIPHER_BLOWFISH_CTR, /**< Blowfish cipher with CTR mode. */ + MBEDTLS_CIPHER_ARC4_128, /**< RC4 cipher with 128-bit mode. */ + MBEDTLS_CIPHER_AES_128_CCM, /**< AES cipher with 128-bit CCM mode. */ + MBEDTLS_CIPHER_AES_192_CCM, /**< AES cipher with 192-bit CCM mode. */ + MBEDTLS_CIPHER_AES_256_CCM, /**< AES cipher with 256-bit CCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CCM, /**< Camellia cipher with 128-bit CCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CCM, /**< Camellia cipher with 192-bit CCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CCM, /**< Camellia cipher with 256-bit CCM mode. */ + MBEDTLS_CIPHER_ARIA_128_ECB, /**< Aria cipher with 128-bit key and ECB mode. */ + MBEDTLS_CIPHER_ARIA_192_ECB, /**< Aria cipher with 192-bit key and ECB mode. */ + MBEDTLS_CIPHER_ARIA_256_ECB, /**< Aria cipher with 256-bit key and ECB mode. */ + MBEDTLS_CIPHER_ARIA_128_CBC, /**< Aria cipher with 128-bit key and CBC mode. */ + MBEDTLS_CIPHER_ARIA_192_CBC, /**< Aria cipher with 192-bit key and CBC mode. */ + MBEDTLS_CIPHER_ARIA_256_CBC, /**< Aria cipher with 256-bit key and CBC mode. */ + MBEDTLS_CIPHER_ARIA_128_CFB128, /**< Aria cipher with 128-bit key and CFB-128 mode. */ + MBEDTLS_CIPHER_ARIA_192_CFB128, /**< Aria cipher with 192-bit key and CFB-128 mode. */ + MBEDTLS_CIPHER_ARIA_256_CFB128, /**< Aria cipher with 256-bit key and CFB-128 mode. */ + MBEDTLS_CIPHER_ARIA_128_CTR, /**< Aria cipher with 128-bit key and CTR mode. */ + MBEDTLS_CIPHER_ARIA_192_CTR, /**< Aria cipher with 192-bit key and CTR mode. */ + MBEDTLS_CIPHER_ARIA_256_CTR, /**< Aria cipher with 256-bit key and CTR mode. */ + MBEDTLS_CIPHER_ARIA_128_GCM, /**< Aria cipher with 128-bit key and GCM mode. */ + MBEDTLS_CIPHER_ARIA_192_GCM, /**< Aria cipher with 192-bit key and GCM mode. */ + MBEDTLS_CIPHER_ARIA_256_GCM, /**< Aria cipher with 256-bit key and GCM mode. */ + MBEDTLS_CIPHER_ARIA_128_CCM, /**< Aria cipher with 128-bit key and CCM mode. */ + MBEDTLS_CIPHER_ARIA_192_CCM, /**< Aria cipher with 192-bit key and CCM mode. */ + MBEDTLS_CIPHER_ARIA_256_CCM, /**< Aria cipher with 256-bit key and CCM mode. */ + MBEDTLS_CIPHER_AES_128_OFB, /**< AES 128-bit cipher in OFB mode. */ + MBEDTLS_CIPHER_AES_192_OFB, /**< AES 192-bit cipher in OFB mode. */ + MBEDTLS_CIPHER_AES_256_OFB, /**< AES 256-bit cipher in OFB mode. */ + MBEDTLS_CIPHER_AES_128_XTS, /**< AES 128-bit cipher in XTS block mode. */ + MBEDTLS_CIPHER_AES_256_XTS, /**< AES 256-bit cipher in XTS block mode. */ + MBEDTLS_CIPHER_CHACHA20, /**< ChaCha20 stream cipher. */ + MBEDTLS_CIPHER_CHACHA20_POLY1305, /**< ChaCha20-Poly1305 AEAD cipher. */ + MBEDTLS_CIPHER_AES_128_KW, /**< AES cipher with 128-bit NIST KW mode. */ + MBEDTLS_CIPHER_AES_192_KW, /**< AES cipher with 192-bit NIST KW mode. */ + MBEDTLS_CIPHER_AES_256_KW, /**< AES cipher with 256-bit NIST KW mode. */ + MBEDTLS_CIPHER_AES_128_KWP, /**< AES cipher with 128-bit NIST KWP mode. */ + MBEDTLS_CIPHER_AES_192_KWP, /**< AES cipher with 192-bit NIST KWP mode. */ + MBEDTLS_CIPHER_AES_256_KWP, /**< AES cipher with 256-bit NIST KWP mode. */ +} mbedtls_cipher_type_t; + +/** Supported cipher modes. */ +typedef enum { + MBEDTLS_MODE_NONE = 0, /**< None. */ + MBEDTLS_MODE_ECB, /**< The ECB cipher mode. */ + MBEDTLS_MODE_CBC, /**< The CBC cipher mode. */ + MBEDTLS_MODE_CFB, /**< The CFB cipher mode. */ + MBEDTLS_MODE_OFB, /**< The OFB cipher mode. */ + MBEDTLS_MODE_CTR, /**< The CTR cipher mode. */ + MBEDTLS_MODE_GCM, /**< The GCM cipher mode. */ + MBEDTLS_MODE_STREAM, /**< The stream cipher mode. */ + MBEDTLS_MODE_CCM, /**< The CCM cipher mode. */ + MBEDTLS_MODE_XTS, /**< The XTS cipher mode. */ + MBEDTLS_MODE_CHACHAPOLY, /**< The ChaCha-Poly cipher mode. */ + MBEDTLS_MODE_KW, /**< The SP800-38F KW mode */ + MBEDTLS_MODE_KWP, /**< The SP800-38F KWP mode */ +} mbedtls_cipher_mode_t; + +/** Supported cipher padding types. */ +typedef enum { + MBEDTLS_PADDING_PKCS7 = 0, /**< PKCS7 padding (default). */ + MBEDTLS_PADDING_ONE_AND_ZEROS, /**< ISO/IEC 7816-4 padding. */ + MBEDTLS_PADDING_ZEROS_AND_LEN, /**< ANSI X.923 padding. */ + MBEDTLS_PADDING_ZEROS, /**< Zero padding (not reversible). */ + MBEDTLS_PADDING_NONE, /**< Never pad (full blocks only). */ +} mbedtls_cipher_padding_t; + +/** Type of operation. */ +typedef enum { + MBEDTLS_OPERATION_NONE = -1, + MBEDTLS_DECRYPT = 0, + MBEDTLS_ENCRYPT, +} mbedtls_operation_t; + +enum { + /** Undefined key length. */ + MBEDTLS_KEY_LENGTH_NONE = 0, + /** Key length, in bits (including parity), for DES keys. */ + MBEDTLS_KEY_LENGTH_DES = 64, + /** Key length in bits, including parity, for DES in two-key EDE. */ + MBEDTLS_KEY_LENGTH_DES_EDE = 128, + /** Key length in bits, including parity, for DES in three-key EDE. */ + MBEDTLS_KEY_LENGTH_DES_EDE3 = 192, +}; + +/** Maximum length of any IV, in Bytes. */ +#define MBEDTLS_MAX_IV_LENGTH 16 +/** Maximum block size of any cipher, in Bytes. */ +#define MBEDTLS_MAX_BLOCK_LENGTH 16 + +/** + * Base cipher information (opaque struct). + */ +typedef struct mbedtls_cipher_base_t mbedtls_cipher_base_t; + +/** + * CMAC context (opaque struct). + */ +typedef struct mbedtls_cmac_context_t mbedtls_cmac_context_t; + +/** + * Cipher information. Allows calling cipher functions + * in a generic way. + */ +typedef struct mbedtls_cipher_info_t +{ + /** Full cipher identifier. For example, + * MBEDTLS_CIPHER_AES_256_CBC. + */ + mbedtls_cipher_type_t type; + + /** The cipher mode. For example, MBEDTLS_MODE_CBC. */ + mbedtls_cipher_mode_t mode; + + /** The cipher key length, in bits. This is the + * default length for variable sized ciphers. + * Includes parity bits for ciphers like DES. + */ + unsigned int key_bitlen; + + /** Name of the cipher. */ + const char * name; + + /** IV or nonce size, in Bytes. + * For ciphers that accept variable IV sizes, + * this is the recommended size. + */ + unsigned int iv_size; + + /** Bitflag comprised of MBEDTLS_CIPHER_VARIABLE_IV_LEN and + * MBEDTLS_CIPHER_VARIABLE_KEY_LEN indicating whether the + * cipher supports variable IV or variable key sizes, respectively. + */ + int flags; + + /** The block size, in Bytes. */ + unsigned int block_size; + + /** Struct for base cipher information and functions. */ + const mbedtls_cipher_base_t *base; + +} mbedtls_cipher_info_t; + +/** + * Generic cipher context. + */ +typedef struct mbedtls_cipher_context_t +{ + /** Information about the associated cipher. */ + const mbedtls_cipher_info_t *cipher_info; + + /** Key length to use. */ + int key_bitlen; + + /** Operation that the key of the context has been + * initialized for. + */ + mbedtls_operation_t operation; + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) + /** Padding functions to use, if relevant for + * the specific cipher mode. + */ + void (*add_padding)( unsigned char *output, size_t olen, size_t data_len ); + int (*get_padding)( unsigned char *input, size_t ilen, size_t *data_len ); +#endif + + /** Buffer for input that has not been processed yet. */ + unsigned char unprocessed_data[MBEDTLS_MAX_BLOCK_LENGTH]; + + /** Number of Bytes that have not been processed yet. */ + size_t unprocessed_len; + + /** Current IV or NONCE_COUNTER for CTR-mode, data unit (or sector) number + * for XTS-mode. */ + unsigned char iv[MBEDTLS_MAX_IV_LENGTH]; + + /** IV size in Bytes, for ciphers with variable-length IVs. */ + size_t iv_size; + + /** The cipher-specific context. */ + void *cipher_ctx; + +#if defined(MBEDTLS_CMAC_C) + /** CMAC-specific context. */ + mbedtls_cmac_context_t *cmac_ctx; +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + /** Indicates whether the cipher operations should be performed + * by Mbed TLS' own crypto library or an external implementation + * of the PSA Crypto API. + * This is unset if the cipher context was established through + * mbedtls_cipher_setup(), and set if it was established through + * mbedtls_cipher_setup_psa(). + */ + unsigned char psa_enabled; +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +} mbedtls_cipher_context_t; + +/** + * \brief This function retrieves the list of ciphers supported + * by the generic cipher module. + * + * For any cipher identifier in the returned list, you can + * obtain the corresponding generic cipher information structure + * via mbedtls_cipher_info_from_type(), which can then be used + * to prepare a cipher context via mbedtls_cipher_setup(). + * + * + * \return A statically-allocated array of cipher identifiers + * of type cipher_type_t. The last entry is zero. + */ +const int *mbedtls_cipher_list( void ); + +/** + * \brief This function retrieves the cipher-information + * structure associated with the given cipher name. + * + * \param cipher_name Name of the cipher to search for. This must not be + * \c NULL. + * + * \return The cipher information structure associated with the + * given \p cipher_name. + * \return \c NULL if the associated cipher information is not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name ); + +/** + * \brief This function retrieves the cipher-information + * structure associated with the given cipher type. + * + * \param cipher_type Type of the cipher to search for. + * + * \return The cipher information structure associated with the + * given \p cipher_type. + * \return \c NULL if the associated cipher information is not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type ); + +/** + * \brief This function retrieves the cipher-information + * structure associated with the given cipher ID, + * key size and mode. + * + * \param cipher_id The ID of the cipher to search for. For example, + * #MBEDTLS_CIPHER_ID_AES. + * \param key_bitlen The length of the key in bits. + * \param mode The cipher mode. For example, #MBEDTLS_MODE_CBC. + * + * \return The cipher information structure associated with the + * given \p cipher_id. + * \return \c NULL if the associated cipher information is not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id, + int key_bitlen, + const mbedtls_cipher_mode_t mode ); + +/** + * \brief This function initializes a \p cipher_context as NONE. + * + * \param ctx The context to be initialized. This must not be \c NULL. + */ +void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ); + +/** + * \brief This function frees and clears the cipher-specific + * context of \p ctx. Freeing \p ctx itself remains the + * responsibility of the caller. + * + * \param ctx The context to be freed. If this is \c NULL, the + * function has no effect, otherwise this must point to an + * initialized context. + */ +void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ); + + +/** + * \brief This function initializes a cipher context for + * use with the given cipher primitive. + * + * \param ctx The context to initialize. This must be initialized. + * \param cipher_info The cipher to use. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_ALLOC_FAILED if allocation of the + * cipher-specific context fails. + * + * \internal Currently, the function also clears the structure. + * In future versions, the caller will be required to call + * mbedtls_cipher_init() on the structure first. + */ +int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, + const mbedtls_cipher_info_t *cipher_info ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +/** + * \brief This function initializes a cipher context for + * PSA-based use with the given cipher primitive. + * + * \note See #MBEDTLS_USE_PSA_CRYPTO for information on PSA. + * + * \param ctx The context to initialize. May not be \c NULL. + * \param cipher_info The cipher to use. + * \param taglen For AEAD ciphers, the length in bytes of the + * authentication tag to use. Subsequent uses of + * mbedtls_cipher_auth_encrypt() or + * mbedtls_cipher_auth_decrypt() must provide + * the same tag length. + * For non-AEAD ciphers, the value must be \c 0. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_ALLOC_FAILED if allocation of the + * cipher-specific context fails. + */ +int mbedtls_cipher_setup_psa( mbedtls_cipher_context_t *ctx, + const mbedtls_cipher_info_t *cipher_info, + size_t taglen ); +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +/** + * \brief This function returns the block size of the given cipher. + * + * \param ctx The context of the cipher. This must be initialized. + * + * \return The block size of the underlying cipher. + * \return \c 0 if \p ctx has not been initialized. + */ +static inline unsigned int mbedtls_cipher_get_block_size( + const mbedtls_cipher_context_t *ctx ) +{ + MBEDTLS_INTERNAL_VALIDATE_RET( ctx != NULL, 0 ); + if( ctx->cipher_info == NULL ) + return 0; + + return ctx->cipher_info->block_size; +} + +/** + * \brief This function returns the mode of operation for + * the cipher. For example, MBEDTLS_MODE_CBC. + * + * \param ctx The context of the cipher. This must be initialized. + * + * \return The mode of operation. + * \return #MBEDTLS_MODE_NONE if \p ctx has not been initialized. + */ +static inline mbedtls_cipher_mode_t mbedtls_cipher_get_cipher_mode( + const mbedtls_cipher_context_t *ctx ) +{ + MBEDTLS_INTERNAL_VALIDATE_RET( ctx != NULL, MBEDTLS_MODE_NONE ); + if( ctx->cipher_info == NULL ) + return MBEDTLS_MODE_NONE; + + return ctx->cipher_info->mode; +} + +/** + * \brief This function returns the size of the IV or nonce + * of the cipher, in Bytes. + * + * \param ctx The context of the cipher. This must be initialized. + * + * \return The recommended IV size if no IV has been set. + * \return \c 0 for ciphers not using an IV or a nonce. + * \return The actual size if an IV has been set. + */ +static inline int mbedtls_cipher_get_iv_size( + const mbedtls_cipher_context_t *ctx ) +{ + MBEDTLS_INTERNAL_VALIDATE_RET( ctx != NULL, 0 ); + if( ctx->cipher_info == NULL ) + return 0; + + if( ctx->iv_size != 0 ) + return (int) ctx->iv_size; + + return (int) ctx->cipher_info->iv_size; +} + +/** + * \brief This function returns the type of the given cipher. + * + * \param ctx The context of the cipher. This must be initialized. + * + * \return The type of the cipher. + * \return #MBEDTLS_CIPHER_NONE if \p ctx has not been initialized. + */ +static inline mbedtls_cipher_type_t mbedtls_cipher_get_type( + const mbedtls_cipher_context_t *ctx ) +{ + MBEDTLS_INTERNAL_VALIDATE_RET( + ctx != NULL, MBEDTLS_CIPHER_NONE ); + if( ctx->cipher_info == NULL ) + return MBEDTLS_CIPHER_NONE; + + return ctx->cipher_info->type; +} + +/** + * \brief This function returns the name of the given cipher + * as a string. + * + * \param ctx The context of the cipher. This must be initialized. + * + * \return The name of the cipher. + * \return NULL if \p ctx has not been not initialized. + */ +static inline const char *mbedtls_cipher_get_name( + const mbedtls_cipher_context_t *ctx ) +{ + MBEDTLS_INTERNAL_VALIDATE_RET( ctx != NULL, 0 ); + if( ctx->cipher_info == NULL ) + return 0; + + return ctx->cipher_info->name; +} + +/** + * \brief This function returns the key length of the cipher. + * + * \param ctx The context of the cipher. This must be initialized. + * + * \return The key length of the cipher in bits. + * \return #MBEDTLS_KEY_LENGTH_NONE if ctx \p has not been + * initialized. + */ +static inline int mbedtls_cipher_get_key_bitlen( + const mbedtls_cipher_context_t *ctx ) +{ + MBEDTLS_INTERNAL_VALIDATE_RET( + ctx != NULL, MBEDTLS_KEY_LENGTH_NONE ); + if( ctx->cipher_info == NULL ) + return MBEDTLS_KEY_LENGTH_NONE; + + return (int) ctx->cipher_info->key_bitlen; +} + +/** + * \brief This function returns the operation of the given cipher. + * + * \param ctx The context of the cipher. This must be initialized. + * + * \return The type of operation: #MBEDTLS_ENCRYPT or #MBEDTLS_DECRYPT. + * \return #MBEDTLS_OPERATION_NONE if \p ctx has not been initialized. + */ +static inline mbedtls_operation_t mbedtls_cipher_get_operation( + const mbedtls_cipher_context_t *ctx ) +{ + MBEDTLS_INTERNAL_VALIDATE_RET( + ctx != NULL, MBEDTLS_OPERATION_NONE ); + if( ctx->cipher_info == NULL ) + return MBEDTLS_OPERATION_NONE; + + return ctx->operation; +} + +/** + * \brief This function sets the key to use with the given context. + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a cipher information structure. + * \param key The key to use. This must be a readable buffer of at + * least \p key_bitlen Bits. + * \param key_bitlen The key length to use, in Bits. + * \param operation The operation that the key will be used for: + * #MBEDTLS_ENCRYPT or #MBEDTLS_DECRYPT. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, + const unsigned char *key, + int key_bitlen, + const mbedtls_operation_t operation ); + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +/** + * \brief This function sets the padding mode, for cipher modes + * that use padding. + * + * The default passing mode is PKCS7 padding. + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a cipher information structure. + * \param mode The padding mode. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE + * if the selected padding mode is not supported. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if the cipher mode + * does not support padding. + */ +int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, + mbedtls_cipher_padding_t mode ); +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +/** + * \brief This function sets the initialization vector (IV) + * or nonce. + * + * \note Some ciphers do not use IVs nor nonce. For these + * ciphers, this function has no effect. + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a cipher information structure. + * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. This + * must be a readable buffer of at least \p iv_len Bytes. + * \param iv_len The IV length for ciphers with variable-size IV. + * This parameter is discarded by ciphers with fixed-size IV. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + */ +int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, + size_t iv_len ); + +/** + * \brief This function resets the cipher state. + * + * \param ctx The generic cipher context. This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + */ +int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ); + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +/** + * \brief This function adds additional data for AEAD ciphers. + * Currently supported with GCM and ChaCha20+Poly1305. + * This must be called exactly once, after + * mbedtls_cipher_reset(). + * + * \param ctx The generic cipher context. This must be initialized. + * \param ad The additional data to use. This must be a readable + * buffer of at least \p ad_len Bytes. + * \param ad_len The length of \p ad in Bytes. + * + * \return \c 0 on success. + * \return A specific error code on failure. + */ +int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, + const unsigned char *ad, size_t ad_len ); +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ + +/** + * \brief The generic cipher update function. It encrypts or + * decrypts using the given cipher context. Writes as + * many block-sized blocks of data as possible to output. + * Any data that cannot be written immediately is either + * added to the next block, or flushed when + * mbedtls_cipher_finish() is called. + * Exception: For MBEDTLS_MODE_ECB, expects a single block + * in size. For example, 16 Bytes for AES. + * + * \note If the underlying cipher is used in GCM mode, all calls + * to this function, except for the last one before + * mbedtls_cipher_finish(), must have \p ilen as a + * multiple of the block size of the cipher. + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a key. + * \param input The buffer holding the input data. This must be a + * readable buffer of at least \p ilen Bytes. + * \param ilen The length of the input data. + * \param output The buffer for the output data. This must be able to + * hold at least `ilen + block_size`. This must not be the + * same buffer as \p input. + * \param olen The length of the output data, to be updated with the + * actual number of Bytes written. This must not be + * \c NULL. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE on an + * unsupported mode for a cipher. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, + const unsigned char *input, + size_t ilen, unsigned char *output, + size_t *olen ); + +/** + * \brief The generic cipher finalization function. If data still + * needs to be flushed from an incomplete block, the data + * contained in it is padded to the size of + * the last block, and written to the \p output buffer. + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a key. + * \param output The buffer to write data to. This needs to be a writable + * buffer of at least \p block_size Bytes. + * \param olen The length of the data written to the \p output buffer. + * This may not be \c NULL. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED on decryption + * expecting a full block but not receiving one. + * \return #MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen ); + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +/** + * \brief This function writes a tag for AEAD ciphers. + * Currently supported with GCM and ChaCha20+Poly1305. + * This must be called after mbedtls_cipher_finish(). + * + * \param ctx The generic cipher context. This must be initialized, + * bound to a key, and have just completed a cipher + * operation through mbedtls_cipher_finish() the tag for + * which should be written. + * \param tag The buffer to write the tag to. This must be a writable + * buffer of at least \p tag_len Bytes. + * \param tag_len The length of the tag to write. + * + * \return \c 0 on success. + * \return A specific error code on failure. + */ +int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, + unsigned char *tag, size_t tag_len ); + +/** + * \brief This function checks the tag for AEAD ciphers. + * Currently supported with GCM and ChaCha20+Poly1305. + * This must be called after mbedtls_cipher_finish(). + * + * \param ctx The generic cipher context. This must be initialized. + * \param tag The buffer holding the tag. This must be a readable + * buffer of at least \p tag_len Bytes. + * \param tag_len The length of the tag to check. + * + * \return \c 0 on success. + * \return A specific error code on failure. + */ +int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, + const unsigned char *tag, size_t tag_len ); +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ + +/** + * \brief The generic all-in-one encryption/decryption function, + * for all ciphers except AEAD constructs. + * + * \param ctx The generic cipher context. This must be initialized. + * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. + * This must be a readable buffer of at least \p iv_len + * Bytes. + * \param iv_len The IV length for ciphers with variable-size IV. + * This parameter is discarded by ciphers with fixed-size + * IV. + * \param input The buffer holding the input data. This must be a + * readable buffer of at least \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * \param output The buffer for the output data. This must be able to + * hold at least `ilen + block_size`. This must not be the + * same buffer as \p input. + * \param olen The length of the output data, to be updated with the + * actual number of Bytes written. This must not be + * \c NULL. + * + * \note Some ciphers do not use IVs nor nonce. For these + * ciphers, use \p iv = NULL and \p iv_len = 0. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED on decryption + * expecting a full block but not receiving one. + * \return #MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen ); + +#if defined(MBEDTLS_CIPHER_MODE_AEAD) +/** + * \brief The generic autenticated encryption (AEAD) function. + * + * \param ctx The generic cipher context. This must be initialized and + * bound to a key. + * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. + * This must be a readable buffer of at least \p iv_len + * Bytes. + * \param iv_len The IV length for ciphers with variable-size IV. + * This parameter is discarded by ciphers with fixed-size IV. + * \param ad The additional data to authenticate. This must be a + * readable buffer of at least \p ad_len Bytes. + * \param ad_len The length of \p ad. + * \param input The buffer holding the input data. This must be a + * readable buffer of at least \p ilen Bytes. + * \param ilen The length of the input data. + * \param output The buffer for the output data. This must be able to + * hold at least \p ilen Bytes. + * \param olen The length of the output data, to be updated with the + * actual number of Bytes written. This must not be + * \c NULL. + * \param tag The buffer for the authentication tag. This must be a + * writable buffer of at least \p tag_len Bytes. + * \param tag_len The desired length of the authentication tag. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + unsigned char *tag, size_t tag_len ); + +/** + * \brief The generic autenticated decryption (AEAD) function. + * + * \note If the data is not authentic, then the output buffer + * is zeroed out to prevent the unauthentic plaintext being + * used, making this interface safer. + * + * \param ctx The generic cipher context. This must be initialized and + * and bound to a key. + * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. + * This must be a readable buffer of at least \p iv_len + * Bytes. + * \param iv_len The IV length for ciphers with variable-size IV. + * This parameter is discarded by ciphers with fixed-size IV. + * \param ad The additional data to be authenticated. This must be a + * readable buffer of at least \p ad_len Bytes. + * \param ad_len The length of \p ad. + * \param input The buffer holding the input data. This must be a + * readable buffer of at least \p ilen Bytes. + * \param ilen The length of the input data. + * \param output The buffer for the output data. + * This must be able to hold at least \p ilen Bytes. + * \param olen The length of the output data, to be updated with the + * actual number of Bytes written. This must not be + * \c NULL. + * \param tag The buffer holding the authentication tag. This must be + * a readable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the authentication tag. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_AUTH_FAILED if data is not authentic. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + const unsigned char *tag, size_t tag_len ); +#endif /* MBEDTLS_CIPHER_MODE_AEAD */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CIPHER_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/cipher_internal.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/cipher_internal.h new file mode 100644 index 000000000..a4d098a65 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/cipher_internal.h @@ -0,0 +1,153 @@ +/** + * \file cipher_internal.h + * + * \brief Cipher wrappers. + * + * \author Adriaan de Jong + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CIPHER_WRAP_H +#define MBEDTLS_CIPHER_WRAP_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "cipher.h" + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "psa/crypto.h" +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Base cipher information. The non-mode specific functions and values. + */ +struct mbedtls_cipher_base_t +{ + /** Base Cipher type (e.g. MBEDTLS_CIPHER_ID_AES) */ + mbedtls_cipher_id_t cipher; + + /** Encrypt using ECB */ + int (*ecb_func)( void *ctx, mbedtls_operation_t mode, + const unsigned char *input, unsigned char *output ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /** Encrypt using CBC */ + int (*cbc_func)( void *ctx, mbedtls_operation_t mode, size_t length, + unsigned char *iv, const unsigned char *input, + unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + /** Encrypt using CFB (Full length) */ + int (*cfb_func)( void *ctx, mbedtls_operation_t mode, size_t length, size_t *iv_off, + unsigned char *iv, const unsigned char *input, + unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_OFB) + /** Encrypt using OFB (Full length) */ + int (*ofb_func)( void *ctx, size_t length, size_t *iv_off, + unsigned char *iv, + const unsigned char *input, + unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /** Encrypt using CTR */ + int (*ctr_func)( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_XTS) + /** Encrypt or decrypt using XTS. */ + int (*xts_func)( void *ctx, mbedtls_operation_t mode, size_t length, + const unsigned char data_unit[16], + const unsigned char *input, unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + /** Encrypt using STREAM */ + int (*stream_func)( void *ctx, size_t length, + const unsigned char *input, unsigned char *output ); +#endif + + /** Set key for encryption purposes */ + int (*setkey_enc_func)( void *ctx, const unsigned char *key, + unsigned int key_bitlen ); + + /** Set key for decryption purposes */ + int (*setkey_dec_func)( void *ctx, const unsigned char *key, + unsigned int key_bitlen); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + +}; + +typedef struct +{ + mbedtls_cipher_type_t type; + const mbedtls_cipher_info_t *info; +} mbedtls_cipher_definition_t; + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +typedef enum +{ + MBEDTLS_CIPHER_PSA_KEY_UNSET = 0, + MBEDTLS_CIPHER_PSA_KEY_OWNED, /* Used for PSA-based cipher contexts which */ + /* use raw key material internally imported */ + /* into a allocated key slot, and which */ + /* hence need to destroy that key slot */ + /* when they are no longer needed. */ + MBEDTLS_CIPHER_PSA_KEY_NOT_OWNED, /* Used for PSA-based cipher contexts */ + /* which use a key from a key slot */ + /* provided by the user, and which */ + /* hence should not be destroyed when */ + /* the context is no longer needed. */ +} mbedtls_cipher_psa_key_ownership; + +typedef struct +{ + psa_algorithm_t alg; + psa_key_handle_t slot; + mbedtls_cipher_psa_key_ownership slot_state; +} mbedtls_cipher_context_psa; +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +extern const mbedtls_cipher_definition_t mbedtls_cipher_definitions[]; + +extern int mbedtls_cipher_supported[]; + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CIPHER_WRAP_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/cmac.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/cmac.h new file mode 100644 index 000000000..d48488fcb --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/cmac.h @@ -0,0 +1,213 @@ +/** + * \file cmac.h + * + * \brief This file contains CMAC definitions and functions. + * + * The Cipher-based Message Authentication Code (CMAC) Mode for + * Authentication is defined in RFC-4493: The AES-CMAC Algorithm. + */ +/* + * Copyright (C) 2015-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CMAC_H +#define MBEDTLS_CMAC_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "cipher.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED -0x007A /**< CMAC hardware accelerator failed. */ + +#define MBEDTLS_AES_BLOCK_SIZE 16 +#define MBEDTLS_DES3_BLOCK_SIZE 8 + +#if defined(MBEDTLS_AES_C) +#define MBEDTLS_CIPHER_BLKSIZE_MAX 16 /**< The longest block used by CMAC is that of AES. */ +#else +#define MBEDTLS_CIPHER_BLKSIZE_MAX 8 /**< The longest block used by CMAC is that of 3DES. */ +#endif + +#if !defined(MBEDTLS_CMAC_ALT) + +/** + * The CMAC context structure. + */ +struct mbedtls_cmac_context_t +{ + /** The internal state of the CMAC algorithm. */ + unsigned char state[MBEDTLS_CIPHER_BLKSIZE_MAX]; + + /** Unprocessed data - either data that was not block aligned and is still + * pending processing, or the final block. */ + unsigned char unprocessed_block[MBEDTLS_CIPHER_BLKSIZE_MAX]; + + /** The length of data pending processing. */ + size_t unprocessed_len; +}; + +#else /* !MBEDTLS_CMAC_ALT */ +#include "cmac_alt.h" +#endif /* !MBEDTLS_CMAC_ALT */ + +/** + * \brief This function sets the CMAC key, and prepares to authenticate + * the input data. + * Must be called with an initialized cipher context. + * + * \param ctx The cipher context used for the CMAC operation, initialized + * as one of the following types: MBEDTLS_CIPHER_AES_128_ECB, + * MBEDTLS_CIPHER_AES_192_ECB, MBEDTLS_CIPHER_AES_256_ECB, + * or MBEDTLS_CIPHER_DES_EDE3_ECB. + * \param key The CMAC key. + * \param keybits The length of the CMAC key in bits. + * Must be supported by the cipher. + * + * \return \c 0 on success. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_cmac_starts( mbedtls_cipher_context_t *ctx, + const unsigned char *key, size_t keybits ); + +/** + * \brief This function feeds an input buffer into an ongoing CMAC + * computation. + * + * It is called between mbedtls_cipher_cmac_starts() or + * mbedtls_cipher_cmac_reset(), and mbedtls_cipher_cmac_finish(). + * Can be called repeatedly. + * + * \param ctx The cipher context used for the CMAC operation. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_cmac_update( mbedtls_cipher_context_t *ctx, + const unsigned char *input, size_t ilen ); + +/** + * \brief This function finishes the CMAC operation, and writes + * the result to the output buffer. + * + * It is called after mbedtls_cipher_cmac_update(). + * It can be followed by mbedtls_cipher_cmac_reset() and + * mbedtls_cipher_cmac_update(), or mbedtls_cipher_free(). + * + * \param ctx The cipher context used for the CMAC operation. + * \param output The output buffer for the CMAC checksum result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_cmac_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output ); + +/** + * \brief This function prepares the authentication of another + * message with the same key as the previous CMAC + * operation. + * + * It is called after mbedtls_cipher_cmac_finish() + * and before mbedtls_cipher_cmac_update(). + * + * \param ctx The cipher context used for the CMAC operation. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_cmac_reset( mbedtls_cipher_context_t *ctx ); + +/** + * \brief This function calculates the full generic CMAC + * on the input buffer with the provided key. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The CMAC result is calculated as + * output = generic CMAC(cmac key, input buffer). + * + * + * \param cipher_info The cipher information. + * \param key The CMAC key. + * \param keylen The length of the CMAC key in bits. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * \param output The buffer for the generic CMAC result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_cmac( const mbedtls_cipher_info_t *cipher_info, + const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ); + +#if defined(MBEDTLS_AES_C) +/** + * \brief This function implements the AES-CMAC-PRF-128 pseudorandom + * function, as defined in + * RFC-4615: The Advanced Encryption Standard-Cipher-based + * Message Authentication Code-Pseudo-Random Function-128 + * (AES-CMAC-PRF-128) Algorithm for the Internet Key + * Exchange Protocol (IKE). + * + * \param key The key to use. + * \param key_len The key length in Bytes. + * \param input The buffer holding the input data. + * \param in_len The length of the input data in Bytes. + * \param output The buffer holding the generated 16 Bytes of + * pseudorandom output. + * + * \return \c 0 on success. + */ +int mbedtls_aes_cmac_prf_128( const unsigned char *key, size_t key_len, + const unsigned char *input, size_t in_len, + unsigned char output[16] ); +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_SELF_TEST) && ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_DES_C) ) +/** + * \brief The CMAC checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_cmac_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST && ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CMAC_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/compat-1.3.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/compat-1.3.h new file mode 100644 index 000000000..15e038b42 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/compat-1.3.h @@ -0,0 +1,2531 @@ +/** + * \file compat-1.3.h + * + * \brief Compatibility definitions for using mbed TLS with client code written + * for the PolarSSL naming conventions. + * + * \deprecated Use the new names directly instead + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) + +#if defined(MBEDTLS_DEPRECATED_WARNING) +#warning "Including compat-1.3.h is deprecated" +#endif + +#ifndef MBEDTLS_COMPAT13_H +#define MBEDTLS_COMPAT13_H + +/* + * config.h options + */ +#if defined MBEDTLS_AESNI_C +#define POLARSSL_AESNI_C MBEDTLS_AESNI_C +#endif +#if defined MBEDTLS_AES_ALT +#define POLARSSL_AES_ALT MBEDTLS_AES_ALT +#endif +#if defined MBEDTLS_AES_C +#define POLARSSL_AES_C MBEDTLS_AES_C +#endif +#if defined MBEDTLS_AES_ROM_TABLES +#define POLARSSL_AES_ROM_TABLES MBEDTLS_AES_ROM_TABLES +#endif +#if defined MBEDTLS_ARC4_ALT +#define POLARSSL_ARC4_ALT MBEDTLS_ARC4_ALT +#endif +#if defined MBEDTLS_ARC4_C +#define POLARSSL_ARC4_C MBEDTLS_ARC4_C +#endif +#if defined MBEDTLS_ASN1_PARSE_C +#define POLARSSL_ASN1_PARSE_C MBEDTLS_ASN1_PARSE_C +#endif +#if defined MBEDTLS_ASN1_WRITE_C +#define POLARSSL_ASN1_WRITE_C MBEDTLS_ASN1_WRITE_C +#endif +#if defined MBEDTLS_BASE64_C +#define POLARSSL_BASE64_C MBEDTLS_BASE64_C +#endif +#if defined MBEDTLS_BIGNUM_C +#define POLARSSL_BIGNUM_C MBEDTLS_BIGNUM_C +#endif +#if defined MBEDTLS_BLOWFISH_ALT +#define POLARSSL_BLOWFISH_ALT MBEDTLS_BLOWFISH_ALT +#endif +#if defined MBEDTLS_BLOWFISH_C +#define POLARSSL_BLOWFISH_C MBEDTLS_BLOWFISH_C +#endif +#if defined MBEDTLS_CAMELLIA_ALT +#define POLARSSL_CAMELLIA_ALT MBEDTLS_CAMELLIA_ALT +#endif +#if defined MBEDTLS_CAMELLIA_C +#define POLARSSL_CAMELLIA_C MBEDTLS_CAMELLIA_C +#endif +#if defined MBEDTLS_CAMELLIA_SMALL_MEMORY +#define POLARSSL_CAMELLIA_SMALL_MEMORY MBEDTLS_CAMELLIA_SMALL_MEMORY +#endif +#if defined MBEDTLS_CCM_C +#define POLARSSL_CCM_C MBEDTLS_CCM_C +#endif +#if defined MBEDTLS_CERTS_C +#define POLARSSL_CERTS_C MBEDTLS_CERTS_C +#endif +#if defined MBEDTLS_CIPHER_C +#define POLARSSL_CIPHER_C MBEDTLS_CIPHER_C +#endif +#if defined MBEDTLS_CIPHER_MODE_CBC +#define POLARSSL_CIPHER_MODE_CBC MBEDTLS_CIPHER_MODE_CBC +#endif +#if defined MBEDTLS_CIPHER_MODE_CFB +#define POLARSSL_CIPHER_MODE_CFB MBEDTLS_CIPHER_MODE_CFB +#endif +#if defined MBEDTLS_CIPHER_MODE_CTR +#define POLARSSL_CIPHER_MODE_CTR MBEDTLS_CIPHER_MODE_CTR +#endif +#if defined MBEDTLS_CIPHER_NULL_CIPHER +#define POLARSSL_CIPHER_NULL_CIPHER MBEDTLS_CIPHER_NULL_CIPHER +#endif +#if defined MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define POLARSSL_CIPHER_PADDING_ONE_AND_ZEROS MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#endif +#if defined MBEDTLS_CIPHER_PADDING_PKCS7 +#define POLARSSL_CIPHER_PADDING_PKCS7 MBEDTLS_CIPHER_PADDING_PKCS7 +#endif +#if defined MBEDTLS_CIPHER_PADDING_ZEROS +#define POLARSSL_CIPHER_PADDING_ZEROS MBEDTLS_CIPHER_PADDING_ZEROS +#endif +#if defined MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define POLARSSL_CIPHER_PADDING_ZEROS_AND_LEN MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#endif +#if defined MBEDTLS_CTR_DRBG_C +#define POLARSSL_CTR_DRBG_C MBEDTLS_CTR_DRBG_C +#endif +#if defined MBEDTLS_DEBUG_C +#define POLARSSL_DEBUG_C MBEDTLS_DEBUG_C +#endif +#if defined MBEDTLS_DEPRECATED_REMOVED +#define POLARSSL_DEPRECATED_REMOVED MBEDTLS_DEPRECATED_REMOVED +#endif +#if defined MBEDTLS_DEPRECATED_WARNING +#define POLARSSL_DEPRECATED_WARNING MBEDTLS_DEPRECATED_WARNING +#endif +#if defined MBEDTLS_DES_ALT +#define POLARSSL_DES_ALT MBEDTLS_DES_ALT +#endif +#if defined MBEDTLS_DES_C +#define POLARSSL_DES_C MBEDTLS_DES_C +#endif +#if defined MBEDTLS_DHM_C +#define POLARSSL_DHM_C MBEDTLS_DHM_C +#endif +#if defined MBEDTLS_ECDH_C +#define POLARSSL_ECDH_C MBEDTLS_ECDH_C +#endif +#if defined MBEDTLS_ECDSA_C +#define POLARSSL_ECDSA_C MBEDTLS_ECDSA_C +#endif +#if defined MBEDTLS_ECDSA_DETERMINISTIC +#define POLARSSL_ECDSA_DETERMINISTIC MBEDTLS_ECDSA_DETERMINISTIC +#endif +#if defined MBEDTLS_ECP_C +#define POLARSSL_ECP_C MBEDTLS_ECP_C +#endif +#if defined MBEDTLS_ECP_DP_BP256R1_ENABLED +#define POLARSSL_ECP_DP_BP256R1_ENABLED MBEDTLS_ECP_DP_BP256R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_BP384R1_ENABLED +#define POLARSSL_ECP_DP_BP384R1_ENABLED MBEDTLS_ECP_DP_BP384R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_BP512R1_ENABLED +#define POLARSSL_ECP_DP_BP512R1_ENABLED MBEDTLS_ECP_DP_BP512R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_CURVE25519_ENABLED +#define POLARSSL_ECP_DP_M255_ENABLED MBEDTLS_ECP_DP_CURVE25519_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP192K1_ENABLED +#define POLARSSL_ECP_DP_SECP192K1_ENABLED MBEDTLS_ECP_DP_SECP192K1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP192R1_ENABLED +#define POLARSSL_ECP_DP_SECP192R1_ENABLED MBEDTLS_ECP_DP_SECP192R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP224K1_ENABLED +#define POLARSSL_ECP_DP_SECP224K1_ENABLED MBEDTLS_ECP_DP_SECP224K1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define POLARSSL_ECP_DP_SECP224R1_ENABLED MBEDTLS_ECP_DP_SECP224R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define POLARSSL_ECP_DP_SECP256K1_ENABLED MBEDTLS_ECP_DP_SECP256K1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define POLARSSL_ECP_DP_SECP256R1_ENABLED MBEDTLS_ECP_DP_SECP256R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define POLARSSL_ECP_DP_SECP384R1_ENABLED MBEDTLS_ECP_DP_SECP384R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP521R1_ENABLED +#define POLARSSL_ECP_DP_SECP521R1_ENABLED MBEDTLS_ECP_DP_SECP521R1_ENABLED +#endif +#if defined MBEDTLS_ECP_FIXED_POINT_OPTIM +#define POLARSSL_ECP_FIXED_POINT_OPTIM MBEDTLS_ECP_FIXED_POINT_OPTIM +#endif +#if defined MBEDTLS_ECP_MAX_BITS +#define POLARSSL_ECP_MAX_BITS MBEDTLS_ECP_MAX_BITS +#endif +#if defined MBEDTLS_ECP_NIST_OPTIM +#define POLARSSL_ECP_NIST_OPTIM MBEDTLS_ECP_NIST_OPTIM +#endif +#if defined MBEDTLS_ECP_WINDOW_SIZE +#define POLARSSL_ECP_WINDOW_SIZE MBEDTLS_ECP_WINDOW_SIZE +#endif +#if defined MBEDTLS_ENABLE_WEAK_CIPHERSUITES +#define POLARSSL_ENABLE_WEAK_CIPHERSUITES MBEDTLS_ENABLE_WEAK_CIPHERSUITES +#endif +#if defined MBEDTLS_ENTROPY_C +#define POLARSSL_ENTROPY_C MBEDTLS_ENTROPY_C +#endif +#if defined MBEDTLS_ENTROPY_FORCE_SHA256 +#define POLARSSL_ENTROPY_FORCE_SHA256 MBEDTLS_ENTROPY_FORCE_SHA256 +#endif +#if defined MBEDTLS_ERROR_C +#define POLARSSL_ERROR_C MBEDTLS_ERROR_C +#endif +#if defined MBEDTLS_ERROR_STRERROR_DUMMY +#define POLARSSL_ERROR_STRERROR_DUMMY MBEDTLS_ERROR_STRERROR_DUMMY +#endif +#if defined MBEDTLS_FS_IO +#define POLARSSL_FS_IO MBEDTLS_FS_IO +#endif +#if defined MBEDTLS_GCM_C +#define POLARSSL_GCM_C MBEDTLS_GCM_C +#endif +#if defined MBEDTLS_GENPRIME +#define POLARSSL_GENPRIME MBEDTLS_GENPRIME +#endif +#if defined MBEDTLS_HAVEGE_C +#define POLARSSL_HAVEGE_C MBEDTLS_HAVEGE_C +#endif +#if defined MBEDTLS_HAVE_ASM +#define POLARSSL_HAVE_ASM MBEDTLS_HAVE_ASM +#endif +#if defined MBEDTLS_HAVE_SSE2 +#define POLARSSL_HAVE_SSE2 MBEDTLS_HAVE_SSE2 +#endif +#if defined MBEDTLS_HAVE_TIME +#define POLARSSL_HAVE_TIME MBEDTLS_HAVE_TIME +#endif +#if defined MBEDTLS_HMAC_DRBG_C +#define POLARSSL_HMAC_DRBG_C MBEDTLS_HMAC_DRBG_C +#endif +#if defined MBEDTLS_HMAC_DRBG_MAX_INPUT +#define POLARSSL_HMAC_DRBG_MAX_INPUT MBEDTLS_HMAC_DRBG_MAX_INPUT +#endif +#if defined MBEDTLS_HMAC_DRBG_MAX_REQUEST +#define POLARSSL_HMAC_DRBG_MAX_REQUEST MBEDTLS_HMAC_DRBG_MAX_REQUEST +#endif +#if defined MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT +#define POLARSSL_HMAC_DRBG_MAX_SEED_INPUT MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT +#endif +#if defined MBEDTLS_HMAC_DRBG_RESEED_INTERVAL +#define POLARSSL_HMAC_DRBG_RESEED_INTERVAL MBEDTLS_HMAC_DRBG_RESEED_INTERVAL +#endif +#if defined MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_PSK_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_RSA_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED +#endif +#if defined MBEDTLS_MD2_ALT +#define POLARSSL_MD2_ALT MBEDTLS_MD2_ALT +#endif +#if defined MBEDTLS_MD2_C +#define POLARSSL_MD2_C MBEDTLS_MD2_C +#endif +#if defined MBEDTLS_MD2_PROCESS_ALT +#define POLARSSL_MD2_PROCESS_ALT MBEDTLS_MD2_PROCESS_ALT +#endif +#if defined MBEDTLS_MD4_ALT +#define POLARSSL_MD4_ALT MBEDTLS_MD4_ALT +#endif +#if defined MBEDTLS_MD4_C +#define POLARSSL_MD4_C MBEDTLS_MD4_C +#endif +#if defined MBEDTLS_MD4_PROCESS_ALT +#define POLARSSL_MD4_PROCESS_ALT MBEDTLS_MD4_PROCESS_ALT +#endif +#if defined MBEDTLS_MD5_ALT +#define POLARSSL_MD5_ALT MBEDTLS_MD5_ALT +#endif +#if defined MBEDTLS_MD5_C +#define POLARSSL_MD5_C MBEDTLS_MD5_C +#endif +#if defined MBEDTLS_MD5_PROCESS_ALT +#define POLARSSL_MD5_PROCESS_ALT MBEDTLS_MD5_PROCESS_ALT +#endif +#if defined MBEDTLS_MD_C +#define POLARSSL_MD_C MBEDTLS_MD_C +#endif +#if defined MBEDTLS_MEMORY_ALIGN_MULTIPLE +#define POLARSSL_MEMORY_ALIGN_MULTIPLE MBEDTLS_MEMORY_ALIGN_MULTIPLE +#endif +#if defined MBEDTLS_MEMORY_BACKTRACE +#define POLARSSL_MEMORY_BACKTRACE MBEDTLS_MEMORY_BACKTRACE +#endif +#if defined MBEDTLS_MEMORY_BUFFER_ALLOC_C +#define POLARSSL_MEMORY_BUFFER_ALLOC_C MBEDTLS_MEMORY_BUFFER_ALLOC_C +#endif +#if defined MBEDTLS_MEMORY_DEBUG +#define POLARSSL_MEMORY_DEBUG MBEDTLS_MEMORY_DEBUG +#endif +#if defined MBEDTLS_MPI_MAX_SIZE +#define POLARSSL_MPI_MAX_SIZE MBEDTLS_MPI_MAX_SIZE +#endif +#if defined MBEDTLS_MPI_WINDOW_SIZE +#define POLARSSL_MPI_WINDOW_SIZE MBEDTLS_MPI_WINDOW_SIZE +#endif +#if defined MBEDTLS_NET_C +#define POLARSSL_NET_C MBEDTLS_NET_C +#endif +#if defined MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES +#define POLARSSL_NO_DEFAULT_ENTROPY_SOURCES MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES +#endif +#if defined MBEDTLS_NO_PLATFORM_ENTROPY +#define POLARSSL_NO_PLATFORM_ENTROPY MBEDTLS_NO_PLATFORM_ENTROPY +#endif +#if defined MBEDTLS_OID_C +#define POLARSSL_OID_C MBEDTLS_OID_C +#endif +#if defined MBEDTLS_PADLOCK_C +#define POLARSSL_PADLOCK_C MBEDTLS_PADLOCK_C +#endif +#if defined MBEDTLS_PEM_PARSE_C +#define POLARSSL_PEM_PARSE_C MBEDTLS_PEM_PARSE_C +#endif +#if defined MBEDTLS_PEM_WRITE_C +#define POLARSSL_PEM_WRITE_C MBEDTLS_PEM_WRITE_C +#endif +#if defined MBEDTLS_PKCS11_C +#define POLARSSL_PKCS11_C MBEDTLS_PKCS11_C +#endif +#if defined MBEDTLS_PKCS12_C +#define POLARSSL_PKCS12_C MBEDTLS_PKCS12_C +#endif +#if defined MBEDTLS_PKCS1_V15 +#define POLARSSL_PKCS1_V15 MBEDTLS_PKCS1_V15 +#endif +#if defined MBEDTLS_PKCS1_V21 +#define POLARSSL_PKCS1_V21 MBEDTLS_PKCS1_V21 +#endif +#if defined MBEDTLS_PKCS5_C +#define POLARSSL_PKCS5_C MBEDTLS_PKCS5_C +#endif +#if defined MBEDTLS_PK_C +#define POLARSSL_PK_C MBEDTLS_PK_C +#endif +#if defined MBEDTLS_PK_PARSE_C +#define POLARSSL_PK_PARSE_C MBEDTLS_PK_PARSE_C +#endif +#if defined MBEDTLS_PK_PARSE_EC_EXTENDED +#define POLARSSL_PK_PARSE_EC_EXTENDED MBEDTLS_PK_PARSE_EC_EXTENDED +#endif +#if defined MBEDTLS_PK_RSA_ALT_SUPPORT +#define POLARSSL_PK_RSA_ALT_SUPPORT MBEDTLS_PK_RSA_ALT_SUPPORT +#endif +#if defined MBEDTLS_PK_WRITE_C +#define POLARSSL_PK_WRITE_C MBEDTLS_PK_WRITE_C +#endif +#if defined MBEDTLS_PLATFORM_C +#define POLARSSL_PLATFORM_C MBEDTLS_PLATFORM_C +#endif +#if defined MBEDTLS_PLATFORM_EXIT_ALT +#define POLARSSL_PLATFORM_EXIT_ALT MBEDTLS_PLATFORM_EXIT_ALT +#endif +#if defined MBEDTLS_PLATFORM_EXIT_MACRO +#define POLARSSL_PLATFORM_EXIT_MACRO MBEDTLS_PLATFORM_EXIT_MACRO +#endif +#if defined MBEDTLS_PLATFORM_FPRINTF_ALT +#define POLARSSL_PLATFORM_FPRINTF_ALT MBEDTLS_PLATFORM_FPRINTF_ALT +#endif +#if defined MBEDTLS_PLATFORM_FPRINTF_MACRO +#define POLARSSL_PLATFORM_FPRINTF_MACRO MBEDTLS_PLATFORM_FPRINTF_MACRO +#endif +#if defined MBEDTLS_PLATFORM_FREE_MACRO +#define POLARSSL_PLATFORM_FREE_MACRO MBEDTLS_PLATFORM_FREE_MACRO +#endif +#if defined MBEDTLS_PLATFORM_MEMORY +#define POLARSSL_PLATFORM_MEMORY MBEDTLS_PLATFORM_MEMORY +#endif +#if defined MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#define POLARSSL_PLATFORM_NO_STD_FUNCTIONS MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#endif +#if defined MBEDTLS_PLATFORM_PRINTF_ALT +#define POLARSSL_PLATFORM_PRINTF_ALT MBEDTLS_PLATFORM_PRINTF_ALT +#endif +#if defined MBEDTLS_PLATFORM_PRINTF_MACRO +#define POLARSSL_PLATFORM_PRINTF_MACRO MBEDTLS_PLATFORM_PRINTF_MACRO +#endif +#if defined MBEDTLS_PLATFORM_SNPRINTF_ALT +#define POLARSSL_PLATFORM_SNPRINTF_ALT MBEDTLS_PLATFORM_SNPRINTF_ALT +#endif +#if defined MBEDTLS_PLATFORM_SNPRINTF_MACRO +#define POLARSSL_PLATFORM_SNPRINTF_MACRO MBEDTLS_PLATFORM_SNPRINTF_MACRO +#endif +#if defined MBEDTLS_PLATFORM_STD_EXIT +#define POLARSSL_PLATFORM_STD_EXIT MBEDTLS_PLATFORM_STD_EXIT +#endif +#if defined MBEDTLS_PLATFORM_STD_FPRINTF +#define POLARSSL_PLATFORM_STD_FPRINTF MBEDTLS_PLATFORM_STD_FPRINTF +#endif +#if defined MBEDTLS_PLATFORM_STD_FREE +#define POLARSSL_PLATFORM_STD_FREE MBEDTLS_PLATFORM_STD_FREE +#endif +#if defined MBEDTLS_PLATFORM_STD_MEM_HDR +#define POLARSSL_PLATFORM_STD_MEM_HDR MBEDTLS_PLATFORM_STD_MEM_HDR +#endif +#if defined MBEDTLS_PLATFORM_STD_PRINTF +#define POLARSSL_PLATFORM_STD_PRINTF MBEDTLS_PLATFORM_STD_PRINTF +#endif +#if defined MBEDTLS_PLATFORM_STD_SNPRINTF +#define POLARSSL_PLATFORM_STD_SNPRINTF MBEDTLS_PLATFORM_STD_SNPRINTF +#endif +#if defined MBEDTLS_PSK_MAX_LEN +#define POLARSSL_PSK_MAX_LEN MBEDTLS_PSK_MAX_LEN +#endif +#if defined MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#define POLARSSL_REMOVE_ARC4_CIPHERSUITES MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#endif +#if defined MBEDTLS_RIPEMD160_ALT +#define POLARSSL_RIPEMD160_ALT MBEDTLS_RIPEMD160_ALT +#endif +#if defined MBEDTLS_RIPEMD160_C +#define POLARSSL_RIPEMD160_C MBEDTLS_RIPEMD160_C +#endif +#if defined MBEDTLS_RIPEMD160_PROCESS_ALT +#define POLARSSL_RIPEMD160_PROCESS_ALT MBEDTLS_RIPEMD160_PROCESS_ALT +#endif +#if defined MBEDTLS_RSA_C +#define POLARSSL_RSA_C MBEDTLS_RSA_C +#endif +#if defined MBEDTLS_RSA_NO_CRT +#define POLARSSL_RSA_NO_CRT MBEDTLS_RSA_NO_CRT +#endif +#if defined MBEDTLS_SELF_TEST +#define POLARSSL_SELF_TEST MBEDTLS_SELF_TEST +#endif +#if defined MBEDTLS_SHA1_ALT +#define POLARSSL_SHA1_ALT MBEDTLS_SHA1_ALT +#endif +#if defined MBEDTLS_SHA1_C +#define POLARSSL_SHA1_C MBEDTLS_SHA1_C +#endif +#if defined MBEDTLS_SHA1_PROCESS_ALT +#define POLARSSL_SHA1_PROCESS_ALT MBEDTLS_SHA1_PROCESS_ALT +#endif +#if defined MBEDTLS_SHA256_ALT +#define POLARSSL_SHA256_ALT MBEDTLS_SHA256_ALT +#endif +#if defined MBEDTLS_SHA256_C +#define POLARSSL_SHA256_C MBEDTLS_SHA256_C +#endif +#if defined MBEDTLS_SHA256_PROCESS_ALT +#define POLARSSL_SHA256_PROCESS_ALT MBEDTLS_SHA256_PROCESS_ALT +#endif +#if defined MBEDTLS_SHA512_ALT +#define POLARSSL_SHA512_ALT MBEDTLS_SHA512_ALT +#endif +#if defined MBEDTLS_SHA512_C +#define POLARSSL_SHA512_C MBEDTLS_SHA512_C +#endif +#if defined MBEDTLS_SHA512_PROCESS_ALT +#define POLARSSL_SHA512_PROCESS_ALT MBEDTLS_SHA512_PROCESS_ALT +#endif +#if defined MBEDTLS_SSL_ALL_ALERT_MESSAGES +#define POLARSSL_SSL_ALL_ALERT_MESSAGES MBEDTLS_SSL_ALL_ALERT_MESSAGES +#endif +#if defined MBEDTLS_SSL_ALPN +#define POLARSSL_SSL_ALPN MBEDTLS_SSL_ALPN +#endif +#if defined MBEDTLS_SSL_CACHE_C +#define POLARSSL_SSL_CACHE_C MBEDTLS_SSL_CACHE_C +#endif +#if defined MBEDTLS_SSL_CBC_RECORD_SPLITTING +#define POLARSSL_SSL_CBC_RECORD_SPLITTING MBEDTLS_SSL_CBC_RECORD_SPLITTING +#endif +#if defined MBEDTLS_SSL_CLI_C +#define POLARSSL_SSL_CLI_C MBEDTLS_SSL_CLI_C +#endif +#if defined MBEDTLS_SSL_COOKIE_C +#define POLARSSL_SSL_COOKIE_C MBEDTLS_SSL_COOKIE_C +#endif +#if defined MBEDTLS_SSL_COOKIE_TIMEOUT +#define POLARSSL_SSL_COOKIE_TIMEOUT MBEDTLS_SSL_COOKIE_TIMEOUT +#endif +#if defined MBEDTLS_SSL_DEBUG_ALL +#define POLARSSL_SSL_DEBUG_ALL MBEDTLS_SSL_DEBUG_ALL +#endif +#if defined MBEDTLS_SSL_DTLS_ANTI_REPLAY +#define POLARSSL_SSL_DTLS_ANTI_REPLAY MBEDTLS_SSL_DTLS_ANTI_REPLAY +#endif +#if defined MBEDTLS_SSL_DTLS_BADMAC_LIMIT +#define POLARSSL_SSL_DTLS_BADMAC_LIMIT MBEDTLS_SSL_DTLS_BADMAC_LIMIT +#endif +#if defined MBEDTLS_SSL_DTLS_HELLO_VERIFY +#define POLARSSL_SSL_DTLS_HELLO_VERIFY MBEDTLS_SSL_DTLS_HELLO_VERIFY +#endif +#if defined MBEDTLS_SSL_ENCRYPT_THEN_MAC +#define POLARSSL_SSL_ENCRYPT_THEN_MAC MBEDTLS_SSL_ENCRYPT_THEN_MAC +#endif +#if defined MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#define POLARSSL_SSL_EXTENDED_MASTER_SECRET MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#endif +#if defined MBEDTLS_SSL_FALLBACK_SCSV +#define POLARSSL_SSL_FALLBACK_SCSV MBEDTLS_SSL_FALLBACK_SCSV +#endif +#if defined MBEDTLS_SSL_HW_RECORD_ACCEL +#define POLARSSL_SSL_HW_RECORD_ACCEL MBEDTLS_SSL_HW_RECORD_ACCEL +#endif +#if defined MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#define POLARSSL_SSL_MAX_FRAGMENT_LENGTH MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#endif +#if defined MBEDTLS_SSL_PROTO_DTLS +#define POLARSSL_SSL_PROTO_DTLS MBEDTLS_SSL_PROTO_DTLS +#endif +#if defined MBEDTLS_SSL_PROTO_SSL3 +#define POLARSSL_SSL_PROTO_SSL3 MBEDTLS_SSL_PROTO_SSL3 +#endif +#if defined MBEDTLS_SSL_PROTO_TLS1 +#define POLARSSL_SSL_PROTO_TLS1 MBEDTLS_SSL_PROTO_TLS1 +#endif +#if defined MBEDTLS_SSL_PROTO_TLS1_1 +#define POLARSSL_SSL_PROTO_TLS1_1 MBEDTLS_SSL_PROTO_TLS1_1 +#endif +#if defined MBEDTLS_SSL_PROTO_TLS1_2 +#define POLARSSL_SSL_PROTO_TLS1_2 MBEDTLS_SSL_PROTO_TLS1_2 +#endif +#if defined MBEDTLS_SSL_RENEGOTIATION +#define POLARSSL_SSL_RENEGOTIATION MBEDTLS_SSL_RENEGOTIATION +#endif +#if defined MBEDTLS_SSL_SERVER_NAME_INDICATION +#define POLARSSL_SSL_SERVER_NAME_INDICATION MBEDTLS_SSL_SERVER_NAME_INDICATION +#endif +#if defined MBEDTLS_SSL_SESSION_TICKETS +#define POLARSSL_SSL_SESSION_TICKETS MBEDTLS_SSL_SESSION_TICKETS +#endif +#if defined MBEDTLS_SSL_SRV_C +#define POLARSSL_SSL_SRV_C MBEDTLS_SSL_SRV_C +#endif +#if defined MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE +#define POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE +#endif +#if defined MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO +#define POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO +#endif +#if defined MBEDTLS_SSL_TLS_C +#define POLARSSL_SSL_TLS_C MBEDTLS_SSL_TLS_C +#endif +#if defined MBEDTLS_SSL_TRUNCATED_HMAC +#define POLARSSL_SSL_TRUNCATED_HMAC MBEDTLS_SSL_TRUNCATED_HMAC +#endif +#if defined MBEDTLS_THREADING_ALT +#define POLARSSL_THREADING_ALT MBEDTLS_THREADING_ALT +#endif +#if defined MBEDTLS_THREADING_C +#define POLARSSL_THREADING_C MBEDTLS_THREADING_C +#endif +#if defined MBEDTLS_THREADING_PTHREAD +#define POLARSSL_THREADING_PTHREAD MBEDTLS_THREADING_PTHREAD +#endif +#if defined MBEDTLS_TIMING_ALT +#define POLARSSL_TIMING_ALT MBEDTLS_TIMING_ALT +#endif +#if defined MBEDTLS_TIMING_C +#define POLARSSL_TIMING_C MBEDTLS_TIMING_C +#endif +#if defined MBEDTLS_VERSION_C +#define POLARSSL_VERSION_C MBEDTLS_VERSION_C +#endif +#if defined MBEDTLS_VERSION_FEATURES +#define POLARSSL_VERSION_FEATURES MBEDTLS_VERSION_FEATURES +#endif +#if defined MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 +#define POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3 MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 +#endif +#if defined MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION +#define POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION +#endif +#if defined MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE +#define POLARSSL_X509_CHECK_EXTENDED_KEY_USAGE MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE +#endif +#if defined MBEDTLS_X509_CHECK_KEY_USAGE +#define POLARSSL_X509_CHECK_KEY_USAGE MBEDTLS_X509_CHECK_KEY_USAGE +#endif +#if defined MBEDTLS_X509_CREATE_C +#define POLARSSL_X509_CREATE_C MBEDTLS_X509_CREATE_C +#endif +#if defined MBEDTLS_X509_CRL_PARSE_C +#define POLARSSL_X509_CRL_PARSE_C MBEDTLS_X509_CRL_PARSE_C +#endif +#if defined MBEDTLS_X509_CRT_PARSE_C +#define POLARSSL_X509_CRT_PARSE_C MBEDTLS_X509_CRT_PARSE_C +#endif +#if defined MBEDTLS_X509_CRT_WRITE_C +#define POLARSSL_X509_CRT_WRITE_C MBEDTLS_X509_CRT_WRITE_C +#endif +#if defined MBEDTLS_X509_CSR_PARSE_C +#define POLARSSL_X509_CSR_PARSE_C MBEDTLS_X509_CSR_PARSE_C +#endif +#if defined MBEDTLS_X509_CSR_WRITE_C +#define POLARSSL_X509_CSR_WRITE_C MBEDTLS_X509_CSR_WRITE_C +#endif +#if defined MBEDTLS_X509_MAX_INTERMEDIATE_CA +#define POLARSSL_X509_MAX_INTERMEDIATE_CA MBEDTLS_X509_MAX_INTERMEDIATE_CA +#endif +#if defined MBEDTLS_X509_RSASSA_PSS_SUPPORT +#define POLARSSL_X509_RSASSA_PSS_SUPPORT MBEDTLS_X509_RSASSA_PSS_SUPPORT +#endif +#if defined MBEDTLS_X509_USE_C +#define POLARSSL_X509_USE_C MBEDTLS_X509_USE_C +#endif +#if defined MBEDTLS_XTEA_ALT +#define POLARSSL_XTEA_ALT MBEDTLS_XTEA_ALT +#endif +#if defined MBEDTLS_XTEA_C +#define POLARSSL_XTEA_C MBEDTLS_XTEA_C +#endif +#if defined MBEDTLS_ZLIB_SUPPORT +#define POLARSSL_ZLIB_SUPPORT MBEDTLS_ZLIB_SUPPORT +#endif + +/* + * Misc names (macros, types, functions, enum constants...) + */ +#define AES_DECRYPT MBEDTLS_AES_DECRYPT +#define AES_ENCRYPT MBEDTLS_AES_ENCRYPT +#define ASN1_BIT_STRING MBEDTLS_ASN1_BIT_STRING +#define ASN1_BMP_STRING MBEDTLS_ASN1_BMP_STRING +#define ASN1_BOOLEAN MBEDTLS_ASN1_BOOLEAN +#define ASN1_CHK_ADD MBEDTLS_ASN1_CHK_ADD +#define ASN1_CONSTRUCTED MBEDTLS_ASN1_CONSTRUCTED +#define ASN1_CONTEXT_SPECIFIC MBEDTLS_ASN1_CONTEXT_SPECIFIC +#define ASN1_GENERALIZED_TIME MBEDTLS_ASN1_GENERALIZED_TIME +#define ASN1_IA5_STRING MBEDTLS_ASN1_IA5_STRING +#define ASN1_INTEGER MBEDTLS_ASN1_INTEGER +#define ASN1_NULL MBEDTLS_ASN1_NULL +#define ASN1_OCTET_STRING MBEDTLS_ASN1_OCTET_STRING +#define ASN1_OID MBEDTLS_ASN1_OID +#define ASN1_PRIMITIVE MBEDTLS_ASN1_PRIMITIVE +#define ASN1_PRINTABLE_STRING MBEDTLS_ASN1_PRINTABLE_STRING +#define ASN1_SEQUENCE MBEDTLS_ASN1_SEQUENCE +#define ASN1_SET MBEDTLS_ASN1_SET +#define ASN1_T61_STRING MBEDTLS_ASN1_T61_STRING +#define ASN1_UNIVERSAL_STRING MBEDTLS_ASN1_UNIVERSAL_STRING +#define ASN1_UTC_TIME MBEDTLS_ASN1_UTC_TIME +#define ASN1_UTF8_STRING MBEDTLS_ASN1_UTF8_STRING +#define BADCERT_CN_MISMATCH MBEDTLS_X509_BADCERT_CN_MISMATCH +#define BADCERT_EXPIRED MBEDTLS_X509_BADCERT_EXPIRED +#define BADCERT_FUTURE MBEDTLS_X509_BADCERT_FUTURE +#define BADCERT_MISSING MBEDTLS_X509_BADCERT_MISSING +#define BADCERT_NOT_TRUSTED MBEDTLS_X509_BADCERT_NOT_TRUSTED +#define BADCERT_OTHER MBEDTLS_X509_BADCERT_OTHER +#define BADCERT_REVOKED MBEDTLS_X509_BADCERT_REVOKED +#define BADCERT_SKIP_VERIFY MBEDTLS_X509_BADCERT_SKIP_VERIFY +#define BADCRL_EXPIRED MBEDTLS_X509_BADCRL_EXPIRED +#define BADCRL_FUTURE MBEDTLS_X509_BADCRL_FUTURE +#define BADCRL_NOT_TRUSTED MBEDTLS_X509_BADCRL_NOT_TRUSTED +#define BLOWFISH_BLOCKSIZE MBEDTLS_BLOWFISH_BLOCKSIZE +#define BLOWFISH_DECRYPT MBEDTLS_BLOWFISH_DECRYPT +#define BLOWFISH_ENCRYPT MBEDTLS_BLOWFISH_ENCRYPT +#define BLOWFISH_MAX_KEY MBEDTLS_BLOWFISH_MAX_KEY_BITS +#define BLOWFISH_MIN_KEY MBEDTLS_BLOWFISH_MIN_KEY_BITS +#define BLOWFISH_ROUNDS MBEDTLS_BLOWFISH_ROUNDS +#define CAMELLIA_DECRYPT MBEDTLS_CAMELLIA_DECRYPT +#define CAMELLIA_ENCRYPT MBEDTLS_CAMELLIA_ENCRYPT +#define COLLECT_SIZE MBEDTLS_HAVEGE_COLLECT_SIZE +#define CTR_DRBG_BLOCKSIZE MBEDTLS_CTR_DRBG_BLOCKSIZE +#define CTR_DRBG_ENTROPY_LEN MBEDTLS_CTR_DRBG_ENTROPY_LEN +#define CTR_DRBG_KEYBITS MBEDTLS_CTR_DRBG_KEYBITS +#define CTR_DRBG_KEYSIZE MBEDTLS_CTR_DRBG_KEYSIZE +#define CTR_DRBG_MAX_INPUT MBEDTLS_CTR_DRBG_MAX_INPUT +#define CTR_DRBG_MAX_REQUEST MBEDTLS_CTR_DRBG_MAX_REQUEST +#define CTR_DRBG_MAX_SEED_INPUT MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +#define CTR_DRBG_PR_OFF MBEDTLS_CTR_DRBG_PR_OFF +#define CTR_DRBG_PR_ON MBEDTLS_CTR_DRBG_PR_ON +#define CTR_DRBG_RESEED_INTERVAL MBEDTLS_CTR_DRBG_RESEED_INTERVAL +#define CTR_DRBG_SEEDLEN MBEDTLS_CTR_DRBG_SEEDLEN +#define DEPRECATED MBEDTLS_DEPRECATED +#define DES_DECRYPT MBEDTLS_DES_DECRYPT +#define DES_ENCRYPT MBEDTLS_DES_ENCRYPT +#define DES_KEY_SIZE MBEDTLS_DES_KEY_SIZE +#define ENTROPY_BLOCK_SIZE MBEDTLS_ENTROPY_BLOCK_SIZE +#define ENTROPY_MAX_GATHER MBEDTLS_ENTROPY_MAX_GATHER +#define ENTROPY_MAX_SEED_SIZE MBEDTLS_ENTROPY_MAX_SEED_SIZE +#define ENTROPY_MAX_SOURCES MBEDTLS_ENTROPY_MAX_SOURCES +#define ENTROPY_MIN_HARDCLOCK MBEDTLS_ENTROPY_MIN_HARDCLOCK +#define ENTROPY_MIN_HAVEGE MBEDTLS_ENTROPY_MIN_HAVEGE +#define ENTROPY_MIN_PLATFORM MBEDTLS_ENTROPY_MIN_PLATFORM +#define ENTROPY_SOURCE_MANUAL MBEDTLS_ENTROPY_SOURCE_MANUAL +#define EXT_AUTHORITY_KEY_IDENTIFIER MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER +#define EXT_BASIC_CONSTRAINTS MBEDTLS_X509_EXT_BASIC_CONSTRAINTS +#define EXT_CERTIFICATE_POLICIES MBEDTLS_X509_EXT_CERTIFICATE_POLICIES +#define EXT_CRL_DISTRIBUTION_POINTS MBEDTLS_X509_EXT_CRL_DISTRIBUTION_POINTS +#define EXT_EXTENDED_KEY_USAGE MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE +#define EXT_FRESHEST_CRL MBEDTLS_X509_EXT_FRESHEST_CRL +#define EXT_INIHIBIT_ANYPOLICY MBEDTLS_X509_EXT_INIHIBIT_ANYPOLICY +#define EXT_ISSUER_ALT_NAME MBEDTLS_X509_EXT_ISSUER_ALT_NAME +#define EXT_KEY_USAGE MBEDTLS_X509_EXT_KEY_USAGE +#define EXT_NAME_CONSTRAINTS MBEDTLS_X509_EXT_NAME_CONSTRAINTS +#define EXT_NS_CERT_TYPE MBEDTLS_X509_EXT_NS_CERT_TYPE +#define EXT_POLICY_CONSTRAINTS MBEDTLS_X509_EXT_POLICY_CONSTRAINTS +#define EXT_POLICY_MAPPINGS MBEDTLS_X509_EXT_POLICY_MAPPINGS +#define EXT_SUBJECT_ALT_NAME MBEDTLS_X509_EXT_SUBJECT_ALT_NAME +#define EXT_SUBJECT_DIRECTORY_ATTRS MBEDTLS_X509_EXT_SUBJECT_DIRECTORY_ATTRS +#define EXT_SUBJECT_KEY_IDENTIFIER MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER +#define GCM_DECRYPT MBEDTLS_GCM_DECRYPT +#define GCM_ENCRYPT MBEDTLS_GCM_ENCRYPT +#define KU_CRL_SIGN MBEDTLS_X509_KU_CRL_SIGN +#define KU_DATA_ENCIPHERMENT MBEDTLS_X509_KU_DATA_ENCIPHERMENT +#define KU_DIGITAL_SIGNATURE MBEDTLS_X509_KU_DIGITAL_SIGNATURE +#define KU_KEY_AGREEMENT MBEDTLS_X509_KU_KEY_AGREEMENT +#define KU_KEY_CERT_SIGN MBEDTLS_X509_KU_KEY_CERT_SIGN +#define KU_KEY_ENCIPHERMENT MBEDTLS_X509_KU_KEY_ENCIPHERMENT +#define KU_NON_REPUDIATION MBEDTLS_X509_KU_NON_REPUDIATION +#define LN_2_DIV_LN_10_SCALE100 MBEDTLS_LN_2_DIV_LN_10_SCALE100 +#define MEMORY_VERIFY_ALLOC MBEDTLS_MEMORY_VERIFY_ALLOC +#define MEMORY_VERIFY_ALWAYS MBEDTLS_MEMORY_VERIFY_ALWAYS +#define MEMORY_VERIFY_FREE MBEDTLS_MEMORY_VERIFY_FREE +#define MEMORY_VERIFY_NONE MBEDTLS_MEMORY_VERIFY_NONE +#define MPI_CHK MBEDTLS_MPI_CHK +#define NET_PROTO_TCP MBEDTLS_NET_PROTO_TCP +#define NET_PROTO_UDP MBEDTLS_NET_PROTO_UDP +#define NS_CERT_TYPE_EMAIL MBEDTLS_X509_NS_CERT_TYPE_EMAIL +#define NS_CERT_TYPE_EMAIL_CA MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA +#define NS_CERT_TYPE_OBJECT_SIGNING MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING +#define NS_CERT_TYPE_OBJECT_SIGNING_CA MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA +#define NS_CERT_TYPE_RESERVED MBEDTLS_X509_NS_CERT_TYPE_RESERVED +#define NS_CERT_TYPE_SSL_CA MBEDTLS_X509_NS_CERT_TYPE_SSL_CA +#define NS_CERT_TYPE_SSL_CLIENT MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT +#define NS_CERT_TYPE_SSL_SERVER MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER +#define OID_ANSI_X9_62 MBEDTLS_OID_ANSI_X9_62 +#define OID_ANSI_X9_62_FIELD_TYPE MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE +#define OID_ANSI_X9_62_PRIME_FIELD MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD +#define OID_ANSI_X9_62_SIG MBEDTLS_OID_ANSI_X9_62_SIG +#define OID_ANSI_X9_62_SIG_SHA2 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 +#define OID_ANY_EXTENDED_KEY_USAGE MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE +#define OID_AT MBEDTLS_OID_AT +#define OID_AT_CN MBEDTLS_OID_AT_CN +#define OID_AT_COUNTRY MBEDTLS_OID_AT_COUNTRY +#define OID_AT_DN_QUALIFIER MBEDTLS_OID_AT_DN_QUALIFIER +#define OID_AT_GENERATION_QUALIFIER MBEDTLS_OID_AT_GENERATION_QUALIFIER +#define OID_AT_GIVEN_NAME MBEDTLS_OID_AT_GIVEN_NAME +#define OID_AT_INITIALS MBEDTLS_OID_AT_INITIALS +#define OID_AT_LOCALITY MBEDTLS_OID_AT_LOCALITY +#define OID_AT_ORGANIZATION MBEDTLS_OID_AT_ORGANIZATION +#define OID_AT_ORG_UNIT MBEDTLS_OID_AT_ORG_UNIT +#define OID_AT_POSTAL_ADDRESS MBEDTLS_OID_AT_POSTAL_ADDRESS +#define OID_AT_POSTAL_CODE MBEDTLS_OID_AT_POSTAL_CODE +#define OID_AT_PSEUDONYM MBEDTLS_OID_AT_PSEUDONYM +#define OID_AT_SERIAL_NUMBER MBEDTLS_OID_AT_SERIAL_NUMBER +#define OID_AT_STATE MBEDTLS_OID_AT_STATE +#define OID_AT_SUR_NAME MBEDTLS_OID_AT_SUR_NAME +#define OID_AT_TITLE MBEDTLS_OID_AT_TITLE +#define OID_AT_UNIQUE_IDENTIFIER MBEDTLS_OID_AT_UNIQUE_IDENTIFIER +#define OID_AUTHORITY_KEY_IDENTIFIER MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER +#define OID_BASIC_CONSTRAINTS MBEDTLS_OID_BASIC_CONSTRAINTS +#define OID_CERTICOM MBEDTLS_OID_CERTICOM +#define OID_CERTIFICATE_POLICIES MBEDTLS_OID_CERTIFICATE_POLICIES +#define OID_CLIENT_AUTH MBEDTLS_OID_CLIENT_AUTH +#define OID_CMP MBEDTLS_OID_CMP +#define OID_CODE_SIGNING MBEDTLS_OID_CODE_SIGNING +#define OID_COUNTRY_US MBEDTLS_OID_COUNTRY_US +#define OID_CRL_DISTRIBUTION_POINTS MBEDTLS_OID_CRL_DISTRIBUTION_POINTS +#define OID_CRL_NUMBER MBEDTLS_OID_CRL_NUMBER +#define OID_DES_CBC MBEDTLS_OID_DES_CBC +#define OID_DES_EDE3_CBC MBEDTLS_OID_DES_EDE3_CBC +#define OID_DIGEST_ALG_MD2 MBEDTLS_OID_DIGEST_ALG_MD2 +#define OID_DIGEST_ALG_MD4 MBEDTLS_OID_DIGEST_ALG_MD4 +#define OID_DIGEST_ALG_MD5 MBEDTLS_OID_DIGEST_ALG_MD5 +#define OID_DIGEST_ALG_SHA1 MBEDTLS_OID_DIGEST_ALG_SHA1 +#define OID_DIGEST_ALG_SHA224 MBEDTLS_OID_DIGEST_ALG_SHA224 +#define OID_DIGEST_ALG_SHA256 MBEDTLS_OID_DIGEST_ALG_SHA256 +#define OID_DIGEST_ALG_SHA384 MBEDTLS_OID_DIGEST_ALG_SHA384 +#define OID_DIGEST_ALG_SHA512 MBEDTLS_OID_DIGEST_ALG_SHA512 +#define OID_DOMAIN_COMPONENT MBEDTLS_OID_DOMAIN_COMPONENT +#define OID_ECDSA_SHA1 MBEDTLS_OID_ECDSA_SHA1 +#define OID_ECDSA_SHA224 MBEDTLS_OID_ECDSA_SHA224 +#define OID_ECDSA_SHA256 MBEDTLS_OID_ECDSA_SHA256 +#define OID_ECDSA_SHA384 MBEDTLS_OID_ECDSA_SHA384 +#define OID_ECDSA_SHA512 MBEDTLS_OID_ECDSA_SHA512 +#define OID_EC_ALG_ECDH MBEDTLS_OID_EC_ALG_ECDH +#define OID_EC_ALG_UNRESTRICTED MBEDTLS_OID_EC_ALG_UNRESTRICTED +#define OID_EC_BRAINPOOL_V1 MBEDTLS_OID_EC_BRAINPOOL_V1 +#define OID_EC_GRP_BP256R1 MBEDTLS_OID_EC_GRP_BP256R1 +#define OID_EC_GRP_BP384R1 MBEDTLS_OID_EC_GRP_BP384R1 +#define OID_EC_GRP_BP512R1 MBEDTLS_OID_EC_GRP_BP512R1 +#define OID_EC_GRP_SECP192K1 MBEDTLS_OID_EC_GRP_SECP192K1 +#define OID_EC_GRP_SECP192R1 MBEDTLS_OID_EC_GRP_SECP192R1 +#define OID_EC_GRP_SECP224K1 MBEDTLS_OID_EC_GRP_SECP224K1 +#define OID_EC_GRP_SECP224R1 MBEDTLS_OID_EC_GRP_SECP224R1 +#define OID_EC_GRP_SECP256K1 MBEDTLS_OID_EC_GRP_SECP256K1 +#define OID_EC_GRP_SECP256R1 MBEDTLS_OID_EC_GRP_SECP256R1 +#define OID_EC_GRP_SECP384R1 MBEDTLS_OID_EC_GRP_SECP384R1 +#define OID_EC_GRP_SECP521R1 MBEDTLS_OID_EC_GRP_SECP521R1 +#define OID_EMAIL_PROTECTION MBEDTLS_OID_EMAIL_PROTECTION +#define OID_EXTENDED_KEY_USAGE MBEDTLS_OID_EXTENDED_KEY_USAGE +#define OID_FRESHEST_CRL MBEDTLS_OID_FRESHEST_CRL +#define OID_GOV MBEDTLS_OID_GOV +#define OID_HMAC_SHA1 MBEDTLS_OID_HMAC_SHA1 +#define OID_ID_CE MBEDTLS_OID_ID_CE +#define OID_INIHIBIT_ANYPOLICY MBEDTLS_OID_INIHIBIT_ANYPOLICY +#define OID_ISO_CCITT_DS MBEDTLS_OID_ISO_CCITT_DS +#define OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ISO_IDENTIFIED_ORG +#define OID_ISO_ITU_COUNTRY MBEDTLS_OID_ISO_ITU_COUNTRY +#define OID_ISO_ITU_US_ORG MBEDTLS_OID_ISO_ITU_US_ORG +#define OID_ISO_MEMBER_BODIES MBEDTLS_OID_ISO_MEMBER_BODIES +#define OID_ISSUER_ALT_NAME MBEDTLS_OID_ISSUER_ALT_NAME +#define OID_KEY_USAGE MBEDTLS_OID_KEY_USAGE +#define OID_KP MBEDTLS_OID_KP +#define OID_MGF1 MBEDTLS_OID_MGF1 +#define OID_NAME_CONSTRAINTS MBEDTLS_OID_NAME_CONSTRAINTS +#define OID_NETSCAPE MBEDTLS_OID_NETSCAPE +#define OID_NS_BASE_URL MBEDTLS_OID_NS_BASE_URL +#define OID_NS_CA_POLICY_URL MBEDTLS_OID_NS_CA_POLICY_URL +#define OID_NS_CA_REVOCATION_URL MBEDTLS_OID_NS_CA_REVOCATION_URL +#define OID_NS_CERT MBEDTLS_OID_NS_CERT +#define OID_NS_CERT_SEQUENCE MBEDTLS_OID_NS_CERT_SEQUENCE +#define OID_NS_CERT_TYPE MBEDTLS_OID_NS_CERT_TYPE +#define OID_NS_COMMENT MBEDTLS_OID_NS_COMMENT +#define OID_NS_DATA_TYPE MBEDTLS_OID_NS_DATA_TYPE +#define OID_NS_RENEWAL_URL MBEDTLS_OID_NS_RENEWAL_URL +#define OID_NS_REVOCATION_URL MBEDTLS_OID_NS_REVOCATION_URL +#define OID_NS_SSL_SERVER_NAME MBEDTLS_OID_NS_SSL_SERVER_NAME +#define OID_OCSP_SIGNING MBEDTLS_OID_OCSP_SIGNING +#define OID_OIW_SECSIG MBEDTLS_OID_OIW_SECSIG +#define OID_OIW_SECSIG_ALG MBEDTLS_OID_OIW_SECSIG_ALG +#define OID_OIW_SECSIG_SHA1 MBEDTLS_OID_OIW_SECSIG_SHA1 +#define OID_ORGANIZATION MBEDTLS_OID_ORGANIZATION +#define OID_ORG_ANSI_X9_62 MBEDTLS_OID_ORG_ANSI_X9_62 +#define OID_ORG_CERTICOM MBEDTLS_OID_ORG_CERTICOM +#define OID_ORG_DOD MBEDTLS_OID_ORG_DOD +#define OID_ORG_GOV MBEDTLS_OID_ORG_GOV +#define OID_ORG_NETSCAPE MBEDTLS_OID_ORG_NETSCAPE +#define OID_ORG_OIW MBEDTLS_OID_ORG_OIW +#define OID_ORG_RSA_DATA_SECURITY MBEDTLS_OID_ORG_RSA_DATA_SECURITY +#define OID_ORG_TELETRUST MBEDTLS_OID_ORG_TELETRUST +#define OID_PKCS MBEDTLS_OID_PKCS +#define OID_PKCS1 MBEDTLS_OID_PKCS1 +#define OID_PKCS12 MBEDTLS_OID_PKCS12 +#define OID_PKCS12_PBE MBEDTLS_OID_PKCS12_PBE +#define OID_PKCS12_PBE_SHA1_DES2_EDE_CBC MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC +#define OID_PKCS12_PBE_SHA1_DES3_EDE_CBC MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC +#define OID_PKCS12_PBE_SHA1_RC2_128_CBC MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_128_CBC +#define OID_PKCS12_PBE_SHA1_RC2_40_CBC MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_40_CBC +#define OID_PKCS12_PBE_SHA1_RC4_128 MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128 +#define OID_PKCS12_PBE_SHA1_RC4_40 MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_40 +#define OID_PKCS1_MD2 MBEDTLS_OID_PKCS1_MD2 +#define OID_PKCS1_MD4 MBEDTLS_OID_PKCS1_MD4 +#define OID_PKCS1_MD5 MBEDTLS_OID_PKCS1_MD5 +#define OID_PKCS1_RSA MBEDTLS_OID_PKCS1_RSA +#define OID_PKCS1_SHA1 MBEDTLS_OID_PKCS1_SHA1 +#define OID_PKCS1_SHA224 MBEDTLS_OID_PKCS1_SHA224 +#define OID_PKCS1_SHA256 MBEDTLS_OID_PKCS1_SHA256 +#define OID_PKCS1_SHA384 MBEDTLS_OID_PKCS1_SHA384 +#define OID_PKCS1_SHA512 MBEDTLS_OID_PKCS1_SHA512 +#define OID_PKCS5 MBEDTLS_OID_PKCS5 +#define OID_PKCS5_PBES2 MBEDTLS_OID_PKCS5_PBES2 +#define OID_PKCS5_PBE_MD2_DES_CBC MBEDTLS_OID_PKCS5_PBE_MD2_DES_CBC +#define OID_PKCS5_PBE_MD2_RC2_CBC MBEDTLS_OID_PKCS5_PBE_MD2_RC2_CBC +#define OID_PKCS5_PBE_MD5_DES_CBC MBEDTLS_OID_PKCS5_PBE_MD5_DES_CBC +#define OID_PKCS5_PBE_MD5_RC2_CBC MBEDTLS_OID_PKCS5_PBE_MD5_RC2_CBC +#define OID_PKCS5_PBE_SHA1_DES_CBC MBEDTLS_OID_PKCS5_PBE_SHA1_DES_CBC +#define OID_PKCS5_PBE_SHA1_RC2_CBC MBEDTLS_OID_PKCS5_PBE_SHA1_RC2_CBC +#define OID_PKCS5_PBKDF2 MBEDTLS_OID_PKCS5_PBKDF2 +#define OID_PKCS5_PBMAC1 MBEDTLS_OID_PKCS5_PBMAC1 +#define OID_PKCS9 MBEDTLS_OID_PKCS9 +#define OID_PKCS9_CSR_EXT_REQ MBEDTLS_OID_PKCS9_CSR_EXT_REQ +#define OID_PKCS9_EMAIL MBEDTLS_OID_PKCS9_EMAIL +#define OID_PKIX MBEDTLS_OID_PKIX +#define OID_POLICY_CONSTRAINTS MBEDTLS_OID_POLICY_CONSTRAINTS +#define OID_POLICY_MAPPINGS MBEDTLS_OID_POLICY_MAPPINGS +#define OID_PRIVATE_KEY_USAGE_PERIOD MBEDTLS_OID_PRIVATE_KEY_USAGE_PERIOD +#define OID_RSASSA_PSS MBEDTLS_OID_RSASSA_PSS +#define OID_RSA_COMPANY MBEDTLS_OID_RSA_COMPANY +#define OID_RSA_SHA_OBS MBEDTLS_OID_RSA_SHA_OBS +#define OID_SERVER_AUTH MBEDTLS_OID_SERVER_AUTH +#define OID_SIZE MBEDTLS_OID_SIZE +#define OID_SUBJECT_ALT_NAME MBEDTLS_OID_SUBJECT_ALT_NAME +#define OID_SUBJECT_DIRECTORY_ATTRS MBEDTLS_OID_SUBJECT_DIRECTORY_ATTRS +#define OID_SUBJECT_KEY_IDENTIFIER MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER +#define OID_TELETRUST MBEDTLS_OID_TELETRUST +#define OID_TIME_STAMPING MBEDTLS_OID_TIME_STAMPING +#define PADLOCK_ACE MBEDTLS_PADLOCK_ACE +#define PADLOCK_ALIGN16 MBEDTLS_PADLOCK_ALIGN16 +#define PADLOCK_PHE MBEDTLS_PADLOCK_PHE +#define PADLOCK_PMM MBEDTLS_PADLOCK_PMM +#define PADLOCK_RNG MBEDTLS_PADLOCK_RNG +#define PKCS12_DERIVE_IV MBEDTLS_PKCS12_DERIVE_IV +#define PKCS12_DERIVE_KEY MBEDTLS_PKCS12_DERIVE_KEY +#define PKCS12_DERIVE_MAC_KEY MBEDTLS_PKCS12_DERIVE_MAC_KEY +#define PKCS12_PBE_DECRYPT MBEDTLS_PKCS12_PBE_DECRYPT +#define PKCS12_PBE_ENCRYPT MBEDTLS_PKCS12_PBE_ENCRYPT +#define PKCS5_DECRYPT MBEDTLS_PKCS5_DECRYPT +#define PKCS5_ENCRYPT MBEDTLS_PKCS5_ENCRYPT +#define POLARSSL_AESNI_AES MBEDTLS_AESNI_AES +#define POLARSSL_AESNI_CLMUL MBEDTLS_AESNI_CLMUL +#define POLARSSL_AESNI_H MBEDTLS_AESNI_H +#define POLARSSL_AES_H MBEDTLS_AES_H +#define POLARSSL_ARC4_H MBEDTLS_ARC4_H +#define POLARSSL_ASN1_H MBEDTLS_ASN1_H +#define POLARSSL_ASN1_WRITE_H MBEDTLS_ASN1_WRITE_H +#define POLARSSL_BASE64_H MBEDTLS_BASE64_H +#define POLARSSL_BIGNUM_H MBEDTLS_BIGNUM_H +#define POLARSSL_BLOWFISH_H MBEDTLS_BLOWFISH_H +#define POLARSSL_BN_MUL_H MBEDTLS_BN_MUL_H +#define POLARSSL_CAMELLIA_H MBEDTLS_CAMELLIA_H +#define POLARSSL_CCM_H MBEDTLS_CCM_H +#define POLARSSL_CERTS_H MBEDTLS_CERTS_H +#define POLARSSL_CHECK_CONFIG_H MBEDTLS_CHECK_CONFIG_H +#define POLARSSL_CIPHERSUITE_NODTLS MBEDTLS_CIPHERSUITE_NODTLS +#define POLARSSL_CIPHERSUITE_SHORT_TAG MBEDTLS_CIPHERSUITE_SHORT_TAG +#define POLARSSL_CIPHERSUITE_WEAK MBEDTLS_CIPHERSUITE_WEAK +#define POLARSSL_CIPHER_AES_128_CBC MBEDTLS_CIPHER_AES_128_CBC +#define POLARSSL_CIPHER_AES_128_CCM MBEDTLS_CIPHER_AES_128_CCM +#define POLARSSL_CIPHER_AES_128_CFB128 MBEDTLS_CIPHER_AES_128_CFB128 +#define POLARSSL_CIPHER_AES_128_CTR MBEDTLS_CIPHER_AES_128_CTR +#define POLARSSL_CIPHER_AES_128_ECB MBEDTLS_CIPHER_AES_128_ECB +#define POLARSSL_CIPHER_AES_128_GCM MBEDTLS_CIPHER_AES_128_GCM +#define POLARSSL_CIPHER_AES_192_CBC MBEDTLS_CIPHER_AES_192_CBC +#define POLARSSL_CIPHER_AES_192_CCM MBEDTLS_CIPHER_AES_192_CCM +#define POLARSSL_CIPHER_AES_192_CFB128 MBEDTLS_CIPHER_AES_192_CFB128 +#define POLARSSL_CIPHER_AES_192_CTR MBEDTLS_CIPHER_AES_192_CTR +#define POLARSSL_CIPHER_AES_192_ECB MBEDTLS_CIPHER_AES_192_ECB +#define POLARSSL_CIPHER_AES_192_GCM MBEDTLS_CIPHER_AES_192_GCM +#define POLARSSL_CIPHER_AES_256_CBC MBEDTLS_CIPHER_AES_256_CBC +#define POLARSSL_CIPHER_AES_256_CCM MBEDTLS_CIPHER_AES_256_CCM +#define POLARSSL_CIPHER_AES_256_CFB128 MBEDTLS_CIPHER_AES_256_CFB128 +#define POLARSSL_CIPHER_AES_256_CTR MBEDTLS_CIPHER_AES_256_CTR +#define POLARSSL_CIPHER_AES_256_ECB MBEDTLS_CIPHER_AES_256_ECB +#define POLARSSL_CIPHER_AES_256_GCM MBEDTLS_CIPHER_AES_256_GCM +#define POLARSSL_CIPHER_ARC4_128 MBEDTLS_CIPHER_ARC4_128 +#define POLARSSL_CIPHER_BLOWFISH_CBC MBEDTLS_CIPHER_BLOWFISH_CBC +#define POLARSSL_CIPHER_BLOWFISH_CFB64 MBEDTLS_CIPHER_BLOWFISH_CFB64 +#define POLARSSL_CIPHER_BLOWFISH_CTR MBEDTLS_CIPHER_BLOWFISH_CTR +#define POLARSSL_CIPHER_BLOWFISH_ECB MBEDTLS_CIPHER_BLOWFISH_ECB +#define POLARSSL_CIPHER_CAMELLIA_128_CBC MBEDTLS_CIPHER_CAMELLIA_128_CBC +#define POLARSSL_CIPHER_CAMELLIA_128_CCM MBEDTLS_CIPHER_CAMELLIA_128_CCM +#define POLARSSL_CIPHER_CAMELLIA_128_CFB128 MBEDTLS_CIPHER_CAMELLIA_128_CFB128 +#define POLARSSL_CIPHER_CAMELLIA_128_CTR MBEDTLS_CIPHER_CAMELLIA_128_CTR +#define POLARSSL_CIPHER_CAMELLIA_128_ECB MBEDTLS_CIPHER_CAMELLIA_128_ECB +#define POLARSSL_CIPHER_CAMELLIA_128_GCM MBEDTLS_CIPHER_CAMELLIA_128_GCM +#define POLARSSL_CIPHER_CAMELLIA_192_CBC MBEDTLS_CIPHER_CAMELLIA_192_CBC +#define POLARSSL_CIPHER_CAMELLIA_192_CCM MBEDTLS_CIPHER_CAMELLIA_192_CCM +#define POLARSSL_CIPHER_CAMELLIA_192_CFB128 MBEDTLS_CIPHER_CAMELLIA_192_CFB128 +#define POLARSSL_CIPHER_CAMELLIA_192_CTR MBEDTLS_CIPHER_CAMELLIA_192_CTR +#define POLARSSL_CIPHER_CAMELLIA_192_ECB MBEDTLS_CIPHER_CAMELLIA_192_ECB +#define POLARSSL_CIPHER_CAMELLIA_192_GCM MBEDTLS_CIPHER_CAMELLIA_192_GCM +#define POLARSSL_CIPHER_CAMELLIA_256_CBC MBEDTLS_CIPHER_CAMELLIA_256_CBC +#define POLARSSL_CIPHER_CAMELLIA_256_CCM MBEDTLS_CIPHER_CAMELLIA_256_CCM +#define POLARSSL_CIPHER_CAMELLIA_256_CFB128 MBEDTLS_CIPHER_CAMELLIA_256_CFB128 +#define POLARSSL_CIPHER_CAMELLIA_256_CTR MBEDTLS_CIPHER_CAMELLIA_256_CTR +#define POLARSSL_CIPHER_CAMELLIA_256_ECB MBEDTLS_CIPHER_CAMELLIA_256_ECB +#define POLARSSL_CIPHER_CAMELLIA_256_GCM MBEDTLS_CIPHER_CAMELLIA_256_GCM +#define POLARSSL_CIPHER_DES_CBC MBEDTLS_CIPHER_DES_CBC +#define POLARSSL_CIPHER_DES_ECB MBEDTLS_CIPHER_DES_ECB +#define POLARSSL_CIPHER_DES_EDE3_CBC MBEDTLS_CIPHER_DES_EDE3_CBC +#define POLARSSL_CIPHER_DES_EDE3_ECB MBEDTLS_CIPHER_DES_EDE3_ECB +#define POLARSSL_CIPHER_DES_EDE_CBC MBEDTLS_CIPHER_DES_EDE_CBC +#define POLARSSL_CIPHER_DES_EDE_ECB MBEDTLS_CIPHER_DES_EDE_ECB +#define POLARSSL_CIPHER_H MBEDTLS_CIPHER_H +#define POLARSSL_CIPHER_ID_3DES MBEDTLS_CIPHER_ID_3DES +#define POLARSSL_CIPHER_ID_AES MBEDTLS_CIPHER_ID_AES +#define POLARSSL_CIPHER_ID_ARC4 MBEDTLS_CIPHER_ID_ARC4 +#define POLARSSL_CIPHER_ID_BLOWFISH MBEDTLS_CIPHER_ID_BLOWFISH +#define POLARSSL_CIPHER_ID_CAMELLIA MBEDTLS_CIPHER_ID_CAMELLIA +#define POLARSSL_CIPHER_ID_DES MBEDTLS_CIPHER_ID_DES +#define POLARSSL_CIPHER_ID_NONE MBEDTLS_CIPHER_ID_NONE +#define POLARSSL_CIPHER_ID_NULL MBEDTLS_CIPHER_ID_NULL +#define POLARSSL_CIPHER_MODE_AEAD MBEDTLS_CIPHER_MODE_AEAD +#define POLARSSL_CIPHER_MODE_STREAM MBEDTLS_CIPHER_MODE_STREAM +#define POLARSSL_CIPHER_MODE_WITH_PADDING MBEDTLS_CIPHER_MODE_WITH_PADDING +#define POLARSSL_CIPHER_NONE MBEDTLS_CIPHER_NONE +#define POLARSSL_CIPHER_NULL MBEDTLS_CIPHER_NULL +#define POLARSSL_CIPHER_VARIABLE_IV_LEN MBEDTLS_CIPHER_VARIABLE_IV_LEN +#define POLARSSL_CIPHER_VARIABLE_KEY_LEN MBEDTLS_CIPHER_VARIABLE_KEY_LEN +#define POLARSSL_CIPHER_WRAP_H MBEDTLS_CIPHER_WRAP_H +#define POLARSSL_CONFIG_H MBEDTLS_CONFIG_H +#define POLARSSL_CTR_DRBG_H MBEDTLS_CTR_DRBG_H +#define POLARSSL_DEBUG_H MBEDTLS_DEBUG_H +#define POLARSSL_DECRYPT MBEDTLS_DECRYPT +#define POLARSSL_DES_H MBEDTLS_DES_H +#define POLARSSL_DHM_H MBEDTLS_DHM_H +#define POLARSSL_DHM_RFC3526_MODP_2048_G MBEDTLS_DHM_RFC3526_MODP_2048_G +#define POLARSSL_DHM_RFC3526_MODP_2048_P MBEDTLS_DHM_RFC3526_MODP_2048_P +#define POLARSSL_DHM_RFC3526_MODP_3072_G MBEDTLS_DHM_RFC3526_MODP_3072_G +#define POLARSSL_DHM_RFC3526_MODP_3072_P MBEDTLS_DHM_RFC3526_MODP_3072_P +#define POLARSSL_DHM_RFC5114_MODP_2048_G MBEDTLS_DHM_RFC5114_MODP_2048_G +#define POLARSSL_DHM_RFC5114_MODP_2048_P MBEDTLS_DHM_RFC5114_MODP_2048_P +#define POLARSSL_ECDH_H MBEDTLS_ECDH_H +#define POLARSSL_ECDH_OURS MBEDTLS_ECDH_OURS +#define POLARSSL_ECDH_THEIRS MBEDTLS_ECDH_THEIRS +#define POLARSSL_ECDSA_H MBEDTLS_ECDSA_H +#define POLARSSL_ECP_DP_BP256R1 MBEDTLS_ECP_DP_BP256R1 +#define POLARSSL_ECP_DP_BP384R1 MBEDTLS_ECP_DP_BP384R1 +#define POLARSSL_ECP_DP_BP512R1 MBEDTLS_ECP_DP_BP512R1 +#define POLARSSL_ECP_DP_M255 MBEDTLS_ECP_DP_CURVE25519 +#define POLARSSL_ECP_DP_MAX MBEDTLS_ECP_DP_MAX +#define POLARSSL_ECP_DP_NONE MBEDTLS_ECP_DP_NONE +#define POLARSSL_ECP_DP_SECP192K1 MBEDTLS_ECP_DP_SECP192K1 +#define POLARSSL_ECP_DP_SECP192R1 MBEDTLS_ECP_DP_SECP192R1 +#define POLARSSL_ECP_DP_SECP224K1 MBEDTLS_ECP_DP_SECP224K1 +#define POLARSSL_ECP_DP_SECP224R1 MBEDTLS_ECP_DP_SECP224R1 +#define POLARSSL_ECP_DP_SECP256K1 MBEDTLS_ECP_DP_SECP256K1 +#define POLARSSL_ECP_DP_SECP256R1 MBEDTLS_ECP_DP_SECP256R1 +#define POLARSSL_ECP_DP_SECP384R1 MBEDTLS_ECP_DP_SECP384R1 +#define POLARSSL_ECP_DP_SECP521R1 MBEDTLS_ECP_DP_SECP521R1 +#define POLARSSL_ECP_H MBEDTLS_ECP_H +#define POLARSSL_ECP_MAX_BYTES MBEDTLS_ECP_MAX_BYTES +#define POLARSSL_ECP_MAX_PT_LEN MBEDTLS_ECP_MAX_PT_LEN +#define POLARSSL_ECP_PF_COMPRESSED MBEDTLS_ECP_PF_COMPRESSED +#define POLARSSL_ECP_PF_UNCOMPRESSED MBEDTLS_ECP_PF_UNCOMPRESSED +#define POLARSSL_ECP_TLS_NAMED_CURVE MBEDTLS_ECP_TLS_NAMED_CURVE +#define POLARSSL_ENCRYPT MBEDTLS_ENCRYPT +#define POLARSSL_ENTROPY_H MBEDTLS_ENTROPY_H +#define POLARSSL_ENTROPY_POLL_H MBEDTLS_ENTROPY_POLL_H +#define POLARSSL_ENTROPY_SHA256_ACCUMULATOR MBEDTLS_ENTROPY_SHA256_ACCUMULATOR +#define POLARSSL_ENTROPY_SHA512_ACCUMULATOR MBEDTLS_ENTROPY_SHA512_ACCUMULATOR +#define POLARSSL_ERROR_H MBEDTLS_ERROR_H +#define POLARSSL_ERR_AES_INVALID_INPUT_LENGTH MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH +#define POLARSSL_ERR_AES_INVALID_KEY_LENGTH MBEDTLS_ERR_AES_INVALID_KEY_LENGTH +#define POLARSSL_ERR_ASN1_BUF_TOO_SMALL MBEDTLS_ERR_ASN1_BUF_TOO_SMALL +#define POLARSSL_ERR_ASN1_INVALID_DATA MBEDTLS_ERR_ASN1_INVALID_DATA +#define POLARSSL_ERR_ASN1_INVALID_LENGTH MBEDTLS_ERR_ASN1_INVALID_LENGTH +#define POLARSSL_ERR_ASN1_LENGTH_MISMATCH MBEDTLS_ERR_ASN1_LENGTH_MISMATCH +#define POLARSSL_ERR_ASN1_MALLOC_FAILED MBEDTLS_ERR_ASN1_ALLOC_FAILED +#define POLARSSL_ERR_ASN1_OUT_OF_DATA MBEDTLS_ERR_ASN1_OUT_OF_DATA +#define POLARSSL_ERR_ASN1_UNEXPECTED_TAG MBEDTLS_ERR_ASN1_UNEXPECTED_TAG +#define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL +#define POLARSSL_ERR_BASE64_INVALID_CHARACTER MBEDTLS_ERR_BASE64_INVALID_CHARACTER +#define POLARSSL_ERR_BLOWFISH_INVALID_INPUT_LENGTH MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH +#define POLARSSL_ERR_BLOWFISH_INVALID_KEY_LENGTH MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH +#define POLARSSL_ERR_CAMELLIA_INVALID_INPUT_LENGTH MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH +#define POLARSSL_ERR_CAMELLIA_INVALID_KEY_LENGTH MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH +#define POLARSSL_ERR_CCM_AUTH_FAILED MBEDTLS_ERR_CCM_AUTH_FAILED +#define POLARSSL_ERR_CCM_BAD_INPUT MBEDTLS_ERR_CCM_BAD_INPUT +#define POLARSSL_ERR_CIPHER_ALLOC_FAILED MBEDTLS_ERR_CIPHER_ALLOC_FAILED +#define POLARSSL_ERR_CIPHER_AUTH_FAILED MBEDTLS_ERR_CIPHER_AUTH_FAILED +#define POLARSSL_ERR_CIPHER_BAD_INPUT_DATA MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA +#define POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_CIPHER_FULL_BLOCK_EXPECTED MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED +#define POLARSSL_ERR_CIPHER_INVALID_PADDING MBEDTLS_ERR_CIPHER_INVALID_PADDING +#define POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED +#define POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR +#define POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG +#define POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG +#define POLARSSL_ERR_DES_INVALID_INPUT_LENGTH MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH +#define POLARSSL_ERR_DHM_BAD_INPUT_DATA MBEDTLS_ERR_DHM_BAD_INPUT_DATA +#define POLARSSL_ERR_DHM_CALC_SECRET_FAILED MBEDTLS_ERR_DHM_CALC_SECRET_FAILED +#define POLARSSL_ERR_DHM_FILE_IO_ERROR MBEDTLS_ERR_DHM_FILE_IO_ERROR +#define POLARSSL_ERR_DHM_INVALID_FORMAT MBEDTLS_ERR_DHM_INVALID_FORMAT +#define POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED +#define POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED +#define POLARSSL_ERR_DHM_MALLOC_FAILED MBEDTLS_ERR_DHM_ALLOC_FAILED +#define POLARSSL_ERR_DHM_READ_PARAMS_FAILED MBEDTLS_ERR_DHM_READ_PARAMS_FAILED +#define POLARSSL_ERR_DHM_READ_PUBLIC_FAILED MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED +#define POLARSSL_ERR_ECP_BAD_INPUT_DATA MBEDTLS_ERR_ECP_BAD_INPUT_DATA +#define POLARSSL_ERR_ECP_BUFFER_TOO_SMALL MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL +#define POLARSSL_ERR_ECP_FEATURE_UNAVAILABLE MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_ECP_INVALID_KEY MBEDTLS_ERR_ECP_INVALID_KEY +#define POLARSSL_ERR_ECP_MALLOC_FAILED MBEDTLS_ERR_ECP_ALLOC_FAILED +#define POLARSSL_ERR_ECP_RANDOM_FAILED MBEDTLS_ERR_ECP_RANDOM_FAILED +#define POLARSSL_ERR_ECP_SIG_LEN_MISMATCH MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH +#define POLARSSL_ERR_ECP_VERIFY_FAILED MBEDTLS_ERR_ECP_VERIFY_FAILED +#define POLARSSL_ERR_ENTROPY_FILE_IO_ERROR MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR +#define POLARSSL_ERR_ENTROPY_MAX_SOURCES MBEDTLS_ERR_ENTROPY_MAX_SOURCES +#define POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED +#define POLARSSL_ERR_ENTROPY_SOURCE_FAILED MBEDTLS_ERR_ENTROPY_SOURCE_FAILED +#define POLARSSL_ERR_GCM_AUTH_FAILED MBEDTLS_ERR_GCM_AUTH_FAILED +#define POLARSSL_ERR_GCM_BAD_INPUT MBEDTLS_ERR_GCM_BAD_INPUT +#define POLARSSL_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED +#define POLARSSL_ERR_HMAC_DRBG_FILE_IO_ERROR MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR +#define POLARSSL_ERR_HMAC_DRBG_INPUT_TOO_BIG MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG +#define POLARSSL_ERR_HMAC_DRBG_REQUEST_TOO_BIG MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG +#define POLARSSL_ERR_MD_ALLOC_FAILED MBEDTLS_ERR_MD_ALLOC_FAILED +#define POLARSSL_ERR_MD_BAD_INPUT_DATA MBEDTLS_ERR_MD_BAD_INPUT_DATA +#define POLARSSL_ERR_MD_FEATURE_UNAVAILABLE MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_MD_FILE_IO_ERROR MBEDTLS_ERR_MD_FILE_IO_ERROR +#define POLARSSL_ERR_MPI_BAD_INPUT_DATA MBEDTLS_ERR_MPI_BAD_INPUT_DATA +#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL +#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO MBEDTLS_ERR_MPI_DIVISION_BY_ZERO +#define POLARSSL_ERR_MPI_FILE_IO_ERROR MBEDTLS_ERR_MPI_FILE_IO_ERROR +#define POLARSSL_ERR_MPI_INVALID_CHARACTER MBEDTLS_ERR_MPI_INVALID_CHARACTER +#define POLARSSL_ERR_MPI_MALLOC_FAILED MBEDTLS_ERR_MPI_ALLOC_FAILED +#define POLARSSL_ERR_MPI_NEGATIVE_VALUE MBEDTLS_ERR_MPI_NEGATIVE_VALUE +#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE MBEDTLS_ERR_MPI_NOT_ACCEPTABLE +#define POLARSSL_ERR_NET_ACCEPT_FAILED MBEDTLS_ERR_NET_ACCEPT_FAILED +#define POLARSSL_ERR_NET_BIND_FAILED MBEDTLS_ERR_NET_BIND_FAILED +#define POLARSSL_ERR_NET_CONNECT_FAILED MBEDTLS_ERR_NET_CONNECT_FAILED +#define POLARSSL_ERR_NET_CONN_RESET MBEDTLS_ERR_NET_CONN_RESET +#define POLARSSL_ERR_NET_LISTEN_FAILED MBEDTLS_ERR_NET_LISTEN_FAILED +#define POLARSSL_ERR_NET_RECV_FAILED MBEDTLS_ERR_NET_RECV_FAILED +#define POLARSSL_ERR_NET_SEND_FAILED MBEDTLS_ERR_NET_SEND_FAILED +#define POLARSSL_ERR_NET_SOCKET_FAILED MBEDTLS_ERR_NET_SOCKET_FAILED +#define POLARSSL_ERR_NET_TIMEOUT MBEDTLS_ERR_SSL_TIMEOUT +#define POLARSSL_ERR_NET_UNKNOWN_HOST MBEDTLS_ERR_NET_UNKNOWN_HOST +#define POLARSSL_ERR_NET_WANT_READ MBEDTLS_ERR_SSL_WANT_READ +#define POLARSSL_ERR_NET_WANT_WRITE MBEDTLS_ERR_SSL_WANT_WRITE +#define POLARSSL_ERR_OID_BUF_TOO_SMALL MBEDTLS_ERR_OID_BUF_TOO_SMALL +#define POLARSSL_ERR_OID_NOT_FOUND MBEDTLS_ERR_OID_NOT_FOUND +#define POLARSSL_ERR_PADLOCK_DATA_MISALIGNED MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED +#define POLARSSL_ERR_PEM_BAD_INPUT_DATA MBEDTLS_ERR_PEM_BAD_INPUT_DATA +#define POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_PEM_INVALID_DATA MBEDTLS_ERR_PEM_INVALID_DATA +#define POLARSSL_ERR_PEM_INVALID_ENC_IV MBEDTLS_ERR_PEM_INVALID_ENC_IV +#define POLARSSL_ERR_PEM_MALLOC_FAILED MBEDTLS_ERR_PEM_ALLOC_FAILED +#define POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT +#define POLARSSL_ERR_PEM_PASSWORD_MISMATCH MBEDTLS_ERR_PEM_PASSWORD_MISMATCH +#define POLARSSL_ERR_PEM_PASSWORD_REQUIRED MBEDTLS_ERR_PEM_PASSWORD_REQUIRED +#define POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG +#define POLARSSL_ERR_PKCS12_BAD_INPUT_DATA MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA +#define POLARSSL_ERR_PKCS12_FEATURE_UNAVAILABLE MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_PKCS12_PASSWORD_MISMATCH MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH +#define POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT +#define POLARSSL_ERR_PKCS5_BAD_INPUT_DATA MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA +#define POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_PKCS5_INVALID_FORMAT MBEDTLS_ERR_PKCS5_INVALID_FORMAT +#define POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH +#define POLARSSL_ERR_PK_BAD_INPUT_DATA MBEDTLS_ERR_PK_BAD_INPUT_DATA +#define POLARSSL_ERR_PK_FEATURE_UNAVAILABLE MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_PK_FILE_IO_ERROR MBEDTLS_ERR_PK_FILE_IO_ERROR +#define POLARSSL_ERR_PK_INVALID_ALG MBEDTLS_ERR_PK_INVALID_ALG +#define POLARSSL_ERR_PK_INVALID_PUBKEY MBEDTLS_ERR_PK_INVALID_PUBKEY +#define POLARSSL_ERR_PK_KEY_INVALID_FORMAT MBEDTLS_ERR_PK_KEY_INVALID_FORMAT +#define POLARSSL_ERR_PK_KEY_INVALID_VERSION MBEDTLS_ERR_PK_KEY_INVALID_VERSION +#define POLARSSL_ERR_PK_MALLOC_FAILED MBEDTLS_ERR_PK_ALLOC_FAILED +#define POLARSSL_ERR_PK_PASSWORD_MISMATCH MBEDTLS_ERR_PK_PASSWORD_MISMATCH +#define POLARSSL_ERR_PK_PASSWORD_REQUIRED MBEDTLS_ERR_PK_PASSWORD_REQUIRED +#define POLARSSL_ERR_PK_SIG_LEN_MISMATCH MBEDTLS_ERR_PK_SIG_LEN_MISMATCH +#define POLARSSL_ERR_PK_TYPE_MISMATCH MBEDTLS_ERR_PK_TYPE_MISMATCH +#define POLARSSL_ERR_PK_UNKNOWN_NAMED_CURVE MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE +#define POLARSSL_ERR_PK_UNKNOWN_PK_ALG MBEDTLS_ERR_PK_UNKNOWN_PK_ALG +#define POLARSSL_ERR_RSA_BAD_INPUT_DATA MBEDTLS_ERR_RSA_BAD_INPUT_DATA +#define POLARSSL_ERR_RSA_INVALID_PADDING MBEDTLS_ERR_RSA_INVALID_PADDING +#define POLARSSL_ERR_RSA_KEY_CHECK_FAILED MBEDTLS_ERR_RSA_KEY_CHECK_FAILED +#define POLARSSL_ERR_RSA_KEY_GEN_FAILED MBEDTLS_ERR_RSA_KEY_GEN_FAILED +#define POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE +#define POLARSSL_ERR_RSA_PRIVATE_FAILED MBEDTLS_ERR_RSA_PRIVATE_FAILED +#define POLARSSL_ERR_RSA_PUBLIC_FAILED MBEDTLS_ERR_RSA_PUBLIC_FAILED +#define POLARSSL_ERR_RSA_RNG_FAILED MBEDTLS_ERR_RSA_RNG_FAILED +#define POLARSSL_ERR_RSA_VERIFY_FAILED MBEDTLS_ERR_RSA_VERIFY_FAILED +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY +#define POLARSSL_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP +#define POLARSSL_ERR_SSL_BAD_HS_FINISHED MBEDTLS_ERR_SSL_BAD_HS_FINISHED +#define POLARSSL_ERR_SSL_BAD_HS_NEW_SESSION_TICKET MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET +#define POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO_DONE MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE +#define POLARSSL_ERR_SSL_BAD_INPUT_DATA MBEDTLS_ERR_SSL_BAD_INPUT_DATA +#define POLARSSL_ERR_SSL_BUFFER_TOO_SMALL MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL +#define POLARSSL_ERR_SSL_CA_CHAIN_REQUIRED MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED +#define POLARSSL_ERR_SSL_CERTIFICATE_REQUIRED MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED +#define POLARSSL_ERR_SSL_CERTIFICATE_TOO_LARGE MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE +#define POLARSSL_ERR_SSL_COMPRESSION_FAILED MBEDTLS_ERR_SSL_COMPRESSION_FAILED +#define POLARSSL_ERR_SSL_CONN_EOF MBEDTLS_ERR_SSL_CONN_EOF +#define POLARSSL_ERR_SSL_COUNTER_WRAPPING MBEDTLS_ERR_SSL_COUNTER_WRAPPING +#define POLARSSL_ERR_SSL_FATAL_ALERT_MESSAGE MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE +#define POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_SSL_HELLO_VERIFY_REQUIRED MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED +#define POLARSSL_ERR_SSL_HW_ACCEL_FAILED MBEDTLS_ERR_SSL_HW_ACCEL_FAILED +#define POLARSSL_ERR_SSL_HW_ACCEL_FALLTHROUGH MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH +#define POLARSSL_ERR_SSL_INTERNAL_ERROR MBEDTLS_ERR_SSL_INTERNAL_ERROR +#define POLARSSL_ERR_SSL_INVALID_MAC MBEDTLS_ERR_SSL_INVALID_MAC +#define POLARSSL_ERR_SSL_INVALID_RECORD MBEDTLS_ERR_SSL_INVALID_RECORD +#define POLARSSL_ERR_SSL_MALLOC_FAILED MBEDTLS_ERR_SSL_ALLOC_FAILED +#define POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN +#define POLARSSL_ERR_SSL_NO_CLIENT_CERTIFICATE MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE +#define POLARSSL_ERR_SSL_NO_RNG MBEDTLS_ERR_SSL_NO_RNG +#define POLARSSL_ERR_SSL_NO_USABLE_CIPHERSUITE MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE +#define POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY +#define POLARSSL_ERR_SSL_PEER_VERIFY_FAILED MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED +#define POLARSSL_ERR_SSL_PK_TYPE_MISMATCH MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH +#define POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED +#define POLARSSL_ERR_SSL_SESSION_TICKET_EXPIRED MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED +#define POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE +#define POLARSSL_ERR_SSL_UNKNOWN_CIPHER MBEDTLS_ERR_SSL_UNKNOWN_CIPHER +#define POLARSSL_ERR_SSL_UNKNOWN_IDENTITY MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY +#define POLARSSL_ERR_SSL_WAITING_SERVER_HELLO_RENEGO MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO +#define POLARSSL_ERR_THREADING_BAD_INPUT_DATA MBEDTLS_ERR_THREADING_BAD_INPUT_DATA +#define POLARSSL_ERR_THREADING_FEATURE_UNAVAILABLE MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_THREADING_MUTEX_ERROR MBEDTLS_ERR_THREADING_MUTEX_ERROR +#define POLARSSL_ERR_X509_BAD_INPUT_DATA MBEDTLS_ERR_X509_BAD_INPUT_DATA +#define POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT +#define POLARSSL_ERR_X509_CERT_VERIFY_FAILED MBEDTLS_ERR_X509_CERT_VERIFY_FAILED +#define POLARSSL_ERR_X509_FEATURE_UNAVAILABLE MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_X509_FILE_IO_ERROR MBEDTLS_ERR_X509_FILE_IO_ERROR +#define POLARSSL_ERR_X509_INVALID_ALG MBEDTLS_ERR_X509_INVALID_ALG +#define POLARSSL_ERR_X509_INVALID_DATE MBEDTLS_ERR_X509_INVALID_DATE +#define POLARSSL_ERR_X509_INVALID_EXTENSIONS MBEDTLS_ERR_X509_INVALID_EXTENSIONS +#define POLARSSL_ERR_X509_INVALID_FORMAT MBEDTLS_ERR_X509_INVALID_FORMAT +#define POLARSSL_ERR_X509_INVALID_NAME MBEDTLS_ERR_X509_INVALID_NAME +#define POLARSSL_ERR_X509_INVALID_SERIAL MBEDTLS_ERR_X509_INVALID_SERIAL +#define POLARSSL_ERR_X509_INVALID_SIGNATURE MBEDTLS_ERR_X509_INVALID_SIGNATURE +#define POLARSSL_ERR_X509_INVALID_VERSION MBEDTLS_ERR_X509_INVALID_VERSION +#define POLARSSL_ERR_X509_MALLOC_FAILED MBEDTLS_ERR_X509_ALLOC_FAILED +#define POLARSSL_ERR_X509_SIG_MISMATCH MBEDTLS_ERR_X509_SIG_MISMATCH +#define POLARSSL_ERR_X509_UNKNOWN_OID MBEDTLS_ERR_X509_UNKNOWN_OID +#define POLARSSL_ERR_X509_UNKNOWN_SIG_ALG MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG +#define POLARSSL_ERR_X509_UNKNOWN_VERSION MBEDTLS_ERR_X509_UNKNOWN_VERSION +#define POLARSSL_ERR_XTEA_INVALID_INPUT_LENGTH MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH +#define POLARSSL_GCM_H MBEDTLS_GCM_H +#define POLARSSL_HAVEGE_H MBEDTLS_HAVEGE_H +#define POLARSSL_HAVE_INT32 MBEDTLS_HAVE_INT32 +#define POLARSSL_HAVE_INT64 MBEDTLS_HAVE_INT64 +#define POLARSSL_HAVE_UDBL MBEDTLS_HAVE_UDBL +#define POLARSSL_HAVE_X86 MBEDTLS_HAVE_X86 +#define POLARSSL_HAVE_X86_64 MBEDTLS_HAVE_X86_64 +#define POLARSSL_HMAC_DRBG_H MBEDTLS_HMAC_DRBG_H +#define POLARSSL_HMAC_DRBG_PR_OFF MBEDTLS_HMAC_DRBG_PR_OFF +#define POLARSSL_HMAC_DRBG_PR_ON MBEDTLS_HMAC_DRBG_PR_ON +#define POLARSSL_KEY_EXCHANGE_DHE_PSK MBEDTLS_KEY_EXCHANGE_DHE_PSK +#define POLARSSL_KEY_EXCHANGE_DHE_RSA MBEDTLS_KEY_EXCHANGE_DHE_RSA +#define POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA +#define POLARSSL_KEY_EXCHANGE_ECDHE_PSK MBEDTLS_KEY_EXCHANGE_ECDHE_PSK +#define POLARSSL_KEY_EXCHANGE_ECDHE_RSA MBEDTLS_KEY_EXCHANGE_ECDHE_RSA +#define POLARSSL_KEY_EXCHANGE_ECDH_ECDSA MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA +#define POLARSSL_KEY_EXCHANGE_ECDH_RSA MBEDTLS_KEY_EXCHANGE_ECDH_RSA +#define POLARSSL_KEY_EXCHANGE_NONE MBEDTLS_KEY_EXCHANGE_NONE +#define POLARSSL_KEY_EXCHANGE_PSK MBEDTLS_KEY_EXCHANGE_PSK +#define POLARSSL_KEY_EXCHANGE_RSA MBEDTLS_KEY_EXCHANGE_RSA +#define POLARSSL_KEY_EXCHANGE_RSA_PSK MBEDTLS_KEY_EXCHANGE_RSA_PSK +#define POLARSSL_KEY_EXCHANGE__SOME__ECDHE_ENABLED MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED +#define POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED +#define POLARSSL_KEY_LENGTH_DES MBEDTLS_KEY_LENGTH_DES +#define POLARSSL_KEY_LENGTH_DES_EDE MBEDTLS_KEY_LENGTH_DES_EDE +#define POLARSSL_KEY_LENGTH_DES_EDE3 MBEDTLS_KEY_LENGTH_DES_EDE3 +#define POLARSSL_KEY_LENGTH_NONE MBEDTLS_KEY_LENGTH_NONE +#define POLARSSL_MAX_BLOCK_LENGTH MBEDTLS_MAX_BLOCK_LENGTH +#define POLARSSL_MAX_IV_LENGTH MBEDTLS_MAX_IV_LENGTH +#define POLARSSL_MD2_H MBEDTLS_MD2_H +#define POLARSSL_MD4_H MBEDTLS_MD4_H +#define POLARSSL_MD5_H MBEDTLS_MD5_H +#define POLARSSL_MD_H MBEDTLS_MD_H +#define POLARSSL_MD_MAX_SIZE MBEDTLS_MD_MAX_SIZE +#define POLARSSL_MD_MD2 MBEDTLS_MD_MD2 +#define POLARSSL_MD_MD4 MBEDTLS_MD_MD4 +#define POLARSSL_MD_MD5 MBEDTLS_MD_MD5 +#define POLARSSL_MD_NONE MBEDTLS_MD_NONE +#define POLARSSL_MD_RIPEMD160 MBEDTLS_MD_RIPEMD160 +#define POLARSSL_MD_SHA1 MBEDTLS_MD_SHA1 +#define POLARSSL_MD_SHA224 MBEDTLS_MD_SHA224 +#define POLARSSL_MD_SHA256 MBEDTLS_MD_SHA256 +#define POLARSSL_MD_SHA384 MBEDTLS_MD_SHA384 +#define POLARSSL_MD_SHA512 MBEDTLS_MD_SHA512 +#define POLARSSL_MD_WRAP_H MBEDTLS_MD_WRAP_H +#define POLARSSL_MEMORY_BUFFER_ALLOC_H MBEDTLS_MEMORY_BUFFER_ALLOC_H +#define POLARSSL_MODE_CBC MBEDTLS_MODE_CBC +#define POLARSSL_MODE_CCM MBEDTLS_MODE_CCM +#define POLARSSL_MODE_CFB MBEDTLS_MODE_CFB +#define POLARSSL_MODE_CTR MBEDTLS_MODE_CTR +#define POLARSSL_MODE_ECB MBEDTLS_MODE_ECB +#define POLARSSL_MODE_GCM MBEDTLS_MODE_GCM +#define POLARSSL_MODE_NONE MBEDTLS_MODE_NONE +#define POLARSSL_MODE_OFB MBEDTLS_MODE_OFB +#define POLARSSL_MODE_STREAM MBEDTLS_MODE_STREAM +#define POLARSSL_MPI_MAX_BITS MBEDTLS_MPI_MAX_BITS +#define POLARSSL_MPI_MAX_BITS_SCALE100 MBEDTLS_MPI_MAX_BITS_SCALE100 +#define POLARSSL_MPI_MAX_LIMBS MBEDTLS_MPI_MAX_LIMBS +#define POLARSSL_MPI_RW_BUFFER_SIZE MBEDTLS_MPI_RW_BUFFER_SIZE +#define POLARSSL_NET_H MBEDTLS_NET_SOCKETS_H +#define POLARSSL_NET_LISTEN_BACKLOG MBEDTLS_NET_LISTEN_BACKLOG +#define POLARSSL_OID_H MBEDTLS_OID_H +#define POLARSSL_OPERATION_NONE MBEDTLS_OPERATION_NONE +#define POLARSSL_PADDING_NONE MBEDTLS_PADDING_NONE +#define POLARSSL_PADDING_ONE_AND_ZEROS MBEDTLS_PADDING_ONE_AND_ZEROS +#define POLARSSL_PADDING_PKCS7 MBEDTLS_PADDING_PKCS7 +#define POLARSSL_PADDING_ZEROS MBEDTLS_PADDING_ZEROS +#define POLARSSL_PADDING_ZEROS_AND_LEN MBEDTLS_PADDING_ZEROS_AND_LEN +#define POLARSSL_PADLOCK_H MBEDTLS_PADLOCK_H +#define POLARSSL_PEM_H MBEDTLS_PEM_H +#define POLARSSL_PKCS11_H MBEDTLS_PKCS11_H +#define POLARSSL_PKCS12_H MBEDTLS_PKCS12_H +#define POLARSSL_PKCS5_H MBEDTLS_PKCS5_H +#define POLARSSL_PK_DEBUG_ECP MBEDTLS_PK_DEBUG_ECP +#define POLARSSL_PK_DEBUG_MAX_ITEMS MBEDTLS_PK_DEBUG_MAX_ITEMS +#define POLARSSL_PK_DEBUG_MPI MBEDTLS_PK_DEBUG_MPI +#define POLARSSL_PK_DEBUG_NONE MBEDTLS_PK_DEBUG_NONE +#define POLARSSL_PK_ECDSA MBEDTLS_PK_ECDSA +#define POLARSSL_PK_ECKEY MBEDTLS_PK_ECKEY +#define POLARSSL_PK_ECKEY_DH MBEDTLS_PK_ECKEY_DH +#define POLARSSL_PK_H MBEDTLS_PK_H +#define POLARSSL_PK_NONE MBEDTLS_PK_NONE +#define POLARSSL_PK_RSA MBEDTLS_PK_RSA +#define POLARSSL_PK_RSASSA_PSS MBEDTLS_PK_RSASSA_PSS +#define POLARSSL_PK_RSA_ALT MBEDTLS_PK_RSA_ALT +#define POLARSSL_PK_WRAP_H MBEDTLS_PK_WRAP_H +#define POLARSSL_PLATFORM_H MBEDTLS_PLATFORM_H +#define POLARSSL_PREMASTER_SIZE MBEDTLS_PREMASTER_SIZE +#define POLARSSL_RIPEMD160_H MBEDTLS_RIPEMD160_H +#define POLARSSL_RSA_H MBEDTLS_RSA_H +#define POLARSSL_SHA1_H MBEDTLS_SHA1_H +#define POLARSSL_SHA256_H MBEDTLS_SHA256_H +#define POLARSSL_SHA512_H MBEDTLS_SHA512_H +#define POLARSSL_SSL_CACHE_H MBEDTLS_SSL_CACHE_H +#define POLARSSL_SSL_CIPHERSUITES_H MBEDTLS_SSL_CIPHERSUITES_H +#define POLARSSL_SSL_COOKIE_H MBEDTLS_SSL_COOKIE_H +#define POLARSSL_SSL_H MBEDTLS_SSL_H +#define POLARSSL_THREADING_H MBEDTLS_THREADING_H +#define POLARSSL_THREADING_IMPL MBEDTLS_THREADING_IMPL +#define POLARSSL_TIMING_H MBEDTLS_TIMING_H +#define POLARSSL_VERSION_H MBEDTLS_VERSION_H +#define POLARSSL_VERSION_MAJOR MBEDTLS_VERSION_MAJOR +#define POLARSSL_VERSION_MINOR MBEDTLS_VERSION_MINOR +#define POLARSSL_VERSION_NUMBER MBEDTLS_VERSION_NUMBER +#define POLARSSL_VERSION_PATCH MBEDTLS_VERSION_PATCH +#define POLARSSL_VERSION_STRING MBEDTLS_VERSION_STRING +#define POLARSSL_VERSION_STRING_FULL MBEDTLS_VERSION_STRING_FULL +#define POLARSSL_X509_CRL_H MBEDTLS_X509_CRL_H +#define POLARSSL_X509_CRT_H MBEDTLS_X509_CRT_H +#define POLARSSL_X509_CSR_H MBEDTLS_X509_CSR_H +#define POLARSSL_X509_H MBEDTLS_X509_H +#define POLARSSL_XTEA_H MBEDTLS_XTEA_H +#define RSA_CRYPT MBEDTLS_RSA_CRYPT +#define RSA_PKCS_V15 MBEDTLS_RSA_PKCS_V15 +#define RSA_PKCS_V21 MBEDTLS_RSA_PKCS_V21 +#define RSA_PRIVATE MBEDTLS_RSA_PRIVATE +#define RSA_PUBLIC MBEDTLS_RSA_PUBLIC +#define RSA_SALT_LEN_ANY MBEDTLS_RSA_SALT_LEN_ANY +#define RSA_SIGN MBEDTLS_RSA_SIGN +#define SSL_ALERT_LEVEL_FATAL MBEDTLS_SSL_ALERT_LEVEL_FATAL +#define SSL_ALERT_LEVEL_WARNING MBEDTLS_SSL_ALERT_LEVEL_WARNING +#define SSL_ALERT_MSG_ACCESS_DENIED MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED +#define SSL_ALERT_MSG_BAD_CERT MBEDTLS_SSL_ALERT_MSG_BAD_CERT +#define SSL_ALERT_MSG_BAD_RECORD_MAC MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC +#define SSL_ALERT_MSG_CERT_EXPIRED MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED +#define SSL_ALERT_MSG_CERT_REVOKED MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED +#define SSL_ALERT_MSG_CERT_UNKNOWN MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN +#define SSL_ALERT_MSG_CLOSE_NOTIFY MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY +#define SSL_ALERT_MSG_DECODE_ERROR MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR +#define SSL_ALERT_MSG_DECOMPRESSION_FAILURE MBEDTLS_SSL_ALERT_MSG_DECOMPRESSION_FAILURE +#define SSL_ALERT_MSG_DECRYPTION_FAILED MBEDTLS_SSL_ALERT_MSG_DECRYPTION_FAILED +#define SSL_ALERT_MSG_DECRYPT_ERROR MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR +#define SSL_ALERT_MSG_EXPORT_RESTRICTION MBEDTLS_SSL_ALERT_MSG_EXPORT_RESTRICTION +#define SSL_ALERT_MSG_HANDSHAKE_FAILURE MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE +#define SSL_ALERT_MSG_ILLEGAL_PARAMETER MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER +#define SSL_ALERT_MSG_INAPROPRIATE_FALLBACK MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK +#define SSL_ALERT_MSG_INSUFFICIENT_SECURITY MBEDTLS_SSL_ALERT_MSG_INSUFFICIENT_SECURITY +#define SSL_ALERT_MSG_INTERNAL_ERROR MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR +#define SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL +#define SSL_ALERT_MSG_NO_CERT MBEDTLS_SSL_ALERT_MSG_NO_CERT +#define SSL_ALERT_MSG_NO_RENEGOTIATION MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION +#define SSL_ALERT_MSG_PROTOCOL_VERSION MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION +#define SSL_ALERT_MSG_RECORD_OVERFLOW MBEDTLS_SSL_ALERT_MSG_RECORD_OVERFLOW +#define SSL_ALERT_MSG_UNEXPECTED_MESSAGE MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE +#define SSL_ALERT_MSG_UNKNOWN_CA MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA +#define SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY +#define SSL_ALERT_MSG_UNRECOGNIZED_NAME MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME +#define SSL_ALERT_MSG_UNSUPPORTED_CERT MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT +#define SSL_ALERT_MSG_UNSUPPORTED_EXT MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_EXT +#define SSL_ALERT_MSG_USER_CANCELED MBEDTLS_SSL_ALERT_MSG_USER_CANCELED +#define SSL_ANTI_REPLAY_DISABLED MBEDTLS_SSL_ANTI_REPLAY_DISABLED +#define SSL_ANTI_REPLAY_ENABLED MBEDTLS_SSL_ANTI_REPLAY_ENABLED +#define SSL_ARC4_DISABLED MBEDTLS_SSL_ARC4_DISABLED +#define SSL_ARC4_ENABLED MBEDTLS_SSL_ARC4_ENABLED +#define SSL_BUFFER_LEN ( ( ( MBEDTLS_SSL_IN_BUFFER_LEN ) < ( MBEDTLS_SSL_OUT_BUFFER_LEN ) ) \ + ? ( MBEDTLS_SSL_IN_BUFFER_LEN ) : ( MBEDTLS_SSL_OUT_BUFFER_LEN ) ) +#define SSL_CACHE_DEFAULT_MAX_ENTRIES MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES +#define SSL_CACHE_DEFAULT_TIMEOUT MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT +#define SSL_CBC_RECORD_SPLITTING_DISABLED MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED +#define SSL_CBC_RECORD_SPLITTING_ENABLED MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED +#define SSL_CERTIFICATE_REQUEST MBEDTLS_SSL_CERTIFICATE_REQUEST +#define SSL_CERTIFICATE_VERIFY MBEDTLS_SSL_CERTIFICATE_VERIFY +#define SSL_CERT_TYPE_ECDSA_SIGN MBEDTLS_SSL_CERT_TYPE_ECDSA_SIGN +#define SSL_CERT_TYPE_RSA_SIGN MBEDTLS_SSL_CERT_TYPE_RSA_SIGN +#define SSL_CHANNEL_INBOUND MBEDTLS_SSL_CHANNEL_INBOUND +#define SSL_CHANNEL_OUTBOUND MBEDTLS_SSL_CHANNEL_OUTBOUND +#define SSL_CIPHERSUITES MBEDTLS_SSL_CIPHERSUITES +#define SSL_CLIENT_CERTIFICATE MBEDTLS_SSL_CLIENT_CERTIFICATE +#define SSL_CLIENT_CHANGE_CIPHER_SPEC MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC +#define SSL_CLIENT_FINISHED MBEDTLS_SSL_CLIENT_FINISHED +#define SSL_CLIENT_HELLO MBEDTLS_SSL_CLIENT_HELLO +#define SSL_CLIENT_KEY_EXCHANGE MBEDTLS_SSL_CLIENT_KEY_EXCHANGE +#define SSL_COMPRESSION_ADD MBEDTLS_SSL_COMPRESSION_ADD +#define SSL_COMPRESS_DEFLATE MBEDTLS_SSL_COMPRESS_DEFLATE +#define SSL_COMPRESS_NULL MBEDTLS_SSL_COMPRESS_NULL +#define SSL_DEBUG_BUF MBEDTLS_SSL_DEBUG_BUF +#define SSL_DEBUG_CRT MBEDTLS_SSL_DEBUG_CRT +#define SSL_DEBUG_ECP MBEDTLS_SSL_DEBUG_ECP +#define SSL_DEBUG_MPI MBEDTLS_SSL_DEBUG_MPI +#define SSL_DEBUG_MSG MBEDTLS_SSL_DEBUG_MSG +#define SSL_DEBUG_RET MBEDTLS_SSL_DEBUG_RET +#define SSL_DEFAULT_TICKET_LIFETIME MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME +#define SSL_DTLS_TIMEOUT_DFL_MAX MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MAX +#define SSL_DTLS_TIMEOUT_DFL_MIN MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN +#define SSL_EMPTY_RENEGOTIATION_INFO MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO +#define SSL_ETM_DISABLED MBEDTLS_SSL_ETM_DISABLED +#define SSL_ETM_ENABLED MBEDTLS_SSL_ETM_ENABLED +#define SSL_EXTENDED_MS_DISABLED MBEDTLS_SSL_EXTENDED_MS_DISABLED +#define SSL_EXTENDED_MS_ENABLED MBEDTLS_SSL_EXTENDED_MS_ENABLED +#define SSL_FALLBACK_SCSV MBEDTLS_SSL_FALLBACK_SCSV +#define SSL_FLUSH_BUFFERS MBEDTLS_SSL_FLUSH_BUFFERS +#define SSL_HANDSHAKE_OVER MBEDTLS_SSL_HANDSHAKE_OVER +#define SSL_HANDSHAKE_WRAPUP MBEDTLS_SSL_HANDSHAKE_WRAPUP +#define SSL_HASH_MD5 MBEDTLS_SSL_HASH_MD5 +#define SSL_HASH_NONE MBEDTLS_SSL_HASH_NONE +#define SSL_HASH_SHA1 MBEDTLS_SSL_HASH_SHA1 +#define SSL_HASH_SHA224 MBEDTLS_SSL_HASH_SHA224 +#define SSL_HASH_SHA256 MBEDTLS_SSL_HASH_SHA256 +#define SSL_HASH_SHA384 MBEDTLS_SSL_HASH_SHA384 +#define SSL_HASH_SHA512 MBEDTLS_SSL_HASH_SHA512 +#define SSL_HELLO_REQUEST MBEDTLS_SSL_HELLO_REQUEST +#define SSL_HS_CERTIFICATE MBEDTLS_SSL_HS_CERTIFICATE +#define SSL_HS_CERTIFICATE_REQUEST MBEDTLS_SSL_HS_CERTIFICATE_REQUEST +#define SSL_HS_CERTIFICATE_VERIFY MBEDTLS_SSL_HS_CERTIFICATE_VERIFY +#define SSL_HS_CLIENT_HELLO MBEDTLS_SSL_HS_CLIENT_HELLO +#define SSL_HS_CLIENT_KEY_EXCHANGE MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE +#define SSL_HS_FINISHED MBEDTLS_SSL_HS_FINISHED +#define SSL_HS_HELLO_REQUEST MBEDTLS_SSL_HS_HELLO_REQUEST +#define SSL_HS_HELLO_VERIFY_REQUEST MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST +#define SSL_HS_NEW_SESSION_TICKET MBEDTLS_SSL_HS_NEW_SESSION_TICKET +#define SSL_HS_SERVER_HELLO MBEDTLS_SSL_HS_SERVER_HELLO +#define SSL_HS_SERVER_HELLO_DONE MBEDTLS_SSL_HS_SERVER_HELLO_DONE +#define SSL_HS_SERVER_KEY_EXCHANGE MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE +#define SSL_INITIAL_HANDSHAKE MBEDTLS_SSL_INITIAL_HANDSHAKE +#define SSL_IS_CLIENT MBEDTLS_SSL_IS_CLIENT +#define SSL_IS_FALLBACK MBEDTLS_SSL_IS_FALLBACK +#define SSL_IS_NOT_FALLBACK MBEDTLS_SSL_IS_NOT_FALLBACK +#define SSL_IS_SERVER MBEDTLS_SSL_IS_SERVER +#define SSL_LEGACY_ALLOW_RENEGOTIATION MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION +#define SSL_LEGACY_BREAK_HANDSHAKE MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE +#define SSL_LEGACY_NO_RENEGOTIATION MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION +#define SSL_LEGACY_RENEGOTIATION MBEDTLS_SSL_LEGACY_RENEGOTIATION +#define SSL_MAC_ADD MBEDTLS_SSL_MAC_ADD +#define SSL_MAJOR_VERSION_3 MBEDTLS_SSL_MAJOR_VERSION_3 +#define SSL_MAX_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN +#define SSL_MAX_FRAG_LEN_1024 MBEDTLS_SSL_MAX_FRAG_LEN_1024 +#define SSL_MAX_FRAG_LEN_2048 MBEDTLS_SSL_MAX_FRAG_LEN_2048 +#define SSL_MAX_FRAG_LEN_4096 MBEDTLS_SSL_MAX_FRAG_LEN_4096 +#define SSL_MAX_FRAG_LEN_512 MBEDTLS_SSL_MAX_FRAG_LEN_512 +#define SSL_MAX_FRAG_LEN_INVALID MBEDTLS_SSL_MAX_FRAG_LEN_INVALID +#define SSL_MAX_FRAG_LEN_NONE MBEDTLS_SSL_MAX_FRAG_LEN_NONE +#define SSL_MAX_MAJOR_VERSION MBEDTLS_SSL_MAX_MAJOR_VERSION +#define SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MAX_MINOR_VERSION +#define SSL_MINOR_VERSION_0 MBEDTLS_SSL_MINOR_VERSION_0 +#define SSL_MINOR_VERSION_1 MBEDTLS_SSL_MINOR_VERSION_1 +#define SSL_MINOR_VERSION_2 MBEDTLS_SSL_MINOR_VERSION_2 +#define SSL_MINOR_VERSION_3 MBEDTLS_SSL_MINOR_VERSION_3 +#define SSL_MIN_MAJOR_VERSION MBEDTLS_SSL_MIN_MAJOR_VERSION +#define SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MIN_MINOR_VERSION +#define SSL_MSG_ALERT MBEDTLS_SSL_MSG_ALERT +#define SSL_MSG_APPLICATION_DATA MBEDTLS_SSL_MSG_APPLICATION_DATA +#define SSL_MSG_CHANGE_CIPHER_SPEC MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC +#define SSL_MSG_HANDSHAKE MBEDTLS_SSL_MSG_HANDSHAKE +#define SSL_PADDING_ADD MBEDTLS_SSL_PADDING_ADD +#define SSL_RENEGOTIATION MBEDTLS_SSL_RENEGOTIATION +#define SSL_RENEGOTIATION_DISABLED MBEDTLS_SSL_RENEGOTIATION_DISABLED +#define SSL_RENEGOTIATION_DONE MBEDTLS_SSL_RENEGOTIATION_DONE +#define SSL_RENEGOTIATION_ENABLED MBEDTLS_SSL_RENEGOTIATION_ENABLED +#define SSL_RENEGOTIATION_NOT_ENFORCED MBEDTLS_SSL_RENEGOTIATION_NOT_ENFORCED +#define SSL_RENEGOTIATION_PENDING MBEDTLS_SSL_RENEGOTIATION_PENDING +#define SSL_RENEGO_MAX_RECORDS_DEFAULT MBEDTLS_SSL_RENEGO_MAX_RECORDS_DEFAULT +#define SSL_RETRANS_FINISHED MBEDTLS_SSL_RETRANS_FINISHED +#define SSL_RETRANS_PREPARING MBEDTLS_SSL_RETRANS_PREPARING +#define SSL_RETRANS_SENDING MBEDTLS_SSL_RETRANS_SENDING +#define SSL_RETRANS_WAITING MBEDTLS_SSL_RETRANS_WAITING +#define SSL_SECURE_RENEGOTIATION MBEDTLS_SSL_SECURE_RENEGOTIATION +#define SSL_SERVER_CERTIFICATE MBEDTLS_SSL_SERVER_CERTIFICATE +#define SSL_SERVER_CHANGE_CIPHER_SPEC MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC +#define SSL_SERVER_FINISHED MBEDTLS_SSL_SERVER_FINISHED +#define SSL_SERVER_HELLO MBEDTLS_SSL_SERVER_HELLO +#define SSL_SERVER_HELLO_DONE MBEDTLS_SSL_SERVER_HELLO_DONE +#define SSL_SERVER_HELLO_VERIFY_REQUEST_SENT MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT +#define SSL_SERVER_KEY_EXCHANGE MBEDTLS_SSL_SERVER_KEY_EXCHANGE +#define SSL_SERVER_NEW_SESSION_TICKET MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET +#define SSL_SESSION_TICKETS_DISABLED MBEDTLS_SSL_SESSION_TICKETS_DISABLED +#define SSL_SESSION_TICKETS_ENABLED MBEDTLS_SSL_SESSION_TICKETS_ENABLED +#define SSL_SIG_ANON MBEDTLS_SSL_SIG_ANON +#define SSL_SIG_ECDSA MBEDTLS_SSL_SIG_ECDSA +#define SSL_SIG_RSA MBEDTLS_SSL_SIG_RSA +#define SSL_TRANSPORT_DATAGRAM MBEDTLS_SSL_TRANSPORT_DATAGRAM +#define SSL_TRANSPORT_STREAM MBEDTLS_SSL_TRANSPORT_STREAM +#define SSL_TRUNCATED_HMAC_LEN MBEDTLS_SSL_TRUNCATED_HMAC_LEN +#define SSL_TRUNC_HMAC_DISABLED MBEDTLS_SSL_TRUNC_HMAC_DISABLED +#define SSL_TRUNC_HMAC_ENABLED MBEDTLS_SSL_TRUNC_HMAC_ENABLED +#define SSL_VERIFY_DATA_MAX_LEN MBEDTLS_SSL_VERIFY_DATA_MAX_LEN +#define SSL_VERIFY_NONE MBEDTLS_SSL_VERIFY_NONE +#define SSL_VERIFY_OPTIONAL MBEDTLS_SSL_VERIFY_OPTIONAL +#define SSL_VERIFY_REQUIRED MBEDTLS_SSL_VERIFY_REQUIRED +#define TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA +#define TLS_DHE_PSK_WITH_AES_128_CBC_SHA MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA +#define TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 +#define TLS_DHE_PSK_WITH_AES_128_CCM MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM +#define TLS_DHE_PSK_WITH_AES_128_CCM_8 MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8 +#define TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 +#define TLS_DHE_PSK_WITH_AES_256_CBC_SHA MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA +#define TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 +#define TLS_DHE_PSK_WITH_AES_256_CCM MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM +#define TLS_DHE_PSK_WITH_AES_256_CCM_8 MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8 +#define TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 +#define TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_DHE_PSK_WITH_NULL_SHA MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA +#define TLS_DHE_PSK_WITH_NULL_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 +#define TLS_DHE_PSK_WITH_NULL_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 +#define TLS_DHE_PSK_WITH_RC4_128_SHA MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA +#define TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA +#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA +#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 +#define TLS_DHE_RSA_WITH_AES_128_CCM MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM +#define TLS_DHE_RSA_WITH_AES_128_CCM_8 MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8 +#define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 +#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA +#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 +#define TLS_DHE_RSA_WITH_AES_256_CCM MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM +#define TLS_DHE_RSA_WITH_AES_256_CCM_8 MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8 +#define TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 +#define TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA +#define TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA +#define TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 +#define TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_DHE_RSA_WITH_DES_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA +#define TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA +#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 +#define TLS_ECDHE_ECDSA_WITH_AES_128_CCM MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM +#define TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 +#define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 +#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA +#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 +#define TLS_ECDHE_ECDSA_WITH_AES_256_CCM MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM +#define TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 +#define TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 +#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_ECDHE_ECDSA_WITH_NULL_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA +#define TLS_ECDHE_ECDSA_WITH_RC4_128_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA +#define TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA +#define TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 +#define TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA +#define TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 +#define TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDHE_PSK_WITH_NULL_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA +#define TLS_ECDHE_PSK_WITH_NULL_SHA256 MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 +#define TLS_ECDHE_PSK_WITH_NULL_SHA384 MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 +#define TLS_ECDHE_PSK_WITH_RC4_128_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA +#define TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA +#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 +#define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 +#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 +#define TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 +#define TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_ECDHE_RSA_WITH_NULL_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA +#define TLS_ECDHE_RSA_WITH_RC4_128_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA +#define TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA +#define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 +#define TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 +#define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA +#define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 +#define TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 +#define TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_ECDH_ECDSA_WITH_NULL_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA +#define TLS_ECDH_ECDSA_WITH_RC4_128_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA +#define TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA +#define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 +#define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 +#define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA +#define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 +#define TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 +#define TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_ECDH_RSA_WITH_NULL_SHA MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA +#define TLS_ECDH_RSA_WITH_RC4_128_SHA MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA +#define TLS_EXT_ALPN MBEDTLS_TLS_EXT_ALPN +#define TLS_EXT_ENCRYPT_THEN_MAC MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC +#define TLS_EXT_EXTENDED_MASTER_SECRET MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET +#define TLS_EXT_MAX_FRAGMENT_LENGTH MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH +#define TLS_EXT_RENEGOTIATION_INFO MBEDTLS_TLS_EXT_RENEGOTIATION_INFO +#define TLS_EXT_SERVERNAME MBEDTLS_TLS_EXT_SERVERNAME +#define TLS_EXT_SERVERNAME_HOSTNAME MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME +#define TLS_EXT_SESSION_TICKET MBEDTLS_TLS_EXT_SESSION_TICKET +#define TLS_EXT_SIG_ALG MBEDTLS_TLS_EXT_SIG_ALG +#define TLS_EXT_SUPPORTED_ELLIPTIC_CURVES MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES +#define TLS_EXT_SUPPORTED_POINT_FORMATS MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS +#define TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT +#define TLS_EXT_TRUNCATED_HMAC MBEDTLS_TLS_EXT_TRUNCATED_HMAC +#define TLS_PSK_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA +#define TLS_PSK_WITH_AES_128_CBC_SHA MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA +#define TLS_PSK_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 +#define TLS_PSK_WITH_AES_128_CCM MBEDTLS_TLS_PSK_WITH_AES_128_CCM +#define TLS_PSK_WITH_AES_128_CCM_8 MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8 +#define TLS_PSK_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 +#define TLS_PSK_WITH_AES_256_CBC_SHA MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA +#define TLS_PSK_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 +#define TLS_PSK_WITH_AES_256_CCM MBEDTLS_TLS_PSK_WITH_AES_256_CCM +#define TLS_PSK_WITH_AES_256_CCM_8 MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8 +#define TLS_PSK_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 +#define TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_PSK_WITH_NULL_SHA MBEDTLS_TLS_PSK_WITH_NULL_SHA +#define TLS_PSK_WITH_NULL_SHA256 MBEDTLS_TLS_PSK_WITH_NULL_SHA256 +#define TLS_PSK_WITH_NULL_SHA384 MBEDTLS_TLS_PSK_WITH_NULL_SHA384 +#define TLS_PSK_WITH_RC4_128_SHA MBEDTLS_TLS_PSK_WITH_RC4_128_SHA +#define TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA +#define TLS_RSA_PSK_WITH_AES_128_CBC_SHA MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA +#define TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 +#define TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 +#define TLS_RSA_PSK_WITH_AES_256_CBC_SHA MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA +#define TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 +#define TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 +#define TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_RSA_PSK_WITH_NULL_SHA MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA +#define TLS_RSA_PSK_WITH_NULL_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 +#define TLS_RSA_PSK_WITH_NULL_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 +#define TLS_RSA_PSK_WITH_RC4_128_SHA MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA +#define TLS_RSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA +#define TLS_RSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA +#define TLS_RSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 +#define TLS_RSA_WITH_AES_128_CCM MBEDTLS_TLS_RSA_WITH_AES_128_CCM +#define TLS_RSA_WITH_AES_128_CCM_8 MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8 +#define TLS_RSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 +#define TLS_RSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA +#define TLS_RSA_WITH_AES_256_CBC_SHA256 MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 +#define TLS_RSA_WITH_AES_256_CCM MBEDTLS_TLS_RSA_WITH_AES_256_CCM +#define TLS_RSA_WITH_AES_256_CCM_8 MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8 +#define TLS_RSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 +#define TLS_RSA_WITH_CAMELLIA_128_CBC_SHA MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA +#define TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_RSA_WITH_CAMELLIA_256_CBC_SHA MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA +#define TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 +#define TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_RSA_WITH_DES_CBC_SHA MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA +#define TLS_RSA_WITH_NULL_MD5 MBEDTLS_TLS_RSA_WITH_NULL_MD5 +#define TLS_RSA_WITH_NULL_SHA MBEDTLS_TLS_RSA_WITH_NULL_SHA +#define TLS_RSA_WITH_NULL_SHA256 MBEDTLS_TLS_RSA_WITH_NULL_SHA256 +#define TLS_RSA_WITH_RC4_128_MD5 MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 +#define TLS_RSA_WITH_RC4_128_SHA MBEDTLS_TLS_RSA_WITH_RC4_128_SHA +#define X509_CRT_VERSION_1 MBEDTLS_X509_CRT_VERSION_1 +#define X509_CRT_VERSION_2 MBEDTLS_X509_CRT_VERSION_2 +#define X509_CRT_VERSION_3 MBEDTLS_X509_CRT_VERSION_3 +#define X509_FORMAT_DER MBEDTLS_X509_FORMAT_DER +#define X509_FORMAT_PEM MBEDTLS_X509_FORMAT_PEM +#define X509_MAX_DN_NAME_SIZE MBEDTLS_X509_MAX_DN_NAME_SIZE +#define X509_RFC5280_MAX_SERIAL_LEN MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN +#define X509_RFC5280_UTC_TIME_LEN MBEDTLS_X509_RFC5280_UTC_TIME_LEN +#define XTEA_DECRYPT MBEDTLS_XTEA_DECRYPT +#define XTEA_ENCRYPT MBEDTLS_XTEA_ENCRYPT +#define _asn1_bitstring mbedtls_asn1_bitstring +#define _asn1_buf mbedtls_asn1_buf +#define _asn1_named_data mbedtls_asn1_named_data +#define _asn1_sequence mbedtls_asn1_sequence +#define _ssl_cache_context mbedtls_ssl_cache_context +#define _ssl_cache_entry mbedtls_ssl_cache_entry +#define _ssl_ciphersuite_t mbedtls_ssl_ciphersuite_t +#define _ssl_context mbedtls_ssl_context +#define _ssl_flight_item mbedtls_ssl_flight_item +#define _ssl_handshake_params mbedtls_ssl_handshake_params +#define _ssl_key_cert mbedtls_ssl_key_cert +#define _ssl_premaster_secret mbedtls_ssl_premaster_secret +#define _ssl_session mbedtls_ssl_session +#define _ssl_transform mbedtls_ssl_transform +#define _x509_crl mbedtls_x509_crl +#define _x509_crl_entry mbedtls_x509_crl_entry +#define _x509_crt mbedtls_x509_crt +#define _x509_csr mbedtls_x509_csr +#define _x509_time mbedtls_x509_time +#define _x509write_cert mbedtls_x509write_cert +#define _x509write_csr mbedtls_x509write_csr +#define aes_context mbedtls_aes_context +#define aes_crypt_cbc mbedtls_aes_crypt_cbc +#define aes_crypt_cfb128 mbedtls_aes_crypt_cfb128 +#define aes_crypt_cfb8 mbedtls_aes_crypt_cfb8 +#define aes_crypt_ctr mbedtls_aes_crypt_ctr +#define aes_crypt_ecb mbedtls_aes_crypt_ecb +#define aes_free mbedtls_aes_free +#define aes_init mbedtls_aes_init +#define aes_self_test mbedtls_aes_self_test +#define aes_setkey_dec mbedtls_aes_setkey_dec +#define aes_setkey_enc mbedtls_aes_setkey_enc +#define aesni_crypt_ecb mbedtls_aesni_crypt_ecb +#define aesni_gcm_mult mbedtls_aesni_gcm_mult +#define aesni_inverse_key mbedtls_aesni_inverse_key +#define aesni_setkey_enc mbedtls_aesni_setkey_enc +#define aesni_supports mbedtls_aesni_has_support +#define alarmed mbedtls_timing_alarmed +#define arc4_context mbedtls_arc4_context +#define arc4_crypt mbedtls_arc4_crypt +#define arc4_free mbedtls_arc4_free +#define arc4_init mbedtls_arc4_init +#define arc4_self_test mbedtls_arc4_self_test +#define arc4_setup mbedtls_arc4_setup +#define asn1_bitstring mbedtls_asn1_bitstring +#define asn1_buf mbedtls_asn1_buf +#define asn1_find_named_data mbedtls_asn1_find_named_data +#define asn1_free_named_data mbedtls_asn1_free_named_data +#define asn1_free_named_data_list mbedtls_asn1_free_named_data_list +#define asn1_get_alg mbedtls_asn1_get_alg +#define asn1_get_alg_null mbedtls_asn1_get_alg_null +#define asn1_get_bitstring mbedtls_asn1_get_bitstring +#define asn1_get_bitstring_null mbedtls_asn1_get_bitstring_null +#define asn1_get_bool mbedtls_asn1_get_bool +#define asn1_get_int mbedtls_asn1_get_int +#define asn1_get_len mbedtls_asn1_get_len +#define asn1_get_mpi mbedtls_asn1_get_mpi +#define asn1_get_sequence_of mbedtls_asn1_get_sequence_of +#define asn1_get_tag mbedtls_asn1_get_tag +#define asn1_named_data mbedtls_asn1_named_data +#define asn1_sequence mbedtls_asn1_sequence +#define asn1_store_named_data mbedtls_asn1_store_named_data +#define asn1_write_algorithm_identifier mbedtls_asn1_write_algorithm_identifier +#define asn1_write_bitstring mbedtls_asn1_write_bitstring +#define asn1_write_bool mbedtls_asn1_write_bool +#define asn1_write_ia5_string mbedtls_asn1_write_ia5_string +#define asn1_write_int mbedtls_asn1_write_int +#define asn1_write_len mbedtls_asn1_write_len +#define asn1_write_mpi mbedtls_asn1_write_mpi +#define asn1_write_null mbedtls_asn1_write_null +#define asn1_write_octet_string mbedtls_asn1_write_octet_string +#define asn1_write_oid mbedtls_asn1_write_oid +#define asn1_write_printable_string mbedtls_asn1_write_printable_string +#define asn1_write_raw_buffer mbedtls_asn1_write_raw_buffer +#define asn1_write_tag mbedtls_asn1_write_tag +#define base64_decode mbedtls_base64_decode +#define base64_encode mbedtls_base64_encode +#define base64_self_test mbedtls_base64_self_test +#define blowfish_context mbedtls_blowfish_context +#define blowfish_crypt_cbc mbedtls_blowfish_crypt_cbc +#define blowfish_crypt_cfb64 mbedtls_blowfish_crypt_cfb64 +#define blowfish_crypt_ctr mbedtls_blowfish_crypt_ctr +#define blowfish_crypt_ecb mbedtls_blowfish_crypt_ecb +#define blowfish_free mbedtls_blowfish_free +#define blowfish_init mbedtls_blowfish_init +#define blowfish_setkey mbedtls_blowfish_setkey +#define camellia_context mbedtls_camellia_context +#define camellia_crypt_cbc mbedtls_camellia_crypt_cbc +#define camellia_crypt_cfb128 mbedtls_camellia_crypt_cfb128 +#define camellia_crypt_ctr mbedtls_camellia_crypt_ctr +#define camellia_crypt_ecb mbedtls_camellia_crypt_ecb +#define camellia_free mbedtls_camellia_free +#define camellia_init mbedtls_camellia_init +#define camellia_self_test mbedtls_camellia_self_test +#define camellia_setkey_dec mbedtls_camellia_setkey_dec +#define camellia_setkey_enc mbedtls_camellia_setkey_enc +#define ccm_auth_decrypt mbedtls_ccm_auth_decrypt +#define ccm_context mbedtls_ccm_context +#define ccm_encrypt_and_tag mbedtls_ccm_encrypt_and_tag +#define ccm_free mbedtls_ccm_free +#define ccm_init mbedtls_ccm_init +#define ccm_self_test mbedtls_ccm_self_test +#define cipher_auth_decrypt mbedtls_cipher_auth_decrypt +#define cipher_auth_encrypt mbedtls_cipher_auth_encrypt +#define cipher_base_t mbedtls_cipher_base_t +#define cipher_check_tag mbedtls_cipher_check_tag +#define cipher_context_t mbedtls_cipher_context_t +#define cipher_crypt mbedtls_cipher_crypt +#define cipher_definition_t mbedtls_cipher_definition_t +#define cipher_definitions mbedtls_cipher_definitions +#define cipher_finish mbedtls_cipher_finish +#define cipher_free mbedtls_cipher_free +#define cipher_get_block_size mbedtls_cipher_get_block_size +#define cipher_get_cipher_mode mbedtls_cipher_get_cipher_mode +#define cipher_get_iv_size mbedtls_cipher_get_iv_size +#define cipher_get_key_size mbedtls_cipher_get_key_bitlen +#define cipher_get_name mbedtls_cipher_get_name +#define cipher_get_operation mbedtls_cipher_get_operation +#define cipher_get_type mbedtls_cipher_get_type +#define cipher_id_t mbedtls_cipher_id_t +#define cipher_info_from_string mbedtls_cipher_info_from_string +#define cipher_info_from_type mbedtls_cipher_info_from_type +#define cipher_info_from_values mbedtls_cipher_info_from_values +#define cipher_info_t mbedtls_cipher_info_t +#define cipher_init mbedtls_cipher_init +#define cipher_init_ctx mbedtls_cipher_setup +#define cipher_list mbedtls_cipher_list +#define cipher_mode_t mbedtls_cipher_mode_t +#define cipher_padding_t mbedtls_cipher_padding_t +#define cipher_reset mbedtls_cipher_reset +#define cipher_set_iv mbedtls_cipher_set_iv +#define cipher_set_padding_mode mbedtls_cipher_set_padding_mode +#define cipher_setkey mbedtls_cipher_setkey +#define cipher_type_t mbedtls_cipher_type_t +#define cipher_update mbedtls_cipher_update +#define cipher_update_ad mbedtls_cipher_update_ad +#define cipher_write_tag mbedtls_cipher_write_tag +#define ctr_drbg_context mbedtls_ctr_drbg_context +#define ctr_drbg_free mbedtls_ctr_drbg_free +#define ctr_drbg_init mbedtls_ctr_drbg_init +#define ctr_drbg_random mbedtls_ctr_drbg_random +#define ctr_drbg_random_with_add mbedtls_ctr_drbg_random_with_add +#define ctr_drbg_reseed mbedtls_ctr_drbg_reseed +#define ctr_drbg_self_test mbedtls_ctr_drbg_self_test +#define ctr_drbg_set_entropy_len mbedtls_ctr_drbg_set_entropy_len +#define ctr_drbg_set_prediction_resistance mbedtls_ctr_drbg_set_prediction_resistance +#define ctr_drbg_set_reseed_interval mbedtls_ctr_drbg_set_reseed_interval +#define ctr_drbg_update mbedtls_ctr_drbg_update +#define ctr_drbg_update_seed_file mbedtls_ctr_drbg_update_seed_file +#define ctr_drbg_write_seed_file mbedtls_ctr_drbg_write_seed_file +#define debug_print_buf mbedtls_debug_print_buf +#define debug_print_crt mbedtls_debug_print_crt +#define debug_print_ecp mbedtls_debug_print_ecp +#define debug_print_mpi mbedtls_debug_print_mpi +#define debug_print_msg mbedtls_debug_print_msg +#define debug_print_ret mbedtls_debug_print_ret +#define debug_set_threshold mbedtls_debug_set_threshold +#define des3_context mbedtls_des3_context +#define des3_crypt_cbc mbedtls_des3_crypt_cbc +#define des3_crypt_ecb mbedtls_des3_crypt_ecb +#define des3_free mbedtls_des3_free +#define des3_init mbedtls_des3_init +#define des3_set2key_dec mbedtls_des3_set2key_dec +#define des3_set2key_enc mbedtls_des3_set2key_enc +#define des3_set3key_dec mbedtls_des3_set3key_dec +#define des3_set3key_enc mbedtls_des3_set3key_enc +#define des_context mbedtls_des_context +#define des_crypt_cbc mbedtls_des_crypt_cbc +#define des_crypt_ecb mbedtls_des_crypt_ecb +#define des_free mbedtls_des_free +#define des_init mbedtls_des_init +#define des_key_check_key_parity mbedtls_des_key_check_key_parity +#define des_key_check_weak mbedtls_des_key_check_weak +#define des_key_set_parity mbedtls_des_key_set_parity +#define des_self_test mbedtls_des_self_test +#define des_setkey_dec mbedtls_des_setkey_dec +#define des_setkey_enc mbedtls_des_setkey_enc +#define dhm_calc_secret mbedtls_dhm_calc_secret +#define dhm_context mbedtls_dhm_context +#define dhm_free mbedtls_dhm_free +#define dhm_init mbedtls_dhm_init +#define dhm_make_params mbedtls_dhm_make_params +#define dhm_make_public mbedtls_dhm_make_public +#define dhm_parse_dhm mbedtls_dhm_parse_dhm +#define dhm_parse_dhmfile mbedtls_dhm_parse_dhmfile +#define dhm_read_params mbedtls_dhm_read_params +#define dhm_read_public mbedtls_dhm_read_public +#define dhm_self_test mbedtls_dhm_self_test +#define ecdh_calc_secret mbedtls_ecdh_calc_secret +#define ecdh_compute_shared mbedtls_ecdh_compute_shared +#define ecdh_context mbedtls_ecdh_context +#define ecdh_free mbedtls_ecdh_free +#define ecdh_gen_public mbedtls_ecdh_gen_public +#define ecdh_get_params mbedtls_ecdh_get_params +#define ecdh_init mbedtls_ecdh_init +#define ecdh_make_params mbedtls_ecdh_make_params +#define ecdh_make_public mbedtls_ecdh_make_public +#define ecdh_read_params mbedtls_ecdh_read_params +#define ecdh_read_public mbedtls_ecdh_read_public +#define ecdh_side mbedtls_ecdh_side +#define ecdsa_context mbedtls_ecdsa_context +#define ecdsa_free mbedtls_ecdsa_free +#define ecdsa_from_keypair mbedtls_ecdsa_from_keypair +#define ecdsa_genkey mbedtls_ecdsa_genkey +#define ecdsa_info mbedtls_ecdsa_info +#define ecdsa_init mbedtls_ecdsa_init +#define ecdsa_read_signature mbedtls_ecdsa_read_signature +#define ecdsa_sign mbedtls_ecdsa_sign +#define ecdsa_sign_det mbedtls_ecdsa_sign_det +#define ecdsa_verify mbedtls_ecdsa_verify +#define ecdsa_write_signature mbedtls_ecdsa_write_signature +#define ecdsa_write_signature_det mbedtls_ecdsa_write_signature_det +#define eckey_info mbedtls_eckey_info +#define eckeydh_info mbedtls_eckeydh_info +#define ecp_check_privkey mbedtls_ecp_check_privkey +#define ecp_check_pub_priv mbedtls_ecp_check_pub_priv +#define ecp_check_pubkey mbedtls_ecp_check_pubkey +#define ecp_copy mbedtls_ecp_copy +#define ecp_curve_info mbedtls_ecp_curve_info +#define ecp_curve_info_from_grp_id mbedtls_ecp_curve_info_from_grp_id +#define ecp_curve_info_from_name mbedtls_ecp_curve_info_from_name +#define ecp_curve_info_from_tls_id mbedtls_ecp_curve_info_from_tls_id +#define ecp_curve_list mbedtls_ecp_curve_list +#define ecp_gen_key mbedtls_ecp_gen_key +#define ecp_gen_keypair mbedtls_ecp_gen_keypair +#define ecp_group mbedtls_ecp_group +#define ecp_group_copy mbedtls_ecp_group_copy +#define ecp_group_free mbedtls_ecp_group_free +#define ecp_group_id mbedtls_ecp_group_id +#define ecp_group_init mbedtls_ecp_group_init +#define ecp_grp_id_list mbedtls_ecp_grp_id_list +#define ecp_is_zero mbedtls_ecp_is_zero +#define ecp_keypair mbedtls_ecp_keypair +#define ecp_keypair_free mbedtls_ecp_keypair_free +#define ecp_keypair_init mbedtls_ecp_keypair_init +#define ecp_mul mbedtls_ecp_mul +#define ecp_point mbedtls_ecp_point +#define ecp_point_free mbedtls_ecp_point_free +#define ecp_point_init mbedtls_ecp_point_init +#define ecp_point_read_binary mbedtls_ecp_point_read_binary +#define ecp_point_read_string mbedtls_ecp_point_read_string +#define ecp_point_write_binary mbedtls_ecp_point_write_binary +#define ecp_self_test mbedtls_ecp_self_test +#define ecp_set_zero mbedtls_ecp_set_zero +#define ecp_tls_read_group mbedtls_ecp_tls_read_group +#define ecp_tls_read_point mbedtls_ecp_tls_read_point +#define ecp_tls_write_group mbedtls_ecp_tls_write_group +#define ecp_tls_write_point mbedtls_ecp_tls_write_point +#define ecp_use_known_dp mbedtls_ecp_group_load +#define entropy_add_source mbedtls_entropy_add_source +#define entropy_context mbedtls_entropy_context +#define entropy_free mbedtls_entropy_free +#define entropy_func mbedtls_entropy_func +#define entropy_gather mbedtls_entropy_gather +#define entropy_init mbedtls_entropy_init +#define entropy_self_test mbedtls_entropy_self_test +#define entropy_update_manual mbedtls_entropy_update_manual +#define entropy_update_seed_file mbedtls_entropy_update_seed_file +#define entropy_write_seed_file mbedtls_entropy_write_seed_file +#define error_strerror mbedtls_strerror +#define f_source_ptr mbedtls_entropy_f_source_ptr +#define gcm_auth_decrypt mbedtls_gcm_auth_decrypt +#define gcm_context mbedtls_gcm_context +#define gcm_crypt_and_tag mbedtls_gcm_crypt_and_tag +#define gcm_finish mbedtls_gcm_finish +#define gcm_free mbedtls_gcm_free +#define gcm_init mbedtls_gcm_init +#define gcm_self_test mbedtls_gcm_self_test +#define gcm_starts mbedtls_gcm_starts +#define gcm_update mbedtls_gcm_update +#define get_timer mbedtls_timing_get_timer +#define hardclock mbedtls_timing_hardclock +#define hardclock_poll mbedtls_hardclock_poll +#define havege_free mbedtls_havege_free +#define havege_init mbedtls_havege_init +#define havege_poll mbedtls_havege_poll +#define havege_random mbedtls_havege_random +#define havege_state mbedtls_havege_state +#define hmac_drbg_context mbedtls_hmac_drbg_context +#define hmac_drbg_free mbedtls_hmac_drbg_free +#define hmac_drbg_init mbedtls_hmac_drbg_init +#define hmac_drbg_random mbedtls_hmac_drbg_random +#define hmac_drbg_random_with_add mbedtls_hmac_drbg_random_with_add +#define hmac_drbg_reseed mbedtls_hmac_drbg_reseed +#define hmac_drbg_self_test mbedtls_hmac_drbg_self_test +#define hmac_drbg_set_entropy_len mbedtls_hmac_drbg_set_entropy_len +#define hmac_drbg_set_prediction_resistance mbedtls_hmac_drbg_set_prediction_resistance +#define hmac_drbg_set_reseed_interval mbedtls_hmac_drbg_set_reseed_interval +#define hmac_drbg_update mbedtls_hmac_drbg_update +#define hmac_drbg_update_seed_file mbedtls_hmac_drbg_update_seed_file +#define hmac_drbg_write_seed_file mbedtls_hmac_drbg_write_seed_file +#define hr_time mbedtls_timing_hr_time +#define key_exchange_type_t mbedtls_key_exchange_type_t +#define md mbedtls_md +#define md2 mbedtls_md2 +#define md2_context mbedtls_md2_context +#define md2_finish mbedtls_md2_finish +#define md2_free mbedtls_md2_free +#define md2_info mbedtls_md2_info +#define md2_init mbedtls_md2_init +#define md2_process mbedtls_md2_process +#define md2_self_test mbedtls_md2_self_test +#define md2_starts mbedtls_md2_starts +#define md2_update mbedtls_md2_update +#define md4 mbedtls_md4 +#define md4_context mbedtls_md4_context +#define md4_finish mbedtls_md4_finish +#define md4_free mbedtls_md4_free +#define md4_info mbedtls_md4_info +#define md4_init mbedtls_md4_init +#define md4_process mbedtls_md4_process +#define md4_self_test mbedtls_md4_self_test +#define md4_starts mbedtls_md4_starts +#define md4_update mbedtls_md4_update +#define md5 mbedtls_md5 +#define md5_context mbedtls_md5_context +#define md5_finish mbedtls_md5_finish +#define md5_free mbedtls_md5_free +#define md5_info mbedtls_md5_info +#define md5_init mbedtls_md5_init +#define md5_process mbedtls_md5_process +#define md5_self_test mbedtls_md5_self_test +#define md5_starts mbedtls_md5_starts +#define md5_update mbedtls_md5_update +#define md_context_t mbedtls_md_context_t +#define md_file mbedtls_md_file +#define md_finish mbedtls_md_finish +#define md_free mbedtls_md_free +#define md_get_name mbedtls_md_get_name +#define md_get_size mbedtls_md_get_size +#define md_get_type mbedtls_md_get_type +#define md_hmac mbedtls_md_hmac +#define md_hmac_finish mbedtls_md_hmac_finish +#define md_hmac_reset mbedtls_md_hmac_reset +#define md_hmac_starts mbedtls_md_hmac_starts +#define md_hmac_update mbedtls_md_hmac_update +#define md_info_from_string mbedtls_md_info_from_string +#define md_info_from_type mbedtls_md_info_from_type +#define md_info_t mbedtls_md_info_t +#define md_init mbedtls_md_init +#define md_init_ctx mbedtls_md_init_ctx +#define md_list mbedtls_md_list +#define md_process mbedtls_md_process +#define md_starts mbedtls_md_starts +#define md_type_t mbedtls_md_type_t +#define md_update mbedtls_md_update +#define memory_buffer_alloc_cur_get mbedtls_memory_buffer_alloc_cur_get +#define memory_buffer_alloc_free mbedtls_memory_buffer_alloc_free +#define memory_buffer_alloc_init mbedtls_memory_buffer_alloc_init +#define memory_buffer_alloc_max_get mbedtls_memory_buffer_alloc_max_get +#define memory_buffer_alloc_max_reset mbedtls_memory_buffer_alloc_max_reset +#define memory_buffer_alloc_self_test mbedtls_memory_buffer_alloc_self_test +#define memory_buffer_alloc_status mbedtls_memory_buffer_alloc_status +#define memory_buffer_alloc_verify mbedtls_memory_buffer_alloc_verify +#define memory_buffer_set_verify mbedtls_memory_buffer_set_verify +#define mpi mbedtls_mpi +#define mpi_add_abs mbedtls_mpi_add_abs +#define mpi_add_int mbedtls_mpi_add_int +#define mpi_add_mpi mbedtls_mpi_add_mpi +#define mpi_cmp_abs mbedtls_mpi_cmp_abs +#define mpi_cmp_int mbedtls_mpi_cmp_int +#define mpi_cmp_mpi mbedtls_mpi_cmp_mpi +#define mpi_copy mbedtls_mpi_copy +#define mpi_div_int mbedtls_mpi_div_int +#define mpi_div_mpi mbedtls_mpi_div_mpi +#define mpi_exp_mod mbedtls_mpi_exp_mod +#define mpi_fill_random mbedtls_mpi_fill_random +#define mpi_free mbedtls_mpi_free +#define mpi_gcd mbedtls_mpi_gcd +#define mpi_gen_prime mbedtls_mpi_gen_prime +#define mpi_get_bit mbedtls_mpi_get_bit +#define mpi_grow mbedtls_mpi_grow +#define mpi_init mbedtls_mpi_init +#define mpi_inv_mod mbedtls_mpi_inv_mod +#define mpi_is_prime mbedtls_mpi_is_prime +#define mpi_lsb mbedtls_mpi_lsb +#define mpi_lset mbedtls_mpi_lset +#define mpi_mod_int mbedtls_mpi_mod_int +#define mpi_mod_mpi mbedtls_mpi_mod_mpi +#define mpi_msb mbedtls_mpi_bitlen +#define mpi_mul_int mbedtls_mpi_mul_int +#define mpi_mul_mpi mbedtls_mpi_mul_mpi +#define mpi_read_binary mbedtls_mpi_read_binary +#define mpi_read_file mbedtls_mpi_read_file +#define mpi_read_string mbedtls_mpi_read_string +#define mpi_safe_cond_assign mbedtls_mpi_safe_cond_assign +#define mpi_safe_cond_swap mbedtls_mpi_safe_cond_swap +#define mpi_self_test mbedtls_mpi_self_test +#define mpi_set_bit mbedtls_mpi_set_bit +#define mpi_shift_l mbedtls_mpi_shift_l +#define mpi_shift_r mbedtls_mpi_shift_r +#define mpi_shrink mbedtls_mpi_shrink +#define mpi_size mbedtls_mpi_size +#define mpi_sub_abs mbedtls_mpi_sub_abs +#define mpi_sub_int mbedtls_mpi_sub_int +#define mpi_sub_mpi mbedtls_mpi_sub_mpi +#define mpi_swap mbedtls_mpi_swap +#define mpi_write_binary mbedtls_mpi_write_binary +#define mpi_write_file mbedtls_mpi_write_file +#define mpi_write_string mbedtls_mpi_write_string +#define net_accept mbedtls_net_accept +#define net_bind mbedtls_net_bind +#define net_close mbedtls_net_free +#define net_connect mbedtls_net_connect +#define net_recv mbedtls_net_recv +#define net_recv_timeout mbedtls_net_recv_timeout +#define net_send mbedtls_net_send +#define net_set_block mbedtls_net_set_block +#define net_set_nonblock mbedtls_net_set_nonblock +#define net_usleep mbedtls_net_usleep +#define oid_descriptor_t mbedtls_oid_descriptor_t +#define oid_get_attr_short_name mbedtls_oid_get_attr_short_name +#define oid_get_cipher_alg mbedtls_oid_get_cipher_alg +#define oid_get_ec_grp mbedtls_oid_get_ec_grp +#define oid_get_extended_key_usage mbedtls_oid_get_extended_key_usage +#define oid_get_md_alg mbedtls_oid_get_md_alg +#define oid_get_numeric_string mbedtls_oid_get_numeric_string +#define oid_get_oid_by_ec_grp mbedtls_oid_get_oid_by_ec_grp +#define oid_get_oid_by_md mbedtls_oid_get_oid_by_md +#define oid_get_oid_by_pk_alg mbedtls_oid_get_oid_by_pk_alg +#define oid_get_oid_by_sig_alg mbedtls_oid_get_oid_by_sig_alg +#define oid_get_pk_alg mbedtls_oid_get_pk_alg +#define oid_get_pkcs12_pbe_alg mbedtls_oid_get_pkcs12_pbe_alg +#define oid_get_sig_alg mbedtls_oid_get_sig_alg +#define oid_get_sig_alg_desc mbedtls_oid_get_sig_alg_desc +#define oid_get_x509_ext_type mbedtls_oid_get_x509_ext_type +#define operation_t mbedtls_operation_t +#define padlock_supports mbedtls_padlock_has_support +#define padlock_xcryptcbc mbedtls_padlock_xcryptcbc +#define padlock_xcryptecb mbedtls_padlock_xcryptecb +#define pem_context mbedtls_pem_context +#define pem_free mbedtls_pem_free +#define pem_init mbedtls_pem_init +#define pem_read_buffer mbedtls_pem_read_buffer +#define pem_write_buffer mbedtls_pem_write_buffer +#define pk_can_do mbedtls_pk_can_do +#define pk_check_pair mbedtls_pk_check_pair +#define pk_context mbedtls_pk_context +#define pk_debug mbedtls_pk_debug +#define pk_debug_item mbedtls_pk_debug_item +#define pk_debug_type mbedtls_pk_debug_type +#define pk_decrypt mbedtls_pk_decrypt +#define pk_ec mbedtls_pk_ec +#define pk_encrypt mbedtls_pk_encrypt +#define pk_free mbedtls_pk_free +#define pk_get_len mbedtls_pk_get_len +#define pk_get_name mbedtls_pk_get_name +#define pk_get_size mbedtls_pk_get_bitlen +#define pk_get_type mbedtls_pk_get_type +#define pk_info_from_type mbedtls_pk_info_from_type +#define pk_info_t mbedtls_pk_info_t +#define pk_init mbedtls_pk_init +#define pk_init_ctx mbedtls_pk_setup +#define pk_init_ctx_rsa_alt mbedtls_pk_setup_rsa_alt +#define pk_load_file mbedtls_pk_load_file +#define pk_parse_key mbedtls_pk_parse_key +#define pk_parse_keyfile mbedtls_pk_parse_keyfile +#define pk_parse_public_key mbedtls_pk_parse_public_key +#define pk_parse_public_keyfile mbedtls_pk_parse_public_keyfile +#define pk_parse_subpubkey mbedtls_pk_parse_subpubkey +#define pk_rsa mbedtls_pk_rsa +#define pk_rsa_alt_decrypt_func mbedtls_pk_rsa_alt_decrypt_func +#define pk_rsa_alt_key_len_func mbedtls_pk_rsa_alt_key_len_func +#define pk_rsa_alt_sign_func mbedtls_pk_rsa_alt_sign_func +#define pk_rsassa_pss_options mbedtls_pk_rsassa_pss_options +#define pk_sign mbedtls_pk_sign +#define pk_type_t mbedtls_pk_type_t +#define pk_verify mbedtls_pk_verify +#define pk_verify_ext mbedtls_pk_verify_ext +#define pk_write_key_der mbedtls_pk_write_key_der +#define pk_write_key_pem mbedtls_pk_write_key_pem +#define pk_write_pubkey mbedtls_pk_write_pubkey +#define pk_write_pubkey_der mbedtls_pk_write_pubkey_der +#define pk_write_pubkey_pem mbedtls_pk_write_pubkey_pem +#define pkcs11_context mbedtls_pkcs11_context +#define pkcs11_decrypt mbedtls_pkcs11_decrypt +#define pkcs11_priv_key_free mbedtls_pkcs11_priv_key_free +#define pkcs11_priv_key_init mbedtls_pkcs11_priv_key_bind +#define pkcs11_sign mbedtls_pkcs11_sign +#define pkcs11_x509_cert_init mbedtls_pkcs11_x509_cert_bind +#define pkcs12_derivation mbedtls_pkcs12_derivation +#define pkcs12_pbe mbedtls_pkcs12_pbe +#define pkcs12_pbe_sha1_rc4_128 mbedtls_pkcs12_pbe_sha1_rc4_128 +#define pkcs5_pbes2 mbedtls_pkcs5_pbes2 +#define pkcs5_pbkdf2_hmac mbedtls_pkcs5_pbkdf2_hmac +#define pkcs5_self_test mbedtls_pkcs5_self_test +#define platform_entropy_poll mbedtls_platform_entropy_poll +#define platform_set_exit mbedtls_platform_set_exit +#define platform_set_fprintf mbedtls_platform_set_fprintf +#define platform_set_printf mbedtls_platform_set_printf +#define platform_set_snprintf mbedtls_platform_set_snprintf +#define polarssl_exit mbedtls_exit +#define polarssl_fprintf mbedtls_fprintf +#define polarssl_free mbedtls_free +#define polarssl_mutex_free mbedtls_mutex_free +#define polarssl_mutex_init mbedtls_mutex_init +#define polarssl_mutex_lock mbedtls_mutex_lock +#define polarssl_mutex_unlock mbedtls_mutex_unlock +#define polarssl_printf mbedtls_printf +#define polarssl_snprintf mbedtls_snprintf +#define polarssl_strerror mbedtls_strerror +#define ripemd160 mbedtls_ripemd160 +#define ripemd160_context mbedtls_ripemd160_context +#define ripemd160_finish mbedtls_ripemd160_finish +#define ripemd160_free mbedtls_ripemd160_free +#define ripemd160_info mbedtls_ripemd160_info +#define ripemd160_init mbedtls_ripemd160_init +#define ripemd160_process mbedtls_ripemd160_process +#define ripemd160_self_test mbedtls_ripemd160_self_test +#define ripemd160_starts mbedtls_ripemd160_starts +#define ripemd160_update mbedtls_ripemd160_update +#define rsa_alt_context mbedtls_rsa_alt_context +#define rsa_alt_info mbedtls_rsa_alt_info +#define rsa_check_privkey mbedtls_rsa_check_privkey +#define rsa_check_pub_priv mbedtls_rsa_check_pub_priv +#define rsa_check_pubkey mbedtls_rsa_check_pubkey +#define rsa_context mbedtls_rsa_context +#define rsa_copy mbedtls_rsa_copy +#define rsa_free mbedtls_rsa_free +#define rsa_gen_key mbedtls_rsa_gen_key +#define rsa_info mbedtls_rsa_info +#define rsa_init mbedtls_rsa_init +#define rsa_pkcs1_decrypt mbedtls_rsa_pkcs1_decrypt +#define rsa_pkcs1_encrypt mbedtls_rsa_pkcs1_encrypt +#define rsa_pkcs1_sign mbedtls_rsa_pkcs1_sign +#define rsa_pkcs1_verify mbedtls_rsa_pkcs1_verify +#define rsa_private mbedtls_rsa_private +#define rsa_public mbedtls_rsa_public +#define rsa_rsaes_oaep_decrypt mbedtls_rsa_rsaes_oaep_decrypt +#define rsa_rsaes_oaep_encrypt mbedtls_rsa_rsaes_oaep_encrypt +#define rsa_rsaes_pkcs1_v15_decrypt mbedtls_rsa_rsaes_pkcs1_v15_decrypt +#define rsa_rsaes_pkcs1_v15_encrypt mbedtls_rsa_rsaes_pkcs1_v15_encrypt +#define rsa_rsassa_pkcs1_v15_sign mbedtls_rsa_rsassa_pkcs1_v15_sign +#define rsa_rsassa_pkcs1_v15_verify mbedtls_rsa_rsassa_pkcs1_v15_verify +#define rsa_rsassa_pss_sign mbedtls_rsa_rsassa_pss_sign +#define rsa_rsassa_pss_verify mbedtls_rsa_rsassa_pss_verify +#define rsa_rsassa_pss_verify_ext mbedtls_rsa_rsassa_pss_verify_ext +#define rsa_self_test mbedtls_rsa_self_test +#define rsa_set_padding mbedtls_rsa_set_padding +#define safer_memcmp mbedtls_ssl_safer_memcmp +#define set_alarm mbedtls_set_alarm +#define sha1 mbedtls_sha1 +#define sha1_context mbedtls_sha1_context +#define sha1_finish mbedtls_sha1_finish +#define sha1_free mbedtls_sha1_free +#define sha1_info mbedtls_sha1_info +#define sha1_init mbedtls_sha1_init +#define sha1_process mbedtls_sha1_process +#define sha1_self_test mbedtls_sha1_self_test +#define sha1_starts mbedtls_sha1_starts +#define sha1_update mbedtls_sha1_update +#define sha224_info mbedtls_sha224_info +#define sha256 mbedtls_sha256 +#define sha256_context mbedtls_sha256_context +#define sha256_finish mbedtls_sha256_finish +#define sha256_free mbedtls_sha256_free +#define sha256_info mbedtls_sha256_info +#define sha256_init mbedtls_sha256_init +#define sha256_process mbedtls_sha256_process +#define sha256_self_test mbedtls_sha256_self_test +#define sha256_starts mbedtls_sha256_starts +#define sha256_update mbedtls_sha256_update +#define sha384_info mbedtls_sha384_info +#define sha512 mbedtls_sha512 +#define sha512_context mbedtls_sha512_context +#define sha512_finish mbedtls_sha512_finish +#define sha512_free mbedtls_sha512_free +#define sha512_info mbedtls_sha512_info +#define sha512_init mbedtls_sha512_init +#define sha512_process mbedtls_sha512_process +#define sha512_self_test mbedtls_sha512_self_test +#define sha512_starts mbedtls_sha512_starts +#define sha512_update mbedtls_sha512_update +#define source_state mbedtls_entropy_source_state +#define ssl_cache_context mbedtls_ssl_cache_context +#define ssl_cache_entry mbedtls_ssl_cache_entry +#define ssl_cache_free mbedtls_ssl_cache_free +#define ssl_cache_get mbedtls_ssl_cache_get +#define ssl_cache_init mbedtls_ssl_cache_init +#define ssl_cache_set mbedtls_ssl_cache_set +#define ssl_cache_set_max_entries mbedtls_ssl_cache_set_max_entries +#define ssl_cache_set_timeout mbedtls_ssl_cache_set_timeout +#define ssl_check_cert_usage mbedtls_ssl_check_cert_usage +#define ssl_ciphersuite_from_id mbedtls_ssl_ciphersuite_from_id +#define ssl_ciphersuite_from_string mbedtls_ssl_ciphersuite_from_string +#define ssl_ciphersuite_t mbedtls_ssl_ciphersuite_t +#define ssl_ciphersuite_uses_ec mbedtls_ssl_ciphersuite_uses_ec +#define ssl_ciphersuite_uses_psk mbedtls_ssl_ciphersuite_uses_psk +#define ssl_close_notify mbedtls_ssl_close_notify +#define ssl_context mbedtls_ssl_context +#define ssl_cookie_check mbedtls_ssl_cookie_check +#define ssl_cookie_check_t mbedtls_ssl_cookie_check_t +#define ssl_cookie_ctx mbedtls_ssl_cookie_ctx +#define ssl_cookie_free mbedtls_ssl_cookie_free +#define ssl_cookie_init mbedtls_ssl_cookie_init +#define ssl_cookie_set_timeout mbedtls_ssl_cookie_set_timeout +#define ssl_cookie_setup mbedtls_ssl_cookie_setup +#define ssl_cookie_write mbedtls_ssl_cookie_write +#define ssl_cookie_write_t mbedtls_ssl_cookie_write_t +#define ssl_derive_keys mbedtls_ssl_derive_keys +#define ssl_dtls_replay_check mbedtls_ssl_dtls_replay_check +#define ssl_dtls_replay_update mbedtls_ssl_dtls_replay_update +#define ssl_fetch_input mbedtls_ssl_fetch_input +#define ssl_flight_item mbedtls_ssl_flight_item +#define ssl_flush_output mbedtls_ssl_flush_output +#define ssl_free mbedtls_ssl_free +#define ssl_get_alpn_protocol mbedtls_ssl_get_alpn_protocol +#define ssl_get_bytes_avail mbedtls_ssl_get_bytes_avail +#define ssl_get_ciphersuite mbedtls_ssl_get_ciphersuite +#define ssl_get_ciphersuite_id mbedtls_ssl_get_ciphersuite_id +#define ssl_get_ciphersuite_name mbedtls_ssl_get_ciphersuite_name +#define ssl_get_ciphersuite_sig_pk_alg mbedtls_ssl_get_ciphersuite_sig_pk_alg +#define ssl_get_peer_cert mbedtls_ssl_get_peer_cert +#define ssl_get_record_expansion mbedtls_ssl_get_record_expansion +#define ssl_get_session mbedtls_ssl_get_session +#define ssl_get_verify_result mbedtls_ssl_get_verify_result +#define ssl_get_version mbedtls_ssl_get_version +#define ssl_handshake mbedtls_ssl_handshake +#define ssl_handshake_client_step mbedtls_ssl_handshake_client_step +#define ssl_handshake_free mbedtls_ssl_handshake_free +#define ssl_handshake_params mbedtls_ssl_handshake_params +#define ssl_handshake_server_step mbedtls_ssl_handshake_server_step +#define ssl_handshake_step mbedtls_ssl_handshake_step +#define ssl_handshake_wrapup mbedtls_ssl_handshake_wrapup +#define ssl_hdr_len mbedtls_ssl_hdr_len +#define ssl_hs_hdr_len mbedtls_ssl_hs_hdr_len +#define ssl_hw_record_activate mbedtls_ssl_hw_record_activate +#define ssl_hw_record_finish mbedtls_ssl_hw_record_finish +#define ssl_hw_record_init mbedtls_ssl_hw_record_init +#define ssl_hw_record_read mbedtls_ssl_hw_record_read +#define ssl_hw_record_reset mbedtls_ssl_hw_record_reset +#define ssl_hw_record_write mbedtls_ssl_hw_record_write +#define ssl_init mbedtls_ssl_init +#define ssl_key_cert mbedtls_ssl_key_cert +#define ssl_legacy_renegotiation mbedtls_ssl_conf_legacy_renegotiation +#define ssl_list_ciphersuites mbedtls_ssl_list_ciphersuites +#define ssl_md_alg_from_hash mbedtls_ssl_md_alg_from_hash +#define ssl_optimize_checksum mbedtls_ssl_optimize_checksum +#define ssl_own_cert mbedtls_ssl_own_cert +#define ssl_own_key mbedtls_ssl_own_key +#define ssl_parse_certificate mbedtls_ssl_parse_certificate +#define ssl_parse_change_cipher_spec mbedtls_ssl_parse_change_cipher_spec +#define ssl_parse_finished mbedtls_ssl_parse_finished +#define ssl_pk_alg_from_sig mbedtls_ssl_pk_alg_from_sig +#define ssl_pkcs11_decrypt mbedtls_ssl_pkcs11_decrypt +#define ssl_pkcs11_key_len mbedtls_ssl_pkcs11_key_len +#define ssl_pkcs11_sign mbedtls_ssl_pkcs11_sign +#define ssl_psk_derive_premaster mbedtls_ssl_psk_derive_premaster +#define ssl_read mbedtls_ssl_read +#define ssl_read_record mbedtls_ssl_read_record +#define ssl_read_version mbedtls_ssl_read_version +#define ssl_recv_flight_completed mbedtls_ssl_recv_flight_completed +#define ssl_renegotiate mbedtls_ssl_renegotiate +#define ssl_resend mbedtls_ssl_resend +#define ssl_reset_checksum mbedtls_ssl_reset_checksum +#define ssl_send_alert_message mbedtls_ssl_send_alert_message +#define ssl_send_fatal_handshake_failure mbedtls_ssl_send_fatal_handshake_failure +#define ssl_send_flight_completed mbedtls_ssl_send_flight_completed +#define ssl_session mbedtls_ssl_session +#define ssl_session_free mbedtls_ssl_session_free +#define ssl_session_init mbedtls_ssl_session_init +#define ssl_session_reset mbedtls_ssl_session_reset +#define ssl_set_alpn_protocols mbedtls_ssl_conf_alpn_protocols +#define ssl_set_arc4_support mbedtls_ssl_conf_arc4_support +#define ssl_set_authmode mbedtls_ssl_conf_authmode +#define ssl_set_bio mbedtls_ssl_set_bio +#define ssl_set_ca_chain mbedtls_ssl_conf_ca_chain +#define ssl_set_cbc_record_splitting mbedtls_ssl_conf_cbc_record_splitting +#define ssl_set_ciphersuites mbedtls_ssl_conf_ciphersuites +#define ssl_set_ciphersuites_for_version mbedtls_ssl_conf_ciphersuites_for_version +#define ssl_set_client_transport_id mbedtls_ssl_set_client_transport_id +#define ssl_set_curves mbedtls_ssl_conf_curves +#define ssl_set_dbg mbedtls_ssl_conf_dbg +#define ssl_set_dh_param mbedtls_ssl_conf_dh_param +#define ssl_set_dh_param_ctx mbedtls_ssl_conf_dh_param_ctx +#define ssl_set_dtls_anti_replay mbedtls_ssl_conf_dtls_anti_replay +#define ssl_set_dtls_badmac_limit mbedtls_ssl_conf_dtls_badmac_limit +#define ssl_set_dtls_cookies mbedtls_ssl_conf_dtls_cookies +#define ssl_set_encrypt_then_mac mbedtls_ssl_conf_encrypt_then_mac +#define ssl_set_endpoint mbedtls_ssl_conf_endpoint +#define ssl_set_extended_master_secret mbedtls_ssl_conf_extended_master_secret +#define ssl_set_fallback mbedtls_ssl_conf_fallback +#define ssl_set_handshake_timeout mbedtls_ssl_conf_handshake_timeout +#define ssl_set_hostname mbedtls_ssl_set_hostname +#define ssl_set_max_frag_len mbedtls_ssl_conf_max_frag_len +#define ssl_set_max_version mbedtls_ssl_conf_max_version +#define ssl_set_min_version mbedtls_ssl_conf_min_version +#define ssl_set_own_cert mbedtls_ssl_conf_own_cert +#define ssl_set_psk mbedtls_ssl_conf_psk +#define ssl_set_psk_cb mbedtls_ssl_conf_psk_cb +#define ssl_set_renegotiation mbedtls_ssl_conf_renegotiation +#define ssl_set_renegotiation_enforced mbedtls_ssl_conf_renegotiation_enforced +#define ssl_set_renegotiation_period mbedtls_ssl_conf_renegotiation_period +#define ssl_set_rng mbedtls_ssl_conf_rng +#define ssl_set_session mbedtls_ssl_set_session +#define ssl_set_session_cache mbedtls_ssl_conf_session_cache +#define ssl_set_session_tickets mbedtls_ssl_conf_session_tickets +#define ssl_set_sni mbedtls_ssl_conf_sni +#define ssl_set_transport mbedtls_ssl_conf_transport +#define ssl_set_truncated_hmac mbedtls_ssl_conf_truncated_hmac +#define ssl_set_verify mbedtls_ssl_conf_verify +#define ssl_sig_from_pk mbedtls_ssl_sig_from_pk +#define ssl_states mbedtls_ssl_states +#define ssl_transform mbedtls_ssl_transform +#define ssl_transform_free mbedtls_ssl_transform_free +#define ssl_write mbedtls_ssl_write +#define ssl_write_certificate mbedtls_ssl_write_certificate +#define ssl_write_change_cipher_spec mbedtls_ssl_write_change_cipher_spec +#define ssl_write_finished mbedtls_ssl_write_finished +#define ssl_write_record mbedtls_ssl_write_record +#define ssl_write_version mbedtls_ssl_write_version +#define supported_ciphers mbedtls_cipher_supported +#define t_sint mbedtls_mpi_sint +#define t_udbl mbedtls_t_udbl +#define t_uint mbedtls_mpi_uint +#define test_ca_crt mbedtls_test_ca_crt +#define test_ca_crt_ec mbedtls_test_ca_crt_ec +#define test_ca_crt_rsa mbedtls_test_ca_crt_rsa +#define test_ca_key mbedtls_test_ca_key +#define test_ca_key_ec mbedtls_test_ca_key_ec +#define test_ca_key_rsa mbedtls_test_ca_key_rsa +#define test_ca_list mbedtls_test_cas_pem +#define test_ca_pwd mbedtls_test_ca_pwd +#define test_ca_pwd_ec mbedtls_test_ca_pwd_ec +#define test_ca_pwd_rsa mbedtls_test_ca_pwd_rsa +#define test_cli_crt mbedtls_test_cli_crt +#define test_cli_crt_ec mbedtls_test_cli_crt_ec +#define test_cli_crt_rsa mbedtls_test_cli_crt_rsa +#define test_cli_key mbedtls_test_cli_key +#define test_cli_key_ec mbedtls_test_cli_key_ec +#define test_cli_key_rsa mbedtls_test_cli_key_rsa +#define test_srv_crt mbedtls_test_srv_crt +#define test_srv_crt_ec mbedtls_test_srv_crt_ec +#define test_srv_crt_rsa mbedtls_test_srv_crt_rsa +#define test_srv_key mbedtls_test_srv_key +#define test_srv_key_ec mbedtls_test_srv_key_ec +#define test_srv_key_rsa mbedtls_test_srv_key_rsa +#define threading_mutex_t mbedtls_threading_mutex_t +#define threading_set_alt mbedtls_threading_set_alt +#define timing_self_test mbedtls_timing_self_test +#define version_check_feature mbedtls_version_check_feature +#define version_get_number mbedtls_version_get_number +#define version_get_string mbedtls_version_get_string +#define version_get_string_full mbedtls_version_get_string_full +#define x509_bitstring mbedtls_x509_bitstring +#define x509_buf mbedtls_x509_buf +#define x509_crl mbedtls_x509_crl +#define x509_crl_entry mbedtls_x509_crl_entry +#define x509_crl_free mbedtls_x509_crl_free +#define x509_crl_info mbedtls_x509_crl_info +#define x509_crl_init mbedtls_x509_crl_init +#define x509_crl_parse mbedtls_x509_crl_parse +#define x509_crl_parse_der mbedtls_x509_crl_parse_der +#define x509_crl_parse_file mbedtls_x509_crl_parse_file +#define x509_crt mbedtls_x509_crt +#define x509_crt_check_extended_key_usage mbedtls_x509_crt_check_extended_key_usage +#define x509_crt_check_key_usage mbedtls_x509_crt_check_key_usage +#define x509_crt_free mbedtls_x509_crt_free +#define x509_crt_info mbedtls_x509_crt_info +#define x509_crt_init mbedtls_x509_crt_init +#define x509_crt_parse mbedtls_x509_crt_parse +#define x509_crt_parse_der mbedtls_x509_crt_parse_der +#define x509_crt_parse_file mbedtls_x509_crt_parse_file +#define x509_crt_parse_path mbedtls_x509_crt_parse_path +#define x509_crt_revoked mbedtls_x509_crt_is_revoked +#define x509_crt_verify mbedtls_x509_crt_verify +#define x509_csr mbedtls_x509_csr +#define x509_csr_free mbedtls_x509_csr_free +#define x509_csr_info mbedtls_x509_csr_info +#define x509_csr_init mbedtls_x509_csr_init +#define x509_csr_parse mbedtls_x509_csr_parse +#define x509_csr_parse_der mbedtls_x509_csr_parse_der +#define x509_csr_parse_file mbedtls_x509_csr_parse_file +#define x509_dn_gets mbedtls_x509_dn_gets +#define x509_get_alg mbedtls_x509_get_alg +#define x509_get_alg_null mbedtls_x509_get_alg_null +#define x509_get_ext mbedtls_x509_get_ext +#define x509_get_name mbedtls_x509_get_name +#define x509_get_rsassa_pss_params mbedtls_x509_get_rsassa_pss_params +#define x509_get_serial mbedtls_x509_get_serial +#define x509_get_sig mbedtls_x509_get_sig +#define x509_get_sig_alg mbedtls_x509_get_sig_alg +#define x509_get_time mbedtls_x509_get_time +#define x509_key_size_helper mbedtls_x509_key_size_helper +#define x509_name mbedtls_x509_name +#define x509_self_test mbedtls_x509_self_test +#define x509_sequence mbedtls_x509_sequence +#define x509_serial_gets mbedtls_x509_serial_gets +#define x509_set_extension mbedtls_x509_set_extension +#define x509_sig_alg_gets mbedtls_x509_sig_alg_gets +#define x509_string_to_names mbedtls_x509_string_to_names +#define x509_time mbedtls_x509_time +#define x509_time_expired mbedtls_x509_time_is_past +#define x509_time_future mbedtls_x509_time_is_future +#define x509_write_extensions mbedtls_x509_write_extensions +#define x509_write_names mbedtls_x509_write_names +#define x509_write_sig mbedtls_x509_write_sig +#define x509write_cert mbedtls_x509write_cert +#define x509write_crt_der mbedtls_x509write_crt_der +#define x509write_crt_free mbedtls_x509write_crt_free +#define x509write_crt_init mbedtls_x509write_crt_init +#define x509write_crt_pem mbedtls_x509write_crt_pem +#define x509write_crt_set_authority_key_identifier mbedtls_x509write_crt_set_authority_key_identifier +#define x509write_crt_set_basic_constraints mbedtls_x509write_crt_set_basic_constraints +#define x509write_crt_set_extension mbedtls_x509write_crt_set_extension +#define x509write_crt_set_issuer_key mbedtls_x509write_crt_set_issuer_key +#define x509write_crt_set_issuer_name mbedtls_x509write_crt_set_issuer_name +#define x509write_crt_set_key_usage mbedtls_x509write_crt_set_key_usage +#define x509write_crt_set_md_alg mbedtls_x509write_crt_set_md_alg +#define x509write_crt_set_ns_cert_type mbedtls_x509write_crt_set_ns_cert_type +#define x509write_crt_set_serial mbedtls_x509write_crt_set_serial +#define x509write_crt_set_subject_key mbedtls_x509write_crt_set_subject_key +#define x509write_crt_set_subject_key_identifier mbedtls_x509write_crt_set_subject_key_identifier +#define x509write_crt_set_subject_name mbedtls_x509write_crt_set_subject_name +#define x509write_crt_set_validity mbedtls_x509write_crt_set_validity +#define x509write_crt_set_version mbedtls_x509write_crt_set_version +#define x509write_csr mbedtls_x509write_csr +#define x509write_csr_der mbedtls_x509write_csr_der +#define x509write_csr_free mbedtls_x509write_csr_free +#define x509write_csr_init mbedtls_x509write_csr_init +#define x509write_csr_pem mbedtls_x509write_csr_pem +#define x509write_csr_set_extension mbedtls_x509write_csr_set_extension +#define x509write_csr_set_key mbedtls_x509write_csr_set_key +#define x509write_csr_set_key_usage mbedtls_x509write_csr_set_key_usage +#define x509write_csr_set_md_alg mbedtls_x509write_csr_set_md_alg +#define x509write_csr_set_ns_cert_type mbedtls_x509write_csr_set_ns_cert_type +#define x509write_csr_set_subject_name mbedtls_x509write_csr_set_subject_name +#define xtea_context mbedtls_xtea_context +#define xtea_crypt_cbc mbedtls_xtea_crypt_cbc +#define xtea_crypt_ecb mbedtls_xtea_crypt_ecb +#define xtea_free mbedtls_xtea_free +#define xtea_init mbedtls_xtea_init +#define xtea_self_test mbedtls_xtea_self_test +#define xtea_setup mbedtls_xtea_setup + +#endif /* compat-1.3.h */ +#endif /* MBEDTLS_DEPRECATED_REMOVED */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/config.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/config.h new file mode 100644 index 000000000..bb3dd75a4 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/config.h @@ -0,0 +1,3521 @@ +/** + * \file config.h + * + * \brief Configuration options (set of defines) + * + * This set of compile-time options may be used to enable + * or disable features selectively, and reduce the global + * memory footprint. + */ +/* + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +/** + * \name SECTION: System support + * + * This section sets system specific settings. + * \{ + */ + +/** + * \def MBEDTLS_HAVE_ASM + * + * The compiler has support for asm(). + * + * Requires support for asm() in compiler. + * + * Used in: + * library/aria.c + * library/timing.c + * include/mbedtls/bn_mul.h + * + * Required by: + * MBEDTLS_AESNI_C + * MBEDTLS_PADLOCK_C + * + * Comment to disable the use of assembly code. + */ +#define MBEDTLS_HAVE_ASM + +/** + * \def MBEDTLS_NO_UDBL_DIVISION + * + * The platform lacks support for double-width integer division (64-bit + * division on a 32-bit platform, 128-bit division on a 64-bit platform). + * + * Used in: + * include/mbedtls/bignum.h + * library/bignum.c + * + * The bignum code uses double-width division to speed up some operations. + * Double-width division is often implemented in software that needs to + * be linked with the program. The presence of a double-width integer + * type is usually detected automatically through preprocessor macros, + * but the automatic detection cannot know whether the code needs to + * and can be linked with an implementation of division for that type. + * By default division is assumed to be usable if the type is present. + * Uncomment this option to prevent the use of double-width division. + * + * Note that division for the native integer type is always required. + * Furthermore, a 64-bit type is always required even on a 32-bit + * platform, but it need not support multiplication or division. In some + * cases it is also desirable to disable some double-width operations. For + * example, if double-width division is implemented in software, disabling + * it can reduce code size in some embedded targets. + */ +//#define MBEDTLS_NO_UDBL_DIVISION + +/** + * \def MBEDTLS_NO_64BIT_MULTIPLICATION + * + * The platform lacks support for 32x32 -> 64-bit multiplication. + * + * Used in: + * library/poly1305.c + * + * Some parts of the library may use multiplication of two unsigned 32-bit + * operands with a 64-bit result in order to speed up computations. On some + * platforms, this is not available in hardware and has to be implemented in + * software, usually in a library provided by the toolchain. + * + * Sometimes it is not desirable to have to link to that library. This option + * removes the dependency of that library on platforms that lack a hardware + * 64-bit multiplier by embedding a software implementation in Mbed TLS. + * + * Note that depending on the compiler, this may decrease performance compared + * to using the library function provided by the toolchain. + */ +//#define MBEDTLS_NO_64BIT_MULTIPLICATION + +/** + * \def MBEDTLS_HAVE_SSE2 + * + * CPU supports SSE2 instruction set. + * + * Uncomment if the CPU supports SSE2 (IA-32 specific). + */ +//#define MBEDTLS_HAVE_SSE2 + +/** + * \def MBEDTLS_HAVE_TIME + * + * System has time.h and time(). + * The time does not need to be correct, only time differences are used, + * by contrast with MBEDTLS_HAVE_TIME_DATE + * + * Defining MBEDTLS_HAVE_TIME allows you to specify MBEDTLS_PLATFORM_TIME_ALT, + * MBEDTLS_PLATFORM_TIME_MACRO, MBEDTLS_PLATFORM_TIME_TYPE_MACRO and + * MBEDTLS_PLATFORM_STD_TIME. + * + * Comment if your system does not support time functions + */ +#define MBEDTLS_HAVE_TIME + +/** + * \def MBEDTLS_HAVE_TIME_DATE + * + * System has time.h, time(), and an implementation for + * mbedtls_platform_gmtime_r() (see below). + * The time needs to be correct (not necessarily very accurate, but at least + * the date should be correct). This is used to verify the validity period of + * X.509 certificates. + * + * Comment if your system does not have a correct clock. + * + * \note mbedtls_platform_gmtime_r() is an abstraction in platform_util.h that + * behaves similarly to the gmtime_r() function from the C standard. Refer to + * the documentation for mbedtls_platform_gmtime_r() for more information. + * + * \note It is possible to configure an implementation for + * mbedtls_platform_gmtime_r() at compile-time by using the macro + * MBEDTLS_PLATFORM_GMTIME_R_ALT. + */ +#define MBEDTLS_HAVE_TIME_DATE + +/** + * \def MBEDTLS_PLATFORM_MEMORY + * + * Enable the memory allocation layer. + * + * By default mbed TLS uses the system-provided calloc() and free(). + * This allows different allocators (self-implemented or provided) to be + * provided to the platform abstraction layer. + * + * Enabling MBEDTLS_PLATFORM_MEMORY without the + * MBEDTLS_PLATFORM_{FREE,CALLOC}_MACROs will provide + * "mbedtls_platform_set_calloc_free()" allowing you to set an alternative calloc() and + * free() function pointer at runtime. + * + * Enabling MBEDTLS_PLATFORM_MEMORY and specifying + * MBEDTLS_PLATFORM_{CALLOC,FREE}_MACROs will allow you to specify the + * alternate function at compile time. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Enable this layer to allow use of alternative memory allocators. + */ +//#define MBEDTLS_PLATFORM_MEMORY + +/** + * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + * + * Do not assign standard functions in the platform layer (e.g. calloc() to + * MBEDTLS_PLATFORM_STD_CALLOC and printf() to MBEDTLS_PLATFORM_STD_PRINTF) + * + * This makes sure there are no linking errors on platforms that do not support + * these functions. You will HAVE to provide alternatives, either at runtime + * via the platform_set_xxx() functions or at compile time by setting + * the MBEDTLS_PLATFORM_STD_XXX defines, or enabling a + * MBEDTLS_PLATFORM_XXX_MACRO. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Uncomment to prevent default assignment of standard functions in the + * platform layer. + */ +//#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + +/** + * \def MBEDTLS_PLATFORM_EXIT_ALT + * + * MBEDTLS_PLATFORM_XXX_ALT: Uncomment a macro to let mbed TLS support the + * function in the platform abstraction layer. + * + * Example: In case you uncomment MBEDTLS_PLATFORM_PRINTF_ALT, mbed TLS will + * provide a function "mbedtls_platform_set_printf()" that allows you to set an + * alternative printf function pointer. + * + * All these define require MBEDTLS_PLATFORM_C to be defined! + * + * \note MBEDTLS_PLATFORM_SNPRINTF_ALT is required on Windows; + * it will be enabled automatically by check_config.h + * + * \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as + * MBEDTLS_PLATFORM_XXX_MACRO! + * + * Requires: MBEDTLS_PLATFORM_TIME_ALT requires MBEDTLS_HAVE_TIME + * + * Uncomment a macro to enable alternate implementation of specific base + * platform function + */ +//#define MBEDTLS_PLATFORM_EXIT_ALT +//#define MBEDTLS_PLATFORM_TIME_ALT +//#define MBEDTLS_PLATFORM_FPRINTF_ALT +//#define MBEDTLS_PLATFORM_PRINTF_ALT +//#define MBEDTLS_PLATFORM_SNPRINTF_ALT +//#define MBEDTLS_PLATFORM_VSNPRINTF_ALT +//#define MBEDTLS_PLATFORM_NV_SEED_ALT +//#define MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT + +/** + * \def MBEDTLS_DEPRECATED_WARNING + * + * Mark deprecated functions so that they generate a warning if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * This only works with GCC and Clang. With other compilers, you may want to + * use MBEDTLS_DEPRECATED_REMOVED + * + * Uncomment to get warnings on using deprecated functions. + */ +//#define MBEDTLS_DEPRECATED_WARNING + +/** + * \def MBEDTLS_DEPRECATED_REMOVED + * + * Remove deprecated functions so that they generate an error if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * Uncomment to get errors on using deprecated functions. + */ +//#define MBEDTLS_DEPRECATED_REMOVED + +/** + * \def MBEDTLS_CHECK_PARAMS + * + * This configuration option controls whether the library validates more of + * the parameters passed to it. + * + * When this flag is not defined, the library only attempts to validate an + * input parameter if: (1) they may come from the outside world (such as the + * network, the filesystem, etc.) or (2) not validating them could result in + * internal memory errors such as overflowing a buffer controlled by the + * library. On the other hand, it doesn't attempt to validate parameters whose + * values are fully controlled by the application (such as pointers). + * + * When this flag is defined, the library additionally attempts to validate + * parameters that are fully controlled by the application, and should always + * be valid if the application code is fully correct and trusted. + * + * For example, when a function accepts as input a pointer to a buffer that may + * contain untrusted data, and its documentation mentions that this pointer + * must not be NULL: + * - the pointer is checked to be non-NULL only if this option is enabled + * - the content of the buffer is always validated + * + * When this flag is defined, if a library function receives a parameter that + * is invalid, it will: + * - invoke the macro MBEDTLS_PARAM_FAILED() which by default expands to a + * call to the function mbedtls_param_failed() + * - immediately return (with a specific error code unless the function + * returns void and can't communicate an error). + * + * When defining this flag, you also need to: + * - either provide a definition of the function mbedtls_param_failed() in + * your application (see platform_util.h for its prototype) as the library + * calls that function, but does not provide a default definition for it, + * - or provide a different definition of the macro MBEDTLS_PARAM_FAILED() + * below if the above mechanism is not flexible enough to suit your needs. + * See the documentation of this macro later in this file. + * + * Uncomment to enable validation of application-controlled parameters. + */ +//#define MBEDTLS_CHECK_PARAMS + +/* \} name SECTION: System support */ + +/** + * \name SECTION: mbed TLS feature support + * + * This section sets support for features that are or are not needed + * within the modules that are enabled. + * \{ + */ + +/** + * \def MBEDTLS_TIMING_ALT + * + * Uncomment to provide your own alternate implementation for mbedtls_timing_hardclock(), + * mbedtls_timing_get_timer(), mbedtls_set_alarm(), mbedtls_set/get_delay() + * + * Only works if you have MBEDTLS_TIMING_C enabled. + * + * You will need to provide a header "timing_alt.h" and an implementation at + * compile time. + */ +//#define MBEDTLS_TIMING_ALT + +/** + * \def MBEDTLS_AES_ALT + * + * MBEDTLS__MODULE_NAME__ALT: Uncomment a macro to let mbed TLS use your + * alternate core implementation of a symmetric crypto, an arithmetic or hash + * module (e.g. platform specific assembly optimized implementations). Keep + * in mind that the function prototypes should remain the same. + * + * This replaces the whole module. If you only want to replace one of the + * functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_AES_ALT, mbed TLS will no longer + * provide the "struct mbedtls_aes_context" definition and omit the base + * function declarations and implementations. "aes_alt.h" will be included from + * "aes.h" to include the new function definitions. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * module. + * + * \warning MD2, MD4, MD5, ARC4, DES and SHA-1 are considered weak and their + * use constitutes a security risk. If possible, we recommend + * avoiding dependencies on them, and considering stronger message + * digests and ciphers instead. + * + */ +//#define MBEDTLS_AES_ALT +//#define MBEDTLS_ARC4_ALT +//#define MBEDTLS_ARIA_ALT +//#define MBEDTLS_BLOWFISH_ALT +//#define MBEDTLS_CAMELLIA_ALT +//#define MBEDTLS_CCM_ALT +//#define MBEDTLS_CHACHA20_ALT +//#define MBEDTLS_CHACHAPOLY_ALT +//#define MBEDTLS_CMAC_ALT +//#define MBEDTLS_DES_ALT +//#define MBEDTLS_DHM_ALT +//#define MBEDTLS_ECJPAKE_ALT +//#define MBEDTLS_GCM_ALT +//#define MBEDTLS_NIST_KW_ALT +//#define MBEDTLS_MD2_ALT +//#define MBEDTLS_MD4_ALT +//#define MBEDTLS_MD5_ALT +//#define MBEDTLS_POLY1305_ALT +//#define MBEDTLS_RIPEMD160_ALT +//#define MBEDTLS_RSA_ALT +//#define MBEDTLS_SHA1_ALT +//#define MBEDTLS_SHA256_ALT +//#define MBEDTLS_SHA512_ALT +//#define MBEDTLS_XTEA_ALT + +/* + * When replacing the elliptic curve module, pleace consider, that it is + * implemented with two .c files: + * - ecp.c + * - ecp_curves.c + * You can replace them very much like all the other MBEDTLS__MODULE_NAME__ALT + * macros as described above. The only difference is that you have to make sure + * that you provide functionality for both .c files. + */ +//#define MBEDTLS_ECP_ALT + +/** + * \def MBEDTLS_MD2_PROCESS_ALT + * + * MBEDTLS__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use you + * alternate core implementation of symmetric crypto or hash function. Keep in + * mind that function prototypes should remain the same. + * + * This replaces only one function. The header file from mbed TLS is still + * used, in contrast to the MBEDTLS__MODULE_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_SHA256_PROCESS_ALT, mbed TLS will + * no longer provide the mbedtls_sha1_process() function, but it will still provide + * the other function (using your mbedtls_sha1_process() function) and the definition + * of mbedtls_sha1_context, so your implementation of mbedtls_sha1_process must be compatible + * with this definition. + * + * \note Because of a signature change, the core AES encryption and decryption routines are + * currently named mbedtls_aes_internal_encrypt and mbedtls_aes_internal_decrypt, + * respectively. When setting up alternative implementations, these functions should + * be overridden, but the wrapper functions mbedtls_aes_decrypt and mbedtls_aes_encrypt + * must stay untouched. + * + * \note If you use the AES_xxx_ALT macros, then is is recommended to also set + * MBEDTLS_AES_ROM_TABLES in order to help the linker garbage-collect the AES + * tables. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + * + * \warning MD2, MD4, MD5, DES and SHA-1 are considered weak and their use + * constitutes a security risk. If possible, we recommend avoiding + * dependencies on them, and considering stronger message digests + * and ciphers instead. + * + */ +//#define MBEDTLS_MD2_PROCESS_ALT +//#define MBEDTLS_MD4_PROCESS_ALT +//#define MBEDTLS_MD5_PROCESS_ALT +//#define MBEDTLS_RIPEMD160_PROCESS_ALT +//#define MBEDTLS_SHA1_PROCESS_ALT +//#define MBEDTLS_SHA256_PROCESS_ALT +//#define MBEDTLS_SHA512_PROCESS_ALT +//#define MBEDTLS_DES_SETKEY_ALT +//#define MBEDTLS_DES_CRYPT_ECB_ALT +//#define MBEDTLS_DES3_CRYPT_ECB_ALT +//#define MBEDTLS_AES_SETKEY_ENC_ALT +//#define MBEDTLS_AES_SETKEY_DEC_ALT +//#define MBEDTLS_AES_ENCRYPT_ALT +//#define MBEDTLS_AES_DECRYPT_ALT +//#define MBEDTLS_ECDH_GEN_PUBLIC_ALT +//#define MBEDTLS_ECDH_COMPUTE_SHARED_ALT +//#define MBEDTLS_ECDSA_VERIFY_ALT +//#define MBEDTLS_ECDSA_SIGN_ALT +//#define MBEDTLS_ECDSA_GENKEY_ALT + +/** + * \def MBEDTLS_ECP_INTERNAL_ALT + * + * Expose a part of the internal interface of the Elliptic Curve Point module. + * + * MBEDTLS_ECP__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use your + * alternative core implementation of elliptic curve arithmetic. Keep in mind + * that function prototypes should remain the same. + * + * This partially replaces one function. The header file from mbed TLS is still + * used, in contrast to the MBEDTLS_ECP_ALT flag. The original implementation + * is still present and it is used for group structures not supported by the + * alternative. + * + * Any of these options become available by defining MBEDTLS_ECP_INTERNAL_ALT + * and implementing the following functions: + * unsigned char mbedtls_internal_ecp_grp_capable( + * const mbedtls_ecp_group *grp ) + * int mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp ) + * void mbedtls_internal_ecp_free( const mbedtls_ecp_group *grp ) + * The mbedtls_internal_ecp_grp_capable function should return 1 if the + * replacement functions implement arithmetic for the given group and 0 + * otherwise. + * The functions mbedtls_internal_ecp_init and mbedtls_internal_ecp_free are + * called before and after each point operation and provide an opportunity to + * implement optimized set up and tear down instructions. + * + * Example: In case you uncomment MBEDTLS_ECP_INTERNAL_ALT and + * MBEDTLS_ECP_DOUBLE_JAC_ALT, mbed TLS will still provide the ecp_double_jac + * function, but will use your mbedtls_internal_ecp_double_jac if the group is + * supported (your mbedtls_internal_ecp_grp_capable function returns 1 when + * receives it as an argument). If the group is not supported then the original + * implementation is used. The other functions and the definition of + * mbedtls_ecp_group and mbedtls_ecp_point will not change, so your + * implementation of mbedtls_internal_ecp_double_jac and + * mbedtls_internal_ecp_grp_capable must be compatible with this definition. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + */ +/* Required for all the functions in this section */ +//#define MBEDTLS_ECP_INTERNAL_ALT +/* Support for Weierstrass curves with Jacobi representation */ +//#define MBEDTLS_ECP_RANDOMIZE_JAC_ALT +//#define MBEDTLS_ECP_ADD_MIXED_ALT +//#define MBEDTLS_ECP_DOUBLE_JAC_ALT +//#define MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT +//#define MBEDTLS_ECP_NORMALIZE_JAC_ALT +/* Support for curves with Montgomery arithmetic */ +//#define MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT +//#define MBEDTLS_ECP_RANDOMIZE_MXZ_ALT +//#define MBEDTLS_ECP_NORMALIZE_MXZ_ALT + +/** + * \def MBEDTLS_TEST_NULL_ENTROPY + * + * Enables testing and use of mbed TLS without any configured entropy sources. + * This permits use of the library on platforms before an entropy source has + * been integrated (see for example the MBEDTLS_ENTROPY_HARDWARE_ALT or the + * MBEDTLS_ENTROPY_NV_SEED switches). + * + * WARNING! This switch MUST be disabled in production builds, and is suitable + * only for development. + * Enabling the switch negates any security provided by the library. + * + * Requires MBEDTLS_ENTROPY_C, MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + * + */ +//#define MBEDTLS_TEST_NULL_ENTROPY + +/** + * \def MBEDTLS_ENTROPY_HARDWARE_ALT + * + * Uncomment this macro to let mbed TLS use your own implementation of a + * hardware entropy collector. + * + * Your function must be called \c mbedtls_hardware_poll(), have the same + * prototype as declared in entropy_poll.h, and accept NULL as first argument. + * + * Uncomment to use your own hardware entropy collector. + */ +//#define MBEDTLS_ENTROPY_HARDWARE_ALT + +/** + * \def MBEDTLS_AES_ROM_TABLES + * + * Use precomputed AES tables stored in ROM. + * + * Uncomment this macro to use precomputed AES tables stored in ROM. + * Comment this macro to generate AES tables in RAM at runtime. + * + * Tradeoff: Using precomputed ROM tables reduces RAM usage by ~8kb + * (or ~2kb if \c MBEDTLS_AES_FEWER_TABLES is used) and reduces the + * initialization time before the first AES operation can be performed. + * It comes at the cost of additional ~8kb ROM use (resp. ~2kb if \c + * MBEDTLS_AES_FEWER_TABLES below is used), and potentially degraded + * performance if ROM access is slower than RAM access. + * + * This option is independent of \c MBEDTLS_AES_FEWER_TABLES. + * + */ +//#define MBEDTLS_AES_ROM_TABLES + +/** + * \def MBEDTLS_AES_FEWER_TABLES + * + * Use less ROM/RAM for AES tables. + * + * Uncommenting this macro omits 75% of the AES tables from + * ROM / RAM (depending on the value of \c MBEDTLS_AES_ROM_TABLES) + * by computing their values on the fly during operations + * (the tables are entry-wise rotations of one another). + * + * Tradeoff: Uncommenting this reduces the RAM / ROM footprint + * by ~6kb but at the cost of more arithmetic operations during + * runtime. Specifically, one has to compare 4 accesses within + * different tables to 4 accesses with additional arithmetic + * operations within the same table. The performance gain/loss + * depends on the system and memory details. + * + * This option is independent of \c MBEDTLS_AES_ROM_TABLES. + * + */ +//#define MBEDTLS_AES_FEWER_TABLES + +/** + * \def MBEDTLS_CAMELLIA_SMALL_MEMORY + * + * Use less ROM for the Camellia implementation (saves about 768 bytes). + * + * Uncomment this macro to use less memory for Camellia. + */ +//#define MBEDTLS_CAMELLIA_SMALL_MEMORY + +/** + * \def MBEDTLS_CIPHER_MODE_CBC + * + * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CBC + +/** + * \def MBEDTLS_CIPHER_MODE_CFB + * + * Enable Cipher Feedback mode (CFB) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CFB + +/** + * \def MBEDTLS_CIPHER_MODE_CTR + * + * Enable Counter Block Cipher mode (CTR) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CTR + +/** + * \def MBEDTLS_CIPHER_MODE_OFB + * + * Enable Output Feedback mode (OFB) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_OFB + +/** + * \def MBEDTLS_CIPHER_MODE_XTS + * + * Enable Xor-encrypt-xor with ciphertext stealing mode (XTS) for AES. + */ +#define MBEDTLS_CIPHER_MODE_XTS + +/** + * \def MBEDTLS_CIPHER_NULL_CIPHER + * + * Enable NULL cipher. + * Warning: Only do so when you know what you are doing. This allows for + * encryption or channels without any security! + * + * Requires MBEDTLS_ENABLE_WEAK_CIPHERSUITES as well to enable + * the following ciphersuites: + * MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA + * + * Uncomment this macro to enable the NULL cipher and ciphersuites + */ +//#define MBEDTLS_CIPHER_NULL_CIPHER + +/** + * \def MBEDTLS_CIPHER_PADDING_PKCS7 + * + * MBEDTLS_CIPHER_PADDING_XXX: Uncomment or comment macros to add support for + * specific padding modes in the cipher layer with cipher modes that support + * padding (e.g. CBC) + * + * If you disable all padding modes, only full blocks can be used with CBC. + * + * Enable padding modes in the cipher layer. + */ +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define MBEDTLS_CIPHER_PADDING_ZEROS + +/** + * \def MBEDTLS_ENABLE_WEAK_CIPHERSUITES + * + * Enable weak ciphersuites in SSL / TLS. + * Warning: Only do so when you know what you are doing. This allows for + * channels with virtually no security at all! + * + * This enables the following ciphersuites: + * MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA + * + * Uncomment this macro to enable weak ciphersuites + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers instead. + */ +//#define MBEDTLS_ENABLE_WEAK_CIPHERSUITES + +/** + * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES + * + * Remove RC4 ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on RC4 from the default list as + * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to + * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them + * explicitly. + * + * Uncomment this macro to remove RC4 ciphersuites by default. + */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES + +/** + * \def MBEDTLS_REMOVE_3DES_CIPHERSUITES + * + * Remove 3DES ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on 3DES from the default list as + * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible + * to enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including + * them explicitly. + * + * A man-in-the-browser attacker can recover authentication tokens sent through + * a TLS connection using a 3DES based cipher suite (see "On the Practical + * (In-)Security of 64-bit Block Ciphers" by Karthikeyan Bhargavan and Gaëtan + * Leurent, see https://sweet32.info/SWEET32_CCS16.pdf). If this attack falls + * in your threat model or you are unsure, then you should keep this option + * enabled to remove 3DES based cipher suites. + * + * Comment this macro to keep 3DES in the default ciphersuite list. + */ +#define MBEDTLS_REMOVE_3DES_CIPHERSUITES + +/** + * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED + * + * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve + * module. By default all supported curves are enabled. + * + * Comment macros to disable the curve and functions for it + */ +#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +#define MBEDTLS_ECP_DP_SECP192K1_ENABLED +#define MBEDTLS_ECP_DP_SECP224K1_ENABLED +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define MBEDTLS_ECP_DP_BP256R1_ENABLED +#define MBEDTLS_ECP_DP_BP384R1_ENABLED +#define MBEDTLS_ECP_DP_BP512R1_ENABLED +#define MBEDTLS_ECP_DP_CURVE25519_ENABLED +#define MBEDTLS_ECP_DP_CURVE448_ENABLED + +/** + * \def MBEDTLS_ECP_NIST_OPTIM + * + * Enable specific 'modulo p' routines for each NIST prime. + * Depending on the prime and architecture, makes operations 4 to 8 times + * faster on the corresponding curve. + * + * Comment this macro to disable NIST curves optimisation. + */ +#define MBEDTLS_ECP_NIST_OPTIM + +/** + * \def MBEDTLS_ECP_RESTARTABLE + * + * Enable "non-blocking" ECC operations that can return early and be resumed. + * + * This allows various functions to pause by returning + * #MBEDTLS_ERR_ECP_IN_PROGRESS (or, for functions in the SSL module, + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) and then be called later again in + * order to further progress and eventually complete their operation. This is + * controlled through mbedtls_ecp_set_max_ops() which limits the maximum + * number of ECC operations a function may perform before pausing; see + * mbedtls_ecp_set_max_ops() for more information. + * + * This is useful in non-threaded environments if you want to avoid blocking + * for too long on ECC (and, hence, X.509 or SSL/TLS) operations. + * + * Uncomment this macro to enable restartable ECC computations. + * + * \note This option only works with the default software implementation of + * elliptic curve functionality. It is incompatible with + * MBEDTLS_ECP_ALT, MBEDTLS_ECDH_XXX_ALT, MBEDTLS_ECDSA_XXX_ALT + * and MBEDTLS_ECDH_LEGACY_CONTEXT. + */ +//#define MBEDTLS_ECP_RESTARTABLE + +/** + * \def MBEDTLS_ECDH_LEGACY_CONTEXT + * + * Use a backward compatible ECDH context. + * + * Mbed TLS supports two formats for ECDH contexts (#mbedtls_ecdh_context + * defined in `ecdh.h`). For most applications, the choice of format makes + * no difference, since all library functions can work with either format, + * except that the new format is incompatible with MBEDTLS_ECP_RESTARTABLE. + + * The new format used when this option is disabled is smaller + * (56 bytes on a 32-bit platform). In future versions of the library, it + * will support alternative implementations of ECDH operations. + * The new format is incompatible with applications that access + * context fields directly and with restartable ECP operations. + * + * Define this macro if you enable MBEDTLS_ECP_RESTARTABLE or if you + * want to access ECDH context fields directly. Otherwise you should + * comment out this macro definition. + * + * This option has no effect if #MBEDTLS_ECDH_C is not enabled. + * + * \note This configuration option is experimental. Future versions of the + * library may modify the way the ECDH context layout is configured + * and may modify the layout of the new context type. + */ +#define MBEDTLS_ECDH_LEGACY_CONTEXT + +/** + * \def MBEDTLS_ECDSA_DETERMINISTIC + * + * Enable deterministic ECDSA (RFC 6979). + * Standard ECDSA is "fragile" in the sense that lack of entropy when signing + * may result in a compromise of the long-term signing key. This is avoided by + * the deterministic variant. + * + * Requires: MBEDTLS_HMAC_DRBG_C + * + * Comment this macro to disable deterministic ECDSA. + */ +#define MBEDTLS_ECDSA_DETERMINISTIC + +/** + * \def MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + * + * Enable the PSK based ciphersuite modes in SSL / TLS. + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + * + * Enable the DHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + * + * \warning Using DHE constitutes a security risk as it + * is not possible to validate custom DH parameters. + * If possible, it is recommended users should consider + * preferring other methods of key exchange. + * See dhm.h for more details. + * + */ +#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + * + * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + * + * Enable the RSA-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + * + * Enable the RSA-only based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + */ +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + * + * Enable the DHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * + * \warning Using DHE constitutes a security risk as it + * is not possible to validate custom DH parameters. + * If possible, it is recommended users should consider + * preferring other methods of key exchange. + * See dhm.h for more details. + * + */ +#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + * + * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + * + * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, MBEDTLS_X509_CRT_PARSE_C, + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + * + * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + * + * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + * + * Enable the ECJPAKE based ciphersuite modes in SSL / TLS. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Requires: MBEDTLS_ECJPAKE_C + * MBEDTLS_SHA256_C + * MBEDTLS_ECP_DP_SECP256R1_ENABLED + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + +/** + * \def MBEDTLS_PK_PARSE_EC_EXTENDED + * + * Enhance support for reading EC keys using variants of SEC1 not allowed by + * RFC 5915 and RFC 5480. + * + * Currently this means parsing the SpecifiedECDomain choice of EC + * parameters (only known groups are supported, not arbitrary domains, to + * avoid validation issues). + * + * Disable if you only need to support RFC 5915 + 5480 key formats. + */ +#define MBEDTLS_PK_PARSE_EC_EXTENDED + +/** + * \def MBEDTLS_ERROR_STRERROR_DUMMY + * + * Enable a dummy error function to make use of mbedtls_strerror() in + * third party libraries easier when MBEDTLS_ERROR_C is disabled + * (no effect when MBEDTLS_ERROR_C is enabled). + * + * You can safely disable this if MBEDTLS_ERROR_C is enabled, or if you're + * not using mbedtls_strerror() or error_strerror() in your application. + * + * Disable if you run into name conflicts and want to really remove the + * mbedtls_strerror() + */ +#define MBEDTLS_ERROR_STRERROR_DUMMY + +/** + * \def MBEDTLS_GENPRIME + * + * Enable the prime-number generation code. + * + * Requires: MBEDTLS_BIGNUM_C + */ +#define MBEDTLS_GENPRIME + +/** + * \def MBEDTLS_FS_IO + * + * Enable functions that use the filesystem. + */ +#define MBEDTLS_FS_IO + +/** + * \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + * + * Do not add default entropy sources. These are the platform specific, + * mbedtls_timing_hardclock and HAVEGE based poll functions. + * + * This is useful to have more control over the added entropy sources in an + * application. + * + * Uncomment this macro to prevent loading of default entropy functions. + */ +//#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + +/** + * \def MBEDTLS_NO_PLATFORM_ENTROPY + * + * Do not use built-in platform entropy functions. + * This is useful if your platform does not support + * standards like the /dev/urandom or Windows CryptoAPI. + * + * Uncomment this macro to disable the built-in platform entropy functions. + */ +//#define MBEDTLS_NO_PLATFORM_ENTROPY + +/** + * \def MBEDTLS_ENTROPY_FORCE_SHA256 + * + * Force the entropy accumulator to use a SHA-256 accumulator instead of the + * default SHA-512 based one (if both are available). + * + * Requires: MBEDTLS_SHA256_C + * + * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option + * if you have performance concerns. + * + * This option is only useful if both MBEDTLS_SHA256_C and + * MBEDTLS_SHA512_C are defined. Otherwise the available hash module is used. + */ +//#define MBEDTLS_ENTROPY_FORCE_SHA256 + +/** + * \def MBEDTLS_ENTROPY_NV_SEED + * + * Enable the non-volatile (NV) seed file-based entropy source. + * (Also enables the NV seed read/write functions in the platform layer) + * + * This is crucial (if not required) on systems that do not have a + * cryptographic entropy source (in hardware or kernel) available. + * + * Requires: MBEDTLS_ENTROPY_C, MBEDTLS_PLATFORM_C + * + * \note The read/write functions that are used by the entropy source are + * determined in the platform layer, and can be modified at runtime and/or + * compile-time depending on the flags (MBEDTLS_PLATFORM_NV_SEED_*) used. + * + * \note If you use the default implementation functions that read a seedfile + * with regular fopen(), please make sure you make a seedfile with the + * proper name (defined in MBEDTLS_PLATFORM_STD_NV_SEED_FILE) and at + * least MBEDTLS_ENTROPY_BLOCK_SIZE bytes in size that can be read from + * and written to or you will get an entropy source error! The default + * implementation will only use the first MBEDTLS_ENTROPY_BLOCK_SIZE + * bytes from the file. + * + * \note The entropy collector will write to the seed file before entropy is + * given to an external source, to update it. + */ +//#define MBEDTLS_ENTROPY_NV_SEED + +/** + * \def MBEDTLS_MEMORY_DEBUG + * + * Enable debugging of buffer allocator memory issues. Automatically prints + * (to stderr) all (fatal) messages on memory allocation issues. Enables + * function for 'debug output' of allocated memory. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Uncomment this macro to let the buffer allocator print out error messages. + */ +//#define MBEDTLS_MEMORY_DEBUG + +/** + * \def MBEDTLS_MEMORY_BACKTRACE + * + * Include backtrace information with each allocated block. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * GLIBC-compatible backtrace() an backtrace_symbols() support + * + * Uncomment this macro to include backtrace information + */ +//#define MBEDTLS_MEMORY_BACKTRACE + +/** + * \def MBEDTLS_PK_RSA_ALT_SUPPORT + * + * Support external private RSA keys (eg from a HSM) in the PK layer. + * + * Comment this macro to disable support for external private RSA keys. + */ +#define MBEDTLS_PK_RSA_ALT_SUPPORT + +/** + * \def MBEDTLS_PKCS1_V15 + * + * Enable support for PKCS#1 v1.5 encoding. + * + * Requires: MBEDTLS_RSA_C + * + * This enables support for PKCS#1 v1.5 operations. + */ +#define MBEDTLS_PKCS1_V15 + +/** + * \def MBEDTLS_PKCS1_V21 + * + * Enable support for PKCS#1 v2.1 encoding. + * + * Requires: MBEDTLS_MD_C, MBEDTLS_RSA_C + * + * This enables support for RSAES-OAEP and RSASSA-PSS operations. + */ +#define MBEDTLS_PKCS1_V21 + +/** + * \def MBEDTLS_PSA_CRYPTO_SPM + * + * When MBEDTLS_PSA_CRYPTO_SPM is defined, the code is built for SPM (Secure + * Partition Manager) integration which separates the code into two parts: a + * NSPE (Non-Secure Process Environment) and an SPE (Secure Process + * Environment). + * + * Module: library/psa_crypto.c + * Requires: MBEDTLS_PSA_CRYPTO_C + * + */ +//#define MBEDTLS_PSA_CRYPTO_SPM + +/** + * \def MBEDTLS_PSA_INJECT_ENTROPY + * + * Enable support for entropy injection at first boot. This feature is + * required on systems that do not have a built-in entropy source (TRNG). + * This feature is currently not supported on systems that have a built-in + * entropy source. + * + * Requires: MBEDTLS_PSA_CRYPTO_STORAGE_C, MBEDTLS_ENTROPY_NV_SEED + * + */ +//#define MBEDTLS_PSA_INJECT_ENTROPY + +/** + * \def MBEDTLS_RSA_NO_CRT + * + * Do not use the Chinese Remainder Theorem + * for the RSA private operation. + * + * Uncomment this macro to disable the use of CRT in RSA. + * + */ +//#define MBEDTLS_RSA_NO_CRT + +/** + * \def MBEDTLS_SELF_TEST + * + * Enable the checkup functions (*_self_test). + */ +#define MBEDTLS_SELF_TEST + +/** + * \def MBEDTLS_SHA256_SMALLER + * + * Enable an implementation of SHA-256 that has lower ROM footprint but also + * lower performance. + * + * The default implementation is meant to be a reasonnable compromise between + * performance and size. This version optimizes more aggressively for size at + * the expense of performance. Eg on Cortex-M4 it reduces the size of + * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about + * 30%. + * + * Uncomment to enable the smaller implementation of SHA256. + */ +//#define MBEDTLS_SHA256_SMALLER + +/** + * \def MBEDTLS_SSL_ALL_ALERT_MESSAGES + * + * Enable sending of alert messages in case of encountered errors as per RFC. + * If you choose not to send the alert messages, mbed TLS can still communicate + * with other servers, only debugging of failures is harder. + * + * The advantage of not sending alert messages, is that no information is given + * about reasons for failures thus preventing adversaries of gaining intel. + * + * Enable sending of all alert messages + */ +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES + +/** + * \def MBEDTLS_SSL_DTLS_CONNECTION_ID + * + * Enable support for the DTLS Connection ID extension + * (version draft-ietf-tls-dtls-connection-id-05, + * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05) + * which allows to identify DTLS connections across changes + * in the underlying transport. + * + * Setting this option enables the SSL APIs `mbedtls_ssl_set_cid()`, + * `mbedtls_ssl_get_peer_cid()` and `mbedtls_ssl_conf_cid()`. + * See the corresponding documentation for more information. + * + * \warning The Connection ID extension is still in draft state. + * We make no stability promises for the availability + * or the shape of the API controlled by this option. + * + * The maximum lengths of outgoing and incoming CIDs can be configured + * through the options + * - MBEDTLS_SSL_CID_OUT_LEN_MAX + * - MBEDTLS_SSL_CID_IN_LEN_MAX. + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + * + * Uncomment to enable the Connection ID extension. + */ +//#define MBEDTLS_SSL_DTLS_CONNECTION_ID + +/** + * \def MBEDTLS_SSL_ASYNC_PRIVATE + * + * Enable asynchronous external private key operations in SSL. This allows + * you to configure an SSL connection to call an external cryptographic + * module to perform private key operations instead of performing the + * operation inside the library. + * + */ +//#define MBEDTLS_SSL_ASYNC_PRIVATE + +/** + * \def MBEDTLS_SSL_DEBUG_ALL + * + * Enable the debug messages in SSL module for all issues. + * Debug messages have been disabled in some places to prevent timing + * attacks due to (unbalanced) debugging function calls. + * + * If you need all error reporting you should enable this during debugging, + * but remove this for production servers that should log as well. + * + * Uncomment this macro to report all debug messages on errors introducing + * a timing side-channel. + * + */ +//#define MBEDTLS_SSL_DEBUG_ALL + +/** \def MBEDTLS_SSL_ENCRYPT_THEN_MAC + * + * Enable support for Encrypt-then-MAC, RFC 7366. + * + * This allows peers that both support it to use a more robust protection for + * ciphersuites using CBC, providing deep resistance against timing attacks + * on the padding or underlying cipher. + * + * This only affects CBC ciphersuites, and is useless if none is defined. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Encrypt-then-MAC + */ +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC + +/** \def MBEDTLS_SSL_EXTENDED_MASTER_SECRET + * + * Enable support for Extended Master Secret, aka Session Hash + * (draft-ietf-tls-session-hash-02). + * + * This was introduced as "the proper fix" to the Triple Handshake familiy of + * attacks, but it is recommended to always use it (even if you disable + * renegotiation), since it actually fixes a more fundamental issue in the + * original SSL/TLS design, and has implications beyond Triple Handshake. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Extended Master Secret. + */ +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET + +/** + * \def MBEDTLS_SSL_FALLBACK_SCSV + * + * Enable support for FALLBACK_SCSV (draft-ietf-tls-downgrade-scsv-00). + * + * For servers, it is recommended to always enable this, unless you support + * only one version of TLS, or know for sure that none of your clients + * implements a fallback strategy. + * + * For clients, you only need this if you're using a fallback strategy, which + * is not recommended in the first place, unless you absolutely need it to + * interoperate with buggy (version-intolerant) servers. + * + * Comment this macro to disable support for FALLBACK_SCSV + */ +#define MBEDTLS_SSL_FALLBACK_SCSV + +/** + * \def MBEDTLS_SSL_KEEP_PEER_CERTIFICATE + * + * This option controls the availability of the API mbedtls_ssl_get_peer_cert() + * giving access to the peer's certificate after completion of the handshake. + * + * Unless you need mbedtls_ssl_peer_cert() in your application, it is + * recommended to disable this option for reduced RAM usage. + * + * \note If this option is disabled, mbedtls_ssl_get_peer_cert() is still + * defined, but always returns \c NULL. + * + * \note This option has no influence on the protection against the + * triple handshake attack. Even if it is disabled, Mbed TLS will + * still ensure that certificates do not change during renegotiation, + * for exaple by keeping a hash of the peer's certificate. + * + * Comment this macro to disable storing the peer's certificate + * after the handshake. + */ +#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE + +/** + * \def MBEDTLS_SSL_HW_RECORD_ACCEL + * + * Enable hooking functions in SSL module for hardware acceleration of + * individual records. + * + * Uncomment this macro to enable hooking functions. + */ +//#define MBEDTLS_SSL_HW_RECORD_ACCEL + +/** + * \def MBEDTLS_SSL_CBC_RECORD_SPLITTING + * + * Enable 1/n-1 record splitting for CBC mode in SSLv3 and TLS 1.0. + * + * This is a countermeasure to the BEAST attack, which also minimizes the risk + * of interoperability issues compared to sending 0-length records. + * + * Comment this macro to disable 1/n-1 record splitting. + */ +#define MBEDTLS_SSL_CBC_RECORD_SPLITTING + +/** + * \def MBEDTLS_SSL_RENEGOTIATION + * + * Enable support for TLS renegotiation. + * + * The two main uses of renegotiation are (1) refresh keys on long-lived + * connections and (2) client authentication after the initial handshake. + * If you don't need renegotiation, it's probably better to disable it, since + * it has been associated with security issues in the past and is easy to + * misuse/misunderstand. + * + * Comment this to disable support for renegotiation. + * + * \note Even if this option is disabled, both client and server are aware + * of the Renegotiation Indication Extension (RFC 5746) used to + * prevent the SSL renegotiation attack (see RFC 5746 Sect. 1). + * (See \c mbedtls_ssl_conf_legacy_renegotiation for the + * configuration of this extension). + * + */ +#define MBEDTLS_SSL_RENEGOTIATION + +/** + * \def MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + * + * Enable support for receiving and parsing SSLv2 Client Hello messages for the + * SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to enable support for SSLv2 Client Hello messages. + */ +//#define MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + +/** + * \def MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + * + * Pick the ciphersuite according to the client's preferences rather than ours + * in the SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to respect client's ciphersuite order + */ +//#define MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + +/** + * \def MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + * + * Enable support for RFC 6066 max_fragment_length extension in SSL. + * + * Comment this macro to disable support for the max_fragment_length extension + */ +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + +/** + * \def MBEDTLS_SSL_PROTO_SSL3 + * + * Enable support for SSL 3.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for SSL 3.0 + */ +//#define MBEDTLS_SSL_PROTO_SSL3 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1 + * + * Enable support for TLS 1.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_1 + * + * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled). + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.1 / DTLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1_1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_2 + * + * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled). + * + * Requires: MBEDTLS_SHA1_C or MBEDTLS_SHA256_C or MBEDTLS_SHA512_C + * (Depends on ciphersuites) + * + * Comment this macro to disable support for TLS 1.2 / DTLS 1.2 + */ +#define MBEDTLS_SSL_PROTO_TLS1_2 + +/** + * \def MBEDTLS_SSL_PROTO_DTLS + * + * Enable support for DTLS (all available versions). + * + * Enable this and MBEDTLS_SSL_PROTO_TLS1_1 to enable DTLS 1.0, + * and/or this and MBEDTLS_SSL_PROTO_TLS1_2 to enable DTLS 1.2. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1_1 + * or MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for DTLS + */ +#define MBEDTLS_SSL_PROTO_DTLS + +/** + * \def MBEDTLS_SSL_ALPN + * + * Enable support for RFC 7301 Application Layer Protocol Negotiation. + * + * Comment this macro to disable support for ALPN. + */ +#define MBEDTLS_SSL_ALPN + +/** + * \def MBEDTLS_SSL_DTLS_ANTI_REPLAY + * + * Enable support for the anti-replay mechanism in DTLS. + * + * Requires: MBEDTLS_SSL_TLS_C + * MBEDTLS_SSL_PROTO_DTLS + * + * \warning Disabling this is often a security risk! + * See mbedtls_ssl_conf_dtls_anti_replay() for details. + * + * Comment this to disable anti-replay in DTLS. + */ +#define MBEDTLS_SSL_DTLS_ANTI_REPLAY + +/** + * \def MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Enable support for HelloVerifyRequest on DTLS servers. + * + * This feature is highly recommended to prevent DTLS servers being used as + * amplifiers in DoS attacks against other hosts. It should always be enabled + * unless you know for sure amplification cannot be a problem in the + * environment in which your server operates. + * + * \warning Disabling this can ba a security risk! (see above) + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + * + * Comment this to disable support for HelloVerifyRequest. + */ +#define MBEDTLS_SSL_DTLS_HELLO_VERIFY + +/** + * \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + * + * Enable server-side support for clients that reconnect from the same port. + * + * Some clients unexpectedly close the connection and try to reconnect using the + * same source port. This needs special support from the server to handle the + * new connection securely, as described in section 4.2.8 of RFC 6347. This + * flag enables that support. + * + * Requires: MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Comment this to disable support for clients reusing the source port. + */ +#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + +/** + * \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT + * + * Enable support for a limit of records with bad MAC. + * + * See mbedtls_ssl_conf_dtls_badmac_limit(). + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + */ +#define MBEDTLS_SSL_DTLS_BADMAC_LIMIT + +/** + * \def MBEDTLS_SSL_SESSION_TICKETS + * + * Enable support for RFC 5077 session tickets in SSL. + * Client-side, provides full support for session tickets (maintenance of a + * session store remains the responsibility of the application, though). + * Server-side, you also need to provide callbacks for writing and parsing + * tickets, including authenticated encryption and key management. Example + * callbacks are provided by MBEDTLS_SSL_TICKET_C. + * + * Comment this macro to disable support for SSL session tickets + */ +#define MBEDTLS_SSL_SESSION_TICKETS + +/** + * \def MBEDTLS_SSL_EXPORT_KEYS + * + * Enable support for exporting key block and master secret. + * This is required for certain users of TLS, e.g. EAP-TLS. + * + * Comment this macro to disable support for key export + */ +#define MBEDTLS_SSL_EXPORT_KEYS + +/** + * \def MBEDTLS_SSL_SERVER_NAME_INDICATION + * + * Enable support for RFC 6066 server name indication (SNI) in SSL. + * + * Requires: MBEDTLS_X509_CRT_PARSE_C + * + * Comment this macro to disable support for server name indication in SSL + */ +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/** + * \def MBEDTLS_SSL_TRUNCATED_HMAC + * + * Enable support for RFC 6066 truncated HMAC in SSL. + * + * Comment this macro to disable support for truncated HMAC in SSL + */ +#define MBEDTLS_SSL_TRUNCATED_HMAC + +/** + * \def MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT + * + * Fallback to old (pre-2.7), non-conforming implementation of the truncated + * HMAC extension which also truncates the HMAC key. Note that this option is + * only meant for a transitory upgrade period and is likely to be removed in + * a future version of the library. + * + * \warning The old implementation is non-compliant and has a security weakness + * (2^80 brute force attack on the HMAC key used for a single, + * uninterrupted connection). This should only be enabled temporarily + * when (1) the use of truncated HMAC is essential in order to save + * bandwidth, and (2) the peer is an Mbed TLS stack that doesn't use + * the fixed implementation yet (pre-2.7). + * + * \deprecated This option is deprecated and will likely be removed in a + * future version of Mbed TLS. + * + * Uncomment to fallback to old, non-compliant truncated HMAC implementation. + * + * Requires: MBEDTLS_SSL_TRUNCATED_HMAC + */ +//#define MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT + +/** + * \def MBEDTLS_THREADING_ALT + * + * Provide your own alternate threading implementation. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to allow your own alternate threading implementation. + */ +//#define MBEDTLS_THREADING_ALT + +/** + * \def MBEDTLS_THREADING_PTHREAD + * + * Enable the pthread wrapper layer for the threading layer. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to enable pthread mutexes. + */ +//#define MBEDTLS_THREADING_PTHREAD + +/** + * \def MBEDTLS_USE_PSA_CRYPTO + * + * Make the X.509 and TLS library use PSA for cryptographic operations, and + * enable new APIs for using keys handled by PSA Crypto. + * + * \note Development of this option is currently in progress, and parts + * of the X.509 and TLS modules are not ported to PSA yet. However, these parts + * will still continue to work as usual, so enabling this option should not + * break backwards compatibility. + * + * \warning The PSA Crypto API is in beta stage. While you're welcome to + * experiment using it, incompatible API changes are still possible, and some + * parts may not have reached the same quality as the rest of Mbed TLS yet. + * + * \warning This option enables new Mbed TLS APIs that are dependent on the + * PSA Crypto API, so can't come with the same stability guarantees as the + * rest of the Mbed TLS APIs. You're welcome to experiment with them, but for + * now, access to these APIs is opt-in (via enabling the present option), in + * order to clearly differentiate them from the stable Mbed TLS APIs. + * + * Requires: MBEDTLS_PSA_CRYPTO_C. + * + * Uncomment this to enable internal use of PSA Crypto and new associated APIs. + */ +//#define MBEDTLS_USE_PSA_CRYPTO + +/** + * \def MBEDTLS_VERSION_FEATURES + * + * Allow run-time checking of compile-time enabled features. Thus allowing users + * to check at run-time if the library is for instance compiled with threading + * support via mbedtls_version_check_feature(). + * + * Requires: MBEDTLS_VERSION_C + * + * Comment this to disable run-time checking and save ROM space + */ +#define MBEDTLS_VERSION_FEATURES + +/** + * \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an extension in a v1 or v2 certificate. + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + +/** + * \def MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an unknown critical extension. + * + * \warning Depending on your PKI use, enabling this can be a security risk! + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + +/** + * \def MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK + * + * If set, this enables the X.509 API `mbedtls_x509_crt_verify_with_ca_cb()` + * and the SSL API `mbedtls_ssl_conf_ca_cb()` which allow users to configure + * the set of trusted certificates through a callback instead of a linked + * list. + * + * This is useful for example in environments where a large number of trusted + * certificates is present and storing them in a linked list isn't efficient + * enough, or when the set of trusted certificates changes frequently. + * + * See the documentation of `mbedtls_x509_crt_verify_with_ca_cb()` and + * `mbedtls_ssl_conf_ca_cb()` for more information. + * + * Uncomment to enable trusted certificate callbacks. + */ +//#define MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK + +/** + * \def MBEDTLS_X509_CHECK_KEY_USAGE + * + * Enable verification of the keyUsage extension (CA and leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused + * (intermediate) CA and leaf certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip keyUsage checking for both CA and leaf certificates. + */ +#define MBEDTLS_X509_CHECK_KEY_USAGE + +/** + * \def MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + * + * Enable verification of the extendedKeyUsage extension (leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip extendedKeyUsage checking for certificates. + */ +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/** + * \def MBEDTLS_X509_RSASSA_PSS_SUPPORT + * + * Enable parsing and verification of X.509 certificates, CRLs and CSRS + * signed with RSASSA-PSS (aka PKCS#1 v2.1). + * + * Comment this macro to disallow using RSASSA-PSS in certificates. + */ +#define MBEDTLS_X509_RSASSA_PSS_SUPPORT + +/** + * \def MBEDTLS_ZLIB_SUPPORT + * + * If set, the SSL/TLS module uses ZLIB to support compression and + * decompression of packet data. + * + * \warning TLS-level compression MAY REDUCE SECURITY! See for example the + * CRIME attack. Before enabling this option, you should examine with care if + * CRIME or similar exploits may be applicable to your use case. + * + * \note Currently compression can't be used with DTLS. + * + * \deprecated This feature is deprecated and will be removed + * in the next major revision of the library. + * + * Used in: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This feature requires zlib library and headers to be present. + * + * Uncomment to enable use of ZLIB + */ +//#define MBEDTLS_ZLIB_SUPPORT +/* \} name SECTION: mbed TLS feature support */ + +/** + * \name SECTION: mbed TLS modules + * + * This section enables or disables entire modules in mbed TLS + * \{ + */ + +/** + * \def MBEDTLS_AESNI_C + * + * Enable AES-NI support on x86-64. + * + * Module: library/aesni.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the AES-NI instructions on x86-64 + */ +#define MBEDTLS_AESNI_C + +/** + * \def MBEDTLS_AES_C + * + * Enable the AES block cipher. + * + * Module: library/aes.c + * Caller: library/cipher.c + * library/pem.c + * library/ctr_drbg.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * + * PEM_PARSE uses AES for decrypting encrypted keys. + */ +#define MBEDTLS_AES_C + +/** + * \def MBEDTLS_ARC4_C + * + * Enable the ARCFOUR stream cipher. + * + * Module: library/arc4.c + * Caller: library/cipher.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. If possible, we recommend avoidng dependencies on + * it, and considering stronger ciphers instead. + * + */ +#define MBEDTLS_ARC4_C + +/** + * \def MBEDTLS_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509.c + * library/dhm.c + * library/pkcs12.c + * library/pkcs5.c + * library/pkparse.c + */ +#define MBEDTLS_ASN1_PARSE_C + +/** + * \def MBEDTLS_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + * Caller: library/ecdsa.c + * library/pkwrite.c + * library/x509_create.c + * library/x509write_crt.c + * library/x509write_csr.c + */ +#define MBEDTLS_ASN1_WRITE_C + +/** + * \def MBEDTLS_BASE64_C + * + * Enable the Base64 module. + * + * Module: library/base64.c + * Caller: library/pem.c + * + * This module is required for PEM support (required by X.509). + */ +#define MBEDTLS_BASE64_C + +/** + * \def MBEDTLS_BIGNUM_C + * + * Enable the multi-precision integer library. + * + * Module: library/bignum.c + * Caller: library/dhm.c + * library/ecp.c + * library/ecdsa.c + * library/rsa.c + * library/rsa_internal.c + * library/ssl_tls.c + * + * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support. + */ +#define MBEDTLS_BIGNUM_C + +/** + * \def MBEDTLS_BLOWFISH_C + * + * Enable the Blowfish block cipher. + * + * Module: library/blowfish.c + */ +#define MBEDTLS_BLOWFISH_C + +/** + * \def MBEDTLS_CAMELLIA_C + * + * Enable the Camellia block cipher. + * + * Module: library/camellia.c + * Caller: library/cipher.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + */ +#define MBEDTLS_CAMELLIA_C + +/** + * \def MBEDTLS_ARIA_C + * + * Enable the ARIA block cipher. + * + * Module: library/aria.c + * Caller: library/cipher.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * + * MBEDTLS_TLS_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 + */ +//#define MBEDTLS_ARIA_C + +/** + * \def MBEDTLS_CCM_C + * + * Enable the Counter with CBC-MAC (CCM) mode for 128-bit block cipher. + * + * Module: library/ccm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-CCM ciphersuites, if other requisites are + * enabled as well. + */ +#define MBEDTLS_CCM_C + +/** + * \def MBEDTLS_CERTS_C + * + * Enable the test certificates. + * + * Module: library/certs.c + * Caller: + * + * This module is used for testing (ssl_client/server). + */ +#define MBEDTLS_CERTS_C + +/** + * \def MBEDTLS_CHACHA20_C + * + * Enable the ChaCha20 stream cipher. + * + * Module: library/chacha20.c + */ +#define MBEDTLS_CHACHA20_C + +/** + * \def MBEDTLS_CHACHAPOLY_C + * + * Enable the ChaCha20-Poly1305 AEAD algorithm. + * + * Module: library/chachapoly.c + * + * This module requires: MBEDTLS_CHACHA20_C, MBEDTLS_POLY1305_C + */ +#define MBEDTLS_CHACHAPOLY_C + +/** + * \def MBEDTLS_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: library/ssl_tls.c + * + * Uncomment to enable generic cipher wrappers. + */ +#define MBEDTLS_CIPHER_C + +/** + * \def MBEDTLS_CMAC_C + * + * Enable the CMAC (Cipher-based Message Authentication Code) mode for block + * ciphers. + * + * Module: library/cmac.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_DES_C + * + */ +//#define MBEDTLS_CMAC_C + +/** + * \def MBEDTLS_CTR_DRBG_C + * + * Enable the CTR_DRBG AES-based random generator. + * The CTR_DRBG generator uses AES-256 by default. + * To use AES-128 instead, enable MBEDTLS_CTR_DRBG_USE_128_BIT_KEY below. + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: MBEDTLS_AES_C + * + * This module provides the CTR_DRBG AES random number generator. + */ +#define MBEDTLS_CTR_DRBG_C + +/** + * \def MBEDTLS_DEBUG_C + * + * Enable the debug functions. + * + * Module: library/debug.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module provides debugging functions. + */ +#define MBEDTLS_DEBUG_C + +/** + * \def MBEDTLS_DES_C + * + * Enable the DES block cipher. + * + * Module: library/des.c + * Caller: library/pem.c + * library/cipher.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * + * PEM_PARSE uses DES/3DES for decrypting encrypted keys. + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers instead. + */ +#define MBEDTLS_DES_C + +/** + * \def MBEDTLS_DHM_C + * + * Enable the Diffie-Hellman-Merkle module. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * DHE-RSA, DHE-PSK + * + * \warning Using DHE constitutes a security risk as it + * is not possible to validate custom DH parameters. + * If possible, it is recommended users should consider + * preferring other methods of key exchange. + * See dhm.h for more details. + * + */ +#define MBEDTLS_DHM_C + +/** + * \def MBEDTLS_ECDH_C + * + * Enable the elliptic curve Diffie-Hellman library. + * + * Module: library/ecdh.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK + * + * Requires: MBEDTLS_ECP_C + */ +#define MBEDTLS_ECDH_C + +/** + * \def MBEDTLS_ECDSA_C + * + * Enable the elliptic curve DSA library. + * + * Module: library/ecdsa.c + * Caller: + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_ASN1_WRITE_C, MBEDTLS_ASN1_PARSE_C + */ +#define MBEDTLS_ECDSA_C + +/** + * \def MBEDTLS_ECJPAKE_C + * + * Enable the elliptic curve J-PAKE library. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Module: library/ecjpake.c + * Caller: + * + * This module is used by the following key exchanges: + * ECJPAKE + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_MD_C + */ +//#define MBEDTLS_ECJPAKE_C + +/** + * \def MBEDTLS_ECP_C + * + * Enable the elliptic curve over GF(p) library. + * + * Module: library/ecp.c + * Caller: library/ecdh.c + * library/ecdsa.c + * library/ecjpake.c + * + * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED + */ +#define MBEDTLS_ECP_C + +/** + * \def MBEDTLS_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C + * + * This module provides a generic entropy pool + */ +#define MBEDTLS_ENTROPY_C + +/** + * \def MBEDTLS_ERROR_C + * + * Enable error code to error string conversion. + * + * Module: library/error.c + * Caller: + * + * This module enables mbedtls_strerror(). + */ +#define MBEDTLS_ERROR_C + +/** + * \def MBEDTLS_GCM_C + * + * Enable the Galois/Counter Mode (GCM) for AES. + * + * Module: library/gcm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other + * requisites are enabled as well. + */ +#define MBEDTLS_GCM_C + +/** + * \def MBEDTLS_HAVEGE_C + * + * Enable the HAVEGE random generator. + * + * Warning: the HAVEGE random generator is not suitable for virtualized + * environments + * + * Warning: the HAVEGE random generator is dependent on timing and specific + * processor traits. It is therefore not advised to use HAVEGE as + * your applications primary random generator or primary entropy pool + * input. As a secondary input to your entropy pool, it IS able add + * the (limited) extra entropy it provides. + * + * Module: library/havege.c + * Caller: + * + * Requires: MBEDTLS_TIMING_C + * + * Uncomment to enable the HAVEGE random generator. + */ +//#define MBEDTLS_HAVEGE_C + +/** + * \def MBEDTLS_HKDF_C + * + * Enable the HKDF algorithm (RFC 5869). + * + * Module: library/hkdf.c + * Caller: + * + * Requires: MBEDTLS_MD_C + * + * This module adds support for the Hashed Message Authentication Code + * (HMAC)-based key derivation function (HKDF). + */ +#define MBEDTLS_HKDF_C + +/** + * \def MBEDTLS_HMAC_DRBG_C + * + * Enable the HMAC_DRBG random generator. + * + * Module: library/hmac_drbg.c + * Caller: + * + * Requires: MBEDTLS_MD_C + * + * Uncomment to enable the HMAC_DRBG random number geerator. + */ +#define MBEDTLS_HMAC_DRBG_C + +/** + * \def MBEDTLS_NIST_KW_C + * + * Enable the Key Wrapping mode for 128-bit block ciphers, + * as defined in NIST SP 800-38F. Only KW and KWP modes + * are supported. At the moment, only AES is approved by NIST. + * + * Module: library/nist_kw.c + * + * Requires: MBEDTLS_AES_C and MBEDTLS_CIPHER_C + */ +//#define MBEDTLS_NIST_KW_C + +/** + * \def MBEDTLS_MD_C + * + * Enable the generic message digest layer. + * + * Module: library/md.c + * Caller: + * + * Uncomment to enable generic message digest wrappers. + */ +#define MBEDTLS_MD_C + +/** + * \def MBEDTLS_MD2_C + * + * Enable the MD2 hash algorithm. + * + * Module: library/md2.c + * Caller: + * + * Uncomment to enable support for (rare) MD2-signed X.509 certs. + * + * \warning MD2 is considered a weak message digest and its use constitutes a + * security risk. If possible, we recommend avoiding dependencies on + * it, and considering stronger message digests instead. + * + */ +//#define MBEDTLS_MD2_C + +/** + * \def MBEDTLS_MD4_C + * + * Enable the MD4 hash algorithm. + * + * Module: library/md4.c + * Caller: + * + * Uncomment to enable support for (rare) MD4-signed X.509 certs. + * + * \warning MD4 is considered a weak message digest and its use constitutes a + * security risk. If possible, we recommend avoiding dependencies on + * it, and considering stronger message digests instead. + * + */ +//#define MBEDTLS_MD4_C + +/** + * \def MBEDTLS_MD5_C + * + * Enable the MD5 hash algorithm. + * + * Module: library/md5.c + * Caller: library/md.c + * library/pem.c + * library/ssl_tls.c + * + * This module is required for SSL/TLS up to version 1.1, and for TLS 1.2 + * depending on the handshake parameters. Further, it is used for checking + * MD5-signed certificates, and for PBKDF1 when decrypting PEM-encoded + * encrypted keys. + * + * \warning MD5 is considered a weak message digest and its use constitutes a + * security risk. If possible, we recommend avoiding dependencies on + * it, and considering stronger message digests instead. + * + */ +#define MBEDTLS_MD5_C + +/** + * \def MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Enable the buffer allocator implementation that makes use of a (stack) + * based buffer to 'allocate' dynamic memory. (replaces calloc() and free() + * calls) + * + * Module: library/memory_buffer_alloc.c + * + * Requires: MBEDTLS_PLATFORM_C + * MBEDTLS_PLATFORM_MEMORY (to use it within mbed TLS) + * + * Enable this module to enable the buffer memory allocator. + */ +//#define MBEDTLS_MEMORY_BUFFER_ALLOC_C + +/** + * \def MBEDTLS_NET_C + * + * Enable the TCP and UDP over IPv6/IPv4 networking routines. + * + * \note This module only works on POSIX/Unix (including Linux, BSD and OS X) + * and Windows. For other platforms, you'll want to disable it, and write your + * own networking callbacks to be passed to \c mbedtls_ssl_set_bio(). + * + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS + * + * Module: library/net_sockets.c + * + * This module provides networking routines. + */ +#define MBEDTLS_NET_C + +/** + * \def MBEDTLS_OID_C + * + * Enable the OID database. + * + * Module: library/oid.c + * Caller: library/asn1write.c + * library/pkcs5.c + * library/pkparse.c + * library/pkwrite.c + * library/rsa.c + * library/x509.c + * library/x509_create.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * library/x509write_crt.c + * library/x509write_csr.c + * + * This modules translates between OIDs and internal values. + */ +#define MBEDTLS_OID_C + +/** + * \def MBEDTLS_PADLOCK_C + * + * Enable VIA Padlock support on x86. + * + * Module: library/padlock.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the VIA PadLock on x86. + */ +#define MBEDTLS_PADLOCK_C + +/** + * \def MBEDTLS_PEM_PARSE_C + * + * Enable PEM decoding / parsing. + * + * Module: library/pem.c + * Caller: library/dhm.c + * library/pkparse.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for decoding / parsing PEM files. + */ +#define MBEDTLS_PEM_PARSE_C + +/** + * \def MBEDTLS_PEM_WRITE_C + * + * Enable PEM encoding / writing. + * + * Module: library/pem.c + * Caller: library/pkwrite.c + * library/x509write_crt.c + * library/x509write_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for encoding / writing PEM files. + */ +#define MBEDTLS_PEM_WRITE_C + +/** + * \def MBEDTLS_PK_C + * + * Enable the generic public (asymetric) key layer. + * + * Module: library/pk.c + * Caller: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_RSA_C or MBEDTLS_ECP_C + * + * Uncomment to enable generic public key wrappers. + */ +#define MBEDTLS_PK_C + +/** + * \def MBEDTLS_PK_PARSE_C + * + * Enable the generic public (asymetric) key parser. + * + * Module: library/pkparse.c + * Caller: library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key parse functions. + */ +#define MBEDTLS_PK_PARSE_C + +/** + * \def MBEDTLS_PK_WRITE_C + * + * Enable the generic public (asymetric) key writer. + * + * Module: library/pkwrite.c + * Caller: library/x509write.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key write functions. + */ +#define MBEDTLS_PK_WRITE_C + +/** + * \def MBEDTLS_PKCS5_C + * + * Enable PKCS#5 functions. + * + * Module: library/pkcs5.c + * + * Requires: MBEDTLS_MD_C + * + * This module adds support for the PKCS#5 functions. + */ +#define MBEDTLS_PKCS5_C + +/** + * \def MBEDTLS_PKCS11_C + * + * Enable wrapper for PKCS#11 smartcard support. + * + * Module: library/pkcs11.c + * Caller: library/pk.c + * + * Requires: MBEDTLS_PK_C + * + * This module enables SSL/TLS PKCS #11 smartcard support. + * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) + */ +//#define MBEDTLS_PKCS11_C + +/** + * \def MBEDTLS_PKCS12_C + * + * Enable PKCS#12 PBE functions. + * Adds algorithms for parsing PKCS#8 encrypted private keys + * + * Module: library/pkcs12.c + * Caller: library/pkparse.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * Can use: MBEDTLS_ARC4_C + * + * This module enables PKCS#12 functions. + */ +#define MBEDTLS_PKCS12_C + +/** + * \def MBEDTLS_PLATFORM_C + * + * Enable the platform abstraction layer that allows you to re-assign + * functions like calloc(), free(), snprintf(), printf(), fprintf(), exit(). + * + * Enabling MBEDTLS_PLATFORM_C enables to use of MBEDTLS_PLATFORM_XXX_ALT + * or MBEDTLS_PLATFORM_XXX_MACRO directives, allowing the functions mentioned + * above to be specified at runtime or compile time respectively. + * + * \note This abstraction layer must be enabled on Windows (including MSYS2) + * as other module rely on it for a fixed snprintf implementation. + * + * Module: library/platform.c + * Caller: Most other .c files + * + * This module enables abstraction of common (libc) functions. + */ +#define MBEDTLS_PLATFORM_C + +/** + * \def MBEDTLS_POLY1305_C + * + * Enable the Poly1305 MAC algorithm. + * + * Module: library/poly1305.c + * Caller: library/chachapoly.c + */ +#define MBEDTLS_POLY1305_C + +/** + * \def MBEDTLS_PSA_CRYPTO_C + * + * Enable the Platform Security Architecture cryptography API. + * + * \warning The PSA Crypto API is still beta status. While you're welcome to + * experiment using it, incompatible API changes are still possible, and some + * parts may not have reached the same quality as the rest of Mbed TLS yet. + * + * Module: crypto/library/psa_crypto.c + * + * Requires: MBEDTLS_CTR_DRBG_C, MBEDTLS_ENTROPY_C + * + */ +#define MBEDTLS_PSA_CRYPTO_C + +/** + * \def MBEDTLS_PSA_CRYPTO_STORAGE_C + * + * Enable the Platform Security Architecture persistent key storage. + * + * Module: crypto/library/psa_crypto_storage.c + * + * Requires: MBEDTLS_PSA_CRYPTO_C, + * either MBEDTLS_PSA_ITS_FILE_C or a native implementation of + * the PSA ITS interface + */ +//#define MBEDTLS_PSA_CRYPTO_STORAGE_C + +/** + * \def MBEDTLS_PSA_ITS_FILE_C + * + * Enable the emulation of the Platform Security Architecture + * Internal Trusted Storage (PSA ITS) over files. + * + * Module: crypto/library/psa_its_file.c + * + * Requires: MBEDTLS_FS_IO + * + */ +//#define MBEDTLS_PSA_ITS_FILE_C + +/** + * \def MBEDTLS_RIPEMD160_C + * + * Enable the RIPEMD-160 hash algorithm. + * + * Module: library/ripemd160.c + * Caller: library/md.c + * + */ +#define MBEDTLS_RIPEMD160_C + +/** + * \def MBEDTLS_RSA_C + * + * Enable the RSA public-key cryptosystem. + * + * Module: library/rsa.c + * library/rsa_internal.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * This module is used by the following key exchanges: + * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C + */ +#define MBEDTLS_RSA_C + +/** + * \def MBEDTLS_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/sha1.c + * Caller: library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * This module is required for SSL/TLS up to version 1.1, for TLS 1.2 + * depending on the handshake parameters, and for SHA1-signed certificates. + * + * \warning SHA-1 is considered a weak message digest and its use constitutes + * a security risk. If possible, we recommend avoiding dependencies + * on it, and considering stronger message digests instead. + * + */ +#define MBEDTLS_SHA1_C + +/** + * \def MBEDTLS_SHA256_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * + * Module: library/sha256.c + * Caller: library/entropy.c + * library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module adds support for SHA-224 and SHA-256. + * This module is required for the SSL/TLS 1.2 PRF function. + */ +#define MBEDTLS_SHA256_C + +/** + * \def MBEDTLS_SHA512_C + * + * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. + * + * Module: library/sha512.c + * Caller: library/entropy.c + * library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This module adds support for SHA-384 and SHA-512. + */ +#define MBEDTLS_SHA512_C + +/** + * \def MBEDTLS_SSL_CACHE_C + * + * Enable simple SSL cache implementation. + * + * Module: library/ssl_cache.c + * Caller: + * + * Requires: MBEDTLS_SSL_CACHE_C + */ +#define MBEDTLS_SSL_CACHE_C + +/** + * \def MBEDTLS_SSL_COOKIE_C + * + * Enable basic implementation of DTLS cookies for hello verification. + * + * Module: library/ssl_cookie.c + * Caller: + */ +#define MBEDTLS_SSL_COOKIE_C + +/** + * \def MBEDTLS_SSL_TICKET_C + * + * Enable an implementation of TLS server-side callbacks for session tickets. + * + * Module: library/ssl_ticket.c + * Caller: + * + * Requires: MBEDTLS_CIPHER_C + */ +#define MBEDTLS_SSL_TICKET_C + +/** + * \def MBEDTLS_SSL_CLI_C + * + * Enable the SSL/TLS client code. + * + * Module: library/ssl_cli.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS client support. + */ +#define MBEDTLS_SSL_CLI_C + +/** + * \def MBEDTLS_SSL_SRV_C + * + * Enable the SSL/TLS server code. + * + * Module: library/ssl_srv.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS server support. + */ +#define MBEDTLS_SSL_SRV_C + +/** + * \def MBEDTLS_SSL_TLS_C + * + * Enable the generic SSL/TLS code. + * + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * and at least one of the MBEDTLS_SSL_PROTO_XXX defines + * + * This module is required for SSL/TLS. + */ +#define MBEDTLS_SSL_TLS_C + +/** + * \def MBEDTLS_THREADING_C + * + * Enable the threading abstraction layer. + * By default mbed TLS assumes it is used in a non-threaded environment or that + * contexts are not shared between threads. If you do intend to use contexts + * between threads, you will need to enable this layer to prevent race + * conditions. See also our Knowledge Base article about threading: + * https://tls.mbed.org/kb/development/thread-safety-and-multi-threading + * + * Module: library/threading.c + * + * This allows different threading implementations (self-implemented or + * provided). + * + * You will have to enable either MBEDTLS_THREADING_ALT or + * MBEDTLS_THREADING_PTHREAD. + * + * Enable this layer to allow use of mutexes within mbed TLS + */ +//#define MBEDTLS_THREADING_C + +/** + * \def MBEDTLS_TIMING_C + * + * Enable the semi-portable timing interface. + * + * \note The provided implementation only works on POSIX/Unix (including Linux, + * BSD and OS X) and Windows. On other platforms, you can either disable that + * module and provide your own implementations of the callbacks needed by + * \c mbedtls_ssl_set_timer_cb() for DTLS, or leave it enabled and provide + * your own implementation of the whole module by setting + * \c MBEDTLS_TIMING_ALT in the current file. + * + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS + * + * Module: library/timing.c + * Caller: library/havege.c + * + * This module is used by the HAVEGE random number generator. + */ +#define MBEDTLS_TIMING_C + +/** + * \def MBEDTLS_VERSION_C + * + * Enable run-time version information. + * + * Module: library/version.c + * + * This module provides run-time version information. + */ +#define MBEDTLS_VERSION_C + +/** + * \def MBEDTLS_X509_USE_C + * + * Enable X.509 core for using certificates. + * + * Module: library/x509.c + * Caller: library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, + * MBEDTLS_PK_PARSE_C + * + * This module is required for the X.509 parsing modules. + */ +#define MBEDTLS_X509_USE_C + +/** + * \def MBEDTLS_X509_CRT_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/x509_crt.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 certificate parsing. + */ +#define MBEDTLS_X509_CRT_PARSE_C + +/** + * \def MBEDTLS_X509_CRL_PARSE_C + * + * Enable X.509 CRL parsing. + * + * Module: library/x509_crl.c + * Caller: library/x509_crt.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 CRL parsing. + */ +#define MBEDTLS_X509_CRL_PARSE_C + +/** + * \def MBEDTLS_X509_CSR_PARSE_C + * + * Enable X.509 Certificate Signing Request (CSR) parsing. + * + * Module: library/x509_csr.c + * Caller: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is used for reading X.509 certificate request. + */ +#define MBEDTLS_X509_CSR_PARSE_C + +/** + * \def MBEDTLS_X509_CREATE_C + * + * Enable X.509 core for creating certificates. + * + * Module: library/x509_create.c + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, MBEDTLS_PK_WRITE_C + * + * This module is the basis for creating X.509 certificates and CSRs. + */ +#define MBEDTLS_X509_CREATE_C + +/** + * \def MBEDTLS_X509_CRT_WRITE_C + * + * Enable creating X.509 certificates. + * + * Module: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate creation. + */ +#define MBEDTLS_X509_CRT_WRITE_C + +/** + * \def MBEDTLS_X509_CSR_WRITE_C + * + * Enable creating X.509 Certificate Signing Requests (CSR). + * + * Module: library/x509_csr_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate request writing. + */ +#define MBEDTLS_X509_CSR_WRITE_C + +/** + * \def MBEDTLS_XTEA_C + * + * Enable the XTEA block cipher. + * + * Module: library/xtea.c + * Caller: + */ +#define MBEDTLS_XTEA_C + +/* \} name SECTION: mbed TLS modules */ + +/** + * \name SECTION: Module configuration options + * + * This section allows for the setting of module specific sizes and + * configuration options. The default values are already present in the + * relevant header files and should suffice for the regular use cases. + * + * Our advice is to enable options and change their values here + * only if you have a good reason and know the consequences. + * + * Please check the respective header file for documentation on these + * parameters (to prevent duplicate documentation). + * \{ + */ + +/* MPI / BIGNUM options */ +//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +//#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ + +/* CTR_DRBG options */ +//#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +//#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ +//#define MBEDTLS_CTR_DRBG_USE_128_BIT_KEY /**< Use 128-bit key for CTR_DRBG - may reduce security (see ctr_drbg.h) */ + +/* HMAC_DRBG options */ +//#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* ECP options */ +//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +//#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ +//#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ + +/* Entropy options */ +//#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +//#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ +//#define MBEDTLS_ENTROPY_MIN_HARDWARE 32 /**< Default minimum number of bytes required for the hardware entropy source mbedtls_hardware_poll() before entropy is released */ + +/* Memory buffer allocator options */ +//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ + +/* Platform options */ +//#define MBEDTLS_PLATFORM_STD_MEM_HDR /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ +//#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ +/* Note: your snprintf must correctly zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS 0 /**< Default exit value to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE 1 /**< Default exit value to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile" /**< Seed file to read/write with default implementation */ + +/* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */ +/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */ +//#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_TIME_MACRO time /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_TIME_TYPE_MACRO time_t /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_PRINTF_MACRO printf /**< Default printf macro to use, can be undefined */ +/* Note: your snprintf must correctly zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_VSNPRINTF_MACRO vsnprintf /**< Default vsnprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ + +/** + * \brief This macro is invoked by the library when an invalid parameter + * is detected that is only checked with MBEDTLS_CHECK_PARAMS + * (see the documentation of that option for context). + * + * When you leave this undefined here, a default definition is + * provided that invokes the function mbedtls_param_failed(), + * which is declared in platform_util.h for the benefit of the + * library, but that you need to define in your application. + * + * When you define this here, this replaces the default + * definition in platform_util.h (which no longer declares the + * function mbedtls_param_failed()) and it is your responsibility + * to make sure this macro expands to something suitable (in + * particular, that all the necessary declarations are visible + * from within the library - you can ensure that by providing + * them in this file next to the macro definition). + * + * Note that you may define this macro to expand to nothing, in + * which case you don't have to worry about declarations or + * definitions. However, you will then be notified about invalid + * parameters only in non-void functions, and void function will + * just silently return early on invalid parameters, which + * partially negates the benefits of enabling + * #MBEDTLS_CHECK_PARAMS in the first place, so is discouraged. + * + * \param cond The expression that should evaluate to true, but doesn't. + */ +//#define MBEDTLS_PARAM_FAILED( cond ) assert( cond ) + +/* SSL Cache options */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ + +/* SSL options */ + +/** \def MBEDTLS_SSL_MAX_CONTENT_LEN + * + * Maximum length (in bytes) of incoming and outgoing plaintext fragments. + * + * This determines the size of both the incoming and outgoing TLS I/O buffers + * in such a way that both are capable of holding the specified amount of + * plaintext data, regardless of the protection mechanism used. + * + * To configure incoming and outgoing I/O buffers separately, use + * #MBEDTLS_SSL_IN_CONTENT_LEN and #MBEDTLS_SSL_OUT_CONTENT_LEN, + * which overwrite the value set by this option. + * + * \note When using a value less than the default of 16KB on the client, it is + * recommended to use the Maximum Fragment Length (MFL) extension to + * inform the server about this limitation. On the server, there + * is no supported, standardized way of informing the client about + * restriction on the maximum size of incoming messages, and unless + * the limitation has been communicated by other means, it is recommended + * to only change the outgoing buffer size #MBEDTLS_SSL_OUT_CONTENT_LEN + * while keeping the default value of 16KB for the incoming buffer. + * + * Uncomment to set the maximum plaintext size of both + * incoming and outgoing I/O buffers. + */ +//#define MBEDTLS_SSL_MAX_CONTENT_LEN 16384 + +/** \def MBEDTLS_SSL_IN_CONTENT_LEN + * + * Maximum length (in bytes) of incoming plaintext fragments. + * + * This determines the size of the incoming TLS I/O buffer in such a way + * that it is capable of holding the specified amount of plaintext data, + * regardless of the protection mechanism used. + * + * If this option is undefined, it inherits its value from + * #MBEDTLS_SSL_MAX_CONTENT_LEN. + * + * \note When using a value less than the default of 16KB on the client, it is + * recommended to use the Maximum Fragment Length (MFL) extension to + * inform the server about this limitation. On the server, there + * is no supported, standardized way of informing the client about + * restriction on the maximum size of incoming messages, and unless + * the limitation has been communicated by other means, it is recommended + * to only change the outgoing buffer size #MBEDTLS_SSL_OUT_CONTENT_LEN + * while keeping the default value of 16KB for the incoming buffer. + * + * Uncomment to set the maximum plaintext size of the incoming I/O buffer + * independently of the outgoing I/O buffer. + */ +//#define MBEDTLS_SSL_IN_CONTENT_LEN 16384 + +/** \def MBEDTLS_SSL_CID_IN_LEN_MAX + * + * The maximum length of CIDs used for incoming DTLS messages. + * + */ +//#define MBEDTLS_SSL_CID_IN_LEN_MAX 32 + +/** \def MBEDTLS_SSL_CID_OUT_LEN_MAX + * + * The maximum length of CIDs used for outgoing DTLS messages. + * + */ +//#define MBEDTLS_SSL_CID_OUT_LEN_MAX 32 + +/** \def MBEDTLS_SSL_CID_PADDING_GRANULARITY + * + * This option controls the use of record plaintext padding + * when using the Connection ID extension in DTLS 1.2. + * + * The padding will always be chosen so that the length of the + * padded plaintext is a multiple of the value of this option. + * + * Note: A value of \c 1 means that no padding will be used + * for outgoing records. + * + * Note: On systems lacking division instructions, + * a power of two should be preferred. + * + */ +//#define MBEDTLS_SSL_CID_PADDING_GRANULARITY 16 + +/** \def MBEDTLS_SSL_OUT_CONTENT_LEN + * + * Maximum length (in bytes) of outgoing plaintext fragments. + * + * This determines the size of the outgoing TLS I/O buffer in such a way + * that it is capable of holding the specified amount of plaintext data, + * regardless of the protection mechanism used. + * + * If this option undefined, it inherits its value from + * #MBEDTLS_SSL_MAX_CONTENT_LEN. + * + * It is possible to save RAM by setting a smaller outward buffer, while keeping + * the default inward 16384 byte buffer to conform to the TLS specification. + * + * The minimum required outward buffer size is determined by the handshake + * protocol's usage. Handshaking will fail if the outward buffer is too small. + * The specific size requirement depends on the configured ciphers and any + * certificate data which is sent during the handshake. + * + * Uncomment to set the maximum plaintext size of the outgoing I/O buffer + * independently of the incoming I/O buffer. + */ +//#define MBEDTLS_SSL_OUT_CONTENT_LEN 16384 + +/** \def MBEDTLS_SSL_DTLS_MAX_BUFFERING + * + * Maximum number of heap-allocated bytes for the purpose of + * DTLS handshake message reassembly and future message buffering. + * + * This should be at least 9/8 * MBEDTLSSL_IN_CONTENT_LEN + * to account for a reassembled handshake message of maximum size, + * together with its reassembly bitmap. + * + * A value of 2 * MBEDTLS_SSL_IN_CONTENT_LEN (32768 by default) + * should be sufficient for all practical situations as it allows + * to reassembly a large handshake message (such as a certificate) + * while buffering multiple smaller handshake messages. + * + */ +//#define MBEDTLS_SSL_DTLS_MAX_BUFFERING 32768 + +//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ +//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ + +/** + * Complete list of ciphersuites to use, in order of preference. + * + * \warning No dependency checking is done on that field! This option can only + * be used to restrict the set of available ciphersuites. It is your + * responsibility to make sure the needed modules are active. + * + * Use this to save a few hundred bytes of ROM (default ordering of all + * available ciphersuites) and a few to a few hundred bytes of RAM. + * + * The value below is only an example, not the default. + */ +//#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + +/* X509 options */ +//#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 /**< Maximum number of intermediate CAs in a verification chain. */ +//#define MBEDTLS_X509_MAX_FILE_PATH_LEN 512 /**< Maximum length of a path/filename string in bytes including the null terminator character ('\0'). */ + +/** + * Allow SHA-1 in the default TLS configuration for certificate signing. + * Without this build-time option, SHA-1 support must be activated explicitly + * through mbedtls_ssl_conf_cert_profile. Turning on this option is not + * recommended because of it is possible to generate SHA-1 collisions, however + * this may be safe for legacy infrastructure where additional controls apply. + * + * \warning SHA-1 is considered a weak message digest and its use constitutes + * a security risk. If possible, we recommend avoiding dependencies + * on it, and considering stronger message digests instead. + * + */ +// #define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES + +/** + * Allow SHA-1 in the default TLS configuration for TLS 1.2 handshake + * signature and ciphersuite selection. Without this build-time option, SHA-1 + * support must be activated explicitly through mbedtls_ssl_conf_sig_hashes. + * The use of SHA-1 in TLS <= 1.1 and in HMAC-SHA-1 is always allowed by + * default. At the time of writing, there is no practical attack on the use + * of SHA-1 in handshake signatures, hence this option is turned on by default + * to preserve compatibility with existing peers, but the general + * warning applies nonetheless: + * + * \warning SHA-1 is considered a weak message digest and its use constitutes + * a security risk. If possible, we recommend avoiding dependencies + * on it, and considering stronger message digests instead. + * + */ +#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE + +/** + * Uncomment the macro to let mbed TLS use your alternate implementation of + * mbedtls_platform_zeroize(). This replaces the default implementation in + * platform_util.c. + * + * mbedtls_platform_zeroize() is a widely used function across the library to + * zero a block of memory. The implementation is expected to be secure in the + * sense that it has been written to prevent the compiler from removing calls + * to mbedtls_platform_zeroize() as part of redundant code elimination + * optimizations. However, it is difficult to guarantee that calls to + * mbedtls_platform_zeroize() will not be optimized by the compiler as older + * versions of the C language standards do not provide a secure implementation + * of memset(). Therefore, MBEDTLS_PLATFORM_ZEROIZE_ALT enables users to + * configure their own implementation of mbedtls_platform_zeroize(), for + * example by using directives specific to their compiler, features from newer + * C standards (e.g using memset_s() in C11) or calling a secure memset() from + * their system (e.g explicit_bzero() in BSD). + */ +//#define MBEDTLS_PLATFORM_ZEROIZE_ALT + +/** + * Uncomment the macro to let Mbed TLS use your alternate implementation of + * mbedtls_platform_gmtime_r(). This replaces the default implementation in + * platform_util.c. + * + * gmtime() is not a thread-safe function as defined in the C standard. The + * library will try to use safer implementations of this function, such as + * gmtime_r() when available. However, if Mbed TLS cannot identify the target + * system, the implementation of mbedtls_platform_gmtime_r() will default to + * using the standard gmtime(). In this case, calls from the library to + * gmtime() will be guarded by the global mutex mbedtls_threading_gmtime_mutex + * if MBEDTLS_THREADING_C is enabled. We recommend that calls from outside the + * library are also guarded with this mutex to avoid race conditions. However, + * if the macro MBEDTLS_PLATFORM_GMTIME_R_ALT is defined, Mbed TLS will + * unconditionally use the implementation for mbedtls_platform_gmtime_r() + * supplied at compile time. + */ +//#define MBEDTLS_PLATFORM_GMTIME_R_ALT + +/* \} name SECTION: Customisation configuration options */ + +/* Target and application specific configurations + * + * Allow user to override any previous default. + * + */ +#if defined(MBEDTLS_USER_CONFIG_FILE) +#include MBEDTLS_USER_CONFIG_FILE +#endif + +#include "check_config.h" + +#endif /* MBEDTLS_CONFIG_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ctr_drbg.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ctr_drbg.h new file mode 100644 index 000000000..f0249aea4 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ctr_drbg.h @@ -0,0 +1,380 @@ +/** + * \file ctr_drbg.h + * + * \brief This file contains CTR_DRBG definitions and functions. + * + * CTR_DRBG is a standardized way of building a PRNG from a block-cipher + * in counter mode operation, as defined in NIST SP 800-90A: + * Recommendation for Random Number Generation Using Deterministic Random + * Bit Generators. + * + * The Mbed TLS implementation of CTR_DRBG uses AES-256 (default) or AES-128 + * as the underlying block cipher. + * + * \warning Using 128-bit keys for CTR_DRBG limits the security of generated + * keys and operations that use random values generated to 128-bit security. + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CTR_DRBG_H +#define MBEDTLS_CTR_DRBG_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "aes.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +#define MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED -0x0034 /**< The entropy source failed. */ +#define MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG -0x0036 /**< The requested random buffer length is too big. */ +#define MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG -0x0038 /**< The input (entropy + additional data) is too large. */ +#define MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR -0x003A /**< Read or write error in file. */ + +#define MBEDTLS_CTR_DRBG_BLOCKSIZE 16 /**< The block size used by the cipher. */ + +#if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY) +#define MBEDTLS_CTR_DRBG_KEYSIZE 16 /**< The key size used by the cipher (compile-time choice: 128 bits). */ +#else +#define MBEDTLS_CTR_DRBG_KEYSIZE 32 /**< The key size used by the cipher (compile-time choice: 256 bits). */ +#endif + +#define MBEDTLS_CTR_DRBG_KEYBITS ( MBEDTLS_CTR_DRBG_KEYSIZE * 8 ) /**< The key size for the DRBG operation, in bits. */ +#define MBEDTLS_CTR_DRBG_SEEDLEN ( MBEDTLS_CTR_DRBG_KEYSIZE + MBEDTLS_CTR_DRBG_BLOCKSIZE ) /**< The seed length, calculated as (counter + AES key). */ + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them using the compiler command + * line. + * \{ + */ + +#if !defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) +#if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_ENTROPY_FORCE_SHA256) +#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 +/**< The amount of entropy used per seed by default: + *
  • 48 with SHA-512.
  • + *
  • 32 with SHA-256.
+ */ +#else +#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 32 +/**< Amount of entropy used per seed by default: + *
  • 48 with SHA-512.
  • + *
  • 32 with SHA-256.
+ */ +#endif +#endif + +#if !defined(MBEDTLS_CTR_DRBG_RESEED_INTERVAL) +#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 +/**< The interval before reseed is performed by default. */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_INPUT) +#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 +/**< The maximum number of additional input Bytes. */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_REQUEST) +#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 +/**< The maximum number of requested Bytes per call. */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) +#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 +/**< The maximum size of seed or reseed buffer. */ +#endif + +/* \} name SECTION: Module settings */ + +#define MBEDTLS_CTR_DRBG_PR_OFF 0 +/**< Prediction resistance is disabled. */ +#define MBEDTLS_CTR_DRBG_PR_ON 1 +/**< Prediction resistance is enabled. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief The CTR_DRBG context structure. + */ +typedef struct mbedtls_ctr_drbg_context +{ + unsigned char counter[16]; /*!< The counter (V). */ + int reseed_counter; /*!< The reseed counter. */ + int prediction_resistance; /*!< This determines whether prediction + resistance is enabled, that is + whether to systematically reseed before + each random generation. */ + size_t entropy_len; /*!< The amount of entropy grabbed on each + seed or reseed operation. */ + int reseed_interval; /*!< The reseed interval. */ + + mbedtls_aes_context aes_ctx; /*!< The AES context. */ + + /* + * Callbacks (Entropy) + */ + int (*f_entropy)(void *, unsigned char *, size_t); + /*!< The entropy callback function. */ + + void *p_entropy; /*!< The context for the entropy function. */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} +mbedtls_ctr_drbg_context; + +/** + * \brief This function initializes the CTR_DRBG context, + * and prepares it for mbedtls_ctr_drbg_seed() + * or mbedtls_ctr_drbg_free(). + * + * \param ctx The CTR_DRBG context to initialize. + */ +void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx ); + +/** + * \brief This function seeds and sets up the CTR_DRBG + * entropy source for future reseeds. + * + * \note Personalization data can be provided in addition to the more generic + * entropy source, to make this instantiation as unique as possible. + * + * \param ctx The CTR_DRBG context to seed. + * \param f_entropy The entropy callback, taking as arguments the + * \p p_entropy context, the buffer to fill, and the + length of the buffer. + * \param p_entropy The entropy context. + * \param custom Personalization data, that is device-specific + identifiers. Can be NULL. + * \param len The length of the personalization data. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on failure. + */ +int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ); + +/** + * \brief This function clears CTR_CRBG context data. + * + * \param ctx The CTR_DRBG context to clear. + */ +void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx ); + +/** + * \brief This function turns prediction resistance on or off. + * The default value is off. + * + * \note If enabled, entropy is gathered at the beginning of + * every call to mbedtls_ctr_drbg_random_with_add(). + * Only use this if your entropy source has sufficient + * throughput. + * + * \param ctx The CTR_DRBG context. + * \param resistance #MBEDTLS_CTR_DRBG_PR_ON or #MBEDTLS_CTR_DRBG_PR_OFF. + */ +void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, + int resistance ); + +/** + * \brief This function sets the amount of entropy grabbed on each + * seed or reseed. The default value is + * #MBEDTLS_CTR_DRBG_ENTROPY_LEN. + * + * \param ctx The CTR_DRBG context. + * \param len The amount of entropy to grab. + */ +void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx, + size_t len ); + +/** + * \brief This function sets the reseed interval. + * The default value is #MBEDTLS_CTR_DRBG_RESEED_INTERVAL. + * + * \param ctx The CTR_DRBG context. + * \param interval The reseed interval. + */ +void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx, + int interval ); + +/** + * \brief This function reseeds the CTR_DRBG context, that is + * extracts data from the entropy source. + * + * \param ctx The CTR_DRBG context. + * \param additional Additional data to add to the state. Can be NULL. + * \param len The length of the additional data. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on failure. + */ +int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t len ); + +/** + * \brief This function updates the state of the CTR_DRBG context. + * + * \param ctx The CTR_DRBG context. + * \param additional The data to update the state with. + * \param add_len Length of \p additional in bytes. This must be at + * most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG if + * \p add_len is more than + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT. + * \return An error from the underlying AES cipher on failure. + */ +int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ); + +/** + * \brief This function updates a CTR_DRBG instance with additional + * data and uses it to generate random data. + * + * \note The function automatically reseeds if the reseed counter is exceeded. + * + * \param p_rng The CTR_DRBG context. This must be a pointer to a + * #mbedtls_ctr_drbg_context structure. + * \param output The buffer to fill. + * \param output_len The length of the buffer. + * \param additional Additional data to update. Can be NULL. + * \param add_len The length of the additional data. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * #MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG on failure. + */ +int mbedtls_ctr_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len ); + +/** + * \brief This function uses CTR_DRBG to generate random data. + * + * \note The function automatically reseeds if the reseed counter is exceeded. + * + * \param p_rng The CTR_DRBG context. This must be a pointer to a + * #mbedtls_ctr_drbg_context structure. + * \param output The buffer to fill. + * \param output_len The length of the buffer. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * #MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG on failure. + */ +int mbedtls_ctr_drbg_random( void *p_rng, + unsigned char *output, size_t output_len ); + + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function updates the state of the CTR_DRBG context. + * + * \deprecated Superseded by mbedtls_ctr_drbg_update_ret() + * in 2.16.0. + * + * \note If \p add_len is greater than + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT, only the first + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT Bytes are used. + * The remaining Bytes are silently discarded. + * + * \param ctx The CTR_DRBG context. + * \param additional The data to update the state with. + * \param add_len Length of \p additional data. + */ +MBEDTLS_DEPRECATED void mbedtls_ctr_drbg_update( + mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ); +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +#if defined(MBEDTLS_FS_IO) +/** + * \brief This function writes a seed file. + * + * \param ctx The CTR_DRBG context. + * \param path The name of the file. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on + * failure. + */ +int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ); + +/** + * \brief This function reads and updates a seed file. The seed + * is added to this instance. + * + * \param ctx The CTR_DRBG context. + * \param path The name of the file. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG on failure. + */ +int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief The CTR_DRBG checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_ctr_drbg_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +/* Internal functions (do not call directly) */ +int mbedtls_ctr_drbg_seed_entropy_len( mbedtls_ctr_drbg_context *, + int (*)(void *, unsigned char *, size_t), void *, + const unsigned char *, size_t, size_t ); + +#ifdef __cplusplus +} +#endif + +#endif /* ctr_drbg.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/debug.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/debug.h new file mode 100644 index 000000000..473128452 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/debug.h @@ -0,0 +1,264 @@ +/** + * \file debug.h + * + * \brief Functions for controlling and providing debug output from the library. + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_DEBUG_H +#define MBEDTLS_DEBUG_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "ssl.h" + +#if defined(MBEDTLS_ECP_C) +#include "ecp.h" +#endif + +#if defined(MBEDTLS_DEBUG_C) + +#define MBEDTLS_DEBUG_STRIP_PARENS( ... ) __VA_ARGS__ + +#define MBEDTLS_SSL_DEBUG_MSG( level, args ) \ + mbedtls_debug_print_msg( ssl, level, __FILE__, __LINE__, \ + MBEDTLS_DEBUG_STRIP_PARENS args ) + +#define MBEDTLS_SSL_DEBUG_RET( level, text, ret ) \ + mbedtls_debug_print_ret( ssl, level, __FILE__, __LINE__, text, ret ) + +#define MBEDTLS_SSL_DEBUG_BUF( level, text, buf, len ) \ + mbedtls_debug_print_buf( ssl, level, __FILE__, __LINE__, text, buf, len ) + +#if defined(MBEDTLS_BIGNUM_C) +#define MBEDTLS_SSL_DEBUG_MPI( level, text, X ) \ + mbedtls_debug_print_mpi( ssl, level, __FILE__, __LINE__, text, X ) +#endif + +#if defined(MBEDTLS_ECP_C) +#define MBEDTLS_SSL_DEBUG_ECP( level, text, X ) \ + mbedtls_debug_print_ecp( ssl, level, __FILE__, __LINE__, text, X ) +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#define MBEDTLS_SSL_DEBUG_CRT( level, text, crt ) \ + mbedtls_debug_print_crt( ssl, level, __FILE__, __LINE__, text, crt ) +#endif + +#if defined(MBEDTLS_ECDH_C) +#define MBEDTLS_SSL_DEBUG_ECDH( level, ecdh, attr ) \ + mbedtls_debug_printf_ecdh( ssl, level, __FILE__, __LINE__, ecdh, attr ) +#endif + +#else /* MBEDTLS_DEBUG_C */ + +#define MBEDTLS_SSL_DEBUG_MSG( level, args ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_RET( level, text, ret ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_BUF( level, text, buf, len ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_MPI( level, text, X ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_ECP( level, text, X ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_CRT( level, text, crt ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_ECDH( level, ecdh, attr ) do { } while( 0 ) + +#endif /* MBEDTLS_DEBUG_C */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Set the threshold error level to handle globally all debug output. + * Debug messages that have a level over the threshold value are + * discarded. + * (Default value: 0 = No debug ) + * + * \param threshold theshold level of messages to filter on. Messages at a + * higher level will be discarded. + * - Debug levels + * - 0 No debug + * - 1 Error + * - 2 State change + * - 3 Informational + * - 4 Verbose + */ +void mbedtls_debug_set_threshold( int threshold ); + +/** + * \brief Print a message to the debug output. This function is always used + * through the MBEDTLS_SSL_DEBUG_MSG() macro, which supplies the ssl + * context, file and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the message has occurred in + * \param line line number the message has occurred at + * \param format format specifier, in printf format + * \param ... variables used by the format specifier + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_print_msg( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *format, ... ); + +/** + * \brief Print the return value of a function to the debug output. This + * function is always used through the MBEDTLS_SSL_DEBUG_RET() macro, + * which supplies the ssl context, file and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the error has occurred in + * \param line line number the error has occurred in + * \param text the name of the function that returned the error + * \param ret the return code value + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_print_ret( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, int ret ); + +/** + * \brief Output a buffer of size len bytes to the debug output. This function + * is always used through the MBEDTLS_SSL_DEBUG_BUF() macro, + * which supplies the ssl context, file and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the error has occurred in + * \param line line number the error has occurred in + * \param text a name or label for the buffer being dumped. Normally the + * variable or buffer name + * \param buf the buffer to be outputted + * \param len length of the buffer + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_print_buf( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, const char *text, + const unsigned char *buf, size_t len ); + +#if defined(MBEDTLS_BIGNUM_C) +/** + * \brief Print a MPI variable to the debug output. This function is always + * used through the MBEDTLS_SSL_DEBUG_MPI() macro, which supplies the + * ssl context, file and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the error has occurred in + * \param line line number the error has occurred in + * \param text a name or label for the MPI being output. Normally the + * variable name + * \param X the MPI variable + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_print_mpi( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_mpi *X ); +#endif + +#if defined(MBEDTLS_ECP_C) +/** + * \brief Print an ECP point to the debug output. This function is always + * used through the MBEDTLS_SSL_DEBUG_ECP() macro, which supplies the + * ssl context, file and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the error has occurred in + * \param line line number the error has occurred in + * \param text a name or label for the ECP point being output. Normally the + * variable name + * \param X the ECP point + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_print_ecp( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_ecp_point *X ); +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Print a X.509 certificate structure to the debug output. This + * function is always used through the MBEDTLS_SSL_DEBUG_CRT() macro, + * which supplies the ssl context, file and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the error has occurred in + * \param line line number the error has occurred in + * \param text a name or label for the certificate being output + * \param crt X.509 certificate structure + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_x509_crt *crt ); +#endif + +#if defined(MBEDTLS_ECDH_C) +typedef enum +{ + MBEDTLS_DEBUG_ECDH_Q, + MBEDTLS_DEBUG_ECDH_QP, + MBEDTLS_DEBUG_ECDH_Z, +} mbedtls_debug_ecdh_attr; + +/** + * \brief Print a field of the ECDH structure in the SSL context to the debug + * output. This function is always used through the + * MBEDTLS_SSL_DEBUG_ECDH() macro, which supplies the ssl context, file + * and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the error has occurred in + * \param line line number the error has occurred in + * \param ecdh the ECDH context + * \param attr the identifier of the attribute being output + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_printf_ecdh( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const mbedtls_ecdh_context *ecdh, + mbedtls_debug_ecdh_attr attr ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* debug.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/des.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/des.h new file mode 100644 index 000000000..2c2e88739 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/des.h @@ -0,0 +1,356 @@ +/** + * \file des.h + * + * \brief DES block cipher + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + * + */ +#ifndef MBEDTLS_DES_H +#define MBEDTLS_DES_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_DES_ENCRYPT 1 +#define MBEDTLS_DES_DECRYPT 0 + +#define MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH -0x0032 /**< The data input has an invalid length. */ + +/* MBEDTLS_ERR_DES_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_DES_HW_ACCEL_FAILED -0x0033 /**< DES hardware accelerator failed. */ + +#define MBEDTLS_DES_KEY_SIZE 8 + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_DES_ALT) +// Regular implementation +// + +/** + * \brief DES context structure + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +typedef struct mbedtls_des_context +{ + uint32_t sk[32]; /*!< DES subkeys */ +} +mbedtls_des_context; + +/** + * \brief Triple-DES context structure + */ +typedef struct mbedtls_des3_context +{ + uint32_t sk[96]; /*!< 3DES subkeys */ +} +mbedtls_des3_context; + +#else /* MBEDTLS_DES_ALT */ +#include "des_alt.h" +#endif /* MBEDTLS_DES_ALT */ + +/** + * \brief Initialize DES context + * + * \param ctx DES context to be initialized + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +void mbedtls_des_init( mbedtls_des_context *ctx ); + +/** + * \brief Clear DES context + * + * \param ctx DES context to be cleared + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +void mbedtls_des_free( mbedtls_des_context *ctx ); + +/** + * \brief Initialize Triple-DES context + * + * \param ctx DES3 context to be initialized + */ +void mbedtls_des3_init( mbedtls_des3_context *ctx ); + +/** + * \brief Clear Triple-DES context + * + * \param ctx DES3 context to be cleared + */ +void mbedtls_des3_free( mbedtls_des3_context *ctx ); + +/** + * \brief Set key parity on the given key to odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +void mbedtls_des_key_set_parity( unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief Check that key parity on the given key is odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + * + * \return 0 is parity was ok, 1 if parity was not correct. + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +int mbedtls_des_key_check_key_parity( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief Check that key is not a weak or semi-weak DES key + * + * \param key 8-byte secret key + * + * \return 0 if no weak key was found, 1 if a weak key was identified. + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +int mbedtls_des_key_check_weak( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, encryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +int mbedtls_des_setkey_enc( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, decryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +int mbedtls_des_setkey_dec( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief Triple-DES key schedule (112-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set2key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (112-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set2key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (168-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set3key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ); + +/** + * \brief Triple-DES key schedule (168-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set3key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ); + +/** + * \brief DES-ECB block encryption/decryption + * + * \param ctx DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +int mbedtls_des_crypt_ecb( mbedtls_des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief DES-CBC buffer encryption/decryption + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx DES context + * \param mode MBEDTLS_DES_ENCRYPT or MBEDTLS_DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +int mbedtls_des_crypt_cbc( mbedtls_des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/** + * \brief 3DES-ECB block encryption/decryption + * + * \param ctx 3DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + */ +int mbedtls_des3_crypt_ecb( mbedtls_des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief 3DES-CBC buffer encryption/decryption + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx 3DES context + * \param mode MBEDTLS_DES_ENCRYPT or MBEDTLS_DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH + */ +int mbedtls_des3_crypt_cbc( mbedtls_des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/** + * \brief Internal function for key expansion. + * (Only exposed to allow overriding it, + * see MBEDTLS_DES_SETKEY_ALT) + * + * \param SK Round keys + * \param key Base key + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +void mbedtls_des_setkey( uint32_t SK[32], + const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_des_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* des.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/dhm.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/dhm.h new file mode 100644 index 000000000..a0ed4ec96 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/dhm.h @@ -0,0 +1,1096 @@ +/** + * \file dhm.h + * + * \brief This file contains Diffie-Hellman-Merkle (DHM) key exchange + * definitions and functions. + * + * Diffie-Hellman-Merkle (DHM) key exchange is defined in + * RFC-2631: Diffie-Hellman Key Agreement Method and + * Public-Key Cryptography Standards (PKCS) #3: Diffie + * Hellman Key Agreement Standard. + * + * RFC-3526: More Modular Exponential (MODP) Diffie-Hellman groups for + * Internet Key Exchange (IKE) defines a number of standardized + * Diffie-Hellman groups for IKE. + * + * RFC-5114: Additional Diffie-Hellman Groups for Use with IETF + * Standards defines a number of standardized Diffie-Hellman + * groups that can be used. + * + * \warning The security of the DHM key exchange relies on the proper choice + * of prime modulus - optimally, it should be a safe prime. The usage + * of non-safe primes both decreases the difficulty of the underlying + * discrete logarithm problem and can lead to small subgroup attacks + * leaking private exponent bits when invalid public keys are used + * and not detected. This is especially relevant if the same DHM + * parameters are reused for multiple key exchanges as in static DHM, + * while the criticality of small-subgroup attacks is lower for + * ephemeral DHM. + * + * \warning For performance reasons, the code does neither perform primality + * nor safe primality tests, nor the expensive checks for invalid + * subgroups. Moreover, even if these were performed, non-standardized + * primes cannot be trusted because of the possibility of backdoors + * that can't be effectively checked for. + * + * \warning Diffie-Hellman-Merkle is therefore a security risk when not using + * standardized primes generated using a trustworthy ("nothing up + * my sleeve") method, such as the RFC 3526 / 7919 primes. In the TLS + * protocol, DH parameters need to be negotiated, so using the default + * primes systematically is not always an option. If possible, use + * Elliptic Curve Diffie-Hellman (ECDH), which has better performance, + * and for which the TLS protocol mandates the use of standard + * parameters. + * + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_DHM_H +#define MBEDTLS_DHM_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif +#include "bignum.h" + +/* + * DHM Error codes + */ +#define MBEDTLS_ERR_DHM_BAD_INPUT_DATA -0x3080 /**< Bad input parameters. */ +#define MBEDTLS_ERR_DHM_READ_PARAMS_FAILED -0x3100 /**< Reading of the DHM parameters failed. */ +#define MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED -0x3180 /**< Making of the DHM parameters failed. */ +#define MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED -0x3200 /**< Reading of the public values failed. */ +#define MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED -0x3280 /**< Making of the public value failed. */ +#define MBEDTLS_ERR_DHM_CALC_SECRET_FAILED -0x3300 /**< Calculation of the DHM secret failed. */ +#define MBEDTLS_ERR_DHM_INVALID_FORMAT -0x3380 /**< The ASN.1 data is not formatted correctly. */ +#define MBEDTLS_ERR_DHM_ALLOC_FAILED -0x3400 /**< Allocation of memory failed. */ +#define MBEDTLS_ERR_DHM_FILE_IO_ERROR -0x3480 /**< Read or write of file failed. */ + +/* MBEDTLS_ERR_DHM_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_DHM_HW_ACCEL_FAILED -0x3500 /**< DHM hardware accelerator failed. */ + +#define MBEDTLS_ERR_DHM_SET_GROUP_FAILED -0x3580 /**< Setting the modulus and generator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_DHM_ALT) + +/** + * \brief The DHM context structure. + */ +typedef struct mbedtls_dhm_context +{ + size_t len; /*!< The size of \p P in Bytes. */ + mbedtls_mpi P; /*!< The prime modulus. */ + mbedtls_mpi G; /*!< The generator. */ + mbedtls_mpi X; /*!< Our secret value. */ + mbedtls_mpi GX; /*!< Our public key = \c G^X mod \c P. */ + mbedtls_mpi GY; /*!< The public key of the peer = \c G^Y mod \c P. */ + mbedtls_mpi K; /*!< The shared secret = \c G^(XY) mod \c P. */ + mbedtls_mpi RP; /*!< The cached value = \c R^2 mod \c P. */ + mbedtls_mpi Vi; /*!< The blinding value. */ + mbedtls_mpi Vf; /*!< The unblinding value. */ + mbedtls_mpi pX; /*!< The previous \c X. */ +} +mbedtls_dhm_context; + +#else /* MBEDTLS_DHM_ALT */ +#include "dhm_alt.h" +#endif /* MBEDTLS_DHM_ALT */ + +/** + * \brief This function initializes the DHM context. + * + * \param ctx The DHM context to initialize. + */ +void mbedtls_dhm_init( mbedtls_dhm_context *ctx ); + +/** + * \brief This function parses the DHM parameters in a + * TLS ServerKeyExchange handshake message + * (DHM modulus, generator, and public key). + * + * \note In a TLS handshake, this is the how the client + * sets up its DHM context from the server's public + * DHM key material. + * + * \param ctx The DHM context to use. This must be initialized. + * \param p On input, *p must be the start of the input buffer. + * On output, *p is updated to point to the end of the data + * that has been read. On success, this is the first byte + * past the end of the ServerKeyExchange parameters. + * On error, this is the point at which an error has been + * detected, which is usually not useful except to debug + * failures. + * \param end The end of the input buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_DHM_XXX error code on failure. + */ +int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx, + unsigned char **p, + const unsigned char *end ); + +/** + * \brief This function generates a DHM key pair and exports its + * public part together with the DHM parameters in the format + * used in a TLS ServerKeyExchange handshake message. + * + * \note This function assumes that the DHM parameters \c ctx->P + * and \c ctx->G have already been properly set. For that, use + * mbedtls_dhm_set_group() below in conjunction with + * mbedtls_mpi_read_binary() and mbedtls_mpi_read_string(). + * + * \note In a TLS handshake, this is the how the server generates + * and exports its DHM key material. + * + * \param ctx The DHM context to use. This must be initialized + * and have the DHM parameters set. It may or may not + * already have imported the peer's public key. + * \param x_size The private key size in Bytes. + * \param olen The address at which to store the number of Bytes + * written on success. This must not be \c NULL. + * \param output The destination buffer. This must be a writable buffer of + * sufficient size to hold the reduced binary presentation of + * the modulus, the generator and the public key, each wrapped + * with a 2-byte length field. It is the responsibility of the + * caller to ensure that enough space is available. Refer to + * mbedtls_mpi_size() to computing the byte-size of an MPI. + * \param f_rng The RNG function. Must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context parameter. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_DHM_XXX error code on failure. + */ +int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size, + unsigned char *output, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function sets the prime modulus and generator. + * + * \note This function can be used to set \c ctx->P, \c ctx->G + * in preparation for mbedtls_dhm_make_params(). + * + * \param ctx The DHM context to configure. This must be initialized. + * \param P The MPI holding the DHM prime modulus. This must be + * an initialized MPI. + * \param G The MPI holding the DHM generator. This must be an + * initialized MPI. + * + * \return \c 0 if successful. + * \return An \c MBEDTLS_ERR_DHM_XXX error code on failure. + */ +int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx, + const mbedtls_mpi *P, + const mbedtls_mpi *G ); + +/** + * \brief This function imports the raw public value of the peer. + * + * \note In a TLS handshake, this is the how the server imports + * the Client's public DHM key. + * + * \param ctx The DHM context to use. This must be initialized and have + * its DHM parameters set, e.g. via mbedtls_dhm_set_group(). + * It may or may not already have generated its own private key. + * \param input The input buffer containing the \c G^Y value of the peer. + * This must be a readable buffer of size \p ilen Bytes. + * \param ilen The size of the input buffer \p input in Bytes. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_DHM_XXX error code on failure. + */ +int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx, + const unsigned char *input, size_t ilen ); + +/** + * \brief This function creates a DHM key pair and exports + * the raw public key in big-endian format. + * + * \note The destination buffer is always fully written + * so as to contain a big-endian representation of G^X mod P. + * If it is larger than \c ctx->len, it is padded accordingly + * with zero-bytes at the beginning. + * + * \param ctx The DHM context to use. This must be initialized and + * have the DHM parameters set. It may or may not already + * have imported the peer's public key. + * \param x_size The private key size in Bytes. + * \param output The destination buffer. This must be a writable buffer of + * size \p olen Bytes. + * \param olen The length of the destination buffer. This must be at least + * equal to `ctx->len` (the size of \c P). + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c NULL + * if \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_DHM_XXX error code on failure. + */ +int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size, + unsigned char *output, size_t olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function derives and exports the shared secret + * \c (G^Y)^X mod \c P. + * + * \note If \p f_rng is not \c NULL, it is used to blind the input as + * a countermeasure against timing attacks. Blinding is used + * only if our private key \c X is re-used, and not used + * otherwise. We recommend always passing a non-NULL + * \p f_rng argument. + * + * \param ctx The DHM context to use. This must be initialized + * and have its own private key generated and the peer's + * public key imported. + * \param output The buffer to write the generated shared key to. This + * must be a writable buffer of size \p output_size Bytes. + * \param output_size The size of the destination buffer. This must be at + * least the size of \c ctx->len (the size of \c P). + * \param olen On exit, holds the actual number of Bytes written. + * \param f_rng The RNG function, for blinding purposes. This may + * b \c NULL if blinding isn't needed. + * \param p_rng The RNG context. This may be \c NULL if \p f_rng + * doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_DHM_XXX error code on failure. + */ +int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx, + unsigned char *output, size_t output_size, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function frees and clears the components + * of a DHM context. + * + * \param ctx The DHM context to free and clear. This may be \c NULL, + * in which case this function is a no-op. If it is not \c NULL, + * it must point to an initialized DHM context. + */ +void mbedtls_dhm_free( mbedtls_dhm_context *ctx ); + +#if defined(MBEDTLS_ASN1_PARSE_C) +/** \ingroup x509_module */ +/** + * \brief This function parses DHM parameters in PEM or DER format. + * + * \param dhm The DHM context to import the DHM parameters into. + * This must be initialized. + * \param dhmin The input buffer. This must be a readable buffer of + * length \p dhminlen Bytes. + * \param dhminlen The size of the input buffer \p dhmin, including the + * terminating \c NULL Byte for PEM data. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_DHM_XXX or \c MBEDTLS_ERR_PEM_XXX error + * code on failure. + */ +int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin, + size_t dhminlen ); + +#if defined(MBEDTLS_FS_IO) +/** \ingroup x509_module */ +/** + * \brief This function loads and parses DHM parameters from a file. + * + * \param dhm The DHM context to load the parameters to. + * This must be initialized. + * \param path The filename to read the DHM parameters from. + * This must not be \c NULL. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_DHM_XXX or \c MBEDTLS_ERR_PEM_XXX + * error code on failure. + */ +int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path ); +#endif /* MBEDTLS_FS_IO */ +#endif /* MBEDTLS_ASN1_PARSE_C */ + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief The DMH checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_dhm_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ +#ifdef __cplusplus +} +#endif + +/** + * RFC 3526, RFC 5114 and RFC 7919 standardize a number of + * Diffie-Hellman groups, some of which are included here + * for use within the SSL/TLS module and the user's convenience + * when configuring the Diffie-Hellman parameters by hand + * through \c mbedtls_ssl_conf_dh_param. + * + * The following lists the source of the above groups in the standards: + * - RFC 5114 section 2.2: 2048-bit MODP Group with 224-bit Prime Order Subgroup + * - RFC 3526 section 3: 2048-bit MODP Group + * - RFC 3526 section 4: 3072-bit MODP Group + * - RFC 3526 section 5: 4096-bit MODP Group + * - RFC 7919 section A.1: ffdhe2048 + * - RFC 7919 section A.2: ffdhe3072 + * - RFC 7919 section A.3: ffdhe4096 + * - RFC 7919 section A.4: ffdhe6144 + * - RFC 7919 section A.5: ffdhe8192 + * + * The constants with suffix "_p" denote the chosen prime moduli, while + * the constants with suffix "_g" denote the chosen generator + * of the associated prime field. + * + * The constants further suffixed with "_bin" are provided in binary format, + * while all other constants represent null-terminated strings holding the + * hexadecimal presentation of the respective numbers. + * + * The primes from RFC 3526 and RFC 7919 have been generating by the following + * trust-worthy procedure: + * - Fix N in { 2048, 3072, 4096, 6144, 8192 } and consider the N-bit number + * the first and last 64 bits are all 1, and the remaining N - 128 bits of + * which are 0x7ff...ff. + * - Add the smallest multiple of the first N - 129 bits of the binary expansion + * of pi (for RFC 5236) or e (for RFC 7919) to this intermediate bit-string + * such that the resulting integer is a safe-prime. + * - The result is the respective RFC 3526 / 7919 prime, and the corresponding + * generator is always chosen to be 2 (which is a square for these prime, + * hence the corresponding subgroup has order (p-1)/2 and avoids leaking a + * bit in the private exponent). + * + */ + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) + +/** + * \warning The origin of the primes in RFC 5114 is not documented and + * their use therefore constitutes a security risk! + * + * \deprecated The hex-encoded primes from RFC 5114 are deprecated and are + * likely to be removed in a future version of the library without + * replacement. + */ + +/** + * The hexadecimal presentation of the prime underlying the + * 2048-bit MODP Group with 224-bit Prime Order Subgroup, as defined + * in RFC-5114: Additional Diffie-Hellman Groups for Use with + * IETF Standards. + */ +#define MBEDTLS_DHM_RFC5114_MODP_2048_P \ + MBEDTLS_DEPRECATED_STRING_CONSTANT( \ + "AD107E1E9123A9D0D660FAA79559C51FA20D64E5683B9FD1" \ + "B54B1597B61D0A75E6FA141DF95A56DBAF9A3C407BA1DF15" \ + "EB3D688A309C180E1DE6B85A1274A0A66D3F8152AD6AC212" \ + "9037C9EDEFDA4DF8D91E8FEF55B7394B7AD5B7D0B6C12207" \ + "C9F98D11ED34DBF6C6BA0B2C8BBC27BE6A00E0A0B9C49708" \ + "B3BF8A317091883681286130BC8985DB1602E714415D9330" \ + "278273C7DE31EFDC7310F7121FD5A07415987D9ADC0A486D" \ + "CDF93ACC44328387315D75E198C641A480CD86A1B9E587E8" \ + "BE60E69CC928B2B9C52172E413042E9B23F10B0E16E79763" \ + "C9B53DCF4BA80A29E3FB73C16B8E75B97EF363E2FFA31F71" \ + "CF9DE5384E71B81C0AC4DFFE0C10E64F" ) + +/** + * The hexadecimal presentation of the chosen generator of the 2048-bit MODP + * Group with 224-bit Prime Order Subgroup, as defined in RFC-5114: + * Additional Diffie-Hellman Groups for Use with IETF Standards. + */ +#define MBEDTLS_DHM_RFC5114_MODP_2048_G \ + MBEDTLS_DEPRECATED_STRING_CONSTANT( \ + "AC4032EF4F2D9AE39DF30B5C8FFDAC506CDEBE7B89998CAF" \ + "74866A08CFE4FFE3A6824A4E10B9A6F0DD921F01A70C4AFA" \ + "AB739D7700C29F52C57DB17C620A8652BE5E9001A8D66AD7" \ + "C17669101999024AF4D027275AC1348BB8A762D0521BC98A" \ + "E247150422EA1ED409939D54DA7460CDB5F6C6B250717CBE" \ + "F180EB34118E98D119529A45D6F834566E3025E316A330EF" \ + "BB77A86F0C1AB15B051AE3D428C8F8ACB70A8137150B8EEB" \ + "10E183EDD19963DDD9E263E4770589EF6AA21E7F5F2FF381" \ + "B539CCE3409D13CD566AFBB48D6C019181E1BCFE94B30269" \ + "EDFE72FE9B6AA4BD7B5A0F1C71CFFF4C19C418E1F6EC0179" \ + "81BC087F2A7065B384B890D3191F2BFA" ) + +/** + * The hexadecimal presentation of the prime underlying the 2048-bit MODP + * Group, as defined in RFC-3526: More Modular Exponential (MODP) + * Diffie-Hellman groups for Internet Key Exchange (IKE). + * + * \deprecated The hex-encoded primes from RFC 3625 are deprecated and + * superseded by the corresponding macros providing them as + * binary constants. Their hex-encoded constants are likely + * to be removed in a future version of the library. + * + */ +#define MBEDTLS_DHM_RFC3526_MODP_2048_P \ + MBEDTLS_DEPRECATED_STRING_CONSTANT( \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ + "15728E5A8AACAA68FFFFFFFFFFFFFFFF" ) + +/** + * The hexadecimal presentation of the chosen generator of the 2048-bit MODP + * Group, as defined in RFC-3526: More Modular Exponential (MODP) + * Diffie-Hellman groups for Internet Key Exchange (IKE). + */ +#define MBEDTLS_DHM_RFC3526_MODP_2048_G \ + MBEDTLS_DEPRECATED_STRING_CONSTANT( "02" ) + +/** + * The hexadecimal presentation of the prime underlying the 3072-bit MODP + * Group, as defined in RFC-3072: More Modular Exponential (MODP) + * Diffie-Hellman groups for Internet Key Exchange (IKE). + */ +#define MBEDTLS_DHM_RFC3526_MODP_3072_P \ + MBEDTLS_DEPRECATED_STRING_CONSTANT( \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF" ) + +/** + * The hexadecimal presentation of the chosen generator of the 3072-bit MODP + * Group, as defined in RFC-3526: More Modular Exponential (MODP) + * Diffie-Hellman groups for Internet Key Exchange (IKE). + */ +#define MBEDTLS_DHM_RFC3526_MODP_3072_G \ + MBEDTLS_DEPRECATED_STRING_CONSTANT( "02" ) + +/** + * The hexadecimal presentation of the prime underlying the 4096-bit MODP + * Group, as defined in RFC-3526: More Modular Exponential (MODP) + * Diffie-Hellman groups for Internet Key Exchange (IKE). + */ +#define MBEDTLS_DHM_RFC3526_MODP_4096_P \ + MBEDTLS_DEPRECATED_STRING_CONSTANT( \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \ + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \ + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \ + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \ + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \ + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" \ + "FFFFFFFFFFFFFFFF" ) + +/** + * The hexadecimal presentation of the chosen generator of the 4096-bit MODP + * Group, as defined in RFC-3526: More Modular Exponential (MODP) + * Diffie-Hellman groups for Internet Key Exchange (IKE). + */ +#define MBEDTLS_DHM_RFC3526_MODP_4096_G \ + MBEDTLS_DEPRECATED_STRING_CONSTANT( "02" ) + +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + +/* + * Trustworthy DHM parameters in binary form + */ + +#define MBEDTLS_DHM_RFC3526_MODP_2048_P_BIN { \ + 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 } + +#define MBEDTLS_DHM_RFC3526_MODP_2048_G_BIN { 0x02 } + +#define MBEDTLS_DHM_RFC3526_MODP_3072_P_BIN { \ + 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 } + +#define MBEDTLS_DHM_RFC3526_MODP_3072_G_BIN { 0x02 } + +#define MBEDTLS_DHM_RFC3526_MODP_4096_P_BIN { \ + 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 } + +#define MBEDTLS_DHM_RFC3526_MODP_4096_G_BIN { 0x02 } + +#define MBEDTLS_DHM_RFC7919_FFDHE2048_P_BIN { \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, \ + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, \ + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, \ + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, \ + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, \ + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, \ + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, \ + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, \ + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, \ + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, \ + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, \ + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, \ + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, \ + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, \ + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, \ + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, \ + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, \ + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, \ + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, \ + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, \ + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, \ + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, \ + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, \ + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, \ + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, \ + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, \ + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, \ + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, \ + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, \ + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x28, 0x5C, 0x97, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, } + +#define MBEDTLS_DHM_RFC7919_FFDHE2048_G_BIN { 0x02 } + +#define MBEDTLS_DHM_RFC7919_FFDHE3072_P_BIN { \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, \ + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, \ + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, \ + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, \ + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, \ + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, \ + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, \ + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, \ + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, \ + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, \ + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, \ + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, \ + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, \ + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, \ + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, \ + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, \ + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, \ + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, \ + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, \ + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, \ + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, \ + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, \ + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, \ + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, \ + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, \ + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, \ + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, \ + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, \ + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, \ + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, \ + 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, \ + 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, \ + 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, \ + 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, \ + 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, \ + 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, \ + 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, \ + 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, \ + 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, \ + 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, \ + 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, \ + 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, \ + 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, \ + 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, \ + 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, \ + 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0xC6, 0x2E, 0x37, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + +#define MBEDTLS_DHM_RFC7919_FFDHE3072_G_BIN { 0x02 } + +#define MBEDTLS_DHM_RFC7919_FFDHE4096_P_BIN { \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, \ + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, \ + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, \ + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, \ + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, \ + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, \ + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, \ + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, \ + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, \ + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, \ + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, \ + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, \ + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, \ + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, \ + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, \ + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, \ + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, \ + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, \ + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, \ + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, \ + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, \ + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, \ + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, \ + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, \ + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, \ + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, \ + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, \ + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, \ + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, \ + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, \ + 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, \ + 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, \ + 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, \ + 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, \ + 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, \ + 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, \ + 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, \ + 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, \ + 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, \ + 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, \ + 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, \ + 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, \ + 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, \ + 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, \ + 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, \ + 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0x9E, 0x1E, 0xF1, \ + 0x6E, 0x6F, 0x52, 0xC3, 0x16, 0x4D, 0xF4, 0xFB, \ + 0x79, 0x30, 0xE9, 0xE4, 0xE5, 0x88, 0x57, 0xB6, \ + 0xAC, 0x7D, 0x5F, 0x42, 0xD6, 0x9F, 0x6D, 0x18, \ + 0x77, 0x63, 0xCF, 0x1D, 0x55, 0x03, 0x40, 0x04, \ + 0x87, 0xF5, 0x5B, 0xA5, 0x7E, 0x31, 0xCC, 0x7A, \ + 0x71, 0x35, 0xC8, 0x86, 0xEF, 0xB4, 0x31, 0x8A, \ + 0xED, 0x6A, 0x1E, 0x01, 0x2D, 0x9E, 0x68, 0x32, \ + 0xA9, 0x07, 0x60, 0x0A, 0x91, 0x81, 0x30, 0xC4, \ + 0x6D, 0xC7, 0x78, 0xF9, 0x71, 0xAD, 0x00, 0x38, \ + 0x09, 0x29, 0x99, 0xA3, 0x33, 0xCB, 0x8B, 0x7A, \ + 0x1A, 0x1D, 0xB9, 0x3D, 0x71, 0x40, 0x00, 0x3C, \ + 0x2A, 0x4E, 0xCE, 0xA9, 0xF9, 0x8D, 0x0A, 0xCC, \ + 0x0A, 0x82, 0x91, 0xCD, 0xCE, 0xC9, 0x7D, 0xCF, \ + 0x8E, 0xC9, 0xB5, 0x5A, 0x7F, 0x88, 0xA4, 0x6B, \ + 0x4D, 0xB5, 0xA8, 0x51, 0xF4, 0x41, 0x82, 0xE1, \ + 0xC6, 0x8A, 0x00, 0x7E, 0x5E, 0x65, 0x5F, 0x6A, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + +#define MBEDTLS_DHM_RFC7919_FFDHE4096_G_BIN { 0x02 } + +#define MBEDTLS_DHM_RFC7919_FFDHE6144_P_BIN { \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, \ + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, \ + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, \ + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, \ + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, \ + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, \ + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, \ + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, \ + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, \ + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, \ + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, \ + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, \ + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, \ + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, \ + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, \ + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, \ + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, \ + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, \ + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, \ + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, \ + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, \ + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, \ + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, \ + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, \ + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, \ + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, \ + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, \ + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, \ + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, \ + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, \ + 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, \ + 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, \ + 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, \ + 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, \ + 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, \ + 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, \ + 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, \ + 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, \ + 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, \ + 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, \ + 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, \ + 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, \ + 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, \ + 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, \ + 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, \ + 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0x9E, 0x1E, 0xF1, \ + 0x6E, 0x6F, 0x52, 0xC3, 0x16, 0x4D, 0xF4, 0xFB, \ + 0x79, 0x30, 0xE9, 0xE4, 0xE5, 0x88, 0x57, 0xB6, \ + 0xAC, 0x7D, 0x5F, 0x42, 0xD6, 0x9F, 0x6D, 0x18, \ + 0x77, 0x63, 0xCF, 0x1D, 0x55, 0x03, 0x40, 0x04, \ + 0x87, 0xF5, 0x5B, 0xA5, 0x7E, 0x31, 0xCC, 0x7A, \ + 0x71, 0x35, 0xC8, 0x86, 0xEF, 0xB4, 0x31, 0x8A, \ + 0xED, 0x6A, 0x1E, 0x01, 0x2D, 0x9E, 0x68, 0x32, \ + 0xA9, 0x07, 0x60, 0x0A, 0x91, 0x81, 0x30, 0xC4, \ + 0x6D, 0xC7, 0x78, 0xF9, 0x71, 0xAD, 0x00, 0x38, \ + 0x09, 0x29, 0x99, 0xA3, 0x33, 0xCB, 0x8B, 0x7A, \ + 0x1A, 0x1D, 0xB9, 0x3D, 0x71, 0x40, 0x00, 0x3C, \ + 0x2A, 0x4E, 0xCE, 0xA9, 0xF9, 0x8D, 0x0A, 0xCC, \ + 0x0A, 0x82, 0x91, 0xCD, 0xCE, 0xC9, 0x7D, 0xCF, \ + 0x8E, 0xC9, 0xB5, 0x5A, 0x7F, 0x88, 0xA4, 0x6B, \ + 0x4D, 0xB5, 0xA8, 0x51, 0xF4, 0x41, 0x82, 0xE1, \ + 0xC6, 0x8A, 0x00, 0x7E, 0x5E, 0x0D, 0xD9, 0x02, \ + 0x0B, 0xFD, 0x64, 0xB6, 0x45, 0x03, 0x6C, 0x7A, \ + 0x4E, 0x67, 0x7D, 0x2C, 0x38, 0x53, 0x2A, 0x3A, \ + 0x23, 0xBA, 0x44, 0x42, 0xCA, 0xF5, 0x3E, 0xA6, \ + 0x3B, 0xB4, 0x54, 0x32, 0x9B, 0x76, 0x24, 0xC8, \ + 0x91, 0x7B, 0xDD, 0x64, 0xB1, 0xC0, 0xFD, 0x4C, \ + 0xB3, 0x8E, 0x8C, 0x33, 0x4C, 0x70, 0x1C, 0x3A, \ + 0xCD, 0xAD, 0x06, 0x57, 0xFC, 0xCF, 0xEC, 0x71, \ + 0x9B, 0x1F, 0x5C, 0x3E, 0x4E, 0x46, 0x04, 0x1F, \ + 0x38, 0x81, 0x47, 0xFB, 0x4C, 0xFD, 0xB4, 0x77, \ + 0xA5, 0x24, 0x71, 0xF7, 0xA9, 0xA9, 0x69, 0x10, \ + 0xB8, 0x55, 0x32, 0x2E, 0xDB, 0x63, 0x40, 0xD8, \ + 0xA0, 0x0E, 0xF0, 0x92, 0x35, 0x05, 0x11, 0xE3, \ + 0x0A, 0xBE, 0xC1, 0xFF, 0xF9, 0xE3, 0xA2, 0x6E, \ + 0x7F, 0xB2, 0x9F, 0x8C, 0x18, 0x30, 0x23, 0xC3, \ + 0x58, 0x7E, 0x38, 0xDA, 0x00, 0x77, 0xD9, 0xB4, \ + 0x76, 0x3E, 0x4E, 0x4B, 0x94, 0xB2, 0xBB, 0xC1, \ + 0x94, 0xC6, 0x65, 0x1E, 0x77, 0xCA, 0xF9, 0x92, \ + 0xEE, 0xAA, 0xC0, 0x23, 0x2A, 0x28, 0x1B, 0xF6, \ + 0xB3, 0xA7, 0x39, 0xC1, 0x22, 0x61, 0x16, 0x82, \ + 0x0A, 0xE8, 0xDB, 0x58, 0x47, 0xA6, 0x7C, 0xBE, \ + 0xF9, 0xC9, 0x09, 0x1B, 0x46, 0x2D, 0x53, 0x8C, \ + 0xD7, 0x2B, 0x03, 0x74, 0x6A, 0xE7, 0x7F, 0x5E, \ + 0x62, 0x29, 0x2C, 0x31, 0x15, 0x62, 0xA8, 0x46, \ + 0x50, 0x5D, 0xC8, 0x2D, 0xB8, 0x54, 0x33, 0x8A, \ + 0xE4, 0x9F, 0x52, 0x35, 0xC9, 0x5B, 0x91, 0x17, \ + 0x8C, 0xCF, 0x2D, 0xD5, 0xCA, 0xCE, 0xF4, 0x03, \ + 0xEC, 0x9D, 0x18, 0x10, 0xC6, 0x27, 0x2B, 0x04, \ + 0x5B, 0x3B, 0x71, 0xF9, 0xDC, 0x6B, 0x80, 0xD6, \ + 0x3F, 0xDD, 0x4A, 0x8E, 0x9A, 0xDB, 0x1E, 0x69, \ + 0x62, 0xA6, 0x95, 0x26, 0xD4, 0x31, 0x61, 0xC1, \ + 0xA4, 0x1D, 0x57, 0x0D, 0x79, 0x38, 0xDA, 0xD4, \ + 0xA4, 0x0E, 0x32, 0x9C, 0xD0, 0xE4, 0x0E, 0x65, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + +#define MBEDTLS_DHM_RFC7919_FFDHE6144_G_BIN { 0x02 } + +#define MBEDTLS_DHM_RFC7919_FFDHE8192_P_BIN { \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \ + 0xAD, 0xF8, 0x54, 0x58, 0xA2, 0xBB, 0x4A, 0x9A, \ + 0xAF, 0xDC, 0x56, 0x20, 0x27, 0x3D, 0x3C, 0xF1, \ + 0xD8, 0xB9, 0xC5, 0x83, 0xCE, 0x2D, 0x36, 0x95, \ + 0xA9, 0xE1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xFB, \ + 0xCC, 0x93, 0x9D, 0xCE, 0x24, 0x9B, 0x3E, 0xF9, \ + 0x7D, 0x2F, 0xE3, 0x63, 0x63, 0x0C, 0x75, 0xD8, \ + 0xF6, 0x81, 0xB2, 0x02, 0xAE, 0xC4, 0x61, 0x7A, \ + 0xD3, 0xDF, 0x1E, 0xD5, 0xD5, 0xFD, 0x65, 0x61, \ + 0x24, 0x33, 0xF5, 0x1F, 0x5F, 0x06, 0x6E, 0xD0, \ + 0x85, 0x63, 0x65, 0x55, 0x3D, 0xED, 0x1A, 0xF3, \ + 0xB5, 0x57, 0x13, 0x5E, 0x7F, 0x57, 0xC9, 0x35, \ + 0x98, 0x4F, 0x0C, 0x70, 0xE0, 0xE6, 0x8B, 0x77, \ + 0xE2, 0xA6, 0x89, 0xDA, 0xF3, 0xEF, 0xE8, 0x72, \ + 0x1D, 0xF1, 0x58, 0xA1, 0x36, 0xAD, 0xE7, 0x35, \ + 0x30, 0xAC, 0xCA, 0x4F, 0x48, 0x3A, 0x79, 0x7A, \ + 0xBC, 0x0A, 0xB1, 0x82, 0xB3, 0x24, 0xFB, 0x61, \ + 0xD1, 0x08, 0xA9, 0x4B, 0xB2, 0xC8, 0xE3, 0xFB, \ + 0xB9, 0x6A, 0xDA, 0xB7, 0x60, 0xD7, 0xF4, 0x68, \ + 0x1D, 0x4F, 0x42, 0xA3, 0xDE, 0x39, 0x4D, 0xF4, \ + 0xAE, 0x56, 0xED, 0xE7, 0x63, 0x72, 0xBB, 0x19, \ + 0x0B, 0x07, 0xA7, 0xC8, 0xEE, 0x0A, 0x6D, 0x70, \ + 0x9E, 0x02, 0xFC, 0xE1, 0xCD, 0xF7, 0xE2, 0xEC, \ + 0xC0, 0x34, 0x04, 0xCD, 0x28, 0x34, 0x2F, 0x61, \ + 0x91, 0x72, 0xFE, 0x9C, 0xE9, 0x85, 0x83, 0xFF, \ + 0x8E, 0x4F, 0x12, 0x32, 0xEE, 0xF2, 0x81, 0x83, \ + 0xC3, 0xFE, 0x3B, 0x1B, 0x4C, 0x6F, 0xAD, 0x73, \ + 0x3B, 0xB5, 0xFC, 0xBC, 0x2E, 0xC2, 0x20, 0x05, \ + 0xC5, 0x8E, 0xF1, 0x83, 0x7D, 0x16, 0x83, 0xB2, \ + 0xC6, 0xF3, 0x4A, 0x26, 0xC1, 0xB2, 0xEF, 0xFA, \ + 0x88, 0x6B, 0x42, 0x38, 0x61, 0x1F, 0xCF, 0xDC, \ + 0xDE, 0x35, 0x5B, 0x3B, 0x65, 0x19, 0x03, 0x5B, \ + 0xBC, 0x34, 0xF4, 0xDE, 0xF9, 0x9C, 0x02, 0x38, \ + 0x61, 0xB4, 0x6F, 0xC9, 0xD6, 0xE6, 0xC9, 0x07, \ + 0x7A, 0xD9, 0x1D, 0x26, 0x91, 0xF7, 0xF7, 0xEE, \ + 0x59, 0x8C, 0xB0, 0xFA, 0xC1, 0x86, 0xD9, 0x1C, \ + 0xAE, 0xFE, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, \ + 0xB4, 0x13, 0x0C, 0x93, 0xBC, 0x43, 0x79, 0x44, \ + 0xF4, 0xFD, 0x44, 0x52, 0xE2, 0xD7, 0x4D, 0xD3, \ + 0x64, 0xF2, 0xE2, 0x1E, 0x71, 0xF5, 0x4B, 0xFF, \ + 0x5C, 0xAE, 0x82, 0xAB, 0x9C, 0x9D, 0xF6, 0x9E, \ + 0xE8, 0x6D, 0x2B, 0xC5, 0x22, 0x36, 0x3A, 0x0D, \ + 0xAB, 0xC5, 0x21, 0x97, 0x9B, 0x0D, 0xEA, 0xDA, \ + 0x1D, 0xBF, 0x9A, 0x42, 0xD5, 0xC4, 0x48, 0x4E, \ + 0x0A, 0xBC, 0xD0, 0x6B, 0xFA, 0x53, 0xDD, 0xEF, \ + 0x3C, 0x1B, 0x20, 0xEE, 0x3F, 0xD5, 0x9D, 0x7C, \ + 0x25, 0xE4, 0x1D, 0x2B, 0x66, 0x9E, 0x1E, 0xF1, \ + 0x6E, 0x6F, 0x52, 0xC3, 0x16, 0x4D, 0xF4, 0xFB, \ + 0x79, 0x30, 0xE9, 0xE4, 0xE5, 0x88, 0x57, 0xB6, \ + 0xAC, 0x7D, 0x5F, 0x42, 0xD6, 0x9F, 0x6D, 0x18, \ + 0x77, 0x63, 0xCF, 0x1D, 0x55, 0x03, 0x40, 0x04, \ + 0x87, 0xF5, 0x5B, 0xA5, 0x7E, 0x31, 0xCC, 0x7A, \ + 0x71, 0x35, 0xC8, 0x86, 0xEF, 0xB4, 0x31, 0x8A, \ + 0xED, 0x6A, 0x1E, 0x01, 0x2D, 0x9E, 0x68, 0x32, \ + 0xA9, 0x07, 0x60, 0x0A, 0x91, 0x81, 0x30, 0xC4, \ + 0x6D, 0xC7, 0x78, 0xF9, 0x71, 0xAD, 0x00, 0x38, \ + 0x09, 0x29, 0x99, 0xA3, 0x33, 0xCB, 0x8B, 0x7A, \ + 0x1A, 0x1D, 0xB9, 0x3D, 0x71, 0x40, 0x00, 0x3C, \ + 0x2A, 0x4E, 0xCE, 0xA9, 0xF9, 0x8D, 0x0A, 0xCC, \ + 0x0A, 0x82, 0x91, 0xCD, 0xCE, 0xC9, 0x7D, 0xCF, \ + 0x8E, 0xC9, 0xB5, 0x5A, 0x7F, 0x88, 0xA4, 0x6B, \ + 0x4D, 0xB5, 0xA8, 0x51, 0xF4, 0x41, 0x82, 0xE1, \ + 0xC6, 0x8A, 0x00, 0x7E, 0x5E, 0x0D, 0xD9, 0x02, \ + 0x0B, 0xFD, 0x64, 0xB6, 0x45, 0x03, 0x6C, 0x7A, \ + 0x4E, 0x67, 0x7D, 0x2C, 0x38, 0x53, 0x2A, 0x3A, \ + 0x23, 0xBA, 0x44, 0x42, 0xCA, 0xF5, 0x3E, 0xA6, \ + 0x3B, 0xB4, 0x54, 0x32, 0x9B, 0x76, 0x24, 0xC8, \ + 0x91, 0x7B, 0xDD, 0x64, 0xB1, 0xC0, 0xFD, 0x4C, \ + 0xB3, 0x8E, 0x8C, 0x33, 0x4C, 0x70, 0x1C, 0x3A, \ + 0xCD, 0xAD, 0x06, 0x57, 0xFC, 0xCF, 0xEC, 0x71, \ + 0x9B, 0x1F, 0x5C, 0x3E, 0x4E, 0x46, 0x04, 0x1F, \ + 0x38, 0x81, 0x47, 0xFB, 0x4C, 0xFD, 0xB4, 0x77, \ + 0xA5, 0x24, 0x71, 0xF7, 0xA9, 0xA9, 0x69, 0x10, \ + 0xB8, 0x55, 0x32, 0x2E, 0xDB, 0x63, 0x40, 0xD8, \ + 0xA0, 0x0E, 0xF0, 0x92, 0x35, 0x05, 0x11, 0xE3, \ + 0x0A, 0xBE, 0xC1, 0xFF, 0xF9, 0xE3, 0xA2, 0x6E, \ + 0x7F, 0xB2, 0x9F, 0x8C, 0x18, 0x30, 0x23, 0xC3, \ + 0x58, 0x7E, 0x38, 0xDA, 0x00, 0x77, 0xD9, 0xB4, \ + 0x76, 0x3E, 0x4E, 0x4B, 0x94, 0xB2, 0xBB, 0xC1, \ + 0x94, 0xC6, 0x65, 0x1E, 0x77, 0xCA, 0xF9, 0x92, \ + 0xEE, 0xAA, 0xC0, 0x23, 0x2A, 0x28, 0x1B, 0xF6, \ + 0xB3, 0xA7, 0x39, 0xC1, 0x22, 0x61, 0x16, 0x82, \ + 0x0A, 0xE8, 0xDB, 0x58, 0x47, 0xA6, 0x7C, 0xBE, \ + 0xF9, 0xC9, 0x09, 0x1B, 0x46, 0x2D, 0x53, 0x8C, \ + 0xD7, 0x2B, 0x03, 0x74, 0x6A, 0xE7, 0x7F, 0x5E, \ + 0x62, 0x29, 0x2C, 0x31, 0x15, 0x62, 0xA8, 0x46, \ + 0x50, 0x5D, 0xC8, 0x2D, 0xB8, 0x54, 0x33, 0x8A, \ + 0xE4, 0x9F, 0x52, 0x35, 0xC9, 0x5B, 0x91, 0x17, \ + 0x8C, 0xCF, 0x2D, 0xD5, 0xCA, 0xCE, 0xF4, 0x03, \ + 0xEC, 0x9D, 0x18, 0x10, 0xC6, 0x27, 0x2B, 0x04, \ + 0x5B, 0x3B, 0x71, 0xF9, 0xDC, 0x6B, 0x80, 0xD6, \ + 0x3F, 0xDD, 0x4A, 0x8E, 0x9A, 0xDB, 0x1E, 0x69, \ + 0x62, 0xA6, 0x95, 0x26, 0xD4, 0x31, 0x61, 0xC1, \ + 0xA4, 0x1D, 0x57, 0x0D, 0x79, 0x38, 0xDA, 0xD4, \ + 0xA4, 0x0E, 0x32, 0x9C, 0xCF, 0xF4, 0x6A, 0xAA, \ + 0x36, 0xAD, 0x00, 0x4C, 0xF6, 0x00, 0xC8, 0x38, \ + 0x1E, 0x42, 0x5A, 0x31, 0xD9, 0x51, 0xAE, 0x64, \ + 0xFD, 0xB2, 0x3F, 0xCE, 0xC9, 0x50, 0x9D, 0x43, \ + 0x68, 0x7F, 0xEB, 0x69, 0xED, 0xD1, 0xCC, 0x5E, \ + 0x0B, 0x8C, 0xC3, 0xBD, 0xF6, 0x4B, 0x10, 0xEF, \ + 0x86, 0xB6, 0x31, 0x42, 0xA3, 0xAB, 0x88, 0x29, \ + 0x55, 0x5B, 0x2F, 0x74, 0x7C, 0x93, 0x26, 0x65, \ + 0xCB, 0x2C, 0x0F, 0x1C, 0xC0, 0x1B, 0xD7, 0x02, \ + 0x29, 0x38, 0x88, 0x39, 0xD2, 0xAF, 0x05, 0xE4, \ + 0x54, 0x50, 0x4A, 0xC7, 0x8B, 0x75, 0x82, 0x82, \ + 0x28, 0x46, 0xC0, 0xBA, 0x35, 0xC3, 0x5F, 0x5C, \ + 0x59, 0x16, 0x0C, 0xC0, 0x46, 0xFD, 0x82, 0x51, \ + 0x54, 0x1F, 0xC6, 0x8C, 0x9C, 0x86, 0xB0, 0x22, \ + 0xBB, 0x70, 0x99, 0x87, 0x6A, 0x46, 0x0E, 0x74, \ + 0x51, 0xA8, 0xA9, 0x31, 0x09, 0x70, 0x3F, 0xEE, \ + 0x1C, 0x21, 0x7E, 0x6C, 0x38, 0x26, 0xE5, 0x2C, \ + 0x51, 0xAA, 0x69, 0x1E, 0x0E, 0x42, 0x3C, 0xFC, \ + 0x99, 0xE9, 0xE3, 0x16, 0x50, 0xC1, 0x21, 0x7B, \ + 0x62, 0x48, 0x16, 0xCD, 0xAD, 0x9A, 0x95, 0xF9, \ + 0xD5, 0xB8, 0x01, 0x94, 0x88, 0xD9, 0xC0, 0xA0, \ + 0xA1, 0xFE, 0x30, 0x75, 0xA5, 0x77, 0xE2, 0x31, \ + 0x83, 0xF8, 0x1D, 0x4A, 0x3F, 0x2F, 0xA4, 0x57, \ + 0x1E, 0xFC, 0x8C, 0xE0, 0xBA, 0x8A, 0x4F, 0xE8, \ + 0xB6, 0x85, 0x5D, 0xFE, 0x72, 0xB0, 0xA6, 0x6E, \ + 0xDE, 0xD2, 0xFB, 0xAB, 0xFB, 0xE5, 0x8A, 0x30, \ + 0xFA, 0xFA, 0xBE, 0x1C, 0x5D, 0x71, 0xA8, 0x7E, \ + 0x2F, 0x74, 0x1E, 0xF8, 0xC1, 0xFE, 0x86, 0xFE, \ + 0xA6, 0xBB, 0xFD, 0xE5, 0x30, 0x67, 0x7F, 0x0D, \ + 0x97, 0xD1, 0x1D, 0x49, 0xF7, 0xA8, 0x44, 0x3D, \ + 0x08, 0x22, 0xE5, 0x06, 0xA9, 0xF4, 0x61, 0x4E, \ + 0x01, 0x1E, 0x2A, 0x94, 0x83, 0x8F, 0xF8, 0x8C, \ + 0xD6, 0x8C, 0x8B, 0xB7, 0xC5, 0xC6, 0x42, 0x4C, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } + +#define MBEDTLS_DHM_RFC7919_FFDHE8192_G_BIN { 0x02 } + +#endif /* dhm.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecdh.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecdh.h new file mode 100644 index 000000000..1b0bcdff5 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecdh.h @@ -0,0 +1,428 @@ +/** + * \file ecdh.h + * + * \brief This file contains ECDH definitions and functions. + * + * The Elliptic Curve Diffie-Hellman (ECDH) protocol is an anonymous + * key agreement protocol allowing two parties to establish a shared + * secret over an insecure channel. Each party must have an + * elliptic-curve public–private key pair. + * + * For more information, see NIST SP 800-56A Rev. 2: Recommendation for + * Pair-Wise Key Establishment Schemes Using Discrete Logarithm + * Cryptography. + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_ECDH_H +#define MBEDTLS_ECDH_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "ecp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Defines the source of the imported EC key. + */ +typedef enum +{ + MBEDTLS_ECDH_OURS, /**< Our key. */ + MBEDTLS_ECDH_THEIRS, /**< The key of the peer. */ +} mbedtls_ecdh_side; + +#if !defined(MBEDTLS_ECDH_LEGACY_CONTEXT) +/** + * Defines the ECDH implementation used. + * + * Later versions of the library may add new variants, therefore users should + * not make any assumptions about them. + */ +typedef enum +{ + MBEDTLS_ECDH_VARIANT_NONE = 0, /*!< Implementation not defined. */ + MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0,/*!< The default Mbed TLS implementation */ +} mbedtls_ecdh_variant; + +/** + * The context used by the default ECDH implementation. + * + * Later versions might change the structure of this context, therefore users + * should not make any assumptions about the structure of + * mbedtls_ecdh_context_mbed. + */ +typedef struct mbedtls_ecdh_context_mbed +{ + mbedtls_ecp_group grp; /*!< The elliptic curve used. */ + mbedtls_mpi d; /*!< The private key. */ + mbedtls_ecp_point Q; /*!< The public key. */ + mbedtls_ecp_point Qp; /*!< The value of the public key of the peer. */ + mbedtls_mpi z; /*!< The shared secret. */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_ctx rs; /*!< The restart context for EC computations. */ +#endif +} mbedtls_ecdh_context_mbed; +#endif + +/** + * + * \warning Performing multiple operations concurrently on the same + * ECDSA context is not supported; objects of this type + * should not be shared between multiple threads. + * \brief The ECDH context structure. + */ +typedef struct mbedtls_ecdh_context +{ +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + mbedtls_ecp_group grp; /*!< The elliptic curve used. */ + mbedtls_mpi d; /*!< The private key. */ + mbedtls_ecp_point Q; /*!< The public key. */ + mbedtls_ecp_point Qp; /*!< The value of the public key of the peer. */ + mbedtls_mpi z; /*!< The shared secret. */ + int point_format; /*!< The format of point export in TLS messages. */ + mbedtls_ecp_point Vi; /*!< The blinding value. */ + mbedtls_ecp_point Vf; /*!< The unblinding value. */ + mbedtls_mpi _d; /*!< The previous \p d. */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + int restart_enabled; /*!< The flag for restartable mode. */ + mbedtls_ecp_restart_ctx rs; /*!< The restart context for EC computations. */ +#endif /* MBEDTLS_ECP_RESTARTABLE */ +#else + uint8_t point_format; /*!< The format of point export in TLS messages + as defined in RFC 4492. */ + mbedtls_ecp_group_id grp_id;/*!< The elliptic curve used. */ + mbedtls_ecdh_variant var; /*!< The ECDH implementation/structure used. */ + union + { + mbedtls_ecdh_context_mbed mbed_ecdh; + } ctx; /*!< Implementation-specific context. The + context in use is specified by the \c var + field. */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + uint8_t restart_enabled; /*!< The flag for restartable mode. Functions of + an alternative implementation not supporting + restartable mode must return + MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED error + if this flag is set. */ +#endif /* MBEDTLS_ECP_RESTARTABLE */ +#endif /* MBEDTLS_ECDH_LEGACY_CONTEXT */ +} +mbedtls_ecdh_context; + +/** + * \brief This function generates an ECDH keypair on an elliptic + * curve. + * + * This function performs the first of two core computations + * implemented during the ECDH key exchange. The second core + * computation is performed by mbedtls_ecdh_compute_shared(). + * + * \see ecp.h + * + * \param grp The ECP group to use. This must be initialized and have + * domain parameters loaded, for example through + * mbedtls_ecp_load() or mbedtls_ecp_tls_read_group(). + * \param d The destination MPI (private key). + * This must be initialized. + * \param Q The destination point (public key). + * This must be initialized. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL in case \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return Another \c MBEDTLS_ERR_ECP_XXX or + * \c MBEDTLS_MPI_XXX error code on failure. + */ +int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function computes the shared secret. + * + * This function performs the second of two core computations + * implemented during the ECDH key exchange. The first core + * computation is performed by mbedtls_ecdh_gen_public(). + * + * \see ecp.h + * + * \note If \p f_rng is not NULL, it is used to implement + * countermeasures against side-channel attacks. + * For more information, see mbedtls_ecp_mul(). + * + * \param grp The ECP group to use. This must be initialized and have + * domain parameters loaded, for example through + * mbedtls_ecp_load() or mbedtls_ecp_tls_read_group(). + * \param z The destination MPI (shared secret). + * This must be initialized. + * \param Q The public key from another party. + * This must be initialized. + * \param d Our secret exponent (private key). + * This must be initialized. + * \param f_rng The RNG function. This may be \c NULL if randomization + * of intermediate results during the ECP computations is + * not needed (discouraged). See the documentation of + * mbedtls_ecp_mul() for more. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a + * context argument. + * + * \return \c 0 on success. + * \return Another \c MBEDTLS_ERR_ECP_XXX or + * \c MBEDTLS_MPI_XXX error code on failure. + */ +int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, + const mbedtls_ecp_point *Q, const mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function initializes an ECDH context. + * + * \param ctx The ECDH context to initialize. This must not be \c NULL. + */ +void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ); + +/** + * \brief This function sets up the ECDH context with the information + * given. + * + * This function should be called after mbedtls_ecdh_init() but + * before mbedtls_ecdh_make_params(). There is no need to call + * this function before mbedtls_ecdh_read_params(). + * + * This is the first function used by a TLS server for ECDHE + * ciphersuites. + * + * \param ctx The ECDH context to set up. This must be initialized. + * \param grp_id The group id of the group to set up the context for. + * + * \return \c 0 on success. + */ +int mbedtls_ecdh_setup( mbedtls_ecdh_context *ctx, + mbedtls_ecp_group_id grp_id ); + +/** + * \brief This function frees a context. + * + * \param ctx The context to free. This may be \c NULL, in which + * case this function does nothing. If it is not \c NULL, + * it must point to an initialized ECDH context. + */ +void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ); + +/** + * \brief This function generates an EC key pair and exports its + * in the format used in a TLS ServerKeyExchange handshake + * message. + * + * This is the second function used by a TLS server for ECDHE + * ciphersuites. (It is called after mbedtls_ecdh_setup().) + * + * \see ecp.h + * + * \param ctx The ECDH context to use. This must be initialized + * and bound to a group, for example via mbedtls_ecdh_setup(). + * \param olen The address at which to store the number of Bytes written. + * \param buf The destination buffer. This must be a writable buffer of + * length \p blen Bytes. + * \param blen The length of the destination buffer \p buf in Bytes. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL in case \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX error code on failure. + */ +int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function parses the ECDHE parameters in a + * TLS ServerKeyExchange handshake message. + * + * \note In a TLS handshake, this is the how the client + * sets up its ECDHE context from the server's public + * ECDHE key material. + * + * \see ecp.h + * + * \param ctx The ECDHE context to use. This must be initialized. + * \param buf On input, \c *buf must be the start of the input buffer. + * On output, \c *buf is updated to point to the end of the + * data that has been read. On success, this is the first byte + * past the end of the ServerKeyExchange parameters. + * On error, this is the point at which an error has been + * detected, which is usually not useful except to debug + * failures. + * \param end The end of the input buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX error code on failure. + * + */ +int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, + const unsigned char **buf, + const unsigned char *end ); + +/** + * \brief This function sets up an ECDH context from an EC key. + * + * It is used by clients and servers in place of the + * ServerKeyEchange for static ECDH, and imports ECDH + * parameters from the EC key information of a certificate. + * + * \see ecp.h + * + * \param ctx The ECDH context to set up. This must be initialized. + * \param key The EC key to use. This must be initialized. + * \param side Defines the source of the key. Possible values are: + * - #MBEDTLS_ECDH_OURS: The key is ours. + * - #MBEDTLS_ECDH_THEIRS: The key is that of the peer. + * + * \return \c 0 on success. + * \return Another \c MBEDTLS_ERR_ECP_XXX error code on failure. + * + */ +int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, + const mbedtls_ecp_keypair *key, + mbedtls_ecdh_side side ); + +/** + * \brief This function generates a public key and exports it + * as a TLS ClientKeyExchange payload. + * + * This is the second function used by a TLS client for ECDH(E) + * ciphersuites. + * + * \see ecp.h + * + * \param ctx The ECDH context to use. This must be initialized + * and bound to a group, the latter usually by + * mbedtls_ecdh_read_params(). + * \param olen The address at which to store the number of Bytes written. + * This must not be \c NULL. + * \param buf The destination buffer. This must be a writable buffer + * of length \p blen Bytes. + * \param blen The size of the destination buffer \p buf in Bytes. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL in case \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX error code on failure. + */ +int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function parses and processes the ECDHE payload of a + * TLS ClientKeyExchange message. + * + * This is the third function used by a TLS server for ECDH(E) + * ciphersuites. (It is called after mbedtls_ecdh_setup() and + * mbedtls_ecdh_make_params().) + * + * \see ecp.h + * + * \param ctx The ECDH context to use. This must be initialized + * and bound to a group, for example via mbedtls_ecdh_setup(). + * \param buf The pointer to the ClientKeyExchange payload. This must + * be a readable buffer of length \p blen Bytes. + * \param blen The length of the input buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX error code on failure. + */ +int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, + const unsigned char *buf, size_t blen ); + +/** + * \brief This function derives and exports the shared secret. + * + * This is the last function used by both TLS client + * and servers. + * + * \note If \p f_rng is not NULL, it is used to implement + * countermeasures against side-channel attacks. + * For more information, see mbedtls_ecp_mul(). + * + * \see ecp.h + + * \param ctx The ECDH context to use. This must be initialized + * and have its own private key generated and the peer's + * public key imported. + * \param olen The address at which to store the total number of + * Bytes written on success. This must not be \c NULL. + * \param buf The buffer to write the generated shared key to. This + * must be a writable buffer of size \p blen Bytes. + * \param blen The length of the destination buffer \p buf in Bytes. + * \param f_rng The RNG function, for blinding purposes. This may + * b \c NULL if blinding isn't needed. + * \param p_rng The RNG context. This may be \c NULL if \p f_rng + * doesn't need a context argument. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX error code on failure. + */ +int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief This function enables restartable EC computations for this + * context. (Default: disabled.) + * + * \see \c mbedtls_ecp_set_max_ops() + * + * \note It is not possible to safely disable restartable + * computations once enabled, except by free-ing the context, + * which cancels possible in-progress operations. + * + * \param ctx The ECDH context to use. This must be initialized. + */ +void mbedtls_ecdh_enable_restart( mbedtls_ecdh_context *ctx ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +#ifdef __cplusplus +} +#endif + +#endif /* ecdh.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecdsa.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecdsa.h new file mode 100644 index 000000000..94585fe17 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecdsa.h @@ -0,0 +1,550 @@ +/** + * \file ecdsa.h + * + * \brief This file contains ECDSA definitions and functions. + * + * The Elliptic Curve Digital Signature Algorithm (ECDSA) is defined in + * Standards for Efficient Cryptography Group (SECG): + * SEC1 Elliptic Curve Cryptography. + * The use of ECDSA for TLS is defined in RFC-4492: Elliptic Curve + * Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS). + * + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_ECDSA_H +#define MBEDTLS_ECDSA_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "ecp.h" +#include "md.h" + +/** + * \brief Maximum ECDSA signature size for a given curve bit size + * + * \param bits Curve size in bits + * \return Maximum signature size in bytes + * + * \note This macro returns a compile-time constant if its argument + * is one. It may evaluate its argument multiple times. + */ +/* + * Ecdsa-Sig-Value ::= SEQUENCE { + * r INTEGER, + * s INTEGER + * } + * + * For each of r and s, the value (V) may include an extra initial "0" bit. + */ +#define MBEDTLS_ECDSA_MAX_SIG_LEN( bits ) \ + ( /*T,L of SEQUENCE*/ ( ( bits ) >= 61 * 8 ? 3 : 2 ) + \ + /*T,L of r,s*/ 2 * ( ( ( bits ) >= 127 * 8 ? 3 : 2 ) + \ + /*V of r,s*/ ( ( bits ) + 8 ) / 8 ) ) + +/** The maximal size of an ECDSA signature in Bytes. */ +#define MBEDTLS_ECDSA_MAX_LEN MBEDTLS_ECDSA_MAX_SIG_LEN( MBEDTLS_ECP_MAX_BITS ) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief The ECDSA context structure. + * + * \warning Performing multiple operations concurrently on the same + * ECDSA context is not supported; objects of this type + * should not be shared between multiple threads. + */ +typedef mbedtls_ecp_keypair mbedtls_ecdsa_context; + +#if defined(MBEDTLS_ECP_RESTARTABLE) + +/** + * \brief Internal restart context for ecdsa_verify() + * + * \note Opaque struct, defined in ecdsa.c + */ +typedef struct mbedtls_ecdsa_restart_ver mbedtls_ecdsa_restart_ver_ctx; + +/** + * \brief Internal restart context for ecdsa_sign() + * + * \note Opaque struct, defined in ecdsa.c + */ +typedef struct mbedtls_ecdsa_restart_sig mbedtls_ecdsa_restart_sig_ctx; + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/** + * \brief Internal restart context for ecdsa_sign_det() + * + * \note Opaque struct, defined in ecdsa.c + */ +typedef struct mbedtls_ecdsa_restart_det mbedtls_ecdsa_restart_det_ctx; +#endif + +/** + * \brief General context for resuming ECDSA operations + */ +typedef struct +{ + mbedtls_ecp_restart_ctx ecp; /*!< base context for ECP restart and + shared administrative info */ + mbedtls_ecdsa_restart_ver_ctx *ver; /*!< ecdsa_verify() sub-context */ + mbedtls_ecdsa_restart_sig_ctx *sig; /*!< ecdsa_sign() sub-context */ +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + mbedtls_ecdsa_restart_det_ctx *det; /*!< ecdsa_sign_det() sub-context */ +#endif +} mbedtls_ecdsa_restart_ctx; + +#else /* MBEDTLS_ECP_RESTARTABLE */ + +/* Now we can declare functions that take a pointer to that */ +typedef void mbedtls_ecdsa_restart_ctx; + +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +/** + * \brief This function computes the ECDSA signature of a + * previously-hashed message. + * + * \note The deterministic version implemented in + * mbedtls_ecdsa_sign_det() is usually preferred. + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated + * as defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.3, step 5. + * + * \see ecp.h + * + * \param grp The context for the elliptic curve to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param r The MPI context in which to store the first part + * the signature. This must be initialized. + * \param s The MPI context in which to store the second part + * the signature. This must be initialized. + * \param d The private signing key. This must be initialized. + * \param buf The content to be signed. This is usually the hash of + * the original data to be signed. This must be a readable + * buffer of length \p blen Bytes. It may be \c NULL if + * \p blen is zero. + * \param blen The length of \p buf in Bytes. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context parameter. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX + * or \c MBEDTLS_MPI_XXX error code on failure. + */ +int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/** + * \brief This function computes the ECDSA signature of a + * previously-hashed message, deterministic version. + * + * For more information, see RFC-6979: Deterministic + * Usage of the Digital Signature Algorithm (DSA) and Elliptic + * Curve Digital Signature Algorithm (ECDSA). + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.3, step 5. + * + * \see ecp.h + * + * \param grp The context for the elliptic curve to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param r The MPI context in which to store the first part + * the signature. This must be initialized. + * \param s The MPI context in which to store the second part + * the signature. This must be initialized. + * \param d The private signing key. This must be initialized + * and setup, for example through mbedtls_ecp_gen_privkey(). + * \param buf The hashed content to be signed. This must be a readable + * buffer of length \p blen Bytes. It may be \c NULL if + * \p blen is zero. + * \param blen The length of \p buf in Bytes. + * \param md_alg The hash algorithm used to hash the original data. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX + * error code on failure. + */ +int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, + mbedtls_mpi *s, const mbedtls_mpi *d, + const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg ); +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +/** + * \brief This function verifies the ECDSA signature of a + * previously-hashed message. + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.4, step 3. + * + * \see ecp.h + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param buf The hashed content that was signed. This must be a readable + * buffer of length \p blen Bytes. It may be \c NULL if + * \p blen is zero. + * \param blen The length of \p buf in Bytes. + * \param Q The public key to use for verification. This must be + * initialized and setup. + * \param r The first integer of the signature. + * This must be initialized. + * \param s The second integer of the signature. + * This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the signature + * is invalid. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX + * error code on failure for any other reason. + */ +int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, const mbedtls_mpi *r, + const mbedtls_mpi *s); + +/** + * \brief This function computes the ECDSA signature and writes it + * to a buffer, serialized as defined in RFC-4492: + * Elliptic Curve Cryptography (ECC) Cipher Suites for + * Transport Layer Security (TLS). + * + * \warning It is not thread-safe to use the same context in + * multiple threads. + * + * \note The deterministic version is used if + * #MBEDTLS_ECDSA_DETERMINISTIC is defined. For more + * information, see RFC-6979: Deterministic Usage + * of the Digital Signature Algorithm (DSA) and Elliptic + * Curve Digital Signature Algorithm (ECDSA). + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.3, step 5. + * + * \see ecp.h + * + * \param ctx The ECDSA context to use. This must be initialized + * and have a group and private key bound to it, for example + * via mbedtls_ecdsa_genkey() or mbedtls_ecdsa_from_keypair(). + * \param md_alg The message digest that was used to hash the message. + * \param hash The message hash to be signed. This must be a readable + * buffer of length \p blen Bytes. + * \param hlen The length of the hash \p hash in Bytes. + * \param sig The buffer to which to write the signature. This must be a + * writable buffer of length at least twice as large as the + * size of the curve used, plus 9. For example, 73 Bytes if + * a 256-bit curve is used. A buffer length of + * #MBEDTLS_ECDSA_MAX_LEN is always safe. + * \param slen The address at which to store the actual length of + * the signature written. Must not be \c NULL. + * \param f_rng The RNG function. This must not be \c NULL if + * #MBEDTLS_ECDSA_DETERMINISTIC is unset. Otherwise, + * it is unused and may be set to \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't use a context. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or + * \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function computes the ECDSA signature and writes it + * to a buffer, in a restartable way. + * + * \see \c mbedtls_ecdsa_write_signature() + * + * \note This function is like \c mbedtls_ecdsa_write_signature() + * but it can return early and restart according to the limit + * set with \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \param ctx The ECDSA context to use. This must be initialized + * and have a group and private key bound to it, for example + * via mbedtls_ecdsa_genkey() or mbedtls_ecdsa_from_keypair(). + * \param md_alg The message digest that was used to hash the message. + * \param hash The message hash to be signed. This must be a readable + * buffer of length \p blen Bytes. + * \param hlen The length of the hash \p hash in Bytes. + * \param sig The buffer to which to write the signature. This must be a + * writable buffer of length at least twice as large as the + * size of the curve used, plus 9. For example, 73 Bytes if + * a 256-bit curve is used. A buffer length of + * #MBEDTLS_ECDSA_MAX_LEN is always safe. + * \param slen The address at which to store the actual length of + * the signature written. Must not be \c NULL. + * \param f_rng The RNG function. This must not be \c NULL if + * #MBEDTLS_ECDSA_DETERMINISTIC is unset. Otherwise, + * it is unused and may be set to \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't use a context. + * \param rs_ctx The restart context to use. This may be \c NULL to disable + * restarting. If it is not \c NULL, it must point to an + * initialized restart context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or + * \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecdsa_restart_ctx *rs_ctx ); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function computes an ECDSA signature and writes + * it to a buffer, serialized as defined in RFC-4492: + * Elliptic Curve Cryptography (ECC) Cipher Suites for + * Transport Layer Security (TLS). + * + * The deterministic version is defined in RFC-6979: + * Deterministic Usage of the Digital Signature Algorithm (DSA) + * and Elliptic Curve Digital Signature Algorithm (ECDSA). + * + * \warning It is not thread-safe to use the same context in + * multiple threads. + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.3, step 5. + * + * \see ecp.h + * + * \deprecated Superseded by mbedtls_ecdsa_write_signature() in + * Mbed TLS version 2.0 and later. + * + * \param ctx The ECDSA context to use. This must be initialized + * and have a group and private key bound to it, for example + * via mbedtls_ecdsa_genkey() or mbedtls_ecdsa_from_keypair(). + * \param hash The message hash to be signed. This must be a readable + * buffer of length \p blen Bytes. + * \param hlen The length of the hash \p hash in Bytes. + * \param sig The buffer to which to write the signature. This must be a + * writable buffer of length at least twice as large as the + * size of the curve used, plus 9. For example, 73 Bytes if + * a 256-bit curve is used. A buffer length of + * #MBEDTLS_ECDSA_MAX_LEN is always safe. + * \param slen The address at which to store the actual length of + * the signature written. Must not be \c NULL. + * \param md_alg The message digest that was used to hash the message. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or + * \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + mbedtls_md_type_t md_alg ) MBEDTLS_DEPRECATED; +#undef MBEDTLS_DEPRECATED +#endif /* MBEDTLS_DEPRECATED_REMOVED */ +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +/** + * \brief This function reads and verifies an ECDSA signature. + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.4, step 3. + * + * \see ecp.h + * + * \param ctx The ECDSA context to use. This must be initialized + * and have a group and public key bound to it. + * \param hash The message hash that was signed. This must be a readable + * buffer of length \p size Bytes. + * \param hlen The size of the hash \p hash. + * \param sig The signature to read and verify. This must be a readable + * buffer of length \p slen Bytes. + * \param slen The size of \p sig in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid. + * \return #MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH if there is a valid + * signature in \p sig, but its length is less than \p siglen. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_ERR_MPI_XXX + * error code on failure for any other reason. + */ +int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen ); + +/** + * \brief This function reads and verifies an ECDSA signature, + * in a restartable way. + * + * \see \c mbedtls_ecdsa_read_signature() + * + * \note This function is like \c mbedtls_ecdsa_read_signature() + * but it can return early and restart according to the limit + * set with \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \param ctx The ECDSA context to use. This must be initialized + * and have a group and public key bound to it. + * \param hash The message hash that was signed. This must be a readable + * buffer of length \p size Bytes. + * \param hlen The size of the hash \p hash. + * \param sig The signature to read and verify. This must be a readable + * buffer of length \p slen Bytes. + * \param slen The size of \p sig in Bytes. + * \param rs_ctx The restart context to use. This may be \c NULL to disable + * restarting. If it is not \c NULL, it must point to an + * initialized restart context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid. + * \return #MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH if there is a valid + * signature in \p sig, but its length is less than \p siglen. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_ERR_MPI_XXX + * error code on failure for any other reason. + */ +int mbedtls_ecdsa_read_signature_restartable( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen, + mbedtls_ecdsa_restart_ctx *rs_ctx ); + +/** + * \brief This function generates an ECDSA keypair on the given curve. + * + * \see ecp.h + * + * \param ctx The ECDSA context to store the keypair in. + * This must be initialized. + * \param gid The elliptic curve to use. One of the various + * \c MBEDTLS_ECP_DP_XXX macros depending on configuration. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX code on failure. + */ +int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief This function sets up an ECDSA context from an EC key pair. + * + * \see ecp.h + * + * \param ctx The ECDSA context to setup. This must be initialized. + * \param key The EC key to use. This must be initialized and hold + * a private-public key pair or a public key. In the former + * case, the ECDSA context may be used for signature creation + * and verification after this call. In the latter case, it + * may be used for signature verification. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX code on failure. + */ +int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, + const mbedtls_ecp_keypair *key ); + +/** + * \brief This function initializes an ECDSA context. + * + * \param ctx The ECDSA context to initialize. + * This must not be \c NULL. + */ +void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ); + +/** + * \brief This function frees an ECDSA context. + * + * \param ctx The ECDSA context to free. This may be \c NULL, + * in which case this function does nothing. If it + * is not \c NULL, it must be initialized. + */ +void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Initialize a restart context. + * + * \param ctx The restart context to initialize. + * This must not be \c NULL. + */ +void mbedtls_ecdsa_restart_init( mbedtls_ecdsa_restart_ctx *ctx ); + +/** + * \brief Free the components of a restart context. + * + * \param ctx The restart context to free. This may be \c NULL, + * in which case this function does nothing. If it + * is not \c NULL, it must be initialized. + */ +void mbedtls_ecdsa_restart_free( mbedtls_ecdsa_restart_ctx *ctx ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +#ifdef __cplusplus +} +#endif + +#endif /* ecdsa.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecjpake.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecjpake.h new file mode 100644 index 000000000..d555a2f28 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecjpake.h @@ -0,0 +1,277 @@ +/** + * \file ecjpake.h + * + * \brief Elliptic curve J-PAKE + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ECJPAKE_H +#define MBEDTLS_ECJPAKE_H + +/* + * J-PAKE is a password-authenticated key exchange that allows deriving a + * strong shared secret from a (potentially low entropy) pre-shared + * passphrase, with forward secrecy and mutual authentication. + * https://en.wikipedia.org/wiki/Password_Authenticated_Key_Exchange_by_Juggling + * + * This file implements the Elliptic Curve variant of J-PAKE, + * as defined in Chapter 7.4 of the Thread v1.0 Specification, + * available to members of the Thread Group http://threadgroup.org/ + * + * As the J-PAKE algorithm is inherently symmetric, so is our API. + * Each party needs to send its first round message, in any order, to the + * other party, then each sends its second round message, in any order. + * The payloads are serialized in a way suitable for use in TLS, but could + * also be use outside TLS. + */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "ecp.h" +#include "md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Roles in the EC J-PAKE exchange + */ +typedef enum { + MBEDTLS_ECJPAKE_CLIENT = 0, /**< Client */ + MBEDTLS_ECJPAKE_SERVER, /**< Server */ +} mbedtls_ecjpake_role; + +#if !defined(MBEDTLS_ECJPAKE_ALT) +/** + * EC J-PAKE context structure. + * + * J-PAKE is a symmetric protocol, except for the identifiers used in + * Zero-Knowledge Proofs, and the serialization of the second message + * (KeyExchange) as defined by the Thread spec. + * + * In order to benefit from this symmetry, we choose a different naming + * convetion from the Thread v1.0 spec. Correspondance is indicated in the + * description as a pair C: client name, S: server name + */ +typedef struct mbedtls_ecjpake_context +{ + const mbedtls_md_info_t *md_info; /**< Hash to use */ + mbedtls_ecp_group grp; /**< Elliptic curve */ + mbedtls_ecjpake_role role; /**< Are we client or server? */ + int point_format; /**< Format for point export */ + + mbedtls_ecp_point Xm1; /**< My public key 1 C: X1, S: X3 */ + mbedtls_ecp_point Xm2; /**< My public key 2 C: X2, S: X4 */ + mbedtls_ecp_point Xp1; /**< Peer public key 1 C: X3, S: X1 */ + mbedtls_ecp_point Xp2; /**< Peer public key 2 C: X4, S: X2 */ + mbedtls_ecp_point Xp; /**< Peer public key C: Xs, S: Xc */ + + mbedtls_mpi xm1; /**< My private key 1 C: x1, S: x3 */ + mbedtls_mpi xm2; /**< My private key 2 C: x2, S: x4 */ + + mbedtls_mpi s; /**< Pre-shared secret (passphrase) */ +} mbedtls_ecjpake_context; + +#else /* MBEDTLS_ECJPAKE_ALT */ +#include "ecjpake_alt.h" +#endif /* MBEDTLS_ECJPAKE_ALT */ + +/** + * \brief Initialize an ECJPAKE context. + * + * \param ctx The ECJPAKE context to initialize. + * This must not be \c NULL. + */ +void mbedtls_ecjpake_init( mbedtls_ecjpake_context *ctx ); + +/** + * \brief Set up an ECJPAKE context for use. + * + * \note Currently the only values for hash/curve allowed by the + * standard are #MBEDTLS_MD_SHA256/#MBEDTLS_ECP_DP_SECP256R1. + * + * \param ctx The ECJPAKE context to set up. This must be initialized. + * \param role The role of the caller. This must be either + * #MBEDTLS_ECJPAKE_CLIENT or #MBEDTLS_ECJPAKE_SERVER. + * \param hash The identifier of the hash function to use, + * for example #MBEDTLS_MD_SHA256. + * \param curve The identifier of the elliptic curve to use, + * for example #MBEDTLS_ECP_DP_SECP256R1. + * \param secret The pre-shared secret (passphrase). This must be + * a readable buffer of length \p len Bytes. It need + * only be valid for the duration of this call. + * \param len The length of the pre-shared secret \p secret. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx, + mbedtls_ecjpake_role role, + mbedtls_md_type_t hash, + mbedtls_ecp_group_id curve, + const unsigned char *secret, + size_t len ); + +/** + * \brief Check if an ECJPAKE context is ready for use. + * + * \param ctx The ECJPAKE context to check. This must be + * initialized. + * + * \return \c 0 if the context is ready for use. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA otherwise. + */ +int mbedtls_ecjpake_check( const mbedtls_ecjpake_context *ctx ); + +/** + * \brief Generate and write the first round message + * (TLS: contents of the Client/ServerHello extension, + * excluding extension type and length bytes). + * + * \param ctx The ECJPAKE context to use. This must be + * initialized and set up. + * \param buf The buffer to write the contents to. This must be a + * writable buffer of length \p len Bytes. + * \param len The length of \p buf in Bytes. + * \param olen The address at which to store the total number + * of Bytes written to \p buf. This must not be \c NULL. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This + * may be \c NULL if \p f_rng doesn't use a context. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Read and process the first round message + * (TLS: contents of the Client/ServerHello extension, + * excluding extension type and length bytes). + * + * \param ctx The ECJPAKE context to use. This must be initialized + * and set up. + * \param buf The buffer holding the first round message. This must + * be a readable buffer of length \p len Bytes. + * \param len The length in Bytes of \p buf. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len ); + +/** + * \brief Generate and write the second round message + * (TLS: contents of the Client/ServerKeyExchange). + * + * \param ctx The ECJPAKE context to use. This must be initialized, + * set up, and already have performed round one. + * \param buf The buffer to write the round two contents to. + * This must be a writable buffer of length \p len Bytes. + * \param len The size of \p buf in Bytes. + * \param olen The address at which to store the total number of Bytes + * written to \p buf. This must not be \c NULL. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This + * may be \c NULL if \p f_rng doesn't use a context. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Read and process the second round message + * (TLS: contents of the Client/ServerKeyExchange). + * + * \param ctx The ECJPAKE context to use. This must be initialized + * and set up and already have performed round one. + * \param buf The buffer holding the second round message. This must + * be a readable buffer of length \p len Bytes. + * \param len The length in Bytes of \p buf. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len ); + +/** + * \brief Derive the shared secret + * (TLS: Pre-Master Secret). + * + * \param ctx The ECJPAKE context to use. This must be initialized, + * set up and have performed both round one and two. + * \param buf The buffer to write the derived secret to. This must + * be a writable buffer of length \p len Bytes. + * \param len The length of \p buf in Bytes. + * \param olen The address at which to store the total number of Bytes + * written to \p buf. This must not be \c NULL. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This + * may be \c NULL if \p f_rng doesn't use a context. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This clears an ECJPAKE context and frees any + * embedded data structure. + * + * \param ctx The ECJPAKE context to free. This may be \c NULL, + * in which case this function does nothing. If it is not + * \c NULL, it must point to an initialized ECJPAKE context. + */ +void mbedtls_ecjpake_free( mbedtls_ecjpake_context *ctx ); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_ecjpake_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + + +#endif /* ecjpake.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecp.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecp.h new file mode 100644 index 000000000..3899291a8 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecp.h @@ -0,0 +1,1173 @@ +/** + * \file ecp.h + * + * \brief This file provides an API for Elliptic Curves over GF(P) (ECP). + * + * The use of ECP in cryptography and TLS is defined in + * Standards for Efficient Cryptography Group (SECG): SEC1 + * Elliptic Curve Cryptography and + * RFC-4492: Elliptic Curve Cryptography (ECC) Cipher Suites + * for Transport Layer Security (TLS). + * + * RFC-2409: The Internet Key Exchange (IKE) defines ECP + * group types. + * + */ + +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_ECP_H +#define MBEDTLS_ECP_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "bignum.h" + +/* + * ECP error codes + */ +#define MBEDTLS_ERR_ECP_BAD_INPUT_DATA -0x4F80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL -0x4F00 /**< The buffer is too small to write to. */ +#define MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE -0x4E80 /**< The requested feature is not available, for example, the requested curve is not supported. */ +#define MBEDTLS_ERR_ECP_VERIFY_FAILED -0x4E00 /**< The signature is not valid. */ +#define MBEDTLS_ERR_ECP_ALLOC_FAILED -0x4D80 /**< Memory allocation failed. */ +#define MBEDTLS_ERR_ECP_RANDOM_FAILED -0x4D00 /**< Generation of random value, such as ephemeral key, failed. */ +#define MBEDTLS_ERR_ECP_INVALID_KEY -0x4C80 /**< Invalid private or public key. */ +#define MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH -0x4C00 /**< The buffer contains a valid signature followed by more data. */ + +/* MBEDTLS_ERR_ECP_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_ECP_HW_ACCEL_FAILED -0x4B80 /**< The ECP hardware accelerator failed. */ + +#define MBEDTLS_ERR_ECP_IN_PROGRESS -0x4B00 /**< Operation in progress, call again with the same parameters to continue. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Domain-parameter identifiers: curve, subgroup, and generator. + * + * \note Only curves over prime fields are supported. + * + * \warning This library does not support validation of arbitrary domain + * parameters. Therefore, only standardized domain parameters from trusted + * sources should be used. See mbedtls_ecp_group_load(). + */ +typedef enum +{ + MBEDTLS_ECP_DP_NONE = 0, /*!< Curve not defined. */ + MBEDTLS_ECP_DP_SECP192R1, /*!< Domain parameters for the 192-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_SECP224R1, /*!< Domain parameters for the 224-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_SECP256R1, /*!< Domain parameters for the 256-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_SECP384R1, /*!< Domain parameters for the 384-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_SECP521R1, /*!< Domain parameters for the 521-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_BP256R1, /*!< Domain parameters for 256-bit Brainpool curve. */ + MBEDTLS_ECP_DP_BP384R1, /*!< Domain parameters for 384-bit Brainpool curve. */ + MBEDTLS_ECP_DP_BP512R1, /*!< Domain parameters for 512-bit Brainpool curve. */ + MBEDTLS_ECP_DP_CURVE25519, /*!< Domain parameters for Curve25519. */ + MBEDTLS_ECP_DP_SECP192K1, /*!< Domain parameters for 192-bit "Koblitz" curve. */ + MBEDTLS_ECP_DP_SECP224K1, /*!< Domain parameters for 224-bit "Koblitz" curve. */ + MBEDTLS_ECP_DP_SECP256K1, /*!< Domain parameters for 256-bit "Koblitz" curve. */ + MBEDTLS_ECP_DP_CURVE448, /*!< Domain parameters for Curve448. */ +} mbedtls_ecp_group_id; + +/** + * The number of supported curves, plus one for #MBEDTLS_ECP_DP_NONE. + * + * \note Montgomery curves are currently excluded. + */ +#define MBEDTLS_ECP_DP_MAX 12 + +/* + * Curve types + */ +typedef enum +{ + MBEDTLS_ECP_TYPE_NONE = 0, + MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS, /* y^2 = x^3 + a x + b */ + MBEDTLS_ECP_TYPE_MONTGOMERY, /* y^2 = x^3 + a x^2 + x */ +} mbedtls_ecp_curve_type; + +/** + * Curve information, for use by other modules. + */ +typedef struct mbedtls_ecp_curve_info +{ + mbedtls_ecp_group_id grp_id; /*!< An internal identifier. */ + uint16_t tls_id; /*!< The TLS NamedCurve identifier. */ + uint16_t bit_size; /*!< The curve size in bits. */ + const char *name; /*!< A human-friendly name. */ +} mbedtls_ecp_curve_info; + +/** + * \brief The ECP point structure, in Jacobian coordinates. + * + * \note All functions expect and return points satisfying + * the following condition: Z == 0 or + * Z == 1. Other values of \p Z are + * used only by internal functions. + * The point is zero, or "at infinity", if Z == 0. + * Otherwise, \p X and \p Y are its standard (affine) + * coordinates. + */ +typedef struct mbedtls_ecp_point +{ + mbedtls_mpi X; /*!< The X coordinate of the ECP point. */ + mbedtls_mpi Y; /*!< The Y coordinate of the ECP point. */ + mbedtls_mpi Z; /*!< The Z coordinate of the ECP point. */ +} +mbedtls_ecp_point; + +#if !defined(MBEDTLS_ECP_ALT) +/* + * default mbed TLS elliptic curve arithmetic implementation + * + * (in case MBEDTLS_ECP_ALT is defined then the developer has to provide an + * alternative implementation for the whole module and it will replace this + * one.) + */ + +/** + * \brief The ECP group structure. + * + * We consider two types of curve equations: + *
  • Short Weierstrass: y^2 = x^3 + A x + B mod P + * (SEC1 + RFC-4492)
  • + *
  • Montgomery: y^2 = x^3 + A x^2 + x mod P (Curve25519, + * Curve448)
+ * In both cases, the generator (\p G) for a prime-order subgroup is fixed. + * + * For Short Weierstrass, this subgroup is the whole curve, and its + * cardinality is denoted by \p N. Our code requires that \p N is an + * odd prime as mbedtls_ecp_mul() requires an odd number, and + * mbedtls_ecdsa_sign() requires that it is prime for blinding purposes. + * + * For Montgomery curves, we do not store \p A, but (A + 2) / 4, + * which is the quantity used in the formulas. Additionally, \p nbits is + * not the size of \p N but the required size for private keys. + * + * If \p modp is NULL, reduction modulo \p P is done using a generic algorithm. + * Otherwise, \p modp must point to a function that takes an \p mbedtls_mpi in the + * range of 0..2^(2*pbits)-1, and transforms it in-place to an integer + * which is congruent mod \p P to the given MPI, and is close enough to \p pbits + * in size, so that it may be efficiently brought in the 0..P-1 range by a few + * additions or subtractions. Therefore, it is only an approximative modular + * reduction. It must return 0 on success and non-zero on failure. + * + * \note Alternative implementations must keep the group IDs distinct. If + * two group structures have the same ID, then they must be + * identical. + * + */ +typedef struct mbedtls_ecp_group +{ + mbedtls_ecp_group_id id; /*!< An internal group identifier. */ + mbedtls_mpi P; /*!< The prime modulus of the base field. */ + mbedtls_mpi A; /*!< For Short Weierstrass: \p A in the equation. For + Montgomery curves: (A + 2) / 4. */ + mbedtls_mpi B; /*!< For Short Weierstrass: \p B in the equation. + For Montgomery curves: unused. */ + mbedtls_ecp_point G; /*!< The generator of the subgroup used. */ + mbedtls_mpi N; /*!< The order of \p G. */ + size_t pbits; /*!< The number of bits in \p P.*/ + size_t nbits; /*!< For Short Weierstrass: The number of bits in \p P. + For Montgomery curves: the number of bits in the + private keys. */ + unsigned int h; /*!< \internal 1 if the constants are static. */ + int (*modp)(mbedtls_mpi *); /*!< The function for fast pseudo-reduction + mod \p P (see above).*/ + int (*t_pre)(mbedtls_ecp_point *, void *); /*!< Unused. */ + int (*t_post)(mbedtls_ecp_point *, void *); /*!< Unused. */ + void *t_data; /*!< Unused. */ + mbedtls_ecp_point *T; /*!< Pre-computed points for ecp_mul_comb(). */ + size_t T_size; /*!< The number of pre-computed points. */ +} +mbedtls_ecp_group; + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h, or define them using the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_ECP_MAX_BITS) +/** + * The maximum size of the groups, that is, of \c N and \c P. + */ +#define MBEDTLS_ECP_MAX_BITS 521 /**< The maximum size of groups, in bits. */ +#endif + +#define MBEDTLS_ECP_MAX_BYTES ( ( MBEDTLS_ECP_MAX_BITS + 7 ) / 8 ) +#define MBEDTLS_ECP_MAX_PT_LEN ( 2 * MBEDTLS_ECP_MAX_BYTES + 1 ) + +#if !defined(MBEDTLS_ECP_WINDOW_SIZE) +/* + * Maximum "window" size used for point multiplication. + * Default: 6. + * Minimum value: 2. Maximum value: 7. + * + * Result is an array of at most ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) ) + * points used for point multiplication. This value is directly tied to EC + * peak memory usage, so decreasing it by one should roughly cut memory usage + * by two (if large curves are in use). + * + * Reduction in size may reduce speed, but larger curves are impacted first. + * Sample performances (in ECDHE handshakes/s, with FIXED_POINT_OPTIM = 1): + * w-size: 6 5 4 3 2 + * 521 145 141 135 120 97 + * 384 214 209 198 177 146 + * 256 320 320 303 262 226 + * 224 475 475 453 398 342 + * 192 640 640 633 587 476 + */ +#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< The maximum window size used. */ +#endif /* MBEDTLS_ECP_WINDOW_SIZE */ + +#if !defined(MBEDTLS_ECP_FIXED_POINT_OPTIM) +/* + * Trade memory for speed on fixed-point multiplication. + * + * This speeds up repeated multiplication of the generator (that is, the + * multiplication in ECDSA signatures, and half of the multiplications in + * ECDSA verification and ECDHE) by a factor roughly 3 to 4. + * + * The cost is increasing EC peak memory usage by a factor roughly 2. + * + * Change this value to 0 to reduce peak memory usage. + */ +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up. */ +#endif /* MBEDTLS_ECP_FIXED_POINT_OPTIM */ + +/* \} name SECTION: Module settings */ + +#else /* MBEDTLS_ECP_ALT */ +#include "ecp_alt.h" +#endif /* MBEDTLS_ECP_ALT */ + +#if defined(MBEDTLS_ECP_RESTARTABLE) + +/** + * \brief Internal restart context for multiplication + * + * \note Opaque struct + */ +typedef struct mbedtls_ecp_restart_mul mbedtls_ecp_restart_mul_ctx; + +/** + * \brief Internal restart context for ecp_muladd() + * + * \note Opaque struct + */ +typedef struct mbedtls_ecp_restart_muladd mbedtls_ecp_restart_muladd_ctx; + +/** + * \brief General context for resuming ECC operations + */ +typedef struct +{ + unsigned ops_done; /*!< current ops count */ + unsigned depth; /*!< call depth (0 = top-level) */ + mbedtls_ecp_restart_mul_ctx *rsm; /*!< ecp_mul_comb() sub-context */ + mbedtls_ecp_restart_muladd_ctx *ma; /*!< ecp_muladd() sub-context */ +} mbedtls_ecp_restart_ctx; + +/* + * Operation counts for restartable functions + */ +#define MBEDTLS_ECP_OPS_CHK 3 /*!< basic ops count for ecp_check_pubkey() */ +#define MBEDTLS_ECP_OPS_DBL 8 /*!< basic ops count for ecp_double_jac() */ +#define MBEDTLS_ECP_OPS_ADD 11 /*!< basic ops count for see ecp_add_mixed() */ +#define MBEDTLS_ECP_OPS_INV 120 /*!< empirical equivalent for mpi_mod_inv() */ + +/** + * \brief Internal; for restartable functions in other modules. + * Check and update basic ops budget. + * + * \param grp Group structure + * \param rs_ctx Restart context + * \param ops Number of basic ops to do + * + * \return \c 0 if doing \p ops basic ops is still allowed, + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS otherwise. + */ +int mbedtls_ecp_check_budget( const mbedtls_ecp_group *grp, + mbedtls_ecp_restart_ctx *rs_ctx, + unsigned ops ); + +/* Utility macro for checking and updating ops budget */ +#define MBEDTLS_ECP_BUDGET( ops ) \ + MBEDTLS_MPI_CHK( mbedtls_ecp_check_budget( grp, rs_ctx, \ + (unsigned) (ops) ) ); + +#else /* MBEDTLS_ECP_RESTARTABLE */ + +#define MBEDTLS_ECP_BUDGET( ops ) /* no-op; for compatibility */ + +/* We want to declare restartable versions of existing functions anyway */ +typedef void mbedtls_ecp_restart_ctx; + +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +/** + * \brief The ECP key-pair structure. + * + * A generic key-pair that may be used for ECDSA and fixed ECDH, for example. + * + * \note Members are deliberately in the same order as in the + * ::mbedtls_ecdsa_context structure. + */ +typedef struct mbedtls_ecp_keypair +{ + mbedtls_ecp_group grp; /*!< Elliptic curve and base point */ + mbedtls_mpi d; /*!< our secret value */ + mbedtls_ecp_point Q; /*!< our public value */ +} +mbedtls_ecp_keypair; + +/* + * Point formats, from RFC 4492's enum ECPointFormat + */ +#define MBEDTLS_ECP_PF_UNCOMPRESSED 0 /**< Uncompressed point format. */ +#define MBEDTLS_ECP_PF_COMPRESSED 1 /**< Compressed point format. */ + +/* + * Some other constants from RFC 4492 + */ +#define MBEDTLS_ECP_TLS_NAMED_CURVE 3 /**< The named_curve of ECCurveType. */ + +#if defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Set the maximum number of basic operations done in a row. + * + * If more operations are needed to complete a computation, + * #MBEDTLS_ERR_ECP_IN_PROGRESS will be returned by the + * function performing the computation. It is then the + * caller's responsibility to either call again with the same + * parameters until it returns 0 or an error code; or to free + * the restart context if the operation is to be aborted. + * + * It is strictly required that all input parameters and the + * restart context be the same on successive calls for the + * same operation, but output parameters need not be the + * same; they must not be used until the function finally + * returns 0. + * + * This only applies to functions whose documentation + * mentions they may return #MBEDTLS_ERR_ECP_IN_PROGRESS (or + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS for functions in the + * SSL module). For functions that accept a "restart context" + * argument, passing NULL disables restart and makes the + * function equivalent to the function with the same name + * with \c _restartable removed. For functions in the ECDH + * module, restart is disabled unless the function accepts + * an "ECDH context" argument and + * mbedtls_ecdh_enable_restart() was previously called on + * that context. For function in the SSL module, restart is + * only enabled for specific sides and key exchanges + * (currently only for clients and ECDHE-ECDSA). + * + * \param max_ops Maximum number of basic operations done in a row. + * Default: 0 (unlimited). + * Lower (non-zero) values mean ECC functions will block for + * a lesser maximum amount of time. + * + * \note A "basic operation" is defined as a rough equivalent of a + * multiplication in GF(p) for the NIST P-256 curve. + * As an indication, with default settings, a scalar + * multiplication (full run of \c mbedtls_ecp_mul()) is: + * - about 3300 basic operations for P-256 + * - about 9400 basic operations for P-384 + * + * \note Very low values are not always respected: sometimes + * functions need to block for a minimum number of + * operations, and will do so even if max_ops is set to a + * lower value. That minimum depends on the curve size, and + * can be made lower by decreasing the value of + * \c MBEDTLS_ECP_WINDOW_SIZE. As an indication, here is the + * lowest effective value for various curves and values of + * that parameter (w for short): + * w=6 w=5 w=4 w=3 w=2 + * P-256 208 208 160 136 124 + * P-384 682 416 320 272 248 + * P-521 1364 832 640 544 496 + * + * \note This setting is currently ignored by Curve25519. + */ +void mbedtls_ecp_set_max_ops( unsigned max_ops ); + +/** + * \brief Check if restart is enabled (max_ops != 0) + * + * \return \c 0 if \c max_ops == 0 (restart disabled) + * \return \c 1 otherwise (restart enabled) + */ +int mbedtls_ecp_restart_is_enabled( void ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +/* + * Get the type of a curve + */ +mbedtls_ecp_curve_type mbedtls_ecp_get_type( const mbedtls_ecp_group *grp ); + +/** + * \brief This function retrieves the information defined in + * mbedtls_ecp_curve_info() for all supported curves in order + * of preference. + * + * \return A statically allocated array. The last entry is 0. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list( void ); + +/** + * \brief This function retrieves the list of internal group + * identifiers of all supported curves in the order of + * preference. + * + * \return A statically allocated array, + * terminated with MBEDTLS_ECP_DP_NONE. + */ +const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list( void ); + +/** + * \brief This function retrieves curve information from an internal + * group identifier. + * + * \param grp_id An \c MBEDTLS_ECP_DP_XXX value. + * + * \return The associated curve information on success. + * \return NULL on failure. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id( mbedtls_ecp_group_id grp_id ); + +/** + * \brief This function retrieves curve information from a TLS + * NamedCurve value. + * + * \param tls_id An \c MBEDTLS_ECP_DP_XXX value. + * + * \return The associated curve information on success. + * \return NULL on failure. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id( uint16_t tls_id ); + +/** + * \brief This function retrieves curve information from a + * human-readable name. + * + * \param name The human-readable name. + * + * \return The associated curve information on success. + * \return NULL on failure. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name ); + +/** + * \brief This function initializes a point as zero. + * + * \param pt The point to initialize. + */ +void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ); + +/** + * \brief This function initializes an ECP group context + * without loading any domain parameters. + * + * \note After this function is called, domain parameters + * for various ECP groups can be loaded through the + * mbedtls_ecp_group_load() or mbedtls_ecp_tls_read_group() + * functions. + */ +void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ); + +/** + * \brief This function initializes a key pair as an invalid one. + * + * \param key The key pair to initialize. + */ +void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key ); + +/** + * \brief This function frees the components of a point. + * + * \param pt The point to free. + */ +void mbedtls_ecp_point_free( mbedtls_ecp_point *pt ); + +/** + * \brief This function frees the components of an ECP group. + * + * \param grp The group to free. This may be \c NULL, in which + * case this function returns immediately. If it is not + * \c NULL, it must point to an initialized ECP group. + */ +void mbedtls_ecp_group_free( mbedtls_ecp_group *grp ); + +/** + * \brief This function frees the components of a key pair. + * + * \param key The key pair to free. This may be \c NULL, in which + * case this function returns immediately. If it is not + * \c NULL, it must point to an initialized ECP key pair. + */ +void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Initialize a restart context. + * + * \param ctx The restart context to initialize. This must + * not be \c NULL. + */ +void mbedtls_ecp_restart_init( mbedtls_ecp_restart_ctx *ctx ); + +/** + * \brief Free the components of a restart context. + * + * \param ctx The restart context to free. This may be \c NULL, in which + * case this function returns immediately. If it is not + * \c NULL, it must point to an initialized restart context. + */ +void mbedtls_ecp_restart_free( mbedtls_ecp_restart_ctx *ctx ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +/** + * \brief This function copies the contents of point \p Q into + * point \p P. + * + * \param P The destination point. This must be initialized. + * \param Q The source point. This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code for other kinds of failure. + */ +int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ); + +/** + * \brief This function copies the contents of group \p src into + * group \p dst. + * + * \param dst The destination group. This must be initialized. + * \param src The source group. This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, + const mbedtls_ecp_group *src ); + +/** + * \brief This function sets a point to the point at infinity. + * + * \param pt The point to set. This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ); + +/** + * \brief This function checks if a point is the point at infinity. + * + * \param pt The point to test. This must be initialized. + * + * \return \c 1 if the point is zero. + * \return \c 0 if the point is non-zero. + * \return A negative error code on failure. + */ +int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ); + +/** + * \brief This function compares two points. + * + * \note This assumes that the points are normalized. Otherwise, + * they may compare as "not equal" even if they are. + * + * \param P The first point to compare. This must be initialized. + * \param Q The second point to compare. This must be initialized. + * + * \return \c 0 if the points are equal. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the points are not equal. + */ +int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ); + +/** + * \brief This function imports a non-zero point from two ASCII + * strings. + * + * \param P The destination point. This must be initialized. + * \param radix The numeric base of the input. + * \param x The first affine coordinate, as a null-terminated string. + * \param y The second affine coordinate, as a null-terminated string. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_MPI_XXX error code on failure. + */ +int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix, + const char *x, const char *y ); + +/** + * \brief This function exports a point into unsigned binary data. + * + * \param grp The group to which the point should belong. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param P The point to export. This must be initialized. + * \param format The point format. This must be either + * #MBEDTLS_ECP_PF_COMPRESSED or #MBEDTLS_ECP_PF_UNCOMPRESSED. + * (For groups without these formats, this parameter is + * ignored. But it still has to be either of the above + * values.) + * \param olen The address at which to store the length of + * the output in Bytes. This must not be \c NULL. + * \param buf The output buffer. This must be a writable buffer + * of length \p buflen Bytes. + * \param buflen The length of the output buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the output buffer + * is too small to hold the point. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format + * or the export for the given group is not implemented. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *P, + int format, size_t *olen, + unsigned char *buf, size_t buflen ); + +/** + * \brief This function imports a point from unsigned binary data. + * + * \note This function does not check that the point actually + * belongs to the given group, see mbedtls_ecp_check_pubkey() + * for that. + * + * \param grp The group to which the point should belong. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param P The destination context to import the point to. + * This must be initialized. + * \param buf The input buffer. This must be a readable buffer + * of length \p ilen Bytes. + * \param ilen The length of the input buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the input is invalid. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the import for the + * given group is not implemented. + */ +int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *P, + const unsigned char *buf, size_t ilen ); + +/** + * \brief This function imports a point from a TLS ECPoint record. + * + * \note On function return, \p *buf is updated to point immediately + * after the ECPoint record. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param pt The destination point. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization + * failure. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + */ +int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, + const unsigned char **buf, size_t len ); + +/** + * \brief This function exports a point as a TLS ECPoint record + * defined in RFC 4492, Section 5.4. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param pt The point to be exported. This must be initialized. + * \param format The point format to use. This must be either + * #MBEDTLS_ECP_PF_COMPRESSED or #MBEDTLS_ECP_PF_UNCOMPRESSED. + * \param olen The address at which to store the length in Bytes + * of the data written. + * \param buf The target buffer. This must be a writable buffer of + * length \p blen Bytes. + * \param blen The length of the target buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the input is invalid. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the target buffer + * is too small to hold the exported point. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen ); + +/** + * \brief This function sets up an ECP group context + * from a standardized set of domain parameters. + * + * \note The index should be a value of the NamedCurve enum, + * as defined in RFC-4492: Elliptic Curve Cryptography + * (ECC) Cipher Suites for Transport Layer Security (TLS), + * usually in the form of an \c MBEDTLS_ECP_DP_XXX macro. + * + * \param grp The group context to setup. This must be initialized. + * \param id The identifier of the domain parameter set to load. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if \p id doesn't + * correspond to a known group. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ); + +/** + * \brief This function sets up an ECP group context from a TLS + * ECParameters record as defined in RFC 4492, Section 5.4. + * + * \note The read pointer \p buf is updated to point right after + * the ECParameters record on exit. + * + * \param grp The group context to setup. This must be initialized. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the input buffer \c *buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the group is not + * recognized. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, + const unsigned char **buf, size_t len ); + +/** + * \brief This function extracts an elliptic curve group ID from a + * TLS ECParameters record as defined in RFC 4492, Section 5.4. + * + * \note The read pointer \p buf is updated to point right after + * the ECParameters record on exit. + * + * \param grp The address at which to store the group id. + * This must not be \c NULL. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the input buffer \c *buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the group is not + * recognized. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_read_group_id( mbedtls_ecp_group_id *grp, + const unsigned char **buf, + size_t len ); +/** + * \brief This function exports an elliptic curve as a TLS + * ECParameters record as defined in RFC 4492, Section 5.4. + * + * \param grp The ECP group to be exported. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param olen The address at which to store the number of Bytes written. + * This must not be \c NULL. + * \param buf The buffer to write to. This must be a writable buffer + * of length \p blen Bytes. + * \param blen The length of the output buffer \p buf in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the output + * buffer is too small to hold the exported group. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, + size_t *olen, + unsigned char *buf, size_t blen ); + +/** + * \brief This function performs a scalar multiplication of a point + * by an integer: \p R = \p m * \p P. + * + * It is not thread-safe to use same group in multiple threads. + * + * \note To prevent timing attacks, this function + * executes the exact same sequence of base-field + * operations for any valid \p m. It avoids any if-branch or + * array index depending on the value of \p m. + * + * \note If \p f_rng is not NULL, it is used to randomize + * intermediate results to prevent potential timing attacks + * targeting these results. We recommend always providing + * a non-NULL \p f_rng. The overhead is negligible. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param R The point in which to store the result of the calculation. + * This must be initialized. + * \param m The integer by which to multiply. This must be initialized. + * \param P The point to multiply. This must be initialized. + * \param f_rng The RNG function. This may be \c NULL if randomization + * of intermediate results isn't desired (discouraged). + * \param p_rng The RNG context to be passed to \p p_rng. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m is not a valid private + * key, or \p P is not a valid public key. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief This function performs multiplication of a point by + * an integer: \p R = \p m * \p P in a restartable way. + * + * \see mbedtls_ecp_mul() + * + * \note This function does the same as \c mbedtls_ecp_mul(), but + * it can return early and restart according to the limit set + * with \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param R The point in which to store the result of the calculation. + * This must be initialized. + * \param m The integer by which to multiply. This must be initialized. + * \param P The point to multiply. This must be initialized. + * \param f_rng The RNG function. This may be \c NULL if randomization + * of intermediate results isn't desired (discouraged). + * \param p_rng The RNG context to be passed to \p p_rng. + * \param rs_ctx The restart context (NULL disables restart). + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m is not a valid private + * key, or \p P is not a valid public key. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_mul_restartable( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx ); + +/** + * \brief This function performs multiplication and addition of two + * points by integers: \p R = \p m * \p P + \p n * \p Q + * + * It is not thread-safe to use same group in multiple threads. + * + * \note In contrast to mbedtls_ecp_mul(), this function does not + * guarantee a constant execution flow and timing. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param R The point in which to store the result of the calculation. + * This must be initialized. + * \param m The integer by which to multiply \p P. + * This must be initialized. + * \param P The point to multiply by \p m. This must be initialized. + * \param n The integer by which to multiply \p Q. + * This must be initialized. + * \param Q The point to be multiplied by \p n. + * This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m or \p n are not + * valid private keys, or \p P or \p Q are not valid public + * keys. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q ); + +/** + * \brief This function performs multiplication and addition of two + * points by integers: \p R = \p m * \p P + \p n * \p Q in a + * restartable way. + * + * \see \c mbedtls_ecp_muladd() + * + * \note This function works the same as \c mbedtls_ecp_muladd(), + * but it can return early and restart according to the limit + * set with \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \param grp The ECP group to use. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param R The point in which to store the result of the calculation. + * This must be initialized. + * \param m The integer by which to multiply \p P. + * This must be initialized. + * \param P The point to multiply by \p m. This must be initialized. + * \param n The integer by which to multiply \p Q. + * This must be initialized. + * \param Q The point to be multiplied by \p n. + * This must be initialized. + * \param rs_ctx The restart context (NULL disables restart). + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m or \p n are not + * valid private keys, or \p P or \p Q are not valid public + * keys. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_muladd_restartable( + mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q, + mbedtls_ecp_restart_ctx *rs_ctx ); + +/** + * \brief This function checks that a point is a valid public key + * on this curve. + * + * It only checks that the point is non-zero, has + * valid coordinates and lies on the curve. It does not verify + * that it is indeed a multiple of \p G. This additional + * check is computationally more expensive, is not required + * by standards, and should not be necessary if the group + * used has a small cofactor. In particular, it is useless for + * the NIST groups which all have a cofactor of 1. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure, to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The ECP group the point should belong to. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param pt The point to check. This must be initialized. + * + * \return \c 0 if the point is a valid public key. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if the point is not + * a valid public key for the given curve. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *pt ); + +/** + * \brief This function checks that an \p mbedtls_mpi is a + * valid private key for this curve. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The ECP group the private key should belong to. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param d The integer to check. This must be initialized. + * + * \return \c 0 if the point is a valid private key. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if the point is not a valid + * private key for the given curve. + * \return Another negative error code on other kinds of failure. + */ +int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, + const mbedtls_mpi *d ); + +/** + * \brief This function generates a private key. + * + * \param grp The ECP group to generate a private key for. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param d The destination MPI (secret part). This must be initialized. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG parameter to be passed to \p f_rng. This may be + * \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. + */ +int mbedtls_ecp_gen_privkey( const mbedtls_ecp_group *grp, + mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function generates a keypair with a configurable base + * point. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The ECP group to generate a key pair for. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param G The base point to use. This must be initialized + * and belong to \p grp. It replaces the default base + * point \c grp->G used by mbedtls_ecp_gen_keypair(). + * \param d The destination MPI (secret part). + * This must be initialized. + * \param Q The destination point (public part). + * This must be initialized. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. + */ +int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function generates an ECP keypair. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The ECP group to generate a key pair for. + * This must be initialized and have group parameters + * set, for example through mbedtls_ecp_group_load(). + * \param d The destination MPI (secret part). + * This must be initialized. + * \param Q The destination point (public part). + * This must be initialized. + * \param f_rng The RNG function. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. + */ +int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, mbedtls_mpi *d, + mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function generates an ECP key. + * + * \param grp_id The ECP group identifier. + * \param key The destination key. This must be initialized. + * \param f_rng The RNG function to use. This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng doesn't need a context argument. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. + */ +int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function reads an elliptic curve private key. + * + * \param grp_id The ECP group identifier. + * \param key The destination key. + * \param buf The the buffer containing the binary representation of the + * key. (Big endian integer for Weierstrass curves, byte + * string for Montgomery curves.) + * \param buflen The length of the buffer in bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY error if the key is + * invalid. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the operation for + * the group is not implemented. + * \return Another negative error code on different kinds of failure. + */ +int mbedtls_ecp_read_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + const unsigned char *buf, size_t buflen ); +/** + * \brief This function checks that the keypair objects + * \p pub and \p prv have the same group and the + * same public point, and that the private key in + * \p prv is consistent with the public key. + * + * \param pub The keypair structure holding the public key. This + * must be initialized. If it contains a private key, that + * part is ignored. + * \param prv The keypair structure holding the full keypair. + * This must be initialized. + * + * \return \c 0 on success, meaning that the keys are valid and match. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the keys are invalid or do not match. + * \return An \c MBEDTLS_ERR_ECP_XXX or an \c MBEDTLS_ERR_MPI_XXX + * error code on calculation failure. + */ +int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, + const mbedtls_ecp_keypair *prv ); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief The ECP checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_ecp_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* ecp.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecp_internal.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecp_internal.h new file mode 100644 index 000000000..65f9fdac4 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ecp_internal.h @@ -0,0 +1,299 @@ +/** + * \file ecp_internal.h + * + * \brief Function declarations for alternative implementation of elliptic curve + * point arithmetic. + */ +/* + * Copyright (C) 2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * [1] BERNSTEIN, Daniel J. Curve25519: new Diffie-Hellman speed records. + * + * + * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis + * for elliptic curve cryptosystems. In : Cryptographic Hardware and + * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302. + * + * + * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to + * render ECC resistant against Side Channel Attacks. IACR Cryptology + * ePrint Archive, 2004, vol. 2004, p. 342. + * + * + * [4] Certicom Research. SEC 2: Recommended Elliptic Curve Domain Parameters. + * + * + * [5] HANKERSON, Darrel, MENEZES, Alfred J., VANSTONE, Scott. Guide to Elliptic + * Curve Cryptography. + * + * [6] Digital Signature Standard (DSS), FIPS 186-4. + * + * + * [7] Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer + * Security (TLS), RFC 4492. + * + * + * [8] + * + * [9] COHEN, Henri. A Course in Computational Algebraic Number Theory. + * Springer Science & Business Media, 1 Aug 2000 + */ + +#ifndef MBEDTLS_ECP_INTERNAL_H +#define MBEDTLS_ECP_INTERNAL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + +/** + * \brief Indicate if the Elliptic Curve Point module extension can + * handle the group. + * + * \param grp The pointer to the elliptic curve group that will be the + * basis of the cryptographic computations. + * + * \return Non-zero if successful. + */ +unsigned char mbedtls_internal_ecp_grp_capable( const mbedtls_ecp_group *grp ); + +/** + * \brief Initialise the Elliptic Curve Point module extension. + * + * If mbedtls_internal_ecp_grp_capable returns true for a + * group, this function has to be able to initialise the + * module for it. + * + * This module can be a driver to a crypto hardware + * accelerator, for which this could be an initialise function. + * + * \param grp The pointer to the group the module needs to be + * initialised for. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp ); + +/** + * \brief Frees and deallocates the Elliptic Curve Point module + * extension. + * + * \param grp The pointer to the group the module was initialised for. + */ +void mbedtls_internal_ecp_free( const mbedtls_ecp_group *grp ); + +#if defined(ECP_SHORTWEIERSTRASS) + +#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) +/** + * \brief Randomize jacobian coordinates: + * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l. + * + * \param grp Pointer to the group representing the curve. + * + * \param pt The point on the curve to be randomised, given with Jacobian + * coordinates. + * + * \param f_rng A function pointer to the random number generator. + * + * \param p_rng A pointer to the random number generator state. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_randomize_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#endif + +#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) +/** + * \brief Addition: R = P + Q, mixed affine-Jacobian coordinates. + * + * The coordinates of Q must be normalized (= affine), + * but those of P don't need to. R is not normalized. + * + * This function is used only as a subrutine of + * ecp_mul_comb(). + * + * Special cases: (1) P or Q is zero, (2) R is zero, + * (3) P == Q. + * None of these cases can happen as intermediate step in + * ecp_mul_comb(): + * - at each step, P, Q and R are multiples of the base + * point, the factor being less than its order, so none of + * them is zero; + * - Q is an odd multiple of the base point, P an even + * multiple, due to the choice of precomputed points in the + * modified comb method. + * So branches for these cases do not leak secret information. + * + * We accept Q->Z being unset (saving memory in tables) as + * meaning 1. + * + * Cost in field operations if done by [5] 3.22: + * 1A := 8M + 3S + * + * \param grp Pointer to the group representing the curve. + * + * \param R Pointer to a point structure to hold the result. + * + * \param P Pointer to the first summand, given with Jacobian + * coordinates + * + * \param Q Pointer to the second summand, given with affine + * coordinates. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_add_mixed( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ); +#endif + +/** + * \brief Point doubling R = 2 P, Jacobian coordinates. + * + * Cost: 1D := 3M + 4S (A == 0) + * 4M + 4S (A == -3) + * 3M + 6S + 1a otherwise + * when the implementation is based on the "dbl-1998-cmo-2" + * doubling formulas in [8] and standard optimizations are + * applied when curve parameter A is one of { 0, -3 }. + * + * \param grp Pointer to the group representing the curve. + * + * \param R Pointer to a point structure to hold the result. + * + * \param P Pointer to the point that has to be doubled, given with + * Jacobian coordinates. + * + * \return 0 if successful. + */ +#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) +int mbedtls_internal_ecp_double_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, const mbedtls_ecp_point *P ); +#endif + +/** + * \brief Normalize jacobian coordinates of an array of (pointers to) + * points. + * + * Using Montgomery's trick to perform only one inversion mod P + * the cost is: + * 1N(t) := 1I + (6t - 3)M + 1S + * (See for example Algorithm 10.3.4. in [9]) + * + * This function is used only as a subrutine of + * ecp_mul_comb(). + * + * Warning: fails (returning an error) if one of the points is + * zero! + * This should never happen, see choice of w in ecp_mul_comb(). + * + * \param grp Pointer to the group representing the curve. + * + * \param T Array of pointers to the points to normalise. + * + * \param t_len Number of elements in the array. + * + * \return 0 if successful, + * an error if one of the points is zero. + */ +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) +int mbedtls_internal_ecp_normalize_jac_many( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *T[], size_t t_len ); +#endif + +/** + * \brief Normalize jacobian coordinates so that Z == 0 || Z == 1. + * + * Cost in field operations if done by [5] 3.2.1: + * 1N := 1I + 3M + 1S + * + * \param grp Pointer to the group representing the curve. + * + * \param pt pointer to the point to be normalised. This is an + * input/output parameter. + * + * \return 0 if successful. + */ +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) +int mbedtls_internal_ecp_normalize_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt ); +#endif + +#endif /* ECP_SHORTWEIERSTRASS */ + +#if defined(ECP_MONTGOMERY) + +#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) +int mbedtls_internal_ecp_double_add_mxz( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, mbedtls_ecp_point *S, const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q, const mbedtls_mpi *d ); +#endif + +/** + * \brief Randomize projective x/z coordinates: + * (X, Z) -> (l X, l Z) for random l + * + * \param grp pointer to the group representing the curve + * + * \param P the point on the curve to be randomised given with + * projective coordinates. This is an input/output parameter. + * + * \param f_rng a function pointer to the random number generator + * + * \param p_rng a pointer to the random number generator state + * + * \return 0 if successful + */ +#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) +int mbedtls_internal_ecp_randomize_mxz( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *P, int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#endif + +/** + * \brief Normalize Montgomery x/z coordinates: X = X/Z, Z = 1. + * + * \param grp pointer to the group representing the curve + * + * \param P pointer to the point to be normalised. This is an + * input/output parameter. + * + * \return 0 if successful + */ +#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) +int mbedtls_internal_ecp_normalize_mxz( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *P ); +#endif + +#endif /* ECP_MONTGOMERY */ + +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ + +#endif /* ecp_internal.h */ + diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/entropy.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/entropy.h new file mode 100644 index 000000000..d68f69f3f --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/entropy.h @@ -0,0 +1,289 @@ +/** + * \file entropy.h + * + * \brief Entropy accumulator implementation + */ +/* + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ENTROPY_H +#define MBEDTLS_ENTROPY_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_ENTROPY_FORCE_SHA256) +#include "sha512.h" +#define MBEDTLS_ENTROPY_SHA512_ACCUMULATOR +#else +#if defined(MBEDTLS_SHA256_C) +#define MBEDTLS_ENTROPY_SHA256_ACCUMULATOR +#include "sha256.h" +#endif +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +#if defined(MBEDTLS_HAVEGE_C) +#include "havege.h" +#endif + +#define MBEDTLS_ERR_ENTROPY_SOURCE_FAILED -0x003C /**< Critical entropy source failure. */ +#define MBEDTLS_ERR_ENTROPY_MAX_SOURCES -0x003E /**< No more sources can be added. */ +#define MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED -0x0040 /**< No sources have been added to poll. */ +#define MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE -0x003D /**< No strong sources have been added to poll. */ +#define MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR -0x003F /**< Read/write error in file. */ + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_ENTROPY_MAX_SOURCES) +#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +#endif + +#if !defined(MBEDTLS_ENTROPY_MAX_GATHER) +#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ +#endif + +/* \} name SECTION: Module settings */ + +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) +#define MBEDTLS_ENTROPY_BLOCK_SIZE 64 /**< Block size of entropy accumulator (SHA-512) */ +#else +#define MBEDTLS_ENTROPY_BLOCK_SIZE 32 /**< Block size of entropy accumulator (SHA-256) */ +#endif + +#define MBEDTLS_ENTROPY_MAX_SEED_SIZE 1024 /**< Maximum size of seed we read from seed file */ +#define MBEDTLS_ENTROPY_SOURCE_MANUAL MBEDTLS_ENTROPY_MAX_SOURCES + +#define MBEDTLS_ENTROPY_SOURCE_STRONG 1 /**< Entropy source is strong */ +#define MBEDTLS_ENTROPY_SOURCE_WEAK 0 /**< Entropy source is weak */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Entropy poll callback pointer + * + * \param data Callback-specific data pointer + * \param output Data to fill + * \param len Maximum size to provide + * \param olen The actual amount of bytes put into the buffer (Can be 0) + * + * \return 0 if no critical failures occurred, + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED otherwise + */ +typedef int (*mbedtls_entropy_f_source_ptr)(void *data, unsigned char *output, size_t len, + size_t *olen); + +/** + * \brief Entropy source state + */ +typedef struct mbedtls_entropy_source_state +{ + mbedtls_entropy_f_source_ptr f_source; /**< The entropy source callback */ + void * p_source; /**< The callback data pointer */ + size_t size; /**< Amount received in bytes */ + size_t threshold; /**< Minimum bytes required before release */ + int strong; /**< Is the source strong? */ +} +mbedtls_entropy_source_state; + +/** + * \brief Entropy context structure + */ +typedef struct mbedtls_entropy_context +{ + int accumulator_started; +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_context accumulator; +#else + mbedtls_sha256_context accumulator; +#endif + int source_count; + mbedtls_entropy_source_state source[MBEDTLS_ENTROPY_MAX_SOURCES]; +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_state havege_data; +#endif +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; /*!< mutex */ +#endif +#if defined(MBEDTLS_ENTROPY_NV_SEED) + int initial_entropy_run; +#endif +} +mbedtls_entropy_context; + +/** + * \brief Initialize the context + * + * \param ctx Entropy context to initialize + */ +void mbedtls_entropy_init( mbedtls_entropy_context *ctx ); + +/** + * \brief Free the data in the context + * + * \param ctx Entropy context to free + */ +void mbedtls_entropy_free( mbedtls_entropy_context *ctx ); + +/** + * \brief Adds an entropy source to poll + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * \param f_source Entropy function + * \param p_source Function data + * \param threshold Minimum required from source before entropy is released + * ( with mbedtls_entropy_func() ) (in bytes) + * \param strong MBEDTLS_ENTROPY_SOURCE_STRONG or + * MBEDTLS_ENTROPY_SOURCE_WEAK. + * At least one strong source needs to be added. + * Weaker sources (such as the cycle counter) can be used as + * a complement. + * + * \return 0 if successful or MBEDTLS_ERR_ENTROPY_MAX_SOURCES + */ +int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx, + mbedtls_entropy_f_source_ptr f_source, void *p_source, + size_t threshold, int strong ); + +/** + * \brief Trigger an extra gather poll for the accumulator + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * + * \return 0 if successful, or MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_gather( mbedtls_entropy_context *ctx ); + +/** + * \brief Retrieve entropy from the accumulator + * (Maximum length: MBEDTLS_ENTROPY_BLOCK_SIZE) + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param data Entropy context + * \param output Buffer to fill + * \param len Number of bytes desired, must be at most MBEDTLS_ENTROPY_BLOCK_SIZE + * + * \return 0 if successful, or MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_func( void *data, unsigned char *output, size_t len ); + +/** + * \brief Add data to the accumulator manually + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * \param data Data to add + * \param len Length of data + * + * \return 0 if successful + */ +int mbedtls_entropy_update_manual( mbedtls_entropy_context *ctx, + const unsigned char *data, size_t len ); + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +/** + * \brief Trigger an update of the seed file in NV by using the + * current entropy pool. + * + * \param ctx Entropy context + * + * \return 0 if successful + */ +int mbedtls_entropy_update_nv_seed( mbedtls_entropy_context *ctx ); +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Write a seed file + * + * \param ctx Entropy context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR on file error, or + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *path ); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance. No more than MBEDTLS_ENTROPY_MAX_SEED_SIZE bytes are + * read from the seed file. The rest is ignored. + * + * \param ctx Entropy context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR on file error, + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * This module self-test also calls the entropy self-test, + * mbedtls_entropy_source_self_test(); + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_entropy_self_test( int verbose ); + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) +/** + * \brief Checkup routine + * + * Verifies the integrity of the hardware entropy source + * provided by the function 'mbedtls_hardware_poll()'. + * + * Note this is the only hardware entropy source that is known + * at link time, and other entropy sources configured + * dynamically at runtime by the function + * mbedtls_entropy_add_source() will not be tested. + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_entropy_source_self_test( int verbose ); +#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* entropy.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/entropy_poll.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/entropy_poll.h new file mode 100644 index 000000000..edaa9fffe --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/entropy_poll.h @@ -0,0 +1,110 @@ +/** + * \file entropy_poll.h + * + * \brief Platform-specific and custom entropy polling functions + */ +/* + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ENTROPY_POLL_H +#define MBEDTLS_ENTROPY_POLL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Default thresholds for built-in sources, in bytes + */ +#define MBEDTLS_ENTROPY_MIN_PLATFORM 32 /**< Minimum for platform source */ +#define MBEDTLS_ENTROPY_MIN_HAVEGE 32 /**< Minimum for HAVEGE */ +#define MBEDTLS_ENTROPY_MIN_HARDCLOCK 4 /**< Minimum for mbedtls_timing_hardclock() */ +#if !defined(MBEDTLS_ENTROPY_MIN_HARDWARE) +#define MBEDTLS_ENTROPY_MIN_HARDWARE 32 /**< Minimum for the hardware source */ +#endif + +/** + * \brief Entropy poll callback that provides 0 entropy. + */ +#if defined(MBEDTLS_TEST_NULL_ENTROPY) + int mbedtls_null_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) +/** + * \brief Platform-specific entropy poll callback + */ +int mbedtls_platform_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_HAVEGE_C) +/** + * \brief HAVEGE based entropy poll callback + * + * Requires an HAVEGE state as its data pointer. + */ +int mbedtls_havege_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_TIMING_C) +/** + * \brief mbedtls_timing_hardclock-based entropy poll callback + */ +int mbedtls_hardclock_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) +/** + * \brief Entropy poll callback for a hardware source + * + * \warning This is not provided by mbed TLS! + * See \c MBEDTLS_ENTROPY_HARDWARE_ALT in config.h. + * + * \note This must accept NULL as its first argument. + */ +int mbedtls_hardware_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +/** + * \brief Entropy poll callback for a non-volatile seed file + * + * \note This must accept NULL as its first argument. + */ +int mbedtls_nv_seed_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* entropy_poll.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/error.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/error.h new file mode 100644 index 000000000..7664a641f --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/error.h @@ -0,0 +1,129 @@ +/** + * \file error.h + * + * \brief Error to string translation + */ +/* + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ERROR_H +#define MBEDTLS_ERROR_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +/** + * Error code layout. + * + * Currently we try to keep all error codes within the negative space of 16 + * bits signed integers to support all platforms (-0x0001 - -0x7FFF). In + * addition we'd like to give two layers of information on the error if + * possible. + * + * For that purpose the error codes are segmented in the following manner: + * + * 16 bit error code bit-segmentation + * + * 1 bit - Unused (sign bit) + * 3 bits - High level module ID + * 5 bits - Module-dependent error code + * 7 bits - Low level module errors + * + * For historical reasons, low-level error codes are divided in even and odd, + * even codes were assigned first, and -1 is reserved for other errors. + * + * Low-level module errors (0x0002-0x007E, 0x0003-0x007F) + * + * Module Nr Codes assigned + * MPI 7 0x0002-0x0010 + * GCM 3 0x0012-0x0014 0x0013-0x0013 + * BLOWFISH 3 0x0016-0x0018 0x0017-0x0017 + * THREADING 3 0x001A-0x001E + * AES 5 0x0020-0x0022 0x0021-0x0025 + * CAMELLIA 3 0x0024-0x0026 0x0027-0x0027 + * XTEA 2 0x0028-0x0028 0x0029-0x0029 + * BASE64 2 0x002A-0x002C + * OID 1 0x002E-0x002E 0x000B-0x000B + * PADLOCK 1 0x0030-0x0030 + * DES 2 0x0032-0x0032 0x0033-0x0033 + * CTR_DBRG 4 0x0034-0x003A + * ENTROPY 3 0x003C-0x0040 0x003D-0x003F + * NET 13 0x0042-0x0052 0x0043-0x0049 + * ARIA 4 0x0058-0x005E + * ASN1 7 0x0060-0x006C + * CMAC 1 0x007A-0x007A + * PBKDF2 1 0x007C-0x007C + * HMAC_DRBG 4 0x0003-0x0009 + * CCM 3 0x000D-0x0011 + * ARC4 1 0x0019-0x0019 + * MD2 1 0x002B-0x002B + * MD4 1 0x002D-0x002D + * MD5 1 0x002F-0x002F + * RIPEMD160 1 0x0031-0x0031 + * SHA1 1 0x0035-0x0035 0x0073-0x0073 + * SHA256 1 0x0037-0x0037 0x0074-0x0074 + * SHA512 1 0x0039-0x0039 0x0075-0x0075 + * CHACHA20 3 0x0051-0x0055 + * POLY1305 3 0x0057-0x005B + * CHACHAPOLY 2 0x0054-0x0056 + * PLATFORM 1 0x0070-0x0072 + * + * High-level module nr (3 bits - 0x0...-0x7...) + * Name ID Nr of Errors + * PEM 1 9 + * PKCS#12 1 4 (Started from top) + * X509 2 20 + * PKCS5 2 4 (Started from top) + * DHM 3 11 + * PK 3 15 (Started from top) + * RSA 4 11 + * ECP 4 10 (Started from top) + * MD 5 5 + * HKDF 5 1 (Started from top) + * CIPHER 6 8 (Started from 0x6080) + * SSL 6 24 (Started from top, plus 0x6000) + * SSL 7 32 + * + * Module dependent error code (5 bits 0x.00.-0x.F8.) + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Translate a mbed TLS error code into a string representation, + * Result is truncated if necessary and always includes a terminating + * null byte. + * + * \param errnum error code + * \param buffer buffer to place representation in + * \param buflen length of the buffer + */ +void mbedtls_strerror( int errnum, char *buffer, size_t buflen ); + +#ifdef __cplusplus +} +#endif + +#endif /* error.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/gcm.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/gcm.h new file mode 100644 index 000000000..d4f38398f --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/gcm.h @@ -0,0 +1,326 @@ +/** + * \file gcm.h + * + * \brief This file contains GCM definitions and functions. + * + * The Galois/Counter Mode (GCM) for 128-bit block ciphers is defined + * in D. McGrew, J. Viega, The Galois/Counter Mode of Operation + * (GCM), Natl. Inst. Stand. Technol. + * + * For more information on GCM, see NIST SP 800-38D: Recommendation for + * Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC. + * + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_GCM_H +#define MBEDTLS_GCM_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "cipher.h" + +#include + +#define MBEDTLS_GCM_ENCRYPT 1 +#define MBEDTLS_GCM_DECRYPT 0 + +#define MBEDTLS_ERR_GCM_AUTH_FAILED -0x0012 /**< Authenticated decryption failed. */ + +/* MBEDTLS_ERR_GCM_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_GCM_HW_ACCEL_FAILED -0x0013 /**< GCM hardware accelerator failed. */ + +#define MBEDTLS_ERR_GCM_BAD_INPUT -0x0014 /**< Bad input parameters to function. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_GCM_ALT) + +/** + * \brief The GCM context structure. + */ +typedef struct mbedtls_gcm_context +{ + mbedtls_cipher_context_t cipher_ctx; /*!< The cipher context used. */ + uint64_t HL[16]; /*!< Precalculated HTable low. */ + uint64_t HH[16]; /*!< Precalculated HTable high. */ + uint64_t len; /*!< The total length of the encrypted data. */ + uint64_t add_len; /*!< The total length of the additional data. */ + unsigned char base_ectr[16]; /*!< The first ECTR for tag. */ + unsigned char y[16]; /*!< The Y working value. */ + unsigned char buf[16]; /*!< The buf working value. */ + int mode; /*!< The operation to perform: + #MBEDTLS_GCM_ENCRYPT or + #MBEDTLS_GCM_DECRYPT. */ +} +mbedtls_gcm_context; + +#else /* !MBEDTLS_GCM_ALT */ +#include "gcm_alt.h" +#endif /* !MBEDTLS_GCM_ALT */ + +/** + * \brief This function initializes the specified GCM context, + * to make references valid, and prepares the context + * for mbedtls_gcm_setkey() or mbedtls_gcm_free(). + * + * The function does not bind the GCM context to a particular + * cipher, nor set the key. For this purpose, use + * mbedtls_gcm_setkey(). + * + * \param ctx The GCM context to initialize. This must not be \c NULL. + */ +void mbedtls_gcm_init( mbedtls_gcm_context *ctx ); + +/** + * \brief This function associates a GCM context with a + * cipher algorithm and a key. + * + * \param ctx The GCM context. This must be initialized. + * \param cipher The 128-bit block cipher to use. + * \param key The encryption key. This must be a readable buffer of at + * least \p keybits bits. + * \param keybits The key size in bits. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return A cipher-specific error code on failure. + */ +int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief This function performs GCM encryption or decryption of a buffer. + * + * \note For encryption, the output buffer can be the same as the + * input buffer. For decryption, the output buffer cannot be + * the same as input buffer. If the buffers overlap, the output + * buffer must trail at least 8 Bytes behind the input buffer. + * + * \warning When this function performs a decryption, it outputs the + * authentication tag and does not verify that the data is + * authentic. You should use this function to perform encryption + * only. For decryption, use mbedtls_gcm_auth_decrypt() instead. + * + * \param ctx The GCM context to use for encryption or decryption. This + * must be initialized. + * \param mode The operation to perform: + * - #MBEDTLS_GCM_ENCRYPT to perform authenticated encryption. + * The ciphertext is written to \p output and the + * authentication tag is written to \p tag. + * - #MBEDTLS_GCM_DECRYPT to perform decryption. + * The plaintext is written to \p output and the + * authentication tag is written to \p tag. + * Note that this mode is not recommended, because it does + * not verify the authenticity of the data. For this reason, + * you should use mbedtls_gcm_auth_decrypt() instead of + * calling this function in decryption mode. + * \param length The length of the input data, which is equal to the length + * of the output data. + * \param iv The initialization vector. This must be a readable buffer of + * at least \p iv_len Bytes. + * \param iv_len The length of the IV. + * \param add The buffer holding the additional data. This must be of at + * least that size in Bytes. + * \param add_len The length of the additional data. + * \param input The buffer holding the input data. If \p length is greater + * than zero, this must be a readable buffer of at least that + * size in Bytes. + * \param output The buffer for holding the output data. If \p length is greater + * than zero, this must be a writable buffer of at least that + * size in Bytes. + * \param tag_len The length of the tag to generate. + * \param tag The buffer for holding the tag. This must be a readable + * buffer of at least \p tag_len Bytes. + * + * \return \c 0 if the encryption or decryption was performed + * successfully. Note that in #MBEDTLS_GCM_DECRYPT mode, + * this does not indicate that the data is authentic. + * \return #MBEDTLS_ERR_GCM_BAD_INPUT if the lengths or pointers are + * not valid or a cipher-specific error code if the encryption + * or decryption failed. + */ +int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx, + int mode, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *input, + unsigned char *output, + size_t tag_len, + unsigned char *tag ); + +/** + * \brief This function performs a GCM authenticated decryption of a + * buffer. + * + * \note For decryption, the output buffer cannot be the same as + * input buffer. If the buffers overlap, the output buffer + * must trail at least 8 Bytes behind the input buffer. + * + * \param ctx The GCM context. This must be initialized. + * \param length The length of the ciphertext to decrypt, which is also + * the length of the decrypted plaintext. + * \param iv The initialization vector. This must be a readable buffer + * of at least \p iv_len Bytes. + * \param iv_len The length of the IV. + * \param add The buffer holding the additional data. This must be of at + * least that size in Bytes. + * \param add_len The length of the additional data. + * \param tag The buffer holding the tag to verify. This must be a + * readable buffer of at least \p tag_len Bytes. + * \param tag_len The length of the tag to verify. + * \param input The buffer holding the ciphertext. If \p length is greater + * than zero, this must be a readable buffer of at least that + * size. + * \param output The buffer for holding the decrypted plaintext. If \p length + * is greater than zero, this must be a writable buffer of at + * least that size. + * + * \return \c 0 if successful and authenticated. + * \return #MBEDTLS_ERR_GCM_AUTH_FAILED if the tag does not match. + * \return #MBEDTLS_ERR_GCM_BAD_INPUT if the lengths or pointers are + * not valid or a cipher-specific error code if the decryption + * failed. + */ +int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *tag, + size_t tag_len, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function starts a GCM encryption or decryption + * operation. + * + * \param ctx The GCM context. This must be initialized. + * \param mode The operation to perform: #MBEDTLS_GCM_ENCRYPT or + * #MBEDTLS_GCM_DECRYPT. + * \param iv The initialization vector. This must be a readable buffer of + * at least \p iv_len Bytes. + * \param iv_len The length of the IV. + * \param add The buffer holding the additional data, or \c NULL + * if \p add_len is \c 0. + * \param add_len The length of the additional data. If \c 0, + * \p add may be \c NULL. + * + * \return \c 0 on success. + */ +int mbedtls_gcm_starts( mbedtls_gcm_context *ctx, + int mode, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len ); + +/** + * \brief This function feeds an input buffer into an ongoing GCM + * encryption or decryption operation. + * + * ` The function expects input to be a multiple of 16 + * Bytes. Only the last call before calling + * mbedtls_gcm_finish() can be less than 16 Bytes. + * + * \note For decryption, the output buffer cannot be the same as + * input buffer. If the buffers overlap, the output buffer + * must trail at least 8 Bytes behind the input buffer. + * + * \param ctx The GCM context. This must be initialized. + * \param length The length of the input data. This must be a multiple of + * 16 except in the last call before mbedtls_gcm_finish(). + * \param input The buffer holding the input data. If \p length is greater + * than zero, this must be a readable buffer of at least that + * size in Bytes. + * \param output The buffer for holding the output data. If \p length is + * greater than zero, this must be a writable buffer of at + * least that size in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_GCM_BAD_INPUT on failure. + */ +int mbedtls_gcm_update( mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function finishes the GCM operation and generates + * the authentication tag. + * + * It wraps up the GCM stream, and generates the + * tag. The tag can have a maximum length of 16 Bytes. + * + * \param ctx The GCM context. This must be initialized. + * \param tag The buffer for holding the tag. This must be a readable + * buffer of at least \p tag_len Bytes. + * \param tag_len The length of the tag to generate. This must be at least + * four. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_GCM_BAD_INPUT on failure. + */ +int mbedtls_gcm_finish( mbedtls_gcm_context *ctx, + unsigned char *tag, + size_t tag_len ); + +/** + * \brief This function clears a GCM context and the underlying + * cipher sub-context. + * + * \param ctx The GCM context to clear. If this is \c NULL, the call has + * no effect. Otherwise, this must be initialized. + */ +void mbedtls_gcm_free( mbedtls_gcm_context *ctx ); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief The GCM checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_gcm_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + + +#endif /* gcm.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/havege.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/havege.h new file mode 100644 index 000000000..ad6a15e73 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/havege.h @@ -0,0 +1,81 @@ +/** + * \file havege.h + * + * \brief HAVEGE: HArdware Volatile Entropy Gathering and Expansion + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_HAVEGE_H +#define MBEDTLS_HAVEGE_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#define MBEDTLS_HAVEGE_COLLECT_SIZE 1024 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief HAVEGE state structure + */ +typedef struct mbedtls_havege_state +{ + int PT1, PT2, offset[2]; + int pool[MBEDTLS_HAVEGE_COLLECT_SIZE]; + int WALK[8192]; +} +mbedtls_havege_state; + +/** + * \brief HAVEGE initialization + * + * \param hs HAVEGE state to be initialized + */ +void mbedtls_havege_init( mbedtls_havege_state *hs ); + +/** + * \brief Clear HAVEGE state + * + * \param hs HAVEGE state to be cleared + */ +void mbedtls_havege_free( mbedtls_havege_state *hs ); + +/** + * \brief HAVEGE rand function + * + * \param p_rng A HAVEGE state + * \param output Buffer to fill + * \param len Length of buffer + * + * \return 0 + */ +int mbedtls_havege_random( void *p_rng, unsigned char *output, size_t len ); + +#ifdef __cplusplus +} +#endif + +#endif /* havege.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/hkdf.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/hkdf.h new file mode 100644 index 000000000..4abe82389 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/hkdf.h @@ -0,0 +1,141 @@ +/** + * \file hkdf.h + * + * \brief This file contains the HKDF interface. + * + * The HMAC-based Extract-and-Expand Key Derivation Function (HKDF) is + * specified by RFC 5869. + */ +/* + * Copyright (C) 2016-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_HKDF_H +#define MBEDTLS_HKDF_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "md.h" + +/** + * \name HKDF Error codes + * \{ + */ +#define MBEDTLS_ERR_HKDF_BAD_INPUT_DATA -0x5F80 /**< Bad input parameters to function. */ +/* \} name */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief This is the HMAC-based Extract-and-Expand Key Derivation Function + * (HKDF). + * + * \param md A hash function; md.size denotes the length of the hash + * function output in bytes. + * \param salt An optional salt value (a non-secret random value); + * if the salt is not provided, a string of all zeros of + * md.size length is used as the salt. + * \param salt_len The length in bytes of the optional \p salt. + * \param ikm The input keying material. + * \param ikm_len The length in bytes of \p ikm. + * \param info An optional context and application specific information + * string. This can be a zero-length string. + * \param info_len The length of \p info in bytes. + * \param okm The output keying material of \p okm_len bytes. + * \param okm_len The length of the output keying material in bytes. This + * must be less than or equal to 255 * md.size bytes. + * + * \return 0 on success. + * \return #MBEDTLS_ERR_HKDF_BAD_INPUT_DATA when the parameters are invalid. + * \return An MBEDTLS_ERR_MD_* error for errors returned from the underlying + * MD layer. + */ +int mbedtls_hkdf( const mbedtls_md_info_t *md, const unsigned char *salt, + size_t salt_len, const unsigned char *ikm, size_t ikm_len, + const unsigned char *info, size_t info_len, + unsigned char *okm, size_t okm_len ); + +/** + * \brief Take the input keying material \p ikm and extract from it a + * fixed-length pseudorandom key \p prk. + * + * \warning This function should only be used if the security of it has been + * studied and established in that particular context (eg. TLS 1.3 + * key schedule). For standard HKDF security guarantees use + * \c mbedtls_hkdf instead. + * + * \param md A hash function; md.size denotes the length of the + * hash function output in bytes. + * \param salt An optional salt value (a non-secret random value); + * if the salt is not provided, a string of all zeros + * of md.size length is used as the salt. + * \param salt_len The length in bytes of the optional \p salt. + * \param ikm The input keying material. + * \param ikm_len The length in bytes of \p ikm. + * \param[out] prk A pseudorandom key of at least md.size bytes. + * + * \return 0 on success. + * \return #MBEDTLS_ERR_HKDF_BAD_INPUT_DATA when the parameters are invalid. + * \return An MBEDTLS_ERR_MD_* error for errors returned from the underlying + * MD layer. + */ +int mbedtls_hkdf_extract( const mbedtls_md_info_t *md, + const unsigned char *salt, size_t salt_len, + const unsigned char *ikm, size_t ikm_len, + unsigned char *prk ); + +/** + * \brief Expand the supplied \p prk into several additional pseudorandom + * keys, which is the output of the HKDF. + * + * \warning This function should only be used if the security of it has been + * studied and established in that particular context (eg. TLS 1.3 + * key schedule). For standard HKDF security guarantees use + * \c mbedtls_hkdf instead. + * + * \param md A hash function; md.size denotes the length of the hash + * function output in bytes. + * \param prk A pseudorandom key of at least md.size bytes. \p prk is + * usually the output from the HKDF extract step. + * \param prk_len The length in bytes of \p prk. + * \param info An optional context and application specific information + * string. This can be a zero-length string. + * \param info_len The length of \p info in bytes. + * \param okm The output keying material of \p okm_len bytes. + * \param okm_len The length of the output keying material in bytes. This + * must be less than or equal to 255 * md.size bytes. + * + * \return 0 on success. + * \return #MBEDTLS_ERR_HKDF_BAD_INPUT_DATA when the parameters are invalid. + * \return An MBEDTLS_ERR_MD_* error for errors returned from the underlying + * MD layer. + */ +int mbedtls_hkdf_expand( const mbedtls_md_info_t *md, const unsigned char *prk, + size_t prk_len, const unsigned char *info, + size_t info_len, unsigned char *okm, size_t okm_len ); + +#ifdef __cplusplus +} +#endif + +#endif /* hkdf.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/hmac_drbg.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/hmac_drbg.h new file mode 100644 index 000000000..3c10ebfef --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/hmac_drbg.h @@ -0,0 +1,334 @@ +/** + * \file hmac_drbg.h + * + * \brief HMAC_DRBG (NIST SP 800-90A) + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_HMAC_DRBG_H +#define MBEDTLS_HMAC_DRBG_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "md.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +/* + * Error codes + */ +#define MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG -0x0003 /**< Too many random requested in single call. */ +#define MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG -0x0005 /**< Input too large (Entropy + additional). */ +#define MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR -0x0007 /**< Read/write error in file. */ +#define MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED -0x0009 /**< The entropy source failed. */ + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_HMAC_DRBG_RESEED_INTERVAL) +#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +#endif + +#if !defined(MBEDTLS_HMAC_DRBG_MAX_INPUT) +#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +#endif + +#if !defined(MBEDTLS_HMAC_DRBG_MAX_REQUEST) +#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +#endif + +#if !defined(MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT) +#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ +#endif + +/* \} name SECTION: Module settings */ + +#define MBEDTLS_HMAC_DRBG_PR_OFF 0 /**< No prediction resistance */ +#define MBEDTLS_HMAC_DRBG_PR_ON 1 /**< Prediction resistance enabled */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * HMAC_DRBG context. + */ +typedef struct mbedtls_hmac_drbg_context +{ + /* Working state: the key K is not stored explicitly, + * but is implied by the HMAC context */ + mbedtls_md_context_t md_ctx; /*!< HMAC context (inc. K) */ + unsigned char V[MBEDTLS_MD_MAX_SIZE]; /*!< V in the spec */ + int reseed_counter; /*!< reseed counter */ + + /* Administrative state */ + size_t entropy_len; /*!< entropy bytes grabbed on each (re)seed */ + int prediction_resistance; /*!< enable prediction resistance (Automatic + reseed before every random generation) */ + int reseed_interval; /*!< reseed interval */ + + /* Callbacks */ + int (*f_entropy)(void *, unsigned char *, size_t); /*!< entropy function */ + void *p_entropy; /*!< context for the entropy function */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} mbedtls_hmac_drbg_context; + +/** + * \brief HMAC_DRBG context initialization + * Makes the context ready for mbedtls_hmac_drbg_seed(), + * mbedtls_hmac_drbg_seed_buf() or + * mbedtls_hmac_drbg_free(). + * + * \param ctx HMAC_DRBG context to be initialized + */ +void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx ); + +/** + * \brief HMAC_DRBG initial seeding + * Seed and setup entropy source for future reseeds. + * + * \param ctx HMAC_DRBG context to be seeded + * \param md_info MD algorithm to use for HMAC_DRBG + * \param f_entropy Entropy callback (p_entropy, buffer to fill, buffer + * length) + * \param p_entropy Entropy context + * \param custom Personalization data (Device specific identifiers) + * (Can be NULL) + * \param len Length of personalization data + * + * \note The "security strength" as defined by NIST is set to: + * 128 bits if md_alg is SHA-1, + * 192 bits if md_alg is SHA-224, + * 256 bits if md_alg is SHA-256 or higher. + * Note that SHA-256 is just as efficient as SHA-224. + * + * \return 0 if successful, or + * MBEDTLS_ERR_MD_BAD_INPUT_DATA, or + * MBEDTLS_ERR_MD_ALLOC_FAILED, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED. + */ +int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t * md_info, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ); + +/** + * \brief Initilisation of simpified HMAC_DRBG (never reseeds). + * (For use with deterministic ECDSA.) + * + * \param ctx HMAC_DRBG context to be initialised + * \param md_info MD algorithm to use for HMAC_DRBG + * \param data Concatenation of entropy string and additional data + * \param data_len Length of data in bytes + * + * \return 0 if successful, or + * MBEDTLS_ERR_MD_BAD_INPUT_DATA, or + * MBEDTLS_ERR_MD_ALLOC_FAILED. + */ +int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t * md_info, + const unsigned char *data, size_t data_len ); + +/** + * \brief Enable / disable prediction resistance (Default: Off) + * + * Note: If enabled, entropy is used for ctx->entropy_len before each call! + * Only use this if you have ample supply of good entropy! + * + * \param ctx HMAC_DRBG context + * \param resistance MBEDTLS_HMAC_DRBG_PR_ON or MBEDTLS_HMAC_DRBG_PR_OFF + */ +void mbedtls_hmac_drbg_set_prediction_resistance( mbedtls_hmac_drbg_context *ctx, + int resistance ); + +/** + * \brief Set the amount of entropy grabbed on each reseed + * (Default: given by the security strength, which + * depends on the hash used, see \c mbedtls_hmac_drbg_init() ) + * + * \param ctx HMAC_DRBG context + * \param len Amount of entropy to grab, in bytes + */ +void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, + size_t len ); + +/** + * \brief Set the reseed interval + * (Default: MBEDTLS_HMAC_DRBG_RESEED_INTERVAL) + * + * \param ctx HMAC_DRBG context + * \param interval Reseed interval + */ +void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx, + int interval ); + +/** + * \brief HMAC_DRBG update state + * + * \param ctx HMAC_DRBG context + * \param additional Additional data to update state with, or NULL + * \param add_len Length of additional data, or 0 + * + * \return \c 0 on success, or an error from the underlying + * hash calculation. + * + * \note Additional data is optional, pass NULL and 0 as second + * third argument if no additional data is being used. + */ +int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t add_len ); + +/** + * \brief HMAC_DRBG reseeding (extracts data from entropy source) + * + * \param ctx HMAC_DRBG context + * \param additional Additional data to add to state (Can be NULL) + * \param len Length of additional data + * + * \return 0 if successful, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + */ +int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t len ); + +/** + * \brief HMAC_DRBG generate random with additional update input + * + * Note: Automatically reseeds if reseed_counter is reached or PR is enabled. + * + * \param p_rng HMAC_DRBG context + * \param output Buffer to fill + * \param output_len Length of the buffer + * \param additional Additional data to update with (can be NULL) + * \param add_len Length of additional data (can be 0) + * + * \return 0 if successful, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED, or + * MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG, or + * MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG. + */ +int mbedtls_hmac_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, + size_t add_len ); + +/** + * \brief HMAC_DRBG generate random + * + * Note: Automatically reseeds if reseed_counter is reached or PR is enabled. + * + * \param p_rng HMAC_DRBG context + * \param output Buffer to fill + * \param out_len Length of the buffer + * + * \return 0 if successful, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED, or + * MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG + */ +int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len ); + +/** + * \brief Free an HMAC_DRBG context + * + * \param ctx HMAC_DRBG context to free. + */ +void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx ); + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief HMAC_DRBG update state + * + * \deprecated Superseded by mbedtls_hmac_drbg_update_ret() + * in 2.16.0. + * + * \param ctx HMAC_DRBG context + * \param additional Additional data to update state with, or NULL + * \param add_len Length of additional data, or 0 + * + * \note Additional data is optional, pass NULL and 0 as second + * third argument if no additional data is being used. + */ +MBEDTLS_DEPRECATED void mbedtls_hmac_drbg_update( + mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t add_len ); +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Write a seed file + * + * \param ctx HMAC_DRBG context + * \param path Name of the file + * + * \return 0 if successful, 1 on file error, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + */ +int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance + * + * \param ctx HMAC_DRBG context + * \param path Name of the file + * + * \return 0 if successful, 1 on file error, + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED or + * MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG + */ +int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ + + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_hmac_drbg_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* hmac_drbg.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md.h new file mode 100644 index 000000000..69ce590f2 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md.h @@ -0,0 +1,474 @@ + /** + * \file md.h + * + * \brief This file contains the generic message-digest wrapper. + * + * \author Adriaan de Jong + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MD_H +#define MBEDTLS_MD_H + +#include + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#define MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE -0x5080 /**< The selected feature is not available. */ +#define MBEDTLS_ERR_MD_BAD_INPUT_DATA -0x5100 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_MD_ALLOC_FAILED -0x5180 /**< Failed to allocate memory. */ +#define MBEDTLS_ERR_MD_FILE_IO_ERROR -0x5200 /**< Opening or reading of file failed. */ + +/* MBEDTLS_ERR_MD_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_MD_HW_ACCEL_FAILED -0x5280 /**< MD hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Supported message digests. + * + * \warning MD2, MD4, MD5 and SHA-1 are considered weak message digests and + * their use constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +typedef enum { + MBEDTLS_MD_NONE=0, /**< None. */ + MBEDTLS_MD_MD2, /**< The MD2 message digest. */ + MBEDTLS_MD_MD4, /**< The MD4 message digest. */ + MBEDTLS_MD_MD5, /**< The MD5 message digest. */ + MBEDTLS_MD_SHA1, /**< The SHA-1 message digest. */ + MBEDTLS_MD_SHA224, /**< The SHA-224 message digest. */ + MBEDTLS_MD_SHA256, /**< The SHA-256 message digest. */ + MBEDTLS_MD_SHA384, /**< The SHA-384 message digest. */ + MBEDTLS_MD_SHA512, /**< The SHA-512 message digest. */ + MBEDTLS_MD_RIPEMD160, /**< The RIPEMD-160 message digest. */ +} mbedtls_md_type_t; + +#if defined(MBEDTLS_SHA512_C) +#define MBEDTLS_MD_MAX_SIZE 64 /* longest known is SHA512 */ +#else +#define MBEDTLS_MD_MAX_SIZE 32 /* longest known is SHA256 or less */ +#endif + +#if defined(MBEDTLS_SHA512_C) +#define MBEDTLS_MD_MAX_BLOCK_SIZE 128 +#else +#define MBEDTLS_MD_MAX_BLOCK_SIZE 64 +#endif + +/** + * Opaque struct defined in md_internal.h. + */ +typedef struct mbedtls_md_info_t mbedtls_md_info_t; + +/** + * The generic message-digest context. + */ +typedef struct mbedtls_md_context_t +{ + /** Information about the associated message digest. */ + const mbedtls_md_info_t *md_info; + + /** The digest-specific context. */ + void *md_ctx; + + /** The HMAC part of the context. */ + void *hmac_ctx; +} mbedtls_md_context_t; + +/** + * \brief This function returns the list of digests supported by the + * generic digest module. + * + * \return A statically allocated array of digests. Each element + * in the returned list is an integer belonging to the + * message-digest enumeration #mbedtls_md_type_t. + * The last entry is 0. + */ +const int *mbedtls_md_list( void ); + +/** + * \brief This function returns the message-digest information + * associated with the given digest name. + * + * \param md_name The name of the digest to search for. + * + * \return The message-digest information associated with \p md_name. + * \return NULL if the associated message-digest information is not found. + */ +const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name ); + +/** + * \brief This function returns the message-digest information + * associated with the given digest type. + * + * \param md_type The type of digest to search for. + * + * \return The message-digest information associated with \p md_type. + * \return NULL if the associated message-digest information is not found. + */ +const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type ); + +/** + * \brief This function initializes a message-digest context without + * binding it to a particular message-digest algorithm. + * + * This function should always be called first. It prepares the + * context for mbedtls_md_setup() for binding it to a + * message-digest algorithm. + */ +void mbedtls_md_init( mbedtls_md_context_t *ctx ); + +/** + * \brief This function clears the internal structure of \p ctx and + * frees any embedded internal structure, but does not free + * \p ctx itself. + * + * If you have called mbedtls_md_setup() on \p ctx, you must + * call mbedtls_md_free() when you are no longer using the + * context. + * Calling this function if you have previously + * called mbedtls_md_init() and nothing else is optional. + * You must not call this function if you have not called + * mbedtls_md_init(). + */ +void mbedtls_md_free( mbedtls_md_context_t *ctx ); + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function selects the message digest algorithm to use, + * and allocates internal structures. + * + * It should be called after mbedtls_md_init() or mbedtls_md_free(). + * Makes it necessary to call mbedtls_md_free() later. + * + * \deprecated Superseded by mbedtls_md_setup() in 2.0.0 + * + * \param ctx The context to set up. + * \param md_info The information structure of the message-digest algorithm + * to use. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + * \return #MBEDTLS_ERR_MD_ALLOC_FAILED on memory-allocation failure. + */ +int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info ) MBEDTLS_DEPRECATED; +#undef MBEDTLS_DEPRECATED +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief This function selects the message digest algorithm to use, + * and allocates internal structures. + * + * It should be called after mbedtls_md_init() or + * mbedtls_md_free(). Makes it necessary to call + * mbedtls_md_free() later. + * + * \param ctx The context to set up. + * \param md_info The information structure of the message-digest algorithm + * to use. + * \param hmac Defines if HMAC is used. 0: HMAC is not used (saves some memory), + * or non-zero: HMAC is used with this context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + * \return #MBEDTLS_ERR_MD_ALLOC_FAILED on memory-allocation failure. + */ +int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac ); + +/** + * \brief This function clones the state of an message-digest + * context. + * + * \note You must call mbedtls_md_setup() on \c dst before calling + * this function. + * + * \note The two contexts must have the same type, + * for example, both are SHA-256. + * + * \warning This function clones the message-digest state, not the + * HMAC state. + * + * \param dst The destination context. + * \param src The context to be cloned. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification failure. + */ +int mbedtls_md_clone( mbedtls_md_context_t *dst, + const mbedtls_md_context_t *src ); + +/** + * \brief This function extracts the message-digest size from the + * message-digest information structure. + * + * \param md_info The information structure of the message-digest algorithm + * to use. + * + * \return The size of the message-digest output in Bytes. + */ +unsigned char mbedtls_md_get_size( const mbedtls_md_info_t *md_info ); + +/** + * \brief This function extracts the message-digest type from the + * message-digest information structure. + * + * \param md_info The information structure of the message-digest algorithm + * to use. + * + * \return The type of the message digest. + */ +mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info ); + +/** + * \brief This function extracts the message-digest name from the + * message-digest information structure. + * + * \param md_info The information structure of the message-digest algorithm + * to use. + * + * \return The name of the message digest. + */ +const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info ); + +/** + * \brief This function starts a message-digest computation. + * + * You must call this function after setting up the context + * with mbedtls_md_setup(), and before passing data with + * mbedtls_md_update(). + * + * \param ctx The generic message-digest context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_starts( mbedtls_md_context_t *ctx ); + +/** + * \brief This function feeds an input buffer into an ongoing + * message-digest computation. + * + * You must call mbedtls_md_starts() before calling this + * function. You may call this function multiple times. + * Afterwards, call mbedtls_md_finish(). + * + * \param ctx The generic message-digest context. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief This function finishes the digest operation, + * and writes the result to the output buffer. + * + * Call this function after a call to mbedtls_md_starts(), + * followed by any number of calls to mbedtls_md_update(). + * Afterwards, you may either clear the context with + * mbedtls_md_free(), or call mbedtls_md_starts() to reuse + * the context for another digest operation with the same + * algorithm. + * + * \param ctx The generic message-digest context. + * \param output The buffer for the generic message-digest checksum result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output ); + +/** + * \brief This function calculates the message-digest of a buffer, + * with respect to a configurable message-digest algorithm + * in a single call. + * + * The result is calculated as + * Output = message_digest(input buffer). + * + * \param md_info The information structure of the message-digest algorithm + * to use. + * \param input The buffer holding the data. + * \param ilen The length of the input data. + * \param output The generic message-digest checksum result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen, + unsigned char *output ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief This function calculates the message-digest checksum + * result of the contents of the provided file. + * + * The result is calculated as + * Output = message_digest(file contents). + * + * \param md_info The information structure of the message-digest algorithm + * to use. + * \param path The input file name. + * \param output The generic message-digest checksum result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_FILE_IO_ERROR on an I/O error accessing + * the file pointed by \p path. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA if \p md_info was NULL. + */ +int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, + unsigned char *output ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief This function sets the HMAC key and prepares to + * authenticate a new message. + * + * Call this function after mbedtls_md_setup(), to use + * the MD context for an HMAC calculation, then call + * mbedtls_md_hmac_update() to provide the input data, and + * mbedtls_md_hmac_finish() to get the HMAC value. + * + * \param ctx The message digest context containing an embedded HMAC + * context. + * \param key The HMAC secret key. + * \param keylen The length of the HMAC key in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, + size_t keylen ); + +/** + * \brief This function feeds an input buffer into an ongoing HMAC + * computation. + * + * Call mbedtls_md_hmac_starts() or mbedtls_md_hmac_reset() + * before calling this function. + * You may call this function multiple times to pass the + * input piecewise. + * Afterwards, call mbedtls_md_hmac_finish(). + * + * \param ctx The message digest context containing an embedded HMAC + * context. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the HMAC operation, and writes + * the result to the output buffer. + * + * Call this function after mbedtls_md_hmac_starts() and + * mbedtls_md_hmac_update() to get the HMAC value. Afterwards + * you may either call mbedtls_md_free() to clear the context, + * or call mbedtls_md_hmac_reset() to reuse the context with + * the same HMAC key. + * + * \param ctx The message digest context containing an embedded HMAC + * context. + * \param output The generic HMAC checksum result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output); + +/** + * \brief This function prepares to authenticate a new message with + * the same key as the previous HMAC operation. + * + * You may call this function after mbedtls_md_hmac_finish(). + * Afterwards call mbedtls_md_hmac_update() to pass the new + * input. + * + * \param ctx The message digest context containing an embedded HMAC + * context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx ); + +/** + * \brief This function calculates the full generic HMAC + * on the input buffer with the provided key. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The HMAC result is calculated as + * output = generic HMAC(hmac key, input buffer). + * + * \param md_info The information structure of the message-digest algorithm + * to use. + * \param key The HMAC secret key. + * \param keylen The length of the HMAC secret key in Bytes. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * \param output The generic HMAC result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_hmac( const mbedtls_md_info_t *md_info, const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ); + +/* Internal use */ +int mbedtls_md_process( mbedtls_md_context_t *ctx, const unsigned char *data ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_MD_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md2.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md2.h new file mode 100644 index 000000000..c359d6d8c --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md2.h @@ -0,0 +1,306 @@ +/** + * \file md2.h + * + * \brief MD2 message digest algorithm (hash function) + * + * \warning MD2 is considered a weak message digest and its use constitutes a + * security risk. We recommend considering stronger message digests + * instead. + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + * + */ +#ifndef MBEDTLS_MD2_H +#define MBEDTLS_MD2_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +/* MBEDTLS_ERR_MD2_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_MD2_HW_ACCEL_FAILED -0x002B /**< MD2 hardware accelerator failed */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_MD2_ALT) +// Regular implementation +// + +/** + * \brief MD2 context structure + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +typedef struct mbedtls_md2_context +{ + unsigned char cksum[16]; /*!< checksum of the data block */ + unsigned char state[48]; /*!< intermediate digest state */ + unsigned char buffer[16]; /*!< data block being processed */ + size_t left; /*!< amount of data in buffer */ +} +mbedtls_md2_context; + +#else /* MBEDTLS_MD2_ALT */ +#include "md2_alt.h" +#endif /* MBEDTLS_MD2_ALT */ + +/** + * \brief Initialize MD2 context + * + * \param ctx MD2 context to be initialized + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md2_init( mbedtls_md2_context *ctx ); + +/** + * \brief Clear MD2 context + * + * \param ctx MD2 context to be cleared + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md2_free( mbedtls_md2_context *ctx ); + +/** + * \brief Clone (the state of) an MD2 context + * + * \param dst The destination context + * \param src The context to be cloned + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md2_clone( mbedtls_md2_context *dst, + const mbedtls_md2_context *src ); + +/** + * \brief MD2 context setup + * + * \param ctx context to be initialized + * + * \return 0 if successful + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md2_starts_ret( mbedtls_md2_context *ctx ); + +/** + * \brief MD2 process buffer + * + * \param ctx MD2 context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \return 0 if successful + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md2_update_ret( mbedtls_md2_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief MD2 final digest + * + * \param ctx MD2 context + * \param output MD2 checksum result + * + * \return 0 if successful + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md2_finish_ret( mbedtls_md2_context *ctx, + unsigned char output[16] ); + +/** + * \brief MD2 process data block (internal use only) + * + * \param ctx MD2 context + * + * \return 0 if successful + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_internal_md2_process( mbedtls_md2_context *ctx ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief MD2 context setup + * + * \deprecated Superseded by mbedtls_md2_starts_ret() in 2.7.0 + * + * \param ctx context to be initialized + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md2_starts( mbedtls_md2_context *ctx ); + +/** + * \brief MD2 process buffer + * + * \deprecated Superseded by mbedtls_md2_update_ret() in 2.7.0 + * + * \param ctx MD2 context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md2_update( mbedtls_md2_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief MD2 final digest + * + * \deprecated Superseded by mbedtls_md2_finish_ret() in 2.7.0 + * + * \param ctx MD2 context + * \param output MD2 checksum result + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md2_finish( mbedtls_md2_context *ctx, + unsigned char output[16] ); + +/** + * \brief MD2 process data block (internal use only) + * + * \deprecated Superseded by mbedtls_internal_md2_process() in 2.7.0 + * + * \param ctx MD2 context + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md2_process( mbedtls_md2_context *ctx ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Output = MD2( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD2 checksum result + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md2_ret( const unsigned char *input, + size_t ilen, + unsigned char output[16] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief Output = MD2( input buffer ) + * + * \deprecated Superseded by mbedtls_md2_ret() in 2.7.0 + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD2 checksum result + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md2( const unsigned char *input, + size_t ilen, + unsigned char output[16] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + * + * \warning MD2 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md2_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_md2.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md4.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md4.h new file mode 100644 index 000000000..ee170ec51 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md4.h @@ -0,0 +1,311 @@ +/** + * \file md4.h + * + * \brief MD4 message digest algorithm (hash function) + * + * \warning MD4 is considered a weak message digest and its use constitutes a + * security risk. We recommend considering stronger message digests + * instead. + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + * + */ +#ifndef MBEDTLS_MD4_H +#define MBEDTLS_MD4_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +/* MBEDTLS_ERR_MD4_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_MD4_HW_ACCEL_FAILED -0x002D /**< MD4 hardware accelerator failed */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_MD4_ALT) +// Regular implementation +// + +/** + * \brief MD4 context structure + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +typedef struct mbedtls_md4_context +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_md4_context; + +#else /* MBEDTLS_MD4_ALT */ +#include "md4_alt.h" +#endif /* MBEDTLS_MD4_ALT */ + +/** + * \brief Initialize MD4 context + * + * \param ctx MD4 context to be initialized + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md4_init( mbedtls_md4_context *ctx ); + +/** + * \brief Clear MD4 context + * + * \param ctx MD4 context to be cleared + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md4_free( mbedtls_md4_context *ctx ); + +/** + * \brief Clone (the state of) an MD4 context + * + * \param dst The destination context + * \param src The context to be cloned + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md4_clone( mbedtls_md4_context *dst, + const mbedtls_md4_context *src ); + +/** + * \brief MD4 context setup + * + * \param ctx context to be initialized + * + * \return 0 if successful + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + */ +int mbedtls_md4_starts_ret( mbedtls_md4_context *ctx ); + +/** + * \brief MD4 process buffer + * + * \param ctx MD4 context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \return 0 if successful + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md4_update_ret( mbedtls_md4_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief MD4 final digest + * + * \param ctx MD4 context + * \param output MD4 checksum result + * + * \return 0 if successful + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md4_finish_ret( mbedtls_md4_context *ctx, + unsigned char output[16] ); + +/** + * \brief MD4 process data block (internal use only) + * + * \param ctx MD4 context + * \param data buffer holding one block of data + * + * \return 0 if successful + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_internal_md4_process( mbedtls_md4_context *ctx, + const unsigned char data[64] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief MD4 context setup + * + * \deprecated Superseded by mbedtls_md4_starts_ret() in 2.7.0 + * + * \param ctx context to be initialized + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md4_starts( mbedtls_md4_context *ctx ); + +/** + * \brief MD4 process buffer + * + * \deprecated Superseded by mbedtls_md4_update_ret() in 2.7.0 + * + * \param ctx MD4 context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md4_update( mbedtls_md4_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief MD4 final digest + * + * \deprecated Superseded by mbedtls_md4_finish_ret() in 2.7.0 + * + * \param ctx MD4 context + * \param output MD4 checksum result + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md4_finish( mbedtls_md4_context *ctx, + unsigned char output[16] ); + +/** + * \brief MD4 process data block (internal use only) + * + * \deprecated Superseded by mbedtls_internal_md4_process() in 2.7.0 + * + * \param ctx MD4 context + * \param data buffer holding one block of data + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md4_process( mbedtls_md4_context *ctx, + const unsigned char data[64] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Output = MD4( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD4 checksum result + * + * \return 0 if successful + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md4_ret( const unsigned char *input, + size_t ilen, + unsigned char output[16] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief Output = MD4( input buffer ) + * + * \deprecated Superseded by mbedtls_md4_ret() in 2.7.0 + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD4 checksum result + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md4( const unsigned char *input, + size_t ilen, + unsigned char output[16] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + * + * \warning MD4 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md4_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_md4.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md5.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md5.h new file mode 100644 index 000000000..13d3bc654 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md5.h @@ -0,0 +1,311 @@ +/** + * \file md5.h + * + * \brief MD5 message digest algorithm (hash function) + * + * \warning MD5 is considered a weak message digest and its use constitutes a + * security risk. We recommend considering stronger message + * digests instead. + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD5_H +#define MBEDTLS_MD5_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +/* MBEDTLS_ERR_MD5_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_MD5_HW_ACCEL_FAILED -0x002F /**< MD5 hardware accelerator failed */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_MD5_ALT) +// Regular implementation +// + +/** + * \brief MD5 context structure + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +typedef struct mbedtls_md5_context +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_md5_context; + +#else /* MBEDTLS_MD5_ALT */ +#include "md5_alt.h" +#endif /* MBEDTLS_MD5_ALT */ + +/** + * \brief Initialize MD5 context + * + * \param ctx MD5 context to be initialized + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md5_init( mbedtls_md5_context *ctx ); + +/** + * \brief Clear MD5 context + * + * \param ctx MD5 context to be cleared + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md5_free( mbedtls_md5_context *ctx ); + +/** + * \brief Clone (the state of) an MD5 context + * + * \param dst The destination context + * \param src The context to be cloned + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md5_clone( mbedtls_md5_context *dst, + const mbedtls_md5_context *src ); + +/** + * \brief MD5 context setup + * + * \param ctx context to be initialized + * + * \return 0 if successful + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5_starts_ret( mbedtls_md5_context *ctx ); + +/** + * \brief MD5 process buffer + * + * \param ctx MD5 context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \return 0 if successful + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5_update_ret( mbedtls_md5_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief MD5 final digest + * + * \param ctx MD5 context + * \param output MD5 checksum result + * + * \return 0 if successful + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5_finish_ret( mbedtls_md5_context *ctx, + unsigned char output[16] ); + +/** + * \brief MD5 process data block (internal use only) + * + * \param ctx MD5 context + * \param data buffer holding one block of data + * + * \return 0 if successful + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_internal_md5_process( mbedtls_md5_context *ctx, + const unsigned char data[64] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief MD5 context setup + * + * \deprecated Superseded by mbedtls_md5_starts_ret() in 2.7.0 + * + * \param ctx context to be initialized + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md5_starts( mbedtls_md5_context *ctx ); + +/** + * \brief MD5 process buffer + * + * \deprecated Superseded by mbedtls_md5_update_ret() in 2.7.0 + * + * \param ctx MD5 context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md5_update( mbedtls_md5_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief MD5 final digest + * + * \deprecated Superseded by mbedtls_md5_finish_ret() in 2.7.0 + * + * \param ctx MD5 context + * \param output MD5 checksum result + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md5_finish( mbedtls_md5_context *ctx, + unsigned char output[16] ); + +/** + * \brief MD5 process data block (internal use only) + * + * \deprecated Superseded by mbedtls_internal_md5_process() in 2.7.0 + * + * \param ctx MD5 context + * \param data buffer holding one block of data + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md5_process( mbedtls_md5_context *ctx, + const unsigned char data[64] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Output = MD5( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + * + * \return 0 if successful + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5_ret( const unsigned char *input, + size_t ilen, + unsigned char output[16] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief Output = MD5( input buffer ) + * + * \deprecated Superseded by mbedtls_md5_ret() in 2.7.0 + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md5( const unsigned char *input, + size_t ilen, + unsigned char output[16] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_md5.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md_internal.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md_internal.h new file mode 100644 index 000000000..5b7b03ff9 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/md_internal.h @@ -0,0 +1,115 @@ +/** + * \file md_internal.h + * + * \brief Message digest wrappers. + * + * \warning This in an internal header. Do not include directly. + * + * \author Adriaan de Jong + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD_WRAP_H +#define MBEDTLS_MD_WRAP_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Message digest information. + * Allows message digest functions to be called in a generic way. + */ +struct mbedtls_md_info_t +{ + /** Digest identifier */ + mbedtls_md_type_t type; + + /** Name of the message digest */ + const char * name; + + /** Output length of the digest function in bytes */ + int size; + + /** Block length of the digest function in bytes */ + int block_size; + + /** Digest initialisation function */ + int (*starts_func)( void *ctx ); + + /** Digest update function */ + int (*update_func)( void *ctx, const unsigned char *input, size_t ilen ); + + /** Digest finalisation function */ + int (*finish_func)( void *ctx, unsigned char *output ); + + /** Generic digest function */ + int (*digest_func)( const unsigned char *input, size_t ilen, + unsigned char *output ); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + + /** Clone state from a context */ + void (*clone_func)( void *dst, const void *src ); + + /** Internal use only */ + int (*process_func)( void *ctx, const unsigned char *input ); +}; + +#if defined(MBEDTLS_MD2_C) +extern const mbedtls_md_info_t mbedtls_md2_info; +#endif +#if defined(MBEDTLS_MD4_C) +extern const mbedtls_md_info_t mbedtls_md4_info; +#endif +#if defined(MBEDTLS_MD5_C) +extern const mbedtls_md_info_t mbedtls_md5_info; +#endif +#if defined(MBEDTLS_RIPEMD160_C) +extern const mbedtls_md_info_t mbedtls_ripemd160_info; +#endif +#if defined(MBEDTLS_SHA1_C) +extern const mbedtls_md_info_t mbedtls_sha1_info; +#endif +#if defined(MBEDTLS_SHA256_C) +extern const mbedtls_md_info_t mbedtls_sha224_info; +extern const mbedtls_md_info_t mbedtls_sha256_info; +#endif +#if defined(MBEDTLS_SHA512_C) +extern const mbedtls_md_info_t mbedtls_sha384_info; +extern const mbedtls_md_info_t mbedtls_sha512_info; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_MD_WRAP_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/memory_buffer_alloc.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/memory_buffer_alloc.h new file mode 100644 index 000000000..294dd2978 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/memory_buffer_alloc.h @@ -0,0 +1,151 @@ +/** + * \file memory_buffer_alloc.h + * + * \brief Buffer-based memory allocator + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MEMORY_BUFFER_ALLOC_H +#define MBEDTLS_MEMORY_BUFFER_ALLOC_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_MEMORY_ALIGN_MULTIPLE) +#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ +#endif + +/* \} name SECTION: Module settings */ + +#define MBEDTLS_MEMORY_VERIFY_NONE 0 +#define MBEDTLS_MEMORY_VERIFY_ALLOC (1 << 0) +#define MBEDTLS_MEMORY_VERIFY_FREE (1 << 1) +#define MBEDTLS_MEMORY_VERIFY_ALWAYS (MBEDTLS_MEMORY_VERIFY_ALLOC | MBEDTLS_MEMORY_VERIFY_FREE) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initialize use of stack-based memory allocator. + * The stack-based allocator does memory management inside the + * presented buffer and does not call calloc() and free(). + * It sets the global mbedtls_calloc() and mbedtls_free() pointers + * to its own functions. + * (Provided mbedtls_calloc() and mbedtls_free() are thread-safe if + * MBEDTLS_THREADING_C is defined) + * + * \note This code is not optimized and provides a straight-forward + * implementation of a stack-based memory allocator. + * + * \param buf buffer to use as heap + * \param len size of the buffer + */ +void mbedtls_memory_buffer_alloc_init( unsigned char *buf, size_t len ); + +/** + * \brief Free the mutex for thread-safety and clear remaining memory + */ +void mbedtls_memory_buffer_alloc_free( void ); + +/** + * \brief Determine when the allocator should automatically verify the state + * of the entire chain of headers / meta-data. + * (Default: MBEDTLS_MEMORY_VERIFY_NONE) + * + * \param verify One of MBEDTLS_MEMORY_VERIFY_NONE, MBEDTLS_MEMORY_VERIFY_ALLOC, + * MBEDTLS_MEMORY_VERIFY_FREE or MBEDTLS_MEMORY_VERIFY_ALWAYS + */ +void mbedtls_memory_buffer_set_verify( int verify ); + +#if defined(MBEDTLS_MEMORY_DEBUG) +/** + * \brief Print out the status of the allocated memory (primarily for use + * after a program should have de-allocated all memory) + * Prints out a list of 'still allocated' blocks and their stack + * trace if MBEDTLS_MEMORY_BACKTRACE is defined. + */ +void mbedtls_memory_buffer_alloc_status( void ); + +/** + * \brief Get the peak heap usage so far + * + * \param max_used Peak number of bytes in use or committed. This + * includes bytes in allocated blocks too small to split + * into smaller blocks but larger than the requested size. + * \param max_blocks Peak number of blocks in use, including free and used + */ +void mbedtls_memory_buffer_alloc_max_get( size_t *max_used, size_t *max_blocks ); + +/** + * \brief Reset peak statistics + */ +void mbedtls_memory_buffer_alloc_max_reset( void ); + +/** + * \brief Get the current heap usage + * + * \param cur_used Current number of bytes in use or committed. This + * includes bytes in allocated blocks too small to split + * into smaller blocks but larger than the requested size. + * \param cur_blocks Current number of blocks in use, including free and used + */ +void mbedtls_memory_buffer_alloc_cur_get( size_t *cur_used, size_t *cur_blocks ); +#endif /* MBEDTLS_MEMORY_DEBUG */ + +/** + * \brief Verifies that all headers in the memory buffer are correct + * and contain sane values. Helps debug buffer-overflow errors. + * + * Prints out first failure if MBEDTLS_MEMORY_DEBUG is defined. + * Prints out full header information if MBEDTLS_MEMORY_DEBUG + * is defined. (Includes stack trace information for each block if + * MBEDTLS_MEMORY_BACKTRACE is defined as well). + * + * \return 0 if verified, 1 otherwise + */ +int mbedtls_memory_buffer_alloc_verify( void ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_memory_buffer_alloc_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* memory_buffer_alloc.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/net.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/net.h new file mode 100644 index 000000000..cce2b7889 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/net.h @@ -0,0 +1,37 @@ +/** + * \file net.h + * + * \brief Deprecated header file that includes net_sockets.h + * + * \deprecated Superseded by mbedtls/net_sockets.h + */ +/* + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#include "net_sockets.h" +#if defined(MBEDTLS_DEPRECATED_WARNING) +#warning "Deprecated header file: Superseded by mbedtls/net_sockets.h" +#endif /* MBEDTLS_DEPRECATED_WARNING */ +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/net_sockets.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/net_sockets.h new file mode 100644 index 000000000..ab84682fb --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/net_sockets.h @@ -0,0 +1,271 @@ +/** + * \file net_sockets.h + * + * \brief Network sockets abstraction layer to integrate Mbed TLS into a + * BSD-style sockets API. + * + * The network sockets module provides an example integration of the + * Mbed TLS library into a BSD sockets implementation. The module is + * intended to be an example of how Mbed TLS can be integrated into a + * networking stack, as well as to be Mbed TLS's network integration + * for its supported platforms. + * + * The module is intended only to be used with the Mbed TLS library and + * is not intended to be used by third party application software + * directly. + * + * The supported platforms are as follows: + * * Microsoft Windows and Windows CE + * * POSIX/Unix platforms including Linux, OS X + * + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_NET_SOCKETS_H +#define MBEDTLS_NET_SOCKETS_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "ssl.h" + +#include +#include + +#define MBEDTLS_ERR_NET_SOCKET_FAILED -0x0042 /**< Failed to open a socket. */ +#define MBEDTLS_ERR_NET_CONNECT_FAILED -0x0044 /**< The connection to the given server / port failed. */ +#define MBEDTLS_ERR_NET_BIND_FAILED -0x0046 /**< Binding of the socket failed. */ +#define MBEDTLS_ERR_NET_LISTEN_FAILED -0x0048 /**< Could not listen on the socket. */ +#define MBEDTLS_ERR_NET_ACCEPT_FAILED -0x004A /**< Could not accept the incoming connection. */ +#define MBEDTLS_ERR_NET_RECV_FAILED -0x004C /**< Reading information from the socket failed. */ +#define MBEDTLS_ERR_NET_SEND_FAILED -0x004E /**< Sending information through the socket failed. */ +#define MBEDTLS_ERR_NET_CONN_RESET -0x0050 /**< Connection was reset by peer. */ +#define MBEDTLS_ERR_NET_UNKNOWN_HOST -0x0052 /**< Failed to get an IP address for the given hostname. */ +#define MBEDTLS_ERR_NET_BUFFER_TOO_SMALL -0x0043 /**< Buffer is too small to hold the data. */ +#define MBEDTLS_ERR_NET_INVALID_CONTEXT -0x0045 /**< The context is invalid, eg because it was free()ed. */ +#define MBEDTLS_ERR_NET_POLL_FAILED -0x0047 /**< Polling the net context failed. */ +#define MBEDTLS_ERR_NET_BAD_INPUT_DATA -0x0049 /**< Input invalid. */ + +#define MBEDTLS_NET_LISTEN_BACKLOG 10 /**< The backlog that listen() should use. */ + +#define MBEDTLS_NET_PROTO_TCP 0 /**< The TCP transport protocol */ +#define MBEDTLS_NET_PROTO_UDP 1 /**< The UDP transport protocol */ + +#define MBEDTLS_NET_POLL_READ 1 /**< Used in \c mbedtls_net_poll to check for pending data */ +#define MBEDTLS_NET_POLL_WRITE 2 /**< Used in \c mbedtls_net_poll to check if write possible */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Wrapper type for sockets. + * + * Currently backed by just a file descriptor, but might be more in the future + * (eg two file descriptors for combined IPv4 + IPv6 support, or additional + * structures for hand-made UDP demultiplexing). + */ +typedef struct mbedtls_net_context +{ + int fd; /**< The underlying file descriptor */ +} +mbedtls_net_context; + +/** + * \brief Initialize a context + * Just makes the context ready to be used or freed safely. + * + * \param ctx Context to initialize + */ +void mbedtls_net_init( mbedtls_net_context *ctx ); + +/** + * \brief Initiate a connection with host:port in the given protocol + * + * \param ctx Socket to use + * \param host Host to connect to + * \param port Port to connect to + * \param proto Protocol: MBEDTLS_NET_PROTO_TCP or MBEDTLS_NET_PROTO_UDP + * + * \return 0 if successful, or one of: + * MBEDTLS_ERR_NET_SOCKET_FAILED, + * MBEDTLS_ERR_NET_UNKNOWN_HOST, + * MBEDTLS_ERR_NET_CONNECT_FAILED + * + * \note Sets the socket in connected mode even with UDP. + */ +int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto ); + +/** + * \brief Create a receiving socket on bind_ip:port in the chosen + * protocol. If bind_ip == NULL, all interfaces are bound. + * + * \param ctx Socket to use + * \param bind_ip IP to bind to, can be NULL + * \param port Port number to use + * \param proto Protocol: MBEDTLS_NET_PROTO_TCP or MBEDTLS_NET_PROTO_UDP + * + * \return 0 if successful, or one of: + * MBEDTLS_ERR_NET_SOCKET_FAILED, + * MBEDTLS_ERR_NET_BIND_FAILED, + * MBEDTLS_ERR_NET_LISTEN_FAILED + * + * \note Regardless of the protocol, opens the sockets and binds it. + * In addition, make the socket listening if protocol is TCP. + */ +int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto ); + +/** + * \brief Accept a connection from a remote client + * + * \param bind_ctx Relevant socket + * \param client_ctx Will contain the connected client socket + * \param client_ip Will contain the client IP address, can be NULL + * \param buf_size Size of the client_ip buffer + * \param ip_len Will receive the size of the client IP written, + * can be NULL if client_ip is null + * + * \return 0 if successful, or + * MBEDTLS_ERR_NET_ACCEPT_FAILED, or + * MBEDTLS_ERR_NET_BUFFER_TOO_SMALL if buf_size is too small, + * MBEDTLS_ERR_SSL_WANT_READ if bind_fd was set to + * non-blocking and accept() would block. + */ +int mbedtls_net_accept( mbedtls_net_context *bind_ctx, + mbedtls_net_context *client_ctx, + void *client_ip, size_t buf_size, size_t *ip_len ); + +/** + * \brief Check and wait for the context to be ready for read/write + * + * \param ctx Socket to check + * \param rw Bitflag composed of MBEDTLS_NET_POLL_READ and + * MBEDTLS_NET_POLL_WRITE specifying the events + * to wait for: + * - If MBEDTLS_NET_POLL_READ is set, the function + * will return as soon as the net context is available + * for reading. + * - If MBEDTLS_NET_POLL_WRITE is set, the function + * will return as soon as the net context is available + * for writing. + * \param timeout Maximal amount of time to wait before returning, + * in milliseconds. If \c timeout is zero, the + * function returns immediately. If \c timeout is + * -1u, the function blocks potentially indefinitely. + * + * \return Bitmask composed of MBEDTLS_NET_POLL_READ/WRITE + * on success or timeout, or a negative return code otherwise. + */ +int mbedtls_net_poll( mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout ); + +/** + * \brief Set the socket blocking + * + * \param ctx Socket to set + * + * \return 0 if successful, or a non-zero error code + */ +int mbedtls_net_set_block( mbedtls_net_context *ctx ); + +/** + * \brief Set the socket non-blocking + * + * \param ctx Socket to set + * + * \return 0 if successful, or a non-zero error code + */ +int mbedtls_net_set_nonblock( mbedtls_net_context *ctx ); + +/** + * \brief Portable usleep helper + * + * \param usec Amount of microseconds to sleep + * + * \note Real amount of time slept will not be less than + * select()'s timeout granularity (typically, 10ms). + */ +void mbedtls_net_usleep( unsigned long usec ); + +/** + * \brief Read at most 'len' characters. If no error occurs, + * the actual amount read is returned. + * + * \param ctx Socket + * \param buf The buffer to write to + * \param len Maximum length of the buffer + * + * \return the number of bytes received, + * or a non-zero error code; with a non-blocking socket, + * MBEDTLS_ERR_SSL_WANT_READ indicates read() would block. + */ +int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ); + +/** + * \brief Write at most 'len' characters. If no error occurs, + * the actual amount read is returned. + * + * \param ctx Socket + * \param buf The buffer to read from + * \param len The length of the buffer + * + * \return the number of bytes sent, + * or a non-zero error code; with a non-blocking socket, + * MBEDTLS_ERR_SSL_WANT_WRITE indicates write() would block. + */ +int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ); + +/** + * \brief Read at most 'len' characters, blocking for at most + * 'timeout' seconds. If no error occurs, the actual amount + * read is returned. + * + * \param ctx Socket + * \param buf The buffer to write to + * \param len Maximum length of the buffer + * \param timeout Maximum number of milliseconds to wait for data + * 0 means no timeout (wait forever) + * + * \return the number of bytes received, + * or a non-zero error code: + * MBEDTLS_ERR_SSL_TIMEOUT if the operation timed out, + * MBEDTLS_ERR_SSL_WANT_READ if interrupted by a signal. + * + * \note This function will block (until data becomes available or + * timeout is reached) even if the socket is set to + * non-blocking. Handling timeouts with non-blocking reads + * requires a different strategy. + */ +int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len, + uint32_t timeout ); + +/** + * \brief Gracefully shutdown the connection and free associated data + * + * \param ctx The context to free + */ +void mbedtls_net_free( mbedtls_net_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* net_sockets.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/nist_kw.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/nist_kw.h new file mode 100644 index 000000000..5c1948dc2 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/nist_kw.h @@ -0,0 +1,184 @@ +/** + * \file nist_kw.h + * + * \brief This file provides an API for key wrapping (KW) and key wrapping with + * padding (KWP) as defined in NIST SP 800-38F. + * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf + * + * Key wrapping specifies a deterministic authenticated-encryption mode + * of operation, according to NIST SP 800-38F: Recommendation for + * Block Cipher Modes of Operation: Methods for Key Wrapping. Its + * purpose is to protect cryptographic keys. + * + * Its equivalent is RFC 3394 for KW, and RFC 5649 for KWP. + * https://tools.ietf.org/html/rfc3394 + * https://tools.ietf.org/html/rfc5649 + * + */ +/* + * Copyright (C) 2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_NIST_KW_H +#define MBEDTLS_NIST_KW_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "cipher.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + MBEDTLS_KW_MODE_KW = 0, + MBEDTLS_KW_MODE_KWP = 1 +} mbedtls_nist_kw_mode_t; + +#if !defined(MBEDTLS_NIST_KW_ALT) +// Regular implementation +// + +/** + * \brief The key wrapping context-type definition. The key wrapping context is passed + * to the APIs called. + * + * \note The definition of this type may change in future library versions. + * Don't make any assumptions on this context! + */ +typedef struct { + mbedtls_cipher_context_t cipher_ctx; /*!< The cipher context used. */ +} mbedtls_nist_kw_context; + +#else /* MBEDTLS_NIST_key wrapping_ALT */ +#include "nist_kw_alt.h" +#endif /* MBEDTLS_NIST_KW_ALT */ + +/** + * \brief This function initializes the specified key wrapping context + * to make references valid and prepare the context + * for mbedtls_nist_kw_setkey() or mbedtls_nist_kw_free(). + * + * \param ctx The key wrapping context to initialize. + * + */ +void mbedtls_nist_kw_init( mbedtls_nist_kw_context *ctx ); + +/** + * \brief This function initializes the key wrapping context set in the + * \p ctx parameter and sets the encryption key. + * + * \param ctx The key wrapping context. + * \param cipher The 128-bit block cipher to use. Only AES is supported. + * \param key The Key Encryption Key (KEK). + * \param keybits The KEK size in bits. This must be acceptable by the cipher. + * \param is_wrap Specify whether the operation within the context is wrapping or unwrapping + * + * \return \c 0 on success. + * \return \c MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA for any invalid input. + * \return \c MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE for 128-bit block ciphers + * which are not supported. + * \return cipher-specific error code on failure of the underlying cipher. + */ +int mbedtls_nist_kw_setkey( mbedtls_nist_kw_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits, + const int is_wrap ); + +/** + * \brief This function releases and clears the specified key wrapping context + * and underlying cipher sub-context. + * + * \param ctx The key wrapping context to clear. + */ +void mbedtls_nist_kw_free( mbedtls_nist_kw_context *ctx ); + +/** + * \brief This function encrypts a buffer using key wrapping. + * + * \param ctx The key wrapping context to use for encryption. + * \param mode The key wrapping mode to use (MBEDTLS_KW_MODE_KW or MBEDTLS_KW_MODE_KWP) + * \param input The buffer holding the input data. + * \param in_len The length of the input data in Bytes. + * The input uses units of 8 Bytes called semiblocks. + *
  • For KW mode: a multiple of 8 bytes between 16 and 2^57-8 inclusive.
  • + *
  • For KWP mode: any length between 1 and 2^32-1 inclusive.
+ * \param[out] output The buffer holding the output data. + *
  • For KW mode: Must be at least 8 bytes larger than \p in_len.
  • + *
  • For KWP mode: Must be at least 8 bytes larger rounded up to a multiple of + * 8 bytes for KWP (15 bytes at most).
+ * \param[out] out_len The number of bytes written to the output buffer. \c 0 on failure. + * \param[in] out_size The capacity of the output buffer. + * + * \return \c 0 on success. + * \return \c MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA for invalid input length. + * \return cipher-specific error code on failure of the underlying cipher. + */ +int mbedtls_nist_kw_wrap( mbedtls_nist_kw_context *ctx, mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t in_len, + unsigned char *output, size_t* out_len, size_t out_size ); + +/** + * \brief This function decrypts a buffer using key wrapping. + * + * \param ctx The key wrapping context to use for decryption. + * \param mode The key wrapping mode to use (MBEDTLS_KW_MODE_KW or MBEDTLS_KW_MODE_KWP) + * \param input The buffer holding the input data. + * \param in_len The length of the input data in Bytes. + * The input uses units of 8 Bytes called semiblocks. + * The input must be a multiple of semiblocks. + *
  • For KW mode: a multiple of 8 bytes between 24 and 2^57 inclusive.
  • + *
  • For KWP mode: a multiple of 8 bytes between 16 and 2^32 inclusive.
+ * \param[out] output The buffer holding the output data. + * The output buffer's minimal length is 8 bytes shorter than \p in_len. + * \param[out] out_len The number of bytes written to the output buffer. \c 0 on failure. + * For KWP mode, the length could be up to 15 bytes shorter than \p in_len, + * depending on how much padding was added to the data. + * \param[in] out_size The capacity of the output buffer. + * + * \return \c 0 on success. + * \return \c MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA for invalid input length. + * \return \c MBEDTLS_ERR_CIPHER_AUTH_FAILED for verification failure of the ciphertext. + * \return cipher-specific error code on failure of the underlying cipher. + */ +int mbedtls_nist_kw_unwrap( mbedtls_nist_kw_context *ctx, mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t in_len, + unsigned char *output, size_t* out_len, size_t out_size); + + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/** + * \brief The key wrapping checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_nist_kw_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_NIST_KW_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/oid.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/oid.h new file mode 100644 index 000000000..b940e207d --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/oid.h @@ -0,0 +1,649 @@ +/** + * \file oid.h + * + * \brief Object Identifier (OID) database + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_OID_H +#define MBEDTLS_OID_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "asn1.h" +#include "pk.h" + +#include + +#if defined(MBEDTLS_CIPHER_C) +#include "cipher.h" +#endif + +#if defined(MBEDTLS_MD_C) +#include "md.h" +#endif + +#define MBEDTLS_ERR_OID_NOT_FOUND -0x002E /**< OID is not found. */ +#define MBEDTLS_ERR_OID_BUF_TOO_SMALL -0x000B /**< output buffer is too small */ + +/* This is for the benefit of X.509, but defined here in order to avoid + * having a "backwards" include of x.509.h here */ +/* + * X.509 extension types (internal, arbitrary values for bitsets) + */ +#define MBEDTLS_OID_X509_EXT_AUTHORITY_KEY_IDENTIFIER (1 << 0) +#define MBEDTLS_OID_X509_EXT_SUBJECT_KEY_IDENTIFIER (1 << 1) +#define MBEDTLS_OID_X509_EXT_KEY_USAGE (1 << 2) +#define MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES (1 << 3) +#define MBEDTLS_OID_X509_EXT_POLICY_MAPPINGS (1 << 4) +#define MBEDTLS_OID_X509_EXT_SUBJECT_ALT_NAME (1 << 5) +#define MBEDTLS_OID_X509_EXT_ISSUER_ALT_NAME (1 << 6) +#define MBEDTLS_OID_X509_EXT_SUBJECT_DIRECTORY_ATTRS (1 << 7) +#define MBEDTLS_OID_X509_EXT_BASIC_CONSTRAINTS (1 << 8) +#define MBEDTLS_OID_X509_EXT_NAME_CONSTRAINTS (1 << 9) +#define MBEDTLS_OID_X509_EXT_POLICY_CONSTRAINTS (1 << 10) +#define MBEDTLS_OID_X509_EXT_EXTENDED_KEY_USAGE (1 << 11) +#define MBEDTLS_OID_X509_EXT_CRL_DISTRIBUTION_POINTS (1 << 12) +#define MBEDTLS_OID_X509_EXT_INIHIBIT_ANYPOLICY (1 << 13) +#define MBEDTLS_OID_X509_EXT_FRESHEST_CRL (1 << 14) +#define MBEDTLS_OID_X509_EXT_NS_CERT_TYPE (1 << 16) + +/* + * Top level OID tuples + */ +#define MBEDTLS_OID_ISO_MEMBER_BODIES "\x2a" /* {iso(1) member-body(2)} */ +#define MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x2b" /* {iso(1) identified-organization(3)} */ +#define MBEDTLS_OID_ISO_CCITT_DS "\x55" /* {joint-iso-ccitt(2) ds(5)} */ +#define MBEDTLS_OID_ISO_ITU_COUNTRY "\x60" /* {joint-iso-itu-t(2) country(16)} */ + +/* + * ISO Member bodies OID parts + */ +#define MBEDTLS_OID_COUNTRY_US "\x86\x48" /* {us(840)} */ +#define MBEDTLS_OID_ORG_RSA_DATA_SECURITY "\x86\xf7\x0d" /* {rsadsi(113549)} */ +#define MBEDTLS_OID_RSA_COMPANY MBEDTLS_OID_ISO_MEMBER_BODIES MBEDTLS_OID_COUNTRY_US \ + MBEDTLS_OID_ORG_RSA_DATA_SECURITY /* {iso(1) member-body(2) us(840) rsadsi(113549)} */ +#define MBEDTLS_OID_ORG_ANSI_X9_62 "\xce\x3d" /* ansi-X9-62(10045) */ +#define MBEDTLS_OID_ANSI_X9_62 MBEDTLS_OID_ISO_MEMBER_BODIES MBEDTLS_OID_COUNTRY_US \ + MBEDTLS_OID_ORG_ANSI_X9_62 + +/* + * ISO Identified organization OID parts + */ +#define MBEDTLS_OID_ORG_DOD "\x06" /* {dod(6)} */ +#define MBEDTLS_OID_ORG_OIW "\x0e" +#define MBEDTLS_OID_OIW_SECSIG MBEDTLS_OID_ORG_OIW "\x03" +#define MBEDTLS_OID_OIW_SECSIG_ALG MBEDTLS_OID_OIW_SECSIG "\x02" +#define MBEDTLS_OID_OIW_SECSIG_SHA1 MBEDTLS_OID_OIW_SECSIG_ALG "\x1a" +#define MBEDTLS_OID_ORG_CERTICOM "\x81\x04" /* certicom(132) */ +#define MBEDTLS_OID_CERTICOM MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_CERTICOM +#define MBEDTLS_OID_ORG_TELETRUST "\x24" /* teletrust(36) */ +#define MBEDTLS_OID_TELETRUST MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_TELETRUST + +/* + * ISO ITU OID parts + */ +#define MBEDTLS_OID_ORGANIZATION "\x01" /* {organization(1)} */ +#define MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ISO_ITU_COUNTRY MBEDTLS_OID_COUNTRY_US MBEDTLS_OID_ORGANIZATION /* {joint-iso-itu-t(2) country(16) us(840) organization(1)} */ + +#define MBEDTLS_OID_ORG_GOV "\x65" /* {gov(101)} */ +#define MBEDTLS_OID_GOV MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ORG_GOV /* {joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)} */ + +#define MBEDTLS_OID_ORG_NETSCAPE "\x86\xF8\x42" /* {netscape(113730)} */ +#define MBEDTLS_OID_NETSCAPE MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ORG_NETSCAPE /* Netscape OID {joint-iso-itu-t(2) country(16) us(840) organization(1) netscape(113730)} */ + +/* ISO arc for standard certificate and CRL extensions */ +#define MBEDTLS_OID_ID_CE MBEDTLS_OID_ISO_CCITT_DS "\x1D" /**< id-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29} */ + +#define MBEDTLS_OID_NIST_ALG MBEDTLS_OID_GOV "\x03\x04" /** { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithm(4) */ + +/** + * Private Internet Extensions + * { iso(1) identified-organization(3) dod(6) internet(1) + * security(5) mechanisms(5) pkix(7) } + */ +#define MBEDTLS_OID_INTERNET MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_DOD "\x01" +#define MBEDTLS_OID_PKIX MBEDTLS_OID_INTERNET "\x05\x05\x07" + +/* + * Arc for standard naming attributes + */ +#define MBEDTLS_OID_AT MBEDTLS_OID_ISO_CCITT_DS "\x04" /**< id-at OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 4} */ +#define MBEDTLS_OID_AT_CN MBEDTLS_OID_AT "\x03" /**< id-at-commonName AttributeType:= {id-at 3} */ +#define MBEDTLS_OID_AT_SUR_NAME MBEDTLS_OID_AT "\x04" /**< id-at-surName AttributeType:= {id-at 4} */ +#define MBEDTLS_OID_AT_SERIAL_NUMBER MBEDTLS_OID_AT "\x05" /**< id-at-serialNumber AttributeType:= {id-at 5} */ +#define MBEDTLS_OID_AT_COUNTRY MBEDTLS_OID_AT "\x06" /**< id-at-countryName AttributeType:= {id-at 6} */ +#define MBEDTLS_OID_AT_LOCALITY MBEDTLS_OID_AT "\x07" /**< id-at-locality AttributeType:= {id-at 7} */ +#define MBEDTLS_OID_AT_STATE MBEDTLS_OID_AT "\x08" /**< id-at-state AttributeType:= {id-at 8} */ +#define MBEDTLS_OID_AT_ORGANIZATION MBEDTLS_OID_AT "\x0A" /**< id-at-organizationName AttributeType:= {id-at 10} */ +#define MBEDTLS_OID_AT_ORG_UNIT MBEDTLS_OID_AT "\x0B" /**< id-at-organizationalUnitName AttributeType:= {id-at 11} */ +#define MBEDTLS_OID_AT_TITLE MBEDTLS_OID_AT "\x0C" /**< id-at-title AttributeType:= {id-at 12} */ +#define MBEDTLS_OID_AT_POSTAL_ADDRESS MBEDTLS_OID_AT "\x10" /**< id-at-postalAddress AttributeType:= {id-at 16} */ +#define MBEDTLS_OID_AT_POSTAL_CODE MBEDTLS_OID_AT "\x11" /**< id-at-postalCode AttributeType:= {id-at 17} */ +#define MBEDTLS_OID_AT_GIVEN_NAME MBEDTLS_OID_AT "\x2A" /**< id-at-givenName AttributeType:= {id-at 42} */ +#define MBEDTLS_OID_AT_INITIALS MBEDTLS_OID_AT "\x2B" /**< id-at-initials AttributeType:= {id-at 43} */ +#define MBEDTLS_OID_AT_GENERATION_QUALIFIER MBEDTLS_OID_AT "\x2C" /**< id-at-generationQualifier AttributeType:= {id-at 44} */ +#define MBEDTLS_OID_AT_UNIQUE_IDENTIFIER MBEDTLS_OID_AT "\x2D" /**< id-at-uniqueIdentifier AttributType:= {id-at 45} */ +#define MBEDTLS_OID_AT_DN_QUALIFIER MBEDTLS_OID_AT "\x2E" /**< id-at-dnQualifier AttributeType:= {id-at 46} */ +#define MBEDTLS_OID_AT_PSEUDONYM MBEDTLS_OID_AT "\x41" /**< id-at-pseudonym AttributeType:= {id-at 65} */ + +#define MBEDTLS_OID_DOMAIN_COMPONENT "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x19" /** id-domainComponent AttributeType:= {itu-t(0) data(9) pss(2342) ucl(19200300) pilot(100) pilotAttributeType(1) domainComponent(25)} */ + +/* + * OIDs for standard certificate extensions + */ +#define MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER MBEDTLS_OID_ID_CE "\x23" /**< id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } */ +#define MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER MBEDTLS_OID_ID_CE "\x0E" /**< id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 14 } */ +#define MBEDTLS_OID_KEY_USAGE MBEDTLS_OID_ID_CE "\x0F" /**< id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } */ +#define MBEDTLS_OID_CERTIFICATE_POLICIES MBEDTLS_OID_ID_CE "\x20" /**< id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } */ +#define MBEDTLS_OID_POLICY_MAPPINGS MBEDTLS_OID_ID_CE "\x21" /**< id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 } */ +#define MBEDTLS_OID_SUBJECT_ALT_NAME MBEDTLS_OID_ID_CE "\x11" /**< id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } */ +#define MBEDTLS_OID_ISSUER_ALT_NAME MBEDTLS_OID_ID_CE "\x12" /**< id-ce-issuerAltName OBJECT IDENTIFIER ::= { id-ce 18 } */ +#define MBEDTLS_OID_SUBJECT_DIRECTORY_ATTRS MBEDTLS_OID_ID_CE "\x09" /**< id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-ce 9 } */ +#define MBEDTLS_OID_BASIC_CONSTRAINTS MBEDTLS_OID_ID_CE "\x13" /**< id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } */ +#define MBEDTLS_OID_NAME_CONSTRAINTS MBEDTLS_OID_ID_CE "\x1E" /**< id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 } */ +#define MBEDTLS_OID_POLICY_CONSTRAINTS MBEDTLS_OID_ID_CE "\x24" /**< id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 } */ +#define MBEDTLS_OID_EXTENDED_KEY_USAGE MBEDTLS_OID_ID_CE "\x25" /**< id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 } */ +#define MBEDTLS_OID_CRL_DISTRIBUTION_POINTS MBEDTLS_OID_ID_CE "\x1F" /**< id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 } */ +#define MBEDTLS_OID_INIHIBIT_ANYPOLICY MBEDTLS_OID_ID_CE "\x36" /**< id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 } */ +#define MBEDTLS_OID_FRESHEST_CRL MBEDTLS_OID_ID_CE "\x2E" /**< id-ce-freshestCRL OBJECT IDENTIFIER ::= { id-ce 46 } */ + +/* + * Certificate policies + */ +#define MBEDTLS_OID_ANY_POLICY MBEDTLS_OID_CERTIFICATE_POLICIES "\x00" /**< anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 } */ + +/* + * Netscape certificate extensions + */ +#define MBEDTLS_OID_NS_CERT MBEDTLS_OID_NETSCAPE "\x01" +#define MBEDTLS_OID_NS_CERT_TYPE MBEDTLS_OID_NS_CERT "\x01" +#define MBEDTLS_OID_NS_BASE_URL MBEDTLS_OID_NS_CERT "\x02" +#define MBEDTLS_OID_NS_REVOCATION_URL MBEDTLS_OID_NS_CERT "\x03" +#define MBEDTLS_OID_NS_CA_REVOCATION_URL MBEDTLS_OID_NS_CERT "\x04" +#define MBEDTLS_OID_NS_RENEWAL_URL MBEDTLS_OID_NS_CERT "\x07" +#define MBEDTLS_OID_NS_CA_POLICY_URL MBEDTLS_OID_NS_CERT "\x08" +#define MBEDTLS_OID_NS_SSL_SERVER_NAME MBEDTLS_OID_NS_CERT "\x0C" +#define MBEDTLS_OID_NS_COMMENT MBEDTLS_OID_NS_CERT "\x0D" +#define MBEDTLS_OID_NS_DATA_TYPE MBEDTLS_OID_NETSCAPE "\x02" +#define MBEDTLS_OID_NS_CERT_SEQUENCE MBEDTLS_OID_NS_DATA_TYPE "\x05" + +/* + * OIDs for CRL extensions + */ +#define MBEDTLS_OID_PRIVATE_KEY_USAGE_PERIOD MBEDTLS_OID_ID_CE "\x10" +#define MBEDTLS_OID_CRL_NUMBER MBEDTLS_OID_ID_CE "\x14" /**< id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 } */ + +/* + * X.509 v3 Extended key usage OIDs + */ +#define MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE MBEDTLS_OID_EXTENDED_KEY_USAGE "\x00" /**< anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } */ + +#define MBEDTLS_OID_KP MBEDTLS_OID_PKIX "\x03" /**< id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } */ +#define MBEDTLS_OID_SERVER_AUTH MBEDTLS_OID_KP "\x01" /**< id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } */ +#define MBEDTLS_OID_CLIENT_AUTH MBEDTLS_OID_KP "\x02" /**< id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } */ +#define MBEDTLS_OID_CODE_SIGNING MBEDTLS_OID_KP "\x03" /**< id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } */ +#define MBEDTLS_OID_EMAIL_PROTECTION MBEDTLS_OID_KP "\x04" /**< id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } */ +#define MBEDTLS_OID_TIME_STAMPING MBEDTLS_OID_KP "\x08" /**< id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } */ +#define MBEDTLS_OID_OCSP_SIGNING MBEDTLS_OID_KP "\x09" /**< id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } */ + +/** + * Wi-SUN Alliance Field Area Network + * { iso(1) identified-organization(3) dod(6) internet(1) + * private(4) enterprise(1) WiSUN(45605) FieldAreaNetwork(1) } + */ +#define MBEDTLS_OID_WISUN_FAN MBEDTLS_OID_INTERNET "\x04\x01\x82\xe4\x25\x01" + +#define MBEDTLS_OID_ON MBEDTLS_OID_PKIX "\x08" /**< id-on OBJECT IDENTIFIER ::= { id-pkix 8 } */ +#define MBEDTLS_OID_ON_HW_MODULE_NAME MBEDTLS_OID_ON "\x04" /**< id-on-hardwareModuleName OBJECT IDENTIFIER ::= { id-on 4 } */ + +/* + * PKCS definition OIDs + */ + +#define MBEDTLS_OID_PKCS MBEDTLS_OID_RSA_COMPANY "\x01" /**< pkcs OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) 1 } */ +#define MBEDTLS_OID_PKCS1 MBEDTLS_OID_PKCS "\x01" /**< pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } */ +#define MBEDTLS_OID_PKCS5 MBEDTLS_OID_PKCS "\x05" /**< pkcs-5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 } */ +#define MBEDTLS_OID_PKCS9 MBEDTLS_OID_PKCS "\x09" /**< pkcs-9 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } */ +#define MBEDTLS_OID_PKCS12 MBEDTLS_OID_PKCS "\x0c" /**< pkcs-12 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 } */ + +/* + * PKCS#1 OIDs + */ +#define MBEDTLS_OID_PKCS1_RSA MBEDTLS_OID_PKCS1 "\x01" /**< rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 } */ +#define MBEDTLS_OID_PKCS1_MD2 MBEDTLS_OID_PKCS1 "\x02" /**< md2WithRSAEncryption ::= { pkcs-1 2 } */ +#define MBEDTLS_OID_PKCS1_MD4 MBEDTLS_OID_PKCS1 "\x03" /**< md4WithRSAEncryption ::= { pkcs-1 3 } */ +#define MBEDTLS_OID_PKCS1_MD5 MBEDTLS_OID_PKCS1 "\x04" /**< md5WithRSAEncryption ::= { pkcs-1 4 } */ +#define MBEDTLS_OID_PKCS1_SHA1 MBEDTLS_OID_PKCS1 "\x05" /**< sha1WithRSAEncryption ::= { pkcs-1 5 } */ +#define MBEDTLS_OID_PKCS1_SHA224 MBEDTLS_OID_PKCS1 "\x0e" /**< sha224WithRSAEncryption ::= { pkcs-1 14 } */ +#define MBEDTLS_OID_PKCS1_SHA256 MBEDTLS_OID_PKCS1 "\x0b" /**< sha256WithRSAEncryption ::= { pkcs-1 11 } */ +#define MBEDTLS_OID_PKCS1_SHA384 MBEDTLS_OID_PKCS1 "\x0c" /**< sha384WithRSAEncryption ::= { pkcs-1 12 } */ +#define MBEDTLS_OID_PKCS1_SHA512 MBEDTLS_OID_PKCS1 "\x0d" /**< sha512WithRSAEncryption ::= { pkcs-1 13 } */ + +#define MBEDTLS_OID_RSA_SHA_OBS "\x2B\x0E\x03\x02\x1D" + +#define MBEDTLS_OID_PKCS9_EMAIL MBEDTLS_OID_PKCS9 "\x01" /**< emailAddress AttributeType ::= { pkcs-9 1 } */ + +/* RFC 4055 */ +#define MBEDTLS_OID_RSASSA_PSS MBEDTLS_OID_PKCS1 "\x0a" /**< id-RSASSA-PSS ::= { pkcs-1 10 } */ +#define MBEDTLS_OID_MGF1 MBEDTLS_OID_PKCS1 "\x08" /**< id-mgf1 ::= { pkcs-1 8 } */ + +/* + * Digest algorithms + */ +#define MBEDTLS_OID_DIGEST_ALG_MD2 MBEDTLS_OID_RSA_COMPANY "\x02\x02" /**< id-mbedtls_md2 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 2 } */ +#define MBEDTLS_OID_DIGEST_ALG_MD4 MBEDTLS_OID_RSA_COMPANY "\x02\x04" /**< id-mbedtls_md4 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 4 } */ +#define MBEDTLS_OID_DIGEST_ALG_MD5 MBEDTLS_OID_RSA_COMPANY "\x02\x05" /**< id-mbedtls_md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA1 MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_OIW_SECSIG_SHA1 /**< id-mbedtls_sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA224 MBEDTLS_OID_NIST_ALG "\x02\x04" /**< id-sha224 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 4 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA256 MBEDTLS_OID_NIST_ALG "\x02\x01" /**< id-mbedtls_sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1 } */ + +#define MBEDTLS_OID_DIGEST_ALG_SHA384 MBEDTLS_OID_NIST_ALG "\x02\x02" /**< id-sha384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 2 } */ + +#define MBEDTLS_OID_DIGEST_ALG_SHA512 MBEDTLS_OID_NIST_ALG "\x02\x03" /**< id-mbedtls_sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3 } */ + +#define MBEDTLS_OID_DIGEST_ALG_RIPEMD160 MBEDTLS_OID_TELETRUST "\x03\x02\x01" /**< id-ripemd160 OBJECT IDENTIFIER :: { iso(1) identified-organization(3) teletrust(36) algorithm(3) hashAlgorithm(2) ripemd160(1) } */ + +#define MBEDTLS_OID_HMAC_SHA1 MBEDTLS_OID_RSA_COMPANY "\x02\x07" /**< id-hmacWithSHA1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 7 } */ + +#define MBEDTLS_OID_HMAC_SHA224 MBEDTLS_OID_RSA_COMPANY "\x02\x08" /**< id-hmacWithSHA224 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 8 } */ + +#define MBEDTLS_OID_HMAC_SHA256 MBEDTLS_OID_RSA_COMPANY "\x02\x09" /**< id-hmacWithSHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 9 } */ + +#define MBEDTLS_OID_HMAC_SHA384 MBEDTLS_OID_RSA_COMPANY "\x02\x0A" /**< id-hmacWithSHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 10 } */ + +#define MBEDTLS_OID_HMAC_SHA512 MBEDTLS_OID_RSA_COMPANY "\x02\x0B" /**< id-hmacWithSHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 11 } */ + +/* + * Encryption algorithms + */ +#define MBEDTLS_OID_DES_CBC MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_OIW_SECSIG_ALG "\x07" /**< desCBC OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 7 } */ +#define MBEDTLS_OID_DES_EDE3_CBC MBEDTLS_OID_RSA_COMPANY "\x03\x07" /**< des-ede3-cbc OBJECT IDENTIFIER ::= { iso(1) member-body(2) -- us(840) rsadsi(113549) encryptionAlgorithm(3) 7 } */ +#define MBEDTLS_OID_AES MBEDTLS_OID_NIST_ALG "\x01" /** aes OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithm(4) 1 } */ + +/* + * Key Wrapping algorithms + */ +/* + * RFC 5649 + */ +#define MBEDTLS_OID_AES128_KW MBEDTLS_OID_AES "\x05" /** id-aes128-wrap OBJECT IDENTIFIER ::= { aes 5 } */ +#define MBEDTLS_OID_AES128_KWP MBEDTLS_OID_AES "\x08" /** id-aes128-wrap-pad OBJECT IDENTIFIER ::= { aes 8 } */ +#define MBEDTLS_OID_AES192_KW MBEDTLS_OID_AES "\x19" /** id-aes192-wrap OBJECT IDENTIFIER ::= { aes 25 } */ +#define MBEDTLS_OID_AES192_KWP MBEDTLS_OID_AES "\x1c" /** id-aes192-wrap-pad OBJECT IDENTIFIER ::= { aes 28 } */ +#define MBEDTLS_OID_AES256_KW MBEDTLS_OID_AES "\x2d" /** id-aes256-wrap OBJECT IDENTIFIER ::= { aes 45 } */ +#define MBEDTLS_OID_AES256_KWP MBEDTLS_OID_AES "\x30" /** id-aes256-wrap-pad OBJECT IDENTIFIER ::= { aes 48 } */ +/* + * PKCS#5 OIDs + */ +#define MBEDTLS_OID_PKCS5_PBKDF2 MBEDTLS_OID_PKCS5 "\x0c" /**< id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} */ +#define MBEDTLS_OID_PKCS5_PBES2 MBEDTLS_OID_PKCS5 "\x0d" /**< id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13} */ +#define MBEDTLS_OID_PKCS5_PBMAC1 MBEDTLS_OID_PKCS5 "\x0e" /**< id-PBMAC1 OBJECT IDENTIFIER ::= {pkcs-5 14} */ + +/* + * PKCS#5 PBES1 algorithms + */ +#define MBEDTLS_OID_PKCS5_PBE_MD2_DES_CBC MBEDTLS_OID_PKCS5 "\x01" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ +#define MBEDTLS_OID_PKCS5_PBE_MD2_RC2_CBC MBEDTLS_OID_PKCS5 "\x04" /**< pbeWithMD2AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 4} */ +#define MBEDTLS_OID_PKCS5_PBE_MD5_DES_CBC MBEDTLS_OID_PKCS5 "\x03" /**< pbeWithMD5AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 3} */ +#define MBEDTLS_OID_PKCS5_PBE_MD5_RC2_CBC MBEDTLS_OID_PKCS5 "\x06" /**< pbeWithMD5AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 6} */ +#define MBEDTLS_OID_PKCS5_PBE_SHA1_DES_CBC MBEDTLS_OID_PKCS5 "\x0a" /**< pbeWithSHA1AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 10} */ +#define MBEDTLS_OID_PKCS5_PBE_SHA1_RC2_CBC MBEDTLS_OID_PKCS5 "\x0b" /**< pbeWithSHA1AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 11} */ + +/* + * PKCS#8 OIDs + */ +#define MBEDTLS_OID_PKCS9_CSR_EXT_REQ MBEDTLS_OID_PKCS9 "\x0e" /**< extensionRequest OBJECT IDENTIFIER ::= {pkcs-9 14} */ + +/* + * PKCS#12 PBE OIDs + */ +#define MBEDTLS_OID_PKCS12_PBE MBEDTLS_OID_PKCS12 "\x01" /**< pkcs-12PbeIds OBJECT IDENTIFIER ::= {pkcs-12 1} */ + +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128 MBEDTLS_OID_PKCS12_PBE "\x01" /**< pbeWithSHAAnd128BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 1} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_40 MBEDTLS_OID_PKCS12_PBE "\x02" /**< pbeWithSHAAnd40BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 2} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC MBEDTLS_OID_PKCS12_PBE "\x03" /**< pbeWithSHAAnd3-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 3} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC MBEDTLS_OID_PKCS12_PBE "\x04" /**< pbeWithSHAAnd2-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 4} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_128_CBC MBEDTLS_OID_PKCS12_PBE "\x05" /**< pbeWithSHAAnd128BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 5} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_40_CBC MBEDTLS_OID_PKCS12_PBE "\x06" /**< pbeWithSHAAnd40BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 6} */ + +/* + * EC key algorithms from RFC 5480 + */ + +/* id-ecPublicKey OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } */ +#define MBEDTLS_OID_EC_ALG_UNRESTRICTED MBEDTLS_OID_ANSI_X9_62 "\x02\01" + +/* id-ecDH OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) + * schemes(1) ecdh(12) } */ +#define MBEDTLS_OID_EC_ALG_ECDH MBEDTLS_OID_CERTICOM "\x01\x0c" + +/* + * ECParameters namedCurve identifiers, from RFC 5480, RFC 5639, and SEC2 + */ + +/* secp192r1 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 1 } */ +#define MBEDTLS_OID_EC_GRP_SECP192R1 MBEDTLS_OID_ANSI_X9_62 "\x03\x01\x01" + +/* secp224r1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 33 } */ +#define MBEDTLS_OID_EC_GRP_SECP224R1 MBEDTLS_OID_CERTICOM "\x00\x21" + +/* secp256r1 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 7 } */ +#define MBEDTLS_OID_EC_GRP_SECP256R1 MBEDTLS_OID_ANSI_X9_62 "\x03\x01\x07" + +/* secp384r1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 34 } */ +#define MBEDTLS_OID_EC_GRP_SECP384R1 MBEDTLS_OID_CERTICOM "\x00\x22" + +/* secp521r1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 35 } */ +#define MBEDTLS_OID_EC_GRP_SECP521R1 MBEDTLS_OID_CERTICOM "\x00\x23" + +/* secp192k1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 31 } */ +#define MBEDTLS_OID_EC_GRP_SECP192K1 MBEDTLS_OID_CERTICOM "\x00\x1f" + +/* secp224k1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 32 } */ +#define MBEDTLS_OID_EC_GRP_SECP224K1 MBEDTLS_OID_CERTICOM "\x00\x20" + +/* secp256k1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 10 } */ +#define MBEDTLS_OID_EC_GRP_SECP256K1 MBEDTLS_OID_CERTICOM "\x00\x0a" + +/* RFC 5639 4.1 + * ecStdCurvesAndGeneration OBJECT IDENTIFIER::= {iso(1) + * identified-organization(3) teletrust(36) algorithm(3) signature- + * algorithm(3) ecSign(2) 8} + * ellipticCurve OBJECT IDENTIFIER ::= {ecStdCurvesAndGeneration 1} + * versionOne OBJECT IDENTIFIER ::= {ellipticCurve 1} */ +#define MBEDTLS_OID_EC_BRAINPOOL_V1 MBEDTLS_OID_TELETRUST "\x03\x03\x02\x08\x01\x01" + +/* brainpoolP256r1 OBJECT IDENTIFIER ::= {versionOne 7} */ +#define MBEDTLS_OID_EC_GRP_BP256R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x07" + +/* brainpoolP384r1 OBJECT IDENTIFIER ::= {versionOne 11} */ +#define MBEDTLS_OID_EC_GRP_BP384R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x0B" + +/* brainpoolP512r1 OBJECT IDENTIFIER ::= {versionOne 13} */ +#define MBEDTLS_OID_EC_GRP_BP512R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x0D" + +/* + * SEC1 C.1 + * + * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 } + * id-fieldType OBJECT IDENTIFIER ::= { ansi-X9-62 fieldType(1)} + */ +#define MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE MBEDTLS_OID_ANSI_X9_62 "\x01" +#define MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE "\x01" + +/* + * ECDSA signature identifiers, from RFC 5480 + */ +#define MBEDTLS_OID_ANSI_X9_62_SIG MBEDTLS_OID_ANSI_X9_62 "\x04" /* signatures(4) */ +#define MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 MBEDTLS_OID_ANSI_X9_62_SIG "\x03" /* ecdsa-with-SHA2(3) */ + +/* ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) 1 } */ +#define MBEDTLS_OID_ECDSA_SHA1 MBEDTLS_OID_ANSI_X9_62_SIG "\x01" + +/* ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 1 } */ +#define MBEDTLS_OID_ECDSA_SHA224 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x01" + +/* ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 2 } */ +#define MBEDTLS_OID_ECDSA_SHA256 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x02" + +/* ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 3 } */ +#define MBEDTLS_OID_ECDSA_SHA384 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x03" + +/* ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 4 } */ +#define MBEDTLS_OID_ECDSA_SHA512 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x04" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Base OID descriptor structure + */ +typedef struct mbedtls_oid_descriptor_t +{ + const char *asn1; /*!< OID ASN.1 representation */ + size_t asn1_len; /*!< length of asn1 */ + const char *name; /*!< official name (e.g. from RFC) */ + const char *description; /*!< human friendly description */ +} mbedtls_oid_descriptor_t; + +/** + * \brief Translate an ASN.1 OID into its numeric representation + * (e.g. "\x2A\x86\x48\x86\xF7\x0D" into "1.2.840.113549") + * + * \param buf buffer to put representation in + * \param size size of the buffer + * \param oid OID to translate + * + * \return Length of the string written (excluding final NULL) or + * MBEDTLS_ERR_OID_BUF_TOO_SMALL in case of error + */ +int mbedtls_oid_get_numeric_string( char *buf, size_t size, const mbedtls_asn1_buf *oid ); + +/** + * \brief Translate an X.509 extension OID into local values + * + * \param oid OID to use + * \param ext_type place to store the extension type + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_x509_ext_type( const mbedtls_asn1_buf *oid, int *ext_type ); + +/** + * \brief Translate an X.509 attribute type OID into the short name + * (e.g. the OID for an X520 Common Name into "CN") + * + * \param oid OID to use + * \param short_name place to store the string pointer + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_attr_short_name( const mbedtls_asn1_buf *oid, const char **short_name ); + +/** + * \brief Translate PublicKeyAlgorithm OID into pk_type + * + * \param oid OID to use + * \param pk_alg place to store public key algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_pk_alg( const mbedtls_asn1_buf *oid, mbedtls_pk_type_t *pk_alg ); + +/** + * \brief Translate pk_type into PublicKeyAlgorithm OID + * + * \param pk_alg Public key type to look for + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_type_t pk_alg, + const char **oid, size_t *olen ); + +#if defined(MBEDTLS_ECP_C) +/** + * \brief Translate NamedCurve OID into an EC group identifier + * + * \param oid OID to use + * \param grp_id place to store group id + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_ec_grp( const mbedtls_asn1_buf *oid, mbedtls_ecp_group_id *grp_id ); + +/** + * \brief Translate EC group identifier into NamedCurve OID + * + * \param grp_id EC group identifier + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_ec_grp( mbedtls_ecp_group_id grp_id, + const char **oid, size_t *olen ); +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_MD_C) +/** + * \brief Translate SignatureAlgorithm OID into md_type and pk_type + * + * \param oid OID to use + * \param md_alg place to store message digest algorithm + * \param pk_alg place to store public key algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_sig_alg( const mbedtls_asn1_buf *oid, + mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg ); + +/** + * \brief Translate SignatureAlgorithm OID into description + * + * \param oid OID to use + * \param desc place to store string pointer + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_sig_alg_desc( const mbedtls_asn1_buf *oid, const char **desc ); + +/** + * \brief Translate md_type and pk_type into SignatureAlgorithm OID + * + * \param md_alg message digest algorithm + * \param pk_alg public key algorithm + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_sig_alg( mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, + const char **oid, size_t *olen ); + +/** + * \brief Translate hash algorithm OID into md_type + * + * \param oid OID to use + * \param md_alg place to store message digest algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_md_alg( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_alg ); + +/** + * \brief Translate hmac algorithm OID into md_type + * + * \param oid OID to use + * \param md_hmac place to store message hmac algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_md_hmac( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_hmac ); +#endif /* MBEDTLS_MD_C */ + +/** + * \brief Translate Extended Key Usage OID into description + * + * \param oid OID to use + * \param desc place to store string pointer + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_extended_key_usage( const mbedtls_asn1_buf *oid, const char **desc ); + +/** + * \brief Translate certificate policies OID into description + * + * \param oid OID to use + * \param desc place to store string pointer + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_certificate_policies( const mbedtls_asn1_buf *oid, const char **desc ); + +/** + * \brief Translate md_type into hash algorithm OID + * + * \param md_alg message digest algorithm + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_md( mbedtls_md_type_t md_alg, const char **oid, size_t *olen ); + +#if defined(MBEDTLS_CIPHER_C) +/** + * \brief Translate encryption algorithm OID into cipher_type + * + * \param oid OID to use + * \param cipher_alg place to store cipher algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_cipher_alg( const mbedtls_asn1_buf *oid, mbedtls_cipher_type_t *cipher_alg ); +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_PKCS12_C) +/** + * \brief Translate PKCS#12 PBE algorithm OID into md_type and + * cipher_type + * + * \param oid OID to use + * \param md_alg place to store message digest algorithm + * \param cipher_alg place to store cipher algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_pkcs12_pbe_alg( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_alg, + mbedtls_cipher_type_t *cipher_alg ); +#endif /* MBEDTLS_PKCS12_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* oid.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/padlock.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/padlock.h new file mode 100644 index 000000000..2b9b5aa10 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/padlock.h @@ -0,0 +1,126 @@ +/** + * \file padlock.h + * + * \brief VIA PadLock ACE for HW encryption/decryption supported by some + * processors + * + * \warning These functions are only for internal use by other library + * functions; you must not call them directly. + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PADLOCK_H +#define MBEDTLS_PADLOCK_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "aes.h" + +#define MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED -0x0030 /**< Input data should be aligned. */ + +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define MBEDTLS_HAVE_ASAN +#endif +#endif + +/* Some versions of ASan result in errors about not enough registers */ +#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && defined(__i386__) && \ + !defined(MBEDTLS_HAVE_ASAN) + +#ifndef MBEDTLS_HAVE_X86 +#define MBEDTLS_HAVE_X86 +#endif + +#include + +#define MBEDTLS_PADLOCK_RNG 0x000C +#define MBEDTLS_PADLOCK_ACE 0x00C0 +#define MBEDTLS_PADLOCK_PHE 0x0C00 +#define MBEDTLS_PADLOCK_PMM 0x3000 + +#define MBEDTLS_PADLOCK_ALIGN16(x) (uint32_t *) (16 + ((int32_t) (x) & ~15)) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Internal PadLock detection routine + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. + * + * \param feature The feature to detect + * + * \return 1 if CPU has support for the feature, 0 otherwise + */ +int mbedtls_padlock_has_support( int feature ); + +/** + * \brief Internal PadLock AES-ECB block en(de)cryption + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if success, 1 if operation failed + */ +int mbedtls_padlock_xcryptecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief Internal PadLock AES-CBC buffer en(de)cryption + * + * \note This function is only for internal use by other library + * functions; you must not call it directly. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if success, 1 if operation failed + */ +int mbedtls_padlock_xcryptcbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#endif /* HAVE_X86 */ + +#endif /* padlock.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pem.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pem.h new file mode 100644 index 000000000..c52a2168f --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pem.h @@ -0,0 +1,136 @@ +/** + * \file pem.h + * + * \brief Privacy Enhanced Mail (PEM) decoding + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PEM_H +#define MBEDTLS_PEM_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +/** + * \name PEM Error codes + * These error codes are returned in case of errors reading the + * PEM data. + * \{ + */ +#define MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT -0x1080 /**< No PEM header or footer found. */ +#define MBEDTLS_ERR_PEM_INVALID_DATA -0x1100 /**< PEM string is not as expected. */ +#define MBEDTLS_ERR_PEM_ALLOC_FAILED -0x1180 /**< Failed to allocate memory. */ +#define MBEDTLS_ERR_PEM_INVALID_ENC_IV -0x1200 /**< RSA IV is not in hex-format. */ +#define MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG -0x1280 /**< Unsupported key encryption algorithm. */ +#define MBEDTLS_ERR_PEM_PASSWORD_REQUIRED -0x1300 /**< Private key password can't be empty. */ +#define MBEDTLS_ERR_PEM_PASSWORD_MISMATCH -0x1380 /**< Given private key password does not allow for correct decryption. */ +#define MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE -0x1400 /**< Unavailable feature, e.g. hashing/encryption combination. */ +#define MBEDTLS_ERR_PEM_BAD_INPUT_DATA -0x1480 /**< Bad input parameters to function. */ +/* \} name */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) +/** + * \brief PEM context structure + */ +typedef struct mbedtls_pem_context +{ + unsigned char *buf; /*!< buffer for decoded data */ + size_t buflen; /*!< length of the buffer */ + unsigned char *info; /*!< buffer for extra header information */ +} +mbedtls_pem_context; + +/** + * \brief PEM context setup + * + * \param ctx context to be initialized + */ +void mbedtls_pem_init( mbedtls_pem_context *ctx ); + +/** + * \brief Read a buffer for PEM information and store the resulting + * data into the specified context buffers. + * + * \param ctx context to use + * \param header header string to seek and expect + * \param footer footer string to seek and expect + * \param data source data to look in (must be nul-terminated) + * \param pwd password for decryption (can be NULL) + * \param pwdlen length of password + * \param use_len destination for total length used (set after header is + * correctly read, so unless you get + * MBEDTLS_ERR_PEM_BAD_INPUT_DATA or + * MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT, use_len is + * the length to skip) + * + * \note Attempts to check password correctness by verifying if + * the decrypted text starts with an ASN.1 sequence of + * appropriate length + * + * \return 0 on success, or a specific PEM error code + */ +int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const char *footer, + const unsigned char *data, + const unsigned char *pwd, + size_t pwdlen, size_t *use_len ); + +/** + * \brief PEM context memory freeing + * + * \param ctx context to be freed + */ +void mbedtls_pem_free( mbedtls_pem_context *ctx ); +#endif /* MBEDTLS_PEM_PARSE_C */ + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a buffer of PEM information from a DER encoded + * buffer. + * + * \param header header string to write + * \param footer footer string to write + * \param der_data DER data to write + * \param der_len length of the DER data + * \param buf buffer to write to + * \param buf_len length of output buffer + * \param olen total length written / required (if buf_len is not enough) + * + * \return 0 on success, or a specific PEM or BASE64 error code. On + * MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL olen is the required + * size. + */ +int mbedtls_pem_write_buffer( const char *header, const char *footer, + const unsigned char *der_data, size_t der_len, + unsigned char *buf, size_t buf_len, size_t *olen ); +#endif /* MBEDTLS_PEM_WRITE_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* pem.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pk.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pk.h new file mode 100644 index 000000000..cc1daa9ef --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pk.h @@ -0,0 +1,818 @@ +/** + * \file pk.h + * + * \brief Public Key abstraction layer + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_PK_H +#define MBEDTLS_PK_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "md.h" + +#if defined(MBEDTLS_RSA_C) +#include "rsa.h" +#endif + +#if defined(MBEDTLS_ECP_C) +#include "ecp.h" +#endif + +#if defined(MBEDTLS_ECDSA_C) +#include "ecdsa.h" +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "psa/crypto.h" +#endif + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#define MBEDTLS_ERR_PK_ALLOC_FAILED -0x3F80 /**< Memory allocation failed. */ +#define MBEDTLS_ERR_PK_TYPE_MISMATCH -0x3F00 /**< Type mismatch, eg attempt to encrypt with an ECDSA key */ +#define MBEDTLS_ERR_PK_BAD_INPUT_DATA -0x3E80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_PK_FILE_IO_ERROR -0x3E00 /**< Read/write of file failed. */ +#define MBEDTLS_ERR_PK_KEY_INVALID_VERSION -0x3D80 /**< Unsupported key version */ +#define MBEDTLS_ERR_PK_KEY_INVALID_FORMAT -0x3D00 /**< Invalid key tag or value. */ +#define MBEDTLS_ERR_PK_UNKNOWN_PK_ALG -0x3C80 /**< Key algorithm is unsupported (only RSA and EC are supported). */ +#define MBEDTLS_ERR_PK_PASSWORD_REQUIRED -0x3C00 /**< Private key password can't be empty. */ +#define MBEDTLS_ERR_PK_PASSWORD_MISMATCH -0x3B80 /**< Given private key password does not allow for correct decryption. */ +#define MBEDTLS_ERR_PK_INVALID_PUBKEY -0x3B00 /**< The pubkey tag or value is invalid (only RSA and EC are supported). */ +#define MBEDTLS_ERR_PK_INVALID_ALG -0x3A80 /**< The algorithm tag or value is invalid. */ +#define MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE -0x3A00 /**< Elliptic curve is unsupported (only NIST curves are supported). */ +#define MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE -0x3980 /**< Unavailable feature, e.g. RSA disabled for RSA key. */ +#define MBEDTLS_ERR_PK_SIG_LEN_MISMATCH -0x3900 /**< The buffer contains a valid signature followed by more data. */ + +/* MBEDTLS_ERR_PK_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_PK_HW_ACCEL_FAILED -0x3880 /**< PK hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Public key types + */ +typedef enum { + MBEDTLS_PK_NONE=0, + MBEDTLS_PK_RSA, + MBEDTLS_PK_ECKEY, + MBEDTLS_PK_ECKEY_DH, + MBEDTLS_PK_ECDSA, + MBEDTLS_PK_RSA_ALT, + MBEDTLS_PK_RSASSA_PSS, + MBEDTLS_PK_OPAQUE, +} mbedtls_pk_type_t; + +/** + * \brief Options for RSASSA-PSS signature verification. + * See \c mbedtls_rsa_rsassa_pss_verify_ext() + */ +typedef struct mbedtls_pk_rsassa_pss_options +{ + mbedtls_md_type_t mgf1_hash_id; + int expected_salt_len; + +} mbedtls_pk_rsassa_pss_options; + +/** + * \brief Types for interfacing with the debug module + */ +typedef enum +{ + MBEDTLS_PK_DEBUG_NONE = 0, + MBEDTLS_PK_DEBUG_MPI, + MBEDTLS_PK_DEBUG_ECP, +} mbedtls_pk_debug_type; + +/** + * \brief Item to send to the debug module + */ +typedef struct mbedtls_pk_debug_item +{ + mbedtls_pk_debug_type type; + const char *name; + void *value; +} mbedtls_pk_debug_item; + +/** Maximum number of item send for debugging, plus 1 */ +#define MBEDTLS_PK_DEBUG_MAX_ITEMS 3 + +/** + * \brief Public key information and operations + */ +typedef struct mbedtls_pk_info_t mbedtls_pk_info_t; + +/** + * \brief Public key container + */ +typedef struct mbedtls_pk_context +{ + const mbedtls_pk_info_t * pk_info; /**< Public key information */ + void * pk_ctx; /**< Underlying public key context */ +} mbedtls_pk_context; + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Context for resuming operations + */ +typedef struct +{ + const mbedtls_pk_info_t * pk_info; /**< Public key information */ + void * rs_ctx; /**< Underlying restart context */ +} mbedtls_pk_restart_ctx; +#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ +/* Now we can declare functions that take a pointer to that */ +typedef void mbedtls_pk_restart_ctx; +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + +#if defined(MBEDTLS_RSA_C) +/** + * Quick access to an RSA context inside a PK context. + * + * \warning You must make sure the PK context actually holds an RSA context + * before using this function! + */ +static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk ) +{ + return( (mbedtls_rsa_context *) (pk).pk_ctx ); +} +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/** + * Quick access to an EC context inside a PK context. + * + * \warning You must make sure the PK context actually holds an EC context + * before using this function! + */ +static inline mbedtls_ecp_keypair *mbedtls_pk_ec( const mbedtls_pk_context pk ) +{ + return( (mbedtls_ecp_keypair *) (pk).pk_ctx ); +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/** + * \brief Types for RSA-alt abstraction + */ +typedef int (*mbedtls_pk_rsa_alt_decrypt_func)( void *ctx, int mode, size_t *olen, + const unsigned char *input, unsigned char *output, + size_t output_max_len ); +typedef int (*mbedtls_pk_rsa_alt_sign_func)( void *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + int mode, mbedtls_md_type_t md_alg, unsigned int hashlen, + const unsigned char *hash, unsigned char *sig ); +typedef size_t (*mbedtls_pk_rsa_alt_key_len_func)( void *ctx ); +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +/** + * \brief Return information associated with the given PK type + * + * \param pk_type PK type to search for. + * + * \return The PK info associated with the type or NULL if not found. + */ +const mbedtls_pk_info_t *mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type ); + +/** + * \brief Initialize a #mbedtls_pk_context (as NONE). + * + * \param ctx The context to initialize. + * This must not be \c NULL. + */ +void mbedtls_pk_init( mbedtls_pk_context *ctx ); + +/** + * \brief Free the components of a #mbedtls_pk_context. + * + * \param ctx The context to clear. It must have been initialized. + * If this is \c NULL, this function does nothing. + * + * \note For contexts that have been set up with + * mbedtls_pk_setup_opaque(), this does not free the underlying + * key slot and you still need to call psa_destroy_key() + * independently if you want to destroy that key. + */ +void mbedtls_pk_free( mbedtls_pk_context *ctx ); + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Initialize a restart context + * + * \param ctx The context to initialize. + * This must not be \c NULL. + */ +void mbedtls_pk_restart_init( mbedtls_pk_restart_ctx *ctx ); + +/** + * \brief Free the components of a restart context + * + * \param ctx The context to clear. It must have been initialized. + * If this is \c NULL, this function does nothing. + */ +void mbedtls_pk_restart_free( mbedtls_pk_restart_ctx *ctx ); +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + +/** + * \brief Initialize a PK context with the information given + * and allocates the type-specific PK subcontext. + * + * \param ctx Context to initialize. It must not have been set + * up yet (type #MBEDTLS_PK_NONE). + * \param info Information to use + * + * \return 0 on success, + * MBEDTLS_ERR_PK_BAD_INPUT_DATA on invalid input, + * MBEDTLS_ERR_PK_ALLOC_FAILED on allocation failure. + * + * \note For contexts holding an RSA-alt key, use + * \c mbedtls_pk_setup_rsa_alt() instead. + */ +int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +/** + * \brief Initialize a PK context to wrap a PSA key slot. + * + * \note This function replaces mbedtls_pk_setup() for contexts + * that wrap a (possibly opaque) PSA key slot instead of + * storing and manipulating the key material directly. + * + * \param ctx The context to initialize. It must be empty (type NONE). + * \param key The PSA key slot to wrap, which must hold an ECC key pair + * (see notes below). + * + * \note The wrapped key slot must remain valid as long as the + * wrapping PK context is in use, that is at least between + * the point this function is called and the point + * mbedtls_pk_free() is called on this context. The wrapped + * key slot might then be independently used or destroyed. + * + * \note This function is currently only available for ECC key + * pairs (that is, ECC keys containing private key material). + * Support for other key types may be added later. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_PK_BAD_INPUT_DATA on invalid input + * (context already used, invalid key slot). + * \return #MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE if the key is not an + * ECC key pair. + * \return #MBEDTLS_ERR_PK_ALLOC_FAILED on allocation failure. + */ +int mbedtls_pk_setup_opaque( mbedtls_pk_context *ctx, const psa_key_handle_t key ); +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/** + * \brief Initialize an RSA-alt context + * + * \param ctx Context to initialize. It must not have been set + * up yet (type #MBEDTLS_PK_NONE). + * \param key RSA key pointer + * \param decrypt_func Decryption function + * \param sign_func Signing function + * \param key_len_func Function returning key length in bytes + * + * \return 0 on success, or MBEDTLS_ERR_PK_BAD_INPUT_DATA if the + * context wasn't already initialized as RSA_ALT. + * + * \note This function replaces \c mbedtls_pk_setup() for RSA-alt. + */ +int mbedtls_pk_setup_rsa_alt( mbedtls_pk_context *ctx, void * key, + mbedtls_pk_rsa_alt_decrypt_func decrypt_func, + mbedtls_pk_rsa_alt_sign_func sign_func, + mbedtls_pk_rsa_alt_key_len_func key_len_func ); +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +/** + * \brief Get the size in bits of the underlying key + * + * \param ctx The context to query. It must have been initialized. + * + * \return Key size in bits, or 0 on error + */ +size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ); + +/** + * \brief Get the length in bytes of the underlying key + * + * \param ctx The context to query. It must have been initialized. + * + * \return Key length in bytes, or 0 on error + */ +static inline size_t mbedtls_pk_get_len( const mbedtls_pk_context *ctx ) +{ + return( ( mbedtls_pk_get_bitlen( ctx ) + 7 ) / 8 ); +} + +/** + * \brief Tell if a context can do the operation given by type + * + * \param ctx The context to query. It must have been initialized. + * \param type The desired type. + * + * \return 1 if the context can do operations on the given type. + * \return 0 if the context cannot do the operations on the given + * type. This is always the case for a context that has + * been initialized but not set up, or that has been + * cleared with mbedtls_pk_free(). + */ +int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ); + +/** + * \brief Verify signature (including padding if relevant). + * + * \param ctx The PK context to use. It must have been set up. + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Signature to verify + * \param sig_len Signature length + * + * \return 0 on success (signature is valid), + * #MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if there is a valid + * signature in sig but its length is less than \p siglen, + * or a specific error code. + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * Use \c mbedtls_pk_verify_ext( MBEDTLS_PK_RSASSA_PSS, ... ) + * to verify RSASSA_PSS signatures. + * + * \note If hash_len is 0, then the length associated with md_alg + * is used instead, or an error returned if it is invalid. + * + * \note md_alg may be MBEDTLS_MD_NONE, only if hash_len != 0 + */ +int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + +/** + * \brief Restartable version of \c mbedtls_pk_verify() + * + * \note Performs the same job as \c mbedtls_pk_verify(), but can + * return early and restart according to the limit set with + * \c mbedtls_ecp_set_max_ops() to reduce blocking for ECC + * operations. For RSA, same as \c mbedtls_pk_verify(). + * + * \param ctx The PK context to use. It must have been set up. + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Signature to verify + * \param sig_len Signature length + * \param rs_ctx Restart context (NULL to disable restart) + * + * \return See \c mbedtls_pk_verify(), or + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + */ +int mbedtls_pk_verify_restartable( mbedtls_pk_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len, + mbedtls_pk_restart_ctx *rs_ctx ); + +/** + * \brief Verify signature, with options. + * (Includes verification of the padding depending on type.) + * + * \param type Signature type (inc. possible padding type) to verify + * \param options Pointer to type-specific options, or NULL + * \param ctx The PK context to use. It must have been set up. + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Signature to verify + * \param sig_len Signature length + * + * \return 0 on success (signature is valid), + * #MBEDTLS_ERR_PK_TYPE_MISMATCH if the PK context can't be + * used for this type of signatures, + * #MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if there is a valid + * signature in sig but its length is less than \p siglen, + * or a specific error code. + * + * \note If hash_len is 0, then the length associated with md_alg + * is used instead, or an error returned if it is invalid. + * + * \note md_alg may be MBEDTLS_MD_NONE, only if hash_len != 0 + * + * \note If type is MBEDTLS_PK_RSASSA_PSS, then options must point + * to a mbedtls_pk_rsassa_pss_options structure, + * otherwise it must be NULL. + */ +int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, + mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + +/** + * \brief Make signature, including padding if relevant. + * + * \param ctx The PK context to use. It must have been set up + * with a private key. + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Place to write the signature + * \param sig_len Number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 on success, or a specific error code. + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * There is no interface in the PK module to make RSASSA-PSS + * signatures yet. + * + * \note If hash_len is 0, then the length associated with md_alg + * is used instead, or an error returned if it is invalid. + * + * \note For RSA, md_alg may be MBEDTLS_MD_NONE if hash_len != 0. + * For ECDSA, md_alg may never be MBEDTLS_MD_NONE. + */ +int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Restartable version of \c mbedtls_pk_sign() + * + * \note Performs the same job as \c mbedtls_pk_sign(), but can + * return early and restart according to the limit set with + * \c mbedtls_ecp_set_max_ops() to reduce blocking for ECC + * operations. For RSA, same as \c mbedtls_pk_sign(). + * + * \param ctx The PK context to use. It must have been set up + * with a private key. + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Place to write the signature + * \param sig_len Number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * \param rs_ctx Restart context (NULL to disable restart) + * + * \return See \c mbedtls_pk_sign(), or + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + */ +int mbedtls_pk_sign_restartable( mbedtls_pk_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_pk_restart_ctx *rs_ctx ); + +/** + * \brief Decrypt message (including padding if relevant). + * + * \param ctx The PK context to use. It must have been set up + * with a private key. + * \param input Input to decrypt + * \param ilen Input size + * \param output Decrypted output + * \param olen Decrypted message length + * \param osize Size of the output buffer + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_pk_decrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Encrypt message (including padding if relevant). + * + * \param ctx The PK context to use. It must have been set up. + * \param input Message to encrypt + * \param ilen Message size + * \param output Encrypted output + * \param olen Encrypted output length + * \param osize Size of the output buffer + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Check if a public-private pair of keys matches. + * + * \param pub Context holding a public key. + * \param prv Context holding a private (and public) key. + * + * \return \c 0 on success (keys were checked and match each other). + * \return #MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE if the keys could not + * be checked - in that case they may or may not match. + * \return #MBEDTLS_ERR_PK_BAD_INPUT_DATA if a context is invalid. + * \return Another non-zero value if the keys do not match. + */ +int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ); + +/** + * \brief Export debug information + * + * \param ctx The PK context to use. It must have been initialized. + * \param items Place to write debug items + * + * \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA + */ +int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items ); + +/** + * \brief Access the type name + * + * \param ctx The PK context to use. It must have been initialized. + * + * \return Type name on success, or "invalid PK" + */ +const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx ); + +/** + * \brief Get the key type + * + * \param ctx The PK context to use. It must have been initialized. + * + * \return Type on success. + * \return #MBEDTLS_PK_NONE for a context that has not been set up. + */ +mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ); + +#if defined(MBEDTLS_PK_PARSE_C) +/** \ingroup pk_module */ +/** + * \brief Parse a private key in PEM or DER format + * + * \param ctx The PK context to fill. It must have been initialized + * but not set up. + * \param key Input buffer to parse. + * The buffer must contain the input exactly, with no + * extra trailing material. For PEM, the buffer must + * contain a null-terminated string. + * \param keylen Size of \b key in bytes. + * For PEM data, this includes the terminating null byte, + * so \p keylen must be equal to `strlen(key) + 1`. + * \param pwd Optional password for decryption. + * Pass \c NULL if expecting a non-encrypted key. + * Pass a string of \p pwdlen bytes if expecting an encrypted + * key; a non-encrypted key will also be accepted. + * The empty password is not supported. + * \param pwdlen Size of the password in bytes. + * Ignored if \p pwd is \c NULL. + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a + * specific key type, check the result with mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_key( mbedtls_pk_context *ctx, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ); + +/** \ingroup pk_module */ +/** + * \brief Parse a public key in PEM or DER format + * + * \param ctx The PK context to fill. It must have been initialized + * but not set up. + * \param key Input buffer to parse. + * The buffer must contain the input exactly, with no + * extra trailing material. For PEM, the buffer must + * contain a null-terminated string. + * \param keylen Size of \b key in bytes. + * For PEM data, this includes the terminating null byte, + * so \p keylen must be equal to `strlen(key) + 1`. + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a + * specific key type, check the result with mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, + const unsigned char *key, size_t keylen ); + +#if defined(MBEDTLS_FS_IO) +/** \ingroup pk_module */ +/** + * \brief Load and parse a private key + * + * \param ctx The PK context to fill. It must have been initialized + * but not set up. + * \param path filename to read the private key from + * \param password Optional password to decrypt the file. + * Pass \c NULL if expecting a non-encrypted key. + * Pass a null-terminated string if expecting an encrypted + * key; a non-encrypted key will also be accepted. + * The empty password is not supported. + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a + * specific key type, check the result with mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, + const char *path, const char *password ); + +/** \ingroup pk_module */ +/** + * \brief Load and parse a public key + * + * \param ctx The PK context to fill. It must have been initialized + * but not set up. + * \param path filename to read the public key from + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If + * you need a specific key type, check the result with + * mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ +#endif /* MBEDTLS_PK_PARSE_C */ + +#if defined(MBEDTLS_PK_WRITE_C) +/** + * \brief Write a private key to a PKCS#1 or SEC1 DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx PK context which must contain a valid private key. + * \param buf buffer to write to + * \param size size of the buffer + * + * \return length of data written if successful, or a specific + * error code + */ +int mbedtls_pk_write_key_der( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); + +/** + * \brief Write a public key to a SubjectPublicKeyInfo DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx PK context which must contain a valid public or private key. + * \param buf buffer to write to + * \param size size of the buffer + * + * \return length of data written if successful, or a specific + * error code + */ +int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a public key to a PEM string + * + * \param ctx PK context which must contain a valid public or private key. + * \param buf Buffer to write to. The output includes a + * terminating null byte. + * \param size Size of the buffer in bytes. + * + * \return 0 if successful, or a specific error code + */ +int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); + +/** + * \brief Write a private key to a PKCS#1 or SEC1 PEM string + * + * \param ctx PK context which must contain a valid private key. + * \param buf Buffer to write to. The output includes a + * terminating null byte. + * \param size Size of the buffer in bytes. + * + * \return 0 if successful, or a specific error code + */ +int mbedtls_pk_write_key_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_PK_WRITE_C */ + +/* + * WARNING: Low-level functions. You probably do not want to use these unless + * you are certain you do ;) + */ + +#if defined(MBEDTLS_PK_PARSE_C) +/** + * \brief Parse a SubjectPublicKeyInfo DER structure + * + * \param p the position in the ASN.1 data + * \param end end of the buffer + * \param pk The PK context to fill. It must have been initialized + * but not set up. + * + * \return 0 if successful, or a specific PK error code + */ +int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end, + mbedtls_pk_context *pk ); +#endif /* MBEDTLS_PK_PARSE_C */ + +#if defined(MBEDTLS_PK_WRITE_C) +/** + * \brief Write a subjectPublicKey to ASN.1 data + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param key PK context which must contain a valid public or private key. + * + * \return the length written or a negative error code + */ +int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start, + const mbedtls_pk_context *key ); +#endif /* MBEDTLS_PK_WRITE_C */ + +/* + * Internal module functions. You probably do not want to use these unless you + * know you do. + */ +#if defined(MBEDTLS_FS_IO) +int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ); +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +/** + * \brief Turn an EC key into an Opaque one + * + * \warning This is a temporary utility function for tests. It might + * change or be removed at any time without notice. + * + * \note Only ECDSA keys are supported so far. Signing with the + * specified hash is the only allowed use of that key. + * + * \param pk Input: the EC key to transfer to a PSA key slot. + * Output: a PK context wrapping that PSA key slot. + * \param slot Output: the chosen slot for storing the key. + * It's the caller's responsibility to destroy that slot + * after calling mbedtls_pk_free() on the PK context. + * \param hash_alg The hash algorithm to allow for use with that key. + * + * \return \c 0 if successful. + * \return An Mbed TLS error code otherwise. + */ +int mbedtls_pk_wrap_as_opaque( mbedtls_pk_context *pk, + psa_key_handle_t *slot, + psa_algorithm_t hash_alg ); +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_PK_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pk_internal.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pk_internal.h new file mode 100644 index 000000000..1d62c7fab --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pk_internal.h @@ -0,0 +1,142 @@ +/** + * \file pk_internal.h + * + * \brief Public Key abstraction layer: wrapper functions + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_PK_WRAP_H +#define MBEDTLS_PK_WRAP_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "pk.h" + +struct mbedtls_pk_info_t +{ + /** Public key type */ + mbedtls_pk_type_t type; + + /** Type name */ + const char *name; + + /** Get key size in bits */ + size_t (*get_bitlen)( const void * ); + + /** Tell if the context implements this type (e.g. ECKEY can do ECDSA) */ + int (*can_do)( mbedtls_pk_type_t type ); + + /** Verify signature */ + int (*verify_func)( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + + /** Make signature */ + int (*sign_func)( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + /** Verify signature (restartable) */ + int (*verify_rs_func)( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len, + void *rs_ctx ); + + /** Make signature (restartable) */ + int (*sign_rs_func)( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, void *rs_ctx ); +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + + /** Decrypt message */ + int (*decrypt_func)( void *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + + /** Encrypt message */ + int (*encrypt_func)( void *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + + /** Check public-private key pair */ + int (*check_pair_func)( const void *pub, const void *prv ); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + /** Allocate the restart context */ + void * (*rs_alloc_func)( void ); + + /** Free the restart context */ + void (*rs_free_func)( void *rs_ctx ); +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + + /** Interface with the debug module */ + void (*debug_func)( const void *ctx, mbedtls_pk_debug_item *items ); + +}; +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* Container for RSA-alt */ +typedef struct +{ + void *key; + mbedtls_pk_rsa_alt_decrypt_func decrypt_func; + mbedtls_pk_rsa_alt_sign_func sign_func; + mbedtls_pk_rsa_alt_key_len_func key_len_func; +} mbedtls_rsa_alt_context; +#endif + +#if defined(MBEDTLS_RSA_C) +extern const mbedtls_pk_info_t mbedtls_rsa_info; +#endif + +#if defined(MBEDTLS_ECP_C) +extern const mbedtls_pk_info_t mbedtls_eckey_info; +extern const mbedtls_pk_info_t mbedtls_eckeydh_info; +#endif + +#if defined(MBEDTLS_ECDSA_C) +extern const mbedtls_pk_info_t mbedtls_ecdsa_info; +#endif + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +extern const mbedtls_pk_info_t mbedtls_rsa_alt_info; +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +extern const mbedtls_pk_info_t mbedtls_pk_opaque_info; +#endif + +#endif /* MBEDTLS_PK_WRAP_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pkcs11.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pkcs11.h new file mode 100644 index 000000000..2523a2a93 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pkcs11.h @@ -0,0 +1,175 @@ +/** + * \file pkcs11.h + * + * \brief Wrapper for PKCS#11 library libpkcs11-helper + * + * \author Adriaan de Jong + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PKCS11_H +#define MBEDTLS_PKCS11_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PKCS11_C) + +#include "x509_crt.h" + +#include + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Context for PKCS #11 private keys. + */ +typedef struct mbedtls_pkcs11_context +{ + pkcs11h_certificate_t pkcs11h_cert; + int len; +} mbedtls_pkcs11_context; + +/** + * Initialize a mbedtls_pkcs11_context. + * (Just making memory references valid.) + */ +void mbedtls_pkcs11_init( mbedtls_pkcs11_context *ctx ); + +/** + * Fill in a mbed TLS certificate, based on the given PKCS11 helper certificate. + * + * \param cert X.509 certificate to fill + * \param pkcs11h_cert PKCS #11 helper certificate + * + * \return 0 on success. + */ +int mbedtls_pkcs11_x509_cert_bind( mbedtls_x509_crt *cert, pkcs11h_certificate_t pkcs11h_cert ); + +/** + * Set up a mbedtls_pkcs11_context storing the given certificate. Note that the + * mbedtls_pkcs11_context will take over control of the certificate, freeing it when + * done. + * + * \param priv_key Private key structure to fill. + * \param pkcs11_cert PKCS #11 helper certificate + * + * \return 0 on success + */ +int mbedtls_pkcs11_priv_key_bind( mbedtls_pkcs11_context *priv_key, + pkcs11h_certificate_t pkcs11_cert ); + +/** + * Free the contents of the given private key context. Note that the structure + * itself is not freed. + * + * \param priv_key Private key structure to cleanup + */ +void mbedtls_pkcs11_priv_key_free( mbedtls_pkcs11_context *priv_key ); + +/** + * \brief Do an RSA private key decrypt, then remove the message + * padding + * + * \param ctx PKCS #11 context + * \param mode must be MBEDTLS_RSA_PRIVATE, for compatibility with rsa.c's signature + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param olen will contain the plaintext length + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int mbedtls_pkcs11_decrypt( mbedtls_pkcs11_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Do a private RSA to sign a message digest + * + * \param ctx PKCS #11 context + * \param mode must be MBEDTLS_RSA_PRIVATE, for compatibility with rsa.c's signature + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_pkcs11_sign( mbedtls_pkcs11_context *ctx, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * SSL/TLS wrappers for PKCS#11 functions + */ +static inline int mbedtls_ssl_pkcs11_decrypt( void *ctx, int mode, size_t *olen, + const unsigned char *input, unsigned char *output, + size_t output_max_len ) +{ + return mbedtls_pkcs11_decrypt( (mbedtls_pkcs11_context *) ctx, mode, olen, input, output, + output_max_len ); +} + +static inline int mbedtls_ssl_pkcs11_sign( void *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + int mode, mbedtls_md_type_t md_alg, unsigned int hashlen, + const unsigned char *hash, unsigned char *sig ) +{ + ((void) f_rng); + ((void) p_rng); + return mbedtls_pkcs11_sign( (mbedtls_pkcs11_context *) ctx, mode, md_alg, + hashlen, hash, sig ); +} + +static inline size_t mbedtls_ssl_pkcs11_key_len( void *ctx ) +{ + return ( (mbedtls_pkcs11_context *) ctx )->len; +} + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_PKCS11_C */ + +#endif /* MBEDTLS_PKCS11_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pkcs12.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pkcs12.h new file mode 100644 index 000000000..039627830 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pkcs12.h @@ -0,0 +1,130 @@ +/** + * \file pkcs12.h + * + * \brief PKCS#12 Personal Information Exchange Syntax + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PKCS12_H +#define MBEDTLS_PKCS12_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "md.h" +#include "cipher.h" +#include "asn1.h" + +#include + +#define MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA -0x1F80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE -0x1F00 /**< Feature not available, e.g. unsupported encryption scheme. */ +#define MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT -0x1E80 /**< PBE ASN.1 data not as expected. */ +#define MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH -0x1E00 /**< Given private key password does not allow for correct decryption. */ + +#define MBEDTLS_PKCS12_DERIVE_KEY 1 /**< encryption/decryption key */ +#define MBEDTLS_PKCS12_DERIVE_IV 2 /**< initialization vector */ +#define MBEDTLS_PKCS12_DERIVE_MAC_KEY 3 /**< integrity / MAC key */ + +#define MBEDTLS_PKCS12_PBE_DECRYPT 0 +#define MBEDTLS_PKCS12_PBE_ENCRYPT 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_ASN1_PARSE_C) + +/** + * \brief PKCS12 Password Based function (encryption / decryption) + * for pbeWithSHAAnd128BitRC4 + * + * \param pbe_params an ASN1 buffer containing the pkcs-12PbeParams structure + * \param mode either MBEDTLS_PKCS12_PBE_ENCRYPT or MBEDTLS_PKCS12_PBE_DECRYPT + * \param pwd the password used (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param input the input data + * \param len data length + * \param output the output buffer + * + * \return 0 if successful, or a MBEDTLS_ERR_XXX code + */ +int mbedtls_pkcs12_pbe_sha1_rc4_128( mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *input, size_t len, + unsigned char *output ); + +/** + * \brief PKCS12 Password Based function (encryption / decryption) + * for cipher-based and mbedtls_md-based PBE's + * + * \param pbe_params an ASN1 buffer containing the pkcs-12PbeParams structure + * \param mode either MBEDTLS_PKCS12_PBE_ENCRYPT or MBEDTLS_PKCS12_PBE_DECRYPT + * \param cipher_type the cipher used + * \param md_type the mbedtls_md used + * \param pwd the password used (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param input the input data + * \param len data length + * \param output the output buffer + * + * \return 0 if successful, or a MBEDTLS_ERR_XXX code + */ +int mbedtls_pkcs12_pbe( mbedtls_asn1_buf *pbe_params, int mode, + mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *input, size_t len, + unsigned char *output ); + +#endif /* MBEDTLS_ASN1_PARSE_C */ + +/** + * \brief The PKCS#12 derivation function uses a password and a salt + * to produce pseudo-random bits for a particular "purpose". + * + * Depending on the given id, this function can produce an + * encryption/decryption key, an nitialization vector or an + * integrity key. + * + * \param data buffer to store the derived data in + * \param datalen length to fill + * \param pwd password to use (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param salt salt buffer to use + * \param saltlen length of the salt + * \param mbedtls_md mbedtls_md type to use during the derivation + * \param id id that describes the purpose (can be MBEDTLS_PKCS12_DERIVE_KEY, + * MBEDTLS_PKCS12_DERIVE_IV or MBEDTLS_PKCS12_DERIVE_MAC_KEY) + * \param iterations number of iterations + * + * \return 0 if successful, or a MD, BIGNUM type error. + */ +int mbedtls_pkcs12_derivation( unsigned char *data, size_t datalen, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *salt, size_t saltlen, + mbedtls_md_type_t mbedtls_md, int id, int iterations ); + +#ifdef __cplusplus +} +#endif + +#endif /* pkcs12.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pkcs5.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pkcs5.h new file mode 100644 index 000000000..91190ad5a --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/pkcs5.h @@ -0,0 +1,109 @@ +/** + * \file pkcs5.h + * + * \brief PKCS#5 functions + * + * \author Mathias Olsson + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PKCS5_H +#define MBEDTLS_PKCS5_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "asn1.h" +#include "md.h" + +#include +#include + +#define MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA -0x2f80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_PKCS5_INVALID_FORMAT -0x2f00 /**< Unexpected ASN.1 data. */ +#define MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE -0x2e80 /**< Requested encryption or digest alg not available. */ +#define MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH -0x2e00 /**< Given private key password does not allow for correct decryption. */ + +#define MBEDTLS_PKCS5_DECRYPT 0 +#define MBEDTLS_PKCS5_ENCRYPT 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_ASN1_PARSE_C) + +/** + * \brief PKCS#5 PBES2 function + * + * \param pbe_params the ASN.1 algorithm parameters + * \param mode either MBEDTLS_PKCS5_DECRYPT or MBEDTLS_PKCS5_ENCRYPT + * \param pwd password to use when generating key + * \param pwdlen length of password + * \param data data to process + * \param datalen length of data + * \param output output buffer + * + * \returns 0 on success, or a MBEDTLS_ERR_XXX code if verification fails. + */ +int mbedtls_pkcs5_pbes2( const mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t datalen, + unsigned char *output ); + +#endif /* MBEDTLS_ASN1_PARSE_C */ + +/** + * \brief PKCS#5 PBKDF2 using HMAC + * + * \param ctx Generic HMAC context + * \param password Password to use when generating key + * \param plen Length of password + * \param salt Salt to use when generating key + * \param slen Length of salt + * \param iteration_count Iteration count + * \param key_length Length of generated key in bytes + * \param output Generated key. Must be at least as big as key_length + * + * \returns 0 on success, or a MBEDTLS_ERR_XXX code if verification fails. + */ +int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *password, + size_t plen, const unsigned char *salt, size_t slen, + unsigned int iteration_count, + uint32_t key_length, unsigned char *output ); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_pkcs5_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* pkcs5.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/platform.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/platform.h new file mode 100644 index 000000000..e9b36489b --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/platform.h @@ -0,0 +1,419 @@ +/** + * \file platform.h + * + * \brief This file contains the definitions and functions of the + * Mbed TLS platform abstraction layer. + * + * The platform abstraction layer removes the need for the library + * to directly link to standard C library functions or operating + * system services, making the library easier to port and embed. + * Application developers and users of the library can provide their own + * implementations of these functions, or implementations specific to + * their platform, which can be statically linked to the library or + * dynamically configured at runtime. + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PLATFORM_H +#define MBEDTLS_PLATFORM_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_HAVE_TIME) +#include "platform_time.h" +#endif + +#define MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED -0x0070 /**< Hardware accelerator failed */ +#define MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED -0x0072 /**< The requested feature is not supported by the platform */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +/* The older Microsoft Windows common runtime provides non-conforming + * implementations of some standard library functions, including snprintf + * and vsnprintf. This affects MSVC and MinGW builds. + */ +#if defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER <= 1900) +#define MBEDTLS_PLATFORM_HAS_NON_CONFORMING_SNPRINTF +#define MBEDTLS_PLATFORM_HAS_NON_CONFORMING_VSNPRINTF +#endif + +#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) +#include +#include +#include +#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF) +#if defined(MBEDTLS_PLATFORM_HAS_NON_CONFORMING_SNPRINTF) +#define MBEDTLS_PLATFORM_STD_SNPRINTF mbedtls_platform_win32_snprintf /**< The default \c snprintf function to use. */ +#else +#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< The default \c snprintf function to use. */ +#endif +#endif +#if !defined(MBEDTLS_PLATFORM_STD_VSNPRINTF) +#if defined(MBEDTLS_PLATFORM_HAS_NON_CONFORMING_VSNPRINTF) +#define MBEDTLS_PLATFORM_STD_VSNPRINTF mbedtls_platform_win32_vsnprintf /**< The default \c vsnprintf function to use. */ +#else +#define MBEDTLS_PLATFORM_STD_VSNPRINTF vsnprintf /**< The default \c vsnprintf function to use. */ +#endif +#endif +#if !defined(MBEDTLS_PLATFORM_STD_PRINTF) +#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< The default \c printf function to use. */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF) +#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< The default \c fprintf function to use. */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_CALLOC) +#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< The default \c calloc function to use. */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_FREE) +#define MBEDTLS_PLATFORM_STD_FREE free /**< The default \c free function to use. */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_EXIT) +#define MBEDTLS_PLATFORM_STD_EXIT exit /**< The default \c exit function to use. */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_TIME) +#define MBEDTLS_PLATFORM_STD_TIME time /**< The default \c time function to use. */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS) +#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS EXIT_SUCCESS /**< The default exit value to use. */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE) +#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE EXIT_FAILURE /**< The default exit value to use. */ +#endif +#if defined(MBEDTLS_FS_IO) +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) +#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read +#endif +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) +#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write +#endif +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_FILE) +#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile" +#endif +#endif /* MBEDTLS_FS_IO */ +#else /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */ +#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) +#include MBEDTLS_PLATFORM_STD_MEM_HDR +#endif +#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */ + + +/* \} name SECTION: Module settings */ + +/* + * The function pointers for calloc and free. + */ +#if defined(MBEDTLS_PLATFORM_MEMORY) +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && \ + defined(MBEDTLS_PLATFORM_CALLOC_MACRO) +#define mbedtls_free MBEDTLS_PLATFORM_FREE_MACRO +#define mbedtls_calloc MBEDTLS_PLATFORM_CALLOC_MACRO +#else +/* For size_t */ +#include +extern void *mbedtls_calloc( size_t n, size_t size ); +extern void mbedtls_free( void *ptr ); + +/** + * \brief This function dynamically sets the memory-management + * functions used by the library, during runtime. + * + * \param calloc_func The \c calloc function implementation. + * \param free_func The \c free function implementation. + * + * \return \c 0. + */ +int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ), + void (*free_func)( void * ) ); +#endif /* MBEDTLS_PLATFORM_FREE_MACRO && MBEDTLS_PLATFORM_CALLOC_MACRO */ +#else /* !MBEDTLS_PLATFORM_MEMORY */ +#define mbedtls_free free +#define mbedtls_calloc calloc +#endif /* MBEDTLS_PLATFORM_MEMORY && !MBEDTLS_PLATFORM_{FREE,CALLOC}_MACRO */ + +/* + * The function pointers for fprintf + */ +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) +/* We need FILE * */ +#include +extern int (*mbedtls_fprintf)( FILE *stream, const char *format, ... ); + +/** + * \brief This function dynamically configures the fprintf + * function that is called when the + * mbedtls_fprintf() function is invoked by the library. + * + * \param fprintf_func The \c fprintf function implementation. + * + * \return \c 0. + */ +int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *stream, const char *, + ... ) ); +#else +#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) +#define mbedtls_fprintf MBEDTLS_PLATFORM_FPRINTF_MACRO +#else +#define mbedtls_fprintf fprintf +#endif /* MBEDTLS_PLATFORM_FPRINTF_MACRO */ +#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */ + +/* + * The function pointers for printf + */ +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) +extern int (*mbedtls_printf)( const char *format, ... ); + +/** + * \brief This function dynamically configures the snprintf + * function that is called when the mbedtls_snprintf() + * function is invoked by the library. + * + * \param printf_func The \c printf function implementation. + * + * \return \c 0 on success. + */ +int mbedtls_platform_set_printf( int (*printf_func)( const char *, ... ) ); +#else /* !MBEDTLS_PLATFORM_PRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) +#define mbedtls_printf MBEDTLS_PLATFORM_PRINTF_MACRO +#else +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_PRINTF_MACRO */ +#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */ + +/* + * The function pointers for snprintf + * + * The snprintf implementation should conform to C99: + * - it *must* always correctly zero-terminate the buffer + * (except when n == 0, then it must leave the buffer untouched) + * - however it is acceptable to return -1 instead of the required length when + * the destination buffer is too short. + */ +#if defined(MBEDTLS_PLATFORM_HAS_NON_CONFORMING_SNPRINTF) +/* For Windows (inc. MSYS2), we provide our own fixed implementation */ +int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... ); +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) +extern int (*mbedtls_snprintf)( char * s, size_t n, const char * format, ... ); + +/** + * \brief This function allows configuring a custom + * \c snprintf function pointer. + * + * \param snprintf_func The \c snprintf function implementation. + * + * \return \c 0 on success. + */ +int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n, + const char * format, ... ) ); +#else /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) +#define mbedtls_snprintf MBEDTLS_PLATFORM_SNPRINTF_MACRO +#else +#define mbedtls_snprintf MBEDTLS_PLATFORM_STD_SNPRINTF +#endif /* MBEDTLS_PLATFORM_SNPRINTF_MACRO */ +#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ + +/* + * The function pointers for vsnprintf + * + * The vsnprintf implementation should conform to C99: + * - it *must* always correctly zero-terminate the buffer + * (except when n == 0, then it must leave the buffer untouched) + * - however it is acceptable to return -1 instead of the required length when + * the destination buffer is too short. + */ +#if defined(MBEDTLS_PLATFORM_HAS_NON_CONFORMING_VSNPRINTF) +#include +/* For Older Windows (inc. MSYS2), we provide our own fixed implementation */ +int mbedtls_platform_win32_vsnprintf( char *s, size_t n, const char *fmt, va_list arg ); +#endif + +#if defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT) +#include +extern int (*mbedtls_vsnprintf)( char * s, size_t n, const char * format, va_list arg ); + +/** + * \brief Set your own snprintf function pointer + * + * \param vsnprintf_func The \c vsnprintf function implementation + * + * \return \c 0 + */ +int mbedtls_platform_set_vsnprintf( int (*vsnprintf_func)( char * s, size_t n, + const char * format, va_list arg ) ); +#else /* MBEDTLS_PLATFORM_VSNPRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_VSNPRINTF_MACRO) +#define mbedtls_vsnprintf MBEDTLS_PLATFORM_VSNPRINTF_MACRO +#else +#define mbedtls_vsnprintf vsnprintf +#endif /* MBEDTLS_PLATFORM_VSNPRINTF_MACRO */ +#endif /* MBEDTLS_PLATFORM_VSNPRINTF_ALT */ + +/* + * The function pointers for exit + */ +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) +extern void (*mbedtls_exit)( int status ); + +/** + * \brief This function dynamically configures the exit + * function that is called when the mbedtls_exit() + * function is invoked by the library. + * + * \param exit_func The \c exit function implementation. + * + * \return \c 0 on success. + */ +int mbedtls_platform_set_exit( void (*exit_func)( int status ) ); +#else +#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) +#define mbedtls_exit MBEDTLS_PLATFORM_EXIT_MACRO +#else +#define mbedtls_exit exit +#endif /* MBEDTLS_PLATFORM_EXIT_MACRO */ +#endif /* MBEDTLS_PLATFORM_EXIT_ALT */ + +/* + * The default exit values + */ +#if defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS) +#define MBEDTLS_EXIT_SUCCESS MBEDTLS_PLATFORM_STD_EXIT_SUCCESS +#else +#define MBEDTLS_EXIT_SUCCESS 0 +#endif +#if defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE) +#define MBEDTLS_EXIT_FAILURE MBEDTLS_PLATFORM_STD_EXIT_FAILURE +#else +#define MBEDTLS_EXIT_FAILURE 1 +#endif + +/* + * The function pointers for reading from and writing a seed file to + * Non-Volatile storage (NV) in a platform-independent way + * + * Only enabled when the NV seed entropy source is enabled + */ +#if defined(MBEDTLS_ENTROPY_NV_SEED) +#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDTLS_FS_IO) +/* Internal standard platform definitions */ +int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len ); +int mbedtls_platform_std_nv_seed_write( unsigned char *buf, size_t buf_len ); +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) +extern int (*mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len ); +extern int (*mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len ); + +/** + * \brief This function allows configuring custom seed file writing and + * reading functions. + * + * \param nv_seed_read_func The seed reading function implementation. + * \param nv_seed_write_func The seed writing function implementation. + * + * \return \c 0 on success. + */ +int mbedtls_platform_set_nv_seed( + int (*nv_seed_read_func)( unsigned char *buf, size_t buf_len ), + int (*nv_seed_write_func)( unsigned char *buf, size_t buf_len ) + ); +#else +#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) && \ + defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO) +#define mbedtls_nv_seed_read MBEDTLS_PLATFORM_NV_SEED_READ_MACRO +#define mbedtls_nv_seed_write MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO +#else +#define mbedtls_nv_seed_read mbedtls_platform_std_nv_seed_read +#define mbedtls_nv_seed_write mbedtls_platform_std_nv_seed_write +#endif +#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */ +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#if !defined(MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT) + +/** + * \brief The platform context structure. + * + * \note This structure may be used to assist platform-specific + * setup or teardown operations. + */ +typedef struct mbedtls_platform_context +{ + char dummy; /**< A placeholder member, as empty structs are not portable. */ +} +mbedtls_platform_context; + +#else +#include "platform_alt.h" +#endif /* !MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT */ + +/** + * \brief This function performs any platform-specific initialization + * operations. + * + * \note This function should be called before any other library functions. + * + * Its implementation is platform-specific, and unless + * platform-specific code is provided, it does nothing. + * + * \note The usage and necessity of this function is dependent on the platform. + * + * \param ctx The platform context. + * + * \return \c 0 on success. + */ +int mbedtls_platform_setup( mbedtls_platform_context *ctx ); +/** + * \brief This function performs any platform teardown operations. + * + * \note This function should be called after every other Mbed TLS module + * has been correctly freed using the appropriate free function. + * + * Its implementation is platform-specific, and unless + * platform-specific code is provided, it does nothing. + * + * \note The usage and necessity of this function is dependent on the platform. + * + * \param ctx The platform context. + * + */ +void mbedtls_platform_teardown( mbedtls_platform_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* platform.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/platform_time.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/platform_time.h new file mode 100644 index 000000000..8ac2c51e3 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/platform_time.h @@ -0,0 +1,82 @@ +/** + * \file platform_time.h + * + * \brief mbed TLS Platform time abstraction + */ +/* + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PLATFORM_TIME_H +#define MBEDTLS_PLATFORM_TIME_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +/* + * The time_t datatype + */ +#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) +typedef MBEDTLS_PLATFORM_TIME_TYPE_MACRO mbedtls_time_t; +#else +/* For time_t */ +#include +typedef time_t mbedtls_time_t; +#endif /* MBEDTLS_PLATFORM_TIME_TYPE_MACRO */ + +/* + * The function pointers for time + */ +#if defined(MBEDTLS_PLATFORM_TIME_ALT) +extern mbedtls_time_t (*mbedtls_time)( mbedtls_time_t* time ); + +/** + * \brief Set your own time function pointer + * + * \param time_func the time function implementation + * + * \return 0 + */ +int mbedtls_platform_set_time( mbedtls_time_t (*time_func)( mbedtls_time_t* time ) ); +#else +#if defined(MBEDTLS_PLATFORM_TIME_MACRO) +#define mbedtls_time MBEDTLS_PLATFORM_TIME_MACRO +#else +#define mbedtls_time time +#endif /* MBEDTLS_PLATFORM_TIME_MACRO */ +#endif /* MBEDTLS_PLATFORM_TIME_ALT */ + +#ifdef __cplusplus +} +#endif + +#endif /* platform_time.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/platform_util.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/platform_util.h new file mode 100644 index 000000000..4051f352d --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/platform_util.h @@ -0,0 +1,185 @@ +/** + * \file platform_util.h + * + * \brief Common and shared functions used by multiple modules in the Mbed TLS + * library. + */ +/* + * Copyright (C) 2018, Arm Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PLATFORM_UTIL_H +#define MBEDTLS_PLATFORM_UTIL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#if defined(MBEDTLS_HAVE_TIME_DATE) +#include "platform_time.h" +#include +#endif /* MBEDTLS_HAVE_TIME_DATE */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_CHECK_PARAMS) + +#if defined(MBEDTLS_PARAM_FAILED) +/** An alternative definition of MBEDTLS_PARAM_FAILED has been set in config.h. + * + * This flag can be used to check whether it is safe to assume that + * MBEDTLS_PARAM_FAILED() will expand to a call to mbedtls_param_failed(). + */ +#define MBEDTLS_PARAM_FAILED_ALT +#else /* MBEDTLS_PARAM_FAILED */ +#define MBEDTLS_PARAM_FAILED( cond ) \ + mbedtls_param_failed( #cond, __FILE__, __LINE__ ) + +/** + * \brief User supplied callback function for parameter validation failure. + * See #MBEDTLS_CHECK_PARAMS for context. + * + * This function will be called unless an alternative treatement + * is defined through the #MBEDTLS_PARAM_FAILED macro. + * + * This function can return, and the operation will be aborted, or + * alternatively, through use of setjmp()/longjmp() can resume + * execution in the application code. + * + * \param failure_condition The assertion that didn't hold. + * \param file The file where the assertion failed. + * \param line The line in the file where the assertion failed. + */ +void mbedtls_param_failed( const char *failure_condition, + const char *file, + int line ); +#endif /* MBEDTLS_PARAM_FAILED */ + +/* Internal macro meant to be called only from within the library. */ +#define MBEDTLS_INTERNAL_VALIDATE_RET( cond, ret ) \ + do { \ + if( !(cond) ) \ + { \ + MBEDTLS_PARAM_FAILED( cond ); \ + return( ret ); \ + } \ + } while( 0 ) + +/* Internal macro meant to be called only from within the library. */ +#define MBEDTLS_INTERNAL_VALIDATE( cond ) \ + do { \ + if( !(cond) ) \ + { \ + MBEDTLS_PARAM_FAILED( cond ); \ + return; \ + } \ + } while( 0 ) + +#else /* MBEDTLS_CHECK_PARAMS */ + +/* Internal macros meant to be called only from within the library. */ +#define MBEDTLS_INTERNAL_VALIDATE_RET( cond, ret ) do { } while( 0 ) +#define MBEDTLS_INTERNAL_VALIDATE( cond ) do { } while( 0 ) + +#endif /* MBEDTLS_CHECK_PARAMS */ + +/* Internal helper macros for deprecating API constants. */ +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +/* Deliberately don't (yet) export MBEDTLS_DEPRECATED here + * to avoid conflict with other headers which define and use + * it, too. We might want to move all these definitions here at + * some point for uniformity. */ +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +MBEDTLS_DEPRECATED typedef char const * mbedtls_deprecated_string_constant_t; +#define MBEDTLS_DEPRECATED_STRING_CONSTANT( VAL ) \ + ( (mbedtls_deprecated_string_constant_t) ( VAL ) ) +MBEDTLS_DEPRECATED typedef int mbedtls_deprecated_numeric_constant_t; +#define MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( VAL ) \ + ( (mbedtls_deprecated_numeric_constant_t) ( VAL ) ) +#undef MBEDTLS_DEPRECATED +#else /* MBEDTLS_DEPRECATED_WARNING */ +#define MBEDTLS_DEPRECATED_STRING_CONSTANT( VAL ) VAL +#define MBEDTLS_DEPRECATED_NUMERIC_CONSTANT( VAL ) VAL +#endif /* MBEDTLS_DEPRECATED_WARNING */ +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Securely zeroize a buffer + * + * The function is meant to wipe the data contained in a buffer so + * that it can no longer be recovered even if the program memory + * is later compromised. Call this function on sensitive data + * stored on the stack before returning from a function, and on + * sensitive data stored on the heap before freeing the heap + * object. + * + * It is extremely difficult to guarantee that calls to + * mbedtls_platform_zeroize() are not removed by aggressive + * compiler optimizations in a portable way. For this reason, Mbed + * TLS provides the configuration option + * MBEDTLS_PLATFORM_ZEROIZE_ALT, which allows users to configure + * mbedtls_platform_zeroize() to use a suitable implementation for + * their platform and needs + * + * \param buf Buffer to be zeroized + * \param len Length of the buffer in bytes + * + */ +void mbedtls_platform_zeroize( void *buf, size_t len ); + +#if defined(MBEDTLS_HAVE_TIME_DATE) +/** + * \brief Platform-specific implementation of gmtime_r() + * + * The function is a thread-safe abstraction that behaves + * similarly to the gmtime_r() function from Unix/POSIX. + * + * Mbed TLS will try to identify the underlying platform and + * make use of an appropriate underlying implementation (e.g. + * gmtime_r() for POSIX and gmtime_s() for Windows). If this is + * not possible, then gmtime() will be used. In this case, calls + * from the library to gmtime() will be guarded by the mutex + * mbedtls_threading_gmtime_mutex if MBEDTLS_THREADING_C is + * enabled. It is recommended that calls from outside the library + * are also guarded by this mutex. + * + * If MBEDTLS_PLATFORM_GMTIME_R_ALT is defined, then Mbed TLS will + * unconditionally use the alternative implementation for + * mbedtls_platform_gmtime_r() supplied by the user at compile time. + * + * \param tt Pointer to an object containing time (in seconds) since the + * epoch to be converted + * \param tm_buf Pointer to an object where the results will be stored + * + * \return Pointer to an object of type struct tm on success, otherwise + * NULL + */ +struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt, + struct tm *tm_buf ); +#endif /* MBEDTLS_HAVE_TIME_DATE */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_PLATFORM_UTIL_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/poly1305.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/poly1305.h new file mode 100644 index 000000000..1ed7715b8 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/poly1305.h @@ -0,0 +1,192 @@ +/** + * \file poly1305.h + * + * \brief This file contains Poly1305 definitions and functions. + * + * Poly1305 is a one-time message authenticator that can be used to + * authenticate messages. Poly1305-AES was created by Daniel + * Bernstein https://cr.yp.to/mac/poly1305-20050329.pdf The generic + * Poly1305 algorithm (not tied to AES) was also standardized in RFC + * 7539. + * + * \author Daniel King + */ + +/* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_POLY1305_H +#define MBEDTLS_POLY1305_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA -0x0057 /**< Invalid input parameter(s). */ + +/* MBEDTLS_ERR_POLY1305_FEATURE_UNAVAILABLE is deprecated and should not be + * used. */ +#define MBEDTLS_ERR_POLY1305_FEATURE_UNAVAILABLE -0x0059 /**< Feature not available. For example, s part of the API is not implemented. */ + +/* MBEDTLS_ERR_POLY1305_HW_ACCEL_FAILED is deprecated and should not be used. + */ +#define MBEDTLS_ERR_POLY1305_HW_ACCEL_FAILED -0x005B /**< Poly1305 hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_POLY1305_ALT) + +typedef struct mbedtls_poly1305_context +{ + uint32_t r[4]; /** The value for 'r' (low 128 bits of the key). */ + uint32_t s[4]; /** The value for 's' (high 128 bits of the key). */ + uint32_t acc[5]; /** The accumulator number. */ + uint8_t queue[16]; /** The current partial block of data. */ + size_t queue_len; /** The number of bytes stored in 'queue'. */ +} +mbedtls_poly1305_context; + +#else /* MBEDTLS_POLY1305_ALT */ +#include "poly1305_alt.h" +#endif /* MBEDTLS_POLY1305_ALT */ + +/** + * \brief This function initializes the specified Poly1305 context. + * + * It must be the first API called before using + * the context. + * + * It is usually followed by a call to + * \c mbedtls_poly1305_starts(), then one or more calls to + * \c mbedtls_poly1305_update(), then one call to + * \c mbedtls_poly1305_finish(), then finally + * \c mbedtls_poly1305_free(). + * + * \param ctx The Poly1305 context to initialize. This must + * not be \c NULL. + */ +void mbedtls_poly1305_init( mbedtls_poly1305_context *ctx ); + +/** + * \brief This function releases and clears the specified + * Poly1305 context. + * + * \param ctx The Poly1305 context to clear. This may be \c NULL, in which + * case this function is a no-op. If it is not \c NULL, it must + * point to an initialized Poly1305 context. + */ +void mbedtls_poly1305_free( mbedtls_poly1305_context *ctx ); + +/** + * \brief This function sets the one-time authentication key. + * + * \warning The key must be unique and unpredictable for each + * invocation of Poly1305. + * + * \param ctx The Poly1305 context to which the key should be bound. + * This must be initialized. + * \param key The buffer containing the \c 32 Byte (\c 256 Bit) key. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_starts( mbedtls_poly1305_context *ctx, + const unsigned char key[32] ); + +/** + * \brief This functions feeds an input buffer into an ongoing + * Poly1305 computation. + * + * It is called between \c mbedtls_cipher_poly1305_starts() and + * \c mbedtls_cipher_poly1305_finish(). + * It can be called repeatedly to process a stream of data. + * + * \param ctx The Poly1305 context to use for the Poly1305 operation. + * This must be initialized and bound to a key. + * \param ilen The length of the input data in Bytes. + * Any value is accepted. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `ilen == 0`. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_update( mbedtls_poly1305_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function generates the Poly1305 Message + * Authentication Code (MAC). + * + * \param ctx The Poly1305 context to use for the Poly1305 operation. + * This must be initialized and bound to a key. + * \param mac The buffer to where the MAC is written. This must + * be a writable buffer of length \c 16 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_finish( mbedtls_poly1305_context *ctx, + unsigned char mac[16] ); + +/** + * \brief This function calculates the Poly1305 MAC of the input + * buffer with the provided key. + * + * \warning The key must be unique and unpredictable for each + * invocation of Poly1305. + * + * \param key The buffer containing the \c 32 Byte (\c 256 Bit) key. + * \param ilen The length of the input data in Bytes. + * Any value is accepted. + * \param input The buffer holding the input data. + * This pointer can be \c NULL if `ilen == 0`. + * \param mac The buffer to where the MAC is written. This must be + * a writable buffer of length \c 16 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_poly1305_mac( const unsigned char key[32], + const unsigned char *input, + size_t ilen, + unsigned char mac[16] ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief The Poly1305 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_poly1305_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_POLY1305_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/psa_util.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/psa_util.h new file mode 100644 index 000000000..a718ef3f2 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/psa_util.h @@ -0,0 +1,482 @@ +/** + * \file psa_util.h + * + * \brief Utility functions for the use of the PSA Crypto library. + * + * \warning This function is not part of the public API and may + * change at any time. + */ +/* + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_PSA_UTIL_H +#define MBEDTLS_PSA_UTIL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + +#include "psa/crypto.h" + +#include "ecp.h" +#include "md.h" +#include "pk.h" +#include "oid.h" + +#include + +/* Translations for symmetric crypto. */ + +static inline psa_key_type_t mbedtls_psa_translate_cipher_type( + mbedtls_cipher_type_t cipher ) +{ + switch( cipher ) + { + case MBEDTLS_CIPHER_AES_128_CCM: + case MBEDTLS_CIPHER_AES_192_CCM: + case MBEDTLS_CIPHER_AES_256_CCM: + case MBEDTLS_CIPHER_AES_128_GCM: + case MBEDTLS_CIPHER_AES_192_GCM: + case MBEDTLS_CIPHER_AES_256_GCM: + case MBEDTLS_CIPHER_AES_128_CBC: + case MBEDTLS_CIPHER_AES_192_CBC: + case MBEDTLS_CIPHER_AES_256_CBC: + return( PSA_KEY_TYPE_AES ); + + /* ARIA not yet supported in PSA. */ + /* case MBEDTLS_CIPHER_ARIA_128_CCM: + case MBEDTLS_CIPHER_ARIA_192_CCM: + case MBEDTLS_CIPHER_ARIA_256_CCM: + case MBEDTLS_CIPHER_ARIA_128_GCM: + case MBEDTLS_CIPHER_ARIA_192_GCM: + case MBEDTLS_CIPHER_ARIA_256_GCM: + case MBEDTLS_CIPHER_ARIA_128_CBC: + case MBEDTLS_CIPHER_ARIA_192_CBC: + case MBEDTLS_CIPHER_ARIA_256_CBC: + return( PSA_KEY_TYPE_ARIA ); */ + + default: + return( 0 ); + } +} + +static inline psa_algorithm_t mbedtls_psa_translate_cipher_mode( + mbedtls_cipher_mode_t mode, size_t taglen ) +{ + switch( mode ) + { + case MBEDTLS_MODE_GCM: + return( PSA_ALG_AEAD_WITH_TAG_LENGTH( PSA_ALG_GCM, taglen ) ); + case MBEDTLS_MODE_CCM: + return( PSA_ALG_AEAD_WITH_TAG_LENGTH( PSA_ALG_CCM, taglen ) ); + case MBEDTLS_MODE_CBC: + if( taglen == 0 ) + return( PSA_ALG_CBC_NO_PADDING ); + /* Intentional fallthrough for taglen != 0 */ + /* fallthrough */ + default: + return( 0 ); + } +} + +static inline psa_key_usage_t mbedtls_psa_translate_cipher_operation( + mbedtls_operation_t op ) +{ + switch( op ) + { + case MBEDTLS_ENCRYPT: + return( PSA_KEY_USAGE_ENCRYPT ); + case MBEDTLS_DECRYPT: + return( PSA_KEY_USAGE_DECRYPT ); + default: + return( 0 ); + } +} + +/* Translations for hashing. */ + +static inline psa_algorithm_t mbedtls_psa_translate_md( mbedtls_md_type_t md_alg ) +{ + switch( md_alg ) + { +#if defined(MBEDTLS_MD2_C) + case MBEDTLS_MD_MD2: + return( PSA_ALG_MD2 ); +#endif +#if defined(MBEDTLS_MD4_C) + case MBEDTLS_MD_MD4: + return( PSA_ALG_MD4 ); +#endif +#if defined(MBEDTLS_MD5_C) + case MBEDTLS_MD_MD5: + return( PSA_ALG_MD5 ); +#endif +#if defined(MBEDTLS_SHA1_C) + case MBEDTLS_MD_SHA1: + return( PSA_ALG_SHA_1 ); +#endif +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_MD_SHA224: + return( PSA_ALG_SHA_224 ); + case MBEDTLS_MD_SHA256: + return( PSA_ALG_SHA_256 ); +#endif +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_MD_SHA384: + return( PSA_ALG_SHA_384 ); + case MBEDTLS_MD_SHA512: + return( PSA_ALG_SHA_512 ); +#endif +#if defined(MBEDTLS_RIPEMD160_C) + case MBEDTLS_MD_RIPEMD160: + return( PSA_ALG_RIPEMD160 ); +#endif + case MBEDTLS_MD_NONE: /* Intentional fallthrough */ + default: + return( 0 ); + } +} + +/* Translations for ECC. */ + +static inline int mbedtls_psa_get_ecc_oid_from_id( + psa_ecc_curve_t curve, char const **oid, size_t *oid_len ) +{ + switch( curve ) + { +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + case PSA_ECC_CURVE_SECP192R1: + *oid = MBEDTLS_OID_EC_GRP_SECP192R1; + *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP192R1 ); + return( 0 ); +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + case PSA_ECC_CURVE_SECP224R1: + *oid = MBEDTLS_OID_EC_GRP_SECP224R1; + *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP224R1 ); + return( 0 ); +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case PSA_ECC_CURVE_SECP256R1: + *oid = MBEDTLS_OID_EC_GRP_SECP256R1; + *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP256R1 ); + return( 0 ); +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + case PSA_ECC_CURVE_SECP384R1: + *oid = MBEDTLS_OID_EC_GRP_SECP384R1; + *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP384R1 ); + return( 0 ); +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + case PSA_ECC_CURVE_SECP521R1: + *oid = MBEDTLS_OID_EC_GRP_SECP521R1; + *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP521R1 ); + return( 0 ); +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + case PSA_ECC_CURVE_SECP192K1: + *oid = MBEDTLS_OID_EC_GRP_SECP192K1; + *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP192K1 ); + return( 0 ); +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + case PSA_ECC_CURVE_SECP224K1: + *oid = MBEDTLS_OID_EC_GRP_SECP224K1; + *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP224K1 ); + return( 0 ); +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + case PSA_ECC_CURVE_SECP256K1: + *oid = MBEDTLS_OID_EC_GRP_SECP256K1; + *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP256K1 ); + return( 0 ); +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + case PSA_ECC_CURVE_BRAINPOOL_P256R1: + *oid = MBEDTLS_OID_EC_GRP_BP256R1; + *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_BP256R1 ); + return( 0 ); +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + case PSA_ECC_CURVE_BRAINPOOL_P384R1: + *oid = MBEDTLS_OID_EC_GRP_BP384R1; + *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_BP384R1 ); + return( 0 ); +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + case PSA_ECC_CURVE_BRAINPOOL_P512R1: + *oid = MBEDTLS_OID_EC_GRP_BP512R1; + *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_BP512R1 ); + return( 0 ); +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + } + + return( -1 ); +} + +#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH 1 + +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) +#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 192 + 7 ) / 8 ) + 1 ) +#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH +#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 192 + 7 ) / 8 ) + 1 ) +#endif +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) +#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 224 + 7 ) / 8 ) + 1 ) +#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH +#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 224 + 7 ) / 8 ) + 1 ) +#endif +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 256 + 7 ) / 8 ) + 1 ) +#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH +#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 256 + 7 ) / 8 ) + 1 ) +#endif +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 384 + 7 ) / 8 ) + 1 ) +#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH +#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 384 + 7 ) / 8 ) + 1 ) +#endif +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 521 + 7 ) / 8 ) + 1 ) +#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH +#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 521 + 7 ) / 8 ) + 1 ) +#endif +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) +#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 192 + 7 ) / 8 ) + 1 ) +#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH +#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 192 + 7 ) / 8 ) + 1 ) +#endif +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 224 + 7 ) / 8 ) + 1 ) +#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH +#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 224 + 7 ) / 8 ) + 1 ) +#endif +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 256 + 7 ) / 8 ) + 1 ) +#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH +#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 256 + 7 ) / 8 ) + 1 ) +#endif +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) +#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 256 + 7 ) / 8 ) + 1 ) +#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH +#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 256 + 7 ) / 8 ) + 1 ) +#endif +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) +#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 384 + 7 ) / 8 ) + 1 ) +#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH +#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 384 + 7 ) / 8 ) + 1 ) +#endif +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) +#if MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH < ( 2 * ( ( 512 + 7 ) / 8 ) + 1 ) +#undef MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH +#define MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH ( 2 * ( ( 512 + 7 ) / 8 ) + 1 ) +#endif +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + + +static inline psa_ecc_curve_t mbedtls_psa_translate_ecc_group( mbedtls_ecp_group_id grpid ) +{ + switch( grpid ) + { +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + case MBEDTLS_ECP_DP_SECP192R1: + return( PSA_ECC_CURVE_SECP192R1 ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + case MBEDTLS_ECP_DP_SECP224R1: + return( PSA_ECC_CURVE_SECP224R1 ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case MBEDTLS_ECP_DP_SECP256R1: + return( PSA_ECC_CURVE_SECP256R1 ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + case MBEDTLS_ECP_DP_SECP384R1: + return( PSA_ECC_CURVE_SECP384R1 ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + case MBEDTLS_ECP_DP_SECP521R1: + return( PSA_ECC_CURVE_SECP521R1 ); +#endif +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + case MBEDTLS_ECP_DP_BP256R1: + return( PSA_ECC_CURVE_BRAINPOOL_P256R1 ); +#endif +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + case MBEDTLS_ECP_DP_BP384R1: + return( PSA_ECC_CURVE_BRAINPOOL_P384R1 ); +#endif +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + case MBEDTLS_ECP_DP_BP512R1: + return( PSA_ECC_CURVE_BRAINPOOL_P512R1 ); +#endif +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + case MBEDTLS_ECP_DP_CURVE25519: + return( PSA_ECC_CURVE_CURVE25519 ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + case MBEDTLS_ECP_DP_SECP192K1: + return( PSA_ECC_CURVE_SECP192K1 ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + case MBEDTLS_ECP_DP_SECP224K1: + return( PSA_ECC_CURVE_SECP224K1 ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + case MBEDTLS_ECP_DP_SECP256K1: + return( PSA_ECC_CURVE_SECP256K1 ); +#endif +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + case MBEDTLS_ECP_DP_CURVE448: + return( PSA_ECC_CURVE_CURVE448 ); +#endif + default: + return( 0 ); + } +} + + +#define MBEDTLS_PSA_ECC_KEY_BITS_OF_CURVE( curve ) \ + ( curve == PSA_ECC_CURVE_SECP192R1 ? 192 : \ + curve == PSA_ECC_CURVE_SECP224R1 ? 224 : \ + curve == PSA_ECC_CURVE_SECP256R1 ? 256 : \ + curve == PSA_ECC_CURVE_SECP384R1 ? 384 : \ + curve == PSA_ECC_CURVE_SECP521R1 ? 521 : \ + curve == PSA_ECC_CURVE_SECP192K1 ? 192 : \ + curve == PSA_ECC_CURVE_SECP224K1 ? 224 : \ + curve == PSA_ECC_CURVE_SECP256K1 ? 256 : \ + curve == PSA_ECC_CURVE_BRAINPOOL_P256R1 ? 256 : \ + curve == PSA_ECC_CURVE_BRAINPOOL_P384R1 ? 384 : \ + curve == PSA_ECC_CURVE_BRAINPOOL_P512R1 ? 512 : \ + 0 ) + +#define MBEDTLS_PSA_ECC_KEY_BYTES_OF_CURVE( curve ) \ + ( ( MBEDTLS_PSA_ECC_KEY_BITS_OF_CURVE( curve ) + 7 ) / 8 ) + +/* Translations for PK layer */ + +static inline int mbedtls_psa_err_translate_pk( psa_status_t status ) +{ + switch( status ) + { + case PSA_SUCCESS: + return( 0 ); + case PSA_ERROR_NOT_SUPPORTED: + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + case PSA_ERROR_INSUFFICIENT_MEMORY: + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + case PSA_ERROR_INSUFFICIENT_ENTROPY: + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + case PSA_ERROR_BAD_STATE: + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + /* All other failures */ + case PSA_ERROR_COMMUNICATION_FAILURE: + case PSA_ERROR_HARDWARE_FAILURE: + case PSA_ERROR_TAMPERING_DETECTED: + return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED ); + default: /* We return the same as for the 'other failures', + * but list them separately nonetheless to indicate + * which failure conditions we have considered. */ + return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED ); + } +} + +/* Translations for ECC */ + +/* This function transforms an ECC group identifier from + * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 + * into a PSA ECC group identifier. */ +static inline psa_ecc_curve_t mbedtls_psa_parse_tls_ecc_group( + uint16_t tls_ecc_grp_reg_id ) +{ + /* The PSA identifiers are currently aligned with those from + * the TLS Supported Groups registry, so no conversion is necessary. */ + return( (psa_ecc_curve_t) tls_ecc_grp_reg_id ); +} + +/* This function takes a buffer holding an EC public key + * exported through psa_export_public_key(), and converts + * it into an ECPoint structure to be put into a ClientKeyExchange + * message in an ECDHE exchange. + * + * Both the present and the foreseeable future format of EC public keys + * used by PSA have the ECPoint structure contained in the exported key + * as a subbuffer, and the function merely selects this subbuffer instead + * of making a copy. + */ +static inline int mbedtls_psa_tls_psa_ec_to_ecpoint( unsigned char *src, + size_t srclen, + unsigned char **dst, + size_t *dstlen ) +{ + *dst = src; + *dstlen = srclen; + return( 0 ); +} + +/* This function takes a buffer holding an ECPoint structure + * (as contained in a TLS ServerKeyExchange message for ECDHE + * exchanges) and converts it into a format that the PSA key + * agreement API understands. + */ +static inline int mbedtls_psa_tls_ecpoint_to_psa_ec( psa_ecc_curve_t curve, + unsigned char const *src, + size_t srclen, + unsigned char *dst, + size_t dstlen, + size_t *olen ) +{ + ((void) curve); + + if( srclen > dstlen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + memcpy( dst, src, srclen ); + *olen = srclen; + return( 0 ); +} + +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#endif /* MBEDTLS_PSA_UTIL_H */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ripemd160.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ripemd160.h new file mode 100644 index 000000000..d8f8d3e18 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ripemd160.h @@ -0,0 +1,237 @@ +/** + * \file ripemd160.h + * + * \brief RIPE MD-160 message digest + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_RIPEMD160_H +#define MBEDTLS_RIPEMD160_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +/* MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED is deprecated and should not be used. + */ +#define MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED -0x0031 /**< RIPEMD160 hardware accelerator failed */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_RIPEMD160_ALT) +// Regular implementation +// + +/** + * \brief RIPEMD-160 context structure + */ +typedef struct mbedtls_ripemd160_context +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_ripemd160_context; + +#else /* MBEDTLS_RIPEMD160_ALT */ +#include "ripemd160.h" +#endif /* MBEDTLS_RIPEMD160_ALT */ + +/** + * \brief Initialize RIPEMD-160 context + * + * \param ctx RIPEMD-160 context to be initialized + */ +void mbedtls_ripemd160_init( mbedtls_ripemd160_context *ctx ); + +/** + * \brief Clear RIPEMD-160 context + * + * \param ctx RIPEMD-160 context to be cleared + */ +void mbedtls_ripemd160_free( mbedtls_ripemd160_context *ctx ); + +/** + * \brief Clone (the state of) an RIPEMD-160 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_ripemd160_clone( mbedtls_ripemd160_context *dst, + const mbedtls_ripemd160_context *src ); + +/** + * \brief RIPEMD-160 context setup + * + * \param ctx context to be initialized + * + * \return 0 if successful + */ +int mbedtls_ripemd160_starts_ret( mbedtls_ripemd160_context *ctx ); + +/** + * \brief RIPEMD-160 process buffer + * + * \param ctx RIPEMD-160 context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \return 0 if successful + */ +int mbedtls_ripemd160_update_ret( mbedtls_ripemd160_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief RIPEMD-160 final digest + * + * \param ctx RIPEMD-160 context + * \param output RIPEMD-160 checksum result + * + * \return 0 if successful + */ +int mbedtls_ripemd160_finish_ret( mbedtls_ripemd160_context *ctx, + unsigned char output[20] ); + +/** + * \brief RIPEMD-160 process data block (internal use only) + * + * \param ctx RIPEMD-160 context + * \param data buffer holding one block of data + * + * \return 0 if successful + */ +int mbedtls_internal_ripemd160_process( mbedtls_ripemd160_context *ctx, + const unsigned char data[64] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief RIPEMD-160 context setup + * + * \deprecated Superseded by mbedtls_ripemd160_starts_ret() in 2.7.0 + * + * \param ctx context to be initialized + */ +MBEDTLS_DEPRECATED void mbedtls_ripemd160_starts( + mbedtls_ripemd160_context *ctx ); + +/** + * \brief RIPEMD-160 process buffer + * + * \deprecated Superseded by mbedtls_ripemd160_update_ret() in 2.7.0 + * + * \param ctx RIPEMD-160 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +MBEDTLS_DEPRECATED void mbedtls_ripemd160_update( + mbedtls_ripemd160_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief RIPEMD-160 final digest + * + * \deprecated Superseded by mbedtls_ripemd160_finish_ret() in 2.7.0 + * + * \param ctx RIPEMD-160 context + * \param output RIPEMD-160 checksum result + */ +MBEDTLS_DEPRECATED void mbedtls_ripemd160_finish( + mbedtls_ripemd160_context *ctx, + unsigned char output[20] ); + +/** + * \brief RIPEMD-160 process data block (internal use only) + * + * \deprecated Superseded by mbedtls_internal_ripemd160_process() in 2.7.0 + * + * \param ctx RIPEMD-160 context + * \param data buffer holding one block of data + */ +MBEDTLS_DEPRECATED void mbedtls_ripemd160_process( + mbedtls_ripemd160_context *ctx, + const unsigned char data[64] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Output = RIPEMD-160( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output RIPEMD-160 checksum result + * + * \return 0 if successful + */ +int mbedtls_ripemd160_ret( const unsigned char *input, + size_t ilen, + unsigned char output[20] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief Output = RIPEMD-160( input buffer ) + * + * \deprecated Superseded by mbedtls_ripemd160_ret() in 2.7.0 + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output RIPEMD-160 checksum result + */ +MBEDTLS_DEPRECATED void mbedtls_ripemd160( const unsigned char *input, + size_t ilen, + unsigned char output[20] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_ripemd160_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_ripemd160.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/rsa.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/rsa.h new file mode 100644 index 000000000..f9a996c7a --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/rsa.h @@ -0,0 +1,1274 @@ +/** + * \file rsa.h + * + * \brief This file provides an API for the RSA public-key cryptosystem. + * + * The RSA public-key cryptosystem is defined in Public-Key + * Cryptography Standards (PKCS) #1 v1.5: RSA Encryption + * and Public-Key Cryptography Standards (PKCS) #1 v2.1: + * RSA Cryptography Specifications. + * + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_RSA_H +#define MBEDTLS_RSA_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "bignum.h" +#include "md.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +/* + * RSA Error codes + */ +#define MBEDTLS_ERR_RSA_BAD_INPUT_DATA -0x4080 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_RSA_INVALID_PADDING -0x4100 /**< Input data contains invalid padding and is rejected. */ +#define MBEDTLS_ERR_RSA_KEY_GEN_FAILED -0x4180 /**< Something failed during generation of a key. */ +#define MBEDTLS_ERR_RSA_KEY_CHECK_FAILED -0x4200 /**< Key failed to pass the validity check of the library. */ +#define MBEDTLS_ERR_RSA_PUBLIC_FAILED -0x4280 /**< The public key operation failed. */ +#define MBEDTLS_ERR_RSA_PRIVATE_FAILED -0x4300 /**< The private key operation failed. */ +#define MBEDTLS_ERR_RSA_VERIFY_FAILED -0x4380 /**< The PKCS#1 verification failed. */ +#define MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE -0x4400 /**< The output buffer for decryption is not large enough. */ +#define MBEDTLS_ERR_RSA_RNG_FAILED -0x4480 /**< The random generator failed to generate non-zeros. */ + +/* MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION is deprecated and should not be used. + */ +#define MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION -0x4500 /**< The implementation does not offer the requested operation, for example, because of security violations or lack of functionality. */ + +/* MBEDTLS_ERR_RSA_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_RSA_HW_ACCEL_FAILED -0x4580 /**< RSA hardware accelerator failed. */ + +/* + * RSA constants + */ +#define MBEDTLS_RSA_PUBLIC 0 /**< Request private key operation. */ +#define MBEDTLS_RSA_PRIVATE 1 /**< Request public key operation. */ + +#define MBEDTLS_RSA_PKCS_V15 0 /**< Use PKCS#1 v1.5 encoding. */ +#define MBEDTLS_RSA_PKCS_V21 1 /**< Use PKCS#1 v2.1 encoding. */ + +#define MBEDTLS_RSA_SIGN 1 /**< Identifier for RSA signature operations. */ +#define MBEDTLS_RSA_CRYPT 2 /**< Identifier for RSA encryption and decryption operations. */ + +#define MBEDTLS_RSA_SALT_LEN_ANY -1 + +/* + * The above constants may be used even if the RSA module is compile out, + * eg for alternative (PKCS#11) RSA implemenations in the PK layers. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_RSA_ALT) +// Regular implementation +// + +/** + * \brief The RSA context structure. + * + * \note Direct manipulation of the members of this structure + * is deprecated. All manipulation should instead be done through + * the public interface functions. + */ +typedef struct mbedtls_rsa_context +{ + int ver; /*!< Always 0.*/ + size_t len; /*!< The size of \p N in Bytes. */ + + mbedtls_mpi N; /*!< The public modulus. */ + mbedtls_mpi E; /*!< The public exponent. */ + + mbedtls_mpi D; /*!< The private exponent. */ + mbedtls_mpi P; /*!< The first prime factor. */ + mbedtls_mpi Q; /*!< The second prime factor. */ + + mbedtls_mpi DP; /*!< D % (P - 1). */ + mbedtls_mpi DQ; /*!< D % (Q - 1). */ + mbedtls_mpi QP; /*!< 1 / (Q % P). */ + + mbedtls_mpi RN; /*!< cached R^2 mod N. */ + + mbedtls_mpi RP; /*!< cached R^2 mod P. */ + mbedtls_mpi RQ; /*!< cached R^2 mod Q. */ + + mbedtls_mpi Vi; /*!< The cached blinding value. */ + mbedtls_mpi Vf; /*!< The cached un-blinding value. */ + + int padding; /*!< Selects padding mode: + #MBEDTLS_RSA_PKCS_V15 for 1.5 padding and + #MBEDTLS_RSA_PKCS_V21 for OAEP or PSS. */ + int hash_id; /*!< Hash identifier of mbedtls_md_type_t type, + as specified in md.h for use in the MGF + mask generating function used in the + EME-OAEP and EMSA-PSS encodings. */ +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; /*!< Thread-safety mutex. */ +#endif +} +mbedtls_rsa_context; + +#else /* MBEDTLS_RSA_ALT */ +#include "rsa_alt.h" +#endif /* MBEDTLS_RSA_ALT */ + +/** + * \brief This function initializes an RSA context. + * + * \note Set padding to #MBEDTLS_RSA_PKCS_V21 for the RSAES-OAEP + * encryption scheme and the RSASSA-PSS signature scheme. + * + * \note The \p hash_id parameter is ignored when using + * #MBEDTLS_RSA_PKCS_V15 padding. + * + * \note The choice of padding mode is strictly enforced for private key + * operations, since there might be security concerns in + * mixing padding modes. For public key operations it is + * a default value, which can be overridden by calling specific + * \c rsa_rsaes_xxx or \c rsa_rsassa_xxx functions. + * + * \note The hash selected in \p hash_id is always used for OEAP + * encryption. For PSS signatures, it is always used for + * making signatures, but can be overridden for verifying them. + * If set to #MBEDTLS_MD_NONE, it is always overridden. + * + * \param ctx The RSA context to initialize. This must not be \c NULL. + * \param padding The padding mode to use. This must be either + * #MBEDTLS_RSA_PKCS_V15 or #MBEDTLS_RSA_PKCS_V21. + * \param hash_id The hash identifier of ::mbedtls_md_type_t type, if + * \p padding is #MBEDTLS_RSA_PKCS_V21. It is unused + * otherwise. + */ +void mbedtls_rsa_init( mbedtls_rsa_context *ctx, + int padding, + int hash_id ); + +/** + * \brief This function imports a set of core parameters into an + * RSA context. + * + * \note This function can be called multiple times for successive + * imports, if the parameters are not simultaneously present. + * + * Any sequence of calls to this function should be followed + * by a call to mbedtls_rsa_complete(), which checks and + * completes the provided information to a ready-for-use + * public or private RSA key. + * + * \note See mbedtls_rsa_complete() for more information on which + * parameters are necessary to set up a private or public + * RSA key. + * + * \note The imported parameters are copied and need not be preserved + * for the lifetime of the RSA context being set up. + * + * \param ctx The initialized RSA context to store the parameters in. + * \param N The RSA modulus. This may be \c NULL. + * \param P The first prime factor of \p N. This may be \c NULL. + * \param Q The second prime factor of \p N. This may be \c NULL. + * \param D The private exponent. This may be \c NULL. + * \param E The public exponent. This may be \c NULL. + * + * \return \c 0 on success. + * \return A non-zero error code on failure. + */ +int mbedtls_rsa_import( mbedtls_rsa_context *ctx, + const mbedtls_mpi *N, + const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, const mbedtls_mpi *E ); + +/** + * \brief This function imports core RSA parameters, in raw big-endian + * binary format, into an RSA context. + * + * \note This function can be called multiple times for successive + * imports, if the parameters are not simultaneously present. + * + * Any sequence of calls to this function should be followed + * by a call to mbedtls_rsa_complete(), which checks and + * completes the provided information to a ready-for-use + * public or private RSA key. + * + * \note See mbedtls_rsa_complete() for more information on which + * parameters are necessary to set up a private or public + * RSA key. + * + * \note The imported parameters are copied and need not be preserved + * for the lifetime of the RSA context being set up. + * + * \param ctx The initialized RSA context to store the parameters in. + * \param N The RSA modulus. This may be \c NULL. + * \param N_len The Byte length of \p N; it is ignored if \p N == NULL. + * \param P The first prime factor of \p N. This may be \c NULL. + * \param P_len The Byte length of \p P; it ns ignored if \p P == NULL. + * \param Q The second prime factor of \p N. This may be \c NULL. + * \param Q_len The Byte length of \p Q; it is ignored if \p Q == NULL. + * \param D The private exponent. This may be \c NULL. + * \param D_len The Byte length of \p D; it is ignored if \p D == NULL. + * \param E The public exponent. This may be \c NULL. + * \param E_len The Byte length of \p E; it is ignored if \p E == NULL. + * + * \return \c 0 on success. + * \return A non-zero error code on failure. + */ +int mbedtls_rsa_import_raw( mbedtls_rsa_context *ctx, + unsigned char const *N, size_t N_len, + unsigned char const *P, size_t P_len, + unsigned char const *Q, size_t Q_len, + unsigned char const *D, size_t D_len, + unsigned char const *E, size_t E_len ); + +/** + * \brief This function completes an RSA context from + * a set of imported core parameters. + * + * To setup an RSA public key, precisely \p N and \p E + * must have been imported. + * + * To setup an RSA private key, sufficient information must + * be present for the other parameters to be derivable. + * + * The default implementation supports the following: + *
  • Derive \p P, \p Q from \p N, \p D, \p E.
  • + *
  • Derive \p N, \p D from \p P, \p Q, \p E.
+ * Alternative implementations need not support these. + * + * If this function runs successfully, it guarantees that + * the RSA context can be used for RSA operations without + * the risk of failure or crash. + * + * \warning This function need not perform consistency checks + * for the imported parameters. In particular, parameters that + * are not needed by the implementation might be silently + * discarded and left unchecked. To check the consistency + * of the key material, see mbedtls_rsa_check_privkey(). + * + * \param ctx The initialized RSA context holding imported parameters. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_RSA_BAD_INPUT_DATA if the attempted derivations + * failed. + * + */ +int mbedtls_rsa_complete( mbedtls_rsa_context *ctx ); + +/** + * \brief This function exports the core parameters of an RSA key. + * + * If this function runs successfully, the non-NULL buffers + * pointed to by \p N, \p P, \p Q, \p D, and \p E are fully + * written, with additional unused space filled leading by + * zero Bytes. + * + * Possible reasons for returning + * #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED:
    + *
  • An alternative RSA implementation is in use, which + * stores the key externally, and either cannot or should + * not export it into RAM.
  • + *
  • A SW or HW implementation might not support a certain + * deduction. For example, \p P, \p Q from \p N, \p D, + * and \p E if the former are not part of the + * implementation.
+ * + * If the function fails due to an unsupported operation, + * the RSA context stays intact and remains usable. + * + * \param ctx The initialized RSA context. + * \param N The MPI to hold the RSA modulus. + * This may be \c NULL if this field need not be exported. + * \param P The MPI to hold the first prime factor of \p N. + * This may be \c NULL if this field need not be exported. + * \param Q The MPI to hold the second prime factor of \p N. + * This may be \c NULL if this field need not be exported. + * \param D The MPI to hold the private exponent. + * This may be \c NULL if this field need not be exported. + * \param E The MPI to hold the public exponent. + * This may be \c NULL if this field need not be exported. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED if exporting the + * requested parameters cannot be done due to missing + * functionality or because of security policies. + * \return A non-zero return code on any other failure. + * + */ +int mbedtls_rsa_export( const mbedtls_rsa_context *ctx, + mbedtls_mpi *N, mbedtls_mpi *P, mbedtls_mpi *Q, + mbedtls_mpi *D, mbedtls_mpi *E ); + +/** + * \brief This function exports core parameters of an RSA key + * in raw big-endian binary format. + * + * If this function runs successfully, the non-NULL buffers + * pointed to by \p N, \p P, \p Q, \p D, and \p E are fully + * written, with additional unused space filled leading by + * zero Bytes. + * + * Possible reasons for returning + * #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED:
    + *
  • An alternative RSA implementation is in use, which + * stores the key externally, and either cannot or should + * not export it into RAM.
  • + *
  • A SW or HW implementation might not support a certain + * deduction. For example, \p P, \p Q from \p N, \p D, + * and \p E if the former are not part of the + * implementation.
+ * If the function fails due to an unsupported operation, + * the RSA context stays intact and remains usable. + * + * \note The length parameters are ignored if the corresponding + * buffer pointers are NULL. + * + * \param ctx The initialized RSA context. + * \param N The Byte array to store the RSA modulus, + * or \c NULL if this field need not be exported. + * \param N_len The size of the buffer for the modulus. + * \param P The Byte array to hold the first prime factor of \p N, + * or \c NULL if this field need not be exported. + * \param P_len The size of the buffer for the first prime factor. + * \param Q The Byte array to hold the second prime factor of \p N, + * or \c NULL if this field need not be exported. + * \param Q_len The size of the buffer for the second prime factor. + * \param D The Byte array to hold the private exponent, + * or \c NULL if this field need not be exported. + * \param D_len The size of the buffer for the private exponent. + * \param E The Byte array to hold the public exponent, + * or \c NULL if this field need not be exported. + * \param E_len The size of the buffer for the public exponent. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED if exporting the + * requested parameters cannot be done due to missing + * functionality or because of security policies. + * \return A non-zero return code on any other failure. + */ +int mbedtls_rsa_export_raw( const mbedtls_rsa_context *ctx, + unsigned char *N, size_t N_len, + unsigned char *P, size_t P_len, + unsigned char *Q, size_t Q_len, + unsigned char *D, size_t D_len, + unsigned char *E, size_t E_len ); + +/** + * \brief This function exports CRT parameters of a private RSA key. + * + * \note Alternative RSA implementations not using CRT-parameters + * internally can implement this function based on + * mbedtls_rsa_deduce_opt(). + * + * \param ctx The initialized RSA context. + * \param DP The MPI to hold \c D modulo `P-1`, + * or \c NULL if it need not be exported. + * \param DQ The MPI to hold \c D modulo `Q-1`, + * or \c NULL if it need not be exported. + * \param QP The MPI to hold modular inverse of \c Q modulo \c P, + * or \c NULL if it need not be exported. + * + * \return \c 0 on success. + * \return A non-zero error code on failure. + * + */ +int mbedtls_rsa_export_crt( const mbedtls_rsa_context *ctx, + mbedtls_mpi *DP, mbedtls_mpi *DQ, mbedtls_mpi *QP ); + +/** + * \brief This function sets padding for an already initialized RSA + * context. See mbedtls_rsa_init() for details. + * + * \param ctx The initialized RSA context to be configured. + * \param padding The padding mode to use. This must be either + * #MBEDTLS_RSA_PKCS_V15 or #MBEDTLS_RSA_PKCS_V21. + * \param hash_id The #MBEDTLS_RSA_PKCS_V21 hash identifier. + */ +void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, + int hash_id ); + +/** + * \brief This function retrieves the length of RSA modulus in Bytes. + * + * \param ctx The initialized RSA context. + * + * \return The length of the RSA modulus in Bytes. + * + */ +size_t mbedtls_rsa_get_len( const mbedtls_rsa_context *ctx ); + +/** + * \brief This function generates an RSA keypair. + * + * \note mbedtls_rsa_init() must be called before this function, + * to set up the RSA context. + * + * \param ctx The initialized RSA context used to hold the key. + * \param f_rng The RNG function to be used for key generation. + * This must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. + * This may be \c NULL if \p f_rng doesn't need a context. + * \param nbits The size of the public key in bits. + * \param exponent The public exponent to use. For example, \c 65537. + * This must be odd and greater than \c 1. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent ); + +/** + * \brief This function checks if a context contains at least an RSA + * public key. + * + * If the function runs successfully, it is guaranteed that + * enough information is present to perform an RSA public key + * operation using mbedtls_rsa_public(). + * + * \param ctx The initialized RSA context to check. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + * + */ +int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ); + +/** + * \brief This function checks if a context contains an RSA private key + * and perform basic consistency checks. + * + * \note The consistency checks performed by this function not only + * ensure that mbedtls_rsa_private() can be called successfully + * on the given context, but that the various parameters are + * mutually consistent with high probability, in the sense that + * mbedtls_rsa_public() and mbedtls_rsa_private() are inverses. + * + * \warning This function should catch accidental misconfigurations + * like swapping of parameters, but it cannot establish full + * trust in neither the quality nor the consistency of the key + * material that was used to setup the given RSA context: + *
  • Consistency: Imported parameters that are irrelevant + * for the implementation might be silently dropped. If dropped, + * the current function does not have access to them, + * and therefore cannot check them. See mbedtls_rsa_complete(). + * If you want to check the consistency of the entire + * content of an PKCS1-encoded RSA private key, for example, you + * should use mbedtls_rsa_validate_params() before setting + * up the RSA context. + * Additionally, if the implementation performs empirical checks, + * these checks substantiate but do not guarantee consistency.
  • + *
  • Quality: This function is not expected to perform + * extended quality assessments like checking that the prime + * factors are safe. Additionally, it is the responsibility of the + * user to ensure the trustworthiness of the source of his RSA + * parameters, which goes beyond what is effectively checkable + * by the library.
+ * + * \param ctx The initialized RSA context to check. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ); + +/** + * \brief This function checks a public-private RSA key pair. + * + * It checks each of the contexts, and makes sure they match. + * + * \param pub The initialized RSA context holding the public key. + * \param prv The initialized RSA context holding the private key. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, + const mbedtls_rsa_context *prv ); + +/** + * \brief This function performs an RSA public key operation. + * + * \param ctx The initialized RSA context to use. + * \param input The input buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \note This function does not handle message padding. + * + * \note Make sure to set \p input[0] = 0 or ensure that + * input is smaller than \p N. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_public( mbedtls_rsa_context *ctx, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function performs an RSA private key operation. + * + * \note Blinding is used if and only if a PRNG is provided. + * + * \note If blinding is used, both the base of exponentation + * and the exponent are blinded, providing protection + * against some side-channel attacks. + * + * \warning It is deprecated and a security risk to not provide + * a PRNG here and thereby prevent the use of blinding. + * Future versions of the library may enforce the presence + * of a PRNG. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function, used for blinding. It is discouraged + * and deprecated to pass \c NULL here, in which case + * blinding will be omitted. + * \param p_rng The RNG context to pass to \p f_rng. This may be \c NULL + * if \p f_rng is \c NULL or if \p f_rng doesn't need a context. + * \param input The input buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + * + */ +int mbedtls_rsa_private( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function adds the message padding, then performs an RSA + * operation. + * + * It is the generic wrapper for performing a PKCS#1 encryption + * operation using the \p mode from the context. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PUBLIC. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PRIVATE and might instead + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG to use. It is mandatory for PKCS#1 v2.1 padding + * encoding, and for PKCS#1 v1.5 padding encoding when used + * with \p mode set to #MBEDTLS_RSA_PUBLIC. For PKCS#1 v1.5 + * padding encoding and \p mode set to #MBEDTLS_RSA_PRIVATE, + * it is used for blinding and should be provided in this + * case; see mbedtls_rsa_private() for more. + * \param p_rng The RNG context to be passed to \p f_rng. May be + * \c NULL if \p f_rng is \c NULL or if \p f_rng doesn't + * need a context argument. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE (deprecated). + * \param ilen The length of the plaintext in Bytes. + * \param input The input data to encrypt. This must be a readable + * buffer of size \p ilen Bytes. It may be \c NULL if + * `ilen == 0`. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function performs a PKCS#1 v1.5 encryption operation + * (RSAES-PKCS1-v1_5-ENCRYPT). + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PUBLIC. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PRIVATE and might instead + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function to use. It is needed for padding generation + * if \p mode is #MBEDTLS_RSA_PUBLIC. If \p mode is + * #MBEDTLS_RSA_PRIVATE (discouraged), it is used for + * blinding and should be provided; see mbedtls_rsa_private(). + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng is \c NULL or if \p f_rng + * doesn't need a context argument. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE (deprecated). + * \param ilen The length of the plaintext in Bytes. + * \param input The input data to encrypt. This must be a readable + * buffer of size \p ilen Bytes. It may be \c NULL if + * `ilen == 0`. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function performs a PKCS#1 v2.1 OAEP encryption + * operation (RSAES-OAEP-ENCRYPT). + * + * \note The output buffer must be as large as the size + * of ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PUBLIC. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PRIVATE and might instead + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initnialized RSA context to use. + * \param f_rng The RNG function to use. This is needed for padding + * generation and must be provided. + * \param p_rng The RNG context to be passed to \p f_rng. This may + * be \c NULL if \p f_rng doesn't need a context argument. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE (deprecated). + * \param label The buffer holding the custom label to use. + * This must be a readable buffer of length \p label_len + * Bytes. It may be \c NULL if \p label_len is \c 0. + * \param label_len The length of the label in Bytes. + * \param ilen The length of the plaintext buffer \p input in Bytes. + * \param input The input data to encrypt. This must be a readable + * buffer of size \p ilen Bytes. It may be \c NULL if + * `ilen == 0`. + * \param output The output buffer. This must be a writable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function performs an RSA operation, then removes the + * message padding. + * + * It is the generic wrapper for performing a PKCS#1 decryption + * operation using the \p mode from the context. + * + * \note The output buffer length \c output_max_len should be + * as large as the size \p ctx->len of \p ctx->N (for example, + * 128 Bytes if RSA-1024 is used) to be able to hold an + * arbitrary decrypted message. If it is not large enough to + * hold the decryption of the particular ciphertext provided, + * the function returns \c MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PRIVATE. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PUBLIC and might instead + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. If \p mode is + * #MBEDTLS_RSA_PUBLIC, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a context. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). + * \param olen The address at which to store the length of + * the plaintext. This must not be \c NULL. + * \param input The ciphertext buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The buffer used to hold the plaintext. This must + * be a writable buffer of length \p output_max_len Bytes. + * \param output_max_len The length in Bytes of the output buffer \p output. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief This function performs a PKCS#1 v1.5 decryption + * operation (RSAES-PKCS1-v1_5-DECRYPT). + * + * \note The output buffer length \c output_max_len should be + * as large as the size \p ctx->len of \p ctx->N, for example, + * 128 Bytes if RSA-1024 is used, to be able to hold an + * arbitrary decrypted message. If it is not large enough to + * hold the decryption of the particular ciphertext provided, + * the function returns #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PRIVATE. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PUBLIC and might instead + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. If \p mode is + * #MBEDTLS_RSA_PUBLIC, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a context. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). + * \param olen The address at which to store the length of + * the plaintext. This must not be \c NULL. + * \param input The ciphertext buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The buffer used to hold the plaintext. This must + * be a writable buffer of length \p output_max_len Bytes. + * \param output_max_len The length in Bytes of the output buffer \p output. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + * + */ +int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief This function performs a PKCS#1 v2.1 OAEP decryption + * operation (RSAES-OAEP-DECRYPT). + * + * \note The output buffer length \c output_max_len should be + * as large as the size \p ctx->len of \p ctx->N, for + * example, 128 Bytes if RSA-1024 is used, to be able to + * hold an arbitrary decrypted message. If it is not + * large enough to hold the decryption of the particular + * ciphertext provided, the function returns + * #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PRIVATE. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PUBLIC and might instead + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. If \p mode is + * #MBEDTLS_RSA_PUBLIC, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a context. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). + * \param label The buffer holding the custom label to use. + * This must be a readable buffer of length \p label_len + * Bytes. It may be \c NULL if \p label_len is \c 0. + * \param label_len The length of the label in Bytes. + * \param olen The address at which to store the length of + * the plaintext. This must not be \c NULL. + * \param input The ciphertext buffer. This must be a readable buffer + * of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * \param output The buffer used to hold the plaintext. This must + * be a writable buffer of length \p output_max_len Bytes. + * \param output_max_len The length in Bytes of the output buffer \p output. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief This function performs a private RSA operation to sign + * a message digest using PKCS#1. + * + * It is the generic wrapper for performing a PKCS#1 + * signature using the \p mode from the context. + * + * \note The \p sig buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \note For PKCS#1 v2.1 encoding, see comments on + * mbedtls_rsa_rsassa_pss_sign() for details on + * \p md_alg and \p hash_id. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PRIVATE. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PUBLIC and might instead + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function to use. If the padding mode is PKCS#1 v2.1, + * this must be provided. If the padding mode is PKCS#1 v1.5 and + * \p mode is #MBEDTLS_RSA_PRIVATE, it is used for blinding + * and should be provided; see mbedtls_rsa_private() for more + * more. It is ignored otherwise. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c NULL + * if \p f_rng is \c NULL or doesn't need a context argument. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. + * Ths is only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest or raw data. + * If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable + * buffer of length \p hashlen Bytes. If \p md_alg is not + * #MBEDTLS_MD_NONE, it must be a readable buffer of length + * the size of the hash corresponding to \p md_alg. + * \param sig The buffer to hold the signature. This must be a writable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 if the signing operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief This function performs a PKCS#1 v1.5 signature + * operation (RSASSA-PKCS1-v1_5-SIGN). + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PRIVATE. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PUBLIC and might instead + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. If \p mode is + * #MBEDTLS_RSA_PUBLIC, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c NULL + * if \p f_rng is \c NULL or doesn't need a context argument. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. + * Ths is only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest or raw data. + * If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable + * buffer of length \p hashlen Bytes. If \p md_alg is not + * #MBEDTLS_MD_NONE, it must be a readable buffer of length + * the size of the hash corresponding to \p md_alg. + * \param sig The buffer to hold the signature. This must be a writable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 if the signing operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief This function performs a PKCS#1 v2.1 PSS signature + * operation (RSASSA-PSS-SIGN). + * + * \note The \p hash_id in the RSA context is the one used for the + * encoding. \p md_alg in the function call is the type of hash + * that is encoded. According to RFC-3447: Public-Key + * Cryptography Standards (PKCS) #1 v2.1: RSA Cryptography + * Specifications it is advised to keep both hashes the + * same. + * + * \note This function always uses the maximum possible salt size, + * up to the length of the payload hash. This choice of salt + * size complies with FIPS 186-4 §5.5 (e) and RFC 8017 (PKCS#1 + * v2.2) §9.1.1 step 3. Furthermore this function enforces a + * minimum salt size which is the hash size minus 2 bytes. If + * this minimum size is too large given the key size (the salt + * size, plus the hash size, plus 2 bytes must be no more than + * the key size in bytes), this function returns + * #MBEDTLS_ERR_RSA_BAD_INPUT_DATA. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PRIVATE. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PUBLIC and might instead + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA context to use. + * \param f_rng The RNG function. It must not be \c NULL. + * \param p_rng The RNG context to be passed to \p f_rng. This may be \c NULL + * if \p f_rng doesn't need a context argument. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PRIVATE or #MBEDTLS_RSA_PUBLIC (deprecated). + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. + * Ths is only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest or raw data. + * If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable + * buffer of length \p hashlen Bytes. If \p md_alg is not + * #MBEDTLS_MD_NONE, it must be a readable buffer of length + * the size of the hash corresponding to \p md_alg. + * \param sig The buffer to hold the signature. This must be a writable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 if the signing operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief This function performs a public RSA operation and checks + * the message digest. + * + * This is the generic wrapper for performing a PKCS#1 + * verification using the mode from the context. + * + * \note For PKCS#1 v2.1 encoding, see comments on + * mbedtls_rsa_rsassa_pss_verify() about \p md_alg and + * \p hash_id. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * set to #MBEDTLS_RSA_PUBLIC. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PRIVATE and might instead + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA public key context to use. + * \param f_rng The RNG function to use. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. Otherwise, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a context. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE (deprecated). + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. + * This is only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest or raw data. + * If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable + * buffer of length \p hashlen Bytes. If \p md_alg is not + * #MBEDTLS_MD_NONE, it must be a readable buffer of length + * the size of the hash corresponding to \p md_alg. + * \param sig The buffer holding the signature. This must be a readable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ); + +/** + * \brief This function performs a PKCS#1 v1.5 verification + * operation (RSASSA-PKCS1-v1_5-VERIFY). + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * set to #MBEDTLS_RSA_PUBLIC. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PRIVATE and might instead + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA public key context to use. + * \param f_rng The RNG function to use. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. Otherwise, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a context. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE (deprecated). + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. + * This is only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest or raw data. + * If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable + * buffer of length \p hashlen Bytes. If \p md_alg is not + * #MBEDTLS_MD_NONE, it must be a readable buffer of length + * the size of the hash corresponding to \p md_alg. + * \param sig The buffer holding the signature. This must be a readable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ); + +/** + * \brief This function performs a PKCS#1 v2.1 PSS verification + * operation (RSASSA-PSS-VERIFY). + * + * The hash function for the MGF mask generating function + * is that specified in the RSA context. + * + * \note The \p hash_id in the RSA context is the one used for the + * verification. \p md_alg in the function call is the type of + * hash that is verified. According to RFC-3447: Public-Key + * Cryptography Standards (PKCS) #1 v2.1: RSA Cryptography + * Specifications it is advised to keep both hashes the + * same. If \p hash_id in the RSA context is unset, + * the \p md_alg from the function call is used. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PUBLIC. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PRIVATE and might instead + * return #MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED. + * + * \param ctx The initialized RSA public key context to use. + * \param f_rng The RNG function to use. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. Otherwise, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a context. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE (deprecated). + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. + * This is only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest or raw data. + * If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable + * buffer of length \p hashlen Bytes. If \p md_alg is not + * #MBEDTLS_MD_NONE, it must be a readable buffer of length + * the size of the hash corresponding to \p md_alg. + * \param sig The buffer holding the signature. This must be a readable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ); + +/** + * \brief This function performs a PKCS#1 v2.1 PSS verification + * operation (RSASSA-PSS-VERIFY). + * + * The hash function for the MGF mask generating function + * is that specified in \p mgf1_hash_id. + * + * \note The \p sig buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \note The \p hash_id in the RSA context is ignored. + * + * \param ctx The initialized RSA public key context to use. + * \param f_rng The RNG function to use. If \p mode is #MBEDTLS_RSA_PRIVATE, + * this is used for blinding and should be provided; see + * mbedtls_rsa_private() for more. Otherwise, it is ignored. + * \param p_rng The RNG context to be passed to \p f_rng. This may be + * \c NULL if \p f_rng is \c NULL or doesn't need a context. + * \param mode The mode of operation. This must be either + * #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. + * This is only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest or raw data. + * If \p md_alg is #MBEDTLS_MD_NONE, this must be a readable + * buffer of length \p hashlen Bytes. If \p md_alg is not + * #MBEDTLS_MD_NONE, it must be a readable buffer of length + * the size of the hash corresponding to \p md_alg. + * \param mgf1_hash_id The message digest used for mask generation. + * \param expected_salt_len The length of the salt used in padding. Use + * #MBEDTLS_RSA_SALT_LEN_ANY to accept any salt length. + * \param sig The buffer holding the signature. This must be a readable + * buffer of length \c ctx->len Bytes. For example, \c 256 Bytes + * for an 2048-bit RSA modulus. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + mbedtls_md_type_t mgf1_hash_id, + int expected_salt_len, + const unsigned char *sig ); + +/** + * \brief This function copies the components of an RSA context. + * + * \param dst The destination context. This must be initialized. + * \param src The source context. This must be initialized. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory allocation failure. + */ +int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src ); + +/** + * \brief This function frees the components of an RSA key. + * + * \param ctx The RSA context to free. May be \c NULL, in which case + * this function is a no-op. If it is not \c NULL, it must + * point to an initialized RSA context. + */ +void mbedtls_rsa_free( mbedtls_rsa_context *ctx ); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief The RSA checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_rsa_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* rsa.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/rsa_internal.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/rsa_internal.h new file mode 100644 index 000000000..c244d3976 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/rsa_internal.h @@ -0,0 +1,226 @@ +/** + * \file rsa_internal.h + * + * \brief Context-independent RSA helper functions + * + * This module declares some RSA-related helper functions useful when + * implementing the RSA interface. These functions are provided in a separate + * compilation unit in order to make it easy for designers of alternative RSA + * implementations to use them in their own code, as it is conceived that the + * functionality they provide will be necessary for most complete + * implementations. + * + * End-users of Mbed TLS who are not providing their own alternative RSA + * implementations should not use these functions directly, and should instead + * use only the functions declared in rsa.h. + * + * The interface provided by this module will be maintained through LTS (Long + * Term Support) branches of Mbed TLS, but may otherwise be subject to change, + * and must be considered an internal interface of the library. + * + * There are two classes of helper functions: + * + * (1) Parameter-generating helpers. These are: + * - mbedtls_rsa_deduce_primes + * - mbedtls_rsa_deduce_private_exponent + * - mbedtls_rsa_deduce_crt + * Each of these functions takes a set of core RSA parameters and + * generates some other, or CRT related parameters. + * + * (2) Parameter-checking helpers. These are: + * - mbedtls_rsa_validate_params + * - mbedtls_rsa_validate_crt + * They take a set of core or CRT related RSA parameters and check their + * validity. + * + */ +/* + * Copyright (C) 2006-2017, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + * + */ + +#ifndef MBEDTLS_RSA_INTERNAL_H +#define MBEDTLS_RSA_INTERNAL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "bignum.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * \brief Compute RSA prime moduli P, Q from public modulus N=PQ + * and a pair of private and public key. + * + * \note This is a 'static' helper function not operating on + * an RSA context. Alternative implementations need not + * overwrite it. + * + * \param N RSA modulus N = PQ, with P, Q to be found + * \param E RSA public exponent + * \param D RSA private exponent + * \param P Pointer to MPI holding first prime factor of N on success + * \param Q Pointer to MPI holding second prime factor of N on success + * + * \return + * - 0 if successful. In this case, P and Q constitute a + * factorization of N. + * - A non-zero error code otherwise. + * + * \note It is neither checked that P, Q are prime nor that + * D, E are modular inverses wrt. P-1 and Q-1. For that, + * use the helper function \c mbedtls_rsa_validate_params. + * + */ +int mbedtls_rsa_deduce_primes( mbedtls_mpi const *N, mbedtls_mpi const *E, + mbedtls_mpi const *D, + mbedtls_mpi *P, mbedtls_mpi *Q ); + +/** + * \brief Compute RSA private exponent from + * prime moduli and public key. + * + * \note This is a 'static' helper function not operating on + * an RSA context. Alternative implementations need not + * overwrite it. + * + * \param P First prime factor of RSA modulus + * \param Q Second prime factor of RSA modulus + * \param E RSA public exponent + * \param D Pointer to MPI holding the private exponent on success. + * + * \return + * - 0 if successful. In this case, D is set to a simultaneous + * modular inverse of E modulo both P-1 and Q-1. + * - A non-zero error code otherwise. + * + * \note This function does not check whether P and Q are primes. + * + */ +int mbedtls_rsa_deduce_private_exponent( mbedtls_mpi const *P, + mbedtls_mpi const *Q, + mbedtls_mpi const *E, + mbedtls_mpi *D ); + + +/** + * \brief Generate RSA-CRT parameters + * + * \note This is a 'static' helper function not operating on + * an RSA context. Alternative implementations need not + * overwrite it. + * + * \param P First prime factor of N + * \param Q Second prime factor of N + * \param D RSA private exponent + * \param DP Output variable for D modulo P-1 + * \param DQ Output variable for D modulo Q-1 + * \param QP Output variable for the modular inverse of Q modulo P. + * + * \return 0 on success, non-zero error code otherwise. + * + * \note This function does not check whether P, Q are + * prime and whether D is a valid private exponent. + * + */ +int mbedtls_rsa_deduce_crt( const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, mbedtls_mpi *DP, + mbedtls_mpi *DQ, mbedtls_mpi *QP ); + + +/** + * \brief Check validity of core RSA parameters + * + * \note This is a 'static' helper function not operating on + * an RSA context. Alternative implementations need not + * overwrite it. + * + * \param N RSA modulus N = PQ + * \param P First prime factor of N + * \param Q Second prime factor of N + * \param D RSA private exponent + * \param E RSA public exponent + * \param f_rng PRNG to be used for primality check, or NULL + * \param p_rng PRNG context for f_rng, or NULL + * + * \return + * - 0 if the following conditions are satisfied + * if all relevant parameters are provided: + * - P prime if f_rng != NULL (%) + * - Q prime if f_rng != NULL (%) + * - 1 < N = P * Q + * - 1 < D, E < N + * - D and E are modular inverses modulo P-1 and Q-1 + * (%) This is only done if MBEDTLS_GENPRIME is defined. + * - A non-zero error code otherwise. + * + * \note The function can be used with a restricted set of arguments + * to perform specific checks only. E.g., calling it with + * (-,P,-,-,-) and a PRNG amounts to a primality check for P. + */ +int mbedtls_rsa_validate_params( const mbedtls_mpi *N, const mbedtls_mpi *P, + const mbedtls_mpi *Q, const mbedtls_mpi *D, + const mbedtls_mpi *E, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Check validity of RSA CRT parameters + * + * \note This is a 'static' helper function not operating on + * an RSA context. Alternative implementations need not + * overwrite it. + * + * \param P First prime factor of RSA modulus + * \param Q Second prime factor of RSA modulus + * \param D RSA private exponent + * \param DP MPI to check for D modulo P-1 + * \param DQ MPI to check for D modulo P-1 + * \param QP MPI to check for the modular inverse of Q modulo P. + * + * \return + * - 0 if the following conditions are satisfied: + * - D = DP mod P-1 if P, D, DP != NULL + * - Q = DQ mod P-1 if P, D, DQ != NULL + * - QP = Q^-1 mod P if P, Q, QP != NULL + * - \c MBEDTLS_ERR_RSA_KEY_CHECK_FAILED if check failed, + * potentially including \c MBEDTLS_ERR_MPI_XXX if some + * MPI calculations failed. + * - \c MBEDTLS_ERR_RSA_BAD_INPUT_DATA if insufficient + * data was provided to check DP, DQ or QP. + * + * \note The function can be used with a restricted set of arguments + * to perform specific checks only. E.g., calling it with the + * parameters (P, -, D, DP, -, -) will check DP = D mod P-1. + */ +int mbedtls_rsa_validate_crt( const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, const mbedtls_mpi *DP, + const mbedtls_mpi *DQ, const mbedtls_mpi *QP ); + +#ifdef __cplusplus +} +#endif + +#endif /* rsa_internal.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/sha1.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/sha1.h new file mode 100644 index 000000000..4aa718a0c --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/sha1.h @@ -0,0 +1,352 @@ +/** + * \file sha1.h + * + * \brief This file contains SHA-1 definitions and functions. + * + * The Secure Hash Algorithm 1 (SHA-1) cryptographic hash function is defined in + * FIPS 180-4: Secure Hash Standard (SHS). + * + * \warning SHA-1 is considered a weak message digest and its use constitutes + * a security risk. We recommend considering stronger message + * digests instead. + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SHA1_H +#define MBEDTLS_SHA1_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +/* MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED -0x0035 /**< SHA-1 hardware accelerator failed */ +#define MBEDTLS_ERR_SHA1_BAD_INPUT_DATA -0x0073 /**< SHA-1 input data was malformed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_SHA1_ALT) +// Regular implementation +// + +/** + * \brief The SHA-1 context structure. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +typedef struct mbedtls_sha1_context +{ + uint32_t total[2]; /*!< The number of Bytes processed. */ + uint32_t state[5]; /*!< The intermediate digest state. */ + unsigned char buffer[64]; /*!< The data block being processed. */ +} +mbedtls_sha1_context; + +#else /* MBEDTLS_SHA1_ALT */ +#include "sha1_alt.h" +#endif /* MBEDTLS_SHA1_ALT */ + +/** + * \brief This function initializes a SHA-1 context. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context to initialize. + * This must not be \c NULL. + * + */ +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ); + +/** + * \brief This function clears a SHA-1 context. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context to clear. This may be \c NULL, + * in which case this function does nothing. If it is + * not \c NULL, it must point to an initialized + * SHA-1 context. + * + */ +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ); + +/** + * \brief This function clones the state of a SHA-1 context. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param dst The SHA-1 context to clone to. This must be initialized. + * \param src The SHA-1 context to clone from. This must be initialized. + * + */ +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ); + +/** + * \brief This function starts a SHA-1 checksum calculation. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context to initialize. This must be initialized. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_sha1_starts_ret( mbedtls_sha1_context *ctx ); + +/** + * \brief This function feeds an input buffer into an ongoing SHA-1 + * checksum calculation. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context. This must be initialized + * and have a hash operation started. + * \param input The buffer holding the input data. + * This must be a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data \p input in Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha1_update_ret( mbedtls_sha1_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the SHA-1 operation, and writes + * the result to the output buffer. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context to use. This must be initialized and + * have a hash operation started. + * \param output The SHA-1 checksum result. This must be a writable + * buffer of length \c 20 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha1_finish_ret( mbedtls_sha1_context *ctx, + unsigned char output[20] ); + +/** + * \brief SHA-1 process data block (internal use only). + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context to use. This must be initialized. + * \param data The data block being processed. This must be a + * readable buffer of length \c 64 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx, + const unsigned char data[64] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function starts a SHA-1 checksum calculation. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \deprecated Superseded by mbedtls_sha1_starts_ret() in 2.7.0. + * + * \param ctx The SHA-1 context to initialize. This must be initialized. + * + */ +MBEDTLS_DEPRECATED void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ); + +/** + * \brief This function feeds an input buffer into an ongoing SHA-1 + * checksum calculation. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \deprecated Superseded by mbedtls_sha1_update_ret() in 2.7.0. + * + * \param ctx The SHA-1 context. This must be initialized and + * have a hash operation started. + * \param input The buffer holding the input data. + * This must be a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data \p input in Bytes. + * + */ +MBEDTLS_DEPRECATED void mbedtls_sha1_update( mbedtls_sha1_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the SHA-1 operation, and writes + * the result to the output buffer. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \deprecated Superseded by mbedtls_sha1_finish_ret() in 2.7.0. + * + * \param ctx The SHA-1 context. This must be initialized and + * have a hash operation started. + * \param output The SHA-1 checksum result. + * This must be a writable buffer of length \c 20 Bytes. + */ +MBEDTLS_DEPRECATED void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, + unsigned char output[20] ); + +/** + * \brief SHA-1 process data block (internal use only). + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \deprecated Superseded by mbedtls_internal_sha1_process() in 2.7.0. + * + * \param ctx The SHA-1 context. This must be initialized. + * \param data The data block being processed. + * This must be a readable buffer of length \c 64 bytes. + * + */ +MBEDTLS_DEPRECATED void mbedtls_sha1_process( mbedtls_sha1_context *ctx, + const unsigned char data[64] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief This function calculates the SHA-1 checksum of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-1 result is calculated as + * output = SHA-1(input buffer). + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param input The buffer holding the input data. + * This must be a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data \p input in Bytes. + * \param output The SHA-1 checksum result. + * This must be a writable buffer of length \c 20 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + * + */ +int mbedtls_sha1_ret( const unsigned char *input, + size_t ilen, + unsigned char output[20] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function calculates the SHA-1 checksum of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-1 result is calculated as + * output = SHA-1(input buffer). + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \deprecated Superseded by mbedtls_sha1_ret() in 2.7.0 + * + * \param input The buffer holding the input data. + * This must be a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data \p input in Bytes. + * \param output The SHA-1 checksum result. This must be a writable + * buffer of size \c 20 Bytes. + * + */ +MBEDTLS_DEPRECATED void mbedtls_sha1( const unsigned char *input, + size_t ilen, + unsigned char output[20] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief The SHA-1 checkup routine. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \return \c 0 on success. + * \return \c 1 on failure. + * + */ +int mbedtls_sha1_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha1.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/sha256.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/sha256.h new file mode 100644 index 000000000..4b8741822 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/sha256.h @@ -0,0 +1,297 @@ +/** + * \file sha256.h + * + * \brief This file contains SHA-224 and SHA-256 definitions and functions. + * + * The Secure Hash Algorithms 224 and 256 (SHA-224 and SHA-256) cryptographic + * hash functions are defined in FIPS 180-4: Secure Hash Standard (SHS). + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SHA256_H +#define MBEDTLS_SHA256_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +/* MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED -0x0037 /**< SHA-256 hardware accelerator failed */ +#define MBEDTLS_ERR_SHA256_BAD_INPUT_DATA -0x0074 /**< SHA-256 input data was malformed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_SHA256_ALT) +// Regular implementation +// + +/** + * \brief The SHA-256 context structure. + * + * The structure is used both for SHA-256 and for SHA-224 + * checksum calculations. The choice between these two is + * made in the call to mbedtls_sha256_starts_ret(). + */ +typedef struct mbedtls_sha256_context +{ + uint32_t total[2]; /*!< The number of Bytes processed. */ + uint32_t state[8]; /*!< The intermediate digest state. */ + unsigned char buffer[64]; /*!< The data block being processed. */ + int is224; /*!< Determines which function to use: + 0: Use SHA-256, or 1: Use SHA-224. */ +} +mbedtls_sha256_context; + +#else /* MBEDTLS_SHA256_ALT */ +#include "sha256_alt.h" +#endif /* MBEDTLS_SHA256_ALT */ + +/** + * \brief This function initializes a SHA-256 context. + * + * \param ctx The SHA-256 context to initialize. This must not be \c NULL. + */ +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ); + +/** + * \brief This function clears a SHA-256 context. + * + * \param ctx The SHA-256 context to clear. This may be \c NULL, in which + * case this function returns immediately. If it is not \c NULL, + * it must point to an initialized SHA-256 context. + */ +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ); + +/** + * \brief This function clones the state of a SHA-256 context. + * + * \param dst The destination context. This must be initialized. + * \param src The context to clone. This must be initialized. + */ +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ); + +/** + * \brief This function starts a SHA-224 or SHA-256 checksum + * calculation. + * + * \param ctx The context to use. This must be initialized. + * \param is224 This determines which function to use. This must be + * either \c 0 for SHA-256, or \c 1 for SHA-224. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha256_starts_ret( mbedtls_sha256_context *ctx, int is224 ); + +/** + * \brief This function feeds an input buffer into an ongoing + * SHA-256 checksum calculation. + * + * \param ctx The SHA-256 context. This must be initialized + * and have a hash operation started. + * \param input The buffer holding the data. This must be a readable + * buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha256_update_ret( mbedtls_sha256_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the SHA-256 operation, and writes + * the result to the output buffer. + * + * \param ctx The SHA-256 context. This must be initialized + * and have a hash operation started. + * \param output The SHA-224 or SHA-256 checksum result. + * This must be a writable buffer of length \c 32 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha256_finish_ret( mbedtls_sha256_context *ctx, + unsigned char output[32] ); + +/** + * \brief This function processes a single data block within + * the ongoing SHA-256 computation. This function is for + * internal use only. + * + * \param ctx The SHA-256 context. This must be initialized. + * \param data The buffer holding one block of data. This must + * be a readable buffer of length \c 64 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx, + const unsigned char data[64] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function starts a SHA-224 or SHA-256 checksum + * calculation. + * + * \deprecated Superseded by mbedtls_sha256_starts_ret() in 2.7.0. + * + * \param ctx The context to use. This must be initialized. + * \param is224 Determines which function to use. This must be + * either \c 0 for SHA-256, or \c 1 for SHA-224. + */ +MBEDTLS_DEPRECATED void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, + int is224 ); + +/** + * \brief This function feeds an input buffer into an ongoing + * SHA-256 checksum calculation. + * + * \deprecated Superseded by mbedtls_sha256_update_ret() in 2.7.0. + * + * \param ctx The SHA-256 context to use. This must be + * initialized and have a hash operation started. + * \param input The buffer holding the data. This must be a readable + * buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + */ +MBEDTLS_DEPRECATED void mbedtls_sha256_update( mbedtls_sha256_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the SHA-256 operation, and writes + * the result to the output buffer. + * + * \deprecated Superseded by mbedtls_sha256_finish_ret() in 2.7.0. + * + * \param ctx The SHA-256 context. This must be initialized and + * have a hash operation started. + * \param output The SHA-224 or SHA-256 checksum result. This must be + * a writable buffer of length \c 32 Bytes. + */ +MBEDTLS_DEPRECATED void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, + unsigned char output[32] ); + +/** + * \brief This function processes a single data block within + * the ongoing SHA-256 computation. This function is for + * internal use only. + * + * \deprecated Superseded by mbedtls_internal_sha256_process() in 2.7.0. + * + * \param ctx The SHA-256 context. This must be initialized. + * \param data The buffer holding one block of data. This must be + * a readable buffer of size \c 64 Bytes. + */ +MBEDTLS_DEPRECATED void mbedtls_sha256_process( mbedtls_sha256_context *ctx, + const unsigned char data[64] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief This function calculates the SHA-224 or SHA-256 + * checksum of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-256 result is calculated as + * output = SHA-256(input buffer). + * + * \param input The buffer holding the data. This must be a readable + * buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * \param output The SHA-224 or SHA-256 checksum result. This must + * be a writable buffer of length \c 32 Bytes. + * \param is224 Determines which function to use. This must be + * either \c 0 for SHA-256, or \c 1 for SHA-224. + */ +int mbedtls_sha256_ret( const unsigned char *input, + size_t ilen, + unsigned char output[32], + int is224 ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif + +/** + * \brief This function calculates the SHA-224 or SHA-256 checksum + * of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-256 result is calculated as + * output = SHA-256(input buffer). + * + * \deprecated Superseded by mbedtls_sha256_ret() in 2.7.0. + * + * \param input The buffer holding the data. This must be a readable + * buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * \param output The SHA-224 or SHA-256 checksum result. This must be + * a writable buffer of length \c 32 Bytes. + * \param is224 Determines which function to use. This must be either + * \c 0 for SHA-256, or \c 1 for SHA-224. + */ +MBEDTLS_DEPRECATED void mbedtls_sha256( const unsigned char *input, + size_t ilen, + unsigned char output[32], + int is224 ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief The SHA-224 and SHA-256 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_sha256_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha256.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/sha512.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/sha512.h new file mode 100644 index 000000000..bc2e7924c --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/sha512.h @@ -0,0 +1,300 @@ +/** + * \file sha512.h + * \brief This file contains SHA-384 and SHA-512 definitions and functions. + * + * The Secure Hash Algorithms 384 and 512 (SHA-384 and SHA-512) cryptographic + * hash functions are defined in FIPS 180-4: Secure Hash Standard (SHS). + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SHA512_H +#define MBEDTLS_SHA512_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +/* MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED -0x0039 /**< SHA-512 hardware accelerator failed */ +#define MBEDTLS_ERR_SHA512_BAD_INPUT_DATA -0x0075 /**< SHA-512 input data was malformed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_SHA512_ALT) +// Regular implementation +// + +/** + * \brief The SHA-512 context structure. + * + * The structure is used both for SHA-384 and for SHA-512 + * checksum calculations. The choice between these two is + * made in the call to mbedtls_sha512_starts_ret(). + */ +typedef struct mbedtls_sha512_context +{ + uint64_t total[2]; /*!< The number of Bytes processed. */ + uint64_t state[8]; /*!< The intermediate digest state. */ + unsigned char buffer[128]; /*!< The data block being processed. */ + int is384; /*!< Determines which function to use: + 0: Use SHA-512, or 1: Use SHA-384. */ +} +mbedtls_sha512_context; + +#else /* MBEDTLS_SHA512_ALT */ +#include "sha512_alt.h" +#endif /* MBEDTLS_SHA512_ALT */ + +/** + * \brief This function initializes a SHA-512 context. + * + * \param ctx The SHA-512 context to initialize. This must + * not be \c NULL. + */ +void mbedtls_sha512_init( mbedtls_sha512_context *ctx ); + +/** + * \brief This function clears a SHA-512 context. + * + * \param ctx The SHA-512 context to clear. This may be \c NULL, + * in which case this function does nothing. If it + * is not \c NULL, it must point to an initialized + * SHA-512 context. + */ +void mbedtls_sha512_free( mbedtls_sha512_context *ctx ); + +/** + * \brief This function clones the state of a SHA-512 context. + * + * \param dst The destination context. This must be initialized. + * \param src The context to clone. This must be initialized. + */ +void mbedtls_sha512_clone( mbedtls_sha512_context *dst, + const mbedtls_sha512_context *src ); + +/** + * \brief This function starts a SHA-384 or SHA-512 checksum + * calculation. + * + * \param ctx The SHA-512 context to use. This must be initialized. + * \param is384 Determines which function to use. This must be + * either \c for SHA-512, or \c 1 for SHA-384. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha512_starts_ret( mbedtls_sha512_context *ctx, int is384 ); + +/** + * \brief This function feeds an input buffer into an ongoing + * SHA-512 checksum calculation. + * + * \param ctx The SHA-512 context. This must be initialized + * and have a hash operation started. + * \param input The buffer holding the input data. This must + * be a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha512_update_ret( mbedtls_sha512_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the SHA-512 operation, and writes + * the result to the output buffer. This function is for + * internal use only. + * + * \param ctx The SHA-512 context. This must be initialized + * and have a hash operation started. + * \param output The SHA-384 or SHA-512 checksum result. + * This must be a writable buffer of length \c 64 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx, + unsigned char output[64] ); + +/** + * \brief This function processes a single data block within + * the ongoing SHA-512 computation. + * + * \param ctx The SHA-512 context. This must be initialized. + * \param data The buffer holding one block of data. This + * must be a readable buffer of length \c 128 Bytes. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_internal_sha512_process( mbedtls_sha512_context *ctx, + const unsigned char data[128] ); +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function starts a SHA-384 or SHA-512 checksum + * calculation. + * + * \deprecated Superseded by mbedtls_sha512_starts_ret() in 2.7.0 + * + * \param ctx The SHA-512 context to use. This must be initialized. + * \param is384 Determines which function to use. This must be either + * \c 0 for SHA-512 or \c 1 for SHA-384. + */ +MBEDTLS_DEPRECATED void mbedtls_sha512_starts( mbedtls_sha512_context *ctx, + int is384 ); + +/** + * \brief This function feeds an input buffer into an ongoing + * SHA-512 checksum calculation. + * + * \deprecated Superseded by mbedtls_sha512_update_ret() in 2.7.0. + * + * \param ctx The SHA-512 context. This must be initialized + * and have a hash operation started. + * \param input The buffer holding the data. This must be a readable + * buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + */ +MBEDTLS_DEPRECATED void mbedtls_sha512_update( mbedtls_sha512_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the SHA-512 operation, and writes + * the result to the output buffer. + * + * \deprecated Superseded by mbedtls_sha512_finish_ret() in 2.7.0. + * + * \param ctx The SHA-512 context. This must be initialized + * and have a hash operation started. + * \param output The SHA-384 or SHA-512 checksum result. This must + * be a writable buffer of size \c 64 Bytes. + */ +MBEDTLS_DEPRECATED void mbedtls_sha512_finish( mbedtls_sha512_context *ctx, + unsigned char output[64] ); + +/** + * \brief This function processes a single data block within + * the ongoing SHA-512 computation. This function is for + * internal use only. + * + * \deprecated Superseded by mbedtls_internal_sha512_process() in 2.7.0. + * + * \param ctx The SHA-512 context. This must be initialized. + * \param data The buffer holding one block of data. This must be + * a readable buffer of length \c 128 Bytes. + */ +MBEDTLS_DEPRECATED void mbedtls_sha512_process( + mbedtls_sha512_context *ctx, + const unsigned char data[128] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief This function calculates the SHA-512 or SHA-384 + * checksum of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-512 result is calculated as + * output = SHA-512(input buffer). + * + * \param input The buffer holding the input data. This must be + * a readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * \param output The SHA-384 or SHA-512 checksum result. + * This must be a writable buffer of length \c 64 Bytes. + * \param is384 Determines which function to use. This must be either + * \c 0 for SHA-512, or \c 1 for SHA-384. + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_sha512_ret( const unsigned char *input, + size_t ilen, + unsigned char output[64], + int is384 ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif + +/** + * \brief This function calculates the SHA-512 or SHA-384 + * checksum of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-512 result is calculated as + * output = SHA-512(input buffer). + * + * \deprecated Superseded by mbedtls_sha512_ret() in 2.7.0 + * + * \param input The buffer holding the data. This must be a + * readable buffer of length \p ilen Bytes. + * \param ilen The length of the input data in Bytes. + * \param output The SHA-384 or SHA-512 checksum result. This must + * be a writable buffer of length \c 64 Bytes. + * \param is384 Determines which function to use. This must be either + * \c 0 for SHA-512, or \c 1 for SHA-384. + */ +MBEDTLS_DEPRECATED void mbedtls_sha512( const unsigned char *input, + size_t ilen, + unsigned char output[64], + int is384 ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +#if defined(MBEDTLS_SELF_TEST) + + /** + * \brief The SHA-384 or SHA-512 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_sha512_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha512.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl.h new file mode 100644 index 000000000..78651f007 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl.h @@ -0,0 +1,3819 @@ +/** + * \file ssl.h + * + * \brief SSL/TLS functions. + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_H +#define MBEDTLS_SSL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "bignum.h" +#include "ecp.h" + +#include "ssl_ciphersuites.h" + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#include "x509_crt.h" +#include "x509_crl.h" +#endif + +#if defined(MBEDTLS_DHM_C) +#include "dhm.h" +#endif + +#if defined(MBEDTLS_ECDH_C) +#include "ecdh.h" +#endif + +#if defined(MBEDTLS_ZLIB_SUPPORT) + +#if defined(MBEDTLS_DEPRECATED_WARNING) +#warning "Record compression support via MBEDTLS_ZLIB_SUPPORT is deprecated and will be removed in the next major revision of the library" +#endif + +#if defined(MBEDTLS_DEPRECATED_REMOVED) +#error "Record compression support via MBEDTLS_ZLIB_SUPPORT is deprecated and cannot be used if MBEDTLS_DEPRECATED_REMOVED is set" +#endif + +#include "zlib.h" +#endif + +#if defined(MBEDTLS_HAVE_TIME) +#include "platform_time.h" +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "psa/crypto.h" +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +/* + * SSL Error codes + */ +#define MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE -0x7080 /**< The requested feature is not available. */ +#define MBEDTLS_ERR_SSL_BAD_INPUT_DATA -0x7100 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_SSL_INVALID_MAC -0x7180 /**< Verification of the message MAC failed. */ +#define MBEDTLS_ERR_SSL_INVALID_RECORD -0x7200 /**< An invalid SSL record was received. */ +#define MBEDTLS_ERR_SSL_CONN_EOF -0x7280 /**< The connection indicated an EOF. */ +#define MBEDTLS_ERR_SSL_UNKNOWN_CIPHER -0x7300 /**< An unknown cipher was received. */ +#define MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN -0x7380 /**< The server has no ciphersuites in common with the client. */ +#define MBEDTLS_ERR_SSL_NO_RNG -0x7400 /**< No RNG was provided to the SSL module. */ +#define MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE -0x7480 /**< No client certification received from the client, but required by the authentication mode. */ +#define MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE -0x7500 /**< Our own certificate(s) is/are too large to send in an SSL message. */ +#define MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED -0x7580 /**< The own certificate is not set, but needed by the server. */ +#define MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED -0x7600 /**< The own private key or pre-shared key is not set, but needed. */ +#define MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED -0x7680 /**< No CA Chain is set, but required to operate. */ +#define MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE -0x7700 /**< An unexpected message was received from our peer. */ +#define MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE -0x7780 /**< A fatal alert message was received from our peer. */ +#define MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED -0x7800 /**< Verification of our peer failed. */ +#define MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY -0x7880 /**< The peer notified us that the connection is going to be closed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO -0x7900 /**< Processing of the ClientHello handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO -0x7980 /**< Processing of the ServerHello handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE -0x7A00 /**< Processing of the Certificate handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST -0x7A80 /**< Processing of the CertificateRequest handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE -0x7B00 /**< Processing of the ServerKeyExchange handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE -0x7B80 /**< Processing of the ServerHelloDone handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE -0x7C00 /**< Processing of the ClientKeyExchange handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP -0x7C80 /**< Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Read Public. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS -0x7D00 /**< Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Calculate Secret. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY -0x7D80 /**< Processing of the CertificateVerify handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC -0x7E00 /**< Processing of the ChangeCipherSpec handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_FINISHED -0x7E80 /**< Processing of the Finished handshake message failed. */ +#define MBEDTLS_ERR_SSL_ALLOC_FAILED -0x7F00 /**< Memory allocation failed */ +#define MBEDTLS_ERR_SSL_HW_ACCEL_FAILED -0x7F80 /**< Hardware acceleration function returned with error */ +#define MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH -0x6F80 /**< Hardware acceleration function skipped / left alone data */ +#define MBEDTLS_ERR_SSL_COMPRESSION_FAILED -0x6F00 /**< Processing of the compression / decompression failed */ +#define MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION -0x6E80 /**< Handshake protocol not within min/max boundaries */ +#define MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET -0x6E00 /**< Processing of the NewSessionTicket handshake message failed. */ +#define MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED -0x6D80 /**< Session ticket has expired. */ +#define MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH -0x6D00 /**< Public key type mismatch (eg, asked for RSA key exchange and presented EC key) */ +#define MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY -0x6C80 /**< Unknown identity received (eg, PSK identity) */ +#define MBEDTLS_ERR_SSL_INTERNAL_ERROR -0x6C00 /**< Internal error (eg, unexpected failure in lower-level module) */ +#define MBEDTLS_ERR_SSL_COUNTER_WRAPPING -0x6B80 /**< A counter would wrap (eg, too many messages exchanged). */ +#define MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO -0x6B00 /**< Unexpected message at ServerHello in renegotiation. */ +#define MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED -0x6A80 /**< DTLS client must retry for hello verification */ +#define MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL -0x6A00 /**< A buffer is too small to receive or write a message */ +#define MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE -0x6980 /**< None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages). */ +#define MBEDTLS_ERR_SSL_WANT_READ -0x6900 /**< No data of requested type currently available on underlying transport. */ +#define MBEDTLS_ERR_SSL_WANT_WRITE -0x6880 /**< Connection requires a write call. */ +#define MBEDTLS_ERR_SSL_TIMEOUT -0x6800 /**< The operation timed out. */ +#define MBEDTLS_ERR_SSL_CLIENT_RECONNECT -0x6780 /**< The client initiated a reconnect from the same port. */ +#define MBEDTLS_ERR_SSL_UNEXPECTED_RECORD -0x6700 /**< Record header looks valid but is not expected. */ +#define MBEDTLS_ERR_SSL_NON_FATAL -0x6680 /**< The alert message received indicates a non-fatal error. */ +#define MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH -0x6600 /**< Couldn't set the hash for verifying CertificateVerify */ +#define MBEDTLS_ERR_SSL_CONTINUE_PROCESSING -0x6580 /**< Internal-only message signaling that further message-processing should be done */ +#define MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS -0x6500 /**< The asynchronous operation is not completed yet. */ +#define MBEDTLS_ERR_SSL_EARLY_MESSAGE -0x6480 /**< Internal-only message signaling that a message arrived early. */ +#define MBEDTLS_ERR_SSL_UNEXPECTED_CID -0x6000 /**< An encrypted DTLS-frame with an unexpected CID was received. */ +#define MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS -0x7000 /**< A cryptographic operation is in progress. Try again later. */ + +/* + * Various constants + */ +#define MBEDTLS_SSL_MAJOR_VERSION_3 3 +#define MBEDTLS_SSL_MINOR_VERSION_0 0 /*!< SSL v3.0 */ +#define MBEDTLS_SSL_MINOR_VERSION_1 1 /*!< TLS v1.0 */ +#define MBEDTLS_SSL_MINOR_VERSION_2 2 /*!< TLS v1.1 */ +#define MBEDTLS_SSL_MINOR_VERSION_3 3 /*!< TLS v1.2 */ + +#define MBEDTLS_SSL_TRANSPORT_STREAM 0 /*!< TLS */ +#define MBEDTLS_SSL_TRANSPORT_DATAGRAM 1 /*!< DTLS */ + +#define MBEDTLS_SSL_MAX_HOST_NAME_LEN 255 /*!< Maximum host name defined in RFC 1035 */ + +/* RFC 6066 section 4, see also mfl_code_to_length in ssl_tls.c + * NONE must be zero so that memset()ing structure to zero works */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_NONE 0 /*!< don't use this extension */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_512 1 /*!< MaxFragmentLength 2^9 */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_1024 2 /*!< MaxFragmentLength 2^10 */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_2048 3 /*!< MaxFragmentLength 2^11 */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_4096 4 /*!< MaxFragmentLength 2^12 */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_INVALID 5 /*!< first invalid value */ + +#define MBEDTLS_SSL_IS_CLIENT 0 +#define MBEDTLS_SSL_IS_SERVER 1 + +#define MBEDTLS_SSL_IS_NOT_FALLBACK 0 +#define MBEDTLS_SSL_IS_FALLBACK 1 + +#define MBEDTLS_SSL_EXTENDED_MS_DISABLED 0 +#define MBEDTLS_SSL_EXTENDED_MS_ENABLED 1 + +#define MBEDTLS_SSL_CID_DISABLED 0 +#define MBEDTLS_SSL_CID_ENABLED 1 + +#define MBEDTLS_SSL_ETM_DISABLED 0 +#define MBEDTLS_SSL_ETM_ENABLED 1 + +#define MBEDTLS_SSL_COMPRESS_NULL 0 +#define MBEDTLS_SSL_COMPRESS_DEFLATE 1 + +#define MBEDTLS_SSL_VERIFY_NONE 0 +#define MBEDTLS_SSL_VERIFY_OPTIONAL 1 +#define MBEDTLS_SSL_VERIFY_REQUIRED 2 +#define MBEDTLS_SSL_VERIFY_UNSET 3 /* Used only for sni_authmode */ + +#define MBEDTLS_SSL_LEGACY_RENEGOTIATION 0 +#define MBEDTLS_SSL_SECURE_RENEGOTIATION 1 + +#define MBEDTLS_SSL_RENEGOTIATION_DISABLED 0 +#define MBEDTLS_SSL_RENEGOTIATION_ENABLED 1 + +#define MBEDTLS_SSL_ANTI_REPLAY_DISABLED 0 +#define MBEDTLS_SSL_ANTI_REPLAY_ENABLED 1 + +#define MBEDTLS_SSL_RENEGOTIATION_NOT_ENFORCED -1 +#define MBEDTLS_SSL_RENEGO_MAX_RECORDS_DEFAULT 16 + +#define MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION 0 +#define MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION 1 +#define MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE 2 + +#define MBEDTLS_SSL_TRUNC_HMAC_DISABLED 0 +#define MBEDTLS_SSL_TRUNC_HMAC_ENABLED 1 +#define MBEDTLS_SSL_TRUNCATED_HMAC_LEN 10 /* 80 bits, rfc 6066 section 7 */ + +#define MBEDTLS_SSL_SESSION_TICKETS_DISABLED 0 +#define MBEDTLS_SSL_SESSION_TICKETS_ENABLED 1 + +#define MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED 0 +#define MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED 1 + +#define MBEDTLS_SSL_ARC4_ENABLED 0 +#define MBEDTLS_SSL_ARC4_DISABLED 1 + +#define MBEDTLS_SSL_PRESET_DEFAULT 0 +#define MBEDTLS_SSL_PRESET_SUITEB 2 + +#define MBEDTLS_SSL_CERT_REQ_CA_LIST_ENABLED 1 +#define MBEDTLS_SSL_CERT_REQ_CA_LIST_DISABLED 0 + +/* + * Default range for DTLS retransmission timer value, in milliseconds. + * RFC 6347 4.2.4.1 says from 1 second to 60 seconds. + */ +#define MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN 1000 +#define MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MAX 60000 + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME) +#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +#endif + +/* + * Maximum fragment length in bytes, + * determines the size of each of the two internal I/O buffers. + * + * Note: the RFC defines the default size of SSL / TLS messages. If you + * change the value here, other clients / servers may not be able to + * communicate with you anymore. Only change this value if you control + * both sides of the connection and have it reduced at both sides, or + * if you're using the Max Fragment Length extension and you know all your + * peers are using it too! + */ +#if !defined(MBEDTLS_SSL_MAX_CONTENT_LEN) +#define MBEDTLS_SSL_MAX_CONTENT_LEN 16384 /**< Size of the input / output buffer */ +#endif + +#if !defined(MBEDTLS_SSL_IN_CONTENT_LEN) +#define MBEDTLS_SSL_IN_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN +#endif + +#if !defined(MBEDTLS_SSL_OUT_CONTENT_LEN) +#define MBEDTLS_SSL_OUT_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN +#endif + +/* + * Maximum number of heap-allocated bytes for the purpose of + * DTLS handshake message reassembly and future message buffering. + */ +#if !defined(MBEDTLS_SSL_DTLS_MAX_BUFFERING) +#define MBEDTLS_SSL_DTLS_MAX_BUFFERING 32768 +#endif + +/* + * Maximum length of CIDs for incoming and outgoing messages. + */ +#if !defined(MBEDTLS_SSL_CID_IN_LEN_MAX) +#define MBEDTLS_SSL_CID_IN_LEN_MAX 32 +#endif + +#if !defined(MBEDTLS_SSL_CID_OUT_LEN_MAX) +#define MBEDTLS_SSL_CID_OUT_LEN_MAX 32 +#endif + +#if !defined(MBEDTLS_SSL_CID_PADDING_GRANULARITY) +#define MBEDTLS_SSL_CID_PADDING_GRANULARITY 16 +#endif + +/* \} name SECTION: Module settings */ + +/* + * Length of the verify data for secure renegotiation + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) +#define MBEDTLS_SSL_VERIFY_DATA_MAX_LEN 36 +#else +#define MBEDTLS_SSL_VERIFY_DATA_MAX_LEN 12 +#endif + +/* + * Signaling ciphersuite values (SCSV) + */ +#define MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO 0xFF /**< renegotiation info ext */ +#define MBEDTLS_SSL_FALLBACK_SCSV_VALUE 0x5600 /**< RFC 7507 section 2 */ + +/* + * Supported Signature and Hash algorithms (For TLS 1.2) + * RFC 5246 section 7.4.1.4.1 + */ +#define MBEDTLS_SSL_HASH_NONE 0 +#define MBEDTLS_SSL_HASH_MD5 1 +#define MBEDTLS_SSL_HASH_SHA1 2 +#define MBEDTLS_SSL_HASH_SHA224 3 +#define MBEDTLS_SSL_HASH_SHA256 4 +#define MBEDTLS_SSL_HASH_SHA384 5 +#define MBEDTLS_SSL_HASH_SHA512 6 + +#define MBEDTLS_SSL_SIG_ANON 0 +#define MBEDTLS_SSL_SIG_RSA 1 +#define MBEDTLS_SSL_SIG_ECDSA 3 + +/* + * Client Certificate Types + * RFC 5246 section 7.4.4 plus RFC 4492 section 5.5 + */ +#define MBEDTLS_SSL_CERT_TYPE_RSA_SIGN 1 +#define MBEDTLS_SSL_CERT_TYPE_ECDSA_SIGN 64 + +/* + * Message, alert and handshake types + */ +#define MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC 20 +#define MBEDTLS_SSL_MSG_ALERT 21 +#define MBEDTLS_SSL_MSG_HANDSHAKE 22 +#define MBEDTLS_SSL_MSG_APPLICATION_DATA 23 +#define MBEDTLS_SSL_MSG_CID 25 + +#define MBEDTLS_SSL_ALERT_LEVEL_WARNING 1 +#define MBEDTLS_SSL_ALERT_LEVEL_FATAL 2 + +#define MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY 0 /* 0x00 */ +#define MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE 10 /* 0x0A */ +#define MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC 20 /* 0x14 */ +#define MBEDTLS_SSL_ALERT_MSG_DECRYPTION_FAILED 21 /* 0x15 */ +#define MBEDTLS_SSL_ALERT_MSG_RECORD_OVERFLOW 22 /* 0x16 */ +#define MBEDTLS_SSL_ALERT_MSG_DECOMPRESSION_FAILURE 30 /* 0x1E */ +#define MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE 40 /* 0x28 */ +#define MBEDTLS_SSL_ALERT_MSG_NO_CERT 41 /* 0x29 */ +#define MBEDTLS_SSL_ALERT_MSG_BAD_CERT 42 /* 0x2A */ +#define MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT 43 /* 0x2B */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED 44 /* 0x2C */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED 45 /* 0x2D */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN 46 /* 0x2E */ +#define MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER 47 /* 0x2F */ +#define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA 48 /* 0x30 */ +#define MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED 49 /* 0x31 */ +#define MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR 50 /* 0x32 */ +#define MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR 51 /* 0x33 */ +#define MBEDTLS_SSL_ALERT_MSG_EXPORT_RESTRICTION 60 /* 0x3C */ +#define MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION 70 /* 0x46 */ +#define MBEDTLS_SSL_ALERT_MSG_INSUFFICIENT_SECURITY 71 /* 0x47 */ +#define MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR 80 /* 0x50 */ +#define MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK 86 /* 0x56 */ +#define MBEDTLS_SSL_ALERT_MSG_USER_CANCELED 90 /* 0x5A */ +#define MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION 100 /* 0x64 */ +#define MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_EXT 110 /* 0x6E */ +#define MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME 112 /* 0x70 */ +#define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY 115 /* 0x73 */ +#define MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL 120 /* 0x78 */ + +#define MBEDTLS_SSL_HS_HELLO_REQUEST 0 +#define MBEDTLS_SSL_HS_CLIENT_HELLO 1 +#define MBEDTLS_SSL_HS_SERVER_HELLO 2 +#define MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST 3 +#define MBEDTLS_SSL_HS_NEW_SESSION_TICKET 4 +#define MBEDTLS_SSL_HS_CERTIFICATE 11 +#define MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE 12 +#define MBEDTLS_SSL_HS_CERTIFICATE_REQUEST 13 +#define MBEDTLS_SSL_HS_SERVER_HELLO_DONE 14 +#define MBEDTLS_SSL_HS_CERTIFICATE_VERIFY 15 +#define MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE 16 +#define MBEDTLS_SSL_HS_FINISHED 20 + +/* + * TLS extensions + */ +#define MBEDTLS_TLS_EXT_SERVERNAME 0 +#define MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME 0 + +#define MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH 1 + +#define MBEDTLS_TLS_EXT_TRUNCATED_HMAC 4 + +#define MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES 10 +#define MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS 11 + +#define MBEDTLS_TLS_EXT_SIG_ALG 13 + +#define MBEDTLS_TLS_EXT_ALPN 16 + +#define MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC 22 /* 0x16 */ +#define MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET 0x0017 /* 23 */ + +#define MBEDTLS_TLS_EXT_SESSION_TICKET 35 + +/* The value of the CID extension is still TBD as of + * draft-ietf-tls-dtls-connection-id-05 + * (https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05) */ +#define MBEDTLS_TLS_EXT_CID 254 /* TBD */ + +#define MBEDTLS_TLS_EXT_ECJPAKE_KKPP 256 /* experimental */ + +#define MBEDTLS_TLS_EXT_RENEGOTIATION_INFO 0xFF01 + +/* + * Size defines + */ +#if !defined(MBEDTLS_PSK_MAX_LEN) +#define MBEDTLS_PSK_MAX_LEN 32 /* 256 bits */ +#endif + +/* Dummy type used only for its size */ +union mbedtls_ssl_premaster_secret +{ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + unsigned char _pms_rsa[48]; /* RFC 5246 8.1.1 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + unsigned char _pms_dhm[MBEDTLS_MPI_MAX_SIZE]; /* RFC 5246 8.1.2 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + unsigned char _pms_ecdh[MBEDTLS_ECP_MAX_BYTES]; /* RFC 4492 5.10 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + unsigned char _pms_psk[4 + 2 * MBEDTLS_PSK_MAX_LEN]; /* RFC 4279 2 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + unsigned char _pms_dhe_psk[4 + MBEDTLS_MPI_MAX_SIZE + + MBEDTLS_PSK_MAX_LEN]; /* RFC 4279 3 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + unsigned char _pms_rsa_psk[52 + MBEDTLS_PSK_MAX_LEN]; /* RFC 4279 4 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + unsigned char _pms_ecdhe_psk[4 + MBEDTLS_ECP_MAX_BYTES + + MBEDTLS_PSK_MAX_LEN]; /* RFC 5489 2 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + unsigned char _pms_ecjpake[32]; /* Thread spec: SHA-256 output */ +#endif +}; + +#define MBEDTLS_PREMASTER_SIZE sizeof( union mbedtls_ssl_premaster_secret ) + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * SSL state machine + */ +typedef enum +{ + MBEDTLS_SSL_HELLO_REQUEST, + MBEDTLS_SSL_CLIENT_HELLO, + MBEDTLS_SSL_SERVER_HELLO, + MBEDTLS_SSL_SERVER_CERTIFICATE, + MBEDTLS_SSL_SERVER_KEY_EXCHANGE, + MBEDTLS_SSL_CERTIFICATE_REQUEST, + MBEDTLS_SSL_SERVER_HELLO_DONE, + MBEDTLS_SSL_CLIENT_CERTIFICATE, + MBEDTLS_SSL_CLIENT_KEY_EXCHANGE, + MBEDTLS_SSL_CERTIFICATE_VERIFY, + MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC, + MBEDTLS_SSL_CLIENT_FINISHED, + MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC, + MBEDTLS_SSL_SERVER_FINISHED, + MBEDTLS_SSL_FLUSH_BUFFERS, + MBEDTLS_SSL_HANDSHAKE_WRAPUP, + MBEDTLS_SSL_HANDSHAKE_OVER, + MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET, + MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT, +} +mbedtls_ssl_states; + +/* + * The tls_prf function types. + */ +typedef enum +{ + MBEDTLS_SSL_TLS_PRF_NONE, + MBEDTLS_SSL_TLS_PRF_SSL3, + MBEDTLS_SSL_TLS_PRF_TLS1, + MBEDTLS_SSL_TLS_PRF_SHA384, + MBEDTLS_SSL_TLS_PRF_SHA256 +} +mbedtls_tls_prf_types; +/** + * \brief Callback type: send data on the network. + * + * \note That callback may be either blocking or non-blocking. + * + * \param ctx Context for the send callback (typically a file descriptor) + * \param buf Buffer holding the data to send + * \param len Length of the data to send + * + * \return The callback must return the number of bytes sent if any, + * or a non-zero error code. + * If performing non-blocking I/O, \c MBEDTLS_ERR_SSL_WANT_WRITE + * must be returned when the operation would block. + * + * \note The callback is allowed to send fewer bytes than requested. + * It must always return the number of bytes actually sent. + */ +typedef int mbedtls_ssl_send_t( void *ctx, + const unsigned char *buf, + size_t len ); + +/** + * \brief Callback type: receive data from the network. + * + * \note That callback may be either blocking or non-blocking. + * + * \param ctx Context for the receive callback (typically a file + * descriptor) + * \param buf Buffer to write the received data to + * \param len Length of the receive buffer + * + * \return The callback must return the number of bytes received, + * or a non-zero error code. + * If performing non-blocking I/O, \c MBEDTLS_ERR_SSL_WANT_READ + * must be returned when the operation would block. + * + * \note The callback may receive fewer bytes than the length of the + * buffer. It must always return the number of bytes actually + * received and written to the buffer. + */ +typedef int mbedtls_ssl_recv_t( void *ctx, + unsigned char *buf, + size_t len ); + +/** + * \brief Callback type: receive data from the network, with timeout + * + * \note That callback must block until data is received, or the + * timeout delay expires, or the operation is interrupted by a + * signal. + * + * \param ctx Context for the receive callback (typically a file descriptor) + * \param buf Buffer to write the received data to + * \param len Length of the receive buffer + * \param timeout Maximum nomber of millisecondes to wait for data + * 0 means no timeout (potentially waiting forever) + * + * \return The callback must return the number of bytes received, + * or a non-zero error code: + * \c MBEDTLS_ERR_SSL_TIMEOUT if the operation timed out, + * \c MBEDTLS_ERR_SSL_WANT_READ if interrupted by a signal. + * + * \note The callback may receive fewer bytes than the length of the + * buffer. It must always return the number of bytes actually + * received and written to the buffer. + */ +typedef int mbedtls_ssl_recv_timeout_t( void *ctx, + unsigned char *buf, + size_t len, + uint32_t timeout ); +/** + * \brief Callback type: set a pair of timers/delays to watch + * + * \param ctx Context pointer + * \param int_ms Intermediate delay in milliseconds + * \param fin_ms Final delay in milliseconds + * 0 cancels the current timer. + * + * \note This callback must at least store the necessary information + * for the associated \c mbedtls_ssl_get_timer_t callback to + * return correct information. + * + * \note If using a event-driven style of programming, an event must + * be generated when the final delay is passed. The event must + * cause a call to \c mbedtls_ssl_handshake() with the proper + * SSL context to be scheduled. Care must be taken to ensure + * that at most one such call happens at a time. + * + * \note Only one timer at a time must be running. Calling this + * function while a timer is running must cancel it. Cancelled + * timers must not generate any event. + */ +typedef void mbedtls_ssl_set_timer_t( void * ctx, + uint32_t int_ms, + uint32_t fin_ms ); + +/** + * \brief Callback type: get status of timers/delays + * + * \param ctx Context pointer + * + * \return This callback must return: + * -1 if cancelled (fin_ms == 0), + * 0 if none of the delays have passed, + * 1 if only the intermediate delay has passed, + * 2 if the final delay has passed. + */ +typedef int mbedtls_ssl_get_timer_t( void * ctx ); + +/* Defined below */ +typedef struct mbedtls_ssl_session mbedtls_ssl_session; +typedef struct mbedtls_ssl_context mbedtls_ssl_context; +typedef struct mbedtls_ssl_config mbedtls_ssl_config; + +/* Defined in ssl_internal.h */ +typedef struct mbedtls_ssl_transform mbedtls_ssl_transform; +typedef struct mbedtls_ssl_handshake_params mbedtls_ssl_handshake_params; +typedef struct mbedtls_ssl_sig_hash_set_t mbedtls_ssl_sig_hash_set_t; +#if defined(MBEDTLS_X509_CRT_PARSE_C) +typedef struct mbedtls_ssl_key_cert mbedtls_ssl_key_cert; +#endif +#if defined(MBEDTLS_SSL_PROTO_DTLS) +typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; +#endif + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Callback type: start external signature operation. + * + * This callback is called during an SSL handshake to start + * a signature decryption operation using an + * external processor. The parameter \p cert contains + * the public key; it is up to the callback function to + * determine how to access the associated private key. + * + * This function typically sends or enqueues a request, and + * does not wait for the operation to complete. This allows + * the handshake step to be non-blocking. + * + * The parameters \p ssl and \p cert are guaranteed to remain + * valid throughout the handshake. On the other hand, this + * function must save the contents of \p hash if the value + * is needed for later processing, because the \p hash buffer + * is no longer valid after this function returns. + * + * This function may call mbedtls_ssl_set_async_operation_data() + * to store an operation context for later retrieval + * by the resume or cancel callback. + * + * \note For RSA signatures, this function must produce output + * that is consistent with PKCS#1 v1.5 in the same way as + * mbedtls_rsa_pkcs1_sign(). Before the private key operation, + * apply the padding steps described in RFC 8017, section 9.2 + * "EMSA-PKCS1-v1_5" as follows. + * - If \p md_alg is #MBEDTLS_MD_NONE, apply the PKCS#1 v1.5 + * encoding, treating \p hash as the DigestInfo to be + * padded. In other words, apply EMSA-PKCS1-v1_5 starting + * from step 3, with `T = hash` and `tLen = hash_len`. + * - If `md_alg != MBEDTLS_MD_NONE`, apply the PKCS#1 v1.5 + * encoding, treating \p hash as the hash to be encoded and + * padded. In other words, apply EMSA-PKCS1-v1_5 starting + * from step 2, with `digestAlgorithm` obtained by calling + * mbedtls_oid_get_oid_by_md() on \p md_alg. + * + * \note For ECDSA signatures, the output format is the DER encoding + * `Ecdsa-Sig-Value` defined in + * [RFC 4492 section 5.4](https://tools.ietf.org/html/rfc4492#section-5.4). + * + * \param ssl The SSL connection instance. It should not be + * modified other than via + * mbedtls_ssl_set_async_operation_data(). + * \param cert Certificate containing the public key. + * In simple cases, this is one of the pointers passed to + * mbedtls_ssl_conf_own_cert() when configuring the SSL + * connection. However, if other callbacks are used, this + * property may not hold. For example, if an SNI callback + * is registered with mbedtls_ssl_conf_sni(), then + * this callback determines what certificate is used. + * \param md_alg Hash algorithm. + * \param hash Buffer containing the hash. This buffer is + * no longer valid when the function returns. + * \param hash_len Size of the \c hash buffer in bytes. + * + * \return 0 if the operation was started successfully and the SSL + * stack should call the resume callback immediately. + * \return #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if the operation + * was started successfully and the SSL stack should return + * immediately without calling the resume callback yet. + * \return #MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH if the external + * processor does not support this key. The SSL stack will + * use the private key object instead. + * \return Any other error indicates a fatal failure and is + * propagated up the call chain. The callback should + * use \c MBEDTLS_ERR_PK_xxx error codes, and must not + * use \c MBEDTLS_ERR_SSL_xxx error codes except as + * directed in the documentation of this callback. + */ +typedef int mbedtls_ssl_async_sign_t( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *cert, + mbedtls_md_type_t md_alg, + const unsigned char *hash, + size_t hash_len ); + +/** + * \brief Callback type: start external decryption operation. + * + * This callback is called during an SSL handshake to start + * an RSA decryption operation using an + * external processor. The parameter \p cert contains + * the public key; it is up to the callback function to + * determine how to access the associated private key. + * + * This function typically sends or enqueues a request, and + * does not wait for the operation to complete. This allows + * the handshake step to be non-blocking. + * + * The parameters \p ssl and \p cert are guaranteed to remain + * valid throughout the handshake. On the other hand, this + * function must save the contents of \p input if the value + * is needed for later processing, because the \p input buffer + * is no longer valid after this function returns. + * + * This function may call mbedtls_ssl_set_async_operation_data() + * to store an operation context for later retrieval + * by the resume or cancel callback. + * + * \warning RSA decryption as used in TLS is subject to a potential + * timing side channel attack first discovered by Bleichenbacher + * in 1998. This attack can be remotely exploitable + * in practice. To avoid this attack, you must ensure that + * if the callback performs an RSA decryption, the time it + * takes to execute and return the result does not depend + * on whether the RSA decryption succeeded or reported + * invalid padding. + * + * \param ssl The SSL connection instance. It should not be + * modified other than via + * mbedtls_ssl_set_async_operation_data(). + * \param cert Certificate containing the public key. + * In simple cases, this is one of the pointers passed to + * mbedtls_ssl_conf_own_cert() when configuring the SSL + * connection. However, if other callbacks are used, this + * property may not hold. For example, if an SNI callback + * is registered with mbedtls_ssl_conf_sni(), then + * this callback determines what certificate is used. + * \param input Buffer containing the input ciphertext. This buffer + * is no longer valid when the function returns. + * \param input_len Size of the \p input buffer in bytes. + * + * \return 0 if the operation was started successfully and the SSL + * stack should call the resume callback immediately. + * \return #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if the operation + * was started successfully and the SSL stack should return + * immediately without calling the resume callback yet. + * \return #MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH if the external + * processor does not support this key. The SSL stack will + * use the private key object instead. + * \return Any other error indicates a fatal failure and is + * propagated up the call chain. The callback should + * use \c MBEDTLS_ERR_PK_xxx error codes, and must not + * use \c MBEDTLS_ERR_SSL_xxx error codes except as + * directed in the documentation of this callback. + */ +typedef int mbedtls_ssl_async_decrypt_t( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *cert, + const unsigned char *input, + size_t input_len ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/** + * \brief Callback type: resume external operation. + * + * This callback is called during an SSL handshake to resume + * an external operation started by the + * ::mbedtls_ssl_async_sign_t or + * ::mbedtls_ssl_async_decrypt_t callback. + * + * This function typically checks the status of a pending + * request or causes the request queue to make progress, and + * does not wait for the operation to complete. This allows + * the handshake step to be non-blocking. + * + * This function may call mbedtls_ssl_get_async_operation_data() + * to retrieve an operation context set by the start callback. + * It may call mbedtls_ssl_set_async_operation_data() to modify + * this context. + * + * Note that when this function returns a status other than + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS, it must free any + * resources associated with the operation. + * + * \param ssl The SSL connection instance. It should not be + * modified other than via + * mbedtls_ssl_set_async_operation_data(). + * \param output Buffer containing the output (signature or decrypted + * data) on success. + * \param output_len On success, number of bytes written to \p output. + * \param output_size Size of the \p output buffer in bytes. + * + * \return 0 if output of the operation is available in the + * \p output buffer. + * \return #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if the operation + * is still in progress. Subsequent requests for progress + * on the SSL connection will call the resume callback + * again. + * \return Any other error means that the operation is aborted. + * The SSL handshake is aborted. The callback should + * use \c MBEDTLS_ERR_PK_xxx error codes, and must not + * use \c MBEDTLS_ERR_SSL_xxx error codes except as + * directed in the documentation of this callback. + */ +typedef int mbedtls_ssl_async_resume_t( mbedtls_ssl_context *ssl, + unsigned char *output, + size_t *output_len, + size_t output_size ); + +/** + * \brief Callback type: cancel external operation. + * + * This callback is called if an SSL connection is closed + * while an asynchronous operation is in progress. Note that + * this callback is not called if the + * ::mbedtls_ssl_async_resume_t callback has run and has + * returned a value other than + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS, since in that case + * the asynchronous operation has already completed. + * + * This function may call mbedtls_ssl_get_async_operation_data() + * to retrieve an operation context set by the start callback. + * + * \param ssl The SSL connection instance. It should not be + * modified. + */ +typedef void mbedtls_ssl_async_cancel_t( mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) && \ + !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) +#define MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN 48 +#if defined(MBEDTLS_SHA256_C) +#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE MBEDTLS_MD_SHA256 +#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN 32 +#elif defined(MBEDTLS_SHA512_C) +#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE MBEDTLS_MD_SHA384 +#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN 48 +#elif defined(MBEDTLS_SHA1_C) +#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE MBEDTLS_MD_SHA1 +#define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN 20 +#else +/* This is already checked in check_config.h, but be sure. */ +#error "Bad configuration - need SHA-1, SHA-256 or SHA-512 enabled to compute digest of peer CRT." +#endif +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED && + !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + +/* + * This structure is used for storing current session data. + */ +struct mbedtls_ssl_session +{ +#if defined(MBEDTLS_HAVE_TIME) + mbedtls_time_t start; /*!< starting time */ +#endif + int ciphersuite; /*!< chosen ciphersuite */ + int compression; /*!< chosen compression */ + size_t id_len; /*!< session id length */ + unsigned char id[32]; /*!< session identifier */ + unsigned char master[48]; /*!< the master secret */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + mbedtls_x509_crt *peer_cert; /*!< peer X.509 cert chain */ +#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + /*! The digest of the peer's end-CRT. This must be kept to detect CRT + * changes during renegotiation, mitigating the triple handshake attack. */ + unsigned char *peer_cert_digest; + size_t peer_cert_digest_len; + mbedtls_md_type_t peer_cert_digest_type; +#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + uint32_t verify_result; /*!< verification result */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) + unsigned char *ticket; /*!< RFC 5077 session ticket */ + size_t ticket_len; /*!< session ticket length */ + uint32_t ticket_lifetime; /*!< ticket lifetime hint */ +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + unsigned char mfl_code; /*!< MaxFragmentLength negotiated by peer */ +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + int trunc_hmac; /*!< flag for truncated hmac activation */ +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + int encrypt_then_mac; /*!< flag for EtM activation */ +#endif +}; + +/** + * SSL/TLS configuration to be shared between mbedtls_ssl_context structures. + */ +struct mbedtls_ssl_config +{ + /* Group items by size (largest first) to minimize padding overhead */ + + /* + * Pointers + */ + + const int *ciphersuite_list[4]; /*!< allowed ciphersuites per version */ + + /** Callback for printing debug output */ + void (*f_dbg)(void *, int, const char *, int, const char *); + void *p_dbg; /*!< context for the debug function */ + + /** Callback for getting (pseudo-)random numbers */ + int (*f_rng)(void *, unsigned char *, size_t); + void *p_rng; /*!< context for the RNG function */ + + /** Callback to retrieve a session from the cache */ + int (*f_get_cache)(void *, mbedtls_ssl_session *); + /** Callback to store a session into the cache */ + int (*f_set_cache)(void *, const mbedtls_ssl_session *); + void *p_cache; /*!< context for cache callbacks */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + /** Callback for setting cert according to SNI extension */ + int (*f_sni)(void *, mbedtls_ssl_context *, const unsigned char *, size_t); + void *p_sni; /*!< context for SNI callback */ +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + /** Callback to customize X.509 certificate chain verification */ + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *); + void *p_vrfy; /*!< context for X.509 verify calllback */ +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + /** Callback to retrieve PSK key from identity */ + int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *, size_t); + void *p_psk; /*!< context for PSK callback */ +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + /** Callback to create & write a cookie for ClientHello veirifcation */ + int (*f_cookie_write)( void *, unsigned char **, unsigned char *, + const unsigned char *, size_t ); + /** Callback to verify validity of a ClientHello cookie */ + int (*f_cookie_check)( void *, const unsigned char *, size_t, + const unsigned char *, size_t ); + void *p_cookie; /*!< context for the cookie callbacks */ +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_SRV_C) + /** Callback to create & write a session ticket */ + int (*f_ticket_write)( void *, const mbedtls_ssl_session *, + unsigned char *, const unsigned char *, size_t *, uint32_t * ); + /** Callback to parse a session ticket into a session structure */ + int (*f_ticket_parse)( void *, mbedtls_ssl_session *, unsigned char *, size_t); + void *p_ticket; /*!< context for the ticket callbacks */ +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + /** Callback to export key block and master secret */ + int (*f_export_keys)( void *, const unsigned char *, + const unsigned char *, size_t, size_t, size_t ); + /** Callback to export key block, master secret, + * tls_prf and random bytes. Should replace f_export_keys */ + int (*f_export_keys_ext)( void *, const unsigned char *, + const unsigned char *, size_t, size_t, size_t, + unsigned char[32], unsigned char[32], mbedtls_tls_prf_types ); + void *p_export_keys; /*!< context for key export callback */ +#endif + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + size_t cid_len; /*!< The length of CIDs for incoming DTLS records. */ +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + const mbedtls_x509_crt_profile *cert_profile; /*!< verification profile */ + mbedtls_ssl_key_cert *key_cert; /*!< own certificate/key pair(s) */ + mbedtls_x509_crt *ca_chain; /*!< trusted CAs */ + mbedtls_x509_crl *ca_crl; /*!< trusted CAs CRLs */ +#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) + mbedtls_x509_crt_ca_cb_t f_ca_cb; + void *p_ca_cb; +#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) +#if defined(MBEDTLS_X509_CRT_PARSE_C) + mbedtls_ssl_async_sign_t *f_async_sign_start; /*!< start asynchronous signature operation */ + mbedtls_ssl_async_decrypt_t *f_async_decrypt_start; /*!< start asynchronous decryption operation */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + mbedtls_ssl_async_resume_t *f_async_resume; /*!< resume asynchronous operation */ + mbedtls_ssl_async_cancel_t *f_async_cancel; /*!< cancel asynchronous operation */ + void *p_async_config_data; /*!< Configuration data set by mbedtls_ssl_conf_async_private_cb(). */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + const int *sig_hashes; /*!< allowed signature hashes */ +#endif + +#if defined(MBEDTLS_ECP_C) + const mbedtls_ecp_group_id *curve_list; /*!< allowed curves */ +#endif + +#if defined(MBEDTLS_DHM_C) + mbedtls_mpi dhm_P; /*!< prime modulus for DHM */ + mbedtls_mpi dhm_G; /*!< generator for DHM */ +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_key_handle_t psk_opaque; /*!< PSA key slot holding opaque PSK. + * This field should only be set via + * mbedtls_ssl_conf_psk_opaque(). + * If either no PSK or a raw PSK have + * been configured, this has value \c 0. */ +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + unsigned char *psk; /*!< The raw pre-shared key. This field should + * only be set via mbedtls_ssl_conf_psk(). + * If either no PSK or an opaque PSK + * have been configured, this has value NULL. */ + size_t psk_len; /*!< The length of the raw pre-shared key. + * This field should only be set via + * mbedtls_ssl_conf_psk(). + * Its value is non-zero if and only if + * \c psk is not \c NULL. */ + + unsigned char *psk_identity; /*!< The PSK identity for PSK negotiation. + * This field should only be set via + * mbedtls_ssl_conf_psk(). + * This is set if and only if either + * \c psk or \c psk_opaque are set. */ + size_t psk_identity_len;/*!< The length of PSK identity. + * This field should only be set via + * mbedtls_ssl_conf_psk(). + * Its value is non-zero if and only if + * \c psk is not \c NULL or \c psk_opaque + * is not \c 0. */ +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_SSL_ALPN) + const char **alpn_list; /*!< ordered list of protocols */ +#endif + + /* + * Numerical settings (int then char) + */ + + uint32_t read_timeout; /*!< timeout for mbedtls_ssl_read (ms) */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + uint32_t hs_timeout_min; /*!< initial value of the handshake + retransmission timeout (ms) */ + uint32_t hs_timeout_max; /*!< maximum value of the handshake + retransmission timeout (ms) */ +#endif + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renego_max_records; /*!< grace period for renegotiation */ + unsigned char renego_period[8]; /*!< value of the record counters + that triggers renegotiation */ +#endif + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) + unsigned int badmac_limit; /*!< limit of records with a bad MAC */ +#endif + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C) + unsigned int dhm_min_bitlen; /*!< min. bit length of the DHM prime */ +#endif + + unsigned char max_major_ver; /*!< max. major version used */ + unsigned char max_minor_ver; /*!< max. minor version used */ + unsigned char min_major_ver; /*!< min. major version used */ + unsigned char min_minor_ver; /*!< min. minor version used */ + + /* + * Flags (bitfields) + */ + + unsigned int endpoint : 1; /*!< 0: client, 1: server */ + unsigned int transport : 1; /*!< stream (TLS) or datagram (DTLS) */ + unsigned int authmode : 2; /*!< MBEDTLS_SSL_VERIFY_XXX */ + /* needed even with renego disabled for LEGACY_BREAK_HANDSHAKE */ + unsigned int allow_legacy_renegotiation : 2 ; /*!< MBEDTLS_LEGACY_XXX */ +#if defined(MBEDTLS_ARC4_C) + unsigned int arc4_disabled : 1; /*!< blacklist RC4 ciphersuites? */ +#endif +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + unsigned int mfl_code : 3; /*!< desired fragment length */ +#endif +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + unsigned int encrypt_then_mac : 1 ; /*!< negotiate encrypt-then-mac? */ +#endif +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + unsigned int extended_ms : 1; /*!< negotiate extended master secret? */ +#endif +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + unsigned int anti_replay : 1; /*!< detect and prevent replay? */ +#endif +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + unsigned int cbc_record_splitting : 1; /*!< do cbc record splitting */ +#endif +#if defined(MBEDTLS_SSL_RENEGOTIATION) + unsigned int disable_renegotiation : 1; /*!< disable renegotiation? */ +#endif +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + unsigned int trunc_hmac : 1; /*!< negotiate truncated hmac? */ +#endif +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + unsigned int session_tickets : 1; /*!< use session tickets? */ +#endif +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) && defined(MBEDTLS_SSL_CLI_C) + unsigned int fallback : 1; /*!< is this a fallback? */ +#endif +#if defined(MBEDTLS_SSL_SRV_C) + unsigned int cert_req_ca_list : 1; /*!< enable sending CA list in + Certificate Request messages? */ +#endif +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + unsigned int ignore_unexpected_cid : 1; /*!< Determines whether DTLS + * record with unexpected CID + * should lead to failure. */ +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ +}; + + +struct mbedtls_ssl_context +{ + const mbedtls_ssl_config *conf; /*!< configuration information */ + + /* + * Miscellaneous + */ + int state; /*!< SSL handshake: current state */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renego_status; /*!< Initial, in progress, pending? */ + int renego_records_seen; /*!< Records since renego request, or with DTLS, + number of retransmissions of request if + renego_max_records is < 0 */ +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + int major_ver; /*!< equal to MBEDTLS_SSL_MAJOR_VERSION_3 */ + int minor_ver; /*!< either 0 (SSL3) or 1 (TLS1.0) */ + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) + unsigned badmac_seen; /*!< records with a bad MAC received */ +#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + /** Callback to customize X.509 certificate chain verification */ + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *); + void *p_vrfy; /*!< context for X.509 verify callback */ +#endif + + mbedtls_ssl_send_t *f_send; /*!< Callback for network send */ + mbedtls_ssl_recv_t *f_recv; /*!< Callback for network receive */ + mbedtls_ssl_recv_timeout_t *f_recv_timeout; + /*!< Callback for network receive with timeout */ + + void *p_bio; /*!< context for I/O operations */ + + /* + * Session layer + */ + mbedtls_ssl_session *session_in; /*!< current session data (in) */ + mbedtls_ssl_session *session_out; /*!< current session data (out) */ + mbedtls_ssl_session *session; /*!< negotiated session data */ + mbedtls_ssl_session *session_negotiate; /*!< session data in negotiation */ + + mbedtls_ssl_handshake_params *handshake; /*!< params required only during + the handshake process */ + + /* + * Record layer transformations + */ + mbedtls_ssl_transform *transform_in; /*!< current transform params (in) */ + mbedtls_ssl_transform *transform_out; /*!< current transform params (in) */ + mbedtls_ssl_transform *transform; /*!< negotiated transform params */ + mbedtls_ssl_transform *transform_negotiate; /*!< transform params in negotiation */ + + /* + * Timers + */ + void *p_timer; /*!< context for the timer callbacks */ + + mbedtls_ssl_set_timer_t *f_set_timer; /*!< set timer callback */ + mbedtls_ssl_get_timer_t *f_get_timer; /*!< get timer callback */ + + /* + * Record layer (incoming data) + */ + unsigned char *in_buf; /*!< input buffer */ + unsigned char *in_ctr; /*!< 64-bit incoming message counter + TLS: maintained by us + DTLS: read from peer */ + unsigned char *in_hdr; /*!< start of record header */ +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + unsigned char *in_cid; /*!< The start of the CID; + * (the end is marked by in_len). */ +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + unsigned char *in_len; /*!< two-bytes message length field */ + unsigned char *in_iv; /*!< ivlen-byte IV */ + unsigned char *in_msg; /*!< message contents (in_iv+ivlen) */ + unsigned char *in_offt; /*!< read offset in application data */ + + int in_msgtype; /*!< record header: message type */ + size_t in_msglen; /*!< record header: message length */ + size_t in_left; /*!< amount of data read so far */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + uint16_t in_epoch; /*!< DTLS epoch for incoming records */ + size_t next_record_offset; /*!< offset of the next record in datagram + (equal to in_left if none) */ +#endif /* MBEDTLS_SSL_PROTO_DTLS */ +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + uint64_t in_window_top; /*!< last validated record seq_num */ + uint64_t in_window; /*!< bitmask for replay detection */ +#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */ + + size_t in_hslen; /*!< current handshake message length, + including the handshake header */ + int nb_zero; /*!< # of 0-length encrypted messages */ + + int keep_current_message; /*!< drop or reuse current message + on next call to record layer? */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + uint8_t disable_datagram_packing; /*!< Disable packing multiple records + * within a single datagram. */ +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + /* + * Record layer (outgoing data) + */ + unsigned char *out_buf; /*!< output buffer */ + unsigned char *out_ctr; /*!< 64-bit outgoing message counter */ + unsigned char *out_hdr; /*!< start of record header */ +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + unsigned char *out_cid; /*!< The start of the CID; + * (the end is marked by in_len). */ +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + unsigned char *out_len; /*!< two-bytes message length field */ + unsigned char *out_iv; /*!< ivlen-byte IV */ + unsigned char *out_msg; /*!< message contents (out_iv+ivlen) */ + + int out_msgtype; /*!< record header: message type */ + size_t out_msglen; /*!< record header: message length */ + size_t out_left; /*!< amount of data not yet written */ + + unsigned char cur_out_ctr[8]; /*!< Outgoing record sequence number. */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + uint16_t mtu; /*!< path mtu, used to fragment outgoing messages */ +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +#if defined(MBEDTLS_ZLIB_SUPPORT) + unsigned char *compress_buf; /*!< zlib data buffer */ +#endif /* MBEDTLS_ZLIB_SUPPORT */ +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + signed char split_done; /*!< current record already splitted? */ +#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ + + /* + * PKI layer + */ + int client_auth; /*!< flag for client auth. */ + + /* + * User settings + */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + char *hostname; /*!< expected peer CN for verification + (and SNI if available) */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_ALPN) + const char *alpn_chosen; /*!< negotiated protocol */ +#endif /* MBEDTLS_SSL_ALPN */ + + /* + * Information for DTLS hello verify + */ +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + unsigned char *cli_id; /*!< transport-level ID of the client */ + size_t cli_id_len; /*!< length of cli_id */ +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */ + + /* + * Secure renegotiation + */ + /* needed to know when to send extension on server */ + int secure_renegotiation; /*!< does peer support legacy or + secure renegotiation */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + size_t verify_data_len; /*!< length of verify data stored */ + char own_verify_data[MBEDTLS_SSL_VERIFY_DATA_MAX_LEN]; /*!< previous handshake verify data */ + char peer_verify_data[MBEDTLS_SSL_VERIFY_DATA_MAX_LEN]; /*!< previous handshake verify data */ +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + /* CID configuration to use in subsequent handshakes. */ + + /*! The next incoming CID, chosen by the user and applying to + * all subsequent handshakes. This may be different from the + * CID currently used in case the user has re-configured the CID + * after an initial handshake. */ + unsigned char own_cid[ MBEDTLS_SSL_CID_IN_LEN_MAX ]; + uint8_t own_cid_len; /*!< The length of \c own_cid. */ + uint8_t negotiate_cid; /*!< This indicates whether the CID extension should + * be negotiated in the next handshake or not. + * Possible values are #MBEDTLS_SSL_CID_ENABLED + * and #MBEDTLS_SSL_CID_DISABLED. */ +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ +}; + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + +#define MBEDTLS_SSL_CHANNEL_OUTBOUND 0 +#define MBEDTLS_SSL_CHANNEL_INBOUND 1 + +extern int (*mbedtls_ssl_hw_record_init)(mbedtls_ssl_context *ssl, + const unsigned char *key_enc, const unsigned char *key_dec, + size_t keylen, + const unsigned char *iv_enc, const unsigned char *iv_dec, + size_t ivlen, + const unsigned char *mac_enc, const unsigned char *mac_dec, + size_t maclen); +extern int (*mbedtls_ssl_hw_record_activate)(mbedtls_ssl_context *ssl, int direction); +extern int (*mbedtls_ssl_hw_record_reset)(mbedtls_ssl_context *ssl); +extern int (*mbedtls_ssl_hw_record_write)(mbedtls_ssl_context *ssl); +extern int (*mbedtls_ssl_hw_record_read)(mbedtls_ssl_context *ssl); +extern int (*mbedtls_ssl_hw_record_finish)(mbedtls_ssl_context *ssl); +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + +/** + * \brief Return the name of the ciphersuite associated with the + * given ID + * + * \param ciphersuite_id SSL ciphersuite ID + * + * \return a string containing the ciphersuite name + */ +const char *mbedtls_ssl_get_ciphersuite_name( const int ciphersuite_id ); + +/** + * \brief Return the ID of the ciphersuite associated with the + * given name + * + * \param ciphersuite_name SSL ciphersuite name + * + * \return the ID with the ciphersuite or 0 if not found + */ +int mbedtls_ssl_get_ciphersuite_id( const char *ciphersuite_name ); + +/** + * \brief Initialize an SSL context + * Just makes the context ready for mbedtls_ssl_setup() or + * mbedtls_ssl_free() + * + * \param ssl SSL context + */ +void mbedtls_ssl_init( mbedtls_ssl_context *ssl ); + +/** + * \brief Set up an SSL context for use + * + * \note No copy of the configuration context is made, it can be + * shared by many mbedtls_ssl_context structures. + * + * \warning The conf structure will be accessed during the session. + * It must not be modified or freed as long as the session + * is active. + * + * \warning This function must be called exactly once per context. + * Calling mbedtls_ssl_setup again is not supported, even + * if no session is active. + * + * \param ssl SSL context + * \param conf SSL configuration to use + * + * \return 0 if successful, or MBEDTLS_ERR_SSL_ALLOC_FAILED if + * memory allocation failed + */ +int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, + const mbedtls_ssl_config *conf ); + +/** + * \brief Reset an already initialized SSL context for re-use + * while retaining application-set variables, function + * pointers and data. + * + * \param ssl SSL context + * \return 0 if successful, or MBEDTLS_ERR_SSL_ALLOC_FAILED, + MBEDTLS_ERR_SSL_HW_ACCEL_FAILED or + * MBEDTLS_ERR_SSL_COMPRESSION_FAILED + */ +int mbedtls_ssl_session_reset( mbedtls_ssl_context *ssl ); + +/** + * \brief Set the current endpoint type + * + * \param conf SSL configuration + * \param endpoint must be MBEDTLS_SSL_IS_CLIENT or MBEDTLS_SSL_IS_SERVER + */ +void mbedtls_ssl_conf_endpoint( mbedtls_ssl_config *conf, int endpoint ); + +/** + * \brief Set the transport type (TLS or DTLS). + * Default: TLS + * + * \note For DTLS, you must either provide a recv callback that + * doesn't block, or one that handles timeouts, see + * \c mbedtls_ssl_set_bio(). You also need to provide timer + * callbacks with \c mbedtls_ssl_set_timer_cb(). + * + * \param conf SSL configuration + * \param transport transport type: + * MBEDTLS_SSL_TRANSPORT_STREAM for TLS, + * MBEDTLS_SSL_TRANSPORT_DATAGRAM for DTLS. + */ +void mbedtls_ssl_conf_transport( mbedtls_ssl_config *conf, int transport ); + +/** + * \brief Set the certificate verification mode + * Default: NONE on server, REQUIRED on client + * + * \param conf SSL configuration + * \param authmode can be: + * + * MBEDTLS_SSL_VERIFY_NONE: peer certificate is not checked + * (default on server) + * (insecure on client) + * + * MBEDTLS_SSL_VERIFY_OPTIONAL: peer certificate is checked, however the + * handshake continues even if verification failed; + * mbedtls_ssl_get_verify_result() can be called after the + * handshake is complete. + * + * MBEDTLS_SSL_VERIFY_REQUIRED: peer *must* present a valid certificate, + * handshake is aborted if verification failed. + * (default on client) + * + * \note On client, MBEDTLS_SSL_VERIFY_REQUIRED is the recommended mode. + * With MBEDTLS_SSL_VERIFY_OPTIONAL, the user needs to call mbedtls_ssl_get_verify_result() at + * the right time(s), which may not be obvious, while REQUIRED always perform + * the verification as soon as possible. For example, REQUIRED was protecting + * against the "triple handshake" attack even before it was found. + */ +void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Set the verification callback (Optional). + * + * If set, the provided verify callback is called for each + * certificate in the peer's CRT chain, including the trusted + * root. For more information, please see the documentation of + * \c mbedtls_x509_crt_verify(). + * + * \note For per context callbacks and contexts, please use + * mbedtls_ssl_set_verify() instead. + * + * \param conf The SSL configuration to use. + * \param f_vrfy The verification callback to use during CRT verification. + * \param p_vrfy The opaque context to be passed to the callback. + */ +void mbedtls_ssl_conf_verify( mbedtls_ssl_config *conf, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/** + * \brief Set the random number generator callback + * + * \param conf SSL configuration + * \param f_rng RNG function + * \param p_rng RNG parameter + */ +void mbedtls_ssl_conf_rng( mbedtls_ssl_config *conf, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Set the debug callback + * + * The callback has the following argument: + * void * opaque context for the callback + * int debug level + * const char * file name + * int line number + * const char * message + * + * \param conf SSL configuration + * \param f_dbg debug function + * \param p_dbg debug parameter + */ +void mbedtls_ssl_conf_dbg( mbedtls_ssl_config *conf, + void (*f_dbg)(void *, int, const char *, int, const char *), + void *p_dbg ); + +/** + * \brief Set the underlying BIO callbacks for write, read and + * read-with-timeout. + * + * \param ssl SSL context + * \param p_bio parameter (context) shared by BIO callbacks + * \param f_send write callback + * \param f_recv read callback + * \param f_recv_timeout blocking read callback with timeout. + * + * \note One of f_recv or f_recv_timeout can be NULL, in which case + * the other is used. If both are non-NULL, f_recv_timeout is + * used and f_recv is ignored (as if it were NULL). + * + * \note The two most common use cases are: + * - non-blocking I/O, f_recv != NULL, f_recv_timeout == NULL + * - blocking I/O, f_recv == NULL, f_recv_timout != NULL + * + * \note For DTLS, you need to provide either a non-NULL + * f_recv_timeout callback, or a f_recv that doesn't block. + * + * \note See the documentations of \c mbedtls_ssl_sent_t, + * \c mbedtls_ssl_recv_t and \c mbedtls_ssl_recv_timeout_t for + * the conventions those callbacks must follow. + * + * \note On some platforms, net_sockets.c provides + * \c mbedtls_net_send(), \c mbedtls_net_recv() and + * \c mbedtls_net_recv_timeout() that are suitable to be used + * here. + */ +void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl, + void *p_bio, + mbedtls_ssl_send_t *f_send, + mbedtls_ssl_recv_t *f_recv, + mbedtls_ssl_recv_timeout_t *f_recv_timeout ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + + +/** + * \brief Configure the use of the Connection ID (CID) + * extension in the next handshake. + * + * Reference: draft-ietf-tls-dtls-connection-id-05 + * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05 + * + * The DTLS CID extension allows the reliable association of + * DTLS records to DTLS connections across changes in the + * underlying transport (changed IP and Port metadata) by + * adding explicit connection identifiers (CIDs) to the + * headers of encrypted DTLS records. The desired CIDs are + * configured by the application layer and are exchanged in + * new `ClientHello` / `ServerHello` extensions during the + * handshake, where each side indicates the CID it wants the + * peer to use when writing encrypted messages. The CIDs are + * put to use once records get encrypted: the stack discards + * any incoming records that don't include the configured CID + * in their header, and adds the peer's requested CID to the + * headers of outgoing messages. + * + * This API enables or disables the use of the CID extension + * in the next handshake and sets the value of the CID to + * be used for incoming messages. + * + * \param ssl The SSL context to configure. This must be initialized. + * \param enable This value determines whether the CID extension should + * be used or not. Possible values are: + * - MBEDTLS_SSL_CID_ENABLED to enable the use of the CID. + * - MBEDTLS_SSL_CID_DISABLED (default) to disable the use + * of the CID. + * \param own_cid The address of the readable buffer holding the CID we want + * the peer to use when sending encrypted messages to us. + * This may be \c NULL if \p own_cid_len is \c 0. + * This parameter is unused if \p enabled is set to + * MBEDTLS_SSL_CID_DISABLED. + * \param own_cid_len The length of \p own_cid. + * This parameter is unused if \p enabled is set to + * MBEDTLS_SSL_CID_DISABLED. + * + * \note The value of \p own_cid_len must match the value of the + * \c len parameter passed to mbedtls_ssl_conf_cid() + * when configuring the ::mbedtls_ssl_config that \p ssl + * is bound to. + * + * \note This CID configuration applies to subsequent handshakes + * performed on the SSL context \p ssl, but does not trigger + * one. You still have to call `mbedtls_ssl_handshake()` + * (for the initial handshake) or `mbedtls_ssl_renegotiate()` + * (for a renegotiation handshake) explicitly after a + * successful call to this function to run the handshake. + * + * \note This call cannot guarantee that the use of the CID + * will be successfully negotiated in the next handshake, + * because the peer might not support it. Specifically: + * - On the Client, enabling the use of the CID through + * this call implies that the `ClientHello` in the next + * handshake will include the CID extension, thereby + * offering the use of the CID to the server. Only if + * the `ServerHello` contains the CID extension, too, + * the CID extension will actually be put to use. + * - On the Server, enabling the use of the CID through + * this call implies that that the server will look for + * the CID extension in a `ClientHello` from the client, + * and, if present, reply with a CID extension in its + * `ServerHello`. + * + * \note To check whether the use of the CID was negotiated + * after the subsequent handshake has completed, please + * use the API mbedtls_ssl_get_peer_cid(). + * + * \warning If the use of the CID extension is enabled in this call + * and the subsequent handshake negotiates its use, Mbed TLS + * will silently drop every packet whose CID does not match + * the CID configured in \p own_cid. It is the responsibility + * of the user to adapt the underlying transport to take care + * of CID-based demultiplexing before handing datagrams to + * Mbed TLS. + * + * \return \c 0 on success. In this case, the CID configuration + * applies to the next handshake. + * \return A negative error code on failure. + */ +int mbedtls_ssl_set_cid( mbedtls_ssl_context *ssl, + int enable, + unsigned char const *own_cid, + size_t own_cid_len ); + +/** + * \brief Get information about the use of the CID extension + * in the current connection. + * + * \param ssl The SSL context to query. + * \param enabled The address at which to store whether the CID extension + * is currently in use or not. If the CID is in use, + * `*enabled` is set to MBEDTLS_SSL_CID_ENABLED; + * otherwise, it is set to MBEDTLS_SSL_CID_DISABLED. + * \param peer_cid The address of the buffer in which to store the CID + * chosen by the peer (if the CID extension is used). + * This may be \c NULL in case the value of peer CID + * isn't needed. If it is not \c NULL, \p peer_cid_len + * must not be \c NULL. + * \param peer_cid_len The address at which to store the size of the CID + * chosen by the peer (if the CID extension is used). + * This is also the number of Bytes in \p peer_cid that + * have been written. + * This may be \c NULL in case the length of the peer CID + * isn't needed. If it is \c NULL, \p peer_cid must be + * \c NULL, too. + * + * \note This applies to the state of the CID negotiated in + * the last complete handshake. If a handshake is in + * progress, this function will attempt to complete + * the handshake first. + * + * \note If CID extensions have been exchanged but both client + * and server chose to use an empty CID, this function + * sets `*enabled` to #MBEDTLS_SSL_CID_DISABLED + * (the rationale for this is that the resulting + * communication is the same as if the CID extensions + * hadn't been used). + * + * \return \c 0 on success. + * \return A negative error code on failure. + */ +int mbedtls_ssl_get_peer_cid( mbedtls_ssl_context *ssl, + int *enabled, + unsigned char peer_cid[ MBEDTLS_SSL_CID_OUT_LEN_MAX ], + size_t *peer_cid_len ); + +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + +/** + * \brief Set the Maximum Tranport Unit (MTU). + * Special value: 0 means unset (no limit). + * This represents the maximum size of a datagram payload + * handled by the transport layer (usually UDP) as determined + * by the network link and stack. In practice, this controls + * the maximum size datagram the DTLS layer will pass to the + * \c f_send() callback set using \c mbedtls_ssl_set_bio(). + * + * \note The limit on datagram size is converted to a limit on + * record payload by subtracting the current overhead of + * encapsulation and encryption/authentication if any. + * + * \note This can be called at any point during the connection, for + * example when a Path Maximum Transfer Unit (PMTU) + * estimate becomes available from other sources, + * such as lower (or higher) protocol layers. + * + * \note This setting only controls the size of the packets we send, + * and does not restrict the size of the datagrams we're + * willing to receive. Client-side, you can request the + * server to use smaller records with \c + * mbedtls_ssl_conf_max_frag_len(). + * + * \note If both a MTU and a maximum fragment length have been + * configured (or negotiated with the peer), the resulting + * lower limit on record payload (see first note) is used. + * + * \note This can only be used to decrease the maximum size + * of datagrams (hence records, see first note) sent. It + * cannot be used to increase the maximum size of records over + * the limit set by #MBEDTLS_SSL_OUT_CONTENT_LEN. + * + * \note Values lower than the current record layer expansion will + * result in an error when trying to send data. + * + * \note Using record compression together with a non-zero MTU value + * will result in an error when trying to send data. + * + * \param ssl SSL context + * \param mtu Value of the path MTU in bytes + */ +void mbedtls_ssl_set_mtu( mbedtls_ssl_context *ssl, uint16_t mtu ); +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Set a connection-specific verification callback (optional). + * + * If set, the provided verify callback is called for each + * certificate in the peer's CRT chain, including the trusted + * root. For more information, please see the documentation of + * \c mbedtls_x509_crt_verify(). + * + * \note This call is analogous to mbedtls_ssl_conf_verify() but + * binds the verification callback and context to an SSL context + * as opposed to an SSL configuration. + * If mbedtls_ssl_conf_verify() and mbedtls_ssl_set_verify() + * are both used, mbedtls_ssl_set_verify() takes precedence. + * + * \param ssl The SSL context to use. + * \param f_vrfy The verification callback to use during CRT verification. + * \param p_vrfy The opaque context to be passed to the callback. + */ +void mbedtls_ssl_set_verify( mbedtls_ssl_context *ssl, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/** + * \brief Set the timeout period for mbedtls_ssl_read() + * (Default: no timeout.) + * + * \param conf SSL configuration context + * \param timeout Timeout value in milliseconds. + * Use 0 for no timeout (default). + * + * \note With blocking I/O, this will only work if a non-NULL + * \c f_recv_timeout was set with \c mbedtls_ssl_set_bio(). + * With non-blocking I/O, this will only work if timer + * callbacks were set with \c mbedtls_ssl_set_timer_cb(). + * + * \note With non-blocking I/O, you may also skip this function + * altogether and handle timeouts at the application layer. + */ +void mbedtls_ssl_conf_read_timeout( mbedtls_ssl_config *conf, uint32_t timeout ); + +/** + * \brief Set the timer callbacks (Mandatory for DTLS.) + * + * \param ssl SSL context + * \param p_timer parameter (context) shared by timer callbacks + * \param f_set_timer set timer callback + * \param f_get_timer get timer callback. Must return: + * + * \note See the documentation of \c mbedtls_ssl_set_timer_t and + * \c mbedtls_ssl_get_timer_t for the conventions this pair of + * callbacks must follow. + * + * \note On some platforms, timing.c provides + * \c mbedtls_timing_set_delay() and + * \c mbedtls_timing_get_delay() that are suitable for using + * here, except if using an event-driven style. + * + * \note See also the "DTLS tutorial" article in our knowledge base. + * https://tls.mbed.org/kb/how-to/dtls-tutorial + */ +void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl, + void *p_timer, + mbedtls_ssl_set_timer_t *f_set_timer, + mbedtls_ssl_get_timer_t *f_get_timer ); + +/** + * \brief Callback type: generate and write session ticket + * + * \note This describes what a callback implementation should do. + * This callback should generate an encrypted and + * authenticated ticket for the session and write it to the + * output buffer. Here, ticket means the opaque ticket part + * of the NewSessionTicket structure of RFC 5077. + * + * \param p_ticket Context for the callback + * \param session SSL session to be written in the ticket + * \param start Start of the output buffer + * \param end End of the output buffer + * \param tlen On exit, holds the length written + * \param lifetime On exit, holds the lifetime of the ticket in seconds + * + * \return 0 if successful, or + * a specific MBEDTLS_ERR_XXX code. + */ +typedef int mbedtls_ssl_ticket_write_t( void *p_ticket, + const mbedtls_ssl_session *session, + unsigned char *start, + const unsigned char *end, + size_t *tlen, + uint32_t *lifetime ); + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +/** + * \brief Callback type: Export key block and master secret + * + * \note This is required for certain uses of TLS, e.g. EAP-TLS + * (RFC 5216) and Thread. The key pointers are ephemeral and + * therefore must not be stored. The master secret and keys + * should not be used directly except as an input to a key + * derivation function. + * + * \param p_expkey Context for the callback + * \param ms Pointer to master secret (fixed length: 48 bytes) + * \param kb Pointer to key block, see RFC 5246 section 6.3 + * (variable length: 2 * maclen + 2 * keylen + 2 * ivlen). + * \param maclen MAC length + * \param keylen Key length + * \param ivlen IV length + * + * \return 0 if successful, or + * a specific MBEDTLS_ERR_XXX code. + */ +typedef int mbedtls_ssl_export_keys_t( void *p_expkey, + const unsigned char *ms, + const unsigned char *kb, + size_t maclen, + size_t keylen, + size_t ivlen ); + +/** + * \brief Callback type: Export key block, master secret, + * handshake randbytes and the tls_prf function + * used to derive keys. + * + * \note This is required for certain uses of TLS, e.g. EAP-TLS + * (RFC 5216) and Thread. The key pointers are ephemeral and + * therefore must not be stored. The master secret and keys + * should not be used directly except as an input to a key + * derivation function. + * + * \param p_expkey Context for the callback. + * \param ms Pointer to master secret (fixed length: 48 bytes). + * \param kb Pointer to key block, see RFC 5246 section 6.3. + * (variable length: 2 * maclen + 2 * keylen + 2 * ivlen). + * \param maclen MAC length. + * \param keylen Key length. + * \param ivlen IV length. + * \param client_random The client random bytes. + * \param server_random The server random bytes. + * \param tls_prf_type The tls_prf enum type. + * + * \return 0 if successful, or + * a specific MBEDTLS_ERR_XXX code. + */ +typedef int mbedtls_ssl_export_keys_ext_t( void *p_expkey, + const unsigned char *ms, + const unsigned char *kb, + size_t maclen, + size_t keylen, + size_t ivlen, + unsigned char client_random[32], + unsigned char server_random[32], + mbedtls_tls_prf_types tls_prf_type ); +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + +/** + * \brief Callback type: parse and load session ticket + * + * \note This describes what a callback implementation should do. + * This callback should parse a session ticket as generated + * by the corresponding mbedtls_ssl_ticket_write_t function, + * and, if the ticket is authentic and valid, load the + * session. + * + * \note The implementation is allowed to modify the first len + * bytes of the input buffer, eg to use it as a temporary + * area for the decrypted ticket contents. + * + * \param p_ticket Context for the callback + * \param session SSL session to be loaded + * \param buf Start of the buffer containing the ticket + * \param len Length of the ticket. + * + * \return 0 if successful, or + * MBEDTLS_ERR_SSL_INVALID_MAC if not authentic, or + * MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED if expired, or + * any other non-zero code for other failures. + */ +typedef int mbedtls_ssl_ticket_parse_t( void *p_ticket, + mbedtls_ssl_session *session, + unsigned char *buf, + size_t len ); + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_SRV_C) +/** + * \brief Configure SSL session ticket callbacks (server only). + * (Default: none.) + * + * \note On server, session tickets are enabled by providing + * non-NULL callbacks. + * + * \note On client, use \c mbedtls_ssl_conf_session_tickets(). + * + * \param conf SSL configuration context + * \param f_ticket_write Callback for writing a ticket + * \param f_ticket_parse Callback for parsing a ticket + * \param p_ticket Context shared by the two callbacks + */ +void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_ticket_write_t *f_ticket_write, + mbedtls_ssl_ticket_parse_t *f_ticket_parse, + void *p_ticket ); +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +/** + * \brief Configure key export callback. + * (Default: none.) + * + * \note See \c mbedtls_ssl_export_keys_t. + * + * \param conf SSL configuration context + * \param f_export_keys Callback for exporting keys + * \param p_export_keys Context for the callback + */ +void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_export_keys_t *f_export_keys, + void *p_export_keys ); + +/** + * \brief Configure extended key export callback. + * (Default: none.) + * + * \note See \c mbedtls_ssl_export_keys_ext_t. + * + * \param conf SSL configuration context + * \param f_export_keys_ext Callback for exporting keys + * \param p_export_keys Context for the callback + */ +void mbedtls_ssl_conf_export_keys_ext_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_export_keys_ext_t *f_export_keys_ext, + void *p_export_keys ); +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) +/** + * \brief Configure asynchronous private key operation callbacks. + * + * \param conf SSL configuration context + * \param f_async_sign Callback to start a signature operation. See + * the description of ::mbedtls_ssl_async_sign_t + * for more information. This may be \c NULL if the + * external processor does not support any signature + * operation; in this case the private key object + * associated with the certificate will be used. + * \param f_async_decrypt Callback to start a decryption operation. See + * the description of ::mbedtls_ssl_async_decrypt_t + * for more information. This may be \c NULL if the + * external processor does not support any decryption + * operation; in this case the private key object + * associated with the certificate will be used. + * \param f_async_resume Callback to resume an asynchronous operation. See + * the description of ::mbedtls_ssl_async_resume_t + * for more information. This may not be \c NULL unless + * \p f_async_sign and \p f_async_decrypt are both + * \c NULL. + * \param f_async_cancel Callback to cancel an asynchronous operation. See + * the description of ::mbedtls_ssl_async_cancel_t + * for more information. This may be \c NULL if + * no cleanup is needed. + * \param config_data A pointer to configuration data which can be + * retrieved with + * mbedtls_ssl_conf_get_async_config_data(). The + * library stores this value without dereferencing it. + */ +void mbedtls_ssl_conf_async_private_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_async_sign_t *f_async_sign, + mbedtls_ssl_async_decrypt_t *f_async_decrypt, + mbedtls_ssl_async_resume_t *f_async_resume, + mbedtls_ssl_async_cancel_t *f_async_cancel, + void *config_data ); + +/** + * \brief Retrieve the configuration data set by + * mbedtls_ssl_conf_async_private_cb(). + * + * \param conf SSL configuration context + * \return The configuration data set by + * mbedtls_ssl_conf_async_private_cb(). + */ +void *mbedtls_ssl_conf_get_async_config_data( const mbedtls_ssl_config *conf ); + +/** + * \brief Retrieve the asynchronous operation user context. + * + * \note This function may only be called while a handshake + * is in progress. + * + * \param ssl The SSL context to access. + * + * \return The asynchronous operation user context that was last + * set during the current handshake. If + * mbedtls_ssl_set_async_operation_data() has not yet been + * called during the current handshake, this function returns + * \c NULL. + */ +void *mbedtls_ssl_get_async_operation_data( const mbedtls_ssl_context *ssl ); + +/** + * \brief Retrieve the asynchronous operation user context. + * + * \note This function may only be called while a handshake + * is in progress. + * + * \param ssl The SSL context to access. + * \param ctx The new value of the asynchronous operation user context. + * Call mbedtls_ssl_get_async_operation_data() later during the + * same handshake to retrieve this value. + */ +void mbedtls_ssl_set_async_operation_data( mbedtls_ssl_context *ssl, + void *ctx ); +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + +/** + * \brief Callback type: generate a cookie + * + * \param ctx Context for the callback + * \param p Buffer to write to, + * must be updated to point right after the cookie + * \param end Pointer to one past the end of the output buffer + * \param info Client ID info that was passed to + * \c mbedtls_ssl_set_client_transport_id() + * \param ilen Length of info in bytes + * + * \return The callback must return 0 on success, + * or a negative error code. + */ +typedef int mbedtls_ssl_cookie_write_t( void *ctx, + unsigned char **p, unsigned char *end, + const unsigned char *info, size_t ilen ); + +/** + * \brief Callback type: verify a cookie + * + * \param ctx Context for the callback + * \param cookie Cookie to verify + * \param clen Length of cookie + * \param info Client ID info that was passed to + * \c mbedtls_ssl_set_client_transport_id() + * \param ilen Length of info in bytes + * + * \return The callback must return 0 if cookie is valid, + * or a negative error code. + */ +typedef int mbedtls_ssl_cookie_check_t( void *ctx, + const unsigned char *cookie, size_t clen, + const unsigned char *info, size_t ilen ); + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) +/** + * \brief Register callbacks for DTLS cookies + * (Server only. DTLS only.) + * + * Default: dummy callbacks that fail, in order to force you to + * register working callbacks (and initialize their context). + * + * To disable HelloVerifyRequest, register NULL callbacks. + * + * \warning Disabling hello verification allows your server to be used + * for amplification in DoS attacks against other hosts. + * Only disable if you known this can't happen in your + * particular environment. + * + * \note See comments on \c mbedtls_ssl_handshake() about handling + * the MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED that is expected + * on the first handshake attempt when this is enabled. + * + * \note This is also necessary to handle client reconnection from + * the same port as described in RFC 6347 section 4.2.8 (only + * the variant with cookies is supported currently). See + * comments on \c mbedtls_ssl_read() for details. + * + * \param conf SSL configuration + * \param f_cookie_write Cookie write callback + * \param f_cookie_check Cookie check callback + * \param p_cookie Context for both callbacks + */ +void mbedtls_ssl_conf_dtls_cookies( mbedtls_ssl_config *conf, + mbedtls_ssl_cookie_write_t *f_cookie_write, + mbedtls_ssl_cookie_check_t *f_cookie_check, + void *p_cookie ); + +/** + * \brief Set client's transport-level identification info. + * (Server only. DTLS only.) + * + * This is usually the IP address (and port), but could be + * anything identify the client depending on the underlying + * network stack. Used for HelloVerifyRequest with DTLS. + * This is *not* used to route the actual packets. + * + * \param ssl SSL context + * \param info Transport-level info identifying the client (eg IP + port) + * \param ilen Length of info in bytes + * + * \note An internal copy is made, so the info buffer can be reused. + * + * \return 0 on success, + * MBEDTLS_ERR_SSL_BAD_INPUT_DATA if used on client, + * MBEDTLS_ERR_SSL_ALLOC_FAILED if out of memory. + */ +int mbedtls_ssl_set_client_transport_id( mbedtls_ssl_context *ssl, + const unsigned char *info, + size_t ilen ); + +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +/** + * \brief Enable or disable anti-replay protection for DTLS. + * (DTLS only, no effect on TLS.) + * Default: enabled. + * + * \param conf SSL configuration + * \param mode MBEDTLS_SSL_ANTI_REPLAY_ENABLED or MBEDTLS_SSL_ANTI_REPLAY_DISABLED. + * + * \warning Disabling this is a security risk unless the application + * protocol handles duplicated packets in a safe way. You + * should not disable this without careful consideration. + * However, if your application already detects duplicated + * packets and needs information about them to adjust its + * transmission strategy, then you'll want to disable this. + */ +void mbedtls_ssl_conf_dtls_anti_replay( mbedtls_ssl_config *conf, char mode ); +#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */ + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) +/** + * \brief Set a limit on the number of records with a bad MAC + * before terminating the connection. + * (DTLS only, no effect on TLS.) + * Default: 0 (disabled). + * + * \param conf SSL configuration + * \param limit Limit, or 0 to disable. + * + * \note If the limit is N, then the connection is terminated when + * the Nth non-authentic record is seen. + * + * \note Records with an invalid header are not counted, only the + * ones going through the authentication-decryption phase. + * + * \note This is a security trade-off related to the fact that it's + * often relatively easy for an active attacker ot inject UDP + * datagrams. On one hand, setting a low limit here makes it + * easier for such an attacker to forcibly terminated a + * connection. On the other hand, a high limit or no limit + * might make us waste resources checking authentication on + * many bogus packets. + */ +void mbedtls_ssl_conf_dtls_badmac_limit( mbedtls_ssl_config *conf, unsigned limit ); +#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + +/** + * \brief Allow or disallow packing of multiple handshake records + * within a single datagram. + * + * \param ssl The SSL context to configure. + * \param allow_packing This determines whether datagram packing may + * be used or not. A value of \c 0 means that every + * record will be sent in a separate datagram; a + * value of \c 1 means that, if space permits, + * multiple handshake messages (including CCS) belonging to + * a single flight may be packed within a single datagram. + * + * \note This is enabled by default and should only be disabled + * for test purposes, or if datagram packing causes + * interoperability issues with peers that don't support it. + * + * \note Allowing datagram packing reduces the network load since + * there's less overhead if multiple messages share the same + * datagram. Also, it increases the handshake efficiency + * since messages belonging to a single datagram will not + * be reordered in transit, and so future message buffering + * or flight retransmission (if no buffering is used) as + * means to deal with reordering are needed less frequently. + * + * \note Application records are not affected by this option and + * are currently always sent in separate datagrams. + * + */ +void mbedtls_ssl_set_datagram_packing( mbedtls_ssl_context *ssl, + unsigned allow_packing ); + +/** + * \brief Set retransmit timeout values for the DTLS handshake. + * (DTLS only, no effect on TLS.) + * + * \param conf SSL configuration + * \param min Initial timeout value in milliseconds. + * Default: 1000 (1 second). + * \param max Maximum timeout value in milliseconds. + * Default: 60000 (60 seconds). + * + * \note Default values are from RFC 6347 section 4.2.4.1. + * + * \note The 'min' value should typically be slightly above the + * expected round-trip time to your peer, plus whatever time + * it takes for the peer to process the message. For example, + * if your RTT is about 600ms and you peer needs up to 1s to + * do the cryptographic operations in the handshake, then you + * should set 'min' slightly above 1600. Lower values of 'min' + * might cause spurious resends which waste network resources, + * while larger value of 'min' will increase overall latency + * on unreliable network links. + * + * \note The more unreliable your network connection is, the larger + * your max / min ratio needs to be in order to achieve + * reliable handshakes. + * + * \note Messages are retransmitted up to log2(ceil(max/min)) times. + * For example, if min = 1s and max = 5s, the retransmit plan + * goes: send ... 1s -> resend ... 2s -> resend ... 4s -> + * resend ... 5s -> give up and return a timeout error. + */ +void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf, uint32_t min, uint32_t max ); +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +#if defined(MBEDTLS_SSL_SRV_C) +/** + * \brief Set the session cache callbacks (server-side only) + * If not set, no session resuming is done (except if session + * tickets are enabled too). + * + * The session cache has the responsibility to check for stale + * entries based on timeout. See RFC 5246 for recommendations. + * + * Warning: session.peer_cert is cleared by the SSL/TLS layer on + * connection shutdown, so do not cache the pointer! Either set + * it to NULL or make a full copy of the certificate. + * + * The get callback is called once during the initial handshake + * to enable session resuming. The get function has the + * following parameters: (void *parameter, mbedtls_ssl_session *session) + * If a valid entry is found, it should fill the master of + * the session object with the cached values and return 0, + * return 1 otherwise. Optionally peer_cert can be set as well + * if it is properly present in cache entry. + * + * The set callback is called once during the initial handshake + * to enable session resuming after the entire handshake has + * been finished. The set function has the following parameters: + * (void *parameter, const mbedtls_ssl_session *session). The function + * should create a cache entry for future retrieval based on + * the data in the session structure and should keep in mind + * that the mbedtls_ssl_session object presented (and all its referenced + * data) is cleared by the SSL/TLS layer when the connection is + * terminated. It is recommended to add metadata to determine if + * an entry is still valid in the future. Return 0 if + * successfully cached, return 1 otherwise. + * + * \param conf SSL configuration + * \param p_cache parmater (context) for both callbacks + * \param f_get_cache session get callback + * \param f_set_cache session set callback + */ +void mbedtls_ssl_conf_session_cache( mbedtls_ssl_config *conf, + void *p_cache, + int (*f_get_cache)(void *, mbedtls_ssl_session *), + int (*f_set_cache)(void *, const mbedtls_ssl_session *) ); +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Request resumption of session (client-side only) + * Session data is copied from presented session structure. + * + * \param ssl SSL context + * \param session session context + * + * \return 0 if successful, + * MBEDTLS_ERR_SSL_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_SSL_BAD_INPUT_DATA if used server-side or + * arguments are otherwise invalid + * + * \sa mbedtls_ssl_get_session() + */ +int mbedtls_ssl_set_session( mbedtls_ssl_context *ssl, const mbedtls_ssl_session *session ); +#endif /* MBEDTLS_SSL_CLI_C */ + +/** + * \brief Set the list of allowed ciphersuites and the preference + * order. First in the list has the highest preference. + * (Overrides all version-specific lists) + * + * The ciphersuites array is not copied, and must remain + * valid for the lifetime of the ssl_config. + * + * Note: The server uses its own preferences + * over the preference of the client unless + * MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE is defined! + * + * \param conf SSL configuration + * \param ciphersuites 0-terminated list of allowed ciphersuites + */ +void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf, + const int *ciphersuites ); + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +#define MBEDTLS_SSL_UNEXPECTED_CID_IGNORE 0 +#define MBEDTLS_SSL_UNEXPECTED_CID_FAIL 1 +/** + * \brief Specify the length of Connection IDs for incoming + * encrypted DTLS records, as well as the behaviour + * on unexpected CIDs. + * + * By default, the CID length is set to \c 0, + * and unexpected CIDs are silently ignored. + * + * \param conf The SSL configuration to modify. + * \param len The length in Bytes of the CID fields in encrypted + * DTLS records using the CID mechanism. This must + * not be larger than #MBEDTLS_SSL_CID_OUT_LEN_MAX. + * \param ignore_other_cids This determines the stack's behaviour when + * receiving a record with an unexpected CID. + * Possible values are: + * - #MBEDTLS_SSL_UNEXPECTED_CID_IGNORE + * In this case, the record is silently ignored. + * - #MBEDTLS_SSL_UNEXPECTED_CID_FAIL + * In this case, the stack fails with the specific + * error code #MBEDTLS_ERR_SSL_UNEXPECTED_CID. + * + * \note The CID specification allows implementations to either + * use a common length for all incoming connection IDs or + * allow variable-length incoming IDs. Mbed TLS currently + * requires a common length for all connections sharing the + * same SSL configuration; this allows simpler parsing of + * record headers. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if \p own_cid_len + * is too large. + */ +int mbedtls_ssl_conf_cid( mbedtls_ssl_config *conf, size_t len, + int ignore_other_cids ); +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + +/** + * \brief Set the list of allowed ciphersuites and the + * preference order for a specific version of the protocol. + * (Only useful on the server side) + * + * The ciphersuites array is not copied, and must remain + * valid for the lifetime of the ssl_config. + * + * \param conf SSL configuration + * \param ciphersuites 0-terminated list of allowed ciphersuites + * \param major Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3 + * supported) + * \param minor Minor version number (MBEDTLS_SSL_MINOR_VERSION_0, + * MBEDTLS_SSL_MINOR_VERSION_1 and MBEDTLS_SSL_MINOR_VERSION_2, + * MBEDTLS_SSL_MINOR_VERSION_3 supported) + * + * \note With DTLS, use MBEDTLS_SSL_MINOR_VERSION_2 for DTLS 1.0 + * and MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2 + */ +void mbedtls_ssl_conf_ciphersuites_for_version( mbedtls_ssl_config *conf, + const int *ciphersuites, + int major, int minor ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Set the X.509 security profile used for verification + * + * \note The restrictions are enforced for all certificates in the + * chain. However, signatures in the handshake are not covered + * by this setting but by \b mbedtls_ssl_conf_sig_hashes(). + * + * \param conf SSL configuration + * \param profile Profile to use + */ +void mbedtls_ssl_conf_cert_profile( mbedtls_ssl_config *conf, + const mbedtls_x509_crt_profile *profile ); + +/** + * \brief Set the data required to verify peer certificate + * + * \note See \c mbedtls_x509_crt_verify() for notes regarding the + * parameters ca_chain (maps to trust_ca for that function) + * and ca_crl. + * + * \param conf SSL configuration + * \param ca_chain trusted CA chain (meaning all fully trusted top-level CAs) + * \param ca_crl trusted CA CRLs + */ +void mbedtls_ssl_conf_ca_chain( mbedtls_ssl_config *conf, + mbedtls_x509_crt *ca_chain, + mbedtls_x509_crl *ca_crl ); + +#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) +/** + * \brief Set the trusted certificate callback. + * + * This API allows to register the set of trusted certificates + * through a callback, instead of a linked list as configured + * by mbedtls_ssl_conf_ca_chain(). + * + * This is useful for example in contexts where a large number + * of CAs are used, and the inefficiency of maintaining them + * in a linked list cannot be tolerated. It is also useful when + * the set of trusted CAs needs to be modified frequently. + * + * See the documentation of `mbedtls_x509_crt_ca_cb_t` for + * more information. + * + * \param conf The SSL configuration to register the callback with. + * \param f_ca_cb The trusted certificate callback to use when verifying + * certificate chains. + * \param p_ca_cb The context to be passed to \p f_ca_cb (for example, + * a reference to a trusted CA database). + * + * \note This API is incompatible with mbedtls_ssl_conf_ca_chain(): + * Any call to this function overwrites the values set through + * earlier calls to mbedtls_ssl_conf_ca_chain() or + * mbedtls_ssl_conf_ca_cb(). + * + * \note This API is incompatible with CA indication in + * CertificateRequest messages: A server-side SSL context which + * is bound to an SSL configuration that uses a CA callback + * configured via mbedtls_ssl_conf_ca_cb(), and which requires + * client authentication, will send an empty CA list in the + * corresponding CertificateRequest message. + * + * \note This API is incompatible with mbedtls_ssl_set_hs_ca_chain(): + * If an SSL context is bound to an SSL configuration which uses + * CA callbacks configured via mbedtls_ssl_conf_ca_cb(), then + * calls to mbedtls_ssl_set_hs_ca_chain() have no effect. + * + * \note The use of this API disables the use of restartable ECC + * during X.509 CRT signature verification (but doesn't affect + * other uses). + * + * \warning This API is incompatible with the use of CRLs. Any call to + * mbedtls_ssl_conf_ca_cb() unsets CRLs configured through + * earlier calls to mbedtls_ssl_conf_ca_chain(). + * + * \warning In multi-threaded environments, the callback \p f_ca_cb + * must be thread-safe, and it is the user's responsibility + * to guarantee this (for example through a mutex + * contained in the callback context pointed to by \p p_ca_cb). + */ +void mbedtls_ssl_conf_ca_cb( mbedtls_ssl_config *conf, + mbedtls_x509_crt_ca_cb_t f_ca_cb, + void *p_ca_cb ); +#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ + +/** + * \brief Set own certificate chain and private key + * + * \note own_cert should contain in order from the bottom up your + * certificate chain. The top certificate (self-signed) + * can be omitted. + * + * \note On server, this function can be called multiple times to + * provision more than one cert/key pair (eg one ECDSA, one + * RSA with SHA-256, one RSA with SHA-1). An adequate + * certificate will be selected according to the client's + * advertised capabilities. In case multiple certificates are + * adequate, preference is given to the one set by the first + * call to this function, then second, etc. + * + * \note On client, only the first call has any effect. That is, + * only one client certificate can be provisioned. The + * server's preferences in its CertficateRequest message will + * be ignored and our only cert will be sent regardless of + * whether it matches those preferences - the server can then + * decide what it wants to do with it. + * + * \note The provided \p pk_key needs to match the public key in the + * first certificate in \p own_cert, or all handshakes using + * that certificate will fail. It is your responsibility + * to ensure that; this function will not perform any check. + * You may use mbedtls_pk_check_pair() in order to perform + * this check yourself, but be aware that this function can + * be computationally expensive on some key types. + * + * \param conf SSL configuration + * \param own_cert own public certificate chain + * \param pk_key own private key + * + * \return 0 on success or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +int mbedtls_ssl_conf_own_cert( mbedtls_ssl_config *conf, + mbedtls_x509_crt *own_cert, + mbedtls_pk_context *pk_key ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +/** + * \brief Configure a pre-shared key (PSK) and identity + * to be used in PSK-based ciphersuites. + * + * \note This is mainly useful for clients. Servers will usually + * want to use \c mbedtls_ssl_conf_psk_cb() instead. + * + * \warning Currently, clients can only register a single pre-shared key. + * Calling this function or mbedtls_ssl_conf_psk_opaque() more + * than once will overwrite values configured in previous calls. + * Support for setting multiple PSKs on clients and selecting + * one based on the identity hint is not a planned feature, + * but feedback is welcomed. + * + * \param conf The SSL configuration to register the PSK with. + * \param psk The pointer to the pre-shared key to use. + * \param psk_len The length of the pre-shared key in bytes. + * \param psk_identity The pointer to the pre-shared key identity. + * \param psk_identity_len The length of the pre-shared key identity + * in bytes. + * + * \note The PSK and its identity are copied internally and + * hence need not be preserved by the caller for the lifetime + * of the SSL configuration. + * + * \return \c 0 if successful. + * \return An \c MBEDTLS_ERR_SSL_XXX error code on failure. + */ +int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf, + const unsigned char *psk, size_t psk_len, + const unsigned char *psk_identity, size_t psk_identity_len ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +/** + * \brief Configure an opaque pre-shared key (PSK) and identity + * to be used in PSK-based ciphersuites. + * + * \note This is mainly useful for clients. Servers will usually + * want to use \c mbedtls_ssl_conf_psk_cb() instead. + * + * \warning Currently, clients can only register a single pre-shared key. + * Calling this function or mbedtls_ssl_conf_psk() more than + * once will overwrite values configured in previous calls. + * Support for setting multiple PSKs on clients and selecting + * one based on the identity hint is not a planned feature, + * but feedback is welcomed. + * + * \param conf The SSL configuration to register the PSK with. + * \param psk The identifier of the key slot holding the PSK. + * Until \p conf is destroyed or this function is successfully + * called again, the key slot \p psk must be populated with a + * key of type PSA_ALG_CATEGORY_KEY_DERIVATION whose policy + * allows its use for the key derivation algorithm applied + * in the handshake. + * \param psk_identity The pointer to the pre-shared key identity. + * \param psk_identity_len The length of the pre-shared key identity + * in bytes. + * + * \note The PSK identity hint is copied internally and hence need + * not be preserved by the caller for the lifetime of the + * SSL configuration. + * + * \return \c 0 if successful. + * \return An \c MBEDTLS_ERR_SSL_XXX error code on failure. + */ +int mbedtls_ssl_conf_psk_opaque( mbedtls_ssl_config *conf, + psa_key_handle_t psk, + const unsigned char *psk_identity, + size_t psk_identity_len ); +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +/** + * \brief Set the pre-shared Key (PSK) for the current handshake. + * + * \note This should only be called inside the PSK callback, + * i.e. the function passed to \c mbedtls_ssl_conf_psk_cb(). + * + * \param ssl The SSL context to configure a PSK for. + * \param psk The pointer to the pre-shared key. + * \param psk_len The length of the pre-shared key in bytes. + * + * \return \c 0 if successful. + * \return An \c MBEDTLS_ERR_SSL_XXX error code on failure. + */ +int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl, + const unsigned char *psk, size_t psk_len ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +/** + * \brief Set an opaque pre-shared Key (PSK) for the current handshake. + * + * \note This should only be called inside the PSK callback, + * i.e. the function passed to \c mbedtls_ssl_conf_psk_cb(). + * + * \param ssl The SSL context to configure a PSK for. + * \param psk The identifier of the key slot holding the PSK. + * For the duration of the current handshake, the key slot + * must be populated with a key of type + * PSA_ALG_CATEGORY_KEY_DERIVATION whose policy allows its + * use for the key derivation algorithm + * applied in the handshake. + * + * \return \c 0 if successful. + * \return An \c MBEDTLS_ERR_SSL_XXX error code on failure. + */ +int mbedtls_ssl_set_hs_psk_opaque( mbedtls_ssl_context *ssl, + psa_key_handle_t psk ); +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +/** + * \brief Set the PSK callback (server-side only). + * + * If set, the PSK callback is called for each + * handshake where a PSK-based ciphersuite was negotiated. + * The caller provides the identity received and wants to + * receive the actual PSK data and length. + * + * The callback has the following parameters: + * - \c void*: The opaque pointer \p p_psk. + * - \c mbedtls_ssl_context*: The SSL context to which + * the operation applies. + * - \c const unsigned char*: The PSK identity + * selected by the client. + * - \c size_t: The length of the PSK identity + * selected by the client. + * + * If a valid PSK identity is found, the callback should use + * \c mbedtls_ssl_set_hs_psk() or + * \c mbedtls_ssl_set_hs_psk_opaque() + * on the SSL context to set the correct PSK and return \c 0. + * Any other return value will result in a denied PSK identity. + * + * \note If you set a PSK callback using this function, then you + * don't need to set a PSK key and identity using + * \c mbedtls_ssl_conf_psk(). + * + * \param conf The SSL configuration to register the callback with. + * \param f_psk The callback for selecting and setting the PSK based + * in the PSK identity chosen by the client. + * \param p_psk A pointer to an opaque structure to be passed to + * the callback, for example a PSK store. + */ +void mbedtls_ssl_conf_psk_cb( mbedtls_ssl_config *conf, + int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *, + size_t), + void *p_psk ); +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_SRV_C) + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) + +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif + +/** + * \brief Set the Diffie-Hellman public P and G values, + * read as hexadecimal strings (server-side only) + * (Default values: MBEDTLS_DHM_RFC3526_MODP_2048_[PG]) + * + * \param conf SSL configuration + * \param dhm_P Diffie-Hellman-Merkle modulus + * \param dhm_G Diffie-Hellman-Merkle generator + * + * \deprecated Superseded by \c mbedtls_ssl_conf_dh_param_bin. + * + * \return 0 if successful + */ +MBEDTLS_DEPRECATED int mbedtls_ssl_conf_dh_param( mbedtls_ssl_config *conf, + const char *dhm_P, + const char *dhm_G ); + +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Set the Diffie-Hellman public P and G values + * from big-endian binary presentations. + * (Default values: MBEDTLS_DHM_RFC3526_MODP_2048_[PG]_BIN) + * + * \param conf SSL configuration + * \param dhm_P Diffie-Hellman-Merkle modulus in big-endian binary form + * \param P_len Length of DHM modulus + * \param dhm_G Diffie-Hellman-Merkle generator in big-endian binary form + * \param G_len Length of DHM generator + * + * \return 0 if successful + */ +int mbedtls_ssl_conf_dh_param_bin( mbedtls_ssl_config *conf, + const unsigned char *dhm_P, size_t P_len, + const unsigned char *dhm_G, size_t G_len ); + +/** + * \brief Set the Diffie-Hellman public P and G values, + * read from existing context (server-side only) + * + * \param conf SSL configuration + * \param dhm_ctx Diffie-Hellman-Merkle context + * + * \return 0 if successful + */ +int mbedtls_ssl_conf_dh_param_ctx( mbedtls_ssl_config *conf, mbedtls_dhm_context *dhm_ctx ); +#endif /* MBEDTLS_DHM_C && defined(MBEDTLS_SSL_SRV_C) */ + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Set the minimum length for Diffie-Hellman parameters. + * (Client-side only.) + * (Default: 1024 bits.) + * + * \param conf SSL configuration + * \param bitlen Minimum bit length of the DHM prime + */ +void mbedtls_ssl_conf_dhm_min_bitlen( mbedtls_ssl_config *conf, + unsigned int bitlen ); +#endif /* MBEDTLS_DHM_C && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_ECP_C) +/** + * \brief Set the allowed curves in order of preference. + * (Default: all defined curves.) + * + * On server: this only affects selection of the ECDHE curve; + * the curves used for ECDH and ECDSA are determined by the + * list of available certificates instead. + * + * On client: this affects the list of curves offered for any + * use. The server can override our preference order. + * + * Both sides: limits the set of curves accepted for use in + * ECDHE and in the peer's end-entity certificate. + * + * \note This has no influence on which curves are allowed inside the + * certificate chains, see \c mbedtls_ssl_conf_cert_profile() + * for that. For the end-entity certificate however, the key + * will be accepted only if it is allowed both by this list + * and by the cert profile. + * + * \note This list should be ordered by decreasing preference + * (preferred curve first). + * + * \param conf SSL configuration + * \param curves Ordered list of allowed curves, + * terminated by MBEDTLS_ECP_DP_NONE. + */ +void mbedtls_ssl_conf_curves( mbedtls_ssl_config *conf, + const mbedtls_ecp_group_id *curves ); +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +/** + * \brief Set the allowed hashes for signatures during the handshake. + * (Default: all available hashes except MD5.) + * + * \note This only affects which hashes are offered and can be used + * for signatures during the handshake. Hashes for message + * authentication and the TLS PRF are controlled by the + * ciphersuite, see \c mbedtls_ssl_conf_ciphersuites(). Hashes + * used for certificate signature are controlled by the + * verification profile, see \c mbedtls_ssl_conf_cert_profile(). + * + * \note This list should be ordered by decreasing preference + * (preferred hash first). + * + * \param conf SSL configuration + * \param hashes Ordered list of allowed signature hashes, + * terminated by \c MBEDTLS_MD_NONE. + */ +void mbedtls_ssl_conf_sig_hashes( mbedtls_ssl_config *conf, + const int *hashes ); +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Set or reset the hostname to check against the received + * server certificate. It sets the ServerName TLS extension, + * too, if that extension is enabled. (client-side only) + * + * \param ssl SSL context + * \param hostname the server hostname, may be NULL to clear hostname + + * \note Maximum hostname length MBEDTLS_SSL_MAX_HOST_NAME_LEN. + * + * \return 0 if successful, MBEDTLS_ERR_SSL_ALLOC_FAILED on + * allocation failure, MBEDTLS_ERR_SSL_BAD_INPUT_DATA on + * too long input hostname. + * + * Hostname set to the one provided on success (cleared + * when NULL). On allocation failure hostname is cleared. + * On too long input failure, old hostname is unchanged. + */ +int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +/** + * \brief Set own certificate and key for the current handshake + * + * \note Same as \c mbedtls_ssl_conf_own_cert() but for use within + * the SNI callback. + * + * \param ssl SSL context + * \param own_cert own public certificate chain + * \param pk_key own private key + * + * \return 0 on success or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +int mbedtls_ssl_set_hs_own_cert( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *own_cert, + mbedtls_pk_context *pk_key ); + +/** + * \brief Set the data required to verify peer certificate for the + * current handshake + * + * \note Same as \c mbedtls_ssl_conf_ca_chain() but for use within + * the SNI callback. + * + * \param ssl SSL context + * \param ca_chain trusted CA chain (meaning all fully trusted top-level CAs) + * \param ca_crl trusted CA CRLs + */ +void mbedtls_ssl_set_hs_ca_chain( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *ca_chain, + mbedtls_x509_crl *ca_crl ); + +/** + * \brief Set authmode for the current handshake. + * + * \note Same as \c mbedtls_ssl_conf_authmode() but for use within + * the SNI callback. + * + * \param ssl SSL context + * \param authmode MBEDTLS_SSL_VERIFY_NONE, MBEDTLS_SSL_VERIFY_OPTIONAL or + * MBEDTLS_SSL_VERIFY_REQUIRED + */ +void mbedtls_ssl_set_hs_authmode( mbedtls_ssl_context *ssl, + int authmode ); + +/** + * \brief Set server side ServerName TLS extension callback + * (optional, server-side only). + * + * If set, the ServerName callback is called whenever the + * server receives a ServerName TLS extension from the client + * during a handshake. The ServerName callback has the + * following parameters: (void *parameter, mbedtls_ssl_context *ssl, + * const unsigned char *hostname, size_t len). If a suitable + * certificate is found, the callback must set the + * certificate(s) and key(s) to use with \c + * mbedtls_ssl_set_hs_own_cert() (can be called repeatedly), + * and may optionally adjust the CA and associated CRL with \c + * mbedtls_ssl_set_hs_ca_chain() as well as the client + * authentication mode with \c mbedtls_ssl_set_hs_authmode(), + * then must return 0. If no matching name is found, the + * callback must either set a default cert, or + * return non-zero to abort the handshake at this point. + * + * \param conf SSL configuration + * \param f_sni verification function + * \param p_sni verification parameter + */ +void mbedtls_ssl_conf_sni( mbedtls_ssl_config *conf, + int (*f_sni)(void *, mbedtls_ssl_context *, const unsigned char *, + size_t), + void *p_sni ); +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +/** + * \brief Set the EC J-PAKE password for current handshake. + * + * \note An internal copy is made, and destroyed as soon as the + * handshake is completed, or when the SSL context is reset or + * freed. + * + * \note The SSL context needs to be already set up. The right place + * to call this function is between \c mbedtls_ssl_setup() or + * \c mbedtls_ssl_reset() and \c mbedtls_ssl_handshake(). + * + * \param ssl SSL context + * \param pw EC J-PAKE password (pre-shared secret) + * \param pw_len length of pw in bytes + * + * \return 0 on success, or a negative error code. + */ +int mbedtls_ssl_set_hs_ecjpake_password( mbedtls_ssl_context *ssl, + const unsigned char *pw, + size_t pw_len ); +#endif /*MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_ALPN) +/** + * \brief Set the supported Application Layer Protocols. + * + * \param conf SSL configuration + * \param protos Pointer to a NULL-terminated list of supported protocols, + * in decreasing preference order. The pointer to the list is + * recorded by the library for later reference as required, so + * the lifetime of the table must be atleast as long as the + * lifetime of the SSL configuration structure. + * + * \return 0 on success, or MBEDTLS_ERR_SSL_BAD_INPUT_DATA. + */ +int mbedtls_ssl_conf_alpn_protocols( mbedtls_ssl_config *conf, const char **protos ); + +/** + * \brief Get the name of the negotiated Application Layer Protocol. + * This function should be called after the handshake is + * completed. + * + * \param ssl SSL context + * + * \return Protcol name, or NULL if no protocol was negotiated. + */ +const char *mbedtls_ssl_get_alpn_protocol( const mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_ALPN */ + +/** + * \brief Set the maximum supported version sent from the client side + * and/or accepted at the server side + * (Default: MBEDTLS_SSL_MAX_MAJOR_VERSION, MBEDTLS_SSL_MAX_MINOR_VERSION) + * + * \note This ignores ciphersuites from higher versions. + * + * \note With DTLS, use MBEDTLS_SSL_MINOR_VERSION_2 for DTLS 1.0 and + * MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2 + * + * \param conf SSL configuration + * \param major Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3 supported) + * \param minor Minor version number (MBEDTLS_SSL_MINOR_VERSION_0, + * MBEDTLS_SSL_MINOR_VERSION_1 and MBEDTLS_SSL_MINOR_VERSION_2, + * MBEDTLS_SSL_MINOR_VERSION_3 supported) + */ +void mbedtls_ssl_conf_max_version( mbedtls_ssl_config *conf, int major, int minor ); + +/** + * \brief Set the minimum accepted SSL/TLS protocol version + * (Default: TLS 1.0) + * + * \note Input outside of the SSL_MAX_XXXXX_VERSION and + * SSL_MIN_XXXXX_VERSION range is ignored. + * + * \note MBEDTLS_SSL_MINOR_VERSION_0 (SSL v3) should be avoided. + * + * \note With DTLS, use MBEDTLS_SSL_MINOR_VERSION_2 for DTLS 1.0 and + * MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2 + * + * \param conf SSL configuration + * \param major Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3 supported) + * \param minor Minor version number (MBEDTLS_SSL_MINOR_VERSION_0, + * MBEDTLS_SSL_MINOR_VERSION_1 and MBEDTLS_SSL_MINOR_VERSION_2, + * MBEDTLS_SSL_MINOR_VERSION_3 supported) + */ +void mbedtls_ssl_conf_min_version( mbedtls_ssl_config *conf, int major, int minor ); + +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) && defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Set the fallback flag (client-side only). + * (Default: MBEDTLS_SSL_IS_NOT_FALLBACK). + * + * \note Set to MBEDTLS_SSL_IS_FALLBACK when preparing a fallback + * connection, that is a connection with max_version set to a + * lower value than the value you're willing to use. Such + * fallback connections are not recommended but are sometimes + * necessary to interoperate with buggy (version-intolerant) + * servers. + * + * \warning You should NOT set this to MBEDTLS_SSL_IS_FALLBACK for + * non-fallback connections! This would appear to work for a + * while, then cause failures when the server is upgraded to + * support a newer TLS version. + * + * \param conf SSL configuration + * \param fallback MBEDTLS_SSL_IS_NOT_FALLBACK or MBEDTLS_SSL_IS_FALLBACK + */ +void mbedtls_ssl_conf_fallback( mbedtls_ssl_config *conf, char fallback ); +#endif /* MBEDTLS_SSL_FALLBACK_SCSV && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +/** + * \brief Enable or disable Encrypt-then-MAC + * (Default: MBEDTLS_SSL_ETM_ENABLED) + * + * \note This should always be enabled, it is a security + * improvement, and should not cause any interoperability + * issue (used only if the peer supports it too). + * + * \param conf SSL configuration + * \param etm MBEDTLS_SSL_ETM_ENABLED or MBEDTLS_SSL_ETM_DISABLED + */ +void mbedtls_ssl_conf_encrypt_then_mac( mbedtls_ssl_config *conf, char etm ); +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +/** + * \brief Enable or disable Extended Master Secret negotiation. + * (Default: MBEDTLS_SSL_EXTENDED_MS_ENABLED) + * + * \note This should always be enabled, it is a security fix to the + * protocol, and should not cause any interoperability issue + * (used only if the peer supports it too). + * + * \param conf SSL configuration + * \param ems MBEDTLS_SSL_EXTENDED_MS_ENABLED or MBEDTLS_SSL_EXTENDED_MS_DISABLED + */ +void mbedtls_ssl_conf_extended_master_secret( mbedtls_ssl_config *conf, char ems ); +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_ARC4_C) +/** + * \brief Disable or enable support for RC4 + * (Default: MBEDTLS_SSL_ARC4_DISABLED) + * + * \warning Use of RC4 in DTLS/TLS has been prohibited by RFC 7465 + * for security reasons. Use at your own risk. + * + * \note This function is deprecated and will likely be removed in + * a future version of the library. + * RC4 is disabled by default at compile time and needs to be + * actively enabled for use with legacy systems. + * + * \param conf SSL configuration + * \param arc4 MBEDTLS_SSL_ARC4_ENABLED or MBEDTLS_SSL_ARC4_DISABLED + */ +void mbedtls_ssl_conf_arc4_support( mbedtls_ssl_config *conf, char arc4 ); +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_SSL_SRV_C) +/** + * \brief Whether to send a list of acceptable CAs in + * CertificateRequest messages. + * (Default: do send) + * + * \param conf SSL configuration + * \param cert_req_ca_list MBEDTLS_SSL_CERT_REQ_CA_LIST_ENABLED or + * MBEDTLS_SSL_CERT_REQ_CA_LIST_DISABLED + */ +void mbedtls_ssl_conf_cert_req_ca_list( mbedtls_ssl_config *conf, + char cert_req_ca_list ); +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +/** + * \brief Set the maximum fragment length to emit and/or negotiate. + * (Typical: the smaller of #MBEDTLS_SSL_IN_CONTENT_LEN and + * #MBEDTLS_SSL_OUT_CONTENT_LEN, usually `2^14` bytes) + * (Server: set maximum fragment length to emit, + * usually negotiated by the client during handshake) + * (Client: set maximum fragment length to emit *and* + * negotiate with the server during handshake) + * (Default: #MBEDTLS_SSL_MAX_FRAG_LEN_NONE) + * + * \note On the client side, the maximum fragment length extension + * *will not* be used, unless the maximum fragment length has + * been set via this function to a value different than + * #MBEDTLS_SSL_MAX_FRAG_LEN_NONE. + * + * \note With TLS, this currently only affects ApplicationData (sent + * with \c mbedtls_ssl_read()), not handshake messages. + * With DTLS, this affects both ApplicationData and handshake. + * + * \note This sets the maximum length for a record's payload, + * excluding record overhead that will be added to it, see + * \c mbedtls_ssl_get_record_expansion(). + * + * \note For DTLS, it is also possible to set a limit for the total + * size of daragrams passed to the transport layer, including + * record overhead, see \c mbedtls_ssl_set_mtu(). + * + * \param conf SSL configuration + * \param mfl_code Code for maximum fragment length (allowed values: + * MBEDTLS_SSL_MAX_FRAG_LEN_512, MBEDTLS_SSL_MAX_FRAG_LEN_1024, + * MBEDTLS_SSL_MAX_FRAG_LEN_2048, MBEDTLS_SSL_MAX_FRAG_LEN_4096) + * + * \return 0 if successful or MBEDTLS_ERR_SSL_BAD_INPUT_DATA + */ +int mbedtls_ssl_conf_max_frag_len( mbedtls_ssl_config *conf, unsigned char mfl_code ); +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +/** + * \brief Activate negotiation of truncated HMAC + * (Default: MBEDTLS_SSL_TRUNC_HMAC_DISABLED) + * + * \param conf SSL configuration + * \param truncate Enable or disable (MBEDTLS_SSL_TRUNC_HMAC_ENABLED or + * MBEDTLS_SSL_TRUNC_HMAC_DISABLED) + */ +void mbedtls_ssl_conf_truncated_hmac( mbedtls_ssl_config *conf, int truncate ); +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) +/** + * \brief Enable / Disable 1/n-1 record splitting + * (Default: MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED) + * + * \note Only affects SSLv3 and TLS 1.0, not higher versions. + * Does not affect non-CBC ciphersuites in any version. + * + * \param conf SSL configuration + * \param split MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED or + * MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED + */ +void mbedtls_ssl_conf_cbc_record_splitting( mbedtls_ssl_config *conf, char split ); +#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Enable / Disable session tickets (client only). + * (Default: MBEDTLS_SSL_SESSION_TICKETS_ENABLED.) + * + * \note On server, use \c mbedtls_ssl_conf_session_tickets_cb(). + * + * \param conf SSL configuration + * \param use_tickets Enable or disable (MBEDTLS_SSL_SESSION_TICKETS_ENABLED or + * MBEDTLS_SSL_SESSION_TICKETS_DISABLED) + */ +void mbedtls_ssl_conf_session_tickets( mbedtls_ssl_config *conf, int use_tickets ); +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +/** + * \brief Enable / Disable renegotiation support for connection when + * initiated by peer + * (Default: MBEDTLS_SSL_RENEGOTIATION_DISABLED) + * + * \warning It is recommended to always disable renegotation unless you + * know you need it and you know what you're doing. In the + * past, there have been several issues associated with + * renegotiation or a poor understanding of its properties. + * + * \note Server-side, enabling renegotiation also makes the server + * susceptible to a resource DoS by a malicious client. + * + * \param conf SSL configuration + * \param renegotiation Enable or disable (MBEDTLS_SSL_RENEGOTIATION_ENABLED or + * MBEDTLS_SSL_RENEGOTIATION_DISABLED) + */ +void mbedtls_ssl_conf_renegotiation( mbedtls_ssl_config *conf, int renegotiation ); +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/** + * \brief Prevent or allow legacy renegotiation. + * (Default: MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION) + * + * MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION allows connections to + * be established even if the peer does not support + * secure renegotiation, but does not allow renegotiation + * to take place if not secure. + * (Interoperable and secure option) + * + * MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION allows renegotiations + * with non-upgraded peers. Allowing legacy renegotiation + * makes the connection vulnerable to specific man in the + * middle attacks. (See RFC 5746) + * (Most interoperable and least secure option) + * + * MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE breaks off connections + * if peer does not support secure renegotiation. Results + * in interoperability issues with non-upgraded peers + * that do not support renegotiation altogether. + * (Most secure option, interoperability issues) + * + * \param conf SSL configuration + * \param allow_legacy Prevent or allow (SSL_NO_LEGACY_RENEGOTIATION, + * SSL_ALLOW_LEGACY_RENEGOTIATION or + * MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE) + */ +void mbedtls_ssl_conf_legacy_renegotiation( mbedtls_ssl_config *conf, int allow_legacy ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +/** + * \brief Enforce renegotiation requests. + * (Default: enforced, max_records = 16) + * + * When we request a renegotiation, the peer can comply or + * ignore the request. This function allows us to decide + * whether to enforce our renegotiation requests by closing + * the connection if the peer doesn't comply. + * + * However, records could already be in transit from the peer + * when the request is emitted. In order to increase + * reliability, we can accept a number of records before the + * expected handshake records. + * + * The optimal value is highly dependent on the specific usage + * scenario. + * + * \note With DTLS and server-initiated renegotiation, the + * HelloRequest is retransmited every time mbedtls_ssl_read() times + * out or receives Application Data, until: + * - max_records records have beens seen, if it is >= 0, or + * - the number of retransmits that would happen during an + * actual handshake has been reached. + * Please remember the request might be lost a few times + * if you consider setting max_records to a really low value. + * + * \warning On client, the grace period can only happen during + * mbedtls_ssl_read(), as opposed to mbedtls_ssl_write() and mbedtls_ssl_renegotiate() + * which always behave as if max_record was 0. The reason is, + * if we receive application data from the server, we need a + * place to write it, which only happens during mbedtls_ssl_read(). + * + * \param conf SSL configuration + * \param max_records Use MBEDTLS_SSL_RENEGOTIATION_NOT_ENFORCED if you don't want to + * enforce renegotiation, or a non-negative value to enforce + * it but allow for a grace period of max_records records. + */ +void mbedtls_ssl_conf_renegotiation_enforced( mbedtls_ssl_config *conf, int max_records ); + +/** + * \brief Set record counter threshold for periodic renegotiation. + * (Default: 2^48 - 1) + * + * Renegotiation is automatically triggered when a record + * counter (outgoing or incoming) crosses the defined + * threshold. The default value is meant to prevent the + * connection from being closed when the counter is about to + * reached its maximal value (it is not allowed to wrap). + * + * Lower values can be used to enforce policies such as "keys + * must be refreshed every N packets with cipher X". + * + * The renegotiation period can be disabled by setting + * conf->disable_renegotiation to + * MBEDTLS_SSL_RENEGOTIATION_DISABLED. + * + * \note When the configured transport is + * MBEDTLS_SSL_TRANSPORT_DATAGRAM the maximum renegotiation + * period is 2^48 - 1, and for MBEDTLS_SSL_TRANSPORT_STREAM, + * the maximum renegotiation period is 2^64 - 1. + * + * \param conf SSL configuration + * \param period The threshold value: a big-endian 64-bit number. + */ +void mbedtls_ssl_conf_renegotiation_period( mbedtls_ssl_config *conf, + const unsigned char period[8] ); +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/** + * \brief Check if there is data already read from the + * underlying transport but not yet processed. + * + * \param ssl SSL context + * + * \return 0 if nothing's pending, 1 otherwise. + * + * \note This is different in purpose and behaviour from + * \c mbedtls_ssl_get_bytes_avail in that it considers + * any kind of unprocessed data, not only unread + * application data. If \c mbedtls_ssl_get_bytes + * returns a non-zero value, this function will + * also signal pending data, but the converse does + * not hold. For example, in DTLS there might be + * further records waiting to be processed from + * the current underlying transport's datagram. + * + * \note If this function returns 1 (data pending), this + * does not imply that a subsequent call to + * \c mbedtls_ssl_read will provide any data; + * e.g., the unprocessed data might turn out + * to be an alert or a handshake message. + * + * \note This function is useful in the following situation: + * If the SSL/TLS module successfully returns from an + * operation - e.g. a handshake or an application record + * read - and you're awaiting incoming data next, you + * must not immediately idle on the underlying transport + * to have data ready, but you need to check the value + * of this function first. The reason is that the desired + * data might already be read but not yet processed. + * If, in contrast, a previous call to the SSL/TLS module + * returned MBEDTLS_ERR_SSL_WANT_READ, it is not necessary + * to call this function, as the latter error code entails + * that all internal data has been processed. + * + */ +int mbedtls_ssl_check_pending( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the number of application data bytes + * remaining to be read from the current record. + * + * \param ssl SSL context + * + * \return How many bytes are available in the application + * data record read buffer. + * + * \note When working over a datagram transport, this is + * useful to detect the current datagram's boundary + * in case \c mbedtls_ssl_read has written the maximal + * amount of data fitting into the input buffer. + * + */ +size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the result of the certificate verification + * + * \param ssl The SSL context to use. + * + * \return \c 0 if the certificate verification was successful. + * \return \c -1u if the result is not available. This may happen + * e.g. if the handshake aborts early, or a verification + * callback returned a fatal error. + * \return A bitwise combination of \c MBEDTLS_X509_BADCERT_XXX + * and \c MBEDTLS_X509_BADCRL_XXX failure flags; see x509.h. + */ +uint32_t mbedtls_ssl_get_verify_result( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the name of the current ciphersuite + * + * \param ssl SSL context + * + * \return a string containing the ciphersuite name + */ +const char *mbedtls_ssl_get_ciphersuite( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the current SSL version (SSLv3/TLSv1/etc) + * + * \param ssl SSL context + * + * \return a string containing the SSL version + */ +const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the (maximum) number of bytes added by the record + * layer: header + encryption/MAC overhead (inc. padding) + * + * \note This function is not available (always returns an error) + * when record compression is enabled. + * + * \param ssl SSL context + * + * \return Current maximum record expansion in bytes, or + * MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE if compression is + * enabled, which makes expansion much less predictable + */ +int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ); + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +/** + * \brief Return the maximum fragment length (payload, in bytes). + * This is the value negotiated with peer if any, + * or the locally configured value. + * + * \sa mbedtls_ssl_conf_max_frag_len() + * \sa mbedtls_ssl_get_max_record_payload() + * + * \param ssl SSL context + * + * \return Current maximum fragment length. + */ +size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +/** + * \brief Return the current maximum outgoing record payload in bytes. + * This takes into account the config.h setting \c + * MBEDTLS_SSL_OUT_CONTENT_LEN, the configured and negotiated + * max fragment length extension if used, and for DTLS the + * path MTU as configured and current record expansion. + * + * \note With DTLS, \c mbedtls_ssl_write() will return an error if + * called with a larger length value. + * With TLS, \c mbedtls_ssl_write() will fragment the input if + * necessary and return the number of bytes written; it is up + * to the caller to call \c mbedtls_ssl_write() again in + * order to send the remaining bytes if any. + * + * \note This function is not available (always returns an error) + * when record compression is enabled. + * + * \sa mbedtls_ssl_set_mtu() + * \sa mbedtls_ssl_get_max_frag_len() + * \sa mbedtls_ssl_get_record_expansion() + * + * \param ssl SSL context + * + * \return Current maximum payload for an outgoing record, + * or a negative error code. + */ +int mbedtls_ssl_get_max_out_record_payload( const mbedtls_ssl_context *ssl ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Return the peer certificate from the current connection. + * + * \param ssl The SSL context to use. This must be initialized and setup. + * + * \return The current peer certificate, if available. + * The returned certificate is owned by the SSL context and + * is valid only until the next call to the SSL API. + * \return \c NULL if no peer certificate is available. This might + * be because the chosen ciphersuite doesn't use CRTs + * (PSK-based ciphersuites, for example), or because + * #MBEDTLS_SSL_KEEP_PEER_CERTIFICATE has been disabled, + * allowing the stack to free the peer's CRT to save memory. + * + * \note For one-time inspection of the peer's certificate during + * the handshake, consider registering an X.509 CRT verification + * callback through mbedtls_ssl_conf_verify() instead of calling + * this function. Using mbedtls_ssl_conf_verify() also comes at + * the benefit of allowing you to influence the verification + * process, for example by masking expected and tolerated + * verification failures. + * + * \warning You must not use the pointer returned by this function + * after any further call to the SSL API, including + * mbedtls_ssl_read() and mbedtls_ssl_write(); this is + * because the pointer might change during renegotiation, + * which happens transparently to the user. + * If you want to use the certificate across API calls, + * you must make a copy. + */ +const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Save session in order to resume it later (client-side only) + * Session data is copied to presented session structure. + * + * + * \param ssl SSL context + * \param session session context + * + * \return 0 if successful, + * MBEDTLS_ERR_SSL_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_SSL_BAD_INPUT_DATA if used server-side or + * arguments are otherwise invalid. + * + * \note Only the server certificate is copied, and not the full chain, + * so you should not attempt to validate the certificate again + * by calling \c mbedtls_x509_crt_verify() on it. + * Instead, you should use the results from the verification + * in the original handshake by calling \c mbedtls_ssl_get_verify_result() + * after loading the session again into a new SSL context + * using \c mbedtls_ssl_set_session(). + * + * \note Once the session object is not needed anymore, you should + * free it by calling \c mbedtls_ssl_session_free(). + * + * \sa mbedtls_ssl_set_session() + */ +int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, mbedtls_ssl_session *session ); +#endif /* MBEDTLS_SSL_CLI_C */ + +/** + * \brief Perform the SSL handshake + * + * \param ssl SSL context + * + * \return \c 0 if successful. + * \return #MBEDTLS_ERR_SSL_WANT_READ or #MBEDTLS_ERR_SSL_WANT_WRITE + * if the handshake is incomplete and waiting for data to + * be available for reading from or writing to the underlying + * transport - in this case you must call this function again + * when the underlying transport is ready for the operation. + * \return #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if an asynchronous + * operation is in progress (see + * mbedtls_ssl_conf_async_private_cb()) - in this case you + * must call this function again when the operation is ready. + * \return #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS if a cryptographic + * operation is in progress (see mbedtls_ecp_set_max_ops()) - + * in this case you must call this function again to complete + * the handshake when you're done attending other tasks. + * \return #MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED if DTLS is in use + * and the client did not demonstrate reachability yet - in + * this case you must stop using the context (see below). + * \return Another SSL error code - in this case you must stop using + * the context (see below). + * + * \warning If this function returns something other than + * \c 0, + * #MBEDTLS_ERR_SSL_WANT_READ, + * #MBEDTLS_ERR_SSL_WANT_WRITE, + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS or + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS, + * you must stop using the SSL context for reading or writing, + * and either free it or call \c mbedtls_ssl_session_reset() + * on it before re-using it for a new connection; the current + * connection must be closed. + * + * \note If DTLS is in use, then you may choose to handle + * #MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED specially for logging + * purposes, as it is an expected return value rather than an + * actual error, but you still need to reset/free the context. + * + * \note Remarks regarding event-driven DTLS: + * If the function returns #MBEDTLS_ERR_SSL_WANT_READ, no datagram + * from the underlying transport layer is currently being processed, + * and it is safe to idle until the timer or the underlying transport + * signal a new event. This is not true for a successful handshake, + * in which case the datagram of the underlying transport that is + * currently being processed might or might not contain further + * DTLS records. + */ +int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl ); + +/** + * \brief Perform a single step of the SSL handshake + * + * \note The state of the context (ssl->state) will be at + * the next state after this function returns \c 0. Do not + * call this function if state is MBEDTLS_SSL_HANDSHAKE_OVER. + * + * \param ssl SSL context + * + * \return See mbedtls_ssl_handshake(). + * + * \warning If this function returns something other than \c 0, + * #MBEDTLS_ERR_SSL_WANT_READ, #MBEDTLS_ERR_SSL_WANT_WRITE, + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS or + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS, you must stop using + * the SSL context for reading or writing, and either free it + * or call \c mbedtls_ssl_session_reset() on it before + * re-using it for a new connection; the current connection + * must be closed. + */ +int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +/** + * \brief Initiate an SSL renegotiation on the running connection. + * Client: perform the renegotiation right now. + * Server: request renegotiation, which will be performed + * during the next call to mbedtls_ssl_read() if honored by + * client. + * + * \param ssl SSL context + * + * \return 0 if successful, or any mbedtls_ssl_handshake() return + * value except #MBEDTLS_ERR_SSL_CLIENT_RECONNECT that can't + * happen during a renegotiation. + * + * \warning If this function returns something other than \c 0, + * #MBEDTLS_ERR_SSL_WANT_READ, #MBEDTLS_ERR_SSL_WANT_WRITE, + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS or + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS, you must stop using + * the SSL context for reading or writing, and either free it + * or call \c mbedtls_ssl_session_reset() on it before + * re-using it for a new connection; the current connection + * must be closed. + * + */ +int mbedtls_ssl_renegotiate( mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/** + * \brief Read at most 'len' application data bytes + * + * \param ssl SSL context + * \param buf buffer that will hold the data + * \param len maximum number of bytes to read + * + * \return The (positive) number of bytes read if successful. + * \return \c 0 if the read end of the underlying transport was closed + * - in this case you must stop using the context (see below). + * \return #MBEDTLS_ERR_SSL_WANT_READ or #MBEDTLS_ERR_SSL_WANT_WRITE + * if the handshake is incomplete and waiting for data to + * be available for reading from or writing to the underlying + * transport - in this case you must call this function again + * when the underlying transport is ready for the operation. + * \return #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if an asynchronous + * operation is in progress (see + * mbedtls_ssl_conf_async_private_cb()) - in this case you + * must call this function again when the operation is ready. + * \return #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS if a cryptographic + * operation is in progress (see mbedtls_ecp_set_max_ops()) - + * in this case you must call this function again to complete + * the handshake when you're done attending other tasks. + * \return #MBEDTLS_ERR_SSL_CLIENT_RECONNECT if we're at the server + * side of a DTLS connection and the client is initiating a + * new connection using the same source port. See below. + * \return Another SSL error code - in this case you must stop using + * the context (see below). + * + * \warning If this function returns something other than + * a positive value, + * #MBEDTLS_ERR_SSL_WANT_READ, + * #MBEDTLS_ERR_SSL_WANT_WRITE, + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS, + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS or + * #MBEDTLS_ERR_SSL_CLIENT_RECONNECT, + * you must stop using the SSL context for reading or writing, + * and either free it or call \c mbedtls_ssl_session_reset() + * on it before re-using it for a new connection; the current + * connection must be closed. + * + * \note When this function returns #MBEDTLS_ERR_SSL_CLIENT_RECONNECT + * (which can only happen server-side), it means that a client + * is initiating a new connection using the same source port. + * You can either treat that as a connection close and wait + * for the client to resend a ClientHello, or directly + * continue with \c mbedtls_ssl_handshake() with the same + * context (as it has been reset internally). Either way, you + * must make sure this is seen by the application as a new + * connection: application state, if any, should be reset, and + * most importantly the identity of the client must be checked + * again. WARNING: not validating the identity of the client + * again, or not transmitting the new identity to the + * application layer, would allow authentication bypass! + * + * \note Remarks regarding event-driven DTLS: + * - If the function returns #MBEDTLS_ERR_SSL_WANT_READ, no datagram + * from the underlying transport layer is currently being processed, + * and it is safe to idle until the timer or the underlying transport + * signal a new event. + * - This function may return MBEDTLS_ERR_SSL_WANT_READ even if data was + * initially available on the underlying transport, as this data may have + * been only e.g. duplicated messages or a renegotiation request. + * Therefore, you must be prepared to receive MBEDTLS_ERR_SSL_WANT_READ even + * when reacting to an incoming-data event from the underlying transport. + * - On success, the datagram of the underlying transport that is currently + * being processed may contain further DTLS records. You should call + * \c mbedtls_ssl_check_pending to check for remaining records. + * + */ +int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ); + +/** + * \brief Try to write exactly 'len' application data bytes + * + * \warning This function will do partial writes in some cases. If the + * return value is non-negative but less than length, the + * function must be called again with updated arguments: + * buf + ret, len - ret (if ret is the return value) until + * it returns a value equal to the last 'len' argument. + * + * \param ssl SSL context + * \param buf buffer holding the data + * \param len how many bytes must be written + * + * \return The (non-negative) number of bytes actually written if + * successful (may be less than \p len). + * \return #MBEDTLS_ERR_SSL_WANT_READ or #MBEDTLS_ERR_SSL_WANT_WRITE + * if the handshake is incomplete and waiting for data to + * be available for reading from or writing to the underlying + * transport - in this case you must call this function again + * when the underlying transport is ready for the operation. + * \return #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS if an asynchronous + * operation is in progress (see + * mbedtls_ssl_conf_async_private_cb()) - in this case you + * must call this function again when the operation is ready. + * \return #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS if a cryptographic + * operation is in progress (see mbedtls_ecp_set_max_ops()) - + * in this case you must call this function again to complete + * the handshake when you're done attending other tasks. + * \return Another SSL error code - in this case you must stop using + * the context (see below). + * + * \warning If this function returns something other than + * a non-negative value, + * #MBEDTLS_ERR_SSL_WANT_READ, + * #MBEDTLS_ERR_SSL_WANT_WRITE, + * #MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS or + * #MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS, + * you must stop using the SSL context for reading or writing, + * and either free it or call \c mbedtls_ssl_session_reset() + * on it before re-using it for a new connection; the current + * connection must be closed. + * + * \note When this function returns #MBEDTLS_ERR_SSL_WANT_WRITE/READ, + * it must be called later with the *same* arguments, + * until it returns a value greater that or equal to 0. When + * the function returns #MBEDTLS_ERR_SSL_WANT_WRITE there may be + * some partial data in the output buffer, however this is not + * yet sent. + * + * \note If the requested length is greater than the maximum + * fragment length (either the built-in limit or the one set + * or negotiated with the peer), then: + * - with TLS, less bytes than requested are written. + * - with DTLS, MBEDTLS_ERR_SSL_BAD_INPUT_DATA is returned. + * \c mbedtls_ssl_get_max_frag_len() may be used to query the + * active maximum fragment length. + * + * \note Attempting to write 0 bytes will result in an empty TLS + * application record being sent. + */ +int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ); + +/** + * \brief Send an alert message + * + * \param ssl SSL context + * \param level The alert level of the message + * (MBEDTLS_SSL_ALERT_LEVEL_WARNING or MBEDTLS_SSL_ALERT_LEVEL_FATAL) + * \param message The alert message (SSL_ALERT_MSG_*) + * + * \return 0 if successful, or a specific SSL error code. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, you must stop using + * the SSL context for reading or writing, and either free it or + * call \c mbedtls_ssl_session_reset() on it before re-using it + * for a new connection; the current connection must be closed. + */ +int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl, + unsigned char level, + unsigned char message ); +/** + * \brief Notify the peer that the connection is being closed + * + * \param ssl SSL context + * + * \return 0 if successful, or a specific SSL error code. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, you must stop using + * the SSL context for reading or writing, and either free it or + * call \c mbedtls_ssl_session_reset() on it before re-using it + * for a new connection; the current connection must be closed. + */ +int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl ); + +/** + * \brief Free referenced items in an SSL context and clear memory + * + * \param ssl SSL context + */ +void mbedtls_ssl_free( mbedtls_ssl_context *ssl ); + +/** + * \brief Initialize an SSL configuration context + * Just makes the context ready for + * mbedtls_ssl_config_defaults() or mbedtls_ssl_config_free(). + * + * \note You need to call mbedtls_ssl_config_defaults() unless you + * manually set all of the relevant fields yourself. + * + * \param conf SSL configuration context + */ +void mbedtls_ssl_config_init( mbedtls_ssl_config *conf ); + +/** + * \brief Load reasonnable default SSL configuration values. + * (You need to call mbedtls_ssl_config_init() first.) + * + * \param conf SSL configuration context + * \param endpoint MBEDTLS_SSL_IS_CLIENT or MBEDTLS_SSL_IS_SERVER + * \param transport MBEDTLS_SSL_TRANSPORT_STREAM for TLS, or + * MBEDTLS_SSL_TRANSPORT_DATAGRAM for DTLS + * \param preset a MBEDTLS_SSL_PRESET_XXX value + * + * \note See \c mbedtls_ssl_conf_transport() for notes on DTLS. + * + * \return 0 if successful, or + * MBEDTLS_ERR_XXX_ALLOC_FAILED on memory allocation error. + */ +int mbedtls_ssl_config_defaults( mbedtls_ssl_config *conf, + int endpoint, int transport, int preset ); + +/** + * \brief Free an SSL configuration context + * + * \param conf SSL configuration context + */ +void mbedtls_ssl_config_free( mbedtls_ssl_config *conf ); + +/** + * \brief Initialize SSL session structure + * + * \param session SSL session + */ +void mbedtls_ssl_session_init( mbedtls_ssl_session *session ); + +/** + * \brief Free referenced items in an SSL session including the + * peer certificate and clear memory + * + * \note A session object can be freed even if the SSL context + * that was used to retrieve the session is still in use. + * + * \param session SSL session + */ +void mbedtls_ssl_session_free( mbedtls_ssl_session *session ); + +/** + * \brief TLS-PRF function for key derivation. + * + * \param prf The tls_prf type funtion type to be used. + * \param secret Secret for the key derivation function. + * \param slen Length of the secret. + * \param label String label for the key derivation function, + * terminated with null character. + * \param random Random bytes. + * \param rlen Length of the random bytes buffer. + * \param dstbuf The buffer holding the derived key. + * \param dlen Length of the output buffer. + * + * \return 0 on sucess. An SSL specific error on failure. + */ +int mbedtls_ssl_tls_prf( const mbedtls_tls_prf_types prf, + const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_cache.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_cache.h new file mode 100644 index 000000000..aa19e3545 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_cache.h @@ -0,0 +1,151 @@ +/** + * \file ssl_cache.h + * + * \brief SSL session cache implementation + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_CACHE_H +#define MBEDTLS_SSL_CACHE_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "ssl.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT) +#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /*!< 1 day */ +#endif + +#if !defined(MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES) +#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /*!< Maximum entries in cache */ +#endif + +/* \} name SECTION: Module settings */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct mbedtls_ssl_cache_context mbedtls_ssl_cache_context; +typedef struct mbedtls_ssl_cache_entry mbedtls_ssl_cache_entry; + +/** + * \brief This structure is used for storing cache entries + */ +struct mbedtls_ssl_cache_entry +{ +#if defined(MBEDTLS_HAVE_TIME) + mbedtls_time_t timestamp; /*!< entry timestamp */ +#endif + mbedtls_ssl_session session; /*!< entry session */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + mbedtls_x509_buf peer_cert; /*!< entry peer_cert */ +#endif + mbedtls_ssl_cache_entry *next; /*!< chain pointer */ +}; + +/** + * \brief Cache context + */ +struct mbedtls_ssl_cache_context +{ + mbedtls_ssl_cache_entry *chain; /*!< start of the chain */ + int timeout; /*!< cache entry timeout */ + int max_entries; /*!< maximum entries */ +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; /*!< mutex */ +#endif +}; + +/** + * \brief Initialize an SSL cache context + * + * \param cache SSL cache context + */ +void mbedtls_ssl_cache_init( mbedtls_ssl_cache_context *cache ); + +/** + * \brief Cache get callback implementation + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param data SSL cache context + * \param session session to retrieve entry for + */ +int mbedtls_ssl_cache_get( void *data, mbedtls_ssl_session *session ); + +/** + * \brief Cache set callback implementation + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param data SSL cache context + * \param session session to store entry for + */ +int mbedtls_ssl_cache_set( void *data, const mbedtls_ssl_session *session ); + +#if defined(MBEDTLS_HAVE_TIME) +/** + * \brief Set the cache timeout + * (Default: MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT (1 day)) + * + * A timeout of 0 indicates no timeout. + * + * \param cache SSL cache context + * \param timeout cache entry timeout in seconds + */ +void mbedtls_ssl_cache_set_timeout( mbedtls_ssl_cache_context *cache, int timeout ); +#endif /* MBEDTLS_HAVE_TIME */ + +/** + * \brief Set the maximum number of cache entries + * (Default: MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES (50)) + * + * \param cache SSL cache context + * \param max cache entry maximum + */ +void mbedtls_ssl_cache_set_max_entries( mbedtls_ssl_cache_context *cache, int max ); + +/** + * \brief Free referenced items in a cache context and clear memory + * + * \param cache SSL cache context + */ +void mbedtls_ssl_cache_free( mbedtls_ssl_cache_context *cache ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_cache.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_ciphersuites.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_ciphersuites.h new file mode 100644 index 000000000..9b10700d7 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_ciphersuites.h @@ -0,0 +1,558 @@ +/** + * \file ssl_ciphersuites.h + * + * \brief SSL Ciphersuites for mbed TLS + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_CIPHERSUITES_H +#define MBEDTLS_SSL_CIPHERSUITES_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "pk.h" +#include "cipher.h" +#include "md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Supported ciphersuites (Official IANA names) + */ +#define MBEDTLS_TLS_RSA_WITH_NULL_MD5 0x01 /**< Weak! */ +#define MBEDTLS_TLS_RSA_WITH_NULL_SHA 0x02 /**< Weak! */ + +#define MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 0x04 +#define MBEDTLS_TLS_RSA_WITH_RC4_128_SHA 0x05 +#define MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA 0x09 /**< Weak! Not in TLS 1.2 */ + +#define MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x0A + +#define MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA 0x15 /**< Weak! Not in TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x16 + +#define MBEDTLS_TLS_PSK_WITH_NULL_SHA 0x2C /**< Weak! */ +#define MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA 0x2D /**< Weak! */ +#define MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA 0x2E /**< Weak! */ +#define MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA 0x2F + +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x33 +#define MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA 0x35 +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x39 + +#define MBEDTLS_TLS_RSA_WITH_NULL_SHA256 0x3B /**< Weak! */ +#define MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 0x3C /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 0x3D /**< TLS 1.2 */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA 0x41 +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA 0x45 + +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x67 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x6B /**< TLS 1.2 */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA 0x84 +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x88 + +#define MBEDTLS_TLS_PSK_WITH_RC4_128_SHA 0x8A +#define MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA 0x8B +#define MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA 0x8C +#define MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA 0x8D + +#define MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA 0x8E +#define MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA 0x8F +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA 0x90 +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA 0x91 + +#define MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA 0x92 +#define MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA 0x93 +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA 0x94 +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA 0x95 + +#define MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 0x9C /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 0x9D /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x9E /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x9F /**< TLS 1.2 */ + +#define MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 0xA8 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 0xA9 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 0xAA /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 0xAB /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 0xAC /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 0xAD /**< TLS 1.2 */ + +#define MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 0xAE +#define MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 0xAF +#define MBEDTLS_TLS_PSK_WITH_NULL_SHA256 0xB0 /**< Weak! */ +#define MBEDTLS_TLS_PSK_WITH_NULL_SHA384 0xB1 /**< Weak! */ + +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 0xB2 +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 0xB3 +#define MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 0xB4 /**< Weak! */ +#define MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 0xB5 /**< Weak! */ + +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 0xB6 +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 0xB7 +#define MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 0xB8 /**< Weak! */ +#define MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 0xB9 /**< Weak! */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xBA /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xBE /**< TLS 1.2 */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 0xC0 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 0xC4 /**< TLS 1.2 */ + +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA 0xC001 /**< Weak! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA 0xC002 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC003 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0xC004 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0xC005 /**< Not in SSL3! */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA 0xC006 /**< Weak! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA 0xC007 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC008 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A /**< Not in SSL3! */ + +#define MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA 0xC00B /**< Weak! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA 0xC00C /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 0xC00D /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 0xC00E /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 0xC00F /**< Not in SSL3! */ + +#define MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA 0xC010 /**< Weak! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA 0xC011 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 0xC012 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014 /**< Not in SSL3! */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 0xC024 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 0xC025 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 0xC026 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 0xC028 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 0xC029 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 0xC02A /**< TLS 1.2 */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xC02C /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0xC02D /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0xC02E /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xC030 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 0xC031 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 0xC032 /**< TLS 1.2 */ + +#define MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA 0xC033 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA 0xC034 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA 0xC035 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA 0xC036 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 0xC037 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 0xC038 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA 0xC039 /**< Weak! No SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 0xC03A /**< Weak! No SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 0xC03B /**< Weak! No SSL3! */ + +#define MBEDTLS_TLS_RSA_WITH_ARIA_128_CBC_SHA256 0xC03C /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_ARIA_256_CBC_SHA384 0xC03D /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 0xC044 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 0xC045 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 0xC048 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 0xC049 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 0xC04A /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 0xC04B /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 0xC04C /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 0xC04D /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 0xC04E /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 0xC04F /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256 0xC050 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384 0xC051 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 0xC052 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 0xC053 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 0xC05C /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 0xC05D /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 0xC05E /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 0xC05F /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 0xC060 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 0xC061 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 0xC062 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 0xC063 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_ARIA_128_CBC_SHA256 0xC064 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_ARIA_256_CBC_SHA384 0xC065 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 0xC066 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 0xC067 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 0xC068 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 0xC069 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256 0xC06A /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384 0xC06B /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 0xC06C /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 0xC06D /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 0xC06E /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 0xC06F /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 0xC070 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 0xC071 /**< TLS 1.2 */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 0xC072 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 0xC073 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 0xC074 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 0xC075 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xC076 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 0xC077 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xC078 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 0xC079 /**< Not in SSL3! */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 0xC07A /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 0xC07B /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 0xC07C /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 0xC07D /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 0xC086 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 0xC087 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 0xC088 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 0xC089 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 0xC08A /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 0xC08B /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 0xC08C /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 0xC08D /**< TLS 1.2 */ + +#define MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 0xC08E /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 0xC08F /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 0xC090 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 0xC091 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 0xC092 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 0xC093 /**< TLS 1.2 */ + +#define MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 0xC094 +#define MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 0xC095 +#define MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 0xC096 +#define MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 0xC097 +#define MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 0xC098 +#define MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 0xC099 +#define MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 0xC09A /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 0xC09B /**< Not in SSL3! */ + +#define MBEDTLS_TLS_RSA_WITH_AES_128_CCM 0xC09C /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_256_CCM 0xC09D /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM 0xC09E /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM 0xC09F /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8 0xC0A0 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8 0xC0A1 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8 0xC0A2 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8 0xC0A3 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_128_CCM 0xC0A4 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_256_CCM 0xC0A5 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM 0xC0A6 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM 0xC0A7 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8 0xC0A8 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8 0xC0A9 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8 0xC0AA /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8 0xC0AB /**< TLS 1.2 */ +/* The last two are named with PSK_DHE in the RFC, which looks like a typo */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM 0xC0AC /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM 0xC0AD /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 0xC0AE /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 0xC0AF /**< TLS 1.2 */ + +#define MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 0xC0FF /**< experimental */ + +/* RFC 7905 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA8 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA9 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCAA /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAB /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAC /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAD /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAE /**< TLS 1.2 */ + +/* Reminder: update mbedtls_ssl_premaster_secret when adding a new key exchange. + * Reminder: update MBEDTLS_KEY_EXCHANGE__xxx below + */ +typedef enum { + MBEDTLS_KEY_EXCHANGE_NONE = 0, + MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_KEY_EXCHANGE_ECJPAKE, +} mbedtls_key_exchange_type_t; + +/* Key exchanges using a certificate */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED +#endif + +/* Key exchanges allowing client certificate requests */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED +#endif + +/* Key exchanges involving server signature in ServerKeyExchange */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED +#endif + +/* Key exchanges using ECDH */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED +#endif + +/* Key exchanges that don't involve ephemeral keys */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED +#endif + +/* Key exchanges that involve ephemeral keys */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED +#endif + +/* Key exchanges using a PSK */ +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED +#endif + +/* Key exchanges using DHE */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED +#endif + +/* Key exchanges using ECDHE */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED +#endif + +typedef struct mbedtls_ssl_ciphersuite_t mbedtls_ssl_ciphersuite_t; + +#define MBEDTLS_CIPHERSUITE_WEAK 0x01 /**< Weak ciphersuite flag */ +#define MBEDTLS_CIPHERSUITE_SHORT_TAG 0x02 /**< Short authentication tag, + eg for CCM_8 */ +#define MBEDTLS_CIPHERSUITE_NODTLS 0x04 /**< Can't be used with DTLS */ + +/** + * \brief This structure is used for storing ciphersuite information + */ +struct mbedtls_ssl_ciphersuite_t +{ + int id; + const char * name; + + mbedtls_cipher_type_t cipher; + mbedtls_md_type_t mac; + mbedtls_key_exchange_type_t key_exchange; + + int min_major_ver; + int min_minor_ver; + int max_major_ver; + int max_minor_ver; + + unsigned char flags; +}; + +const int *mbedtls_ssl_list_ciphersuites( void ); + +const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_string( const char *ciphersuite_name ); +const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_id( int ciphersuite_id ); + +#if defined(MBEDTLS_PK_C) +mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg( const mbedtls_ssl_ciphersuite_t *info ); +mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_alg( const mbedtls_ssl_ciphersuite_t *info ); +#endif + +int mbedtls_ssl_ciphersuite_uses_ec( const mbedtls_ssl_ciphersuite_t *info ); +int mbedtls_ssl_ciphersuite_uses_psk( const mbedtls_ssl_ciphersuite_t *info ); + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED) +static inline int mbedtls_ssl_ciphersuite_has_pfs( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_DHE_RSA: + case MBEDTLS_KEY_EXCHANGE_DHE_PSK: + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK: + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + case MBEDTLS_KEY_EXCHANGE_ECJPAKE: + return( 1 ); + + default: + return( 0 ); + } +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED) +static inline int mbedtls_ssl_ciphersuite_no_pfs( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_ECDH_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA: + case MBEDTLS_KEY_EXCHANGE_RSA: + case MBEDTLS_KEY_EXCHANGE_PSK: + case MBEDTLS_KEY_EXCHANGE_RSA_PSK: + return( 1 ); + + default: + return( 0 ); + } +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED) +static inline int mbedtls_ssl_ciphersuite_uses_ecdh( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_ECDH_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA: + return( 1 ); + + default: + return( 0 ); + } +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED */ + +static inline int mbedtls_ssl_ciphersuite_cert_req_allowed( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_RSA: + case MBEDTLS_KEY_EXCHANGE_DHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + return( 1 ); + + default: + return( 0 ); + } +} + +static inline int mbedtls_ssl_ciphersuite_uses_srv_cert( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_RSA: + case MBEDTLS_KEY_EXCHANGE_RSA_PSK: + case MBEDTLS_KEY_EXCHANGE_DHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + return( 1 ); + + default: + return( 0 ); + } +} + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED) +static inline int mbedtls_ssl_ciphersuite_uses_dhe( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_DHE_RSA: + case MBEDTLS_KEY_EXCHANGE_DHE_PSK: + return( 1 ); + + default: + return( 0 ); + } +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED) */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED) +static inline int mbedtls_ssl_ciphersuite_uses_ecdhe( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK: + return( 1 ); + + default: + return( 0 ); + } +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED) */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) +static inline int mbedtls_ssl_ciphersuite_uses_server_signature( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_DHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + return( 1 ); + + default: + return( 0 ); + } +} +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_ciphersuites.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_cookie.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_cookie.h new file mode 100644 index 000000000..5bbd4f9e1 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_cookie.h @@ -0,0 +1,115 @@ +/** + * \file ssl_cookie.h + * + * \brief DTLS cookie callbacks implementation + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_COOKIE_H +#define MBEDTLS_SSL_COOKIE_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "ssl.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ +#ifndef MBEDTLS_SSL_COOKIE_TIMEOUT +#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ +#endif + +/* \} name SECTION: Module settings */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Context for the default cookie functions. + */ +typedef struct mbedtls_ssl_cookie_ctx +{ + mbedtls_md_context_t hmac_ctx; /*!< context for the HMAC portion */ +#if !defined(MBEDTLS_HAVE_TIME) + unsigned long serial; /*!< serial number for expiration */ +#endif + unsigned long timeout; /*!< timeout delay, in seconds if HAVE_TIME, + or in number of tickets issued */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} mbedtls_ssl_cookie_ctx; + +/** + * \brief Initialize cookie context + */ +void mbedtls_ssl_cookie_init( mbedtls_ssl_cookie_ctx *ctx ); + +/** + * \brief Setup cookie context (generate keys) + */ +int mbedtls_ssl_cookie_setup( mbedtls_ssl_cookie_ctx *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Set expiration delay for cookies + * (Default MBEDTLS_SSL_COOKIE_TIMEOUT) + * + * \param ctx Cookie contex + * \param delay Delay, in seconds if HAVE_TIME, or in number of cookies + * issued in the meantime. + * 0 to disable expiration (NOT recommended) + */ +void mbedtls_ssl_cookie_set_timeout( mbedtls_ssl_cookie_ctx *ctx, unsigned long delay ); + +/** + * \brief Free cookie context + */ +void mbedtls_ssl_cookie_free( mbedtls_ssl_cookie_ctx *ctx ); + +/** + * \brief Generate cookie, see \c mbedtls_ssl_cookie_write_t + */ +mbedtls_ssl_cookie_write_t mbedtls_ssl_cookie_write; + +/** + * \brief Verify cookie, see \c mbedtls_ssl_cookie_write_t + */ +mbedtls_ssl_cookie_check_t mbedtls_ssl_cookie_check; + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_cookie.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_internal.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_internal.h new file mode 100644 index 000000000..920e77859 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_internal.h @@ -0,0 +1,1020 @@ +/** + * \file ssl_internal.h + * + * \brief Internal functions shared by the SSL modules + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_INTERNAL_H +#define MBEDTLS_SSL_INTERNAL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "ssl.h" +#include "cipher.h" + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "psa/crypto.h" +#endif + +#if defined(MBEDTLS_MD5_C) +#include "md5.h" +#endif + +#if defined(MBEDTLS_SHA1_C) +#include "sha1.h" +#endif + +#if defined(MBEDTLS_SHA256_C) +#include "sha256.h" +#endif + +#if defined(MBEDTLS_SHA512_C) +#include "sha512.h" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +#include "ecjpake.h" +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "psa/crypto.h" +#include "psa_util.h" +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* Determine minimum supported version */ +#define MBEDTLS_SSL_MIN_MAJOR_VERSION MBEDTLS_SSL_MAJOR_VERSION_3 + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +#define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_0 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1) +#define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_1 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) +#define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_2 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_3 +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1 */ +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#define MBEDTLS_SSL_MIN_VALID_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_1 +#define MBEDTLS_SSL_MIN_VALID_MAJOR_VERSION MBEDTLS_SSL_MAJOR_VERSION_3 + +/* Determine maximum supported version */ +#define MBEDTLS_SSL_MAX_MAJOR_VERSION MBEDTLS_SSL_MAJOR_VERSION_3 + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_3 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) +#define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_2 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1) +#define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_1 +#else +#if defined(MBEDTLS_SSL_PROTO_SSL3) +#define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_0 +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +/* Shorthand for restartable ECC */ +#if defined(MBEDTLS_ECP_RESTARTABLE) && \ + defined(MBEDTLS_SSL_CLI_C) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +#define MBEDTLS_SSL__ECP_RESTARTABLE +#endif + +#define MBEDTLS_SSL_INITIAL_HANDSHAKE 0 +#define MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS 1 /* In progress */ +#define MBEDTLS_SSL_RENEGOTIATION_DONE 2 /* Done or aborted */ +#define MBEDTLS_SSL_RENEGOTIATION_PENDING 3 /* Requested (server only) */ + +/* + * DTLS retransmission states, see RFC 6347 4.2.4 + * + * The SENDING state is merged in PREPARING for initial sends, + * but is distinct for resends. + * + * Note: initial state is wrong for server, but is not used anyway. + */ +#define MBEDTLS_SSL_RETRANS_PREPARING 0 +#define MBEDTLS_SSL_RETRANS_SENDING 1 +#define MBEDTLS_SSL_RETRANS_WAITING 2 +#define MBEDTLS_SSL_RETRANS_FINISHED 3 + +/* + * Allow extra bytes for record, authentication and encryption overhead: + * counter (8) + header (5) + IV(16) + MAC (16-48) + padding (0-256) + * and allow for a maximum of 1024 of compression expansion if + * enabled. + */ +#if defined(MBEDTLS_ZLIB_SUPPORT) +#define MBEDTLS_SSL_COMPRESSION_ADD 1024 +#else +#define MBEDTLS_SSL_COMPRESSION_ADD 0 +#endif + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) || \ + ( defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_AES_C) || \ + defined(MBEDTLS_CAMELLIA_C) || \ + defined(MBEDTLS_ARIA_C) || \ + defined(MBEDTLS_DES_C) ) ) +#define MBEDTLS_SSL_SOME_MODES_USE_MAC +#endif + +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) +/* Ciphersuites using HMAC */ +#if defined(MBEDTLS_SHA512_C) +#define MBEDTLS_SSL_MAC_ADD 48 /* SHA-384 used for HMAC */ +#elif defined(MBEDTLS_SHA256_C) +#define MBEDTLS_SSL_MAC_ADD 32 /* SHA-256 used for HMAC */ +#else +#define MBEDTLS_SSL_MAC_ADD 20 /* SHA-1 used for HMAC */ +#endif +#else /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ +/* AEAD ciphersuites: GCM and CCM use a 128 bits tag */ +#define MBEDTLS_SSL_MAC_ADD 16 +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#define MBEDTLS_SSL_PADDING_ADD 256 +#else +#define MBEDTLS_SSL_PADDING_ADD 0 +#endif + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +#define MBEDTLS_SSL_MAX_CID_EXPANSION MBEDTLS_SSL_CID_PADDING_GRANULARITY +#else +#define MBEDTLS_SSL_MAX_CID_EXPANSION 0 +#endif + +#define MBEDTLS_SSL_PAYLOAD_OVERHEAD ( MBEDTLS_SSL_COMPRESSION_ADD + \ + MBEDTLS_MAX_IV_LENGTH + \ + MBEDTLS_SSL_MAC_ADD + \ + MBEDTLS_SSL_PADDING_ADD + \ + MBEDTLS_SSL_MAX_CID_EXPANSION \ + ) + +#define MBEDTLS_SSL_IN_PAYLOAD_LEN ( MBEDTLS_SSL_PAYLOAD_OVERHEAD + \ + ( MBEDTLS_SSL_IN_CONTENT_LEN ) ) + +#define MBEDTLS_SSL_OUT_PAYLOAD_LEN ( MBEDTLS_SSL_PAYLOAD_OVERHEAD + \ + ( MBEDTLS_SSL_OUT_CONTENT_LEN ) ) + +/* The maximum number of buffered handshake messages. */ +#define MBEDTLS_SSL_MAX_BUFFERED_HS 4 + +/* Maximum length we can advertise as our max content length for + RFC 6066 max_fragment_length extension negotiation purposes + (the lesser of both sizes, if they are unequal.) + */ +#define MBEDTLS_TLS_EXT_ADV_CONTENT_LEN ( \ + (MBEDTLS_SSL_IN_CONTENT_LEN > MBEDTLS_SSL_OUT_CONTENT_LEN) \ + ? ( MBEDTLS_SSL_OUT_CONTENT_LEN ) \ + : ( MBEDTLS_SSL_IN_CONTENT_LEN ) \ + ) + +/* + * Check that we obey the standard's message size bounds + */ + +#if MBEDTLS_SSL_MAX_CONTENT_LEN > 16384 +#error "Bad configuration - record content too large." +#endif + +#if MBEDTLS_SSL_IN_CONTENT_LEN > MBEDTLS_SSL_MAX_CONTENT_LEN +#error "Bad configuration - incoming record content should not be larger than MBEDTLS_SSL_MAX_CONTENT_LEN." +#endif + +#if MBEDTLS_SSL_OUT_CONTENT_LEN > MBEDTLS_SSL_MAX_CONTENT_LEN +#error "Bad configuration - outgoing record content should not be larger than MBEDTLS_SSL_MAX_CONTENT_LEN." +#endif + +#if MBEDTLS_SSL_IN_PAYLOAD_LEN > MBEDTLS_SSL_MAX_CONTENT_LEN + 2048 +#error "Bad configuration - incoming protected record payload too large." +#endif + +#if MBEDTLS_SSL_OUT_PAYLOAD_LEN > MBEDTLS_SSL_MAX_CONTENT_LEN + 2048 +#error "Bad configuration - outgoing protected record payload too large." +#endif + +/* Calculate buffer sizes */ + +/* Note: Even though the TLS record header is only 5 bytes + long, we're internally using 8 bytes to store the + implicit sequence number. */ +#define MBEDTLS_SSL_HEADER_LEN 13 + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +#define MBEDTLS_SSL_IN_BUFFER_LEN \ + ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_IN_PAYLOAD_LEN ) ) +#else +#define MBEDTLS_SSL_IN_BUFFER_LEN \ + ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_IN_PAYLOAD_LEN ) \ + + ( MBEDTLS_SSL_CID_IN_LEN_MAX ) ) +#endif + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +#define MBEDTLS_SSL_OUT_BUFFER_LEN \ + ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_OUT_PAYLOAD_LEN ) ) +#else +#define MBEDTLS_SSL_OUT_BUFFER_LEN \ + ( ( MBEDTLS_SSL_HEADER_LEN ) + ( MBEDTLS_SSL_OUT_PAYLOAD_LEN ) \ + + ( MBEDTLS_SSL_CID_OUT_LEN_MAX ) ) +#endif + +#ifdef MBEDTLS_ZLIB_SUPPORT +/* Compression buffer holds both IN and OUT buffers, so should be size of the larger */ +#define MBEDTLS_SSL_COMPRESS_BUFFER_LEN ( \ + ( MBEDTLS_SSL_IN_BUFFER_LEN > MBEDTLS_SSL_OUT_BUFFER_LEN ) \ + ? MBEDTLS_SSL_IN_BUFFER_LEN \ + : MBEDTLS_SSL_OUT_BUFFER_LEN \ + ) +#endif + +/* + * TLS extension flags (for extensions with outgoing ServerHello content + * that need it (e.g. for RENEGOTIATION_INFO the server already knows because + * of state of the renegotiation flag, so no indicator is required) + */ +#define MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT (1 << 0) +#define MBEDTLS_TLS_EXT_ECJPAKE_KKPP_OK (1 << 1) + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +/* + * Abstraction for a grid of allowed signature-hash-algorithm pairs. + */ +struct mbedtls_ssl_sig_hash_set_t +{ + /* At the moment, we only need to remember a single suitable + * hash algorithm per signature algorithm. As long as that's + * the case - and we don't need a general lookup function - + * we can implement the sig-hash-set as a map from signatures + * to hash algorithms. */ + mbedtls_md_type_t rsa; + mbedtls_md_type_t ecdsa; +}; +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +typedef int mbedtls_ssl_tls_prf_cb( const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ); +/* + * This structure contains the parameters only needed during handshake. + */ +struct mbedtls_ssl_handshake_params +{ + /* + * Handshake specific crypto variables + */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + mbedtls_ssl_sig_hash_set_t hash_algs; /*!< Set of suitable sig-hash pairs */ +#endif +#if defined(MBEDTLS_DHM_C) + mbedtls_dhm_context dhm_ctx; /*!< DHM key exchange */ +#endif +#if defined(MBEDTLS_ECDH_C) + mbedtls_ecdh_context ecdh_ctx; /*!< ECDH key exchange */ + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_ecc_curve_t ecdh_psa_curve; + psa_key_handle_t ecdh_psa_privkey; + unsigned char ecdh_psa_peerkey[MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH]; + size_t ecdh_psa_peerkey_len; +#endif /* MBEDTLS_USE_PSA_CRYPTO */ +#endif /* MBEDTLS_ECDH_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + mbedtls_ecjpake_context ecjpake_ctx; /*!< EC J-PAKE key exchange */ +#if defined(MBEDTLS_SSL_CLI_C) + unsigned char *ecjpake_cache; /*!< Cache for ClientHello ext */ + size_t ecjpake_cache_len; /*!< Length of cached data */ +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + const mbedtls_ecp_curve_info **curves; /*!< Supported elliptic curves */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +#if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_key_handle_t psk_opaque; /*!< Opaque PSK from the callback */ +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + unsigned char *psk; /*!< PSK from the callback */ + size_t psk_len; /*!< Length of PSK from callback */ +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + mbedtls_ssl_key_cert *key_cert; /*!< chosen key/cert pair (server) */ +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + int sni_authmode; /*!< authmode from SNI callback */ + mbedtls_ssl_key_cert *sni_key_cert; /*!< key/cert list from SNI */ + mbedtls_x509_crt *sni_ca_chain; /*!< trusted CAs from SNI callback */ + mbedtls_x509_crl *sni_ca_crl; /*!< trusted CAs CRLs from SNI */ +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + int ecrs_enabled; /*!< Handshake supports EC restart? */ + mbedtls_x509_crt_restart_ctx ecrs_ctx; /*!< restart context */ + enum { /* this complements ssl->state with info on intra-state operations */ + ssl_ecrs_none = 0, /*!< nothing going on (yet) */ + ssl_ecrs_crt_verify, /*!< Certificate: crt_verify() */ + ssl_ecrs_ske_start_processing, /*!< ServerKeyExchange: pk_verify() */ + ssl_ecrs_cke_ecdh_calc_secret, /*!< ClientKeyExchange: ECDH step 2 */ + ssl_ecrs_crt_vrfy_sign, /*!< CertificateVerify: pk_sign() */ + } ecrs_state; /*!< current (or last) operation */ + mbedtls_x509_crt *ecrs_peer_cert; /*!< The peer's CRT chain. */ + size_t ecrs_n; /*!< place for saving a length */ +#endif +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + mbedtls_pk_context peer_pubkey; /*!< The public key from the peer. */ +#endif /* MBEDTLS_X509_CRT_PARSE_C && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + unsigned int out_msg_seq; /*!< Outgoing handshake sequence number */ + unsigned int in_msg_seq; /*!< Incoming handshake sequence number */ + + unsigned char *verify_cookie; /*!< Cli: HelloVerifyRequest cookie + Srv: unused */ + unsigned char verify_cookie_len; /*!< Cli: cookie length + Srv: flag for sending a cookie */ + + uint32_t retransmit_timeout; /*!< Current value of timeout */ + unsigned char retransmit_state; /*!< Retransmission state */ + mbedtls_ssl_flight_item *flight; /*!< Current outgoing flight */ + mbedtls_ssl_flight_item *cur_msg; /*!< Current message in flight */ + unsigned char *cur_msg_p; /*!< Position in current message */ + unsigned int in_flight_start_seq; /*!< Minimum message sequence in the + flight being received */ + mbedtls_ssl_transform *alt_transform_out; /*!< Alternative transform for + resending messages */ + unsigned char alt_out_ctr[8]; /*!< Alternative record epoch/counter + for resending messages */ + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + /* The state of CID configuration in this handshake. */ + + uint8_t cid_in_use; /*!< This indicates whether the use of the CID extension + * has been negotiated. Possible values are + * #MBEDTLS_SSL_CID_ENABLED and + * #MBEDTLS_SSL_CID_DISABLED. */ + unsigned char peer_cid[ MBEDTLS_SSL_CID_OUT_LEN_MAX ]; /*! The peer's CID */ + uint8_t peer_cid_len; /*!< The length of + * \c peer_cid. */ +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + + struct + { + size_t total_bytes_buffered; /*!< Cumulative size of heap allocated + * buffers used for message buffering. */ + + uint8_t seen_ccs; /*!< Indicates if a CCS message has + * been seen in the current flight. */ + + struct mbedtls_ssl_hs_buffer + { + unsigned is_valid : 1; + unsigned is_fragmented : 1; + unsigned is_complete : 1; + unsigned char *data; + size_t data_len; + } hs[MBEDTLS_SSL_MAX_BUFFERED_HS]; + + struct + { + unsigned char *data; + size_t len; + unsigned epoch; + } future_record; + + } buffering; + + uint16_t mtu; /*!< Handshake mtu, used to fragment outgoing messages */ +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + /* + * Checksum contexts + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_context fin_md5; + mbedtls_sha1_context fin_sha1; +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_hash_operation_t fin_sha256_psa; +#else + mbedtls_sha256_context fin_sha256; +#endif +#endif +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_hash_operation_t fin_sha384_psa; +#else + mbedtls_sha512_context fin_sha512; +#endif +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + void (*update_checksum)(mbedtls_ssl_context *, const unsigned char *, size_t); + void (*calc_verify)(mbedtls_ssl_context *, unsigned char *); + void (*calc_finished)(mbedtls_ssl_context *, unsigned char *, int); + mbedtls_ssl_tls_prf_cb *tls_prf; + + mbedtls_ssl_ciphersuite_t const *ciphersuite_info; + + size_t pmslen; /*!< premaster length */ + + unsigned char randbytes[64]; /*!< random bytes */ + unsigned char premaster[MBEDTLS_PREMASTER_SIZE]; + /*!< premaster secret */ + + int resume; /*!< session resume indicator*/ + int max_major_ver; /*!< max. major version client*/ + int max_minor_ver; /*!< max. minor version client*/ + int cli_exts; /*!< client extension presence*/ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + int new_session_ticket; /*!< use NewSessionTicket? */ +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + int extended_ms; /*!< use Extended Master Secret? */ +#endif + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + unsigned int async_in_progress : 1; /*!< an asynchronous operation is in progress */ +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + /** Asynchronous operation context. This field is meant for use by the + * asynchronous operation callbacks (mbedtls_ssl_config::f_async_sign_start, + * mbedtls_ssl_config::f_async_decrypt_start, + * mbedtls_ssl_config::f_async_resume, mbedtls_ssl_config::f_async_cancel). + * The library does not use it internally. */ + void *user_async_ctx; +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ +}; + +typedef struct mbedtls_ssl_hs_buffer mbedtls_ssl_hs_buffer; + +/* + * Representation of decryption/encryption transformations on records + * + * There are the following general types of record transformations: + * - Stream transformations (TLS versions <= 1.2 only) + * Transformation adding a MAC and applying a stream-cipher + * to the authenticated message. + * - CBC block cipher transformations ([D]TLS versions <= 1.2 only) + * In addition to the distinction of the order of encryption and + * authentication, there's a fundamental difference between the + * handling in SSL3 & TLS 1.0 and TLS 1.1 and TLS 1.2: For SSL3 + * and TLS 1.0, the final IV after processing a record is used + * as the IV for the next record. No explicit IV is contained + * in an encrypted record. The IV for the first record is extracted + * at key extraction time. In contrast, for TLS 1.1 and 1.2, no + * IV is generated at key extraction time, but every encrypted + * record is explicitly prefixed by the IV with which it was encrypted. + * - AEAD transformations ([D]TLS versions >= 1.2 only) + * These come in two fundamentally different versions, the first one + * used in TLS 1.2, excluding ChaChaPoly ciphersuites, and the second + * one used for ChaChaPoly ciphersuites in TLS 1.2 as well as for TLS 1.3. + * In the first transformation, the IV to be used for a record is obtained + * as the concatenation of an explicit, static 4-byte IV and the 8-byte + * record sequence number, and explicitly prepending this sequence number + * to the encrypted record. In contrast, in the second transformation + * the IV is obtained by XOR'ing a static IV obtained at key extraction + * time with the 8-byte record sequence number, without prepending the + * latter to the encrypted record. + * + * In addition to type and version, the following parameters are relevant: + * - The symmetric cipher algorithm to be used. + * - The (static) encryption/decryption keys for the cipher. + * - For stream/CBC, the type of message digest to be used. + * - For stream/CBC, (static) encryption/decryption keys for the digest. + * - For AEAD transformations, the size (potentially 0) of an explicit, + * random initialization vector placed in encrypted records. + * - For some transformations (currently AEAD and CBC in SSL3 and TLS 1.0) + * an implicit IV. It may be static (e.g. AEAD) or dynamic (e.g. CBC) + * and (if present) is combined with the explicit IV in a transformation- + * dependent way (e.g. appending in TLS 1.2 and XOR'ing in TLS 1.3). + * - For stream/CBC, a flag determining the order of encryption and MAC. + * - The details of the transformation depend on the SSL/TLS version. + * - The length of the authentication tag. + * + * Note: Except for CBC in SSL3 and TLS 1.0, these parameters are + * constant across multiple encryption/decryption operations. + * For CBC, the implicit IV needs to be updated after each + * operation. + * + * The struct below refines this abstract view as follows: + * - The cipher underlying the transformation is managed in + * cipher contexts cipher_ctx_{enc/dec}, which must have the + * same cipher type. The mode of these cipher contexts determines + * the type of the transformation in the sense above: e.g., if + * the type is MBEDTLS_CIPHER_AES_256_CBC resp. MBEDTLS_CIPHER_AES_192_GCM + * then the transformation has type CBC resp. AEAD. + * - The cipher keys are never stored explicitly but + * are maintained within cipher_ctx_{enc/dec}. + * - For stream/CBC transformations, the message digest contexts + * used for the MAC's are stored in md_ctx_{enc/dec}. These contexts + * are unused for AEAD transformations. + * - For stream/CBC transformations and versions > SSL3, the + * MAC keys are not stored explicitly but maintained within + * md_ctx_{enc/dec}. + * - For stream/CBC transformations and version SSL3, the MAC + * keys are stored explicitly in mac_enc, mac_dec and have + * a fixed size of 20 bytes. These fields are unused for + * AEAD transformations or transformations >= TLS 1.0. + * - For transformations using an implicit IV maintained within + * the transformation context, its contents are stored within + * iv_{enc/dec}. + * - The value of ivlen indicates the length of the IV. + * This is redundant in case of stream/CBC transformations + * which always use 0 resp. the cipher's block length as the + * IV length, but is needed for AEAD ciphers and may be + * different from the underlying cipher's block length + * in this case. + * - The field fixed_ivlen is nonzero for AEAD transformations only + * and indicates the length of the static part of the IV which is + * constant throughout the communication, and which is stored in + * the first fixed_ivlen bytes of the iv_{enc/dec} arrays. + * Note: For CBC in SSL3 and TLS 1.0, the fields iv_{enc/dec} + * still store IV's for continued use across multiple transformations, + * so it is not true that fixed_ivlen == 0 means that iv_{enc/dec} are + * not being used! + * - minor_ver denotes the SSL/TLS version + * - For stream/CBC transformations, maclen denotes the length of the + * authentication tag, while taglen is unused and 0. + * - For AEAD transformations, taglen denotes the length of the + * authentication tag, while maclen is unused and 0. + * - For CBC transformations, encrypt_then_mac determines the + * order of encryption and authentication. This field is unused + * in other transformations. + * + */ +struct mbedtls_ssl_transform +{ + /* + * Session specific crypto layer + */ + size_t minlen; /*!< min. ciphertext length */ + size_t ivlen; /*!< IV length */ + size_t fixed_ivlen; /*!< Fixed part of IV (AEAD) */ + size_t maclen; /*!< MAC(CBC) len */ + size_t taglen; /*!< TAG(AEAD) len */ + + unsigned char iv_enc[16]; /*!< IV (encryption) */ + unsigned char iv_dec[16]; /*!< IV (decryption) */ + +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + /* Needed only for SSL v3.0 secret */ + unsigned char mac_enc[20]; /*!< SSL v3.0 secret (enc) */ + unsigned char mac_dec[20]; /*!< SSL v3.0 secret (dec) */ +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + + mbedtls_md_context_t md_ctx_enc; /*!< MAC (encryption) */ + mbedtls_md_context_t md_ctx_dec; /*!< MAC (decryption) */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + int encrypt_then_mac; /*!< flag for EtM activation */ +#endif + +#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ + + mbedtls_cipher_context_t cipher_ctx_enc; /*!< encryption context */ + mbedtls_cipher_context_t cipher_ctx_dec; /*!< decryption context */ + int minor_ver; + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + uint8_t in_cid_len; + uint8_t out_cid_len; + unsigned char in_cid [ MBEDTLS_SSL_CID_OUT_LEN_MAX ]; + unsigned char out_cid[ MBEDTLS_SSL_CID_OUT_LEN_MAX ]; +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + + /* + * Session specific compression layer + */ +#if defined(MBEDTLS_ZLIB_SUPPORT) + z_stream ctx_deflate; /*!< compression context */ + z_stream ctx_inflate; /*!< decompression context */ +#endif +}; + +/* + * Internal representation of record frames + * + * Instances come in two flavors: + * (1) Encrypted + * These always have data_offset = 0 + * (2) Unencrypted + * These have data_offset set to the amount of + * pre-expansion during record protection. Concretely, + * this is the length of the fixed part of the explicit IV + * used for encryption, or 0 if no explicit IV is used + * (e.g. for CBC in TLS 1.0, or stream ciphers). + * + * The reason for the data_offset in the unencrypted case + * is to allow for in-place conversion of an unencrypted to + * an encrypted record. If the offset wasn't included, the + * encrypted content would need to be shifted afterwards to + * make space for the fixed IV. + * + */ +#if MBEDTLS_SSL_CID_OUT_LEN_MAX > MBEDTLS_SSL_CID_IN_LEN_MAX +#define MBEDTLS_SSL_CID_LEN_MAX MBEDTLS_SSL_CID_OUT_LEN_MAX +#else +#define MBEDTLS_SSL_CID_LEN_MAX MBEDTLS_SSL_CID_IN_LEN_MAX +#endif + +typedef struct +{ + uint8_t ctr[8]; /* Record sequence number */ + uint8_t type; /* Record type */ + uint8_t ver[2]; /* SSL/TLS version */ + + unsigned char *buf; /* Memory buffer enclosing the record content */ + size_t buf_len; /* Buffer length */ + size_t data_offset; /* Offset of record content */ + size_t data_len; /* Length of record content */ + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + uint8_t cid_len; /* Length of the CID (0 if not present) */ + unsigned char cid[ MBEDTLS_SSL_CID_LEN_MAX ]; /* The CID */ +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ +} mbedtls_record; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/* + * List of certificate + private key pairs + */ +struct mbedtls_ssl_key_cert +{ + mbedtls_x509_crt *cert; /*!< cert */ + mbedtls_pk_context *key; /*!< private key */ + mbedtls_ssl_key_cert *next; /*!< next key/cert pair */ +}; +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +/* + * List of handshake messages kept around for resending + */ +struct mbedtls_ssl_flight_item +{ + unsigned char *p; /*!< message, including handshake headers */ + size_t len; /*!< length of p */ + unsigned char type; /*!< type of the message: handshake or CCS */ + mbedtls_ssl_flight_item *next; /*!< next handshake message(s) */ +}; +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + +/* Find an entry in a signature-hash set matching a given hash algorithm. */ +mbedtls_md_type_t mbedtls_ssl_sig_hash_set_find( mbedtls_ssl_sig_hash_set_t *set, + mbedtls_pk_type_t sig_alg ); +/* Add a signature-hash-pair to a signature-hash set */ +void mbedtls_ssl_sig_hash_set_add( mbedtls_ssl_sig_hash_set_t *set, + mbedtls_pk_type_t sig_alg, + mbedtls_md_type_t md_alg ); +/* Allow exactly one hash algorithm for each signature. */ +void mbedtls_ssl_sig_hash_set_const_hash( mbedtls_ssl_sig_hash_set_t *set, + mbedtls_md_type_t md_alg ); + +/* Setup an empty signature-hash set */ +static inline void mbedtls_ssl_sig_hash_set_init( mbedtls_ssl_sig_hash_set_t *set ) +{ + mbedtls_ssl_sig_hash_set_const_hash( set, MBEDTLS_MD_NONE ); +} + +#endif /* MBEDTLS_SSL_PROTO_TLS1_2) && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +/** + * \brief Free referenced items in an SSL transform context and clear + * memory + * + * \param transform SSL transform context + */ +void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ); + +/** + * \brief Free referenced items in an SSL handshake context and clear + * memory + * + * \param ssl SSL context + */ +void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl ); +void mbedtls_ssl_handshake_wrapup( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_send_fatal_handshake_failure( mbedtls_ssl_context *ssl ); + +void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ); +void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl ); + +/** + * \brief Update record layer + * + * This function roughly separates the implementation + * of the logic of (D)TLS from the implementation + * of the secure transport. + * + * \param ssl The SSL context to use. + * \param update_hs_digest This indicates if the handshake digest + * should be automatically updated in case + * a handshake message is found. + * + * \return 0 or non-zero error code. + * + * \note A clarification on what is called 'record layer' here + * is in order, as many sensible definitions are possible: + * + * The record layer takes as input an untrusted underlying + * transport (stream or datagram) and transforms it into + * a serially multiplexed, secure transport, which + * conceptually provides the following: + * + * (1) Three datagram based, content-agnostic transports + * for handshake, alert and CCS messages. + * (2) One stream- or datagram-based transport + * for application data. + * (3) Functionality for changing the underlying transform + * securing the contents. + * + * The interface to this functionality is given as follows: + * + * a Updating + * [Currently implemented by mbedtls_ssl_read_record] + * + * Check if and on which of the four 'ports' data is pending: + * Nothing, a controlling datagram of type (1), or application + * data (2). In any case data is present, internal buffers + * provide access to the data for the user to process it. + * Consumption of type (1) datagrams is done automatically + * on the next update, invalidating that the internal buffers + * for previous datagrams, while consumption of application + * data (2) is user-controlled. + * + * b Reading of application data + * [Currently manual adaption of ssl->in_offt pointer] + * + * As mentioned in the last paragraph, consumption of data + * is different from the automatic consumption of control + * datagrams (1) because application data is treated as a stream. + * + * c Tracking availability of application data + * [Currently manually through decreasing ssl->in_msglen] + * + * For efficiency and to retain datagram semantics for + * application data in case of DTLS, the record layer + * provides functionality for checking how much application + * data is still available in the internal buffer. + * + * d Changing the transformation securing the communication. + * + * Given an opaque implementation of the record layer in the + * above sense, it should be possible to implement the logic + * of (D)TLS on top of it without the need to know anything + * about the record layer's internals. This is done e.g. + * in all the handshake handling functions, and in the + * application data reading function mbedtls_ssl_read. + * + * \note The above tries to give a conceptual picture of the + * record layer, but the current implementation deviates + * from it in some places. For example, our implementation of + * the update functionality through mbedtls_ssl_read_record + * discards datagrams depending on the current state, which + * wouldn't fall under the record layer's responsibility + * following the above definition. + * + */ +int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl, + unsigned update_hs_digest ); +int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ); + +int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ); +int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl ); + +void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, + const mbedtls_ssl_ciphersuite_t *ciphersuite_info ); + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exchange_type_t key_ex ); +#endif + +#if defined(MBEDTLS_PK_C) +unsigned char mbedtls_ssl_sig_from_pk( mbedtls_pk_context *pk ); +unsigned char mbedtls_ssl_sig_from_pk_alg( mbedtls_pk_type_t type ); +mbedtls_pk_type_t mbedtls_ssl_pk_alg_from_sig( unsigned char sig ); +#endif + +mbedtls_md_type_t mbedtls_ssl_md_alg_from_hash( unsigned char hash ); +unsigned char mbedtls_ssl_hash_from_md_alg( int md ); +int mbedtls_ssl_set_calc_verify_md( mbedtls_ssl_context *ssl, int md ); + +#if defined(MBEDTLS_ECP_C) +int mbedtls_ssl_check_curve( const mbedtls_ssl_context *ssl, mbedtls_ecp_group_id grp_id ); +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl, + mbedtls_md_type_t md ); +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +static inline mbedtls_pk_context *mbedtls_ssl_own_key( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_key_cert *key_cert; + + if( ssl->handshake != NULL && ssl->handshake->key_cert != NULL ) + key_cert = ssl->handshake->key_cert; + else + key_cert = ssl->conf->key_cert; + + return( key_cert == NULL ? NULL : key_cert->key ); +} + +static inline mbedtls_x509_crt *mbedtls_ssl_own_cert( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_key_cert *key_cert; + + if( ssl->handshake != NULL && ssl->handshake->key_cert != NULL ) + key_cert = ssl->handshake->key_cert; + else + key_cert = ssl->conf->key_cert; + + return( key_cert == NULL ? NULL : key_cert->cert ); +} + +/* + * Check usage of a certificate wrt extensions: + * keyUsage, extendedKeyUsage (later), and nSCertType (later). + * + * Warning: cert_endpoint is the endpoint of the cert (ie, of our peer when we + * check a cert we received from them)! + * + * Return 0 if everything is OK, -1 if not. + */ +int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, + const mbedtls_ssl_ciphersuite_t *ciphersuite, + int cert_endpoint, + uint32_t *flags ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +void mbedtls_ssl_write_version( int major, int minor, int transport, + unsigned char ver[2] ); +void mbedtls_ssl_read_version( int *major, int *minor, int transport, + const unsigned char ver[2] ); + +static inline size_t mbedtls_ssl_in_hdr_len( const mbedtls_ssl_context *ssl ) +{ + return( (size_t) ( ssl->in_iv - ssl->in_hdr ) ); +} + +static inline size_t mbedtls_ssl_out_hdr_len( const mbedtls_ssl_context *ssl ) +{ + return( (size_t) ( ssl->out_iv - ssl->out_hdr ) ); +} + +static inline size_t mbedtls_ssl_hs_hdr_len( const mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( 12 ); +#else + ((void) ssl); +#endif + return( 4 ); +} + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ); +void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl ); +#endif + +/* Visible for testing purposes only */ +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +int mbedtls_ssl_dtls_replay_check( mbedtls_ssl_context *ssl ); +void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl ); +#endif + +int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst, + const mbedtls_ssl_session *src ); + +/* constant-time buffer comparison */ +static inline int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ) +{ + size_t i; + volatile const unsigned char *A = (volatile const unsigned char *) a; + volatile const unsigned char *B = (volatile const unsigned char *) b; + volatile unsigned char diff = 0; + + for( i = 0; i < n; i++ ) + { + /* Read volatile data in order before computing diff. + * This avoids IAR compiler warning: + * 'the order of volatile accesses is undefined ..' */ + unsigned char x = A[i], y = B[i]; + diff |= x ^ y; + } + + return( diff ); +} + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) +int mbedtls_ssl_get_key_exchange_md_ssl_tls( mbedtls_ssl_context *ssl, + unsigned char *output, + unsigned char *data, size_t data_len ); +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || \ + MBEDTLS_SSL_PROTO_TLS1_1 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) +/* The hash buffer must have at least MBEDTLS_MD_MAX_SIZE bytes of length. */ +int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl, + unsigned char *hash, size_t *hashlen, + unsigned char *data, size_t data_len, + mbedtls_md_type_t md_alg ); +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + +#ifdef __cplusplus +} +#endif + +void mbedtls_ssl_transform_init( mbedtls_ssl_transform *transform ); +int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform, + mbedtls_record *rec, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform, + mbedtls_record *rec ); + +#endif /* ssl_internal.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_ticket.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_ticket.h new file mode 100644 index 000000000..4bf6b8c2c --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/ssl_ticket.h @@ -0,0 +1,142 @@ +/** + * \file ssl_ticket.h + * + * \brief TLS server ticket callbacks implementation + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_TICKET_H +#define MBEDTLS_SSL_TICKET_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/* + * This implementation of the session ticket callbacks includes key + * management, rotating the keys periodically in order to preserve forward + * secrecy, when MBEDTLS_HAVE_TIME is defined. + */ + +#include "ssl.h" +#include "cipher.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Information for session ticket protection + */ +typedef struct mbedtls_ssl_ticket_key +{ + unsigned char name[4]; /*!< random key identifier */ + uint32_t generation_time; /*!< key generation timestamp (seconds) */ + mbedtls_cipher_context_t ctx; /*!< context for auth enc/decryption */ +} +mbedtls_ssl_ticket_key; + +/** + * \brief Context for session ticket handling functions + */ +typedef struct mbedtls_ssl_ticket_context +{ + mbedtls_ssl_ticket_key keys[2]; /*!< ticket protection keys */ + unsigned char active; /*!< index of the currently active key */ + + uint32_t ticket_lifetime; /*!< lifetime of tickets in seconds */ + + /** Callback for getting (pseudo-)random numbers */ + int (*f_rng)(void *, unsigned char *, size_t); + void *p_rng; /*!< context for the RNG function */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} +mbedtls_ssl_ticket_context; + +/** + * \brief Initialize a ticket context. + * (Just make it ready for mbedtls_ssl_ticket_setup() + * or mbedtls_ssl_ticket_free().) + * + * \param ctx Context to be initialized + */ +void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx ); + +/** + * \brief Prepare context to be actually used + * + * \param ctx Context to be set up + * \param f_rng RNG callback function + * \param p_rng RNG callback context + * \param cipher AEAD cipher to use for ticket protection. + * Recommended value: MBEDTLS_CIPHER_AES_256_GCM. + * \param lifetime Tickets lifetime in seconds + * Recommended value: 86400 (one day). + * + * \note It is highly recommended to select a cipher that is at + * least as strong as the the strongest ciphersuite + * supported. Usually that means a 256-bit key. + * + * \note The lifetime of the keys is twice the lifetime of tickets. + * It is recommended to pick a reasonnable lifetime so as not + * to negate the benefits of forward secrecy. + * + * \return 0 if successful, + * or a specific MBEDTLS_ERR_XXX error code + */ +int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_cipher_type_t cipher, + uint32_t lifetime ); + +/** + * \brief Implementation of the ticket write callback + * + * \note See \c mbedtls_ssl_ticket_write_t for description + */ +mbedtls_ssl_ticket_write_t mbedtls_ssl_ticket_write; + +/** + * \brief Implementation of the ticket parse callback + * + * \note See \c mbedtls_ssl_ticket_parse_t for description + */ +mbedtls_ssl_ticket_parse_t mbedtls_ssl_ticket_parse; + +/** + * \brief Free a context's content and zeroize it. + * + * \param ctx Context to be cleaned up + */ +void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_ticket.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/threading.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/threading.h new file mode 100644 index 000000000..c0475e9f0 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/threading.h @@ -0,0 +1,122 @@ +/** + * \file threading.h + * + * \brief Threading abstraction layer + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_THREADING_H +#define MBEDTLS_THREADING_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE is deprecated and should not be + * used. */ +#define MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE -0x001A /**< The selected feature is not available. */ + +#define MBEDTLS_ERR_THREADING_BAD_INPUT_DATA -0x001C /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_THREADING_MUTEX_ERROR -0x001E /**< Locking / unlocking / free failed with error code. */ + +#if defined(MBEDTLS_THREADING_PTHREAD) +#include +typedef struct mbedtls_threading_mutex_t +{ + pthread_mutex_t mutex; + char is_valid; +} mbedtls_threading_mutex_t; +#endif + +#if defined(MBEDTLS_THREADING_ALT) +/* You should define the mbedtls_threading_mutex_t type in your header */ +#include "threading_alt.h" + +/** + * \brief Set your alternate threading implementation function + * pointers and initialize global mutexes. If used, this + * function must be called once in the main thread before any + * other mbed TLS function is called, and + * mbedtls_threading_free_alt() must be called once in the main + * thread after all other mbed TLS functions. + * + * \note mutex_init() and mutex_free() don't return a status code. + * If mutex_init() fails, it should leave its argument (the + * mutex) in a state such that mutex_lock() will fail when + * called with this argument. + * + * \param mutex_init the init function implementation + * \param mutex_free the free function implementation + * \param mutex_lock the lock function implementation + * \param mutex_unlock the unlock function implementation + */ +void mbedtls_threading_set_alt( void (*mutex_init)( mbedtls_threading_mutex_t * ), + void (*mutex_free)( mbedtls_threading_mutex_t * ), + int (*mutex_lock)( mbedtls_threading_mutex_t * ), + int (*mutex_unlock)( mbedtls_threading_mutex_t * ) ); + +/** + * \brief Free global mutexes. + */ +void mbedtls_threading_free_alt( void ); +#endif /* MBEDTLS_THREADING_ALT */ + +#if defined(MBEDTLS_THREADING_C) +/* + * The function pointers for mutex_init, mutex_free, mutex_ and mutex_unlock + * + * All these functions are expected to work or the result will be undefined. + */ +extern void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t *mutex ); +extern void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t *mutex ); +extern int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t *mutex ); +extern int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t *mutex ); + +/* + * Global mutexes + */ +#if defined(MBEDTLS_FS_IO) +extern mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex; +#endif + +#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT) +/* This mutex may or may not be used in the default definition of + * mbedtls_platform_gmtime_r(), but in order to determine that, + * we need to check POSIX features, hence modify _POSIX_C_SOURCE. + * With the current approach, this declaration is orphaned, lacking + * an accompanying definition, in case mbedtls_platform_gmtime_r() + * doesn't need it, but that's not a problem. */ +extern mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex; +#endif /* MBEDTLS_HAVE_TIME_DATE && !MBEDTLS_PLATFORM_GMTIME_R_ALT */ + +#endif /* MBEDTLS_THREADING_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* threading.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/timing.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/timing.h new file mode 100644 index 000000000..26bd9f43d --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/timing.h @@ -0,0 +1,153 @@ +/** + * \file timing.h + * + * \brief Portable interface to timeouts and to the CPU cycle counter + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_TIMING_H +#define MBEDTLS_TIMING_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_TIMING_ALT) +// Regular implementation +// + +/** + * \brief timer structure + */ +struct mbedtls_timing_hr_time +{ + unsigned char opaque[32]; +}; + +/** + * \brief Context for mbedtls_timing_set/get_delay() + */ +typedef struct mbedtls_timing_delay_context +{ + struct mbedtls_timing_hr_time timer; + uint32_t int_ms; + uint32_t fin_ms; +} mbedtls_timing_delay_context; + +#else /* MBEDTLS_TIMING_ALT */ +#include "timing_alt.h" +#endif /* MBEDTLS_TIMING_ALT */ + +extern volatile int mbedtls_timing_alarmed; + +/** + * \brief Return the CPU cycle counter value + * + * \warning This is only a best effort! Do not rely on this! + * In particular, it is known to be unreliable on virtual + * machines. + * + * \note This value starts at an unspecified origin and + * may wrap around. + */ +unsigned long mbedtls_timing_hardclock( void ); + +/** + * \brief Return the elapsed time in milliseconds + * + * \param val points to a timer structure + * \param reset If 0, query the elapsed time. Otherwise (re)start the timer. + * + * \return Elapsed time since the previous reset in ms. When + * restarting, this is always 0. + * + * \note To initialize a timer, call this function with reset=1. + * + * Determining the elapsed time and resetting the timer is not + * atomic on all platforms, so after the sequence + * `{ get_timer(1); ...; time1 = get_timer(1); ...; time2 = + * get_timer(0) }` the value time1+time2 is only approximately + * the delay since the first reset. + */ +unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ); + +/** + * \brief Setup an alarm clock + * + * \param seconds delay before the "mbedtls_timing_alarmed" flag is set + * (must be >=0) + * + * \warning Only one alarm at a time is supported. In a threaded + * context, this means one for the whole process, not one per + * thread. + */ +void mbedtls_set_alarm( int seconds ); + +/** + * \brief Set a pair of delays to watch + * (See \c mbedtls_timing_get_delay().) + * + * \param data Pointer to timing data. + * Must point to a valid \c mbedtls_timing_delay_context struct. + * \param int_ms First (intermediate) delay in milliseconds. + * The effect if int_ms > fin_ms is unspecified. + * \param fin_ms Second (final) delay in milliseconds. + * Pass 0 to cancel the current delay. + * + * \note To set a single delay, either use \c mbedtls_timing_set_timer + * directly or use this function with int_ms == fin_ms. + */ +void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ); + +/** + * \brief Get the status of delays + * (Memory helper: number of delays passed.) + * + * \param data Pointer to timing data + * Must point to a valid \c mbedtls_timing_delay_context struct. + * + * \return -1 if cancelled (fin_ms = 0), + * 0 if none of the delays are passed, + * 1 if only the intermediate delay is passed, + * 2 if the final delay is passed. + */ +int mbedtls_timing_get_delay( void *data ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_timing_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* timing.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/version.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/version.h new file mode 100644 index 000000000..d794fa5f2 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/version.h @@ -0,0 +1,112 @@ +/** + * \file version.h + * + * \brief Run-time version information + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * This set of compile-time defines and run-time variables can be used to + * determine the version number of the mbed TLS library used. + */ +#ifndef MBEDTLS_VERSION_H +#define MBEDTLS_VERSION_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/** + * The version number x.y.z is split into three parts. + * Major, Minor, Patchlevel + */ +#define MBEDTLS_VERSION_MAJOR 2 +#define MBEDTLS_VERSION_MINOR 18 +#define MBEDTLS_VERSION_PATCH 0 + +/** + * The single version number has the following structure: + * MMNNPP00 + * Major version | Minor version | Patch version + */ +#define MBEDTLS_VERSION_NUMBER 0x02120000 +#define MBEDTLS_VERSION_STRING "2.18.0" +#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.18.0" + +#if defined(MBEDTLS_VERSION_C) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get the version number. + * + * \return The constructed version number in the format + * MMNNPP00 (Major, Minor, Patch). + */ +unsigned int mbedtls_version_get_number( void ); + +/** + * Get the version string ("x.y.z"). + * + * \param string The string that will receive the value. + * (Should be at least 9 bytes in size) + */ +void mbedtls_version_get_string( char *string ); + +/** + * Get the full version string ("mbed TLS x.y.z"). + * + * \param string The string that will receive the value. The mbed TLS version + * string will use 18 bytes AT MOST including a terminating + * null byte. + * (So the buffer should be at least 18 bytes to receive this + * version string). + */ +void mbedtls_version_get_string_full( char *string ); + +/** + * \brief Check if support for a feature was compiled into this + * mbed TLS binary. This allows you to see at runtime if the + * library was for instance compiled with or without + * Multi-threading support. + * + * \note only checks against defines in the sections "System + * support", "mbed TLS modules" and "mbed TLS feature + * support" in config.h + * + * \param feature The string for the define to check (e.g. "MBEDTLS_AES_C") + * + * \return 0 if the feature is present, + * -1 if the feature is not present and + * -2 if support for feature checking as a whole was not + * compiled in. + */ +int mbedtls_version_check_feature( const char *feature ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_VERSION_C */ + +#endif /* version.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509.h new file mode 100644 index 000000000..9e78eb6ad --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509.h @@ -0,0 +1,361 @@ +/** + * \file x509.h + * + * \brief X.509 generic defines and structures + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_H +#define MBEDTLS_X509_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "asn1.h" +#include "pk.h" + +#if defined(MBEDTLS_RSA_C) +#include "rsa.h" +#endif + +/** + * \addtogroup x509_module + * \{ + */ + +#if !defined(MBEDTLS_X509_MAX_INTERMEDIATE_CA) +/** + * Maximum number of intermediate CAs in a verification chain. + * That is, maximum length of the chain, excluding the end-entity certificate + * and the trusted root certificate. + * + * Set this to a low value to prevent an adversary from making you waste + * resources verifying an overlong certificate chain. + */ +#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 +#endif + +/** + * \name X509 Error codes + * \{ + */ +#define MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE -0x2080 /**< Unavailable feature, e.g. RSA hashing/encryption combination. */ +#define MBEDTLS_ERR_X509_UNKNOWN_OID -0x2100 /**< Requested OID is unknown. */ +#define MBEDTLS_ERR_X509_INVALID_FORMAT -0x2180 /**< The CRT/CRL/CSR format is invalid, e.g. different type expected. */ +#define MBEDTLS_ERR_X509_INVALID_VERSION -0x2200 /**< The CRT/CRL/CSR version element is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_SERIAL -0x2280 /**< The serial tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_ALG -0x2300 /**< The algorithm tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_NAME -0x2380 /**< The name tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_DATE -0x2400 /**< The date tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_SIGNATURE -0x2480 /**< The signature tag or value invalid. */ +#define MBEDTLS_ERR_X509_INVALID_EXTENSIONS -0x2500 /**< The extension tag or value is invalid. */ +#define MBEDTLS_ERR_X509_UNKNOWN_VERSION -0x2580 /**< CRT/CRL/CSR has an unsupported version number. */ +#define MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG -0x2600 /**< Signature algorithm (oid) is unsupported. */ +#define MBEDTLS_ERR_X509_SIG_MISMATCH -0x2680 /**< Signature algorithms do not match. (see \c ::mbedtls_x509_crt sig_oid) */ +#define MBEDTLS_ERR_X509_CERT_VERIFY_FAILED -0x2700 /**< Certificate verification failed, e.g. CRL, CA or signature check failed. */ +#define MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT -0x2780 /**< Format not recognized as DER or PEM. */ +#define MBEDTLS_ERR_X509_BAD_INPUT_DATA -0x2800 /**< Input invalid. */ +#define MBEDTLS_ERR_X509_ALLOC_FAILED -0x2880 /**< Allocation of memory failed. */ +#define MBEDTLS_ERR_X509_FILE_IO_ERROR -0x2900 /**< Read/write of file failed. */ +#define MBEDTLS_ERR_X509_BUFFER_TOO_SMALL -0x2980 /**< Destination buffer is too small. */ +#define MBEDTLS_ERR_X509_FATAL_ERROR -0x3000 /**< A fatal error occurred, eg the chain is too long or the vrfy callback failed. */ +/* \} name */ + +/** + * \name X509 Verify codes + * \{ + */ +/* Reminder: update x509_crt_verify_strings[] in library/x509_crt.c */ +#define MBEDTLS_X509_BADCERT_EXPIRED 0x01 /**< The certificate validity has expired. */ +#define MBEDTLS_X509_BADCERT_REVOKED 0x02 /**< The certificate has been revoked (is on a CRL). */ +#define MBEDTLS_X509_BADCERT_CN_MISMATCH 0x04 /**< The certificate Common Name (CN) does not match with the expected CN. */ +#define MBEDTLS_X509_BADCERT_NOT_TRUSTED 0x08 /**< The certificate is not correctly signed by the trusted CA. */ +#define MBEDTLS_X509_BADCRL_NOT_TRUSTED 0x10 /**< The CRL is not correctly signed by the trusted CA. */ +#define MBEDTLS_X509_BADCRL_EXPIRED 0x20 /**< The CRL is expired. */ +#define MBEDTLS_X509_BADCERT_MISSING 0x40 /**< Certificate was missing. */ +#define MBEDTLS_X509_BADCERT_SKIP_VERIFY 0x80 /**< Certificate verification was skipped. */ +#define MBEDTLS_X509_BADCERT_OTHER 0x0100 /**< Other reason (can be used by verify callback) */ +#define MBEDTLS_X509_BADCERT_FUTURE 0x0200 /**< The certificate validity starts in the future. */ +#define MBEDTLS_X509_BADCRL_FUTURE 0x0400 /**< The CRL is from the future */ +#define MBEDTLS_X509_BADCERT_KEY_USAGE 0x0800 /**< Usage does not match the keyUsage extension. */ +#define MBEDTLS_X509_BADCERT_EXT_KEY_USAGE 0x1000 /**< Usage does not match the extendedKeyUsage extension. */ +#define MBEDTLS_X509_BADCERT_NS_CERT_TYPE 0x2000 /**< Usage does not match the nsCertType extension. */ +#define MBEDTLS_X509_BADCERT_BAD_MD 0x4000 /**< The certificate is signed with an unacceptable hash. */ +#define MBEDTLS_X509_BADCERT_BAD_PK 0x8000 /**< The certificate is signed with an unacceptable PK alg (eg RSA vs ECDSA). */ +#define MBEDTLS_X509_BADCERT_BAD_KEY 0x010000 /**< The certificate is signed with an unacceptable key (eg bad curve, RSA too short). */ +#define MBEDTLS_X509_BADCRL_BAD_MD 0x020000 /**< The CRL is signed with an unacceptable hash. */ +#define MBEDTLS_X509_BADCRL_BAD_PK 0x040000 /**< The CRL is signed with an unacceptable PK alg (eg RSA vs ECDSA). */ +#define MBEDTLS_X509_BADCRL_BAD_KEY 0x080000 /**< The CRL is signed with an unacceptable key (eg bad curve, RSA too short). */ + +/* \} name */ +/* \} addtogroup x509_module */ + +/* + * X.509 v3 Subject Alternative Name types. + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER + */ +#define MBEDTLS_X509_SAN_OTHER_NAME 0 +#define MBEDTLS_X509_SAN_RFC822_NAME 1 +#define MBEDTLS_X509_SAN_DNS_NAME 2 +#define MBEDTLS_X509_SAN_X400_ADDRESS_NAME 3 +#define MBEDTLS_X509_SAN_DIRECTORY_NAME 4 +#define MBEDTLS_X509_SAN_EDI_PARTY_NAME 5 +#define MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER 6 +#define MBEDTLS_X509_SAN_IP_ADDRESS 7 +#define MBEDTLS_X509_SAN_REGISTERED_ID 8 + +/* + * X.509 v3 Key Usage Extension flags + * Reminder: update x509_info_key_usage() when adding new flags. + */ +#define MBEDTLS_X509_KU_DIGITAL_SIGNATURE (0x80) /* bit 0 */ +#define MBEDTLS_X509_KU_NON_REPUDIATION (0x40) /* bit 1 */ +#define MBEDTLS_X509_KU_KEY_ENCIPHERMENT (0x20) /* bit 2 */ +#define MBEDTLS_X509_KU_DATA_ENCIPHERMENT (0x10) /* bit 3 */ +#define MBEDTLS_X509_KU_KEY_AGREEMENT (0x08) /* bit 4 */ +#define MBEDTLS_X509_KU_KEY_CERT_SIGN (0x04) /* bit 5 */ +#define MBEDTLS_X509_KU_CRL_SIGN (0x02) /* bit 6 */ +#define MBEDTLS_X509_KU_ENCIPHER_ONLY (0x01) /* bit 7 */ +#define MBEDTLS_X509_KU_DECIPHER_ONLY (0x8000) /* bit 8 */ + +/* + * Netscape certificate types + * (http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html) + */ + +#define MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT (0x80) /* bit 0 */ +#define MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER (0x40) /* bit 1 */ +#define MBEDTLS_X509_NS_CERT_TYPE_EMAIL (0x20) /* bit 2 */ +#define MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING (0x10) /* bit 3 */ +#define MBEDTLS_X509_NS_CERT_TYPE_RESERVED (0x08) /* bit 4 */ +#define MBEDTLS_X509_NS_CERT_TYPE_SSL_CA (0x04) /* bit 5 */ +#define MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA (0x02) /* bit 6 */ +#define MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA (0x01) /* bit 7 */ + +/* + * X.509 extension types + * + * Comments refer to the status for using certificates. Status can be + * different for writing certificates or reading CRLs or CSRs. + * + * Those are defined in oid.h as oid.c needs them in a data structure. Since + * these were previously defined here, let's have aliases for compatibility. + */ +#define MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER MBEDTLS_OID_X509_EXT_AUTHORITY_KEY_IDENTIFIER +#define MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER MBEDTLS_OID_X509_EXT_SUBJECT_KEY_IDENTIFIER +#define MBEDTLS_X509_EXT_KEY_USAGE MBEDTLS_OID_X509_EXT_KEY_USAGE +#define MBEDTLS_X509_EXT_CERTIFICATE_POLICIES MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES +#define MBEDTLS_X509_EXT_POLICY_MAPPINGS MBEDTLS_OID_X509_EXT_POLICY_MAPPINGS +#define MBEDTLS_X509_EXT_SUBJECT_ALT_NAME MBEDTLS_OID_X509_EXT_SUBJECT_ALT_NAME /* Supported (DNS) */ +#define MBEDTLS_X509_EXT_ISSUER_ALT_NAME MBEDTLS_OID_X509_EXT_ISSUER_ALT_NAME +#define MBEDTLS_X509_EXT_SUBJECT_DIRECTORY_ATTRS MBEDTLS_OID_X509_EXT_SUBJECT_DIRECTORY_ATTRS +#define MBEDTLS_X509_EXT_BASIC_CONSTRAINTS MBEDTLS_OID_X509_EXT_BASIC_CONSTRAINTS /* Supported */ +#define MBEDTLS_X509_EXT_NAME_CONSTRAINTS MBEDTLS_OID_X509_EXT_NAME_CONSTRAINTS +#define MBEDTLS_X509_EXT_POLICY_CONSTRAINTS MBEDTLS_OID_X509_EXT_POLICY_CONSTRAINTS +#define MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE MBEDTLS_OID_X509_EXT_EXTENDED_KEY_USAGE +#define MBEDTLS_X509_EXT_CRL_DISTRIBUTION_POINTS MBEDTLS_OID_X509_EXT_CRL_DISTRIBUTION_POINTS +#define MBEDTLS_X509_EXT_INIHIBIT_ANYPOLICY MBEDTLS_OID_X509_EXT_INIHIBIT_ANYPOLICY +#define MBEDTLS_X509_EXT_FRESHEST_CRL MBEDTLS_OID_X509_EXT_FRESHEST_CRL +#define MBEDTLS_X509_EXT_NS_CERT_TYPE MBEDTLS_OID_X509_EXT_NS_CERT_TYPE + +/* + * Storage format identifiers + * Recognized formats: PEM and DER + */ +#define MBEDTLS_X509_FORMAT_DER 1 +#define MBEDTLS_X509_FORMAT_PEM 2 + +#define MBEDTLS_X509_MAX_DN_NAME_SIZE 256 /**< Maximum value size of a DN entry */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures for parsing X.509 certificates, CRLs and CSRs + * \{ + */ + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef mbedtls_asn1_buf mbedtls_x509_buf; + +/** + * Container for ASN1 bit strings. + */ +typedef mbedtls_asn1_bitstring mbedtls_x509_bitstring; + +/** + * Container for ASN1 named information objects. + * It allows for Relative Distinguished Names (e.g. cn=localhost,ou=code,etc.). + */ +typedef mbedtls_asn1_named_data mbedtls_x509_name; + +/** + * Container for a sequence of ASN.1 items + */ +typedef mbedtls_asn1_sequence mbedtls_x509_sequence; + +/** Container for date and time (precision in seconds). */ +typedef struct mbedtls_x509_time +{ + int year, mon, day; /**< Date. */ + int hour, min, sec; /**< Time. */ +} +mbedtls_x509_time; + +/** \} name Structures for parsing X.509 certificates, CRLs and CSRs */ +/** \} addtogroup x509_module */ + +/** + * \brief Store the certificate DN in printable form into buf; + * no more than size characters will be written. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param dn The X509 name to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_dn_gets( char *buf, size_t size, const mbedtls_x509_name *dn ); + +/** + * \brief Store the certificate serial in printable form into buf; + * no more than size characters will be written. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param serial The X509 serial to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_serial_gets( char *buf, size_t size, const mbedtls_x509_buf *serial ); + +/** + * \brief Check a given mbedtls_x509_time against the system time + * and tell if it's in the past. + * + * \note Intended usage is "if( is_past( valid_to ) ) ERROR". + * Hence the return value of 1 if on internal errors. + * + * \param to mbedtls_x509_time to check + * + * \return 1 if the given time is in the past or an error occurred, + * 0 otherwise. + */ +int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ); + +/** + * \brief Check a given mbedtls_x509_time against the system time + * and tell if it's in the future. + * + * \note Intended usage is "if( is_future( valid_from ) ) ERROR". + * Hence the return value of 1 if on internal errors. + * + * \param from mbedtls_x509_time to check + * + * \return 1 if the given time is in the future or an error occurred, + * 0 otherwise. + */ +int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_x509_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +/* + * Internal module functions. You probably do not want to use these unless you + * know you do. + */ +int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, + mbedtls_x509_name *cur ); +int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg ); +int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg, mbedtls_x509_buf *params ); +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) +int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, + mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md, + int *salt_len ); +#endif +int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig ); +int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x509_buf *sig_params, + mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg, + void **sig_opts ); +int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, + mbedtls_x509_time *t ); +int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *serial ); +int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *ext, int tag ); +int mbedtls_x509_sig_alg_gets( char *buf, size_t size, const mbedtls_x509_buf *sig_oid, + mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, + const void *sig_opts ); +int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name ); +int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *name ); +int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid, size_t oid_len, + int critical, const unsigned char *val, + size_t val_len ); +int mbedtls_x509_write_extensions( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ); +int mbedtls_x509_write_names( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ); +int mbedtls_x509_write_sig( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + unsigned char *sig, size_t size ); + +#define MBEDTLS_X509_SAFE_SNPRINTF \ + do { \ + if( ret < 0 || (size_t) ret >= n ) \ + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); \ + \ + n -= (size_t) ret; \ + p += (size_t) ret; \ + } while( 0 ) + +#ifdef __cplusplus +} +#endif + +#endif /* x509.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509_crl.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509_crl.h new file mode 100644 index 000000000..e027f6f89 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509_crl.h @@ -0,0 +1,174 @@ +/** + * \file x509_crl.h + * + * \brief X.509 certificate revocation list parsing + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_CRL_H +#define MBEDTLS_X509_CRL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "x509.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures and functions for parsing CRLs + * \{ + */ + +/** + * Certificate revocation list entry. + * Contains the CA-specific serial numbers and revocation dates. + */ +typedef struct mbedtls_x509_crl_entry +{ + mbedtls_x509_buf raw; + + mbedtls_x509_buf serial; + + mbedtls_x509_time revocation_date; + + mbedtls_x509_buf entry_ext; + + struct mbedtls_x509_crl_entry *next; +} +mbedtls_x509_crl_entry; + +/** + * Certificate revocation list structure. + * Every CRL may have multiple entries. + */ +typedef struct mbedtls_x509_crl +{ + mbedtls_x509_buf raw; /**< The raw certificate data (DER). */ + mbedtls_x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; /**< CRL version (1=v1, 2=v2) */ + mbedtls_x509_buf sig_oid; /**< CRL signature type identifier */ + + mbedtls_x509_buf issuer_raw; /**< The raw issuer data (DER). */ + + mbedtls_x509_name issuer; /**< The parsed issuer data (named information object). */ + + mbedtls_x509_time this_update; + mbedtls_x509_time next_update; + + mbedtls_x509_crl_entry entry; /**< The CRL entries containing the certificate revocation times for this CA. */ + + mbedtls_x509_buf crl_ext; + + mbedtls_x509_buf sig_oid2; + mbedtls_x509_buf sig; + mbedtls_md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. MBEDTLS_MD_SHA256 */ + mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */ + void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */ + + struct mbedtls_x509_crl *next; +} +mbedtls_x509_crl; + +/** + * \brief Parse a DER-encoded CRL and append it to the chained list + * + * \param chain points to the start of the chain + * \param buf buffer holding the CRL data in DER format + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain, + const unsigned char *buf, size_t buflen ); +/** + * \brief Parse one or more CRLs and append them to the chained list + * + * \note Multiple CRLs are accepted only if using PEM format + * + * \param chain points to the start of the chain + * \param buf buffer holding the CRL data in PEM or DER format + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crl_parse( mbedtls_x509_crl *chain, const unsigned char *buf, size_t buflen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Load one or more CRLs and append them to the chained list + * + * \note Multiple CRLs are accepted only if using PEM format + * + * \param chain points to the start of the chain + * \param path filename to read the CRLs from (in PEM or DER encoding) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crl_parse_file( mbedtls_x509_crl *chain, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Returns an informational string about the CRL. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crl The X509 CRL to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_crl_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crl *crl ); + +/** + * \brief Initialize a CRL (chain) + * + * \param crl CRL chain to initialize + */ +void mbedtls_x509_crl_init( mbedtls_x509_crl *crl ); + +/** + * \brief Unallocate all CRL data + * + * \param crl CRL chain to free + */ +void mbedtls_x509_crl_free( mbedtls_x509_crl *crl ); + +/* \} name */ +/* \} addtogroup x509_module */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_x509_crl.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509_crt.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509_crt.h new file mode 100644 index 000000000..c56b2f869 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509_crt.h @@ -0,0 +1,999 @@ +/** + * \file x509_crt.h + * + * \brief X.509 certificate parsing and writing + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_CRT_H +#define MBEDTLS_X509_CRT_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "x509.h" +#include "x509_crl.h" + +/** + * \addtogroup x509_module + * \{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Structures and functions for parsing and writing X.509 certificates + * \{ + */ + +/** + * Container for an X.509 certificate. The certificate may be chained. + */ +typedef struct mbedtls_x509_crt +{ + int own_buffer; /**< Indicates if \c raw is owned + * by the structure or not. */ + mbedtls_x509_buf raw; /**< The raw certificate data (DER). */ + mbedtls_x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; /**< The X.509 version. (1=v1, 2=v2, 3=v3) */ + mbedtls_x509_buf serial; /**< Unique id for certificate issued by a specific CA. */ + mbedtls_x509_buf sig_oid; /**< Signature algorithm, e.g. sha1RSA */ + + mbedtls_x509_buf issuer_raw; /**< The raw issuer data (DER). Used for quick comparison. */ + mbedtls_x509_buf subject_raw; /**< The raw subject data (DER). Used for quick comparison. */ + + mbedtls_x509_name issuer; /**< The parsed issuer data (named information object). */ + mbedtls_x509_name subject; /**< The parsed subject data (named information object). */ + + mbedtls_x509_time valid_from; /**< Start time of certificate validity. */ + mbedtls_x509_time valid_to; /**< End time of certificate validity. */ + + mbedtls_x509_buf pk_raw; + mbedtls_pk_context pk; /**< Container for the public key context. */ + + mbedtls_x509_buf issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */ + mbedtls_x509_buf subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ + mbedtls_x509_buf v3_ext; /**< Optional X.509 v3 extensions. */ + mbedtls_x509_sequence subject_alt_names; /**< Optional list of raw entries of Subject Alternative Names extension (currently only dNSName and OtherName are listed). */ + + mbedtls_x509_sequence certificate_policies; /**< Optional list of certificate policies (Only anyPolicy is printed and enforced, however the rest of the policies are still listed). */ + + int ext_types; /**< Bit string containing detected and parsed extensions */ + int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ + int max_pathlen; /**< Optional Basic Constraint extension value: The maximum path length to the root certificate. Path length is 1 higher than RFC 5280 'meaning', so 1+ */ + + unsigned int key_usage; /**< Optional key usage extension value: See the values in x509.h */ + + mbedtls_x509_sequence ext_key_usage; /**< Optional list of extended key usage OIDs. */ + + unsigned char ns_cert_type; /**< Optional Netscape certificate type extension value: See the values in x509.h */ + + mbedtls_x509_buf sig; /**< Signature: hash of the tbs part signed with the private key. */ + mbedtls_md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. MBEDTLS_MD_SHA256 */ + mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */ + void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */ + + struct mbedtls_x509_crt *next; /**< Next certificate in the CA-chain. */ +} +mbedtls_x509_crt; + +/** + * From RFC 5280 section 4.2.1.6: + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } + */ +typedef struct mbedtls_x509_san_other_name +{ + /** + * The type_id is an OID as deifned in RFC 5280. + * To check the value of the type id, you should use + * \p MBEDTLS_OID_CMP with a known OID mbedtls_x509_buf. + */ + mbedtls_x509_buf type_id; /**< The type id. */ + union + { + /** + * From RFC 4108 section 5: + * HardwareModuleName ::= SEQUENCE { + * hwType OBJECT IDENTIFIER, + * hwSerialNum OCTET STRING } + */ + struct + { + mbedtls_x509_buf oid; /**< The object identifier. */ + mbedtls_x509_buf val; /**< The named value. */ + } + hardware_module_name; + } + value; +} +mbedtls_x509_san_other_name; + +/** + * A structure for holding the parsed Subject Alternative Name, according to type + */ +typedef struct mbedtls_x509_subject_alternative_name +{ + int type; /**< The SAN type, value of MBEDTLS_X509_SAN_XXX. */ + union { + mbedtls_x509_san_other_name other_name; /**< The otherName supported type. */ + mbedtls_x509_buf unstructured_name; /**< The buffer for the un constructed types. Only dnsName currently supported */ + } + san; /**< A union of the supported SAN types */ +} +mbedtls_x509_subject_alternative_name; + +/** + * Build flag from an algorithm/curve identifier (pk, md, ecp) + * Since 0 is always XXX_NONE, ignore it. + */ +#define MBEDTLS_X509_ID_FLAG( id ) ( 1 << ( (id) - 1 ) ) + +/** + * Security profile for certificate verification. + * + * All lists are bitfields, built by ORing flags from MBEDTLS_X509_ID_FLAG(). + */ +typedef struct mbedtls_x509_crt_profile +{ + uint32_t allowed_mds; /**< MDs for signatures */ + uint32_t allowed_pks; /**< PK algs for signatures */ + uint32_t allowed_curves; /**< Elliptic curves for ECDSA */ + uint32_t rsa_min_bitlen; /**< Minimum size for RSA keys */ +} +mbedtls_x509_crt_profile; + +#define MBEDTLS_X509_CRT_VERSION_1 0 +#define MBEDTLS_X509_CRT_VERSION_2 1 +#define MBEDTLS_X509_CRT_VERSION_3 2 + +#define MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN 32 +#define MBEDTLS_X509_RFC5280_UTC_TIME_LEN 15 + +#if !defined( MBEDTLS_X509_MAX_FILE_PATH_LEN ) +#define MBEDTLS_X509_MAX_FILE_PATH_LEN 512 +#endif + +/** + * Container for writing a certificate (CRT) + */ +typedef struct mbedtls_x509write_cert +{ + int version; + mbedtls_mpi serial; + mbedtls_pk_context *subject_key; + mbedtls_pk_context *issuer_key; + mbedtls_asn1_named_data *subject; + mbedtls_asn1_named_data *issuer; + mbedtls_md_type_t md_alg; + char not_before[MBEDTLS_X509_RFC5280_UTC_TIME_LEN + 1]; + char not_after[MBEDTLS_X509_RFC5280_UTC_TIME_LEN + 1]; + mbedtls_asn1_named_data *extensions; +} +mbedtls_x509write_cert; + +/** + * Item in a verification chain: cert and flags for it + */ +typedef struct { + mbedtls_x509_crt *crt; + uint32_t flags; +} mbedtls_x509_crt_verify_chain_item; + +/** + * Max size of verification chain: end-entity + intermediates + trusted root + */ +#define MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE ( MBEDTLS_X509_MAX_INTERMEDIATE_CA + 2 ) + +/** + * Verification chain as built by \c mbedtls_crt_verify_chain() + */ +typedef struct +{ + mbedtls_x509_crt_verify_chain_item items[MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE]; + unsigned len; + +#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) + /* This stores the list of potential trusted signers obtained from + * the CA callback used for the CRT verification, if configured. + * We must track it somewhere because the callback passes its + * ownership to the caller. */ + mbedtls_x509_crt *trust_ca_cb_result; +#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ +} mbedtls_x509_crt_verify_chain; + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + +/** + * \brief Context for resuming X.509 verify operations + */ +typedef struct +{ + /* for check_signature() */ + mbedtls_pk_restart_ctx pk; + + /* for find_parent_in() */ + mbedtls_x509_crt *parent; /* non-null iff parent_in in progress */ + mbedtls_x509_crt *fallback_parent; + int fallback_signature_is_good; + + /* for find_parent() */ + int parent_is_trusted; /* -1 if find_parent is not in progress */ + + /* for verify_chain() */ + enum { + x509_crt_rs_none, + x509_crt_rs_find_parent, + } in_progress; /* none if no operation is in progress */ + int self_cnt; + mbedtls_x509_crt_verify_chain ver_chain; + +} mbedtls_x509_crt_restart_ctx; + +#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + +/* Now we can declare functions that take a pointer to that */ +typedef void mbedtls_x509_crt_restart_ctx; + +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * Default security profile. Should provide a good balance between security + * and compatibility with current deployments. + */ +extern const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default; + +/** + * Expected next default profile. Recommended for new deployments. + * Currently targets a 128-bit security level, except for RSA-2048. + */ +extern const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next; + +/** + * NSA Suite B profile. + */ +extern const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb; + +/** + * \brief Parse a single DER formatted certificate and add it + * to the end of the provided chained list. + * + * \param chain The pointer to the start of the CRT chain to attach to. + * When parsing the first CRT in a chain, this should point + * to an instance of ::mbedtls_x509_crt initialized through + * mbedtls_x509_crt_init(). + * \param buf The buffer holding the DER encoded certificate. + * \param buflen The size in Bytes of \p buf. + * + * \note This function makes an internal copy of the CRT buffer + * \p buf. In particular, \p buf may be destroyed or reused + * after this call returns. To avoid duplicating the CRT + * buffer (at the cost of stricter lifetime constraints), + * use mbedtls_x509_crt_parse_der_nocopy() instead. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, + const unsigned char *buf, + size_t buflen ); + +/** + * \brief Parse a single DER formatted certificate and add it + * to the end of the provided chained list. This is a + * variant of mbedtls_x509_crt_parse_der() which takes + * temporary ownership of the CRT buffer until the CRT + * is destroyed. + * + * \param chain The pointer to the start of the CRT chain to attach to. + * When parsing the first CRT in a chain, this should point + * to an instance of ::mbedtls_x509_crt initialized through + * mbedtls_x509_crt_init(). + * \param buf The address of the readable buffer holding the DER encoded + * certificate to use. On success, this buffer must be + * retained and not be changed for the liftetime of the + * CRT chain \p chain, that is, until \p chain is destroyed + * through a call to mbedtls_x509_crt_free(). + * \param buflen The size in Bytes of \p buf. + * + * \note This call is functionally equivalent to + * mbedtls_x509_crt_parse_der(), but it avoids creating a + * copy of the input buffer at the cost of stronger lifetime + * constraints. This is useful in constrained environments + * where duplication of the CRT cannot be tolerated. + * + * \return \c 0 if successful. + * \return A negative error code on failure. + */ +int mbedtls_x509_crt_parse_der_nocopy( mbedtls_x509_crt *chain, + const unsigned char *buf, + size_t buflen ); + +/** + * \brief Parse one DER-encoded or one or more concatenated PEM-encoded + * certificates and add them to the chained list. + * + * For CRTs in PEM encoding, the function parses permissively: + * if at least one certificate can be parsed, the function + * returns the number of certificates for which parsing failed + * (hence \c 0 if all certificates were parsed successfully). + * If no certificate could be parsed, the function returns + * the first (negative) error encountered during parsing. + * + * PEM encoded certificates may be interleaved by other data + * such as human readable descriptions of their content, as + * long as the certificates are enclosed in the PEM specific + * '-----{BEGIN/END} CERTIFICATE-----' delimiters. + * + * \param chain The chain to which to add the parsed certificates. + * \param buf The buffer holding the certificate data in PEM or DER format. + * For certificates in PEM encoding, this may be a concatenation + * of multiple certificates; for DER encoding, the buffer must + * comprise exactly one certificate. + * \param buflen The size of \p buf, including the terminating \c NULL byte + * in case of PEM encoded data. + * + * \return \c 0 if all certificates were parsed successfully. + * \return The (positive) number of certificates that couldn't + * be parsed if parsing was partly successful (see above). + * \return A negative X509 or PEM error code otherwise. + * + */ +int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Load one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param path filename to read the certificates from + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path ); + +/** + * \brief Load one or more certificate files from a path and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param path directory / folder to read the certificate files from + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ); + +#endif /* MBEDTLS_FS_IO */ +/** + * \brief This function parses an item in the SubjectAlternativeNames + * extension. + * + * \param san_buf The buffer holding the raw data item of the subject + * alternative name. + * \param san The target structure to populate with the parsed presentation + * of the subject alternative name encoded in \p san_raw. + * + * \note Only "dnsName" and "otherName" of type hardware_module_name + * as defined in RFC 4180 is supported. + * + * \note This function should be called on a single raw data of + * subject alternative name. For example, after successful + * certificate parsing, one must iterate on every item in the + * \p crt->subject_alt_names sequence, and pass it to + * this function. + * + * \warning The target structure contains pointers to the raw data of the + * parsed certificate, and its lifetime is restricted by the + * lifetime of the certificate. + * + * \return \c 0 on success + * \return #MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE for an unsupported + * SAN type. + * \return Another negative value for any other failure. + */ +int mbedtls_x509_parse_subject_alt_name( const mbedtls_x509_buf *san_buf, + mbedtls_x509_subject_alternative_name *san ); +/** + * \brief Returns an informational string about the + * certificate. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crt The X509 certificate to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crt *crt ); + +/** + * \brief Returns an informational string about the + * verification status of a certificate. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param flags Verification flags created by mbedtls_x509_crt_verify() + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix, + uint32_t flags ); + +/** + * \brief Verify a chain of certificates. + * + * The verify callback is a user-supplied callback that + * can clear / modify / add flags for a certificate. If set, + * the verification callback is called for each + * certificate in the chain (from the trust-ca down to the + * presented crt). The parameters for the callback are: + * (void *parameter, mbedtls_x509_crt *crt, int certificate_depth, + * int *flags). With the flags representing current flags for + * that specific certificate and the certificate depth from + * the bottom (Peer cert depth = 0). + * + * All flags left after returning from the callback + * are also returned to the application. The function should + * return 0 for anything (including invalid certificates) + * other than fatal error, as a non-zero return code + * immediately aborts the verification process. For fatal + * errors, a specific error code should be used (different + * from MBEDTLS_ERR_X509_CERT_VERIFY_FAILED which should not + * be returned at this point), or MBEDTLS_ERR_X509_FATAL_ERROR + * can be used if no better code is available. + * + * \note In case verification failed, the results can be displayed + * using \c mbedtls_x509_crt_verify_info() + * + * \note Same as \c mbedtls_x509_crt_verify_with_profile() with the + * default security profile. + * + * \note It is your responsibility to provide up-to-date CRLs for + * all trusted CAs. If no CRL is provided for the CA that was + * used to sign the certificate, CRL verification is skipped + * silently, that is *without* setting any flag. + * + * \note The \c trust_ca list can contain two types of certificates: + * (1) those of trusted root CAs, so that certificates + * chaining up to those CAs will be trusted, and (2) + * self-signed end-entity certificates to be trusted (for + * specific peers you know) - in that case, the self-signed + * certificate doesn't need to have the CA bit set. + * + * \param crt The certificate chain to be verified. + * \param trust_ca The list of trusted CAs. + * \param ca_crl The list of CRLs for trusted CAs. + * \param cn The expected Common Name. This may be \c NULL if the + * CN need not be verified. + * \param flags The address at which to store the result of the verification. + * If the verification couldn't be completed, the flag value is + * set to (uint32_t) -1. + * \param f_vrfy The verification callback to use. See the documentation + * of mbedtls_x509_crt_verify() for more information. + * \param p_vrfy The context to be passed to \p f_vrfy. + * + * \return \c 0 if the chain is valid with respect to the + * passed CN, CAs, CRLs and security profile. + * \return #MBEDTLS_ERR_X509_CERT_VERIFY_FAILED in case the + * certificate chain verification failed. In this case, + * \c *flags will have one or more + * \c MBEDTLS_X509_BADCERT_XXX or \c MBEDTLS_X509_BADCRL_XXX + * flags set. + * \return Another negative error code in case of a fatal error + * encountered during the verification process. + */ +int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ); + +/** + * \brief Verify a chain of certificates with respect to + * a configurable security profile. + * + * \note Same as \c mbedtls_x509_crt_verify(), but with explicit + * security profile. + * + * \note The restrictions on keys (RSA minimum size, allowed curves + * for ECDSA) apply to all certificates: trusted root, + * intermediate CAs if any, and end entity certificate. + * + * \param crt The certificate chain to be verified. + * \param trust_ca The list of trusted CAs. + * \param ca_crl The list of CRLs for trusted CAs. + * \param profile The security profile to use for the verification. + * \param cn The expected Common Name. This may be \c NULL if the + * CN need not be verified. + * \param flags The address at which to store the result of the verification. + * If the verification couldn't be completed, the flag value is + * set to (uint32_t) -1. + * \param f_vrfy The verification callback to use. See the documentation + * of mbedtls_x509_crt_verify() for more information. + * \param p_vrfy The context to be passed to \p f_vrfy. + * + * \return \c 0 if the chain is valid with respect to the + * passed CN, CAs, CRLs and security profile. + * \return #MBEDTLS_ERR_X509_CERT_VERIFY_FAILED in case the + * certificate chain verification failed. In this case, + * \c *flags will have one or more + * \c MBEDTLS_X509_BADCERT_XXX or \c MBEDTLS_X509_BADCRL_XXX + * flags set. + * \return Another negative error code in case of a fatal error + * encountered during the verification process. + */ +int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ); + +/** + * \brief Restartable version of \c mbedtls_crt_verify_with_profile() + * + * \note Performs the same job as \c mbedtls_crt_verify_with_profile() + * but can return early and restart according to the limit + * set with \c mbedtls_ecp_set_max_ops() to reduce blocking. + * + * \param crt The certificate chain to be verified. + * \param trust_ca The list of trusted CAs. + * \param ca_crl The list of CRLs for trusted CAs. + * \param profile The security profile to use for the verification. + * \param cn The expected Common Name. This may be \c NULL if the + * CN need not be verified. + * \param flags The address at which to store the result of the verification. + * If the verification couldn't be completed, the flag value is + * set to (uint32_t) -1. + * \param f_vrfy The verification callback to use. See the documentation + * of mbedtls_x509_crt_verify() for more information. + * \param p_vrfy The context to be passed to \p f_vrfy. + * \param rs_ctx The restart context to use. This may be set to \c NULL + * to disable restartable ECC. + * + * \return See \c mbedtls_crt_verify_with_profile(), or + * \return #MBEDTLS_ERR_ECP_IN_PROGRESS if maximum number of + * operations was reached: see \c mbedtls_ecp_set_max_ops(). + */ +int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy, + mbedtls_x509_crt_restart_ctx *rs_ctx ); + +/** + * \brief The type of trusted certificate callbacks. + * + * Callbacks of this type are passed to and used by the CRT + * verification routine mbedtls_x509_crt_verify_with_ca_cb() + * when looking for trusted signers of a given certificate. + * + * On success, the callback returns a list of trusted + * certificates to be considered as potential signers + * for the input certificate. + * + * \param p_ctx An opaque context passed to the callback. + * \param child The certificate for which to search a potential signer. + * This will point to a readable certificate. + * \param candidate_cas The address at which to store the address of the first + * entry in the generated linked list of candidate signers. + * This will not be \c NULL. + * + * \note The callback must only return a non-zero value on a + * fatal error. If, in contrast, the search for a potential + * signer completes without a single candidate, the + * callback must return \c 0 and set \c *candidate_cas + * to \c NULL. + * + * \return \c 0 on success. In this case, \c *candidate_cas points + * to a heap-allocated linked list of instances of + * ::mbedtls_x509_crt, and ownership of this list is passed + * to the caller. + * \return A negative error code on failure. + */ +typedef int (*mbedtls_x509_crt_ca_cb_t)( void *p_ctx, + mbedtls_x509_crt const *child, + mbedtls_x509_crt **candidate_cas ); + +#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) +/** + * \brief Version of \c mbedtls_x509_crt_verify_with_profile() which + * uses a callback to acquire the list of trusted CA + * certificates. + * + * \param crt The certificate chain to be verified. + * \param f_ca_cb The callback to be used to query for potential signers + * of a given child certificate. See the documentation of + * ::mbedtls_x509_crt_ca_cb_t for more information. + * \param p_ca_cb The opaque context to be passed to \p f_ca_cb. + * \param profile The security profile for the verification. + * \param cn The expected Common Name. This may be \c NULL if the + * CN need not be verified. + * \param flags The address at which to store the result of the verification. + * If the verification couldn't be completed, the flag value is + * set to (uint32_t) -1. + * \param f_vrfy The verification callback to use. See the documentation + * of mbedtls_x509_crt_verify() for more information. + * \param p_vrfy The context to be passed to \p f_vrfy. + * + * \return See \c mbedtls_crt_verify_with_profile(). + */ +int mbedtls_x509_crt_verify_with_ca_cb( mbedtls_x509_crt *crt, + mbedtls_x509_crt_ca_cb_t f_ca_cb, + void *p_ca_cb, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ); + +#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) +/** + * \brief Check usage of certificate against keyUsage extension. + * + * \param crt Leaf certificate used. + * \param usage Intended usage(s) (eg MBEDTLS_X509_KU_KEY_ENCIPHERMENT + * before using the certificate to perform an RSA key + * exchange). + * + * \note Except for decipherOnly and encipherOnly, a bit set in the + * usage argument means this bit MUST be set in the + * certificate. For decipherOnly and encipherOnly, it means + * that bit MAY be set. + * + * \return 0 is these uses of the certificate are allowed, + * MBEDTLS_ERR_X509_BAD_INPUT_DATA if the keyUsage extension + * is present but does not match the usage argument. + * + * \note You should only call this function on leaf certificates, on + * (intermediate) CAs the keyUsage extension is automatically + * checked by \c mbedtls_x509_crt_verify(). + */ +int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, + unsigned int usage ); +#endif /* MBEDTLS_X509_CHECK_KEY_USAGE) */ + +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) +/** + * \brief Check usage of certificate against extendedKeyUsage. + * + * \param crt Leaf certificate used. + * \param usage_oid Intended usage (eg MBEDTLS_OID_SERVER_AUTH or + * MBEDTLS_OID_CLIENT_AUTH). + * \param usage_len Length of usage_oid (eg given by MBEDTLS_OID_SIZE()). + * + * \return 0 if this use of the certificate is allowed, + * MBEDTLS_ERR_X509_BAD_INPUT_DATA if not. + * + * \note Usually only makes sense on leaf certificates. + */ +int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, + const char *usage_oid, + size_t usage_len ); +#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ + +#if defined(MBEDTLS_X509_CRL_PARSE_C) +/** + * \brief Verify the certificate revocation status + * + * \param crt a certificate to be verified + * \param crl the CRL to verify against + * + * \return 1 if the certificate is revoked, 0 otherwise + * + */ +int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl ); +#endif /* MBEDTLS_X509_CRL_PARSE_C */ + +/** + * \brief Initialize a certificate (chain) + * + * \param crt Certificate chain to initialize + */ +void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ); + +/** + * \brief Unallocate all certificate data + * + * \param crt Certificate chain to free + */ +void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ); + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +/** + * \brief Initialize a restart context + */ +void mbedtls_x509_crt_restart_init( mbedtls_x509_crt_restart_ctx *ctx ); + +/** + * \brief Free the components of a restart context + */ +void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx ); +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/* \} name */ +/* \} addtogroup x509_module */ + +#if defined(MBEDTLS_X509_CRT_WRITE_C) +/** + * \brief Initialize a CRT writing context + * + * \param ctx CRT context to initialize + */ +void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx ); + +/** + * \brief Set the verion for a Certificate + * Default: MBEDTLS_X509_CRT_VERSION_3 + * + * \param ctx CRT context to use + * \param version version to set (MBEDTLS_X509_CRT_VERSION_1, MBEDTLS_X509_CRT_VERSION_2 or + * MBEDTLS_X509_CRT_VERSION_3) + */ +void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version ); + +/** + * \brief Set the serial number for a Certificate. + * + * \param ctx CRT context to use + * \param serial serial number to set + * + * \return 0 if successful + */ +int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx, const mbedtls_mpi *serial ); + +/** + * \brief Set the validity period for a Certificate + * Timestamps should be in string format for UTC timezone + * i.e. "YYYYMMDDhhmmss" + * e.g. "20131231235959" for December 31st 2013 + * at 23:59:59 + * + * \param ctx CRT context to use + * \param not_before not_before timestamp + * \param not_after not_after timestamp + * + * \return 0 if timestamp was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert *ctx, const char *not_before, + const char *not_after ); + +/** + * \brief Set the issuer name for a Certificate + * Issuer names should contain a comma-separated list + * of OID types and values: + * e.g. "C=UK,O=ARM,CN=mbed TLS CA" + * + * \param ctx CRT context to use + * \param issuer_name issuer name to set + * + * \return 0 if issuer name was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_crt_set_issuer_name( mbedtls_x509write_cert *ctx, + const char *issuer_name ); + +/** + * \brief Set the subject name for a Certificate + * Subject names should contain a comma-separated list + * of OID types and values: + * e.g. "C=UK,O=ARM,CN=mbed TLS Server 1" + * + * \param ctx CRT context to use + * \param subject_name subject name to set + * + * \return 0 if subject name was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_crt_set_subject_name( mbedtls_x509write_cert *ctx, + const char *subject_name ); + +/** + * \brief Set the subject public key for the certificate + * + * \param ctx CRT context to use + * \param key public key to include + */ +void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key ); + +/** + * \brief Set the issuer key used for signing the certificate + * + * \param ctx CRT context to use + * \param key private key to sign with + */ +void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key ); + +/** + * \brief Set the MD algorithm to use for the signature + * (e.g. MBEDTLS_MD_SHA1) + * + * \param ctx CRT context to use + * \param md_alg MD algorithm to use + */ +void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert *ctx, mbedtls_md_type_t md_alg ); + +/** + * \brief Generic function to add to or replace an extension in the + * CRT + * + * \param ctx CRT context to use + * \param oid OID of the extension + * \param oid_len length of the OID + * \param critical if the extension is critical (per the RFC's definition) + * \param val value of the extension OCTET STRING + * \param val_len length of the value data + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_extension( mbedtls_x509write_cert *ctx, + const char *oid, size_t oid_len, + int critical, + const unsigned char *val, size_t val_len ); + +/** + * \brief Set the basicConstraints extension for a CRT + * + * \param ctx CRT context to use + * \param is_ca is this a CA certificate + * \param max_pathlen maximum length of certificate chains below this + * certificate (only for CA certificates, -1 is + * inlimited) + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_basic_constraints( mbedtls_x509write_cert *ctx, + int is_ca, int max_pathlen ); + +#if defined(MBEDTLS_SHA1_C) +/** + * \brief Set the subjectKeyIdentifier extension for a CRT + * Requires that mbedtls_x509write_crt_set_subject_key() has been + * called before + * + * \param ctx CRT context to use + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ctx ); + +/** + * \brief Set the authorityKeyIdentifier extension for a CRT + * Requires that mbedtls_x509write_crt_set_issuer_key() has been + * called before + * + * \param ctx CRT context to use + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *ctx ); +#endif /* MBEDTLS_SHA1_C */ + +/** + * \brief Set the Key Usage Extension flags + * (e.g. MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_CERT_SIGN) + * + * \param ctx CRT context to use + * \param key_usage key usage flags to set + * + * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx, + unsigned int key_usage ); + +/** + * \brief Set the Netscape Cert Type flags + * (e.g. MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT | MBEDTLS_X509_NS_CERT_TYPE_EMAIL) + * + * \param ctx CRT context to use + * \param ns_cert_type Netscape Cert Type flags to set + * + * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx, + unsigned char ns_cert_type ); + +/** + * \brief Free the contents of a CRT write context + * + * \param ctx CRT context to free + */ +void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx ); + +/** + * \brief Write a built up certificate to a X509 DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx certificate to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return length of data written if successful, or a specific + * error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a built up certificate to a X509 PEM string + * + * \param ctx certificate to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return 0 if successful, or a specific error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +int mbedtls_x509write_crt_pem( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_X509_CRT_WRITE_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_x509_crt.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509_csr.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509_csr.h new file mode 100644 index 000000000..c8d093869 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/x509_csr.h @@ -0,0 +1,307 @@ +/** + * \file x509_csr.h + * + * \brief X.509 certificate signing request parsing and writing + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_CSR_H +#define MBEDTLS_X509_CSR_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "x509.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures and functions for X.509 Certificate Signing Requests (CSR) + * \{ + */ + +/** + * Certificate Signing Request (CSR) structure. + */ +typedef struct mbedtls_x509_csr +{ + mbedtls_x509_buf raw; /**< The raw CSR data (DER). */ + mbedtls_x509_buf cri; /**< The raw CertificateRequestInfo body (DER). */ + + int version; /**< CSR version (1=v1). */ + + mbedtls_x509_buf subject_raw; /**< The raw subject data (DER). */ + mbedtls_x509_name subject; /**< The parsed subject data (named information object). */ + + mbedtls_pk_context pk; /**< Container for the public key context. */ + + mbedtls_x509_buf sig_oid; + mbedtls_x509_buf sig; + mbedtls_md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. MBEDTLS_MD_SHA256 */ + mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */ + void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */ +} +mbedtls_x509_csr; + +/** + * Container for writing a CSR + */ +typedef struct mbedtls_x509write_csr +{ + mbedtls_pk_context *key; + mbedtls_asn1_named_data *subject; + mbedtls_md_type_t md_alg; + mbedtls_asn1_named_data *extensions; +} +mbedtls_x509write_csr; + +#if defined(MBEDTLS_X509_CSR_PARSE_C) +/** + * \brief Load a Certificate Signing Request (CSR) in DER format + * + * \note CSR attributes (if any) are currently silently ignored. + * + * \param csr CSR context to fill + * \param buf buffer holding the CRL data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 error code + */ +int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr, + const unsigned char *buf, size_t buflen ); + +/** + * \brief Load a Certificate Signing Request (CSR), DER or PEM format + * + * \note See notes for \c mbedtls_x509_csr_parse_der() + * + * \param csr CSR context to fill + * \param buf buffer holding the CRL data + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_csr_parse( mbedtls_x509_csr *csr, const unsigned char *buf, size_t buflen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Load a Certificate Signing Request (CSR) + * + * \note See notes for \c mbedtls_x509_csr_parse() + * + * \param csr CSR context to fill + * \param path filename to read the CSR from + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_csr_parse_file( mbedtls_x509_csr *csr, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Returns an informational string about the + * CSR. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param csr The X509 CSR to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_csr_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_csr *csr ); + +/** + * \brief Initialize a CSR + * + * \param csr CSR to initialize + */ +void mbedtls_x509_csr_init( mbedtls_x509_csr *csr ); + +/** + * \brief Unallocate all CSR data + * + * \param csr CSR to free + */ +void mbedtls_x509_csr_free( mbedtls_x509_csr *csr ); +#endif /* MBEDTLS_X509_CSR_PARSE_C */ + +/* \} name */ +/* \} addtogroup x509_module */ + +#if defined(MBEDTLS_X509_CSR_WRITE_C) +/** + * \brief Initialize a CSR context + * + * \param ctx CSR context to initialize + */ +void mbedtls_x509write_csr_init( mbedtls_x509write_csr *ctx ); + +/** + * \brief Set the subject name for a CSR + * Subject names should contain a comma-separated list + * of OID types and values: + * e.g. "C=UK,O=ARM,CN=mbed TLS Server 1" + * + * \param ctx CSR context to use + * \param subject_name subject name to set + * + * \return 0 if subject name was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_csr_set_subject_name( mbedtls_x509write_csr *ctx, + const char *subject_name ); + +/** + * \brief Set the key for a CSR (public key will be included, + * private key used to sign the CSR when writing it) + * + * \param ctx CSR context to use + * \param key Asymetric key to include + */ +void mbedtls_x509write_csr_set_key( mbedtls_x509write_csr *ctx, mbedtls_pk_context *key ); + +/** + * \brief Set the MD algorithm to use for the signature + * (e.g. MBEDTLS_MD_SHA1) + * + * \param ctx CSR context to use + * \param md_alg MD algorithm to use + */ +void mbedtls_x509write_csr_set_md_alg( mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg ); + +/** + * \brief Set the Key Usage Extension flags + * (e.g. MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_CERT_SIGN) + * + * \param ctx CSR context to use + * \param key_usage key usage flags to set + * + * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + * + * \note The decipherOnly flag from the Key Usage + * extension is represented by bit 8 (i.e. + * 0x8000), which cannot typically be represented + * in an unsigned char. Therefore, the flag + * decipherOnly (i.e. + * #MBEDTLS_X509_KU_DECIPHER_ONLY) cannot be set using this + * function. + */ +int mbedtls_x509write_csr_set_key_usage( mbedtls_x509write_csr *ctx, unsigned char key_usage ); + +/** + * \brief Set the Netscape Cert Type flags + * (e.g. MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT | MBEDTLS_X509_NS_CERT_TYPE_EMAIL) + * + * \param ctx CSR context to use + * \param ns_cert_type Netscape Cert Type flags to set + * + * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_csr_set_ns_cert_type( mbedtls_x509write_csr *ctx, + unsigned char ns_cert_type ); + +/** + * \brief Generic function to add to or replace an extension in the + * CSR + * + * \param ctx CSR context to use + * \param oid OID of the extension + * \param oid_len length of the OID + * \param val value of the extension OCTET STRING + * \param val_len length of the value data + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_csr_set_extension( mbedtls_x509write_csr *ctx, + const char *oid, size_t oid_len, + const unsigned char *val, size_t val_len ); + +/** + * \brief Free the contents of a CSR context + * + * \param ctx CSR context to free + */ +void mbedtls_x509write_csr_free( mbedtls_x509write_csr *ctx ); + +/** + * \brief Write a CSR (Certificate Signing Request) to a + * DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx CSR to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return length of data written if successful, or a specific + * error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a CSR (Certificate Signing Request) to a + * PEM string + * + * \param ctx CSR to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return 0 if successful, or a specific error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +int mbedtls_x509write_csr_pem( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_X509_CSR_WRITE_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_x509_csr.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/xtea.h b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/xtea.h new file mode 100644 index 000000000..de380ee77 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/include/mbedtls/xtea.h @@ -0,0 +1,139 @@ +/** + * \file xtea.h + * + * \brief XTEA block cipher (32-bit) + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_XTEA_H +#define MBEDTLS_XTEA_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_XTEA_ENCRYPT 1 +#define MBEDTLS_XTEA_DECRYPT 0 + +#define MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH -0x0028 /**< The data input has an invalid length. */ + +/* MBEDTLS_ERR_XTEA_HW_ACCEL_FAILED is deprecated and should not be used. */ +#define MBEDTLS_ERR_XTEA_HW_ACCEL_FAILED -0x0029 /**< XTEA hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_XTEA_ALT) +// Regular implementation +// + +/** + * \brief XTEA context structure + */ +typedef struct mbedtls_xtea_context +{ + uint32_t k[4]; /*!< key */ +} +mbedtls_xtea_context; + +#else /* MBEDTLS_XTEA_ALT */ +#include "xtea_alt.h" +#endif /* MBEDTLS_XTEA_ALT */ + +/** + * \brief Initialize XTEA context + * + * \param ctx XTEA context to be initialized + */ +void mbedtls_xtea_init( mbedtls_xtea_context *ctx ); + +/** + * \brief Clear XTEA context + * + * \param ctx XTEA context to be cleared + */ +void mbedtls_xtea_free( mbedtls_xtea_context *ctx ); + +/** + * \brief XTEA key schedule + * + * \param ctx XTEA context to be initialized + * \param key the secret key + */ +void mbedtls_xtea_setup( mbedtls_xtea_context *ctx, const unsigned char key[16] ); + +/** + * \brief XTEA cipher function + * + * \param ctx XTEA context + * \param mode MBEDTLS_XTEA_ENCRYPT or MBEDTLS_XTEA_DECRYPT + * \param input 8-byte input block + * \param output 8-byte output block + * + * \return 0 if successful + */ +int mbedtls_xtea_crypt_ecb( mbedtls_xtea_context *ctx, + int mode, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief XTEA CBC cipher function + * + * \param ctx XTEA context + * \param mode MBEDTLS_XTEA_ENCRYPT or MBEDTLS_XTEA_DECRYPT + * \param length the length of input, multiple of 8 + * \param iv initialization vector for CBC mode + * \param input input block + * \param output output block + * + * \return 0 if successful, + * MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH if the length % 8 != 0 + */ +int mbedtls_xtea_crypt_cbc( mbedtls_xtea_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_xtea_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* xtea.h */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/aes.c b/FreeRTOS-Labs/Source/mbedtls/library/aes.c new file mode 100644 index 000000000..f97c921cf --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/aes.c @@ -0,0 +1,2209 @@ +/* + * FIPS-197 compliant AES implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_AES_C) + +#include + +#include "mbedtls/aes.h" +#include "mbedtls/platform.h" +#include "mbedtls/platform_util.h" +#if defined(MBEDTLS_PADLOCK_C) +#include "mbedtls/padlock.h" +#endif +#if defined(MBEDTLS_AESNI_C) +#include "mbedtls/aesni.h" +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_AES_ALT) + +/* Parameter validation macros based on platform_util.h */ +#define AES_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_AES_BAD_INPUT_DATA ) +#define AES_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +#if defined(MBEDTLS_PADLOCK_C) && \ + ( defined(MBEDTLS_HAVE_X86) || defined(MBEDTLS_PADLOCK_ALIGN16) ) +static int aes_padlock_ace = -1; +#endif + +#if defined(MBEDTLS_AES_ROM_TABLES) +/* + * Forward S-box + */ +static const unsigned char FSb[256] = +{ + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, + 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, + 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, + 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, + 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, + 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, + 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, + 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, + 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, + 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, + 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, + 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 +}; + +/* + * Forward tables + */ +#define FT \ +\ + V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \ + V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \ + V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \ + V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \ + V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \ + V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \ + V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \ + V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \ + V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \ + V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \ + V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \ + V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \ + V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \ + V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \ + V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \ + V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \ + V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \ + V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \ + V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \ + V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \ + V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \ + V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \ + V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \ + V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \ + V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \ + V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \ + V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \ + V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \ + V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \ + V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \ + V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \ + V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \ + V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \ + V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \ + V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \ + V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \ + V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \ + V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \ + V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \ + V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \ + V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \ + V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \ + V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \ + V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \ + V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \ + V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \ + V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \ + V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \ + V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \ + V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \ + V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \ + V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \ + V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \ + V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \ + V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \ + V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \ + V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \ + V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \ + V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \ + V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \ + V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \ + V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \ + V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \ + V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C) + +#define V(a,b,c,d) 0x##a##b##c##d +static const uint32_t FT0[256] = { FT }; +#undef V + +#if !defined(MBEDTLS_AES_FEWER_TABLES) + +#define V(a,b,c,d) 0x##b##c##d##a +static const uint32_t FT1[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const uint32_t FT2[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const uint32_t FT3[256] = { FT }; +#undef V + +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + +#undef FT + +/* + * Reverse S-box + */ +static const unsigned char RSb[256] = +{ + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, + 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, + 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, + 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, + 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, + 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, + 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, + 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, + 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, + 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, + 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, + 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D +}; + +/* + * Reverse tables + */ +#define RT \ +\ + V(50,A7,F4,51), V(53,65,41,7E), V(C3,A4,17,1A), V(96,5E,27,3A), \ + V(CB,6B,AB,3B), V(F1,45,9D,1F), V(AB,58,FA,AC), V(93,03,E3,4B), \ + V(55,FA,30,20), V(F6,6D,76,AD), V(91,76,CC,88), V(25,4C,02,F5), \ + V(FC,D7,E5,4F), V(D7,CB,2A,C5), V(80,44,35,26), V(8F,A3,62,B5), \ + V(49,5A,B1,DE), V(67,1B,BA,25), V(98,0E,EA,45), V(E1,C0,FE,5D), \ + V(02,75,2F,C3), V(12,F0,4C,81), V(A3,97,46,8D), V(C6,F9,D3,6B), \ + V(E7,5F,8F,03), V(95,9C,92,15), V(EB,7A,6D,BF), V(DA,59,52,95), \ + V(2D,83,BE,D4), V(D3,21,74,58), V(29,69,E0,49), V(44,C8,C9,8E), \ + V(6A,89,C2,75), V(78,79,8E,F4), V(6B,3E,58,99), V(DD,71,B9,27), \ + V(B6,4F,E1,BE), V(17,AD,88,F0), V(66,AC,20,C9), V(B4,3A,CE,7D), \ + V(18,4A,DF,63), V(82,31,1A,E5), V(60,33,51,97), V(45,7F,53,62), \ + V(E0,77,64,B1), V(84,AE,6B,BB), V(1C,A0,81,FE), V(94,2B,08,F9), \ + V(58,68,48,70), V(19,FD,45,8F), V(87,6C,DE,94), V(B7,F8,7B,52), \ + V(23,D3,73,AB), V(E2,02,4B,72), V(57,8F,1F,E3), V(2A,AB,55,66), \ + V(07,28,EB,B2), V(03,C2,B5,2F), V(9A,7B,C5,86), V(A5,08,37,D3), \ + V(F2,87,28,30), V(B2,A5,BF,23), V(BA,6A,03,02), V(5C,82,16,ED), \ + V(2B,1C,CF,8A), V(92,B4,79,A7), V(F0,F2,07,F3), V(A1,E2,69,4E), \ + V(CD,F4,DA,65), V(D5,BE,05,06), V(1F,62,34,D1), V(8A,FE,A6,C4), \ + V(9D,53,2E,34), V(A0,55,F3,A2), V(32,E1,8A,05), V(75,EB,F6,A4), \ + V(39,EC,83,0B), V(AA,EF,60,40), V(06,9F,71,5E), V(51,10,6E,BD), \ + V(F9,8A,21,3E), V(3D,06,DD,96), V(AE,05,3E,DD), V(46,BD,E6,4D), \ + V(B5,8D,54,91), V(05,5D,C4,71), V(6F,D4,06,04), V(FF,15,50,60), \ + V(24,FB,98,19), V(97,E9,BD,D6), V(CC,43,40,89), V(77,9E,D9,67), \ + V(BD,42,E8,B0), V(88,8B,89,07), V(38,5B,19,E7), V(DB,EE,C8,79), \ + V(47,0A,7C,A1), V(E9,0F,42,7C), V(C9,1E,84,F8), V(00,00,00,00), \ + V(83,86,80,09), V(48,ED,2B,32), V(AC,70,11,1E), V(4E,72,5A,6C), \ + V(FB,FF,0E,FD), V(56,38,85,0F), V(1E,D5,AE,3D), V(27,39,2D,36), \ + V(64,D9,0F,0A), V(21,A6,5C,68), V(D1,54,5B,9B), V(3A,2E,36,24), \ + V(B1,67,0A,0C), V(0F,E7,57,93), V(D2,96,EE,B4), V(9E,91,9B,1B), \ + V(4F,C5,C0,80), V(A2,20,DC,61), V(69,4B,77,5A), V(16,1A,12,1C), \ + V(0A,BA,93,E2), V(E5,2A,A0,C0), V(43,E0,22,3C), V(1D,17,1B,12), \ + V(0B,0D,09,0E), V(AD,C7,8B,F2), V(B9,A8,B6,2D), V(C8,A9,1E,14), \ + V(85,19,F1,57), V(4C,07,75,AF), V(BB,DD,99,EE), V(FD,60,7F,A3), \ + V(9F,26,01,F7), V(BC,F5,72,5C), V(C5,3B,66,44), V(34,7E,FB,5B), \ + V(76,29,43,8B), V(DC,C6,23,CB), V(68,FC,ED,B6), V(63,F1,E4,B8), \ + V(CA,DC,31,D7), V(10,85,63,42), V(40,22,97,13), V(20,11,C6,84), \ + V(7D,24,4A,85), V(F8,3D,BB,D2), V(11,32,F9,AE), V(6D,A1,29,C7), \ + V(4B,2F,9E,1D), V(F3,30,B2,DC), V(EC,52,86,0D), V(D0,E3,C1,77), \ + V(6C,16,B3,2B), V(99,B9,70,A9), V(FA,48,94,11), V(22,64,E9,47), \ + V(C4,8C,FC,A8), V(1A,3F,F0,A0), V(D8,2C,7D,56), V(EF,90,33,22), \ + V(C7,4E,49,87), V(C1,D1,38,D9), V(FE,A2,CA,8C), V(36,0B,D4,98), \ + V(CF,81,F5,A6), V(28,DE,7A,A5), V(26,8E,B7,DA), V(A4,BF,AD,3F), \ + V(E4,9D,3A,2C), V(0D,92,78,50), V(9B,CC,5F,6A), V(62,46,7E,54), \ + V(C2,13,8D,F6), V(E8,B8,D8,90), V(5E,F7,39,2E), V(F5,AF,C3,82), \ + V(BE,80,5D,9F), V(7C,93,D0,69), V(A9,2D,D5,6F), V(B3,12,25,CF), \ + V(3B,99,AC,C8), V(A7,7D,18,10), V(6E,63,9C,E8), V(7B,BB,3B,DB), \ + V(09,78,26,CD), V(F4,18,59,6E), V(01,B7,9A,EC), V(A8,9A,4F,83), \ + V(65,6E,95,E6), V(7E,E6,FF,AA), V(08,CF,BC,21), V(E6,E8,15,EF), \ + V(D9,9B,E7,BA), V(CE,36,6F,4A), V(D4,09,9F,EA), V(D6,7C,B0,29), \ + V(AF,B2,A4,31), V(31,23,3F,2A), V(30,94,A5,C6), V(C0,66,A2,35), \ + V(37,BC,4E,74), V(A6,CA,82,FC), V(B0,D0,90,E0), V(15,D8,A7,33), \ + V(4A,98,04,F1), V(F7,DA,EC,41), V(0E,50,CD,7F), V(2F,F6,91,17), \ + V(8D,D6,4D,76), V(4D,B0,EF,43), V(54,4D,AA,CC), V(DF,04,96,E4), \ + V(E3,B5,D1,9E), V(1B,88,6A,4C), V(B8,1F,2C,C1), V(7F,51,65,46), \ + V(04,EA,5E,9D), V(5D,35,8C,01), V(73,74,87,FA), V(2E,41,0B,FB), \ + V(5A,1D,67,B3), V(52,D2,DB,92), V(33,56,10,E9), V(13,47,D6,6D), \ + V(8C,61,D7,9A), V(7A,0C,A1,37), V(8E,14,F8,59), V(89,3C,13,EB), \ + V(EE,27,A9,CE), V(35,C9,61,B7), V(ED,E5,1C,E1), V(3C,B1,47,7A), \ + V(59,DF,D2,9C), V(3F,73,F2,55), V(79,CE,14,18), V(BF,37,C7,73), \ + V(EA,CD,F7,53), V(5B,AA,FD,5F), V(14,6F,3D,DF), V(86,DB,44,78), \ + V(81,F3,AF,CA), V(3E,C4,68,B9), V(2C,34,24,38), V(5F,40,A3,C2), \ + V(72,C3,1D,16), V(0C,25,E2,BC), V(8B,49,3C,28), V(41,95,0D,FF), \ + V(71,01,A8,39), V(DE,B3,0C,08), V(9C,E4,B4,D8), V(90,C1,56,64), \ + V(61,84,CB,7B), V(70,B6,32,D5), V(74,5C,6C,48), V(42,57,B8,D0) + +#define V(a,b,c,d) 0x##a##b##c##d +static const uint32_t RT0[256] = { RT }; +#undef V + +#if !defined(MBEDTLS_AES_FEWER_TABLES) + +#define V(a,b,c,d) 0x##b##c##d##a +static const uint32_t RT1[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const uint32_t RT2[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const uint32_t RT3[256] = { RT }; +#undef V + +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + +#undef RT + +/* + * Round constants + */ +static const uint32_t RCON[10] = +{ + 0x00000001, 0x00000002, 0x00000004, 0x00000008, + 0x00000010, 0x00000020, 0x00000040, 0x00000080, + 0x0000001B, 0x00000036 +}; + +#else /* MBEDTLS_AES_ROM_TABLES */ + +/* + * Forward S-box & tables + */ +static unsigned char FSb[256]; +static uint32_t FT0[256]; +#if !defined(MBEDTLS_AES_FEWER_TABLES) +static uint32_t FT1[256]; +static uint32_t FT2[256]; +static uint32_t FT3[256]; +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + +/* + * Reverse S-box & tables + */ +static unsigned char RSb[256]; +static uint32_t RT0[256]; +#if !defined(MBEDTLS_AES_FEWER_TABLES) +static uint32_t RT1[256]; +static uint32_t RT2[256]; +static uint32_t RT3[256]; +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + +/* + * Round constants + */ +static uint32_t RCON[10]; + +/* + * Tables generation code + */ +#define ROTL8(x) ( ( (x) << 8 ) & 0xFFFFFFFF ) | ( (x) >> 24 ) +#define XTIME(x) ( ( (x) << 1 ) ^ ( ( (x) & 0x80 ) ? 0x1B : 0x00 ) ) +#define MUL(x,y) ( ( (x) && (y) ) ? pow[(log[(x)]+log[(y)]) % 255] : 0 ) + +static int aes_init_done = 0; + +static void aes_gen_tables( void ) +{ + int i, x, y, z; + int pow[256]; + int log[256]; + + /* + * compute pow and log tables over GF(2^8) + */ + for( i = 0, x = 1; i < 256; i++ ) + { + pow[i] = x; + log[x] = i; + x = ( x ^ XTIME( x ) ) & 0xFF; + } + + /* + * calculate the round constants + */ + for( i = 0, x = 1; i < 10; i++ ) + { + RCON[i] = (uint32_t) x; + x = XTIME( x ) & 0xFF; + } + + /* + * generate the forward and reverse S-boxes + */ + FSb[0x00] = 0x63; + RSb[0x63] = 0x00; + + for( i = 1; i < 256; i++ ) + { + x = pow[255 - log[i]]; + + y = x; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y ^ 0x63; + + FSb[i] = (unsigned char) x; + RSb[x] = (unsigned char) i; + } + + /* + * generate the forward and reverse tables + */ + for( i = 0; i < 256; i++ ) + { + x = FSb[i]; + y = XTIME( x ) & 0xFF; + z = ( y ^ x ) & 0xFF; + + FT0[i] = ( (uint32_t) y ) ^ + ( (uint32_t) x << 8 ) ^ + ( (uint32_t) x << 16 ) ^ + ( (uint32_t) z << 24 ); + +#if !defined(MBEDTLS_AES_FEWER_TABLES) + FT1[i] = ROTL8( FT0[i] ); + FT2[i] = ROTL8( FT1[i] ); + FT3[i] = ROTL8( FT2[i] ); +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + + x = RSb[i]; + + RT0[i] = ( (uint32_t) MUL( 0x0E, x ) ) ^ + ( (uint32_t) MUL( 0x09, x ) << 8 ) ^ + ( (uint32_t) MUL( 0x0D, x ) << 16 ) ^ + ( (uint32_t) MUL( 0x0B, x ) << 24 ); + +#if !defined(MBEDTLS_AES_FEWER_TABLES) + RT1[i] = ROTL8( RT0[i] ); + RT2[i] = ROTL8( RT1[i] ); + RT3[i] = ROTL8( RT2[i] ); +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + } +} + +#undef ROTL8 + +#endif /* MBEDTLS_AES_ROM_TABLES */ + +#if defined(MBEDTLS_AES_FEWER_TABLES) + +#define ROTL8(x) ( (uint32_t)( ( x ) << 8 ) + (uint32_t)( ( x ) >> 24 ) ) +#define ROTL16(x) ( (uint32_t)( ( x ) << 16 ) + (uint32_t)( ( x ) >> 16 ) ) +#define ROTL24(x) ( (uint32_t)( ( x ) << 24 ) + (uint32_t)( ( x ) >> 8 ) ) + +#define AES_RT0(idx) RT0[idx] +#define AES_RT1(idx) ROTL8( RT0[idx] ) +#define AES_RT2(idx) ROTL16( RT0[idx] ) +#define AES_RT3(idx) ROTL24( RT0[idx] ) + +#define AES_FT0(idx) FT0[idx] +#define AES_FT1(idx) ROTL8( FT0[idx] ) +#define AES_FT2(idx) ROTL16( FT0[idx] ) +#define AES_FT3(idx) ROTL24( FT0[idx] ) + +#else /* MBEDTLS_AES_FEWER_TABLES */ + +#define AES_RT0(idx) RT0[idx] +#define AES_RT1(idx) RT1[idx] +#define AES_RT2(idx) RT2[idx] +#define AES_RT3(idx) RT3[idx] + +#define AES_FT0(idx) FT0[idx] +#define AES_FT1(idx) FT1[idx] +#define AES_FT2(idx) FT2[idx] +#define AES_FT3(idx) FT3[idx] + +#endif /* MBEDTLS_AES_FEWER_TABLES */ + +void mbedtls_aes_init( mbedtls_aes_context *ctx ) +{ + AES_VALIDATE( ctx != NULL ); + + memset( ctx, 0, sizeof( mbedtls_aes_context ) ); +} + +void mbedtls_aes_free( mbedtls_aes_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_aes_context ) ); +} + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +void mbedtls_aes_xts_init( mbedtls_aes_xts_context *ctx ) +{ + AES_VALIDATE( ctx != NULL ); + + mbedtls_aes_init( &ctx->crypt ); + mbedtls_aes_init( &ctx->tweak ); +} + +void mbedtls_aes_xts_free( mbedtls_aes_xts_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_aes_free( &ctx->crypt ); + mbedtls_aes_free( &ctx->tweak ); +} +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +/* + * AES key schedule (encryption) + */ +#if !defined(MBEDTLS_AES_SETKEY_ENC_ALT) +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + unsigned int i; + uint32_t *RK; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( key != NULL ); + + switch( keybits ) + { + case 128: ctx->nr = 10; break; + case 192: ctx->nr = 12; break; + case 256: ctx->nr = 14; break; + default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + +#if !defined(MBEDTLS_AES_ROM_TABLES) + if( aes_init_done == 0 ) + { + aes_gen_tables(); + aes_init_done = 1; + } +#endif + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16) + if( aes_padlock_ace == -1 ) + aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE ); + + if( aes_padlock_ace ) + ctx->rk = RK = MBEDTLS_PADLOCK_ALIGN16( ctx->buf ); + else +#endif + ctx->rk = RK = ctx->buf; + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) ) + return( mbedtls_aesni_setkey_enc( (unsigned char *) ctx->rk, key, keybits ) ); +#endif + + for( i = 0; i < ( keybits >> 5 ); i++ ) + { + GET_UINT32_LE( RK[i], key, i << 2 ); + } + + switch( ctx->nr ) + { + case 10: + + for( i = 0; i < 10; i++, RK += 4 ) + { + RK[4] = RK[0] ^ RCON[i] ^ + ( (uint32_t) FSb[ ( RK[3] >> 8 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[3] >> 16 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[3] ) & 0xFF ] << 24 ); + + RK[5] = RK[1] ^ RK[4]; + RK[6] = RK[2] ^ RK[5]; + RK[7] = RK[3] ^ RK[6]; + } + break; + + case 12: + + for( i = 0; i < 8; i++, RK += 6 ) + { + RK[6] = RK[0] ^ RCON[i] ^ + ( (uint32_t) FSb[ ( RK[5] >> 8 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[5] >> 16 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[5] ) & 0xFF ] << 24 ); + + RK[7] = RK[1] ^ RK[6]; + RK[8] = RK[2] ^ RK[7]; + RK[9] = RK[3] ^ RK[8]; + RK[10] = RK[4] ^ RK[9]; + RK[11] = RK[5] ^ RK[10]; + } + break; + + case 14: + + for( i = 0; i < 7; i++, RK += 8 ) + { + RK[8] = RK[0] ^ RCON[i] ^ + ( (uint32_t) FSb[ ( RK[7] >> 8 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[7] >> 16 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[7] ) & 0xFF ] << 24 ); + + RK[9] = RK[1] ^ RK[8]; + RK[10] = RK[2] ^ RK[9]; + RK[11] = RK[3] ^ RK[10]; + + RK[12] = RK[4] ^ + ( (uint32_t) FSb[ ( RK[11] ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[11] >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 ); + + RK[13] = RK[5] ^ RK[12]; + RK[14] = RK[6] ^ RK[13]; + RK[15] = RK[7] ^ RK[14]; + } + break; + } + + return( 0 ); +} +#endif /* !MBEDTLS_AES_SETKEY_ENC_ALT */ + +/* + * AES key schedule (decryption) + */ +#if !defined(MBEDTLS_AES_SETKEY_DEC_ALT) +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + int i, j, ret; + mbedtls_aes_context cty; + uint32_t *RK; + uint32_t *SK; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( key != NULL ); + + mbedtls_aes_init( &cty ); + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16) + if( aes_padlock_ace == -1 ) + aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE ); + + if( aes_padlock_ace ) + ctx->rk = RK = MBEDTLS_PADLOCK_ALIGN16( ctx->buf ); + else +#endif + ctx->rk = RK = ctx->buf; + + /* Also checks keybits */ + if( ( ret = mbedtls_aes_setkey_enc( &cty, key, keybits ) ) != 0 ) + goto exit; + + ctx->nr = cty.nr; + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) ) + { + mbedtls_aesni_inverse_key( (unsigned char *) ctx->rk, + (const unsigned char *) cty.rk, ctx->nr ); + goto exit; + } +#endif + + SK = cty.rk + cty.nr * 4; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + for( i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8 ) + { + for( j = 0; j < 4; j++, SK++ ) + { + *RK++ = AES_RT0( FSb[ ( *SK ) & 0xFF ] ) ^ + AES_RT1( FSb[ ( *SK >> 8 ) & 0xFF ] ) ^ + AES_RT2( FSb[ ( *SK >> 16 ) & 0xFF ] ) ^ + AES_RT3( FSb[ ( *SK >> 24 ) & 0xFF ] ); + } + } + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + +exit: + mbedtls_aes_free( &cty ); + + return( ret ); +} + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +static int mbedtls_aes_xts_decode_keys( const unsigned char *key, + unsigned int keybits, + const unsigned char **key1, + unsigned int *key1bits, + const unsigned char **key2, + unsigned int *key2bits ) +{ + const unsigned int half_keybits = keybits / 2; + const unsigned int half_keybytes = half_keybits / 8; + + switch( keybits ) + { + case 256: break; + case 512: break; + default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + + *key1bits = half_keybits; + *key2bits = half_keybits; + *key1 = &key[0]; + *key2 = &key[half_keybytes]; + + return 0; +} + +int mbedtls_aes_xts_setkey_enc( mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits) +{ + int ret; + const unsigned char *key1, *key2; + unsigned int key1bits, key2bits; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( key != NULL ); + + ret = mbedtls_aes_xts_decode_keys( key, keybits, &key1, &key1bits, + &key2, &key2bits ); + if( ret != 0 ) + return( ret ); + + /* Set the tweak key. Always set tweak key for the encryption mode. */ + ret = mbedtls_aes_setkey_enc( &ctx->tweak, key2, key2bits ); + if( ret != 0 ) + return( ret ); + + /* Set crypt key for encryption. */ + return mbedtls_aes_setkey_enc( &ctx->crypt, key1, key1bits ); +} + +int mbedtls_aes_xts_setkey_dec( mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits) +{ + int ret; + const unsigned char *key1, *key2; + unsigned int key1bits, key2bits; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( key != NULL ); + + ret = mbedtls_aes_xts_decode_keys( key, keybits, &key1, &key1bits, + &key2, &key2bits ); + if( ret != 0 ) + return( ret ); + + /* Set the tweak key. Always set tweak key for encryption. */ + ret = mbedtls_aes_setkey_enc( &ctx->tweak, key2, key2bits ); + if( ret != 0 ) + return( ret ); + + /* Set crypt key for decryption. */ + return mbedtls_aes_setkey_dec( &ctx->crypt, key1, key1bits ); +} +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#endif /* !MBEDTLS_AES_SETKEY_DEC_ALT */ + +#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ + do \ + { \ + (X0) = *RK++ ^ AES_FT0( ( (Y0) ) & 0xFF ) ^ \ + AES_FT1( ( (Y1) >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( (Y2) >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( (Y3) >> 24 ) & 0xFF ); \ + \ + (X1) = *RK++ ^ AES_FT0( ( (Y1) ) & 0xFF ) ^ \ + AES_FT1( ( (Y2) >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( (Y3) >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( (Y0) >> 24 ) & 0xFF ); \ + \ + (X2) = *RK++ ^ AES_FT0( ( (Y2) ) & 0xFF ) ^ \ + AES_FT1( ( (Y3) >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( (Y0) >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( (Y1) >> 24 ) & 0xFF ); \ + \ + (X3) = *RK++ ^ AES_FT0( ( (Y3) ) & 0xFF ) ^ \ + AES_FT1( ( (Y0) >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( (Y1) >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( (Y2) >> 24 ) & 0xFF ); \ + } while( 0 ) + +#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ + do \ + { \ + (X0) = *RK++ ^ AES_RT0( ( (Y0) ) & 0xFF ) ^ \ + AES_RT1( ( (Y3) >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( (Y2) >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( (Y1) >> 24 ) & 0xFF ); \ + \ + (X1) = *RK++ ^ AES_RT0( ( (Y1) ) & 0xFF ) ^ \ + AES_RT1( ( (Y0) >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( (Y3) >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( (Y2) >> 24 ) & 0xFF ); \ + \ + (X2) = *RK++ ^ AES_RT0( ( (Y2) ) & 0xFF ) ^ \ + AES_RT1( ( (Y1) >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( (Y0) >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( (Y3) >> 24 ) & 0xFF ); \ + \ + (X3) = *RK++ ^ AES_RT0( ( (Y3) ) & 0xFF ) ^ \ + AES_RT1( ( (Y2) >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( (Y1) >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( (Y0) >> 24 ) & 0xFF ); \ + } while( 0 ) + +/* + * AES-ECB block encryption + */ +#if !defined(MBEDTLS_AES_ENCRYPT_ALT) +int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + int i; + uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->rk; + + GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++; + GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++; + GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++; + GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++; + + for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- ) + { + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y0 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); + + X1 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y1 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); + + X2 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y2 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); + + X3 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y3 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); + + PUT_UINT32_LE( X0, output, 0 ); + PUT_UINT32_LE( X1, output, 4 ); + PUT_UINT32_LE( X2, output, 8 ); + PUT_UINT32_LE( X3, output, 12 ); + + return( 0 ); +} +#endif /* !MBEDTLS_AES_ENCRYPT_ALT */ + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + mbedtls_internal_aes_encrypt( ctx, input, output ); +} +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/* + * AES-ECB block decryption + */ +#if !defined(MBEDTLS_AES_DECRYPT_ALT) +int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + int i; + uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->rk; + + GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++; + GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++; + GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++; + GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++; + + for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- ) + { + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y0 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); + + X1 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y1 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); + + X2 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y2 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); + + X3 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y3 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); + + PUT_UINT32_LE( X0, output, 0 ); + PUT_UINT32_LE( X1, output, 4 ); + PUT_UINT32_LE( X2, output, 8 ); + PUT_UINT32_LE( X3, output, 12 ); + + return( 0 ); +} +#endif /* !MBEDTLS_AES_DECRYPT_ALT */ + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + mbedtls_internal_aes_decrypt( ctx, input, output ); +} +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/* + * AES-ECB block encryption/decryption + */ +int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( input != NULL ); + AES_VALIDATE_RET( output != NULL ); + AES_VALIDATE_RET( mode == MBEDTLS_AES_ENCRYPT || + mode == MBEDTLS_AES_DECRYPT ); + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) ) + return( mbedtls_aesni_crypt_ecb( ctx, mode, input, output ) ); +#endif + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86) + if( aes_padlock_ace ) + { + if( mbedtls_padlock_xcryptecb( ctx, mode, input, output ) == 0 ) + return( 0 ); + + // If padlock data misaligned, we just fall back to + // unaccelerated mode + // + } +#endif + + if( mode == MBEDTLS_AES_ENCRYPT ) + return( mbedtls_internal_aes_encrypt( ctx, input, output ) ); + else + return( mbedtls_internal_aes_decrypt( ctx, input, output ) ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * AES-CBC buffer encryption/decryption + */ +int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[16]; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( mode == MBEDTLS_AES_ENCRYPT || + mode == MBEDTLS_AES_DECRYPT ); + AES_VALIDATE_RET( iv != NULL ); + AES_VALIDATE_RET( input != NULL ); + AES_VALIDATE_RET( output != NULL ); + + if( length % 16 ) + return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86) + if( aes_padlock_ace ) + { + if( mbedtls_padlock_xcryptcbc( ctx, mode, length, iv, input, output ) == 0 ) + return( 0 ); + + // If padlock data misaligned, we just fall back to + // unaccelerated mode + // + } +#endif + + if( mode == MBEDTLS_AES_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 16 ); + mbedtls_aes_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_aes_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) + +/* Endianess with 64 bits values */ +#ifndef GET_UINT64_LE +#define GET_UINT64_LE(n,b,i) \ +{ \ + (n) = ( (uint64_t) (b)[(i) + 7] << 56 ) \ + | ( (uint64_t) (b)[(i) + 6] << 48 ) \ + | ( (uint64_t) (b)[(i) + 5] << 40 ) \ + | ( (uint64_t) (b)[(i) + 4] << 32 ) \ + | ( (uint64_t) (b)[(i) + 3] << 24 ) \ + | ( (uint64_t) (b)[(i) + 2] << 16 ) \ + | ( (uint64_t) (b)[(i) + 1] << 8 ) \ + | ( (uint64_t) (b)[(i) ] ); \ +} +#endif + +#ifndef PUT_UINT64_LE +#define PUT_UINT64_LE(n,b,i) \ +{ \ + (b)[(i) + 7] = (unsigned char) ( (n) >> 56 ); \ + (b)[(i) + 6] = (unsigned char) ( (n) >> 48 ); \ + (b)[(i) + 5] = (unsigned char) ( (n) >> 40 ); \ + (b)[(i) + 4] = (unsigned char) ( (n) >> 32 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) ] = (unsigned char) ( (n) ); \ +} +#endif + +typedef unsigned char mbedtls_be128[16]; + +/* + * GF(2^128) multiplication function + * + * This function multiplies a field element by x in the polynomial field + * representation. It uses 64-bit word operations to gain speed but compensates + * for machine endianess and hence works correctly on both big and little + * endian machines. + */ +static void mbedtls_gf128mul_x_ble( unsigned char r[16], + const unsigned char x[16] ) +{ + uint64_t a, b, ra, rb; + + GET_UINT64_LE( a, x, 0 ); + GET_UINT64_LE( b, x, 8 ); + + ra = ( a << 1 ) ^ 0x0087 >> ( 8 - ( ( b >> 63 ) << 3 ) ); + rb = ( a >> 63 ) | ( b << 1 ); + + PUT_UINT64_LE( ra, r, 0 ); + PUT_UINT64_LE( rb, r, 8 ); +} + +/* + * AES-XTS buffer encryption/decryption + */ +int mbedtls_aes_crypt_xts( mbedtls_aes_xts_context *ctx, + int mode, + size_t length, + const unsigned char data_unit[16], + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t blocks = length / 16; + size_t leftover = length % 16; + unsigned char tweak[16]; + unsigned char prev_tweak[16]; + unsigned char tmp[16]; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( mode == MBEDTLS_AES_ENCRYPT || + mode == MBEDTLS_AES_DECRYPT ); + AES_VALIDATE_RET( data_unit != NULL ); + AES_VALIDATE_RET( input != NULL ); + AES_VALIDATE_RET( output != NULL ); + + /* Data units must be at least 16 bytes long. */ + if( length < 16 ) + return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; + + /* NIST SP 800-38E disallows data units larger than 2**20 blocks. */ + if( length > ( 1 << 20 ) * 16 ) + return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; + + /* Compute the tweak. */ + ret = mbedtls_aes_crypt_ecb( &ctx->tweak, MBEDTLS_AES_ENCRYPT, + data_unit, tweak ); + if( ret != 0 ) + return( ret ); + + while( blocks-- ) + { + size_t i; + + if( leftover && ( mode == MBEDTLS_AES_DECRYPT ) && blocks == 0 ) + { + /* We are on the last block in a decrypt operation that has + * leftover bytes, so we need to use the next tweak for this block, + * and this tweak for the lefover bytes. Save the current tweak for + * the leftovers and then update the current tweak for use on this, + * the last full block. */ + memcpy( prev_tweak, tweak, sizeof( tweak ) ); + mbedtls_gf128mul_x_ble( tweak, tweak ); + } + + for( i = 0; i < 16; i++ ) + tmp[i] = input[i] ^ tweak[i]; + + ret = mbedtls_aes_crypt_ecb( &ctx->crypt, mode, tmp, tmp ); + if( ret != 0 ) + return( ret ); + + for( i = 0; i < 16; i++ ) + output[i] = tmp[i] ^ tweak[i]; + + /* Update the tweak for the next block. */ + mbedtls_gf128mul_x_ble( tweak, tweak ); + + output += 16; + input += 16; + } + + if( leftover ) + { + /* If we are on the leftover bytes in a decrypt operation, we need to + * use the previous tweak for these bytes (as saved in prev_tweak). */ + unsigned char *t = mode == MBEDTLS_AES_DECRYPT ? prev_tweak : tweak; + + /* We are now on the final part of the data unit, which doesn't divide + * evenly by 16. It's time for ciphertext stealing. */ + size_t i; + unsigned char *prev_output = output - 16; + + /* Copy ciphertext bytes from the previous block to our output for each + * byte of cyphertext we won't steal. At the same time, copy the + * remainder of the input for this final round (since the loop bounds + * are the same). */ + for( i = 0; i < leftover; i++ ) + { + output[i] = prev_output[i]; + tmp[i] = input[i] ^ t[i]; + } + + /* Copy ciphertext bytes from the previous block for input in this + * round. */ + for( ; i < 16; i++ ) + tmp[i] = prev_output[i] ^ t[i]; + + ret = mbedtls_aes_crypt_ecb( &ctx->crypt, mode, tmp, tmp ); + if( ret != 0 ) + return ret; + + /* Write the result back to the previous block, overriding the previous + * output we copied. */ + for( i = 0; i < 16; i++ ) + prev_output[i] = tmp[i] ^ t[i]; + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * AES-CFB128 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( mode == MBEDTLS_AES_ENCRYPT || + mode == MBEDTLS_AES_DECRYPT ); + AES_VALIDATE_RET( iv_off != NULL ); + AES_VALIDATE_RET( iv != NULL ); + AES_VALIDATE_RET( input != NULL ); + AES_VALIDATE_RET( output != NULL ); + + n = *iv_off; + + if( n > 15 ) + return( MBEDTLS_ERR_AES_BAD_INPUT_DATA ); + + if( mode == MBEDTLS_AES_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} + +/* + * AES-CFB8 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + unsigned char c; + unsigned char ov[17]; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( mode == MBEDTLS_AES_ENCRYPT || + mode == MBEDTLS_AES_DECRYPT ); + AES_VALIDATE_RET( iv != NULL ); + AES_VALIDATE_RET( input != NULL ); + AES_VALIDATE_RET( output != NULL ); + while( length-- ) + { + memcpy( ov, iv, 16 ); + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + if( mode == MBEDTLS_AES_DECRYPT ) + ov[16] = *input; + + c = *output++ = (unsigned char)( iv[0] ^ *input++ ); + + if( mode == MBEDTLS_AES_ENCRYPT ) + ov[16] = c; + + memcpy( iv, ov + 1, 16 ); + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +/* + * AES-OFB (Output Feedback Mode) buffer encryption/decryption + */ +int mbedtls_aes_crypt_ofb( mbedtls_aes_context *ctx, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int ret = 0; + size_t n; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( iv_off != NULL ); + AES_VALIDATE_RET( iv != NULL ); + AES_VALIDATE_RET( input != NULL ); + AES_VALIDATE_RET( output != NULL ); + + n = *iv_off; + + if( n > 15 ) + return( MBEDTLS_ERR_AES_BAD_INPUT_DATA ); + + while( length-- ) + { + if( n == 0 ) + { + ret = mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + if( ret != 0 ) + goto exit; + } + *output++ = *input++ ^ iv[n]; + + n = ( n + 1 ) & 0x0F; + } + + *iv_off = n; + +exit: + return( ret ); +} +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * AES-CTR buffer encryption/decryption + */ +int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n; + + AES_VALIDATE_RET( ctx != NULL ); + AES_VALIDATE_RET( nc_off != NULL ); + AES_VALIDATE_RET( nonce_counter != NULL ); + AES_VALIDATE_RET( stream_block != NULL ); + AES_VALIDATE_RET( input != NULL ); + AES_VALIDATE_RET( output != NULL ); + + n = *nc_off; + + if ( n > 0x0F ) + return( MBEDTLS_ERR_AES_BAD_INPUT_DATA ); + + while( length-- ) + { + if( n == 0 ) { + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, nonce_counter, stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#endif /* !MBEDTLS_AES_ALT */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * AES test vectors from: + * + * http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip + */ +static const unsigned char aes_test_ecb_dec[3][16] = +{ + { 0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58, + 0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0 }, + { 0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2, + 0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4 }, + { 0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D, + 0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE } +}; + +static const unsigned char aes_test_ecb_enc[3][16] = +{ + { 0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73, + 0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F }, + { 0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11, + 0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14 }, + { 0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D, + 0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4 } +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const unsigned char aes_test_cbc_dec[3][16] = +{ + { 0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73, + 0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86 }, + { 0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75, + 0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B }, + { 0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75, + 0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13 } +}; + +static const unsigned char aes_test_cbc_enc[3][16] = +{ + { 0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84, + 0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D }, + { 0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB, + 0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04 }, + { 0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5, + 0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * AES-CFB128 test vectors from: + * + * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + */ +static const unsigned char aes_test_cfb128_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }, + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }, + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char aes_test_cfb128_iv[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; + +static const unsigned char aes_test_cfb128_pt[64] = +{ + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 +}; + +static const unsigned char aes_test_cfb128_ct[3][64] = +{ + { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, + 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A, + 0xC8, 0xA6, 0x45, 0x37, 0xA0, 0xB3, 0xA9, 0x3F, + 0xCD, 0xE3, 0xCD, 0xAD, 0x9F, 0x1C, 0xE5, 0x8B, + 0x26, 0x75, 0x1F, 0x67, 0xA3, 0xCB, 0xB1, 0x40, + 0xB1, 0x80, 0x8C, 0xF1, 0x87, 0xA4, 0xF4, 0xDF, + 0xC0, 0x4B, 0x05, 0x35, 0x7C, 0x5D, 0x1C, 0x0E, + 0xEA, 0xC4, 0xC6, 0x6F, 0x9F, 0xF7, 0xF2, 0xE6 }, + { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB, + 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74, + 0x67, 0xCE, 0x7F, 0x7F, 0x81, 0x17, 0x36, 0x21, + 0x96, 0x1A, 0x2B, 0x70, 0x17, 0x1D, 0x3D, 0x7A, + 0x2E, 0x1E, 0x8A, 0x1D, 0xD5, 0x9B, 0x88, 0xB1, + 0xC8, 0xE6, 0x0F, 0xED, 0x1E, 0xFA, 0xC4, 0xC9, + 0xC0, 0x5F, 0x9F, 0x9C, 0xA9, 0x83, 0x4F, 0xA0, + 0x42, 0xAE, 0x8F, 0xBA, 0x58, 0x4B, 0x09, 0xFF }, + { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B, + 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60, + 0x39, 0xFF, 0xED, 0x14, 0x3B, 0x28, 0xB1, 0xC8, + 0x32, 0x11, 0x3C, 0x63, 0x31, 0xE5, 0x40, 0x7B, + 0xDF, 0x10, 0x13, 0x24, 0x15, 0xE5, 0x4B, 0x92, + 0xA1, 0x3E, 0xD0, 0xA8, 0x26, 0x7A, 0xE2, 0xF9, + 0x75, 0xA3, 0x85, 0x74, 0x1A, 0xB9, 0xCE, 0xF8, + 0x20, 0x31, 0x62, 0x3D, 0x55, 0xB1, 0xE4, 0x71 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +/* + * AES-OFB test vectors from: + * + * https://csrc.nist.gov/publications/detail/sp/800-38a/final + */ +static const unsigned char aes_test_ofb_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }, + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }, + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char aes_test_ofb_iv[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; + +static const unsigned char aes_test_ofb_pt[64] = +{ + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 +}; + +static const unsigned char aes_test_ofb_ct[3][64] = +{ + { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, + 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A, + 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, + 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25, + 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, + 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc, + 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, + 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e }, + { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB, + 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74, + 0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c, + 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01, + 0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f, + 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2, + 0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, + 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a }, + { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B, + 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60, + 0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, + 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d, + 0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, + 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08, + 0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, + 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84 } +}; +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * AES-CTR test vectors from: + * + * http://www.faqs.org/rfcs/rfc3686.html + */ + +static const unsigned char aes_test_ctr_key[3][16] = +{ + { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E }, + { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7, + 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 }, + { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, + 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC } +}; + +static const unsigned char aes_test_ctr_nonce_counter[3][16] = +{ + { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59, + 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F, + 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 } +}; + +static const unsigned char aes_test_ctr_pt[3][48] = +{ + { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 } +}; + +static const unsigned char aes_test_ctr_ct[3][48] = +{ + { 0xE4, 0x09, 0x5D, 0x4F, 0xB7, 0xA7, 0xB3, 0x79, + 0x2D, 0x61, 0x75, 0xA3, 0x26, 0x13, 0x11, 0xB8 }, + { 0x51, 0x04, 0xA1, 0x06, 0x16, 0x8A, 0x72, 0xD9, + 0x79, 0x0D, 0x41, 0xEE, 0x8E, 0xDA, 0xD3, 0x88, + 0xEB, 0x2E, 0x1E, 0xFC, 0x46, 0xDA, 0x57, 0xC8, + 0xFC, 0xE6, 0x30, 0xDF, 0x91, 0x41, 0xBE, 0x28 }, + { 0xC1, 0xCF, 0x48, 0xA8, 0x9F, 0x2F, 0xFD, 0xD9, + 0xCF, 0x46, 0x52, 0xE9, 0xEF, 0xDB, 0x72, 0xD7, + 0x45, 0x40, 0xA4, 0x2B, 0xDE, 0x6D, 0x78, 0x36, + 0xD5, 0x9A, 0x5C, 0xEA, 0xAE, 0xF3, 0x10, 0x53, + 0x25, 0xB2, 0x07, 0x2F } +}; + +static const int aes_test_ctr_len[3] = + { 16, 32, 36 }; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/* + * AES-XTS test vectors from: + * + * IEEE P1619/D16 Annex B + * https://web.archive.org/web/20150629024421/http://grouper.ieee.org/groups/1619/email/pdf00086.pdf + * (Archived from original at http://grouper.ieee.org/groups/1619/email/pdf00086.pdf) + */ +static const unsigned char aes_test_xts_key[][32] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }, + { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, + 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }, +}; + +static const unsigned char aes_test_xts_pt32[][32] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }, + { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }, +}; + +static const unsigned char aes_test_xts_ct32[][32] = +{ + { 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec, + 0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92, + 0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85, + 0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e }, + { 0xc4, 0x54, 0x18, 0x5e, 0x6a, 0x16, 0x93, 0x6e, + 0x39, 0x33, 0x40, 0x38, 0xac, 0xef, 0x83, 0x8b, + 0xfb, 0x18, 0x6f, 0xff, 0x74, 0x80, 0xad, 0xc4, + 0x28, 0x93, 0x82, 0xec, 0xd6, 0xd3, 0x94, 0xf0 }, + { 0xaf, 0x85, 0x33, 0x6b, 0x59, 0x7a, 0xfc, 0x1a, + 0x90, 0x0b, 0x2e, 0xb2, 0x1e, 0xc9, 0x49, 0xd2, + 0x92, 0xdf, 0x4c, 0x04, 0x7e, 0x0b, 0x21, 0x53, + 0x21, 0x86, 0xa5, 0x97, 0x1a, 0x22, 0x7a, 0x89 }, +}; + +static const unsigned char aes_test_xts_data_unit[][16] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +}; + +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +/* + * Checkup routine + */ +int mbedtls_aes_self_test( int verbose ) +{ + int ret = 0, i, j, u, mode; + unsigned int keybits; + unsigned char key[32]; + unsigned char buf[64]; + const unsigned char *aes_tests; +#if defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB) + unsigned char iv[16]; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + unsigned char prv[16]; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_CFB) || \ + defined(MBEDTLS_CIPHER_MODE_OFB) + size_t offset; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_XTS) + int len; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; +#endif + mbedtls_aes_context ctx; + + memset( key, 0, 32 ); + mbedtls_aes_init( &ctx ); + + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-ECB-%3d (%s): ", keybits, + ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memset( buf, 0, 16 ); + + if( mode == MBEDTLS_AES_DECRYPT ) + { + ret = mbedtls_aes_setkey_dec( &ctx, key, keybits ); + aes_tests = aes_test_ecb_dec[u]; + } + else + { + ret = mbedtls_aes_setkey_enc( &ctx, key, keybits ); + aes_tests = aes_test_ecb_enc[u]; + } + + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation i.e. when + * MBEDTLS_AES_ALT is defined. + */ + if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192 ) + { + mbedtls_printf( "skipped\n" ); + continue; + } + else if( ret != 0 ) + { + goto exit; + } + + for( j = 0; j < 10000; j++ ) + { + ret = mbedtls_aes_crypt_ecb( &ctx, mode, buf, buf ); + if( ret != 0 ) + goto exit; + } + + if( memcmp( buf, aes_tests, 16 ) != 0 ) + { + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-CBC-%3d (%s): ", keybits, + ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memset( iv , 0, 16 ); + memset( prv, 0, 16 ); + memset( buf, 0, 16 ); + + if( mode == MBEDTLS_AES_DECRYPT ) + { + ret = mbedtls_aes_setkey_dec( &ctx, key, keybits ); + aes_tests = aes_test_cbc_dec[u]; + } + else + { + ret = mbedtls_aes_setkey_enc( &ctx, key, keybits ); + aes_tests = aes_test_cbc_enc[u]; + } + + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation i.e. when + * MBEDTLS_AES_ALT is defined. + */ + if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192 ) + { + mbedtls_printf( "skipped\n" ); + continue; + } + else if( ret != 0 ) + { + goto exit; + } + + for( j = 0; j < 10000; j++ ) + { + if( mode == MBEDTLS_AES_ENCRYPT ) + { + unsigned char tmp[16]; + + memcpy( tmp, prv, 16 ); + memcpy( prv, buf, 16 ); + memcpy( buf, tmp, 16 ); + } + + ret = mbedtls_aes_crypt_cbc( &ctx, mode, 16, iv, buf, buf ); + if( ret != 0 ) + goto exit; + + } + + if( memcmp( buf, aes_tests, 16 ) != 0 ) + { + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + /* + * CFB128 mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-CFB128-%3d (%s): ", keybits, + ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, aes_test_cfb128_iv, 16 ); + memcpy( key, aes_test_cfb128_key[u], keybits / 8 ); + + offset = 0; + ret = mbedtls_aes_setkey_enc( &ctx, key, keybits ); + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation i.e. when + * MBEDTLS_AES_ALT is defined. + */ + if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192 ) + { + mbedtls_printf( "skipped\n" ); + continue; + } + else if( ret != 0 ) + { + goto exit; + } + + if( mode == MBEDTLS_AES_DECRYPT ) + { + memcpy( buf, aes_test_cfb128_ct[u], 64 ); + aes_tests = aes_test_cfb128_pt; + } + else + { + memcpy( buf, aes_test_cfb128_pt, 64 ); + aes_tests = aes_test_cfb128_ct[u]; + } + + ret = mbedtls_aes_crypt_cfb128( &ctx, mode, 64, &offset, iv, buf, buf ); + if( ret != 0 ) + goto exit; + + if( memcmp( buf, aes_tests, 64 ) != 0 ) + { + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) + /* + * OFB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-OFB-%3d (%s): ", keybits, + ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, aes_test_ofb_iv, 16 ); + memcpy( key, aes_test_ofb_key[u], keybits / 8 ); + + offset = 0; + ret = mbedtls_aes_setkey_enc( &ctx, key, keybits ); + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation i.e. when + * MBEDTLS_AES_ALT is defined. + */ + if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && keybits == 192 ) + { + mbedtls_printf( "skipped\n" ); + continue; + } + else if( ret != 0 ) + { + goto exit; + } + + if( mode == MBEDTLS_AES_DECRYPT ) + { + memcpy( buf, aes_test_ofb_ct[u], 64 ); + aes_tests = aes_test_ofb_pt; + } + else + { + memcpy( buf, aes_test_ofb_pt, 64 ); + aes_tests = aes_test_ofb_ct[u]; + } + + ret = mbedtls_aes_crypt_ofb( &ctx, 64, &offset, iv, buf, buf ); + if( ret != 0 ) + goto exit; + + if( memcmp( buf, aes_tests, 64 ) != 0 ) + { + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /* + * CTR mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + mode = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-CTR-128 (%s): ", + ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( nonce_counter, aes_test_ctr_nonce_counter[u], 16 ); + memcpy( key, aes_test_ctr_key[u], 16 ); + + offset = 0; + if( ( ret = mbedtls_aes_setkey_enc( &ctx, key, 128 ) ) != 0 ) + goto exit; + + len = aes_test_ctr_len[u]; + + if( mode == MBEDTLS_AES_DECRYPT ) + { + memcpy( buf, aes_test_ctr_ct[u], len ); + aes_tests = aes_test_ctr_pt[u]; + } + else + { + memcpy( buf, aes_test_ctr_pt[u], len ); + aes_tests = aes_test_ctr_ct[u]; + } + + ret = mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter, + stream_block, buf, buf ); + if( ret != 0 ) + goto exit; + + if( memcmp( buf, aes_tests, len ) != 0 ) + { + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) + { + static const int num_tests = + sizeof(aes_test_xts_key) / sizeof(*aes_test_xts_key); + mbedtls_aes_xts_context ctx_xts; + + /* + * XTS mode + */ + mbedtls_aes_xts_init( &ctx_xts ); + + for( i = 0; i < num_tests << 1; i++ ) + { + const unsigned char *data_unit; + u = i >> 1; + mode = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-XTS-128 (%s): ", + ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memset( key, 0, sizeof( key ) ); + memcpy( key, aes_test_xts_key[u], 32 ); + data_unit = aes_test_xts_data_unit[u]; + + len = sizeof( *aes_test_xts_ct32 ); + + if( mode == MBEDTLS_AES_DECRYPT ) + { + ret = mbedtls_aes_xts_setkey_dec( &ctx_xts, key, 256 ); + if( ret != 0) + goto exit; + memcpy( buf, aes_test_xts_ct32[u], len ); + aes_tests = aes_test_xts_pt32[u]; + } + else + { + ret = mbedtls_aes_xts_setkey_enc( &ctx_xts, key, 256 ); + if( ret != 0) + goto exit; + memcpy( buf, aes_test_xts_pt32[u], len ); + aes_tests = aes_test_xts_ct32[u]; + } + + + ret = mbedtls_aes_crypt_xts( &ctx_xts, mode, len, data_unit, + buf, buf ); + if( ret != 0 ) + goto exit; + + if( memcmp( buf, aes_tests, len ) != 0 ) + { + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + mbedtls_aes_xts_free( &ctx_xts ); + } +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + + ret = 0; + +exit: + if( ret != 0 && verbose != 0 ) + mbedtls_printf( "failed\n" ); + + mbedtls_aes_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_AES_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/aesni.c b/FreeRTOS-Labs/Source/mbedtls/library/aesni.c new file mode 100644 index 000000000..cd0bbd3a9 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/aesni.c @@ -0,0 +1,470 @@ +/* + * AES-NI support functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * [AES-WP] http://software.intel.com/en-us/articles/intel-advanced-encryption-standard-aes-instructions-set + * [CLMUL-WP] http://software.intel.com/en-us/articles/intel-carry-less-multiplication-instruction-and-its-usage-for-computing-the-gcm-mode/ + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_AESNI_C) + +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) +#warning "MBEDTLS_AESNI_C is known to cause spurious error reports with some memory sanitizers as they do not understand the assembly code." +#endif +#endif + +#include "mbedtls/aesni.h" + +#include + +#ifndef asm +#define asm __asm +#endif + +#if defined(MBEDTLS_HAVE_X86_64) + +/* + * AES-NI support detection routine + */ +int mbedtls_aesni_has_support( unsigned int what ) +{ + static int done = 0; + static unsigned int c = 0; + + if( ! done ) + { + asm( "movl $1, %%eax \n\t" + "cpuid \n\t" + : "=c" (c) + : + : "eax", "ebx", "edx" ); + done = 1; + } + + return( ( c & what ) != 0 ); +} + +/* + * Binutils needs to be at least 2.19 to support AES-NI instructions. + * Unfortunately, a lot of users have a lower version now (2014-04). + * Emit bytecode directly in order to support "old" version of gas. + * + * Opcodes from the Intel architecture reference manual, vol. 3. + * We always use registers, so we don't need prefixes for memory operands. + * Operand macros are in gas order (src, dst) as opposed to Intel order + * (dst, src) in order to blend better into the surrounding assembly code. + */ +#define AESDEC ".byte 0x66,0x0F,0x38,0xDE," +#define AESDECLAST ".byte 0x66,0x0F,0x38,0xDF," +#define AESENC ".byte 0x66,0x0F,0x38,0xDC," +#define AESENCLAST ".byte 0x66,0x0F,0x38,0xDD," +#define AESIMC ".byte 0x66,0x0F,0x38,0xDB," +#define AESKEYGENA ".byte 0x66,0x0F,0x3A,0xDF," +#define PCLMULQDQ ".byte 0x66,0x0F,0x3A,0x44," + +#define xmm0_xmm0 "0xC0" +#define xmm0_xmm1 "0xC8" +#define xmm0_xmm2 "0xD0" +#define xmm0_xmm3 "0xD8" +#define xmm0_xmm4 "0xE0" +#define xmm1_xmm0 "0xC1" +#define xmm1_xmm2 "0xD1" + +/* + * AES-NI AES-ECB block en(de)cryption + */ +int mbedtls_aesni_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + asm( "movdqu (%3), %%xmm0 \n\t" // load input + "movdqu (%1), %%xmm1 \n\t" // load round key 0 + "pxor %%xmm1, %%xmm0 \n\t" // round 0 + "add $16, %1 \n\t" // point to next round key + "subl $1, %0 \n\t" // normal rounds = nr - 1 + "test %2, %2 \n\t" // mode? + "jz 2f \n\t" // 0 = decrypt + + "1: \n\t" // encryption loop + "movdqu (%1), %%xmm1 \n\t" // load round key + AESENC xmm1_xmm0 "\n\t" // do round + "add $16, %1 \n\t" // point to next round key + "subl $1, %0 \n\t" // loop + "jnz 1b \n\t" + "movdqu (%1), %%xmm1 \n\t" // load round key + AESENCLAST xmm1_xmm0 "\n\t" // last round + "jmp 3f \n\t" + + "2: \n\t" // decryption loop + "movdqu (%1), %%xmm1 \n\t" + AESDEC xmm1_xmm0 "\n\t" // do round + "add $16, %1 \n\t" + "subl $1, %0 \n\t" + "jnz 2b \n\t" + "movdqu (%1), %%xmm1 \n\t" // load round key + AESDECLAST xmm1_xmm0 "\n\t" // last round + + "3: \n\t" + "movdqu %%xmm0, (%4) \n\t" // export output + : + : "r" (ctx->nr), "r" (ctx->rk), "r" (mode), "r" (input), "r" (output) + : "memory", "cc", "xmm0", "xmm1" ); + + + return( 0 ); +} + +/* + * GCM multiplication: c = a times b in GF(2^128) + * Based on [CLMUL-WP] algorithms 1 (with equation 27) and 5. + */ +void mbedtls_aesni_gcm_mult( unsigned char c[16], + const unsigned char a[16], + const unsigned char b[16] ) +{ + unsigned char aa[16], bb[16], cc[16]; + size_t i; + + /* The inputs are in big-endian order, so byte-reverse them */ + for( i = 0; i < 16; i++ ) + { + aa[i] = a[15 - i]; + bb[i] = b[15 - i]; + } + + asm( "movdqu (%0), %%xmm0 \n\t" // a1:a0 + "movdqu (%1), %%xmm1 \n\t" // b1:b0 + + /* + * Caryless multiplication xmm2:xmm1 = xmm0 * xmm1 + * using [CLMUL-WP] algorithm 1 (p. 13). + */ + "movdqa %%xmm1, %%xmm2 \n\t" // copy of b1:b0 + "movdqa %%xmm1, %%xmm3 \n\t" // same + "movdqa %%xmm1, %%xmm4 \n\t" // same + PCLMULQDQ xmm0_xmm1 ",0x00 \n\t" // a0*b0 = c1:c0 + PCLMULQDQ xmm0_xmm2 ",0x11 \n\t" // a1*b1 = d1:d0 + PCLMULQDQ xmm0_xmm3 ",0x10 \n\t" // a0*b1 = e1:e0 + PCLMULQDQ xmm0_xmm4 ",0x01 \n\t" // a1*b0 = f1:f0 + "pxor %%xmm3, %%xmm4 \n\t" // e1+f1:e0+f0 + "movdqa %%xmm4, %%xmm3 \n\t" // same + "psrldq $8, %%xmm4 \n\t" // 0:e1+f1 + "pslldq $8, %%xmm3 \n\t" // e0+f0:0 + "pxor %%xmm4, %%xmm2 \n\t" // d1:d0+e1+f1 + "pxor %%xmm3, %%xmm1 \n\t" // c1+e0+f1:c0 + + /* + * Now shift the result one bit to the left, + * taking advantage of [CLMUL-WP] eq 27 (p. 20) + */ + "movdqa %%xmm1, %%xmm3 \n\t" // r1:r0 + "movdqa %%xmm2, %%xmm4 \n\t" // r3:r2 + "psllq $1, %%xmm1 \n\t" // r1<<1:r0<<1 + "psllq $1, %%xmm2 \n\t" // r3<<1:r2<<1 + "psrlq $63, %%xmm3 \n\t" // r1>>63:r0>>63 + "psrlq $63, %%xmm4 \n\t" // r3>>63:r2>>63 + "movdqa %%xmm3, %%xmm5 \n\t" // r1>>63:r0>>63 + "pslldq $8, %%xmm3 \n\t" // r0>>63:0 + "pslldq $8, %%xmm4 \n\t" // r2>>63:0 + "psrldq $8, %%xmm5 \n\t" // 0:r1>>63 + "por %%xmm3, %%xmm1 \n\t" // r1<<1|r0>>63:r0<<1 + "por %%xmm4, %%xmm2 \n\t" // r3<<1|r2>>62:r2<<1 + "por %%xmm5, %%xmm2 \n\t" // r3<<1|r2>>62:r2<<1|r1>>63 + + /* + * Now reduce modulo the GCM polynomial x^128 + x^7 + x^2 + x + 1 + * using [CLMUL-WP] algorithm 5 (p. 20). + * Currently xmm2:xmm1 holds x3:x2:x1:x0 (already shifted). + */ + /* Step 2 (1) */ + "movdqa %%xmm1, %%xmm3 \n\t" // x1:x0 + "movdqa %%xmm1, %%xmm4 \n\t" // same + "movdqa %%xmm1, %%xmm5 \n\t" // same + "psllq $63, %%xmm3 \n\t" // x1<<63:x0<<63 = stuff:a + "psllq $62, %%xmm4 \n\t" // x1<<62:x0<<62 = stuff:b + "psllq $57, %%xmm5 \n\t" // x1<<57:x0<<57 = stuff:c + + /* Step 2 (2) */ + "pxor %%xmm4, %%xmm3 \n\t" // stuff:a+b + "pxor %%xmm5, %%xmm3 \n\t" // stuff:a+b+c + "pslldq $8, %%xmm3 \n\t" // a+b+c:0 + "pxor %%xmm3, %%xmm1 \n\t" // x1+a+b+c:x0 = d:x0 + + /* Steps 3 and 4 */ + "movdqa %%xmm1,%%xmm0 \n\t" // d:x0 + "movdqa %%xmm1,%%xmm4 \n\t" // same + "movdqa %%xmm1,%%xmm5 \n\t" // same + "psrlq $1, %%xmm0 \n\t" // e1:x0>>1 = e1:e0' + "psrlq $2, %%xmm4 \n\t" // f1:x0>>2 = f1:f0' + "psrlq $7, %%xmm5 \n\t" // g1:x0>>7 = g1:g0' + "pxor %%xmm4, %%xmm0 \n\t" // e1+f1:e0'+f0' + "pxor %%xmm5, %%xmm0 \n\t" // e1+f1+g1:e0'+f0'+g0' + // e0'+f0'+g0' is almost e0+f0+g0, ex\tcept for some missing + // bits carried from d. Now get those\t bits back in. + "movdqa %%xmm1,%%xmm3 \n\t" // d:x0 + "movdqa %%xmm1,%%xmm4 \n\t" // same + "movdqa %%xmm1,%%xmm5 \n\t" // same + "psllq $63, %%xmm3 \n\t" // d<<63:stuff + "psllq $62, %%xmm4 \n\t" // d<<62:stuff + "psllq $57, %%xmm5 \n\t" // d<<57:stuff + "pxor %%xmm4, %%xmm3 \n\t" // d<<63+d<<62:stuff + "pxor %%xmm5, %%xmm3 \n\t" // missing bits of d:stuff + "psrldq $8, %%xmm3 \n\t" // 0:missing bits of d + "pxor %%xmm3, %%xmm0 \n\t" // e1+f1+g1:e0+f0+g0 + "pxor %%xmm1, %%xmm0 \n\t" // h1:h0 + "pxor %%xmm2, %%xmm0 \n\t" // x3+h1:x2+h0 + + "movdqu %%xmm0, (%2) \n\t" // done + : + : "r" (aa), "r" (bb), "r" (cc) + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" ); + + /* Now byte-reverse the outputs */ + for( i = 0; i < 16; i++ ) + c[i] = cc[15 - i]; + + return; +} + +/* + * Compute decryption round keys from encryption round keys + */ +void mbedtls_aesni_inverse_key( unsigned char *invkey, + const unsigned char *fwdkey, int nr ) +{ + unsigned char *ik = invkey; + const unsigned char *fk = fwdkey + 16 * nr; + + memcpy( ik, fk, 16 ); + + for( fk -= 16, ik += 16; fk > fwdkey; fk -= 16, ik += 16 ) + asm( "movdqu (%0), %%xmm0 \n\t" + AESIMC xmm0_xmm0 "\n\t" + "movdqu %%xmm0, (%1) \n\t" + : + : "r" (fk), "r" (ik) + : "memory", "xmm0" ); + + memcpy( ik, fk, 16 ); +} + +/* + * Key expansion, 128-bit case + */ +static void aesni_setkey_enc_128( unsigned char *rk, + const unsigned char *key ) +{ + asm( "movdqu (%1), %%xmm0 \n\t" // copy the original key + "movdqu %%xmm0, (%0) \n\t" // as round key 0 + "jmp 2f \n\t" // skip auxiliary routine + + /* + * Finish generating the next round key. + * + * On entry xmm0 is r3:r2:r1:r0 and xmm1 is X:stuff:stuff:stuff + * with X = rot( sub( r3 ) ) ^ RCON. + * + * On exit, xmm0 is r7:r6:r5:r4 + * with r4 = X + r0, r5 = r4 + r1, r6 = r5 + r2, r7 = r6 + r3 + * and those are written to the round key buffer. + */ + "1: \n\t" + "pshufd $0xff, %%xmm1, %%xmm1 \n\t" // X:X:X:X + "pxor %%xmm0, %%xmm1 \n\t" // X+r3:X+r2:X+r1:r4 + "pslldq $4, %%xmm0 \n\t" // r2:r1:r0:0 + "pxor %%xmm0, %%xmm1 \n\t" // X+r3+r2:X+r2+r1:r5:r4 + "pslldq $4, %%xmm0 \n\t" // etc + "pxor %%xmm0, %%xmm1 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm1, %%xmm0 \n\t" // update xmm0 for next time! + "add $16, %0 \n\t" // point to next round key + "movdqu %%xmm0, (%0) \n\t" // write it + "ret \n\t" + + /* Main "loop" */ + "2: \n\t" + AESKEYGENA xmm0_xmm1 ",0x01 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x02 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x04 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x08 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x10 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x20 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x40 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x80 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x1B \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x36 \n\tcall 1b \n\t" + : + : "r" (rk), "r" (key) + : "memory", "cc", "0" ); +} + +/* + * Key expansion, 192-bit case + */ +static void aesni_setkey_enc_192( unsigned char *rk, + const unsigned char *key ) +{ + asm( "movdqu (%1), %%xmm0 \n\t" // copy original round key + "movdqu %%xmm0, (%0) \n\t" + "add $16, %0 \n\t" + "movq 16(%1), %%xmm1 \n\t" + "movq %%xmm1, (%0) \n\t" + "add $8, %0 \n\t" + "jmp 2f \n\t" // skip auxiliary routine + + /* + * Finish generating the next 6 quarter-keys. + * + * On entry xmm0 is r3:r2:r1:r0, xmm1 is stuff:stuff:r5:r4 + * and xmm2 is stuff:stuff:X:stuff with X = rot( sub( r3 ) ) ^ RCON. + * + * On exit, xmm0 is r9:r8:r7:r6 and xmm1 is stuff:stuff:r11:r10 + * and those are written to the round key buffer. + */ + "1: \n\t" + "pshufd $0x55, %%xmm2, %%xmm2 \n\t" // X:X:X:X + "pxor %%xmm0, %%xmm2 \n\t" // X+r3:X+r2:X+r1:r4 + "pslldq $4, %%xmm0 \n\t" // etc + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm2, %%xmm0 \n\t" // update xmm0 = r9:r8:r7:r6 + "movdqu %%xmm0, (%0) \n\t" + "add $16, %0 \n\t" + "pshufd $0xff, %%xmm0, %%xmm2 \n\t" // r9:r9:r9:r9 + "pxor %%xmm1, %%xmm2 \n\t" // stuff:stuff:r9+r5:r10 + "pslldq $4, %%xmm1 \n\t" // r2:r1:r0:0 + "pxor %%xmm2, %%xmm1 \n\t" // xmm1 = stuff:stuff:r11:r10 + "movq %%xmm1, (%0) \n\t" + "add $8, %0 \n\t" + "ret \n\t" + + "2: \n\t" + AESKEYGENA xmm1_xmm2 ",0x01 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x02 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x04 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x08 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x10 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x20 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x40 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x80 \n\tcall 1b \n\t" + + : + : "r" (rk), "r" (key) + : "memory", "cc", "0" ); +} + +/* + * Key expansion, 256-bit case + */ +static void aesni_setkey_enc_256( unsigned char *rk, + const unsigned char *key ) +{ + asm( "movdqu (%1), %%xmm0 \n\t" + "movdqu %%xmm0, (%0) \n\t" + "add $16, %0 \n\t" + "movdqu 16(%1), %%xmm1 \n\t" + "movdqu %%xmm1, (%0) \n\t" + "jmp 2f \n\t" // skip auxiliary routine + + /* + * Finish generating the next two round keys. + * + * On entry xmm0 is r3:r2:r1:r0, xmm1 is r7:r6:r5:r4 and + * xmm2 is X:stuff:stuff:stuff with X = rot( sub( r7 )) ^ RCON + * + * On exit, xmm0 is r11:r10:r9:r8 and xmm1 is r15:r14:r13:r12 + * and those have been written to the output buffer. + */ + "1: \n\t" + "pshufd $0xff, %%xmm2, %%xmm2 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm2, %%xmm0 \n\t" + "add $16, %0 \n\t" + "movdqu %%xmm0, (%0) \n\t" + + /* Set xmm2 to stuff:Y:stuff:stuff with Y = subword( r11 ) + * and proceed to generate next round key from there */ + AESKEYGENA xmm0_xmm2 ",0x00 \n\t" + "pshufd $0xaa, %%xmm2, %%xmm2 \n\t" + "pxor %%xmm1, %%xmm2 \n\t" + "pslldq $4, %%xmm1 \n\t" + "pxor %%xmm1, %%xmm2 \n\t" + "pslldq $4, %%xmm1 \n\t" + "pxor %%xmm1, %%xmm2 \n\t" + "pslldq $4, %%xmm1 \n\t" + "pxor %%xmm2, %%xmm1 \n\t" + "add $16, %0 \n\t" + "movdqu %%xmm1, (%0) \n\t" + "ret \n\t" + + /* + * Main "loop" - Generating one more key than necessary, + * see definition of mbedtls_aes_context.buf + */ + "2: \n\t" + AESKEYGENA xmm1_xmm2 ",0x01 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x02 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x04 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x08 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x10 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x20 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x40 \n\tcall 1b \n\t" + : + : "r" (rk), "r" (key) + : "memory", "cc", "0" ); +} + +/* + * Key expansion, wrapper + */ +int mbedtls_aesni_setkey_enc( unsigned char *rk, + const unsigned char *key, + size_t bits ) +{ + switch( bits ) + { + case 128: aesni_setkey_enc_128( rk, key ); break; + case 192: aesni_setkey_enc_192( rk, key ); break; + case 256: aesni_setkey_enc_256( rk, key ); break; + default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + + return( 0 ); +} + +#endif /* MBEDTLS_HAVE_X86_64 */ + +#endif /* MBEDTLS_AESNI_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/arc4.c b/FreeRTOS-Labs/Source/mbedtls/library/arc4.c new file mode 100644 index 000000000..025dc2ed5 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/arc4.c @@ -0,0 +1,201 @@ +/* + * An implementation of the ARCFOUR algorithm + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ARCFOUR algorithm was publicly disclosed on 94/09. + * + * http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ARC4_C) + +#include "mbedtls/arc4.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_ARC4_ALT) + +void mbedtls_arc4_init( mbedtls_arc4_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_arc4_context ) ); +} + +void mbedtls_arc4_free( mbedtls_arc4_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_arc4_context ) ); +} + +/* + * ARC4 key schedule + */ +void mbedtls_arc4_setup( mbedtls_arc4_context *ctx, const unsigned char *key, + unsigned int keylen ) +{ + int i, j, a; + unsigned int k; + unsigned char *m; + + ctx->x = 0; + ctx->y = 0; + m = ctx->m; + + for( i = 0; i < 256; i++ ) + m[i] = (unsigned char) i; + + j = k = 0; + + for( i = 0; i < 256; i++, k++ ) + { + if( k >= keylen ) k = 0; + + a = m[i]; + j = ( j + a + key[k] ) & 0xFF; + m[i] = m[j]; + m[j] = (unsigned char) a; + } +} + +/* + * ARC4 cipher function + */ +int mbedtls_arc4_crypt( mbedtls_arc4_context *ctx, size_t length, const unsigned char *input, + unsigned char *output ) +{ + int x, y, a, b; + size_t i; + unsigned char *m; + + x = ctx->x; + y = ctx->y; + m = ctx->m; + + for( i = 0; i < length; i++ ) + { + x = ( x + 1 ) & 0xFF; a = m[x]; + y = ( y + a ) & 0xFF; b = m[y]; + + m[x] = (unsigned char) b; + m[y] = (unsigned char) a; + + output[i] = (unsigned char) + ( input[i] ^ m[(unsigned char)( a + b )] ); + } + + ctx->x = x; + ctx->y = y; + + return( 0 ); +} + +#endif /* !MBEDTLS_ARC4_ALT */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * ARC4 tests vectors as posted by Eric Rescorla in sep. 1994: + * + * http://groups.google.com/group/comp.security.misc/msg/10a300c9d21afca0 + */ +static const unsigned char arc4_test_key[3][8] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char arc4_test_pt[3][8] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char arc4_test_ct[3][8] = +{ + { 0x75, 0xB7, 0x87, 0x80, 0x99, 0xE0, 0xC5, 0x96 }, + { 0x74, 0x94, 0xC2, 0xE7, 0x10, 0x4B, 0x08, 0x79 }, + { 0xDE, 0x18, 0x89, 0x41, 0xA3, 0x37, 0x5D, 0x3A } +}; + +/* + * Checkup routine + */ +int mbedtls_arc4_self_test( int verbose ) +{ + int i, ret = 0; + unsigned char ibuf[8]; + unsigned char obuf[8]; + mbedtls_arc4_context ctx; + + mbedtls_arc4_init( &ctx ); + + for( i = 0; i < 3; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " ARC4 test #%d: ", i + 1 ); + + memcpy( ibuf, arc4_test_pt[i], 8 ); + + mbedtls_arc4_setup( &ctx, arc4_test_key[i], 8 ); + mbedtls_arc4_crypt( &ctx, 8, ibuf, obuf ); + + if( memcmp( obuf, arc4_test_ct[i], 8 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_arc4_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ARC4_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/aria.c b/FreeRTOS-Labs/Source/mbedtls/library/aria.c new file mode 100644 index 000000000..d1e03c42a --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/aria.c @@ -0,0 +1,1079 @@ +/* + * ARIA implementation + * + * Copyright (C) 2006-2017, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * This implementation is based on the following standards: + * [1] http://210.104.33.10/ARIA/doc/ARIA-specification-e.pdf + * [2] https://tools.ietf.org/html/rfc5794 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ARIA_C) + +#include "mbedtls/aria.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_ARIA_ALT) + +#include "mbedtls/platform_util.h" + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* Parameter validation macros */ +#define ARIA_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ARIA_BAD_INPUT_DATA ) +#define ARIA_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE( n, b, i ) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE( n, b, i ) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +/* + * modify byte order: ( A B C D ) -> ( B A D C ), i.e. swap pairs of bytes + * + * This is submatrix P1 in [1] Appendix B.1 + * + * Common compilers fail to translate this to minimal number of instructions, + * so let's provide asm versions for common platforms with C fallback. + */ +#if defined(MBEDTLS_HAVE_ASM) +#if defined(__arm__) /* rev16 available from v6 up */ +/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ +#if defined(__GNUC__) && \ + ( !defined(__ARMCC_VERSION) || __ARMCC_VERSION >= 6000000 ) && \ + __ARM_ARCH >= 6 +static inline uint32_t aria_p1( uint32_t x ) +{ + uint32_t r; + __asm( "rev16 %0, %1" : "=l" (r) : "l" (x) ); + return( r ); +} +#define ARIA_P1 aria_p1 +#elif defined(__ARMCC_VERSION) && __ARMCC_VERSION < 6000000 && \ + ( __TARGET_ARCH_ARM >= 6 || __TARGET_ARCH_THUMB >= 3 ) +static inline uint32_t aria_p1( uint32_t x ) +{ + uint32_t r; + __asm( "rev16 r, x" ); + return( r ); +} +#define ARIA_P1 aria_p1 +#endif +#endif /* arm */ +#if defined(__GNUC__) && \ + defined(__i386__) || defined(__amd64__) || defined( __x86_64__) +/* I couldn't find an Intel equivalent of rev16, so two instructions */ +#define ARIA_P1(x) ARIA_P2( ARIA_P3( x ) ) +#endif /* x86 gnuc */ +#endif /* MBEDTLS_HAVE_ASM && GNUC */ +#if !defined(ARIA_P1) +#define ARIA_P1(x) ((((x) >> 8) & 0x00FF00FF) ^ (((x) & 0x00FF00FF) << 8)) +#endif + +/* + * modify byte order: ( A B C D ) -> ( C D A B ), i.e. rotate by 16 bits + * + * This is submatrix P2 in [1] Appendix B.1 + * + * Common compilers will translate this to a single instruction. + */ +#define ARIA_P2(x) (((x) >> 16) ^ ((x) << 16)) + +/* + * modify byte order: ( A B C D ) -> ( D C B A ), i.e. change endianness + * + * This is submatrix P3 in [1] Appendix B.1 + * + * Some compilers fail to translate this to a single instruction, + * so let's provide asm versions for common platforms with C fallback. + */ +#if defined(MBEDTLS_HAVE_ASM) +#if defined(__arm__) /* rev available from v6 up */ +/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ +#if defined(__GNUC__) && \ + ( !defined(__ARMCC_VERSION) || __ARMCC_VERSION >= 6000000 ) && \ + __ARM_ARCH >= 6 +static inline uint32_t aria_p3( uint32_t x ) +{ + uint32_t r; + __asm( "rev %0, %1" : "=l" (r) : "l" (x) ); + return( r ); +} +#define ARIA_P3 aria_p3 +#elif defined(__ARMCC_VERSION) && __ARMCC_VERSION < 6000000 && \ + ( __TARGET_ARCH_ARM >= 6 || __TARGET_ARCH_THUMB >= 3 ) +static inline uint32_t aria_p3( uint32_t x ) +{ + uint32_t r; + __asm( "rev r, x" ); + return( r ); +} +#define ARIA_P3 aria_p3 +#endif +#endif /* arm */ +#if defined(__GNUC__) && \ + defined(__i386__) || defined(__amd64__) || defined( __x86_64__) +static inline uint32_t aria_p3( uint32_t x ) +{ + __asm( "bswap %0" : "=r" (x) : "0" (x) ); + return( x ); +} +#define ARIA_P3 aria_p3 +#endif /* x86 gnuc */ +#endif /* MBEDTLS_HAVE_ASM && GNUC */ +#if !defined(ARIA_P3) +#define ARIA_P3(x) ARIA_P2( ARIA_P1 ( x ) ) +#endif + +/* + * ARIA Affine Transform + * (a, b, c, d) = state in/out + * + * If we denote the first byte of input by 0, ..., the last byte by f, + * then inputs are: a = 0123, b = 4567, c = 89ab, d = cdef. + * + * Reading [1] 2.4 or [2] 2.4.3 in columns and performing simple + * rearrangements on adjacent pairs, output is: + * + * a = 3210 + 4545 + 6767 + 88aa + 99bb + dccd + effe + * = 3210 + 4567 + 6745 + 89ab + 98ba + dcfe + efcd + * b = 0101 + 2323 + 5476 + 8998 + baab + eecc + ffdd + * = 0123 + 2301 + 5476 + 89ab + ba98 + efcd + fedc + * c = 0022 + 1133 + 4554 + 7667 + ab89 + dcdc + fefe + * = 0123 + 1032 + 4567 + 7654 + ab89 + dcfe + fedc + * d = 1001 + 2332 + 6644 + 7755 + 9898 + baba + cdef + * = 1032 + 2301 + 6745 + 7654 + 98ba + ba98 + cdef + * + * Note: another presentation of the A transform can be found as the first + * half of App. B.1 in [1] in terms of 4-byte operators P1, P2, P3 and P4. + * The implementation below uses only P1 and P2 as they are sufficient. + */ +static inline void aria_a( uint32_t *a, uint32_t *b, + uint32_t *c, uint32_t *d ) +{ + uint32_t ta, tb, tc; + ta = *b; // 4567 + *b = *a; // 0123 + *a = ARIA_P2( ta ); // 6745 + tb = ARIA_P2( *d ); // efcd + *d = ARIA_P1( *c ); // 98ba + *c = ARIA_P1( tb ); // fedc + ta ^= *d; // 4567+98ba + tc = ARIA_P2( *b ); // 2301 + ta = ARIA_P1( ta ) ^ tc ^ *c; // 2301+5476+89ab+fedc + tb ^= ARIA_P2( *d ); // ba98+efcd + tc ^= ARIA_P1( *a ); // 2301+7654 + *b ^= ta ^ tb; // 0123+2301+5476+89ab+ba98+efcd+fedc OUT + tb = ARIA_P2( tb ) ^ ta; // 2301+5476+89ab+98ba+cdef+fedc + *a ^= ARIA_P1( tb ); // 3210+4567+6745+89ab+98ba+dcfe+efcd OUT + ta = ARIA_P2( ta ); // 0123+7654+ab89+dcfe + *d ^= ARIA_P1( ta ) ^ tc; // 1032+2301+6745+7654+98ba+ba98+cdef OUT + tc = ARIA_P2( tc ); // 0123+5476 + *c ^= ARIA_P1( tc ) ^ ta; // 0123+1032+4567+7654+ab89+dcfe+fedc OUT +} + +/* + * ARIA Substitution Layer SL1 / SL2 + * (a, b, c, d) = state in/out + * (sa, sb, sc, sd) = 256 8-bit S-Boxes (see below) + * + * By passing sb1, sb2, is1, is2 as S-Boxes you get SL1 + * By passing is1, is2, sb1, sb2 as S-Boxes you get SL2 + */ +static inline void aria_sl( uint32_t *a, uint32_t *b, + uint32_t *c, uint32_t *d, + const uint8_t sa[256], const uint8_t sb[256], + const uint8_t sc[256], const uint8_t sd[256] ) +{ + *a = ( (uint32_t) sa[ *a & 0xFF] ) ^ + (((uint32_t) sb[(*a >> 8) & 0xFF]) << 8) ^ + (((uint32_t) sc[(*a >> 16) & 0xFF]) << 16) ^ + (((uint32_t) sd[ *a >> 24 ]) << 24); + *b = ( (uint32_t) sa[ *b & 0xFF] ) ^ + (((uint32_t) sb[(*b >> 8) & 0xFF]) << 8) ^ + (((uint32_t) sc[(*b >> 16) & 0xFF]) << 16) ^ + (((uint32_t) sd[ *b >> 24 ]) << 24); + *c = ( (uint32_t) sa[ *c & 0xFF] ) ^ + (((uint32_t) sb[(*c >> 8) & 0xFF]) << 8) ^ + (((uint32_t) sc[(*c >> 16) & 0xFF]) << 16) ^ + (((uint32_t) sd[ *c >> 24 ]) << 24); + *d = ( (uint32_t) sa[ *d & 0xFF] ) ^ + (((uint32_t) sb[(*d >> 8) & 0xFF]) << 8) ^ + (((uint32_t) sc[(*d >> 16) & 0xFF]) << 16) ^ + (((uint32_t) sd[ *d >> 24 ]) << 24); +} + +/* + * S-Boxes + */ +static const uint8_t aria_sb1[256] = +{ + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, + 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, + 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, + 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, + 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, + 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, + 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, + 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, + 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, + 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, + 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, + 0xB0, 0x54, 0xBB, 0x16 +}; + +static const uint8_t aria_sb2[256] = +{ + 0xE2, 0x4E, 0x54, 0xFC, 0x94, 0xC2, 0x4A, 0xCC, 0x62, 0x0D, 0x6A, 0x46, + 0x3C, 0x4D, 0x8B, 0xD1, 0x5E, 0xFA, 0x64, 0xCB, 0xB4, 0x97, 0xBE, 0x2B, + 0xBC, 0x77, 0x2E, 0x03, 0xD3, 0x19, 0x59, 0xC1, 0x1D, 0x06, 0x41, 0x6B, + 0x55, 0xF0, 0x99, 0x69, 0xEA, 0x9C, 0x18, 0xAE, 0x63, 0xDF, 0xE7, 0xBB, + 0x00, 0x73, 0x66, 0xFB, 0x96, 0x4C, 0x85, 0xE4, 0x3A, 0x09, 0x45, 0xAA, + 0x0F, 0xEE, 0x10, 0xEB, 0x2D, 0x7F, 0xF4, 0x29, 0xAC, 0xCF, 0xAD, 0x91, + 0x8D, 0x78, 0xC8, 0x95, 0xF9, 0x2F, 0xCE, 0xCD, 0x08, 0x7A, 0x88, 0x38, + 0x5C, 0x83, 0x2A, 0x28, 0x47, 0xDB, 0xB8, 0xC7, 0x93, 0xA4, 0x12, 0x53, + 0xFF, 0x87, 0x0E, 0x31, 0x36, 0x21, 0x58, 0x48, 0x01, 0x8E, 0x37, 0x74, + 0x32, 0xCA, 0xE9, 0xB1, 0xB7, 0xAB, 0x0C, 0xD7, 0xC4, 0x56, 0x42, 0x26, + 0x07, 0x98, 0x60, 0xD9, 0xB6, 0xB9, 0x11, 0x40, 0xEC, 0x20, 0x8C, 0xBD, + 0xA0, 0xC9, 0x84, 0x04, 0x49, 0x23, 0xF1, 0x4F, 0x50, 0x1F, 0x13, 0xDC, + 0xD8, 0xC0, 0x9E, 0x57, 0xE3, 0xC3, 0x7B, 0x65, 0x3B, 0x02, 0x8F, 0x3E, + 0xE8, 0x25, 0x92, 0xE5, 0x15, 0xDD, 0xFD, 0x17, 0xA9, 0xBF, 0xD4, 0x9A, + 0x7E, 0xC5, 0x39, 0x67, 0xFE, 0x76, 0x9D, 0x43, 0xA7, 0xE1, 0xD0, 0xF5, + 0x68, 0xF2, 0x1B, 0x34, 0x70, 0x05, 0xA3, 0x8A, 0xD5, 0x79, 0x86, 0xA8, + 0x30, 0xC6, 0x51, 0x4B, 0x1E, 0xA6, 0x27, 0xF6, 0x35, 0xD2, 0x6E, 0x24, + 0x16, 0x82, 0x5F, 0xDA, 0xE6, 0x75, 0xA2, 0xEF, 0x2C, 0xB2, 0x1C, 0x9F, + 0x5D, 0x6F, 0x80, 0x0A, 0x72, 0x44, 0x9B, 0x6C, 0x90, 0x0B, 0x5B, 0x33, + 0x7D, 0x5A, 0x52, 0xF3, 0x61, 0xA1, 0xF7, 0xB0, 0xD6, 0x3F, 0x7C, 0x6D, + 0xED, 0x14, 0xE0, 0xA5, 0x3D, 0x22, 0xB3, 0xF8, 0x89, 0xDE, 0x71, 0x1A, + 0xAF, 0xBA, 0xB5, 0x81 +}; + +static const uint8_t aria_is1[256] = +{ + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, + 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, + 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, + 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, + 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, + 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, + 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, + 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, + 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, + 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, + 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, + 0x55, 0x21, 0x0C, 0x7D +}; + +static const uint8_t aria_is2[256] = +{ + 0x30, 0x68, 0x99, 0x1B, 0x87, 0xB9, 0x21, 0x78, 0x50, 0x39, 0xDB, 0xE1, + 0x72, 0x09, 0x62, 0x3C, 0x3E, 0x7E, 0x5E, 0x8E, 0xF1, 0xA0, 0xCC, 0xA3, + 0x2A, 0x1D, 0xFB, 0xB6, 0xD6, 0x20, 0xC4, 0x8D, 0x81, 0x65, 0xF5, 0x89, + 0xCB, 0x9D, 0x77, 0xC6, 0x57, 0x43, 0x56, 0x17, 0xD4, 0x40, 0x1A, 0x4D, + 0xC0, 0x63, 0x6C, 0xE3, 0xB7, 0xC8, 0x64, 0x6A, 0x53, 0xAA, 0x38, 0x98, + 0x0C, 0xF4, 0x9B, 0xED, 0x7F, 0x22, 0x76, 0xAF, 0xDD, 0x3A, 0x0B, 0x58, + 0x67, 0x88, 0x06, 0xC3, 0x35, 0x0D, 0x01, 0x8B, 0x8C, 0xC2, 0xE6, 0x5F, + 0x02, 0x24, 0x75, 0x93, 0x66, 0x1E, 0xE5, 0xE2, 0x54, 0xD8, 0x10, 0xCE, + 0x7A, 0xE8, 0x08, 0x2C, 0x12, 0x97, 0x32, 0xAB, 0xB4, 0x27, 0x0A, 0x23, + 0xDF, 0xEF, 0xCA, 0xD9, 0xB8, 0xFA, 0xDC, 0x31, 0x6B, 0xD1, 0xAD, 0x19, + 0x49, 0xBD, 0x51, 0x96, 0xEE, 0xE4, 0xA8, 0x41, 0xDA, 0xFF, 0xCD, 0x55, + 0x86, 0x36, 0xBE, 0x61, 0x52, 0xF8, 0xBB, 0x0E, 0x82, 0x48, 0x69, 0x9A, + 0xE0, 0x47, 0x9E, 0x5C, 0x04, 0x4B, 0x34, 0x15, 0x79, 0x26, 0xA7, 0xDE, + 0x29, 0xAE, 0x92, 0xD7, 0x84, 0xE9, 0xD2, 0xBA, 0x5D, 0xF3, 0xC5, 0xB0, + 0xBF, 0xA4, 0x3B, 0x71, 0x44, 0x46, 0x2B, 0xFC, 0xEB, 0x6F, 0xD5, 0xF6, + 0x14, 0xFE, 0x7C, 0x70, 0x5A, 0x7D, 0xFD, 0x2F, 0x18, 0x83, 0x16, 0xA5, + 0x91, 0x1F, 0x05, 0x95, 0x74, 0xA9, 0xC1, 0x5B, 0x4A, 0x85, 0x6D, 0x13, + 0x07, 0x4F, 0x4E, 0x45, 0xB2, 0x0F, 0xC9, 0x1C, 0xA6, 0xBC, 0xEC, 0x73, + 0x90, 0x7B, 0xCF, 0x59, 0x8F, 0xA1, 0xF9, 0x2D, 0xF2, 0xB1, 0x00, 0x94, + 0x37, 0x9F, 0xD0, 0x2E, 0x9C, 0x6E, 0x28, 0x3F, 0x80, 0xF0, 0x3D, 0xD3, + 0x25, 0x8A, 0xB5, 0xE7, 0x42, 0xB3, 0xC7, 0xEA, 0xF7, 0x4C, 0x11, 0x33, + 0x03, 0xA2, 0xAC, 0x60 +}; + +/* + * Helper for key schedule: r = FO( p, k ) ^ x + */ +static void aria_fo_xor( uint32_t r[4], const uint32_t p[4], + const uint32_t k[4], const uint32_t x[4] ) +{ + uint32_t a, b, c, d; + + a = p[0] ^ k[0]; + b = p[1] ^ k[1]; + c = p[2] ^ k[2]; + d = p[3] ^ k[3]; + + aria_sl( &a, &b, &c, &d, aria_sb1, aria_sb2, aria_is1, aria_is2 ); + aria_a( &a, &b, &c, &d ); + + r[0] = a ^ x[0]; + r[1] = b ^ x[1]; + r[2] = c ^ x[2]; + r[3] = d ^ x[3]; +} + +/* + * Helper for key schedule: r = FE( p, k ) ^ x + */ +static void aria_fe_xor( uint32_t r[4], const uint32_t p[4], + const uint32_t k[4], const uint32_t x[4] ) +{ + uint32_t a, b, c, d; + + a = p[0] ^ k[0]; + b = p[1] ^ k[1]; + c = p[2] ^ k[2]; + d = p[3] ^ k[3]; + + aria_sl( &a, &b, &c, &d, aria_is1, aria_is2, aria_sb1, aria_sb2 ); + aria_a( &a, &b, &c, &d ); + + r[0] = a ^ x[0]; + r[1] = b ^ x[1]; + r[2] = c ^ x[2]; + r[3] = d ^ x[3]; +} + +/* + * Big endian 128-bit rotation: r = a ^ (b <<< n), used only in key setup. + * + * We chose to store bytes into 32-bit words in little-endian format (see + * GET/PUT_UINT32_LE) so we need to reverse bytes here. + */ +static void aria_rot128( uint32_t r[4], const uint32_t a[4], + const uint32_t b[4], uint8_t n ) +{ + uint8_t i, j; + uint32_t t, u; + + const uint8_t n1 = n % 32; // bit offset + const uint8_t n2 = n1 ? 32 - n1 : 0; // reverse bit offset + + j = ( n / 32 ) % 4; // initial word offset + t = ARIA_P3( b[j] ); // big endian + for( i = 0; i < 4; i++ ) + { + j = ( j + 1 ) % 4; // get next word, big endian + u = ARIA_P3( b[j] ); + t <<= n1; // rotate + t |= u >> n2; + t = ARIA_P3( t ); // back to little endian + r[i] = a[i] ^ t; // store + t = u; // move to next word + } +} + +/* + * Set encryption key + */ +int mbedtls_aria_setkey_enc( mbedtls_aria_context *ctx, + const unsigned char *key, unsigned int keybits ) +{ + /* round constant masks */ + const uint32_t rc[3][4] = + { + { 0xB7C17C51, 0x940A2227, 0xE8AB13FE, 0xE06E9AFA }, + { 0xCC4AB16D, 0x20C8219E, 0xD5B128FF, 0xB0E25DEF }, + { 0x1D3792DB, 0x70E92621, 0x75972403, 0x0EC9E804 } + }; + + int i; + uint32_t w[4][4], *w2; + ARIA_VALIDATE_RET( ctx != NULL ); + ARIA_VALIDATE_RET( key != NULL ); + + if( keybits != 128 && keybits != 192 && keybits != 256 ) + return( MBEDTLS_ERR_ARIA_BAD_INPUT_DATA ); + + /* Copy key to W0 (and potential remainder to W1) */ + GET_UINT32_LE( w[0][0], key, 0 ); + GET_UINT32_LE( w[0][1], key, 4 ); + GET_UINT32_LE( w[0][2], key, 8 ); + GET_UINT32_LE( w[0][3], key, 12 ); + + memset( w[1], 0, 16 ); + if( keybits >= 192 ) + { + GET_UINT32_LE( w[1][0], key, 16 ); // 192 bit key + GET_UINT32_LE( w[1][1], key, 20 ); + } + if( keybits == 256 ) + { + GET_UINT32_LE( w[1][2], key, 24 ); // 256 bit key + GET_UINT32_LE( w[1][3], key, 28 ); + } + + i = ( keybits - 128 ) >> 6; // index: 0, 1, 2 + ctx->nr = 12 + 2 * i; // no. rounds: 12, 14, 16 + + aria_fo_xor( w[1], w[0], rc[i], w[1] ); // W1 = FO(W0, CK1) ^ KR + i = i < 2 ? i + 1 : 0; + aria_fe_xor( w[2], w[1], rc[i], w[0] ); // W2 = FE(W1, CK2) ^ W0 + i = i < 2 ? i + 1 : 0; + aria_fo_xor( w[3], w[2], rc[i], w[1] ); // W3 = FO(W2, CK3) ^ W1 + + for( i = 0; i < 4; i++ ) // create round keys + { + w2 = w[(i + 1) & 3]; + aria_rot128( ctx->rk[i ], w[i], w2, 128 - 19 ); + aria_rot128( ctx->rk[i + 4], w[i], w2, 128 - 31 ); + aria_rot128( ctx->rk[i + 8], w[i], w2, 61 ); + aria_rot128( ctx->rk[i + 12], w[i], w2, 31 ); + } + aria_rot128( ctx->rk[16], w[0], w[1], 19 ); + + /* w holds enough info to reconstruct the round keys */ + mbedtls_platform_zeroize( w, sizeof( w ) ); + + return( 0 ); +} + +/* + * Set decryption key + */ +int mbedtls_aria_setkey_dec( mbedtls_aria_context *ctx, + const unsigned char *key, unsigned int keybits ) +{ + int i, j, k, ret; + ARIA_VALIDATE_RET( ctx != NULL ); + ARIA_VALIDATE_RET( key != NULL ); + + ret = mbedtls_aria_setkey_enc( ctx, key, keybits ); + if( ret != 0 ) + return( ret ); + + /* flip the order of round keys */ + for( i = 0, j = ctx->nr; i < j; i++, j-- ) + { + for( k = 0; k < 4; k++ ) + { + uint32_t t = ctx->rk[i][k]; + ctx->rk[i][k] = ctx->rk[j][k]; + ctx->rk[j][k] = t; + } + } + + /* apply affine transform to middle keys */ + for( i = 1; i < ctx->nr; i++ ) + { + aria_a( &ctx->rk[i][0], &ctx->rk[i][1], + &ctx->rk[i][2], &ctx->rk[i][3] ); + } + + return( 0 ); +} + +/* + * Encrypt a block + */ +int mbedtls_aria_crypt_ecb( mbedtls_aria_context *ctx, + const unsigned char input[MBEDTLS_ARIA_BLOCKSIZE], + unsigned char output[MBEDTLS_ARIA_BLOCKSIZE] ) +{ + int i; + + uint32_t a, b, c, d; + ARIA_VALIDATE_RET( ctx != NULL ); + ARIA_VALIDATE_RET( input != NULL ); + ARIA_VALIDATE_RET( output != NULL ); + + GET_UINT32_LE( a, input, 0 ); + GET_UINT32_LE( b, input, 4 ); + GET_UINT32_LE( c, input, 8 ); + GET_UINT32_LE( d, input, 12 ); + + i = 0; + while( 1 ) + { + a ^= ctx->rk[i][0]; + b ^= ctx->rk[i][1]; + c ^= ctx->rk[i][2]; + d ^= ctx->rk[i][3]; + i++; + + aria_sl( &a, &b, &c, &d, aria_sb1, aria_sb2, aria_is1, aria_is2 ); + aria_a( &a, &b, &c, &d ); + + a ^= ctx->rk[i][0]; + b ^= ctx->rk[i][1]; + c ^= ctx->rk[i][2]; + d ^= ctx->rk[i][3]; + i++; + + aria_sl( &a, &b, &c, &d, aria_is1, aria_is2, aria_sb1, aria_sb2 ); + if( i >= ctx->nr ) + break; + aria_a( &a, &b, &c, &d ); + } + + /* final key mixing */ + a ^= ctx->rk[i][0]; + b ^= ctx->rk[i][1]; + c ^= ctx->rk[i][2]; + d ^= ctx->rk[i][3]; + + PUT_UINT32_LE( a, output, 0 ); + PUT_UINT32_LE( b, output, 4 ); + PUT_UINT32_LE( c, output, 8 ); + PUT_UINT32_LE( d, output, 12 ); + + return( 0 ); +} + +/* Initialize context */ +void mbedtls_aria_init( mbedtls_aria_context *ctx ) +{ + ARIA_VALIDATE( ctx != NULL ); + memset( ctx, 0, sizeof( mbedtls_aria_context ) ); +} + +/* Clear context */ +void mbedtls_aria_free( mbedtls_aria_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_aria_context ) ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * ARIA-CBC buffer encryption/decryption + */ +int mbedtls_aria_crypt_cbc( mbedtls_aria_context *ctx, + int mode, + size_t length, + unsigned char iv[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[MBEDTLS_ARIA_BLOCKSIZE]; + + ARIA_VALIDATE_RET( ctx != NULL ); + ARIA_VALIDATE_RET( mode == MBEDTLS_ARIA_ENCRYPT || + mode == MBEDTLS_ARIA_DECRYPT ); + ARIA_VALIDATE_RET( length == 0 || input != NULL ); + ARIA_VALIDATE_RET( length == 0 || output != NULL ); + ARIA_VALIDATE_RET( iv != NULL ); + + if( length % MBEDTLS_ARIA_BLOCKSIZE ) + return( MBEDTLS_ERR_ARIA_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_ARIA_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, MBEDTLS_ARIA_BLOCKSIZE ); + mbedtls_aria_crypt_ecb( ctx, input, output ); + + for( i = 0; i < MBEDTLS_ARIA_BLOCKSIZE; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, MBEDTLS_ARIA_BLOCKSIZE ); + + input += MBEDTLS_ARIA_BLOCKSIZE; + output += MBEDTLS_ARIA_BLOCKSIZE; + length -= MBEDTLS_ARIA_BLOCKSIZE; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < MBEDTLS_ARIA_BLOCKSIZE; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_aria_crypt_ecb( ctx, output, output ); + memcpy( iv, output, MBEDTLS_ARIA_BLOCKSIZE ); + + input += MBEDTLS_ARIA_BLOCKSIZE; + output += MBEDTLS_ARIA_BLOCKSIZE; + length -= MBEDTLS_ARIA_BLOCKSIZE; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * ARIA-CFB128 buffer encryption/decryption + */ +int mbedtls_aria_crypt_cfb128( mbedtls_aria_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + unsigned char c; + size_t n; + + ARIA_VALIDATE_RET( ctx != NULL ); + ARIA_VALIDATE_RET( mode == MBEDTLS_ARIA_ENCRYPT || + mode == MBEDTLS_ARIA_DECRYPT ); + ARIA_VALIDATE_RET( length == 0 || input != NULL ); + ARIA_VALIDATE_RET( length == 0 || output != NULL ); + ARIA_VALIDATE_RET( iv != NULL ); + ARIA_VALIDATE_RET( iv_off != NULL ); + + n = *iv_off; + + /* An overly large value of n can lead to an unlimited + * buffer overflow. Therefore, guard against this + * outside of parameter validation. */ + if( n >= MBEDTLS_ARIA_BLOCKSIZE ) + return( MBEDTLS_ERR_ARIA_BAD_INPUT_DATA ); + + if( mode == MBEDTLS_ARIA_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aria_crypt_ecb( ctx, iv, iv ); + + c = *input++; + *output++ = c ^ iv[n]; + iv[n] = c; + + n = ( n + 1 ) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aria_crypt_ecb( ctx, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * ARIA-CTR buffer encryption/decryption + */ +int mbedtls_aria_crypt_ctr( mbedtls_aria_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[MBEDTLS_ARIA_BLOCKSIZE], + unsigned char stream_block[MBEDTLS_ARIA_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n; + + ARIA_VALIDATE_RET( ctx != NULL ); + ARIA_VALIDATE_RET( length == 0 || input != NULL ); + ARIA_VALIDATE_RET( length == 0 || output != NULL ); + ARIA_VALIDATE_RET( nonce_counter != NULL ); + ARIA_VALIDATE_RET( stream_block != NULL ); + ARIA_VALIDATE_RET( nc_off != NULL ); + + n = *nc_off; + /* An overly large value of n can lead to an unlimited + * buffer overflow. Therefore, guard against this + * outside of parameter validation. */ + if( n >= MBEDTLS_ARIA_BLOCKSIZE ) + return( MBEDTLS_ERR_ARIA_BAD_INPUT_DATA ); + + while( length-- ) + { + if( n == 0 ) { + mbedtls_aria_crypt_ecb( ctx, nonce_counter, + stream_block ); + + for( i = MBEDTLS_ARIA_BLOCKSIZE; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ +#endif /* !MBEDTLS_ARIA_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Basic ARIA ECB test vectors from RFC 5794 + */ +static const uint8_t aria_test1_ecb_key[32] = // test key +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 128 bit + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, // 192 bit + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F // 256 bit +}; + +static const uint8_t aria_test1_ecb_pt[MBEDTLS_ARIA_BLOCKSIZE] = // plaintext +{ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // same for all + 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF // key sizes +}; + +static const uint8_t aria_test1_ecb_ct[3][MBEDTLS_ARIA_BLOCKSIZE] = // ciphertext +{ + { 0xD7, 0x18, 0xFB, 0xD6, 0xAB, 0x64, 0x4C, 0x73, // 128 bit + 0x9D, 0xA9, 0x5F, 0x3B, 0xE6, 0x45, 0x17, 0x78 }, + { 0x26, 0x44, 0x9C, 0x18, 0x05, 0xDB, 0xE7, 0xAA, // 192 bit + 0x25, 0xA4, 0x68, 0xCE, 0x26, 0x3A, 0x9E, 0x79 }, + { 0xF9, 0x2B, 0xD7, 0xC7, 0x9F, 0xB7, 0x2E, 0x2F, // 256 bit + 0x2B, 0x8F, 0x80, 0xC1, 0x97, 0x2D, 0x24, 0xFC } +}; + +/* + * Mode tests from "Test Vectors for ARIA" Version 1.0 + * http://210.104.33.10/ARIA/doc/ARIA-testvector-e.pdf + */ +#if (defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB) || \ + defined(MBEDTLS_CIPHER_MODE_CTR)) +static const uint8_t aria_test2_key[32] = +{ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // 128 bit + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, // 192 bit + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff // 256 bit +}; + +static const uint8_t aria_test2_pt[48] = +{ + 0x11, 0x11, 0x11, 0x11, 0xaa, 0xaa, 0xaa, 0xaa, // same for all + 0x11, 0x11, 0x11, 0x11, 0xbb, 0xbb, 0xbb, 0xbb, + 0x11, 0x11, 0x11, 0x11, 0xcc, 0xcc, 0xcc, 0xcc, + 0x11, 0x11, 0x11, 0x11, 0xdd, 0xdd, 0xdd, 0xdd, + 0x22, 0x22, 0x22, 0x22, 0xaa, 0xaa, 0xaa, 0xaa, + 0x22, 0x22, 0x22, 0x22, 0xbb, 0xbb, 0xbb, 0xbb, +}; +#endif + +#if (defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB)) +static const uint8_t aria_test2_iv[MBEDTLS_ARIA_BLOCKSIZE] = +{ + 0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a, 0x69, 0x78, // same for CBC, CFB + 0x87, 0x96, 0xa5, 0xb4, 0xc3, 0xd2, 0xe1, 0xf0 // CTR has zero IV +}; +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const uint8_t aria_test2_cbc_ct[3][48] = // CBC ciphertext +{ + { 0x49, 0xd6, 0x18, 0x60, 0xb1, 0x49, 0x09, 0x10, // 128-bit key + 0x9c, 0xef, 0x0d, 0x22, 0xa9, 0x26, 0x81, 0x34, + 0xfa, 0xdf, 0x9f, 0xb2, 0x31, 0x51, 0xe9, 0x64, + 0x5f, 0xba, 0x75, 0x01, 0x8b, 0xdb, 0x15, 0x38, + 0xb5, 0x33, 0x34, 0x63, 0x4b, 0xbf, 0x7d, 0x4c, + 0xd4, 0xb5, 0x37, 0x70, 0x33, 0x06, 0x0c, 0x15 }, + { 0xaf, 0xe6, 0xcf, 0x23, 0x97, 0x4b, 0x53, 0x3c, // 192-bit key + 0x67, 0x2a, 0x82, 0x62, 0x64, 0xea, 0x78, 0x5f, + 0x4e, 0x4f, 0x7f, 0x78, 0x0d, 0xc7, 0xf3, 0xf1, + 0xe0, 0x96, 0x2b, 0x80, 0x90, 0x23, 0x86, 0xd5, + 0x14, 0xe9, 0xc3, 0xe7, 0x72, 0x59, 0xde, 0x92, + 0xdd, 0x11, 0x02, 0xff, 0xab, 0x08, 0x6c, 0x1e }, + { 0x52, 0x3a, 0x8a, 0x80, 0x6a, 0xe6, 0x21, 0xf1, // 256-bit key + 0x55, 0xfd, 0xd2, 0x8d, 0xbc, 0x34, 0xe1, 0xab, + 0x7b, 0x9b, 0x42, 0x43, 0x2a, 0xd8, 0xb2, 0xef, + 0xb9, 0x6e, 0x23, 0xb1, 0x3f, 0x0a, 0x6e, 0x52, + 0xf3, 0x61, 0x85, 0xd5, 0x0a, 0xd0, 0x02, 0xc5, + 0xf6, 0x01, 0xbe, 0xe5, 0x49, 0x3f, 0x11, 0x8b } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const uint8_t aria_test2_cfb_ct[3][48] = // CFB ciphertext +{ + { 0x37, 0x20, 0xe5, 0x3b, 0xa7, 0xd6, 0x15, 0x38, // 128-bit key + 0x34, 0x06, 0xb0, 0x9f, 0x0a, 0x05, 0xa2, 0x00, + 0xc0, 0x7c, 0x21, 0xe6, 0x37, 0x0f, 0x41, 0x3a, + 0x5d, 0x13, 0x25, 0x00, 0xa6, 0x82, 0x85, 0x01, + 0x7c, 0x61, 0xb4, 0x34, 0xc7, 0xb7, 0xca, 0x96, + 0x85, 0xa5, 0x10, 0x71, 0x86, 0x1e, 0x4d, 0x4b }, + { 0x41, 0x71, 0xf7, 0x19, 0x2b, 0xf4, 0x49, 0x54, // 192-bit key + 0x94, 0xd2, 0x73, 0x61, 0x29, 0x64, 0x0f, 0x5c, + 0x4d, 0x87, 0xa9, 0xa2, 0x13, 0x66, 0x4c, 0x94, + 0x48, 0x47, 0x7c, 0x6e, 0xcc, 0x20, 0x13, 0x59, + 0x8d, 0x97, 0x66, 0x95, 0x2d, 0xd8, 0xc3, 0x86, + 0x8f, 0x17, 0xe3, 0x6e, 0xf6, 0x6f, 0xd8, 0x4b }, + { 0x26, 0x83, 0x47, 0x05, 0xb0, 0xf2, 0xc0, 0xe2, // 256-bit key + 0x58, 0x8d, 0x4a, 0x7f, 0x09, 0x00, 0x96, 0x35, + 0xf2, 0x8b, 0xb9, 0x3d, 0x8c, 0x31, 0xf8, 0x70, + 0xec, 0x1e, 0x0b, 0xdb, 0x08, 0x2b, 0x66, 0xfa, + 0x40, 0x2d, 0xd9, 0xc2, 0x02, 0xbe, 0x30, 0x0c, + 0x45, 0x17, 0xd1, 0x96, 0xb1, 0x4d, 0x4c, 0xe1 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const uint8_t aria_test2_ctr_ct[3][48] = // CTR ciphertext +{ + { 0xac, 0x5d, 0x7d, 0xe8, 0x05, 0xa0, 0xbf, 0x1c, // 128-bit key + 0x57, 0xc8, 0x54, 0x50, 0x1a, 0xf6, 0x0f, 0xa1, + 0x14, 0x97, 0xe2, 0xa3, 0x45, 0x19, 0xde, 0xa1, + 0x56, 0x9e, 0x91, 0xe5, 0xb5, 0xcc, 0xae, 0x2f, + 0xf3, 0xbf, 0xa1, 0xbf, 0x97, 0x5f, 0x45, 0x71, + 0xf4, 0x8b, 0xe1, 0x91, 0x61, 0x35, 0x46, 0xc3 }, + { 0x08, 0x62, 0x5c, 0xa8, 0xfe, 0x56, 0x9c, 0x19, // 192-bit key + 0xba, 0x7a, 0xf3, 0x76, 0x0a, 0x6e, 0xd1, 0xce, + 0xf4, 0xd1, 0x99, 0x26, 0x3e, 0x99, 0x9d, 0xde, + 0x14, 0x08, 0x2d, 0xbb, 0xa7, 0x56, 0x0b, 0x79, + 0xa4, 0xc6, 0xb4, 0x56, 0xb8, 0x70, 0x7d, 0xce, + 0x75, 0x1f, 0x98, 0x54, 0xf1, 0x88, 0x93, 0xdf }, + { 0x30, 0x02, 0x6c, 0x32, 0x96, 0x66, 0x14, 0x17, // 256-bit key + 0x21, 0x17, 0x8b, 0x99, 0xc0, 0xa1, 0xf1, 0xb2, + 0xf0, 0x69, 0x40, 0x25, 0x3f, 0x7b, 0x30, 0x89, + 0xe2, 0xa3, 0x0e, 0xa8, 0x6a, 0xa3, 0xc8, 0x8f, + 0x59, 0x40, 0xf0, 0x5a, 0xd7, 0xee, 0x41, 0xd7, + 0x13, 0x47, 0xbb, 0x72, 0x61, 0xe3, 0x48, 0xf1 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#define ARIA_SELF_TEST_IF_FAIL \ + { \ + if( verbose ) \ + mbedtls_printf( "failed\n" ); \ + return( 1 ); \ + } else { \ + if( verbose ) \ + mbedtls_printf( "passed\n" ); \ + } + +/* + * Checkup routine + */ +int mbedtls_aria_self_test( int verbose ) +{ + int i; + uint8_t blk[MBEDTLS_ARIA_BLOCKSIZE]; + mbedtls_aria_context ctx; + +#if (defined(MBEDTLS_CIPHER_MODE_CFB) || defined(MBEDTLS_CIPHER_MODE_CTR)) + size_t j; +#endif + +#if (defined(MBEDTLS_CIPHER_MODE_CBC) || \ + defined(MBEDTLS_CIPHER_MODE_CFB) || \ + defined(MBEDTLS_CIPHER_MODE_CTR)) + uint8_t buf[48], iv[MBEDTLS_ARIA_BLOCKSIZE]; +#endif + + /* + * Test set 1 + */ + for( i = 0; i < 3; i++ ) + { + /* test ECB encryption */ + if( verbose ) + mbedtls_printf( " ARIA-ECB-%d (enc): ", 128 + 64 * i ); + mbedtls_aria_setkey_enc( &ctx, aria_test1_ecb_key, 128 + 64 * i ); + mbedtls_aria_crypt_ecb( &ctx, aria_test1_ecb_pt, blk ); + if( memcmp( blk, aria_test1_ecb_ct[i], MBEDTLS_ARIA_BLOCKSIZE ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + + /* test ECB decryption */ + if( verbose ) + mbedtls_printf( " ARIA-ECB-%d (dec): ", 128 + 64 * i ); + mbedtls_aria_setkey_dec( &ctx, aria_test1_ecb_key, 128 + 64 * i ); + mbedtls_aria_crypt_ecb( &ctx, aria_test1_ecb_ct[i], blk ); + if( memcmp( blk, aria_test1_ecb_pt, MBEDTLS_ARIA_BLOCKSIZE ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + } + if( verbose ) + mbedtls_printf( "\n" ); + + /* + * Test set 2 + */ +#if defined(MBEDTLS_CIPHER_MODE_CBC) + for( i = 0; i < 3; i++ ) + { + /* Test CBC encryption */ + if( verbose ) + mbedtls_printf( " ARIA-CBC-%d (enc): ", 128 + 64 * i ); + mbedtls_aria_setkey_enc( &ctx, aria_test2_key, 128 + 64 * i ); + memcpy( iv, aria_test2_iv, MBEDTLS_ARIA_BLOCKSIZE ); + memset( buf, 0x55, sizeof( buf ) ); + mbedtls_aria_crypt_cbc( &ctx, MBEDTLS_ARIA_ENCRYPT, 48, iv, + aria_test2_pt, buf ); + if( memcmp( buf, aria_test2_cbc_ct[i], 48 ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + + /* Test CBC decryption */ + if( verbose ) + mbedtls_printf( " ARIA-CBC-%d (dec): ", 128 + 64 * i ); + mbedtls_aria_setkey_dec( &ctx, aria_test2_key, 128 + 64 * i ); + memcpy( iv, aria_test2_iv, MBEDTLS_ARIA_BLOCKSIZE ); + memset( buf, 0xAA, sizeof( buf ) ); + mbedtls_aria_crypt_cbc( &ctx, MBEDTLS_ARIA_DECRYPT, 48, iv, + aria_test2_cbc_ct[i], buf ); + if( memcmp( buf, aria_test2_pt, 48 ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + } + if( verbose ) + mbedtls_printf( "\n" ); + +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + for( i = 0; i < 3; i++ ) + { + /* Test CFB encryption */ + if( verbose ) + mbedtls_printf( " ARIA-CFB-%d (enc): ", 128 + 64 * i ); + mbedtls_aria_setkey_enc( &ctx, aria_test2_key, 128 + 64 * i ); + memcpy( iv, aria_test2_iv, MBEDTLS_ARIA_BLOCKSIZE ); + memset( buf, 0x55, sizeof( buf ) ); + j = 0; + mbedtls_aria_crypt_cfb128( &ctx, MBEDTLS_ARIA_ENCRYPT, 48, &j, iv, + aria_test2_pt, buf ); + if( memcmp( buf, aria_test2_cfb_ct[i], 48 ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + + /* Test CFB decryption */ + if( verbose ) + mbedtls_printf( " ARIA-CFB-%d (dec): ", 128 + 64 * i ); + mbedtls_aria_setkey_enc( &ctx, aria_test2_key, 128 + 64 * i ); + memcpy( iv, aria_test2_iv, MBEDTLS_ARIA_BLOCKSIZE ); + memset( buf, 0xAA, sizeof( buf ) ); + j = 0; + mbedtls_aria_crypt_cfb128( &ctx, MBEDTLS_ARIA_DECRYPT, 48, &j, + iv, aria_test2_cfb_ct[i], buf ); + if( memcmp( buf, aria_test2_pt, 48 ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + } + if( verbose ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + for( i = 0; i < 3; i++ ) + { + /* Test CTR encryption */ + if( verbose ) + mbedtls_printf( " ARIA-CTR-%d (enc): ", 128 + 64 * i ); + mbedtls_aria_setkey_enc( &ctx, aria_test2_key, 128 + 64 * i ); + memset( iv, 0, MBEDTLS_ARIA_BLOCKSIZE ); // IV = 0 + memset( buf, 0x55, sizeof( buf ) ); + j = 0; + mbedtls_aria_crypt_ctr( &ctx, 48, &j, iv, blk, + aria_test2_pt, buf ); + if( memcmp( buf, aria_test2_ctr_ct[i], 48 ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + + /* Test CTR decryption */ + if( verbose ) + mbedtls_printf( " ARIA-CTR-%d (dec): ", 128 + 64 * i ); + mbedtls_aria_setkey_enc( &ctx, aria_test2_key, 128 + 64 * i ); + memset( iv, 0, MBEDTLS_ARIA_BLOCKSIZE ); // IV = 0 + memset( buf, 0xAA, sizeof( buf ) ); + j = 0; + mbedtls_aria_crypt_ctr( &ctx, 48, &j, iv, blk, + aria_test2_ctr_ct[i], buf ); + if( memcmp( buf, aria_test2_pt, 48 ) != 0 ) + ARIA_SELF_TEST_IF_FAIL; + } + if( verbose ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ARIA_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/asn1parse.c b/FreeRTOS-Labs/Source/mbedtls/library/asn1parse.c new file mode 100644 index 000000000..ce65812b5 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/asn1parse.c @@ -0,0 +1,389 @@ +/* + * Generic ASN.1 parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ASN1_PARSE_C) + +#include "mbedtls/asn1.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/bignum.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/* + * ASN.1 DER decoding routines + */ +int mbedtls_asn1_get_len( unsigned char **p, + const unsigned char *end, + size_t *len ) +{ + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( ( **p & 0x80 ) == 0 ) + *len = *(*p)++; + else + { + switch( **p & 0x7F ) + { + case 1: + if( ( end - *p ) < 2 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = (*p)[1]; + (*p) += 2; + break; + + case 2: + if( ( end - *p ) < 3 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 8 ) | (*p)[2]; + (*p) += 3; + break; + + case 3: + if( ( end - *p ) < 4 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 16 ) | + ( (size_t)(*p)[2] << 8 ) | (*p)[3]; + (*p) += 4; + break; + + case 4: + if( ( end - *p ) < 5 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 24 ) | ( (size_t)(*p)[2] << 16 ) | + ( (size_t)(*p)[3] << 8 ) | (*p)[4]; + (*p) += 5; + break; + + default: + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + } + } + + if( *len > (size_t) ( end - *p ) ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + return( 0 ); +} + +int mbedtls_asn1_get_tag( unsigned char **p, + const unsigned char *end, + size_t *len, int tag ) +{ + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( **p != tag ) + return( MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + (*p)++; + + return( mbedtls_asn1_get_len( p, end, len ) ); +} + +int mbedtls_asn1_get_bool( unsigned char **p, + const unsigned char *end, + int *val ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_BOOLEAN ) ) != 0 ) + return( ret ); + + if( len != 1 ) + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + *val = ( **p != 0 ) ? 1 : 0; + (*p)++; + + return( 0 ); +} + +int mbedtls_asn1_get_int( unsigned char **p, + const unsigned char *end, + int *val ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) + return( ret ); + + if( len == 0 || len > sizeof( int ) || ( **p & 0x80 ) != 0 ) + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + *val = 0; + + while( len-- > 0 ) + { + *val = ( *val << 8 ) | **p; + (*p)++; + } + + return( 0 ); +} + +#if defined(MBEDTLS_BIGNUM_C) +int mbedtls_asn1_get_mpi( unsigned char **p, + const unsigned char *end, + mbedtls_mpi *X ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) + return( ret ); + + ret = mbedtls_mpi_read_binary( X, *p, len ); + + *p += len; + + return( ret ); +} +#endif /* MBEDTLS_BIGNUM_C */ + +int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end, + mbedtls_asn1_bitstring *bs) +{ + int ret; + + /* Certificate type is a single byte bitstring */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &bs->len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 ) + return( ret ); + + /* Check length, subtract one for actual bit string length */ + if( bs->len < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + bs->len -= 1; + + /* Get number of unused bits, ensure unused bits <= 7 */ + bs->unused_bits = **p; + if( bs->unused_bits > 7 ) + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + (*p)++; + + /* Get actual bitstring */ + bs->p = *p; + *p += bs->len; + + if( *p != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Get a bit string without unused bits + */ +int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end, + size_t *len ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 ) + return( ret ); + + if( (*len)-- < 2 || *(*p)++ != 0 ) + return( MBEDTLS_ERR_ASN1_INVALID_DATA ); + + return( 0 ); +} + + + +/* + * Parses and splits an ASN.1 "SEQUENCE OF " + */ +int mbedtls_asn1_get_sequence_of( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_sequence *cur, + int tag) +{ + int ret; + size_t len; + mbedtls_asn1_buf *buf; + + /* Get main sequence tag */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + buf = &(cur->buf); + buf->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &buf->len, tag ) ) != 0 ) + return( ret ); + + buf->p = *p; + *p += buf->len; + + /* Allocate and assign next pointer */ + if( *p < end ) + { + cur->next = (mbedtls_asn1_sequence*)mbedtls_calloc( 1, + sizeof( mbedtls_asn1_sequence ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + cur = cur->next; + } + } + + /* Set final sequence entry's next pointer to NULL */ + cur->next = NULL; + + if( *p != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +int mbedtls_asn1_get_alg( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + alg->tag = **p; + end = *p + len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &alg->len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( ret ); + + alg->p = *p; + *p += alg->len; + + if( *p == end ) + { + mbedtls_platform_zeroize( params, sizeof(mbedtls_asn1_buf) ); + return( 0 ); + } + + params->tag = **p; + (*p)++; + + if( ( ret = mbedtls_asn1_get_len( p, end, ¶ms->len ) ) != 0 ) + return( ret ); + + params->p = *p; + *p += params->len; + + if( *p != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +int mbedtls_asn1_get_alg_null( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg ) +{ + int ret; + mbedtls_asn1_buf params; + + memset( ¶ms, 0, sizeof(mbedtls_asn1_buf) ); + + if( ( ret = mbedtls_asn1_get_alg( p, end, alg, ¶ms ) ) != 0 ) + return( ret ); + + if( ( params.tag != MBEDTLS_ASN1_NULL && params.tag != 0 ) || params.len != 0 ) + return( MBEDTLS_ERR_ASN1_INVALID_DATA ); + + return( 0 ); +} + +void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *cur ) +{ + if( cur == NULL ) + return; + + mbedtls_free( cur->oid.p ); + mbedtls_free( cur->val.p ); + + mbedtls_platform_zeroize( cur, sizeof( mbedtls_asn1_named_data ) ); +} + +void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head ) +{ + mbedtls_asn1_named_data *cur; + + while( ( cur = *head ) != NULL ) + { + *head = cur->next; + mbedtls_asn1_free_named_data( cur ); + mbedtls_free( cur ); + } +} + +mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list, + const char *oid, size_t len ) +{ + while( list != NULL ) + { + if( list->oid.len == len && + memcmp( list->oid.p, oid, len ) == 0 ) + { + break; + } + + list = list->next; + } + + return( list ); +} + +#endif /* MBEDTLS_ASN1_PARSE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/asn1write.c b/FreeRTOS-Labs/Source/mbedtls/library/asn1write.c new file mode 100644 index 000000000..c231ef4b9 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/asn1write.c @@ -0,0 +1,464 @@ +/* + * ASN.1 buffer writing functionality + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ASN1_WRITE_C) + +#include "mbedtls/asn1write.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len ) +{ + if( len < 0x80 ) + { + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = (unsigned char) len; + return( 1 ); + } + + if( len <= 0xFF ) + { + if( *p - start < 2 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = (unsigned char) len; + *--(*p) = 0x81; + return( 2 ); + } + + if( len <= 0xFFFF ) + { + if( *p - start < 3 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = ( len ) & 0xFF; + *--(*p) = ( len >> 8 ) & 0xFF; + *--(*p) = 0x82; + return( 3 ); + } + + if( len <= 0xFFFFFF ) + { + if( *p - start < 4 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = ( len ) & 0xFF; + *--(*p) = ( len >> 8 ) & 0xFF; + *--(*p) = ( len >> 16 ) & 0xFF; + *--(*p) = 0x83; + return( 4 ); + } + +#if SIZE_MAX > 0xFFFFFFFF + if( len <= 0xFFFFFFFF ) +#endif + { + if( *p - start < 5 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = ( len ) & 0xFF; + *--(*p) = ( len >> 8 ) & 0xFF; + *--(*p) = ( len >> 16 ) & 0xFF; + *--(*p) = ( len >> 24 ) & 0xFF; + *--(*p) = 0x84; + return( 5 ); + } + +#if SIZE_MAX > 0xFFFFFFFF + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); +#endif +} + +int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag ) +{ + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = tag; + + return( 1 ); +} + +int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ) +{ + size_t len = 0; + + if( *p < start || (size_t)( *p - start ) < size ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len = size; + (*p) -= len; + memcpy( *p, buf, len ); + + return( (int) len ); +} + +#if defined(MBEDTLS_BIGNUM_C) +int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X ) +{ + int ret; + size_t len = 0; + + // Write the MPI + // + len = mbedtls_mpi_size( X ); + + if( *p < start || (size_t)( *p - start ) < len ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + (*p) -= len; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, *p, len ) ); + + // DER format assumes 2s complement for numbers, so the leftmost bit + // should be 0 for positive numbers and 1 for negative numbers. + // + if( X->s ==1 && **p & 0x80 ) + { + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0x00; + len += 1; + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) ); + + ret = (int) len; + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_BIGNUM_C */ + +int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start ) +{ + int ret; + size_t len = 0; + + // Write NULL + // + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, 0) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_NULL ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) oid, oid_len ) ); + MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OID ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + size_t par_len ) +{ + int ret; + size_t len = 0; + + if( par_len == 0 ) + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_null( p, start ) ); + else + len += par_len; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean ) +{ + int ret; + size_t len = 0; + + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = (boolean) ? 255 : 0; + len++; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BOOLEAN ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val ) +{ + int ret; + size_t len = 0; + + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len += 1; + *--(*p) = val; + + if( val > 0 && **p & 0x80 ) + { + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0x00; + len += 1; + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_tagged_string( unsigned char **p, unsigned char *start, int tag, + const char *text, size_t text_len ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) text, text_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, tag ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_utf8_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ) +{ + return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_UTF8_STRING, text, text_len) ); +} + +int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ) +{ + return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_PRINTABLE_STRING, text, text_len) ); +} + +int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ) +{ + return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_IA5_STRING, text, text_len) ); +} + +int mbedtls_asn1_write_named_bitstring( unsigned char **p, + unsigned char *start, + const unsigned char *buf, + size_t bits ) +{ + size_t unused_bits, byte_len; + const unsigned char *cur_byte; + unsigned char cur_byte_shifted; + unsigned char bit; + + byte_len = ( bits + 7 ) / 8; + unused_bits = ( byte_len * 8 ) - bits; + + /* + * Named bitstrings require that trailing 0s are excluded in the encoding + * of the bitstring. Trailing 0s are considered part of the 'unused' bits + * when encoding this value in the first content octet + */ + if( bits != 0 ) + { + cur_byte = buf + byte_len - 1; + cur_byte_shifted = *cur_byte >> unused_bits; + + for( ; ; ) + { + bit = cur_byte_shifted & 0x1; + cur_byte_shifted >>= 1; + + if( bit != 0 ) + break; + + bits--; + if( bits == 0 ) + break; + + if( bits % 8 == 0 ) + cur_byte_shifted = *--cur_byte; + } + } + + return( mbedtls_asn1_write_bitstring( p, start, buf, bits ) ); +} + +int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t bits ) +{ + int ret; + size_t len = 0; + size_t unused_bits, byte_len; + + byte_len = ( bits + 7 ) / 8; + unused_bits = ( byte_len * 8 ) - bits; + + if( *p < start || (size_t)( *p - start ) < byte_len + 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len = byte_len + 1; + + /* Write the bitstring. Ensure the unused bits are zeroed */ + if( byte_len > 0 ) + { + byte_len--; + *--( *p ) = buf[byte_len] & ~( ( 0x1 << unused_bits ) - 1 ); + ( *p ) -= byte_len; + memcpy( *p, buf, byte_len ); + } + + /* Write unused bits */ + *--( *p ) = (unsigned char)unused_bits; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, buf, size ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OCTET_STRING ) ); + + return( (int) len ); +} + + +/* This is a copy of the ASN.1 parsing function mbedtls_asn1_find_named_data(), + * which is replicated to avoid a dependency ASN1_WRITE_C on ASN1_PARSE_C. */ +static mbedtls_asn1_named_data *asn1_find_named_data( + mbedtls_asn1_named_data *list, + const char *oid, size_t len ) +{ + while( list != NULL ) + { + if( list->oid.len == len && + memcmp( list->oid.p, oid, len ) == 0 ) + { + break; + } + + list = list->next; + } + + return( list ); +} + +mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( + mbedtls_asn1_named_data **head, + const char *oid, size_t oid_len, + const unsigned char *val, + size_t val_len ) +{ + mbedtls_asn1_named_data *cur; + + if( ( cur = asn1_find_named_data( *head, oid, oid_len ) ) == NULL ) + { + // Add new entry if not present yet based on OID + // + cur = (mbedtls_asn1_named_data*)mbedtls_calloc( 1, + sizeof(mbedtls_asn1_named_data) ); + if( cur == NULL ) + return( NULL ); + + cur->oid.len = oid_len; + cur->oid.p = mbedtls_calloc( 1, oid_len ); + if( cur->oid.p == NULL ) + { + mbedtls_free( cur ); + return( NULL ); + } + + memcpy( cur->oid.p, oid, oid_len ); + + cur->val.len = val_len; + cur->val.p = mbedtls_calloc( 1, val_len ); + if( cur->val.p == NULL ) + { + mbedtls_free( cur->oid.p ); + mbedtls_free( cur ); + return( NULL ); + } + + cur->next = *head; + *head = cur; + } + else if( cur->val.len < val_len ) + { + /* + * Enlarge existing value buffer if needed + * Preserve old data until the allocation succeeded, to leave list in + * a consistent state in case allocation fails. + */ + void *p = mbedtls_calloc( 1, val_len ); + if( p == NULL ) + return( NULL ); + + mbedtls_free( cur->val.p ); + cur->val.p = p; + cur->val.len = val_len; + } + + if( val != NULL ) + memcpy( cur->val.p, val, val_len ); + + return( cur ); +} +#endif /* MBEDTLS_ASN1_WRITE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/base64.c b/FreeRTOS-Labs/Source/mbedtls/library/base64.c new file mode 100644 index 000000000..72cd7a3b2 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/base64.c @@ -0,0 +1,293 @@ +/* + * RFC 1521 base64 encoding/decoding + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_BASE64_C) + +#include "mbedtls/base64.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#include +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +static const unsigned char base64_enc_map[64] = +{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/' +}; + +static const unsigned char base64_dec_map[128] = +{ + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, + 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 127, 127, 127, 127, 127 +}; + +#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ + +/* + * Encode a buffer into base64 format + */ +int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ) +{ + size_t i, n; + int C1, C2, C3; + unsigned char *p; + + if( slen == 0 ) + { + *olen = 0; + return( 0 ); + } + + n = slen / 3 + ( slen % 3 != 0 ); + + if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 ) + { + *olen = BASE64_SIZE_T_MAX; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + n *= 4; + + if( ( dlen < n + 1 ) || ( NULL == dst ) ) + { + *olen = n + 1; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + n = ( slen / 3 ) * 3; + + for( i = 0, p = dst; i < n; i += 3 ) + { + C1 = *src++; + C2 = *src++; + C3 = *src++; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F]; + *p++ = base64_enc_map[C3 & 0x3F]; + } + + if( i < slen ) + { + C1 = *src++; + C2 = ( ( i + 1 ) < slen ) ? *src++ : 0; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + + if( ( i + 1 ) < slen ) + *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F]; + else *p++ = '='; + + *p++ = '='; + } + + *olen = p - dst; + *p = 0; + + return( 0 ); +} + +/* + * Decode a base64-formatted buffer + */ +int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ) +{ + size_t i, n; + uint32_t j, x; + unsigned char *p; + + /* First pass: check for validity and get output length */ + for( i = n = j = 0; i < slen; i++ ) + { + /* Skip spaces before checking for EOL */ + x = 0; + while( i < slen && src[i] == ' ' ) + { + ++i; + ++x; + } + + /* Spaces at end of buffer are OK */ + if( i == slen ) + break; + + if( ( slen - i ) >= 2 && + src[i] == '\r' && src[i + 1] == '\n' ) + continue; + + if( src[i] == '\n' ) + continue; + + /* Space inside a line is an error */ + if( x != 0 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + if( src[i] == '=' && ++j > 2 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + if( src[i] > 127 || base64_dec_map[src[i]] == 127 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + if( base64_dec_map[src[i]] < 64 && j != 0 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + n++; + } + + if( n == 0 ) + { + *olen = 0; + return( 0 ); + } + + /* The following expression is to calculate the following formula without + * risk of integer overflow in n: + * n = ( ( n * 6 ) + 7 ) >> 3; + */ + n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 ); + n -= j; + + if( dst == NULL || dlen < n ) + { + *olen = n; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) + { + if( *src == '\r' || *src == '\n' || *src == ' ' ) + continue; + + j -= ( base64_dec_map[*src] == 64 ); + x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F ); + + if( ++n == 4 ) + { + n = 0; + if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); + if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); + if( j > 2 ) *p++ = (unsigned char)( x ); + } + } + + *olen = p - dst; + + return( 0 ); +} + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char base64_test_dec[64] = +{ + 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD, + 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01, + 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09, + 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13, + 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31, + 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38, + 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B, + 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97 +}; + +static const unsigned char base64_test_enc[] = + "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK" + "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw=="; + +/* + * Checkup routine + */ +int mbedtls_base64_self_test( int verbose ) +{ + size_t len; + const unsigned char *src; + unsigned char buffer[128]; + + if( verbose != 0 ) + mbedtls_printf( " Base64 encoding test: " ); + + src = base64_test_dec; + + if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 || + memcmp( base64_test_enc, buffer, 88 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n Base64 decoding test: " ); + + src = base64_test_enc; + + if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 || + memcmp( base64_test_dec, buffer, 64 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_BASE64_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/bignum.c b/FreeRTOS-Labs/Source/mbedtls/library/bignum.c new file mode 100644 index 000000000..22e2bb565 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/bignum.c @@ -0,0 +1,2837 @@ +/* + * Multi-precision integer library + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The following sources were referenced in the design of this Multi-precision + * Integer library: + * + * [1] Handbook of Applied Cryptography - 1997 + * Menezes, van Oorschot and Vanstone + * + * [2] Multi-Precision Math + * Tom St Denis + * https://github.com/libtom/libtommath/blob/develop/tommath.pdf + * + * [3] GNU Multi-Precision Arithmetic Library + * https://gmplib.org/manual/index.html + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_BIGNUM_C) + +#include "mbedtls/bignum.h" +#include "mbedtls/bn_mul.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#define MPI_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA ) +#define MPI_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#define ciL (sizeof(mbedtls_mpi_uint)) /* chars in limb */ +#define biL (ciL << 3) /* bits in limb */ +#define biH (ciL << 2) /* half limb size */ + +#define MPI_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ + +/* + * Convert between bits/chars and number of limbs + * Divide first in order to avoid potential overflows + */ +#define BITS_TO_LIMBS(i) ( (i) / biL + ( (i) % biL != 0 ) ) +#define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) ) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_mpi_zeroize( mbedtls_mpi_uint *v, size_t n ) +{ + mbedtls_platform_zeroize( v, ciL * n ); +} + +/* + * Initialize one MPI + */ +void mbedtls_mpi_init( mbedtls_mpi *X ) +{ + MPI_VALIDATE( X != NULL ); + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Unallocate one MPI + */ +void mbedtls_mpi_free( mbedtls_mpi *X ) +{ + if( X == NULL ) + return; + + if( X->p != NULL ) + { + mbedtls_mpi_zeroize( X->p, X->n ); + mbedtls_free( X->p ); + } + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Enlarge to the specified number of limbs + */ +int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs ) +{ + mbedtls_mpi_uint *p; + MPI_VALIDATE_RET( X != NULL ); + + if( nblimbs > MBEDTLS_MPI_MAX_LIMBS ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + if( X->n < nblimbs ) + { + if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL ) ) == NULL ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + if( X->p != NULL ) + { + memcpy( p, X->p, X->n * ciL ); + mbedtls_mpi_zeroize( X->p, X->n ); + mbedtls_free( X->p ); + } + + X->n = nblimbs; + X->p = p; + } + + return( 0 ); +} + +/* + * Resize down as much as possible, + * while keeping at least the specified number of limbs + */ +int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ) +{ + mbedtls_mpi_uint *p; + size_t i; + MPI_VALIDATE_RET( X != NULL ); + + if( nblimbs > MBEDTLS_MPI_MAX_LIMBS ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + /* Actually resize up in this case */ + if( X->n <= nblimbs ) + return( mbedtls_mpi_grow( X, nblimbs ) ); + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + i++; + + if( i < nblimbs ) + i = nblimbs; + + if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( i, ciL ) ) == NULL ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + if( X->p != NULL ) + { + memcpy( p, X->p, i * ciL ); + mbedtls_mpi_zeroize( X->p, X->n ); + mbedtls_free( X->p ); + } + + X->n = i; + X->p = p; + + return( 0 ); +} + +/* + * Copy the contents of Y into X + */ +int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ) +{ + int ret = 0; + size_t i; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( Y != NULL ); + + if( X == Y ) + return( 0 ); + + if( Y->p == NULL ) + { + mbedtls_mpi_free( X ); + return( 0 ); + } + + for( i = Y->n - 1; i > 0; i-- ) + if( Y->p[i] != 0 ) + break; + i++; + + X->s = Y->s; + + if( X->n < i ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) ); + } + else + { + memset( X->p + i, 0, ( X->n - i ) * ciL ); + } + + memcpy( X->p, Y->p, i * ciL ); + +cleanup: + + return( ret ); +} + +/* + * Swap the contents of X and Y + */ +void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ) +{ + mbedtls_mpi T; + MPI_VALIDATE( X != NULL ); + MPI_VALIDATE( Y != NULL ); + + memcpy( &T, X, sizeof( mbedtls_mpi ) ); + memcpy( X, Y, sizeof( mbedtls_mpi ) ); + memcpy( Y, &T, sizeof( mbedtls_mpi ) ); +} + +/* + * Conditionally assign X = Y, without leaking information + * about whether the assignment was made or not. + * (Leaking information about the respective sizes of X and Y is ok however.) + */ +int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ) +{ + int ret = 0; + size_t i; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( Y != NULL ); + + /* make sure assign is 0 or 1 in a time-constant manner */ + assign = (assign | (unsigned char)-assign) >> 7; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); + + X->s = X->s * ( 1 - assign ) + Y->s * assign; + + for( i = 0; i < Y->n; i++ ) + X->p[i] = X->p[i] * ( 1 - assign ) + Y->p[i] * assign; + + for( ; i < X->n; i++ ) + X->p[i] *= ( 1 - assign ); + +cleanup: + return( ret ); +} + +/* + * Conditionally swap X and Y, without leaking information + * about whether the swap was made or not. + * Here it is not ok to simply swap the pointers, which whould lead to + * different memory access patterns when X and Y are used afterwards. + */ +int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap ) +{ + int ret, s; + size_t i; + mbedtls_mpi_uint tmp; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( Y != NULL ); + + if( X == Y ) + return( 0 ); + + /* make sure swap is 0 or 1 in a time-constant manner */ + swap = (swap | (unsigned char)-swap) >> 7; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) ); + + s = X->s; + X->s = X->s * ( 1 - swap ) + Y->s * swap; + Y->s = Y->s * ( 1 - swap ) + s * swap; + + + for( i = 0; i < X->n; i++ ) + { + tmp = X->p[i]; + X->p[i] = X->p[i] * ( 1 - swap ) + Y->p[i] * swap; + Y->p[i] = Y->p[i] * ( 1 - swap ) + tmp * swap; + } + +cleanup: + return( ret ); +} + +/* + * Set value from integer + */ +int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ) +{ + int ret; + MPI_VALIDATE_RET( X != NULL ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) ); + memset( X->p, 0, X->n * ciL ); + + X->p[0] = ( z < 0 ) ? -z : z; + X->s = ( z < 0 ) ? -1 : 1; + +cleanup: + + return( ret ); +} + +/* + * Get a specific bit + */ +int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos ) +{ + MPI_VALIDATE_RET( X != NULL ); + + if( X->n * biL <= pos ) + return( 0 ); + + return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 ); +} + +/* Get a specific byte, without range checks. */ +#define GET_BYTE( X, i ) \ + ( ( ( X )->p[( i ) / ciL] >> ( ( ( i ) % ciL ) * 8 ) ) & 0xff ) + +/* + * Set a bit to a specific value of 0 or 1 + */ +int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val ) +{ + int ret = 0; + size_t off = pos / biL; + size_t idx = pos % biL; + MPI_VALIDATE_RET( X != NULL ); + + if( val != 0 && val != 1 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + if( X->n * biL <= pos ) + { + if( val == 0 ) + return( 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, off + 1 ) ); + } + + X->p[off] &= ~( (mbedtls_mpi_uint) 0x01 << idx ); + X->p[off] |= (mbedtls_mpi_uint) val << idx; + +cleanup: + + return( ret ); +} + +/* + * Return the number of less significant zero-bits + */ +size_t mbedtls_mpi_lsb( const mbedtls_mpi *X ) +{ + size_t i, j, count = 0; + MBEDTLS_INTERNAL_VALIDATE_RET( X != NULL, 0 ); + + for( i = 0; i < X->n; i++ ) + for( j = 0; j < biL; j++, count++ ) + if( ( ( X->p[i] >> j ) & 1 ) != 0 ) + return( count ); + + return( 0 ); +} + +/* + * Count leading zero bits in a given integer + */ +static size_t mbedtls_clz( const mbedtls_mpi_uint x ) +{ + size_t j; + mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1); + + for( j = 0; j < biL; j++ ) + { + if( x & mask ) break; + + mask >>= 1; + } + + return j; +} + +/* + * Return the number of bits + */ +size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X ) +{ + size_t i, j; + + if( X->n == 0 ) + return( 0 ); + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + + j = biL - mbedtls_clz( X->p[i] ); + + return( ( i * biL ) + j ); +} + +/* + * Return the total size in bytes + */ +size_t mbedtls_mpi_size( const mbedtls_mpi *X ) +{ + return( ( mbedtls_mpi_bitlen( X ) + 7 ) >> 3 ); +} + +/* + * Convert an ASCII character to digit value + */ +static int mpi_get_digit( mbedtls_mpi_uint *d, int radix, char c ) +{ + *d = 255; + + if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; + if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; + if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; + + if( *d >= (mbedtls_mpi_uint) radix ) + return( MBEDTLS_ERR_MPI_INVALID_CHARACTER ); + + return( 0 ); +} + +/* + * Import from an ASCII string + */ +int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s ) +{ + int ret; + size_t i, j, slen, n; + mbedtls_mpi_uint d; + mbedtls_mpi T; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( s != NULL ); + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &T ); + + slen = strlen( s ); + + if( radix == 16 ) + { + if( slen > MPI_SIZE_T_MAX >> 2 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + n = BITS_TO_LIMBS( slen << 2 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i = slen, j = 0; i > 0; i--, j++ ) + { + if( i == 1 && s[i - 1] == '-' ) + { + X->s = -1; + break; + } + + MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) ); + X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 ); + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i = 0; i < slen; i++ ) + { + if( i == 0 && s[i] == '-' ) + { + X->s = -1; + continue; + } + + MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T, X, radix ) ); + + if( X->s == 1 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, &T, d ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( X, &T, d ) ); + } + } + } + +cleanup: + + mbedtls_mpi_free( &T ); + + return( ret ); +} + +/* + * Helper to write the digits high-order first. + */ +static int mpi_write_hlp( mbedtls_mpi *X, int radix, + char **p, const size_t buflen ) +{ + int ret; + mbedtls_mpi_uint r; + size_t length = 0; + char *p_end = *p + buflen; + + do + { + if( length >= buflen ) + { + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) ); + /* + * Write the residue in the current position, as an ASCII character. + */ + if( r < 0xA ) + *(--p_end) = (char)( '0' + r ); + else + *(--p_end) = (char)( 'A' + ( r - 0xA ) ); + + length++; + } while( mbedtls_mpi_cmp_int( X, 0 ) != 0 ); + + memmove( *p, p_end, length ); + *p += length; + +cleanup: + + return( ret ); +} + +/* + * Export into an ASCII string + */ +int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix, + char *buf, size_t buflen, size_t *olen ) +{ + int ret = 0; + size_t n; + char *p; + mbedtls_mpi T; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( olen != NULL ); + MPI_VALIDATE_RET( buflen == 0 || buf != NULL ); + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + n = mbedtls_mpi_bitlen( X ); /* Number of bits necessary to present `n`. */ + if( radix >= 4 ) n >>= 1; /* Number of 4-adic digits necessary to present + * `n`. If radix > 4, this might be a strict + * overapproximation of the number of + * radix-adic digits needed to present `n`. */ + if( radix >= 16 ) n >>= 1; /* Number of hexadecimal digits necessary to + * present `n`. */ + + n += 1; /* Terminating null byte */ + n += 1; /* Compensate for the divisions above, which round down `n` + * in case it's not even. */ + n += 1; /* Potential '-'-sign. */ + n += ( n & 1 ); /* Make n even to have enough space for hexadecimal writing, + * which always uses an even number of hex-digits. */ + + if( buflen < n ) + { + *olen = n; + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + } + + p = buf; + mbedtls_mpi_init( &T ); + + if( X->s == -1 ) + { + *p++ = '-'; + buflen--; + } + + if( radix == 16 ) + { + int c; + size_t i, j, k; + + for( i = X->n, k = 0; i > 0; i-- ) + { + for( j = ciL; j > 0; j-- ) + { + c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF; + + if( c == 0 && k == 0 && ( i + j ) != 2 ) + continue; + + *(p++) = "0123456789ABCDEF" [c / 16]; + *(p++) = "0123456789ABCDEF" [c % 16]; + k = 1; + } + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T, X ) ); + + if( T.s == -1 ) + T.s = 1; + + MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p, buflen ) ); + } + + *p++ = '\0'; + *olen = p - buf; + +cleanup: + + mbedtls_mpi_free( &T ); + + return( ret ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Read X from an opened file + */ +int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin ) +{ + mbedtls_mpi_uint d; + size_t slen; + char *p; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ]; + + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( fin != NULL ); + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + memset( s, 0, sizeof( s ) ); + if( fgets( s, sizeof( s ) - 1, fin ) == NULL ) + return( MBEDTLS_ERR_MPI_FILE_IO_ERROR ); + + slen = strlen( s ); + if( slen == sizeof( s ) - 2 ) + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + + if( slen > 0 && s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; } + if( slen > 0 && s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; } + + p = s + slen; + while( p-- > s ) + if( mpi_get_digit( &d, radix, *p ) != 0 ) + break; + + return( mbedtls_mpi_read_string( X, radix, p + 1 ) ); +} + +/* + * Write X into an opened file (or stdout if fout == NULL) + */ +int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout ) +{ + int ret; + size_t n, slen, plen; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ]; + MPI_VALIDATE_RET( X != NULL ); + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + memset( s, 0, sizeof( s ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_string( X, radix, s, sizeof( s ) - 2, &n ) ); + + if( p == NULL ) p = ""; + + plen = strlen( p ); + slen = strlen( s ); + s[slen++] = '\r'; + s[slen++] = '\n'; + + if( fout != NULL ) + { + if( fwrite( p, 1, plen, fout ) != plen || + fwrite( s, 1, slen, fout ) != slen ) + return( MBEDTLS_ERR_MPI_FILE_IO_ERROR ); + } + else + mbedtls_printf( "%s%s", p, s ); + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + + +/* Convert a big-endian byte array aligned to the size of mbedtls_mpi_uint + * into the storage form used by mbedtls_mpi. */ + +static mbedtls_mpi_uint mpi_uint_bigendian_to_host_c( mbedtls_mpi_uint x ) +{ + uint8_t i; + mbedtls_mpi_uint tmp = 0; + /* This works regardless of the endianness. */ + for( i = 0; i < ciL; i++, x >>= 8 ) + tmp |= ( x & 0xFF ) << ( ( ciL - 1 - i ) << 3 ); + return( tmp ); +} + +static mbedtls_mpi_uint mpi_uint_bigendian_to_host( mbedtls_mpi_uint x ) +{ +#if defined(__BYTE_ORDER__) + +/* Nothing to do on bigendian systems. */ +#if ( __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ) + return( x ); +#endif /* __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ */ + +#if ( __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ) + +/* For GCC and Clang, have builtins for byte swapping. */ +#if defined(__GNUC__) && defined(__GNUC_PREREQ) +#if __GNUC_PREREQ(4,3) +#define have_bswap +#endif +#endif + +#if defined(__clang__) && defined(__has_builtin) +#if __has_builtin(__builtin_bswap32) && \ + __has_builtin(__builtin_bswap64) +#define have_bswap +#endif +#endif + +#if defined(have_bswap) + /* The compiler is hopefully able to statically evaluate this! */ + switch( sizeof(mbedtls_mpi_uint) ) + { + case 4: + return( __builtin_bswap32(x) ); + case 8: + return( __builtin_bswap64(x) ); + } +#endif +#endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */ +#endif /* __BYTE_ORDER__ */ + + /* Fall back to C-based reordering if we don't know the byte order + * or we couldn't use a compiler-specific builtin. */ + return( mpi_uint_bigendian_to_host_c( x ) ); +} + +static void mpi_bigendian_to_host( mbedtls_mpi_uint * const p, size_t limbs ) +{ + mbedtls_mpi_uint *cur_limb_left; + mbedtls_mpi_uint *cur_limb_right; + if( limbs == 0 ) + return; + + /* + * Traverse limbs and + * - adapt byte-order in each limb + * - swap the limbs themselves. + * For that, simultaneously traverse the limbs from left to right + * and from right to left, as long as the left index is not bigger + * than the right index (it's not a problem if limbs is odd and the + * indices coincide in the last iteration). + */ + for( cur_limb_left = p, cur_limb_right = p + ( limbs - 1 ); + cur_limb_left <= cur_limb_right; + cur_limb_left++, cur_limb_right-- ) + { + mbedtls_mpi_uint tmp; + /* Note that if cur_limb_left == cur_limb_right, + * this code effectively swaps the bytes only once. */ + tmp = mpi_uint_bigendian_to_host( *cur_limb_left ); + *cur_limb_left = mpi_uint_bigendian_to_host( *cur_limb_right ); + *cur_limb_right = tmp; + } +} + +/* + * Import X from unsigned binary data, little endian + */ +int mbedtls_mpi_read_binary_le( mbedtls_mpi *X, + const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t i; + size_t const limbs = CHARS_TO_LIMBS( buflen ); + + /* Ensure that target MPI has exactly the necessary number of limbs */ + if( X->n != limbs ) + { + mbedtls_mpi_free( X ); + mbedtls_mpi_init( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i = 0; i < buflen; i++ ) + X->p[i / ciL] |= ((mbedtls_mpi_uint) buf[i]) << ((i % ciL) << 3); + +cleanup: + + /* + * This function is also used to import keys. However, wiping the buffers + * upon failure is not necessary because failure only can happen before any + * input is copied. + */ + return( ret ); +} + +/* + * Import X from unsigned binary data, big endian + */ +int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t const limbs = CHARS_TO_LIMBS( buflen ); + size_t const overhead = ( limbs * ciL ) - buflen; + unsigned char *Xp; + + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( buflen == 0 || buf != NULL ); + + /* Ensure that target MPI has exactly the necessary number of limbs */ + if( X->n != limbs ) + { + mbedtls_mpi_free( X ); + mbedtls_mpi_init( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) ); + } + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + /* Avoid calling `memcpy` with NULL source argument, + * even if buflen is 0. */ + if( buf != NULL ) + { + Xp = (unsigned char*) X->p; + memcpy( Xp + overhead, buf, buflen ); + + mpi_bigendian_to_host( X->p, limbs ); + } + +cleanup: + + /* + * This function is also used to import keys. However, wiping the buffers + * upon failure is not necessary because failure only can happen before any + * input is copied. + */ + return( ret ); +} + +/* + * Export X into unsigned binary data, little endian + */ +int mbedtls_mpi_write_binary_le( const mbedtls_mpi *X, + unsigned char *buf, size_t buflen ) +{ + size_t stored_bytes = X->n * ciL; + size_t bytes_to_copy; + size_t i; + + if( stored_bytes < buflen ) + { + bytes_to_copy = stored_bytes; + } + else + { + bytes_to_copy = buflen; + + /* The output buffer is smaller than the allocated size of X. + * However X may fit if its leading bytes are zero. */ + for( i = bytes_to_copy; i < stored_bytes; i++ ) + { + if( GET_BYTE( X, i ) != 0 ) + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + } + } + + for( i = 0; i < bytes_to_copy; i++ ) + buf[i] = GET_BYTE( X, i ); + + if( stored_bytes < buflen ) + { + /* Write trailing 0 bytes */ + memset( buf + stored_bytes, 0, buflen - stored_bytes ); + } + + return( 0 ); +} + +/* + * Export X into unsigned binary data, big endian + */ +int mbedtls_mpi_write_binary( const mbedtls_mpi *X, + unsigned char *buf, size_t buflen ) +{ + size_t stored_bytes; + size_t bytes_to_copy; + unsigned char *p; + size_t i; + + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( buflen == 0 || buf != NULL ); + + stored_bytes = X->n * ciL; + + if( stored_bytes < buflen ) + { + /* There is enough space in the output buffer. Write initial + * null bytes and record the position at which to start + * writing the significant bytes. In this case, the execution + * trace of this function does not depend on the value of the + * number. */ + bytes_to_copy = stored_bytes; + p = buf + buflen - stored_bytes; + memset( buf, 0, buflen - stored_bytes ); + } + else + { + /* The output buffer is smaller than the allocated size of X. + * However X may fit if its leading bytes are zero. */ + bytes_to_copy = buflen; + p = buf; + for( i = bytes_to_copy; i < stored_bytes; i++ ) + { + if( GET_BYTE( X, i ) != 0 ) + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + } + } + + for( i = 0; i < bytes_to_copy; i++ ) + p[bytes_to_copy - i - 1] = GET_BYTE( X, i ); + + return( 0 ); +} + +/* + * Left-shift: X <<= count + */ +int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count ) +{ + int ret; + size_t i, v0, t1; + mbedtls_mpi_uint r0 = 0, r1; + MPI_VALIDATE_RET( X != NULL ); + + v0 = count / (biL ); + t1 = count & (biL - 1); + + i = mbedtls_mpi_bitlen( X ) + count; + + if( X->n * biL < i ) + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, BITS_TO_LIMBS( i ) ) ); + + ret = 0; + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = X->n; i > v0; i-- ) + X->p[i - 1] = X->p[i - v0 - 1]; + + for( ; i > 0; i-- ) + X->p[i - 1] = 0; + } + + /* + * shift by count % limb_size + */ + if( t1 > 0 ) + { + for( i = v0; i < X->n; i++ ) + { + r1 = X->p[i] >> (biL - t1); + X->p[i] <<= t1; + X->p[i] |= r0; + r0 = r1; + } + } + +cleanup: + + return( ret ); +} + +/* + * Right-shift: X >>= count + */ +int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count ) +{ + size_t i, v0, v1; + mbedtls_mpi_uint r0 = 0, r1; + MPI_VALIDATE_RET( X != NULL ); + + v0 = count / biL; + v1 = count & (biL - 1); + + if( v0 > X->n || ( v0 == X->n && v1 > 0 ) ) + return mbedtls_mpi_lset( X, 0 ); + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = 0; i < X->n - v0; i++ ) + X->p[i] = X->p[i + v0]; + + for( ; i < X->n; i++ ) + X->p[i] = 0; + } + + /* + * shift by count % limb_size + */ + if( v1 > 0 ) + { + for( i = X->n; i > 0; i-- ) + { + r1 = X->p[i - 1] << (biL - v1); + X->p[i - 1] >>= v1; + X->p[i - 1] |= r0; + r0 = r1; + } + } + + return( 0 ); +} + +/* + * Compare unsigned values + */ +int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y ) +{ + size_t i, j; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( Y != NULL ); + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( 1 ); + if( j > i ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( 1 ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -1 ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ) +{ + size_t i, j; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( Y != NULL ); + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( X->s ); + if( j > i ) return( -Y->s ); + + if( X->s > 0 && Y->s < 0 ) return( 1 ); + if( Y->s > 0 && X->s < 0 ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( X->s ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z ) +{ + mbedtls_mpi Y; + mbedtls_mpi_uint p[1]; + MPI_VALIDATE_RET( X != NULL ); + + *p = ( z < 0 ) ? -z : z; + Y.s = ( z < 0 ) ? -1 : 1; + Y.n = 1; + Y.p = p; + + return( mbedtls_mpi_cmp_mpi( X, &Y ) ); +} + +/* + * Unsigned addition: X = |A| + |B| (HAC 14.7) + */ +int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t i, j; + mbedtls_mpi_uint *o, *p, c, tmp; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); + + if( X == B ) + { + const mbedtls_mpi *T = A; A = X; B = T; + } + + if( X != A ) + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned additions. + */ + X->s = 1; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) ); + + o = B->p; p = X->p; c = 0; + + /* + * tmp is used because it might happen that p == o + */ + for( i = 0; i < j; i++, o++, p++ ) + { + tmp= *o; + *p += c; c = ( *p < c ); + *p += tmp; c += ( *p < tmp ); + } + + while( c != 0 ) + { + if( i >= X->n ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + 1 ) ); + p = X->p + i; + } + + *p += c; c = ( *p < c ); i++; p++; + } + +cleanup: + + return( ret ); +} + +/* + * Helper for mbedtls_mpi subtraction + */ +static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d ) +{ + size_t i; + mbedtls_mpi_uint c, z; + + for( i = c = 0; i < n; i++, s++, d++ ) + { + z = ( *d < c ); *d -= c; + c = ( *d < *s ) + z; *d -= *s; + } + + while( c != 0 ) + { + z = ( *d < c ); *d -= c; + c = z; d++; + } +} + +/* + * Unsigned subtraction: X = |A| - |B| (HAC 14.9) + */ +int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + mbedtls_mpi TB; + int ret; + size_t n; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); + + if( mbedtls_mpi_cmp_abs( A, B ) < 0 ) + return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); + + mbedtls_mpi_init( &TB ); + + if( X == B ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); + B = &TB; + } + + if( X != A ) + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned subtractions. + */ + X->s = 1; + + ret = 0; + + for( n = B->n; n > 0; n-- ) + if( B->p[n - 1] != 0 ) + break; + + mpi_sub_hlp( n, B->p, X->p ); + +cleanup: + + mbedtls_mpi_free( &TB ); + + return( ret ); +} + +/* + * Signed addition: X = A + B + */ +int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret, s; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); + + s = A->s; + if( A->s * B->s < 0 ) + { + if( mbedtls_mpi_cmp_abs( A, B ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed subtraction: X = A - B + */ +int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret, s; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); + + s = A->s; + if( A->s * B->s > 0 ) + { + if( mbedtls_mpi_cmp_abs( A, B ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed addition: X = A + b + */ +int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mbedtls_mpi_add_mpi( X, A, &_B ) ); +} + +/* + * Signed subtraction: X = A - b + */ +int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mbedtls_mpi_sub_mpi( X, A, &_B ) ); +} + +/* + * Helper for mbedtls_mpi multiplication + */ +static +#if defined(__APPLE__) && defined(__arm__) +/* + * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn) + * appears to need this to prevent bad ARM code generation at -O3. + */ +__attribute__ ((noinline)) +#endif +void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b ) +{ + mbedtls_mpi_uint c = 0, t = 0; + +#if defined(MULADDC_HUIT) + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_HUIT + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#else /* MULADDC_HUIT */ + for( ; i >= 16; i -= 16 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#endif /* MULADDC_HUIT */ + + t++; + + do { + *d += c; c = ( *d < c ); d++; + } + while( c != 0 ); +} + +/* + * Baseline multiplication: X = A * B (HAC 14.12) + */ +int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t i, j; + mbedtls_mpi TA, TB; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); + + mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB ); + + if( X == A ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); A = &TA; } + if( X == B ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); B = &TB; } + + for( i = A->n; i > 0; i-- ) + if( A->p[i - 1] != 0 ) + break; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( ; j > 0; j-- ) + mpi_mul_hlp( i, A->p, X->p + j - 1, B->p[j - 1] ); + + X->s = A->s * B->s; + +cleanup: + + mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TA ); + + return( ret ); +} + +/* + * Baseline multiplication: X = A * b + */ +int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + + _B.s = 1; + _B.n = 1; + _B.p = p; + p[0] = b; + + return( mbedtls_mpi_mul_mpi( X, A, &_B ) ); +} + +/* + * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and + * mbedtls_mpi_uint divisor, d + */ +static mbedtls_mpi_uint mbedtls_int_div_int( mbedtls_mpi_uint u1, + mbedtls_mpi_uint u0, mbedtls_mpi_uint d, mbedtls_mpi_uint *r ) +{ +#if defined(MBEDTLS_HAVE_UDBL) + mbedtls_t_udbl dividend, quotient; +#else + const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH; + const mbedtls_mpi_uint uint_halfword_mask = ( (mbedtls_mpi_uint) 1 << biH ) - 1; + mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient; + mbedtls_mpi_uint u0_msw, u0_lsw; + size_t s; +#endif + + /* + * Check for overflow + */ + if( 0 == d || u1 >= d ) + { + if (r != NULL) *r = ~0; + + return ( ~0 ); + } + +#if defined(MBEDTLS_HAVE_UDBL) + dividend = (mbedtls_t_udbl) u1 << biL; + dividend |= (mbedtls_t_udbl) u0; + quotient = dividend / d; + if( quotient > ( (mbedtls_t_udbl) 1 << biL ) - 1 ) + quotient = ( (mbedtls_t_udbl) 1 << biL ) - 1; + + if( r != NULL ) + *r = (mbedtls_mpi_uint)( dividend - (quotient * d ) ); + + return (mbedtls_mpi_uint) quotient; +#else + + /* + * Algorithm D, Section 4.3.1 - The Art of Computer Programming + * Vol. 2 - Seminumerical Algorithms, Knuth + */ + + /* + * Normalize the divisor, d, and dividend, u0, u1 + */ + s = mbedtls_clz( d ); + d = d << s; + + u1 = u1 << s; + u1 |= ( u0 >> ( biL - s ) ) & ( -(mbedtls_mpi_sint)s >> ( biL - 1 ) ); + u0 = u0 << s; + + d1 = d >> biH; + d0 = d & uint_halfword_mask; + + u0_msw = u0 >> biH; + u0_lsw = u0 & uint_halfword_mask; + + /* + * Find the first quotient and remainder + */ + q1 = u1 / d1; + r0 = u1 - d1 * q1; + + while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) ) + { + q1 -= 1; + r0 += d1; + + if ( r0 >= radix ) break; + } + + rAX = ( u1 * radix ) + ( u0_msw - q1 * d ); + q0 = rAX / d1; + r0 = rAX - q0 * d1; + + while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) ) + { + q0 -= 1; + r0 += d1; + + if ( r0 >= radix ) break; + } + + if (r != NULL) + *r = ( rAX * radix + u0_lsw - q0 * d ) >> s; + + quotient = q1 * radix + q0; + + return quotient; +#endif +} + +/* + * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20) + */ +int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, + const mbedtls_mpi *B ) +{ + int ret; + size_t i, n, t, k; + mbedtls_mpi X, Y, Z, T1, T2; + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); + + if( mbedtls_mpi_cmp_int( B, 0 ) == 0 ) + return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO ); + + mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z ); + mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 ); + + if( mbedtls_mpi_cmp_abs( A, B ) < 0 ) + { + if( Q != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_lset( Q, 0 ) ); + if( R != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, A ) ); + return( 0 ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &X, A ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, B ) ); + X.s = Y.s = 1; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &Z, A->n + 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Z, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T1, 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T2, 3 ) ); + + k = mbedtls_mpi_bitlen( &Y ) % biL; + if( k < biL - 1 ) + { + k = biL - 1 - k; + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &X, k ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, k ) ); + } + else k = 0; + + n = X.n - 1; + t = Y.n - 1; + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, biL * ( n - t ) ) ); + + while( mbedtls_mpi_cmp_mpi( &X, &Y ) >= 0 ) + { + Z.p[n - t]++; + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &Y ) ); + } + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, biL * ( n - t ) ) ); + + for( i = n; i > t ; i-- ) + { + if( X.p[i] >= Y.p[t] ) + Z.p[i - t - 1] = ~0; + else + { + Z.p[i - t - 1] = mbedtls_int_div_int( X.p[i], X.p[i - 1], + Y.p[t], NULL); + } + + Z.p[i - t - 1]++; + do + { + Z.p[i - t - 1]--; + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T1, 0 ) ); + T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1]; + T1.p[1] = Y.p[t]; + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T2, 0 ) ); + T2.p[0] = ( i < 2 ) ? 0 : X.p[i - 2]; + T2.p[1] = ( i < 1 ) ? 0 : X.p[i - 1]; + T2.p[2] = X.p[i]; + } + while( mbedtls_mpi_cmp_mpi( &T1, &T2 ) > 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) ); + + if( mbedtls_mpi_cmp_int( &X, 0 ) < 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T1, &Y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &X, &X, &T1 ) ); + Z.p[i - t - 1]--; + } + } + + if( Q != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( Q, &Z ) ); + Q->s = A->s * B->s; + } + + if( R != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &X, k ) ); + X.s = A->s; + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, &X ) ); + + if( mbedtls_mpi_cmp_int( R, 0 ) == 0 ) + R->s = 1; + } + +cleanup: + + mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); + mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); + + return( ret ); +} + +/* + * Division by int: A = Q * b + R + */ +int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, + const mbedtls_mpi *A, + mbedtls_mpi_sint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + MPI_VALIDATE_RET( A != NULL ); + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mbedtls_mpi_div_mpi( Q, R, A, &_B ) ); +} + +/* + * Modulo: R = A mod B + */ +int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + MPI_VALIDATE_RET( R != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); + + if( mbedtls_mpi_cmp_int( B, 0 ) < 0 ) + return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( NULL, R, A, B ) ); + + while( mbedtls_mpi_cmp_int( R, 0 ) < 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) ); + + while( mbedtls_mpi_cmp_mpi( R, B ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) ); + +cleanup: + + return( ret ); +} + +/* + * Modulo: r = A mod b + */ +int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + size_t i; + mbedtls_mpi_uint x, y, z; + MPI_VALIDATE_RET( r != NULL ); + MPI_VALIDATE_RET( A != NULL ); + + if( b == 0 ) + return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO ); + + if( b < 0 ) + return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); + + /* + * handle trivial cases + */ + if( b == 1 ) + { + *r = 0; + return( 0 ); + } + + if( b == 2 ) + { + *r = A->p[0] & 1; + return( 0 ); + } + + /* + * general case + */ + for( i = A->n, y = 0; i > 0; i-- ) + { + x = A->p[i - 1]; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + + x <<= biH; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + } + + /* + * If A is negative, then the current y represents a negative value. + * Flipping it to the positive side. + */ + if( A->s < 0 && y != 0 ) + y = b - y; + + *r = y; + + return( 0 ); +} + +/* + * Fast Montgomery initialization (thanks to Tom St Denis) + */ +static void mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N ) +{ + mbedtls_mpi_uint x, m0 = N->p[0]; + unsigned int i; + + x = m0; + x += ( ( m0 + 2 ) & 4 ) << 1; + + for( i = biL; i >= 8; i /= 2 ) + x *= ( 2 - ( m0 * x ) ); + + *mm = ~x + 1; +} + +/* + * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) + */ +static int mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi *N, mbedtls_mpi_uint mm, + const mbedtls_mpi *T ) +{ + size_t i, n, m; + mbedtls_mpi_uint u0, u1, *d; + + if( T->n < N->n + 1 || T->p == NULL ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + memset( T->p, 0, T->n * ciL ); + + d = T->p; + n = N->n; + m = ( B->n < n ) ? B->n : n; + + for( i = 0; i < n; i++ ) + { + /* + * T = (T + u0*B + u1*N) / 2^biL + */ + u0 = A->p[i]; + u1 = ( d[0] + u0 * B->p[0] ) * mm; + + mpi_mul_hlp( m, B->p, d, u0 ); + mpi_mul_hlp( n, N->p, d, u1 ); + + *d++ = u0; d[n + 1] = 0; + } + + memcpy( A->p, d, ( n + 1 ) * ciL ); + + if( mbedtls_mpi_cmp_abs( A, N ) >= 0 ) + mpi_sub_hlp( n, N->p, A->p ); + else + /* prevent timing attacks */ + mpi_sub_hlp( n, A->p, T->p ); + + return( 0 ); +} + +/* + * Montgomery reduction: A = A * R^-1 mod N + */ +static int mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, + mbedtls_mpi_uint mm, const mbedtls_mpi *T ) +{ + mbedtls_mpi_uint z = 1; + mbedtls_mpi U; + + U.n = U.s = (int) z; + U.p = &z; + + return( mpi_montmul( A, &U, N, mm, T ) ); +} + +/* + * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) + */ +int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, + const mbedtls_mpi *E, const mbedtls_mpi *N, + mbedtls_mpi *_RR ) +{ + int ret; + size_t wbits, wsize, one = 1; + size_t i, j, nblimbs; + size_t bufsize, nbits; + mbedtls_mpi_uint ei, mm, state; + mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos; + int neg; + + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( E != NULL ); + MPI_VALIDATE_RET( N != NULL ); + + if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 || ( N->p[0] & 1 ) == 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + if( mbedtls_mpi_cmp_int( E, 0 ) < 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + /* + * Init temps and window size + */ + mpi_montg_init( &mm, N ); + mbedtls_mpi_init( &RR ); mbedtls_mpi_init( &T ); + mbedtls_mpi_init( &Apos ); + memset( W, 0, sizeof( W ) ); + + i = mbedtls_mpi_bitlen( E ); + + wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : + ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; + +#if( MBEDTLS_MPI_WINDOW_SIZE < 6 ) + if( wsize > MBEDTLS_MPI_WINDOW_SIZE ) + wsize = MBEDTLS_MPI_WINDOW_SIZE; +#endif + + j = N->n + 1; + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1], j ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) ); + + /* + * Compensate for negative A (and correct at the end) + */ + neg = ( A->s == -1 ); + if( neg ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Apos, A ) ); + Apos.s = 1; + A = &Apos; + } + + /* + * If 1st call, pre-compute R^2 mod N + */ + if( _RR == NULL || _RR->p == NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &RR, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &RR, N->n * 2 * biL ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &RR, &RR, N ) ); + + if( _RR != NULL ) + memcpy( _RR, &RR, sizeof( mbedtls_mpi ) ); + } + else + memcpy( &RR, _RR, sizeof( mbedtls_mpi ) ); + + /* + * W[1] = A * R^2 * R^-1 mod N = A * R mod N + */ + if( mbedtls_mpi_cmp_mpi( A, N ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &W[1], A, N ) ); + else + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[1], A ) ); + + MBEDTLS_MPI_CHK( mpi_montmul( &W[1], &RR, N, mm, &T ) ); + + /* + * X = R^2 * R^-1 mod N = R mod N + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) ); + MBEDTLS_MPI_CHK( mpi_montred( X, N, mm, &T ) ); + + if( wsize > 1 ) + { + /* + * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) + */ + j = one << ( wsize - 1 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1] ) ); + + for( i = 0; i < wsize - 1; i++ ) + MBEDTLS_MPI_CHK( mpi_montmul( &W[j], &W[j], N, mm, &T ) ); + + /* + * W[i] = W[i - 1] * W[1] + */ + for( i = j + 1; i < ( one << wsize ); i++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) ); + + MBEDTLS_MPI_CHK( mpi_montmul( &W[i], &W[1], N, mm, &T ) ); + } + } + + nblimbs = E->n; + bufsize = 0; + nbits = 0; + wbits = 0; + state = 0; + + while( 1 ) + { + if( bufsize == 0 ) + { + if( nblimbs == 0 ) + break; + + nblimbs--; + + bufsize = sizeof( mbedtls_mpi_uint ) << 3; + } + + bufsize--; + + ei = (E->p[nblimbs] >> bufsize) & 1; + + /* + * skip leading 0s + */ + if( ei == 0 && state == 0 ) + continue; + + if( ei == 0 && state == 1 ) + { + /* + * out of window, square X + */ + MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) ); + continue; + } + + /* + * add ei to current window + */ + state = 2; + + nbits++; + wbits |= ( ei << ( wsize - nbits ) ); + + if( nbits == wsize ) + { + /* + * X = X^wsize R^-1 mod N + */ + for( i = 0; i < wsize; i++ ) + MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) ); + + /* + * X = X * W[wbits] R^-1 mod N + */ + MBEDTLS_MPI_CHK( mpi_montmul( X, &W[wbits], N, mm, &T ) ); + + state--; + nbits = 0; + wbits = 0; + } + } + + /* + * process the remaining bits + */ + for( i = 0; i < nbits; i++ ) + { + MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) ); + + wbits <<= 1; + + if( ( wbits & ( one << wsize ) ) != 0 ) + MBEDTLS_MPI_CHK( mpi_montmul( X, &W[1], N, mm, &T ) ); + } + + /* + * X = A^E * R * R^-1 mod N = A^E mod N + */ + MBEDTLS_MPI_CHK( mpi_montred( X, N, mm, &T ) ); + + if( neg && E->n != 0 && ( E->p[0] & 1 ) != 0 ) + { + X->s = -1; + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) ); + } + +cleanup: + + for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ ) + mbedtls_mpi_free( &W[i] ); + + mbedtls_mpi_free( &W[1] ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos ); + + if( _RR == NULL || _RR->p == NULL ) + mbedtls_mpi_free( &RR ); + + return( ret ); +} + +/* + * Greatest common divisor: G = gcd(A, B) (HAC 14.54) + */ +int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t lz, lzt; + mbedtls_mpi TG, TA, TB; + + MPI_VALIDATE_RET( G != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( B != NULL ); + + mbedtls_mpi_init( &TG ); mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); + + lz = mbedtls_mpi_lsb( &TA ); + lzt = mbedtls_mpi_lsb( &TB ); + + if( lzt < lz ) + lz = lzt; + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, lz ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, lz ) ); + + TA.s = TB.s = 1; + + while( mbedtls_mpi_cmp_int( &TA, 0 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, mbedtls_mpi_lsb( &TA ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, mbedtls_mpi_lsb( &TB ) ) ); + + if( mbedtls_mpi_cmp_mpi( &TA, &TB ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TA, &TA, &TB ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, 1 ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TB, &TB, &TA ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, 1 ) ); + } + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &TB, lz ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( G, &TB ) ); + +cleanup: + + mbedtls_mpi_free( &TG ); mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TB ); + + return( ret ); +} + +/* + * Fill X with size bytes of random. + * + * Use a temporary bytes representation to make sure the result is the same + * regardless of the platform endianness (useful when f_rng is actually + * deterministic, eg for tests). + */ +int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t const limbs = CHARS_TO_LIMBS( size ); + size_t const overhead = ( limbs * ciL ) - size; + unsigned char *Xp; + + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( f_rng != NULL ); + + /* Ensure that target MPI has exactly the necessary number of limbs */ + if( X->n != limbs ) + { + mbedtls_mpi_free( X ); + mbedtls_mpi_init( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) ); + } + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + Xp = (unsigned char*) X->p; + f_rng( p_rng, Xp + overhead, size ); + + mpi_bigendian_to_host( X->p, limbs ); + +cleanup: + return( ret ); +} + +/* + * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) + */ +int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N ) +{ + int ret; + mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( A != NULL ); + MPI_VALIDATE_RET( N != NULL ); + + if( mbedtls_mpi_cmp_int( N, 1 ) <= 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TU ); mbedtls_mpi_init( &U1 ); mbedtls_mpi_init( &U2 ); + mbedtls_mpi_init( &G ); mbedtls_mpi_init( &TB ); mbedtls_mpi_init( &TV ); + mbedtls_mpi_init( &V1 ); mbedtls_mpi_init( &V2 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, A, N ) ); + + if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &TA, A, N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TU, &TA ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TV, N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U1, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U2, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V1, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V2, 1 ) ); + + do + { + while( ( TU.p[0] & 1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TU, 1 ) ); + + if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &U1, &U1, &TB ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &TA ) ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U1, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U2, 1 ) ); + } + + while( ( TV.p[0] & 1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TV, 1 ) ); + + if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, &TB ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &TA ) ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V1, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V2, 1 ) ); + } + + if( mbedtls_mpi_cmp_mpi( &TU, &TV ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TU, &TU, &TV ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U1, &U1, &V1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &V2 ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TV, &TV, &TU ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, &U1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &U2 ) ); + } + } + while( mbedtls_mpi_cmp_int( &TU, 0 ) != 0 ); + + while( mbedtls_mpi_cmp_int( &V1, 0 ) < 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, N ) ); + + while( mbedtls_mpi_cmp_mpi( &V1, N ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &V1 ) ); + +cleanup: + + mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TU ); mbedtls_mpi_free( &U1 ); mbedtls_mpi_free( &U2 ); + mbedtls_mpi_free( &G ); mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TV ); + mbedtls_mpi_free( &V1 ); mbedtls_mpi_free( &V2 ); + + return( ret ); +} + +#if defined(MBEDTLS_GENPRIME) + +static const int small_prime[] = +{ + 3, 5, 7, 11, 13, 17, 19, 23, + 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773, + 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, + 887, 907, 911, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997, -103 +}; + +/* + * Small divisors test (X must be positive) + * + * Return values: + * 0: no small factor (possible prime, more tests needed) + * 1: certain prime + * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime + * other negative: error + */ +static int mpi_check_small_factors( const mbedtls_mpi *X ) +{ + int ret = 0; + size_t i; + mbedtls_mpi_uint r; + + if( ( X->p[0] & 1 ) == 0 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + + for( i = 0; small_prime[i] > 0; i++ ) + { + if( mbedtls_mpi_cmp_int( X, small_prime[i] ) <= 0 ) + return( 1 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, small_prime[i] ) ); + + if( r == 0 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + } + +cleanup: + return( ret ); +} + +/* + * Miller-Rabin pseudo-primality test (HAC 4.24) + */ +static int mpi_miller_rabin( const mbedtls_mpi *X, size_t rounds, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, count; + size_t i, j, k, s; + mbedtls_mpi W, R, T, A, RR; + + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( f_rng != NULL ); + + mbedtls_mpi_init( &W ); mbedtls_mpi_init( &R ); + mbedtls_mpi_init( &T ); mbedtls_mpi_init( &A ); + mbedtls_mpi_init( &RR ); + + /* + * W = |X| - 1 + * R = W >> lsb( W ) + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &W, X, 1 ) ); + s = mbedtls_mpi_lsb( &W ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R, &W ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) ); + + i = mbedtls_mpi_bitlen( X ); + + for( i = 0; i < rounds; i++ ) + { + /* + * pick a random A, 1 < A < |X| - 1 + */ + count = 0; + do { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); + + j = mbedtls_mpi_bitlen( &A ); + k = mbedtls_mpi_bitlen( &W ); + if (j > k) { + A.p[A.n - 1] &= ( (mbedtls_mpi_uint) 1 << ( k - ( A.n - 1 ) * biL - 1 ) ) - 1; + } + + if (count++ > 30) { + return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + } + + } while ( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 || + mbedtls_mpi_cmp_int( &A, 1 ) <= 0 ); + + /* + * A = A^R mod |X| + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &A, &A, &R, X, &RR ) ); + + if( mbedtls_mpi_cmp_mpi( &A, &W ) == 0 || + mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) + continue; + + j = 1; + while( j < s && mbedtls_mpi_cmp_mpi( &A, &W ) != 0 ) + { + /* + * A = A * A mod |X| + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &A, &A ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &A, &T, X ) ); + + if( mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) + break; + + j++; + } + + /* + * not prime if A != |X| - 1 or A == 1 + */ + if( mbedtls_mpi_cmp_mpi( &A, &W ) != 0 || + mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) + { + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + break; + } + } + +cleanup: + mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R ); + mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A ); + mbedtls_mpi_free( &RR ); + + return( ret ); +} + +/* + * Pseudo-primality test: small factors, then Miller-Rabin + */ +int mbedtls_mpi_is_prime_ext( const mbedtls_mpi *X, int rounds, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_mpi XX; + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( f_rng != NULL ); + + XX.s = 1; + XX.n = X->n; + XX.p = X->p; + + if( mbedtls_mpi_cmp_int( &XX, 0 ) == 0 || + mbedtls_mpi_cmp_int( &XX, 1 ) == 0 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + + if( mbedtls_mpi_cmp_int( &XX, 2 ) == 0 ) + return( 0 ); + + if( ( ret = mpi_check_small_factors( &XX ) ) != 0 ) + { + if( ret == 1 ) + return( 0 ); + + return( ret ); + } + + return( mpi_miller_rabin( &XX, rounds, f_rng, p_rng ) ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +/* + * Pseudo-primality test, error probability 2^-80 + */ +int mbedtls_mpi_is_prime( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( f_rng != NULL ); + + /* + * In the past our key generation aimed for an error rate of at most + * 2^-80. Since this function is deprecated, aim for the same certainty + * here as well. + */ + return( mbedtls_mpi_is_prime_ext( X, 40, f_rng, p_rng ) ); +} +#endif + +/* + * Prime number generation + * + * To generate an RSA key in a way recommended by FIPS 186-4, both primes must + * be either 1024 bits or 1536 bits long, and flags must contain + * MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR. + */ +int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int flags, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ +#ifdef MBEDTLS_HAVE_INT64 +// ceil(2^63.5) +#define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL +#else +// ceil(2^31.5) +#define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U +#endif + int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + size_t k, n; + int rounds; + mbedtls_mpi_uint r; + mbedtls_mpi Y; + + MPI_VALIDATE_RET( X != NULL ); + MPI_VALIDATE_RET( f_rng != NULL ); + + if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &Y ); + + n = BITS_TO_LIMBS( nbits ); + + if( ( flags & MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR ) == 0 ) + { + /* + * 2^-80 error probability, number of rounds chosen per HAC, table 4.4 + */ + rounds = ( ( nbits >= 1300 ) ? 2 : ( nbits >= 850 ) ? 3 : + ( nbits >= 650 ) ? 4 : ( nbits >= 350 ) ? 8 : + ( nbits >= 250 ) ? 12 : ( nbits >= 150 ) ? 18 : 27 ); + } + else + { + /* + * 2^-100 error probability, number of rounds computed based on HAC, + * fact 4.48 + */ + rounds = ( ( nbits >= 1450 ) ? 4 : ( nbits >= 1150 ) ? 5 : + ( nbits >= 1000 ) ? 6 : ( nbits >= 850 ) ? 7 : + ( nbits >= 750 ) ? 8 : ( nbits >= 500 ) ? 13 : + ( nbits >= 250 ) ? 28 : ( nbits >= 150 ) ? 40 : 51 ); + } + + while( 1 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) ); + /* make sure generated number is at least (nbits-1)+0.5 bits (FIPS 186-4 §B.3.3 steps 4.4, 5.5) */ + if( X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2 ) continue; + + k = n * biL; + if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits ) ); + X->p[0] |= 1; + + if( ( flags & MBEDTLS_MPI_GEN_PRIME_FLAG_DH ) == 0 ) + { + ret = mbedtls_mpi_is_prime_ext( X, rounds, f_rng, p_rng ); + + if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + } + else + { + /* + * An necessary condition for Y and X = 2Y + 1 to be prime + * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3). + * Make sure it is satisfied, while keeping X = 3 mod 4 + */ + + X->p[0] |= 2; + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) ); + if( r == 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) ); + else if( r == 1 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) ); + + /* Set Y = (X-1) / 2, which is X / 2 because X is odd */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) ); + + while( 1 ) + { + /* + * First, check small factors for X and Y + * before doing Miller-Rabin on any of them + */ + if( ( ret = mpi_check_small_factors( X ) ) == 0 && + ( ret = mpi_check_small_factors( &Y ) ) == 0 && + ( ret = mpi_miller_rabin( X, rounds, f_rng, p_rng ) ) + == 0 && + ( ret = mpi_miller_rabin( &Y, rounds, f_rng, p_rng ) ) + == 0 ) + goto cleanup; + + if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + /* + * Next candidates. We want to preserve Y = (X-1) / 2 and + * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3) + * so up Y by 6 and X by 12. + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 12 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6 ) ); + } + } + } + +cleanup: + + mbedtls_mpi_free( &Y ); + + return( ret ); +} + +#endif /* MBEDTLS_GENPRIME */ + +#if defined(MBEDTLS_SELF_TEST) + +#define GCD_PAIR_COUNT 3 + +static const int gcd_pairs[GCD_PAIR_COUNT][3] = +{ + { 693, 609, 21 }, + { 1764, 868, 28 }, + { 768454923, 542167814, 1 } +}; + +/* + * Checkup routine + */ +int mbedtls_mpi_self_test( int verbose ) +{ + int ret, i; + mbedtls_mpi A, E, N, X, Y, U, V; + + mbedtls_mpi_init( &A ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &N ); mbedtls_mpi_init( &X ); + mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &U ); mbedtls_mpi_init( &V ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &A, 16, + "EFE021C2645FD1DC586E69184AF4A31E" \ + "D5F53E93B5F123FA41680867BA110131" \ + "944FE7952E2517337780CB0DB80E61AA" \ + "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &E, 16, + "B2E7EFD37075B9F03FF989C7C5051C20" \ + "34D2A323810251127E7BF8625A4F49A5" \ + "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ + "5B5C25763222FEFCCFC38B832366C29E" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &N, 16, + "0066A198186C18C10B2F5ED9B522752A" \ + "9830B69916E535C8F047518A889A43A5" \ + "94B6BED27A168D31D4A52F88925AA8F5" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &A, &N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "602AB7ECA597A3D6B56FF9829A5E8B85" \ + "9E857EA95A03512E2BAE7391688D264A" \ + "A5663B0341DB9CCFD2C4C5F421FEC814" \ + "8001B72E848A38CAE1C65F78E56ABDEF" \ + "E12D3C039B8A02D6BE593F0BBBDA56F1" \ + "ECF677152EF804370C1A305CAF3B5BF1" \ + "30879B56C61DE584A0F53A2447A51E" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #1 (mul_mpi): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &X, &Y, &A, &N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "256567336059E52CAE22925474705F39A94" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &V, 16, + "6613F26162223DF488E9CD48CC132C7A" \ + "0AC93C701B001B092E4E5B9F73BCD27B" \ + "9EE50D0657C77F374E903CDFA4C642" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #2 (div_mpi): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 || + mbedtls_mpi_cmp_mpi( &Y, &V ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &X, &A, &E, &N, NULL ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "36E139AEA55215609D2816998ED020BB" \ + "BD96C37890F65171D948E9BC7CBAA4D9" \ + "325D24D6A3C12710F10A09FA08AB87" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #3 (exp_mod): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &X, &A, &N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ + "C3DBA76456363A10869622EAC2DD84EC" \ + "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #4 (inv_mod): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #5 (simple gcd): " ); + + for( i = 0; i < GCD_PAIR_COUNT; i++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &X, gcd_pairs[i][0] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Y, gcd_pairs[i][1] ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &A, &X, &Y ) ); + + if( mbedtls_mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed at %d\n", i ); + + ret = 1; + goto cleanup; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +cleanup: + + if( ret != 0 && verbose != 0 ) + mbedtls_printf( "Unexpected error, return code = %08X\n", ret ); + + mbedtls_mpi_free( &A ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &N ); mbedtls_mpi_free( &X ); + mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &U ); mbedtls_mpi_free( &V ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_BIGNUM_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/blowfish.c b/FreeRTOS-Labs/Source/mbedtls/library/blowfish.c new file mode 100644 index 000000000..75ffb42a6 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/blowfish.c @@ -0,0 +1,696 @@ +/* + * Blowfish implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The Blowfish block cipher was designed by Bruce Schneier in 1993. + * http://www.schneier.com/blowfish.html + * http://en.wikipedia.org/wiki/Blowfish_%28cipher%29 + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_BLOWFISH_C) + +#include "mbedtls/blowfish.h" +#include "mbedtls/platform_util.h" + +#include + +#if !defined(MBEDTLS_BLOWFISH_ALT) + +/* Parameter validation macros */ +#define BLOWFISH_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA ) +#define BLOWFISH_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +static const uint32_t P[MBEDTLS_BLOWFISH_ROUNDS + 2] = { + 0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L, + 0xA4093822L, 0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L, + 0x452821E6L, 0x38D01377L, 0xBE5466CFL, 0x34E90C6CL, + 0xC0AC29B7L, 0xC97C50DDL, 0x3F84D5B5L, 0xB5470917L, + 0x9216D5D9L, 0x8979FB1BL +}; + +/* declarations of data at the end of this file */ +static const uint32_t S[4][256]; + +static uint32_t F( mbedtls_blowfish_context *ctx, uint32_t x ) +{ + unsigned short a, b, c, d; + uint32_t y; + + d = (unsigned short)(x & 0xFF); + x >>= 8; + c = (unsigned short)(x & 0xFF); + x >>= 8; + b = (unsigned short)(x & 0xFF); + x >>= 8; + a = (unsigned short)(x & 0xFF); + y = ctx->S[0][a] + ctx->S[1][b]; + y = y ^ ctx->S[2][c]; + y = y + ctx->S[3][d]; + + return( y ); +} + +static void blowfish_enc( mbedtls_blowfish_context *ctx, uint32_t *xl, uint32_t *xr ) +{ + uint32_t Xl, Xr, temp; + short i; + + Xl = *xl; + Xr = *xr; + + for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS; ++i ) + { + Xl = Xl ^ ctx->P[i]; + Xr = F( ctx, Xl ) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx->P[MBEDTLS_BLOWFISH_ROUNDS]; + Xl = Xl ^ ctx->P[MBEDTLS_BLOWFISH_ROUNDS + 1]; + + *xl = Xl; + *xr = Xr; +} + +static void blowfish_dec( mbedtls_blowfish_context *ctx, uint32_t *xl, uint32_t *xr ) +{ + uint32_t Xl, Xr, temp; + short i; + + Xl = *xl; + Xr = *xr; + + for( i = MBEDTLS_BLOWFISH_ROUNDS + 1; i > 1; --i ) + { + Xl = Xl ^ ctx->P[i]; + Xr = F( ctx, Xl ) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx->P[1]; + Xl = Xl ^ ctx->P[0]; + + *xl = Xl; + *xr = Xr; +} + +void mbedtls_blowfish_init( mbedtls_blowfish_context *ctx ) +{ + BLOWFISH_VALIDATE( ctx != NULL ); + memset( ctx, 0, sizeof( mbedtls_blowfish_context ) ); +} + +void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_blowfish_context ) ); +} + +/* + * Blowfish key schedule + */ +int mbedtls_blowfish_setkey( mbedtls_blowfish_context *ctx, + const unsigned char *key, + unsigned int keybits ) +{ + unsigned int i, j, k; + uint32_t data, datal, datar; + BLOWFISH_VALIDATE_RET( ctx != NULL ); + BLOWFISH_VALIDATE_RET( key != NULL ); + + if( keybits < MBEDTLS_BLOWFISH_MIN_KEY_BITS || + keybits > MBEDTLS_BLOWFISH_MAX_KEY_BITS || + keybits % 8 != 0 ) + { + return( MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA ); + } + + keybits >>= 3; + + for( i = 0; i < 4; i++ ) + { + for( j = 0; j < 256; j++ ) + ctx->S[i][j] = S[i][j]; + } + + j = 0; + for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS + 2; ++i ) + { + data = 0x00000000; + for( k = 0; k < 4; ++k ) + { + data = ( data << 8 ) | key[j++]; + if( j >= keybits ) + j = 0; + } + ctx->P[i] = P[i] ^ data; + } + + datal = 0x00000000; + datar = 0x00000000; + + for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS + 2; i += 2 ) + { + blowfish_enc( ctx, &datal, &datar ); + ctx->P[i] = datal; + ctx->P[i + 1] = datar; + } + + for( i = 0; i < 4; i++ ) + { + for( j = 0; j < 256; j += 2 ) + { + blowfish_enc( ctx, &datal, &datar ); + ctx->S[i][j] = datal; + ctx->S[i][j + 1] = datar; + } + } + return( 0 ); +} + +/* + * Blowfish-ECB block encryption/decryption + */ +int mbedtls_blowfish_crypt_ecb( mbedtls_blowfish_context *ctx, + int mode, + const unsigned char input[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char output[MBEDTLS_BLOWFISH_BLOCKSIZE] ) +{ + uint32_t X0, X1; + BLOWFISH_VALIDATE_RET( ctx != NULL ); + BLOWFISH_VALIDATE_RET( mode == MBEDTLS_BLOWFISH_ENCRYPT || + mode == MBEDTLS_BLOWFISH_DECRYPT ); + BLOWFISH_VALIDATE_RET( input != NULL ); + BLOWFISH_VALIDATE_RET( output != NULL ); + + GET_UINT32_BE( X0, input, 0 ); + GET_UINT32_BE( X1, input, 4 ); + + if( mode == MBEDTLS_BLOWFISH_DECRYPT ) + { + blowfish_dec( ctx, &X0, &X1 ); + } + else /* MBEDTLS_BLOWFISH_ENCRYPT */ + { + blowfish_enc( ctx, &X0, &X1 ); + } + + PUT_UINT32_BE( X0, output, 0 ); + PUT_UINT32_BE( X1, output, 4 ); + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * Blowfish-CBC buffer encryption/decryption + */ +int mbedtls_blowfish_crypt_cbc( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[MBEDTLS_BLOWFISH_BLOCKSIZE]; + BLOWFISH_VALIDATE_RET( ctx != NULL ); + BLOWFISH_VALIDATE_RET( mode == MBEDTLS_BLOWFISH_ENCRYPT || + mode == MBEDTLS_BLOWFISH_DECRYPT ); + BLOWFISH_VALIDATE_RET( iv != NULL ); + BLOWFISH_VALIDATE_RET( length == 0 || input != NULL ); + BLOWFISH_VALIDATE_RET( length == 0 || output != NULL ); + + if( length % MBEDTLS_BLOWFISH_BLOCKSIZE ) + return( MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_BLOWFISH_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, MBEDTLS_BLOWFISH_BLOCKSIZE ); + mbedtls_blowfish_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < MBEDTLS_BLOWFISH_BLOCKSIZE;i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, MBEDTLS_BLOWFISH_BLOCKSIZE ); + + input += MBEDTLS_BLOWFISH_BLOCKSIZE; + output += MBEDTLS_BLOWFISH_BLOCKSIZE; + length -= MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < MBEDTLS_BLOWFISH_BLOCKSIZE; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_blowfish_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, MBEDTLS_BLOWFISH_BLOCKSIZE ); + + input += MBEDTLS_BLOWFISH_BLOCKSIZE; + output += MBEDTLS_BLOWFISH_BLOCKSIZE; + length -= MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * Blowfish CFB buffer encryption/decryption + */ +int mbedtls_blowfish_crypt_cfb64( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n; + + BLOWFISH_VALIDATE_RET( ctx != NULL ); + BLOWFISH_VALIDATE_RET( mode == MBEDTLS_BLOWFISH_ENCRYPT || + mode == MBEDTLS_BLOWFISH_DECRYPT ); + BLOWFISH_VALIDATE_RET( iv != NULL ); + BLOWFISH_VALIDATE_RET( iv_off != NULL ); + BLOWFISH_VALIDATE_RET( length == 0 || input != NULL ); + BLOWFISH_VALIDATE_RET( length == 0 || output != NULL ); + + n = *iv_off; + if( n >= 8 ) + return( MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA ); + + if( mode == MBEDTLS_BLOWFISH_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + + *iv_off = n; + + return( 0 ); +} +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * Blowfish CTR buffer encryption/decryption + */ +int mbedtls_blowfish_crypt_ctr( mbedtls_blowfish_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char stream_block[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n; + BLOWFISH_VALIDATE_RET( ctx != NULL ); + BLOWFISH_VALIDATE_RET( nonce_counter != NULL ); + BLOWFISH_VALIDATE_RET( stream_block != NULL ); + BLOWFISH_VALIDATE_RET( nc_off != NULL ); + BLOWFISH_VALIDATE_RET( length == 0 || input != NULL ); + BLOWFISH_VALIDATE_RET( length == 0 || output != NULL ); + + n = *nc_off; + if( n >= 8 ) + return( MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA ); + + while( length-- ) + { + if( n == 0 ) { + mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, nonce_counter, + stream_block ); + + for( i = MBEDTLS_BLOWFISH_BLOCKSIZE; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static const uint32_t S[4][256] = { + { 0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L, + 0xB8E1AFEDL, 0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L, + 0x24A19947L, 0xB3916CF7L, 0x0801F2E2L, 0x858EFC16L, + 0x636920D8L, 0x71574E69L, 0xA458FEA3L, 0xF4933D7EL, + 0x0D95748FL, 0x728EB658L, 0x718BCD58L, 0x82154AEEL, + 0x7B54A41DL, 0xC25A59B5L, 0x9C30D539L, 0x2AF26013L, + 0xC5D1B023L, 0x286085F0L, 0xCA417918L, 0xB8DB38EFL, + 0x8E79DCB0L, 0x603A180EL, 0x6C9E0E8BL, 0xB01E8A3EL, + 0xD71577C1L, 0xBD314B27L, 0x78AF2FDAL, 0x55605C60L, + 0xE65525F3L, 0xAA55AB94L, 0x57489862L, 0x63E81440L, + 0x55CA396AL, 0x2AAB10B6L, 0xB4CC5C34L, 0x1141E8CEL, + 0xA15486AFL, 0x7C72E993L, 0xB3EE1411L, 0x636FBC2AL, + 0x2BA9C55DL, 0x741831F6L, 0xCE5C3E16L, 0x9B87931EL, + 0xAFD6BA33L, 0x6C24CF5CL, 0x7A325381L, 0x28958677L, + 0x3B8F4898L, 0x6B4BB9AFL, 0xC4BFE81BL, 0x66282193L, + 0x61D809CCL, 0xFB21A991L, 0x487CAC60L, 0x5DEC8032L, + 0xEF845D5DL, 0xE98575B1L, 0xDC262302L, 0xEB651B88L, + 0x23893E81L, 0xD396ACC5L, 0x0F6D6FF3L, 0x83F44239L, + 0x2E0B4482L, 0xA4842004L, 0x69C8F04AL, 0x9E1F9B5EL, + 0x21C66842L, 0xF6E96C9AL, 0x670C9C61L, 0xABD388F0L, + 0x6A51A0D2L, 0xD8542F68L, 0x960FA728L, 0xAB5133A3L, + 0x6EEF0B6CL, 0x137A3BE4L, 0xBA3BF050L, 0x7EFB2A98L, + 0xA1F1651DL, 0x39AF0176L, 0x66CA593EL, 0x82430E88L, + 0x8CEE8619L, 0x456F9FB4L, 0x7D84A5C3L, 0x3B8B5EBEL, + 0xE06F75D8L, 0x85C12073L, 0x401A449FL, 0x56C16AA6L, + 0x4ED3AA62L, 0x363F7706L, 0x1BFEDF72L, 0x429B023DL, + 0x37D0D724L, 0xD00A1248L, 0xDB0FEAD3L, 0x49F1C09BL, + 0x075372C9L, 0x80991B7BL, 0x25D479D8L, 0xF6E8DEF7L, + 0xE3FE501AL, 0xB6794C3BL, 0x976CE0BDL, 0x04C006BAL, + 0xC1A94FB6L, 0x409F60C4L, 0x5E5C9EC2L, 0x196A2463L, + 0x68FB6FAFL, 0x3E6C53B5L, 0x1339B2EBL, 0x3B52EC6FL, + 0x6DFC511FL, 0x9B30952CL, 0xCC814544L, 0xAF5EBD09L, + 0xBEE3D004L, 0xDE334AFDL, 0x660F2807L, 0x192E4BB3L, + 0xC0CBA857L, 0x45C8740FL, 0xD20B5F39L, 0xB9D3FBDBL, + 0x5579C0BDL, 0x1A60320AL, 0xD6A100C6L, 0x402C7279L, + 0x679F25FEL, 0xFB1FA3CCL, 0x8EA5E9F8L, 0xDB3222F8L, + 0x3C7516DFL, 0xFD616B15L, 0x2F501EC8L, 0xAD0552ABL, + 0x323DB5FAL, 0xFD238760L, 0x53317B48L, 0x3E00DF82L, + 0x9E5C57BBL, 0xCA6F8CA0L, 0x1A87562EL, 0xDF1769DBL, + 0xD542A8F6L, 0x287EFFC3L, 0xAC6732C6L, 0x8C4F5573L, + 0x695B27B0L, 0xBBCA58C8L, 0xE1FFA35DL, 0xB8F011A0L, + 0x10FA3D98L, 0xFD2183B8L, 0x4AFCB56CL, 0x2DD1D35BL, + 0x9A53E479L, 0xB6F84565L, 0xD28E49BCL, 0x4BFB9790L, + 0xE1DDF2DAL, 0xA4CB7E33L, 0x62FB1341L, 0xCEE4C6E8L, + 0xEF20CADAL, 0x36774C01L, 0xD07E9EFEL, 0x2BF11FB4L, + 0x95DBDA4DL, 0xAE909198L, 0xEAAD8E71L, 0x6B93D5A0L, + 0xD08ED1D0L, 0xAFC725E0L, 0x8E3C5B2FL, 0x8E7594B7L, + 0x8FF6E2FBL, 0xF2122B64L, 0x8888B812L, 0x900DF01CL, + 0x4FAD5EA0L, 0x688FC31CL, 0xD1CFF191L, 0xB3A8C1ADL, + 0x2F2F2218L, 0xBE0E1777L, 0xEA752DFEL, 0x8B021FA1L, + 0xE5A0CC0FL, 0xB56F74E8L, 0x18ACF3D6L, 0xCE89E299L, + 0xB4A84FE0L, 0xFD13E0B7L, 0x7CC43B81L, 0xD2ADA8D9L, + 0x165FA266L, 0x80957705L, 0x93CC7314L, 0x211A1477L, + 0xE6AD2065L, 0x77B5FA86L, 0xC75442F5L, 0xFB9D35CFL, + 0xEBCDAF0CL, 0x7B3E89A0L, 0xD6411BD3L, 0xAE1E7E49L, + 0x00250E2DL, 0x2071B35EL, 0x226800BBL, 0x57B8E0AFL, + 0x2464369BL, 0xF009B91EL, 0x5563911DL, 0x59DFA6AAL, + 0x78C14389L, 0xD95A537FL, 0x207D5BA2L, 0x02E5B9C5L, + 0x83260376L, 0x6295CFA9L, 0x11C81968L, 0x4E734A41L, + 0xB3472DCAL, 0x7B14A94AL, 0x1B510052L, 0x9A532915L, + 0xD60F573FL, 0xBC9BC6E4L, 0x2B60A476L, 0x81E67400L, + 0x08BA6FB5L, 0x571BE91FL, 0xF296EC6BL, 0x2A0DD915L, + 0xB6636521L, 0xE7B9F9B6L, 0xFF34052EL, 0xC5855664L, + 0x53B02D5DL, 0xA99F8FA1L, 0x08BA4799L, 0x6E85076AL }, + { 0x4B7A70E9L, 0xB5B32944L, 0xDB75092EL, 0xC4192623L, + 0xAD6EA6B0L, 0x49A7DF7DL, 0x9CEE60B8L, 0x8FEDB266L, + 0xECAA8C71L, 0x699A17FFL, 0x5664526CL, 0xC2B19EE1L, + 0x193602A5L, 0x75094C29L, 0xA0591340L, 0xE4183A3EL, + 0x3F54989AL, 0x5B429D65L, 0x6B8FE4D6L, 0x99F73FD6L, + 0xA1D29C07L, 0xEFE830F5L, 0x4D2D38E6L, 0xF0255DC1L, + 0x4CDD2086L, 0x8470EB26L, 0x6382E9C6L, 0x021ECC5EL, + 0x09686B3FL, 0x3EBAEFC9L, 0x3C971814L, 0x6B6A70A1L, + 0x687F3584L, 0x52A0E286L, 0xB79C5305L, 0xAA500737L, + 0x3E07841CL, 0x7FDEAE5CL, 0x8E7D44ECL, 0x5716F2B8L, + 0xB03ADA37L, 0xF0500C0DL, 0xF01C1F04L, 0x0200B3FFL, + 0xAE0CF51AL, 0x3CB574B2L, 0x25837A58L, 0xDC0921BDL, + 0xD19113F9L, 0x7CA92FF6L, 0x94324773L, 0x22F54701L, + 0x3AE5E581L, 0x37C2DADCL, 0xC8B57634L, 0x9AF3DDA7L, + 0xA9446146L, 0x0FD0030EL, 0xECC8C73EL, 0xA4751E41L, + 0xE238CD99L, 0x3BEA0E2FL, 0x3280BBA1L, 0x183EB331L, + 0x4E548B38L, 0x4F6DB908L, 0x6F420D03L, 0xF60A04BFL, + 0x2CB81290L, 0x24977C79L, 0x5679B072L, 0xBCAF89AFL, + 0xDE9A771FL, 0xD9930810L, 0xB38BAE12L, 0xDCCF3F2EL, + 0x5512721FL, 0x2E6B7124L, 0x501ADDE6L, 0x9F84CD87L, + 0x7A584718L, 0x7408DA17L, 0xBC9F9ABCL, 0xE94B7D8CL, + 0xEC7AEC3AL, 0xDB851DFAL, 0x63094366L, 0xC464C3D2L, + 0xEF1C1847L, 0x3215D908L, 0xDD433B37L, 0x24C2BA16L, + 0x12A14D43L, 0x2A65C451L, 0x50940002L, 0x133AE4DDL, + 0x71DFF89EL, 0x10314E55L, 0x81AC77D6L, 0x5F11199BL, + 0x043556F1L, 0xD7A3C76BL, 0x3C11183BL, 0x5924A509L, + 0xF28FE6EDL, 0x97F1FBFAL, 0x9EBABF2CL, 0x1E153C6EL, + 0x86E34570L, 0xEAE96FB1L, 0x860E5E0AL, 0x5A3E2AB3L, + 0x771FE71CL, 0x4E3D06FAL, 0x2965DCB9L, 0x99E71D0FL, + 0x803E89D6L, 0x5266C825L, 0x2E4CC978L, 0x9C10B36AL, + 0xC6150EBAL, 0x94E2EA78L, 0xA5FC3C53L, 0x1E0A2DF4L, + 0xF2F74EA7L, 0x361D2B3DL, 0x1939260FL, 0x19C27960L, + 0x5223A708L, 0xF71312B6L, 0xEBADFE6EL, 0xEAC31F66L, + 0xE3BC4595L, 0xA67BC883L, 0xB17F37D1L, 0x018CFF28L, + 0xC332DDEFL, 0xBE6C5AA5L, 0x65582185L, 0x68AB9802L, + 0xEECEA50FL, 0xDB2F953BL, 0x2AEF7DADL, 0x5B6E2F84L, + 0x1521B628L, 0x29076170L, 0xECDD4775L, 0x619F1510L, + 0x13CCA830L, 0xEB61BD96L, 0x0334FE1EL, 0xAA0363CFL, + 0xB5735C90L, 0x4C70A239L, 0xD59E9E0BL, 0xCBAADE14L, + 0xEECC86BCL, 0x60622CA7L, 0x9CAB5CABL, 0xB2F3846EL, + 0x648B1EAFL, 0x19BDF0CAL, 0xA02369B9L, 0x655ABB50L, + 0x40685A32L, 0x3C2AB4B3L, 0x319EE9D5L, 0xC021B8F7L, + 0x9B540B19L, 0x875FA099L, 0x95F7997EL, 0x623D7DA8L, + 0xF837889AL, 0x97E32D77L, 0x11ED935FL, 0x16681281L, + 0x0E358829L, 0xC7E61FD6L, 0x96DEDFA1L, 0x7858BA99L, + 0x57F584A5L, 0x1B227263L, 0x9B83C3FFL, 0x1AC24696L, + 0xCDB30AEBL, 0x532E3054L, 0x8FD948E4L, 0x6DBC3128L, + 0x58EBF2EFL, 0x34C6FFEAL, 0xFE28ED61L, 0xEE7C3C73L, + 0x5D4A14D9L, 0xE864B7E3L, 0x42105D14L, 0x203E13E0L, + 0x45EEE2B6L, 0xA3AAABEAL, 0xDB6C4F15L, 0xFACB4FD0L, + 0xC742F442L, 0xEF6ABBB5L, 0x654F3B1DL, 0x41CD2105L, + 0xD81E799EL, 0x86854DC7L, 0xE44B476AL, 0x3D816250L, + 0xCF62A1F2L, 0x5B8D2646L, 0xFC8883A0L, 0xC1C7B6A3L, + 0x7F1524C3L, 0x69CB7492L, 0x47848A0BL, 0x5692B285L, + 0x095BBF00L, 0xAD19489DL, 0x1462B174L, 0x23820E00L, + 0x58428D2AL, 0x0C55F5EAL, 0x1DADF43EL, 0x233F7061L, + 0x3372F092L, 0x8D937E41L, 0xD65FECF1L, 0x6C223BDBL, + 0x7CDE3759L, 0xCBEE7460L, 0x4085F2A7L, 0xCE77326EL, + 0xA6078084L, 0x19F8509EL, 0xE8EFD855L, 0x61D99735L, + 0xA969A7AAL, 0xC50C06C2L, 0x5A04ABFCL, 0x800BCADCL, + 0x9E447A2EL, 0xC3453484L, 0xFDD56705L, 0x0E1E9EC9L, + 0xDB73DBD3L, 0x105588CDL, 0x675FDA79L, 0xE3674340L, + 0xC5C43465L, 0x713E38D8L, 0x3D28F89EL, 0xF16DFF20L, + 0x153E21E7L, 0x8FB03D4AL, 0xE6E39F2BL, 0xDB83ADF7L }, + { 0xE93D5A68L, 0x948140F7L, 0xF64C261CL, 0x94692934L, + 0x411520F7L, 0x7602D4F7L, 0xBCF46B2EL, 0xD4A20068L, + 0xD4082471L, 0x3320F46AL, 0x43B7D4B7L, 0x500061AFL, + 0x1E39F62EL, 0x97244546L, 0x14214F74L, 0xBF8B8840L, + 0x4D95FC1DL, 0x96B591AFL, 0x70F4DDD3L, 0x66A02F45L, + 0xBFBC09ECL, 0x03BD9785L, 0x7FAC6DD0L, 0x31CB8504L, + 0x96EB27B3L, 0x55FD3941L, 0xDA2547E6L, 0xABCA0A9AL, + 0x28507825L, 0x530429F4L, 0x0A2C86DAL, 0xE9B66DFBL, + 0x68DC1462L, 0xD7486900L, 0x680EC0A4L, 0x27A18DEEL, + 0x4F3FFEA2L, 0xE887AD8CL, 0xB58CE006L, 0x7AF4D6B6L, + 0xAACE1E7CL, 0xD3375FECL, 0xCE78A399L, 0x406B2A42L, + 0x20FE9E35L, 0xD9F385B9L, 0xEE39D7ABL, 0x3B124E8BL, + 0x1DC9FAF7L, 0x4B6D1856L, 0x26A36631L, 0xEAE397B2L, + 0x3A6EFA74L, 0xDD5B4332L, 0x6841E7F7L, 0xCA7820FBL, + 0xFB0AF54EL, 0xD8FEB397L, 0x454056ACL, 0xBA489527L, + 0x55533A3AL, 0x20838D87L, 0xFE6BA9B7L, 0xD096954BL, + 0x55A867BCL, 0xA1159A58L, 0xCCA92963L, 0x99E1DB33L, + 0xA62A4A56L, 0x3F3125F9L, 0x5EF47E1CL, 0x9029317CL, + 0xFDF8E802L, 0x04272F70L, 0x80BB155CL, 0x05282CE3L, + 0x95C11548L, 0xE4C66D22L, 0x48C1133FL, 0xC70F86DCL, + 0x07F9C9EEL, 0x41041F0FL, 0x404779A4L, 0x5D886E17L, + 0x325F51EBL, 0xD59BC0D1L, 0xF2BCC18FL, 0x41113564L, + 0x257B7834L, 0x602A9C60L, 0xDFF8E8A3L, 0x1F636C1BL, + 0x0E12B4C2L, 0x02E1329EL, 0xAF664FD1L, 0xCAD18115L, + 0x6B2395E0L, 0x333E92E1L, 0x3B240B62L, 0xEEBEB922L, + 0x85B2A20EL, 0xE6BA0D99L, 0xDE720C8CL, 0x2DA2F728L, + 0xD0127845L, 0x95B794FDL, 0x647D0862L, 0xE7CCF5F0L, + 0x5449A36FL, 0x877D48FAL, 0xC39DFD27L, 0xF33E8D1EL, + 0x0A476341L, 0x992EFF74L, 0x3A6F6EABL, 0xF4F8FD37L, + 0xA812DC60L, 0xA1EBDDF8L, 0x991BE14CL, 0xDB6E6B0DL, + 0xC67B5510L, 0x6D672C37L, 0x2765D43BL, 0xDCD0E804L, + 0xF1290DC7L, 0xCC00FFA3L, 0xB5390F92L, 0x690FED0BL, + 0x667B9FFBL, 0xCEDB7D9CL, 0xA091CF0BL, 0xD9155EA3L, + 0xBB132F88L, 0x515BAD24L, 0x7B9479BFL, 0x763BD6EBL, + 0x37392EB3L, 0xCC115979L, 0x8026E297L, 0xF42E312DL, + 0x6842ADA7L, 0xC66A2B3BL, 0x12754CCCL, 0x782EF11CL, + 0x6A124237L, 0xB79251E7L, 0x06A1BBE6L, 0x4BFB6350L, + 0x1A6B1018L, 0x11CAEDFAL, 0x3D25BDD8L, 0xE2E1C3C9L, + 0x44421659L, 0x0A121386L, 0xD90CEC6EL, 0xD5ABEA2AL, + 0x64AF674EL, 0xDA86A85FL, 0xBEBFE988L, 0x64E4C3FEL, + 0x9DBC8057L, 0xF0F7C086L, 0x60787BF8L, 0x6003604DL, + 0xD1FD8346L, 0xF6381FB0L, 0x7745AE04L, 0xD736FCCCL, + 0x83426B33L, 0xF01EAB71L, 0xB0804187L, 0x3C005E5FL, + 0x77A057BEL, 0xBDE8AE24L, 0x55464299L, 0xBF582E61L, + 0x4E58F48FL, 0xF2DDFDA2L, 0xF474EF38L, 0x8789BDC2L, + 0x5366F9C3L, 0xC8B38E74L, 0xB475F255L, 0x46FCD9B9L, + 0x7AEB2661L, 0x8B1DDF84L, 0x846A0E79L, 0x915F95E2L, + 0x466E598EL, 0x20B45770L, 0x8CD55591L, 0xC902DE4CL, + 0xB90BACE1L, 0xBB8205D0L, 0x11A86248L, 0x7574A99EL, + 0xB77F19B6L, 0xE0A9DC09L, 0x662D09A1L, 0xC4324633L, + 0xE85A1F02L, 0x09F0BE8CL, 0x4A99A025L, 0x1D6EFE10L, + 0x1AB93D1DL, 0x0BA5A4DFL, 0xA186F20FL, 0x2868F169L, + 0xDCB7DA83L, 0x573906FEL, 0xA1E2CE9BL, 0x4FCD7F52L, + 0x50115E01L, 0xA70683FAL, 0xA002B5C4L, 0x0DE6D027L, + 0x9AF88C27L, 0x773F8641L, 0xC3604C06L, 0x61A806B5L, + 0xF0177A28L, 0xC0F586E0L, 0x006058AAL, 0x30DC7D62L, + 0x11E69ED7L, 0x2338EA63L, 0x53C2DD94L, 0xC2C21634L, + 0xBBCBEE56L, 0x90BCB6DEL, 0xEBFC7DA1L, 0xCE591D76L, + 0x6F05E409L, 0x4B7C0188L, 0x39720A3DL, 0x7C927C24L, + 0x86E3725FL, 0x724D9DB9L, 0x1AC15BB4L, 0xD39EB8FCL, + 0xED545578L, 0x08FCA5B5L, 0xD83D7CD3L, 0x4DAD0FC4L, + 0x1E50EF5EL, 0xB161E6F8L, 0xA28514D9L, 0x6C51133CL, + 0x6FD5C7E7L, 0x56E14EC4L, 0x362ABFCEL, 0xDDC6C837L, + 0xD79A3234L, 0x92638212L, 0x670EFA8EL, 0x406000E0L }, + { 0x3A39CE37L, 0xD3FAF5CFL, 0xABC27737L, 0x5AC52D1BL, + 0x5CB0679EL, 0x4FA33742L, 0xD3822740L, 0x99BC9BBEL, + 0xD5118E9DL, 0xBF0F7315L, 0xD62D1C7EL, 0xC700C47BL, + 0xB78C1B6BL, 0x21A19045L, 0xB26EB1BEL, 0x6A366EB4L, + 0x5748AB2FL, 0xBC946E79L, 0xC6A376D2L, 0x6549C2C8L, + 0x530FF8EEL, 0x468DDE7DL, 0xD5730A1DL, 0x4CD04DC6L, + 0x2939BBDBL, 0xA9BA4650L, 0xAC9526E8L, 0xBE5EE304L, + 0xA1FAD5F0L, 0x6A2D519AL, 0x63EF8CE2L, 0x9A86EE22L, + 0xC089C2B8L, 0x43242EF6L, 0xA51E03AAL, 0x9CF2D0A4L, + 0x83C061BAL, 0x9BE96A4DL, 0x8FE51550L, 0xBA645BD6L, + 0x2826A2F9L, 0xA73A3AE1L, 0x4BA99586L, 0xEF5562E9L, + 0xC72FEFD3L, 0xF752F7DAL, 0x3F046F69L, 0x77FA0A59L, + 0x80E4A915L, 0x87B08601L, 0x9B09E6ADL, 0x3B3EE593L, + 0xE990FD5AL, 0x9E34D797L, 0x2CF0B7D9L, 0x022B8B51L, + 0x96D5AC3AL, 0x017DA67DL, 0xD1CF3ED6L, 0x7C7D2D28L, + 0x1F9F25CFL, 0xADF2B89BL, 0x5AD6B472L, 0x5A88F54CL, + 0xE029AC71L, 0xE019A5E6L, 0x47B0ACFDL, 0xED93FA9BL, + 0xE8D3C48DL, 0x283B57CCL, 0xF8D56629L, 0x79132E28L, + 0x785F0191L, 0xED756055L, 0xF7960E44L, 0xE3D35E8CL, + 0x15056DD4L, 0x88F46DBAL, 0x03A16125L, 0x0564F0BDL, + 0xC3EB9E15L, 0x3C9057A2L, 0x97271AECL, 0xA93A072AL, + 0x1B3F6D9BL, 0x1E6321F5L, 0xF59C66FBL, 0x26DCF319L, + 0x7533D928L, 0xB155FDF5L, 0x03563482L, 0x8ABA3CBBL, + 0x28517711L, 0xC20AD9F8L, 0xABCC5167L, 0xCCAD925FL, + 0x4DE81751L, 0x3830DC8EL, 0x379D5862L, 0x9320F991L, + 0xEA7A90C2L, 0xFB3E7BCEL, 0x5121CE64L, 0x774FBE32L, + 0xA8B6E37EL, 0xC3293D46L, 0x48DE5369L, 0x6413E680L, + 0xA2AE0810L, 0xDD6DB224L, 0x69852DFDL, 0x09072166L, + 0xB39A460AL, 0x6445C0DDL, 0x586CDECFL, 0x1C20C8AEL, + 0x5BBEF7DDL, 0x1B588D40L, 0xCCD2017FL, 0x6BB4E3BBL, + 0xDDA26A7EL, 0x3A59FF45L, 0x3E350A44L, 0xBCB4CDD5L, + 0x72EACEA8L, 0xFA6484BBL, 0x8D6612AEL, 0xBF3C6F47L, + 0xD29BE463L, 0x542F5D9EL, 0xAEC2771BL, 0xF64E6370L, + 0x740E0D8DL, 0xE75B1357L, 0xF8721671L, 0xAF537D5DL, + 0x4040CB08L, 0x4EB4E2CCL, 0x34D2466AL, 0x0115AF84L, + 0xE1B00428L, 0x95983A1DL, 0x06B89FB4L, 0xCE6EA048L, + 0x6F3F3B82L, 0x3520AB82L, 0x011A1D4BL, 0x277227F8L, + 0x611560B1L, 0xE7933FDCL, 0xBB3A792BL, 0x344525BDL, + 0xA08839E1L, 0x51CE794BL, 0x2F32C9B7L, 0xA01FBAC9L, + 0xE01CC87EL, 0xBCC7D1F6L, 0xCF0111C3L, 0xA1E8AAC7L, + 0x1A908749L, 0xD44FBD9AL, 0xD0DADECBL, 0xD50ADA38L, + 0x0339C32AL, 0xC6913667L, 0x8DF9317CL, 0xE0B12B4FL, + 0xF79E59B7L, 0x43F5BB3AL, 0xF2D519FFL, 0x27D9459CL, + 0xBF97222CL, 0x15E6FC2AL, 0x0F91FC71L, 0x9B941525L, + 0xFAE59361L, 0xCEB69CEBL, 0xC2A86459L, 0x12BAA8D1L, + 0xB6C1075EL, 0xE3056A0CL, 0x10D25065L, 0xCB03A442L, + 0xE0EC6E0EL, 0x1698DB3BL, 0x4C98A0BEL, 0x3278E964L, + 0x9F1F9532L, 0xE0D392DFL, 0xD3A0342BL, 0x8971F21EL, + 0x1B0A7441L, 0x4BA3348CL, 0xC5BE7120L, 0xC37632D8L, + 0xDF359F8DL, 0x9B992F2EL, 0xE60B6F47L, 0x0FE3F11DL, + 0xE54CDA54L, 0x1EDAD891L, 0xCE6279CFL, 0xCD3E7E6FL, + 0x1618B166L, 0xFD2C1D05L, 0x848FD2C5L, 0xF6FB2299L, + 0xF523F357L, 0xA6327623L, 0x93A83531L, 0x56CCCD02L, + 0xACF08162L, 0x5A75EBB5L, 0x6E163697L, 0x88D273CCL, + 0xDE966292L, 0x81B949D0L, 0x4C50901BL, 0x71C65614L, + 0xE6C6C7BDL, 0x327A140AL, 0x45E1D006L, 0xC3F27B9AL, + 0xC9AA53FDL, 0x62A80F00L, 0xBB25BFE2L, 0x35BDD2F6L, + 0x71126905L, 0xB2040222L, 0xB6CBCF7CL, 0xCD769C2BL, + 0x53113EC0L, 0x1640E3D3L, 0x38ABBD60L, 0x2547ADF0L, + 0xBA38209CL, 0xF746CE76L, 0x77AFA1C5L, 0x20756060L, + 0x85CBFE4EL, 0x8AE88DD8L, 0x7AAAF9B0L, 0x4CF9AA7EL, + 0x1948C25CL, 0x02FB8A8CL, 0x01C36AE4L, 0xD6EBE1F9L, + 0x90D4F869L, 0xA65CDEA0L, 0x3F09252DL, 0xC208E69FL, + 0xB74E6132L, 0xCE77E25BL, 0x578FDFE3L, 0x3AC372E6L } +}; + +#endif /* !MBEDTLS_BLOWFISH_ALT */ +#endif /* MBEDTLS_BLOWFISH_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/camellia.c b/FreeRTOS-Labs/Source/mbedtls/library/camellia.c new file mode 100644 index 000000000..8b6aa572d --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/camellia.c @@ -0,0 +1,1114 @@ +/* + * Camellia implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The Camellia block cipher was designed by NTT and Mitsubishi Electric + * Corporation. + * + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/01espec.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CAMELLIA_C) + +#include "mbedtls/camellia.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_CAMELLIA_ALT) + +/* Parameter validation macros */ +#define CAMELLIA_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA ) +#define CAMELLIA_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +static const unsigned char SIGMA_CHARS[6][8] = +{ + { 0xa0, 0x9e, 0x66, 0x7f, 0x3b, 0xcc, 0x90, 0x8b }, + { 0xb6, 0x7a, 0xe8, 0x58, 0x4c, 0xaa, 0x73, 0xb2 }, + { 0xc6, 0xef, 0x37, 0x2f, 0xe9, 0x4f, 0x82, 0xbe }, + { 0x54, 0xff, 0x53, 0xa5, 0xf1, 0xd3, 0x6f, 0x1c }, + { 0x10, 0xe5, 0x27, 0xfa, 0xde, 0x68, 0x2d, 0x1d }, + { 0xb0, 0x56, 0x88, 0xc2, 0xb3, 0xe6, 0xc1, 0xfd } +}; + +#if defined(MBEDTLS_CAMELLIA_SMALL_MEMORY) + +static const unsigned char FSb[256] = +{ + 112,130, 44,236,179, 39,192,229,228,133, 87, 53,234, 12,174, 65, + 35,239,107,147, 69, 25,165, 33,237, 14, 79, 78, 29,101,146,189, + 134,184,175,143,124,235, 31,206, 62, 48,220, 95, 94,197, 11, 26, + 166,225, 57,202,213, 71, 93, 61,217, 1, 90,214, 81, 86,108, 77, + 139, 13,154,102,251,204,176, 45,116, 18, 43, 32,240,177,132,153, + 223, 76,203,194, 52,126,118, 5,109,183,169, 49,209, 23, 4,215, + 20, 88, 58, 97,222, 27, 17, 28, 50, 15,156, 22, 83, 24,242, 34, + 254, 68,207,178,195,181,122,145, 36, 8,232,168, 96,252,105, 80, + 170,208,160,125,161,137, 98,151, 84, 91, 30,149,224,255,100,210, + 16,196, 0, 72,163,247,117,219,138, 3,230,218, 9, 63,221,148, + 135, 92,131, 2,205, 74,144, 51,115,103,246,243,157,127,191,226, + 82,155,216, 38,200, 55,198, 59,129,150,111, 75, 19,190, 99, 46, + 233,121,167,140,159,110,188,142, 41,245,249,182, 47,253,180, 89, + 120,152, 6,106,231, 70,113,186,212, 37,171, 66,136,162,141,250, + 114, 7,185, 85,248,238,172, 10, 54, 73, 42,104, 60, 56,241,164, + 64, 40,211,123,187,201, 67,193, 21,227,173,244,119,199,128,158 +}; + +#define SBOX1(n) FSb[(n)] +#define SBOX2(n) (unsigned char)((FSb[(n)] >> 7 ^ FSb[(n)] << 1) & 0xff) +#define SBOX3(n) (unsigned char)((FSb[(n)] >> 1 ^ FSb[(n)] << 7) & 0xff) +#define SBOX4(n) FSb[((n) << 1 ^ (n) >> 7) &0xff] + +#else /* MBEDTLS_CAMELLIA_SMALL_MEMORY */ + +static const unsigned char FSb[256] = +{ + 112, 130, 44, 236, 179, 39, 192, 229, 228, 133, 87, 53, 234, 12, 174, 65, + 35, 239, 107, 147, 69, 25, 165, 33, 237, 14, 79, 78, 29, 101, 146, 189, + 134, 184, 175, 143, 124, 235, 31, 206, 62, 48, 220, 95, 94, 197, 11, 26, + 166, 225, 57, 202, 213, 71, 93, 61, 217, 1, 90, 214, 81, 86, 108, 77, + 139, 13, 154, 102, 251, 204, 176, 45, 116, 18, 43, 32, 240, 177, 132, 153, + 223, 76, 203, 194, 52, 126, 118, 5, 109, 183, 169, 49, 209, 23, 4, 215, + 20, 88, 58, 97, 222, 27, 17, 28, 50, 15, 156, 22, 83, 24, 242, 34, + 254, 68, 207, 178, 195, 181, 122, 145, 36, 8, 232, 168, 96, 252, 105, 80, + 170, 208, 160, 125, 161, 137, 98, 151, 84, 91, 30, 149, 224, 255, 100, 210, + 16, 196, 0, 72, 163, 247, 117, 219, 138, 3, 230, 218, 9, 63, 221, 148, + 135, 92, 131, 2, 205, 74, 144, 51, 115, 103, 246, 243, 157, 127, 191, 226, + 82, 155, 216, 38, 200, 55, 198, 59, 129, 150, 111, 75, 19, 190, 99, 46, + 233, 121, 167, 140, 159, 110, 188, 142, 41, 245, 249, 182, 47, 253, 180, 89, + 120, 152, 6, 106, 231, 70, 113, 186, 212, 37, 171, 66, 136, 162, 141, 250, + 114, 7, 185, 85, 248, 238, 172, 10, 54, 73, 42, 104, 60, 56, 241, 164, + 64, 40, 211, 123, 187, 201, 67, 193, 21, 227, 173, 244, 119, 199, 128, 158 +}; + +static const unsigned char FSb2[256] = +{ + 224, 5, 88, 217, 103, 78, 129, 203, 201, 11, 174, 106, 213, 24, 93, 130, + 70, 223, 214, 39, 138, 50, 75, 66, 219, 28, 158, 156, 58, 202, 37, 123, + 13, 113, 95, 31, 248, 215, 62, 157, 124, 96, 185, 190, 188, 139, 22, 52, + 77, 195, 114, 149, 171, 142, 186, 122, 179, 2, 180, 173, 162, 172, 216, 154, + 23, 26, 53, 204, 247, 153, 97, 90, 232, 36, 86, 64, 225, 99, 9, 51, + 191, 152, 151, 133, 104, 252, 236, 10, 218, 111, 83, 98, 163, 46, 8, 175, + 40, 176, 116, 194, 189, 54, 34, 56, 100, 30, 57, 44, 166, 48, 229, 68, + 253, 136, 159, 101, 135, 107, 244, 35, 72, 16, 209, 81, 192, 249, 210, 160, + 85, 161, 65, 250, 67, 19, 196, 47, 168, 182, 60, 43, 193, 255, 200, 165, + 32, 137, 0, 144, 71, 239, 234, 183, 21, 6, 205, 181, 18, 126, 187, 41, + 15, 184, 7, 4, 155, 148, 33, 102, 230, 206, 237, 231, 59, 254, 127, 197, + 164, 55, 177, 76, 145, 110, 141, 118, 3, 45, 222, 150, 38, 125, 198, 92, + 211, 242, 79, 25, 63, 220, 121, 29, 82, 235, 243, 109, 94, 251, 105, 178, + 240, 49, 12, 212, 207, 140, 226, 117, 169, 74, 87, 132, 17, 69, 27, 245, + 228, 14, 115, 170, 241, 221, 89, 20, 108, 146, 84, 208, 120, 112, 227, 73, + 128, 80, 167, 246, 119, 147, 134, 131, 42, 199, 91, 233, 238, 143, 1, 61 +}; + +static const unsigned char FSb3[256] = +{ + 56, 65, 22, 118, 217, 147, 96, 242, 114, 194, 171, 154, 117, 6, 87, 160, + 145, 247, 181, 201, 162, 140, 210, 144, 246, 7, 167, 39, 142, 178, 73, 222, + 67, 92, 215, 199, 62, 245, 143, 103, 31, 24, 110, 175, 47, 226, 133, 13, + 83, 240, 156, 101, 234, 163, 174, 158, 236, 128, 45, 107, 168, 43, 54, 166, + 197, 134, 77, 51, 253, 102, 88, 150, 58, 9, 149, 16, 120, 216, 66, 204, + 239, 38, 229, 97, 26, 63, 59, 130, 182, 219, 212, 152, 232, 139, 2, 235, + 10, 44, 29, 176, 111, 141, 136, 14, 25, 135, 78, 11, 169, 12, 121, 17, + 127, 34, 231, 89, 225, 218, 61, 200, 18, 4, 116, 84, 48, 126, 180, 40, + 85, 104, 80, 190, 208, 196, 49, 203, 42, 173, 15, 202, 112, 255, 50, 105, + 8, 98, 0, 36, 209, 251, 186, 237, 69, 129, 115, 109, 132, 159, 238, 74, + 195, 46, 193, 1, 230, 37, 72, 153, 185, 179, 123, 249, 206, 191, 223, 113, + 41, 205, 108, 19, 100, 155, 99, 157, 192, 75, 183, 165, 137, 95, 177, 23, + 244, 188, 211, 70, 207, 55, 94, 71, 148, 250, 252, 91, 151, 254, 90, 172, + 60, 76, 3, 53, 243, 35, 184, 93, 106, 146, 213, 33, 68, 81, 198, 125, + 57, 131, 220, 170, 124, 119, 86, 5, 27, 164, 21, 52, 30, 28, 248, 82, + 32, 20, 233, 189, 221, 228, 161, 224, 138, 241, 214, 122, 187, 227, 64, 79 +}; + +static const unsigned char FSb4[256] = +{ + 112, 44, 179, 192, 228, 87, 234, 174, 35, 107, 69, 165, 237, 79, 29, 146, + 134, 175, 124, 31, 62, 220, 94, 11, 166, 57, 213, 93, 217, 90, 81, 108, + 139, 154, 251, 176, 116, 43, 240, 132, 223, 203, 52, 118, 109, 169, 209, 4, + 20, 58, 222, 17, 50, 156, 83, 242, 254, 207, 195, 122, 36, 232, 96, 105, + 170, 160, 161, 98, 84, 30, 224, 100, 16, 0, 163, 117, 138, 230, 9, 221, + 135, 131, 205, 144, 115, 246, 157, 191, 82, 216, 200, 198, 129, 111, 19, 99, + 233, 167, 159, 188, 41, 249, 47, 180, 120, 6, 231, 113, 212, 171, 136, 141, + 114, 185, 248, 172, 54, 42, 60, 241, 64, 211, 187, 67, 21, 173, 119, 128, + 130, 236, 39, 229, 133, 53, 12, 65, 239, 147, 25, 33, 14, 78, 101, 189, + 184, 143, 235, 206, 48, 95, 197, 26, 225, 202, 71, 61, 1, 214, 86, 77, + 13, 102, 204, 45, 18, 32, 177, 153, 76, 194, 126, 5, 183, 49, 23, 215, + 88, 97, 27, 28, 15, 22, 24, 34, 68, 178, 181, 145, 8, 168, 252, 80, + 208, 125, 137, 151, 91, 149, 255, 210, 196, 72, 247, 219, 3, 218, 63, 148, + 92, 2, 74, 51, 103, 243, 127, 226, 155, 38, 55, 59, 150, 75, 190, 46, + 121, 140, 110, 142, 245, 182, 253, 89, 152, 106, 70, 186, 37, 66, 162, 250, + 7, 85, 238, 10, 73, 104, 56, 164, 40, 123, 201, 193, 227, 244, 199, 158 +}; + +#define SBOX1(n) FSb[(n)] +#define SBOX2(n) FSb2[(n)] +#define SBOX3(n) FSb3[(n)] +#define SBOX4(n) FSb4[(n)] + +#endif /* MBEDTLS_CAMELLIA_SMALL_MEMORY */ + +static const unsigned char shifts[2][4][4] = +{ + { + { 1, 1, 1, 1 }, /* KL */ + { 0, 0, 0, 0 }, /* KR */ + { 1, 1, 1, 1 }, /* KA */ + { 0, 0, 0, 0 } /* KB */ + }, + { + { 1, 0, 1, 1 }, /* KL */ + { 1, 1, 0, 1 }, /* KR */ + { 1, 1, 1, 0 }, /* KA */ + { 1, 1, 0, 1 } /* KB */ + } +}; + +static const signed char indexes[2][4][20] = +{ + { + { 0, 1, 2, 3, 8, 9, 10, 11, 38, 39, + 36, 37, 23, 20, 21, 22, 27, -1, -1, 26 }, /* KL -> RK */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /* KR -> RK */ + { 4, 5, 6, 7, 12, 13, 14, 15, 16, 17, + 18, 19, -1, 24, 25, -1, 31, 28, 29, 30 }, /* KA -> RK */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } /* KB -> RK */ + }, + { + { 0, 1, 2, 3, 61, 62, 63, 60, -1, -1, + -1, -1, 27, 24, 25, 26, 35, 32, 33, 34 }, /* KL -> RK */ + { -1, -1, -1, -1, 8, 9, 10, 11, 16, 17, + 18, 19, -1, -1, -1, -1, 39, 36, 37, 38 }, /* KR -> RK */ + { -1, -1, -1, -1, 12, 13, 14, 15, 58, 59, + 56, 57, 31, 28, 29, 30, -1, -1, -1, -1 }, /* KA -> RK */ + { 4, 5, 6, 7, 65, 66, 67, 64, 20, 21, + 22, 23, -1, -1, -1, -1, 43, 40, 41, 42 } /* KB -> RK */ + } +}; + +static const signed char transposes[2][20] = +{ + { + 21, 22, 23, 20, + -1, -1, -1, -1, + 18, 19, 16, 17, + 11, 8, 9, 10, + 15, 12, 13, 14 + }, + { + 25, 26, 27, 24, + 29, 30, 31, 28, + 18, 19, 16, 17, + -1, -1, -1, -1, + -1, -1, -1, -1 + } +}; + +/* Shift macro for 128 bit strings with rotation smaller than 32 bits (!) */ +#define ROTL(DEST, SRC, SHIFT) \ +{ \ + (DEST)[0] = (SRC)[0] << (SHIFT) ^ (SRC)[1] >> (32 - (SHIFT)); \ + (DEST)[1] = (SRC)[1] << (SHIFT) ^ (SRC)[2] >> (32 - (SHIFT)); \ + (DEST)[2] = (SRC)[2] << (SHIFT) ^ (SRC)[3] >> (32 - (SHIFT)); \ + (DEST)[3] = (SRC)[3] << (SHIFT) ^ (SRC)[0] >> (32 - (SHIFT)); \ +} + +#define FL(XL, XR, KL, KR) \ +{ \ + (XR) = ((((XL) & (KL)) << 1) | (((XL) & (KL)) >> 31)) ^ (XR); \ + (XL) = ((XR) | (KR)) ^ (XL); \ +} + +#define FLInv(YL, YR, KL, KR) \ +{ \ + (YL) = ((YR) | (KR)) ^ (YL); \ + (YR) = ((((YL) & (KL)) << 1) | (((YL) & (KL)) >> 31)) ^ (YR); \ +} + +#define SHIFT_AND_PLACE(INDEX, OFFSET) \ +{ \ + TK[0] = KC[(OFFSET) * 4 + 0]; \ + TK[1] = KC[(OFFSET) * 4 + 1]; \ + TK[2] = KC[(OFFSET) * 4 + 2]; \ + TK[3] = KC[(OFFSET) * 4 + 3]; \ + \ + for( i = 1; i <= 4; i++ ) \ + if( shifts[(INDEX)][(OFFSET)][i -1] ) \ + ROTL(TK + i * 4, TK, ( 15 * i ) % 32); \ + \ + for( i = 0; i < 20; i++ ) \ + if( indexes[(INDEX)][(OFFSET)][i] != -1 ) { \ + RK[indexes[(INDEX)][(OFFSET)][i]] = TK[ i ]; \ + } \ +} + +static void camellia_feistel( const uint32_t x[2], const uint32_t k[2], + uint32_t z[2]) +{ + uint32_t I0, I1; + I0 = x[0] ^ k[0]; + I1 = x[1] ^ k[1]; + + I0 = ((uint32_t) SBOX1((I0 >> 24) & 0xFF) << 24) | + ((uint32_t) SBOX2((I0 >> 16) & 0xFF) << 16) | + ((uint32_t) SBOX3((I0 >> 8) & 0xFF) << 8) | + ((uint32_t) SBOX4((I0 ) & 0xFF) ); + I1 = ((uint32_t) SBOX2((I1 >> 24) & 0xFF) << 24) | + ((uint32_t) SBOX3((I1 >> 16) & 0xFF) << 16) | + ((uint32_t) SBOX4((I1 >> 8) & 0xFF) << 8) | + ((uint32_t) SBOX1((I1 ) & 0xFF) ); + + I0 ^= (I1 << 8) | (I1 >> 24); + I1 ^= (I0 << 16) | (I0 >> 16); + I0 ^= (I1 >> 8) | (I1 << 24); + I1 ^= (I0 >> 8) | (I0 << 24); + + z[0] ^= I1; + z[1] ^= I0; +} + +void mbedtls_camellia_init( mbedtls_camellia_context *ctx ) +{ + CAMELLIA_VALIDATE( ctx != NULL ); + memset( ctx, 0, sizeof( mbedtls_camellia_context ) ); +} + +void mbedtls_camellia_free( mbedtls_camellia_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_camellia_context ) ); +} + +/* + * Camellia key schedule (encryption) + */ +int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, + const unsigned char *key, + unsigned int keybits ) +{ + int idx; + size_t i; + uint32_t *RK; + unsigned char t[64]; + uint32_t SIGMA[6][2]; + uint32_t KC[16]; + uint32_t TK[20]; + + CAMELLIA_VALIDATE_RET( ctx != NULL ); + CAMELLIA_VALIDATE_RET( key != NULL ); + + RK = ctx->rk; + + memset( t, 0, 64 ); + memset( RK, 0, sizeof(ctx->rk) ); + + switch( keybits ) + { + case 128: ctx->nr = 3; idx = 0; break; + case 192: + case 256: ctx->nr = 4; idx = 1; break; + default : return( MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA ); + } + + for( i = 0; i < keybits / 8; ++i ) + t[i] = key[i]; + + if( keybits == 192 ) { + for( i = 0; i < 8; i++ ) + t[24 + i] = ~t[16 + i]; + } + + /* + * Prepare SIGMA values + */ + for( i = 0; i < 6; i++ ) { + GET_UINT32_BE( SIGMA[i][0], SIGMA_CHARS[i], 0 ); + GET_UINT32_BE( SIGMA[i][1], SIGMA_CHARS[i], 4 ); + } + + /* + * Key storage in KC + * Order: KL, KR, KA, KB + */ + memset( KC, 0, sizeof(KC) ); + + /* Store KL, KR */ + for( i = 0; i < 8; i++ ) + GET_UINT32_BE( KC[i], t, i * 4 ); + + /* Generate KA */ + for( i = 0; i < 4; ++i ) + KC[8 + i] = KC[i] ^ KC[4 + i]; + + camellia_feistel( KC + 8, SIGMA[0], KC + 10 ); + camellia_feistel( KC + 10, SIGMA[1], KC + 8 ); + + for( i = 0; i < 4; ++i ) + KC[8 + i] ^= KC[i]; + + camellia_feistel( KC + 8, SIGMA[2], KC + 10 ); + camellia_feistel( KC + 10, SIGMA[3], KC + 8 ); + + if( keybits > 128 ) { + /* Generate KB */ + for( i = 0; i < 4; ++i ) + KC[12 + i] = KC[4 + i] ^ KC[8 + i]; + + camellia_feistel( KC + 12, SIGMA[4], KC + 14 ); + camellia_feistel( KC + 14, SIGMA[5], KC + 12 ); + } + + /* + * Generating subkeys + */ + + /* Manipulating KL */ + SHIFT_AND_PLACE( idx, 0 ); + + /* Manipulating KR */ + if( keybits > 128 ) { + SHIFT_AND_PLACE( idx, 1 ); + } + + /* Manipulating KA */ + SHIFT_AND_PLACE( idx, 2 ); + + /* Manipulating KB */ + if( keybits > 128 ) { + SHIFT_AND_PLACE( idx, 3 ); + } + + /* Do transpositions */ + for( i = 0; i < 20; i++ ) { + if( transposes[idx][i] != -1 ) { + RK[32 + 12 * idx + i] = RK[transposes[idx][i]]; + } + } + + return( 0 ); +} + +/* + * Camellia key schedule (decryption) + */ +int mbedtls_camellia_setkey_dec( mbedtls_camellia_context *ctx, + const unsigned char *key, + unsigned int keybits ) +{ + int idx, ret; + size_t i; + mbedtls_camellia_context cty; + uint32_t *RK; + uint32_t *SK; + CAMELLIA_VALIDATE_RET( ctx != NULL ); + CAMELLIA_VALIDATE_RET( key != NULL ); + + mbedtls_camellia_init( &cty ); + + /* Also checks keybits */ + if( ( ret = mbedtls_camellia_setkey_enc( &cty, key, keybits ) ) != 0 ) + goto exit; + + ctx->nr = cty.nr; + idx = ( ctx->nr == 4 ); + + RK = ctx->rk; + SK = cty.rk + 24 * 2 + 8 * idx * 2; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + for( i = 22 + 8 * idx, SK -= 6; i > 0; i--, SK -= 4 ) + { + *RK++ = *SK++; + *RK++ = *SK++; + } + + SK -= 2; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + +exit: + mbedtls_camellia_free( &cty ); + + return( ret ); +} + +/* + * Camellia-ECB block encryption/decryption + */ +int mbedtls_camellia_crypt_ecb( mbedtls_camellia_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + int NR; + uint32_t *RK, X[4]; + CAMELLIA_VALIDATE_RET( ctx != NULL ); + CAMELLIA_VALIDATE_RET( mode == MBEDTLS_CAMELLIA_ENCRYPT || + mode == MBEDTLS_CAMELLIA_DECRYPT ); + CAMELLIA_VALIDATE_RET( input != NULL ); + CAMELLIA_VALIDATE_RET( output != NULL ); + + ( (void) mode ); + + NR = ctx->nr; + RK = ctx->rk; + + GET_UINT32_BE( X[0], input, 0 ); + GET_UINT32_BE( X[1], input, 4 ); + GET_UINT32_BE( X[2], input, 8 ); + GET_UINT32_BE( X[3], input, 12 ); + + X[0] ^= *RK++; + X[1] ^= *RK++; + X[2] ^= *RK++; + X[3] ^= *RK++; + + while( NR ) { + --NR; + camellia_feistel( X, RK, X + 2 ); + RK += 2; + camellia_feistel( X + 2, RK, X ); + RK += 2; + camellia_feistel( X, RK, X + 2 ); + RK += 2; + camellia_feistel( X + 2, RK, X ); + RK += 2; + camellia_feistel( X, RK, X + 2 ); + RK += 2; + camellia_feistel( X + 2, RK, X ); + RK += 2; + + if( NR ) { + FL(X[0], X[1], RK[0], RK[1]); + RK += 2; + FLInv(X[2], X[3], RK[0], RK[1]); + RK += 2; + } + } + + X[2] ^= *RK++; + X[3] ^= *RK++; + X[0] ^= *RK++; + X[1] ^= *RK++; + + PUT_UINT32_BE( X[2], output, 0 ); + PUT_UINT32_BE( X[3], output, 4 ); + PUT_UINT32_BE( X[0], output, 8 ); + PUT_UINT32_BE( X[1], output, 12 ); + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * Camellia-CBC buffer encryption/decryption + */ +int mbedtls_camellia_crypt_cbc( mbedtls_camellia_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[16]; + CAMELLIA_VALIDATE_RET( ctx != NULL ); + CAMELLIA_VALIDATE_RET( mode == MBEDTLS_CAMELLIA_ENCRYPT || + mode == MBEDTLS_CAMELLIA_DECRYPT ); + CAMELLIA_VALIDATE_RET( iv != NULL ); + CAMELLIA_VALIDATE_RET( length == 0 || input != NULL ); + CAMELLIA_VALIDATE_RET( length == 0 || output != NULL ); + + if( length % 16 ) + return( MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_CAMELLIA_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 16 ); + mbedtls_camellia_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_camellia_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * Camellia-CFB128 buffer encryption/decryption + */ +int mbedtls_camellia_crypt_cfb128( mbedtls_camellia_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n; + CAMELLIA_VALIDATE_RET( ctx != NULL ); + CAMELLIA_VALIDATE_RET( mode == MBEDTLS_CAMELLIA_ENCRYPT || + mode == MBEDTLS_CAMELLIA_DECRYPT ); + CAMELLIA_VALIDATE_RET( iv != NULL ); + CAMELLIA_VALIDATE_RET( iv_off != NULL ); + CAMELLIA_VALIDATE_RET( length == 0 || input != NULL ); + CAMELLIA_VALIDATE_RET( length == 0 || output != NULL ); + + n = *iv_off; + if( n >= 16 ) + return( MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA ); + + if( mode == MBEDTLS_CAMELLIA_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * Camellia-CTR buffer encryption/decryption + */ +int mbedtls_camellia_crypt_ctr( mbedtls_camellia_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n; + CAMELLIA_VALIDATE_RET( ctx != NULL ); + CAMELLIA_VALIDATE_RET( nonce_counter != NULL ); + CAMELLIA_VALIDATE_RET( stream_block != NULL ); + CAMELLIA_VALIDATE_RET( nc_off != NULL ); + CAMELLIA_VALIDATE_RET( length == 0 || input != NULL ); + CAMELLIA_VALIDATE_RET( length == 0 || output != NULL ); + + n = *nc_off; + if( n >= 16 ) + return( MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA ); + + while( length-- ) + { + if( n == 0 ) { + mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, nonce_counter, + stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ +#endif /* !MBEDTLS_CAMELLIA_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Camellia test vectors from: + * + * http://info.isl.ntt.co.jp/crypt/eng/camellia/technology.html: + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/cryptrec/intermediate.txt + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/cryptrec/t_camellia.txt + * (For each bitlength: Key 0, Nr 39) + */ +#define CAMELLIA_TESTS_ECB 2 + +static const unsigned char camellia_test_ecb_key[3][CAMELLIA_TESTS_ECB][32] = +{ + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, +}; + +static const unsigned char camellia_test_ecb_plain[CAMELLIA_TESTS_ECB][16] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char camellia_test_ecb_cipher[3][CAMELLIA_TESTS_ECB][16] = +{ + { + { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73, + 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 }, + { 0x38, 0x3C, 0x6C, 0x2A, 0xAB, 0xEF, 0x7F, 0xDE, + 0x25, 0xCD, 0x47, 0x0B, 0xF7, 0x74, 0xA3, 0x31 } + }, + { + { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8, + 0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 }, + { 0xD1, 0x76, 0x3F, 0xC0, 0x19, 0xD7, 0x7C, 0xC9, + 0x30, 0xBF, 0xF2, 0xA5, 0x6F, 0x7C, 0x93, 0x64 } + }, + { + { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c, + 0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 }, + { 0x05, 0x03, 0xFB, 0x10, 0xAB, 0x24, 0x1E, 0x7C, + 0xF4, 0x5D, 0x8C, 0xDE, 0xEE, 0x47, 0x43, 0x35 } + } +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#define CAMELLIA_TESTS_CBC 3 + +static const unsigned char camellia_test_cbc_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C } + , + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B } + , + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char camellia_test_cbc_iv[16] = + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F } +; + +static const unsigned char camellia_test_cbc_plain[CAMELLIA_TESTS_CBC][16] = +{ + { 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A }, + { 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51 }, + { 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF } + +}; + +static const unsigned char camellia_test_cbc_cipher[3][CAMELLIA_TESTS_CBC][16] = +{ + { + { 0x16, 0x07, 0xCF, 0x49, 0x4B, 0x36, 0xBB, 0xF0, + 0x0D, 0xAE, 0xB0, 0xB5, 0x03, 0xC8, 0x31, 0xAB }, + { 0xA2, 0xF2, 0xCF, 0x67, 0x16, 0x29, 0xEF, 0x78, + 0x40, 0xC5, 0xA5, 0xDF, 0xB5, 0x07, 0x48, 0x87 }, + { 0x0F, 0x06, 0x16, 0x50, 0x08, 0xCF, 0x8B, 0x8B, + 0x5A, 0x63, 0x58, 0x63, 0x62, 0x54, 0x3E, 0x54 } + }, + { + { 0x2A, 0x48, 0x30, 0xAB, 0x5A, 0xC4, 0xA1, 0xA2, + 0x40, 0x59, 0x55, 0xFD, 0x21, 0x95, 0xCF, 0x93 }, + { 0x5D, 0x5A, 0x86, 0x9B, 0xD1, 0x4C, 0xE5, 0x42, + 0x64, 0xF8, 0x92, 0xA6, 0xDD, 0x2E, 0xC3, 0xD5 }, + { 0x37, 0xD3, 0x59, 0xC3, 0x34, 0x98, 0x36, 0xD8, + 0x84, 0xE3, 0x10, 0xAD, 0xDF, 0x68, 0xC4, 0x49 } + }, + { + { 0xE6, 0xCF, 0xA3, 0x5F, 0xC0, 0x2B, 0x13, 0x4A, + 0x4D, 0x2C, 0x0B, 0x67, 0x37, 0xAC, 0x3E, 0xDA }, + { 0x36, 0xCB, 0xEB, 0x73, 0xBD, 0x50, 0x4B, 0x40, + 0x70, 0xB1, 0xB7, 0xDE, 0x2B, 0x21, 0xEB, 0x50 }, + { 0xE3, 0x1A, 0x60, 0x55, 0x29, 0x7D, 0x96, 0xCA, + 0x33, 0x30, 0xCD, 0xF1, 0xB1, 0x86, 0x0A, 0x83 } + } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * Camellia-CTR test vectors from: + * + * http://www.faqs.org/rfcs/rfc5528.html + */ + +static const unsigned char camellia_test_ctr_key[3][16] = +{ + { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E }, + { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7, + 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 }, + { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, + 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC } +}; + +static const unsigned char camellia_test_ctr_nonce_counter[3][16] = +{ + { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59, + 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F, + 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 } +}; + +static const unsigned char camellia_test_ctr_pt[3][48] = +{ + { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 } +}; + +static const unsigned char camellia_test_ctr_ct[3][48] = +{ + { 0xD0, 0x9D, 0xC2, 0x9A, 0x82, 0x14, 0x61, 0x9A, + 0x20, 0x87, 0x7C, 0x76, 0xDB, 0x1F, 0x0B, 0x3F }, + { 0xDB, 0xF3, 0xC7, 0x8D, 0xC0, 0x83, 0x96, 0xD4, + 0xDA, 0x7C, 0x90, 0x77, 0x65, 0xBB, 0xCB, 0x44, + 0x2B, 0x8E, 0x8E, 0x0F, 0x31, 0xF0, 0xDC, 0xA7, + 0x2C, 0x74, 0x17, 0xE3, 0x53, 0x60, 0xE0, 0x48 }, + { 0xB1, 0x9D, 0x1F, 0xCD, 0xCB, 0x75, 0xEB, 0x88, + 0x2F, 0x84, 0x9C, 0xE2, 0x4D, 0x85, 0xCF, 0x73, + 0x9C, 0xE6, 0x4B, 0x2B, 0x5C, 0x9D, 0x73, 0xF1, + 0x4F, 0x2D, 0x5D, 0x9D, 0xCE, 0x98, 0x89, 0xCD, + 0xDF, 0x50, 0x86, 0x96 } +}; + +static const int camellia_test_ctr_len[3] = + { 16, 32, 36 }; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +/* + * Checkup routine + */ +int mbedtls_camellia_self_test( int verbose ) +{ + int i, j, u, v; + unsigned char key[32]; + unsigned char buf[64]; + unsigned char src[16]; + unsigned char dst[16]; +#if defined(MBEDTLS_CIPHER_MODE_CBC) + unsigned char iv[16]; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + size_t offset, len; + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; +#endif + + mbedtls_camellia_context ctx; + + memset( key, 0, 32 ); + + for( j = 0; j < 6; j++ ) { + u = j >> 1; + v = j & 1; + + if( verbose != 0 ) + mbedtls_printf( " CAMELLIA-ECB-%3d (%s): ", 128 + u * 64, + (v == MBEDTLS_CAMELLIA_DECRYPT) ? "dec" : "enc"); + + for( i = 0; i < CAMELLIA_TESTS_ECB; i++ ) { + memcpy( key, camellia_test_ecb_key[u][i], 16 + 8 * u ); + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) { + mbedtls_camellia_setkey_dec( &ctx, key, 128 + u * 64 ); + memcpy( src, camellia_test_ecb_cipher[u][i], 16 ); + memcpy( dst, camellia_test_ecb_plain[i], 16 ); + } else { /* MBEDTLS_CAMELLIA_ENCRYPT */ + mbedtls_camellia_setkey_enc( &ctx, key, 128 + u * 64 ); + memcpy( src, camellia_test_ecb_plain[i], 16 ); + memcpy( dst, camellia_test_ecb_cipher[u][i], 16 ); + } + + mbedtls_camellia_crypt_ecb( &ctx, v, src, buf ); + + if( memcmp( buf, dst, 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for( j = 0; j < 6; j++ ) + { + u = j >> 1; + v = j & 1; + + if( verbose != 0 ) + mbedtls_printf( " CAMELLIA-CBC-%3d (%s): ", 128 + u * 64, + ( v == MBEDTLS_CAMELLIA_DECRYPT ) ? "dec" : "enc" ); + + memcpy( src, camellia_test_cbc_iv, 16 ); + memcpy( dst, camellia_test_cbc_iv, 16 ); + memcpy( key, camellia_test_cbc_key[u], 16 + 8 * u ); + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) { + mbedtls_camellia_setkey_dec( &ctx, key, 128 + u * 64 ); + } else { + mbedtls_camellia_setkey_enc( &ctx, key, 128 + u * 64 ); + } + + for( i = 0; i < CAMELLIA_TESTS_CBC; i++ ) { + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) { + memcpy( iv , src, 16 ); + memcpy( src, camellia_test_cbc_cipher[u][i], 16 ); + memcpy( dst, camellia_test_cbc_plain[i], 16 ); + } else { /* MBEDTLS_CAMELLIA_ENCRYPT */ + memcpy( iv , dst, 16 ); + memcpy( src, camellia_test_cbc_plain[i], 16 ); + memcpy( dst, camellia_test_cbc_cipher[u][i], 16 ); + } + + mbedtls_camellia_crypt_cbc( &ctx, v, 16, iv, src, buf ); + + if( memcmp( buf, dst, 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /* + * CTR mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " CAMELLIA-CTR-128 (%s): ", + ( v == MBEDTLS_CAMELLIA_DECRYPT ) ? "dec" : "enc" ); + + memcpy( nonce_counter, camellia_test_ctr_nonce_counter[u], 16 ); + memcpy( key, camellia_test_ctr_key[u], 16 ); + + offset = 0; + mbedtls_camellia_setkey_enc( &ctx, key, 128 ); + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) + { + len = camellia_test_ctr_len[u]; + memcpy( buf, camellia_test_ctr_ct[u], len ); + + mbedtls_camellia_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, + buf, buf ); + + if( memcmp( buf, camellia_test_ctr_pt[u], len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + else + { + len = camellia_test_ctr_len[u]; + memcpy( buf, camellia_test_ctr_pt[u], len ); + + mbedtls_camellia_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, + buf, buf ); + + if( memcmp( buf, camellia_test_ctr_ct[u], len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CAMELLIA_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ccm.c b/FreeRTOS-Labs/Source/mbedtls/library/ccm.c new file mode 100644 index 000000000..4f30f3064 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ccm.c @@ -0,0 +1,552 @@ +/* + * NIST SP800-38C compliant CCM implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * Definition of CCM: + * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf + * RFC 3610 "Counter with CBC-MAC (CCM)" + * + * Related: + * RFC 5116 "An Interface and Algorithms for Authenticated Encryption" + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CCM_C) + +#include "mbedtls/ccm.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#if !defined(MBEDTLS_CCM_ALT) + +#define CCM_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CCM_BAD_INPUT ) +#define CCM_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#define CCM_ENCRYPT 0 +#define CCM_DECRYPT 1 + +/* + * Initialize context + */ +void mbedtls_ccm_init( mbedtls_ccm_context *ctx ) +{ + CCM_VALIDATE( ctx != NULL ); + memset( ctx, 0, sizeof( mbedtls_ccm_context ) ); +} + +int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ) +{ + int ret; + const mbedtls_cipher_info_t *cipher_info; + + CCM_VALIDATE_RET( ctx != NULL ); + CCM_VALIDATE_RET( key != NULL ); + + cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, + MBEDTLS_MODE_ECB ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + if( cipher_info->block_size != 16 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + mbedtls_cipher_free( &ctx->cipher_ctx ); + + if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits, + MBEDTLS_ENCRYPT ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +/* + * Free context + */ +void mbedtls_ccm_free( mbedtls_ccm_context *ctx ) +{ + if( ctx == NULL ) + return; + mbedtls_cipher_free( &ctx->cipher_ctx ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ccm_context ) ); +} + +/* + * Macros for common operations. + * Results in smaller compiled code than static inline functions. + */ + +/* + * Update the CBC-MAC state in y using a block in b + * (Always using b as the source helps the compiler optimise a bit better.) + */ +#define UPDATE_CBC_MAC \ + for( i = 0; i < 16; i++ ) \ + y[i] ^= b[i]; \ + \ + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \ + return( ret ); + +/* + * Encrypt or decrypt a partial block with CTR + * Warning: using b for temporary storage! src and dst must not be b! + * This avoids allocating one more 16 bytes buffer while allowing src == dst. + */ +#define CTR_CRYPT( dst, src, len ) \ + do \ + { \ + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, \ + 16, b, &olen ) ) != 0 ) \ + { \ + return( ret ); \ + } \ + \ + for( i = 0; i < (len); i++ ) \ + (dst)[i] = (src)[i] ^ b[i]; \ + } while( 0 ) + +/* + * Authenticated encryption or decryption + */ +static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ) +{ + int ret; + unsigned char i; + unsigned char q; + size_t len_left, olen; + unsigned char b[16]; + unsigned char y[16]; + unsigned char ctr[16]; + const unsigned char *src; + unsigned char *dst; + + /* + * Check length requirements: SP800-38C A.1 + * Additional requirement: a < 2^16 - 2^8 to simplify the code. + * 'length' checked later (when writing it to the first block) + * + * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4). + */ + if( tag_len == 2 || tag_len > 16 || tag_len % 2 != 0 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + /* Also implies q is within bounds */ + if( iv_len < 7 || iv_len > 13 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + if( add_len > 0xFF00 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + q = 16 - 1 - (unsigned char) iv_len; + + /* + * First block B_0: + * 0 .. 0 flags + * 1 .. iv_len nonce (aka iv) + * iv_len+1 .. 15 length + * + * With flags as (bits): + * 7 0 + * 6 add present? + * 5 .. 3 (t - 2) / 2 + * 2 .. 0 q - 1 + */ + b[0] = 0; + b[0] |= ( add_len > 0 ) << 6; + b[0] |= ( ( tag_len - 2 ) / 2 ) << 3; + b[0] |= q - 1; + + memcpy( b + 1, iv, iv_len ); + + for( i = 0, len_left = length; i < q; i++, len_left >>= 8 ) + b[15-i] = (unsigned char)( len_left & 0xFF ); + + if( len_left > 0 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + + /* Start CBC-MAC with first block */ + memset( y, 0, 16 ); + UPDATE_CBC_MAC; + + /* + * If there is additional data, update CBC-MAC with + * add_len, add, 0 (padding to a block boundary) + */ + if( add_len > 0 ) + { + size_t use_len; + len_left = add_len; + src = add; + + memset( b, 0, 16 ); + b[0] = (unsigned char)( ( add_len >> 8 ) & 0xFF ); + b[1] = (unsigned char)( ( add_len ) & 0xFF ); + + use_len = len_left < 16 - 2 ? len_left : 16 - 2; + memcpy( b + 2, src, use_len ); + len_left -= use_len; + src += use_len; + + UPDATE_CBC_MAC; + + while( len_left > 0 ) + { + use_len = len_left > 16 ? 16 : len_left; + + memset( b, 0, 16 ); + memcpy( b, src, use_len ); + UPDATE_CBC_MAC; + + len_left -= use_len; + src += use_len; + } + } + + /* + * Prepare counter block for encryption: + * 0 .. 0 flags + * 1 .. iv_len nonce (aka iv) + * iv_len+1 .. 15 counter (initially 1) + * + * With flags as (bits): + * 7 .. 3 0 + * 2 .. 0 q - 1 + */ + ctr[0] = q - 1; + memcpy( ctr + 1, iv, iv_len ); + memset( ctr + 1 + iv_len, 0, q ); + ctr[15] = 1; + + /* + * Authenticate and {en,de}crypt the message. + * + * The only difference between encryption and decryption is + * the respective order of authentication and {en,de}cryption. + */ + len_left = length; + src = input; + dst = output; + + while( len_left > 0 ) + { + size_t use_len = len_left > 16 ? 16 : len_left; + + if( mode == CCM_ENCRYPT ) + { + memset( b, 0, 16 ); + memcpy( b, src, use_len ); + UPDATE_CBC_MAC; + } + + CTR_CRYPT( dst, src, use_len ); + + if( mode == CCM_DECRYPT ) + { + memset( b, 0, 16 ); + memcpy( b, dst, use_len ); + UPDATE_CBC_MAC; + } + + dst += use_len; + src += use_len; + len_left -= use_len; + + /* + * Increment counter. + * No need to check for overflow thanks to the length check above. + */ + for( i = 0; i < q; i++ ) + if( ++ctr[15-i] != 0 ) + break; + } + + /* + * Authentication: reset counter and crypt/mask internal tag + */ + for( i = 0; i < q; i++ ) + ctr[15-i] = 0; + + CTR_CRYPT( y, y, 16 ); + memcpy( tag, y, tag_len ); + + return( 0 ); +} + +/* + * Authenticated encryption + */ +int mbedtls_ccm_star_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ) +{ + CCM_VALIDATE_RET( ctx != NULL ); + CCM_VALIDATE_RET( iv != NULL ); + CCM_VALIDATE_RET( add_len == 0 || add != NULL ); + CCM_VALIDATE_RET( length == 0 || input != NULL ); + CCM_VALIDATE_RET( length == 0 || output != NULL ); + CCM_VALIDATE_RET( tag_len == 0 || tag != NULL ); + return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len, + add, add_len, input, output, tag, tag_len ) ); +} + +int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ) +{ + CCM_VALIDATE_RET( ctx != NULL ); + CCM_VALIDATE_RET( iv != NULL ); + CCM_VALIDATE_RET( add_len == 0 || add != NULL ); + CCM_VALIDATE_RET( length == 0 || input != NULL ); + CCM_VALIDATE_RET( length == 0 || output != NULL ); + CCM_VALIDATE_RET( tag_len == 0 || tag != NULL ); + if( tag_len == 0 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + return( mbedtls_ccm_star_encrypt_and_tag( ctx, length, iv, iv_len, add, + add_len, input, output, tag, tag_len ) ); +} + +/* + * Authenticated decryption + */ +int mbedtls_ccm_star_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len ) +{ + int ret; + unsigned char check_tag[16]; + unsigned char i; + int diff; + + CCM_VALIDATE_RET( ctx != NULL ); + CCM_VALIDATE_RET( iv != NULL ); + CCM_VALIDATE_RET( add_len == 0 || add != NULL ); + CCM_VALIDATE_RET( length == 0 || input != NULL ); + CCM_VALIDATE_RET( length == 0 || output != NULL ); + CCM_VALIDATE_RET( tag_len == 0 || tag != NULL ); + + if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length, + iv, iv_len, add, add_len, + input, output, check_tag, tag_len ) ) != 0 ) + { + return( ret ); + } + + /* Check tag in "constant-time" */ + for( diff = 0, i = 0; i < tag_len; i++ ) + diff |= tag[i] ^ check_tag[i]; + + if( diff != 0 ) + { + mbedtls_platform_zeroize( output, length ); + return( MBEDTLS_ERR_CCM_AUTH_FAILED ); + } + + return( 0 ); +} + +int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len ) +{ + CCM_VALIDATE_RET( ctx != NULL ); + CCM_VALIDATE_RET( iv != NULL ); + CCM_VALIDATE_RET( add_len == 0 || add != NULL ); + CCM_VALIDATE_RET( length == 0 || input != NULL ); + CCM_VALIDATE_RET( length == 0 || output != NULL ); + CCM_VALIDATE_RET( tag_len == 0 || tag != NULL ); + + if( tag_len == 0 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + return( mbedtls_ccm_star_auth_decrypt( ctx, length, iv, iv_len, add, + add_len, input, output, tag, tag_len ) ); +} +#endif /* !MBEDTLS_CCM_ALT */ + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/* + * Examples 1 to 3 from SP800-38C Appendix C + */ + +#define NB_TESTS 3 +#define CCM_SELFTEST_PT_MAX_LEN 24 +#define CCM_SELFTEST_CT_MAX_LEN 32 +/* + * The data is the same for all tests, only the used length changes + */ +static const unsigned char key_test_data[] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f +}; + +static const unsigned char iv_test_data[] = { + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b +}; + +static const unsigned char ad_test_data[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13 +}; + +static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, +}; + +static const size_t iv_len_test_data [NB_TESTS] = { 7, 8, 12 }; +static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 }; +static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 }; +static const size_t tag_len_test_data[NB_TESTS] = { 4, 6, 8 }; + +static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = { + { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d }, + { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, + 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d, + 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd }, + { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, + 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, + 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, + 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 } +}; + +int mbedtls_ccm_self_test( int verbose ) +{ + mbedtls_ccm_context ctx; + /* + * Some hardware accelerators require the input and output buffers + * would be in RAM, because the flash is not accessible. + * Use buffers on the stack to hold the test vectors data. + */ + unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN]; + unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN]; + size_t i; + int ret; + + mbedtls_ccm_init( &ctx ); + + if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key_test_data, + 8 * sizeof key_test_data ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( " CCM: setup failed" ); + + return( 1 ); + } + + for( i = 0; i < NB_TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i + 1 ); + + memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN ); + memset( ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN ); + memcpy( plaintext, msg_test_data, msg_len_test_data[i] ); + + ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len_test_data[i], + iv_test_data, iv_len_test_data[i], + ad_test_data, add_len_test_data[i], + plaintext, ciphertext, + ciphertext + msg_len_test_data[i], + tag_len_test_data[i] ); + + if( ret != 0 || + memcmp( ciphertext, res_test_data[i], + msg_len_test_data[i] + tag_len_test_data[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN ); + + ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len_test_data[i], + iv_test_data, iv_len_test_data[i], + ad_test_data, add_len_test_data[i], + ciphertext, plaintext, + ciphertext + msg_len_test_data[i], + tag_len_test_data[i] ); + + if( ret != 0 || + memcmp( plaintext, msg_test_data, msg_len_test_data[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + mbedtls_ccm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#endif /* MBEDTLS_CCM_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/certs.c b/FreeRTOS-Labs/Source/mbedtls/library/certs.c new file mode 100644 index 000000000..c4246ef1a --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/certs.c @@ -0,0 +1,436 @@ +/* + * X.509 test certificates + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "mbedtls/certs.h" + +#if defined(MBEDTLS_CERTS_C) + +#if defined(MBEDTLS_ECDSA_C) +#define TEST_CA_CRT_EC \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIICUjCCAdegAwIBAgIJAMFD4n5iQ8zoMAoGCCqGSM49BAMCMD4xCzAJBgNVBAYT\r\n" \ +"Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF\r\n" \ +"QyBDQTAeFw0xMzA5MjQxNTQ5NDhaFw0yMzA5MjIxNTQ5NDhaMD4xCzAJBgNVBAYT\r\n" \ +"Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF\r\n" \ +"QyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMPaKzRBN1gvh1b+/Im6KUNLTuBu\r\n" \ +"ww5XUzM5WNRStJGVOQsj318XJGJI/BqVKc4sLYfCiFKAr9ZqqyHduNMcbli4yuiy\r\n" \ +"aY7zQa0pw7RfdadHb9UZKVVpmlM7ILRmFmAzHqOBoDCBnTAdBgNVHQ4EFgQUnW0g\r\n" \ +"JEkBPyvLeLUZvH4kydv7NnwwbgYDVR0jBGcwZYAUnW0gJEkBPyvLeLUZvH4kydv7\r\n" \ +"NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UE\r\n" \ +"AxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAwGA1UdEwQFMAMBAf8w\r\n" \ +"CgYIKoZIzj0EAwIDaQAwZgIxAMO0YnNWKJUAfXgSJtJxexn4ipg+kv4znuR50v56\r\n" \ +"t4d0PCu412mUC6Nnd7izvtE2MgIxAP1nnJQjZ8BWukszFQDG48wxCCyci9qpdSMv\r\n" \ +"uCjn8pwUOkABXK8Mss90fzCfCEOtIA==\r\n" \ +"-----END CERTIFICATE-----\r\n" +const char mbedtls_test_ca_crt_ec[] = TEST_CA_CRT_EC; +const size_t mbedtls_test_ca_crt_ec_len = sizeof( mbedtls_test_ca_crt_ec ); + +const char mbedtls_test_ca_key_ec[] = +"-----BEGIN EC PRIVATE KEY-----\r\n" +"Proc-Type: 4,ENCRYPTED\r\n" +"DEK-Info: DES-EDE3-CBC,307EAB469933D64E\r\n" +"\r\n" +"IxbrRmKcAzctJqPdTQLA4SWyBYYGYJVkYEna+F7Pa5t5Yg/gKADrFKcm6B72e7DG\r\n" +"ihExtZI648s0zdYw6qSJ74vrPSuWDe5qm93BqsfVH9svtCzWHW0pm1p0KTBCFfUq\r\n" +"UsuWTITwJImcnlAs1gaRZ3sAWm7cOUidL0fo2G0fYUFNcYoCSLffCFTEHBuPnagb\r\n" +"a77x/sY1Bvii8S9/XhDTb6pTMx06wzrm\r\n" +"-----END EC PRIVATE KEY-----\r\n"; +const size_t mbedtls_test_ca_key_ec_len = sizeof( mbedtls_test_ca_key_ec ); + +const char mbedtls_test_ca_pwd_ec[] = "PolarSSLTest"; +const size_t mbedtls_test_ca_pwd_ec_len = sizeof( mbedtls_test_ca_pwd_ec ) - 1; + +const char mbedtls_test_srv_crt_ec[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIICHzCCAaWgAwIBAgIBCTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN\r\n" +"MTMwOTI0MTU1MjA0WhcNMjMwOTIyMTU1MjA0WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG\r\n" +"CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA\r\n" +"2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jgZ0wgZowCQYDVR0TBAIwADAd\r\n" +"BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wbgYDVR0jBGcwZYAUnW0gJEkB\r\n" +"PyvLeLUZvH4kydv7NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xh\r\n" +"clNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAoG\r\n" +"CCqGSM49BAMCA2gAMGUCMQCaLFzXptui5WQN8LlO3ddh1hMxx6tzgLvT03MTVK2S\r\n" +"C12r0Lz3ri/moSEpNZWqPjkCMCE2f53GXcYLqyfyJR078c/xNSUU5+Xxl7VZ414V\r\n" +"fGa5kHvHARBPc8YAIVIqDvHH1Q==\r\n" +"-----END CERTIFICATE-----\r\n"; +const size_t mbedtls_test_srv_crt_ec_len = sizeof( mbedtls_test_srv_crt_ec ); + +const char mbedtls_test_srv_key_ec[] = +"-----BEGIN EC PRIVATE KEY-----\r\n" +"MHcCAQEEIPEqEyB2AnCoPL/9U/YDHvdqXYbIogTywwyp6/UfDw6noAoGCCqGSM49\r\n" +"AwEHoUQDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO5QDYIxH/\r\n" +"6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/w==\r\n" +"-----END EC PRIVATE KEY-----\r\n"; +const size_t mbedtls_test_srv_key_ec_len = sizeof( mbedtls_test_srv_key_ec ); + +const char mbedtls_test_cli_crt_ec[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIICLDCCAbKgAwIBAgIBDTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN\r\n" +"MTMwOTI0MTU1MjA0WhcNMjMwOTIyMTU1MjA0WjBBMQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxHzAdBgNVBAMTFlBvbGFyU1NMIFRlc3QgQ2xpZW50IDIw\r\n" +"WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARX5a6xc9/TrLuTuIH/Eq7u5lOszlVT\r\n" +"9jQOzC7jYyUL35ji81xgNpbA1RgUcOV/n9VLRRjlsGzVXPiWj4dwo+THo4GdMIGa\r\n" +"MAkGA1UdEwQCMAAwHQYDVR0OBBYEFHoAX4Zk/OBd5REQO7LmO8QmP8/iMG4GA1Ud\r\n" +"IwRnMGWAFJ1tICRJAT8ry3i1Gbx+JMnb+zZ8oUKkQDA+MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0GC\r\n" +"CQDBQ+J+YkPM6DAKBggqhkjOPQQDAgNoADBlAjBKZQ17IIOimbmoD/yN7o89u3BM\r\n" +"lgOsjnhw3fIOoLIWy2WOGsk/LGF++DzvrRzuNiACMQCd8iem1XS4JK7haj8xocpU\r\n" +"LwjQje5PDGHfd3h9tP38Qknu5bJqws0md2KOKHyeV0U=\r\n" +"-----END CERTIFICATE-----\r\n"; +const size_t mbedtls_test_cli_crt_ec_len = sizeof( mbedtls_test_cli_crt_ec ); + +const char mbedtls_test_cli_key_ec[] = +"-----BEGIN EC PRIVATE KEY-----\r\n" +"MHcCAQEEIPb3hmTxZ3/mZI3vyk7p3U3wBf+WIop6hDhkFzJhmLcqoAoGCCqGSM49\r\n" +"AwEHoUQDQgAEV+WusXPf06y7k7iB/xKu7uZTrM5VU/Y0Dswu42MlC9+Y4vNcYDaW\r\n" +"wNUYFHDlf5/VS0UY5bBs1Vz4lo+HcKPkxw==\r\n" +"-----END EC PRIVATE KEY-----\r\n"; +const size_t mbedtls_test_cli_key_ec_len = sizeof( mbedtls_test_cli_key_ec ); +#endif /* MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_RSA_C) +#if defined(MBEDTLS_SHA256_C) +#define TEST_CA_CRT_RSA_SHA256 \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIIDhzCCAm+gAwIBAgIBADANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n" \ +"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ +"MTcwNTA0MTY1NzAxWhcNMjcwNTA1MTY1NzAxWjA7MQswCQYDVQQGEwJOTDERMA8G\r\n" \ +"A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G\r\n" \ +"CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx\r\n" \ +"mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny\r\n" \ +"50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n\r\n" \ +"YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL\r\n" \ +"R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu\r\n" \ +"KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj\r\n" \ +"gZUwgZIwHQYDVR0OBBYEFLRa5KWz3tJS9rnVppUP6z68x/3/MGMGA1UdIwRcMFqA\r\n" \ +"FLRa5KWz3tJS9rnVppUP6z68x/3/oT+kPTA7MQswCQYDVQQGEwJOTDERMA8GA1UE\r\n" \ +"CgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0GCAQAwDAYDVR0T\r\n" \ +"BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAHK/HHrTZMnnVMpde1io+voAtql7j\r\n" \ +"4sRhLrjD7o3THtwRbDa2diCvpq0Sq23Ng2LMYoXsOxoL/RQK3iN7UKxV3MKPEr0w\r\n" \ +"XQS+kKQqiT2bsfrjnWMVHZtUOMpm6FNqcdGm/Rss3vKda2lcKl8kUnq/ylc1+QbB\r\n" \ +"G6A6tUvQcr2ZyWfVg+mM5XkhTrOOXus2OLikb4WwEtJTJRNE0f+yPODSUz0/vT57\r\n" \ +"ApH0CnB80bYJshYHPHHymOtleAB8KSYtqm75g/YNobjnjB6cm4HkW3OZRVIl6fYY\r\n" \ +"n20NRVA1Vjs6GAROr4NqW4k/+LofY9y0LLDE+p0oIEKXIsIvhPr39swxSA==\r\n" \ +"-----END CERTIFICATE-----\r\n" + +static const char mbedtls_test_ca_crt_rsa_sha256[] = TEST_CA_CRT_RSA_SHA256; +const char mbedtls_test_ca_crt_rsa[] = TEST_CA_CRT_RSA_SHA256; +const size_t mbedtls_test_ca_crt_rsa_len = sizeof( mbedtls_test_ca_crt_rsa ); +#define TEST_CA_CRT_RSA_SOME +#endif /* MBEDTLS_SHA256_C */ + +#if !defined(TEST_CA_CRT_RSA_SOME) || defined(MBEDTLS_SHA1_C) +#define TEST_CA_CRT_RSA_SHA1 \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIIDhzCCAm+gAwIBAgIBADANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" \ +"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ +"MTEwMjEyMTQ0NDAwWhcNMjEwMjEyMTQ0NDAwWjA7MQswCQYDVQQGEwJOTDERMA8G\r\n" \ +"A1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G\r\n" \ +"CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx\r\n" \ +"mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny\r\n" \ +"50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n\r\n" \ +"YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL\r\n" \ +"R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu\r\n" \ +"KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj\r\n" \ +"gZUwgZIwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUtFrkpbPe0lL2udWmlQ/rPrzH\r\n" \ +"/f8wYwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJBgNV\r\n" \ +"BAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wgVGVz\r\n" \ +"dCBDQYIBADANBgkqhkiG9w0BAQUFAAOCAQEAuP1U2ABUkIslsCfdlc2i94QHHYeJ\r\n" \ +"SsR4EdgHtdciUI5I62J6Mom+Y0dT/7a+8S6MVMCZP6C5NyNyXw1GWY/YR82XTJ8H\r\n" \ +"DBJiCTok5DbZ6SzaONBzdWHXwWwmi5vg1dxn7YxrM9d0IjxM27WNKs4sDQhZBQkF\r\n" \ +"pjmfs2cb4oPl4Y9T9meTx/lvdkRYEug61Jfn6cA+qHpyPYdTH+UshITnmp5/Ztkf\r\n" \ +"m/UTSLBNFNHesiTZeH31NcxYGdHSme9Nc/gfidRa0FLOCfWxRlFqAI47zG9jAQCZ\r\n" \ +"7Z2mCGDNMhjQc+BYcdnl0lPXjdDK6V0qCg1dVewhUBcW5gZKzV7e9+DpVA==\r\n" \ +"-----END CERTIFICATE-----\r\n" + +static const char mbedtls_test_ca_crt_rsa_sha1[] = TEST_CA_CRT_RSA_SHA1; + +#if !defined (TEST_CA_CRT_RSA_SOME) +const char mbedtls_test_ca_crt_rsa[] = TEST_CA_CRT_RSA_SHA1; +const size_t mbedtls_test_ca_crt_rsa_len = sizeof( mbedtls_test_ca_crt_rsa ); +#endif /* !TEST_CA_CRT_RSA_SOME */ +#endif /* !TEST_CA_CRT_RSA_COME || MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) +/* tests/data_files/server2-sha256.crt */ +#define TEST_SRV_CRT_RSA_SHA256 \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n" \ +"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ +"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" \ +"A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n" \ +"AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n" \ +"owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n" \ +"NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n" \ +"tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n" \ +"hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n" \ +"HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n" \ +"VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n" \ +"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQELBQADggEBAGGEshT5\r\n" \ +"kvnRmLVScVeUEdwIrvW7ezbGbUvJ8VxeJ79/HSjlLiGbMc4uUathwtzEdi9R/4C5\r\n" \ +"DXBNeEPTkbB+fhG1W06iHYj/Dp8+aaG7fuDxKVKHVZSqBnmQLn73ymyclZNHii5A\r\n" \ +"3nTS8WUaHAzxN/rajOtoM7aH1P9tULpHrl+7HOeLMpxUnwI12ZqZaLIzxbcdJVcr\r\n" \ +"ra2F00aXCGkYVLvyvbZIq7LC+yVysej5gCeQYD7VFOEks0jhFjrS06gP0/XnWv6v\r\n" \ +"eBoPez9d+CCjkrhseiWzXOiriIMICX48EloO/DrsMRAtvlwq7EDz4QhILz6ffndm\r\n" \ +"e4K1cVANRPN2o9Y=\r\n" \ +"-----END CERTIFICATE-----\r\n" + +const char mbedtls_test_srv_crt_rsa[] = TEST_SRV_CRT_RSA_SHA256; +const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa ); +#define TEST_SRV_CRT_RSA_SOME +#endif /* MBEDTLS_SHA256_C */ + +#if !defined(TEST_SRV_CRT_RSA_SOME) || defined(MBEDTLS_SHA1_C) +/* tests/data_files/server2.crt */ +#define TEST_SRV_CRT_RSA_SHA1 \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" \ +"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ +"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" \ +"A1UECgwIUG9sYXJTU0wxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n" \ +"AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n" \ +"owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n" \ +"NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n" \ +"tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n" \ +"hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n" \ +"HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n" \ +"VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n" \ +"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQEFBQADggEBAAFzC0rF\r\n" \ +"y6De8WMcdgQrEw3AhBHFjzqnxZw1ene4IBSC7lTw8rBSy3jOWQdPUWn+0y/pCeeF\r\n" \ +"kti6sevFdl1hLemGtd4q+T9TKEKGg3ND4ARfB5AUZZ9uEHq8WBkiwus5clGS17Qd\r\n" \ +"dS/TOisB59tQruLx1E1bPLtBKyqk4koC5WAULJwfpswGSyWJTpYwIpxcWE3D2tBu\r\n" \ +"UB6MZfXZFzWmWEOyKbeoXjXe8GBCGgHLywvYDsGQ36HSGtEsAvR2QaTLSxWYcfk1\r\n" \ +"fbDn4jSWkb4yZy1r01UEigFQtONieGwRFaUqEcFJHJvEEGVgh9keaVlOj2vrwf5r\r\n" \ +"4mN4lW7gLdenN6g=\r\n" \ +"-----END CERTIFICATE-----\r\n"; + +#if !defined(TEST_SRV_CRT_RSA_SOME) +const char mbedtls_test_srv_crt_rsa[] = TEST_SRV_CRT_RSA_SHA1; +const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa ); +#endif /* TEST_SRV_CRT_RSA_SOME */ +#endif /* !TEST_CA_CRT_RSA_SOME || MBEDTLS_SHA1_C */ + +const char mbedtls_test_ca_key_rsa[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"Proc-Type: 4,ENCRYPTED\r\n" +"DEK-Info: DES-EDE3-CBC,A8A95B05D5B7206B\r\n" +"\r\n" +"9Qd9GeArejl1GDVh2lLV1bHt0cPtfbh5h/5zVpAVaFpqtSPMrElp50Rntn9et+JA\r\n" +"7VOyboR+Iy2t/HU4WvA687k3Bppe9GwKHjHhtl//8xFKwZr3Xb5yO5JUP8AUctQq\r\n" +"Nb8CLlZyuUC+52REAAthdWgsX+7dJO4yabzUcQ22Tp9JSD0hiL43BlkWYUNK3dAo\r\n" +"PZlmiptjnzVTjg1MxsBSydZinWOLBV8/JQgxSPo2yD4uEfig28qbvQ2wNIn0pnAb\r\n" +"GxnSAOazkongEGfvcjIIs+LZN9gXFhxcOh6kc4Q/c99B7QWETwLLkYgZ+z1a9VY9\r\n" +"gEU7CwCxYCD+h9hY6FPmsK0/lC4O7aeRKpYq00rPPxs6i7phiexg6ax6yTMmArQq\r\n" +"QmK3TAsJm8V/J5AWpLEV6jAFgRGymGGHnof0DXzVWZidrcZJWTNuGEX90nB3ee2w\r\n" +"PXJEFWKoD3K3aFcSLdHYr3mLGxP7H9ThQai9VsycxZKS5kwvBKQ//YMrmFfwPk8x\r\n" +"vTeY4KZMaUrveEel5tWZC94RSMKgxR6cyE1nBXyTQnDOGbfpNNgBKxyKbINWoOJU\r\n" +"WJZAwlsQn+QzCDwpri7+sV1mS3gBE6UY7aQmnmiiaC2V3Hbphxct/en5QsfDOt1X\r\n" +"JczSfpRWLlbPznZg8OQh/VgCMA58N5DjOzTIK7sJJ5r+94ZBTCpgAMbF588f0NTR\r\n" +"KCe4yrxGJR7X02M4nvD4IwOlpsQ8xQxZtOSgXv4LkxvdU9XJJKWZ/XNKJeWztxSe\r\n" +"Z1vdTc2YfsDBA2SEv33vxHx2g1vqtw8SjDRT2RaQSS0QuSaMJimdOX6mTOCBKk1J\r\n" +"9Q5mXTrER+/LnK0jEmXsBXWA5bqqVZIyahXSx4VYZ7l7w/PHiUDtDgyRhMMKi4n2\r\n" +"iQvQcWSQTjrpnlJbca1/DkpRt3YwrvJwdqb8asZU2VrNETh5x0QVefDRLFiVpif/\r\n" +"tUaeAe/P1F8OkS7OIZDs1SUbv/sD2vMbhNkUoCms3/PvNtdnvgL4F0zhaDpKCmlT\r\n" +"P8vx49E7v5CyRNmED9zZg4o3wmMqrQO93PtTug3Eu9oVx1zPQM1NVMyBa2+f29DL\r\n" +"1nuTCeXdo9+ni45xx+jAI4DCwrRdhJ9uzZyC6962H37H6D+5naNvClFR1s6li1Gb\r\n" +"nqPoiy/OBsEx9CaDGcqQBp5Wme/3XW+6z1ISOx+igwNTVCT14mHdBMbya0eIKft5\r\n" +"X+GnwtgEMyCYyyWuUct8g4RzErcY9+yW9Om5Hzpx4zOuW4NPZgPDTgK+t2RSL/Yq\r\n" +"rE1njrgeGYcVeG3f+OftH4s6fPbq7t1A5ZgUscbLMBqr9tK+OqygR4EgKBPsH6Cz\r\n" +"L6zlv/2RV0qAHvVuDJcIDIgwY5rJtINEm32rhOeFNJwZS5MNIC1czXZx5//ugX7l\r\n" +"I4sy5nbVhwSjtAk8Xg5dZbdTZ6mIrb7xqH+fdakZor1khG7bC2uIwibD3cSl2XkR\r\n" +"wN48lslbHnqqagr6Xm1nNOSVl8C/6kbJEsMpLhAezfRtGwvOucoaE+WbeUNolGde\r\n" +"P/eQiddSf0brnpiLJRh7qZrl9XuqYdpUqnoEdMAfotDOID8OtV7gt8a48ad8VPW2\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; +const size_t mbedtls_test_ca_key_rsa_len = sizeof( mbedtls_test_ca_key_rsa ); + +const char mbedtls_test_ca_pwd_rsa[] = "PolarSSLTest"; +const size_t mbedtls_test_ca_pwd_rsa_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1; + +const char mbedtls_test_srv_key_rsa[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"MIIEpAIBAAKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r\r\n" +"lqdStJDvLXJ6PiSa/LY0rCT1d+AmZIycsCh9odrqjObJHJa8/sEEUrM21KP64bF2\r\n" +"2JDBYbRmUjaiJlOqq3ReB30Zgtsq2B+g2Q0cLUlm91slc0boC4pPaQy1AJDh2oIQ\r\n" +"Zn2uVCuLZXmRoeJhw81ASQjuaAzxi4bSRr/QuKoRAx5/VqgaHkQYDw+Fi9qLRF7i\r\n" +"GMZiL8dmjfpd2H3zJ4kpAcWQDj8n8TDISg7v1t7HxydrxwU9esQCPJodPg/oNJhb\r\n" +"y3NLUpbYEaIsgIhpOVrTD7DeWS8Rx/fqEgEwlwIDAQABAoIBAQCXR0S8EIHFGORZ\r\n" +"++AtOg6eENxD+xVs0f1IeGz57Tjo3QnXX7VBZNdj+p1ECvhCE/G7XnkgU5hLZX+G\r\n" +"Z0jkz/tqJOI0vRSdLBbipHnWouyBQ4e/A1yIJdlBtqXxJ1KE/ituHRbNc4j4kL8Z\r\n" +"/r6pvwnTI0PSx2Eqs048YdS92LT6qAv4flbNDxMn2uY7s4ycS4Q8w1JXnCeaAnYm\r\n" +"WYI5wxO+bvRELR2Mcz5DmVnL8jRyml6l6582bSv5oufReFIbyPZbQWlXgYnpu6He\r\n" +"GTc7E1zKYQGG/9+DQUl/1vQuCPqQwny0tQoX2w5tdYpdMdVm+zkLtbajzdTviJJa\r\n" +"TWzL6lt5AoGBAN86+SVeJDcmQJcv4Eq6UhtRr4QGMiQMz0Sod6ettYxYzMgxtw28\r\n" +"CIrgpozCc+UaZJLo7UxvC6an85r1b2nKPCLQFaggJ0H4Q0J/sZOhBIXaoBzWxveK\r\n" +"nupceKdVxGsFi8CDy86DBfiyFivfBj+47BbaQzPBj7C4rK7UlLjab2rDAoGBAN2u\r\n" +"AM2gchoFiu4v1HFL8D7lweEpi6ZnMJjnEu/dEgGQJFjwdpLnPbsj4c75odQ4Gz8g\r\n" +"sw9lao9VVzbusoRE/JGI4aTdO0pATXyG7eG1Qu+5Yc1YGXcCrliA2xM9xx+d7f+s\r\n" +"mPzN+WIEg5GJDYZDjAzHG5BNvi/FfM1C9dOtjv2dAoGAF0t5KmwbjWHBhcVqO4Ic\r\n" +"BVvN3BIlc1ue2YRXEDlxY5b0r8N4XceMgKmW18OHApZxfl8uPDauWZLXOgl4uepv\r\n" +"whZC3EuWrSyyICNhLY21Ah7hbIEBPF3L3ZsOwC+UErL+dXWLdB56Jgy3gZaBeW7b\r\n" +"vDrEnocJbqCm7IukhXHOBK8CgYEAwqdHB0hqyNSzIOGY7v9abzB6pUdA3BZiQvEs\r\n" +"3LjHVd4HPJ2x0N8CgrBIWOE0q8+0hSMmeE96WW/7jD3fPWwCR5zlXknxBQsfv0gP\r\n" +"3BC5PR0Qdypz+d+9zfMf625kyit4T/hzwhDveZUzHnk1Cf+IG7Q+TOEnLnWAWBED\r\n" +"ISOWmrUCgYAFEmRxgwAc/u+D6t0syCwAYh6POtscq9Y0i9GyWk89NzgC4NdwwbBH\r\n" +"4AgahOxIxXx2gxJnq3yfkJfIjwf0s2DyP0kY2y6Ua1OeomPeY9mrIS4tCuDQ6LrE\r\n" +"TB6l9VGoxJL4fyHnZb8L5gGvnB1bbD8cL6YPaDiOhcRseC9vBiEuVg==\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; +const size_t mbedtls_test_srv_key_rsa_len = sizeof( mbedtls_test_srv_key_rsa ); + +/* tests/data_files/cli-rsa-sha256.crt */ +const char mbedtls_test_cli_crt_rsa[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDPzCCAiegAwIBAgIBBDANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" +"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA8MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UECgwIUG9sYXJTU0wxGjAYBgNVBAMMEVBvbGFyU1NMIENsaWVudCAyMIIBIjAN\r\n" +"BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6f\r\n" +"M60Nj4o8VmXl3ETZzGaFB9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu\r\n" +"1C93KYRhTYJQj6eVSHD1bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEw\r\n" +"MjDV0/YI0FZPRo7yX/k9Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v\r\n" +"4Jv4EFbMs44TFeY0BGbH7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx/\r\n" +"/DZrtenNLQNiTrM9AM+vdqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQAB\r\n" +"o00wSzAJBgNVHRMEAjAAMB0GA1UdDgQWBBRxoQBzckAvVHZeM/xSj7zx3WtGITAf\r\n" +"BgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zANBgkqhkiG9w0BAQsFAAOC\r\n" +"AQEAlHabem2Tu69VUN7EipwnQn1dIHdgvT5i+iQHpSxY1crPnBbAeSdAXwsVEqLQ\r\n" +"gOOIAQD5VIITNuoGgo4i+4OpNh9u7ZkpRHla+/swsfrFWRRbBNP5Bcu74AGLstwU\r\n" +"zM8gIkBiyfM1Q1qDQISV9trlCG6O8vh8dp/rbI3rfzo99BOHXgFCrzXjCuW4vDsF\r\n" +"r+Dao26bX3sJ6UnEWg1H3o2x6PpUcvQ36h71/bz4TEbbUUEpe02V4QWuL+wrhHJL\r\n" +"U7o3SVE3Og7jPF8sat0a50YUWhwEFI256m02KAXLg89ueUyYKEr6rNwhcvXJpvU9\r\n" +"giIVvd0Sbjjnn7NC4VDbcXV8vw==\r\n" +"-----END CERTIFICATE-----\r\n"; +const size_t mbedtls_test_cli_crt_rsa_len = sizeof( mbedtls_test_cli_crt_rsa ); + +/* tests/data_files/cli-rsa.key */ +const char mbedtls_test_cli_key_rsa[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"MIIEpAIBAAKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6fM60Nj4o8VmXl3ETZzGaF\r\n" +"B9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu1C93KYRhTYJQj6eVSHD1\r\n" +"bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEwMjDV0/YI0FZPRo7yX/k9\r\n" +"Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v4Jv4EFbMs44TFeY0BGbH\r\n" +"7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx//DZrtenNLQNiTrM9AM+v\r\n" +"dqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQABAoIBAGdNtfYDiap6bzst\r\n" +"yhCiI8m9TtrhZw4MisaEaN/ll3XSjaOG2dvV6xMZCMV+5TeXDHOAZnY18Yi18vzz\r\n" +"4Ut2TnNFzizCECYNaA2fST3WgInnxUkV3YXAyP6CNxJaCmv2aA0yFr2kFVSeaKGt\r\n" +"ymvljNp2NVkvm7Th8fBQBO7I7AXhz43k0mR7XmPgewe8ApZOG3hstkOaMvbWAvWA\r\n" +"zCZupdDjZYjOJqlA4eEA4H8/w7F83r5CugeBE8LgEREjLPiyejrU5H1fubEY+h0d\r\n" +"l5HZBJ68ybTXfQ5U9o/QKA3dd0toBEhhdRUDGzWtjvwkEQfqF1reGWj/tod/gCpf\r\n" +"DFi6X0ECgYEA4wOv/pjSC3ty6TuOvKX2rOUiBrLXXv2JSxZnMoMiWI5ipLQt+RYT\r\n" +"VPafL/m7Dn6MbwjayOkcZhBwk5CNz5A6Q4lJ64Mq/lqHznRCQQ2Mc1G8eyDF/fYL\r\n" +"Ze2pLvwP9VD5jTc2miDfw+MnvJhywRRLcemDFP8k4hQVtm8PMp3ZmNECgYEA4gz7\r\n" +"wzObR4gn8ibe617uQPZjWzUj9dUHYd+in1gwBCIrtNnaRn9I9U/Q6tegRYpii4ys\r\n" +"c176NmU+umy6XmuSKV5qD9bSpZWG2nLFnslrN15Lm3fhZxoeMNhBaEDTnLT26yoi\r\n" +"33gp0mSSWy94ZEqipms+ULF6sY1ZtFW6tpGFoy8CgYAQHhnnvJflIs2ky4q10B60\r\n" +"ZcxFp3rtDpkp0JxhFLhiizFrujMtZSjYNm5U7KkgPVHhLELEUvCmOnKTt4ap/vZ0\r\n" +"BxJNe1GZH3pW6SAvGDQpl9sG7uu/vTFP+lCxukmzxB0DrrDcvorEkKMom7ZCCRvW\r\n" +"KZsZ6YeH2Z81BauRj218kQKBgQCUV/DgKP2985xDTT79N08jUo3hTP5MVYCCuj/+\r\n" +"UeEw1TvZcx3LJby7P6Xad6a1/BqveaGyFKIfEFIaBUBItk801sDDpDaYc4gL00Xc\r\n" +"7lFuBHOZkxJYlss5QrGpuOEl9ZwUt5IrFLBdYaKqNHzNVC1pCPfb/JyH6Dr2HUxq\r\n" +"gxUwAQKBgQCcU6G2L8AG9d9c0UpOyL1tMvFe5Ttw0KjlQVdsh1MP6yigYo9DYuwu\r\n" +"bHFVW2r0dBTqegP2/KTOxKzaHfC1qf0RGDsUoJCNJrd1cwoCLG8P2EF4w3OBrKqv\r\n" +"8u4ytY0F+Vlanj5lm3TaoHSVF1+NWPyOTiwevIECGKwSxvlki4fDAA==\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; +const size_t mbedtls_test_cli_key_rsa_len = sizeof( mbedtls_test_cli_key_rsa ); +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_PEM_PARSE_C) +/* Concatenation of all available CA certificates */ +const char mbedtls_test_cas_pem[] = +#ifdef TEST_CA_CRT_RSA_SHA1 + TEST_CA_CRT_RSA_SHA1 +#endif +#ifdef TEST_CA_CRT_RSA_SHA256 + TEST_CA_CRT_RSA_SHA256 +#endif +#ifdef TEST_CA_CRT_EC + TEST_CA_CRT_EC +#endif + ""; +const size_t mbedtls_test_cas_pem_len = sizeof( mbedtls_test_cas_pem ); +#endif + +/* List of all available CA certificates */ +const char * mbedtls_test_cas[] = { +#if defined(TEST_CA_CRT_RSA_SHA1) + mbedtls_test_ca_crt_rsa_sha1, +#endif +#if defined(TEST_CA_CRT_RSA_SHA256) + mbedtls_test_ca_crt_rsa_sha256, +#endif +#if defined(MBEDTLS_ECDSA_C) + mbedtls_test_ca_crt_ec, +#endif + NULL +}; +const size_t mbedtls_test_cas_len[] = { +#if defined(TEST_CA_CRT_RSA_SHA1) + sizeof( mbedtls_test_ca_crt_rsa_sha1 ), +#endif +#if defined(TEST_CA_CRT_RSA_SHA256) + sizeof( mbedtls_test_ca_crt_rsa_sha256 ), +#endif +#if defined(MBEDTLS_ECDSA_C) + sizeof( mbedtls_test_ca_crt_ec ), +#endif + 0 +}; + +#if defined(MBEDTLS_RSA_C) +const char *mbedtls_test_ca_crt = mbedtls_test_ca_crt_rsa; /* SHA1 or SHA256 */ +const char *mbedtls_test_ca_key = mbedtls_test_ca_key_rsa; +const char *mbedtls_test_ca_pwd = mbedtls_test_ca_pwd_rsa; +const char *mbedtls_test_srv_crt = mbedtls_test_srv_crt_rsa; +const char *mbedtls_test_srv_key = mbedtls_test_srv_key_rsa; +const char *mbedtls_test_cli_crt = mbedtls_test_cli_crt_rsa; +const char *mbedtls_test_cli_key = mbedtls_test_cli_key_rsa; +const size_t mbedtls_test_ca_crt_len = sizeof( mbedtls_test_ca_crt_rsa ); +const size_t mbedtls_test_ca_key_len = sizeof( mbedtls_test_ca_key_rsa ); +const size_t mbedtls_test_ca_pwd_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1; +const size_t mbedtls_test_srv_crt_len = sizeof( mbedtls_test_srv_crt_rsa ); +const size_t mbedtls_test_srv_key_len = sizeof( mbedtls_test_srv_key_rsa ); +const size_t mbedtls_test_cli_crt_len = sizeof( mbedtls_test_cli_crt_rsa ); +const size_t mbedtls_test_cli_key_len = sizeof( mbedtls_test_cli_key_rsa ); +#else /* ! MBEDTLS_RSA_C, so MBEDTLS_ECDSA_C */ +const char *mbedtls_test_ca_crt = mbedtls_test_ca_crt_ec; +const char *mbedtls_test_ca_key = mbedtls_test_ca_key_ec; +const char *mbedtls_test_ca_pwd = mbedtls_test_ca_pwd_ec; +const char *mbedtls_test_srv_crt = mbedtls_test_srv_crt_ec; +const char *mbedtls_test_srv_key = mbedtls_test_srv_key_ec; +const char *mbedtls_test_cli_crt = mbedtls_test_cli_crt_ec; +const char *mbedtls_test_cli_key = mbedtls_test_cli_key_ec; +const size_t mbedtls_test_ca_crt_len = sizeof( mbedtls_test_ca_crt_ec ); +const size_t mbedtls_test_ca_key_len = sizeof( mbedtls_test_ca_key_ec ); +const size_t mbedtls_test_ca_pwd_len = sizeof( mbedtls_test_ca_pwd_ec ) - 1; +const size_t mbedtls_test_srv_crt_len = sizeof( mbedtls_test_srv_crt_ec ); +const size_t mbedtls_test_srv_key_len = sizeof( mbedtls_test_srv_key_ec ); +const size_t mbedtls_test_cli_crt_len = sizeof( mbedtls_test_cli_crt_ec ); +const size_t mbedtls_test_cli_key_len = sizeof( mbedtls_test_cli_key_ec ); +#endif /* MBEDTLS_RSA_C */ + +#endif /* MBEDTLS_CERTS_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/chacha20.c b/FreeRTOS-Labs/Source/mbedtls/library/chacha20.c new file mode 100644 index 000000000..830ec22b8 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/chacha20.c @@ -0,0 +1,570 @@ +/** + * \file chacha20.c + * + * \brief ChaCha20 cipher. + * + * \author Daniel King + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CHACHA20_C) + +#include "mbedtls/chacha20.h" +#include "mbedtls/platform_util.h" + +#include +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_CHACHA20_ALT) + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* Parameter validation macros */ +#define CHACHA20_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA ) +#define CHACHA20_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#define BYTES_TO_U32_LE( data, offset ) \ + ( (uint32_t) (data)[offset] \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 1] << 8 ) \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 2] << 16 ) \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 3] << 24 ) \ + ) + +#define ROTL32( value, amount ) \ + ( (uint32_t) ( (value) << (amount) ) | ( (value) >> ( 32 - (amount) ) ) ) + +#define CHACHA20_CTR_INDEX ( 12U ) + +#define CHACHA20_BLOCK_SIZE_BYTES ( 4U * 16U ) + +/** + * \brief ChaCha20 quarter round operation. + * + * The quarter round is defined as follows (from RFC 7539): + * 1. a += b; d ^= a; d <<<= 16; + * 2. c += d; b ^= c; b <<<= 12; + * 3. a += b; d ^= a; d <<<= 8; + * 4. c += d; b ^= c; b <<<= 7; + * + * \param state ChaCha20 state to modify. + * \param a The index of 'a' in the state. + * \param b The index of 'b' in the state. + * \param c The index of 'c' in the state. + * \param d The index of 'd' in the state. + */ +static inline void chacha20_quarter_round( uint32_t state[16], + size_t a, + size_t b, + size_t c, + size_t d ) +{ + /* a += b; d ^= a; d <<<= 16; */ + state[a] += state[b]; + state[d] ^= state[a]; + state[d] = ROTL32( state[d], 16 ); + + /* c += d; b ^= c; b <<<= 12 */ + state[c] += state[d]; + state[b] ^= state[c]; + state[b] = ROTL32( state[b], 12 ); + + /* a += b; d ^= a; d <<<= 8; */ + state[a] += state[b]; + state[d] ^= state[a]; + state[d] = ROTL32( state[d], 8 ); + + /* c += d; b ^= c; b <<<= 7; */ + state[c] += state[d]; + state[b] ^= state[c]; + state[b] = ROTL32( state[b], 7 ); +} + +/** + * \brief Perform the ChaCha20 inner block operation. + * + * This function performs two rounds: the column round and the + * diagonal round. + * + * \param state The ChaCha20 state to update. + */ +static void chacha20_inner_block( uint32_t state[16] ) +{ + chacha20_quarter_round( state, 0, 4, 8, 12 ); + chacha20_quarter_round( state, 1, 5, 9, 13 ); + chacha20_quarter_round( state, 2, 6, 10, 14 ); + chacha20_quarter_round( state, 3, 7, 11, 15 ); + + chacha20_quarter_round( state, 0, 5, 10, 15 ); + chacha20_quarter_round( state, 1, 6, 11, 12 ); + chacha20_quarter_round( state, 2, 7, 8, 13 ); + chacha20_quarter_round( state, 3, 4, 9, 14 ); +} + +/** + * \brief Generates a keystream block. + * + * \param initial_state The initial ChaCha20 state (key, nonce, counter). + * \param keystream Generated keystream bytes are written to this buffer. + */ +static void chacha20_block( const uint32_t initial_state[16], + unsigned char keystream[64] ) +{ + uint32_t working_state[16]; + size_t i; + + memcpy( working_state, + initial_state, + CHACHA20_BLOCK_SIZE_BYTES ); + + for( i = 0U; i < 10U; i++ ) + chacha20_inner_block( working_state ); + + working_state[ 0] += initial_state[ 0]; + working_state[ 1] += initial_state[ 1]; + working_state[ 2] += initial_state[ 2]; + working_state[ 3] += initial_state[ 3]; + working_state[ 4] += initial_state[ 4]; + working_state[ 5] += initial_state[ 5]; + working_state[ 6] += initial_state[ 6]; + working_state[ 7] += initial_state[ 7]; + working_state[ 8] += initial_state[ 8]; + working_state[ 9] += initial_state[ 9]; + working_state[10] += initial_state[10]; + working_state[11] += initial_state[11]; + working_state[12] += initial_state[12]; + working_state[13] += initial_state[13]; + working_state[14] += initial_state[14]; + working_state[15] += initial_state[15]; + + for( i = 0U; i < 16; i++ ) + { + size_t offset = i * 4U; + + keystream[offset ] = (unsigned char)( working_state[i] ); + keystream[offset + 1U] = (unsigned char)( working_state[i] >> 8 ); + keystream[offset + 2U] = (unsigned char)( working_state[i] >> 16 ); + keystream[offset + 3U] = (unsigned char)( working_state[i] >> 24 ); + } + + mbedtls_platform_zeroize( working_state, sizeof( working_state ) ); +} + +void mbedtls_chacha20_init( mbedtls_chacha20_context *ctx ) +{ + CHACHA20_VALIDATE( ctx != NULL ); + + mbedtls_platform_zeroize( ctx->state, sizeof( ctx->state ) ); + mbedtls_platform_zeroize( ctx->keystream8, sizeof( ctx->keystream8 ) ); + + /* Initially, there's no keystream bytes available */ + ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES; +} + +void mbedtls_chacha20_free( mbedtls_chacha20_context *ctx ) +{ + if( ctx != NULL ) + { + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_chacha20_context ) ); + } +} + +int mbedtls_chacha20_setkey( mbedtls_chacha20_context *ctx, + const unsigned char key[32] ) +{ + CHACHA20_VALIDATE_RET( ctx != NULL ); + CHACHA20_VALIDATE_RET( key != NULL ); + + /* ChaCha20 constants - the string "expand 32-byte k" */ + ctx->state[0] = 0x61707865; + ctx->state[1] = 0x3320646e; + ctx->state[2] = 0x79622d32; + ctx->state[3] = 0x6b206574; + + /* Set key */ + ctx->state[4] = BYTES_TO_U32_LE( key, 0 ); + ctx->state[5] = BYTES_TO_U32_LE( key, 4 ); + ctx->state[6] = BYTES_TO_U32_LE( key, 8 ); + ctx->state[7] = BYTES_TO_U32_LE( key, 12 ); + ctx->state[8] = BYTES_TO_U32_LE( key, 16 ); + ctx->state[9] = BYTES_TO_U32_LE( key, 20 ); + ctx->state[10] = BYTES_TO_U32_LE( key, 24 ); + ctx->state[11] = BYTES_TO_U32_LE( key, 28 ); + + return( 0 ); +} + +int mbedtls_chacha20_starts( mbedtls_chacha20_context* ctx, + const unsigned char nonce[12], + uint32_t counter ) +{ + CHACHA20_VALIDATE_RET( ctx != NULL ); + CHACHA20_VALIDATE_RET( nonce != NULL ); + + /* Counter */ + ctx->state[12] = counter; + + /* Nonce */ + ctx->state[13] = BYTES_TO_U32_LE( nonce, 0 ); + ctx->state[14] = BYTES_TO_U32_LE( nonce, 4 ); + ctx->state[15] = BYTES_TO_U32_LE( nonce, 8 ); + + mbedtls_platform_zeroize( ctx->keystream8, sizeof( ctx->keystream8 ) ); + + /* Initially, there's no keystream bytes available */ + ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES; + + return( 0 ); +} + +int mbedtls_chacha20_update( mbedtls_chacha20_context *ctx, + size_t size, + const unsigned char *input, + unsigned char *output ) +{ + size_t offset = 0U; + size_t i; + + CHACHA20_VALIDATE_RET( ctx != NULL ); + CHACHA20_VALIDATE_RET( size == 0 || input != NULL ); + CHACHA20_VALIDATE_RET( size == 0 || output != NULL ); + + /* Use leftover keystream bytes, if available */ + while( size > 0U && ctx->keystream_bytes_used < CHACHA20_BLOCK_SIZE_BYTES ) + { + output[offset] = input[offset] + ^ ctx->keystream8[ctx->keystream_bytes_used]; + + ctx->keystream_bytes_used++; + offset++; + size--; + } + + /* Process full blocks */ + while( size >= CHACHA20_BLOCK_SIZE_BYTES ) + { + /* Generate new keystream block and increment counter */ + chacha20_block( ctx->state, ctx->keystream8 ); + ctx->state[CHACHA20_CTR_INDEX]++; + + for( i = 0U; i < 64U; i += 8U ) + { + output[offset + i ] = input[offset + i ] ^ ctx->keystream8[i ]; + output[offset + i+1] = input[offset + i+1] ^ ctx->keystream8[i+1]; + output[offset + i+2] = input[offset + i+2] ^ ctx->keystream8[i+2]; + output[offset + i+3] = input[offset + i+3] ^ ctx->keystream8[i+3]; + output[offset + i+4] = input[offset + i+4] ^ ctx->keystream8[i+4]; + output[offset + i+5] = input[offset + i+5] ^ ctx->keystream8[i+5]; + output[offset + i+6] = input[offset + i+6] ^ ctx->keystream8[i+6]; + output[offset + i+7] = input[offset + i+7] ^ ctx->keystream8[i+7]; + } + + offset += CHACHA20_BLOCK_SIZE_BYTES; + size -= CHACHA20_BLOCK_SIZE_BYTES; + } + + /* Last (partial) block */ + if( size > 0U ) + { + /* Generate new keystream block and increment counter */ + chacha20_block( ctx->state, ctx->keystream8 ); + ctx->state[CHACHA20_CTR_INDEX]++; + + for( i = 0U; i < size; i++) + { + output[offset + i] = input[offset + i] ^ ctx->keystream8[i]; + } + + ctx->keystream_bytes_used = size; + + } + + return( 0 ); +} + +int mbedtls_chacha20_crypt( const unsigned char key[32], + const unsigned char nonce[12], + uint32_t counter, + size_t data_len, + const unsigned char* input, + unsigned char* output ) +{ + mbedtls_chacha20_context ctx; + int ret; + + CHACHA20_VALIDATE_RET( key != NULL ); + CHACHA20_VALIDATE_RET( nonce != NULL ); + CHACHA20_VALIDATE_RET( data_len == 0 || input != NULL ); + CHACHA20_VALIDATE_RET( data_len == 0 || output != NULL ); + + mbedtls_chacha20_init( &ctx ); + + ret = mbedtls_chacha20_setkey( &ctx, key ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chacha20_starts( &ctx, nonce, counter ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chacha20_update( &ctx, data_len, input, output ); + +cleanup: + mbedtls_chacha20_free( &ctx ); + return( ret ); +} + +#endif /* !MBEDTLS_CHACHA20_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char test_keys[2][32] = +{ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 + } +}; + +static const unsigned char test_nonces[2][12] = +{ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02 + } +}; + +static const uint32_t test_counters[2] = +{ + 0U, + 1U +}; + +static const unsigned char test_input[2][375] = +{ + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }, + { + 0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d, + 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, + 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45, + 0x54, 0x46, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, + 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x20, 0x66, + 0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, + 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72, + 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, + 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20, + 0x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, + 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49, + 0x45, 0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69, + 0x76, 0x69, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20, + 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, + 0x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49, + 0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x2e, 0x20, 0x53, 0x75, 0x63, 0x68, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45, + 0x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20, + 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63, + 0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63, + 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61, + 0x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e, + 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f, + 0x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2c, + 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61, + 0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f + } +}; + +static const unsigned char test_output[2][375] = +{ + { + 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, + 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28, + 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, + 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7, + 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d, + 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37, + 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c, + 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86 + }, + { + 0xa3, 0xfb, 0xf0, 0x7d, 0xf3, 0xfa, 0x2f, 0xde, + 0x4f, 0x37, 0x6c, 0xa2, 0x3e, 0x82, 0x73, 0x70, + 0x41, 0x60, 0x5d, 0x9f, 0x4f, 0x4f, 0x57, 0xbd, + 0x8c, 0xff, 0x2c, 0x1d, 0x4b, 0x79, 0x55, 0xec, + 0x2a, 0x97, 0x94, 0x8b, 0xd3, 0x72, 0x29, 0x15, + 0xc8, 0xf3, 0xd3, 0x37, 0xf7, 0xd3, 0x70, 0x05, + 0x0e, 0x9e, 0x96, 0xd6, 0x47, 0xb7, 0xc3, 0x9f, + 0x56, 0xe0, 0x31, 0xca, 0x5e, 0xb6, 0x25, 0x0d, + 0x40, 0x42, 0xe0, 0x27, 0x85, 0xec, 0xec, 0xfa, + 0x4b, 0x4b, 0xb5, 0xe8, 0xea, 0xd0, 0x44, 0x0e, + 0x20, 0xb6, 0xe8, 0xdb, 0x09, 0xd8, 0x81, 0xa7, + 0xc6, 0x13, 0x2f, 0x42, 0x0e, 0x52, 0x79, 0x50, + 0x42, 0xbd, 0xfa, 0x77, 0x73, 0xd8, 0xa9, 0x05, + 0x14, 0x47, 0xb3, 0x29, 0x1c, 0xe1, 0x41, 0x1c, + 0x68, 0x04, 0x65, 0x55, 0x2a, 0xa6, 0xc4, 0x05, + 0xb7, 0x76, 0x4d, 0x5e, 0x87, 0xbe, 0xa8, 0x5a, + 0xd0, 0x0f, 0x84, 0x49, 0xed, 0x8f, 0x72, 0xd0, + 0xd6, 0x62, 0xab, 0x05, 0x26, 0x91, 0xca, 0x66, + 0x42, 0x4b, 0xc8, 0x6d, 0x2d, 0xf8, 0x0e, 0xa4, + 0x1f, 0x43, 0xab, 0xf9, 0x37, 0xd3, 0x25, 0x9d, + 0xc4, 0xb2, 0xd0, 0xdf, 0xb4, 0x8a, 0x6c, 0x91, + 0x39, 0xdd, 0xd7, 0xf7, 0x69, 0x66, 0xe9, 0x28, + 0xe6, 0x35, 0x55, 0x3b, 0xa7, 0x6c, 0x5c, 0x87, + 0x9d, 0x7b, 0x35, 0xd4, 0x9e, 0xb2, 0xe6, 0x2b, + 0x08, 0x71, 0xcd, 0xac, 0x63, 0x89, 0x39, 0xe2, + 0x5e, 0x8a, 0x1e, 0x0e, 0xf9, 0xd5, 0x28, 0x0f, + 0xa8, 0xca, 0x32, 0x8b, 0x35, 0x1c, 0x3c, 0x76, + 0x59, 0x89, 0xcb, 0xcf, 0x3d, 0xaa, 0x8b, 0x6c, + 0xcc, 0x3a, 0xaf, 0x9f, 0x39, 0x79, 0xc9, 0x2b, + 0x37, 0x20, 0xfc, 0x88, 0xdc, 0x95, 0xed, 0x84, + 0xa1, 0xbe, 0x05, 0x9c, 0x64, 0x99, 0xb9, 0xfd, + 0xa2, 0x36, 0xe7, 0xe8, 0x18, 0xb0, 0x4b, 0x0b, + 0xc3, 0x9c, 0x1e, 0x87, 0x6b, 0x19, 0x3b, 0xfe, + 0x55, 0x69, 0x75, 0x3f, 0x88, 0x12, 0x8c, 0xc0, + 0x8a, 0xaa, 0x9b, 0x63, 0xd1, 0xa1, 0x6f, 0x80, + 0xef, 0x25, 0x54, 0xd7, 0x18, 0x9c, 0x41, 0x1f, + 0x58, 0x69, 0xca, 0x52, 0xc5, 0xb8, 0x3f, 0xa3, + 0x6f, 0xf2, 0x16, 0xb9, 0xc1, 0xd3, 0x00, 0x62, + 0xbe, 0xbc, 0xfd, 0x2d, 0xc5, 0xbc, 0xe0, 0x91, + 0x19, 0x34, 0xfd, 0xa7, 0x9a, 0x86, 0xf6, 0xe6, + 0x98, 0xce, 0xd7, 0x59, 0xc3, 0xff, 0x9b, 0x64, + 0x77, 0x33, 0x8f, 0x3d, 0xa4, 0xf9, 0xcd, 0x85, + 0x14, 0xea, 0x99, 0x82, 0xcc, 0xaf, 0xb3, 0x41, + 0xb2, 0x38, 0x4d, 0xd9, 0x02, 0xf3, 0xd1, 0xab, + 0x7a, 0xc6, 0x1d, 0xd2, 0x9c, 0x6f, 0x21, 0xba, + 0x5b, 0x86, 0x2f, 0x37, 0x30, 0xe3, 0x7c, 0xfd, + 0xc4, 0xfd, 0x80, 0x6c, 0x22, 0xf2, 0x21 + } +}; + +static const size_t test_lengths[2] = +{ + 64U, + 375U +}; + +#define ASSERT( cond, args ) \ + do \ + { \ + if( ! ( cond ) ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf args; \ + \ + return( -1 ); \ + } \ + } \ + while( 0 ) + +int mbedtls_chacha20_self_test( int verbose ) +{ + unsigned char output[381]; + unsigned i; + int ret; + + for( i = 0U; i < 2U; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " ChaCha20 test %u ", i ); + + ret = mbedtls_chacha20_crypt( test_keys[i], + test_nonces[i], + test_counters[i], + test_lengths[i], + test_input[i], + output ); + + ASSERT( 0 == ret, ( "error code: %i\n", ret ) ); + + ASSERT( 0 == memcmp( output, test_output[i], test_lengths[i] ), + ( "failed (output)\n" ) ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* !MBEDTLS_CHACHA20_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/chachapoly.c b/FreeRTOS-Labs/Source/mbedtls/library/chachapoly.c new file mode 100644 index 000000000..716fc6c93 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/chachapoly.c @@ -0,0 +1,540 @@ +/** + * \file chachapoly.c + * + * \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539. + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + +#include "mbedtls/chachapoly.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_CHACHAPOLY_ALT) + +/* Parameter validation macros */ +#define CHACHAPOLY_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA ) +#define CHACHAPOLY_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#define CHACHAPOLY_STATE_INIT ( 0 ) +#define CHACHAPOLY_STATE_AAD ( 1 ) +#define CHACHAPOLY_STATE_CIPHERTEXT ( 2 ) /* Encrypting or decrypting */ +#define CHACHAPOLY_STATE_FINISHED ( 3 ) + +/** + * \brief Adds nul bytes to pad the AAD for Poly1305. + * + * \param ctx The ChaCha20-Poly1305 context. + */ +static int chachapoly_pad_aad( mbedtls_chachapoly_context *ctx ) +{ + uint32_t partial_block_len = (uint32_t) ( ctx->aad_len % 16U ); + unsigned char zeroes[15]; + + if( partial_block_len == 0U ) + return( 0 ); + + memset( zeroes, 0, sizeof( zeroes ) ); + + return( mbedtls_poly1305_update( &ctx->poly1305_ctx, + zeroes, + 16U - partial_block_len ) ); +} + +/** + * \brief Adds nul bytes to pad the ciphertext for Poly1305. + * + * \param ctx The ChaCha20-Poly1305 context. + */ +static int chachapoly_pad_ciphertext( mbedtls_chachapoly_context *ctx ) +{ + uint32_t partial_block_len = (uint32_t) ( ctx->ciphertext_len % 16U ); + unsigned char zeroes[15]; + + if( partial_block_len == 0U ) + return( 0 ); + + memset( zeroes, 0, sizeof( zeroes ) ); + return( mbedtls_poly1305_update( &ctx->poly1305_ctx, + zeroes, + 16U - partial_block_len ) ); +} + +void mbedtls_chachapoly_init( mbedtls_chachapoly_context *ctx ) +{ + CHACHAPOLY_VALIDATE( ctx != NULL ); + + mbedtls_chacha20_init( &ctx->chacha20_ctx ); + mbedtls_poly1305_init( &ctx->poly1305_ctx ); + ctx->aad_len = 0U; + ctx->ciphertext_len = 0U; + ctx->state = CHACHAPOLY_STATE_INIT; + ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT; +} + +void mbedtls_chachapoly_free( mbedtls_chachapoly_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_chacha20_free( &ctx->chacha20_ctx ); + mbedtls_poly1305_free( &ctx->poly1305_ctx ); + ctx->aad_len = 0U; + ctx->ciphertext_len = 0U; + ctx->state = CHACHAPOLY_STATE_INIT; + ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT; +} + +int mbedtls_chachapoly_setkey( mbedtls_chachapoly_context *ctx, + const unsigned char key[32] ) +{ + int ret; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( key != NULL ); + + ret = mbedtls_chacha20_setkey( &ctx->chacha20_ctx, key ); + + return( ret ); +} + +int mbedtls_chachapoly_starts( mbedtls_chachapoly_context *ctx, + const unsigned char nonce[12], + mbedtls_chachapoly_mode_t mode ) +{ + int ret; + unsigned char poly1305_key[64]; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( nonce != NULL ); + + /* Set counter = 0, will be update to 1 when generating Poly1305 key */ + ret = mbedtls_chacha20_starts( &ctx->chacha20_ctx, nonce, 0U ); + if( ret != 0 ) + goto cleanup; + + /* Generate the Poly1305 key by getting the ChaCha20 keystream output with + * counter = 0. This is the same as encrypting a buffer of zeroes. + * Only the first 256-bits (32 bytes) of the key is used for Poly1305. + * The other 256 bits are discarded. + */ + memset( poly1305_key, 0, sizeof( poly1305_key ) ); + ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, sizeof( poly1305_key ), + poly1305_key, poly1305_key ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_poly1305_starts( &ctx->poly1305_ctx, poly1305_key ); + + if( ret == 0 ) + { + ctx->aad_len = 0U; + ctx->ciphertext_len = 0U; + ctx->state = CHACHAPOLY_STATE_AAD; + ctx->mode = mode; + } + +cleanup: + mbedtls_platform_zeroize( poly1305_key, 64U ); + return( ret ); +} + +int mbedtls_chachapoly_update_aad( mbedtls_chachapoly_context *ctx, + const unsigned char *aad, + size_t aad_len ) +{ + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL ); + + if( ctx->state != CHACHAPOLY_STATE_AAD ) + return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE ); + + ctx->aad_len += aad_len; + + return( mbedtls_poly1305_update( &ctx->poly1305_ctx, aad, aad_len ) ); +} + +int mbedtls_chachapoly_update( mbedtls_chachapoly_context *ctx, + size_t len, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( len == 0 || input != NULL ); + CHACHAPOLY_VALIDATE_RET( len == 0 || output != NULL ); + + if( ( ctx->state != CHACHAPOLY_STATE_AAD ) && + ( ctx->state != CHACHAPOLY_STATE_CIPHERTEXT ) ) + { + return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE ); + } + + if( ctx->state == CHACHAPOLY_STATE_AAD ) + { + ctx->state = CHACHAPOLY_STATE_CIPHERTEXT; + + ret = chachapoly_pad_aad( ctx ); + if( ret != 0 ) + return( ret ); + } + + ctx->ciphertext_len += len; + + if( ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT ) + { + ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, output, len ); + if( ret != 0 ) + return( ret ); + } + else /* DECRYPT */ + { + ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, input, len ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output ); + if( ret != 0 ) + return( ret ); + } + + return( 0 ); +} + +int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx, + unsigned char mac[16] ) +{ + int ret; + unsigned char len_block[16]; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( mac != NULL ); + + if( ctx->state == CHACHAPOLY_STATE_INIT ) + { + return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE ); + } + + if( ctx->state == CHACHAPOLY_STATE_AAD ) + { + ret = chachapoly_pad_aad( ctx ); + if( ret != 0 ) + return( ret ); + } + else if( ctx->state == CHACHAPOLY_STATE_CIPHERTEXT ) + { + ret = chachapoly_pad_ciphertext( ctx ); + if( ret != 0 ) + return( ret ); + } + + ctx->state = CHACHAPOLY_STATE_FINISHED; + + /* The lengths of the AAD and ciphertext are processed by + * Poly1305 as the final 128-bit block, encoded as little-endian integers. + */ + len_block[ 0] = (unsigned char)( ctx->aad_len ); + len_block[ 1] = (unsigned char)( ctx->aad_len >> 8 ); + len_block[ 2] = (unsigned char)( ctx->aad_len >> 16 ); + len_block[ 3] = (unsigned char)( ctx->aad_len >> 24 ); + len_block[ 4] = (unsigned char)( ctx->aad_len >> 32 ); + len_block[ 5] = (unsigned char)( ctx->aad_len >> 40 ); + len_block[ 6] = (unsigned char)( ctx->aad_len >> 48 ); + len_block[ 7] = (unsigned char)( ctx->aad_len >> 56 ); + len_block[ 8] = (unsigned char)( ctx->ciphertext_len ); + len_block[ 9] = (unsigned char)( ctx->ciphertext_len >> 8 ); + len_block[10] = (unsigned char)( ctx->ciphertext_len >> 16 ); + len_block[11] = (unsigned char)( ctx->ciphertext_len >> 24 ); + len_block[12] = (unsigned char)( ctx->ciphertext_len >> 32 ); + len_block[13] = (unsigned char)( ctx->ciphertext_len >> 40 ); + len_block[14] = (unsigned char)( ctx->ciphertext_len >> 48 ); + len_block[15] = (unsigned char)( ctx->ciphertext_len >> 56 ); + + ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, len_block, 16U ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_poly1305_finish( &ctx->poly1305_ctx, mac ); + + return( ret ); +} + +static int chachapoly_crypt_and_tag( mbedtls_chachapoly_context *ctx, + mbedtls_chachapoly_mode_t mode, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char *input, + unsigned char *output, + unsigned char tag[16] ) +{ + int ret; + + ret = mbedtls_chachapoly_starts( ctx, nonce, mode ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chachapoly_update_aad( ctx, aad, aad_len ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chachapoly_update( ctx, length, input, output ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_chachapoly_finish( ctx, tag ); + +cleanup: + return( ret ); +} + +int mbedtls_chachapoly_encrypt_and_tag( mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char *input, + unsigned char *output, + unsigned char tag[16] ) +{ + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( nonce != NULL ); + CHACHAPOLY_VALIDATE_RET( tag != NULL ); + CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL ); + CHACHAPOLY_VALIDATE_RET( length == 0 || input != NULL ); + CHACHAPOLY_VALIDATE_RET( length == 0 || output != NULL ); + + return( chachapoly_crypt_and_tag( ctx, MBEDTLS_CHACHAPOLY_ENCRYPT, + length, nonce, aad, aad_len, + input, output, tag ) ); +} + +int mbedtls_chachapoly_auth_decrypt( mbedtls_chachapoly_context *ctx, + size_t length, + const unsigned char nonce[12], + const unsigned char *aad, + size_t aad_len, + const unsigned char tag[16], + const unsigned char *input, + unsigned char *output ) +{ + int ret; + unsigned char check_tag[16]; + size_t i; + int diff; + CHACHAPOLY_VALIDATE_RET( ctx != NULL ); + CHACHAPOLY_VALIDATE_RET( nonce != NULL ); + CHACHAPOLY_VALIDATE_RET( tag != NULL ); + CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL ); + CHACHAPOLY_VALIDATE_RET( length == 0 || input != NULL ); + CHACHAPOLY_VALIDATE_RET( length == 0 || output != NULL ); + + if( ( ret = chachapoly_crypt_and_tag( ctx, + MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce, + aad, aad_len, input, output, check_tag ) ) != 0 ) + { + return( ret ); + } + + /* Check tag in "constant-time" */ + for( diff = 0, i = 0; i < sizeof( check_tag ); i++ ) + diff |= tag[i] ^ check_tag[i]; + + if( diff != 0 ) + { + mbedtls_platform_zeroize( output, length ); + return( MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED ); + } + + return( 0 ); +} + +#endif /* MBEDTLS_CHACHAPOLY_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char test_key[1][32] = +{ + { + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f + } +}; + +static const unsigned char test_nonce[1][12] = +{ + { + 0x07, 0x00, 0x00, 0x00, /* 32-bit common part */ + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 /* 64-bit IV */ + } +}; + +static const unsigned char test_aad[1][12] = +{ + { + 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7 + } +}; + +static const size_t test_aad_len[1] = +{ + 12U +}; + +static const unsigned char test_input[1][114] = +{ + { + 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, + 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, + 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, + 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, + 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, + 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, + 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, + 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, + 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, + 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, + 0x74, 0x2e + } +}; + +static const unsigned char test_output[1][114] = +{ + { + 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, + 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2, + 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, + 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, + 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12, + 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, + 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29, + 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36, + 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, + 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58, + 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94, + 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc, + 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d, + 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b, + 0x61, 0x16 + } +}; + +static const size_t test_input_len[1] = +{ + 114U +}; + +static const unsigned char test_mac[1][16] = +{ + { + 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, + 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91 + } +}; + +#define ASSERT( cond, args ) \ + do \ + { \ + if( ! ( cond ) ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf args; \ + \ + return( -1 ); \ + } \ + } \ + while( 0 ) + +int mbedtls_chachapoly_self_test( int verbose ) +{ + mbedtls_chachapoly_context ctx; + unsigned i; + int ret; + unsigned char output[200]; + unsigned char mac[16]; + + for( i = 0U; i < 1U; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " ChaCha20-Poly1305 test %u ", i ); + + mbedtls_chachapoly_init( &ctx ); + + ret = mbedtls_chachapoly_setkey( &ctx, test_key[i] ); + ASSERT( 0 == ret, ( "setkey() error code: %i\n", ret ) ); + + ret = mbedtls_chachapoly_encrypt_and_tag( &ctx, + test_input_len[i], + test_nonce[i], + test_aad[i], + test_aad_len[i], + test_input[i], + output, + mac ); + + ASSERT( 0 == ret, ( "crypt_and_tag() error code: %i\n", ret ) ); + + ASSERT( 0 == memcmp( output, test_output[i], test_input_len[i] ), + ( "failure (wrong output)\n" ) ); + + ASSERT( 0 == memcmp( mac, test_mac[i], 16U ), + ( "failure (wrong MAC)\n" ) ); + + mbedtls_chachapoly_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CHACHAPOLY_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/cipher.c b/FreeRTOS-Labs/Source/mbedtls/library/cipher.c new file mode 100644 index 000000000..ca8ab7287 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/cipher.c @@ -0,0 +1,1540 @@ +/** + * \file cipher.c + * + * \brief Generic cipher wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CIPHER_C) + +#include "mbedtls/cipher.h" +#include "mbedtls/cipher_internal.h" +#include "mbedtls/platform_util.h" + +#include +#include + +#if defined(MBEDTLS_CHACHAPOLY_C) +#include "mbedtls/chachapoly.h" +#endif + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/gcm.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/ccm.h" +#endif + +#if defined(MBEDTLS_CHACHA20_C) +#include "mbedtls/chacha20.h" +#endif + +#if defined(MBEDTLS_CMAC_C) +#include "mbedtls/cmac.h" +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "psa/crypto.h" +#include "mbedtls/psa_util.h" +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#if defined(MBEDTLS_NIST_KW_C) +#include "mbedtls/nist_kw.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#define CIPHER_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ) +#define CIPHER_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +/* Compare the contents of two buffers in constant time. + * Returns 0 if the contents are bitwise identical, otherwise returns + * a non-zero value. + * This is currently only used by GCM and ChaCha20+Poly1305. + */ +static int mbedtls_constant_time_memcmp( const void *v1, const void *v2, + size_t len ) +{ + const unsigned char *p1 = (const unsigned char*) v1; + const unsigned char *p2 = (const unsigned char*) v2; + size_t i; + unsigned char diff; + + for( diff = 0, i = 0; i < len; i++ ) + diff |= p1[i] ^ p2[i]; + + return( (int)diff ); +} +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ + +static int supported_init = 0; + +const int *mbedtls_cipher_list( void ) +{ + const mbedtls_cipher_definition_t *def; + int *type; + + if( ! supported_init ) + { + def = mbedtls_cipher_definitions; + type = mbedtls_cipher_supported; + + while( def->type != 0 ) + *type++ = (*def++).type; + + *type = 0; + + supported_init = 1; + } + + return( mbedtls_cipher_supported ); +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( + const mbedtls_cipher_type_t cipher_type ) +{ + const mbedtls_cipher_definition_t *def; + + for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) + if( def->type == cipher_type ) + return( def->info ); + + return( NULL ); +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( + const char *cipher_name ) +{ + const mbedtls_cipher_definition_t *def; + + if( NULL == cipher_name ) + return( NULL ); + + for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) + if( ! strcmp( def->info->name, cipher_name ) ) + return( def->info ); + + return( NULL ); +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( + const mbedtls_cipher_id_t cipher_id, + int key_bitlen, + const mbedtls_cipher_mode_t mode ) +{ + const mbedtls_cipher_definition_t *def; + + for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) + if( def->info->base->cipher == cipher_id && + def->info->key_bitlen == (unsigned) key_bitlen && + def->info->mode == mode ) + return( def->info ); + + return( NULL ); +} + +void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ) +{ + CIPHER_VALIDATE( ctx != NULL ); + memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); +} + +void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ) +{ + if( ctx == NULL ) + return; + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( ctx->psa_enabled == 1 ) + { + if( ctx->cipher_ctx != NULL ) + { + mbedtls_cipher_context_psa * const cipher_psa = + (mbedtls_cipher_context_psa *) ctx->cipher_ctx; + + if( cipher_psa->slot_state == MBEDTLS_CIPHER_PSA_KEY_OWNED ) + { + /* xxx_free() doesn't allow to return failures. */ + (void) psa_destroy_key( cipher_psa->slot ); + } + + mbedtls_platform_zeroize( cipher_psa, sizeof( *cipher_psa ) ); + mbedtls_free( cipher_psa ); + } + + mbedtls_platform_zeroize( ctx, sizeof(mbedtls_cipher_context_t) ); + return; + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#if defined(MBEDTLS_CMAC_C) + if( ctx->cmac_ctx ) + { + mbedtls_platform_zeroize( ctx->cmac_ctx, + sizeof( mbedtls_cmac_context_t ) ); + mbedtls_free( ctx->cmac_ctx ); + } +#endif + + if( ctx->cipher_ctx ) + ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx ); + + mbedtls_platform_zeroize( ctx, sizeof(mbedtls_cipher_context_t) ); +} + +int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, + const mbedtls_cipher_info_t *cipher_info ) +{ + CIPHER_VALIDATE_RET( ctx != NULL ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); + + if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) ) + return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED ); + + ctx->cipher_info = cipher_info; + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) + /* + * Ignore possible errors caused by a cipher mode that doesn't use padding + */ +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) + (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_PKCS7 ); +#else + (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_NONE ); +#endif +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + + return( 0 ); +} + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +int mbedtls_cipher_setup_psa( mbedtls_cipher_context_t *ctx, + const mbedtls_cipher_info_t *cipher_info, + size_t taglen ) +{ + psa_algorithm_t alg; + mbedtls_cipher_context_psa *cipher_psa; + + if( NULL == cipher_info || NULL == ctx ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + /* Check that the underlying cipher mode and cipher type are + * supported by the underlying PSA Crypto implementation. */ + alg = mbedtls_psa_translate_cipher_mode( cipher_info->mode, taglen ); + if( alg == 0 ) + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + if( mbedtls_psa_translate_cipher_type( cipher_info->type ) == 0 ) + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + + memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); + + cipher_psa = mbedtls_calloc( 1, sizeof(mbedtls_cipher_context_psa ) ); + if( cipher_psa == NULL ) + return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED ); + cipher_psa->alg = alg; + ctx->cipher_ctx = cipher_psa; + ctx->cipher_info = cipher_info; + ctx->psa_enabled = 1; + return( 0 ); +} +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, + const unsigned char *key, + int key_bitlen, + const mbedtls_operation_t operation ) +{ + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( key != NULL ); + CIPHER_VALIDATE_RET( operation == MBEDTLS_ENCRYPT || + operation == MBEDTLS_DECRYPT ); + if( ctx->cipher_info == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( ctx->psa_enabled == 1 ) + { + mbedtls_cipher_context_psa * const cipher_psa = + (mbedtls_cipher_context_psa *) ctx->cipher_ctx; + + size_t const key_bytelen = ( (size_t) key_bitlen + 7 ) / 8; + + psa_status_t status; + psa_key_type_t key_type; + psa_key_usage_t key_usage; + psa_key_policy_t key_policy; + + /* PSA Crypto API only accepts byte-aligned keys. */ + if( key_bitlen % 8 != 0 ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + /* Don't allow keys to be set multiple times. */ + if( cipher_psa->slot_state != MBEDTLS_CIPHER_PSA_KEY_UNSET ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + key_type = mbedtls_psa_translate_cipher_type( + ctx->cipher_info->type ); + if( key_type == 0 ) + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + + /* Allocate a key slot to use. */ + status = psa_allocate_key( &cipher_psa->slot ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED ); + + /* Indicate that we own the key slot and need to + * destroy it in mbedtls_cipher_free(). */ + cipher_psa->slot_state = MBEDTLS_CIPHER_PSA_KEY_OWNED; + + /* From that point on, the responsibility for destroying the + * key slot is on mbedtls_cipher_free(). This includes the case + * where the policy setup or key import below fail, as + * mbedtls_cipher_free() needs to be called in any case. */ + + /* Setup policy for the new key slot. */ + key_policy = psa_key_policy_init(); + + /* Mbed TLS' cipher layer doesn't enforce the mode of operation + * (encrypt vs. decrypt): it is possible to setup a key for encryption + * and use it for AEAD decryption. Until tests relying on this + * are changed, allow any usage in PSA. */ + /* key_usage = mbedtls_psa_translate_cipher_operation( operation ); */ + key_usage = PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT; + psa_key_policy_set_usage( &key_policy, key_usage, cipher_psa->alg ); + status = psa_set_key_policy( cipher_psa->slot, &key_policy ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED ); + + /* Populate new key slot. */ + status = psa_import_key( cipher_psa->slot, + key_type, key, key_bytelen ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED ); + + ctx->key_bitlen = key_bitlen; + ctx->operation = operation; + return( 0 ); + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ) == 0 && + (int) ctx->cipher_info->key_bitlen != key_bitlen ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + ctx->key_bitlen = key_bitlen; + ctx->operation = operation; + + /* + * For OFB, CFB and CTR mode always use the encryption key schedule + */ + if( MBEDTLS_ENCRYPT == operation || + MBEDTLS_MODE_CFB == ctx->cipher_info->mode || + MBEDTLS_MODE_OFB == ctx->cipher_info->mode || + MBEDTLS_MODE_CTR == ctx->cipher_info->mode ) + { + return( ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key, + ctx->key_bitlen ) ); + } + + if( MBEDTLS_DECRYPT == operation ) + return( ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key, + ctx->key_bitlen ) ); + + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); +} + +int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, + size_t iv_len ) +{ + size_t actual_iv_size; + + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL ); + if( ctx->cipher_info == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( ctx->psa_enabled == 1 ) + { + /* While PSA Crypto has an API for multipart + * operations, we currently don't make it + * accessible through the cipher layer. */ + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + /* avoid buffer overflow in ctx->iv */ + if( iv_len > MBEDTLS_MAX_IV_LENGTH ) + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + + if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_IV_LEN ) != 0 ) + actual_iv_size = iv_len; + else + { + actual_iv_size = ctx->cipher_info->iv_size; + + /* avoid reading past the end of input buffer */ + if( actual_iv_size > iv_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_CHACHA20_C) + if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20 ) + { + if ( 0 != mbedtls_chacha20_starts( (mbedtls_chacha20_context*)ctx->cipher_ctx, + iv, + 0U ) ) /* Initial counter value */ + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + } +#endif + + if ( actual_iv_size != 0 ) + { + memcpy( ctx->iv, iv, actual_iv_size ); + ctx->iv_size = actual_iv_size; + } + + return( 0 ); +} + +int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ) +{ + CIPHER_VALIDATE_RET( ctx != NULL ); + if( ctx->cipher_info == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( ctx->psa_enabled == 1 ) + { + /* We don't support resetting PSA-based + * cipher contexts, yet. */ + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + ctx->unprocessed_len = 0; + + return( 0 ); +} + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, + const unsigned char *ad, size_t ad_len ) +{ + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL ); + if( ctx->cipher_info == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( ctx->psa_enabled == 1 ) + { + /* While PSA Crypto has an API for multipart + * operations, we currently don't make it + * accessible through the cipher layer. */ + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#if defined(MBEDTLS_GCM_C) + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + return( mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation, + ctx->iv, ctx->iv_size, ad, ad_len ) ); + } +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + int result; + mbedtls_chachapoly_mode_t mode; + + mode = ( ctx->operation == MBEDTLS_ENCRYPT ) + ? MBEDTLS_CHACHAPOLY_ENCRYPT + : MBEDTLS_CHACHAPOLY_DECRYPT; + + result = mbedtls_chachapoly_starts( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + ctx->iv, + mode ); + if ( result != 0 ) + return( result ); + + return( mbedtls_chachapoly_update_aad( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + ad, ad_len ) ); + } +#endif + + return( 0 ); +} +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ + +int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input, + size_t ilen, unsigned char *output, size_t *olen ) +{ + int ret; + size_t block_size; + + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); + CIPHER_VALIDATE_RET( output != NULL ); + CIPHER_VALIDATE_RET( olen != NULL ); + if( ctx->cipher_info == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( ctx->psa_enabled == 1 ) + { + /* While PSA Crypto has an API for multipart + * operations, we currently don't make it + * accessible through the cipher layer. */ + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + *olen = 0; + block_size = mbedtls_cipher_get_block_size( ctx ); + + if( ctx->cipher_info->mode == MBEDTLS_MODE_ECB ) + { + if( ilen != block_size ) + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + + *olen = ilen; + + if( 0 != ( ret = ctx->cipher_info->base->ecb_func( ctx->cipher_ctx, + ctx->operation, input, output ) ) ) + { + return( ret ); + } + + return( 0 ); + } + +#if defined(MBEDTLS_GCM_C) + if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM ) + { + *olen = ilen; + return( mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input, + output ) ); + } +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 ) + { + *olen = ilen; + return( mbedtls_chachapoly_update( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + ilen, input, output ) ); + } +#endif + + if ( 0 == block_size ) + { + return( MBEDTLS_ERR_CIPHER_INVALID_CONTEXT ); + } + + if( input == output && + ( ctx->unprocessed_len != 0 || ilen % block_size ) ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + if( ctx->cipher_info->mode == MBEDTLS_MODE_CBC ) + { + size_t copy_len = 0; + + /* + * If there is not enough data for a full block, cache it. + */ + if( ( ctx->operation == MBEDTLS_DECRYPT && NULL != ctx->add_padding && + ilen <= block_size - ctx->unprocessed_len ) || + ( ctx->operation == MBEDTLS_DECRYPT && NULL == ctx->add_padding && + ilen < block_size - ctx->unprocessed_len ) || + ( ctx->operation == MBEDTLS_ENCRYPT && + ilen < block_size - ctx->unprocessed_len ) ) + { + memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, + ilen ); + + ctx->unprocessed_len += ilen; + return( 0 ); + } + + /* + * Process cached data first + */ + if( 0 != ctx->unprocessed_len ) + { + copy_len = block_size - ctx->unprocessed_len; + + memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, + copy_len ); + + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, block_size, ctx->iv, + ctx->unprocessed_data, output ) ) ) + { + return( ret ); + } + + *olen += block_size; + output += block_size; + ctx->unprocessed_len = 0; + + input += copy_len; + ilen -= copy_len; + } + + /* + * Cache final, incomplete block + */ + if( 0 != ilen ) + { + if( 0 == block_size ) + { + return( MBEDTLS_ERR_CIPHER_INVALID_CONTEXT ); + } + + /* Encryption: only cache partial blocks + * Decryption w/ padding: always keep at least one whole block + * Decryption w/o padding: only cache partial blocks + */ + copy_len = ilen % block_size; + if( copy_len == 0 && + ctx->operation == MBEDTLS_DECRYPT && + NULL != ctx->add_padding) + { + copy_len = block_size; + } + + memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ), + copy_len ); + + ctx->unprocessed_len += copy_len; + ilen -= copy_len; + } + + /* + * Process remaining full blocks + */ + if( ilen ) + { + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, ilen, ctx->iv, input, output ) ) ) + { + return( ret ); + } + + *olen += ilen; + } + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + if( ctx->cipher_info->mode == MBEDTLS_MODE_CFB ) + { + if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx, + ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv, + input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) + if( ctx->cipher_info->mode == MBEDTLS_MODE_OFB ) + { + if( 0 != ( ret = ctx->cipher_info->base->ofb_func( ctx->cipher_ctx, + ilen, &ctx->unprocessed_len, ctx->iv, input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR ) + { + if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx, + ilen, &ctx->unprocessed_len, ctx->iv, + ctx->unprocessed_data, input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) + if( ctx->cipher_info->mode == MBEDTLS_MODE_XTS ) + { + if( ctx->unprocessed_len > 0 ) { + /* We can only process an entire data unit at a time. */ + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } + + ret = ctx->cipher_info->base->xts_func( ctx->cipher_ctx, + ctx->operation, ilen, ctx->iv, input, output ); + if( ret != 0 ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM ) + { + if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx, + ilen, input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_STREAM */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) +/* + * PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len + */ +static void add_pkcs_padding( unsigned char *output, size_t output_len, + size_t data_len ) +{ + size_t padding_len = output_len - data_len; + unsigned char i; + + for( i = 0; i < padding_len; i++ ) + output[data_len + i] = (unsigned char) padding_len; +} + +static int get_pkcs_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i, pad_idx; + unsigned char padding_len, bad = 0; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + padding_len = input[input_len - 1]; + *data_len = input_len - padding_len; + + /* Avoid logical || since it results in a branch */ + bad |= padding_len > input_len; + bad |= padding_len == 0; + + /* The number of bytes checked must be independent of padding_len, + * so pick input_len, which is usually 8 or 16 (one block) */ + pad_idx = input_len - padding_len; + for( i = 0; i < input_len; i++ ) + bad |= ( input[i] ^ padding_len ) * ( i >= pad_idx ); + + return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); +} +#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ + +#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) +/* + * One and zeros padding: fill with 80 00 ... 00 + */ +static void add_one_and_zeros_padding( unsigned char *output, + size_t output_len, size_t data_len ) +{ + size_t padding_len = output_len - data_len; + unsigned char i = 0; + + output[data_len] = 0x80; + for( i = 1; i < padding_len; i++ ) + output[data_len + i] = 0x00; +} + +static int get_one_and_zeros_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i; + unsigned char done = 0, prev_done, bad; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + bad = 0x80; + *data_len = 0; + for( i = input_len; i > 0; i-- ) + { + prev_done = done; + done |= ( input[i - 1] != 0 ); + *data_len |= ( i - 1 ) * ( done != prev_done ); + bad ^= input[i - 1] * ( done != prev_done ); + } + + return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); + +} +#endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */ + +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) +/* + * Zeros and len padding: fill with 00 ... 00 ll, where ll is padding length + */ +static void add_zeros_and_len_padding( unsigned char *output, + size_t output_len, size_t data_len ) +{ + size_t padding_len = output_len - data_len; + unsigned char i = 0; + + for( i = 1; i < padding_len; i++ ) + output[data_len + i - 1] = 0x00; + output[output_len - 1] = (unsigned char) padding_len; +} + +static int get_zeros_and_len_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i, pad_idx; + unsigned char padding_len, bad = 0; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + padding_len = input[input_len - 1]; + *data_len = input_len - padding_len; + + /* Avoid logical || since it results in a branch */ + bad |= padding_len > input_len; + bad |= padding_len == 0; + + /* The number of bytes checked must be independent of padding_len */ + pad_idx = input_len - padding_len; + for( i = 0; i < input_len - 1; i++ ) + bad |= input[i] * ( i >= pad_idx ); + + return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); +} +#endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */ + +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS) +/* + * Zero padding: fill with 00 ... 00 + */ +static void add_zeros_padding( unsigned char *output, + size_t output_len, size_t data_len ) +{ + size_t i; + + for( i = data_len; i < output_len; i++ ) + output[i] = 0x00; +} + +static int get_zeros_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i; + unsigned char done = 0, prev_done; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + *data_len = 0; + for( i = input_len; i > 0; i-- ) + { + prev_done = done; + done |= ( input[i-1] != 0 ); + *data_len |= i * ( done != prev_done ); + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */ + +/* + * No padding: don't pad :) + * + * There is no add_padding function (check for NULL in mbedtls_cipher_finish) + * but a trivial get_padding function + */ +static int get_no_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + *data_len = input_len; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen ) +{ + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( output != NULL ); + CIPHER_VALIDATE_RET( olen != NULL ); + if( ctx->cipher_info == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( ctx->psa_enabled == 1 ) + { + /* While PSA Crypto has an API for multipart + * operations, we currently don't make it + * accessible through the cipher layer. */ + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + *olen = 0; + + if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode || + MBEDTLS_MODE_OFB == ctx->cipher_info->mode || + MBEDTLS_MODE_CTR == ctx->cipher_info->mode || + MBEDTLS_MODE_GCM == ctx->cipher_info->mode || + MBEDTLS_MODE_XTS == ctx->cipher_info->mode || + MBEDTLS_MODE_STREAM == ctx->cipher_info->mode ) + { + return( 0 ); + } + + if ( ( MBEDTLS_CIPHER_CHACHA20 == ctx->cipher_info->type ) || + ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) ) + { + return( 0 ); + } + + if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode ) + { + if( ctx->unprocessed_len != 0 ) + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + + return( 0 ); + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + if( MBEDTLS_MODE_CBC == ctx->cipher_info->mode ) + { + int ret = 0; + + if( MBEDTLS_ENCRYPT == ctx->operation ) + { + /* check for 'no padding' mode */ + if( NULL == ctx->add_padding ) + { + if( 0 != ctx->unprocessed_len ) + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + + return( 0 ); + } + + ctx->add_padding( ctx->unprocessed_data, mbedtls_cipher_get_iv_size( ctx ), + ctx->unprocessed_len ); + } + else if( mbedtls_cipher_get_block_size( ctx ) != ctx->unprocessed_len ) + { + /* + * For decrypt operations, expect a full block, + * or an empty block if no padding + */ + if( NULL == ctx->add_padding && 0 == ctx->unprocessed_len ) + return( 0 ); + + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + } + + /* cipher block */ + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv, + ctx->unprocessed_data, output ) ) ) + { + return( ret ); + } + + /* Set output size for decryption */ + if( MBEDTLS_DECRYPT == ctx->operation ) + return( ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ), + olen ) ); + + /* Set output size for encryption */ + *olen = mbedtls_cipher_get_block_size( ctx ); + return( 0 ); + } +#else + ((void) output); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, + mbedtls_cipher_padding_t mode ) +{ + CIPHER_VALIDATE_RET( ctx != NULL ); + + if( NULL == ctx->cipher_info || MBEDTLS_MODE_CBC != ctx->cipher_info->mode ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( ctx->psa_enabled == 1 ) + { + /* While PSA Crypto knows about CBC padding + * schemes, we currently don't make them + * accessible through the cipher layer. */ + if( mode != MBEDTLS_PADDING_NONE ) + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + + return( 0 ); + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + switch( mode ) + { +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) + case MBEDTLS_PADDING_PKCS7: + ctx->add_padding = add_pkcs_padding; + ctx->get_padding = get_pkcs_padding; + break; +#endif +#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) + case MBEDTLS_PADDING_ONE_AND_ZEROS: + ctx->add_padding = add_one_and_zeros_padding; + ctx->get_padding = get_one_and_zeros_padding; + break; +#endif +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) + case MBEDTLS_PADDING_ZEROS_AND_LEN: + ctx->add_padding = add_zeros_and_len_padding; + ctx->get_padding = get_zeros_and_len_padding; + break; +#endif +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS) + case MBEDTLS_PADDING_ZEROS: + ctx->add_padding = add_zeros_padding; + ctx->get_padding = get_zeros_padding; + break; +#endif + case MBEDTLS_PADDING_NONE: + ctx->add_padding = NULL; + ctx->get_padding = get_no_padding; + break; + + default: + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, + unsigned char *tag, size_t tag_len ) +{ + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); + if( ctx->cipher_info == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( MBEDTLS_ENCRYPT != ctx->operation ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( ctx->psa_enabled == 1 ) + { + /* While PSA Crypto has an API for multipart + * operations, we currently don't make it + * accessible through the cipher layer. */ + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + + return( 0 ); + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#if defined(MBEDTLS_GCM_C) + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + return( mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, + tag, tag_len ) ); +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + /* Don't allow truncated MAC for Poly1305 */ + if ( tag_len != 16U ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + return( mbedtls_chachapoly_finish( + (mbedtls_chachapoly_context*) ctx->cipher_ctx, tag ) ); + } +#endif + + return( 0 ); +} + +int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, + const unsigned char *tag, size_t tag_len ) +{ + unsigned char check_tag[16]; + int ret; + + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); + if( ctx->cipher_info == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( MBEDTLS_DECRYPT != ctx->operation ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( ctx->psa_enabled == 1 ) + { + /* While PSA Crypto has an API for multipart + * operations, we currently don't make it + * accessible through the cipher layer. */ + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#if defined(MBEDTLS_GCM_C) + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + if( tag_len > sizeof( check_tag ) ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( 0 != ( ret = mbedtls_gcm_finish( + (mbedtls_gcm_context *) ctx->cipher_ctx, + check_tag, tag_len ) ) ) + { + return( ret ); + } + + /* Check the tag in "constant-time" */ + if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 ) + return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); + + return( 0 ); + } +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + /* Don't allow truncated MAC for Poly1305 */ + if ( tag_len != sizeof( check_tag ) ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + ret = mbedtls_chachapoly_finish( + (mbedtls_chachapoly_context*) ctx->cipher_ctx, check_tag ); + if ( ret != 0 ) + { + return( ret ); + } + + /* Check the tag in "constant-time" */ + if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 ) + return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); + + return( 0 ); + } +#endif /* MBEDTLS_CHACHAPOLY_C */ + + return( 0 ); +} +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ + +/* + * Packet-oriented wrapper for non-AEAD modes + */ +int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen ) +{ + int ret; + size_t finish_olen; + + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL ); + CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); + CIPHER_VALIDATE_RET( output != NULL ); + CIPHER_VALIDATE_RET( olen != NULL ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( ctx->psa_enabled == 1 ) + { + /* As in the non-PSA case, we don't check that + * a key has been set. If not, the key slot will + * still be in its default state of 0, which is + * guaranteed to be invalid, hence the PSA-call + * below will gracefully fail. */ + mbedtls_cipher_context_psa * const cipher_psa = + (mbedtls_cipher_context_psa *) ctx->cipher_ctx; + + psa_status_t status; + psa_cipher_operation_t cipher_op = PSA_CIPHER_OPERATION_INIT; + size_t part_len; + + if( ctx->operation == MBEDTLS_DECRYPT ) + { + status = psa_cipher_decrypt_setup( &cipher_op, + cipher_psa->slot, + cipher_psa->alg ); + } + else if( ctx->operation == MBEDTLS_ENCRYPT ) + { + status = psa_cipher_encrypt_setup( &cipher_op, + cipher_psa->slot, + cipher_psa->alg ); + } + else + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + /* In the following, we can immediately return on an error, + * because the PSA Crypto API guarantees that cipher operations + * are terminated by unsuccessful calls to psa_cipher_update(), + * and by any call to psa_cipher_finish(). */ + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED ); + + status = psa_cipher_set_iv( &cipher_op, iv, iv_len ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED ); + + status = psa_cipher_update( &cipher_op, + input, ilen, + output, ilen, olen ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED ); + + status = psa_cipher_finish( &cipher_op, + output + *olen, ilen - *olen, + &part_len ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED ); + + *olen += part_len; + return( 0 ); + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_update( ctx, input, ilen, + output, olen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, + &finish_olen ) ) != 0 ) + return( ret ); + + *olen += finish_olen; + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_AEAD) +/* + * Packet-oriented encryption for AEAD modes + */ +int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + unsigned char *tag, size_t tag_len ) +{ + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( iv != NULL ); + CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL ); + CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); + CIPHER_VALIDATE_RET( output != NULL ); + CIPHER_VALIDATE_RET( olen != NULL ); + CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( ctx->psa_enabled == 1 ) + { + /* As in the non-PSA case, we don't check that + * a key has been set. If not, the key slot will + * still be in its default state of 0, which is + * guaranteed to be invalid, hence the PSA-call + * below will gracefully fail. */ + mbedtls_cipher_context_psa * const cipher_psa = + (mbedtls_cipher_context_psa *) ctx->cipher_ctx; + + psa_status_t status; + + /* PSA Crypto API always writes the authentication tag + * at the end of the encrypted message. */ + if( tag != output + ilen ) + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + + status = psa_aead_encrypt( cipher_psa->slot, + cipher_psa->alg, + iv, iv_len, + ad, ad_len, + input, ilen, + output, ilen + tag_len, olen ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED ); + + *olen -= tag_len; + return( 0 ); + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#if defined(MBEDTLS_GCM_C) + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + *olen = ilen; + return( mbedtls_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, + ilen, iv, iv_len, ad, ad_len, + input, output, tag_len, tag ) ); + } +#endif /* MBEDTLS_GCM_C */ +#if defined(MBEDTLS_CCM_C) + if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode ) + { + *olen = ilen; + return( mbedtls_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, input, output, + tag, tag_len ) ); + } +#endif /* MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + /* ChachaPoly has fixed length nonce and MAC (tag) */ + if ( ( iv_len != ctx->cipher_info->iv_size ) || + ( tag_len != 16U ) ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + *olen = ilen; + return( mbedtls_chachapoly_encrypt_and_tag( ctx->cipher_ctx, + ilen, iv, ad, ad_len, input, output, tag ) ); + } +#endif /* MBEDTLS_CHACHAPOLY_C */ +#if defined(MBEDTLS_NIST_KW_C) + if( MBEDTLS_MODE_KW == ctx->cipher_info->mode || + MBEDTLS_MODE_KWP == ctx->cipher_info->mode ) + { + mbedtls_nist_kw_mode_t mode = ( MBEDTLS_MODE_KW == ctx->cipher_info->mode ) ? + MBEDTLS_KW_MODE_KW : MBEDTLS_KW_MODE_KWP; + + /* There is no iv, tag or ad associated with KW and KWP, these length should be 0 */ + if( iv_len != 0 || tag_len != 0 || ad_len != 0 ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + return( mbedtls_nist_kw_wrap( ctx->cipher_ctx, mode, input, ilen, output, olen, SIZE_MAX ) ); + } +#endif /* MBEDTLS_NIST_KW_C */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} + +/* + * Packet-oriented decryption for AEAD modes + */ +int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + const unsigned char *tag, size_t tag_len ) +{ + CIPHER_VALIDATE_RET( ctx != NULL ); + CIPHER_VALIDATE_RET( iv != NULL ); + CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL ); + CIPHER_VALIDATE_RET( ilen == 0 || input != NULL ); + CIPHER_VALIDATE_RET( output != NULL ); + CIPHER_VALIDATE_RET( olen != NULL ); + CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( ctx->psa_enabled == 1 ) + { + /* As in the non-PSA case, we don't check that + * a key has been set. If not, the key slot will + * still be in its default state of 0, which is + * guaranteed to be invalid, hence the PSA-call + * below will gracefully fail. */ + mbedtls_cipher_context_psa * const cipher_psa = + (mbedtls_cipher_context_psa *) ctx->cipher_ctx; + + psa_status_t status; + + /* PSA Crypto API always writes the authentication tag + * at the end of the encrypted message. */ + if( tag != input + ilen ) + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + + status = psa_aead_decrypt( cipher_psa->slot, + cipher_psa->alg, + iv, iv_len, + ad, ad_len, + input, ilen + tag_len, + output, ilen, olen ); + if( status == PSA_ERROR_INVALID_SIGNATURE ) + return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); + else if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED ); + + return( 0 ); + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#if defined(MBEDTLS_GCM_C) + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + int ret; + + *olen = ilen; + ret = mbedtls_gcm_auth_decrypt( ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, + tag, tag_len, input, output ); + + if( ret == MBEDTLS_ERR_GCM_AUTH_FAILED ) + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + + return( ret ); + } +#endif /* MBEDTLS_GCM_C */ +#if defined(MBEDTLS_CCM_C) + if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode ) + { + int ret; + + *olen = ilen; + ret = mbedtls_ccm_auth_decrypt( ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, + input, output, tag, tag_len ); + + if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED ) + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + + return( ret ); + } +#endif /* MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + int ret; + + /* ChachaPoly has fixed length nonce and MAC (tag) */ + if ( ( iv_len != ctx->cipher_info->iv_size ) || + ( tag_len != 16U ) ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + *olen = ilen; + ret = mbedtls_chachapoly_auth_decrypt( ctx->cipher_ctx, ilen, + iv, ad, ad_len, tag, input, output ); + + if( ret == MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED ) + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + + return( ret ); + } +#endif /* MBEDTLS_CHACHAPOLY_C */ +#if defined(MBEDTLS_NIST_KW_C) + if( MBEDTLS_MODE_KW == ctx->cipher_info->mode || + MBEDTLS_MODE_KWP == ctx->cipher_info->mode ) + { + mbedtls_nist_kw_mode_t mode = ( MBEDTLS_MODE_KW == ctx->cipher_info->mode ) ? + MBEDTLS_KW_MODE_KW : MBEDTLS_KW_MODE_KWP; + + /* There is no iv, tag or ad associated with KW and KWP, these length should be 0 */ + if( iv_len != 0 || tag_len != 0 || ad_len != 0 ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + return( mbedtls_nist_kw_unwrap( ctx->cipher_ctx, mode, input, ilen, output, olen, SIZE_MAX ) ); + } +#endif /* MBEDTLS_NIST_KW_C */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} +#endif /* MBEDTLS_CIPHER_MODE_AEAD */ + +#endif /* MBEDTLS_CIPHER_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/cipher_wrap.c b/FreeRTOS-Labs/Source/mbedtls/library/cipher_wrap.c new file mode 100644 index 000000000..f3fde332d --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/cipher_wrap.c @@ -0,0 +1,2411 @@ +/** + * \file cipher_wrap.c + * + * \brief Generic cipher wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CIPHER_C) + +#include "mbedtls/cipher_internal.h" + +#if defined(MBEDTLS_CHACHAPOLY_C) +#include "mbedtls/chachapoly.h" +#endif + +#if defined(MBEDTLS_AES_C) +#include "mbedtls/aes.h" +#endif + +#if defined(MBEDTLS_ARC4_C) +#include "mbedtls/arc4.h" +#endif + +#if defined(MBEDTLS_CAMELLIA_C) +#include "mbedtls/camellia.h" +#endif + +#if defined(MBEDTLS_ARIA_C) +#include "mbedtls/aria.h" +#endif + +#if defined(MBEDTLS_DES_C) +#include "mbedtls/des.h" +#endif + +#if defined(MBEDTLS_BLOWFISH_C) +#include "mbedtls/blowfish.h" +#endif + +#if defined(MBEDTLS_CHACHA20_C) +#include "mbedtls/chacha20.h" +#endif + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/gcm.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/ccm.h" +#endif + +#if defined(MBEDTLS_NIST_KW_C) +#include "mbedtls/nist_kw.h" +#endif + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#include +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_GCM_C) +/* shared by all GCM ciphers */ +static void *gcm_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_gcm_context ) ); + + if( ctx != NULL ) + mbedtls_gcm_init( (mbedtls_gcm_context *) ctx ); + + return( ctx ); +} + +static void gcm_ctx_free( void *ctx ) +{ + mbedtls_gcm_free( ctx ); + mbedtls_free( ctx ); +} +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +/* shared by all CCM ciphers */ +static void *ccm_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ccm_context ) ); + + if( ctx != NULL ) + mbedtls_ccm_init( (mbedtls_ccm_context *) ctx ); + + return( ctx ); +} + +static void ccm_ctx_free( void *ctx ) +{ + mbedtls_ccm_free( ctx ); + mbedtls_free( ctx ); +} +#endif /* MBEDTLS_CCM_C */ + +#if defined(MBEDTLS_AES_C) + +static int aes_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_ecb( (mbedtls_aes_context *) ctx, operation, input, output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int aes_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_cbc( (mbedtls_aes_context *) ctx, operation, length, iv, input, + output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int aes_crypt_cfb128_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_cfb128( (mbedtls_aes_context *) ctx, operation, length, iv_off, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +static int aes_crypt_ofb_wrap( void *ctx, size_t length, size_t *iv_off, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_ofb( (mbedtls_aes_context *) ctx, length, iv_off, + iv, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int aes_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_ctr( (mbedtls_aes_context *) ctx, length, nc_off, nonce_counter, + stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +static int aes_crypt_xts_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, + const unsigned char data_unit[16], + const unsigned char *input, + unsigned char *output ) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + int mode; + + switch( operation ) + { + case MBEDTLS_ENCRYPT: + mode = MBEDTLS_AES_ENCRYPT; + break; + case MBEDTLS_DECRYPT: + mode = MBEDTLS_AES_DECRYPT; + break; + default: + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + return mbedtls_aes_crypt_xts( xts_ctx, mode, length, + data_unit, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +static int aes_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_aes_setkey_dec( (mbedtls_aes_context *) ctx, key, key_bitlen ); +} + +static int aes_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_aes_setkey_enc( (mbedtls_aes_context *) ctx, key, key_bitlen ); +} + +static void * aes_ctx_alloc( void ) +{ + mbedtls_aes_context *aes = mbedtls_calloc( 1, sizeof( mbedtls_aes_context ) ); + + if( aes == NULL ) + return( NULL ); + + mbedtls_aes_init( aes ); + + return( aes ); +} + +static void aes_ctx_free( void *ctx ) +{ + mbedtls_aes_free( (mbedtls_aes_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t aes_info = { + MBEDTLS_CIPHER_ID_AES, + aes_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + aes_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + aes_crypt_cfb128_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + aes_crypt_ofb_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + aes_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + aes_setkey_enc_wrap, + aes_setkey_dec_wrap, + aes_ctx_alloc, + aes_ctx_free +}; + +static const mbedtls_cipher_info_t aes_128_ecb_info = { + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_MODE_ECB, + 128, + "AES-128-ECB", + 0, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ecb_info = { + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_MODE_ECB, + 192, + "AES-192-ECB", + 0, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ecb_info = { + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_MODE_ECB, + 256, + "AES-256-ECB", + 0, + 0, + 16, + &aes_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t aes_128_cbc_info = { + MBEDTLS_CIPHER_AES_128_CBC, + MBEDTLS_MODE_CBC, + 128, + "AES-128-CBC", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_cbc_info = { + MBEDTLS_CIPHER_AES_192_CBC, + MBEDTLS_MODE_CBC, + 192, + "AES-192-CBC", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_cbc_info = { + MBEDTLS_CIPHER_AES_256_CBC, + MBEDTLS_MODE_CBC, + 256, + "AES-256-CBC", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t aes_128_cfb128_info = { + MBEDTLS_CIPHER_AES_128_CFB128, + MBEDTLS_MODE_CFB, + 128, + "AES-128-CFB128", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_cfb128_info = { + MBEDTLS_CIPHER_AES_192_CFB128, + MBEDTLS_MODE_CFB, + 192, + "AES-192-CFB128", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_cfb128_info = { + MBEDTLS_CIPHER_AES_256_CFB128, + MBEDTLS_MODE_CFB, + 256, + "AES-256-CFB128", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +static const mbedtls_cipher_info_t aes_128_ofb_info = { + MBEDTLS_CIPHER_AES_128_OFB, + MBEDTLS_MODE_OFB, + 128, + "AES-128-OFB", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ofb_info = { + MBEDTLS_CIPHER_AES_192_OFB, + MBEDTLS_MODE_OFB, + 192, + "AES-192-OFB", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ofb_info = { + MBEDTLS_CIPHER_AES_256_OFB, + MBEDTLS_MODE_OFB, + 256, + "AES-256-OFB", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t aes_128_ctr_info = { + MBEDTLS_CIPHER_AES_128_CTR, + MBEDTLS_MODE_CTR, + 128, + "AES-128-CTR", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ctr_info = { + MBEDTLS_CIPHER_AES_192_CTR, + MBEDTLS_MODE_CTR, + 192, + "AES-192-CTR", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ctr_info = { + MBEDTLS_CIPHER_AES_256_CTR, + MBEDTLS_MODE_CTR, + 256, + "AES-256-CTR", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +static int xts_aes_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + return( mbedtls_aes_xts_setkey_enc( xts_ctx, key, key_bitlen ) ); +} + +static int xts_aes_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + return( mbedtls_aes_xts_setkey_dec( xts_ctx, key, key_bitlen ) ); +} + +static void *xts_aes_ctx_alloc( void ) +{ + mbedtls_aes_xts_context *xts_ctx = mbedtls_calloc( 1, sizeof( *xts_ctx ) ); + + if( xts_ctx != NULL ) + mbedtls_aes_xts_init( xts_ctx ); + + return( xts_ctx ); +} + +static void xts_aes_ctx_free( void *ctx ) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + + if( xts_ctx == NULL ) + return; + + mbedtls_aes_xts_free( xts_ctx ); + mbedtls_free( xts_ctx ); +} + +static const mbedtls_cipher_base_t xts_aes_info = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + aes_crypt_xts_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + xts_aes_setkey_enc_wrap, + xts_aes_setkey_dec_wrap, + xts_aes_ctx_alloc, + xts_aes_ctx_free +}; + +static const mbedtls_cipher_info_t aes_128_xts_info = { + MBEDTLS_CIPHER_AES_128_XTS, + MBEDTLS_MODE_XTS, + 256, + "AES-128-XTS", + 16, + 0, + 16, + &xts_aes_info +}; + +static const mbedtls_cipher_info_t aes_256_xts_info = { + MBEDTLS_CIPHER_AES_256_XTS, + MBEDTLS_MODE_XTS, + 512, + "AES-256-XTS", + 16, + 0, + 16, + &xts_aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#if defined(MBEDTLS_GCM_C) +static int gcm_aes_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_gcm_setkey( (mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_AES, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t gcm_aes_info = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + gcm_aes_setkey_wrap, + gcm_aes_setkey_wrap, + gcm_ctx_alloc, + gcm_ctx_free, +}; + +static const mbedtls_cipher_info_t aes_128_gcm_info = { + MBEDTLS_CIPHER_AES_128_GCM, + MBEDTLS_MODE_GCM, + 128, + "AES-128-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aes_info +}; + +static const mbedtls_cipher_info_t aes_192_gcm_info = { + MBEDTLS_CIPHER_AES_192_GCM, + MBEDTLS_MODE_GCM, + 192, + "AES-192-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aes_info +}; + +static const mbedtls_cipher_info_t aes_256_gcm_info = { + MBEDTLS_CIPHER_AES_256_GCM, + MBEDTLS_MODE_GCM, + 256, + "AES-256-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aes_info +}; +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +static int ccm_aes_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_ccm_setkey( (mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_AES, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t ccm_aes_info = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + ccm_aes_setkey_wrap, + ccm_aes_setkey_wrap, + ccm_ctx_alloc, + ccm_ctx_free, +}; + +static const mbedtls_cipher_info_t aes_128_ccm_info = { + MBEDTLS_CIPHER_AES_128_CCM, + MBEDTLS_MODE_CCM, + 128, + "AES-128-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ccm_info = { + MBEDTLS_CIPHER_AES_192_CCM, + MBEDTLS_MODE_CCM, + 192, + "AES-192-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ccm_info = { + MBEDTLS_CIPHER_AES_256_CCM, + MBEDTLS_MODE_CCM, + 256, + "AES-256-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aes_info +}; +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) + +static int camellia_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_ecb( (mbedtls_camellia_context *) ctx, operation, input, + output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int camellia_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_cbc( (mbedtls_camellia_context *) ctx, operation, length, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int camellia_crypt_cfb128_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_cfb128( (mbedtls_camellia_context *) ctx, operation, length, + iv_off, iv, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int camellia_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_ctr( (mbedtls_camellia_context *) ctx, length, nc_off, + nonce_counter, stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static int camellia_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_camellia_setkey_dec( (mbedtls_camellia_context *) ctx, key, key_bitlen ); +} + +static int camellia_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_camellia_setkey_enc( (mbedtls_camellia_context *) ctx, key, key_bitlen ); +} + +static void * camellia_ctx_alloc( void ) +{ + mbedtls_camellia_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_camellia_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_camellia_init( ctx ); + + return( ctx ); +} + +static void camellia_ctx_free( void *ctx ) +{ + mbedtls_camellia_free( (mbedtls_camellia_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t camellia_info = { + MBEDTLS_CIPHER_ID_CAMELLIA, + camellia_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + camellia_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + camellia_crypt_cfb128_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + camellia_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + camellia_setkey_enc_wrap, + camellia_setkey_dec_wrap, + camellia_ctx_alloc, + camellia_ctx_free +}; + +static const mbedtls_cipher_info_t camellia_128_ecb_info = { + MBEDTLS_CIPHER_CAMELLIA_128_ECB, + MBEDTLS_MODE_ECB, + 128, + "CAMELLIA-128-ECB", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_ecb_info = { + MBEDTLS_CIPHER_CAMELLIA_192_ECB, + MBEDTLS_MODE_ECB, + 192, + "CAMELLIA-192-ECB", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_ecb_info = { + MBEDTLS_CIPHER_CAMELLIA_256_ECB, + MBEDTLS_MODE_ECB, + 256, + "CAMELLIA-256-ECB", + 16, + 0, + 16, + &camellia_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t camellia_128_cbc_info = { + MBEDTLS_CIPHER_CAMELLIA_128_CBC, + MBEDTLS_MODE_CBC, + 128, + "CAMELLIA-128-CBC", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_cbc_info = { + MBEDTLS_CIPHER_CAMELLIA_192_CBC, + MBEDTLS_MODE_CBC, + 192, + "CAMELLIA-192-CBC", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_cbc_info = { + MBEDTLS_CIPHER_CAMELLIA_256_CBC, + MBEDTLS_MODE_CBC, + 256, + "CAMELLIA-256-CBC", + 16, + 0, + 16, + &camellia_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t camellia_128_cfb128_info = { + MBEDTLS_CIPHER_CAMELLIA_128_CFB128, + MBEDTLS_MODE_CFB, + 128, + "CAMELLIA-128-CFB128", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_cfb128_info = { + MBEDTLS_CIPHER_CAMELLIA_192_CFB128, + MBEDTLS_MODE_CFB, + 192, + "CAMELLIA-192-CFB128", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_cfb128_info = { + MBEDTLS_CIPHER_CAMELLIA_256_CFB128, + MBEDTLS_MODE_CFB, + 256, + "CAMELLIA-256-CFB128", + 16, + 0, + 16, + &camellia_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t camellia_128_ctr_info = { + MBEDTLS_CIPHER_CAMELLIA_128_CTR, + MBEDTLS_MODE_CTR, + 128, + "CAMELLIA-128-CTR", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_ctr_info = { + MBEDTLS_CIPHER_CAMELLIA_192_CTR, + MBEDTLS_MODE_CTR, + 192, + "CAMELLIA-192-CTR", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_ctr_info = { + MBEDTLS_CIPHER_CAMELLIA_256_CTR, + MBEDTLS_MODE_CTR, + 256, + "CAMELLIA-256-CTR", + 16, + 0, + 16, + &camellia_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_GCM_C) +static int gcm_camellia_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_gcm_setkey( (mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_CAMELLIA, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t gcm_camellia_info = { + MBEDTLS_CIPHER_ID_CAMELLIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + gcm_camellia_setkey_wrap, + gcm_camellia_setkey_wrap, + gcm_ctx_alloc, + gcm_ctx_free, +}; + +static const mbedtls_cipher_info_t camellia_128_gcm_info = { + MBEDTLS_CIPHER_CAMELLIA_128_GCM, + MBEDTLS_MODE_GCM, + 128, + "CAMELLIA-128-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_gcm_info = { + MBEDTLS_CIPHER_CAMELLIA_192_GCM, + MBEDTLS_MODE_GCM, + 192, + "CAMELLIA-192-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_gcm_info = { + MBEDTLS_CIPHER_CAMELLIA_256_GCM, + MBEDTLS_MODE_GCM, + 256, + "CAMELLIA-256-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_camellia_info +}; +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +static int ccm_camellia_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_ccm_setkey( (mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_CAMELLIA, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t ccm_camellia_info = { + MBEDTLS_CIPHER_ID_CAMELLIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + ccm_camellia_setkey_wrap, + ccm_camellia_setkey_wrap, + ccm_ctx_alloc, + ccm_ctx_free, +}; + +static const mbedtls_cipher_info_t camellia_128_ccm_info = { + MBEDTLS_CIPHER_CAMELLIA_128_CCM, + MBEDTLS_MODE_CCM, + 128, + "CAMELLIA-128-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_ccm_info = { + MBEDTLS_CIPHER_CAMELLIA_192_CCM, + MBEDTLS_MODE_CCM, + 192, + "CAMELLIA-192-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_ccm_info = { + MBEDTLS_CIPHER_CAMELLIA_256_CCM, + MBEDTLS_MODE_CCM, + 256, + "CAMELLIA-256-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_camellia_info +}; +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_ARIA_C) + +static int aria_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + (void) operation; + return mbedtls_aria_crypt_ecb( (mbedtls_aria_context *) ctx, input, + output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int aria_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aria_crypt_cbc( (mbedtls_aria_context *) ctx, operation, length, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int aria_crypt_cfb128_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aria_crypt_cfb128( (mbedtls_aria_context *) ctx, operation, length, + iv_off, iv, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int aria_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aria_crypt_ctr( (mbedtls_aria_context *) ctx, length, nc_off, + nonce_counter, stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static int aria_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_aria_setkey_dec( (mbedtls_aria_context *) ctx, key, key_bitlen ); +} + +static int aria_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_aria_setkey_enc( (mbedtls_aria_context *) ctx, key, key_bitlen ); +} + +static void * aria_ctx_alloc( void ) +{ + mbedtls_aria_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_aria_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_aria_init( ctx ); + + return( ctx ); +} + +static void aria_ctx_free( void *ctx ) +{ + mbedtls_aria_free( (mbedtls_aria_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t aria_info = { + MBEDTLS_CIPHER_ID_ARIA, + aria_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + aria_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + aria_crypt_cfb128_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + aria_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + aria_setkey_enc_wrap, + aria_setkey_dec_wrap, + aria_ctx_alloc, + aria_ctx_free +}; + +static const mbedtls_cipher_info_t aria_128_ecb_info = { + MBEDTLS_CIPHER_ARIA_128_ECB, + MBEDTLS_MODE_ECB, + 128, + "ARIA-128-ECB", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_192_ecb_info = { + MBEDTLS_CIPHER_ARIA_192_ECB, + MBEDTLS_MODE_ECB, + 192, + "ARIA-192-ECB", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_256_ecb_info = { + MBEDTLS_CIPHER_ARIA_256_ECB, + MBEDTLS_MODE_ECB, + 256, + "ARIA-256-ECB", + 16, + 0, + 16, + &aria_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t aria_128_cbc_info = { + MBEDTLS_CIPHER_ARIA_128_CBC, + MBEDTLS_MODE_CBC, + 128, + "ARIA-128-CBC", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_192_cbc_info = { + MBEDTLS_CIPHER_ARIA_192_CBC, + MBEDTLS_MODE_CBC, + 192, + "ARIA-192-CBC", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_256_cbc_info = { + MBEDTLS_CIPHER_ARIA_256_CBC, + MBEDTLS_MODE_CBC, + 256, + "ARIA-256-CBC", + 16, + 0, + 16, + &aria_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t aria_128_cfb128_info = { + MBEDTLS_CIPHER_ARIA_128_CFB128, + MBEDTLS_MODE_CFB, + 128, + "ARIA-128-CFB128", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_192_cfb128_info = { + MBEDTLS_CIPHER_ARIA_192_CFB128, + MBEDTLS_MODE_CFB, + 192, + "ARIA-192-CFB128", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_256_cfb128_info = { + MBEDTLS_CIPHER_ARIA_256_CFB128, + MBEDTLS_MODE_CFB, + 256, + "ARIA-256-CFB128", + 16, + 0, + 16, + &aria_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t aria_128_ctr_info = { + MBEDTLS_CIPHER_ARIA_128_CTR, + MBEDTLS_MODE_CTR, + 128, + "ARIA-128-CTR", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_192_ctr_info = { + MBEDTLS_CIPHER_ARIA_192_CTR, + MBEDTLS_MODE_CTR, + 192, + "ARIA-192-CTR", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_256_ctr_info = { + MBEDTLS_CIPHER_ARIA_256_CTR, + MBEDTLS_MODE_CTR, + 256, + "ARIA-256-CTR", + 16, + 0, + 16, + &aria_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_GCM_C) +static int gcm_aria_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_gcm_setkey( (mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_ARIA, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t gcm_aria_info = { + MBEDTLS_CIPHER_ID_ARIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + gcm_aria_setkey_wrap, + gcm_aria_setkey_wrap, + gcm_ctx_alloc, + gcm_ctx_free, +}; + +static const mbedtls_cipher_info_t aria_128_gcm_info = { + MBEDTLS_CIPHER_ARIA_128_GCM, + MBEDTLS_MODE_GCM, + 128, + "ARIA-128-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aria_info +}; + +static const mbedtls_cipher_info_t aria_192_gcm_info = { + MBEDTLS_CIPHER_ARIA_192_GCM, + MBEDTLS_MODE_GCM, + 192, + "ARIA-192-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aria_info +}; + +static const mbedtls_cipher_info_t aria_256_gcm_info = { + MBEDTLS_CIPHER_ARIA_256_GCM, + MBEDTLS_MODE_GCM, + 256, + "ARIA-256-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aria_info +}; +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +static int ccm_aria_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_ccm_setkey( (mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_ARIA, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t ccm_aria_info = { + MBEDTLS_CIPHER_ID_ARIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + ccm_aria_setkey_wrap, + ccm_aria_setkey_wrap, + ccm_ctx_alloc, + ccm_ctx_free, +}; + +static const mbedtls_cipher_info_t aria_128_ccm_info = { + MBEDTLS_CIPHER_ARIA_128_CCM, + MBEDTLS_MODE_CCM, + 128, + "ARIA-128-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aria_info +}; + +static const mbedtls_cipher_info_t aria_192_ccm_info = { + MBEDTLS_CIPHER_ARIA_192_CCM, + MBEDTLS_MODE_CCM, + 192, + "ARIA-192-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aria_info +}; + +static const mbedtls_cipher_info_t aria_256_ccm_info = { + MBEDTLS_CIPHER_ARIA_256_CCM, + MBEDTLS_MODE_CCM, + 256, + "ARIA-256-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aria_info +}; +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_ARIA_C */ + +#if defined(MBEDTLS_DES_C) + +static int des_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + ((void) operation); + return mbedtls_des_crypt_ecb( (mbedtls_des_context *) ctx, input, output ); +} + +static int des3_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + ((void) operation); + return mbedtls_des3_crypt_ecb( (mbedtls_des3_context *) ctx, input, output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int des_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_des_crypt_cbc( (mbedtls_des_context *) ctx, operation, length, iv, input, + output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int des3_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_des3_crypt_cbc( (mbedtls_des3_context *) ctx, operation, length, iv, input, + output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +static int des_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des_setkey_dec( (mbedtls_des_context *) ctx, key ); +} + +static int des_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des_setkey_enc( (mbedtls_des_context *) ctx, key ); +} + +static int des3_set2key_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set2key_dec( (mbedtls_des3_context *) ctx, key ); +} + +static int des3_set2key_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set2key_enc( (mbedtls_des3_context *) ctx, key ); +} + +static int des3_set3key_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set3key_dec( (mbedtls_des3_context *) ctx, key ); +} + +static int des3_set3key_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set3key_enc( (mbedtls_des3_context *) ctx, key ); +} + +static void * des_ctx_alloc( void ) +{ + mbedtls_des_context *des = mbedtls_calloc( 1, sizeof( mbedtls_des_context ) ); + + if( des == NULL ) + return( NULL ); + + mbedtls_des_init( des ); + + return( des ); +} + +static void des_ctx_free( void *ctx ) +{ + mbedtls_des_free( (mbedtls_des_context *) ctx ); + mbedtls_free( ctx ); +} + +static void * des3_ctx_alloc( void ) +{ + mbedtls_des3_context *des3; + des3 = mbedtls_calloc( 1, sizeof( mbedtls_des3_context ) ); + + if( des3 == NULL ) + return( NULL ); + + mbedtls_des3_init( des3 ); + + return( des3 ); +} + +static void des3_ctx_free( void *ctx ) +{ + mbedtls_des3_free( (mbedtls_des3_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t des_info = { + MBEDTLS_CIPHER_ID_DES, + des_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + des_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + des_setkey_enc_wrap, + des_setkey_dec_wrap, + des_ctx_alloc, + des_ctx_free +}; + +static const mbedtls_cipher_info_t des_ecb_info = { + MBEDTLS_CIPHER_DES_ECB, + MBEDTLS_MODE_ECB, + MBEDTLS_KEY_LENGTH_DES, + "DES-ECB", + 8, + 0, + 8, + &des_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t des_cbc_info = { + MBEDTLS_CIPHER_DES_CBC, + MBEDTLS_MODE_CBC, + MBEDTLS_KEY_LENGTH_DES, + "DES-CBC", + 8, + 0, + 8, + &des_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +static const mbedtls_cipher_base_t des_ede_info = { + MBEDTLS_CIPHER_ID_DES, + des3_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + des3_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + des3_set2key_enc_wrap, + des3_set2key_dec_wrap, + des3_ctx_alloc, + des3_ctx_free +}; + +static const mbedtls_cipher_info_t des_ede_ecb_info = { + MBEDTLS_CIPHER_DES_EDE_ECB, + MBEDTLS_MODE_ECB, + MBEDTLS_KEY_LENGTH_DES_EDE, + "DES-EDE-ECB", + 8, + 0, + 8, + &des_ede_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t des_ede_cbc_info = { + MBEDTLS_CIPHER_DES_EDE_CBC, + MBEDTLS_MODE_CBC, + MBEDTLS_KEY_LENGTH_DES_EDE, + "DES-EDE-CBC", + 8, + 0, + 8, + &des_ede_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +static const mbedtls_cipher_base_t des_ede3_info = { + MBEDTLS_CIPHER_ID_3DES, + des3_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + des3_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + des3_set3key_enc_wrap, + des3_set3key_dec_wrap, + des3_ctx_alloc, + des3_ctx_free +}; + +static const mbedtls_cipher_info_t des_ede3_ecb_info = { + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_MODE_ECB, + MBEDTLS_KEY_LENGTH_DES_EDE3, + "DES-EDE3-ECB", + 8, + 0, + 8, + &des_ede3_info +}; +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t des_ede3_cbc_info = { + MBEDTLS_CIPHER_DES_EDE3_CBC, + MBEDTLS_MODE_CBC, + MBEDTLS_KEY_LENGTH_DES_EDE3, + "DES-EDE3-CBC", + 8, + 0, + 8, + &des_ede3_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_BLOWFISH_C) + +static int blowfish_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_blowfish_crypt_ecb( (mbedtls_blowfish_context *) ctx, operation, input, + output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int blowfish_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, unsigned char *iv, const unsigned char *input, + unsigned char *output ) +{ + return mbedtls_blowfish_crypt_cbc( (mbedtls_blowfish_context *) ctx, operation, length, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int blowfish_crypt_cfb64_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_blowfish_crypt_cfb64( (mbedtls_blowfish_context *) ctx, operation, length, + iv_off, iv, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int blowfish_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_blowfish_crypt_ctr( (mbedtls_blowfish_context *) ctx, length, nc_off, + nonce_counter, stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static int blowfish_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_blowfish_setkey( (mbedtls_blowfish_context *) ctx, key, key_bitlen ); +} + +static void * blowfish_ctx_alloc( void ) +{ + mbedtls_blowfish_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_blowfish_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_blowfish_init( ctx ); + + return( ctx ); +} + +static void blowfish_ctx_free( void *ctx ) +{ + mbedtls_blowfish_free( (mbedtls_blowfish_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t blowfish_info = { + MBEDTLS_CIPHER_ID_BLOWFISH, + blowfish_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + blowfish_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + blowfish_crypt_cfb64_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + blowfish_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + blowfish_setkey_wrap, + blowfish_setkey_wrap, + blowfish_ctx_alloc, + blowfish_ctx_free +}; + +static const mbedtls_cipher_info_t blowfish_ecb_info = { + MBEDTLS_CIPHER_BLOWFISH_ECB, + MBEDTLS_MODE_ECB, + 128, + "BLOWFISH-ECB", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t blowfish_cbc_info = { + MBEDTLS_CIPHER_BLOWFISH_CBC, + MBEDTLS_MODE_CBC, + 128, + "BLOWFISH-CBC", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t blowfish_cfb64_info = { + MBEDTLS_CIPHER_BLOWFISH_CFB64, + MBEDTLS_MODE_CFB, + 128, + "BLOWFISH-CFB64", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t blowfish_ctr_info = { + MBEDTLS_CIPHER_BLOWFISH_CTR, + MBEDTLS_MODE_CTR, + 128, + "BLOWFISH-CTR", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ +#endif /* MBEDTLS_BLOWFISH_C */ + +#if defined(MBEDTLS_ARC4_C) +static int arc4_crypt_stream_wrap( void *ctx, size_t length, + const unsigned char *input, + unsigned char *output ) +{ + return( mbedtls_arc4_crypt( (mbedtls_arc4_context *) ctx, length, input, output ) ); +} + +static int arc4_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + /* we get key_bitlen in bits, arc4 expects it in bytes */ + if( key_bitlen % 8 != 0 ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + mbedtls_arc4_setup( (mbedtls_arc4_context *) ctx, key, key_bitlen / 8 ); + return( 0 ); +} + +static void * arc4_ctx_alloc( void ) +{ + mbedtls_arc4_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_arc4_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_arc4_init( ctx ); + + return( ctx ); +} + +static void arc4_ctx_free( void *ctx ) +{ + mbedtls_arc4_free( (mbedtls_arc4_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t arc4_base_info = { + MBEDTLS_CIPHER_ID_ARC4, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + arc4_crypt_stream_wrap, +#endif + arc4_setkey_wrap, + arc4_setkey_wrap, + arc4_ctx_alloc, + arc4_ctx_free +}; + +static const mbedtls_cipher_info_t arc4_128_info = { + MBEDTLS_CIPHER_ARC4_128, + MBEDTLS_MODE_STREAM, + 128, + "ARC4-128", + 0, + 0, + 1, + &arc4_base_info +}; +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CHACHA20_C) + +static int chacha20_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + if( key_bitlen != 256U ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if ( 0 != mbedtls_chacha20_setkey( (mbedtls_chacha20_context*)ctx, key ) ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + return( 0 ); +} + +static int chacha20_stream_wrap( void *ctx, size_t length, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + + ret = mbedtls_chacha20_update( ctx, length, input, output ); + if( ret == MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + return( ret ); +} + +static void * chacha20_ctx_alloc( void ) +{ + mbedtls_chacha20_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_chacha20_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_chacha20_init( ctx ); + + return( ctx ); +} + +static void chacha20_ctx_free( void *ctx ) +{ + mbedtls_chacha20_free( (mbedtls_chacha20_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t chacha20_base_info = { + MBEDTLS_CIPHER_ID_CHACHA20, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + chacha20_stream_wrap, +#endif + chacha20_setkey_wrap, + chacha20_setkey_wrap, + chacha20_ctx_alloc, + chacha20_ctx_free +}; +static const mbedtls_cipher_info_t chacha20_info = { + MBEDTLS_CIPHER_CHACHA20, + MBEDTLS_MODE_STREAM, + 256, + "CHACHA20", + 12, + 0, + 1, + &chacha20_base_info +}; +#endif /* MBEDTLS_CHACHA20_C */ + +#if defined(MBEDTLS_CHACHAPOLY_C) + +static int chachapoly_setkey_wrap( void *ctx, + const unsigned char *key, + unsigned int key_bitlen ) +{ + if( key_bitlen != 256U ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if ( 0 != mbedtls_chachapoly_setkey( (mbedtls_chachapoly_context*)ctx, key ) ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + return( 0 ); +} + +static void * chachapoly_ctx_alloc( void ) +{ + mbedtls_chachapoly_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_chachapoly_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_chachapoly_init( ctx ); + + return( ctx ); +} + +static void chachapoly_ctx_free( void *ctx ) +{ + mbedtls_chachapoly_free( (mbedtls_chachapoly_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t chachapoly_base_info = { + MBEDTLS_CIPHER_ID_CHACHA20, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + chachapoly_setkey_wrap, + chachapoly_setkey_wrap, + chachapoly_ctx_alloc, + chachapoly_ctx_free +}; +static const mbedtls_cipher_info_t chachapoly_info = { + MBEDTLS_CIPHER_CHACHA20_POLY1305, + MBEDTLS_MODE_CHACHAPOLY, + 256, + "CHACHA20-POLY1305", + 12, + 0, + 1, + &chachapoly_base_info +}; +#endif /* MBEDTLS_CHACHAPOLY_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +static int null_crypt_stream( void *ctx, size_t length, + const unsigned char *input, + unsigned char *output ) +{ + ((void) ctx); + memmove( output, input, length ); + return( 0 ); +} + +static int null_setkey( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) ctx); + ((void) key); + ((void) key_bitlen); + + return( 0 ); +} + +static void * null_ctx_alloc( void ) +{ + return( (void *) 1 ); +} + +static void null_ctx_free( void *ctx ) +{ + ((void) ctx); +} + +static const mbedtls_cipher_base_t null_base_info = { + MBEDTLS_CIPHER_ID_NULL, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + null_crypt_stream, +#endif + null_setkey, + null_setkey, + null_ctx_alloc, + null_ctx_free +}; + +static const mbedtls_cipher_info_t null_cipher_info = { + MBEDTLS_CIPHER_NULL, + MBEDTLS_MODE_STREAM, + 0, + "NULL", + 0, + 0, + 1, + &null_base_info +}; +#endif /* defined(MBEDTLS_CIPHER_NULL_CIPHER) */ + +#if defined(MBEDTLS_NIST_KW_C) +static void *kw_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_nist_kw_context ) ); + + if( ctx != NULL ) + mbedtls_nist_kw_init( (mbedtls_nist_kw_context *) ctx ); + + return( ctx ); +} + +static void kw_ctx_free( void *ctx ) +{ + mbedtls_nist_kw_free( ctx ); + mbedtls_free( ctx ); +} + +static int kw_aes_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_nist_kw_setkey( (mbedtls_nist_kw_context *) ctx, + MBEDTLS_CIPHER_ID_AES, key, key_bitlen, 1 ); +} + +static int kw_aes_setkey_unwrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_nist_kw_setkey( (mbedtls_nist_kw_context *) ctx, + MBEDTLS_CIPHER_ID_AES, key, key_bitlen, 0 ); +} + +static const mbedtls_cipher_base_t kw_aes_info = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + kw_aes_setkey_wrap, + kw_aes_setkey_unwrap, + kw_ctx_alloc, + kw_ctx_free, +}; + +static const mbedtls_cipher_info_t aes_128_nist_kw_info = { + MBEDTLS_CIPHER_AES_128_KW, + MBEDTLS_MODE_KW, + 128, + "AES-128-KW", + 0, + 0, + 16, + &kw_aes_info +}; + +static const mbedtls_cipher_info_t aes_192_nist_kw_info = { + MBEDTLS_CIPHER_AES_192_KW, + MBEDTLS_MODE_KW, + 192, + "AES-192-KW", + 0, + 0, + 16, + &kw_aes_info +}; + +static const mbedtls_cipher_info_t aes_256_nist_kw_info = { + MBEDTLS_CIPHER_AES_256_KW, + MBEDTLS_MODE_KW, + 256, + "AES-256-KW", + 0, + 0, + 16, + &kw_aes_info +}; + +static const mbedtls_cipher_info_t aes_128_nist_kwp_info = { + MBEDTLS_CIPHER_AES_128_KWP, + MBEDTLS_MODE_KWP, + 128, + "AES-128-KWP", + 0, + 0, + 16, + &kw_aes_info +}; + +static const mbedtls_cipher_info_t aes_192_nist_kwp_info = { + MBEDTLS_CIPHER_AES_192_KWP, + MBEDTLS_MODE_KWP, + 192, + "AES-192-KWP", + 0, + 0, + 16, + &kw_aes_info +}; + +static const mbedtls_cipher_info_t aes_256_nist_kwp_info = { + MBEDTLS_CIPHER_AES_256_KWP, + MBEDTLS_MODE_KWP, + 256, + "AES-256-KWP", + 0, + 0, + 16, + &kw_aes_info +}; +#endif /* MBEDTLS_NIST_KW_C */ + +const mbedtls_cipher_definition_t mbedtls_cipher_definitions[] = +{ +#if defined(MBEDTLS_AES_C) + { MBEDTLS_CIPHER_AES_128_ECB, &aes_128_ecb_info }, + { MBEDTLS_CIPHER_AES_192_ECB, &aes_192_ecb_info }, + { MBEDTLS_CIPHER_AES_256_ECB, &aes_256_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_AES_128_CBC, &aes_128_cbc_info }, + { MBEDTLS_CIPHER_AES_192_CBC, &aes_192_cbc_info }, + { MBEDTLS_CIPHER_AES_256_CBC, &aes_256_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_AES_128_CFB128, &aes_128_cfb128_info }, + { MBEDTLS_CIPHER_AES_192_CFB128, &aes_192_cfb128_info }, + { MBEDTLS_CIPHER_AES_256_CFB128, &aes_256_cfb128_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + { MBEDTLS_CIPHER_AES_128_OFB, &aes_128_ofb_info }, + { MBEDTLS_CIPHER_AES_192_OFB, &aes_192_ofb_info }, + { MBEDTLS_CIPHER_AES_256_OFB, &aes_256_ofb_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_AES_128_CTR, &aes_128_ctr_info }, + { MBEDTLS_CIPHER_AES_192_CTR, &aes_192_ctr_info }, + { MBEDTLS_CIPHER_AES_256_CTR, &aes_256_ctr_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + { MBEDTLS_CIPHER_AES_128_XTS, &aes_128_xts_info }, + { MBEDTLS_CIPHER_AES_256_XTS, &aes_256_xts_info }, +#endif +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_CIPHER_AES_128_GCM, &aes_128_gcm_info }, + { MBEDTLS_CIPHER_AES_192_GCM, &aes_192_gcm_info }, + { MBEDTLS_CIPHER_AES_256_GCM, &aes_256_gcm_info }, +#endif +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_CIPHER_AES_128_CCM, &aes_128_ccm_info }, + { MBEDTLS_CIPHER_AES_192_CCM, &aes_192_ccm_info }, + { MBEDTLS_CIPHER_AES_256_CCM, &aes_256_ccm_info }, +#endif +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_ARC4_C) + { MBEDTLS_CIPHER_ARC4_128, &arc4_128_info }, +#endif + +#if defined(MBEDTLS_BLOWFISH_C) + { MBEDTLS_CIPHER_BLOWFISH_ECB, &blowfish_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_BLOWFISH_CBC, &blowfish_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_BLOWFISH_CFB64, &blowfish_cfb64_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_BLOWFISH_CTR, &blowfish_ctr_info }, +#endif +#endif /* MBEDTLS_BLOWFISH_C */ + +#if defined(MBEDTLS_CAMELLIA_C) + { MBEDTLS_CIPHER_CAMELLIA_128_ECB, &camellia_128_ecb_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_ECB, &camellia_192_ecb_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_ECB, &camellia_256_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_CAMELLIA_128_CBC, &camellia_128_cbc_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CBC, &camellia_192_cbc_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CBC, &camellia_256_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_CAMELLIA_128_CFB128, &camellia_128_cfb128_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CFB128, &camellia_192_cfb128_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CFB128, &camellia_256_cfb128_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_CAMELLIA_128_CTR, &camellia_128_ctr_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CTR, &camellia_192_ctr_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CTR, &camellia_256_ctr_info }, +#endif +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_CIPHER_CAMELLIA_128_GCM, &camellia_128_gcm_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_GCM, &camellia_192_gcm_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_GCM, &camellia_256_gcm_info }, +#endif +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_CIPHER_CAMELLIA_128_CCM, &camellia_128_ccm_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CCM, &camellia_192_ccm_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CCM, &camellia_256_ccm_info }, +#endif +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_ARIA_C) + { MBEDTLS_CIPHER_ARIA_128_ECB, &aria_128_ecb_info }, + { MBEDTLS_CIPHER_ARIA_192_ECB, &aria_192_ecb_info }, + { MBEDTLS_CIPHER_ARIA_256_ECB, &aria_256_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_ARIA_128_CBC, &aria_128_cbc_info }, + { MBEDTLS_CIPHER_ARIA_192_CBC, &aria_192_cbc_info }, + { MBEDTLS_CIPHER_ARIA_256_CBC, &aria_256_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_ARIA_128_CFB128, &aria_128_cfb128_info }, + { MBEDTLS_CIPHER_ARIA_192_CFB128, &aria_192_cfb128_info }, + { MBEDTLS_CIPHER_ARIA_256_CFB128, &aria_256_cfb128_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_ARIA_128_CTR, &aria_128_ctr_info }, + { MBEDTLS_CIPHER_ARIA_192_CTR, &aria_192_ctr_info }, + { MBEDTLS_CIPHER_ARIA_256_CTR, &aria_256_ctr_info }, +#endif +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_CIPHER_ARIA_128_GCM, &aria_128_gcm_info }, + { MBEDTLS_CIPHER_ARIA_192_GCM, &aria_192_gcm_info }, + { MBEDTLS_CIPHER_ARIA_256_GCM, &aria_256_gcm_info }, +#endif +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_CIPHER_ARIA_128_CCM, &aria_128_ccm_info }, + { MBEDTLS_CIPHER_ARIA_192_CCM, &aria_192_ccm_info }, + { MBEDTLS_CIPHER_ARIA_256_CCM, &aria_256_ccm_info }, +#endif +#endif /* MBEDTLS_ARIA_C */ + +#if defined(MBEDTLS_DES_C) + { MBEDTLS_CIPHER_DES_ECB, &des_ecb_info }, + { MBEDTLS_CIPHER_DES_EDE_ECB, &des_ede_ecb_info }, + { MBEDTLS_CIPHER_DES_EDE3_ECB, &des_ede3_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_DES_CBC, &des_cbc_info }, + { MBEDTLS_CIPHER_DES_EDE_CBC, &des_ede_cbc_info }, + { MBEDTLS_CIPHER_DES_EDE3_CBC, &des_ede3_cbc_info }, +#endif +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_CHACHA20_C) + { MBEDTLS_CIPHER_CHACHA20, &chacha20_info }, +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + { MBEDTLS_CIPHER_CHACHA20_POLY1305, &chachapoly_info }, +#endif + +#if defined(MBEDTLS_NIST_KW_C) + { MBEDTLS_CIPHER_AES_128_KW, &aes_128_nist_kw_info }, + { MBEDTLS_CIPHER_AES_192_KW, &aes_192_nist_kw_info }, + { MBEDTLS_CIPHER_AES_256_KW, &aes_256_nist_kw_info }, + { MBEDTLS_CIPHER_AES_128_KWP, &aes_128_nist_kwp_info }, + { MBEDTLS_CIPHER_AES_192_KWP, &aes_192_nist_kwp_info }, + { MBEDTLS_CIPHER_AES_256_KWP, &aes_256_nist_kwp_info }, +#endif + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) + { MBEDTLS_CIPHER_NULL, &null_cipher_info }, +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ + + { MBEDTLS_CIPHER_NONE, NULL } +}; + +#define NUM_CIPHERS ( sizeof(mbedtls_cipher_definitions) / \ + sizeof(mbedtls_cipher_definitions[0]) ) +int mbedtls_cipher_supported[NUM_CIPHERS]; + +#endif /* MBEDTLS_CIPHER_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/cmac.c b/FreeRTOS-Labs/Source/mbedtls/library/cmac.c new file mode 100644 index 000000000..fad7d25f8 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/cmac.c @@ -0,0 +1,1078 @@ +/** + * \file cmac.c + * + * \brief NIST SP800-38B compliant CMAC implementation for AES and 3DES + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * - NIST SP 800-38B Recommendation for Block Cipher Modes of Operation: The + * CMAC Mode for Authentication + * http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38b.pdf + * + * - RFC 4493 - The AES-CMAC Algorithm + * https://tools.ietf.org/html/rfc4493 + * + * - RFC 4615 - The Advanced Encryption Standard-Cipher-based Message + * Authentication Code-Pseudo-Random Function-128 (AES-CMAC-PRF-128) + * Algorithm for the Internet Key Exchange Protocol (IKE) + * https://tools.ietf.org/html/rfc4615 + * + * Additional test vectors: ISO/IEC 9797-1 + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CMAC_C) + +#include "mbedtls/cmac.h" +#include "mbedtls/platform_util.h" + +#include + + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#if defined(MBEDTLS_SELF_TEST) +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_SELF_TEST */ +#endif /* MBEDTLS_PLATFORM_C */ + +#if !defined(MBEDTLS_CMAC_ALT) || defined(MBEDTLS_SELF_TEST) + +/* + * Multiplication by u in the Galois field of GF(2^n) + * + * As explained in NIST SP 800-38B, this can be computed: + * + * If MSB(p) = 0, then p = (p << 1) + * If MSB(p) = 1, then p = (p << 1) ^ R_n + * with R_64 = 0x1B and R_128 = 0x87 + * + * Input and output MUST NOT point to the same buffer + * Block size must be 8 bytes or 16 bytes - the block sizes for DES and AES. + */ +static int cmac_multiply_by_u( unsigned char *output, + const unsigned char *input, + size_t blocksize ) +{ + const unsigned char R_128 = 0x87; + const unsigned char R_64 = 0x1B; + unsigned char R_n, mask; + unsigned char overflow = 0x00; + int i; + + if( blocksize == MBEDTLS_AES_BLOCK_SIZE ) + { + R_n = R_128; + } + else if( blocksize == MBEDTLS_DES3_BLOCK_SIZE ) + { + R_n = R_64; + } + else + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + for( i = (int)blocksize - 1; i >= 0; i-- ) + { + output[i] = input[i] << 1 | overflow; + overflow = input[i] >> 7; + } + + /* mask = ( input[0] >> 7 ) ? 0xff : 0x00 + * using bit operations to avoid branches */ + + /* MSVC has a warning about unary minus on unsigned, but this is + * well-defined and precisely what we want to do here */ +#if defined(_MSC_VER) +#pragma warning( push ) +#pragma warning( disable : 4146 ) +#endif + mask = - ( input[0] >> 7 ); +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif + + output[ blocksize - 1 ] ^= R_n & mask; + + return( 0 ); +} + +/* + * Generate subkeys + * + * - as specified by RFC 4493, section 2.3 Subkey Generation Algorithm + */ +static int cmac_generate_subkeys( mbedtls_cipher_context_t *ctx, + unsigned char* K1, unsigned char* K2 ) +{ + int ret; + unsigned char L[MBEDTLS_CIPHER_BLKSIZE_MAX]; + size_t olen, block_size; + + mbedtls_platform_zeroize( L, sizeof( L ) ); + + block_size = ctx->cipher_info->block_size; + + /* Calculate Ek(0) */ + if( ( ret = mbedtls_cipher_update( ctx, L, block_size, L, &olen ) ) != 0 ) + goto exit; + + /* + * Generate K1 and K2 + */ + if( ( ret = cmac_multiply_by_u( K1, L , block_size ) ) != 0 ) + goto exit; + + if( ( ret = cmac_multiply_by_u( K2, K1 , block_size ) ) != 0 ) + goto exit; + +exit: + mbedtls_platform_zeroize( L, sizeof( L ) ); + + return( ret ); +} +#endif /* !defined(MBEDTLS_CMAC_ALT) || defined(MBEDTLS_SELF_TEST) */ + +#if !defined(MBEDTLS_CMAC_ALT) +static void cmac_xor_block( unsigned char *output, const unsigned char *input1, + const unsigned char *input2, + const size_t block_size ) +{ + size_t idx; + + for( idx = 0; idx < block_size; idx++ ) + output[ idx ] = input1[ idx ] ^ input2[ idx ]; +} + +/* + * Create padded last block from (partial) last block. + * + * We can't use the padding option from the cipher layer, as it only works for + * CBC and we use ECB mode, and anyway we need to XOR K1 or K2 in addition. + */ +static void cmac_pad( unsigned char padded_block[MBEDTLS_CIPHER_BLKSIZE_MAX], + size_t padded_block_len, + const unsigned char *last_block, + size_t last_block_len ) +{ + size_t j; + + for( j = 0; j < padded_block_len; j++ ) + { + if( j < last_block_len ) + padded_block[j] = last_block[j]; + else if( j == last_block_len ) + padded_block[j] = 0x80; + else + padded_block[j] = 0x00; + } +} + +int mbedtls_cipher_cmac_starts( mbedtls_cipher_context_t *ctx, + const unsigned char *key, size_t keybits ) +{ + mbedtls_cipher_type_t type; + mbedtls_cmac_context_t *cmac_ctx; + int retval; + + if( ctx == NULL || ctx->cipher_info == NULL || key == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( ( retval = mbedtls_cipher_setkey( ctx, key, (int)keybits, + MBEDTLS_ENCRYPT ) ) != 0 ) + return( retval ); + + type = ctx->cipher_info->type; + + switch( type ) + { + case MBEDTLS_CIPHER_AES_128_ECB: + case MBEDTLS_CIPHER_AES_192_ECB: + case MBEDTLS_CIPHER_AES_256_ECB: + case MBEDTLS_CIPHER_DES_EDE3_ECB: + break; + default: + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + /* Allocated and initialise in the cipher context memory for the CMAC + * context */ + cmac_ctx = mbedtls_calloc( 1, sizeof( mbedtls_cmac_context_t ) ); + if( cmac_ctx == NULL ) + return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED ); + + ctx->cmac_ctx = cmac_ctx; + + mbedtls_platform_zeroize( cmac_ctx->state, sizeof( cmac_ctx->state ) ); + + return 0; +} + +int mbedtls_cipher_cmac_update( mbedtls_cipher_context_t *ctx, + const unsigned char *input, size_t ilen ) +{ + mbedtls_cmac_context_t* cmac_ctx; + unsigned char *state; + int ret = 0; + size_t n, j, olen, block_size; + + if( ctx == NULL || ctx->cipher_info == NULL || input == NULL || + ctx->cmac_ctx == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + cmac_ctx = ctx->cmac_ctx; + block_size = ctx->cipher_info->block_size; + state = ctx->cmac_ctx->state; + + /* Is there data still to process from the last call, that's greater in + * size than a block? */ + if( cmac_ctx->unprocessed_len > 0 && + ilen > block_size - cmac_ctx->unprocessed_len ) + { + memcpy( &cmac_ctx->unprocessed_block[cmac_ctx->unprocessed_len], + input, + block_size - cmac_ctx->unprocessed_len ); + + cmac_xor_block( state, cmac_ctx->unprocessed_block, state, block_size ); + + if( ( ret = mbedtls_cipher_update( ctx, state, block_size, state, + &olen ) ) != 0 ) + { + goto exit; + } + + input += block_size - cmac_ctx->unprocessed_len; + ilen -= block_size - cmac_ctx->unprocessed_len; + cmac_ctx->unprocessed_len = 0; + } + + /* n is the number of blocks including any final partial block */ + n = ( ilen + block_size - 1 ) / block_size; + + /* Iterate across the input data in block sized chunks, excluding any + * final partial or complete block */ + for( j = 1; j < n; j++ ) + { + cmac_xor_block( state, input, state, block_size ); + + if( ( ret = mbedtls_cipher_update( ctx, state, block_size, state, + &olen ) ) != 0 ) + goto exit; + + ilen -= block_size; + input += block_size; + } + + /* If there is data left over that wasn't aligned to a block */ + if( ilen > 0 ) + { + memcpy( &cmac_ctx->unprocessed_block[cmac_ctx->unprocessed_len], + input, + ilen ); + cmac_ctx->unprocessed_len += ilen; + } + +exit: + return( ret ); +} + +int mbedtls_cipher_cmac_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output ) +{ + mbedtls_cmac_context_t* cmac_ctx; + unsigned char *state, *last_block; + unsigned char K1[MBEDTLS_CIPHER_BLKSIZE_MAX]; + unsigned char K2[MBEDTLS_CIPHER_BLKSIZE_MAX]; + unsigned char M_last[MBEDTLS_CIPHER_BLKSIZE_MAX]; + int ret; + size_t olen, block_size; + + if( ctx == NULL || ctx->cipher_info == NULL || ctx->cmac_ctx == NULL || + output == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + cmac_ctx = ctx->cmac_ctx; + block_size = ctx->cipher_info->block_size; + state = cmac_ctx->state; + + mbedtls_platform_zeroize( K1, sizeof( K1 ) ); + mbedtls_platform_zeroize( K2, sizeof( K2 ) ); + cmac_generate_subkeys( ctx, K1, K2 ); + + last_block = cmac_ctx->unprocessed_block; + + /* Calculate last block */ + if( cmac_ctx->unprocessed_len < block_size ) + { + cmac_pad( M_last, block_size, last_block, cmac_ctx->unprocessed_len ); + cmac_xor_block( M_last, M_last, K2, block_size ); + } + else + { + /* Last block is complete block */ + cmac_xor_block( M_last, last_block, K1, block_size ); + } + + + cmac_xor_block( state, M_last, state, block_size ); + if( ( ret = mbedtls_cipher_update( ctx, state, block_size, state, + &olen ) ) != 0 ) + { + goto exit; + } + + memcpy( output, state, block_size ); + +exit: + /* Wipe the generated keys on the stack, and any other transients to avoid + * side channel leakage */ + mbedtls_platform_zeroize( K1, sizeof( K1 ) ); + mbedtls_platform_zeroize( K2, sizeof( K2 ) ); + + cmac_ctx->unprocessed_len = 0; + mbedtls_platform_zeroize( cmac_ctx->unprocessed_block, + sizeof( cmac_ctx->unprocessed_block ) ); + + mbedtls_platform_zeroize( state, MBEDTLS_CIPHER_BLKSIZE_MAX ); + return( ret ); +} + +int mbedtls_cipher_cmac_reset( mbedtls_cipher_context_t *ctx ) +{ + mbedtls_cmac_context_t* cmac_ctx; + + if( ctx == NULL || ctx->cipher_info == NULL || ctx->cmac_ctx == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + cmac_ctx = ctx->cmac_ctx; + + /* Reset the internal state */ + cmac_ctx->unprocessed_len = 0; + mbedtls_platform_zeroize( cmac_ctx->unprocessed_block, + sizeof( cmac_ctx->unprocessed_block ) ); + mbedtls_platform_zeroize( cmac_ctx->state, + sizeof( cmac_ctx->state ) ); + + return( 0 ); +} + +int mbedtls_cipher_cmac( const mbedtls_cipher_info_t *cipher_info, + const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_cipher_context_t ctx; + int ret; + + if( cipher_info == NULL || key == NULL || input == NULL || output == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + mbedtls_cipher_init( &ctx ); + + if( ( ret = mbedtls_cipher_setup( &ctx, cipher_info ) ) != 0 ) + goto exit; + + ret = mbedtls_cipher_cmac_starts( &ctx, key, keylen ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_cipher_cmac_update( &ctx, input, ilen ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_cipher_cmac_finish( &ctx, output ); + +exit: + mbedtls_cipher_free( &ctx ); + + return( ret ); +} + +#if defined(MBEDTLS_AES_C) +/* + * Implementation of AES-CMAC-PRF-128 defined in RFC 4615 + */ +int mbedtls_aes_cmac_prf_128( const unsigned char *key, size_t key_length, + const unsigned char *input, size_t in_len, + unsigned char *output ) +{ + int ret; + const mbedtls_cipher_info_t *cipher_info; + unsigned char zero_key[MBEDTLS_AES_BLOCK_SIZE]; + unsigned char int_key[MBEDTLS_AES_BLOCK_SIZE]; + + if( key == NULL || input == NULL || output == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + cipher_info = mbedtls_cipher_info_from_type( MBEDTLS_CIPHER_AES_128_ECB ); + if( cipher_info == NULL ) + { + /* Failing at this point must be due to a build issue */ + ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + goto exit; + } + + if( key_length == MBEDTLS_AES_BLOCK_SIZE ) + { + /* Use key as is */ + memcpy( int_key, key, MBEDTLS_AES_BLOCK_SIZE ); + } + else + { + memset( zero_key, 0, MBEDTLS_AES_BLOCK_SIZE ); + + ret = mbedtls_cipher_cmac( cipher_info, zero_key, 128, key, + key_length, int_key ); + if( ret != 0 ) + goto exit; + } + + ret = mbedtls_cipher_cmac( cipher_info, int_key, 128, input, in_len, + output ); + +exit: + mbedtls_platform_zeroize( int_key, sizeof( int_key ) ); + + return( ret ); +} +#endif /* MBEDTLS_AES_C */ + +#endif /* !MBEDTLS_CMAC_ALT */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * CMAC test data for SP800-38B + * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/AES_CMAC.pdf + * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/TDES_CMAC.pdf + * + * AES-CMAC-PRF-128 test data from RFC 4615 + * https://tools.ietf.org/html/rfc4615#page-4 + */ + +#define NB_CMAC_TESTS_PER_KEY 4 +#define NB_PRF_TESTS 3 + +#if defined(MBEDTLS_AES_C) || defined(MBEDTLS_DES_C) +/* All CMAC test inputs are truncated from the same 64 byte buffer. */ +static const unsigned char test_message[] = { + /* PT */ + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 +}; +#endif /* MBEDTLS_AES_C || MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) +/* Truncation point of message for AES CMAC tests */ +static const unsigned int aes_message_lengths[NB_CMAC_TESTS_PER_KEY] = { + /* Mlen */ + 0, + 16, + 20, + 64 +}; + +/* CMAC-AES128 Test Data */ +static const unsigned char aes_128_key[16] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c +}; +static const unsigned char aes_128_subkeys[2][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* K1 */ + 0xfb, 0xee, 0xd6, 0x18, 0x35, 0x71, 0x33, 0x66, + 0x7c, 0x85, 0xe0, 0x8f, 0x72, 0x36, 0xa8, 0xde + }, + { + /* K2 */ + 0xf7, 0xdd, 0xac, 0x30, 0x6a, 0xe2, 0x66, 0xcc, + 0xf9, 0x0b, 0xc1, 0x1e, 0xe4, 0x6d, 0x51, 0x3b + } +}; +static const unsigned char aes_128_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* Example #1 */ + 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, + 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 + }, + { + /* Example #2 */ + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c + }, + { + /* Example #3 */ + 0x7d, 0x85, 0x44, 0x9e, 0xa6, 0xea, 0x19, 0xc8, + 0x23, 0xa7, 0xbf, 0x78, 0x83, 0x7d, 0xfa, 0xde + }, + { + /* Example #4 */ + 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, + 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe + } +}; + +/* CMAC-AES192 Test Data */ +static const unsigned char aes_192_key[24] = { + 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, + 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b +}; +static const unsigned char aes_192_subkeys[2][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* K1 */ + 0x44, 0x8a, 0x5b, 0x1c, 0x93, 0x51, 0x4b, 0x27, + 0x3e, 0xe6, 0x43, 0x9d, 0xd4, 0xda, 0xa2, 0x96 + }, + { + /* K2 */ + 0x89, 0x14, 0xb6, 0x39, 0x26, 0xa2, 0x96, 0x4e, + 0x7d, 0xcc, 0x87, 0x3b, 0xa9, 0xb5, 0x45, 0x2c + } +}; +static const unsigned char aes_192_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* Example #1 */ + 0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5, + 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67 + }, + { + /* Example #2 */ + 0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90, + 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84 + }, + { + /* Example #3 */ + 0x3d, 0x75, 0xc1, 0x94, 0xed, 0x96, 0x07, 0x04, + 0x44, 0xa9, 0xfa, 0x7e, 0xc7, 0x40, 0xec, 0xf8 + }, + { + /* Example #4 */ + 0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79, + 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11 + } +}; + +/* CMAC-AES256 Test Data */ +static const unsigned char aes_256_key[32] = { + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 +}; +static const unsigned char aes_256_subkeys[2][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* K1 */ + 0xca, 0xd1, 0xed, 0x03, 0x29, 0x9e, 0xed, 0xac, + 0x2e, 0x9a, 0x99, 0x80, 0x86, 0x21, 0x50, 0x2f + }, + { + /* K2 */ + 0x95, 0xa3, 0xda, 0x06, 0x53, 0x3d, 0xdb, 0x58, + 0x5d, 0x35, 0x33, 0x01, 0x0c, 0x42, 0xa0, 0xd9 + } +}; +static const unsigned char aes_256_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* Example #1 */ + 0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, + 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83 + }, + { + /* Example #2 */ + 0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, + 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c + }, + { + /* Example #3 */ + 0x15, 0x67, 0x27, 0xdc, 0x08, 0x78, 0x94, 0x4a, + 0x02, 0x3c, 0x1f, 0xe0, 0x3b, 0xad, 0x6d, 0x93 + }, + { + /* Example #4 */ + 0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5, + 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10 + } +}; +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_DES_C) +/* Truncation point of message for 3DES CMAC tests */ +static const unsigned int des3_message_lengths[NB_CMAC_TESTS_PER_KEY] = { + 0, + 16, + 20, + 32 +}; + +/* CMAC-TDES (Generation) - 2 Key Test Data */ +static const unsigned char des3_2key_key[24] = { + /* Key1 */ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + /* Key2 */ + 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xEF, 0x01, + /* Key3 */ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef +}; +static const unsigned char des3_2key_subkeys[2][8] = { + { + /* K1 */ + 0x0d, 0xd2, 0xcb, 0x7a, 0x3d, 0x88, 0x88, 0xd9 + }, + { + /* K2 */ + 0x1b, 0xa5, 0x96, 0xf4, 0x7b, 0x11, 0x11, 0xb2 + } +}; +static const unsigned char des3_2key_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_DES3_BLOCK_SIZE] = { + { + /* Sample #1 */ + 0x79, 0xce, 0x52, 0xa7, 0xf7, 0x86, 0xa9, 0x60 + }, + { + /* Sample #2 */ + 0xcc, 0x18, 0xa0, 0xb7, 0x9a, 0xf2, 0x41, 0x3b + }, + { + /* Sample #3 */ + 0xc0, 0x6d, 0x37, 0x7e, 0xcd, 0x10, 0x19, 0x69 + }, + { + /* Sample #4 */ + 0x9c, 0xd3, 0x35, 0x80, 0xf9, 0xb6, 0x4d, 0xfb + } +}; + +/* CMAC-TDES (Generation) - 3 Key Test Data */ +static const unsigned char des3_3key_key[24] = { + /* Key1 */ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xaa, 0xcd, 0xef, + /* Key2 */ + 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, + /* Key3 */ + 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23 +}; +static const unsigned char des3_3key_subkeys[2][8] = { + { + /* K1 */ + 0x9d, 0x74, 0xe7, 0x39, 0x33, 0x17, 0x96, 0xc0 + }, + { + /* K2 */ + 0x3a, 0xe9, 0xce, 0x72, 0x66, 0x2f, 0x2d, 0x9b + } +}; +static const unsigned char des3_3key_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_DES3_BLOCK_SIZE] = { + { + /* Sample #1 */ + 0x7d, 0xb0, 0xd3, 0x7d, 0xf9, 0x36, 0xc5, 0x50 + }, + { + /* Sample #2 */ + 0x30, 0x23, 0x9c, 0xf1, 0xf5, 0x2e, 0x66, 0x09 + }, + { + /* Sample #3 */ + 0x6c, 0x9f, 0x3e, 0xe4, 0x92, 0x3f, 0x6b, 0xe2 + }, + { + /* Sample #4 */ + 0x99, 0x42, 0x9b, 0xd0, 0xbF, 0x79, 0x04, 0xe5 + } +}; + +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) +/* AES AES-CMAC-PRF-128 Test Data */ +static const unsigned char PRFK[] = { + /* Key */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0xed, 0xcb +}; + +/* Sizes in bytes */ +static const size_t PRFKlen[NB_PRF_TESTS] = { + 18, + 16, + 10 +}; + +/* Message */ +static const unsigned char PRFM[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13 +}; + +static const unsigned char PRFT[NB_PRF_TESTS][16] = { + { + 0x84, 0xa3, 0x48, 0xa4, 0xa4, 0x5d, 0x23, 0x5b, + 0xab, 0xff, 0xfc, 0x0d, 0x2b, 0x4d, 0xa0, 0x9a + }, + { + 0x98, 0x0a, 0xe8, 0x7b, 0x5f, 0x4c, 0x9c, 0x52, + 0x14, 0xf5, 0xb6, 0xa8, 0x45, 0x5e, 0x4c, 0x2d + }, + { + 0x29, 0x0d, 0x9e, 0x11, 0x2e, 0xdb, 0x09, 0xee, + 0x14, 0x1f, 0xcf, 0x64, 0xc0, 0xb7, 0x2f, 0x3d + } +}; +#endif /* MBEDTLS_AES_C */ + +static int cmac_test_subkeys( int verbose, + const char* testname, + const unsigned char* key, + int keybits, + const unsigned char* subkeys, + mbedtls_cipher_type_t cipher_type, + int block_size, + int num_tests ) +{ + int i, ret = 0; + mbedtls_cipher_context_t ctx; + const mbedtls_cipher_info_t *cipher_info; + unsigned char K1[MBEDTLS_CIPHER_BLKSIZE_MAX]; + unsigned char K2[MBEDTLS_CIPHER_BLKSIZE_MAX]; + + cipher_info = mbedtls_cipher_info_from_type( cipher_type ); + if( cipher_info == NULL ) + { + /* Failing at this point must be due to a build issue */ + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } + + for( i = 0; i < num_tests; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " %s CMAC subkey #%u: ", testname, i + 1 ); + + mbedtls_cipher_init( &ctx ); + + if( ( ret = mbedtls_cipher_setup( &ctx, cipher_info ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "test execution failed\n" ); + + goto cleanup; + } + + if( ( ret = mbedtls_cipher_setkey( &ctx, key, keybits, + MBEDTLS_ENCRYPT ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "test execution failed\n" ); + + goto cleanup; + } + + ret = cmac_generate_subkeys( &ctx, K1, K2 ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + goto cleanup; + } + + if( ( ret = memcmp( K1, subkeys, block_size ) ) != 0 || + ( ret = memcmp( K2, &subkeys[block_size], block_size ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + mbedtls_cipher_free( &ctx ); + } + + ret = 0; + goto exit; + +cleanup: + mbedtls_cipher_free( &ctx ); + +exit: + return( ret ); +} + +static int cmac_test_wth_cipher( int verbose, + const char* testname, + const unsigned char* key, + int keybits, + const unsigned char* messages, + const unsigned int message_lengths[4], + const unsigned char* expected_result, + mbedtls_cipher_type_t cipher_type, + int block_size, + int num_tests ) +{ + const mbedtls_cipher_info_t *cipher_info; + int i, ret = 0; + unsigned char output[MBEDTLS_CIPHER_BLKSIZE_MAX]; + + cipher_info = mbedtls_cipher_info_from_type( cipher_type ); + if( cipher_info == NULL ) + { + /* Failing at this point must be due to a build issue */ + ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + goto exit; + } + + for( i = 0; i < num_tests; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " %s CMAC #%u: ", testname, i + 1 ); + + if( ( ret = mbedtls_cipher_cmac( cipher_info, key, keybits, messages, + message_lengths[i], output ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + goto exit; + } + + if( ( ret = memcmp( output, &expected_result[i * block_size], block_size ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + ret = 0; + +exit: + return( ret ); +} + +#if defined(MBEDTLS_AES_C) +static int test_aes128_cmac_prf( int verbose ) +{ + int i; + int ret; + unsigned char output[MBEDTLS_AES_BLOCK_SIZE]; + + for( i = 0; i < NB_PRF_TESTS; i++ ) + { + mbedtls_printf( " AES CMAC 128 PRF #%u: ", i ); + ret = mbedtls_aes_cmac_prf_128( PRFK, PRFKlen[i], PRFM, 20, output ); + if( ret != 0 || + memcmp( output, PRFT[i], MBEDTLS_AES_BLOCK_SIZE ) != 0 ) + { + + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); + } + else if( verbose != 0 ) + { + mbedtls_printf( "passed\n" ); + } + } + return( ret ); +} +#endif /* MBEDTLS_AES_C */ + +int mbedtls_cmac_self_test( int verbose ) +{ + int ret; + +#if defined(MBEDTLS_AES_C) + /* AES-128 */ + if( ( ret = cmac_test_subkeys( verbose, + "AES 128", + aes_128_key, + 128, + (const unsigned char*)aes_128_subkeys, + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher( verbose, + "AES 128", + aes_128_key, + 128, + test_message, + aes_message_lengths, + (const unsigned char*)aes_128_expected_result, + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + /* AES-192 */ + if( ( ret = cmac_test_subkeys( verbose, + "AES 192", + aes_192_key, + 192, + (const unsigned char*)aes_192_subkeys, + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher( verbose, + "AES 192", + aes_192_key, + 192, + test_message, + aes_message_lengths, + (const unsigned char*)aes_192_expected_result, + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + /* AES-256 */ + if( ( ret = cmac_test_subkeys( verbose, + "AES 256", + aes_256_key, + 256, + (const unsigned char*)aes_256_subkeys, + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher ( verbose, + "AES 256", + aes_256_key, + 256, + test_message, + aes_message_lengths, + (const unsigned char*)aes_256_expected_result, + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_DES_C) + /* 3DES 2 key */ + if( ( ret = cmac_test_subkeys( verbose, + "3DES 2 key", + des3_2key_key, + 192, + (const unsigned char*)des3_2key_subkeys, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_DES3_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher( verbose, + "3DES 2 key", + des3_2key_key, + 192, + test_message, + des3_message_lengths, + (const unsigned char*)des3_2key_expected_result, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_DES3_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + /* 3DES 3 key */ + if( ( ret = cmac_test_subkeys( verbose, + "3DES 3 key", + des3_3key_key, + 192, + (const unsigned char*)des3_3key_subkeys, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_DES3_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher( verbose, + "3DES 3 key", + des3_3key_key, + 192, + test_message, + des3_message_lengths, + (const unsigned char*)des3_3key_expected_result, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_DES3_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) + if( ( ret = test_aes128_cmac_prf( verbose ) ) != 0 ) + return( ret ); +#endif /* MBEDTLS_AES_C */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CMAC_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ctr_drbg.c b/FreeRTOS-Labs/Source/mbedtls/library/ctr_drbg.c new file mode 100644 index 000000000..95de3c919 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ctr_drbg.c @@ -0,0 +1,751 @@ +/* + * CTR_DRBG implementation based on AES-256 (NIST SP 800-90) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The NIST SP 800-90 DRBGs are described in the following publication. + * + * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CTR_DRBG_C) + +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +/* + * CTR_DRBG context initialization + */ +void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +/* + * Non-public function wrapped by mbedtls_ctr_drbg_seed(). Necessary to allow + * NIST tests to succeed (which require known length fixed entropy) + */ +/* CTR_DRBG_Instantiate with derivation function (SP 800-90A §10.2.1.3.2) + * mbedtls_ctr_drbg_seed_entropy_len(ctx, f_entropy, p_entropy, + * custom, len, entropy_len) + * implements + * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string, + * security_strength) -> initial_working_state + * with inputs + * custom[:len] = nonce || personalization_string + * where entropy_input comes from f_entropy for entropy_len bytes + * and with outputs + * ctx = initial_working_state + */ +int mbedtls_ctr_drbg_seed_entropy_len( + mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len, + size_t entropy_len ) +{ + int ret; + unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE]; + + memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE ); + + mbedtls_aes_init( &ctx->aes_ctx ); + + ctx->f_entropy = f_entropy; + ctx->p_entropy = p_entropy; + + ctx->entropy_len = entropy_len; + ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL; + + /* + * Initialize with an empty key + */ + if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, key, + MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = mbedtls_ctr_drbg_reseed( ctx, custom, len ) ) != 0 ) + { + return( ret ); + } + return( 0 ); +} + +int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ) +{ + return( mbedtls_ctr_drbg_seed_entropy_len( ctx, f_entropy, p_entropy, + custom, len, + MBEDTLS_CTR_DRBG_ENTROPY_LEN ) ); +} + +void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx ) +{ + if( ctx == NULL ) + return; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif + mbedtls_aes_free( &ctx->aes_ctx ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) ); +} + +void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, + int resistance ) +{ + ctx->prediction_resistance = resistance; +} + +void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx, + size_t len ) +{ + ctx->entropy_len = len; +} + +void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx, + int interval ) +{ + ctx->reseed_interval = interval; +} + +static int block_cipher_df( unsigned char *output, + const unsigned char *data, size_t data_len ) +{ + unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + + MBEDTLS_CTR_DRBG_BLOCKSIZE + 16]; + unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE]; + unsigned char chain[MBEDTLS_CTR_DRBG_BLOCKSIZE]; + unsigned char *p, *iv; + mbedtls_aes_context aes_ctx; + int ret = 0; + + int i, j; + size_t buf_len, use_len; + + if( data_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + + MBEDTLS_CTR_DRBG_BLOCKSIZE + 16 ); + mbedtls_aes_init( &aes_ctx ); + + /* + * Construct IV (16 bytes) and S in buffer + * IV = Counter (in 32-bits) padded to 16 with zeroes + * S = Length input string (in 32-bits) || Length of output (in 32-bits) || + * data || 0x80 + * (Total is padded to a multiple of 16-bytes with zeroes) + */ + p = buf + MBEDTLS_CTR_DRBG_BLOCKSIZE; + *p++ = ( data_len >> 24 ) & 0xff; + *p++ = ( data_len >> 16 ) & 0xff; + *p++ = ( data_len >> 8 ) & 0xff; + *p++ = ( data_len ) & 0xff; + p += 3; + *p++ = MBEDTLS_CTR_DRBG_SEEDLEN; + memcpy( p, data, data_len ); + p[data_len] = 0x80; + + buf_len = MBEDTLS_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1; + + for( i = 0; i < MBEDTLS_CTR_DRBG_KEYSIZE; i++ ) + key[i] = i; + + if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, key, + MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 ) + { + goto exit; + } + + /* + * Reduce data to MBEDTLS_CTR_DRBG_SEEDLEN bytes of data + */ + for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE ) + { + p = buf; + memset( chain, 0, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + use_len = buf_len; + + while( use_len > 0 ) + { + for( i = 0; i < MBEDTLS_CTR_DRBG_BLOCKSIZE; i++ ) + chain[i] ^= p[i]; + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + use_len -= ( use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE ) ? + MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len; + + if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT, + chain, chain ) ) != 0 ) + { + goto exit; + } + } + + memcpy( tmp + j, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + + /* + * Update IV + */ + buf[3]++; + } + + /* + * Do final encryption with reduced data + */ + if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, tmp, + MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 ) + { + goto exit; + } + iv = tmp + MBEDTLS_CTR_DRBG_KEYSIZE; + p = output; + + for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE ) + { + if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT, + iv, iv ) ) != 0 ) + { + goto exit; + } + memcpy( p, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + } +exit: + mbedtls_aes_free( &aes_ctx ); + /* + * tidy up the stack + */ + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); + mbedtls_platform_zeroize( key, sizeof( key ) ); + mbedtls_platform_zeroize( chain, sizeof( chain ) ); + if( 0 != ret ) + { + /* + * wipe partial seed from memory + */ + mbedtls_platform_zeroize( output, MBEDTLS_CTR_DRBG_SEEDLEN ); + } + + return( ret ); +} + +/* CTR_DRBG_Update (SP 800-90A §10.2.1.2) + * ctr_drbg_update_internal(ctx, provided_data) + * implements + * CTR_DRBG_Update(provided_data, Key, V) + * with inputs and outputs + * ctx->aes_ctx = Key + * ctx->counter = V + */ +static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx, + const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN] ) +{ + unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char *p = tmp; + int i, j; + int ret = 0; + + memset( tmp, 0, MBEDTLS_CTR_DRBG_SEEDLEN ); + + for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE ) + { + /* + * Increase counter + */ + for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- ) + if( ++ctx->counter[i - 1] != 0 ) + break; + + /* + * Crypt counter block + */ + if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, + ctx->counter, p ) ) != 0 ) + { + goto exit; + } + + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + } + + for( i = 0; i < MBEDTLS_CTR_DRBG_SEEDLEN; i++ ) + tmp[i] ^= data[i]; + + /* + * Update key and counter + */ + if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, tmp, + MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 ) + { + goto exit; + } + memcpy( ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE, + MBEDTLS_CTR_DRBG_BLOCKSIZE ); + +exit: + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); + return( ret ); +} + +/* CTR_DRBG_Instantiate with derivation function (SP 800-90A §10.2.1.3.2) + * mbedtls_ctr_drbg_update(ctx, additional, add_len) + * implements + * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string, + * security_strength) -> initial_working_state + * with inputs + * ctx->counter = all-bits-0 + * ctx->aes_ctx = context from all-bits-0 key + * additional[:add_len] = entropy_input || nonce || personalization_string + * and with outputs + * ctx = initial_working_state + */ +int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ) +{ + unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN]; + int ret; + + if( add_len == 0 ) + return( 0 ); + + if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 ) + goto exit; + if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 ) + goto exit; + +exit: + mbedtls_platform_zeroize( add_input, sizeof( add_input ) ); + return( ret ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ) +{ + /* MAX_INPUT would be more logical here, but we have to match + * block_cipher_df()'s limits since we can't propagate errors */ + if( add_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) + add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT; + (void) mbedtls_ctr_drbg_update_ret( ctx, additional, add_len ); +} +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + +/* CTR_DRBG_Reseed with derivation function (SP 800-90A §10.2.1.4.2) + * mbedtls_ctr_drbg_reseed(ctx, additional, len) + * implements + * CTR_DRBG_Reseed(working_state, entropy_input, additional_input) + * -> new_working_state + * with inputs + * ctx contains working_state + * additional[:len] = additional_input + * and entropy_input comes from calling ctx->f_entropy + * and with output + * ctx contains new_working_state + */ +int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t len ) +{ + unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT]; + size_t seedlen = 0; + int ret; + + if( ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT || + len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len ) + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ); + + /* + * Gather entropy_len bytes of entropy to seed state + */ + if( 0 != ctx->f_entropy( ctx->p_entropy, seed, + ctx->entropy_len ) ) + { + return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED ); + } + + seedlen += ctx->entropy_len; + + /* + * Add additional data + */ + if( additional && len ) + { + memcpy( seed + seedlen, additional, len ); + seedlen += len; + } + + /* + * Reduce to 384 bits + */ + if( ( ret = block_cipher_df( seed, seed, seedlen ) ) != 0 ) + goto exit; + + /* + * Update state + */ + if( ( ret = ctr_drbg_update_internal( ctx, seed ) ) != 0 ) + goto exit; + ctx->reseed_counter = 1; + +exit: + mbedtls_platform_zeroize( seed, sizeof( seed ) ); + return( ret ); +} + +/* CTR_DRBG_Generate with derivation function (SP 800-90A §10.2.1.5.2) + * mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, additional, add_len) + * implements + * CTR_DRBG_Reseed(working_state, entropy_input, additional[:add_len]) + * -> working_state_after_reseed + * if required, then + * CTR_DRBG_Generate(working_state_after_reseed, + * requested_number_of_bits, additional_input) + * -> status, returned_bits, new_working_state + * with inputs + * ctx contains working_state + * requested_number_of_bits = 8 * output_len + * additional[:add_len] = additional_input + * and entropy_input comes from calling ctx->f_entropy + * and with outputs + * status = SUCCESS (this function does the reseed internally) + * returned_bits = output[:output_len] + * ctx contains new_working_state + */ +int mbedtls_ctr_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len ) +{ + int ret = 0; + mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng; + unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char *p = output; + unsigned char tmp[MBEDTLS_CTR_DRBG_BLOCKSIZE]; + int i; + size_t use_len; + + if( output_len > MBEDTLS_CTR_DRBG_MAX_REQUEST ) + return( MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG ); + + if( add_len > MBEDTLS_CTR_DRBG_MAX_INPUT ) + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN ); + + if( ctx->reseed_counter > ctx->reseed_interval || + ctx->prediction_resistance ) + { + if( ( ret = mbedtls_ctr_drbg_reseed( ctx, additional, add_len ) ) != 0 ) + { + return( ret ); + } + add_len = 0; + } + + if( add_len > 0 ) + { + if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 ) + goto exit; + if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 ) + goto exit; + } + + while( output_len > 0 ) + { + /* + * Increase counter + */ + for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- ) + if( ++ctx->counter[i - 1] != 0 ) + break; + + /* + * Crypt counter block + */ + if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, + ctx->counter, tmp ) ) != 0 ) + { + goto exit; + } + + use_len = ( output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE ) + ? MBEDTLS_CTR_DRBG_BLOCKSIZE : output_len; + /* + * Copy random block to destination + */ + memcpy( p, tmp, use_len ); + p += use_len; + output_len -= use_len; + } + + if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 ) + goto exit; + + ctx->reseed_counter++; + +exit: + mbedtls_platform_zeroize( add_input, sizeof( add_input ) ); + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); + return( 0 ); +} + +int mbedtls_ctr_drbg_random( void *p_rng, unsigned char *output, + size_t output_len ) +{ + int ret; + mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = mbedtls_ctr_drbg_random_with_add( ctx, output, output_len, NULL, 0 ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, + const char *path ) +{ + int ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + FILE *f; + unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); + + if( ( ret = mbedtls_ctr_drbg_random( ctx, buf, + MBEDTLS_CTR_DRBG_MAX_INPUT ) ) != 0 ) + goto exit; + + if( fwrite( buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f ) != + MBEDTLS_CTR_DRBG_MAX_INPUT ) + { + ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + } + else + { + ret = 0; + } + +exit: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + + fclose( f ); + return( ret ); +} + +int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, + const char *path ) +{ + int ret = 0; + FILE *f = NULL; + size_t n; + unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ]; + unsigned char c; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); + + n = fread( buf, 1, sizeof( buf ), f ); + if( fread( &c, 1, 1, f ) != 0 ) + { + ret = MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG; + goto exit; + } + if( n == 0 || ferror( f ) ) + { + ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + goto exit; + } + fclose( f ); + f = NULL; + + ret = mbedtls_ctr_drbg_update_ret( ctx, buf, n ); + +exit: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + if( f != NULL ) + fclose( f ); + if( ret != 0 ) + return( ret ); + return( mbedtls_ctr_drbg_write_seed_file( ctx, path ) ); +} +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char entropy_source_pr[96] = + { 0xc1, 0x80, 0x81, 0xa6, 0x5d, 0x44, 0x02, 0x16, + 0x19, 0xb3, 0xf1, 0x80, 0xb1, 0xc9, 0x20, 0x02, + 0x6a, 0x54, 0x6f, 0x0c, 0x70, 0x81, 0x49, 0x8b, + 0x6e, 0xa6, 0x62, 0x52, 0x6d, 0x51, 0xb1, 0xcb, + 0x58, 0x3b, 0xfa, 0xd5, 0x37, 0x5f, 0xfb, 0xc9, + 0xff, 0x46, 0xd2, 0x19, 0xc7, 0x22, 0x3e, 0x95, + 0x45, 0x9d, 0x82, 0xe1, 0xe7, 0x22, 0x9f, 0x63, + 0x31, 0x69, 0xd2, 0x6b, 0x57, 0x47, 0x4f, 0xa3, + 0x37, 0xc9, 0x98, 0x1c, 0x0b, 0xfb, 0x91, 0x31, + 0x4d, 0x55, 0xb9, 0xe9, 0x1c, 0x5a, 0x5e, 0xe4, + 0x93, 0x92, 0xcf, 0xc5, 0x23, 0x12, 0xd5, 0x56, + 0x2c, 0x4a, 0x6e, 0xff, 0xdc, 0x10, 0xd0, 0x68 }; + +static const unsigned char entropy_source_nopr[64] = + { 0x5a, 0x19, 0x4d, 0x5e, 0x2b, 0x31, 0x58, 0x14, + 0x54, 0xde, 0xf6, 0x75, 0xfb, 0x79, 0x58, 0xfe, + 0xc7, 0xdb, 0x87, 0x3e, 0x56, 0x89, 0xfc, 0x9d, + 0x03, 0x21, 0x7c, 0x68, 0xd8, 0x03, 0x38, 0x20, + 0xf9, 0xe6, 0x5e, 0x04, 0xd8, 0x56, 0xf3, 0xa9, + 0xc4, 0x4a, 0x4c, 0xbd, 0xc1, 0xd0, 0x08, 0x46, + 0xf5, 0x98, 0x3d, 0x77, 0x1c, 0x1b, 0x13, 0x7e, + 0x4e, 0x0f, 0x9d, 0x8e, 0xf4, 0x09, 0xf9, 0x2e }; + +static const unsigned char nonce_pers_pr[16] = + { 0xd2, 0x54, 0xfc, 0xff, 0x02, 0x1e, 0x69, 0xd2, + 0x29, 0xc9, 0xcf, 0xad, 0x85, 0xfa, 0x48, 0x6c }; + +static const unsigned char nonce_pers_nopr[16] = + { 0x1b, 0x54, 0xb8, 0xff, 0x06, 0x42, 0xbf, 0xf5, + 0x21, 0xf1, 0x5c, 0x1c, 0x0b, 0x66, 0x5f, 0x3f }; + +static const unsigned char result_pr[16] = + { 0x34, 0x01, 0x16, 0x56, 0xb4, 0x29, 0x00, 0x8f, + 0x35, 0x63, 0xec, 0xb5, 0xf2, 0x59, 0x07, 0x23 }; + +static const unsigned char result_nopr[16] = + { 0xa0, 0x54, 0x30, 0x3d, 0x8a, 0x7e, 0xa9, 0x88, + 0x9d, 0x90, 0x3e, 0x07, 0x7c, 0x6f, 0x21, 0x8f }; + +static size_t test_offset; +static int ctr_drbg_self_test_entropy( void *data, unsigned char *buf, + size_t len ) +{ + const unsigned char *p = data; + memcpy( buf, p + test_offset, len ); + test_offset += len; + return( 0 ); +} + +#define CHK( c ) if( (c) != 0 ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf( "failed\n" ); \ + return( 1 ); \ + } + +/* + * Checkup routine + */ +int mbedtls_ctr_drbg_self_test( int verbose ) +{ + mbedtls_ctr_drbg_context ctx; + unsigned char buf[16]; + + mbedtls_ctr_drbg_init( &ctx ); + + /* + * Based on a NIST CTR_DRBG test vector (PR = True) + */ + if( verbose != 0 ) + mbedtls_printf( " CTR_DRBG (PR = TRUE) : " ); + + test_offset = 0; + CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy, + (void *) entropy_source_pr, nonce_pers_pr, 16, 32 ) ); + mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); + CHK( memcmp( buf, result_pr, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); + + mbedtls_ctr_drbg_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + /* + * Based on a NIST CTR_DRBG test vector (PR = FALSE) + */ + if( verbose != 0 ) + mbedtls_printf( " CTR_DRBG (PR = FALSE): " ); + + mbedtls_ctr_drbg_init( &ctx ); + + test_offset = 0; + CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy, + (void *) entropy_source_nopr, nonce_pers_nopr, 16, 32 ) ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) ); + CHK( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) ); + CHK( memcmp( buf, result_nopr, 16 ) ); + + mbedtls_ctr_drbg_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CTR_DRBG_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/debug.c b/FreeRTOS-Labs/Source/mbedtls/library/debug.c new file mode 100644 index 000000000..bbf15fc78 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/debug.c @@ -0,0 +1,438 @@ +/* + * Debugging routines + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_DEBUG_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#define mbedtls_time_t time_t +#define mbedtls_snprintf snprintf +#define mbedtls_vsnprintf vsnprintf +#endif + +#include "mbedtls/debug.h" + +#include +#include +#include + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#define DEBUG_BUF_SIZE 512 + +static int debug_threshold = 0; + +void mbedtls_debug_set_threshold( int threshold ) +{ + debug_threshold = threshold; +} + +/* + * All calls to f_dbg must be made via this function + */ +static inline void debug_send_line( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *str ) +{ + /* + * If in a threaded environment, we need a thread identifier. + * Since there is no portable way to get one, use the address of the ssl + * context instead, as it shouldn't be shared between threads. + */ +#if defined(MBEDTLS_THREADING_C) + char idstr[20 + DEBUG_BUF_SIZE]; /* 0x + 16 nibbles + ': ' */ + mbedtls_snprintf( idstr, sizeof( idstr ), "%p: %s", (void*)ssl, str ); + ssl->conf->f_dbg( ssl->conf->p_dbg, level, file, line, idstr ); +#else + ssl->conf->f_dbg( ssl->conf->p_dbg, level, file, line, str ); +#endif +} + +void mbedtls_debug_print_msg( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *format, ... ) +{ + va_list argp; + char str[DEBUG_BUF_SIZE]; + int ret; + + if( NULL == ssl || + NULL == ssl->conf || + NULL == ssl->conf->f_dbg || + level > debug_threshold ) + { + return; + } + + va_start( argp, format ); + ret = mbedtls_vsnprintf( str, DEBUG_BUF_SIZE, format, argp ); + va_end( argp ); + + if( ret >= 0 && ret < DEBUG_BUF_SIZE - 1 ) + { + str[ret] = '\n'; + str[ret + 1] = '\0'; + } + + debug_send_line( ssl, level, file, line, str ); +} + +void mbedtls_debug_print_ret( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, int ret ) +{ + char str[DEBUG_BUF_SIZE]; + + if( NULL == ssl || + NULL == ssl->conf || + NULL == ssl->conf->f_dbg || + level > debug_threshold ) + { + return; + } + + /* + * With non-blocking I/O and examples that just retry immediately, + * the logs would be quickly flooded with WANT_READ, so ignore that. + * Don't ignore WANT_WRITE however, since is is usually rare. + */ + if( ret == MBEDTLS_ERR_SSL_WANT_READ ) + return; + + mbedtls_snprintf( str, sizeof( str ), "%s() returned %d (-0x%04x)\n", + text, ret, -ret ); + + debug_send_line( ssl, level, file, line, str ); +} + +void mbedtls_debug_print_buf( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, const char *text, + const unsigned char *buf, size_t len ) +{ + char str[DEBUG_BUF_SIZE]; + char txt[17]; + size_t i, idx = 0; + + if( NULL == ssl || + NULL == ssl->conf || + NULL == ssl->conf->f_dbg || + level > debug_threshold ) + { + return; + } + + mbedtls_snprintf( str + idx, sizeof( str ) - idx, "dumping '%s' (%u bytes)\n", + text, (unsigned int) len ); + + debug_send_line( ssl, level, file, line, str ); + + idx = 0; + memset( txt, 0, sizeof( txt ) ); + for( i = 0; i < len; i++ ) + { + if( i >= 4096 ) + break; + + if( i % 16 == 0 ) + { + if( i > 0 ) + { + mbedtls_snprintf( str + idx, sizeof( str ) - idx, " %s\n", txt ); + debug_send_line( ssl, level, file, line, str ); + + idx = 0; + memset( txt, 0, sizeof( txt ) ); + } + + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, "%04x: ", + (unsigned int) i ); + + } + + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " %02x", + (unsigned int) buf[i] ); + txt[i % 16] = ( buf[i] > 31 && buf[i] < 127 ) ? buf[i] : '.' ; + } + + if( len > 0 ) + { + for( /* i = i */; i % 16 != 0; i++ ) + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " " ); + + mbedtls_snprintf( str + idx, sizeof( str ) - idx, " %s\n", txt ); + debug_send_line( ssl, level, file, line, str ); + } +} + +#if defined(MBEDTLS_ECP_C) +void mbedtls_debug_print_ecp( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_ecp_point *X ) +{ + char str[DEBUG_BUF_SIZE]; + + if( NULL == ssl || + NULL == ssl->conf || + NULL == ssl->conf->f_dbg || + level > debug_threshold ) + { + return; + } + + mbedtls_snprintf( str, sizeof( str ), "%s(X)", text ); + mbedtls_debug_print_mpi( ssl, level, file, line, str, &X->X ); + + mbedtls_snprintf( str, sizeof( str ), "%s(Y)", text ); + mbedtls_debug_print_mpi( ssl, level, file, line, str, &X->Y ); +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_BIGNUM_C) +void mbedtls_debug_print_mpi( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_mpi *X ) +{ + char str[DEBUG_BUF_SIZE]; + int j, k, zeros = 1; + size_t i, n, idx = 0; + + if( NULL == ssl || + NULL == ssl->conf || + NULL == ssl->conf->f_dbg || + NULL == X || + level > debug_threshold ) + { + return; + } + + for( n = X->n - 1; n > 0; n-- ) + if( X->p[n] != 0 ) + break; + + for( j = ( sizeof(mbedtls_mpi_uint) << 3 ) - 1; j >= 0; j-- ) + if( ( ( X->p[n] >> j ) & 1 ) != 0 ) + break; + + mbedtls_snprintf( str + idx, sizeof( str ) - idx, "value of '%s' (%d bits) is:\n", + text, (int) ( ( n * ( sizeof(mbedtls_mpi_uint) << 3 ) ) + j + 1 ) ); + + debug_send_line( ssl, level, file, line, str ); + + idx = 0; + for( i = n + 1, j = 0; i > 0; i-- ) + { + if( zeros && X->p[i - 1] == 0 ) + continue; + + for( k = sizeof( mbedtls_mpi_uint ) - 1; k >= 0; k-- ) + { + if( zeros && ( ( X->p[i - 1] >> ( k << 3 ) ) & 0xFF ) == 0 ) + continue; + else + zeros = 0; + + if( j % 16 == 0 ) + { + if( j > 0 ) + { + mbedtls_snprintf( str + idx, sizeof( str ) - idx, "\n" ); + debug_send_line( ssl, level, file, line, str ); + idx = 0; + } + } + + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " %02x", (unsigned int) + ( X->p[i - 1] >> ( k << 3 ) ) & 0xFF ); + + j++; + } + + } + + if( zeros == 1 ) + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " 00" ); + + mbedtls_snprintf( str + idx, sizeof( str ) - idx, "\n" ); + debug_send_line( ssl, level, file, line, str ); +} +#endif /* MBEDTLS_BIGNUM_C */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +static void debug_print_pk( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_pk_context *pk ) +{ + size_t i; + mbedtls_pk_debug_item items[MBEDTLS_PK_DEBUG_MAX_ITEMS]; + char name[16]; + + memset( items, 0, sizeof( items ) ); + + if( mbedtls_pk_debug( pk, items ) != 0 ) + { + debug_send_line( ssl, level, file, line, + "invalid PK context\n" ); + return; + } + + for( i = 0; i < MBEDTLS_PK_DEBUG_MAX_ITEMS; i++ ) + { + if( items[i].type == MBEDTLS_PK_DEBUG_NONE ) + return; + + mbedtls_snprintf( name, sizeof( name ), "%s%s", text, items[i].name ); + name[sizeof( name ) - 1] = '\0'; + + if( items[i].type == MBEDTLS_PK_DEBUG_MPI ) + mbedtls_debug_print_mpi( ssl, level, file, line, name, items[i].value ); + else +#if defined(MBEDTLS_ECP_C) + if( items[i].type == MBEDTLS_PK_DEBUG_ECP ) + mbedtls_debug_print_ecp( ssl, level, file, line, name, items[i].value ); + else +#endif + debug_send_line( ssl, level, file, line, + "should not happen\n" ); + } +} + +static void debug_print_line_by_line( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, const char *text ) +{ + char str[DEBUG_BUF_SIZE]; + const char *start, *cur; + + start = text; + for( cur = text; *cur != '\0'; cur++ ) + { + if( *cur == '\n' ) + { + size_t len = cur - start + 1; + if( len > DEBUG_BUF_SIZE - 1 ) + len = DEBUG_BUF_SIZE - 1; + + memcpy( str, start, len ); + str[len] = '\0'; + + debug_send_line( ssl, level, file, line, str ); + + start = cur + 1; + } + } +} + +void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_x509_crt *crt ) +{ + char str[DEBUG_BUF_SIZE]; + int i = 0; + + if( NULL == ssl || + NULL == ssl->conf || + NULL == ssl->conf->f_dbg || + NULL == crt || + level > debug_threshold ) + { + return; + } + + while( crt != NULL ) + { + char buf[1024]; + + mbedtls_snprintf( str, sizeof( str ), "%s #%d:\n", text, ++i ); + debug_send_line( ssl, level, file, line, str ); + + mbedtls_x509_crt_info( buf, sizeof( buf ) - 1, "", crt ); + debug_print_line_by_line( ssl, level, file, line, buf ); + + debug_print_pk( ssl, level, file, line, "crt->", &crt->pk ); + + crt = crt->next; + } +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_ECDH_C) +static void mbedtls_debug_printf_ecdh_internal( const mbedtls_ssl_context *ssl, + int level, const char *file, + int line, + const mbedtls_ecdh_context *ecdh, + mbedtls_debug_ecdh_attr attr ) +{ +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + const mbedtls_ecdh_context* ctx = ecdh; +#else + const mbedtls_ecdh_context_mbed* ctx = &ecdh->ctx.mbed_ecdh; +#endif + + switch( attr ) + { + case MBEDTLS_DEBUG_ECDH_Q: + mbedtls_debug_print_ecp( ssl, level, file, line, "ECDH: Q", + &ctx->Q ); + break; + case MBEDTLS_DEBUG_ECDH_QP: + mbedtls_debug_print_ecp( ssl, level, file, line, "ECDH: Qp", + &ctx->Qp ); + break; + case MBEDTLS_DEBUG_ECDH_Z: + mbedtls_debug_print_mpi( ssl, level, file, line, "ECDH: z", + &ctx->z ); + break; + default: + break; + } +} + +void mbedtls_debug_printf_ecdh( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const mbedtls_ecdh_context *ecdh, + mbedtls_debug_ecdh_attr attr ) +{ +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + mbedtls_debug_printf_ecdh_internal( ssl, level, file, line, ecdh, attr ); +#else + switch( ecdh->var ) + { + default: + mbedtls_debug_printf_ecdh_internal( ssl, level, file, line, ecdh, + attr ); + } +#endif +} +#endif /* MBEDTLS_ECDH_C */ + +#endif /* MBEDTLS_DEBUG_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/des.c b/FreeRTOS-Labs/Source/mbedtls/library/des.c new file mode 100644 index 000000000..5246c5d26 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/des.c @@ -0,0 +1,1064 @@ +/* + * FIPS-46-3 compliant Triple-DES implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * DES, on which TDES is based, was originally designed by Horst Feistel + * at IBM in 1974, and was adopted as a standard by NIST (formerly NBS). + * + * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_DES_C) + +#include "mbedtls/des.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_DES_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * Expanded DES S-boxes + */ +static const uint32_t SB1[64] = +{ + 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 +}; + +static const uint32_t SB2[64] = +{ + 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 +}; + +static const uint32_t SB3[64] = +{ + 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 +}; + +static const uint32_t SB4[64] = +{ + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 +}; + +static const uint32_t SB5[64] = +{ + 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 +}; + +static const uint32_t SB6[64] = +{ + 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 +}; + +static const uint32_t SB7[64] = +{ + 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 +}; + +static const uint32_t SB8[64] = +{ + 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 +}; + +/* + * PC1: left and right halves bit-swap + */ +static const uint32_t LHs[16] = +{ + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static const uint32_t RHs[16] = +{ + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100, + 0x00000001, 0x01000001, 0x00010001, 0x01010001, + 0x00000101, 0x01000101, 0x00010101, 0x01010101, +}; + +/* + * Initial Permutation macro + */ +#define DES_IP(X,Y) \ + do \ + { \ + T = (((X) >> 4) ^ (Y)) & 0x0F0F0F0F; (Y) ^= T; (X) ^= (T << 4); \ + T = (((X) >> 16) ^ (Y)) & 0x0000FFFF; (Y) ^= T; (X) ^= (T << 16); \ + T = (((Y) >> 2) ^ (X)) & 0x33333333; (X) ^= T; (Y) ^= (T << 2); \ + T = (((Y) >> 8) ^ (X)) & 0x00FF00FF; (X) ^= T; (Y) ^= (T << 8); \ + (Y) = (((Y) << 1) | ((Y) >> 31)) & 0xFFFFFFFF; \ + T = ((X) ^ (Y)) & 0xAAAAAAAA; (Y) ^= T; (X) ^= T; \ + (X) = (((X) << 1) | ((X) >> 31)) & 0xFFFFFFFF; \ + } while( 0 ) + +/* + * Final Permutation macro + */ +#define DES_FP(X,Y) \ + do \ + { \ + (X) = (((X) << 31) | ((X) >> 1)) & 0xFFFFFFFF; \ + T = ((X) ^ (Y)) & 0xAAAAAAAA; (X) ^= T; (Y) ^= T; \ + (Y) = (((Y) << 31) | ((Y) >> 1)) & 0xFFFFFFFF; \ + T = (((Y) >> 8) ^ (X)) & 0x00FF00FF; (X) ^= T; (Y) ^= (T << 8); \ + T = (((Y) >> 2) ^ (X)) & 0x33333333; (X) ^= T; (Y) ^= (T << 2); \ + T = (((X) >> 16) ^ (Y)) & 0x0000FFFF; (Y) ^= T; (X) ^= (T << 16); \ + T = (((X) >> 4) ^ (Y)) & 0x0F0F0F0F; (Y) ^= T; (X) ^= (T << 4); \ + } while( 0 ) + +/* + * DES round macro + */ +#define DES_ROUND(X,Y) \ + do \ + { \ + T = *SK++ ^ (X); \ + (Y) ^= SB8[ (T ) & 0x3F ] ^ \ + SB6[ (T >> 8) & 0x3F ] ^ \ + SB4[ (T >> 16) & 0x3F ] ^ \ + SB2[ (T >> 24) & 0x3F ]; \ + \ + T = *SK++ ^ (((X) << 28) | ((X) >> 4)); \ + (Y) ^= SB7[ (T ) & 0x3F ] ^ \ + SB5[ (T >> 8) & 0x3F ] ^ \ + SB3[ (T >> 16) & 0x3F ] ^ \ + SB1[ (T >> 24) & 0x3F ]; \ + } while( 0 ) + +#define SWAP(a,b) \ + do \ + { \ + uint32_t t = (a); (a) = (b); (b) = t; t = 0; \ + } while( 0 ) + +void mbedtls_des_init( mbedtls_des_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_des_context ) ); +} + +void mbedtls_des_free( mbedtls_des_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_des_context ) ); +} + +void mbedtls_des3_init( mbedtls_des3_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_des3_context ) ); +} + +void mbedtls_des3_free( mbedtls_des3_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_des3_context ) ); +} + +static const unsigned char odd_parity_table[128] = { 1, 2, 4, 7, 8, + 11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31, 32, 35, 37, 38, 41, 42, 44, + 47, 49, 50, 52, 55, 56, 59, 61, 62, 64, 67, 69, 70, 73, 74, 76, 79, 81, + 82, 84, 87, 88, 91, 93, 94, 97, 98, 100, 103, 104, 107, 109, 110, 112, + 115, 117, 118, 121, 122, 124, 127, 128, 131, 133, 134, 137, 138, 140, + 143, 145, 146, 148, 151, 152, 155, 157, 158, 161, 162, 164, 167, 168, + 171, 173, 174, 176, 179, 181, 182, 185, 186, 188, 191, 193, 194, 196, + 199, 200, 203, 205, 206, 208, 211, 213, 214, 217, 218, 220, 223, 224, + 227, 229, 230, 233, 234, 236, 239, 241, 242, 244, 247, 248, 251, 253, + 254 }; + +void mbedtls_des_key_set_parity( unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < MBEDTLS_DES_KEY_SIZE; i++ ) + key[i] = odd_parity_table[key[i] / 2]; +} + +/* + * Check the given key's parity, returns 1 on failure, 0 on SUCCESS + */ +int mbedtls_des_key_check_key_parity( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < MBEDTLS_DES_KEY_SIZE; i++ ) + if( key[i] != odd_parity_table[key[i] / 2] ) + return( 1 ); + + return( 0 ); +} + +/* + * Table of weak and semi-weak keys + * + * Source: http://en.wikipedia.org/wiki/Weak_key + * + * Weak: + * Alternating ones + zeros (0x0101010101010101) + * Alternating 'F' + 'E' (0xFEFEFEFEFEFEFEFE) + * '0xE0E0E0E0F1F1F1F1' + * '0x1F1F1F1F0E0E0E0E' + * + * Semi-weak: + * 0x011F011F010E010E and 0x1F011F010E010E01 + * 0x01E001E001F101F1 and 0xE001E001F101F101 + * 0x01FE01FE01FE01FE and 0xFE01FE01FE01FE01 + * 0x1FE01FE00EF10EF1 and 0xE01FE01FF10EF10E + * 0x1FFE1FFE0EFE0EFE and 0xFE1FFE1FFE0EFE0E + * 0xE0FEE0FEF1FEF1FE and 0xFEE0FEE0FEF1FEF1 + * + */ + +#define WEAK_KEY_COUNT 16 + +static const unsigned char weak_key_table[WEAK_KEY_COUNT][MBEDTLS_DES_KEY_SIZE] = +{ + { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE }, + { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E }, + { 0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1 }, + + { 0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E }, + { 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01 }, + { 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1 }, + { 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01 }, + { 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE }, + { 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01 }, + { 0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1 }, + { 0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E }, + { 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE }, + { 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E }, + { 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE }, + { 0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1 } +}; + +int mbedtls_des_key_check_weak( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < WEAK_KEY_COUNT; i++ ) + if( memcmp( weak_key_table[i], key, MBEDTLS_DES_KEY_SIZE) == 0 ) + return( 1 ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DES_SETKEY_ALT) +void mbedtls_des_setkey( uint32_t SK[32], const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + uint32_t X, Y, T; + + GET_UINT32_BE( X, key, 0 ); + GET_UINT32_BE( Y, key, 4 ); + + /* + * Permuted Choice 1 + */ + T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); + T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); + + X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) + | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) + | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) + | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); + + Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) + | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) + | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) + | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); + + X &= 0x0FFFFFFF; + Y &= 0x0FFFFFFF; + + /* + * calculate subkeys + */ + for( i = 0; i < 16; i++ ) + { + if( i < 2 || i == 8 || i == 15 ) + { + X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; + Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; + } + else + { + X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; + Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; + } + + *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) + | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) + | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) + | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) + | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) + | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) + | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) + | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) + | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) + | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) + | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); + + *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) + | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) + | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) + | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) + | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) + | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) + | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) + | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) + | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) + | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) + | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); + } +} +#endif /* !MBEDTLS_DES_SETKEY_ALT */ + +/* + * DES key schedule (56-bit, encryption) + */ +int mbedtls_des_setkey_enc( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + mbedtls_des_setkey( ctx->sk, key ); + + return( 0 ); +} + +/* + * DES key schedule (56-bit, decryption) + */ +int mbedtls_des_setkey_dec( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + mbedtls_des_setkey( ctx->sk, key ); + + for( i = 0; i < 16; i += 2 ) + { + SWAP( ctx->sk[i ], ctx->sk[30 - i] ); + SWAP( ctx->sk[i + 1], ctx->sk[31 - i] ); + } + + return( 0 ); +} + +static void des3_set2key( uint32_t esk[96], + uint32_t dsk[96], + const unsigned char key[MBEDTLS_DES_KEY_SIZE*2] ) +{ + int i; + + mbedtls_des_setkey( esk, key ); + mbedtls_des_setkey( dsk + 32, key + 8 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[30 - i]; + dsk[i + 1] = esk[31 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + esk[i + 64] = esk[i ]; + esk[i + 65] = esk[i + 1]; + + dsk[i + 64] = dsk[i ]; + dsk[i + 65] = dsk[i + 1]; + } +} + +/* + * Triple-DES key schedule (112-bit, encryption) + */ +int mbedtls_des3_set2key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ) +{ + uint32_t sk[96]; + + des3_set2key( ctx->sk, sk, key ); + mbedtls_platform_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +/* + * Triple-DES key schedule (112-bit, decryption) + */ +int mbedtls_des3_set2key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ) +{ + uint32_t sk[96]; + + des3_set2key( sk, ctx->sk, key ); + mbedtls_platform_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +static void des3_set3key( uint32_t esk[96], + uint32_t dsk[96], + const unsigned char key[24] ) +{ + int i; + + mbedtls_des_setkey( esk, key ); + mbedtls_des_setkey( dsk + 32, key + 8 ); + mbedtls_des_setkey( esk + 64, key + 16 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[94 - i]; + dsk[i + 1] = esk[95 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + dsk[i + 64] = esk[30 - i]; + dsk[i + 65] = esk[31 - i]; + } +} + +/* + * Triple-DES key schedule (168-bit, encryption) + */ +int mbedtls_des3_set3key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ) +{ + uint32_t sk[96]; + + des3_set3key( ctx->sk, sk, key ); + mbedtls_platform_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +/* + * Triple-DES key schedule (168-bit, decryption) + */ +int mbedtls_des3_set3key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ) +{ + uint32_t sk[96]; + + des3_set3key( sk, ctx->sk, key ); + mbedtls_platform_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +/* + * DES-ECB block encryption/decryption + */ +#if !defined(MBEDTLS_DES_CRYPT_ECB_ALT) +int mbedtls_des_crypt_ecb( mbedtls_des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + uint32_t X, Y, T, *SK; + + SK = ctx->sk; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); + + return( 0 ); +} +#endif /* !MBEDTLS_DES_CRYPT_ECB_ALT */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * DES-CBC buffer encryption/decryption + */ +int mbedtls_des_crypt_cbc( mbedtls_des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_des_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* MBEDTLS_DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + mbedtls_des_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/* + * 3DES-ECB block encryption/decryption + */ +#if !defined(MBEDTLS_DES3_CRYPT_ECB_ALT) +int mbedtls_des3_crypt_ecb( mbedtls_des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + uint32_t X, Y, T, *SK; + + SK = ctx->sk; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( X, Y ); + DES_ROUND( Y, X ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); + + return( 0 ); +} +#endif /* !MBEDTLS_DES3_CRYPT_ECB_ALT */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * 3DES-CBC buffer encryption/decryption + */ +int mbedtls_des3_crypt_cbc( mbedtls_des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_des3_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* MBEDTLS_DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + mbedtls_des3_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#endif /* !MBEDTLS_DES_ALT */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * DES and 3DES test vectors from: + * + * http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip + */ +static const unsigned char des3_test_keys[24] = +{ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, + 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23 +}; + +static const unsigned char des3_test_buf[8] = +{ + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74 +}; + +static const unsigned char des3_test_ecb_dec[3][8] = +{ + { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D }, + { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB }, + { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A } +}; + +static const unsigned char des3_test_ecb_enc[3][8] = +{ + { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B }, + { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 }, + { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 } +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const unsigned char des3_test_iv[8] = +{ + 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, +}; + +static const unsigned char des3_test_cbc_dec[3][8] = +{ + { 0x12, 0x9F, 0x40, 0xB9, 0xD2, 0x00, 0x56, 0xB3 }, + { 0x47, 0x0E, 0xFC, 0x9A, 0x6B, 0x8E, 0xE3, 0x93 }, + { 0xC5, 0xCE, 0xCF, 0x63, 0xEC, 0xEC, 0x51, 0x4C } +}; + +static const unsigned char des3_test_cbc_enc[3][8] = +{ + { 0x54, 0xF1, 0x5A, 0xF6, 0xEB, 0xE3, 0xA4, 0xB4 }, + { 0x35, 0x76, 0x11, 0x56, 0x5F, 0xA1, 0x8E, 0x4D }, + { 0xCB, 0x19, 0x1F, 0x85, 0xD1, 0xED, 0x84, 0x39 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/* + * Checkup routine + */ +int mbedtls_des_self_test( int verbose ) +{ + int i, j, u, v, ret = 0; + mbedtls_des_context ctx; + mbedtls_des3_context ctx3; + unsigned char buf[8]; +#if defined(MBEDTLS_CIPHER_MODE_CBC) + unsigned char prv[8]; + unsigned char iv[8]; +#endif + + mbedtls_des_init( &ctx ); + mbedtls_des3_init( &ctx3 ); + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " DES%c-ECB-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == MBEDTLS_DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + mbedtls_des_setkey_dec( &ctx, des3_test_keys ); + break; + + case 1: + mbedtls_des_setkey_enc( &ctx, des3_test_keys ); + break; + + case 2: + mbedtls_des3_set2key_dec( &ctx3, des3_test_keys ); + break; + + case 3: + mbedtls_des3_set2key_enc( &ctx3, des3_test_keys ); + break; + + case 4: + mbedtls_des3_set3key_dec( &ctx3, des3_test_keys ); + break; + + case 5: + mbedtls_des3_set3key_enc( &ctx3, des3_test_keys ); + break; + + default: + return( 1 ); + } + + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + mbedtls_des_crypt_ecb( &ctx, buf, buf ); + else + mbedtls_des3_crypt_ecb( &ctx3, buf, buf ); + } + + if( ( v == MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_ecb_dec[u], 8 ) != 0 ) || + ( v != MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_ecb_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " DES%c-CBC-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == MBEDTLS_DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, des3_test_iv, 8 ); + memcpy( prv, des3_test_iv, 8 ); + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + mbedtls_des_setkey_dec( &ctx, des3_test_keys ); + break; + + case 1: + mbedtls_des_setkey_enc( &ctx, des3_test_keys ); + break; + + case 2: + mbedtls_des3_set2key_dec( &ctx3, des3_test_keys ); + break; + + case 3: + mbedtls_des3_set2key_enc( &ctx3, des3_test_keys ); + break; + + case 4: + mbedtls_des3_set3key_dec( &ctx3, des3_test_keys ); + break; + + case 5: + mbedtls_des3_set3key_enc( &ctx3, des3_test_keys ); + break; + + default: + return( 1 ); + } + + if( v == MBEDTLS_DES_DECRYPT ) + { + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + mbedtls_des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + mbedtls_des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + } + } + else + { + for( j = 0; j < 10000; j++ ) + { + unsigned char tmp[8]; + + if( u == 0 ) + mbedtls_des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + mbedtls_des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + + memcpy( tmp, prv, 8 ); + memcpy( prv, buf, 8 ); + memcpy( buf, tmp, 8 ); + } + + memcpy( buf, prv, 8 ); + } + + if( ( v == MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_cbc_dec[u], 8 ) != 0 ) || + ( v != MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_cbc_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_des_free( &ctx ); + mbedtls_des3_free( &ctx3 ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DES_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/dhm.c b/FreeRTOS-Labs/Source/mbedtls/library/dhm.c new file mode 100644 index 000000000..3d4199bb5 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/dhm.c @@ -0,0 +1,696 @@ +/* + * Diffie-Hellman-Merkle key exchange + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The following sources were referenced in the design of this implementation + * of the Diffie-Hellman-Merkle algorithm: + * + * [1] Handbook of Applied Cryptography - 1997, Chapter 12 + * Menezes, van Oorschot and Vanstone + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_DHM_C) + +#include "mbedtls/dhm.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_ASN1_PARSE_C) +#include "mbedtls/asn1.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if !defined(MBEDTLS_DHM_ALT) + +#define DHM_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_DHM_BAD_INPUT_DATA ) +#define DHM_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +/* + * helper to validate the mbedtls_mpi size and import it + */ +static int dhm_read_bignum( mbedtls_mpi *X, + unsigned char **p, + const unsigned char *end ) +{ + int ret, n; + + if( end - *p < 2 ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + n = ( (*p)[0] << 8 ) | (*p)[1]; + (*p) += 2; + + if( (int)( end - *p ) < n ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_mpi_read_binary( X, *p, n ) ) != 0 ) + return( MBEDTLS_ERR_DHM_READ_PARAMS_FAILED + ret ); + + (*p) += n; + + return( 0 ); +} + +/* + * Verify sanity of parameter with regards to P + * + * Parameter should be: 2 <= public_param <= P - 2 + * + * This means that we need to return an error if + * public_param < 2 or public_param > P-2 + * + * For more information on the attack, see: + * http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf + * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643 + */ +static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P ) +{ + mbedtls_mpi L, U; + int ret = 0; + + mbedtls_mpi_init( &L ); mbedtls_mpi_init( &U ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &L, 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) ); + + if( mbedtls_mpi_cmp_mpi( param, &L ) < 0 || + mbedtls_mpi_cmp_mpi( param, &U ) > 0 ) + { + ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA; + } + +cleanup: + mbedtls_mpi_free( &L ); mbedtls_mpi_free( &U ); + return( ret ); +} + +void mbedtls_dhm_init( mbedtls_dhm_context *ctx ) +{ + DHM_VALIDATE( ctx != NULL ); + memset( ctx, 0, sizeof( mbedtls_dhm_context ) ); +} + +/* + * Parse the ServerKeyExchange parameters + */ +int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx, + unsigned char **p, + const unsigned char *end ) +{ + int ret; + DHM_VALIDATE_RET( ctx != NULL ); + DHM_VALIDATE_RET( p != NULL && *p != NULL ); + DHM_VALIDATE_RET( end != NULL ); + + if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 || + ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 || + ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 ) + return( ret ); + + if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) + return( ret ); + + ctx->len = mbedtls_mpi_size( &ctx->P ); + + return( 0 ); +} + +/* + * Setup and write the ServerKeyExchange parameters + */ +int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size, + unsigned char *output, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, count = 0; + size_t n1, n2, n3; + unsigned char *p; + DHM_VALIDATE_RET( ctx != NULL ); + DHM_VALIDATE_RET( output != NULL ); + DHM_VALIDATE_RET( olen != NULL ); + DHM_VALIDATE_RET( f_rng != NULL ); + + if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + /* + * Generate X as large as possible ( < P ) + */ + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) ); + + while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED ); + } + while( dhm_check_range( &ctx->X, &ctx->P ) != 0 ); + + /* + * Calculate GX = G^X mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, + &ctx->P , &ctx->RP ) ); + + if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 ) + return( ret ); + + /* + * export P, G, GX + */ +#define DHM_MPI_EXPORT( X, n ) \ + do { \ + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( ( X ), \ + p + 2, \ + ( n ) ) ); \ + *p++ = (unsigned char)( ( n ) >> 8 ); \ + *p++ = (unsigned char)( ( n ) ); \ + p += ( n ); \ + } while( 0 ) + + n1 = mbedtls_mpi_size( &ctx->P ); + n2 = mbedtls_mpi_size( &ctx->G ); + n3 = mbedtls_mpi_size( &ctx->GX ); + + p = output; + DHM_MPI_EXPORT( &ctx->P , n1 ); + DHM_MPI_EXPORT( &ctx->G , n2 ); + DHM_MPI_EXPORT( &ctx->GX, n3 ); + + *olen = p - output; + + ctx->len = n1; + +cleanup: + + if( ret != 0 ) + return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + ret ); + + return( 0 ); +} + +/* + * Set prime modulus and generator + */ +int mbedtls_dhm_set_group( mbedtls_dhm_context *ctx, + const mbedtls_mpi *P, + const mbedtls_mpi *G ) +{ + int ret; + DHM_VALIDATE_RET( ctx != NULL ); + DHM_VALIDATE_RET( P != NULL ); + DHM_VALIDATE_RET( G != NULL ); + + if( ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 || + ( ret = mbedtls_mpi_copy( &ctx->G, G ) ) != 0 ) + { + return( MBEDTLS_ERR_DHM_SET_GROUP_FAILED + ret ); + } + + ctx->len = mbedtls_mpi_size( &ctx->P ); + return( 0 ); +} + +/* + * Import the peer's public value G^Y + */ +int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx, + const unsigned char *input, size_t ilen ) +{ + int ret; + DHM_VALIDATE_RET( ctx != NULL ); + DHM_VALIDATE_RET( input != NULL ); + + if( ilen < 1 || ilen > ctx->len ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 ) + return( MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED + ret ); + + return( 0 ); +} + +/* + * Create own private value X and export G^X + */ +int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size, + unsigned char *output, size_t olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, count = 0; + DHM_VALIDATE_RET( ctx != NULL ); + DHM_VALIDATE_RET( output != NULL ); + DHM_VALIDATE_RET( f_rng != NULL ); + + if( olen < 1 || olen > ctx->len ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + /* + * generate X and calculate GX = G^X mod P + */ + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ) ); + + while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED ); + } + while( dhm_check_range( &ctx->X, &ctx->P ) != 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, + &ctx->P , &ctx->RP ) ); + + if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 ) + return( ret ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) ); + +cleanup: + + if( ret != 0 ) + return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED + ret ); + + return( 0 ); +} + +/* + * Use the blinding method and optimisation suggested in section 10 of: + * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, + * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer + * Berlin Heidelberg, 1996. p. 104-113. + */ +static int dhm_update_blinding( mbedtls_dhm_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret, count; + + /* + * Don't use any blinding the first time a particular X is used, + * but remember it to use blinding next time. + */ + if( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->pX ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &ctx->pX, &ctx->X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vi, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vf, 1 ) ); + + return( 0 ); + } + + /* + * Ok, we need blinding. Can we re-use existing values? + * If yes, just update them by squaring them. + */ + if( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) ); + + return( 0 ); + } + + /* + * We need to generate blinding values from scratch + */ + + /* Vi = random( 2, P-1 ) */ + count = 0; + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vi, mbedtls_mpi_size( &ctx->P ), f_rng, p_rng ) ); + + while( mbedtls_mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->Vi, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + } + while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) <= 0 ); + + /* Vf = Vi^-X mod P */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vf, &ctx->Vi, &ctx->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) ); + +cleanup: + return( ret ); +} + +/* + * Derive and export the shared secret (G^Y)^X mod P + */ +int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx, + unsigned char *output, size_t output_size, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_mpi GYb; + DHM_VALIDATE_RET( ctx != NULL ); + DHM_VALIDATE_RET( output != NULL ); + DHM_VALIDATE_RET( olen != NULL ); + + if( output_size < ctx->len ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) + return( ret ); + + mbedtls_mpi_init( &GYb ); + + /* Blind peer's value */ + if( f_rng != NULL ) + { + MBEDTLS_MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &GYb, &GYb, &ctx->P ) ); + } + else + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &GYb, &ctx->GY ) ); + + /* Do modular exponentiation */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->K, &GYb, &ctx->X, + &ctx->P, &ctx->RP ) ); + + /* Unblind secret value */ + if( f_rng != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) ); + } + + *olen = mbedtls_mpi_size( &ctx->K ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) ); + +cleanup: + mbedtls_mpi_free( &GYb ); + + if( ret != 0 ) + return( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED + ret ); + + return( 0 ); +} + +/* + * Free the components of a DHM key + */ +void mbedtls_dhm_free( mbedtls_dhm_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_mpi_free( &ctx->pX ); + mbedtls_mpi_free( &ctx->Vf ); + mbedtls_mpi_free( &ctx->Vi ); + mbedtls_mpi_free( &ctx->RP ); + mbedtls_mpi_free( &ctx->K ); + mbedtls_mpi_free( &ctx->GY ); + mbedtls_mpi_free( &ctx->GX ); + mbedtls_mpi_free( &ctx->X ); + mbedtls_mpi_free( &ctx->G ); + mbedtls_mpi_free( &ctx->P ); + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_dhm_context ) ); +} + +#if defined(MBEDTLS_ASN1_PARSE_C) +/* + * Parse DHM parameters + */ +int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin, + size_t dhminlen ) +{ + int ret; + size_t len; + unsigned char *p, *end; +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_context pem; +#endif /* MBEDTLS_PEM_PARSE_C */ + + DHM_VALIDATE_RET( dhm != NULL ); + DHM_VALIDATE_RET( dhmin != NULL ); + +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_init( &pem ); + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( dhminlen == 0 || dhmin[dhminlen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN DH PARAMETERS-----", + "-----END DH PARAMETERS-----", + dhmin, NULL, 0, &dhminlen ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + dhminlen = pem.buflen; + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + goto exit; + + p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin; +#else + p = (unsigned char *) dhmin; +#endif /* MBEDTLS_PEM_PARSE_C */ + end = p + dhminlen; + + /* + * DHParams ::= SEQUENCE { + * prime INTEGER, -- P + * generator INTEGER, -- g + * privateValueLength INTEGER OPTIONAL + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; + goto exit; + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->P ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->G ) ) != 0 ) + { + ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; + goto exit; + } + + if( p != end ) + { + /* This might be the optional privateValueLength. + * If so, we can cleanly discard it */ + mbedtls_mpi rec; + mbedtls_mpi_init( &rec ); + ret = mbedtls_asn1_get_mpi( &p, end, &rec ); + mbedtls_mpi_free( &rec ); + if ( ret != 0 ) + { + ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; + goto exit; + } + if ( p != end ) + { + ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + goto exit; + } + } + + ret = 0; + + dhm->len = mbedtls_mpi_size( &dhm->P ); + +exit: +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_free( &pem ); +#endif + if( ret != 0 ) + mbedtls_dhm_free( dhm ); + + return( ret ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Load all data from a file into a given buffer. + * + * The file is expected to contain either PEM or DER encoded data. + * A terminating null byte is always appended. It is included in the announced + * length only if the data looks like it is PEM encoded. + */ +static int load_file( const char *path, unsigned char **buf, size_t *n ) +{ + FILE *f; + long size; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + if( ( size = ftell( f ) ) == -1 ) + { + fclose( f ); + return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); + } + fseek( f, 0, SEEK_SET ); + + *n = (size_t) size; + + if( *n + 1 == 0 || + ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL ) + { + fclose( f ); + return( MBEDTLS_ERR_DHM_ALLOC_FAILED ); + } + + if( fread( *buf, 1, *n, f ) != *n ) + { + fclose( f ); + + mbedtls_platform_zeroize( *buf, *n + 1 ); + mbedtls_free( *buf ); + + return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); + } + + fclose( f ); + + (*buf)[*n] = '\0'; + + if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL ) + ++*n; + + return( 0 ); +} + +/* + * Load and parse DHM parameters + */ +int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + DHM_VALIDATE_RET( dhm != NULL ); + DHM_VALIDATE_RET( path != NULL ); + + if( ( ret = load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_dhm_parse_dhm( dhm, buf, n ); + + mbedtls_platform_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ +#endif /* MBEDTLS_ASN1_PARSE_C */ +#endif /* MBEDTLS_DHM_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +static const char mbedtls_test_dhm_params[] = +"-----BEGIN DH PARAMETERS-----\r\n" +"MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n" +"1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n" +"9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n" +"-----END DH PARAMETERS-----\r\n"; + +static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params ); + +/* + * Checkup routine + */ +int mbedtls_dhm_self_test( int verbose ) +{ + int ret; + mbedtls_dhm_context dhm; + + mbedtls_dhm_init( &dhm ); + + if( verbose != 0 ) + mbedtls_printf( " DHM parameter load: " ); + + if( ( ret = mbedtls_dhm_parse_dhm( &dhm, + (const unsigned char *) mbedtls_test_dhm_params, + mbedtls_test_dhm_params_len ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n\n" ); + +exit: + mbedtls_dhm_free( &dhm ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DHM_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ecdh.c b/FreeRTOS-Labs/Source/mbedtls/library/ecdh.c new file mode 100644 index 000000000..1b1967a20 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ecdh.c @@ -0,0 +1,680 @@ +/* + * Elliptic curve Diffie-Hellman + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * SEC1 http://www.secg.org/index.php?action=secg,docs_secg + * RFC 4492 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECDH_C) + +#include "mbedtls/ecdh.h" +#include "mbedtls/platform_util.h" + +#include + +/* Parameter validation macros based on platform_util.h */ +#define ECDH_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) +#define ECDH_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) +typedef mbedtls_ecdh_context mbedtls_ecdh_context_mbed; +#endif + +static mbedtls_ecp_group_id mbedtls_ecdh_grp_id( + const mbedtls_ecdh_context *ctx ) +{ +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ctx->grp.id ); +#else + return( ctx->grp_id ); +#endif +} + +#if !defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT) +/* + * Generate public key (restartable version) + * + * Note: this internal function relies on its caller preserving the value of + * the output parameter 'd' across continuation calls. This would not be + * acceptable for a public function but is OK here as we control call sites. + */ +static int ecdh_gen_public_restartable( mbedtls_ecp_group *grp, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx ) +{ + int ret; + + /* If multiplication is in progress, we already generated a privkey */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx == NULL || rs_ctx->rsm == NULL ) +#endif + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, Q, d, &grp->G, + f_rng, p_rng, rs_ctx ) ); + +cleanup: + return( ret ); +} + +/* + * Generate public key + */ +int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + ECDH_VALIDATE_RET( grp != NULL ); + ECDH_VALIDATE_RET( d != NULL ); + ECDH_VALIDATE_RET( Q != NULL ); + ECDH_VALIDATE_RET( f_rng != NULL ); + return( ecdh_gen_public_restartable( grp, d, Q, f_rng, p_rng, NULL ) ); +} +#endif /* !MBEDTLS_ECDH_GEN_PUBLIC_ALT */ + +#if !defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) +/* + * Compute shared secret (SEC1 3.3.1) + */ +static int ecdh_compute_shared_restartable( mbedtls_ecp_group *grp, + mbedtls_mpi *z, + const mbedtls_ecp_point *Q, const mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx ) +{ + int ret; + mbedtls_ecp_point P; + + mbedtls_ecp_point_init( &P ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &P, d, Q, + f_rng, p_rng, rs_ctx ) ); + + if( mbedtls_ecp_is_zero( &P ) ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( z, &P.X ) ); + +cleanup: + mbedtls_ecp_point_free( &P ); + + return( ret ); +} + +/* + * Compute shared secret (SEC1 3.3.1) + */ +int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, + const mbedtls_ecp_point *Q, const mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + ECDH_VALIDATE_RET( grp != NULL ); + ECDH_VALIDATE_RET( Q != NULL ); + ECDH_VALIDATE_RET( d != NULL ); + ECDH_VALIDATE_RET( z != NULL ); + return( ecdh_compute_shared_restartable( grp, z, Q, d, + f_rng, p_rng, NULL ) ); +} +#endif /* !MBEDTLS_ECDH_COMPUTE_SHARED_ALT */ + +static void ecdh_init_internal( mbedtls_ecdh_context_mbed *ctx ) +{ + mbedtls_ecp_group_init( &ctx->grp ); + mbedtls_mpi_init( &ctx->d ); + mbedtls_ecp_point_init( &ctx->Q ); + mbedtls_ecp_point_init( &ctx->Qp ); + mbedtls_mpi_init( &ctx->z ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_init( &ctx->rs ); +#endif +} + +/* + * Initialize context + */ +void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ) +{ + ECDH_VALIDATE( ctx != NULL ); + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + ecdh_init_internal( ctx ); + mbedtls_ecp_point_init( &ctx->Vi ); + mbedtls_ecp_point_init( &ctx->Vf ); + mbedtls_mpi_init( &ctx->_d ); +#else + memset( ctx, 0, sizeof( mbedtls_ecdh_context ) ); + + ctx->var = MBEDTLS_ECDH_VARIANT_NONE; +#endif + ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; +#if defined(MBEDTLS_ECP_RESTARTABLE) + ctx->restart_enabled = 0; +#endif +} + +static int ecdh_setup_internal( mbedtls_ecdh_context_mbed *ctx, + mbedtls_ecp_group_id grp_id ) +{ + int ret; + + ret = mbedtls_ecp_group_load( &ctx->grp, grp_id ); + if( ret != 0 ) + { + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + } + + return( 0 ); +} + +/* + * Setup context + */ +int mbedtls_ecdh_setup( mbedtls_ecdh_context *ctx, mbedtls_ecp_group_id grp_id ) +{ + ECDH_VALIDATE_RET( ctx != NULL ); + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_setup_internal( ctx, grp_id ) ); +#else + switch( grp_id ) + { + default: + ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; + ctx->var = MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0; + ctx->grp_id = grp_id; + ecdh_init_internal( &ctx->ctx.mbed_ecdh ); + return( ecdh_setup_internal( &ctx->ctx.mbed_ecdh, grp_id ) ); + } +#endif +} + +static void ecdh_free_internal( mbedtls_ecdh_context_mbed *ctx ) +{ + mbedtls_ecp_group_free( &ctx->grp ); + mbedtls_mpi_free( &ctx->d ); + mbedtls_ecp_point_free( &ctx->Q ); + mbedtls_ecp_point_free( &ctx->Qp ); + mbedtls_mpi_free( &ctx->z ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_free( &ctx->rs ); +#endif +} + +#if defined(MBEDTLS_ECP_RESTARTABLE) +/* + * Enable restartable operations for context + */ +void mbedtls_ecdh_enable_restart( mbedtls_ecdh_context *ctx ) +{ + ECDH_VALIDATE( ctx != NULL ); + + ctx->restart_enabled = 1; +} +#endif + +/* + * Free context + */ +void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ) +{ + if( ctx == NULL ) + return; + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + mbedtls_ecp_point_free( &ctx->Vi ); + mbedtls_ecp_point_free( &ctx->Vf ); + mbedtls_mpi_free( &ctx->_d ); + ecdh_free_internal( ctx ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + ecdh_free_internal( &ctx->ctx.mbed_ecdh ); + break; + default: + break; + } + + ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; + ctx->var = MBEDTLS_ECDH_VARIANT_NONE; + ctx->grp_id = MBEDTLS_ECP_DP_NONE; +#endif +} + +static int ecdh_make_params_internal( mbedtls_ecdh_context_mbed *ctx, + size_t *olen, int point_format, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, + unsigned char *, + size_t), + void *p_rng, + int restart_enabled ) +{ + int ret; + size_t grp_len, pt_len; +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_ctx *rs_ctx = NULL; +#endif + + if( ctx->grp.pbits == 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( restart_enabled ) + rs_ctx = &ctx->rs; +#else + (void) restart_enabled; +#endif + + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng, rs_ctx ) ) != 0 ) + return( ret ); +#else + if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng ) ) != 0 ) + return( ret ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf, + blen ) ) != 0 ) + return( ret ); + + buf += grp_len; + blen -= grp_len; + + if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format, + &pt_len, buf, blen ) ) != 0 ) + return( ret ); + + *olen = grp_len + pt_len; + return( 0 ); +} + +/* + * Setup and write the ServerKeyExhange parameters (RFC 4492) + * struct { + * ECParameters curve_params; + * ECPoint public; + * } ServerECDHParams; + */ +int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int restart_enabled = 0; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( olen != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + ECDH_VALIDATE_RET( f_rng != NULL ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + restart_enabled = ctx->restart_enabled; +#else + (void) restart_enabled; +#endif + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_make_params_internal( ctx, olen, ctx->point_format, buf, blen, + f_rng, p_rng, restart_enabled ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_make_params_internal( &ctx->ctx.mbed_ecdh, olen, + ctx->point_format, buf, blen, + f_rng, p_rng, + restart_enabled ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_read_params_internal( mbedtls_ecdh_context_mbed *ctx, + const unsigned char **buf, + const unsigned char *end ) +{ + return( mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf, + end - *buf ) ); +} + +/* + * Read the ServerKeyExhange parameters (RFC 4492) + * struct { + * ECParameters curve_params; + * ECPoint public; + * } ServerECDHParams; + */ +int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, + const unsigned char **buf, + const unsigned char *end ) +{ + int ret; + mbedtls_ecp_group_id grp_id; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + ECDH_VALIDATE_RET( *buf != NULL ); + ECDH_VALIDATE_RET( end != NULL ); + + if( ( ret = mbedtls_ecp_tls_read_group_id( &grp_id, buf, end - *buf ) ) + != 0 ) + return( ret ); + + if( ( ret = mbedtls_ecdh_setup( ctx, grp_id ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_read_params_internal( ctx, buf, end ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_read_params_internal( &ctx->ctx.mbed_ecdh, + buf, end ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_get_params_internal( mbedtls_ecdh_context_mbed *ctx, + const mbedtls_ecp_keypair *key, + mbedtls_ecdh_side side ) +{ + int ret; + + /* If it's not our key, just import the public part as Qp */ + if( side == MBEDTLS_ECDH_THEIRS ) + return( mbedtls_ecp_copy( &ctx->Qp, &key->Q ) ); + + /* Our key: import public (as Q) and private parts */ + if( side != MBEDTLS_ECDH_OURS ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 || + ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Get parameters from a keypair + */ +int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, + const mbedtls_ecp_keypair *key, + mbedtls_ecdh_side side ) +{ + int ret; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( key != NULL ); + ECDH_VALIDATE_RET( side == MBEDTLS_ECDH_OURS || + side == MBEDTLS_ECDH_THEIRS ); + + if( mbedtls_ecdh_grp_id( ctx ) == MBEDTLS_ECP_DP_NONE ) + { + /* This is the first call to get_params(). Set up the context + * for use with the group. */ + if( ( ret = mbedtls_ecdh_setup( ctx, key->grp.id ) ) != 0 ) + return( ret ); + } + else + { + /* This is not the first call to get_params(). Check that the + * current key's group is the same as the context's, which was set + * from the first key's group. */ + if( mbedtls_ecdh_grp_id( ctx ) != key->grp.id ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_get_params_internal( ctx, key, side ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_get_params_internal( &ctx->ctx.mbed_ecdh, + key, side ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_make_public_internal( mbedtls_ecdh_context_mbed *ctx, + size_t *olen, int point_format, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, + unsigned char *, + size_t), + void *p_rng, + int restart_enabled ) +{ + int ret; +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_ctx *rs_ctx = NULL; +#endif + + if( ctx->grp.pbits == 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( restart_enabled ) + rs_ctx = &ctx->rs; +#else + (void) restart_enabled; +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( ( ret = ecdh_gen_public_restartable( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng, rs_ctx ) ) != 0 ) + return( ret ); +#else + if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, + f_rng, p_rng ) ) != 0 ) + return( ret ); +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, point_format, olen, + buf, blen ); +} + +/* + * Setup and export the client public value + */ +int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int restart_enabled = 0; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( olen != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + ECDH_VALIDATE_RET( f_rng != NULL ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + restart_enabled = ctx->restart_enabled; +#endif + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_make_public_internal( ctx, olen, ctx->point_format, buf, blen, + f_rng, p_rng, restart_enabled ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_make_public_internal( &ctx->ctx.mbed_ecdh, olen, + ctx->point_format, buf, blen, + f_rng, p_rng, + restart_enabled ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_read_public_internal( mbedtls_ecdh_context_mbed *ctx, + const unsigned char *buf, size_t blen ) +{ + int ret; + const unsigned char *p = buf; + + if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p, + blen ) ) != 0 ) + return( ret ); + + if( (size_t)( p - buf ) != blen ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + return( 0 ); +} + +/* + * Parse and import the client's public value + */ +int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, + const unsigned char *buf, size_t blen ) +{ + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_read_public_internal( ctx, buf, blen ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_read_public_internal( &ctx->ctx.mbed_ecdh, + buf, blen ) ); + default: + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } +#endif +} + +static int ecdh_calc_secret_internal( mbedtls_ecdh_context_mbed *ctx, + size_t *olen, unsigned char *buf, + size_t blen, + int (*f_rng)(void *, + unsigned char *, + size_t), + void *p_rng, + int restart_enabled ) +{ + int ret; +#if defined(MBEDTLS_ECP_RESTARTABLE) + mbedtls_ecp_restart_ctx *rs_ctx = NULL; +#endif + + if( ctx == NULL || ctx->grp.pbits == 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( restart_enabled ) + rs_ctx = &ctx->rs; +#else + (void) restart_enabled; +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( ( ret = ecdh_compute_shared_restartable( &ctx->grp, &ctx->z, &ctx->Qp, + &ctx->d, f_rng, p_rng, + rs_ctx ) ) != 0 ) + { + return( ret ); + } +#else + if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp, + &ctx->d, f_rng, p_rng ) ) != 0 ) + { + return( ret ); + } +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + if( mbedtls_mpi_size( &ctx->z ) > blen ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + *olen = ctx->grp.pbits / 8 + ( ( ctx->grp.pbits % 8 ) != 0 ); + + if( mbedtls_ecp_get_type( &ctx->grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY ) + return mbedtls_mpi_write_binary_le( &ctx->z, buf, *olen ); + + return mbedtls_mpi_write_binary( &ctx->z, buf, *olen ); +} + +/* + * Derive and export the shared secret + */ +int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int restart_enabled = 0; + ECDH_VALIDATE_RET( ctx != NULL ); + ECDH_VALIDATE_RET( olen != NULL ); + ECDH_VALIDATE_RET( buf != NULL ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + restart_enabled = ctx->restart_enabled; +#endif + +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + return( ecdh_calc_secret_internal( ctx, olen, buf, blen, f_rng, p_rng, + restart_enabled ) ); +#else + switch( ctx->var ) + { + case MBEDTLS_ECDH_VARIANT_MBEDTLS_2_0: + return( ecdh_calc_secret_internal( &ctx->ctx.mbed_ecdh, olen, buf, + blen, f_rng, p_rng, + restart_enabled ) ); + default: + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } +#endif +} + +#endif /* MBEDTLS_ECDH_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ecdsa.c b/FreeRTOS-Labs/Source/mbedtls/library/ecdsa.c new file mode 100644 index 000000000..6b60834e5 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ecdsa.c @@ -0,0 +1,899 @@ +/* + * Elliptic curve DSA + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * SEC1 http://www.secg.org/index.php?action=secg,docs_secg + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECDSA_C) + +#include "mbedtls/ecdsa.h" +#include "mbedtls/asn1write.h" + +#include + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +#include "mbedtls/hmac_drbg.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/platform_util.h" + +/* Parameter validation macros based on platform_util.h */ +#define ECDSA_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) +#define ECDSA_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if defined(MBEDTLS_ECP_RESTARTABLE) + +/* + * Sub-context for ecdsa_verify() + */ +struct mbedtls_ecdsa_restart_ver +{ + mbedtls_mpi u1, u2; /* intermediate values */ + enum { /* what to do next? */ + ecdsa_ver_init = 0, /* getting started */ + ecdsa_ver_muladd, /* muladd step */ + } state; +}; + +/* + * Init verify restart sub-context + */ +static void ecdsa_restart_ver_init( mbedtls_ecdsa_restart_ver_ctx *ctx ) +{ + mbedtls_mpi_init( &ctx->u1 ); + mbedtls_mpi_init( &ctx->u2 ); + ctx->state = ecdsa_ver_init; +} + +/* + * Free the components of a verify restart sub-context + */ +static void ecdsa_restart_ver_free( mbedtls_ecdsa_restart_ver_ctx *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_mpi_free( &ctx->u1 ); + mbedtls_mpi_free( &ctx->u2 ); + + ecdsa_restart_ver_init( ctx ); +} + +/* + * Sub-context for ecdsa_sign() + */ +struct mbedtls_ecdsa_restart_sig +{ + int sign_tries; + int key_tries; + mbedtls_mpi k; /* per-signature random */ + mbedtls_mpi r; /* r value */ + enum { /* what to do next? */ + ecdsa_sig_init = 0, /* getting started */ + ecdsa_sig_mul, /* doing ecp_mul() */ + ecdsa_sig_modn, /* mod N computations */ + } state; +}; + +/* + * Init verify sign sub-context + */ +static void ecdsa_restart_sig_init( mbedtls_ecdsa_restart_sig_ctx *ctx ) +{ + ctx->sign_tries = 0; + ctx->key_tries = 0; + mbedtls_mpi_init( &ctx->k ); + mbedtls_mpi_init( &ctx->r ); + ctx->state = ecdsa_sig_init; +} + +/* + * Free the components of a sign restart sub-context + */ +static void ecdsa_restart_sig_free( mbedtls_ecdsa_restart_sig_ctx *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_mpi_free( &ctx->k ); + mbedtls_mpi_free( &ctx->r ); +} + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/* + * Sub-context for ecdsa_sign_det() + */ +struct mbedtls_ecdsa_restart_det +{ + mbedtls_hmac_drbg_context rng_ctx; /* DRBG state */ + enum { /* what to do next? */ + ecdsa_det_init = 0, /* getting started */ + ecdsa_det_sign, /* make signature */ + } state; +}; + +/* + * Init verify sign_det sub-context + */ +static void ecdsa_restart_det_init( mbedtls_ecdsa_restart_det_ctx *ctx ) +{ + mbedtls_hmac_drbg_init( &ctx->rng_ctx ); + ctx->state = ecdsa_det_init; +} + +/* + * Free the components of a sign_det restart sub-context + */ +static void ecdsa_restart_det_free( mbedtls_ecdsa_restart_det_ctx *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_hmac_drbg_free( &ctx->rng_ctx ); + + ecdsa_restart_det_init( ctx ); +} +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +#define ECDSA_RS_ECP &rs_ctx->ecp + +/* Utility macro for checking and updating ops budget */ +#define ECDSA_BUDGET( ops ) \ + MBEDTLS_MPI_CHK( mbedtls_ecp_check_budget( grp, &rs_ctx->ecp, ops ) ); + +/* Call this when entering a function that needs its own sub-context */ +#define ECDSA_RS_ENTER( SUB ) do { \ + /* reset ops count for this call if top-level */ \ + if( rs_ctx != NULL && rs_ctx->ecp.depth++ == 0 ) \ + rs_ctx->ecp.ops_done = 0; \ + \ + /* set up our own sub-context if needed */ \ + if( mbedtls_ecp_restart_is_enabled() && \ + rs_ctx != NULL && rs_ctx->SUB == NULL ) \ + { \ + rs_ctx->SUB = mbedtls_calloc( 1, sizeof( *rs_ctx->SUB ) ); \ + if( rs_ctx->SUB == NULL ) \ + return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); \ + \ + ecdsa_restart_## SUB ##_init( rs_ctx->SUB ); \ + } \ +} while( 0 ) + +/* Call this when leaving a function that needs its own sub-context */ +#define ECDSA_RS_LEAVE( SUB ) do { \ + /* clear our sub-context when not in progress (done or error) */ \ + if( rs_ctx != NULL && rs_ctx->SUB != NULL && \ + ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) \ + { \ + ecdsa_restart_## SUB ##_free( rs_ctx->SUB ); \ + mbedtls_free( rs_ctx->SUB ); \ + rs_ctx->SUB = NULL; \ + } \ + \ + if( rs_ctx != NULL ) \ + rs_ctx->ecp.depth--; \ +} while( 0 ) + +#else /* MBEDTLS_ECP_RESTARTABLE */ + +#define ECDSA_RS_ECP NULL + +#define ECDSA_BUDGET( ops ) /* no-op; for compatibility */ + +#define ECDSA_RS_ENTER( SUB ) (void) rs_ctx +#define ECDSA_RS_LEAVE( SUB ) (void) rs_ctx + +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +/* + * Derive a suitable integer for group grp from a buffer of length len + * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3 + */ +static int derive_mpi( const mbedtls_ecp_group *grp, mbedtls_mpi *x, + const unsigned char *buf, size_t blen ) +{ + int ret; + size_t n_size = ( grp->nbits + 7 ) / 8; + size_t use_size = blen > n_size ? n_size : blen; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( x, buf, use_size ) ); + if( use_size * 8 > grp->nbits ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( x, use_size * 8 - grp->nbits ) ); + + /* While at it, reduce modulo N */ + if( mbedtls_mpi_cmp_mpi( x, &grp->N ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( x, x, &grp->N ) ); + +cleanup: + return( ret ); +} + +#if !defined(MBEDTLS_ECDSA_SIGN_ALT) +/* + * Compute ECDSA signature of a hashed message (SEC1 4.1.3) + * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) + */ +static int ecdsa_sign_restartable( mbedtls_ecp_group *grp, + mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_ecdsa_restart_ctx *rs_ctx ) +{ + int ret, key_tries, sign_tries; + int *p_sign_tries = &sign_tries, *p_key_tries = &key_tries; + mbedtls_ecp_point R; + mbedtls_mpi k, e, t; + mbedtls_mpi *pk = &k, *pr = r; + + /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ + if( grp->N.p == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* Make sure d is in range 1..n-1 */ + if( mbedtls_mpi_cmp_int( d, 1 ) < 0 || mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + mbedtls_ecp_point_init( &R ); + mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t ); + + ECDSA_RS_ENTER( sig ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->sig != NULL ) + { + /* redirect to our context */ + p_sign_tries = &rs_ctx->sig->sign_tries; + p_key_tries = &rs_ctx->sig->key_tries; + pk = &rs_ctx->sig->k; + pr = &rs_ctx->sig->r; + + /* jump to current step */ + if( rs_ctx->sig->state == ecdsa_sig_mul ) + goto mul; + if( rs_ctx->sig->state == ecdsa_sig_modn ) + goto modn; + } +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + *p_sign_tries = 0; + do + { + if( *p_sign_tries++ > 10 ) + { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + + /* + * Steps 1-3: generate a suitable ephemeral keypair + * and set r = xR mod n + */ + *p_key_tries = 0; + do + { + if( *p_key_tries++ > 10 ) + { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, pk, f_rng, p_rng ) ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->sig != NULL ) + rs_ctx->sig->state = ecdsa_sig_mul; + +mul: +#endif + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, &R, pk, &grp->G, + f_rng, p_rng, ECDSA_RS_ECP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pr, &R.X, &grp->N ) ); + } + while( mbedtls_mpi_cmp_int( pr, 0 ) == 0 ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->sig != NULL ) + rs_ctx->sig->state = ecdsa_sig_modn; + +modn: +#endif + /* + * Accounting for everything up to the end of the loop + * (step 6, but checking now avoids saving e and t) + */ + ECDSA_BUDGET( MBEDTLS_ECP_OPS_INV + 4 ); + + /* + * Step 5: derive MPI from hashed message + */ + MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); + + /* + * Generate a random value to blind inv_mod in next step, + * avoiding a potential timing leak. + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, &t, f_rng, p_rng ) ); + + /* + * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, pr, d ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &e, &e, s ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &e, &e, &t ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pk, pk, &t ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, pk, &grp->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) ); + } + while( mbedtls_mpi_cmp_int( s, 0 ) == 0 ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->sig != NULL ) + mbedtls_mpi_copy( r, pr ); +#endif + +cleanup: + mbedtls_ecp_point_free( &R ); + mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t ); + + ECDSA_RS_LEAVE( sig ); + + return( ret ); +} + +/* + * Compute ECDSA signature of a hashed message + */ +int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + ECDSA_VALIDATE_RET( grp != NULL ); + ECDSA_VALIDATE_RET( r != NULL ); + ECDSA_VALIDATE_RET( s != NULL ); + ECDSA_VALIDATE_RET( d != NULL ); + ECDSA_VALIDATE_RET( f_rng != NULL ); + ECDSA_VALIDATE_RET( buf != NULL || blen == 0 ); + + return( ecdsa_sign_restartable( grp, r, s, d, buf, blen, + f_rng, p_rng, NULL ) ); +} +#endif /* !MBEDTLS_ECDSA_SIGN_ALT */ + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/* + * Deterministic signature wrapper + */ +static int ecdsa_sign_det_restartable( mbedtls_ecp_group *grp, + mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg, + mbedtls_ecdsa_restart_ctx *rs_ctx ) +{ + int ret; + mbedtls_hmac_drbg_context rng_ctx; + mbedtls_hmac_drbg_context *p_rng = &rng_ctx; + unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES]; + size_t grp_len = ( grp->nbits + 7 ) / 8; + const mbedtls_md_info_t *md_info; + mbedtls_mpi h; + + if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &h ); + mbedtls_hmac_drbg_init( &rng_ctx ); + + ECDSA_RS_ENTER( det ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->det != NULL ) + { + /* redirect to our context */ + p_rng = &rs_ctx->det->rng_ctx; + + /* jump to current step */ + if( rs_ctx->det->state == ecdsa_det_sign ) + goto sign; + } +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + /* Use private key and message hash (reduced) to initialize HMAC_DRBG */ + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, data, grp_len ) ); + MBEDTLS_MPI_CHK( derive_mpi( grp, &h, buf, blen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) ); + mbedtls_hmac_drbg_seed_buf( p_rng, md_info, data, 2 * grp_len ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->det != NULL ) + rs_ctx->det->state = ecdsa_det_sign; + +sign: +#endif +#if defined(MBEDTLS_ECDSA_SIGN_ALT) + ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen, + mbedtls_hmac_drbg_random, p_rng ); +#else + ret = ecdsa_sign_restartable( grp, r, s, d, buf, blen, + mbedtls_hmac_drbg_random, p_rng, rs_ctx ); +#endif /* MBEDTLS_ECDSA_SIGN_ALT */ + +cleanup: + mbedtls_hmac_drbg_free( &rng_ctx ); + mbedtls_mpi_free( &h ); + + ECDSA_RS_LEAVE( det ); + + return( ret ); +} + +/* + * Deterministic signature wrapper + */ +int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg ) +{ + ECDSA_VALIDATE_RET( grp != NULL ); + ECDSA_VALIDATE_RET( r != NULL ); + ECDSA_VALIDATE_RET( s != NULL ); + ECDSA_VALIDATE_RET( d != NULL ); + ECDSA_VALIDATE_RET( buf != NULL || blen == 0 ); + + return( ecdsa_sign_det_restartable( grp, r, s, d, buf, blen, md_alg, NULL ) ); +} +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +#if !defined(MBEDTLS_ECDSA_VERIFY_ALT) +/* + * Verify ECDSA signature of hashed message (SEC1 4.1.4) + * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message) + */ +static int ecdsa_verify_restartable( mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, + const mbedtls_mpi *r, const mbedtls_mpi *s, + mbedtls_ecdsa_restart_ctx *rs_ctx ) +{ + int ret; + mbedtls_mpi e, s_inv, u1, u2; + mbedtls_ecp_point R; + mbedtls_mpi *pu1 = &u1, *pu2 = &u2; + + mbedtls_ecp_point_init( &R ); + mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv ); + mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 ); + + /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ + if( grp->N.p == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + ECDSA_RS_ENTER( ver ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->ver != NULL ) + { + /* redirect to our context */ + pu1 = &rs_ctx->ver->u1; + pu2 = &rs_ctx->ver->u2; + + /* jump to current step */ + if( rs_ctx->ver->state == ecdsa_ver_muladd ) + goto muladd; + } +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + /* + * Step 1: make sure r and s are in range 1..n-1 + */ + if( mbedtls_mpi_cmp_int( r, 1 ) < 0 || mbedtls_mpi_cmp_mpi( r, &grp->N ) >= 0 || + mbedtls_mpi_cmp_int( s, 1 ) < 0 || mbedtls_mpi_cmp_mpi( s, &grp->N ) >= 0 ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + + /* + * Step 3: derive MPI from hashed message + */ + MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); + + /* + * Step 4: u1 = e / s mod n, u2 = r / s mod n + */ + ECDSA_BUDGET( MBEDTLS_ECP_OPS_CHK + MBEDTLS_ECP_OPS_INV + 2 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu1, &e, &s_inv ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu1, pu1, &grp->N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( pu2, r, &s_inv ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( pu2, pu2, &grp->N ) ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->ver != NULL ) + rs_ctx->ver->state = ecdsa_ver_muladd; + +muladd: +#endif + /* + * Step 5: R = u1 G + u2 Q + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd_restartable( grp, + &R, pu1, &grp->G, pu2, Q, ECDSA_RS_ECP ) ); + + if( mbedtls_ecp_is_zero( &R ) ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + + /* + * Step 6: convert xR to an integer (no-op) + * Step 7: reduce xR mod n (gives v) + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &R.X, &R.X, &grp->N ) ); + + /* + * Step 8: check if v (that is, R.X) is equal to r + */ + if( mbedtls_mpi_cmp_mpi( &R.X, r ) != 0 ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free( &R ); + mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv ); + mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 ); + + ECDSA_RS_LEAVE( ver ); + + return( ret ); +} + +/* + * Verify ECDSA signature of hashed message + */ +int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, + const mbedtls_mpi *r, + const mbedtls_mpi *s) +{ + ECDSA_VALIDATE_RET( grp != NULL ); + ECDSA_VALIDATE_RET( Q != NULL ); + ECDSA_VALIDATE_RET( r != NULL ); + ECDSA_VALIDATE_RET( s != NULL ); + ECDSA_VALIDATE_RET( buf != NULL || blen == 0 ); + + return( ecdsa_verify_restartable( grp, buf, blen, Q, r, s, NULL ) ); +} +#endif /* !MBEDTLS_ECDSA_VERIFY_ALT */ + +/* + * Convert a signature (given by context) to ASN.1 + */ +static int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, + unsigned char *sig, size_t *slen ) +{ + int ret; + unsigned char buf[MBEDTLS_ECDSA_MAX_LEN]; + unsigned char *p = buf + sizeof( buf ); + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, s ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, r ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &p, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &p, buf, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); + + memcpy( sig, p, len ); + *slen = len; + + return( 0 ); +} + +/* + * Compute and write signature + */ +int mbedtls_ecdsa_write_signature_restartable( mbedtls_ecdsa_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecdsa_restart_ctx *rs_ctx ) +{ + int ret; + mbedtls_mpi r, s; + ECDSA_VALIDATE_RET( ctx != NULL ); + ECDSA_VALIDATE_RET( hash != NULL ); + ECDSA_VALIDATE_RET( sig != NULL ); + ECDSA_VALIDATE_RET( slen != NULL ); + + mbedtls_mpi_init( &r ); + mbedtls_mpi_init( &s ); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + (void) f_rng; + (void) p_rng; + + MBEDTLS_MPI_CHK( ecdsa_sign_det_restartable( &ctx->grp, &r, &s, &ctx->d, + hash, hlen, md_alg, rs_ctx ) ); +#else + (void) md_alg; + +#if defined(MBEDTLS_ECDSA_SIGN_ALT) + MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d, + hash, hlen, f_rng, p_rng ) ); +#else + MBEDTLS_MPI_CHK( ecdsa_sign_restartable( &ctx->grp, &r, &s, &ctx->d, + hash, hlen, f_rng, p_rng, rs_ctx ) ); +#endif /* MBEDTLS_ECDSA_SIGN_ALT */ +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + + MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) ); + +cleanup: + mbedtls_mpi_free( &r ); + mbedtls_mpi_free( &s ); + + return( ret ); +} + +/* + * Compute and write signature + */ +int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + ECDSA_VALIDATE_RET( ctx != NULL ); + ECDSA_VALIDATE_RET( hash != NULL ); + ECDSA_VALIDATE_RET( sig != NULL ); + ECDSA_VALIDATE_RET( slen != NULL ); + return( mbedtls_ecdsa_write_signature_restartable( + ctx, md_alg, hash, hlen, sig, slen, f_rng, p_rng, NULL ) ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) && \ + defined(MBEDTLS_ECDSA_DETERMINISTIC) +int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + mbedtls_md_type_t md_alg ) +{ + ECDSA_VALIDATE_RET( ctx != NULL ); + ECDSA_VALIDATE_RET( hash != NULL ); + ECDSA_VALIDATE_RET( sig != NULL ); + ECDSA_VALIDATE_RET( slen != NULL ); + return( mbedtls_ecdsa_write_signature( ctx, md_alg, hash, hlen, sig, slen, + NULL, NULL ) ); +} +#endif + +/* + * Read and check signature + */ +int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen ) +{ + ECDSA_VALIDATE_RET( ctx != NULL ); + ECDSA_VALIDATE_RET( hash != NULL ); + ECDSA_VALIDATE_RET( sig != NULL ); + return( mbedtls_ecdsa_read_signature_restartable( + ctx, hash, hlen, sig, slen, NULL ) ); +} + +/* + * Restartable read and check signature + */ +int mbedtls_ecdsa_read_signature_restartable( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen, + mbedtls_ecdsa_restart_ctx *rs_ctx ) +{ + int ret; + unsigned char *p = (unsigned char *) sig; + const unsigned char *end = sig + slen; + size_t len; + mbedtls_mpi r, s; + ECDSA_VALIDATE_RET( ctx != NULL ); + ECDSA_VALIDATE_RET( hash != NULL ); + ECDSA_VALIDATE_RET( sig != NULL ); + + mbedtls_mpi_init( &r ); + mbedtls_mpi_init( &s ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + if( p + len != end ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + goto cleanup; + } + + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &r ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &s ) ) != 0 ) + { + ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } +#if defined(MBEDTLS_ECDSA_VERIFY_ALT) + if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen, + &ctx->Q, &r, &s ) ) != 0 ) + goto cleanup; +#else + if( ( ret = ecdsa_verify_restartable( &ctx->grp, hash, hlen, + &ctx->Q, &r, &s, rs_ctx ) ) != 0 ) + goto cleanup; +#endif /* MBEDTLS_ECDSA_VERIFY_ALT */ + + /* At this point we know that the buffer starts with a valid signature. + * Return 0 if the buffer just contains the signature, and a specific + * error code if the valid signature is followed by more data. */ + if( p != end ) + ret = MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH; + +cleanup: + mbedtls_mpi_free( &r ); + mbedtls_mpi_free( &s ); + + return( ret ); +} + +#if !defined(MBEDTLS_ECDSA_GENKEY_ALT) +/* + * Generate key pair + */ +int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret = 0; + ECDSA_VALIDATE_RET( ctx != NULL ); + ECDSA_VALIDATE_RET( f_rng != NULL ); + + ret = mbedtls_ecp_group_load( &ctx->grp, gid ); + if( ret != 0 ) + return( ret ); + + return( mbedtls_ecp_gen_keypair( &ctx->grp, &ctx->d, + &ctx->Q, f_rng, p_rng ) ); +} +#endif /* !MBEDTLS_ECDSA_GENKEY_ALT */ + +/* + * Set context from an mbedtls_ecp_keypair + */ +int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ) +{ + int ret; + ECDSA_VALIDATE_RET( ctx != NULL ); + ECDSA_VALIDATE_RET( key != NULL ); + + if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 || + ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 || + ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 ) + { + mbedtls_ecdsa_free( ctx ); + } + + return( ret ); +} + +/* + * Initialize context + */ +void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ) +{ + ECDSA_VALIDATE( ctx != NULL ); + + mbedtls_ecp_keypair_init( ctx ); +} + +/* + * Free context + */ +void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_ecp_keypair_free( ctx ); +} + +#if defined(MBEDTLS_ECP_RESTARTABLE) +/* + * Initialize a restart context + */ +void mbedtls_ecdsa_restart_init( mbedtls_ecdsa_restart_ctx *ctx ) +{ + ECDSA_VALIDATE( ctx != NULL ); + + mbedtls_ecp_restart_init( &ctx->ecp ); + + ctx->ver = NULL; + ctx->sig = NULL; +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + ctx->det = NULL; +#endif +} + +/* + * Free the components of a restart context + */ +void mbedtls_ecdsa_restart_free( mbedtls_ecdsa_restart_ctx *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_ecp_restart_free( &ctx->ecp ); + + ecdsa_restart_ver_free( ctx->ver ); + mbedtls_free( ctx->ver ); + ctx->ver = NULL; + + ecdsa_restart_sig_free( ctx->sig ); + mbedtls_free( ctx->sig ); + ctx->sig = NULL; + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + ecdsa_restart_det_free( ctx->det ); + mbedtls_free( ctx->det ); + ctx->det = NULL; +#endif +} +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +#endif /* MBEDTLS_ECDSA_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ecjpake.c b/FreeRTOS-Labs/Source/mbedtls/library/ecjpake.c new file mode 100644 index 000000000..c626dc056 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ecjpake.c @@ -0,0 +1,1140 @@ +/* + * Elliptic curve J-PAKE + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References in the code are to the Thread v1.0 Specification, + * available to members of the Thread Group http://threadgroup.org/ + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECJPAKE_C) + +#include "mbedtls/ecjpake.h" +#include "mbedtls/platform_util.h" + +#include + +#if !defined(MBEDTLS_ECJPAKE_ALT) + +/* Parameter validation macros based on platform_util.h */ +#define ECJPAKE_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) +#define ECJPAKE_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +/* + * Convert a mbedtls_ecjpake_role to identifier string + */ +static const char * const ecjpake_id[] = { + "client", + "server" +}; + +#define ID_MINE ( ecjpake_id[ ctx->role ] ) +#define ID_PEER ( ecjpake_id[ 1 - ctx->role ] ) + +/* + * Initialize context + */ +void mbedtls_ecjpake_init( mbedtls_ecjpake_context *ctx ) +{ + ECJPAKE_VALIDATE( ctx != NULL ); + + ctx->md_info = NULL; + mbedtls_ecp_group_init( &ctx->grp ); + ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; + + mbedtls_ecp_point_init( &ctx->Xm1 ); + mbedtls_ecp_point_init( &ctx->Xm2 ); + mbedtls_ecp_point_init( &ctx->Xp1 ); + mbedtls_ecp_point_init( &ctx->Xp2 ); + mbedtls_ecp_point_init( &ctx->Xp ); + + mbedtls_mpi_init( &ctx->xm1 ); + mbedtls_mpi_init( &ctx->xm2 ); + mbedtls_mpi_init( &ctx->s ); +} + +/* + * Free context + */ +void mbedtls_ecjpake_free( mbedtls_ecjpake_context *ctx ) +{ + if( ctx == NULL ) + return; + + ctx->md_info = NULL; + mbedtls_ecp_group_free( &ctx->grp ); + + mbedtls_ecp_point_free( &ctx->Xm1 ); + mbedtls_ecp_point_free( &ctx->Xm2 ); + mbedtls_ecp_point_free( &ctx->Xp1 ); + mbedtls_ecp_point_free( &ctx->Xp2 ); + mbedtls_ecp_point_free( &ctx->Xp ); + + mbedtls_mpi_free( &ctx->xm1 ); + mbedtls_mpi_free( &ctx->xm2 ); + mbedtls_mpi_free( &ctx->s ); +} + +/* + * Setup context + */ +int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx, + mbedtls_ecjpake_role role, + mbedtls_md_type_t hash, + mbedtls_ecp_group_id curve, + const unsigned char *secret, + size_t len ) +{ + int ret; + + ECJPAKE_VALIDATE_RET( ctx != NULL ); + ECJPAKE_VALIDATE_RET( role == MBEDTLS_ECJPAKE_CLIENT || + role == MBEDTLS_ECJPAKE_SERVER ); + ECJPAKE_VALIDATE_RET( secret != NULL || len == 0 ); + + ctx->role = role; + + if( ( ctx->md_info = mbedtls_md_info_from_type( hash ) ) == NULL ) + return( MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ctx->grp, curve ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->s, secret, len ) ); + +cleanup: + if( ret != 0 ) + mbedtls_ecjpake_free( ctx ); + + return( ret ); +} + +/* + * Check if context is ready for use + */ +int mbedtls_ecjpake_check( const mbedtls_ecjpake_context *ctx ) +{ + ECJPAKE_VALIDATE_RET( ctx != NULL ); + + if( ctx->md_info == NULL || + ctx->grp.id == MBEDTLS_ECP_DP_NONE || + ctx->s.p == NULL ) + { + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + return( 0 ); +} + +/* + * Write a point plus its length to a buffer + */ +static int ecjpake_write_len_point( unsigned char **p, + const unsigned char *end, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *P ) +{ + int ret; + size_t len; + + /* Need at least 4 for length plus 1 for point */ + if( end < *p || end - *p < 5 ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + ret = mbedtls_ecp_point_write_binary( grp, P, pf, + &len, *p + 4, end - ( *p + 4 ) ); + if( ret != 0 ) + return( ret ); + + (*p)[0] = (unsigned char)( ( len >> 24 ) & 0xFF ); + (*p)[1] = (unsigned char)( ( len >> 16 ) & 0xFF ); + (*p)[2] = (unsigned char)( ( len >> 8 ) & 0xFF ); + (*p)[3] = (unsigned char)( ( len ) & 0xFF ); + + *p += 4 + len; + + return( 0 ); +} + +/* + * Size of the temporary buffer for ecjpake_hash: + * 3 EC points plus their length, plus ID and its length (4 + 6 bytes) + */ +#define ECJPAKE_HASH_BUF_LEN ( 3 * ( 4 + MBEDTLS_ECP_MAX_PT_LEN ) + 4 + 6 ) + +/* + * Compute hash for ZKP (7.4.2.2.2.1) + */ +static int ecjpake_hash( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + const mbedtls_ecp_point *V, + const mbedtls_ecp_point *X, + const char *id, + mbedtls_mpi *h ) +{ + int ret; + unsigned char buf[ECJPAKE_HASH_BUF_LEN]; + unsigned char *p = buf; + const unsigned char *end = buf + sizeof( buf ); + const size_t id_len = strlen( id ); + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + + /* Write things to temporary buffer */ + MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, pf, G ) ); + MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, pf, V ) ); + MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, pf, X ) ); + + if( end - p < 4 ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + *p++ = (unsigned char)( ( id_len >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( id_len >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( id_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( id_len ) & 0xFF ); + + if( end < p || (size_t)( end - p ) < id_len ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + memcpy( p, id, id_len ); + p += id_len; + + /* Compute hash */ + mbedtls_md( md_info, buf, p - buf, hash ); + + /* Turn it into an integer mod n */ + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( h, hash, + mbedtls_md_get_size( md_info ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( h, h, &grp->N ) ); + +cleanup: + return( ret ); +} + +/* + * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3) + */ +static int ecjpake_zkp_read( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + const mbedtls_ecp_point *X, + const char *id, + const unsigned char **p, + const unsigned char *end ) +{ + int ret; + mbedtls_ecp_point V, VV; + mbedtls_mpi r, h; + size_t r_len; + + mbedtls_ecp_point_init( &V ); + mbedtls_ecp_point_init( &VV ); + mbedtls_mpi_init( &r ); + mbedtls_mpi_init( &h ); + + /* + * struct { + * ECPoint V; + * opaque r<1..2^8-1>; + * } ECSchnorrZKP; + */ + if( end < *p ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, &V, p, end - *p ) ); + + if( end < *p || (size_t)( end - *p ) < 1 ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + r_len = *(*p)++; + + if( end < *p || (size_t)( end - *p ) < r_len ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &r, *p, r_len ) ); + *p += r_len; + + /* + * Verification + */ + MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, pf, G, &V, X, id, &h ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( (mbedtls_ecp_group *) grp, + &VV, &h, X, &r, G ) ); + + if( mbedtls_ecp_point_cmp( &VV, &V ) != 0 ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free( &V ); + mbedtls_ecp_point_free( &VV ); + mbedtls_mpi_free( &r ); + mbedtls_mpi_free( &h ); + + return( ret ); +} + +/* + * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2) + */ +static int ecjpake_zkp_write( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + const mbedtls_mpi *x, + const mbedtls_ecp_point *X, + const char *id, + unsigned char **p, + const unsigned char *end, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point V; + mbedtls_mpi v; + mbedtls_mpi h; /* later recycled to hold r */ + size_t len; + + if( end < *p ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + mbedtls_ecp_point_init( &V ); + mbedtls_mpi_init( &v ); + mbedtls_mpi_init( &h ); + + /* Compute signature */ + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp, + G, &v, &V, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, pf, G, &V, X, id, &h ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &h, &h, x ) ); /* x*h */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &h, &v, &h ) ); /* v - x*h */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &h, &h, &grp->N ) ); /* r */ + + /* Write it out */ + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, &V, + pf, &len, *p, end - *p ) ); + *p += len; + + len = mbedtls_mpi_size( &h ); /* actually r */ + if( end < *p || (size_t)( end - *p ) < 1 + len || len > 255 ) + { + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + goto cleanup; + } + + *(*p)++ = (unsigned char)( len & 0xFF ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, *p, len ) ); /* r */ + *p += len; + +cleanup: + mbedtls_ecp_point_free( &V ); + mbedtls_mpi_free( &v ); + mbedtls_mpi_free( &h ); + + return( ret ); +} + +/* + * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof + * Output: verified public key X + */ +static int ecjpake_kkp_read( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_ecp_point *X, + const char *id, + const unsigned char **p, + const unsigned char *end ) +{ + int ret; + + if( end < *p ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * struct { + * ECPoint X; + * ECSchnorrZKP zkp; + * } ECJPAKEKeyKP; + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, X, p, end - *p ) ); + if( mbedtls_ecp_is_zero( X ) ) + { + ret = MBEDTLS_ERR_ECP_INVALID_KEY; + goto cleanup; + } + + MBEDTLS_MPI_CHK( ecjpake_zkp_read( md_info, grp, pf, G, X, id, p, end ) ); + +cleanup: + return( ret ); +} + +/* + * Generate an ECJPAKEKeyKP + * Output: the serialized structure, plus private/public key pair + */ +static int ecjpake_kkp_write( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_mpi *x, + mbedtls_ecp_point *X, + const char *id, + unsigned char **p, + const unsigned char *end, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t len; + + if( end < *p ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + /* Generate key (7.4.2.3.1) and write it out */ + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp, G, x, X, + f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, X, + pf, &len, *p, end - *p ) ); + *p += len; + + /* Generate and write proof */ + MBEDTLS_MPI_CHK( ecjpake_zkp_write( md_info, grp, pf, G, x, X, id, + p, end, f_rng, p_rng ) ); + +cleanup: + return( ret ); +} + +/* + * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs + * Ouputs: verified peer public keys Xa, Xb + */ +static int ecjpake_kkpp_read( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_ecp_point *Xa, + mbedtls_ecp_point *Xb, + const char *id, + const unsigned char *buf, + size_t len ) +{ + int ret; + const unsigned char *p = buf; + const unsigned char *end = buf + len; + + /* + * struct { + * ECJPAKEKeyKP ecjpake_key_kp_pair_list[2]; + * } ECJPAKEKeyKPPairList; + */ + MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, grp, pf, G, Xa, id, &p, end ) ); + MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, grp, pf, G, Xb, id, &p, end ) ); + + if( p != end ) + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + +cleanup: + return( ret ); +} + +/* + * Generate a ECJPAKEKeyKPPairList + * Outputs: the serialized structure, plus two private/public key pairs + */ +static int ecjpake_kkpp_write( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_mpi *xm1, + mbedtls_ecp_point *Xa, + mbedtls_mpi *xm2, + mbedtls_ecp_point *Xb, + const char *id, + unsigned char *buf, + size_t len, + size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char *p = buf; + const unsigned char *end = buf + len; + + MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, grp, pf, G, xm1, Xa, id, + &p, end, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, grp, pf, G, xm2, Xb, id, + &p, end, f_rng, p_rng ) ); + + *olen = p - buf; + +cleanup: + return( ret ); +} + +/* + * Read and process the first round message + */ +int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len ) +{ + ECJPAKE_VALIDATE_RET( ctx != NULL ); + ECJPAKE_VALIDATE_RET( buf != NULL ); + + return( ecjpake_kkpp_read( ctx->md_info, &ctx->grp, ctx->point_format, + &ctx->grp.G, + &ctx->Xp1, &ctx->Xp2, ID_PEER, + buf, len ) ); +} + +/* + * Generate and write the first round message + */ +int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + ECJPAKE_VALIDATE_RET( ctx != NULL ); + ECJPAKE_VALIDATE_RET( buf != NULL ); + ECJPAKE_VALIDATE_RET( olen != NULL ); + ECJPAKE_VALIDATE_RET( f_rng != NULL ); + + return( ecjpake_kkpp_write( ctx->md_info, &ctx->grp, ctx->point_format, + &ctx->grp.G, + &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2, + ID_MINE, buf, len, olen, f_rng, p_rng ) ); +} + +/* + * Compute the sum of three points R = A + B + C + */ +static int ecjpake_ecp_add3( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *A, + const mbedtls_ecp_point *B, + const mbedtls_ecp_point *C ) +{ + int ret; + mbedtls_mpi one; + + mbedtls_mpi_init( &one ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, A, &one, B ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, R, &one, C ) ); + +cleanup: + mbedtls_mpi_free( &one ); + + return( ret ); +} + +/* + * Read and process second round message (C: 7.4.2.5, S: 7.4.2.6) + */ +int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len ) +{ + int ret; + const unsigned char *p = buf; + const unsigned char *end = buf + len; + mbedtls_ecp_group grp; + mbedtls_ecp_point G; /* C: GB, S: GA */ + + ECJPAKE_VALIDATE_RET( ctx != NULL ); + ECJPAKE_VALIDATE_RET( buf != NULL ); + + mbedtls_ecp_group_init( &grp ); + mbedtls_ecp_point_init( &G ); + + /* + * Server: GA = X3 + X4 + X1 (7.4.2.6.1) + * Client: GB = X1 + X2 + X3 (7.4.2.5.1) + * Unified: G = Xm1 + Xm2 + Xp1 + * We need that before parsing in order to check Xp as we read it + */ + MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &G, + &ctx->Xm1, &ctx->Xm2, &ctx->Xp1 ) ); + + /* + * struct { + * ECParameters curve_params; // only client reading server msg + * ECJPAKEKeyKP ecjpake_key_kp; + * } Client/ServerECJPAKEParams; + */ + if( ctx->role == MBEDTLS_ECJPAKE_CLIENT ) + { + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_group( &grp, &p, len ) ); + if( grp.id != ctx->grp.id ) + { + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + goto cleanup; + } + } + + MBEDTLS_MPI_CHK( ecjpake_kkp_read( ctx->md_info, &ctx->grp, + ctx->point_format, + &G, &ctx->Xp, ID_PEER, &p, end ) ); + + if( p != end ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + +cleanup: + mbedtls_ecp_group_free( &grp ); + mbedtls_ecp_point_free( &G ); + + return( ret ); +} + +/* + * Compute R = +/- X * S mod N, taking care not to leak S + */ +static int ecjpake_mul_secret( mbedtls_mpi *R, int sign, + const mbedtls_mpi *X, + const mbedtls_mpi *S, + const mbedtls_mpi *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_mpi b; /* Blinding value, then s + N * blinding */ + + mbedtls_mpi_init( &b ); + + /* b = s + rnd-128-bit * N */ + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &b, 16, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &b, &b, N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &b, &b, S ) ); + + /* R = sign * X * b mod N */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( R, X, &b ) ); + R->s *= sign; + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( R, R, N ) ); + +cleanup: + mbedtls_mpi_free( &b ); + + return( ret ); +} + +/* + * Generate and write the second round message (S: 7.4.2.5, C: 7.4.2.6) + */ +int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point G; /* C: GA, S: GB */ + mbedtls_ecp_point Xm; /* C: Xc, S: Xs */ + mbedtls_mpi xm; /* C: xc, S: xs */ + unsigned char *p = buf; + const unsigned char *end = buf + len; + size_t ec_len; + + ECJPAKE_VALIDATE_RET( ctx != NULL ); + ECJPAKE_VALIDATE_RET( buf != NULL ); + ECJPAKE_VALIDATE_RET( olen != NULL ); + ECJPAKE_VALIDATE_RET( f_rng != NULL ); + + mbedtls_ecp_point_init( &G ); + mbedtls_ecp_point_init( &Xm ); + mbedtls_mpi_init( &xm ); + + /* + * First generate private/public key pair (S: 7.4.2.5.1, C: 7.4.2.6.1) + * + * Client: GA = X1 + X3 + X4 | xs = x2 * s | Xc = xc * GA + * Server: GB = X3 + X1 + X2 | xs = x4 * s | Xs = xs * GB + * Unified: G = Xm1 + Xp1 + Xp2 | xm = xm2 * s | Xm = xm * G + */ + MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &G, + &ctx->Xp1, &ctx->Xp2, &ctx->Xm1 ) ); + MBEDTLS_MPI_CHK( ecjpake_mul_secret( &xm, 1, &ctx->xm2, &ctx->s, + &ctx->grp.N, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &Xm, &xm, &G, f_rng, p_rng ) ); + + /* + * Now write things out + * + * struct { + * ECParameters curve_params; // only server writing its message + * ECJPAKEKeyKP ecjpake_key_kp; + * } Client/ServerECJPAKEParams; + */ + if( ctx->role == MBEDTLS_ECJPAKE_SERVER ) + { + if( end < p ) + { + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + goto cleanup; + } + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_group( &ctx->grp, &ec_len, + p, end - p ) ); + p += ec_len; + } + + if( end < p ) + { + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + goto cleanup; + } + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( &ctx->grp, &Xm, + ctx->point_format, &ec_len, p, end - p ) ); + p += ec_len; + + MBEDTLS_MPI_CHK( ecjpake_zkp_write( ctx->md_info, &ctx->grp, + ctx->point_format, + &G, &xm, &Xm, ID_MINE, + &p, end, f_rng, p_rng ) ); + + *olen = p - buf; + +cleanup: + mbedtls_ecp_point_free( &G ); + mbedtls_ecp_point_free( &Xm ); + mbedtls_mpi_free( &xm ); + + return( ret ); +} + +/* + * Derive PMS (7.4.2.7 / 7.4.2.8) + */ +int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point K; + mbedtls_mpi m_xm2_s, one; + unsigned char kx[MBEDTLS_ECP_MAX_BYTES]; + size_t x_bytes; + + ECJPAKE_VALIDATE_RET( ctx != NULL ); + ECJPAKE_VALIDATE_RET( buf != NULL ); + ECJPAKE_VALIDATE_RET( olen != NULL ); + ECJPAKE_VALIDATE_RET( f_rng != NULL ); + + *olen = mbedtls_md_get_size( ctx->md_info ); + if( len < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + mbedtls_ecp_point_init( &K ); + mbedtls_mpi_init( &m_xm2_s ); + mbedtls_mpi_init( &one ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) ); + + /* + * Client: K = ( Xs - X4 * x2 * s ) * x2 + * Server: K = ( Xc - X2 * x4 * s ) * x4 + * Unified: K = ( Xp - Xp2 * xm2 * s ) * xm2 + */ + MBEDTLS_MPI_CHK( ecjpake_mul_secret( &m_xm2_s, -1, &ctx->xm2, &ctx->s, + &ctx->grp.N, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( &ctx->grp, &K, + &one, &ctx->Xp, + &m_xm2_s, &ctx->Xp2 ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &K, &ctx->xm2, &K, + f_rng, p_rng ) ); + + /* PMS = SHA-256( K.X ) */ + x_bytes = ( ctx->grp.pbits + 7 ) / 8; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &K.X, kx, x_bytes ) ); + MBEDTLS_MPI_CHK( mbedtls_md( ctx->md_info, kx, x_bytes, buf ) ); + +cleanup: + mbedtls_ecp_point_free( &K ); + mbedtls_mpi_free( &m_xm2_s ); + mbedtls_mpi_free( &one ); + + return( ret ); +} + +#undef ID_MINE +#undef ID_PEER + +#endif /* ! MBEDTLS_ECJPAKE_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif + +#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + !defined(MBEDTLS_SHA256_C) +int mbedtls_ecjpake_self_test( int verbose ) +{ + (void) verbose; + return( 0 ); +} +#else + +static const unsigned char ecjpake_test_password[] = { + 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x6a, 0x70, 0x61, 0x6b, 0x65, 0x74, + 0x65, 0x73, 0x74 +}; + +static const unsigned char ecjpake_test_x1[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21 +}; + +static const unsigned char ecjpake_test_x2[] = { + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, + 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81 +}; + +static const unsigned char ecjpake_test_x3[] = { + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, + 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81 +}; + +static const unsigned char ecjpake_test_x4[] = { + 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, + 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1 +}; + +static const unsigned char ecjpake_test_cli_one[] = { + 0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19, + 0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44, + 0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad, + 0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62, + 0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9, + 0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d, + 0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e, + 0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e, + 0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73, + 0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22, + 0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce, + 0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00, + 0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b, + 0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58, 0x41, 0x04, 0x7e, + 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, 0xd7, 0x92, 0x62, + 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, 0x40, 0x9a, 0xc5, + 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, 0x79, 0x0a, 0xeb, + 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, 0xd1, 0xc3, 0x35, + 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, 0xe3, 0x2b, 0xb0, + 0x13, 0xbb, 0x2b, 0x41, 0x04, 0xa4, 0x95, 0x58, 0xd3, 0x2e, 0xd1, 0xeb, + 0xfc, 0x18, 0x16, 0xaf, 0x4f, 0xf0, 0x9b, 0x55, 0xfc, 0xb4, 0xca, 0x47, + 0xb2, 0xa0, 0x2d, 0x1e, 0x7c, 0xaf, 0x11, 0x79, 0xea, 0x3f, 0xe1, 0x39, + 0x5b, 0x22, 0xb8, 0x61, 0x96, 0x40, 0x16, 0xfa, 0xba, 0xf7, 0x2c, 0x97, + 0x56, 0x95, 0xd9, 0x3d, 0x4d, 0xf0, 0xe5, 0x19, 0x7f, 0xe9, 0xf0, 0x40, + 0x63, 0x4e, 0xd5, 0x97, 0x64, 0x93, 0x77, 0x87, 0xbe, 0x20, 0xbc, 0x4d, + 0xee, 0xbb, 0xf9, 0xb8, 0xd6, 0x0a, 0x33, 0x5f, 0x04, 0x6c, 0xa3, 0xaa, + 0x94, 0x1e, 0x45, 0x86, 0x4c, 0x7c, 0xad, 0xef, 0x9c, 0xf7, 0x5b, 0x3d, + 0x8b, 0x01, 0x0e, 0x44, 0x3e, 0xf0 +}; + +static const unsigned char ecjpake_test_srv_one[] = { + 0x41, 0x04, 0x7e, 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, + 0xd7, 0x92, 0x62, 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, + 0x40, 0x9a, 0xc5, 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, + 0x79, 0x0a, 0xeb, 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, + 0xd1, 0xc3, 0x35, 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, + 0xe3, 0x2b, 0xb0, 0x13, 0xbb, 0x2b, 0x41, 0x04, 0x09, 0xf8, 0x5b, 0x3d, + 0x20, 0xeb, 0xd7, 0x88, 0x5c, 0xe4, 0x64, 0xc0, 0x8d, 0x05, 0x6d, 0x64, + 0x28, 0xfe, 0x4d, 0xd9, 0x28, 0x7a, 0xa3, 0x65, 0xf1, 0x31, 0xf4, 0x36, + 0x0f, 0xf3, 0x86, 0xd8, 0x46, 0x89, 0x8b, 0xc4, 0xb4, 0x15, 0x83, 0xc2, + 0xa5, 0x19, 0x7f, 0x65, 0xd7, 0x87, 0x42, 0x74, 0x6c, 0x12, 0xa5, 0xec, + 0x0a, 0x4f, 0xfe, 0x2f, 0x27, 0x0a, 0x75, 0x0a, 0x1d, 0x8f, 0xb5, 0x16, + 0x20, 0x93, 0x4d, 0x74, 0xeb, 0x43, 0xe5, 0x4d, 0xf4, 0x24, 0xfd, 0x96, + 0x30, 0x6c, 0x01, 0x17, 0xbf, 0x13, 0x1a, 0xfa, 0xbf, 0x90, 0xa9, 0xd3, + 0x3d, 0x11, 0x98, 0xd9, 0x05, 0x19, 0x37, 0x35, 0x14, 0x41, 0x04, 0x19, + 0x0a, 0x07, 0x70, 0x0f, 0xfa, 0x4b, 0xe6, 0xae, 0x1d, 0x79, 0xee, 0x0f, + 0x06, 0xae, 0xb5, 0x44, 0xcd, 0x5a, 0xdd, 0xaa, 0xbe, 0xdf, 0x70, 0xf8, + 0x62, 0x33, 0x21, 0x33, 0x2c, 0x54, 0xf3, 0x55, 0xf0, 0xfb, 0xfe, 0xc7, + 0x83, 0xed, 0x35, 0x9e, 0x5d, 0x0b, 0xf7, 0x37, 0x7a, 0x0f, 0xc4, 0xea, + 0x7a, 0xce, 0x47, 0x3c, 0x9c, 0x11, 0x2b, 0x41, 0xcc, 0xd4, 0x1a, 0xc5, + 0x6a, 0x56, 0x12, 0x41, 0x04, 0x36, 0x0a, 0x1c, 0xea, 0x33, 0xfc, 0xe6, + 0x41, 0x15, 0x64, 0x58, 0xe0, 0xa4, 0xea, 0xc2, 0x19, 0xe9, 0x68, 0x31, + 0xe6, 0xae, 0xbc, 0x88, 0xb3, 0xf3, 0x75, 0x2f, 0x93, 0xa0, 0x28, 0x1d, + 0x1b, 0xf1, 0xfb, 0x10, 0x60, 0x51, 0xdb, 0x96, 0x94, 0xa8, 0xd6, 0xe8, + 0x62, 0xa5, 0xef, 0x13, 0x24, 0xa3, 0xd9, 0xe2, 0x78, 0x94, 0xf1, 0xee, + 0x4f, 0x7c, 0x59, 0x19, 0x99, 0x65, 0xa8, 0xdd, 0x4a, 0x20, 0x91, 0x84, + 0x7d, 0x2d, 0x22, 0xdf, 0x3e, 0xe5, 0x5f, 0xaa, 0x2a, 0x3f, 0xb3, 0x3f, + 0xd2, 0xd1, 0xe0, 0x55, 0xa0, 0x7a, 0x7c, 0x61, 0xec, 0xfb, 0x8d, 0x80, + 0xec, 0x00, 0xc2, 0xc9, 0xeb, 0x12 +}; + +static const unsigned char ecjpake_test_srv_two[] = { + 0x03, 0x00, 0x17, 0x41, 0x04, 0x0f, 0xb2, 0x2b, 0x1d, 0x5d, 0x11, 0x23, + 0xe0, 0xef, 0x9f, 0xeb, 0x9d, 0x8a, 0x2e, 0x59, 0x0a, 0x1f, 0x4d, 0x7c, + 0xed, 0x2c, 0x2b, 0x06, 0x58, 0x6e, 0x8f, 0x2a, 0x16, 0xd4, 0xeb, 0x2f, + 0xda, 0x43, 0x28, 0xa2, 0x0b, 0x07, 0xd8, 0xfd, 0x66, 0x76, 0x54, 0xca, + 0x18, 0xc5, 0x4e, 0x32, 0xa3, 0x33, 0xa0, 0x84, 0x54, 0x51, 0xe9, 0x26, + 0xee, 0x88, 0x04, 0xfd, 0x7a, 0xf0, 0xaa, 0xa7, 0xa6, 0x41, 0x04, 0x55, + 0x16, 0xea, 0x3e, 0x54, 0xa0, 0xd5, 0xd8, 0xb2, 0xce, 0x78, 0x6b, 0x38, + 0xd3, 0x83, 0x37, 0x00, 0x29, 0xa5, 0xdb, 0xe4, 0x45, 0x9c, 0x9d, 0xd6, + 0x01, 0xb4, 0x08, 0xa2, 0x4a, 0xe6, 0x46, 0x5c, 0x8a, 0xc9, 0x05, 0xb9, + 0xeb, 0x03, 0xb5, 0xd3, 0x69, 0x1c, 0x13, 0x9e, 0xf8, 0x3f, 0x1c, 0xd4, + 0x20, 0x0f, 0x6c, 0x9c, 0xd4, 0xec, 0x39, 0x22, 0x18, 0xa5, 0x9e, 0xd2, + 0x43, 0xd3, 0xc8, 0x20, 0xff, 0x72, 0x4a, 0x9a, 0x70, 0xb8, 0x8c, 0xb8, + 0x6f, 0x20, 0xb4, 0x34, 0xc6, 0x86, 0x5a, 0xa1, 0xcd, 0x79, 0x06, 0xdd, + 0x7c, 0x9b, 0xce, 0x35, 0x25, 0xf5, 0x08, 0x27, 0x6f, 0x26, 0x83, 0x6c +}; + +static const unsigned char ecjpake_test_cli_two[] = { + 0x41, 0x04, 0x69, 0xd5, 0x4e, 0xe8, 0x5e, 0x90, 0xce, 0x3f, 0x12, 0x46, + 0x74, 0x2d, 0xe5, 0x07, 0xe9, 0x39, 0xe8, 0x1d, 0x1d, 0xc1, 0xc5, 0xcb, + 0x98, 0x8b, 0x58, 0xc3, 0x10, 0xc9, 0xfd, 0xd9, 0x52, 0x4d, 0x93, 0x72, + 0x0b, 0x45, 0x54, 0x1c, 0x83, 0xee, 0x88, 0x41, 0x19, 0x1d, 0xa7, 0xce, + 0xd8, 0x6e, 0x33, 0x12, 0xd4, 0x36, 0x23, 0xc1, 0xd6, 0x3e, 0x74, 0x98, + 0x9a, 0xba, 0x4a, 0xff, 0xd1, 0xee, 0x41, 0x04, 0x07, 0x7e, 0x8c, 0x31, + 0xe2, 0x0e, 0x6b, 0xed, 0xb7, 0x60, 0xc1, 0x35, 0x93, 0xe6, 0x9f, 0x15, + 0xbe, 0x85, 0xc2, 0x7d, 0x68, 0xcd, 0x09, 0xcc, 0xb8, 0xc4, 0x18, 0x36, + 0x08, 0x91, 0x7c, 0x5c, 0x3d, 0x40, 0x9f, 0xac, 0x39, 0xfe, 0xfe, 0xe8, + 0x2f, 0x72, 0x92, 0xd3, 0x6f, 0x0d, 0x23, 0xe0, 0x55, 0x91, 0x3f, 0x45, + 0xa5, 0x2b, 0x85, 0xdd, 0x8a, 0x20, 0x52, 0xe9, 0xe1, 0x29, 0xbb, 0x4d, + 0x20, 0x0f, 0x01, 0x1f, 0x19, 0x48, 0x35, 0x35, 0xa6, 0xe8, 0x9a, 0x58, + 0x0c, 0x9b, 0x00, 0x03, 0xba, 0xf2, 0x14, 0x62, 0xec, 0xe9, 0x1a, 0x82, + 0xcc, 0x38, 0xdb, 0xdc, 0xae, 0x60, 0xd9, 0xc5, 0x4c +}; + +static const unsigned char ecjpake_test_pms[] = { + 0xf3, 0xd4, 0x7f, 0x59, 0x98, 0x44, 0xdb, 0x92, 0xa5, 0x69, 0xbb, 0xe7, + 0x98, 0x1e, 0x39, 0xd9, 0x31, 0xfd, 0x74, 0x3b, 0xf2, 0x2e, 0x98, 0xf9, + 0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51 +}; + +/* Load my private keys and generate the corresponding public keys */ +static int ecjpake_test_load( mbedtls_ecjpake_context *ctx, + const unsigned char *xm1, size_t len1, + const unsigned char *xm2, size_t len2 ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->xm1, xm1, len1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->xm2, xm2, len2 ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &ctx->Xm1, &ctx->xm1, + &ctx->grp.G, NULL, NULL ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &ctx->Xm2, &ctx->xm2, + &ctx->grp.G, NULL, NULL ) ); + +cleanup: + return( ret ); +} + +/* For tests we don't need a secure RNG; + * use the LGC from Numerical Recipes for simplicity */ +static int ecjpake_lgc( void *p, unsigned char *out, size_t len ) +{ + static uint32_t x = 42; + (void) p; + + while( len > 0 ) + { + size_t use_len = len > 4 ? 4 : len; + x = 1664525 * x + 1013904223; + memcpy( out, &x, use_len ); + out += use_len; + len -= use_len; + } + + return( 0 ); +} + +#define TEST_ASSERT( x ) \ + do { \ + if( x ) \ + ret = 0; \ + else \ + { \ + ret = 1; \ + goto cleanup; \ + } \ + } while( 0 ) + +/* + * Checkup routine + */ +int mbedtls_ecjpake_self_test( int verbose ) +{ + int ret; + mbedtls_ecjpake_context cli; + mbedtls_ecjpake_context srv; + unsigned char buf[512], pms[32]; + size_t len, pmslen; + + mbedtls_ecjpake_init( &cli ); + mbedtls_ecjpake_init( &srv ); + + if( verbose != 0 ) + mbedtls_printf( " ECJPAKE test #0 (setup): " ); + + TEST_ASSERT( mbedtls_ecjpake_setup( &cli, MBEDTLS_ECJPAKE_CLIENT, + MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1, + ecjpake_test_password, + sizeof( ecjpake_test_password ) ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_setup( &srv, MBEDTLS_ECJPAKE_SERVER, + MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1, + ecjpake_test_password, + sizeof( ecjpake_test_password ) ) == 0 ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " ECJPAKE test #1 (random handshake): " ); + + TEST_ASSERT( mbedtls_ecjpake_write_round_one( &cli, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_one( &srv, buf, len ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_write_round_one( &srv, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_one( &cli, buf, len ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_write_round_two( &srv, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_two( &cli, buf, len ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_derive_secret( &cli, + pms, sizeof( pms ), &pmslen, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_write_round_two( &cli, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_two( &srv, buf, len ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_derive_secret( &srv, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( len == pmslen ); + TEST_ASSERT( memcmp( buf, pms, len ) == 0 ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " ECJPAKE test #2 (reference handshake): " ); + + /* Simulate generation of round one */ + MBEDTLS_MPI_CHK( ecjpake_test_load( &cli, + ecjpake_test_x1, sizeof( ecjpake_test_x1 ), + ecjpake_test_x2, sizeof( ecjpake_test_x2 ) ) ); + + MBEDTLS_MPI_CHK( ecjpake_test_load( &srv, + ecjpake_test_x3, sizeof( ecjpake_test_x3 ), + ecjpake_test_x4, sizeof( ecjpake_test_x4 ) ) ); + + /* Read round one */ + TEST_ASSERT( mbedtls_ecjpake_read_round_one( &srv, + ecjpake_test_cli_one, + sizeof( ecjpake_test_cli_one ) ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_one( &cli, + ecjpake_test_srv_one, + sizeof( ecjpake_test_srv_one ) ) == 0 ); + + /* Skip generation of round two, read round two */ + TEST_ASSERT( mbedtls_ecjpake_read_round_two( &cli, + ecjpake_test_srv_two, + sizeof( ecjpake_test_srv_two ) ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_two( &srv, + ecjpake_test_cli_two, + sizeof( ecjpake_test_cli_two ) ) == 0 ); + + /* Server derives PMS */ + TEST_ASSERT( mbedtls_ecjpake_derive_secret( &srv, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( len == sizeof( ecjpake_test_pms ) ); + TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 ); + + memset( buf, 0, len ); /* Avoid interferences with next step */ + + /* Client derives PMS */ + TEST_ASSERT( mbedtls_ecjpake_derive_secret( &cli, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( len == sizeof( ecjpake_test_pms ) ); + TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +cleanup: + mbedtls_ecjpake_free( &cli ); + mbedtls_ecjpake_free( &srv ); + + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( ret ); +} + +#undef TEST_ASSERT + +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */ + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ECJPAKE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ecp.c b/FreeRTOS-Labs/Source/mbedtls/library/ecp.c new file mode 100644 index 000000000..4b8442ea0 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ecp.c @@ -0,0 +1,3089 @@ +/* + * Elliptic curves over GF(p): generic functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * SEC1 http://www.secg.org/index.php?action=secg,docs_secg + * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone + * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf + * RFC 4492 for the related TLS structures and constants + * RFC 7748 for the Curve448 and Curve25519 curve definitions + * + * [Curve25519] http://cr.yp.to/ecdh/curve25519-20060209.pdf + * + * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis + * for elliptic curve cryptosystems. In : Cryptographic Hardware and + * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302. + * + * + * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to + * render ECC resistant against Side Channel Attacks. IACR Cryptology + * ePrint Archive, 2004, vol. 2004, p. 342. + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/** + * \brief Function level alternative implementation. + * + * The MBEDTLS_ECP_INTERNAL_ALT macro enables alternative implementations to + * replace certain functions in this module. The alternative implementations are + * typically hardware accelerators and need to activate the hardware before the + * computation starts and deactivate it after it finishes. The + * mbedtls_internal_ecp_init() and mbedtls_internal_ecp_free() functions serve + * this purpose. + * + * To preserve the correct functionality the following conditions must hold: + * + * - The alternative implementation must be activated by + * mbedtls_internal_ecp_init() before any of the replaceable functions is + * called. + * - mbedtls_internal_ecp_free() must \b only be called when the alternative + * implementation is activated. + * - mbedtls_internal_ecp_init() must \b not be called when the alternative + * implementation is activated. + * - Public functions must not return while the alternative implementation is + * activated. + * - Replaceable functions are guarded by \c MBEDTLS_ECP_XXX_ALT macros and + * before calling them an \code if( mbedtls_internal_ecp_grp_capable( grp ) ) + * \endcode ensures that the alternative implementation supports the current + * group. + */ +#if defined(MBEDTLS_ECP_INTERNAL_ALT) +#endif + +#if defined(MBEDTLS_ECP_C) + +#include "mbedtls/ecp.h" +#include "mbedtls/threading.h" +#include "mbedtls/platform_util.h" + +#include + +#if !defined(MBEDTLS_ECP_ALT) + +/* Parameter validation macros based on platform_util.h */ +#define ECP_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) +#define ECP_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/ecp_internal.h" + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#if defined(MBEDTLS_SELF_TEST) +/* + * Counts of point addition and doubling, and field multiplications. + * Used to test resistance of point multiplication to simple timing attacks. + */ +static unsigned long add_count, dbl_count, mul_count; +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) +/* + * Maximum number of "basic operations" to be done in a row. + * + * Default value 0 means that ECC operations will not yield. + * Note that regardless of the value of ecp_max_ops, always at + * least one step is performed before yielding. + * + * Setting ecp_max_ops=1 can be suitable for testing purposes + * as it will interrupt computation at all possible points. + */ +static unsigned ecp_max_ops = 0; + +/* + * Set ecp_max_ops + */ +void mbedtls_ecp_set_max_ops( unsigned max_ops ) +{ + ecp_max_ops = max_ops; +} + +/* + * Check if restart is enabled + */ +int mbedtls_ecp_restart_is_enabled( void ) +{ + return( ecp_max_ops != 0 ); +} + +/* + * Restart sub-context for ecp_mul_comb() + */ +struct mbedtls_ecp_restart_mul +{ + mbedtls_ecp_point R; /* current intermediate result */ + size_t i; /* current index in various loops, 0 outside */ + mbedtls_ecp_point *T; /* table for precomputed points */ + unsigned char T_size; /* number of points in table T */ + enum { /* what were we doing last time we returned? */ + ecp_rsm_init = 0, /* nothing so far, dummy initial state */ + ecp_rsm_pre_dbl, /* precompute 2^n multiples */ + ecp_rsm_pre_norm_dbl, /* normalize precomputed 2^n multiples */ + ecp_rsm_pre_add, /* precompute remaining points by adding */ + ecp_rsm_pre_norm_add, /* normalize all precomputed points */ + ecp_rsm_comb_core, /* ecp_mul_comb_core() */ + ecp_rsm_final_norm, /* do the final normalization */ + } state; +}; + +/* + * Init restart_mul sub-context + */ +static void ecp_restart_rsm_init( mbedtls_ecp_restart_mul_ctx *ctx ) +{ + mbedtls_ecp_point_init( &ctx->R ); + ctx->i = 0; + ctx->T = NULL; + ctx->T_size = 0; + ctx->state = ecp_rsm_init; +} + +/* + * Free the components of a restart_mul sub-context + */ +static void ecp_restart_rsm_free( mbedtls_ecp_restart_mul_ctx *ctx ) +{ + unsigned char i; + + if( ctx == NULL ) + return; + + mbedtls_ecp_point_free( &ctx->R ); + + if( ctx->T != NULL ) + { + for( i = 0; i < ctx->T_size; i++ ) + mbedtls_ecp_point_free( ctx->T + i ); + mbedtls_free( ctx->T ); + } + + ecp_restart_rsm_init( ctx ); +} + +/* + * Restart context for ecp_muladd() + */ +struct mbedtls_ecp_restart_muladd +{ + mbedtls_ecp_point mP; /* mP value */ + mbedtls_ecp_point R; /* R intermediate result */ + enum { /* what should we do next? */ + ecp_rsma_mul1 = 0, /* first multiplication */ + ecp_rsma_mul2, /* second multiplication */ + ecp_rsma_add, /* addition */ + ecp_rsma_norm, /* normalization */ + } state; +}; + +/* + * Init restart_muladd sub-context + */ +static void ecp_restart_ma_init( mbedtls_ecp_restart_muladd_ctx *ctx ) +{ + mbedtls_ecp_point_init( &ctx->mP ); + mbedtls_ecp_point_init( &ctx->R ); + ctx->state = ecp_rsma_mul1; +} + +/* + * Free the components of a restart_muladd sub-context + */ +static void ecp_restart_ma_free( mbedtls_ecp_restart_muladd_ctx *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_ecp_point_free( &ctx->mP ); + mbedtls_ecp_point_free( &ctx->R ); + + ecp_restart_ma_init( ctx ); +} + +/* + * Initialize a restart context + */ +void mbedtls_ecp_restart_init( mbedtls_ecp_restart_ctx *ctx ) +{ + ECP_VALIDATE( ctx != NULL ); + ctx->ops_done = 0; + ctx->depth = 0; + ctx->rsm = NULL; + ctx->ma = NULL; +} + +/* + * Free the components of a restart context + */ +void mbedtls_ecp_restart_free( mbedtls_ecp_restart_ctx *ctx ) +{ + if( ctx == NULL ) + return; + + ecp_restart_rsm_free( ctx->rsm ); + mbedtls_free( ctx->rsm ); + + ecp_restart_ma_free( ctx->ma ); + mbedtls_free( ctx->ma ); + + mbedtls_ecp_restart_init( ctx ); +} + +/* + * Check if we can do the next step + */ +int mbedtls_ecp_check_budget( const mbedtls_ecp_group *grp, + mbedtls_ecp_restart_ctx *rs_ctx, + unsigned ops ) +{ + ECP_VALIDATE_RET( grp != NULL ); + + if( rs_ctx != NULL && ecp_max_ops != 0 ) + { + /* scale depending on curve size: the chosen reference is 256-bit, + * and multiplication is quadratic. Round to the closest integer. */ + if( grp->pbits >= 512 ) + ops *= 4; + else if( grp->pbits >= 384 ) + ops *= 2; + + /* Avoid infinite loops: always allow first step. + * Because of that, however, it's not generally true + * that ops_done <= ecp_max_ops, so the check + * ops_done > ecp_max_ops below is mandatory. */ + if( ( rs_ctx->ops_done != 0 ) && + ( rs_ctx->ops_done > ecp_max_ops || + ops > ecp_max_ops - rs_ctx->ops_done ) ) + { + return( MBEDTLS_ERR_ECP_IN_PROGRESS ); + } + + /* update running count */ + rs_ctx->ops_done += ops; + } + + return( 0 ); +} + +/* Call this when entering a function that needs its own sub-context */ +#define ECP_RS_ENTER( SUB ) do { \ + /* reset ops count for this call if top-level */ \ + if( rs_ctx != NULL && rs_ctx->depth++ == 0 ) \ + rs_ctx->ops_done = 0; \ + \ + /* set up our own sub-context if needed */ \ + if( mbedtls_ecp_restart_is_enabled() && \ + rs_ctx != NULL && rs_ctx->SUB == NULL ) \ + { \ + rs_ctx->SUB = mbedtls_calloc( 1, sizeof( *rs_ctx->SUB ) ); \ + if( rs_ctx->SUB == NULL ) \ + return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); \ + \ + ecp_restart_## SUB ##_init( rs_ctx->SUB ); \ + } \ +} while( 0 ) + +/* Call this when leaving a function that needs its own sub-context */ +#define ECP_RS_LEAVE( SUB ) do { \ + /* clear our sub-context when not in progress (done or error) */ \ + if( rs_ctx != NULL && rs_ctx->SUB != NULL && \ + ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) \ + { \ + ecp_restart_## SUB ##_free( rs_ctx->SUB ); \ + mbedtls_free( rs_ctx->SUB ); \ + rs_ctx->SUB = NULL; \ + } \ + \ + if( rs_ctx != NULL ) \ + rs_ctx->depth--; \ +} while( 0 ) + +#else /* MBEDTLS_ECP_RESTARTABLE */ + +#define ECP_RS_ENTER( sub ) (void) rs_ctx; +#define ECP_RS_LEAVE( sub ) (void) rs_ctx; + +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +#define ECP_SHORTWEIERSTRASS +#endif + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) || \ + defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +#define ECP_MONTGOMERY +#endif + +/* + * List of supported curves: + * - internal ID + * - TLS NamedCurve ID (RFC 4492 sec. 5.1.1, RFC 7071 sec. 2) + * - size in bits + * - readable name + * + * Curves are listed in order: largest curves first, and for a given size, + * fastest curves first. This provides the default order for the SSL module. + * + * Reminder: update profiles in x509_crt.c when adding a new curves! + */ +static const mbedtls_ecp_curve_info ecp_supported_curves[] = +{ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + { MBEDTLS_ECP_DP_SECP521R1, 25, 521, "secp521r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + { MBEDTLS_ECP_DP_BP512R1, 28, 512, "brainpoolP512r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + { MBEDTLS_ECP_DP_SECP384R1, 24, 384, "secp384r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + { MBEDTLS_ECP_DP_BP384R1, 27, 384, "brainpoolP384r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + { MBEDTLS_ECP_DP_SECP256R1, 23, 256, "secp256r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + { MBEDTLS_ECP_DP_SECP256K1, 22, 256, "secp256k1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + { MBEDTLS_ECP_DP_BP256R1, 26, 256, "brainpoolP256r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + { MBEDTLS_ECP_DP_SECP224R1, 21, 224, "secp224r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + { MBEDTLS_ECP_DP_SECP224K1, 20, 224, "secp224k1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + { MBEDTLS_ECP_DP_SECP192R1, 19, 192, "secp192r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + { MBEDTLS_ECP_DP_SECP192K1, 18, 192, "secp192k1" }, +#endif + { MBEDTLS_ECP_DP_NONE, 0, 0, NULL }, +}; + +#define ECP_NB_CURVES sizeof( ecp_supported_curves ) / \ + sizeof( ecp_supported_curves[0] ) + +static mbedtls_ecp_group_id ecp_supported_grp_id[ECP_NB_CURVES]; + +/* + * List of supported curves and associated info + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list( void ) +{ + return( ecp_supported_curves ); +} + +/* + * List of supported curves, group ID only + */ +const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list( void ) +{ + static int init_done = 0; + + if( ! init_done ) + { + size_t i = 0; + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + ecp_supported_grp_id[i++] = curve_info->grp_id; + } + ecp_supported_grp_id[i] = MBEDTLS_ECP_DP_NONE; + + init_done = 1; + } + + return( ecp_supported_grp_id ); +} + +/* + * Get the curve info for the internal identifier + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id( mbedtls_ecp_group_id grp_id ) +{ + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + if( curve_info->grp_id == grp_id ) + return( curve_info ); + } + + return( NULL ); +} + +/* + * Get the curve info from the TLS identifier + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id( uint16_t tls_id ) +{ + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + if( curve_info->tls_id == tls_id ) + return( curve_info ); + } + + return( NULL ); +} + +/* + * Get the curve info from the name + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name ) +{ + const mbedtls_ecp_curve_info *curve_info; + + if( name == NULL ) + return( NULL ); + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + if( strcmp( curve_info->name, name ) == 0 ) + return( curve_info ); + } + + return( NULL ); +} + +/* + * Get the type of a curve + */ +mbedtls_ecp_curve_type mbedtls_ecp_get_type( const mbedtls_ecp_group *grp ) +{ + if( grp->G.X.p == NULL ) + return( MBEDTLS_ECP_TYPE_NONE ); + + if( grp->G.Y.p == NULL ) + return( MBEDTLS_ECP_TYPE_MONTGOMERY ); + else + return( MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ); +} + +/* + * Initialize (the components of) a point + */ +void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ) +{ + ECP_VALIDATE( pt != NULL ); + + mbedtls_mpi_init( &pt->X ); + mbedtls_mpi_init( &pt->Y ); + mbedtls_mpi_init( &pt->Z ); +} + +/* + * Initialize (the components of) a group + */ +void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ) +{ + ECP_VALIDATE( grp != NULL ); + + grp->id = MBEDTLS_ECP_DP_NONE; + mbedtls_mpi_init( &grp->P ); + mbedtls_mpi_init( &grp->A ); + mbedtls_mpi_init( &grp->B ); + mbedtls_ecp_point_init( &grp->G ); + mbedtls_mpi_init( &grp->N ); + grp->pbits = 0; + grp->nbits = 0; + grp->h = 0; + grp->modp = NULL; + grp->t_pre = NULL; + grp->t_post = NULL; + grp->t_data = NULL; + grp->T = NULL; + grp->T_size = 0; +} + +/* + * Initialize (the components of) a key pair + */ +void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key ) +{ + ECP_VALIDATE( key != NULL ); + + mbedtls_ecp_group_init( &key->grp ); + mbedtls_mpi_init( &key->d ); + mbedtls_ecp_point_init( &key->Q ); +} + +/* + * Unallocate (the components of) a point + */ +void mbedtls_ecp_point_free( mbedtls_ecp_point *pt ) +{ + if( pt == NULL ) + return; + + mbedtls_mpi_free( &( pt->X ) ); + mbedtls_mpi_free( &( pt->Y ) ); + mbedtls_mpi_free( &( pt->Z ) ); +} + +/* + * Unallocate (the components of) a group + */ +void mbedtls_ecp_group_free( mbedtls_ecp_group *grp ) +{ + size_t i; + + if( grp == NULL ) + return; + + if( grp->h != 1 ) + { + mbedtls_mpi_free( &grp->P ); + mbedtls_mpi_free( &grp->A ); + mbedtls_mpi_free( &grp->B ); + mbedtls_ecp_point_free( &grp->G ); + mbedtls_mpi_free( &grp->N ); + } + + if( grp->T != NULL ) + { + for( i = 0; i < grp->T_size; i++ ) + mbedtls_ecp_point_free( &grp->T[i] ); + mbedtls_free( grp->T ); + } + + mbedtls_platform_zeroize( grp, sizeof( mbedtls_ecp_group ) ); +} + +/* + * Unallocate (the components of) a key pair + */ +void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key ) +{ + if( key == NULL ) + return; + + mbedtls_ecp_group_free( &key->grp ); + mbedtls_mpi_free( &key->d ); + mbedtls_ecp_point_free( &key->Q ); +} + +/* + * Copy the contents of a point + */ +int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) +{ + int ret; + ECP_VALIDATE_RET( P != NULL ); + ECP_VALIDATE_RET( Q != NULL ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->X, &Q->X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->Y, &Q->Y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->Z, &Q->Z ) ); + +cleanup: + return( ret ); +} + +/* + * Copy the contents of a group object + */ +int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src ) +{ + ECP_VALIDATE_RET( dst != NULL ); + ECP_VALIDATE_RET( src != NULL ); + + return( mbedtls_ecp_group_load( dst, src->id ) ); +} + +/* + * Set point to zero + */ +int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ) +{ + int ret; + ECP_VALIDATE_RET( pt != NULL ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->X , 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Y , 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z , 0 ) ); + +cleanup: + return( ret ); +} + +/* + * Tell if a point is zero + */ +int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ) +{ + ECP_VALIDATE_RET( pt != NULL ); + + return( mbedtls_mpi_cmp_int( &pt->Z, 0 ) == 0 ); +} + +/* + * Compare two points lazily + */ +int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ) +{ + ECP_VALIDATE_RET( P != NULL ); + ECP_VALIDATE_RET( Q != NULL ); + + if( mbedtls_mpi_cmp_mpi( &P->X, &Q->X ) == 0 && + mbedtls_mpi_cmp_mpi( &P->Y, &Q->Y ) == 0 && + mbedtls_mpi_cmp_mpi( &P->Z, &Q->Z ) == 0 ) + { + return( 0 ); + } + + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +} + +/* + * Import a non-zero point from ASCII strings + */ +int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix, + const char *x, const char *y ) +{ + int ret; + ECP_VALIDATE_RET( P != NULL ); + ECP_VALIDATE_RET( x != NULL ); + ECP_VALIDATE_RET( y != NULL ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->X, radix, x ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->Y, radix, y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &P->Z, 1 ) ); + +cleanup: + return( ret ); +} + +/* + * Export a point into unsigned binary data (SEC1 2.3.3 and RFC7748) + */ +int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *P, + int format, size_t *olen, + unsigned char *buf, size_t buflen ) +{ + int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + size_t plen; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( P != NULL ); + ECP_VALIDATE_RET( olen != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( format == MBEDTLS_ECP_PF_UNCOMPRESSED || + format == MBEDTLS_ECP_PF_COMPRESSED ); + + plen = mbedtls_mpi_size( &grp->P ); + +#if defined(ECP_MONTGOMERY) + if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY ) + { + *olen = plen; + if( buflen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary_le( &P->X, buf, plen ) ); + } +#endif +#if defined(ECP_SHORTWEIERSTRASS) + if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ) + { + /* + * Common case: P == 0 + */ + if( mbedtls_mpi_cmp_int( &P->Z, 0 ) == 0 ) + { + if( buflen < 1 ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + buf[0] = 0x00; + *olen = 1; + + return( 0 ); + } + + if( format == MBEDTLS_ECP_PF_UNCOMPRESSED ) + { + *olen = 2 * plen + 1; + + if( buflen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + buf[0] = 0x04; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->X, buf + 1, plen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->Y, buf + 1 + plen, plen ) ); + } + else if( format == MBEDTLS_ECP_PF_COMPRESSED ) + { + *olen = plen + 1; + + if( buflen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + buf[0] = 0x02 + mbedtls_mpi_get_bit( &P->Y, 0 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->X, buf + 1, plen ) ); + } + } +#endif + +cleanup: + return( ret ); +} + +/* + * Import a point from unsigned binary data (SEC1 2.3.4 and RFC7748) + */ +int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, + const unsigned char *buf, size_t ilen ) +{ + int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + size_t plen; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( pt != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + + if( ilen < 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + plen = mbedtls_mpi_size( &grp->P ); + +#if defined(ECP_MONTGOMERY) + if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY ) + { + if( plen != ilen ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary_le( &pt->X, buf, plen ) ); + mbedtls_mpi_free( &pt->Y ); + + if( grp->id == MBEDTLS_ECP_DP_CURVE25519 ) + /* Set most significant bit to 0 as prescribed in RFC7748 §5 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &pt->X, plen * 8 - 1, 0 ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) ); + } +#endif +#if defined(ECP_SHORTWEIERSTRASS) + if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ) + { + if( buf[0] == 0x00 ) + { + if( ilen == 1 ) + return( mbedtls_ecp_set_zero( pt ) ); + else + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + if( buf[0] != 0x04 ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + if( ilen != 2 * plen + 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->X, buf + 1, plen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->Y, + buf + 1 + plen, plen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) ); + } +#endif + +cleanup: + return( ret ); +} + +/* + * Import a point from a TLS ECPoint record (RFC 4492) + * struct { + * opaque point <1..2^8-1>; + * } ECPoint; + */ +int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, + const unsigned char **buf, size_t buf_len ) +{ + unsigned char data_len; + const unsigned char *buf_start; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( pt != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( *buf != NULL ); + + /* + * We must have at least two bytes (1 for length, at least one for data) + */ + if( buf_len < 2 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + data_len = *(*buf)++; + if( data_len < 1 || data_len > buf_len - 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Save buffer start for read_binary and update buf + */ + buf_start = *buf; + *buf += data_len; + + return( mbedtls_ecp_point_read_binary( grp, pt, buf_start, data_len ) ); +} + +/* + * Export a point as a TLS ECPoint record (RFC 4492) + * struct { + * opaque point <1..2^8-1>; + * } ECPoint; + */ +int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen ) +{ + int ret; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( pt != NULL ); + ECP_VALIDATE_RET( olen != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( format == MBEDTLS_ECP_PF_UNCOMPRESSED || + format == MBEDTLS_ECP_PF_COMPRESSED ); + + /* + * buffer length must be at least one, for our length byte + */ + if( blen < 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_point_write_binary( grp, pt, format, + olen, buf + 1, blen - 1) ) != 0 ) + return( ret ); + + /* + * write length to the first byte and update total length + */ + buf[0] = (unsigned char) *olen; + ++*olen; + + return( 0 ); +} + +/* + * Set a group from an ECParameters record (RFC 4492) + */ +int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, + const unsigned char **buf, size_t len ) +{ + int ret; + mbedtls_ecp_group_id grp_id; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( *buf != NULL ); + + if( ( ret = mbedtls_ecp_tls_read_group_id( &grp_id, buf, len ) ) != 0 ) + return( ret ); + + return( mbedtls_ecp_group_load( grp, grp_id ) ); +} + +/* + * Read a group id from an ECParameters record (RFC 4492) and convert it to + * mbedtls_ecp_group_id. + */ +int mbedtls_ecp_tls_read_group_id( mbedtls_ecp_group_id *grp, + const unsigned char **buf, size_t len ) +{ + uint16_t tls_id; + const mbedtls_ecp_curve_info *curve_info; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( *buf != NULL ); + + /* + * We expect at least three bytes (see below) + */ + if( len < 3 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * First byte is curve_type; only named_curve is handled + */ + if( *(*buf)++ != MBEDTLS_ECP_TLS_NAMED_CURVE ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Next two bytes are the namedcurve value + */ + tls_id = *(*buf)++; + tls_id <<= 8; + tls_id |= *(*buf)++; + + if( ( curve_info = mbedtls_ecp_curve_info_from_tls_id( tls_id ) ) == NULL ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + *grp = curve_info->grp_id; + + return( 0 ); +} + +/* + * Write the ECParameters record corresponding to a group (RFC 4492) + */ +int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, + unsigned char *buf, size_t blen ) +{ + const mbedtls_ecp_curve_info *curve_info; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( olen != NULL ); + + if( ( curve_info = mbedtls_ecp_curve_info_from_grp_id( grp->id ) ) == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * We are going to write 3 bytes (see below) + */ + *olen = 3; + if( blen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + /* + * First byte is curve_type, always named_curve + */ + *buf++ = MBEDTLS_ECP_TLS_NAMED_CURVE; + + /* + * Next two bytes are the namedcurve value + */ + buf[0] = curve_info->tls_id >> 8; + buf[1] = curve_info->tls_id & 0xFF; + + return( 0 ); +} + +/* + * Wrapper around fast quasi-modp functions, with fall-back to mbedtls_mpi_mod_mpi. + * See the documentation of struct mbedtls_ecp_group. + * + * This function is in the critial loop for mbedtls_ecp_mul, so pay attention to perf. + */ +static int ecp_modp( mbedtls_mpi *N, const mbedtls_ecp_group *grp ) +{ + int ret; + + if( grp->modp == NULL ) + return( mbedtls_mpi_mod_mpi( N, N, &grp->P ) ); + + /* N->s < 0 is a much faster test, which fails only if N is 0 */ + if( ( N->s < 0 && mbedtls_mpi_cmp_int( N, 0 ) != 0 ) || + mbedtls_mpi_bitlen( N ) > 2 * grp->pbits ) + { + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + MBEDTLS_MPI_CHK( grp->modp( N ) ); + + /* N->s < 0 is a much faster test, which fails only if N is 0 */ + while( N->s < 0 && mbedtls_mpi_cmp_int( N, 0 ) != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &grp->P ) ); + + while( mbedtls_mpi_cmp_mpi( N, &grp->P ) >= 0 ) + /* we known P, N and the result are positive */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( N, N, &grp->P ) ); + +cleanup: + return( ret ); +} + +/* + * Fast mod-p functions expect their argument to be in the 0..p^2 range. + * + * In order to guarantee that, we need to ensure that operands of + * mbedtls_mpi_mul_mpi are in the 0..p range. So, after each operation we will + * bring the result back to this range. + * + * The following macros are shortcuts for doing that. + */ + +/* + * Reduce a mbedtls_mpi mod p in-place, general case, to use after mbedtls_mpi_mul_mpi + */ +#if defined(MBEDTLS_SELF_TEST) +#define INC_MUL_COUNT mul_count++; +#else +#define INC_MUL_COUNT +#endif + +#define MOD_MUL( N ) \ + do \ + { \ + MBEDTLS_MPI_CHK( ecp_modp( &(N), grp ) ); \ + INC_MUL_COUNT \ + } while( 0 ) + +/* + * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_sub_mpi + * N->s < 0 is a very fast test, which fails only if N is 0 + */ +#define MOD_SUB( N ) \ + while( (N).s < 0 && mbedtls_mpi_cmp_int( &(N), 0 ) != 0 ) \ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &(N), &(N), &grp->P ) ) + +/* + * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_add_mpi and mbedtls_mpi_mul_int. + * We known P, N and the result are positive, so sub_abs is correct, and + * a bit faster. + */ +#define MOD_ADD( N ) \ + while( mbedtls_mpi_cmp_mpi( &(N), &grp->P ) >= 0 ) \ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &(N), &(N), &grp->P ) ) + +#if defined(ECP_SHORTWEIERSTRASS) +/* + * For curves in short Weierstrass form, we do all the internal operations in + * Jacobian coordinates. + * + * For multiplication, we'll use a comb method with coutermeasueres against + * SPA, hence timing attacks. + */ + +/* + * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1) + * Cost: 1N := 1I + 3M + 1S + */ +static int ecp_normalize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt ) +{ + int ret; + mbedtls_mpi Zi, ZZi; + + if( mbedtls_mpi_cmp_int( &pt->Z, 0 ) == 0 ) + return( 0 ); + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_normalize_jac( grp, pt ) ); +#endif /* MBEDTLS_ECP_NORMALIZE_JAC_ALT */ + + mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi ); + + /* + * X = X / Z^2 mod p + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &Zi, &pt->Z, &grp->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->X, &pt->X, &ZZi ) ); MOD_MUL( pt->X ); + + /* + * Y = Y / Z^3 mod p + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y, &pt->Y, &ZZi ) ); MOD_MUL( pt->Y ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y, &pt->Y, &Zi ) ); MOD_MUL( pt->Y ); + + /* + * Z = 1 + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) ); + +cleanup: + + mbedtls_mpi_free( &Zi ); mbedtls_mpi_free( &ZZi ); + + return( ret ); +} + +/* + * Normalize jacobian coordinates of an array of (pointers to) points, + * using Montgomery's trick to perform only one inversion mod P. + * (See for example Cohen's "A Course in Computational Algebraic Number + * Theory", Algorithm 10.3.4.) + * + * Warning: fails (returning an error) if one of the points is zero! + * This should never happen, see choice of w in ecp_mul_comb(). + * + * Cost: 1N(t) := 1I + (6t - 3)M + 1S + */ +static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *T[], size_t T_size ) +{ + int ret; + size_t i; + mbedtls_mpi *c, u, Zi, ZZi; + + if( T_size < 2 ) + return( ecp_normalize_jac( grp, *T ) ); + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_normalize_jac_many( grp, T, T_size ) ); +#endif + + if( ( c = mbedtls_calloc( T_size, sizeof( mbedtls_mpi ) ) ) == NULL ) + return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); + + for( i = 0; i < T_size; i++ ) + mbedtls_mpi_init( &c[i] ); + + mbedtls_mpi_init( &u ); mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi ); + + /* + * c[i] = Z_0 * ... * Z_i + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &c[0], &T[0]->Z ) ); + for( i = 1; i < T_size; i++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &c[i], &c[i-1], &T[i]->Z ) ); + MOD_MUL( c[i] ); + } + + /* + * u = 1 / (Z_0 * ... * Z_n) mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &u, &c[T_size-1], &grp->P ) ); + + for( i = T_size - 1; ; i-- ) + { + /* + * Zi = 1 / Z_i mod p + * u = 1 / (Z_0 * ... * Z_i) mod P + */ + if( i == 0 ) { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Zi, &u ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &Zi, &u, &c[i-1] ) ); MOD_MUL( Zi ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u, &u, &T[i]->Z ) ); MOD_MUL( u ); + } + + /* + * proceed as in normalize() + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->X, &T[i]->X, &ZZi ) ); MOD_MUL( T[i]->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->Y, &T[i]->Y, &ZZi ) ); MOD_MUL( T[i]->Y ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->Y, &T[i]->Y, &Zi ) ); MOD_MUL( T[i]->Y ); + + /* + * Post-precessing: reclaim some memory by shrinking coordinates + * - not storing Z (always 1) + * - shrinking other coordinates, but still keeping the same number of + * limbs as P, as otherwise it will too likely be regrown too fast. + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_shrink( &T[i]->X, grp->P.n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shrink( &T[i]->Y, grp->P.n ) ); + mbedtls_mpi_free( &T[i]->Z ); + + if( i == 0 ) + break; + } + +cleanup: + + mbedtls_mpi_free( &u ); mbedtls_mpi_free( &Zi ); mbedtls_mpi_free( &ZZi ); + for( i = 0; i < T_size; i++ ) + mbedtls_mpi_free( &c[i] ); + mbedtls_free( c ); + + return( ret ); +} + +/* + * Conditional point inversion: Q -> -Q = (Q.X, -Q.Y, Q.Z) without leak. + * "inv" must be 0 (don't invert) or 1 (invert) or the result will be invalid + */ +static int ecp_safe_invert_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *Q, + unsigned char inv ) +{ + int ret; + unsigned char nonzero; + mbedtls_mpi mQY; + + mbedtls_mpi_init( &mQY ); + + /* Use the fact that -Q.Y mod P = P - Q.Y unless Q.Y == 0 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mQY, &grp->P, &Q->Y ) ); + nonzero = mbedtls_mpi_cmp_int( &Q->Y, 0 ) != 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &Q->Y, &mQY, inv & nonzero ) ); + +cleanup: + mbedtls_mpi_free( &mQY ); + + return( ret ); +} + +/* + * Point doubling R = 2 P, Jacobian coordinates + * + * Based on http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2 . + * + * We follow the variable naming fairly closely. The formula variations that trade a MUL for a SQR + * (plus a few ADDs) aren't useful as our bignum implementation doesn't distinguish squaring. + * + * Standard optimizations are applied when curve parameter A is one of { 0, -3 }. + * + * Cost: 1D := 3M + 4S (A == 0) + * 4M + 4S (A == -3) + * 3M + 6S + 1a otherwise + */ +static int ecp_double_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *P ) +{ + int ret; + mbedtls_mpi M, S, T, U; + +#if defined(MBEDTLS_SELF_TEST) + dbl_count++; +#endif + +#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_double_jac( grp, R, P ) ); +#endif /* MBEDTLS_ECP_DOUBLE_JAC_ALT */ + + mbedtls_mpi_init( &M ); mbedtls_mpi_init( &S ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &U ); + + /* Special case for A = -3 */ + if( grp->A.p == NULL ) + { + /* M = 3(X + Z^2)(X - Z^2) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->Z, &P->Z ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T, &P->X, &S ) ); MOD_ADD( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U, &P->X, &S ) ); MOD_SUB( U ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &T, &U ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &M, &S, 3 ) ); MOD_ADD( M ); + } + else + { + /* M = 3.X^2 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->X, &P->X ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &M, &S, 3 ) ); MOD_ADD( M ); + + /* Optimize away for "koblitz" curves with A = 0 */ + if( mbedtls_mpi_cmp_int( &grp->A, 0 ) != 0 ) + { + /* M += A.Z^4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->Z, &P->Z ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &S, &S ) ); MOD_MUL( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &T, &grp->A ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &M, &M, &S ) ); MOD_ADD( M ); + } + } + + /* S = 4.X.Y^2 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &P->Y, &P->Y ) ); MOD_MUL( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T, 1 ) ); MOD_ADD( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->X, &T ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &S, 1 ) ); MOD_ADD( S ); + + /* U = 8.Y^4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &U, &T, &T ) ); MOD_MUL( U ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &U, 1 ) ); MOD_ADD( U ); + + /* T = M^2 - 2.S */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &M, &M ) ); MOD_MUL( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T, &S ) ); MOD_SUB( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T, &S ) ); MOD_SUB( T ); + + /* S = M(S - T) - U */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S, &S, &T ) ); MOD_SUB( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &S, &M ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S, &S, &U ) ); MOD_SUB( S ); + + /* U = 2.Y.Z */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &U, &P->Y, &P->Z ) ); MOD_MUL( U ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &U, 1 ) ); MOD_ADD( U ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->X, &T ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Y, &S ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Z, &U ) ); + +cleanup: + mbedtls_mpi_free( &M ); mbedtls_mpi_free( &S ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &U ); + + return( ret ); +} + +/* + * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22) + * + * The coordinates of Q must be normalized (= affine), + * but those of P don't need to. R is not normalized. + * + * Special cases: (1) P or Q is zero, (2) R is zero, (3) P == Q. + * None of these cases can happen as intermediate step in ecp_mul_comb(): + * - at each step, P, Q and R are multiples of the base point, the factor + * being less than its order, so none of them is zero; + * - Q is an odd multiple of the base point, P an even multiple, + * due to the choice of precomputed points in the modified comb method. + * So branches for these cases do not leak secret information. + * + * We accept Q->Z being unset (saving memory in tables) as meaning 1. + * + * Cost: 1A := 8M + 3S + */ +static int ecp_add_mixed( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) +{ + int ret; + mbedtls_mpi T1, T2, T3, T4, X, Y, Z; + +#if defined(MBEDTLS_SELF_TEST) + add_count++; +#endif + +#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_add_mixed( grp, R, P, Q ) ); +#endif /* MBEDTLS_ECP_ADD_MIXED_ALT */ + + /* + * Trivial cases: P == 0 or Q == 0 (case 1) + */ + if( mbedtls_mpi_cmp_int( &P->Z, 0 ) == 0 ) + return( mbedtls_ecp_copy( R, Q ) ); + + if( Q->Z.p != NULL && mbedtls_mpi_cmp_int( &Q->Z, 0 ) == 0 ) + return( mbedtls_ecp_copy( R, P ) ); + + /* + * Make sure Q coordinates are normalized + */ + if( Q->Z.p != NULL && mbedtls_mpi_cmp_int( &Q->Z, 1 ) != 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 ); mbedtls_mpi_init( &T3 ); mbedtls_mpi_init( &T4 ); + mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T2, &T1, &P->Z ) ); MOD_MUL( T2 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T1, &Q->X ) ); MOD_MUL( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T2, &T2, &Q->Y ) ); MOD_MUL( T2 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T1, &T1, &P->X ) ); MOD_SUB( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T2, &T2, &P->Y ) ); MOD_SUB( T2 ); + + /* Special cases (2) and (3) */ + if( mbedtls_mpi_cmp_int( &T1, 0 ) == 0 ) + { + if( mbedtls_mpi_cmp_int( &T2, 0 ) == 0 ) + { + ret = ecp_double_jac( grp, R, P ); + goto cleanup; + } + else + { + ret = mbedtls_ecp_set_zero( R ); + goto cleanup; + } + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &Z, &P->Z, &T1 ) ); MOD_MUL( Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3, &T1, &T1 ) ); MOD_MUL( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T4, &T3, &T1 ) ); MOD_MUL( T4 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3, &T3, &P->X ) ); MOD_MUL( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T4 ) ); MOD_SUB( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T3, &T3, &X ) ); MOD_SUB( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3, &T3, &T2 ) ); MOD_MUL( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T4, &T4, &P->Y ) ); MOD_MUL( T4 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &Y, &T3, &T4 ) ); MOD_SUB( Y ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->X, &X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Y, &Y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Z, &Z ) ); + +cleanup: + + mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); mbedtls_mpi_free( &T3 ); mbedtls_mpi_free( &T4 ); + mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); + + return( ret ); +} + +/* + * Randomize jacobian coordinates: + * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l + * This is sort of the reverse operation of ecp_normalize_jac(). + * + * This countermeasure was first suggested in [2]. + */ +static int ecp_randomize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + mbedtls_mpi l, ll; + size_t p_size; + int count = 0; + +#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_randomize_jac( grp, pt, f_rng, p_rng ) ); +#endif /* MBEDTLS_ECP_RANDOMIZE_JAC_ALT */ + + p_size = ( grp->pbits + 7 ) / 8; + mbedtls_mpi_init( &l ); mbedtls_mpi_init( &ll ); + + /* Generate l such that 1 < l < p */ + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &l, p_size, f_rng, p_rng ) ); + + while( mbedtls_mpi_cmp_mpi( &l, &grp->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &l, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( &l, 1 ) <= 0 ); + + /* Z = l * Z */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Z, &pt->Z, &l ) ); MOD_MUL( pt->Z ); + + /* X = l^2 * X */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ll, &l, &l ) ); MOD_MUL( ll ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->X, &pt->X, &ll ) ); MOD_MUL( pt->X ); + + /* Y = l^3 * Y */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ll, &ll, &l ) ); MOD_MUL( ll ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y, &pt->Y, &ll ) ); MOD_MUL( pt->Y ); + +cleanup: + mbedtls_mpi_free( &l ); mbedtls_mpi_free( &ll ); + + return( ret ); +} + +/* + * Check and define parameters used by the comb method (see below for details) + */ +#if MBEDTLS_ECP_WINDOW_SIZE < 2 || MBEDTLS_ECP_WINDOW_SIZE > 7 +#error "MBEDTLS_ECP_WINDOW_SIZE out of bounds" +#endif + +/* d = ceil( n / w ) */ +#define COMB_MAX_D ( MBEDTLS_ECP_MAX_BITS + 1 ) / 2 + +/* number of precomputed points */ +#define COMB_MAX_PRE ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) ) + +/* + * Compute the representation of m that will be used with our comb method. + * + * The basic comb method is described in GECC 3.44 for example. We use a + * modified version that provides resistance to SPA by avoiding zero + * digits in the representation as in [3]. We modify the method further by + * requiring that all K_i be odd, which has the small cost that our + * representation uses one more K_i, due to carries, but saves on the size of + * the precomputed table. + * + * Summary of the comb method and its modifications: + * + * - The goal is to compute m*P for some w*d-bit integer m. + * + * - The basic comb method splits m into the w-bit integers + * x[0] .. x[d-1] where x[i] consists of the bits in m whose + * index has residue i modulo d, and computes m * P as + * S[x[0]] + 2 * S[x[1]] + .. + 2^(d-1) S[x[d-1]], where + * S[i_{w-1} .. i_0] := i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + i_0 P. + * + * - If it happens that, say, x[i+1]=0 (=> S[x[i+1]]=0), one can replace the sum by + * .. + 2^{i-1} S[x[i-1]] - 2^i S[x[i]] + 2^{i+1} S[x[i]] + 2^{i+2} S[x[i+2]] .., + * thereby successively converting it into a form where all summands + * are nonzero, at the cost of negative summands. This is the basic idea of [3]. + * + * - More generally, even if x[i+1] != 0, we can first transform the sum as + * .. - 2^i S[x[i]] + 2^{i+1} ( S[x[i]] + S[x[i+1]] ) + 2^{i+2} S[x[i+2]] .., + * and then replace S[x[i]] + S[x[i+1]] = S[x[i] ^ x[i+1]] + 2 S[x[i] & x[i+1]]. + * Performing and iterating this procedure for those x[i] that are even + * (keeping track of carry), we can transform the original sum into one of the form + * S[x'[0]] +- 2 S[x'[1]] +- .. +- 2^{d-1} S[x'[d-1]] + 2^d S[x'[d]] + * with all x'[i] odd. It is therefore only necessary to know S at odd indices, + * which is why we are only computing half of it in the first place in + * ecp_precompute_comb and accessing it with index abs(i) / 2 in ecp_select_comb. + * + * - For the sake of compactness, only the seven low-order bits of x[i] + * are used to represent its absolute value (K_i in the paper), and the msb + * of x[i] encodes the sign (s_i in the paper): it is set if and only if + * if s_i == -1; + * + * Calling conventions: + * - x is an array of size d + 1 + * - w is the size, ie number of teeth, of the comb, and must be between + * 2 and 7 (in practice, between 2 and MBEDTLS_ECP_WINDOW_SIZE) + * - m is the MPI, expected to be odd and such that bitlength(m) <= w * d + * (the result will be incorrect if these assumptions are not satisfied) + */ +static void ecp_comb_recode_core( unsigned char x[], size_t d, + unsigned char w, const mbedtls_mpi *m ) +{ + size_t i, j; + unsigned char c, cc, adjust; + + memset( x, 0, d+1 ); + + /* First get the classical comb values (except for x_d = 0) */ + for( i = 0; i < d; i++ ) + for( j = 0; j < w; j++ ) + x[i] |= mbedtls_mpi_get_bit( m, i + d * j ) << j; + + /* Now make sure x_1 .. x_d are odd */ + c = 0; + for( i = 1; i <= d; i++ ) + { + /* Add carry and update it */ + cc = x[i] & c; + x[i] = x[i] ^ c; + c = cc; + + /* Adjust if needed, avoiding branches */ + adjust = 1 - ( x[i] & 0x01 ); + c |= x[i] & ( x[i-1] * adjust ); + x[i] = x[i] ^ ( x[i-1] * adjust ); + x[i-1] |= adjust << 7; + } +} + +/* + * Precompute points for the adapted comb method + * + * Assumption: T must be able to hold 2^{w - 1} elements. + * + * Operation: If i = i_{w-1} ... i_1 is the binary representation of i, + * sets T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P. + * + * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1) + * + * Note: Even comb values (those where P would be omitted from the + * sum defining T[i] above) are not needed in our adaption + * the comb method. See ecp_comb_recode_core(). + * + * This function currently works in four steps: + * (1) [dbl] Computation of intermediate T[i] for 2-power values of i + * (2) [norm_dbl] Normalization of coordinates of these T[i] + * (3) [add] Computation of all T[i] + * (4) [norm_add] Normalization of all T[i] + * + * Step 1 can be interrupted but not the others; together with the final + * coordinate normalization they are the largest steps done at once, depending + * on the window size. Here are operation counts for P-256: + * + * step (2) (3) (4) + * w = 5 142 165 208 + * w = 4 136 77 160 + * w = 3 130 33 136 + * w = 2 124 11 124 + * + * So if ECC operations are blocking for too long even with a low max_ops + * value, it's useful to set MBEDTLS_ECP_WINDOW_SIZE to a lower value in order + * to minimize maximum blocking time. + */ +static int ecp_precompute_comb( const mbedtls_ecp_group *grp, + mbedtls_ecp_point T[], const mbedtls_ecp_point *P, + unsigned char w, size_t d, + mbedtls_ecp_restart_ctx *rs_ctx ) +{ + int ret; + unsigned char i; + size_t j = 0; + const unsigned char T_size = 1U << ( w - 1 ); + mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1]; + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + { + if( rs_ctx->rsm->state == ecp_rsm_pre_dbl ) + goto dbl; + if( rs_ctx->rsm->state == ecp_rsm_pre_norm_dbl ) + goto norm_dbl; + if( rs_ctx->rsm->state == ecp_rsm_pre_add ) + goto add; + if( rs_ctx->rsm->state == ecp_rsm_pre_norm_add ) + goto norm_add; + } +#else + (void) rs_ctx; +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + { + rs_ctx->rsm->state = ecp_rsm_pre_dbl; + + /* initial state for the loop */ + rs_ctx->rsm->i = 0; + } + +dbl: +#endif + /* + * Set T[0] = P and + * T[2^{l-1}] = 2^{dl} P for l = 1 .. w-1 (this is not the final value) + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( &T[0], P ) ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0 ) + j = rs_ctx->rsm->i; + else +#endif + j = 0; + + for( ; j < d * ( w - 1 ); j++ ) + { + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_DBL ); + + i = 1U << ( j / d ); + cur = T + i; + + if( j % d == 0 ) + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( cur, T + ( i >> 1 ) ) ); + + MBEDTLS_MPI_CHK( ecp_double_jac( grp, cur, cur ) ); + } + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + rs_ctx->rsm->state = ecp_rsm_pre_norm_dbl; + +norm_dbl: +#endif + /* + * Normalize current elements in T. As T has holes, + * use an auxiliary array of pointers to elements in T. + */ + j = 0; + for( i = 1; i < T_size; i <<= 1 ) + TT[j++] = T + i; + + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV + 6 * j - 2 ); + + MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, j ) ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + rs_ctx->rsm->state = ecp_rsm_pre_add; + +add: +#endif + /* + * Compute the remaining ones using the minimal number of additions + * Be careful to update T[2^l] only after using it! + */ + MBEDTLS_ECP_BUDGET( ( T_size - 1 ) * MBEDTLS_ECP_OPS_ADD ); + + for( i = 1; i < T_size; i <<= 1 ) + { + j = i; + while( j-- ) + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, &T[i + j], &T[j], &T[i] ) ); + } + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + rs_ctx->rsm->state = ecp_rsm_pre_norm_add; + +norm_add: +#endif + /* + * Normalize final elements in T. Even though there are no holes now, we + * still need the auxiliary array for homogeneity with the previous + * call. Also, skip T[0] which is already normalised, being a copy of P. + */ + for( j = 0; j + 1 < T_size; j++ ) + TT[j] = T + j + 1; + + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV + 6 * j - 2 ); + + MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, j ) ); + +cleanup: +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL && + ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + { + if( rs_ctx->rsm->state == ecp_rsm_pre_dbl ) + rs_ctx->rsm->i = j; + } +#endif + + return( ret ); +} + +/* + * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ] + * + * See ecp_comb_recode_core() for background + */ +static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point T[], unsigned char T_size, + unsigned char i ) +{ + int ret; + unsigned char ii, j; + + /* Ignore the "sign" bit and scale down */ + ii = ( i & 0x7Fu ) >> 1; + + /* Read the whole table to thwart cache-based timing attacks */ + for( j = 0; j < T_size; j++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->X, &T[j].X, j == ii ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->Y, &T[j].Y, j == ii ) ); + } + + /* Safely invert result if i is "negative" */ + MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, R, i >> 7 ) ); + +cleanup: + return( ret ); +} + +/* + * Core multiplication algorithm for the (modified) comb method. + * This part is actually common with the basic comb method (GECC 3.44) + * + * Cost: d A + d D + 1 R + */ +static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point T[], unsigned char T_size, + const unsigned char x[], size_t d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx ) +{ + int ret; + mbedtls_ecp_point Txi; + size_t i; + + mbedtls_ecp_point_init( &Txi ); + +#if !defined(MBEDTLS_ECP_RESTARTABLE) + (void) rs_ctx; +#endif + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL && + rs_ctx->rsm->state != ecp_rsm_comb_core ) + { + rs_ctx->rsm->i = 0; + rs_ctx->rsm->state = ecp_rsm_comb_core; + } + + /* new 'if' instead of nested for the sake of the 'else' branch */ + if( rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0 ) + { + /* restore current index (R already pointing to rs_ctx->rsm->R) */ + i = rs_ctx->rsm->i; + } + else +#endif + { + /* Start with a non-zero point and randomize its coordinates */ + i = d; + MBEDTLS_MPI_CHK( ecp_select_comb( grp, R, T, T_size, x[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 1 ) ); + if( f_rng != 0 ) + MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) ); + } + + while( i != 0 ) + { + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_DBL + MBEDTLS_ECP_OPS_ADD ); + --i; + + MBEDTLS_MPI_CHK( ecp_double_jac( grp, R, R ) ); + MBEDTLS_MPI_CHK( ecp_select_comb( grp, &Txi, T, T_size, x[i] ) ); + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, R, &Txi ) ); + } + +cleanup: + + mbedtls_ecp_point_free( &Txi ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL && + ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + { + rs_ctx->rsm->i = i; + /* no need to save R, already pointing to rs_ctx->rsm->R */ + } +#endif + + return( ret ); +} + +/* + * Recode the scalar to get constant-time comb multiplication + * + * As the actual scalar recoding needs an odd scalar as a starting point, + * this wrapper ensures that by replacing m by N - m if necessary, and + * informs the caller that the result of multiplication will be negated. + * + * This works because we only support large prime order for Short Weierstrass + * curves, so N is always odd hence either m or N - m is. + * + * See ecp_comb_recode_core() for background. + */ +static int ecp_comb_recode_scalar( const mbedtls_ecp_group *grp, + const mbedtls_mpi *m, + unsigned char k[COMB_MAX_D + 1], + size_t d, + unsigned char w, + unsigned char *parity_trick ) +{ + int ret; + mbedtls_mpi M, mm; + + mbedtls_mpi_init( &M ); + mbedtls_mpi_init( &mm ); + + /* N is always odd (see above), just make extra sure */ + if( mbedtls_mpi_get_bit( &grp->N, 0 ) != 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* do we need the parity trick? */ + *parity_trick = ( mbedtls_mpi_get_bit( m, 0 ) == 0 ); + + /* execute parity fix in constant time */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &M, m ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mm, &grp->N, m ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &M, &mm, *parity_trick ) ); + + /* actual scalar recoding */ + ecp_comb_recode_core( k, d, w, &M ); + +cleanup: + mbedtls_mpi_free( &mm ); + mbedtls_mpi_free( &M ); + + return( ret ); +} + +/* + * Perform comb multiplication (for short Weierstrass curves) + * once the auxiliary table has been pre-computed. + * + * Scalar recoding may use a parity trick that makes us compute -m * P, + * if that is the case we'll need to recover m * P at the end. + */ +static int ecp_mul_comb_after_precomp( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + const mbedtls_mpi *m, + const mbedtls_ecp_point *T, + unsigned char T_size, + unsigned char w, + size_t d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx ) +{ + int ret; + unsigned char parity_trick; + unsigned char k[COMB_MAX_D + 1]; + mbedtls_ecp_point *RR = R; + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + { + RR = &rs_ctx->rsm->R; + + if( rs_ctx->rsm->state == ecp_rsm_final_norm ) + goto final_norm; + } +#endif + + MBEDTLS_MPI_CHK( ecp_comb_recode_scalar( grp, m, k, d, w, + &parity_trick ) ); + MBEDTLS_MPI_CHK( ecp_mul_comb_core( grp, RR, T, T_size, k, d, + f_rng, p_rng, rs_ctx ) ); + MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, RR, parity_trick ) ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + rs_ctx->rsm->state = ecp_rsm_final_norm; + +final_norm: +#endif + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV ); + MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, RR ) ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL ) + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, RR ) ); +#endif + +cleanup: + return( ret ); +} + +/* + * Pick window size based on curve size and whether we optimize for base point + */ +static unsigned char ecp_pick_window_size( const mbedtls_ecp_group *grp, + unsigned char p_eq_g ) +{ + unsigned char w; + + /* + * Minimize the number of multiplications, that is minimize + * 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w ) + * (see costs of the various parts, with 1S = 1M) + */ + w = grp->nbits >= 384 ? 5 : 4; + + /* + * If P == G, pre-compute a bit more, since this may be re-used later. + * Just adding one avoids upping the cost of the first mul too much, + * and the memory cost too. + */ + if( p_eq_g ) + w++; + + /* + * Make sure w is within bounds. + * (The last test is useful only for very small curves in the test suite.) + */ + if( w > MBEDTLS_ECP_WINDOW_SIZE ) + w = MBEDTLS_ECP_WINDOW_SIZE; + if( w >= grp->nbits ) + w = 2; + + return( w ); +} + +/* + * Multiplication using the comb method - for curves in short Weierstrass form + * + * This function is mainly responsible for administrative work: + * - managing the restart context if enabled + * - managing the table of precomputed points (passed between the below two + * functions): allocation, computation, ownership tranfer, freeing. + * + * It delegates the actual arithmetic work to: + * ecp_precompute_comb() and ecp_mul_comb_with_precomp() + * + * See comments on ecp_comb_recode_core() regarding the computation strategy. + */ +static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx ) +{ + int ret; + unsigned char w, p_eq_g, i; + size_t d; + unsigned char T_size, T_ok; + mbedtls_ecp_point *T; + + ECP_RS_ENTER( rsm ); + + /* Is P the base point ? */ +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 + p_eq_g = ( mbedtls_mpi_cmp_mpi( &P->Y, &grp->G.Y ) == 0 && + mbedtls_mpi_cmp_mpi( &P->X, &grp->G.X ) == 0 ); +#else + p_eq_g = 0; +#endif + + /* Pick window size and deduce related sizes */ + w = ecp_pick_window_size( grp, p_eq_g ); + T_size = 1U << ( w - 1 ); + d = ( grp->nbits + w - 1 ) / w; + + /* Pre-computed table: do we have it already for the base point? */ + if( p_eq_g && grp->T != NULL ) + { + /* second pointer to the same table, will be deleted on exit */ + T = grp->T; + T_ok = 1; + } + else +#if defined(MBEDTLS_ECP_RESTARTABLE) + /* Pre-computed table: do we have one in progress? complete? */ + if( rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->T != NULL ) + { + /* transfer ownership of T from rsm to local function */ + T = rs_ctx->rsm->T; + rs_ctx->rsm->T = NULL; + rs_ctx->rsm->T_size = 0; + + /* This effectively jumps to the call to mul_comb_after_precomp() */ + T_ok = rs_ctx->rsm->state >= ecp_rsm_comb_core; + } + else +#endif + /* Allocate table if we didn't have any */ + { + T = mbedtls_calloc( T_size, sizeof( mbedtls_ecp_point ) ); + if( T == NULL ) + { + ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; + goto cleanup; + } + + for( i = 0; i < T_size; i++ ) + mbedtls_ecp_point_init( &T[i] ); + + T_ok = 0; + } + + /* Compute table (or finish computing it) if not done already */ + if( !T_ok ) + { + MBEDTLS_MPI_CHK( ecp_precompute_comb( grp, T, P, w, d, rs_ctx ) ); + + if( p_eq_g ) + { + /* almost transfer ownership of T to the group, but keep a copy of + * the pointer to use for calling the next function more easily */ + grp->T = T; + grp->T_size = T_size; + } + } + + /* Actual comb multiplication using precomputed points */ + MBEDTLS_MPI_CHK( ecp_mul_comb_after_precomp( grp, R, m, + T, T_size, w, d, + f_rng, p_rng, rs_ctx ) ); + +cleanup: + + /* does T belong to the group? */ + if( T == grp->T ) + T = NULL; + + /* does T belong to the restart context? */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->rsm != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS && T != NULL ) + { + /* transfer ownership of T from local function to rsm */ + rs_ctx->rsm->T_size = T_size; + rs_ctx->rsm->T = T; + T = NULL; + } +#endif + + /* did T belong to us? then let's destroy it! */ + if( T != NULL ) + { + for( i = 0; i < T_size; i++ ) + mbedtls_ecp_point_free( &T[i] ); + mbedtls_free( T ); + } + + /* don't free R while in progress in case R == P */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) +#endif + /* prevent caller from using invalid value */ + if( ret != 0 ) + mbedtls_ecp_point_free( R ); + + ECP_RS_LEAVE( rsm ); + + return( ret ); +} + +#endif /* ECP_SHORTWEIERSTRASS */ + +#if defined(ECP_MONTGOMERY) +/* + * For Montgomery curves, we do all the internal arithmetic in projective + * coordinates. Import/export of points uses only the x coordinates, which is + * internaly represented as X / Z. + * + * For scalar multiplication, we'll use a Montgomery ladder. + */ + +/* + * Normalize Montgomery x/z coordinates: X = X/Z, Z = 1 + * Cost: 1M + 1I + */ +static int ecp_normalize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P ) +{ + int ret; + +#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_normalize_mxz( grp, P ) ); +#endif /* MBEDTLS_ECP_NORMALIZE_MXZ_ALT */ + + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &P->Z, &P->Z, &grp->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->X, &P->X, &P->Z ) ); MOD_MUL( P->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &P->Z, 1 ) ); + +cleanup: + return( ret ); +} + +/* + * Randomize projective x/z coordinates: + * (X, Z) -> (l X, l Z) for random l + * This is sort of the reverse operation of ecp_normalize_mxz(). + * + * This countermeasure was first suggested in [2]. + * Cost: 2M + */ +static int ecp_randomize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + mbedtls_mpi l; + size_t p_size; + int count = 0; + +#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_randomize_mxz( grp, P, f_rng, p_rng ); +#endif /* MBEDTLS_ECP_RANDOMIZE_MXZ_ALT */ + + p_size = ( grp->pbits + 7 ) / 8; + mbedtls_mpi_init( &l ); + + /* Generate l such that 1 < l < p */ + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &l, p_size, f_rng, p_rng ) ); + + while( mbedtls_mpi_cmp_mpi( &l, &grp->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &l, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( &l, 1 ) <= 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->X, &P->X, &l ) ); MOD_MUL( P->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->Z, &P->Z, &l ) ); MOD_MUL( P->Z ); + +cleanup: + mbedtls_mpi_free( &l ); + + return( ret ); +} + +/* + * Double-and-add: R = 2P, S = P + Q, with d = X(P - Q), + * for Montgomery curves in x/z coordinates. + * + * http://www.hyperelliptic.org/EFD/g1p/auto-code/montgom/xz/ladder/mladd-1987-m.op3 + * with + * d = X1 + * P = (X2, Z2) + * Q = (X3, Z3) + * R = (X4, Z4) + * S = (X5, Z5) + * and eliminating temporary variables tO, ..., t4. + * + * Cost: 5M + 4S + */ +static int ecp_double_add_mxz( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, mbedtls_ecp_point *S, + const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q, + const mbedtls_mpi *d ) +{ + int ret; + mbedtls_mpi A, AA, B, BB, E, C, D, DA, CB; + +#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) + if( mbedtls_internal_ecp_grp_capable( grp ) ) + return( mbedtls_internal_ecp_double_add_mxz( grp, R, S, P, Q, d ) ); +#endif /* MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT */ + + mbedtls_mpi_init( &A ); mbedtls_mpi_init( &AA ); mbedtls_mpi_init( &B ); + mbedtls_mpi_init( &BB ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &C ); + mbedtls_mpi_init( &D ); mbedtls_mpi_init( &DA ); mbedtls_mpi_init( &CB ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &A, &P->X, &P->Z ) ); MOD_ADD( A ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &AA, &A, &A ) ); MOD_MUL( AA ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &B, &P->X, &P->Z ) ); MOD_SUB( B ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &BB, &B, &B ) ); MOD_MUL( BB ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &E, &AA, &BB ) ); MOD_SUB( E ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &C, &Q->X, &Q->Z ) ); MOD_ADD( C ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &D, &Q->X, &Q->Z ) ); MOD_SUB( D ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DA, &D, &A ) ); MOD_MUL( DA ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &CB, &C, &B ) ); MOD_MUL( CB ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &S->X, &DA, &CB ) ); MOD_MUL( S->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->X, &S->X, &S->X ) ); MOD_MUL( S->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S->Z, &DA, &CB ) ); MOD_SUB( S->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->Z, &S->Z, &S->Z ) ); MOD_MUL( S->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->Z, d, &S->Z ) ); MOD_MUL( S->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->X, &AA, &BB ) ); MOD_MUL( R->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->Z, &grp->A, &E ) ); MOD_MUL( R->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &R->Z, &BB, &R->Z ) ); MOD_ADD( R->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->Z, &E, &R->Z ) ); MOD_MUL( R->Z ); + +cleanup: + mbedtls_mpi_free( &A ); mbedtls_mpi_free( &AA ); mbedtls_mpi_free( &B ); + mbedtls_mpi_free( &BB ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &C ); + mbedtls_mpi_free( &D ); mbedtls_mpi_free( &DA ); mbedtls_mpi_free( &CB ); + + return( ret ); +} + +/* + * Multiplication with Montgomery ladder in x/z coordinates, + * for curves in Montgomery form + */ +static int ecp_mul_mxz( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t i; + unsigned char b; + mbedtls_ecp_point RP; + mbedtls_mpi PX; + + mbedtls_ecp_point_init( &RP ); mbedtls_mpi_init( &PX ); + + /* Save PX and read from P before writing to R, in case P == R */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &PX, &P->X ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( &RP, P ) ); + + /* Set R to zero in modified x/z coordinates */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->X, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 0 ) ); + mbedtls_mpi_free( &R->Y ); + + /* RP.X might be sligtly larger than P, so reduce it */ + MOD_ADD( RP.X ); + + /* Randomize coordinates of the starting point */ + if( f_rng != NULL ) + MBEDTLS_MPI_CHK( ecp_randomize_mxz( grp, &RP, f_rng, p_rng ) ); + + /* Loop invariant: R = result so far, RP = R + P */ + i = mbedtls_mpi_bitlen( m ); /* one past the (zero-based) most significant bit */ + while( i-- > 0 ) + { + b = mbedtls_mpi_get_bit( m, i ); + /* + * if (b) R = 2R + P else R = 2R, + * which is: + * if (b) double_add( RP, R, RP, R ) + * else double_add( R, RP, R, RP ) + * but using safe conditional swaps to avoid leaks + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->X, &RP.X, b ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->Z, &RP.Z, b ) ); + MBEDTLS_MPI_CHK( ecp_double_add_mxz( grp, R, &RP, R, &RP, &PX ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->X, &RP.X, b ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->Z, &RP.Z, b ) ); + } + + MBEDTLS_MPI_CHK( ecp_normalize_mxz( grp, R ) ); + +cleanup: + mbedtls_ecp_point_free( &RP ); mbedtls_mpi_free( &PX ); + + return( ret ); +} + +#endif /* ECP_MONTGOMERY */ + +/* + * Restartable multiplication R = m * P + */ +int mbedtls_ecp_mul_restartable( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_ecp_restart_ctx *rs_ctx ) +{ + int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + char is_grp_capable = 0; +#endif + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( R != NULL ); + ECP_VALIDATE_RET( m != NULL ); + ECP_VALIDATE_RET( P != NULL ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + /* reset ops count for this call if top-level */ + if( rs_ctx != NULL && rs_ctx->depth++ == 0 ) + rs_ctx->ops_done = 0; +#endif + +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + if( ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) ) + MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) ); +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ + +#if defined(MBEDTLS_ECP_RESTARTABLE) + /* skip argument check when restarting */ + if( rs_ctx == NULL || rs_ctx->rsm == NULL ) +#endif + { + /* check_privkey is free */ + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_CHK ); + + /* Common sanity checks */ + MBEDTLS_MPI_CHK( mbedtls_ecp_check_privkey( grp, m ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, P ) ); + } + + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; +#if defined(ECP_MONTGOMERY) + if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY ) + MBEDTLS_MPI_CHK( ecp_mul_mxz( grp, R, m, P, f_rng, p_rng ) ); +#endif +#if defined(ECP_SHORTWEIERSTRASS) + if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ) + MBEDTLS_MPI_CHK( ecp_mul_comb( grp, R, m, P, f_rng, p_rng, rs_ctx ) ); +#endif + +cleanup: + +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + if( is_grp_capable ) + mbedtls_internal_ecp_free( grp ); +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL ) + rs_ctx->depth--; +#endif + + return( ret ); +} + +/* + * Multiplication R = m * P + */ +int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( R != NULL ); + ECP_VALIDATE_RET( m != NULL ); + ECP_VALIDATE_RET( P != NULL ); + return( mbedtls_ecp_mul_restartable( grp, R, m, P, f_rng, p_rng, NULL ) ); +} + +#if defined(ECP_SHORTWEIERSTRASS) +/* + * Check that an affine point is valid as a public key, + * short weierstrass curves (SEC1 3.2.3.1) + */ +static int ecp_check_pubkey_sw( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) +{ + int ret; + mbedtls_mpi YY, RHS; + + /* pt coordinates must be normalized for our checks */ + if( mbedtls_mpi_cmp_int( &pt->X, 0 ) < 0 || + mbedtls_mpi_cmp_int( &pt->Y, 0 ) < 0 || + mbedtls_mpi_cmp_mpi( &pt->X, &grp->P ) >= 0 || + mbedtls_mpi_cmp_mpi( &pt->Y, &grp->P ) >= 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + mbedtls_mpi_init( &YY ); mbedtls_mpi_init( &RHS ); + + /* + * YY = Y^2 + * RHS = X (X^2 + A) + B = X^3 + A X + B + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &YY, &pt->Y, &pt->Y ) ); MOD_MUL( YY ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &RHS, &pt->X, &pt->X ) ); MOD_MUL( RHS ); + + /* Special case for A = -3 */ + if( grp->A.p == NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &RHS, &RHS, 3 ) ); MOD_SUB( RHS ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &RHS, &RHS, &grp->A ) ); MOD_ADD( RHS ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &RHS, &RHS, &pt->X ) ); MOD_MUL( RHS ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &RHS, &RHS, &grp->B ) ); MOD_ADD( RHS ); + + if( mbedtls_mpi_cmp_mpi( &YY, &RHS ) != 0 ) + ret = MBEDTLS_ERR_ECP_INVALID_KEY; + +cleanup: + + mbedtls_mpi_free( &YY ); mbedtls_mpi_free( &RHS ); + + return( ret ); +} +#endif /* ECP_SHORTWEIERSTRASS */ + +/* + * R = m * P with shortcuts for m == 1 and m == -1 + * NOT constant-time - ONLY for short Weierstrass! + */ +static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + const mbedtls_mpi *m, + const mbedtls_ecp_point *P, + mbedtls_ecp_restart_ctx *rs_ctx ) +{ + int ret; + + if( mbedtls_mpi_cmp_int( m, 1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) ); + } + else if( mbedtls_mpi_cmp_int( m, -1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) ); + if( mbedtls_mpi_cmp_int( &R->Y, 0 ) != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &R->Y, &grp->P, &R->Y ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_restartable( grp, R, m, P, + NULL, NULL, rs_ctx ) ); + } + +cleanup: + return( ret ); +} + +/* + * Restartable linear combination + * NOT constant-time + */ +int mbedtls_ecp_muladd_restartable( + mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q, + mbedtls_ecp_restart_ctx *rs_ctx ) +{ + int ret; + mbedtls_ecp_point mP; + mbedtls_ecp_point *pmP = &mP; + mbedtls_ecp_point *pR = R; +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + char is_grp_capable = 0; +#endif + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( R != NULL ); + ECP_VALIDATE_RET( m != NULL ); + ECP_VALIDATE_RET( P != NULL ); + ECP_VALIDATE_RET( n != NULL ); + ECP_VALIDATE_RET( Q != NULL ); + + if( mbedtls_ecp_get_type( grp ) != MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + mbedtls_ecp_point_init( &mP ); + + ECP_RS_ENTER( ma ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->ma != NULL ) + { + /* redirect intermediate results to restart context */ + pmP = &rs_ctx->ma->mP; + pR = &rs_ctx->ma->R; + + /* jump to next operation */ + if( rs_ctx->ma->state == ecp_rsma_mul2 ) + goto mul2; + if( rs_ctx->ma->state == ecp_rsma_add ) + goto add; + if( rs_ctx->ma->state == ecp_rsma_norm ) + goto norm; + } +#endif /* MBEDTLS_ECP_RESTARTABLE */ + + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, pmP, m, P, rs_ctx ) ); +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->ma != NULL ) + rs_ctx->ma->state = ecp_rsma_mul2; + +mul2: +#endif + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, pR, n, Q, rs_ctx ) ); + +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + if( ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) ) + MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) ); +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->ma != NULL ) + rs_ctx->ma->state = ecp_rsma_add; + +add: +#endif + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_ADD ); + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, pR, pmP, pR ) ); +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->ma != NULL ) + rs_ctx->ma->state = ecp_rsma_norm; + +norm: +#endif + MBEDTLS_ECP_BUDGET( MBEDTLS_ECP_OPS_INV ); + MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, pR ) ); + +#if defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && rs_ctx->ma != NULL ) + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, pR ) ); +#endif + +cleanup: +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + if( is_grp_capable ) + mbedtls_internal_ecp_free( grp ); +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ + + mbedtls_ecp_point_free( &mP ); + + ECP_RS_LEAVE( ma ); + + return( ret ); +} + +/* + * Linear combination + * NOT constant-time + */ +int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q ) +{ + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( R != NULL ); + ECP_VALIDATE_RET( m != NULL ); + ECP_VALIDATE_RET( P != NULL ); + ECP_VALIDATE_RET( n != NULL ); + ECP_VALIDATE_RET( Q != NULL ); + return( mbedtls_ecp_muladd_restartable( grp, R, m, P, n, Q, NULL ) ); +} + +#if defined(ECP_MONTGOMERY) +/* + * Check validity of a public key for Montgomery curves with x-only schemes + */ +static int ecp_check_pubkey_mx( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) +{ + /* [Curve25519 p. 5] Just check X is the correct number of bytes */ + /* Allow any public value, if it's too big then we'll just reduce it mod p + * (RFC 7748 sec. 5 para. 3). */ + if( mbedtls_mpi_size( &pt->X ) > ( grp->nbits + 7 ) / 8 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + return( 0 ); +} +#endif /* ECP_MONTGOMERY */ + +/* + * Check that a point is valid as a public key + */ +int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, + const mbedtls_ecp_point *pt ) +{ + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( pt != NULL ); + + /* Must use affine coordinates */ + if( mbedtls_mpi_cmp_int( &pt->Z, 1 ) != 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + +#if defined(ECP_MONTGOMERY) + if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY ) + return( ecp_check_pubkey_mx( grp, pt ) ); +#endif +#if defined(ECP_SHORTWEIERSTRASS) + if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ) + return( ecp_check_pubkey_sw( grp, pt ) ); +#endif + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +} + +/* + * Check that an mbedtls_mpi is valid as a private key + */ +int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, + const mbedtls_mpi *d ) +{ + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( d != NULL ); + +#if defined(ECP_MONTGOMERY) + if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY ) + { + /* see RFC 7748 sec. 5 para. 5 */ + if( mbedtls_mpi_get_bit( d, 0 ) != 0 || + mbedtls_mpi_get_bit( d, 1 ) != 0 || + mbedtls_mpi_bitlen( d ) - 1 != grp->nbits ) /* mbedtls_mpi_bitlen is one-based! */ + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + /* see [Curve25519] page 5 */ + if( grp->nbits == 254 && mbedtls_mpi_get_bit( d, 2 ) != 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + return( 0 ); + } +#endif /* ECP_MONTGOMERY */ +#if defined(ECP_SHORTWEIERSTRASS) + if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ) + { + /* see SEC1 3.2 */ + if( mbedtls_mpi_cmp_int( d, 1 ) < 0 || + mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + else + return( 0 ); + } +#endif /* ECP_SHORTWEIERSTRASS */ + + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +} + +/* + * Generate a private key + */ +int mbedtls_ecp_gen_privkey( const mbedtls_ecp_group *grp, + mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + size_t n_size; + + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( d != NULL ); + ECP_VALIDATE_RET( f_rng != NULL ); + + n_size = ( grp->nbits + 7 ) / 8; + +#if defined(ECP_MONTGOMERY) + if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY ) + { + /* [M225] page 5 */ + size_t b; + + do { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( d, n_size, f_rng, p_rng ) ); + } while( mbedtls_mpi_bitlen( d ) == 0); + + /* Make sure the most significant bit is nbits */ + b = mbedtls_mpi_bitlen( d ) - 1; /* mbedtls_mpi_bitlen is one-based */ + if( b > grp->nbits ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( d, b - grp->nbits ) ); + else + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, grp->nbits, 1 ) ); + + /* Make sure the last two bits are unset for Curve448, three bits for + Curve25519 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 0, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 1, 0 ) ); + if( grp->nbits == 254 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 2, 0 ) ); + } + } +#endif /* ECP_MONTGOMERY */ + +#if defined(ECP_SHORTWEIERSTRASS) + if( mbedtls_ecp_get_type( grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ) + { + /* SEC1 3.2.1: Generate d such that 1 <= n < N */ + int count = 0; + + /* + * Match the procedure given in RFC 6979 (deterministic ECDSA): + * - use the same byte ordering; + * - keep the leftmost nbits bits of the generated octet string; + * - try until result is in the desired range. + * This also avoids any biais, which is especially important for ECDSA. + */ + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( d, n_size, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( d, 8 * n_size - grp->nbits ) ); + + /* + * Each try has at worst a probability 1/2 of failing (the msb has + * a probability 1/2 of being 0, and then the result will be < N), + * so after 30 tries failure probability is a most 2**(-30). + * + * For most curves, 1 try is enough with overwhelming probability, + * since N starts with a lot of 1s in binary, but some curves + * such as secp224k1 are actually very close to the worst case. + */ + if( ++count > 30 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( d, 1 ) < 0 || + mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ); + } +#endif /* ECP_SHORTWEIERSTRASS */ + +cleanup: + return( ret ); +} + +/* + * Generate a keypair with configurable base point + */ +int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( d != NULL ); + ECP_VALIDATE_RET( G != NULL ); + ECP_VALIDATE_RET( Q != NULL ); + ECP_VALIDATE_RET( f_rng != NULL ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_privkey( grp, d, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, Q, d, G, f_rng, p_rng ) ); + +cleanup: + return( ret ); +} + +/* + * Generate key pair, wrapper for conventional base point + */ +int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + ECP_VALIDATE_RET( grp != NULL ); + ECP_VALIDATE_RET( d != NULL ); + ECP_VALIDATE_RET( Q != NULL ); + ECP_VALIDATE_RET( f_rng != NULL ); + + return( mbedtls_ecp_gen_keypair_base( grp, &grp->G, d, Q, f_rng, p_rng ) ); +} + +/* + * Generate a keypair, prettier wrapper + */ +int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + ECP_VALIDATE_RET( key != NULL ); + ECP_VALIDATE_RET( f_rng != NULL ); + + if( ( ret = mbedtls_ecp_group_load( &key->grp, grp_id ) ) != 0 ) + return( ret ); + + return( mbedtls_ecp_gen_keypair( &key->grp, &key->d, &key->Q, f_rng, p_rng ) ); +} + +#define ECP_CURVE25519_KEY_SIZE 32 +/* + * Read a private key. + */ +int mbedtls_ecp_read_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + const unsigned char *buf, size_t buflen ) +{ + int ret = 0; + + ECP_VALIDATE_RET( key != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + + if( ( ret = mbedtls_ecp_group_load( &key->grp, grp_id ) ) != 0 ) + return( ret ); + + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + +#if defined(ECP_MONTGOMERY) + if( mbedtls_ecp_get_type( &key->grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY ) + { + /* + * If it is Curve25519 curve then mask the key as mandated by RFC7748 + */ + if( grp_id == MBEDTLS_ECP_DP_CURVE25519 ) + { + if( buflen != ECP_CURVE25519_KEY_SIZE ) + return MBEDTLS_ERR_ECP_INVALID_KEY; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary_le( &key->d, buf, buflen ) ); + + /* Set the three least significant bits to 0 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &key->d, 0, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &key->d, 1, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &key->d, 2, 0 ) ); + + /* Set the most significant bit to 0 */ + MBEDTLS_MPI_CHK( + mbedtls_mpi_set_bit( &key->d, + ECP_CURVE25519_KEY_SIZE * 8 - 1, 0 ) + ); + + /* Set the second most significant bit to 1 */ + MBEDTLS_MPI_CHK( + mbedtls_mpi_set_bit( &key->d, + ECP_CURVE25519_KEY_SIZE * 8 - 2, 1 ) + ); + } + else + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + } + +#endif +#if defined(ECP_SHORTWEIERSTRASS) + if( mbedtls_ecp_get_type( &key->grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &key->d, buf, buflen ) ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_check_privkey( &key->grp, &key->d ) ); + } + +#endif +cleanup: + + if( ret != 0 ) + mbedtls_mpi_free( &key->d ); + + return( ret ); +} + +/* + * Check a public-private key pair + */ +int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv ) +{ + int ret; + mbedtls_ecp_point Q; + mbedtls_ecp_group grp; + ECP_VALIDATE_RET( pub != NULL ); + ECP_VALIDATE_RET( prv != NULL ); + + if( pub->grp.id == MBEDTLS_ECP_DP_NONE || + pub->grp.id != prv->grp.id || + mbedtls_mpi_cmp_mpi( &pub->Q.X, &prv->Q.X ) || + mbedtls_mpi_cmp_mpi( &pub->Q.Y, &prv->Q.Y ) || + mbedtls_mpi_cmp_mpi( &pub->Q.Z, &prv->Q.Z ) ) + { + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + mbedtls_ecp_point_init( &Q ); + mbedtls_ecp_group_init( &grp ); + + /* mbedtls_ecp_mul() needs a non-const group... */ + mbedtls_ecp_group_copy( &grp, &prv->grp ); + + /* Also checks d is valid */ + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &Q, &prv->d, &prv->grp.G, NULL, NULL ) ); + + if( mbedtls_mpi_cmp_mpi( &Q.X, &prv->Q.X ) || + mbedtls_mpi_cmp_mpi( &Q.Y, &prv->Q.Y ) || + mbedtls_mpi_cmp_mpi( &Q.Z, &prv->Q.Z ) ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free( &Q ); + mbedtls_ecp_group_free( &grp ); + + return( ret ); +} + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Checkup routine + */ +int mbedtls_ecp_self_test( int verbose ) +{ + int ret; + size_t i; + mbedtls_ecp_group grp; + mbedtls_ecp_point R, P; + mbedtls_mpi m; + unsigned long add_c_prev, dbl_c_prev, mul_c_prev; + /* exponents especially adapted for secp192r1 */ + const char *exponents[] = + { + "000000000000000000000000000000000000000000000001", /* one */ + "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22830", /* N - 1 */ + "5EA6F389A38B8BC81E767753B15AA5569E1782E30ABE7D25", /* random */ + "400000000000000000000000000000000000000000000000", /* one and zeros */ + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", /* all ones */ + "555555555555555555555555555555555555555555555555", /* 101010... */ + }; + + mbedtls_ecp_group_init( &grp ); + mbedtls_ecp_point_init( &R ); + mbedtls_ecp_point_init( &P ); + mbedtls_mpi_init( &m ); + + /* Use secp192r1 if available, or any available curve */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &grp, MBEDTLS_ECP_DP_SECP192R1 ) ); +#else + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &grp, mbedtls_ecp_curve_list()->grp_id ) ); +#endif + + if( verbose != 0 ) + mbedtls_printf( " ECP test #1 (constant op_count, base point G): " ); + + /* Do a dummy multiplication first to trigger precomputation */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &m, 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &P, &m, &grp.G, NULL, NULL ) ); + + add_count = 0; + dbl_count = 0; + mul_count = 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[0] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) ); + + for( i = 1; i < sizeof( exponents ) / sizeof( exponents[0] ); i++ ) + { + add_c_prev = add_count; + dbl_c_prev = dbl_count; + mul_c_prev = mul_count; + add_count = 0; + dbl_count = 0; + mul_count = 0; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) ); + + if( add_count != add_c_prev || + dbl_count != dbl_c_prev || + mul_count != mul_c_prev ) + { + if( verbose != 0 ) + mbedtls_printf( "failed (%u)\n", (unsigned int) i ); + + ret = 1; + goto cleanup; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " ECP test #2 (constant op_count, other point): " ); + /* We computed P = 2G last time, use it */ + + add_count = 0; + dbl_count = 0; + mul_count = 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[0] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &P, NULL, NULL ) ); + + for( i = 1; i < sizeof( exponents ) / sizeof( exponents[0] ); i++ ) + { + add_c_prev = add_count; + dbl_c_prev = dbl_count; + mul_c_prev = mul_count; + add_count = 0; + dbl_count = 0; + mul_count = 0; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &P, NULL, NULL ) ); + + if( add_count != add_c_prev || + dbl_count != dbl_c_prev || + mul_count != mul_c_prev ) + { + if( verbose != 0 ) + mbedtls_printf( "failed (%u)\n", (unsigned int) i ); + + ret = 1; + goto cleanup; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +cleanup: + + if( ret < 0 && verbose != 0 ) + mbedtls_printf( "Unexpected error, return code = %08X\n", ret ); + + mbedtls_ecp_group_free( &grp ); + mbedtls_ecp_point_free( &R ); + mbedtls_ecp_point_free( &P ); + mbedtls_mpi_free( &m ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* !MBEDTLS_ECP_ALT */ + +#endif /* MBEDTLS_ECP_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ecp_curves.c b/FreeRTOS-Labs/Source/mbedtls/library/ecp_curves.c new file mode 100644 index 000000000..c9a51c028 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ecp_curves.c @@ -0,0 +1,1470 @@ +/* + * Elliptic curves over GF(p): curve-specific data and functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECP_C) + +#include "mbedtls/ecp.h" +#include "mbedtls/platform_util.h" + +#include + +#if !defined(MBEDTLS_ECP_ALT) + +/* Parameter validation macros based on platform_util.h */ +#define ECP_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA ) +#define ECP_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* + * Conversion macros for embedded constants: + * build lists of mbedtls_mpi_uint's from lists of unsigned char's grouped by 8, 4 or 2 + */ +#if defined(MBEDTLS_HAVE_INT32) + +#define BYTES_TO_T_UINT_4( a, b, c, d ) \ + ( (mbedtls_mpi_uint) (a) << 0 ) | \ + ( (mbedtls_mpi_uint) (b) << 8 ) | \ + ( (mbedtls_mpi_uint) (c) << 16 ) | \ + ( (mbedtls_mpi_uint) (d) << 24 ) + +#define BYTES_TO_T_UINT_2( a, b ) \ + BYTES_TO_T_UINT_4( a, b, 0, 0 ) + +#define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \ + BYTES_TO_T_UINT_4( a, b, c, d ), \ + BYTES_TO_T_UINT_4( e, f, g, h ) + +#else /* 64-bits */ + +#define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \ + ( (mbedtls_mpi_uint) (a) << 0 ) | \ + ( (mbedtls_mpi_uint) (b) << 8 ) | \ + ( (mbedtls_mpi_uint) (c) << 16 ) | \ + ( (mbedtls_mpi_uint) (d) << 24 ) | \ + ( (mbedtls_mpi_uint) (e) << 32 ) | \ + ( (mbedtls_mpi_uint) (f) << 40 ) | \ + ( (mbedtls_mpi_uint) (g) << 48 ) | \ + ( (mbedtls_mpi_uint) (h) << 56 ) + +#define BYTES_TO_T_UINT_4( a, b, c, d ) \ + BYTES_TO_T_UINT_8( a, b, c, d, 0, 0, 0, 0 ) + +#define BYTES_TO_T_UINT_2( a, b ) \ + BYTES_TO_T_UINT_8( a, b, 0, 0, 0, 0, 0, 0 ) + +#endif /* bits in mbedtls_mpi_uint */ + +/* + * Note: the constants are in little-endian order + * to be directly usable in MPIs + */ + +/* + * Domain parameters for secp192r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) +static const mbedtls_mpi_uint secp192r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp192r1_b[] = { + BYTES_TO_T_UINT_8( 0xB1, 0xB9, 0x46, 0xC1, 0xEC, 0xDE, 0xB8, 0xFE ), + BYTES_TO_T_UINT_8( 0x49, 0x30, 0x24, 0x72, 0xAB, 0xE9, 0xA7, 0x0F ), + BYTES_TO_T_UINT_8( 0xE7, 0x80, 0x9C, 0xE5, 0x19, 0x05, 0x21, 0x64 ), +}; +static const mbedtls_mpi_uint secp192r1_gx[] = { + BYTES_TO_T_UINT_8( 0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4 ), + BYTES_TO_T_UINT_8( 0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C ), + BYTES_TO_T_UINT_8( 0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18 ), +}; +static const mbedtls_mpi_uint secp192r1_gy[] = { + BYTES_TO_T_UINT_8( 0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73 ), + BYTES_TO_T_UINT_8( 0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63 ), + BYTES_TO_T_UINT_8( 0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07 ), +}; +static const mbedtls_mpi_uint secp192r1_n[] = { + BYTES_TO_T_UINT_8( 0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14 ), + BYTES_TO_T_UINT_8( 0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +/* + * Domain parameters for secp224r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) +static const mbedtls_mpi_uint secp224r1_p[] = { + BYTES_TO_T_UINT_8( 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp224r1_b[] = { + BYTES_TO_T_UINT_8( 0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27 ), + BYTES_TO_T_UINT_8( 0xBA, 0xD8, 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50 ), + BYTES_TO_T_UINT_8( 0x56, 0x32, 0x41, 0xF5, 0xAB, 0xB3, 0x04, 0x0C ), + BYTES_TO_T_UINT_4( 0x85, 0x0A, 0x05, 0xB4 ), +}; +static const mbedtls_mpi_uint secp224r1_gx[] = { + BYTES_TO_T_UINT_8( 0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34 ), + BYTES_TO_T_UINT_8( 0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A ), + BYTES_TO_T_UINT_8( 0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B ), + BYTES_TO_T_UINT_4( 0xBD, 0x0C, 0x0E, 0xB7 ), +}; +static const mbedtls_mpi_uint secp224r1_gy[] = { + BYTES_TO_T_UINT_8( 0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44 ), + BYTES_TO_T_UINT_8( 0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD ), + BYTES_TO_T_UINT_8( 0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5 ), + BYTES_TO_T_UINT_4( 0x88, 0x63, 0x37, 0xBD ), +}; +static const mbedtls_mpi_uint secp224r1_n[] = { + BYTES_TO_T_UINT_8( 0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13 ), + BYTES_TO_T_UINT_8( 0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_4( 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +/* + * Domain parameters for secp256r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +static const mbedtls_mpi_uint secp256r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp256r1_b[] = { + BYTES_TO_T_UINT_8( 0x4B, 0x60, 0xD2, 0x27, 0x3E, 0x3C, 0xCE, 0x3B ), + BYTES_TO_T_UINT_8( 0xF6, 0xB0, 0x53, 0xCC, 0xB0, 0x06, 0x1D, 0x65 ), + BYTES_TO_T_UINT_8( 0xBC, 0x86, 0x98, 0x76, 0x55, 0xBD, 0xEB, 0xB3 ), + BYTES_TO_T_UINT_8( 0xE7, 0x93, 0x3A, 0xAA, 0xD8, 0x35, 0xC6, 0x5A ), +}; +static const mbedtls_mpi_uint secp256r1_gx[] = { + BYTES_TO_T_UINT_8( 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4 ), + BYTES_TO_T_UINT_8( 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77 ), + BYTES_TO_T_UINT_8( 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8 ), + BYTES_TO_T_UINT_8( 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B ), +}; +static const mbedtls_mpi_uint secp256r1_gy[] = { + BYTES_TO_T_UINT_8( 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB ), + BYTES_TO_T_UINT_8( 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B ), + BYTES_TO_T_UINT_8( 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E ), + BYTES_TO_T_UINT_8( 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F ), +}; +static const mbedtls_mpi_uint secp256r1_n[] = { + BYTES_TO_T_UINT_8( 0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3 ), + BYTES_TO_T_UINT_8( 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +/* + * Domain parameters for secp384r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +static const mbedtls_mpi_uint secp384r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp384r1_b[] = { + BYTES_TO_T_UINT_8( 0xEF, 0x2A, 0xEC, 0xD3, 0xED, 0xC8, 0x85, 0x2A ), + BYTES_TO_T_UINT_8( 0x9D, 0xD1, 0x2E, 0x8A, 0x8D, 0x39, 0x56, 0xC6 ), + BYTES_TO_T_UINT_8( 0x5A, 0x87, 0x13, 0x50, 0x8F, 0x08, 0x14, 0x03 ), + BYTES_TO_T_UINT_8( 0x12, 0x41, 0x81, 0xFE, 0x6E, 0x9C, 0x1D, 0x18 ), + BYTES_TO_T_UINT_8( 0x19, 0x2D, 0xF8, 0xE3, 0x6B, 0x05, 0x8E, 0x98 ), + BYTES_TO_T_UINT_8( 0xE4, 0xE7, 0x3E, 0xE2, 0xA7, 0x2F, 0x31, 0xB3 ), +}; +static const mbedtls_mpi_uint secp384r1_gx[] = { + BYTES_TO_T_UINT_8( 0xB7, 0x0A, 0x76, 0x72, 0x38, 0x5E, 0x54, 0x3A ), + BYTES_TO_T_UINT_8( 0x6C, 0x29, 0x55, 0xBF, 0x5D, 0xF2, 0x02, 0x55 ), + BYTES_TO_T_UINT_8( 0x38, 0x2A, 0x54, 0x82, 0xE0, 0x41, 0xF7, 0x59 ), + BYTES_TO_T_UINT_8( 0x98, 0x9B, 0xA7, 0x8B, 0x62, 0x3B, 0x1D, 0x6E ), + BYTES_TO_T_UINT_8( 0x74, 0xAD, 0x20, 0xF3, 0x1E, 0xC7, 0xB1, 0x8E ), + BYTES_TO_T_UINT_8( 0x37, 0x05, 0x8B, 0xBE, 0x22, 0xCA, 0x87, 0xAA ), +}; +static const mbedtls_mpi_uint secp384r1_gy[] = { + BYTES_TO_T_UINT_8( 0x5F, 0x0E, 0xEA, 0x90, 0x7C, 0x1D, 0x43, 0x7A ), + BYTES_TO_T_UINT_8( 0x9D, 0x81, 0x7E, 0x1D, 0xCE, 0xB1, 0x60, 0x0A ), + BYTES_TO_T_UINT_8( 0xC0, 0xB8, 0xF0, 0xB5, 0x13, 0x31, 0xDA, 0xE9 ), + BYTES_TO_T_UINT_8( 0x7C, 0x14, 0x9A, 0x28, 0xBD, 0x1D, 0xF4, 0xF8 ), + BYTES_TO_T_UINT_8( 0x29, 0xDC, 0x92, 0x92, 0xBF, 0x98, 0x9E, 0x5D ), + BYTES_TO_T_UINT_8( 0x6F, 0x2C, 0x26, 0x96, 0x4A, 0xDE, 0x17, 0x36 ), +}; +static const mbedtls_mpi_uint secp384r1_n[] = { + BYTES_TO_T_UINT_8( 0x73, 0x29, 0xC5, 0xCC, 0x6A, 0x19, 0xEC, 0xEC ), + BYTES_TO_T_UINT_8( 0x7A, 0xA7, 0xB0, 0x48, 0xB2, 0x0D, 0x1A, 0x58 ), + BYTES_TO_T_UINT_8( 0xDF, 0x2D, 0x37, 0xF4, 0x81, 0x4D, 0x63, 0xC7 ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +/* + * Domain parameters for secp521r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +static const mbedtls_mpi_uint secp521r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_2( 0xFF, 0x01 ), +}; +static const mbedtls_mpi_uint secp521r1_b[] = { + BYTES_TO_T_UINT_8( 0x00, 0x3F, 0x50, 0x6B, 0xD4, 0x1F, 0x45, 0xEF ), + BYTES_TO_T_UINT_8( 0xF1, 0x34, 0x2C, 0x3D, 0x88, 0xDF, 0x73, 0x35 ), + BYTES_TO_T_UINT_8( 0x07, 0xBF, 0xB1, 0x3B, 0xBD, 0xC0, 0x52, 0x16 ), + BYTES_TO_T_UINT_8( 0x7B, 0x93, 0x7E, 0xEC, 0x51, 0x39, 0x19, 0x56 ), + BYTES_TO_T_UINT_8( 0xE1, 0x09, 0xF1, 0x8E, 0x91, 0x89, 0xB4, 0xB8 ), + BYTES_TO_T_UINT_8( 0xF3, 0x15, 0xB3, 0x99, 0x5B, 0x72, 0xDA, 0xA2 ), + BYTES_TO_T_UINT_8( 0xEE, 0x40, 0x85, 0xB6, 0xA0, 0x21, 0x9A, 0x92 ), + BYTES_TO_T_UINT_8( 0x1F, 0x9A, 0x1C, 0x8E, 0x61, 0xB9, 0x3E, 0x95 ), + BYTES_TO_T_UINT_2( 0x51, 0x00 ), +}; +static const mbedtls_mpi_uint secp521r1_gx[] = { + BYTES_TO_T_UINT_8( 0x66, 0xBD, 0xE5, 0xC2, 0x31, 0x7E, 0x7E, 0xF9 ), + BYTES_TO_T_UINT_8( 0x9B, 0x42, 0x6A, 0x85, 0xC1, 0xB3, 0x48, 0x33 ), + BYTES_TO_T_UINT_8( 0xDE, 0xA8, 0xFF, 0xA2, 0x27, 0xC1, 0x1D, 0xFE ), + BYTES_TO_T_UINT_8( 0x28, 0x59, 0xE7, 0xEF, 0x77, 0x5E, 0x4B, 0xA1 ), + BYTES_TO_T_UINT_8( 0xBA, 0x3D, 0x4D, 0x6B, 0x60, 0xAF, 0x28, 0xF8 ), + BYTES_TO_T_UINT_8( 0x21, 0xB5, 0x3F, 0x05, 0x39, 0x81, 0x64, 0x9C ), + BYTES_TO_T_UINT_8( 0x42, 0xB4, 0x95, 0x23, 0x66, 0xCB, 0x3E, 0x9E ), + BYTES_TO_T_UINT_8( 0xCD, 0xE9, 0x04, 0x04, 0xB7, 0x06, 0x8E, 0x85 ), + BYTES_TO_T_UINT_2( 0xC6, 0x00 ), +}; +static const mbedtls_mpi_uint secp521r1_gy[] = { + BYTES_TO_T_UINT_8( 0x50, 0x66, 0xD1, 0x9F, 0x76, 0x94, 0xBE, 0x88 ), + BYTES_TO_T_UINT_8( 0x40, 0xC2, 0x72, 0xA2, 0x86, 0x70, 0x3C, 0x35 ), + BYTES_TO_T_UINT_8( 0x61, 0x07, 0xAD, 0x3F, 0x01, 0xB9, 0x50, 0xC5 ), + BYTES_TO_T_UINT_8( 0x40, 0x26, 0xF4, 0x5E, 0x99, 0x72, 0xEE, 0x97 ), + BYTES_TO_T_UINT_8( 0x2C, 0x66, 0x3E, 0x27, 0x17, 0xBD, 0xAF, 0x17 ), + BYTES_TO_T_UINT_8( 0x68, 0x44, 0x9B, 0x57, 0x49, 0x44, 0xF5, 0x98 ), + BYTES_TO_T_UINT_8( 0xD9, 0x1B, 0x7D, 0x2C, 0xB4, 0x5F, 0x8A, 0x5C ), + BYTES_TO_T_UINT_8( 0x04, 0xC0, 0x3B, 0x9A, 0x78, 0x6A, 0x29, 0x39 ), + BYTES_TO_T_UINT_2( 0x18, 0x01 ), +}; +static const mbedtls_mpi_uint secp521r1_n[] = { + BYTES_TO_T_UINT_8( 0x09, 0x64, 0x38, 0x91, 0x1E, 0xB7, 0x6F, 0xBB ), + BYTES_TO_T_UINT_8( 0xAE, 0x47, 0x9C, 0x89, 0xB8, 0xC9, 0xB5, 0x3B ), + BYTES_TO_T_UINT_8( 0xD0, 0xA5, 0x09, 0xF7, 0x48, 0x01, 0xCC, 0x7F ), + BYTES_TO_T_UINT_8( 0x6B, 0x96, 0x2F, 0xBF, 0x83, 0x87, 0x86, 0x51 ), + BYTES_TO_T_UINT_8( 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_2( 0xFF, 0x01 ), +}; +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) +static const mbedtls_mpi_uint secp192k1_p[] = { + BYTES_TO_T_UINT_8( 0x37, 0xEE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp192k1_a[] = { + BYTES_TO_T_UINT_2( 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp192k1_b[] = { + BYTES_TO_T_UINT_2( 0x03, 0x00 ), +}; +static const mbedtls_mpi_uint secp192k1_gx[] = { + BYTES_TO_T_UINT_8( 0x7D, 0x6C, 0xE0, 0xEA, 0xB1, 0xD1, 0xA5, 0x1D ), + BYTES_TO_T_UINT_8( 0x34, 0xF4, 0xB7, 0x80, 0x02, 0x7D, 0xB0, 0x26 ), + BYTES_TO_T_UINT_8( 0xAE, 0xE9, 0x57, 0xC0, 0x0E, 0xF1, 0x4F, 0xDB ), +}; +static const mbedtls_mpi_uint secp192k1_gy[] = { + BYTES_TO_T_UINT_8( 0x9D, 0x2F, 0x5E, 0xD9, 0x88, 0xAA, 0x82, 0x40 ), + BYTES_TO_T_UINT_8( 0x34, 0x86, 0xBE, 0x15, 0xD0, 0x63, 0x41, 0x84 ), + BYTES_TO_T_UINT_8( 0xA7, 0x28, 0x56, 0x9C, 0x6D, 0x2F, 0x2F, 0x9B ), +}; +static const mbedtls_mpi_uint secp192k1_n[] = { + BYTES_TO_T_UINT_8( 0x8D, 0xFD, 0xDE, 0x74, 0x6A, 0x46, 0x69, 0x0F ), + BYTES_TO_T_UINT_8( 0x17, 0xFC, 0xF2, 0x26, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +static const mbedtls_mpi_uint secp224k1_p[] = { + BYTES_TO_T_UINT_8( 0x6D, 0xE5, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_4( 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp224k1_a[] = { + BYTES_TO_T_UINT_2( 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp224k1_b[] = { + BYTES_TO_T_UINT_2( 0x05, 0x00 ), +}; +static const mbedtls_mpi_uint secp224k1_gx[] = { + BYTES_TO_T_UINT_8( 0x5C, 0xA4, 0xB7, 0xB6, 0x0E, 0x65, 0x7E, 0x0F ), + BYTES_TO_T_UINT_8( 0xA9, 0x75, 0x70, 0xE4, 0xE9, 0x67, 0xA4, 0x69 ), + BYTES_TO_T_UINT_8( 0xA1, 0x28, 0xFC, 0x30, 0xDF, 0x99, 0xF0, 0x4D ), + BYTES_TO_T_UINT_4( 0x33, 0x5B, 0x45, 0xA1 ), +}; +static const mbedtls_mpi_uint secp224k1_gy[] = { + BYTES_TO_T_UINT_8( 0xA5, 0x61, 0x6D, 0x55, 0xDB, 0x4B, 0xCA, 0xE2 ), + BYTES_TO_T_UINT_8( 0x59, 0xBD, 0xB0, 0xC0, 0xF7, 0x19, 0xE3, 0xF7 ), + BYTES_TO_T_UINT_8( 0xD6, 0xFB, 0xCA, 0x82, 0x42, 0x34, 0xBA, 0x7F ), + BYTES_TO_T_UINT_4( 0xED, 0x9F, 0x08, 0x7E ), +}; +static const mbedtls_mpi_uint secp224k1_n[] = { + BYTES_TO_T_UINT_8( 0xF7, 0xB1, 0x9F, 0x76, 0x71, 0xA9, 0xF0, 0xCA ), + BYTES_TO_T_UINT_8( 0x84, 0x61, 0xEC, 0xD2, 0xE8, 0xDC, 0x01, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ), +}; +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +static const mbedtls_mpi_uint secp256k1_p[] = { + BYTES_TO_T_UINT_8( 0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp256k1_a[] = { + BYTES_TO_T_UINT_2( 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp256k1_b[] = { + BYTES_TO_T_UINT_2( 0x07, 0x00 ), +}; +static const mbedtls_mpi_uint secp256k1_gx[] = { + BYTES_TO_T_UINT_8( 0x98, 0x17, 0xF8, 0x16, 0x5B, 0x81, 0xF2, 0x59 ), + BYTES_TO_T_UINT_8( 0xD9, 0x28, 0xCE, 0x2D, 0xDB, 0xFC, 0x9B, 0x02 ), + BYTES_TO_T_UINT_8( 0x07, 0x0B, 0x87, 0xCE, 0x95, 0x62, 0xA0, 0x55 ), + BYTES_TO_T_UINT_8( 0xAC, 0xBB, 0xDC, 0xF9, 0x7E, 0x66, 0xBE, 0x79 ), +}; +static const mbedtls_mpi_uint secp256k1_gy[] = { + BYTES_TO_T_UINT_8( 0xB8, 0xD4, 0x10, 0xFB, 0x8F, 0xD0, 0x47, 0x9C ), + BYTES_TO_T_UINT_8( 0x19, 0x54, 0x85, 0xA6, 0x48, 0xB4, 0x17, 0xFD ), + BYTES_TO_T_UINT_8( 0xA8, 0x08, 0x11, 0x0E, 0xFC, 0xFB, 0xA4, 0x5D ), + BYTES_TO_T_UINT_8( 0x65, 0xC4, 0xA3, 0x26, 0x77, 0xDA, 0x3A, 0x48 ), +}; +static const mbedtls_mpi_uint secp256k1_n[] = { + BYTES_TO_T_UINT_8( 0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF ), + BYTES_TO_T_UINT_8( 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA ), + BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +/* + * Domain parameters for brainpoolP256r1 (RFC 5639 3.4) + */ +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP256r1_p[] = { + BYTES_TO_T_UINT_8( 0x77, 0x53, 0x6E, 0x1F, 0x1D, 0x48, 0x13, 0x20 ), + BYTES_TO_T_UINT_8( 0x28, 0x20, 0x26, 0xD5, 0x23, 0xF6, 0x3B, 0x6E ), + BYTES_TO_T_UINT_8( 0x72, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E ), + BYTES_TO_T_UINT_8( 0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9 ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_a[] = { + BYTES_TO_T_UINT_8( 0xD9, 0xB5, 0x30, 0xF3, 0x44, 0x4B, 0x4A, 0xE9 ), + BYTES_TO_T_UINT_8( 0x6C, 0x5C, 0xDC, 0x26, 0xC1, 0x55, 0x80, 0xFB ), + BYTES_TO_T_UINT_8( 0xE7, 0xFF, 0x7A, 0x41, 0x30, 0x75, 0xF6, 0xEE ), + BYTES_TO_T_UINT_8( 0x57, 0x30, 0x2C, 0xFC, 0x75, 0x09, 0x5A, 0x7D ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_b[] = { + BYTES_TO_T_UINT_8( 0xB6, 0x07, 0x8C, 0xFF, 0x18, 0xDC, 0xCC, 0x6B ), + BYTES_TO_T_UINT_8( 0xCE, 0xE1, 0xF7, 0x5C, 0x29, 0x16, 0x84, 0x95 ), + BYTES_TO_T_UINT_8( 0xBF, 0x7C, 0xD7, 0xBB, 0xD9, 0xB5, 0x30, 0xF3 ), + BYTES_TO_T_UINT_8( 0x44, 0x4B, 0x4A, 0xE9, 0x6C, 0x5C, 0xDC, 0x26 ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_gx[] = { + BYTES_TO_T_UINT_8( 0x62, 0x32, 0xCE, 0x9A, 0xBD, 0x53, 0x44, 0x3A ), + BYTES_TO_T_UINT_8( 0xC2, 0x23, 0xBD, 0xE3, 0xE1, 0x27, 0xDE, 0xB9 ), + BYTES_TO_T_UINT_8( 0xAF, 0xB7, 0x81, 0xFC, 0x2F, 0x48, 0x4B, 0x2C ), + BYTES_TO_T_UINT_8( 0xCB, 0x57, 0x7E, 0xCB, 0xB9, 0xAE, 0xD2, 0x8B ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_gy[] = { + BYTES_TO_T_UINT_8( 0x97, 0x69, 0x04, 0x2F, 0xC7, 0x54, 0x1D, 0x5C ), + BYTES_TO_T_UINT_8( 0x54, 0x8E, 0xED, 0x2D, 0x13, 0x45, 0x77, 0xC2 ), + BYTES_TO_T_UINT_8( 0xC9, 0x1D, 0x61, 0x14, 0x1A, 0x46, 0xF8, 0x97 ), + BYTES_TO_T_UINT_8( 0xFD, 0xC4, 0xDA, 0xC3, 0x35, 0xF8, 0x7E, 0x54 ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_n[] = { + BYTES_TO_T_UINT_8( 0xA7, 0x56, 0x48, 0x97, 0x82, 0x0E, 0x1E, 0x90 ), + BYTES_TO_T_UINT_8( 0xF7, 0xA6, 0x61, 0xB5, 0xA3, 0x7A, 0x39, 0x8C ), + BYTES_TO_T_UINT_8( 0x71, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E ), + BYTES_TO_T_UINT_8( 0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9 ), +}; +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ + +/* + * Domain parameters for brainpoolP384r1 (RFC 5639 3.6) + */ +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP384r1_p[] = { + BYTES_TO_T_UINT_8( 0x53, 0xEC, 0x07, 0x31, 0x13, 0x00, 0x47, 0x87 ), + BYTES_TO_T_UINT_8( 0x71, 0x1A, 0x1D, 0x90, 0x29, 0xA7, 0xD3, 0xAC ), + BYTES_TO_T_UINT_8( 0x23, 0x11, 0xB7, 0x7F, 0x19, 0xDA, 0xB1, 0x12 ), + BYTES_TO_T_UINT_8( 0xB4, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15 ), + BYTES_TO_T_UINT_8( 0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F ), + BYTES_TO_T_UINT_8( 0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_a[] = { + BYTES_TO_T_UINT_8( 0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04 ), + BYTES_TO_T_UINT_8( 0xEB, 0xD4, 0x3A, 0x50, 0x4A, 0x81, 0xA5, 0x8A ), + BYTES_TO_T_UINT_8( 0x0F, 0xF9, 0x91, 0xBA, 0xEF, 0x65, 0x91, 0x13 ), + BYTES_TO_T_UINT_8( 0x87, 0x27, 0xB2, 0x4F, 0x8E, 0xA2, 0xBE, 0xC2 ), + BYTES_TO_T_UINT_8( 0xA0, 0xAF, 0x05, 0xCE, 0x0A, 0x08, 0x72, 0x3C ), + BYTES_TO_T_UINT_8( 0x0C, 0x15, 0x8C, 0x3D, 0xC6, 0x82, 0xC3, 0x7B ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_b[] = { + BYTES_TO_T_UINT_8( 0x11, 0x4C, 0x50, 0xFA, 0x96, 0x86, 0xB7, 0x3A ), + BYTES_TO_T_UINT_8( 0x94, 0xC9, 0xDB, 0x95, 0x02, 0x39, 0xB4, 0x7C ), + BYTES_TO_T_UINT_8( 0xD5, 0x62, 0xEB, 0x3E, 0xA5, 0x0E, 0x88, 0x2E ), + BYTES_TO_T_UINT_8( 0xA6, 0xD2, 0xDC, 0x07, 0xE1, 0x7D, 0xB7, 0x2F ), + BYTES_TO_T_UINT_8( 0x7C, 0x44, 0xF0, 0x16, 0x54, 0xB5, 0x39, 0x8B ), + BYTES_TO_T_UINT_8( 0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04 ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_gx[] = { + BYTES_TO_T_UINT_8( 0x1E, 0xAF, 0xD4, 0x47, 0xE2, 0xB2, 0x87, 0xEF ), + BYTES_TO_T_UINT_8( 0xAA, 0x46, 0xD6, 0x36, 0x34, 0xE0, 0x26, 0xE8 ), + BYTES_TO_T_UINT_8( 0xE8, 0x10, 0xBD, 0x0C, 0xFE, 0xCA, 0x7F, 0xDB ), + BYTES_TO_T_UINT_8( 0xE3, 0x4F, 0xF1, 0x7E, 0xE7, 0xA3, 0x47, 0x88 ), + BYTES_TO_T_UINT_8( 0x6B, 0x3F, 0xC1, 0xB7, 0x81, 0x3A, 0xA6, 0xA2 ), + BYTES_TO_T_UINT_8( 0xFF, 0x45, 0xCF, 0x68, 0xF0, 0x64, 0x1C, 0x1D ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_gy[] = { + BYTES_TO_T_UINT_8( 0x15, 0x53, 0x3C, 0x26, 0x41, 0x03, 0x82, 0x42 ), + BYTES_TO_T_UINT_8( 0x11, 0x81, 0x91, 0x77, 0x21, 0x46, 0x46, 0x0E ), + BYTES_TO_T_UINT_8( 0x28, 0x29, 0x91, 0xF9, 0x4F, 0x05, 0x9C, 0xE1 ), + BYTES_TO_T_UINT_8( 0x64, 0x58, 0xEC, 0xFE, 0x29, 0x0B, 0xB7, 0x62 ), + BYTES_TO_T_UINT_8( 0x52, 0xD5, 0xCF, 0x95, 0x8E, 0xEB, 0xB1, 0x5C ), + BYTES_TO_T_UINT_8( 0xA4, 0xC2, 0xF9, 0x20, 0x75, 0x1D, 0xBE, 0x8A ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_n[] = { + BYTES_TO_T_UINT_8( 0x65, 0x65, 0x04, 0xE9, 0x02, 0x32, 0x88, 0x3B ), + BYTES_TO_T_UINT_8( 0x10, 0xC3, 0x7F, 0x6B, 0xAF, 0xB6, 0x3A, 0xCF ), + BYTES_TO_T_UINT_8( 0xA7, 0x25, 0x04, 0xAC, 0x6C, 0x6E, 0x16, 0x1F ), + BYTES_TO_T_UINT_8( 0xB3, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15 ), + BYTES_TO_T_UINT_8( 0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F ), + BYTES_TO_T_UINT_8( 0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C ), +}; +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ + +/* + * Domain parameters for brainpoolP512r1 (RFC 5639 3.7) + */ +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP512r1_p[] = { + BYTES_TO_T_UINT_8( 0xF3, 0x48, 0x3A, 0x58, 0x56, 0x60, 0xAA, 0x28 ), + BYTES_TO_T_UINT_8( 0x85, 0xC6, 0x82, 0x2D, 0x2F, 0xFF, 0x81, 0x28 ), + BYTES_TO_T_UINT_8( 0xE6, 0x80, 0xA3, 0xE6, 0x2A, 0xA1, 0xCD, 0xAE ), + BYTES_TO_T_UINT_8( 0x42, 0x68, 0xC6, 0x9B, 0x00, 0x9B, 0x4D, 0x7D ), + BYTES_TO_T_UINT_8( 0x71, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6 ), + BYTES_TO_T_UINT_8( 0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB ), + BYTES_TO_T_UINT_8( 0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F ), + BYTES_TO_T_UINT_8( 0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_a[] = { + BYTES_TO_T_UINT_8( 0xCA, 0x94, 0xFC, 0x77, 0x4D, 0xAC, 0xC1, 0xE7 ), + BYTES_TO_T_UINT_8( 0xB9, 0xC7, 0xF2, 0x2B, 0xA7, 0x17, 0x11, 0x7F ), + BYTES_TO_T_UINT_8( 0xB5, 0xC8, 0x9A, 0x8B, 0xC9, 0xF1, 0x2E, 0x0A ), + BYTES_TO_T_UINT_8( 0xA1, 0x3A, 0x25, 0xA8, 0x5A, 0x5D, 0xED, 0x2D ), + BYTES_TO_T_UINT_8( 0xBC, 0x63, 0x98, 0xEA, 0xCA, 0x41, 0x34, 0xA8 ), + BYTES_TO_T_UINT_8( 0x10, 0x16, 0xF9, 0x3D, 0x8D, 0xDD, 0xCB, 0x94 ), + BYTES_TO_T_UINT_8( 0xC5, 0x4C, 0x23, 0xAC, 0x45, 0x71, 0x32, 0xE2 ), + BYTES_TO_T_UINT_8( 0x89, 0x3B, 0x60, 0x8B, 0x31, 0xA3, 0x30, 0x78 ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_b[] = { + BYTES_TO_T_UINT_8( 0x23, 0xF7, 0x16, 0x80, 0x63, 0xBD, 0x09, 0x28 ), + BYTES_TO_T_UINT_8( 0xDD, 0xE5, 0xBA, 0x5E, 0xB7, 0x50, 0x40, 0x98 ), + BYTES_TO_T_UINT_8( 0x67, 0x3E, 0x08, 0xDC, 0xCA, 0x94, 0xFC, 0x77 ), + BYTES_TO_T_UINT_8( 0x4D, 0xAC, 0xC1, 0xE7, 0xB9, 0xC7, 0xF2, 0x2B ), + BYTES_TO_T_UINT_8( 0xA7, 0x17, 0x11, 0x7F, 0xB5, 0xC8, 0x9A, 0x8B ), + BYTES_TO_T_UINT_8( 0xC9, 0xF1, 0x2E, 0x0A, 0xA1, 0x3A, 0x25, 0xA8 ), + BYTES_TO_T_UINT_8( 0x5A, 0x5D, 0xED, 0x2D, 0xBC, 0x63, 0x98, 0xEA ), + BYTES_TO_T_UINT_8( 0xCA, 0x41, 0x34, 0xA8, 0x10, 0x16, 0xF9, 0x3D ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_gx[] = { + BYTES_TO_T_UINT_8( 0x22, 0xF8, 0xB9, 0xBC, 0x09, 0x22, 0x35, 0x8B ), + BYTES_TO_T_UINT_8( 0x68, 0x5E, 0x6A, 0x40, 0x47, 0x50, 0x6D, 0x7C ), + BYTES_TO_T_UINT_8( 0x5F, 0x7D, 0xB9, 0x93, 0x7B, 0x68, 0xD1, 0x50 ), + BYTES_TO_T_UINT_8( 0x8D, 0xD4, 0xD0, 0xE2, 0x78, 0x1F, 0x3B, 0xFF ), + BYTES_TO_T_UINT_8( 0x8E, 0x09, 0xD0, 0xF4, 0xEE, 0x62, 0x3B, 0xB4 ), + BYTES_TO_T_UINT_8( 0xC1, 0x16, 0xD9, 0xB5, 0x70, 0x9F, 0xED, 0x85 ), + BYTES_TO_T_UINT_8( 0x93, 0x6A, 0x4C, 0x9C, 0x2E, 0x32, 0x21, 0x5A ), + BYTES_TO_T_UINT_8( 0x64, 0xD9, 0x2E, 0xD8, 0xBD, 0xE4, 0xAE, 0x81 ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_gy[] = { + BYTES_TO_T_UINT_8( 0x92, 0x08, 0xD8, 0x3A, 0x0F, 0x1E, 0xCD, 0x78 ), + BYTES_TO_T_UINT_8( 0x06, 0x54, 0xF0, 0xA8, 0x2F, 0x2B, 0xCA, 0xD1 ), + BYTES_TO_T_UINT_8( 0xAE, 0x63, 0x27, 0x8A, 0xD8, 0x4B, 0xCA, 0x5B ), + BYTES_TO_T_UINT_8( 0x5E, 0x48, 0x5F, 0x4A, 0x49, 0xDE, 0xDC, 0xB2 ), + BYTES_TO_T_UINT_8( 0x11, 0x81, 0x1F, 0x88, 0x5B, 0xC5, 0x00, 0xA0 ), + BYTES_TO_T_UINT_8( 0x1A, 0x7B, 0xA5, 0x24, 0x00, 0xF7, 0x09, 0xF2 ), + BYTES_TO_T_UINT_8( 0xFD, 0x22, 0x78, 0xCF, 0xA9, 0xBF, 0xEA, 0xC0 ), + BYTES_TO_T_UINT_8( 0xEC, 0x32, 0x63, 0x56, 0x5D, 0x38, 0xDE, 0x7D ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_n[] = { + BYTES_TO_T_UINT_8( 0x69, 0x00, 0xA9, 0x9C, 0x82, 0x96, 0x87, 0xB5 ), + BYTES_TO_T_UINT_8( 0xDD, 0xDA, 0x5D, 0x08, 0x81, 0xD3, 0xB1, 0x1D ), + BYTES_TO_T_UINT_8( 0x47, 0x10, 0xAC, 0x7F, 0x19, 0x61, 0x86, 0x41 ), + BYTES_TO_T_UINT_8( 0x19, 0x26, 0xA9, 0x4C, 0x41, 0x5C, 0x3E, 0x55 ), + BYTES_TO_T_UINT_8( 0x70, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6 ), + BYTES_TO_T_UINT_8( 0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB ), + BYTES_TO_T_UINT_8( 0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F ), + BYTES_TO_T_UINT_8( 0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA ), +}; +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + +/* + * Create an MPI from embedded constants + * (assumes len is an exact multiple of sizeof mbedtls_mpi_uint) + */ +static inline void ecp_mpi_load( mbedtls_mpi *X, const mbedtls_mpi_uint *p, size_t len ) +{ + X->s = 1; + X->n = len / sizeof( mbedtls_mpi_uint ); + X->p = (mbedtls_mpi_uint *) p; +} + +/* + * Set an MPI to static value 1 + */ +static inline void ecp_mpi_set1( mbedtls_mpi *X ) +{ + static mbedtls_mpi_uint one[] = { 1 }; + X->s = 1; + X->n = 1; + X->p = one; +} + +/* + * Make group available from embedded constants + */ +static int ecp_group_load( mbedtls_ecp_group *grp, + const mbedtls_mpi_uint *p, size_t plen, + const mbedtls_mpi_uint *a, size_t alen, + const mbedtls_mpi_uint *b, size_t blen, + const mbedtls_mpi_uint *gx, size_t gxlen, + const mbedtls_mpi_uint *gy, size_t gylen, + const mbedtls_mpi_uint *n, size_t nlen) +{ + ecp_mpi_load( &grp->P, p, plen ); + if( a != NULL ) + ecp_mpi_load( &grp->A, a, alen ); + ecp_mpi_load( &grp->B, b, blen ); + ecp_mpi_load( &grp->N, n, nlen ); + + ecp_mpi_load( &grp->G.X, gx, gxlen ); + ecp_mpi_load( &grp->G.Y, gy, gylen ); + ecp_mpi_set1( &grp->G.Z ); + + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + grp->nbits = mbedtls_mpi_bitlen( &grp->N ); + + grp->h = 1; + + return( 0 ); +} + +#if defined(MBEDTLS_ECP_NIST_OPTIM) +/* Forward declarations */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) +static int ecp_mod_p192( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) +static int ecp_mod_p224( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +static int ecp_mod_p256( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +static int ecp_mod_p384( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +static int ecp_mod_p521( mbedtls_mpi * ); +#endif + +#define NIST_MODP( P ) grp->modp = ecp_mod_ ## P; +#else +#define NIST_MODP( P ) +#endif /* MBEDTLS_ECP_NIST_OPTIM */ + +/* Additional forward declarations */ +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +static int ecp_mod_p255( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +static int ecp_mod_p448( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) +static int ecp_mod_p192k1( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +static int ecp_mod_p224k1( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +static int ecp_mod_p256k1( mbedtls_mpi * ); +#endif + +#define LOAD_GROUP_A( G ) ecp_group_load( grp, \ + G ## _p, sizeof( G ## _p ), \ + G ## _a, sizeof( G ## _a ), \ + G ## _b, sizeof( G ## _b ), \ + G ## _gx, sizeof( G ## _gx ), \ + G ## _gy, sizeof( G ## _gy ), \ + G ## _n, sizeof( G ## _n ) ) + +#define LOAD_GROUP( G ) ecp_group_load( grp, \ + G ## _p, sizeof( G ## _p ), \ + NULL, 0, \ + G ## _b, sizeof( G ## _b ), \ + G ## _gx, sizeof( G ## _gx ), \ + G ## _gy, sizeof( G ## _gy ), \ + G ## _n, sizeof( G ## _n ) ) + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +/* + * Specialized function for creating the Curve25519 group + */ +static int ecp_use_curve25519( mbedtls_ecp_group *grp ) +{ + int ret; + + /* Actually ( A + 2 ) / 4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &grp->A, 16, "01DB42" ) ); + + /* P = 2^255 - 19 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &grp->P, 255 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 19 ) ); + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + + /* N = 2^252 + 27742317777372353535851937790883648493 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &grp->N, 16, + "14DEF9DEA2F79CD65812631A5CF5D3ED" ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &grp->N, 252, 1 ) ); + + /* Y intentionally not set, since we use x/z coordinates. + * This is used as a marker to identify Montgomery curves! */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.X, 9 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.Z, 1 ) ); + mbedtls_mpi_free( &grp->G.Y ); + + /* Actually, the required msb for private keys */ + grp->nbits = 254; + +cleanup: + if( ret != 0 ) + mbedtls_ecp_group_free( grp ); + + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +/* + * Specialized function for creating the Curve448 group + */ +static int ecp_use_curve448( mbedtls_ecp_group *grp ) +{ + mbedtls_mpi Ns; + int ret; + + mbedtls_mpi_init( &Ns ); + + /* Actually ( A + 2 ) / 4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &grp->A, 16, "98AA" ) ); + + /* P = 2^448 - 2^224 - 1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &grp->P, 224 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &grp->P, 224 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 1 ) ); + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + + /* Y intentionally not set, since we use x/z coordinates. + * This is used as a marker to identify Montgomery curves! */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.X, 5 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.Z, 1 ) ); + mbedtls_mpi_free( &grp->G.Y ); + + /* N = 2^446 - 13818066809895115352007386748515426880336692474882178609894547503885 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &grp->N, 446, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &Ns, 16, + "8335DC163BB124B65129C96FDE933D8D723A70AADC873D6D54A7BB0D" ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &grp->N, &grp->N, &Ns ) ); + + /* Actually, the required msb for private keys */ + grp->nbits = 447; + +cleanup: + mbedtls_mpi_free( &Ns ); + if( ret != 0 ) + mbedtls_ecp_group_free( grp ); + + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + +/* + * Set a group using well-known domain parameters + */ +int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ) +{ + ECP_VALIDATE_RET( grp != NULL ); + mbedtls_ecp_group_free( grp ); + + grp->id = id; + + switch( id ) + { +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + case MBEDTLS_ECP_DP_SECP192R1: + NIST_MODP( p192 ); + return( LOAD_GROUP( secp192r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + case MBEDTLS_ECP_DP_SECP224R1: + NIST_MODP( p224 ); + return( LOAD_GROUP( secp224r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case MBEDTLS_ECP_DP_SECP256R1: + NIST_MODP( p256 ); + return( LOAD_GROUP( secp256r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + case MBEDTLS_ECP_DP_SECP384R1: + NIST_MODP( p384 ); + return( LOAD_GROUP( secp384r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + case MBEDTLS_ECP_DP_SECP521R1: + NIST_MODP( p521 ); + return( LOAD_GROUP( secp521r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + case MBEDTLS_ECP_DP_SECP192K1: + grp->modp = ecp_mod_p192k1; + return( LOAD_GROUP_A( secp192k1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + case MBEDTLS_ECP_DP_SECP224K1: + grp->modp = ecp_mod_p224k1; + return( LOAD_GROUP_A( secp224k1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + case MBEDTLS_ECP_DP_SECP256K1: + grp->modp = ecp_mod_p256k1; + return( LOAD_GROUP_A( secp256k1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + case MBEDTLS_ECP_DP_BP256R1: + return( LOAD_GROUP_A( brainpoolP256r1 ) ); +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + case MBEDTLS_ECP_DP_BP384R1: + return( LOAD_GROUP_A( brainpoolP384r1 ) ); +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + case MBEDTLS_ECP_DP_BP512R1: + return( LOAD_GROUP_A( brainpoolP512r1 ) ); +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + case MBEDTLS_ECP_DP_CURVE25519: + grp->modp = ecp_mod_p255; + return( ecp_use_curve25519( grp ) ); +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + case MBEDTLS_ECP_DP_CURVE448: + grp->modp = ecp_mod_p448; + return( ecp_use_curve448( grp ) ); +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + + default: + mbedtls_ecp_group_free( grp ); + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + } +} + +#if defined(MBEDTLS_ECP_NIST_OPTIM) +/* + * Fast reduction modulo the primes used by the NIST curves. + * + * These functions are critical for speed, but not needed for correct + * operations. So, we make the choice to heavily rely on the internals of our + * bignum library, which creates a tight coupling between these functions and + * our MPI implementation. However, the coupling between the ECP module and + * MPI remains loose, since these functions can be deactivated at will. + */ + +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) +/* + * Compared to the way things are presented in FIPS 186-3 D.2, + * we proceed in columns, from right (least significant chunk) to left, + * adding chunks to N in place, and keeping a carry for the next chunk. + * This avoids moving things around in memory, and uselessly adding zeros, + * compared to the more straightforward, line-oriented approach. + * + * For this prime we need to handle data in chunks of 64 bits. + * Since this is always a multiple of our basic mbedtls_mpi_uint, we can + * use a mbedtls_mpi_uint * to designate such a chunk, and small loops to handle it. + */ + +/* Add 64-bit chunks (dst += src) and update carry */ +static inline void add64( mbedtls_mpi_uint *dst, mbedtls_mpi_uint *src, mbedtls_mpi_uint *carry ) +{ + unsigned char i; + mbedtls_mpi_uint c = 0; + for( i = 0; i < 8 / sizeof( mbedtls_mpi_uint ); i++, dst++, src++ ) + { + *dst += c; c = ( *dst < c ); + *dst += *src; c += ( *dst < *src ); + } + *carry += c; +} + +/* Add carry to a 64-bit chunk and update carry */ +static inline void carry64( mbedtls_mpi_uint *dst, mbedtls_mpi_uint *carry ) +{ + unsigned char i; + for( i = 0; i < 8 / sizeof( mbedtls_mpi_uint ); i++, dst++ ) + { + *dst += *carry; + *carry = ( *dst < *carry ); + } +} + +#define WIDTH 8 / sizeof( mbedtls_mpi_uint ) +#define A( i ) N->p + (i) * WIDTH +#define ADD( i ) add64( p, A( i ), &c ) +#define NEXT p += WIDTH; carry64( p, &c ) +#define LAST p += WIDTH; *p = c; while( ++p < end ) *p = 0 + +/* + * Fast quasi-reduction modulo p192 (FIPS 186-3 D.2.1) + */ +static int ecp_mod_p192( mbedtls_mpi *N ) +{ + int ret; + mbedtls_mpi_uint c = 0; + mbedtls_mpi_uint *p, *end; + + /* Make sure we have enough blocks so that A(5) is legal */ + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( N, 6 * WIDTH ) ); + + p = N->p; + end = p + N->n; + + ADD( 3 ); ADD( 5 ); NEXT; // A0 += A3 + A5 + ADD( 3 ); ADD( 4 ); ADD( 5 ); NEXT; // A1 += A3 + A4 + A5 + ADD( 4 ); ADD( 5 ); LAST; // A2 += A4 + A5 + +cleanup: + return( ret ); +} + +#undef WIDTH +#undef A +#undef ADD +#undef NEXT +#undef LAST +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +/* + * The reader is advised to first understand ecp_mod_p192() since the same + * general structure is used here, but with additional complications: + * (1) chunks of 32 bits, and (2) subtractions. + */ + +/* + * For these primes, we need to handle data in chunks of 32 bits. + * This makes it more complicated if we use 64 bits limbs in MPI, + * which prevents us from using a uniform access method as for p192. + * + * So, we define a mini abstraction layer to access 32 bit chunks, + * load them in 'cur' for work, and store them back from 'cur' when done. + * + * While at it, also define the size of N in terms of 32-bit chunks. + */ +#define LOAD32 cur = A( i ); + +#if defined(MBEDTLS_HAVE_INT32) /* 32 bit */ + +#define MAX32 N->n +#define A( j ) N->p[j] +#define STORE32 N->p[i] = cur; + +#else /* 64-bit */ + +#define MAX32 N->n * 2 +#define A( j ) (j) % 2 ? (uint32_t)( N->p[(j)/2] >> 32 ) : \ + (uint32_t)( N->p[(j)/2] ) +#define STORE32 \ + if( i % 2 ) { \ + N->p[i/2] &= 0x00000000FFFFFFFF; \ + N->p[i/2] |= ((mbedtls_mpi_uint) cur) << 32; \ + } else { \ + N->p[i/2] &= 0xFFFFFFFF00000000; \ + N->p[i/2] |= (mbedtls_mpi_uint) cur; \ + } + +#endif /* sizeof( mbedtls_mpi_uint ) */ + +/* + * Helpers for addition and subtraction of chunks, with signed carry. + */ +static inline void add32( uint32_t *dst, uint32_t src, signed char *carry ) +{ + *dst += src; + *carry += ( *dst < src ); +} + +static inline void sub32( uint32_t *dst, uint32_t src, signed char *carry ) +{ + *carry -= ( *dst < src ); + *dst -= src; +} + +#define ADD( j ) add32( &cur, A( j ), &c ); +#define SUB( j ) sub32( &cur, A( j ), &c ); + +/* + * Helpers for the main 'loop' + * (see fix_negative for the motivation of C) + */ +#define INIT( b ) \ + int ret; \ + signed char c = 0, cc; \ + uint32_t cur; \ + size_t i = 0, bits = (b); \ + mbedtls_mpi C; \ + mbedtls_mpi_uint Cp[ (b) / 8 / sizeof( mbedtls_mpi_uint) + 1 ]; \ + \ + C.s = 1; \ + C.n = (b) / 8 / sizeof( mbedtls_mpi_uint) + 1; \ + C.p = Cp; \ + memset( Cp, 0, C.n * sizeof( mbedtls_mpi_uint ) ); \ + \ + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( N, (b) * 2 / 8 / \ + sizeof( mbedtls_mpi_uint ) ) ); \ + LOAD32; + +#define NEXT \ + STORE32; i++; LOAD32; \ + cc = c; c = 0; \ + if( cc < 0 ) \ + sub32( &cur, -cc, &c ); \ + else \ + add32( &cur, cc, &c ); \ + +#define LAST \ + STORE32; i++; \ + cur = c > 0 ? c : 0; STORE32; \ + cur = 0; while( ++i < MAX32 ) { STORE32; } \ + if( c < 0 ) fix_negative( N, c, &C, bits ); + +/* + * If the result is negative, we get it in the form + * c * 2^(bits + 32) + N, with c negative and N positive shorter than 'bits' + */ +static inline int fix_negative( mbedtls_mpi *N, signed char c, mbedtls_mpi *C, size_t bits ) +{ + int ret; + + /* C = - c * 2^(bits + 32) */ +#if !defined(MBEDTLS_HAVE_INT64) + ((void) bits); +#else + if( bits == 224 ) + C->p[ C->n - 1 ] = ((mbedtls_mpi_uint) -c) << 32; + else +#endif + C->p[ C->n - 1 ] = (mbedtls_mpi_uint) -c; + + /* N = - ( C - N ) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( N, C, N ) ); + N->s = -1; + +cleanup: + + return( ret ); +} + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) +/* + * Fast quasi-reduction modulo p224 (FIPS 186-3 D.2.2) + */ +static int ecp_mod_p224( mbedtls_mpi *N ) +{ + INIT( 224 ); + + SUB( 7 ); SUB( 11 ); NEXT; // A0 += -A7 - A11 + SUB( 8 ); SUB( 12 ); NEXT; // A1 += -A8 - A12 + SUB( 9 ); SUB( 13 ); NEXT; // A2 += -A9 - A13 + SUB( 10 ); ADD( 7 ); ADD( 11 ); NEXT; // A3 += -A10 + A7 + A11 + SUB( 11 ); ADD( 8 ); ADD( 12 ); NEXT; // A4 += -A11 + A8 + A12 + SUB( 12 ); ADD( 9 ); ADD( 13 ); NEXT; // A5 += -A12 + A9 + A13 + SUB( 13 ); ADD( 10 ); LAST; // A6 += -A13 + A10 + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +/* + * Fast quasi-reduction modulo p256 (FIPS 186-3 D.2.3) + */ +static int ecp_mod_p256( mbedtls_mpi *N ) +{ + INIT( 256 ); + + ADD( 8 ); ADD( 9 ); + SUB( 11 ); SUB( 12 ); SUB( 13 ); SUB( 14 ); NEXT; // A0 + + ADD( 9 ); ADD( 10 ); + SUB( 12 ); SUB( 13 ); SUB( 14 ); SUB( 15 ); NEXT; // A1 + + ADD( 10 ); ADD( 11 ); + SUB( 13 ); SUB( 14 ); SUB( 15 ); NEXT; // A2 + + ADD( 11 ); ADD( 11 ); ADD( 12 ); ADD( 12 ); ADD( 13 ); + SUB( 15 ); SUB( 8 ); SUB( 9 ); NEXT; // A3 + + ADD( 12 ); ADD( 12 ); ADD( 13 ); ADD( 13 ); ADD( 14 ); + SUB( 9 ); SUB( 10 ); NEXT; // A4 + + ADD( 13 ); ADD( 13 ); ADD( 14 ); ADD( 14 ); ADD( 15 ); + SUB( 10 ); SUB( 11 ); NEXT; // A5 + + ADD( 14 ); ADD( 14 ); ADD( 15 ); ADD( 15 ); ADD( 14 ); ADD( 13 ); + SUB( 8 ); SUB( 9 ); NEXT; // A6 + + ADD( 15 ); ADD( 15 ); ADD( 15 ); ADD( 8 ); + SUB( 10 ); SUB( 11 ); SUB( 12 ); SUB( 13 ); LAST; // A7 + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +/* + * Fast quasi-reduction modulo p384 (FIPS 186-3 D.2.4) + */ +static int ecp_mod_p384( mbedtls_mpi *N ) +{ + INIT( 384 ); + + ADD( 12 ); ADD( 21 ); ADD( 20 ); + SUB( 23 ); NEXT; // A0 + + ADD( 13 ); ADD( 22 ); ADD( 23 ); + SUB( 12 ); SUB( 20 ); NEXT; // A2 + + ADD( 14 ); ADD( 23 ); + SUB( 13 ); SUB( 21 ); NEXT; // A2 + + ADD( 15 ); ADD( 12 ); ADD( 20 ); ADD( 21 ); + SUB( 14 ); SUB( 22 ); SUB( 23 ); NEXT; // A3 + + ADD( 21 ); ADD( 21 ); ADD( 16 ); ADD( 13 ); ADD( 12 ); ADD( 20 ); ADD( 22 ); + SUB( 15 ); SUB( 23 ); SUB( 23 ); NEXT; // A4 + + ADD( 22 ); ADD( 22 ); ADD( 17 ); ADD( 14 ); ADD( 13 ); ADD( 21 ); ADD( 23 ); + SUB( 16 ); NEXT; // A5 + + ADD( 23 ); ADD( 23 ); ADD( 18 ); ADD( 15 ); ADD( 14 ); ADD( 22 ); + SUB( 17 ); NEXT; // A6 + + ADD( 19 ); ADD( 16 ); ADD( 15 ); ADD( 23 ); + SUB( 18 ); NEXT; // A7 + + ADD( 20 ); ADD( 17 ); ADD( 16 ); + SUB( 19 ); NEXT; // A8 + + ADD( 21 ); ADD( 18 ); ADD( 17 ); + SUB( 20 ); NEXT; // A9 + + ADD( 22 ); ADD( 19 ); ADD( 18 ); + SUB( 21 ); NEXT; // A10 + + ADD( 23 ); ADD( 20 ); ADD( 19 ); + SUB( 22 ); LAST; // A11 + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#undef A +#undef LOAD32 +#undef STORE32 +#undef MAX32 +#undef INIT +#undef NEXT +#undef LAST + +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED || + MBEDTLS_ECP_DP_SECP256R1_ENABLED || + MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +/* + * Here we have an actual Mersenne prime, so things are more straightforward. + * However, chunks are aligned on a 'weird' boundary (521 bits). + */ + +/* Size of p521 in terms of mbedtls_mpi_uint */ +#define P521_WIDTH ( 521 / 8 / sizeof( mbedtls_mpi_uint ) + 1 ) + +/* Bits to keep in the most significant mbedtls_mpi_uint */ +#define P521_MASK 0x01FF + +/* + * Fast quasi-reduction modulo p521 (FIPS 186-3 D.2.5) + * Write N as A1 + 2^521 A0, return A0 + A1 + */ +static int ecp_mod_p521( mbedtls_mpi *N ) +{ + int ret; + size_t i; + mbedtls_mpi M; + mbedtls_mpi_uint Mp[P521_WIDTH + 1]; + /* Worst case for the size of M is when mbedtls_mpi_uint is 16 bits: + * we need to hold bits 513 to 1056, which is 34 limbs, that is + * P521_WIDTH + 1. Otherwise P521_WIDTH is enough. */ + + if( N->n < P521_WIDTH ) + return( 0 ); + + /* M = A1 */ + M.s = 1; + M.n = N->n - ( P521_WIDTH - 1 ); + if( M.n > P521_WIDTH + 1 ) + M.n = P521_WIDTH + 1; + M.p = Mp; + memcpy( Mp, N->p + P521_WIDTH - 1, M.n * sizeof( mbedtls_mpi_uint ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, 521 % ( 8 * sizeof( mbedtls_mpi_uint ) ) ) ); + + /* N = A0 */ + N->p[P521_WIDTH - 1] &= P521_MASK; + for( i = P521_WIDTH; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + +cleanup: + return( ret ); +} + +#undef P521_WIDTH +#undef P521_MASK +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#endif /* MBEDTLS_ECP_NIST_OPTIM */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + +/* Size of p255 in terms of mbedtls_mpi_uint */ +#define P255_WIDTH ( 255 / 8 / sizeof( mbedtls_mpi_uint ) + 1 ) + +/* + * Fast quasi-reduction modulo p255 = 2^255 - 19 + * Write N as A0 + 2^255 A1, return A0 + 19 * A1 + */ +static int ecp_mod_p255( mbedtls_mpi *N ) +{ + int ret; + size_t i; + mbedtls_mpi M; + mbedtls_mpi_uint Mp[P255_WIDTH + 2]; + + if( N->n < P255_WIDTH ) + return( 0 ); + + /* M = A1 */ + M.s = 1; + M.n = N->n - ( P255_WIDTH - 1 ); + if( M.n > P255_WIDTH + 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + M.p = Mp; + memset( Mp, 0, sizeof Mp ); + memcpy( Mp, N->p + P255_WIDTH - 1, M.n * sizeof( mbedtls_mpi_uint ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, 255 % ( 8 * sizeof( mbedtls_mpi_uint ) ) ) ); + M.n++; /* Make room for multiplication by 19 */ + + /* N = A0 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( N, 255, 0 ) ); + for( i = P255_WIDTH; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + 19 * A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &M, &M, 19 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + +/* Size of p448 in terms of mbedtls_mpi_uint */ +#define P448_WIDTH ( 448 / 8 / sizeof( mbedtls_mpi_uint ) ) + +/* Number of limbs fully occupied by 2^224 (max), and limbs used by it (min) */ +#define DIV_ROUND_UP( X, Y ) ( ( ( X ) + ( Y ) - 1 ) / ( Y ) ) +#define P224_WIDTH_MIN ( 28 / sizeof( mbedtls_mpi_uint ) ) +#define P224_WIDTH_MAX DIV_ROUND_UP( 28, sizeof( mbedtls_mpi_uint ) ) +#define P224_UNUSED_BITS ( ( P224_WIDTH_MAX * sizeof( mbedtls_mpi_uint ) * 8 ) - 224 ) + +/* + * Fast quasi-reduction modulo p448 = 2^448 - 2^224 - 1 + * Write N as A0 + 2^448 A1 and A1 as B0 + 2^224 B1, and return + * A0 + A1 + B1 + (B0 + B1) * 2^224. This is different to the reference + * implementation of Curve448, which uses its own special 56-bit limbs rather + * than a generic bignum library. We could squeeze some extra speed out on + * 32-bit machines by splitting N up into 32-bit limbs and doing the + * arithmetic using the limbs directly as we do for the NIST primes above, + * but for 64-bit targets it should use half the number of operations if we do + * the reduction with 224-bit limbs, since mpi_add_mpi will then use 64-bit adds. + */ +static int ecp_mod_p448( mbedtls_mpi *N ) +{ + int ret; + size_t i; + mbedtls_mpi M, Q; + mbedtls_mpi_uint Mp[P448_WIDTH + 1], Qp[P448_WIDTH]; + + if( N->n <= P448_WIDTH ) + return( 0 ); + + /* M = A1 */ + M.s = 1; + M.n = N->n - ( P448_WIDTH ); + if( M.n > P448_WIDTH ) + /* Shouldn't be called with N larger than 2^896! */ + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + M.p = Mp; + memset( Mp, 0, sizeof( Mp ) ); + memcpy( Mp, N->p + P448_WIDTH, M.n * sizeof( mbedtls_mpi_uint ) ); + + /* N = A0 */ + for( i = P448_WIDTH; i < N->n; i++ ) + N->p[i] = 0; + + /* N += A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &M ) ); + + /* Q = B1, N += B1 */ + Q = M; + Q.p = Qp; + memcpy( Qp, Mp, sizeof( Qp ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Q, 224 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &Q ) ); + + /* M = (B0 + B1) * 2^224, N += M */ + if( sizeof( mbedtls_mpi_uint ) > 4 ) + Mp[P224_WIDTH_MIN] &= ( (mbedtls_mpi_uint)-1 ) >> ( P224_UNUSED_BITS ); + for( i = P224_WIDTH_MAX; i < M.n; ++i ) + Mp[i] = 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &M, &M, &Q ) ); + M.n = P448_WIDTH + 1; /* Make room for shifted carry bit from the addition */ + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &M, 224 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &M ) ); + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +/* + * Fast quasi-reduction modulo P = 2^s - R, + * with R about 33 bits, used by the Koblitz curves. + * + * Write N as A0 + 2^224 A1, return A0 + R * A1. + * Actually do two passes, since R is big. + */ +#define P_KOBLITZ_MAX ( 256 / 8 / sizeof( mbedtls_mpi_uint ) ) // Max limbs in P +#define P_KOBLITZ_R ( 8 / sizeof( mbedtls_mpi_uint ) ) // Limbs in R +static inline int ecp_mod_koblitz( mbedtls_mpi *N, mbedtls_mpi_uint *Rp, size_t p_limbs, + size_t adjust, size_t shift, mbedtls_mpi_uint mask ) +{ + int ret; + size_t i; + mbedtls_mpi M, R; + mbedtls_mpi_uint Mp[P_KOBLITZ_MAX + P_KOBLITZ_R + 1]; + + if( N->n < p_limbs ) + return( 0 ); + + /* Init R */ + R.s = 1; + R.p = Rp; + R.n = P_KOBLITZ_R; + + /* Common setup for M */ + M.s = 1; + M.p = Mp; + + /* M = A1 */ + M.n = N->n - ( p_limbs - adjust ); + if( M.n > p_limbs + adjust ) + M.n = p_limbs + adjust; + memset( Mp, 0, sizeof Mp ); + memcpy( Mp, N->p + p_limbs - adjust, M.n * sizeof( mbedtls_mpi_uint ) ); + if( shift != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, shift ) ); + M.n += R.n; /* Make room for multiplication by R */ + + /* N = A0 */ + if( mask != 0 ) + N->p[p_limbs - 1] &= mask; + for( i = p_limbs; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + R * A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &M, &M, &R ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + + /* Second pass */ + + /* M = A1 */ + M.n = N->n - ( p_limbs - adjust ); + if( M.n > p_limbs + adjust ) + M.n = p_limbs + adjust; + memset( Mp, 0, sizeof Mp ); + memcpy( Mp, N->p + p_limbs - adjust, M.n * sizeof( mbedtls_mpi_uint ) ); + if( shift != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, shift ) ); + M.n += R.n; /* Make room for multiplication by R */ + + /* N = A0 */ + if( mask != 0 ) + N->p[p_limbs - 1] &= mask; + for( i = p_limbs; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + R * A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &M, &M, &R ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED) || + MBEDTLS_ECP_DP_SECP224K1_ENABLED) || + MBEDTLS_ECP_DP_SECP256K1_ENABLED) */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) +/* + * Fast quasi-reduction modulo p192k1 = 2^192 - R, + * with R = 2^32 + 2^12 + 2^8 + 2^7 + 2^6 + 2^3 + 1 = 0x0100001119 + */ +static int ecp_mod_p192k1( mbedtls_mpi *N ) +{ + static mbedtls_mpi_uint Rp[] = { + BYTES_TO_T_UINT_8( 0xC9, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) }; + + return( ecp_mod_koblitz( N, Rp, 192 / 8 / sizeof( mbedtls_mpi_uint ), 0, 0, 0 ) ); +} +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +/* + * Fast quasi-reduction modulo p224k1 = 2^224 - R, + * with R = 2^32 + 2^12 + 2^11 + 2^9 + 2^7 + 2^4 + 2 + 1 = 0x0100001A93 + */ +static int ecp_mod_p224k1( mbedtls_mpi *N ) +{ + static mbedtls_mpi_uint Rp[] = { + BYTES_TO_T_UINT_8( 0x93, 0x1A, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) }; + +#if defined(MBEDTLS_HAVE_INT64) + return( ecp_mod_koblitz( N, Rp, 4, 1, 32, 0xFFFFFFFF ) ); +#else + return( ecp_mod_koblitz( N, Rp, 224 / 8 / sizeof( mbedtls_mpi_uint ), 0, 0, 0 ) ); +#endif +} + +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +/* + * Fast quasi-reduction modulo p256k1 = 2^256 - R, + * with R = 2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1 = 0x01000003D1 + */ +static int ecp_mod_p256k1( mbedtls_mpi *N ) +{ + static mbedtls_mpi_uint Rp[] = { + BYTES_TO_T_UINT_8( 0xD1, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) }; + return( ecp_mod_koblitz( N, Rp, 256 / 8 / sizeof( mbedtls_mpi_uint ), 0, 0, 0 ) ); +} +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +#endif /* !MBEDTLS_ECP_ALT */ + +#endif /* MBEDTLS_ECP_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/entropy.c b/FreeRTOS-Labs/Source/mbedtls/library/entropy.c new file mode 100644 index 000000000..785ca4831 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/entropy.c @@ -0,0 +1,721 @@ +/* + * Entropy accumulator implementation + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ENTROPY_C) + +#if defined(MBEDTLS_TEST_NULL_ENTROPY) +#warning "**** WARNING! MBEDTLS_TEST_NULL_ENTROPY defined! " +#warning "**** THIS BUILD HAS NO DEFINED ENTROPY SOURCES " +#warning "**** THIS BUILD IS *NOT* SUITABLE FOR PRODUCTION USE " +#endif + +#include "mbedtls/entropy.h" +#include "mbedtls/entropy_poll.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +#include "mbedtls/platform.h" +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if defined(MBEDTLS_HAVEGE_C) +#include "mbedtls/havege.h" +#endif + +#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */ + +void mbedtls_entropy_init( mbedtls_entropy_context *ctx ) +{ + ctx->source_count = 0; + memset( ctx->source, 0, sizeof( ctx->source ) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif + + ctx->accumulator_started = 0; +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_init( &ctx->accumulator ); +#else + mbedtls_sha256_init( &ctx->accumulator ); +#endif +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_init( &ctx->havege_data ); +#endif + + /* Reminder: Update ENTROPY_HAVE_STRONG in the test files + * when adding more strong entropy sources here. */ + +#if defined(MBEDTLS_TEST_NULL_ENTROPY) + mbedtls_entropy_add_source( ctx, mbedtls_null_entropy_poll, NULL, + 1, MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif + +#if !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) +#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) + mbedtls_entropy_add_source( ctx, mbedtls_platform_entropy_poll, NULL, + MBEDTLS_ENTROPY_MIN_PLATFORM, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#if defined(MBEDTLS_TIMING_C) + mbedtls_entropy_add_source( ctx, mbedtls_hardclock_poll, NULL, + MBEDTLS_ENTROPY_MIN_HARDCLOCK, + MBEDTLS_ENTROPY_SOURCE_WEAK ); +#endif +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_entropy_add_source( ctx, mbedtls_havege_poll, &ctx->havege_data, + MBEDTLS_ENTROPY_MIN_HAVEGE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + mbedtls_entropy_add_source( ctx, mbedtls_hardware_poll, NULL, + MBEDTLS_ENTROPY_MIN_HARDWARE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#if defined(MBEDTLS_ENTROPY_NV_SEED) + mbedtls_entropy_add_source( ctx, mbedtls_nv_seed_poll, NULL, + MBEDTLS_ENTROPY_BLOCK_SIZE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); + ctx->initial_entropy_run = 0; +#endif +#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */ +} + +void mbedtls_entropy_free( mbedtls_entropy_context *ctx ) +{ +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_free( &ctx->havege_data ); +#endif +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_free( &ctx->accumulator ); +#else + mbedtls_sha256_free( &ctx->accumulator ); +#endif +#if defined(MBEDTLS_ENTROPY_NV_SEED) + ctx->initial_entropy_run = 0; +#endif + ctx->source_count = 0; + mbedtls_platform_zeroize( ctx->source, sizeof( ctx->source ) ); + ctx->accumulator_started = 0; +} + +int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx, + mbedtls_entropy_f_source_ptr f_source, void *p_source, + size_t threshold, int strong ) +{ + int idx, ret = 0; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + idx = ctx->source_count; + if( idx >= MBEDTLS_ENTROPY_MAX_SOURCES ) + { + ret = MBEDTLS_ERR_ENTROPY_MAX_SOURCES; + goto exit; + } + + ctx->source[idx].f_source = f_source; + ctx->source[idx].p_source = p_source; + ctx->source[idx].threshold = threshold; + ctx->source[idx].strong = strong; + + ctx->source_count++; + +exit: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Entropy accumulator update + */ +static int entropy_update( mbedtls_entropy_context *ctx, unsigned char source_id, + const unsigned char *data, size_t len ) +{ + unsigned char header[2]; + unsigned char tmp[MBEDTLS_ENTROPY_BLOCK_SIZE]; + size_t use_len = len; + const unsigned char *p = data; + int ret = 0; + + if( use_len > MBEDTLS_ENTROPY_BLOCK_SIZE ) + { +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + if( ( ret = mbedtls_sha512_ret( data, len, tmp, 0 ) ) != 0 ) + goto cleanup; +#else + if( ( ret = mbedtls_sha256_ret( data, len, tmp, 0 ) ) != 0 ) + goto cleanup; +#endif + p = tmp; + use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; + } + + header[0] = source_id; + header[1] = use_len & 0xFF; + + /* + * Start the accumulator if this has not already happened. Note that + * it is sufficient to start the accumulator here only because all calls to + * gather entropy eventually execute this code. + */ +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + if( ctx->accumulator_started == 0 && + ( ret = mbedtls_sha512_starts_ret( &ctx->accumulator, 0 ) ) != 0 ) + goto cleanup; + else + ctx->accumulator_started = 1; + if( ( ret = mbedtls_sha512_update_ret( &ctx->accumulator, header, 2 ) ) != 0 ) + goto cleanup; + ret = mbedtls_sha512_update_ret( &ctx->accumulator, p, use_len ); +#else + if( ctx->accumulator_started == 0 && + ( ret = mbedtls_sha256_starts_ret( &ctx->accumulator, 0 ) ) != 0 ) + goto cleanup; + else + ctx->accumulator_started = 1; + if( ( ret = mbedtls_sha256_update_ret( &ctx->accumulator, header, 2 ) ) != 0 ) + goto cleanup; + ret = mbedtls_sha256_update_ret( &ctx->accumulator, p, use_len ); +#endif + +cleanup: + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); + + return( ret ); +} + +int mbedtls_entropy_update_manual( mbedtls_entropy_context *ctx, + const unsigned char *data, size_t len ) +{ + int ret; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = entropy_update( ctx, MBEDTLS_ENTROPY_SOURCE_MANUAL, data, len ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Run through the different sources to add entropy to our accumulator + */ +static int entropy_gather_internal( mbedtls_entropy_context *ctx ) +{ + int ret, i, have_one_strong = 0; + unsigned char buf[MBEDTLS_ENTROPY_MAX_GATHER]; + size_t olen; + + if( ctx->source_count == 0 ) + return( MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED ); + + /* + * Run through our entropy sources + */ + for( i = 0; i < ctx->source_count; i++ ) + { + if( ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG ) + have_one_strong = 1; + + olen = 0; + if( ( ret = ctx->source[i].f_source( ctx->source[i].p_source, + buf, MBEDTLS_ENTROPY_MAX_GATHER, &olen ) ) != 0 ) + { + goto cleanup; + } + + /* + * Add if we actually gathered something + */ + if( olen > 0 ) + { + if( ( ret = entropy_update( ctx, (unsigned char) i, + buf, olen ) ) != 0 ) + return( ret ); + ctx->source[i].size += olen; + } + } + + if( have_one_strong == 0 ) + ret = MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE; + +cleanup: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + + return( ret ); +} + +/* + * Thread-safe wrapper for entropy_gather_internal() + */ +int mbedtls_entropy_gather( mbedtls_entropy_context *ctx ) +{ + int ret; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = entropy_gather_internal( ctx ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +int mbedtls_entropy_func( void *data, unsigned char *output, size_t len ) +{ + int ret, count = 0, i, done; + mbedtls_entropy_context *ctx = (mbedtls_entropy_context *) data; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + if( len > MBEDTLS_ENTROPY_BLOCK_SIZE ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + +#if defined(MBEDTLS_ENTROPY_NV_SEED) + /* Update the NV entropy seed before generating any entropy for outside + * use. + */ + if( ctx->initial_entropy_run == 0 ) + { + ctx->initial_entropy_run = 1; + if( ( ret = mbedtls_entropy_update_nv_seed( ctx ) ) != 0 ) + return( ret ); + } +#endif + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + /* + * Always gather extra entropy before a call + */ + do + { + if( count++ > ENTROPY_MAX_LOOP ) + { + ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; + goto exit; + } + + if( ( ret = entropy_gather_internal( ctx ) ) != 0 ) + goto exit; + + done = 1; + for( i = 0; i < ctx->source_count; i++ ) + if( ctx->source[i].size < ctx->source[i].threshold ) + done = 0; + } + while( ! done ); + + memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + /* + * Note that at this stage it is assumed that the accumulator was started + * in a previous call to entropy_update(). If this is not guaranteed, the + * code below will fail. + */ + if( ( ret = mbedtls_sha512_finish_ret( &ctx->accumulator, buf ) ) != 0 ) + goto exit; + + /* + * Reset accumulator and counters and recycle existing entropy + */ + mbedtls_sha512_free( &ctx->accumulator ); + mbedtls_sha512_init( &ctx->accumulator ); + if( ( ret = mbedtls_sha512_starts_ret( &ctx->accumulator, 0 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_sha512_update_ret( &ctx->accumulator, buf, + MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 ) + goto exit; + + /* + * Perform second SHA-512 on entropy + */ + if( ( ret = mbedtls_sha512_ret( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, + buf, 0 ) ) != 0 ) + goto exit; +#else /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */ + if( ( ret = mbedtls_sha256_finish_ret( &ctx->accumulator, buf ) ) != 0 ) + goto exit; + + /* + * Reset accumulator and counters and recycle existing entropy + */ + mbedtls_sha256_free( &ctx->accumulator ); + mbedtls_sha256_init( &ctx->accumulator ); + if( ( ret = mbedtls_sha256_starts_ret( &ctx->accumulator, 0 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_sha256_update_ret( &ctx->accumulator, buf, + MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 ) + goto exit; + + /* + * Perform second SHA-256 on entropy + */ + if( ( ret = mbedtls_sha256_ret( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, + buf, 0 ) ) != 0 ) + goto exit; +#endif /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */ + + for( i = 0; i < ctx->source_count; i++ ) + ctx->source[i].size = 0; + + memcpy( output, buf, len ); + + ret = 0; + +exit: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +int mbedtls_entropy_update_nv_seed( mbedtls_entropy_context *ctx ) +{ + int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + /* Read new seed and write it to NV */ + if( ( ret = mbedtls_entropy_func( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 ) + return( ret ); + + if( mbedtls_nv_seed_write( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) < 0 ) + return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); + + /* Manually update the remaining stream with a separator value to diverge */ + memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + ret = mbedtls_entropy_update_manual( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + return( ret ); +} +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#if defined(MBEDTLS_FS_IO) +int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *path ) +{ + int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + FILE *f; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); + + if( ( ret = mbedtls_entropy_func( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 ) + goto exit; + + if( fwrite( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) != MBEDTLS_ENTROPY_BLOCK_SIZE ) + { + ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + goto exit; + } + + ret = 0; + +exit: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + + fclose( f ); + return( ret ); +} + +int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *path ) +{ + int ret = 0; + FILE *f; + size_t n; + unsigned char buf[ MBEDTLS_ENTROPY_MAX_SEED_SIZE ]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( n > MBEDTLS_ENTROPY_MAX_SEED_SIZE ) + n = MBEDTLS_ENTROPY_MAX_SEED_SIZE; + + if( fread( buf, 1, n, f ) != n ) + ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + else + ret = mbedtls_entropy_update_manual( ctx, buf, n ); + + fclose( f ); + + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + + if( ret != 0 ) + return( ret ); + + return( mbedtls_entropy_write_seed_file( ctx, path ) ); +} +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) +#if !defined(MBEDTLS_TEST_NULL_ENTROPY) +/* + * Dummy source function + */ +static int entropy_dummy_source( void *data, unsigned char *output, + size_t len, size_t *olen ) +{ + ((void) data); + + memset( output, 0x2a, len ); + *olen = len; + + return( 0 ); +} +#endif /* !MBEDTLS_TEST_NULL_ENTROPY */ + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + +static int mbedtls_entropy_source_self_test_gather( unsigned char *buf, size_t buf_len ) +{ + int ret = 0; + size_t entropy_len = 0; + size_t olen = 0; + size_t attempts = buf_len; + + while( attempts > 0 && entropy_len < buf_len ) + { + if( ( ret = mbedtls_hardware_poll( NULL, buf + entropy_len, + buf_len - entropy_len, &olen ) ) != 0 ) + return( ret ); + + entropy_len += olen; + attempts--; + } + + if( entropy_len < buf_len ) + { + ret = 1; + } + + return( ret ); +} + + +static int mbedtls_entropy_source_self_test_check_bits( const unsigned char *buf, + size_t buf_len ) +{ + unsigned char set= 0xFF; + unsigned char unset = 0x00; + size_t i; + + for( i = 0; i < buf_len; i++ ) + { + set &= buf[i]; + unset |= buf[i]; + } + + return( set == 0xFF || unset == 0x00 ); +} + +/* + * A test to ensure hat the entropy sources are functioning correctly + * and there is no obvious failure. The test performs the following checks: + * - The entropy source is not providing only 0s (all bits unset) or 1s (all + * bits set). + * - The entropy source is not providing values in a pattern. Because the + * hardware could be providing data in an arbitrary length, this check polls + * the hardware entropy source twice and compares the result to ensure they + * are not equal. + * - The error code returned by the entropy source is not an error. + */ +int mbedtls_entropy_source_self_test( int verbose ) +{ + int ret = 0; + unsigned char buf0[2 * sizeof( unsigned long long int )]; + unsigned char buf1[2 * sizeof( unsigned long long int )]; + + if( verbose != 0 ) + mbedtls_printf( " ENTROPY_BIAS test: " ); + + memset( buf0, 0x00, sizeof( buf0 ) ); + memset( buf1, 0x00, sizeof( buf1 ) ); + + if( ( ret = mbedtls_entropy_source_self_test_gather( buf0, sizeof( buf0 ) ) ) != 0 ) + goto cleanup; + if( ( ret = mbedtls_entropy_source_self_test_gather( buf1, sizeof( buf1 ) ) ) != 0 ) + goto cleanup; + + /* Make sure that the returned values are not all 0 or 1 */ + if( ( ret = mbedtls_entropy_source_self_test_check_bits( buf0, sizeof( buf0 ) ) ) != 0 ) + goto cleanup; + if( ( ret = mbedtls_entropy_source_self_test_check_bits( buf1, sizeof( buf1 ) ) ) != 0 ) + goto cleanup; + + /* Make sure that the entropy source is not returning values in a + * pattern */ + ret = memcmp( buf0, buf1, sizeof( buf0 ) ) == 0; + +cleanup: + if( verbose != 0 ) + { + if( ret != 0 ) + mbedtls_printf( "failed\n" ); + else + mbedtls_printf( "passed\n" ); + + mbedtls_printf( "\n" ); + } + + return( ret != 0 ); +} + +#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ + +/* + * The actual entropy quality is hard to test, but we can at least + * test that the functions don't cause errors and write the correct + * amount of data to buffers. + */ +int mbedtls_entropy_self_test( int verbose ) +{ + int ret = 1; +#if !defined(MBEDTLS_TEST_NULL_ENTROPY) + mbedtls_entropy_context ctx; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; + unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; + size_t i, j; +#endif /* !MBEDTLS_TEST_NULL_ENTROPY */ + + if( verbose != 0 ) + mbedtls_printf( " ENTROPY test: " ); + +#if !defined(MBEDTLS_TEST_NULL_ENTROPY) + mbedtls_entropy_init( &ctx ); + + /* First do a gather to make sure we have default sources */ + if( ( ret = mbedtls_entropy_gather( &ctx ) ) != 0 ) + goto cleanup; + + ret = mbedtls_entropy_add_source( &ctx, entropy_dummy_source, NULL, 16, + MBEDTLS_ENTROPY_SOURCE_WEAK ); + if( ret != 0 ) + goto cleanup; + + if( ( ret = mbedtls_entropy_update_manual( &ctx, buf, sizeof buf ) ) != 0 ) + goto cleanup; + + /* + * To test that mbedtls_entropy_func writes correct number of bytes: + * - use the whole buffer and rely on ASan to detect overruns + * - collect entropy 8 times and OR the result in an accumulator: + * any byte should then be 0 with probably 2^(-64), so requiring + * each of the 32 or 64 bytes to be non-zero has a false failure rate + * of at most 2^(-58) which is acceptable. + */ + for( i = 0; i < 8; i++ ) + { + if( ( ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ) ) != 0 ) + goto cleanup; + + for( j = 0; j < sizeof( buf ); j++ ) + acc[j] |= buf[j]; + } + + for( j = 0; j < sizeof( buf ); j++ ) + { + if( acc[j] == 0 ) + { + ret = 1; + goto cleanup; + } + } + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + if( ( ret = mbedtls_entropy_source_self_test( 0 ) ) != 0 ) + goto cleanup; +#endif + +cleanup: + mbedtls_entropy_free( &ctx ); +#endif /* !MBEDTLS_TEST_NULL_ENTROPY */ + + if( verbose != 0 ) + { + if( ret != 0 ) + mbedtls_printf( "failed\n" ); + else + mbedtls_printf( "passed\n" ); + + mbedtls_printf( "\n" ); + } + + return( ret != 0 ); +} +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ENTROPY_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/entropy_poll.c b/FreeRTOS-Labs/Source/mbedtls/library/entropy_poll.c new file mode 100644 index 000000000..3b8fea231 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/entropy_poll.c @@ -0,0 +1,236 @@ +/* + * Platform-specific and custom entropy polling functions + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if defined(__linux__) +/* Ensure that syscall() is available even when compiling with -std=c99 */ +#define _GNU_SOURCE +#endif + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_ENTROPY_C) + +#include "mbedtls/entropy.h" +#include "mbedtls/entropy_poll.h" + +#if defined(MBEDTLS_TIMING_C) +#include "mbedtls/timing.h" +#endif +#if defined(MBEDTLS_HAVEGE_C) +#include "mbedtls/havege.h" +#endif +#if defined(MBEDTLS_ENTROPY_NV_SEED) +#include "mbedtls/platform.h" +#endif + +#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) + +#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ + !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ + !defined(__HAIKU__) +#error "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in config.h" +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + +#if !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x0400 +#endif +#include +#include + +int mbedtls_platform_entropy_poll( void *data, unsigned char *output, size_t len, + size_t *olen ) +{ + HCRYPTPROV provider; + ((void) data); + *olen = 0; + + if( CryptAcquireContext( &provider, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) == FALSE ) + { + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + } + + if( CryptGenRandom( provider, (DWORD) len, output ) == FALSE ) + { + CryptReleaseContext( provider, 0 ); + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + } + + CryptReleaseContext( provider, 0 ); + *olen = len; + + return( 0 ); +} +#else /* _WIN32 && !EFIX64 && !EFI32 */ + +/* + * Test for Linux getrandom() support. + * Since there is no wrapper in the libc yet, use the generic syscall wrapper + * available in GNU libc and compatible libc's (eg uClibc). + */ +#if defined(__linux__) && defined(__GLIBC__) +#include +#include +#if defined(SYS_getrandom) +#define HAVE_GETRANDOM +#include + +static int getrandom_wrapper( void *buf, size_t buflen, unsigned int flags ) +{ + /* MemSan cannot understand that the syscall writes to the buffer */ +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) + memset( buf, 0, buflen ); +#endif +#endif + return( syscall( SYS_getrandom, buf, buflen, flags ) ); +} +#endif /* SYS_getrandom */ +#endif /* __linux__ */ + +#include + +int mbedtls_platform_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + FILE *file; + size_t read_len; + int ret; + ((void) data); + +#if defined(HAVE_GETRANDOM) + ret = getrandom_wrapper( output, len, 0 ); + if( ret >= 0 ) + { + *olen = ret; + return( 0 ); + } + else if( errno != ENOSYS ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + /* Fall through if the system call isn't known. */ +#else + ((void) ret); +#endif /* HAVE_GETRANDOM */ + + *olen = 0; + + file = fopen( "/dev/urandom", "rb" ); + if( file == NULL ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + read_len = fread( output, 1, len, file ); + if( read_len != len ) + { + fclose( file ); + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + } + + fclose( file ); + *olen = len; + + return( 0 ); +} +#endif /* _WIN32 && !EFIX64 && !EFI32 */ +#endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */ + +#if defined(MBEDTLS_TEST_NULL_ENTROPY) +int mbedtls_null_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + ((void) data); + ((void) output); + *olen = 0; + + if( len < sizeof(unsigned char) ) + return( 0 ); + + *olen = sizeof(unsigned char); + + return( 0 ); +} +#endif + +#if defined(MBEDTLS_TIMING_C) +int mbedtls_hardclock_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + unsigned long timer = mbedtls_timing_hardclock(); + ((void) data); + *olen = 0; + + if( len < sizeof(unsigned long) ) + return( 0 ); + + memcpy( output, &timer, sizeof(unsigned long) ); + *olen = sizeof(unsigned long); + + return( 0 ); +} +#endif /* MBEDTLS_TIMING_C */ + +#if defined(MBEDTLS_HAVEGE_C) +int mbedtls_havege_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + mbedtls_havege_state *hs = (mbedtls_havege_state *) data; + *olen = 0; + + if( mbedtls_havege_random( hs, output, len ) != 0 ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + *olen = len; + + return( 0 ); +} +#endif /* MBEDTLS_HAVEGE_C */ + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +int mbedtls_nv_seed_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + size_t use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; + ((void) data); + + memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + if( mbedtls_nv_seed_read( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) < 0 ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + if( len < use_len ) + use_len = len; + + memcpy( output, buf, use_len ); + *olen = use_len; + + return( 0 ); +} +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#endif /* MBEDTLS_ENTROPY_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/error.c b/FreeRTOS-Labs/Source/mbedtls/library/error.c new file mode 100644 index 000000000..94ae0a21f --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/error.c @@ -0,0 +1,918 @@ +/* + * Error message information + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ERROR_C) || defined(MBEDTLS_ERROR_STRERROR_DUMMY) +#include "mbedtls/error.h" +#include +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_snprintf snprintf +#define mbedtls_time_t time_t +#endif + +#if defined(MBEDTLS_ERROR_C) + +#include + +#if defined(MBEDTLS_AES_C) +#include "mbedtls/aes.h" +#endif + +#if defined(MBEDTLS_ARC4_C) +#include "mbedtls/arc4.h" +#endif + +#if defined(MBEDTLS_ARIA_C) +#include "mbedtls/aria.h" +#endif + +#if defined(MBEDTLS_BASE64_C) +#include "mbedtls/base64.h" +#endif + +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/bignum.h" +#endif + +#if defined(MBEDTLS_BLOWFISH_C) +#include "mbedtls/blowfish.h" +#endif + +#if defined(MBEDTLS_CAMELLIA_C) +#include "mbedtls/camellia.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/ccm.h" +#endif + +#if defined(MBEDTLS_CHACHA20_C) +#include "mbedtls/chacha20.h" +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) +#include "mbedtls/chachapoly.h" +#endif + +#if defined(MBEDTLS_CIPHER_C) +#include "mbedtls/cipher.h" +#endif + +#if defined(MBEDTLS_CMAC_C) +#include "mbedtls/cmac.h" +#endif + +#if defined(MBEDTLS_CTR_DRBG_C) +#include "mbedtls/ctr_drbg.h" +#endif + +#if defined(MBEDTLS_DES_C) +#include "mbedtls/des.h" +#endif + +#if defined(MBEDTLS_DHM_C) +#include "mbedtls/dhm.h" +#endif + +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif + +#if defined(MBEDTLS_ENTROPY_C) +#include "mbedtls/entropy.h" +#endif + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/gcm.h" +#endif + +#if defined(MBEDTLS_HKDF_C) +#include "mbedtls/hkdf.h" +#endif + +#if defined(MBEDTLS_HMAC_DRBG_C) +#include "mbedtls/hmac_drbg.h" +#endif + +#if defined(MBEDTLS_MD_C) +#include "mbedtls/md.h" +#endif + +#if defined(MBEDTLS_MD2_C) +#include "mbedtls/md2.h" +#endif + +#if defined(MBEDTLS_MD4_C) +#include "mbedtls/md4.h" +#endif + +#if defined(MBEDTLS_MD5_C) +#include "mbedtls/md5.h" +#endif + +#if defined(MBEDTLS_OID_C) +#include "mbedtls/oid.h" +#endif + +#if defined(MBEDTLS_PADLOCK_C) +#include "mbedtls/padlock.h" +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PK_C) +#include "mbedtls/pk.h" +#endif + +#if defined(MBEDTLS_PKCS12_C) +#include "mbedtls/pkcs12.h" +#endif + +#if defined(MBEDTLS_PKCS5_C) +#include "mbedtls/pkcs5.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#endif + +#if defined(MBEDTLS_POLY1305_C) +#include "mbedtls/poly1305.h" +#endif + +#if defined(MBEDTLS_RIPEMD160_C) +#include "mbedtls/ripemd160.h" +#endif + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif + +#if defined(MBEDTLS_SHA1_C) +#include "mbedtls/sha1.h" +#endif + +#if defined(MBEDTLS_SHA256_C) +#include "mbedtls/sha256.h" +#endif + +#if defined(MBEDTLS_SHA512_C) +#include "mbedtls/sha512.h" +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +#if defined(MBEDTLS_XTEA_C) +#include "mbedtls/xtea.h" +#endif + +#if defined(MBEDTLS_NET_C) +#include "mbedtls/net_sockets.h" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) +#include "mbedtls/ssl.h" +#endif + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +#include "mbedtls/x509.h" +#endif + + +void mbedtls_strerror( int ret, char *buf, size_t buflen ) +{ + size_t len; + int use_ret; + + if( buflen == 0 ) + return; + + memset( buf, 0x00, buflen ); + + if( ret < 0 ) + ret = -ret; + + if( ret & 0xFF80 ) + { + use_ret = ret & 0xFF80; + + // High level error codes + // + // BEGIN generated code +#if defined(MBEDTLS_CIPHER_C) + if( use_ret == -(MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "CIPHER - The selected feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Bad input parameters" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Failed to allocate memory" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_INVALID_PADDING) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Input data contains invalid padding and is rejected" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Decryption of block requires a full block" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Authentication failed (for AEAD modes)" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_INVALID_CONTEXT) ) + mbedtls_snprintf( buf, buflen, "CIPHER - The context is invalid. For example, because it was freed" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Cipher hardware accelerator failed" ); +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_DHM_C) + if( use_ret == -(MBEDTLS_ERR_DHM_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "DHM - Bad input parameters" ); + if( use_ret == -(MBEDTLS_ERR_DHM_READ_PARAMS_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Reading of the DHM parameters failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Making of the DHM parameters failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Reading of the public values failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Making of the public value failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_CALC_SECRET_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Calculation of the DHM secret failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "DHM - The ASN.1 data is not formatted correctly" ); + if( use_ret == -(MBEDTLS_ERR_DHM_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Allocation of memory failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "DHM - Read or write of file failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - DHM hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_SET_GROUP_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Setting the modulus and generator failed" ); +#endif /* MBEDTLS_DHM_C */ + +#if defined(MBEDTLS_ECP_C) + if( use_ret == -(MBEDTLS_ERR_ECP_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "ECP - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "ECP - The buffer is too small to write to" ); + if( use_ret == -(MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "ECP - The requested feature is not available, for example, the requested curve is not supported" ); + if( use_ret == -(MBEDTLS_ERR_ECP_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "ECP - The signature is not valid" ); + if( use_ret == -(MBEDTLS_ERR_ECP_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "ECP - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_ECP_RANDOM_FAILED) ) + mbedtls_snprintf( buf, buflen, "ECP - Generation of random value, such as ephemeral key, failed" ); + if( use_ret == -(MBEDTLS_ERR_ECP_INVALID_KEY) ) + mbedtls_snprintf( buf, buflen, "ECP - Invalid private or public key" ); + if( use_ret == -(MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "ECP - The buffer contains a valid signature followed by more data" ); + if( use_ret == -(MBEDTLS_ERR_ECP_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "ECP - The ECP hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_ECP_IN_PROGRESS) ) + mbedtls_snprintf( buf, buflen, "ECP - Operation in progress, call again with the same parameters to continue" ); +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_MD_C) + if( use_ret == -(MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "MD - The selected feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_MD_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "MD - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_MD_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "MD - Failed to allocate memory" ); + if( use_ret == -(MBEDTLS_ERR_MD_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "MD - Opening or reading of file failed" ); + if( use_ret == -(MBEDTLS_ERR_MD_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "MD - MD hardware accelerator failed" ); +#endif /* MBEDTLS_MD_C */ + +#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) + if( use_ret == -(MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) ) + mbedtls_snprintf( buf, buflen, "PEM - No PEM header or footer found" ); + if( use_ret == -(MBEDTLS_ERR_PEM_INVALID_DATA) ) + mbedtls_snprintf( buf, buflen, "PEM - PEM string is not as expected" ); + if( use_ret == -(MBEDTLS_ERR_PEM_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "PEM - Failed to allocate memory" ); + if( use_ret == -(MBEDTLS_ERR_PEM_INVALID_ENC_IV) ) + mbedtls_snprintf( buf, buflen, "PEM - RSA IV is not in hex-format" ); + if( use_ret == -(MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG) ) + mbedtls_snprintf( buf, buflen, "PEM - Unsupported key encryption algorithm" ); + if( use_ret == -(MBEDTLS_ERR_PEM_PASSWORD_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "PEM - Private key password can't be empty" ); + if( use_ret == -(MBEDTLS_ERR_PEM_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PEM - Given private key password does not allow for correct decryption" ); + if( use_ret == -(MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PEM - Unavailable feature, e.g. hashing/encryption combination" ); + if( use_ret == -(MBEDTLS_ERR_PEM_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PEM - Bad input parameters to function" ); +#endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */ + +#if defined(MBEDTLS_PK_C) + if( use_ret == -(MBEDTLS_ERR_PK_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "PK - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_PK_TYPE_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PK - Type mismatch, eg attempt to encrypt with an ECDSA key" ); + if( use_ret == -(MBEDTLS_ERR_PK_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PK - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_PK_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "PK - Read/write of file failed" ); + if( use_ret == -(MBEDTLS_ERR_PK_KEY_INVALID_VERSION) ) + mbedtls_snprintf( buf, buflen, "PK - Unsupported key version" ); + if( use_ret == -(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "PK - Invalid key tag or value" ); + if( use_ret == -(MBEDTLS_ERR_PK_UNKNOWN_PK_ALG) ) + mbedtls_snprintf( buf, buflen, "PK - Key algorithm is unsupported (only RSA and EC are supported)" ); + if( use_ret == -(MBEDTLS_ERR_PK_PASSWORD_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "PK - Private key password can't be empty" ); + if( use_ret == -(MBEDTLS_ERR_PK_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PK - Given private key password does not allow for correct decryption" ); + if( use_ret == -(MBEDTLS_ERR_PK_INVALID_PUBKEY) ) + mbedtls_snprintf( buf, buflen, "PK - The pubkey tag or value is invalid (only RSA and EC are supported)" ); + if( use_ret == -(MBEDTLS_ERR_PK_INVALID_ALG) ) + mbedtls_snprintf( buf, buflen, "PK - The algorithm tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE) ) + mbedtls_snprintf( buf, buflen, "PK - Elliptic curve is unsupported (only NIST curves are supported)" ); + if( use_ret == -(MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PK - Unavailable feature, e.g. RSA disabled for RSA key" ); + if( use_ret == -(MBEDTLS_ERR_PK_SIG_LEN_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PK - The buffer contains a valid signature followed by more data" ); + if( use_ret == -(MBEDTLS_ERR_PK_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "PK - PK hardware accelerator failed" ); +#endif /* MBEDTLS_PK_C */ + +#if defined(MBEDTLS_PKCS12_C) + if( use_ret == -(MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - Feature not available, e.g. unsupported encryption scheme" ); + if( use_ret == -(MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - PBE ASN.1 data not as expected" ); + if( use_ret == -(MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - Given private key password does not allow for correct decryption" ); +#endif /* MBEDTLS_PKCS12_C */ + +#if defined(MBEDTLS_PKCS5_C) + if( use_ret == -(MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_PKCS5_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Unexpected ASN.1 data" ); + if( use_ret == -(MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Requested encryption or digest alg not available" ); + if( use_ret == -(MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Given private key password does not allow for correct decryption" ); +#endif /* MBEDTLS_PKCS5_C */ + +#if defined(MBEDTLS_RSA_C) + if( use_ret == -(MBEDTLS_ERR_RSA_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "RSA - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_RSA_INVALID_PADDING) ) + mbedtls_snprintf( buf, buflen, "RSA - Input data contains invalid padding and is rejected" ); + if( use_ret == -(MBEDTLS_ERR_RSA_KEY_GEN_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - Something failed during generation of a key" ); + if( use_ret == -(MBEDTLS_ERR_RSA_KEY_CHECK_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - Key failed to pass the validity check of the library" ); + if( use_ret == -(MBEDTLS_ERR_RSA_PUBLIC_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The public key operation failed" ); + if( use_ret == -(MBEDTLS_ERR_RSA_PRIVATE_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The private key operation failed" ); + if( use_ret == -(MBEDTLS_ERR_RSA_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The PKCS#1 verification failed" ); + if( use_ret == -(MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE) ) + mbedtls_snprintf( buf, buflen, "RSA - The output buffer for decryption is not large enough" ); + if( use_ret == -(MBEDTLS_ERR_RSA_RNG_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The random generator failed to generate non-zeros" ); + if( use_ret == -(MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION) ) + mbedtls_snprintf( buf, buflen, "RSA - The implementation does not offer the requested operation, for example, because of security violations or lack of functionality" ); + if( use_ret == -(MBEDTLS_ERR_RSA_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - RSA hardware accelerator failed" ); +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_SSL_TLS_C) + if( use_ret == -(MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "SSL - The requested feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "SSL - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_MAC) ) + mbedtls_snprintf( buf, buflen, "SSL - Verification of the message MAC failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_RECORD) ) + mbedtls_snprintf( buf, buflen, "SSL - An invalid SSL record was received" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CONN_EOF) ) + mbedtls_snprintf( buf, buflen, "SSL - The connection indicated an EOF" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNKNOWN_CIPHER) ) + mbedtls_snprintf( buf, buflen, "SSL - An unknown cipher was received" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN) ) + mbedtls_snprintf( buf, buflen, "SSL - The server has no ciphersuites in common with the client" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_RNG) ) + mbedtls_snprintf( buf, buflen, "SSL - No RNG was provided to the SSL module" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE) ) + mbedtls_snprintf( buf, buflen, "SSL - No client certification received from the client, but required by the authentication mode" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Our own certificate(s) is/are too large to send in an SSL message" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - The own certificate is not set, but needed by the server" ); + if( use_ret == -(MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - The own private key or pre-shared key is not set, but needed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - No CA Chain is set, but required to operate" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE) ) + mbedtls_snprintf( buf, buflen, "SSL - An unexpected message was received from our peer" ); + if( use_ret == -(MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE) ) + { + mbedtls_snprintf( buf, buflen, "SSL - A fatal alert message was received from our peer" ); + return; + } + if( use_ret == -(MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Verification of our peer failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) ) + mbedtls_snprintf( buf, buflen, "SSL - The peer notified us that the connection is going to be closed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientHello handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ServerHello handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the Certificate handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the CertificateRequest handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ServerKeyExchange handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ServerHelloDone handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Read Public" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Calculate Secret" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the CertificateVerify handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ChangeCipherSpec handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_FINISHED) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the Finished handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Hardware acceleration function returned with error" ); + if( use_ret == -(MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH) ) + mbedtls_snprintf( buf, buflen, "SSL - Hardware acceleration function skipped / left alone data" ); + if( use_ret == -(MBEDTLS_ERR_SSL_COMPRESSION_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the compression / decompression failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION) ) + mbedtls_snprintf( buf, buflen, "SSL - Handshake protocol not within min/max boundaries" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the NewSessionTicket handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - Session ticket has expired" ); + if( use_ret == -(MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "SSL - Public key type mismatch (eg, asked for RSA key exchange and presented EC key)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY) ) + mbedtls_snprintf( buf, buflen, "SSL - Unknown identity received (eg, PSK identity)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INTERNAL_ERROR) ) + mbedtls_snprintf( buf, buflen, "SSL - Internal error (eg, unexpected failure in lower-level module)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_COUNTER_WRAPPING) ) + mbedtls_snprintf( buf, buflen, "SSL - A counter would wrap (eg, too many messages exchanged)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO) ) + mbedtls_snprintf( buf, buflen, "SSL - Unexpected message at ServerHello in renegotiation" ); + if( use_ret == -(MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - DTLS client must retry for hello verification" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "SSL - A buffer is too small to receive or write a message" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) ) + mbedtls_snprintf( buf, buflen, "SSL - None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_WANT_READ) ) + mbedtls_snprintf( buf, buflen, "SSL - No data of requested type currently available on underlying transport" ); + if( use_ret == -(MBEDTLS_ERR_SSL_WANT_WRITE) ) + mbedtls_snprintf( buf, buflen, "SSL - Connection requires a write call" ); + if( use_ret == -(MBEDTLS_ERR_SSL_TIMEOUT) ) + mbedtls_snprintf( buf, buflen, "SSL - The operation timed out" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CLIENT_RECONNECT) ) + mbedtls_snprintf( buf, buflen, "SSL - The client initiated a reconnect from the same port" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNEXPECTED_RECORD) ) + mbedtls_snprintf( buf, buflen, "SSL - Record header looks valid but is not expected" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NON_FATAL) ) + mbedtls_snprintf( buf, buflen, "SSL - The alert message received indicates a non-fatal error" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH) ) + mbedtls_snprintf( buf, buflen, "SSL - Couldn't set the hash for verifying CertificateVerify" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CONTINUE_PROCESSING) ) + mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that further message-processing should be done" ); + if( use_ret == -(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) ) + mbedtls_snprintf( buf, buflen, "SSL - The asynchronous operation is not completed yet" ); + if( use_ret == -(MBEDTLS_ERR_SSL_EARLY_MESSAGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that a message arrived early" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNEXPECTED_CID) ) + mbedtls_snprintf( buf, buflen, "SSL - An encrypted DTLS-frame with an unexpected CID was received" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) ) + mbedtls_snprintf( buf, buflen, "SSL - A cryptographic operation is in progress. Try again later" ); +#endif /* MBEDTLS_SSL_TLS_C */ + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) + if( use_ret == -(MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "X509 - Unavailable feature, e.g. RSA hashing/encryption combination" ); + if( use_ret == -(MBEDTLS_ERR_X509_UNKNOWN_OID) ) + mbedtls_snprintf( buf, buflen, "X509 - Requested OID is unknown" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "X509 - The CRT/CRL/CSR format is invalid, e.g. different type expected" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_VERSION) ) + mbedtls_snprintf( buf, buflen, "X509 - The CRT/CRL/CSR version element is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_SERIAL) ) + mbedtls_snprintf( buf, buflen, "X509 - The serial tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_ALG) ) + mbedtls_snprintf( buf, buflen, "X509 - The algorithm tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_NAME) ) + mbedtls_snprintf( buf, buflen, "X509 - The name tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_DATE) ) + mbedtls_snprintf( buf, buflen, "X509 - The date tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_SIGNATURE) ) + mbedtls_snprintf( buf, buflen, "X509 - The signature tag or value invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_EXTENSIONS) ) + mbedtls_snprintf( buf, buflen, "X509 - The extension tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_UNKNOWN_VERSION) ) + mbedtls_snprintf( buf, buflen, "X509 - CRT/CRL/CSR has an unsupported version number" ); + if( use_ret == -(MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG) ) + mbedtls_snprintf( buf, buflen, "X509 - Signature algorithm (oid) is unsupported" ); + if( use_ret == -(MBEDTLS_ERR_X509_SIG_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "X509 - Signature algorithms do not match. (see \\c ::mbedtls_x509_crt sig_oid)" ); + if( use_ret == -(MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "X509 - Certificate verification failed, e.g. CRL, CA or signature check failed" ); + if( use_ret == -(MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT) ) + mbedtls_snprintf( buf, buflen, "X509 - Format not recognized as DER or PEM" ); + if( use_ret == -(MBEDTLS_ERR_X509_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "X509 - Input invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "X509 - Allocation of memory failed" ); + if( use_ret == -(MBEDTLS_ERR_X509_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "X509 - Read/write of file failed" ); + if( use_ret == -(MBEDTLS_ERR_X509_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "X509 - Destination buffer is too small" ); + if( use_ret == -(MBEDTLS_ERR_X509_FATAL_ERROR) ) + mbedtls_snprintf( buf, buflen, "X509 - A fatal error occurred, eg the chain is too long or the vrfy callback failed" ); +#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */ + // END generated code + + if( strlen( buf ) == 0 ) + mbedtls_snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret ); + } + + use_ret = ret & ~0xFF80; + + if( use_ret == 0 ) + return; + + // If high level code is present, make a concatenation between both + // error strings. + // + len = strlen( buf ); + + if( len > 0 ) + { + if( buflen - len < 5 ) + return; + + mbedtls_snprintf( buf + len, buflen - len, " : " ); + + buf += len + 3; + buflen -= len + 3; + } + + // Low level error codes + // + // BEGIN generated code +#if defined(MBEDTLS_AES_C) + if( use_ret == -(MBEDTLS_ERR_AES_INVALID_KEY_LENGTH) ) + mbedtls_snprintf( buf, buflen, "AES - Invalid key length" ); + if( use_ret == -(MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "AES - Invalid data input length" ); + if( use_ret == -(MBEDTLS_ERR_AES_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "AES - Invalid input data" ); + if( use_ret == -(MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "AES - Feature not available. For example, an unsupported AES key size" ); + if( use_ret == -(MBEDTLS_ERR_AES_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "AES - AES hardware accelerator failed" ); +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_ARC4_C) + if( use_ret == -(MBEDTLS_ERR_ARC4_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "ARC4 - ARC4 hardware accelerator failed" ); +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_ARIA_C) + if( use_ret == -(MBEDTLS_ERR_ARIA_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "ARIA - Bad input data" ); + if( use_ret == -(MBEDTLS_ERR_ARIA_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "ARIA - Invalid data input length" ); + if( use_ret == -(MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "ARIA - Feature not available. For example, an unsupported ARIA key size" ); + if( use_ret == -(MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "ARIA - ARIA hardware accelerator failed" ); +#endif /* MBEDTLS_ARIA_C */ + +#if defined(MBEDTLS_ASN1_PARSE_C) + if( use_ret == -(MBEDTLS_ERR_ASN1_OUT_OF_DATA) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Out of data when parsing an ASN1 data structure" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) ) + mbedtls_snprintf( buf, buflen, "ASN1 - ASN1 tag was of an unexpected value" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_INVALID_LENGTH) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Error when trying to determine the length or invalid length" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_LENGTH_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Actual length differs from expected length" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_INVALID_DATA) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Data is invalid. (not used)" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_BUF_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Buffer too small when writing ASN.1 data structure" ); +#endif /* MBEDTLS_ASN1_PARSE_C */ + +#if defined(MBEDTLS_BASE64_C) + if( use_ret == -(MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "BASE64 - Output buffer too small" ); + if( use_ret == -(MBEDTLS_ERR_BASE64_INVALID_CHARACTER) ) + mbedtls_snprintf( buf, buflen, "BASE64 - Invalid character in input" ); +#endif /* MBEDTLS_BASE64_C */ + +#if defined(MBEDTLS_BIGNUM_C) + if( use_ret == -(MBEDTLS_ERR_MPI_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - An error occurred while reading from or writing to a file" ); + if( use_ret == -(MBEDTLS_ERR_MPI_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_MPI_INVALID_CHARACTER) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - There is an invalid character in the digit string" ); + if( use_ret == -(MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The buffer is too small to write to" ); + if( use_ret == -(MBEDTLS_ERR_MPI_NEGATIVE_VALUE) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The input arguments are negative or result in illegal output" ); + if( use_ret == -(MBEDTLS_ERR_MPI_DIVISION_BY_ZERO) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The input argument for division is zero, which is not allowed" ); + if( use_ret == -(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The input arguments are not acceptable" ); + if( use_ret == -(MBEDTLS_ERR_MPI_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - Memory allocation failed" ); +#endif /* MBEDTLS_BIGNUM_C */ + +#if defined(MBEDTLS_BLOWFISH_C) + if( use_ret == -(MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "BLOWFISH - Bad input data" ); + if( use_ret == -(MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "BLOWFISH - Invalid data input length" ); + if( use_ret == -(MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "BLOWFISH - Blowfish hardware accelerator failed" ); +#endif /* MBEDTLS_BLOWFISH_C */ + +#if defined(MBEDTLS_CAMELLIA_C) + if( use_ret == -(MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "CAMELLIA - Bad input data" ); + if( use_ret == -(MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "CAMELLIA - Invalid data input length" ); + if( use_ret == -(MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "CAMELLIA - Camellia hardware accelerator failed" ); +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_CCM_C) + if( use_ret == -(MBEDTLS_ERR_CCM_BAD_INPUT) ) + mbedtls_snprintf( buf, buflen, "CCM - Bad input parameters to the function" ); + if( use_ret == -(MBEDTLS_ERR_CCM_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "CCM - Authenticated decryption failed" ); + if( use_ret == -(MBEDTLS_ERR_CCM_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "CCM - CCM hardware accelerator failed" ); +#endif /* MBEDTLS_CCM_C */ + +#if defined(MBEDTLS_CHACHA20_C) + if( use_ret == -(MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "CHACHA20 - Invalid input parameter(s)" ); + if( use_ret == -(MBEDTLS_ERR_CHACHA20_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "CHACHA20 - Feature not available. For example, s part of the API is not implemented" ); + if( use_ret == -(MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "CHACHA20 - Chacha20 hardware accelerator failed" ); +#endif /* MBEDTLS_CHACHA20_C */ + +#if defined(MBEDTLS_CHACHAPOLY_C) + if( use_ret == -(MBEDTLS_ERR_CHACHAPOLY_BAD_STATE) ) + mbedtls_snprintf( buf, buflen, "CHACHAPOLY - The requested operation is not permitted in the current state" ); + if( use_ret == -(MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "CHACHAPOLY - Authenticated decryption failed: data was not authentic" ); +#endif /* MBEDTLS_CHACHAPOLY_C */ + +#if defined(MBEDTLS_CMAC_C) + if( use_ret == -(MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "CMAC - CMAC hardware accelerator failed" ); +#endif /* MBEDTLS_CMAC_C */ + +#if defined(MBEDTLS_CTR_DRBG_C) + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - The entropy source failed" ); + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - The requested random buffer length is too big" ); + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - The input (entropy + additional data) is too large" ); + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - Read or write error in file" ); +#endif /* MBEDTLS_CTR_DRBG_C */ + +#if defined(MBEDTLS_DES_C) + if( use_ret == -(MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "DES - The data input has an invalid length" ); + if( use_ret == -(MBEDTLS_ERR_DES_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "DES - DES hardware accelerator failed" ); +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ENTROPY_C) + if( use_ret == -(MBEDTLS_ERR_ENTROPY_SOURCE_FAILED) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - Critical entropy source failure" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_MAX_SOURCES) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - No more sources can be added" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - No sources have been added to poll" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - No strong sources have been added to poll" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - Read/write error in file" ); +#endif /* MBEDTLS_ENTROPY_C */ + +#if defined(MBEDTLS_GCM_C) + if( use_ret == -(MBEDTLS_ERR_GCM_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "GCM - Authenticated decryption failed" ); + if( use_ret == -(MBEDTLS_ERR_GCM_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "GCM - GCM hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_GCM_BAD_INPUT) ) + mbedtls_snprintf( buf, buflen, "GCM - Bad input parameters to function" ); +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_HKDF_C) + if( use_ret == -(MBEDTLS_ERR_HKDF_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "HKDF - Bad input parameters to function" ); +#endif /* MBEDTLS_HKDF_C */ + +#if defined(MBEDTLS_HMAC_DRBG_C) + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Too many random requested in single call" ); + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Input too large (Entropy + additional)" ); + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Read/write error in file" ); + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - The entropy source failed" ); +#endif /* MBEDTLS_HMAC_DRBG_C */ + +#if defined(MBEDTLS_MD2_C) + if( use_ret == -(MBEDTLS_ERR_MD2_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "MD2 - MD2 hardware accelerator failed" ); +#endif /* MBEDTLS_MD2_C */ + +#if defined(MBEDTLS_MD4_C) + if( use_ret == -(MBEDTLS_ERR_MD4_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "MD4 - MD4 hardware accelerator failed" ); +#endif /* MBEDTLS_MD4_C */ + +#if defined(MBEDTLS_MD5_C) + if( use_ret == -(MBEDTLS_ERR_MD5_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "MD5 - MD5 hardware accelerator failed" ); +#endif /* MBEDTLS_MD5_C */ + +#if defined(MBEDTLS_OID_C) + if( use_ret == -(MBEDTLS_ERR_OID_NOT_FOUND) ) + mbedtls_snprintf( buf, buflen, "OID - OID is not found" ); + if( use_ret == -(MBEDTLS_ERR_OID_BUF_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "OID - output buffer is too small" ); +#endif /* MBEDTLS_OID_C */ + +#if defined(MBEDTLS_PADLOCK_C) + if( use_ret == -(MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED) ) + mbedtls_snprintf( buf, buflen, "PADLOCK - Input data should be aligned" ); +#endif /* MBEDTLS_PADLOCK_C */ + +#if defined(MBEDTLS_PLATFORM_C) + if( use_ret == -(MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "PLATFORM - Hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED) ) + mbedtls_snprintf( buf, buflen, "PLATFORM - The requested feature is not supported by the platform" ); +#endif /* MBEDTLS_PLATFORM_C */ + +#if defined(MBEDTLS_POLY1305_C) + if( use_ret == -(MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "POLY1305 - Invalid input parameter(s)" ); + if( use_ret == -(MBEDTLS_ERR_POLY1305_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "POLY1305 - Feature not available. For example, s part of the API is not implemented" ); + if( use_ret == -(MBEDTLS_ERR_POLY1305_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "POLY1305 - Poly1305 hardware accelerator failed" ); +#endif /* MBEDTLS_POLY1305_C */ + +#if defined(MBEDTLS_RIPEMD160_C) + if( use_ret == -(MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "RIPEMD160 - RIPEMD160 hardware accelerator failed" ); +#endif /* MBEDTLS_RIPEMD160_C */ + +#if defined(MBEDTLS_SHA1_C) + if( use_ret == -(MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "SHA1 - SHA-1 hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_SHA1_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "SHA1 - SHA-1 input data was malformed" ); +#endif /* MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) + if( use_ret == -(MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "SHA256 - SHA-256 hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_SHA256_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "SHA256 - SHA-256 input data was malformed" ); +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + if( use_ret == -(MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "SHA512 - SHA-512 hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_SHA512_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "SHA512 - SHA-512 input data was malformed" ); +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_THREADING_C) + if( use_ret == -(MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "THREADING - The selected feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_THREADING_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "THREADING - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_THREADING_MUTEX_ERROR) ) + mbedtls_snprintf( buf, buflen, "THREADING - Locking / unlocking / free failed with error code" ); +#endif /* MBEDTLS_THREADING_C */ + +#if defined(MBEDTLS_XTEA_C) + if( use_ret == -(MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "XTEA - The data input has an invalid length" ); + if( use_ret == -(MBEDTLS_ERR_XTEA_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "XTEA - XTEA hardware accelerator failed" ); +#endif /* MBEDTLS_XTEA_C */ + +#if defined(MBEDTLS_NET_C) + if( use_ret == -(MBEDTLS_ERR_NET_SOCKET_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Failed to open a socket" ); + if( use_ret == -(MBEDTLS_ERR_NET_CONNECT_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - The connection to the given server / port failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_BIND_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Binding of the socket failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_LISTEN_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Could not listen on the socket" ); + if( use_ret == -(MBEDTLS_ERR_NET_ACCEPT_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Could not accept the incoming connection" ); + if( use_ret == -(MBEDTLS_ERR_NET_RECV_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Reading information from the socket failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_SEND_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Sending information through the socket failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_CONN_RESET) ) + mbedtls_snprintf( buf, buflen, "NET - Connection was reset by peer" ); + if( use_ret == -(MBEDTLS_ERR_NET_UNKNOWN_HOST) ) + mbedtls_snprintf( buf, buflen, "NET - Failed to get an IP address for the given hostname" ); + if( use_ret == -(MBEDTLS_ERR_NET_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "NET - Buffer is too small to hold the data" ); + if( use_ret == -(MBEDTLS_ERR_NET_INVALID_CONTEXT) ) + mbedtls_snprintf( buf, buflen, "NET - The context is invalid, eg because it was free()ed" ); + if( use_ret == -(MBEDTLS_ERR_NET_POLL_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Polling the net context failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "NET - Input invalid" ); +#endif /* MBEDTLS_NET_C */ + // END generated code + + if( strlen( buf ) != 0 ) + return; + + mbedtls_snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret ); +} + +#else /* MBEDTLS_ERROR_C */ + +#if defined(MBEDTLS_ERROR_STRERROR_DUMMY) + +/* + * Provide an non-function in case MBEDTLS_ERROR_C is not defined + */ +void mbedtls_strerror( int ret, char *buf, size_t buflen ) +{ + ((void) ret); + + if( buflen > 0 ) + buf[0] = '\0'; +} + +#endif /* MBEDTLS_ERROR_STRERROR_DUMMY */ + +#endif /* MBEDTLS_ERROR_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/gcm.c b/FreeRTOS-Labs/Source/mbedtls/library/gcm.c new file mode 100644 index 000000000..5ca13e9c5 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/gcm.c @@ -0,0 +1,1020 @@ +/* + * NIST SP800-38D compliant GCM implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf + * + * See also: + * [MGV] http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf + * + * We use the algorithm described as Shoup's method with 4-bit tables in + * [MGV] 4.1, pp. 12-13, to enhance speed without using too much memory. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_GCM_C) + +#include "mbedtls/gcm.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_AESNI_C) +#include "mbedtls/aesni.h" +#endif + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +#include "mbedtls/aes.h" +#include "mbedtls/platform.h" +#if !defined(MBEDTLS_PLATFORM_C) +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#if !defined(MBEDTLS_GCM_ALT) + +/* Parameter validation macros */ +#define GCM_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_GCM_BAD_INPUT ) +#define GCM_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * Initialize a context + */ +void mbedtls_gcm_init( mbedtls_gcm_context *ctx ) +{ + GCM_VALIDATE( ctx != NULL ); + memset( ctx, 0, sizeof( mbedtls_gcm_context ) ); +} + +/* + * Precompute small multiples of H, that is set + * HH[i] || HL[i] = H times i, + * where i is seen as a field element as in [MGV], ie high-order bits + * correspond to low powers of P. The result is stored in the same way, that + * is the high-order bit of HH corresponds to P^0 and the low-order bit of HL + * corresponds to P^127. + */ +static int gcm_gen_table( mbedtls_gcm_context *ctx ) +{ + int ret, i, j; + uint64_t hi, lo; + uint64_t vl, vh; + unsigned char h[16]; + size_t olen = 0; + + memset( h, 0, 16 ); + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, h, 16, h, &olen ) ) != 0 ) + return( ret ); + + /* pack h as two 64-bits ints, big-endian */ + GET_UINT32_BE( hi, h, 0 ); + GET_UINT32_BE( lo, h, 4 ); + vh = (uint64_t) hi << 32 | lo; + + GET_UINT32_BE( hi, h, 8 ); + GET_UINT32_BE( lo, h, 12 ); + vl = (uint64_t) hi << 32 | lo; + + /* 8 = 1000 corresponds to 1 in GF(2^128) */ + ctx->HL[8] = vl; + ctx->HH[8] = vh; + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + /* With CLMUL support, we need only h, not the rest of the table */ + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_CLMUL ) ) + return( 0 ); +#endif + + /* 0 corresponds to 0 in GF(2^128) */ + ctx->HH[0] = 0; + ctx->HL[0] = 0; + + for( i = 4; i > 0; i >>= 1 ) + { + uint32_t T = ( vl & 1 ) * 0xe1000000U; + vl = ( vh << 63 ) | ( vl >> 1 ); + vh = ( vh >> 1 ) ^ ( (uint64_t) T << 32); + + ctx->HL[i] = vl; + ctx->HH[i] = vh; + } + + for( i = 2; i <= 8; i *= 2 ) + { + uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i; + vh = *HiH; + vl = *HiL; + for( j = 1; j < i; j++ ) + { + HiH[j] = vh ^ ctx->HH[j]; + HiL[j] = vl ^ ctx->HL[j]; + } + } + + return( 0 ); +} + +int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ) +{ + int ret; + const mbedtls_cipher_info_t *cipher_info; + + GCM_VALIDATE_RET( ctx != NULL ); + GCM_VALIDATE_RET( key != NULL ); + GCM_VALIDATE_RET( keybits == 128 || keybits == 192 || keybits == 256 ); + + cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, + MBEDTLS_MODE_ECB ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + + if( cipher_info->block_size != 16 ) + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + + mbedtls_cipher_free( &ctx->cipher_ctx ); + + if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits, + MBEDTLS_ENCRYPT ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = gcm_gen_table( ctx ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Shoup's method for multiplication use this table with + * last4[x] = x times P^128 + * where x and last4[x] are seen as elements of GF(2^128) as in [MGV] + */ +static const uint64_t last4[16] = +{ + 0x0000, 0x1c20, 0x3840, 0x2460, + 0x7080, 0x6ca0, 0x48c0, 0x54e0, + 0xe100, 0xfd20, 0xd940, 0xc560, + 0x9180, 0x8da0, 0xa9c0, 0xb5e0 +}; + +/* + * Sets output to x times H using the precomputed tables. + * x and output are seen as elements of GF(2^128) as in [MGV]. + */ +static void gcm_mult( mbedtls_gcm_context *ctx, const unsigned char x[16], + unsigned char output[16] ) +{ + int i = 0; + unsigned char lo, hi, rem; + uint64_t zh, zl; + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_CLMUL ) ) { + unsigned char h[16]; + + PUT_UINT32_BE( ctx->HH[8] >> 32, h, 0 ); + PUT_UINT32_BE( ctx->HH[8], h, 4 ); + PUT_UINT32_BE( ctx->HL[8] >> 32, h, 8 ); + PUT_UINT32_BE( ctx->HL[8], h, 12 ); + + mbedtls_aesni_gcm_mult( output, x, h ); + return; + } +#endif /* MBEDTLS_AESNI_C && MBEDTLS_HAVE_X86_64 */ + + lo = x[15] & 0xf; + + zh = ctx->HH[lo]; + zl = ctx->HL[lo]; + + for( i = 15; i >= 0; i-- ) + { + lo = x[i] & 0xf; + hi = x[i] >> 4; + + if( i != 15 ) + { + rem = (unsigned char) zl & 0xf; + zl = ( zh << 60 ) | ( zl >> 4 ); + zh = ( zh >> 4 ); + zh ^= (uint64_t) last4[rem] << 48; + zh ^= ctx->HH[lo]; + zl ^= ctx->HL[lo]; + + } + + rem = (unsigned char) zl & 0xf; + zl = ( zh << 60 ) | ( zl >> 4 ); + zh = ( zh >> 4 ); + zh ^= (uint64_t) last4[rem] << 48; + zh ^= ctx->HH[hi]; + zl ^= ctx->HL[hi]; + } + + PUT_UINT32_BE( zh >> 32, output, 0 ); + PUT_UINT32_BE( zh, output, 4 ); + PUT_UINT32_BE( zl >> 32, output, 8 ); + PUT_UINT32_BE( zl, output, 12 ); +} + +int mbedtls_gcm_starts( mbedtls_gcm_context *ctx, + int mode, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len ) +{ + int ret; + unsigned char work_buf[16]; + size_t i; + const unsigned char *p; + size_t use_len, olen = 0; + + GCM_VALIDATE_RET( ctx != NULL ); + GCM_VALIDATE_RET( iv != NULL ); + GCM_VALIDATE_RET( add_len == 0 || add != NULL ); + + /* IV and AD are limited to 2^64 bits, so 2^61 bytes */ + /* IV is not allowed to be zero length */ + if( iv_len == 0 || + ( (uint64_t) iv_len ) >> 61 != 0 || + ( (uint64_t) add_len ) >> 61 != 0 ) + { + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + } + + memset( ctx->y, 0x00, sizeof(ctx->y) ); + memset( ctx->buf, 0x00, sizeof(ctx->buf) ); + + ctx->mode = mode; + ctx->len = 0; + ctx->add_len = 0; + + if( iv_len == 12 ) + { + memcpy( ctx->y, iv, iv_len ); + ctx->y[15] = 1; + } + else + { + memset( work_buf, 0x00, 16 ); + PUT_UINT32_BE( iv_len * 8, work_buf, 12 ); + + p = iv; + while( iv_len > 0 ) + { + use_len = ( iv_len < 16 ) ? iv_len : 16; + + for( i = 0; i < use_len; i++ ) + ctx->y[i] ^= p[i]; + + gcm_mult( ctx, ctx->y, ctx->y ); + + iv_len -= use_len; + p += use_len; + } + + for( i = 0; i < 16; i++ ) + ctx->y[i] ^= work_buf[i]; + + gcm_mult( ctx, ctx->y, ctx->y ); + } + + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, + ctx->base_ectr, &olen ) ) != 0 ) + { + return( ret ); + } + + ctx->add_len = add_len; + p = add; + while( add_len > 0 ) + { + use_len = ( add_len < 16 ) ? add_len : 16; + + for( i = 0; i < use_len; i++ ) + ctx->buf[i] ^= p[i]; + + gcm_mult( ctx, ctx->buf, ctx->buf ); + + add_len -= use_len; + p += use_len; + } + + return( 0 ); +} + +int mbedtls_gcm_update( mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + unsigned char ectr[16]; + size_t i; + const unsigned char *p; + unsigned char *out_p = output; + size_t use_len, olen = 0; + + GCM_VALIDATE_RET( ctx != NULL ); + GCM_VALIDATE_RET( length == 0 || input != NULL ); + GCM_VALIDATE_RET( length == 0 || output != NULL ); + + if( output > input && (size_t) ( output - input ) < length ) + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + + /* Total length is restricted to 2^39 - 256 bits, ie 2^36 - 2^5 bytes + * Also check for possible overflow */ + if( ctx->len + length < ctx->len || + (uint64_t) ctx->len + length > 0xFFFFFFFE0ull ) + { + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + } + + ctx->len += length; + + p = input; + while( length > 0 ) + { + use_len = ( length < 16 ) ? length : 16; + + for( i = 16; i > 12; i-- ) + if( ++ctx->y[i - 1] != 0 ) + break; + + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ectr, + &olen ) ) != 0 ) + { + return( ret ); + } + + for( i = 0; i < use_len; i++ ) + { + if( ctx->mode == MBEDTLS_GCM_DECRYPT ) + ctx->buf[i] ^= p[i]; + out_p[i] = ectr[i] ^ p[i]; + if( ctx->mode == MBEDTLS_GCM_ENCRYPT ) + ctx->buf[i] ^= out_p[i]; + } + + gcm_mult( ctx, ctx->buf, ctx->buf ); + + length -= use_len; + p += use_len; + out_p += use_len; + } + + return( 0 ); +} + +int mbedtls_gcm_finish( mbedtls_gcm_context *ctx, + unsigned char *tag, + size_t tag_len ) +{ + unsigned char work_buf[16]; + size_t i; + uint64_t orig_len; + uint64_t orig_add_len; + + GCM_VALIDATE_RET( ctx != NULL ); + GCM_VALIDATE_RET( tag != NULL ); + + orig_len = ctx->len * 8; + orig_add_len = ctx->add_len * 8; + + if( tag_len > 16 || tag_len < 4 ) + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + + memcpy( tag, ctx->base_ectr, tag_len ); + + if( orig_len || orig_add_len ) + { + memset( work_buf, 0x00, 16 ); + + PUT_UINT32_BE( ( orig_add_len >> 32 ), work_buf, 0 ); + PUT_UINT32_BE( ( orig_add_len ), work_buf, 4 ); + PUT_UINT32_BE( ( orig_len >> 32 ), work_buf, 8 ); + PUT_UINT32_BE( ( orig_len ), work_buf, 12 ); + + for( i = 0; i < 16; i++ ) + ctx->buf[i] ^= work_buf[i]; + + gcm_mult( ctx, ctx->buf, ctx->buf ); + + for( i = 0; i < tag_len; i++ ) + tag[i] ^= ctx->buf[i]; + } + + return( 0 ); +} + +int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx, + int mode, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *input, + unsigned char *output, + size_t tag_len, + unsigned char *tag ) +{ + int ret; + + GCM_VALIDATE_RET( ctx != NULL ); + GCM_VALIDATE_RET( iv != NULL ); + GCM_VALIDATE_RET( add_len == 0 || add != NULL ); + GCM_VALIDATE_RET( length == 0 || input != NULL ); + GCM_VALIDATE_RET( length == 0 || output != NULL ); + GCM_VALIDATE_RET( tag != NULL ); + + if( ( ret = mbedtls_gcm_starts( ctx, mode, iv, iv_len, add, add_len ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_gcm_update( ctx, length, input, output ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_gcm_finish( ctx, tag, tag_len ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *tag, + size_t tag_len, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + unsigned char check_tag[16]; + size_t i; + int diff; + + GCM_VALIDATE_RET( ctx != NULL ); + GCM_VALIDATE_RET( iv != NULL ); + GCM_VALIDATE_RET( add_len == 0 || add != NULL ); + GCM_VALIDATE_RET( tag != NULL ); + GCM_VALIDATE_RET( length == 0 || input != NULL ); + GCM_VALIDATE_RET( length == 0 || output != NULL ); + + if( ( ret = mbedtls_gcm_crypt_and_tag( ctx, MBEDTLS_GCM_DECRYPT, length, + iv, iv_len, add, add_len, + input, output, tag_len, check_tag ) ) != 0 ) + { + return( ret ); + } + + /* Check tag in "constant-time" */ + for( diff = 0, i = 0; i < tag_len; i++ ) + diff |= tag[i] ^ check_tag[i]; + + if( diff != 0 ) + { + mbedtls_platform_zeroize( output, length ); + return( MBEDTLS_ERR_GCM_AUTH_FAILED ); + } + + return( 0 ); +} + +void mbedtls_gcm_free( mbedtls_gcm_context *ctx ) +{ + if( ctx == NULL ) + return; + mbedtls_cipher_free( &ctx->cipher_ctx ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_gcm_context ) ); +} + +#endif /* !MBEDTLS_GCM_ALT */ + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/* + * AES-GCM test vectors from: + * + * http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip + */ +#define MAX_TESTS 6 + +static const int key_index_test_data[MAX_TESTS] = + { 0, 0, 1, 1, 1, 1 }; + +static const unsigned char key_test_data[MAX_TESTS][32] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, +}; + +static const size_t iv_len_test_data[MAX_TESTS] = + { 12, 12, 12, 12, 8, 60 }; + +static const int iv_index_test_data[MAX_TESTS] = + { 0, 0, 1, 1, 1, 2 }; + +static const unsigned char iv_test_data[MAX_TESTS][64] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + { 0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5, + 0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa, + 0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1, + 0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28, + 0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39, + 0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54, + 0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57, + 0xa6, 0x37, 0xb3, 0x9b }, +}; + +static const size_t add_len_test_data[MAX_TESTS] = + { 0, 0, 0, 20, 20, 20 }; + +static const int add_index_test_data[MAX_TESTS] = + { 0, 0, 0, 1, 1, 1 }; + +static const unsigned char additional_test_data[MAX_TESTS][64] = +{ + { 0x00 }, + { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xab, 0xad, 0xda, 0xd2 }, +}; + +static const size_t pt_len_test_data[MAX_TESTS] = + { 0, 16, 64, 60, 60, 60 }; + +static const int pt_index_test_data[MAX_TESTS] = + { 0, 0, 1, 1, 1, 1 }; + +static const unsigned char pt_test_data[MAX_TESTS][64] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }, +}; + +static const unsigned char ct_test_data[MAX_TESTS * 3][64] = +{ + { 0x00 }, + { 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, + 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78 }, + { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85 }, + { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91 }, + { 0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a, + 0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a, 0x47, 0x55, + 0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8, + 0x37, 0x66, 0xe5, 0xf9, 0x7b, 0x6c, 0x74, 0x23, + 0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2, + 0x2b, 0x09, 0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42, + 0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07, + 0xc2, 0x3f, 0x45, 0x98 }, + { 0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6, + 0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f, 0xb8, 0x94, + 0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8, + 0xba, 0x26, 0x2a, 0x3c, 0xca, 0x7e, 0x2c, 0xa7, + 0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90, + 0xcc, 0xdc, 0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f, + 0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03, + 0x4c, 0x34, 0xae, 0xe5 }, + { 0x00 }, + { 0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41, + 0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00 }, + { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, + 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, + 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, + 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, + 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, + 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, + 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, + 0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56 }, + { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, + 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, + 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, + 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, + 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, + 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, + 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, + 0xcc, 0xda, 0x27, 0x10 }, + { 0x0f, 0x10, 0xf5, 0x99, 0xae, 0x14, 0xa1, 0x54, + 0xed, 0x24, 0xb3, 0x6e, 0x25, 0x32, 0x4d, 0xb8, + 0xc5, 0x66, 0x63, 0x2e, 0xf2, 0xbb, 0xb3, 0x4f, + 0x83, 0x47, 0x28, 0x0f, 0xc4, 0x50, 0x70, 0x57, + 0xfd, 0xdc, 0x29, 0xdf, 0x9a, 0x47, 0x1f, 0x75, + 0xc6, 0x65, 0x41, 0xd4, 0xd4, 0xda, 0xd1, 0xc9, + 0xe9, 0x3a, 0x19, 0xa5, 0x8e, 0x8b, 0x47, 0x3f, + 0xa0, 0xf0, 0x62, 0xf7 }, + { 0xd2, 0x7e, 0x88, 0x68, 0x1c, 0xe3, 0x24, 0x3c, + 0x48, 0x30, 0x16, 0x5a, 0x8f, 0xdc, 0xf9, 0xff, + 0x1d, 0xe9, 0xa1, 0xd8, 0xe6, 0xb4, 0x47, 0xef, + 0x6e, 0xf7, 0xb7, 0x98, 0x28, 0x66, 0x6e, 0x45, + 0x81, 0xe7, 0x90, 0x12, 0xaf, 0x34, 0xdd, 0xd9, + 0xe2, 0xf0, 0x37, 0x58, 0x9b, 0x29, 0x2d, 0xb3, + 0xe6, 0x7c, 0x03, 0x67, 0x45, 0xfa, 0x22, 0xe7, + 0xe9, 0xb7, 0x37, 0x3b }, + { 0x00 }, + { 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, + 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18 }, + { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad }, + { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62 }, + { 0xc3, 0x76, 0x2d, 0xf1, 0xca, 0x78, 0x7d, 0x32, + 0xae, 0x47, 0xc1, 0x3b, 0xf1, 0x98, 0x44, 0xcb, + 0xaf, 0x1a, 0xe1, 0x4d, 0x0b, 0x97, 0x6a, 0xfa, + 0xc5, 0x2f, 0xf7, 0xd7, 0x9b, 0xba, 0x9d, 0xe0, + 0xfe, 0xb5, 0x82, 0xd3, 0x39, 0x34, 0xa4, 0xf0, + 0x95, 0x4c, 0xc2, 0x36, 0x3b, 0xc7, 0x3f, 0x78, + 0x62, 0xac, 0x43, 0x0e, 0x64, 0xab, 0xe4, 0x99, + 0xf4, 0x7c, 0x9b, 0x1f }, + { 0x5a, 0x8d, 0xef, 0x2f, 0x0c, 0x9e, 0x53, 0xf1, + 0xf7, 0x5d, 0x78, 0x53, 0x65, 0x9e, 0x2a, 0x20, + 0xee, 0xb2, 0xb2, 0x2a, 0xaf, 0xde, 0x64, 0x19, + 0xa0, 0x58, 0xab, 0x4f, 0x6f, 0x74, 0x6b, 0xf4, + 0x0f, 0xc0, 0xc3, 0xb7, 0x80, 0xf2, 0x44, 0x45, + 0x2d, 0xa3, 0xeb, 0xf1, 0xc5, 0xd8, 0x2c, 0xde, + 0xa2, 0x41, 0x89, 0x97, 0x20, 0x0e, 0xf8, 0x2e, + 0x44, 0xae, 0x7e, 0x3f }, +}; + +static const unsigned char tag_test_data[MAX_TESTS * 3][16] = +{ + { 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61, + 0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a }, + { 0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd, + 0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf }, + { 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, + 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 }, + { 0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb, + 0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47 }, + { 0x36, 0x12, 0xd2, 0xe7, 0x9e, 0x3b, 0x07, 0x85, + 0x56, 0x1b, 0xe1, 0x4a, 0xac, 0xa2, 0xfc, 0xcb }, + { 0x61, 0x9c, 0xc5, 0xae, 0xff, 0xfe, 0x0b, 0xfa, + 0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99, 0xd0, 0x50 }, + { 0xcd, 0x33, 0xb2, 0x8a, 0xc7, 0x73, 0xf7, 0x4b, + 0xa0, 0x0e, 0xd1, 0xf3, 0x12, 0x57, 0x24, 0x35 }, + { 0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab, + 0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb }, + { 0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf, + 0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14 }, + { 0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f, + 0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c }, + { 0x65, 0xdc, 0xc5, 0x7f, 0xcf, 0x62, 0x3a, 0x24, + 0x09, 0x4f, 0xcc, 0xa4, 0x0d, 0x35, 0x33, 0xf8 }, + { 0xdc, 0xf5, 0x66, 0xff, 0x29, 0x1c, 0x25, 0xbb, + 0xb8, 0x56, 0x8f, 0xc3, 0xd3, 0x76, 0xa6, 0xd9 }, + { 0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9, + 0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, 0x73, 0x8b }, + { 0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0, + 0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19 }, + { 0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd, + 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c }, + { 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, + 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b }, + { 0x3a, 0x33, 0x7d, 0xbf, 0x46, 0xa7, 0x92, 0xc4, + 0x5e, 0x45, 0x49, 0x13, 0xfe, 0x2e, 0xa8, 0xf2 }, + { 0xa4, 0x4a, 0x82, 0x66, 0xee, 0x1c, 0x8e, 0xb0, + 0xc8, 0xb5, 0xd4, 0xcf, 0x5a, 0xe9, 0xf1, 0x9a }, +}; + +int mbedtls_gcm_self_test( int verbose ) +{ + mbedtls_gcm_context ctx; + unsigned char buf[64]; + unsigned char tag_buf[16]; + int i, j, ret; + mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES; + + for( j = 0; j < 3; j++ ) + { + int key_len = 128 + 64 * j; + + for( i = 0; i < MAX_TESTS; i++ ) + { + mbedtls_gcm_init( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d (%s): ", + key_len, i, "enc" ); + + ret = mbedtls_gcm_setkey( &ctx, cipher, + key_test_data[key_index_test_data[i]], + key_len ); + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation i.e. when + * MBEDTLS_AES_ALT is defined. + */ + if( ret == MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED && key_len == 192 ) + { + mbedtls_printf( "skipped\n" ); + break; + } + else if( ret != 0 ) + { + goto exit; + } + + ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_ENCRYPT, + pt_len_test_data[i], + iv_test_data[iv_index_test_data[i]], + iv_len_test_data[i], + additional_test_data[add_index_test_data[i]], + add_len_test_data[i], + pt_test_data[pt_index_test_data[i]], + buf, 16, tag_buf ); + if( ret != 0 ) + goto exit; + + if ( memcmp( buf, ct_test_data[j * 6 + i], + pt_len_test_data[i] ) != 0 || + memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 ) + { + ret = 1; + goto exit; + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + mbedtls_gcm_init( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d (%s): ", + key_len, i, "dec" ); + + ret = mbedtls_gcm_setkey( &ctx, cipher, + key_test_data[key_index_test_data[i]], + key_len ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_DECRYPT, + pt_len_test_data[i], + iv_test_data[iv_index_test_data[i]], + iv_len_test_data[i], + additional_test_data[add_index_test_data[i]], + add_len_test_data[i], + ct_test_data[j * 6 + i], buf, 16, tag_buf ); + + if( ret != 0 ) + goto exit; + + if( memcmp( buf, pt_test_data[pt_index_test_data[i]], + pt_len_test_data[i] ) != 0 || + memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 ) + { + ret = 1; + goto exit; + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + mbedtls_gcm_init( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d split (%s): ", + key_len, i, "enc" ); + + ret = mbedtls_gcm_setkey( &ctx, cipher, + key_test_data[key_index_test_data[i]], + key_len ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_ENCRYPT, + iv_test_data[iv_index_test_data[i]], + iv_len_test_data[i], + additional_test_data[add_index_test_data[i]], + add_len_test_data[i] ); + if( ret != 0 ) + goto exit; + + if( pt_len_test_data[i] > 32 ) + { + size_t rest_len = pt_len_test_data[i] - 32; + ret = mbedtls_gcm_update( &ctx, 32, + pt_test_data[pt_index_test_data[i]], + buf ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_gcm_update( &ctx, rest_len, + pt_test_data[pt_index_test_data[i]] + 32, + buf + 32 ); + if( ret != 0 ) + goto exit; + } + else + { + ret = mbedtls_gcm_update( &ctx, pt_len_test_data[i], + pt_test_data[pt_index_test_data[i]], + buf ); + if( ret != 0 ) + goto exit; + } + + ret = mbedtls_gcm_finish( &ctx, tag_buf, 16 ); + if( ret != 0 ) + goto exit; + + if( memcmp( buf, ct_test_data[j * 6 + i], + pt_len_test_data[i] ) != 0 || + memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 ) + { + ret = 1; + goto exit; + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + mbedtls_gcm_init( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d split (%s): ", + key_len, i, "dec" ); + + ret = mbedtls_gcm_setkey( &ctx, cipher, + key_test_data[key_index_test_data[i]], + key_len ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_DECRYPT, + iv_test_data[iv_index_test_data[i]], + iv_len_test_data[i], + additional_test_data[add_index_test_data[i]], + add_len_test_data[i] ); + if( ret != 0 ) + goto exit; + + if( pt_len_test_data[i] > 32 ) + { + size_t rest_len = pt_len_test_data[i] - 32; + ret = mbedtls_gcm_update( &ctx, 32, ct_test_data[j * 6 + i], + buf ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_gcm_update( &ctx, rest_len, + ct_test_data[j * 6 + i] + 32, + buf + 32 ); + if( ret != 0 ) + goto exit; + } + else + { + ret = mbedtls_gcm_update( &ctx, pt_len_test_data[i], + ct_test_data[j * 6 + i], + buf ); + if( ret != 0 ) + goto exit; + } + + ret = mbedtls_gcm_finish( &ctx, tag_buf, 16 ); + if( ret != 0 ) + goto exit; + + if( memcmp( buf, pt_test_data[pt_index_test_data[i]], + pt_len_test_data[i] ) != 0 || + memcmp( tag_buf, tag_test_data[j * 6 + i], 16 ) != 0 ) + { + ret = 1; + goto exit; + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + ret = 0; + +exit: + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + mbedtls_gcm_free( &ctx ); + } + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#endif /* MBEDTLS_GCM_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/havege.c b/FreeRTOS-Labs/Source/mbedtls/library/havege.c new file mode 100644 index 000000000..a2c98ca29 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/havege.c @@ -0,0 +1,241 @@ +/** + * \brief HAVEGE: HArdware Volatile Entropy Gathering and Expansion + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The HAVEGE RNG was designed by Andre Seznec in 2002. + * + * http://www.irisa.fr/caps/projects/hipsor/publi.php + * + * Contact: seznec(at)irisa_dot_fr - orocheco(at)irisa_dot_fr + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_HAVEGE_C) + +#include "mbedtls/havege.h" +#include "mbedtls/timing.h" +#include "mbedtls/platform_util.h" + +#include + +/* ------------------------------------------------------------------------ + * On average, one iteration accesses two 8-word blocks in the havege WALK + * table, and generates 16 words in the RES array. + * + * The data read in the WALK table is updated and permuted after each use. + * The result of the hardware clock counter read is used for this update. + * + * 25 conditional tests are present. The conditional tests are grouped in + * two nested groups of 12 conditional tests and 1 test that controls the + * permutation; on average, there should be 6 tests executed and 3 of them + * should be mispredicted. + * ------------------------------------------------------------------------ + */ + +#define SWAP(X,Y) { int *T = (X); (X) = (Y); (Y) = T; } + +#define TST1_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1; +#define TST2_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1; + +#define TST1_LEAVE U1++; } +#define TST2_LEAVE U2++; } + +#define ONE_ITERATION \ + \ + PTEST = PT1 >> 20; \ + \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + \ + PTX = (PT1 >> 18) & 7; \ + PT1 &= 0x1FFF; \ + PT2 &= 0x1FFF; \ + CLK = (int) mbedtls_timing_hardclock(); \ + \ + i = 0; \ + A = &WALK[PT1 ]; RES[i++] ^= *A; \ + B = &WALK[PT2 ]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 1]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 4]; RES[i++] ^= *D; \ + \ + IN = (*A >> (1)) ^ (*A << (31)) ^ CLK; \ + *A = (*B >> (2)) ^ (*B << (30)) ^ CLK; \ + *B = IN ^ U1; \ + *C = (*C >> (3)) ^ (*C << (29)) ^ CLK; \ + *D = (*D >> (4)) ^ (*D << (28)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 2]; RES[i++] ^= *A; \ + B = &WALK[PT2 ^ 2]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 3]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 6]; RES[i++] ^= *D; \ + \ + if( PTEST & 1 ) SWAP( A, C ); \ + \ + IN = (*A >> (5)) ^ (*A << (27)) ^ CLK; \ + *A = (*B >> (6)) ^ (*B << (26)) ^ CLK; \ + *B = IN; CLK = (int) mbedtls_timing_hardclock(); \ + *C = (*C >> (7)) ^ (*C << (25)) ^ CLK; \ + *D = (*D >> (8)) ^ (*D << (24)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 4]; \ + B = &WALK[PT2 ^ 1]; \ + \ + PTEST = PT2 >> 1; \ + \ + PT2 = (RES[(i - 8) ^ PTY] ^ WALK[PT2 ^ PTY ^ 7]); \ + PT2 = ((PT2 & 0x1FFF) & (~8)) ^ ((PT1 ^ 8) & 0x8); \ + PTY = (PT2 >> 10) & 7; \ + \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + \ + C = &WALK[PT1 ^ 5]; \ + D = &WALK[PT2 ^ 5]; \ + \ + RES[i++] ^= *A; \ + RES[i++] ^= *B; \ + RES[i++] ^= *C; \ + RES[i++] ^= *D; \ + \ + IN = (*A >> ( 9)) ^ (*A << (23)) ^ CLK; \ + *A = (*B >> (10)) ^ (*B << (22)) ^ CLK; \ + *B = IN ^ U2; \ + *C = (*C >> (11)) ^ (*C << (21)) ^ CLK; \ + *D = (*D >> (12)) ^ (*D << (20)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 6]; RES[i++] ^= *A; \ + B = &WALK[PT2 ^ 3]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 7]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 7]; RES[i++] ^= *D; \ + \ + IN = (*A >> (13)) ^ (*A << (19)) ^ CLK; \ + *A = (*B >> (14)) ^ (*B << (18)) ^ CLK; \ + *B = IN; \ + *C = (*C >> (15)) ^ (*C << (17)) ^ CLK; \ + *D = (*D >> (16)) ^ (*D << (16)) ^ CLK; \ + \ + PT1 = ( RES[( i - 8 ) ^ PTX] ^ \ + WALK[PT1 ^ PTX ^ 7] ) & (~1); \ + PT1 ^= (PT2 ^ 0x10) & 0x10; \ + \ + for( n++, i = 0; i < 16; i++ ) \ + hs->pool[n % MBEDTLS_HAVEGE_COLLECT_SIZE] ^= RES[i]; + +/* + * Entropy gathering function + */ +static void havege_fill( mbedtls_havege_state *hs ) +{ + int i, n = 0; + int U1, U2, *A, *B, *C, *D; + int PT1, PT2, *WALK, RES[16]; + int PTX, PTY, CLK, PTEST, IN; + + WALK = hs->WALK; + PT1 = hs->PT1; + PT2 = hs->PT2; + + PTX = U1 = 0; + PTY = U2 = 0; + + (void)PTX; + + memset( RES, 0, sizeof( RES ) ); + + while( n < MBEDTLS_HAVEGE_COLLECT_SIZE * 4 ) + { + ONE_ITERATION + ONE_ITERATION + ONE_ITERATION + ONE_ITERATION + } + + hs->PT1 = PT1; + hs->PT2 = PT2; + + hs->offset[0] = 0; + hs->offset[1] = MBEDTLS_HAVEGE_COLLECT_SIZE / 2; +} + +/* + * HAVEGE initialization + */ +void mbedtls_havege_init( mbedtls_havege_state *hs ) +{ + memset( hs, 0, sizeof( mbedtls_havege_state ) ); + + havege_fill( hs ); +} + +void mbedtls_havege_free( mbedtls_havege_state *hs ) +{ + if( hs == NULL ) + return; + + mbedtls_platform_zeroize( hs, sizeof( mbedtls_havege_state ) ); +} + +/* + * HAVEGE rand function + */ +int mbedtls_havege_random( void *p_rng, unsigned char *buf, size_t len ) +{ + int val; + size_t use_len; + mbedtls_havege_state *hs = (mbedtls_havege_state *) p_rng; + unsigned char *p = buf; + + while( len > 0 ) + { + use_len = len; + if( use_len > sizeof(int) ) + use_len = sizeof(int); + + if( hs->offset[1] >= MBEDTLS_HAVEGE_COLLECT_SIZE ) + havege_fill( hs ); + + val = hs->pool[hs->offset[0]++]; + val ^= hs->pool[hs->offset[1]++]; + + memcpy( p, &val, use_len ); + + len -= use_len; + p += use_len; + } + + return( 0 ); +} + +#endif /* MBEDTLS_HAVEGE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/hkdf.c b/FreeRTOS-Labs/Source/mbedtls/library/hkdf.c new file mode 100644 index 000000000..6dc55fce4 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/hkdf.c @@ -0,0 +1,192 @@ +/* + * HKDF implementation -- RFC 5869 + * + * Copyright (C) 2016-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_HKDF_C) + +#include +#include "mbedtls/hkdf.h" +#include "mbedtls/platform_util.h" + +int mbedtls_hkdf( const mbedtls_md_info_t *md, const unsigned char *salt, + size_t salt_len, const unsigned char *ikm, size_t ikm_len, + const unsigned char *info, size_t info_len, + unsigned char *okm, size_t okm_len ) +{ + int ret; + unsigned char prk[MBEDTLS_MD_MAX_SIZE]; + + ret = mbedtls_hkdf_extract( md, salt, salt_len, ikm, ikm_len, prk ); + + if( ret == 0 ) + { + ret = mbedtls_hkdf_expand( md, prk, mbedtls_md_get_size( md ), + info, info_len, okm, okm_len ); + } + + mbedtls_platform_zeroize( prk, sizeof( prk ) ); + + return( ret ); +} + +int mbedtls_hkdf_extract( const mbedtls_md_info_t *md, + const unsigned char *salt, size_t salt_len, + const unsigned char *ikm, size_t ikm_len, + unsigned char *prk ) +{ + unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' }; + + if( salt == NULL ) + { + size_t hash_len; + + if( salt_len != 0 ) + { + return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; + } + + hash_len = mbedtls_md_get_size( md ); + + if( hash_len == 0 ) + { + return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; + } + + salt = null_salt; + salt_len = hash_len; + } + + return( mbedtls_md_hmac( md, salt, salt_len, ikm, ikm_len, prk ) ); +} + +int mbedtls_hkdf_expand( const mbedtls_md_info_t *md, const unsigned char *prk, + size_t prk_len, const unsigned char *info, + size_t info_len, unsigned char *okm, size_t okm_len ) +{ + size_t hash_len; + size_t where = 0; + size_t n; + size_t t_len = 0; + size_t i; + int ret = 0; + mbedtls_md_context_t ctx; + unsigned char t[MBEDTLS_MD_MAX_SIZE]; + + if( okm == NULL ) + { + return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA ); + } + + hash_len = mbedtls_md_get_size( md ); + + if( prk_len < hash_len || hash_len == 0 ) + { + return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA ); + } + + if( info == NULL ) + { + info = (const unsigned char *) ""; + info_len = 0; + } + + n = okm_len / hash_len; + + if( (okm_len % hash_len) != 0 ) + { + n++; + } + + /* + * Per RFC 5869 Section 2.3, okm_len must not exceed + * 255 times the hash length + */ + if( n > 255 ) + { + return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA ); + } + + mbedtls_md_init( &ctx ); + + if( (ret = mbedtls_md_setup( &ctx, md, 1) ) != 0 ) + { + goto exit; + } + + /* + * Compute T = T(1) | T(2) | T(3) | ... | T(N) + * Where T(N) is defined in RFC 5869 Section 2.3 + */ + for( i = 1; i <= n; i++ ) + { + size_t num_to_copy; + unsigned char c = i & 0xff; + + ret = mbedtls_md_hmac_starts( &ctx, prk, prk_len ); + if( ret != 0 ) + { + goto exit; + } + + ret = mbedtls_md_hmac_update( &ctx, t, t_len ); + if( ret != 0 ) + { + goto exit; + } + + ret = mbedtls_md_hmac_update( &ctx, info, info_len ); + if( ret != 0 ) + { + goto exit; + } + + /* The constant concatenated to the end of each T(n) is a single octet. + * */ + ret = mbedtls_md_hmac_update( &ctx, &c, 1 ); + if( ret != 0 ) + { + goto exit; + } + + ret = mbedtls_md_hmac_finish( &ctx, t ); + if( ret != 0 ) + { + goto exit; + } + + num_to_copy = i != n ? hash_len : okm_len - where; + memcpy( okm + where, t, num_to_copy ); + where += hash_len; + t_len = hash_len; + } + +exit: + mbedtls_md_free( &ctx ); + mbedtls_platform_zeroize( t, sizeof( t ) ); + + return( ret ); +} + +#endif /* MBEDTLS_HKDF_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/hmac_drbg.c b/FreeRTOS-Labs/Source/mbedtls/library/hmac_drbg.c new file mode 100644 index 000000000..e6cf4ee91 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/hmac_drbg.c @@ -0,0 +1,580 @@ +/* + * HMAC_DRBG implementation (NIST SP 800-90) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The NIST SP 800-90A DRBGs are described in the following publication. + * http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf + * References below are based on rev. 1 (January 2012). + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_HMAC_DRBG_C) + +#include "mbedtls/hmac_drbg.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_SELF_TEST */ +#endif /* MBEDTLS_PLATFORM_C */ + +/* + * HMAC_DRBG context initialization + */ +void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_hmac_drbg_context ) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +/* + * HMAC_DRBG update, using optional additional data (10.1.2.2) + */ +int mbedtls_hmac_drbg_update_ret( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ) +{ + size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info ); + unsigned char rounds = ( additional != NULL && add_len != 0 ) ? 2 : 1; + unsigned char sep[1]; + unsigned char K[MBEDTLS_MD_MAX_SIZE]; + int ret; + + for( sep[0] = 0; sep[0] < rounds; sep[0]++ ) + { + /* Step 1 or 4 */ + if( ( ret = mbedtls_md_hmac_reset( &ctx->md_ctx ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + ctx->V, md_len ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + sep, 1 ) ) != 0 ) + goto exit; + if( rounds == 2 ) + { + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + additional, add_len ) ) != 0 ) + goto exit; + } + if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, K ) ) != 0 ) + goto exit; + + /* Step 2 or 5 */ + if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, K, md_len ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + ctx->V, md_len ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ) ) != 0 ) + goto exit; + } + +exit: + mbedtls_platform_zeroize( K, sizeof( K ) ); + return( ret ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, + size_t add_len ) +{ + (void) mbedtls_hmac_drbg_update_ret( ctx, additional, add_len ); +} +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + +/* + * Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA) + */ +int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t * md_info, + const unsigned char *data, size_t data_len ) +{ + int ret; + + if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + /* + * Set initial working state. + * Use the V memory location, which is currently all 0, to initialize the + * MD context with an all-zero key. Then set V to its initial value. + */ + if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, + mbedtls_md_get_size( md_info ) ) ) != 0 ) + return( ret ); + memset( ctx->V, 0x01, mbedtls_md_get_size( md_info ) ); + + if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, data, data_len ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * HMAC_DRBG reseeding: 10.1.2.4 (arabic) + 9.2 (Roman) + */ +int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t len ) +{ + unsigned char seed[MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT]; + size_t seedlen; + int ret; + + /* III. Check input length */ + if( len > MBEDTLS_HMAC_DRBG_MAX_INPUT || + ctx->entropy_len + len > MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT ) + { + return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + } + + memset( seed, 0, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT ); + + /* IV. Gather entropy_len bytes of entropy for the seed */ + if( ( ret = ctx->f_entropy( ctx->p_entropy, + seed, ctx->entropy_len ) ) != 0 ) + return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED ); + + seedlen = ctx->entropy_len; + + /* 1. Concatenate entropy and additional data if any */ + if( additional != NULL && len != 0 ) + { + memcpy( seed + seedlen, additional, len ); + seedlen += len; + } + + /* 2. Update state */ + if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, seed, seedlen ) ) != 0 ) + goto exit; + + /* 3. Reset reseed_counter */ + ctx->reseed_counter = 1; + +exit: + /* 4. Done */ + mbedtls_platform_zeroize( seed, seedlen ); + return( ret ); +} + +/* + * HMAC_DRBG initialisation (10.1.2.3 + 9.1) + */ +int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t * md_info, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ) +{ + int ret; + size_t entropy_len, md_size; + + if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + md_size = mbedtls_md_get_size( md_info ); + + /* + * Set initial working state. + * Use the V memory location, which is currently all 0, to initialize the + * MD context with an all-zero key. Then set V to its initial value. + */ + if( ( ret = mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, md_size ) ) != 0 ) + return( ret ); + memset( ctx->V, 0x01, md_size ); + + ctx->f_entropy = f_entropy; + ctx->p_entropy = p_entropy; + + ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL; + + /* + * See SP800-57 5.6.1 (p. 65-66) for the security strength provided by + * each hash function, then according to SP800-90A rev1 10.1 table 2, + * min_entropy_len (in bits) is security_strength. + * + * (This also matches the sizes used in the NIST test vectors.) + */ + entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */ + md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */ + 32; /* better (256+) -> 256 bits */ + + /* + * For initialisation, use more entropy to emulate a nonce + * (Again, matches test vectors.) + */ + ctx->entropy_len = entropy_len * 3 / 2; + + if( ( ret = mbedtls_hmac_drbg_reseed( ctx, custom, len ) ) != 0 ) + return( ret ); + + ctx->entropy_len = entropy_len; + + return( 0 ); +} + +/* + * Set prediction resistance + */ +void mbedtls_hmac_drbg_set_prediction_resistance( mbedtls_hmac_drbg_context *ctx, + int resistance ) +{ + ctx->prediction_resistance = resistance; +} + +/* + * Set entropy length grabbed for reseeds + */ +void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, size_t len ) +{ + ctx->entropy_len = len; +} + +/* + * Set reseed interval + */ +void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx, int interval ) +{ + ctx->reseed_interval = interval; +} + +/* + * HMAC_DRBG random function with optional additional data: + * 10.1.2.5 (arabic) + 9.3 (Roman) + */ +int mbedtls_hmac_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t out_len, + const unsigned char *additional, size_t add_len ) +{ + int ret; + mbedtls_hmac_drbg_context *ctx = (mbedtls_hmac_drbg_context *) p_rng; + size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info ); + size_t left = out_len; + unsigned char *out = output; + + /* II. Check request length */ + if( out_len > MBEDTLS_HMAC_DRBG_MAX_REQUEST ) + return( MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG ); + + /* III. Check input length */ + if( add_len > MBEDTLS_HMAC_DRBG_MAX_INPUT ) + return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + + /* 1. (aka VII and IX) Check reseed counter and PR */ + if( ctx->f_entropy != NULL && /* For no-reseeding instances */ + ( ctx->prediction_resistance == MBEDTLS_HMAC_DRBG_PR_ON || + ctx->reseed_counter > ctx->reseed_interval ) ) + { + if( ( ret = mbedtls_hmac_drbg_reseed( ctx, additional, add_len ) ) != 0 ) + return( ret ); + + add_len = 0; /* VII.4 */ + } + + /* 2. Use additional data if any */ + if( additional != NULL && add_len != 0 ) + { + if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, + additional, add_len ) ) != 0 ) + goto exit; + } + + /* 3, 4, 5. Generate bytes */ + while( left != 0 ) + { + size_t use_len = left > md_len ? md_len : left; + + if( ( ret = mbedtls_md_hmac_reset( &ctx->md_ctx ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_update( &ctx->md_ctx, + ctx->V, md_len ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ) ) != 0 ) + goto exit; + + memcpy( out, ctx->V, use_len ); + out += use_len; + left -= use_len; + } + + /* 6. Update */ + if( ( ret = mbedtls_hmac_drbg_update_ret( ctx, + additional, add_len ) ) != 0 ) + goto exit; + + /* 7. Update reseed counter */ + ctx->reseed_counter++; + +exit: + /* 8. Done */ + return( ret ); +} + +/* + * HMAC_DRBG random function + */ +int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len ) +{ + int ret; + mbedtls_hmac_drbg_context *ctx = (mbedtls_hmac_drbg_context *) p_rng; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = mbedtls_hmac_drbg_random_with_add( ctx, output, out_len, NULL, 0 ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Free an HMAC_DRBG context + */ +void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx ) +{ + if( ctx == NULL ) + return; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif + mbedtls_md_free( &ctx->md_ctx ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) ); +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ) +{ + int ret; + FILE *f; + unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); + + if( ( ret = mbedtls_hmac_drbg_random( ctx, buf, sizeof( buf ) ) ) != 0 ) + goto exit; + + if( fwrite( buf, 1, sizeof( buf ), f ) != sizeof( buf ) ) + { + ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; + goto exit; + } + + ret = 0; + +exit: + fclose( f ); + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + + return( ret ); +} + +int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ) +{ + int ret = 0; + FILE *f = NULL; + size_t n; + unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ]; + unsigned char c; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); + + n = fread( buf, 1, sizeof( buf ), f ); + if( fread( &c, 1, 1, f ) != 0 ) + { + ret = MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG; + goto exit; + } + if( n == 0 || ferror( f ) ) + { + ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; + goto exit; + } + fclose( f ); + f = NULL; + + ret = mbedtls_hmac_drbg_update_ret( ctx, buf, n ); + +exit: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + if( f != NULL ) + fclose( f ); + if( ret != 0 ) + return( ret ); + return( mbedtls_hmac_drbg_write_seed_file( ctx, path ) ); +} +#endif /* MBEDTLS_FS_IO */ + + +#if defined(MBEDTLS_SELF_TEST) + +#if !defined(MBEDTLS_SHA1_C) +/* Dummy checkup routine */ +int mbedtls_hmac_drbg_self_test( int verbose ) +{ + (void) verbose; + return( 0 ); +} +#else + +#define OUTPUT_LEN 80 + +/* From a NIST PR=true test vector */ +static const unsigned char entropy_pr[] = { + 0xa0, 0xc9, 0xab, 0x58, 0xf1, 0xe2, 0xe5, 0xa4, 0xde, 0x3e, 0xbd, 0x4f, + 0xf7, 0x3e, 0x9c, 0x5b, 0x64, 0xef, 0xd8, 0xca, 0x02, 0x8c, 0xf8, 0x11, + 0x48, 0xa5, 0x84, 0xfe, 0x69, 0xab, 0x5a, 0xee, 0x42, 0xaa, 0x4d, 0x42, + 0x17, 0x60, 0x99, 0xd4, 0x5e, 0x13, 0x97, 0xdc, 0x40, 0x4d, 0x86, 0xa3, + 0x7b, 0xf5, 0x59, 0x54, 0x75, 0x69, 0x51, 0xe4 }; +static const unsigned char result_pr[OUTPUT_LEN] = { + 0x9a, 0x00, 0xa2, 0xd0, 0x0e, 0xd5, 0x9b, 0xfe, 0x31, 0xec, 0xb1, 0x39, + 0x9b, 0x60, 0x81, 0x48, 0xd1, 0x96, 0x9d, 0x25, 0x0d, 0x3c, 0x1e, 0x94, + 0x10, 0x10, 0x98, 0x12, 0x93, 0x25, 0xca, 0xb8, 0xfc, 0xcc, 0x2d, 0x54, + 0x73, 0x19, 0x70, 0xc0, 0x10, 0x7a, 0xa4, 0x89, 0x25, 0x19, 0x95, 0x5e, + 0x4b, 0xc6, 0x00, 0x1d, 0x7f, 0x4e, 0x6a, 0x2b, 0xf8, 0xa3, 0x01, 0xab, + 0x46, 0x05, 0x5c, 0x09, 0xa6, 0x71, 0x88, 0xf1, 0xa7, 0x40, 0xee, 0xf3, + 0xe1, 0x5c, 0x02, 0x9b, 0x44, 0xaf, 0x03, 0x44 }; + +/* From a NIST PR=false test vector */ +static const unsigned char entropy_nopr[] = { + 0x79, 0x34, 0x9b, 0xbf, 0x7c, 0xdd, 0xa5, 0x79, 0x95, 0x57, 0x86, 0x66, + 0x21, 0xc9, 0x13, 0x83, 0x11, 0x46, 0x73, 0x3a, 0xbf, 0x8c, 0x35, 0xc8, + 0xc7, 0x21, 0x5b, 0x5b, 0x96, 0xc4, 0x8e, 0x9b, 0x33, 0x8c, 0x74, 0xe3, + 0xe9, 0x9d, 0xfe, 0xdf }; +static const unsigned char result_nopr[OUTPUT_LEN] = { + 0xc6, 0xa1, 0x6a, 0xb8, 0xd4, 0x20, 0x70, 0x6f, 0x0f, 0x34, 0xab, 0x7f, + 0xec, 0x5a, 0xdc, 0xa9, 0xd8, 0xca, 0x3a, 0x13, 0x3e, 0x15, 0x9c, 0xa6, + 0xac, 0x43, 0xc6, 0xf8, 0xa2, 0xbe, 0x22, 0x83, 0x4a, 0x4c, 0x0a, 0x0a, + 0xff, 0xb1, 0x0d, 0x71, 0x94, 0xf1, 0xc1, 0xa5, 0xcf, 0x73, 0x22, 0xec, + 0x1a, 0xe0, 0x96, 0x4e, 0xd4, 0xbf, 0x12, 0x27, 0x46, 0xe0, 0x87, 0xfd, + 0xb5, 0xb3, 0xe9, 0x1b, 0x34, 0x93, 0xd5, 0xbb, 0x98, 0xfa, 0xed, 0x49, + 0xe8, 0x5f, 0x13, 0x0f, 0xc8, 0xa4, 0x59, 0xb7 }; + +/* "Entropy" from buffer */ +static size_t test_offset; +static int hmac_drbg_self_test_entropy( void *data, + unsigned char *buf, size_t len ) +{ + const unsigned char *p = data; + memcpy( buf, p + test_offset, len ); + test_offset += len; + return( 0 ); +} + +#define CHK( c ) if( (c) != 0 ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf( "failed\n" ); \ + return( 1 ); \ + } + +/* + * Checkup routine for HMAC_DRBG with SHA-1 + */ +int mbedtls_hmac_drbg_self_test( int verbose ) +{ + mbedtls_hmac_drbg_context ctx; + unsigned char buf[OUTPUT_LEN]; + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ); + + mbedtls_hmac_drbg_init( &ctx ); + + /* + * PR = True + */ + if( verbose != 0 ) + mbedtls_printf( " HMAC_DRBG (PR = True) : " ); + + test_offset = 0; + CHK( mbedtls_hmac_drbg_seed( &ctx, md_info, + hmac_drbg_self_test_entropy, (void *) entropy_pr, + NULL, 0 ) ); + mbedtls_hmac_drbg_set_prediction_resistance( &ctx, MBEDTLS_HMAC_DRBG_PR_ON ); + CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); + CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); + CHK( memcmp( buf, result_pr, OUTPUT_LEN ) ); + mbedtls_hmac_drbg_free( &ctx ); + + mbedtls_hmac_drbg_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + /* + * PR = False + */ + if( verbose != 0 ) + mbedtls_printf( " HMAC_DRBG (PR = False) : " ); + + mbedtls_hmac_drbg_init( &ctx ); + + test_offset = 0; + CHK( mbedtls_hmac_drbg_seed( &ctx, md_info, + hmac_drbg_self_test_entropy, (void *) entropy_nopr, + NULL, 0 ) ); + CHK( mbedtls_hmac_drbg_reseed( &ctx, NULL, 0 ) ); + CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); + CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); + CHK( memcmp( buf, result_nopr, OUTPUT_LEN ) ); + mbedtls_hmac_drbg_free( &ctx ); + + mbedtls_hmac_drbg_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_HMAC_DRBG_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/md.c b/FreeRTOS-Labs/Source/mbedtls/library/md.c new file mode 100644 index 000000000..9eb386d24 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/md.c @@ -0,0 +1,475 @@ +/** + * \file mbedtls_md.c + * + * \brief Generic message digest wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD_C) + +#include "mbedtls/md.h" +#include "mbedtls/md_internal.h" +#include "mbedtls/platform_util.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +/* + * Reminder: update profiles in x509_crt.c when adding a new hash! + */ +static const int supported_digests[] = { + +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_MD_SHA512, + MBEDTLS_MD_SHA384, +#endif + +#if defined(MBEDTLS_SHA256_C) + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA224, +#endif + +#if defined(MBEDTLS_SHA1_C) + MBEDTLS_MD_SHA1, +#endif + +#if defined(MBEDTLS_RIPEMD160_C) + MBEDTLS_MD_RIPEMD160, +#endif + +#if defined(MBEDTLS_MD5_C) + MBEDTLS_MD_MD5, +#endif + +#if defined(MBEDTLS_MD4_C) + MBEDTLS_MD_MD4, +#endif + +#if defined(MBEDTLS_MD2_C) + MBEDTLS_MD_MD2, +#endif + + MBEDTLS_MD_NONE +}; + +const int *mbedtls_md_list( void ) +{ + return( supported_digests ); +} + +const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name ) +{ + if( NULL == md_name ) + return( NULL ); + + /* Get the appropriate digest information */ +#if defined(MBEDTLS_MD2_C) + if( !strcmp( "MD2", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_MD2 ); +#endif +#if defined(MBEDTLS_MD4_C) + if( !strcmp( "MD4", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_MD4 ); +#endif +#if defined(MBEDTLS_MD5_C) + if( !strcmp( "MD5", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_MD5 ); +#endif +#if defined(MBEDTLS_RIPEMD160_C) + if( !strcmp( "RIPEMD160", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_RIPEMD160 ); +#endif +#if defined(MBEDTLS_SHA1_C) + if( !strcmp( "SHA1", md_name ) || !strcmp( "SHA", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ); +#endif +#if defined(MBEDTLS_SHA256_C) + if( !strcmp( "SHA224", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA224 ); + if( !strcmp( "SHA256", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ); +#endif +#if defined(MBEDTLS_SHA512_C) + if( !strcmp( "SHA384", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA384 ); + if( !strcmp( "SHA512", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA512 ); +#endif + return( NULL ); +} + +const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type ) +{ + switch( md_type ) + { +#if defined(MBEDTLS_MD2_C) + case MBEDTLS_MD_MD2: + return( &mbedtls_md2_info ); +#endif +#if defined(MBEDTLS_MD4_C) + case MBEDTLS_MD_MD4: + return( &mbedtls_md4_info ); +#endif +#if defined(MBEDTLS_MD5_C) + case MBEDTLS_MD_MD5: + return( &mbedtls_md5_info ); +#endif +#if defined(MBEDTLS_RIPEMD160_C) + case MBEDTLS_MD_RIPEMD160: + return( &mbedtls_ripemd160_info ); +#endif +#if defined(MBEDTLS_SHA1_C) + case MBEDTLS_MD_SHA1: + return( &mbedtls_sha1_info ); +#endif +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_MD_SHA224: + return( &mbedtls_sha224_info ); + case MBEDTLS_MD_SHA256: + return( &mbedtls_sha256_info ); +#endif +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_MD_SHA384: + return( &mbedtls_sha384_info ); + case MBEDTLS_MD_SHA512: + return( &mbedtls_sha512_info ); +#endif + default: + return( NULL ); + } +} + +void mbedtls_md_init( mbedtls_md_context_t *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md_context_t ) ); +} + +void mbedtls_md_free( mbedtls_md_context_t *ctx ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return; + + if( ctx->md_ctx != NULL ) + ctx->md_info->ctx_free_func( ctx->md_ctx ); + + if( ctx->hmac_ctx != NULL ) + { + mbedtls_platform_zeroize( ctx->hmac_ctx, + 2 * ctx->md_info->block_size ); + mbedtls_free( ctx->hmac_ctx ); + } + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md_context_t ) ); +} + +int mbedtls_md_clone( mbedtls_md_context_t *dst, + const mbedtls_md_context_t *src ) +{ + if( dst == NULL || dst->md_info == NULL || + src == NULL || src->md_info == NULL || + dst->md_info != src->md_info ) + { + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + } + + dst->md_info->clone_func( dst->md_ctx, src->md_ctx ); + + return( 0 ); +} + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info ) +{ + return mbedtls_md_setup( ctx, md_info, 1 ); +} +#endif + +int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac ) +{ + if( md_info == NULL || ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( ( ctx->md_ctx = md_info->ctx_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_MD_ALLOC_FAILED ); + + if( hmac != 0 ) + { + ctx->hmac_ctx = mbedtls_calloc( 2, md_info->block_size ); + if( ctx->hmac_ctx == NULL ) + { + md_info->ctx_free_func( ctx->md_ctx ); + return( MBEDTLS_ERR_MD_ALLOC_FAILED ); + } + } + + ctx->md_info = md_info; + + return( 0 ); +} + +int mbedtls_md_starts( mbedtls_md_context_t *ctx ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + return( ctx->md_info->starts_func( ctx->md_ctx ) ); +} + +int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + return( ctx->md_info->update_func( ctx->md_ctx, input, ilen ) ); +} + +int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + return( ctx->md_info->finish_func( ctx->md_ctx, output ) ); +} + +int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + return( md_info->digest_func( input, ilen, output ) ); +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, unsigned char *output ) +{ + int ret; + FILE *f; + size_t n; + mbedtls_md_context_t ctx; + unsigned char buf[1024]; + + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_MD_FILE_IO_ERROR ); + + mbedtls_md_init( &ctx ); + + if( ( ret = mbedtls_md_setup( &ctx, md_info, 0 ) ) != 0 ) + goto cleanup; + + if( ( ret = md_info->starts_func( ctx.md_ctx ) ) != 0 ) + goto cleanup; + + while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + if( ( ret = md_info->update_func( ctx.md_ctx, buf, n ) ) != 0 ) + goto cleanup; + + if( ferror( f ) != 0 ) + ret = MBEDTLS_ERR_MD_FILE_IO_ERROR; + else + ret = md_info->finish_func( ctx.md_ctx, output ); + +cleanup: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + fclose( f ); + mbedtls_md_free( &ctx ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, size_t keylen ) +{ + int ret; + unsigned char sum[MBEDTLS_MD_MAX_SIZE]; + unsigned char *ipad, *opad; + size_t i; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( keylen > (size_t) ctx->md_info->block_size ) + { + if( ( ret = ctx->md_info->starts_func( ctx->md_ctx ) ) != 0 ) + goto cleanup; + if( ( ret = ctx->md_info->update_func( ctx->md_ctx, key, keylen ) ) != 0 ) + goto cleanup; + if( ( ret = ctx->md_info->finish_func( ctx->md_ctx, sum ) ) != 0 ) + goto cleanup; + + keylen = ctx->md_info->size; + key = sum; + } + + ipad = (unsigned char *) ctx->hmac_ctx; + opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size; + + memset( ipad, 0x36, ctx->md_info->block_size ); + memset( opad, 0x5C, ctx->md_info->block_size ); + + for( i = 0; i < keylen; i++ ) + { + ipad[i] = (unsigned char)( ipad[i] ^ key[i] ); + opad[i] = (unsigned char)( opad[i] ^ key[i] ); + } + + if( ( ret = ctx->md_info->starts_func( ctx->md_ctx ) ) != 0 ) + goto cleanup; + if( ( ret = ctx->md_info->update_func( ctx->md_ctx, ipad, + ctx->md_info->block_size ) ) != 0 ) + goto cleanup; + +cleanup: + mbedtls_platform_zeroize( sum, sizeof( sum ) ); + + return( ret ); +} + +int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ) +{ + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + return( ctx->md_info->update_func( ctx->md_ctx, input, ilen ) ); +} + +int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output ) +{ + int ret; + unsigned char tmp[MBEDTLS_MD_MAX_SIZE]; + unsigned char *opad; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size; + + if( ( ret = ctx->md_info->finish_func( ctx->md_ctx, tmp ) ) != 0 ) + return( ret ); + if( ( ret = ctx->md_info->starts_func( ctx->md_ctx ) ) != 0 ) + return( ret ); + if( ( ret = ctx->md_info->update_func( ctx->md_ctx, opad, + ctx->md_info->block_size ) ) != 0 ) + return( ret ); + if( ( ret = ctx->md_info->update_func( ctx->md_ctx, tmp, + ctx->md_info->size ) ) != 0 ) + return( ret ); + return( ctx->md_info->finish_func( ctx->md_ctx, output ) ); +} + +int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx ) +{ + int ret; + unsigned char *ipad; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ipad = (unsigned char *) ctx->hmac_ctx; + + if( ( ret = ctx->md_info->starts_func( ctx->md_ctx ) ) != 0 ) + return( ret ); + return( ctx->md_info->update_func( ctx->md_ctx, ipad, + ctx->md_info->block_size ) ); +} + +int mbedtls_md_hmac( const mbedtls_md_info_t *md_info, + const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_md_context_t ctx; + int ret; + + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + mbedtls_md_init( &ctx ); + + if( ( ret = mbedtls_md_setup( &ctx, md_info, 1 ) ) != 0 ) + goto cleanup; + + if( ( ret = mbedtls_md_hmac_starts( &ctx, key, keylen ) ) != 0 ) + goto cleanup; + if( ( ret = mbedtls_md_hmac_update( &ctx, input, ilen ) ) != 0 ) + goto cleanup; + if( ( ret = mbedtls_md_hmac_finish( &ctx, output ) ) != 0 ) + goto cleanup; + +cleanup: + mbedtls_md_free( &ctx ); + + return( ret ); +} + +int mbedtls_md_process( mbedtls_md_context_t *ctx, const unsigned char *data ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + return( ctx->md_info->process_func( ctx->md_ctx, data ) ); +} + +unsigned char mbedtls_md_get_size( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( 0 ); + + return md_info->size; +} + +mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( MBEDTLS_MD_NONE ); + + return md_info->type; +} + +const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( NULL ); + + return md_info->name; +} + +#endif /* MBEDTLS_MD_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/md2.c b/FreeRTOS-Labs/Source/mbedtls/library/md2.c new file mode 100644 index 000000000..951207934 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/md2.c @@ -0,0 +1,363 @@ +/* + * RFC 1115/1319 compliant MD2 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The MD2 algorithm was designed by Ron Rivest in 1989. + * + * http://www.ietf.org/rfc/rfc1115.txt + * http://www.ietf.org/rfc/rfc1319.txt + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD2_C) + +#include "mbedtls/md2.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_MD2_ALT) + +static const unsigned char PI_SUBST[256] = +{ + 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, + 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3, + 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, + 0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, + 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 0xBE, 0x4E, + 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, + 0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, + 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, + 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, + 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 0xFF, 0x19, 0x30, 0xB3, + 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, + 0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, + 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D, + 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, + 0xE6, 0x2D, 0xA8, 0x02, 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, + 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, + 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, + 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E, + 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, + 0x4D, 0x52, 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, + 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88, + 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, + 0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, + 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, + 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, + 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14 +}; + +void mbedtls_md2_init( mbedtls_md2_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md2_context ) ); +} + +void mbedtls_md2_free( mbedtls_md2_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md2_context ) ); +} + +void mbedtls_md2_clone( mbedtls_md2_context *dst, + const mbedtls_md2_context *src ) +{ + *dst = *src; +} + +/* + * MD2 context setup + */ +int mbedtls_md2_starts_ret( mbedtls_md2_context *ctx ) +{ + memset( ctx->cksum, 0, 16 ); + memset( ctx->state, 0, 46 ); + memset( ctx->buffer, 0, 16 ); + ctx->left = 0; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md2_starts( mbedtls_md2_context *ctx ) +{ + mbedtls_md2_starts_ret( ctx ); +} +#endif + +#if !defined(MBEDTLS_MD2_PROCESS_ALT) +int mbedtls_internal_md2_process( mbedtls_md2_context *ctx ) +{ + int i, j; + unsigned char t = 0; + + for( i = 0; i < 16; i++ ) + { + ctx->state[i + 16] = ctx->buffer[i]; + ctx->state[i + 32] = + (unsigned char)( ctx->buffer[i] ^ ctx->state[i]); + } + + for( i = 0; i < 18; i++ ) + { + for( j = 0; j < 48; j++ ) + { + ctx->state[j] = (unsigned char) + ( ctx->state[j] ^ PI_SUBST[t] ); + t = ctx->state[j]; + } + + t = (unsigned char)( t + i ); + } + + t = ctx->cksum[15]; + + for( i = 0; i < 16; i++ ) + { + ctx->cksum[i] = (unsigned char) + ( ctx->cksum[i] ^ PI_SUBST[ctx->buffer[i] ^ t] ); + t = ctx->cksum[i]; + } + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md2_process( mbedtls_md2_context *ctx ) +{ + mbedtls_internal_md2_process( ctx ); +} +#endif +#endif /* !MBEDTLS_MD2_PROCESS_ALT */ + +/* + * MD2 process buffer + */ +int mbedtls_md2_update_ret( mbedtls_md2_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + int ret; + size_t fill; + + while( ilen > 0 ) + { + if( ilen > 16 - ctx->left ) + fill = 16 - ctx->left; + else + fill = ilen; + + memcpy( ctx->buffer + ctx->left, input, fill ); + + ctx->left += fill; + input += fill; + ilen -= fill; + + if( ctx->left == 16 ) + { + ctx->left = 0; + if( ( ret = mbedtls_internal_md2_process( ctx ) ) != 0 ) + return( ret ); + } + } + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md2_update( mbedtls_md2_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + mbedtls_md2_update_ret( ctx, input, ilen ); +} +#endif + +/* + * MD2 final digest + */ +int mbedtls_md2_finish_ret( mbedtls_md2_context *ctx, + unsigned char output[16] ) +{ + int ret; + size_t i; + unsigned char x; + + x = (unsigned char)( 16 - ctx->left ); + + for( i = ctx->left; i < 16; i++ ) + ctx->buffer[i] = x; + + if( ( ret = mbedtls_internal_md2_process( ctx ) ) != 0 ) + return( ret ); + + memcpy( ctx->buffer, ctx->cksum, 16 ); + if( ( ret = mbedtls_internal_md2_process( ctx ) ) != 0 ) + return( ret ); + + memcpy( output, ctx->state, 16 ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md2_finish( mbedtls_md2_context *ctx, + unsigned char output[16] ) +{ + mbedtls_md2_finish_ret( ctx, output ); +} +#endif + +#endif /* !MBEDTLS_MD2_ALT */ + +/* + * output = MD2( input buffer ) + */ +int mbedtls_md2_ret( const unsigned char *input, + size_t ilen, + unsigned char output[16] ) +{ + int ret; + mbedtls_md2_context ctx; + + mbedtls_md2_init( &ctx ); + + if( ( ret = mbedtls_md2_starts_ret( &ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md2_update_ret( &ctx, input, ilen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md2_finish_ret( &ctx, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_md2_free( &ctx ); + + return( ret ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md2( const unsigned char *input, + size_t ilen, + unsigned char output[16] ) +{ + mbedtls_md2_ret( input, ilen, output ); +} +#endif + +#if defined(MBEDTLS_SELF_TEST) + +/* + * RFC 1319 test vectors + */ +static const unsigned char md2_test_str[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" + "345678901234567890" } +}; + +static const size_t md2_test_strlen[7] = +{ + 0, 1, 3, 14, 26, 62, 80 +}; + +static const unsigned char md2_test_sum[7][16] = +{ + { 0x83, 0x50, 0xE5, 0xA3, 0xE2, 0x4C, 0x15, 0x3D, + 0xF2, 0x27, 0x5C, 0x9F, 0x80, 0x69, 0x27, 0x73 }, + { 0x32, 0xEC, 0x01, 0xEC, 0x4A, 0x6D, 0xAC, 0x72, + 0xC0, 0xAB, 0x96, 0xFB, 0x34, 0xC0, 0xB5, 0xD1 }, + { 0xDA, 0x85, 0x3B, 0x0D, 0x3F, 0x88, 0xD9, 0x9B, + 0x30, 0x28, 0x3A, 0x69, 0xE6, 0xDE, 0xD6, 0xBB }, + { 0xAB, 0x4F, 0x49, 0x6B, 0xFB, 0x2A, 0x53, 0x0B, + 0x21, 0x9F, 0xF3, 0x30, 0x31, 0xFE, 0x06, 0xB0 }, + { 0x4E, 0x8D, 0xDF, 0xF3, 0x65, 0x02, 0x92, 0xAB, + 0x5A, 0x41, 0x08, 0xC3, 0xAA, 0x47, 0x94, 0x0B }, + { 0xDA, 0x33, 0xDE, 0xF2, 0xA4, 0x2D, 0xF1, 0x39, + 0x75, 0x35, 0x28, 0x46, 0xC3, 0x03, 0x38, 0xCD }, + { 0xD5, 0x97, 0x6F, 0x79, 0xD8, 0x3D, 0x3A, 0x0D, + 0xC9, 0x80, 0x6C, 0x3C, 0x66, 0xF3, 0xEF, 0xD8 } +}; + +/* + * Checkup routine + */ +int mbedtls_md2_self_test( int verbose ) +{ + int i, ret = 0; + unsigned char md2sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " MD2 test #%d: ", i + 1 ); + + ret = mbedtls_md2_ret( md2_test_str[i], md2_test_strlen[i], md2sum ); + if( ret != 0 ) + goto fail; + + if( memcmp( md2sum, md2_test_sum[i], 16 ) != 0 ) + { + ret = 1; + goto fail; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); + +fail: + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MD2_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/md4.c b/FreeRTOS-Labs/Source/mbedtls/library/md4.c new file mode 100644 index 000000000..9cd9976e9 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/md4.c @@ -0,0 +1,484 @@ +/* + * RFC 1186/1320 compliant MD4 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The MD4 algorithm was designed by Ron Rivest in 1990. + * + * http://www.ietf.org/rfc/rfc1186.txt + * http://www.ietf.org/rfc/rfc1320.txt + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD4_C) + +#include "mbedtls/md4.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_MD4_ALT) + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +void mbedtls_md4_init( mbedtls_md4_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md4_context ) ); +} + +void mbedtls_md4_free( mbedtls_md4_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md4_context ) ); +} + +void mbedtls_md4_clone( mbedtls_md4_context *dst, + const mbedtls_md4_context *src ) +{ + *dst = *src; +} + +/* + * MD4 context setup + */ +int mbedtls_md4_starts_ret( mbedtls_md4_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md4_starts( mbedtls_md4_context *ctx ) +{ + mbedtls_md4_starts_ret( ctx ); +} +#endif + +#if !defined(MBEDTLS_MD4_PROCESS_ALT) +int mbedtls_internal_md4_process( mbedtls_md4_context *ctx, + const unsigned char data[64] ) +{ + uint32_t X[16], A, B, C, D; + + GET_UINT32_LE( X[ 0], data, 0 ); + GET_UINT32_LE( X[ 1], data, 4 ); + GET_UINT32_LE( X[ 2], data, 8 ); + GET_UINT32_LE( X[ 3], data, 12 ); + GET_UINT32_LE( X[ 4], data, 16 ); + GET_UINT32_LE( X[ 5], data, 20 ); + GET_UINT32_LE( X[ 6], data, 24 ); + GET_UINT32_LE( X[ 7], data, 28 ); + GET_UINT32_LE( X[ 8], data, 32 ); + GET_UINT32_LE( X[ 9], data, 36 ); + GET_UINT32_LE( X[10], data, 40 ); + GET_UINT32_LE( X[11], data, 44 ); + GET_UINT32_LE( X[12], data, 48 ); + GET_UINT32_LE( X[13], data, 52 ); + GET_UINT32_LE( X[14], data, 56 ); + GET_UINT32_LE( X[15], data, 60 ); + +#define S(x,n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n)))) + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x, y, z) (((x) & (y)) | ((~(x)) & (z))) +#define P(a,b,c,d,x,s) \ + do \ + { \ + (a) += F((b),(c),(d)) + (x); \ + (a) = S((a),(s)); \ + } while( 0 ) + + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 1], 7 ); + P( C, D, A, B, X[ 2], 11 ); + P( B, C, D, A, X[ 3], 19 ); + P( A, B, C, D, X[ 4], 3 ); + P( D, A, B, C, X[ 5], 7 ); + P( C, D, A, B, X[ 6], 11 ); + P( B, C, D, A, X[ 7], 19 ); + P( A, B, C, D, X[ 8], 3 ); + P( D, A, B, C, X[ 9], 7 ); + P( C, D, A, B, X[10], 11 ); + P( B, C, D, A, X[11], 19 ); + P( A, B, C, D, X[12], 3 ); + P( D, A, B, C, X[13], 7 ); + P( C, D, A, B, X[14], 11 ); + P( B, C, D, A, X[15], 19 ); + +#undef P +#undef F + +#define F(x,y,z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define P(a,b,c,d,x,s) \ + do \ + { \ + (a) += F((b),(c),(d)) + (x) + 0x5A827999; \ + (a) = S((a),(s)); \ + } while( 0 ) + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 4], 5 ); + P( C, D, A, B, X[ 8], 9 ); + P( B, C, D, A, X[12], 13 ); + P( A, B, C, D, X[ 1], 3 ); + P( D, A, B, C, X[ 5], 5 ); + P( C, D, A, B, X[ 9], 9 ); + P( B, C, D, A, X[13], 13 ); + P( A, B, C, D, X[ 2], 3 ); + P( D, A, B, C, X[ 6], 5 ); + P( C, D, A, B, X[10], 9 ); + P( B, C, D, A, X[14], 13 ); + P( A, B, C, D, X[ 3], 3 ); + P( D, A, B, C, X[ 7], 5 ); + P( C, D, A, B, X[11], 9 ); + P( B, C, D, A, X[15], 13 ); + +#undef P +#undef F + +#define F(x,y,z) ((x) ^ (y) ^ (z)) +#define P(a,b,c,d,x,s) \ + do \ + { \ + (a) += F((b),(c),(d)) + (x) + 0x6ED9EBA1; \ + (a) = S((a),(s)); \ + } while( 0 ) + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 8], 9 ); + P( C, D, A, B, X[ 4], 11 ); + P( B, C, D, A, X[12], 15 ); + P( A, B, C, D, X[ 2], 3 ); + P( D, A, B, C, X[10], 9 ); + P( C, D, A, B, X[ 6], 11 ); + P( B, C, D, A, X[14], 15 ); + P( A, B, C, D, X[ 1], 3 ); + P( D, A, B, C, X[ 9], 9 ); + P( C, D, A, B, X[ 5], 11 ); + P( B, C, D, A, X[13], 15 ); + P( A, B, C, D, X[ 3], 3 ); + P( D, A, B, C, X[11], 9 ); + P( C, D, A, B, X[ 7], 11 ); + P( B, C, D, A, X[15], 15 ); + +#undef F +#undef P + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md4_process( mbedtls_md4_context *ctx, + const unsigned char data[64] ) +{ + mbedtls_internal_md4_process( ctx, data ); +} +#endif +#endif /* !MBEDTLS_MD4_PROCESS_ALT */ + +/* + * MD4 process buffer + */ +int mbedtls_md4_update_ret( mbedtls_md4_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + int ret; + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return( 0 ); + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, fill ); + + if( ( ret = mbedtls_internal_md4_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + if( ( ret = mbedtls_internal_md4_process( ctx, input ) ) != 0 ) + return( ret ); + + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, ilen ); + } + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md4_update( mbedtls_md4_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + mbedtls_md4_update_ret( ctx, input, ilen ); +} +#endif + +static const unsigned char md4_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * MD4 final digest + */ +int mbedtls_md4_finish_ret( mbedtls_md4_context *ctx, + unsigned char output[16] ) +{ + int ret; + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_LE( low, msglen, 0 ); + PUT_UINT32_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + ret = mbedtls_md4_update_ret( ctx, (unsigned char *)md4_padding, padn ); + if( ret != 0 ) + return( ret ); + + if( ( ret = mbedtls_md4_update_ret( ctx, msglen, 8 ) ) != 0 ) + return( ret ); + + + PUT_UINT32_LE( ctx->state[0], output, 0 ); + PUT_UINT32_LE( ctx->state[1], output, 4 ); + PUT_UINT32_LE( ctx->state[2], output, 8 ); + PUT_UINT32_LE( ctx->state[3], output, 12 ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md4_finish( mbedtls_md4_context *ctx, + unsigned char output[16] ) +{ + mbedtls_md4_finish_ret( ctx, output ); +} +#endif + +#endif /* !MBEDTLS_MD4_ALT */ + +/* + * output = MD4( input buffer ) + */ +int mbedtls_md4_ret( const unsigned char *input, + size_t ilen, + unsigned char output[16] ) +{ + int ret; + mbedtls_md4_context ctx; + + mbedtls_md4_init( &ctx ); + + if( ( ret = mbedtls_md4_starts_ret( &ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md4_update_ret( &ctx, input, ilen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md4_finish_ret( &ctx, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_md4_free( &ctx ); + + return( ret ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md4( const unsigned char *input, + size_t ilen, + unsigned char output[16] ) +{ + mbedtls_md4_ret( input, ilen, output ); +} +#endif + +#if defined(MBEDTLS_SELF_TEST) + +/* + * RFC 1320 test vectors + */ +static const unsigned char md4_test_str[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" + "345678901234567890" } +}; + +static const size_t md4_test_strlen[7] = +{ + 0, 1, 3, 14, 26, 62, 80 +}; + +static const unsigned char md4_test_sum[7][16] = +{ + { 0x31, 0xD6, 0xCF, 0xE0, 0xD1, 0x6A, 0xE9, 0x31, + 0xB7, 0x3C, 0x59, 0xD7, 0xE0, 0xC0, 0x89, 0xC0 }, + { 0xBD, 0xE5, 0x2C, 0xB3, 0x1D, 0xE3, 0x3E, 0x46, + 0x24, 0x5E, 0x05, 0xFB, 0xDB, 0xD6, 0xFB, 0x24 }, + { 0xA4, 0x48, 0x01, 0x7A, 0xAF, 0x21, 0xD8, 0x52, + 0x5F, 0xC1, 0x0A, 0xE8, 0x7A, 0xA6, 0x72, 0x9D }, + { 0xD9, 0x13, 0x0A, 0x81, 0x64, 0x54, 0x9F, 0xE8, + 0x18, 0x87, 0x48, 0x06, 0xE1, 0xC7, 0x01, 0x4B }, + { 0xD7, 0x9E, 0x1C, 0x30, 0x8A, 0xA5, 0xBB, 0xCD, + 0xEE, 0xA8, 0xED, 0x63, 0xDF, 0x41, 0x2D, 0xA9 }, + { 0x04, 0x3F, 0x85, 0x82, 0xF2, 0x41, 0xDB, 0x35, + 0x1C, 0xE6, 0x27, 0xE1, 0x53, 0xE7, 0xF0, 0xE4 }, + { 0xE3, 0x3B, 0x4D, 0xDC, 0x9C, 0x38, 0xF2, 0x19, + 0x9C, 0x3E, 0x7B, 0x16, 0x4F, 0xCC, 0x05, 0x36 } +}; + +/* + * Checkup routine + */ +int mbedtls_md4_self_test( int verbose ) +{ + int i, ret = 0; + unsigned char md4sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " MD4 test #%d: ", i + 1 ); + + ret = mbedtls_md4_ret( md4_test_str[i], md4_test_strlen[i], md4sum ); + if( ret != 0 ) + goto fail; + + if( memcmp( md4sum, md4_test_sum[i], 16 ) != 0 ) + { + ret = 1; + goto fail; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); + +fail: + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MD4_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/md5.c b/FreeRTOS-Labs/Source/mbedtls/library/md5.c new file mode 100644 index 000000000..50288885a --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/md5.c @@ -0,0 +1,498 @@ +/* + * RFC 1321 compliant MD5 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The MD5 algorithm was designed by Ron Rivest in 1991. + * + * http://www.ietf.org/rfc/rfc1321.txt + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD5_C) + +#include "mbedtls/md5.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_MD5_ALT) + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +void mbedtls_md5_init( mbedtls_md5_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md5_context ) ); +} + +void mbedtls_md5_free( mbedtls_md5_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md5_context ) ); +} + +void mbedtls_md5_clone( mbedtls_md5_context *dst, + const mbedtls_md5_context *src ) +{ + *dst = *src; +} + +/* + * MD5 context setup + */ +int mbedtls_md5_starts_ret( mbedtls_md5_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md5_starts( mbedtls_md5_context *ctx ) +{ + mbedtls_md5_starts_ret( ctx ); +} +#endif + +#if !defined(MBEDTLS_MD5_PROCESS_ALT) +int mbedtls_internal_md5_process( mbedtls_md5_context *ctx, + const unsigned char data[64] ) +{ + uint32_t X[16], A, B, C, D; + + GET_UINT32_LE( X[ 0], data, 0 ); + GET_UINT32_LE( X[ 1], data, 4 ); + GET_UINT32_LE( X[ 2], data, 8 ); + GET_UINT32_LE( X[ 3], data, 12 ); + GET_UINT32_LE( X[ 4], data, 16 ); + GET_UINT32_LE( X[ 5], data, 20 ); + GET_UINT32_LE( X[ 6], data, 24 ); + GET_UINT32_LE( X[ 7], data, 28 ); + GET_UINT32_LE( X[ 8], data, 32 ); + GET_UINT32_LE( X[ 9], data, 36 ); + GET_UINT32_LE( X[10], data, 40 ); + GET_UINT32_LE( X[11], data, 44 ); + GET_UINT32_LE( X[12], data, 48 ); + GET_UINT32_LE( X[13], data, 52 ); + GET_UINT32_LE( X[14], data, 56 ); + GET_UINT32_LE( X[15], data, 60 ); + +#define S(x,n) \ + ( ( (x) << (n) ) | ( ( (x) & 0xFFFFFFFF) >> ( 32 - (n) ) ) ) + +#define P(a,b,c,d,k,s,t) \ + do \ + { \ + (a) += F((b),(c),(d)) + X[(k)] + (t); \ + (a) = S((a),(s)) + (b); \ + } while( 0 ) + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) + + P( A, B, C, D, 0, 7, 0xD76AA478 ); + P( D, A, B, C, 1, 12, 0xE8C7B756 ); + P( C, D, A, B, 2, 17, 0x242070DB ); + P( B, C, D, A, 3, 22, 0xC1BDCEEE ); + P( A, B, C, D, 4, 7, 0xF57C0FAF ); + P( D, A, B, C, 5, 12, 0x4787C62A ); + P( C, D, A, B, 6, 17, 0xA8304613 ); + P( B, C, D, A, 7, 22, 0xFD469501 ); + P( A, B, C, D, 8, 7, 0x698098D8 ); + P( D, A, B, C, 9, 12, 0x8B44F7AF ); + P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); + P( B, C, D, A, 11, 22, 0x895CD7BE ); + P( A, B, C, D, 12, 7, 0x6B901122 ); + P( D, A, B, C, 13, 12, 0xFD987193 ); + P( C, D, A, B, 14, 17, 0xA679438E ); + P( B, C, D, A, 15, 22, 0x49B40821 ); + +#undef F + +#define F(x,y,z) ((y) ^ ((z) & ((x) ^ (y)))) + + P( A, B, C, D, 1, 5, 0xF61E2562 ); + P( D, A, B, C, 6, 9, 0xC040B340 ); + P( C, D, A, B, 11, 14, 0x265E5A51 ); + P( B, C, D, A, 0, 20, 0xE9B6C7AA ); + P( A, B, C, D, 5, 5, 0xD62F105D ); + P( D, A, B, C, 10, 9, 0x02441453 ); + P( C, D, A, B, 15, 14, 0xD8A1E681 ); + P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); + P( A, B, C, D, 9, 5, 0x21E1CDE6 ); + P( D, A, B, C, 14, 9, 0xC33707D6 ); + P( C, D, A, B, 3, 14, 0xF4D50D87 ); + P( B, C, D, A, 8, 20, 0x455A14ED ); + P( A, B, C, D, 13, 5, 0xA9E3E905 ); + P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); + P( C, D, A, B, 7, 14, 0x676F02D9 ); + P( B, C, D, A, 12, 20, 0x8D2A4C8A ); + +#undef F + +#define F(x,y,z) ((x) ^ (y) ^ (z)) + + P( A, B, C, D, 5, 4, 0xFFFA3942 ); + P( D, A, B, C, 8, 11, 0x8771F681 ); + P( C, D, A, B, 11, 16, 0x6D9D6122 ); + P( B, C, D, A, 14, 23, 0xFDE5380C ); + P( A, B, C, D, 1, 4, 0xA4BEEA44 ); + P( D, A, B, C, 4, 11, 0x4BDECFA9 ); + P( C, D, A, B, 7, 16, 0xF6BB4B60 ); + P( B, C, D, A, 10, 23, 0xBEBFBC70 ); + P( A, B, C, D, 13, 4, 0x289B7EC6 ); + P( D, A, B, C, 0, 11, 0xEAA127FA ); + P( C, D, A, B, 3, 16, 0xD4EF3085 ); + P( B, C, D, A, 6, 23, 0x04881D05 ); + P( A, B, C, D, 9, 4, 0xD9D4D039 ); + P( D, A, B, C, 12, 11, 0xE6DB99E5 ); + P( C, D, A, B, 15, 16, 0x1FA27CF8 ); + P( B, C, D, A, 2, 23, 0xC4AC5665 ); + +#undef F + +#define F(x,y,z) ((y) ^ ((x) | ~(z))) + + P( A, B, C, D, 0, 6, 0xF4292244 ); + P( D, A, B, C, 7, 10, 0x432AFF97 ); + P( C, D, A, B, 14, 15, 0xAB9423A7 ); + P( B, C, D, A, 5, 21, 0xFC93A039 ); + P( A, B, C, D, 12, 6, 0x655B59C3 ); + P( D, A, B, C, 3, 10, 0x8F0CCC92 ); + P( C, D, A, B, 10, 15, 0xFFEFF47D ); + P( B, C, D, A, 1, 21, 0x85845DD1 ); + P( A, B, C, D, 8, 6, 0x6FA87E4F ); + P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); + P( C, D, A, B, 6, 15, 0xA3014314 ); + P( B, C, D, A, 13, 21, 0x4E0811A1 ); + P( A, B, C, D, 4, 6, 0xF7537E82 ); + P( D, A, B, C, 11, 10, 0xBD3AF235 ); + P( C, D, A, B, 2, 15, 0x2AD7D2BB ); + P( B, C, D, A, 9, 21, 0xEB86D391 ); + +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md5_process( mbedtls_md5_context *ctx, + const unsigned char data[64] ) +{ + mbedtls_internal_md5_process( ctx, data ); +} +#endif +#endif /* !MBEDTLS_MD5_PROCESS_ALT */ + +/* + * MD5 process buffer + */ +int mbedtls_md5_update_ret( mbedtls_md5_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + int ret; + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return( 0 ); + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + if( ( ret = mbedtls_internal_md5_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + if( ( ret = mbedtls_internal_md5_process( ctx, input ) ) != 0 ) + return( ret ); + + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), input, ilen ); + } + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md5_update( mbedtls_md5_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + mbedtls_md5_update_ret( ctx, input, ilen ); +} +#endif + +/* + * MD5 final digest + */ +int mbedtls_md5_finish_ret( mbedtls_md5_context *ctx, + unsigned char output[16] ) +{ + int ret; + uint32_t used; + uint32_t high, low; + + /* + * Add padding: 0x80 then 0x00 until 8 bytes remain for the length + */ + used = ctx->total[0] & 0x3F; + + ctx->buffer[used++] = 0x80; + + if( used <= 56 ) + { + /* Enough room for padding + length in current block */ + memset( ctx->buffer + used, 0, 56 - used ); + } + else + { + /* We'll need an extra block */ + memset( ctx->buffer + used, 0, 64 - used ); + + if( ( ret = mbedtls_internal_md5_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + memset( ctx->buffer, 0, 56 ); + } + + /* + * Add message length + */ + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_LE( low, ctx->buffer, 56 ); + PUT_UINT32_LE( high, ctx->buffer, 60 ); + + if( ( ret = mbedtls_internal_md5_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + /* + * Output final state + */ + PUT_UINT32_LE( ctx->state[0], output, 0 ); + PUT_UINT32_LE( ctx->state[1], output, 4 ); + PUT_UINT32_LE( ctx->state[2], output, 8 ); + PUT_UINT32_LE( ctx->state[3], output, 12 ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md5_finish( mbedtls_md5_context *ctx, + unsigned char output[16] ) +{ + mbedtls_md5_finish_ret( ctx, output ); +} +#endif + +#endif /* !MBEDTLS_MD5_ALT */ + +/* + * output = MD5( input buffer ) + */ +int mbedtls_md5_ret( const unsigned char *input, + size_t ilen, + unsigned char output[16] ) +{ + int ret; + mbedtls_md5_context ctx; + + mbedtls_md5_init( &ctx ); + + if( ( ret = mbedtls_md5_starts_ret( &ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md5_update_ret( &ctx, input, ilen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md5_finish_ret( &ctx, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_md5_free( &ctx ); + + return( ret ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md5( const unsigned char *input, + size_t ilen, + unsigned char output[16] ) +{ + mbedtls_md5_ret( input, ilen, output ); +} +#endif + +#if defined(MBEDTLS_SELF_TEST) +/* + * RFC 1321 test vectors + */ +static const unsigned char md5_test_buf[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" + "345678901234567890" } +}; + +static const size_t md5_test_buflen[7] = +{ + 0, 1, 3, 14, 26, 62, 80 +}; + +static const unsigned char md5_test_sum[7][16] = +{ + { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04, + 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E }, + { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8, + 0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 }, + { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0, + 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 }, + { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D, + 0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 }, + { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00, + 0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B }, + { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5, + 0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F }, + { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55, + 0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A } +}; + +/* + * Checkup routine + */ +int mbedtls_md5_self_test( int verbose ) +{ + int i, ret = 0; + unsigned char md5sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " MD5 test #%d: ", i + 1 ); + + ret = mbedtls_md5_ret( md5_test_buf[i], md5_test_buflen[i], md5sum ); + if( ret != 0 ) + goto fail; + + if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 ) + { + ret = 1; + goto fail; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); + +fail: + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MD5_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/md_wrap.c b/FreeRTOS-Labs/Source/mbedtls/library/md_wrap.c new file mode 100644 index 000000000..5b57cda8f --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/md_wrap.c @@ -0,0 +1,586 @@ +/** + * \file md_wrap.c + * + * \brief Generic message digest wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD_C) + +#include "mbedtls/md_internal.h" + +#if defined(MBEDTLS_MD2_C) +#include "mbedtls/md2.h" +#endif + +#if defined(MBEDTLS_MD4_C) +#include "mbedtls/md4.h" +#endif + +#if defined(MBEDTLS_MD5_C) +#include "mbedtls/md5.h" +#endif + +#if defined(MBEDTLS_RIPEMD160_C) +#include "mbedtls/ripemd160.h" +#endif + +#if defined(MBEDTLS_SHA1_C) +#include "mbedtls/sha1.h" +#endif + +#if defined(MBEDTLS_SHA256_C) +#include "mbedtls/sha256.h" +#endif + +#if defined(MBEDTLS_SHA512_C) +#include "mbedtls/sha512.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_MD2_C) + +static int md2_starts_wrap( void *ctx ) +{ + return( mbedtls_md2_starts_ret( (mbedtls_md2_context *) ctx ) ); +} + +static int md2_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + return( mbedtls_md2_update_ret( (mbedtls_md2_context *) ctx, input, ilen ) ); +} + +static int md2_finish_wrap( void *ctx, unsigned char *output ) +{ + return( mbedtls_md2_finish_ret( (mbedtls_md2_context *) ctx, output ) ); +} + +static void *md2_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md2_context ) ); + + if( ctx != NULL ) + mbedtls_md2_init( (mbedtls_md2_context *) ctx ); + + return( ctx ); +} + +static void md2_ctx_free( void *ctx ) +{ + mbedtls_md2_free( (mbedtls_md2_context *) ctx ); + mbedtls_free( ctx ); +} + +static void md2_clone_wrap( void *dst, const void *src ) +{ + mbedtls_md2_clone( (mbedtls_md2_context *) dst, + (const mbedtls_md2_context *) src ); +} + +static int md2_process_wrap( void *ctx, const unsigned char *data ) +{ + ((void) data); + + return( mbedtls_internal_md2_process( (mbedtls_md2_context *) ctx ) ); +} + +const mbedtls_md_info_t mbedtls_md2_info = { + MBEDTLS_MD_MD2, + "MD2", + 16, + 16, + md2_starts_wrap, + md2_update_wrap, + md2_finish_wrap, + mbedtls_md2_ret, + md2_ctx_alloc, + md2_ctx_free, + md2_clone_wrap, + md2_process_wrap, +}; + +#endif /* MBEDTLS_MD2_C */ + +#if defined(MBEDTLS_MD4_C) + +static int md4_starts_wrap( void *ctx ) +{ + return( mbedtls_md4_starts_ret( (mbedtls_md4_context *) ctx ) ); +} + +static int md4_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + return( mbedtls_md4_update_ret( (mbedtls_md4_context *) ctx, input, ilen ) ); +} + +static int md4_finish_wrap( void *ctx, unsigned char *output ) +{ + return( mbedtls_md4_finish_ret( (mbedtls_md4_context *) ctx, output ) ); +} + +static void *md4_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md4_context ) ); + + if( ctx != NULL ) + mbedtls_md4_init( (mbedtls_md4_context *) ctx ); + + return( ctx ); +} + +static void md4_ctx_free( void *ctx ) +{ + mbedtls_md4_free( (mbedtls_md4_context *) ctx ); + mbedtls_free( ctx ); +} + +static void md4_clone_wrap( void *dst, const void *src ) +{ + mbedtls_md4_clone( (mbedtls_md4_context *) dst, + (const mbedtls_md4_context *) src ); +} + +static int md4_process_wrap( void *ctx, const unsigned char *data ) +{ + return( mbedtls_internal_md4_process( (mbedtls_md4_context *) ctx, data ) ); +} + +const mbedtls_md_info_t mbedtls_md4_info = { + MBEDTLS_MD_MD4, + "MD4", + 16, + 64, + md4_starts_wrap, + md4_update_wrap, + md4_finish_wrap, + mbedtls_md4_ret, + md4_ctx_alloc, + md4_ctx_free, + md4_clone_wrap, + md4_process_wrap, +}; + +#endif /* MBEDTLS_MD4_C */ + +#if defined(MBEDTLS_MD5_C) + +static int md5_starts_wrap( void *ctx ) +{ + return( mbedtls_md5_starts_ret( (mbedtls_md5_context *) ctx ) ); +} + +static int md5_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + return( mbedtls_md5_update_ret( (mbedtls_md5_context *) ctx, input, ilen ) ); +} + +static int md5_finish_wrap( void *ctx, unsigned char *output ) +{ + return( mbedtls_md5_finish_ret( (mbedtls_md5_context *) ctx, output ) ); +} + +static void *md5_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md5_context ) ); + + if( ctx != NULL ) + mbedtls_md5_init( (mbedtls_md5_context *) ctx ); + + return( ctx ); +} + +static void md5_ctx_free( void *ctx ) +{ + mbedtls_md5_free( (mbedtls_md5_context *) ctx ); + mbedtls_free( ctx ); +} + +static void md5_clone_wrap( void *dst, const void *src ) +{ + mbedtls_md5_clone( (mbedtls_md5_context *) dst, + (const mbedtls_md5_context *) src ); +} + +static int md5_process_wrap( void *ctx, const unsigned char *data ) +{ + return( mbedtls_internal_md5_process( (mbedtls_md5_context *) ctx, data ) ); +} + +const mbedtls_md_info_t mbedtls_md5_info = { + MBEDTLS_MD_MD5, + "MD5", + 16, + 64, + md5_starts_wrap, + md5_update_wrap, + md5_finish_wrap, + mbedtls_md5_ret, + md5_ctx_alloc, + md5_ctx_free, + md5_clone_wrap, + md5_process_wrap, +}; + +#endif /* MBEDTLS_MD5_C */ + +#if defined(MBEDTLS_RIPEMD160_C) + +static int ripemd160_starts_wrap( void *ctx ) +{ + return( mbedtls_ripemd160_starts_ret( (mbedtls_ripemd160_context *) ctx ) ); +} + +static int ripemd160_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + return( mbedtls_ripemd160_update_ret( (mbedtls_ripemd160_context *) ctx, + input, ilen ) ); +} + +static int ripemd160_finish_wrap( void *ctx, unsigned char *output ) +{ + return( mbedtls_ripemd160_finish_ret( (mbedtls_ripemd160_context *) ctx, + output ) ); +} + +static void *ripemd160_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ripemd160_context ) ); + + if( ctx != NULL ) + mbedtls_ripemd160_init( (mbedtls_ripemd160_context *) ctx ); + + return( ctx ); +} + +static void ripemd160_ctx_free( void *ctx ) +{ + mbedtls_ripemd160_free( (mbedtls_ripemd160_context *) ctx ); + mbedtls_free( ctx ); +} + +static void ripemd160_clone_wrap( void *dst, const void *src ) +{ + mbedtls_ripemd160_clone( (mbedtls_ripemd160_context *) dst, + (const mbedtls_ripemd160_context *) src ); +} + +static int ripemd160_process_wrap( void *ctx, const unsigned char *data ) +{ + return( mbedtls_internal_ripemd160_process( + (mbedtls_ripemd160_context *) ctx, data ) ); +} + +const mbedtls_md_info_t mbedtls_ripemd160_info = { + MBEDTLS_MD_RIPEMD160, + "RIPEMD160", + 20, + 64, + ripemd160_starts_wrap, + ripemd160_update_wrap, + ripemd160_finish_wrap, + mbedtls_ripemd160_ret, + ripemd160_ctx_alloc, + ripemd160_ctx_free, + ripemd160_clone_wrap, + ripemd160_process_wrap, +}; + +#endif /* MBEDTLS_RIPEMD160_C */ + +#if defined(MBEDTLS_SHA1_C) + +static int sha1_starts_wrap( void *ctx ) +{ + return( mbedtls_sha1_starts_ret( (mbedtls_sha1_context *) ctx ) ); +} + +static int sha1_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + return( mbedtls_sha1_update_ret( (mbedtls_sha1_context *) ctx, + input, ilen ) ); +} + +static int sha1_finish_wrap( void *ctx, unsigned char *output ) +{ + return( mbedtls_sha1_finish_ret( (mbedtls_sha1_context *) ctx, output ) ); +} + +static void *sha1_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha1_context ) ); + + if( ctx != NULL ) + mbedtls_sha1_init( (mbedtls_sha1_context *) ctx ); + + return( ctx ); +} + +static void sha1_clone_wrap( void *dst, const void *src ) +{ + mbedtls_sha1_clone( (mbedtls_sha1_context *) dst, + (const mbedtls_sha1_context *) src ); +} + +static void sha1_ctx_free( void *ctx ) +{ + mbedtls_sha1_free( (mbedtls_sha1_context *) ctx ); + mbedtls_free( ctx ); +} + +static int sha1_process_wrap( void *ctx, const unsigned char *data ) +{ + return( mbedtls_internal_sha1_process( (mbedtls_sha1_context *) ctx, + data ) ); +} + +const mbedtls_md_info_t mbedtls_sha1_info = { + MBEDTLS_MD_SHA1, + "SHA1", + 20, + 64, + sha1_starts_wrap, + sha1_update_wrap, + sha1_finish_wrap, + mbedtls_sha1_ret, + sha1_ctx_alloc, + sha1_ctx_free, + sha1_clone_wrap, + sha1_process_wrap, +}; + +#endif /* MBEDTLS_SHA1_C */ + +/* + * Wrappers for generic message digests + */ +#if defined(MBEDTLS_SHA256_C) + +static int sha224_starts_wrap( void *ctx ) +{ + return( mbedtls_sha256_starts_ret( (mbedtls_sha256_context *) ctx, 1 ) ); +} + +static int sha224_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + return( mbedtls_sha256_update_ret( (mbedtls_sha256_context *) ctx, + input, ilen ) ); +} + +static int sha224_finish_wrap( void *ctx, unsigned char *output ) +{ + return( mbedtls_sha256_finish_ret( (mbedtls_sha256_context *) ctx, + output ) ); +} + +static int sha224_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + return( mbedtls_sha256_ret( input, ilen, output, 1 ) ); +} + +static void *sha224_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha256_context ) ); + + if( ctx != NULL ) + mbedtls_sha256_init( (mbedtls_sha256_context *) ctx ); + + return( ctx ); +} + +static void sha224_ctx_free( void *ctx ) +{ + mbedtls_sha256_free( (mbedtls_sha256_context *) ctx ); + mbedtls_free( ctx ); +} + +static void sha224_clone_wrap( void *dst, const void *src ) +{ + mbedtls_sha256_clone( (mbedtls_sha256_context *) dst, + (const mbedtls_sha256_context *) src ); +} + +static int sha224_process_wrap( void *ctx, const unsigned char *data ) +{ + return( mbedtls_internal_sha256_process( (mbedtls_sha256_context *) ctx, + data ) ); +} + +const mbedtls_md_info_t mbedtls_sha224_info = { + MBEDTLS_MD_SHA224, + "SHA224", + 28, + 64, + sha224_starts_wrap, + sha224_update_wrap, + sha224_finish_wrap, + sha224_wrap, + sha224_ctx_alloc, + sha224_ctx_free, + sha224_clone_wrap, + sha224_process_wrap, +}; + +static int sha256_starts_wrap( void *ctx ) +{ + return( mbedtls_sha256_starts_ret( (mbedtls_sha256_context *) ctx, 0 ) ); +} + +static int sha256_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + return( mbedtls_sha256_ret( input, ilen, output, 0 ) ); +} + +const mbedtls_md_info_t mbedtls_sha256_info = { + MBEDTLS_MD_SHA256, + "SHA256", + 32, + 64, + sha256_starts_wrap, + sha224_update_wrap, + sha224_finish_wrap, + sha256_wrap, + sha224_ctx_alloc, + sha224_ctx_free, + sha224_clone_wrap, + sha224_process_wrap, +}; + +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + +static int sha384_starts_wrap( void *ctx ) +{ + return( mbedtls_sha512_starts_ret( (mbedtls_sha512_context *) ctx, 1 ) ); +} + +static int sha384_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + return( mbedtls_sha512_update_ret( (mbedtls_sha512_context *) ctx, + input, ilen ) ); +} + +static int sha384_finish_wrap( void *ctx, unsigned char *output ) +{ + return( mbedtls_sha512_finish_ret( (mbedtls_sha512_context *) ctx, + output ) ); +} + +static int sha384_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + return( mbedtls_sha512_ret( input, ilen, output, 1 ) ); +} + +static void *sha384_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha512_context ) ); + + if( ctx != NULL ) + mbedtls_sha512_init( (mbedtls_sha512_context *) ctx ); + + return( ctx ); +} + +static void sha384_ctx_free( void *ctx ) +{ + mbedtls_sha512_free( (mbedtls_sha512_context *) ctx ); + mbedtls_free( ctx ); +} + +static void sha384_clone_wrap( void *dst, const void *src ) +{ + mbedtls_sha512_clone( (mbedtls_sha512_context *) dst, + (const mbedtls_sha512_context *) src ); +} + +static int sha384_process_wrap( void *ctx, const unsigned char *data ) +{ + return( mbedtls_internal_sha512_process( (mbedtls_sha512_context *) ctx, + data ) ); +} + +const mbedtls_md_info_t mbedtls_sha384_info = { + MBEDTLS_MD_SHA384, + "SHA384", + 48, + 128, + sha384_starts_wrap, + sha384_update_wrap, + sha384_finish_wrap, + sha384_wrap, + sha384_ctx_alloc, + sha384_ctx_free, + sha384_clone_wrap, + sha384_process_wrap, +}; + +static int sha512_starts_wrap( void *ctx ) +{ + return( mbedtls_sha512_starts_ret( (mbedtls_sha512_context *) ctx, 0 ) ); +} + +static int sha512_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + return( mbedtls_sha512_ret( input, ilen, output, 0 ) ); +} + +const mbedtls_md_info_t mbedtls_sha512_info = { + MBEDTLS_MD_SHA512, + "SHA512", + 64, + 128, + sha512_starts_wrap, + sha384_update_wrap, + sha384_finish_wrap, + sha512_wrap, + sha384_ctx_alloc, + sha384_ctx_free, + sha384_clone_wrap, + sha384_process_wrap, +}; + +#endif /* MBEDTLS_SHA512_C */ + +#endif /* MBEDTLS_MD_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/memory_buffer_alloc.c b/FreeRTOS-Labs/Source/mbedtls/library/memory_buffer_alloc.c new file mode 100644 index 000000000..70676ccf0 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/memory_buffer_alloc.c @@ -0,0 +1,750 @@ +/* + * Buffer-based memory allocator + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) +#include "mbedtls/memory_buffer_alloc.h" + +/* No need for the header guard as MBEDTLS_MEMORY_BUFFER_ALLOC_C + is dependent upon MBEDTLS_PLATFORM_C */ +#include "mbedtls/platform.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_MEMORY_BACKTRACE) +#include +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +#define MAGIC1 0xFF00AA55 +#define MAGIC2 0xEE119966 +#define MAX_BT 20 + +typedef struct _memory_header memory_header; +struct _memory_header +{ + size_t magic1; + size_t size; + size_t alloc; + memory_header *prev; + memory_header *next; + memory_header *prev_free; + memory_header *next_free; +#if defined(MBEDTLS_MEMORY_BACKTRACE) + char **trace; + size_t trace_count; +#endif + size_t magic2; +}; + +typedef struct +{ + unsigned char *buf; + size_t len; + memory_header *first; + memory_header *first_free; + int verify; +#if defined(MBEDTLS_MEMORY_DEBUG) + size_t alloc_count; + size_t free_count; + size_t total_used; + size_t maximum_used; + size_t header_count; + size_t maximum_header_count; +#endif +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} +buffer_alloc_ctx; + +static buffer_alloc_ctx heap; + +#if defined(MBEDTLS_MEMORY_DEBUG) +static void debug_header( memory_header *hdr ) +{ +#if defined(MBEDTLS_MEMORY_BACKTRACE) + size_t i; +#endif + + mbedtls_fprintf( stderr, "HDR: PTR(%10zu), PREV(%10zu), NEXT(%10zu), " + "ALLOC(%zu), SIZE(%10zu)\n", + (size_t) hdr, (size_t) hdr->prev, (size_t) hdr->next, + hdr->alloc, hdr->size ); + mbedtls_fprintf( stderr, " FPREV(%10zu), FNEXT(%10zu)\n", + (size_t) hdr->prev_free, (size_t) hdr->next_free ); + +#if defined(MBEDTLS_MEMORY_BACKTRACE) + mbedtls_fprintf( stderr, "TRACE: \n" ); + for( i = 0; i < hdr->trace_count; i++ ) + mbedtls_fprintf( stderr, "%s\n", hdr->trace[i] ); + mbedtls_fprintf( stderr, "\n" ); +#endif +} + +static void debug_chain( void ) +{ + memory_header *cur = heap.first; + + mbedtls_fprintf( stderr, "\nBlock list\n" ); + while( cur != NULL ) + { + debug_header( cur ); + cur = cur->next; + } + + mbedtls_fprintf( stderr, "Free list\n" ); + cur = heap.first_free; + + while( cur != NULL ) + { + debug_header( cur ); + cur = cur->next_free; + } +} +#endif /* MBEDTLS_MEMORY_DEBUG */ + +static int verify_header( memory_header *hdr ) +{ + if( hdr->magic1 != MAGIC1 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: MAGIC1 mismatch\n" ); +#endif + return( 1 ); + } + + if( hdr->magic2 != MAGIC2 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: MAGIC2 mismatch\n" ); +#endif + return( 1 ); + } + + if( hdr->alloc > 1 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: alloc has illegal value\n" ); +#endif + return( 1 ); + } + + if( hdr->prev != NULL && hdr->prev == hdr->next ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: prev == next\n" ); +#endif + return( 1 ); + } + + if( hdr->prev_free != NULL && hdr->prev_free == hdr->next_free ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: prev_free == next_free\n" ); +#endif + return( 1 ); + } + + return( 0 ); +} + +static int verify_chain( void ) +{ + memory_header *prv = heap.first, *cur; + + if( prv == NULL || verify_header( prv ) != 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: verification of first header " + "failed\n" ); +#endif + return( 1 ); + } + + if( heap.first->prev != NULL ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: verification failed: " + "first->prev != NULL\n" ); +#endif + return( 1 ); + } + + cur = heap.first->next; + + while( cur != NULL ) + { + if( verify_header( cur ) != 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: verification of header " + "failed\n" ); +#endif + return( 1 ); + } + + if( cur->prev != prv ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: verification failed: " + "cur->prev != prv\n" ); +#endif + return( 1 ); + } + + prv = cur; + cur = cur->next; + } + + return( 0 ); +} + +static void *buffer_alloc_calloc( size_t n, size_t size ) +{ + memory_header *new, *cur = heap.first_free; + unsigned char *p; + void *ret; + size_t original_len, len; +#if defined(MBEDTLS_MEMORY_BACKTRACE) + void *trace_buffer[MAX_BT]; + size_t trace_cnt; +#endif + + if( heap.buf == NULL || heap.first == NULL ) + return( NULL ); + + original_len = len = n * size; + + if( n == 0 || size == 0 || len / n != size ) + return( NULL ); + else if( len > (size_t)-MBEDTLS_MEMORY_ALIGN_MULTIPLE ) + return( NULL ); + + if( len % MBEDTLS_MEMORY_ALIGN_MULTIPLE ) + { + len -= len % MBEDTLS_MEMORY_ALIGN_MULTIPLE; + len += MBEDTLS_MEMORY_ALIGN_MULTIPLE; + } + + // Find block that fits + // + while( cur != NULL ) + { + if( cur->size >= len ) + break; + + cur = cur->next_free; + } + + if( cur == NULL ) + return( NULL ); + + if( cur->alloc != 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: block in free_list but allocated " + "data\n" ); +#endif + mbedtls_exit( 1 ); + } + +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.alloc_count++; +#endif + + // Found location, split block if > memory_header + 4 room left + // + if( cur->size - len < sizeof(memory_header) + + MBEDTLS_MEMORY_ALIGN_MULTIPLE ) + { + cur->alloc = 1; + + // Remove from free_list + // + if( cur->prev_free != NULL ) + cur->prev_free->next_free = cur->next_free; + else + heap.first_free = cur->next_free; + + if( cur->next_free != NULL ) + cur->next_free->prev_free = cur->prev_free; + + cur->prev_free = NULL; + cur->next_free = NULL; + +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.total_used += cur->size; + if( heap.total_used > heap.maximum_used ) + heap.maximum_used = heap.total_used; +#endif +#if defined(MBEDTLS_MEMORY_BACKTRACE) + trace_cnt = backtrace( trace_buffer, MAX_BT ); + cur->trace = backtrace_symbols( trace_buffer, trace_cnt ); + cur->trace_count = trace_cnt; +#endif + + if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 ) + mbedtls_exit( 1 ); + + ret = (unsigned char *) cur + sizeof( memory_header ); + memset( ret, 0, original_len ); + + return( ret ); + } + + p = ( (unsigned char *) cur ) + sizeof(memory_header) + len; + new = (memory_header *) p; + + new->size = cur->size - len - sizeof(memory_header); + new->alloc = 0; + new->prev = cur; + new->next = cur->next; +#if defined(MBEDTLS_MEMORY_BACKTRACE) + new->trace = NULL; + new->trace_count = 0; +#endif + new->magic1 = MAGIC1; + new->magic2 = MAGIC2; + + if( new->next != NULL ) + new->next->prev = new; + + // Replace cur with new in free_list + // + new->prev_free = cur->prev_free; + new->next_free = cur->next_free; + if( new->prev_free != NULL ) + new->prev_free->next_free = new; + else + heap.first_free = new; + + if( new->next_free != NULL ) + new->next_free->prev_free = new; + + cur->alloc = 1; + cur->size = len; + cur->next = new; + cur->prev_free = NULL; + cur->next_free = NULL; + +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.header_count++; + if( heap.header_count > heap.maximum_header_count ) + heap.maximum_header_count = heap.header_count; + heap.total_used += cur->size; + if( heap.total_used > heap.maximum_used ) + heap.maximum_used = heap.total_used; +#endif +#if defined(MBEDTLS_MEMORY_BACKTRACE) + trace_cnt = backtrace( trace_buffer, MAX_BT ); + cur->trace = backtrace_symbols( trace_buffer, trace_cnt ); + cur->trace_count = trace_cnt; +#endif + + if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 ) + mbedtls_exit( 1 ); + + ret = (unsigned char *) cur + sizeof( memory_header ); + memset( ret, 0, original_len ); + + return( ret ); +} + +static void buffer_alloc_free( void *ptr ) +{ + memory_header *hdr, *old = NULL; + unsigned char *p = (unsigned char *) ptr; + + if( ptr == NULL || heap.buf == NULL || heap.first == NULL ) + return; + + if( p < heap.buf || p >= heap.buf + heap.len ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: mbedtls_free() outside of managed " + "space\n" ); +#endif + mbedtls_exit( 1 ); + } + + p -= sizeof(memory_header); + hdr = (memory_header *) p; + + if( verify_header( hdr ) != 0 ) + mbedtls_exit( 1 ); + + if( hdr->alloc != 1 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: mbedtls_free() on unallocated " + "data\n" ); +#endif + mbedtls_exit( 1 ); + } + + hdr->alloc = 0; + +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.free_count++; + heap.total_used -= hdr->size; +#endif + +#if defined(MBEDTLS_MEMORY_BACKTRACE) + free( hdr->trace ); + hdr->trace = NULL; + hdr->trace_count = 0; +#endif + + // Regroup with block before + // + if( hdr->prev != NULL && hdr->prev->alloc == 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.header_count--; +#endif + hdr->prev->size += sizeof(memory_header) + hdr->size; + hdr->prev->next = hdr->next; + old = hdr; + hdr = hdr->prev; + + if( hdr->next != NULL ) + hdr->next->prev = hdr; + + memset( old, 0, sizeof(memory_header) ); + } + + // Regroup with block after + // + if( hdr->next != NULL && hdr->next->alloc == 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.header_count--; +#endif + hdr->size += sizeof(memory_header) + hdr->next->size; + old = hdr->next; + hdr->next = hdr->next->next; + + if( hdr->prev_free != NULL || hdr->next_free != NULL ) + { + if( hdr->prev_free != NULL ) + hdr->prev_free->next_free = hdr->next_free; + else + heap.first_free = hdr->next_free; + + if( hdr->next_free != NULL ) + hdr->next_free->prev_free = hdr->prev_free; + } + + hdr->prev_free = old->prev_free; + hdr->next_free = old->next_free; + + if( hdr->prev_free != NULL ) + hdr->prev_free->next_free = hdr; + else + heap.first_free = hdr; + + if( hdr->next_free != NULL ) + hdr->next_free->prev_free = hdr; + + if( hdr->next != NULL ) + hdr->next->prev = hdr; + + memset( old, 0, sizeof(memory_header) ); + } + + // Prepend to free_list if we have not merged + // (Does not have to stay in same order as prev / next list) + // + if( old == NULL ) + { + hdr->next_free = heap.first_free; + if( heap.first_free != NULL ) + heap.first_free->prev_free = hdr; + heap.first_free = hdr; + } + + if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_FREE ) && verify_chain() != 0 ) + mbedtls_exit( 1 ); +} + +void mbedtls_memory_buffer_set_verify( int verify ) +{ + heap.verify = verify; +} + +int mbedtls_memory_buffer_alloc_verify( void ) +{ + return verify_chain(); +} + +#if defined(MBEDTLS_MEMORY_DEBUG) +void mbedtls_memory_buffer_alloc_status( void ) +{ + mbedtls_fprintf( stderr, + "Current use: %zu blocks / %zu bytes, max: %zu blocks / " + "%zu bytes (total %zu bytes), alloc / free: %zu / %zu\n", + heap.header_count, heap.total_used, + heap.maximum_header_count, heap.maximum_used, + heap.maximum_header_count * sizeof( memory_header ) + + heap.maximum_used, + heap.alloc_count, heap.free_count ); + + if( heap.first->next == NULL ) + { + mbedtls_fprintf( stderr, "All memory de-allocated in stack buffer\n" ); + } + else + { + mbedtls_fprintf( stderr, "Memory currently allocated:\n" ); + debug_chain(); + } +} + +void mbedtls_memory_buffer_alloc_max_get( size_t *max_used, size_t *max_blocks ) +{ + *max_used = heap.maximum_used; + *max_blocks = heap.maximum_header_count; +} + +void mbedtls_memory_buffer_alloc_max_reset( void ) +{ + heap.maximum_used = 0; + heap.maximum_header_count = 0; +} + +void mbedtls_memory_buffer_alloc_cur_get( size_t *cur_used, size_t *cur_blocks ) +{ + *cur_used = heap.total_used; + *cur_blocks = heap.header_count; +} +#endif /* MBEDTLS_MEMORY_DEBUG */ + +#if defined(MBEDTLS_THREADING_C) +static void *buffer_alloc_calloc_mutexed( size_t n, size_t size ) +{ + void *buf; + if( mbedtls_mutex_lock( &heap.mutex ) != 0 ) + return( NULL ); + buf = buffer_alloc_calloc( n, size ); + if( mbedtls_mutex_unlock( &heap.mutex ) ) + return( NULL ); + return( buf ); +} + +static void buffer_alloc_free_mutexed( void *ptr ) +{ + /* We have to good option here, but corrupting the heap seems + * worse than loosing memory. */ + if( mbedtls_mutex_lock( &heap.mutex ) ) + return; + buffer_alloc_free( ptr ); + (void) mbedtls_mutex_unlock( &heap.mutex ); +} +#endif /* MBEDTLS_THREADING_C */ + +void mbedtls_memory_buffer_alloc_init( unsigned char *buf, size_t len ) +{ + memset( &heap, 0, sizeof( buffer_alloc_ctx ) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &heap.mutex ); + mbedtls_platform_set_calloc_free( buffer_alloc_calloc_mutexed, + buffer_alloc_free_mutexed ); +#else + mbedtls_platform_set_calloc_free( buffer_alloc_calloc, buffer_alloc_free ); +#endif + + if( len < sizeof( memory_header ) + MBEDTLS_MEMORY_ALIGN_MULTIPLE ) + return; + else if( (size_t)buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE ) + { + /* Adjust len first since buf is used in the computation */ + len -= MBEDTLS_MEMORY_ALIGN_MULTIPLE + - (size_t)buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE; + buf += MBEDTLS_MEMORY_ALIGN_MULTIPLE + - (size_t)buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE; + } + + memset( buf, 0, len ); + + heap.buf = buf; + heap.len = len; + + heap.first = (memory_header *)buf; + heap.first->size = len - sizeof( memory_header ); + heap.first->magic1 = MAGIC1; + heap.first->magic2 = MAGIC2; + heap.first_free = heap.first; +} + +void mbedtls_memory_buffer_alloc_free( void ) +{ +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &heap.mutex ); +#endif + mbedtls_platform_zeroize( &heap, sizeof(buffer_alloc_ctx) ); +} + +#if defined(MBEDTLS_SELF_TEST) +static int check_pointer( void *p ) +{ + if( p == NULL ) + return( -1 ); + + if( (size_t) p % MBEDTLS_MEMORY_ALIGN_MULTIPLE != 0 ) + return( -1 ); + + return( 0 ); +} + +static int check_all_free( void ) +{ + if( +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.total_used != 0 || +#endif + heap.first != heap.first_free || + (void *) heap.first != (void *) heap.buf ) + { + return( -1 ); + } + + return( 0 ); +} + +#define TEST_ASSERT( condition ) \ + if( ! (condition) ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf( "failed\n" ); \ + \ + ret = 1; \ + goto cleanup; \ + } + +int mbedtls_memory_buffer_alloc_self_test( int verbose ) +{ + unsigned char buf[1024]; + unsigned char *p, *q, *r, *end; + int ret = 0; + + if( verbose != 0 ) + mbedtls_printf( " MBA test #1 (basic alloc-free cycle): " ); + + mbedtls_memory_buffer_alloc_init( buf, sizeof( buf ) ); + + p = mbedtls_calloc( 1, 1 ); + q = mbedtls_calloc( 1, 128 ); + r = mbedtls_calloc( 1, 16 ); + + TEST_ASSERT( check_pointer( p ) == 0 && + check_pointer( q ) == 0 && + check_pointer( r ) == 0 ); + + mbedtls_free( r ); + mbedtls_free( q ); + mbedtls_free( p ); + + TEST_ASSERT( check_all_free( ) == 0 ); + + /* Memorize end to compare with the next test */ + end = heap.buf + heap.len; + + mbedtls_memory_buffer_alloc_free( ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " MBA test #2 (buf not aligned): " ); + + mbedtls_memory_buffer_alloc_init( buf + 1, sizeof( buf ) - 1 ); + + TEST_ASSERT( heap.buf + heap.len == end ); + + p = mbedtls_calloc( 1, 1 ); + q = mbedtls_calloc( 1, 128 ); + r = mbedtls_calloc( 1, 16 ); + + TEST_ASSERT( check_pointer( p ) == 0 && + check_pointer( q ) == 0 && + check_pointer( r ) == 0 ); + + mbedtls_free( r ); + mbedtls_free( q ); + mbedtls_free( p ); + + TEST_ASSERT( check_all_free( ) == 0 ); + + mbedtls_memory_buffer_alloc_free( ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " MBA test #3 (full): " ); + + mbedtls_memory_buffer_alloc_init( buf, sizeof( buf ) ); + + p = mbedtls_calloc( 1, sizeof( buf ) - sizeof( memory_header ) ); + + TEST_ASSERT( check_pointer( p ) == 0 ); + TEST_ASSERT( mbedtls_calloc( 1, 1 ) == NULL ); + + mbedtls_free( p ); + + p = mbedtls_calloc( 1, sizeof( buf ) - 2 * sizeof( memory_header ) - 16 ); + q = mbedtls_calloc( 1, 16 ); + + TEST_ASSERT( check_pointer( p ) == 0 && check_pointer( q ) == 0 ); + TEST_ASSERT( mbedtls_calloc( 1, 1 ) == NULL ); + + mbedtls_free( q ); + + TEST_ASSERT( mbedtls_calloc( 1, 17 ) == NULL ); + + mbedtls_free( p ); + + TEST_ASSERT( check_all_free( ) == 0 ); + + mbedtls_memory_buffer_alloc_free( ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +cleanup: + mbedtls_memory_buffer_alloc_free( ); + + return( ret ); +} +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/net_sockets.c b/FreeRTOS-Labs/Source/mbedtls/library/net_sockets.c new file mode 100644 index 000000000..7bb27bd1b --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/net_sockets.c @@ -0,0 +1,668 @@ +/* + * TCP/IP or UDP/IP networking functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* Enable definition of getaddrinfo() even when compiling with -std=c99. Must + * be set before config.h, which pulls in glibc's features.h indirectly. + * Harmless on other platforms. */ +#define _POSIX_C_SOURCE 200112L + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_NET_C) + +#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ + !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ + !defined(__HAIKU__) +#error "This module only works on Unix and Windows, see MBEDTLS_NET_C in config.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#endif + +#include "mbedtls/net_sockets.h" + +#include + +#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ + !defined(EFI32) + +#define IS_EINTR( ret ) ( ( ret ) == WSAEINTR ) + +#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0501) +#undef _WIN32_WINNT +/* Enables getaddrinfo() & Co */ +#define _WIN32_WINNT 0x0501 +#endif + +#include + +#include +#include + +#if defined(_MSC_VER) +#if defined(_WIN32_WCE) +#pragma comment( lib, "ws2.lib" ) +#else +#pragma comment( lib, "ws2_32.lib" ) +#endif +#endif /* _MSC_VER */ + +#define read(fd,buf,len) recv( fd, (char*)( buf ), (int)( len ), 0 ) +#define write(fd,buf,len) send( fd, (char*)( buf ), (int)( len ), 0 ) +#define close(fd) closesocket(fd) + +static int wsa_init_done = 0; + +#else /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IS_EINTR( ret ) ( ( ret ) == EINTR ) + +#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ + +/* Some MS functions want int and MSVC warns if we pass size_t, + * but the standard functions use socklen_t, so cast only for MSVC */ +#if defined(_MSC_VER) +#define MSVC_INT_CAST (int) +#else +#define MSVC_INT_CAST +#endif + +#include + +#include + +#include + +/* + * Prepare for using the sockets interface + */ +static int net_prepare( void ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + WSADATA wsaData; + + if( wsa_init_done == 0 ) + { + if( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 ) + return( MBEDTLS_ERR_NET_SOCKET_FAILED ); + + wsa_init_done = 1; + } +#else +#if !defined(EFIX64) && !defined(EFI32) + signal( SIGPIPE, SIG_IGN ); +#endif +#endif + return( 0 ); +} + +/* + * Initialize a context + */ +void mbedtls_net_init( mbedtls_net_context *ctx ) +{ + ctx->fd = -1; +} + +/* + * Initiate a TCP connection with host:port and the given protocol + */ +int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, + const char *port, int proto ) +{ + int ret; + struct addrinfo hints, *addr_list, *cur; + + if( ( ret = net_prepare() ) != 0 ) + return( ret ); + + /* Do name resolution with both IPv6 and IPv4 */ + memset( &hints, 0, sizeof( hints ) ); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; + + if( getaddrinfo( host, port, &hints, &addr_list ) != 0 ) + return( MBEDTLS_ERR_NET_UNKNOWN_HOST ); + + /* Try the sockaddrs until a connection succeeds */ + ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; + for( cur = addr_list; cur != NULL; cur = cur->ai_next ) + { + ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype, + cur->ai_protocol ); + if( ctx->fd < 0 ) + { + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + continue; + } + + if( connect( ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) == 0 ) + { + ret = 0; + break; + } + + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_CONNECT_FAILED; + } + + freeaddrinfo( addr_list ); + + return( ret ); +} + +/* + * Create a listening socket on bind_ip:port + */ +int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto ) +{ + int n, ret; + struct addrinfo hints, *addr_list, *cur; + + if( ( ret = net_prepare() ) != 0 ) + return( ret ); + + /* Bind to IPv6 and/or IPv4, but only in the desired protocol */ + memset( &hints, 0, sizeof( hints ) ); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; + if( bind_ip == NULL ) + hints.ai_flags = AI_PASSIVE; + + if( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 ) + return( MBEDTLS_ERR_NET_UNKNOWN_HOST ); + + /* Try the sockaddrs until a binding succeeds */ + ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; + for( cur = addr_list; cur != NULL; cur = cur->ai_next ) + { + ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype, + cur->ai_protocol ); + if( ctx->fd < 0 ) + { + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + continue; + } + + n = 1; + if( setsockopt( ctx->fd, SOL_SOCKET, SO_REUSEADDR, + (const char *) &n, sizeof( n ) ) != 0 ) + { + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + continue; + } + + if( bind( ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) != 0 ) + { + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_BIND_FAILED; + continue; + } + + /* Listen only makes sense for TCP */ + if( proto == MBEDTLS_NET_PROTO_TCP ) + { + if( listen( ctx->fd, MBEDTLS_NET_LISTEN_BACKLOG ) != 0 ) + { + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_LISTEN_FAILED; + continue; + } + } + + /* Bind was successful */ + ret = 0; + break; + } + + freeaddrinfo( addr_list ); + + return( ret ); + +} + +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) +/* + * Check if the requested operation would be blocking on a non-blocking socket + * and thus 'failed' with a negative return value. + */ +static int net_would_block( const mbedtls_net_context *ctx ) +{ + ((void) ctx); + return( WSAGetLastError() == WSAEWOULDBLOCK ); +} +#else +/* + * Check if the requested operation would be blocking on a non-blocking socket + * and thus 'failed' with a negative return value. + * + * Note: on a blocking socket this function always returns 0! + */ +static int net_would_block( const mbedtls_net_context *ctx ) +{ + int err = errno; + + /* + * Never return 'WOULD BLOCK' on a non-blocking socket + */ + if( ( fcntl( ctx->fd, F_GETFL ) & O_NONBLOCK ) != O_NONBLOCK ) + { + errno = err; + return( 0 ); + } + + switch( errno = err ) + { +#if defined EAGAIN + case EAGAIN: +#endif +#if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + return( 1 ); + } + return( 0 ); +} +#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ + +/* + * Accept a connection from a remote client + */ +int mbedtls_net_accept( mbedtls_net_context *bind_ctx, + mbedtls_net_context *client_ctx, + void *client_ip, size_t buf_size, size_t *ip_len ) +{ + int ret; + int type; + + struct sockaddr_storage client_addr; + +#if defined(__socklen_t_defined) || defined(_SOCKLEN_T) || \ + defined(_SOCKLEN_T_DECLARED) || defined(__DEFINED_socklen_t) + socklen_t n = (socklen_t) sizeof( client_addr ); + socklen_t type_len = (socklen_t) sizeof( type ); +#else + int n = (int) sizeof( client_addr ); + int type_len = (int) sizeof( type ); +#endif + + /* Is this a TCP or UDP socket? */ + if( getsockopt( bind_ctx->fd, SOL_SOCKET, SO_TYPE, + (void *) &type, &type_len ) != 0 || + ( type != SOCK_STREAM && type != SOCK_DGRAM ) ) + { + return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + } + + if( type == SOCK_STREAM ) + { + /* TCP: actual accept() */ + ret = client_ctx->fd = (int) accept( bind_ctx->fd, + (struct sockaddr *) &client_addr, &n ); + } + else + { + /* UDP: wait for a message, but keep it in the queue */ + char buf[1] = { 0 }; + + ret = (int) recvfrom( bind_ctx->fd, buf, sizeof( buf ), MSG_PEEK, + (struct sockaddr *) &client_addr, &n ); + +#if defined(_WIN32) + if( ret == SOCKET_ERROR && + WSAGetLastError() == WSAEMSGSIZE ) + { + /* We know buf is too small, thanks, just peeking here */ + ret = 0; + } +#endif + } + + if( ret < 0 ) + { + if( net_would_block( bind_ctx ) != 0 ) + return( MBEDTLS_ERR_SSL_WANT_READ ); + + return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + } + + /* UDP: hijack the listening socket to communicate with the client, + * then bind a new socket to accept new connections */ + if( type != SOCK_STREAM ) + { + struct sockaddr_storage local_addr; + int one = 1; + + if( connect( bind_ctx->fd, (struct sockaddr *) &client_addr, n ) != 0 ) + return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + + client_ctx->fd = bind_ctx->fd; + bind_ctx->fd = -1; /* In case we exit early */ + + n = sizeof( struct sockaddr_storage ); + if( getsockname( client_ctx->fd, + (struct sockaddr *) &local_addr, &n ) != 0 || + ( bind_ctx->fd = (int) socket( local_addr.ss_family, + SOCK_DGRAM, IPPROTO_UDP ) ) < 0 || + setsockopt( bind_ctx->fd, SOL_SOCKET, SO_REUSEADDR, + (const char *) &one, sizeof( one ) ) != 0 ) + { + return( MBEDTLS_ERR_NET_SOCKET_FAILED ); + } + + if( bind( bind_ctx->fd, (struct sockaddr *) &local_addr, n ) != 0 ) + { + return( MBEDTLS_ERR_NET_BIND_FAILED ); + } + } + + if( client_ip != NULL ) + { + if( client_addr.ss_family == AF_INET ) + { + struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr; + *ip_len = sizeof( addr4->sin_addr.s_addr ); + + if( buf_size < *ip_len ) + return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL ); + + memcpy( client_ip, &addr4->sin_addr.s_addr, *ip_len ); + } + else + { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr; + *ip_len = sizeof( addr6->sin6_addr.s6_addr ); + + if( buf_size < *ip_len ) + return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL ); + + memcpy( client_ip, &addr6->sin6_addr.s6_addr, *ip_len); + } + } + + return( 0 ); +} + +/* + * Set the socket blocking or non-blocking + */ +int mbedtls_net_set_block( mbedtls_net_context *ctx ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + u_long n = 0; + return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); +#else + return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL ) & ~O_NONBLOCK ) ); +#endif +} + +int mbedtls_net_set_nonblock( mbedtls_net_context *ctx ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + u_long n = 1; + return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); +#else + return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL ) | O_NONBLOCK ) ); +#endif +} + +/* + * Check if data is available on the socket + */ + +int mbedtls_net_poll( mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout ) +{ + int ret; + struct timeval tv; + + fd_set read_fds; + fd_set write_fds; + + int fd = ctx->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) + /* Ensure that memory sanitizers consider read_fds and write_fds as + * initialized even on platforms such as Glibc/x86_64 where FD_ZERO + * is implemented in assembly. */ + memset( &read_fds, 0, sizeof( read_fds ) ); + memset( &write_fds, 0, sizeof( write_fds ) ); +#endif +#endif + + FD_ZERO( &read_fds ); + if( rw & MBEDTLS_NET_POLL_READ ) + { + rw &= ~MBEDTLS_NET_POLL_READ; + FD_SET( fd, &read_fds ); + } + + FD_ZERO( &write_fds ); + if( rw & MBEDTLS_NET_POLL_WRITE ) + { + rw &= ~MBEDTLS_NET_POLL_WRITE; + FD_SET( fd, &write_fds ); + } + + if( rw != 0 ) + return( MBEDTLS_ERR_NET_BAD_INPUT_DATA ); + + tv.tv_sec = timeout / 1000; + tv.tv_usec = ( timeout % 1000 ) * 1000; + + do + { + ret = select( fd + 1, &read_fds, &write_fds, NULL, + timeout == (uint32_t) -1 ? NULL : &tv ); + } + while( IS_EINTR( ret ) ); + + if( ret < 0 ) + return( MBEDTLS_ERR_NET_POLL_FAILED ); + + ret = 0; + if( FD_ISSET( fd, &read_fds ) ) + ret |= MBEDTLS_NET_POLL_READ; + if( FD_ISSET( fd, &write_fds ) ) + ret |= MBEDTLS_NET_POLL_WRITE; + + return( ret ); +} + +/* + * Portable usleep helper + */ +void mbedtls_net_usleep( unsigned long usec ) +{ +#if defined(_WIN32) + Sleep( ( usec + 999 ) / 1000 ); +#else + struct timeval tv; + tv.tv_sec = usec / 1000000; +#if defined(__unix__) || defined(__unix) || \ + ( defined(__APPLE__) && defined(__MACH__) ) + tv.tv_usec = (suseconds_t) usec % 1000000; +#else + tv.tv_usec = usec % 1000000; +#endif + select( 0, NULL, NULL, NULL, &tv ); +#endif +} + +/* + * Read at most 'len' characters + */ +int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ) +{ + int ret; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + + ret = (int) read( fd, buf, len ); + + if( ret < 0 ) + { + if( net_would_block( ctx ) != 0 ) + return( MBEDTLS_ERR_SSL_WANT_READ ); + +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + if( WSAGetLastError() == WSAECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); +#else + if( errno == EPIPE || errno == ECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); + + if( errno == EINTR ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#endif + + return( MBEDTLS_ERR_NET_RECV_FAILED ); + } + + return( ret ); +} + +/* + * Read at most 'len' characters, blocking for at most 'timeout' ms + */ +int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, + size_t len, uint32_t timeout ) +{ + int ret; + struct timeval tv; + fd_set read_fds; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + + FD_ZERO( &read_fds ); + FD_SET( fd, &read_fds ); + + tv.tv_sec = timeout / 1000; + tv.tv_usec = ( timeout % 1000 ) * 1000; + + ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv ); + + /* Zero fds ready means we timed out */ + if( ret == 0 ) + return( MBEDTLS_ERR_SSL_TIMEOUT ); + + if( ret < 0 ) + { +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + if( WSAGetLastError() == WSAEINTR ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#else + if( errno == EINTR ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#endif + + return( MBEDTLS_ERR_NET_RECV_FAILED ); + } + + /* This call will not block */ + return( mbedtls_net_recv( ctx, buf, len ) ); +} + +/* + * Write at most 'len' characters + */ +int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ) +{ + int ret; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + + ret = (int) write( fd, buf, len ); + + if( ret < 0 ) + { + if( net_would_block( ctx ) != 0 ) + return( MBEDTLS_ERR_SSL_WANT_WRITE ); + +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + if( WSAGetLastError() == WSAECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); +#else + if( errno == EPIPE || errno == ECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); + + if( errno == EINTR ) + return( MBEDTLS_ERR_SSL_WANT_WRITE ); +#endif + + return( MBEDTLS_ERR_NET_SEND_FAILED ); + } + + return( ret ); +} + +/* + * Gracefully close the connection + */ +void mbedtls_net_free( mbedtls_net_context *ctx ) +{ + if( ctx->fd == -1 ) + return; + + shutdown( ctx->fd, 2 ); + close( ctx->fd ); + + ctx->fd = -1; +} + +#endif /* MBEDTLS_NET_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/nist_kw.c b/FreeRTOS-Labs/Source/mbedtls/library/nist_kw.c new file mode 100644 index 000000000..6f4bbea21 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/nist_kw.c @@ -0,0 +1,755 @@ +/* + * Implementation of NIST SP 800-38F key wrapping, supporting KW and KWP modes + * only + * + * Copyright (C) 2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +/* + * Definition of Key Wrapping: + * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf + * RFC 3394 "Advanced Encryption Standard (AES) Key Wrap Algorithm" + * RFC 5649 "Advanced Encryption Standard (AES) Key Wrap with Padding Algorithm" + * + * Note: RFC 3394 defines different methodology for intermediate operations for + * the wrapping and unwrapping operation than the definition in NIST SP 800-38F. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_NIST_KW_C) + +#include "mbedtls/nist_kw.h" +#include "mbedtls/platform_util.h" + +#include +#include + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#if !defined(MBEDTLS_NIST_KW_ALT) + +#define KW_SEMIBLOCK_LENGTH 8 +#define MIN_SEMIBLOCKS_COUNT 3 + +/* constant-time buffer comparison */ +static inline unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t n ) +{ + size_t i; + volatile const unsigned char *A = (volatile const unsigned char *) a; + volatile const unsigned char *B = (volatile const unsigned char *) b; + volatile unsigned char diff = 0; + + for( i = 0; i < n; i++ ) + { + /* Read volatile data in order before computing diff. + * This avoids IAR compiler warning: + * 'the order of volatile accesses is undefined ..' */ + unsigned char x = A[i], y = B[i]; + diff |= x ^ y; + } + + return( diff ); +} + +/*! The 64-bit default integrity check value (ICV) for KW mode. */ +static const unsigned char NIST_KW_ICV1[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6}; +/*! The 32-bit default integrity check value (ICV) for KWP mode. */ +static const unsigned char NIST_KW_ICV2[] = {0xA6, 0x59, 0x59, 0xA6}; + +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +do { \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} while( 0 ) +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +do { \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} while( 0 ) +#endif + +/* + * Initialize context + */ +void mbedtls_nist_kw_init( mbedtls_nist_kw_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_nist_kw_context ) ); +} + +int mbedtls_nist_kw_setkey( mbedtls_nist_kw_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits, + const int is_wrap ) +{ + int ret; + const mbedtls_cipher_info_t *cipher_info; + + cipher_info = mbedtls_cipher_info_from_values( cipher, + keybits, + MBEDTLS_MODE_ECB ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( cipher_info->block_size != 16 ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + /* + * SP 800-38F currently defines AES cipher as the only block cipher allowed: + * "For KW and KWP, the underlying block cipher shall be approved, and the + * block size shall be 128 bits. Currently, the AES block cipher, with key + * lengths of 128, 192, or 256 bits, is the only block cipher that fits + * this profile." + * Currently we don't support other 128 bit block ciphers for key wrapping, + * such as Camellia and Aria. + */ + if( cipher != MBEDTLS_CIPHER_ID_AES ) + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + + mbedtls_cipher_free( &ctx->cipher_ctx ); + + if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits, + is_wrap ? MBEDTLS_ENCRYPT : + MBEDTLS_DECRYPT ) + ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +/* + * Free context + */ +void mbedtls_nist_kw_free( mbedtls_nist_kw_context *ctx ) +{ + mbedtls_cipher_free( &ctx->cipher_ctx ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_nist_kw_context ) ); +} + +/* + * Helper function for Xoring the uint64_t "t" with the encrypted A. + * Defined in NIST SP 800-38F section 6.1 + */ +static void calc_a_xor_t( unsigned char A[KW_SEMIBLOCK_LENGTH], uint64_t t ) +{ + size_t i = 0; + for( i = 0; i < sizeof( t ); i++ ) + { + A[i] ^= ( t >> ( ( sizeof( t ) - 1 - i ) * 8 ) ) & 0xff; + } +} + +/* + * KW-AE as defined in SP 800-38F section 6.2 + * KWP-AE as defined in SP 800-38F section 6.3 + */ +int mbedtls_nist_kw_wrap( mbedtls_nist_kw_context *ctx, + mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t in_len, + unsigned char *output, size_t *out_len, size_t out_size ) +{ + int ret = 0; + size_t semiblocks = 0; + size_t s; + size_t olen, padlen = 0; + uint64_t t = 0; + unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2]; + unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2]; + unsigned char *R2 = output + KW_SEMIBLOCK_LENGTH; + unsigned char *A = output; + + *out_len = 0; + /* + * Generate the String to work on + */ + if( mode == MBEDTLS_KW_MODE_KW ) + { + if( out_size < in_len + KW_SEMIBLOCK_LENGTH ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + /* + * According to SP 800-38F Table 1, the plaintext length for KW + * must be between 2 to 2^54-1 semiblocks inclusive. + */ + if( in_len < 16 || +#if SIZE_MAX > 0x1FFFFFFFFFFFFF8 + in_len > 0x1FFFFFFFFFFFFF8 || +#endif + in_len % KW_SEMIBLOCK_LENGTH != 0 ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + memcpy( output, NIST_KW_ICV1, KW_SEMIBLOCK_LENGTH ); + memmove( output + KW_SEMIBLOCK_LENGTH, input, in_len ); + } + else + { + if( in_len % 8 != 0 ) + { + padlen = ( 8 - ( in_len % 8 ) ); + } + + if( out_size < in_len + KW_SEMIBLOCK_LENGTH + padlen ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + /* + * According to SP 800-38F Table 1, the plaintext length for KWP + * must be between 1 and 2^32-1 octets inclusive. + */ + if( in_len < 1 +#if SIZE_MAX > 0xFFFFFFFF + || in_len > 0xFFFFFFFF +#endif + ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + memcpy( output, NIST_KW_ICV2, KW_SEMIBLOCK_LENGTH / 2 ); + PUT_UINT32_BE( ( in_len & 0xffffffff ), output, + KW_SEMIBLOCK_LENGTH / 2 ); + + memcpy( output + KW_SEMIBLOCK_LENGTH, input, in_len ); + memset( output + KW_SEMIBLOCK_LENGTH + in_len, 0, padlen ); + } + semiblocks = ( ( in_len + padlen ) / KW_SEMIBLOCK_LENGTH ) + 1; + + s = 6 * ( semiblocks - 1 ); + + if( mode == MBEDTLS_KW_MODE_KWP + && in_len <= KW_SEMIBLOCK_LENGTH ) + { + memcpy( inbuff, output, 16 ); + ret = mbedtls_cipher_update( &ctx->cipher_ctx, + inbuff, 16, output, &olen ); + if( ret != 0 ) + goto cleanup; + } + else + { + /* + * Do the wrapping function W, as defined in RFC 3394 section 2.2.1 + */ + if( semiblocks < MIN_SEMIBLOCKS_COUNT ) + { + ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + goto cleanup; + } + + /* Calculate intermediate values */ + for( t = 1; t <= s; t++ ) + { + memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH ); + memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R2, KW_SEMIBLOCK_LENGTH ); + + ret = mbedtls_cipher_update( &ctx->cipher_ctx, + inbuff, 16, outbuff, &olen ); + if( ret != 0 ) + goto cleanup; + + memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH ); + calc_a_xor_t( A, t ); + + memcpy( R2, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH ); + R2 += KW_SEMIBLOCK_LENGTH; + if( R2 >= output + ( semiblocks * KW_SEMIBLOCK_LENGTH ) ) + R2 = output + KW_SEMIBLOCK_LENGTH; + } + } + + *out_len = semiblocks * KW_SEMIBLOCK_LENGTH; + +cleanup: + + if( ret != 0) + { + memset( output, 0, semiblocks * KW_SEMIBLOCK_LENGTH ); + } + mbedtls_platform_zeroize( inbuff, KW_SEMIBLOCK_LENGTH * 2 ); + mbedtls_platform_zeroize( outbuff, KW_SEMIBLOCK_LENGTH * 2 ); + + return( ret ); +} + +/* + * W-1 function as defined in RFC 3394 section 2.2.2 + * This function assumes the following: + * 1. Output buffer is at least of size ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH. + * 2. The input buffer is of size semiblocks * KW_SEMIBLOCK_LENGTH. + * 3. Minimal number of semiblocks is 3. + * 4. A is a buffer to hold the first semiblock of the input buffer. + */ +static int unwrap( mbedtls_nist_kw_context *ctx, + const unsigned char *input, size_t semiblocks, + unsigned char A[KW_SEMIBLOCK_LENGTH], + unsigned char *output, size_t* out_len ) +{ + int ret = 0; + const size_t s = 6 * ( semiblocks - 1 ); + size_t olen; + uint64_t t = 0; + unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2]; + unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2]; + unsigned char *R = output + ( semiblocks - 2 ) * KW_SEMIBLOCK_LENGTH; + *out_len = 0; + + if( semiblocks < MIN_SEMIBLOCKS_COUNT ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + memcpy( A, input, KW_SEMIBLOCK_LENGTH ); + memmove( output, input + KW_SEMIBLOCK_LENGTH, ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH ); + + /* Calculate intermediate values */ + for( t = s; t >= 1; t-- ) + { + calc_a_xor_t( A, t ); + + memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH ); + memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R, KW_SEMIBLOCK_LENGTH ); + + ret = mbedtls_cipher_update( &ctx->cipher_ctx, + inbuff, 16, outbuff, &olen ); + if( ret != 0 ) + goto cleanup; + + memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH ); + + /* Set R as LSB64 of outbuff */ + memcpy( R, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH ); + + if( R == output ) + R = output + ( semiblocks - 2 ) * KW_SEMIBLOCK_LENGTH; + else + R -= KW_SEMIBLOCK_LENGTH; + } + + *out_len = ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH; + +cleanup: + if( ret != 0) + memset( output, 0, ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH ); + mbedtls_platform_zeroize( inbuff, sizeof( inbuff ) ); + mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) ); + + return( ret ); +} + +/* + * KW-AD as defined in SP 800-38F section 6.2 + * KWP-AD as defined in SP 800-38F section 6.3 + */ +int mbedtls_nist_kw_unwrap( mbedtls_nist_kw_context *ctx, + mbedtls_nist_kw_mode_t mode, + const unsigned char *input, size_t in_len, + unsigned char *output, size_t *out_len, size_t out_size ) +{ + int ret = 0; + size_t i, olen; + unsigned char A[KW_SEMIBLOCK_LENGTH]; + unsigned char diff, bad_padding = 0; + + *out_len = 0; + if( out_size < in_len - KW_SEMIBLOCK_LENGTH ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + if( mode == MBEDTLS_KW_MODE_KW ) + { + /* + * According to SP 800-38F Table 1, the ciphertext length for KW + * must be between 3 to 2^54 semiblocks inclusive. + */ + if( in_len < 24 || +#if SIZE_MAX > 0x200000000000000 + in_len > 0x200000000000000 || +#endif + in_len % KW_SEMIBLOCK_LENGTH != 0 ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH, + A, output, out_len ); + if( ret != 0 ) + goto cleanup; + + /* Check ICV in "constant-time" */ + diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH ); + + if( diff != 0 ) + { + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + goto cleanup; + } + + } + else if( mode == MBEDTLS_KW_MODE_KWP ) + { + size_t padlen = 0; + uint32_t Plen; + /* + * According to SP 800-38F Table 1, the ciphertext length for KWP + * must be between 2 to 2^29 semiblocks inclusive. + */ + if( in_len < KW_SEMIBLOCK_LENGTH * 2 || +#if SIZE_MAX > 0x100000000 + in_len > 0x100000000 || +#endif + in_len % KW_SEMIBLOCK_LENGTH != 0 ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + if( in_len == KW_SEMIBLOCK_LENGTH * 2 ) + { + unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2]; + ret = mbedtls_cipher_update( &ctx->cipher_ctx, + input, 16, outbuff, &olen ); + if( ret != 0 ) + goto cleanup; + + memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH ); + memcpy( output, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH ); + mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) ); + *out_len = KW_SEMIBLOCK_LENGTH; + } + else + { + /* in_len >= KW_SEMIBLOCK_LENGTH * 3 */ + ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH, + A, output, out_len ); + if( ret != 0 ) + goto cleanup; + } + + /* Check ICV in "constant-time" */ + diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2 ); + + if( diff != 0 ) + { + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + } + + GET_UINT32_BE( Plen, A, KW_SEMIBLOCK_LENGTH / 2 ); + + /* + * Plen is the length of the plaintext, when the input is valid. + * If Plen is larger than the plaintext and padding, padlen will be + * larger than 8, because of the type wrap around. + */ + padlen = in_len - KW_SEMIBLOCK_LENGTH - Plen; + if ( padlen > 7 ) + { + padlen &= 7; + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + } + + /* Check padding in "constant-time" */ + for( diff = 0, i = 0; i < KW_SEMIBLOCK_LENGTH; i++ ) + { + if( i >= KW_SEMIBLOCK_LENGTH - padlen ) + diff |= output[*out_len - KW_SEMIBLOCK_LENGTH + i]; + else + bad_padding |= output[*out_len - KW_SEMIBLOCK_LENGTH + i]; + } + + if( diff != 0 ) + { + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + } + + if( ret != 0 ) + { + goto cleanup; + } + memset( output + Plen, 0, padlen ); + *out_len = Plen; + } + else + { + ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + goto cleanup; + } + +cleanup: + if( ret != 0 ) + { + memset( output, 0, *out_len ); + *out_len = 0; + } + + mbedtls_platform_zeroize( &bad_padding, sizeof( bad_padding) ); + mbedtls_platform_zeroize( &diff, sizeof( diff ) ); + mbedtls_platform_zeroize( A, sizeof( A ) ); + + return( ret ); +} + +#endif /* !MBEDTLS_NIST_KW_ALT */ + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) + +#define KW_TESTS 3 + +/* + * Test vectors taken from NIST + * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/CAVP-TESTING-BLOCK-CIPHER-MODES#KW + */ +static const unsigned int key_len[KW_TESTS] = { 16, 24, 32 }; + +static const unsigned char kw_key[KW_TESTS][32] = { + { 0x75, 0x75, 0xda, 0x3a, 0x93, 0x60, 0x7c, 0xc2, + 0xbf, 0xd8, 0xce, 0xc7, 0xaa, 0xdf, 0xd9, 0xa6 }, + { 0x2d, 0x85, 0x26, 0x08, 0x1d, 0x02, 0xfb, 0x5b, + 0x85, 0xf6, 0x9a, 0xc2, 0x86, 0xec, 0xd5, 0x7d, + 0x40, 0xdf, 0x5d, 0xf3, 0x49, 0x47, 0x44, 0xd3 }, + { 0x11, 0x2a, 0xd4, 0x1b, 0x48, 0x56, 0xc7, 0x25, + 0x4a, 0x98, 0x48, 0xd3, 0x0f, 0xdd, 0x78, 0x33, + 0x5b, 0x03, 0x9a, 0x48, 0xa8, 0x96, 0x2c, 0x4d, + 0x1c, 0xb7, 0x8e, 0xab, 0xd5, 0xda, 0xd7, 0x88 } +}; + +static const unsigned char kw_msg[KW_TESTS][40] = { + { 0x42, 0x13, 0x6d, 0x3c, 0x38, 0x4a, 0x3e, 0xea, + 0xc9, 0x5a, 0x06, 0x6f, 0xd2, 0x8f, 0xed, 0x3f }, + { 0x95, 0xc1, 0x1b, 0xf5, 0x35, 0x3a, 0xfe, 0xdb, + 0x98, 0xfd, 0xd6, 0xc8, 0xca, 0x6f, 0xdb, 0x6d, + 0xa5, 0x4b, 0x74, 0xb4, 0x99, 0x0f, 0xdc, 0x45, + 0xc0, 0x9d, 0x15, 0x8f, 0x51, 0xce, 0x62, 0x9d, + 0xe2, 0xaf, 0x26, 0xe3, 0x25, 0x0e, 0x6b, 0x4c }, + { 0x1b, 0x20, 0xbf, 0x19, 0x90, 0xb0, 0x65, 0xd7, + 0x98, 0xe1, 0xb3, 0x22, 0x64, 0xad, 0x50, 0xa8, + 0x74, 0x74, 0x92, 0xba, 0x09, 0xa0, 0x4d, 0xd1 } +}; + +static const size_t kw_msg_len[KW_TESTS] = { 16, 40, 24 }; +static const size_t kw_out_len[KW_TESTS] = { 24, 48, 32 }; +static const unsigned char kw_res[KW_TESTS][48] = { + { 0x03, 0x1f, 0x6b, 0xd7, 0xe6, 0x1e, 0x64, 0x3d, + 0xf6, 0x85, 0x94, 0x81, 0x6f, 0x64, 0xca, 0xa3, + 0xf5, 0x6f, 0xab, 0xea, 0x25, 0x48, 0xf5, 0xfb }, + { 0x44, 0x3c, 0x6f, 0x15, 0x09, 0x83, 0x71, 0x91, + 0x3e, 0x5c, 0x81, 0x4c, 0xa1, 0xa0, 0x42, 0xec, + 0x68, 0x2f, 0x7b, 0x13, 0x6d, 0x24, 0x3a, 0x4d, + 0x6c, 0x42, 0x6f, 0xc6, 0x97, 0x15, 0x63, 0xe8, + 0xa1, 0x4a, 0x55, 0x8e, 0x09, 0x64, 0x16, 0x19, + 0xbf, 0x03, 0xfc, 0xaf, 0x90, 0xb1, 0xfc, 0x2d }, + { 0xba, 0x8a, 0x25, 0x9a, 0x47, 0x1b, 0x78, 0x7d, + 0xd5, 0xd5, 0x40, 0xec, 0x25, 0xd4, 0x3d, 0x87, + 0x20, 0x0f, 0xda, 0xdc, 0x6d, 0x1f, 0x05, 0xd9, + 0x16, 0x58, 0x4f, 0xa9, 0xf6, 0xcb, 0xf5, 0x12 } +}; + +static const unsigned char kwp_key[KW_TESTS][32] = { + { 0x78, 0x65, 0xe2, 0x0f, 0x3c, 0x21, 0x65, 0x9a, + 0xb4, 0x69, 0x0b, 0x62, 0x9c, 0xdf, 0x3c, 0xc4 }, + { 0xf5, 0xf8, 0x96, 0xa3, 0xbd, 0x2f, 0x4a, 0x98, + 0x23, 0xef, 0x16, 0x2b, 0x00, 0xb8, 0x05, 0xd7, + 0xde, 0x1e, 0xa4, 0x66, 0x26, 0x96, 0xa2, 0x58 }, + { 0x95, 0xda, 0x27, 0x00, 0xca, 0x6f, 0xd9, 0xa5, + 0x25, 0x54, 0xee, 0x2a, 0x8d, 0xf1, 0x38, 0x6f, + 0x5b, 0x94, 0xa1, 0xa6, 0x0e, 0xd8, 0xa4, 0xae, + 0xf6, 0x0a, 0x8d, 0x61, 0xab, 0x5f, 0x22, 0x5a } +}; + +static const unsigned char kwp_msg[KW_TESTS][31] = { + { 0xbd, 0x68, 0x43, 0xd4, 0x20, 0x37, 0x8d, 0xc8, + 0x96 }, + { 0x6c, 0xcd, 0xd5, 0x85, 0x18, 0x40, 0x97, 0xeb, + 0xd5, 0xc3, 0xaf, 0x3e, 0x47, 0xd0, 0x2c, 0x19, + 0x14, 0x7b, 0x4d, 0x99, 0x5f, 0x96, 0x43, 0x66, + 0x91, 0x56, 0x75, 0x8c, 0x13, 0x16, 0x8f }, + { 0xd1 } +}; +static const size_t kwp_msg_len[KW_TESTS] = { 9, 31, 1 }; + +static const unsigned char kwp_res[KW_TESTS][48] = { + { 0x41, 0xec, 0xa9, 0x56, 0xd4, 0xaa, 0x04, 0x7e, + 0xb5, 0xcf, 0x4e, 0xfe, 0x65, 0x96, 0x61, 0xe7, + 0x4d, 0xb6, 0xf8, 0xc5, 0x64, 0xe2, 0x35, 0x00 }, + { 0x4e, 0x9b, 0xc2, 0xbc, 0xbc, 0x6c, 0x1e, 0x13, + 0xd3, 0x35, 0xbc, 0xc0, 0xf7, 0x73, 0x6a, 0x88, + 0xfa, 0x87, 0x53, 0x66, 0x15, 0xbb, 0x8e, 0x63, + 0x8b, 0xcc, 0x81, 0x66, 0x84, 0x68, 0x17, 0x90, + 0x67, 0xcf, 0xa9, 0x8a, 0x9d, 0x0e, 0x33, 0x26 }, + { 0x06, 0xba, 0x7a, 0xe6, 0xf3, 0x24, 0x8c, 0xfd, + 0xcf, 0x26, 0x75, 0x07, 0xfa, 0x00, 0x1b, 0xc4 } +}; +static const size_t kwp_out_len[KW_TESTS] = { 24, 40, 16 }; + +int mbedtls_nist_kw_self_test( int verbose ) +{ + mbedtls_nist_kw_context ctx; + unsigned char out[48]; + size_t olen; + int i; + int ret = 0; + mbedtls_nist_kw_init( &ctx ); + + for( i = 0; i < KW_TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " KW-AES-%u ", (unsigned int) key_len[i] * 8 ); + + ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, + kw_key[i], key_len[i] * 8, 1 ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( " KW: setup failed " ); + + goto end; + } + + ret = mbedtls_nist_kw_wrap( &ctx, MBEDTLS_KW_MODE_KW, kw_msg[i], + kw_msg_len[i], out, &olen, sizeof( out ) ); + if( ret != 0 || kw_out_len[i] != olen || + memcmp( out, kw_res[i], kw_out_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed. "); + + ret = 1; + goto end; + } + + if( ( ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, + kw_key[i], key_len[i] * 8, 0 ) ) + != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( " KW: setup failed "); + + goto end; + } + + ret = mbedtls_nist_kw_unwrap( &ctx, MBEDTLS_KW_MODE_KW, + out, olen, out, &olen, sizeof( out ) ); + + if( ret != 0 || olen != kw_msg_len[i] || + memcmp( out, kw_msg[i], kw_msg_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto end; + } + + if( verbose != 0 ) + mbedtls_printf( " passed\n" ); + } + + for( i = 0; i < KW_TESTS; i++ ) + { + olen = sizeof( out ); + if( verbose != 0 ) + mbedtls_printf( " KWP-AES-%u ", (unsigned int) key_len[i] * 8 ); + + ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, kwp_key[i], + key_len[i] * 8, 1 ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( " KWP: setup failed " ); + + goto end; + } + ret = mbedtls_nist_kw_wrap( &ctx, MBEDTLS_KW_MODE_KWP, kwp_msg[i], + kwp_msg_len[i], out, &olen, sizeof( out ) ); + + if( ret != 0 || kwp_out_len[i] != olen || + memcmp( out, kwp_res[i], kwp_out_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed. "); + + ret = 1; + goto end; + } + + if( ( ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, + kwp_key[i], key_len[i] * 8, 0 ) ) + != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( " KWP: setup failed "); + + goto end; + } + + ret = mbedtls_nist_kw_unwrap( &ctx, MBEDTLS_KW_MODE_KWP, out, + olen, out, &olen, sizeof( out ) ); + + if( ret != 0 || olen != kwp_msg_len[i] || + memcmp( out, kwp_msg[i], kwp_msg_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed. "); + + ret = 1; + goto end; + } + + if( verbose != 0 ) + mbedtls_printf( " passed\n" ); + } +end: + mbedtls_nist_kw_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#endif /* MBEDTLS_NIST_KW_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/oid.c b/FreeRTOS-Labs/Source/mbedtls/library/oid.c new file mode 100644 index 000000000..e0fdcd670 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/oid.c @@ -0,0 +1,772 @@ +/** + * \file oid.c + * + * \brief Object Identifier (OID) database + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_OID_C) + +#include "mbedtls/oid.h" +#include "mbedtls/rsa.h" + +#include +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_snprintf snprintf +#endif + +/* + * Macro to automatically add the size of #define'd OIDs + */ +#define ADD_LEN(s) s, MBEDTLS_OID_SIZE(s) + +/* + * Macro to generate an internal function for oid_XXX_from_asn1() (used by + * the other functions) + */ +#define FN_OID_TYPED_FROM_ASN1( TYPE_T, NAME, LIST ) \ + static const TYPE_T * oid_ ## NAME ## _from_asn1( \ + const mbedtls_asn1_buf *oid ) \ + { \ + const TYPE_T *p = (LIST); \ + const mbedtls_oid_descriptor_t *cur = \ + (const mbedtls_oid_descriptor_t *) p; \ + if( p == NULL || oid == NULL ) return( NULL ); \ + while( cur->asn1 != NULL ) { \ + if( cur->asn1_len == oid->len && \ + memcmp( cur->asn1, oid->p, oid->len ) == 0 ) { \ + return( p ); \ + } \ + p++; \ + cur = (const mbedtls_oid_descriptor_t *) p; \ + } \ + return( NULL ); \ + } + +/* + * Macro to generate a function for retrieving a single attribute from the + * descriptor of an mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_DESCRIPTOR_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \ +int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) \ +{ \ + const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \ + if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ + *ATTR1 = data->descriptor.ATTR1; \ + return( 0 ); \ +} + +/* + * Macro to generate a function for retrieving a single attribute from an + * mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \ +int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) \ +{ \ + const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \ + if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ + *ATTR1 = data->ATTR1; \ + return( 0 ); \ +} + +/* + * Macro to generate a function for retrieving two attributes from an + * mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_ATTR2(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1, \ + ATTR2_TYPE, ATTR2) \ +int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1, \ + ATTR2_TYPE * ATTR2 ) \ +{ \ + const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \ + if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ + *(ATTR1) = data->ATTR1; \ + *(ATTR2) = data->ATTR2; \ + return( 0 ); \ +} + +/* + * Macro to generate a function for retrieving the OID based on a single + * attribute from a mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_OID_BY_ATTR1(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1) \ +int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen ) \ +{ \ + const TYPE_T *cur = (LIST); \ + while( cur->descriptor.asn1 != NULL ) { \ + if( cur->ATTR1 == (ATTR1) ) { \ + *oid = cur->descriptor.asn1; \ + *olen = cur->descriptor.asn1_len; \ + return( 0 ); \ + } \ + cur++; \ + } \ + return( MBEDTLS_ERR_OID_NOT_FOUND ); \ +} + +/* + * Macro to generate a function for retrieving the OID based on two + * attributes from a mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_OID_BY_ATTR2(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1, \ + ATTR2_TYPE, ATTR2) \ +int FN_NAME( ATTR1_TYPE ATTR1, ATTR2_TYPE ATTR2, const char **oid , \ + size_t *olen ) \ +{ \ + const TYPE_T *cur = (LIST); \ + while( cur->descriptor.asn1 != NULL ) { \ + if( cur->ATTR1 == (ATTR1) && cur->ATTR2 == (ATTR2) ) { \ + *oid = cur->descriptor.asn1; \ + *olen = cur->descriptor.asn1_len; \ + return( 0 ); \ + } \ + cur++; \ + } \ + return( MBEDTLS_ERR_OID_NOT_FOUND ); \ +} + +/* + * For X520 attribute types + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + const char *short_name; +} oid_x520_attr_t; + +static const oid_x520_attr_t oid_x520_attr_type[] = +{ + { + { ADD_LEN( MBEDTLS_OID_AT_CN ), "id-at-commonName", "Common Name" }, + "CN", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_COUNTRY ), "id-at-countryName", "Country" }, + "C", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_LOCALITY ), "id-at-locality", "Locality" }, + "L", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_STATE ), "id-at-state", "State" }, + "ST", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_ORGANIZATION ),"id-at-organizationName", "Organization" }, + "O", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_ORG_UNIT ), "id-at-organizationalUnitName", "Org Unit" }, + "OU", + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS9_EMAIL ), "emailAddress", "E-mail address" }, + "emailAddress", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_SERIAL_NUMBER ),"id-at-serialNumber", "Serial number" }, + "serialNumber", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_POSTAL_ADDRESS ),"id-at-postalAddress", "Postal address" }, + "postalAddress", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_POSTAL_CODE ), "id-at-postalCode", "Postal code" }, + "postalCode", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_SUR_NAME ), "id-at-surName", "Surname" }, + "SN", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_GIVEN_NAME ), "id-at-givenName", "Given name" }, + "GN", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_INITIALS ), "id-at-initials", "Initials" }, + "initials", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_GENERATION_QUALIFIER ), "id-at-generationQualifier", "Generation qualifier" }, + "generationQualifier", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_TITLE ), "id-at-title", "Title" }, + "title", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_DN_QUALIFIER ),"id-at-dnQualifier", "Distinguished Name qualifier" }, + "dnQualifier", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_PSEUDONYM ), "id-at-pseudonym", "Pseudonym" }, + "pseudonym", + }, + { + { ADD_LEN( MBEDTLS_OID_DOMAIN_COMPONENT ), "id-domainComponent", "Domain component" }, + "DC", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_UNIQUE_IDENTIFIER ), "id-at-uniqueIdentifier", "Unique Identifier" }, + "uniqueIdentifier", + }, + { + { NULL, 0, NULL, NULL }, + NULL, + } +}; + +FN_OID_TYPED_FROM_ASN1(oid_x520_attr_t, x520_attr, oid_x520_attr_type) +FN_OID_GET_ATTR1(mbedtls_oid_get_attr_short_name, oid_x520_attr_t, x520_attr, const char *, short_name) + +/* + * For X509 extensions + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + int ext_type; +} oid_x509_ext_t; + +static const oid_x509_ext_t oid_x509_ext[] = +{ + { + { ADD_LEN( MBEDTLS_OID_BASIC_CONSTRAINTS ), "id-ce-basicConstraints", "Basic Constraints" }, + MBEDTLS_OID_X509_EXT_BASIC_CONSTRAINTS, + }, + { + { ADD_LEN( MBEDTLS_OID_KEY_USAGE ), "id-ce-keyUsage", "Key Usage" }, + MBEDTLS_OID_X509_EXT_KEY_USAGE, + }, + { + { ADD_LEN( MBEDTLS_OID_EXTENDED_KEY_USAGE ), "id-ce-extKeyUsage", "Extended Key Usage" }, + MBEDTLS_OID_X509_EXT_EXTENDED_KEY_USAGE, + }, + { + { ADD_LEN( MBEDTLS_OID_SUBJECT_ALT_NAME ), "id-ce-subjectAltName", "Subject Alt Name" }, + MBEDTLS_OID_X509_EXT_SUBJECT_ALT_NAME, + }, + { + { ADD_LEN( MBEDTLS_OID_NS_CERT_TYPE ), "id-netscape-certtype", "Netscape Certificate Type" }, + MBEDTLS_OID_X509_EXT_NS_CERT_TYPE, + }, + { + { ADD_LEN( MBEDTLS_OID_CERTIFICATE_POLICIES ), "id-ce-certificatePolicies", "Certificate Policies" }, + MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES, + }, + { + { NULL, 0, NULL, NULL }, + 0, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_x509_ext_t, x509_ext, oid_x509_ext) +FN_OID_GET_ATTR1(mbedtls_oid_get_x509_ext_type, oid_x509_ext_t, x509_ext, int, ext_type) + +static const mbedtls_oid_descriptor_t oid_ext_key_usage[] = +{ + { ADD_LEN( MBEDTLS_OID_SERVER_AUTH ), "id-kp-serverAuth", "TLS Web Server Authentication" }, + { ADD_LEN( MBEDTLS_OID_CLIENT_AUTH ), "id-kp-clientAuth", "TLS Web Client Authentication" }, + { ADD_LEN( MBEDTLS_OID_CODE_SIGNING ), "id-kp-codeSigning", "Code Signing" }, + { ADD_LEN( MBEDTLS_OID_EMAIL_PROTECTION ), "id-kp-emailProtection", "E-mail Protection" }, + { ADD_LEN( MBEDTLS_OID_TIME_STAMPING ), "id-kp-timeStamping", "Time Stamping" }, + { ADD_LEN( MBEDTLS_OID_OCSP_SIGNING ), "id-kp-OCSPSigning", "OCSP Signing" }, + { ADD_LEN( MBEDTLS_OID_WISUN_FAN ), "id-kp-wisun-fan-device", "Wi-SUN Alliance Field Area Network (FAN)" }, + { NULL, 0, NULL, NULL }, +}; + +FN_OID_TYPED_FROM_ASN1(mbedtls_oid_descriptor_t, ext_key_usage, oid_ext_key_usage) +FN_OID_GET_ATTR1(mbedtls_oid_get_extended_key_usage, mbedtls_oid_descriptor_t, ext_key_usage, const char *, description) + +static const mbedtls_oid_descriptor_t oid_certificate_policies[] = +{ + { ADD_LEN( MBEDTLS_OID_ANY_POLICY ), "anyPolicy", "Any Policy" }, + { NULL, 0, NULL, NULL }, +}; + +FN_OID_TYPED_FROM_ASN1(mbedtls_oid_descriptor_t, certificate_policies, oid_certificate_policies) +FN_OID_GET_ATTR1(mbedtls_oid_get_certificate_policies, mbedtls_oid_descriptor_t, certificate_policies, const char *, description) + +#if defined(MBEDTLS_MD_C) +/* + * For SignatureAlgorithmIdentifier + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_md_type_t md_alg; + mbedtls_pk_type_t pk_alg; +} oid_sig_alg_t; + +static const oid_sig_alg_t oid_sig_alg[] = +{ +#if defined(MBEDTLS_RSA_C) +#if defined(MBEDTLS_MD2_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_MD2 ), "md2WithRSAEncryption", "RSA with MD2" }, + MBEDTLS_MD_MD2, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_MD2_C */ +#if defined(MBEDTLS_MD4_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_MD4 ), "md4WithRSAEncryption", "RSA with MD4" }, + MBEDTLS_MD_MD4, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_MD4_C */ +#if defined(MBEDTLS_MD5_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_MD5 ), "md5WithRSAEncryption", "RSA with MD5" }, + MBEDTLS_MD_MD5, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_MD5_C */ +#if defined(MBEDTLS_SHA1_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA1 ), "sha-1WithRSAEncryption", "RSA with SHA1" }, + MBEDTLS_MD_SHA1, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA224 ), "sha224WithRSAEncryption", "RSA with SHA-224" }, + MBEDTLS_MD_SHA224, MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA256 ), "sha256WithRSAEncryption", "RSA with SHA-256" }, + MBEDTLS_MD_SHA256, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA384 ), "sha384WithRSAEncryption", "RSA with SHA-384" }, + MBEDTLS_MD_SHA384, MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA512 ), "sha512WithRSAEncryption", "RSA with SHA-512" }, + MBEDTLS_MD_SHA512, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_SHA1_C) + { + { ADD_LEN( MBEDTLS_OID_RSA_SHA_OBS ), "sha-1WithRSAEncryption", "RSA with SHA1" }, + MBEDTLS_MD_SHA1, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECDSA_C) +#if defined(MBEDTLS_SHA1_C) + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA1 ), "ecdsa-with-SHA1", "ECDSA with SHA1" }, + MBEDTLS_MD_SHA1, MBEDTLS_PK_ECDSA, + }, +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA224 ), "ecdsa-with-SHA224", "ECDSA with SHA224" }, + MBEDTLS_MD_SHA224, MBEDTLS_PK_ECDSA, + }, + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA256 ), "ecdsa-with-SHA256", "ECDSA with SHA256" }, + MBEDTLS_MD_SHA256, MBEDTLS_PK_ECDSA, + }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA384 ), "ecdsa-with-SHA384", "ECDSA with SHA384" }, + MBEDTLS_MD_SHA384, MBEDTLS_PK_ECDSA, + }, + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA512 ), "ecdsa-with-SHA512", "ECDSA with SHA512" }, + MBEDTLS_MD_SHA512, MBEDTLS_PK_ECDSA, + }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_ECDSA_C */ +#if defined(MBEDTLS_RSA_C) + { + { ADD_LEN( MBEDTLS_OID_RSASSA_PSS ), "RSASSA-PSS", "RSASSA-PSS" }, + MBEDTLS_MD_NONE, MBEDTLS_PK_RSASSA_PSS, + }, +#endif /* MBEDTLS_RSA_C */ + { + { NULL, 0, NULL, NULL }, + MBEDTLS_MD_NONE, MBEDTLS_PK_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_sig_alg_t, sig_alg, oid_sig_alg) +FN_OID_GET_DESCRIPTOR_ATTR1(mbedtls_oid_get_sig_alg_desc, oid_sig_alg_t, sig_alg, const char *, description) +FN_OID_GET_ATTR2(mbedtls_oid_get_sig_alg, oid_sig_alg_t, sig_alg, mbedtls_md_type_t, md_alg, mbedtls_pk_type_t, pk_alg) +FN_OID_GET_OID_BY_ATTR2(mbedtls_oid_get_oid_by_sig_alg, oid_sig_alg_t, oid_sig_alg, mbedtls_pk_type_t, pk_alg, mbedtls_md_type_t, md_alg) +#endif /* MBEDTLS_MD_C */ + +/* + * For PublicKeyInfo (PKCS1, RFC 5480) + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_pk_type_t pk_alg; +} oid_pk_alg_t; + +static const oid_pk_alg_t oid_pk_alg[] = +{ + { + { ADD_LEN( MBEDTLS_OID_PKCS1_RSA ), "rsaEncryption", "RSA" }, + MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_ALG_UNRESTRICTED ), "id-ecPublicKey", "Generic EC key" }, + MBEDTLS_PK_ECKEY, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_ALG_ECDH ), "id-ecDH", "EC key for ECDH" }, + MBEDTLS_PK_ECKEY_DH, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_PK_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_pk_alg_t, pk_alg, oid_pk_alg) +FN_OID_GET_ATTR1(mbedtls_oid_get_pk_alg, oid_pk_alg_t, pk_alg, mbedtls_pk_type_t, pk_alg) +FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_pk_alg, oid_pk_alg_t, oid_pk_alg, mbedtls_pk_type_t, pk_alg) + +#if defined(MBEDTLS_ECP_C) +/* + * For namedCurve (RFC 5480) + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_ecp_group_id grp_id; +} oid_ecp_grp_t; + +static const oid_ecp_grp_t oid_ecp_grp[] = +{ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP192R1 ), "secp192r1", "secp192r1" }, + MBEDTLS_ECP_DP_SECP192R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP224R1 ), "secp224r1", "secp224r1" }, + MBEDTLS_ECP_DP_SECP224R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP256R1 ), "secp256r1", "secp256r1" }, + MBEDTLS_ECP_DP_SECP256R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP384R1 ), "secp384r1", "secp384r1" }, + MBEDTLS_ECP_DP_SECP384R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP521R1 ), "secp521r1", "secp521r1" }, + MBEDTLS_ECP_DP_SECP521R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP192K1 ), "secp192k1", "secp192k1" }, + MBEDTLS_ECP_DP_SECP192K1, + }, +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP224K1 ), "secp224k1", "secp224k1" }, + MBEDTLS_ECP_DP_SECP224K1, + }, +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP256K1 ), "secp256k1", "secp256k1" }, + MBEDTLS_ECP_DP_SECP256K1, + }, +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_BP256R1 ), "brainpoolP256r1","brainpool256r1" }, + MBEDTLS_ECP_DP_BP256R1, + }, +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_BP384R1 ), "brainpoolP384r1","brainpool384r1" }, + MBEDTLS_ECP_DP_BP384R1, + }, +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_BP512R1 ), "brainpoolP512r1","brainpool512r1" }, + MBEDTLS_ECP_DP_BP512R1, + }, +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + { + { NULL, 0, NULL, NULL }, + MBEDTLS_ECP_DP_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_ecp_grp_t, grp_id, oid_ecp_grp) +FN_OID_GET_ATTR1(mbedtls_oid_get_ec_grp, oid_ecp_grp_t, grp_id, mbedtls_ecp_group_id, grp_id) +FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_ec_grp, oid_ecp_grp_t, oid_ecp_grp, mbedtls_ecp_group_id, grp_id) +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_CIPHER_C) +/* + * For PKCS#5 PBES2 encryption algorithm + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_cipher_type_t cipher_alg; +} oid_cipher_alg_t; + +static const oid_cipher_alg_t oid_cipher_alg[] = +{ + { + { ADD_LEN( MBEDTLS_OID_DES_CBC ), "desCBC", "DES-CBC" }, + MBEDTLS_CIPHER_DES_CBC, + }, + { + { ADD_LEN( MBEDTLS_OID_DES_EDE3_CBC ), "des-ede3-cbc", "DES-EDE3-CBC" }, + MBEDTLS_CIPHER_DES_EDE3_CBC, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_CIPHER_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_cipher_alg_t, cipher_alg, oid_cipher_alg) +FN_OID_GET_ATTR1(mbedtls_oid_get_cipher_alg, oid_cipher_alg_t, cipher_alg, mbedtls_cipher_type_t, cipher_alg) +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_MD_C) +/* + * For digestAlgorithm + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_md_type_t md_alg; +} oid_md_alg_t; + +static const oid_md_alg_t oid_md_alg[] = +{ +#if defined(MBEDTLS_MD2_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD2 ), "id-md2", "MD2" }, + MBEDTLS_MD_MD2, + }, +#endif /* MBEDTLS_MD2_C */ +#if defined(MBEDTLS_MD4_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD4 ), "id-md4", "MD4" }, + MBEDTLS_MD_MD4, + }, +#endif /* MBEDTLS_MD4_C */ +#if defined(MBEDTLS_MD5_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD5 ), "id-md5", "MD5" }, + MBEDTLS_MD_MD5, + }, +#endif /* MBEDTLS_MD5_C */ +#if defined(MBEDTLS_SHA1_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA1 ), "id-sha1", "SHA-1" }, + MBEDTLS_MD_SHA1, + }, +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA224 ), "id-sha224", "SHA-224" }, + MBEDTLS_MD_SHA224, + }, + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA256 ), "id-sha256", "SHA-256" }, + MBEDTLS_MD_SHA256, + }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA384 ), "id-sha384", "SHA-384" }, + MBEDTLS_MD_SHA384, + }, + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA512 ), "id-sha512", "SHA-512" }, + MBEDTLS_MD_SHA512, + }, +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_RIPEMD160_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_RIPEMD160 ), "id-ripemd160", "RIPEMD-160" }, + MBEDTLS_MD_RIPEMD160, + }, +#endif /* MBEDTLS_RIPEMD160_C */ + { + { NULL, 0, NULL, NULL }, + MBEDTLS_MD_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_md_alg_t, md_alg, oid_md_alg) +FN_OID_GET_ATTR1(mbedtls_oid_get_md_alg, oid_md_alg_t, md_alg, mbedtls_md_type_t, md_alg) +FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_md, oid_md_alg_t, oid_md_alg, mbedtls_md_type_t, md_alg) + +/* + * For HMAC digestAlgorithm + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_md_type_t md_hmac; +} oid_md_hmac_t; + +static const oid_md_hmac_t oid_md_hmac[] = +{ +#if defined(MBEDTLS_SHA1_C) + { + { ADD_LEN( MBEDTLS_OID_HMAC_SHA1 ), "hmacSHA1", "HMAC-SHA-1" }, + MBEDTLS_MD_SHA1, + }, +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) + { + { ADD_LEN( MBEDTLS_OID_HMAC_SHA224 ), "hmacSHA224", "HMAC-SHA-224" }, + MBEDTLS_MD_SHA224, + }, + { + { ADD_LEN( MBEDTLS_OID_HMAC_SHA256 ), "hmacSHA256", "HMAC-SHA-256" }, + MBEDTLS_MD_SHA256, + }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { + { ADD_LEN( MBEDTLS_OID_HMAC_SHA384 ), "hmacSHA384", "HMAC-SHA-384" }, + MBEDTLS_MD_SHA384, + }, + { + { ADD_LEN( MBEDTLS_OID_HMAC_SHA512 ), "hmacSHA512", "HMAC-SHA-512" }, + MBEDTLS_MD_SHA512, + }, +#endif /* MBEDTLS_SHA512_C */ + { + { NULL, 0, NULL, NULL }, + MBEDTLS_MD_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_md_hmac_t, md_hmac, oid_md_hmac) +FN_OID_GET_ATTR1(mbedtls_oid_get_md_hmac, oid_md_hmac_t, md_hmac, mbedtls_md_type_t, md_hmac) +#endif /* MBEDTLS_MD_C */ + +#if defined(MBEDTLS_PKCS12_C) +/* + * For PKCS#12 PBEs + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_md_type_t md_alg; + mbedtls_cipher_type_t cipher_alg; +} oid_pkcs12_pbe_alg_t; + +static const oid_pkcs12_pbe_alg_t oid_pkcs12_pbe_alg[] = +{ + { + { ADD_LEN( MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC ), "pbeWithSHAAnd3-KeyTripleDES-CBC", "PBE with SHA1 and 3-Key 3DES" }, + MBEDTLS_MD_SHA1, MBEDTLS_CIPHER_DES_EDE3_CBC, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC ), "pbeWithSHAAnd2-KeyTripleDES-CBC", "PBE with SHA1 and 2-Key 3DES" }, + MBEDTLS_MD_SHA1, MBEDTLS_CIPHER_DES_EDE_CBC, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_MD_NONE, MBEDTLS_CIPHER_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, oid_pkcs12_pbe_alg) +FN_OID_GET_ATTR2(mbedtls_oid_get_pkcs12_pbe_alg, oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, mbedtls_md_type_t, md_alg, mbedtls_cipher_type_t, cipher_alg) +#endif /* MBEDTLS_PKCS12_C */ + +#define OID_SAFE_SNPRINTF \ + do { \ + if( ret < 0 || (size_t) ret >= n ) \ + return( MBEDTLS_ERR_OID_BUF_TOO_SMALL ); \ + \ + n -= (size_t) ret; \ + p += (size_t) ret; \ + } while( 0 ) + +/* Return the x.y.z.... style numeric string for the given OID */ +int mbedtls_oid_get_numeric_string( char *buf, size_t size, + const mbedtls_asn1_buf *oid ) +{ + int ret; + size_t i, n; + unsigned int value; + char *p; + + p = buf; + n = size; + + /* First byte contains first two dots */ + if( oid->len > 0 ) + { + ret = mbedtls_snprintf( p, n, "%d.%d", oid->p[0] / 40, oid->p[0] % 40 ); + OID_SAFE_SNPRINTF; + } + + value = 0; + for( i = 1; i < oid->len; i++ ) + { + /* Prevent overflow in value. */ + if( ( ( value << 7 ) >> 7 ) != value ) + return( MBEDTLS_ERR_OID_BUF_TOO_SMALL ); + + value <<= 7; + value += oid->p[i] & 0x7F; + + if( !( oid->p[i] & 0x80 ) ) + { + /* Last byte */ + ret = mbedtls_snprintf( p, n, ".%d", value ); + OID_SAFE_SNPRINTF; + value = 0; + } + } + + return( (int) ( size - n ) ); +} + +#endif /* MBEDTLS_OID_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/padlock.c b/FreeRTOS-Labs/Source/mbedtls/library/padlock.c new file mode 100644 index 000000000..5c59b18b8 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/padlock.c @@ -0,0 +1,170 @@ +/* + * VIA PadLock support functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * This implementation is based on the VIA PadLock Programming Guide: + * + * http://www.via.com.tw/en/downloads/whitepapers/initiatives/padlock/ + * programming_guide.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PADLOCK_C) + +#include "mbedtls/padlock.h" + +#include + +#ifndef asm +#define asm __asm +#endif + +#if defined(MBEDTLS_HAVE_X86) + +/* + * PadLock detection routine + */ +int mbedtls_padlock_has_support( int feature ) +{ + static int flags = -1; + int ebx = 0, edx = 0; + + if( flags == -1 ) + { + asm( "movl %%ebx, %0 \n\t" + "movl $0xC0000000, %%eax \n\t" + "cpuid \n\t" + "cmpl $0xC0000001, %%eax \n\t" + "movl $0, %%edx \n\t" + "jb unsupported \n\t" + "movl $0xC0000001, %%eax \n\t" + "cpuid \n\t" + "unsupported: \n\t" + "movl %%edx, %1 \n\t" + "movl %2, %%ebx \n\t" + : "=m" (ebx), "=m" (edx) + : "m" (ebx) + : "eax", "ecx", "edx" ); + + flags = edx; + } + + return( flags & feature ); +} + +/* + * PadLock AES-ECB block en(de)cryption + */ +int mbedtls_padlock_xcryptecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + int ebx = 0; + uint32_t *rk; + uint32_t *blk; + uint32_t *ctrl; + unsigned char buf[256]; + + rk = ctx->rk; + blk = MBEDTLS_PADLOCK_ALIGN16( buf ); + memcpy( blk, input, 16 ); + + ctrl = blk + 4; + *ctrl = 0x80 | ctx->nr | ( ( ctx->nr + ( mode^1 ) - 10 ) << 9 ); + + asm( "pushfl \n\t" + "popfl \n\t" + "movl %%ebx, %0 \n\t" + "movl $1, %%ecx \n\t" + "movl %2, %%edx \n\t" + "movl %3, %%ebx \n\t" + "movl %4, %%esi \n\t" + "movl %4, %%edi \n\t" + ".byte 0xf3,0x0f,0xa7,0xc8 \n\t" + "movl %1, %%ebx \n\t" + : "=m" (ebx) + : "m" (ebx), "m" (ctrl), "m" (rk), "m" (blk) + : "memory", "ecx", "edx", "esi", "edi" ); + + memcpy( output, blk, 16 ); + + return( 0 ); +} + +/* + * PadLock AES-CBC buffer en(de)cryption + */ +int mbedtls_padlock_xcryptcbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int ebx = 0; + size_t count; + uint32_t *rk; + uint32_t *iw; + uint32_t *ctrl; + unsigned char buf[256]; + + if( ( (long) input & 15 ) != 0 || + ( (long) output & 15 ) != 0 ) + return( MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED ); + + rk = ctx->rk; + iw = MBEDTLS_PADLOCK_ALIGN16( buf ); + memcpy( iw, iv, 16 ); + + ctrl = iw + 4; + *ctrl = 0x80 | ctx->nr | ( ( ctx->nr + ( mode ^ 1 ) - 10 ) << 9 ); + + count = ( length + 15 ) >> 4; + + asm( "pushfl \n\t" + "popfl \n\t" + "movl %%ebx, %0 \n\t" + "movl %2, %%ecx \n\t" + "movl %3, %%edx \n\t" + "movl %4, %%ebx \n\t" + "movl %5, %%esi \n\t" + "movl %6, %%edi \n\t" + "movl %7, %%eax \n\t" + ".byte 0xf3,0x0f,0xa7,0xd0 \n\t" + "movl %1, %%ebx \n\t" + : "=m" (ebx) + : "m" (ebx), "m" (count), "m" (ctrl), + "m" (rk), "m" (input), "m" (output), "m" (iw) + : "memory", "eax", "ecx", "edx", "esi", "edi" ); + + memcpy( iv, iw, 16 ); + + return( 0 ); +} + +#endif /* MBEDTLS_HAVE_X86 */ + +#endif /* MBEDTLS_PADLOCK_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/pem.c b/FreeRTOS-Labs/Source/mbedtls/library/pem.c new file mode 100644 index 000000000..06cc4ca98 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/pem.c @@ -0,0 +1,490 @@ +/* + * Privacy Enhanced Mail (PEM) decoding + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) + +#include "mbedtls/pem.h" +#include "mbedtls/base64.h" +#include "mbedtls/des.h" +#include "mbedtls/aes.h" +#include "mbedtls/md5.h" +#include "mbedtls/cipher.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) +void mbedtls_pem_init( mbedtls_pem_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_pem_context ) ); +} + +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) +/* + * Read a 16-byte hex string and convert it to binary + */ +static int pem_get_iv( const unsigned char *s, unsigned char *iv, + size_t iv_len ) +{ + size_t i, j, k; + + memset( iv, 0, iv_len ); + + for( i = 0; i < iv_len * 2; i++, s++ ) + { + if( *s >= '0' && *s <= '9' ) j = *s - '0'; else + if( *s >= 'A' && *s <= 'F' ) j = *s - '7'; else + if( *s >= 'a' && *s <= 'f' ) j = *s - 'W'; else + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + k = ( ( i & 1 ) != 0 ) ? j : j << 4; + + iv[i >> 1] = (unsigned char)( iv[i >> 1] | k ); + } + + return( 0 ); +} + +static int pem_pbkdf1( unsigned char *key, size_t keylen, + unsigned char *iv, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_md5_context md5_ctx; + unsigned char md5sum[16]; + size_t use_len; + int ret; + + mbedtls_md5_init( &md5_ctx ); + + /* + * key[ 0..15] = MD5(pwd || IV) + */ + if( ( ret = mbedtls_md5_starts_ret( &md5_ctx ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_update_ret( &md5_ctx, pwd, pwdlen ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_update_ret( &md5_ctx, iv, 8 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_finish_ret( &md5_ctx, md5sum ) ) != 0 ) + goto exit; + + if( keylen <= 16 ) + { + memcpy( key, md5sum, keylen ); + goto exit; + } + + memcpy( key, md5sum, 16 ); + + /* + * key[16..23] = MD5(key[ 0..15] || pwd || IV]) + */ + if( ( ret = mbedtls_md5_starts_ret( &md5_ctx ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_update_ret( &md5_ctx, md5sum, 16 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_update_ret( &md5_ctx, pwd, pwdlen ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_update_ret( &md5_ctx, iv, 8 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_finish_ret( &md5_ctx, md5sum ) ) != 0 ) + goto exit; + + use_len = 16; + if( keylen < 32 ) + use_len = keylen - 16; + + memcpy( key + 16, md5sum, use_len ); + +exit: + mbedtls_md5_free( &md5_ctx ); + mbedtls_platform_zeroize( md5sum, 16 ); + + return( ret ); +} + +#if defined(MBEDTLS_DES_C) +/* + * Decrypt with DES-CBC, using PBKDF1 for key derivation + */ +static int pem_des_decrypt( unsigned char des_iv[8], + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_des_context des_ctx; + unsigned char des_key[8]; + int ret; + + mbedtls_des_init( &des_ctx ); + + if( ( ret = pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_des_setkey_dec( &des_ctx, des_key ) ) != 0 ) + goto exit; + ret = mbedtls_des_crypt_cbc( &des_ctx, MBEDTLS_DES_DECRYPT, buflen, + des_iv, buf, buf ); + +exit: + mbedtls_des_free( &des_ctx ); + mbedtls_platform_zeroize( des_key, 8 ); + + return( ret ); +} + +/* + * Decrypt with 3DES-CBC, using PBKDF1 for key derivation + */ +static int pem_des3_decrypt( unsigned char des3_iv[8], + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_des3_context des3_ctx; + unsigned char des3_key[24]; + int ret; + + mbedtls_des3_init( &des3_ctx ); + + if( ( ret = pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_des3_set3key_dec( &des3_ctx, des3_key ) ) != 0 ) + goto exit; + ret = mbedtls_des3_crypt_cbc( &des3_ctx, MBEDTLS_DES_DECRYPT, buflen, + des3_iv, buf, buf ); + +exit: + mbedtls_des3_free( &des3_ctx ); + mbedtls_platform_zeroize( des3_key, 24 ); + + return( ret ); +} +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) +/* + * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation + */ +static int pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen, + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_aes_context aes_ctx; + unsigned char aes_key[32]; + int ret; + + mbedtls_aes_init( &aes_ctx ); + + if( ( ret = pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 ) ) != 0 ) + goto exit; + ret = mbedtls_aes_crypt_cbc( &aes_ctx, MBEDTLS_AES_DECRYPT, buflen, + aes_iv, buf, buf ); + +exit: + mbedtls_aes_free( &aes_ctx ); + mbedtls_platform_zeroize( aes_key, keylen ); + + return( ret ); +} +#endif /* MBEDTLS_AES_C */ + +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + +int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const char *footer, + const unsigned char *data, const unsigned char *pwd, + size_t pwdlen, size_t *use_len ) +{ + int ret, enc; + size_t len; + unsigned char *buf; + const unsigned char *s1, *s2, *end; +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) + unsigned char pem_iv[16]; + mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE; +#else + ((void) pwd); + ((void) pwdlen); +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + + if( ctx == NULL ) + return( MBEDTLS_ERR_PEM_BAD_INPUT_DATA ); + + s1 = (unsigned char *) strstr( (const char *) data, header ); + + if( s1 == NULL ) + return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + s2 = (unsigned char *) strstr( (const char *) data, footer ); + + if( s2 == NULL || s2 <= s1 ) + return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + s1 += strlen( header ); + if( *s1 == ' ' ) s1++; + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + end = s2; + end += strlen( footer ); + if( *end == ' ' ) end++; + if( *end == '\r' ) end++; + if( *end == '\n' ) end++; + *use_len = end - data; + + enc = 0; + + if( s2 - s1 >= 22 && memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 ) + { +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) + enc++; + + s1 += 22; + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( MBEDTLS_ERR_PEM_INVALID_DATA ); + + +#if defined(MBEDTLS_DES_C) + if( s2 - s1 >= 23 && memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 ) + { + enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC; + + s1 += 23; + if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8 ) != 0 ) + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + s1 += 16; + } + else if( s2 - s1 >= 18 && memcmp( s1, "DEK-Info: DES-CBC,", 18 ) == 0 ) + { + enc_alg = MBEDTLS_CIPHER_DES_CBC; + + s1 += 18; + if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8) != 0 ) + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + s1 += 16; + } +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) + if( s2 - s1 >= 14 && memcmp( s1, "DEK-Info: AES-", 14 ) == 0 ) + { + if( s2 - s1 < 22 ) + return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG ); + else if( memcmp( s1, "DEK-Info: AES-128-CBC,", 22 ) == 0 ) + enc_alg = MBEDTLS_CIPHER_AES_128_CBC; + else if( memcmp( s1, "DEK-Info: AES-192-CBC,", 22 ) == 0 ) + enc_alg = MBEDTLS_CIPHER_AES_192_CBC; + else if( memcmp( s1, "DEK-Info: AES-256-CBC,", 22 ) == 0 ) + enc_alg = MBEDTLS_CIPHER_AES_256_CBC; + else + return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG ); + + s1 += 22; + if( s2 - s1 < 32 || pem_get_iv( s1, pem_iv, 16 ) != 0 ) + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + s1 += 32; + } +#endif /* MBEDTLS_AES_C */ + + if( enc_alg == MBEDTLS_CIPHER_NONE ) + return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG ); + + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( MBEDTLS_ERR_PEM_INVALID_DATA ); +#else + return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE ); +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + } + + if( s1 >= s2 ) + return( MBEDTLS_ERR_PEM_INVALID_DATA ); + + ret = mbedtls_base64_decode( NULL, 0, &len, s1, s2 - s1 ); + + if( ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER ) + return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); + + if( ( buf = mbedtls_calloc( 1, len ) ) == NULL ) + return( MBEDTLS_ERR_PEM_ALLOC_FAILED ); + + if( ( ret = mbedtls_base64_decode( buf, len, &len, s1, s2 - s1 ) ) != 0 ) + { + mbedtls_platform_zeroize( buf, len ); + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); + } + + if( enc != 0 ) + { +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) + if( pwd == NULL ) + { + mbedtls_platform_zeroize( buf, len ); + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ); + } + + ret = 0; + +#if defined(MBEDTLS_DES_C) + if( enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC ) + ret = pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_DES_CBC ) + ret = pem_des_decrypt( pem_iv, buf, len, pwd, pwdlen ); +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) + if( enc_alg == MBEDTLS_CIPHER_AES_128_CBC ) + ret = pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_AES_192_CBC ) + ret = pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_AES_256_CBC ) + ret = pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen ); +#endif /* MBEDTLS_AES_C */ + + if( ret != 0 ) + { + mbedtls_free( buf ); + return( ret ); + } + + /* + * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3 + * length bytes (allow 4 to be sure) in all known use cases. + * + * Use that as a heuristic to try to detect password mismatches. + */ + if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 ) + { + mbedtls_platform_zeroize( buf, len ); + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ); + } +#else + mbedtls_platform_zeroize( buf, len ); + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE ); +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + } + + ctx->buf = buf; + ctx->buflen = len; + + return( 0 ); +} + +void mbedtls_pem_free( mbedtls_pem_context *ctx ) +{ + if ( ctx->buf != NULL ) + { + mbedtls_platform_zeroize( ctx->buf, ctx->buflen ); + mbedtls_free( ctx->buf ); + } + mbedtls_free( ctx->info ); + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_pem_context ) ); +} +#endif /* MBEDTLS_PEM_PARSE_C */ + +#if defined(MBEDTLS_PEM_WRITE_C) +int mbedtls_pem_write_buffer( const char *header, const char *footer, + const unsigned char *der_data, size_t der_len, + unsigned char *buf, size_t buf_len, size_t *olen ) +{ + int ret; + unsigned char *encode_buf = NULL, *c, *p = buf; + size_t len = 0, use_len, add_len = 0; + + mbedtls_base64_encode( NULL, 0, &use_len, der_data, der_len ); + add_len = strlen( header ) + strlen( footer ) + ( use_len / 64 ) + 1; + + if( use_len + add_len > buf_len ) + { + *olen = use_len + add_len; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + if( use_len != 0 && + ( ( encode_buf = mbedtls_calloc( 1, use_len ) ) == NULL ) ) + return( MBEDTLS_ERR_PEM_ALLOC_FAILED ); + + if( ( ret = mbedtls_base64_encode( encode_buf, use_len, &use_len, der_data, + der_len ) ) != 0 ) + { + mbedtls_free( encode_buf ); + return( ret ); + } + + memcpy( p, header, strlen( header ) ); + p += strlen( header ); + c = encode_buf; + + while( use_len ) + { + len = ( use_len > 64 ) ? 64 : use_len; + memcpy( p, c, len ); + use_len -= len; + p += len; + c += len; + *p++ = '\n'; + } + + memcpy( p, footer, strlen( footer ) ); + p += strlen( footer ); + + *p++ = '\0'; + *olen = p - buf; + + mbedtls_free( encode_buf ); + return( 0 ); +} +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/pk.c b/FreeRTOS-Labs/Source/mbedtls/library/pk.c new file mode 100644 index 000000000..2f54723a9 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/pk.c @@ -0,0 +1,646 @@ +/* + * Public Key abstraction layer + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_C) +#include "mbedtls/pk.h" +#include "mbedtls/pk_internal.h" + +#include "mbedtls/platform_util.h" + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "mbedtls/psa_util.h" +#endif + +#include +#include + +/* Parameter validation macros based on platform_util.h */ +#define PK_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_PK_BAD_INPUT_DATA ) +#define PK_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +/* + * Initialise a mbedtls_pk_context + */ +void mbedtls_pk_init( mbedtls_pk_context *ctx ) +{ + PK_VALIDATE( ctx != NULL ); + + ctx->pk_info = NULL; + ctx->pk_ctx = NULL; +} + +/* + * Free (the components of) a mbedtls_pk_context + */ +void mbedtls_pk_free( mbedtls_pk_context *ctx ) +{ + if( ctx == NULL ) + return; + + if ( ctx->pk_info != NULL ) + ctx->pk_info->ctx_free_func( ctx->pk_ctx ); + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_pk_context ) ); +} + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +/* + * Initialize a restart context + */ +void mbedtls_pk_restart_init( mbedtls_pk_restart_ctx *ctx ) +{ + PK_VALIDATE( ctx != NULL ); + ctx->pk_info = NULL; + ctx->rs_ctx = NULL; +} + +/* + * Free the components of a restart context + */ +void mbedtls_pk_restart_free( mbedtls_pk_restart_ctx *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL || + ctx->pk_info->rs_free_func == NULL ) + { + return; + } + + ctx->pk_info->rs_free_func( ctx->rs_ctx ); + + ctx->pk_info = NULL; + ctx->rs_ctx = NULL; +} +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + +/* + * Get pk_info structure from type + */ +const mbedtls_pk_info_t * mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type ) +{ + switch( pk_type ) { +#if defined(MBEDTLS_RSA_C) + case MBEDTLS_PK_RSA: + return( &mbedtls_rsa_info ); +#endif +#if defined(MBEDTLS_ECP_C) + case MBEDTLS_PK_ECKEY: + return( &mbedtls_eckey_info ); + case MBEDTLS_PK_ECKEY_DH: + return( &mbedtls_eckeydh_info ); +#endif +#if defined(MBEDTLS_ECDSA_C) + case MBEDTLS_PK_ECDSA: + return( &mbedtls_ecdsa_info ); +#endif + /* MBEDTLS_PK_RSA_ALT omitted on purpose */ + default: + return( NULL ); + } +} + +/* + * Initialise context + */ +int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ) +{ + PK_VALIDATE_RET( ctx != NULL ); + if( info == NULL || ctx->pk_info != NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + + ctx->pk_info = info; + + return( 0 ); +} + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +/* + * Initialise a PSA-wrapping context + */ +int mbedtls_pk_setup_opaque( mbedtls_pk_context *ctx, const psa_key_handle_t key ) +{ + const mbedtls_pk_info_t * const info = &mbedtls_pk_opaque_info; + psa_key_handle_t *pk_ctx; + psa_key_type_t type; + + if( ctx == NULL || ctx->pk_info != NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( PSA_SUCCESS != psa_get_key_information( key, &type, NULL ) ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + /* Current implementation of can_do() relies on this. */ + if( ! PSA_KEY_TYPE_IS_ECC_KEYPAIR( type ) ) + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE) ; + + if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + + ctx->pk_info = info; + + pk_ctx = (psa_key_handle_t *) ctx->pk_ctx; + *pk_ctx = key; + + return( 0 ); +} +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* + * Initialize an RSA-alt context + */ +int mbedtls_pk_setup_rsa_alt( mbedtls_pk_context *ctx, void * key, + mbedtls_pk_rsa_alt_decrypt_func decrypt_func, + mbedtls_pk_rsa_alt_sign_func sign_func, + mbedtls_pk_rsa_alt_key_len_func key_len_func ) +{ + mbedtls_rsa_alt_context *rsa_alt; + const mbedtls_pk_info_t *info = &mbedtls_rsa_alt_info; + + PK_VALIDATE_RET( ctx != NULL ); + if( ctx->pk_info != NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + + ctx->pk_info = info; + + rsa_alt = (mbedtls_rsa_alt_context *) ctx->pk_ctx; + + rsa_alt->key = key; + rsa_alt->decrypt_func = decrypt_func; + rsa_alt->sign_func = sign_func; + rsa_alt->key_len_func = key_len_func; + + return( 0 ); +} +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +/* + * Tell if a PK can do the operations of the given type + */ +int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ) +{ + /* A context with null pk_info is not set up yet and can't do anything. + * For backward compatibility, also accept NULL instead of a context + * pointer. */ + if( ctx == NULL || ctx->pk_info == NULL ) + return( 0 ); + + return( ctx->pk_info->can_do( type ) ); +} + +/* + * Helper for mbedtls_pk_sign and mbedtls_pk_verify + */ +static inline int pk_hashlen_helper( mbedtls_md_type_t md_alg, size_t *hash_len ) +{ + const mbedtls_md_info_t *md_info; + + if( *hash_len != 0 ) + return( 0 ); + + if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL ) + return( -1 ); + + *hash_len = mbedtls_md_get_size( md_info ); + return( 0 ); +} + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +/* + * Helper to set up a restart context if needed + */ +static int pk_restart_setup( mbedtls_pk_restart_ctx *ctx, + const mbedtls_pk_info_t *info ) +{ + /* Don't do anything if already set up or invalid */ + if( ctx == NULL || ctx->pk_info != NULL ) + return( 0 ); + + /* Should never happen when we're called */ + if( info->rs_alloc_func == NULL || info->rs_free_func == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ( ctx->rs_ctx = info->rs_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + + ctx->pk_info = info; + + return( 0 ); +} +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + +/* + * Verify a signature (restartable) + */ +int mbedtls_pk_verify_restartable( mbedtls_pk_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len, + mbedtls_pk_restart_ctx *rs_ctx ) +{ + PK_VALIDATE_RET( ctx != NULL ); + PK_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && hash_len == 0 ) || + hash != NULL ); + PK_VALIDATE_RET( sig != NULL ); + + if( ctx->pk_info == NULL || + pk_hashlen_helper( md_alg, &hash_len ) != 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + /* optimization: use non-restartable version if restart disabled */ + if( rs_ctx != NULL && + mbedtls_ecp_restart_is_enabled() && + ctx->pk_info->verify_rs_func != NULL ) + { + int ret; + + if( ( ret = pk_restart_setup( rs_ctx, ctx->pk_info ) ) != 0 ) + return( ret ); + + ret = ctx->pk_info->verify_rs_func( ctx->pk_ctx, + md_alg, hash, hash_len, sig, sig_len, rs_ctx->rs_ctx ); + + if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) + mbedtls_pk_restart_free( rs_ctx ); + + return( ret ); + } +#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + (void) rs_ctx; +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + + if( ctx->pk_info->verify_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->verify_func( ctx->pk_ctx, md_alg, hash, hash_len, + sig, sig_len ) ); +} + +/* + * Verify a signature + */ +int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + return( mbedtls_pk_verify_restartable( ctx, md_alg, hash, hash_len, + sig, sig_len, NULL ) ); +} + +/* + * Verify a signature with options + */ +int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, + mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + PK_VALIDATE_RET( ctx != NULL ); + PK_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && hash_len == 0 ) || + hash != NULL ); + PK_VALIDATE_RET( sig != NULL ); + + if( ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ! mbedtls_pk_can_do( ctx, type ) ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + if( type == MBEDTLS_PK_RSASSA_PSS ) + { +#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_PKCS1_V21) + int ret; + const mbedtls_pk_rsassa_pss_options *pss_opts; + +#if SIZE_MAX > UINT_MAX + if( md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* SIZE_MAX > UINT_MAX */ + + if( options == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + pss_opts = (const mbedtls_pk_rsassa_pss_options *) options; + + if( sig_len < mbedtls_pk_get_len( ctx ) ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + ret = mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_pk_rsa( *ctx ), + NULL, NULL, MBEDTLS_RSA_PUBLIC, + md_alg, (unsigned int) hash_len, hash, + pss_opts->mgf1_hash_id, + pss_opts->expected_salt_len, + sig ); + if( ret != 0 ) + return( ret ); + + if( sig_len > mbedtls_pk_get_len( ctx ) ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + + return( 0 ); +#else + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); +#endif /* MBEDTLS_RSA_C && MBEDTLS_PKCS1_V21 */ + } + + /* General case: no options */ + if( options != NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + return( mbedtls_pk_verify( ctx, md_alg, hash, hash_len, sig, sig_len ) ); +} + +/* + * Make a signature (restartable) + */ +int mbedtls_pk_sign_restartable( mbedtls_pk_context *ctx, + mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_pk_restart_ctx *rs_ctx ) +{ + PK_VALIDATE_RET( ctx != NULL ); + PK_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && hash_len == 0 ) || + hash != NULL ); + PK_VALIDATE_RET( sig != NULL ); + + if( ctx->pk_info == NULL || + pk_hashlen_helper( md_alg, &hash_len ) != 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + /* optimization: use non-restartable version if restart disabled */ + if( rs_ctx != NULL && + mbedtls_ecp_restart_is_enabled() && + ctx->pk_info->sign_rs_func != NULL ) + { + int ret; + + if( ( ret = pk_restart_setup( rs_ctx, ctx->pk_info ) ) != 0 ) + return( ret ); + + ret = ctx->pk_info->sign_rs_func( ctx->pk_ctx, md_alg, + hash, hash_len, sig, sig_len, f_rng, p_rng, rs_ctx->rs_ctx ); + + if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) + mbedtls_pk_restart_free( rs_ctx ); + + return( ret ); + } +#else /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + (void) rs_ctx; +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + + if( ctx->pk_info->sign_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->sign_func( ctx->pk_ctx, md_alg, hash, hash_len, + sig, sig_len, f_rng, p_rng ) ); +} + +/* + * Make a signature + */ +int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + return( mbedtls_pk_sign_restartable( ctx, md_alg, hash, hash_len, + sig, sig_len, f_rng, p_rng, NULL ) ); +} + +/* + * Decrypt message + */ +int mbedtls_pk_decrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + PK_VALIDATE_RET( ctx != NULL ); + PK_VALIDATE_RET( input != NULL || ilen == 0 ); + PK_VALIDATE_RET( output != NULL || osize == 0 ); + PK_VALIDATE_RET( olen != NULL ); + + if( ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->decrypt_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->decrypt_func( ctx->pk_ctx, input, ilen, + output, olen, osize, f_rng, p_rng ) ); +} + +/* + * Encrypt message + */ +int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + PK_VALIDATE_RET( ctx != NULL ); + PK_VALIDATE_RET( input != NULL || ilen == 0 ); + PK_VALIDATE_RET( output != NULL || osize == 0 ); + PK_VALIDATE_RET( olen != NULL ); + + if( ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->encrypt_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->encrypt_func( ctx->pk_ctx, input, ilen, + output, olen, osize, f_rng, p_rng ) ); +} + +/* + * Check public-private key pair + */ +int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ) +{ + PK_VALIDATE_RET( pub != NULL ); + PK_VALIDATE_RET( prv != NULL ); + + if( pub->pk_info == NULL || + prv->pk_info == NULL ) + { + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + } + + if( prv->pk_info->check_pair_func == NULL ) + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + if( prv->pk_info->type == MBEDTLS_PK_RSA_ALT ) + { + if( pub->pk_info->type != MBEDTLS_PK_RSA ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + } + else + { + if( pub->pk_info != prv->pk_info ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + } + + return( prv->pk_info->check_pair_func( pub->pk_ctx, prv->pk_ctx ) ); +} + +/* + * Get key size in bits + */ +size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ) +{ + /* For backward compatibility, accept NULL or a context that + * isn't set up yet, and return a fake value that should be safe. */ + if( ctx == NULL || ctx->pk_info == NULL ) + return( 0 ); + + return( ctx->pk_info->get_bitlen( ctx->pk_ctx ) ); +} + +/* + * Export debug information + */ +int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items ) +{ + PK_VALIDATE_RET( ctx != NULL ); + if( ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->debug_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + ctx->pk_info->debug_func( ctx->pk_ctx, items ); + return( 0 ); +} + +/* + * Access the PK type name + */ +const char *mbedtls_pk_get_name( const mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( "invalid PK" ); + + return( ctx->pk_info->name ); +} + +/* + * Access the PK type + */ +mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_PK_NONE ); + + return( ctx->pk_info->type ); +} + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +/* + * Load the key to a PSA key slot, + * then turn the PK context into a wrapper for that key slot. + * + * Currently only works for EC private keys. + */ +int mbedtls_pk_wrap_as_opaque( mbedtls_pk_context *pk, + psa_key_handle_t *slot, + psa_algorithm_t hash_alg ) +{ +#if !defined(MBEDTLS_ECP_C) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); +#else + psa_key_handle_t key; + const mbedtls_ecp_keypair *ec; + unsigned char d[MBEDTLS_ECP_MAX_BYTES]; + size_t d_len; + psa_ecc_curve_t curve_id; + psa_key_type_t key_type; + psa_key_policy_t policy; + int ret; + + /* export the private key material in the format PSA wants */ + if( mbedtls_pk_get_type( pk ) != MBEDTLS_PK_ECKEY ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + ec = mbedtls_pk_ec( *pk ); + d_len = ( ec->grp.nbits + 7 ) / 8; + if( ( ret = mbedtls_mpi_write_binary( &ec->d, d, d_len ) ) != 0 ) + return( ret ); + + curve_id = mbedtls_ecp_curve_info_from_grp_id( ec->grp.id )->tls_id; + key_type = PSA_KEY_TYPE_ECC_KEYPAIR( + mbedtls_psa_parse_tls_ecc_group ( curve_id ) ); + + /* allocate a key slot */ + if( PSA_SUCCESS != psa_allocate_key( &key ) ) + return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED ); + + /* set policy */ + policy = psa_key_policy_init(); + psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_SIGN, + PSA_ALG_ECDSA(hash_alg) ); + if( PSA_SUCCESS != psa_set_key_policy( key, &policy ) ) + return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED ); + + /* import private key in slot */ + if( PSA_SUCCESS != psa_import_key( key, key_type, d, d_len ) ) + return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED ); + + /* remember slot number to be destroyed later by caller */ + *slot = key; + + /* make PK context wrap the key slot */ + mbedtls_pk_free( pk ); + mbedtls_pk_init( pk ); + + return( mbedtls_pk_setup_opaque( pk, key ) ); +#endif /* MBEDTLS_ECP_C */ +} +#endif /* MBEDTLS_USE_PSA_CRYPTO */ +#endif /* MBEDTLS_PK_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/pk_wrap.c b/FreeRTOS-Labs/Source/mbedtls/library/pk_wrap.c new file mode 100644 index 000000000..feda6f83e --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/pk_wrap.c @@ -0,0 +1,1058 @@ +/* + * Public Key abstraction layer: wrapper functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_C) +#include "mbedtls/pk_internal.h" + +/* Even if RSA not activated, for the sake of RSA-alt */ +#include "mbedtls/rsa.h" + +#include + +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif + +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "mbedtls/asn1write.h" +#endif + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +#include "mbedtls/platform_util.h" +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "psa/crypto.h" +#include "mbedtls/psa_util.h" +#include "mbedtls/asn1.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include +#include + +#if defined(MBEDTLS_RSA_C) +static int rsa_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_RSA || + type == MBEDTLS_PK_RSASSA_PSS ); +} + +static size_t rsa_get_bitlen( const void *ctx ) +{ + const mbedtls_rsa_context * rsa = (const mbedtls_rsa_context *) ctx; + return( 8 * mbedtls_rsa_get_len( rsa ) ); +} + +static int rsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + int ret; + mbedtls_rsa_context * rsa = (mbedtls_rsa_context *) ctx; + size_t rsa_len = mbedtls_rsa_get_len( rsa ); + +#if SIZE_MAX > UINT_MAX + if( md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* SIZE_MAX > UINT_MAX */ + + if( sig_len < rsa_len ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( ( ret = mbedtls_rsa_pkcs1_verify( rsa, NULL, NULL, + MBEDTLS_RSA_PUBLIC, md_alg, + (unsigned int) hash_len, hash, sig ) ) != 0 ) + return( ret ); + + /* The buffer contains a valid signature followed by extra data. + * We have a special error code for that so that so that callers can + * use mbedtls_pk_verify() to check "Does the buffer start with a + * valid signature?" and not just "Does the buffer contain a valid + * signature?". */ + if( sig_len > rsa_len ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + + return( 0 ); +} + +static int rsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + mbedtls_rsa_context * rsa = (mbedtls_rsa_context *) ctx; + +#if SIZE_MAX > UINT_MAX + if( md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* SIZE_MAX > UINT_MAX */ + + *sig_len = mbedtls_rsa_get_len( rsa ); + + return( mbedtls_rsa_pkcs1_sign( rsa, f_rng, p_rng, MBEDTLS_RSA_PRIVATE, + md_alg, (unsigned int) hash_len, hash, sig ) ); +} + +static int rsa_decrypt_wrap( void *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + mbedtls_rsa_context * rsa = (mbedtls_rsa_context *) ctx; + + if( ilen != mbedtls_rsa_get_len( rsa ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + return( mbedtls_rsa_pkcs1_decrypt( rsa, f_rng, p_rng, + MBEDTLS_RSA_PRIVATE, olen, input, output, osize ) ); +} + +static int rsa_encrypt_wrap( void *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + mbedtls_rsa_context * rsa = (mbedtls_rsa_context *) ctx; + *olen = mbedtls_rsa_get_len( rsa ); + + if( *olen > osize ) + return( MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE ); + + return( mbedtls_rsa_pkcs1_encrypt( rsa, f_rng, p_rng, MBEDTLS_RSA_PUBLIC, + ilen, input, output ) ); +} + +static int rsa_check_pair_wrap( const void *pub, const void *prv ) +{ + return( mbedtls_rsa_check_pub_priv( (const mbedtls_rsa_context *) pub, + (const mbedtls_rsa_context *) prv ) ); +} + +static void *rsa_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_rsa_context ) ); + + if( ctx != NULL ) + mbedtls_rsa_init( (mbedtls_rsa_context *) ctx, 0, 0 ); + + return( ctx ); +} + +static void rsa_free_wrap( void *ctx ) +{ + mbedtls_rsa_free( (mbedtls_rsa_context *) ctx ); + mbedtls_free( ctx ); +} + +static void rsa_debug( const void *ctx, mbedtls_pk_debug_item *items ) +{ + items->type = MBEDTLS_PK_DEBUG_MPI; + items->name = "rsa.N"; + items->value = &( ((mbedtls_rsa_context *) ctx)->N ); + + items++; + + items->type = MBEDTLS_PK_DEBUG_MPI; + items->name = "rsa.E"; + items->value = &( ((mbedtls_rsa_context *) ctx)->E ); +} + +const mbedtls_pk_info_t mbedtls_rsa_info = { + MBEDTLS_PK_RSA, + "RSA", + rsa_get_bitlen, + rsa_can_do, + rsa_verify_wrap, + rsa_sign_wrap, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, + NULL, +#endif + rsa_decrypt_wrap, + rsa_encrypt_wrap, + rsa_check_pair_wrap, + rsa_alloc_wrap, + rsa_free_wrap, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, + NULL, +#endif + rsa_debug, +}; +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * Generic EC key + */ +static int eckey_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_ECKEY || + type == MBEDTLS_PK_ECKEY_DH || + type == MBEDTLS_PK_ECDSA ); +} + +static size_t eckey_get_bitlen( const void *ctx ) +{ + return( ((mbedtls_ecp_keypair *) ctx)->grp.pbits ); +} + +#if defined(MBEDTLS_ECDSA_C) +/* Forward declarations */ +static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + +static int ecdsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +static int eckey_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + int ret; + mbedtls_ecdsa_context ecdsa; + + mbedtls_ecdsa_init( &ecdsa ); + + if( ( ret = mbedtls_ecdsa_from_keypair( &ecdsa, ctx ) ) == 0 ) + ret = ecdsa_verify_wrap( &ecdsa, md_alg, hash, hash_len, sig, sig_len ); + + mbedtls_ecdsa_free( &ecdsa ); + + return( ret ); +} + +static int eckey_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + mbedtls_ecdsa_context ecdsa; + + mbedtls_ecdsa_init( &ecdsa ); + + if( ( ret = mbedtls_ecdsa_from_keypair( &ecdsa, ctx ) ) == 0 ) + ret = ecdsa_sign_wrap( &ecdsa, md_alg, hash, hash_len, sig, sig_len, + f_rng, p_rng ); + + mbedtls_ecdsa_free( &ecdsa ); + + return( ret ); +} + +#if defined(MBEDTLS_ECP_RESTARTABLE) +/* Forward declarations */ +static int ecdsa_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len, + void *rs_ctx ); + +static int ecdsa_sign_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + void *rs_ctx ); + +/* + * Restart context for ECDSA operations with ECKEY context + * + * We need to store an actual ECDSA context, as we need to pass the same to + * the underlying ecdsa function, so we can't create it on the fly every time. + */ +typedef struct +{ + mbedtls_ecdsa_restart_ctx ecdsa_rs; + mbedtls_ecdsa_context ecdsa_ctx; +} eckey_restart_ctx; + +static void *eckey_rs_alloc( void ) +{ + eckey_restart_ctx *rs_ctx; + + void *ctx = mbedtls_calloc( 1, sizeof( eckey_restart_ctx ) ); + + if( ctx != NULL ) + { + rs_ctx = ctx; + mbedtls_ecdsa_restart_init( &rs_ctx->ecdsa_rs ); + mbedtls_ecdsa_init( &rs_ctx->ecdsa_ctx ); + } + + return( ctx ); +} + +static void eckey_rs_free( void *ctx ) +{ + eckey_restart_ctx *rs_ctx; + + if( ctx == NULL) + return; + + rs_ctx = ctx; + mbedtls_ecdsa_restart_free( &rs_ctx->ecdsa_rs ); + mbedtls_ecdsa_free( &rs_ctx->ecdsa_ctx ); + + mbedtls_free( ctx ); +} + +static int eckey_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len, + void *rs_ctx ) +{ + int ret; + eckey_restart_ctx *rs = rs_ctx; + + /* Should never happen */ + if( rs == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + /* set up our own sub-context if needed (that is, on first run) */ + if( rs->ecdsa_ctx.grp.pbits == 0 ) + MBEDTLS_MPI_CHK( mbedtls_ecdsa_from_keypair( &rs->ecdsa_ctx, ctx ) ); + + MBEDTLS_MPI_CHK( ecdsa_verify_rs_wrap( &rs->ecdsa_ctx, + md_alg, hash, hash_len, + sig, sig_len, &rs->ecdsa_rs ) ); + +cleanup: + return( ret ); +} + +static int eckey_sign_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + void *rs_ctx ) +{ + int ret; + eckey_restart_ctx *rs = rs_ctx; + + /* Should never happen */ + if( rs == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + /* set up our own sub-context if needed (that is, on first run) */ + if( rs->ecdsa_ctx.grp.pbits == 0 ) + MBEDTLS_MPI_CHK( mbedtls_ecdsa_from_keypair( &rs->ecdsa_ctx, ctx ) ); + + MBEDTLS_MPI_CHK( ecdsa_sign_rs_wrap( &rs->ecdsa_ctx, md_alg, + hash, hash_len, sig, sig_len, + f_rng, p_rng, &rs->ecdsa_rs ) ); + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_RESTARTABLE */ +#endif /* MBEDTLS_ECDSA_C */ + +static int eckey_check_pair( const void *pub, const void *prv ) +{ + return( mbedtls_ecp_check_pub_priv( (const mbedtls_ecp_keypair *) pub, + (const mbedtls_ecp_keypair *) prv ) ); +} + +static void *eckey_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecp_keypair ) ); + + if( ctx != NULL ) + mbedtls_ecp_keypair_init( ctx ); + + return( ctx ); +} + +static void eckey_free_wrap( void *ctx ) +{ + mbedtls_ecp_keypair_free( (mbedtls_ecp_keypair *) ctx ); + mbedtls_free( ctx ); +} + +static void eckey_debug( const void *ctx, mbedtls_pk_debug_item *items ) +{ + items->type = MBEDTLS_PK_DEBUG_ECP; + items->name = "eckey.Q"; + items->value = &( ((mbedtls_ecp_keypair *) ctx)->Q ); +} + +const mbedtls_pk_info_t mbedtls_eckey_info = { + MBEDTLS_PK_ECKEY, + "EC", + eckey_get_bitlen, + eckey_can_do, +#if defined(MBEDTLS_ECDSA_C) + eckey_verify_wrap, + eckey_sign_wrap, +#if defined(MBEDTLS_ECP_RESTARTABLE) + eckey_verify_rs_wrap, + eckey_sign_rs_wrap, +#endif +#else /* MBEDTLS_ECDSA_C */ + NULL, + NULL, +#endif /* MBEDTLS_ECDSA_C */ + NULL, + NULL, + eckey_check_pair, + eckey_alloc_wrap, + eckey_free_wrap, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + eckey_rs_alloc, + eckey_rs_free, +#endif + eckey_debug, +}; + +/* + * EC key restricted to ECDH + */ +static int eckeydh_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_ECKEY || + type == MBEDTLS_PK_ECKEY_DH ); +} + +const mbedtls_pk_info_t mbedtls_eckeydh_info = { + MBEDTLS_PK_ECKEY_DH, + "EC_DH", + eckey_get_bitlen, /* Same underlying key structure */ + eckeydh_can_do, + NULL, + NULL, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, + NULL, +#endif + NULL, + NULL, + eckey_check_pair, + eckey_alloc_wrap, /* Same underlying key structure */ + eckey_free_wrap, /* Same underlying key structure */ +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, + NULL, +#endif + eckey_debug, /* Same underlying key structure */ +}; +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_ECDSA_C) +static int ecdsa_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_ECDSA ); +} + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +/* + * An ASN.1 encoded signature is a sequence of two ASN.1 integers. Parse one of + * those integers and convert it to the fixed-length encoding expected by PSA. + */ +static int extract_ecdsa_sig_int( unsigned char **from, const unsigned char *end, + unsigned char *to, size_t to_len ) +{ + int ret; + size_t unpadded_len, padding_len; + + if( ( ret = mbedtls_asn1_get_tag( from, end, &unpadded_len, + MBEDTLS_ASN1_INTEGER ) ) != 0 ) + { + return( ret ); + } + + while( unpadded_len > 0 && **from == 0x00 ) + { + ( *from )++; + unpadded_len--; + } + + if( unpadded_len > to_len || unpadded_len == 0 ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + padding_len = to_len - unpadded_len; + memset( to, 0x00, padding_len ); + memcpy( to + padding_len, *from, unpadded_len ); + ( *from ) += unpadded_len; + + return( 0 ); +} + +/* + * Convert a signature from an ASN.1 sequence of two integers + * to a raw {r,s} buffer. Note: the provided sig buffer must be at least + * twice as big as int_size. + */ +static int extract_ecdsa_sig( unsigned char **p, const unsigned char *end, + unsigned char *sig, size_t int_size ) +{ + int ret; + size_t tmp_size; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &tmp_size, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + /* Extract r */ + if( ( ret = extract_ecdsa_sig_int( p, end, sig, int_size ) ) != 0 ) + return( ret ); + /* Extract s */ + if( ( ret = extract_ecdsa_sig_int( p, end, sig + int_size, int_size ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + int ret; + psa_key_handle_t key_slot; + psa_key_policy_t policy; + psa_key_type_t psa_type; + mbedtls_pk_context key; + int key_len; + /* see ECP_PUB_DER_MAX_BYTES in pkwrite.c */ + unsigned char buf[30 + 2 * MBEDTLS_ECP_MAX_BYTES]; + unsigned char *p; + mbedtls_pk_info_t pk_info = mbedtls_eckey_info; + psa_algorithm_t psa_sig_md, psa_md; + psa_ecc_curve_t curve = mbedtls_psa_translate_ecc_group( + ( (mbedtls_ecdsa_context *) ctx )->grp.id ); + const size_t signature_part_size = ( ( (mbedtls_ecdsa_context *) ctx )->grp.nbits + 7 ) / 8; + + if( curve == 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + /* mbedtls_pk_write_pubkey() expects a full PK context; + * re-construct one to make it happy */ + key.pk_info = &pk_info; + key.pk_ctx = ctx; + p = buf + sizeof( buf ); + key_len = mbedtls_pk_write_pubkey( &p, buf, &key ); + if( key_len <= 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + psa_md = mbedtls_psa_translate_md( md_alg ); + if( psa_md == 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + psa_sig_md = PSA_ALG_ECDSA( psa_md ); + psa_type = PSA_KEY_TYPE_ECC_PUBLIC_KEY( curve ); + + if( ( ret = psa_allocate_key( &key_slot ) ) != PSA_SUCCESS ) + return( mbedtls_psa_err_translate_pk( ret ) ); + + policy = psa_key_policy_init(); + psa_key_policy_set_usage( &policy, PSA_KEY_USAGE_VERIFY, psa_sig_md ); + if( ( ret = psa_set_key_policy( key_slot, &policy ) ) != PSA_SUCCESS ) + { + ret = mbedtls_psa_err_translate_pk( ret ); + goto cleanup; + } + + if( psa_import_key( key_slot, psa_type, buf + sizeof( buf ) - key_len, key_len ) + != PSA_SUCCESS ) + { + ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; + goto cleanup; + } + + /* We don't need the exported key anymore and can + * reuse its buffer for signature extraction. */ + if( 2 * signature_part_size > sizeof( buf ) ) + { + ret = MBEDTLS_ERR_PK_BAD_INPUT_DATA; + goto cleanup; + } + + p = (unsigned char*) sig; + if( ( ret = extract_ecdsa_sig( &p, sig + sig_len, buf, + signature_part_size ) ) != 0 ) + { + goto cleanup; + } + + if( psa_asymmetric_verify( key_slot, psa_sig_md, + hash, hash_len, + buf, 2 * signature_part_size ) + != PSA_SUCCESS ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + + if( p != sig + sig_len ) + { + ret = MBEDTLS_ERR_PK_SIG_LEN_MISMATCH; + goto cleanup; + } + ret = 0; + +cleanup: + psa_destroy_key( key_slot ); + return( ret ); +} +#else /* MBEDTLS_USE_PSA_CRYPTO */ +static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + int ret; + ((void) md_alg); + + ret = mbedtls_ecdsa_read_signature( (mbedtls_ecdsa_context *) ctx, + hash, hash_len, sig, sig_len ); + + if( ret == MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + + return( ret ); +} +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +static int ecdsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + return( mbedtls_ecdsa_write_signature( (mbedtls_ecdsa_context *) ctx, + md_alg, hash, hash_len, sig, sig_len, f_rng, p_rng ) ); +} + +#if defined(MBEDTLS_ECP_RESTARTABLE) +static int ecdsa_verify_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len, + void *rs_ctx ) +{ + int ret; + ((void) md_alg); + + ret = mbedtls_ecdsa_read_signature_restartable( + (mbedtls_ecdsa_context *) ctx, + hash, hash_len, sig, sig_len, + (mbedtls_ecdsa_restart_ctx *) rs_ctx ); + + if( ret == MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + + return( ret ); +} + +static int ecdsa_sign_rs_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + void *rs_ctx ) +{ + return( mbedtls_ecdsa_write_signature_restartable( + (mbedtls_ecdsa_context *) ctx, + md_alg, hash, hash_len, sig, sig_len, f_rng, p_rng, + (mbedtls_ecdsa_restart_ctx *) rs_ctx ) ); + +} +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +static void *ecdsa_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecdsa_context ) ); + + if( ctx != NULL ) + mbedtls_ecdsa_init( (mbedtls_ecdsa_context *) ctx ); + + return( ctx ); +} + +static void ecdsa_free_wrap( void *ctx ) +{ + mbedtls_ecdsa_free( (mbedtls_ecdsa_context *) ctx ); + mbedtls_free( ctx ); +} + +#if defined(MBEDTLS_ECP_RESTARTABLE) +static void *ecdsa_rs_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecdsa_restart_ctx ) ); + + if( ctx != NULL ) + mbedtls_ecdsa_restart_init( ctx ); + + return( ctx ); +} + +static void ecdsa_rs_free( void *ctx ) +{ + mbedtls_ecdsa_restart_free( ctx ); + mbedtls_free( ctx ); +} +#endif /* MBEDTLS_ECP_RESTARTABLE */ + +const mbedtls_pk_info_t mbedtls_ecdsa_info = { + MBEDTLS_PK_ECDSA, + "ECDSA", + eckey_get_bitlen, /* Compatible key structures */ + ecdsa_can_do, + ecdsa_verify_wrap, + ecdsa_sign_wrap, +#if defined(MBEDTLS_ECP_RESTARTABLE) + ecdsa_verify_rs_wrap, + ecdsa_sign_rs_wrap, +#endif + NULL, + NULL, + eckey_check_pair, /* Compatible key structures */ + ecdsa_alloc_wrap, + ecdsa_free_wrap, +#if defined(MBEDTLS_ECP_RESTARTABLE) + ecdsa_rs_alloc, + ecdsa_rs_free, +#endif + eckey_debug, /* Compatible key structures */ +}; +#endif /* MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* + * Support for alternative RSA-private implementations + */ + +static int rsa_alt_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_RSA ); +} + +static size_t rsa_alt_get_bitlen( const void *ctx ) +{ + const mbedtls_rsa_alt_context *rsa_alt = (const mbedtls_rsa_alt_context *) ctx; + + return( 8 * rsa_alt->key_len_func( rsa_alt->key ) ); +} + +static int rsa_alt_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + mbedtls_rsa_alt_context *rsa_alt = (mbedtls_rsa_alt_context *) ctx; + +#if SIZE_MAX > UINT_MAX + if( UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* SIZE_MAX > UINT_MAX */ + + *sig_len = rsa_alt->key_len_func( rsa_alt->key ); + + return( rsa_alt->sign_func( rsa_alt->key, f_rng, p_rng, MBEDTLS_RSA_PRIVATE, + md_alg, (unsigned int) hash_len, hash, sig ) ); +} + +static int rsa_alt_decrypt_wrap( void *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + mbedtls_rsa_alt_context *rsa_alt = (mbedtls_rsa_alt_context *) ctx; + + ((void) f_rng); + ((void) p_rng); + + if( ilen != rsa_alt->key_len_func( rsa_alt->key ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + return( rsa_alt->decrypt_func( rsa_alt->key, + MBEDTLS_RSA_PRIVATE, olen, input, output, osize ) ); +} + +#if defined(MBEDTLS_RSA_C) +static int rsa_alt_check_pair( const void *pub, const void *prv ) +{ + unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; + unsigned char hash[32]; + size_t sig_len = 0; + int ret; + + if( rsa_alt_get_bitlen( prv ) != rsa_get_bitlen( pub ) ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + memset( hash, 0x2a, sizeof( hash ) ); + + if( ( ret = rsa_alt_sign_wrap( (void *) prv, MBEDTLS_MD_NONE, + hash, sizeof( hash ), + sig, &sig_len, NULL, NULL ) ) != 0 ) + { + return( ret ); + } + + if( rsa_verify_wrap( (void *) pub, MBEDTLS_MD_NONE, + hash, sizeof( hash ), sig, sig_len ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + return( 0 ); +} +#endif /* MBEDTLS_RSA_C */ + +static void *rsa_alt_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_rsa_alt_context ) ); + + if( ctx != NULL ) + memset( ctx, 0, sizeof( mbedtls_rsa_alt_context ) ); + + return( ctx ); +} + +static void rsa_alt_free_wrap( void *ctx ) +{ + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_rsa_alt_context ) ); + mbedtls_free( ctx ); +} + +const mbedtls_pk_info_t mbedtls_rsa_alt_info = { + MBEDTLS_PK_RSA_ALT, + "RSA-alt", + rsa_alt_get_bitlen, + rsa_alt_can_do, + NULL, + rsa_alt_sign_wrap, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, + NULL, +#endif + rsa_alt_decrypt_wrap, + NULL, +#if defined(MBEDTLS_RSA_C) + rsa_alt_check_pair, +#else + NULL, +#endif + rsa_alt_alloc_wrap, + rsa_alt_free_wrap, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, + NULL, +#endif + NULL, +}; + +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + +static void *pk_opaque_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( psa_key_handle_t ) ); + + /* no _init() function to call, an calloc() already zeroized */ + + return( ctx ); +} + +static void pk_opaque_free_wrap( void *ctx ) +{ + mbedtls_platform_zeroize( ctx, sizeof( psa_key_handle_t ) ); + mbedtls_free( ctx ); +} + +static size_t pk_opaque_get_bitlen( const void *ctx ) +{ + const psa_key_handle_t *key = (const psa_key_handle_t *) ctx; + size_t bits; + + if( PSA_SUCCESS != psa_get_key_information( *key, NULL, &bits ) ) + return( 0 ); + + return( bits ); +} + +static int pk_opaque_can_do( mbedtls_pk_type_t type ) +{ + /* For now opaque PSA keys can only wrap ECC keypairs, + * as checked by setup_psa(). + * Also, ECKEY_DH does not really make sense with the current API. */ + return( type == MBEDTLS_PK_ECKEY || + type == MBEDTLS_PK_ECDSA ); +} + +/* + * Simultaneously convert and move raw MPI from the beginning of a buffer + * to an ASN.1 MPI at the end of the buffer. + * See also mbedtls_asn1_write_mpi(). + * + * p: pointer to the end of the output buffer + * start: start of the output buffer, and also of the mpi to write at the end + * n_len: length of the mpi to read from start + */ +static int asn1_write_mpibuf( unsigned char **p, unsigned char *start, + size_t n_len ) +{ + int ret; + size_t len = 0; + + if( (size_t)( *p - start ) < n_len ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len = n_len; + *p -= len; + memmove( *p, start, len ); + + /* ASN.1 DER encoding requires minimal length, so skip leading 0s. + * Neither r nor s should be 0, but as a failsafe measure, still detect + * that rather than overflowing the buffer in case of a PSA error. */ + while( len > 0 && **p == 0x00 ) + { + ++(*p); + --len; + } + + /* this is only reached if the signature was invalid */ + if( len == 0 ) + return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED ); + + /* if the msb is 1, ASN.1 requires that we prepend a 0. + * Neither r nor s can be 0, so we can assume len > 0 at all times. */ + if( **p & 0x80 ) + { + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0x00; + len += 1; + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, + MBEDTLS_ASN1_INTEGER ) ); + + return( (int) len ); +} + +/* Transcode signature from PSA format to ASN.1 sequence. + * See ecdsa_signature_to_asn1 in ecdsa.c, but with byte buffers instead of + * MPIs, and in-place. + * + * [in/out] sig: the signature pre- and post-transcoding + * [in/out] sig_len: signature length pre- and post-transcoding + * [int] buf_len: the available size the in/out buffer + */ +static int pk_ecdsa_sig_asn1_from_psa( unsigned char *sig, size_t *sig_len, + size_t buf_len ) +{ + int ret; + size_t len = 0; + const size_t rs_len = *sig_len / 2; + unsigned char *p = sig + buf_len; + + MBEDTLS_ASN1_CHK_ADD( len, asn1_write_mpibuf( &p, sig + rs_len, rs_len ) ); + MBEDTLS_ASN1_CHK_ADD( len, asn1_write_mpibuf( &p, sig, rs_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &p, sig, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &p, sig, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); + + memmove( sig, p, len ); + *sig_len = len; + + return( 0 ); +} + +static int pk_opaque_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + const psa_key_handle_t *key = (const psa_key_handle_t *) ctx; + psa_algorithm_t alg = PSA_ALG_ECDSA( mbedtls_psa_translate_md( md_alg ) ); + size_t bits, buf_len; + psa_status_t status; + + /* PSA has its own RNG */ + (void) f_rng; + (void) p_rng; + + /* PSA needs an output buffer of known size, but our API doesn't provide + * that information. Assume that the buffer is large enough for a + * maximal-length signature with that key (otherwise the application is + * buggy anyway). */ + status = psa_get_key_information( *key, NULL, &bits ); + if( status != PSA_SUCCESS ) + return( mbedtls_psa_err_translate_pk( status ) ); + + buf_len = MBEDTLS_ECDSA_MAX_SIG_LEN( bits ); + + /* make the signature */ + status = psa_asymmetric_sign( *key, alg, hash, hash_len, + sig, buf_len, sig_len ); + if( status != PSA_SUCCESS ) + return( mbedtls_psa_err_translate_pk( status ) ); + + /* transcode it to ASN.1 sequence */ + return( pk_ecdsa_sig_asn1_from_psa( sig, sig_len, buf_len ) ); +} + +const mbedtls_pk_info_t mbedtls_pk_opaque_info = { + MBEDTLS_PK_OPAQUE, + "Opaque", + pk_opaque_get_bitlen, + pk_opaque_can_do, + NULL, /* verify - will be done later */ + pk_opaque_sign_wrap, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, /* restartable verify - not relevant */ + NULL, /* restartable sign - not relevant */ +#endif + NULL, /* decrypt - will be done later */ + NULL, /* encrypt - will be done later */ + NULL, /* check_pair - could be done later or left NULL */ + pk_opaque_alloc_wrap, + pk_opaque_free_wrap, +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + NULL, /* restart alloc - not relevant */ + NULL, /* restart free - not relevant */ +#endif + NULL, /* debug - could be done later, or even left NULL */ +}; + +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#endif /* MBEDTLS_PK_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/pkcs11.c b/FreeRTOS-Labs/Source/mbedtls/library/pkcs11.c new file mode 100644 index 000000000..aca4a2699 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/pkcs11.c @@ -0,0 +1,240 @@ +/** + * \file pkcs11.c + * + * \brief Wrapper for PKCS#11 library libpkcs11-helper + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/pkcs11.h" + +#if defined(MBEDTLS_PKCS11_C) + +#include "mbedtls/md.h" +#include "mbedtls/oid.h" +#include "mbedtls/x509_crt.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include + +void mbedtls_pkcs11_init( mbedtls_pkcs11_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_pkcs11_context ) ); +} + +int mbedtls_pkcs11_x509_cert_bind( mbedtls_x509_crt *cert, pkcs11h_certificate_t pkcs11_cert ) +{ + int ret = 1; + unsigned char *cert_blob = NULL; + size_t cert_blob_size = 0; + + if( cert == NULL ) + { + ret = 2; + goto cleanup; + } + + if( pkcs11h_certificate_getCertificateBlob( pkcs11_cert, NULL, + &cert_blob_size ) != CKR_OK ) + { + ret = 3; + goto cleanup; + } + + cert_blob = mbedtls_calloc( 1, cert_blob_size ); + if( NULL == cert_blob ) + { + ret = 4; + goto cleanup; + } + + if( pkcs11h_certificate_getCertificateBlob( pkcs11_cert, cert_blob, + &cert_blob_size ) != CKR_OK ) + { + ret = 5; + goto cleanup; + } + + if( 0 != mbedtls_x509_crt_parse( cert, cert_blob, cert_blob_size ) ) + { + ret = 6; + goto cleanup; + } + + ret = 0; + +cleanup: + if( NULL != cert_blob ) + mbedtls_free( cert_blob ); + + return( ret ); +} + + +int mbedtls_pkcs11_priv_key_bind( mbedtls_pkcs11_context *priv_key, + pkcs11h_certificate_t pkcs11_cert ) +{ + int ret = 1; + mbedtls_x509_crt cert; + + mbedtls_x509_crt_init( &cert ); + + if( priv_key == NULL ) + goto cleanup; + + if( 0 != mbedtls_pkcs11_x509_cert_bind( &cert, pkcs11_cert ) ) + goto cleanup; + + priv_key->len = mbedtls_pk_get_len( &cert.pk ); + priv_key->pkcs11h_cert = pkcs11_cert; + + ret = 0; + +cleanup: + mbedtls_x509_crt_free( &cert ); + + return( ret ); +} + +void mbedtls_pkcs11_priv_key_free( mbedtls_pkcs11_context *priv_key ) +{ + if( NULL != priv_key ) + pkcs11h_certificate_freeCertificate( priv_key->pkcs11h_cert ); +} + +int mbedtls_pkcs11_decrypt( mbedtls_pkcs11_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ) +{ + size_t input_len, output_len; + + if( NULL == ctx ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( MBEDTLS_RSA_PRIVATE != mode ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + output_len = input_len = ctx->len; + + if( input_len < 16 || input_len > output_max_len ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* Determine size of output buffer */ + if( pkcs11h_certificate_decryptAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, input, + input_len, NULL, &output_len ) != CKR_OK ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + if( output_len > output_max_len ) + return( MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE ); + + if( pkcs11h_certificate_decryptAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, input, + input_len, output, &output_len ) != CKR_OK ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + *olen = output_len; + return( 0 ); +} + +int mbedtls_pkcs11_sign( mbedtls_pkcs11_context *ctx, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + size_t sig_len = 0, asn_len = 0, oid_size = 0; + unsigned char *p = sig; + const char *oid; + + if( NULL == ctx ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( MBEDTLS_RSA_PRIVATE != mode ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( md_alg != MBEDTLS_MD_NONE ) + { + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hashlen = mbedtls_md_get_size( md_info ); + asn_len = 10 + oid_size; + } + + sig_len = ctx->len; + if( hashlen > sig_len || asn_len > sig_len || + hashlen + asn_len > sig_len ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + if( md_alg != MBEDTLS_MD_NONE ) + { + /* + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * Digest ::= OCTET STRING + */ + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char) ( 0x08 + oid_size + hashlen ); + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char) ( 0x04 + oid_size ); + *p++ = MBEDTLS_ASN1_OID; + *p++ = oid_size & 0xFF; + memcpy( p, oid, oid_size ); + p += oid_size; + *p++ = MBEDTLS_ASN1_NULL; + *p++ = 0x00; + *p++ = MBEDTLS_ASN1_OCTET_STRING; + *p++ = hashlen; + } + + memcpy( p, hash, hashlen ); + + if( pkcs11h_certificate_signAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, sig, + asn_len + hashlen, sig, &sig_len ) != CKR_OK ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + return( 0 ); +} + +#endif /* defined(MBEDTLS_PKCS11_C) */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/pkcs12.c b/FreeRTOS-Labs/Source/mbedtls/library/pkcs12.c new file mode 100644 index 000000000..f4a427bdc --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/pkcs12.c @@ -0,0 +1,365 @@ +/* + * PKCS#12 Personal Information Exchange Syntax + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The PKCS #12 Personal Information Exchange Syntax Standard v1.1 + * + * http://www.rsa.com/rsalabs/pkcs/files/h11301-wp-pkcs-12v1-1-personal-information-exchange-syntax.pdf + * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1-1.asn + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PKCS12_C) + +#include "mbedtls/pkcs12.h" +#include "mbedtls/asn1.h" +#include "mbedtls/cipher.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_ARC4_C) +#include "mbedtls/arc4.h" +#endif + +#if defined(MBEDTLS_DES_C) +#include "mbedtls/des.h" +#endif + +#if defined(MBEDTLS_ASN1_PARSE_C) + +static int pkcs12_parse_pbe_params( mbedtls_asn1_buf *params, + mbedtls_asn1_buf *salt, int *iterations ) +{ + int ret; + unsigned char **p = ¶ms->p; + const unsigned char *end = params->p + params->len; + + /* + * pkcs-12PbeParams ::= SEQUENCE { + * salt OCTET STRING, + * iterations INTEGER + * } + * + */ + if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + if( ( ret = mbedtls_asn1_get_tag( p, end, &salt->len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + ret ); + + salt->p = *p; + *p += salt->len; + + if( ( ret = mbedtls_asn1_get_int( p, end, iterations ) ) != 0 ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +#define PKCS12_MAX_PWDLEN 128 + +static int pkcs12_pbe_derive_key_iv( mbedtls_asn1_buf *pbe_params, mbedtls_md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + unsigned char *key, size_t keylen, + unsigned char *iv, size_t ivlen ) +{ + int ret, iterations = 0; + mbedtls_asn1_buf salt; + size_t i; + unsigned char unipwd[PKCS12_MAX_PWDLEN * 2 + 2]; + + if( pwdlen > PKCS12_MAX_PWDLEN ) + return( MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA ); + + memset( &salt, 0, sizeof(mbedtls_asn1_buf) ); + memset( &unipwd, 0, sizeof(unipwd) ); + + if( ( ret = pkcs12_parse_pbe_params( pbe_params, &salt, + &iterations ) ) != 0 ) + return( ret ); + + for( i = 0; i < pwdlen; i++ ) + unipwd[i * 2 + 1] = pwd[i]; + + if( ( ret = mbedtls_pkcs12_derivation( key, keylen, unipwd, pwdlen * 2 + 2, + salt.p, salt.len, md_type, + MBEDTLS_PKCS12_DERIVE_KEY, iterations ) ) != 0 ) + { + return( ret ); + } + + if( iv == NULL || ivlen == 0 ) + return( 0 ); + + if( ( ret = mbedtls_pkcs12_derivation( iv, ivlen, unipwd, pwdlen * 2 + 2, + salt.p, salt.len, md_type, + MBEDTLS_PKCS12_DERIVE_IV, iterations ) ) != 0 ) + { + return( ret ); + } + return( 0 ); +} + +#undef PKCS12_MAX_PWDLEN + +int mbedtls_pkcs12_pbe_sha1_rc4_128( mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t len, + unsigned char *output ) +{ +#if !defined(MBEDTLS_ARC4_C) + ((void) pbe_params); + ((void) mode); + ((void) pwd); + ((void) pwdlen); + ((void) data); + ((void) len); + ((void) output); + return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); +#else + int ret; + unsigned char key[16]; + mbedtls_arc4_context ctx; + ((void) mode); + + mbedtls_arc4_init( &ctx ); + + if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, MBEDTLS_MD_SHA1, + pwd, pwdlen, + key, 16, NULL, 0 ) ) != 0 ) + { + return( ret ); + } + + mbedtls_arc4_setup( &ctx, key, 16 ); + if( ( ret = mbedtls_arc4_crypt( &ctx, len, data, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_platform_zeroize( key, sizeof( key ) ); + mbedtls_arc4_free( &ctx ); + + return( ret ); +#endif /* MBEDTLS_ARC4_C */ +} + +int mbedtls_pkcs12_pbe( mbedtls_asn1_buf *pbe_params, int mode, + mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t len, + unsigned char *output ) +{ + int ret, keylen = 0; + unsigned char key[32]; + unsigned char iv[16]; + const mbedtls_cipher_info_t *cipher_info; + mbedtls_cipher_context_t cipher_ctx; + size_t olen = 0; + + cipher_info = mbedtls_cipher_info_from_type( cipher_type ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); + + keylen = cipher_info->key_bitlen / 8; + + if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, md_type, pwd, pwdlen, + key, keylen, + iv, cipher_info->iv_size ) ) != 0 ) + { + return( ret ); + } + + mbedtls_cipher_init( &cipher_ctx ); + + if( ( ret = mbedtls_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen, (mbedtls_operation_t) mode ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_set_iv( &cipher_ctx, iv, cipher_info->iv_size ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_reset( &cipher_ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_update( &cipher_ctx, data, len, + output, &olen ) ) != 0 ) + { + goto exit; + } + + if( ( ret = mbedtls_cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 ) + ret = MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH; + +exit: + mbedtls_platform_zeroize( key, sizeof( key ) ); + mbedtls_platform_zeroize( iv, sizeof( iv ) ); + mbedtls_cipher_free( &cipher_ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_ASN1_PARSE_C */ + +static void pkcs12_fill_buffer( unsigned char *data, size_t data_len, + const unsigned char *filler, size_t fill_len ) +{ + unsigned char *p = data; + size_t use_len; + + while( data_len > 0 ) + { + use_len = ( data_len > fill_len ) ? fill_len : data_len; + memcpy( p, filler, use_len ); + p += use_len; + data_len -= use_len; + } +} + +int mbedtls_pkcs12_derivation( unsigned char *data, size_t datalen, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *salt, size_t saltlen, + mbedtls_md_type_t md_type, int id, int iterations ) +{ + int ret; + unsigned int j; + + unsigned char diversifier[128]; + unsigned char salt_block[128], pwd_block[128], hash_block[128]; + unsigned char hash_output[MBEDTLS_MD_MAX_SIZE]; + unsigned char *p; + unsigned char c; + + size_t hlen, use_len, v, i; + + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + // This version only allows max of 64 bytes of password or salt + if( datalen > 128 || pwdlen > 64 || saltlen > 64 ) + return( MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA ); + + md_info = mbedtls_md_info_from_type( md_type ); + if( md_info == NULL ) + return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); + + mbedtls_md_init( &md_ctx ); + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + return( ret ); + hlen = mbedtls_md_get_size( md_info ); + + if( hlen <= 32 ) + v = 64; + else + v = 128; + + memset( diversifier, (unsigned char) id, v ); + + pkcs12_fill_buffer( salt_block, v, salt, saltlen ); + pkcs12_fill_buffer( pwd_block, v, pwd, pwdlen ); + + p = data; + while( datalen > 0 ) + { + // Calculate hash( diversifier || salt_block || pwd_block ) + if( ( ret = mbedtls_md_starts( &md_ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_update( &md_ctx, diversifier, v ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_update( &md_ctx, salt_block, v ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_update( &md_ctx, pwd_block, v ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_finish( &md_ctx, hash_output ) ) != 0 ) + goto exit; + + // Perform remaining ( iterations - 1 ) recursive hash calculations + for( i = 1; i < (size_t) iterations; i++ ) + { + if( ( ret = mbedtls_md( md_info, hash_output, hlen, hash_output ) ) != 0 ) + goto exit; + } + + use_len = ( datalen > hlen ) ? hlen : datalen; + memcpy( p, hash_output, use_len ); + datalen -= use_len; + p += use_len; + + if( datalen == 0 ) + break; + + // Concatenating copies of hash_output into hash_block (B) + pkcs12_fill_buffer( hash_block, v, hash_output, hlen ); + + // B += 1 + for( i = v; i > 0; i-- ) + if( ++hash_block[i - 1] != 0 ) + break; + + // salt_block += B + c = 0; + for( i = v; i > 0; i-- ) + { + j = salt_block[i - 1] + hash_block[i - 1] + c; + c = (unsigned char) (j >> 8); + salt_block[i - 1] = j & 0xFF; + } + + // pwd_block += B + c = 0; + for( i = v; i > 0; i-- ) + { + j = pwd_block[i - 1] + hash_block[i - 1] + c; + c = (unsigned char) (j >> 8); + pwd_block[i - 1] = j & 0xFF; + } + } + + ret = 0; + +exit: + mbedtls_platform_zeroize( salt_block, sizeof( salt_block ) ); + mbedtls_platform_zeroize( pwd_block, sizeof( pwd_block ) ); + mbedtls_platform_zeroize( hash_block, sizeof( hash_block ) ); + mbedtls_platform_zeroize( hash_output, sizeof( hash_output ) ); + + mbedtls_md_free( &md_ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_PKCS12_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/pkcs5.c b/FreeRTOS-Labs/Source/mbedtls/library/pkcs5.c new file mode 100644 index 000000000..e7247e41c --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/pkcs5.c @@ -0,0 +1,417 @@ +/** + * \file pkcs5.c + * + * \brief PKCS#5 functions + * + * \author Mathias Olsson + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * PKCS#5 includes PBKDF2 and more + * + * http://tools.ietf.org/html/rfc2898 (Specification) + * http://tools.ietf.org/html/rfc6070 (Test vectors) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PKCS5_C) + +#include "mbedtls/pkcs5.h" + +#if defined(MBEDTLS_ASN1_PARSE_C) +#include "mbedtls/asn1.h" +#include "mbedtls/cipher.h" +#include "mbedtls/oid.h" +#endif /* MBEDTLS_ASN1_PARSE_C */ + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif + +#if defined(MBEDTLS_ASN1_PARSE_C) +static int pkcs5_parse_pbkdf2_params( const mbedtls_asn1_buf *params, + mbedtls_asn1_buf *salt, int *iterations, + int *keylen, mbedtls_md_type_t *md_type ) +{ + int ret; + mbedtls_asn1_buf prf_alg_oid; + unsigned char *p = params->p; + const unsigned char *end = params->p + params->len; + + if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + /* + * PBKDF2-params ::= SEQUENCE { + * salt OCTET STRING, + * iterationCount INTEGER, + * keyLength INTEGER OPTIONAL + * prf AlgorithmIdentifier DEFAULT algid-hmacWithSHA1 + * } + * + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &salt->len, + MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + salt->p = p; + p += salt->len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, iterations ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + if( p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_int( &p, end, keylen ) ) != 0 ) + { + if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + } + + if( p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_alg_null( &p, end, &prf_alg_oid ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + if( mbedtls_oid_get_md_hmac( &prf_alg_oid, md_type ) != 0 ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + if( p != end ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +int mbedtls_pkcs5_pbes2( const mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t datalen, + unsigned char *output ) +{ + int ret, iterations = 0, keylen = 0; + unsigned char *p, *end; + mbedtls_asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params; + mbedtls_asn1_buf salt; + mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1; + unsigned char key[32], iv[32]; + size_t olen = 0; + const mbedtls_md_info_t *md_info; + const mbedtls_cipher_info_t *cipher_info; + mbedtls_md_context_t md_ctx; + mbedtls_cipher_type_t cipher_alg; + mbedtls_cipher_context_t cipher_ctx; + + p = pbe_params->p; + end = p + pbe_params->len; + + /* + * PBES2-params ::= SEQUENCE { + * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, + * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} + * } + */ + if( pbe_params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + if( ( ret = mbedtls_asn1_get_alg( &p, end, &kdf_alg_oid, + &kdf_alg_params ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + // Only PBKDF2 supported at the moment + // + if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBKDF2, &kdf_alg_oid ) != 0 ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + if( ( ret = pkcs5_parse_pbkdf2_params( &kdf_alg_params, + &salt, &iterations, &keylen, + &md_type ) ) != 0 ) + { + return( ret ); + } + + md_info = mbedtls_md_info_from_type( md_type ); + if( md_info == NULL ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + if( ( ret = mbedtls_asn1_get_alg( &p, end, &enc_scheme_oid, + &enc_scheme_params ) ) != 0 ) + { + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + } + + if( mbedtls_oid_get_cipher_alg( &enc_scheme_oid, &cipher_alg ) != 0 ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + cipher_info = mbedtls_cipher_info_from_type( cipher_alg ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + /* + * The value of keylen from pkcs5_parse_pbkdf2_params() is ignored + * since it is optional and we don't know if it was set or not + */ + keylen = cipher_info->key_bitlen / 8; + + if( enc_scheme_params.tag != MBEDTLS_ASN1_OCTET_STRING || + enc_scheme_params.len != cipher_info->iv_size ) + { + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT ); + } + + mbedtls_md_init( &md_ctx ); + mbedtls_cipher_init( &cipher_ctx ); + + memcpy( iv, enc_scheme_params.p, enc_scheme_params.len ); + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_pkcs5_pbkdf2_hmac( &md_ctx, pwd, pwdlen, salt.p, salt.len, + iterations, keylen, key ) ) != 0 ) + { + goto exit; + } + + if( ( ret = mbedtls_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen, + (mbedtls_operation_t) mode ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_crypt( &cipher_ctx, iv, enc_scheme_params.len, + data, datalen, output, &olen ) ) != 0 ) + ret = MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH; + +exit: + mbedtls_md_free( &md_ctx ); + mbedtls_cipher_free( &cipher_ctx ); + + return( ret ); +} +#endif /* MBEDTLS_ASN1_PARSE_C */ + +int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, + const unsigned char *password, + size_t plen, const unsigned char *salt, size_t slen, + unsigned int iteration_count, + uint32_t key_length, unsigned char *output ) +{ + int ret, j; + unsigned int i; + unsigned char md1[MBEDTLS_MD_MAX_SIZE]; + unsigned char work[MBEDTLS_MD_MAX_SIZE]; + unsigned char md_size = mbedtls_md_get_size( ctx->md_info ); + size_t use_len; + unsigned char *out_p = output; + unsigned char counter[4]; + + memset( counter, 0, 4 ); + counter[3] = 1; + +#if UINT_MAX > 0xFFFFFFFF + if( iteration_count > 0xFFFFFFFF ) + return( MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA ); +#endif + + while( key_length ) + { + // U1 ends up in work + // + if( ( ret = mbedtls_md_hmac_starts( ctx, password, plen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_update( ctx, salt, slen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_update( ctx, counter, 4 ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_finish( ctx, work ) ) != 0 ) + return( ret ); + + memcpy( md1, work, md_size ); + + for( i = 1; i < iteration_count; i++ ) + { + // U2 ends up in md1 + // + if( ( ret = mbedtls_md_hmac_starts( ctx, password, plen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_update( ctx, md1, md_size ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_finish( ctx, md1 ) ) != 0 ) + return( ret ); + + // U1 xor U2 + // + for( j = 0; j < md_size; j++ ) + work[j] ^= md1[j]; + } + + use_len = ( key_length < md_size ) ? key_length : md_size; + memcpy( out_p, work, use_len ); + + key_length -= (uint32_t) use_len; + out_p += use_len; + + for( i = 4; i > 0; i-- ) + if( ++counter[i - 1] != 0 ) + break; + } + + return( 0 ); +} + +#if defined(MBEDTLS_SELF_TEST) + +#if !defined(MBEDTLS_SHA1_C) +int mbedtls_pkcs5_self_test( int verbose ) +{ + if( verbose != 0 ) + mbedtls_printf( " PBKDF2 (SHA1): skipped\n\n" ); + + return( 0 ); +} +#else + +#define MAX_TESTS 6 + +static const size_t plen_test_data[MAX_TESTS] = + { 8, 8, 8, 24, 9 }; + +static const unsigned char password_test_data[MAX_TESTS][32] = +{ + "password", + "password", + "password", + "passwordPASSWORDpassword", + "pass\0word", +}; + +static const size_t slen_test_data[MAX_TESTS] = + { 4, 4, 4, 36, 5 }; + +static const unsigned char salt_test_data[MAX_TESTS][40] = +{ + "salt", + "salt", + "salt", + "saltSALTsaltSALTsaltSALTsaltSALTsalt", + "sa\0lt", +}; + +static const uint32_t it_cnt_test_data[MAX_TESTS] = + { 1, 2, 4096, 4096, 4096 }; + +static const uint32_t key_len_test_data[MAX_TESTS] = + { 20, 20, 20, 25, 16 }; + +static const unsigned char result_key_test_data[MAX_TESTS][32] = +{ + { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71, + 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06, + 0x2f, 0xe0, 0x37, 0xa6 }, + { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c, + 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0, + 0xd8, 0xde, 0x89, 0x57 }, + { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a, + 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0, + 0x65, 0xa4, 0x29, 0xc1 }, + { 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b, + 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a, + 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, + 0x38 }, + { 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d, + 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 }, +}; + +int mbedtls_pkcs5_self_test( int verbose ) +{ + mbedtls_md_context_t sha1_ctx; + const mbedtls_md_info_t *info_sha1; + int ret, i; + unsigned char key[64]; + + mbedtls_md_init( &sha1_ctx ); + + info_sha1 = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ); + if( info_sha1 == NULL ) + { + ret = 1; + goto exit; + } + + if( ( ret = mbedtls_md_setup( &sha1_ctx, info_sha1, 1 ) ) != 0 ) + { + ret = 1; + goto exit; + } + + for( i = 0; i < MAX_TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " PBKDF2 (SHA1) #%d: ", i ); + + ret = mbedtls_pkcs5_pbkdf2_hmac( &sha1_ctx, password_test_data[i], + plen_test_data[i], salt_test_data[i], + slen_test_data[i], it_cnt_test_data[i], + key_len_test_data[i], key ); + if( ret != 0 || + memcmp( result_key_test_data[i], key, key_len_test_data[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_md_free( &sha1_ctx ); + + return( ret ); +} +#endif /* MBEDTLS_SHA1_C */ + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_PKCS5_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/pkparse.c b/FreeRTOS-Labs/Source/mbedtls/library/pkparse.c new file mode 100644 index 000000000..9123b1313 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/pkparse.c @@ -0,0 +1,1482 @@ +/* + * Public Key layer for parsing key files and structures + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_PARSE_C) + +#include "mbedtls/pk.h" +#include "mbedtls/asn1.h" +#include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif +#if defined(MBEDTLS_PKCS5_C) +#include "mbedtls/pkcs5.h" +#endif +#if defined(MBEDTLS_PKCS12_C) +#include "mbedtls/pkcs12.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/* Parameter validation macros based on platform_util.h */ +#define PK_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_PK_BAD_INPUT_DATA ) +#define PK_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if defined(MBEDTLS_FS_IO) +/* + * Load all data from a file into a given buffer. + * + * The file is expected to contain either PEM or DER encoded data. + * A terminating null byte is always appended. It is included in the announced + * length only if the data looks like it is PEM encoded. + */ +int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ) +{ + FILE *f; + long size; + + PK_VALIDATE_RET( path != NULL ); + PK_VALIDATE_RET( buf != NULL ); + PK_VALIDATE_RET( n != NULL ); + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + if( ( size = ftell( f ) ) == -1 ) + { + fclose( f ); + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + } + fseek( f, 0, SEEK_SET ); + + *n = (size_t) size; + + if( *n + 1 == 0 || + ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL ) + { + fclose( f ); + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + } + + if( fread( *buf, 1, *n, f ) != *n ) + { + fclose( f ); + + mbedtls_platform_zeroize( *buf, *n ); + mbedtls_free( *buf ); + + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + } + + fclose( f ); + + (*buf)[*n] = '\0'; + + if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL ) + ++*n; + + return( 0 ); +} + +/* + * Load and parse a private key + */ +int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, + const char *path, const char *pwd ) +{ + int ret; + size_t n; + unsigned char *buf; + + PK_VALIDATE_RET( ctx != NULL ); + PK_VALIDATE_RET( path != NULL ); + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + if( pwd == NULL ) + ret = mbedtls_pk_parse_key( ctx, buf, n, NULL, 0 ); + else + ret = mbedtls_pk_parse_key( ctx, buf, n, + (const unsigned char *) pwd, strlen( pwd ) ); + + mbedtls_platform_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} + +/* + * Load and parse a public key + */ +int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + PK_VALIDATE_RET( ctx != NULL ); + PK_VALIDATE_RET( path != NULL ); + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_pk_parse_public_key( ctx, buf, n ); + + mbedtls_platform_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_ECP_C) +/* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf + * + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } + * -- implicitCurve NULL + * } + */ +static int pk_get_ecparams( unsigned char **p, const unsigned char *end, + mbedtls_asn1_buf *params ) +{ + int ret; + + if ( end - *p < 1 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + /* Tag may be either OID or SEQUENCE */ + params->tag = **p; + if( params->tag != MBEDTLS_ASN1_OID +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) + && params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) +#endif + ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + } + + if( ( ret = mbedtls_asn1_get_tag( p, end, ¶ms->len, params->tag ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + params->p = *p; + *p += params->len; + + if( *p != end ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) +/* + * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it. + * WARNING: the resulting group should only be used with + * pk_group_id_from_specified(), since its base point may not be set correctly + * if it was encoded compressed. + * + * SpecifiedECDomain ::= SEQUENCE { + * version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...), + * fieldID FieldID {{FieldTypes}}, + * curve Curve, + * base ECPoint, + * order INTEGER, + * cofactor INTEGER OPTIONAL, + * hash HashAlgorithm OPTIONAL, + * ... + * } + * + * We only support prime-field as field type, and ignore hash and cofactor. + */ +static int pk_group_from_specified( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) +{ + int ret; + unsigned char *p = params->p; + const unsigned char * const end = params->p + params->len; + const unsigned char *end_field, *end_curve; + size_t len; + int ver; + + /* SpecifiedECDomainVersion ::= INTEGER { 1, 2, 3 } */ + if( ( ret = mbedtls_asn1_get_int( &p, end, &ver ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ver < 1 || ver > 3 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + + /* + * FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field + * fieldType FIELD-ID.&id({IOSet}), + * parameters FIELD-ID.&Type({IOSet}{@fieldType}) + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + end_field = p + len; + + /* + * FIELD-ID ::= TYPE-IDENTIFIER + * FieldTypes FIELD-ID ::= { + * { Prime-p IDENTIFIED BY prime-field } | + * { Characteristic-two IDENTIFIED BY characteristic-two-field } + * } + * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end_field, &len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( ret ); + + if( len != MBEDTLS_OID_SIZE( MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD ) || + memcmp( p, MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD, len ) != 0 ) + { + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + } + + p += len; + + /* Prime-p ::= INTEGER -- Field of size p. */ + if( ( ret = mbedtls_asn1_get_mpi( &p, end_field, &grp->P ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + + if( p != end_field ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * Curve ::= SEQUENCE { + * a FieldElement, + * b FieldElement, + * seed BIT STRING OPTIONAL + * -- Shall be present if used in SpecifiedECDomain + * -- with version equal to ecdpVer2 or ecdpVer3 + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + end_curve = p + len; + + /* + * FieldElement ::= OCTET STRING + * containing an integer in the case of a prime field + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || + ( ret = mbedtls_mpi_read_binary( &grp->A, p, len ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + p += len; + + if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || + ( ret = mbedtls_mpi_read_binary( &grp->B, p, len ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + p += len; + + /* Ignore seed BIT STRING OPTIONAL */ + if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_BIT_STRING ) ) == 0 ) + p += len; + + if( p != end_curve ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * ECPoint ::= OCTET STRING + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_ecp_point_read_binary( grp, &grp->G, + ( const unsigned char *) p, len ) ) != 0 ) + { + /* + * If we can't read the point because it's compressed, cheat by + * reading only the X coordinate and the parity bit of Y. + */ + if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE || + ( p[0] != 0x02 && p[0] != 0x03 ) || + len != mbedtls_mpi_size( &grp->P ) + 1 || + mbedtls_mpi_read_binary( &grp->G.X, p + 1, len - 1 ) != 0 || + mbedtls_mpi_lset( &grp->G.Y, p[0] - 2 ) != 0 || + mbedtls_mpi_lset( &grp->G.Z, 1 ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + } + } + + p += len; + + /* + * order INTEGER + */ + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &grp->N ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + grp->nbits = mbedtls_mpi_bitlen( &grp->N ); + + /* + * Allow optional elements by purposefully not enforcing p == end here. + */ + + return( 0 ); +} + +/* + * Find the group id associated with an (almost filled) group as generated by + * pk_group_from_specified(), or return an error if unknown. + */ +static int pk_group_id_from_group( const mbedtls_ecp_group *grp, mbedtls_ecp_group_id *grp_id ) +{ + int ret = 0; + mbedtls_ecp_group ref; + const mbedtls_ecp_group_id *id; + + mbedtls_ecp_group_init( &ref ); + + for( id = mbedtls_ecp_grp_id_list(); *id != MBEDTLS_ECP_DP_NONE; id++ ) + { + /* Load the group associated to that id */ + mbedtls_ecp_group_free( &ref ); + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ref, *id ) ); + + /* Compare to the group we were given, starting with easy tests */ + if( grp->pbits == ref.pbits && grp->nbits == ref.nbits && + mbedtls_mpi_cmp_mpi( &grp->P, &ref.P ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->A, &ref.A ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->B, &ref.B ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->N, &ref.N ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->G.X, &ref.G.X ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->G.Z, &ref.G.Z ) == 0 && + /* For Y we may only know the parity bit, so compare only that */ + mbedtls_mpi_get_bit( &grp->G.Y, 0 ) == mbedtls_mpi_get_bit( &ref.G.Y, 0 ) ) + { + break; + } + + } + +cleanup: + mbedtls_ecp_group_free( &ref ); + + *grp_id = *id; + + if( ret == 0 && *id == MBEDTLS_ECP_DP_NONE ) + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + + return( ret ); +} + +/* + * Parse a SpecifiedECDomain (SEC 1 C.2) and find the associated group ID + */ +static int pk_group_id_from_specified( const mbedtls_asn1_buf *params, + mbedtls_ecp_group_id *grp_id ) +{ + int ret; + mbedtls_ecp_group grp; + + mbedtls_ecp_group_init( &grp ); + + if( ( ret = pk_group_from_specified( params, &grp ) ) != 0 ) + goto cleanup; + + ret = pk_group_id_from_group( &grp, grp_id ); + +cleanup: + mbedtls_ecp_group_free( &grp ); + + return( ret ); +} +#endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */ + +/* + * Use EC parameters to initialise an EC group + * + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } + * -- implicitCurve NULL + */ +static int pk_use_ecparams( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) +{ + int ret; + mbedtls_ecp_group_id grp_id; + + if( params->tag == MBEDTLS_ASN1_OID ) + { + if( mbedtls_oid_get_ec_grp( params, &grp_id ) != 0 ) + return( MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE ); + } + else + { +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) + if( ( ret = pk_group_id_from_specified( params, &grp_id ) ) != 0 ) + return( ret ); +#else + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); +#endif + } + + /* + * grp may already be initilialized; if so, make sure IDs match + */ + if( grp->id != MBEDTLS_ECP_DP_NONE && grp->id != grp_id ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + + if( ( ret = mbedtls_ecp_group_load( grp, grp_id ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * EC public key is an EC point + * + * The caller is responsible for clearing the structure upon failure if + * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE + * return code of mbedtls_ecp_point_read_binary() and leave p in a usable state. + */ +static int pk_get_ecpubkey( unsigned char **p, const unsigned char *end, + mbedtls_ecp_keypair *key ) +{ + int ret; + + if( ( ret = mbedtls_ecp_point_read_binary( &key->grp, &key->Q, + (const unsigned char *) *p, end - *p ) ) == 0 ) + { + ret = mbedtls_ecp_check_pubkey( &key->grp, &key->Q ); + } + + /* + * We know mbedtls_ecp_point_read_binary consumed all bytes or failed + */ + *p = (unsigned char *) end; + + return( ret ); +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_RSA_C) +/* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ +static int pk_get_rsapubkey( unsigned char **p, + const unsigned char *end, + mbedtls_rsa_context *rsa ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* Import N */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( ( ret = mbedtls_rsa_import_raw( rsa, *p, len, NULL, 0, NULL, 0, + NULL, 0, NULL, 0 ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); + + *p += len; + + /* Import E */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0, + NULL, 0, *p, len ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); + + *p += len; + + if( mbedtls_rsa_complete( rsa ) != 0 || + mbedtls_rsa_check_pubkey( rsa ) != 0 ) + { + return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); + } + + if( *p != end ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} +#endif /* MBEDTLS_RSA_C */ + +/* Get a PK algorithm identifier + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + */ +static int pk_get_pk_alg( unsigned char **p, + const unsigned char *end, + mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params ) +{ + int ret; + mbedtls_asn1_buf alg_oid; + + memset( params, 0, sizeof(mbedtls_asn1_buf) ); + + if( ( ret = mbedtls_asn1_get_alg( p, end, &alg_oid, params ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_ALG + ret ); + + if( mbedtls_oid_get_pk_alg( &alg_oid, pk_alg ) != 0 ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + /* + * No parameters with RSA (only for EC) + */ + if( *pk_alg == MBEDTLS_PK_RSA && + ( ( params->tag != MBEDTLS_ASN1_NULL && params->tag != 0 ) || + params->len != 0 ) ) + { + return( MBEDTLS_ERR_PK_INVALID_ALG ); + } + + return( 0 ); +} + +/* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + */ +int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end, + mbedtls_pk_context *pk ) +{ + int ret; + size_t len; + mbedtls_asn1_buf alg_params; + mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; + const mbedtls_pk_info_t *pk_info; + + PK_VALIDATE_RET( p != NULL ); + PK_VALIDATE_RET( *p != NULL ); + PK_VALIDATE_RET( end != NULL ); + PK_VALIDATE_RET( pk != NULL ); + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = *p + len; + + if( ( ret = pk_get_pk_alg( p, end, &pk_alg, &alg_params ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_RSA_C) + if( pk_alg == MBEDTLS_PK_RSA ) + { + ret = pk_get_rsapubkey( p, end, mbedtls_pk_rsa( *pk ) ); + } else +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECP_C) + if( pk_alg == MBEDTLS_PK_ECKEY_DH || pk_alg == MBEDTLS_PK_ECKEY ) + { + ret = pk_use_ecparams( &alg_params, &mbedtls_pk_ec( *pk )->grp ); + if( ret == 0 ) + ret = pk_get_ecpubkey( p, end, mbedtls_pk_ec( *pk ) ); + } else +#endif /* MBEDTLS_ECP_C */ + ret = MBEDTLS_ERR_PK_UNKNOWN_PK_ALG; + + if( ret == 0 && *p != end ) + ret = MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + + if( ret != 0 ) + mbedtls_pk_free( pk ); + + return( ret ); +} + +#if defined(MBEDTLS_RSA_C) +/* + * Parse a PKCS#1 encoded private RSA key + */ +static int pk_parse_key_pkcs1_der( mbedtls_rsa_context *rsa, + const unsigned char *key, + size_t keylen ) +{ + int ret, version; + size_t len; + unsigned char *p, *end; + + mbedtls_mpi T; + mbedtls_mpi_init( &T ); + + p = (unsigned char *) key; + end = p + keylen; + + /* + * This function parses the RSAPrivateKey (PKCS#1) + * + * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER, -- (inverse of q) mod p + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + if( version != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); + } + + /* Import N */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_INTEGER ) ) != 0 || + ( ret = mbedtls_rsa_import_raw( rsa, p, len, NULL, 0, NULL, 0, + NULL, 0, NULL, 0 ) ) != 0 ) + goto cleanup; + p += len; + + /* Import E */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_INTEGER ) ) != 0 || + ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0, + NULL, 0, p, len ) ) != 0 ) + goto cleanup; + p += len; + + /* Import D */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_INTEGER ) ) != 0 || + ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0, + p, len, NULL, 0 ) ) != 0 ) + goto cleanup; + p += len; + + /* Import P */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_INTEGER ) ) != 0 || + ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, p, len, NULL, 0, + NULL, 0, NULL, 0 ) ) != 0 ) + goto cleanup; + p += len; + + /* Import Q */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_INTEGER ) ) != 0 || + ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, p, len, + NULL, 0, NULL, 0 ) ) != 0 ) + goto cleanup; + p += len; + + /* Complete the RSA private key */ + if( ( ret = mbedtls_rsa_complete( rsa ) ) != 0 ) + goto cleanup; + + /* Check optional parameters */ + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &T ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &T ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &T ) ) != 0 ) + goto cleanup; + + if( p != end ) + { + ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ; + } + +cleanup: + + mbedtls_mpi_free( &T ); + + if( ret != 0 ) + { + /* Wrap error code if it's coming from a lower level */ + if( ( ret & 0xff80 ) == 0 ) + ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret; + else + ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; + + mbedtls_rsa_free( rsa ); + } + + return( ret ); +} +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * Parse a SEC1 encoded private EC key + */ +static int pk_parse_key_sec1_der( mbedtls_ecp_keypair *eck, + const unsigned char *key, + size_t keylen ) +{ + int ret; + int version, pubkey_done; + size_t len; + mbedtls_asn1_buf params; + unsigned char *p = (unsigned char *) key; + unsigned char *end = p + keylen; + unsigned char *end2; + + /* + * RFC 5915, or SEC1 Appendix C.4 + * + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( version != 1 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_mpi_read_binary( &eck->d, p, len ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + p += len; + + pubkey_done = 0; + if( p != end ) + { + /* + * Is 'parameters' present? + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 ) + { + if( ( ret = pk_get_ecparams( &p, p + len, ¶ms) ) != 0 || + ( ret = pk_use_ecparams( ¶ms, &eck->grp ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( ret ); + } + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + } + + if( p != end ) + { + /* + * Is 'publickey' present? If not, or if we can't read it (eg because it + * is compressed), create it from the private key. + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 ) + { + end2 = p + len; + + if( ( ret = mbedtls_asn1_get_bitstring_null( &p, end2, &len ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( p + len != end2 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( ret = pk_get_ecpubkey( &p, end2, eck ) ) == 0 ) + pubkey_done = 1; + else + { + /* + * The only acceptable failure mode of pk_get_ecpubkey() above + * is if the point format is not recognized. + */ + if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + } + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + } + + if( ! pubkey_done && + ( ret = mbedtls_ecp_mul( &eck->grp, &eck->Q, &eck->d, &eck->grp.G, + NULL, NULL ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_ecp_check_privkey( &eck->grp, &eck->d ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_ECP_C */ + +/* + * Parse an unencrypted PKCS#8 encoded private key + * + * Notes: + * + * - This function does not own the key buffer. It is the + * responsibility of the caller to take care of zeroizing + * and freeing it after use. + * + * - The function is responsible for freeing the provided + * PK context on failure. + * + */ +static int pk_parse_key_pkcs8_unencrypted_der( + mbedtls_pk_context *pk, + const unsigned char* key, + size_t keylen ) +{ + int ret, version; + size_t len; + mbedtls_asn1_buf params; + unsigned char *p = (unsigned char *) key; + unsigned char *end = p + keylen; + mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; + const mbedtls_pk_info_t *pk_info; + + /* + * This function parses the PrivateKeyInfo object (PKCS#8 v1.2 = RFC 5208) + * + * PrivateKeyInfo ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes [0] IMPLICIT Attributes OPTIONAL } + * + * Version ::= INTEGER + * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier + * PrivateKey ::= OCTET STRING + * + * The PrivateKey OCTET STRING is a SEC1 ECPrivateKey + */ + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( version != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION + ret ); + + if( ( ret = pk_get_pk_alg( &p, end, &pk_alg, ¶ms ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( len < 1 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_RSA_C) + if( pk_alg == MBEDTLS_PK_RSA ) + { + if( ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), p, len ) ) != 0 ) + { + mbedtls_pk_free( pk ); + return( ret ); + } + } else +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECP_C) + if( pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH ) + { + if( ( ret = pk_use_ecparams( ¶ms, &mbedtls_pk_ec( *pk )->grp ) ) != 0 || + ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), p, len ) ) != 0 ) + { + mbedtls_pk_free( pk ); + return( ret ); + } + } else +#endif /* MBEDTLS_ECP_C */ + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + return( 0 ); +} + +/* + * Parse an encrypted PKCS#8 encoded private key + * + * To save space, the decryption happens in-place on the given key buffer. + * Also, while this function may modify the keybuffer, it doesn't own it, + * and instead it is the responsibility of the caller to zeroize and properly + * free it after use. + * + */ +#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) +static int pk_parse_key_pkcs8_encrypted_der( + mbedtls_pk_context *pk, + unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ) +{ + int ret, decrypted = 0; + size_t len; + unsigned char *buf; + unsigned char *p, *end; + mbedtls_asn1_buf pbe_alg_oid, pbe_params; +#if defined(MBEDTLS_PKCS12_C) + mbedtls_cipher_type_t cipher_alg; + mbedtls_md_type_t md_alg; +#endif + + p = key; + end = p + keylen; + + if( pwdlen == 0 ) + return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); + + /* + * This function parses the EncryptedPrivateKeyInfo object (PKCS#8) + * + * EncryptedPrivateKeyInfo ::= SEQUENCE { + * encryptionAlgorithm EncryptionAlgorithmIdentifier, + * encryptedData EncryptedData + * } + * + * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * + * EncryptedData ::= OCTET STRING + * + * The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo + * + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_alg( &p, end, &pbe_alg_oid, &pbe_params ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + buf = p; + + /* + * Decrypt EncryptedData with appropriate PBE + */ +#if defined(MBEDTLS_PKCS12_C) + if( mbedtls_oid_get_pkcs12_pbe_alg( &pbe_alg_oid, &md_alg, &cipher_alg ) == 0 ) + { + if( ( ret = mbedtls_pkcs12_pbe( &pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT, + cipher_alg, md_alg, + pwd, pwdlen, p, len, buf ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + + return( ret ); + } + + decrypted = 1; + } + else if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128, &pbe_alg_oid ) == 0 ) + { + if( ( ret = mbedtls_pkcs12_pbe_sha1_rc4_128( &pbe_params, + MBEDTLS_PKCS12_PBE_DECRYPT, + pwd, pwdlen, + p, len, buf ) ) != 0 ) + { + return( ret ); + } + + // Best guess for password mismatch when using RC4. If first tag is + // not MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE + // + if( *buf != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + + decrypted = 1; + } + else +#endif /* MBEDTLS_PKCS12_C */ +#if defined(MBEDTLS_PKCS5_C) + if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid ) == 0 ) + { + if( ( ret = mbedtls_pkcs5_pbes2( &pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen, + p, len, buf ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + + return( ret ); + } + + decrypted = 1; + } + else +#endif /* MBEDTLS_PKCS5_C */ + { + ((void) pwd); + } + + if( decrypted == 0 ) + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + return( pk_parse_key_pkcs8_unencrypted_der( pk, buf, len ) ); +} +#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ + +/* + * Parse a private key + */ +int mbedtls_pk_parse_key( mbedtls_pk_context *pk, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ) +{ + int ret; + const mbedtls_pk_info_t *pk_info; +#if defined(MBEDTLS_PEM_PARSE_C) + size_t len; + mbedtls_pem_context pem; +#endif + + PK_VALIDATE_RET( pk != NULL ); + if( keylen == 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + PK_VALIDATE_RET( key != NULL ); + +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_init( &pem ); + +#if defined(MBEDTLS_RSA_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN RSA PRIVATE KEY-----", + "-----END RSA PRIVATE KEY-----", + key, pwd, pwdlen, &len ); + + if( ret == 0 ) + { + pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ); + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) + return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN EC PRIVATE KEY-----", + "-----END EC PRIVATE KEY-----", + key, pwd, pwdlen, &len ); + if( ret == 0 ) + { + pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) + return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); +#endif /* MBEDTLS_ECP_C */ + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN PRIVATE KEY-----", + "-----END PRIVATE KEY-----", + key, NULL, 0, &len ); + if( ret == 0 ) + { + if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); + +#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN ENCRYPTED PRIVATE KEY-----", + "-----END ENCRYPTED PRIVATE KEY-----", + key, NULL, 0, &len ); + if( ret == 0 ) + { + if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, + pem.buf, pem.buflen, + pwd, pwdlen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); +#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ +#else + ((void) pwd); + ((void) pwdlen); +#endif /* MBEDTLS_PEM_PARSE_C */ + + /* + * At this point we only know it's not a PEM formatted key. Could be any + * of the known DER encoded private key formats + * + * We try the different DER format parsers to see if one passes without + * error + */ +#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) + { + unsigned char *key_copy; + + if( ( key_copy = mbedtls_calloc( 1, keylen ) ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + + memcpy( key_copy, key, keylen ); + + ret = pk_parse_key_pkcs8_encrypted_der( pk, key_copy, keylen, + pwd, pwdlen ); + + mbedtls_platform_zeroize( key_copy, keylen ); + mbedtls_free( key_copy ); + } + + if( ret == 0 ) + return( 0 ); + + mbedtls_pk_free( pk ); + mbedtls_pk_init( pk ); + + if( ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH ) + { + return( ret ); + } +#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ + + if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen ) ) == 0 ) + return( 0 ); + + mbedtls_pk_free( pk ); + mbedtls_pk_init( pk ); + +#if defined(MBEDTLS_RSA_C) + + pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ); + if( mbedtls_pk_setup( pk, pk_info ) == 0 && + pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), key, keylen ) == 0 ) + { + return( 0 ); + } + + mbedtls_pk_free( pk ); + mbedtls_pk_init( pk ); +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) + pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ); + if( mbedtls_pk_setup( pk, pk_info ) == 0 && + pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), + key, keylen ) == 0 ) + { + return( 0 ); + } + mbedtls_pk_free( pk ); +#endif /* MBEDTLS_ECP_C */ + + /* If MBEDTLS_RSA_C is defined but MBEDTLS_ECP_C isn't, + * it is ok to leave the PK context initialized but not + * freed: It is the caller's responsibility to call pk_init() + * before calling this function, and to call pk_free() + * when it fails. If MBEDTLS_ECP_C is defined but MBEDTLS_RSA_C + * isn't, this leads to mbedtls_pk_free() being called + * twice, once here and once by the caller, but this is + * also ok and in line with the mbedtls_pk_free() calls + * on failed PEM parsing attempts. */ + + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); +} + +/* + * Parse a public key + */ +int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, + const unsigned char *key, size_t keylen ) +{ + int ret; + unsigned char *p; +#if defined(MBEDTLS_RSA_C) + const mbedtls_pk_info_t *pk_info; +#endif +#if defined(MBEDTLS_PEM_PARSE_C) + size_t len; + mbedtls_pem_context pem; +#endif + + PK_VALIDATE_RET( ctx != NULL ); + if( keylen == 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + PK_VALIDATE_RET( key != NULL || keylen == 0 ); + +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_init( &pem ); +#if defined(MBEDTLS_RSA_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN RSA PUBLIC KEY-----", + "-----END RSA PUBLIC KEY-----", + key, NULL, 0, &len ); + + if( ret == 0 ) + { + p = pem.buf; + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 ) + return( ret ); + + if ( ( ret = pk_get_rsapubkey( &p, p + pem.buflen, mbedtls_pk_rsa( *ctx ) ) ) != 0 ) + mbedtls_pk_free( ctx ); + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } +#endif /* MBEDTLS_RSA_C */ + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN PUBLIC KEY-----", + "-----END PUBLIC KEY-----", + key, NULL, 0, &len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + p = pem.buf; + + ret = mbedtls_pk_parse_subpubkey( &p, p + pem.buflen, ctx ); + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } + mbedtls_pem_free( &pem ); +#endif /* MBEDTLS_PEM_PARSE_C */ + +#if defined(MBEDTLS_RSA_C) + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 ) + return( ret ); + + p = (unsigned char *)key; + ret = pk_get_rsapubkey( &p, p + keylen, mbedtls_pk_rsa( *ctx ) ); + if( ret == 0 ) + { + return( ret ); + } + mbedtls_pk_free( ctx ); + if( ret != ( MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) + { + return( ret ); + } +#endif /* MBEDTLS_RSA_C */ + p = (unsigned char *) key; + + ret = mbedtls_pk_parse_subpubkey( &p, p + keylen, ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_PK_PARSE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/pkwrite.c b/FreeRTOS-Labs/Source/mbedtls/library/pkwrite.c new file mode 100644 index 000000000..9ab3c7bde --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/pkwrite.c @@ -0,0 +1,606 @@ +/* + * Public Key layer for writing key files and structures + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_WRITE_C) + +#include "mbedtls/pk.h" +#include "mbedtls/asn1write.h" +#include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif +#if defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "psa/crypto.h" +#include "mbedtls/psa_util.h" +#endif +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/* Parameter validation macros based on platform_util.h */ +#define PK_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_PK_BAD_INPUT_DATA ) +#define PK_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if defined(MBEDTLS_RSA_C) +/* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ +static int pk_write_rsa_pubkey( unsigned char **p, unsigned char *start, + mbedtls_rsa_context *rsa ) +{ + int ret; + size_t len = 0; + mbedtls_mpi T; + + mbedtls_mpi_init( &T ); + + /* Export E */ + if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL, NULL, NULL, &T ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( p, start, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export N */ + if ( ( ret = mbedtls_rsa_export( rsa, &T, NULL, NULL, NULL, NULL ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( p, start, &T ) ) < 0 ) + goto end_of_export; + len += ret; + +end_of_export: + + mbedtls_mpi_free( &T ); + if( ret < 0 ) + return( ret ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * EC public key is an EC point + */ +static int pk_write_ec_pubkey( unsigned char **p, unsigned char *start, + mbedtls_ecp_keypair *ec ) +{ + int ret; + size_t len = 0; + unsigned char buf[MBEDTLS_ECP_MAX_PT_LEN]; + + if( ( ret = mbedtls_ecp_point_write_binary( &ec->grp, &ec->Q, + MBEDTLS_ECP_PF_UNCOMPRESSED, + &len, buf, sizeof( buf ) ) ) != 0 ) + { + return( ret ); + } + + if( *p < start || (size_t)( *p - start ) < len ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *p -= len; + memcpy( *p, buf, len ); + + return( (int) len ); +} + +/* + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * } + */ +static int pk_write_ec_param( unsigned char **p, unsigned char *start, + mbedtls_ecp_keypair *ec ) +{ + int ret; + size_t len = 0; + const char *oid; + size_t oid_len; + + if( ( ret = mbedtls_oid_get_oid_by_ec_grp( ec->grp.id, &oid, &oid_len ) ) != 0 ) + return( ret ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) ); + + return( (int) len ); +} +#endif /* MBEDTLS_ECP_C */ + +int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start, + const mbedtls_pk_context *key ) +{ + int ret; + size_t len = 0; + + PK_VALIDATE_RET( p != NULL ); + PK_VALIDATE_RET( *p != NULL ); + PK_VALIDATE_RET( start != NULL ); + PK_VALIDATE_RET( key != NULL ); + +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) + MBEDTLS_ASN1_CHK_ADD( len, pk_write_rsa_pubkey( p, start, mbedtls_pk_rsa( *key ) ) ); + else +#endif +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + MBEDTLS_ASN1_CHK_ADD( len, pk_write_ec_pubkey( p, start, mbedtls_pk_ec( *key ) ) ); + else +#endif +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_OPAQUE ) + { + size_t buffer_size; + psa_key_handle_t* key_slot = (psa_key_handle_t*) key->pk_ctx; + + if ( *p < start ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + buffer_size = (size_t)( *p - start ); + if ( psa_export_public_key( *key_slot, start, buffer_size, &len ) + != PSA_SUCCESS ) + { + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + } + else + { + *p -= len; + memmove( *p, start, len ); + } + } + else +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + return( (int) len ); +} + +int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char *c; + size_t len = 0, par_len = 0, oid_len; + mbedtls_pk_type_t pk_type; + const char *oid; + + PK_VALIDATE_RET( key != NULL ); + if( size == 0 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + PK_VALIDATE_RET( buf != NULL ); + + c = buf + size; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, key ) ); + + if( c - buf < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + /* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + */ + *--c = 0; + len += 1; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_BIT_STRING ) ); + + pk_type = mbedtls_pk_get_type( key ); +#if defined(MBEDTLS_ECP_C) + if( pk_type == MBEDTLS_PK_ECKEY ) + { + MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, mbedtls_pk_ec( *key ) ) ); + } +#endif +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( pk_type == MBEDTLS_PK_OPAQUE ) + { + psa_status_t status; + psa_key_type_t key_type; + psa_key_handle_t handle; + psa_ecc_curve_t curve; + + handle = *((psa_key_handle_t*) key->pk_ctx ); + + status = psa_get_key_information( handle, &key_type, + NULL /* bitsize not needed */ ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED ); + + curve = PSA_KEY_TYPE_GET_CURVE( key_type ); + if( curve == 0 ) + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + ret = mbedtls_psa_get_ecc_oid_from_id( curve, &oid, &oid_len ); + if( ret != 0 ) + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + /* Write EC algorithm parameters; that's akin + * to pk_write_ec_param() above. */ + MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_oid( &c, buf, + oid, oid_len ) ); + + /* The rest of the function works as for legacy EC contexts. */ + pk_type = MBEDTLS_PK_ECKEY; + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + if( ( ret = mbedtls_oid_get_oid_by_pk_alg( pk_type, &oid, + &oid_len ) ) != 0 ) + { + return( ret ); + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, buf, oid, oid_len, + par_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char *c; + size_t len = 0; + + PK_VALIDATE_RET( key != NULL ); + if( size == 0 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + PK_VALIDATE_RET( buf != NULL ); + + c = buf + size; + +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) + { + mbedtls_mpi T; /* Temporary holding the exported parameters */ + mbedtls_rsa_context *rsa = mbedtls_pk_rsa( *key ); + + /* + * Export the parameters one after another to avoid simultaneous copies. + */ + + mbedtls_mpi_init( &T ); + + /* Export QP */ + if( ( ret = mbedtls_rsa_export_crt( rsa, NULL, NULL, &T ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export DQ */ + if( ( ret = mbedtls_rsa_export_crt( rsa, NULL, &T, NULL ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export DP */ + if( ( ret = mbedtls_rsa_export_crt( rsa, &T, NULL, NULL ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export Q */ + if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL, + &T, NULL, NULL ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export P */ + if ( ( ret = mbedtls_rsa_export( rsa, NULL, &T, + NULL, NULL, NULL ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export D */ + if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL, + NULL, &T, NULL ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export E */ + if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL, + NULL, NULL, &T ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export N */ + if ( ( ret = mbedtls_rsa_export( rsa, &T, NULL, + NULL, NULL, NULL ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + end_of_export: + + mbedtls_mpi_free( &T ); + if( ret < 0 ) + return( ret ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 0 ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, + buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + } + else +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + { + mbedtls_ecp_keypair *ec = mbedtls_pk_ec( *key ); + size_t pub_len = 0, par_len = 0; + + /* + * RFC 5915, or SEC1 Appendix C.4 + * + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL + * } + */ + + /* publicKey */ + MBEDTLS_ASN1_CHK_ADD( pub_len, pk_write_ec_pubkey( &c, buf, ec ) ); + + if( c - buf < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + *--c = 0; + pub_len += 1; + + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_len( &c, buf, pub_len ) ); + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_BIT_STRING ) ); + + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_len( &c, buf, pub_len ) ); + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_tag( &c, buf, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ); + len += pub_len; + + /* parameters */ + MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, ec ) ); + + MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_len( &c, buf, par_len ) ); + MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_tag( &c, buf, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ); + len += par_len; + + /* privateKey: write as MPI then fix tag */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &ec->d ) ); + *c = MBEDTLS_ASN1_OCTET_STRING; + + /* version */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 1 ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + } + else +#endif /* MBEDTLS_ECP_C */ + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + return( (int) len ); +} + +#if defined(MBEDTLS_PEM_WRITE_C) + +#define PEM_BEGIN_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\n" +#define PEM_END_PUBLIC_KEY "-----END PUBLIC KEY-----\n" + +#define PEM_BEGIN_PRIVATE_KEY_RSA "-----BEGIN RSA PRIVATE KEY-----\n" +#define PEM_END_PRIVATE_KEY_RSA "-----END RSA PRIVATE KEY-----\n" +#define PEM_BEGIN_PRIVATE_KEY_EC "-----BEGIN EC PRIVATE KEY-----\n" +#define PEM_END_PRIVATE_KEY_EC "-----END EC PRIVATE KEY-----\n" + +/* + * Max sizes of key per types. Shown as tag + len (+ content). + */ + +#if defined(MBEDTLS_RSA_C) +/* + * RSA public keys: + * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 3 + * algorithm AlgorithmIdentifier, 1 + 1 (sequence) + * + 1 + 1 + 9 (rsa oid) + * + 1 + 1 (params null) + * subjectPublicKey BIT STRING } 1 + 3 + (1 + below) + * RSAPublicKey ::= SEQUENCE { 1 + 3 + * modulus INTEGER, -- n 1 + 3 + MPI_MAX + 1 + * publicExponent INTEGER -- e 1 + 3 + MPI_MAX + 1 + * } + */ +#define RSA_PUB_DER_MAX_BYTES 38 + 2 * MBEDTLS_MPI_MAX_SIZE + +/* + * RSA private keys: + * RSAPrivateKey ::= SEQUENCE { 1 + 3 + * version Version, 1 + 1 + 1 + * modulus INTEGER, 1 + 3 + MPI_MAX + 1 + * publicExponent INTEGER, 1 + 3 + MPI_MAX + 1 + * privateExponent INTEGER, 1 + 3 + MPI_MAX + 1 + * prime1 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * prime2 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * exponent1 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * exponent2 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * coefficient INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * otherPrimeInfos OtherPrimeInfos OPTIONAL 0 (not supported) + * } + */ +#define MPI_MAX_SIZE_2 MBEDTLS_MPI_MAX_SIZE / 2 + \ + MBEDTLS_MPI_MAX_SIZE % 2 +#define RSA_PRV_DER_MAX_BYTES 47 + 3 * MBEDTLS_MPI_MAX_SIZE \ + + 5 * MPI_MAX_SIZE_2 + +#else /* MBEDTLS_RSA_C */ + +#define RSA_PUB_DER_MAX_BYTES 0 +#define RSA_PRV_DER_MAX_BYTES 0 + +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * EC public keys: + * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 2 + * algorithm AlgorithmIdentifier, 1 + 1 (sequence) + * + 1 + 1 + 7 (ec oid) + * + 1 + 1 + 9 (namedCurve oid) + * subjectPublicKey BIT STRING 1 + 2 + 1 [1] + * + 1 (point format) [1] + * + 2 * ECP_MAX (coords) [1] + * } + */ +#define ECP_PUB_DER_MAX_BYTES 30 + 2 * MBEDTLS_ECP_MAX_BYTES + +/* + * EC private keys: + * ECPrivateKey ::= SEQUENCE { 1 + 2 + * version INTEGER , 1 + 1 + 1 + * privateKey OCTET STRING, 1 + 1 + ECP_MAX + * parameters [0] ECParameters OPTIONAL, 1 + 1 + (1 + 1 + 9) + * publicKey [1] BIT STRING OPTIONAL 1 + 2 + [1] above + * } + */ +#define ECP_PRV_DER_MAX_BYTES 29 + 3 * MBEDTLS_ECP_MAX_BYTES + +#else /* MBEDTLS_ECP_C */ + +#define ECP_PUB_DER_MAX_BYTES 0 +#define ECP_PRV_DER_MAX_BYTES 0 + +#endif /* MBEDTLS_ECP_C */ + +#define PUB_DER_MAX_BYTES RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ + RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES +#define PRV_DER_MAX_BYTES RSA_PRV_DER_MAX_BYTES > ECP_PRV_DER_MAX_BYTES ? \ + RSA_PRV_DER_MAX_BYTES : ECP_PRV_DER_MAX_BYTES + +int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char output_buf[PUB_DER_MAX_BYTES]; + size_t olen = 0; + + PK_VALIDATE_RET( key != NULL ); + PK_VALIDATE_RET( buf != NULL || size == 0 ); + + if( ( ret = mbedtls_pk_write_pubkey_der( key, output_buf, + sizeof(output_buf) ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +int mbedtls_pk_write_key_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char output_buf[PRV_DER_MAX_BYTES]; + const char *begin, *end; + size_t olen = 0; + + PK_VALIDATE_RET( key != NULL ); + PK_VALIDATE_RET( buf != NULL || size == 0 ); + + if( ( ret = mbedtls_pk_write_key_der( key, output_buf, sizeof(output_buf) ) ) < 0 ) + return( ret ); + +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) + { + begin = PEM_BEGIN_PRIVATE_KEY_RSA; + end = PEM_END_PRIVATE_KEY_RSA; + } + else +#endif +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + { + begin = PEM_BEGIN_PRIVATE_KEY_EC; + end = PEM_END_PRIVATE_KEY_EC; + } + else +#endif + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + if( ( ret = mbedtls_pem_write_buffer( begin, end, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_PEM_WRITE_C */ + +#endif /* MBEDTLS_PK_WRITE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/platform.c b/FreeRTOS-Labs/Source/mbedtls/library/platform.c new file mode 100644 index 000000000..fc10a4445 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/platform.c @@ -0,0 +1,391 @@ +/* + * Platform abstraction layer + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PLATFORM_C) + +#include "mbedtls/platform.h" +#include "mbedtls/platform_util.h" + +/* The compile time configuration of memory allocation via the macros + * MBEDTLS_PLATFORM_{FREE/CALLOC}_MACRO takes precedence over the runtime + * configuration via mbedtls_platform_set_calloc_free(). So, omit everything + * related to the latter if MBEDTLS_PLATFORM_{FREE/CALLOC}_MACRO are defined. */ +#if defined(MBEDTLS_PLATFORM_MEMORY) && \ + !( defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && \ + defined(MBEDTLS_PLATFORM_FREE_MACRO) ) + +#if !defined(MBEDTLS_PLATFORM_STD_CALLOC) +static void *platform_calloc_uninit( size_t n, size_t size ) +{ + ((void) n); + ((void) size); + return( NULL ); +} + +#define MBEDTLS_PLATFORM_STD_CALLOC platform_calloc_uninit +#endif /* !MBEDTLS_PLATFORM_STD_CALLOC */ + +#if !defined(MBEDTLS_PLATFORM_STD_FREE) +static void platform_free_uninit( void *ptr ) +{ + ((void) ptr); +} + +#define MBEDTLS_PLATFORM_STD_FREE platform_free_uninit +#endif /* !MBEDTLS_PLATFORM_STD_FREE */ + +static void * (*mbedtls_calloc_func)( size_t, size_t ) = MBEDTLS_PLATFORM_STD_CALLOC; +static void (*mbedtls_free_func)( void * ) = MBEDTLS_PLATFORM_STD_FREE; + +void * mbedtls_calloc( size_t nmemb, size_t size ) +{ + return (*mbedtls_calloc_func)( nmemb, size ); +} + +void mbedtls_free( void * ptr ) +{ + (*mbedtls_free_func)( ptr ); +} + +int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ), + void (*free_func)( void * ) ) +{ + mbedtls_calloc_func = calloc_func; + mbedtls_free_func = free_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_MEMORY && + !( defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && + defined(MBEDTLS_PLATFORM_FREE_MACRO) ) */ + +#if defined(MBEDTLS_PLATFORM_HAS_NON_CONFORMING_SNPRINTF) +#include +int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... ) +{ + int ret; + va_list argp; + + va_start( argp, fmt ); + ret = mbedtls_vsnprintf( s, n, fmt, argp ); + va_end( argp ); + + return( ret ); +} +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_snprintf_uninit( char * s, size_t n, + const char * format, ... ) +{ + ((void) s); + ((void) n); + ((void) format); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_SNPRINTF platform_snprintf_uninit +#endif /* !MBEDTLS_PLATFORM_STD_SNPRINTF */ + +int (*mbedtls_snprintf)( char * s, size_t n, + const char * format, + ... ) = MBEDTLS_PLATFORM_STD_SNPRINTF; + +int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n, + const char * format, + ... ) ) +{ + mbedtls_snprintf = snprintf_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ + +#if defined(MBEDTLS_PLATFORM_HAS_NON_CONFORMING_VSNPRINTF) +#include +int mbedtls_platform_win32_vsnprintf( char *s, size_t n, const char *fmt, va_list arg ) +{ + int ret; + + /* Avoid calling the invalid parameter handler by checking ourselves */ + if( s == NULL || n == 0 || fmt == NULL ) + return( -1 ); + +#if defined(_TRUNCATE) + ret = vsnprintf_s( s, n, _TRUNCATE, fmt, arg ); +#else + ret = vsnprintf( s, n, fmt, arg ); + if( ret < 0 || (size_t) ret == n ) + { + s[n-1] = '\0'; + ret = -1; + } +#endif + + return( ret ); +} +#endif + +#if defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_VSNPRINTF) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_vsnprintf_uninit( char * s, size_t n, + const char * format, va_list arg ) +{ + ((void) s); + ((void) n); + ((void) format); + ((void) arg); + return( -1 ); +} + +#define MBEDTLS_PLATFORM_STD_VSNPRINTF platform_vsnprintf_uninit +#endif /* !MBEDTLS_PLATFORM_STD_VSNPRINTF */ + +int (*mbedtls_vsnprintf)( char * s, size_t n, + const char * format, + va_list arg ) = MBEDTLS_PLATFORM_STD_VSNPRINTF; + +int mbedtls_platform_set_vsnprintf( int (*vsnprintf_func)( char * s, size_t n, + const char * format, + va_list arg ) ) +{ + mbedtls_vsnprintf = vsnprintf_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_VSNPRINTF_ALT */ + +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_PRINTF) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_printf_uninit( const char *format, ... ) +{ + ((void) format); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_PRINTF platform_printf_uninit +#endif /* !MBEDTLS_PLATFORM_STD_PRINTF */ + +int (*mbedtls_printf)( const char *, ... ) = MBEDTLS_PLATFORM_STD_PRINTF; + +int mbedtls_platform_set_printf( int (*printf_func)( const char *, ... ) ) +{ + mbedtls_printf = printf_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */ + +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_fprintf_uninit( FILE *stream, const char *format, ... ) +{ + ((void) stream); + ((void) format); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_FPRINTF platform_fprintf_uninit +#endif /* !MBEDTLS_PLATFORM_STD_FPRINTF */ + +int (*mbedtls_fprintf)( FILE *, const char *, ... ) = + MBEDTLS_PLATFORM_STD_FPRINTF; + +int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *, const char *, ... ) ) +{ + mbedtls_fprintf = fprintf_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */ + +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_EXIT) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static void platform_exit_uninit( int status ) +{ + ((void) status); +} + +#define MBEDTLS_PLATFORM_STD_EXIT platform_exit_uninit +#endif /* !MBEDTLS_PLATFORM_STD_EXIT */ + +void (*mbedtls_exit)( int status ) = MBEDTLS_PLATFORM_STD_EXIT; + +int mbedtls_platform_set_exit( void (*exit_func)( int status ) ) +{ + mbedtls_exit = exit_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_EXIT_ALT */ + +#if defined(MBEDTLS_HAVE_TIME) + +#if defined(MBEDTLS_PLATFORM_TIME_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_TIME) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static mbedtls_time_t platform_time_uninit( mbedtls_time_t* timer ) +{ + ((void) timer); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_TIME platform_time_uninit +#endif /* !MBEDTLS_PLATFORM_STD_TIME */ + +mbedtls_time_t (*mbedtls_time)( mbedtls_time_t* timer ) = MBEDTLS_PLATFORM_STD_TIME; + +int mbedtls_platform_set_time( mbedtls_time_t (*time_func)( mbedtls_time_t* timer ) ) +{ + mbedtls_time = time_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_TIME_ALT */ + +#endif /* MBEDTLS_HAVE_TIME */ + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDTLS_FS_IO) +/* Default implementations for the platform independent seed functions use + * standard libc file functions to read from and write to a pre-defined filename + */ +int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len ) +{ + FILE *file; + size_t n; + + if( ( file = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "rb" ) ) == NULL ) + return( -1 ); + + if( ( n = fread( buf, 1, buf_len, file ) ) != buf_len ) + { + fclose( file ); + mbedtls_platform_zeroize( buf, buf_len ); + return( -1 ); + } + + fclose( file ); + return( (int)n ); +} + +int mbedtls_platform_std_nv_seed_write( unsigned char *buf, size_t buf_len ) +{ + FILE *file; + size_t n; + + if( ( file = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "w" ) ) == NULL ) + return -1; + + if( ( n = fwrite( buf, 1, buf_len, file ) ) != buf_len ) + { + fclose( file ); + return -1; + } + + fclose( file ); + return( (int)n ); +} +#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */ + +#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_nv_seed_read_uninit( unsigned char *buf, size_t buf_len ) +{ + ((void) buf); + ((void) buf_len); + return( -1 ); +} + +#define MBEDTLS_PLATFORM_STD_NV_SEED_READ platform_nv_seed_read_uninit +#endif /* !MBEDTLS_PLATFORM_STD_NV_SEED_READ */ + +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_nv_seed_write_uninit( unsigned char *buf, size_t buf_len ) +{ + ((void) buf); + ((void) buf_len); + return( -1 ); +} + +#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE platform_nv_seed_write_uninit +#endif /* !MBEDTLS_PLATFORM_STD_NV_SEED_WRITE */ + +int (*mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len ) = + MBEDTLS_PLATFORM_STD_NV_SEED_READ; +int (*mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len ) = + MBEDTLS_PLATFORM_STD_NV_SEED_WRITE; + +int mbedtls_platform_set_nv_seed( + int (*nv_seed_read_func)( unsigned char *buf, size_t buf_len ), + int (*nv_seed_write_func)( unsigned char *buf, size_t buf_len ) ) +{ + mbedtls_nv_seed_read = nv_seed_read_func; + mbedtls_nv_seed_write = nv_seed_write_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */ +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#if !defined(MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT) +/* + * Placeholder platform setup that does nothing by default + */ +int mbedtls_platform_setup( mbedtls_platform_context *ctx ) +{ + (void)ctx; + + return( 0 ); +} + +/* + * Placeholder platform teardown that does nothing by default + */ +void mbedtls_platform_teardown( mbedtls_platform_context *ctx ) +{ + (void)ctx; +} +#endif /* MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT */ + +#endif /* MBEDTLS_PLATFORM_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/platform_util.c b/FreeRTOS-Labs/Source/mbedtls/library/platform_util.c new file mode 100644 index 000000000..b226cff3e --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/platform_util.c @@ -0,0 +1,136 @@ +/* + * Common and shared functions used by multiple modules in the Mbed TLS + * library. + * + * Copyright (C) 2018, Arm Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +/* + * Ensure gmtime_r is available even with -std=c99; must be defined before + * config.h, which pulls in glibc's features.h. Harmless on other platforms. + */ +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 200112L +#endif + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "mbedtls/platform_util.h" +#include "mbedtls/platform.h" +#include "mbedtls/threading.h" + +#include +#include + +#if !defined(MBEDTLS_PLATFORM_ZEROIZE_ALT) +/* + * This implementation should never be optimized out by the compiler + * + * This implementation for mbedtls_platform_zeroize() was inspired from Colin + * Percival's blog article at: + * + * http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html + * + * It uses a volatile function pointer to the standard memset(). Because the + * pointer is volatile the compiler expects it to change at + * any time and will not optimize out the call that could potentially perform + * other operations on the input buffer instead of just setting it to 0. + * Nevertheless, as pointed out by davidtgoldblatt on Hacker News + * (refer to http://www.daemonology.net/blog/2014-09-05-erratum.html for + * details), optimizations of the following form are still possible: + * + * if( memset_func != memset ) + * memset_func( buf, 0, len ); + * + * Note that it is extremely difficult to guarantee that + * mbedtls_platform_zeroize() will not be optimized out by aggressive compilers + * in a portable way. For this reason, Mbed TLS also provides the configuration + * option MBEDTLS_PLATFORM_ZEROIZE_ALT, which allows users to configure + * mbedtls_platform_zeroize() to use a suitable implementation for their + * platform and needs. + */ +static void * (* const volatile memset_func)( void *, int, size_t ) = memset; + +void mbedtls_platform_zeroize( void *buf, size_t len ) +{ + memset_func( buf, 0, len ); +} +#endif /* MBEDTLS_PLATFORM_ZEROIZE_ALT */ + +#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT) +#include +#if !defined(_WIN32) && (defined(unix) || \ + defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \ + defined(__MACH__))) +#include +#endif /* !_WIN32 && (unix || __unix || __unix__ || + * (__APPLE__ && __MACH__)) */ + +#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \ + ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \ + _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) +/* + * This is a convenience shorthand macro to avoid checking the long + * preprocessor conditions above. Ideally, we could expose this macro in + * platform_util.h and simply use it in platform_util.c, threading.c and + * threading.h. However, this macro is not part of the Mbed TLS public API, so + * we keep it private by only defining it in this file + */ +#if ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) +#define PLATFORM_UTIL_USE_GMTIME +#endif /* ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) */ + +#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \ + ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \ + _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */ + +struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt, + struct tm *tm_buf ) +{ +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + return( ( gmtime_s( tm_buf, tt ) == 0 ) ? tm_buf : NULL ); +#elif !defined(PLATFORM_UTIL_USE_GMTIME) + return( gmtime_r( tt, tm_buf ) ); +#else + struct tm *lt; + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &mbedtls_threading_gmtime_mutex ) != 0 ) + return( NULL ); +#endif /* MBEDTLS_THREADING_C */ + + lt = gmtime( tt ); + + if( lt != NULL ) + { + memcpy( tm_buf, lt, sizeof( struct tm ) ); + } + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &mbedtls_threading_gmtime_mutex ) != 0 ) + return( NULL ); +#endif /* MBEDTLS_THREADING_C */ + + return( ( lt == NULL ) ? NULL : tm_buf ); +#endif /* _WIN32 && !EFIX64 && !EFI32 */ +} +#endif /* MBEDTLS_HAVE_TIME_DATE && MBEDTLS_PLATFORM_GMTIME_R_ALT */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/poly1305.c b/FreeRTOS-Labs/Source/mbedtls/library/poly1305.c new file mode 100644 index 000000000..bce1a9a2e --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/poly1305.c @@ -0,0 +1,559 @@ +/** + * \file poly1305.c + * + * \brief Poly1305 authentication algorithm. + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_POLY1305_C) + +#include "mbedtls/poly1305.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_POLY1305_ALT) + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* Parameter validation macros */ +#define POLY1305_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA ) +#define POLY1305_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#define POLY1305_BLOCK_SIZE_BYTES ( 16U ) + +#define BYTES_TO_U32_LE( data, offset ) \ + ( (uint32_t) (data)[offset] \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 1] << 8 ) \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 2] << 16 ) \ + | (uint32_t) ( (uint32_t) (data)[( offset ) + 3] << 24 ) \ + ) + +/* + * Our implementation is tuned for 32-bit platforms with a 64-bit multiplier. + * However we provided an alternative for platforms without such a multiplier. + */ +#if defined(MBEDTLS_NO_64BIT_MULTIPLICATION) +static uint64_t mul64( uint32_t a, uint32_t b ) +{ + /* a = al + 2**16 ah, b = bl + 2**16 bh */ + const uint16_t al = (uint16_t) a; + const uint16_t bl = (uint16_t) b; + const uint16_t ah = a >> 16; + const uint16_t bh = b >> 16; + + /* ab = al*bl + 2**16 (ah*bl + bl*bh) + 2**32 ah*bh */ + const uint32_t lo = (uint32_t) al * bl; + const uint64_t me = (uint64_t)( (uint32_t) ah * bl ) + (uint32_t) al * bh; + const uint32_t hi = (uint32_t) ah * bh; + + return( lo + ( me << 16 ) + ( (uint64_t) hi << 32 ) ); +} +#else +static inline uint64_t mul64( uint32_t a, uint32_t b ) +{ + return( (uint64_t) a * b ); +} +#endif + + +/** + * \brief Process blocks with Poly1305. + * + * \param ctx The Poly1305 context. + * \param nblocks Number of blocks to process. Note that this + * function only processes full blocks. + * \param input Buffer containing the input block(s). + * \param needs_padding Set to 0 if the padding bit has already been + * applied to the input data before calling this + * function. Otherwise, set this parameter to 1. + */ +static void poly1305_process( mbedtls_poly1305_context *ctx, + size_t nblocks, + const unsigned char *input, + uint32_t needs_padding ) +{ + uint64_t d0, d1, d2, d3; + uint32_t acc0, acc1, acc2, acc3, acc4; + uint32_t r0, r1, r2, r3; + uint32_t rs1, rs2, rs3; + size_t offset = 0U; + size_t i; + + r0 = ctx->r[0]; + r1 = ctx->r[1]; + r2 = ctx->r[2]; + r3 = ctx->r[3]; + + rs1 = r1 + ( r1 >> 2U ); + rs2 = r2 + ( r2 >> 2U ); + rs3 = r3 + ( r3 >> 2U ); + + acc0 = ctx->acc[0]; + acc1 = ctx->acc[1]; + acc2 = ctx->acc[2]; + acc3 = ctx->acc[3]; + acc4 = ctx->acc[4]; + + /* Process full blocks */ + for( i = 0U; i < nblocks; i++ ) + { + /* The input block is treated as a 128-bit little-endian integer */ + d0 = BYTES_TO_U32_LE( input, offset + 0 ); + d1 = BYTES_TO_U32_LE( input, offset + 4 ); + d2 = BYTES_TO_U32_LE( input, offset + 8 ); + d3 = BYTES_TO_U32_LE( input, offset + 12 ); + + /* Compute: acc += (padded) block as a 130-bit integer */ + d0 += (uint64_t) acc0; + d1 += (uint64_t) acc1 + ( d0 >> 32U ); + d2 += (uint64_t) acc2 + ( d1 >> 32U ); + d3 += (uint64_t) acc3 + ( d2 >> 32U ); + acc0 = (uint32_t) d0; + acc1 = (uint32_t) d1; + acc2 = (uint32_t) d2; + acc3 = (uint32_t) d3; + acc4 += (uint32_t) ( d3 >> 32U ) + needs_padding; + + /* Compute: acc *= r */ + d0 = mul64( acc0, r0 ) + + mul64( acc1, rs3 ) + + mul64( acc2, rs2 ) + + mul64( acc3, rs1 ); + d1 = mul64( acc0, r1 ) + + mul64( acc1, r0 ) + + mul64( acc2, rs3 ) + + mul64( acc3, rs2 ) + + mul64( acc4, rs1 ); + d2 = mul64( acc0, r2 ) + + mul64( acc1, r1 ) + + mul64( acc2, r0 ) + + mul64( acc3, rs3 ) + + mul64( acc4, rs2 ); + d3 = mul64( acc0, r3 ) + + mul64( acc1, r2 ) + + mul64( acc2, r1 ) + + mul64( acc3, r0 ) + + mul64( acc4, rs3 ); + acc4 *= r0; + + /* Compute: acc %= (2^130 - 5) (partial remainder) */ + d1 += ( d0 >> 32 ); + d2 += ( d1 >> 32 ); + d3 += ( d2 >> 32 ); + acc0 = (uint32_t) d0; + acc1 = (uint32_t) d1; + acc2 = (uint32_t) d2; + acc3 = (uint32_t) d3; + acc4 = (uint32_t) ( d3 >> 32 ) + acc4; + + d0 = (uint64_t) acc0 + ( acc4 >> 2 ) + ( acc4 & 0xFFFFFFFCU ); + acc4 &= 3U; + acc0 = (uint32_t) d0; + d0 = (uint64_t) acc1 + ( d0 >> 32U ); + acc1 = (uint32_t) d0; + d0 = (uint64_t) acc2 + ( d0 >> 32U ); + acc2 = (uint32_t) d0; + d0 = (uint64_t) acc3 + ( d0 >> 32U ); + acc3 = (uint32_t) d0; + d0 = (uint64_t) acc4 + ( d0 >> 32U ); + acc4 = (uint32_t) d0; + + offset += POLY1305_BLOCK_SIZE_BYTES; + } + + ctx->acc[0] = acc0; + ctx->acc[1] = acc1; + ctx->acc[2] = acc2; + ctx->acc[3] = acc3; + ctx->acc[4] = acc4; +} + +/** + * \brief Compute the Poly1305 MAC + * + * \param ctx The Poly1305 context. + * \param mac The buffer to where the MAC is written. Must be + * big enough to contain the 16-byte MAC. + */ +static void poly1305_compute_mac( const mbedtls_poly1305_context *ctx, + unsigned char mac[16] ) +{ + uint64_t d; + uint32_t g0, g1, g2, g3, g4; + uint32_t acc0, acc1, acc2, acc3, acc4; + uint32_t mask; + uint32_t mask_inv; + + acc0 = ctx->acc[0]; + acc1 = ctx->acc[1]; + acc2 = ctx->acc[2]; + acc3 = ctx->acc[3]; + acc4 = ctx->acc[4]; + + /* Before adding 's' we ensure that the accumulator is mod 2^130 - 5. + * We do this by calculating acc - (2^130 - 5), then checking if + * the 131st bit is set. If it is, then reduce: acc -= (2^130 - 5) + */ + + /* Calculate acc + -(2^130 - 5) */ + d = ( (uint64_t) acc0 + 5U ); + g0 = (uint32_t) d; + d = ( (uint64_t) acc1 + ( d >> 32 ) ); + g1 = (uint32_t) d; + d = ( (uint64_t) acc2 + ( d >> 32 ) ); + g2 = (uint32_t) d; + d = ( (uint64_t) acc3 + ( d >> 32 ) ); + g3 = (uint32_t) d; + g4 = acc4 + (uint32_t) ( d >> 32U ); + + /* mask == 0xFFFFFFFF if 131st bit is set, otherwise mask == 0 */ + mask = (uint32_t) 0U - ( g4 >> 2U ); + mask_inv = ~mask; + + /* If 131st bit is set then acc=g, otherwise, acc is unmodified */ + acc0 = ( acc0 & mask_inv ) | ( g0 & mask ); + acc1 = ( acc1 & mask_inv ) | ( g1 & mask ); + acc2 = ( acc2 & mask_inv ) | ( g2 & mask ); + acc3 = ( acc3 & mask_inv ) | ( g3 & mask ); + + /* Add 's' */ + d = (uint64_t) acc0 + ctx->s[0]; + acc0 = (uint32_t) d; + d = (uint64_t) acc1 + ctx->s[1] + ( d >> 32U ); + acc1 = (uint32_t) d; + d = (uint64_t) acc2 + ctx->s[2] + ( d >> 32U ); + acc2 = (uint32_t) d; + acc3 += ctx->s[3] + (uint32_t) ( d >> 32U ); + + /* Compute MAC (128 least significant bits of the accumulator) */ + mac[ 0] = (unsigned char)( acc0 ); + mac[ 1] = (unsigned char)( acc0 >> 8 ); + mac[ 2] = (unsigned char)( acc0 >> 16 ); + mac[ 3] = (unsigned char)( acc0 >> 24 ); + mac[ 4] = (unsigned char)( acc1 ); + mac[ 5] = (unsigned char)( acc1 >> 8 ); + mac[ 6] = (unsigned char)( acc1 >> 16 ); + mac[ 7] = (unsigned char)( acc1 >> 24 ); + mac[ 8] = (unsigned char)( acc2 ); + mac[ 9] = (unsigned char)( acc2 >> 8 ); + mac[10] = (unsigned char)( acc2 >> 16 ); + mac[11] = (unsigned char)( acc2 >> 24 ); + mac[12] = (unsigned char)( acc3 ); + mac[13] = (unsigned char)( acc3 >> 8 ); + mac[14] = (unsigned char)( acc3 >> 16 ); + mac[15] = (unsigned char)( acc3 >> 24 ); +} + +void mbedtls_poly1305_init( mbedtls_poly1305_context *ctx ) +{ + POLY1305_VALIDATE( ctx != NULL ); + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_poly1305_context ) ); +} + +void mbedtls_poly1305_free( mbedtls_poly1305_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_poly1305_context ) ); +} + +int mbedtls_poly1305_starts( mbedtls_poly1305_context *ctx, + const unsigned char key[32] ) +{ + POLY1305_VALIDATE_RET( ctx != NULL ); + POLY1305_VALIDATE_RET( key != NULL ); + + /* r &= 0x0ffffffc0ffffffc0ffffffc0fffffff */ + ctx->r[0] = BYTES_TO_U32_LE( key, 0 ) & 0x0FFFFFFFU; + ctx->r[1] = BYTES_TO_U32_LE( key, 4 ) & 0x0FFFFFFCU; + ctx->r[2] = BYTES_TO_U32_LE( key, 8 ) & 0x0FFFFFFCU; + ctx->r[3] = BYTES_TO_U32_LE( key, 12 ) & 0x0FFFFFFCU; + + ctx->s[0] = BYTES_TO_U32_LE( key, 16 ); + ctx->s[1] = BYTES_TO_U32_LE( key, 20 ); + ctx->s[2] = BYTES_TO_U32_LE( key, 24 ); + ctx->s[3] = BYTES_TO_U32_LE( key, 28 ); + + /* Initial accumulator state */ + ctx->acc[0] = 0U; + ctx->acc[1] = 0U; + ctx->acc[2] = 0U; + ctx->acc[3] = 0U; + ctx->acc[4] = 0U; + + /* Queue initially empty */ + mbedtls_platform_zeroize( ctx->queue, sizeof( ctx->queue ) ); + ctx->queue_len = 0U; + + return( 0 ); +} + +int mbedtls_poly1305_update( mbedtls_poly1305_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + size_t offset = 0U; + size_t remaining = ilen; + size_t queue_free_len; + size_t nblocks; + POLY1305_VALIDATE_RET( ctx != NULL ); + POLY1305_VALIDATE_RET( ilen == 0 || input != NULL ); + + if( ( remaining > 0U ) && ( ctx->queue_len > 0U ) ) + { + queue_free_len = ( POLY1305_BLOCK_SIZE_BYTES - ctx->queue_len ); + + if( ilen < queue_free_len ) + { + /* Not enough data to complete the block. + * Store this data with the other leftovers. + */ + memcpy( &ctx->queue[ctx->queue_len], + input, + ilen ); + + ctx->queue_len += ilen; + + remaining = 0U; + } + else + { + /* Enough data to produce a complete block */ + memcpy( &ctx->queue[ctx->queue_len], + input, + queue_free_len ); + + ctx->queue_len = 0U; + + poly1305_process( ctx, 1U, ctx->queue, 1U ); /* add padding bit */ + + offset += queue_free_len; + remaining -= queue_free_len; + } + } + + if( remaining >= POLY1305_BLOCK_SIZE_BYTES ) + { + nblocks = remaining / POLY1305_BLOCK_SIZE_BYTES; + + poly1305_process( ctx, nblocks, &input[offset], 1U ); + + offset += nblocks * POLY1305_BLOCK_SIZE_BYTES; + remaining %= POLY1305_BLOCK_SIZE_BYTES; + } + + if( remaining > 0U ) + { + /* Store partial block */ + ctx->queue_len = remaining; + memcpy( ctx->queue, &input[offset], remaining ); + } + + return( 0 ); +} + +int mbedtls_poly1305_finish( mbedtls_poly1305_context *ctx, + unsigned char mac[16] ) +{ + POLY1305_VALIDATE_RET( ctx != NULL ); + POLY1305_VALIDATE_RET( mac != NULL ); + + /* Process any leftover data */ + if( ctx->queue_len > 0U ) + { + /* Add padding bit */ + ctx->queue[ctx->queue_len] = 1U; + ctx->queue_len++; + + /* Pad with zeroes */ + memset( &ctx->queue[ctx->queue_len], + 0, + POLY1305_BLOCK_SIZE_BYTES - ctx->queue_len ); + + poly1305_process( ctx, 1U, /* Process 1 block */ + ctx->queue, 0U ); /* Already padded above */ + } + + poly1305_compute_mac( ctx, mac ); + + return( 0 ); +} + +int mbedtls_poly1305_mac( const unsigned char key[32], + const unsigned char *input, + size_t ilen, + unsigned char mac[16] ) +{ + mbedtls_poly1305_context ctx; + int ret; + POLY1305_VALIDATE_RET( key != NULL ); + POLY1305_VALIDATE_RET( mac != NULL ); + POLY1305_VALIDATE_RET( ilen == 0 || input != NULL ); + + mbedtls_poly1305_init( &ctx ); + + ret = mbedtls_poly1305_starts( &ctx, key ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_poly1305_update( &ctx, input, ilen ); + if( ret != 0 ) + goto cleanup; + + ret = mbedtls_poly1305_finish( &ctx, mac ); + +cleanup: + mbedtls_poly1305_free( &ctx ); + return( ret ); +} + +#endif /* MBEDTLS_POLY1305_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char test_keys[2][32] = +{ + { + 0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33, + 0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5, 0x06, 0xa8, + 0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd, + 0x4a, 0xbf, 0xf6, 0xaf, 0x41, 0x49, 0xf5, 0x1b + }, + { + 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, + 0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0, + 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09, + 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0 + } +}; + +static const unsigned char test_data[2][127] = +{ + { + 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x69, 0x63, 0x20, 0x46, 0x6f, + 0x72, 0x75, 0x6d, 0x20, 0x52, 0x65, 0x73, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6f, + 0x75, 0x70 + }, + { + 0x27, 0x54, 0x77, 0x61, 0x73, 0x20, 0x62, 0x72, + 0x69, 0x6c, 0x6c, 0x69, 0x67, 0x2c, 0x20, 0x61, + 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, + 0x6c, 0x69, 0x74, 0x68, 0x79, 0x20, 0x74, 0x6f, + 0x76, 0x65, 0x73, 0x0a, 0x44, 0x69, 0x64, 0x20, + 0x67, 0x79, 0x72, 0x65, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x67, 0x69, 0x6d, 0x62, 0x6c, 0x65, 0x20, + 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, + 0x61, 0x62, 0x65, 0x3a, 0x0a, 0x41, 0x6c, 0x6c, + 0x20, 0x6d, 0x69, 0x6d, 0x73, 0x79, 0x20, 0x77, + 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, + 0x62, 0x6f, 0x72, 0x6f, 0x67, 0x6f, 0x76, 0x65, + 0x73, 0x2c, 0x0a, 0x41, 0x6e, 0x64, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x6d, 0x65, 0x20, + 0x72, 0x61, 0x74, 0x68, 0x73, 0x20, 0x6f, 0x75, + 0x74, 0x67, 0x72, 0x61, 0x62, 0x65, 0x2e + } +}; + +static const size_t test_data_len[2] = +{ + 34U, + 127U +}; + +static const unsigned char test_mac[2][16] = +{ + { + 0xa8, 0x06, 0x1d, 0xc1, 0x30, 0x51, 0x36, 0xc6, + 0xc2, 0x2b, 0x8b, 0xaf, 0x0c, 0x01, 0x27, 0xa9 + }, + { + 0x45, 0x41, 0x66, 0x9a, 0x7e, 0xaa, 0xee, 0x61, + 0xe7, 0x08, 0xdc, 0x7c, 0xbc, 0xc5, 0xeb, 0x62 + } +}; + +#define ASSERT( cond, args ) \ + do \ + { \ + if( ! ( cond ) ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf args; \ + \ + return( -1 ); \ + } \ + } \ + while( 0 ) + +int mbedtls_poly1305_self_test( int verbose ) +{ + unsigned char mac[16]; + unsigned i; + int ret; + + for( i = 0U; i < 2U; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " Poly1305 test %u ", i ); + + ret = mbedtls_poly1305_mac( test_keys[i], + test_data[i], + test_data_len[i], + mac ); + ASSERT( 0 == ret, ( "error code: %i\n", ret ) ); + + ASSERT( 0 == memcmp( mac, test_mac[i], 16U ), ( "failed (mac)\n" ) ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_POLY1305_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ripemd160.c b/FreeRTOS-Labs/Source/mbedtls/library/ripemd160.c new file mode 100644 index 000000000..c5702cf64 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ripemd160.c @@ -0,0 +1,559 @@ +/* + * RIPE MD-160 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The RIPEMD-160 algorithm was designed by RIPE in 1996 + * http://homes.esat.kuleuven.be/~bosselae/mbedtls_ripemd160.html + * http://ehash.iaik.tugraz.at/wiki/RIPEMD-160 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_RIPEMD160_C) + +#include "mbedtls/ripemd160.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_RIPEMD160_ALT) + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +void mbedtls_ripemd160_init( mbedtls_ripemd160_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ripemd160_context ) ); +} + +void mbedtls_ripemd160_free( mbedtls_ripemd160_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ripemd160_context ) ); +} + +void mbedtls_ripemd160_clone( mbedtls_ripemd160_context *dst, + const mbedtls_ripemd160_context *src ) +{ + *dst = *src; +} + +/* + * RIPEMD-160 context setup + */ +int mbedtls_ripemd160_starts_ret( mbedtls_ripemd160_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_ripemd160_starts( mbedtls_ripemd160_context *ctx ) +{ + mbedtls_ripemd160_starts_ret( ctx ); +} +#endif + +#if !defined(MBEDTLS_RIPEMD160_PROCESS_ALT) +/* + * Process one block + */ +int mbedtls_internal_ripemd160_process( mbedtls_ripemd160_context *ctx, + const unsigned char data[64] ) +{ + uint32_t A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, X[16]; + + GET_UINT32_LE( X[ 0], data, 0 ); + GET_UINT32_LE( X[ 1], data, 4 ); + GET_UINT32_LE( X[ 2], data, 8 ); + GET_UINT32_LE( X[ 3], data, 12 ); + GET_UINT32_LE( X[ 4], data, 16 ); + GET_UINT32_LE( X[ 5], data, 20 ); + GET_UINT32_LE( X[ 6], data, 24 ); + GET_UINT32_LE( X[ 7], data, 28 ); + GET_UINT32_LE( X[ 8], data, 32 ); + GET_UINT32_LE( X[ 9], data, 36 ); + GET_UINT32_LE( X[10], data, 40 ); + GET_UINT32_LE( X[11], data, 44 ); + GET_UINT32_LE( X[12], data, 48 ); + GET_UINT32_LE( X[13], data, 52 ); + GET_UINT32_LE( X[14], data, 56 ); + GET_UINT32_LE( X[15], data, 60 ); + + A = Ap = ctx->state[0]; + B = Bp = ctx->state[1]; + C = Cp = ctx->state[2]; + D = Dp = ctx->state[3]; + E = Ep = ctx->state[4]; + +#define F1( x, y, z ) ( (x) ^ (y) ^ (z) ) +#define F2( x, y, z ) ( ( (x) & (y) ) | ( ~(x) & (z) ) ) +#define F3( x, y, z ) ( ( (x) | ~(y) ) ^ (z) ) +#define F4( x, y, z ) ( ( (x) & (z) ) | ( (y) & ~(z) ) ) +#define F5( x, y, z ) ( (x) ^ ( (y) | ~(z) ) ) + +#define S( x, n ) ( ( (x) << (n) ) | ( (x) >> (32 - (n)) ) ) + +#define P( a, b, c, d, e, r, s, f, k ) \ + do \ + { \ + (a) += f( (b), (c), (d) ) + X[r] + (k); \ + (a) = S( (a), (s) ) + (e); \ + (c) = S( (c), 10 ); \ + } while( 0 ) + +#define P2( a, b, c, d, e, r, s, rp, sp ) \ + do \ + { \ + P( (a), (b), (c), (d), (e), (r), (s), F, K ); \ + P( a ## p, b ## p, c ## p, d ## p, e ## p, \ + (rp), (sp), Fp, Kp ); \ + } while( 0 ) + +#define F F1 +#define K 0x00000000 +#define Fp F5 +#define Kp 0x50A28BE6 + P2( A, B, C, D, E, 0, 11, 5, 8 ); + P2( E, A, B, C, D, 1, 14, 14, 9 ); + P2( D, E, A, B, C, 2, 15, 7, 9 ); + P2( C, D, E, A, B, 3, 12, 0, 11 ); + P2( B, C, D, E, A, 4, 5, 9, 13 ); + P2( A, B, C, D, E, 5, 8, 2, 15 ); + P2( E, A, B, C, D, 6, 7, 11, 15 ); + P2( D, E, A, B, C, 7, 9, 4, 5 ); + P2( C, D, E, A, B, 8, 11, 13, 7 ); + P2( B, C, D, E, A, 9, 13, 6, 7 ); + P2( A, B, C, D, E, 10, 14, 15, 8 ); + P2( E, A, B, C, D, 11, 15, 8, 11 ); + P2( D, E, A, B, C, 12, 6, 1, 14 ); + P2( C, D, E, A, B, 13, 7, 10, 14 ); + P2( B, C, D, E, A, 14, 9, 3, 12 ); + P2( A, B, C, D, E, 15, 8, 12, 6 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F2 +#define K 0x5A827999 +#define Fp F4 +#define Kp 0x5C4DD124 + P2( E, A, B, C, D, 7, 7, 6, 9 ); + P2( D, E, A, B, C, 4, 6, 11, 13 ); + P2( C, D, E, A, B, 13, 8, 3, 15 ); + P2( B, C, D, E, A, 1, 13, 7, 7 ); + P2( A, B, C, D, E, 10, 11, 0, 12 ); + P2( E, A, B, C, D, 6, 9, 13, 8 ); + P2( D, E, A, B, C, 15, 7, 5, 9 ); + P2( C, D, E, A, B, 3, 15, 10, 11 ); + P2( B, C, D, E, A, 12, 7, 14, 7 ); + P2( A, B, C, D, E, 0, 12, 15, 7 ); + P2( E, A, B, C, D, 9, 15, 8, 12 ); + P2( D, E, A, B, C, 5, 9, 12, 7 ); + P2( C, D, E, A, B, 2, 11, 4, 6 ); + P2( B, C, D, E, A, 14, 7, 9, 15 ); + P2( A, B, C, D, E, 11, 13, 1, 13 ); + P2( E, A, B, C, D, 8, 12, 2, 11 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F3 +#define K 0x6ED9EBA1 +#define Fp F3 +#define Kp 0x6D703EF3 + P2( D, E, A, B, C, 3, 11, 15, 9 ); + P2( C, D, E, A, B, 10, 13, 5, 7 ); + P2( B, C, D, E, A, 14, 6, 1, 15 ); + P2( A, B, C, D, E, 4, 7, 3, 11 ); + P2( E, A, B, C, D, 9, 14, 7, 8 ); + P2( D, E, A, B, C, 15, 9, 14, 6 ); + P2( C, D, E, A, B, 8, 13, 6, 6 ); + P2( B, C, D, E, A, 1, 15, 9, 14 ); + P2( A, B, C, D, E, 2, 14, 11, 12 ); + P2( E, A, B, C, D, 7, 8, 8, 13 ); + P2( D, E, A, B, C, 0, 13, 12, 5 ); + P2( C, D, E, A, B, 6, 6, 2, 14 ); + P2( B, C, D, E, A, 13, 5, 10, 13 ); + P2( A, B, C, D, E, 11, 12, 0, 13 ); + P2( E, A, B, C, D, 5, 7, 4, 7 ); + P2( D, E, A, B, C, 12, 5, 13, 5 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F4 +#define K 0x8F1BBCDC +#define Fp F2 +#define Kp 0x7A6D76E9 + P2( C, D, E, A, B, 1, 11, 8, 15 ); + P2( B, C, D, E, A, 9, 12, 6, 5 ); + P2( A, B, C, D, E, 11, 14, 4, 8 ); + P2( E, A, B, C, D, 10, 15, 1, 11 ); + P2( D, E, A, B, C, 0, 14, 3, 14 ); + P2( C, D, E, A, B, 8, 15, 11, 14 ); + P2( B, C, D, E, A, 12, 9, 15, 6 ); + P2( A, B, C, D, E, 4, 8, 0, 14 ); + P2( E, A, B, C, D, 13, 9, 5, 6 ); + P2( D, E, A, B, C, 3, 14, 12, 9 ); + P2( C, D, E, A, B, 7, 5, 2, 12 ); + P2( B, C, D, E, A, 15, 6, 13, 9 ); + P2( A, B, C, D, E, 14, 8, 9, 12 ); + P2( E, A, B, C, D, 5, 6, 7, 5 ); + P2( D, E, A, B, C, 6, 5, 10, 15 ); + P2( C, D, E, A, B, 2, 12, 14, 8 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F5 +#define K 0xA953FD4E +#define Fp F1 +#define Kp 0x00000000 + P2( B, C, D, E, A, 4, 9, 12, 8 ); + P2( A, B, C, D, E, 0, 15, 15, 5 ); + P2( E, A, B, C, D, 5, 5, 10, 12 ); + P2( D, E, A, B, C, 9, 11, 4, 9 ); + P2( C, D, E, A, B, 7, 6, 1, 12 ); + P2( B, C, D, E, A, 12, 8, 5, 5 ); + P2( A, B, C, D, E, 2, 13, 8, 14 ); + P2( E, A, B, C, D, 10, 12, 7, 6 ); + P2( D, E, A, B, C, 14, 5, 6, 8 ); + P2( C, D, E, A, B, 1, 12, 2, 13 ); + P2( B, C, D, E, A, 3, 13, 13, 6 ); + P2( A, B, C, D, E, 8, 14, 14, 5 ); + P2( E, A, B, C, D, 11, 11, 0, 15 ); + P2( D, E, A, B, C, 6, 8, 3, 13 ); + P2( C, D, E, A, B, 15, 5, 9, 11 ); + P2( B, C, D, E, A, 13, 6, 11, 11 ); +#undef F +#undef K +#undef Fp +#undef Kp + + C = ctx->state[1] + C + Dp; + ctx->state[1] = ctx->state[2] + D + Ep; + ctx->state[2] = ctx->state[3] + E + Ap; + ctx->state[3] = ctx->state[4] + A + Bp; + ctx->state[4] = ctx->state[0] + B + Cp; + ctx->state[0] = C; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_ripemd160_process( mbedtls_ripemd160_context *ctx, + const unsigned char data[64] ) +{ + mbedtls_internal_ripemd160_process( ctx, data ); +} +#endif +#endif /* !MBEDTLS_RIPEMD160_PROCESS_ALT */ + +/* + * RIPEMD-160 process buffer + */ +int mbedtls_ripemd160_update_ret( mbedtls_ripemd160_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + int ret; + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return( 0 ); + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + + if( ( ret = mbedtls_internal_ripemd160_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + if( ( ret = mbedtls_internal_ripemd160_process( ctx, input ) ) != 0 ) + return( ret ); + + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), input, ilen ); + } + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_ripemd160_update( mbedtls_ripemd160_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + mbedtls_ripemd160_update_ret( ctx, input, ilen ); +} +#endif + +static const unsigned char ripemd160_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * RIPEMD-160 final digest + */ +int mbedtls_ripemd160_finish_ret( mbedtls_ripemd160_context *ctx, + unsigned char output[20] ) +{ + int ret; + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_LE( low, msglen, 0 ); + PUT_UINT32_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + ret = mbedtls_ripemd160_update_ret( ctx, ripemd160_padding, padn ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_ripemd160_update_ret( ctx, msglen, 8 ); + if( ret != 0 ) + return( ret ); + + PUT_UINT32_LE( ctx->state[0], output, 0 ); + PUT_UINT32_LE( ctx->state[1], output, 4 ); + PUT_UINT32_LE( ctx->state[2], output, 8 ); + PUT_UINT32_LE( ctx->state[3], output, 12 ); + PUT_UINT32_LE( ctx->state[4], output, 16 ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_ripemd160_finish( mbedtls_ripemd160_context *ctx, + unsigned char output[20] ) +{ + mbedtls_ripemd160_finish_ret( ctx, output ); +} +#endif + +#endif /* ! MBEDTLS_RIPEMD160_ALT */ + +/* + * output = RIPEMD-160( input buffer ) + */ +int mbedtls_ripemd160_ret( const unsigned char *input, + size_t ilen, + unsigned char output[20] ) +{ + int ret; + mbedtls_ripemd160_context ctx; + + mbedtls_ripemd160_init( &ctx ); + + if( ( ret = mbedtls_ripemd160_starts_ret( &ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_ripemd160_update_ret( &ctx, input, ilen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_ripemd160_finish_ret( &ctx, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_ripemd160_free( &ctx ); + + return( ret ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_ripemd160( const unsigned char *input, + size_t ilen, + unsigned char output[20] ) +{ + mbedtls_ripemd160_ret( input, ilen, output ); +} +#endif + +#if defined(MBEDTLS_SELF_TEST) +/* + * Test vectors from the RIPEMD-160 paper and + * http://homes.esat.kuleuven.be/~bosselae/mbedtls_ripemd160.html#HMAC + */ +#define TESTS 8 +static const unsigned char ripemd160_test_str[TESTS][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" + "345678901234567890" }, +}; + +static const size_t ripemd160_test_strlen[TESTS] = +{ + 0, 1, 3, 14, 26, 56, 62, 80 +}; + +static const unsigned char ripemd160_test_md[TESTS][20] = +{ + { 0x9c, 0x11, 0x85, 0xa5, 0xc5, 0xe9, 0xfc, 0x54, 0x61, 0x28, + 0x08, 0x97, 0x7e, 0xe8, 0xf5, 0x48, 0xb2, 0x25, 0x8d, 0x31 }, + { 0x0b, 0xdc, 0x9d, 0x2d, 0x25, 0x6b, 0x3e, 0xe9, 0xda, 0xae, + 0x34, 0x7b, 0xe6, 0xf4, 0xdc, 0x83, 0x5a, 0x46, 0x7f, 0xfe }, + { 0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, 0x9b, 0x04, + 0x4a, 0x8e, 0x98, 0xc6, 0xb0, 0x87, 0xf1, 0x5a, 0x0b, 0xfc }, + { 0x5d, 0x06, 0x89, 0xef, 0x49, 0xd2, 0xfa, 0xe5, 0x72, 0xb8, + 0x81, 0xb1, 0x23, 0xa8, 0x5f, 0xfa, 0x21, 0x59, 0x5f, 0x36 }, + { 0xf7, 0x1c, 0x27, 0x10, 0x9c, 0x69, 0x2c, 0x1b, 0x56, 0xbb, + 0xdc, 0xeb, 0x5b, 0x9d, 0x28, 0x65, 0xb3, 0x70, 0x8d, 0xbc }, + { 0x12, 0xa0, 0x53, 0x38, 0x4a, 0x9c, 0x0c, 0x88, 0xe4, 0x05, + 0xa0, 0x6c, 0x27, 0xdc, 0xf4, 0x9a, 0xda, 0x62, 0xeb, 0x2b }, + { 0xb0, 0xe2, 0x0b, 0x6e, 0x31, 0x16, 0x64, 0x02, 0x86, 0xed, + 0x3a, 0x87, 0xa5, 0x71, 0x30, 0x79, 0xb2, 0x1f, 0x51, 0x89 }, + { 0x9b, 0x75, 0x2e, 0x45, 0x57, 0x3d, 0x4b, 0x39, 0xf4, 0xdb, + 0xd3, 0x32, 0x3c, 0xab, 0x82, 0xbf, 0x63, 0x32, 0x6b, 0xfb }, +}; + +/* + * Checkup routine + */ +int mbedtls_ripemd160_self_test( int verbose ) +{ + int i, ret = 0; + unsigned char output[20]; + + memset( output, 0, sizeof output ); + + for( i = 0; i < TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " RIPEMD-160 test #%d: ", i + 1 ); + + ret = mbedtls_ripemd160_ret( ripemd160_test_str[i], + ripemd160_test_strlen[i], output ); + if( ret != 0 ) + goto fail; + + if( memcmp( output, ripemd160_test_md[i], 20 ) != 0 ) + { + ret = 1; + goto fail; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); + +fail: + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_RIPEMD160_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/rsa.c b/FreeRTOS-Labs/Source/mbedtls/library/rsa.c new file mode 100644 index 000000000..11a5067b9 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/rsa.c @@ -0,0 +1,2729 @@ +/* + * The RSA public-key cryptosystem + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The following sources were referenced in the design of this implementation + * of the RSA algorithm: + * + * [1] A method for obtaining digital signatures and public-key cryptosystems + * R Rivest, A Shamir, and L Adleman + * http://people.csail.mit.edu/rivest/pubs.html#RSA78 + * + * [2] Handbook of Applied Cryptography - 1997, Chapter 8 + * Menezes, van Oorschot and Vanstone + * + * [3] Malware Guard Extension: Using SGX to Conceal Cache Attacks + * Michael Schwarz, Samuel Weiser, Daniel Gruss, Clémentine Maurice and + * Stefan Mangard + * https://arxiv.org/abs/1702.08719v2 + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_RSA_C) + +#include "mbedtls/rsa.h" +#include "mbedtls/rsa_internal.h" +#include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_PKCS1_V21) +#include "mbedtls/md.h" +#endif + +#if defined(MBEDTLS_PKCS1_V15) && !defined(__OpenBSD__) +#include +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if !defined(MBEDTLS_RSA_ALT) + +/* Parameter validation macros */ +#define RSA_VALIDATE_RET( cond ) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_RSA_BAD_INPUT_DATA ) +#define RSA_VALIDATE( cond ) \ + MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if defined(MBEDTLS_PKCS1_V15) +/* constant-time buffer comparison */ +static inline int mbedtls_safer_memcmp( const void *a, const void *b, size_t n ) +{ + size_t i; + const unsigned char *A = (const unsigned char *) a; + const unsigned char *B = (const unsigned char *) b; + unsigned char diff = 0; + + for( i = 0; i < n; i++ ) + diff |= A[i] ^ B[i]; + + return( diff ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +int mbedtls_rsa_import( mbedtls_rsa_context *ctx, + const mbedtls_mpi *N, + const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, const mbedtls_mpi *E ) +{ + int ret; + RSA_VALIDATE_RET( ctx != NULL ); + + if( ( N != NULL && ( ret = mbedtls_mpi_copy( &ctx->N, N ) ) != 0 ) || + ( P != NULL && ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 ) || + ( Q != NULL && ( ret = mbedtls_mpi_copy( &ctx->Q, Q ) ) != 0 ) || + ( D != NULL && ( ret = mbedtls_mpi_copy( &ctx->D, D ) ) != 0 ) || + ( E != NULL && ( ret = mbedtls_mpi_copy( &ctx->E, E ) ) != 0 ) ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + } + + if( N != NULL ) + ctx->len = mbedtls_mpi_size( &ctx->N ); + + return( 0 ); +} + +int mbedtls_rsa_import_raw( mbedtls_rsa_context *ctx, + unsigned char const *N, size_t N_len, + unsigned char const *P, size_t P_len, + unsigned char const *Q, size_t Q_len, + unsigned char const *D, size_t D_len, + unsigned char const *E, size_t E_len ) +{ + int ret = 0; + RSA_VALIDATE_RET( ctx != NULL ); + + if( N != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->N, N, N_len ) ); + ctx->len = mbedtls_mpi_size( &ctx->N ); + } + + if( P != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->P, P, P_len ) ); + + if( Q != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->Q, Q, Q_len ) ); + + if( D != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->D, D, D_len ) ); + + if( E != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->E, E, E_len ) ); + +cleanup: + + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + + return( 0 ); +} + +/* + * Checks whether the context fields are set in such a way + * that the RSA primitives will be able to execute without error. + * It does *not* make guarantees for consistency of the parameters. + */ +static int rsa_check_context( mbedtls_rsa_context const *ctx, int is_priv, + int blinding_needed ) +{ +#if !defined(MBEDTLS_RSA_NO_CRT) + /* blinding_needed is only used for NO_CRT to decide whether + * P,Q need to be present or not. */ + ((void) blinding_needed); +#endif + + if( ctx->len != mbedtls_mpi_size( &ctx->N ) || + ctx->len > MBEDTLS_MPI_MAX_SIZE ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + /* + * 1. Modular exponentiation needs positive, odd moduli. + */ + + /* Modular exponentiation wrt. N is always used for + * RSA public key operations. */ + if( mbedtls_mpi_cmp_int( &ctx->N, 0 ) <= 0 || + mbedtls_mpi_get_bit( &ctx->N, 0 ) == 0 ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + +#if !defined(MBEDTLS_RSA_NO_CRT) + /* Modular exponentiation for P and Q is only + * used for private key operations and if CRT + * is used. */ + if( is_priv && + ( mbedtls_mpi_cmp_int( &ctx->P, 0 ) <= 0 || + mbedtls_mpi_get_bit( &ctx->P, 0 ) == 0 || + mbedtls_mpi_cmp_int( &ctx->Q, 0 ) <= 0 || + mbedtls_mpi_get_bit( &ctx->Q, 0 ) == 0 ) ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } +#endif /* !MBEDTLS_RSA_NO_CRT */ + + /* + * 2. Exponents must be positive + */ + + /* Always need E for public key operations */ + if( mbedtls_mpi_cmp_int( &ctx->E, 0 ) <= 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_RSA_NO_CRT) + /* For private key operations, use D or DP & DQ + * as (unblinded) exponents. */ + if( is_priv && mbedtls_mpi_cmp_int( &ctx->D, 0 ) <= 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); +#else + if( is_priv && + ( mbedtls_mpi_cmp_int( &ctx->DP, 0 ) <= 0 || + mbedtls_mpi_cmp_int( &ctx->DQ, 0 ) <= 0 ) ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* Blinding shouldn't make exponents negative either, + * so check that P, Q >= 1 if that hasn't yet been + * done as part of 1. */ +#if defined(MBEDTLS_RSA_NO_CRT) + if( is_priv && blinding_needed && + ( mbedtls_mpi_cmp_int( &ctx->P, 0 ) <= 0 || + mbedtls_mpi_cmp_int( &ctx->Q, 0 ) <= 0 ) ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } +#endif + + /* It wouldn't lead to an error if it wasn't satisfied, + * but check for QP >= 1 nonetheless. */ +#if !defined(MBEDTLS_RSA_NO_CRT) + if( is_priv && + mbedtls_mpi_cmp_int( &ctx->QP, 0 ) <= 0 ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } +#endif + + return( 0 ); +} + +int mbedtls_rsa_complete( mbedtls_rsa_context *ctx ) +{ + int ret = 0; + int have_N, have_P, have_Q, have_D, have_E; + int n_missing, pq_missing, d_missing, is_pub, is_priv; + + RSA_VALIDATE_RET( ctx != NULL ); + + have_N = ( mbedtls_mpi_cmp_int( &ctx->N, 0 ) != 0 ); + have_P = ( mbedtls_mpi_cmp_int( &ctx->P, 0 ) != 0 ); + have_Q = ( mbedtls_mpi_cmp_int( &ctx->Q, 0 ) != 0 ); + have_D = ( mbedtls_mpi_cmp_int( &ctx->D, 0 ) != 0 ); + have_E = ( mbedtls_mpi_cmp_int( &ctx->E, 0 ) != 0 ); + + /* + * Check whether provided parameters are enough + * to deduce all others. The following incomplete + * parameter sets for private keys are supported: + * + * (1) P, Q missing. + * (2) D and potentially N missing. + * + */ + + n_missing = have_P && have_Q && have_D && have_E; + pq_missing = have_N && !have_P && !have_Q && have_D && have_E; + d_missing = have_P && have_Q && !have_D && have_E; + is_pub = have_N && !have_P && !have_Q && !have_D && have_E; + + /* These three alternatives are mutually exclusive */ + is_priv = n_missing || pq_missing || d_missing; + + if( !is_priv && !is_pub ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* + * Step 1: Deduce N if P, Q are provided. + */ + + if( !have_N && have_P && have_Q ) + { + if( ( ret = mbedtls_mpi_mul_mpi( &ctx->N, &ctx->P, + &ctx->Q ) ) != 0 ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + } + + ctx->len = mbedtls_mpi_size( &ctx->N ); + } + + /* + * Step 2: Deduce and verify all remaining core parameters. + */ + + if( pq_missing ) + { + ret = mbedtls_rsa_deduce_primes( &ctx->N, &ctx->E, &ctx->D, + &ctx->P, &ctx->Q ); + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + + } + else if( d_missing ) + { + if( ( ret = mbedtls_rsa_deduce_private_exponent( &ctx->P, + &ctx->Q, + &ctx->E, + &ctx->D ) ) != 0 ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + } + } + + /* + * Step 3: Deduce all additional parameters specific + * to our current RSA implementation. + */ + +#if !defined(MBEDTLS_RSA_NO_CRT) + if( is_priv ) + { + ret = mbedtls_rsa_deduce_crt( &ctx->P, &ctx->Q, &ctx->D, + &ctx->DP, &ctx->DQ, &ctx->QP ); + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + } +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* + * Step 3: Basic sanity checks + */ + + return( rsa_check_context( ctx, is_priv, 1 ) ); +} + +int mbedtls_rsa_export_raw( const mbedtls_rsa_context *ctx, + unsigned char *N, size_t N_len, + unsigned char *P, size_t P_len, + unsigned char *Q, size_t Q_len, + unsigned char *D, size_t D_len, + unsigned char *E, size_t E_len ) +{ + int ret = 0; + int is_priv; + RSA_VALIDATE_RET( ctx != NULL ); + + /* Check if key is private or public */ + is_priv = + mbedtls_mpi_cmp_int( &ctx->N, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->P, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->Q, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->D, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->E, 0 ) != 0; + + if( !is_priv ) + { + /* If we're trying to export private parameters for a public key, + * something must be wrong. */ + if( P != NULL || Q != NULL || D != NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + } + + if( N != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->N, N, N_len ) ); + + if( P != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->P, P, P_len ) ); + + if( Q != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->Q, Q, Q_len ) ); + + if( D != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->D, D, D_len ) ); + + if( E != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->E, E, E_len ) ); + +cleanup: + + return( ret ); +} + +int mbedtls_rsa_export( const mbedtls_rsa_context *ctx, + mbedtls_mpi *N, mbedtls_mpi *P, mbedtls_mpi *Q, + mbedtls_mpi *D, mbedtls_mpi *E ) +{ + int ret; + int is_priv; + RSA_VALIDATE_RET( ctx != NULL ); + + /* Check if key is private or public */ + is_priv = + mbedtls_mpi_cmp_int( &ctx->N, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->P, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->Q, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->D, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->E, 0 ) != 0; + + if( !is_priv ) + { + /* If we're trying to export private parameters for a public key, + * something must be wrong. */ + if( P != NULL || Q != NULL || D != NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + } + + /* Export all requested core parameters. */ + + if( ( N != NULL && ( ret = mbedtls_mpi_copy( N, &ctx->N ) ) != 0 ) || + ( P != NULL && ( ret = mbedtls_mpi_copy( P, &ctx->P ) ) != 0 ) || + ( Q != NULL && ( ret = mbedtls_mpi_copy( Q, &ctx->Q ) ) != 0 ) || + ( D != NULL && ( ret = mbedtls_mpi_copy( D, &ctx->D ) ) != 0 ) || + ( E != NULL && ( ret = mbedtls_mpi_copy( E, &ctx->E ) ) != 0 ) ) + { + return( ret ); + } + + return( 0 ); +} + +/* + * Export CRT parameters + * This must also be implemented if CRT is not used, for being able to + * write DER encoded RSA keys. The helper function mbedtls_rsa_deduce_crt + * can be used in this case. + */ +int mbedtls_rsa_export_crt( const mbedtls_rsa_context *ctx, + mbedtls_mpi *DP, mbedtls_mpi *DQ, mbedtls_mpi *QP ) +{ + int ret; + int is_priv; + RSA_VALIDATE_RET( ctx != NULL ); + + /* Check if key is private or public */ + is_priv = + mbedtls_mpi_cmp_int( &ctx->N, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->P, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->Q, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->D, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->E, 0 ) != 0; + + if( !is_priv ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + +#if !defined(MBEDTLS_RSA_NO_CRT) + /* Export all requested blinding parameters. */ + if( ( DP != NULL && ( ret = mbedtls_mpi_copy( DP, &ctx->DP ) ) != 0 ) || + ( DQ != NULL && ( ret = mbedtls_mpi_copy( DQ, &ctx->DQ ) ) != 0 ) || + ( QP != NULL && ( ret = mbedtls_mpi_copy( QP, &ctx->QP ) ) != 0 ) ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + } +#else + if( ( ret = mbedtls_rsa_deduce_crt( &ctx->P, &ctx->Q, &ctx->D, + DP, DQ, QP ) ) != 0 ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + } +#endif + + return( 0 ); +} + +/* + * Initialize an RSA context + */ +void mbedtls_rsa_init( mbedtls_rsa_context *ctx, + int padding, + int hash_id ) +{ + RSA_VALIDATE( ctx != NULL ); + RSA_VALIDATE( padding == MBEDTLS_RSA_PKCS_V15 || + padding == MBEDTLS_RSA_PKCS_V21 ); + + memset( ctx, 0, sizeof( mbedtls_rsa_context ) ); + + mbedtls_rsa_set_padding( ctx, padding, hash_id ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +/* + * Set padding for an existing RSA context + */ +void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, + int hash_id ) +{ + RSA_VALIDATE( ctx != NULL ); + RSA_VALIDATE( padding == MBEDTLS_RSA_PKCS_V15 || + padding == MBEDTLS_RSA_PKCS_V21 ); + + ctx->padding = padding; + ctx->hash_id = hash_id; +} + +/* + * Get length in bytes of RSA modulus + */ + +size_t mbedtls_rsa_get_len( const mbedtls_rsa_context *ctx ) +{ + return( ctx->len ); +} + + +#if defined(MBEDTLS_GENPRIME) + +/* + * Generate an RSA keypair + * + * This generation method follows the RSA key pair generation procedure of + * FIPS 186-4 if 2^16 < exponent < 2^256 and nbits = 2048 or nbits = 3072. + */ +int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent ) +{ + int ret; + mbedtls_mpi H, G, L; + int prime_quality = 0; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( f_rng != NULL ); + + if( nbits < 128 || exponent < 3 || nbits % 2 != 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* + * If the modulus is 1024 bit long or shorter, then the security strength of + * the RSA algorithm is less than or equal to 80 bits and therefore an error + * rate of 2^-80 is sufficient. + */ + if( nbits > 1024 ) + prime_quality = MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR; + + mbedtls_mpi_init( &H ); + mbedtls_mpi_init( &G ); + mbedtls_mpi_init( &L ); + + /* + * find primes P and Q with Q < P so that: + * 1. |P-Q| > 2^( nbits / 2 - 100 ) + * 2. GCD( E, (P-1)*(Q-1) ) == 1 + * 3. E^-1 mod LCM(P-1, Q-1) > 2^( nbits / 2 ) + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->E, exponent ) ); + + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->P, nbits >> 1, + prime_quality, f_rng, p_rng ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->Q, nbits >> 1, + prime_quality, f_rng, p_rng ) ); + + /* make sure the difference between p and q is not too small (FIPS 186-4 §B.3.3 step 5.4) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &H, &ctx->P, &ctx->Q ) ); + if( mbedtls_mpi_bitlen( &H ) <= ( ( nbits >= 200 ) ? ( ( nbits >> 1 ) - 99 ) : 0 ) ) + continue; + + /* not required by any standards, but some users rely on the fact that P > Q */ + if( H.s < 0 ) + mbedtls_mpi_swap( &ctx->P, &ctx->Q ); + + /* Temporarily replace P,Q by P-1, Q-1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &ctx->P, &ctx->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &ctx->Q, &ctx->Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &ctx->P, &ctx->Q ) ); + + /* check GCD( E, (P-1)*(Q-1) ) == 1 (FIPS 186-4 §B.3.1 criterion 2(a)) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) ); + if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 ) + continue; + + /* compute smallest possible D = E^-1 mod LCM(P-1, Q-1) (FIPS 186-4 §B.3.1 criterion 3(b)) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->P, &ctx->Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &L, NULL, &H, &G ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->D, &ctx->E, &L ) ); + + if( mbedtls_mpi_bitlen( &ctx->D ) <= ( ( nbits + 1 ) / 2 ) ) // (FIPS 186-4 §B.3.1 criterion 3(a)) + continue; + + break; + } + while( 1 ); + + /* Restore P,Q */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &ctx->P, &ctx->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &ctx->Q, &ctx->Q, 1 ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) ); + + ctx->len = mbedtls_mpi_size( &ctx->N ); + +#if !defined(MBEDTLS_RSA_NO_CRT) + /* + * DP = D mod (P - 1) + * DQ = D mod (Q - 1) + * QP = Q^-1 mod P + */ + MBEDTLS_MPI_CHK( mbedtls_rsa_deduce_crt( &ctx->P, &ctx->Q, &ctx->D, + &ctx->DP, &ctx->DQ, &ctx->QP ) ); +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* Double-check */ + MBEDTLS_MPI_CHK( mbedtls_rsa_check_privkey( ctx ) ); + +cleanup: + + mbedtls_mpi_free( &H ); + mbedtls_mpi_free( &G ); + mbedtls_mpi_free( &L ); + + if( ret != 0 ) + { + mbedtls_rsa_free( ctx ); + return( MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret ); + } + + return( 0 ); +} + +#endif /* MBEDTLS_GENPRIME */ + +/* + * Check a public RSA key + */ +int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ) +{ + RSA_VALIDATE_RET( ctx != NULL ); + + if( rsa_check_context( ctx, 0 /* public */, 0 /* no blinding */ ) != 0 ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + if( mbedtls_mpi_bitlen( &ctx->N ) < 128 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + if( mbedtls_mpi_get_bit( &ctx->E, 0 ) == 0 || + mbedtls_mpi_bitlen( &ctx->E ) < 2 || + mbedtls_mpi_cmp_mpi( &ctx->E, &ctx->N ) >= 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + return( 0 ); +} + +/* + * Check for the consistency of all fields in an RSA private key context + */ +int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ) +{ + RSA_VALIDATE_RET( ctx != NULL ); + + if( mbedtls_rsa_check_pubkey( ctx ) != 0 || + rsa_check_context( ctx, 1 /* private */, 1 /* blinding */ ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + if( mbedtls_rsa_validate_params( &ctx->N, &ctx->P, &ctx->Q, + &ctx->D, &ctx->E, NULL, NULL ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + +#if !defined(MBEDTLS_RSA_NO_CRT) + else if( mbedtls_rsa_validate_crt( &ctx->P, &ctx->Q, &ctx->D, + &ctx->DP, &ctx->DQ, &ctx->QP ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } +#endif + + return( 0 ); +} + +/* + * Check if contexts holding a public and private key match + */ +int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, + const mbedtls_rsa_context *prv ) +{ + RSA_VALIDATE_RET( pub != NULL ); + RSA_VALIDATE_RET( prv != NULL ); + + if( mbedtls_rsa_check_pubkey( pub ) != 0 || + mbedtls_rsa_check_privkey( prv ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + if( mbedtls_mpi_cmp_mpi( &pub->N, &prv->N ) != 0 || + mbedtls_mpi_cmp_mpi( &pub->E, &prv->E ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + return( 0 ); +} + +/* + * Do an RSA public key operation + */ +int mbedtls_rsa_public( mbedtls_rsa_context *ctx, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t olen; + mbedtls_mpi T; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( input != NULL ); + RSA_VALIDATE_RET( output != NULL ); + + if( rsa_check_context( ctx, 0 /* public */, 0 /* no blinding */ ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &T ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) ); + + if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) + { + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + goto cleanup; + } + + olen = ctx->len; + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) ); + +cleanup: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + mbedtls_mpi_free( &T ); + + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_PUBLIC_FAILED + ret ); + + return( 0 ); +} + +/* + * Generate or update blinding values, see section 10 of: + * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, + * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer + * Berlin Heidelberg, 1996. p. 104-113. + */ +static int rsa_prepare_blinding( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret, count = 0; + + if( ctx->Vf.p != NULL ) + { + /* We already have blinding values, just update them by squaring */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->N ) ); + + goto cleanup; + } + + /* Unblinding value: Vf = random number, invertible mod N */ + do { + if( count++ > 10 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vf, ctx->len - 1, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &ctx->Vi, &ctx->Vf, &ctx->N ) ); + } while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 ); + + /* Blinding value: Vi = Vf^(-e) mod N */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vi, &ctx->Vf, &ctx->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vi, &ctx->Vi, &ctx->E, &ctx->N, &ctx->RN ) ); + + +cleanup: + return( ret ); +} + +/* + * Exponent blinding supposed to prevent side-channel attacks using multiple + * traces of measurements to recover the RSA key. The more collisions are there, + * the more bits of the key can be recovered. See [3]. + * + * Collecting n collisions with m bit long blinding value requires 2^(m-m/n) + * observations on avarage. + * + * For example with 28 byte blinding to achieve 2 collisions the adversary has + * to make 2^112 observations on avarage. + * + * (With the currently (as of 2017 April) known best algorithms breaking 2048 + * bit RSA requires approximately as much time as trying out 2^112 random keys. + * Thus in this sense with 28 byte blinding the security is not reduced by + * side-channel attacks like the one in [3]) + * + * This countermeasure does not help if the key recovery is possible with a + * single trace. + */ +#define RSA_EXPONENT_BLINDING 28 + +/* + * Do an RSA private key operation + */ +int mbedtls_rsa_private( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t olen; + + /* Temporary holding the result */ + mbedtls_mpi T; + + /* Temporaries holding P-1, Q-1 and the + * exponent blinding factor, respectively. */ + mbedtls_mpi P1, Q1, R; + +#if !defined(MBEDTLS_RSA_NO_CRT) + /* Temporaries holding the results mod p resp. mod q. */ + mbedtls_mpi TP, TQ; + + /* Temporaries holding the blinded exponents for + * the mod p resp. mod q computation (if used). */ + mbedtls_mpi DP_blind, DQ_blind; + + /* Pointers to actual exponents to be used - either the unblinded + * or the blinded ones, depending on the presence of a PRNG. */ + mbedtls_mpi *DP = &ctx->DP; + mbedtls_mpi *DQ = &ctx->DQ; +#else + /* Temporary holding the blinded exponent (if used). */ + mbedtls_mpi D_blind; + + /* Pointer to actual exponent to be used - either the unblinded + * or the blinded one, depending on the presence of a PRNG. */ + mbedtls_mpi *D = &ctx->D; +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* Temporaries holding the initial input and the double + * checked result; should be the same in the end. */ + mbedtls_mpi I, C; + + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( input != NULL ); + RSA_VALIDATE_RET( output != NULL ); + + if( rsa_check_context( ctx, 1 /* private key checks */, + f_rng != NULL /* blinding y/n */ ) != 0 ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + /* MPI Initialization */ + mbedtls_mpi_init( &T ); + + mbedtls_mpi_init( &P1 ); + mbedtls_mpi_init( &Q1 ); + mbedtls_mpi_init( &R ); + + if( f_rng != NULL ) + { +#if defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_init( &D_blind ); +#else + mbedtls_mpi_init( &DP_blind ); + mbedtls_mpi_init( &DQ_blind ); +#endif + } + +#if !defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_init( &TP ); mbedtls_mpi_init( &TQ ); +#endif + + mbedtls_mpi_init( &I ); + mbedtls_mpi_init( &C ); + + /* End of MPI initialization */ + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) ); + if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) + { + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &I, &T ) ); + + if( f_rng != NULL ) + { + /* + * Blinding + * T = T * Vi mod N + */ + MBEDTLS_MPI_CHK( rsa_prepare_blinding( ctx, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &T, &ctx->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) ); + + /* + * Exponent blinding + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) ); + +#if defined(MBEDTLS_RSA_NO_CRT) + /* + * D_blind = ( P - 1 ) * ( Q - 1 ) * R + D + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &R, RSA_EXPONENT_BLINDING, + f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &D_blind, &P1, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &D_blind, &D_blind, &R ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &D_blind, &D_blind, &ctx->D ) ); + + D = &D_blind; +#else + /* + * DP_blind = ( P - 1 ) * R + DP + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &R, RSA_EXPONENT_BLINDING, + f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DP_blind, &P1, &R ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &DP_blind, &DP_blind, + &ctx->DP ) ); + + DP = &DP_blind; + + /* + * DQ_blind = ( Q - 1 ) * R + DQ + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &R, RSA_EXPONENT_BLINDING, + f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DQ_blind, &Q1, &R ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &DQ_blind, &DQ_blind, + &ctx->DQ ) ); + + DQ = &DQ_blind; +#endif /* MBEDTLS_RSA_NO_CRT */ + } + +#if defined(MBEDTLS_RSA_NO_CRT) + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T, &T, D, &ctx->N, &ctx->RN ) ); +#else + /* + * Faster decryption using the CRT + * + * TP = input ^ dP mod P + * TQ = input ^ dQ mod Q + */ + + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &TP, &T, DP, &ctx->P, &ctx->RP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &TQ, &T, DQ, &ctx->Q, &ctx->RQ ) ); + + /* + * T = (TP - TQ) * (Q^-1 mod P) mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &TP, &TQ ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &TP, &T, &ctx->QP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &TP, &ctx->P ) ); + + /* + * T = TQ + T * Q + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &TP, &T, &ctx->Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T, &TQ, &TP ) ); +#endif /* MBEDTLS_RSA_NO_CRT */ + + if( f_rng != NULL ) + { + /* + * Unblind + * T = T * Vf mod N + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &T, &ctx->Vf ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) ); + } + + /* Verify the result to prevent glitching attacks. */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &C, &T, &ctx->E, + &ctx->N, &ctx->RN ) ); + if( mbedtls_mpi_cmp_mpi( &C, &I ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_VERIFY_FAILED; + goto cleanup; + } + + olen = ctx->len; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) ); + +cleanup: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + mbedtls_mpi_free( &P1 ); + mbedtls_mpi_free( &Q1 ); + mbedtls_mpi_free( &R ); + + if( f_rng != NULL ) + { +#if defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_free( &D_blind ); +#else + mbedtls_mpi_free( &DP_blind ); + mbedtls_mpi_free( &DQ_blind ); +#endif + } + + mbedtls_mpi_free( &T ); + +#if !defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_free( &TP ); mbedtls_mpi_free( &TQ ); +#endif + + mbedtls_mpi_free( &C ); + mbedtls_mpi_free( &I ); + + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_PRIVATE_FAILED + ret ); + + return( 0 ); +} + +#if defined(MBEDTLS_PKCS1_V21) +/** + * Generate and apply the MGF1 operation (from PKCS#1 v2.1) to a buffer. + * + * \param dst buffer to mask + * \param dlen length of destination buffer + * \param src source of the mask generation + * \param slen length of the source buffer + * \param md_ctx message digest context to use + */ +static int mgf_mask( unsigned char *dst, size_t dlen, unsigned char *src, + size_t slen, mbedtls_md_context_t *md_ctx ) +{ + unsigned char mask[MBEDTLS_MD_MAX_SIZE]; + unsigned char counter[4]; + unsigned char *p; + unsigned int hlen; + size_t i, use_len; + int ret = 0; + + memset( mask, 0, MBEDTLS_MD_MAX_SIZE ); + memset( counter, 0, 4 ); + + hlen = mbedtls_md_get_size( md_ctx->md_info ); + + /* Generate and apply dbMask */ + p = dst; + + while( dlen > 0 ) + { + use_len = hlen; + if( dlen < hlen ) + use_len = dlen; + + if( ( ret = mbedtls_md_starts( md_ctx ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_update( md_ctx, src, slen ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_update( md_ctx, counter, 4 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_finish( md_ctx, mask ) ) != 0 ) + goto exit; + + for( i = 0; i < use_len; ++i ) + *p++ ^= mask[i]; + + counter[3]++; + + dlen -= use_len; + } + +exit: + mbedtls_platform_zeroize( mask, sizeof( mask ) ); + + return( ret ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSAES-OAEP-ENCRYPT function + */ +int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + size_t olen; + int ret; + unsigned char *p = output; + unsigned int hlen; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( output != NULL ); + RSA_VALIDATE_RET( ilen == 0 || input != NULL ); + RSA_VALIDATE_RET( label_len == 0 || label != NULL ); + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( f_rng == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + hlen = mbedtls_md_get_size( md_info ); + + /* first comparison checks for overflow */ + if( ilen + 2 * hlen + 2 < ilen || olen < ilen + 2 * hlen + 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + memset( output, 0, olen ); + + *p++ = 0; + + /* Generate a random octet string seed */ + if( ( ret = f_rng( p_rng, p, hlen ) ) != 0 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED + ret ); + + p += hlen; + + /* Construct DB */ + if( ( ret = mbedtls_md( md_info, label, label_len, p ) ) != 0 ) + return( ret ); + p += hlen; + p += olen - 2 * hlen - 2 - ilen; + *p++ = 1; + if( ilen != 0 ) + memcpy( p, input, ilen ); + + mbedtls_md_init( &md_ctx ); + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + goto exit; + + /* maskedDB: Apply dbMask to DB */ + if( ( ret = mgf_mask( output + hlen + 1, olen - hlen - 1, output + 1, hlen, + &md_ctx ) ) != 0 ) + goto exit; + + /* maskedSeed: Apply seedMask to seed */ + if( ( ret = mgf_mask( output + 1, hlen, output + hlen + 1, olen - hlen - 1, + &md_ctx ) ) != 0 ) + goto exit; + +exit: + mbedtls_md_free( &md_ctx ); + + if( ret != 0 ) + return( ret ); + + return( ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, output, output ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, output, output ) ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function + */ +int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + size_t nb_pad, olen; + int ret; + unsigned char *p = output; + + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( output != NULL ); + RSA_VALIDATE_RET( ilen == 0 || input != NULL ); + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + + /* first comparison checks for overflow */ + if( ilen + 11 < ilen || olen < ilen + 11 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + nb_pad = olen - 3 - ilen; + + *p++ = 0; + if( mode == MBEDTLS_RSA_PUBLIC ) + { + if( f_rng == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + *p++ = MBEDTLS_RSA_CRYPT; + + while( nb_pad-- > 0 ) + { + int rng_dl = 100; + + do { + ret = f_rng( p_rng, p, 1 ); + } while( *p == 0 && --rng_dl && ret == 0 ); + + /* Check if RNG failed to generate data */ + if( rng_dl == 0 || ret != 0 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED + ret ); + + p++; + } + } + else + { + *p++ = MBEDTLS_RSA_SIGN; + + while( nb_pad-- > 0 ) + *p++ = 0xFF; + } + + *p++ = 0; + if( ilen != 0 ) + memcpy( p, input, ilen ); + + return( ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, output, output ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, output, output ) ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Add the message padding, then do an RSA operation + */ +int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( output != NULL ); + RSA_VALIDATE_RET( ilen == 0 || input != NULL ); + + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsaes_pkcs1_v15_encrypt( ctx, f_rng, p_rng, mode, ilen, + input, output ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsaes_oaep_encrypt( ctx, f_rng, p_rng, mode, NULL, 0, + ilen, input, output ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSAES-OAEP-DECRYPT function + */ +int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ) +{ + int ret; + size_t ilen, i, pad_len; + unsigned char *p, bad, pad_done; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + unsigned char lhash[MBEDTLS_MD_MAX_SIZE]; + unsigned int hlen; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( output_max_len == 0 || output != NULL ); + RSA_VALIDATE_RET( label_len == 0 || label != NULL ); + RSA_VALIDATE_RET( input != NULL ); + RSA_VALIDATE_RET( olen != NULL ); + + /* + * Parameters sanity checks + */ + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ilen = ctx->len; + + if( ilen < 16 || ilen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hlen = mbedtls_md_get_size( md_info ); + + // checking for integer underflow + if( 2 * hlen + 2 > ilen ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* + * RSA operation + */ + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, input, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, input, buf ); + + if( ret != 0 ) + goto cleanup; + + /* + * Unmask data and generate lHash + */ + mbedtls_md_init( &md_ctx ); + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + { + mbedtls_md_free( &md_ctx ); + goto cleanup; + } + + /* seed: Apply seedMask to maskedSeed */ + if( ( ret = mgf_mask( buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1, + &md_ctx ) ) != 0 || + /* DB: Apply dbMask to maskedDB */ + ( ret = mgf_mask( buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen, + &md_ctx ) ) != 0 ) + { + mbedtls_md_free( &md_ctx ); + goto cleanup; + } + + mbedtls_md_free( &md_ctx ); + + /* Generate lHash */ + if( ( ret = mbedtls_md( md_info, label, label_len, lhash ) ) != 0 ) + goto cleanup; + + /* + * Check contents, in "constant-time" + */ + p = buf; + bad = 0; + + bad |= *p++; /* First byte must be 0 */ + + p += hlen; /* Skip seed */ + + /* Check lHash */ + for( i = 0; i < hlen; i++ ) + bad |= lhash[i] ^ *p++; + + /* Get zero-padding len, but always read till end of buffer + * (minus one, for the 01 byte) */ + pad_len = 0; + pad_done = 0; + for( i = 0; i < ilen - 2 * hlen - 2; i++ ) + { + pad_done |= p[i]; + pad_len += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1; + } + + p += pad_len; + bad |= *p++ ^ 0x01; + + /* + * The only information "leaked" is whether the padding was correct or not + * (eg, no data is copied if it was not correct). This meets the + * recommendations in PKCS#1 v2.2: an opponent cannot distinguish between + * the different error conditions. + */ + if( bad != 0 ) + { + ret = MBEDTLS_ERR_RSA_INVALID_PADDING; + goto cleanup; + } + + if( ilen - ( p - buf ) > output_max_len ) + { + ret = MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE; + goto cleanup; + } + + *olen = ilen - (p - buf); + if( *olen != 0 ) + memcpy( output, p, *olen ); + ret = 0; + +cleanup: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( lhash, sizeof( lhash ) ); + + return( ret ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/** Turn zero-or-nonzero into zero-or-all-bits-one, without branches. + * + * \param value The value to analyze. + * \return Zero if \p value is zero, otherwise all-bits-one. + */ +static unsigned all_or_nothing_int( unsigned value ) +{ + /* MSVC has a warning about unary minus on unsigned, but this is + * well-defined and precisely what we want to do here */ +#if defined(_MSC_VER) +#pragma warning( push ) +#pragma warning( disable : 4146 ) +#endif + return( - ( ( value | - value ) >> ( sizeof( value ) * 8 - 1 ) ) ); +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif +} + +/** Check whether a size is out of bounds, without branches. + * + * This is equivalent to `size > max`, but is likely to be compiled to + * to code using bitwise operation rather than a branch. + * + * \param size Size to check. + * \param max Maximum desired value for \p size. + * \return \c 0 if `size <= max`. + * \return \c 1 if `size > max`. + */ +static unsigned size_greater_than( size_t size, size_t max ) +{ + /* Return the sign bit (1 for negative) of (max - size). */ + return( ( max - size ) >> ( sizeof( size_t ) * 8 - 1 ) ); +} + +/** Choose between two integer values, without branches. + * + * This is equivalent to `cond ? if1 : if0`, but is likely to be compiled + * to code using bitwise operation rather than a branch. + * + * \param cond Condition to test. + * \param if1 Value to use if \p cond is nonzero. + * \param if0 Value to use if \p cond is zero. + * \return \c if1 if \p cond is nonzero, otherwise \c if0. + */ +static unsigned if_int( unsigned cond, unsigned if1, unsigned if0 ) +{ + unsigned mask = all_or_nothing_int( cond ); + return( ( mask & if1 ) | (~mask & if0 ) ); +} + +/** Shift some data towards the left inside a buffer without leaking + * the length of the data through side channels. + * + * `mem_move_to_left(start, total, offset)` is functionally equivalent to + * ``` + * memmove(start, start + offset, total - offset); + * memset(start + offset, 0, total - offset); + * ``` + * but it strives to use a memory access pattern (and thus total timing) + * that does not depend on \p offset. This timing independence comes at + * the expense of performance. + * + * \param start Pointer to the start of the buffer. + * \param total Total size of the buffer. + * \param offset Offset from which to copy \p total - \p offset bytes. + */ +static void mem_move_to_left( void *start, + size_t total, + size_t offset ) +{ + volatile unsigned char *buf = start; + size_t i, n; + if( total == 0 ) + return; + for( i = 0; i < total; i++ ) + { + unsigned no_op = size_greater_than( total - offset, i ); + /* The first `total - offset` passes are a no-op. The last + * `offset` passes shift the data one byte to the left and + * zero out the last byte. */ + for( n = 0; n < total - 1; n++ ) + { + unsigned char current = buf[n]; + unsigned char next = buf[n+1]; + buf[n] = if_int( no_op, current, next ); + } + buf[total-1] = if_int( no_op, buf[total-1], 0 ); + } +} + +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function + */ +int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ) +{ + int ret; + size_t ilen, i, plaintext_max_size; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + /* The following variables take sensitive values: their value must + * not leak into the observable behavior of the function other than + * the designated outputs (output, olen, return value). Otherwise + * this would open the execution of the function to + * side-channel-based variants of the Bleichenbacher padding oracle + * attack. Potential side channels include overall timing, memory + * access patterns (especially visible to an adversary who has access + * to a shared memory cache), and branches (especially visible to + * an adversary who has access to a shared code cache or to a shared + * branch predictor). */ + size_t pad_count = 0; + unsigned bad = 0; + unsigned char pad_done = 0; + size_t plaintext_size = 0; + unsigned output_too_large; + + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( output_max_len == 0 || output != NULL ); + RSA_VALIDATE_RET( input != NULL ); + RSA_VALIDATE_RET( olen != NULL ); + + ilen = ctx->len; + plaintext_max_size = ( output_max_len > ilen - 11 ? + ilen - 11 : + output_max_len ); + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( ilen < 16 || ilen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, input, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, input, buf ); + + if( ret != 0 ) + goto cleanup; + + /* Check and get padding length in constant time and constant + * memory trace. The first byte must be 0. */ + bad |= buf[0]; + + if( mode == MBEDTLS_RSA_PRIVATE ) + { + /* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00 + * where PS must be at least 8 nonzero bytes. */ + bad |= buf[1] ^ MBEDTLS_RSA_CRYPT; + + /* Read the whole buffer. Set pad_done to nonzero if we find + * the 0x00 byte and remember the padding length in pad_count. */ + for( i = 2; i < ilen; i++ ) + { + pad_done |= ((buf[i] | (unsigned char)-buf[i]) >> 7) ^ 1; + pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1; + } + } + else + { + /* Decode EMSA-PKCS1-v1_5 padding: 0x00 || 0x01 || PS || 0x00 + * where PS must be at least 8 bytes with the value 0xFF. */ + bad |= buf[1] ^ MBEDTLS_RSA_SIGN; + + /* Read the whole buffer. Set pad_done to nonzero if we find + * the 0x00 byte and remember the padding length in pad_count. + * If there's a non-0xff byte in the padding, the padding is bad. */ + for( i = 2; i < ilen; i++ ) + { + pad_done |= if_int( buf[i], 0, 1 ); + pad_count += if_int( pad_done, 0, 1 ); + bad |= if_int( pad_done, 0, buf[i] ^ 0xFF ); + } + } + + /* If pad_done is still zero, there's no data, only unfinished padding. */ + bad |= if_int( pad_done, 0, 1 ); + + /* There must be at least 8 bytes of padding. */ + bad |= size_greater_than( 8, pad_count ); + + /* If the padding is valid, set plaintext_size to the number of + * remaining bytes after stripping the padding. If the padding + * is invalid, avoid leaking this fact through the size of the + * output: use the maximum message size that fits in the output + * buffer. Do it without branches to avoid leaking the padding + * validity through timing. RSA keys are small enough that all the + * size_t values involved fit in unsigned int. */ + plaintext_size = if_int( bad, + (unsigned) plaintext_max_size, + (unsigned) ( ilen - pad_count - 3 ) ); + + /* Set output_too_large to 0 if the plaintext fits in the output + * buffer and to 1 otherwise. */ + output_too_large = size_greater_than( plaintext_size, + plaintext_max_size ); + + /* Set ret without branches to avoid timing attacks. Return: + * - INVALID_PADDING if the padding is bad (bad != 0). + * - OUTPUT_TOO_LARGE if the padding is good but the decrypted + * plaintext does not fit in the output buffer. + * - 0 if the padding is correct. */ + ret = - (int) if_int( bad, - MBEDTLS_ERR_RSA_INVALID_PADDING, + if_int( output_too_large, - MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE, + 0 ) ); + + /* If the padding is bad or the plaintext is too large, zero the + * data that we're about to copy to the output buffer. + * We need to copy the same amount of data + * from the same buffer whether the padding is good or not to + * avoid leaking the padding validity through overall timing or + * through memory or cache access patterns. */ + bad = all_or_nothing_int( bad | output_too_large ); + for( i = 11; i < ilen; i++ ) + buf[i] &= ~bad; + + /* If the plaintext is too large, truncate it to the buffer size. + * Copy anyway to avoid revealing the length through timing, because + * revealing the length is as bad as revealing the padding validity + * for a Bleichenbacher attack. */ + plaintext_size = if_int( output_too_large, + (unsigned) plaintext_max_size, + (unsigned) plaintext_size ); + + /* Move the plaintext to the leftmost position where it can start in + * the working buffer, i.e. make it start plaintext_max_size from + * the end of the buffer. Do this with a memory access trace that + * does not depend on the plaintext size. After this move, the + * starting location of the plaintext is no longer sensitive + * information. */ + mem_move_to_left( buf + ilen - plaintext_max_size, + plaintext_max_size, + plaintext_max_size - plaintext_size ); + + /* Finally copy the decrypted plaintext plus trailing zeros into the output + * buffer. If output_max_len is 0, then output may be an invalid pointer + * and the result of memcpy() would be undefined; prevent undefined + * behavior making sure to depend only on output_max_len (the size of the + * user-provided output buffer), which is independent from plaintext + * length, validity of padding, success of the decryption, and other + * secrets. */ + if( output_max_len != 0 ) + memcpy( output, buf + ilen - plaintext_max_size, plaintext_max_size ); + + /* Report the amount of data we copied to the output buffer. In case + * of errors (bad padding or output too large), the value of *olen + * when this function returns is not specified. Making it equivalent + * to the good case limits the risks of leaking the padding validity. */ + *olen = plaintext_size; + +cleanup: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + + return( ret ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation, then remove the message padding + */ +int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len) +{ + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( output_max_len == 0 || output != NULL ); + RSA_VALIDATE_RET( input != NULL ); + RSA_VALIDATE_RET( olen != NULL ); + + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsaes_pkcs1_v15_decrypt( ctx, f_rng, p_rng, mode, olen, + input, output, output_max_len ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsaes_oaep_decrypt( ctx, f_rng, p_rng, mode, NULL, 0, + olen, input, output, + output_max_len ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function + */ +int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + size_t olen; + unsigned char *p = sig; + unsigned char salt[MBEDTLS_MD_MAX_SIZE]; + size_t slen, min_slen, hlen, offset = 0; + int ret; + size_t msb; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && + hashlen == 0 ) || + hash != NULL ); + RSA_VALIDATE_RET( sig != NULL ); + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( f_rng == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + + if( md_alg != MBEDTLS_MD_NONE ) + { + /* Gather length of hash to sign */ + md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hashlen = mbedtls_md_get_size( md_info ); + } + + md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hlen = mbedtls_md_get_size( md_info ); + + /* Calculate the largest possible salt length. Normally this is the hash + * length, which is the maximum length the salt can have. If there is not + * enough room, use the maximum salt length that fits. The constraint is + * that the hash length plus the salt length plus 2 bytes must be at most + * the key length. This complies with FIPS 186-4 §5.5 (e) and RFC 8017 + * (PKCS#1 v2.2) §9.1.1 step 3. */ + min_slen = hlen - 2; + if( olen < hlen + min_slen + 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + else if( olen >= hlen + hlen + 2 ) + slen = hlen; + else + slen = olen - hlen - 2; + + memset( sig, 0, olen ); + + /* Generate salt of length slen */ + if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED + ret ); + + /* Note: EMSA-PSS encoding is over the length of N - 1 bits */ + msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; + p += olen - hlen - slen - 2; + *p++ = 0x01; + memcpy( p, salt, slen ); + p += slen; + + mbedtls_md_init( &md_ctx ); + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + goto exit; + + /* Generate H = Hash( M' ) */ + if( ( ret = mbedtls_md_starts( &md_ctx ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_update( &md_ctx, p, 8 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_update( &md_ctx, hash, hashlen ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_update( &md_ctx, salt, slen ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_finish( &md_ctx, p ) ) != 0 ) + goto exit; + + /* Compensate for boundary condition when applying mask */ + if( msb % 8 == 0 ) + offset = 1; + + /* maskedDB: Apply dbMask to DB */ + if( ( ret = mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen, + &md_ctx ) ) != 0 ) + goto exit; + + msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; + sig[0] &= 0xFF >> ( olen * 8 - msb ); + + p += hlen; + *p++ = 0xBC; + + mbedtls_platform_zeroize( salt, sizeof( salt ) ); + +exit: + mbedtls_md_free( &md_ctx ); + + if( ret != 0 ) + return( ret ); + + return( ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, sig, sig ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig ) ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function + */ + +/* Construct a PKCS v1.5 encoding of a hashed message + * + * This is used both for signature generation and verification. + * + * Parameters: + * - md_alg: Identifies the hash algorithm used to generate the given hash; + * MBEDTLS_MD_NONE if raw data is signed. + * - hashlen: Length of hash in case hashlen is MBEDTLS_MD_NONE. + * - hash: Buffer containing the hashed message or the raw data. + * - dst_len: Length of the encoded message. + * - dst: Buffer to hold the encoded message. + * + * Assumptions: + * - hash has size hashlen if md_alg == MBEDTLS_MD_NONE. + * - hash has size corresponding to md_alg if md_alg != MBEDTLS_MD_NONE. + * - dst points to a buffer of size at least dst_len. + * + */ +static int rsa_rsassa_pkcs1_v15_encode( mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + size_t dst_len, + unsigned char *dst ) +{ + size_t oid_size = 0; + size_t nb_pad = dst_len; + unsigned char *p = dst; + const char *oid = NULL; + + /* Are we signing hashed or raw data? */ + if( md_alg != MBEDTLS_MD_NONE ) + { + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hashlen = mbedtls_md_get_size( md_info ); + + /* Double-check that 8 + hashlen + oid_size can be used as a + * 1-byte ASN.1 length encoding and that there's no overflow. */ + if( 8 + hashlen + oid_size >= 0x80 || + 10 + hashlen < hashlen || + 10 + hashlen + oid_size < 10 + hashlen ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* + * Static bounds check: + * - Need 10 bytes for five tag-length pairs. + * (Insist on 1-byte length encodings to protect against variants of + * Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification) + * - Need hashlen bytes for hash + * - Need oid_size bytes for hash alg OID. + */ + if( nb_pad < 10 + hashlen + oid_size ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + nb_pad -= 10 + hashlen + oid_size; + } + else + { + if( nb_pad < hashlen ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + nb_pad -= hashlen; + } + + /* Need space for signature header and padding delimiter (3 bytes), + * and 8 bytes for the minimal padding */ + if( nb_pad < 3 + 8 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + nb_pad -= 3; + + /* Now nb_pad is the amount of memory to be filled + * with padding, and at least 8 bytes long. */ + + /* Write signature header and padding */ + *p++ = 0; + *p++ = MBEDTLS_RSA_SIGN; + memset( p, 0xFF, nb_pad ); + p += nb_pad; + *p++ = 0; + + /* Are we signing raw data? */ + if( md_alg == MBEDTLS_MD_NONE ) + { + memcpy( p, hash, hashlen ); + return( 0 ); + } + + /* Signing hashed data, add corresponding ASN.1 structure + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * Digest ::= OCTET STRING + * + * Schematic: + * TAG-SEQ + LEN [ TAG-SEQ + LEN [ TAG-OID + LEN [ OID ] + * TAG-NULL + LEN [ NULL ] ] + * TAG-OCTET + LEN [ HASH ] ] + */ + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char)( 0x08 + oid_size + hashlen ); + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char)( 0x04 + oid_size ); + *p++ = MBEDTLS_ASN1_OID; + *p++ = (unsigned char) oid_size; + memcpy( p, oid, oid_size ); + p += oid_size; + *p++ = MBEDTLS_ASN1_NULL; + *p++ = 0x00; + *p++ = MBEDTLS_ASN1_OCTET_STRING; + *p++ = (unsigned char) hashlen; + memcpy( p, hash, hashlen ); + p += hashlen; + + /* Just a sanity-check, should be automatic + * after the initial bounds check. */ + if( p != dst + dst_len ) + { + mbedtls_platform_zeroize( dst, dst_len ); + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + return( 0 ); +} + +/* + * Do an RSA operation to sign the message digest + */ +int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + int ret; + unsigned char *sig_try = NULL, *verif = NULL; + + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && + hashlen == 0 ) || + hash != NULL ); + RSA_VALIDATE_RET( sig != NULL ); + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* + * Prepare PKCS1-v1.5 encoding (padding and hash identifier) + */ + + if( ( ret = rsa_rsassa_pkcs1_v15_encode( md_alg, hashlen, hash, + ctx->len, sig ) ) != 0 ) + return( ret ); + + /* + * Call respective RSA primitive + */ + + if( mode == MBEDTLS_RSA_PUBLIC ) + { + /* Skip verification on a public key operation */ + return( mbedtls_rsa_public( ctx, sig, sig ) ); + } + + /* Private key operation + * + * In order to prevent Lenstra's attack, make the signature in a + * temporary buffer and check it before returning it. + */ + + sig_try = mbedtls_calloc( 1, ctx->len ); + if( sig_try == NULL ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + verif = mbedtls_calloc( 1, ctx->len ); + if( verif == NULL ) + { + mbedtls_free( sig_try ); + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + } + + MBEDTLS_MPI_CHK( mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig_try ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_public( ctx, sig_try, verif ) ); + + if( mbedtls_safer_memcmp( verif, sig, ctx->len ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_PRIVATE_FAILED; + goto cleanup; + } + + memcpy( sig, sig_try, ctx->len ); + +cleanup: + mbedtls_free( sig_try ); + mbedtls_free( verif ); + + return( ret ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation to sign the message digest + */ +int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && + hashlen == 0 ) || + hash != NULL ); + RSA_VALIDATE_RET( sig != NULL ); + + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsassa_pkcs1_v15_sign( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsassa_pss_sign( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function + */ +int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + mbedtls_md_type_t mgf1_hash_id, + int expected_salt_len, + const unsigned char *sig ) +{ + int ret; + size_t siglen; + unsigned char *p; + unsigned char *hash_start; + unsigned char result[MBEDTLS_MD_MAX_SIZE]; + unsigned char zeros[8]; + unsigned int hlen; + size_t observed_salt_len, msb; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( sig != NULL ); + RSA_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && + hashlen == 0 ) || + hash != NULL ); + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + siglen = ctx->len; + + if( siglen < 16 || siglen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, sig, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + + if( buf[siglen - 1] != 0xBC ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + + if( md_alg != MBEDTLS_MD_NONE ) + { + /* Gather length of hash to sign */ + md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hashlen = mbedtls_md_get_size( md_info ); + } + + md_info = mbedtls_md_info_from_type( mgf1_hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hlen = mbedtls_md_get_size( md_info ); + + memset( zeros, 0, 8 ); + + /* + * Note: EMSA-PSS verification is over the length of N - 1 bits + */ + msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; + + if( buf[0] >> ( 8 - siglen * 8 + msb ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* Compensate for boundary condition when applying mask */ + if( msb % 8 == 0 ) + { + p++; + siglen -= 1; + } + + if( siglen < hlen + 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + hash_start = p + siglen - hlen - 1; + + mbedtls_md_init( &md_ctx ); + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + goto exit; + + ret = mgf_mask( p, siglen - hlen - 1, hash_start, hlen, &md_ctx ); + if( ret != 0 ) + goto exit; + + buf[0] &= 0xFF >> ( siglen * 8 - msb ); + + while( p < hash_start - 1 && *p == 0 ) + p++; + + if( *p++ != 0x01 ) + { + ret = MBEDTLS_ERR_RSA_INVALID_PADDING; + goto exit; + } + + observed_salt_len = hash_start - p; + + if( expected_salt_len != MBEDTLS_RSA_SALT_LEN_ANY && + observed_salt_len != (size_t) expected_salt_len ) + { + ret = MBEDTLS_ERR_RSA_INVALID_PADDING; + goto exit; + } + + /* + * Generate H = Hash( M' ) + */ + ret = mbedtls_md_starts( &md_ctx ); + if ( ret != 0 ) + goto exit; + ret = mbedtls_md_update( &md_ctx, zeros, 8 ); + if ( ret != 0 ) + goto exit; + ret = mbedtls_md_update( &md_ctx, hash, hashlen ); + if ( ret != 0 ) + goto exit; + ret = mbedtls_md_update( &md_ctx, p, observed_salt_len ); + if ( ret != 0 ) + goto exit; + ret = mbedtls_md_finish( &md_ctx, result ); + if ( ret != 0 ) + goto exit; + + if( memcmp( hash_start, result, hlen ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_VERIFY_FAILED; + goto exit; + } + +exit: + mbedtls_md_free( &md_ctx ); + + return( ret ); +} + +/* + * Simplified PKCS#1 v2.1 RSASSA-PSS-VERIFY function + */ +int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ) +{ + mbedtls_md_type_t mgf1_hash_id; + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( sig != NULL ); + RSA_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && + hashlen == 0 ) || + hash != NULL ); + + mgf1_hash_id = ( ctx->hash_id != MBEDTLS_MD_NONE ) + ? (mbedtls_md_type_t) ctx->hash_id + : md_alg; + + return( mbedtls_rsa_rsassa_pss_verify_ext( ctx, f_rng, p_rng, mode, + md_alg, hashlen, hash, + mgf1_hash_id, MBEDTLS_RSA_SALT_LEN_ANY, + sig ) ); + +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function + */ +int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ) +{ + int ret = 0; + size_t sig_len; + unsigned char *encoded = NULL, *encoded_expected = NULL; + + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( sig != NULL ); + RSA_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && + hashlen == 0 ) || + hash != NULL ); + + sig_len = ctx->len; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* + * Prepare expected PKCS1 v1.5 encoding of hash. + */ + + if( ( encoded = mbedtls_calloc( 1, sig_len ) ) == NULL || + ( encoded_expected = mbedtls_calloc( 1, sig_len ) ) == NULL ) + { + ret = MBEDTLS_ERR_MPI_ALLOC_FAILED; + goto cleanup; + } + + if( ( ret = rsa_rsassa_pkcs1_v15_encode( md_alg, hashlen, hash, sig_len, + encoded_expected ) ) != 0 ) + goto cleanup; + + /* + * Apply RSA primitive to get what should be PKCS1 encoded hash. + */ + + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, sig, encoded ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, encoded ); + if( ret != 0 ) + goto cleanup; + + /* + * Compare + */ + + if( ( ret = mbedtls_safer_memcmp( encoded, encoded_expected, + sig_len ) ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_VERIFY_FAILED; + goto cleanup; + } + +cleanup: + + if( encoded != NULL ) + { + mbedtls_platform_zeroize( encoded, sig_len ); + mbedtls_free( encoded ); + } + + if( encoded_expected != NULL ) + { + mbedtls_platform_zeroize( encoded_expected, sig_len ); + mbedtls_free( encoded_expected ); + } + + return( ret ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation and check the message digest + */ +int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ) +{ + RSA_VALIDATE_RET( ctx != NULL ); + RSA_VALIDATE_RET( mode == MBEDTLS_RSA_PRIVATE || + mode == MBEDTLS_RSA_PUBLIC ); + RSA_VALIDATE_RET( sig != NULL ); + RSA_VALIDATE_RET( ( md_alg == MBEDTLS_MD_NONE && + hashlen == 0 ) || + hash != NULL ); + + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsassa_pkcs1_v15_verify( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsassa_pss_verify( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +/* + * Copy the components of an RSA key + */ +int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src ) +{ + int ret; + RSA_VALIDATE_RET( dst != NULL ); + RSA_VALIDATE_RET( src != NULL ); + + dst->ver = src->ver; + dst->len = src->len; + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->N, &src->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->E, &src->E ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->D, &src->D ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->P, &src->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Q, &src->Q ) ); + +#if !defined(MBEDTLS_RSA_NO_CRT) + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->DP, &src->DP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->DQ, &src->DQ ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->QP, &src->QP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RP, &src->RP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RQ, &src->RQ ) ); +#endif + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RN, &src->RN ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Vi, &src->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Vf, &src->Vf ) ); + + dst->padding = src->padding; + dst->hash_id = src->hash_id; + +cleanup: + if( ret != 0 ) + mbedtls_rsa_free( dst ); + + return( ret ); +} + +/* + * Free the components of an RSA key + */ +void mbedtls_rsa_free( mbedtls_rsa_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_mpi_free( &ctx->Vi ); + mbedtls_mpi_free( &ctx->Vf ); + mbedtls_mpi_free( &ctx->RN ); + mbedtls_mpi_free( &ctx->D ); + mbedtls_mpi_free( &ctx->Q ); + mbedtls_mpi_free( &ctx->P ); + mbedtls_mpi_free( &ctx->E ); + mbedtls_mpi_free( &ctx->N ); + +#if !defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_free( &ctx->RQ ); + mbedtls_mpi_free( &ctx->RP ); + mbedtls_mpi_free( &ctx->QP ); + mbedtls_mpi_free( &ctx->DQ ); + mbedtls_mpi_free( &ctx->DP ); +#endif /* MBEDTLS_RSA_NO_CRT */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif +} + +#endif /* !MBEDTLS_RSA_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +#include "mbedtls/sha1.h" + +/* + * Example RSA-1024 keypair, for test purposes + */ +#define KEY_LEN 128 + +#define RSA_N "9292758453063D803DD603D5E777D788" \ + "8ED1D5BF35786190FA2F23EBC0848AEA" \ + "DDA92CA6C3D80B32C4D109BE0F36D6AE" \ + "7130B9CED7ACDF54CFC7555AC14EEBAB" \ + "93A89813FBF3C4F8066D2D800F7C38A8" \ + "1AE31942917403FF4946B0A83D3D3E05" \ + "EE57C6F5F5606FB5D4BC6CD34EE0801A" \ + "5E94BB77B07507233A0BC7BAC8F90F79" + +#define RSA_E "10001" + +#define RSA_D "24BF6185468786FDD303083D25E64EFC" \ + "66CA472BC44D253102F8B4A9D3BFA750" \ + "91386C0077937FE33FA3252D28855837" \ + "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ + "DF79C5CE07EE72C7F123142198164234" \ + "CABB724CF78B8173B9F880FC86322407" \ + "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ + "071513A1E85B5DFA031F21ECAE91A34D" + +#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ + "2C01CAD19EA484A87EA4377637E75500" \ + "FCB2005C5C7DD6EC4AC023CDA285D796" \ + "C3D9E75E1EFC42488BB4F1D13AC30A57" + +#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \ + "E211C2B9E5DB1ED0BF61D0D9899620F4" \ + "910E4168387E3C30AA1E00C339A79508" \ + "8452DD96A9A5EA5D9DCA68DA636032AF" + +#define PT_LEN 24 +#define RSA_PT "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \ + "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD" + +#if defined(MBEDTLS_PKCS1_V15) +static int myrand( void *rng_state, unsigned char *output, size_t len ) +{ +#if !defined(__OpenBSD__) + size_t i; + + if( rng_state != NULL ) + rng_state = NULL; + + for( i = 0; i < len; ++i ) + output[i] = rand(); +#else + if( rng_state != NULL ) + rng_state = NULL; + + arc4random_buf( output, len ); +#endif /* !OpenBSD */ + + return( 0 ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Checkup routine + */ +int mbedtls_rsa_self_test( int verbose ) +{ + int ret = 0; +#if defined(MBEDTLS_PKCS1_V15) + size_t len; + mbedtls_rsa_context rsa; + unsigned char rsa_plaintext[PT_LEN]; + unsigned char rsa_decrypted[PT_LEN]; + unsigned char rsa_ciphertext[KEY_LEN]; +#if defined(MBEDTLS_SHA1_C) + unsigned char sha1sum[20]; +#endif + + mbedtls_mpi K; + + mbedtls_mpi_init( &K ); + mbedtls_rsa_init( &rsa, MBEDTLS_RSA_PKCS_V15, 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &K, 16, RSA_N ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_import( &rsa, &K, NULL, NULL, NULL, NULL ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &K, 16, RSA_P ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_import( &rsa, NULL, &K, NULL, NULL, NULL ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &K, 16, RSA_Q ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_import( &rsa, NULL, NULL, &K, NULL, NULL ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &K, 16, RSA_D ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_import( &rsa, NULL, NULL, NULL, &K, NULL ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &K, 16, RSA_E ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_import( &rsa, NULL, NULL, NULL, NULL, &K ) ); + + MBEDTLS_MPI_CHK( mbedtls_rsa_complete( &rsa ) ); + + if( verbose != 0 ) + mbedtls_printf( " RSA key validation: " ); + + if( mbedtls_rsa_check_pubkey( &rsa ) != 0 || + mbedtls_rsa_check_privkey( &rsa ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n PKCS#1 encryption : " ); + + memcpy( rsa_plaintext, RSA_PT, PT_LEN ); + + if( mbedtls_rsa_pkcs1_encrypt( &rsa, myrand, NULL, MBEDTLS_RSA_PUBLIC, + PT_LEN, rsa_plaintext, + rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n PKCS#1 decryption : " ); + + if( mbedtls_rsa_pkcs1_decrypt( &rsa, myrand, NULL, MBEDTLS_RSA_PRIVATE, + &len, rsa_ciphertext, rsa_decrypted, + sizeof(rsa_decrypted) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +#if defined(MBEDTLS_SHA1_C) + if( verbose != 0 ) + mbedtls_printf( " PKCS#1 data sign : " ); + + if( mbedtls_sha1_ret( rsa_plaintext, PT_LEN, sha1sum ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( mbedtls_rsa_pkcs1_sign( &rsa, myrand, NULL, + MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 0, + sha1sum, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n PKCS#1 sig. verify: " ); + + if( mbedtls_rsa_pkcs1_verify( &rsa, NULL, NULL, + MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 0, + sha1sum, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); +#endif /* MBEDTLS_SHA1_C */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +cleanup: + mbedtls_mpi_free( &K ); + mbedtls_rsa_free( &rsa ); +#else /* MBEDTLS_PKCS1_V15 */ + ((void) verbose); +#endif /* MBEDTLS_PKCS1_V15 */ + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_RSA_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/rsa_internal.c b/FreeRTOS-Labs/Source/mbedtls/library/rsa_internal.c new file mode 100644 index 000000000..1e5e55f15 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/rsa_internal.c @@ -0,0 +1,492 @@ +/* + * Helper functions for the RSA module + * + * Copyright (C) 2006-2017, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_RSA_C) + +#include "mbedtls/rsa.h" +#include "mbedtls/bignum.h" +#include "mbedtls/rsa_internal.h" + +/* + * Compute RSA prime factors from public and private exponents + * + * Summary of algorithm: + * Setting F := lcm(P-1,Q-1), the idea is as follows: + * + * (a) For any 1 <= X < N with gcd(X,N)=1, we have X^F = 1 modulo N, so X^(F/2) + * is a square root of 1 in Z/NZ. Since Z/NZ ~= Z/PZ x Z/QZ by CRT and the + * square roots of 1 in Z/PZ and Z/QZ are +1 and -1, this leaves the four + * possibilities X^(F/2) = (+-1, +-1). If it happens that X^(F/2) = (-1,+1) + * or (+1,-1), then gcd(X^(F/2) + 1, N) will be equal to one of the prime + * factors of N. + * + * (b) If we don't know F/2 but (F/2) * K for some odd (!) K, then the same + * construction still applies since (-)^K is the identity on the set of + * roots of 1 in Z/NZ. + * + * The public and private key primitives (-)^E and (-)^D are mutually inverse + * bijections on Z/NZ if and only if (-)^(DE) is the identity on Z/NZ, i.e. + * if and only if DE - 1 is a multiple of F, say DE - 1 = F * L. + * Splitting L = 2^t * K with K odd, we have + * + * DE - 1 = FL = (F/2) * (2^(t+1)) * K, + * + * so (F / 2) * K is among the numbers + * + * (DE - 1) >> 1, (DE - 1) >> 2, ..., (DE - 1) >> ord + * + * where ord is the order of 2 in (DE - 1). + * We can therefore iterate through these numbers apply the construction + * of (a) and (b) above to attempt to factor N. + * + */ +int mbedtls_rsa_deduce_primes( mbedtls_mpi const *N, + mbedtls_mpi const *E, mbedtls_mpi const *D, + mbedtls_mpi *P, mbedtls_mpi *Q ) +{ + int ret = 0; + + uint16_t attempt; /* Number of current attempt */ + uint16_t iter; /* Number of squares computed in the current attempt */ + + uint16_t order; /* Order of 2 in DE - 1 */ + + mbedtls_mpi T; /* Holds largest odd divisor of DE - 1 */ + mbedtls_mpi K; /* Temporary holding the current candidate */ + + const unsigned char primes[] = { 2, + 3, 5, 7, 11, 13, 17, 19, 23, + 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251 + }; + + const size_t num_primes = sizeof( primes ) / sizeof( *primes ); + + if( P == NULL || Q == NULL || P->p != NULL || Q->p != NULL ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 || + mbedtls_mpi_cmp_int( D, 1 ) <= 0 || + mbedtls_mpi_cmp_mpi( D, N ) >= 0 || + mbedtls_mpi_cmp_int( E, 1 ) <= 0 || + mbedtls_mpi_cmp_mpi( E, N ) >= 0 ) + { + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + } + + /* + * Initializations and temporary changes + */ + + mbedtls_mpi_init( &K ); + mbedtls_mpi_init( &T ); + + /* T := DE - 1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, D, E ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &T, &T, 1 ) ); + + if( ( order = (uint16_t) mbedtls_mpi_lsb( &T ) ) == 0 ) + { + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + goto cleanup; + } + + /* After this operation, T holds the largest odd divisor of DE - 1. */ + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &T, order ) ); + + /* + * Actual work + */ + + /* Skip trying 2 if N == 1 mod 8 */ + attempt = 0; + if( N->p[0] % 8 == 1 ) + attempt = 1; + + for( ; attempt < num_primes; ++attempt ) + { + mbedtls_mpi_lset( &K, primes[attempt] ); + + /* Check if gcd(K,N) = 1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( P, &K, N ) ); + if( mbedtls_mpi_cmp_int( P, 1 ) != 0 ) + continue; + + /* Go through K^T + 1, K^(2T) + 1, K^(4T) + 1, ... + * and check whether they have nontrivial GCD with N. */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &K, &K, &T, N, + Q /* temporarily use Q for storing Montgomery + * multiplication helper values */ ) ); + + for( iter = 1; iter <= order; ++iter ) + { + /* If we reach 1 prematurely, there's no point + * in continuing to square K */ + if( mbedtls_mpi_cmp_int( &K, 1 ) == 0 ) + break; + + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &K, &K, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( P, &K, N ) ); + + if( mbedtls_mpi_cmp_int( P, 1 ) == 1 && + mbedtls_mpi_cmp_mpi( P, N ) == -1 ) + { + /* + * Have found a nontrivial divisor P of N. + * Set Q := N / P. + */ + + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( Q, NULL, N, P ) ); + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, &K, &K ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, N ) ); + } + + /* + * If we get here, then either we prematurely aborted the loop because + * we reached 1, or K holds primes[attempt]^(DE - 1) mod N, which must + * be 1 if D,E,N were consistent. + * Check if that's the case and abort if not, to avoid very long, + * yet eventually failing, computations if N,D,E were not sane. + */ + if( mbedtls_mpi_cmp_int( &K, 1 ) != 0 ) + { + break; + } + } + + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + +cleanup: + + mbedtls_mpi_free( &K ); + mbedtls_mpi_free( &T ); + return( ret ); +} + +/* + * Given P, Q and the public exponent E, deduce D. + * This is essentially a modular inversion. + */ +int mbedtls_rsa_deduce_private_exponent( mbedtls_mpi const *P, + mbedtls_mpi const *Q, + mbedtls_mpi const *E, + mbedtls_mpi *D ) +{ + int ret = 0; + mbedtls_mpi K, L; + + if( D == NULL || mbedtls_mpi_cmp_int( D, 0 ) != 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + if( mbedtls_mpi_cmp_int( P, 1 ) <= 0 || + mbedtls_mpi_cmp_int( Q, 1 ) <= 0 || + mbedtls_mpi_cmp_int( E, 0 ) == 0 ) + { + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + } + + mbedtls_mpi_init( &K ); + mbedtls_mpi_init( &L ); + + /* Temporarily put K := P-1 and L := Q-1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &L, Q, 1 ) ); + + /* Temporarily put D := gcd(P-1, Q-1) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( D, &K, &L ) ); + + /* K := LCM(P-1, Q-1) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, &K, &L ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &K, NULL, &K, D ) ); + + /* Compute modular inverse of E in LCM(P-1, Q-1) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( D, E, &K ) ); + +cleanup: + + mbedtls_mpi_free( &K ); + mbedtls_mpi_free( &L ); + + return( ret ); +} + +/* + * Check that RSA CRT parameters are in accordance with core parameters. + */ +int mbedtls_rsa_validate_crt( const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, const mbedtls_mpi *DP, + const mbedtls_mpi *DQ, const mbedtls_mpi *QP ) +{ + int ret = 0; + + mbedtls_mpi K, L; + mbedtls_mpi_init( &K ); + mbedtls_mpi_init( &L ); + + /* Check that DP - D == 0 mod P - 1 */ + if( DP != NULL ) + { + if( P == NULL ) + { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &L, DP, D ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &L, &L, &K ) ); + + if( mbedtls_mpi_cmp_int( &L, 0 ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + + /* Check that DQ - D == 0 mod Q - 1 */ + if( DQ != NULL ) + { + if( Q == NULL ) + { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &L, DQ, D ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &L, &L, &K ) ); + + if( mbedtls_mpi_cmp_int( &L, 0 ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + + /* Check that QP * Q - 1 == 0 mod P */ + if( QP != NULL ) + { + if( P == NULL || Q == NULL ) + { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, QP, Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, P ) ); + if( mbedtls_mpi_cmp_int( &K, 0 ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + +cleanup: + + /* Wrap MPI error codes by RSA check failure error code */ + if( ret != 0 && + ret != MBEDTLS_ERR_RSA_KEY_CHECK_FAILED && + ret != MBEDTLS_ERR_RSA_BAD_INPUT_DATA ) + { + ret += MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + + mbedtls_mpi_free( &K ); + mbedtls_mpi_free( &L ); + + return( ret ); +} + +/* + * Check that core RSA parameters are sane. + */ +int mbedtls_rsa_validate_params( const mbedtls_mpi *N, const mbedtls_mpi *P, + const mbedtls_mpi *Q, const mbedtls_mpi *D, + const mbedtls_mpi *E, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret = 0; + mbedtls_mpi K, L; + + mbedtls_mpi_init( &K ); + mbedtls_mpi_init( &L ); + + /* + * Step 1: If PRNG provided, check that P and Q are prime + */ + +#if defined(MBEDTLS_GENPRIME) + /* + * When generating keys, the strongest security we support aims for an error + * rate of at most 2^-100 and we are aiming for the same certainty here as + * well. + */ + if( f_rng != NULL && P != NULL && + ( ret = mbedtls_mpi_is_prime_ext( P, 50, f_rng, p_rng ) ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + + if( f_rng != NULL && Q != NULL && + ( ret = mbedtls_mpi_is_prime_ext( Q, 50, f_rng, p_rng ) ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } +#else + ((void) f_rng); + ((void) p_rng); +#endif /* MBEDTLS_GENPRIME */ + + /* + * Step 2: Check that 1 < N = P * Q + */ + + if( P != NULL && Q != NULL && N != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, P, Q ) ); + if( mbedtls_mpi_cmp_int( N, 1 ) <= 0 || + mbedtls_mpi_cmp_mpi( &K, N ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + + /* + * Step 3: Check and 1 < D, E < N if present. + */ + + if( N != NULL && D != NULL && E != NULL ) + { + if ( mbedtls_mpi_cmp_int( D, 1 ) <= 0 || + mbedtls_mpi_cmp_int( E, 1 ) <= 0 || + mbedtls_mpi_cmp_mpi( D, N ) >= 0 || + mbedtls_mpi_cmp_mpi( E, N ) >= 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + + /* + * Step 4: Check that D, E are inverse modulo P-1 and Q-1 + */ + + if( P != NULL && Q != NULL && D != NULL && E != NULL ) + { + if( mbedtls_mpi_cmp_int( P, 1 ) <= 0 || + mbedtls_mpi_cmp_int( Q, 1 ) <= 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + + /* Compute DE-1 mod P-1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, D, E ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &L, P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, &L ) ); + if( mbedtls_mpi_cmp_int( &K, 0 ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + + /* Compute DE-1 mod Q-1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, D, E ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &L, Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, &L ) ); + if( mbedtls_mpi_cmp_int( &K, 0 ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + +cleanup: + + mbedtls_mpi_free( &K ); + mbedtls_mpi_free( &L ); + + /* Wrap MPI error codes by RSA check failure error code */ + if( ret != 0 && ret != MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ) + { + ret += MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + + return( ret ); +} + +int mbedtls_rsa_deduce_crt( const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, mbedtls_mpi *DP, + mbedtls_mpi *DQ, mbedtls_mpi *QP ) +{ + int ret = 0; + mbedtls_mpi K; + mbedtls_mpi_init( &K ); + + /* DP = D mod P-1 */ + if( DP != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( DP, D, &K ) ); + } + + /* DQ = D mod Q-1 */ + if( DQ != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( DQ, D, &K ) ); + } + + /* QP = Q^{-1} mod P */ + if( QP != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( QP, Q, P ) ); + } + +cleanup: + mbedtls_mpi_free( &K ); + + return( ret ); +} + +#endif /* MBEDTLS_RSA_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/sha1.c b/FreeRTOS-Labs/Source/mbedtls/library/sha1.c new file mode 100644 index 000000000..dc290c7d3 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/sha1.c @@ -0,0 +1,573 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SHA-1 standard was published by NIST in 1993. + * + * http://www.itl.nist.gov/fipspubs/fip180-1.htm + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA1_C) + +#include "mbedtls/sha1.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#define SHA1_VALIDATE_RET(cond) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA1_BAD_INPUT_DATA ) + +#define SHA1_VALIDATE(cond) MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if !defined(MBEDTLS_SHA1_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ) +{ + SHA1_VALIDATE( ctx != NULL ); + + memset( ctx, 0, sizeof( mbedtls_sha1_context ) ); +} + +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha1_context ) ); +} + +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ) +{ + SHA1_VALIDATE( dst != NULL ); + SHA1_VALIDATE( src != NULL ); + + *dst = *src; +} + +/* + * SHA-1 context setup + */ +int mbedtls_sha1_starts_ret( mbedtls_sha1_context *ctx ) +{ + SHA1_VALIDATE_RET( ctx != NULL ); + + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ) +{ + mbedtls_sha1_starts_ret( ctx ); +} +#endif + +#if !defined(MBEDTLS_SHA1_PROCESS_ALT) +int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx, + const unsigned char data[64] ) +{ + uint32_t temp, W[16], A, B, C, D, E; + + SHA1_VALIDATE_RET( ctx != NULL ); + SHA1_VALIDATE_RET( (const unsigned char *)data != NULL ); + + GET_UINT32_BE( W[ 0], data, 0 ); + GET_UINT32_BE( W[ 1], data, 4 ); + GET_UINT32_BE( W[ 2], data, 8 ); + GET_UINT32_BE( W[ 3], data, 12 ); + GET_UINT32_BE( W[ 4], data, 16 ); + GET_UINT32_BE( W[ 5], data, 20 ); + GET_UINT32_BE( W[ 6], data, 24 ); + GET_UINT32_BE( W[ 7], data, 28 ); + GET_UINT32_BE( W[ 8], data, 32 ); + GET_UINT32_BE( W[ 9], data, 36 ); + GET_UINT32_BE( W[10], data, 40 ); + GET_UINT32_BE( W[11], data, 44 ); + GET_UINT32_BE( W[12], data, 48 ); + GET_UINT32_BE( W[13], data, 52 ); + GET_UINT32_BE( W[14], data, 56 ); + GET_UINT32_BE( W[15], data, 60 ); + +#define S(x,n) (((x) << (n)) | (((x) & 0xFFFFFFFF) >> (32 - (n)))) + +#define R(t) \ + ( \ + temp = W[( (t) - 3 ) & 0x0F] ^ W[( (t) - 8 ) & 0x0F] ^ \ + W[( (t) - 14 ) & 0x0F] ^ W[ (t) & 0x0F], \ + ( W[(t) & 0x0F] = S(temp,1) ) \ + ) + +#define P(a,b,c,d,e,x) \ + do \ + { \ + (e) += S((a),5) + F((b),(c),(d)) + K + (x); \ + (b) = S((b),30); \ + } while( 0 ) + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define F(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define K 0x5A827999 + + P( A, B, C, D, E, W[0] ); + P( E, A, B, C, D, W[1] ); + P( D, E, A, B, C, W[2] ); + P( C, D, E, A, B, W[3] ); + P( B, C, D, E, A, W[4] ); + P( A, B, C, D, E, W[5] ); + P( E, A, B, C, D, W[6] ); + P( D, E, A, B, C, W[7] ); + P( C, D, E, A, B, W[8] ); + P( B, C, D, E, A, W[9] ); + P( A, B, C, D, E, W[10] ); + P( E, A, B, C, D, W[11] ); + P( D, E, A, B, C, W[12] ); + P( C, D, E, A, B, W[13] ); + P( B, C, D, E, A, W[14] ); + P( A, B, C, D, E, W[15] ); + P( E, A, B, C, D, R(16) ); + P( D, E, A, B, C, R(17) ); + P( C, D, E, A, B, R(18) ); + P( B, C, D, E, A, R(19) ); + +#undef K +#undef F + +#define F(x,y,z) ((x) ^ (y) ^ (z)) +#define K 0x6ED9EBA1 + + P( A, B, C, D, E, R(20) ); + P( E, A, B, C, D, R(21) ); + P( D, E, A, B, C, R(22) ); + P( C, D, E, A, B, R(23) ); + P( B, C, D, E, A, R(24) ); + P( A, B, C, D, E, R(25) ); + P( E, A, B, C, D, R(26) ); + P( D, E, A, B, C, R(27) ); + P( C, D, E, A, B, R(28) ); + P( B, C, D, E, A, R(29) ); + P( A, B, C, D, E, R(30) ); + P( E, A, B, C, D, R(31) ); + P( D, E, A, B, C, R(32) ); + P( C, D, E, A, B, R(33) ); + P( B, C, D, E, A, R(34) ); + P( A, B, C, D, E, R(35) ); + P( E, A, B, C, D, R(36) ); + P( D, E, A, B, C, R(37) ); + P( C, D, E, A, B, R(38) ); + P( B, C, D, E, A, R(39) ); + +#undef K +#undef F + +#define F(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define K 0x8F1BBCDC + + P( A, B, C, D, E, R(40) ); + P( E, A, B, C, D, R(41) ); + P( D, E, A, B, C, R(42) ); + P( C, D, E, A, B, R(43) ); + P( B, C, D, E, A, R(44) ); + P( A, B, C, D, E, R(45) ); + P( E, A, B, C, D, R(46) ); + P( D, E, A, B, C, R(47) ); + P( C, D, E, A, B, R(48) ); + P( B, C, D, E, A, R(49) ); + P( A, B, C, D, E, R(50) ); + P( E, A, B, C, D, R(51) ); + P( D, E, A, B, C, R(52) ); + P( C, D, E, A, B, R(53) ); + P( B, C, D, E, A, R(54) ); + P( A, B, C, D, E, R(55) ); + P( E, A, B, C, D, R(56) ); + P( D, E, A, B, C, R(57) ); + P( C, D, E, A, B, R(58) ); + P( B, C, D, E, A, R(59) ); + +#undef K +#undef F + +#define F(x,y,z) ((x) ^ (y) ^ (z)) +#define K 0xCA62C1D6 + + P( A, B, C, D, E, R(60) ); + P( E, A, B, C, D, R(61) ); + P( D, E, A, B, C, R(62) ); + P( C, D, E, A, B, R(63) ); + P( B, C, D, E, A, R(64) ); + P( A, B, C, D, E, R(65) ); + P( E, A, B, C, D, R(66) ); + P( D, E, A, B, C, R(67) ); + P( C, D, E, A, B, R(68) ); + P( B, C, D, E, A, R(69) ); + P( A, B, C, D, E, R(70) ); + P( E, A, B, C, D, R(71) ); + P( D, E, A, B, C, R(72) ); + P( C, D, E, A, B, R(73) ); + P( B, C, D, E, A, R(74) ); + P( A, B, C, D, E, R(75) ); + P( E, A, B, C, D, R(76) ); + P( D, E, A, B, C, R(77) ); + P( C, D, E, A, B, R(78) ); + P( B, C, D, E, A, R(79) ); + +#undef K +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha1_process( mbedtls_sha1_context *ctx, + const unsigned char data[64] ) +{ + mbedtls_internal_sha1_process( ctx, data ); +} +#endif +#endif /* !MBEDTLS_SHA1_PROCESS_ALT */ + +/* + * SHA-1 process buffer + */ +int mbedtls_sha1_update_ret( mbedtls_sha1_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + int ret; + size_t fill; + uint32_t left; + + SHA1_VALIDATE_RET( ctx != NULL ); + SHA1_VALIDATE_RET( ilen == 0 || input != NULL ); + + if( ilen == 0 ) + return( 0 ); + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + + if( ( ret = mbedtls_internal_sha1_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + if( ( ret = mbedtls_internal_sha1_process( ctx, input ) ) != 0 ) + return( ret ); + + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha1_update( mbedtls_sha1_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha1_update_ret( ctx, input, ilen ); +} +#endif + +/* + * SHA-1 final digest + */ +int mbedtls_sha1_finish_ret( mbedtls_sha1_context *ctx, + unsigned char output[20] ) +{ + int ret; + uint32_t used; + uint32_t high, low; + + SHA1_VALIDATE_RET( ctx != NULL ); + SHA1_VALIDATE_RET( (unsigned char *)output != NULL ); + + /* + * Add padding: 0x80 then 0x00 until 8 bytes remain for the length + */ + used = ctx->total[0] & 0x3F; + + ctx->buffer[used++] = 0x80; + + if( used <= 56 ) + { + /* Enough room for padding + length in current block */ + memset( ctx->buffer + used, 0, 56 - used ); + } + else + { + /* We'll need an extra block */ + memset( ctx->buffer + used, 0, 64 - used ); + + if( ( ret = mbedtls_internal_sha1_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + memset( ctx->buffer, 0, 56 ); + } + + /* + * Add message length + */ + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, ctx->buffer, 56 ); + PUT_UINT32_BE( low, ctx->buffer, 60 ); + + if( ( ret = mbedtls_internal_sha1_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + /* + * Output final state + */ + PUT_UINT32_BE( ctx->state[0], output, 0 ); + PUT_UINT32_BE( ctx->state[1], output, 4 ); + PUT_UINT32_BE( ctx->state[2], output, 8 ); + PUT_UINT32_BE( ctx->state[3], output, 12 ); + PUT_UINT32_BE( ctx->state[4], output, 16 ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, + unsigned char output[20] ) +{ + mbedtls_sha1_finish_ret( ctx, output ); +} +#endif + +#endif /* !MBEDTLS_SHA1_ALT */ + +/* + * output = SHA-1( input buffer ) + */ +int mbedtls_sha1_ret( const unsigned char *input, + size_t ilen, + unsigned char output[20] ) +{ + int ret; + mbedtls_sha1_context ctx; + + SHA1_VALIDATE_RET( ilen == 0 || input != NULL ); + SHA1_VALIDATE_RET( (unsigned char *)output != NULL ); + + mbedtls_sha1_init( &ctx ); + + if( ( ret = mbedtls_sha1_starts_ret( &ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_sha1_update_ret( &ctx, input, ilen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_sha1_finish_ret( &ctx, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_sha1_free( &ctx ); + + return( ret ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha1( const unsigned char *input, + size_t ilen, + unsigned char output[20] ) +{ + mbedtls_sha1_ret( input, ilen, output ); +} +#endif + +#if defined(MBEDTLS_SELF_TEST) +/* + * FIPS-180-1 test vectors + */ +static const unsigned char sha1_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const size_t sha1_test_buflen[3] = +{ + 3, 56, 1000 +}; + +static const unsigned char sha1_test_sum[3][20] = +{ + { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E, + 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D }, + { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE, + 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 }, + { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E, + 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F } +}; + +/* + * Checkup routine + */ +int mbedtls_sha1_self_test( int verbose ) +{ + int i, j, buflen, ret = 0; + unsigned char buf[1024]; + unsigned char sha1sum[20]; + mbedtls_sha1_context ctx; + + mbedtls_sha1_init( &ctx ); + + /* + * SHA-1 + */ + for( i = 0; i < 3; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " SHA-1 test #%d: ", i + 1 ); + + if( ( ret = mbedtls_sha1_starts_ret( &ctx ) ) != 0 ) + goto fail; + + if( i == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + { + ret = mbedtls_sha1_update_ret( &ctx, buf, buflen ); + if( ret != 0 ) + goto fail; + } + } + else + { + ret = mbedtls_sha1_update_ret( &ctx, sha1_test_buf[i], + sha1_test_buflen[i] ); + if( ret != 0 ) + goto fail; + } + + if( ( ret = mbedtls_sha1_finish_ret( &ctx, sha1sum ) ) != 0 ) + goto fail; + + if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 ) + { + ret = 1; + goto fail; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + goto exit; + +fail: + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + +exit: + mbedtls_sha1_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA1_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/sha256.c b/FreeRTOS-Labs/Source/mbedtls/library/sha256.c new file mode 100644 index 000000000..0b32a4220 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/sha256.c @@ -0,0 +1,586 @@ +/* + * FIPS-180-2 compliant SHA-256 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SHA-256 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA256_C) + +#include "mbedtls/sha256.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#define SHA256_VALIDATE_RET(cond) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA256_BAD_INPUT_DATA ) +#define SHA256_VALIDATE(cond) MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if !defined(MBEDTLS_SHA256_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +do { \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} while( 0 ) +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +do { \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} while( 0 ) +#endif + +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ) +{ + SHA256_VALIDATE( ctx != NULL ); + + memset( ctx, 0, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ) +{ + SHA256_VALIDATE( dst != NULL ); + SHA256_VALIDATE( src != NULL ); + + *dst = *src; +} + +/* + * SHA-256 context setup + */ +int mbedtls_sha256_starts_ret( mbedtls_sha256_context *ctx, int is224 ) +{ + SHA256_VALIDATE_RET( ctx != NULL ); + SHA256_VALIDATE_RET( is224 == 0 || is224 == 1 ); + + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is224 == 0 ) + { + /* SHA-256 */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; + } + else + { + /* SHA-224 */ + ctx->state[0] = 0xC1059ED8; + ctx->state[1] = 0x367CD507; + ctx->state[2] = 0x3070DD17; + ctx->state[3] = 0xF70E5939; + ctx->state[4] = 0xFFC00B31; + ctx->state[5] = 0x68581511; + ctx->state[6] = 0x64F98FA7; + ctx->state[7] = 0xBEFA4FA4; + } + + ctx->is224 = is224; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, + int is224 ) +{ + mbedtls_sha256_starts_ret( ctx, is224 ); +} +#endif + +#if !defined(MBEDTLS_SHA256_PROCESS_ALT) +static const uint32_t K[] = +{ + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, +}; + +#define SHR(x,n) (((x) & 0xFFFFFFFF) >> (n)) +#define ROTR(x,n) (SHR(x,n) | ((x) << (32 - (n)))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) + +#define F0(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define F1(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) + +#define R(t) \ + ( \ + W[t] = S1(W[(t) - 2]) + W[(t) - 7] + \ + S0(W[(t) - 15]) + W[(t) - 16] \ + ) + +#define P(a,b,c,d,e,f,g,h,x,K) \ + do \ + { \ + temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x); \ + temp2 = S2(a) + F0((a),(b),(c)); \ + (d) += temp1; (h) = temp1 + temp2; \ + } while( 0 ) + +int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx, + const unsigned char data[64] ) +{ + uint32_t temp1, temp2, W[64]; + uint32_t A[8]; + unsigned int i; + + SHA256_VALIDATE_RET( ctx != NULL ); + SHA256_VALIDATE_RET( (const unsigned char *)data != NULL ); + + for( i = 0; i < 8; i++ ) + A[i] = ctx->state[i]; + +#if defined(MBEDTLS_SHA256_SMALLER) + for( i = 0; i < 64; i++ ) + { + if( i < 16 ) + GET_UINT32_BE( W[i], data, 4 * i ); + else + R( i ); + + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] ); + + temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3]; + A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1; + } +#else /* MBEDTLS_SHA256_SMALLER */ + for( i = 0; i < 16; i++ ) + GET_UINT32_BE( W[i], data, 4 * i ); + + for( i = 0; i < 16; i += 8 ) + { + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] ); + P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] ); + P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] ); + P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] ); + P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] ); + P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] ); + P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] ); + P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] ); + } + + for( i = 16; i < 64; i += 8 ) + { + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] ); + P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] ); + P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] ); + P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] ); + P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] ); + P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] ); + P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] ); + P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] ); + } +#endif /* MBEDTLS_SHA256_SMALLER */ + + for( i = 0; i < 8; i++ ) + ctx->state[i] += A[i]; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha256_process( mbedtls_sha256_context *ctx, + const unsigned char data[64] ) +{ + mbedtls_internal_sha256_process( ctx, data ); +} +#endif +#endif /* !MBEDTLS_SHA256_PROCESS_ALT */ + +/* + * SHA-256 process buffer + */ +int mbedtls_sha256_update_ret( mbedtls_sha256_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + int ret; + size_t fill; + uint32_t left; + + SHA256_VALIDATE_RET( ctx != NULL ); + SHA256_VALIDATE_RET( ilen == 0 || input != NULL ); + + if( ilen == 0 ) + return( 0 ); + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + + if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + if( ( ret = mbedtls_internal_sha256_process( ctx, input ) ) != 0 ) + return( ret ); + + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha256_update( mbedtls_sha256_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha256_update_ret( ctx, input, ilen ); +} +#endif + +/* + * SHA-256 final digest + */ +int mbedtls_sha256_finish_ret( mbedtls_sha256_context *ctx, + unsigned char output[32] ) +{ + int ret; + uint32_t used; + uint32_t high, low; + + SHA256_VALIDATE_RET( ctx != NULL ); + SHA256_VALIDATE_RET( (unsigned char *)output != NULL ); + + /* + * Add padding: 0x80 then 0x00 until 8 bytes remain for the length + */ + used = ctx->total[0] & 0x3F; + + ctx->buffer[used++] = 0x80; + + if( used <= 56 ) + { + /* Enough room for padding + length in current block */ + memset( ctx->buffer + used, 0, 56 - used ); + } + else + { + /* We'll need an extra block */ + memset( ctx->buffer + used, 0, 64 - used ); + + if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + memset( ctx->buffer, 0, 56 ); + } + + /* + * Add message length + */ + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, ctx->buffer, 56 ); + PUT_UINT32_BE( low, ctx->buffer, 60 ); + + if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + /* + * Output final state + */ + PUT_UINT32_BE( ctx->state[0], output, 0 ); + PUT_UINT32_BE( ctx->state[1], output, 4 ); + PUT_UINT32_BE( ctx->state[2], output, 8 ); + PUT_UINT32_BE( ctx->state[3], output, 12 ); + PUT_UINT32_BE( ctx->state[4], output, 16 ); + PUT_UINT32_BE( ctx->state[5], output, 20 ); + PUT_UINT32_BE( ctx->state[6], output, 24 ); + + if( ctx->is224 == 0 ) + PUT_UINT32_BE( ctx->state[7], output, 28 ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, + unsigned char output[32] ) +{ + mbedtls_sha256_finish_ret( ctx, output ); +} +#endif + +#endif /* !MBEDTLS_SHA256_ALT */ + +/* + * output = SHA-256( input buffer ) + */ +int mbedtls_sha256_ret( const unsigned char *input, + size_t ilen, + unsigned char output[32], + int is224 ) +{ + int ret; + mbedtls_sha256_context ctx; + + SHA256_VALIDATE_RET( is224 == 0 || is224 == 1 ); + SHA256_VALIDATE_RET( ilen == 0 || input != NULL ); + SHA256_VALIDATE_RET( (unsigned char *)output != NULL ); + + mbedtls_sha256_init( &ctx ); + + if( ( ret = mbedtls_sha256_starts_ret( &ctx, is224 ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_sha256_update_ret( &ctx, input, ilen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_sha256_finish_ret( &ctx, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_sha256_free( &ctx ); + + return( ret ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha256( const unsigned char *input, + size_t ilen, + unsigned char output[32], + int is224 ) +{ + mbedtls_sha256_ret( input, ilen, output, is224 ); +} +#endif + +#if defined(MBEDTLS_SELF_TEST) +/* + * FIPS-180-2 test vectors + */ +static const unsigned char sha256_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const size_t sha256_test_buflen[3] = +{ + 3, 56, 1000 +}; + +static const unsigned char sha256_test_sum[6][32] = +{ + /* + * SHA-224 test vectors + */ + { 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22, + 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3, + 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7, + 0xE3, 0x6C, 0x9D, 0xA7 }, + { 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC, + 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50, + 0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19, + 0x52, 0x52, 0x25, 0x25 }, + { 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8, + 0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B, + 0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE, + 0x4E, 0xE7, 0xAD, 0x67 }, + + /* + * SHA-256 test vectors + */ + { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, + 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23, + 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, + 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD }, + { 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8, + 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39, + 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67, + 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 }, + { 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92, + 0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67, + 0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E, + 0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 } +}; + +/* + * Checkup routine + */ +int mbedtls_sha256_self_test( int verbose ) +{ + int i, j, k, buflen, ret = 0; + unsigned char *buf; + unsigned char sha256sum[32]; + mbedtls_sha256_context ctx; + + buf = mbedtls_calloc( 1024, sizeof(unsigned char) ); + if( NULL == buf ) + { + if( verbose != 0 ) + mbedtls_printf( "Buffer allocation failed\n" ); + + return( 1 ); + } + + mbedtls_sha256_init( &ctx ); + + for( i = 0; i < 6; i++ ) + { + j = i % 3; + k = i < 3; + + if( verbose != 0 ) + mbedtls_printf( " SHA-%d test #%d: ", 256 - k * 32, j + 1 ); + + if( ( ret = mbedtls_sha256_starts_ret( &ctx, k ) ) != 0 ) + goto fail; + + if( j == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + { + ret = mbedtls_sha256_update_ret( &ctx, buf, buflen ); + if( ret != 0 ) + goto fail; + } + + } + else + { + ret = mbedtls_sha256_update_ret( &ctx, sha256_test_buf[j], + sha256_test_buflen[j] ); + if( ret != 0 ) + goto fail; + } + + if( ( ret = mbedtls_sha256_finish_ret( &ctx, sha256sum ) ) != 0 ) + goto fail; + + + if( memcmp( sha256sum, sha256_test_sum[i], 32 - k * 4 ) != 0 ) + { + ret = 1; + goto fail; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + goto exit; + +fail: + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + +exit: + mbedtls_sha256_free( &ctx ); + mbedtls_free( buf ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA256_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/sha512.c b/FreeRTOS-Labs/Source/mbedtls/library/sha512.c new file mode 100644 index 000000000..df0690edb --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/sha512.c @@ -0,0 +1,636 @@ +/* + * FIPS-180-2 compliant SHA-384/512 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SHA-512 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA512_C) + +#include "mbedtls/sha512.h" +#include "mbedtls/platform_util.h" + +#if defined(_MSC_VER) || defined(__WATCOMC__) + #define UL64(x) x##ui64 +#else + #define UL64(x) x##ULL +#endif + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#define SHA512_VALIDATE_RET(cond) \ + MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_SHA512_BAD_INPUT_DATA ) +#define SHA512_VALIDATE(cond) MBEDTLS_INTERNAL_VALIDATE( cond ) + +#if !defined(MBEDTLS_SHA512_ALT) + +/* + * 64-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT64_BE +#define GET_UINT64_BE(n,b,i) \ +{ \ + (n) = ( (uint64_t) (b)[(i) ] << 56 ) \ + | ( (uint64_t) (b)[(i) + 1] << 48 ) \ + | ( (uint64_t) (b)[(i) + 2] << 40 ) \ + | ( (uint64_t) (b)[(i) + 3] << 32 ) \ + | ( (uint64_t) (b)[(i) + 4] << 24 ) \ + | ( (uint64_t) (b)[(i) + 5] << 16 ) \ + | ( (uint64_t) (b)[(i) + 6] << 8 ) \ + | ( (uint64_t) (b)[(i) + 7] ); \ +} +#endif /* GET_UINT64_BE */ + +#ifndef PUT_UINT64_BE +#define PUT_UINT64_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 56 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 48 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 40 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 32 ); \ + (b)[(i) + 4] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 5] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 6] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 7] = (unsigned char) ( (n) ); \ +} +#endif /* PUT_UINT64_BE */ + +void mbedtls_sha512_init( mbedtls_sha512_context *ctx ) +{ + SHA512_VALIDATE( ctx != NULL ); + + memset( ctx, 0, sizeof( mbedtls_sha512_context ) ); +} + +void mbedtls_sha512_free( mbedtls_sha512_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha512_context ) ); +} + +void mbedtls_sha512_clone( mbedtls_sha512_context *dst, + const mbedtls_sha512_context *src ) +{ + SHA512_VALIDATE( dst != NULL ); + SHA512_VALIDATE( src != NULL ); + + *dst = *src; +} + +/* + * SHA-512 context setup + */ +int mbedtls_sha512_starts_ret( mbedtls_sha512_context *ctx, int is384 ) +{ + SHA512_VALIDATE_RET( ctx != NULL ); + SHA512_VALIDATE_RET( is384 == 0 || is384 == 1 ); + + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is384 == 0 ) + { + /* SHA-512 */ + ctx->state[0] = UL64(0x6A09E667F3BCC908); + ctx->state[1] = UL64(0xBB67AE8584CAA73B); + ctx->state[2] = UL64(0x3C6EF372FE94F82B); + ctx->state[3] = UL64(0xA54FF53A5F1D36F1); + ctx->state[4] = UL64(0x510E527FADE682D1); + ctx->state[5] = UL64(0x9B05688C2B3E6C1F); + ctx->state[6] = UL64(0x1F83D9ABFB41BD6B); + ctx->state[7] = UL64(0x5BE0CD19137E2179); + } + else + { + /* SHA-384 */ + ctx->state[0] = UL64(0xCBBB9D5DC1059ED8); + ctx->state[1] = UL64(0x629A292A367CD507); + ctx->state[2] = UL64(0x9159015A3070DD17); + ctx->state[3] = UL64(0x152FECD8F70E5939); + ctx->state[4] = UL64(0x67332667FFC00B31); + ctx->state[5] = UL64(0x8EB44A8768581511); + ctx->state[6] = UL64(0xDB0C2E0D64F98FA7); + ctx->state[7] = UL64(0x47B5481DBEFA4FA4); + } + + ctx->is384 = is384; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha512_starts( mbedtls_sha512_context *ctx, + int is384 ) +{ + mbedtls_sha512_starts_ret( ctx, is384 ); +} +#endif + +#if !defined(MBEDTLS_SHA512_PROCESS_ALT) + +/* + * Round constants + */ +static const uint64_t K[80] = +{ + UL64(0x428A2F98D728AE22), UL64(0x7137449123EF65CD), + UL64(0xB5C0FBCFEC4D3B2F), UL64(0xE9B5DBA58189DBBC), + UL64(0x3956C25BF348B538), UL64(0x59F111F1B605D019), + UL64(0x923F82A4AF194F9B), UL64(0xAB1C5ED5DA6D8118), + UL64(0xD807AA98A3030242), UL64(0x12835B0145706FBE), + UL64(0x243185BE4EE4B28C), UL64(0x550C7DC3D5FFB4E2), + UL64(0x72BE5D74F27B896F), UL64(0x80DEB1FE3B1696B1), + UL64(0x9BDC06A725C71235), UL64(0xC19BF174CF692694), + UL64(0xE49B69C19EF14AD2), UL64(0xEFBE4786384F25E3), + UL64(0x0FC19DC68B8CD5B5), UL64(0x240CA1CC77AC9C65), + UL64(0x2DE92C6F592B0275), UL64(0x4A7484AA6EA6E483), + UL64(0x5CB0A9DCBD41FBD4), UL64(0x76F988DA831153B5), + UL64(0x983E5152EE66DFAB), UL64(0xA831C66D2DB43210), + UL64(0xB00327C898FB213F), UL64(0xBF597FC7BEEF0EE4), + UL64(0xC6E00BF33DA88FC2), UL64(0xD5A79147930AA725), + UL64(0x06CA6351E003826F), UL64(0x142929670A0E6E70), + UL64(0x27B70A8546D22FFC), UL64(0x2E1B21385C26C926), + UL64(0x4D2C6DFC5AC42AED), UL64(0x53380D139D95B3DF), + UL64(0x650A73548BAF63DE), UL64(0x766A0ABB3C77B2A8), + UL64(0x81C2C92E47EDAEE6), UL64(0x92722C851482353B), + UL64(0xA2BFE8A14CF10364), UL64(0xA81A664BBC423001), + UL64(0xC24B8B70D0F89791), UL64(0xC76C51A30654BE30), + UL64(0xD192E819D6EF5218), UL64(0xD69906245565A910), + UL64(0xF40E35855771202A), UL64(0x106AA07032BBD1B8), + UL64(0x19A4C116B8D2D0C8), UL64(0x1E376C085141AB53), + UL64(0x2748774CDF8EEB99), UL64(0x34B0BCB5E19B48A8), + UL64(0x391C0CB3C5C95A63), UL64(0x4ED8AA4AE3418ACB), + UL64(0x5B9CCA4F7763E373), UL64(0x682E6FF3D6B2B8A3), + UL64(0x748F82EE5DEFB2FC), UL64(0x78A5636F43172F60), + UL64(0x84C87814A1F0AB72), UL64(0x8CC702081A6439EC), + UL64(0x90BEFFFA23631E28), UL64(0xA4506CEBDE82BDE9), + UL64(0xBEF9A3F7B2C67915), UL64(0xC67178F2E372532B), + UL64(0xCA273ECEEA26619C), UL64(0xD186B8C721C0C207), + UL64(0xEADA7DD6CDE0EB1E), UL64(0xF57D4F7FEE6ED178), + UL64(0x06F067AA72176FBA), UL64(0x0A637DC5A2C898A6), + UL64(0x113F9804BEF90DAE), UL64(0x1B710B35131C471B), + UL64(0x28DB77F523047D84), UL64(0x32CAAB7B40C72493), + UL64(0x3C9EBE0A15C9BEBC), UL64(0x431D67C49C100D4C), + UL64(0x4CC5D4BECB3E42B6), UL64(0x597F299CFC657E2A), + UL64(0x5FCB6FAB3AD6FAEC), UL64(0x6C44198C4A475817) +}; + +int mbedtls_internal_sha512_process( mbedtls_sha512_context *ctx, + const unsigned char data[128] ) +{ + int i; + uint64_t temp1, temp2, W[80]; + uint64_t A, B, C, D, E, F, G, H; + + SHA512_VALIDATE_RET( ctx != NULL ); + SHA512_VALIDATE_RET( (const unsigned char *)data != NULL ); + +#define SHR(x,n) ((x) >> (n)) +#define ROTR(x,n) (SHR((x),(n)) | ((x) << (64 - (n)))) + +#define S0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7)) +#define S1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x, 6)) + +#define S2(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) +#define S3(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41)) + +#define F0(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define F1(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) + +#define P(a,b,c,d,e,f,g,h,x,K) \ + do \ + { \ + temp1 = (h) + S3(e) + F1((e),(f),(g)) + (K) + (x); \ + temp2 = S2(a) + F0((a),(b),(c)); \ + (d) += temp1; (h) = temp1 + temp2; \ + } while( 0 ) + + for( i = 0; i < 16; i++ ) + { + GET_UINT64_BE( W[i], data, i << 3 ); + } + + for( ; i < 80; i++ ) + { + W[i] = S1(W[i - 2]) + W[i - 7] + + S0(W[i - 15]) + W[i - 16]; + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + i = 0; + + do + { + P( A, B, C, D, E, F, G, H, W[i], K[i] ); i++; + P( H, A, B, C, D, E, F, G, W[i], K[i] ); i++; + P( G, H, A, B, C, D, E, F, W[i], K[i] ); i++; + P( F, G, H, A, B, C, D, E, W[i], K[i] ); i++; + P( E, F, G, H, A, B, C, D, W[i], K[i] ); i++; + P( D, E, F, G, H, A, B, C, W[i], K[i] ); i++; + P( C, D, E, F, G, H, A, B, W[i], K[i] ); i++; + P( B, C, D, E, F, G, H, A, W[i], K[i] ); i++; + } + while( i < 80 ); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha512_process( mbedtls_sha512_context *ctx, + const unsigned char data[128] ) +{ + mbedtls_internal_sha512_process( ctx, data ); +} +#endif +#endif /* !MBEDTLS_SHA512_PROCESS_ALT */ + +/* + * SHA-512 process buffer + */ +int mbedtls_sha512_update_ret( mbedtls_sha512_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + int ret; + size_t fill; + unsigned int left; + + SHA512_VALIDATE_RET( ctx != NULL ); + SHA512_VALIDATE_RET( ilen == 0 || input != NULL ); + + if( ilen == 0 ) + return( 0 ); + + left = (unsigned int) (ctx->total[0] & 0x7F); + fill = 128 - left; + + ctx->total[0] += (uint64_t) ilen; + + if( ctx->total[0] < (uint64_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + + if( ( ret = mbedtls_internal_sha512_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 128 ) + { + if( ( ret = mbedtls_internal_sha512_process( ctx, input ) ) != 0 ) + return( ret ); + + input += 128; + ilen -= 128; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha512_update( mbedtls_sha512_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha512_update_ret( ctx, input, ilen ); +} +#endif + +/* + * SHA-512 final digest + */ +int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx, + unsigned char output[64] ) +{ + int ret; + unsigned used; + uint64_t high, low; + + SHA512_VALIDATE_RET( ctx != NULL ); + SHA512_VALIDATE_RET( (unsigned char *)output != NULL ); + + /* + * Add padding: 0x80 then 0x00 until 16 bytes remain for the length + */ + used = ctx->total[0] & 0x7F; + + ctx->buffer[used++] = 0x80; + + if( used <= 112 ) + { + /* Enough room for padding + length in current block */ + memset( ctx->buffer + used, 0, 112 - used ); + } + else + { + /* We'll need an extra block */ + memset( ctx->buffer + used, 0, 128 - used ); + + if( ( ret = mbedtls_internal_sha512_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + memset( ctx->buffer, 0, 112 ); + } + + /* + * Add message length + */ + high = ( ctx->total[0] >> 61 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT64_BE( high, ctx->buffer, 112 ); + PUT_UINT64_BE( low, ctx->buffer, 120 ); + + if( ( ret = mbedtls_internal_sha512_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + /* + * Output final state + */ + PUT_UINT64_BE( ctx->state[0], output, 0 ); + PUT_UINT64_BE( ctx->state[1], output, 8 ); + PUT_UINT64_BE( ctx->state[2], output, 16 ); + PUT_UINT64_BE( ctx->state[3], output, 24 ); + PUT_UINT64_BE( ctx->state[4], output, 32 ); + PUT_UINT64_BE( ctx->state[5], output, 40 ); + + if( ctx->is384 == 0 ) + { + PUT_UINT64_BE( ctx->state[6], output, 48 ); + PUT_UINT64_BE( ctx->state[7], output, 56 ); + } + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha512_finish( mbedtls_sha512_context *ctx, + unsigned char output[64] ) +{ + mbedtls_sha512_finish_ret( ctx, output ); +} +#endif + +#endif /* !MBEDTLS_SHA512_ALT */ + +/* + * output = SHA-512( input buffer ) + */ +int mbedtls_sha512_ret( const unsigned char *input, + size_t ilen, + unsigned char output[64], + int is384 ) +{ + int ret; + mbedtls_sha512_context ctx; + + SHA512_VALIDATE_RET( is384 == 0 || is384 == 1 ); + SHA512_VALIDATE_RET( ilen == 0 || input != NULL ); + SHA512_VALIDATE_RET( (unsigned char *)output != NULL ); + + mbedtls_sha512_init( &ctx ); + + if( ( ret = mbedtls_sha512_starts_ret( &ctx, is384 ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_sha512_update_ret( &ctx, input, ilen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_sha512_finish_ret( &ctx, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_sha512_free( &ctx ); + + return( ret ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha512( const unsigned char *input, + size_t ilen, + unsigned char output[64], + int is384 ) +{ + mbedtls_sha512_ret( input, ilen, output, is384 ); +} +#endif + +#if defined(MBEDTLS_SELF_TEST) + +/* + * FIPS-180-2 test vectors + */ +static const unsigned char sha512_test_buf[3][113] = +{ + { "abc" }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" }, + { "" } +}; + +static const size_t sha512_test_buflen[3] = +{ + 3, 112, 1000 +}; + +static const unsigned char sha512_test_sum[6][64] = +{ + /* + * SHA-384 test vectors + */ + { 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B, + 0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07, + 0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63, + 0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED, + 0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23, + 0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7 }, + { 0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8, + 0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47, + 0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2, + 0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12, + 0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9, + 0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39 }, + { 0x9D, 0x0E, 0x18, 0x09, 0x71, 0x64, 0x74, 0xCB, + 0x08, 0x6E, 0x83, 0x4E, 0x31, 0x0A, 0x4A, 0x1C, + 0xED, 0x14, 0x9E, 0x9C, 0x00, 0xF2, 0x48, 0x52, + 0x79, 0x72, 0xCE, 0xC5, 0x70, 0x4C, 0x2A, 0x5B, + 0x07, 0xB8, 0xB3, 0xDC, 0x38, 0xEC, 0xC4, 0xEB, + 0xAE, 0x97, 0xDD, 0xD8, 0x7F, 0x3D, 0x89, 0x85 }, + + /* + * SHA-512 test vectors + */ + { 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, + 0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31, + 0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2, + 0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A, + 0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8, + 0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD, + 0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E, + 0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F }, + { 0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA, + 0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F, + 0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1, + 0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18, + 0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4, + 0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A, + 0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54, + 0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09 }, + { 0xE7, 0x18, 0x48, 0x3D, 0x0C, 0xE7, 0x69, 0x64, + 0x4E, 0x2E, 0x42, 0xC7, 0xBC, 0x15, 0xB4, 0x63, + 0x8E, 0x1F, 0x98, 0xB1, 0x3B, 0x20, 0x44, 0x28, + 0x56, 0x32, 0xA8, 0x03, 0xAF, 0xA9, 0x73, 0xEB, + 0xDE, 0x0F, 0xF2, 0x44, 0x87, 0x7E, 0xA6, 0x0A, + 0x4C, 0xB0, 0x43, 0x2C, 0xE5, 0x77, 0xC3, 0x1B, + 0xEB, 0x00, 0x9C, 0x5C, 0x2C, 0x49, 0xAA, 0x2E, + 0x4E, 0xAD, 0xB2, 0x17, 0xAD, 0x8C, 0xC0, 0x9B } +}; + +/* + * Checkup routine + */ +int mbedtls_sha512_self_test( int verbose ) +{ + int i, j, k, buflen, ret = 0; + unsigned char *buf; + unsigned char sha512sum[64]; + mbedtls_sha512_context ctx; + + buf = mbedtls_calloc( 1024, sizeof(unsigned char) ); + if( NULL == buf ) + { + if( verbose != 0 ) + mbedtls_printf( "Buffer allocation failed\n" ); + + return( 1 ); + } + + mbedtls_sha512_init( &ctx ); + + for( i = 0; i < 6; i++ ) + { + j = i % 3; + k = i < 3; + + if( verbose != 0 ) + mbedtls_printf( " SHA-%d test #%d: ", 512 - k * 128, j + 1 ); + + if( ( ret = mbedtls_sha512_starts_ret( &ctx, k ) ) != 0 ) + goto fail; + + if( j == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + { + ret = mbedtls_sha512_update_ret( &ctx, buf, buflen ); + if( ret != 0 ) + goto fail; + } + } + else + { + ret = mbedtls_sha512_update_ret( &ctx, sha512_test_buf[j], + sha512_test_buflen[j] ); + if( ret != 0 ) + goto fail; + } + + if( ( ret = mbedtls_sha512_finish_ret( &ctx, sha512sum ) ) != 0 ) + goto fail; + + if( memcmp( sha512sum, sha512_test_sum[i], 64 - k * 16 ) != 0 ) + { + ret = 1; + goto fail; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + goto exit; + +fail: + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + +exit: + mbedtls_sha512_free( &ctx ); + mbedtls_free( buf ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA512_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ssl_cache.c b/FreeRTOS-Labs/Source/mbedtls/library/ssl_cache.c new file mode 100644 index 000000000..036b468c4 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ssl_cache.c @@ -0,0 +1,353 @@ +/* + * SSL session cache implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * These session callbacks use a simple chained list + * to store and retrieve the session information. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_CACHE_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/ssl_cache.h" +#include "mbedtls/ssl_internal.h" + +#include + +void mbedtls_ssl_cache_init( mbedtls_ssl_cache_context *cache ) +{ + memset( cache, 0, sizeof( mbedtls_ssl_cache_context ) ); + + cache->timeout = MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT; + cache->max_entries = MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &cache->mutex ); +#endif +} + +int mbedtls_ssl_cache_get( void *data, mbedtls_ssl_session *session ) +{ + int ret = 1; +#if defined(MBEDTLS_HAVE_TIME) + mbedtls_time_t t = mbedtls_time( NULL ); +#endif + mbedtls_ssl_cache_context *cache = (mbedtls_ssl_cache_context *) data; + mbedtls_ssl_cache_entry *cur, *entry; + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &cache->mutex ) != 0 ) + return( 1 ); +#endif + + cur = cache->chain; + entry = NULL; + + while( cur != NULL ) + { + entry = cur; + cur = cur->next; + +#if defined(MBEDTLS_HAVE_TIME) + if( cache->timeout != 0 && + (int) ( t - entry->timestamp ) > cache->timeout ) + continue; +#endif + + if( session->ciphersuite != entry->session.ciphersuite || + session->compression != entry->session.compression || + session->id_len != entry->session.id_len ) + continue; + + if( memcmp( session->id, entry->session.id, + entry->session.id_len ) != 0 ) + continue; + + ret = mbedtls_ssl_session_copy( session, &entry->session ); + if( ret != 0 ) + { + ret = 1; + goto exit; + } + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + /* + * Restore peer certificate (without rest of the original chain) + */ + if( entry->peer_cert.p != NULL ) + { + /* `session->peer_cert` is NULL after the call to + * mbedtls_ssl_session_copy(), because cache entries + * have the `peer_cert` field set to NULL. */ + + if( ( session->peer_cert = mbedtls_calloc( 1, + sizeof(mbedtls_x509_crt) ) ) == NULL ) + { + ret = 1; + goto exit; + } + + mbedtls_x509_crt_init( session->peer_cert ); + if( mbedtls_x509_crt_parse( session->peer_cert, entry->peer_cert.p, + entry->peer_cert.len ) != 0 ) + { + mbedtls_free( session->peer_cert ); + session->peer_cert = NULL; + ret = 1; + goto exit; + } + } +#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + + ret = 0; + goto exit; + } + +exit: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &cache->mutex ) != 0 ) + ret = 1; +#endif + + return( ret ); +} + +int mbedtls_ssl_cache_set( void *data, const mbedtls_ssl_session *session ) +{ + int ret = 1; +#if defined(MBEDTLS_HAVE_TIME) + mbedtls_time_t t = mbedtls_time( NULL ), oldest = 0; + mbedtls_ssl_cache_entry *old = NULL; +#endif + mbedtls_ssl_cache_context *cache = (mbedtls_ssl_cache_context *) data; + mbedtls_ssl_cache_entry *cur, *prv; + int count = 0; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &cache->mutex ) ) != 0 ) + return( ret ); +#endif + + cur = cache->chain; + prv = NULL; + + while( cur != NULL ) + { + count++; + +#if defined(MBEDTLS_HAVE_TIME) + if( cache->timeout != 0 && + (int) ( t - cur->timestamp ) > cache->timeout ) + { + cur->timestamp = t; + break; /* expired, reuse this slot, update timestamp */ + } +#endif + + if( memcmp( session->id, cur->session.id, cur->session.id_len ) == 0 ) + break; /* client reconnected, keep timestamp for session id */ + +#if defined(MBEDTLS_HAVE_TIME) + if( oldest == 0 || cur->timestamp < oldest ) + { + oldest = cur->timestamp; + old = cur; + } +#endif + + prv = cur; + cur = cur->next; + } + + if( cur == NULL ) + { +#if defined(MBEDTLS_HAVE_TIME) + /* + * Reuse oldest entry if max_entries reached + */ + if( count >= cache->max_entries ) + { + if( old == NULL ) + { + ret = 1; + goto exit; + } + + cur = old; + } +#else /* MBEDTLS_HAVE_TIME */ + /* + * Reuse first entry in chain if max_entries reached, + * but move to last place + */ + if( count >= cache->max_entries ) + { + if( cache->chain == NULL ) + { + ret = 1; + goto exit; + } + + cur = cache->chain; + cache->chain = cur->next; + cur->next = NULL; + prv->next = cur; + } +#endif /* MBEDTLS_HAVE_TIME */ + else + { + /* + * max_entries not reached, create new entry + */ + cur = mbedtls_calloc( 1, sizeof(mbedtls_ssl_cache_entry) ); + if( cur == NULL ) + { + ret = 1; + goto exit; + } + + if( prv == NULL ) + cache->chain = cur; + else + prv->next = cur; + } + +#if defined(MBEDTLS_HAVE_TIME) + cur->timestamp = t; +#endif + } + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + /* + * If we're reusing an entry, free its certificate first + */ + if( cur->peer_cert.p != NULL ) + { + mbedtls_free( cur->peer_cert.p ); + memset( &cur->peer_cert, 0, sizeof(mbedtls_x509_buf) ); + } +#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + + /* Copy the entire session; this temporarily makes a copy of the + * X.509 CRT structure even though we only want to store the raw CRT. + * This inefficiency will go away as soon as we implement on-demand + * parsing of CRTs, in which case there's no need for the `peer_cert` + * field anymore in the first place, and we're done after this call. */ + ret = mbedtls_ssl_session_copy( &cur->session, session ); + if( ret != 0 ) + { + ret = 1; + goto exit; + } + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + /* If present, free the X.509 structure and only store the raw CRT data. */ + if( cur->session.peer_cert != NULL ) + { + cur->peer_cert.p = + mbedtls_calloc( 1, cur->session.peer_cert->raw.len ); + if( cur->peer_cert.p == NULL ) + { + ret = 1; + goto exit; + } + + memcpy( cur->peer_cert.p, + cur->session.peer_cert->raw.p, + cur->session.peer_cert->raw.len ); + cur->peer_cert.len = session->peer_cert->raw.len; + + mbedtls_x509_crt_free( cur->session.peer_cert ); + mbedtls_free( cur->session.peer_cert ); + cur->session.peer_cert = NULL; + } +#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + + ret = 0; + +exit: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &cache->mutex ) != 0 ) + ret = 1; +#endif + + return( ret ); +} + +#if defined(MBEDTLS_HAVE_TIME) +void mbedtls_ssl_cache_set_timeout( mbedtls_ssl_cache_context *cache, int timeout ) +{ + if( timeout < 0 ) timeout = 0; + + cache->timeout = timeout; +} +#endif /* MBEDTLS_HAVE_TIME */ + +void mbedtls_ssl_cache_set_max_entries( mbedtls_ssl_cache_context *cache, int max ) +{ + if( max < 0 ) max = 0; + + cache->max_entries = max; +} + +void mbedtls_ssl_cache_free( mbedtls_ssl_cache_context *cache ) +{ + mbedtls_ssl_cache_entry *cur, *prv; + + cur = cache->chain; + + while( cur != NULL ) + { + prv = cur; + cur = cur->next; + + mbedtls_ssl_session_free( &prv->session ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + mbedtls_free( prv->peer_cert.p ); +#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + + mbedtls_free( prv ); + } + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &cache->mutex ); +#endif + cache->chain = NULL; +} + +#endif /* MBEDTLS_SSL_CACHE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ssl_ciphersuites.c b/FreeRTOS-Labs/Source/mbedtls/library/ssl_ciphersuites.c new file mode 100644 index 000000000..49bb86eb5 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ssl_ciphersuites.c @@ -0,0 +1,2373 @@ +/** + * \file ssl_ciphersuites.c + * + * \brief SSL ciphersuites for mbed TLS + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_TLS_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#endif + +#include "mbedtls/ssl_ciphersuites.h" +#include "mbedtls/ssl.h" + +#include + +/* + * Ordered from most preferred to least preferred in terms of security. + * + * Current rule (except RC4 and 3DES, weak and null which come last): + * 1. By key exchange: + * Forward-secure non-PSK > forward-secure PSK > ECJPAKE > other non-PSK > other PSK + * 2. By key length and cipher: + * ChaCha > AES-256 > Camellia-256 > ARIA-256 > AES-128 > Camellia-128 > ARIA-128 + * 3. By cipher mode when relevant GCM > CCM > CBC > CCM_8 + * 4. By hash function used when relevant + * 5. By key exchange/auth again: EC > non-EC + */ +static const int ciphersuite_preference[] = +{ +#if defined(MBEDTLS_SSL_CIPHERSUITES) + MBEDTLS_SSL_CIPHERSUITES, +#else + /* Chacha-Poly ephemeral suites */ + MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + + /* All AES-256 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8, + + /* All CAMELLIA-256 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, + + /* All ARIA-256 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384, + + /* All AES-128 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8, + + /* All CAMELLIA-128 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, + + /* All ARIA-128 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256, + + /* The PSK ephemeral suites */ + MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8, + MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384, + + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8, + MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256, + + /* The ECJPAKE suite */ + MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8, + + /* All AES-256 suites */ + MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_RSA_WITH_AES_256_CCM, + MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8, + + /* All CAMELLIA-256 suites */ + MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, + + /* All ARIA-256 suites */ + MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384, + MBEDTLS_TLS_RSA_WITH_ARIA_256_CBC_SHA384, + + /* All AES-128 suites */ + MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_RSA_WITH_AES_128_CCM, + MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8, + + /* All CAMELLIA-128 suites */ + MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, + + /* All ARIA-128 suites */ + MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_ARIA_128_CBC_SHA256, + + /* The RSA PSK suites */ + MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384, + + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256, + + /* The PSK suites */ + MBEDTLS_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256, + MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_PSK_WITH_AES_256_CCM, + MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, + MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384, + MBEDTLS_TLS_PSK_WITH_ARIA_256_CBC_SHA384, + + MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_PSK_WITH_AES_128_CCM, + MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, + MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256, + MBEDTLS_TLS_PSK_WITH_ARIA_128_CBC_SHA256, + + /* 3DES suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA, + + /* RC4 suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA, + MBEDTLS_TLS_RSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_RSA_WITH_RC4_128_MD5, + MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA, + MBEDTLS_TLS_PSK_WITH_RC4_128_SHA, + + /* Weak suites */ + MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA, + + /* NULL suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA, + MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA, + + MBEDTLS_TLS_RSA_WITH_NULL_SHA256, + MBEDTLS_TLS_RSA_WITH_NULL_SHA, + MBEDTLS_TLS_RSA_WITH_NULL_MD5, + MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA, + MBEDTLS_TLS_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_PSK_WITH_NULL_SHA, + +#endif /* MBEDTLS_SSL_CIPHERSUITES */ + 0 +}; + +static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] = +{ +#if defined(MBEDTLS_CHACHAPOLY_C) && \ + defined(MBEDTLS_SHA256_C) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) + { MBEDTLS_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + { MBEDTLS_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + { MBEDTLS_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256, + "TLS-PSK-WITH-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + { MBEDTLS_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, + "TLS-ECDHE-PSK-WITH-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + { MBEDTLS_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256, + "TLS-DHE-PSK-WITH-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + { MBEDTLS_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256, + "TLS-RSA-PSK-WITH-CHACHA20-POLY1305-SHA256", + MBEDTLS_CIPHER_CHACHA20_POLY1305, MBEDTLS_MD_SHA256, + MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#endif /* MBEDTLS_CHACHAPOLY_C && + MBEDTLS_SHA256_C && + MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, "TLS-ECDHE-ECDSA-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, "TLS-ECDHE-ECDSA-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, "TLS-ECDHE-ECDSA-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, "TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, "TLS-ECDHE-ECDSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, "TLS-ECDHE-ECDSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA, "TLS-ECDHE-ECDSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDHE-RSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDHE-RSA-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-ECDHE-RSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-ECDHE-RSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA, "TLS-ECDHE-RSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA, "TLS-ECDHE-RSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C && MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, "TLS-DHE-RSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, "TLS-DHE-RSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM, "TLS-DHE-RSA-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8, "TLS-DHE-RSA-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM, "TLS-DHE-RSA-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8, "TLS-DHE-RSA-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-DHE-RSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-DHE-RSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384, "TLS-RSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C && MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256, "TLS-RSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS-RSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256, "TLS-RSA-WITH-AES-256-CBC-SHA256", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA, "TLS-RSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA, "TLS-RSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_RSA_WITH_AES_256_CCM, "TLS-RSA-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8, "TLS-RSA-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_RSA_WITH_AES_128_CCM, "TLS-RSA-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8, "TLS-RSA-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-RSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-RSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS-RSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_MD5_C) + { MBEDTLS_TLS_RSA_WITH_RC4_128_MD5, "TLS-RSA-WITH-RC4-128-MD5", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_MD5, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_RC4_128_SHA, "TLS-RSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, "TLS-ECDH-RSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, "TLS-ECDH-RSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDH-RSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDH-RSA-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-ECDH-RSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-ECDH-RSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, "TLS-ECDH-RSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA, "TLS-ECDH-RSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA, "TLS-ECDH-RSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, "TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, "TLS-ECDH-ECDSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, "TLS-ECDH-ECDSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA, "TLS-ECDH-ECDSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA, "TLS-ECDH-ECDSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, "TLS-PSK-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384, "TLS-PSK-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256, "TLS-PSK-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384, "TLS-PSK-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA, "TLS-PSK-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA, "TLS-PSK-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_PSK_WITH_AES_256_CCM, "TLS-PSK-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, "TLS-PSK-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_PSK_WITH_AES_128_CCM, "TLS-PSK-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, "TLS-PSK-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256, "TLS-PSK-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384, "TLS-PSK-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256, "TLS-PSK-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384, "TLS-PSK-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-PSK-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_PSK_WITH_RC4_128_SHA, "TLS-PSK-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, "TLS-DHE-PSK-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, "TLS-DHE-PSK-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, "TLS-DHE-PSK-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, "TLS-DHE-PSK-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA, "TLS-DHE-PSK-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA, "TLS-DHE-PSK-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM, "TLS-DHE-PSK-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8, "TLS-DHE-PSK-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM, "TLS-DHE-PSK-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8, "TLS-DHE-PSK-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, "TLS-DHE-PSK-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, "TLS-DHE-PSK-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256, "TLS-DHE-PSK-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384, "TLS-DHE-PSK-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-DHE-PSK-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA, "TLS-DHE-PSK-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +#if defined(MBEDTLS_AES_C) + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, "TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, "TLS-ECDHE-PSK-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, "TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, "TLS-ECDHE-PSK-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDHE-PSK-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDHE-PSK-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-ECDHE-PSK-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA, "TLS-ECDHE-PSK-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, "TLS-RSA-PSK-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, "TLS-RSA-PSK-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, "TLS-RSA-PSK-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, "TLS-RSA-PSK-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA, "TLS-RSA-PSK-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA, "TLS-RSA-PSK-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256, "TLS-RSA-PSK-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384, "TLS-RSA-PSK-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256, "TLS-RSA-PSK-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384, "TLS-RSA-PSK-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-RSA-PSK-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA, "TLS-RSA-PSK-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8, "TLS-ECJPAKE-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECJPAKE, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_ENABLE_WEAK_CIPHERSUITES) +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) +#if defined(MBEDTLS_MD5_C) + { MBEDTLS_TLS_RSA_WITH_NULL_MD5, "TLS-RSA-WITH-NULL-MD5", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_MD5, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_NULL_SHA, "TLS-RSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_WITH_NULL_SHA256, "TLS-RSA-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_PSK_WITH_NULL_SHA, "TLS-PSK-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_NULL_SHA256, "TLS-PSK-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_NULL_SHA384, "TLS-PSK-WITH-NULL-SHA384", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA, "TLS-DHE-PSK-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256, "TLS-DHE-PSK-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384, "TLS-DHE-PSK-WITH-NULL-SHA384", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA, "TLS-ECDHE-PSK-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256, "TLS-ECDHE-PSK-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384, "TLS-ECDHE-PSK-WITH-NULL-SHA384", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA, "TLS-RSA-PSK-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256, "TLS-RSA-PSK-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384, "TLS-RSA-PSK-WITH-NULL-SHA384", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA, "TLS-DHE-RSA-WITH-DES-CBC-SHA", + MBEDTLS_CIPHER_DES_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA, "TLS-RSA-WITH-DES-CBC-SHA", + MBEDTLS_CIPHER_DES_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ +#endif /* MBEDTLS_ENABLE_WEAK_CIPHERSUITES */ + +#if defined(MBEDTLS_ARIA_C) + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384, + "TLS-RSA-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_RSA_WITH_ARIA_256_CBC_SHA384, + "TLS-RSA-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256, + "TLS-RSA-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_RSA_WITH_ARIA_128_CBC_SHA256, + "TLS-RSA-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384, + "TLS-RSA-PSK-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384, + "TLS-RSA-PSK-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256, + "TLS-RSA-PSK-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256, + "TLS-RSA-PSK-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384, + "TLS-PSK-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384,MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_PSK_WITH_ARIA_256_CBC_SHA384, + "TLS-PSK-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256, + "TLS-PSK-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_PSK_WITH_ARIA_128_CBC_SHA256, + "TLS-PSK-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384, + "TLS-ECDH-RSA-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384, + "TLS-ECDH-RSA-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256, + "TLS-ECDH-RSA-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256, + "TLS-ECDH-RSA-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384, + "TLS-ECDHE-RSA-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384, + "TLS-ECDHE-RSA-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256, + "TLS-ECDHE-RSA-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256, + "TLS-ECDHE-RSA-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384, + "TLS-ECDHE-PSK-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256, + "TLS-ECDHE-PSK-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384, + "TLS-ECDHE-ECDSA-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384, + "TLS-ECDHE-ECDSA-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256, + "TLS-ECDHE-ECDSA-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256, + "TLS-ECDHE-ECDSA-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384, + "TLS-ECDH-ECDSA-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384, + "TLS-ECDH-ECDSA-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256, + "TLS-ECDH-ECDSA-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256, + "TLS-ECDH-ECDSA-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384, + "TLS-DHE-RSA-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384, + "TLS-DHE-RSA-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256, + "TLS-DHE-RSA-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256, + "TLS-DHE-RSA-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384, + "TLS-DHE-PSK-WITH-ARIA-256-GCM-SHA384", + MBEDTLS_CIPHER_ARIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA512_C)) + { MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384, + "TLS-DHE-PSK-WITH-ARIA-256-CBC-SHA384", + MBEDTLS_CIPHER_ARIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_GCM_C) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256, + "TLS-DHE-PSK-WITH-ARIA-128-GCM-SHA256", + MBEDTLS_CIPHER_ARIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif +#if (defined(MBEDTLS_CIPHER_MODE_CBC) && defined(MBEDTLS_SHA256_C)) + { MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256, + "TLS-DHE-PSK-WITH-ARIA-128-CBC-SHA256", + MBEDTLS_CIPHER_ARIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif + +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#endif /* MBEDTLS_ARIA_C */ + + + { 0, "", + MBEDTLS_CIPHER_NONE, MBEDTLS_MD_NONE, MBEDTLS_KEY_EXCHANGE_NONE, + 0, 0, 0, 0, 0 } +}; + +#if defined(MBEDTLS_SSL_CIPHERSUITES) +const int *mbedtls_ssl_list_ciphersuites( void ) +{ + return( ciphersuite_preference ); +} +#else +#define MAX_CIPHERSUITES sizeof( ciphersuite_definitions ) / \ + sizeof( ciphersuite_definitions[0] ) +static int supported_ciphersuites[MAX_CIPHERSUITES]; +static int supported_init = 0; + +static int ciphersuite_is_removed( const mbedtls_ssl_ciphersuite_t *cs_info ) +{ + (void)cs_info; + +#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES) + if( cs_info->cipher == MBEDTLS_CIPHER_ARC4_128 ) + return( 1 ); +#endif /* MBEDTLS_REMOVE_ARC4_CIPHERSUITES */ + +#if defined(MBEDTLS_REMOVE_3DES_CIPHERSUITES) + if( cs_info->cipher == MBEDTLS_CIPHER_DES_EDE3_ECB || + cs_info->cipher == MBEDTLS_CIPHER_DES_EDE3_CBC ) + { + return( 1 ); + } +#endif /* MBEDTLS_REMOVE_3DES_CIPHERSUITES */ + + return( 0 ); +} + +const int *mbedtls_ssl_list_ciphersuites( void ) +{ + /* + * On initial call filter out all ciphersuites not supported by current + * build based on presence in the ciphersuite_definitions. + */ + if( supported_init == 0 ) + { + const int *p; + int *q; + + for( p = ciphersuite_preference, q = supported_ciphersuites; + *p != 0 && q < supported_ciphersuites + MAX_CIPHERSUITES - 1; + p++ ) + { + const mbedtls_ssl_ciphersuite_t *cs_info; + if( ( cs_info = mbedtls_ssl_ciphersuite_from_id( *p ) ) != NULL && + !ciphersuite_is_removed( cs_info ) ) + { + *(q++) = *p; + } + } + *q = 0; + + supported_init = 1; + } + + return( supported_ciphersuites ); +} +#endif /* MBEDTLS_SSL_CIPHERSUITES */ + +const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_string( + const char *ciphersuite_name ) +{ + const mbedtls_ssl_ciphersuite_t *cur = ciphersuite_definitions; + + if( NULL == ciphersuite_name ) + return( NULL ); + + while( cur->id != 0 ) + { + if( 0 == strcmp( cur->name, ciphersuite_name ) ) + return( cur ); + + cur++; + } + + return( NULL ); +} + +const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_id( int ciphersuite ) +{ + const mbedtls_ssl_ciphersuite_t *cur = ciphersuite_definitions; + + while( cur->id != 0 ) + { + if( cur->id == ciphersuite ) + return( cur ); + + cur++; + } + + return( NULL ); +} + +const char *mbedtls_ssl_get_ciphersuite_name( const int ciphersuite_id ) +{ + const mbedtls_ssl_ciphersuite_t *cur; + + cur = mbedtls_ssl_ciphersuite_from_id( ciphersuite_id ); + + if( cur == NULL ) + return( "unknown" ); + + return( cur->name ); +} + +int mbedtls_ssl_get_ciphersuite_id( const char *ciphersuite_name ) +{ + const mbedtls_ssl_ciphersuite_t *cur; + + cur = mbedtls_ssl_ciphersuite_from_string( ciphersuite_name ); + + if( cur == NULL ) + return( 0 ); + + return( cur->id ); +} + +#if defined(MBEDTLS_PK_C) +mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_RSA: + case MBEDTLS_KEY_EXCHANGE_DHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + case MBEDTLS_KEY_EXCHANGE_RSA_PSK: + return( MBEDTLS_PK_RSA ); + + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + return( MBEDTLS_PK_ECDSA ); + + case MBEDTLS_KEY_EXCHANGE_ECDH_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA: + return( MBEDTLS_PK_ECKEY ); + + default: + return( MBEDTLS_PK_NONE ); + } +} + +mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_alg( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_RSA: + case MBEDTLS_KEY_EXCHANGE_DHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + return( MBEDTLS_PK_RSA ); + + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + return( MBEDTLS_PK_ECDSA ); + + default: + return( MBEDTLS_PK_NONE ); + } +} + +#endif /* MBEDTLS_PK_C */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +int mbedtls_ssl_ciphersuite_uses_ec( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK: + case MBEDTLS_KEY_EXCHANGE_ECDH_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA: + case MBEDTLS_KEY_EXCHANGE_ECJPAKE: + return( 1 ); + + default: + return( 0 ); + } +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED*/ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +int mbedtls_ssl_ciphersuite_uses_psk( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_PSK: + case MBEDTLS_KEY_EXCHANGE_RSA_PSK: + case MBEDTLS_KEY_EXCHANGE_DHE_PSK: + case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK: + return( 1 ); + + default: + return( 0 ); + } +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#endif /* MBEDTLS_SSL_TLS_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ssl_cli.c b/FreeRTOS-Labs/Source/mbedtls/library/ssl_cli.c new file mode 100644 index 000000000..78744698a --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ssl_cli.c @@ -0,0 +1,4065 @@ +/* + * SSLv3/TLSv1 client-side functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_CLI_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "mbedtls/psa_util.h" +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#include + +#include + +#if defined(MBEDTLS_HAVE_TIME) +#include "mbedtls/platform_time.h" +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +#include "mbedtls/platform_util.h" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +static int ssl_conf_has_static_psk( mbedtls_ssl_config const *conf ) +{ + if( conf->psk_identity == NULL || + conf->psk_identity_len == 0 ) + { + return( 0 ); + } + + if( conf->psk != NULL && conf->psk_len != 0 ) + return( 1 ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( conf->psk_opaque != 0 ) + return( 1 ); +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + return( 0 ); +} + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +static int ssl_conf_has_static_raw_psk( mbedtls_ssl_config const *conf ) +{ + if( conf->psk_identity == NULL || + conf->psk_identity_len == 0 ) + { + return( 0 ); + } + + if( conf->psk != NULL && conf->psk_len != 0 ) + return( 1 ); + + return( 0 ); +} +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +static void ssl_write_hostname_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + size_t hostname_len; + + *olen = 0; + + if( ssl->hostname == NULL ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding server name extension: %s", + ssl->hostname ) ); + + hostname_len = strlen( ssl->hostname ); + + if( end < p || (size_t)( end - p ) < hostname_len + 9 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + /* + * Sect. 3, RFC 6066 (TLS Extensions Definitions) + * + * In order to provide any of the server names, clients MAY include an + * extension of type "server_name" in the (extended) client hello. The + * "extension_data" field of this extension SHALL contain + * "ServerNameList" where: + * + * struct { + * NameType name_type; + * select (name_type) { + * case host_name: HostName; + * } name; + * } ServerName; + * + * enum { + * host_name(0), (255) + * } NameType; + * + * opaque HostName<1..2^16-1>; + * + * struct { + * ServerName server_name_list<1..2^16-1> + * } ServerNameList; + * + */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME ) & 0xFF ); + + *p++ = (unsigned char)( ( (hostname_len + 5) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( (hostname_len + 5) ) & 0xFF ); + + *p++ = (unsigned char)( ( (hostname_len + 3) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( (hostname_len + 3) ) & 0xFF ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME ) & 0xFF ); + *p++ = (unsigned char)( ( hostname_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( hostname_len ) & 0xFF ); + + memcpy( p, ssl->hostname, hostname_len ); + + *olen = hostname_len + 9; +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +static void ssl_write_renegotiation_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + + *olen = 0; + + /* We're always including an TLS_EMPTY_RENEGOTIATION_INFO_SCSV in the + * initial ClientHello, in which case also adding the renegotiation + * info extension is NOT RECOMMENDED as per RFC 5746 Section 3.4. */ + if( ssl->renego_status != MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding renegotiation extension" ) ); + + if( end < p || (size_t)( end - p ) < 5 + ssl->verify_data_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + /* + * Secure renegotiation + */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_RENEGOTIATION_INFO >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_RENEGOTIATION_INFO ) & 0xFF ); + + *p++ = 0x00; + *p++ = ( ssl->verify_data_len + 1 ) & 0xFF; + *p++ = ssl->verify_data_len & 0xFF; + + memcpy( p, ssl->own_verify_data, ssl->verify_data_len ); + + *olen = 5 + ssl->verify_data_len; +} +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/* + * Only if we handle at least one key exchange that needs signatures. + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +static void ssl_write_signature_algorithms_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + size_t sig_alg_len = 0; + const int *md; +#if defined(MBEDTLS_RSA_C) || defined(MBEDTLS_ECDSA_C) + unsigned char *sig_alg_list = buf + 6; +#endif + + *olen = 0; + + if( ssl->conf->max_minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding signature_algorithms extension" ) ); + + for( md = ssl->conf->sig_hashes; *md != MBEDTLS_MD_NONE; md++ ) + { +#if defined(MBEDTLS_ECDSA_C) + sig_alg_len += 2; +#endif +#if defined(MBEDTLS_RSA_C) + sig_alg_len += 2; +#endif + } + + if( end < p || (size_t)( end - p ) < sig_alg_len + 6 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + /* + * Prepare signature_algorithms extension (TLS 1.2) + */ + sig_alg_len = 0; + + for( md = ssl->conf->sig_hashes; *md != MBEDTLS_MD_NONE; md++ ) + { +#if defined(MBEDTLS_ECDSA_C) + sig_alg_list[sig_alg_len++] = mbedtls_ssl_hash_from_md_alg( *md ); + sig_alg_list[sig_alg_len++] = MBEDTLS_SSL_SIG_ECDSA; +#endif +#if defined(MBEDTLS_RSA_C) + sig_alg_list[sig_alg_len++] = mbedtls_ssl_hash_from_md_alg( *md ); + sig_alg_list[sig_alg_len++] = MBEDTLS_SSL_SIG_RSA; +#endif + } + + /* + * enum { + * none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), + * sha512(6), (255) + * } HashAlgorithm; + * + * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } + * SignatureAlgorithm; + * + * struct { + * HashAlgorithm hash; + * SignatureAlgorithm signature; + * } SignatureAndHashAlgorithm; + * + * SignatureAndHashAlgorithm + * supported_signature_algorithms<2..2^16-2>; + */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SIG_ALG >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SIG_ALG ) & 0xFF ); + + *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( sig_alg_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( sig_alg_len ) & 0xFF ); + + *olen = 6 + sig_alg_len; +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static void ssl_write_supported_elliptic_curves_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + unsigned char *elliptic_curve_list = p + 6; + size_t elliptic_curve_len = 0; + const mbedtls_ecp_curve_info *info; +#if defined(MBEDTLS_ECP_C) + const mbedtls_ecp_group_id *grp_id; +#else + ((void) ssl); +#endif + + *olen = 0; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding supported_elliptic_curves extension" ) ); + +#if defined(MBEDTLS_ECP_C) + for( grp_id = ssl->conf->curve_list; *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ ) +#else + for( info = mbedtls_ecp_curve_list(); info->grp_id != MBEDTLS_ECP_DP_NONE; info++ ) +#endif + { +#if defined(MBEDTLS_ECP_C) + info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); +#endif + if( info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid curve in ssl configuration" ) ); + return; + } + + elliptic_curve_len += 2; + } + + if( end < p || (size_t)( end - p ) < 6 + elliptic_curve_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + elliptic_curve_len = 0; + +#if defined(MBEDTLS_ECP_C) + for( grp_id = ssl->conf->curve_list; *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ ) +#else + for( info = mbedtls_ecp_curve_list(); info->grp_id != MBEDTLS_ECP_DP_NONE; info++ ) +#endif + { +#if defined(MBEDTLS_ECP_C) + info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); +#endif + elliptic_curve_list[elliptic_curve_len++] = info->tls_id >> 8; + elliptic_curve_list[elliptic_curve_len++] = info->tls_id & 0xFF; + } + + if( elliptic_curve_len == 0 ) + return; + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES ) & 0xFF ); + + *p++ = (unsigned char)( ( ( elliptic_curve_len + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( elliptic_curve_len + 2 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( ( elliptic_curve_len ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( elliptic_curve_len ) ) & 0xFF ); + + *olen = 6 + elliptic_curve_len; +} + +static void ssl_write_supported_point_formats_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + + *olen = 0; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding supported_point_formats extension" ) ); + + if( end < p || (size_t)( end - p ) < 6 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS ) & 0xFF ); + + *p++ = 0x00; + *p++ = 2; + + *p++ = 1; + *p++ = MBEDTLS_ECP_PF_UNCOMPRESSED; + + *olen = 6; +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static void ssl_write_ecjpake_kkpp_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + int ret; + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + size_t kkpp_len; + + *olen = 0; + + /* Skip costly extension if we can't use EC J-PAKE anyway */ + if( mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding ecjpake_kkpp extension" ) ); + + if( end - p < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ECJPAKE_KKPP >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ECJPAKE_KKPP ) & 0xFF ); + + /* + * We may need to send ClientHello multiple times for Hello verification. + * We don't want to compute fresh values every time (both for performance + * and consistency reasons), so cache the extension content. + */ + if( ssl->handshake->ecjpake_cache == NULL || + ssl->handshake->ecjpake_cache_len == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "generating new ecjpake parameters" ) ); + + ret = mbedtls_ecjpake_write_round_one( &ssl->handshake->ecjpake_ctx, + p + 2, end - p - 2, &kkpp_len, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1 , "mbedtls_ecjpake_write_round_one", ret ); + return; + } + + ssl->handshake->ecjpake_cache = mbedtls_calloc( 1, kkpp_len ); + if( ssl->handshake->ecjpake_cache == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "allocation failed" ) ); + return; + } + + memcpy( ssl->handshake->ecjpake_cache, p + 2, kkpp_len ); + ssl->handshake->ecjpake_cache_len = kkpp_len; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "re-using cached ecjpake parameters" ) ); + + kkpp_len = ssl->handshake->ecjpake_cache_len; + + if( (size_t)( end - p - 2 ) < kkpp_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + memcpy( p + 2, ssl->handshake->ecjpake_cache, kkpp_len ); + } + + *p++ = (unsigned char)( ( kkpp_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( kkpp_len ) & 0xFF ); + + *olen = kkpp_len + 4; +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +static void ssl_write_cid_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + size_t ext_len; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + + /* + * Quoting draft-ietf-tls-dtls-connection-id-05 + * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05 + * + * struct { + * opaque cid<0..2^8-1>; + * } ConnectionId; + */ + + *olen = 0; + if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM || + ssl->negotiate_cid == MBEDTLS_SSL_CID_DISABLED ) + { + return; + } + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding CID extension" ) ); + + /* ssl->own_cid_len is at most MBEDTLS_SSL_CID_IN_LEN_MAX + * which is at most 255, so the increment cannot overflow. */ + if( end < p || (size_t)( end - p ) < (unsigned)( ssl->own_cid_len + 5 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + /* Add extension ID + size */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_CID >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_CID ) & 0xFF ); + ext_len = (size_t) ssl->own_cid_len + 1; + *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_len ) & 0xFF ); + + *p++ = (uint8_t) ssl->own_cid_len; + memcpy( p, ssl->own_cid, ssl->own_cid_len ); + + *olen = ssl->own_cid_len + 5; +} +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static void ssl_write_max_fragment_length_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + + *olen = 0; + + if( ssl->conf->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE ) { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding max_fragment_length extension" ) ); + + if( end < p || (size_t)( end - p ) < 5 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH ) & 0xFF ); + + *p++ = 0x00; + *p++ = 1; + + *p++ = ssl->conf->mfl_code; + + *olen = 5; +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +static void ssl_write_truncated_hmac_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + + *olen = 0; + + if( ssl->conf->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_DISABLED ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding truncated_hmac extension" ) ); + + if( end < p || (size_t)( end - p ) < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_TRUNCATED_HMAC >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_TRUNCATED_HMAC ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +static void ssl_write_encrypt_then_mac_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + + *olen = 0; + + if( ssl->conf->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED || + ssl->conf->max_minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding encrypt_then_mac " + "extension" ) ); + + if( end < p || (size_t)( end - p ) < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +static void ssl_write_extended_ms_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + + *olen = 0; + + if( ssl->conf->extended_ms == MBEDTLS_SSL_EXTENDED_MS_DISABLED || + ssl->conf->max_minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding extended_master_secret " + "extension" ) ); + + if( end < p || (size_t)( end - p ) < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static void ssl_write_session_ticket_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + size_t tlen = ssl->session_negotiate->ticket_len; + + *olen = 0; + + if( ssl->conf->session_tickets == MBEDTLS_SSL_SESSION_TICKETS_DISABLED ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding session ticket extension" ) ); + + if( end < p || (size_t)( end - p ) < 4 + tlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SESSION_TICKET >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SESSION_TICKET ) & 0xFF ); + + *p++ = (unsigned char)( ( tlen >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( tlen ) & 0xFF ); + + *olen = 4; + + if( ssl->session_negotiate->ticket == NULL || tlen == 0 ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "sending session ticket of length %d", tlen ) ); + + memcpy( p, ssl->session_negotiate->ticket, tlen ); + + *olen += tlen; +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_ALPN) +static void ssl_write_alpn_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + size_t alpnlen = 0; + const char **cur; + + *olen = 0; + + if( ssl->conf->alpn_list == NULL ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding alpn extension" ) ); + + for( cur = ssl->conf->alpn_list; *cur != NULL; cur++ ) + alpnlen += (unsigned char)( strlen( *cur ) & 0xFF ) + 1; + + if( end < p || (size_t)( end - p ) < 6 + alpnlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN ) & 0xFF ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + */ + + /* Skip writing extension and list length for now */ + p += 4; + + for( cur = ssl->conf->alpn_list; *cur != NULL; cur++ ) + { + *p = (unsigned char)( strlen( *cur ) & 0xFF ); + memcpy( p + 1, *cur, *p ); + p += 1 + *p; + } + + *olen = p - buf; + + /* List length = olen - 2 (ext_type) - 2 (ext_len) - 2 (list_len) */ + buf[4] = (unsigned char)( ( ( *olen - 6 ) >> 8 ) & 0xFF ); + buf[5] = (unsigned char)( ( ( *olen - 6 ) ) & 0xFF ); + + /* Extension length = olen - 2 (ext_type) - 2 (ext_len) */ + buf[2] = (unsigned char)( ( ( *olen - 4 ) >> 8 ) & 0xFF ); + buf[3] = (unsigned char)( ( ( *olen - 4 ) ) & 0xFF ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +/* + * Generate random bytes for ClientHello + */ +static int ssl_generate_random( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *p = ssl->handshake->randbytes; +#if defined(MBEDTLS_HAVE_TIME) + mbedtls_time_t t; +#endif + + /* + * When responding to a verify request, MUST reuse random (RFC 6347 4.2.1) + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->verify_cookie != NULL ) + { + return( 0 ); + } +#endif + +#if defined(MBEDTLS_HAVE_TIME) + t = mbedtls_time( NULL ); + *p++ = (unsigned char)( t >> 24 ); + *p++ = (unsigned char)( t >> 16 ); + *p++ = (unsigned char)( t >> 8 ); + *p++ = (unsigned char)( t ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, current time: %lu", t ) ); +#else + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 4 ) ) != 0 ) + return( ret ); + + p += 4; +#endif /* MBEDTLS_HAVE_TIME */ + + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 28 ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/** + * \brief Validate cipher suite against config in SSL context. + * + * \param suite_info cipher suite to validate + * \param ssl SSL context + * \param min_minor_ver Minimal minor version to accept a cipher suite + * \param max_minor_ver Maximal minor version to accept a cipher suite + * + * \return 0 if valid, else 1 + */ +static int ssl_validate_ciphersuite( const mbedtls_ssl_ciphersuite_t * suite_info, + const mbedtls_ssl_context * ssl, + int min_minor_ver, int max_minor_ver ) +{ + (void) ssl; + if( suite_info == NULL ) + return( 1 ); + + if( suite_info->min_minor_ver > max_minor_ver || + suite_info->max_minor_ver < min_minor_ver ) + return( 1 ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( suite_info->flags & MBEDTLS_CIPHERSUITE_NODTLS ) ) + return( 1 ); +#endif + +#if defined(MBEDTLS_ARC4_C) + if( ssl->conf->arc4_disabled == MBEDTLS_SSL_ARC4_DISABLED && + suite_info->cipher == MBEDTLS_CIPHER_ARC4_128 ) + return( 1 ); +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( suite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE && + mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 ) + return( 1 ); +#endif + + /* Don't suggest PSK-based ciphersuite if no PSK is available. */ +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + if( mbedtls_ssl_ciphersuite_uses_psk( suite_info ) && + ssl_conf_has_static_psk( ssl->conf ) == 0 ) + { + return( 1 ); + } +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + + return( 0 ); +} + +static int ssl_write_client_hello( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t i, n, olen, ext_len = 0; + unsigned char *buf; + unsigned char *p, *q; + unsigned char offer_compress; + const int *ciphersuites; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + int uses_ec = 0; +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write client hello" ) ); + + if( ssl->conf->f_rng == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no RNG provided") ); + return( MBEDTLS_ERR_SSL_NO_RNG ); + } + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) +#endif + { + ssl->major_ver = ssl->conf->min_major_ver; + ssl->minor_ver = ssl->conf->min_minor_ver; + } + + if( ssl->conf->max_major_ver == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "configured max major version is invalid, " + "consider using mbedtls_ssl_config_defaults()" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 highest version supported + * 6 . 9 current UNIX time + * 10 . 37 random bytes + */ + buf = ssl->out_msg; + p = buf + 4; + + mbedtls_ssl_write_version( ssl->conf->max_major_ver, ssl->conf->max_minor_ver, + ssl->conf->transport, p ); + p += 2; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, max version: [%d:%d]", + buf[4], buf[5] ) ); + + if( ( ret = ssl_generate_random( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_generate_random", ret ); + return( ret ); + } + + memcpy( p, ssl->handshake->randbytes, 32 ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, random bytes", p, 32 ); + p += 32; + + /* + * 38 . 38 session id length + * 39 . 39+n session id + * 39+n . 39+n DTLS only: cookie length (1 byte) + * 40+n . .. DTSL only: cookie + * .. . .. ciphersuitelist length (2 bytes) + * .. . .. ciphersuitelist + * .. . .. compression methods length (1 byte) + * .. . .. compression methods + * .. . .. extensions length (2 bytes) + * .. . .. extensions + */ + n = ssl->session_negotiate->id_len; + + if( n < 16 || n > 32 || +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE || +#endif + ssl->handshake->resume == 0 ) + { + n = 0; + } + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + /* + * RFC 5077 section 3.4: "When presenting a ticket, the client MAY + * generate and include a Session ID in the TLS ClientHello." + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) +#endif + { + if( ssl->session_negotiate->ticket != NULL && + ssl->session_negotiate->ticket_len != 0 ) + { + ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->session_negotiate->id, 32 ); + + if( ret != 0 ) + return( ret ); + + ssl->session_negotiate->id_len = n = 32; + } + } +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + + *p++ = (unsigned char) n; + + for( i = 0; i < n; i++ ) + *p++ = ssl->session_negotiate->id[i]; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, session id len.: %d", n ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, session id", buf + 39, n ); + + /* + * DTLS cookie + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + if( ssl->handshake->verify_cookie == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no verify cookie to send" ) ); + *p++ = 0; + } + else + { + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, cookie", + ssl->handshake->verify_cookie, + ssl->handshake->verify_cookie_len ); + + *p++ = ssl->handshake->verify_cookie_len; + memcpy( p, ssl->handshake->verify_cookie, + ssl->handshake->verify_cookie_len ); + p += ssl->handshake->verify_cookie_len; + } + } +#endif + + /* + * Ciphersuite list + */ + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + + /* Skip writing ciphersuite length for now */ + n = 0; + q = p; + p += 2; + + for( i = 0; ciphersuites[i] != 0; i++ ) + { + ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuites[i] ); + + if( ssl_validate_ciphersuite( ciphersuite_info, ssl, + ssl->conf->min_minor_ver, + ssl->conf->max_minor_ver ) != 0 ) + continue; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, add ciphersuite: %04x", + ciphersuites[i] ) ); + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + uses_ec |= mbedtls_ssl_ciphersuite_uses_ec( ciphersuite_info ); +#endif + + n++; + *p++ = (unsigned char)( ciphersuites[i] >> 8 ); + *p++ = (unsigned char)( ciphersuites[i] ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, got %d ciphersuites (excluding SCSVs)", n ) ); + + /* + * Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "adding EMPTY_RENEGOTIATION_INFO_SCSV" ) ); + *p++ = (unsigned char)( MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO >> 8 ); + *p++ = (unsigned char)( MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO ); + n++; + } + + /* Some versions of OpenSSL don't handle it correctly if not at end */ +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) + if( ssl->conf->fallback == MBEDTLS_SSL_IS_FALLBACK ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "adding FALLBACK_SCSV" ) ); + *p++ = (unsigned char)( MBEDTLS_SSL_FALLBACK_SCSV_VALUE >> 8 ); + *p++ = (unsigned char)( MBEDTLS_SSL_FALLBACK_SCSV_VALUE ); + n++; + } +#endif + + *q++ = (unsigned char)( n >> 7 ); + *q++ = (unsigned char)( n << 1 ); + +#if defined(MBEDTLS_ZLIB_SUPPORT) + offer_compress = 1; +#else + offer_compress = 0; +#endif + + /* + * We don't support compression with DTLS right now: if many records come + * in the same datagram, uncompressing one could overwrite the next one. + * We don't want to add complexity for handling that case unless there is + * an actual need for it. + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + offer_compress = 0; +#endif + + if( offer_compress ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 2 ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d %d", + MBEDTLS_SSL_COMPRESS_DEFLATE, MBEDTLS_SSL_COMPRESS_NULL ) ); + + *p++ = 2; + *p++ = MBEDTLS_SSL_COMPRESS_DEFLATE; + *p++ = MBEDTLS_SSL_COMPRESS_NULL; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 1 ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d", + MBEDTLS_SSL_COMPRESS_NULL ) ); + + *p++ = 1; + *p++ = MBEDTLS_SSL_COMPRESS_NULL; + } + + // First write extensions, then the total length + // +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + ssl_write_hostname_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + + /* Note that TLS_EMPTY_RENEGOTIATION_INFO_SCSV is always added + * even if MBEDTLS_SSL_RENEGOTIATION is not defined. */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl_write_renegotiation_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + ssl_write_signature_algorithms_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( uses_ec ) + { + ssl_write_supported_elliptic_curves_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; + + ssl_write_supported_point_formats_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; + } +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl_write_ecjpake_kkpp_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + ssl_write_cid_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + ssl_write_max_fragment_length_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + ssl_write_truncated_hmac_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + ssl_write_encrypt_then_mac_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + ssl_write_extended_ms_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_ALPN) + ssl_write_alpn_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + ssl_write_session_ticket_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + + /* olen unused if all extensions are disabled */ + ((void) olen); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d", + ext_len ) ); + + if( ext_len > 0 ) + { + *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_len ) & 0xFF ); + p += ext_len; + } + + ssl->out_msglen = p - buf; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CLIENT_HELLO; + + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_send_flight_completed( ssl ); +#endif + + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); + return( ret ); + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write client hello" ) ); + + return( 0 ); +} + +static int ssl_parse_renegotiation_info( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + /* Check verify-data in constant-time. The length OTOH is no secret */ + if( len != 1 + ssl->verify_data_len * 2 || + buf[0] != ssl->verify_data_len * 2 || + mbedtls_ssl_safer_memcmp( buf + 1, + ssl->own_verify_data, ssl->verify_data_len ) != 0 || + mbedtls_ssl_safer_memcmp( buf + 1 + ssl->verify_data_len, + ssl->peer_verify_data, ssl->verify_data_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + } + else +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + { + if( len != 1 || buf[0] != 0x00 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-zero length renegotiation info" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ssl->secure_renegotiation = MBEDTLS_SSL_SECURE_RENEGOTIATION; + } + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static int ssl_parse_max_fragment_length_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + /* + * server should use the extension only if we did, + * and if so the server's value should match ours (and len is always 1) + */ + if( ssl->conf->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE || + len != 1 || + buf[0] != ssl->conf->mfl_code ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching max fragment length extension" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +static int ssl_parse_truncated_hmac_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( ssl->conf->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_DISABLED || + len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching truncated HMAC extension" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ((void) buf); + + ssl->session_negotiate->trunc_hmac = MBEDTLS_SSL_TRUNC_HMAC_ENABLED; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +static int ssl_parse_cid_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t peer_cid_len; + + if( /* CID extension only makes sense in DTLS */ + ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM || + /* The server must only send the CID extension if we have offered it. */ + ssl->negotiate_cid == MBEDTLS_SSL_CID_DISABLED ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "CID extension unexpected" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( len == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "CID extension invalid" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + peer_cid_len = *buf++; + len--; + + if( peer_cid_len > MBEDTLS_SSL_CID_OUT_LEN_MAX ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "CID extension invalid" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( len != peer_cid_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "CID extension invalid" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ssl->handshake->cid_in_use = MBEDTLS_SSL_CID_ENABLED; + ssl->handshake->peer_cid_len = (uint8_t) peer_cid_len; + memcpy( ssl->handshake->peer_cid, buf, peer_cid_len ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Use of CID extension negotiated" ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Server CID", buf, peer_cid_len ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +static int ssl_parse_encrypt_then_mac_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( ssl->conf->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 || + len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching encrypt-then-MAC extension" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ((void) buf); + + ssl->session_negotiate->encrypt_then_mac = MBEDTLS_SSL_ETM_ENABLED; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +static int ssl_parse_extended_ms_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( ssl->conf->extended_ms == MBEDTLS_SSL_EXTENDED_MS_DISABLED || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 || + len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching extended master secret extension" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ((void) buf); + + ssl->handshake->extended_ms = MBEDTLS_SSL_EXTENDED_MS_ENABLED; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static int ssl_parse_session_ticket_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( ssl->conf->session_tickets == MBEDTLS_SSL_SESSION_TICKETS_DISABLED || + len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching session ticket extension" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ((void) buf); + + ssl->handshake->new_session_ticket = 1; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static int ssl_parse_supported_point_formats_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t list_size; + const unsigned char *p; + + if( len == 0 || (size_t)( buf[0] + 1 ) != len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + list_size = buf[0]; + + p = buf + 1; + while( list_size > 0 ) + { + if( p[0] == MBEDTLS_ECP_PF_UNCOMPRESSED || + p[0] == MBEDTLS_ECP_PF_COMPRESSED ) + { +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + ssl->handshake->ecdh_ctx.point_format = p[0]; +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl->handshake->ecjpake_ctx.point_format = p[0]; +#endif + MBEDTLS_SSL_DEBUG_MSG( 4, ( "point format selected: %d", p[0] ) ); + return( 0 ); + } + + list_size--; + p++; + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no point format in common" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static int ssl_parse_ecjpake_kkpp( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + + if( ssl->handshake->ciphersuite_info->key_exchange != + MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip ecjpake kkpp extension" ) ); + return( 0 ); + } + + /* If we got here, we no longer need our cached extension */ + mbedtls_free( ssl->handshake->ecjpake_cache ); + ssl->handshake->ecjpake_cache = NULL; + ssl->handshake->ecjpake_cache_len = 0; + + if( ( ret = mbedtls_ecjpake_read_round_one( &ssl->handshake->ecjpake_ctx, + buf, len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_one", ret ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_ALPN) +static int ssl_parse_alpn_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + size_t list_len, name_len; + const char **p; + + /* If we didn't send it, the server shouldn't send it */ + if( ssl->conf->alpn_list == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching ALPN extension" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + * + * the "ProtocolNameList" MUST contain exactly one "ProtocolName" + */ + + /* Min length is 2 (list_len) + 1 (name_len) + 1 (name) */ + if( len < 4 ) + { + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + list_len = ( buf[0] << 8 ) | buf[1]; + if( list_len != len - 2 ) + { + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + name_len = buf[2]; + if( name_len != list_len - 1 ) + { + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* Check that the server chosen protocol was in our list and save it */ + for( p = ssl->conf->alpn_list; *p != NULL; p++ ) + { + if( name_len == strlen( *p ) && + memcmp( buf + 3, *p, name_len ) == 0 ) + { + ssl->alpn_chosen = *p; + return( 0 ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ALPN extension: no matching protocol" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +/* + * Parse HelloVerifyRequest. Only called after verifying the HS type. + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) +static int ssl_parse_hello_verify_request( mbedtls_ssl_context *ssl ) +{ + const unsigned char *p = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + int major_ver, minor_ver; + unsigned char cookie_len; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse hello verify request" ) ); + + /* + * struct { + * ProtocolVersion server_version; + * opaque cookie<0..2^8-1>; + * } HelloVerifyRequest; + */ + MBEDTLS_SSL_DEBUG_BUF( 3, "server version", p, 2 ); + mbedtls_ssl_read_version( &major_ver, &minor_ver, ssl->conf->transport, p ); + p += 2; + + /* + * Since the RFC is not clear on this point, accept DTLS 1.0 (TLS 1.1) + * even is lower than our min version. + */ + if( major_ver < MBEDTLS_SSL_MAJOR_VERSION_3 || + minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 || + major_ver > ssl->conf->max_major_ver || + minor_ver > ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server version" ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION ); + + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + cookie_len = *p++; + MBEDTLS_SSL_DEBUG_BUF( 3, "cookie", p, cookie_len ); + + if( ( ssl->in_msg + ssl->in_msglen ) - p < cookie_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "cookie length does not match incoming message size" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + mbedtls_free( ssl->handshake->verify_cookie ); + + ssl->handshake->verify_cookie = mbedtls_calloc( 1, cookie_len ); + if( ssl->handshake->verify_cookie == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed (%d bytes)", cookie_len ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + memcpy( ssl->handshake->verify_cookie, p, cookie_len ); + ssl->handshake->verify_cookie_len = cookie_len; + + /* Start over at ClientHello */ + ssl->state = MBEDTLS_SSL_CLIENT_HELLO; + mbedtls_ssl_reset_checksum( ssl ); + + mbedtls_ssl_recv_flight_completed( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse hello verify request" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +static int ssl_parse_server_hello( mbedtls_ssl_context *ssl ) +{ + int ret, i; + size_t n; + size_t ext_len; + unsigned char *buf, *ext; + unsigned char comp; +#if defined(MBEDTLS_ZLIB_SUPPORT) + int accept_comp; +#endif +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renegotiation_info_seen = 0; +#endif + int handshake_failure = 0; + const mbedtls_ssl_ciphersuite_t *suite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server hello" ) ); + + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) + { + /* No alert on a read error. */ + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + buf = ssl->in_msg; + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + ssl->renego_records_seen++; + + if( ssl->conf->renego_max_records >= 0 && + ssl->renego_records_seen > ssl->conf->renego_max_records ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation requested, " + "but not honored by server" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-handshake message during renego" ) ); + + ssl->keep_current_message = 1; + return( MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO ); + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + if( buf[0] == MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received hello verify request" ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse server hello" ) ); + return( ssl_parse_hello_verify_request( ssl ) ); + } + else + { + /* We made it through the verification process */ + mbedtls_free( ssl->handshake->verify_cookie ); + ssl->handshake->verify_cookie = NULL; + ssl->handshake->verify_cookie_len = 0; + } + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + if( ssl->in_hslen < 38 + mbedtls_ssl_hs_hdr_len( ssl ) || + buf[0] != MBEDTLS_SSL_HS_SERVER_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* + * 0 . 1 server_version + * 2 . 33 random (maybe including 4 bytes of Unix time) + * 34 . 34 session_id length = n + * 35 . 34+n session_id + * 35+n . 36+n cipher_suite + * 37+n . 37+n compression_method + * + * 38+n . 39+n extensions length (optional) + * 40+n . .. extensions + */ + buf += mbedtls_ssl_hs_hdr_len( ssl ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, version", buf + 0, 2 ); + mbedtls_ssl_read_version( &ssl->major_ver, &ssl->minor_ver, + ssl->conf->transport, buf + 0 ); + + if( ssl->major_ver < ssl->conf->min_major_ver || + ssl->minor_ver < ssl->conf->min_minor_ver || + ssl->major_ver > ssl->conf->max_major_ver || + ssl->minor_ver > ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server version out of bounds - " + " min: [%d:%d], server: [%d:%d], max: [%d:%d]", + ssl->conf->min_major_ver, ssl->conf->min_minor_ver, + ssl->major_ver, ssl->minor_ver, + ssl->conf->max_major_ver, ssl->conf->max_minor_ver ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION ); + + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu", + ( (uint32_t) buf[2] << 24 ) | + ( (uint32_t) buf[3] << 16 ) | + ( (uint32_t) buf[4] << 8 ) | + ( (uint32_t) buf[5] ) ) ); + + memcpy( ssl->handshake->randbytes + 32, buf + 2, 32 ); + + n = buf[34]; + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 2, 32 ); + + if( n > 32 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( ssl->in_hslen > mbedtls_ssl_hs_hdr_len( ssl ) + 39 + n ) + { + ext_len = ( ( buf[38 + n] << 8 ) + | ( buf[39 + n] ) ); + + if( ( ext_len > 0 && ext_len < 4 ) || + ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) + 40 + n + ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + } + else if( ssl->in_hslen == mbedtls_ssl_hs_hdr_len( ssl ) + 38 + n ) + { + ext_len = 0; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* ciphersuite (used later) */ + i = ( buf[35 + n] << 8 ) | buf[36 + n]; + + /* + * Read and check compression + */ + comp = buf[37 + n]; + +#if defined(MBEDTLS_ZLIB_SUPPORT) + /* See comments in ssl_write_client_hello() */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + accept_comp = 0; + else +#endif + accept_comp = 1; + + if( comp != MBEDTLS_SSL_COMPRESS_NULL && + ( comp != MBEDTLS_SSL_COMPRESS_DEFLATE || accept_comp == 0 ) ) +#else /* MBEDTLS_ZLIB_SUPPORT */ + if( comp != MBEDTLS_SSL_COMPRESS_NULL ) +#endif/* MBEDTLS_ZLIB_SUPPORT */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server hello, bad compression: %d", comp ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + /* + * Initialize update checksum functions + */ + ssl->handshake->ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( i ); + if( ssl->handshake->ciphersuite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ciphersuite info for %04x not found", i ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + mbedtls_ssl_optimize_checksum( ssl, ssl->handshake->ciphersuite_info ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, session id len.: %d", n ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, session id", buf + 35, n ); + + /* + * Check if the session can be resumed + */ + if( ssl->handshake->resume == 0 || n == 0 || +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE || +#endif + ssl->session_negotiate->ciphersuite != i || + ssl->session_negotiate->compression != comp || + ssl->session_negotiate->id_len != n || + memcmp( ssl->session_negotiate->id, buf + 35, n ) != 0 ) + { + ssl->state++; + ssl->handshake->resume = 0; +#if defined(MBEDTLS_HAVE_TIME) + ssl->session_negotiate->start = mbedtls_time( NULL ); +#endif + ssl->session_negotiate->ciphersuite = i; + ssl->session_negotiate->compression = comp; + ssl->session_negotiate->id_len = n; + memcpy( ssl->session_negotiate->id, buf + 35, n ); + } + else + { + ssl->state = MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC; + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR ); + return( ret ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "%s session has been resumed", + ssl->handshake->resume ? "a" : "no" ) ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %04x", i ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: %d", buf[37 + n] ) ); + + /* + * Perform cipher suite validation in same way as in ssl_write_client_hello. + */ + i = 0; + while( 1 ) + { + if( ssl->conf->ciphersuite_list[ssl->minor_ver][i] == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( ssl->conf->ciphersuite_list[ssl->minor_ver][i++] == + ssl->session_negotiate->ciphersuite ) + { + break; + } + } + + suite_info = mbedtls_ssl_ciphersuite_from_id( ssl->session_negotiate->ciphersuite ); + if( ssl_validate_ciphersuite( suite_info, ssl, ssl->minor_ver, ssl->minor_ver ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s", suite_info->name ) ); + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( suite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA && + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + ssl->handshake->ecrs_enabled = 1; + } +#endif + + if( comp != MBEDTLS_SSL_COMPRESS_NULL +#if defined(MBEDTLS_ZLIB_SUPPORT) + && comp != MBEDTLS_SSL_COMPRESS_DEFLATE +#endif + ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + ssl->session_negotiate->compression = comp; + + ext = buf + 40 + n; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "server hello, total extension length: %d", ext_len ) ); + + while( ext_len ) + { + unsigned int ext_id = ( ( ext[0] << 8 ) + | ( ext[1] ) ); + unsigned int ext_size = ( ( ext[2] << 8 ) + | ( ext[3] ) ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + switch( ext_id ) + { + case MBEDTLS_TLS_EXT_RENEGOTIATION_INFO: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found renegotiation extension" ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + renegotiation_info_seen = 1; +#endif + + if( ( ret = ssl_parse_renegotiation_info( ssl, ext + 4, + ext_size ) ) != 0 ) + return( ret ); + + break; + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + case MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found max_fragment_length extension" ) ); + + if( ( ret = ssl_parse_max_fragment_length_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + case MBEDTLS_TLS_EXT_TRUNCATED_HMAC: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found truncated_hmac extension" ) ); + + if( ( ret = ssl_parse_truncated_hmac_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + case MBEDTLS_TLS_EXT_CID: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found CID extension" ) ); + + if( ( ret = ssl_parse_cid_ext( ssl, + ext + 4, + ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + case MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found encrypt_then_mac extension" ) ); + + if( ( ret = ssl_parse_encrypt_then_mac_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + case MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found extended_master_secret extension" ) ); + + if( ( ret = ssl_parse_extended_ms_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + case MBEDTLS_TLS_EXT_SESSION_TICKET: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found session_ticket extension" ) ); + + if( ( ret = ssl_parse_session_ticket_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + case MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported_point_formats extension" ) ); + + if( ( ret = ssl_parse_supported_point_formats_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + case MBEDTLS_TLS_EXT_ECJPAKE_KKPP: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found ecjpake_kkpp extension" ) ); + + if( ( ret = ssl_parse_ecjpake_kkpp( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_ALPN) + case MBEDTLS_TLS_EXT_ALPN: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found alpn extension" ) ); + + if( ( ret = ssl_parse_alpn_ext( ssl, ext + 4, ext_size ) ) != 0 ) + return( ret ); + + break; +#endif /* MBEDTLS_SSL_ALPN */ + + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)", + ext_id ) ); + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + } + + /* + * Renegotiation security checks + */ + if( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); + handshake_failure = 1; + } +#if defined(MBEDTLS_SSL_RENEGOTIATION) + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_SECURE_RENEGOTIATION && + renegotiation_info_seen == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation_info extension missing (secure)" ) ); + handshake_failure = 1; + } + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation not allowed" ) ); + handshake_failure = 1; + } + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + renegotiation_info_seen == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation_info extension present (legacy)" ) ); + handshake_failure = 1; + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + if( handshake_failure == 1 ) + { + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse server hello" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) +static int ssl_parse_server_dh_params( mbedtls_ssl_context *ssl, unsigned char **p, + unsigned char *end ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + + /* + * Ephemeral DH parameters: + * + * struct { + * opaque dh_p<1..2^16-1>; + * opaque dh_g<1..2^16-1>; + * opaque dh_Ys<1..2^16-1>; + * } ServerDHParams; + */ + if( ( ret = mbedtls_dhm_read_params( &ssl->handshake->dhm_ctx, p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 2, ( "mbedtls_dhm_read_params" ), ret ); + return( ret ); + } + + if( ssl->handshake->dhm_ctx.len * 8 < ssl->conf->dhm_min_bitlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "DHM prime too short: %d < %d", + ssl->handshake->dhm_ctx.len * 8, + ssl->conf->dhm_min_bitlen ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->handshake->dhm_ctx.P ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: G ", &ssl->handshake->dhm_ctx.G ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: GY", &ssl->handshake->dhm_ctx.GY ); + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +static int ssl_check_server_ecdh_params( const mbedtls_ssl_context *ssl ) +{ + const mbedtls_ecp_curve_info *curve_info; + mbedtls_ecp_group_id grp_id; +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + grp_id = ssl->handshake->ecdh_ctx.grp.id; +#else + grp_id = ssl->handshake->ecdh_ctx.grp_id; +#endif + + curve_info = mbedtls_ecp_curve_info_from_grp_id( grp_id ); + if( curve_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDH curve: %s", curve_info->name ) ); + +#if defined(MBEDTLS_ECP_C) + if( mbedtls_ssl_check_curve( ssl, grp_id ) != 0 ) +#else + if( ssl->handshake->ecdh_ctx.grp.nbits < 163 || + ssl->handshake->ecdh_ctx.grp.nbits > 521 ) +#endif + return( -1 ); + + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_QP ); + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +#if defined(MBEDTLS_USE_PSA_CRYPTO) && \ + ( defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) ) +static int ssl_parse_server_ecdh_params_psa( mbedtls_ssl_context *ssl, + unsigned char **p, + unsigned char *end ) +{ + uint16_t tls_id; + uint8_t ecpoint_len; + mbedtls_ssl_handshake_params *handshake = ssl->handshake; + + /* + * Parse ECC group + */ + + if( end - *p < 4 ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + + /* First byte is curve_type; only named_curve is handled */ + if( *(*p)++ != MBEDTLS_ECP_TLS_NAMED_CURVE ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + + /* Next two bytes are the namedcurve value */ + tls_id = *(*p)++; + tls_id <<= 8; + tls_id |= *(*p)++; + + /* Convert EC group to PSA key type. */ + if( ( handshake->ecdh_psa_curve = + mbedtls_psa_parse_tls_ecc_group( tls_id ) ) == 0 ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + /* + * Put peer's ECDH public key in the format understood by PSA. + */ + + ecpoint_len = *(*p)++; + if( (size_t)( end - *p ) < ecpoint_len ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + + if( mbedtls_psa_tls_ecpoint_to_psa_ec( handshake->ecdh_psa_curve, + *p, ecpoint_len, + handshake->ecdh_psa_peerkey, + sizeof( handshake->ecdh_psa_peerkey ), + &handshake->ecdh_psa_peerkey_len ) != 0 ) + { + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + + *p += ecpoint_len; + return( 0 ); +} +#endif /* MBEDTLS_USE_PSA_CRYPTO && + ( MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED ) */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +static int ssl_parse_server_ecdh_params( mbedtls_ssl_context *ssl, + unsigned char **p, + unsigned char *end ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + + /* + * Ephemeral ECDH parameters: + * + * struct { + * ECParameters curve_params; + * ECPoint public; + * } ServerECDHParams; + */ + if( ( ret = mbedtls_ecdh_read_params( &ssl->handshake->ecdh_ctx, + (const unsigned char **) p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_read_params" ), ret ); +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS; +#endif + return( ret ); + } + + if( ssl_check_server_ecdh_params( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message (ECDHE curve)" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +static int ssl_parse_server_psk_hint( mbedtls_ssl_context *ssl, + unsigned char **p, + unsigned char *end ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t len; + ((void) ssl); + + /* + * PSK parameters: + * + * opaque psk_identity_hint<0..2^16-1>; + */ + if( end - (*p) < 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message " + "(psk_identity_hint length)" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + len = (*p)[0] << 8 | (*p)[1]; + *p += 2; + + if( end - (*p) < (int) len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message " + "(psk_identity_hint length)" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + /* + * Note: we currently ignore the PKS identity hint, as we only allow one + * PSK to be provisionned on the client. This could be changed later if + * someone needs that feature. + */ + *p += len; + ret = 0; + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) +/* + * Generate a pre-master secret and encrypt it with the server's RSA key + */ +static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl, + size_t offset, size_t *olen, + size_t pms_offset ) +{ + int ret; + size_t len_bytes = ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ? 0 : 2; + unsigned char *p = ssl->handshake->premaster + pms_offset; + mbedtls_pk_context * peer_pk; + + if( offset + len_bytes > MBEDTLS_SSL_OUT_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small for encrypted pms" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* + * Generate (part of) the pre-master as + * struct { + * ProtocolVersion client_version; + * opaque random[46]; + * } PreMasterSecret; + */ + mbedtls_ssl_write_version( ssl->conf->max_major_ver, ssl->conf->max_minor_ver, + ssl->conf->transport, p ); + + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p + 2, 46 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "f_rng", ret ); + return( ret ); + } + + ssl->handshake->pmslen = 48; + +#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + peer_pk = &ssl->handshake->peer_pubkey; +#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + if( ssl->session_negotiate->peer_cert == NULL ) + { + /* Should never happen */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + peer_pk = &ssl->session_negotiate->peer_cert->pk; +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + + /* + * Now write it out, encrypted + */ + if( ! mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_RSA ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate key type mismatch" ) ); + return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + } + + if( ( ret = mbedtls_pk_encrypt( peer_pk, + p, ssl->handshake->pmslen, + ssl->out_msg + offset + len_bytes, olen, + MBEDTLS_SSL_OUT_CONTENT_LEN - offset - len_bytes, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_rsa_pkcs1_encrypt", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( len_bytes == 2 ) + { + ssl->out_msg[offset+0] = (unsigned char)( *olen >> 8 ); + ssl->out_msg[offset+1] = (unsigned char)( *olen ); + *olen += 2; + } +#endif + +#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + /* We don't need the peer's public key anymore. Free it. */ + mbedtls_pk_free( peer_pk ); +#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_parse_signature_algorithm( mbedtls_ssl_context *ssl, + unsigned char **p, + unsigned char *end, + mbedtls_md_type_t *md_alg, + mbedtls_pk_type_t *pk_alg ) +{ + ((void) ssl); + *md_alg = MBEDTLS_MD_NONE; + *pk_alg = MBEDTLS_PK_NONE; + + /* Only in TLS 1.2 */ + if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) + { + return( 0 ); + } + + if( (*p) + 2 > end ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + + /* + * Get hash algorithm + */ + if( ( *md_alg = mbedtls_ssl_md_alg_from_hash( (*p)[0] ) ) == MBEDTLS_MD_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Server used unsupported " + "HashAlgorithm %d", *(p)[0] ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + /* + * Get signature algorithm + */ + if( ( *pk_alg = mbedtls_ssl_pk_alg_from_sig( (*p)[1] ) ) == MBEDTLS_PK_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server used unsupported " + "SignatureAlgorithm %d", (*p)[1] ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + /* + * Check if the hash is acceptable + */ + if( mbedtls_ssl_check_sig_hash( ssl, *md_alg ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server used HashAlgorithm %d that was not offered", + *(p)[0] ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Server used SignatureAlgorithm %d", (*p)[1] ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Server used HashAlgorithm %d", (*p)[0] ) ); + *p += 2; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl ) +{ + int ret; + const mbedtls_ecp_keypair *peer_key; + mbedtls_pk_context * peer_pk; + +#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + peer_pk = &ssl->handshake->peer_pubkey; +#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + if( ssl->session_negotiate->peer_cert == NULL ) + { + /* Should never happen */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + peer_pk = &ssl->session_negotiate->peer_cert->pk; +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + + if( ! mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_ECKEY ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key not ECDH capable" ) ); + return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + } + + peer_key = mbedtls_pk_ec( *peer_pk ); + + if( ( ret = mbedtls_ecdh_get_params( &ssl->handshake->ecdh_ctx, peer_key, + MBEDTLS_ECDH_THEIRS ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_get_params" ), ret ); + return( ret ); + } + + if( ssl_check_server_ecdh_params( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server certificate (ECDH curve)" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + +#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + /* We don't need the peer's public key anymore. Free it, + * so that more RAM is available for upcoming expensive + * operations like ECDHE. */ + mbedtls_pk_free( peer_pk ); +#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + unsigned char *p = NULL, *end = NULL; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server key exchange" ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse server key exchange" ) ); + ssl->state++; + return( 0 ); + } + ((void) p); + ((void) end); +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA ) + { + if( ( ret = ssl_get_ecdh_params_from_cert( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_get_ecdh_params_from_cert", ret ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse server key exchange" ) ); + ssl->state++; + return( 0 ); + } + ((void) p); + ((void) end); +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled && + ssl->handshake->ecrs_state == ssl_ecrs_ske_start_processing ) + { + goto start_processing; + } +#endif + + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* + * ServerKeyExchange may be skipped with PSK and RSA-PSK when the server + * doesn't use a psk_identity_hint + */ + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE ) + { + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + /* Current message is probably either + * CertificateRequest or ServerHelloDone */ + ssl->keep_current_message = 1; + goto exit; + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key exchange message must " + "not be skipped" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); + + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled ) + ssl->handshake->ecrs_state = ssl_ecrs_ske_start_processing; + +start_processing: +#endif + p = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + end = ssl->in_msg + ssl->in_hslen; + MBEDTLS_SSL_DEBUG_BUF( 3, "server key exchange", p, end - p ); + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + if( ssl_parse_server_psk_hint( ssl, &p, end ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } /* FALLTROUGH */ +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + ; /* nothing more to do */ + else +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED || + MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { + if( ssl_parse_server_dh_params( ssl, &p, end ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_USE_PSA_CRYPTO) && \ + ( defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) ) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + if( ssl_parse_server_ecdh_params_psa( ssl, &p, end ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } + else +#endif /* MBEDTLS_USE_PSA_CRYPTO && + ( MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED ) */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + if( ssl_parse_server_ecdh_params( ssl, &p, end ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + ret = mbedtls_ecjpake_read_round_two( &ssl->handshake->ecjpake_ctx, + p, end - p ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_two", ret ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) + if( mbedtls_ssl_ciphersuite_uses_server_signature( ciphersuite_info ) ) + { + size_t sig_len, hashlen; + unsigned char hash[64]; + mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE; + mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; + unsigned char *params = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + size_t params_len = p - params; + void *rs_ctx = NULL; + + mbedtls_pk_context * peer_pk; + + /* + * Handle the digitally-signed structure + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + if( ssl_parse_signature_algorithm( ssl, &p, end, + &md_alg, &pk_alg ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + if( pk_alg != mbedtls_ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 ) + { + pk_alg = mbedtls_ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ); + + /* Default hash for ECDSA is SHA-1 */ + if( pk_alg == MBEDTLS_PK_ECDSA && md_alg == MBEDTLS_MD_NONE ) + md_alg = MBEDTLS_MD_SHA1; + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* + * Read signature + */ + + if( p > end - 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + sig_len = ( p[0] << 8 ) | p[1]; + p += 2; + + if( p != end - sig_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "signature", p, sig_len ); + + /* + * Compute the hash that has been signed + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( md_alg == MBEDTLS_MD_NONE ) + { + hashlen = 36; + ret = mbedtls_ssl_get_key_exchange_md_ssl_tls( ssl, hash, params, + params_len ); + if( ret != 0 ) + return( ret ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || \ + MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( md_alg != MBEDTLS_MD_NONE ) + { + ret = mbedtls_ssl_get_key_exchange_md_tls1_2( ssl, hash, &hashlen, + params, params_len, + md_alg ); + if( ret != 0 ) + return( ret ); + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen ); + +#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + peer_pk = &ssl->handshake->peer_pubkey; +#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + if( ssl->session_negotiate->peer_cert == NULL ) + { + /* Should never happen */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + peer_pk = &ssl->session_negotiate->peer_cert->pk; +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + + /* + * Verify signature + */ + if( !mbedtls_pk_can_do( peer_pk, pk_alg ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + } + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled ) + rs_ctx = &ssl->handshake->ecrs_ctx.pk; +#endif + + if( ( ret = mbedtls_pk_verify_restartable( peer_pk, + md_alg, hash, hashlen, p, sig_len, rs_ctx ) ) != 0 ) + { +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) +#endif + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR ); + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret ); +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS; +#endif + return( ret ); + } + +#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + /* We don't need the peer's public key anymore. Free it, + * so that more RAM is available for upcoming expensive + * operations like ECDHE. */ + mbedtls_pk_free( peer_pk ); +#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + } +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ + +exit: + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse server key exchange" ) ); + + return( 0 ); +} + +#if ! defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED) +static int ssl_parse_certificate_request( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) ); + + if( ! mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate request" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} +#else /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */ +static int ssl_parse_certificate_request( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *buf; + size_t n = 0; + size_t cert_type_len = 0, dn_len = 0; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) ); + + if( ! mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate request" ) ); + ssl->state++; + return( 0 ); + } + + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + ssl->state++; + ssl->client_auth = ( ssl->in_msg[0] == MBEDTLS_SSL_HS_CERTIFICATE_REQUEST ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "got %s certificate request", + ssl->client_auth ? "a" : "no" ) ); + + if( ssl->client_auth == 0 ) + { + /* Current message is probably the ServerHelloDone */ + ssl->keep_current_message = 1; + goto exit; + } + + /* + * struct { + * ClientCertificateType certificate_types<1..2^8-1>; + * SignatureAndHashAlgorithm + * supported_signature_algorithms<2^16-1>; -- TLS 1.2 only + * DistinguishedName certificate_authorities<0..2^16-1>; + * } CertificateRequest; + * + * Since we only support a single certificate on clients, let's just + * ignore all the information that's supposed to help us pick a + * certificate. + * + * We could check that our certificate matches the request, and bail out + * if it doesn't, but it's simpler to just send the certificate anyway, + * and give the server the opportunity to decide if it should terminate + * the connection when it doesn't like our certificate. + * + * Same goes for the hash in TLS 1.2's signature_algorithms: at this + * point we only have one hash available (see comments in + * write_certificate_verify), so let's just use what we have. + * + * However, we still minimally parse the message to check it is at least + * superficially sane. + */ + buf = ssl->in_msg; + + /* certificate_types */ + if( ssl->in_hslen <= mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + cert_type_len = buf[mbedtls_ssl_hs_hdr_len( ssl )]; + n = cert_type_len; + + /* + * In the subsequent code there are two paths that read from buf: + * * the length of the signature algorithms field (if minor version of + * SSL is 3), + * * distinguished name length otherwise. + * Both reach at most the index: + * ...hdr_len + 2 + n, + * therefore the buffer length at this point must be greater than that + * regardless of the actual code path. + */ + if( ssl->in_hslen <= mbedtls_ssl_hs_hdr_len( ssl ) + 2 + n ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + + /* supported_signature_algorithms */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + size_t sig_alg_len = ( ( buf[mbedtls_ssl_hs_hdr_len( ssl ) + 1 + n] << 8 ) + | ( buf[mbedtls_ssl_hs_hdr_len( ssl ) + 2 + n] ) ); +#if defined(MBEDTLS_DEBUG_C) + unsigned char* sig_alg; + size_t i; +#endif + + /* + * The furthest access in buf is in the loop few lines below: + * sig_alg[i + 1], + * where: + * sig_alg = buf + ...hdr_len + 3 + n, + * max(i) = sig_alg_len - 1. + * Therefore the furthest access is: + * buf[...hdr_len + 3 + n + sig_alg_len - 1 + 1], + * which reduces to: + * buf[...hdr_len + 3 + n + sig_alg_len], + * which is one less than we need the buf to be. + */ + if( ssl->in_hslen <= mbedtls_ssl_hs_hdr_len( ssl ) + 3 + n + sig_alg_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + +#if defined(MBEDTLS_DEBUG_C) + sig_alg = buf + mbedtls_ssl_hs_hdr_len( ssl ) + 3 + n; + for( i = 0; i < sig_alg_len; i += 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Supported Signature Algorithm found: %d" + ",%d", sig_alg[i], sig_alg[i + 1] ) ); + } +#endif + + n += 2 + sig_alg_len; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + /* certificate_authorities */ + dn_len = ( ( buf[mbedtls_ssl_hs_hdr_len( ssl ) + 1 + n] << 8 ) + | ( buf[mbedtls_ssl_hs_hdr_len( ssl ) + 2 + n] ) ); + + n += dn_len; + if( ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) + 3 + n ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + +exit: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate request" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */ + +static int ssl_parse_server_hello_done( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server hello done" ) ); + + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello done message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) || + ssl->in_msg[0] != MBEDTLS_SSL_HS_SERVER_HELLO_DONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello done message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE ); + } + + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_recv_flight_completed( ssl ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse server hello done" ) ); + + return( 0 ); +} + +static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + + size_t header_len; + size_t content_len; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write client key exchange" ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA ) + { + /* + * DHM key exchange -- send G^X mod P + */ + content_len = ssl->handshake->dhm_ctx.len; + + ssl->out_msg[4] = (unsigned char)( content_len >> 8 ); + ssl->out_msg[5] = (unsigned char)( content_len ); + header_len = 6; + + ret = mbedtls_dhm_make_public( &ssl->handshake->dhm_ctx, + (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ), + &ssl->out_msg[header_len], content_len, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_public", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->handshake->dhm_ctx.X ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: GX", &ssl->handshake->dhm_ctx.GX ); + + if( ( ret = mbedtls_dhm_calc_secret( &ssl->handshake->dhm_ctx, + ssl->handshake->premaster, + MBEDTLS_PREMASTER_SIZE, + &ssl->handshake->pmslen, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->handshake->dhm_ctx.K ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ +#if defined(MBEDTLS_USE_PSA_CRYPTO) && \ + ( defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) ) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + psa_status_t status; + psa_key_policy_t policy; + + mbedtls_ssl_handshake_params *handshake = ssl->handshake; + + unsigned char own_pubkey[MBEDTLS_PSA_MAX_EC_PUBKEY_LENGTH]; + size_t own_pubkey_len; + unsigned char *own_pubkey_ecpoint; + size_t own_pubkey_ecpoint_len; + + psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT; + + header_len = 4; + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Perform PSA-based ECDH computation." ) ); + + /* + * Generate EC private key for ECDHE exchange. + */ + + /* Allocate a new key slot for the private key. */ + + status = psa_allocate_key( &handshake->ecdh_psa_privkey ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + + /* The master secret is obtained from the shared ECDH secret by + * applying the TLS 1.2 PRF with a specific salt and label. While + * the PSA Crypto API encourages combining key agreement schemes + * such as ECDH with fixed KDFs such as TLS 1.2 PRF, it does not + * yet support the provisioning of salt + label to the KDF. + * For the time being, we therefore need to split the computation + * of the ECDH secret and the application of the TLS 1.2 PRF. */ + policy = psa_key_policy_init(); + psa_key_policy_set_usage( &policy, + PSA_KEY_USAGE_DERIVE, + PSA_ALG_ECDH( PSA_ALG_SELECT_RAW ) ); + status = psa_set_key_policy( handshake->ecdh_psa_privkey, &policy ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + + /* Generate ECDH private key. */ + status = psa_generate_key( handshake->ecdh_psa_privkey, + PSA_KEY_TYPE_ECC_KEYPAIR( handshake->ecdh_psa_curve ), + MBEDTLS_PSA_ECC_KEY_BITS_OF_CURVE( handshake->ecdh_psa_curve ), + NULL, 0 ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + + /* Export the public part of the ECDH private key from PSA + * and convert it to ECPoint format used in ClientKeyExchange. */ + status = psa_export_public_key( handshake->ecdh_psa_privkey, + own_pubkey, sizeof( own_pubkey ), + &own_pubkey_len ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + + if( mbedtls_psa_tls_psa_ec_to_ecpoint( own_pubkey, + own_pubkey_len, + &own_pubkey_ecpoint, + &own_pubkey_ecpoint_len ) != 0 ) + { + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + + /* Copy ECPoint structure to outgoing message buffer. */ + ssl->out_msg[header_len] = (unsigned char) own_pubkey_ecpoint_len; + memcpy( ssl->out_msg + header_len + 1, + own_pubkey_ecpoint, own_pubkey_ecpoint_len ); + content_len = own_pubkey_ecpoint_len + 1; + + /* Compute ECDH shared secret. */ + status = psa_key_agreement( &generator, + handshake->ecdh_psa_privkey, + handshake->ecdh_psa_peerkey, + handshake->ecdh_psa_peerkey_len, + PSA_ALG_ECDH( PSA_ALG_SELECT_RAW ) ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + + /* The ECDH secret is the premaster secret used for key derivation. */ + + ssl->handshake->pmslen = + MBEDTLS_PSA_ECC_KEY_BYTES_OF_CURVE( handshake->ecdh_psa_curve ); + + status = psa_generator_read( &generator, + ssl->handshake->premaster, + ssl->handshake->pmslen ); + if( status != PSA_SUCCESS ) + { + psa_generator_abort( &generator ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + + status = psa_generator_abort( &generator ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + + status = psa_destroy_key( handshake->ecdh_psa_privkey ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + handshake->ecdh_psa_privkey = 0; + } + else +#endif /* MBEDTLS_USE_PSA_CRYPTO && + ( MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED ) */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA ) + { + /* + * ECDH key exchange -- send client public value + */ + header_len = 4; + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled ) + { + if( ssl->handshake->ecrs_state == ssl_ecrs_cke_ecdh_calc_secret ) + goto ecdh_calc_secret; + + mbedtls_ecdh_enable_restart( &ssl->handshake->ecdh_ctx ); + } +#endif + + ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx, + &content_len, + &ssl->out_msg[header_len], 1000, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_public", ret ); +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS; +#endif + return( ret ); + } + + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Q ); + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled ) + { + ssl->handshake->ecrs_n = content_len; + ssl->handshake->ecrs_state = ssl_ecrs_cke_ecdh_calc_secret; + } + +ecdh_calc_secret: + if( ssl->handshake->ecrs_enabled ) + content_len = ssl->handshake->ecrs_n; +#endif + if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, + &ssl->handshake->pmslen, + ssl->handshake->premaster, + MBEDTLS_MPI_MAX_SIZE, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret ); +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS; +#endif + return( ret ); + } + + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Z ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + if( mbedtls_ssl_ciphersuite_uses_psk( ciphersuite_info ) ) + { + /* + * opaque psk_identity<0..2^16-1>; + */ + if( ssl_conf_has_static_psk( ssl->conf ) == 0 ) + { + /* We don't offer PSK suites if we don't have a PSK, + * and we check that the server's choice is among the + * ciphersuites we offered, so this should never happen. */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + header_len = 4; + content_len = ssl->conf->psk_identity_len; + + if( header_len + 2 + content_len > MBEDTLS_SSL_OUT_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "psk identity too long or " + "SSL buffer too short" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + ssl->out_msg[header_len++] = (unsigned char)( content_len >> 8 ); + ssl->out_msg[header_len++] = (unsigned char)( content_len ); + + memcpy( ssl->out_msg + header_len, + ssl->conf->psk_identity, + ssl->conf->psk_identity_len ); + header_len += ssl->conf->psk_identity_len; + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ) + { + content_len = 0; + } + else +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { +#if defined(MBEDTLS_USE_PSA_CRYPTO) + /* Opaque PSKs are currently only supported for PSK-only suites. */ + if( ssl_conf_has_static_raw_psk( ssl->conf ) == 0 ) + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + if( ( ret = ssl_write_encrypted_pms( ssl, header_len, + &content_len, 2 ) ) != 0 ) + return( ret ); + } + else +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { +#if defined(MBEDTLS_USE_PSA_CRYPTO) + /* Opaque PSKs are currently only supported for PSK-only suites. */ + if( ssl_conf_has_static_raw_psk( ssl->conf ) == 0 ) + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + /* + * ClientDiffieHellmanPublic public (DHM send G^X mod P) + */ + content_len = ssl->handshake->dhm_ctx.len; + + if( header_len + 2 + content_len > + MBEDTLS_SSL_OUT_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "psk identity or DHM size too long" + " or SSL buffer too short" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + ssl->out_msg[header_len++] = (unsigned char)( content_len >> 8 ); + ssl->out_msg[header_len++] = (unsigned char)( content_len ); + + ret = mbedtls_dhm_make_public( &ssl->handshake->dhm_ctx, + (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ), + &ssl->out_msg[header_len], content_len, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_public", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { +#if defined(MBEDTLS_USE_PSA_CRYPTO) + /* Opaque PSKs are currently only supported for PSK-only suites. */ + if( ssl_conf_has_static_raw_psk( ssl->conf ) == 0 ) + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + /* + * ClientECDiffieHellmanPublic public; + */ + ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx, + &content_len, + &ssl->out_msg[header_len], + MBEDTLS_SSL_OUT_CONTENT_LEN - header_len, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_public", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Q ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_USE_PSA_CRYPTO) && \ + defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK && + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 && + ssl_conf_has_static_raw_psk( ssl->conf ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "skip PMS generation for opaque PSK" ) ); + } + else +#endif /* MBEDTLS_USE_PSA_CRYPTO && + MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA ) + { + header_len = 4; + if( ( ret = ssl_write_encrypted_pms( ssl, header_len, + &content_len, 0 ) ) != 0 ) + return( ret ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + header_len = 4; + + ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx, + ssl->out_msg + header_len, + MBEDTLS_SSL_OUT_CONTENT_LEN - header_len, + &content_len, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_write_round_two", ret ); + return( ret ); + } + + ret = mbedtls_ecjpake_derive_secret( &ssl->handshake->ecjpake_ctx, + ssl->handshake->premaster, 32, &ssl->handshake->pmslen, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_derive_secret", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ + { + ((void) ciphersuite_info); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->out_msglen = header_len + content_len; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE; + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write client key exchange" ) ); + + return( 0 ); +} + +#if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED) +static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) ); + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + return( ret ); + } + + if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} +#else /* !MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */ +static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + size_t n = 0, offset = 0; + unsigned char hash[48]; + unsigned char *hash_start = hash; + mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE; + unsigned int hashlen; + void *rs_ctx = NULL; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) ); + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled && + ssl->handshake->ecrs_state == ssl_ecrs_crt_vrfy_sign ) + { + goto sign; + } +#endif + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + return( ret ); + } + + if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + if( ssl->client_auth == 0 || mbedtls_ssl_own_cert( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + if( mbedtls_ssl_own_key( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key for certificate" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* + * Make a signature of the handshake digests + */ +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled ) + ssl->handshake->ecrs_state = ssl_ecrs_crt_vrfy_sign; + +sign: +#endif + + ssl->handshake->calc_verify( ssl, hash ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) + { + /* + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * + * md5_hash + * MD5(handshake_messages); + * + * sha_hash + * SHA(handshake_messages); + */ + hashlen = 36; + md_alg = MBEDTLS_MD_NONE; + + /* + * For ECDSA, default hash is SHA-1 only + */ + if( mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_ECDSA ) ) + { + hash_start += 16; + hashlen -= 16; + md_alg = MBEDTLS_MD_SHA1; + } + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || \ + MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + /* + * digitally-signed struct { + * opaque handshake_messages[handshake_messages_length]; + * }; + * + * Taking shortcut here. We assume that the server always allows the + * PRF Hash function and has sent it in the allowed signature + * algorithms list received in the Certificate Request message. + * + * Until we encounter a server that does not, we will take this + * shortcut. + * + * Reason: Otherwise we should have running hashes for SHA512 and SHA224 + * in order to satisfy 'weird' needs from the server side. + */ + if( ssl->handshake->ciphersuite_info->mac == MBEDTLS_MD_SHA384 ) + { + md_alg = MBEDTLS_MD_SHA384; + ssl->out_msg[4] = MBEDTLS_SSL_HASH_SHA384; + } + else + { + md_alg = MBEDTLS_MD_SHA256; + ssl->out_msg[4] = MBEDTLS_SSL_HASH_SHA256; + } + ssl->out_msg[5] = mbedtls_ssl_sig_from_pk( mbedtls_ssl_own_key( ssl ) ); + + /* Info from md_alg will be used instead */ + hashlen = 0; + offset = 2; + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled ) + rs_ctx = &ssl->handshake->ecrs_ctx.pk; +#endif + + if( ( ret = mbedtls_pk_sign_restartable( mbedtls_ssl_own_key( ssl ), + md_alg, hash_start, hashlen, + ssl->out_msg + 6 + offset, &n, + ssl->conf->f_rng, ssl->conf->p_rng, rs_ctx ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret ); +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + ret = MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS; +#endif + return( ret ); + } + + ssl->out_msg[4 + offset] = (unsigned char)( n >> 8 ); + ssl->out_msg[5 + offset] = (unsigned char)( n ); + + ssl->out_msglen = 6 + n + offset; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE_VERIFY; + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate verify" ) ); + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static int ssl_parse_new_session_ticket( mbedtls_ssl_context *ssl ) +{ + int ret; + uint32_t lifetime; + size_t ticket_len; + unsigned char *ticket; + const unsigned char *msg; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse new session ticket" ) ); + + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* + * struct { + * uint32 ticket_lifetime_hint; + * opaque ticket<0..2^16-1>; + * } NewSessionTicket; + * + * 0 . 3 ticket_lifetime_hint + * 4 . 5 ticket_len (n) + * 6 . 5+n ticket content + */ + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_NEW_SESSION_TICKET || + ssl->in_hslen < 6 + mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET ); + } + + msg = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + + lifetime = ( ((uint32_t) msg[0]) << 24 ) | ( msg[1] << 16 ) | + ( msg[2] << 8 ) | ( msg[3] ); + + ticket_len = ( msg[4] << 8 ) | ( msg[5] ); + + if( ticket_len + 6 + mbedtls_ssl_hs_hdr_len( ssl ) != ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket length: %d", ticket_len ) ); + + /* We're not waiting for a NewSessionTicket message any more */ + ssl->handshake->new_session_ticket = 0; + ssl->state = MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC; + + /* + * Zero-length ticket means the server changed his mind and doesn't want + * to send a ticket after all, so just forget it + */ + if( ticket_len == 0 ) + return( 0 ); + + if( ssl->session != NULL && ssl->session->ticket != NULL ) + { + mbedtls_platform_zeroize( ssl->session->ticket, + ssl->session->ticket_len ); + mbedtls_free( ssl->session->ticket ); + ssl->session->ticket = NULL; + ssl->session->ticket_len = 0; + } + + mbedtls_platform_zeroize( ssl->session_negotiate->ticket, + ssl->session_negotiate->ticket_len ); + mbedtls_free( ssl->session_negotiate->ticket ); + ssl->session_negotiate->ticket = NULL; + ssl->session_negotiate->ticket_len = 0; + + if( ( ticket = mbedtls_calloc( 1, ticket_len ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ticket alloc failed" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + memcpy( ticket, msg + 6, ticket_len ); + + ssl->session_negotiate->ticket = ticket; + ssl->session_negotiate->ticket_len = ticket_len; + ssl->session_negotiate->ticket_lifetime = lifetime; + + /* + * RFC 5077 section 3.4: + * "If the client receives a session ticket from the server, then it + * discards any Session ID that was sent in the ServerHello." + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket in use, discarding session id" ) ); + ssl->session_negotiate->id_len = 0; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse new session ticket" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +/* + * SSL handshake -- client side -- single step + */ +int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) ); + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) + { + if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + return( ret ); + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + /* Change state now, so that it is right in mbedtls_ssl_read_record(), used + * by DTLS for dropping out-of-sequence ChangeCipherSpec records */ +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + if( ssl->state == MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC && + ssl->handshake->new_session_ticket != 0 ) + { + ssl->state = MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET; + } +#endif + + switch( ssl->state ) + { + case MBEDTLS_SSL_HELLO_REQUEST: + ssl->state = MBEDTLS_SSL_CLIENT_HELLO; + break; + + /* + * ==> ClientHello + */ + case MBEDTLS_SSL_CLIENT_HELLO: + ret = ssl_write_client_hello( ssl ); + break; + + /* + * <== ServerHello + * Certificate + * ( ServerKeyExchange ) + * ( CertificateRequest ) + * ServerHelloDone + */ + case MBEDTLS_SSL_SERVER_HELLO: + ret = ssl_parse_server_hello( ssl ); + break; + + case MBEDTLS_SSL_SERVER_CERTIFICATE: + ret = mbedtls_ssl_parse_certificate( ssl ); + break; + + case MBEDTLS_SSL_SERVER_KEY_EXCHANGE: + ret = ssl_parse_server_key_exchange( ssl ); + break; + + case MBEDTLS_SSL_CERTIFICATE_REQUEST: + ret = ssl_parse_certificate_request( ssl ); + break; + + case MBEDTLS_SSL_SERVER_HELLO_DONE: + ret = ssl_parse_server_hello_done( ssl ); + break; + + /* + * ==> ( Certificate/Alert ) + * ClientKeyExchange + * ( CertificateVerify ) + * ChangeCipherSpec + * Finished + */ + case MBEDTLS_SSL_CLIENT_CERTIFICATE: + ret = mbedtls_ssl_write_certificate( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE: + ret = ssl_write_client_key_exchange( ssl ); + break; + + case MBEDTLS_SSL_CERTIFICATE_VERIFY: + ret = ssl_write_certificate_verify( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC: + ret = mbedtls_ssl_write_change_cipher_spec( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_FINISHED: + ret = mbedtls_ssl_write_finished( ssl ); + break; + + /* + * <== ( NewSessionTicket ) + * ChangeCipherSpec + * Finished + */ +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + case MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET: + ret = ssl_parse_new_session_ticket( ssl ); + break; +#endif + + case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC: + ret = mbedtls_ssl_parse_change_cipher_spec( ssl ); + break; + + case MBEDTLS_SSL_SERVER_FINISHED: + ret = mbedtls_ssl_parse_finished( ssl ); + break; + + case MBEDTLS_SSL_FLUSH_BUFFERS: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake: done" ) ); + ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP; + break; + + case MBEDTLS_SSL_HANDSHAKE_WRAPUP: + mbedtls_ssl_handshake_wrapup( ssl ); + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + return( ret ); +} +#endif /* MBEDTLS_SSL_CLI_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ssl_cookie.c b/FreeRTOS-Labs/Source/mbedtls/library/ssl_cookie.c new file mode 100644 index 000000000..7c7764a4f --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ssl_cookie.c @@ -0,0 +1,256 @@ +/* + * DTLS cookie callbacks implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * These session callbacks use a simple chained list + * to store and retrieve the session information. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_COOKIE_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/ssl_cookie.h" +#include "mbedtls/ssl_internal.h" +#include "mbedtls/platform_util.h" + +#include + +/* + * If DTLS is in use, then at least one of SHA-1, SHA-256, SHA-512 is + * available. Try SHA-256 first, 512 wastes resources since we need to stay + * with max 32 bytes of cookie for DTLS 1.0 + */ +#if defined(MBEDTLS_SHA256_C) +#define COOKIE_MD MBEDTLS_MD_SHA224 +#define COOKIE_MD_OUTLEN 32 +#define COOKIE_HMAC_LEN 28 +#elif defined(MBEDTLS_SHA512_C) +#define COOKIE_MD MBEDTLS_MD_SHA384 +#define COOKIE_MD_OUTLEN 48 +#define COOKIE_HMAC_LEN 28 +#elif defined(MBEDTLS_SHA1_C) +#define COOKIE_MD MBEDTLS_MD_SHA1 +#define COOKIE_MD_OUTLEN 20 +#define COOKIE_HMAC_LEN 20 +#else +#error "DTLS hello verify needs SHA-1 or SHA-2" +#endif + +/* + * Cookies are formed of a 4-bytes timestamp (or serial number) and + * an HMAC of timestemp and client ID. + */ +#define COOKIE_LEN ( 4 + COOKIE_HMAC_LEN ) + +void mbedtls_ssl_cookie_init( mbedtls_ssl_cookie_ctx *ctx ) +{ + mbedtls_md_init( &ctx->hmac_ctx ); +#if !defined(MBEDTLS_HAVE_TIME) + ctx->serial = 0; +#endif + ctx->timeout = MBEDTLS_SSL_COOKIE_TIMEOUT; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +void mbedtls_ssl_cookie_set_timeout( mbedtls_ssl_cookie_ctx *ctx, unsigned long delay ) +{ + ctx->timeout = delay; +} + +void mbedtls_ssl_cookie_free( mbedtls_ssl_cookie_ctx *ctx ) +{ + mbedtls_md_free( &ctx->hmac_ctx ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ssl_cookie_ctx ) ); +} + +int mbedtls_ssl_cookie_setup( mbedtls_ssl_cookie_ctx *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char key[COOKIE_MD_OUTLEN]; + + if( ( ret = f_rng( p_rng, key, sizeof( key ) ) ) != 0 ) + return( ret ); + + ret = mbedtls_md_setup( &ctx->hmac_ctx, mbedtls_md_info_from_type( COOKIE_MD ), 1 ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_md_hmac_starts( &ctx->hmac_ctx, key, sizeof( key ) ); + if( ret != 0 ) + return( ret ); + + mbedtls_platform_zeroize( key, sizeof( key ) ); + + return( 0 ); +} + +/* + * Generate the HMAC part of a cookie + */ +static int ssl_cookie_hmac( mbedtls_md_context_t *hmac_ctx, + const unsigned char time[4], + unsigned char **p, unsigned char *end, + const unsigned char *cli_id, size_t cli_id_len ) +{ + unsigned char hmac_out[COOKIE_MD_OUTLEN]; + + if( (size_t)( end - *p ) < COOKIE_HMAC_LEN ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + if( mbedtls_md_hmac_reset( hmac_ctx ) != 0 || + mbedtls_md_hmac_update( hmac_ctx, time, 4 ) != 0 || + mbedtls_md_hmac_update( hmac_ctx, cli_id, cli_id_len ) != 0 || + mbedtls_md_hmac_finish( hmac_ctx, hmac_out ) != 0 ) + { + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + memcpy( *p, hmac_out, COOKIE_HMAC_LEN ); + *p += COOKIE_HMAC_LEN; + + return( 0 ); +} + +/* + * Generate cookie for DTLS ClientHello verification + */ +int mbedtls_ssl_cookie_write( void *p_ctx, + unsigned char **p, unsigned char *end, + const unsigned char *cli_id, size_t cli_id_len ) +{ + int ret; + mbedtls_ssl_cookie_ctx *ctx = (mbedtls_ssl_cookie_ctx *) p_ctx; + unsigned long t; + + if( ctx == NULL || cli_id == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( (size_t)( end - *p ) < COOKIE_LEN ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + +#if defined(MBEDTLS_HAVE_TIME) + t = (unsigned long) mbedtls_time( NULL ); +#else + t = ctx->serial++; +#endif + + (*p)[0] = (unsigned char)( t >> 24 ); + (*p)[1] = (unsigned char)( t >> 16 ); + (*p)[2] = (unsigned char)( t >> 8 ); + (*p)[3] = (unsigned char)( t ); + *p += 4; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR + ret ); +#endif + + ret = ssl_cookie_hmac( &ctx->hmac_ctx, *p - 4, + p, end, cli_id, cli_id_len ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR + + MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Check a cookie + */ +int mbedtls_ssl_cookie_check( void *p_ctx, + const unsigned char *cookie, size_t cookie_len, + const unsigned char *cli_id, size_t cli_id_len ) +{ + unsigned char ref_hmac[COOKIE_HMAC_LEN]; + int ret = 0; + unsigned char *p = ref_hmac; + mbedtls_ssl_cookie_ctx *ctx = (mbedtls_ssl_cookie_ctx *) p_ctx; + unsigned long cur_time, cookie_time; + + if( ctx == NULL || cli_id == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( cookie_len != COOKIE_LEN ) + return( -1 ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR + ret ); +#endif + + if( ssl_cookie_hmac( &ctx->hmac_ctx, cookie, + &p, p + sizeof( ref_hmac ), + cli_id, cli_id_len ) != 0 ) + ret = -1; + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR + + MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + if( ret != 0 ) + return( ret ); + + if( mbedtls_ssl_safer_memcmp( cookie + 4, ref_hmac, sizeof( ref_hmac ) ) != 0 ) + return( -1 ); + +#if defined(MBEDTLS_HAVE_TIME) + cur_time = (unsigned long) mbedtls_time( NULL ); +#else + cur_time = ctx->serial; +#endif + + cookie_time = ( (unsigned long) cookie[0] << 24 ) | + ( (unsigned long) cookie[1] << 16 ) | + ( (unsigned long) cookie[2] << 8 ) | + ( (unsigned long) cookie[3] ); + + if( ctx->timeout != 0 && cur_time - cookie_time > ctx->timeout ) + return( -1 ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_COOKIE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ssl_srv.c b/FreeRTOS-Labs/Source/mbedtls/library/ssl_srv.c new file mode 100644 index 000000000..c5331213f --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ssl_srv.c @@ -0,0 +1,4573 @@ +/* + * SSLv3/TLSv1 server-side functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_SRV_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif + +#if defined(MBEDTLS_HAVE_TIME) +#include "mbedtls/platform_time.h" +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) +int mbedtls_ssl_set_client_transport_id( mbedtls_ssl_context *ssl, + const unsigned char *info, + size_t ilen ) +{ + if( ssl->conf->endpoint != MBEDTLS_SSL_IS_SERVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + mbedtls_free( ssl->cli_id ); + + if( ( ssl->cli_id = mbedtls_calloc( 1, ilen ) ) == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( ssl->cli_id, info, ilen ); + ssl->cli_id_len = ilen; + + return( 0 ); +} + +void mbedtls_ssl_conf_dtls_cookies( mbedtls_ssl_config *conf, + mbedtls_ssl_cookie_write_t *f_cookie_write, + mbedtls_ssl_cookie_check_t *f_cookie_check, + void *p_cookie ) +{ + conf->f_cookie_write = f_cookie_write; + conf->f_cookie_check = f_cookie_check; + conf->p_cookie = p_cookie; +} +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +static int ssl_parse_servername_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + size_t servername_list_size, hostname_len; + const unsigned char *p; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "parse ServerName extension" ) ); + + if( len < 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + servername_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( servername_list_size + 2 != len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + p = buf + 2; + while( servername_list_size > 2 ) + { + hostname_len = ( ( p[1] << 8 ) | p[2] ); + if( hostname_len + 3 > servername_list_size ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( p[0] == MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME ) + { + ret = ssl->conf->f_sni( ssl->conf->p_sni, + ssl, p + 3, hostname_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_sni_wrapper", ret ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + return( 0 ); + } + + servername_list_size -= hostname_len + 3; + p += hostname_len + 3; + } + + if( servername_list_size != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +static int ssl_conf_has_psk_or_cb( mbedtls_ssl_config const *conf ) +{ + if( conf->f_psk != NULL ) + return( 1 ); + + if( conf->psk_identity_len == 0 || conf->psk_identity == NULL ) + return( 0 ); + + if( conf->psk != NULL && conf->psk_len != 0 ) + return( 1 ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( conf->psk_opaque != 0 ) + return( 1 ); +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + return( 0 ); +} + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +static int ssl_use_opaque_psk( mbedtls_ssl_context const *ssl ) +{ + if( ssl->conf->f_psk != NULL ) + { + /* If we've used a callback to select the PSK, + * the static configuration is irrelevant. */ + + if( ssl->handshake->psk_opaque != 0 ) + return( 1 ); + + return( 0 ); + } + + if( ssl->conf->psk_opaque != 0 ) + return( 1 ); + + return( 0 ); +} +#endif /* MBEDTLS_USE_PSA_CRYPTO */ +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +static int ssl_parse_renegotiation_info( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + /* Check verify-data in constant-time. The length OTOH is no secret */ + if( len != 1 + ssl->verify_data_len || + buf[0] != ssl->verify_data_len || + mbedtls_ssl_safer_memcmp( buf + 1, ssl->peer_verify_data, + ssl->verify_data_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } + else +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + { + if( len != 1 || buf[0] != 0x0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-zero length renegotiation info" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->secure_renegotiation = MBEDTLS_SSL_SECURE_RENEGOTIATION; + } + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + +/* + * Status of the implementation of signature-algorithms extension: + * + * Currently, we are only considering the signature-algorithm extension + * to pick a ciphersuite which allows us to send the ServerKeyExchange + * message with a signature-hash combination that the user allows. + * + * We do *not* check whether all certificates in our certificate + * chain are signed with an allowed signature-hash pair. + * This needs to be done at a later stage. + * + */ +static int ssl_parse_signature_algorithms_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t sig_alg_list_size; + + const unsigned char *p; + const unsigned char *end = buf + len; + + mbedtls_md_type_t md_cur; + mbedtls_pk_type_t sig_cur; + + if ( len < 2 ) { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + sig_alg_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( sig_alg_list_size + 2 != len || + sig_alg_list_size % 2 != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* Currently we only guarantee signing the ServerKeyExchange message according + * to the constraints specified in this extension (see above), so it suffices + * to remember only one suitable hash for each possible signature algorithm. + * + * This will change when we also consider certificate signatures, + * in which case we will need to remember the whole signature-hash + * pair list from the extension. + */ + + for( p = buf + 2; p < end; p += 2 ) + { + /* Silently ignore unknown signature or hash algorithms. */ + + if( ( sig_cur = mbedtls_ssl_pk_alg_from_sig( p[1] ) ) == MBEDTLS_PK_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext" + " unknown sig alg encoding %d", p[1] ) ); + continue; + } + + /* Check if we support the hash the user proposes */ + md_cur = mbedtls_ssl_md_alg_from_hash( p[0] ); + if( md_cur == MBEDTLS_MD_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext:" + " unknown hash alg encoding %d", p[0] ) ); + continue; + } + + if( mbedtls_ssl_check_sig_hash( ssl, md_cur ) == 0 ) + { + mbedtls_ssl_sig_hash_set_add( &ssl->handshake->hash_algs, sig_cur, md_cur ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext:" + " match sig %d and hash %d", + sig_cur, md_cur ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext: " + "hash alg %d not supported", md_cur ) ); + } + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static int ssl_parse_supported_elliptic_curves( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t list_size, our_size; + const unsigned char *p; + const mbedtls_ecp_curve_info *curve_info, **curves; + + if ( len < 2 ) { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( list_size + 2 != len || + list_size % 2 != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* Should never happen unless client duplicates the extension */ + if( ssl->handshake->curves != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* Don't allow our peer to make us allocate too much memory, + * and leave room for a final 0 */ + our_size = list_size / 2 + 1; + if( our_size > MBEDTLS_ECP_DP_MAX ) + our_size = MBEDTLS_ECP_DP_MAX; + + if( ( curves = mbedtls_calloc( our_size, sizeof( *curves ) ) ) == NULL ) + { + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + ssl->handshake->curves = curves; + + p = buf + 2; + while( list_size > 0 && our_size > 1 ) + { + curve_info = mbedtls_ecp_curve_info_from_tls_id( ( p[0] << 8 ) | p[1] ); + + if( curve_info != NULL ) + { + *curves++ = curve_info; + our_size--; + } + + list_size -= 2; + p += 2; + } + + return( 0 ); +} + +static int ssl_parse_supported_point_formats( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t list_size; + const unsigned char *p; + + if( len == 0 || (size_t)( buf[0] + 1 ) != len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + list_size = buf[0]; + + p = buf + 1; + while( list_size > 0 ) + { + if( p[0] == MBEDTLS_ECP_PF_UNCOMPRESSED || + p[0] == MBEDTLS_ECP_PF_COMPRESSED ) + { +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + ssl->handshake->ecdh_ctx.point_format = p[0]; +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl->handshake->ecjpake_ctx.point_format = p[0]; +#endif + MBEDTLS_SSL_DEBUG_MSG( 4, ( "point format selected: %d", p[0] ) ); + return( 0 ); + } + + list_size--; + p++; + } + + return( 0 ); +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static int ssl_parse_ecjpake_kkpp( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + + if( mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip ecjpake kkpp extension" ) ); + return( 0 ); + } + + if( ( ret = mbedtls_ecjpake_read_round_one( &ssl->handshake->ecjpake_ctx, + buf, len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_one", ret ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( ret ); + } + + /* Only mark the extension as OK when we're sure it is */ + ssl->handshake->cli_exts |= MBEDTLS_TLS_EXT_ECJPAKE_KKPP_OK; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static int ssl_parse_max_fragment_length_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 1 || buf[0] >= MBEDTLS_SSL_MAX_FRAG_LEN_INVALID ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->session_negotiate->mfl_code = buf[0]; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +static int ssl_parse_cid_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t peer_cid_len; + + /* CID extension only makes sense in DTLS */ + if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * Quoting draft-ietf-tls-dtls-connection-id-05 + * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05 + * + * struct { + * opaque cid<0..2^8-1>; + * } ConnectionId; + */ + + if( len < 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + peer_cid_len = *buf++; + len--; + + if( len != peer_cid_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* Ignore CID if the user has disabled its use. */ + if( ssl->negotiate_cid == MBEDTLS_SSL_CID_DISABLED ) + { + /* Leave ssl->handshake->cid_in_use in its default + * value of MBEDTLS_SSL_CID_DISABLED. */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Client sent CID extension, but CID disabled" ) ); + return( 0 ); + } + + if( peer_cid_len > MBEDTLS_SSL_CID_OUT_LEN_MAX ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->handshake->cid_in_use = MBEDTLS_SSL_CID_ENABLED; + ssl->handshake->peer_cid_len = (uint8_t) peer_cid_len; + memcpy( ssl->handshake->peer_cid, buf, peer_cid_len ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Use of CID extension negotiated" ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Client CID", buf, peer_cid_len ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +static int ssl_parse_truncated_hmac_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ((void) buf); + + if( ssl->conf->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_ENABLED ) + ssl->session_negotiate->trunc_hmac = MBEDTLS_SSL_TRUNC_HMAC_ENABLED; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +static int ssl_parse_encrypt_then_mac_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ((void) buf); + + if( ssl->conf->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED && + ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl->session_negotiate->encrypt_then_mac = MBEDTLS_SSL_ETM_ENABLED; + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +static int ssl_parse_extended_ms_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ((void) buf); + + if( ssl->conf->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED && + ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl->handshake->extended_ms = MBEDTLS_SSL_EXTENDED_MS_ENABLED; + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static int ssl_parse_session_ticket_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t len ) +{ + int ret; + mbedtls_ssl_session session; + + mbedtls_ssl_session_init( &session ); + + if( ssl->conf->f_ticket_parse == NULL || + ssl->conf->f_ticket_write == NULL ) + { + return( 0 ); + } + + /* Remember the client asked us to send a new ticket */ + ssl->handshake->new_session_ticket = 1; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket length: %d", len ) ); + + if( len == 0 ) + return( 0 ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket rejected: renegotiating" ) ); + return( 0 ); + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + /* + * Failures are ok: just ignore the ticket and proceed. + */ + if( ( ret = ssl->conf->f_ticket_parse( ssl->conf->p_ticket, &session, + buf, len ) ) != 0 ) + { + mbedtls_ssl_session_free( &session ); + + if( ret == MBEDTLS_ERR_SSL_INVALID_MAC ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket is not authentic" ) ); + else if( ret == MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket is expired" ) ); + else + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_ticket_parse", ret ); + + return( 0 ); + } + + /* + * Keep the session ID sent by the client, since we MUST send it back to + * inform them we're accepting the ticket (RFC 5077 section 3.4) + */ + session.id_len = ssl->session_negotiate->id_len; + memcpy( &session.id, ssl->session_negotiate->id, session.id_len ); + + mbedtls_ssl_session_free( ssl->session_negotiate ); + memcpy( ssl->session_negotiate, &session, sizeof( mbedtls_ssl_session ) ); + + /* Zeroize instead of free as we copied the content */ + mbedtls_platform_zeroize( &session, sizeof( mbedtls_ssl_session ) ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "session successfully restored from ticket" ) ); + + ssl->handshake->resume = 1; + + /* Don't send a new ticket after all, this one is OK */ + ssl->handshake->new_session_ticket = 0; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_ALPN) +static int ssl_parse_alpn_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + size_t list_len, cur_len, ours_len; + const unsigned char *theirs, *start, *end; + const char **ours; + + /* If ALPN not configured, just ignore the extension */ + if( ssl->conf->alpn_list == NULL ) + return( 0 ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + */ + + /* Min length is 2 (list_len) + 1 (name_len) + 1 (name) */ + if( len < 4 ) + { + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + list_len = ( buf[0] << 8 ) | buf[1]; + if( list_len != len - 2 ) + { + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * Validate peer's list (lengths) + */ + start = buf + 2; + end = buf + len; + for( theirs = start; theirs != end; theirs += cur_len ) + { + cur_len = *theirs++; + + /* Current identifier must fit in list */ + if( cur_len > (size_t)( end - theirs ) ) + { + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* Empty strings MUST NOT be included */ + if( cur_len == 0 ) + { + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } + + /* + * Use our order of preference + */ + for( ours = ssl->conf->alpn_list; *ours != NULL; ours++ ) + { + ours_len = strlen( *ours ); + for( theirs = start; theirs != end; theirs += cur_len ) + { + cur_len = *theirs++; + + if( cur_len == ours_len && + memcmp( theirs, *ours, cur_len ) == 0 ) + { + ssl->alpn_chosen = *ours; + return( 0 ); + } + } + } + + /* If we get there, no match was found */ + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +/* + * Auxiliary functions for ServerHello parsing and related actions + */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/* + * Return 0 if the given key uses one of the acceptable curves, -1 otherwise + */ +#if defined(MBEDTLS_ECDSA_C) +static int ssl_check_key_curve( mbedtls_pk_context *pk, + const mbedtls_ecp_curve_info **curves ) +{ + const mbedtls_ecp_curve_info **crv = curves; + mbedtls_ecp_group_id grp_id = mbedtls_pk_ec( *pk )->grp.id; + + while( *crv != NULL ) + { + if( (*crv)->grp_id == grp_id ) + return( 0 ); + crv++; + } + + return( -1 ); +} +#endif /* MBEDTLS_ECDSA_C */ + +/* + * Try picking a certificate for this ciphersuite, + * return 0 on success and -1 on failure. + */ +static int ssl_pick_cert( mbedtls_ssl_context *ssl, + const mbedtls_ssl_ciphersuite_t * ciphersuite_info ) +{ + mbedtls_ssl_key_cert *cur, *list, *fallback = NULL; + mbedtls_pk_type_t pk_alg = + mbedtls_ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ); + uint32_t flags; + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_key_cert != NULL ) + list = ssl->handshake->sni_key_cert; + else +#endif + list = ssl->conf->key_cert; + + if( pk_alg == MBEDTLS_PK_NONE ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite requires certificate" ) ); + + if( list == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server has no certificate" ) ); + return( -1 ); + } + + for( cur = list; cur != NULL; cur = cur->next ) + { + MBEDTLS_SSL_DEBUG_CRT( 3, "candidate certificate chain, certificate", + cur->cert ); + + if( ! mbedtls_pk_can_do( &cur->cert->pk, pk_alg ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: key type" ) ); + continue; + } + + /* + * This avoids sending the client a cert it'll reject based on + * keyUsage or other extensions. + * + * It also allows the user to provision different certificates for + * different uses based on keyUsage, eg if they want to avoid signing + * and decrypting with the same RSA key. + */ + if( mbedtls_ssl_check_cert_usage( cur->cert, ciphersuite_info, + MBEDTLS_SSL_IS_SERVER, &flags ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: " + "(extended) key usage extension" ) ); + continue; + } + +#if defined(MBEDTLS_ECDSA_C) + if( pk_alg == MBEDTLS_PK_ECDSA && + ssl_check_key_curve( &cur->cert->pk, ssl->handshake->curves ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: elliptic curve" ) ); + continue; + } +#endif + + /* + * Try to select a SHA-1 certificate for pre-1.2 clients, but still + * present them a SHA-higher cert rather than failing if it's the only + * one we got that satisfies the other conditions. + */ + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 && + cur->cert->sig_md != MBEDTLS_MD_SHA1 ) + { + if( fallback == NULL ) + fallback = cur; + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate not preferred: " + "sha-2 with pre-TLS 1.2 client" ) ); + continue; + } + } + + /* If we get there, we got a winner */ + break; + } + + if( cur == NULL ) + cur = fallback; + + /* Do not update ssl->handshake->key_cert unless there is a match */ + if( cur != NULL ) + { + ssl->handshake->key_cert = cur; + MBEDTLS_SSL_DEBUG_CRT( 3, "selected certificate chain, certificate", + ssl->handshake->key_cert->cert ); + return( 0 ); + } + + return( -1 ); +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/* + * Check if a given ciphersuite is suitable for use with our config/keys/etc + * Sets ciphersuite_info only if the suite matches. + */ +static int ssl_ciphersuite_match( mbedtls_ssl_context *ssl, int suite_id, + const mbedtls_ssl_ciphersuite_t **ciphersuite_info ) +{ + const mbedtls_ssl_ciphersuite_t *suite_info; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + mbedtls_pk_type_t sig_type; +#endif + + suite_info = mbedtls_ssl_ciphersuite_from_id( suite_id ); + if( suite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "trying ciphersuite: %s", suite_info->name ) ); + + if( suite_info->min_minor_ver > ssl->minor_ver || + suite_info->max_minor_ver < ssl->minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: version" ) ); + return( 0 ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( suite_info->flags & MBEDTLS_CIPHERSUITE_NODTLS ) ) + return( 0 ); +#endif + +#if defined(MBEDTLS_ARC4_C) + if( ssl->conf->arc4_disabled == MBEDTLS_SSL_ARC4_DISABLED && + suite_info->cipher == MBEDTLS_CIPHER_ARC4_128 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: rc4" ) ); + return( 0 ); + } +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( suite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE && + ( ssl->handshake->cli_exts & MBEDTLS_TLS_EXT_ECJPAKE_KKPP_OK ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: ecjpake " + "not configured or ext missing" ) ); + return( 0 ); + } +#endif + + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + if( mbedtls_ssl_ciphersuite_uses_ec( suite_info ) && + ( ssl->handshake->curves == NULL || + ssl->handshake->curves[0] == NULL ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: " + "no common elliptic curve" ) ); + return( 0 ); + } +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + /* If the ciphersuite requires a pre-shared key and we don't + * have one, skip it now rather than failing later */ + if( mbedtls_ssl_ciphersuite_uses_psk( suite_info ) && + ssl_conf_has_psk_or_cb( ssl->conf ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: no pre-shared key" ) ); + return( 0 ); + } +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + /* If the ciphersuite requires signing, check whether + * a suitable hash algorithm is present. */ + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + sig_type = mbedtls_ssl_get_ciphersuite_sig_alg( suite_info ); + if( sig_type != MBEDTLS_PK_NONE && + mbedtls_ssl_sig_hash_set_find( &ssl->handshake->hash_algs, sig_type ) == MBEDTLS_MD_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: no suitable hash algorithm " + "for signature algorithm %d", sig_type ) ); + return( 0 ); + } + } + +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + /* + * Final check: if ciphersuite requires us to have a + * certificate/key of a particular type: + * - select the appropriate certificate if we have one, or + * - try the next ciphersuite if we don't + * This must be done last since we modify the key_cert list. + */ + if( ssl_pick_cert( ssl, suite_info ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: " + "no suitable certificate" ) ); + return( 0 ); + } +#endif + + *ciphersuite_info = suite_info; + return( 0 ); +} + +#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) +static int ssl_parse_client_hello_v2( mbedtls_ssl_context *ssl ) +{ + int ret, got_common_suite; + unsigned int i, j; + size_t n; + unsigned int ciph_len, sess_len, chal_len; + unsigned char *buf, *p; + const int *ciphersuites; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client hello v2" ) ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client hello v2 illegal for renegotiation" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + buf = ssl->in_hdr; + + MBEDTLS_SSL_DEBUG_BUF( 4, "record header", buf, 5 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v2, message type: %d", + buf[2] ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v2, message len.: %d", + ( ( buf[0] & 0x7F ) << 8 ) | buf[1] ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v2, max. version: [%d:%d]", + buf[3], buf[4] ) ); + + /* + * SSLv2 Client Hello + * + * Record layer: + * 0 . 1 message length + * + * SSL layer: + * 2 . 2 message type + * 3 . 4 protocol version + */ + if( buf[2] != MBEDTLS_SSL_HS_CLIENT_HELLO || + buf[3] != MBEDTLS_SSL_MAJOR_VERSION_3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + n = ( ( buf[0] << 8 ) | buf[1] ) & 0x7FFF; + + if( n < 17 || n > 512 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->major_ver = MBEDTLS_SSL_MAJOR_VERSION_3; + ssl->minor_ver = ( buf[4] <= ssl->conf->max_minor_ver ) + ? buf[4] : ssl->conf->max_minor_ver; + + if( ssl->minor_ver < ssl->conf->min_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum" + " [%d:%d] < [%d:%d]", + ssl->major_ver, ssl->minor_ver, + ssl->conf->min_major_ver, ssl->conf->min_minor_ver ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION ); + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + ssl->handshake->max_major_ver = buf[3]; + ssl->handshake->max_minor_ver = buf[4]; + + if( ( ret = mbedtls_ssl_fetch_input( ssl, 2 + n ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + + ssl->handshake->update_checksum( ssl, buf + 2, n ); + + buf = ssl->in_msg; + n = ssl->in_left - 5; + + /* + * 0 . 1 ciphersuitelist length + * 2 . 3 session id length + * 4 . 5 challenge length + * 6 . .. ciphersuitelist + * .. . .. session id + * .. . .. challenge + */ + MBEDTLS_SSL_DEBUG_BUF( 4, "record contents", buf, n ); + + ciph_len = ( buf[0] << 8 ) | buf[1]; + sess_len = ( buf[2] << 8 ) | buf[3]; + chal_len = ( buf[4] << 8 ) | buf[5]; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciph_len: %d, sess_len: %d, chal_len: %d", + ciph_len, sess_len, chal_len ) ); + + /* + * Make sure each parameter length is valid + */ + if( ciph_len < 3 || ( ciph_len % 3 ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( sess_len > 32 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( chal_len < 8 || chal_len > 32 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( n != 6 + ciph_len + sess_len + chal_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist", + buf + 6, ciph_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, session id", + buf + 6 + ciph_len, sess_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, challenge", + buf + 6 + ciph_len + sess_len, chal_len ); + + p = buf + 6 + ciph_len; + ssl->session_negotiate->id_len = sess_len; + memset( ssl->session_negotiate->id, 0, + sizeof( ssl->session_negotiate->id ) ); + memcpy( ssl->session_negotiate->id, p, ssl->session_negotiate->id_len ); + + p += sess_len; + memset( ssl->handshake->randbytes, 0, 64 ); + memcpy( ssl->handshake->randbytes + 32 - chal_len, p, chal_len ); + + /* + * Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV + */ + for( i = 0, p = buf + 6; i < ciph_len; i += 3, p += 3 ) + { + if( p[0] == 0 && p[1] == 0 && p[2] == MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV " + "during renegotiation" ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + ssl->secure_renegotiation = MBEDTLS_SSL_SECURE_RENEGOTIATION; + break; + } + } + +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) + for( i = 0, p = buf + 6; i < ciph_len; i += 3, p += 3 ) + { + if( p[0] == 0 && + p[1] == (unsigned char)( ( MBEDTLS_SSL_FALLBACK_SCSV_VALUE >> 8 ) & 0xff ) && + p[2] == (unsigned char)( ( MBEDTLS_SSL_FALLBACK_SCSV_VALUE ) & 0xff ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "received FALLBACK_SCSV" ) ); + + if( ssl->minor_ver < ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "inapropriate fallback" ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + break; + } + } +#endif /* MBEDTLS_SSL_FALLBACK_SCSV */ + + got_common_suite = 0; + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + ciphersuite_info = NULL; +#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE) + for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 ) + for( i = 0; ciphersuites[i] != 0; i++ ) +#else + for( i = 0; ciphersuites[i] != 0; i++ ) + for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 ) +#endif + { + if( p[0] != 0 || + p[1] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) || + p[2] != ( ( ciphersuites[i] ) & 0xFF ) ) + continue; + + got_common_suite = 1; + + if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i], + &ciphersuite_info ) ) != 0 ) + return( ret ); + + if( ciphersuite_info != NULL ) + goto have_ciphersuite_v2; + } + + if( got_common_suite ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got ciphersuites in common, " + "but none of them usable" ) ); + return( MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) ); + return( MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN ); + } + +have_ciphersuite_v2: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "selected ciphersuite: %s", ciphersuite_info->name ) ); + + ssl->session_negotiate->ciphersuite = ciphersuites[i]; + ssl->handshake->ciphersuite_info = ciphersuite_info; + + /* + * SSLv2 Client Hello relevant renegotiation security checks + */ + if( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->in_left = 0; + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse client hello v2" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO */ + +/* This function doesn't alert on errors that happen early during + ClientHello parsing because they might indicate that the client is + not talking SSL/TLS at all and would not understand our alert. */ +static int ssl_parse_client_hello( mbedtls_ssl_context *ssl ) +{ + int ret, got_common_suite; + size_t i, j; + size_t ciph_offset, comp_offset, ext_offset; + size_t msg_len, ciph_len, sess_len, comp_len, ext_len; +#if defined(MBEDTLS_SSL_PROTO_DTLS) + size_t cookie_offset, cookie_len; +#endif + unsigned char *buf, *p, *ext; +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renegotiation_info_seen = 0; +#endif + int handshake_failure = 0; + const int *ciphersuites; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + int major, minor; + + /* If there is no signature-algorithm extension present, + * we need to fall back to the default values for allowed + * signature-hash pairs. */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + int sig_hash_alg_ext_present = 0; +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) ); + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +read_record_header: +#endif + /* + * If renegotiating, then the input was read with mbedtls_ssl_read_record(), + * otherwise read it ourselves manually in order to support SSLv2 + * ClientHello, which doesn't use the same record layer format. + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) +#endif + { + if( ( ret = mbedtls_ssl_fetch_input( ssl, 5 ) ) != 0 ) + { + /* No alert on a read error. */ + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + } + + buf = ssl->in_hdr; + +#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_STREAM ) +#endif + if( ( buf[0] & 0x80 ) != 0 ) + return( ssl_parse_client_hello_v2( ssl ) ); +#endif + + MBEDTLS_SSL_DEBUG_BUF( 4, "record header", buf, mbedtls_ssl_in_hdr_len( ssl ) ); + + /* + * SSLv3/TLS Client Hello + * + * Record layer: + * 0 . 0 message type + * 1 . 2 protocol version + * 3 . 11 DTLS: epoch + record sequence number + * 3 . 4 message length + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, message type: %d", + buf[0] ) ); + + if( buf[0] != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, message len.: %d", + ( ssl->in_len[0] << 8 ) | ssl->in_len[1] ) ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, protocol version: [%d:%d]", + buf[1], buf[2] ) ); + + mbedtls_ssl_read_version( &major, &minor, ssl->conf->transport, buf + 1 ); + + /* According to RFC 5246 Appendix E.1, the version here is typically + * "{03,00}, the lowest version number supported by the client, [or] the + * value of ClientHello.client_version", so the only meaningful check here + * is the major version shouldn't be less than 3 */ + if( major < MBEDTLS_SSL_MAJOR_VERSION_3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* For DTLS if this is the initial handshake, remember the client sequence + * number to use it in our next message (RFC 6347 4.2.1) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM +#if defined(MBEDTLS_SSL_RENEGOTIATION) + && ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE +#endif + ) + { + /* Epoch should be 0 for initial handshakes */ + if( ssl->in_ctr[0] != 0 || ssl->in_ctr[1] != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + memcpy( ssl->cur_out_ctr + 2, ssl->in_ctr + 2, 6 ); + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + if( mbedtls_ssl_dtls_replay_check( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "replayed record, discarding" ) ); + ssl->next_record_offset = 0; + ssl->in_left = 0; + goto read_record_header; + } + + /* No MAC to check yet, so we can update right now */ + mbedtls_ssl_dtls_replay_update( ssl ); +#endif + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + msg_len = ( ssl->in_len[0] << 8 ) | ssl->in_len[1]; + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + /* Set by mbedtls_ssl_read_record() */ + msg_len = ssl->in_hslen; + } + else +#endif + { + if( msg_len > MBEDTLS_SSL_IN_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( ( ret = mbedtls_ssl_fetch_input( ssl, + mbedtls_ssl_in_hdr_len( ssl ) + msg_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + + /* Done reading this record, get ready for the next one */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + ssl->next_record_offset = msg_len + mbedtls_ssl_in_hdr_len( ssl ); + else +#endif + ssl->in_left = 0; + } + + buf = ssl->in_msg; + + MBEDTLS_SSL_DEBUG_BUF( 4, "record contents", buf, msg_len ); + + ssl->handshake->update_checksum( ssl, buf, msg_len ); + + /* + * Handshake layer: + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 DTLS only: message seqence number + * 6 . 8 DTLS only: fragment offset + * 9 . 11 DTLS only: fragment length + */ + if( msg_len < mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, handshake type: %d", buf[0] ) ); + + if( buf[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, handshake len.: %d", + ( buf[1] << 16 ) | ( buf[2] << 8 ) | buf[3] ) ); + + /* We don't support fragmentation of ClientHello (yet?) */ + if( buf[1] != 0 || + msg_len != mbedtls_ssl_hs_hdr_len( ssl ) + ( ( buf[2] << 8 ) | buf[3] ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + /* + * Copy the client's handshake message_seq on initial handshakes, + * check sequence number on renego. + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + /* This couldn't be done in ssl_prepare_handshake_record() */ + unsigned int cli_msg_seq = ( ssl->in_msg[4] << 8 ) | + ssl->in_msg[5]; + + if( cli_msg_seq != ssl->handshake->in_msg_seq ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message_seq: " + "%d (expected %d)", cli_msg_seq, + ssl->handshake->in_msg_seq ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->handshake->in_msg_seq++; + } + else +#endif + { + unsigned int cli_msg_seq = ( ssl->in_msg[4] << 8 ) | + ssl->in_msg[5]; + ssl->handshake->out_msg_seq = cli_msg_seq; + ssl->handshake->in_msg_seq = cli_msg_seq + 1; + } + + /* + * For now we don't support fragmentation, so make sure + * fragment_offset == 0 and fragment_length == length + */ + if( ssl->in_msg[6] != 0 || ssl->in_msg[7] != 0 || ssl->in_msg[8] != 0 || + memcmp( ssl->in_msg + 1, ssl->in_msg + 9, 3 ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ClientHello fragmentation not supported" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + buf += mbedtls_ssl_hs_hdr_len( ssl ); + msg_len -= mbedtls_ssl_hs_hdr_len( ssl ); + + /* + * ClientHello layer: + * 0 . 1 protocol version + * 2 . 33 random bytes (starting with 4 bytes of Unix time) + * 34 . 35 session id length (1 byte) + * 35 . 34+x session id + * 35+x . 35+x DTLS only: cookie length (1 byte) + * 36+x . .. DTLS only: cookie + * .. . .. ciphersuite list length (2 bytes) + * .. . .. ciphersuite list + * .. . .. compression alg. list length (1 byte) + * .. . .. compression alg. list + * .. . .. extensions length (2 bytes, optional) + * .. . .. extensions (optional) + */ + + /* + * Minimal length (with everything empty and extensions omitted) is + * 2 + 32 + 1 + 2 + 1 = 38 bytes. Check that first, so that we can + * read at least up to session id length without worrying. + */ + if( msg_len < 38 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * Check and save the protocol version + */ + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, version", buf, 2 ); + + mbedtls_ssl_read_version( &ssl->major_ver, &ssl->minor_ver, + ssl->conf->transport, buf ); + + ssl->handshake->max_major_ver = ssl->major_ver; + ssl->handshake->max_minor_ver = ssl->minor_ver; + + if( ssl->major_ver < ssl->conf->min_major_ver || + ssl->minor_ver < ssl->conf->min_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum" + " [%d:%d] < [%d:%d]", + ssl->major_ver, ssl->minor_ver, + ssl->conf->min_major_ver, ssl->conf->min_minor_ver ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION ); + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + if( ssl->major_ver > ssl->conf->max_major_ver ) + { + ssl->major_ver = ssl->conf->max_major_ver; + ssl->minor_ver = ssl->conf->max_minor_ver; + } + else if( ssl->minor_ver > ssl->conf->max_minor_ver ) + ssl->minor_ver = ssl->conf->max_minor_ver; + + /* + * Save client random (inc. Unix time) + */ + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, random bytes", buf + 2, 32 ); + + memcpy( ssl->handshake->randbytes, buf + 2, 32 ); + + /* + * Check the session ID length and save session ID + */ + sess_len = buf[34]; + + if( sess_len > sizeof( ssl->session_negotiate->id ) || + sess_len + 34 + 2 > msg_len ) /* 2 for cipherlist length field */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, session id", buf + 35, sess_len ); + + ssl->session_negotiate->id_len = sess_len; + memset( ssl->session_negotiate->id, 0, + sizeof( ssl->session_negotiate->id ) ); + memcpy( ssl->session_negotiate->id, buf + 35, + ssl->session_negotiate->id_len ); + + /* + * Check the cookie length and content + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + cookie_offset = 35 + sess_len; + cookie_len = buf[cookie_offset]; + + if( cookie_offset + 1 + cookie_len + 2 > msg_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, cookie", + buf + cookie_offset + 1, cookie_len ); + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) + if( ssl->conf->f_cookie_check != NULL +#if defined(MBEDTLS_SSL_RENEGOTIATION) + && ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE +#endif + ) + { + if( ssl->conf->f_cookie_check( ssl->conf->p_cookie, + buf + cookie_offset + 1, cookie_len, + ssl->cli_id, ssl->cli_id_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification failed" ) ); + ssl->handshake->verify_cookie_len = 1; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification passed" ) ); + ssl->handshake->verify_cookie_len = 0; + } + } + else +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ + { + /* We know we didn't send a cookie, so it should be empty */ + if( cookie_len != 0 ) + { + /* This may be an attacker's probe, so don't send an alert */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification skipped" ) ); + } + + /* + * Check the ciphersuitelist length (will be parsed later) + */ + ciph_offset = cookie_offset + 1 + cookie_len; + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + ciph_offset = 35 + sess_len; + + ciph_len = ( buf[ciph_offset + 0] << 8 ) + | ( buf[ciph_offset + 1] ); + + if( ciph_len < 2 || + ciph_len + 2 + ciph_offset + 1 > msg_len || /* 1 for comp. alg. len */ + ( ciph_len % 2 ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist", + buf + ciph_offset + 2, ciph_len ); + + /* + * Check the compression algorithms length and pick one + */ + comp_offset = ciph_offset + 2 + ciph_len; + + comp_len = buf[comp_offset]; + + if( comp_len < 1 || + comp_len > 16 || + comp_len + comp_offset + 1 > msg_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, compression", + buf + comp_offset + 1, comp_len ); + + ssl->session_negotiate->compression = MBEDTLS_SSL_COMPRESS_NULL; +#if defined(MBEDTLS_ZLIB_SUPPORT) + for( i = 0; i < comp_len; ++i ) + { + if( buf[comp_offset + 1 + i] == MBEDTLS_SSL_COMPRESS_DEFLATE ) + { + ssl->session_negotiate->compression = MBEDTLS_SSL_COMPRESS_DEFLATE; + break; + } + } +#endif + + /* See comments in ssl_write_client_hello() */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + ssl->session_negotiate->compression = MBEDTLS_SSL_COMPRESS_NULL; +#endif + + /* Do not parse the extensions if the protocol is SSLv3 */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ( ssl->major_ver != 3 ) || ( ssl->minor_ver != 0 ) ) + { +#endif + /* + * Check the extension length + */ + ext_offset = comp_offset + 1 + comp_len; + if( msg_len > ext_offset ) + { + if( msg_len < ext_offset + 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ext_len = ( buf[ext_offset + 0] << 8 ) + | ( buf[ext_offset + 1] ); + + if( ( ext_len > 0 && ext_len < 4 ) || + msg_len != ext_offset + 2 + ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } + else + ext_len = 0; + + ext = buf + ext_offset + 2; + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello extensions", ext, ext_len ); + + while( ext_len != 0 ) + { + unsigned int ext_id; + unsigned int ext_size; + if ( ext_len < 4 ) { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + ext_id = ( ( ext[0] << 8 ) | ( ext[1] ) ); + ext_size = ( ( ext[2] << 8 ) | ( ext[3] ) ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + switch( ext_id ) + { +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + case MBEDTLS_TLS_EXT_SERVERNAME: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found ServerName extension" ) ); + if( ssl->conf->f_sni == NULL ) + break; + + ret = ssl_parse_servername_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + + case MBEDTLS_TLS_EXT_RENEGOTIATION_INFO: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found renegotiation extension" ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + renegotiation_info_seen = 1; +#endif + + ret = ssl_parse_renegotiation_info( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + case MBEDTLS_TLS_EXT_SIG_ALG: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found signature_algorithms extension" ) ); + + ret = ssl_parse_signature_algorithms_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + + sig_hash_alg_ext_present = 1; + break; +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + case MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported elliptic curves extension" ) ); + + ret = ssl_parse_supported_elliptic_curves( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; + + case MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported point formats extension" ) ); + ssl->handshake->cli_exts |= MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT; + + ret = ssl_parse_supported_point_formats( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + case MBEDTLS_TLS_EXT_ECJPAKE_KKPP: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found ecjpake kkpp extension" ) ); + + ret = ssl_parse_ecjpake_kkpp( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + case MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found max fragment length extension" ) ); + + ret = ssl_parse_max_fragment_length_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + case MBEDTLS_TLS_EXT_TRUNCATED_HMAC: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found truncated hmac extension" ) ); + + ret = ssl_parse_truncated_hmac_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + case MBEDTLS_TLS_EXT_CID: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found CID extension" ) ); + + ret = ssl_parse_cid_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + case MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found encrypt then mac extension" ) ); + + ret = ssl_parse_encrypt_then_mac_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + case MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found extended master secret extension" ) ); + + ret = ssl_parse_extended_ms_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + case MBEDTLS_TLS_EXT_SESSION_TICKET: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found session ticket extension" ) ); + + ret = ssl_parse_session_ticket_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_ALPN) + case MBEDTLS_TLS_EXT_ALPN: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found alpn extension" ) ); + + ret = ssl_parse_alpn_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)", + ext_id ) ); + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } +#if defined(MBEDTLS_SSL_PROTO_SSL3) + } +#endif + +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) + for( i = 0, p = buf + ciph_offset + 2; i < ciph_len; i += 2, p += 2 ) + { + if( p[0] == (unsigned char)( ( MBEDTLS_SSL_FALLBACK_SCSV_VALUE >> 8 ) & 0xff ) && + p[1] == (unsigned char)( ( MBEDTLS_SSL_FALLBACK_SCSV_VALUE ) & 0xff ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received FALLBACK_SCSV" ) ); + + if( ssl->minor_ver < ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "inapropriate fallback" ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + break; + } + } +#endif /* MBEDTLS_SSL_FALLBACK_SCSV */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + + /* + * Try to fall back to default hash SHA1 if the client + * hasn't provided any preferred signature-hash combinations. + */ + if( sig_hash_alg_ext_present == 0 ) + { + mbedtls_md_type_t md_default = MBEDTLS_MD_SHA1; + + if( mbedtls_ssl_check_sig_hash( ssl, md_default ) != 0 ) + md_default = MBEDTLS_MD_NONE; + + mbedtls_ssl_sig_hash_set_const_hash( &ssl->handshake->hash_algs, md_default ); + } + +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + + /* + * Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV + */ + for( i = 0, p = buf + ciph_offset + 2; i < ciph_len; i += 2, p += 2 ) + { + if( p[0] == 0 && p[1] == MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV " + "during renegotiation" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } +#endif + ssl->secure_renegotiation = MBEDTLS_SSL_SECURE_RENEGOTIATION; + break; + } + } + + /* + * Renegotiation security checks + */ + if( ssl->secure_renegotiation != MBEDTLS_SSL_SECURE_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); + handshake_failure = 1; + } +#if defined(MBEDTLS_SSL_RENEGOTIATION) + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_SECURE_RENEGOTIATION && + renegotiation_info_seen == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation_info extension missing (secure)" ) ); + handshake_failure = 1; + } + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation not allowed" ) ); + handshake_failure = 1; + } + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + renegotiation_info_seen == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation_info extension present (legacy)" ) ); + handshake_failure = 1; + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + if( handshake_failure == 1 ) + { + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * Search for a matching ciphersuite + * (At the end because we need information from the EC-based extensions + * and certificate from the SNI callback triggered by the SNI extension.) + */ + got_common_suite = 0; + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + ciphersuite_info = NULL; +#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE) + for( j = 0, p = buf + ciph_offset + 2; j < ciph_len; j += 2, p += 2 ) + for( i = 0; ciphersuites[i] != 0; i++ ) +#else + for( i = 0; ciphersuites[i] != 0; i++ ) + for( j = 0, p = buf + ciph_offset + 2; j < ciph_len; j += 2, p += 2 ) +#endif + { + if( p[0] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) || + p[1] != ( ( ciphersuites[i] ) & 0xFF ) ) + continue; + + got_common_suite = 1; + + if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i], + &ciphersuite_info ) ) != 0 ) + return( ret ); + + if( ciphersuite_info != NULL ) + goto have_ciphersuite; + } + + if( got_common_suite ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got ciphersuites in common, " + "but none of them usable" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ); + return( MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN ); + } + +have_ciphersuite: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "selected ciphersuite: %s", ciphersuite_info->name ) ); + + ssl->session_negotiate->ciphersuite = ciphersuites[i]; + ssl->handshake->ciphersuite_info = ciphersuite_info; + + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_recv_flight_completed( ssl ); +#endif + + /* Debugging-only output for testsuite */ +#if defined(MBEDTLS_DEBUG_C) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + mbedtls_pk_type_t sig_alg = mbedtls_ssl_get_ciphersuite_sig_alg( ciphersuite_info ); + if( sig_alg != MBEDTLS_PK_NONE ) + { + mbedtls_md_type_t md_alg = mbedtls_ssl_sig_hash_set_find( &ssl->handshake->hash_algs, + sig_alg ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext: %d", + mbedtls_ssl_hash_from_md_alg( md_alg ) ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no hash algorithm for signature algorithm " + "%d - should not happen", sig_alg ) ); + } + } +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse client hello" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +static void ssl_write_truncated_hmac_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->session_negotiate->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_DISABLED ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding truncated hmac extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_TRUNCATED_HMAC >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_TRUNCATED_HMAC ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +static void ssl_write_cid_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + size_t ext_len; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + + *olen = 0; + + /* Skip writing the extension if we don't want to use it or if + * the client hasn't offered it. */ + if( ssl->handshake->cid_in_use == MBEDTLS_SSL_CID_DISABLED ) + return; + + /* ssl->own_cid_len is at most MBEDTLS_SSL_CID_IN_LEN_MAX + * which is at most 255, so the increment cannot overflow. */ + if( end < p || (size_t)( end - p ) < (unsigned)( ssl->own_cid_len + 5 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding CID extension" ) ); + + /* + * Quoting draft-ietf-tls-dtls-connection-id-05 + * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05 + * + * struct { + * opaque cid<0..2^8-1>; + * } ConnectionId; + */ + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_CID >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_CID ) & 0xFF ); + ext_len = (size_t) ssl->own_cid_len + 1; + *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_len ) & 0xFF ); + + *p++ = (uint8_t) ssl->own_cid_len; + memcpy( p, ssl->own_cid, ssl->own_cid_len ); + + *olen = ssl->own_cid_len + 5; +} +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +static void ssl_write_encrypt_then_mac_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const mbedtls_ssl_ciphersuite_t *suite = NULL; + const mbedtls_cipher_info_t *cipher = NULL; + + if( ssl->session_negotiate->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + *olen = 0; + return; + } + + /* + * RFC 7366: "If a server receives an encrypt-then-MAC request extension + * from a client and then selects a stream or Authenticated Encryption + * with Associated Data (AEAD) ciphersuite, it MUST NOT send an + * encrypt-then-MAC response extension back to the client." + */ + if( ( suite = mbedtls_ssl_ciphersuite_from_id( + ssl->session_negotiate->ciphersuite ) ) == NULL || + ( cipher = mbedtls_cipher_info_from_type( suite->cipher ) ) == NULL || + cipher->mode != MBEDTLS_MODE_CBC ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding encrypt then mac extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +static void ssl_write_extended_ms_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_DISABLED || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding extended master secret " + "extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static void ssl_write_session_ticket_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->handshake->new_session_ticket == 0 ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding session ticket extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SESSION_TICKET >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SESSION_TICKET ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +static void ssl_write_renegotiation_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->secure_renegotiation != MBEDTLS_SSL_SECURE_RENEGOTIATION ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, secure renegotiation extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_RENEGOTIATION_INFO >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_RENEGOTIATION_INFO ) & 0xFF ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + *p++ = 0x00; + *p++ = ( ssl->verify_data_len * 2 + 1 ) & 0xFF; + *p++ = ssl->verify_data_len * 2 & 0xFF; + + memcpy( p, ssl->peer_verify_data, ssl->verify_data_len ); + p += ssl->verify_data_len; + memcpy( p, ssl->own_verify_data, ssl->verify_data_len ); + p += ssl->verify_data_len; + } + else +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + { + *p++ = 0x00; + *p++ = 0x01; + *p++ = 0x00; + } + + *olen = p - buf; +} + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static void ssl_write_max_fragment_length_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->session_negotiate->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, max_fragment_length extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH ) & 0xFF ); + + *p++ = 0x00; + *p++ = 1; + + *p++ = ssl->session_negotiate->mfl_code; + + *olen = 5; +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static void ssl_write_supported_point_formats_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + ((void) ssl); + + if( ( ssl->handshake->cli_exts & + MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT ) == 0 ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, supported_point_formats extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS ) & 0xFF ); + + *p++ = 0x00; + *p++ = 2; + + *p++ = 1; + *p++ = MBEDTLS_ECP_PF_UNCOMPRESSED; + + *olen = 6; +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static void ssl_write_ecjpake_kkpp_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + int ret; + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + size_t kkpp_len; + + *olen = 0; + + /* Skip costly computation if not needed */ + if( ssl->handshake->ciphersuite_info->key_exchange != + MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, ecjpake kkpp extension" ) ); + + if( end - p < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ECJPAKE_KKPP >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ECJPAKE_KKPP ) & 0xFF ); + + ret = mbedtls_ecjpake_write_round_one( &ssl->handshake->ecjpake_ctx, + p + 2, end - p - 2, &kkpp_len, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1 , "mbedtls_ecjpake_write_round_one", ret ); + return; + } + + *p++ = (unsigned char)( ( kkpp_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( kkpp_len ) & 0xFF ); + + *olen = kkpp_len + 4; +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_ALPN ) +static void ssl_write_alpn_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + if( ssl->alpn_chosen == NULL ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding alpn extension" ) ); + + /* + * 0 . 1 ext identifier + * 2 . 3 ext length + * 4 . 5 protocol list length + * 6 . 6 protocol name length + * 7 . 7+n protocol name + */ + buf[0] = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN >> 8 ) & 0xFF ); + buf[1] = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN ) & 0xFF ); + + *olen = 7 + strlen( ssl->alpn_chosen ); + + buf[2] = (unsigned char)( ( ( *olen - 4 ) >> 8 ) & 0xFF ); + buf[3] = (unsigned char)( ( ( *olen - 4 ) ) & 0xFF ); + + buf[4] = (unsigned char)( ( ( *olen - 6 ) >> 8 ) & 0xFF ); + buf[5] = (unsigned char)( ( ( *olen - 6 ) ) & 0xFF ); + + buf[6] = (unsigned char)( ( ( *olen - 7 ) ) & 0xFF ); + + memcpy( buf + 7, ssl->alpn_chosen, *olen - 7 ); +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) +static int ssl_write_hello_verify_request( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *p = ssl->out_msg + 4; + unsigned char *cookie_len_byte; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write hello verify request" ) ); + + /* + * struct { + * ProtocolVersion server_version; + * opaque cookie<0..2^8-1>; + * } HelloVerifyRequest; + */ + + /* The RFC is not clear on this point, but sending the actual negotiated + * version looks like the most interoperable thing to do. */ + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, p ); + MBEDTLS_SSL_DEBUG_BUF( 3, "server version", p, 2 ); + p += 2; + + /* If we get here, f_cookie_check is not null */ + if( ssl->conf->f_cookie_write == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "inconsistent cookie callbacks" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* Skip length byte until we know the length */ + cookie_len_byte = p++; + + if( ( ret = ssl->conf->f_cookie_write( ssl->conf->p_cookie, + &p, ssl->out_buf + MBEDTLS_SSL_OUT_BUFFER_LEN, + ssl->cli_id, ssl->cli_id_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "f_cookie_write", ret ); + return( ret ); + } + + *cookie_len_byte = (unsigned char)( p - ( cookie_len_byte + 1 ) ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "cookie sent", cookie_len_byte + 1, *cookie_len_byte ); + + ssl->out_msglen = p - ssl->out_msg; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST; + + ssl->state = MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT; + + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); + return( ret ); + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write hello verify request" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ + +static int ssl_write_server_hello( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_HAVE_TIME) + mbedtls_time_t t; +#endif + int ret; + size_t olen, ext_len = 0, n; + unsigned char *buf, *p; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server hello" ) ); + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->verify_cookie_len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "client hello was not authenticated" ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello" ) ); + + return( ssl_write_hello_verify_request( ssl ) ); + } +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ + + if( ssl->conf->f_rng == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no RNG provided") ); + return( MBEDTLS_ERR_SSL_NO_RNG ); + } + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 protocol version + * 6 . 9 UNIX time() + * 10 . 37 random bytes + */ + buf = ssl->out_msg; + p = buf + 4; + + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, p ); + p += 2; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen version: [%d:%d]", + buf[4], buf[5] ) ); + +#if defined(MBEDTLS_HAVE_TIME) + t = mbedtls_time( NULL ); + *p++ = (unsigned char)( t >> 24 ); + *p++ = (unsigned char)( t >> 16 ); + *p++ = (unsigned char)( t >> 8 ); + *p++ = (unsigned char)( t ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu", t ) ); +#else + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 4 ) ) != 0 ) + return( ret ); + + p += 4; +#endif /* MBEDTLS_HAVE_TIME */ + + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 28 ) ) != 0 ) + return( ret ); + + p += 28; + + memcpy( ssl->handshake->randbytes + 32, buf + 6, 32 ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 6, 32 ); + + /* + * Resume is 0 by default, see ssl_handshake_init(). + * It may be already set to 1 by ssl_parse_session_ticket_ext(). + * If not, try looking up session ID in our cache. + */ + if( ssl->handshake->resume == 0 && +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE && +#endif + ssl->session_negotiate->id_len != 0 && + ssl->conf->f_get_cache != NULL && + ssl->conf->f_get_cache( ssl->conf->p_cache, ssl->session_negotiate ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "session successfully restored from cache" ) ); + ssl->handshake->resume = 1; + } + + if( ssl->handshake->resume == 0 ) + { + /* + * New session, create a new session id, + * unless we're about to issue a session ticket + */ + ssl->state++; + +#if defined(MBEDTLS_HAVE_TIME) + ssl->session_negotiate->start = mbedtls_time( NULL ); +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + if( ssl->handshake->new_session_ticket != 0 ) + { + ssl->session_negotiate->id_len = n = 0; + memset( ssl->session_negotiate->id, 0, 32 ); + } + else +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + { + ssl->session_negotiate->id_len = n = 32; + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->session_negotiate->id, + n ) ) != 0 ) + return( ret ); + } + } + else + { + /* + * Resuming a session + */ + n = ssl->session_negotiate->id_len; + ssl->state = MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC; + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + return( ret ); + } + } + + /* + * 38 . 38 session id length + * 39 . 38+n session id + * 39+n . 40+n chosen ciphersuite + * 41+n . 41+n chosen compression alg. + * 42+n . 43+n extensions length + * 44+n . 43+n+m extensions + */ + *p++ = (unsigned char) ssl->session_negotiate->id_len; + memcpy( p, ssl->session_negotiate->id, ssl->session_negotiate->id_len ); + p += ssl->session_negotiate->id_len; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, session id len.: %d", n ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, session id", buf + 39, n ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "%s session has been resumed", + ssl->handshake->resume ? "a" : "no" ) ); + + *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite >> 8 ); + *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite ); + *p++ = (unsigned char)( ssl->session_negotiate->compression ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s", + mbedtls_ssl_get_ciphersuite_name( ssl->session_negotiate->ciphersuite ) ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: 0x%02X", + ssl->session_negotiate->compression ) ); + + /* Do not write the extensions if the protocol is SSLv3 */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ( ssl->major_ver != 3 ) || ( ssl->minor_ver != 0 ) ) + { +#endif + + /* + * First write extensions, then the total length + */ + ssl_write_renegotiation_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + ssl_write_max_fragment_length_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + ssl_write_truncated_hmac_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + ssl_write_cid_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + ssl_write_encrypt_then_mac_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + ssl_write_extended_ms_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + ssl_write_session_ticket_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if ( mbedtls_ssl_ciphersuite_uses_ec( + mbedtls_ssl_ciphersuite_from_id( ssl->session_negotiate->ciphersuite ) ) ) + { + ssl_write_supported_point_formats_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; + } +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl_write_ecjpake_kkpp_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_ALPN) + ssl_write_alpn_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, total extension length: %d", ext_len ) ); + + if( ext_len > 0 ) + { + *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_len ) & 0xFF ); + p += ext_len; + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + } +#endif + + ssl->out_msglen = p - buf; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_HELLO; + + ret = mbedtls_ssl_write_handshake_msg( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello" ) ); + + return( ret ); +} + +#if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED) +static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) ); + + if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} +#else /* !MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */ +static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + size_t dn_size, total_dn_size; /* excluding length bytes */ + size_t ct_len, sa_len; /* including length bytes */ + unsigned char *buf, *p; + const unsigned char * const end = ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN; + const mbedtls_x509_crt *crt; + int authmode; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) ); + + ssl->state++; + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET ) + authmode = ssl->handshake->sni_authmode; + else +#endif + authmode = ssl->conf->authmode; + + if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) || + authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) ); + return( 0 ); + } + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 4 cert type count + * 5 .. m-1 cert types + * m .. m+1 sig alg length (TLS 1.2 only) + * m+1 .. n-1 SignatureAndHashAlgorithms (TLS 1.2 only) + * n .. n+1 length of all DNs + * n+2 .. n+3 length of DN 1 + * n+4 .. ... Distinguished Name #1 + * ... .. ... length of DN 2, etc. + */ + buf = ssl->out_msg; + p = buf + 4; + + /* + * Supported certificate types + * + * ClientCertificateType certificate_types<1..2^8-1>; + * enum { (255) } ClientCertificateType; + */ + ct_len = 0; + +#if defined(MBEDTLS_RSA_C) + p[1 + ct_len++] = MBEDTLS_SSL_CERT_TYPE_RSA_SIGN; +#endif +#if defined(MBEDTLS_ECDSA_C) + p[1 + ct_len++] = MBEDTLS_SSL_CERT_TYPE_ECDSA_SIGN; +#endif + + p[0] = (unsigned char) ct_len++; + p += ct_len; + + sa_len = 0; +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + /* + * Add signature_algorithms for verify (TLS 1.2) + * + * SignatureAndHashAlgorithm supported_signature_algorithms<2..2^16-2>; + * + * struct { + * HashAlgorithm hash; + * SignatureAlgorithm signature; + * } SignatureAndHashAlgorithm; + * + * enum { (255) } HashAlgorithm; + * enum { (255) } SignatureAlgorithm; + */ + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + const int *cur; + + /* + * Supported signature algorithms + */ + for( cur = ssl->conf->sig_hashes; *cur != MBEDTLS_MD_NONE; cur++ ) + { + unsigned char hash = mbedtls_ssl_hash_from_md_alg( *cur ); + + if( MBEDTLS_SSL_HASH_NONE == hash || mbedtls_ssl_set_calc_verify_md( ssl, hash ) ) + continue; + +#if defined(MBEDTLS_RSA_C) + p[2 + sa_len++] = hash; + p[2 + sa_len++] = MBEDTLS_SSL_SIG_RSA; +#endif +#if defined(MBEDTLS_ECDSA_C) + p[2 + sa_len++] = hash; + p[2 + sa_len++] = MBEDTLS_SSL_SIG_ECDSA; +#endif + } + + p[0] = (unsigned char)( sa_len >> 8 ); + p[1] = (unsigned char)( sa_len ); + sa_len += 2; + p += sa_len; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + /* + * DistinguishedName certificate_authorities<0..2^16-1>; + * opaque DistinguishedName<1..2^16-1>; + */ + p += 2; + + total_dn_size = 0; + + if( ssl->conf->cert_req_ca_list == MBEDTLS_SSL_CERT_REQ_CA_LIST_ENABLED ) + { + /* NOTE: If trusted certificates are provisioned + * via a CA callback (configured through + * `mbedtls_ssl_conf_ca_cb()`, then the + * CertificateRequest is currently left empty. */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_ca_chain != NULL ) + crt = ssl->handshake->sni_ca_chain; + else +#endif + crt = ssl->conf->ca_chain; + + while( crt != NULL && crt->version != 0 ) + { + dn_size = crt->subject_raw.len; + + if( end < p || + (size_t)( end - p ) < dn_size || + (size_t)( end - p ) < 2 + dn_size ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "skipping CAs: buffer too short" ) ); + break; + } + + *p++ = (unsigned char)( dn_size >> 8 ); + *p++ = (unsigned char)( dn_size ); + memcpy( p, crt->subject_raw.p, dn_size ); + p += dn_size; + + MBEDTLS_SSL_DEBUG_BUF( 3, "requested DN", p - dn_size, dn_size ); + + total_dn_size += 2 + dn_size; + crt = crt->next; + } + } + + ssl->out_msglen = p - buf; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE_REQUEST; + ssl->out_msg[4 + ct_len + sa_len] = (unsigned char)( total_dn_size >> 8 ); + ssl->out_msg[5 + ct_len + sa_len] = (unsigned char)( total_dn_size ); + + ret = mbedtls_ssl_write_handshake_msg( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate request" ) ); + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl ) +{ + int ret; + + if( ! mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_ECKEY ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key not ECDH capable" ) ); + return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + } + + if( ( ret = mbedtls_ecdh_get_params( &ssl->handshake->ecdh_ctx, + mbedtls_pk_ec( *mbedtls_ssl_own_key( ssl ) ), + MBEDTLS_ECDH_OURS ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_get_params" ), ret ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \ + defined(MBEDTLS_SSL_ASYNC_PRIVATE) +static int ssl_resume_server_key_exchange( mbedtls_ssl_context *ssl, + size_t *signature_len ) +{ + /* Append the signature to ssl->out_msg, leaving 2 bytes for the + * signature length which will be added in ssl_write_server_key_exchange + * after the call to ssl_prepare_server_key_exchange. + * ssl_write_server_key_exchange also takes care of incrementing + * ssl->out_msglen. */ + unsigned char *sig_start = ssl->out_msg + ssl->out_msglen + 2; + size_t sig_max_len = ( ssl->out_buf + MBEDTLS_SSL_OUT_CONTENT_LEN + - sig_start ); + int ret = ssl->conf->f_async_resume( ssl, + sig_start, signature_len, sig_max_len ); + if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + { + ssl->handshake->async_in_progress = 0; + mbedtls_ssl_set_async_operation_data( ssl, NULL ); + } + MBEDTLS_SSL_DEBUG_RET( 2, "ssl_resume_server_key_exchange", ret ); + return( ret ); +} +#endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && + defined(MBEDTLS_SSL_ASYNC_PRIVATE) */ + +/* Prepare the ServerKeyExchange message, up to and including + * calculating the signature if any, but excluding formatting the + * signature and sending the message. */ +static int ssl_prepare_server_key_exchange( mbedtls_ssl_context *ssl, + size_t *signature_len ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED) +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) + unsigned char *dig_signed = NULL; +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ +#endif /* MBEDTLS_KEY_EXCHANGE__SOME_PFS__ENABLED */ + + (void) ciphersuite_info; /* unused in some configurations */ +#if !defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) + (void) signature_len; +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ + + ssl->out_msglen = 4; /* header (type:1, length:3) to be written later */ + + /* + * + * Part 1: Provide key exchange parameters for chosen ciphersuite. + * + */ + + /* + * - ECJPAKE key exchanges + */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + int ret; + size_t len = 0; + + ret = mbedtls_ecjpake_write_round_two( + &ssl->handshake->ecjpake_ctx, + ssl->out_msg + ssl->out_msglen, + MBEDTLS_SSL_OUT_CONTENT_LEN - ssl->out_msglen, &len, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_write_round_two", ret ); + return( ret ); + } + + ssl->out_msglen += len; + } +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + + /* + * For (EC)DHE key exchanges with PSK, parameters are prefixed by support + * identity hint (RFC 4279, Sec. 3). Until someone needs this feature, + * we use empty support identity hints here. + **/ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + ssl->out_msg[ssl->out_msglen++] = 0x00; + ssl->out_msg[ssl->out_msglen++] = 0x00; + } +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + + /* + * - DHE key exchanges + */ +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED) + if( mbedtls_ssl_ciphersuite_uses_dhe( ciphersuite_info ) ) + { + int ret; + size_t len = 0; + + if( ssl->conf->dhm_P.p == NULL || ssl->conf->dhm_G.p == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no DH parameters set" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* + * Ephemeral DH parameters: + * + * struct { + * opaque dh_p<1..2^16-1>; + * opaque dh_g<1..2^16-1>; + * opaque dh_Ys<1..2^16-1>; + * } ServerDHParams; + */ + if( ( ret = mbedtls_dhm_set_group( &ssl->handshake->dhm_ctx, + &ssl->conf->dhm_P, + &ssl->conf->dhm_G ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_set_group", ret ); + return( ret ); + } + + if( ( ret = mbedtls_dhm_make_params( + &ssl->handshake->dhm_ctx, + (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ), + ssl->out_msg + ssl->out_msglen, &len, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_params", ret ); + return( ret ); + } + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) + dig_signed = ssl->out_msg + ssl->out_msglen; +#endif + + ssl->out_msglen += len; + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->handshake->dhm_ctx.X ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->handshake->dhm_ctx.P ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: G ", &ssl->handshake->dhm_ctx.G ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: GX", &ssl->handshake->dhm_ctx.GX ); + } +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__DHE_ENABLED */ + + /* + * - ECDHE key exchanges + */ +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED) + if( mbedtls_ssl_ciphersuite_uses_ecdhe( ciphersuite_info ) ) + { + /* + * Ephemeral ECDH parameters: + * + * struct { + * ECParameters curve_params; + * ECPoint public; + * } ServerECDHParams; + */ + const mbedtls_ecp_curve_info **curve = NULL; + const mbedtls_ecp_group_id *gid; + int ret; + size_t len = 0; + + /* Match our preference list against the offered curves */ + for( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ ) + for( curve = ssl->handshake->curves; *curve != NULL; curve++ ) + if( (*curve)->grp_id == *gid ) + goto curve_matching_done; + +curve_matching_done: + if( curve == NULL || *curve == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no matching curve for ECDHE" ) ); + return( MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDHE curve: %s", (*curve)->name ) ); + + if( ( ret = mbedtls_ecdh_setup( &ssl->handshake->ecdh_ctx, + (*curve)->grp_id ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecp_group_load", ret ); + return( ret ); + } + + if( ( ret = mbedtls_ecdh_make_params( + &ssl->handshake->ecdh_ctx, &len, + ssl->out_msg + ssl->out_msglen, + MBEDTLS_SSL_OUT_CONTENT_LEN - ssl->out_msglen, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_params", ret ); + return( ret ); + } + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) + dig_signed = ssl->out_msg + ssl->out_msglen; +#endif + + ssl->out_msglen += len; + + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Q ); + } +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED */ + + /* + * + * Part 2: For key exchanges involving the server signing the + * exchange parameters, compute and add the signature here. + * + */ +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) + if( mbedtls_ssl_ciphersuite_uses_server_signature( ciphersuite_info ) ) + { + size_t dig_signed_len = ssl->out_msg + ssl->out_msglen - dig_signed; + size_t hashlen = 0; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + int ret; + + /* + * 2.1: Choose hash algorithm: + * A: For TLS 1.2, obey signature-hash-algorithm extension + * to choose appropriate hash. + * B: For SSL3, TLS1.0, TLS1.1 and ECDHE_ECDSA, use SHA1 + * (RFC 4492, Sec. 5.4) + * C: Otherwise, use MD5 + SHA1 (RFC 4346, Sec. 7.4.3) + */ + + mbedtls_md_type_t md_alg; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + mbedtls_pk_type_t sig_alg = + mbedtls_ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ); + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + /* A: For TLS 1.2, obey signature-hash-algorithm extension + * (RFC 5246, Sec. 7.4.1.4.1). */ + if( sig_alg == MBEDTLS_PK_NONE || + ( md_alg = mbedtls_ssl_sig_hash_set_find( &ssl->handshake->hash_algs, + sig_alg ) ) == MBEDTLS_MD_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + /* (... because we choose a cipher suite + * only if there is a matching hash.) */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + /* B: Default hash SHA1 */ + md_alg = MBEDTLS_MD_SHA1; + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || \ + MBEDTLS_SSL_PROTO_TLS1_1 */ + { + /* C: MD5 + SHA1 */ + md_alg = MBEDTLS_MD_NONE; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "pick hash algorithm %d for signing", md_alg ) ); + + /* + * 2.2: Compute the hash to be signed + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( md_alg == MBEDTLS_MD_NONE ) + { + hashlen = 36; + ret = mbedtls_ssl_get_key_exchange_md_ssl_tls( ssl, hash, + dig_signed, + dig_signed_len ); + if( ret != 0 ) + return( ret ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || \ + MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( md_alg != MBEDTLS_MD_NONE ) + { + ret = mbedtls_ssl_get_key_exchange_md_tls1_2( ssl, hash, &hashlen, + dig_signed, + dig_signed_len, + md_alg ); + if( ret != 0 ) + return( ret ); + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen ); + + /* + * 2.3: Compute and add the signature + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + /* + * For TLS 1.2, we need to specify signature and hash algorithm + * explicitly through a prefix to the signature. + * + * struct { + * HashAlgorithm hash; + * SignatureAlgorithm signature; + * } SignatureAndHashAlgorithm; + * + * struct { + * SignatureAndHashAlgorithm algorithm; + * opaque signature<0..2^16-1>; + * } DigitallySigned; + * + */ + + ssl->out_msg[ssl->out_msglen++] = + mbedtls_ssl_hash_from_md_alg( md_alg ); + ssl->out_msg[ssl->out_msglen++] = + mbedtls_ssl_sig_from_pk_alg( sig_alg ); + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + if( ssl->conf->f_async_sign_start != NULL ) + { + ret = ssl->conf->f_async_sign_start( ssl, + mbedtls_ssl_own_cert( ssl ), + md_alg, hash, hashlen ); + switch( ret ) + { + case MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH: + /* act as if f_async_sign was null */ + break; + case 0: + ssl->handshake->async_in_progress = 1; + return( ssl_resume_server_key_exchange( ssl, signature_len ) ); + case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS: + ssl->handshake->async_in_progress = 1; + return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); + default: + MBEDTLS_SSL_DEBUG_RET( 1, "f_async_sign_start", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + + if( mbedtls_ssl_own_key( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* Append the signature to ssl->out_msg, leaving 2 bytes for the + * signature length which will be added in ssl_write_server_key_exchange + * after the call to ssl_prepare_server_key_exchange. + * ssl_write_server_key_exchange also takes care of incrementing + * ssl->out_msglen. */ + if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), + md_alg, hash, hashlen, + ssl->out_msg + ssl->out_msglen + 2, + signature_len, + ssl->conf->f_rng, + ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ + + return( 0 ); +} + +/* Prepare the ServerKeyExchange message and send it. For ciphersuites + * that do not include a ServerKeyExchange message, do nothing. Either + * way, if successful, move on to the next step in the SSL state + * machine. */ +static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t signature_len = 0; +#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED) + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; +#endif /* MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED) + /* Extract static ECDH parameters and abort if ServerKeyExchange + * is not needed. */ + if( mbedtls_ssl_ciphersuite_no_pfs( ciphersuite_info ) ) + { + /* For suites involving ECDH, extract DH parameters + * from certificate at this point. */ +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED) + if( mbedtls_ssl_ciphersuite_uses_ecdh( ciphersuite_info ) ) + { + ssl_get_ecdh_params_from_cert( ssl ); + } +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDH_ENABLED */ + + /* Key exchanges not involving ephemeral keys don't use + * ServerKeyExchange, so end here. */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) ); + ssl->state++; + return( 0 ); + } +#endif /* MBEDTLS_KEY_EXCHANGE__SOME_NON_PFS__ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && \ + defined(MBEDTLS_SSL_ASYNC_PRIVATE) + /* If we have already prepared the message and there is an ongoing + * signature operation, resume signing. */ + if( ssl->handshake->async_in_progress != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming signature operation" ) ); + ret = ssl_resume_server_key_exchange( ssl, &signature_len ); + } + else +#endif /* defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) && + defined(MBEDTLS_SSL_ASYNC_PRIVATE) */ + { + /* ServerKeyExchange is needed. Prepare the message. */ + ret = ssl_prepare_server_key_exchange( ssl, &signature_len ); + } + + if( ret != 0 ) + { + /* If we're starting to write a new message, set ssl->out_msglen + * to 0. But if we're resuming after an asynchronous message, + * out_msglen is the amount of data written so far and mst be + * preserved. */ + if( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange (pending)" ) ); + else + ssl->out_msglen = 0; + return( ret ); + } + + /* If there is a signature, write its length. + * ssl_prepare_server_key_exchange already wrote the signature + * itself at its proper place in the output buffer. */ +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED) + if( signature_len != 0 ) + { + ssl->out_msg[ssl->out_msglen++] = (unsigned char)( signature_len >> 8 ); + ssl->out_msg[ssl->out_msglen++] = (unsigned char)( signature_len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "my signature", + ssl->out_msg + ssl->out_msglen, + signature_len ); + + /* Skip over the already-written signature */ + ssl->out_msglen += signature_len; + } +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_SERVER_SIGNATURE__ENABLED */ + + /* Add header and send. */ + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE; + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange" ) ); + return( 0 ); +} + +static int ssl_write_server_hello_done( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server hello done" ) ); + + ssl->out_msglen = 4; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_HELLO_DONE; + + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_send_flight_completed( ssl ); +#endif + + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); + return( ret ); + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello done" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) +static int ssl_parse_client_dh_public( mbedtls_ssl_context *ssl, unsigned char **p, + const unsigned char *end ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t n; + + /* + * Receive G^Y mod P, premaster = (G^Y)^X mod P + */ + if( *p + 2 > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + n = ( (*p)[0] << 8 ) | (*p)[1]; + *p += 2; + + if( *p + n > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ( ret = mbedtls_dhm_read_public( &ssl->handshake->dhm_ctx, *p, n ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_read_public", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP ); + } + + *p += n; + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: GY", &ssl->handshake->dhm_ctx.GY ); + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) +static int ssl_resume_decrypt_pms( mbedtls_ssl_context *ssl, + unsigned char *peer_pms, + size_t *peer_pmslen, + size_t peer_pmssize ) +{ + int ret = ssl->conf->f_async_resume( ssl, + peer_pms, peer_pmslen, peer_pmssize ); + if( ret != MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + { + ssl->handshake->async_in_progress = 0; + mbedtls_ssl_set_async_operation_data( ssl, NULL ); + } + MBEDTLS_SSL_DEBUG_RET( 2, "ssl_decrypt_encrypted_pms", ret ); + return( ret ); +} +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + +static int ssl_decrypt_encrypted_pms( mbedtls_ssl_context *ssl, + const unsigned char *p, + const unsigned char *end, + unsigned char *peer_pms, + size_t *peer_pmslen, + size_t peer_pmssize ) +{ + int ret; + mbedtls_pk_context *private_key = mbedtls_ssl_own_key( ssl ); + mbedtls_pk_context *public_key = &mbedtls_ssl_own_cert( ssl )->pk; + size_t len = mbedtls_pk_get_len( public_key ); + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + /* If we have already started decoding the message and there is an ongoing + * decryption operation, resume signing. */ + if( ssl->handshake->async_in_progress != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "resuming decryption operation" ) ); + return( ssl_resume_decrypt_pms( ssl, + peer_pms, peer_pmslen, peer_pmssize ) ); + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + + /* + * Prepare to decrypt the premaster using own private RSA key + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if ( p + 2 > end ) { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + if( *p++ != ( ( len >> 8 ) & 0xFF ) || + *p++ != ( ( len ) & 0xFF ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + } +#endif + + if( p + len != end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + /* + * Decrypt the premaster secret + */ +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + if( ssl->conf->f_async_decrypt_start != NULL ) + { + ret = ssl->conf->f_async_decrypt_start( ssl, + mbedtls_ssl_own_cert( ssl ), + p, len ); + switch( ret ) + { + case MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH: + /* act as if f_async_decrypt_start was null */ + break; + case 0: + ssl->handshake->async_in_progress = 1; + return( ssl_resume_decrypt_pms( ssl, + peer_pms, + peer_pmslen, + peer_pmssize ) ); + case MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS: + ssl->handshake->async_in_progress = 1; + return( MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ); + default: + MBEDTLS_SSL_DEBUG_RET( 1, "f_async_decrypt_start", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + + if( ! mbedtls_pk_can_do( private_key, MBEDTLS_PK_RSA ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no RSA private key" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + ret = mbedtls_pk_decrypt( private_key, p, len, + peer_pms, peer_pmslen, peer_pmssize, + ssl->conf->f_rng, ssl->conf->p_rng ); + return( ret ); +} + +static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, + const unsigned char *p, + const unsigned char *end, + size_t pms_offset ) +{ + int ret; + unsigned char *pms = ssl->handshake->premaster + pms_offset; + unsigned char ver[2]; + unsigned char fake_pms[48], peer_pms[48]; + unsigned char mask; + size_t i, peer_pmslen; + unsigned int diff; + + /* In case of a failure in decryption, the decryption may write less than + * 2 bytes of output, but we always read the first two bytes. It doesn't + * matter in the end because diff will be nonzero in that case due to + * peer_pmslen being less than 48, and we only care whether diff is 0. + * But do initialize peer_pms for robustness anyway. This also makes + * memory analyzers happy (don't access uninitialized memory, even + * if it's an unsigned char). */ + peer_pms[0] = peer_pms[1] = ~0; + + ret = ssl_decrypt_encrypted_pms( ssl, p, end, + peer_pms, + &peer_pmslen, + sizeof( peer_pms ) ); + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + if ( ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS ) + return( ret ); +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + + mbedtls_ssl_write_version( ssl->handshake->max_major_ver, + ssl->handshake->max_minor_ver, + ssl->conf->transport, ver ); + + /* Avoid data-dependent branches while checking for invalid + * padding, to protect against timing-based Bleichenbacher-type + * attacks. */ + diff = (unsigned int) ret; + diff |= peer_pmslen ^ 48; + diff |= peer_pms[0] ^ ver[0]; + diff |= peer_pms[1] ^ ver[1]; + + /* mask = diff ? 0xff : 0x00 using bit operations to avoid branches */ + /* MSVC has a warning about unary minus on unsigned, but this is + * well-defined and precisely what we want to do here */ +#if defined(_MSC_VER) +#pragma warning( push ) +#pragma warning( disable : 4146 ) +#endif + mask = - ( ( diff | - diff ) >> ( sizeof( unsigned int ) * 8 - 1 ) ); +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif + + /* + * Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding + * must not cause the connection to end immediately; instead, send a + * bad_record_mac later in the handshake. + * To protect against timing-based variants of the attack, we must + * not have any branch that depends on whether the decryption was + * successful. In particular, always generate the fake premaster secret, + * regardless of whether it will ultimately influence the output or not. + */ + ret = ssl->conf->f_rng( ssl->conf->p_rng, fake_pms, sizeof( fake_pms ) ); + if( ret != 0 ) + { + /* It's ok to abort on an RNG failure, since this does not reveal + * anything about the RSA decryption. */ + return( ret ); + } + +#if defined(MBEDTLS_SSL_DEBUG_ALL) + if( diff != 0 ) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); +#endif + + if( sizeof( ssl->handshake->premaster ) < pms_offset || + sizeof( ssl->handshake->premaster ) - pms_offset < 48 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + ssl->handshake->pmslen = 48; + + /* Set pms to either the true or the fake PMS, without + * data-dependent branches. */ + for( i = 0; i < ssl->handshake->pmslen; i++ ) + pms[i] = ( mask & fake_pms[i] ) | ( (~mask) & peer_pms[i] ); + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +static int ssl_parse_client_psk_identity( mbedtls_ssl_context *ssl, unsigned char **p, + const unsigned char *end ) +{ + int ret = 0; + size_t n; + + if( ssl_conf_has_psk_or_cb( ssl->conf ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no pre-shared key" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* + * Receive client pre-shared key identity name + */ + if( end - *p < 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + n = ( (*p)[0] << 8 ) | (*p)[1]; + *p += 2; + + if( n < 1 || n > 65535 || n > (size_t) ( end - *p ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ssl->conf->f_psk != NULL ) + { + if( ssl->conf->f_psk( ssl->conf->p_psk, ssl, *p, n ) != 0 ) + ret = MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY; + } + else + { + /* Identity is not a big secret since clients send it in the clear, + * but treat it carefully anyway, just in case */ + if( n != ssl->conf->psk_identity_len || + mbedtls_ssl_safer_memcmp( ssl->conf->psk_identity, *p, n ) != 0 ) + { + ret = MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY; + } + } + + if( ret == MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY ) + { + MBEDTLS_SSL_DEBUG_BUF( 3, "Unknown PSK identity", *p, n ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY ); + return( MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY ); + } + + *p += n; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + unsigned char *p, *end; + + ciphersuite_info = ssl->handshake->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client key exchange" ) ); + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) && \ + ( defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) ) + if( ( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA ) && + ( ssl->handshake->async_in_progress != 0 ) ) + { + /* We've already read a record and there is an asynchronous + * operation in progress to decrypt it. So skip reading the + * record. */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "will resume decryption of previously-read record" ) ); + } + else +#endif + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + p = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + end = ssl->in_msg + ssl->in_hslen; + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA ) + { + if( ( ret = ssl_parse_client_dh_public( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_dh_public" ), ret ); + return( ret ); + } + + if( p != end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ( ret = mbedtls_dhm_calc_secret( &ssl->handshake->dhm_ctx, + ssl->handshake->premaster, + MBEDTLS_PREMASTER_SIZE, + &ssl->handshake->pmslen, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->handshake->dhm_ctx.K ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA ) + { + if( ( ret = mbedtls_ecdh_read_public( &ssl->handshake->ecdh_ctx, + p, end - p) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_read_public", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP ); + } + + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_QP ); + + if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, + &ssl->handshake->pmslen, + ssl->handshake->premaster, + MBEDTLS_MPI_MAX_SIZE, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS ); + } + + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Z ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ) + { + if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret ); + return( ret ); + } + + if( p != end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + /* For opaque PSKs, we perform the PSK-to-MS derivation atomatically + * and skip the intermediate PMS. */ + if( ssl_use_opaque_psk( ssl ) == 1 ) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "skip PMS generation for opaque PSK" ) ); + else +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + if ( ssl->handshake->async_in_progress != 0 ) + { + /* There is an asynchronous operation in progress to + * decrypt the encrypted premaster secret, so skip + * directly to resuming this operation. */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "PSK identity already parsed" ) ); + /* Update p to skip the PSK identity. ssl_parse_encrypted_pms + * won't actually use it, but maintain p anyway for robustness. */ + p += ssl->conf->psk_identity_len + 2; + } + else +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret ); + return( ret ); + } + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + /* Opaque PSKs are currently only supported for PSK-only. */ + if( ssl_use_opaque_psk( ssl ) == 1 ) + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +#endif + + if( ( ret = ssl_parse_encrypted_pms( ssl, p, end, 2 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_encrypted_pms" ), ret ); + return( ret ); + } + + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { + if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret ); + return( ret ); + } + if( ( ret = ssl_parse_client_dh_public( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_dh_public" ), ret ); + return( ret ); + } + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + /* Opaque PSKs are currently only supported for PSK-only. */ + if( ssl_use_opaque_psk( ssl ) == 1 ) + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +#endif + + if( p != end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret ); + return( ret ); + } + + if( ( ret = mbedtls_ecdh_read_public( &ssl->handshake->ecdh_ctx, + p, end - p ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_read_public", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP ); + } + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + /* Opaque PSKs are currently only supported for PSK-only. */ + if( ssl_use_opaque_psk( ssl ) == 1 ) + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +#endif + + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_QP ); + + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA ) + { + if( ( ret = ssl_parse_encrypted_pms( ssl, p, end, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_parse_encrypted_pms_secret" ), ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + ret = mbedtls_ecjpake_read_round_two( &ssl->handshake->ecjpake_ctx, + p, end - p ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_two", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + ret = mbedtls_ecjpake_derive_secret( &ssl->handshake->ecjpake_ctx, + ssl->handshake->premaster, 32, &ssl->handshake->pmslen, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_derive_secret", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + return( ret ); + } + + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse client key exchange" ) ); + + return( 0 ); +} + +#if !defined(MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED) +static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) ); + + if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} +#else /* !MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */ +static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t i, sig_len; + unsigned char hash[48]; + unsigned char *hash_start = hash; + size_t hashlen; +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + mbedtls_pk_type_t pk_alg; +#endif + mbedtls_md_type_t md_alg; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + mbedtls_pk_context * peer_pk; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) ); + + if( !mbedtls_ssl_ciphersuite_cert_req_allowed( ciphersuite_info ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) ); + ssl->state++; + return( 0 ); + } + +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + if( ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) ); + ssl->state++; + return( 0 ); + } +#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + if( ssl->session_negotiate->peer_cert_digest == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) ); + ssl->state++; + return( 0 ); + } +#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + + /* Read the message without adding it to the checksum */ + ret = mbedtls_ssl_read_record( ssl, 0 /* no checksum update */ ); + if( 0 != ret ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record" ), ret ); + return( ret ); + } + + ssl->state++; + + /* Process the message contents */ + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || + ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE_VERIFY ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + i = mbedtls_ssl_hs_hdr_len( ssl ); + +#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + peer_pk = &ssl->handshake->peer_pubkey; +#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + if( ssl->session_negotiate->peer_cert == NULL ) + { + /* Should never happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + peer_pk = &ssl->session_negotiate->peer_cert->pk; +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + + /* + * struct { + * SignatureAndHashAlgorithm algorithm; -- TLS 1.2 only + * opaque signature<0..2^16-1>; + * } DigitallySigned; + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) + { + md_alg = MBEDTLS_MD_NONE; + hashlen = 36; + + /* For ECDSA, use SHA-1, not MD-5 + SHA-1 */ + if( mbedtls_pk_can_do( peer_pk, MBEDTLS_PK_ECDSA ) ) + { + hash_start += 16; + hashlen -= 16; + md_alg = MBEDTLS_MD_SHA1; + } + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || + MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + if( i + 2 > ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + /* + * Hash + */ + md_alg = mbedtls_ssl_md_alg_from_hash( ssl->in_msg[i] ); + + if( md_alg == MBEDTLS_MD_NONE || mbedtls_ssl_set_calc_verify_md( ssl, ssl->in_msg[i] ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg" + " for verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + +#if !defined(MBEDTLS_MD_SHA1) + if( MBEDTLS_MD_SHA1 == md_alg ) + hash_start += 16; +#endif + + /* Info from md_alg will be used instead */ + hashlen = 0; + + i++; + + /* + * Signature + */ + if( ( pk_alg = mbedtls_ssl_pk_alg_from_sig( ssl->in_msg[i] ) ) + == MBEDTLS_PK_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg" + " for verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + /* + * Check the certificate's key type matches the signature alg + */ + if( !mbedtls_pk_can_do( peer_pk, pk_alg ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "sig_alg doesn't match cert key" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + i++; + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( i + 2 > ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + sig_len = ( ssl->in_msg[i] << 8 ) | ssl->in_msg[i+1]; + i += 2; + + if( i + sig_len != ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + /* Calculate hash and verify signature */ + ssl->handshake->calc_verify( ssl, hash ); + + if( ( ret = mbedtls_pk_verify( peer_pk, + md_alg, hash_start, hashlen, + ssl->in_msg + i, sig_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret ); + return( ret ); + } + + mbedtls_ssl_update_handshake_status( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate verify" ) ); + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__CERT_REQ_ALLOWED__ENABLED */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static int ssl_write_new_session_ticket( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t tlen; + uint32_t lifetime; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write new session ticket" ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_NEW_SESSION_TICKET; + + /* + * struct { + * uint32 ticket_lifetime_hint; + * opaque ticket<0..2^16-1>; + * } NewSessionTicket; + * + * 4 . 7 ticket_lifetime_hint (0 = unspecified) + * 8 . 9 ticket_len (n) + * 10 . 9+n ticket content + */ + + if( ( ret = ssl->conf->f_ticket_write( ssl->conf->p_ticket, + ssl->session_negotiate, + ssl->out_msg + 10, + ssl->out_msg + MBEDTLS_SSL_OUT_CONTENT_LEN, + &tlen, &lifetime ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_ticket_write", ret ); + tlen = 0; + } + + ssl->out_msg[4] = ( lifetime >> 24 ) & 0xFF; + ssl->out_msg[5] = ( lifetime >> 16 ) & 0xFF; + ssl->out_msg[6] = ( lifetime >> 8 ) & 0xFF; + ssl->out_msg[7] = ( lifetime ) & 0xFF; + + ssl->out_msg[8] = (unsigned char)( ( tlen >> 8 ) & 0xFF ); + ssl->out_msg[9] = (unsigned char)( ( tlen ) & 0xFF ); + + ssl->out_msglen = 10 + tlen; + + /* + * Morally equivalent to updating ssl->state, but NewSessionTicket and + * ChangeCipherSpec share the same state. + */ + ssl->handshake->new_session_ticket = 0; + + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write new session ticket" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +/* + * SSL handshake -- server side -- single step + */ +int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "server state: %d", ssl->state ) ); + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) + { + if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + return( ret ); + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + switch( ssl->state ) + { + case MBEDTLS_SSL_HELLO_REQUEST: + ssl->state = MBEDTLS_SSL_CLIENT_HELLO; + break; + + /* + * <== ClientHello + */ + case MBEDTLS_SSL_CLIENT_HELLO: + ret = ssl_parse_client_hello( ssl ); + break; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + case MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT: + return( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ); +#endif + + /* + * ==> ServerHello + * Certificate + * ( ServerKeyExchange ) + * ( CertificateRequest ) + * ServerHelloDone + */ + case MBEDTLS_SSL_SERVER_HELLO: + ret = ssl_write_server_hello( ssl ); + break; + + case MBEDTLS_SSL_SERVER_CERTIFICATE: + ret = mbedtls_ssl_write_certificate( ssl ); + break; + + case MBEDTLS_SSL_SERVER_KEY_EXCHANGE: + ret = ssl_write_server_key_exchange( ssl ); + break; + + case MBEDTLS_SSL_CERTIFICATE_REQUEST: + ret = ssl_write_certificate_request( ssl ); + break; + + case MBEDTLS_SSL_SERVER_HELLO_DONE: + ret = ssl_write_server_hello_done( ssl ); + break; + + /* + * <== ( Certificate/Alert ) + * ClientKeyExchange + * ( CertificateVerify ) + * ChangeCipherSpec + * Finished + */ + case MBEDTLS_SSL_CLIENT_CERTIFICATE: + ret = mbedtls_ssl_parse_certificate( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE: + ret = ssl_parse_client_key_exchange( ssl ); + break; + + case MBEDTLS_SSL_CERTIFICATE_VERIFY: + ret = ssl_parse_certificate_verify( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC: + ret = mbedtls_ssl_parse_change_cipher_spec( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_FINISHED: + ret = mbedtls_ssl_parse_finished( ssl ); + break; + + /* + * ==> ( NewSessionTicket ) + * ChangeCipherSpec + * Finished + */ + case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC: +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + if( ssl->handshake->new_session_ticket != 0 ) + ret = ssl_write_new_session_ticket( ssl ); + else +#endif + ret = mbedtls_ssl_write_change_cipher_spec( ssl ); + break; + + case MBEDTLS_SSL_SERVER_FINISHED: + ret = mbedtls_ssl_write_finished( ssl ); + break; + + case MBEDTLS_SSL_FLUSH_BUFFERS: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake: done" ) ); + ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP; + break; + + case MBEDTLS_SSL_HANDSHAKE_WRAPUP: + mbedtls_ssl_handshake_wrapup( ssl ); + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + return( ret ); +} +#endif /* MBEDTLS_SSL_SRV_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ssl_ticket.c b/FreeRTOS-Labs/Source/mbedtls/library/ssl_ticket.c new file mode 100644 index 000000000..241a887c3 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ssl_ticket.c @@ -0,0 +1,595 @@ +/* + * TLS server tickets callbacks implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_TICKET_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/ssl_ticket.h" +#include "mbedtls/platform_util.h" + +#include + +/* + * Initialze context + */ +void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ssl_ticket_context ) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +#define MAX_KEY_BYTES 32 /* 256 bits */ + +#define TICKET_KEY_NAME_BYTES 4 +#define TICKET_IV_BYTES 12 +#define TICKET_CRYPT_LEN_BYTES 2 +#define TICKET_AUTH_TAG_BYTES 16 + +#define TICKET_MIN_LEN ( TICKET_KEY_NAME_BYTES + \ + TICKET_IV_BYTES + \ + TICKET_CRYPT_LEN_BYTES + \ + TICKET_AUTH_TAG_BYTES ) +#define TICKET_ADD_DATA_LEN ( TICKET_KEY_NAME_BYTES + \ + TICKET_IV_BYTES + \ + TICKET_CRYPT_LEN_BYTES ) + +/* + * Generate/update a key + */ +static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx, + unsigned char index ) +{ + int ret; + unsigned char buf[MAX_KEY_BYTES]; + mbedtls_ssl_ticket_key *key = ctx->keys + index; + +#if defined(MBEDTLS_HAVE_TIME) + key->generation_time = (uint32_t) mbedtls_time( NULL ); +#endif + + if( ( ret = ctx->f_rng( ctx->p_rng, key->name, sizeof( key->name ) ) ) != 0 ) + return( ret ); + + if( ( ret = ctx->f_rng( ctx->p_rng, buf, sizeof( buf ) ) ) != 0 ) + return( ret ); + + /* With GCM and CCM, same context can encrypt & decrypt */ + ret = mbedtls_cipher_setkey( &key->ctx, buf, + mbedtls_cipher_get_key_bitlen( &key->ctx ), + MBEDTLS_ENCRYPT ); + + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + + return( ret ); +} + +/* + * Rotate/generate keys if necessary + */ +static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx ) +{ +#if !defined(MBEDTLS_HAVE_TIME) + ((void) ctx); +#else + if( ctx->ticket_lifetime != 0 ) + { + uint32_t current_time = (uint32_t) mbedtls_time( NULL ); + uint32_t key_time = ctx->keys[ctx->active].generation_time; + + if( current_time >= key_time && + current_time - key_time < ctx->ticket_lifetime ) + { + return( 0 ); + } + + ctx->active = 1 - ctx->active; + + return( ssl_ticket_gen_key( ctx, ctx->active ) ); + } + else +#endif /* MBEDTLS_HAVE_TIME */ + return( 0 ); +} + +/* + * Setup context for actual use + */ +int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_cipher_type_t cipher, + uint32_t lifetime ) +{ + int ret; + const mbedtls_cipher_info_t *cipher_info; + + ctx->f_rng = f_rng; + ctx->p_rng = p_rng; + + ctx->ticket_lifetime = lifetime; + + cipher_info = mbedtls_cipher_info_from_type( cipher); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( cipher_info->mode != MBEDTLS_MODE_GCM && + cipher_info->mode != MBEDTLS_MODE_CCM ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + ret = mbedtls_cipher_setup_psa( &ctx->keys[0].ctx, + cipher_info, TICKET_AUTH_TAG_BYTES ); + if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ) + return( ret ); + /* We don't yet expect to support all ciphers through PSA, + * so allow fallback to ordinary mbedtls_cipher_setup(). */ + if( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ) +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + if( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + ret = mbedtls_cipher_setup_psa( &ctx->keys[1].ctx, + cipher_info, TICKET_AUTH_TAG_BYTES ); + if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ) + return( ret ); + if( ret == MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ) +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + if( ( ret = mbedtls_cipher_setup( &ctx->keys[1].ctx, cipher_info ) ) != 0 ) + return( ret ); + + if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 || + ( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +/* + * Serialize a session in the following format: + * + * - If MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is enabled: + * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session) + * n . n+2 peer_cert length = m (0 if no certificate) + * n+3 . n+2+m peer cert ASN.1 + * + * - If MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is disabled: + * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session) + * n . n length of peer certificate digest = k (0 if no digest) + * n+1 . n+k peer certificate digest (digest type encoded in session) + */ +static int ssl_save_session( const mbedtls_ssl_session *session, + unsigned char *buf, size_t buf_len, + size_t *olen ) +{ + unsigned char *p = buf; + size_t left = buf_len; +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + size_t cert_len; +#else + size_t cert_digest_len; +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + if( left < sizeof( mbedtls_ssl_session ) ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + /* This also copies the values of pointer fields in the + * session to be serialized, but they'll be ignored when + * loading the session through ssl_load_session(). */ + memcpy( p, session, sizeof( mbedtls_ssl_session ) ); + p += sizeof( mbedtls_ssl_session ); + left -= sizeof( mbedtls_ssl_session ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + if( session->peer_cert == NULL ) + cert_len = 0; + else + cert_len = session->peer_cert->raw.len; + + if( left < 3 + cert_len ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + *p++ = (unsigned char)( ( cert_len >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( cert_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( cert_len ) & 0xFF ); + left -= 3; + + if( session->peer_cert != NULL ) + memcpy( p, session->peer_cert->raw.p, cert_len ); + + p += cert_len; + left -= cert_len; +#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + if( session->peer_cert_digest != NULL ) + cert_digest_len = 0; + else + cert_digest_len = session->peer_cert_digest_len; + + if( left < 1 + cert_digest_len ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + *p++ = (unsigned char) cert_digest_len; + left--; + + if( session->peer_cert_digest != NULL ) + memcpy( p, session->peer_cert_digest, cert_digest_len ); + + p += cert_digest_len; + left -= cert_digest_len; +#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + *olen = p - buf; + + return( 0 ); +} + +/* + * Unserialise session, see ssl_save_session() + */ +static int ssl_load_session( mbedtls_ssl_session *session, + const unsigned char *buf, size_t len ) +{ + const unsigned char *p = buf; + const unsigned char * const end = buf + len; +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + size_t cert_len; +#else + size_t cert_digest_len; +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + if( sizeof( mbedtls_ssl_session ) > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + memcpy( session, p, sizeof( mbedtls_ssl_session ) ); + p += sizeof( mbedtls_ssl_session ); + + /* Non-NULL pointer fields of `session` are meaningless + * and potentially harmful. Zeroize them for safety. */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + session->peer_cert = NULL; +#else + session->peer_cert_digest = NULL; +#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) + session->ticket = NULL; +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + /* Deserialize CRT from the end of the ticket. */ + if( 3 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2]; + p += 3; + + if( cert_len != 0 ) + { + int ret; + + if( cert_len > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + session->peer_cert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); + + if( session->peer_cert == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + mbedtls_x509_crt_init( session->peer_cert ); + + if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert, + p, cert_len ) ) != 0 ) + { + mbedtls_x509_crt_free( session->peer_cert ); + mbedtls_free( session->peer_cert ); + session->peer_cert = NULL; + return( ret ); + } + + p += cert_len; + } +#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + /* Deserialize CRT digest from the end of the ticket. */ + if( 1 > (size_t)( end - p ) ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + cert_digest_len = (size_t) p[0]; + p++; + + if( cert_digest_len != 0 ) + { + if( cert_digest_len > (size_t)( end - p ) || + cert_digest_len != session->peer_cert_digest_len ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + session->peer_cert_digest = mbedtls_calloc( 1, cert_digest_len ); + if( session->peer_cert_digest == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( session->peer_cert_digest, p, cert_digest_len ); + p += cert_digest_len; + } +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + if( p != end ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + return( 0 ); +} + +/* + * Create session ticket, with the following structure: + * + * struct { + * opaque key_name[4]; + * opaque iv[12]; + * opaque encrypted_state<0..2^16-1>; + * opaque tag[16]; + * } ticket; + * + * The key_name, iv, and length of encrypted_state are the additional + * authenticated data. + */ + +int mbedtls_ssl_ticket_write( void *p_ticket, + const mbedtls_ssl_session *session, + unsigned char *start, + const unsigned char *end, + size_t *tlen, + uint32_t *ticket_lifetime ) +{ + int ret; + mbedtls_ssl_ticket_context *ctx = p_ticket; + mbedtls_ssl_ticket_key *key; + unsigned char *key_name = start; + unsigned char *iv = start + TICKET_KEY_NAME_BYTES; + unsigned char *state_len_bytes = iv + TICKET_IV_BYTES; + unsigned char *state = state_len_bytes + TICKET_CRYPT_LEN_BYTES; + unsigned char *tag; + size_t clear_len, ciph_len; + + *tlen = 0; + + if( ctx == NULL || ctx->f_rng == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag, + * in addition to session itself, that will be checked when writing it. */ + if( end - start < TICKET_MIN_LEN ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 ) + goto cleanup; + + key = &ctx->keys[ctx->active]; + + *ticket_lifetime = ctx->ticket_lifetime; + + memcpy( key_name, key->name, TICKET_KEY_NAME_BYTES ); + + if( ( ret = ctx->f_rng( ctx->p_rng, iv, TICKET_IV_BYTES ) ) != 0 ) + goto cleanup; + + /* Dump session state */ + if( ( ret = ssl_save_session( session, + state, end - state, &clear_len ) ) != 0 || + (unsigned long) clear_len > 65535 ) + { + goto cleanup; + } + state_len_bytes[0] = ( clear_len >> 8 ) & 0xff; + state_len_bytes[1] = ( clear_len ) & 0xff; + + /* Encrypt and authenticate */ + tag = state + clear_len; + if( ( ret = mbedtls_cipher_auth_encrypt( &key->ctx, + iv, TICKET_IV_BYTES, + /* Additional data: key name, IV and length */ + key_name, TICKET_ADD_DATA_LEN, + state, clear_len, state, &ciph_len, + tag, TICKET_AUTH_TAG_BYTES ) ) != 0 ) + { + goto cleanup; + } + if( ciph_len != clear_len ) + { + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto cleanup; + } + + *tlen = TICKET_MIN_LEN + ciph_len; + +cleanup: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Select key based on name + */ +static mbedtls_ssl_ticket_key *ssl_ticket_select_key( + mbedtls_ssl_ticket_context *ctx, + const unsigned char name[4] ) +{ + unsigned char i; + + for( i = 0; i < sizeof( ctx->keys ) / sizeof( *ctx->keys ); i++ ) + if( memcmp( name, ctx->keys[i].name, 4 ) == 0 ) + return( &ctx->keys[i] ); + + return( NULL ); +} + +/* + * Load session ticket (see mbedtls_ssl_ticket_write for structure) + */ +int mbedtls_ssl_ticket_parse( void *p_ticket, + mbedtls_ssl_session *session, + unsigned char *buf, + size_t len ) +{ + int ret; + mbedtls_ssl_ticket_context *ctx = p_ticket; + mbedtls_ssl_ticket_key *key; + unsigned char *key_name = buf; + unsigned char *iv = buf + TICKET_KEY_NAME_BYTES; + unsigned char *enc_len_p = iv + TICKET_IV_BYTES; + unsigned char *ticket = enc_len_p + TICKET_CRYPT_LEN_BYTES; + unsigned char *tag; + size_t enc_len, clear_len; + + if( ctx == NULL || ctx->f_rng == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( len < TICKET_MIN_LEN ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 ) + goto cleanup; + + enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1]; + tag = ticket + enc_len; + + if( len != TICKET_MIN_LEN + enc_len ) + { + ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA; + goto cleanup; + } + + /* Select key */ + if( ( key = ssl_ticket_select_key( ctx, key_name ) ) == NULL ) + { + /* We can't know for sure but this is a likely option unless we're + * under attack - this is only informative anyway */ + ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; + goto cleanup; + } + + /* Decrypt and authenticate */ + if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx, + iv, TICKET_IV_BYTES, + /* Additional data: key name, IV and length */ + key_name, TICKET_ADD_DATA_LEN, + ticket, enc_len, + ticket, &clear_len, + tag, TICKET_AUTH_TAG_BYTES ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED ) + ret = MBEDTLS_ERR_SSL_INVALID_MAC; + + goto cleanup; + } + if( clear_len != enc_len ) + { + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto cleanup; + } + + /* Actually load session */ + if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 ) + goto cleanup; + +#if defined(MBEDTLS_HAVE_TIME) + { + /* Check for expiration */ + mbedtls_time_t current_time = mbedtls_time( NULL ); + + if( current_time < session->start || + (uint32_t)( current_time - session->start ) > ctx->ticket_lifetime ) + { + ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; + goto cleanup; + } + } +#endif + +cleanup: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Free context + */ +void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx ) +{ + mbedtls_cipher_free( &ctx->keys[0].ctx ); + mbedtls_cipher_free( &ctx->keys[1].ctx ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) ); +} + +#endif /* MBEDTLS_SSL_TICKET_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/ssl_tls.c b/FreeRTOS-Labs/Source/mbedtls/library/ssl_tls.c new file mode 100644 index 000000000..4de73c1ea --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/ssl_tls.c @@ -0,0 +1,11348 @@ +/* + * SSLv3/TLSv1 shared functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SSL 3.0 specification was drafted by Netscape in 1996, + * and became an IETF standard in 1999. + * + * http://wp.netscape.com/eng/ssl3/ + * http://www.ietf.org/rfc/rfc2246.txt + * http://www.ietf.org/rfc/rfc4346.txt + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_TLS_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "mbedtls/psa_util.h" +#include "psa/crypto.h" +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#include "mbedtls/oid.h" +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "mbedtls/psa_util.h" +#endif + +static void ssl_reset_in_out_pointers( mbedtls_ssl_context *ssl ); +static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl ); + +/* Length of the "epoch" field in the record header */ +static inline size_t ssl_ep_len( const mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( 2 ); +#else + ((void) ssl); +#endif + return( 0 ); +} + +/* + * Start a timer. + * Passing millisecs = 0 cancels a running timer. + */ +static void ssl_set_timer( mbedtls_ssl_context *ssl, uint32_t millisecs ) +{ + if( ssl->f_set_timer == NULL ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "set_timer to %d ms", (int) millisecs ) ); + ssl->f_set_timer( ssl->p_timer, millisecs / 4, millisecs ); +} + +/* + * Return -1 is timer is expired, 0 if it isn't. + */ +static int ssl_check_timer( mbedtls_ssl_context *ssl ) +{ + if( ssl->f_get_timer == NULL ) + return( 0 ); + + if( ssl->f_get_timer( ssl->p_timer ) == 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "timer expired" ) ); + return( -1 ); + } + + return( 0 ); +} + +static void ssl_update_out_pointers( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform ); +static void ssl_update_in_pointers( mbedtls_ssl_context *ssl ); + +#define SSL_DONT_FORCE_FLUSH 0 +#define SSL_FORCE_FLUSH 1 + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +/* Top-level Connection ID API */ + +int mbedtls_ssl_conf_cid( mbedtls_ssl_config *conf, + size_t len, + int ignore_other_cid ) +{ + if( len > MBEDTLS_SSL_CID_IN_LEN_MAX ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( ignore_other_cid != MBEDTLS_SSL_UNEXPECTED_CID_FAIL && + ignore_other_cid != MBEDTLS_SSL_UNEXPECTED_CID_IGNORE ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + conf->ignore_unexpected_cid = ignore_other_cid; + conf->cid_len = len; + return( 0 ); +} + +int mbedtls_ssl_set_cid( mbedtls_ssl_context *ssl, + int enable, + unsigned char const *own_cid, + size_t own_cid_len ) +{ + if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + ssl->negotiate_cid = enable; + if( enable == MBEDTLS_SSL_CID_DISABLED ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Disable use of CID extension." ) ); + return( 0 ); + } + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Enable use of CID extension." ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Own CID", own_cid, own_cid_len ); + + if( own_cid_len != ssl->conf->cid_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "CID length %u does not match CID length %u in config", + (unsigned) own_cid_len, + (unsigned) ssl->conf->cid_len ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + memcpy( ssl->own_cid, own_cid, own_cid_len ); + /* Truncation is not an issue here because + * MBEDTLS_SSL_CID_IN_LEN_MAX at most 255. */ + ssl->own_cid_len = (uint8_t) own_cid_len; + + return( 0 ); +} + +int mbedtls_ssl_get_peer_cid( mbedtls_ssl_context *ssl, + int *enabled, + unsigned char peer_cid[ MBEDTLS_SSL_CID_OUT_LEN_MAX ], + size_t *peer_cid_len ) +{ + *enabled = MBEDTLS_SSL_CID_DISABLED; + + if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM || + ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* We report MBEDTLS_SSL_CID_DISABLED in case the CID extensions + * were used, but client and server requested the empty CID. + * This is indistinguishable from not using the CID extension + * in the first place. */ + if( ssl->transform_in->in_cid_len == 0 && + ssl->transform_in->out_cid_len == 0 ) + { + return( 0 ); + } + + if( peer_cid_len != NULL ) + { + *peer_cid_len = ssl->transform_in->out_cid_len; + if( peer_cid != NULL ) + { + memcpy( peer_cid, ssl->transform_in->out_cid, + ssl->transform_in->out_cid_len ); + } + } + + *enabled = MBEDTLS_SSL_CID_ENABLED; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + +/* Forward declarations for functions related to message buffering. */ +static void ssl_buffering_free( mbedtls_ssl_context *ssl ); +static void ssl_buffering_free_slot( mbedtls_ssl_context *ssl, + uint8_t slot ); +static void ssl_free_buffered_record( mbedtls_ssl_context *ssl ); +static int ssl_load_buffered_message( mbedtls_ssl_context *ssl ); +static int ssl_load_buffered_record( mbedtls_ssl_context *ssl ); +static int ssl_buffer_message( mbedtls_ssl_context *ssl ); +static int ssl_buffer_future_record( mbedtls_ssl_context *ssl ); +static int ssl_next_record_is_in_datagram( mbedtls_ssl_context *ssl ); + +static size_t ssl_get_current_mtu( const mbedtls_ssl_context *ssl ); +static size_t ssl_get_maximum_datagram_size( mbedtls_ssl_context const *ssl ) +{ + size_t mtu = ssl_get_current_mtu( ssl ); + + if( mtu != 0 && mtu < MBEDTLS_SSL_OUT_BUFFER_LEN ) + return( mtu ); + + return( MBEDTLS_SSL_OUT_BUFFER_LEN ); +} + +static int ssl_get_remaining_space_in_datagram( mbedtls_ssl_context const *ssl ) +{ + size_t const bytes_written = ssl->out_left; + size_t const mtu = ssl_get_maximum_datagram_size( ssl ); + + /* Double-check that the write-index hasn't gone + * past what we can transmit in a single datagram. */ + if( bytes_written > mtu ) + { + /* Should never happen... */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + return( (int) ( mtu - bytes_written ) ); +} + +static int ssl_get_remaining_payload_in_datagram( mbedtls_ssl_context const *ssl ) +{ + int ret; + size_t remaining, expansion; + size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN; + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + const size_t mfl = mbedtls_ssl_get_max_frag_len( ssl ); + + if( max_len > mfl ) + max_len = mfl; + + /* By the standard (RFC 6066 Sect. 4), the MFL extension + * only limits the maximum record payload size, so in theory + * we would be allowed to pack multiple records of payload size + * MFL into a single datagram. However, this would mean that there's + * no way to explicitly communicate MTU restrictions to the peer. + * + * The following reduction of max_len makes sure that we never + * write datagrams larger than MFL + Record Expansion Overhead. + */ + if( max_len <= ssl->out_left ) + return( 0 ); + + max_len -= ssl->out_left; +#endif + + ret = ssl_get_remaining_space_in_datagram( ssl ); + if( ret < 0 ) + return( ret ); + remaining = (size_t) ret; + + ret = mbedtls_ssl_get_record_expansion( ssl ); + if( ret < 0 ) + return( ret ); + expansion = (size_t) ret; + + if( remaining <= expansion ) + return( 0 ); + + remaining -= expansion; + if( remaining >= max_len ) + remaining = max_len; + + return( (int) remaining ); +} + +/* + * Double the retransmit timeout value, within the allowed range, + * returning -1 if the maximum value has already been reached. + */ +static int ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl ) +{ + uint32_t new_timeout; + + if( ssl->handshake->retransmit_timeout >= ssl->conf->hs_timeout_max ) + return( -1 ); + + /* Implement the final paragraph of RFC 6347 section 4.1.1.1 + * in the following way: after the initial transmission and a first + * retransmission, back off to a temporary estimated MTU of 508 bytes. + * This value is guaranteed to be deliverable (if not guaranteed to be + * delivered) of any compliant IPv4 (and IPv6) network, and should work + * on most non-IP stacks too. */ + if( ssl->handshake->retransmit_timeout != ssl->conf->hs_timeout_min ) + { + ssl->handshake->mtu = 508; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "mtu autoreduction to %d bytes", ssl->handshake->mtu ) ); + } + + new_timeout = 2 * ssl->handshake->retransmit_timeout; + + /* Avoid arithmetic overflow and range overflow */ + if( new_timeout < ssl->handshake->retransmit_timeout || + new_timeout > ssl->conf->hs_timeout_max ) + { + new_timeout = ssl->conf->hs_timeout_max; + } + + ssl->handshake->retransmit_timeout = new_timeout; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "update timeout value to %d millisecs", + ssl->handshake->retransmit_timeout ) ); + + return( 0 ); +} + +static void ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl ) +{ + ssl->handshake->retransmit_timeout = ssl->conf->hs_timeout_min; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "update timeout value to %d millisecs", + ssl->handshake->retransmit_timeout ) ); +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +/* + * Convert max_fragment_length codes to length. + * RFC 6066 says: + * enum{ + * 2^9(1), 2^10(2), 2^11(3), 2^12(4), (255) + * } MaxFragmentLength; + * and we add 0 -> extension unused + */ +static unsigned int ssl_mfl_code_to_length( int mfl ) +{ + switch( mfl ) + { + case MBEDTLS_SSL_MAX_FRAG_LEN_NONE: + return ( MBEDTLS_TLS_EXT_ADV_CONTENT_LEN ); + case MBEDTLS_SSL_MAX_FRAG_LEN_512: + return 512; + case MBEDTLS_SSL_MAX_FRAG_LEN_1024: + return 1024; + case MBEDTLS_SSL_MAX_FRAG_LEN_2048: + return 2048; + case MBEDTLS_SSL_MAX_FRAG_LEN_4096: + return 4096; + default: + return ( MBEDTLS_TLS_EXT_ADV_CONTENT_LEN ); + } +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +int mbedtls_ssl_session_copy( mbedtls_ssl_session *dst, + const mbedtls_ssl_session *src ) +{ + mbedtls_ssl_session_free( dst ); + memcpy( dst, src, sizeof( mbedtls_ssl_session ) ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + if( src->peer_cert != NULL ) + { + int ret; + + dst->peer_cert = mbedtls_calloc( 1, sizeof(mbedtls_x509_crt) ); + if( dst->peer_cert == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + mbedtls_x509_crt_init( dst->peer_cert ); + + if( ( ret = mbedtls_x509_crt_parse_der( dst->peer_cert, src->peer_cert->raw.p, + src->peer_cert->raw.len ) ) != 0 ) + { + mbedtls_free( dst->peer_cert ); + dst->peer_cert = NULL; + return( ret ); + } + } +#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + if( src->peer_cert_digest != NULL ) + { + dst->peer_cert_digest = + mbedtls_calloc( 1, src->peer_cert_digest_len ); + if( dst->peer_cert_digest == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( dst->peer_cert_digest, src->peer_cert_digest, + src->peer_cert_digest_len ); + dst->peer_cert_digest_type = src->peer_cert_digest_type; + dst->peer_cert_digest_len = src->peer_cert_digest_len; + } +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) + if( src->ticket != NULL ) + { + dst->ticket = mbedtls_calloc( 1, src->ticket_len ); + if( dst->ticket == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( dst->ticket, src->ticket, src->ticket_len ); + } +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) +int (*mbedtls_ssl_hw_record_init)( mbedtls_ssl_context *ssl, + const unsigned char *key_enc, const unsigned char *key_dec, + size_t keylen, + const unsigned char *iv_enc, const unsigned char *iv_dec, + size_t ivlen, + const unsigned char *mac_enc, const unsigned char *mac_dec, + size_t maclen ) = NULL; +int (*mbedtls_ssl_hw_record_activate)( mbedtls_ssl_context *ssl, int direction) = NULL; +int (*mbedtls_ssl_hw_record_reset)( mbedtls_ssl_context *ssl ) = NULL; +int (*mbedtls_ssl_hw_record_write)( mbedtls_ssl_context *ssl ) = NULL; +int (*mbedtls_ssl_hw_record_read)( mbedtls_ssl_context *ssl ) = NULL; +int (*mbedtls_ssl_hw_record_finish)( mbedtls_ssl_context *ssl ) = NULL; +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + +/* + * Key material generation + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) +static int ssl3_prf( const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + int ret = 0; + size_t i; + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + unsigned char padding[16]; + unsigned char sha1sum[20]; + ((void)label); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + /* + * SSLv3: + * block = + * MD5( secret + SHA1( 'A' + secret + random ) ) + + * MD5( secret + SHA1( 'BB' + secret + random ) ) + + * MD5( secret + SHA1( 'CCC' + secret + random ) ) + + * ... + */ + for( i = 0; i < dlen / 16; i++ ) + { + memset( padding, (unsigned char) ('A' + i), 1 + i ); + + if( ( ret = mbedtls_sha1_starts_ret( &sha1 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_sha1_update_ret( &sha1, padding, 1 + i ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_sha1_update_ret( &sha1, secret, slen ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_sha1_update_ret( &sha1, random, rlen ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_sha1_finish_ret( &sha1, sha1sum ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md5_starts_ret( &md5 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_update_ret( &md5, secret, slen ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_update_ret( &md5, sha1sum, 20 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_finish_ret( &md5, dstbuf + i * 16 ) ) != 0 ) + goto exit; + } + +exit: + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + mbedtls_platform_zeroize( padding, sizeof( padding ) ); + mbedtls_platform_zeroize( sha1sum, sizeof( sha1sum ) ); + + return( ret ); +} +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) +static int tls1_prf( const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + size_t nb, hs; + size_t i, j, k; + const unsigned char *S1, *S2; + unsigned char *tmp; + size_t tmp_len = 0; + unsigned char h_i[20]; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + int ret; + + mbedtls_md_init( &md_ctx ); + + tmp_len = 20 + strlen( label ) + rlen; + tmp = mbedtls_calloc( 1, tmp_len ); + if( tmp == NULL ) + { + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto exit; + } + + hs = ( slen + 1 ) / 2; + S1 = secret; + S2 = secret + slen - hs; + + nb = strlen( label ); + memcpy( tmp + 20, label, nb ); + memcpy( tmp + 20 + nb, random, rlen ); + nb += rlen; + + /* + * First compute P_md5(secret,label+random)[0..dlen] + */ + if( ( md_info = mbedtls_md_info_from_type( MBEDTLS_MD_MD5 ) ) == NULL ) + { + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto exit; + } + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + { + goto exit; + } + + mbedtls_md_hmac_starts( &md_ctx, S1, hs ); + mbedtls_md_hmac_update( &md_ctx, tmp + 20, nb ); + mbedtls_md_hmac_finish( &md_ctx, 4 + tmp ); + + for( i = 0; i < dlen; i += 16 ) + { + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, 4 + tmp, 16 + nb ); + mbedtls_md_hmac_finish( &md_ctx, h_i ); + + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, 4 + tmp, 16 ); + mbedtls_md_hmac_finish( &md_ctx, 4 + tmp ); + + k = ( i + 16 > dlen ) ? dlen % 16 : 16; + + for( j = 0; j < k; j++ ) + dstbuf[i + j] = h_i[j]; + } + + mbedtls_md_free( &md_ctx ); + + /* + * XOR out with P_sha1(secret,label+random)[0..dlen] + */ + if( ( md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ) ) == NULL ) + { + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto exit; + } + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + { + goto exit; + } + + mbedtls_md_hmac_starts( &md_ctx, S2, hs ); + mbedtls_md_hmac_update( &md_ctx, tmp + 20, nb ); + mbedtls_md_hmac_finish( &md_ctx, tmp ); + + for( i = 0; i < dlen; i += 20 ) + { + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, tmp, 20 + nb ); + mbedtls_md_hmac_finish( &md_ctx, h_i ); + + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, tmp, 20 ); + mbedtls_md_hmac_finish( &md_ctx, tmp ); + + k = ( i + 20 > dlen ) ? dlen % 20 : 20; + + for( j = 0; j < k; j++ ) + dstbuf[i + j] = (unsigned char)( dstbuf[i + j] ^ h_i[j] ); + } + +exit: + mbedtls_md_free( &md_ctx ); + + mbedtls_platform_zeroize( tmp, tmp_len ); + mbedtls_platform_zeroize( h_i, sizeof( h_i ) ); + + mbedtls_free( tmp ); + return( ret ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1) || MBEDTLS_SSL_PROTO_TLS1_1 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_USE_PSA_CRYPTO) +static int tls_prf_generic( mbedtls_md_type_t md_type, + const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + psa_status_t status; + psa_algorithm_t alg; + psa_key_policy_t policy; + psa_key_handle_t master_slot; + psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT; + + if( ( status = psa_allocate_key( &master_slot ) ) != PSA_SUCCESS ) + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + + if( md_type == MBEDTLS_MD_SHA384 ) + alg = PSA_ALG_TLS12_PRF(PSA_ALG_SHA_384); + else + alg = PSA_ALG_TLS12_PRF(PSA_ALG_SHA_256); + + policy = psa_key_policy_init(); + psa_key_policy_set_usage( &policy, + PSA_KEY_USAGE_DERIVE, + alg ); + status = psa_set_key_policy( master_slot, &policy ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + + status = psa_import_key( master_slot, PSA_KEY_TYPE_DERIVE, secret, slen ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + + status = psa_key_derivation( &generator, + master_slot, alg, + random, rlen, + (unsigned char const *) label, + (size_t) strlen( label ), + dlen ); + if( status != PSA_SUCCESS ) + { + psa_generator_abort( &generator ); + psa_destroy_key( master_slot ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + + status = psa_generator_read( &generator, dstbuf, dlen ); + if( status != PSA_SUCCESS ) + { + psa_generator_abort( &generator ); + psa_destroy_key( master_slot ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + + status = psa_generator_abort( &generator ); + if( status != PSA_SUCCESS ) + { + psa_destroy_key( master_slot ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + + status = psa_destroy_key( master_slot ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + + return( 0 ); +} + +#else /* MBEDTLS_USE_PSA_CRYPTO */ + +static int tls_prf_generic( mbedtls_md_type_t md_type, + const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + size_t nb; + size_t i, j, k, md_len; + unsigned char *tmp; + size_t tmp_len = 0; + unsigned char h_i[MBEDTLS_MD_MAX_SIZE]; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + int ret; + + mbedtls_md_init( &md_ctx ); + + if( ( md_info = mbedtls_md_info_from_type( md_type ) ) == NULL ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + md_len = mbedtls_md_get_size( md_info ); + + tmp_len = md_len + strlen( label ) + rlen; + tmp = mbedtls_calloc( 1, tmp_len ); + if( tmp == NULL ) + { + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto exit; + } + + nb = strlen( label ); + memcpy( tmp + md_len, label, nb ); + memcpy( tmp + md_len + nb, random, rlen ); + nb += rlen; + + /* + * Compute P_(secret, label + random)[0..dlen] + */ + if ( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + goto exit; + + mbedtls_md_hmac_starts( &md_ctx, secret, slen ); + mbedtls_md_hmac_update( &md_ctx, tmp + md_len, nb ); + mbedtls_md_hmac_finish( &md_ctx, tmp ); + + for( i = 0; i < dlen; i += md_len ) + { + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, tmp, md_len + nb ); + mbedtls_md_hmac_finish( &md_ctx, h_i ); + + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, tmp, md_len ); + mbedtls_md_hmac_finish( &md_ctx, tmp ); + + k = ( i + md_len > dlen ) ? dlen % md_len : md_len; + + for( j = 0; j < k; j++ ) + dstbuf[i + j] = h_i[j]; + } + +exit: + mbedtls_md_free( &md_ctx ); + + mbedtls_platform_zeroize( tmp, tmp_len ); + mbedtls_platform_zeroize( h_i, sizeof( h_i ) ); + + mbedtls_free( tmp ); + + return( ret ); +} +#endif /* MBEDTLS_USE_PSA_CRYPTO */ +#if defined(MBEDTLS_SHA256_C) +static int tls_prf_sha256( const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + return( tls_prf_generic( MBEDTLS_MD_SHA256, secret, slen, + label, random, rlen, dstbuf, dlen ) ); +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +static int tls_prf_sha384( const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + return( tls_prf_generic( MBEDTLS_MD_SHA384, secret, slen, + label, random, rlen, dstbuf, dlen ) ); +} +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +static void ssl_update_checksum_start( mbedtls_ssl_context *, const unsigned char *, size_t ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) +static void ssl_update_checksum_md5sha1( mbedtls_ssl_context *, const unsigned char *, size_t ); +#endif + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +static void ssl_calc_verify_ssl( mbedtls_ssl_context *, unsigned char * ); +static void ssl_calc_finished_ssl( mbedtls_ssl_context *, unsigned char *, int ); +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) +static void ssl_calc_verify_tls( mbedtls_ssl_context *, unsigned char * ); +static void ssl_calc_finished_tls( mbedtls_ssl_context *, unsigned char *, int ); +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +static void ssl_update_checksum_sha256( mbedtls_ssl_context *, const unsigned char *, size_t ); +static void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *,unsigned char * ); +static void ssl_calc_finished_tls_sha256( mbedtls_ssl_context *,unsigned char *, int ); +#endif + +#if defined(MBEDTLS_SHA512_C) +static void ssl_update_checksum_sha384( mbedtls_ssl_context *, const unsigned char *, size_t ); +static void ssl_calc_verify_tls_sha384( mbedtls_ssl_context *, unsigned char * ); +static void ssl_calc_finished_tls_sha384( mbedtls_ssl_context *, unsigned char *, int ); +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) && \ + defined(MBEDTLS_USE_PSA_CRYPTO) +static int ssl_use_opaque_psk( mbedtls_ssl_context const *ssl ) +{ + if( ssl->conf->f_psk != NULL ) + { + /* If we've used a callback to select the PSK, + * the static configuration is irrelevant. */ + if( ssl->handshake->psk_opaque != 0 ) + return( 1 ); + + return( 0 ); + } + + if( ssl->conf->psk_opaque != 0 ) + return( 1 ); + + return( 0 ); +} +#endif /* MBEDTLS_USE_PSA_CRYPTO && + MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +static mbedtls_tls_prf_types tls_prf_get_type( mbedtls_ssl_tls_prf_cb *tls_prf ) +{ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( tls_prf == ssl3_prf ) + { + return( MBEDTLS_SSL_TLS_PRF_SSL3 ); + } + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( tls_prf == tls1_prf ) + { + return( MBEDTLS_SSL_TLS_PRF_TLS1 ); + } + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA512_C) + if( tls_prf == tls_prf_sha384 ) + { + return( MBEDTLS_SSL_TLS_PRF_SHA384 ); + } + else +#endif +#if defined(MBEDTLS_SHA256_C) + if( tls_prf == tls_prf_sha256 ) + { + return( MBEDTLS_SSL_TLS_PRF_SHA256 ); + } + else +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + return( MBEDTLS_SSL_TLS_PRF_NONE ); +} +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + +int mbedtls_ssl_tls_prf( const mbedtls_tls_prf_types prf, + const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + mbedtls_ssl_tls_prf_cb *tls_prf = NULL; + + switch( prf ) + { +#if defined(MBEDTLS_SSL_PROTO_SSL3) + case MBEDTLS_SSL_TLS_PRF_SSL3: + tls_prf = ssl3_prf; + break; +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) + case MBEDTLS_SSL_TLS_PRF_TLS1: + tls_prf = tls1_prf; + break; +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_SSL_TLS_PRF_SHA384: + tls_prf = tls_prf_sha384; + break; +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_SSL_TLS_PRF_SHA256: + tls_prf = tls_prf_sha256; + break; +#endif /* MBEDTLS_SHA256_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + default: + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + return( tls_prf( secret, slen, label, random, rlen, dstbuf, dlen ) ); +} + +int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) +{ + int ret = 0; +#if defined(MBEDTLS_USE_PSA_CRYPTO) + int psa_fallthrough; +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + unsigned char tmp[64]; + unsigned char keyblk[256]; + unsigned char *key1; + unsigned char *key2; + unsigned char *mac_enc; + unsigned char *mac_dec; + size_t mac_key_len; + size_t iv_copy_len; + unsigned keylen; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + const mbedtls_cipher_info_t *cipher_info; + const mbedtls_md_info_t *md_info; + + /* cf. RFC 5246, Section 8.1: + * "The master secret is always exactly 48 bytes in length." */ + size_t const master_secret_len = 48; + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + unsigned char session_hash[48]; +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + + mbedtls_ssl_session *session = ssl->session_negotiate; + mbedtls_ssl_transform *transform = ssl->transform_negotiate; + mbedtls_ssl_handshake_params *handshake = ssl->handshake; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> derive keys" ) ); + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \ + defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) + transform->encrypt_then_mac = session->encrypt_then_mac; +#endif + transform->minor_ver = ssl->minor_ver; + + ciphersuite_info = handshake->ciphersuite_info; + cipher_info = mbedtls_cipher_info_from_type( ciphersuite_info->cipher ); + if( cipher_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "cipher info for %d not found", + ciphersuite_info->cipher ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + md_info = mbedtls_md_info_from_type( ciphersuite_info->mac ); + if( md_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "mbedtls_md info for %d not found", + ciphersuite_info->mac ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + /* Copy own and peer's CID if the use of the CID + * extension has been negotiated. */ + if( ssl->handshake->cid_in_use == MBEDTLS_SSL_CID_ENABLED ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Copy CIDs into SSL transform" ) ); + + transform->in_cid_len = ssl->own_cid_len; + memcpy( transform->in_cid, ssl->own_cid, ssl->own_cid_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Incoming CID", transform->in_cid, + transform->in_cid_len ); + + transform->out_cid_len = ssl->handshake->peer_cid_len; + memcpy( transform->out_cid, ssl->handshake->peer_cid, + ssl->handshake->peer_cid_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Outgoing CID", transform->out_cid, + transform->out_cid_len ); + } +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + + /* + * Set appropriate PRF function and other SSL / TLS / TLS1.2 functions + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + handshake->tls_prf = ssl3_prf; + handshake->calc_verify = ssl_calc_verify_ssl; + handshake->calc_finished = ssl_calc_finished_ssl; + } + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 ) + { + handshake->tls_prf = tls1_prf; + handshake->calc_verify = ssl_calc_verify_tls; + handshake->calc_finished = ssl_calc_finished_tls; + } + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA512_C) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 && + ciphersuite_info->mac == MBEDTLS_MD_SHA384 ) + { + handshake->tls_prf = tls_prf_sha384; + handshake->calc_verify = ssl_calc_verify_tls_sha384; + handshake->calc_finished = ssl_calc_finished_tls_sha384; + } + else +#endif +#if defined(MBEDTLS_SHA256_C) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + handshake->tls_prf = tls_prf_sha256; + handshake->calc_verify = ssl_calc_verify_tls_sha256; + handshake->calc_finished = ssl_calc_finished_tls_sha256; + } + else +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* + * SSLv3: + * master = + * MD5( premaster + SHA1( 'A' + premaster + randbytes ) ) + + * MD5( premaster + SHA1( 'BB' + premaster + randbytes ) ) + + * MD5( premaster + SHA1( 'CCC' + premaster + randbytes ) ) + * + * TLSv1+: + * master = PRF( premaster, "master secret", randbytes )[0..47] + */ + if( handshake->resume != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no premaster (session resumed)" ) ); + } + else + { + /* The label for the KDF used for key expansion. + * This is either "master secret" or "extended master secret" + * depending on whether the Extended Master Secret extension + * is used. */ + char const *lbl = "master secret"; + + /* The salt for the KDF used for key expansion. + * - If the Extended Master Secret extension is not used, + * this is ClientHello.Random + ServerHello.Random + * (see Sect. 8.1 in RFC 5246). + * - If the Extended Master Secret extension is used, + * this is the transcript of the handshake so far. + * (see Sect. 4 in RFC 7627). */ + unsigned char const *salt = handshake->randbytes; + size_t salt_len = 64; + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + if( ssl->handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "using extended master secret" ) ); + + lbl = "extended master secret"; + salt = session_hash; + ssl->handshake->calc_verify( ssl, session_hash ); +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { +#if defined(MBEDTLS_SHA512_C) + if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 ) + { + salt_len = 48; + } + else +#endif /* MBEDTLS_SHA512_C */ + salt_len = 32; + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + salt_len = 36; + + MBEDTLS_SSL_DEBUG_BUF( 3, "session hash", session_hash, salt_len ); + } +#endif /* MBEDTLS_SSL_EXTENDED_MS_ENABLED */ + +#if defined(MBEDTLS_USE_PSA_CRYPTO) && \ + defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK && + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 && + ssl_use_opaque_psk( ssl ) == 1 ) + { + /* Perform PSK-to-MS expansion in a single step. */ + psa_status_t status; + psa_algorithm_t alg; + psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT; + psa_key_handle_t psk; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "perform PSA-based PSK-to-MS expansion" ) ); + + psk = ssl->conf->psk_opaque; + if( ssl->handshake->psk_opaque != 0 ) + psk = ssl->handshake->psk_opaque; + + if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 ) + alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_384); + else + alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256); + + status = psa_key_derivation( &generator, psk, alg, + salt, salt_len, + (unsigned char const *) lbl, + (size_t) strlen( lbl ), + master_secret_len ); + if( status != PSA_SUCCESS ) + { + psa_generator_abort( &generator ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + + status = psa_generator_read( &generator, session->master, + master_secret_len ); + if( status != PSA_SUCCESS ) + { + psa_generator_abort( &generator ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + + status = psa_generator_abort( &generator ); + if( status != PSA_SUCCESS ) + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + else +#endif + { + ret = handshake->tls_prf( handshake->premaster, handshake->pmslen, + lbl, salt, salt_len, + session->master, + master_secret_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "premaster secret", + handshake->premaster, + handshake->pmslen ); + + mbedtls_platform_zeroize( handshake->premaster, + sizeof(handshake->premaster) ); + } + } + + /* + * Swap the client and server random values. + */ + memcpy( tmp, handshake->randbytes, 64 ); + memcpy( handshake->randbytes, tmp + 32, 32 ); + memcpy( handshake->randbytes + 32, tmp, 32 ); + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); + + /* + * SSLv3: + * key block = + * MD5( master + SHA1( 'A' + master + randbytes ) ) + + * MD5( master + SHA1( 'BB' + master + randbytes ) ) + + * MD5( master + SHA1( 'CCC' + master + randbytes ) ) + + * MD5( master + SHA1( 'DDDD' + master + randbytes ) ) + + * ... + * + * TLSv1: + * key block = PRF( master, "key expansion", randbytes ) + */ + ret = handshake->tls_prf( session->master, 48, "key expansion", + handshake->randbytes, 64, keyblk, 256 ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite = %s", + mbedtls_ssl_get_ciphersuite_name( session->ciphersuite ) ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "master secret", session->master, 48 ); + MBEDTLS_SSL_DEBUG_BUF( 4, "random bytes", handshake->randbytes, 64 ); + MBEDTLS_SSL_DEBUG_BUF( 4, "key block", keyblk, 256 ); + + /* + * Determine the appropriate key, IV and MAC length. + */ + + keylen = cipher_info->key_bitlen / 8; + +#if defined(MBEDTLS_GCM_C) || \ + defined(MBEDTLS_CCM_C) || \ + defined(MBEDTLS_CHACHAPOLY_C) + if( cipher_info->mode == MBEDTLS_MODE_GCM || + cipher_info->mode == MBEDTLS_MODE_CCM || + cipher_info->mode == MBEDTLS_MODE_CHACHAPOLY ) + { + size_t explicit_ivlen; + + transform->maclen = 0; + mac_key_len = 0; + transform->taglen = + ciphersuite_info->flags & MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16; + + /* All modes haves 96-bit IVs; + * GCM and CCM has 4 implicit and 8 explicit bytes + * ChachaPoly has all 12 bytes implicit + */ + transform->ivlen = 12; + if( cipher_info->mode == MBEDTLS_MODE_CHACHAPOLY ) + transform->fixed_ivlen = 12; + else + transform->fixed_ivlen = 4; + + /* Minimum length of encrypted record */ + explicit_ivlen = transform->ivlen - transform->fixed_ivlen; + transform->minlen = explicit_ivlen + transform->taglen; + } + else +#endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C || MBEDTLS_CHACHAPOLY_C */ +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) + if( cipher_info->mode == MBEDTLS_MODE_STREAM || + cipher_info->mode == MBEDTLS_MODE_CBC ) + { + /* Initialize HMAC contexts */ + if( ( ret = mbedtls_md_setup( &transform->md_ctx_enc, md_info, 1 ) ) != 0 || + ( ret = mbedtls_md_setup( &transform->md_ctx_dec, md_info, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_setup", ret ); + goto end; + } + + /* Get MAC length */ + mac_key_len = mbedtls_md_get_size( md_info ); + transform->maclen = mac_key_len; + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + /* + * If HMAC is to be truncated, we shall keep the leftmost bytes, + * (rfc 6066 page 13 or rfc 2104 section 4), + * so we only need to adjust the length here. + */ + if( session->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_ENABLED ) + { + transform->maclen = MBEDTLS_SSL_TRUNCATED_HMAC_LEN; + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT) + /* Fall back to old, non-compliant version of the truncated + * HMAC implementation which also truncates the key + * (Mbed TLS versions from 1.3 to 2.6.0) */ + mac_key_len = transform->maclen; +#endif + } +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + + /* IV length */ + transform->ivlen = cipher_info->iv_size; + + /* Minimum length */ + if( cipher_info->mode == MBEDTLS_MODE_STREAM ) + transform->minlen = transform->maclen; + else + { + /* + * GenericBlockCipher: + * 1. if EtM is in use: one block plus MAC + * otherwise: * first multiple of blocklen greater than maclen + * 2. IV except for SSL3 and TLS 1.0 + */ +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + if( session->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED ) + { + transform->minlen = transform->maclen + + cipher_info->block_size; + } + else +#endif + { + transform->minlen = transform->maclen + + cipher_info->block_size + - transform->maclen % cipher_info->block_size; + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_1 ) + ; /* No need to adjust minlen */ + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_2 || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + transform->minlen += transform->ivlen; + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto end; + } + } + } + else +#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "keylen: %u, minlen: %u, ivlen: %u, maclen: %u", + (unsigned) keylen, + (unsigned) transform->minlen, + (unsigned) transform->ivlen, + (unsigned) transform->maclen ) ); + + /* + * Finally setup the cipher contexts, IVs and MAC secrets. + */ +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + key1 = keyblk + mac_key_len * 2; + key2 = keyblk + mac_key_len * 2 + keylen; + + mac_enc = keyblk; + mac_dec = keyblk + mac_key_len; + + /* + * This is not used in TLS v1.1. + */ + iv_copy_len = ( transform->fixed_ivlen ) ? + transform->fixed_ivlen : transform->ivlen; + memcpy( transform->iv_enc, key2 + keylen, iv_copy_len ); + memcpy( transform->iv_dec, key2 + keylen + iv_copy_len, + iv_copy_len ); + } + else +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + key1 = keyblk + mac_key_len * 2 + keylen; + key2 = keyblk + mac_key_len * 2; + + mac_enc = keyblk + mac_key_len; + mac_dec = keyblk; + + /* + * This is not used in TLS v1.1. + */ + iv_copy_len = ( transform->fixed_ivlen ) ? + transform->fixed_ivlen : transform->ivlen; + memcpy( transform->iv_dec, key1 + keylen, iv_copy_len ); + memcpy( transform->iv_enc, key1 + keylen + iv_copy_len, + iv_copy_len ); + } + else +#endif /* MBEDTLS_SSL_SRV_C */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto end; + } + +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( mac_key_len > sizeof( transform->mac_enc ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto end; + } + + memcpy( transform->mac_enc, mac_enc, mac_key_len ); + memcpy( transform->mac_dec, mac_dec, mac_key_len ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) + { + /* For HMAC-based ciphersuites, initialize the HMAC transforms. + For AEAD-based ciphersuites, there is nothing to do here. */ + if( mac_key_len != 0 ) + { + mbedtls_md_hmac_starts( &transform->md_ctx_enc, mac_enc, mac_key_len ); + mbedtls_md_hmac_starts( &transform->md_ctx_dec, mac_dec, mac_key_len ); + } + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto end; + } +#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_init != NULL ) + { + int ret = 0; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_init()" ) ); + + if( ( ret = mbedtls_ssl_hw_record_init( ssl, key1, key2, keylen, + transform->iv_enc, transform->iv_dec, + iv_copy_len, + mac_enc, mac_dec, + mac_key_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_init", ret ); + ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED; + goto end; + } + } +#else + ((void) mac_dec); + ((void) mac_enc); +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + if( ssl->conf->f_export_keys != NULL ) + { + ssl->conf->f_export_keys( ssl->conf->p_export_keys, + session->master, keyblk, + mac_key_len, keylen, + iv_copy_len ); + } + + if( ssl->conf->f_export_keys_ext != NULL ) + { + ssl->conf->f_export_keys_ext( ssl->conf->p_export_keys, + session->master, keyblk, + mac_key_len, keylen, + iv_copy_len, + handshake->randbytes + 32, + handshake->randbytes, + tls_prf_get_type( handshake->tls_prf ) ); + } +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + + /* Only use PSA-based ciphers for TLS-1.2. + * That's relevant at least for TLS-1.0, where + * we assume that mbedtls_cipher_crypt() updates + * the structure field for the IV, which the PSA-based + * implementation currently doesn't. */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + ret = mbedtls_cipher_setup_psa( &transform->cipher_ctx_enc, + cipher_info, transform->taglen ); + if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup_psa", ret ); + goto end; + } + + if( ret == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Successfully setup PSA-based encryption cipher context" ) ); + psa_fallthrough = 0; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Failed to setup PSA-based cipher context for record encryption - fall through to default setup." ) ); + psa_fallthrough = 1; + } + } + else + psa_fallthrough = 1; +#else + psa_fallthrough = 1; +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + if( psa_fallthrough == 1 ) +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_enc, + cipher_info ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); + goto end; + } + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + /* Only use PSA-based ciphers for TLS-1.2. + * That's relevant at least for TLS-1.0, where + * we assume that mbedtls_cipher_crypt() updates + * the structure field for the IV, which the PSA-based + * implementation currently doesn't. */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + ret = mbedtls_cipher_setup_psa( &transform->cipher_ctx_dec, + cipher_info, transform->taglen ); + if( ret != 0 && ret != MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup_psa", ret ); + goto end; + } + + if( ret == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Successfully setup PSA-based decryption cipher context" ) ); + psa_fallthrough = 0; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Failed to setup PSA-based cipher context for record decryption - fall through to default setup." ) ); + psa_fallthrough = 1; + } + } + else + psa_fallthrough = 1; +#else + psa_fallthrough = 1; +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + if( psa_fallthrough == 1 ) +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_dec, + cipher_info ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); + goto end; + } + + if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_enc, key1, + cipher_info->key_bitlen, + MBEDTLS_ENCRYPT ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret ); + goto end; + } + + if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_dec, key2, + cipher_info->key_bitlen, + MBEDTLS_DECRYPT ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret ); + goto end; + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + if( cipher_info->mode == MBEDTLS_MODE_CBC ) + { + if( ( ret = mbedtls_cipher_set_padding_mode( &transform->cipher_ctx_enc, + MBEDTLS_PADDING_NONE ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_set_padding_mode", ret ); + goto end; + } + + if( ( ret = mbedtls_cipher_set_padding_mode( &transform->cipher_ctx_dec, + MBEDTLS_PADDING_NONE ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_set_padding_mode", ret ); + goto end; + } + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + +#if defined(MBEDTLS_ZLIB_SUPPORT) + // Initialize compression + // + if( session->compression == MBEDTLS_SSL_COMPRESS_DEFLATE ) + { + if( ssl->compress_buf == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Allocating compression buffer" ) ); + ssl->compress_buf = mbedtls_calloc( 1, MBEDTLS_SSL_COMPRESS_BUFFER_LEN ); + if( ssl->compress_buf == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", + MBEDTLS_SSL_COMPRESS_BUFFER_LEN ) ); + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto end; + } + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Initializing zlib states" ) ); + + memset( &transform->ctx_deflate, 0, sizeof( transform->ctx_deflate ) ); + memset( &transform->ctx_inflate, 0, sizeof( transform->ctx_inflate ) ); + + if( deflateInit( &transform->ctx_deflate, + Z_DEFAULT_COMPRESSION ) != Z_OK || + inflateInit( &transform->ctx_inflate ) != Z_OK ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Failed to initialize compression" ) ); + ret = MBEDTLS_ERR_SSL_COMPRESSION_FAILED; + goto end; + } + } +#endif /* MBEDTLS_ZLIB_SUPPORT */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= derive keys" ) ); +end: + mbedtls_platform_zeroize( keyblk, sizeof( keyblk ) ); + mbedtls_platform_zeroize( handshake->randbytes, + sizeof( handshake->randbytes ) ); + return( ret ); +} + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +void ssl_calc_verify_ssl( mbedtls_ssl_context *ssl, unsigned char hash[36] ) +{ + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + unsigned char pad_1[48]; + unsigned char pad_2[48]; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify ssl" ) ); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 ); + mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 ); + + memset( pad_1, 0x36, 48 ); + memset( pad_2, 0x5C, 48 ); + + mbedtls_md5_update_ret( &md5, ssl->session_negotiate->master, 48 ); + mbedtls_md5_update_ret( &md5, pad_1, 48 ); + mbedtls_md5_finish_ret( &md5, hash ); + + mbedtls_md5_starts_ret( &md5 ); + mbedtls_md5_update_ret( &md5, ssl->session_negotiate->master, 48 ); + mbedtls_md5_update_ret( &md5, pad_2, 48 ); + mbedtls_md5_update_ret( &md5, hash, 16 ); + mbedtls_md5_finish_ret( &md5, hash ); + + mbedtls_sha1_update_ret( &sha1, ssl->session_negotiate->master, 48 ); + mbedtls_sha1_update_ret( &sha1, pad_1, 40 ); + mbedtls_sha1_finish_ret( &sha1, hash + 16 ); + + mbedtls_sha1_starts_ret( &sha1 ); + mbedtls_sha1_update_ret( &sha1, ssl->session_negotiate->master, 48 ); + mbedtls_sha1_update_ret( &sha1, pad_2, 40 ); + mbedtls_sha1_update_ret( &sha1, hash + 16, 20 ); + mbedtls_sha1_finish_ret( &sha1, hash + 16 ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + return; +} +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) +void ssl_calc_verify_tls( mbedtls_ssl_context *ssl, unsigned char hash[36] ) +{ + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify tls" ) ); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 ); + mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 ); + + mbedtls_md5_finish_ret( &md5, hash ); + mbedtls_sha1_finish_ret( &sha1, hash + 16 ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + return; +} +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *ssl, unsigned char hash[32] ) +{ +#if defined(MBEDTLS_USE_PSA_CRYPTO) + size_t hash_size; + psa_status_t status; + psa_hash_operation_t sha256_psa = psa_hash_operation_init(); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> PSA calc verify sha256" ) ); + status = psa_hash_clone( &ssl->handshake->fin_sha256_psa, &sha256_psa ); + if( status != PSA_SUCCESS ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash clone failed" ) ); + return; + } + + status = psa_hash_finish( &sha256_psa, hash, 32, &hash_size ); + if( status != PSA_SUCCESS ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash finish failed" ) ); + return; + } + MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated verify result", hash, 32 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= PSA calc verify" ) ); +#else + mbedtls_sha256_context sha256; + + mbedtls_sha256_init( &sha256 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify sha256" ) ); + + mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 ); + mbedtls_sha256_finish_ret( &sha256, hash ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 32 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + mbedtls_sha256_free( &sha256 ); +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + return; +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +void ssl_calc_verify_tls_sha384( mbedtls_ssl_context *ssl, unsigned char hash[48] ) +{ +#if defined(MBEDTLS_USE_PSA_CRYPTO) + size_t hash_size; + psa_status_t status; + psa_hash_operation_t sha384_psa = psa_hash_operation_init(); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> PSA calc verify sha384" ) ); + status = psa_hash_clone( &ssl->handshake->fin_sha384_psa, &sha384_psa ); + if( status != PSA_SUCCESS ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash clone failed" ) ); + return; + } + + status = psa_hash_finish( &sha384_psa, hash, 48, &hash_size ); + if( status != PSA_SUCCESS ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash finish failed" ) ); + return; + } + MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated verify result", hash, 48 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= PSA calc verify" ) ); +#else + mbedtls_sha512_context sha512; + + mbedtls_sha512_init( &sha512 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify sha384" ) ); + + mbedtls_sha512_clone( &sha512, &ssl->handshake->fin_sha512 ); + mbedtls_sha512_finish_ret( &sha512, hash ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 48 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + mbedtls_sha512_free( &sha512 ); +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + return; +} +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exchange_type_t key_ex ) +{ + unsigned char *p = ssl->handshake->premaster; + unsigned char *end = p + sizeof( ssl->handshake->premaster ); + const unsigned char *psk = ssl->conf->psk; + size_t psk_len = ssl->conf->psk_len; + + /* If the psk callback was called, use its result */ + if( ssl->handshake->psk != NULL ) + { + psk = ssl->handshake->psk; + psk_len = ssl->handshake->psk_len; + } + + /* + * PMS = struct { + * opaque other_secret<0..2^16-1>; + * opaque psk<0..2^16-1>; + * }; + * with "other_secret" depending on the particular key exchange + */ +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + if( key_ex == MBEDTLS_KEY_EXCHANGE_PSK ) + { + if( end - p < 2 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + *(p++) = (unsigned char)( psk_len >> 8 ); + *(p++) = (unsigned char)( psk_len ); + + if( end < p || (size_t)( end - p ) < psk_len ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + memset( p, 0, psk_len ); + p += psk_len; + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( key_ex == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + /* + * other_secret already set by the ClientKeyExchange message, + * and is 48 bytes long + */ + if( end - p < 2 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + *p++ = 0; + *p++ = 48; + p += 48; + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( key_ex == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { + int ret; + size_t len; + + /* Write length only when we know the actual value */ + if( ( ret = mbedtls_dhm_calc_secret( &ssl->handshake->dhm_ctx, + p + 2, end - ( p + 2 ), &len, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret ); + return( ret ); + } + *(p++) = (unsigned char)( len >> 8 ); + *(p++) = (unsigned char)( len ); + p += len; + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->handshake->dhm_ctx.K ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + if( key_ex == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + int ret; + size_t zlen; + + if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, &zlen, + p + 2, end - ( p + 2 ), + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret ); + return( ret ); + } + + *(p++) = (unsigned char)( zlen >> 8 ); + *(p++) = (unsigned char)( zlen ); + p += zlen; + + MBEDTLS_SSL_DEBUG_ECDH( 3, &ssl->handshake->ecdh_ctx, + MBEDTLS_DEBUG_ECDH_Z ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* opaque psk<0..2^16-1>; */ + if( end - p < 2 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + *(p++) = (unsigned char)( psk_len >> 8 ); + *(p++) = (unsigned char)( psk_len ); + + if( end < p || (size_t)( end - p ) < psk_len ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + memcpy( p, psk, psk_len ); + p += psk_len; + + ssl->handshake->pmslen = p - ssl->handshake->premaster; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +/* + * SSLv3.0 MAC functions + */ +#define SSL_MAC_MAX_BYTES 20 /* MD-5 or SHA-1 */ +static void ssl_mac( mbedtls_md_context_t *md_ctx, + const unsigned char *secret, + const unsigned char *buf, size_t len, + const unsigned char *ctr, int type, + unsigned char out[SSL_MAC_MAX_BYTES] ) +{ + unsigned char header[11]; + unsigned char padding[48]; + int padlen; + int md_size = mbedtls_md_get_size( md_ctx->md_info ); + int md_type = mbedtls_md_get_type( md_ctx->md_info ); + + /* Only MD5 and SHA-1 supported */ + if( md_type == MBEDTLS_MD_MD5 ) + padlen = 48; + else + padlen = 40; + + memcpy( header, ctr, 8 ); + header[ 8] = (unsigned char) type; + header[ 9] = (unsigned char)( len >> 8 ); + header[10] = (unsigned char)( len ); + + memset( padding, 0x36, padlen ); + mbedtls_md_starts( md_ctx ); + mbedtls_md_update( md_ctx, secret, md_size ); + mbedtls_md_update( md_ctx, padding, padlen ); + mbedtls_md_update( md_ctx, header, 11 ); + mbedtls_md_update( md_ctx, buf, len ); + mbedtls_md_finish( md_ctx, out ); + + memset( padding, 0x5C, padlen ); + mbedtls_md_starts( md_ctx ); + mbedtls_md_update( md_ctx, secret, md_size ); + mbedtls_md_update( md_ctx, padding, padlen ); + mbedtls_md_update( md_ctx, out, md_size ); + mbedtls_md_finish( md_ctx, out ); +} +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +/* The function below is only used in the Lucky 13 counter-measure in + * mbedtls_ssl_decrypt_buf(). These are the defines that guard the call site. */ +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) && \ + ( defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) ) +/* This function makes sure every byte in the memory region is accessed + * (in ascending addresses order) */ +static void ssl_read_memory( unsigned char *p, size_t len ) +{ + unsigned char acc = 0; + volatile unsigned char force; + + for( ; len != 0; p++, len-- ) + acc ^= *p; + + force = acc; + (void) force; +} +#endif /* SSL_SOME_MODES_USE_MAC && ( TLS1 || TLS1_1 || TLS1_2 ) */ + +/* + * Encryption/decryption functions + */ + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) +/* This functions transforms a DTLS plaintext fragment and a record content + * type into an instance of the DTLSInnerPlaintext structure: + * + * struct { + * opaque content[DTLSPlaintext.length]; + * ContentType real_type; + * uint8 zeros[length_of_padding]; + * } DTLSInnerPlaintext; + * + * Input: + * - `content`: The beginning of the buffer holding the + * plaintext to be wrapped. + * - `*content_size`: The length of the plaintext in Bytes. + * - `max_len`: The number of Bytes available starting from + * `content`. This must be `>= *content_size`. + * - `rec_type`: The desired record content type. + * + * Output: + * - `content`: The beginning of the resulting DTLSInnerPlaintext structure. + * - `*content_size`: The length of the resulting DTLSInnerPlaintext structure. + * + * Returns: + * - `0` on success. + * - A negative error code if `max_len` didn't offer enough space + * for the expansion. + */ +static int ssl_cid_build_inner_plaintext( unsigned char *content, + size_t *content_size, + size_t remaining, + uint8_t rec_type ) +{ + size_t len = *content_size; + size_t pad = ( MBEDTLS_SSL_CID_PADDING_GRANULARITY - + ( len + 1 ) % MBEDTLS_SSL_CID_PADDING_GRANULARITY ) % + MBEDTLS_SSL_CID_PADDING_GRANULARITY; + + /* Write real content type */ + if( remaining == 0 ) + return( -1 ); + content[ len ] = rec_type; + len++; + remaining--; + + if( remaining < pad ) + return( -1 ); + memset( content + len, 0, pad ); + len += pad; + remaining -= pad; + + *content_size = len; + return( 0 ); +} + +/* This function parses a DTLSInnerPlaintext structure. + * See ssl_cid_build_inner_plaintext() for details. */ +static int ssl_cid_parse_inner_plaintext( unsigned char const *content, + size_t *content_size, + uint8_t *rec_type ) +{ + size_t remaining = *content_size; + + /* Determine length of padding by skipping zeroes from the back. */ + do + { + if( remaining == 0 ) + return( -1 ); + remaining--; + } while( content[ remaining ] == 0 ); + + *content_size = remaining; + *rec_type = content[ remaining ]; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + +/* `add_data` must have size 13 Bytes if the CID extension is disabled, + * and 13 + 1 + CID-length Bytes if the CID extension is enabled. */ +static void ssl_extract_add_data_from_record( unsigned char* add_data, + size_t *add_data_len, + mbedtls_record *rec ) +{ + /* Quoting RFC 5246 (TLS 1.2): + * + * additional_data = seq_num + TLSCompressed.type + + * TLSCompressed.version + TLSCompressed.length; + * + * For the CID extension, this is extended as follows + * (quoting draft-ietf-tls-dtls-connection-id-05, + * https://tools.ietf.org/html/draft-ietf-tls-dtls-connection-id-05): + * + * additional_data = seq_num + DTLSPlaintext.type + + * DTLSPlaintext.version + + * cid + + * cid_length + + * length_of_DTLSInnerPlaintext; + */ + + memcpy( add_data, rec->ctr, sizeof( rec->ctr ) ); + add_data[8] = rec->type; + memcpy( add_data + 9, rec->ver, sizeof( rec->ver ) ); + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + if( rec->cid_len != 0 ) + { + memcpy( add_data + 11, rec->cid, rec->cid_len ); + add_data[11 + rec->cid_len + 0] = rec->cid_len; + add_data[11 + rec->cid_len + 1] = ( rec->data_len >> 8 ) & 0xFF; + add_data[11 + rec->cid_len + 2] = ( rec->data_len >> 0 ) & 0xFF; + *add_data_len = 13 + 1 + rec->cid_len; + } + else +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + { + add_data[11 + 0] = ( rec->data_len >> 8 ) & 0xFF; + add_data[11 + 1] = ( rec->data_len >> 0 ) & 0xFF; + *add_data_len = 13; + } +} + +int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform, + mbedtls_record *rec, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + mbedtls_cipher_mode_t mode; + int auth_done = 0; + unsigned char * data; + unsigned char add_data[13 + 1 + MBEDTLS_SSL_CID_OUT_LEN_MAX ]; + size_t add_data_len; + size_t post_avail; + + /* The SSL context is only used for debugging purposes! */ +#if !defined(MBEDTLS_DEBUG_C) + ((void) ssl); +#endif + + /* The PRNG is used for dynamic IV generation that's used + * for CBC transformations in TLS 1.1 and TLS 1.2. */ +#if !( defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_AES_C) || \ + defined(MBEDTLS_ARIA_C) || \ + defined(MBEDTLS_CAMELLIA_C) ) && \ + ( defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) ) ) + ((void) f_rng); + ((void) p_rng); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> encrypt buf" ) ); + + if( transform == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no transform provided to encrypt_buf" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + if( rec == NULL + || rec->buf == NULL + || rec->buf_len < rec->data_offset + || rec->buf_len - rec->data_offset < rec->data_len +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + || rec->cid_len != 0 +#endif + ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad record structure provided to encrypt_buf" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + data = rec->buf + rec->data_offset; + post_avail = rec->buf_len - ( rec->data_len + rec->data_offset ); + MBEDTLS_SSL_DEBUG_BUF( 4, "before encrypt: output payload", + data, rec->data_len ); + + mode = mbedtls_cipher_get_cipher_mode( &transform->cipher_ctx_enc ); + + if( rec->data_len > MBEDTLS_SSL_OUT_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record content %u too large, maximum %d", + (unsigned) rec->data_len, + MBEDTLS_SSL_OUT_CONTENT_LEN ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + /* + * Add CID information + */ + rec->cid_len = transform->out_cid_len; + memcpy( rec->cid, transform->out_cid, transform->out_cid_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "CID", rec->cid, rec->cid_len ); + + if( rec->cid_len != 0 ) + { + /* + * Wrap plaintext into DTLSInnerPlaintext structure. + * See ssl_cid_build_inner_plaintext() for more information. + * + * Note that this changes `rec->data_len`, and hence + * `post_avail` needs to be recalculated afterwards. + */ + if( ssl_cid_build_inner_plaintext( data, + &rec->data_len, + post_avail, + rec->type ) != 0 ) + { + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + rec->type = MBEDTLS_SSL_MSG_CID; + } +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + + post_avail = rec->buf_len - ( rec->data_len + rec->data_offset ); + + /* + * Add MAC before if needed + */ +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) + if( mode == MBEDTLS_MODE_STREAM || + ( mode == MBEDTLS_MODE_CBC +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + && transform->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED +#endif + ) ) + { + if( post_avail < transform->maclen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( transform->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + unsigned char mac[SSL_MAC_MAX_BYTES]; + ssl_mac( &transform->md_ctx_enc, transform->mac_enc, + data, rec->data_len, rec->ctr, rec->type, mac ); + memcpy( data + rec->data_len, mac, transform->maclen ); + } + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( transform->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) + { + unsigned char mac[MBEDTLS_SSL_MAC_ADD]; + + ssl_extract_add_data_from_record( add_data, &add_data_len, rec ); + + mbedtls_md_hmac_update( &transform->md_ctx_enc, add_data, + add_data_len ); + mbedtls_md_hmac_update( &transform->md_ctx_enc, + data, rec->data_len ); + mbedtls_md_hmac_finish( &transform->md_ctx_enc, mac ); + mbedtls_md_hmac_reset( &transform->md_ctx_enc ); + + memcpy( data + rec->data_len, mac, transform->maclen ); + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", data + rec->data_len, + transform->maclen ); + + rec->data_len += transform->maclen; + post_avail -= transform->maclen; + auth_done++; + } +#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ + + /* + * Encrypt + */ +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) + if( mode == MBEDTLS_MODE_STREAM ) + { + int ret; + size_t olen; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " + "including %d bytes of padding", + rec->data_len, 0 ) ); + + if( ( ret = mbedtls_cipher_crypt( &transform->cipher_ctx_enc, + transform->iv_enc, transform->ivlen, + data, rec->data_len, + data, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( rec->data_len != olen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else +#endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */ + +#if defined(MBEDTLS_GCM_C) || \ + defined(MBEDTLS_CCM_C) || \ + defined(MBEDTLS_CHACHAPOLY_C) + if( mode == MBEDTLS_MODE_GCM || + mode == MBEDTLS_MODE_CCM || + mode == MBEDTLS_MODE_CHACHAPOLY ) + { + int ret; + unsigned char iv[12]; + size_t explicit_iv_len = transform->ivlen - transform->fixed_ivlen; + + /* Check that there's space for both the authentication tag + * and the explicit IV before and after the record content. */ + if( post_avail < transform->taglen || + rec->data_offset < explicit_iv_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* + * Generate IV + */ + if( transform->ivlen == 12 && transform->fixed_ivlen == 4 ) + { + /* GCM and CCM: fixed || explicit (=seqnum) */ + memcpy( iv, transform->iv_enc, transform->fixed_ivlen ); + memcpy( iv + transform->fixed_ivlen, rec->ctr, + explicit_iv_len ); + /* Prefix record content with explicit IV. */ + memcpy( data - explicit_iv_len, rec->ctr, explicit_iv_len ); + } + else if( transform->ivlen == 12 && transform->fixed_ivlen == 12 ) + { + /* ChachaPoly: fixed XOR sequence number */ + unsigned char i; + + memcpy( iv, transform->iv_enc, transform->fixed_ivlen ); + + for( i = 0; i < 8; i++ ) + iv[i+4] ^= rec->ctr[i]; + } + else + { + /* Reminder if we ever add an AEAD mode with a different size */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl_extract_add_data_from_record( add_data, &add_data_len, rec ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "IV used (internal)", + iv, transform->ivlen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "IV used (transmitted)", + data - explicit_iv_len, explicit_iv_len ); + MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", + add_data, add_data_len ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " + "including 0 bytes of padding", + rec->data_len ) ); + + /* + * Encrypt and authenticate + */ + + if( ( ret = mbedtls_cipher_auth_encrypt( &transform->cipher_ctx_enc, + iv, transform->ivlen, + add_data, add_data_len, /* add data */ + data, rec->data_len, /* source */ + data, &rec->data_len, /* destination */ + data + rec->data_len, transform->taglen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_encrypt", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "after encrypt: tag", + data + rec->data_len, transform->taglen ); + + rec->data_len += transform->taglen + explicit_iv_len; + rec->data_offset -= explicit_iv_len; + post_avail -= transform->taglen; + auth_done++; + } + else +#endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) || defined(MBEDTLS_ARIA_C) ) + if( mode == MBEDTLS_MODE_CBC ) + { + int ret; + size_t padlen, i; + size_t olen; + + /* Currently we're always using minimal padding + * (up to 255 bytes would be allowed). */ + padlen = transform->ivlen - ( rec->data_len + 1 ) % transform->ivlen; + if( padlen == transform->ivlen ) + padlen = 0; + + /* Check there's enough space in the buffer for the padding. */ + if( post_avail < padlen + 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + for( i = 0; i <= padlen; i++ ) + data[rec->data_len + i] = (unsigned char) padlen; + + rec->data_len += padlen + 1; + post_avail -= padlen + 1; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) + /* + * Prepend per-record IV for block cipher in TLS v1.1 and up as per + * Method 1 (6.2.3.2. in RFC4346 and RFC5246) + */ + if( transform->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + if( f_rng == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "No PRNG provided to encrypt_record routine" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( rec->data_offset < transform->ivlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* + * Generate IV + */ + ret = f_rng( p_rng, transform->iv_enc, transform->ivlen ); + if( ret != 0 ) + return( ret ); + + memcpy( data - transform->ivlen, transform->iv_enc, + transform->ivlen ); + + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1_2 */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " + "including %d bytes of IV and %d bytes of padding", + rec->data_len, transform->ivlen, + padlen + 1 ) ); + + if( ( ret = mbedtls_cipher_crypt( &transform->cipher_ctx_enc, + transform->iv_enc, + transform->ivlen, + data, rec->data_len, + data, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( rec->data_len != olen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) + if( transform->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ) + { + /* + * Save IV in SSL3 and TLS1 + */ + memcpy( transform->iv_enc, transform->cipher_ctx_enc.iv, + transform->ivlen ); + } + else +#endif + { + data -= transform->ivlen; + rec->data_offset -= transform->ivlen; + rec->data_len += transform->ivlen; + } + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + if( auth_done == 0 ) + { + unsigned char mac[MBEDTLS_SSL_MAC_ADD]; + + /* + * MAC(MAC_write_key, seq_num + + * TLSCipherText.type + + * TLSCipherText.version + + * length_of( (IV +) ENC(...) ) + + * IV + // except for TLS 1.0 + * ENC(content + padding + padding_length)); + */ + + if( post_avail < transform->maclen) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Buffer provided for encrypted record not large enough" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + ssl_extract_add_data_from_record( add_data, &add_data_len, rec ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); + MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", add_data, + add_data_len ); + + mbedtls_md_hmac_update( &transform->md_ctx_enc, add_data, + add_data_len ); + mbedtls_md_hmac_update( &transform->md_ctx_enc, + data, rec->data_len ); + mbedtls_md_hmac_finish( &transform->md_ctx_enc, mac ); + mbedtls_md_hmac_reset( &transform->md_ctx_enc ); + + memcpy( data + rec->data_len, mac, transform->maclen ); + + rec->data_len += transform->maclen; + post_avail -= transform->maclen; + auth_done++; + } +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + } + else +#endif /* MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C || MBEDTLS_ARIA_C ) */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* Make extra sure authentication was performed, exactly once */ + if( auth_done != 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= encrypt buf" ) ); + + return( 0 ); +} + +int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform, + mbedtls_record *rec ) +{ + size_t olen; + mbedtls_cipher_mode_t mode; + int ret, auth_done = 0; +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) + size_t padlen = 0, correct = 1; +#endif + unsigned char* data; + unsigned char add_data[13 + 1 + MBEDTLS_SSL_CID_IN_LEN_MAX ]; + size_t add_data_len; + +#if !defined(MBEDTLS_DEBUG_C) + ((void) ssl); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> decrypt buf" ) ); + if( transform == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no transform provided to decrypt_buf" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + if( rec == NULL || + rec->buf == NULL || + rec->buf_len < rec->data_offset || + rec->buf_len - rec->data_offset < rec->data_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad record structure provided to decrypt_buf" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + data = rec->buf + rec->data_offset; + mode = mbedtls_cipher_get_cipher_mode( &transform->cipher_ctx_dec ); + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + /* + * Match record's CID with incoming CID. + */ + if( rec->cid_len != transform->in_cid_len || + memcmp( rec->cid, transform->in_cid, rec->cid_len ) != 0 ) + { + return( MBEDTLS_ERR_SSL_UNEXPECTED_CID ); + } +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) + if( mode == MBEDTLS_MODE_STREAM ) + { + padlen = 0; + if( ( ret = mbedtls_cipher_crypt( &transform->cipher_ctx_dec, + transform->iv_dec, + transform->ivlen, + data, rec->data_len, + data, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( rec->data_len != olen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else +#endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */ +#if defined(MBEDTLS_GCM_C) || \ + defined(MBEDTLS_CCM_C) || \ + defined(MBEDTLS_CHACHAPOLY_C) + if( mode == MBEDTLS_MODE_GCM || + mode == MBEDTLS_MODE_CCM || + mode == MBEDTLS_MODE_CHACHAPOLY ) + { + unsigned char iv[12]; + size_t explicit_iv_len = transform->ivlen - transform->fixed_ivlen; + + /* + * Compute and update sizes + */ + if( rec->data_len < explicit_iv_len + transform->taglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < explicit_iv_len (%d) " + "+ taglen (%d)", rec->data_len, + explicit_iv_len, transform->taglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + + /* + * Prepare IV + */ + if( transform->ivlen == 12 && transform->fixed_ivlen == 4 ) + { + /* GCM and CCM: fixed || explicit (transmitted) */ + memcpy( iv, transform->iv_dec, transform->fixed_ivlen ); + memcpy( iv + transform->fixed_ivlen, data, 8 ); + + } + else if( transform->ivlen == 12 && transform->fixed_ivlen == 12 ) + { + /* ChachaPoly: fixed XOR sequence number */ + unsigned char i; + + memcpy( iv, transform->iv_dec, transform->fixed_ivlen ); + + for( i = 0; i < 8; i++ ) + iv[i+4] ^= rec->ctr[i]; + } + else + { + /* Reminder if we ever add an AEAD mode with a different size */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + data += explicit_iv_len; + rec->data_offset += explicit_iv_len; + rec->data_len -= explicit_iv_len + transform->taglen; + + ssl_extract_add_data_from_record( add_data, &add_data_len, rec ); + MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", + add_data, add_data_len ); + + memcpy( transform->iv_dec + transform->fixed_ivlen, + data - explicit_iv_len, explicit_iv_len ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", iv, transform->ivlen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "TAG used", data + rec->data_len, + transform->taglen ); + + + /* + * Decrypt and authenticate + */ + if( ( ret = mbedtls_cipher_auth_decrypt( &transform->cipher_ctx_dec, + iv, transform->ivlen, + add_data, add_data_len, + data, rec->data_len, + data, &olen, + data + rec->data_len, + transform->taglen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_decrypt", ret ); + + if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED ) + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + + return( ret ); + } + auth_done++; + + if( olen != rec->data_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else +#endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) || defined(MBEDTLS_ARIA_C) ) + if( mode == MBEDTLS_MODE_CBC ) + { + size_t minlen = 0; + + /* + * Check immediate ciphertext sanity + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( transform->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + /* The ciphertext is prefixed with the CBC IV. */ + minlen += transform->ivlen; + } +#endif + + /* Size considerations: + * + * - The CBC cipher text must not be empty and hence + * at least of size transform->ivlen. + * + * Together with the potential IV-prefix, this explains + * the first of the two checks below. + * + * - The record must contain a MAC, either in plain or + * encrypted, depending on whether Encrypt-then-MAC + * is used or not. + * - If it is, the message contains the IV-prefix, + * the CBC ciphertext, and the MAC. + * - If it is not, the padded plaintext, and hence + * the CBC ciphertext, has at least length maclen + 1 + * because there is at least the padding length byte. + * + * As the CBC ciphertext is not empty, both cases give the + * lower bound minlen + maclen + 1 on the record size, which + * we test for in the second check below. + */ + if( rec->data_len < minlen + transform->ivlen || + rec->data_len < minlen + transform->maclen + 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < max( ivlen(%d), maclen (%d) " + "+ 1 ) ( + expl IV )", rec->data_len, + transform->ivlen, + transform->maclen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + + /* + * Authenticate before decrypt if enabled + */ +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + if( transform->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED ) + { + unsigned char mac_expect[MBEDTLS_SSL_MAC_ADD]; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); + + /* Safe due to the check data_len >= minlen + maclen + 1 above. */ + rec->data_len -= transform->maclen; + + ssl_extract_add_data_from_record( add_data, &add_data_len, rec ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", add_data, + add_data_len ); + mbedtls_md_hmac_update( &transform->md_ctx_dec, add_data, + add_data_len ); + mbedtls_md_hmac_update( &transform->md_ctx_dec, + data, rec->data_len ); + mbedtls_md_hmac_finish( &transform->md_ctx_dec, mac_expect ); + mbedtls_md_hmac_reset( &transform->md_ctx_dec ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", data + rec->data_len, + transform->maclen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "expected mac", mac_expect, + transform->maclen ); + + if( mbedtls_ssl_safer_memcmp( data + rec->data_len, mac_expect, + transform->maclen ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + auth_done++; + } +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + + /* + * Check length sanity + */ + if( rec->data_len % transform->ivlen != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) %% ivlen (%d) != 0", + rec->data_len, transform->ivlen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) + /* + * Initialize for prepended IV for block cipher in TLS v1.1 and up + */ + if( transform->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + /* This is safe because data_len >= minlen + maclen + 1 initially, + * and at this point we have at most subtracted maclen (note that + * minlen == transform->ivlen here). */ + memcpy( transform->iv_dec, data, transform->ivlen ); + + data += transform->ivlen; + rec->data_offset += transform->ivlen; + rec->data_len -= transform->ivlen; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1_2 */ + + if( ( ret = mbedtls_cipher_crypt( &transform->cipher_ctx_dec, + transform->iv_dec, transform->ivlen, + data, rec->data_len, data, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( rec->data_len != olen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) + if( transform->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ) + { + /* + * Save IV in SSL3 and TLS1 + */ + memcpy( transform->iv_dec, transform->cipher_ctx_dec.iv, + transform->ivlen ); + } +#endif + + /* Safe since data_len >= minlen + maclen + 1, so after having + * subtracted at most minlen and maclen up to this point, + * data_len > 0. */ + padlen = data[rec->data_len - 1]; + + if( auth_done == 1 ) + { + correct *= ( rec->data_len >= padlen + 1 ); + padlen *= ( rec->data_len >= padlen + 1 ); + } + else + { +#if defined(MBEDTLS_SSL_DEBUG_ALL) + if( rec->data_len < transform->maclen + padlen + 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < maclen (%d) + padlen (%d)", + rec->data_len, + transform->maclen, + padlen + 1 ) ); + } +#endif + + correct *= ( rec->data_len >= transform->maclen + padlen + 1 ); + padlen *= ( rec->data_len >= transform->maclen + padlen + 1 ); + } + + padlen++; + + /* Regardless of the validity of the padding, + * we have data_len >= padlen here. */ + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( transform->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( padlen > transform->ivlen ) + { +#if defined(MBEDTLS_SSL_DEBUG_ALL) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad padding length: is %d, " + "should be no more than %d", + padlen, transform->ivlen ) ); +#endif + correct = 0; + } + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( transform->minor_ver > MBEDTLS_SSL_MINOR_VERSION_0 ) + { + /* The padding check involves a series of up to 256 + * consecutive memory reads at the end of the record + * plaintext buffer. In order to hide the length and + * validity of the padding, always perform exactly + * `min(256,plaintext_len)` reads (but take into account + * only the last `padlen` bytes for the padding check). */ + size_t pad_count = 0; + size_t real_count = 0; + volatile unsigned char* const check = data; + + /* Index of first padding byte; it has been ensured above + * that the subtraction is safe. */ + size_t const padding_idx = rec->data_len - padlen; + size_t const num_checks = rec->data_len <= 256 ? rec->data_len : 256; + size_t const start_idx = rec->data_len - num_checks; + size_t idx; + + for( idx = start_idx; idx < rec->data_len; idx++ ) + { + real_count |= ( idx >= padding_idx ); + pad_count += real_count * ( check[idx] == padlen - 1 ); + } + correct &= ( pad_count == padlen ); + +#if defined(MBEDTLS_SSL_DEBUG_ALL) + if( padlen > 0 && correct == 0 ) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad padding byte detected" ) ); +#endif + padlen &= correct * 0x1FF; + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* If the padding was found to be invalid, padlen == 0 + * and the subtraction is safe. If the padding was found valid, + * padlen hasn't been changed and the previous assertion + * data_len >= padlen still holds. */ + rec->data_len -= padlen; + } + else +#endif /* MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C || MBEDTLS_ARIA_C ) */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_DEBUG_ALL) + MBEDTLS_SSL_DEBUG_BUF( 4, "raw buffer after decryption", + data, rec->data_len ); +#endif + + /* + * Authenticate if not done yet. + * Compute the MAC regardless of the padding result (RFC4346, CBCTIME). + */ +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) + if( auth_done == 0 ) + { + unsigned char mac_expect[MBEDTLS_SSL_MAC_ADD]; + + /* If the initial value of padlen was such that + * data_len < maclen + padlen + 1, then padlen + * got reset to 1, and the initial check + * data_len >= minlen + maclen + 1 + * guarantees that at this point we still + * have at least data_len >= maclen. + * + * If the initial value of padlen was such that + * data_len >= maclen + padlen + 1, then we have + * subtracted either padlen + 1 (if the padding was correct) + * or 0 (if the padding was incorrect) since then, + * hence data_len >= maclen in any case. + */ + rec->data_len -= transform->maclen; + + ssl_extract_add_data_from_record( add_data, &add_data_len, rec ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( transform->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl_mac( &transform->md_ctx_dec, + transform->mac_dec, + data, rec->data_len, + rec->ctr, rec->type, + mac_expect ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( transform->minor_ver > MBEDTLS_SSL_MINOR_VERSION_0 ) + { + /* + * Process MAC and always update for padlen afterwards to make + * total time independent of padlen. + * + * Known timing attacks: + * - Lucky Thirteen (http://www.isg.rhul.ac.uk/tls/TLStiming.pdf) + * + * To compensate for different timings for the MAC calculation + * depending on how much padding was removed (which is determined + * by padlen), process extra_run more blocks through the hash + * function. + * + * The formula in the paper is + * extra_run = ceil( (L1-55) / 64 ) - ceil( (L2-55) / 64 ) + * where L1 is the size of the header plus the decrypted message + * plus CBC padding and L2 is the size of the header plus the + * decrypted message. This is for an underlying hash function + * with 64-byte blocks. + * We use ( (Lx+8) / 64 ) to handle 'negative Lx' values + * correctly. We round down instead of up, so -56 is the correct + * value for our calculations instead of -55. + * + * Repeat the formula rather than defining a block_size variable. + * This avoids requiring division by a variable at runtime + * (which would be marginally less efficient and would require + * linking an extra division function in some builds). + */ + size_t j, extra_run = 0; + unsigned char tmp[MBEDTLS_MD_MAX_BLOCK_SIZE]; + + /* + * The next two sizes are the minimum and maximum values of + * in_msglen over all padlen values. + * + * They're independent of padlen, since we previously did + * in_msglen -= padlen. + * + * Note that max_len + maclen is never more than the buffer + * length, as we previously did in_msglen -= maclen too. + */ + const size_t max_len = rec->data_len + padlen; + const size_t min_len = ( max_len > 256 ) ? max_len - 256 : 0; + + memset( tmp, 0, sizeof( tmp ) ); + + switch( mbedtls_md_get_type( transform->md_ctx_dec.md_info ) ) + { +#if defined(MBEDTLS_MD5_C) || defined(MBEDTLS_SHA1_C) || \ + defined(MBEDTLS_SHA256_C) + case MBEDTLS_MD_MD5: + case MBEDTLS_MD_SHA1: + case MBEDTLS_MD_SHA256: + /* 8 bytes of message size, 64-byte compression blocks */ + extra_run = + ( add_data_len + rec->data_len + padlen + 8 ) / 64 - + ( add_data_len + rec->data_len + 8 ) / 64; + break; +#endif +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_MD_SHA384: + /* 16 bytes of message size, 128-byte compression blocks */ + extra_run = + ( add_data_len + rec->data_len + padlen + 16 ) / 128 - + ( add_data_len + rec->data_len + 16 ) / 128; + break; +#endif + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + extra_run &= correct * 0xFF; + + mbedtls_md_hmac_update( &transform->md_ctx_dec, add_data, + add_data_len ); + mbedtls_md_hmac_update( &transform->md_ctx_dec, data, + rec->data_len ); + /* Make sure we access everything even when padlen > 0. This + * makes the synchronisation requirements for just-in-time + * Prime+Probe attacks much tighter and hopefully impractical. */ + ssl_read_memory( data + rec->data_len, padlen ); + mbedtls_md_hmac_finish( &transform->md_ctx_dec, mac_expect ); + + /* Call mbedtls_md_process at least once due to cache attacks + * that observe whether md_process() was called of not */ + for( j = 0; j < extra_run + 1; j++ ) + mbedtls_md_process( &transform->md_ctx_dec, tmp ); + + mbedtls_md_hmac_reset( &transform->md_ctx_dec ); + + /* Make sure we access all the memory that could contain the MAC, + * before we check it in the next code block. This makes the + * synchronisation requirements for just-in-time Prime+Probe + * attacks much tighter and hopefully impractical. */ + ssl_read_memory( data + min_len, + max_len - min_len + transform->maclen ); + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_DEBUG_ALL) + MBEDTLS_SSL_DEBUG_BUF( 4, "expected mac", mac_expect, transform->maclen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", data + rec->data_len, transform->maclen ); +#endif + + if( mbedtls_ssl_safer_memcmp( data + rec->data_len, mac_expect, + transform->maclen ) != 0 ) + { +#if defined(MBEDTLS_SSL_DEBUG_ALL) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); +#endif + correct = 0; + } + auth_done++; + } + + /* + * Finally check the correct flag + */ + if( correct == 0 ) + return( MBEDTLS_ERR_SSL_INVALID_MAC ); +#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */ + + /* Make extra sure authentication was performed, exactly once */ + if( auth_done != 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + if( rec->cid_len != 0 ) + { + ret = ssl_cid_parse_inner_plaintext( data, &rec->data_len, + &rec->type ); + if( ret != 0 ) + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= decrypt buf" ) ); + + return( 0 ); +} + +#undef MAC_NONE +#undef MAC_PLAINTEXT +#undef MAC_CIPHERTEXT + +#if defined(MBEDTLS_ZLIB_SUPPORT) +/* + * Compression/decompression functions + */ +static int ssl_compress_buf( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *msg_post = ssl->out_msg; + ptrdiff_t bytes_written = ssl->out_msg - ssl->out_buf; + size_t len_pre = ssl->out_msglen; + unsigned char *msg_pre = ssl->compress_buf; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> compress buf" ) ); + + if( len_pre == 0 ) + return( 0 ); + + memcpy( msg_pre, ssl->out_msg, len_pre ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before compression: msglen = %d, ", + ssl->out_msglen ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "before compression: output payload", + ssl->out_msg, ssl->out_msglen ); + + ssl->transform_out->ctx_deflate.next_in = msg_pre; + ssl->transform_out->ctx_deflate.avail_in = len_pre; + ssl->transform_out->ctx_deflate.next_out = msg_post; + ssl->transform_out->ctx_deflate.avail_out = MBEDTLS_SSL_OUT_BUFFER_LEN - bytes_written; + + ret = deflate( &ssl->transform_out->ctx_deflate, Z_SYNC_FLUSH ); + if( ret != Z_OK ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "failed to perform compression (%d)", ret ) ); + return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); + } + + ssl->out_msglen = MBEDTLS_SSL_OUT_BUFFER_LEN - + ssl->transform_out->ctx_deflate.avail_out - bytes_written; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "after compression: msglen = %d, ", + ssl->out_msglen ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "after compression: output payload", + ssl->out_msg, ssl->out_msglen ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= compress buf" ) ); + + return( 0 ); +} + +static int ssl_decompress_buf( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *msg_post = ssl->in_msg; + ptrdiff_t header_bytes = ssl->in_msg - ssl->in_buf; + size_t len_pre = ssl->in_msglen; + unsigned char *msg_pre = ssl->compress_buf; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> decompress buf" ) ); + + if( len_pre == 0 ) + return( 0 ); + + memcpy( msg_pre, ssl->in_msg, len_pre ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before decompression: msglen = %d, ", + ssl->in_msglen ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "before decompression: input payload", + ssl->in_msg, ssl->in_msglen ); + + ssl->transform_in->ctx_inflate.next_in = msg_pre; + ssl->transform_in->ctx_inflate.avail_in = len_pre; + ssl->transform_in->ctx_inflate.next_out = msg_post; + ssl->transform_in->ctx_inflate.avail_out = MBEDTLS_SSL_IN_BUFFER_LEN - + header_bytes; + + ret = inflate( &ssl->transform_in->ctx_inflate, Z_SYNC_FLUSH ); + if( ret != Z_OK ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "failed to perform decompression (%d)", ret ) ); + return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); + } + + ssl->in_msglen = MBEDTLS_SSL_IN_BUFFER_LEN - + ssl->transform_in->ctx_inflate.avail_out - header_bytes; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "after decompression: msglen = %d, ", + ssl->in_msglen ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "after decompression: input payload", + ssl->in_msg, ssl->in_msglen ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= decompress buf" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_ZLIB_SUPPORT */ + +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION) +static int ssl_write_hello_request( mbedtls_ssl_context *ssl ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +static int ssl_resend_hello_request( mbedtls_ssl_context *ssl ) +{ + /* If renegotiation is not enforced, retransmit until we would reach max + * timeout if we were using the usual handshake doubling scheme */ + if( ssl->conf->renego_max_records < 0 ) + { + uint32_t ratio = ssl->conf->hs_timeout_max / ssl->conf->hs_timeout_min + 1; + unsigned char doublings = 1; + + while( ratio != 0 ) + { + ++doublings; + ratio >>= 1; + } + + if( ++ssl->renego_records_seen > doublings ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "no longer retransmitting hello request" ) ); + return( 0 ); + } + } + + return( ssl_write_hello_request( ssl ) ); +} +#endif +#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_RENEGOTIATION */ + +/* + * Fill the input message buffer by appending data to it. + * The amount of data already fetched is in ssl->in_left. + * + * If we return 0, is it guaranteed that (at least) nb_want bytes are + * available (from this read and/or a previous one). Otherwise, an error code + * is returned (possibly EOF or WANT_READ). + * + * With stream transport (TLS) on success ssl->in_left == nb_want, but + * with datagram transport (DTLS) on success ssl->in_left >= nb_want, + * since we always read a whole datagram at once. + * + * For DTLS, it is up to the caller to set ssl->next_record_offset when + * they're done reading a record. + */ +int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) +{ + int ret; + size_t len; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> fetch input" ) ); + + if( ssl->f_recv == NULL && ssl->f_recv_timeout == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() " + "or mbedtls_ssl_set_bio()" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( nb_want > MBEDTLS_SSL_IN_BUFFER_LEN - (size_t)( ssl->in_hdr - ssl->in_buf ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "requesting more data than fits" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + uint32_t timeout; + + /* Just to be sure */ + if( ssl->f_set_timer == NULL || ssl->f_get_timer == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "You must use " + "mbedtls_ssl_set_timer_cb() for DTLS" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* + * The point is, we need to always read a full datagram at once, so we + * sometimes read more then requested, and handle the additional data. + * It could be the rest of the current record (while fetching the + * header) and/or some other records in the same datagram. + */ + + /* + * Move to the next record in the already read datagram if applicable + */ + if( ssl->next_record_offset != 0 ) + { + if( ssl->in_left < ssl->next_record_offset ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->in_left -= ssl->next_record_offset; + + if( ssl->in_left != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "next record in same datagram, offset: %d", + ssl->next_record_offset ) ); + memmove( ssl->in_hdr, + ssl->in_hdr + ssl->next_record_offset, + ssl->in_left ); + } + + ssl->next_record_offset = 0; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d", + ssl->in_left, nb_want ) ); + + /* + * Done if we already have enough data. + */ + if( nb_want <= ssl->in_left) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= fetch input" ) ); + return( 0 ); + } + + /* + * A record can't be split across datagrams. If we need to read but + * are not at the beginning of a new record, the caller did something + * wrong. + */ + if( ssl->in_left != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* + * Don't even try to read if time's out already. + * This avoids by-passing the timer when repeatedly receiving messages + * that will end up being dropped. + */ + if( ssl_check_timer( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "timer has expired" ) ); + ret = MBEDTLS_ERR_SSL_TIMEOUT; + } + else + { + len = MBEDTLS_SSL_IN_BUFFER_LEN - ( ssl->in_hdr - ssl->in_buf ); + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + timeout = ssl->handshake->retransmit_timeout; + else + timeout = ssl->conf->read_timeout; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "f_recv_timeout: %u ms", timeout ) ); + + if( ssl->f_recv_timeout != NULL ) + ret = ssl->f_recv_timeout( ssl->p_bio, ssl->in_hdr, len, + timeout ); + else + ret = ssl->f_recv( ssl->p_bio, ssl->in_hdr, len ); + + MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_recv(_timeout)", ret ); + + if( ret == 0 ) + return( MBEDTLS_ERR_SSL_CONN_EOF ); + } + + if( ret == MBEDTLS_ERR_SSL_TIMEOUT ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "timeout" ) ); + ssl_set_timer( ssl, 0 ); + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + if( ssl_double_retransmit_timeout( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake timeout" ) ); + return( MBEDTLS_ERR_SSL_TIMEOUT ); + } + + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_resend", ret ); + return( ret ); + } + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION) + else if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) + { + if( ( ret = ssl_resend_hello_request( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_resend_hello_request", ret ); + return( ret ); + } + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } +#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_RENEGOTIATION */ + } + + if( ret < 0 ) + return( ret ); + + ssl->in_left = ret; + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d", + ssl->in_left, nb_want ) ); + + while( ssl->in_left < nb_want ) + { + len = nb_want - ssl->in_left; + + if( ssl_check_timer( ssl ) != 0 ) + ret = MBEDTLS_ERR_SSL_TIMEOUT; + else + { + if( ssl->f_recv_timeout != NULL ) + { + ret = ssl->f_recv_timeout( ssl->p_bio, + ssl->in_hdr + ssl->in_left, len, + ssl->conf->read_timeout ); + } + else + { + ret = ssl->f_recv( ssl->p_bio, + ssl->in_hdr + ssl->in_left, len ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d", + ssl->in_left, nb_want ) ); + MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_recv(_timeout)", ret ); + + if( ret == 0 ) + return( MBEDTLS_ERR_SSL_CONN_EOF ); + + if( ret < 0 ) + return( ret ); + + if ( (size_t)ret > len || ( INT_MAX > SIZE_MAX && ret > SIZE_MAX ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "f_recv returned %d bytes but only %lu were requested", + ret, (unsigned long)len ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->in_left += ret; + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= fetch input" ) ); + + return( 0 ); +} + +/* + * Flush any data not yet written + */ +int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *buf; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> flush output" ) ); + + if( ssl->f_send == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() " + "or mbedtls_ssl_set_bio()" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* Avoid incrementing counter if data is flushed */ + if( ssl->out_left == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= flush output" ) ); + return( 0 ); + } + + while( ssl->out_left > 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "message length: %d, out_left: %d", + mbedtls_ssl_out_hdr_len( ssl ) + ssl->out_msglen, ssl->out_left ) ); + + buf = ssl->out_hdr - ssl->out_left; + ret = ssl->f_send( ssl->p_bio, buf, ssl->out_left ); + + MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_send", ret ); + + if( ret <= 0 ) + return( ret ); + + if( (size_t)ret > ssl->out_left || ( INT_MAX > SIZE_MAX && ret > SIZE_MAX ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "f_send returned %d bytes but only %lu bytes were sent", + ret, (unsigned long)ssl->out_left ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->out_left -= ret; + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->out_hdr = ssl->out_buf; + } + else +#endif + { + ssl->out_hdr = ssl->out_buf + 8; + } + ssl_update_out_pointers( ssl, ssl->transform_out ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= flush output" ) ); + + return( 0 ); +} + +/* + * Functions to handle the DTLS retransmission state machine + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) +/* + * Append current handshake message to current outgoing flight + */ +static int ssl_flight_append( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_flight_item *msg; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_flight_append" ) ); + MBEDTLS_SSL_DEBUG_BUF( 4, "message appended to flight", + ssl->out_msg, ssl->out_msglen ); + + /* Allocate space for current message */ + if( ( msg = mbedtls_calloc( 1, sizeof( mbedtls_ssl_flight_item ) ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc %d bytes failed", + sizeof( mbedtls_ssl_flight_item ) ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + if( ( msg->p = mbedtls_calloc( 1, ssl->out_msglen ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc %d bytes failed", ssl->out_msglen ) ); + mbedtls_free( msg ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + /* Copy current handshake message with headers */ + memcpy( msg->p, ssl->out_msg, ssl->out_msglen ); + msg->len = ssl->out_msglen; + msg->type = ssl->out_msgtype; + msg->next = NULL; + + /* Append to the current flight */ + if( ssl->handshake->flight == NULL ) + ssl->handshake->flight = msg; + else + { + mbedtls_ssl_flight_item *cur = ssl->handshake->flight; + while( cur->next != NULL ) + cur = cur->next; + cur->next = msg; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_flight_append" ) ); + return( 0 ); +} + +/* + * Free the current flight of handshake messages + */ +static void ssl_flight_free( mbedtls_ssl_flight_item *flight ) +{ + mbedtls_ssl_flight_item *cur = flight; + mbedtls_ssl_flight_item *next; + + while( cur != NULL ) + { + next = cur->next; + + mbedtls_free( cur->p ); + mbedtls_free( cur ); + + cur = next; + } +} + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +static void ssl_dtls_replay_reset( mbedtls_ssl_context *ssl ); +#endif + +/* + * Swap transform_out and out_ctr with the alternative ones + */ +static void ssl_swap_epochs( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_transform *tmp_transform; + unsigned char tmp_out_ctr[8]; + + if( ssl->transform_out == ssl->handshake->alt_transform_out ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip swap epochs" ) ); + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "swap epochs" ) ); + + /* Swap transforms */ + tmp_transform = ssl->transform_out; + ssl->transform_out = ssl->handshake->alt_transform_out; + ssl->handshake->alt_transform_out = tmp_transform; + + /* Swap epoch + sequence_number */ + memcpy( tmp_out_ctr, ssl->cur_out_ctr, 8 ); + memcpy( ssl->cur_out_ctr, ssl->handshake->alt_out_ctr, 8 ); + memcpy( ssl->handshake->alt_out_ctr, tmp_out_ctr, 8 ); + + /* Adjust to the newly activated transform */ + ssl_update_out_pointers( ssl, ssl->transform_out ); + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_activate != NULL ) + { + if( ( ret = mbedtls_ssl_hw_record_activate( ssl, MBEDTLS_SSL_CHANNEL_OUTBOUND ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_activate", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif +} + +/* + * Retransmit the current flight of messages. + */ +int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_resend" ) ); + + ret = mbedtls_ssl_flight_transmit( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_resend" ) ); + + return( ret ); +} + +/* + * Transmit or retransmit the current flight of messages. + * + * Need to remember the current message in case flush_output returns + * WANT_WRITE, causing us to exit this function and come back later. + * This function must be called until state is no longer SENDING. + */ +int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl ) +{ + int ret; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_flight_transmit" ) ); + + if( ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialise flight transmission" ) ); + + ssl->handshake->cur_msg = ssl->handshake->flight; + ssl->handshake->cur_msg_p = ssl->handshake->flight->p + 12; + ssl_swap_epochs( ssl ); + + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_SENDING; + } + + while( ssl->handshake->cur_msg != NULL ) + { + size_t max_frag_len; + const mbedtls_ssl_flight_item * const cur = ssl->handshake->cur_msg; + + int const is_finished = + ( cur->type == MBEDTLS_SSL_MSG_HANDSHAKE && + cur->p[0] == MBEDTLS_SSL_HS_FINISHED ); + + uint8_t const force_flush = ssl->disable_datagram_packing == 1 ? + SSL_FORCE_FLUSH : SSL_DONT_FORCE_FLUSH; + + /* Swap epochs before sending Finished: we can't do it after + * sending ChangeCipherSpec, in case write returns WANT_READ. + * Must be done before copying, may change out_msg pointer */ + if( is_finished && ssl->handshake->cur_msg_p == ( cur->p + 12 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "swap epochs to send finished message" ) ); + ssl_swap_epochs( ssl ); + } + + ret = ssl_get_remaining_payload_in_datagram( ssl ); + if( ret < 0 ) + return( ret ); + max_frag_len = (size_t) ret; + + /* CCS is copied as is, while HS messages may need fragmentation */ + if( cur->type == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) + { + if( max_frag_len == 0 ) + { + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + continue; + } + + memcpy( ssl->out_msg, cur->p, cur->len ); + ssl->out_msglen = cur->len; + ssl->out_msgtype = cur->type; + + /* Update position inside current message */ + ssl->handshake->cur_msg_p += cur->len; + } + else + { + const unsigned char * const p = ssl->handshake->cur_msg_p; + const size_t hs_len = cur->len - 12; + const size_t frag_off = p - ( cur->p + 12 ); + const size_t rem_len = hs_len - frag_off; + size_t cur_hs_frag_len, max_hs_frag_len; + + if( ( max_frag_len < 12 ) || ( max_frag_len == 12 && hs_len != 0 ) ) + { + if( is_finished ) + ssl_swap_epochs( ssl ); + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + continue; + } + max_hs_frag_len = max_frag_len - 12; + + cur_hs_frag_len = rem_len > max_hs_frag_len ? + max_hs_frag_len : rem_len; + + if( frag_off == 0 && cur_hs_frag_len != hs_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "fragmenting handshake message (%u > %u)", + (unsigned) cur_hs_frag_len, + (unsigned) max_hs_frag_len ) ); + } + + /* Messages are stored with handshake headers as if not fragmented, + * copy beginning of headers then fill fragmentation fields. + * Handshake headers: type(1) len(3) seq(2) f_off(3) f_len(3) */ + memcpy( ssl->out_msg, cur->p, 6 ); + + ssl->out_msg[6] = ( ( frag_off >> 16 ) & 0xff ); + ssl->out_msg[7] = ( ( frag_off >> 8 ) & 0xff ); + ssl->out_msg[8] = ( ( frag_off ) & 0xff ); + + ssl->out_msg[ 9] = ( ( cur_hs_frag_len >> 16 ) & 0xff ); + ssl->out_msg[10] = ( ( cur_hs_frag_len >> 8 ) & 0xff ); + ssl->out_msg[11] = ( ( cur_hs_frag_len ) & 0xff ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "handshake header", ssl->out_msg, 12 ); + + /* Copy the handshake message content and set records fields */ + memcpy( ssl->out_msg + 12, p, cur_hs_frag_len ); + ssl->out_msglen = cur_hs_frag_len + 12; + ssl->out_msgtype = cur->type; + + /* Update position inside current message */ + ssl->handshake->cur_msg_p += cur_hs_frag_len; + } + + /* If done with the current message move to the next one if any */ + if( ssl->handshake->cur_msg_p >= cur->p + cur->len ) + { + if( cur->next != NULL ) + { + ssl->handshake->cur_msg = cur->next; + ssl->handshake->cur_msg_p = cur->next->p + 12; + } + else + { + ssl->handshake->cur_msg = NULL; + ssl->handshake->cur_msg_p = NULL; + } + } + + /* Actually send the message out */ + if( ( ret = mbedtls_ssl_write_record( ssl, force_flush ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + } + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + /* Update state and set timer */ + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED; + else + { + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_WAITING; + ssl_set_timer( ssl, ssl->handshake->retransmit_timeout ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_flight_transmit" ) ); + + return( 0 ); +} + +/* + * To be called when the last message of an incoming flight is received. + */ +void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl ) +{ + /* We won't need to resend that one any more */ + ssl_flight_free( ssl->handshake->flight ); + ssl->handshake->flight = NULL; + ssl->handshake->cur_msg = NULL; + + /* The next incoming flight will start with this msg_seq */ + ssl->handshake->in_flight_start_seq = ssl->handshake->in_msg_seq; + + /* We don't want to remember CCS's across flight boundaries. */ + ssl->handshake->buffering.seen_ccs = 0; + + /* Clear future message buffering structure. */ + ssl_buffering_free( ssl ); + + /* Cancel timer */ + ssl_set_timer( ssl, 0 ); + + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == MBEDTLS_SSL_HS_FINISHED ) + { + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED; + } + else + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_PREPARING; +} + +/* + * To be called when the last message of an outgoing flight is send. + */ +void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ) +{ + ssl_reset_retransmit_timeout( ssl ); + ssl_set_timer( ssl, ssl->handshake->retransmit_timeout ); + + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == MBEDTLS_SSL_HS_FINISHED ) + { + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED; + } + else + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_WAITING; +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +/* + * Handshake layer functions + */ + +/* + * Write (DTLS: or queue) current handshake (including CCS) message. + * + * - fill in handshake headers + * - update handshake checksum + * - DTLS: save message for resending + * - then pass to the record layer + * + * DTLS: except for HelloRequest, messages are only queued, and will only be + * actually sent when calling flight_transmit() or resend(). + * + * Inputs: + * - ssl->out_msglen: 4 + actual handshake message len + * (4 is the size of handshake headers for TLS) + * - ssl->out_msg[0]: the handshake type (ClientHello, ServerHello, etc) + * - ssl->out_msg + 4: the handshake message body + * + * Outputs, ie state before passing to flight_append() or write_record(): + * - ssl->out_msglen: the length of the record contents + * (including handshake headers but excluding record headers) + * - ssl->out_msg: the record contents (handshake headers + content) + */ +int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl ) +{ + int ret; + const size_t hs_len = ssl->out_msglen - 4; + const unsigned char hs_type = ssl->out_msg[0]; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write handshake message" ) ); + + /* + * Sanity checks + */ + if( ssl->out_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->out_msgtype != MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) + { + /* In SSLv3, the client might send a NoCertificate alert. */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) && defined(MBEDTLS_SSL_CLI_C) + if( ! ( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 && + ssl->out_msgtype == MBEDTLS_SSL_MSG_ALERT && + ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) ) +#endif /* MBEDTLS_SSL_PROTO_SSL3 && MBEDTLS_SSL_SRV_C */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + + /* Whenever we send anything different from a + * HelloRequest we should be in a handshake - double check. */ + if( ! ( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + hs_type == MBEDTLS_SSL_HS_HELLO_REQUEST ) && + ssl->handshake == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake != NULL && + ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } +#endif + + /* Double-check that we did not exceed the bounds + * of the outgoing record buffer. + * This should never fail as the various message + * writing functions must obey the bounds of the + * outgoing record buffer, but better be safe. + * + * Note: We deliberately do not check for the MTU or MFL here. + */ + if( ssl->out_msglen > MBEDTLS_SSL_OUT_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record too large: " + "size %u, maximum %u", + (unsigned) ssl->out_msglen, + (unsigned) MBEDTLS_SSL_OUT_CONTENT_LEN ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* + * Fill handshake headers + */ + if( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + { + ssl->out_msg[1] = (unsigned char)( hs_len >> 16 ); + ssl->out_msg[2] = (unsigned char)( hs_len >> 8 ); + ssl->out_msg[3] = (unsigned char)( hs_len ); + + /* + * DTLS has additional fields in the Handshake layer, + * between the length field and the actual payload: + * uint16 message_seq; + * uint24 fragment_offset; + * uint24 fragment_length; + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + /* Make room for the additional DTLS fields */ + if( MBEDTLS_SSL_OUT_CONTENT_LEN - ssl->out_msglen < 8 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "DTLS handshake message too large: " + "size %u, maximum %u", + (unsigned) ( hs_len ), + (unsigned) ( MBEDTLS_SSL_OUT_CONTENT_LEN - 12 ) ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + memmove( ssl->out_msg + 12, ssl->out_msg + 4, hs_len ); + ssl->out_msglen += 8; + + /* Write message_seq and update it, except for HelloRequest */ + if( hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST ) + { + ssl->out_msg[4] = ( ssl->handshake->out_msg_seq >> 8 ) & 0xFF; + ssl->out_msg[5] = ( ssl->handshake->out_msg_seq ) & 0xFF; + ++( ssl->handshake->out_msg_seq ); + } + else + { + ssl->out_msg[4] = 0; + ssl->out_msg[5] = 0; + } + + /* Handshake hashes are computed without fragmentation, + * so set frag_offset = 0 and frag_len = hs_len for now */ + memset( ssl->out_msg + 6, 0x00, 3 ); + memcpy( ssl->out_msg + 9, ssl->out_msg + 1, 3 ); + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + /* Update running hashes of handshake messages seen */ + if( hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST ) + ssl->handshake->update_checksum( ssl, ssl->out_msg, ssl->out_msglen ); + } + + /* Either send now, or just save to be sent (and resent) later */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ! ( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + hs_type == MBEDTLS_SSL_HS_HELLO_REQUEST ) ) + { + if( ( ret = ssl_flight_append( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_flight_append", ret ); + return( ret ); + } + } + else +#endif + { + if( ( ret = mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_record", ret ); + return( ret ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write handshake message" ) ); + + return( 0 ); +} + +/* + * Record layer functions + */ + +/* + * Write current record. + * + * Uses: + * - ssl->out_msgtype: type of the message (AppData, Handshake, Alert, CCS) + * - ssl->out_msglen: length of the record content (excl headers) + * - ssl->out_msg: record content + */ +int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush ) +{ + int ret, done = 0; + size_t len = ssl->out_msglen; + uint8_t flush = force_flush; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write record" ) ); + +#if defined(MBEDTLS_ZLIB_SUPPORT) + if( ssl->transform_out != NULL && + ssl->session_out->compression == MBEDTLS_SSL_COMPRESS_DEFLATE ) + { + if( ( ret = ssl_compress_buf( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_compress_buf", ret ); + return( ret ); + } + + len = ssl->out_msglen; + } +#endif /*MBEDTLS_ZLIB_SUPPORT */ + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_write != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_write()" ) ); + + ret = mbedtls_ssl_hw_record_write( ssl ); + if( ret != 0 && ret != MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_write", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + + if( ret == 0 ) + done = 1; + } +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + if( !done ) + { + unsigned i; + size_t protected_record_size; + + /* Skip writing the record content type to after the encryption, + * as it may change when using the CID extension. */ + + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, ssl->out_hdr + 1 ); + + memcpy( ssl->out_ctr, ssl->cur_out_ctr, 8 ); + ssl->out_len[0] = (unsigned char)( len >> 8 ); + ssl->out_len[1] = (unsigned char)( len ); + + if( ssl->transform_out != NULL ) + { + mbedtls_record rec; + + rec.buf = ssl->out_iv; + rec.buf_len = MBEDTLS_SSL_OUT_BUFFER_LEN - + ( ssl->out_iv - ssl->out_buf ); + rec.data_len = ssl->out_msglen; + rec.data_offset = ssl->out_msg - rec.buf; + + memcpy( &rec.ctr[0], ssl->out_ctr, 8 ); + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, rec.ver ); + rec.type = ssl->out_msgtype; + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + /* The CID is set by mbedtls_ssl_encrypt_buf(). */ + rec.cid_len = 0; +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + + if( ( ret = mbedtls_ssl_encrypt_buf( ssl, ssl->transform_out, &rec, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_encrypt_buf", ret ); + return( ret ); + } + + if( rec.data_offset != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* Update the record content type and CID. */ + ssl->out_msgtype = rec.type; +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID ) + memcpy( ssl->out_cid, rec.cid, rec.cid_len ); +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + ssl->out_msglen = len = rec.data_len; + ssl->out_len[0] = (unsigned char)( rec.data_len >> 8 ); + ssl->out_len[1] = (unsigned char)( rec.data_len ); + } + + protected_record_size = len + mbedtls_ssl_out_hdr_len( ssl ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + /* In case of DTLS, double-check that we don't exceed + * the remaining space in the datagram. */ + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ret = ssl_get_remaining_space_in_datagram( ssl ); + if( ret < 0 ) + return( ret ); + + if( protected_record_size > (size_t) ret ) + { + /* Should never happen */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + /* Now write the potentially updated record content type. */ + ssl->out_hdr[0] = (unsigned char) ssl->out_msgtype; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "output record: msgtype = %d, " + "version = [%d:%d], msglen = %d", + ssl->out_hdr[0], ssl->out_hdr[1], + ssl->out_hdr[2], len ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "output record sent to network", + ssl->out_hdr, protected_record_size ); + + ssl->out_left += protected_record_size; + ssl->out_hdr += protected_record_size; + ssl_update_out_pointers( ssl, ssl->transform_out ); + + for( i = 8; i > ssl_ep_len( ssl ); i-- ) + if( ++ssl->cur_out_ctr[i - 1] != 0 ) + break; + + /* The loop goes to its end iff the counter is wrapping */ + if( i == ssl_ep_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "outgoing message counter would wrap" ) ); + return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); + } + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + flush == SSL_DONT_FORCE_FLUSH ) + { + size_t remaining; + ret = ssl_get_remaining_payload_in_datagram( ssl ); + if( ret < 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_get_remaining_payload_in_datagram", + ret ); + return( ret ); + } + + remaining = (size_t) ret; + if( remaining == 0 ) + { + flush = SSL_FORCE_FLUSH; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Still %u bytes available in current datagram", (unsigned) remaining ) ); + } + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + if( ( flush == SSL_FORCE_FLUSH ) && + ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flush_output", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write record" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + +static int ssl_hs_is_proper_fragment( mbedtls_ssl_context *ssl ) +{ + if( ssl->in_msglen < ssl->in_hslen || + memcmp( ssl->in_msg + 6, "\0\0\0", 3 ) != 0 || + memcmp( ssl->in_msg + 9, ssl->in_msg + 1, 3 ) != 0 ) + { + return( 1 ); + } + return( 0 ); +} + +static uint32_t ssl_get_hs_frag_len( mbedtls_ssl_context const *ssl ) +{ + return( ( ssl->in_msg[9] << 16 ) | + ( ssl->in_msg[10] << 8 ) | + ssl->in_msg[11] ); +} + +static uint32_t ssl_get_hs_frag_off( mbedtls_ssl_context const *ssl ) +{ + return( ( ssl->in_msg[6] << 16 ) | + ( ssl->in_msg[7] << 8 ) | + ssl->in_msg[8] ); +} + +static int ssl_check_hs_header( mbedtls_ssl_context const *ssl ) +{ + uint32_t msg_len, frag_off, frag_len; + + msg_len = ssl_get_hs_total_len( ssl ); + frag_off = ssl_get_hs_frag_off( ssl ); + frag_len = ssl_get_hs_frag_len( ssl ); + + if( frag_off > msg_len ) + return( -1 ); + + if( frag_len > msg_len - frag_off ) + return( -1 ); + + if( frag_len + 12 > ssl->in_msglen ) + return( -1 ); + + return( 0 ); +} + +/* + * Mark bits in bitmask (used for DTLS HS reassembly) + */ +static void ssl_bitmask_set( unsigned char *mask, size_t offset, size_t len ) +{ + unsigned int start_bits, end_bits; + + start_bits = 8 - ( offset % 8 ); + if( start_bits != 8 ) + { + size_t first_byte_idx = offset / 8; + + /* Special case */ + if( len <= start_bits ) + { + for( ; len != 0; len-- ) + mask[first_byte_idx] |= 1 << ( start_bits - len ); + + /* Avoid potential issues with offset or len becoming invalid */ + return; + } + + offset += start_bits; /* Now offset % 8 == 0 */ + len -= start_bits; + + for( ; start_bits != 0; start_bits-- ) + mask[first_byte_idx] |= 1 << ( start_bits - 1 ); + } + + end_bits = len % 8; + if( end_bits != 0 ) + { + size_t last_byte_idx = ( offset + len ) / 8; + + len -= end_bits; /* Now len % 8 == 0 */ + + for( ; end_bits != 0; end_bits-- ) + mask[last_byte_idx] |= 1 << ( 8 - end_bits ); + } + + memset( mask + offset / 8, 0xFF, len / 8 ); +} + +/* + * Check that bitmask is full + */ +static int ssl_bitmask_check( unsigned char *mask, size_t len ) +{ + size_t i; + + for( i = 0; i < len / 8; i++ ) + if( mask[i] != 0xFF ) + return( -1 ); + + for( i = 0; i < len % 8; i++ ) + if( ( mask[len / 8] & ( 1 << ( 7 - i ) ) ) == 0 ) + return( -1 ); + + return( 0 ); +} + +/* msg_len does not include the handshake header */ +static size_t ssl_get_reassembly_buffer_size( size_t msg_len, + unsigned add_bitmap ) +{ + size_t alloc_len; + + alloc_len = 12; /* Handshake header */ + alloc_len += msg_len; /* Content buffer */ + + if( add_bitmap ) + alloc_len += msg_len / 8 + ( msg_len % 8 != 0 ); /* Bitmap */ + + return( alloc_len ); +} + +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl ) +{ + return( ( ssl->in_msg[1] << 16 ) | + ( ssl->in_msg[2] << 8 ) | + ssl->in_msg[3] ); +} + +int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ) +{ + if( ssl->in_msglen < mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake message too short: %d", + ssl->in_msglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + ssl->in_hslen = mbedtls_ssl_hs_hdr_len( ssl ) + ssl_get_hs_total_len( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "handshake message: msglen =" + " %d, type = %d, hslen = %d", + ssl->in_msglen, ssl->in_msg[0], ssl->in_hslen ) ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + int ret; + unsigned int recv_msg_seq = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5]; + + if( ssl_check_hs_header( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid handshake header" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + if( ssl->handshake != NULL && + ( ( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER && + recv_msg_seq != ssl->handshake->in_msg_seq ) || + ( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER && + ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) ) ) + { + if( recv_msg_seq > ssl->handshake->in_msg_seq ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received future handshake message of sequence number %u (next %u)", + recv_msg_seq, + ssl->handshake->in_msg_seq ) ); + return( MBEDTLS_ERR_SSL_EARLY_MESSAGE ); + } + + /* Retransmit only on last message from previous flight, to avoid + * too many retransmissions. + * Besides, No sane server ever retransmits HelloVerifyRequest */ + if( recv_msg_seq == ssl->handshake->in_flight_start_seq - 1 && + ssl->in_msg[0] != MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received message from last flight, " + "message_seq = %d, start_of_flight = %d", + recv_msg_seq, + ssl->handshake->in_flight_start_seq ) ); + + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_resend", ret ); + return( ret ); + } + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "dropping out-of-sequence message: " + "message_seq = %d, expected = %d", + recv_msg_seq, + ssl->handshake->in_msg_seq ) ); + } + + return( MBEDTLS_ERR_SSL_CONTINUE_PROCESSING ); + } + /* Wait until message completion to increment in_msg_seq */ + + /* Message reassembly is handled alongside buffering of future + * messages; the commonality is that both handshake fragments and + * future messages cannot be forwarded immediately to the + * handshake logic layer. */ + if( ssl_hs_is_proper_fragment( ssl ) == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "found fragmented DTLS handshake message" ) ); + return( MBEDTLS_ERR_SSL_EARLY_MESSAGE ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + /* With TLS we don't handle fragmentation (for now) */ + if( ssl->in_msglen < ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLS handshake fragmentation not supported" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + return( 0 ); +} + +void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER && hs != NULL ) + { + ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen ); + } + + /* Handshake message is complete, increment counter */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake != NULL ) + { + unsigned offset; + mbedtls_ssl_hs_buffer *hs_buf; + + /* Increment handshake sequence number */ + hs->in_msg_seq++; + + /* + * Clear up handshake buffering and reassembly structure. + */ + + /* Free first entry */ + ssl_buffering_free_slot( ssl, 0 ); + + /* Shift all other entries */ + for( offset = 0, hs_buf = &hs->buffering.hs[0]; + offset + 1 < MBEDTLS_SSL_MAX_BUFFERED_HS; + offset++, hs_buf++ ) + { + *hs_buf = *(hs_buf + 1); + } + + /* Create a fresh last entry */ + memset( hs_buf, 0, sizeof( mbedtls_ssl_hs_buffer ) ); + } +#endif +} + +/* + * DTLS anti-replay: RFC 6347 4.1.2.6 + * + * in_window is a field of bits numbered from 0 (lsb) to 63 (msb). + * Bit n is set iff record number in_window_top - n has been seen. + * + * Usually, in_window_top is the last record number seen and the lsb of + * in_window is set. The only exception is the initial state (record number 0 + * not seen yet). + */ +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +static void ssl_dtls_replay_reset( mbedtls_ssl_context *ssl ) +{ + ssl->in_window_top = 0; + ssl->in_window = 0; +} + +static inline uint64_t ssl_load_six_bytes( unsigned char *buf ) +{ + return( ( (uint64_t) buf[0] << 40 ) | + ( (uint64_t) buf[1] << 32 ) | + ( (uint64_t) buf[2] << 24 ) | + ( (uint64_t) buf[3] << 16 ) | + ( (uint64_t) buf[4] << 8 ) | + ( (uint64_t) buf[5] ) ); +} + +/* + * Return 0 if sequence number is acceptable, -1 otherwise + */ +int mbedtls_ssl_dtls_replay_check( mbedtls_ssl_context *ssl ) +{ + uint64_t rec_seqnum = ssl_load_six_bytes( ssl->in_ctr + 2 ); + uint64_t bit; + + if( ssl->conf->anti_replay == MBEDTLS_SSL_ANTI_REPLAY_DISABLED ) + return( 0 ); + + if( rec_seqnum > ssl->in_window_top ) + return( 0 ); + + bit = ssl->in_window_top - rec_seqnum; + + if( bit >= 64 ) + return( -1 ); + + if( ( ssl->in_window & ( (uint64_t) 1 << bit ) ) != 0 ) + return( -1 ); + + return( 0 ); +} + +/* + * Update replay window on new validated record + */ +void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl ) +{ + uint64_t rec_seqnum = ssl_load_six_bytes( ssl->in_ctr + 2 ); + + if( ssl->conf->anti_replay == MBEDTLS_SSL_ANTI_REPLAY_DISABLED ) + return; + + if( rec_seqnum > ssl->in_window_top ) + { + /* Update window_top and the contents of the window */ + uint64_t shift = rec_seqnum - ssl->in_window_top; + + if( shift >= 64 ) + ssl->in_window = 1; + else + { + ssl->in_window <<= shift; + ssl->in_window |= 1; + } + + ssl->in_window_top = rec_seqnum; + } + else + { + /* Mark that number as seen in the current window */ + uint64_t bit = ssl->in_window_top - rec_seqnum; + + if( bit < 64 ) /* Always true, but be extra sure */ + ssl->in_window |= (uint64_t) 1 << bit; + } +} +#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */ + +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C) +/* Forward declaration */ +static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ); + +/* + * Without any SSL context, check if a datagram looks like a ClientHello with + * a valid cookie, and if it doesn't, generate a HelloVerifyRequest message. + * Both input and output include full DTLS headers. + * + * - if cookie is valid, return 0 + * - if ClientHello looks superficially valid but cookie is not, + * fill obuf and set olen, then + * return MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED + * - otherwise return a specific error code + */ +static int ssl_check_dtls_clihlo_cookie( + mbedtls_ssl_cookie_write_t *f_cookie_write, + mbedtls_ssl_cookie_check_t *f_cookie_check, + void *p_cookie, + const unsigned char *cli_id, size_t cli_id_len, + const unsigned char *in, size_t in_len, + unsigned char *obuf, size_t buf_len, size_t *olen ) +{ + size_t sid_len, cookie_len; + unsigned char *p; + + if( f_cookie_write == NULL || f_cookie_check == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + /* + * Structure of ClientHello with record and handshake headers, + * and expected values. We don't need to check a lot, more checks will be + * done when actually parsing the ClientHello - skipping those checks + * avoids code duplication and does not make cookie forging any easier. + * + * 0-0 ContentType type; copied, must be handshake + * 1-2 ProtocolVersion version; copied + * 3-4 uint16 epoch; copied, must be 0 + * 5-10 uint48 sequence_number; copied + * 11-12 uint16 length; (ignored) + * + * 13-13 HandshakeType msg_type; (ignored) + * 14-16 uint24 length; (ignored) + * 17-18 uint16 message_seq; copied + * 19-21 uint24 fragment_offset; copied, must be 0 + * 22-24 uint24 fragment_length; (ignored) + * + * 25-26 ProtocolVersion client_version; (ignored) + * 27-58 Random random; (ignored) + * 59-xx SessionID session_id; 1 byte len + sid_len content + * 60+ opaque cookie<0..2^8-1>; 1 byte len + content + * ... + * + * Minimum length is 61 bytes. + */ + if( in_len < 61 || + in[0] != MBEDTLS_SSL_MSG_HANDSHAKE || + in[3] != 0 || in[4] != 0 || + in[19] != 0 || in[20] != 0 || in[21] != 0 ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + sid_len = in[59]; + if( sid_len > in_len - 61 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + cookie_len = in[60 + sid_len]; + if( cookie_len > in_len - 60 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + if( f_cookie_check( p_cookie, in + sid_len + 61, cookie_len, + cli_id, cli_id_len ) == 0 ) + { + /* Valid cookie */ + return( 0 ); + } + + /* + * If we get here, we've got an invalid cookie, let's prepare HVR. + * + * 0-0 ContentType type; copied + * 1-2 ProtocolVersion version; copied + * 3-4 uint16 epoch; copied + * 5-10 uint48 sequence_number; copied + * 11-12 uint16 length; olen - 13 + * + * 13-13 HandshakeType msg_type; hello_verify_request + * 14-16 uint24 length; olen - 25 + * 17-18 uint16 message_seq; copied + * 19-21 uint24 fragment_offset; copied + * 22-24 uint24 fragment_length; olen - 25 + * + * 25-26 ProtocolVersion server_version; 0xfe 0xff + * 27-27 opaque cookie<0..2^8-1>; cookie_len = olen - 27, cookie + * + * Minimum length is 28. + */ + if( buf_len < 28 ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + /* Copy most fields and adapt others */ + memcpy( obuf, in, 25 ); + obuf[13] = MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST; + obuf[25] = 0xfe; + obuf[26] = 0xff; + + /* Generate and write actual cookie */ + p = obuf + 28; + if( f_cookie_write( p_cookie, + &p, obuf + buf_len, cli_id, cli_id_len ) != 0 ) + { + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + *olen = p - obuf; + + /* Go back and fill length fields */ + obuf[27] = (unsigned char)( *olen - 28 ); + + obuf[14] = obuf[22] = (unsigned char)( ( *olen - 25 ) >> 16 ); + obuf[15] = obuf[23] = (unsigned char)( ( *olen - 25 ) >> 8 ); + obuf[16] = obuf[24] = (unsigned char)( ( *olen - 25 ) ); + + obuf[11] = (unsigned char)( ( *olen - 13 ) >> 8 ); + obuf[12] = (unsigned char)( ( *olen - 13 ) ); + + return( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ); +} + +/* + * Handle possible client reconnect with the same UDP quadruplet + * (RFC 6347 Section 4.2.8). + * + * Called by ssl_parse_record_header() in case we receive an epoch 0 record + * that looks like a ClientHello. + * + * - if the input looks like a ClientHello without cookies, + * send back HelloVerifyRequest, then + * return MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED + * - if the input looks like a ClientHello with a valid cookie, + * reset the session of the current context, and + * return MBEDTLS_ERR_SSL_CLIENT_RECONNECT + * - if anything goes wrong, return a specific error code + * + * mbedtls_ssl_read_record() will ignore the record if anything else than + * MBEDTLS_ERR_SSL_CLIENT_RECONNECT or 0 is returned, although this function + * cannot not return 0. + */ +static int ssl_handle_possible_reconnect( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t len; + + ret = ssl_check_dtls_clihlo_cookie( + ssl->conf->f_cookie_write, + ssl->conf->f_cookie_check, + ssl->conf->p_cookie, + ssl->cli_id, ssl->cli_id_len, + ssl->in_buf, ssl->in_left, + ssl->out_buf, MBEDTLS_SSL_OUT_CONTENT_LEN, &len ); + + MBEDTLS_SSL_DEBUG_RET( 2, "ssl_check_dtls_clihlo_cookie", ret ); + + if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ) + { + /* Don't check write errors as we can't do anything here. + * If the error is permanent we'll catch it later, + * if it's not, then hopefully it'll work next time. */ + (void) ssl->f_send( ssl->p_bio, ssl->out_buf, len ); + + return( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ); + } + + if( ret == 0 ) + { + /* Got a valid cookie, partially reset context */ + if( ( ret = ssl_session_reset_int( ssl, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "reset", ret ); + return( ret ); + } + + return( MBEDTLS_ERR_SSL_CLIENT_RECONNECT ); + } + + return( ret ); +} +#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */ + +static int ssl_check_record_type( uint8_t record_type ) +{ + if( record_type != MBEDTLS_SSL_MSG_HANDSHAKE && + record_type != MBEDTLS_SSL_MSG_ALERT && + record_type != MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC && + record_type != MBEDTLS_SSL_MSG_APPLICATION_DATA ) + { + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + return( 0 ); +} + +/* + * ContentType type; + * ProtocolVersion version; + * uint16 epoch; // DTLS only + * uint48 sequence_number; // DTLS only + * uint16 length; + * + * Return 0 if header looks sane (and, for DTLS, the record is expected) + * MBEDTLS_ERR_SSL_INVALID_RECORD if the header looks bad, + * MBEDTLS_ERR_SSL_UNEXPECTED_RECORD (DTLS only) if sane but unexpected. + * + * With DTLS, mbedtls_ssl_read_record() will: + * 1. proceed with the record if this function returns 0 + * 2. drop only the current record if this function returns UNEXPECTED_RECORD + * 3. return CLIENT_RECONNECT if this function return that value + * 4. drop the whole datagram if this function returns anything else. + * Point 2 is needed when the peer is resending, and we have already received + * the first record from a datagram but are still waiting for the others. + */ +static int ssl_parse_record_header( mbedtls_ssl_context *ssl ) +{ + int major_ver, minor_ver; + int ret; + + /* Parse and validate record content type and version */ + + ssl->in_msgtype = ssl->in_hdr[0]; + mbedtls_ssl_read_version( &major_ver, &minor_ver, ssl->conf->transport, ssl->in_hdr + 1 ); + + /* Check record type */ +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->in_msgtype == MBEDTLS_SSL_MSG_CID && + ssl->conf->cid_len != 0 ) + { + /* Shift pointers to account for record header including CID + * struct { + * ContentType special_type = tls12_cid; + * ProtocolVersion version; + * uint16 epoch; + * uint48 sequence_number; + * opaque cid[cid_length]; // Additional field compared to + * // default DTLS record format + * uint16 length; + * opaque enc_content[DTLSCiphertext.length]; + * } DTLSCiphertext; + */ + + /* So far, we only support static CID lengths + * fixed in the configuration. */ + ssl->in_len = ssl->in_cid + ssl->conf->cid_len; + ssl->in_iv = ssl->in_msg = ssl->in_len + 2; + } + else +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + if( ssl_check_record_type( ssl->in_msgtype ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "unknown record type" ) ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + /* Silently ignore invalid DTLS records as recommended by RFC 6347 + * Section 4.1.2.7 */ + if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM ) +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); + + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + /* Check version */ + if( major_ver != ssl->major_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "major version mismatch" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + if( minor_ver > ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "minor version mismatch" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + /* Now that the total length of the record header is known, ensure + * that the current datagram is large enough to hold it. + * This would fail, for example, if we received a datagram of + * size 13 + n Bytes where n is less than the size of incoming CIDs. */ + ret = mbedtls_ssl_fetch_input( ssl, mbedtls_ssl_in_hdr_len( ssl ) ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + MBEDTLS_SSL_DEBUG_BUF( 4, "input record header", ssl->in_hdr, mbedtls_ssl_in_hdr_len( ssl ) ); + + /* Parse and validate record length + * This must happen after the CID parsing because + * its position in the record header depends on + * the presence of a CID. */ + + ssl->in_msglen = ( ssl->in_len[0] << 8 ) | ssl->in_len[1]; + if( ssl->in_msglen > MBEDTLS_SSL_IN_BUFFER_LEN + - (size_t)( ssl->in_msg - ssl->in_buf ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "input record: msgtype = %d, " + "version = [%d:%d], msglen = %d", + ssl->in_msgtype, + major_ver, minor_ver, ssl->in_msglen ) ); + + /* + * DTLS-related tests. + * Check epoch before checking length constraint because + * the latter varies with the epoch. E.g., if a ChangeCipherSpec + * message gets duplicated before the corresponding Finished message, + * the second ChangeCipherSpec should be discarded because it belongs + * to an old epoch, but not because its length is shorter than + * the minimum record length for packets using the new record transform. + * Note that these two kinds of failures are handled differently, + * as an unexpected record is silently skipped but an invalid + * record leads to the entire datagram being dropped. + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + unsigned int rec_epoch = ( ssl->in_ctr[0] << 8 ) | ssl->in_ctr[1]; + + /* Check epoch (and sequence number) with DTLS */ + if( rec_epoch != ssl->in_epoch ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "record from another epoch: " + "expected %d, received %d", + ssl->in_epoch, rec_epoch ) ); + +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C) + /* + * Check for an epoch 0 ClientHello. We can't use in_msg here to + * access the first byte of record content (handshake type), as we + * have an active transform (possibly iv_len != 0), so use the + * fact that the record header len is 13 instead. + */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER && + rec_epoch == 0 && + ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_left > 13 && + ssl->in_buf[13] == MBEDTLS_SSL_HS_CLIENT_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "possible client reconnect " + "from the same port" ) ); + return( ssl_handle_possible_reconnect( ssl ) ); + } + else +#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */ + { + /* Consider buffering the record. */ + if( rec_epoch == (unsigned int) ssl->in_epoch + 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Consider record for buffering" ) ); + return( MBEDTLS_ERR_SSL_EARLY_MESSAGE ); + } + + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } + } + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + /* Replay detection only works for the current epoch */ + if( rec_epoch == ssl->in_epoch && + mbedtls_ssl_dtls_replay_check( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "replayed record" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } +#endif + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + + /* Check length against bounds of the current transform and version */ + if( ssl->transform_in == NULL ) + { + if( ssl->in_msglen < 1 || + ssl->in_msglen > MBEDTLS_SSL_IN_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + } + else + { + if( ssl->in_msglen < ssl->transform_in->minlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 && + ssl->in_msglen > ssl->transform_in->minlen + MBEDTLS_SSL_IN_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + /* + * TLS encrypted messages can have up to 256 bytes of padding + */ + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 && + ssl->in_msglen > ssl->transform_in->minlen + + MBEDTLS_SSL_IN_CONTENT_LEN + 256 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } +#endif + } + + return( 0 ); +} + +/* + * If applicable, decrypt (and decompress) record content + */ +static int ssl_prepare_record_content( mbedtls_ssl_context *ssl ) +{ + int ret, done = 0; + + MBEDTLS_SSL_DEBUG_BUF( 4, "input record from network", + ssl->in_hdr, mbedtls_ssl_in_hdr_len( ssl ) + ssl->in_msglen ); + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_read != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_read()" ) ); + + ret = mbedtls_ssl_hw_record_read( ssl ); + if( ret != 0 && ret != MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_read", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + + if( ret == 0 ) + done = 1; + } +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + if( !done && ssl->transform_in != NULL ) + { + mbedtls_record rec; + + rec.buf = ssl->in_iv; + rec.buf_len = MBEDTLS_SSL_IN_BUFFER_LEN + - ( ssl->in_iv - ssl->in_buf ); + rec.data_len = ssl->in_msglen; + rec.data_offset = 0; +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID ) + rec.cid_len = (uint8_t)( ssl->in_len - ssl->in_cid ); + memcpy( rec.cid, ssl->in_cid, rec.cid_len ); +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + + memcpy( &rec.ctr[0], ssl->in_ctr, 8 ); + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, rec.ver ); + rec.type = ssl->in_msgtype; + if( ( ret = mbedtls_ssl_decrypt_buf( ssl, ssl->transform_in, + &rec ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_decrypt_buf", ret ); + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + if( ret == MBEDTLS_ERR_SSL_UNEXPECTED_CID && + ssl->conf->ignore_unexpected_cid + == MBEDTLS_SSL_UNEXPECTED_CID_IGNORE ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ignoring unexpected CID" ) ); + ret = MBEDTLS_ERR_SSL_CONTINUE_PROCESSING; + } +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + + return( ret ); + } + + if( ssl->in_msgtype != rec.type ) + { + MBEDTLS_SSL_DEBUG_MSG( 4, ( "record type after decrypt (before %d): %d", + ssl->in_msgtype, rec.type ) ); + } + + /* The record content type may change during decryption, + * so re-read it. */ + ssl->in_msgtype = rec.type; + /* Also update the input buffer, because unfortunately + * the server-side ssl_parse_client_hello() reparses the + * record header when receiving a ClientHello initiating + * a renegotiation. */ + ssl->in_hdr[0] = rec.type; + ssl->in_msg = rec.buf + rec.data_offset; + ssl->in_msglen = rec.data_len; + ssl->in_len[0] = (unsigned char)( rec.data_len >> 8 ); + ssl->in_len[1] = (unsigned char)( rec.data_len ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "input payload after decrypt", + ssl->in_msg, ssl->in_msglen ); + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + /* We have already checked the record content type + * in ssl_parse_record_header(), failing or silently + * dropping the record in the case of an unknown type. + * + * Since with the use of CIDs, the record content type + * might change during decryption, re-check the record + * content type, but treat a failure as fatal this time. */ + if( ssl_check_record_type( ssl->in_msgtype ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "unknown record type" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + + if( ssl->in_msglen > MBEDTLS_SSL_IN_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + else if( ssl->in_msglen == 0 ) + { +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 + && ssl->in_msgtype != MBEDTLS_SSL_MSG_APPLICATION_DATA ) + { + /* TLS v1.2 explicitly disallows zero-length messages which are not application data */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid zero-length message type: %d", ssl->in_msgtype ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + ssl->nb_zero++; + + /* + * Three or more empty messages may be a DoS attack + * (excessive CPU consumption). + */ + if( ssl->nb_zero > 3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "received four consecutive empty " + "messages, possible DoS attack" ) ); + /* Treat the records as if they were not properly authenticated, + * thereby failing the connection if we see more than allowed + * by the configured bad MAC threshold. */ + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + } + else + ssl->nb_zero = 0; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ; /* in_ctr read from peer, not maintained internally */ + } + else +#endif + { + unsigned i; + for( i = 8; i > ssl_ep_len( ssl ); i-- ) + if( ++ssl->in_ctr[i - 1] != 0 ) + break; + + /* The loop goes to its end iff the counter is wrapping */ + if( i == ssl_ep_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "incoming message counter would wrap" ) ); + return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); + } + } + + } + +#if defined(MBEDTLS_ZLIB_SUPPORT) + if( ssl->transform_in != NULL && + ssl->session_in->compression == MBEDTLS_SSL_COMPRESS_DEFLATE ) + { + if( ( ret = ssl_decompress_buf( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_decompress_buf", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_ZLIB_SUPPORT */ + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + mbedtls_ssl_dtls_replay_update( ssl ); + } +#endif + + return( 0 ); +} + +static void ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl ); + +/* + * Read a record. + * + * Silently ignore non-fatal alert (and for DTLS, invalid records as well, + * RFC 6347 4.1.2.7) and continue reading until a valid record is found. + * + */ + +/* Helper functions for mbedtls_ssl_read_record(). */ +static int ssl_consume_current_message( mbedtls_ssl_context *ssl ); +static int ssl_get_next_record( mbedtls_ssl_context *ssl ); +static int ssl_record_is_in_progress( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl, + unsigned update_hs_digest ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read record" ) ); + + if( ssl->keep_current_message == 0 ) + { + do { + + ret = ssl_consume_current_message( ssl ); + if( ret != 0 ) + return( ret ); + + if( ssl_record_is_in_progress( ssl ) == 0 ) + { +#if defined(MBEDTLS_SSL_PROTO_DTLS) + int have_buffered = 0; + + /* We only check for buffered messages if the + * current datagram is fully consumed. */ + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl_next_record_is_in_datagram( ssl ) == 0 ) + { + if( ssl_load_buffered_message( ssl ) == 0 ) + have_buffered = 1; + } + + if( have_buffered == 0 ) +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + { + ret = ssl_get_next_record( ssl ); + if( ret == MBEDTLS_ERR_SSL_CONTINUE_PROCESSING ) + continue; + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_get_next_record" ), ret ); + return( ret ); + } + } + } + + ret = mbedtls_ssl_handle_message_type( ssl ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ret == MBEDTLS_ERR_SSL_EARLY_MESSAGE ) + { + /* Buffer future message */ + ret = ssl_buffer_message( ssl ); + if( ret != 0 ) + return( ret ); + + ret = MBEDTLS_ERR_SSL_CONTINUE_PROCESSING; + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + } while( MBEDTLS_ERR_SSL_NON_FATAL == ret || + MBEDTLS_ERR_SSL_CONTINUE_PROCESSING == ret ); + + if( 0 != ret ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_handle_message_type" ), ret ); + return( ret ); + } + + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + update_hs_digest == 1 ) + { + mbedtls_ssl_update_handshake_status( ssl ); + } + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "reuse previously read message" ) ); + ssl->keep_current_message = 0; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= read record" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +static int ssl_next_record_is_in_datagram( mbedtls_ssl_context *ssl ) +{ + if( ssl->in_left > ssl->next_record_offset ) + return( 1 ); + + return( 0 ); +} + +static int ssl_load_buffered_message( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + mbedtls_ssl_hs_buffer * hs_buf; + int ret = 0; + + if( hs == NULL ) + return( -1 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_load_buffered_messsage" ) ); + + if( ssl->state == MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC || + ssl->state == MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC ) + { + /* Check if we have seen a ChangeCipherSpec before. + * If yes, synthesize a CCS record. */ + if( !hs->buffering.seen_ccs ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "CCS not seen in the current flight" ) ); + ret = -1; + goto exit; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Injecting buffered CCS message" ) ); + ssl->in_msgtype = MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC; + ssl->in_msglen = 1; + ssl->in_msg[0] = 1; + + /* As long as they are equal, the exact value doesn't matter. */ + ssl->in_left = 0; + ssl->next_record_offset = 0; + + hs->buffering.seen_ccs = 0; + goto exit; + } + +#if defined(MBEDTLS_DEBUG_C) + /* Debug only */ + { + unsigned offset; + for( offset = 1; offset < MBEDTLS_SSL_MAX_BUFFERED_HS; offset++ ) + { + hs_buf = &hs->buffering.hs[offset]; + if( hs_buf->is_valid == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Future message with sequence number %u %s buffered.", + hs->in_msg_seq + offset, + hs_buf->is_complete ? "fully" : "partially" ) ); + } + } + } +#endif /* MBEDTLS_DEBUG_C */ + + /* Check if we have buffered and/or fully reassembled the + * next handshake message. */ + hs_buf = &hs->buffering.hs[0]; + if( ( hs_buf->is_valid == 1 ) && ( hs_buf->is_complete == 1 ) ) + { + /* Synthesize a record containing the buffered HS message. */ + size_t msg_len = ( hs_buf->data[1] << 16 ) | + ( hs_buf->data[2] << 8 ) | + hs_buf->data[3]; + + /* Double-check that we haven't accidentally buffered + * a message that doesn't fit into the input buffer. */ + if( msg_len + 12 > MBEDTLS_SSL_IN_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Next handshake message has been buffered - load" ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Buffered handshake message (incl. header)", + hs_buf->data, msg_len + 12 ); + + ssl->in_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->in_hslen = msg_len + 12; + ssl->in_msglen = msg_len + 12; + memcpy( ssl->in_msg, hs_buf->data, ssl->in_hslen ); + + ret = 0; + goto exit; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Next handshake message %u not or only partially bufffered", + hs->in_msg_seq ) ); + } + + ret = -1; + +exit: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_load_buffered_message" ) ); + return( ret ); +} + +static int ssl_buffer_make_space( mbedtls_ssl_context *ssl, + size_t desired ) +{ + int offset; + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Attempt to free buffered messages to have %u bytes available", + (unsigned) desired ) ); + + /* Get rid of future records epoch first, if such exist. */ + ssl_free_buffered_record( ssl ); + + /* Check if we have enough space available now. */ + if( desired <= ( MBEDTLS_SSL_DTLS_MAX_BUFFERING - + hs->buffering.total_bytes_buffered ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Enough space available after freeing future epoch record" ) ); + return( 0 ); + } + + /* We don't have enough space to buffer the next expected handshake + * message. Remove buffers used for future messages to gain space, + * starting with the most distant one. */ + for( offset = MBEDTLS_SSL_MAX_BUFFERED_HS - 1; + offset >= 0; offset-- ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Free buffering slot %d to make space for reassembly of next handshake message", + offset ) ); + + ssl_buffering_free_slot( ssl, (uint8_t) offset ); + + /* Check if we have enough space available now. */ + if( desired <= ( MBEDTLS_SSL_DTLS_MAX_BUFFERING - + hs->buffering.total_bytes_buffered ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Enough space available after freeing buffered HS messages" ) ); + return( 0 ); + } + } + + return( -1 ); +} + +static int ssl_buffer_message( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + + if( hs == NULL ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_buffer_message" ) ); + + switch( ssl->in_msgtype ) + { + case MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Remember CCS message" ) ); + + hs->buffering.seen_ccs = 1; + break; + + case MBEDTLS_SSL_MSG_HANDSHAKE: + { + unsigned recv_msg_seq_offset; + unsigned recv_msg_seq = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5]; + mbedtls_ssl_hs_buffer *hs_buf; + size_t msg_len = ssl->in_hslen - 12; + + /* We should never receive an old handshake + * message - double-check nonetheless. */ + if( recv_msg_seq < ssl->handshake->in_msg_seq ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + recv_msg_seq_offset = recv_msg_seq - ssl->handshake->in_msg_seq; + if( recv_msg_seq_offset >= MBEDTLS_SSL_MAX_BUFFERED_HS ) + { + /* Silently ignore -- message too far in the future */ + MBEDTLS_SSL_DEBUG_MSG( 2, + ( "Ignore future HS message with sequence number %u, " + "buffering window %u - %u", + recv_msg_seq, ssl->handshake->in_msg_seq, + ssl->handshake->in_msg_seq + MBEDTLS_SSL_MAX_BUFFERED_HS - 1 ) ); + + goto exit; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering HS message with sequence number %u, offset %u ", + recv_msg_seq, recv_msg_seq_offset ) ); + + hs_buf = &hs->buffering.hs[ recv_msg_seq_offset ]; + + /* Check if the buffering for this seq nr has already commenced. */ + if( !hs_buf->is_valid ) + { + size_t reassembly_buf_sz; + + hs_buf->is_fragmented = + ( ssl_hs_is_proper_fragment( ssl ) == 1 ); + + /* We copy the message back into the input buffer + * after reassembly, so check that it's not too large. + * This is an implementation-specific limitation + * and not one from the standard, hence it is not + * checked in ssl_check_hs_header(). */ + if( msg_len + 12 > MBEDTLS_SSL_IN_CONTENT_LEN ) + { + /* Ignore message */ + goto exit; + } + + /* Check if we have enough space to buffer the message. */ + if( hs->buffering.total_bytes_buffered > + MBEDTLS_SSL_DTLS_MAX_BUFFERING ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + reassembly_buf_sz = ssl_get_reassembly_buffer_size( msg_len, + hs_buf->is_fragmented ); + + if( reassembly_buf_sz > ( MBEDTLS_SSL_DTLS_MAX_BUFFERING - + hs->buffering.total_bytes_buffered ) ) + { + if( recv_msg_seq_offset > 0 ) + { + /* If we can't buffer a future message because + * of space limitations -- ignore. */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering of future message of size %u would exceed the compile-time limit %u (already %u bytes buffered) -- ignore\n", + (unsigned) msg_len, MBEDTLS_SSL_DTLS_MAX_BUFFERING, + (unsigned) hs->buffering.total_bytes_buffered ) ); + goto exit; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering of future message of size %u would exceed the compile-time limit %u (already %u bytes buffered) -- attempt to make space by freeing buffered future messages\n", + (unsigned) msg_len, MBEDTLS_SSL_DTLS_MAX_BUFFERING, + (unsigned) hs->buffering.total_bytes_buffered ) ); + } + + if( ssl_buffer_make_space( ssl, reassembly_buf_sz ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reassembly of next message of size %u (%u with bitmap) would exceed the compile-time limit %u (already %u bytes buffered) -- fail\n", + (unsigned) msg_len, + (unsigned) reassembly_buf_sz, + MBEDTLS_SSL_DTLS_MAX_BUFFERING, + (unsigned) hs->buffering.total_bytes_buffered ) ); + ret = MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL; + goto exit; + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialize reassembly, total length = %d", + msg_len ) ); + + hs_buf->data = mbedtls_calloc( 1, reassembly_buf_sz ); + if( hs_buf->data == NULL ) + { + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto exit; + } + hs_buf->data_len = reassembly_buf_sz; + + /* Prepare final header: copy msg_type, length and message_seq, + * then add standardised fragment_offset and fragment_length */ + memcpy( hs_buf->data, ssl->in_msg, 6 ); + memset( hs_buf->data + 6, 0, 3 ); + memcpy( hs_buf->data + 9, hs_buf->data + 1, 3 ); + + hs_buf->is_valid = 1; + + hs->buffering.total_bytes_buffered += reassembly_buf_sz; + } + else + { + /* Make sure msg_type and length are consistent */ + if( memcmp( hs_buf->data, ssl->in_msg, 4 ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Fragment header mismatch - ignore" ) ); + /* Ignore */ + goto exit; + } + } + + if( !hs_buf->is_complete ) + { + size_t frag_len, frag_off; + unsigned char * const msg = hs_buf->data + 12; + + /* + * Check and copy current fragment + */ + + /* Validation of header fields already done in + * mbedtls_ssl_prepare_handshake_record(). */ + frag_off = ssl_get_hs_frag_off( ssl ); + frag_len = ssl_get_hs_frag_len( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "adding fragment, offset = %d, length = %d", + frag_off, frag_len ) ); + memcpy( msg + frag_off, ssl->in_msg + 12, frag_len ); + + if( hs_buf->is_fragmented ) + { + unsigned char * const bitmask = msg + msg_len; + ssl_bitmask_set( bitmask, frag_off, frag_len ); + hs_buf->is_complete = ( ssl_bitmask_check( bitmask, + msg_len ) == 0 ); + } + else + { + hs_buf->is_complete = 1; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "message %scomplete", + hs_buf->is_complete ? "" : "not yet " ) ); + } + + break; + } + + default: + /* We don't buffer other types of messages. */ + break; + } + +exit: + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_buffer_message" ) ); + return( ret ); +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +static int ssl_consume_current_message( mbedtls_ssl_context *ssl ) +{ + /* + * Consume last content-layer message and potentially + * update in_msglen which keeps track of the contents' + * consumption state. + * + * (1) Handshake messages: + * Remove last handshake message, move content + * and adapt in_msglen. + * + * (2) Alert messages: + * Consume whole record content, in_msglen = 0. + * + * (3) Change cipher spec: + * Consume whole record content, in_msglen = 0. + * + * (4) Application data: + * Don't do anything - the record layer provides + * the application data as a stream transport + * and consumes through mbedtls_ssl_read only. + * + */ + + /* Case (1): Handshake messages */ + if( ssl->in_hslen != 0 ) + { + /* Hard assertion to be sure that no application data + * is in flight, as corrupting ssl->in_msglen during + * ssl->in_offt != NULL is fatal. */ + if( ssl->in_offt != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* + * Get next Handshake message in the current record + */ + + /* Notes: + * (1) in_hslen is not necessarily the size of the + * current handshake content: If DTLS handshake + * fragmentation is used, that's the fragment + * size instead. Using the total handshake message + * size here is faulty and should be changed at + * some point. + * (2) While it doesn't seem to cause problems, one + * has to be very careful not to assume that in_hslen + * is always <= in_msglen in a sensible communication. + * Again, it's wrong for DTLS handshake fragmentation. + * The following check is therefore mandatory, and + * should not be treated as a silently corrected assertion. + * Additionally, ssl->in_hslen might be arbitrarily out of + * bounds after handling a DTLS message with an unexpected + * sequence number, see mbedtls_ssl_prepare_handshake_record. + */ + if( ssl->in_hslen < ssl->in_msglen ) + { + ssl->in_msglen -= ssl->in_hslen; + memmove( ssl->in_msg, ssl->in_msg + ssl->in_hslen, + ssl->in_msglen ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "remaining content in record", + ssl->in_msg, ssl->in_msglen ); + } + else + { + ssl->in_msglen = 0; + } + + ssl->in_hslen = 0; + } + /* Case (4): Application data */ + else if( ssl->in_offt != NULL ) + { + return( 0 ); + } + /* Everything else (CCS & Alerts) */ + else + { + ssl->in_msglen = 0; + } + + return( 0 ); +} + +static int ssl_record_is_in_progress( mbedtls_ssl_context *ssl ) +{ + if( ssl->in_msglen > 0 ) + return( 1 ); + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + +static void ssl_free_buffered_record( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + if( hs == NULL ) + return; + + if( hs->buffering.future_record.data != NULL ) + { + hs->buffering.total_bytes_buffered -= + hs->buffering.future_record.len; + + mbedtls_free( hs->buffering.future_record.data ); + hs->buffering.future_record.data = NULL; + } +} + +static int ssl_load_buffered_record( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + unsigned char * rec; + size_t rec_len; + unsigned rec_epoch; + + if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( 0 ); + + if( hs == NULL ) + return( 0 ); + + rec = hs->buffering.future_record.data; + rec_len = hs->buffering.future_record.len; + rec_epoch = hs->buffering.future_record.epoch; + + if( rec == NULL ) + return( 0 ); + + /* Only consider loading future records if the + * input buffer is empty. */ + if( ssl_next_record_is_in_datagram( ssl ) == 1 ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_load_buffered_record" ) ); + + if( rec_epoch != ssl->in_epoch ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffered record not from current epoch." ) ); + goto exit; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Found buffered record from current epoch - load" ) ); + + /* Double-check that the record is not too large */ + if( rec_len > MBEDTLS_SSL_IN_BUFFER_LEN - + (size_t)( ssl->in_hdr - ssl->in_buf ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + memcpy( ssl->in_hdr, rec, rec_len ); + ssl->in_left = rec_len; + ssl->next_record_offset = 0; + + ssl_free_buffered_record( ssl ); + +exit: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_load_buffered_record" ) ); + return( 0 ); +} + +static int ssl_buffer_future_record( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + size_t const rec_hdr_len = 13; + size_t const total_buf_sz = rec_hdr_len + ssl->in_msglen; + + /* Don't buffer future records outside handshakes. */ + if( hs == NULL ) + return( 0 ); + + /* Only buffer handshake records (we are only interested + * in Finished messages). */ + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + return( 0 ); + + /* Don't buffer more than one future epoch record. */ + if( hs->buffering.future_record.data != NULL ) + return( 0 ); + + /* Don't buffer record if there's not enough buffering space remaining. */ + if( total_buf_sz > ( MBEDTLS_SSL_DTLS_MAX_BUFFERING - + hs->buffering.total_bytes_buffered ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering of future epoch record of size %u would exceed the compile-time limit %u (already %u bytes buffered) -- ignore\n", + (unsigned) total_buf_sz, MBEDTLS_SSL_DTLS_MAX_BUFFERING, + (unsigned) hs->buffering.total_bytes_buffered ) ); + return( 0 ); + } + + /* Buffer record */ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffer record from epoch %u", + ssl->in_epoch + 1 ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "Buffered record", ssl->in_hdr, + rec_hdr_len + ssl->in_msglen ); + + /* ssl_parse_record_header() only considers records + * of the next epoch as candidates for buffering. */ + hs->buffering.future_record.epoch = ssl->in_epoch + 1; + hs->buffering.future_record.len = total_buf_sz; + + hs->buffering.future_record.data = + mbedtls_calloc( 1, hs->buffering.future_record.len ); + if( hs->buffering.future_record.data == NULL ) + { + /* If we run out of RAM trying to buffer a + * record from the next epoch, just ignore. */ + return( 0 ); + } + + memcpy( hs->buffering.future_record.data, ssl->in_hdr, total_buf_sz ); + + hs->buffering.total_bytes_buffered += total_buf_sz; + return( 0 ); +} + +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +static int ssl_get_next_record( mbedtls_ssl_context *ssl ) +{ + int ret; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + /* We might have buffered a future record; if so, + * and if the epoch matches now, load it. + * On success, this call will set ssl->in_left to + * the length of the buffered record, so that + * the calls to ssl_fetch_input() below will + * essentially be no-ops. */ + ret = ssl_load_buffered_record( ssl ); + if( ret != 0 ) + return( ret ); +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + /* Reset in pointers to default state for TLS/DTLS records, + * assuming no CID and no offset between record content and + * record plaintext. */ + ssl_update_in_pointers( ssl ); + + /* Ensure that we have enough space available for the default form + * of TLS / DTLS record headers (5 Bytes for TLS, 13 Bytes for DTLS, + * with no space for CIDs counted in). */ + ret = mbedtls_ssl_fetch_input( ssl, mbedtls_ssl_in_hdr_len( ssl ) ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + + if( ( ret = ssl_parse_record_header( ssl ) ) != 0 ) + { +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ret != MBEDTLS_ERR_SSL_CLIENT_RECONNECT ) + { + if( ret == MBEDTLS_ERR_SSL_EARLY_MESSAGE ) + { + ret = ssl_buffer_future_record( ssl ); + if( ret != 0 ) + return( ret ); + + /* Fall through to handling of unexpected records */ + ret = MBEDTLS_ERR_SSL_UNEXPECTED_RECORD; + } + + if( ret == MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ) + { + /* Skip unexpected record (but not whole datagram) */ + ssl->next_record_offset = ssl->in_msglen + + mbedtls_ssl_in_hdr_len( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "discarding unexpected record " + "(header)" ) ); + } + else + { + /* Skip invalid record and the rest of the datagram */ + ssl->next_record_offset = 0; + ssl->in_left = 0; + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "discarding invalid record " + "(header)" ) ); + } + + /* Get next record */ + return( MBEDTLS_ERR_SSL_CONTINUE_PROCESSING ); + } +#endif + return( ret ); + } + + /* + * Read and optionally decrypt the message contents + */ + if( ( ret = mbedtls_ssl_fetch_input( ssl, + mbedtls_ssl_in_hdr_len( ssl ) + ssl->in_msglen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + + /* Done reading this record, get ready for the next one */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->next_record_offset = ssl->in_msglen + mbedtls_ssl_in_hdr_len( ssl ); + if( ssl->next_record_offset < ssl->in_left ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "more than one record within datagram" ) ); + } + } + else +#endif + ssl->in_left = 0; + + if( ( ret = ssl_prepare_record_content( ssl ) ) != 0 ) + { +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + /* Silently discard invalid records */ + if( ret == MBEDTLS_ERR_SSL_INVALID_MAC ) + { + /* Except when waiting for Finished as a bad mac here + * probably means something went wrong in the handshake + * (eg wrong psk used, mitm downgrade attempt, etc.) */ + if( ssl->state == MBEDTLS_SSL_CLIENT_FINISHED || + ssl->state == MBEDTLS_SSL_SERVER_FINISHED ) + { +#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) + if( ret == MBEDTLS_ERR_SSL_INVALID_MAC ) + { + mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC ); + } +#endif + return( ret ); + } + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) + if( ssl->conf->badmac_limit != 0 && + ++ssl->badmac_seen >= ssl->conf->badmac_limit ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "too many records with bad MAC" ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } +#endif + + /* As above, invalid records cause + * dismissal of the whole datagram. */ + + ssl->next_record_offset = 0; + ssl->in_left = 0; + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "discarding invalid record (mac)" ) ); + return( MBEDTLS_ERR_SSL_CONTINUE_PROCESSING ); + } + + return( ret ); + } + else +#endif + { + /* Error out (and send alert) on invalid records */ +#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) + if( ret == MBEDTLS_ERR_SSL_INVALID_MAC ) + { + mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC ); + } +#endif + return( ret ); + } + } + + return( 0 ); +} + +int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl ) +{ + int ret; + + /* + * Handle particular types of records + */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + { + if( ( ret = mbedtls_ssl_prepare_handshake_record( ssl ) ) != 0 ) + { + return( ret ); + } + } + + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) + { + if( ssl->in_msglen != 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid CCS message, len: %d", + ssl->in_msglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + if( ssl->in_msg[0] != 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid CCS message, content: %02x", + ssl->in_msg[0] ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->state != MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC && + ssl->state != MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC ) + { + if( ssl->handshake == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping ChangeCipherSpec outside handshake" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "received out-of-order ChangeCipherSpec - remember" ) ); + return( MBEDTLS_ERR_SSL_EARLY_MESSAGE ); + } +#endif + } + + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT ) + { + if( ssl->in_msglen != 2 ) + { + /* Note: Standard allows for more than one 2 byte alert + to be packed in a single message, but Mbed TLS doesn't + currently support this. */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid alert message, len: %d", + ssl->in_msglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "got an alert message, type: [%d:%d]", + ssl->in_msg[0], ssl->in_msg[1] ) ); + + /* + * Ignore non-fatal alerts, except close_notify and no_renegotiation + */ + if( ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_FATAL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "is a fatal alert message (msg %d)", + ssl->in_msg[1] ) ); + return( MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE ); + } + + if( ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "is a close notify message" ) ); + return( MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY ); + } + +#if defined(MBEDTLS_SSL_RENEGOTIATION_ENABLED) + if( ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "is a SSLv3 no renegotiation alert" ) ); + /* Will be handled when trying to parse ServerHello */ + return( 0 ); + } +#endif + +#if defined(MBEDTLS_SSL_PROTO_SSL3) && defined(MBEDTLS_SSL_SRV_C) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 && + ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_NO_CERT ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "is a SSLv3 no_cert" ) ); + /* Will be handled in mbedtls_ssl_parse_certificate() */ + return( 0 ); + } +#endif /* MBEDTLS_SSL_PROTO_SSL3 && MBEDTLS_SSL_SRV_C */ + + /* Silently ignore: fetch new message */ + return MBEDTLS_ERR_SSL_NON_FATAL; + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + /* Drop unexpected ApplicationData records, + * except at the beginning of renegotiations */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA && + ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER +#if defined(MBEDTLS_SSL_RENEGOTIATION) + && ! ( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->state == MBEDTLS_SSL_SERVER_HELLO ) +#endif + ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ApplicationData" ) ); + return( MBEDTLS_ERR_SSL_NON_FATAL ); + } + + if( ssl->handshake != NULL && + ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + { + ssl_handshake_wrapup_free_hs_transform( ssl ); + } + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + return( 0 ); +} + +int mbedtls_ssl_send_fatal_handshake_failure( mbedtls_ssl_context *ssl ) +{ + int ret; + + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl, + unsigned char level, + unsigned char message ) +{ + int ret; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> send alert message" ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "send alert level=%u message=%u", level, message )); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_ALERT; + ssl->out_msglen = 2; + ssl->out_msg[0] = level; + ssl->out_msg[1] = message; + + if( ( ret = mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= send alert message" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +static void ssl_clear_peer_cert( mbedtls_ssl_session *session ) +{ +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + if( session->peer_cert != NULL ) + { + mbedtls_x509_crt_free( session->peer_cert ); + mbedtls_free( session->peer_cert ); + session->peer_cert = NULL; + } +#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + if( session->peer_cert_digest != NULL ) + { + /* Zeroization is not necessary. */ + mbedtls_free( session->peer_cert_digest ); + session->peer_cert_digest = NULL; + session->peer_cert_digest_type = MBEDTLS_MD_NONE; + session->peer_cert_digest_len = 0; + } +#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/* + * Handshake functions + */ +#if !defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +/* No certificate support -> dummy functions */ +int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) ); + + if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} + +int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); + + if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} + +#else /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ +/* Some certificate support -> implement write and parse */ + +int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t i, n; + const mbedtls_x509_crt *crt; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) ); + + if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + ssl->state++; + return( 0 ); + } + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + if( ssl->client_auth == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + ssl->state++; + return( 0 ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + /* + * If using SSLv3 and got no cert, send an Alert message + * (otherwise an empty Certificate message will be sent). + */ + if( mbedtls_ssl_own_cert( ssl ) == NULL && + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl->out_msglen = 2; + ssl->out_msgtype = MBEDTLS_SSL_MSG_ALERT; + ssl->out_msg[0] = MBEDTLS_SSL_ALERT_LEVEL_WARNING; + ssl->out_msg[1] = MBEDTLS_SSL_ALERT_MSG_NO_CERT; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "got no certificate to send" ) ); + goto write_msg; + } +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + } +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( mbedtls_ssl_own_cert( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no certificate to send" ) ); + return( MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED ); + } + } +#endif + + MBEDTLS_SSL_DEBUG_CRT( 3, "own certificate", mbedtls_ssl_own_cert( ssl ) ); + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 6 length of all certs + * 7 . 9 length of cert. 1 + * 10 . n-1 peer certificate + * n . n+2 length of cert. 2 + * n+3 . ... upper level cert, etc. + */ + i = 7; + crt = mbedtls_ssl_own_cert( ssl ); + + while( crt != NULL ) + { + n = crt->raw.len; + if( n > MBEDTLS_SSL_OUT_CONTENT_LEN - 3 - i ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate too large, %d > %d", + i + 3 + n, MBEDTLS_SSL_OUT_CONTENT_LEN ) ); + return( MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE ); + } + + ssl->out_msg[i ] = (unsigned char)( n >> 16 ); + ssl->out_msg[i + 1] = (unsigned char)( n >> 8 ); + ssl->out_msg[i + 2] = (unsigned char)( n ); + + i += 3; memcpy( ssl->out_msg + i, crt->raw.p, n ); + i += n; crt = crt->next; + } + + ssl->out_msg[4] = (unsigned char)( ( i - 7 ) >> 16 ); + ssl->out_msg[5] = (unsigned char)( ( i - 7 ) >> 8 ); + ssl->out_msg[6] = (unsigned char)( ( i - 7 ) ); + + ssl->out_msglen = i; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE; + +#if defined(MBEDTLS_SSL_PROTO_SSL3) && defined(MBEDTLS_SSL_CLI_C) +write_msg: +#endif + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate" ) ); + + return( ret ); +} + +#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C) + +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) +static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl, + unsigned char *crt_buf, + size_t crt_buf_len ) +{ + mbedtls_x509_crt const * const peer_crt = ssl->session->peer_cert; + + if( peer_crt == NULL ) + return( -1 ); + + if( peer_crt->raw.len != crt_buf_len ) + return( -1 ); + + return( memcmp( peer_crt->raw.p, crt_buf, crt_buf_len ) ); +} +#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +static int ssl_check_peer_crt_unchanged( mbedtls_ssl_context *ssl, + unsigned char *crt_buf, + size_t crt_buf_len ) +{ + int ret; + unsigned char const * const peer_cert_digest = + ssl->session->peer_cert_digest; + mbedtls_md_type_t const peer_cert_digest_type = + ssl->session->peer_cert_digest_type; + mbedtls_md_info_t const * const digest_info = + mbedtls_md_info_from_type( peer_cert_digest_type ); + unsigned char tmp_digest[MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN]; + size_t digest_len; + + if( peer_cert_digest == NULL || digest_info == NULL ) + return( -1 ); + + digest_len = mbedtls_md_get_size( digest_info ); + if( digest_len > MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN ) + return( -1 ); + + ret = mbedtls_md( digest_info, crt_buf, crt_buf_len, tmp_digest ); + if( ret != 0 ) + return( -1 ); + + return( memcmp( tmp_digest, peer_cert_digest, digest_len ) ); +} +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */ + +/* + * Once the certificate message is read, parse it into a cert chain and + * perform basic checks, but leave actual verification to the caller + */ +static int ssl_parse_certificate_chain( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *chain ) +{ + int ret; +#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C) + int crt_cnt=0; +#endif + size_t i, n; + uint8_t alert; + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE || + ssl->in_hslen < mbedtls_ssl_hs_hdr_len( ssl ) + 3 + 3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + i = mbedtls_ssl_hs_hdr_len( ssl ); + + /* + * Same message structure as in mbedtls_ssl_write_certificate() + */ + n = ( ssl->in_msg[i+1] << 8 ) | ssl->in_msg[i+2]; + + if( ssl->in_msg[i] != 0 || + ssl->in_hslen != n + 3 + mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + /* Make &ssl->in_msg[i] point to the beginning of the CRT chain. */ + i += 3; + + /* Iterate through and parse the CRTs in the provided chain. */ + while( i < ssl->in_hslen ) + { + /* Check that there's room for the next CRT's length fields. */ + if ( i + 3 > ssl->in_hslen ) { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + /* In theory, the CRT can be up to 2**24 Bytes, but we don't support + * anything beyond 2**16 ~ 64K. */ + if( ssl->in_msg[i] != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + /* Read length of the next CRT in the chain. */ + n = ( (unsigned int) ssl->in_msg[i + 1] << 8 ) + | (unsigned int) ssl->in_msg[i + 2]; + i += 3; + + if( n < 128 || i + n > ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + /* Check if we're handling the first CRT in the chain. */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C) + if( crt_cnt++ == 0 && + ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + /* During client-side renegotiation, check that the server's + * end-CRTs hasn't changed compared to the initial handshake, + * mitigating the triple handshake attack. On success, reuse + * the original end-CRT instead of parsing it again. */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Check that peer CRT hasn't changed during renegotiation" ) ); + if( ssl_check_peer_crt_unchanged( ssl, + &ssl->in_msg[i], + n ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "new server cert during renegotiation" ) ); + mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + /* Now we can safely free the original chain. */ + ssl_clear_peer_cert( ssl->session ); + } +#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */ + + /* Parse the next certificate in the chain. */ +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + ret = mbedtls_x509_crt_parse_der( chain, ssl->in_msg + i, n ); +#else + /* If we don't need to store the CRT chain permanently, parse + * it in-place from the input buffer instead of making a copy. */ + ret = mbedtls_x509_crt_parse_der_nocopy( chain, ssl->in_msg + i, n ); +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + switch( ret ) + { + case 0: /*ok*/ + case MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + MBEDTLS_ERR_OID_NOT_FOUND: + /* Ignore certificate with an unknown algorithm: maybe a + prior certificate was already trusted. */ + break; + + case MBEDTLS_ERR_X509_ALLOC_FAILED: + alert = MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR; + goto crt_parse_der_failed; + + case MBEDTLS_ERR_X509_UNKNOWN_VERSION: + alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; + goto crt_parse_der_failed; + + default: + alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT; + crt_parse_der_failed: + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, alert ); + MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret ); + return( ret ); + } + + i += n; + } + + MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", chain ); + return( 0 ); +} + +#if defined(MBEDTLS_SSL_SRV_C) +static int ssl_srv_check_client_no_crt_notification( mbedtls_ssl_context *ssl ) +{ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + return( -1 ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + /* + * Check if the client sent an empty certificate + */ + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( ssl->in_msglen == 2 && + ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT && + ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_NO_CERT ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "SSLv3 client has no certificate" ) ); + return( 0 ); + } + + return( -1 ); + } +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->in_hslen == 3 + mbedtls_ssl_hs_hdr_len( ssl ) && + ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == MBEDTLS_SSL_HS_CERTIFICATE && + memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), "\0\0\0", 3 ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLSv1 client has no certificate" ) ); + return( 0 ); + } + + return( -1 ); +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +} +#endif /* MBEDTLS_SSL_SRV_C */ + +/* Check if a certificate message is expected. + * Return either + * - SSL_CERTIFICATE_EXPECTED, or + * - SSL_CERTIFICATE_SKIP + * indicating whether a Certificate message is expected or not. + */ +#define SSL_CERTIFICATE_EXPECTED 0 +#define SSL_CERTIFICATE_SKIP 1 +static int ssl_parse_certificate_coordinate( mbedtls_ssl_context *ssl, + int authmode ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + + if( !mbedtls_ssl_ciphersuite_uses_srv_cert( ciphersuite_info ) ) + return( SSL_CERTIFICATE_SKIP ); + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + return( SSL_CERTIFICATE_SKIP ); + + if( authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + ssl->session_negotiate->verify_result = + MBEDTLS_X509_BADCERT_SKIP_VERIFY; + return( SSL_CERTIFICATE_SKIP ); + } + } +#else + ((void) authmode); +#endif /* MBEDTLS_SSL_SRV_C */ + + return( SSL_CERTIFICATE_EXPECTED ); +} + +static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl, + int authmode, + mbedtls_x509_crt *chain, + void *rs_ctx ) +{ + int ret = 0; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->handshake->ciphersuite_info; + int have_ca_chain = 0; + + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *); + void *p_vrfy; + + if( authmode == MBEDTLS_SSL_VERIFY_NONE ) + return( 0 ); + + if( ssl->f_vrfy != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Use context-specific verification callback" ) ); + f_vrfy = ssl->f_vrfy; + p_vrfy = ssl->p_vrfy; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Use configuration-specific verification callback" ) ); + f_vrfy = ssl->conf->f_vrfy; + p_vrfy = ssl->conf->p_vrfy; + } + + /* + * Main check: verify certificate + */ +#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) + if( ssl->conf->f_ca_cb != NULL ) + { + ((void) rs_ctx); + have_ca_chain = 1; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "use CA callback for X.509 CRT verification" ) ); + ret = mbedtls_x509_crt_verify_with_ca_cb( + chain, + ssl->conf->f_ca_cb, + ssl->conf->p_ca_cb, + ssl->conf->cert_profile, + ssl->hostname, + &ssl->session_negotiate->verify_result, + f_vrfy, p_vrfy ); + } + else +#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ + { + mbedtls_x509_crt *ca_chain; + mbedtls_x509_crl *ca_crl; + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_ca_chain != NULL ) + { + ca_chain = ssl->handshake->sni_ca_chain; + ca_crl = ssl->handshake->sni_ca_crl; + } + else +#endif + { + ca_chain = ssl->conf->ca_chain; + ca_crl = ssl->conf->ca_crl; + } + + if( ca_chain != NULL ) + have_ca_chain = 1; + + ret = mbedtls_x509_crt_verify_restartable( + chain, + ca_chain, ca_crl, + ssl->conf->cert_profile, + ssl->hostname, + &ssl->session_negotiate->verify_result, + f_vrfy, p_vrfy, rs_ctx ); + } + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret ); + } + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + return( MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS ); +#endif + + /* + * Secondary checks: always done, but change 'ret' only if it was 0 + */ + +#if defined(MBEDTLS_ECP_C) + { + const mbedtls_pk_context *pk = &chain->pk; + + /* If certificate uses an EC key, make sure the curve is OK */ + if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) && + mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 ) + { + ssl->session_negotiate->verify_result |= MBEDTLS_X509_BADCERT_BAD_KEY; + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) ); + if( ret == 0 ) + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + } + } +#endif /* MBEDTLS_ECP_C */ + + if( mbedtls_ssl_check_cert_usage( chain, + ciphersuite_info, + ! ssl->conf->endpoint, + &ssl->session_negotiate->verify_result ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (usage extensions)" ) ); + if( ret == 0 ) + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + } + + /* mbedtls_x509_crt_verify_with_profile is supposed to report a + * verification failure through MBEDTLS_ERR_X509_CERT_VERIFY_FAILED, + * with details encoded in the verification flags. All other kinds + * of error codes, including those from the user provided f_vrfy + * functions, are treated as fatal and lead to a failure of + * ssl_parse_certificate even if verification was optional. */ + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL && + ( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED || + ret == MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ) ) + { + ret = 0; + } + + if( have_ca_chain == 0 && authmode == MBEDTLS_SSL_VERIFY_REQUIRED ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) ); + ret = MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED; + } + + if( ret != 0 ) + { + uint8_t alert; + + /* The certificate may have been rejected for several reasons. + Pick one and send the corresponding alert. Which alert to send + may be a subject of debate in some cases. */ + if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_OTHER ) + alert = MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_CN_MISMATCH ) + alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_KEY_USAGE ) + alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXT_KEY_USAGE ) + alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NS_CERT_TYPE ) + alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_PK ) + alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_BAD_KEY ) + alert = MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_EXPIRED ) + alert = MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_REVOKED ) + alert = MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED; + else if( ssl->session_negotiate->verify_result & MBEDTLS_X509_BADCERT_NOT_TRUSTED ) + alert = MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA; + else + alert = MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN; + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + alert ); + } + +#if defined(MBEDTLS_DEBUG_C) + if( ssl->session_negotiate->verify_result != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "! Certificate verification flags %x", + ssl->session_negotiate->verify_result ) ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Certificate verification flags clear" ) ); + } +#endif /* MBEDTLS_DEBUG_C */ + + return( ret ); +} + +#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) +static int ssl_remember_peer_crt_digest( mbedtls_ssl_context *ssl, + unsigned char *start, size_t len ) +{ + int ret; + /* Remember digest of the peer's end-CRT. */ + ssl->session_negotiate->peer_cert_digest = + mbedtls_calloc( 1, MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN ); + if( ssl->session_negotiate->peer_cert_digest == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", + sizeof( MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN ) ) ); + mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR ); + + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + ret = mbedtls_md( mbedtls_md_info_from_type( + MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE ), + start, len, + ssl->session_negotiate->peer_cert_digest ); + + ssl->session_negotiate->peer_cert_digest_type = + MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE; + ssl->session_negotiate->peer_cert_digest_len = + MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN; + + return( ret ); +} + +static int ssl_remember_peer_pubkey( mbedtls_ssl_context *ssl, + unsigned char *start, size_t len ) +{ + unsigned char *end = start + len; + int ret; + + /* Make a copy of the peer's raw public key. */ + mbedtls_pk_init( &ssl->handshake->peer_pubkey ); + ret = mbedtls_pk_parse_subpubkey( &start, end, + &ssl->handshake->peer_pubkey ); + if( ret != 0 ) + { + /* We should have parsed the public key before. */ + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + return( 0 ); +} +#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + +int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + int crt_expected; +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + const int authmode = ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET + ? ssl->handshake->sni_authmode + : ssl->conf->authmode; +#else + const int authmode = ssl->conf->authmode; +#endif + void *rs_ctx = NULL; + mbedtls_x509_crt *chain = NULL; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); + + crt_expected = ssl_parse_certificate_coordinate( ssl, authmode ); + if( crt_expected == SSL_CERTIFICATE_SKIP ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + goto exit; + } + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled && + ssl->handshake->ecrs_state == ssl_ecrs_crt_verify ) + { + chain = ssl->handshake->ecrs_peer_cert; + ssl->handshake->ecrs_peer_cert = NULL; + goto crt_verify; + } +#endif + + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) + { + /* mbedtls_ssl_read_record may have sent an alert already. We + let it decide whether to alert. */ + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + goto exit; + } + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl_srv_check_client_no_crt_notification( ssl ) == 0 ) + { + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; + + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + ret = 0; + else + ret = MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE; + + goto exit; + } +#endif /* MBEDTLS_SSL_SRV_C */ + + /* Clear existing peer CRT structure in case we tried to + * reuse a session but it failed, and allocate a new one. */ + ssl_clear_peer_cert( ssl->session_negotiate ); + + chain = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); + if( chain == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", + sizeof( mbedtls_x509_crt ) ) ); + mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR ); + + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto exit; + } + mbedtls_x509_crt_init( chain ); + + ret = ssl_parse_certificate_chain( ssl, chain ); + if( ret != 0 ) + goto exit; + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ssl->handshake->ecrs_enabled) + ssl->handshake->ecrs_state = ssl_ecrs_crt_verify; + +crt_verify: + if( ssl->handshake->ecrs_enabled) + rs_ctx = &ssl->handshake->ecrs_ctx; +#endif + + ret = ssl_parse_certificate_verify( ssl, authmode, + chain, rs_ctx ); + if( ret != 0 ) + goto exit; + +#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + { + unsigned char *crt_start, *pk_start; + size_t crt_len, pk_len; + + /* We parse the CRT chain without copying, so + * these pointers point into the input buffer, + * and are hence still valid after freeing the + * CRT chain. */ + + crt_start = chain->raw.p; + crt_len = chain->raw.len; + + pk_start = chain->pk_raw.p; + pk_len = chain->pk_raw.len; + + /* Free the CRT structures before computing + * digest and copying the peer's public key. */ + mbedtls_x509_crt_free( chain ); + mbedtls_free( chain ); + chain = NULL; + + ret = ssl_remember_peer_crt_digest( ssl, crt_start, crt_len ); + if( ret != 0 ) + goto exit; + + ret = ssl_remember_peer_pubkey( ssl, pk_start, pk_len ); + if( ret != 0 ) + goto exit; + } +#else /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + /* Pass ownership to session structure. */ + ssl->session_negotiate->peer_cert = chain; + chain = NULL; +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) ); + +exit: + + if( ret == 0 ) + ssl->state++; + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + if( ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS ) + { + ssl->handshake->ecrs_peer_cert = chain; + chain = NULL; + } +#endif + + if( chain != NULL ) + { + mbedtls_x509_crt_free( chain ); + mbedtls_free( chain ); + } + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write change cipher spec" ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC; + ssl->out_msglen = 1; + ssl->out_msg[0] = 1; + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write change cipher spec" ) ); + + return( 0 ); +} + +int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse change cipher spec" ) ); + + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* CCS records are only accepted if they have length 1 and content '1', + * so we don't need to check this here. */ + + /* + * Switch to our negotiated transform and session parameters for inbound + * data. + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "switching to new transform spec for inbound data" ) ); + ssl->transform_in = ssl->transform_negotiate; + ssl->session_in = ssl->session_negotiate; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + ssl_dtls_replay_reset( ssl ); +#endif + + /* Increment epoch */ + if( ++ssl->in_epoch == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "DTLS epoch would wrap" ) ); + /* This is highly unlikely to happen for legitimate reasons, so + treat it as an attack and don't send an alert. */ + return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + memset( ssl->in_ctr, 0, 8 ); + + ssl_update_in_pointers( ssl ); + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_activate != NULL ) + { + if( ( ret = mbedtls_ssl_hw_record_activate( ssl, MBEDTLS_SSL_CHANNEL_INBOUND ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_activate", ret ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif + + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse change cipher spec" ) ); + + return( 0 ); +} + +void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, + const mbedtls_ssl_ciphersuite_t *ciphersuite_info ) +{ + ((void) ciphersuite_info); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 ) + ssl->handshake->update_checksum = ssl_update_checksum_md5sha1; + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA512_C) + if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 ) + ssl->handshake->update_checksum = ssl_update_checksum_sha384; + else +#endif +#if defined(MBEDTLS_SHA256_C) + if( ciphersuite_info->mac != MBEDTLS_MD_SHA384 ) + ssl->handshake->update_checksum = ssl_update_checksum_sha256; + else +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return; + } +} + +void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_starts_ret( &ssl->handshake->fin_md5 ); + mbedtls_sha1_starts_ret( &ssl->handshake->fin_sha1 ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_hash_abort( &ssl->handshake->fin_sha256_psa ); + psa_hash_setup( &ssl->handshake->fin_sha256_psa, PSA_ALG_SHA_256 ); +#else + mbedtls_sha256_starts_ret( &ssl->handshake->fin_sha256, 0 ); +#endif +#endif +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_hash_abort( &ssl->handshake->fin_sha384_psa ); + psa_hash_setup( &ssl->handshake->fin_sha384_psa, PSA_ALG_SHA_384 ); +#else + mbedtls_sha512_starts_ret( &ssl->handshake->fin_sha512, 1 ); +#endif +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +} + +static void ssl_update_checksum_start( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_update_ret( &ssl->handshake->fin_md5 , buf, len ); + mbedtls_sha1_update_ret( &ssl->handshake->fin_sha1, buf, len ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_hash_update( &ssl->handshake->fin_sha256_psa, buf, len ); +#else + mbedtls_sha256_update_ret( &ssl->handshake->fin_sha256, buf, len ); +#endif +#endif +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_hash_update( &ssl->handshake->fin_sha384_psa, buf, len ); +#else + mbedtls_sha512_update_ret( &ssl->handshake->fin_sha512, buf, len ); +#endif +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +} + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) +static void ssl_update_checksum_md5sha1( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + mbedtls_md5_update_ret( &ssl->handshake->fin_md5 , buf, len ); + mbedtls_sha1_update_ret( &ssl->handshake->fin_sha1, buf, len ); +} +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +static void ssl_update_checksum_sha256( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ +#if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_hash_update( &ssl->handshake->fin_sha256_psa, buf, len ); +#else + mbedtls_sha256_update_ret( &ssl->handshake->fin_sha256, buf, len ); +#endif +} +#endif + +#if defined(MBEDTLS_SHA512_C) +static void ssl_update_checksum_sha384( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ +#if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_hash_update( &ssl->handshake->fin_sha384_psa, buf, len ); +#else + mbedtls_sha512_update_ret( &ssl->handshake->fin_sha512, buf, len ); +#endif +} +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +static void ssl_calc_finished_ssl( + mbedtls_ssl_context *ssl, unsigned char *buf, int from ) +{ + const char *sender; + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + + unsigned char padbuf[48]; + unsigned char md5sum[16]; + unsigned char sha1sum[20]; + + mbedtls_ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished ssl" ) ); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 ); + mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 ); + + /* + * SSLv3: + * hash = + * MD5( master + pad2 + + * MD5( handshake + sender + master + pad1 ) ) + * + SHA1( master + pad2 + + * SHA1( handshake + sender + master + pad1 ) ) + */ + +#if !defined(MBEDTLS_MD5_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished md5 state", (unsigned char *) + md5.state, sizeof( md5.state ) ); +#endif + +#if !defined(MBEDTLS_SHA1_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha1 state", (unsigned char *) + sha1.state, sizeof( sha1.state ) ); +#endif + + sender = ( from == MBEDTLS_SSL_IS_CLIENT ) ? "CLNT" + : "SRVR"; + + memset( padbuf, 0x36, 48 ); + + mbedtls_md5_update_ret( &md5, (const unsigned char *) sender, 4 ); + mbedtls_md5_update_ret( &md5, session->master, 48 ); + mbedtls_md5_update_ret( &md5, padbuf, 48 ); + mbedtls_md5_finish_ret( &md5, md5sum ); + + mbedtls_sha1_update_ret( &sha1, (const unsigned char *) sender, 4 ); + mbedtls_sha1_update_ret( &sha1, session->master, 48 ); + mbedtls_sha1_update_ret( &sha1, padbuf, 40 ); + mbedtls_sha1_finish_ret( &sha1, sha1sum ); + + memset( padbuf, 0x5C, 48 ); + + mbedtls_md5_starts_ret( &md5 ); + mbedtls_md5_update_ret( &md5, session->master, 48 ); + mbedtls_md5_update_ret( &md5, padbuf, 48 ); + mbedtls_md5_update_ret( &md5, md5sum, 16 ); + mbedtls_md5_finish_ret( &md5, buf ); + + mbedtls_sha1_starts_ret( &sha1 ); + mbedtls_sha1_update_ret( &sha1, session->master, 48 ); + mbedtls_sha1_update_ret( &sha1, padbuf , 40 ); + mbedtls_sha1_update_ret( &sha1, sha1sum, 20 ); + mbedtls_sha1_finish_ret( &sha1, buf + 16 ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, 36 ); + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) ); + mbedtls_platform_zeroize( md5sum, sizeof( md5sum ) ); + mbedtls_platform_zeroize( sha1sum, sizeof( sha1sum ) ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) +static void ssl_calc_finished_tls( + mbedtls_ssl_context *ssl, unsigned char *buf, int from ) +{ + int len = 12; + const char *sender; + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + unsigned char padbuf[36]; + + mbedtls_ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished tls" ) ); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 ); + mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 ); + + /* + * TLSv1: + * hash = PRF( master, finished_label, + * MD5( handshake ) + SHA1( handshake ) )[0..11] + */ + +#if !defined(MBEDTLS_MD5_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished md5 state", (unsigned char *) + md5.state, sizeof( md5.state ) ); +#endif + +#if !defined(MBEDTLS_SHA1_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha1 state", (unsigned char *) + sha1.state, sizeof( sha1.state ) ); +#endif + + sender = ( from == MBEDTLS_SSL_IS_CLIENT ) + ? "client finished" + : "server finished"; + + mbedtls_md5_finish_ret( &md5, padbuf ); + mbedtls_sha1_finish_ret( &sha1, padbuf + 16 ); + + ssl->handshake->tls_prf( session->master, 48, sender, + padbuf, 36, buf, len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +static void ssl_calc_finished_tls_sha256( + mbedtls_ssl_context *ssl, unsigned char *buf, int from ) +{ + int len = 12; + const char *sender; + unsigned char padbuf[32]; +#if defined(MBEDTLS_USE_PSA_CRYPTO) + size_t hash_size; + psa_hash_operation_t sha256_psa = PSA_HASH_OPERATION_INIT; + psa_status_t status; +#else + mbedtls_sha256_context sha256; +#endif + + mbedtls_ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + sender = ( from == MBEDTLS_SSL_IS_CLIENT ) + ? "client finished" + : "server finished"; + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + sha256_psa = psa_hash_operation_init(); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc PSA finished tls sha256" ) ); + + status = psa_hash_clone( &ssl->handshake->fin_sha256_psa, &sha256_psa ); + if( status != PSA_SUCCESS ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash clone failed" ) ); + return; + } + + status = psa_hash_finish( &sha256_psa, padbuf, sizeof( padbuf ), &hash_size ); + if( status != PSA_SUCCESS ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash finish failed" ) ); + return; + } + MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated padbuf", padbuf, 32 ); +#else + + mbedtls_sha256_init( &sha256 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished tls sha256" ) ); + + mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 ); + + /* + * TLSv1.2: + * hash = PRF( master, finished_label, + * Hash( handshake ) )[0.11] + */ + +#if !defined(MBEDTLS_SHA256_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha2 state", (unsigned char *) + sha256.state, sizeof( sha256.state ) ); +#endif + + mbedtls_sha256_finish_ret( &sha256, padbuf ); + mbedtls_sha256_free( &sha256 ); +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + + ssl->handshake->tls_prf( session->master, 48, sender, + padbuf, 32, buf, len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +static void ssl_calc_finished_tls_sha384( + mbedtls_ssl_context *ssl, unsigned char *buf, int from ) +{ + int len = 12; + const char *sender; + unsigned char padbuf[48]; +#if defined(MBEDTLS_USE_PSA_CRYPTO) + size_t hash_size; + psa_hash_operation_t sha384_psa = PSA_HASH_OPERATION_INIT; + psa_status_t status; +#else + mbedtls_sha512_context sha512; +#endif + + mbedtls_ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + sender = ( from == MBEDTLS_SSL_IS_CLIENT ) + ? "client finished" + : "server finished"; + +#if defined(MBEDTLS_USE_PSA_CRYPTO) + sha384_psa = psa_hash_operation_init(); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc PSA finished tls sha384" ) ); + + status = psa_hash_clone( &ssl->handshake->fin_sha384_psa, &sha384_psa ); + if( status != PSA_SUCCESS ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash clone failed" ) ); + return; + } + + status = psa_hash_finish( &sha384_psa, padbuf, sizeof( padbuf ), &hash_size ); + if( status != PSA_SUCCESS ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash finish failed" ) ); + return; + } + MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated padbuf", padbuf, 48 ); +#else + mbedtls_sha512_init( &sha512 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished tls sha384" ) ); + + mbedtls_sha512_clone( &sha512, &ssl->handshake->fin_sha512 ); + + /* + * TLSv1.2: + * hash = PRF( master, finished_label, + * Hash( handshake ) )[0.11] + */ + +#if !defined(MBEDTLS_SHA512_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha512 state", (unsigned char *) + sha512.state, sizeof( sha512.state ) ); +#endif + + mbedtls_sha512_finish_ret( &sha512, padbuf ); + mbedtls_sha512_free( &sha512 ); +#endif + + ssl->handshake->tls_prf( session->master, 48, sender, + padbuf, 48, buf, len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + mbedtls_platform_zeroize( padbuf, sizeof( padbuf ) ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +static void ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl ) +{ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "=> handshake wrapup: final free" ) ); + + /* + * Free our handshake params + */ + mbedtls_ssl_handshake_free( ssl ); + mbedtls_free( ssl->handshake ); + ssl->handshake = NULL; + + /* + * Free the previous transform and swith in the current one + */ + if( ssl->transform ) + { + mbedtls_ssl_transform_free( ssl->transform ); + mbedtls_free( ssl->transform ); + } + ssl->transform = ssl->transform_negotiate; + ssl->transform_negotiate = NULL; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= handshake wrapup: final free" ) ); +} + +void mbedtls_ssl_handshake_wrapup( mbedtls_ssl_context *ssl ) +{ + int resume = ssl->handshake->resume; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_DONE; + ssl->renego_records_seen = 0; + } +#endif + + /* + * Free the previous session and switch in the current one + */ + if( ssl->session ) + { +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + /* RFC 7366 3.1: keep the EtM state */ + ssl->session_negotiate->encrypt_then_mac = + ssl->session->encrypt_then_mac; +#endif + + mbedtls_ssl_session_free( ssl->session ); + mbedtls_free( ssl->session ); + } + ssl->session = ssl->session_negotiate; + ssl->session_negotiate = NULL; + + /* + * Add cache entry + */ + if( ssl->conf->f_set_cache != NULL && + ssl->session->id_len != 0 && + resume == 0 ) + { + if( ssl->conf->f_set_cache( ssl->conf->p_cache, ssl->session ) != 0 ) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "cache did not store session" ) ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->flight != NULL ) + { + /* Cancel handshake timer */ + ssl_set_timer( ssl, 0 ); + + /* Keep last flight around in case we need to resend it: + * we need the handshake and transform structures for that */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip freeing handshake and transform" ) ); + } + else +#endif + ssl_handshake_wrapup_free_hs_transform( ssl ); + + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= handshake wrapup" ) ); +} + +int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl ) +{ + int ret, hash_len; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write finished" ) ); + + ssl_update_out_pointers( ssl, ssl->transform_negotiate ); + + ssl->handshake->calc_finished( ssl, ssl->out_msg + 4, ssl->conf->endpoint ); + + /* + * RFC 5246 7.4.9 (Page 63) says 12 is the default length and ciphersuites + * may define some other value. Currently (early 2016), no defined + * ciphersuite does this (and this is unlikely to change as activity has + * moved to TLS 1.3 now) so we can keep the hardcoded 12 here. + */ + hash_len = ( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) ? 36 : 12; + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->verify_data_len = hash_len; + memcpy( ssl->own_verify_data, ssl->out_msg + 4, hash_len ); +#endif + + ssl->out_msglen = 4 + hash_len; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_FINISHED; + + /* + * In case of session resuming, invert the client and server + * ChangeCipherSpec messages order. + */ + if( ssl->handshake->resume != 0 ) + { +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP; +#endif +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + ssl->state = MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC; +#endif + } + else + ssl->state++; + + /* + * Switch to our negotiated transform and session parameters for outbound + * data. + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "switching to new transform spec for outbound data" ) ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + unsigned char i; + + /* Remember current epoch settings for resending */ + ssl->handshake->alt_transform_out = ssl->transform_out; + memcpy( ssl->handshake->alt_out_ctr, ssl->cur_out_ctr, 8 ); + + /* Set sequence_number to zero */ + memset( ssl->cur_out_ctr + 2, 0, 6 ); + + /* Increment epoch */ + for( i = 2; i > 0; i-- ) + if( ++ssl->cur_out_ctr[i - 1] != 0 ) + break; + + /* The loop goes to its end iff the counter is wrapping */ + if( i == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "DTLS epoch would wrap" ) ); + return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + memset( ssl->cur_out_ctr, 0, 8 ); + + ssl->transform_out = ssl->transform_negotiate; + ssl->session_out = ssl->session_negotiate; + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_activate != NULL ) + { + if( ( ret = mbedtls_ssl_hw_record_activate( ssl, MBEDTLS_SSL_CHANNEL_OUTBOUND ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_activate", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_send_flight_completed( ssl ); +#endif + + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret ); + return( ret ); + } +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write finished" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +#define SSL_MAX_HASH_LEN 36 +#else +#define SSL_MAX_HASH_LEN 12 +#endif + +int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned int hash_len; + unsigned char buf[SSL_MAX_HASH_LEN]; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse finished" ) ); + + ssl->handshake->calc_finished( ssl, buf, ssl->conf->endpoint ^ 1 ); + + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* There is currently no ciphersuite using another length with TLS 1.2 */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + hash_len = 36; + else +#endif + hash_len = 12; + + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_FINISHED || + ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) + hash_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); + } + + if( mbedtls_ssl_safer_memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), + buf, hash_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); + } + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->verify_data_len = hash_len; + memcpy( ssl->peer_verify_data, buf, hash_len ); +#endif + + if( ssl->handshake->resume != 0 ) + { +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + ssl->state = MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC; +#endif +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP; +#endif + } + else + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_recv_flight_completed( ssl ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse finished" ) ); + + return( 0 ); +} + +static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake ) +{ + memset( handshake, 0, sizeof( mbedtls_ssl_handshake_params ) ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_init( &handshake->fin_md5 ); + mbedtls_sha1_init( &handshake->fin_sha1 ); + mbedtls_md5_starts_ret( &handshake->fin_md5 ); + mbedtls_sha1_starts_ret( &handshake->fin_sha1 ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_USE_PSA_CRYPTO) + handshake->fin_sha256_psa = psa_hash_operation_init(); + psa_hash_setup( &handshake->fin_sha256_psa, PSA_ALG_SHA_256 ); +#else + mbedtls_sha256_init( &handshake->fin_sha256 ); + mbedtls_sha256_starts_ret( &handshake->fin_sha256, 0 ); +#endif +#endif +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_USE_PSA_CRYPTO) + handshake->fin_sha384_psa = psa_hash_operation_init(); + psa_hash_setup( &handshake->fin_sha384_psa, PSA_ALG_SHA_384 ); +#else + mbedtls_sha512_init( &handshake->fin_sha512 ); + mbedtls_sha512_starts_ret( &handshake->fin_sha512, 1 ); +#endif +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + handshake->update_checksum = ssl_update_checksum_start; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + mbedtls_ssl_sig_hash_set_init( &handshake->hash_algs ); +#endif + +#if defined(MBEDTLS_DHM_C) + mbedtls_dhm_init( &handshake->dhm_ctx ); +#endif +#if defined(MBEDTLS_ECDH_C) + mbedtls_ecdh_init( &handshake->ecdh_ctx ); +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + mbedtls_ecjpake_init( &handshake->ecjpake_ctx ); +#if defined(MBEDTLS_SSL_CLI_C) + handshake->ecjpake_cache = NULL; + handshake->ecjpake_cache_len = 0; +#endif +#endif + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + mbedtls_x509_crt_restart_init( &handshake->ecrs_ctx ); +#endif + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + handshake->sni_authmode = MBEDTLS_SSL_VERIFY_UNSET; +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + mbedtls_pk_init( &handshake->peer_pubkey ); +#endif +} + +void mbedtls_ssl_transform_init( mbedtls_ssl_transform *transform ) +{ + memset( transform, 0, sizeof(mbedtls_ssl_transform) ); + + mbedtls_cipher_init( &transform->cipher_ctx_enc ); + mbedtls_cipher_init( &transform->cipher_ctx_dec ); + +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) + mbedtls_md_init( &transform->md_ctx_enc ); + mbedtls_md_init( &transform->md_ctx_dec ); +#endif +} + +void mbedtls_ssl_session_init( mbedtls_ssl_session *session ) +{ + memset( session, 0, sizeof(mbedtls_ssl_session) ); +} + +static int ssl_handshake_init( mbedtls_ssl_context *ssl ) +{ + /* Clear old handshake information if present */ + if( ssl->transform_negotiate ) + mbedtls_ssl_transform_free( ssl->transform_negotiate ); + if( ssl->session_negotiate ) + mbedtls_ssl_session_free( ssl->session_negotiate ); + if( ssl->handshake ) + mbedtls_ssl_handshake_free( ssl ); + + /* + * Either the pointers are now NULL or cleared properly and can be freed. + * Now allocate missing structures. + */ + if( ssl->transform_negotiate == NULL ) + { + ssl->transform_negotiate = mbedtls_calloc( 1, sizeof(mbedtls_ssl_transform) ); + } + + if( ssl->session_negotiate == NULL ) + { + ssl->session_negotiate = mbedtls_calloc( 1, sizeof(mbedtls_ssl_session) ); + } + + if( ssl->handshake == NULL ) + { + ssl->handshake = mbedtls_calloc( 1, sizeof(mbedtls_ssl_handshake_params) ); + } + + /* All pointers should exist and can be directly freed without issue */ + if( ssl->handshake == NULL || + ssl->transform_negotiate == NULL || + ssl->session_negotiate == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc() of ssl sub-contexts failed" ) ); + + mbedtls_free( ssl->handshake ); + mbedtls_free( ssl->transform_negotiate ); + mbedtls_free( ssl->session_negotiate ); + + ssl->handshake = NULL; + ssl->transform_negotiate = NULL; + ssl->session_negotiate = NULL; + + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + /* Initialize structures */ + mbedtls_ssl_session_init( ssl->session_negotiate ); + mbedtls_ssl_transform_init( ssl->transform_negotiate ); + ssl_handshake_params_init( ssl->handshake ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->handshake->alt_transform_out = ssl->transform_out; + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_PREPARING; + else + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_WAITING; + + ssl_set_timer( ssl, 0 ); + } +#endif + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) +/* Dummy cookie callbacks for defaults */ +static int ssl_cookie_write_dummy( void *ctx, + unsigned char **p, unsigned char *end, + const unsigned char *cli_id, size_t cli_id_len ) +{ + ((void) ctx); + ((void) p); + ((void) end); + ((void) cli_id); + ((void) cli_id_len); + + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +} + +static int ssl_cookie_check_dummy( void *ctx, + const unsigned char *cookie, size_t cookie_len, + const unsigned char *cli_id, size_t cli_id_len ) +{ + ((void) ctx); + ((void) cookie); + ((void) cookie_len); + ((void) cli_id); + ((void) cli_id_len); + + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +} +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */ + +/* Once ssl->out_hdr as the address of the beginning of the + * next outgoing record is set, deduce the other pointers. + * + * Note: For TLS, we save the implicit record sequence number + * (entering MAC computation) in the 8 bytes before ssl->out_hdr, + * and the caller has to make sure there's space for this. + */ + +static void ssl_update_out_pointers( mbedtls_ssl_context *ssl, + mbedtls_ssl_transform *transform ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->out_ctr = ssl->out_hdr + 3; +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + ssl->out_cid = ssl->out_ctr + 8; + ssl->out_len = ssl->out_cid; + if( transform != NULL ) + ssl->out_len += transform->out_cid_len; +#else /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + ssl->out_len = ssl->out_ctr + 8; +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + ssl->out_iv = ssl->out_len + 2; + } + else +#endif + { + ssl->out_ctr = ssl->out_hdr - 8; + ssl->out_len = ssl->out_hdr + 3; +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + ssl->out_cid = ssl->out_len; +#endif + ssl->out_iv = ssl->out_hdr + 5; + } + + /* Adjust out_msg to make space for explicit IV, if used. */ + if( transform != NULL && + ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + ssl->out_msg = ssl->out_iv + transform->ivlen - transform->fixed_ivlen; + } + else + ssl->out_msg = ssl->out_iv; +} + +/* Once ssl->in_hdr as the address of the beginning of the + * next incoming record is set, deduce the other pointers. + * + * Note: For TLS, we save the implicit record sequence number + * (entering MAC computation) in the 8 bytes before ssl->in_hdr, + * and the caller has to make sure there's space for this. + */ + +static void ssl_update_in_pointers( mbedtls_ssl_context *ssl ) +{ + /* This function sets the pointers to match the case + * of unprotected TLS/DTLS records, with both ssl->in_iv + * and ssl->in_msg pointing to the beginning of the record + * content. + * + * When decrypting a protected record, ssl->in_msg + * will be shifted to point to the beginning of the + * record plaintext. + */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + /* This sets the header pointers to match records + * without CID. When we receive a record containing + * a CID, the fields are shifted accordingly in + * ssl_parse_record_header(). */ + ssl->in_ctr = ssl->in_hdr + 3; +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + ssl->in_cid = ssl->in_ctr + 8; + ssl->in_len = ssl->in_cid; /* Default: no CID */ +#else /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + ssl->in_len = ssl->in_ctr + 8; +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + ssl->in_iv = ssl->in_len + 2; + } + else +#endif + { + ssl->in_ctr = ssl->in_hdr - 8; + ssl->in_len = ssl->in_hdr + 3; +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + ssl->in_cid = ssl->in_len; +#endif + ssl->in_iv = ssl->in_hdr + 5; + } + + /* This will be adjusted at record decryption time. */ + ssl->in_msg = ssl->in_iv; +} + +/* + * Initialize an SSL context + */ +void mbedtls_ssl_init( mbedtls_ssl_context *ssl ) +{ + memset( ssl, 0, sizeof( mbedtls_ssl_context ) ); +} + +/* + * Setup an SSL context + */ + +static void ssl_reset_in_out_pointers( mbedtls_ssl_context *ssl ) +{ + /* Set the incoming and outgoing record pointers. */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->out_hdr = ssl->out_buf; + ssl->in_hdr = ssl->in_buf; + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + { + ssl->out_hdr = ssl->out_buf + 8; + ssl->in_hdr = ssl->in_buf + 8; + } + + /* Derive other internal pointers. */ + ssl_update_out_pointers( ssl, NULL /* no transform enabled */ ); + ssl_update_in_pointers ( ssl ); +} + +int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, + const mbedtls_ssl_config *conf ) +{ + int ret; + + ssl->conf = conf; + + /* + * Prepare base structures + */ + + /* Set to NULL in case of an error condition */ + ssl->out_buf = NULL; + + ssl->in_buf = mbedtls_calloc( 1, MBEDTLS_SSL_IN_BUFFER_LEN ); + if( ssl->in_buf == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", MBEDTLS_SSL_IN_BUFFER_LEN) ); + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto error; + } + + ssl->out_buf = mbedtls_calloc( 1, MBEDTLS_SSL_OUT_BUFFER_LEN ); + if( ssl->out_buf == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", MBEDTLS_SSL_OUT_BUFFER_LEN) ); + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto error; + } + + ssl_reset_in_out_pointers( ssl ); + + if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) + goto error; + + return( 0 ); + +error: + mbedtls_free( ssl->in_buf ); + mbedtls_free( ssl->out_buf ); + + ssl->conf = NULL; + + ssl->in_buf = NULL; + ssl->out_buf = NULL; + + ssl->in_hdr = NULL; + ssl->in_ctr = NULL; + ssl->in_len = NULL; + ssl->in_iv = NULL; + ssl->in_msg = NULL; + + ssl->out_hdr = NULL; + ssl->out_ctr = NULL; + ssl->out_len = NULL; + ssl->out_iv = NULL; + ssl->out_msg = NULL; + + return( ret ); +} + +/* + * Reset an initialized and used SSL context for re-use while retaining + * all application-set variables, function pointers and data. + * + * If partial is non-zero, keep data in the input buffer and client ID. + * (Use when a DTLS client reconnects from the same port.) + */ +static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) +{ + int ret; + +#if !defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) || \ + !defined(MBEDTLS_SSL_SRV_C) + ((void) partial); +#endif + + ssl->state = MBEDTLS_SSL_HELLO_REQUEST; + + /* Cancel any possibly running timer */ + ssl_set_timer( ssl, 0 ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->renego_status = MBEDTLS_SSL_INITIAL_HANDSHAKE; + ssl->renego_records_seen = 0; + + ssl->verify_data_len = 0; + memset( ssl->own_verify_data, 0, MBEDTLS_SSL_VERIFY_DATA_MAX_LEN ); + memset( ssl->peer_verify_data, 0, MBEDTLS_SSL_VERIFY_DATA_MAX_LEN ); +#endif + ssl->secure_renegotiation = MBEDTLS_SSL_LEGACY_RENEGOTIATION; + + ssl->in_offt = NULL; + ssl_reset_in_out_pointers( ssl ); + + ssl->in_msgtype = 0; + ssl->in_msglen = 0; +#if defined(MBEDTLS_SSL_PROTO_DTLS) + ssl->next_record_offset = 0; + ssl->in_epoch = 0; +#endif +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + ssl_dtls_replay_reset( ssl ); +#endif + + ssl->in_hslen = 0; + ssl->nb_zero = 0; + + ssl->keep_current_message = 0; + + ssl->out_msgtype = 0; + ssl->out_msglen = 0; + ssl->out_left = 0; +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + if( ssl->split_done != MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED ) + ssl->split_done = 0; +#endif + + memset( ssl->cur_out_ctr, 0, sizeof( ssl->cur_out_ctr ) ); + + ssl->transform_in = NULL; + ssl->transform_out = NULL; + + ssl->session_in = NULL; + ssl->session_out = NULL; + + memset( ssl->out_buf, 0, MBEDTLS_SSL_OUT_BUFFER_LEN ); + +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C) + if( partial == 0 ) +#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */ + { + ssl->in_left = 0; + memset( ssl->in_buf, 0, MBEDTLS_SSL_IN_BUFFER_LEN ); + } + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_reset != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_reset()" ) ); + if( ( ret = mbedtls_ssl_hw_record_reset( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_reset", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif + + if( ssl->transform ) + { + mbedtls_ssl_transform_free( ssl->transform ); + mbedtls_free( ssl->transform ); + ssl->transform = NULL; + } + + if( ssl->session ) + { + mbedtls_ssl_session_free( ssl->session ); + mbedtls_free( ssl->session ); + ssl->session = NULL; + } + +#if defined(MBEDTLS_SSL_ALPN) + ssl->alpn_chosen = NULL; +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) + if( partial == 0 ) +#endif + { + mbedtls_free( ssl->cli_id ); + ssl->cli_id = NULL; + ssl->cli_id_len = 0; + } +#endif + + if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Reset an initialized and used SSL context for re-use while retaining + * all application-set variables, function pointers and data. + */ +int mbedtls_ssl_session_reset( mbedtls_ssl_context *ssl ) +{ + return( ssl_session_reset_int( ssl, 0 ) ); +} + +/* + * SSL set accessors + */ +void mbedtls_ssl_conf_endpoint( mbedtls_ssl_config *conf, int endpoint ) +{ + conf->endpoint = endpoint; +} + +void mbedtls_ssl_conf_transport( mbedtls_ssl_config *conf, int transport ) +{ + conf->transport = transport; +} + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +void mbedtls_ssl_conf_dtls_anti_replay( mbedtls_ssl_config *conf, char mode ) +{ + conf->anti_replay = mode; +} +#endif + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) +void mbedtls_ssl_conf_dtls_badmac_limit( mbedtls_ssl_config *conf, unsigned limit ) +{ + conf->badmac_limit = limit; +} +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + +void mbedtls_ssl_set_datagram_packing( mbedtls_ssl_context *ssl, + unsigned allow_packing ) +{ + ssl->disable_datagram_packing = !allow_packing; +} + +void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf, + uint32_t min, uint32_t max ) +{ + conf->hs_timeout_min = min; + conf->hs_timeout_max = max; +} +#endif + +void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode ) +{ + conf->authmode = authmode; +} + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +void mbedtls_ssl_conf_verify( mbedtls_ssl_config *conf, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + conf->f_vrfy = f_vrfy; + conf->p_vrfy = p_vrfy; +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +void mbedtls_ssl_conf_rng( mbedtls_ssl_config *conf, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + conf->f_rng = f_rng; + conf->p_rng = p_rng; +} + +void mbedtls_ssl_conf_dbg( mbedtls_ssl_config *conf, + void (*f_dbg)(void *, int, const char *, int, const char *), + void *p_dbg ) +{ + conf->f_dbg = f_dbg; + conf->p_dbg = p_dbg; +} + +void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl, + void *p_bio, + mbedtls_ssl_send_t *f_send, + mbedtls_ssl_recv_t *f_recv, + mbedtls_ssl_recv_timeout_t *f_recv_timeout ) +{ + ssl->p_bio = p_bio; + ssl->f_send = f_send; + ssl->f_recv = f_recv; + ssl->f_recv_timeout = f_recv_timeout; +} + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +void mbedtls_ssl_set_mtu( mbedtls_ssl_context *ssl, uint16_t mtu ) +{ + ssl->mtu = mtu; +} +#endif + +void mbedtls_ssl_conf_read_timeout( mbedtls_ssl_config *conf, uint32_t timeout ) +{ + conf->read_timeout = timeout; +} + +void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl, + void *p_timer, + mbedtls_ssl_set_timer_t *f_set_timer, + mbedtls_ssl_get_timer_t *f_get_timer ) +{ + ssl->p_timer = p_timer; + ssl->f_set_timer = f_set_timer; + ssl->f_get_timer = f_get_timer; + + /* Make sure we start with no timer running */ + ssl_set_timer( ssl, 0 ); +} + +#if defined(MBEDTLS_SSL_SRV_C) +void mbedtls_ssl_conf_session_cache( mbedtls_ssl_config *conf, + void *p_cache, + int (*f_get_cache)(void *, mbedtls_ssl_session *), + int (*f_set_cache)(void *, const mbedtls_ssl_session *) ) +{ + conf->p_cache = p_cache; + conf->f_get_cache = f_get_cache; + conf->f_set_cache = f_set_cache; +} +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) +int mbedtls_ssl_set_session( mbedtls_ssl_context *ssl, const mbedtls_ssl_session *session ) +{ + int ret; + + if( ssl == NULL || + session == NULL || + ssl->session_negotiate == NULL || + ssl->conf->endpoint != MBEDTLS_SSL_IS_CLIENT ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( ( ret = mbedtls_ssl_session_copy( ssl->session_negotiate, + session ) ) != 0 ) + return( ret ); + + ssl->handshake->resume = 1; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_CLI_C */ + +void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf, + const int *ciphersuites ) +{ + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_0] = ciphersuites; + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = ciphersuites; + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = ciphersuites; + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = ciphersuites; +} + +void mbedtls_ssl_conf_ciphersuites_for_version( mbedtls_ssl_config *conf, + const int *ciphersuites, + int major, int minor ) +{ + if( major != MBEDTLS_SSL_MAJOR_VERSION_3 ) + return; + + if( minor < MBEDTLS_SSL_MINOR_VERSION_0 || minor > MBEDTLS_SSL_MINOR_VERSION_3 ) + return; + + conf->ciphersuite_list[minor] = ciphersuites; +} + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +void mbedtls_ssl_conf_cert_profile( mbedtls_ssl_config *conf, + const mbedtls_x509_crt_profile *profile ) +{ + conf->cert_profile = profile; +} + +/* Append a new keycert entry to a (possibly empty) list */ +static int ssl_append_key_cert( mbedtls_ssl_key_cert **head, + mbedtls_x509_crt *cert, + mbedtls_pk_context *key ) +{ + mbedtls_ssl_key_cert *new_cert; + + new_cert = mbedtls_calloc( 1, sizeof( mbedtls_ssl_key_cert ) ); + if( new_cert == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + new_cert->cert = cert; + new_cert->key = key; + new_cert->next = NULL; + + /* Update head is the list was null, else add to the end */ + if( *head == NULL ) + { + *head = new_cert; + } + else + { + mbedtls_ssl_key_cert *cur = *head; + while( cur->next != NULL ) + cur = cur->next; + cur->next = new_cert; + } + + return( 0 ); +} + +int mbedtls_ssl_conf_own_cert( mbedtls_ssl_config *conf, + mbedtls_x509_crt *own_cert, + mbedtls_pk_context *pk_key ) +{ + return( ssl_append_key_cert( &conf->key_cert, own_cert, pk_key ) ); +} + +void mbedtls_ssl_conf_ca_chain( mbedtls_ssl_config *conf, + mbedtls_x509_crt *ca_chain, + mbedtls_x509_crl *ca_crl ) +{ + conf->ca_chain = ca_chain; + conf->ca_crl = ca_crl; + +#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) + /* mbedtls_ssl_conf_ca_chain() and mbedtls_ssl_conf_ca_cb() + * cannot be used together. */ + conf->f_ca_cb = NULL; + conf->p_ca_cb = NULL; +#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ +} + +#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) +void mbedtls_ssl_conf_ca_cb( mbedtls_ssl_config *conf, + mbedtls_x509_crt_ca_cb_t f_ca_cb, + void *p_ca_cb ) +{ + conf->f_ca_cb = f_ca_cb; + conf->p_ca_cb = p_ca_cb; + + /* mbedtls_ssl_conf_ca_chain() and mbedtls_ssl_conf_ca_cb() + * cannot be used together. */ + conf->ca_chain = NULL; + conf->ca_crl = NULL; +} +#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +int mbedtls_ssl_set_hs_own_cert( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *own_cert, + mbedtls_pk_context *pk_key ) +{ + return( ssl_append_key_cert( &ssl->handshake->sni_key_cert, + own_cert, pk_key ) ); +} + +void mbedtls_ssl_set_hs_ca_chain( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *ca_chain, + mbedtls_x509_crl *ca_crl ) +{ + ssl->handshake->sni_ca_chain = ca_chain; + ssl->handshake->sni_ca_crl = ca_crl; +} + +void mbedtls_ssl_set_hs_authmode( mbedtls_ssl_context *ssl, + int authmode ) +{ + ssl->handshake->sni_authmode = authmode; +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +void mbedtls_ssl_set_verify( mbedtls_ssl_context *ssl, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + ssl->f_vrfy = f_vrfy; + ssl->p_vrfy = p_vrfy; +} +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +/* + * Set EC J-PAKE password for current handshake + */ +int mbedtls_ssl_set_hs_ecjpake_password( mbedtls_ssl_context *ssl, + const unsigned char *pw, + size_t pw_len ) +{ + mbedtls_ecjpake_role role; + + if( ssl->handshake == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + role = MBEDTLS_ECJPAKE_SERVER; + else + role = MBEDTLS_ECJPAKE_CLIENT; + + return( mbedtls_ecjpake_setup( &ssl->handshake->ecjpake_ctx, + role, + MBEDTLS_MD_SHA256, + MBEDTLS_ECP_DP_SECP256R1, + pw, pw_len ) ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + +static void ssl_conf_remove_psk( mbedtls_ssl_config *conf ) +{ + /* Remove reference to existing PSK, if any. */ +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( conf->psk_opaque != 0 ) + { + /* The maintenance of the PSK key slot is the + * user's responsibility. */ + conf->psk_opaque = 0; + } + /* This and the following branch should never + * be taken simultaenously as we maintain the + * invariant that raw and opaque PSKs are never + * configured simultaneously. As a safeguard, + * though, `else` is omitted here. */ +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + if( conf->psk != NULL ) + { + mbedtls_platform_zeroize( conf->psk, conf->psk_len ); + + mbedtls_free( conf->psk ); + conf->psk = NULL; + conf->psk_len = 0; + } + + /* Remove reference to PSK identity, if any. */ + if( conf->psk_identity != NULL ) + { + mbedtls_free( conf->psk_identity ); + conf->psk_identity = NULL; + conf->psk_identity_len = 0; + } +} + +/* This function assumes that PSK identity in the SSL config is unset. + * It checks that the provided identity is well-formed and attempts + * to make a copy of it in the SSL config. + * On failure, the PSK identity in the config remains unset. */ +static int ssl_conf_set_psk_identity( mbedtls_ssl_config *conf, + unsigned char const *psk_identity, + size_t psk_identity_len ) +{ + /* Identity len will be encoded on two bytes */ + if( psk_identity == NULL || + ( psk_identity_len >> 16 ) != 0 || + psk_identity_len > MBEDTLS_SSL_OUT_CONTENT_LEN ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + conf->psk_identity = mbedtls_calloc( 1, psk_identity_len ); + if( conf->psk_identity == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + conf->psk_identity_len = psk_identity_len; + memcpy( conf->psk_identity, psk_identity, conf->psk_identity_len ); + + return( 0 ); +} + +int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf, + const unsigned char *psk, size_t psk_len, + const unsigned char *psk_identity, size_t psk_identity_len ) +{ + int ret; + /* Remove opaque/raw PSK + PSK Identity */ + ssl_conf_remove_psk( conf ); + + /* Check and set raw PSK */ + if( psk == NULL || psk_len > MBEDTLS_PSK_MAX_LEN ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + if( ( conf->psk = mbedtls_calloc( 1, psk_len ) ) == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + conf->psk_len = psk_len; + memcpy( conf->psk, psk, conf->psk_len ); + + /* Check and set PSK Identity */ + ret = ssl_conf_set_psk_identity( conf, psk_identity, psk_identity_len ); + if( ret != 0 ) + ssl_conf_remove_psk( conf ); + + return( ret ); +} + +static void ssl_remove_psk( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( ssl->handshake->psk_opaque != 0 ) + { + ssl->handshake->psk_opaque = 0; + } + else +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + if( ssl->handshake->psk != NULL ) + { + mbedtls_platform_zeroize( ssl->handshake->psk, + ssl->handshake->psk_len ); + mbedtls_free( ssl->handshake->psk ); + ssl->handshake->psk_len = 0; + } +} + +int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl, + const unsigned char *psk, size_t psk_len ) +{ + if( psk == NULL || ssl->handshake == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( psk_len > MBEDTLS_PSK_MAX_LEN ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + ssl_remove_psk( ssl ); + + if( ( ssl->handshake->psk = mbedtls_calloc( 1, psk_len ) ) == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ssl->handshake->psk_len = psk_len; + memcpy( ssl->handshake->psk, psk, ssl->handshake->psk_len ); + + return( 0 ); +} + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +int mbedtls_ssl_conf_psk_opaque( mbedtls_ssl_config *conf, + psa_key_handle_t psk_slot, + const unsigned char *psk_identity, + size_t psk_identity_len ) +{ + int ret; + /* Clear opaque/raw PSK + PSK Identity, if present. */ + ssl_conf_remove_psk( conf ); + + /* Check and set opaque PSK */ + if( psk_slot == 0 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + conf->psk_opaque = psk_slot; + + /* Check and set PSK Identity */ + ret = ssl_conf_set_psk_identity( conf, psk_identity, + psk_identity_len ); + if( ret != 0 ) + ssl_conf_remove_psk( conf ); + + return( ret ); +} + +int mbedtls_ssl_set_hs_psk_opaque( mbedtls_ssl_context *ssl, + psa_key_handle_t psk_slot ) +{ + if( psk_slot == 0 || ssl->handshake == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + ssl_remove_psk( ssl ); + ssl->handshake->psk_opaque = psk_slot; + return( 0 ); +} +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +void mbedtls_ssl_conf_psk_cb( mbedtls_ssl_config *conf, + int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *, + size_t), + void *p_psk ) +{ + conf->f_psk = f_psk; + conf->p_psk = p_psk; +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_SRV_C) + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +int mbedtls_ssl_conf_dh_param( mbedtls_ssl_config *conf, const char *dhm_P, const char *dhm_G ) +{ + int ret; + + if( ( ret = mbedtls_mpi_read_string( &conf->dhm_P, 16, dhm_P ) ) != 0 || + ( ret = mbedtls_mpi_read_string( &conf->dhm_G, 16, dhm_G ) ) != 0 ) + { + mbedtls_mpi_free( &conf->dhm_P ); + mbedtls_mpi_free( &conf->dhm_G ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + +int mbedtls_ssl_conf_dh_param_bin( mbedtls_ssl_config *conf, + const unsigned char *dhm_P, size_t P_len, + const unsigned char *dhm_G, size_t G_len ) +{ + int ret; + + if( ( ret = mbedtls_mpi_read_binary( &conf->dhm_P, dhm_P, P_len ) ) != 0 || + ( ret = mbedtls_mpi_read_binary( &conf->dhm_G, dhm_G, G_len ) ) != 0 ) + { + mbedtls_mpi_free( &conf->dhm_P ); + mbedtls_mpi_free( &conf->dhm_G ); + return( ret ); + } + + return( 0 ); +} + +int mbedtls_ssl_conf_dh_param_ctx( mbedtls_ssl_config *conf, mbedtls_dhm_context *dhm_ctx ) +{ + int ret; + + if( ( ret = mbedtls_mpi_copy( &conf->dhm_P, &dhm_ctx->P ) ) != 0 || + ( ret = mbedtls_mpi_copy( &conf->dhm_G, &dhm_ctx->G ) ) != 0 ) + { + mbedtls_mpi_free( &conf->dhm_P ); + mbedtls_mpi_free( &conf->dhm_G ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_DHM_C && MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C) +/* + * Set the minimum length for Diffie-Hellman parameters + */ +void mbedtls_ssl_conf_dhm_min_bitlen( mbedtls_ssl_config *conf, + unsigned int bitlen ) +{ + conf->dhm_min_bitlen = bitlen; +} +#endif /* MBEDTLS_DHM_C && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +/* + * Set allowed/preferred hashes for handshake signatures + */ +void mbedtls_ssl_conf_sig_hashes( mbedtls_ssl_config *conf, + const int *hashes ) +{ + conf->sig_hashes = hashes; +} +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_ECP_C) +/* + * Set the allowed elliptic curves + */ +void mbedtls_ssl_conf_curves( mbedtls_ssl_config *conf, + const mbedtls_ecp_group_id *curve_list ) +{ + conf->curve_list = curve_list; +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname ) +{ + /* Initialize to suppress unnecessary compiler warning */ + size_t hostname_len = 0; + + /* Check if new hostname is valid before + * making any change to current one */ + if( hostname != NULL ) + { + hostname_len = strlen( hostname ); + + if( hostname_len > MBEDTLS_SSL_MAX_HOST_NAME_LEN ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* Now it's clear that we will overwrite the old hostname, + * so we can free it safely */ + + if( ssl->hostname != NULL ) + { + mbedtls_platform_zeroize( ssl->hostname, strlen( ssl->hostname ) ); + mbedtls_free( ssl->hostname ); + } + + /* Passing NULL as hostname shall clear the old one */ + + if( hostname == NULL ) + { + ssl->hostname = NULL; + } + else + { + ssl->hostname = mbedtls_calloc( 1, hostname_len + 1 ); + if( ssl->hostname == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( ssl->hostname, hostname, hostname_len ); + + ssl->hostname[hostname_len] = '\0'; + } + + return( 0 ); +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +void mbedtls_ssl_conf_sni( mbedtls_ssl_config *conf, + int (*f_sni)(void *, mbedtls_ssl_context *, + const unsigned char *, size_t), + void *p_sni ) +{ + conf->f_sni = f_sni; + conf->p_sni = p_sni; +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_SSL_ALPN) +int mbedtls_ssl_conf_alpn_protocols( mbedtls_ssl_config *conf, const char **protos ) +{ + size_t cur_len, tot_len; + const char **p; + + /* + * RFC 7301 3.1: "Empty strings MUST NOT be included and byte strings + * MUST NOT be truncated." + * We check lengths now rather than later. + */ + tot_len = 0; + for( p = protos; *p != NULL; p++ ) + { + cur_len = strlen( *p ); + tot_len += cur_len; + + if( cur_len == 0 || cur_len > 255 || tot_len > 65535 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + conf->alpn_list = protos; + + return( 0 ); +} + +const char *mbedtls_ssl_get_alpn_protocol( const mbedtls_ssl_context *ssl ) +{ + return( ssl->alpn_chosen ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +void mbedtls_ssl_conf_max_version( mbedtls_ssl_config *conf, int major, int minor ) +{ + conf->max_major_ver = major; + conf->max_minor_ver = minor; +} + +void mbedtls_ssl_conf_min_version( mbedtls_ssl_config *conf, int major, int minor ) +{ + conf->min_major_ver = major; + conf->min_minor_ver = minor; +} + +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) && defined(MBEDTLS_SSL_CLI_C) +void mbedtls_ssl_conf_fallback( mbedtls_ssl_config *conf, char fallback ) +{ + conf->fallback = fallback; +} +#endif + +#if defined(MBEDTLS_SSL_SRV_C) +void mbedtls_ssl_conf_cert_req_ca_list( mbedtls_ssl_config *conf, + char cert_req_ca_list ) +{ + conf->cert_req_ca_list = cert_req_ca_list; +} +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +void mbedtls_ssl_conf_encrypt_then_mac( mbedtls_ssl_config *conf, char etm ) +{ + conf->encrypt_then_mac = etm; +} +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +void mbedtls_ssl_conf_extended_master_secret( mbedtls_ssl_config *conf, char ems ) +{ + conf->extended_ms = ems; +} +#endif + +#if defined(MBEDTLS_ARC4_C) +void mbedtls_ssl_conf_arc4_support( mbedtls_ssl_config *conf, char arc4 ) +{ + conf->arc4_disabled = arc4; +} +#endif + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +int mbedtls_ssl_conf_max_frag_len( mbedtls_ssl_config *conf, unsigned char mfl_code ) +{ + if( mfl_code >= MBEDTLS_SSL_MAX_FRAG_LEN_INVALID || + ssl_mfl_code_to_length( mfl_code ) > MBEDTLS_TLS_EXT_ADV_CONTENT_LEN ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + conf->mfl_code = mfl_code; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +void mbedtls_ssl_conf_truncated_hmac( mbedtls_ssl_config *conf, int truncate ) +{ + conf->trunc_hmac = truncate; +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) +void mbedtls_ssl_conf_cbc_record_splitting( mbedtls_ssl_config *conf, char split ) +{ + conf->cbc_record_splitting = split; +} +#endif + +void mbedtls_ssl_conf_legacy_renegotiation( mbedtls_ssl_config *conf, int allow_legacy ) +{ + conf->allow_legacy_renegotiation = allow_legacy; +} + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +void mbedtls_ssl_conf_renegotiation( mbedtls_ssl_config *conf, int renegotiation ) +{ + conf->disable_renegotiation = renegotiation; +} + +void mbedtls_ssl_conf_renegotiation_enforced( mbedtls_ssl_config *conf, int max_records ) +{ + conf->renego_max_records = max_records; +} + +void mbedtls_ssl_conf_renegotiation_period( mbedtls_ssl_config *conf, + const unsigned char period[8] ) +{ + memcpy( conf->renego_period, period, 8 ); +} +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +#if defined(MBEDTLS_SSL_CLI_C) +void mbedtls_ssl_conf_session_tickets( mbedtls_ssl_config *conf, int use_tickets ) +{ + conf->session_tickets = use_tickets; +} +#endif + +#if defined(MBEDTLS_SSL_SRV_C) +void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_ticket_write_t *f_ticket_write, + mbedtls_ssl_ticket_parse_t *f_ticket_parse, + void *p_ticket ) +{ + conf->f_ticket_write = f_ticket_write; + conf->f_ticket_parse = f_ticket_parse; + conf->p_ticket = p_ticket; +} +#endif +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_export_keys_t *f_export_keys, + void *p_export_keys ) +{ + conf->f_export_keys = f_export_keys; + conf->p_export_keys = p_export_keys; +} + +void mbedtls_ssl_conf_export_keys_ext_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_export_keys_ext_t *f_export_keys_ext, + void *p_export_keys ) +{ + conf->f_export_keys_ext = f_export_keys_ext; + conf->p_export_keys = p_export_keys; +} +#endif + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) +void mbedtls_ssl_conf_async_private_cb( + mbedtls_ssl_config *conf, + mbedtls_ssl_async_sign_t *f_async_sign, + mbedtls_ssl_async_decrypt_t *f_async_decrypt, + mbedtls_ssl_async_resume_t *f_async_resume, + mbedtls_ssl_async_cancel_t *f_async_cancel, + void *async_config_data ) +{ + conf->f_async_sign_start = f_async_sign; + conf->f_async_decrypt_start = f_async_decrypt; + conf->f_async_resume = f_async_resume; + conf->f_async_cancel = f_async_cancel; + conf->p_async_config_data = async_config_data; +} + +void *mbedtls_ssl_conf_get_async_config_data( const mbedtls_ssl_config *conf ) +{ + return( conf->p_async_config_data ); +} + +void *mbedtls_ssl_get_async_operation_data( const mbedtls_ssl_context *ssl ) +{ + if( ssl->handshake == NULL ) + return( NULL ); + else + return( ssl->handshake->user_async_ctx ); +} + +void mbedtls_ssl_set_async_operation_data( mbedtls_ssl_context *ssl, + void *ctx ) +{ + if( ssl->handshake != NULL ) + ssl->handshake->user_async_ctx = ctx; +} +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + +/* + * SSL get accessors + */ +size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl ) +{ + return( ssl->in_offt == NULL ? 0 : ssl->in_msglen ); +} + +int mbedtls_ssl_check_pending( const mbedtls_ssl_context *ssl ) +{ + /* + * Case A: We're currently holding back + * a message for further processing. + */ + + if( ssl->keep_current_message == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: record held back for processing" ) ); + return( 1 ); + } + + /* + * Case B: Further records are pending in the current datagram. + */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->in_left > ssl->next_record_offset ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: more records within current datagram" ) ); + return( 1 ); + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + /* + * Case C: A handshake message is being processed. + */ + + if( ssl->in_hslen > 0 && ssl->in_hslen < ssl->in_msglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: more handshake messages within current record" ) ); + return( 1 ); + } + + /* + * Case D: An application data message is being processed + */ + if( ssl->in_offt != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: application data record is being processed" ) ); + return( 1 ); + } + + /* + * In all other cases, the rest of the message can be dropped. + * As in ssl_get_next_record, this needs to be adapted if + * we implement support for multiple alerts in single records. + */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ssl_check_pending: nothing pending" ) ); + return( 0 ); +} + +uint32_t mbedtls_ssl_get_verify_result( const mbedtls_ssl_context *ssl ) +{ + if( ssl->session != NULL ) + return( ssl->session->verify_result ); + + if( ssl->session_negotiate != NULL ) + return( ssl->session_negotiate->verify_result ); + + return( 0xFFFFFFFF ); +} + +const char *mbedtls_ssl_get_ciphersuite( const mbedtls_ssl_context *ssl ) +{ + if( ssl == NULL || ssl->session == NULL ) + return( NULL ); + + return mbedtls_ssl_get_ciphersuite_name( ssl->session->ciphersuite ); +} + +const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + switch( ssl->minor_ver ) + { + case MBEDTLS_SSL_MINOR_VERSION_2: + return( "DTLSv1.0" ); + + case MBEDTLS_SSL_MINOR_VERSION_3: + return( "DTLSv1.2" ); + + default: + return( "unknown (DTLS)" ); + } + } +#endif + + switch( ssl->minor_ver ) + { + case MBEDTLS_SSL_MINOR_VERSION_0: + return( "SSLv3.0" ); + + case MBEDTLS_SSL_MINOR_VERSION_1: + return( "TLSv1.0" ); + + case MBEDTLS_SSL_MINOR_VERSION_2: + return( "TLSv1.1" ); + + case MBEDTLS_SSL_MINOR_VERSION_3: + return( "TLSv1.2" ); + + default: + return( "unknown" ); + } +} + +int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ) +{ + size_t transform_expansion = 0; + const mbedtls_ssl_transform *transform = ssl->transform_out; + unsigned block_size; + + size_t out_hdr_len = mbedtls_ssl_out_hdr_len( ssl ); + + if( transform == NULL ) + return( (int) out_hdr_len ); + +#if defined(MBEDTLS_ZLIB_SUPPORT) + if( ssl->session_out->compression != MBEDTLS_SSL_COMPRESS_NULL ) + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +#endif + + switch( mbedtls_cipher_get_cipher_mode( &transform->cipher_ctx_enc ) ) + { + case MBEDTLS_MODE_GCM: + case MBEDTLS_MODE_CCM: + case MBEDTLS_MODE_CHACHAPOLY: + case MBEDTLS_MODE_STREAM: + transform_expansion = transform->minlen; + break; + + case MBEDTLS_MODE_CBC: + + block_size = mbedtls_cipher_get_block_size( + &transform->cipher_ctx_enc ); + + /* Expansion due to the addition of the MAC. */ + transform_expansion += transform->maclen; + + /* Expansion due to the addition of CBC padding; + * Theoretically up to 256 bytes, but we never use + * more than the block size of the underlying cipher. */ + transform_expansion += block_size; + + /* For TLS 1.1 or higher, an explicit IV is added + * after the record header. */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + transform_expansion += block_size; +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1_2 */ + + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + if( transform->out_cid_len != 0 ) + transform_expansion += MBEDTLS_SSL_MAX_CID_EXPANSION; +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ + + return( (int)( out_hdr_len + transform_expansion ) ); +} + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ) +{ + size_t max_len; + + /* + * Assume mfl_code is correct since it was checked when set + */ + max_len = ssl_mfl_code_to_length( ssl->conf->mfl_code ); + + /* Check if a smaller max length was negotiated */ + if( ssl->session_out != NULL && + ssl_mfl_code_to_length( ssl->session_out->mfl_code ) < max_len ) + { + max_len = ssl_mfl_code_to_length( ssl->session_out->mfl_code ); + } + + /* During a handshake, use the value being negotiated */ + if( ssl->session_negotiate != NULL && + ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code ) < max_len ) + { + max_len = ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code ); + } + + return( max_len ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +static size_t ssl_get_current_mtu( const mbedtls_ssl_context *ssl ) +{ + /* Return unlimited mtu for client hello messages to avoid fragmentation. */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + ( ssl->state == MBEDTLS_SSL_CLIENT_HELLO || + ssl->state == MBEDTLS_SSL_SERVER_HELLO ) ) + return ( 0 ); + + if( ssl->handshake == NULL || ssl->handshake->mtu == 0 ) + return( ssl->mtu ); + + if( ssl->mtu == 0 ) + return( ssl->handshake->mtu ); + + return( ssl->mtu < ssl->handshake->mtu ? + ssl->mtu : ssl->handshake->mtu ); +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +int mbedtls_ssl_get_max_out_record_payload( const mbedtls_ssl_context *ssl ) +{ + size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN; + +#if !defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) && \ + !defined(MBEDTLS_SSL_PROTO_DTLS) + (void) ssl; +#endif + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + const size_t mfl = mbedtls_ssl_get_max_frag_len( ssl ); + + if( max_len > mfl ) + max_len = mfl; +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl_get_current_mtu( ssl ) != 0 ) + { + const size_t mtu = ssl_get_current_mtu( ssl ); + const int ret = mbedtls_ssl_get_record_expansion( ssl ); + const size_t overhead = (size_t) ret; + + if( ret < 0 ) + return( ret ); + + if( mtu <= overhead ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "MTU too low for record expansion" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + if( max_len > mtu - overhead ) + max_len = mtu - overhead; + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +#if !defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) && \ + !defined(MBEDTLS_SSL_PROTO_DTLS) + ((void) ssl); +#endif + + return( (int) max_len ); +} + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ssl ) +{ + if( ssl == NULL || ssl->session == NULL ) + return( NULL ); + +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + return( ssl->session->peer_cert ); +#else + return( NULL ); +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_CLI_C) +int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, + mbedtls_ssl_session *dst ) +{ + if( ssl == NULL || + dst == NULL || + ssl->session == NULL || + ssl->conf->endpoint != MBEDTLS_SSL_IS_CLIENT ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + return( mbedtls_ssl_session_copy( dst, ssl->session ) ); +} +#endif /* MBEDTLS_SSL_CLI_C */ + +/* + * Perform a single step of the SSL handshake + */ +int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + ret = mbedtls_ssl_handshake_client_step( ssl ); +#endif +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + ret = mbedtls_ssl_handshake_server_step( ssl ); +#endif + + return( ret ); +} + +/* + * Perform the SSL handshake + */ +int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> handshake" ) ); + + while( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + ret = mbedtls_ssl_handshake_step( ssl ); + + if( ret != 0 ) + break; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= handshake" ) ); + + return( ret ); +} + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +#if defined(MBEDTLS_SSL_SRV_C) +/* + * Write HelloRequest to request renegotiation on server + */ +static int ssl_write_hello_request( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write hello request" ) ); + + ssl->out_msglen = 4; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_HELLO_REQUEST; + + if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write hello request" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SRV_C */ + +/* + * Actually renegotiate current connection, triggered by either: + * - any side: calling mbedtls_ssl_renegotiate(), + * - client: receiving a HelloRequest during mbedtls_ssl_read(), + * - server: receiving any handshake message on server during mbedtls_ssl_read() after + * the initial handshake is completed. + * If the handshake doesn't complete due to waiting for I/O, it will continue + * during the next calls to mbedtls_ssl_renegotiate() or mbedtls_ssl_read() respectively. + */ +static int ssl_start_renegotiation( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> renegotiate" ) ); + + if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) + return( ret ); + + /* RFC 6347 4.2.2: "[...] the HelloRequest will have message_seq = 0 and + * the ServerHello will have message_seq = 1" */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) + { + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + ssl->handshake->out_msg_seq = 1; + else + ssl->handshake->in_msg_seq = 1; + } +#endif + + ssl->state = MBEDTLS_SSL_HELLO_REQUEST; + ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS; + + if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= renegotiate" ) ); + + return( 0 ); +} + +/* + * Renegotiate current connection on client, + * or request renegotiation on server + */ +int mbedtls_ssl_renegotiate( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_SSL_SRV_C) + /* On server, just send the request */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING; + + /* Did we already try/start sending HelloRequest? */ + if( ssl->out_left != 0 ) + return( mbedtls_ssl_flush_output( ssl ) ); + + return( ssl_write_hello_request( ssl ) ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) + /* + * On client, either start the renegotiation process or, + * if already in progress, continue the handshake + */ + if( ssl->renego_status != MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( ( ret = ssl_start_renegotiation( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_start_renegotiation", ret ); + return( ret ); + } + } + else + { + if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_SSL_CLI_C */ + + return( ret ); +} + +/* + * Check record counters and renegotiate if they're above the limit. + */ +static int ssl_check_ctr_renegotiate( mbedtls_ssl_context *ssl ) +{ + size_t ep_len = ssl_ep_len( ssl ); + int in_ctr_cmp; + int out_ctr_cmp; + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER || + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING || + ssl->conf->disable_renegotiation == MBEDTLS_SSL_RENEGOTIATION_DISABLED ) + { + return( 0 ); + } + + in_ctr_cmp = memcmp( ssl->in_ctr + ep_len, + ssl->conf->renego_period + ep_len, 8 - ep_len ); + out_ctr_cmp = memcmp( ssl->cur_out_ctr + ep_len, + ssl->conf->renego_period + ep_len, 8 - ep_len ); + + if( in_ctr_cmp <= 0 && out_ctr_cmp <= 0 ) + { + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "record counter limit reached: renegotiate" ) ); + return( mbedtls_ssl_renegotiate( ssl ) ); +} +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/* + * Receive application data decrypted from the SSL layer + */ +int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) +{ + int ret; + size_t n; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read" ) ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + if( ssl->handshake != NULL && + ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) + { + if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 ) + return( ret ); + } + } +#endif + + /* + * Check if renegotiation is necessary and/or handshake is + * in process. If yes, perform/continue, and fall through + * if an unexpected packet is received while the client + * is waiting for the ServerHello. + * + * (There is no equivalent to the last condition on + * the server-side as it is not treated as within + * a handshake while waiting for the ClientHello + * after a renegotiation request.) + */ + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ret = ssl_check_ctr_renegotiate( ssl ); + if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && + ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_check_ctr_renegotiate", ret ); + return( ret ); + } +#endif + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + ret = mbedtls_ssl_handshake( ssl ); + if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && + ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } + } + + /* Loop as long as no application data record is available */ + while( ssl->in_offt == NULL ) + { + /* Start timer if not already running */ + if( ssl->f_get_timer != NULL && + ssl->f_get_timer( ssl->p_timer ) == -1 ) + { + ssl_set_timer( ssl, ssl->conf->read_timeout ); + } + + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_SSL_CONN_EOF ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msglen == 0 && + ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA ) + { + /* + * OpenSSL sends empty messages to randomize the IV + */ + if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_SSL_CONN_EOF ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + } + + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "received handshake message" ) ); + + /* + * - For client-side, expect SERVER_HELLO_REQUEST. + * - For server-side, expect CLIENT_HELLO. + * - Fail (TLS) or silently drop record (DTLS) in other cases. + */ + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + ( ssl->in_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST || + ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not HelloRequest)" ) ); + + /* With DTLS, drop the packet (probably from last handshake) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + continue; + } +#endif + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } +#endif /* MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not ClientHello)" ) ); + + /* With DTLS, drop the packet (probably from last handshake) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + continue; + } +#endif + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + /* Determine whether renegotiation attempt should be accepted */ + if( ! ( ssl->conf->disable_renegotiation == MBEDTLS_SSL_RENEGOTIATION_DISABLED || + ( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == + MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) ) ) + { + /* + * Accept renegotiation request + */ + + /* DTLS clients need to know renego is server-initiated */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING; + } +#endif + ret = ssl_start_renegotiation( ssl ); + if( ret != MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO && + ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_start_renegotiation", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + { + /* + * Refuse renegotiation + */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "refusing renegotiation, sending alert" ) ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + /* SSLv3 does not have a "no_renegotiation" warning, so + we send a fatal alert and abort the connection. */ + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) + { + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_WARNING, + MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) ) != 0 ) + { + return( ret ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + + /* At this point, we don't know whether the renegotiation has been + * completed or not. The cases to consider are the following: + * 1) The renegotiation is complete. In this case, no new record + * has been read yet. + * 2) The renegotiation is incomplete because the client received + * an application data record while awaiting the ServerHello. + * 3) The renegotiation is incomplete because the client received + * a non-handshake, non-application data message while awaiting + * the ServerHello. + * In each of these case, looping will be the proper action: + * - For 1), the next iteration will read a new record and check + * if it's application data. + * - For 2), the loop condition isn't satisfied as application data + * is present, hence continue is the same as break + * - For 3), the loop condition is satisfied and read_record + * will re-deliver the message that was held back by the client + * when expecting the ServerHello. + */ + continue; + } +#if defined(MBEDTLS_SSL_RENEGOTIATION) + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) + { + if( ssl->conf->renego_max_records >= 0 ) + { + if( ++ssl->renego_records_seen > ssl->conf->renego_max_records ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation requested, " + "but not honored by client" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + } + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + /* Fatal and closure alerts handled by mbedtls_ssl_read_record() */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ignoring non-fatal non-closure alert" ) ); + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_APPLICATION_DATA ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad application data message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + ssl->in_offt = ssl->in_msg; + + /* We're going to return something now, cancel timer, + * except if handshake (renegotiation) is in progress */ + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + ssl_set_timer( ssl, 0 ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + /* If we requested renego but received AppData, resend HelloRequest. + * Do it now, after setting in_offt, to avoid taking this branch + * again if ssl_write_hello_request() returns WANT_WRITE */ +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) + { + if( ( ret = ssl_resend_hello_request( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_resend_hello_request", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_RENEGOTIATION */ +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + } + + n = ( len < ssl->in_msglen ) + ? len : ssl->in_msglen; + + memcpy( buf, ssl->in_offt, n ); + ssl->in_msglen -= n; + + if( ssl->in_msglen == 0 ) + { + /* all bytes consumed */ + ssl->in_offt = NULL; + ssl->keep_current_message = 0; + } + else + { + /* more data available */ + ssl->in_offt += n; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= read" ) ); + + return( (int) n ); +} + +/* + * Send application data to be encrypted by the SSL layer, taking care of max + * fragment length and buffer size. + * + * According to RFC 5246 Section 6.2.1: + * + * Zero-length fragments of Application data MAY be sent as they are + * potentially useful as a traffic analysis countermeasure. + * + * Therefore, it is possible that the input message length is 0 and the + * corresponding return code is 0 on success. + */ +static int ssl_write_real( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + int ret = mbedtls_ssl_get_max_out_record_payload( ssl ); + const size_t max_len = (size_t) ret; + + if( ret < 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_get_max_out_record_payload", ret ); + return( ret ); + } + + if( len > max_len ) + { +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "fragment larger than the (negotiated) " + "maximum fragment length: %d > %d", + len, max_len ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + else +#endif + len = max_len; + } + + if( ssl->out_left != 0 ) + { + /* + * The user has previously tried to send the data and + * MBEDTLS_ERR_SSL_WANT_WRITE or the message was only partially + * written. In this case, we expect the high-level write function + * (e.g. mbedtls_ssl_write()) to be called with the same parameters + */ + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flush_output", ret ); + return( ret ); + } + } + else + { + /* + * The user is trying to send a message the first time, so we need to + * copy the data into the internal buffers and setup the data structure + * to keep track of partial writes + */ + ssl->out_msglen = len; + ssl->out_msgtype = MBEDTLS_SSL_MSG_APPLICATION_DATA; + memcpy( ssl->out_msg, buf, len ); + + if( ( ret = mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + } + + return( (int) len ); +} + +/* + * Write application data, doing 1/n-1 splitting if necessary. + * + * With non-blocking I/O, ssl_write_real() may return WANT_WRITE, + * then the caller will call us again with the same arguments, so + * remember whether we already did the split or not. + */ +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) +static int ssl_write_split( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + int ret; + + if( ssl->conf->cbc_record_splitting == + MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED || + len <= 1 || + ssl->minor_ver > MBEDTLS_SSL_MINOR_VERSION_1 || + mbedtls_cipher_get_cipher_mode( &ssl->transform_out->cipher_ctx_enc ) + != MBEDTLS_MODE_CBC ) + { + return( ssl_write_real( ssl, buf, len ) ); + } + + if( ssl->split_done == 0 ) + { + if( ( ret = ssl_write_real( ssl, buf, 1 ) ) <= 0 ) + return( ret ); + ssl->split_done = 1; + } + + if( ( ret = ssl_write_real( ssl, buf + 1, len - 1 ) ) <= 0 ) + return( ret ); + ssl->split_done = 0; + + return( ret + 1 ); +} +#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ + +/* + * Write application data (public-facing wrapper) + */ +int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write" ) ); + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ( ret = ssl_check_ctr_renegotiate( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_check_ctr_renegotiate", ret ); + return( ret ); + } +#endif + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } + } + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + ret = ssl_write_split( ssl, buf, len ); +#else + ret = ssl_write_real( ssl, buf, len ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write" ) ); + + return( ret ); +} + +/* + * Notify the peer that the connection is being closed + */ +int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl ) +{ + int ret; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write close notify" ) ); + + if( ssl->out_left != 0 ) + return( mbedtls_ssl_flush_output( ssl ) ); + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + { + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_WARNING, + MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_send_alert_message", ret ); + return( ret ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write close notify" ) ); + + return( 0 ); +} + +void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ) +{ + if( transform == NULL ) + return; + +#if defined(MBEDTLS_ZLIB_SUPPORT) + deflateEnd( &transform->ctx_deflate ); + inflateEnd( &transform->ctx_inflate ); +#endif + + mbedtls_cipher_free( &transform->cipher_ctx_enc ); + mbedtls_cipher_free( &transform->cipher_ctx_dec ); + +#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) + mbedtls_md_free( &transform->md_ctx_enc ); + mbedtls_md_free( &transform->md_ctx_dec ); +#endif + + mbedtls_platform_zeroize( transform, sizeof( mbedtls_ssl_transform ) ); +} + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +static void ssl_key_cert_free( mbedtls_ssl_key_cert *key_cert ) +{ + mbedtls_ssl_key_cert *cur = key_cert, *next; + + while( cur != NULL ) + { + next = cur->next; + mbedtls_free( cur ); + cur = next; + } +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + +static void ssl_buffering_free( mbedtls_ssl_context *ssl ) +{ + unsigned offset; + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + + if( hs == NULL ) + return; + + ssl_free_buffered_record( ssl ); + + for( offset = 0; offset < MBEDTLS_SSL_MAX_BUFFERED_HS; offset++ ) + ssl_buffering_free_slot( ssl, offset ); +} + +static void ssl_buffering_free_slot( mbedtls_ssl_context *ssl, + uint8_t slot ) +{ + mbedtls_ssl_handshake_params * const hs = ssl->handshake; + mbedtls_ssl_hs_buffer * const hs_buf = &hs->buffering.hs[slot]; + + if( slot >= MBEDTLS_SSL_MAX_BUFFERED_HS ) + return; + + if( hs_buf->is_valid == 1 ) + { + hs->buffering.total_bytes_buffered -= hs_buf->data_len; + mbedtls_platform_zeroize( hs_buf->data, hs_buf->data_len ); + mbedtls_free( hs_buf->data ); + memset( hs_buf, 0, sizeof( mbedtls_ssl_hs_buffer ) ); + } +} + +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_handshake_params *handshake = ssl->handshake; + + if( handshake == NULL ) + return; + +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + if( ssl->conf->f_async_cancel != NULL && handshake->async_in_progress != 0 ) + { + ssl->conf->f_async_cancel( ssl ); + handshake->async_in_progress = 0; + } +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_free( &handshake->fin_md5 ); + mbedtls_sha1_free( &handshake->fin_sha1 ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_hash_abort( &handshake->fin_sha256_psa ); +#else + mbedtls_sha256_free( &handshake->fin_sha256 ); +#endif +#endif +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_hash_abort( &handshake->fin_sha384_psa ); +#else + mbedtls_sha512_free( &handshake->fin_sha512 ); +#endif +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_DHM_C) + mbedtls_dhm_free( &handshake->dhm_ctx ); +#endif +#if defined(MBEDTLS_ECDH_C) + mbedtls_ecdh_free( &handshake->ecdh_ctx ); +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + mbedtls_ecjpake_free( &handshake->ecjpake_ctx ); +#if defined(MBEDTLS_SSL_CLI_C) + mbedtls_free( handshake->ecjpake_cache ); + handshake->ecjpake_cache = NULL; + handshake->ecjpake_cache_len = 0; +#endif +#endif + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + /* explicit void pointer cast for buggy MS compiler */ + mbedtls_free( (void *) handshake->curves ); +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + if( handshake->psk != NULL ) + { + mbedtls_platform_zeroize( handshake->psk, handshake->psk_len ); + mbedtls_free( handshake->psk ); + } +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + /* + * Free only the linked list wrapper, not the keys themselves + * since the belong to the SNI callback + */ + if( handshake->sni_key_cert != NULL ) + { + mbedtls_ssl_key_cert *cur = handshake->sni_key_cert, *next; + + while( cur != NULL ) + { + next = cur->next; + mbedtls_free( cur ); + cur = next; + } + } +#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_SSL__ECP_RESTARTABLE) + mbedtls_x509_crt_restart_free( &handshake->ecrs_ctx ); + if( handshake->ecrs_peer_cert != NULL ) + { + mbedtls_x509_crt_free( handshake->ecrs_peer_cert ); + mbedtls_free( handshake->ecrs_peer_cert ); + } +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + mbedtls_pk_free( &handshake->peer_pubkey ); +#endif /* MBEDTLS_X509_CRT_PARSE_C && !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + mbedtls_free( handshake->verify_cookie ); + ssl_flight_free( handshake->flight ); + ssl_buffering_free( ssl ); +#endif + +#if defined(MBEDTLS_ECDH_C) && \ + defined(MBEDTLS_USE_PSA_CRYPTO) + psa_destroy_key( handshake->ecdh_psa_privkey ); +#endif /* MBEDTLS_ECDH_C && MBEDTLS_USE_PSA_CRYPTO */ + + mbedtls_platform_zeroize( handshake, + sizeof( mbedtls_ssl_handshake_params ) ); +} + +void mbedtls_ssl_session_free( mbedtls_ssl_session *session ) +{ + if( session == NULL ) + return; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + ssl_clear_peer_cert( session ); +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) + mbedtls_free( session->ticket ); +#endif + + mbedtls_platform_zeroize( session, sizeof( mbedtls_ssl_session ) ); +} + +/* + * Free an SSL context + */ +void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) +{ + if( ssl == NULL ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> free" ) ); + + if( ssl->out_buf != NULL ) + { + mbedtls_platform_zeroize( ssl->out_buf, MBEDTLS_SSL_OUT_BUFFER_LEN ); + mbedtls_free( ssl->out_buf ); + } + + if( ssl->in_buf != NULL ) + { + mbedtls_platform_zeroize( ssl->in_buf, MBEDTLS_SSL_IN_BUFFER_LEN ); + mbedtls_free( ssl->in_buf ); + } + +#if defined(MBEDTLS_ZLIB_SUPPORT) + if( ssl->compress_buf != NULL ) + { + mbedtls_platform_zeroize( ssl->compress_buf, MBEDTLS_SSL_COMPRESS_BUFFER_LEN ); + mbedtls_free( ssl->compress_buf ); + } +#endif + + if( ssl->transform ) + { + mbedtls_ssl_transform_free( ssl->transform ); + mbedtls_free( ssl->transform ); + } + + if( ssl->handshake ) + { + mbedtls_ssl_handshake_free( ssl ); + mbedtls_ssl_transform_free( ssl->transform_negotiate ); + mbedtls_ssl_session_free( ssl->session_negotiate ); + + mbedtls_free( ssl->handshake ); + mbedtls_free( ssl->transform_negotiate ); + mbedtls_free( ssl->session_negotiate ); + } + + if( ssl->session ) + { + mbedtls_ssl_session_free( ssl->session ); + mbedtls_free( ssl->session ); + } + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( ssl->hostname != NULL ) + { + mbedtls_platform_zeroize( ssl->hostname, strlen( ssl->hostname ) ); + mbedtls_free( ssl->hostname ); + } +#endif + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_finish != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_finish()" ) ); + mbedtls_ssl_hw_record_finish( ssl ); + } +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + mbedtls_free( ssl->cli_id ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= free" ) ); + + /* Actually clear after last debug message */ + mbedtls_platform_zeroize( ssl, sizeof( mbedtls_ssl_context ) ); +} + +/* + * Initialze mbedtls_ssl_config + */ +void mbedtls_ssl_config_init( mbedtls_ssl_config *conf ) +{ + memset( conf, 0, sizeof( mbedtls_ssl_config ) ); +} + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +static int ssl_preset_default_hashes[] = { +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_MD_SHA512, + MBEDTLS_MD_SHA384, +#endif +#if defined(MBEDTLS_SHA256_C) + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA224, +#endif +#if defined(MBEDTLS_SHA1_C) && defined(MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE) + MBEDTLS_MD_SHA1, +#endif + MBEDTLS_MD_NONE +}; +#endif + +static int ssl_preset_suiteb_ciphersuites[] = { + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + 0 +}; + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +static int ssl_preset_suiteb_hashes[] = { + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA384, + MBEDTLS_MD_NONE +}; +#endif + +#if defined(MBEDTLS_ECP_C) +static mbedtls_ecp_group_id ssl_preset_suiteb_curves[] = { + MBEDTLS_ECP_DP_SECP256R1, + MBEDTLS_ECP_DP_SECP384R1, + MBEDTLS_ECP_DP_NONE +}; +#endif + +/* + * Load default in mbedtls_ssl_config + */ +int mbedtls_ssl_config_defaults( mbedtls_ssl_config *conf, + int endpoint, int transport, int preset ) +{ +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_SRV_C) + int ret; +#endif + + /* Use the functions here so that they are covered in tests, + * but otherwise access member directly for efficiency */ + mbedtls_ssl_conf_endpoint( conf, endpoint ); + mbedtls_ssl_conf_transport( conf, transport ); + + /* + * Things that are common to all presets + */ +#if defined(MBEDTLS_SSL_CLI_C) + if( endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + conf->authmode = MBEDTLS_SSL_VERIFY_REQUIRED; +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + conf->session_tickets = MBEDTLS_SSL_SESSION_TICKETS_ENABLED; +#endif + } +#endif + +#if defined(MBEDTLS_ARC4_C) + conf->arc4_disabled = MBEDTLS_SSL_ARC4_DISABLED; +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + conf->encrypt_then_mac = MBEDTLS_SSL_ETM_ENABLED; +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + conf->extended_ms = MBEDTLS_SSL_EXTENDED_MS_ENABLED; +#endif + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + conf->cbc_record_splitting = MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED; +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + conf->f_cookie_write = ssl_cookie_write_dummy; + conf->f_cookie_check = ssl_cookie_check_dummy; +#endif + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + conf->anti_replay = MBEDTLS_SSL_ANTI_REPLAY_ENABLED; +#endif + +#if defined(MBEDTLS_SSL_SRV_C) + conf->cert_req_ca_list = MBEDTLS_SSL_CERT_REQ_CA_LIST_ENABLED; +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + conf->hs_timeout_min = MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN; + conf->hs_timeout_max = MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MAX; +#endif + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + conf->renego_max_records = MBEDTLS_SSL_RENEGO_MAX_RECORDS_DEFAULT; + memset( conf->renego_period, 0x00, 2 ); + memset( conf->renego_period + 2, 0xFF, 6 ); +#endif + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_SRV_C) + if( endpoint == MBEDTLS_SSL_IS_SERVER ) + { + const unsigned char dhm_p[] = + MBEDTLS_DHM_RFC3526_MODP_2048_P_BIN; + const unsigned char dhm_g[] = + MBEDTLS_DHM_RFC3526_MODP_2048_G_BIN; + + if ( ( ret = mbedtls_ssl_conf_dh_param_bin( conf, + dhm_p, sizeof( dhm_p ), + dhm_g, sizeof( dhm_g ) ) ) != 0 ) + { + return( ret ); + } + } +#endif + + /* + * Preset-specific defaults + */ + switch( preset ) + { + /* + * NSA Suite B + */ + case MBEDTLS_SSL_PRESET_SUITEB: + conf->min_major_ver = MBEDTLS_SSL_MAJOR_VERSION_3; + conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS 1.2 */ + conf->max_major_ver = MBEDTLS_SSL_MAX_MAJOR_VERSION; + conf->max_minor_ver = MBEDTLS_SSL_MAX_MINOR_VERSION; + + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_0] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = + ssl_preset_suiteb_ciphersuites; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + conf->cert_profile = &mbedtls_x509_crt_profile_suiteb; +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + conf->sig_hashes = ssl_preset_suiteb_hashes; +#endif + +#if defined(MBEDTLS_ECP_C) + conf->curve_list = ssl_preset_suiteb_curves; +#endif + break; + + /* + * Default + */ + default: + conf->min_major_ver = ( MBEDTLS_SSL_MIN_MAJOR_VERSION > + MBEDTLS_SSL_MIN_VALID_MAJOR_VERSION ) ? + MBEDTLS_SSL_MIN_MAJOR_VERSION : + MBEDTLS_SSL_MIN_VALID_MAJOR_VERSION; + conf->min_minor_ver = ( MBEDTLS_SSL_MIN_MINOR_VERSION > + MBEDTLS_SSL_MIN_VALID_MINOR_VERSION ) ? + MBEDTLS_SSL_MIN_MINOR_VERSION : + MBEDTLS_SSL_MIN_VALID_MINOR_VERSION; + conf->max_major_ver = MBEDTLS_SSL_MAX_MAJOR_VERSION; + conf->max_minor_ver = MBEDTLS_SSL_MAX_MINOR_VERSION; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_2; +#endif + + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_0] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = + mbedtls_ssl_list_ciphersuites(); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + conf->cert_profile = &mbedtls_x509_crt_profile_default; +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + conf->sig_hashes = ssl_preset_default_hashes; +#endif + +#if defined(MBEDTLS_ECP_C) + conf->curve_list = mbedtls_ecp_grp_id_list(); +#endif + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C) + conf->dhm_min_bitlen = 1024; +#endif + } + + return( 0 ); +} + +/* + * Free mbedtls_ssl_config + */ +void mbedtls_ssl_config_free( mbedtls_ssl_config *conf ) +{ +#if defined(MBEDTLS_DHM_C) + mbedtls_mpi_free( &conf->dhm_P ); + mbedtls_mpi_free( &conf->dhm_G ); +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + if( conf->psk != NULL ) + { + mbedtls_platform_zeroize( conf->psk, conf->psk_len ); + mbedtls_free( conf->psk ); + conf->psk = NULL; + conf->psk_len = 0; + } + + if( conf->psk_identity != NULL ) + { + mbedtls_platform_zeroize( conf->psk_identity, conf->psk_identity_len ); + mbedtls_free( conf->psk_identity ); + conf->psk_identity = NULL; + conf->psk_identity_len = 0; + } +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + ssl_key_cert_free( conf->key_cert ); +#endif + + mbedtls_platform_zeroize( conf, sizeof( mbedtls_ssl_config ) ); +} + +#if defined(MBEDTLS_PK_C) && \ + ( defined(MBEDTLS_RSA_C) || defined(MBEDTLS_ECDSA_C) ) +/* + * Convert between MBEDTLS_PK_XXX and SSL_SIG_XXX + */ +unsigned char mbedtls_ssl_sig_from_pk( mbedtls_pk_context *pk ) +{ +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_can_do( pk, MBEDTLS_PK_RSA ) ) + return( MBEDTLS_SSL_SIG_RSA ); +#endif +#if defined(MBEDTLS_ECDSA_C) + if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECDSA ) ) + return( MBEDTLS_SSL_SIG_ECDSA ); +#endif + return( MBEDTLS_SSL_SIG_ANON ); +} + +unsigned char mbedtls_ssl_sig_from_pk_alg( mbedtls_pk_type_t type ) +{ + switch( type ) { + case MBEDTLS_PK_RSA: + return( MBEDTLS_SSL_SIG_RSA ); + case MBEDTLS_PK_ECDSA: + case MBEDTLS_PK_ECKEY: + return( MBEDTLS_SSL_SIG_ECDSA ); + default: + return( MBEDTLS_SSL_SIG_ANON ); + } +} + +mbedtls_pk_type_t mbedtls_ssl_pk_alg_from_sig( unsigned char sig ) +{ + switch( sig ) + { +#if defined(MBEDTLS_RSA_C) + case MBEDTLS_SSL_SIG_RSA: + return( MBEDTLS_PK_RSA ); +#endif +#if defined(MBEDTLS_ECDSA_C) + case MBEDTLS_SSL_SIG_ECDSA: + return( MBEDTLS_PK_ECDSA ); +#endif + default: + return( MBEDTLS_PK_NONE ); + } +} +#endif /* MBEDTLS_PK_C && ( MBEDTLS_RSA_C || MBEDTLS_ECDSA_C ) */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + +/* Find an entry in a signature-hash set matching a given hash algorithm. */ +mbedtls_md_type_t mbedtls_ssl_sig_hash_set_find( mbedtls_ssl_sig_hash_set_t *set, + mbedtls_pk_type_t sig_alg ) +{ + switch( sig_alg ) + { + case MBEDTLS_PK_RSA: + return( set->rsa ); + case MBEDTLS_PK_ECDSA: + return( set->ecdsa ); + default: + return( MBEDTLS_MD_NONE ); + } +} + +/* Add a signature-hash-pair to a signature-hash set */ +void mbedtls_ssl_sig_hash_set_add( mbedtls_ssl_sig_hash_set_t *set, + mbedtls_pk_type_t sig_alg, + mbedtls_md_type_t md_alg ) +{ + switch( sig_alg ) + { + case MBEDTLS_PK_RSA: + if( set->rsa == MBEDTLS_MD_NONE ) + set->rsa = md_alg; + break; + + case MBEDTLS_PK_ECDSA: + if( set->ecdsa == MBEDTLS_MD_NONE ) + set->ecdsa = md_alg; + break; + + default: + break; + } +} + +/* Allow exactly one hash algorithm for each signature. */ +void mbedtls_ssl_sig_hash_set_const_hash( mbedtls_ssl_sig_hash_set_t *set, + mbedtls_md_type_t md_alg ) +{ + set->rsa = md_alg; + set->ecdsa = md_alg; +} + +#endif /* MBEDTLS_SSL_PROTO_TLS1_2) && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +/* + * Convert from MBEDTLS_SSL_HASH_XXX to MBEDTLS_MD_XXX + */ +mbedtls_md_type_t mbedtls_ssl_md_alg_from_hash( unsigned char hash ) +{ + switch( hash ) + { +#if defined(MBEDTLS_MD5_C) + case MBEDTLS_SSL_HASH_MD5: + return( MBEDTLS_MD_MD5 ); +#endif +#if defined(MBEDTLS_SHA1_C) + case MBEDTLS_SSL_HASH_SHA1: + return( MBEDTLS_MD_SHA1 ); +#endif +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_SSL_HASH_SHA224: + return( MBEDTLS_MD_SHA224 ); + case MBEDTLS_SSL_HASH_SHA256: + return( MBEDTLS_MD_SHA256 ); +#endif +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_SSL_HASH_SHA384: + return( MBEDTLS_MD_SHA384 ); + case MBEDTLS_SSL_HASH_SHA512: + return( MBEDTLS_MD_SHA512 ); +#endif + default: + return( MBEDTLS_MD_NONE ); + } +} + +/* + * Convert from MBEDTLS_MD_XXX to MBEDTLS_SSL_HASH_XXX + */ +unsigned char mbedtls_ssl_hash_from_md_alg( int md ) +{ + switch( md ) + { +#if defined(MBEDTLS_MD5_C) + case MBEDTLS_MD_MD5: + return( MBEDTLS_SSL_HASH_MD5 ); +#endif +#if defined(MBEDTLS_SHA1_C) + case MBEDTLS_MD_SHA1: + return( MBEDTLS_SSL_HASH_SHA1 ); +#endif +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_MD_SHA224: + return( MBEDTLS_SSL_HASH_SHA224 ); + case MBEDTLS_MD_SHA256: + return( MBEDTLS_SSL_HASH_SHA256 ); +#endif +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_MD_SHA384: + return( MBEDTLS_SSL_HASH_SHA384 ); + case MBEDTLS_MD_SHA512: + return( MBEDTLS_SSL_HASH_SHA512 ); +#endif + default: + return( MBEDTLS_SSL_HASH_NONE ); + } +} + +#if defined(MBEDTLS_ECP_C) +/* + * Check if a curve proposed by the peer is in our list. + * Return 0 if we're willing to use it, -1 otherwise. + */ +int mbedtls_ssl_check_curve( const mbedtls_ssl_context *ssl, mbedtls_ecp_group_id grp_id ) +{ + const mbedtls_ecp_group_id *gid; + + if( ssl->conf->curve_list == NULL ) + return( -1 ); + + for( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ ) + if( *gid == grp_id ) + return( 0 ); + + return( -1 ); +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +/* + * Check if a hash proposed by the peer is in our list. + * Return 0 if we're willing to use it, -1 otherwise. + */ +int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl, + mbedtls_md_type_t md ) +{ + const int *cur; + + if( ssl->conf->sig_hashes == NULL ) + return( -1 ); + + for( cur = ssl->conf->sig_hashes; *cur != MBEDTLS_MD_NONE; cur++ ) + if( *cur == (int) md ) + return( 0 ); + + return( -1 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, + const mbedtls_ssl_ciphersuite_t *ciphersuite, + int cert_endpoint, + uint32_t *flags ) +{ + int ret = 0; +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + int usage = 0; +#endif +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) + const char *ext_oid; + size_t ext_len; +#endif + +#if !defined(MBEDTLS_X509_CHECK_KEY_USAGE) && \ + !defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) + ((void) cert); + ((void) cert_endpoint); + ((void) flags); +#endif + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + if( cert_endpoint == MBEDTLS_SSL_IS_SERVER ) + { + /* Server part of the key exchange */ + switch( ciphersuite->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_RSA: + case MBEDTLS_KEY_EXCHANGE_RSA_PSK: + usage = MBEDTLS_X509_KU_KEY_ENCIPHERMENT; + break; + + case MBEDTLS_KEY_EXCHANGE_DHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + usage = MBEDTLS_X509_KU_DIGITAL_SIGNATURE; + break; + + case MBEDTLS_KEY_EXCHANGE_ECDH_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA: + usage = MBEDTLS_X509_KU_KEY_AGREEMENT; + break; + + /* Don't use default: we want warnings when adding new values */ + case MBEDTLS_KEY_EXCHANGE_NONE: + case MBEDTLS_KEY_EXCHANGE_PSK: + case MBEDTLS_KEY_EXCHANGE_DHE_PSK: + case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK: + case MBEDTLS_KEY_EXCHANGE_ECJPAKE: + usage = 0; + } + } + else + { + /* Client auth: we only implement rsa_sign and mbedtls_ecdsa_sign for now */ + usage = MBEDTLS_X509_KU_DIGITAL_SIGNATURE; + } + + if( mbedtls_x509_crt_check_key_usage( cert, usage ) != 0 ) + { + *flags |= MBEDTLS_X509_BADCERT_KEY_USAGE; + ret = -1; + } +#else + ((void) ciphersuite); +#endif /* MBEDTLS_X509_CHECK_KEY_USAGE */ + +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) + if( cert_endpoint == MBEDTLS_SSL_IS_SERVER ) + { + ext_oid = MBEDTLS_OID_SERVER_AUTH; + ext_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_SERVER_AUTH ); + } + else + { + ext_oid = MBEDTLS_OID_CLIENT_AUTH; + ext_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_CLIENT_AUTH ); + } + + if( mbedtls_x509_crt_check_extended_key_usage( cert, ext_oid, ext_len ) != 0 ) + { + *flags |= MBEDTLS_X509_BADCERT_EXT_KEY_USAGE; + ret = -1; + } +#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ + + return( ret ); +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/* + * Convert version numbers to/from wire format + * and, for DTLS, to/from TLS equivalent. + * + * For TLS this is the identity. + * For DTLS, use 1's complement (v -> 255 - v, and then map as follows: + * 1.0 <-> 3.2 (DTLS 1.0 is based on TLS 1.1) + * 1.x <-> 3.x+1 for x != 0 (DTLS 1.2 based on TLS 1.2) + */ +void mbedtls_ssl_write_version( int major, int minor, int transport, + unsigned char ver[2] ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + if( minor == MBEDTLS_SSL_MINOR_VERSION_2 ) + --minor; /* DTLS 1.0 stored as TLS 1.1 internally */ + + ver[0] = (unsigned char)( 255 - ( major - 2 ) ); + ver[1] = (unsigned char)( 255 - ( minor - 1 ) ); + } + else +#else + ((void) transport); +#endif + { + ver[0] = (unsigned char) major; + ver[1] = (unsigned char) minor; + } +} + +void mbedtls_ssl_read_version( int *major, int *minor, int transport, + const unsigned char ver[2] ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + *major = 255 - ver[0] + 2; + *minor = 255 - ver[1] + 1; + + if( *minor == MBEDTLS_SSL_MINOR_VERSION_1 ) + ++*minor; /* DTLS 1.0 stored as TLS 1.1 internally */ + } + else +#else + ((void) transport); +#endif + { + *major = ver[0]; + *minor = ver[1]; + } +} + +int mbedtls_ssl_set_calc_verify_md( mbedtls_ssl_context *ssl, int md ) +{ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) + return MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH; + + switch( md ) + { +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) +#if defined(MBEDTLS_MD5_C) + case MBEDTLS_SSL_HASH_MD5: + return MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH; +#endif +#if defined(MBEDTLS_SHA1_C) + case MBEDTLS_SSL_HASH_SHA1: + ssl->handshake->calc_verify = ssl_calc_verify_tls; + break; +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_SSL_HASH_SHA384: + ssl->handshake->calc_verify = ssl_calc_verify_tls_sha384; + break; +#endif +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_SSL_HASH_SHA256: + ssl->handshake->calc_verify = ssl_calc_verify_tls_sha256; + break; +#endif + default: + return MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH; + } + + return 0; +#else /* !MBEDTLS_SSL_PROTO_TLS1_2 */ + (void) ssl; + (void) md; + + return MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH; +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +} + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) +int mbedtls_ssl_get_key_exchange_md_ssl_tls( mbedtls_ssl_context *ssl, + unsigned char *output, + unsigned char *data, size_t data_len ) +{ + int ret = 0; + mbedtls_md5_context mbedtls_md5; + mbedtls_sha1_context mbedtls_sha1; + + mbedtls_md5_init( &mbedtls_md5 ); + mbedtls_sha1_init( &mbedtls_sha1 ); + + /* + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * + * md5_hash + * MD5(ClientHello.random + ServerHello.random + * + ServerParams); + * sha_hash + * SHA(ClientHello.random + ServerHello.random + * + ServerParams); + */ + if( ( ret = mbedtls_md5_starts_ret( &mbedtls_md5 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md5_starts_ret", ret ); + goto exit; + } + if( ( ret = mbedtls_md5_update_ret( &mbedtls_md5, + ssl->handshake->randbytes, 64 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md5_update_ret", ret ); + goto exit; + } + if( ( ret = mbedtls_md5_update_ret( &mbedtls_md5, data, data_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md5_update_ret", ret ); + goto exit; + } + if( ( ret = mbedtls_md5_finish_ret( &mbedtls_md5, output ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md5_finish_ret", ret ); + goto exit; + } + + if( ( ret = mbedtls_sha1_starts_ret( &mbedtls_sha1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha1_starts_ret", ret ); + goto exit; + } + if( ( ret = mbedtls_sha1_update_ret( &mbedtls_sha1, + ssl->handshake->randbytes, 64 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha1_update_ret", ret ); + goto exit; + } + if( ( ret = mbedtls_sha1_update_ret( &mbedtls_sha1, data, + data_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha1_update_ret", ret ); + goto exit; + } + if( ( ret = mbedtls_sha1_finish_ret( &mbedtls_sha1, + output + 16 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_sha1_finish_ret", ret ); + goto exit; + } + +exit: + mbedtls_md5_free( &mbedtls_md5 ); + mbedtls_sha1_free( &mbedtls_sha1 ); + + if( ret != 0 ) + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR ); + + return( ret ); + +} +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || \ + MBEDTLS_SSL_PROTO_TLS1_1 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl, + unsigned char *hash, size_t *hashlen, + unsigned char *data, size_t data_len, + mbedtls_md_type_t md_alg ) +{ + psa_status_t status; + psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT; + psa_algorithm_t hash_alg = mbedtls_psa_translate_md( md_alg ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Perform PSA-based computation of digest of ServerKeyExchange" ) ); + + if( ( status = psa_hash_setup( &hash_operation, + hash_alg ) ) != PSA_SUCCESS ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "psa_hash_setup", status ); + goto exit; + } + + if( ( status = psa_hash_update( &hash_operation, ssl->handshake->randbytes, + 64 ) ) != PSA_SUCCESS ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "psa_hash_update", status ); + goto exit; + } + + if( ( status = psa_hash_update( &hash_operation, + data, data_len ) ) != PSA_SUCCESS ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "psa_hash_update", status ); + goto exit; + } + + if( ( status = psa_hash_finish( &hash_operation, hash, MBEDTLS_MD_MAX_SIZE, + hashlen ) ) != PSA_SUCCESS ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "psa_hash_finish", status ); + goto exit; + } + +exit: + if( status != PSA_SUCCESS ) + { + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR ); + switch( status ) + { + case PSA_ERROR_NOT_SUPPORTED: + return( MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE ); + case PSA_ERROR_BAD_STATE: /* Intentional fallthrough */ + case PSA_ERROR_BUFFER_TOO_SMALL: + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + case PSA_ERROR_INSUFFICIENT_MEMORY: + return( MBEDTLS_ERR_MD_ALLOC_FAILED ); + default: + return( MBEDTLS_ERR_MD_HW_ACCEL_FAILED ); + } + } + return( 0 ); +} + +#else + +int mbedtls_ssl_get_key_exchange_md_tls1_2( mbedtls_ssl_context *ssl, + unsigned char *hash, size_t *hashlen, + unsigned char *data, size_t data_len, + mbedtls_md_type_t md_alg ) +{ + int ret = 0; + mbedtls_md_context_t ctx; + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); + *hashlen = mbedtls_md_get_size( md_info ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Perform mbedtls-based computation of digest of ServerKeyExchange" ) ); + + mbedtls_md_init( &ctx ); + + /* + * digitally-signed struct { + * opaque client_random[32]; + * opaque server_random[32]; + * ServerDHParams params; + * }; + */ + if( ( ret = mbedtls_md_setup( &ctx, md_info, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_setup", ret ); + goto exit; + } + if( ( ret = mbedtls_md_starts( &ctx ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_starts", ret ); + goto exit; + } + if( ( ret = mbedtls_md_update( &ctx, ssl->handshake->randbytes, 64 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_update", ret ); + goto exit; + } + if( ( ret = mbedtls_md_update( &ctx, data, data_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_update", ret ); + goto exit; + } + if( ( ret = mbedtls_md_finish( &ctx, hash ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_finish", ret ); + goto exit; + } + +exit: + mbedtls_md_free( &ctx ); + + if( ret != 0 ) + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR ); + + return( ret ); +} +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + +#endif /* MBEDTLS_SSL_TLS_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/threading.c b/FreeRTOS-Labs/Source/mbedtls/library/threading.c new file mode 100644 index 000000000..770162bc0 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/threading.c @@ -0,0 +1,187 @@ +/* + * Threading abstraction layer + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * Ensure gmtime_r is available even with -std=c99; must be defined before + * config.h, which pulls in glibc's features.h. Harmless on other platforms. + */ +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 200112L +#endif + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_THREADING_C) + +#include "mbedtls/threading.h" + +#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT) + +#if !defined(_WIN32) && (defined(unix) || \ + defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \ + defined(__MACH__))) +#include +#endif /* !_WIN32 && (unix || __unix || __unix__ || + * (__APPLE__ && __MACH__)) */ + +#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \ + ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \ + _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) +/* + * This is a convenience shorthand macro to avoid checking the long + * preprocessor conditions above. Ideally, we could expose this macro in + * platform_util.h and simply use it in platform_util.c, threading.c and + * threading.h. However, this macro is not part of the Mbed TLS public API, so + * we keep it private by only defining it in this file + */ + +#if ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) +#define THREADING_USE_GMTIME +#endif /* ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) */ + +#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \ + ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \ + _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */ + +#endif /* MBEDTLS_HAVE_TIME_DATE && !MBEDTLS_PLATFORM_GMTIME_R_ALT */ + +#if defined(MBEDTLS_THREADING_PTHREAD) +static void threading_mutex_init_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL ) + return; + + mutex->is_valid = pthread_mutex_init( &mutex->mutex, NULL ) == 0; +} + +static void threading_mutex_free_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL || !mutex->is_valid ) + return; + + (void) pthread_mutex_destroy( &mutex->mutex ); + mutex->is_valid = 0; +} + +static int threading_mutex_lock_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL || ! mutex->is_valid ) + return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA ); + + if( pthread_mutex_lock( &mutex->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + + return( 0 ); +} + +static int threading_mutex_unlock_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL || ! mutex->is_valid ) + return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA ); + + if( pthread_mutex_unlock( &mutex->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + + return( 0 ); +} + +void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t * ) = threading_mutex_init_pthread; +void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t * ) = threading_mutex_free_pthread; +int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t * ) = threading_mutex_lock_pthread; +int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t * ) = threading_mutex_unlock_pthread; + +/* + * With phtreads we can statically initialize mutexes + */ +#define MUTEX_INIT = { PTHREAD_MUTEX_INITIALIZER, 1 } + +#endif /* MBEDTLS_THREADING_PTHREAD */ + +#if defined(MBEDTLS_THREADING_ALT) +static int threading_mutex_fail( mbedtls_threading_mutex_t *mutex ) +{ + ((void) mutex ); + return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA ); +} +static void threading_mutex_dummy( mbedtls_threading_mutex_t *mutex ) +{ + ((void) mutex ); + return; +} + +void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t * ) = threading_mutex_dummy; +void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t * ) = threading_mutex_dummy; +int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t * ) = threading_mutex_fail; +int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t * ) = threading_mutex_fail; + +/* + * Set functions pointers and initialize global mutexes + */ +void mbedtls_threading_set_alt( void (*mutex_init)( mbedtls_threading_mutex_t * ), + void (*mutex_free)( mbedtls_threading_mutex_t * ), + int (*mutex_lock)( mbedtls_threading_mutex_t * ), + int (*mutex_unlock)( mbedtls_threading_mutex_t * ) ) +{ + mbedtls_mutex_init = mutex_init; + mbedtls_mutex_free = mutex_free; + mbedtls_mutex_lock = mutex_lock; + mbedtls_mutex_unlock = mutex_unlock; + +#if defined(MBEDTLS_FS_IO) + mbedtls_mutex_init( &mbedtls_threading_readdir_mutex ); +#endif +#if defined(THREADING_USE_GMTIME) + mbedtls_mutex_init( &mbedtls_threading_gmtime_mutex ); +#endif +} + +/* + * Free global mutexes + */ +void mbedtls_threading_free_alt( void ) +{ +#if defined(MBEDTLS_FS_IO) + mbedtls_mutex_free( &mbedtls_threading_readdir_mutex ); +#endif +#if defined(THREADING_USE_GMTIME) + mbedtls_mutex_free( &mbedtls_threading_gmtime_mutex ); +#endif +} +#endif /* MBEDTLS_THREADING_ALT */ + +/* + * Define global mutexes + */ +#ifndef MUTEX_INIT +#define MUTEX_INIT +#endif +#if defined(MBEDTLS_FS_IO) +mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex MUTEX_INIT; +#endif +#if defined(THREADING_USE_GMTIME) +mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex MUTEX_INIT; +#endif + +#endif /* MBEDTLS_THREADING_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/timing.c b/FreeRTOS-Labs/Source/mbedtls/library/timing.c new file mode 100644 index 000000000..082fcf6c1 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/timing.c @@ -0,0 +1,537 @@ +/* + * Portable interface to the CPU cycle counter + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif + +#if defined(MBEDTLS_TIMING_C) + +#include "mbedtls/timing.h" + +#if !defined(MBEDTLS_TIMING_ALT) + +#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ + !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ + !defined(__HAIKU__) +#error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h" +#endif + +#ifndef asm +#define asm __asm +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + +#include +#include +#include + +struct _hr_time +{ + LARGE_INTEGER start; +}; + +#else + +#include +#include +#include +#include +#include + +struct _hr_time +{ + struct timeval start; +}; + +#endif /* _WIN32 && !EFIX64 && !EFI32 */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + ( defined(_MSC_VER) && defined(_M_IX86) ) || defined(__WATCOMC__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tsc; + __asm rdtsc + __asm mov [tsc], eax + return( tsc ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */ + +/* some versions of mingw-64 have 32-bit longs even on x84_64 */ +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && ( defined(__i386__) || ( \ + ( defined(__amd64__) || defined( __x86_64__) ) && __SIZEOF_LONG__ == 4 ) ) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long lo, hi; + asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); + return( lo ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __i386__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && ( defined(__amd64__) || defined(__x86_64__) ) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long lo, hi; + asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); + return( lo | ( hi << 32 ) ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && ( __amd64__ || __x86_64__ ) */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && ( defined(__powerpc__) || defined(__ppc__) ) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tbl, tbu0, tbu1; + + do + { + asm volatile( "mftbu %0" : "=r" (tbu0) ); + asm volatile( "mftb %0" : "=r" (tbl ) ); + asm volatile( "mftbu %0" : "=r" (tbu1) ); + } + while( tbu0 != tbu1 ); + + return( tbl ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && ( __powerpc__ || __ppc__ ) */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__sparc64__) + +#if defined(__OpenBSD__) +#warning OpenBSD does not allow access to tick register using software version instead +#else +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tick; + asm volatile( "rdpr %%tick, %0;" : "=&r" (tick) ); + return( tick ); +} +#endif /* __OpenBSD__ */ +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __sparc64__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tick; + asm volatile( ".byte 0x83, 0x41, 0x00, 0x00" ); + asm volatile( "mov %%g1, %0" : "=r" (tick) ); + return( tick ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __sparc__ && !__sparc64__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__alpha__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long cc; + asm volatile( "rpcc %0" : "=r" (cc) ); + return( cc & 0xFFFFFFFF ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __alpha__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__ia64__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long itc; + asm volatile( "mov %0 = ar.itc" : "=r" (itc) ); + return( itc ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __ia64__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \ + !defined(EFIX64) && !defined(EFI32) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + LARGE_INTEGER offset; + + QueryPerformanceCounter( &offset ); + + return( (unsigned long)( offset.QuadPart ) ); +} +#endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */ + +#if !defined(HAVE_HARDCLOCK) + +#define HAVE_HARDCLOCK + +static int hardclock_init = 0; +static struct timeval tv_init; + +unsigned long mbedtls_timing_hardclock( void ) +{ + struct timeval tv_cur; + + if( hardclock_init == 0 ) + { + gettimeofday( &tv_init, NULL ); + hardclock_init = 1; + } + + gettimeofday( &tv_cur, NULL ); + return( ( tv_cur.tv_sec - tv_init.tv_sec ) * 1000000 + + ( tv_cur.tv_usec - tv_init.tv_usec ) ); +} +#endif /* !HAVE_HARDCLOCK */ + +volatile int mbedtls_timing_alarmed = 0; + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + +unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) +{ + struct _hr_time *t = (struct _hr_time *) val; + + if( reset ) + { + QueryPerformanceCounter( &t->start ); + return( 0 ); + } + else + { + unsigned long delta; + LARGE_INTEGER now, hfreq; + QueryPerformanceCounter( &now ); + QueryPerformanceFrequency( &hfreq ); + delta = (unsigned long)( ( now.QuadPart - t->start.QuadPart ) * 1000ul + / hfreq.QuadPart ); + return( delta ); + } +} + +/* It's OK to use a global because alarm() is supposed to be global anyway */ +static DWORD alarmMs; + +static void TimerProc( void *TimerContext ) +{ + (void) TimerContext; + Sleep( alarmMs ); + mbedtls_timing_alarmed = 1; + /* _endthread will be called implicitly on return + * That ensures execution of thread funcition's epilogue */ +} + +void mbedtls_set_alarm( int seconds ) +{ + if( seconds == 0 ) + { + /* No need to create a thread for this simple case. + * Also, this shorcut is more reliable at least on MinGW32 */ + mbedtls_timing_alarmed = 1; + return; + } + + mbedtls_timing_alarmed = 0; + alarmMs = seconds * 1000; + (void) _beginthread( TimerProc, 0, NULL ); +} + +#else /* _WIN32 && !EFIX64 && !EFI32 */ + +unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) +{ + struct _hr_time *t = (struct _hr_time *) val; + + if( reset ) + { + gettimeofday( &t->start, NULL ); + return( 0 ); + } + else + { + unsigned long delta; + struct timeval now; + gettimeofday( &now, NULL ); + delta = ( now.tv_sec - t->start.tv_sec ) * 1000ul + + ( now.tv_usec - t->start.tv_usec ) / 1000; + return( delta ); + } +} + +static void sighandler( int signum ) +{ + mbedtls_timing_alarmed = 1; + signal( signum, sighandler ); +} + +void mbedtls_set_alarm( int seconds ) +{ + mbedtls_timing_alarmed = 0; + signal( SIGALRM, sighandler ); + alarm( seconds ); + if( seconds == 0 ) + { + /* alarm(0) cancelled any previous pending alarm, but the + handler won't fire, so raise the flag straight away. */ + mbedtls_timing_alarmed = 1; + } +} + +#endif /* _WIN32 && !EFIX64 && !EFI32 */ + +/* + * Set delays to watch + */ +void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ) +{ + mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; + + ctx->int_ms = int_ms; + ctx->fin_ms = fin_ms; + + if( fin_ms != 0 ) + (void) mbedtls_timing_get_timer( &ctx->timer, 1 ); +} + +/* + * Get number of delays expired + */ +int mbedtls_timing_get_delay( void *data ) +{ + mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; + unsigned long elapsed_ms; + + if( ctx->fin_ms == 0 ) + return( -1 ); + + elapsed_ms = mbedtls_timing_get_timer( &ctx->timer, 0 ); + + if( elapsed_ms >= ctx->fin_ms ) + return( 2 ); + + if( elapsed_ms >= ctx->int_ms ) + return( 1 ); + + return( 0 ); +} + +#endif /* !MBEDTLS_TIMING_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Busy-waits for the given number of milliseconds. + * Used for testing mbedtls_timing_hardclock. + */ +static void busy_msleep( unsigned long msec ) +{ + struct mbedtls_timing_hr_time hires; + unsigned long i = 0; /* for busy-waiting */ + volatile unsigned long j; /* to prevent optimisation */ + + (void) mbedtls_timing_get_timer( &hires, 1 ); + + while( mbedtls_timing_get_timer( &hires, 0 ) < msec ) + i++; + + j = i; + (void) j; +} + +#define FAIL do \ + { \ + if( verbose != 0 ) \ + { \ + mbedtls_printf( "failed at line %d\n", __LINE__ ); \ + mbedtls_printf( " cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \ + cycles, ratio, millisecs, secs, hardfail, \ + (unsigned long) a, (unsigned long) b ); \ + mbedtls_printf( " elapsed(hires)=%lu elapsed(ctx)=%lu status(ctx)=%d\n", \ + mbedtls_timing_get_timer( &hires, 0 ), \ + mbedtls_timing_get_timer( &ctx.timer, 0 ), \ + mbedtls_timing_get_delay( &ctx ) ); \ + } \ + return( 1 ); \ + } while( 0 ) + +/* + * Checkup routine + * + * Warning: this is work in progress, some tests may not be reliable enough + * yet! False positives may happen. + */ +int mbedtls_timing_self_test( int verbose ) +{ + unsigned long cycles = 0, ratio = 0; + unsigned long millisecs = 0, secs = 0; + int hardfail = 0; + struct mbedtls_timing_hr_time hires; + uint32_t a = 0, b = 0; + mbedtls_timing_delay_context ctx; + + if( verbose != 0 ) + mbedtls_printf( " TIMING tests note: will take some time!\n" ); + + if( verbose != 0 ) + mbedtls_printf( " TIMING test #1 (set_alarm / get_timer): " ); + + { + secs = 1; + + (void) mbedtls_timing_get_timer( &hires, 1 ); + + mbedtls_set_alarm( (int) secs ); + while( !mbedtls_timing_alarmed ) + ; + + millisecs = mbedtls_timing_get_timer( &hires, 0 ); + + /* For some reason on Windows it looks like alarm has an extra delay + * (maybe related to creating a new thread). Allow some room here. */ + if( millisecs < 800 * secs || millisecs > 1200 * secs + 300 ) + FAIL; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " TIMING test #2 (set/get_delay ): " ); + + { + a = 800; + b = 400; + mbedtls_timing_set_delay( &ctx, a, a + b ); /* T = 0 */ + + busy_msleep( a - a / 4 ); /* T = a - a/4 */ + if( mbedtls_timing_get_delay( &ctx ) != 0 ) + FAIL; + + busy_msleep( a / 4 + b / 4 ); /* T = a + b/4 */ + if( mbedtls_timing_get_delay( &ctx ) != 1 ) + FAIL; + + busy_msleep( b ); /* T = a + b + b/4 */ + if( mbedtls_timing_get_delay( &ctx ) != 2 ) + FAIL; + } + + mbedtls_timing_set_delay( &ctx, 0, 0 ); + busy_msleep( 200 ); + if( mbedtls_timing_get_delay( &ctx ) != -1 ) + FAIL; + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " TIMING test #3 (hardclock / get_timer): " ); + + /* + * Allow one failure for possible counter wrapping. + * On a 4Ghz 32-bit machine the cycle counter wraps about once per second; + * since the whole test is about 10ms, it shouldn't happen twice in a row. + */ + +hard_test: + if( hardfail > 1 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed (ignored)\n" ); + + goto hard_test_done; + } + + /* Get a reference ratio cycles/ms */ + millisecs = 1; + cycles = mbedtls_timing_hardclock(); + busy_msleep( millisecs ); + cycles = mbedtls_timing_hardclock() - cycles; + ratio = cycles / millisecs; + + /* Check that the ratio is mostly constant */ + for( millisecs = 2; millisecs <= 4; millisecs++ ) + { + cycles = mbedtls_timing_hardclock(); + busy_msleep( millisecs ); + cycles = mbedtls_timing_hardclock() - cycles; + + /* Allow variation up to 20% */ + if( cycles / millisecs < ratio - ratio / 5 || + cycles / millisecs > ratio + ratio / 5 ) + { + hardfail++; + goto hard_test; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +hard_test_done: + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_TIMING_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/version.c b/FreeRTOS-Labs/Source/mbedtls/library/version.c new file mode 100644 index 000000000..c45731d8a --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/version.c @@ -0,0 +1,50 @@ +/* + * Version information + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_VERSION_C) + +#include "mbedtls/version.h" +#include + +unsigned int mbedtls_version_get_number( void ) +{ + return( MBEDTLS_VERSION_NUMBER ); +} + +void mbedtls_version_get_string( char *string ) +{ + memcpy( string, MBEDTLS_VERSION_STRING, + sizeof( MBEDTLS_VERSION_STRING ) ); +} + +void mbedtls_version_get_string_full( char *string ) +{ + memcpy( string, MBEDTLS_VERSION_STRING_FULL, + sizeof( MBEDTLS_VERSION_STRING_FULL ) ); +} + +#endif /* MBEDTLS_VERSION_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/version_features.c b/FreeRTOS-Labs/Source/mbedtls/library/version_features.c new file mode 100644 index 000000000..0bb30bdff --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/version_features.c @@ -0,0 +1,812 @@ +/* + * Version feature information + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_VERSION_C) + +#include "mbedtls/version.h" + +#include + +static const char *features[] = { +#if defined(MBEDTLS_VERSION_FEATURES) +#if defined(MBEDTLS_HAVE_ASM) + "MBEDTLS_HAVE_ASM", +#endif /* MBEDTLS_HAVE_ASM */ +#if defined(MBEDTLS_NO_UDBL_DIVISION) + "MBEDTLS_NO_UDBL_DIVISION", +#endif /* MBEDTLS_NO_UDBL_DIVISION */ +#if defined(MBEDTLS_NO_64BIT_MULTIPLICATION) + "MBEDTLS_NO_64BIT_MULTIPLICATION", +#endif /* MBEDTLS_NO_64BIT_MULTIPLICATION */ +#if defined(MBEDTLS_HAVE_SSE2) + "MBEDTLS_HAVE_SSE2", +#endif /* MBEDTLS_HAVE_SSE2 */ +#if defined(MBEDTLS_HAVE_TIME) + "MBEDTLS_HAVE_TIME", +#endif /* MBEDTLS_HAVE_TIME */ +#if defined(MBEDTLS_HAVE_TIME_DATE) + "MBEDTLS_HAVE_TIME_DATE", +#endif /* MBEDTLS_HAVE_TIME_DATE */ +#if defined(MBEDTLS_PLATFORM_MEMORY) + "MBEDTLS_PLATFORM_MEMORY", +#endif /* MBEDTLS_PLATFORM_MEMORY */ +#if defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) + "MBEDTLS_PLATFORM_NO_STD_FUNCTIONS", +#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */ +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) + "MBEDTLS_PLATFORM_EXIT_ALT", +#endif /* MBEDTLS_PLATFORM_EXIT_ALT */ +#if defined(MBEDTLS_PLATFORM_TIME_ALT) + "MBEDTLS_PLATFORM_TIME_ALT", +#endif /* MBEDTLS_PLATFORM_TIME_ALT */ +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) + "MBEDTLS_PLATFORM_FPRINTF_ALT", +#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) + "MBEDTLS_PLATFORM_PRINTF_ALT", +#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) + "MBEDTLS_PLATFORM_SNPRINTF_ALT", +#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_VSNPRINTF_ALT) + "MBEDTLS_PLATFORM_VSNPRINTF_ALT", +#endif /* MBEDTLS_PLATFORM_VSNPRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) + "MBEDTLS_PLATFORM_NV_SEED_ALT", +#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */ +#if defined(MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT) + "MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT", +#endif /* MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT */ +#if defined(MBEDTLS_DEPRECATED_WARNING) + "MBEDTLS_DEPRECATED_WARNING", +#endif /* MBEDTLS_DEPRECATED_WARNING */ +#if defined(MBEDTLS_DEPRECATED_REMOVED) + "MBEDTLS_DEPRECATED_REMOVED", +#endif /* MBEDTLS_DEPRECATED_REMOVED */ +#if defined(MBEDTLS_CHECK_PARAMS) + "MBEDTLS_CHECK_PARAMS", +#endif /* MBEDTLS_CHECK_PARAMS */ +#if defined(MBEDTLS_TIMING_ALT) + "MBEDTLS_TIMING_ALT", +#endif /* MBEDTLS_TIMING_ALT */ +#if defined(MBEDTLS_AES_ALT) + "MBEDTLS_AES_ALT", +#endif /* MBEDTLS_AES_ALT */ +#if defined(MBEDTLS_ARC4_ALT) + "MBEDTLS_ARC4_ALT", +#endif /* MBEDTLS_ARC4_ALT */ +#if defined(MBEDTLS_ARIA_ALT) + "MBEDTLS_ARIA_ALT", +#endif /* MBEDTLS_ARIA_ALT */ +#if defined(MBEDTLS_BLOWFISH_ALT) + "MBEDTLS_BLOWFISH_ALT", +#endif /* MBEDTLS_BLOWFISH_ALT */ +#if defined(MBEDTLS_CAMELLIA_ALT) + "MBEDTLS_CAMELLIA_ALT", +#endif /* MBEDTLS_CAMELLIA_ALT */ +#if defined(MBEDTLS_CCM_ALT) + "MBEDTLS_CCM_ALT", +#endif /* MBEDTLS_CCM_ALT */ +#if defined(MBEDTLS_CHACHA20_ALT) + "MBEDTLS_CHACHA20_ALT", +#endif /* MBEDTLS_CHACHA20_ALT */ +#if defined(MBEDTLS_CHACHAPOLY_ALT) + "MBEDTLS_CHACHAPOLY_ALT", +#endif /* MBEDTLS_CHACHAPOLY_ALT */ +#if defined(MBEDTLS_CMAC_ALT) + "MBEDTLS_CMAC_ALT", +#endif /* MBEDTLS_CMAC_ALT */ +#if defined(MBEDTLS_DES_ALT) + "MBEDTLS_DES_ALT", +#endif /* MBEDTLS_DES_ALT */ +#if defined(MBEDTLS_DHM_ALT) + "MBEDTLS_DHM_ALT", +#endif /* MBEDTLS_DHM_ALT */ +#if defined(MBEDTLS_ECJPAKE_ALT) + "MBEDTLS_ECJPAKE_ALT", +#endif /* MBEDTLS_ECJPAKE_ALT */ +#if defined(MBEDTLS_GCM_ALT) + "MBEDTLS_GCM_ALT", +#endif /* MBEDTLS_GCM_ALT */ +#if defined(MBEDTLS_NIST_KW_ALT) + "MBEDTLS_NIST_KW_ALT", +#endif /* MBEDTLS_NIST_KW_ALT */ +#if defined(MBEDTLS_MD2_ALT) + "MBEDTLS_MD2_ALT", +#endif /* MBEDTLS_MD2_ALT */ +#if defined(MBEDTLS_MD4_ALT) + "MBEDTLS_MD4_ALT", +#endif /* MBEDTLS_MD4_ALT */ +#if defined(MBEDTLS_MD5_ALT) + "MBEDTLS_MD5_ALT", +#endif /* MBEDTLS_MD5_ALT */ +#if defined(MBEDTLS_POLY1305_ALT) + "MBEDTLS_POLY1305_ALT", +#endif /* MBEDTLS_POLY1305_ALT */ +#if defined(MBEDTLS_RIPEMD160_ALT) + "MBEDTLS_RIPEMD160_ALT", +#endif /* MBEDTLS_RIPEMD160_ALT */ +#if defined(MBEDTLS_RSA_ALT) + "MBEDTLS_RSA_ALT", +#endif /* MBEDTLS_RSA_ALT */ +#if defined(MBEDTLS_SHA1_ALT) + "MBEDTLS_SHA1_ALT", +#endif /* MBEDTLS_SHA1_ALT */ +#if defined(MBEDTLS_SHA256_ALT) + "MBEDTLS_SHA256_ALT", +#endif /* MBEDTLS_SHA256_ALT */ +#if defined(MBEDTLS_SHA512_ALT) + "MBEDTLS_SHA512_ALT", +#endif /* MBEDTLS_SHA512_ALT */ +#if defined(MBEDTLS_XTEA_ALT) + "MBEDTLS_XTEA_ALT", +#endif /* MBEDTLS_XTEA_ALT */ +#if defined(MBEDTLS_ECP_ALT) + "MBEDTLS_ECP_ALT", +#endif /* MBEDTLS_ECP_ALT */ +#if defined(MBEDTLS_MD2_PROCESS_ALT) + "MBEDTLS_MD2_PROCESS_ALT", +#endif /* MBEDTLS_MD2_PROCESS_ALT */ +#if defined(MBEDTLS_MD4_PROCESS_ALT) + "MBEDTLS_MD4_PROCESS_ALT", +#endif /* MBEDTLS_MD4_PROCESS_ALT */ +#if defined(MBEDTLS_MD5_PROCESS_ALT) + "MBEDTLS_MD5_PROCESS_ALT", +#endif /* MBEDTLS_MD5_PROCESS_ALT */ +#if defined(MBEDTLS_RIPEMD160_PROCESS_ALT) + "MBEDTLS_RIPEMD160_PROCESS_ALT", +#endif /* MBEDTLS_RIPEMD160_PROCESS_ALT */ +#if defined(MBEDTLS_SHA1_PROCESS_ALT) + "MBEDTLS_SHA1_PROCESS_ALT", +#endif /* MBEDTLS_SHA1_PROCESS_ALT */ +#if defined(MBEDTLS_SHA256_PROCESS_ALT) + "MBEDTLS_SHA256_PROCESS_ALT", +#endif /* MBEDTLS_SHA256_PROCESS_ALT */ +#if defined(MBEDTLS_SHA512_PROCESS_ALT) + "MBEDTLS_SHA512_PROCESS_ALT", +#endif /* MBEDTLS_SHA512_PROCESS_ALT */ +#if defined(MBEDTLS_DES_SETKEY_ALT) + "MBEDTLS_DES_SETKEY_ALT", +#endif /* MBEDTLS_DES_SETKEY_ALT */ +#if defined(MBEDTLS_DES_CRYPT_ECB_ALT) + "MBEDTLS_DES_CRYPT_ECB_ALT", +#endif /* MBEDTLS_DES_CRYPT_ECB_ALT */ +#if defined(MBEDTLS_DES3_CRYPT_ECB_ALT) + "MBEDTLS_DES3_CRYPT_ECB_ALT", +#endif /* MBEDTLS_DES3_CRYPT_ECB_ALT */ +#if defined(MBEDTLS_AES_SETKEY_ENC_ALT) + "MBEDTLS_AES_SETKEY_ENC_ALT", +#endif /* MBEDTLS_AES_SETKEY_ENC_ALT */ +#if defined(MBEDTLS_AES_SETKEY_DEC_ALT) + "MBEDTLS_AES_SETKEY_DEC_ALT", +#endif /* MBEDTLS_AES_SETKEY_DEC_ALT */ +#if defined(MBEDTLS_AES_ENCRYPT_ALT) + "MBEDTLS_AES_ENCRYPT_ALT", +#endif /* MBEDTLS_AES_ENCRYPT_ALT */ +#if defined(MBEDTLS_AES_DECRYPT_ALT) + "MBEDTLS_AES_DECRYPT_ALT", +#endif /* MBEDTLS_AES_DECRYPT_ALT */ +#if defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT) + "MBEDTLS_ECDH_GEN_PUBLIC_ALT", +#endif /* MBEDTLS_ECDH_GEN_PUBLIC_ALT */ +#if defined(MBEDTLS_ECDH_COMPUTE_SHARED_ALT) + "MBEDTLS_ECDH_COMPUTE_SHARED_ALT", +#endif /* MBEDTLS_ECDH_COMPUTE_SHARED_ALT */ +#if defined(MBEDTLS_ECDSA_VERIFY_ALT) + "MBEDTLS_ECDSA_VERIFY_ALT", +#endif /* MBEDTLS_ECDSA_VERIFY_ALT */ +#if defined(MBEDTLS_ECDSA_SIGN_ALT) + "MBEDTLS_ECDSA_SIGN_ALT", +#endif /* MBEDTLS_ECDSA_SIGN_ALT */ +#if defined(MBEDTLS_ECDSA_GENKEY_ALT) + "MBEDTLS_ECDSA_GENKEY_ALT", +#endif /* MBEDTLS_ECDSA_GENKEY_ALT */ +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + "MBEDTLS_ECP_INTERNAL_ALT", +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ +#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) + "MBEDTLS_ECP_RANDOMIZE_JAC_ALT", +#endif /* MBEDTLS_ECP_RANDOMIZE_JAC_ALT */ +#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) + "MBEDTLS_ECP_ADD_MIXED_ALT", +#endif /* MBEDTLS_ECP_ADD_MIXED_ALT */ +#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) + "MBEDTLS_ECP_DOUBLE_JAC_ALT", +#endif /* MBEDTLS_ECP_DOUBLE_JAC_ALT */ +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) + "MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT", +#endif /* MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT */ +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) + "MBEDTLS_ECP_NORMALIZE_JAC_ALT", +#endif /* MBEDTLS_ECP_NORMALIZE_JAC_ALT */ +#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) + "MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT", +#endif /* MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT */ +#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) + "MBEDTLS_ECP_RANDOMIZE_MXZ_ALT", +#endif /* MBEDTLS_ECP_RANDOMIZE_MXZ_ALT */ +#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) + "MBEDTLS_ECP_NORMALIZE_MXZ_ALT", +#endif /* MBEDTLS_ECP_NORMALIZE_MXZ_ALT */ +#if defined(MBEDTLS_TEST_NULL_ENTROPY) + "MBEDTLS_TEST_NULL_ENTROPY", +#endif /* MBEDTLS_TEST_NULL_ENTROPY */ +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + "MBEDTLS_ENTROPY_HARDWARE_ALT", +#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ +#if defined(MBEDTLS_AES_ROM_TABLES) + "MBEDTLS_AES_ROM_TABLES", +#endif /* MBEDTLS_AES_ROM_TABLES */ +#if defined(MBEDTLS_AES_FEWER_TABLES) + "MBEDTLS_AES_FEWER_TABLES", +#endif /* MBEDTLS_AES_FEWER_TABLES */ +#if defined(MBEDTLS_CAMELLIA_SMALL_MEMORY) + "MBEDTLS_CAMELLIA_SMALL_MEMORY", +#endif /* MBEDTLS_CAMELLIA_SMALL_MEMORY */ +#if defined(MBEDTLS_CIPHER_MODE_CBC) + "MBEDTLS_CIPHER_MODE_CBC", +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_CIPHER_MODE_CFB) + "MBEDTLS_CIPHER_MODE_CFB", +#endif /* MBEDTLS_CIPHER_MODE_CFB */ +#if defined(MBEDTLS_CIPHER_MODE_CTR) + "MBEDTLS_CIPHER_MODE_CTR", +#endif /* MBEDTLS_CIPHER_MODE_CTR */ +#if defined(MBEDTLS_CIPHER_MODE_OFB) + "MBEDTLS_CIPHER_MODE_OFB", +#endif /* MBEDTLS_CIPHER_MODE_OFB */ +#if defined(MBEDTLS_CIPHER_MODE_XTS) + "MBEDTLS_CIPHER_MODE_XTS", +#endif /* MBEDTLS_CIPHER_MODE_XTS */ +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) + "MBEDTLS_CIPHER_NULL_CIPHER", +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) + "MBEDTLS_CIPHER_PADDING_PKCS7", +#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ +#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) + "MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS", +#endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */ +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) + "MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN", +#endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */ +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS) + "MBEDTLS_CIPHER_PADDING_ZEROS", +#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */ +#if defined(MBEDTLS_ENABLE_WEAK_CIPHERSUITES) + "MBEDTLS_ENABLE_WEAK_CIPHERSUITES", +#endif /* MBEDTLS_ENABLE_WEAK_CIPHERSUITES */ +#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES) + "MBEDTLS_REMOVE_ARC4_CIPHERSUITES", +#endif /* MBEDTLS_REMOVE_ARC4_CIPHERSUITES */ +#if defined(MBEDTLS_REMOVE_3DES_CIPHERSUITES) + "MBEDTLS_REMOVE_3DES_CIPHERSUITES", +#endif /* MBEDTLS_REMOVE_3DES_CIPHERSUITES */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + "MBEDTLS_ECP_DP_SECP192R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + "MBEDTLS_ECP_DP_SECP224R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + "MBEDTLS_ECP_DP_SECP256R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + "MBEDTLS_ECP_DP_SECP384R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + "MBEDTLS_ECP_DP_SECP521R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + "MBEDTLS_ECP_DP_SECP192K1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + "MBEDTLS_ECP_DP_SECP224K1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + "MBEDTLS_ECP_DP_SECP256K1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + "MBEDTLS_ECP_DP_BP256R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + "MBEDTLS_ECP_DP_BP384R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + "MBEDTLS_ECP_DP_BP512R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + "MBEDTLS_ECP_DP_CURVE25519_ENABLED", +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + "MBEDTLS_ECP_DP_CURVE448_ENABLED", +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ +#if defined(MBEDTLS_ECP_NIST_OPTIM) + "MBEDTLS_ECP_NIST_OPTIM", +#endif /* MBEDTLS_ECP_NIST_OPTIM */ +#if defined(MBEDTLS_ECP_RESTARTABLE) + "MBEDTLS_ECP_RESTARTABLE", +#endif /* MBEDTLS_ECP_RESTARTABLE */ +#if defined(MBEDTLS_ECDH_LEGACY_CONTEXT) + "MBEDTLS_ECDH_LEGACY_CONTEXT", +#endif /* MBEDTLS_ECDH_LEGACY_CONTEXT */ +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + "MBEDTLS_ECDSA_DETERMINISTIC", +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + "MBEDTLS_KEY_EXCHANGE_PSK_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + "MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + "MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_RSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) + "MBEDTLS_PK_PARSE_EC_EXTENDED", +#endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */ +#if defined(MBEDTLS_ERROR_STRERROR_DUMMY) + "MBEDTLS_ERROR_STRERROR_DUMMY", +#endif /* MBEDTLS_ERROR_STRERROR_DUMMY */ +#if defined(MBEDTLS_GENPRIME) + "MBEDTLS_GENPRIME", +#endif /* MBEDTLS_GENPRIME */ +#if defined(MBEDTLS_FS_IO) + "MBEDTLS_FS_IO", +#endif /* MBEDTLS_FS_IO */ +#if defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) + "MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES", +#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */ +#if defined(MBEDTLS_NO_PLATFORM_ENTROPY) + "MBEDTLS_NO_PLATFORM_ENTROPY", +#endif /* MBEDTLS_NO_PLATFORM_ENTROPY */ +#if defined(MBEDTLS_ENTROPY_FORCE_SHA256) + "MBEDTLS_ENTROPY_FORCE_SHA256", +#endif /* MBEDTLS_ENTROPY_FORCE_SHA256 */ +#if defined(MBEDTLS_ENTROPY_NV_SEED) + "MBEDTLS_ENTROPY_NV_SEED", +#endif /* MBEDTLS_ENTROPY_NV_SEED */ +#if defined(MBEDTLS_MEMORY_DEBUG) + "MBEDTLS_MEMORY_DEBUG", +#endif /* MBEDTLS_MEMORY_DEBUG */ +#if defined(MBEDTLS_MEMORY_BACKTRACE) + "MBEDTLS_MEMORY_BACKTRACE", +#endif /* MBEDTLS_MEMORY_BACKTRACE */ +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) + "MBEDTLS_PK_RSA_ALT_SUPPORT", +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ +#if defined(MBEDTLS_PKCS1_V15) + "MBEDTLS_PKCS1_V15", +#endif /* MBEDTLS_PKCS1_V15 */ +#if defined(MBEDTLS_PKCS1_V21) + "MBEDTLS_PKCS1_V21", +#endif /* MBEDTLS_PKCS1_V21 */ +#if defined(MBEDTLS_PSA_CRYPTO_SPM) + "MBEDTLS_PSA_CRYPTO_SPM", +#endif /* MBEDTLS_PSA_CRYPTO_SPM */ +#if defined(MBEDTLS_PSA_INJECT_ENTROPY) + "MBEDTLS_PSA_INJECT_ENTROPY", +#endif /* MBEDTLS_PSA_INJECT_ENTROPY */ +#if defined(MBEDTLS_RSA_NO_CRT) + "MBEDTLS_RSA_NO_CRT", +#endif /* MBEDTLS_RSA_NO_CRT */ +#if defined(MBEDTLS_SELF_TEST) + "MBEDTLS_SELF_TEST", +#endif /* MBEDTLS_SELF_TEST */ +#if defined(MBEDTLS_SHA256_SMALLER) + "MBEDTLS_SHA256_SMALLER", +#endif /* MBEDTLS_SHA256_SMALLER */ +#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) + "MBEDTLS_SSL_ALL_ALERT_MESSAGES", +#endif /* MBEDTLS_SSL_ALL_ALERT_MESSAGES */ +#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID) + "MBEDTLS_SSL_DTLS_CONNECTION_ID", +#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */ +#if defined(MBEDTLS_SSL_ASYNC_PRIVATE) + "MBEDTLS_SSL_ASYNC_PRIVATE", +#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */ +#if defined(MBEDTLS_SSL_DEBUG_ALL) + "MBEDTLS_SSL_DEBUG_ALL", +#endif /* MBEDTLS_SSL_DEBUG_ALL */ +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + "MBEDTLS_SSL_ENCRYPT_THEN_MAC", +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + "MBEDTLS_SSL_EXTENDED_MASTER_SECRET", +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) + "MBEDTLS_SSL_FALLBACK_SCSV", +#endif /* MBEDTLS_SSL_FALLBACK_SCSV */ +#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) + "MBEDTLS_SSL_KEEP_PEER_CERTIFICATE", +#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */ +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + "MBEDTLS_SSL_HW_RECORD_ACCEL", +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + "MBEDTLS_SSL_CBC_RECORD_SPLITTING", +#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + "MBEDTLS_SSL_RENEGOTIATION", +#endif /* MBEDTLS_SSL_RENEGOTIATION */ +#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) + "MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO", +#endif /* MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO */ +#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE) + "MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE", +#endif /* MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE */ +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + "MBEDTLS_SSL_MAX_FRAGMENT_LENGTH", +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + "MBEDTLS_SSL_PROTO_SSL3", +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) + "MBEDTLS_SSL_PROTO_TLS1", +#endif /* MBEDTLS_SSL_PROTO_TLS1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) + "MBEDTLS_SSL_PROTO_TLS1_1", +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + "MBEDTLS_SSL_PROTO_TLS1_2", +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + "MBEDTLS_SSL_PROTO_DTLS", +#endif /* MBEDTLS_SSL_PROTO_DTLS */ +#if defined(MBEDTLS_SSL_ALPN) + "MBEDTLS_SSL_ALPN", +#endif /* MBEDTLS_SSL_ALPN */ +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + "MBEDTLS_SSL_DTLS_ANTI_REPLAY", +#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */ +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) + "MBEDTLS_SSL_DTLS_HELLO_VERIFY", +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) + "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE", +#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE */ +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) + "MBEDTLS_SSL_DTLS_BADMAC_LIMIT", +#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */ +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + "MBEDTLS_SSL_SESSION_TICKETS", +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + "MBEDTLS_SSL_EXPORT_KEYS", +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + "MBEDTLS_SSL_SERVER_NAME_INDICATION", +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + "MBEDTLS_SSL_TRUNCATED_HMAC", +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT) + "MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT", +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT */ +#if defined(MBEDTLS_THREADING_ALT) + "MBEDTLS_THREADING_ALT", +#endif /* MBEDTLS_THREADING_ALT */ +#if defined(MBEDTLS_THREADING_PTHREAD) + "MBEDTLS_THREADING_PTHREAD", +#endif /* MBEDTLS_THREADING_PTHREAD */ +#if defined(MBEDTLS_USE_PSA_CRYPTO) + "MBEDTLS_USE_PSA_CRYPTO", +#endif /* MBEDTLS_USE_PSA_CRYPTO */ +#if defined(MBEDTLS_VERSION_FEATURES) + "MBEDTLS_VERSION_FEATURES", +#endif /* MBEDTLS_VERSION_FEATURES */ +#if defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) + "MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3", +#endif /* MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 */ +#if defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) + "MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION", +#endif /* MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION */ +#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) + "MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK", +#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + "MBEDTLS_X509_CHECK_KEY_USAGE", +#endif /* MBEDTLS_X509_CHECK_KEY_USAGE */ +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) + "MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE", +#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + "MBEDTLS_X509_RSASSA_PSS_SUPPORT", +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ +#if defined(MBEDTLS_ZLIB_SUPPORT) + "MBEDTLS_ZLIB_SUPPORT", +#endif /* MBEDTLS_ZLIB_SUPPORT */ +#if defined(MBEDTLS_AESNI_C) + "MBEDTLS_AESNI_C", +#endif /* MBEDTLS_AESNI_C */ +#if defined(MBEDTLS_AES_C) + "MBEDTLS_AES_C", +#endif /* MBEDTLS_AES_C */ +#if defined(MBEDTLS_ARC4_C) + "MBEDTLS_ARC4_C", +#endif /* MBEDTLS_ARC4_C */ +#if defined(MBEDTLS_ASN1_PARSE_C) + "MBEDTLS_ASN1_PARSE_C", +#endif /* MBEDTLS_ASN1_PARSE_C */ +#if defined(MBEDTLS_ASN1_WRITE_C) + "MBEDTLS_ASN1_WRITE_C", +#endif /* MBEDTLS_ASN1_WRITE_C */ +#if defined(MBEDTLS_BASE64_C) + "MBEDTLS_BASE64_C", +#endif /* MBEDTLS_BASE64_C */ +#if defined(MBEDTLS_BIGNUM_C) + "MBEDTLS_BIGNUM_C", +#endif /* MBEDTLS_BIGNUM_C */ +#if defined(MBEDTLS_BLOWFISH_C) + "MBEDTLS_BLOWFISH_C", +#endif /* MBEDTLS_BLOWFISH_C */ +#if defined(MBEDTLS_CAMELLIA_C) + "MBEDTLS_CAMELLIA_C", +#endif /* MBEDTLS_CAMELLIA_C */ +#if defined(MBEDTLS_ARIA_C) + "MBEDTLS_ARIA_C", +#endif /* MBEDTLS_ARIA_C */ +#if defined(MBEDTLS_CCM_C) + "MBEDTLS_CCM_C", +#endif /* MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CERTS_C) + "MBEDTLS_CERTS_C", +#endif /* MBEDTLS_CERTS_C */ +#if defined(MBEDTLS_CHACHA20_C) + "MBEDTLS_CHACHA20_C", +#endif /* MBEDTLS_CHACHA20_C */ +#if defined(MBEDTLS_CHACHAPOLY_C) + "MBEDTLS_CHACHAPOLY_C", +#endif /* MBEDTLS_CHACHAPOLY_C */ +#if defined(MBEDTLS_CIPHER_C) + "MBEDTLS_CIPHER_C", +#endif /* MBEDTLS_CIPHER_C */ +#if defined(MBEDTLS_CMAC_C) + "MBEDTLS_CMAC_C", +#endif /* MBEDTLS_CMAC_C */ +#if defined(MBEDTLS_CTR_DRBG_C) + "MBEDTLS_CTR_DRBG_C", +#endif /* MBEDTLS_CTR_DRBG_C */ +#if defined(MBEDTLS_DEBUG_C) + "MBEDTLS_DEBUG_C", +#endif /* MBEDTLS_DEBUG_C */ +#if defined(MBEDTLS_DES_C) + "MBEDTLS_DES_C", +#endif /* MBEDTLS_DES_C */ +#if defined(MBEDTLS_DHM_C) + "MBEDTLS_DHM_C", +#endif /* MBEDTLS_DHM_C */ +#if defined(MBEDTLS_ECDH_C) + "MBEDTLS_ECDH_C", +#endif /* MBEDTLS_ECDH_C */ +#if defined(MBEDTLS_ECDSA_C) + "MBEDTLS_ECDSA_C", +#endif /* MBEDTLS_ECDSA_C */ +#if defined(MBEDTLS_ECJPAKE_C) + "MBEDTLS_ECJPAKE_C", +#endif /* MBEDTLS_ECJPAKE_C */ +#if defined(MBEDTLS_ECP_C) + "MBEDTLS_ECP_C", +#endif /* MBEDTLS_ECP_C */ +#if defined(MBEDTLS_ENTROPY_C) + "MBEDTLS_ENTROPY_C", +#endif /* MBEDTLS_ENTROPY_C */ +#if defined(MBEDTLS_ERROR_C) + "MBEDTLS_ERROR_C", +#endif /* MBEDTLS_ERROR_C */ +#if defined(MBEDTLS_GCM_C) + "MBEDTLS_GCM_C", +#endif /* MBEDTLS_GCM_C */ +#if defined(MBEDTLS_HAVEGE_C) + "MBEDTLS_HAVEGE_C", +#endif /* MBEDTLS_HAVEGE_C */ +#if defined(MBEDTLS_HKDF_C) + "MBEDTLS_HKDF_C", +#endif /* MBEDTLS_HKDF_C */ +#if defined(MBEDTLS_HMAC_DRBG_C) + "MBEDTLS_HMAC_DRBG_C", +#endif /* MBEDTLS_HMAC_DRBG_C */ +#if defined(MBEDTLS_NIST_KW_C) + "MBEDTLS_NIST_KW_C", +#endif /* MBEDTLS_NIST_KW_C */ +#if defined(MBEDTLS_MD_C) + "MBEDTLS_MD_C", +#endif /* MBEDTLS_MD_C */ +#if defined(MBEDTLS_MD2_C) + "MBEDTLS_MD2_C", +#endif /* MBEDTLS_MD2_C */ +#if defined(MBEDTLS_MD4_C) + "MBEDTLS_MD4_C", +#endif /* MBEDTLS_MD4_C */ +#if defined(MBEDTLS_MD5_C) + "MBEDTLS_MD5_C", +#endif /* MBEDTLS_MD5_C */ +#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) + "MBEDTLS_MEMORY_BUFFER_ALLOC_C", +#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */ +#if defined(MBEDTLS_NET_C) + "MBEDTLS_NET_C", +#endif /* MBEDTLS_NET_C */ +#if defined(MBEDTLS_OID_C) + "MBEDTLS_OID_C", +#endif /* MBEDTLS_OID_C */ +#if defined(MBEDTLS_PADLOCK_C) + "MBEDTLS_PADLOCK_C", +#endif /* MBEDTLS_PADLOCK_C */ +#if defined(MBEDTLS_PEM_PARSE_C) + "MBEDTLS_PEM_PARSE_C", +#endif /* MBEDTLS_PEM_PARSE_C */ +#if defined(MBEDTLS_PEM_WRITE_C) + "MBEDTLS_PEM_WRITE_C", +#endif /* MBEDTLS_PEM_WRITE_C */ +#if defined(MBEDTLS_PK_C) + "MBEDTLS_PK_C", +#endif /* MBEDTLS_PK_C */ +#if defined(MBEDTLS_PK_PARSE_C) + "MBEDTLS_PK_PARSE_C", +#endif /* MBEDTLS_PK_PARSE_C */ +#if defined(MBEDTLS_PK_WRITE_C) + "MBEDTLS_PK_WRITE_C", +#endif /* MBEDTLS_PK_WRITE_C */ +#if defined(MBEDTLS_PKCS5_C) + "MBEDTLS_PKCS5_C", +#endif /* MBEDTLS_PKCS5_C */ +#if defined(MBEDTLS_PKCS11_C) + "MBEDTLS_PKCS11_C", +#endif /* MBEDTLS_PKCS11_C */ +#if defined(MBEDTLS_PKCS12_C) + "MBEDTLS_PKCS12_C", +#endif /* MBEDTLS_PKCS12_C */ +#if defined(MBEDTLS_PLATFORM_C) + "MBEDTLS_PLATFORM_C", +#endif /* MBEDTLS_PLATFORM_C */ +#if defined(MBEDTLS_POLY1305_C) + "MBEDTLS_POLY1305_C", +#endif /* MBEDTLS_POLY1305_C */ +#if defined(MBEDTLS_PSA_CRYPTO_C) + "MBEDTLS_PSA_CRYPTO_C", +#endif /* MBEDTLS_PSA_CRYPTO_C */ +#if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C) + "MBEDTLS_PSA_CRYPTO_STORAGE_C", +#endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */ +#if defined(MBEDTLS_PSA_ITS_FILE_C) + "MBEDTLS_PSA_ITS_FILE_C", +#endif /* MBEDTLS_PSA_ITS_FILE_C */ +#if defined(MBEDTLS_RIPEMD160_C) + "MBEDTLS_RIPEMD160_C", +#endif /* MBEDTLS_RIPEMD160_C */ +#if defined(MBEDTLS_RSA_C) + "MBEDTLS_RSA_C", +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_SHA1_C) + "MBEDTLS_SHA1_C", +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) + "MBEDTLS_SHA256_C", +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + "MBEDTLS_SHA512_C", +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_SSL_CACHE_C) + "MBEDTLS_SSL_CACHE_C", +#endif /* MBEDTLS_SSL_CACHE_C */ +#if defined(MBEDTLS_SSL_COOKIE_C) + "MBEDTLS_SSL_COOKIE_C", +#endif /* MBEDTLS_SSL_COOKIE_C */ +#if defined(MBEDTLS_SSL_TICKET_C) + "MBEDTLS_SSL_TICKET_C", +#endif /* MBEDTLS_SSL_TICKET_C */ +#if defined(MBEDTLS_SSL_CLI_C) + "MBEDTLS_SSL_CLI_C", +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + "MBEDTLS_SSL_SRV_C", +#endif /* MBEDTLS_SSL_SRV_C */ +#if defined(MBEDTLS_SSL_TLS_C) + "MBEDTLS_SSL_TLS_C", +#endif /* MBEDTLS_SSL_TLS_C */ +#if defined(MBEDTLS_THREADING_C) + "MBEDTLS_THREADING_C", +#endif /* MBEDTLS_THREADING_C */ +#if defined(MBEDTLS_TIMING_C) + "MBEDTLS_TIMING_C", +#endif /* MBEDTLS_TIMING_C */ +#if defined(MBEDTLS_VERSION_C) + "MBEDTLS_VERSION_C", +#endif /* MBEDTLS_VERSION_C */ +#if defined(MBEDTLS_X509_USE_C) + "MBEDTLS_X509_USE_C", +#endif /* MBEDTLS_X509_USE_C */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + "MBEDTLS_X509_CRT_PARSE_C", +#endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_X509_CRL_PARSE_C) + "MBEDTLS_X509_CRL_PARSE_C", +#endif /* MBEDTLS_X509_CRL_PARSE_C */ +#if defined(MBEDTLS_X509_CSR_PARSE_C) + "MBEDTLS_X509_CSR_PARSE_C", +#endif /* MBEDTLS_X509_CSR_PARSE_C */ +#if defined(MBEDTLS_X509_CREATE_C) + "MBEDTLS_X509_CREATE_C", +#endif /* MBEDTLS_X509_CREATE_C */ +#if defined(MBEDTLS_X509_CRT_WRITE_C) + "MBEDTLS_X509_CRT_WRITE_C", +#endif /* MBEDTLS_X509_CRT_WRITE_C */ +#if defined(MBEDTLS_X509_CSR_WRITE_C) + "MBEDTLS_X509_CSR_WRITE_C", +#endif /* MBEDTLS_X509_CSR_WRITE_C */ +#if defined(MBEDTLS_XTEA_C) + "MBEDTLS_XTEA_C", +#endif /* MBEDTLS_XTEA_C */ +#endif /* MBEDTLS_VERSION_FEATURES */ + NULL +}; + +int mbedtls_version_check_feature( const char *feature ) +{ + const char **idx = features; + + if( *idx == NULL ) + return( -2 ); + + if( feature == NULL ) + return( -1 ); + + while( *idx != NULL ) + { + if( !strcmp( *idx, feature ) ) + return( 0 ); + idx++; + } + return( -1 ); +} + +#endif /* MBEDTLS_VERSION_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/x509.c b/FreeRTOS-Labs/Source/mbedtls/library/x509.c new file mode 100644 index 000000000..604bcc228 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/x509.c @@ -0,0 +1,1069 @@ +/* + * X.509 common functions for parsing and verification + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_USE_C) + +#include "mbedtls/x509.h" +#include "mbedtls/asn1.h" +#include "mbedtls/oid.h" + +#include +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_printf printf +#define mbedtls_snprintf snprintf +#endif + +#if defined(MBEDTLS_HAVE_TIME) +#include "mbedtls/platform_time.h" +#endif +#if defined(MBEDTLS_HAVE_TIME_DATE) +#include "mbedtls/platform_util.h" +#include +#endif + +#define CHECK(code) if( ( ret = ( code ) ) != 0 ){ return( ret ); } +#define CHECK_RANGE(min, max, val) \ + do \ + { \ + if( ( val ) < ( min ) || ( val ) > ( max ) ) \ + { \ + return( ret ); \ + } \ + } while( 0 ) + +/* + * CertificateSerialNumber ::= INTEGER + */ +int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *serial ) +{ + int ret; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_SERIAL + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( **p != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_PRIMITIVE | 2 ) && + **p != MBEDTLS_ASN1_INTEGER ) + return( MBEDTLS_ERR_X509_INVALID_SERIAL + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + serial->tag = *(*p)++; + + if( ( ret = mbedtls_asn1_get_len( p, end, &serial->len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_SERIAL + ret ); + + serial->p = *p; + *p += serial->len; + + return( 0 ); +} + +/* Get an algorithm identifier without parameters (eg for signatures) + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + */ +int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_alg_null( p, end, alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + return( 0 ); +} + +/* + * Parse an algorithm identifier with (optional) parameters + */ +int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg, mbedtls_x509_buf *params ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_alg( p, end, alg, params ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + return( 0 ); +} + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) +/* + * HashAlgorithm ::= AlgorithmIdentifier + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + * + * For HashAlgorithm, parameters MUST be NULL or absent. + */ +static int x509_get_hash_alg( const mbedtls_x509_buf *alg, mbedtls_md_type_t *md_alg ) +{ + int ret; + unsigned char *p; + const unsigned char *end; + mbedtls_x509_buf md_oid; + size_t len; + + /* Make sure we got a SEQUENCE and setup bounds */ + if( alg->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + p = (unsigned char *) alg->p; + end = p + alg->len; + + if( p >= end ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + /* Parse md_oid */ + md_oid.tag = *p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &md_oid.len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + md_oid.p = p; + p += md_oid.len; + + /* Get md_alg from md_oid */ + if( ( ret = mbedtls_oid_get_md_alg( &md_oid, md_alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + /* Make sure params is absent of NULL */ + if( p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_NULL ) ) != 0 || len != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * RSASSA-PSS-params ::= SEQUENCE { + * hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier, + * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1Identifier, + * saltLength [2] INTEGER DEFAULT 20, + * trailerField [3] INTEGER DEFAULT 1 } + * -- Note that the tags in this Sequence are explicit. + * + * RFC 4055 (which defines use of RSASSA-PSS in PKIX) states that the value + * of trailerField MUST be 1, and PKCS#1 v2.2 doesn't even define any other + * option. Enfore this at parsing time. + */ +int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, + mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md, + int *salt_len ) +{ + int ret; + unsigned char *p; + const unsigned char *end, *end2; + size_t len; + mbedtls_x509_buf alg_id, alg_params; + + /* First set everything to defaults */ + *md_alg = MBEDTLS_MD_SHA1; + *mgf_md = MBEDTLS_MD_SHA1; + *salt_len = 20; + + /* Make sure params is a SEQUENCE and setup bounds */ + if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + p = (unsigned char *) params->p; + end = p + params->len; + + if( p == end ) + return( 0 ); + + /* + * HashAlgorithm + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 ) + { + end2 = p + len; + + /* HashAlgorithm ::= AlgorithmIdentifier (without parameters) */ + if( ( ret = mbedtls_x509_get_alg_null( &p, end2, &alg_id ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_oid_get_md_alg( &alg_id, md_alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p == end ) + return( 0 ); + + /* + * MaskGenAlgorithm + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 ) + { + end2 = p + len; + + /* MaskGenAlgorithm ::= AlgorithmIdentifier (params = HashAlgorithm) */ + if( ( ret = mbedtls_x509_get_alg( &p, end2, &alg_id, &alg_params ) ) != 0 ) + return( ret ); + + /* Only MFG1 is recognised for now */ + if( MBEDTLS_OID_CMP( MBEDTLS_OID_MGF1, &alg_id ) != 0 ) + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE + + MBEDTLS_ERR_OID_NOT_FOUND ); + + /* Parse HashAlgorithm */ + if( ( ret = x509_get_hash_alg( &alg_params, mgf_md ) ) != 0 ) + return( ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p == end ) + return( 0 ); + + /* + * salt_len + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 2 ) ) == 0 ) + { + end2 = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end2, salt_len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p == end ) + return( 0 ); + + /* + * trailer_field (if present, must be 1) + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 3 ) ) == 0 ) + { + int trailer_field; + + end2 = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end2, &trailer_field ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( trailer_field != 1 ) + return( MBEDTLS_ERR_X509_INVALID_ALG ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + +/* + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + */ +static int x509_get_attr_type_value( unsigned char **p, + const unsigned char *end, + mbedtls_x509_name *cur ) +{ + int ret; + size_t len; + mbedtls_x509_buf *oid; + mbedtls_x509_buf *val; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + oid = &cur->oid; + oid->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &oid->len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + oid->p = *p; + *p += oid->len; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( **p != MBEDTLS_ASN1_BMP_STRING && **p != MBEDTLS_ASN1_UTF8_STRING && + **p != MBEDTLS_ASN1_T61_STRING && **p != MBEDTLS_ASN1_PRINTABLE_STRING && + **p != MBEDTLS_ASN1_IA5_STRING && **p != MBEDTLS_ASN1_UNIVERSAL_STRING && + **p != MBEDTLS_ASN1_BIT_STRING ) + return( MBEDTLS_ERR_X509_INVALID_NAME + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + val = &cur->val; + val->tag = *(*p)++; + + if( ( ret = mbedtls_asn1_get_len( p, end, &val->len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + val->p = *p; + *p += val->len; + + cur->next = NULL; + + return( 0 ); +} + +/* + * Name ::= CHOICE { -- only one possibility for now -- + * rdnSequence RDNSequence } + * + * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + * + * RelativeDistinguishedName ::= + * SET OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + * + * The data structure is optimized for the common case where each RDN has only + * one element, which is represented as a list of AttributeTypeAndValue. + * For the general case we still use a flat list, but we mark elements of the + * same set so that they are "merged" together in the functions that consume + * this list, eg mbedtls_x509_dn_gets(). + */ +int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, + mbedtls_x509_name *cur ) +{ + int ret; + size_t set_len; + const unsigned char *end_set; + + /* don't use recursion, we'd risk stack overflow if not optimized */ + while( 1 ) + { + /* + * parse SET + */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &set_len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + end_set = *p + set_len; + + while( 1 ) + { + if( ( ret = x509_get_attr_type_value( p, end_set, cur ) ) != 0 ) + return( ret ); + + if( *p == end_set ) + break; + + /* Mark this item as being no the only one in a set */ + cur->next_merged = 1; + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + cur = cur->next; + } + + /* + * continue until end of SEQUENCE is reached + */ + if( *p == end ) + return( 0 ); + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + cur = cur->next; + } +} + +static int x509_parse_int( unsigned char **p, size_t n, int *res ) +{ + *res = 0; + + for( ; n > 0; --n ) + { + if( ( **p < '0') || ( **p > '9' ) ) + return ( MBEDTLS_ERR_X509_INVALID_DATE ); + + *res *= 10; + *res += ( *(*p)++ - '0' ); + } + + return( 0 ); +} + +static int x509_date_is_valid(const mbedtls_x509_time *t ) +{ + int ret = MBEDTLS_ERR_X509_INVALID_DATE; + int month_len; + + CHECK_RANGE( 0, 9999, t->year ); + CHECK_RANGE( 0, 23, t->hour ); + CHECK_RANGE( 0, 59, t->min ); + CHECK_RANGE( 0, 59, t->sec ); + + switch( t->mon ) + { + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + month_len = 31; + break; + case 4: case 6: case 9: case 11: + month_len = 30; + break; + case 2: + if( ( !( t->year % 4 ) && t->year % 100 ) || + !( t->year % 400 ) ) + month_len = 29; + else + month_len = 28; + break; + default: + return( ret ); + } + CHECK_RANGE( 1, month_len, t->day ); + + return( 0 ); +} + +/* + * Parse an ASN1_UTC_TIME (yearlen=2) or ASN1_GENERALIZED_TIME (yearlen=4) + * field. + */ +static int x509_parse_time( unsigned char **p, size_t len, size_t yearlen, + mbedtls_x509_time *tm ) +{ + int ret; + + /* + * Minimum length is 10 or 12 depending on yearlen + */ + if ( len < yearlen + 8 ) + return ( MBEDTLS_ERR_X509_INVALID_DATE ); + len -= yearlen + 8; + + /* + * Parse year, month, day, hour, minute + */ + CHECK( x509_parse_int( p, yearlen, &tm->year ) ); + if ( 2 == yearlen ) + { + if ( tm->year < 50 ) + tm->year += 100; + + tm->year += 1900; + } + + CHECK( x509_parse_int( p, 2, &tm->mon ) ); + CHECK( x509_parse_int( p, 2, &tm->day ) ); + CHECK( x509_parse_int( p, 2, &tm->hour ) ); + CHECK( x509_parse_int( p, 2, &tm->min ) ); + + /* + * Parse seconds if present + */ + if ( len >= 2 ) + { + CHECK( x509_parse_int( p, 2, &tm->sec ) ); + len -= 2; + } + else + return ( MBEDTLS_ERR_X509_INVALID_DATE ); + + /* + * Parse trailing 'Z' if present + */ + if ( 1 == len && 'Z' == **p ) + { + (*p)++; + len--; + } + + /* + * We should have parsed all characters at this point + */ + if ( 0 != len ) + return ( MBEDTLS_ERR_X509_INVALID_DATE ); + + CHECK( x509_date_is_valid( tm ) ); + + return ( 0 ); +} + +/* + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + */ +int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, + mbedtls_x509_time *tm ) +{ + int ret; + size_t len, year_len; + unsigned char tag; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + tag = **p; + + if( tag == MBEDTLS_ASN1_UTC_TIME ) + year_len = 2; + else if( tag == MBEDTLS_ASN1_GENERALIZED_TIME ) + year_len = 4; + else + return( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + (*p)++; + ret = mbedtls_asn1_get_len( p, end, &len ); + + if( ret != 0 ) + return( MBEDTLS_ERR_X509_INVALID_DATE + ret ); + + return x509_parse_time( p, len, year_len, tm ); +} + +int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig ) +{ + int ret; + size_t len; + int tag_type; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_SIGNATURE + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + tag_type = **p; + + if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_SIGNATURE + ret ); + + sig->tag = tag_type; + sig->len = len; + sig->p = *p; + + *p += len; + + return( 0 ); +} + +/* + * Get signature algorithm from alg OID and optional parameters + */ +int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x509_buf *sig_params, + mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg, + void **sig_opts ) +{ + int ret; + + if( *sig_opts != NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_oid_get_sig_alg( sig_oid, md_alg, pk_alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + ret ); + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + if( *pk_alg == MBEDTLS_PK_RSASSA_PSS ) + { + mbedtls_pk_rsassa_pss_options *pss_opts; + + pss_opts = mbedtls_calloc( 1, sizeof( mbedtls_pk_rsassa_pss_options ) ); + if( pss_opts == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + ret = mbedtls_x509_get_rsassa_pss_params( sig_params, + md_alg, + &pss_opts->mgf1_hash_id, + &pss_opts->expected_salt_len ); + if( ret != 0 ) + { + mbedtls_free( pss_opts ); + return( ret ); + } + + *sig_opts = (void *) pss_opts; + } + else +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + { + /* Make sure parameters are absent or NULL */ + if( ( sig_params->tag != MBEDTLS_ASN1_NULL && sig_params->tag != 0 ) || + sig_params->len != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG ); + } + + return( 0 ); +} + +/* + * X.509 Extensions (No parsing of extensions, pointer should + * be either manually updated or extensions should be parsed!) + */ +int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *ext, int tag ) +{ + int ret; + size_t len; + + if( *p == end ) + return( 0 ); + + ext->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &ext->len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | tag ) ) != 0 ) + return( ret ); + + ext->p = *p; + end = *p + ext->len; + + /* + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( end != *p + len ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Store the name in printable form into buf; no more + * than size characters will be written + */ +int mbedtls_x509_dn_gets( char *buf, size_t size, const mbedtls_x509_name *dn ) +{ + int ret; + size_t i, n; + unsigned char c, merge = 0; + const mbedtls_x509_name *name; + const char *short_name = NULL; + char s[MBEDTLS_X509_MAX_DN_NAME_SIZE], *p; + + memset( s, 0, sizeof( s ) ); + + name = dn; + p = buf; + n = size; + + while( name != NULL ) + { + if( !name->oid.p ) + { + name = name->next; + continue; + } + + if( name != dn ) + { + ret = mbedtls_snprintf( p, n, merge ? " + " : ", " ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + ret = mbedtls_oid_get_attr_short_name( &name->oid, &short_name ); + + if( ret == 0 ) + ret = mbedtls_snprintf( p, n, "%s=", short_name ); + else + ret = mbedtls_snprintf( p, n, "\?\?=" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + for( i = 0; i < name->val.len; i++ ) + { + if( i >= sizeof( s ) - 1 ) + break; + + c = name->val.p[i]; + if( c < 32 || c == 127 || ( c > 128 && c < 160 ) ) + s[i] = '?'; + else s[i] = c; + } + s[i] = '\0'; + ret = mbedtls_snprintf( p, n, "%s", s ); + MBEDTLS_X509_SAFE_SNPRINTF; + + merge = name->next_merged; + name = name->next; + } + + return( (int) ( size - n ) ); +} + +/* + * Store the serial in printable form into buf; no more + * than size characters will be written + */ +int mbedtls_x509_serial_gets( char *buf, size_t size, const mbedtls_x509_buf *serial ) +{ + int ret; + size_t i, n, nr; + char *p; + + p = buf; + n = size; + + nr = ( serial->len <= 32 ) + ? serial->len : 28; + + for( i = 0; i < nr; i++ ) + { + if( i == 0 && nr > 1 && serial->p[i] == 0x0 ) + continue; + + ret = mbedtls_snprintf( p, n, "%02X%s", + serial->p[i], ( i < nr - 1 ) ? ":" : "" ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + if( nr != serial->len ) + { + ret = mbedtls_snprintf( p, n, "...." ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + return( (int) ( size - n ) ); +} + +/* + * Helper for writing signature algorithms + */ +int mbedtls_x509_sig_alg_gets( char *buf, size_t size, const mbedtls_x509_buf *sig_oid, + mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, + const void *sig_opts ) +{ + int ret; + char *p = buf; + size_t n = size; + const char *desc = NULL; + + ret = mbedtls_oid_get_sig_alg_desc( sig_oid, &desc ); + if( ret != 0 ) + ret = mbedtls_snprintf( p, n, "???" ); + else + ret = mbedtls_snprintf( p, n, "%s", desc ); + MBEDTLS_X509_SAFE_SNPRINTF; + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + if( pk_alg == MBEDTLS_PK_RSASSA_PSS ) + { + const mbedtls_pk_rsassa_pss_options *pss_opts; + const mbedtls_md_info_t *md_info, *mgf_md_info; + + pss_opts = (const mbedtls_pk_rsassa_pss_options *) sig_opts; + + md_info = mbedtls_md_info_from_type( md_alg ); + mgf_md_info = mbedtls_md_info_from_type( pss_opts->mgf1_hash_id ); + + ret = mbedtls_snprintf( p, n, " (%s, MGF1-%s, 0x%02X)", + md_info ? mbedtls_md_get_name( md_info ) : "???", + mgf_md_info ? mbedtls_md_get_name( mgf_md_info ) : "???", + pss_opts->expected_salt_len ); + MBEDTLS_X509_SAFE_SNPRINTF; + } +#else + ((void) pk_alg); + ((void) md_alg); + ((void) sig_opts); +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + + return( (int)( size - n ) ); +} + +/* + * Helper for writing "RSA key size", "EC key size", etc + */ +int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name ) +{ + char *p = buf; + size_t n = buf_size; + int ret; + + ret = mbedtls_snprintf( p, n, "%s key size", name ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( 0 ); +} + +#if defined(MBEDTLS_HAVE_TIME_DATE) +/* + * Set the time structure to the current time. + * Return 0 on success, non-zero on failure. + */ +static int x509_get_current_time( mbedtls_x509_time *now ) +{ + struct tm *lt, tm_buf; + mbedtls_time_t tt; + int ret = 0; + + tt = mbedtls_time( NULL ); + lt = mbedtls_platform_gmtime_r( &tt, &tm_buf ); + + if( lt == NULL ) + ret = -1; + else + { + now->year = lt->tm_year + 1900; + now->mon = lt->tm_mon + 1; + now->day = lt->tm_mday; + now->hour = lt->tm_hour; + now->min = lt->tm_min; + now->sec = lt->tm_sec; + } + + return( ret ); +} + +/* + * Return 0 if before <= after, 1 otherwise + */ +static int x509_check_time( const mbedtls_x509_time *before, const mbedtls_x509_time *after ) +{ + if( before->year > after->year ) + return( 1 ); + + if( before->year == after->year && + before->mon > after->mon ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day > after->day ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day == after->day && + before->hour > after->hour ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day == after->day && + before->hour == after->hour && + before->min > after->min ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day == after->day && + before->hour == after->hour && + before->min == after->min && + before->sec > after->sec ) + return( 1 ); + + return( 0 ); +} + +int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ) +{ + mbedtls_x509_time now; + + if( x509_get_current_time( &now ) != 0 ) + return( 1 ); + + return( x509_check_time( &now, to ) ); +} + +int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ) +{ + mbedtls_x509_time now; + + if( x509_get_current_time( &now ) != 0 ) + return( 1 ); + + return( x509_check_time( from, &now ) ); +} + +#else /* MBEDTLS_HAVE_TIME_DATE */ + +int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ) +{ + ((void) to); + return( 0 ); +} + +int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ) +{ + ((void) from); + return( 0 ); +} +#endif /* MBEDTLS_HAVE_TIME_DATE */ + +#if defined(MBEDTLS_SELF_TEST) + +#include "mbedtls/x509_crt.h" +#include "mbedtls/certs.h" + +/* + * Checkup routine + */ +int mbedtls_x509_self_test( int verbose ) +{ + int ret = 0; +#if defined(MBEDTLS_CERTS_C) && defined(MBEDTLS_SHA256_C) + uint32_t flags; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; + + if( verbose != 0 ) + mbedtls_printf( " X.509 certificate load: " ); + + mbedtls_x509_crt_init( &cacert ); + mbedtls_x509_crt_init( &clicert ); + + ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) mbedtls_test_cli_crt, + mbedtls_test_cli_crt_len ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + goto cleanup; + } + + ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_ca_crt, + mbedtls_test_ca_crt_len ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n X.509 signature verify: "); + + ret = mbedtls_x509_crt_verify( &clicert, &cacert, NULL, NULL, &flags, NULL, NULL ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n\n"); + +cleanup: + mbedtls_x509_crt_free( &cacert ); + mbedtls_x509_crt_free( &clicert ); +#else + ((void) verbose); +#endif /* MBEDTLS_CERTS_C && MBEDTLS_SHA1_C */ + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_X509_USE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/x509_create.c b/FreeRTOS-Labs/Source/mbedtls/library/x509_create.c new file mode 100644 index 000000000..5aede32e7 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/x509_create.c @@ -0,0 +1,379 @@ +/* + * X.509 base functions for creating certificates / CSRs + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CREATE_C) + +#include "mbedtls/x509.h" +#include "mbedtls/asn1write.h" +#include "mbedtls/oid.h" + +#include + +/* Structure linking OIDs for X.509 DN AttributeTypes to their + * string representations and default string encodings used by Mbed TLS. */ +typedef struct { + const char *name; /* String representation of AttributeType, e.g. + * "CN" or "emailAddress". */ + size_t name_len; /* Length of 'name', without trailing 0 byte. */ + const char *oid; /* String representation of OID of AttributeType, + * as per RFC 5280, Appendix A.1. */ + int default_tag; /* The default character encoding used for the + * given attribute type, e.g. + * MBEDTLS_ASN1_UTF8_STRING for UTF-8. */ +} x509_attr_descriptor_t; + +#define ADD_STRLEN( s ) s, sizeof( s ) - 1 + +/* X.509 DN attributes from RFC 5280, Appendix A.1. */ +static const x509_attr_descriptor_t x509_attrs[] = +{ + { ADD_STRLEN( "CN" ), + MBEDTLS_OID_AT_CN, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "commonName" ), + MBEDTLS_OID_AT_CN, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "C" ), + MBEDTLS_OID_AT_COUNTRY, MBEDTLS_ASN1_PRINTABLE_STRING }, + { ADD_STRLEN( "countryName" ), + MBEDTLS_OID_AT_COUNTRY, MBEDTLS_ASN1_PRINTABLE_STRING }, + { ADD_STRLEN( "O" ), + MBEDTLS_OID_AT_ORGANIZATION, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "organizationName" ), + MBEDTLS_OID_AT_ORGANIZATION, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "L" ), + MBEDTLS_OID_AT_LOCALITY, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "locality" ), + MBEDTLS_OID_AT_LOCALITY, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "R" ), + MBEDTLS_OID_PKCS9_EMAIL, MBEDTLS_ASN1_IA5_STRING }, + { ADD_STRLEN( "OU" ), + MBEDTLS_OID_AT_ORG_UNIT, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "organizationalUnitName" ), + MBEDTLS_OID_AT_ORG_UNIT, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "ST" ), + MBEDTLS_OID_AT_STATE, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "stateOrProvinceName" ), + MBEDTLS_OID_AT_STATE, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "emailAddress" ), + MBEDTLS_OID_PKCS9_EMAIL, MBEDTLS_ASN1_IA5_STRING }, + { ADD_STRLEN( "serialNumber" ), + MBEDTLS_OID_AT_SERIAL_NUMBER, MBEDTLS_ASN1_PRINTABLE_STRING }, + { ADD_STRLEN( "postalAddress" ), + MBEDTLS_OID_AT_POSTAL_ADDRESS, MBEDTLS_ASN1_PRINTABLE_STRING }, + { ADD_STRLEN( "postalCode" ), + MBEDTLS_OID_AT_POSTAL_CODE, MBEDTLS_ASN1_PRINTABLE_STRING }, + { ADD_STRLEN( "dnQualifier" ), + MBEDTLS_OID_AT_DN_QUALIFIER, MBEDTLS_ASN1_PRINTABLE_STRING }, + { ADD_STRLEN( "title" ), + MBEDTLS_OID_AT_TITLE, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "surName" ), + MBEDTLS_OID_AT_SUR_NAME, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "SN" ), + MBEDTLS_OID_AT_SUR_NAME, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "givenName" ), + MBEDTLS_OID_AT_GIVEN_NAME, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "GN" ), + MBEDTLS_OID_AT_GIVEN_NAME, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "initials" ), + MBEDTLS_OID_AT_INITIALS, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "pseudonym" ), + MBEDTLS_OID_AT_PSEUDONYM, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "generationQualifier" ), + MBEDTLS_OID_AT_GENERATION_QUALIFIER, MBEDTLS_ASN1_UTF8_STRING }, + { ADD_STRLEN( "domainComponent" ), + MBEDTLS_OID_DOMAIN_COMPONENT, MBEDTLS_ASN1_IA5_STRING }, + { ADD_STRLEN( "DC" ), + MBEDTLS_OID_DOMAIN_COMPONENT, MBEDTLS_ASN1_IA5_STRING }, + { NULL, 0, NULL, MBEDTLS_ASN1_NULL } +}; + +static const x509_attr_descriptor_t *x509_attr_descr_from_name( const char *name, size_t name_len ) +{ + const x509_attr_descriptor_t *cur; + + for( cur = x509_attrs; cur->name != NULL; cur++ ) + if( cur->name_len == name_len && + strncmp( cur->name, name, name_len ) == 0 ) + break; + + if ( cur->name == NULL ) + return( NULL ); + + return( cur ); +} + +int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *name ) +{ + int ret = 0; + const char *s = name, *c = s; + const char *end = s + strlen( s ); + const char *oid = NULL; + const x509_attr_descriptor_t* attr_descr = NULL; + int in_tag = 1; + char data[MBEDTLS_X509_MAX_DN_NAME_SIZE]; + char *d = data; + + /* Clear existing chain if present */ + mbedtls_asn1_free_named_data_list( head ); + + while( c <= end ) + { + if( in_tag && *c == '=' ) + { + if( ( attr_descr = x509_attr_descr_from_name( s, c - s ) ) == NULL ) + { + ret = MBEDTLS_ERR_X509_UNKNOWN_OID; + goto exit; + } + + oid = attr_descr->oid; + s = c + 1; + in_tag = 0; + d = data; + } + + if( !in_tag && *c == '\\' && c != end ) + { + c++; + + /* Check for valid escaped characters */ + if( c == end || *c != ',' ) + { + ret = MBEDTLS_ERR_X509_INVALID_NAME; + goto exit; + } + } + else if( !in_tag && ( *c == ',' || c == end ) ) + { + mbedtls_asn1_named_data* cur = + mbedtls_asn1_store_named_data( head, oid, strlen( oid ), + (unsigned char *) data, + d - data ); + + if(cur == NULL ) + { + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + } + + // set tagType + cur->val.tag = attr_descr->default_tag; + + while( c < end && *(c + 1) == ' ' ) + c++; + + s = c + 1; + in_tag = 1; + } + + if( !in_tag && s != c + 1 ) + { + *(d++) = *c; + + if( d - data == MBEDTLS_X509_MAX_DN_NAME_SIZE ) + { + ret = MBEDTLS_ERR_X509_INVALID_NAME; + goto exit; + } + } + + c++; + } + +exit: + + return( ret ); +} + +/* The first byte of the value in the mbedtls_asn1_named_data structure is reserved + * to store the critical boolean for us + */ +int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid, size_t oid_len, + int critical, const unsigned char *val, size_t val_len ) +{ + mbedtls_asn1_named_data *cur; + + if( ( cur = mbedtls_asn1_store_named_data( head, oid, oid_len, + NULL, val_len + 1 ) ) == NULL ) + { + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + } + + cur->val.p[0] = critical; + memcpy( cur->val.p + 1, val, val_len ); + + return( 0 ); +} + +/* + * RelativeDistinguishedName ::= + * SET OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + */ +static int x509_write_name( unsigned char **p, unsigned char *start, mbedtls_asn1_named_data* cur_name) +{ + int ret; + size_t len = 0; + const char *oid = (const char*)cur_name->oid.p; + size_t oid_len = cur_name->oid.len; + const unsigned char *name = cur_name->val.p; + size_t name_len = cur_name->val.len; + + // Write correct string tag and value + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tagged_string( p, start, + cur_name->val.tag, + (const char *) name, + name_len ) ); + // Write OID + // + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, + oid_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, + MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, + MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SET ) ); + + return( (int) len ); +} + +int mbedtls_x509_write_names( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ) +{ + int ret; + size_t len = 0; + mbedtls_asn1_named_data *cur = first; + + while( cur != NULL ) + { + MBEDTLS_ASN1_CHK_ADD( len, x509_write_name( p, start, cur ) ); + cur = cur->next; + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +int mbedtls_x509_write_sig( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + unsigned char *sig, size_t size ) +{ + int ret; + size_t len = 0; + + if( *p < start || (size_t)( *p - start ) < size ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len = size; + (*p) -= len; + memcpy( *p, sig, len ); + + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0; + len += 1; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) ); + + // Write OID + // + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( p, start, oid, + oid_len, 0 ) ); + + return( (int) len ); +} + +static int x509_write_extension( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *ext ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, ext->val.p + 1, + ext->val.len - 1 ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, ext->val.len - 1 ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OCTET_STRING ) ); + + if( ext->val.p[0] != 0 ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( p, start, 1 ) ); + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, ext->oid.p, + ext->oid.len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, ext->oid.len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OID ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +/* + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING + * -- contains the DER encoding of an ASN.1 value + * -- corresponding to the extension type identified + * -- by extnID + * } + */ +int mbedtls_x509_write_extensions( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ) +{ + int ret; + size_t len = 0; + mbedtls_asn1_named_data *cur_ext = first; + + while( cur_ext != NULL ) + { + MBEDTLS_ASN1_CHK_ADD( len, x509_write_extension( p, start, cur_ext ) ); + cur_ext = cur_ext->next; + } + + return( (int) len ); +} + +#endif /* MBEDTLS_X509_CREATE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/x509_crl.c b/FreeRTOS-Labs/Source/mbedtls/library/x509_crl.c new file mode 100644 index 000000000..55376a73c --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/x509_crl.c @@ -0,0 +1,773 @@ +/* + * X.509 Certidicate Revocation List (CRL) parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CRL_PARSE_C) + +#include "mbedtls/x509_crl.h" +#include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_snprintf snprintf +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) +#include +#else +#include +#endif + +#if defined(MBEDTLS_FS_IO) || defined(EFIX64) || defined(EFI32) +#include +#endif + +/* + * Version ::= INTEGER { v1(0), v2(1) } + */ +static int x509_crl_get_version( unsigned char **p, + const unsigned char *end, + int *ver ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + *ver = 0; + return( 0 ); + } + + return( MBEDTLS_ERR_X509_INVALID_VERSION + ret ); + } + + return( 0 ); +} + +/* + * X.509 CRL v2 extensions + * + * We currently don't parse any extension's content, but we do check that the + * list of extensions is well-formed and abort on critical extensions (that + * are unsupported as we don't support any extension so far) + */ +static int x509_get_crl_ext( unsigned char **p, + const unsigned char *end, + mbedtls_x509_buf *ext ) +{ + int ret; + + /* + * crlExtensions [0] EXPLICIT Extensions OPTIONAL + * -- if present, version MUST be v2 + */ + if( ( ret = mbedtls_x509_get_ext( p, end, ext, 0 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + while( *p < end ) + { + /* + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + */ + int is_critical = 0; + const unsigned char *end_ext_data; + size_t len; + + /* Get enclosing sequence tag */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + end_ext_data = *p + len; + + /* Get OID (currently ignored) */ + if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &len, + MBEDTLS_ASN1_OID ) ) != 0 ) + { + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + } + *p += len; + + /* Get optional critical */ + if( ( ret = mbedtls_asn1_get_bool( p, end_ext_data, + &is_critical ) ) != 0 && + ( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) + { + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + } + + /* Data should be octet string type */ + if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &len, + MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + /* Ignore data so far and just check its length */ + *p += len; + if( *p != end_ext_data ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* Abort on (unsupported) critical extensions */ + if( is_critical ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + } + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 CRL v2 entry extensions (no extensions parsed yet.) + */ +static int x509_get_crl_entry_ext( unsigned char **p, + const unsigned char *end, + mbedtls_x509_buf *ext ) +{ + int ret; + size_t len = 0; + + /* OPTIONAL */ + if( end <= *p ) + return( 0 ); + + ext->tag = **p; + ext->p = *p; + + /* + * Get CRL-entry extension sequence header + * crlEntryExtensions Extensions OPTIONAL -- if present, MUST be v2 + */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &ext->len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + ext->p = NULL; + return( 0 ); + } + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + } + + end = *p + ext->len; + + if( end != *p + ext->len ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + *p += len; + } + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 CRL Entries + */ +static int x509_get_entries( unsigned char **p, + const unsigned char *end, + mbedtls_x509_crl_entry *entry ) +{ + int ret; + size_t entry_len; + mbedtls_x509_crl_entry *cur_entry = entry; + + if( *p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_tag( p, end, &entry_len, + MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + end = *p + entry_len; + + while( *p < end ) + { + size_t len2; + const unsigned char *end2; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len2, + MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED ) ) != 0 ) + { + return( ret ); + } + + cur_entry->raw.tag = **p; + cur_entry->raw.p = *p; + cur_entry->raw.len = len2; + end2 = *p + len2; + + if( ( ret = mbedtls_x509_get_serial( p, end2, &cur_entry->serial ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_x509_get_time( p, end2, + &cur_entry->revocation_date ) ) != 0 ) + return( ret ); + + if( ( ret = x509_get_crl_entry_ext( p, end2, + &cur_entry->entry_ext ) ) != 0 ) + return( ret ); + + if( *p < end ) + { + cur_entry->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crl_entry ) ); + + if( cur_entry->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + cur_entry = cur_entry->next; + } + } + + return( 0 ); +} + +/* + * Parse one CRLs in DER format and append it to the chained list + */ +int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain, + const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t len; + unsigned char *p = NULL, *end = NULL; + mbedtls_x509_buf sig_params1, sig_params2, sig_oid2; + mbedtls_x509_crl *crl = chain; + + /* + * Check for valid input + */ + if( crl == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + memset( &sig_params1, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_params2, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_oid2, 0, sizeof( mbedtls_x509_buf ) ); + + /* + * Add new CRL on the end of the chain if needed. + */ + while( crl->version != 0 && crl->next != NULL ) + crl = crl->next; + + if( crl->version != 0 && crl->next == NULL ) + { + crl->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crl ) ); + + if( crl->next == NULL ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + } + + mbedtls_x509_crl_init( crl->next ); + crl = crl->next; + } + + /* + * Copy raw DER-encoded CRL + */ + if( buflen == 0 ) + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + + p = mbedtls_calloc( 1, buflen ); + if( p == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + memcpy( p, buf, buflen ); + + crl->raw.p = p; + crl->raw.len = buflen; + + end = p + buflen; + + /* + * CertificateList ::= SEQUENCE { + * tbsCertList TBSCertList, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + } + + if( len != (size_t) ( end - p ) ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + /* + * TBSCertList ::= SEQUENCE { + */ + crl->tbs.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + end = p + len; + crl->tbs.len = end - crl->tbs.p; + + /* + * Version ::= INTEGER OPTIONAL { v1(0), v2(1) } + * -- if present, MUST be v2 + * + * signature AlgorithmIdentifier + */ + if( ( ret = x509_crl_get_version( &p, end, &crl->version ) ) != 0 || + ( ret = mbedtls_x509_get_alg( &p, end, &crl->sig_oid, &sig_params1 ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + if( crl->version < 0 || crl->version > 1 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); + } + + crl->version++; + + if( ( ret = mbedtls_x509_get_sig_alg( &crl->sig_oid, &sig_params1, + &crl->sig_md, &crl->sig_pk, + &crl->sig_opts ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG ); + } + + /* + * issuer Name + */ + crl->issuer_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_x509_get_name( &p, p + len, &crl->issuer ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + crl->issuer_raw.len = p - crl->issuer_raw.p; + + /* + * thisUpdate Time + * nextUpdate Time OPTIONAL + */ + if( ( ret = mbedtls_x509_get_time( &p, end, &crl->this_update ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + if( ( ret = mbedtls_x509_get_time( &p, end, &crl->next_update ) ) != 0 ) + { + if( ret != ( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) && + ret != ( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ) ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + } + + /* + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, MUST be v2 + * } OPTIONAL + */ + if( ( ret = x509_get_entries( &p, end, &crl->entry ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + /* + * crlExtensions EXPLICIT Extensions OPTIONAL + * -- if present, MUST be v2 + */ + if( crl->version == 2 ) + { + ret = x509_get_crl_ext( &p, end, &crl->crl_ext ); + + if( ret != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + } + + if( p != end ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + end = crl->raw.p + crl->raw.len; + + /* + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + */ + if( ( ret = mbedtls_x509_get_alg( &p, end, &sig_oid2, &sig_params2 ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + if( crl->sig_oid.len != sig_oid2.len || + memcmp( crl->sig_oid.p, sig_oid2.p, crl->sig_oid.len ) != 0 || + sig_params1.len != sig_params2.len || + ( sig_params1.len != 0 && + memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_SIG_MISMATCH ); + } + + if( ( ret = mbedtls_x509_get_sig( &p, end, &crl->sig ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + if( p != end ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + return( 0 ); +} + +/* + * Parse one or more CRLs and add them to the chained list + */ +int mbedtls_x509_crl_parse( mbedtls_x509_crl *chain, const unsigned char *buf, size_t buflen ) +{ +#if defined(MBEDTLS_PEM_PARSE_C) + int ret; + size_t use_len; + mbedtls_pem_context pem; + int is_pem = 0; + + if( chain == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + do + { + mbedtls_pem_init( &pem ); + + // Avoid calling mbedtls_pem_read_buffer() on non-null-terminated + // string + if( buflen == 0 || buf[buflen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN X509 CRL-----", + "-----END X509 CRL-----", + buf, NULL, 0, &use_len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + is_pem = 1; + + buflen -= use_len; + buf += use_len; + + if( ( ret = mbedtls_x509_crl_parse_der( chain, + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } + } + else if( is_pem ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } + + mbedtls_pem_free( &pem ); + } + /* In the PEM case, buflen is 1 at the end, for the terminated NULL byte. + * And a valid CRL cannot be less than 1 byte anyway. */ + while( is_pem && buflen > 1 ); + + if( is_pem ) + return( 0 ); + else +#endif /* MBEDTLS_PEM_PARSE_C */ + return( mbedtls_x509_crl_parse_der( chain, buf, buflen ) ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Load one or more CRLs and add them to the chained list + */ +int mbedtls_x509_crl_parse_file( mbedtls_x509_crl *chain, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_x509_crl_parse( chain, buf, n ); + + mbedtls_platform_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +/* + * Return an informational string about the certificate. + */ +#define BEFORE_COLON 14 +#define BC "14" +/* + * Return an informational string about the CRL. + */ +int mbedtls_x509_crl_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crl *crl ) +{ + int ret; + size_t n; + char *p; + const mbedtls_x509_crl_entry *entry; + + p = buf; + n = size; + + ret = mbedtls_snprintf( p, n, "%sCRL version : %d", + prefix, crl->version ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &crl->issuer ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sthis update : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crl->this_update.year, crl->this_update.mon, + crl->this_update.day, crl->this_update.hour, + crl->this_update.min, crl->this_update.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%snext update : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crl->next_update.year, crl->next_update.mon, + crl->next_update.day, crl->next_update.hour, + crl->next_update.min, crl->next_update.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + entry = &crl->entry; + + ret = mbedtls_snprintf( p, n, "\n%sRevoked certificates:", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + while( entry != NULL && entry->raw.len != 0 ) + { + ret = mbedtls_snprintf( p, n, "\n%sserial number: ", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_serial_gets( p, n, &entry->serial ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, " revocation date: " \ + "%04d-%02d-%02d %02d:%02d:%02d", + entry->revocation_date.year, entry->revocation_date.mon, + entry->revocation_date.day, entry->revocation_date.hour, + entry->revocation_date.min, entry->revocation_date.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + entry = entry->next; + } + + ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_sig_alg_gets( p, n, &crl->sig_oid, crl->sig_pk, crl->sig_md, + crl->sig_opts ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( (int) ( size - n ) ); +} + +/* + * Initialize a CRL chain + */ +void mbedtls_x509_crl_init( mbedtls_x509_crl *crl ) +{ + memset( crl, 0, sizeof(mbedtls_x509_crl) ); +} + +/* + * Unallocate all CRL data + */ +void mbedtls_x509_crl_free( mbedtls_x509_crl *crl ) +{ + mbedtls_x509_crl *crl_cur = crl; + mbedtls_x509_crl *crl_prv; + mbedtls_x509_name *name_cur; + mbedtls_x509_name *name_prv; + mbedtls_x509_crl_entry *entry_cur; + mbedtls_x509_crl_entry *entry_prv; + + if( crl == NULL ) + return; + + do + { +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_free( crl_cur->sig_opts ); +#endif + + name_cur = crl_cur->issuer.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + entry_cur = crl_cur->entry.next; + while( entry_cur != NULL ) + { + entry_prv = entry_cur; + entry_cur = entry_cur->next; + mbedtls_platform_zeroize( entry_prv, + sizeof( mbedtls_x509_crl_entry ) ); + mbedtls_free( entry_prv ); + } + + if( crl_cur->raw.p != NULL ) + { + mbedtls_platform_zeroize( crl_cur->raw.p, crl_cur->raw.len ); + mbedtls_free( crl_cur->raw.p ); + } + + crl_cur = crl_cur->next; + } + while( crl_cur != NULL ); + + crl_cur = crl; + do + { + crl_prv = crl_cur; + crl_cur = crl_cur->next; + + mbedtls_platform_zeroize( crl_prv, sizeof( mbedtls_x509_crl ) ); + if( crl_prv != crl ) + mbedtls_free( crl_prv ); + } + while( crl_cur != NULL ); +} + +#endif /* MBEDTLS_X509_CRL_PARSE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/x509_crt.c b/FreeRTOS-Labs/Source/mbedtls/library/x509_crt.c new file mode 100644 index 000000000..9e4dd10bb --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/x509_crt.c @@ -0,0 +1,3352 @@ +/* + * X.509 certificate parsing and verification + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + * + * [SIRO] https://cabforum.org/wp-content/uploads/Chunghwatelecom201503cabforumV4.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + +#include "mbedtls/x509_crt.h" +#include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "psa/crypto.h" +#include "mbedtls/psa_util.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_snprintf snprintf +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) +#include +#else +#include +#endif + +#if defined(MBEDTLS_FS_IO) +#include +#if !defined(_WIN32) || defined(EFIX64) || defined(EFI32) +#include +#include +#include +#endif /* !_WIN32 || EFIX64 || EFI32 */ +#endif + +/* + * Item in a verification chain: cert and flags for it + */ +typedef struct { + mbedtls_x509_crt *crt; + uint32_t flags; +} x509_crt_verify_chain_item; + +/* + * Max size of verification chain: end-entity + intermediates + trusted root + */ +#define X509_MAX_VERIFY_CHAIN_SIZE ( MBEDTLS_X509_MAX_INTERMEDIATE_CA + 2 ) + +/* + * Default profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default = +{ +#if defined(MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES) + /* Allow SHA-1 (weak, but still safe in controlled environments) */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | +#endif + /* Only SHA-2 hashes */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), + 0xFFFFFFF, /* Any PK alg */ + 0xFFFFFFF, /* Any curve */ + 2048, +}; + +/* + * Next-default profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next = +{ + /* Hashes from SHA-256 and above */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), + 0xFFFFFFF, /* Any PK alg */ +#if defined(MBEDTLS_ECP_C) + /* Curves at or above 128-bit security level */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP521R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP256R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP384R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP512R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256K1 ), +#else + 0, +#endif + 2048, +}; + +/* + * NSA Suite B Profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb = +{ + /* Only SHA-256 and 384 */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ), + /* Only ECDSA */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECDSA ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECKEY ), +#if defined(MBEDTLS_ECP_C) + /* Only NIST P-256 and P-384 */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ), +#else + 0, +#endif + 0, +}; + +/* + * Check md_alg against profile + * Return 0 if md_alg is acceptable for this profile, -1 otherwise + */ +static int x509_profile_check_md_alg( const mbedtls_x509_crt_profile *profile, + mbedtls_md_type_t md_alg ) +{ + if( md_alg == MBEDTLS_MD_NONE ) + return( -1 ); + + if( ( profile->allowed_mds & MBEDTLS_X509_ID_FLAG( md_alg ) ) != 0 ) + return( 0 ); + + return( -1 ); +} + +/* + * Check pk_alg against profile + * Return 0 if pk_alg is acceptable for this profile, -1 otherwise + */ +static int x509_profile_check_pk_alg( const mbedtls_x509_crt_profile *profile, + mbedtls_pk_type_t pk_alg ) +{ + if( pk_alg == MBEDTLS_PK_NONE ) + return( -1 ); + + if( ( profile->allowed_pks & MBEDTLS_X509_ID_FLAG( pk_alg ) ) != 0 ) + return( 0 ); + + return( -1 ); +} + +/* + * Check key against profile + * Return 0 if pk is acceptable for this profile, -1 otherwise + */ +static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile, + const mbedtls_pk_context *pk ) +{ + const mbedtls_pk_type_t pk_alg = mbedtls_pk_get_type( pk ); + +#if defined(MBEDTLS_RSA_C) + if( pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS ) + { + if( mbedtls_pk_get_bitlen( pk ) >= profile->rsa_min_bitlen ) + return( 0 ); + + return( -1 ); + } +#endif + +#if defined(MBEDTLS_ECP_C) + if( pk_alg == MBEDTLS_PK_ECDSA || + pk_alg == MBEDTLS_PK_ECKEY || + pk_alg == MBEDTLS_PK_ECKEY_DH ) + { + const mbedtls_ecp_group_id gid = mbedtls_pk_ec( *pk )->grp.id; + + if( gid == MBEDTLS_ECP_DP_NONE ) + return( -1 ); + + if( ( profile->allowed_curves & MBEDTLS_X509_ID_FLAG( gid ) ) != 0 ) + return( 0 ); + + return( -1 ); + } +#endif + + return( -1 ); +} + +/* + * Like memcmp, but case-insensitive and always returns -1 if different + */ +static int x509_memcasecmp( const void *s1, const void *s2, size_t len ) +{ + size_t i; + unsigned char diff; + const unsigned char *n1 = s1, *n2 = s2; + + for( i = 0; i < len; i++ ) + { + diff = n1[i] ^ n2[i]; + + if( diff == 0 ) + continue; + + if( diff == 32 && + ( ( n1[i] >= 'a' && n1[i] <= 'z' ) || + ( n1[i] >= 'A' && n1[i] <= 'Z' ) ) ) + { + continue; + } + + return( -1 ); + } + + return( 0 ); +} + +/* + * Return 0 if name matches wildcard, -1 otherwise + */ +static int x509_check_wildcard( const char *cn, const mbedtls_x509_buf *name ) +{ + size_t i; + size_t cn_idx = 0, cn_len = strlen( cn ); + + /* We can't have a match if there is no wildcard to match */ + if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' ) + return( -1 ); + + for( i = 0; i < cn_len; ++i ) + { + if( cn[i] == '.' ) + { + cn_idx = i; + break; + } + } + + if( cn_idx == 0 ) + return( -1 ); + + if( cn_len - cn_idx == name->len - 1 && + x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 ) + { + return( 0 ); + } + + return( -1 ); +} + +/* + * Compare two X.509 strings, case-insensitive, and allowing for some encoding + * variations (but not all). + * + * Return 0 if equal, -1 otherwise. + */ +static int x509_string_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b ) +{ + if( a->tag == b->tag && + a->len == b->len && + memcmp( a->p, b->p, b->len ) == 0 ) + { + return( 0 ); + } + + if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && + ( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && + a->len == b->len && + x509_memcasecmp( a->p, b->p, b->len ) == 0 ) + { + return( 0 ); + } + + return( -1 ); +} + +/* + * Compare two X.509 Names (aka rdnSequence). + * + * See RFC 5280 section 7.1, though we don't implement the whole algorithm: + * we sometimes return unequal when the full algorithm would return equal, + * but never the other way. (In particular, we don't do Unicode normalisation + * or space folding.) + * + * Return 0 if equal, -1 otherwise. + */ +static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b ) +{ + /* Avoid recursion, it might not be optimised by the compiler */ + while( a != NULL || b != NULL ) + { + if( a == NULL || b == NULL ) + return( -1 ); + + /* type */ + if( a->oid.tag != b->oid.tag || + a->oid.len != b->oid.len || + memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 ) + { + return( -1 ); + } + + /* value */ + if( x509_string_cmp( &a->val, &b->val ) != 0 ) + return( -1 ); + + /* structure of the list of sets */ + if( a->next_merged != b->next_merged ) + return( -1 ); + + a = a->next; + b = b->next; + } + + /* a == NULL == b */ + return( 0 ); +} + +/* + * Reset (init or clear) a verify_chain + */ +static void x509_crt_verify_chain_reset( + mbedtls_x509_crt_verify_chain *ver_chain ) +{ + size_t i; + + for( i = 0; i < MBEDTLS_X509_MAX_VERIFY_CHAIN_SIZE; i++ ) + { + ver_chain->items[i].crt = NULL; + ver_chain->items[i].flags = (uint32_t) -1; + } + + ver_chain->len = 0; + +#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) + ver_chain->trust_ca_cb_result = NULL; +#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ +} + +/* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ +static int x509_get_version( unsigned char **p, + const unsigned char *end, + int *ver ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + *ver = 0; + return( 0 ); + } + + return( ret ); + } + + end = *p + len; + + if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_VERSION + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_VERSION + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + */ +static int x509_get_dates( unsigned char **p, + const unsigned char *end, + mbedtls_x509_time *from, + mbedtls_x509_time *to ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_DATE + ret ); + + end = *p + len; + + if( ( ret = mbedtls_x509_get_time( p, end, from ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_x509_get_time( p, end, to ) ) != 0 ) + return( ret ); + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 v2/v3 unique identifier (not parsed) + */ +static int x509_get_uid( unsigned char **p, + const unsigned char *end, + mbedtls_x509_buf *uid, int n ) +{ + int ret; + + if( *p == end ) + return( 0 ); + + uid->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &uid->len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | n ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + uid->p = *p; + *p += uid->len; + + return( 0 ); +} + +static int x509_get_basic_constraints( unsigned char **p, + const unsigned char *end, + int *ca_istrue, + int *max_pathlen ) +{ + int ret; + size_t len; + + /* + * BasicConstraints ::= SEQUENCE { + * cA BOOLEAN DEFAULT FALSE, + * pathLenConstraint INTEGER (0..MAX) OPTIONAL } + */ + *ca_istrue = 0; /* DEFAULT FALSE */ + *max_pathlen = 0; /* endless */ + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_bool( p, end, ca_istrue ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + ret = mbedtls_asn1_get_int( p, end, ca_istrue ); + + if( ret != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *ca_istrue != 0 ) + *ca_istrue = 1; + } + + if( *p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_int( p, end, max_pathlen ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + (*max_pathlen)++; + + return( 0 ); +} + +static int x509_get_ns_cert_type( unsigned char **p, + const unsigned char *end, + unsigned char *ns_cert_type) +{ + int ret; + mbedtls_x509_bitstring bs = { 0, 0, NULL }; + + if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( bs.len != 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + /* Get actual bitstring */ + *ns_cert_type = *bs.p; + return( 0 ); +} + +static int x509_get_key_usage( unsigned char **p, + const unsigned char *end, + unsigned int *key_usage) +{ + int ret; + size_t i; + mbedtls_x509_bitstring bs = { 0, 0, NULL }; + + if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( bs.len < 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + /* Get actual bitstring */ + *key_usage = 0; + for( i = 0; i < bs.len && i < sizeof( unsigned int ); i++ ) + { + *key_usage |= (unsigned int) bs.p[i] << (8*i); + } + + return( 0 ); +} + +/* + * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + * + * KeyPurposeId ::= OBJECT IDENTIFIER + */ +static int x509_get_ext_key_usage( unsigned char **p, + const unsigned char *end, + mbedtls_x509_sequence *ext_key_usage) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_sequence_of( p, end, ext_key_usage, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + /* Sequence length must be >= 1 */ + if( ext_key_usage->buf.p == NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + return( 0 ); +} + +/* + * SubjectAltName ::= GeneralNames + * + * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + * + * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER } + * + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } + * + * EDIPartyName ::= SEQUENCE { + * nameAssigner [0] DirectoryString OPTIONAL, + * partyName [1] DirectoryString } + * + * NOTE: we list all types, but only use dNSName and otherName + * of type HwModuleName, as defined in RFC 4108, at this point. + */ +static int x509_get_subject_alt_name( unsigned char **p, + const unsigned char *end, + mbedtls_x509_sequence *subject_alt_name ) +{ + int ret; + size_t len, tag_len; + mbedtls_asn1_buf *buf; + unsigned char tag; + mbedtls_asn1_sequence *cur = subject_alt_name; + + /* Get main sequence tag */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + mbedtls_x509_subject_alternative_name dummy_san_buf; + memset( &dummy_san_buf, 0, sizeof( dummy_san_buf ) ); + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + tag = **p; + (*p)++; + if( ( ret = mbedtls_asn1_get_len( p, end, &tag_len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( ( tag & MBEDTLS_ASN1_TAG_CLASS_MASK ) != + MBEDTLS_ASN1_CONTEXT_SPECIFIC ) + { + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + } + + /* + * Check that the SAN are structured correct. + */ + ret = mbedtls_x509_parse_subject_alt_name( &(cur->buf), &dummy_san_buf ); + /* + * In case the extension is malformed, return an error, + * and clear the allocated sequences. + */ + if( ret != 0 && ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) + { + mbedtls_x509_sequence *seq_cur = subject_alt_name->next; + mbedtls_x509_sequence *seq_prv; + while( seq_cur != NULL ) + { + seq_prv = seq_cur; + seq_cur = seq_cur->next; + mbedtls_platform_zeroize( seq_prv, + sizeof( mbedtls_x509_sequence ) ); + mbedtls_free( seq_prv ); + } + subject_alt_name->next = NULL; + return( ret ); + } + + /* Allocate and assign next pointer */ + if( cur->buf.p != NULL ) + { + if( cur->next != NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + cur = cur->next; + } + + buf = &(cur->buf); + buf->tag = tag; + buf->p = *p; + buf->len = tag_len; + *p += buf->len; + } + + /* Set final sequence entry's next pointer to NULL */ + cur->next = NULL; + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } + * + * anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 } + * + * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation + * + * PolicyInformation ::= SEQUENCE { + * policyIdentifier CertPolicyId, + * policyQualifiers SEQUENCE SIZE (1..MAX) OF + * PolicyQualifierInfo OPTIONAL } + * + * CertPolicyId ::= OBJECT IDENTIFIER + * + * PolicyQualifierInfo ::= SEQUENCE { + * policyQualifierId PolicyQualifierId, + * qualifier ANY DEFINED BY policyQualifierId } + * + * -- policyQualifierIds for Internet policy qualifiers + * + * id-qt OBJECT IDENTIFIER ::= { id-pkix 2 } + * id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 } + * id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 } + * + * PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice ) + * + * Qualifier ::= CHOICE { + * cPSuri CPSuri, + * userNotice UserNotice } + * + * CPSuri ::= IA5String + * + * UserNotice ::= SEQUENCE { + * noticeRef NoticeReference OPTIONAL, + * explicitText DisplayText OPTIONAL } + * + * NoticeReference ::= SEQUENCE { + * organization DisplayText, + * noticeNumbers SEQUENCE OF INTEGER } + * + * DisplayText ::= CHOICE { + * ia5String IA5String (SIZE (1..200)), + * visibleString VisibleString (SIZE (1..200)), + * bmpString BMPString (SIZE (1..200)), + * utf8String UTF8String (SIZE (1..200)) } + * + * NOTE: we only parse and use anyPolicy without qualifiers at this point + * as defined in RFC 5280. + */ +static int x509_get_certificate_policies( unsigned char **p, + const unsigned char *end, + mbedtls_x509_sequence *certificate_policies ) +{ + int ret, parse_ret = 0; + size_t len; + mbedtls_asn1_buf *buf; + mbedtls_asn1_sequence *cur = certificate_policies; + + /* Get main sequence tag */ + ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * Cannot be an empty sequence. + */ + if( len == 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + mbedtls_x509_buf policy_oid; + const unsigned char *policy_end; + + /* + * Get the policy sequence + */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + policy_end = *p + len; + + if( ( ret = mbedtls_asn1_get_tag( p, policy_end, &len, + MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + policy_oid.tag = MBEDTLS_ASN1_OID; + policy_oid.len = len; + policy_oid.p = *p; + + /* + * Only AnyPolicy is currently supported when enforcing policy. + */ + if( MBEDTLS_OID_CMP( MBEDTLS_OID_ANY_POLICY, &policy_oid ) != 0 ) + { + /* + * Set the parsing return code but continue parsing, in case this + * extension is critical and MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + * is configured. + */ + parse_ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE; + } + + /* Allocate and assign next pointer */ + if( cur->buf.p != NULL ) + { + if( cur->next != NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + cur = cur->next; + } + + buf = &( cur->buf ); + buf->tag = policy_oid.tag; + buf->p = policy_oid.p; + buf->len = policy_oid.len; + + *p += len; + + /* + * If there is an optional qualifier, then *p < policy_end + * Check the Qualifier len to verify it doesn't exceed policy_end. + */ + if( *p < policy_end ) + { + if( ( ret = mbedtls_asn1_get_tag( p, policy_end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + /* + * Skip the optional policy qualifiers. + */ + *p += len; + } + + if( *p != policy_end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + /* Set final sequence entry's next pointer to NULL */ + cur->next = NULL; + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( parse_ret ); +} + +/* + * X.509 v3 extensions + * + */ +static int x509_get_crt_ext( unsigned char **p, + const unsigned char *end, + mbedtls_x509_crt *crt ) +{ + int ret; + size_t len; + unsigned char *end_ext_data, *end_ext_octet; + + if( ( ret = mbedtls_x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + while( *p < end ) + { + /* + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + */ + mbedtls_x509_buf extn_oid = {0, 0, NULL}; + int is_critical = 0; /* DEFAULT FALSE */ + int ext_type = 0; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + end_ext_data = *p + len; + + /* Get extension ID */ + if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &extn_oid.len, + MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + extn_oid.tag = MBEDTLS_ASN1_OID; + extn_oid.p = *p; + *p += extn_oid.len; + + /* Get optional critical */ + if( ( ret = mbedtls_asn1_get_bool( p, end_ext_data, &is_critical ) ) != 0 && + ( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + /* Data should be octet string type */ + if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &len, + MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + end_ext_octet = *p + len; + + if( end_ext_octet != end_ext_data ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * Detect supported extensions + */ + ret = mbedtls_oid_get_x509_ext_type( &extn_oid, &ext_type ); + + if( ret != 0 ) + { + /* No parser found, skip extension */ + *p = end_ext_octet; + +#if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) + if( is_critical ) + { + /* Data is marked as critical: fail */ + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + } +#endif + continue; + } + + /* Forbid repeated extensions */ + if( ( crt->ext_types & ext_type ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); + + crt->ext_types |= ext_type; + + switch( ext_type ) + { + case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS: + /* Parse basic constraints */ + if( ( ret = x509_get_basic_constraints( p, end_ext_octet, + &crt->ca_istrue, &crt->max_pathlen ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_KEY_USAGE: + /* Parse key usage */ + if( ( ret = x509_get_key_usage( p, end_ext_octet, + &crt->key_usage ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE: + /* Parse extended key usage */ + if( ( ret = x509_get_ext_key_usage( p, end_ext_octet, + &crt->ext_key_usage ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME: + /* Parse subject alt name */ + if( ( ret = x509_get_subject_alt_name( p, end_ext_octet, + &crt->subject_alt_names ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_NS_CERT_TYPE: + /* Parse netscape certificate type */ + if( ( ret = x509_get_ns_cert_type( p, end_ext_octet, + &crt->ns_cert_type ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES: + /* Parse certificate policies type */ + if( ( ret = x509_get_certificate_policies( p, end_ext_octet, + &crt->certificate_policies ) ) != 0 ) + { +#if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) + if( is_critical ) + return( ret ); + else +#endif + /* + * If MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE is returned, then we + * cannot interpret or enforce the policy. However, it is up to + * the user to choose how to enforce the policies, + * unless the extension is critical. + */ + if( ret != MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) + return( ret ); + } + break; + + default: + /* + * If this is a non-critical extension, which the oid layer + * supports, but there isn't an x509 parser for it, + * skip the extension. + */ +#if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) + if( is_critical ) + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); + else +#endif + *p = end_ext_octet; + } + } + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Parse and fill a single X.509 certificate in DER format + */ +static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, + const unsigned char *buf, + size_t buflen, + int make_copy ) +{ + int ret; + size_t len; + unsigned char *p, *end, *crt_end; + mbedtls_x509_buf sig_params1, sig_params2, sig_oid2; + + memset( &sig_params1, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_params2, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_oid2, 0, sizeof( mbedtls_x509_buf ) ); + + /* + * Check for valid input + */ + if( crt == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + /* Use the original buffer until we figure out actual length. */ + p = (unsigned char*) buf; + len = buflen; + end = p + len; + + /* + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + } + + end = crt_end = p + len; + crt->raw.len = crt_end - buf; + if( make_copy != 0 ) + { + /* Create and populate a new buffer for the raw field. */ + crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len ); + if( crt->raw.p == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + memcpy( crt->raw.p, buf, crt->raw.len ); + crt->own_buffer = 1; + + p += crt->raw.len - len; + end = crt_end = p + len; + } + else + { + crt->raw.p = (unsigned char*) buf; + crt->own_buffer = 0; + } + + /* + * TBSCertificate ::= SEQUENCE { + */ + crt->tbs.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + end = p + len; + crt->tbs.len = end - crt->tbs.p; + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + * + * CertificateSerialNumber ::= INTEGER + * + * signature AlgorithmIdentifier + */ + if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 || + ( ret = mbedtls_x509_get_serial( &p, end, &crt->serial ) ) != 0 || + ( ret = mbedtls_x509_get_alg( &p, end, &crt->sig_oid, + &sig_params1 ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + if( crt->version < 0 || crt->version > 2 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); + } + + crt->version++; + + if( ( ret = mbedtls_x509_get_sig_alg( &crt->sig_oid, &sig_params1, + &crt->sig_md, &crt->sig_pk, + &crt->sig_opts ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + /* + * issuer Name + */ + crt->issuer_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_x509_get_name( &p, p + len, &crt->issuer ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + crt->issuer_raw.len = p - crt->issuer_raw.p; + + /* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + * + */ + if( ( ret = x509_get_dates( &p, end, &crt->valid_from, + &crt->valid_to ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + /* + * subject Name + */ + crt->subject_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( len && ( ret = mbedtls_x509_get_name( &p, p + len, &crt->subject ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + crt->subject_raw.len = p - crt->subject_raw.p; + + /* + * SubjectPublicKeyInfo + */ + crt->pk_raw.p = p; + if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + crt->pk_raw.len = p - crt->pk_raw.p; + + /* + * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + * extensions [3] EXPLICIT Extensions OPTIONAL + * -- If present, version shall be v3 + */ + if( crt->version == 2 || crt->version == 3 ) + { + ret = x509_get_uid( &p, end, &crt->issuer_id, 1 ); + if( ret != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + } + + if( crt->version == 2 || crt->version == 3 ) + { + ret = x509_get_uid( &p, end, &crt->subject_id, 2 ); + if( ret != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + } + +#if !defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) + if( crt->version == 3 ) +#endif + { + ret = x509_get_crt_ext( &p, end, crt ); + if( ret != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + } + + if( p != end ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + end = crt_end; + + /* + * } + * -- end of TBSCertificate + * + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + */ + if( ( ret = mbedtls_x509_get_alg( &p, end, &sig_oid2, &sig_params2 ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + if( crt->sig_oid.len != sig_oid2.len || + memcmp( crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len ) != 0 || + sig_params1.len != sig_params2.len || + ( sig_params1.len != 0 && + memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_SIG_MISMATCH ); + } + + if( ( ret = mbedtls_x509_get_sig( &p, end, &crt->sig ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + if( p != end ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + return( 0 ); +} + +/* + * Parse one X.509 certificate in DER format from a buffer and add them to a + * chained list + */ +static int mbedtls_x509_crt_parse_der_internal( mbedtls_x509_crt *chain, + const unsigned char *buf, + size_t buflen, + int make_copy ) +{ + int ret; + mbedtls_x509_crt *crt = chain, *prev = NULL; + + /* + * Check for valid input + */ + if( crt == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + while( crt->version != 0 && crt->next != NULL ) + { + prev = crt; + crt = crt->next; + } + + /* + * Add new certificate on the end of the chain if needed. + */ + if( crt->version != 0 && crt->next == NULL ) + { + crt->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); + + if( crt->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + prev = crt; + mbedtls_x509_crt_init( crt->next ); + crt = crt->next; + } + + if( ( ret = x509_crt_parse_der_core( crt, buf, buflen, make_copy ) ) != 0 ) + { + if( prev ) + prev->next = NULL; + + if( crt != chain ) + mbedtls_free( crt ); + + return( ret ); + } + + return( 0 ); +} + +int mbedtls_x509_crt_parse_der_nocopy( mbedtls_x509_crt *chain, + const unsigned char *buf, + size_t buflen ) +{ + return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 0 ) ); +} + +int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, + const unsigned char *buf, + size_t buflen ) +{ + return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 1 ) ); +} + +/* + * Parse one or more PEM certificates from a buffer and add them to the chained + * list + */ +int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, + const unsigned char *buf, + size_t buflen ) +{ +#if defined(MBEDTLS_PEM_PARSE_C) + int success = 0, first_error = 0, total_failed = 0; + int buf_format = MBEDTLS_X509_FORMAT_DER; +#endif + + /* + * Check for valid input + */ + if( chain == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + /* + * Determine buffer content. Buffer contains either one DER certificate or + * one or more PEM certificates. + */ +#if defined(MBEDTLS_PEM_PARSE_C) + if( buflen != 0 && buf[buflen - 1] == '\0' && + strstr( (const char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL ) + { + buf_format = MBEDTLS_X509_FORMAT_PEM; + } + + if( buf_format == MBEDTLS_X509_FORMAT_DER ) + return mbedtls_x509_crt_parse_der( chain, buf, buflen ); +#else + return mbedtls_x509_crt_parse_der( chain, buf, buflen ); +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) + if( buf_format == MBEDTLS_X509_FORMAT_PEM ) + { + int ret; + mbedtls_pem_context pem; + + /* 1 rather than 0 since the terminating NULL byte is counted in */ + while( buflen > 1 ) + { + size_t use_len; + mbedtls_pem_init( &pem ); + + /* If we get there, we know the string is null-terminated */ + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN CERTIFICATE-----", + "-----END CERTIFICATE-----", + buf, NULL, 0, &use_len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + buflen -= use_len; + buf += use_len; + } + else if( ret == MBEDTLS_ERR_PEM_BAD_INPUT_DATA ) + { + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + + /* + * PEM header and footer were found + */ + buflen -= use_len; + buf += use_len; + + if( first_error == 0 ) + first_error = ret; + + total_failed++; + continue; + } + else + break; + + ret = mbedtls_x509_crt_parse_der( chain, pem.buf, pem.buflen ); + + mbedtls_pem_free( &pem ); + + if( ret != 0 ) + { + /* + * Quit parsing on a memory error + */ + if( ret == MBEDTLS_ERR_X509_ALLOC_FAILED ) + return( ret ); + + if( first_error == 0 ) + first_error = ret; + + total_failed++; + continue; + } + + success = 1; + } + } + + if( success ) + return( total_failed ); + else if( first_error ) + return( first_error ); + else + return( MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT ); +#endif /* MBEDTLS_PEM_PARSE_C */ +} + +#if defined(MBEDTLS_FS_IO) +/* + * Load one or more certificates and add them to the chained list + */ +int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_x509_crt_parse( chain, buf, n ); + + mbedtls_platform_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} + +int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) +{ + int ret = 0; +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + int w_ret; + WCHAR szDir[MAX_PATH]; + char filename[MAX_PATH]; + char *p; + size_t len = strlen( path ); + + WIN32_FIND_DATAW file_data; + HANDLE hFind; + + if( len > MAX_PATH - 3 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + memset( szDir, 0, sizeof(szDir) ); + memset( filename, 0, MAX_PATH ); + memcpy( filename, path, len ); + filename[len++] = '\\'; + p = filename + len; + filename[len++] = '*'; + + w_ret = MultiByteToWideChar( CP_ACP, 0, filename, (int)len, szDir, + MAX_PATH - 3 ); + if( w_ret == 0 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + hFind = FindFirstFileW( szDir, &file_data ); + if( hFind == INVALID_HANDLE_VALUE ) + return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); + + len = MAX_PATH - len; + do + { + memset( p, 0, len ); + + if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + continue; + + w_ret = WideCharToMultiByte( CP_ACP, 0, file_data.cFileName, + lstrlenW( file_data.cFileName ), + p, (int) len - 1, + NULL, NULL ); + if( w_ret == 0 ) + { + ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; + goto cleanup; + } + + w_ret = mbedtls_x509_crt_parse_file( chain, filename ); + if( w_ret < 0 ) + ret++; + else + ret += w_ret; + } + while( FindNextFileW( hFind, &file_data ) != 0 ); + + if( GetLastError() != ERROR_NO_MORE_FILES ) + ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; + +cleanup: + FindClose( hFind ); +#else /* _WIN32 */ + int t_ret; + int snp_ret; + struct stat sb; + struct dirent *entry; + char entry_name[MBEDTLS_X509_MAX_FILE_PATH_LEN]; + DIR *dir = opendir( path ); + + if( dir == NULL ) + return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &mbedtls_threading_readdir_mutex ) ) != 0 ) + { + closedir( dir ); + return( ret ); + } +#endif /* MBEDTLS_THREADING_C */ + + while( ( entry = readdir( dir ) ) != NULL ) + { + snp_ret = mbedtls_snprintf( entry_name, sizeof entry_name, + "%s/%s", path, entry->d_name ); + + if( snp_ret < 0 || (size_t)snp_ret >= sizeof entry_name ) + { + ret = MBEDTLS_ERR_X509_BUFFER_TOO_SMALL; + goto cleanup; + } + else if( stat( entry_name, &sb ) == -1 ) + { + ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; + goto cleanup; + } + + if( !S_ISREG( sb.st_mode ) ) + continue; + + // Ignore parse errors + // + t_ret = mbedtls_x509_crt_parse_file( chain, entry_name ); + if( t_ret < 0 ) + ret++; + else + ret += t_ret; + } + +cleanup: + closedir( dir ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &mbedtls_threading_readdir_mutex ) != 0 ) + ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR; +#endif /* MBEDTLS_THREADING_C */ + +#endif /* _WIN32 */ + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +/* + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } + * + * HardwareModuleName ::= SEQUENCE { + * hwType OBJECT IDENTIFIER, + * hwSerialNum OCTET STRING } + * + * NOTE: we currently only parse and use otherName of type HwModuleName, + * as defined in RFC 4108. + */ +static int x509_get_other_name( const mbedtls_x509_buf *subject_alt_name, + mbedtls_x509_san_other_name *other_name ) +{ + int ret = 0; + size_t len; + unsigned char *p = subject_alt_name->p; + const unsigned char *end = p + subject_alt_name->len; + mbedtls_x509_buf cur_oid; + + if( ( subject_alt_name->tag & + ( MBEDTLS_ASN1_TAG_CLASS_MASK | MBEDTLS_ASN1_TAG_VALUE_MASK ) ) != + ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME ) ) + { + /* + * The given subject alternative name is not of type "othername". + */ + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + } + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + cur_oid.tag = MBEDTLS_ASN1_OID; + cur_oid.p = p; + cur_oid.len = len; + + /* + * Only HwModuleName is currently supported. + */ + if( MBEDTLS_OID_CMP( MBEDTLS_OID_ON_HW_MODULE_NAME, &cur_oid ) != 0 ) + { + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); + } + + if( p + len >= end ) + { + mbedtls_platform_zeroize( other_name, sizeof( other_name ) ); + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + p += len; + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + other_name->value.hardware_module_name.oid.tag = MBEDTLS_ASN1_OID; + other_name->value.hardware_module_name.oid.p = p; + other_name->value.hardware_module_name.oid.len = len; + + if( p + len >= end ) + { + mbedtls_platform_zeroize( other_name, sizeof( other_name ) ); + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + p += len; + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + other_name->value.hardware_module_name.val.tag = MBEDTLS_ASN1_OCTET_STRING; + other_name->value.hardware_module_name.val.p = p; + other_name->value.hardware_module_name.val.len = len; + p += len; + if( p != end ) + { + mbedtls_platform_zeroize( other_name, + sizeof( other_name ) ); + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + return( 0 ); +} + +static int x509_info_subject_alt_name( char **buf, size_t *size, + const mbedtls_x509_sequence + *subject_alt_name, + const char *prefix ) +{ + int ret; + size_t n = *size; + char *p = *buf; + const mbedtls_x509_sequence *cur = subject_alt_name; + mbedtls_x509_subject_alternative_name san; + int parse_ret; + + while( cur != NULL ) + { + memset( &san, 0, sizeof( san ) ); + parse_ret = mbedtls_x509_parse_subject_alt_name( &cur->buf, &san ); + if( parse_ret != 0 ) + { + if( parse_ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ) + { + ret = mbedtls_snprintf( p, n, "\n%s ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + else + { + ret = mbedtls_snprintf( p, n, "\n%s ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + cur = cur->next; + continue; + } + + switch( san.type ) + { + /* + * otherName + */ + case MBEDTLS_X509_SAN_OTHER_NAME: + { + mbedtls_x509_san_other_name *other_name = &san.san.other_name; + + ret = mbedtls_snprintf( p, n, "\n%s otherName :", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( MBEDTLS_OID_CMP( MBEDTLS_OID_ON_HW_MODULE_NAME, + &other_name->value.hardware_module_name.oid ) != 0 ) + { + ret = mbedtls_snprintf( p, n, "\n%s hardware module name :", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_snprintf( p, n, "\n%s hardware type : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_oid_get_numeric_string( p, n, &other_name->value.hardware_module_name.oid ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%s hardware serial number : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( other_name->value.hardware_module_name.val.len >= n ) + { + *p = '\0'; + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); + } + + memcpy( p, other_name->value.hardware_module_name.val.p, + other_name->value.hardware_module_name.val.len ); + p += other_name->value.hardware_module_name.val.len; + + n -= other_name->value.hardware_module_name.val.len; + + }/* MBEDTLS_OID_ON_HW_MODULE_NAME */ + } + break; + + /* + * dNSName + */ + case MBEDTLS_X509_SAN_DNS_NAME: + { + ret = mbedtls_snprintf( p, n, "\n%s dNSName : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + if( san.san.unstructured_name.len >= n ) + { + *p = '\0'; + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); + } + + memcpy( p, san.san.unstructured_name.p, san.san.unstructured_name.len ); + p += san.san.unstructured_name.len; + n -= san.san.unstructured_name.len; + } + break; + + /* + * Type not supported, skip item. + */ + default: + ret = mbedtls_snprintf( p, n, "\n%s ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + break; + } + + cur = cur->next; + } + + *p = '\0'; + + *size = n; + *buf = p; + + return( 0 ); +} + +int mbedtls_x509_parse_subject_alt_name( const mbedtls_x509_buf *san_buf, + mbedtls_x509_subject_alternative_name *san ) +{ + int ret; + switch( san_buf->tag & + ( MBEDTLS_ASN1_TAG_CLASS_MASK | + MBEDTLS_ASN1_TAG_VALUE_MASK ) ) + { + /* + * otherName + */ + case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_OTHER_NAME ): + { + mbedtls_x509_san_other_name other_name; + + ret = x509_get_other_name( san_buf, &other_name ); + if( ret != 0 ) + return( ret ); + + memset( san, 0, sizeof( mbedtls_x509_subject_alternative_name ) ); + san->type = MBEDTLS_X509_SAN_OTHER_NAME; + memcpy( &san->san.other_name, + &other_name, sizeof( other_name ) ); + + } + break; + + /* + * dNSName + */ + case( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_X509_SAN_DNS_NAME ): + { + memset( san, 0, sizeof( mbedtls_x509_subject_alternative_name ) ); + san->type = MBEDTLS_X509_SAN_DNS_NAME; + + memcpy( &san->san.unstructured_name, + san_buf, sizeof( *san_buf ) ); + + } + break; + + /* + * Type not supported + */ + default: + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); + } + return( 0 ); +} + +#define PRINT_ITEM(i) \ + { \ + ret = mbedtls_snprintf( p, n, "%s" i, sep ); \ + MBEDTLS_X509_SAFE_SNPRINTF; \ + sep = ", "; \ + } + +#define CERT_TYPE(type,name) \ + if( ns_cert_type & (type) ) \ + PRINT_ITEM( name ); + +static int x509_info_cert_type( char **buf, size_t *size, + unsigned char ns_cert_type ) +{ + int ret; + size_t n = *size; + char *p = *buf; + const char *sep = ""; + + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT, "SSL Client" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER, "SSL Server" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_EMAIL, "Email" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING, "Object Signing" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_RESERVED, "Reserved" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_CA, "SSL CA" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA, "Email CA" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA, "Object Signing CA" ); + + *size = n; + *buf = p; + + return( 0 ); +} + +#define KEY_USAGE(code,name) \ + if( key_usage & (code) ) \ + PRINT_ITEM( name ); + +static int x509_info_key_usage( char **buf, size_t *size, + unsigned int key_usage ) +{ + int ret; + size_t n = *size; + char *p = *buf; + const char *sep = ""; + + KEY_USAGE( MBEDTLS_X509_KU_DIGITAL_SIGNATURE, "Digital Signature" ); + KEY_USAGE( MBEDTLS_X509_KU_NON_REPUDIATION, "Non Repudiation" ); + KEY_USAGE( MBEDTLS_X509_KU_KEY_ENCIPHERMENT, "Key Encipherment" ); + KEY_USAGE( MBEDTLS_X509_KU_DATA_ENCIPHERMENT, "Data Encipherment" ); + KEY_USAGE( MBEDTLS_X509_KU_KEY_AGREEMENT, "Key Agreement" ); + KEY_USAGE( MBEDTLS_X509_KU_KEY_CERT_SIGN, "Key Cert Sign" ); + KEY_USAGE( MBEDTLS_X509_KU_CRL_SIGN, "CRL Sign" ); + KEY_USAGE( MBEDTLS_X509_KU_ENCIPHER_ONLY, "Encipher Only" ); + KEY_USAGE( MBEDTLS_X509_KU_DECIPHER_ONLY, "Decipher Only" ); + + *size = n; + *buf = p; + + return( 0 ); +} + +static int x509_info_ext_key_usage( char **buf, size_t *size, + const mbedtls_x509_sequence *extended_key_usage ) +{ + int ret; + const char *desc; + size_t n = *size; + char *p = *buf; + const mbedtls_x509_sequence *cur = extended_key_usage; + const char *sep = ""; + + while( cur != NULL ) + { + if( mbedtls_oid_get_extended_key_usage( &cur->buf, &desc ) != 0 ) + desc = "???"; + + ret = mbedtls_snprintf( p, n, "%s%s", sep, desc ); + MBEDTLS_X509_SAFE_SNPRINTF; + + sep = ", "; + + cur = cur->next; + } + + *size = n; + *buf = p; + + return( 0 ); +} + +static int x509_info_cert_policies( char **buf, size_t *size, + const mbedtls_x509_sequence *certificate_policies ) +{ + int ret; + const char *desc; + size_t n = *size; + char *p = *buf; + const mbedtls_x509_sequence *cur = certificate_policies; + const char *sep = ""; + + while( cur != NULL ) + { + if( mbedtls_oid_get_certificate_policies( &cur->buf, &desc ) != 0 ) + desc = "???"; + + ret = mbedtls_snprintf( p, n, "%s%s", sep, desc ); + MBEDTLS_X509_SAFE_SNPRINTF; + + sep = ", "; + + cur = cur->next; + } + + *size = n; + *buf = p; + + return( 0 ); +} + +/* + * Return an informational string about the certificate. + */ +#define BEFORE_COLON 18 +#define BC "18" +int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crt *crt ) +{ + int ret; + size_t n; + char *p; + char key_size_str[BEFORE_COLON]; + + p = buf; + n = size; + + if( NULL == crt ) + { + ret = mbedtls_snprintf( p, n, "\nCertificate is uninitialised!\n" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( (int) ( size - n ) ); + } + + ret = mbedtls_snprintf( p, n, "%scert. version : %d\n", + prefix, crt->version ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_snprintf( p, n, "%sserial number : ", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_serial_gets( p, n, &crt->serial ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &crt->issuer ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &crt->subject ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sissued on : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crt->valid_from.year, crt->valid_from.mon, + crt->valid_from.day, crt->valid_from.hour, + crt->valid_from.min, crt->valid_from.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crt->valid_to.year, crt->valid_to.mon, + crt->valid_to.day, crt->valid_to.hour, + crt->valid_to.min, crt->valid_to.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_sig_alg_gets( p, n, &crt->sig_oid, crt->sig_pk, + crt->sig_md, crt->sig_opts ); + MBEDTLS_X509_SAFE_SNPRINTF; + + /* Key size */ + if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, + mbedtls_pk_get_name( &crt->pk ) ) ) != 0 ) + { + return( ret ); + } + + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str, + (int) mbedtls_pk_get_bitlen( &crt->pk ) ); + MBEDTLS_X509_SAFE_SNPRINTF; + + /* + * Optional extensions + */ + + if( crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS ) + { + ret = mbedtls_snprintf( p, n, "\n%sbasic constraints : CA=%s", prefix, + crt->ca_istrue ? "true" : "false" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( crt->max_pathlen > 0 ) + { + ret = mbedtls_snprintf( p, n, ", max_pathlen=%d", crt->max_pathlen - 1 ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + } + + if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) + { + ret = mbedtls_snprintf( p, n, "\n%ssubject alt name :", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_subject_alt_name( &p, &n, + &crt->subject_alt_names, + prefix ) ) != 0 ) + return( ret ); + } + + if( crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE ) + { + ret = mbedtls_snprintf( p, n, "\n%scert. type : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_cert_type( &p, &n, crt->ns_cert_type ) ) != 0 ) + return( ret ); + } + + if( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) + { + ret = mbedtls_snprintf( p, n, "\n%skey usage : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_key_usage( &p, &n, crt->key_usage ) ) != 0 ) + return( ret ); + } + + if( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) + { + ret = mbedtls_snprintf( p, n, "\n%sext key usage : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_ext_key_usage( &p, &n, + &crt->ext_key_usage ) ) != 0 ) + return( ret ); + } + + if( crt->ext_types & MBEDTLS_OID_X509_EXT_CERTIFICATE_POLICIES ) + { + ret = mbedtls_snprintf( p, n, "\n%scertificate policies : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_cert_policies( &p, &n, + &crt->certificate_policies ) ) != 0 ) + return( ret ); + } + + ret = mbedtls_snprintf( p, n, "\n" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( (int) ( size - n ) ); +} + +struct x509_crt_verify_string { + int code; + const char *string; +}; + +static const struct x509_crt_verify_string x509_crt_verify_strings[] = { + { MBEDTLS_X509_BADCERT_EXPIRED, "The certificate validity has expired" }, + { MBEDTLS_X509_BADCERT_REVOKED, "The certificate has been revoked (is on a CRL)" }, + { MBEDTLS_X509_BADCERT_CN_MISMATCH, "The certificate Common Name (CN) does not match with the expected CN" }, + { MBEDTLS_X509_BADCERT_NOT_TRUSTED, "The certificate is not correctly signed by the trusted CA" }, + { MBEDTLS_X509_BADCRL_NOT_TRUSTED, "The CRL is not correctly signed by the trusted CA" }, + { MBEDTLS_X509_BADCRL_EXPIRED, "The CRL is expired" }, + { MBEDTLS_X509_BADCERT_MISSING, "Certificate was missing" }, + { MBEDTLS_X509_BADCERT_SKIP_VERIFY, "Certificate verification was skipped" }, + { MBEDTLS_X509_BADCERT_OTHER, "Other reason (can be used by verify callback)" }, + { MBEDTLS_X509_BADCERT_FUTURE, "The certificate validity starts in the future" }, + { MBEDTLS_X509_BADCRL_FUTURE, "The CRL is from the future" }, + { MBEDTLS_X509_BADCERT_KEY_USAGE, "Usage does not match the keyUsage extension" }, + { MBEDTLS_X509_BADCERT_EXT_KEY_USAGE, "Usage does not match the extendedKeyUsage extension" }, + { MBEDTLS_X509_BADCERT_NS_CERT_TYPE, "Usage does not match the nsCertType extension" }, + { MBEDTLS_X509_BADCERT_BAD_MD, "The certificate is signed with an unacceptable hash." }, + { MBEDTLS_X509_BADCERT_BAD_PK, "The certificate is signed with an unacceptable PK alg (eg RSA vs ECDSA)." }, + { MBEDTLS_X509_BADCERT_BAD_KEY, "The certificate is signed with an unacceptable key (eg bad curve, RSA too short)." }, + { MBEDTLS_X509_BADCRL_BAD_MD, "The CRL is signed with an unacceptable hash." }, + { MBEDTLS_X509_BADCRL_BAD_PK, "The CRL is signed with an unacceptable PK alg (eg RSA vs ECDSA)." }, + { MBEDTLS_X509_BADCRL_BAD_KEY, "The CRL is signed with an unacceptable key (eg bad curve, RSA too short)." }, + { 0, NULL } +}; + +int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix, + uint32_t flags ) +{ + int ret; + const struct x509_crt_verify_string *cur; + char *p = buf; + size_t n = size; + + for( cur = x509_crt_verify_strings; cur->string != NULL ; cur++ ) + { + if( ( flags & cur->code ) == 0 ) + continue; + + ret = mbedtls_snprintf( p, n, "%s%s\n", prefix, cur->string ); + MBEDTLS_X509_SAFE_SNPRINTF; + flags ^= cur->code; + } + + if( flags != 0 ) + { + ret = mbedtls_snprintf( p, n, "%sUnknown reason " + "(this should not happen)\n", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + return( (int) ( size - n ) ); +} + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) +int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, + unsigned int usage ) +{ + unsigned int usage_must, usage_may; + unsigned int may_mask = MBEDTLS_X509_KU_ENCIPHER_ONLY + | MBEDTLS_X509_KU_DECIPHER_ONLY; + + if( ( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) == 0 ) + return( 0 ); + + usage_must = usage & ~may_mask; + + if( ( ( crt->key_usage & ~may_mask ) & usage_must ) != usage_must ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + usage_may = usage & may_mask; + + if( ( ( crt->key_usage & may_mask ) | usage_may ) != usage_may ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + return( 0 ); +} +#endif + +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) +int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, + const char *usage_oid, + size_t usage_len ) +{ + const mbedtls_x509_sequence *cur; + + /* Extension is not mandatory, absent means no restriction */ + if( ( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) == 0 ) + return( 0 ); + + /* + * Look for the requested usage (or wildcard ANY) in our list + */ + for( cur = &crt->ext_key_usage; cur != NULL; cur = cur->next ) + { + const mbedtls_x509_buf *cur_oid = &cur->buf; + + if( cur_oid->len == usage_len && + memcmp( cur_oid->p, usage_oid, usage_len ) == 0 ) + { + return( 0 ); + } + + if( MBEDTLS_OID_CMP( MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, cur_oid ) == 0 ) + return( 0 ); + } + + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); +} +#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ + +#if defined(MBEDTLS_X509_CRL_PARSE_C) +/* + * Return 1 if the certificate is revoked, or 0 otherwise. + */ +int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl ) +{ + const mbedtls_x509_crl_entry *cur = &crl->entry; + + while( cur != NULL && cur->serial.len != 0 ) + { + if( crt->serial.len == cur->serial.len && + memcmp( crt->serial.p, cur->serial.p, crt->serial.len ) == 0 ) + { + if( mbedtls_x509_time_is_past( &cur->revocation_date ) ) + return( 1 ); + } + + cur = cur->next; + } + + return( 0 ); +} + +/* + * Check that the given certificate is not revoked according to the CRL. + * Skip validation if no CRL for the given CA is present. + */ +static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, + mbedtls_x509_crl *crl_list, + const mbedtls_x509_crt_profile *profile ) +{ + int flags = 0; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + const mbedtls_md_info_t *md_info; + + if( ca == NULL ) + return( flags ); + + while( crl_list != NULL ) + { + if( crl_list->version == 0 || + x509_name_cmp( &crl_list->issuer, &ca->subject ) != 0 ) + { + crl_list = crl_list->next; + continue; + } + + /* + * Check if the CA is configured to sign CRLs + */ +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + if( mbedtls_x509_crt_check_key_usage( ca, + MBEDTLS_X509_KU_CRL_SIGN ) != 0 ) + { + flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; + break; + } +#endif + + /* + * Check if CRL is correctly signed by the trusted CA + */ + if( x509_profile_check_md_alg( profile, crl_list->sig_md ) != 0 ) + flags |= MBEDTLS_X509_BADCRL_BAD_MD; + + if( x509_profile_check_pk_alg( profile, crl_list->sig_pk ) != 0 ) + flags |= MBEDTLS_X509_BADCRL_BAD_PK; + + md_info = mbedtls_md_info_from_type( crl_list->sig_md ); + if( mbedtls_md( md_info, crl_list->tbs.p, crl_list->tbs.len, hash ) != 0 ) + { + /* Note: this can't happen except after an internal error */ + flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; + break; + } + + if( x509_profile_check_key( profile, &ca->pk ) != 0 ) + flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + if( mbedtls_pk_verify_ext( crl_list->sig_pk, crl_list->sig_opts, &ca->pk, + crl_list->sig_md, hash, mbedtls_md_get_size( md_info ), + crl_list->sig.p, crl_list->sig.len ) != 0 ) + { + flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; + break; + } + + /* + * Check for validity of CRL (Do not drop out) + */ + if( mbedtls_x509_time_is_past( &crl_list->next_update ) ) + flags |= MBEDTLS_X509_BADCRL_EXPIRED; + + if( mbedtls_x509_time_is_future( &crl_list->this_update ) ) + flags |= MBEDTLS_X509_BADCRL_FUTURE; + + /* + * Check if certificate is revoked + */ + if( mbedtls_x509_crt_is_revoked( crt, crl_list ) ) + { + flags |= MBEDTLS_X509_BADCERT_REVOKED; + break; + } + + crl_list = crl_list->next; + } + + return( flags ); +} +#endif /* MBEDTLS_X509_CRL_PARSE_C */ + +/* + * Check the signature of a certificate by its parent + */ +static int x509_crt_check_signature( const mbedtls_x509_crt *child, + mbedtls_x509_crt *parent, + mbedtls_x509_crt_restart_ctx *rs_ctx ) +{ + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + size_t hash_len; +#if !defined(MBEDTLS_USE_PSA_CRYPTO) + const mbedtls_md_info_t *md_info; + md_info = mbedtls_md_info_from_type( child->sig_md ); + hash_len = mbedtls_md_get_size( md_info ); + + /* Note: hash errors can happen only after an internal error */ + if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 ) + return( -1 ); +#else + psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT; + psa_algorithm_t hash_alg = mbedtls_psa_translate_md( child->sig_md ); + + if( psa_hash_setup( &hash_operation, hash_alg ) != PSA_SUCCESS ) + return( -1 ); + + if( psa_hash_update( &hash_operation, child->tbs.p, child->tbs.len ) + != PSA_SUCCESS ) + { + return( -1 ); + } + + if( psa_hash_finish( &hash_operation, hash, sizeof( hash ), &hash_len ) + != PSA_SUCCESS ) + { + return( -1 ); + } +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + /* Skip expensive computation on obvious mismatch */ + if( ! mbedtls_pk_can_do( &parent->pk, child->sig_pk ) ) + return( -1 ); + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && child->sig_pk == MBEDTLS_PK_ECDSA ) + { + return( mbedtls_pk_verify_restartable( &parent->pk, + child->sig_md, hash, hash_len, + child->sig.p, child->sig.len, &rs_ctx->pk ) ); + } +#else + (void) rs_ctx; +#endif + + return( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk, + child->sig_md, hash, hash_len, + child->sig.p, child->sig.len ) ); +} + +/* + * Check if 'parent' is a suitable parent (signing CA) for 'child'. + * Return 0 if yes, -1 if not. + * + * top means parent is a locally-trusted certificate + */ +static int x509_crt_check_parent( const mbedtls_x509_crt *child, + const mbedtls_x509_crt *parent, + int top ) +{ + int need_ca_bit; + + /* Parent must be the issuer */ + if( x509_name_cmp( &child->issuer, &parent->subject ) != 0 ) + return( -1 ); + + /* Parent must have the basicConstraints CA bit set as a general rule */ + need_ca_bit = 1; + + /* Exception: v1/v2 certificates that are locally trusted. */ + if( top && parent->version < 3 ) + need_ca_bit = 0; + + if( need_ca_bit && ! parent->ca_istrue ) + return( -1 ); + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + if( need_ca_bit && + mbedtls_x509_crt_check_key_usage( parent, MBEDTLS_X509_KU_KEY_CERT_SIGN ) != 0 ) + { + return( -1 ); + } +#endif + + return( 0 ); +} + +/* + * Find a suitable parent for child in candidates, or return NULL. + * + * Here suitable is defined as: + * 1. subject name matches child's issuer + * 2. if necessary, the CA bit is set and key usage allows signing certs + * 3. for trusted roots, the signature is correct + * (for intermediates, the signature is checked and the result reported) + * 4. pathlen constraints are satisfied + * + * If there's a suitable candidate which is also time-valid, return the first + * such. Otherwise, return the first suitable candidate (or NULL if there is + * none). + * + * The rationale for this rule is that someone could have a list of trusted + * roots with two versions on the same root with different validity periods. + * (At least one user reported having such a list and wanted it to just work.) + * The reason we don't just require time-validity is that generally there is + * only one version, and if it's expired we want the flags to state that + * rather than NOT_TRUSTED, as would be the case if we required it here. + * + * The rationale for rule 3 (signature for trusted roots) is that users might + * have two versions of the same CA with different keys in their list, and the + * way we select the correct one is by checking the signature (as we don't + * rely on key identifier extensions). (This is one way users might choose to + * handle key rollover, another relies on self-issued certs, see [SIRO].) + * + * Arguments: + * - [in] child: certificate for which we're looking for a parent + * - [in] candidates: chained list of potential parents + * - [out] r_parent: parent found (or NULL) + * - [out] r_signature_is_good: 1 if child signature by parent is valid, or 0 + * - [in] top: 1 if candidates consists of trusted roots, ie we're at the top + * of the chain, 0 otherwise + * - [in] path_cnt: number of intermediates seen so far + * - [in] self_cnt: number of self-signed intermediates seen so far + * (will never be greater than path_cnt) + * - [in-out] rs_ctx: context for restarting operations + * + * Return value: + * - 0 on success + * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise + */ +static int x509_crt_find_parent_in( + mbedtls_x509_crt *child, + mbedtls_x509_crt *candidates, + mbedtls_x509_crt **r_parent, + int *r_signature_is_good, + int top, + unsigned path_cnt, + unsigned self_cnt, + mbedtls_x509_crt_restart_ctx *rs_ctx ) +{ + int ret; + mbedtls_x509_crt *parent, *fallback_parent; + int signature_is_good, fallback_signature_is_good; + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + /* did we have something in progress? */ + if( rs_ctx != NULL && rs_ctx->parent != NULL ) + { + /* restore saved state */ + parent = rs_ctx->parent; + fallback_parent = rs_ctx->fallback_parent; + fallback_signature_is_good = rs_ctx->fallback_signature_is_good; + + /* clear saved state */ + rs_ctx->parent = NULL; + rs_ctx->fallback_parent = NULL; + rs_ctx->fallback_signature_is_good = 0; + + /* resume where we left */ + goto check_signature; + } +#endif + + fallback_parent = NULL; + fallback_signature_is_good = 0; + + for( parent = candidates; parent != NULL; parent = parent->next ) + { + /* basic parenting skills (name, CA bit, key usage) */ + if( x509_crt_check_parent( child, parent, top ) != 0 ) + continue; + + /* +1 because stored max_pathlen is 1 higher that the actual value */ + if( parent->max_pathlen > 0 && + (size_t) parent->max_pathlen < 1 + path_cnt - self_cnt ) + { + continue; + } + + /* Signature */ +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +check_signature: +#endif + ret = x509_crt_check_signature( child, parent, rs_ctx ); + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + { + /* save state */ + rs_ctx->parent = parent; + rs_ctx->fallback_parent = fallback_parent; + rs_ctx->fallback_signature_is_good = fallback_signature_is_good; + + return( ret ); + } +#else + (void) ret; +#endif + + signature_is_good = ret == 0; + if( top && ! signature_is_good ) + continue; + + /* optional time check */ + if( mbedtls_x509_time_is_past( &parent->valid_to ) || + mbedtls_x509_time_is_future( &parent->valid_from ) ) + { + if( fallback_parent == NULL ) + { + fallback_parent = parent; + fallback_signature_is_good = signature_is_good; + } + + continue; + } + + break; + } + + if( parent != NULL ) + { + *r_parent = parent; + *r_signature_is_good = signature_is_good; + } + else + { + *r_parent = fallback_parent; + *r_signature_is_good = fallback_signature_is_good; + } + + return( 0 ); +} + +/* + * Find a parent in trusted CAs or the provided chain, or return NULL. + * + * Searches in trusted CAs first, and return the first suitable parent found + * (see find_parent_in() for definition of suitable). + * + * Arguments: + * - [in] child: certificate for which we're looking for a parent, followed + * by a chain of possible intermediates + * - [in] trust_ca: list of locally trusted certificates + * - [out] parent: parent found (or NULL) + * - [out] parent_is_trusted: 1 if returned `parent` is trusted, or 0 + * - [out] signature_is_good: 1 if child signature by parent is valid, or 0 + * - [in] path_cnt: number of links in the chain so far (EE -> ... -> child) + * - [in] self_cnt: number of self-signed certs in the chain so far + * (will always be no greater than path_cnt) + * - [in-out] rs_ctx: context for restarting operations + * + * Return value: + * - 0 on success + * - MBEDTLS_ERR_ECP_IN_PROGRESS otherwise + */ +static int x509_crt_find_parent( + mbedtls_x509_crt *child, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crt **parent, + int *parent_is_trusted, + int *signature_is_good, + unsigned path_cnt, + unsigned self_cnt, + mbedtls_x509_crt_restart_ctx *rs_ctx ) +{ + int ret; + mbedtls_x509_crt *search_list; + + *parent_is_trusted = 1; + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + /* restore then clear saved state if we have some stored */ + if( rs_ctx != NULL && rs_ctx->parent_is_trusted != -1 ) + { + *parent_is_trusted = rs_ctx->parent_is_trusted; + rs_ctx->parent_is_trusted = -1; + } +#endif + + while( 1 ) { + search_list = *parent_is_trusted ? trust_ca : child->next; + + ret = x509_crt_find_parent_in( child, search_list, + parent, signature_is_good, + *parent_is_trusted, + path_cnt, self_cnt, rs_ctx ); + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + { + /* save state */ + rs_ctx->parent_is_trusted = *parent_is_trusted; + return( ret ); + } +#else + (void) ret; +#endif + + /* stop here if found or already in second iteration */ + if( *parent != NULL || *parent_is_trusted == 0 ) + break; + + /* prepare second iteration */ + *parent_is_trusted = 0; + } + + /* extra precaution against mistakes in the caller */ + if( *parent == NULL ) + { + *parent_is_trusted = 0; + *signature_is_good = 0; + } + + return( 0 ); +} + +/* + * Check if an end-entity certificate is locally trusted + * + * Currently we require such certificates to be self-signed (actually only + * check for self-issued as self-signatures are not checked) + */ +static int x509_crt_check_ee_locally_trusted( + mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca ) +{ + mbedtls_x509_crt *cur; + + /* must be self-issued */ + if( x509_name_cmp( &crt->issuer, &crt->subject ) != 0 ) + return( -1 ); + + /* look for an exact match with trusted cert */ + for( cur = trust_ca; cur != NULL; cur = cur->next ) + { + if( crt->raw.len == cur->raw.len && + memcmp( crt->raw.p, cur->raw.p, crt->raw.len ) == 0 ) + { + return( 0 ); + } + } + + /* too bad */ + return( -1 ); +} + +/* + * Build and verify a certificate chain + * + * Given a peer-provided list of certificates EE, C1, ..., Cn and + * a list of trusted certs R1, ... Rp, try to build and verify a chain + * EE, Ci1, ... Ciq [, Rj] + * such that every cert in the chain is a child of the next one, + * jumping to a trusted root as early as possible. + * + * Verify that chain and return it with flags for all issues found. + * + * Special cases: + * - EE == Rj -> return a one-element list containing it + * - EE, Ci1, ..., Ciq cannot be continued with a trusted root + * -> return that chain with NOT_TRUSTED set on Ciq + * + * Tests for (aspects of) this function should include at least: + * - trusted EE + * - EE -> trusted root + * - EE -> intermediate CA -> trusted root + * - if relevant: EE untrusted + * - if relevant: EE -> intermediate, untrusted + * with the aspect under test checked at each relevant level (EE, int, root). + * For some aspects longer chains are required, but usually length 2 is + * enough (but length 1 is not in general). + * + * Arguments: + * - [in] crt: the cert list EE, C1, ..., Cn + * - [in] trust_ca: the trusted list R1, ..., Rp + * - [in] ca_crl, profile: as in verify_with_profile() + * - [out] ver_chain: the built and verified chain + * Only valid when return value is 0, may contain garbage otherwise! + * Restart note: need not be the same when calling again to resume. + * - [in-out] rs_ctx: context for restarting operations + * + * Return value: + * - non-zero if the chain could not be fully built and examined + * - 0 is the chain was successfully built and examined, + * even if it was found to be invalid + */ +static int x509_crt_verify_chain( + mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + mbedtls_x509_crt_ca_cb_t f_ca_cb, + void *p_ca_cb, + const mbedtls_x509_crt_profile *profile, + mbedtls_x509_crt_verify_chain *ver_chain, + mbedtls_x509_crt_restart_ctx *rs_ctx ) +{ + /* Don't initialize any of those variables here, so that the compiler can + * catch potential issues with jumping ahead when restarting */ + int ret; + uint32_t *flags; + mbedtls_x509_crt_verify_chain_item *cur; + mbedtls_x509_crt *child; + mbedtls_x509_crt *parent; + int parent_is_trusted; + int child_is_trusted; + int signature_is_good; + unsigned self_cnt; + mbedtls_x509_crt *cur_trust_ca = NULL; + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + /* resume if we had an operation in progress */ + if( rs_ctx != NULL && rs_ctx->in_progress == x509_crt_rs_find_parent ) + { + /* restore saved state */ + *ver_chain = rs_ctx->ver_chain; /* struct copy */ + self_cnt = rs_ctx->self_cnt; + + /* restore derived state */ + cur = &ver_chain->items[ver_chain->len - 1]; + child = cur->crt; + flags = &cur->flags; + + goto find_parent; + } +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + + child = crt; + self_cnt = 0; + parent_is_trusted = 0; + child_is_trusted = 0; + + while( 1 ) { + /* Add certificate to the verification chain */ + cur = &ver_chain->items[ver_chain->len]; + cur->crt = child; + cur->flags = 0; + ver_chain->len++; + flags = &cur->flags; + + /* Check time-validity (all certificates) */ + if( mbedtls_x509_time_is_past( &child->valid_to ) ) + *flags |= MBEDTLS_X509_BADCERT_EXPIRED; + + if( mbedtls_x509_time_is_future( &child->valid_from ) ) + *flags |= MBEDTLS_X509_BADCERT_FUTURE; + + /* Stop here for trusted roots (but not for trusted EE certs) */ + if( child_is_trusted ) + return( 0 ); + + /* Check signature algorithm: MD & PK algs */ + if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_MD; + + if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_PK; + + /* Special case: EE certs that are locally trusted */ + if( ver_chain->len == 1 && + x509_crt_check_ee_locally_trusted( child, trust_ca ) == 0 ) + { + return( 0 ); + } + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +find_parent: +#endif + + /* Obtain list of potential trusted signers from CA callback, + * or use statically provided list. */ +#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) + if( f_ca_cb != NULL ) + { + mbedtls_x509_crt_free( ver_chain->trust_ca_cb_result ); + mbedtls_free( ver_chain->trust_ca_cb_result ); + ver_chain->trust_ca_cb_result = NULL; + + ret = f_ca_cb( p_ca_cb, child, &ver_chain->trust_ca_cb_result ); + if( ret != 0 ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + + cur_trust_ca = ver_chain->trust_ca_cb_result; + } + else +#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ + { + ((void) f_ca_cb); + ((void) p_ca_cb); + cur_trust_ca = trust_ca; + } + + /* Look for a parent in trusted CAs or up the chain */ + ret = x509_crt_find_parent( child, cur_trust_ca, &parent, + &parent_is_trusted, &signature_is_good, + ver_chain->len - 1, self_cnt, rs_ctx ); + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS ) + { + /* save state */ + rs_ctx->in_progress = x509_crt_rs_find_parent; + rs_ctx->self_cnt = self_cnt; + rs_ctx->ver_chain = *ver_chain; /* struct copy */ + + return( ret ); + } +#else + (void) ret; +#endif + + /* No parent? We're done here */ + if( parent == NULL ) + { + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + return( 0 ); + } + + /* Count intermediate self-issued (not necessarily self-signed) certs. + * These can occur with some strategies for key rollover, see [SIRO], + * and should be excluded from max_pathlen checks. */ + if( ver_chain->len != 1 && + x509_name_cmp( &child->issuer, &child->subject ) == 0 ) + { + self_cnt++; + } + + /* path_cnt is 0 for the first intermediate CA, + * and if parent is trusted it's not an intermediate CA */ + if( ! parent_is_trusted && + ver_chain->len > MBEDTLS_X509_MAX_INTERMEDIATE_CA ) + { + /* return immediately to avoid overflow the chain array */ + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + } + + /* signature was checked while searching parent */ + if( ! signature_is_good ) + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + + /* check size of signing key */ + if( x509_profile_check_key( profile, &parent->pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + +#if defined(MBEDTLS_X509_CRL_PARSE_C) + /* Check trusted CA's CRL for the given crt */ + *flags |= x509_crt_verifycrl( child, parent, ca_crl, profile ); +#else + (void) ca_crl; +#endif + + /* prepare for next iteration */ + child = parent; + parent = NULL; + child_is_trusted = parent_is_trusted; + signature_is_good = 0; + } +} + +/* + * Check for CN match + */ +static int x509_crt_check_cn( const mbedtls_x509_buf *name, + const char *cn, size_t cn_len ) +{ + /* try exact match */ + if( name->len == cn_len && + x509_memcasecmp( cn, name->p, cn_len ) == 0 ) + { + return( 0 ); + } + + /* try wildcard match */ + if( x509_check_wildcard( cn, name ) == 0 ) + { + return( 0 ); + } + + return( -1 ); +} + +/* + * Verify the requested CN - only call this if cn is not NULL! + */ +static void x509_crt_verify_name( const mbedtls_x509_crt *crt, + const char *cn, + uint32_t *flags ) +{ + const mbedtls_x509_name *name; + const mbedtls_x509_sequence *cur; + size_t cn_len = strlen( cn ); + + if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) + { + for( cur = &crt->subject_alt_names; cur != NULL; cur = cur->next ) + { + if( x509_crt_check_cn( &cur->buf, cn, cn_len ) == 0 ) + break; + } + + if( cur == NULL ) + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + } + else + { + for( name = &crt->subject; name != NULL; name = name->next ) + { + if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 && + x509_crt_check_cn( &name->val, cn, cn_len ) == 0 ) + { + break; + } + } + + if( name == NULL ) + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + } +} + +/* + * Merge the flags for all certs in the chain, after calling callback + */ +static int x509_crt_merge_flags_with_cb( + uint32_t *flags, + const mbedtls_x509_crt_verify_chain *ver_chain, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + int ret; + unsigned i; + uint32_t cur_flags; + const mbedtls_x509_crt_verify_chain_item *cur; + + for( i = ver_chain->len; i != 0; --i ) + { + cur = &ver_chain->items[i-1]; + cur_flags = cur->flags; + + if( NULL != f_vrfy ) + if( ( ret = f_vrfy( p_vrfy, cur->crt, (int) i-1, &cur_flags ) ) != 0 ) + return( ret ); + + *flags |= cur_flags; + } + + return( 0 ); +} + +/* + * Verify the certificate validity, with profile, restartable version + * + * This function: + * - checks the requested CN (if any) + * - checks the type and size of the EE cert's key, + * as that isn't done as part of chain building/verification currently + * - builds and verifies the chain + * - then calls the callback and merges the flags + * + * The parameters pairs `trust_ca`, `ca_crl` and `f_ca_cb`, `p_ca_cb` + * are mutually exclusive: If `f_ca_cb != NULL`, it will be used by the + * verification routine to search for trusted signers, and CRLs will + * be disabled. Otherwise, `trust_ca` will be used as the static list + * of trusted signers, and `ca_crl` will be use as the static list + * of CRLs. + */ +static int x509_crt_verify_restartable_ca_cb( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + mbedtls_x509_crt_ca_cb_t f_ca_cb, + void *p_ca_cb, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy, + mbedtls_x509_crt_restart_ctx *rs_ctx ) +{ + int ret; + mbedtls_pk_type_t pk_type; + mbedtls_x509_crt_verify_chain ver_chain; + uint32_t ee_flags; + + *flags = 0; + ee_flags = 0; + x509_crt_verify_chain_reset( &ver_chain ); + + if( profile == NULL ) + { + ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; + goto exit; + } + + /* check name if requested */ + if( cn != NULL ) + x509_crt_verify_name( crt, cn, &ee_flags ); + + /* Check the type and size of the key */ + pk_type = mbedtls_pk_get_type( &crt->pk ); + + if( x509_profile_check_pk_alg( profile, pk_type ) != 0 ) + ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK; + + if( x509_profile_check_key( profile, &crt->pk ) != 0 ) + ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + /* Check the chain */ + ret = x509_crt_verify_chain( crt, trust_ca, ca_crl, + f_ca_cb, p_ca_cb, profile, + &ver_chain, rs_ctx ); + + if( ret != 0 ) + goto exit; + + /* Merge end-entity flags */ + ver_chain.items[0].flags |= ee_flags; + + /* Build final flags, calling callback on the way if any */ + ret = x509_crt_merge_flags_with_cb( flags, &ver_chain, f_vrfy, p_vrfy ); + +exit: + +#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) + mbedtls_x509_crt_free( ver_chain.trust_ca_cb_result ); + mbedtls_free( ver_chain.trust_ca_cb_result ); + ver_chain.trust_ca_cb_result = NULL; +#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) + if( rs_ctx != NULL && ret != MBEDTLS_ERR_ECP_IN_PROGRESS ) + mbedtls_x509_crt_restart_free( rs_ctx ); +#endif + + /* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by + * the SSL module for authmode optional, but non-zero return from the + * callback means a fatal error so it shouldn't be ignored */ + if( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ) + ret = MBEDTLS_ERR_X509_FATAL_ERROR; + + if( ret != 0 ) + { + *flags = (uint32_t) -1; + return( ret ); + } + + if( *flags != 0 ) + return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ); + + return( 0 ); +} + + +/* + * Verify the certificate validity (default profile, not restartable) + */ +int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + return( x509_crt_verify_restartable_ca_cb( crt, trust_ca, ca_crl, + NULL, NULL, + &mbedtls_x509_crt_profile_default, + cn, flags, + f_vrfy, p_vrfy, NULL ) ); +} + +/* + * Verify the certificate validity (user-chosen profile, not restartable) + */ +int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + return( x509_crt_verify_restartable_ca_cb( crt, trust_ca, ca_crl, + NULL, NULL, + profile, cn, flags, + f_vrfy, p_vrfy, NULL ) ); +} + +#if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK) +/* + * Verify the certificate validity (user-chosen profile, CA callback, + * not restartable). + */ +int mbedtls_x509_crt_verify_with_ca_cb( mbedtls_x509_crt *crt, + mbedtls_x509_crt_ca_cb_t f_ca_cb, + void *p_ca_cb, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + return( x509_crt_verify_restartable_ca_cb( crt, NULL, NULL, + f_ca_cb, p_ca_cb, + profile, cn, flags, + f_vrfy, p_vrfy, NULL ) ); +} +#endif /* MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK */ + +int mbedtls_x509_crt_verify_restartable( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy, + mbedtls_x509_crt_restart_ctx *rs_ctx ) +{ + return( x509_crt_verify_restartable_ca_cb( crt, trust_ca, ca_crl, + NULL, NULL, + profile, cn, flags, + f_vrfy, p_vrfy, rs_ctx ) ); +} + + +/* + * Initialize a certificate chain + */ +void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ) +{ + memset( crt, 0, sizeof(mbedtls_x509_crt) ); +} + +/* + * Unallocate all certificate data + */ +void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) +{ + mbedtls_x509_crt *cert_cur = crt; + mbedtls_x509_crt *cert_prv; + mbedtls_x509_name *name_cur; + mbedtls_x509_name *name_prv; + mbedtls_x509_sequence *seq_cur; + mbedtls_x509_sequence *seq_prv; + + if( crt == NULL ) + return; + + do + { + mbedtls_pk_free( &cert_cur->pk ); + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_free( cert_cur->sig_opts ); +#endif + + name_cur = cert_cur->issuer.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + name_cur = cert_cur->subject.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + seq_cur = cert_cur->ext_key_usage.next; + while( seq_cur != NULL ) + { + seq_prv = seq_cur; + seq_cur = seq_cur->next; + mbedtls_platform_zeroize( seq_prv, + sizeof( mbedtls_x509_sequence ) ); + mbedtls_free( seq_prv ); + } + + seq_cur = cert_cur->subject_alt_names.next; + while( seq_cur != NULL ) + { + seq_prv = seq_cur; + seq_cur = seq_cur->next; + mbedtls_platform_zeroize( seq_prv, + sizeof( mbedtls_x509_sequence ) ); + mbedtls_free( seq_prv ); + } + + seq_cur = cert_cur->certificate_policies.next; + while( seq_cur != NULL ) + { + seq_prv = seq_cur; + seq_cur = seq_cur->next; + mbedtls_platform_zeroize( seq_prv, + sizeof( mbedtls_x509_sequence ) ); + mbedtls_free( seq_prv ); + } + + if( cert_cur->raw.p != NULL && cert_cur->own_buffer ) + { + mbedtls_platform_zeroize( cert_cur->raw.p, cert_cur->raw.len ); + mbedtls_free( cert_cur->raw.p ); + } + + cert_cur = cert_cur->next; + } + while( cert_cur != NULL ); + + cert_cur = crt; + do + { + cert_prv = cert_cur; + cert_cur = cert_cur->next; + + mbedtls_platform_zeroize( cert_prv, sizeof( mbedtls_x509_crt ) ); + if( cert_prv != crt ) + mbedtls_free( cert_prv ); + } + while( cert_cur != NULL ); +} + +#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) +/* + * Initialize a restart context + */ +void mbedtls_x509_crt_restart_init( mbedtls_x509_crt_restart_ctx *ctx ) +{ + mbedtls_pk_restart_init( &ctx->pk ); + + ctx->parent = NULL; + ctx->fallback_parent = NULL; + ctx->fallback_signature_is_good = 0; + + ctx->parent_is_trusted = -1; + + ctx->in_progress = x509_crt_rs_none; + ctx->self_cnt = 0; + x509_crt_verify_chain_reset( &ctx->ver_chain ); +} + +/* + * Free the components of a restart context + */ +void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_pk_restart_free( &ctx->pk ); + mbedtls_x509_crt_restart_init( ctx ); +} +#endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */ + +#endif /* MBEDTLS_X509_CRT_PARSE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/x509_csr.c b/FreeRTOS-Labs/Source/mbedtls/library/x509_csr.c new file mode 100644 index 000000000..dc4cb230d --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/x509_csr.c @@ -0,0 +1,419 @@ +/* + * X.509 Certificate Signing Request (CSR) parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CSR_PARSE_C) + +#include "mbedtls/x509_csr.h" +#include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_snprintf snprintf +#endif + +#if defined(MBEDTLS_FS_IO) || defined(EFIX64) || defined(EFI32) +#include +#endif + +/* + * Version ::= INTEGER { v1(0) } + */ +static int x509_csr_get_version( unsigned char **p, + const unsigned char *end, + int *ver ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + *ver = 0; + return( 0 ); + } + + return( MBEDTLS_ERR_X509_INVALID_VERSION + ret ); + } + + return( 0 ); +} + +/* + * Parse a CSR in DER format + */ +int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr, + const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t len; + unsigned char *p, *end; + mbedtls_x509_buf sig_params; + + memset( &sig_params, 0, sizeof( mbedtls_x509_buf ) ); + + /* + * Check for valid input + */ + if( csr == NULL || buf == NULL || buflen == 0 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + mbedtls_x509_csr_init( csr ); + + /* + * first copy the raw DER data + */ + p = mbedtls_calloc( 1, len = buflen ); + + if( p == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + memcpy( p, buf, buflen ); + + csr->raw.p = p; + csr->raw.len = len; + end = p + len; + + /* + * CertificationRequest ::= SEQUENCE { + * certificationRequestInfo CertificationRequestInfo, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + } + + if( len != (size_t) ( end - p ) ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + /* + * CertificationRequestInfo ::= SEQUENCE { + */ + csr->cri.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + end = p + len; + csr->cri.len = end - csr->cri.p; + + /* + * Version ::= INTEGER { v1(0) } + */ + if( ( ret = x509_csr_get_version( &p, end, &csr->version ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + if( csr->version != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); + } + + csr->version++; + + /* + * subject Name + */ + csr->subject_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_x509_get_name( &p, p + len, &csr->subject ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + csr->subject_raw.len = p - csr->subject_raw.p; + + /* + * subjectPKInfo SubjectPublicKeyInfo + */ + if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &csr->pk ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + /* + * attributes [0] Attributes + * + * The list of possible attributes is open-ended, though RFC 2985 + * (PKCS#9) defines a few in section 5.4. We currently don't support any, + * so we just ignore them. This is a safe thing to do as the worst thing + * that could happen is that we issue a certificate that does not match + * the requester's expectations - this cannot cause a violation of our + * signature policies. + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + p += len; + + end = csr->raw.p + csr->raw.len; + + /* + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + */ + if( ( ret = mbedtls_x509_get_alg( &p, end, &csr->sig_oid, &sig_params ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + if( ( ret = mbedtls_x509_get_sig_alg( &csr->sig_oid, &sig_params, + &csr->sig_md, &csr->sig_pk, + &csr->sig_opts ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG ); + } + + if( ( ret = mbedtls_x509_get_sig( &p, end, &csr->sig ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + if( p != end ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + return( 0 ); +} + +/* + * Parse a CSR, allowing for PEM or raw DER encoding + */ +int mbedtls_x509_csr_parse( mbedtls_x509_csr *csr, const unsigned char *buf, size_t buflen ) +{ +#if defined(MBEDTLS_PEM_PARSE_C) + int ret; + size_t use_len; + mbedtls_pem_context pem; +#endif + + /* + * Check for valid input + */ + if( csr == NULL || buf == NULL || buflen == 0 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_PEM_PARSE_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( buf[buflen - 1] == '\0' ) + { + mbedtls_pem_init( &pem ); + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN CERTIFICATE REQUEST-----", + "-----END CERTIFICATE REQUEST-----", + buf, NULL, 0, &use_len ); + if( ret == MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN NEW CERTIFICATE REQUEST-----", + "-----END NEW CERTIFICATE REQUEST-----", + buf, NULL, 0, &use_len ); + } + + if( ret == 0 ) + { + /* + * Was PEM encoded, parse the result + */ + ret = mbedtls_x509_csr_parse_der( csr, pem.buf, pem.buflen ); + } + + mbedtls_pem_free( &pem ); + if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); + } +#endif /* MBEDTLS_PEM_PARSE_C */ + return( mbedtls_x509_csr_parse_der( csr, buf, buflen ) ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Load a CSR into the structure + */ +int mbedtls_x509_csr_parse_file( mbedtls_x509_csr *csr, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_x509_csr_parse( csr, buf, n ); + + mbedtls_platform_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +#define BEFORE_COLON 14 +#define BC "14" +/* + * Return an informational string about the CSR. + */ +int mbedtls_x509_csr_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_csr *csr ) +{ + int ret; + size_t n; + char *p; + char key_size_str[BEFORE_COLON]; + + p = buf; + n = size; + + ret = mbedtls_snprintf( p, n, "%sCSR version : %d", + prefix, csr->version ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &csr->subject ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_sig_alg_gets( p, n, &csr->sig_oid, csr->sig_pk, csr->sig_md, + csr->sig_opts ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, + mbedtls_pk_get_name( &csr->pk ) ) ) != 0 ) + { + return( ret ); + } + + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits\n", prefix, key_size_str, + (int) mbedtls_pk_get_bitlen( &csr->pk ) ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( (int) ( size - n ) ); +} + +/* + * Initialize a CSR + */ +void mbedtls_x509_csr_init( mbedtls_x509_csr *csr ) +{ + memset( csr, 0, sizeof(mbedtls_x509_csr) ); +} + +/* + * Unallocate all CSR data + */ +void mbedtls_x509_csr_free( mbedtls_x509_csr *csr ) +{ + mbedtls_x509_name *name_cur; + mbedtls_x509_name *name_prv; + + if( csr == NULL ) + return; + + mbedtls_pk_free( &csr->pk ); + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_free( csr->sig_opts ); +#endif + + name_cur = csr->subject.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + if( csr->raw.p != NULL ) + { + mbedtls_platform_zeroize( csr->raw.p, csr->raw.len ); + mbedtls_free( csr->raw.p ); + } + + mbedtls_platform_zeroize( csr, sizeof( mbedtls_x509_csr ) ); +} + +#endif /* MBEDTLS_X509_CSR_PARSE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/x509write_crt.c b/FreeRTOS-Labs/Source/mbedtls/library/x509write_crt.c new file mode 100644 index 000000000..3d5b657f3 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/x509write_crt.c @@ -0,0 +1,495 @@ +/* + * X.509 certificate writing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * References: + * - certificates: RFC 5280, updated by RFC 6818 + * - CSRs: PKCS#10 v1.7 aka RFC 2986 + * - attributes: PKCS#9 v2.0 aka RFC 2985 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CRT_WRITE_C) + +#include "mbedtls/x509_crt.h" +#include "mbedtls/oid.h" +#include "mbedtls/asn1write.h" +#include "mbedtls/sha1.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif /* MBEDTLS_PEM_WRITE_C */ + +void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_x509write_cert ) ); + + mbedtls_mpi_init( &ctx->serial ); + ctx->version = MBEDTLS_X509_CRT_VERSION_3; +} + +void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx ) +{ + mbedtls_mpi_free( &ctx->serial ); + + mbedtls_asn1_free_named_data_list( &ctx->subject ); + mbedtls_asn1_free_named_data_list( &ctx->issuer ); + mbedtls_asn1_free_named_data_list( &ctx->extensions ); + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_x509write_cert ) ); +} + +void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version ) +{ + ctx->version = version; +} + +void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert *ctx, mbedtls_md_type_t md_alg ) +{ + ctx->md_alg = md_alg; +} + +void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key ) +{ + ctx->subject_key = key; +} + +void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key ) +{ + ctx->issuer_key = key; +} + +int mbedtls_x509write_crt_set_subject_name( mbedtls_x509write_cert *ctx, + const char *subject_name ) +{ + return mbedtls_x509_string_to_names( &ctx->subject, subject_name ); +} + +int mbedtls_x509write_crt_set_issuer_name( mbedtls_x509write_cert *ctx, + const char *issuer_name ) +{ + return mbedtls_x509_string_to_names( &ctx->issuer, issuer_name ); +} + +int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx, const mbedtls_mpi *serial ) +{ + int ret; + + if( ( ret = mbedtls_mpi_copy( &ctx->serial, serial ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert *ctx, const char *not_before, + const char *not_after ) +{ + if( strlen( not_before ) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 || + strlen( not_after ) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 ) + { + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + } + strncpy( ctx->not_before, not_before, MBEDTLS_X509_RFC5280_UTC_TIME_LEN ); + strncpy( ctx->not_after , not_after , MBEDTLS_X509_RFC5280_UTC_TIME_LEN ); + ctx->not_before[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z'; + ctx->not_after[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z'; + + return( 0 ); +} + +int mbedtls_x509write_crt_set_extension( mbedtls_x509write_cert *ctx, + const char *oid, size_t oid_len, + int critical, + const unsigned char *val, size_t val_len ) +{ + return mbedtls_x509_set_extension( &ctx->extensions, oid, oid_len, + critical, val, val_len ); +} + +int mbedtls_x509write_crt_set_basic_constraints( mbedtls_x509write_cert *ctx, + int is_ca, int max_pathlen ) +{ + int ret; + unsigned char buf[9]; + unsigned char *c = buf + sizeof(buf); + size_t len = 0; + + memset( buf, 0, sizeof(buf) ); + + if( is_ca && max_pathlen > 127 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + if( is_ca ) + { + if( max_pathlen >= 0 ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, max_pathlen ) ); + } + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( &c, buf, 1 ) ); + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS, + MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ), + 0, buf + sizeof(buf) - len, len ); +} + +#if defined(MBEDTLS_SHA1_C) +int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ctx ) +{ + int ret; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */ + unsigned char *c = buf + sizeof(buf); + size_t len = 0; + + memset( buf, 0, sizeof(buf) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->subject_key ) ); + + ret = mbedtls_sha1_ret( buf + sizeof( buf ) - len, len, + buf + sizeof( buf ) - 20 ); + if( ret != 0 ) + return( ret ); + c = buf + sizeof( buf ) - 20; + len = 20; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_OCTET_STRING ) ); + + return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER, + MBEDTLS_OID_SIZE( MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER ), + 0, buf + sizeof(buf) - len, len ); +} + +int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *ctx ) +{ + int ret; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */ + unsigned char *c = buf + sizeof( buf ); + size_t len = 0; + + memset( buf, 0, sizeof(buf) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->issuer_key ) ); + + ret = mbedtls_sha1_ret( buf + sizeof( buf ) - len, len, + buf + sizeof( buf ) - 20 ); + if( ret != 0 ) + return( ret ); + c = buf + sizeof( buf ) - 20; + len = 20; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | 0 ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER, + MBEDTLS_OID_SIZE( MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER ), + 0, buf + sizeof( buf ) - len, len ); +} +#endif /* MBEDTLS_SHA1_C */ + +int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx, + unsigned int key_usage ) +{ + unsigned char buf[5], ku[2]; + unsigned char *c; + int ret; + const unsigned int allowed_bits = MBEDTLS_X509_KU_DIGITAL_SIGNATURE | + MBEDTLS_X509_KU_NON_REPUDIATION | + MBEDTLS_X509_KU_KEY_ENCIPHERMENT | + MBEDTLS_X509_KU_DATA_ENCIPHERMENT | + MBEDTLS_X509_KU_KEY_AGREEMENT | + MBEDTLS_X509_KU_KEY_CERT_SIGN | + MBEDTLS_X509_KU_CRL_SIGN | + MBEDTLS_X509_KU_ENCIPHER_ONLY | + MBEDTLS_X509_KU_DECIPHER_ONLY; + + /* Check that nothing other than the allowed flags is set */ + if( ( key_usage & ~allowed_bits ) != 0 ) + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); + + c = buf + 5; + ku[0] = (unsigned char)( key_usage ); + ku[1] = (unsigned char)( key_usage >> 8 ); + ret = mbedtls_asn1_write_named_bitstring( &c, buf, ku, 9 ); + + if( ret < 0 ) + return( ret ); + else if( ret < 3 || ret > 5 ) + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + + ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_KEY_USAGE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ), + 1, c, (size_t)ret ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx, + unsigned char ns_cert_type ) +{ + unsigned char buf[4]; + unsigned char *c; + int ret; + + c = buf + 4; + + ret = mbedtls_asn1_write_named_bitstring( &c, buf, &ns_cert_type, 8 ); + if( ret < 3 || ret > 4 ) + return( ret ); + + ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ), + 0, c, (size_t)ret ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +static int x509_write_time( unsigned char **p, unsigned char *start, + const char *t, size_t size ) +{ + int ret; + size_t len = 0; + + /* + * write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter) + */ + if( t[0] == '2' && t[1] == '0' && t[2] < '5' ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) t + 2, + size - 2 ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_UTC_TIME ) ); + } + else + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) t, + size ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_GENERALIZED_TIME ) ); + } + + return( (int) len ); +} + +int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + const char *sig_oid; + size_t sig_oid_len = 0; + unsigned char *c, *c2; + unsigned char hash[64]; + unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; + unsigned char tmp_buf[2048]; + size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len; + size_t len = 0; + mbedtls_pk_type_t pk_alg; + + /* + * Prepare data to be signed in tmp_buf + */ + c = tmp_buf + sizeof( tmp_buf ); + + /* Signature algorithm needed in TBS, and later for actual signature */ + + /* There's no direct way of extracting a signature algorithm + * (represented as an element of mbedtls_pk_type_t) from a PK instance. */ + if( mbedtls_pk_can_do( ctx->issuer_key, MBEDTLS_PK_RSA ) ) + pk_alg = MBEDTLS_PK_RSA; + else if( mbedtls_pk_can_do( ctx->issuer_key, MBEDTLS_PK_ECDSA ) ) + pk_alg = MBEDTLS_PK_ECDSA; + else + return( MBEDTLS_ERR_X509_INVALID_ALG ); + + if( ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg, + &sig_oid, &sig_oid_len ) ) != 0 ) + { + return( ret ); + } + + /* + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + */ + + /* Only for v3 */ + if( ctx->version == MBEDTLS_X509_CRT_VERSION_3 ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_extensions( &c, tmp_buf, ctx->extensions ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | + MBEDTLS_ASN1_CONSTRUCTED | 3 ) ); + } + + /* + * SubjectPublicKeyInfo + */ + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_pk_write_pubkey_der( ctx->subject_key, + tmp_buf, c - tmp_buf ) ); + c -= pub_len; + len += pub_len; + + /* + * Subject ::= Name + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->subject ) ); + + /* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + */ + sub_len = 0; + + MBEDTLS_ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_after, + MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) ); + + MBEDTLS_ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_before, + MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) ); + + len += sub_len; + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + /* + * Issuer ::= Name + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->issuer ) ); + + /* + * Signature ::= AlgorithmIdentifier + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, tmp_buf, + sig_oid, strlen( sig_oid ), 0 ) ); + + /* + * Serial ::= INTEGER + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, tmp_buf, &ctx->serial ) ); + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ + + /* Can be omitted for v1 */ + if( ctx->version != MBEDTLS_X509_CRT_VERSION_1 ) + { + sub_len = 0; + MBEDTLS_ASN1_CHK_ADD( sub_len, mbedtls_asn1_write_int( &c, tmp_buf, ctx->version ) ); + len += sub_len; + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | + MBEDTLS_ASN1_CONSTRUCTED | 0 ) ); + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + /* + * Make signature + */ + if( ( ret = mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, + len, hash ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = mbedtls_pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len, + f_rng, p_rng ) ) != 0 ) + { + return( ret ); + } + + /* + * Write data to output buffer + */ + c2 = buf + size; + MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf, + sig_oid, sig_oid_len, sig, sig_len ) ); + + if( len > (size_t)( c2 - buf ) ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + c2 -= len; + memcpy( c2, c, len ); + + len += sig_and_oid_len; + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c2, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c2, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +#define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n" +#define PEM_END_CRT "-----END CERTIFICATE-----\n" + +#if defined(MBEDTLS_PEM_WRITE_C) +int mbedtls_x509write_crt_pem( mbedtls_x509write_cert *crt, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char output_buf[4096]; + size_t olen = 0; + + if( ( ret = mbedtls_x509write_crt_der( crt, output_buf, sizeof(output_buf), + f_rng, p_rng ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_CRT, PEM_END_CRT, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_PEM_WRITE_C */ + +#endif /* MBEDTLS_X509_CRT_WRITE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/x509write_csr.c b/FreeRTOS-Labs/Source/mbedtls/library/x509write_csr.c new file mode 100644 index 000000000..9ca2d0e55 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/x509write_csr.c @@ -0,0 +1,287 @@ +/* + * X.509 Certificate Signing Request writing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * References: + * - CSRs: PKCS#10 v1.7 aka RFC 2986 + * - attributes: PKCS#9 v2.0 aka RFC 2985 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CSR_WRITE_C) + +#include "mbedtls/x509_csr.h" +#include "mbedtls/oid.h" +#include "mbedtls/asn1write.h" +#include "mbedtls/platform_util.h" + +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "psa/crypto.h" +#include "mbedtls/psa_util.h" +#endif + +#include +#include + +#if defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif + +void mbedtls_x509write_csr_init( mbedtls_x509write_csr *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_x509write_csr ) ); +} + +void mbedtls_x509write_csr_free( mbedtls_x509write_csr *ctx ) +{ + mbedtls_asn1_free_named_data_list( &ctx->subject ); + mbedtls_asn1_free_named_data_list( &ctx->extensions ); + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_x509write_csr ) ); +} + +void mbedtls_x509write_csr_set_md_alg( mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg ) +{ + ctx->md_alg = md_alg; +} + +void mbedtls_x509write_csr_set_key( mbedtls_x509write_csr *ctx, mbedtls_pk_context *key ) +{ + ctx->key = key; +} + +int mbedtls_x509write_csr_set_subject_name( mbedtls_x509write_csr *ctx, + const char *subject_name ) +{ + return mbedtls_x509_string_to_names( &ctx->subject, subject_name ); +} + +int mbedtls_x509write_csr_set_extension( mbedtls_x509write_csr *ctx, + const char *oid, size_t oid_len, + const unsigned char *val, size_t val_len ) +{ + return mbedtls_x509_set_extension( &ctx->extensions, oid, oid_len, + 0, val, val_len ); +} + +int mbedtls_x509write_csr_set_key_usage( mbedtls_x509write_csr *ctx, unsigned char key_usage ) +{ + unsigned char buf[4]; + unsigned char *c; + int ret; + + c = buf + 4; + + ret = mbedtls_asn1_write_named_bitstring( &c, buf, &key_usage, 8 ); + if( ret < 3 || ret > 4 ) + return( ret ); + + ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_KEY_USAGE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ), + c, (size_t)ret ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_x509write_csr_set_ns_cert_type( mbedtls_x509write_csr *ctx, + unsigned char ns_cert_type ) +{ + unsigned char buf[4]; + unsigned char *c; + int ret; + + c = buf + 4; + + ret = mbedtls_asn1_write_named_bitstring( &c, buf, &ns_cert_type, 8 ); + if( ret < 3 || ret > 4 ) + return( ret ); + + ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ), + c, (size_t)ret ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + const char *sig_oid; + size_t sig_oid_len = 0; + unsigned char *c, *c2; + unsigned char hash[64]; + unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; + unsigned char tmp_buf[2048]; + size_t pub_len = 0, sig_and_oid_len = 0, sig_len; + size_t len = 0; + mbedtls_pk_type_t pk_alg; +#if defined(MBEDTLS_USE_PSA_CRYPTO) + psa_hash_operation_t hash_operation = PSA_HASH_OPERATION_INIT; + size_t hash_len; + psa_algorithm_t hash_alg = mbedtls_psa_translate_md( ctx->md_alg ); +#endif /* MBEDTLS_USE_PSA_CRYPTO */ + /* + * Prepare data to be signed in tmp_buf + */ + c = tmp_buf + sizeof( tmp_buf ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_extensions( &c, tmp_buf, ctx->extensions ) ); + + if( len ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SET ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( &c, tmp_buf, MBEDTLS_OID_PKCS9_CSR_EXT_REQ, + MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS9_CSR_EXT_REQ ) ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ); + + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_pk_write_pubkey_der( ctx->key, + tmp_buf, c - tmp_buf ) ); + c -= pub_len; + len += pub_len; + + /* + * Subject ::= Name + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->subject ) ); + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, tmp_buf, 0 ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + /* + * Prepare signature + * Note: hash errors can happen only after an internal error + */ +#if defined(MBEDTLS_USE_PSA_CRYPTO) + if( psa_hash_setup( &hash_operation, hash_alg ) != PSA_SUCCESS ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + + if( psa_hash_update( &hash_operation, c, len ) != PSA_SUCCESS ) + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + + if( psa_hash_finish( &hash_operation, hash, sizeof( hash ), &hash_len ) + != PSA_SUCCESS ) + { + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + } +#else /* MBEDTLS_USE_PSA_CRYPTO */ + mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, len, hash ); +#endif + if( ( ret = mbedtls_pk_sign( ctx->key, ctx->md_alg, hash, 0, sig, &sig_len, + f_rng, p_rng ) ) != 0 ) + { + return( ret ); + } + + if( mbedtls_pk_can_do( ctx->key, MBEDTLS_PK_RSA ) ) + pk_alg = MBEDTLS_PK_RSA; + else if( mbedtls_pk_can_do( ctx->key, MBEDTLS_PK_ECDSA ) ) + pk_alg = MBEDTLS_PK_ECDSA; + else + return( MBEDTLS_ERR_X509_INVALID_ALG ); + + if( ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg, + &sig_oid, &sig_oid_len ) ) != 0 ) + { + return( ret ); + } + + /* + * Write data to output buffer + */ + c2 = buf + size; + MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf, + sig_oid, sig_oid_len, sig, sig_len ) ); + + if( len > (size_t)( c2 - buf ) ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + c2 -= len; + memcpy( c2, c, len ); + + len += sig_and_oid_len; + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c2, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c2, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +#define PEM_BEGIN_CSR "-----BEGIN CERTIFICATE REQUEST-----\n" +#define PEM_END_CSR "-----END CERTIFICATE REQUEST-----\n" + +#if defined(MBEDTLS_PEM_WRITE_C) +int mbedtls_x509write_csr_pem( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char output_buf[4096]; + size_t olen = 0; + + if( ( ret = mbedtls_x509write_csr_der( ctx, output_buf, sizeof(output_buf), + f_rng, p_rng ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_CSR, PEM_END_CSR, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_PEM_WRITE_C */ + +#endif /* MBEDTLS_X509_CSR_WRITE_C */ diff --git a/FreeRTOS-Labs/Source/mbedtls/library/xtea.c b/FreeRTOS-Labs/Source/mbedtls/library/xtea.c new file mode 100644 index 000000000..3eb7035e2 --- /dev/null +++ b/FreeRTOS-Labs/Source/mbedtls/library/xtea.c @@ -0,0 +1,277 @@ +/* + * An 32-bit implementation of the XTEA algorithm + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_XTEA_C) + +#include "mbedtls/xtea.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_XTEA_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +void mbedtls_xtea_init( mbedtls_xtea_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_xtea_context ) ); +} + +void mbedtls_xtea_free( mbedtls_xtea_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_xtea_context ) ); +} + +/* + * XTEA key schedule + */ +void mbedtls_xtea_setup( mbedtls_xtea_context *ctx, const unsigned char key[16] ) +{ + int i; + + memset( ctx, 0, sizeof(mbedtls_xtea_context) ); + + for( i = 0; i < 4; i++ ) + { + GET_UINT32_BE( ctx->k[i], key, i << 2 ); + } +} + +/* + * XTEA encrypt function + */ +int mbedtls_xtea_crypt_ecb( mbedtls_xtea_context *ctx, int mode, + const unsigned char input[8], unsigned char output[8]) +{ + uint32_t *k, v0, v1, i; + + k = ctx->k; + + GET_UINT32_BE( v0, input, 0 ); + GET_UINT32_BE( v1, input, 4 ); + + if( mode == MBEDTLS_XTEA_ENCRYPT ) + { + uint32_t sum = 0, delta = 0x9E3779B9; + + for( i = 0; i < 32; i++ ) + { + v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]); + sum += delta; + v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]); + } + } + else /* MBEDTLS_XTEA_DECRYPT */ + { + uint32_t delta = 0x9E3779B9, sum = delta * 32; + + for( i = 0; i < 32; i++ ) + { + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]); + sum -= delta; + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]); + } + } + + PUT_UINT32_BE( v0, output, 0 ); + PUT_UINT32_BE( v1, output, 4 ); + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * XTEA-CBC buffer encryption/decryption + */ +int mbedtls_xtea_crypt_cbc( mbedtls_xtea_context *ctx, int mode, size_t length, + unsigned char iv[8], const unsigned char *input, + unsigned char *output) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_XTEA_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + mbedtls_xtea_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_xtea_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* !MBEDTLS_XTEA_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * XTEA tests vectors (non-official) + */ + +static const unsigned char xtea_test_key[6][16] = +{ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char xtea_test_pt[6][8] = +{ + { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }, + { 0x5a, 0x5b, 0x6e, 0x27, 0x89, 0x48, 0xd7, 0x7f }, + { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }, + { 0x70, 0xe1, 0x22, 0x5d, 0x6e, 0x4e, 0x76, 0x55 } +}; + +static const unsigned char xtea_test_ct[6][8] = +{ + { 0x49, 0x7d, 0xf3, 0xd0, 0x72, 0x61, 0x2c, 0xb5 }, + { 0xe7, 0x8f, 0x2d, 0x13, 0x74, 0x43, 0x41, 0xd8 }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }, + { 0xa0, 0x39, 0x05, 0x89, 0xf8, 0xb8, 0xef, 0xa5 }, + { 0xed, 0x23, 0x37, 0x5a, 0x82, 0x1a, 0x8c, 0x2d }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 } +}; + +/* + * Checkup routine + */ +int mbedtls_xtea_self_test( int verbose ) +{ + int i, ret = 0; + unsigned char buf[8]; + mbedtls_xtea_context ctx; + + mbedtls_xtea_init( &ctx ); + for( i = 0; i < 6; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " XTEA test #%d: ", i + 1 ); + + memcpy( buf, xtea_test_pt[i], 8 ); + + mbedtls_xtea_setup( &ctx, xtea_test_key[i] ); + mbedtls_xtea_crypt_ecb( &ctx, MBEDTLS_XTEA_ENCRYPT, buf, buf ); + + if( memcmp( buf, xtea_test_ct[i], 8 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_xtea_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_XTEA_C */ diff --git a/FreeRTOS-Labs/readme.txt b/FreeRTOS-Labs/readme.txt new file mode 100644 index 000000000..f22ea729a --- /dev/null +++ b/FreeRTOS-Labs/readme.txt @@ -0,0 +1,53 @@ +*** IMPORTANT NOTE *** + +FreeRTOS-Labs contains libraries and demos that are fully functional, but +undergoing optimizations or refactoring to improve memory usage, modularity, +documentation, demo usability, or test coverage. At this time the projects ARE +A WORK IN PROGRESS and will be released in the main FreeRTOS directories of the +download following full review and completion of the documentation. + + + +*** INTRODUCTION *** + +This distribution currently contains demos from the FreeRTOS task pool library, +MQTT library, HTTPS Client library, Shadow library, and Jobs library. + +The pre-configured projects use the FreeRTOS kernel Windows port (often +called the Windows simulator) to enable their evaluation using the free Visual +Studio tools and without needing specific microcontroller hardware. + + + +*** INSTRUCTIONS *** + +Instructions for configuring and using the FreeRTOS IoT libraries are in the +following links: + + + https://www.FreeRTOS.org/task-pool/ + + https://www.FreeRTOS.org/mqtt/ + + https://www.freertos.org/https/ + + https://www.FreeRTOS.org/shadow/ + + https://www.FreeRTOS.org/jobs/ + + +*** LOCATING THE EXAMPLE PROJECTS *** + +The Visual Studio projects for each of the FreeRTOS IoT library examples are +located in sub-directories of the following top-level directories: + + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/utilities + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/mqtt + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/https + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/shadow + + /FreeRTOS-Labs/Demo/FreeRTOS_IoT_Libraries/jobs + + +*** ADDITIONAL INFORMATION *** + +See http://www.freertos.org/a00017.html for full details of the FreeRTOS +directory structure + +See also - +http://www.freertos.org/FreeRTOS-quick-start-guide.html +http://www.freertos.org/FAQHelp.html -- 2.39.2